@skybin-tech/nebula-ui 0.0.28 → 0.0.30

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 (273) hide show
  1. package/README.md +422 -356
  2. package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -1
  3. package/dist/cjs/components/Accordion/Accordion.cjs.map +1 -1
  4. package/dist/cjs/components/Alert/Alert.cjs.map +1 -1
  5. package/dist/cjs/components/Avatar/Avatar.cjs.map +1 -1
  6. package/dist/cjs/components/Badge/Badge.cjs.map +1 -1
  7. package/dist/cjs/components/Button/Button.cjs +1 -1
  8. package/dist/cjs/components/Button/Button.cjs.map +1 -1
  9. package/dist/cjs/components/Card/Card.cjs.map +1 -1
  10. package/dist/cjs/components/Checkbox/Checkbox.cjs.map +1 -1
  11. package/dist/cjs/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  12. package/dist/cjs/components/Form/Checkbox.cjs.map +1 -1
  13. package/dist/cjs/components/Form/Combobox.cjs +124 -0
  14. package/dist/cjs/components/Form/Combobox.cjs.map +1 -0
  15. package/dist/cjs/components/Form/CountryPicker.cjs +101 -0
  16. package/dist/cjs/components/Form/CountryPicker.cjs.map +1 -0
  17. package/dist/cjs/components/Form/CountrySelect.cjs +111 -0
  18. package/dist/cjs/components/Form/CountrySelect.cjs.map +1 -0
  19. package/dist/cjs/components/Form/DatePicker.cjs +122 -0
  20. package/dist/cjs/components/Form/DatePicker.cjs.map +1 -0
  21. package/dist/cjs/components/Form/FieldLayout.cjs +65 -0
  22. package/dist/cjs/components/Form/FieldLayout.cjs.map +1 -0
  23. package/dist/cjs/components/Form/Form.cjs +12 -9
  24. package/dist/cjs/components/Form/Form.cjs.map +1 -1
  25. package/dist/cjs/components/Form/FormSwitch.cjs.map +1 -1
  26. package/dist/cjs/components/Form/PhoneInput.cjs +170 -0
  27. package/dist/cjs/components/Form/PhoneInput.cjs.map +1 -0
  28. package/dist/cjs/components/Form/Radio.cjs.map +1 -1
  29. package/dist/cjs/components/Form/Select.cjs +35 -47
  30. package/dist/cjs/components/Form/Select.cjs.map +1 -1
  31. package/dist/cjs/components/Form/TextArea.cjs +1 -1
  32. package/dist/cjs/components/Form/TextArea.cjs.map +1 -1
  33. package/dist/cjs/components/Form/TextBox.cjs +50 -61
  34. package/dist/cjs/components/Form/TextBox.cjs.map +1 -1
  35. package/dist/cjs/components/Form/context.cjs +25 -11
  36. package/dist/cjs/components/Form/context.cjs.map +1 -1
  37. package/dist/cjs/components/Form/hooks.cjs.map +1 -1
  38. package/dist/cjs/components/Form/index.cjs +16 -0
  39. package/dist/cjs/components/Form/variants.cjs.map +1 -1
  40. package/dist/cjs/components/Input/Input.cjs +2 -2
  41. package/dist/cjs/components/Input/Input.cjs.map +1 -1
  42. package/dist/cjs/components/Label/Label.cjs.map +1 -1
  43. package/dist/cjs/components/Pagination/Pagination.cjs +4 -4
  44. package/dist/cjs/components/Pagination/Pagination.cjs.map +1 -1
  45. package/dist/cjs/components/Separator/Separator.cjs.map +1 -1
  46. package/dist/cjs/components/Switch/Switch.cjs.map +1 -1
  47. package/dist/cjs/components/Tabs/Tabs.cjs.map +1 -1
  48. package/dist/cjs/components/Textarea/Textarea.cjs.map +1 -1
  49. package/dist/cjs/components/Tooltip/Tooltip.cjs.map +1 -1
  50. package/dist/cjs/data/countries.cjs +1062 -0
  51. package/dist/cjs/data/countries.cjs.map +1 -0
  52. package/dist/cjs/hooks/useDebounce.cjs.map +1 -1
  53. package/dist/cjs/hooks/useToast.cjs.map +1 -1
  54. package/dist/cjs/hooks/useToggle.cjs.map +1 -1
  55. package/dist/cjs/index.cjs +64 -4
  56. package/dist/cjs/primitives/accordion.cjs.map +1 -1
  57. package/dist/cjs/primitives/alert-dialog.cjs +73 -0
  58. package/dist/cjs/primitives/alert-dialog.cjs.map +1 -0
  59. package/dist/cjs/primitives/alert.cjs.map +1 -1
  60. package/dist/cjs/primitives/avatar.cjs.map +1 -1
  61. package/dist/cjs/primitives/badge.cjs.map +1 -1
  62. package/dist/cjs/primitives/breadcrumb.cjs +73 -0
  63. package/dist/cjs/primitives/breadcrumb.cjs.map +1 -0
  64. package/dist/cjs/primitives/button.cjs +8 -7
  65. package/dist/cjs/primitives/button.cjs.map +1 -1
  66. package/dist/cjs/primitives/calendar.cjs.map +1 -1
  67. package/dist/cjs/primitives/card.cjs.map +1 -1
  68. package/dist/cjs/primitives/checkbox.cjs.map +1 -1
  69. package/dist/cjs/primitives/command.cjs.map +1 -1
  70. package/dist/cjs/primitives/dialog.cjs.map +1 -1
  71. package/dist/cjs/primitives/dropdown-menu.cjs.map +1 -1
  72. package/dist/cjs/primitives/input-otp.cjs +49 -0
  73. package/dist/cjs/primitives/input-otp.cjs.map +1 -0
  74. package/dist/cjs/primitives/label.cjs.map +1 -1
  75. package/dist/cjs/primitives/popover.cjs.map +1 -1
  76. package/dist/cjs/primitives/progress.cjs +24 -0
  77. package/dist/cjs/primitives/progress.cjs.map +1 -0
  78. package/dist/cjs/primitives/radio-group.cjs.map +1 -1
  79. package/dist/cjs/primitives/scroll-area.cjs.map +1 -1
  80. package/dist/cjs/primitives/select.cjs.map +1 -1
  81. package/dist/cjs/primitives/separator.cjs.map +1 -1
  82. package/dist/cjs/primitives/sheet.cjs +78 -0
  83. package/dist/cjs/primitives/sheet.cjs.map +1 -0
  84. package/dist/cjs/primitives/slider.cjs +23 -0
  85. package/dist/cjs/primitives/slider.cjs.map +1 -0
  86. package/dist/cjs/primitives/sonner.cjs.map +1 -1
  87. package/dist/cjs/primitives/switch.cjs.map +1 -1
  88. package/dist/cjs/primitives/table.cjs.map +1 -1
  89. package/dist/cjs/primitives/tabs.cjs.map +1 -1
  90. package/dist/cjs/primitives/textarea.cjs +1 -1
  91. package/dist/cjs/primitives/textarea.cjs.map +1 -1
  92. package/dist/cjs/primitives/textbox.cjs +1 -1
  93. package/dist/cjs/primitives/textbox.cjs.map +1 -1
  94. package/dist/cjs/primitives/toast.cjs.map +1 -1
  95. package/dist/cjs/primitives/toggle.cjs.map +1 -1
  96. package/dist/cjs/utils/cn.cjs.map +1 -1
  97. package/dist/components/Alert/Alert.js.map +1 -1
  98. package/dist/components/AlertDialog/AlertDialog.d.ts +2 -0
  99. package/dist/components/AlertDialog/AlertDialog.d.ts.map +1 -0
  100. package/dist/components/AlertDialog/index.d.ts +2 -0
  101. package/dist/components/AlertDialog/index.d.ts.map +1 -0
  102. package/dist/components/Avatar/Avatar.js.map +1 -1
  103. package/dist/components/Badge/Badge.js.map +1 -1
  104. package/dist/components/Breadcrumb/Breadcrumb.d.ts +2 -0
  105. package/dist/components/Breadcrumb/Breadcrumb.d.ts.map +1 -0
  106. package/dist/components/Breadcrumb/index.d.ts +2 -0
  107. package/dist/components/Breadcrumb/index.d.ts.map +1 -0
  108. package/dist/components/Button/Button.d.ts.map +1 -1
  109. package/dist/components/Button/Button.js +2 -2
  110. package/dist/components/Button/Button.js.map +1 -1
  111. package/dist/components/Card/Card.js.map +1 -1
  112. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  113. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  114. package/dist/components/Form/Checkbox.js.map +1 -1
  115. package/dist/components/Form/Combobox.d.ts +31 -0
  116. package/dist/components/Form/Combobox.d.ts.map +1 -0
  117. package/dist/components/Form/Combobox.js +124 -0
  118. package/dist/components/Form/Combobox.js.map +1 -0
  119. package/dist/components/Form/CountryPicker.d.ts +17 -0
  120. package/dist/components/Form/CountryPicker.d.ts.map +1 -0
  121. package/dist/components/Form/CountryPicker.js +101 -0
  122. package/dist/components/Form/CountryPicker.js.map +1 -0
  123. package/dist/components/Form/CountrySelect.d.ts +32 -0
  124. package/dist/components/Form/CountrySelect.d.ts.map +1 -0
  125. package/dist/components/Form/CountrySelect.js +111 -0
  126. package/dist/components/Form/CountrySelect.js.map +1 -0
  127. package/dist/components/Form/DatePicker.d.ts +27 -0
  128. package/dist/components/Form/DatePicker.d.ts.map +1 -0
  129. package/dist/components/Form/DatePicker.js +122 -0
  130. package/dist/components/Form/DatePicker.js.map +1 -0
  131. package/dist/components/Form/FieldLayout.d.ts +15 -0
  132. package/dist/components/Form/FieldLayout.d.ts.map +1 -0
  133. package/dist/components/Form/FieldLayout.js +65 -0
  134. package/dist/components/Form/FieldLayout.js.map +1 -0
  135. package/dist/components/Form/Form.d.ts +1 -1
  136. package/dist/components/Form/Form.d.ts.map +1 -1
  137. package/dist/components/Form/Form.js +12 -9
  138. package/dist/components/Form/Form.js.map +1 -1
  139. package/dist/components/Form/FormSwitch.js.map +1 -1
  140. package/dist/components/Form/PhoneInput.d.ts +38 -0
  141. package/dist/components/Form/PhoneInput.d.ts.map +1 -0
  142. package/dist/components/Form/PhoneInput.js +170 -0
  143. package/dist/components/Form/PhoneInput.js.map +1 -0
  144. package/dist/components/Form/Radio.js.map +1 -1
  145. package/dist/components/Form/Select.d.ts.map +1 -1
  146. package/dist/components/Form/Select.js +35 -47
  147. package/dist/components/Form/Select.js.map +1 -1
  148. package/dist/components/Form/TextArea.js +1 -1
  149. package/dist/components/Form/TextArea.js.map +1 -1
  150. package/dist/components/Form/TextBox.d.ts.map +1 -1
  151. package/dist/components/Form/TextBox.js +50 -61
  152. package/dist/components/Form/TextBox.js.map +1 -1
  153. package/dist/components/Form/context.d.ts.map +1 -1
  154. package/dist/components/Form/context.js +25 -11
  155. package/dist/components/Form/context.js.map +1 -1
  156. package/dist/components/Form/context.test.d.ts +2 -0
  157. package/dist/components/Form/context.test.d.ts.map +1 -0
  158. package/dist/components/Form/hooks.js.map +1 -1
  159. package/dist/components/Form/index.d.ts +12 -0
  160. package/dist/components/Form/index.d.ts.map +1 -1
  161. package/dist/components/Form/index.js +7 -1
  162. package/dist/components/Input/Input.js +2 -2
  163. package/dist/components/Input/Input.js.map +1 -1
  164. package/dist/components/InputOTP/InputOTP.d.ts +2 -0
  165. package/dist/components/InputOTP/InputOTP.d.ts.map +1 -0
  166. package/dist/components/InputOTP/index.d.ts +2 -0
  167. package/dist/components/InputOTP/index.d.ts.map +1 -0
  168. package/dist/components/Label/Label.js.map +1 -1
  169. package/dist/components/Pagination/Pagination.d.ts +2 -2
  170. package/dist/components/Pagination/Pagination.d.ts.map +1 -1
  171. package/dist/components/Pagination/Pagination.js +4 -4
  172. package/dist/components/Pagination/Pagination.js.map +1 -1
  173. package/dist/components/Progress/Progress.d.ts +2 -0
  174. package/dist/components/Progress/Progress.d.ts.map +1 -0
  175. package/dist/components/Progress/index.d.ts +2 -0
  176. package/dist/components/Progress/index.d.ts.map +1 -0
  177. package/dist/components/Separator/Separator.js.map +1 -1
  178. package/dist/components/Sheet/Sheet.d.ts +2 -0
  179. package/dist/components/Sheet/Sheet.d.ts.map +1 -0
  180. package/dist/components/Sheet/index.d.ts +2 -0
  181. package/dist/components/Sheet/index.d.ts.map +1 -0
  182. package/dist/components/Slider/Slider.d.ts +2 -0
  183. package/dist/components/Slider/Slider.d.ts.map +1 -0
  184. package/dist/components/Slider/index.d.ts +2 -0
  185. package/dist/components/Slider/index.d.ts.map +1 -0
  186. package/dist/components/Switch/Switch.js.map +1 -1
  187. package/dist/components/Tabs/Tabs.js.map +1 -1
  188. package/dist/components/Textarea/Textarea.js.map +1 -1
  189. package/dist/data/countries.d.ts +18 -0
  190. package/dist/data/countries.d.ts.map +1 -0
  191. package/dist/data/countries.js +1054 -0
  192. package/dist/data/countries.js.map +1 -0
  193. package/dist/hooks/useDebounce.js.map +1 -1
  194. package/dist/hooks/useToast.js.map +1 -1
  195. package/dist/hooks/useToggle.js.map +1 -1
  196. package/dist/index.d.ts +10 -2
  197. package/dist/index.d.ts.map +1 -1
  198. package/dist/index.js +16 -5
  199. package/dist/primitives/accordion.js.map +1 -1
  200. package/dist/primitives/alert-dialog.d.ts +21 -0
  201. package/dist/primitives/alert-dialog.d.ts.map +1 -0
  202. package/dist/primitives/alert-dialog.js +60 -0
  203. package/dist/primitives/alert-dialog.js.map +1 -0
  204. package/dist/primitives/alert.js.map +1 -1
  205. package/dist/primitives/avatar.js.map +1 -1
  206. package/dist/primitives/breadcrumb.d.ts +20 -0
  207. package/dist/primitives/breadcrumb.d.ts.map +1 -0
  208. package/dist/primitives/breadcrumb.js +65 -0
  209. package/dist/primitives/breadcrumb.js.map +1 -0
  210. package/dist/primitives/button.d.ts +4 -3
  211. package/dist/primitives/button.d.ts.map +1 -1
  212. package/dist/primitives/button.js +7 -7
  213. package/dist/primitives/button.js.map +1 -1
  214. package/dist/primitives/calendar.js.map +1 -1
  215. package/dist/primitives/card.js.map +1 -1
  216. package/dist/primitives/checkbox.js.map +1 -1
  217. package/dist/primitives/command.js.map +1 -1
  218. package/dist/primitives/dialog.js.map +1 -1
  219. package/dist/primitives/dropdown-menu.js.map +1 -1
  220. package/dist/primitives/index.d.ts +6 -0
  221. package/dist/primitives/index.d.ts.map +1 -1
  222. package/dist/primitives/input-otp.d.ts +35 -0
  223. package/dist/primitives/input-otp.d.ts.map +1 -0
  224. package/dist/primitives/input-otp.js +44 -0
  225. package/dist/primitives/input-otp.js.map +1 -0
  226. package/dist/primitives/input.d.ts +1 -3
  227. package/dist/primitives/input.d.ts.map +1 -1
  228. package/dist/primitives/label.js.map +1 -1
  229. package/dist/primitives/popover.js.map +1 -1
  230. package/dist/primitives/progress.d.ts +5 -0
  231. package/dist/primitives/progress.d.ts.map +1 -0
  232. package/dist/primitives/progress.js +21 -0
  233. package/dist/primitives/progress.js.map +1 -0
  234. package/dist/primitives/radio-group.js.map +1 -1
  235. package/dist/primitives/scroll-area.js.map +1 -1
  236. package/dist/primitives/select.js.map +1 -1
  237. package/dist/primitives/separator.js.map +1 -1
  238. package/dist/primitives/sheet.d.ts +26 -0
  239. package/dist/primitives/sheet.d.ts.map +1 -0
  240. package/dist/primitives/sheet.js +66 -0
  241. package/dist/primitives/sheet.js.map +1 -0
  242. package/dist/primitives/slider.d.ts +5 -0
  243. package/dist/primitives/slider.d.ts.map +1 -0
  244. package/dist/primitives/slider.js +20 -0
  245. package/dist/primitives/slider.js.map +1 -0
  246. package/dist/primitives/sonner.js.map +1 -1
  247. package/dist/primitives/switch.js.map +1 -1
  248. package/dist/primitives/table.js.map +1 -1
  249. package/dist/primitives/tabs.js.map +1 -1
  250. package/dist/primitives/textarea.js +1 -1
  251. package/dist/primitives/textarea.js.map +1 -1
  252. package/dist/primitives/textbox.js +1 -1
  253. package/dist/primitives/textbox.js.map +1 -1
  254. package/dist/primitives/toast.js.map +1 -1
  255. package/dist/primitives/toggle.js.map +1 -1
  256. package/package.json +168 -60
  257. package/src/styles/index.css +107 -0
  258. package/dist/cjs/primitives/input.cjs +0 -20
  259. package/dist/cjs/primitives/input.cjs.map +0 -1
  260. package/dist/primitives/input.js +0 -18
  261. package/dist/primitives/input.js.map +0 -1
  262. package/dist/stories/Button.d.ts +0 -15
  263. package/dist/stories/Button.d.ts.map +0 -1
  264. package/dist/stories/Button.stories.d.ts +0 -24
  265. package/dist/stories/Button.stories.d.ts.map +0 -1
  266. package/dist/stories/Header.d.ts +0 -12
  267. package/dist/stories/Header.d.ts.map +0 -1
  268. package/dist/stories/Header.stories.d.ts +0 -19
  269. package/dist/stories/Header.stories.d.ts.map +0 -1
  270. package/dist/stories/Page.d.ts +0 -3
  271. package/dist/stories/Page.d.ts.map +0 -1
  272. package/dist/stories/Page.stories.d.ts +0 -13
  273. package/dist/stories/Page.stories.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Radio.cjs","names":[],"sources":["../../../../src/components/Form/Radio.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, useId, useContext, createContext, useEffect } from \"react\";\nimport type { ReactNode, ComponentPropsWithoutRef } from \"react\";\nimport { useController, useFormContext as useRHFFormContext, type FieldValues, type FieldPath, type Control } from \"react-hook-form\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../../utils/cn\";\nimport { FormConfigContext, type FormConfig, type FieldValidationRules } from \"../Form/context\";\nimport { RadioGroup as ShadcnRadioGroup, RadioGroupItem as ShadcnRadioGroupItem } from \"../../primitives/radio-group\";\nimport { Label } from \"../../primitives/label\";\nimport type * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\n\nconst radioSizeVariants = cva(\n \"\",\n {\n variants: {\n size: {\n sm: \"h-4 w-4\",\n md: \"h-5 w-5\",\n lg: \"h-6 w-6\",\n },\n },\n defaultVariants: {\n size: \"md\",\n },\n }\n);\n\nconst labelVariants = cva(\n \"text-sm font-medium cursor-pointer select-none\",\n {\n variants: {\n disabled: {\n true: \"cursor-not-allowed opacity-50\",\n false: \"\",\n },\n },\n defaultVariants: {\n disabled: false,\n },\n }\n);\n\n// Radio Group Context\ninterface RadioGroupContextValue {\n name: string;\n value: string | number | undefined;\n onChange: (value: string | number) => void;\n disabled?: boolean;\n size?: \"sm\" | \"md\" | \"lg\";\n}\n\nconst RadioGroupContext = createContext<RadioGroupContextValue | null>(null);\n\nexport interface RadioOption {\n label: ReactNode;\n value: string | number;\n disabled?: boolean;\n}\n\nexport interface RadioGroupProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> extends VariantProps<typeof radioSizeVariants> {\n /** Field name - required for form integration */\n name: TName;\n /** Label text for the radio group */\n label?: string;\n /** Helper text displayed below the radio group */\n helperText?: string;\n /** Whether to show the error message */\n showError?: boolean;\n /** Custom error message (overrides form error) */\n error?: string;\n /** Options for the radio group */\n options?: RadioOption[];\n /** Layout direction */\n direction?: \"horizontal\" | \"vertical\";\n /** External control (for use outside Form) */\n control?: Control<TFieldValues>;\n /** Children (alternative to options prop) */\n children?: ReactNode;\n /** Disabled state */\n disabled?: boolean;\n /** Additional class name */\n className?: string;\n /** Variant style */\n variant?: \"default\" | \"error\";\n \n // Validation props\n /** Field is required */\n required?: boolean | string;\n /** Custom validation function */\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\n}\n\n/**\n * RadioGroup component with form integration\n * \n * This is a wrapper around the shadcn/ui RadioGroup primitive that adds:\n * - Form integration with react-hook-form\n * - Automatic validation registration\n * - Label, helper text, and error message support\n * \n * @example\n * ```tsx\n * // Inside a Form component\n * <RadioGroup \n * name=\"gender\" \n * label=\"Gender\"\n * required\n * options={[\n * { label: \"Male\", value: \"male\" },\n * { label: \"Female\", value: \"female\" },\n * { label: \"Other\", value: \"other\" },\n * ]} \n * />\n * ```\n */\nexport function RadioGroup<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n name,\n label,\n helperText,\n showError = true,\n error: customError,\n size,\n variant,\n options = [],\n direction = \"vertical\",\n control: externalControl,\n children,\n disabled,\n className,\n // Validation props\n required,\n validate,\n}: RadioGroupProps<TFieldValues, TName>) {\n const generatedId = useId();\n \n // Try to get form context\n const formConfigContext = useContext(FormConfigContext);\n const formConfig: FormConfig = formConfigContext ?? {};\n \n // Get form context from react-hook-form\n const rhfContext = useRHFFormContext<TFieldValues>();\n const control = externalControl ?? rhfContext?.control;\n\n // Register validation rules with the form\n useEffect(() => {\n if (formConfigContext?.registerFieldValidation) {\n const rules: FieldValidationRules = {};\n \n if (required !== undefined) rules.required = required;\n if (validate !== undefined) rules.validate = validate;\n\n formConfigContext.registerFieldValidation({\n name: name as string,\n type: \"string\",\n rules,\n });\n\n return () => {\n formConfigContext.unregisterFieldValidation(name as string);\n };\n }\n }, [formConfigContext, name, required, validate]);\n\n // Use controller for form integration\n const { field, fieldState } = useController<TFieldValues, TName>({\n name,\n control,\n });\n\n const fieldError = fieldState.error?.message;\n const errorMessage = customError ?? fieldError;\n const hasError = !!errorMessage;\n \n // Merge sizes - prop takes precedence over form config\n const effectiveSize = size ?? formConfig.size ?? \"md\";\n const effectiveDisabled = disabled ?? formConfig.disabled;\n const effectiveVariant = hasError ? \"error\" : variant;\n\n const contextValue: RadioGroupContextValue = {\n name: name as string,\n value: field.value,\n onChange: field.onChange,\n disabled: effectiveDisabled,\n size: effectiveSize,\n };\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n {label && (\n <Label className={cn(\n \"block\",\n required && \"after:content-['*'] after:ml-0.5 after:text-destructive\"\n )}>\n {label}\n {formConfig.colon && \":\"}\n </Label>\n )}\n \n <RadioGroupContext.Provider value={contextValue}>\n <ShadcnRadioGroup\n value={field.value?.toString()}\n onValueChange={(value) => field.onChange(value)}\n disabled={effectiveDisabled}\n aria-labelledby={label ? `${generatedId}-label` : undefined}\n className={cn(\n direction === \"horizontal\" && \"flex flex-row gap-4\",\n direction === \"vertical\" && \"flex flex-col gap-2\"\n )}\n >\n {children ?? options.map((option) => (\n <RadioItem\n key={option.value}\n value={option.value}\n disabled={option.disabled}\n size={effectiveSize}\n variant={effectiveVariant}\n >\n {option.label}\n </RadioItem>\n ))}\n </ShadcnRadioGroup>\n </RadioGroupContext.Provider>\n\n {showError && hasError && (\n <p className=\"text-sm text-destructive\" role=\"alert\">\n {errorMessage}\n </p>\n )}\n \n {helperText && !hasError && (\n <p className=\"text-sm text-muted-foreground\">\n {helperText}\n </p>\n )}\n </div>\n );\n}\n\nRadioGroup.displayName = \"RadioGroup\";\n\nexport interface RadioItemProps extends Omit<ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>, \"value\">,\n VariantProps<typeof radioSizeVariants> {\n /** Value for this radio option */\n value: string | number;\n /** Label for this radio option */\n children?: ReactNode;\n /** Variant style */\n variant?: \"default\" | \"error\";\n}\n\n/**\n * RadioItem component - must be used within RadioGroup\n * \n * This is a wrapper around the shadcn/ui RadioGroupItem primitive\n */\nfunction RadioItemInner(\n {\n value,\n children,\n size,\n variant,\n className,\n disabled,\n id: providedId,\n ...props\n }: RadioItemProps,\n ref: React.ForwardedRef<React.ElementRef<typeof RadioGroupPrimitive.Item>>\n) {\n const generatedId = useId();\n const inputId = providedId ?? generatedId;\n \n const groupContext = useContext(RadioGroupContext);\n \n const effectiveSize = size ?? groupContext?.size ?? \"md\";\n const effectiveDisabled = disabled ?? groupContext?.disabled;\n\n return (\n <div className=\"flex items-center gap-2\">\n <ShadcnRadioGroupItem\n {...props}\n ref={ref}\n id={inputId}\n value={value.toString()}\n disabled={effectiveDisabled}\n className={cn(\n radioSizeVariants({ size: effectiveSize }),\n variant === \"error\" && \"border-destructive\",\n className\n )}\n />\n \n {children && (\n <Label\n htmlFor={inputId}\n className={labelVariants({ disabled: effectiveDisabled })}\n >\n {children}\n </Label>\n )}\n </div>\n );\n}\n\nexport const RadioItem = forwardRef(RadioItemInner);\nRadioItem.displayName = \"RadioItem\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"Radio.cjs","names":[],"sources":["../../../../src/components/Form/Radio.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { forwardRef, useId, useContext, createContext, useEffect } from \"react\";\r\nimport type { ReactNode, ComponentPropsWithoutRef } from \"react\";\r\nimport { useController, useFormContext as useRHFFormContext, type FieldValues, type FieldPath, type Control } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { FormConfigContext, type FormConfig, type FieldValidationRules } from \"../Form/context\";\r\nimport { RadioGroup as ShadcnRadioGroup, RadioGroupItem as ShadcnRadioGroupItem } from \"../../primitives/radio-group\";\r\nimport { Label } from \"../../primitives/label\";\r\nimport type * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\r\n\r\nconst radioSizeVariants = cva(\r\n \"\",\r\n {\r\n variants: {\r\n size: {\r\n sm: \"h-4 w-4\",\r\n md: \"h-5 w-5\",\r\n lg: \"h-6 w-6\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n },\r\n }\r\n);\r\n\r\nconst labelVariants = cva(\r\n \"text-sm font-medium cursor-pointer select-none\",\r\n {\r\n variants: {\r\n disabled: {\r\n true: \"cursor-not-allowed opacity-50\",\r\n false: \"\",\r\n },\r\n },\r\n defaultVariants: {\r\n disabled: false,\r\n },\r\n }\r\n);\r\n\r\n// Radio Group Context\r\ninterface RadioGroupContextValue {\r\n name: string;\r\n value: string | number | undefined;\r\n onChange: (value: string | number) => void;\r\n disabled?: boolean;\r\n size?: \"sm\" | \"md\" | \"lg\";\r\n}\r\n\r\nconst RadioGroupContext = createContext<RadioGroupContextValue | null>(null);\r\n\r\nexport interface RadioOption {\r\n label: ReactNode;\r\n value: string | number;\r\n disabled?: boolean;\r\n}\r\n\r\nexport interface RadioGroupProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends VariantProps<typeof radioSizeVariants> {\r\n /** Field name - required for form integration */\r\n name: TName;\r\n /** Label text for the radio group */\r\n label?: string;\r\n /** Helper text displayed below the radio group */\r\n helperText?: string;\r\n /** Whether to show the error message */\r\n showError?: boolean;\r\n /** Custom error message (overrides form error) */\r\n error?: string;\r\n /** Options for the radio group */\r\n options?: RadioOption[];\r\n /** Layout direction */\r\n direction?: \"horizontal\" | \"vertical\";\r\n /** External control (for use outside Form) */\r\n control?: Control<TFieldValues>;\r\n /** Children (alternative to options prop) */\r\n children?: ReactNode;\r\n /** Disabled state */\r\n disabled?: boolean;\r\n /** Additional class name */\r\n className?: string;\r\n /** Variant style */\r\n variant?: \"default\" | \"error\";\r\n \r\n // Validation props\r\n /** Field is required */\r\n required?: boolean | string;\r\n /** Custom validation function */\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\n/**\r\n * RadioGroup component with form integration\r\n * \r\n * This is a wrapper around the shadcn/ui RadioGroup primitive that adds:\r\n * - Form integration with react-hook-form\r\n * - Automatic validation registration\r\n * - Label, helper text, and error message support\r\n * \r\n * @example\r\n * ```tsx\r\n * // Inside a Form component\r\n * <RadioGroup \r\n * name=\"gender\" \r\n * label=\"Gender\"\r\n * required\r\n * options={[\r\n * { label: \"Male\", value: \"male\" },\r\n * { label: \"Female\", value: \"female\" },\r\n * { label: \"Other\", value: \"other\" },\r\n * ]} \r\n * />\r\n * ```\r\n */\r\nexport function RadioGroup<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n>({\r\n name,\r\n label,\r\n helperText,\r\n showError = true,\r\n error: customError,\r\n size,\r\n variant,\r\n options = [],\r\n direction = \"vertical\",\r\n control: externalControl,\r\n children,\r\n disabled,\r\n className,\r\n // Validation props\r\n required,\r\n validate,\r\n}: RadioGroupProps<TFieldValues, TName>) {\r\n const generatedId = useId();\r\n \r\n // Try to get form context\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n \r\n // Get form context from react-hook-form\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n // Register validation rules with the form\r\n useEffect(() => {\r\n if (formConfigContext?.registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n \r\n if (required !== undefined) rules.required = required;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n formConfigContext.registerFieldValidation({\r\n name: name as string,\r\n type: \"string\",\r\n rules,\r\n });\r\n\r\n return () => {\r\n formConfigContext.unregisterFieldValidation(name as string);\r\n };\r\n }\r\n }, [formConfigContext, name, required, validate]);\r\n\r\n // Use controller for form integration\r\n const { field, fieldState } = useController<TFieldValues, TName>({\r\n name,\r\n control,\r\n });\r\n\r\n const fieldError = fieldState.error?.message;\r\n const errorMessage = customError ?? fieldError;\r\n const hasError = !!errorMessage;\r\n \r\n // Merge sizes - prop takes precedence over form config\r\n const effectiveSize = size ?? formConfig.size ?? \"md\";\r\n const effectiveDisabled = disabled ?? formConfig.disabled;\r\n const effectiveVariant = hasError ? \"error\" : variant;\r\n\r\n const contextValue: RadioGroupContextValue = {\r\n name: name as string,\r\n value: field.value,\r\n onChange: field.onChange,\r\n disabled: effectiveDisabled,\r\n size: effectiveSize,\r\n };\r\n\r\n return (\r\n <div className={cn(\"space-y-2\", className)}>\r\n {label && (\r\n <Label className={cn(\r\n \"block\",\r\n required && \"after:content-['*'] after:ml-0.5 after:text-destructive\"\r\n )}>\r\n {label}\r\n {formConfig.colon && \":\"}\r\n </Label>\r\n )}\r\n \r\n <RadioGroupContext.Provider value={contextValue}>\r\n <ShadcnRadioGroup\r\n value={field.value?.toString()}\r\n onValueChange={(value) => field.onChange(value)}\r\n disabled={effectiveDisabled}\r\n aria-labelledby={label ? `${generatedId}-label` : undefined}\r\n className={cn(\r\n direction === \"horizontal\" && \"flex flex-row gap-4\",\r\n direction === \"vertical\" && \"flex flex-col gap-2\"\r\n )}\r\n >\r\n {children ?? options.map((option) => (\r\n <RadioItem\r\n key={option.value}\r\n value={option.value}\r\n disabled={option.disabled}\r\n size={effectiveSize}\r\n variant={effectiveVariant}\r\n >\r\n {option.label}\r\n </RadioItem>\r\n ))}\r\n </ShadcnRadioGroup>\r\n </RadioGroupContext.Provider>\r\n\r\n {showError && hasError && (\r\n <p className=\"text-sm text-destructive\" role=\"alert\">\r\n {errorMessage}\r\n </p>\r\n )}\r\n \r\n {helperText && !hasError && (\r\n <p className=\"text-sm text-muted-foreground\">\r\n {helperText}\r\n </p>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nRadioGroup.displayName = \"RadioGroup\";\r\n\r\nexport interface RadioItemProps extends Omit<ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>, \"value\">,\r\n VariantProps<typeof radioSizeVariants> {\r\n /** Value for this radio option */\r\n value: string | number;\r\n /** Label for this radio option */\r\n children?: ReactNode;\r\n /** Variant style */\r\n variant?: \"default\" | \"error\";\r\n}\r\n\r\n/**\r\n * RadioItem component - must be used within RadioGroup\r\n * \r\n * This is a wrapper around the shadcn/ui RadioGroupItem primitive\r\n */\r\nfunction RadioItemInner(\r\n {\r\n value,\r\n children,\r\n size,\r\n variant,\r\n className,\r\n disabled,\r\n id: providedId,\r\n ...props\r\n }: RadioItemProps,\r\n ref: React.ForwardedRef<React.ElementRef<typeof RadioGroupPrimitive.Item>>\r\n) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n \r\n const groupContext = useContext(RadioGroupContext);\r\n \r\n const effectiveSize = size ?? groupContext?.size ?? \"md\";\r\n const effectiveDisabled = disabled ?? groupContext?.disabled;\r\n\r\n return (\r\n <div className=\"flex items-center gap-2\">\r\n <ShadcnRadioGroupItem\r\n {...props}\r\n ref={ref}\r\n id={inputId}\r\n value={value.toString()}\r\n disabled={effectiveDisabled}\r\n className={cn(\r\n radioSizeVariants({ size: effectiveSize }),\r\n variant === \"error\" && \"border-destructive\",\r\n className\r\n )}\r\n />\r\n \r\n {children && (\r\n <Label\r\n htmlFor={inputId}\r\n className={labelVariants({ disabled: effectiveDisabled })}\r\n >\r\n {children}\r\n </Label>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nexport const RadioItem = forwardRef(RadioItemInner);\r\nRadioItem.displayName = \"RadioItem\";\r\n"],"mappings":"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"}
@@ -2,8 +2,7 @@
2
2
  "use client";
3
3
  const require_cn = require("../../utils/cn.cjs");
4
4
  const require_context = require("./context.cjs");
5
- const require_variants = require("./variants.cjs");
6
- const require_label = require("../../primitives/label.cjs");
5
+ const require_FieldLayout = require("./FieldLayout.cjs");
7
6
  const require_select = require("../../primitives/select.cjs");
8
7
  let react = require("react");
9
8
  let class_variance_authority = require("class-variance-authority");
@@ -77,51 +76,40 @@ function Select({ name, label, helperText, showError = true, error: customError,
77
76
  const effectiveSize = size ?? formConfig.size ?? "md";
78
77
  const effectiveDisabled = disabled ?? formConfig.disabled;
79
78
  const effectiveVariant = hasError ? "error" : variant;
80
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
81
- className: require_cn.cn("space-y-1.5", fullWidth && "w-full"),
82
- children: [
83
- label && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_label.Label, {
84
- htmlFor: inputId,
85
- className: require_variants.labelVariants({ required: !!required }),
86
- children: [label, formConfig.colon && ":"]
87
- }),
88
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_select.Select, {
89
- value: field.value?.toString() ?? "",
90
- onValueChange: (value) => {
91
- if (value === "" && allowClear) field.onChange("");
92
- else field.onChange(value);
93
- },
94
- disabled: effectiveDisabled,
95
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_select.SelectTrigger, {
96
- id: inputId,
97
- "aria-invalid": hasError,
98
- "aria-describedby": hasError ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0,
99
- className: require_cn.cn(selectSizeVariants({ size: effectiveSize }), effectiveVariant === "error" && "border-destructive focus:ring-destructive", effectiveVariant === "success" && "border-green-500 focus:ring-green-500", className),
100
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_select.SelectValue, { placeholder })
101
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_select.SelectContent, { children: [allowClear && field.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_select.SelectItem, {
102
- value: "",
103
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
104
- className: "text-muted-foreground",
105
- children: "Clear selection"
106
- })
107
- }), children ?? options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_select.SelectItem, {
108
- value: option.value.toString(),
109
- disabled: option.disabled,
110
- children: option.label
111
- }, option.value))] })]
112
- }),
113
- showError && hasError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
114
- id: `${inputId}-error`,
115
- className: "text-sm text-destructive",
116
- role: "alert",
117
- children: errorMessage
118
- }),
119
- helperText && !hasError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
120
- id: `${inputId}-helper`,
121
- className: "text-sm text-muted-foreground",
122
- children: helperText
123
- })
124
- ]
79
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_FieldLayout.FieldLayout, {
80
+ inputId,
81
+ label,
82
+ required: !!required,
83
+ helperText,
84
+ errorMessage: showError ? errorMessage : void 0,
85
+ showError,
86
+ fullWidth,
87
+ formConfig,
88
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_select.Select, {
89
+ value: field.value?.toString() ?? "",
90
+ onValueChange: (value) => {
91
+ if (value === "" && allowClear) field.onChange("");
92
+ else field.onChange(value);
93
+ },
94
+ disabled: effectiveDisabled,
95
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_select.SelectTrigger, {
96
+ id: inputId,
97
+ "aria-invalid": hasError,
98
+ "aria-describedby": hasError ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0,
99
+ className: require_cn.cn(selectSizeVariants({ size: effectiveSize }), effectiveVariant === "error" && "border-destructive focus:ring-destructive", effectiveVariant === "success" && "border-green-500 focus:ring-green-500", className),
100
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_select.SelectValue, { placeholder })
101
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_select.SelectContent, { children: [allowClear && field.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_select.SelectItem, {
102
+ value: "",
103
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
104
+ className: "text-muted-foreground",
105
+ children: "Clear selection"
106
+ })
107
+ }), children ?? options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_select.SelectItem, {
108
+ value: option.value.toString(),
109
+ disabled: option.disabled,
110
+ children: option.label
111
+ }, option.value))] })]
112
+ })
125
113
  });
126
114
  }
127
115
  Select.displayName = "Select";
@@ -1 +1 @@
1
- {"version":3,"file":"Select.cjs","names":[],"sources":["../../../../src/components/Form/Select.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useContext, useEffect } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { useController, useFormContext as useRHFFormContext, type FieldValues, type FieldPath, type Control } from \"react-hook-form\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../../utils/cn\";\nimport { labelVariants } from \"./variants\";\nimport { FormConfigContext, type FormConfig, type FieldValidationRules } from \"../Form/context\";\nimport {\n Select as ShadcnSelect,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../primitives/select\";\nimport { Label } from \"../../primitives/label\";\n\nconst selectSizeVariants = cva(\n \"\",\n {\n variants: {\n size: {\n sm: \"h-8 text-xs\",\n md: \"h-10 text-sm\",\n lg: \"h-12 text-base\",\n },\n },\n defaultVariants: {\n size: \"md\",\n },\n }\n);\n\nexport interface SelectOption {\n label: string;\n value: string | number;\n disabled?: boolean;\n}\n\nexport interface SelectProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> extends VariantProps<typeof selectSizeVariants> {\n /** Field name - required for form integration */\n name: TName;\n /** Label text for the select */\n label?: string;\n /** Helper text displayed below the select */\n helperText?: string;\n /** Whether to show the error message */\n showError?: boolean;\n /** Custom error message (overrides form error) */\n error?: string;\n /** Whether the select should take full width */\n fullWidth?: boolean;\n /** Options for the select */\n options?: SelectOption[];\n /** Placeholder text */\n placeholder?: string;\n /** Allow clear selection */\n allowClear?: boolean;\n /** External control (for use outside Form) */\n control?: Control<TFieldValues>;\n /** Children (alternative to options prop) */\n children?: ReactNode;\n /** Disabled state */\n disabled?: boolean;\n /** Additional class name */\n className?: string;\n /** ID for the select */\n id?: string;\n /** Variant style */\n variant?: \"default\" | \"error\" | \"success\";\n \n // Validation props\n /** Field is required */\n required?: boolean | string;\n /** Custom validation function */\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\n}\n\n/**\n * Select component with form integration\n * \n * This is a wrapper around the shadcn/ui Select primitive that adds:\n * - Form integration with react-hook-form\n * - Automatic validation registration\n * - Label, helper text, and error message support\n * \n * @example\n * ```tsx\n * // Inside a Form component\n * <Select \n * name=\"country\" \n * label=\"Country\" \n * required\n * options={[\n * { label: \"USA\", value: \"us\" },\n * { label: \"Canada\", value: \"ca\" },\n * ]} \n * />\n * ```\n */\nexport function Select<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n name,\n label,\n helperText,\n showError = true,\n error: customError,\n size,\n variant,\n fullWidth = true,\n className,\n disabled,\n options = [],\n placeholder,\n allowClear,\n id: providedId,\n control: externalControl,\n children,\n // Validation props\n required,\n validate,\n}: SelectProps<TFieldValues, TName>) {\n const generatedId = useId();\n const inputId = providedId ?? generatedId;\n \n // Try to get form context\n const formConfigContext = useContext(FormConfigContext);\n const formConfig: FormConfig = formConfigContext ?? {};\n \n // Get form context from react-hook-form\n const rhfContext = useRHFFormContext<TFieldValues>();\n const control = externalControl ?? rhfContext?.control;\n\n // Register validation rules with the form\n useEffect(() => {\n if (formConfigContext?.registerFieldValidation) {\n const rules: FieldValidationRules = {};\n \n if (required !== undefined) rules.required = required;\n if (validate !== undefined) rules.validate = validate;\n\n formConfigContext.registerFieldValidation({\n name: name as string,\n type: \"string\",\n rules,\n });\n\n return () => {\n formConfigContext.unregisterFieldValidation(name as string);\n };\n }\n }, [formConfigContext, name, required, validate]);\n\n // Use controller for form integration\n const { field, fieldState } = useController<TFieldValues, TName>({\n name,\n control,\n });\n\n const fieldError = fieldState.error?.message;\n const errorMessage = customError ?? fieldError;\n const hasError = !!errorMessage;\n \n // Merge sizes - prop takes precedence over form config\n const effectiveSize = size ?? formConfig.size ?? \"md\";\n const effectiveDisabled = disabled ?? formConfig.disabled;\n \n // Determine variant based on error state\n const effectiveVariant = hasError ? \"error\" : variant;\n\n return (\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\n {label && (\n <Label\n htmlFor={inputId}\n className={labelVariants({ required: !!required })}\n >\n {label}\n {formConfig.colon && \":\"}\n </Label>\n )}\n \n <ShadcnSelect\n value={field.value?.toString() ?? \"\"}\n onValueChange={(value) => {\n // Handle clear selection\n if (value === \"\" && allowClear) {\n field.onChange(\"\");\n } else {\n field.onChange(value);\n }\n }}\n disabled={effectiveDisabled}\n >\n <SelectTrigger\n id={inputId}\n aria-invalid={hasError}\n aria-describedby={\n hasError\n ? `${inputId}-error`\n : helperText\n ? `${inputId}-helper`\n : undefined\n }\n className={cn(\n selectSizeVariants({ size: effectiveSize }),\n effectiveVariant === \"error\" && \"border-destructive focus:ring-destructive\",\n effectiveVariant === \"success\" && \"border-green-500 focus:ring-green-500\",\n className\n )}\n >\n <SelectValue placeholder={placeholder} />\n </SelectTrigger>\n <SelectContent>\n {allowClear && field.value && (\n <SelectItem value=\"\">\n <span className=\"text-muted-foreground\">Clear selection</span>\n </SelectItem>\n )}\n {children ?? options.map((option) => (\n <SelectItem\n key={option.value}\n value={option.value.toString()}\n disabled={option.disabled}\n >\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </ShadcnSelect>\n\n {showError && hasError && (\n <p\n id={`${inputId}-error`}\n className=\"text-sm text-destructive\"\n role=\"alert\"\n >\n {errorMessage}\n </p>\n )}\n \n {helperText && !hasError && (\n <p\n id={`${inputId}-helper`}\n className=\"text-sm text-muted-foreground\"\n >\n {helperText}\n </p>\n )}\n </div>\n );\n}\n\nSelect.displayName = \"Select\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"Select.cjs","names":[],"sources":["../../../../src/components/Form/Select.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useId, useContext, useEffect } from \"react\";\r\nimport type { ReactNode } from \"react\";\r\nimport { useController, useFormContext as useRHFFormContext, type FieldValues, type FieldPath, type Control } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { FormConfigContext, type FormConfig, type FieldValidationRules } from \"../Form/context\";\r\nimport { FieldLayout } from \"./FieldLayout\";\r\nimport {\r\n Select as ShadcnSelect,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"../../primitives/select\";\r\n\r\nconst selectSizeVariants = cva(\r\n \"\",\r\n {\r\n variants: {\r\n size: {\r\n sm: \"h-8 text-xs\",\r\n md: \"h-10 text-sm\",\r\n lg: \"h-12 text-base\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n },\r\n }\r\n);\r\n\r\nexport interface SelectOption {\r\n label: string;\r\n value: string | number;\r\n disabled?: boolean;\r\n}\r\n\r\nexport interface SelectProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends VariantProps<typeof selectSizeVariants> {\r\n /** Field name - required for form integration */\r\n name: TName;\r\n /** Label text for the select */\r\n label?: string;\r\n /** Helper text displayed below the select */\r\n helperText?: string;\r\n /** Whether to show the error message */\r\n showError?: boolean;\r\n /** Custom error message (overrides form error) */\r\n error?: string;\r\n /** Whether the select should take full width */\r\n fullWidth?: boolean;\r\n /** Options for the select */\r\n options?: SelectOption[];\r\n /** Placeholder text */\r\n placeholder?: string;\r\n /** Allow clear selection */\r\n allowClear?: boolean;\r\n /** External control (for use outside Form) */\r\n control?: Control<TFieldValues>;\r\n /** Children (alternative to options prop) */\r\n children?: ReactNode;\r\n /** Disabled state */\r\n disabled?: boolean;\r\n /** Additional class name */\r\n className?: string;\r\n /** ID for the select */\r\n id?: string;\r\n /** Variant style */\r\n variant?: \"default\" | \"error\" | \"success\";\r\n \r\n // Validation props\r\n /** Field is required */\r\n required?: boolean | string;\r\n /** Custom validation function */\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\n/**\r\n * Select component with form integration\r\n * \r\n * This is a wrapper around the shadcn/ui Select primitive that adds:\r\n * - Form integration with react-hook-form\r\n * - Automatic validation registration\r\n * - Label, helper text, and error message support\r\n * \r\n * @example\r\n * ```tsx\r\n * // Inside a Form component\r\n * <Select \r\n * name=\"country\" \r\n * label=\"Country\" \r\n * required\r\n * options={[\r\n * { label: \"USA\", value: \"us\" },\r\n * { label: \"Canada\", value: \"ca\" },\r\n * ]} \r\n * />\r\n * ```\r\n */\r\nexport function Select<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n>({\r\n name,\r\n label,\r\n helperText,\r\n showError = true,\r\n error: customError,\r\n size,\r\n variant,\r\n fullWidth = true,\r\n className,\r\n disabled,\r\n options = [],\r\n placeholder,\r\n allowClear,\r\n id: providedId,\r\n control: externalControl,\r\n children,\r\n // Validation props\r\n required,\r\n validate,\r\n}: SelectProps<TFieldValues, TName>) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n \r\n // Try to get form context\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n \r\n // Get form context from react-hook-form\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n // Register validation rules with the form\r\n useEffect(() => {\r\n if (formConfigContext?.registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n \r\n if (required !== undefined) rules.required = required;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n formConfigContext.registerFieldValidation({\r\n name: name as string,\r\n type: \"string\",\r\n rules,\r\n });\r\n\r\n return () => {\r\n formConfigContext.unregisterFieldValidation(name as string);\r\n };\r\n }\r\n }, [formConfigContext, name, required, validate]);\r\n\r\n // Use controller for form integration\r\n const { field, fieldState } = useController<TFieldValues, TName>({\r\n name,\r\n control,\r\n });\r\n\r\n const fieldError = fieldState.error?.message;\r\n const errorMessage = customError ?? fieldError;\r\n const hasError = !!errorMessage;\r\n \r\n // Merge sizes - prop takes precedence over form config\r\n const effectiveSize = size ?? formConfig.size ?? \"md\";\r\n const effectiveDisabled = disabled ?? formConfig.disabled;\r\n \r\n // Determine variant based on error state\r\n const effectiveVariant = hasError ? \"error\" : variant;\r\n\r\n return (\r\n <FieldLayout\r\n inputId={inputId}\r\n label={label}\r\n required={!!required}\r\n helperText={helperText}\r\n errorMessage={showError ? errorMessage : undefined}\r\n showError={showError}\r\n fullWidth={fullWidth}\r\n formConfig={formConfig}\r\n >\r\n <ShadcnSelect\r\n value={field.value?.toString() ?? \"\"}\r\n onValueChange={(value) => {\r\n if (value === \"\" && allowClear) {\r\n field.onChange(\"\");\r\n } else {\r\n field.onChange(value);\r\n }\r\n }}\r\n disabled={effectiveDisabled}\r\n >\r\n <SelectTrigger\r\n id={inputId}\r\n aria-invalid={hasError}\r\n aria-describedby={\r\n hasError\r\n ? `${inputId}-error`\r\n : helperText\r\n ? `${inputId}-helper`\r\n : undefined\r\n }\r\n className={cn(\r\n selectSizeVariants({ size: effectiveSize }),\r\n effectiveVariant === \"error\" && \"border-destructive focus:ring-destructive\",\r\n effectiveVariant === \"success\" && \"border-green-500 focus:ring-green-500\",\r\n className\r\n )}\r\n >\r\n <SelectValue placeholder={placeholder} />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {allowClear && field.value && (\r\n <SelectItem value=\"\">\r\n <span className=\"text-muted-foreground\">Clear selection</span>\r\n </SelectItem>\r\n )}\r\n {children ?? options.map((option) => (\r\n <SelectItem\r\n key={option.value}\r\n value={option.value.toString()}\r\n disabled={option.disabled}\r\n >\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </ShadcnSelect>\r\n </FieldLayout>\r\n );\r\n}\r\n\r\nSelect.displayName = \"Select\";\r\n"],"mappings":"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"}
@@ -2,8 +2,8 @@
2
2
  "use client";
3
3
  const require_cn = require("../../utils/cn.cjs");
4
4
  const require_context = require("./context.cjs");
5
- const require_variants = require("./variants.cjs");
6
5
  const require_label = require("../../primitives/label.cjs");
6
+ const require_variants = require("./variants.cjs");
7
7
  const require_textarea = require("../../primitives/textarea.cjs");
8
8
  let react = require("react");
9
9
  let class_variance_authority = require("class-variance-authority");
@@ -1 +1 @@
1
- {"version":3,"file":"TextArea.cjs","names":[],"sources":["../../../../src/components/Form/TextArea.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, useId, useContext, useEffect } from \"react\";\nimport type { TextareaHTMLAttributes } from \"react\";\nimport { useController, useFormContext as useRHFFormContext, type FieldValues, type FieldPath, type Control } from \"react-hook-form\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../../utils/cn\";\nimport { FormConfigContext, type FormConfig, type FieldValidationRules } from \"../Form/context\";\nimport { labelVariants } from \"./variants\";\nimport { Textarea } from \"../../primitives/textarea\";\nimport { Label } from \"../../primitives/label\";\n\nconst textAreaSizeVariants = cva(\n \"\",\n {\n variants: {\n size: {\n sm: \"text-xs px-2 py-1.5 min-h-[60px]\",\n md: \"text-sm px-3 py-2 min-h-[80px]\",\n lg: \"text-base px-4 py-3 min-h-[100px]\",\n },\n variant: {\n default: \"border-input focus-visible:ring-ring\",\n error: \"border-destructive focus-visible:ring-destructive\",\n success: \"border-green-500 focus-visible:ring-green-500\",\n },\n },\n defaultVariants: {\n size: \"md\",\n variant: \"default\",\n },\n }\n);\n\n/**\n * Validation rule with optional custom message\n */\ntype ValidationRule<T> = T | { value: T; message: string };\n\nexport interface TextAreaProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, \"name\" | \"required\" | \"minLength\" | \"maxLength\">,\n VariantProps<typeof textAreaSizeVariants> {\n /** Field name - required for form integration */\n name: TName;\n /** Label text for the textarea */\n label?: string;\n /** Helper text displayed below the textarea */\n helperText?: string;\n /** Whether to show the error message */\n showError?: boolean;\n /** Custom error message (overrides form error) */\n error?: string;\n /** Whether the textarea should take full width */\n fullWidth?: boolean;\n /** Show character count */\n showCount?: boolean;\n /** Maximum character count (for display) */\n maxCount?: number;\n /** External control (for use outside Form) */\n control?: Control<TFieldValues>;\n \n // Validation props\n /** Field is required */\n required?: boolean | string;\n /** Minimum length */\n minLength?: ValidationRule<number>;\n /** Maximum length */\n maxLength?: ValidationRule<number>;\n /** Custom validation function */\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\n}\n\n/**\n * TextArea component with form integration\n * \n * This is a wrapper around the shadcn/ui Textarea primitive that adds:\n * - Form integration with react-hook-form\n * - Automatic validation registration\n * - Label, helper text, and error message support\n * - Character count display\n * \n * @example\n * ```tsx\n * // Inside a Form component\n * <TextArea name=\"description\" label=\"Description\" required minLength={10} />\n * <TextArea name=\"bio\" label=\"Bio\" showCount maxCount={500} maxLength={500} />\n * ```\n */\nfunction TextAreaInner<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>(\n {\n name,\n label,\n helperText,\n showError = true,\n error: customError,\n size,\n variant,\n fullWidth = true,\n className,\n disabled,\n showCount,\n maxCount,\n id: providedId,\n control: externalControl,\n // Validation props\n required,\n minLength,\n maxLength,\n validate,\n ...props\n }: TextAreaProps<TFieldValues, TName>,\n ref: React.ForwardedRef<HTMLTextAreaElement>\n) {\n const generatedId = useId();\n const inputId = providedId ?? generatedId;\n \n // Try to get form context\n const formConfigContext = useContext(FormConfigContext);\n const formConfig: FormConfig = formConfigContext ?? {};\n \n // Get form context from react-hook-form\n const rhfContext = useRHFFormContext<TFieldValues>();\n const control = externalControl ?? rhfContext?.control;\n\n // Register validation rules with the form\n useEffect(() => {\n if (formConfigContext?.registerFieldValidation) {\n const rules: FieldValidationRules = {};\n \n if (required !== undefined) rules.required = required;\n if (minLength !== undefined) rules.minLength = minLength;\n if (maxLength !== undefined) rules.maxLength = maxLength;\n if (validate !== undefined) rules.validate = validate;\n\n formConfigContext.registerFieldValidation({\n name: name as string,\n type: \"string\",\n rules,\n });\n\n return () => {\n formConfigContext.unregisterFieldValidation(name as string);\n };\n }\n }, [formConfigContext, name, required, minLength, maxLength, validate]);\n\n // Use controller for form integration\n const { field, fieldState } = useController<TFieldValues, TName>({\n name,\n control,\n });\n\n const fieldError = fieldState.error?.message;\n const errorMessage = customError ?? fieldError;\n const hasError = !!errorMessage;\n \n // Merge sizes - prop takes precedence over form config\n const effectiveSize = size ?? formConfig.size ?? \"md\";\n const effectiveDisabled = disabled ?? formConfig.disabled;\n \n // Determine variant based on error state\n const effectiveVariant = hasError ? \"error\" : variant;\n\n const currentLength = typeof field.value === \"string\" ? field.value.length : 0;\n \n // Get maxLength value for HTML attribute\n const maxLengthValue = maxCount ?? (typeof maxLength === \"number\" ? maxLength : (maxLength as { value: number })?.value);\n\n return (\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\n {label && (\n <Label\n htmlFor={inputId}\n className={labelVariants({ required: !!required })}\n >\n {label}\n {formConfig.colon && \":\"}\n </Label>\n )}\n \n <div className=\"relative\">\n <Textarea\n {...props}\n {...field}\n ref={(node) => {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n field.ref(node);\n }}\n id={inputId}\n disabled={effectiveDisabled}\n maxLength={maxLengthValue}\n aria-invalid={hasError}\n aria-describedby={\n hasError\n ? `${inputId}-error`\n : helperText\n ? `${inputId}-helper`\n : undefined\n }\n className={cn(\n textAreaSizeVariants({ size: effectiveSize, variant: effectiveVariant }),\n showCount && \"pb-6\",\n className\n )}\n />\n \n {showCount && (\n <div className=\"absolute bottom-2 right-2 text-xs text-muted-foreground\">\n {currentLength}{maxCount ? `/${maxCount}` : \"\"}\n </div>\n )}\n </div>\n\n {showError && hasError && (\n <p\n id={`${inputId}-error`}\n className=\"text-sm text-destructive\"\n role=\"alert\"\n >\n {errorMessage}\n </p>\n )}\n \n {helperText && !hasError && (\n <p\n id={`${inputId}-helper`}\n className=\"text-sm text-muted-foreground\"\n >\n {helperText}\n </p>\n )}\n </div>\n );\n}\n\n// Use forwardRef with generic support\nexport const TextArea = forwardRef(TextAreaInner) as <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>(\n props: TextAreaProps<TFieldValues, TName> & { ref?: React.ForwardedRef<HTMLTextAreaElement> }\n) => React.ReactElement;\n\n(TextArea as React.FC).displayName = \"TextArea\";\n"],"mappings":";;;;;;;;;;;;AAYA,IAAM,wBAAA,GAAA,yBAAA,IAAA,CACJ,IACA;CACE,UAAU;EACR,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EACA,SAAS;GACP,SAAS;GACT,OAAO;GACP,SAAS;EACX;CACF;CACA,iBAAiB;EACf,MAAM;EACN,SAAS;CACX;AACF,CACF;;;;;;;;;;;;;;;;;AA0DA,SAAS,cAIP,EACE,MACA,OACA,YACA,YAAY,MACZ,OAAO,aACP,MACA,SACA,YAAY,MACZ,WACA,UACA,WACA,UACA,IAAI,YACJ,SAAS,iBAET,UACA,WACA,WACA,UACA,GAAG,SAEL,KACA;CACA,MAAM,eAAA,GAAA,MAAA,MAAA,CAAoB;CAC1B,MAAM,UAAU,cAAc;CAG9B,MAAM,qBAAA,GAAA,MAAA,WAAA,CAA+B,gBAAA,iBAAiB;CACtD,MAAM,aAAyB,qBAAqB,CAAC;CAGrD,MAAM,cAAA,GAAA,gBAAA,eAAA,CAA6C;CACnD,MAAM,UAAU,mBAAmB,YAAY;CAG/C,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,mBAAmB,yBAAyB;GAC9C,MAAM,QAA8B,CAAC;GAErC,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAC7C,IAAI,cAAc,KAAA,GAAW,MAAM,YAAY;GAC/C,IAAI,cAAc,KAAA,GAAW,MAAM,YAAY;GAC/C,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAE7C,kBAAkB,wBAAwB;IAClC;IACN,MAAM;IACN;GACF,CAAC;GAED,aAAa;IACX,kBAAkB,0BAA0B,IAAc;GAC5D;EACF;CACF,GAAG;EAAC;EAAmB;EAAM;EAAU;EAAW;EAAW;CAAQ,CAAC;CAGtE,MAAM,EAAE,OAAO,gBAAA,GAAA,gBAAA,cAAA,CAAkD;EAC/D;EACA;CACF,CAAC;CAED,MAAM,aAAa,WAAW,OAAO;CACrC,MAAM,eAAe,eAAe;CACpC,MAAM,WAAW,CAAC,CAAC;CAGnB,MAAM,gBAAgB,QAAQ,WAAW,QAAQ;CACjD,MAAM,oBAAoB,YAAY,WAAW;CAGjD,MAAM,mBAAmB,WAAW,UAAU;CAE9C,MAAM,gBAAgB,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,SAAS;CAG7E,MAAM,iBAAiB,aAAa,OAAO,cAAc,WAAW,YAAa,WAAiC;CAElH,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,WAAW,WAAA,GAAG,eAAe,aAAa,QAAQ;YAAvD;GACG,SACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,cAAA,OAAD;IACE,SAAS;IACT,WAAW,iBAAA,cAAc,EAAE,UAAU,CAAC,CAAC,SAAS,CAAC;cAFnD,CAIG,OACA,WAAW,SAAS,GAChB;;GAGT,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;cAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,iBAAA,UAAD;KACE,GAAI;KACJ,GAAI;KACJ,MAAM,SAAS;MACb,IAAI,OAAO,QAAQ,YACjB,IAAI,IAAI;WACH,IAAI,KACT,IAAI,UAAU;MAEhB,MAAM,IAAI,IAAI;KAChB;KACA,IAAI;KACJ,UAAU;KACV,WAAW;KACX,gBAAc;KACd,oBACE,WACI,GAAG,QAAQ,UACX,aACA,GAAG,QAAQ,WACX,KAAA;KAEN,WAAW,WAAA,GACT,qBAAqB;MAAE,MAAM;MAAe,SAAS;KAAiB,CAAC,GACvE,aAAa,QACb,SACF;IACD,CAAA,GAEA,aACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;eAAf,CACG,eAAe,WAAW,IAAI,aAAa,EACzC;MAEJ;;GAEJ,aAAa,YACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;IACE,IAAI,GAAG,QAAQ;IACf,WAAU;IACV,MAAK;cAEJ;GACA,CAAA;GAGJ,cAAc,CAAC,YACd,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;IACE,IAAI,GAAG,QAAQ;IACf,WAAU;cAET;GACA,CAAA;EAEF;;AAET;AAGA,IAAa,YAAA,GAAA,MAAA,WAAA,CAAsB,aAAa;AAOhD,SAAuB,cAAc"}
1
+ {"version":3,"file":"TextArea.cjs","names":[],"sources":["../../../../src/components/Form/TextArea.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { forwardRef, useId, useContext, useEffect } from \"react\";\r\nimport type { TextareaHTMLAttributes } from \"react\";\r\nimport { useController, useFormContext as useRHFFormContext, type FieldValues, type FieldPath, type Control } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { FormConfigContext, type FormConfig, type FieldValidationRules } from \"../Form/context\";\r\nimport { labelVariants } from \"./variants\";\r\nimport { Textarea } from \"../../primitives/textarea\";\r\nimport { Label } from \"../../primitives/label\";\r\n\r\nconst textAreaSizeVariants = cva(\r\n \"\",\r\n {\r\n variants: {\r\n size: {\r\n sm: \"text-xs px-2 py-1.5 min-h-[60px]\",\r\n md: \"text-sm px-3 py-2 min-h-[80px]\",\r\n lg: \"text-base px-4 py-3 min-h-[100px]\",\r\n },\r\n variant: {\r\n default: \"border-input focus-visible:ring-ring\",\r\n error: \"border-destructive focus-visible:ring-destructive\",\r\n success: \"border-green-500 focus-visible:ring-green-500\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n variant: \"default\",\r\n },\r\n }\r\n);\r\n\r\n/**\r\n * Validation rule with optional custom message\r\n */\r\ntype ValidationRule<T> = T | { value: T; message: string };\r\n\r\nexport interface TextAreaProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, \"name\" | \"required\" | \"minLength\" | \"maxLength\">,\r\n VariantProps<typeof textAreaSizeVariants> {\r\n /** Field name - required for form integration */\r\n name: TName;\r\n /** Label text for the textarea */\r\n label?: string;\r\n /** Helper text displayed below the textarea */\r\n helperText?: string;\r\n /** Whether to show the error message */\r\n showError?: boolean;\r\n /** Custom error message (overrides form error) */\r\n error?: string;\r\n /** Whether the textarea should take full width */\r\n fullWidth?: boolean;\r\n /** Show character count */\r\n showCount?: boolean;\r\n /** Maximum character count (for display) */\r\n maxCount?: number;\r\n /** External control (for use outside Form) */\r\n control?: Control<TFieldValues>;\r\n \r\n // Validation props\r\n /** Field is required */\r\n required?: boolean | string;\r\n /** Minimum length */\r\n minLength?: ValidationRule<number>;\r\n /** Maximum length */\r\n maxLength?: ValidationRule<number>;\r\n /** Custom validation function */\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\n/**\r\n * TextArea component with form integration\r\n * \r\n * This is a wrapper around the shadcn/ui Textarea primitive that adds:\r\n * - Form integration with react-hook-form\r\n * - Automatic validation registration\r\n * - Label, helper text, and error message support\r\n * - Character count display\r\n * \r\n * @example\r\n * ```tsx\r\n * // Inside a Form component\r\n * <TextArea name=\"description\" label=\"Description\" required minLength={10} />\r\n * <TextArea name=\"bio\" label=\"Bio\" showCount maxCount={500} maxLength={500} />\r\n * ```\r\n */\r\nfunction TextAreaInner<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n>(\r\n {\r\n name,\r\n label,\r\n helperText,\r\n showError = true,\r\n error: customError,\r\n size,\r\n variant,\r\n fullWidth = true,\r\n className,\r\n disabled,\r\n showCount,\r\n maxCount,\r\n id: providedId,\r\n control: externalControl,\r\n // Validation props\r\n required,\r\n minLength,\r\n maxLength,\r\n validate,\r\n ...props\r\n }: TextAreaProps<TFieldValues, TName>,\r\n ref: React.ForwardedRef<HTMLTextAreaElement>\r\n) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n \r\n // Try to get form context\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n \r\n // Get form context from react-hook-form\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n // Register validation rules with the form\r\n useEffect(() => {\r\n if (formConfigContext?.registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n \r\n if (required !== undefined) rules.required = required;\r\n if (minLength !== undefined) rules.minLength = minLength;\r\n if (maxLength !== undefined) rules.maxLength = maxLength;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n formConfigContext.registerFieldValidation({\r\n name: name as string,\r\n type: \"string\",\r\n rules,\r\n });\r\n\r\n return () => {\r\n formConfigContext.unregisterFieldValidation(name as string);\r\n };\r\n }\r\n }, [formConfigContext, name, required, minLength, maxLength, validate]);\r\n\r\n // Use controller for form integration\r\n const { field, fieldState } = useController<TFieldValues, TName>({\r\n name,\r\n control,\r\n });\r\n\r\n const fieldError = fieldState.error?.message;\r\n const errorMessage = customError ?? fieldError;\r\n const hasError = !!errorMessage;\r\n \r\n // Merge sizes - prop takes precedence over form config\r\n const effectiveSize = size ?? formConfig.size ?? \"md\";\r\n const effectiveDisabled = disabled ?? formConfig.disabled;\r\n \r\n // Determine variant based on error state\r\n const effectiveVariant = hasError ? \"error\" : variant;\r\n\r\n const currentLength = typeof field.value === \"string\" ? field.value.length : 0;\r\n \r\n // Get maxLength value for HTML attribute\r\n const maxLengthValue = maxCount ?? (typeof maxLength === \"number\" ? maxLength : (maxLength as { value: number })?.value);\r\n\r\n return (\r\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\r\n {label && (\r\n <Label\r\n htmlFor={inputId}\r\n className={labelVariants({ required: !!required })}\r\n >\r\n {label}\r\n {formConfig.colon && \":\"}\r\n </Label>\r\n )}\r\n \r\n <div className=\"relative\">\r\n <Textarea\r\n {...props}\r\n {...field}\r\n ref={(node) => {\r\n if (typeof ref === \"function\") {\r\n ref(node);\r\n } else if (ref) {\r\n ref.current = node;\r\n }\r\n field.ref(node);\r\n }}\r\n id={inputId}\r\n disabled={effectiveDisabled}\r\n maxLength={maxLengthValue}\r\n aria-invalid={hasError}\r\n aria-describedby={\r\n hasError\r\n ? `${inputId}-error`\r\n : helperText\r\n ? `${inputId}-helper`\r\n : undefined\r\n }\r\n className={cn(\r\n textAreaSizeVariants({ size: effectiveSize, variant: effectiveVariant }),\r\n showCount && \"pb-6\",\r\n className\r\n )}\r\n />\r\n \r\n {showCount && (\r\n <div className=\"absolute bottom-2 right-2 text-xs text-muted-foreground\">\r\n {currentLength}{maxCount ? `/${maxCount}` : \"\"}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {showError && hasError && (\r\n <p\r\n id={`${inputId}-error`}\r\n className=\"text-sm text-destructive\"\r\n role=\"alert\"\r\n >\r\n {errorMessage}\r\n </p>\r\n )}\r\n \r\n {helperText && !hasError && (\r\n <p\r\n id={`${inputId}-helper`}\r\n className=\"text-sm text-muted-foreground\"\r\n >\r\n {helperText}\r\n </p>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Use forwardRef with generic support\r\nexport const TextArea = forwardRef(TextAreaInner) as <\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n>(\r\n props: TextAreaProps<TFieldValues, TName> & { ref?: React.ForwardedRef<HTMLTextAreaElement> }\r\n) => React.ReactElement;\r\n\r\n(TextArea as React.FC).displayName = \"TextArea\";\r\n"],"mappings":";;;;;;;;;;;;AAYA,IAAM,wBAAA,GAAuB,yBAAA,IAAA,CAC3B,IACA;CACE,UAAU;EACR,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EACA,SAAS;GACP,SAAS;GACT,OAAO;GACP,SAAS;EACX;CACF;CACA,iBAAiB;EACf,MAAM;EACN,SAAS;CACX;AACF,CACF;;;;;;;;;;;;;;;;;AA0DA,SAAS,cAIP,EACE,MACA,OACA,YACA,YAAY,MACZ,OAAO,aACP,MACA,SACA,YAAY,MACZ,WACA,UACA,WACA,UACA,IAAI,YACJ,SAAS,iBAET,UACA,WACA,WACA,UACA,GAAG,SAEL,KACA;CACA,MAAM,eAAA,GAAc,MAAA,MAAA,CAAM;CAC1B,MAAM,UAAU,cAAc;CAG9B,MAAM,qBAAA,GAAoB,MAAA,WAAA,CAAW,gBAAA,iBAAiB;CACtD,MAAM,aAAyB,qBAAqB,CAAC;CAGrD,MAAM,cAAA,GAAa,gBAAA,eAAA,CAAgC;CACnD,MAAM,UAAU,mBAAmB,YAAY;CAG/C,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,mBAAmB,yBAAyB;GAC9C,MAAM,QAA8B,CAAC;GAErC,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAC7C,IAAI,cAAc,KAAA,GAAW,MAAM,YAAY;GAC/C,IAAI,cAAc,KAAA,GAAW,MAAM,YAAY;GAC/C,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAE7C,kBAAkB,wBAAwB;IAClC;IACN,MAAM;IACN;GACF,CAAC;GAED,aAAa;IACX,kBAAkB,0BAA0B,IAAc;GAC5D;EACF;CACF,GAAG;EAAC;EAAmB;EAAM;EAAU;EAAW;EAAW;CAAQ,CAAC;CAGtE,MAAM,EAAE,OAAO,gBAAA,GAAe,gBAAA,cAAA,CAAmC;EAC/D;EACA;CACF,CAAC;CAED,MAAM,aAAa,WAAW,OAAO;CACrC,MAAM,eAAe,eAAe;CACpC,MAAM,WAAW,CAAC,CAAC;CAGnB,MAAM,gBAAgB,QAAQ,WAAW,QAAQ;CACjD,MAAM,oBAAoB,YAAY,WAAW;CAGjD,MAAM,mBAAmB,WAAW,UAAU;CAE9C,MAAM,gBAAgB,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,SAAS;CAG7E,MAAM,iBAAiB,aAAa,OAAO,cAAc,WAAW,YAAa,WAAiC;CAElH,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,WAAW,WAAA,GAAG,eAAe,aAAa,QAAQ;EAAvD,UAAA;GACG,SACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,cAAA,OAAD;IACE,SAAS;IACT,WAAW,iBAAA,cAAc,EAAE,UAAU,CAAC,CAAC,SAAS,CAAC;IAFnD,UAAA,CAIG,OACA,WAAW,SAAS,GAChB;;GAGT,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,iBAAA,UAAD;KACE,GAAI;KACJ,GAAI;KACJ,MAAM,SAAS;MACb,IAAI,OAAO,QAAQ,YACjB,IAAI,IAAI;WACH,IAAI,KACT,IAAI,UAAU;MAEhB,MAAM,IAAI,IAAI;KAChB;KACA,IAAI;KACJ,UAAU;KACV,WAAW;KACX,gBAAc;KACd,oBACE,WACI,GAAG,QAAQ,UACX,aACA,GAAG,QAAQ,WACX,KAAA;KAEN,WAAW,WAAA,GACT,qBAAqB;MAAE,MAAM;MAAe,SAAS;KAAiB,CAAC,GACvE,aAAa,QACb,SACF;IACD,CAAA,GAEA,aACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACG,eAAe,WAAW,IAAI,aAAa,EACzC;IAEJ,CAAA,CAAA;;GAEJ,aAAa,YACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;IACE,IAAI,GAAG,QAAQ;IACf,WAAU;IACV,MAAK;IAEJ,UAAA;GACA,CAAA;GAGJ,cAAc,CAAC,YACd,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;IACE,IAAI,GAAG,QAAQ;IACf,WAAU;IAET,UAAA;GACA,CAAA;EAEF;;AAET;AAGA,IAAa,YAAA,GAAW,MAAA,WAAA,CAAW,aAAa;AAOhD,SAAuB,cAAc"}
@@ -2,9 +2,8 @@
2
2
  "use client";
3
3
  const require_cn = require("../../utils/cn.cjs");
4
4
  const require_context = require("./context.cjs");
5
- const require_variants = require("./variants.cjs");
5
+ const require_FieldLayout = require("./FieldLayout.cjs");
6
6
  const require_textbox = require("../../primitives/textbox.cjs");
7
- const require_label = require("../../primitives/label.cjs");
8
7
  let react = require("react");
9
8
  let class_variance_authority = require("class-variance-authority");
10
9
  let react_jsx_runtime = require("react/jsx-runtime");
@@ -119,65 +118,55 @@ function TextBoxInner({ name, label, helperText, showError = true, error: custom
119
118
  field.onChange("");
120
119
  onClear?.();
121
120
  };
122
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
123
- className: require_cn.cn("space-y-1.5", fullWidth && "w-full"),
124
- children: [
125
- label && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_label.Label, {
126
- htmlFor: inputId,
127
- className: require_variants.labelVariants({ required: !!required }),
128
- children: [label, formConfig.colon && ":"]
129
- }),
130
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
131
- className: "relative",
132
- children: [
133
- prefix && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
134
- className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground",
135
- children: prefix
136
- }),
137
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_textbox.TextBoxPrimitive, {
138
- ...props,
139
- ...field,
140
- ref: (node) => {
141
- if (typeof ref === "function") ref(node);
142
- else if (ref) ref.current = node;
143
- field.ref(node);
144
- },
145
- id: inputId,
146
- disabled: effectiveDisabled,
147
- "aria-invalid": hasError,
148
- "aria-describedby": hasError ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0,
149
- className: require_cn.cn(textBoxVariants({
150
- size: effectiveSize,
151
- variant: effectiveVariant
152
- }), prefix && "pl-10", (suffix || allowClear) && "pr-10", className)
153
- }),
154
- (suffix || allowClear && field.value) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
155
- className: "absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-1",
156
- children: [allowClear && field.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
157
- type: "button",
158
- onClick: handleClear,
159
- className: "text-muted-foreground hover:text-foreground transition-colors",
160
- tabIndex: -1,
161
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.X, { className: "h-4 w-4" })
162
- }), suffix && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
163
- className: "text-muted-foreground",
164
- children: suffix
165
- })]
166
- })
167
- ]
168
- }),
169
- showError && hasError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
170
- id: `${inputId}-error`,
171
- className: "text-sm text-destructive",
172
- role: "alert",
173
- children: errorMessage
174
- }),
175
- helperText && !hasError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
176
- id: `${inputId}-helper`,
177
- className: "text-sm text-muted-foreground",
178
- children: helperText
179
- })
180
- ]
121
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_FieldLayout.FieldLayout, {
122
+ inputId,
123
+ label,
124
+ required: !!required,
125
+ helperText,
126
+ errorMessage: showError ? errorMessage : void 0,
127
+ showError,
128
+ fullWidth,
129
+ formConfig,
130
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
131
+ className: "relative",
132
+ children: [
133
+ prefix && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
134
+ className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground",
135
+ children: prefix
136
+ }),
137
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_textbox.TextBoxPrimitive, {
138
+ ...props,
139
+ ...field,
140
+ ref: (node) => {
141
+ if (typeof ref === "function") ref(node);
142
+ else if (ref) ref.current = node;
143
+ field.ref(node);
144
+ },
145
+ id: inputId,
146
+ disabled: effectiveDisabled,
147
+ "aria-invalid": hasError,
148
+ "aria-describedby": hasError ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0,
149
+ className: require_cn.cn(textBoxVariants({
150
+ size: effectiveSize,
151
+ variant: effectiveVariant
152
+ }), prefix && "pl-10", (suffix || allowClear) && "pr-10", className)
153
+ }),
154
+ (suffix || allowClear && field.value) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
155
+ className: "absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-1",
156
+ children: [allowClear && field.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
157
+ type: "button",
158
+ onClick: handleClear,
159
+ className: "text-muted-foreground hover:text-foreground transition-colors",
160
+ tabIndex: -1,
161
+ "aria-label": "Clear",
162
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.X, { className: "h-4 w-4" })
163
+ }), suffix && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
164
+ className: "text-muted-foreground",
165
+ children: suffix
166
+ })]
167
+ })
168
+ ]
169
+ })
181
170
  });
182
171
  }
183
172
  var TextBox = (0, react.forwardRef)(TextBoxInner);
@@ -1 +1 @@
1
- {"version":3,"file":"TextBox.cjs","names":[],"sources":["../../../../src/components/Form/TextBox.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, useId, useContext, useEffect } from \"react\";\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\nimport { useController, useFormContext as useRHFFormContext, type FieldValues, type FieldPath, type Control } from \"react-hook-form\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../../utils/cn\";\nimport { FormConfigContext, type FormConfig, type FieldValidationRules } from \"../Form/context\";\nimport { labelVariants } from \"./variants\";\nimport { TextBoxPrimitive } from \"../../primitives/textbox\";\nimport { Label } from \"../../primitives/label\";\nimport { X } from \"lucide-react\";\n\nconst textBoxVariants = cva(\n \"\",\n {\n variants: {\n size: {\n sm: \"h-8 text-xs px-2\",\n md: \"h-10 text-sm px-3\",\n lg: \"h-12 text-base px-4\",\n },\n variant: {\n default: \"border-input focus-visible:ring-ring\",\n error: \"border-destructive focus-visible:ring-destructive\",\n success: \"border-green-500 focus-visible:ring-green-500\",\n },\n },\n defaultVariants: {\n size: \"md\",\n variant: \"default\",\n },\n }\n);\n\n/**\n * Validation rule with optional custom message\n */\ntype ValidationRule<T> = T | { value: T; message: string };\n\nexport interface TextBoxProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> extends Omit<InputHTMLAttributes<HTMLInputElement>, \"size\" | \"name\" | \"prefix\" | \"pattern\" | \"required\" | \"minLength\" | \"maxLength\">,\n VariantProps<typeof textBoxVariants> {\n /** Field name - required for form integration */\n name: TName;\n /** Label text for the input */\n label?: string;\n /** Helper text displayed below the input */\n helperText?: string;\n /** Whether to show the error message */\n showError?: boolean;\n /** Custom error message (overrides form error) */\n error?: string;\n /** Whether the input should take full width */\n fullWidth?: boolean;\n /** Prefix element */\n prefix?: ReactNode;\n /** Suffix element */\n suffix?: ReactNode;\n /** Allow clear button */\n allowClear?: boolean;\n /** Callback when clear is clicked */\n onClear?: () => void;\n /** External control (for use outside Form) */\n control?: Control<TFieldValues>;\n \n // Validation props\n /** Field is required */\n required?: boolean | string;\n /** Minimum length for strings */\n minLength?: ValidationRule<number>;\n /** Maximum length for strings */\n maxLength?: ValidationRule<number>;\n /** Minimum value for numbers */\n minValue?: ValidationRule<number>;\n /** Maximum value for numbers */\n maxValue?: ValidationRule<number>;\n /** Regex pattern for validation */\n pattern?: ValidationRule<RegExp>;\n /** Email validation */\n email?: boolean | string;\n /** URL validation */\n url?: boolean | string;\n /** Custom validation function */\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\n}\n\n/**\n * TextBox component with form integration and automatic validation registration\n * \n * This is a wrapper around the shadcn/ui Input primitive that adds:\n * - Form integration with react-hook-form\n * - Automatic validation registration\n * - Label, helper text, and error message support\n * - Prefix/suffix elements\n * - Clear button functionality\n * \n * @example\n * ```tsx\n * // Inside a Form component - validation is automatically registered\n * <Form onSubmit={handleSubmit} defaultValues={{ username: \"\", email: \"\" }}>\n * <TextBox name=\"username\" label=\"Username\" required minLength={3} maxLength={50} />\n * <TextBox name=\"email\" label=\"Email\" type=\"email\" required email />\n * <TextBox name=\"website\" label=\"Website\" url />\n * <Button type=\"submit\">Submit</Button>\n * </Form>\n * ```\n */\nfunction TextBoxInner<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>(\n {\n name,\n label,\n helperText,\n showError = true,\n error: customError,\n size,\n variant,\n fullWidth = true,\n className,\n disabled,\n prefix,\n suffix,\n allowClear,\n onClear,\n id: providedId,\n control: externalControl,\n // Validation props\n required,\n minLength,\n maxLength,\n minValue,\n maxValue,\n pattern,\n email,\n url,\n validate,\n ...props\n }: TextBoxProps<TFieldValues, TName>,\n ref: React.ForwardedRef<HTMLInputElement>\n) {\n const generatedId = useId();\n const inputId = providedId ?? generatedId;\n \n // Try to get form context\n const formConfigContext = useContext(FormConfigContext);\n const formConfig: FormConfig = formConfigContext ?? {};\n\n // Get form context from react-hook-form\n const rhfContext = useRHFFormContext<TFieldValues>();\n const control = externalControl ?? rhfContext?.control;\n\n // Destructure stable function references so the effect doesn't depend on the\n // context object identity (which changes every render due to inline construction).\n const registerFieldValidation = formConfigContext?.registerFieldValidation;\n const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;\n\n // Register validation rules with the form\n useEffect(() => {\n if (registerFieldValidation) {\n const rules: FieldValidationRules = {};\n\n if (required !== undefined) rules.required = required;\n if (minLength !== undefined) rules.minLength = minLength;\n if (maxLength !== undefined) rules.maxLength = maxLength;\n if (minValue !== undefined) rules.min = minValue;\n if (maxValue !== undefined) rules.max = maxValue;\n if (pattern !== undefined) rules.pattern = pattern;\n if (email !== undefined) rules.email = email;\n if (url !== undefined) rules.url = url;\n if (validate !== undefined) rules.validate = validate;\n\n // Determine field type and auto-infer rules from input type\n const inputType = props.type ?? \"text\";\n let fieldType: \"string\" | \"number\" | \"date\" = \"string\";\n\n if (inputType === \"number\") {\n fieldType = \"number\";\n } else if (inputType === \"date\") {\n fieldType = \"date\";\n } else if (inputType === \"email\" && rules.email === undefined) {\n rules.email = true;\n } else if (inputType === \"url\" && rules.url === undefined) {\n rules.url = true;\n } else if (inputType === \"tel\" && rules.pattern === undefined) {\n rules.pattern = { value: /^\\+?[\\d\\s\\-().]{7,}$/, message: \"Invalid phone number\" };\n }\n\n registerFieldValidation({\n name: name as string,\n type: fieldType,\n rules,\n });\n\n return () => {\n unregisterFieldValidation?.(name as string);\n };\n }\n }, [\n registerFieldValidation,\n unregisterFieldValidation,\n name,\n required,\n minLength,\n maxLength,\n minValue,\n maxValue,\n pattern,\n email,\n url,\n validate,\n props.type,\n ]);\n\n // Use controller for form integration\n const { field, fieldState } = useController<TFieldValues, TName>({\n name,\n control,\n });\n\n const fieldError = fieldState.error?.message;\n const errorMessage = customError ?? fieldError;\n const hasError = !!errorMessage;\n \n // Merge sizes - prop takes precedence over form config\n const effectiveSize = size ?? formConfig.size ?? \"md\";\n const effectiveDisabled = disabled ?? formConfig.disabled;\n \n // Determine variant based on error state\n const effectiveVariant = hasError ? \"error\" : variant;\n\n const handleClear = () => {\n field.onChange(\"\");\n onClear?.();\n };\n\n return (\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\n {label && (\n <Label\n htmlFor={inputId}\n className={labelVariants({ required: !!required })}\n >\n {label}\n {formConfig.colon && \":\"}\n </Label>\n )}\n \n <div className=\"relative\">\n {prefix && (\n <div className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground\">\n {prefix}\n </div>\n )}\n \n <TextBoxPrimitive\n {...props}\n {...field}\n ref={(node) => {\n // Handle both refs\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n field.ref(node);\n }}\n id={inputId}\n disabled={effectiveDisabled}\n aria-invalid={hasError}\n aria-describedby={\n hasError\n ? `${inputId}-error`\n : helperText\n ? `${inputId}-helper`\n : undefined\n }\n className={cn(\n textBoxVariants({ size: effectiveSize, variant: effectiveVariant }),\n prefix && \"pl-10\",\n (suffix || allowClear) && \"pr-10\",\n className\n )}\n />\n\n {(suffix || (allowClear && field.value)) && (\n <div className=\"absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-1\">\n {allowClear && field.value && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"text-muted-foreground hover:text-foreground transition-colors\"\n tabIndex={-1}\n >\n <X className=\"h-4 w-4\" />\n </button>\n )}\n {suffix && (\n <span className=\"text-muted-foreground\">{suffix}</span>\n )}\n </div>\n )}\n </div>\n\n {showError && hasError && (\n <p\n id={`${inputId}-error`}\n className=\"text-sm text-destructive\"\n role=\"alert\"\n >\n {errorMessage}\n </p>\n )}\n \n {helperText && !hasError && (\n <p\n id={`${inputId}-helper`}\n className=\"text-sm text-muted-foreground\"\n >\n {helperText}\n </p>\n )}\n </div>\n );\n}\n\n// Use forwardRef with generic support\nexport const TextBox = forwardRef(TextBoxInner) as <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>(\n props: TextBoxProps<TFieldValues, TName> & { ref?: React.ForwardedRef<HTMLInputElement> }\n) => React.ReactElement;\n\n(TextBox as React.FC).displayName = \"TextBox\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"TextBox.cjs","names":[],"sources":["../../../../src/components/Form/TextBox.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { forwardRef, useId, useContext, useEffect } from \"react\";\r\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\r\nimport { useController, useFormContext as useRHFFormContext, type FieldValues, type FieldPath, type Control } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { FormConfigContext, type FormConfig, type FieldValidationRules } from \"../Form/context\";\r\nimport { FieldLayout } from \"./FieldLayout\";\r\nimport { TextBoxPrimitive } from \"../../primitives/textbox\";\r\nimport { X } from \"lucide-react\";\r\n\r\nconst textBoxVariants = cva(\r\n \"\",\r\n {\r\n variants: {\r\n size: {\r\n sm: \"h-8 text-xs px-2\",\r\n md: \"h-10 text-sm px-3\",\r\n lg: \"h-12 text-base px-4\",\r\n },\r\n variant: {\r\n default: \"border-input focus-visible:ring-ring\",\r\n error: \"border-destructive focus-visible:ring-destructive\",\r\n success: \"border-green-500 focus-visible:ring-green-500\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n variant: \"default\",\r\n },\r\n }\r\n);\r\n\r\n/**\r\n * Validation rule with optional custom message\r\n */\r\ntype ValidationRule<T> = T | { value: T; message: string };\r\n\r\nexport interface TextBoxProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends Omit<InputHTMLAttributes<HTMLInputElement>, \"size\" | \"name\" | \"prefix\" | \"pattern\" | \"required\" | \"minLength\" | \"maxLength\">,\r\n VariantProps<typeof textBoxVariants> {\r\n /** Field name - required for form integration */\r\n name: TName;\r\n /** Label text for the input */\r\n label?: string;\r\n /** Helper text displayed below the input */\r\n helperText?: string;\r\n /** Whether to show the error message */\r\n showError?: boolean;\r\n /** Custom error message (overrides form error) */\r\n error?: string;\r\n /** Whether the input should take full width */\r\n fullWidth?: boolean;\r\n /** Prefix element */\r\n prefix?: ReactNode;\r\n /** Suffix element */\r\n suffix?: ReactNode;\r\n /** Allow clear button */\r\n allowClear?: boolean;\r\n /** Callback when clear is clicked */\r\n onClear?: () => void;\r\n /** External control (for use outside Form) */\r\n control?: Control<TFieldValues>;\r\n \r\n // Validation props\r\n /** Field is required */\r\n required?: boolean | string;\r\n /** Minimum length for strings */\r\n minLength?: ValidationRule<number>;\r\n /** Maximum length for strings */\r\n maxLength?: ValidationRule<number>;\r\n /** Minimum value for numbers */\r\n minValue?: ValidationRule<number>;\r\n /** Maximum value for numbers */\r\n maxValue?: ValidationRule<number>;\r\n /** Regex pattern for validation */\r\n pattern?: ValidationRule<RegExp>;\r\n /** Email validation */\r\n email?: boolean | string;\r\n /** URL validation */\r\n url?: boolean | string;\r\n /** Custom validation function */\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\n/**\r\n * TextBox component with form integration and automatic validation registration\r\n * \r\n * This is a wrapper around the shadcn/ui Input primitive that adds:\r\n * - Form integration with react-hook-form\r\n * - Automatic validation registration\r\n * - Label, helper text, and error message support\r\n * - Prefix/suffix elements\r\n * - Clear button functionality\r\n * \r\n * @example\r\n * ```tsx\r\n * // Inside a Form component - validation is automatically registered\r\n * <Form onSubmit={handleSubmit} defaultValues={{ username: \"\", email: \"\" }}>\r\n * <TextBox name=\"username\" label=\"Username\" required minLength={3} maxLength={50} />\r\n * <TextBox name=\"email\" label=\"Email\" type=\"email\" required email />\r\n * <TextBox name=\"website\" label=\"Website\" url />\r\n * <Button type=\"submit\">Submit</Button>\r\n * </Form>\r\n * ```\r\n */\r\nfunction TextBoxInner<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n>(\r\n {\r\n name,\r\n label,\r\n helperText,\r\n showError = true,\r\n error: customError,\r\n size,\r\n variant,\r\n fullWidth = true,\r\n className,\r\n disabled,\r\n prefix,\r\n suffix,\r\n allowClear,\r\n onClear,\r\n id: providedId,\r\n control: externalControl,\r\n // Validation props\r\n required,\r\n minLength,\r\n maxLength,\r\n minValue,\r\n maxValue,\r\n pattern,\r\n email,\r\n url,\r\n validate,\r\n ...props\r\n }: TextBoxProps<TFieldValues, TName>,\r\n ref: React.ForwardedRef<HTMLInputElement>\r\n) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n \r\n // Try to get form context\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n\r\n // Get form context from react-hook-form\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n // Destructure stable function references so the effect doesn't depend on the\r\n // context object identity (which changes every render due to inline construction).\r\n const registerFieldValidation = formConfigContext?.registerFieldValidation;\r\n const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;\r\n\r\n // Register validation rules with the form\r\n useEffect(() => {\r\n if (registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n\r\n if (required !== undefined) rules.required = required;\r\n if (minLength !== undefined) rules.minLength = minLength;\r\n if (maxLength !== undefined) rules.maxLength = maxLength;\r\n if (minValue !== undefined) rules.min = minValue;\r\n if (maxValue !== undefined) rules.max = maxValue;\r\n if (pattern !== undefined) rules.pattern = pattern;\r\n if (email !== undefined) rules.email = email;\r\n if (url !== undefined) rules.url = url;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n // Determine field type and auto-infer rules from input type\r\n const inputType = props.type ?? \"text\";\r\n let fieldType: \"string\" | \"number\" | \"date\" = \"string\";\r\n\r\n if (inputType === \"number\") {\r\n fieldType = \"number\";\r\n } else if (inputType === \"date\") {\r\n fieldType = \"date\";\r\n } else if (inputType === \"email\" && rules.email === undefined) {\r\n rules.email = true;\r\n } else if (inputType === \"url\" && rules.url === undefined) {\r\n rules.url = true;\r\n } else if (inputType === \"tel\" && rules.pattern === undefined) {\r\n rules.pattern = { value: /^\\+?[\\d\\s\\-().]{7,}$/, message: \"Invalid phone number\" };\r\n }\r\n\r\n registerFieldValidation({\r\n name: name as string,\r\n type: fieldType,\r\n rules,\r\n });\r\n\r\n return () => {\r\n unregisterFieldValidation?.(name as string);\r\n };\r\n }\r\n }, [\r\n registerFieldValidation,\r\n unregisterFieldValidation,\r\n name,\r\n required,\r\n minLength,\r\n maxLength,\r\n minValue,\r\n maxValue,\r\n pattern,\r\n email,\r\n url,\r\n validate,\r\n props.type,\r\n ]);\r\n\r\n // Use controller for form integration\r\n const { field, fieldState } = useController<TFieldValues, TName>({\r\n name,\r\n control,\r\n });\r\n\r\n const fieldError = fieldState.error?.message;\r\n const errorMessage = customError ?? fieldError;\r\n const hasError = !!errorMessage;\r\n \r\n // Merge sizes - prop takes precedence over form config\r\n const effectiveSize = size ?? formConfig.size ?? \"md\";\r\n const effectiveDisabled = disabled ?? formConfig.disabled;\r\n \r\n // Determine variant based on error state\r\n const effectiveVariant = hasError ? \"error\" : variant;\r\n\r\n const handleClear = () => {\r\n field.onChange(\"\");\r\n onClear?.();\r\n };\r\n\r\n return (\r\n <FieldLayout\r\n inputId={inputId}\r\n label={label}\r\n required={!!required}\r\n helperText={helperText}\r\n errorMessage={showError ? errorMessage : undefined}\r\n showError={showError}\r\n fullWidth={fullWidth}\r\n formConfig={formConfig}\r\n >\r\n <div className=\"relative\">\r\n {prefix && (\r\n <div className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground\">\r\n {prefix}\r\n </div>\r\n )}\r\n\r\n <TextBoxPrimitive\r\n {...props}\r\n {...field}\r\n ref={(node) => {\r\n if (typeof ref === \"function\") {\r\n ref(node);\r\n } else if (ref) {\r\n ref.current = node;\r\n }\r\n field.ref(node);\r\n }}\r\n id={inputId}\r\n disabled={effectiveDisabled}\r\n aria-invalid={hasError}\r\n aria-describedby={\r\n hasError\r\n ? `${inputId}-error`\r\n : helperText\r\n ? `${inputId}-helper`\r\n : undefined\r\n }\r\n className={cn(\r\n textBoxVariants({ size: effectiveSize, variant: effectiveVariant }),\r\n prefix && \"pl-10\",\r\n (suffix || allowClear) && \"pr-10\",\r\n className\r\n )}\r\n />\r\n\r\n {(suffix || (allowClear && field.value)) && (\r\n <div className=\"absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-1\">\r\n {allowClear && field.value && (\r\n <button\r\n type=\"button\"\r\n onClick={handleClear}\r\n className=\"text-muted-foreground hover:text-foreground transition-colors\"\r\n tabIndex={-1}\r\n aria-label=\"Clear\"\r\n >\r\n <X className=\"h-4 w-4\" />\r\n </button>\r\n )}\r\n {suffix && (\r\n <span className=\"text-muted-foreground\">{suffix}</span>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n </FieldLayout>\r\n );\r\n}\r\n\r\n// Use forwardRef with generic support\r\nexport const TextBox = forwardRef(TextBoxInner) as <\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n>(\r\n props: TextBoxProps<TFieldValues, TName> & { ref?: React.ForwardedRef<HTMLInputElement> }\r\n) => React.ReactElement;\r\n\r\n(TextBox as React.FC).displayName = \"TextBox\";\r\n"],"mappings":"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"}
@@ -54,10 +54,9 @@ function buildZodSchemaFromRules(type, rules) {
54
54
  }
55
55
  if (rules.required) {
56
56
  const message = typeof rules.required === "string" ? rules.required : "This field is required";
57
- schema = schema.min(1, message);
58
- return schema;
57
+ return finalizeSchema(zod.z.preprocess((value) => value === void 0 || value === null ? "" : value, schema.min(1, message)), rules);
59
58
  }
60
- return schema.optional();
59
+ return finalizeSchema(schema.optional(), rules);
61
60
  }
62
61
  if (type === "number") {
63
62
  let schema = zod.z.coerce.number();
@@ -65,18 +64,18 @@ function buildZodSchemaFromRules(type, rules) {
65
64
  if (minRule) schema = schema.min(minRule.value, minRule.message);
66
65
  const maxRule = getValueAndMessage(rules.max, `Maximum value is ${typeof rules.max === "number" ? rules.max : rules.max?.value}`);
67
66
  if (maxRule) schema = schema.max(maxRule.value, maxRule.message);
68
- if (!rules.required) return schema.optional();
69
- return schema;
67
+ if (!rules.required) return finalizeSchema(schema.optional(), rules);
68
+ return finalizeSchema(schema, rules);
70
69
  }
71
70
  if (type === "boolean") {
72
71
  const schema = zod.z.boolean();
73
- if (rules.required) return schema.refine((val) => val === true, { message: typeof rules.required === "string" ? rules.required : "This field is required" });
74
- return schema.optional();
72
+ if (rules.required) return finalizeSchema(schema.refine((val) => val === true, { message: typeof rules.required === "string" ? rules.required : "This field is required" }), rules);
73
+ return finalizeSchema(schema.optional(), rules);
75
74
  }
76
75
  if (type === "date") {
77
76
  const schema = zod.z.coerce.date();
78
- if (!rules.required) return schema.optional();
79
- return schema;
77
+ if (!rules.required) return finalizeSchema(schema.optional(), rules);
78
+ return finalizeSchema(schema, rules);
80
79
  }
81
80
  if (type === "array") {
82
81
  let schema = zod.z.array(zod.z.unknown());
@@ -84,9 +83,24 @@ function buildZodSchemaFromRules(type, rules) {
84
83
  const message = typeof rules.required === "string" ? rules.required : "This field is required";
85
84
  schema = schema.min(1, message);
86
85
  }
87
- return schema;
86
+ return finalizeSchema(schema, rules);
88
87
  }
89
- return zod.z.unknown();
88
+ return finalizeSchema(zod.z.unknown(), rules);
89
+ }
90
+ function applyCustomValidate(schema, rules) {
91
+ if (!rules.validate) return schema;
92
+ const validateFn = rules.validate;
93
+ return schema.superRefine(async (value, ctx) => {
94
+ const result = await validateFn(value);
95
+ if (result === true) return;
96
+ ctx.addIssue({
97
+ code: zod.z.ZodIssueCode.custom,
98
+ message: typeof result === "string" ? result : "Invalid value"
99
+ });
100
+ });
101
+ }
102
+ function finalizeSchema(schema, rules) {
103
+ return applyCustomValidate(schema, rules);
90
104
  }
91
105
  /**
92
106
  * Hook to manage field validations