{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-copy-button",
  "type": "registry:component",
  "title": "Copy button",
  "description": "An icon action that copies a value and acknowledges it",
  "author": "sudo-kw <https://github.com/sudo-kw>",
  "dependencies": [
    "@gpuix/native@0.11.0",
    "@gpuix/react@0.11.0",
    "effect@4.1.2",
    "react@^19.2.4"
  ],
  "registryDependencies": [
    "https://gpuixui.sudokw.com/gpuix-icons.json",
    "https://gpuixui.sudokw.com/gpuix-motion.json",
    "https://gpuixui.sudokw.com/gpuix-primitives.json",
    "https://gpuixui.sudokw.com/gpuix-tokens.json",
    "https://gpuixui.sudokw.com/gpuix-tw.json"
  ],
  "files": [
    {
      "path": "packages/components/src/copy-button.tsx",
      "target": "@ui/gpuixui/components/copy-button.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { Props } from \"@gpuix/react\";\nimport {\n  mergeStyles,\n  resolveStyle,\n  type StateStyle,\n} from \"@gpuix/react/floating\";\nimport { Icon } from \"../icons/index.js\";\nimport { cn } from \"../tw/index.js\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useMotionPreference } from \"./internal/presence.js\";\nimport { recipeStyle } from \"./internal/recipe.js\";\nimport { IconButton, type ButtonSize } from \"./internal/button.js\";\nimport { useTheme } from \"./internal/theme.js\";\nimport { surfaceLevelOf, type SurfaceLevel } from \"./motion.js\";\nimport { Reveal } from \"./reveal.js\";\nimport {\n  acknowledgementWindow,\n  copyButtonIcon,\n  copyButtonLabel,\n} from \"./copy-button/logic.js\";\n\nconst COPY_GLYPH_RISE = 3;\n\nexport interface CopyButtonState {\n  readonly acknowledged: boolean;\n  readonly reducedMotion: boolean;\n}\n\nexport interface CopyButtonProps extends Omit<Props, \"children\" | \"style\"> {\n  readonly text: string;\n\n  readonly onCopy: (text: string) => void;\n\n  readonly label?: string;\n\n  readonly copiedLabel?: string;\n\n  readonly acknowledgeMs?: number;\n\n  readonly size?: ButtonSize;\n\n  readonly disabled?: boolean;\n\n  readonly color?: string;\n\n  readonly level?: SurfaceLevel;\n\n  readonly className?: string;\n\n  readonly style?: StateStyle<CopyButtonState>;\n}\n\nexport const CopyButton = ({\n  text,\n  onCopy,\n  label,\n  copiedLabel,\n  acknowledgeMs,\n  size = \"sm\",\n  disabled = false,\n  color,\n  level: storedLevel = \"fast\",\n  className,\n  style,\n  testId,\n  ...rest\n}: CopyButtonProps) => {\n  const theme = useTheme();\n  const preference = useMotionPreference();\n  const level = surfaceLevelOf(storedLevel);\n  const [acknowledged, setAcknowledged] = useState(false);\n  const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n  const base = testId ?? \"copy-button\";\n  const windowMs = acknowledgementWindow(acknowledgeMs);\n\n  useEffect(\n    () => () => {\n      if (timer.current !== undefined) clearTimeout(timer.current);\n    },\n    [],\n  );\n\n  const copy = (): void => {\n    onCopy(text);\n    setAcknowledged(true);\n    if (timer.current !== undefined) clearTimeout(timer.current);\n    timer.current = setTimeout(() => setAcknowledged(false), windowMs);\n  };\n\n  const state: CopyButtonState = {\n    acknowledged,\n    reducedMotion: preference === \"reduced\",\n  };\n  const glyph = (\n    <Icon\n      name={copyButtonIcon(acknowledged)}\n      size=\"sm\"\n      color={color ?? theme.colors.mutedForeground}\n    />\n  );\n\n  return (\n    <IconButton\n      {...rest}\n      testId={base}\n      size={size}\n      disabled={disabled}\n      label={copyButtonLabel(acknowledged, { label, copiedLabel })}\n      onClick={copy}\n      style={mergeStyles(\n        recipeStyle(cn(className), theme),\n        resolveStyle(style, state),\n      )}\n    >\n      {acknowledged && level !== \"none\" ? (\n        <Reveal\n          key=\"copied\"\n          testId={`${base}-glyph`}\n          from=\"below\"\n          distance={COPY_GLYPH_RISE}\n          level={level}\n        >\n          {glyph}\n        </Reveal>\n      ) : (\n        <div testId={`${base}-glyph`}>{glyph}</div>\n      )}\n    </IconButton>\n  );\n};\n\nexport const copyButtonMeta = {\n  name: \"Copy button\",\n  tier: 5,\n  status: \"done\",\n  gpuixSupport: \"partial\",\n  limitations: [\n    \"0.11.0 publishes no clipboard API, so the press calls the caller's `onCopy` and acknowledges it; the control never writes\",\n    \"the confirmation is the button's changing name, because the runtime has no live region to announce it\",\n    \"the checked glyph fades and rises in rather than scaling: there is no `transform` (upstream issue #102)\",\n  ],\n  docs: \"docs/copy-button.mdx\",\n  example: \"examples/copy-button.example.tsx\",\n  testFile: \"src/behaviour/copy-button.test.tsx\",\n} as const;\n"
    },
    {
      "path": "packages/components/src/copy-button/logic.ts",
      "target": "@ui/gpuixui/components/copy-button/logic.ts",
      "type": "registry:lib",
      "content": "import { pipe } from \"effect\";\nimport * as Option from \"effect/Option\";\nimport { nameOf } from \"../internal/text.js\";\n\nconst DEFAULT_LABEL = \"Copy\";\n\nconst DEFAULT_COPIED_LABEL = \"Copied\";\n\nexport const COPY_ACKNOWLEDGEMENT_MS = 1_200;\n\nconst named = (value: unknown, fallback: string): string =>\n  Option.getOrElse(Option.fromNullishOr(nameOf(value)), () => fallback);\n\nexport interface CopyButtonLabels {\n  readonly label?: unknown;\n\n  readonly copiedLabel?: unknown;\n}\n\nexport const copyButtonLabel = (\n  acknowledged: boolean,\n  labels: CopyButtonLabels = {},\n): string =>\n  acknowledged\n    ? named(labels.copiedLabel, DEFAULT_COPIED_LABEL)\n    : named(labels.label, DEFAULT_LABEL);\n\nexport const copyButtonIcon = (acknowledged: boolean): \"copy\" | \"check\" =>\n  acknowledged ? \"check\" : \"copy\";\n\nexport const acknowledgementWindow = (milliseconds?: number): number =>\n  pipe(\n    Option.fromNullishOr(milliseconds),\n    Option.filter((value) => Number.isFinite(value) && value > 0),\n    Option.getOrElse(() => COPY_ACKNOWLEDGEMENT_MS),\n  );\n"
    },
    {
      "path": "packages/components/src/internal/button.tsx",
      "target": "@ui/gpuixui/components/internal/button.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { Props } from \"@gpuix/react\";\nimport type { ReactNode } from \"react\";\nimport {\n  Button as PrimitiveButton,\n  IconButton as PrimitiveIconButton,\n  actionOnColor as primitiveActionOnColor,\n  type ButtonVariant as PrimitiveVariant,\n} from \"../../primitives/button.js\";\nimport { cn } from \"../../tw/index.js\";\nimport * as Schema from \"effect/Schema\";\nimport type { Theme } from \"./theme.js\";\n\nconst ButtonVariants = Schema.Literals([\n  \"primary\",\n  \"secondary\",\n  \"ghost\",\n  \"danger\",\n  \"link\",\n]);\n\nexport type ButtonVariant = typeof ButtonVariants.Type;\n\nexport type ButtonSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface ButtonProps extends Props {\n  readonly variant?: ButtonVariant;\n\n  readonly size?: ButtonSize;\n\n  readonly disabled?: boolean;\n\n  readonly loading?: boolean;\n\n  readonly loadingLabel?: string;\n\n  readonly reducedMotion?: boolean;\n\n  readonly leading?: ReactNode;\n\n  readonly trailing?: ReactNode;\n}\n\nexport interface IconButtonProps extends Props {\n  readonly label: string;\n\n  readonly size?: ButtonSize;\n  readonly disabled?: boolean;\n}\n\ninterface Look {\n  readonly variant: PrimitiveVariant;\n  readonly className: string;\n}\n\nconst LOOKS: Readonly<Record<ButtonVariant, Look>> = {\n  primary: { variant: \"primary\", className: \"\" },\n  secondary: { variant: \"secondary\", className: \"border border-strong\" },\n  ghost: { variant: \"ghost\", className: \"\" },\n  danger: { variant: \"destructive\", className: \"\" },\n\n  link: { variant: \"link\", className: \"underline underline-offset-4\" },\n};\n\nconst lookOf = (variant: unknown): Look =>\n  LOOKS[Schema.is(ButtonVariants)(variant) ? variant : \"secondary\"];\n\nexport const actionOnColor = (theme: Theme, variant: ButtonVariant): string =>\n  primitiveActionOnColor(theme, lookOf(variant).variant);\n\nexport const Button = ({\n  variant = \"secondary\",\n  size = \"md\",\n  disabled = false,\n  onClick,\n  style,\n  \"aria-label\": ariaLabel,\n  ...rest\n}: ButtonProps) => {\n  const look = lookOf(variant);\n  return (\n    <PrimitiveButton\n      {...rest}\n      variant={look.variant}\n      size={size}\n      disabled={disabled}\n      label={ariaLabel}\n      className={cn(look.className)}\n      onActivate={onClick}\n      style={style}\n    />\n  );\n};\n\nexport const IconButton = ({\n  label,\n  size = \"md\",\n  disabled = false,\n  onClick,\n  style,\n  children,\n  ...rest\n}: IconButtonProps) => (\n  <PrimitiveIconButton\n    {...rest}\n    icon={children}\n    variant=\"ghost\"\n    size={size}\n    disabled={disabled}\n    label={label}\n    className=\"text-muted-foreground hover:text-foreground\"\n    onActivate={onClick}\n    style={style}\n  />\n);\n"
    },
    {
      "path": "packages/components/src/internal/presence.tsx",
      "target": "@ui/gpuixui/components/internal/presence.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { MotionProps } from \"@gpuix/react\";\nimport {\n  delayedTiming,\n  exitWindowMs,\n  fadeFrom,\n  fadeFromAnchor,\n  fadeFromSide,\n  fadeOnly,\n  presenceMotion as motionOfPresence,\n  presenceStyle,\n  transitionWindowMs,\n  type PresenceFrames,\n  type PresenceHitRule,\n  type PresenceSide,\n  type PresenceTiming,\n  type PresenceTransition,\n} from \"../../motion/presence.js\";\nimport {\n  MotionProvider,\n  useMotionPreference,\n  useSurfacePresence,\n  useSurfaceTiming,\n  type MotionProviderProps,\n  type SurfacePresence,\n} from \"../../motion/react/presence.js\";\nimport {\n  motionTiming,\n  type MotionLevel,\n  type MotionPreference,\n} from \"../../motion/timing.js\";\n\nexport { MotionProvider, useMotionPreference, type MotionProviderProps };\n\nexport type SurfaceFrames = PresenceFrames;\n\nexport type SurfaceTiming = PresenceTiming;\n\nexport type PanelSide = PresenceSide;\n\nexport {\n  delayedTiming,\n  exitWindowMs,\n  fadeFrom,\n  fadeFromAnchor,\n  fadeFromSide,\n  fadeOnly,\n  presenceStyle,\n  transitionWindowMs,\n};\nexport type { PresenceHitRule };\n\nexport { useSurfacePresence, useSurfaceTiming, type SurfacePresence };\n\nexport const moveTiming = (\n  level: MotionLevel,\n  preference: MotionPreference,\n): PresenceTransition => motionTiming(level, { phase: \"standard\", preference });\n\nexport const useMoveTiming = (level: MotionLevel): PresenceTransition =>\n  moveTiming(level, useMotionPreference());\n\nexport const presenceMotion = (\n  frames: SurfaceFrames,\n  presence: SurfacePresence,\n  timing: SurfaceTiming = presence.timing,\n): MotionProps => motionOfPresence(frames, presence.present, timing);\n\nexport const PresenceShield = ({ present }: { readonly present: boolean }) =>\n  present ? null : (\n    <div\n      testId=\"presence-shield\"\n      style={{ position: \"absolute\", top: 0, right: 0, bottom: 0, left: 0 }}\n    />\n  );\n\nexport const presenceTabStop = (\n  present: boolean,\n): { readonly tabIndex?: number } => (present ? {} : { tabIndex: -1 });\n"
    },
    {
      "path": "packages/components/src/internal/recipe.ts",
      "target": "@ui/gpuixui/components/internal/recipe.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport { createRecipeCache } from \"../../tw/index.js\";\nimport type { Theme } from \"./theme.js\";\n\nexport const recipeStyle: (recipe: string, theme: Theme) => StyleDesc =\n  createRecipeCache(512);\n"
    },
    {
      "path": "packages/components/src/internal/text.ts",
      "target": "@ui/gpuixui/components/internal/text.ts",
      "type": "registry:lib",
      "content": "import { pipe } from \"effect\";\nimport * as Option from \"effect/Option\";\nimport * as Str from \"effect/String\";\n\nexport const textOf = (value: unknown): string =>\n  typeof value === \"string\" ? value : \"\";\n\nexport const nameOf = (value: unknown): string | undefined =>\n  pipe(\n    Option.some(textOf(value)),\n    Option.map(Str.trim),\n    Option.filter(Str.isNonEmpty),\n    Option.getOrUndefined,\n  );\n"
    },
    {
      "path": "packages/components/src/internal/theme.ts",
      "target": "@ui/gpuixui/components/internal/theme.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport * as Schema from \"effect/Schema\";\nimport {\n  alpha,\n  avatarPixels,\n  avatarSize,\n  brandTextOn,\n  controlFocusRing,\n  controlHeight,\n  controlPaddingX,\n  currentPlatform,\n  darkTheme,\n  disabledAction,\n  disabledOpacity,\n  elevationShadow,\n  filledHover,\n  filledPressed,\n  findHighlight,\n  focusRing,\n  keyboardFocusRing,\n  lightTheme,\n  nativeTextTheme,\n  pointerWash,\n  selectionOn,\n  statusTone,\n  syntaxColors,\n  targetSize,\n  textStyle,\n  type BoxShadow,\n  type ElevationLevel,\n  type FindHighlightSource,\n  type NativeTextFill,\n  type PlatformName,\n  type PointerWashSurface,\n  type StatusTone,\n  type SyntaxColors,\n  type SyntaxRole,\n  type TextRole,\n  type Theme,\n  type ThemeColors,\n} from \"../../tokens/index.js\";\n\nexport {\n  alpha,\n  avatarPixels,\n  avatarSize,\n  controlFocusRing,\n  controlHeight,\n  controlPaddingX,\n  currentPlatform,\n  darkTheme,\n  disabledAction,\n  disabledOpacity,\n  elevationShadow,\n  filledHover,\n  filledPressed,\n  findHighlight,\n  focusRing,\n  keyboardFocusRing,\n  lightTheme,\n  nativeTextTheme,\n  statusTone,\n  syntaxColors,\n  targetSize,\n  textStyle,\n};\nexport type {\n  BoxShadow,\n  ElevationLevel,\n  FindHighlightSource,\n  NativeTextFill,\n  PlatformName,\n  StatusTone,\n  SyntaxColors,\n  SyntaxRole,\n  TextRole,\n  Theme,\n};\nexport { ThemeProvider, useTheme } from \"../../tokens/react.js\";\n\nexport const keyboardRing = (theme: Theme, invalid = false): StyleDesc =>\n  controlFocusRing(theme, { invalid }) ?? {};\n\nexport interface ControlRingState {\n  readonly disabled?: boolean;\n\n  readonly invalid?: boolean;\n}\n\nexport const controlRing = (\n  theme: Theme,\n  state: ControlRingState = {},\n): StyleDesc => controlFocusRing(theme, state) ?? {};\n\nexport const pressWash = (theme: Theme, replaced: PointerWashSurface): string =>\n  pointerWash(theme, \"active\", replaced) ?? theme.colors.active;\n\nexport const selectionWash = (theme: Theme): StyleDesc => ({\n  selectionColor: theme.colors.selection,\n});\n\nexport const keepContent: StyleDesc = { keyboardFocusDim: false };\n\nexport const disabledFade = (\n  disabled: boolean,\n): { readonly opacity: number } | undefined =>\n  disabled ? { opacity: disabledOpacity } : undefined;\n\nconst Tones = Schema.Literals([\"info\", \"success\", \"warning\", \"danger\"]);\n\nexport type Tone = typeof Tones.Type;\n\nexport const toneOf = (value: unknown): Tone =>\n  Schema.is(Tones)(value) ? value : \"info\";\n\nexport interface ToneStyle {\n  readonly fg: string;\n  readonly bg: string;\n  readonly border: string;\n}\n\nconst TOKEN_TONE: Readonly<Record<Tone, StatusTone>> = {\n  info: \"info\",\n  success: \"success\",\n  warning: \"warning\",\n  danger: \"destructive\",\n};\n\nexport const tone = (theme: Theme, value: Tone): ToneStyle => {\n  const { background, border, foreground } = statusTone(\n    theme,\n    TOKEN_TONE[value],\n  );\n  return { bg: background, border, fg: foreground };\n};\n\nconst softRoles: Readonly<Record<Tone, keyof ThemeColors>> = {\n  info: \"infoSoft\",\n  success: \"successSoft\",\n  warning: \"warningSoft\",\n  danger: \"destructiveSoft\",\n};\n\nexport const messageLink = (theme: Theme, value: Tone): string =>\n  brandTextOn(theme, softRoles[value]);\n\nexport const messageSelection = (theme: Theme, value: Tone): string =>\n  selectionOn(theme, softRoles[value]);\n\nexport const toneSurface = (theme: Theme, value: Tone): StyleDesc => {\n  const { bg, border, fg } = tone(theme, value);\n  return {\n    backgroundColor: bg,\n    color: fg,\n    borderWidth: theme.borderWidth.thin,\n    borderColor: border,\n  };\n};\n"
    },
    {
      "path": "packages/components/src/motion.tsx",
      "target": "@ui/gpuixui/components/motion.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport { motionLevelOf, type MotionLevel } from \"../motion/timing.js\";\n\nexport {\n  MotionProvider,\n  useMotionPreference,\n  type MotionProviderProps,\n} from \"./internal/presence.js\";\nexport type { MotionPreference } from \"../motion/timing.js\";\n\nexport type SurfaceLevel = MotionLevel | \"none\";\n\nexport const surfaceLevelOf = (value: unknown): SurfaceLevel =>\n  value === \"none\" ? \"none\" : motionLevelOf(value);\n"
    },
    {
      "path": "packages/components/src/reveal.tsx",
      "target": "@ui/gpuixui/components/reveal.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { Props } from \"@gpuix/react\";\nimport {\n  mergeStyles,\n  resolveStyle,\n  type StateStyle,\n} from \"@gpuix/react/floating\";\nimport type { MotionLevel } from \"../motion/timing.js\";\nimport { cn } from \"../tw/index.js\";\nimport * as Option from \"effect/Option\";\nimport type { ReactNode } from \"react\";\nimport {\n  delayedTiming,\n  PresenceShield,\n  presenceMotion,\n  presenceStyle,\n  useMotionPreference,\n  useSurfacePresence,\n  useSurfaceTiming,\n} from \"./internal/presence.js\";\nimport { recipeStyle } from \"./internal/recipe.js\";\nimport { useTheme } from \"./internal/theme.js\";\nimport { revealFrames, type RevealFrom } from \"./reveal/frames.js\";\n\nexport interface RevealState {\n  readonly open: boolean;\n  readonly from: RevealFrom;\n  readonly reducedMotion: boolean;\n}\n\nexport interface RevealProps extends Omit<Props, \"children\" | \"style\"> {\n  readonly children?: ReactNode;\n\n  readonly open?: boolean;\n\n  readonly from?: RevealFrom;\n\n  readonly distance?: number;\n\n  readonly level?: MotionLevel;\n\n  readonly delayMs?: number;\n\n  readonly className?: string;\n\n  readonly style?: StateStyle<RevealState>;\n}\n\nexport const Reveal = ({\n  children,\n  open,\n  from = \"below\",\n  distance,\n  level = \"normal\",\n  delayMs,\n  className,\n  style,\n  ...rest\n}: RevealProps) => {\n  const theme = useTheme();\n  const preference = useMotionPreference();\n  const timing = useSurfaceTiming(level);\n  const delay = Option.getOrElse(Option.fromNullishOr(delayMs), () => 0);\n  const travel = Option.getOrElse(Option.fromNullishOr(distance), () => 8);\n  const presence = useSurfacePresence(open ?? true, {\n    enter: delayedTiming(timing.enter, delay),\n    exit: timing.exit,\n  });\n\n  if (!presence.mounted) return null;\n\n  const state: RevealState = {\n    open: open ?? true,\n    from,\n    reducedMotion: preference === \"reduced\",\n  };\n\n  return (\n    <div\n      {...rest}\n      motion={presenceMotion(revealFrames(from, travel), presence)}\n      style={mergeStyles(\n        mergeStyles(\n          { position: \"relative\" },\n          recipeStyle(cn(className), theme),\n        ),\n        mergeStyles(\n          presenceStyle(presence.present, \"wrapper\"),\n          resolveStyle(style, state),\n        ),\n      )}\n    >\n      {children}\n      <PresenceShield present={presence.present} />\n    </div>\n  );\n};\n\nexport const revealMeta = {\n  name: \"Reveal\",\n  tier: 5,\n  status: \"done\",\n  gpuixSupport: \"partial\",\n  limitations: [\n    \"fade plus a top/left offset: the runtime has no transform, so there is no zoom or scale\",\n    \"no blur: StyleDesc has no filter\",\n    \"the travel does not reflow, so the content's final layout is the one it is laid out in\",\n  ],\n  docs: \"docs/reveal.mdx\",\n  example: \"examples/reveal.example.tsx\",\n  testFile: \"src/behaviour/reveal.test.tsx\",\n} as const;\n"
    },
    {
      "path": "packages/components/src/reveal/frames.ts",
      "target": "@ui/gpuixui/components/reveal/frames.ts",
      "type": "registry:lib",
      "content": "import type { MotionStyle } from \"@gpuix/react\";\nimport { Match } from \"effect\";\nimport * as Schema from \"effect/Schema\";\n\nconst RevealEdge = Schema.Literals([\"below\", \"above\", \"left\", \"right\", \"none\"]);\n\nexport type RevealFrom = typeof RevealEdge.Type;\n\nconst revealEdgeOf = (from: unknown): RevealFrom =>\n  Schema.is(RevealEdge)(from) ? from : \"below\";\n\nexport interface RevealFrames {\n  readonly initial: MotionStyle;\n  readonly animate: MotionStyle;\n  readonly exit: MotionStyle;\n}\n\nconst travelling = (axis: \"top\" | \"left\", amount: number): RevealFrames => ({\n  initial: { opacity: 0, [axis]: amount },\n  animate: { opacity: 1, [axis]: 0 },\n  exit: { opacity: 0, [axis]: amount },\n});\n\nconst still: RevealFrames = {\n  initial: { opacity: 0 },\n  animate: { opacity: 1 },\n  exit: { opacity: 0 },\n};\n\nexport const revealFrames = (from: unknown, distance: number): RevealFrames => {\n  const travel =\n    Number.isFinite(distance) && distance > 0 ? Math.round(distance) : 8;\n\n  return Match.value(revealEdgeOf(from)).pipe(\n    Match.when(\"none\", () => still),\n    Match.when(\"below\", () => travelling(\"top\", travel)),\n    Match.when(\"above\", () => travelling(\"top\", -travel)),\n    Match.when(\"right\", () => travelling(\"left\", travel)),\n    Match.when(\"left\", () => travelling(\"left\", -travel)),\n    Match.exhaustive,\n  );\n};\n"
    }
  ],
  "docs": "[Copy button](https://gpuixui.sudokw.com/components/copy-button) — These are GPUix native components: the files render through GPUix's reconciler against `@gpuix/react`, not the DOM, and need the per-platform `@gpuix/native` binding. The CLI installs the `@gpuixui/*` runtime the components import as registry items, so the copied tree resolves on its own; wrap it in `ThemeProvider` before it renders.",
  "meta": {
    "url": "/components/copy-button",
    "kind": "component",
    "runtime": "gpuix",
    "registry": "gpuixui"
  }
}