Skip to content
OrreryIris

Media card

Tap the icon. It becomes the card’s icon, not a new one.

  • shape="squircle"
  • triggerSize={72}
  • preset={presets.snappy}

How it moves

One open, captured at 60fps. The icon is an Iris.Shared slot: it travels from the trigger to the card’s corner while the surface grows around it.One open at 60fps. The icon is an Iris.Shared slot that travels into the card’s corner.

  1. The Brukas app icon at rest.The Brukas app icon at rest.

    00Rest

  2. The icon has moved up-left as an empty card surface grows around it.The icon has moved up-left as an empty card surface grows around it.

    01≈20%

  3. The card is near full size; its Brukas title and GET button are fading in.The card is near full size; its Brukas title and GET button are fading in.

    02≈50%

  4. The card at full size, its price, category, age and platform row in place and its description fading in.The card at full size, its price, category, age and platform row in place and its description fading in.

    03≈80%

  5. The settled card: the Brukas icon, title and Focus Coach subtitle, a GET button, its price, category, age and platform, and a one-line description.The settled card: the Brukas icon, title and Focus Coach subtitle, a GET button, its price, category, age and platform, and a one-line description.

    04Settled

Code

"use client";

import { Iris, presets, type AnchorId } from "@orrery-ui/iris";
import "./media-card.css";

// The whole point of this example: the SAME icon renders in both
// <Iris.Shared> slots (trigger-side and sheet-side). The package's
// FLIP morph animates one continuous element between them, so what you
// tapped does not get replaced by an unrelated panel. It grows INTO the
// card's own icon. A modal opening over the trigger cannot do this; that
// continuity is the "why" this example exists to show.
function AppIcon() {
  return (
    <div className="media-icon">
      <img src="/images/brukas/app-store-icon.webp" alt="" />
    </div>
  );
}

// Where the icon rests until it's dragged: the package's bottom-center
// unless the page picks (the docs stage picks center when it's wide).
export function MediaCard({ defaultAnchor }: { defaultAnchor?: AnchorId }) {
  return (
    <Iris.Root
      className="media-theme"
      defaultAnchor={defaultAnchor}
      preset={presets.snappy}
      shape="squircle"
      triggerSize={72}
    >
      <Iris.Shadow />

      <Iris.Trigger aria-label="Open Brukas preview">
        <Iris.Shared>
          <AppIcon />
        </Iris.Shared>
      </Iris.Trigger>

      <Iris.Sheet aria-labelledby="media-card-title">
        <Iris.Shared>
          <AppIcon />
        </Iris.Shared>

        <Iris.Close aria-label="Close" />

        <Iris.Content>
          <Iris.Item>
            <div className="media-header">
              <div>
                <h2 id="media-card-title" className="media-title">
                  Brukas
                </h2>
                <p className="media-subtitle">Focus Coach</p>
              </div>
              <a
                className="media-get"
                href="https://apps.apple.com/us/app/brukas-focus-coach/id6759548205"
                target="_blank"
                rel="noopener"
                aria-label="Get Brukas on the App Store"
              >
                GET
              </a>
            </div>
          </Iris.Item>

          <Iris.Item>
            <dl className="media-meta">
              <div className="media-meta-stat">
                <dt>Price</dt>
                <dd>Free</dd>
              </div>
              <div className="media-meta-stat">
                <dt>Category</dt>
                <dd>Productivity</dd>
              </div>
              <div className="media-meta-stat">
                <dt>Age</dt>
                <dd>9+</dd>
              </div>
              <div className="media-meta-stat">
                <dt>Platform</dt>
                <dd>iPhone</dd>
              </div>
            </dl>
          </Iris.Item>

          <Iris.Item>
            <p className="media-description">
              An AI focus coach for the hardest moment of any task: the one
              right before you start.
            </p>
          </Iris.Item>
        </Iris.Content>
      </Iris.Sheet>
    </Iris.Root>
  );
}