{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "action-list",
  "title": "Action list",
  "description": "Stacked action rows for links, clipboard values and pending or completed actions.",
  "dependencies": [
    "class-variance-authority@^0.7"
  ],
  "registryDependencies": [
    "@dwellir/dwellir-theme",
    "@dwellir/utils",
    "@dwellir/button",
    "@dwellir/copy-field",
    "@dwellir/spinner",
    "@dwellir/rune-icons"
  ],
  "files": [
    {
      "path": "components/ui/action-list.tsx",
      "content": "'use client';\n\nimport { cva } from 'class-variance-authority';\nimport type { ComponentProps, ReactNode } from 'react';\nimport { RuneCheck, RuneCopy, RuneExternalLink } from '@/components/brand/rune-icons';\nimport { Button } from '@/components/ui/button';\nimport { Spinner } from '@/components/ui/spinner';\nimport { useCopyFeedback } from '@/hooks/use-copy-feedback';\nimport { cn } from '@/lib/utils';\n\nconst actionListItemVariants = cva('w-full min-h-11 touch-manipulation text-sm font-normal', {\n  variants: {\n    state: {\n      idle: '',\n      done: '[&>svg]:text-accent-ink',\n      pending:\n        'cursor-wait aria-disabled:aria-busy:pointer-events-auto motion-reduce:[&_svg]:animate-none',\n    },\n  },\n  defaultVariants: { state: 'idle' },\n});\n\nfunction ActionList({ className, ...props }: ComponentProps<'ul'>) {\n  return (\n    <ul\n      data-slot=\"action-list\"\n      className={cn('flex min-w-0 flex-col gap-2', className)}\n      {...props}\n    />\n  );\n}\n\nfunction ActionListItem({ className, ...props }: ComponentProps<'li'>) {\n  return <li data-slot=\"action-list-item\" className={cn('min-w-0', className)} {...props} />;\n}\n\nfunction ActionContent({\n  icon,\n  children,\n  mark,\n}: {\n  icon?: ReactNode;\n  children: ReactNode;\n  mark?: ReactNode;\n}) {\n  return (\n    <>\n      {icon ? (\n        <span\n          data-slot=\"action-list-icon\"\n          aria-hidden=\"true\"\n          className=\"shrink-0 text-muted-foreground [&_svg]:size-4\"\n        >\n          {icon}\n        </span>\n      ) : null}\n      <span data-slot=\"action-list-label\" className=\"min-w-0 flex-1 text-left wrap-anywhere\">\n        {children}\n      </span>\n      {mark}\n    </>\n  );\n}\n\ntype ActionListButtonProps = Omit<ComponentProps<'button'>, 'children'> & {\n  children: ReactNode;\n  icon?: ReactNode;\n  pending?: boolean;\n  done?: boolean;\n  mark?: ReactNode;\n};\n\nfunction ActionControl({\n  children,\n  icon,\n  pending = false,\n  done = false,\n  mark,\n  disabled,\n  onClick,\n  className,\n  ...props\n}: ActionListButtonProps) {\n  return (\n    <Button\n      type=\"button\"\n      variant=\"outline\"\n      size=\"row\"\n      shape=\"rounded\"\n      disabled={disabled}\n      aria-busy={pending || undefined}\n      aria-disabled={pending || undefined}\n      data-pending={pending || undefined}\n      data-slot=\"action-list-button\"\n      className={cn(\n        actionListItemVariants({ state: pending ? 'pending' : done ? 'done' : 'idle' }),\n        className,\n      )}\n      {...props}\n      onClick={(event) => {\n        if (pending) {\n          event.preventDefault();\n          event.stopPropagation();\n          return;\n        }\n        onClick?.(event);\n      }}\n    >\n      {pending ? <Spinner size={null} aria-hidden=\"true\" /> : null}\n      <ActionContent\n        icon={pending ? undefined : icon}\n        mark={\n          pending ? null : done ? (\n            <RuneCheck size={24} data-slot=\"action-list-done\" aria-hidden=\"true\" />\n          ) : (\n            mark\n          )\n        }\n      >\n        {children}\n      </ActionContent>\n    </Button>\n  );\n}\n\nfunction ActionListButton({ pending = false, done = false, ...props }: ActionListButtonProps) {\n  return (\n    <>\n      <ActionControl pending={pending} done={done} {...props} />\n      <span\n        data-slot=\"action-list-status\"\n        role=\"status\"\n        aria-live=\"polite\"\n        aria-atomic=\"true\"\n        className=\"sr-only\"\n      >\n        {pending ? 'In progress' : done ? 'Done' : ''}\n      </span>\n    </>\n  );\n}\n\ntype ActionListLinkProps = Omit<ComponentProps<'a'>, 'children' | 'href'> & {\n  href: string;\n  children: ReactNode;\n  icon?: ReactNode;\n};\n\nfunction ActionListLink({ children, icon, className, target, rel, ...props }: ActionListLinkProps) {\n  return (\n    <Button\n      asChild\n      variant=\"outline\"\n      size=\"row\"\n      shape=\"rounded\"\n      className={cn(actionListItemVariants(), className)}\n    >\n      <a\n        data-slot=\"action-list-link\"\n        target={target}\n        rel={target === '_blank' ? ['noopener noreferrer', rel].filter(Boolean).join(' ') : rel}\n        {...props}\n      >\n        <ActionContent\n          icon={icon}\n          mark={\n            target === '_blank' ? (\n              <RuneExternalLink size={24} data-slot=\"action-list-external\" aria-hidden=\"true\" />\n            ) : null\n          }\n        >\n          {children}\n        </ActionContent>\n        {target === '_blank' ? (\n          <span data-slot=\"action-list-link-hint\" className=\"sr-only\">\n            {' '}\n            (opens in a new tab)\n          </span>\n        ) : null}\n      </a>\n    </Button>\n  );\n}\n\ntype ActionListCopyProps = Omit<ActionListButtonProps, 'onCopy' | 'pending' | 'done' | 'mark'> & {\n  value: string;\n  onCopy?: () => void;\n};\n\nfunction ActionListCopy({\n  value,\n  children,\n  icon,\n  onCopy,\n  onClick,\n  disabled,\n  className,\n  ...props\n}: ActionListCopyProps) {\n  const { status, copy } = useCopyFeedback(value, onCopy);\n  return (\n    <>\n      <ActionControl\n        data-slot=\"action-list-copy\"\n        icon={icon}\n        pending={status === 'pending'}\n        mark={\n          status === 'copied' ? (\n            <RuneCheck\n              size={24}\n              data-slot=\"action-list-copy-done\"\n              aria-hidden=\"true\"\n              className=\"text-accent-ink\"\n            />\n          ) : (\n            <RuneCopy size={24} data-slot=\"action-list-copy-mark\" aria-hidden=\"true\" />\n          )\n        }\n        disabled={disabled}\n        className={className}\n        onClick={(event) => {\n          onClick?.(event);\n          if (!event.defaultPrevented) void copy();\n        }}\n        {...props}\n      >\n        {children}\n      </ActionControl>\n      <span\n        data-slot=\"action-list-copy-status\"\n        role=\"status\"\n        aria-live=\"polite\"\n        aria-atomic=\"true\"\n        className={status === 'error' ? 'text-sm text-destructive' : 'sr-only'}\n      >\n        {status === 'copied' ? 'Copied' : null}\n        {status === 'error' ? 'Could not copy. Try again.' : null}\n      </span>\n    </>\n  );\n}\n\nexport {\n  ActionList,\n  ActionListButton,\n  type ActionListButtonProps,\n  ActionListCopy,\n  type ActionListCopyProps,\n  ActionListItem,\n  ActionListLink,\n  type ActionListLinkProps,\n  actionListItemVariants,\n};\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}