{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "extends": "none",
  "name": "choice-box",
  "title": "choice-box",
  "description": "choice-box",
  "dependencies": [
    "react-aria-components",
    "tailwind-merge",
    "tailwind-variants"
  ],
  "registryDependencies": [
    "https://intentui.com/r/primitive",
    "https://intentui.com/r/checkbox"
  ],
  "files": [
    {
      "path": "src/components/ui/choice-box.tsx",
      "content": "'use client'\n\nimport { createContext, use } from 'react'\nimport type { GridListItemProps, GridListProps, TextProps } from 'react-aria-components'\nimport { composeRenderProps, GridList, GridListItem, Text } from 'react-aria-components'\nimport { twMerge } from 'tailwind-merge'\nimport type { VariantProps } from 'tailwind-variants'\nimport { tv } from 'tailwind-variants'\nimport { cx } from '@/lib/primitive'\nimport { Checkbox, CheckboxField } from './checkbox'\n\nconst choiceBoxStyles = tv({\n  base: 'grid [--gutter:--spacing(4)]',\n  variants: {\n    columns: {\n      1: 'col-span-full grid-cols-[auto_1fr]',\n      2: 'sm:grid-cols-2',\n      3: 'sm:grid-cols-3',\n      4: 'sm:grid-cols-4',\n      5: 'sm:grid-cols-5',\n      6: 'sm:grid-cols-6',\n    },\n    gap: {\n      0: 'gap-0',\n      1: 'gap-1',\n      2: 'gap-2',\n      3: 'gap-3',\n      4: 'gap-4',\n      5: 'gap-5',\n      6: 'gap-6',\n      8: 'gap-8',\n      10: 'gap-10',\n      12: 'gap-12',\n    },\n  },\n  defaultVariants: {\n    columns: 1,\n    gap: 0,\n  },\n  compoundVariants: [\n    {\n      gap: 0,\n      columns: 1,\n      className:\n        'rounded-lg *:data-[slot=choice-box-item]:inset-ring *:data-[slot=choice-box-item]:-mt-px *:data-[slot=choice-box-item]:rounded-none *:data-[slot=choice-box-item]:last:rounded-b-[calc(var(--radius-lg)-1px)] *:data-[slot=choice-box-item]:first:rounded-t-[calc(var(--radius-lg)-1px)]',\n    },\n  ],\n})\n\nconst ChoiceBoxContext = createContext<{ columns?: number; gap?: number; isReadOnly?: boolean }>({})\n\nconst useChoiceBoxContext = () => use(ChoiceBoxContext)\n\ninterface ChoiceBoxProps<T extends object>\n  extends GridListProps<T>, VariantProps<typeof choiceBoxStyles> {\n  isReadOnly?: boolean\n}\n\nconst ChoiceBox = <T extends object>({\n  columns = 1,\n  gap = 0,\n  className,\n  selectionMode = 'single',\n  isReadOnly,\n  ...props\n}: ChoiceBoxProps<T>) => {\n  return (\n    <ChoiceBoxContext value={{ columns, gap, isReadOnly }}>\n      <GridList\n        data-slot=\"choice-box\"\n        layout={columns === 1 ? 'stack' : 'grid'}\n        selectionMode={selectionMode}\n        className={cx(\n          choiceBoxStyles({\n            columns,\n            gap,\n          }),\n          className\n        )}\n        {...props}\n      />\n    </ChoiceBoxContext>\n  )\n}\n\nconst choiceBoxItemStyles = tv({\n  base: [\n    'group outline-hidden',\n    '[--choice-box-fg:var(--color-primary-subtle-fg)] [--choice-box:var(--color-primary-subtle)]',\n    '[--choice-box-selected-hovered:var(--color-primary-subtle)]/90',\n    'inset-ring inset-ring-border rounded-lg p-(--gutter) **:data-[slot=label]:font-medium',\n    '**:data-[slot=avatar]:row-span-2 **:data-[slot=avatar]:mt-0.5 **:data-[slot=avatar]:shrink-0',\n    '**:[svg]:row-span-2 **:[svg]:h-[1.1lh] **:[svg]:w-5 **:[svg]:shrink-0',\n    'has-[svg:not([data-slot=check-indicator])]:grid-cols-[auto_1fr_auto] has-data-[slot=avatar]:grid-cols-[auto_1fr_auto]',\n    'grid grid-cols-[1fr_auto] content-start items-start gap-x-[calc(var(--gutter)-(--spacing(1)))] gap-y-1',\n    '[--choice-box-active-ring:var(--color-ring)]/70 [--choice-box-ring:var(--color-ring)]/20',\n    'has-[[slot=description]]:**:data-[slot=label]:font-medium',\n  ],\n  variants: {\n    isLink: {\n      true: 'cursor-pointer',\n      false: 'cursor-default',\n    },\n    isHovered: {\n      true: 'not-data-readonly:not-data-focus-visible:not-selected:inset-ring-muted-fg/30',\n    },\n    isFocused: {\n      true: 'inset-ring-(--choice-box-active-ring) ring-(--choice-box-ring) ring-3 invalid:ring-danger-subtle-fg/20',\n    },\n    isInvalid: { true: 'ring-3 ring-danger-subtle-fg/20' },\n    isOneColumn: {\n      true: 'col-span-full',\n    },\n    isActive: {\n      true: [\n        'bg-(--choice-box) text-(--choice-box-fg)',\n        'inset-ring-(--choice-box-active-ring) z-20 hover:bg-(--choice-box-selected-hovered)',\n        '**:data-[slot=label]:text-(--choice-box-fg)',\n        '**:[[slot=description]]:text-(--choice-box-fg)',\n      ],\n    },\n    isDisabled: {\n      true: 'z-10 opacity-50 **:data-[slot=label]:text-muted-fg forced-colors:text-[GrayText] **:[[slot=description]]:text-muted-fg/70',\n    },\n  },\n})\n\ninterface ChoiceBoxItemProps extends GridListItemProps, VariantProps<typeof choiceBoxItemStyles> {\n  label?: string\n  description?: string\n}\n\nconst ChoiceBoxItem = ({\n  className,\n  label,\n  description,\n  children,\n  ...props\n}: ChoiceBoxItemProps) => {\n  const textValue = typeof children === 'string' ? children : undefined\n  const { columns, isReadOnly } = useChoiceBoxContext()\n  return (\n    <GridListItem\n      textValue={textValue}\n      data-readonly={isReadOnly}\n      data-slot=\"choice-box-item\"\n      {...props}\n      className={composeRenderProps(\n        className,\n        (className, { isFocusVisible, isSelected, ...renderProps }) =>\n          choiceBoxItemStyles({\n            ...renderProps,\n            isOneColumn: columns === 1,\n            isLink: 'href' in props,\n            isFocused: !isReadOnly && renderProps.isFocused,\n            isActive: (!isReadOnly && isSelected) || isFocusVisible,\n            className,\n          })\n      )}\n    >\n      {composeRenderProps(children, (children, { selectionMode }) => {\n        const isStringChild = typeof children === 'string'\n        const hasCustomChildren = typeof children !== 'undefined'\n\n        const content = hasCustomChildren ? (\n          isStringChild ? (\n            <ChoiceBoxLabel>{children}</ChoiceBoxLabel>\n          ) : (\n            children\n          )\n        ) : (\n          <>\n            {label && <ChoiceBoxLabel>{label}</ChoiceBoxLabel>}\n            {description && <ChoiceBoxDescription>{description}</ChoiceBoxDescription>}\n          </>\n        )\n        return (\n          <>\n            {content}\n            {selectionMode === 'multiple' && (\n              <CheckboxField\n                slot=\"selection\"\n                className=\"gap-x-0 col-start-2 self-start group-has-[svg:not([data-slot=check-indicator])]:col-start-3 group-has-data-[slot=avatar]:col-start-3\"\n              >\n                <Checkbox className=\"col-span-1\" />\n              </CheckboxField>\n            )}\n          </>\n        )\n      })}\n    </GridListItem>\n  )\n}\n\ninterface ChoiceBoxLabelProps extends TextProps {\n  ref?: React.Ref<HTMLDivElement>\n}\n\nconst ChoiceBoxLabel = ({ className, ref, ...props }: ChoiceBoxLabelProps) => {\n  return (\n    <Text\n      data-slot=\"label\"\n      ref={ref}\n      className={twMerge(\n        'select-none text-base/6 text-fg group-disabled:opacity-50 sm:text-sm/6',\n        'col-start-1 row-start-1',\n        'group-has-[svg:not([data-slot=check-indicator])]:col-start-2',\n        'group-has-data-[slot=avatar]:col-start-2',\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\ntype ChoiceBoxDescriptionProps = ChoiceBoxLabelProps\n\nconst ChoiceBoxDescription = ({ className, ref, ...props }: ChoiceBoxDescriptionProps) => {\n  return (\n    <Text\n      slot=\"description\"\n      ref={ref}\n      className={twMerge(\n        'col-start-1 row-start-2',\n        'group-has-[svg:not([data-slot=check-indicator])]:col-start-2',\n        'group-has-data-[slot=avatar]:col-start-2',\n        'text-base/6 text-muted-fg sm:text-sm/6',\n        'group-disabled:opacity-50',\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport type { ChoiceBoxItemProps, ChoiceBoxProps }\nexport { ChoiceBox, ChoiceBoxDescription, ChoiceBoxItem, ChoiceBoxLabel }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}