{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "swap-icon",
  "title": "Swap Icon",
  "description": "Cross-fades one icon into another in place.",
  "dependencies": [
    "@stylexjs/stylex"
  ],
  "registryDependencies": [
    "https://constella.aayush.cv/r/base.json"
  ],
  "files": [
    {
      "path": "src/components/primitives/swap-icon.tsx",
      "content": "import * as stylex from \"@stylexjs/stylex\";\nimport { createContext, use } from \"react\";\nimport type { ComponentProps } from \"react\";\n\nimport type { Sx } from \"@/lib/constella/styles\";\nimport {\n  durations,\n  easings,\n  media,\n  motion,\n} from \"@/lib/constella/tokens.stylex\";\n\ntype Styled<T> = Omit<T, \"className\" | \"style\"> & {\n  sx?: Sx;\n};\n\nconst styles = stylex.create({\n  // Every item shares one cell, so a swap is a crossfade in place.\n  swap: {\n    display: \"inline-grid\",\n    flexShrink: 0,\n  },\n  item: {\n    display: \"flex\",\n    gridArea: \"1 / 1\",\n    transitionDuration: {\n      default: durations.crossfade,\n      // Swapped from the keyboard on the control it sits in (only a keyboard focus matches `:focus-visible`), it doesn't move.\n      \":is(:focus-visible > [data-slot='swap-icon'] > *)\": \"0s\",\n    },\n    transitionProperty: {\n      default: \"opacity, filter, transform\",\n      [media.reducedMotion]: \"opacity, filter\",\n    },\n    transitionTimingFunction: easings.crossfade,\n  },\n  hidden: {\n    filter: `blur(${motion.crossfadeBlur})`,\n    opacity: 0,\n    transform: `scale(${motion.crossfadeScale})`,\n  },\n});\n\nconst SwapIconContext = createContext<string | undefined>(undefined);\n\n/** Shows the item whose `value` matches its own, cross-fading between them. */\nfunction SwapIcon({\n  sx,\n  value,\n  ...props\n}: Styled<ComponentProps<\"span\">> & { value: string }) {\n  return (\n    <SwapIconContext value={value}>\n      <span\n        data-slot=\"swap-icon\"\n        {...props}\n        {...stylex.props(styles.swap, sx)}\n      />\n    </SwapIconContext>\n  );\n}\n\nfunction SwapIconItem({\n  sx,\n  value,\n  ...props\n}: Styled<ComponentProps<\"span\">> & { value: string }) {\n  const shown = use(SwapIconContext) === value;\n  return (\n    <span\n      aria-hidden={!shown}\n      data-shown={shown || undefined}\n      data-slot=\"swap-icon-item\"\n      {...props}\n      {...stylex.props(styles.item, !shown && styles.hidden, sx)}\n    />\n  );\n}\n\nexport { SwapIcon, SwapIconItem };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Usage: https://constella.aayush.cv/docs/components/swap-icon/index.md",
  "type": "registry:ui"
}