@fuf-stack/uniform 1.22.8 → 1.22.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/Checkboxes/index.cjs +8 -8
  2. package/dist/Checkboxes/index.cjs.map +1 -1
  3. package/dist/Checkboxes/index.d.cts +2 -2
  4. package/dist/Checkboxes/index.d.cts.map +1 -1
  5. package/dist/Checkboxes/index.d.ts +2 -2
  6. package/dist/Checkboxes/index.d.ts.map +1 -1
  7. package/dist/Checkboxes/index.js +8 -8
  8. package/dist/Checkboxes/index.js.map +1 -1
  9. package/dist/DatePicker/index.cjs +3 -0
  10. package/dist/DatePicker/index.cjs.map +1 -1
  11. package/dist/DatePicker/index.d.cts +125 -6
  12. package/dist/DatePicker/index.d.cts.map +1 -1
  13. package/dist/DatePicker/index.d.ts +125 -6
  14. package/dist/DatePicker/index.d.ts.map +1 -1
  15. package/dist/DatePicker/index.js +3 -0
  16. package/dist/DatePicker/index.js.map +1 -1
  17. package/dist/RadioBoxes/index.cjs +6 -2
  18. package/dist/RadioBoxes/index.cjs.map +1 -1
  19. package/dist/RadioBoxes/index.d.cts +2 -2
  20. package/dist/RadioBoxes/index.d.cts.map +1 -1
  21. package/dist/RadioBoxes/index.d.ts +2 -2
  22. package/dist/RadioBoxes/index.d.ts.map +1 -1
  23. package/dist/RadioBoxes/index.js +6 -2
  24. package/dist/RadioBoxes/index.js.map +1 -1
  25. package/dist/RadioTabs/index.cjs +6 -2
  26. package/dist/RadioTabs/index.cjs.map +1 -1
  27. package/dist/RadioTabs/index.d.cts +2 -2
  28. package/dist/RadioTabs/index.d.cts.map +1 -1
  29. package/dist/RadioTabs/index.d.ts +2 -2
  30. package/dist/RadioTabs/index.d.ts.map +1 -1
  31. package/dist/RadioTabs/index.js +6 -2
  32. package/dist/RadioTabs/index.js.map +1 -1
  33. package/dist/Radios/index.cjs +6 -2
  34. package/dist/Radios/index.cjs.map +1 -1
  35. package/dist/Radios/index.d.cts +2 -2
  36. package/dist/Radios/index.d.cts.map +1 -1
  37. package/dist/Radios/index.d.ts +2 -2
  38. package/dist/Radios/index.d.ts.map +1 -1
  39. package/dist/Radios/index.js +6 -2
  40. package/dist/Radios/index.js.map +1 -1
  41. package/dist/Select/index.cjs +43 -31
  42. package/dist/Select/index.cjs.map +1 -1
  43. package/dist/Select/index.d.cts +2 -2
  44. package/dist/Select/index.d.cts.map +1 -1
  45. package/dist/Select/index.d.ts +2 -2
  46. package/dist/Select/index.d.ts.map +1 -1
  47. package/dist/Select/index.js +43 -31
  48. package/dist/Select/index.js.map +1 -1
  49. package/dist/Slider/index.cjs +7 -3
  50. package/dist/Slider/index.cjs.map +1 -1
  51. package/dist/Slider/index.d.cts +12 -12
  52. package/dist/Slider/index.d.cts.map +1 -1
  53. package/dist/Slider/index.d.ts +12 -12
  54. package/dist/Slider/index.d.ts.map +1 -1
  55. package/dist/Slider/index.js +7 -3
  56. package/dist/Slider/index.js.map +1 -1
  57. package/dist/Switch/index.d.cts +10 -10
  58. package/dist/Switch/index.d.ts +10 -10
  59. package/dist/SwitchBox/index.d.cts +35 -35
  60. package/dist/SwitchBox/index.d.cts.map +1 -1
  61. package/dist/SwitchBox/index.d.ts +35 -35
  62. package/dist/SwitchBox/index.d.ts.map +1 -1
  63. package/dist/Time/index.cjs +1 -1
  64. package/dist/Time/index.cjs.map +1 -1
  65. package/dist/Time/index.js +1 -1
  66. package/dist/Time/index.js.map +1 -1
  67. package/dist/helpers/index.cjs +33 -0
  68. package/dist/helpers/index.cjs.map +1 -1
  69. package/dist/helpers/index.d.cts +15 -1
  70. package/dist/helpers/index.d.cts.map +1 -1
  71. package/dist/helpers/index.d.ts +15 -1
  72. package/dist/helpers/index.d.ts.map +1 -1
  73. package/dist/helpers/index.js +33 -1
  74. package/dist/helpers/index.js.map +1 -1
  75. package/dist/hooks/useUniformField/index.cjs +5 -4
  76. package/dist/hooks/useUniformField/index.cjs.map +1 -1
  77. package/dist/hooks/useUniformField/index.d.cts +4 -2
  78. package/dist/hooks/useUniformField/index.d.cts.map +1 -1
  79. package/dist/hooks/useUniformField/index.d.ts +4 -2
  80. package/dist/hooks/useUniformField/index.d.ts.map +1 -1
  81. package/dist/hooks/useUniformField/index.js +6 -5
  82. package/dist/hooks/useUniformField/index.js.map +1 -1
  83. package/dist/hooks/useUniformFieldArray/index.d.cts.map +1 -1
  84. package/dist/hooks/useUniformFieldArray/index.d.ts.map +1 -1
  85. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["HeroRadioGroup"],"sources":["../../src/RadioBoxes/RadioBox.tsx","../../src/RadioBoxes/RadioBoxes.tsx","../../src/RadioBoxes/index.ts"],"sourcesContent":["import type { TVClassName } from '@fuf-stack/pixel-utils';\nimport type { RadioProps as HeroRadioProps } from '@heroui/radio';\nimport type { ReactNode } from 'react';\n\nimport { useRadio } from '@heroui/radio';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\n\nimport { cn, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\n\nexport const radioBoxVariants = tv({\n slots: {\n base: 'group inline-flex flex-auto cursor-pointer items-center justify-between gap-4 rounded-lg border-2 border-default p-4 hover:bg-content2 data-[selected=true]:border-focus',\n control: '',\n description: 'text-foreground opacity-70 text-small',\n icon: '',\n label: '',\n labelWrapper: 'grow',\n },\n variants: {\n isDisabled: {\n true: {\n base: 'pointer-events-none opacity-disabled',\n },\n },\n isInvalid: {\n true: {\n base: '!border-danger',\n },\n },\n },\n});\n\ntype ClassName = TVClassName<typeof radioBoxVariants>;\n\nexport interface RadioBoxProps extends Omit<HeroRadioProps, 'className'> {\n /** CSS class name */\n className?: ClassName;\n /** icon for the option */\n icon?: ReactNode;\n /** whether the radio is invalid */\n isInvalid?: boolean;\n}\n\nexport const RadioBox = ({\n classNames: _classNames = undefined,\n icon = undefined,\n isInvalid = false,\n ...props\n}: RadioBoxProps) => {\n const {\n children,\n Component,\n description,\n getBaseProps,\n getControlProps,\n getInputProps,\n getLabelProps,\n getLabelWrapperProps,\n getWrapperProps,\n isDisabled,\n } = useRadio(props as HeroRadioProps);\n\n // classNames from slots\n const variants = radioBoxVariants({\n isDisabled,\n isInvalid,\n });\n const classNames = variantsToClassNames(\n variants,\n // @ts-expect-error not sure here, but it works\n _classNames,\n 'base',\n );\n\n return (\n <Component {...getBaseProps()} className={classNames.base}>\n <VisuallyHidden>\n <input {...getInputProps()} />\n </VisuallyHidden>\n {!icon ? (\n <span {...getWrapperProps()}>\n <span\n {...getControlProps()}\n className={cn(getControlProps().className, classNames.control)}\n />\n </span>\n ) : null}\n {icon ? <div className={classNames.icon}>{icon}</div> : null}\n <div\n {...getLabelWrapperProps()}\n className={cn(\n getLabelWrapperProps().className,\n classNames.labelWrapper,\n )}\n >\n {children ? (\n <span\n {...getLabelProps()}\n className={cn(getLabelProps().className, classNames.label)}\n >\n {children}\n </span>\n ) : null}\n {description ? (\n <div className={classNames.description}>{description}</div>\n ) : null}\n </div>\n {icon ? (\n <span {...getWrapperProps()}>\n <span\n {...getControlProps()}\n className={cn(getControlProps().className, classNames.control)}\n />\n </span>\n ) : null}\n </Component>\n );\n};\n\nexport default RadioBox;\n","import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { ReactNode } from 'react';\n//\nimport type { RadioBoxProps } from './RadioBox';\n\nimport { RadioGroup as HeroRadioGroup } from '@heroui/radio';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\nimport { RadioBox } from './RadioBox';\n\nexport const radioBoxesVariants = tv({\n slots: {\n base: 'group gap-0', // Needs group for group-data condition\n boxBase: '',\n boxControl: '',\n boxDescription: '',\n boxLabel: '',\n boxLabelWrapper: '',\n // see HeroUI styles for group-data condition,\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/core/theme/src/components/select.ts\n label:\n 'mb-2 inline-flex text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n wrapper: '',\n },\n});\n\ntype VariantProps = TVProps<typeof radioBoxesVariants>;\ntype ClassName = TVClassName<typeof radioBoxesVariants>;\n\nexport interface RadioBoxOption {\n /** Description of the value. Works with variant radioBox. */\n description?: ReactNode;\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number;\n}\n\nexport interface RadioBoxesProps extends VariantProps {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioBoxOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n}\n\n/**\n * RadioBoxes component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n */\nconst RadioBoxes = ({\n className = undefined,\n inline = false,\n name,\n options,\n ...uniformFieldProps\n}: RadioBoxesProps) => {\n const {\n ariaLabel,\n errorMessage,\n invalid,\n disabled,\n label,\n field: { onBlur, onChange, ref, value },\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n // classNames from slots\n const variants = radioBoxesVariants();\n const classNames = variantsToClassNames(variants, className, 'base');\n const boxClassNames: RadioBoxProps['classNames'] = {\n base: classNames.boxBase,\n control: classNames.boxControl,\n description: classNames.boxDescription,\n label: classNames.boxLabel,\n labelWrapper: classNames.boxLabelWrapper,\n };\n\n return (\n <HeroRadioGroup\n ref={ref}\n aria-label={ariaLabel}\n classNames={classNames}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={name}\n onBlur={onBlur}\n onValueChange={(newValue) => {\n onChange(convertToOriginalType(newValue));\n }}\n orientation={inline ? 'horizontal' : 'vertical'}\n value={value != null ? String(value) : ''}\n >\n {options.map((option) => {\n if ('value' in option) {\n const optionTestId = slugify(\n `${testId}_option_${option.testId ?? option.value}`,\n { replaceDots: true },\n );\n return (\n <RadioBox\n key={String(option.value)}\n classNames={boxClassNames}\n data-testid={optionTestId}\n description={option.description}\n icon={option.icon}\n isDisabled={!!disabled || option.disabled}\n isInvalid={invalid}\n value={String(option.value)}\n >\n {option.label ?? option.value}\n </RadioBox>\n );\n }\n return null;\n })}\n </HeroRadioGroup>\n );\n};\n\nexport default RadioBoxes;\n","import RadioBoxes from './RadioBoxes';\n\nexport type { RadioBoxesProps, RadioBoxOption } from './RadioBoxes';\n\nexport { radioBoxVariants } from './RadioBox';\n\nexport default RadioBoxes;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["HeroRadioGroup"],"sources":["../../src/RadioBoxes/RadioBox.tsx","../../src/RadioBoxes/RadioBoxes.tsx","../../src/RadioBoxes/index.ts"],"sourcesContent":["import type { TVClassName } from '@fuf-stack/pixel-utils';\nimport type { RadioProps as HeroRadioProps } from '@heroui/radio';\nimport type { ReactNode } from 'react';\n\nimport { useRadio } from '@heroui/radio';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\n\nimport { cn, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\n\nexport const radioBoxVariants = tv({\n slots: {\n base: 'group inline-flex flex-auto cursor-pointer items-center justify-between gap-4 rounded-lg border-2 border-default p-4 hover:bg-content2 data-[selected=true]:border-focus',\n control: '',\n description: 'text-foreground opacity-70 text-small',\n icon: '',\n label: '',\n labelWrapper: 'grow',\n },\n variants: {\n isDisabled: {\n true: {\n base: 'pointer-events-none opacity-disabled',\n },\n },\n isInvalid: {\n true: {\n base: '!border-danger',\n },\n },\n },\n});\n\ntype ClassName = TVClassName<typeof radioBoxVariants>;\n\nexport interface RadioBoxProps extends Omit<HeroRadioProps, 'className'> {\n /** CSS class name */\n className?: ClassName;\n /** icon for the option */\n icon?: ReactNode;\n /** whether the radio is invalid */\n isInvalid?: boolean;\n}\n\nexport const RadioBox = ({\n classNames: _classNames = undefined,\n icon = undefined,\n isInvalid = false,\n ...props\n}: RadioBoxProps) => {\n const {\n children,\n Component,\n description,\n getBaseProps,\n getControlProps,\n getInputProps,\n getLabelProps,\n getLabelWrapperProps,\n getWrapperProps,\n isDisabled,\n } = useRadio(props as HeroRadioProps);\n\n // classNames from slots\n const variants = radioBoxVariants({\n isDisabled,\n isInvalid,\n });\n const classNames = variantsToClassNames(\n variants,\n // @ts-expect-error not sure here, but it works\n _classNames,\n 'base',\n );\n\n return (\n <Component {...getBaseProps()} className={classNames.base}>\n <VisuallyHidden>\n <input {...getInputProps()} />\n </VisuallyHidden>\n {!icon ? (\n <span {...getWrapperProps()}>\n <span\n {...getControlProps()}\n className={cn(getControlProps().className, classNames.control)}\n />\n </span>\n ) : null}\n {icon ? <div className={classNames.icon}>{icon}</div> : null}\n <div\n {...getLabelWrapperProps()}\n className={cn(\n getLabelWrapperProps().className,\n classNames.labelWrapper,\n )}\n >\n {children ? (\n <span\n {...getLabelProps()}\n className={cn(getLabelProps().className, classNames.label)}\n >\n {children}\n </span>\n ) : null}\n {description ? (\n <div className={classNames.description}>{description}</div>\n ) : null}\n </div>\n {icon ? (\n <span {...getWrapperProps()}>\n <span\n {...getControlProps()}\n className={cn(getControlProps().className, classNames.control)}\n />\n </span>\n ) : null}\n </Component>\n );\n};\n\nexport default RadioBox;\n","import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { ReactNode } from 'react';\n//\nimport type { RadioBoxProps } from './RadioBox';\n\nimport { RadioGroup as HeroRadioGroup } from '@heroui/radio';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\nimport { RadioBox } from './RadioBox';\n\nexport const radioBoxesVariants = tv({\n slots: {\n base: [\n // Needs group for group-data condition.\n 'group',\n // Match shared field wrapper layout.\n 'flex w-full flex-col',\n // Keep spacing between label/radio boxes consistent.\n 'gap-y-1.5',\n ],\n boxBase: '',\n boxControl: '',\n boxDescription: '',\n boxLabel: '',\n boxLabelWrapper: '',\n // see HeroUI styles for group-data condition,\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/core/theme/src/components/select.ts\n label:\n 'mb-2 inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n wrapper: '',\n },\n});\n\ntype VariantProps = TVProps<typeof radioBoxesVariants>;\ntype ClassName = TVClassName<typeof radioBoxesVariants>;\n\nexport interface RadioBoxOption {\n /** Description of the value. Works with variant radioBox. */\n description?: ReactNode;\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number;\n}\n\nexport interface RadioBoxesProps extends VariantProps {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioBoxOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n}\n\n/**\n * RadioBoxes component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n */\nconst RadioBoxes = ({\n className = undefined,\n inline = false,\n name,\n options,\n ...uniformFieldProps\n}: RadioBoxesProps) => {\n const {\n ariaLabel,\n errorMessage,\n invalid,\n disabled,\n label,\n field: { onBlur, onChange, ref, value },\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n // classNames from slots\n const variants = radioBoxesVariants();\n const classNames = variantsToClassNames(variants, className, 'base');\n const boxClassNames: RadioBoxProps['classNames'] = {\n base: classNames.boxBase,\n control: classNames.boxControl,\n description: classNames.boxDescription,\n label: classNames.boxLabel,\n labelWrapper: classNames.boxLabelWrapper,\n };\n\n return (\n <HeroRadioGroup\n ref={ref}\n aria-label={ariaLabel}\n classNames={classNames}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={name}\n onBlur={onBlur}\n onValueChange={(newValue) => {\n onChange(convertToOriginalType(newValue));\n }}\n orientation={inline ? 'horizontal' : 'vertical'}\n value={value != null ? String(value) : ''}\n >\n {options.map((option) => {\n if ('value' in option) {\n const optionTestId = slugify(\n `${testId}_option_${option.testId ?? option.value}`,\n { replaceDots: true },\n );\n return (\n <RadioBox\n key={String(option.value)}\n classNames={boxClassNames}\n data-testid={optionTestId}\n description={option.description}\n icon={option.icon}\n isDisabled={!!disabled || option.disabled}\n isInvalid={invalid}\n value={String(option.value)}\n >\n {option.label ?? option.value}\n </RadioBox>\n );\n }\n return null;\n })}\n </HeroRadioGroup>\n );\n};\n\nexport default RadioBoxes;\n","import RadioBoxes from './RadioBoxes';\n\nexport type { RadioBoxesProps, RadioBoxOption } from './RadioBoxes';\n\nexport { radioBoxVariants } from './RadioBox';\n\nexport default RadioBoxes;\n"],"mappings":"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"}
@@ -15,9 +15,13 @@ _fuf_stack_pixels_Tabs = require_FormContext.__toESM(_fuf_stack_pixels_Tabs);
15
15
  //#region src/RadioTabs/RadioTabs.tsx
16
16
  const radioTabsVariants = (0, _fuf_stack_pixel_utils.tv)({
17
17
  slots: {
18
- base: "group gap-0",
18
+ base: [
19
+ "group",
20
+ "flex w-full flex-col",
21
+ "gap-y-1.5"
22
+ ],
19
23
  cursor: "",
20
- label: "mb-2 inline-flex text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger",
24
+ label: "mb-2 inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger",
21
25
  tab: "",
22
26
  tabBase: "",
23
27
  tabContent: "",
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["useUniformField","createOptionValueConverter","VisuallyHidden","HeroRadioGroup","Tabs"],"sources":["../../src/RadioTabs/RadioTabs.tsx","../../src/RadioTabs/index.ts"],"sourcesContent":["import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { TabsProps } from '@fuf-stack/pixels';\nimport type { TabProps } from '@fuf-stack/pixels/Tabs';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport { useRef } from 'react';\n\nimport { RadioGroup as HeroRadioGroup } from '@heroui/radio';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\nimport Tabs from '@fuf-stack/pixels/Tabs';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\n\nexport const radioTabsVariants = tv({\n slots: {\n base: 'group gap-0', // Needs group for group-data condition\n cursor: '',\n label:\n 'mb-2 inline-flex text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n tab: '',\n tabBase: '',\n tabContent: '',\n tabList: '',\n tabPanel: 'p-3',\n tabWrapper: '',\n wrapper: '',\n },\n variants: {\n hasContent: {\n true: {\n base: '',\n tabBase: 'p-1',\n tabWrapper: [\n // border style\n 'rounded-medium border border-divider',\n // full width\n 'w-full',\n ],\n },\n },\n fullWidth: {\n true: {\n tabWrapper: 'w-full',\n },\n },\n isInvalid: {\n true: {\n tabWrapper: 'rounded-medium border-2 !border-danger',\n },\n },\n },\n});\n\ntype VariantProps = TVProps<typeof radioTabsVariants>;\ntype ClassName = TVClassName<typeof radioTabsVariants>;\n\nexport interface RadioTabOption {\n /** Optional content inside of the tab */\n content?: ReactNode;\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number | boolean;\n}\n\nexport interface RadioTabsProps extends Omit<VariantProps, 'hasContent'> {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** Whether tabs should take up full container width */\n fullWidth?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioTabOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n /** How the RadioTabs should look like. */\n variant?: TabsProps['variant'];\n}\n\n/**\n * RadioTabs component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n * and [HeroUI Tabs](https://www.heroui.com//docs/components/tabs)\n */\nconst RadioTabs = ({\n className = undefined,\n fullWidth = false,\n inline = false,\n name,\n options,\n variant = undefined,\n ...uniformFieldProps\n}: RadioTabsProps): ReactElement => {\n const {\n ariaLabel,\n disabled,\n errorMessage,\n field: { onBlur, onChange, ref, value },\n invalid,\n label,\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create a ref for the visual radio group to forward focus\n const visualRadioGroupRef = useRef<HTMLDivElement>(null);\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n const tabOptions = options.map<TabProps>((option) => {\n return {\n content: option?.content,\n disabled: option?.disabled,\n // Tabs component uses string keys internally\n key: String(option.value),\n label: option?.label ?? option?.value,\n testId: slugify(`option_${option?.testId ?? option?.value}`, {\n replaceDots: true,\n }),\n };\n });\n\n const disabledAllKeys: string[] | undefined = tabOptions?.map((option) => {\n return option.key as string;\n });\n\n // check if any option has content\n // eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/promise-function-async\n const hasContent = options.some((option) => {\n return option.content;\n });\n\n // classNames from slots\n const variants = radioTabsVariants({\n fullWidth,\n hasContent,\n isInvalid: invalid,\n });\n const classNames = variantsToClassNames(variants, className, 'base');\n\n return (\n <>\n {/* Visually hidden input for React Hook Form focus management */}\n <VisuallyHidden>\n <input\n ref={ref}\n aria-label={ariaLabel}\n name={name}\n onBlur={onBlur}\n onChange={(e) => {\n onChange(convertToOriginalType(e.target.value));\n }}\n onFocus={() => {\n // Forward focus to the first tab when RHF focuses this input\n const firstTab = visualRadioGroupRef.current?.querySelector(\n '[role=\"tab\"]',\n ) as HTMLElement;\n firstTab?.focus();\n }}\n value={value ?? ''}\n />\n </VisuallyHidden>\n\n <HeroRadioGroup\n ref={visualRadioGroupRef}\n aria-label={ariaLabel}\n classNames={{\n base: classNames.base,\n label: classNames.label,\n wrapper: classNames.wrapper,\n }}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={`${name}_radiotabs`}\n orientation={inline ? 'horizontal' : 'vertical'}\n >\n <Tabs\n className={{\n base: classNames.tabBase,\n cursor: classNames.cursor,\n panel: classNames.tabPanel,\n tab: classNames.tab,\n tabContent: classNames.tabContent,\n tabList: classNames.tabList,\n tabWrapper: classNames.tabWrapper,\n }}\n disabledKeys={disabled ? disabledAllKeys : undefined}\n onSelectionChange={(key) => {\n if (key != null) {\n onChange(convertToOriginalType(key));\n }\n }}\n tabs={tabOptions}\n testId={testId}\n variant={variant}\n // make sure component is controlled (convert to string for Tabs)\n selectedKey={value != null ? String(value) : ''}\n />\n </HeroRadioGroup>\n </>\n );\n};\n\nexport default RadioTabs;\n","import RadioTabs from './RadioTabs';\n\nexport type { RadioTabsProps, RadioTabOption } from './RadioTabs';\n\nexport { radioTabsVariants } from './RadioTabs';\n\nexport default RadioTabs;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["useUniformField","createOptionValueConverter","VisuallyHidden","HeroRadioGroup","Tabs"],"sources":["../../src/RadioTabs/RadioTabs.tsx","../../src/RadioTabs/index.ts"],"sourcesContent":["import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { TabsProps } from '@fuf-stack/pixels';\nimport type { TabProps } from '@fuf-stack/pixels/Tabs';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport { useRef } from 'react';\n\nimport { RadioGroup as HeroRadioGroup } from '@heroui/radio';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\nimport Tabs from '@fuf-stack/pixels/Tabs';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\n\nexport const radioTabsVariants = tv({\n slots: {\n base: [\n // Needs group for group-data condition.\n 'group',\n // Match shared field wrapper layout.\n 'flex w-full flex-col',\n // Keep spacing between label/tabs consistent.\n 'gap-y-1.5',\n ],\n cursor: '',\n label:\n 'mb-2 inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n tab: '',\n tabBase: '',\n tabContent: '',\n tabList: '',\n tabPanel: 'p-3',\n tabWrapper: '',\n wrapper: '',\n },\n variants: {\n hasContent: {\n true: {\n base: '',\n tabBase: 'p-1',\n tabWrapper: [\n // border style\n 'rounded-medium border border-divider',\n // full width\n 'w-full',\n ],\n },\n },\n fullWidth: {\n true: {\n tabWrapper: 'w-full',\n },\n },\n isInvalid: {\n true: {\n tabWrapper: 'rounded-medium border-2 !border-danger',\n },\n },\n },\n});\n\ntype VariantProps = TVProps<typeof radioTabsVariants>;\ntype ClassName = TVClassName<typeof radioTabsVariants>;\n\nexport interface RadioTabOption {\n /** Optional content inside of the tab */\n content?: ReactNode;\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number | boolean;\n}\n\nexport interface RadioTabsProps extends Omit<VariantProps, 'hasContent'> {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** Whether tabs should take up full container width */\n fullWidth?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioTabOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n /** How the RadioTabs should look like. */\n variant?: TabsProps['variant'];\n}\n\n/**\n * RadioTabs component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n * and [HeroUI Tabs](https://www.heroui.com//docs/components/tabs)\n */\nconst RadioTabs = ({\n className = undefined,\n fullWidth = false,\n inline = false,\n name,\n options,\n variant = undefined,\n ...uniformFieldProps\n}: RadioTabsProps): ReactElement => {\n const {\n ariaLabel,\n disabled,\n errorMessage,\n field: { onBlur, onChange, ref, value },\n invalid,\n label,\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create a ref for the visual radio group to forward focus\n const visualRadioGroupRef = useRef<HTMLDivElement>(null);\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n const tabOptions = options.map<TabProps>((option) => {\n return {\n content: option?.content,\n disabled: option?.disabled,\n // Tabs component uses string keys internally\n key: String(option.value),\n label: option?.label ?? option?.value,\n testId: slugify(`option_${option?.testId ?? option?.value}`, {\n replaceDots: true,\n }),\n };\n });\n\n const disabledAllKeys: string[] | undefined = tabOptions?.map((option) => {\n return option.key as string;\n });\n\n // check if any option has content\n // eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/promise-function-async\n const hasContent = options.some((option) => {\n return option.content;\n });\n\n // classNames from slots\n const variants = radioTabsVariants({\n fullWidth,\n hasContent,\n isInvalid: invalid,\n });\n const classNames = variantsToClassNames(variants, className, 'base');\n\n return (\n <>\n {/* Visually hidden input for React Hook Form focus management */}\n <VisuallyHidden>\n <input\n ref={ref}\n aria-label={ariaLabel}\n name={name}\n onBlur={onBlur}\n onChange={(e) => {\n onChange(convertToOriginalType(e.target.value));\n }}\n onFocus={() => {\n // Forward focus to the first tab when RHF focuses this input\n const firstTab = visualRadioGroupRef.current?.querySelector(\n '[role=\"tab\"]',\n ) as HTMLElement;\n firstTab?.focus();\n }}\n value={value ?? ''}\n />\n </VisuallyHidden>\n\n <HeroRadioGroup\n ref={visualRadioGroupRef}\n aria-label={ariaLabel}\n classNames={{\n base: classNames.base,\n label: classNames.label,\n wrapper: classNames.wrapper,\n }}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={`${name}_radiotabs`}\n orientation={inline ? 'horizontal' : 'vertical'}\n >\n <Tabs\n className={{\n base: classNames.tabBase,\n cursor: classNames.cursor,\n panel: classNames.tabPanel,\n tab: classNames.tab,\n tabContent: classNames.tabContent,\n tabList: classNames.tabList,\n tabWrapper: classNames.tabWrapper,\n }}\n disabledKeys={disabled ? disabledAllKeys : undefined}\n onSelectionChange={(key) => {\n if (key != null) {\n onChange(convertToOriginalType(key));\n }\n }}\n tabs={tabOptions}\n testId={testId}\n variant={variant}\n // make sure component is controlled (convert to string for Tabs)\n selectedKey={value != null ? String(value) : ''}\n />\n </HeroRadioGroup>\n </>\n );\n};\n\nexport default RadioTabs;\n","import RadioTabs from './RadioTabs';\n\nexport type { RadioTabsProps, RadioTabOption } from './RadioTabs';\n\nexport { radioTabsVariants } from './RadioTabs';\n\nexport default RadioTabs;\n"],"mappings":"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"}
@@ -361,7 +361,7 @@ declare const radioTabsVariants: ((props?: ({
361
361
  extend: undefined;
362
362
  base: undefined;
363
363
  slots: {
364
- base: string;
364
+ base: string[];
365
365
  cursor: string;
366
366
  label: string;
367
367
  tab: string;
@@ -446,7 +446,7 @@ declare const radioTabsVariants: ((props?: ({
446
446
  };
447
447
  base: undefined;
448
448
  slots: {
449
- base: string;
449
+ base: string[];
450
450
  cursor: string;
451
451
  label: string;
452
452
  tab: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/RadioTabs/RadioTabs.tsx"],"mappings":";;;;;cAgBa,iBAAA,IAAiB,KAAA;;;;;gbAsC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;obAGY;;;;wbAAuC;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mbAqCzC;obAAS;mbAAA;kbAwIpB;sbAAA;qbAAA;sbAjIkB;ybAAA;sbAAA;ubAAA;ybAAA;IAAA;;;;ubAiIlB;obAjIkB;mbAAA;kbAAA;sbAAA;qbAAA;sbAAA;ybAAA;sbAAA;ubAAA;ybAAA;IAAA;EAAA;;;;;;;;;;;;;;;;KA7Cd,YAAA,GAAe,OAAO,QAAQ,iBAAA;AAAA,KAC9B,SAAA,GAAY,WAAW,QAAQ,iBAAA;AAAA,UAEnB,cAAA;;EAEf,OAAA,GAAU,SAAA;;EAEV,QAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA,GAAO,SAAA;;EAEP,MAAA;;EAEA,KAAA;AAAA;AAAA,UAGe,cAAA,SAAuB,IAAA,CAAK,YAAA;;EAE3C,SAAA;;EAEA,SAAA,GAAY,SAAA;;EAEZ,QAAA;;EAEA,SAAA;;EAEA,MAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA;;EAEA,OAAA,EAAS,cAAA;;EAET,MAAA;;EAEA,OAAA,GAAU,SAAA;AAAA;;;;;cAON,SAAA;EAAa,SAAA;EAAA,SAAA;EAAA,MAAA;EAAA,IAAA;EAAA,OAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAQhB,cAAA,KAAiB,YAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/RadioTabs/RadioTabs.tsx"],"mappings":";;;;;cAgBa,iBAAA,IAAiB,KAAA;;;;;gbA6C5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;obAGY;;;;wbAAuC;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mbAqCzC;obAAS;mbAAA;kbAwIpB;sbAAA;qbAAA;sbAjIkB;ybAAA;sbAAA;ubAAA;ybAAA;IAAA;;;;ubAiIlB;obAjIkB;mbAAA;kbAAA;sbAAA;qbAAA;sbAAA;ybAAA;sbAAA;ubAAA;ybAAA;IAAA;EAAA;;;;;;;;;;;;;;;;KA7Cd,YAAA,GAAe,OAAO,QAAQ,iBAAA;AAAA,KAC9B,SAAA,GAAY,WAAW,QAAQ,iBAAA;AAAA,UAEnB,cAAA;;EAEf,OAAA,GAAU,SAAA;;EAEV,QAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA,GAAO,SAAA;;EAEP,MAAA;;EAEA,KAAA;AAAA;AAAA,UAGe,cAAA,SAAuB,IAAA,CAAK,YAAA;;EAE3C,SAAA;;EAEA,SAAA,GAAY,SAAA;;EAEZ,QAAA;;EAEA,SAAA;;EAEA,MAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA;;EAEA,OAAA,EAAS,cAAA;;EAET,MAAA;;EAEA,OAAA,GAAU,SAAA;AAAA;;;;;cAON,SAAA;EAAa,SAAA;EAAA,SAAA;EAAA,MAAA;EAAA,IAAA;EAAA,OAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAQhB,cAAA,KAAiB,YAAA"}
@@ -361,7 +361,7 @@ declare const radioTabsVariants: ((props?: ({
361
361
  extend: undefined;
362
362
  base: undefined;
363
363
  slots: {
364
- base: string;
364
+ base: string[];
365
365
  cursor: string;
366
366
  label: string;
367
367
  tab: string;
@@ -446,7 +446,7 @@ declare const radioTabsVariants: ((props?: ({
446
446
  };
447
447
  base: undefined;
448
448
  slots: {
449
- base: string;
449
+ base: string[];
450
450
  cursor: string;
451
451
  label: string;
452
452
  tab: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/RadioTabs/RadioTabs.tsx"],"mappings":";;;;;cAgBa,iBAAA,IAAiB,KAAA;;;;;gbAsC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;obAGY;;;;wbAAuC;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mbAqCzC;obAAS;mbAAA;kbAwIpB;sbAAA;qbAAA;sbAjIkB;ybAAA;sbAAA;ubAAA;ybAAA;IAAA;;;;ubAiIlB;obAjIkB;mbAAA;kbAAA;sbAAA;qbAAA;sbAAA;ybAAA;sbAAA;ubAAA;ybAAA;IAAA;EAAA;;;;;;;;;;;;;;;;KA7Cd,YAAA,GAAe,OAAO,QAAQ,iBAAA;AAAA,KAC9B,SAAA,GAAY,WAAW,QAAQ,iBAAA;AAAA,UAEnB,cAAA;;EAEf,OAAA,GAAU,SAAA;;EAEV,QAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA,GAAO,SAAA;;EAEP,MAAA;;EAEA,KAAA;AAAA;AAAA,UAGe,cAAA,SAAuB,IAAA,CAAK,YAAA;;EAE3C,SAAA;;EAEA,SAAA,GAAY,SAAA;;EAEZ,QAAA;;EAEA,SAAA;;EAEA,MAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA;;EAEA,OAAA,EAAS,cAAA;;EAET,MAAA;;EAEA,OAAA,GAAU,SAAA;AAAA;;;;;cAON,SAAA;EAAa,SAAA;EAAA,SAAA;EAAA,MAAA;EAAA,IAAA;EAAA,OAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAQhB,cAAA,KAAiB,YAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/RadioTabs/RadioTabs.tsx"],"mappings":";;;;;cAgBa,iBAAA,IAAiB,KAAA;;;;;gbA6C5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;obAGY;;;;wbAAuC;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mbAqCzC;obAAS;mbAAA;kbAwIpB;sbAAA;qbAAA;sbAjIkB;ybAAA;sbAAA;ubAAA;ybAAA;IAAA;;;;ubAiIlB;obAjIkB;mbAAA;kbAAA;sbAAA;qbAAA;sbAAA;ybAAA;sbAAA;ubAAA;ybAAA;IAAA;EAAA;;;;;;;;;;;;;;;;KA7Cd,YAAA,GAAe,OAAO,QAAQ,iBAAA;AAAA,KAC9B,SAAA,GAAY,WAAW,QAAQ,iBAAA;AAAA,UAEnB,cAAA;;EAEf,OAAA,GAAU,SAAA;;EAEV,QAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA,GAAO,SAAA;;EAEP,MAAA;;EAEA,KAAA;AAAA;AAAA,UAGe,cAAA,SAAuB,IAAA,CAAK,YAAA;;EAE3C,SAAA;;EAEA,SAAA,GAAY,SAAA;;EAEZ,QAAA;;EAEA,SAAA;;EAEA,MAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA;;EAEA,OAAA,EAAS,cAAA;;EAET,MAAA;;EAEA,OAAA,GAAU,SAAA;AAAA;;;;;cAON,SAAA;EAAa,SAAA;EAAA,SAAA;EAAA,MAAA;EAAA,IAAA;EAAA,OAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAQhB,cAAA,KAAiB,YAAA"}
@@ -9,9 +9,13 @@ import Tabs from "@fuf-stack/pixels/Tabs";
9
9
  //#region src/RadioTabs/RadioTabs.tsx
10
10
  const radioTabsVariants = tv({
11
11
  slots: {
12
- base: "group gap-0",
12
+ base: [
13
+ "group",
14
+ "flex w-full flex-col",
15
+ "gap-y-1.5"
16
+ ],
13
17
  cursor: "",
14
- label: "mb-2 inline-flex text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger",
18
+ label: "mb-2 inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger",
15
19
  tab: "",
16
20
  tabBase: "",
17
21
  tabContent: "",
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["HeroRadioGroup"],"sources":["../../src/RadioTabs/RadioTabs.tsx","../../src/RadioTabs/index.ts"],"sourcesContent":["import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { TabsProps } from '@fuf-stack/pixels';\nimport type { TabProps } from '@fuf-stack/pixels/Tabs';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport { useRef } from 'react';\n\nimport { RadioGroup as HeroRadioGroup } from '@heroui/radio';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\nimport Tabs from '@fuf-stack/pixels/Tabs';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\n\nexport const radioTabsVariants = tv({\n slots: {\n base: 'group gap-0', // Needs group for group-data condition\n cursor: '',\n label:\n 'mb-2 inline-flex text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n tab: '',\n tabBase: '',\n tabContent: '',\n tabList: '',\n tabPanel: 'p-3',\n tabWrapper: '',\n wrapper: '',\n },\n variants: {\n hasContent: {\n true: {\n base: '',\n tabBase: 'p-1',\n tabWrapper: [\n // border style\n 'rounded-medium border border-divider',\n // full width\n 'w-full',\n ],\n },\n },\n fullWidth: {\n true: {\n tabWrapper: 'w-full',\n },\n },\n isInvalid: {\n true: {\n tabWrapper: 'rounded-medium border-2 !border-danger',\n },\n },\n },\n});\n\ntype VariantProps = TVProps<typeof radioTabsVariants>;\ntype ClassName = TVClassName<typeof radioTabsVariants>;\n\nexport interface RadioTabOption {\n /** Optional content inside of the tab */\n content?: ReactNode;\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number | boolean;\n}\n\nexport interface RadioTabsProps extends Omit<VariantProps, 'hasContent'> {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** Whether tabs should take up full container width */\n fullWidth?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioTabOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n /** How the RadioTabs should look like. */\n variant?: TabsProps['variant'];\n}\n\n/**\n * RadioTabs component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n * and [HeroUI Tabs](https://www.heroui.com//docs/components/tabs)\n */\nconst RadioTabs = ({\n className = undefined,\n fullWidth = false,\n inline = false,\n name,\n options,\n variant = undefined,\n ...uniformFieldProps\n}: RadioTabsProps): ReactElement => {\n const {\n ariaLabel,\n disabled,\n errorMessage,\n field: { onBlur, onChange, ref, value },\n invalid,\n label,\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create a ref for the visual radio group to forward focus\n const visualRadioGroupRef = useRef<HTMLDivElement>(null);\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n const tabOptions = options.map<TabProps>((option) => {\n return {\n content: option?.content,\n disabled: option?.disabled,\n // Tabs component uses string keys internally\n key: String(option.value),\n label: option?.label ?? option?.value,\n testId: slugify(`option_${option?.testId ?? option?.value}`, {\n replaceDots: true,\n }),\n };\n });\n\n const disabledAllKeys: string[] | undefined = tabOptions?.map((option) => {\n return option.key as string;\n });\n\n // check if any option has content\n // eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/promise-function-async\n const hasContent = options.some((option) => {\n return option.content;\n });\n\n // classNames from slots\n const variants = radioTabsVariants({\n fullWidth,\n hasContent,\n isInvalid: invalid,\n });\n const classNames = variantsToClassNames(variants, className, 'base');\n\n return (\n <>\n {/* Visually hidden input for React Hook Form focus management */}\n <VisuallyHidden>\n <input\n ref={ref}\n aria-label={ariaLabel}\n name={name}\n onBlur={onBlur}\n onChange={(e) => {\n onChange(convertToOriginalType(e.target.value));\n }}\n onFocus={() => {\n // Forward focus to the first tab when RHF focuses this input\n const firstTab = visualRadioGroupRef.current?.querySelector(\n '[role=\"tab\"]',\n ) as HTMLElement;\n firstTab?.focus();\n }}\n value={value ?? ''}\n />\n </VisuallyHidden>\n\n <HeroRadioGroup\n ref={visualRadioGroupRef}\n aria-label={ariaLabel}\n classNames={{\n base: classNames.base,\n label: classNames.label,\n wrapper: classNames.wrapper,\n }}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={`${name}_radiotabs`}\n orientation={inline ? 'horizontal' : 'vertical'}\n >\n <Tabs\n className={{\n base: classNames.tabBase,\n cursor: classNames.cursor,\n panel: classNames.tabPanel,\n tab: classNames.tab,\n tabContent: classNames.tabContent,\n tabList: classNames.tabList,\n tabWrapper: classNames.tabWrapper,\n }}\n disabledKeys={disabled ? disabledAllKeys : undefined}\n onSelectionChange={(key) => {\n if (key != null) {\n onChange(convertToOriginalType(key));\n }\n }}\n tabs={tabOptions}\n testId={testId}\n variant={variant}\n // make sure component is controlled (convert to string for Tabs)\n selectedKey={value != null ? String(value) : ''}\n />\n </HeroRadioGroup>\n </>\n );\n};\n\nexport default RadioTabs;\n","import RadioTabs from './RadioTabs';\n\nexport type { RadioTabsProps, RadioTabOption } from './RadioTabs';\n\nexport { radioTabsVariants } from './RadioTabs';\n\nexport default RadioTabs;\n"],"mappings":";;;;;;;;;AAgBA,MAAa,oBAAoB,GAAG;CAClC,OAAO;EACL,MAAM;EACN,QAAQ;EACR,OACE;EACF,KAAK;EACL,SAAS;EACT,YAAY;EACZ,SAAS;EACT,UAAU;EACV,YAAY;EACZ,SAAS;CACX;CACA,UAAU;EACR,YAAY,EACV,MAAM;GACJ,MAAM;GACN,SAAS;GACT,YAAY,CAEV,wCAEA,QACF;EACF,EACF;EACA,WAAW,EACT,MAAM,EACJ,YAAY,SACd,EACF;EACA,WAAW,EACT,MAAM,EACJ,YAAY,yCACd,EACF;CACF;AACF,CAAC;;;;;AA+CD,MAAM,aAAa,EACjB,YAAY,KAAA,GACZ,YAAY,OACZ,SAAS,OACT,MACA,SACA,UAAU,KAAA,GACV,GAAG,wBAC+B;CAClC,MAAM,EACJ,WACA,UACA,cACA,OAAO,EAAE,QAAQ,UAAU,KAAK,SAChC,SACA,OACA,UACA,WACE,gBAAgB;EAClB;EACA,GAAG;CACL,CAAC;CAGD,MAAM,sBAAsB,OAAuB,IAAI;CAGvD,MAAM,EAAE,0BAA0B,2BAA2B,OAAO;CAEpE,MAAM,aAAa,QAAQ,KAAe,WAAW;EACnD,OAAO;GACL,SAAS,QAAQ;GACjB,UAAU,QAAQ;GAElB,KAAK,OAAO,OAAO,KAAK;GACxB,OAAO,QAAQ,SAAS,QAAQ;GAChC,QAAQ,QAAQ,UAAU,QAAQ,UAAU,QAAQ,SAAS,EAC3D,aAAa,KACf,CAAC;EACH;CACF,CAAC;CAED,MAAM,kBAAwC,YAAY,KAAK,WAAW;EACxE,OAAO,OAAO;CAChB,CAAC;CAcD,MAAM,aAAa,qBALF,kBAAkB;EACjC;EACA,YAPiB,QAAQ,MAAM,WAAW;GAC1C,OAAO,OAAO;EAChB,CAKW;EACT,WAAW;CACb,CAC+C,GAAG,WAAW,MAAM;CAEnE,OACE,qBAAA,UAAA,EAAA,UAAA,CAEE,oBAAC,gBAAD,EAAA,UACE,oBAAC,SAAD;EACO;EACL,cAAY;EACN;EACE;EACR,WAAW,MAAM;GACf,SAAS,sBAAsB,EAAE,OAAO,KAAK,CAAC;EAChD;EACA,eAAe;GAKb,CAHiB,oBAAoB,SAAS,cAC5C,gBACF,IACU,MAAM;EAClB;EACA,OAAO,SAAS;CACjB,CAAA,EACa,CAAA,GAEhB,oBAACA,YAAD;EACE,KAAK;EACL,cAAY;EACZ,YAAY;GACV,MAAM,WAAW;GACjB,OAAO,WAAW;GAClB,SAAS,WAAW;EACtB;EAGA,gBAAc;EACd,iBAAe;EACf,eAAa;EACC;EACd,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,OAAO,QAAQ,oBAAC,UAAD,EAAA,UAAS,MAAc,CAAA,IAAI;EAC1C,MAAM,GAAG,KAAK;EACd,aAAa,SAAS,eAAe;YAErC,oBAAC,MAAD;GACE,WAAW;IACT,MAAM,WAAW;IACjB,QAAQ,WAAW;IACnB,OAAO,WAAW;IAClB,KAAK,WAAW;IAChB,YAAY,WAAW;IACvB,SAAS,WAAW;IACpB,YAAY,WAAW;GACzB;GACA,cAAc,WAAW,kBAAkB,KAAA;GAC3C,oBAAoB,QAAQ;IAC1B,IAAI,OAAO,MACT,SAAS,sBAAsB,GAAG,CAAC;GAEvC;GACA,MAAM;GACE;GACC;GAET,aAAa,SAAS,OAAO,OAAO,KAAK,IAAI;EAC9C,CAAA;CACa,CAAA,CAChB,EAAA,CAAA;AAEN;;;AChOA,IAAA,oBAAe"}
1
+ {"version":3,"file":"index.js","names":["HeroRadioGroup"],"sources":["../../src/RadioTabs/RadioTabs.tsx","../../src/RadioTabs/index.ts"],"sourcesContent":["import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { TabsProps } from '@fuf-stack/pixels';\nimport type { TabProps } from '@fuf-stack/pixels/Tabs';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport { useRef } from 'react';\n\nimport { RadioGroup as HeroRadioGroup } from '@heroui/radio';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\nimport Tabs from '@fuf-stack/pixels/Tabs';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\n\nexport const radioTabsVariants = tv({\n slots: {\n base: [\n // Needs group for group-data condition.\n 'group',\n // Match shared field wrapper layout.\n 'flex w-full flex-col',\n // Keep spacing between label/tabs consistent.\n 'gap-y-1.5',\n ],\n cursor: '',\n label:\n 'mb-2 inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n tab: '',\n tabBase: '',\n tabContent: '',\n tabList: '',\n tabPanel: 'p-3',\n tabWrapper: '',\n wrapper: '',\n },\n variants: {\n hasContent: {\n true: {\n base: '',\n tabBase: 'p-1',\n tabWrapper: [\n // border style\n 'rounded-medium border border-divider',\n // full width\n 'w-full',\n ],\n },\n },\n fullWidth: {\n true: {\n tabWrapper: 'w-full',\n },\n },\n isInvalid: {\n true: {\n tabWrapper: 'rounded-medium border-2 !border-danger',\n },\n },\n },\n});\n\ntype VariantProps = TVProps<typeof radioTabsVariants>;\ntype ClassName = TVClassName<typeof radioTabsVariants>;\n\nexport interface RadioTabOption {\n /** Optional content inside of the tab */\n content?: ReactNode;\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number | boolean;\n}\n\nexport interface RadioTabsProps extends Omit<VariantProps, 'hasContent'> {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** Whether tabs should take up full container width */\n fullWidth?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioTabOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n /** How the RadioTabs should look like. */\n variant?: TabsProps['variant'];\n}\n\n/**\n * RadioTabs component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n * and [HeroUI Tabs](https://www.heroui.com//docs/components/tabs)\n */\nconst RadioTabs = ({\n className = undefined,\n fullWidth = false,\n inline = false,\n name,\n options,\n variant = undefined,\n ...uniformFieldProps\n}: RadioTabsProps): ReactElement => {\n const {\n ariaLabel,\n disabled,\n errorMessage,\n field: { onBlur, onChange, ref, value },\n invalid,\n label,\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create a ref for the visual radio group to forward focus\n const visualRadioGroupRef = useRef<HTMLDivElement>(null);\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n const tabOptions = options.map<TabProps>((option) => {\n return {\n content: option?.content,\n disabled: option?.disabled,\n // Tabs component uses string keys internally\n key: String(option.value),\n label: option?.label ?? option?.value,\n testId: slugify(`option_${option?.testId ?? option?.value}`, {\n replaceDots: true,\n }),\n };\n });\n\n const disabledAllKeys: string[] | undefined = tabOptions?.map((option) => {\n return option.key as string;\n });\n\n // check if any option has content\n // eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/promise-function-async\n const hasContent = options.some((option) => {\n return option.content;\n });\n\n // classNames from slots\n const variants = radioTabsVariants({\n fullWidth,\n hasContent,\n isInvalid: invalid,\n });\n const classNames = variantsToClassNames(variants, className, 'base');\n\n return (\n <>\n {/* Visually hidden input for React Hook Form focus management */}\n <VisuallyHidden>\n <input\n ref={ref}\n aria-label={ariaLabel}\n name={name}\n onBlur={onBlur}\n onChange={(e) => {\n onChange(convertToOriginalType(e.target.value));\n }}\n onFocus={() => {\n // Forward focus to the first tab when RHF focuses this input\n const firstTab = visualRadioGroupRef.current?.querySelector(\n '[role=\"tab\"]',\n ) as HTMLElement;\n firstTab?.focus();\n }}\n value={value ?? ''}\n />\n </VisuallyHidden>\n\n <HeroRadioGroup\n ref={visualRadioGroupRef}\n aria-label={ariaLabel}\n classNames={{\n base: classNames.base,\n label: classNames.label,\n wrapper: classNames.wrapper,\n }}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={`${name}_radiotabs`}\n orientation={inline ? 'horizontal' : 'vertical'}\n >\n <Tabs\n className={{\n base: classNames.tabBase,\n cursor: classNames.cursor,\n panel: classNames.tabPanel,\n tab: classNames.tab,\n tabContent: classNames.tabContent,\n tabList: classNames.tabList,\n tabWrapper: classNames.tabWrapper,\n }}\n disabledKeys={disabled ? disabledAllKeys : undefined}\n onSelectionChange={(key) => {\n if (key != null) {\n onChange(convertToOriginalType(key));\n }\n }}\n tabs={tabOptions}\n testId={testId}\n variant={variant}\n // make sure component is controlled (convert to string for Tabs)\n selectedKey={value != null ? String(value) : ''}\n />\n </HeroRadioGroup>\n </>\n );\n};\n\nexport default RadioTabs;\n","import RadioTabs from './RadioTabs';\n\nexport type { RadioTabsProps, RadioTabOption } from './RadioTabs';\n\nexport { radioTabsVariants } from './RadioTabs';\n\nexport default RadioTabs;\n"],"mappings":";;;;;;;;;AAgBA,MAAa,oBAAoB,GAAG;CAClC,OAAO;EACL,MAAM;GAEJ;GAEA;GAEA;EACF;EACA,QAAQ;EACR,OACE;EACF,KAAK;EACL,SAAS;EACT,YAAY;EACZ,SAAS;EACT,UAAU;EACV,YAAY;EACZ,SAAS;CACX;CACA,UAAU;EACR,YAAY,EACV,MAAM;GACJ,MAAM;GACN,SAAS;GACT,YAAY,CAEV,wCAEA,QACF;EACF,EACF;EACA,WAAW,EACT,MAAM,EACJ,YAAY,SACd,EACF;EACA,WAAW,EACT,MAAM,EACJ,YAAY,yCACd,EACF;CACF;AACF,CAAC;;;;;AA+CD,MAAM,aAAa,EACjB,YAAY,KAAA,GACZ,YAAY,OACZ,SAAS,OACT,MACA,SACA,UAAU,KAAA,GACV,GAAG,wBAC+B;CAClC,MAAM,EACJ,WACA,UACA,cACA,OAAO,EAAE,QAAQ,UAAU,KAAK,SAChC,SACA,OACA,UACA,WACE,gBAAgB;EAClB;EACA,GAAG;CACL,CAAC;CAGD,MAAM,sBAAsB,OAAuB,IAAI;CAGvD,MAAM,EAAE,0BAA0B,2BAA2B,OAAO;CAEpE,MAAM,aAAa,QAAQ,KAAe,WAAW;EACnD,OAAO;GACL,SAAS,QAAQ;GACjB,UAAU,QAAQ;GAElB,KAAK,OAAO,OAAO,KAAK;GACxB,OAAO,QAAQ,SAAS,QAAQ;GAChC,QAAQ,QAAQ,UAAU,QAAQ,UAAU,QAAQ,SAAS,EAC3D,aAAa,KACf,CAAC;EACH;CACF,CAAC;CAED,MAAM,kBAAwC,YAAY,KAAK,WAAW;EACxE,OAAO,OAAO;CAChB,CAAC;CAcD,MAAM,aAAa,qBALF,kBAAkB;EACjC;EACA,YAPiB,QAAQ,MAAM,WAAW;GAC1C,OAAO,OAAO;EAChB,CAKW;EACT,WAAW;CACb,CAC+C,GAAG,WAAW,MAAM;CAEnE,OACE,qBAAA,UAAA,EAAA,UAAA,CAEE,oBAAC,gBAAD,EAAA,UACE,oBAAC,SAAD;EACO;EACL,cAAY;EACN;EACE;EACR,WAAW,MAAM;GACf,SAAS,sBAAsB,EAAE,OAAO,KAAK,CAAC;EAChD;EACA,eAAe;GAKb,CAHiB,oBAAoB,SAAS,cAC5C,gBACF,IACU,MAAM;EAClB;EACA,OAAO,SAAS;CACjB,CAAA,EACa,CAAA,GAEhB,oBAACA,YAAD;EACE,KAAK;EACL,cAAY;EACZ,YAAY;GACV,MAAM,WAAW;GACjB,OAAO,WAAW;GAClB,SAAS,WAAW;EACtB;EAGA,gBAAc;EACd,iBAAe;EACf,eAAa;EACC;EACd,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,OAAO,QAAQ,oBAAC,UAAD,EAAA,UAAS,MAAc,CAAA,IAAI;EAC1C,MAAM,GAAG,KAAK;EACd,aAAa,SAAS,eAAe;YAErC,oBAAC,MAAD;GACE,WAAW;IACT,MAAM,WAAW;IACjB,QAAQ,WAAW;IACnB,OAAO,WAAW;IAClB,KAAK,WAAW;IAChB,YAAY,WAAW;IACvB,SAAS,WAAW;IACpB,YAAY,WAAW;GACzB;GACA,cAAc,WAAW,kBAAkB,KAAA;GAC3C,oBAAoB,QAAQ;IAC1B,IAAI,OAAO,MACT,SAAS,sBAAsB,GAAG,CAAC;GAEvC;GACA,MAAM;GACE;GACC;GAET,aAAa,SAAS,OAAO,OAAO,KAAK,IAAI;EAC9C,CAAA;CACa,CAAA,CAChB,EAAA,CAAA;AAEN;;;ACvOA,IAAA,oBAAe"}
@@ -9,14 +9,18 @@ let react_jsx_runtime = require("react/jsx-runtime");
9
9
  let _heroui_radio = require("@heroui/radio");
10
10
  //#region src/Radios/Radios.tsx
11
11
  const radiosVariants = (0, _fuf_stack_pixel_utils.tv)({ slots: {
12
- base: "group gap-0",
12
+ base: [
13
+ "group",
14
+ "flex w-full flex-col",
15
+ "gap-y-1.5"
16
+ ],
13
17
  itemBase: "",
14
18
  itemControl: "bg-focus group-data-[invalid=true]:bg-danger",
15
19
  itemDescription: "",
16
20
  itemLabel: "text-sm",
17
21
  itemLabelWrapper: "",
18
22
  itemWrapper: "group-data-[invalid=true]:border-danger! [&:not(group-data-[invalid=\"true\"]):not(group-data-[selected=\"false\"])]:border-focus",
19
- label: "mb-2 inline-flex text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger",
23
+ label: "mb-2 inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger",
20
24
  wrapper: ""
21
25
  } });
22
26
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["useUniformField","createOptionValueConverter","HeroRadioGroup","HeroRadio"],"sources":["../../src/Radios/Radios.tsx","../../src/Radios/index.ts"],"sourcesContent":["import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport {\n Radio as HeroRadio,\n RadioGroup as HeroRadioGroup,\n} from '@heroui/radio';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\n\nexport const radiosVariants = tv({\n slots: {\n // Needs group for group-data condition\n base: 'group gap-0',\n itemBase: '',\n itemControl: 'bg-focus group-data-[invalid=true]:bg-danger',\n itemDescription: '',\n itemLabel: 'text-sm',\n itemLabelWrapper: '',\n itemWrapper:\n 'group-data-[invalid=true]:border-danger! [&:not(group-data-[invalid=\"true\"]):not(group-data-[selected=\"false\"])]:border-focus',\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/core/theme/src/components/select.ts\n label:\n 'mb-2 inline-flex text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n wrapper: '',\n },\n});\n\ntype VariantProps = TVProps<typeof radiosVariants>;\ntype ClassName = TVClassName<typeof radiosVariants>;\n\nexport interface RadioOption {\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number;\n}\n\nexport interface RadiosProps extends VariantProps {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n}\n\n/**\n * Radios component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n */\nconst Radios = ({\n className = undefined,\n inline = false,\n name,\n options,\n ...uniformFieldProps\n}: RadiosProps): ReactElement => {\n const {\n ariaLabel,\n disabled,\n errorMessage,\n field: { onBlur, onChange, ref, value },\n invalid,\n label,\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n // classNames from slots\n const variants = radiosVariants();\n const classNames = variantsToClassNames(variants, className, 'base');\n\n const itemClassNames = {\n base: classNames.itemBase,\n control: classNames.itemControl,\n description: classNames.itemDescription,\n label: classNames.itemLabel,\n labelWrapper: classNames.itemLabelWrapper,\n wrapper: classNames.itemWrapper,\n };\n\n return (\n <HeroRadioGroup\n ref={ref}\n aria-label={ariaLabel}\n classNames={classNames}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={name}\n onBlur={onBlur}\n onValueChange={(newValue) => {\n onChange(convertToOriginalType(newValue));\n }}\n orientation={inline ? 'horizontal' : 'vertical'}\n value={value != null ? String(value) : ''}\n >\n {options.map((option) => {\n if ('value' in option) {\n const optionTestId = slugify(\n `${testId}_option_${option.testId ?? option.value}`,\n { replaceDots: true },\n );\n return (\n <HeroRadio\n key={String(option.value)}\n classNames={itemClassNames}\n data-testid={optionTestId}\n isDisabled={!!disabled || option.disabled}\n value={String(option.value)}\n >\n {option.label ?? option.value}\n </HeroRadio>\n );\n }\n return null;\n })}\n </HeroRadioGroup>\n );\n};\n\nexport default Radios;\n","import Radios from './Radios';\n\nexport type { RadiosProps, RadioOption } from './Radios';\n\nexport { radiosVariants } from './Radios';\n\nexport default Radios;\n"],"mappings":";;;;;;;;;;AAaA,MAAa,kBAAA,GAAA,uBAAA,IAAoB,EAC/B,OAAO;CAEL,MAAM;CACN,UAAU;CACV,aAAa;CACb,iBAAiB;CACjB,WAAW;CACX,kBAAkB;CAClB,aACE;CAEF,OACE;CACF,SAAS;AACX,EACF,CAAC;;;;AAwCD,MAAM,UAAU,EACd,YAAY,KAAA,GACZ,SAAS,OACT,MACA,SACA,GAAG,wBAC4B;CAC/B,MAAM,EACJ,WACA,UACA,cACA,OAAO,EAAE,QAAQ,UAAU,KAAK,SAChC,SACA,OACA,UACA,WACEA,oCAAAA,gBAAgB;EAClB;EACA,GAAG;CACL,CAAC;CAGD,MAAM,EAAE,0BAA0BC,sBAAAA,2BAA2B,OAAO;CAIpE,MAAM,cAAA,GAAA,uBAAA,sBADW,eAC8B,GAAG,WAAW,MAAM;CAEnE,MAAM,iBAAiB;EACrB,MAAM,WAAW;EACjB,SAAS,WAAW;EACpB,aAAa,WAAW;EACxB,OAAO,WAAW;EAClB,cAAc,WAAW;EACzB,SAAS,WAAW;CACtB;CAEA,OACE,iBAAA,GAAA,kBAAA,KAACC,cAAAA,YAAD;EACO;EACL,cAAY;EACA;EAGZ,gBAAc;EACd,iBAAe;EACf,eAAa;EACC;EACd,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,OAAO,QAAQ,iBAAA,GAAA,kBAAA,KAAC,UAAD,EAAA,UAAS,MAAc,CAAA,IAAI;EACpC;EACE;EACR,gBAAgB,aAAa;GAC3B,SAAS,sBAAsB,QAAQ,CAAC;EAC1C;EACA,aAAa,SAAS,eAAe;EACrC,OAAO,SAAS,OAAO,OAAO,KAAK,IAAI;YAEtC,QAAQ,KAAK,WAAW;GACvB,IAAI,WAAW,QAKb,OACE,iBAAA,GAAA,kBAAA,KAACC,cAAAA,OAAD;IAEE,YAAY;IACZ,gBAAA,GAAA,uBAAA,SAPF,GAAG,OAAO,UAAU,OAAO,UAAU,OAAO,SAC5C,EAAE,aAAa,KAAK,CAMM;IACxB,YAAY,CAAC,CAAC,YAAY,OAAO;IACjC,OAAO,OAAO,OAAO,KAAK;cAEzB,OAAO,SAAS,OAAO;GACf,GAPJ,OAAO,OAAO,KAAK,CAOf;GAGf,OAAO;EACT,CAAC;CACa,CAAA;AAEpB;;;ACjJA,IAAA,iBAAe"}
1
+ {"version":3,"file":"index.cjs","names":["useUniformField","createOptionValueConverter","HeroRadioGroup","HeroRadio"],"sources":["../../src/Radios/Radios.tsx","../../src/Radios/index.ts"],"sourcesContent":["import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport {\n Radio as HeroRadio,\n RadioGroup as HeroRadioGroup,\n} from '@heroui/radio';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\n\nexport const radiosVariants = tv({\n slots: {\n base: [\n // Needs group for group-data condition.\n 'group',\n // Match shared field wrapper layout.\n 'flex w-full flex-col',\n // Keep spacing between label/group consistent.\n 'gap-y-1.5',\n ],\n itemBase: '',\n itemControl: 'bg-focus group-data-[invalid=true]:bg-danger',\n itemDescription: '',\n itemLabel: 'text-sm',\n itemLabelWrapper: '',\n itemWrapper:\n 'group-data-[invalid=true]:border-danger! [&:not(group-data-[invalid=\"true\"]):not(group-data-[selected=\"false\"])]:border-focus',\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/core/theme/src/components/select.ts\n label:\n 'mb-2 inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n wrapper: '',\n },\n});\n\ntype VariantProps = TVProps<typeof radiosVariants>;\ntype ClassName = TVClassName<typeof radiosVariants>;\n\nexport interface RadioOption {\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number;\n}\n\nexport interface RadiosProps extends VariantProps {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n}\n\n/**\n * Radios component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n */\nconst Radios = ({\n className = undefined,\n inline = false,\n name,\n options,\n ...uniformFieldProps\n}: RadiosProps): ReactElement => {\n const {\n ariaLabel,\n disabled,\n errorMessage,\n field: { onBlur, onChange, ref, value },\n invalid,\n label,\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n // classNames from slots\n const variants = radiosVariants();\n const classNames = variantsToClassNames(variants, className, 'base');\n\n const itemClassNames = {\n base: classNames.itemBase,\n control: classNames.itemControl,\n description: classNames.itemDescription,\n label: classNames.itemLabel,\n labelWrapper: classNames.itemLabelWrapper,\n wrapper: classNames.itemWrapper,\n };\n\n return (\n <HeroRadioGroup\n ref={ref}\n aria-label={ariaLabel}\n classNames={classNames}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={name}\n onBlur={onBlur}\n onValueChange={(newValue) => {\n onChange(convertToOriginalType(newValue));\n }}\n orientation={inline ? 'horizontal' : 'vertical'}\n value={value != null ? String(value) : ''}\n >\n {options.map((option) => {\n if ('value' in option) {\n const optionTestId = slugify(\n `${testId}_option_${option.testId ?? option.value}`,\n { replaceDots: true },\n );\n return (\n <HeroRadio\n key={String(option.value)}\n classNames={itemClassNames}\n data-testid={optionTestId}\n isDisabled={!!disabled || option.disabled}\n value={String(option.value)}\n >\n {option.label ?? option.value}\n </HeroRadio>\n );\n }\n return null;\n })}\n </HeroRadioGroup>\n );\n};\n\nexport default Radios;\n","import Radios from './Radios';\n\nexport type { RadiosProps, RadioOption } from './Radios';\n\nexport { radiosVariants } from './Radios';\n\nexport default Radios;\n"],"mappings":";;;;;;;;;;AAaA,MAAa,kBAAA,GAAA,uBAAA,IAAoB,EAC/B,OAAO;CACL,MAAM;EAEJ;EAEA;EAEA;CACF;CACA,UAAU;CACV,aAAa;CACb,iBAAiB;CACjB,WAAW;CACX,kBAAkB;CAClB,aACE;CAEF,OACE;CACF,SAAS;AACX,EACF,CAAC;;;;AAwCD,MAAM,UAAU,EACd,YAAY,KAAA,GACZ,SAAS,OACT,MACA,SACA,GAAG,wBAC4B;CAC/B,MAAM,EACJ,WACA,UACA,cACA,OAAO,EAAE,QAAQ,UAAU,KAAK,SAChC,SACA,OACA,UACA,WACEA,oCAAAA,gBAAgB;EAClB;EACA,GAAG;CACL,CAAC;CAGD,MAAM,EAAE,0BAA0BC,sBAAAA,2BAA2B,OAAO;CAIpE,MAAM,cAAA,GAAA,uBAAA,sBADW,eAC8B,GAAG,WAAW,MAAM;CAEnE,MAAM,iBAAiB;EACrB,MAAM,WAAW;EACjB,SAAS,WAAW;EACpB,aAAa,WAAW;EACxB,OAAO,WAAW;EAClB,cAAc,WAAW;EACzB,SAAS,WAAW;CACtB;CAEA,OACE,iBAAA,GAAA,kBAAA,KAACC,cAAAA,YAAD;EACO;EACL,cAAY;EACA;EAGZ,gBAAc;EACd,iBAAe;EACf,eAAa;EACC;EACd,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,OAAO,QAAQ,iBAAA,GAAA,kBAAA,KAAC,UAAD,EAAA,UAAS,MAAc,CAAA,IAAI;EACpC;EACE;EACR,gBAAgB,aAAa;GAC3B,SAAS,sBAAsB,QAAQ,CAAC;EAC1C;EACA,aAAa,SAAS,eAAe;EACrC,OAAO,SAAS,OAAO,OAAO,KAAK,IAAI;YAEtC,QAAQ,KAAK,WAAW;GACvB,IAAI,WAAW,QAKb,OACE,iBAAA,GAAA,kBAAA,KAACC,cAAAA,OAAD;IAEE,YAAY;IACZ,gBAAA,GAAA,uBAAA,SAPF,GAAG,OAAO,UAAU,OAAO,UAAU,OAAO,SAC5C,EAAE,aAAa,KAAK,CAMM;IACxB,YAAY,CAAC,CAAC,YAAY,OAAO;IACjC,OAAO,OAAO,OAAO,KAAK;cAEzB,OAAO,SAAS,OAAO;GACf,GAPJ,OAAO,OAAO,KAAK,CAOf;GAGf,OAAO;EACT,CAAC;CACa,CAAA;AAEpB;;;ACvJA,IAAA,iBAAe"}
@@ -1066,7 +1066,7 @@ declare const radiosVariants: ((props?: ({
1066
1066
  extend: undefined;
1067
1067
  base: undefined;
1068
1068
  slots: {
1069
- base: string;
1069
+ base: string[];
1070
1070
  itemBase: string;
1071
1071
  itemControl: string;
1072
1072
  itemDescription: string;
@@ -1118,7 +1118,7 @@ declare const radiosVariants: ((props?: ({
1118
1118
  };
1119
1119
  base: undefined;
1120
1120
  slots: {
1121
- base: string;
1121
+ base: string[];
1122
1122
  itemBase: string;
1123
1123
  itemControl: string;
1124
1124
  itemDescription: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/Radios/Radios.tsx"],"mappings":";;;;cAaa,cAAA,IAAc,KAAA;EAAA;;;gbAgBzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gbAhByB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kbAkBV;;;;sbACH;EAAA;kbAAc;;;;sbAEA;EAAA;;;;;kbAM1B;;;;sbAIK;EAAA;IAAA;;;kbAOO;;;;sbAJmC;EAAA;IAAA;;;kbAInC;;;;sbAMJ;EAAA;IAAA;;;kbAMF;;;;sbAwFP;EAAA;IAAA;;;kbA5EE;;;;sbANa;EAAA;kbAAA;;;;sbAAA;EAAA;;;;;kbAkFf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAxHI,YAAA,GAAe,OAAO,QAAQ,cAAA;AAAA,KAC9B,SAAA,GAAY,WAAW,QAAQ,cAAA;AAAA,UAEnB,WAAA;;EAEf,QAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA,GAAO,SAAS;;EAEhB,MAAA;;EAEA,KAAA;AAAA;AAAA,UAGe,WAAA,SAAoB,YAAA;;EAEnC,SAAA;;EAEA,SAAA,GAAY,SAAA;;EAEZ,QAAA;;EAEA,MAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA;;EAEA,OAAA,EAAS,WAAA;;EAET,MAAA;AAAA;;;;cAMI,MAAA;EAAU,SAAA;EAAA,MAAA;EAAA,IAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAMb,WAAA,KAAc,YAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/Radios/Radios.tsx"],"mappings":";;;;cAaa,cAAA,IAAc,KAAA;EAAA;;;gbAsBzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gbAtByB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kbAwBV;;;;sbACH;EAAA;kbAAc;;;;sbAEA;EAAA;;;;;kbAM1B;;;;sbAIK;EAAA;IAAA;;;kbAOO;;;;sbAJmC;EAAA;IAAA;;;kbAInC;;;;sbAMJ;EAAA;IAAA;;;kbAMF;;;;sbAwFP;EAAA;IAAA;;;kbA5EE;;;;sbANa;EAAA;kbAAA;;;;sbAAA;EAAA;;;;;kbAkFf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAxHI,YAAA,GAAe,OAAO,QAAQ,cAAA;AAAA,KAC9B,SAAA,GAAY,WAAW,QAAQ,cAAA;AAAA,UAEnB,WAAA;;EAEf,QAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA,GAAO,SAAS;;EAEhB,MAAA;;EAEA,KAAA;AAAA;AAAA,UAGe,WAAA,SAAoB,YAAA;;EAEnC,SAAA;;EAEA,SAAA,GAAY,SAAA;;EAEZ,QAAA;;EAEA,MAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA;;EAEA,OAAA,EAAS,WAAA;;EAET,MAAA;AAAA;;;;cAMI,MAAA;EAAU,SAAA;EAAA,MAAA;EAAA,IAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAMb,WAAA,KAAc,YAAA"}
@@ -1066,7 +1066,7 @@ declare const radiosVariants: ((props?: ({
1066
1066
  extend: undefined;
1067
1067
  base: undefined;
1068
1068
  slots: {
1069
- base: string;
1069
+ base: string[];
1070
1070
  itemBase: string;
1071
1071
  itemControl: string;
1072
1072
  itemDescription: string;
@@ -1118,7 +1118,7 @@ declare const radiosVariants: ((props?: ({
1118
1118
  };
1119
1119
  base: undefined;
1120
1120
  slots: {
1121
- base: string;
1121
+ base: string[];
1122
1122
  itemBase: string;
1123
1123
  itemControl: string;
1124
1124
  itemDescription: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/Radios/Radios.tsx"],"mappings":";;;;cAaa,cAAA,IAAc,KAAA;EAAA;;;gbAgBzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gbAhByB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kbAkBV;;;;sbACH;EAAA;kbAAc;;;;sbAEA;EAAA;;;;;kbAM1B;;;;sbAIK;EAAA;IAAA;;;kbAOO;;;;sbAJmC;EAAA;IAAA;;;kbAInC;;;;sbAMJ;EAAA;IAAA;;;kbAMF;;;;sbAwFP;EAAA;IAAA;;;kbA5EE;;;;sbANa;EAAA;kbAAA;;;;sbAAA;EAAA;;;;;kbAkFf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAxHI,YAAA,GAAe,OAAO,QAAQ,cAAA;AAAA,KAC9B,SAAA,GAAY,WAAW,QAAQ,cAAA;AAAA,UAEnB,WAAA;;EAEf,QAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA,GAAO,SAAS;;EAEhB,MAAA;;EAEA,KAAA;AAAA;AAAA,UAGe,WAAA,SAAoB,YAAA;;EAEnC,SAAA;;EAEA,SAAA,GAAY,SAAA;;EAEZ,QAAA;;EAEA,MAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA;;EAEA,OAAA,EAAS,WAAA;;EAET,MAAA;AAAA;;;;cAMI,MAAA;EAAU,SAAA;EAAA,MAAA;EAAA,IAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAMb,WAAA,KAAc,YAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/Radios/Radios.tsx"],"mappings":";;;;cAaa,cAAA,IAAc,KAAA;EAAA;;;gbAsBzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gbAtByB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kbAwBV;;;;sbACH;EAAA;kbAAc;;;;sbAEA;EAAA;;;;;kbAM1B;;;;sbAIK;EAAA;IAAA;;;kbAOO;;;;sbAJmC;EAAA;IAAA;;;kbAInC;;;;sbAMJ;EAAA;IAAA;;;kbAMF;;;;sbAwFP;EAAA;IAAA;;;kbA5EE;;;;sbANa;EAAA;kbAAA;;;;sbAAA;EAAA;;;;;kbAkFf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAxHI,YAAA,GAAe,OAAO,QAAQ,cAAA;AAAA,KAC9B,SAAA,GAAY,WAAW,QAAQ,cAAA;AAAA,UAEnB,WAAA;;EAEf,QAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA,GAAO,SAAS;;EAEhB,MAAA;;EAEA,KAAA;AAAA;AAAA,UAGe,WAAA,SAAoB,YAAA;;EAEnC,SAAA;;EAEA,SAAA,GAAY,SAAA;;EAEZ,QAAA;;EAEA,MAAA;;EAEA,KAAA,GAAQ,SAAA;;EAER,IAAA;;EAEA,OAAA,EAAS,WAAA;;EAET,MAAA;AAAA;;;;cAMI,MAAA;EAAU,SAAA;EAAA,MAAA;EAAA,IAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAMb,WAAA,KAAc,YAAA"}
@@ -5,14 +5,18 @@ import { jsx } from "react/jsx-runtime";
5
5
  import { Radio, RadioGroup } from "@heroui/radio";
6
6
  //#region src/Radios/Radios.tsx
7
7
  const radiosVariants = tv({ slots: {
8
- base: "group gap-0",
8
+ base: [
9
+ "group",
10
+ "flex w-full flex-col",
11
+ "gap-y-1.5"
12
+ ],
9
13
  itemBase: "",
10
14
  itemControl: "bg-focus group-data-[invalid=true]:bg-danger",
11
15
  itemDescription: "",
12
16
  itemLabel: "text-sm",
13
17
  itemLabelWrapper: "",
14
18
  itemWrapper: "group-data-[invalid=true]:border-danger! [&:not(group-data-[invalid=\"true\"]):not(group-data-[selected=\"false\"])]:border-focus",
15
- label: "mb-2 inline-flex text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger",
19
+ label: "mb-2 inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger",
16
20
  wrapper: ""
17
21
  } });
18
22
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["HeroRadioGroup","HeroRadio"],"sources":["../../src/Radios/Radios.tsx","../../src/Radios/index.ts"],"sourcesContent":["import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport {\n Radio as HeroRadio,\n RadioGroup as HeroRadioGroup,\n} from '@heroui/radio';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\n\nexport const radiosVariants = tv({\n slots: {\n // Needs group for group-data condition\n base: 'group gap-0',\n itemBase: '',\n itemControl: 'bg-focus group-data-[invalid=true]:bg-danger',\n itemDescription: '',\n itemLabel: 'text-sm',\n itemLabelWrapper: '',\n itemWrapper:\n 'group-data-[invalid=true]:border-danger! [&:not(group-data-[invalid=\"true\"]):not(group-data-[selected=\"false\"])]:border-focus',\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/core/theme/src/components/select.ts\n label:\n 'mb-2 inline-flex text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n wrapper: '',\n },\n});\n\ntype VariantProps = TVProps<typeof radiosVariants>;\ntype ClassName = TVClassName<typeof radiosVariants>;\n\nexport interface RadioOption {\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number;\n}\n\nexport interface RadiosProps extends VariantProps {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n}\n\n/**\n * Radios component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n */\nconst Radios = ({\n className = undefined,\n inline = false,\n name,\n options,\n ...uniformFieldProps\n}: RadiosProps): ReactElement => {\n const {\n ariaLabel,\n disabled,\n errorMessage,\n field: { onBlur, onChange, ref, value },\n invalid,\n label,\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n // classNames from slots\n const variants = radiosVariants();\n const classNames = variantsToClassNames(variants, className, 'base');\n\n const itemClassNames = {\n base: classNames.itemBase,\n control: classNames.itemControl,\n description: classNames.itemDescription,\n label: classNames.itemLabel,\n labelWrapper: classNames.itemLabelWrapper,\n wrapper: classNames.itemWrapper,\n };\n\n return (\n <HeroRadioGroup\n ref={ref}\n aria-label={ariaLabel}\n classNames={classNames}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={name}\n onBlur={onBlur}\n onValueChange={(newValue) => {\n onChange(convertToOriginalType(newValue));\n }}\n orientation={inline ? 'horizontal' : 'vertical'}\n value={value != null ? String(value) : ''}\n >\n {options.map((option) => {\n if ('value' in option) {\n const optionTestId = slugify(\n `${testId}_option_${option.testId ?? option.value}`,\n { replaceDots: true },\n );\n return (\n <HeroRadio\n key={String(option.value)}\n classNames={itemClassNames}\n data-testid={optionTestId}\n isDisabled={!!disabled || option.disabled}\n value={String(option.value)}\n >\n {option.label ?? option.value}\n </HeroRadio>\n );\n }\n return null;\n })}\n </HeroRadioGroup>\n );\n};\n\nexport default Radios;\n","import Radios from './Radios';\n\nexport type { RadiosProps, RadioOption } from './Radios';\n\nexport { radiosVariants } from './Radios';\n\nexport default Radios;\n"],"mappings":";;;;;;AAaA,MAAa,iBAAiB,GAAG,EAC/B,OAAO;CAEL,MAAM;CACN,UAAU;CACV,aAAa;CACb,iBAAiB;CACjB,WAAW;CACX,kBAAkB;CAClB,aACE;CAEF,OACE;CACF,SAAS;AACX,EACF,CAAC;;;;AAwCD,MAAM,UAAU,EACd,YAAY,KAAA,GACZ,SAAS,OACT,MACA,SACA,GAAG,wBAC4B;CAC/B,MAAM,EACJ,WACA,UACA,cACA,OAAO,EAAE,QAAQ,UAAU,KAAK,SAChC,SACA,OACA,UACA,WACE,gBAAgB;EAClB;EACA,GAAG;CACL,CAAC;CAGD,MAAM,EAAE,0BAA0B,2BAA2B,OAAO;CAIpE,MAAM,aAAa,qBADF,eAC8B,GAAG,WAAW,MAAM;CAEnE,MAAM,iBAAiB;EACrB,MAAM,WAAW;EACjB,SAAS,WAAW;EACpB,aAAa,WAAW;EACxB,OAAO,WAAW;EAClB,cAAc,WAAW;EACzB,SAAS,WAAW;CACtB;CAEA,OACE,oBAACA,YAAD;EACO;EACL,cAAY;EACA;EAGZ,gBAAc;EACd,iBAAe;EACf,eAAa;EACC;EACd,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,OAAO,QAAQ,oBAAC,UAAD,EAAA,UAAS,MAAc,CAAA,IAAI;EACpC;EACE;EACR,gBAAgB,aAAa;GAC3B,SAAS,sBAAsB,QAAQ,CAAC;EAC1C;EACA,aAAa,SAAS,eAAe;EACrC,OAAO,SAAS,OAAO,OAAO,KAAK,IAAI;YAEtC,QAAQ,KAAK,WAAW;GACvB,IAAI,WAAW,QAKb,OACE,oBAACC,OAAD;IAEE,YAAY;IACZ,eARiB,QACnB,GAAG,OAAO,UAAU,OAAO,UAAU,OAAO,SAC5C,EAAE,aAAa,KAAK,CAMM;IACxB,YAAY,CAAC,CAAC,YAAY,OAAO;IACjC,OAAO,OAAO,OAAO,KAAK;cAEzB,OAAO,SAAS,OAAO;GACf,GAPJ,OAAO,OAAO,KAAK,CAOf;GAGf,OAAO;EACT,CAAC;CACa,CAAA;AAEpB;;;ACjJA,IAAA,iBAAe"}
1
+ {"version":3,"file":"index.js","names":["HeroRadioGroup","HeroRadio"],"sources":["../../src/Radios/Radios.tsx","../../src/Radios/index.ts"],"sourcesContent":["import type { TVClassName, TVProps } from '@fuf-stack/pixel-utils';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport {\n Radio as HeroRadio,\n RadioGroup as HeroRadioGroup,\n} from '@heroui/radio';\n\nimport { slugify, tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\n\nimport { createOptionValueConverter } from '../helpers';\nimport { useUniformField } from '../hooks/useUniformField';\n\nexport const radiosVariants = tv({\n slots: {\n base: [\n // Needs group for group-data condition.\n 'group',\n // Match shared field wrapper layout.\n 'flex w-full flex-col',\n // Keep spacing between label/group consistent.\n 'gap-y-1.5',\n ],\n itemBase: '',\n itemControl: 'bg-focus group-data-[invalid=true]:bg-danger',\n itemDescription: '',\n itemLabel: 'text-sm',\n itemLabelWrapper: '',\n itemWrapper:\n 'group-data-[invalid=true]:border-danger! [&:not(group-data-[invalid=\"true\"]):not(group-data-[selected=\"false\"])]:border-focus',\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/core/theme/src/components/select.ts\n label:\n 'mb-2 inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:text-danger',\n wrapper: '',\n },\n});\n\ntype VariantProps = TVProps<typeof radiosVariants>;\ntype ClassName = TVClassName<typeof radiosVariants>;\n\nexport interface RadioOption {\n /** disables the option */\n disabled?: boolean;\n /** option label */\n label?: ReactNode;\n /** option icon */\n icon?: ReactNode;\n /** HTML data-testid attribute of the option */\n testId?: string;\n /** option value */\n value: string | number;\n}\n\nexport interface RadiosProps extends VariantProps {\n /** Custom aria-label for accessibility. If not provided, falls back to field name when no visible label exists */\n ariaLabel?: string;\n /** CSS class name */\n className?: ClassName;\n /** Determines if the Buttons are disabled or not. */\n disabled?: boolean;\n /** determines orientation of the Buttons. */\n inline?: boolean;\n /** Label displayed next to the RadioButton. */\n label?: ReactNode;\n /** Name the RadioButtons are registered at in HTML forms (react-hook-form). */\n name: string;\n /** Radio button configuration. */\n options: RadioOption[];\n /** Id to grab element in internal tests. */\n testId?: string;\n}\n\n/**\n * Radios component based on [HeroUI RadioGroup](https://www.heroui.com//docs/components/radio-group)\n */\nconst Radios = ({\n className = undefined,\n inline = false,\n name,\n options,\n ...uniformFieldProps\n}: RadiosProps): ReactElement => {\n const {\n ariaLabel,\n disabled,\n errorMessage,\n field: { onBlur, onChange, ref, value },\n invalid,\n label,\n required,\n testId,\n } = useUniformField({\n name,\n ...uniformFieldProps,\n });\n\n // Create converter to preserve number types for option values\n const { convertToOriginalType } = createOptionValueConverter(options);\n\n // classNames from slots\n const variants = radiosVariants();\n const classNames = variantsToClassNames(variants, className, 'base');\n\n const itemClassNames = {\n base: classNames.itemBase,\n control: classNames.itemControl,\n description: classNames.itemDescription,\n label: classNames.itemLabel,\n labelWrapper: classNames.itemLabelWrapper,\n wrapper: classNames.itemWrapper,\n };\n\n return (\n <HeroRadioGroup\n ref={ref}\n aria-label={ariaLabel}\n classNames={classNames}\n // see HeroUI styles for group-data condition (data-invalid),\n // e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts\n data-invalid={invalid}\n data-required={required}\n data-testid={testId}\n errorMessage={errorMessage}\n isDisabled={disabled}\n isInvalid={invalid}\n isRequired={required}\n label={label ? <legend>{label}</legend> : null}\n name={name}\n onBlur={onBlur}\n onValueChange={(newValue) => {\n onChange(convertToOriginalType(newValue));\n }}\n orientation={inline ? 'horizontal' : 'vertical'}\n value={value != null ? String(value) : ''}\n >\n {options.map((option) => {\n if ('value' in option) {\n const optionTestId = slugify(\n `${testId}_option_${option.testId ?? option.value}`,\n { replaceDots: true },\n );\n return (\n <HeroRadio\n key={String(option.value)}\n classNames={itemClassNames}\n data-testid={optionTestId}\n isDisabled={!!disabled || option.disabled}\n value={String(option.value)}\n >\n {option.label ?? option.value}\n </HeroRadio>\n );\n }\n return null;\n })}\n </HeroRadioGroup>\n );\n};\n\nexport default Radios;\n","import Radios from './Radios';\n\nexport type { RadiosProps, RadioOption } from './Radios';\n\nexport { radiosVariants } from './Radios';\n\nexport default Radios;\n"],"mappings":";;;;;;AAaA,MAAa,iBAAiB,GAAG,EAC/B,OAAO;CACL,MAAM;EAEJ;EAEA;EAEA;CACF;CACA,UAAU;CACV,aAAa;CACb,iBAAiB;CACjB,WAAW;CACX,kBAAkB;CAClB,aACE;CAEF,OACE;CACF,SAAS;AACX,EACF,CAAC;;;;AAwCD,MAAM,UAAU,EACd,YAAY,KAAA,GACZ,SAAS,OACT,MACA,SACA,GAAG,wBAC4B;CAC/B,MAAM,EACJ,WACA,UACA,cACA,OAAO,EAAE,QAAQ,UAAU,KAAK,SAChC,SACA,OACA,UACA,WACE,gBAAgB;EAClB;EACA,GAAG;CACL,CAAC;CAGD,MAAM,EAAE,0BAA0B,2BAA2B,OAAO;CAIpE,MAAM,aAAa,qBADF,eAC8B,GAAG,WAAW,MAAM;CAEnE,MAAM,iBAAiB;EACrB,MAAM,WAAW;EACjB,SAAS,WAAW;EACpB,aAAa,WAAW;EACxB,OAAO,WAAW;EAClB,cAAc,WAAW;EACzB,SAAS,WAAW;CACtB;CAEA,OACE,oBAACA,YAAD;EACO;EACL,cAAY;EACA;EAGZ,gBAAc;EACd,iBAAe;EACf,eAAa;EACC;EACd,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,OAAO,QAAQ,oBAAC,UAAD,EAAA,UAAS,MAAc,CAAA,IAAI;EACpC;EACE;EACR,gBAAgB,aAAa;GAC3B,SAAS,sBAAsB,QAAQ,CAAC;EAC1C;EACA,aAAa,SAAS,eAAe;EACrC,OAAO,SAAS,OAAO,OAAO,KAAK,IAAI;YAEtC,QAAQ,KAAK,WAAW;GACvB,IAAI,WAAW,QAKb,OACE,oBAACC,OAAD;IAEE,YAAY;IACZ,eARiB,QACnB,GAAG,OAAO,UAAU,OAAO,UAAU,OAAO,SAC5C,EAAE,aAAa,KAAK,CAMM;IACxB,YAAY,CAAC,CAAC,YAAY,OAAO;IACjC,OAAO,OAAO,OAAO,KAAK;cAEzB,OAAO,SAAS,OAAO;GACf,GAPJ,OAAO,OAAO,KAAK,CAOf;GAGf,OAAO;EACT,CAAC;CACa,CAAA;AAEpB;;;ACvJA,IAAA,iBAAe"}
@@ -12,9 +12,49 @@ let react_jsx_runtime = require("react/jsx-runtime");
12
12
  let react_select = require("react-select");
13
13
  react_select = require_FormContext.__toESM(react_select);
14
14
  let _heroui_select = require("@heroui/select");
15
+ //#region src/Select/SelectComponents.tsx
16
+ /** Mirrors the select test id onto the underlying react-select input element. */
17
+ const InputComponent = (props) => {
18
+ const testId = `${props.selectProps["data-testid"]}`;
19
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_select.components.Input, {
20
+ "data-testid": testId,
21
+ ...props
22
+ });
23
+ };
24
+ /** Wraps the control root to expose a stable `*_select` test id hook. */
25
+ const ControlComponent = (props) => {
26
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
27
+ "data-testid": `${props.selectProps["data-testid"]}_select`,
28
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_select.components.Control, { ...props })
29
+ });
30
+ };
31
+ /** Adds deterministic option test ids and forwards disabled state semantics. */
32
+ const OptionComponent = (props) => {
33
+ const { isDisabled } = props;
34
+ const testId = `${props.selectProps["data-testid"]}_select_option_${(0, _fuf_stack_pixel_utils.slugify)(String(props?.data?.testId ?? props?.data?.value), { replaceDots: true })}`;
35
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
36
+ "aria-disabled": isDisabled ? true : void 0,
37
+ "data-testid": testId,
38
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_select.components.Option, { ...props })
39
+ });
40
+ };
41
+ /** Wraps the dropdown indicator with a predictable test id for automation. */
42
+ const DropdownIndicatorComponent = (props) => {
43
+ const testId = props?.selectProps["data-testid"];
44
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
45
+ "data-testid": `${testId}_select_dropdown`,
46
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_select.components.DropdownIndicator, { ...props })
47
+ });
48
+ };
49
+ //#endregion
15
50
  //#region src/Select/Select.tsx
16
51
  const selectVariants = (0, _fuf_stack_pixel_utils.tv)({ slots: {
17
- base: "group leading-normal",
52
+ base: [
53
+ "group",
54
+ "flex w-full flex-col",
55
+ "gap-y-1.5",
56
+ "leading-normal"
57
+ ],
18
58
  clearIndicator: "rounded-md p-1 text-foreground-500 hover:cursor-pointer hover:bg-default-200 hover:text-foreground-800",
19
59
  control: "duration-150! rounded-lg border-2 border-default-200 bg-content1 transition-background hover:border-default-400 group-data-[invalid=true]:border-danger group-data-[invalid=true]:hover:border-danger motion-reduce:transition-none",
20
60
  control_focused: "border-focus",
@@ -26,7 +66,7 @@ const selectVariants = (0, _fuf_stack_pixel_utils.tv)({ slots: {
26
66
  indicatorsContainer: "gap-1 p-1",
27
67
  indicatorSeparator: "bg-default-300",
28
68
  input: "py-0.5 pl-1",
29
- label: "pointer-events-auto relative bottom-1.5 ml-1 text-foreground subpixel-antialiased text-small group-data-[invalid=true]:!text-danger",
69
+ label: "pointer-events-auto inline-flex cursor-default text-sm text-foreground subpixel-antialiased group-data-[invalid=true]:!text-danger",
30
70
  loadingIndicator: "",
31
71
  loadingMessage: "rounded-sm p-2 text-foreground-500",
32
72
  menu: "mt-2 rounded-xl border border-default-200 bg-content1 p-1 shadow-lg",
@@ -46,38 +86,10 @@ const selectVariants = (0, _fuf_stack_pixel_utils.tv)({ slots: {
46
86
  singleValue: "ml-1! leading-7!",
47
87
  valueContainer: "gap-1 p-1"
48
88
  } });
49
- const InputComponent = (props) => {
50
- const testId = `${props.selectProps["data-testid"]}`;
51
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_select.components.Input, {
52
- "data-testid": testId,
53
- ...props
54
- });
55
- };
56
- const ControlComponent = (props) => {
57
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
58
- "data-testid": `${props.selectProps["data-testid"]}_select`,
59
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_select.components.Control, { ...props })
60
- });
61
- };
62
- const OptionComponent = (props) => {
63
- const { isDisabled } = props;
64
- const testId = `${props.selectProps["data-testid"]}_select_option_${(0, _fuf_stack_pixel_utils.slugify)(String(props?.data?.testId ?? props?.data?.value), { replaceDots: true })}`;
65
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
66
- "aria-disabled": isDisabled ? true : void 0,
67
- "data-testid": testId,
68
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_select.components.Option, { ...props })
69
- });
70
- };
71
- const DropdownIndicatorComponent = (props) => {
72
- const testId = props?.selectProps["data-testid"];
73
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
74
- "data-testid": `${testId}_select_dropdown`,
75
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_select.components.DropdownIndicator, { ...props })
76
- });
77
- };
78
89
  /** Select component based on [HeroUI Select](https://www.heroui.com//docs/components/select) and [React-Select](https://react-select.com/home) */
79
90
  const Select = ({ className = void 0, clearable = true, debugMenuOpen = false, filterOption = void 0, inputValue = void 0, loading = false, multiSelect = false, name, onInputChange = void 0, options, placeholder = void 0, renderEmptyOptions = void 0, renderOptionLabel = void 0, selectedOptionFallback = void 0, ...uniformFieldProps }) => {
80
91
  const { ariaLabel, disabled, errorMessage, field: { onBlur, onChange, ref, value }, getErrorMessageProps, getHelperWrapperProps, getLabelProps, invalid, label, required, testId } = require_hooks_useUniformField_index.useUniformField({
92
+ isArrayValue: multiSelect,
81
93
  name,
82
94
  ...uniformFieldProps
83
95
  });