@skybin-tech/nebula-ui 0.0.29 → 0.0.31
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.
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -1
- package/dist/cjs/components/Accordion/Accordion.cjs.map +1 -1
- package/dist/cjs/components/Alert/Alert.cjs.map +1 -1
- package/dist/cjs/components/Avatar/Avatar.cjs.map +1 -1
- package/dist/cjs/components/Button/Button.cjs.map +1 -1
- package/dist/cjs/components/Card/Card.cjs.map +1 -1
- package/dist/cjs/components/Checkbox/Checkbox.cjs.map +1 -1
- package/dist/cjs/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
- package/dist/cjs/components/Form/Checkbox.cjs.map +1 -1
- package/dist/cjs/components/Form/Combobox.cjs.map +1 -1
- package/dist/cjs/components/Form/CountryPicker.cjs.map +1 -1
- package/dist/cjs/components/Form/CountrySelect.cjs.map +1 -1
- package/dist/cjs/components/Form/DatePicker.cjs +8 -2
- package/dist/cjs/components/Form/DatePicker.cjs.map +1 -1
- package/dist/cjs/components/Form/DateTimePicker.cjs +202 -0
- package/dist/cjs/components/Form/DateTimePicker.cjs.map +1 -0
- package/dist/cjs/components/Form/FieldLayout.cjs.map +1 -1
- package/dist/cjs/components/Form/Form.cjs +9 -8
- package/dist/cjs/components/Form/Form.cjs.map +1 -1
- package/dist/cjs/components/Form/FormSwitch.cjs.map +1 -1
- package/dist/cjs/components/Form/PasswordRevealToggle.cjs +21 -0
- package/dist/cjs/components/Form/PasswordRevealToggle.cjs.map +1 -0
- package/dist/cjs/components/Form/PhoneInput.cjs.map +1 -1
- package/dist/cjs/components/Form/Radio.cjs.map +1 -1
- package/dist/cjs/components/Form/Select.cjs.map +1 -1
- package/dist/cjs/components/Form/TextArea.cjs.map +1 -1
- package/dist/cjs/components/Form/TextBox.cjs +29 -14
- package/dist/cjs/components/Form/TextBox.cjs.map +1 -1
- package/dist/cjs/components/Form/TimePicker.cjs +111 -0
- package/dist/cjs/components/Form/TimePicker.cjs.map +1 -0
- package/dist/cjs/components/Form/context.cjs +1 -1
- package/dist/cjs/components/Form/context.cjs.map +1 -1
- package/dist/cjs/components/Form/hooks.cjs.map +1 -1
- package/dist/cjs/components/Form/index.cjs +7 -0
- package/dist/cjs/components/Form/variants.cjs.map +1 -1
- package/dist/cjs/components/Input/Input.cjs +32 -4
- package/dist/cjs/components/Input/Input.cjs.map +1 -1
- package/dist/cjs/components/Label/Label.cjs.map +1 -1
- package/dist/cjs/components/Pagination/Pagination.cjs.map +1 -1
- package/dist/cjs/components/Separator/Separator.cjs.map +1 -1
- package/dist/cjs/components/Switch/Switch.cjs.map +1 -1
- package/dist/cjs/components/Tabs/Tabs.cjs.map +1 -1
- package/dist/cjs/components/Textarea/Textarea.cjs.map +1 -1
- package/dist/cjs/components/Tooltip/Tooltip.cjs.map +1 -1
- package/dist/cjs/hooks/useDebounce.cjs.map +1 -1
- package/dist/cjs/hooks/useToggle.cjs.map +1 -1
- package/dist/cjs/index.cjs +7 -0
- package/dist/cjs/primitives/accordion.cjs.map +1 -1
- package/dist/cjs/primitives/alert.cjs.map +1 -1
- package/dist/cjs/primitives/badge.cjs.map +1 -1
- package/dist/cjs/primitives/breadcrumb.cjs.map +1 -1
- package/dist/cjs/primitives/button.cjs.map +1 -1
- package/dist/cjs/primitives/checkbox.cjs.map +1 -1
- package/dist/cjs/primitives/command.cjs.map +1 -1
- package/dist/cjs/primitives/dialog.cjs.map +1 -1
- package/dist/cjs/primitives/dropdown-menu.cjs.map +1 -1
- package/dist/cjs/primitives/input-otp.cjs.map +1 -1
- package/dist/cjs/primitives/label.cjs.map +1 -1
- package/dist/cjs/primitives/progress.cjs.map +1 -1
- package/dist/cjs/primitives/radio-group.cjs.map +1 -1
- package/dist/cjs/primitives/scroll-area.cjs.map +1 -1
- package/dist/cjs/primitives/select.cjs.map +1 -1
- package/dist/cjs/primitives/sheet.cjs.map +1 -1
- package/dist/cjs/primitives/slider.cjs.map +1 -1
- package/dist/cjs/primitives/switch.cjs.map +1 -1
- package/dist/cjs/primitives/table.cjs.map +1 -1
- package/dist/cjs/primitives/toast.cjs.map +1 -1
- package/dist/cjs/primitives/toggle.cjs.map +1 -1
- package/dist/cjs/utils/cn.cjs.map +1 -1
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Form/Checkbox.js.map +1 -1
- package/dist/components/Form/Combobox.js.map +1 -1
- package/dist/components/Form/CountryPicker.js.map +1 -1
- package/dist/components/Form/CountrySelect.js.map +1 -1
- package/dist/components/Form/DatePicker.d.ts.map +1 -1
- package/dist/components/Form/DatePicker.js +9 -3
- package/dist/components/Form/DatePicker.js.map +1 -1
- package/dist/components/Form/DateTimePicker.d.ts +28 -0
- package/dist/components/Form/DateTimePicker.d.ts.map +1 -0
- package/dist/components/Form/DateTimePicker.js +202 -0
- package/dist/components/Form/DateTimePicker.js.map +1 -0
- package/dist/components/Form/FieldLayout.js.map +1 -1
- package/dist/components/Form/Form.js +9 -8
- package/dist/components/Form/Form.js.map +1 -1
- package/dist/components/Form/FormSwitch.js.map +1 -1
- package/dist/components/Form/PasswordRevealToggle.d.ts +7 -0
- package/dist/components/Form/PasswordRevealToggle.d.ts.map +1 -0
- package/dist/components/Form/PasswordRevealToggle.js +21 -0
- package/dist/components/Form/PasswordRevealToggle.js.map +1 -0
- package/dist/components/Form/PhoneInput.js.map +1 -1
- package/dist/components/Form/Radio.js.map +1 -1
- package/dist/components/Form/Select.js.map +1 -1
- package/dist/components/Form/TextArea.js.map +1 -1
- package/dist/components/Form/TextBox.d.ts +5 -0
- package/dist/components/Form/TextBox.d.ts.map +1 -1
- package/dist/components/Form/TextBox.js +30 -15
- package/dist/components/Form/TextBox.js.map +1 -1
- package/dist/components/Form/TimePicker.d.ts +14 -0
- package/dist/components/Form/TimePicker.d.ts.map +1 -0
- package/dist/components/Form/TimePicker.js +111 -0
- package/dist/components/Form/TimePicker.js.map +1 -0
- package/dist/components/Form/context.d.ts +1 -1
- package/dist/components/Form/context.d.ts.map +1 -1
- package/dist/components/Form/context.js +1 -1
- package/dist/components/Form/context.js.map +1 -1
- package/dist/components/Form/index.d.ts +6 -0
- package/dist/components/Form/index.d.ts.map +1 -1
- package/dist/components/Form/index.js +4 -1
- package/dist/components/Input/Input.d.ts +14 -2
- package/dist/components/Input/Input.d.ts.map +1 -1
- package/dist/components/Input/Input.js +34 -6
- package/dist/components/Input/Input.js.map +1 -1
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/primitives/accordion.js.map +1 -1
- package/dist/primitives/breadcrumb.js.map +1 -1
- package/dist/primitives/checkbox.js.map +1 -1
- package/dist/primitives/command.js.map +1 -1
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/dropdown-menu.js.map +1 -1
- package/dist/primitives/input-otp.js.map +1 -1
- package/dist/primitives/progress.js.map +1 -1
- package/dist/primitives/radio-group.js.map +1 -1
- package/dist/primitives/scroll-area.js.map +1 -1
- package/dist/primitives/select.js.map +1 -1
- package/dist/primitives/sheet.js.map +1 -1
- package/dist/primitives/slider.js.map +1 -1
- package/dist/primitives/switch.js.map +1 -1
- package/dist/primitives/table.js.map +1 -1
- package/dist/primitives/toast.js.map +1 -1
- package/package.json +22 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.js","names":[],"sources":["../../../src/components/Form/Combobox.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useContext, useEffect, useId, useMemo, useState } from \"react\";\r\nimport { Check, ChevronsUpDown } from \"lucide-react\";\r\nimport { useController, useFormContext as useRHFFormContext, type Control, type FieldPath, type FieldValues } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Button } from \"../../primitives/button\";\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n} from \"../../primitives/command\";\r\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\r\nimport { FormConfigContext, type FieldValidationRules, type FormConfig } from \"./context\";\r\nimport { FieldLayout } from \"./FieldLayout\";\r\nimport type { SelectOption } from \"./Select\";\r\n\r\nconst comboboxVariants = cva(\"w-full justify-between font-normal\", {\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 variant: {\r\n default: \"border-input\",\r\n error: \"border-destructive\",\r\n success: \"border-green-500\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n variant: \"default\",\r\n },\r\n});\r\n\r\nexport interface ComboboxProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends VariantProps<typeof comboboxVariants> {\r\n name: TName;\r\n label?: string;\r\n helperText?: string;\r\n showError?: boolean;\r\n error?: string;\r\n fullWidth?: boolean;\r\n placeholder?: string;\r\n searchPlaceholder?: string;\r\n emptyText?: string;\r\n options?: SelectOption[];\r\n disabled?: boolean;\r\n className?: string;\r\n id?: string;\r\n control?: Control<TFieldValues>;\r\n required?: boolean | string;\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\nexport function Combobox<\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 placeholder = \"Select option\",\r\n searchPlaceholder = \"Search...\",\r\n emptyText = \"No option found.\",\r\n options = [],\r\n disabled,\r\n className,\r\n id: providedId,\r\n control: externalControl,\r\n required,\r\n validate,\r\n}: ComboboxProps<TFieldValues, TName>) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n const [open, setOpen] = useState(false);\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n const registerFieldValidation = formConfigContext?.registerFieldValidation;\r\n const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;\r\n\r\n useEffect(() => {\r\n if (registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n if (required !== undefined) rules.required = required;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n registerFieldValidation({\r\n name: name as string,\r\n type: \"string\",\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 validate,\r\n ]);\r\n\r\n const { field, fieldState } = useController<TFieldValues, TName>({\r\n name,\r\n control,\r\n });\r\n\r\n const selectedOption = useMemo(\r\n () => options.find((option) => option.value.toString() === field.value?.toString()),\r\n [field.value, options]\r\n );\r\n\r\n const fieldError = fieldState.error?.message;\r\n const errorMessage = customError ?? fieldError;\r\n const hasError = !!errorMessage;\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 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 <Popover open={open} onOpenChange={setOpen}>\r\n <PopoverTrigger asChild>\r\n <Button\r\n id={inputId}\r\n type=\"button\"\r\n variant=\"outline\"\r\n role=\"combobox\"\r\n aria-expanded={open}\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 comboboxVariants({ size: effectiveSize, variant: effectiveVariant }),\r\n !field.value && \"text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n {selectedOption?.label ?? placeholder}\r\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\r\n </Button>\r\n </PopoverTrigger>\r\n <PopoverContent className=\"w-[320px] p-0\" align=\"start\">\r\n <Command>\r\n <CommandInput placeholder={searchPlaceholder} />\r\n <CommandList>\r\n <CommandEmpty>{emptyText}</CommandEmpty>\r\n <CommandGroup>\r\n {options.map((option) => (\r\n <CommandItem\r\n key={option.value}\r\n value={option.label}\r\n disabled={option.disabled}\r\n onSelect={() => {\r\n field.onChange(option.value.toString());\r\n setOpen(false);\r\n }}\r\n >\r\n <Check\r\n className={cn(\r\n \"mr-2 h-4 w-4\",\r\n field.value?.toString() === option.value.toString()\r\n ? \"opacity-100\"\r\n : \"opacity-0\"\r\n )}\r\n />\r\n {option.label}\r\n </CommandItem>\r\n ))}\r\n </CommandGroup>\r\n </CommandList>\r\n </Command>\r\n </PopoverContent>\r\n </Popover>\r\n </FieldLayout>\r\n );\r\n}\r\n\r\nCombobox.displayName = \"Combobox\";\r\n"],"mappings":";;;;;;;;;;;;;;AAqBA,IAAM,mBAAmB,IAAI,sCAAsC;CACjE,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,CAAC;AAwBD,SAAgB,SAGd,EACA,MACA,OACA,YACA,YAAY,MACZ,OAAO,aACP,MACA,SACA,YAAY,MACZ,cAAc,iBACd,oBAAoB,aACpB,YAAY,oBACZ,UAAU,CAAC,GACX,UACA,WACA,IAAI,YACJ,SAAS,iBACT,UACA,YACqC;CACrC,MAAM,cAAc,MAAM;CAC1B,MAAM,UAAU,cAAc;CAC9B,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,oBAAoB,WAAW,iBAAiB;CACtD,MAAM,aAAyB,qBAAqB,CAAC;CACrD,MAAM,aAAa,eAAgC;CACnD,MAAM,UAAU,mBAAmB,YAAY;CAE/C,MAAM,0BAA0B,mBAAmB;CACnD,MAAM,4BAA4B,mBAAmB;CAErD,gBAAgB;EACd,IAAI,yBAAyB;GAC3B,MAAM,QAA8B,CAAC;GACrC,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAC7C,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAE7C,wBAAwB;IAChB;IACN,MAAM;IACN;GACF,CAAC;GAED,aAAa;IACX,4BAA4B,IAAc;GAC5C;EACF;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,OAAO,eAAe,cAAmC;EAC/D;EACA;CACF,CAAC;CAED,MAAM,iBAAiB,cACf,QAAQ,MAAM,WAAW,OAAO,MAAM,SAAS,MAAM,MAAM,OAAO,SAAS,CAAC,GAClF,CAAC,MAAM,OAAO,OAAO,CACvB;CAEA,MAAM,aAAa,WAAW,OAAO;CACrC,MAAM,eAAe,eAAe;CACpC,MAAM,WAAW,CAAC,CAAC;CACnB,MAAM,gBAAgB,QAAQ,WAAW,QAAQ;CACjD,MAAM,oBAAoB,YAAY,WAAW;CACjD,MAAM,mBAAmB,WAAW,UAAU;CAE9C,OACE,oBAAC,aAAD;EACW;EACF;EACP,UAAU,CAAC,CAAC;EACA;EACZ,cAAc,YAAY,eAAe,KAAA;EAC9B;EACA;EACC;
|
|
1
|
+
{"version":3,"file":"Combobox.js","names":[],"sources":["../../../src/components/Form/Combobox.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useContext, useEffect, useId, useMemo, useState } from \"react\";\r\nimport { Check, ChevronsUpDown } from \"lucide-react\";\r\nimport { useController, useFormContext as useRHFFormContext, type Control, type FieldPath, type FieldValues } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Button } from \"../../primitives/button\";\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n} from \"../../primitives/command\";\r\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\r\nimport { FormConfigContext, type FieldValidationRules, type FormConfig } from \"./context\";\r\nimport { FieldLayout } from \"./FieldLayout\";\r\nimport type { SelectOption } from \"./Select\";\r\n\r\nconst comboboxVariants = cva(\"w-full justify-between font-normal\", {\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 variant: {\r\n default: \"border-input\",\r\n error: \"border-destructive\",\r\n success: \"border-green-500\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n variant: \"default\",\r\n },\r\n});\r\n\r\nexport interface ComboboxProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends VariantProps<typeof comboboxVariants> {\r\n name: TName;\r\n label?: string;\r\n helperText?: string;\r\n showError?: boolean;\r\n error?: string;\r\n fullWidth?: boolean;\r\n placeholder?: string;\r\n searchPlaceholder?: string;\r\n emptyText?: string;\r\n options?: SelectOption[];\r\n disabled?: boolean;\r\n className?: string;\r\n id?: string;\r\n control?: Control<TFieldValues>;\r\n required?: boolean | string;\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\nexport function Combobox<\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 placeholder = \"Select option\",\r\n searchPlaceholder = \"Search...\",\r\n emptyText = \"No option found.\",\r\n options = [],\r\n disabled,\r\n className,\r\n id: providedId,\r\n control: externalControl,\r\n required,\r\n validate,\r\n}: ComboboxProps<TFieldValues, TName>) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n const [open, setOpen] = useState(false);\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n const registerFieldValidation = formConfigContext?.registerFieldValidation;\r\n const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;\r\n\r\n useEffect(() => {\r\n if (registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n if (required !== undefined) rules.required = required;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n registerFieldValidation({\r\n name: name as string,\r\n type: \"string\",\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 validate,\r\n ]);\r\n\r\n const { field, fieldState } = useController<TFieldValues, TName>({\r\n name,\r\n control,\r\n });\r\n\r\n const selectedOption = useMemo(\r\n () => options.find((option) => option.value.toString() === field.value?.toString()),\r\n [field.value, options]\r\n );\r\n\r\n const fieldError = fieldState.error?.message;\r\n const errorMessage = customError ?? fieldError;\r\n const hasError = !!errorMessage;\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 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 <Popover open={open} onOpenChange={setOpen}>\r\n <PopoverTrigger asChild>\r\n <Button\r\n id={inputId}\r\n type=\"button\"\r\n variant=\"outline\"\r\n role=\"combobox\"\r\n aria-expanded={open}\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 comboboxVariants({ size: effectiveSize, variant: effectiveVariant }),\r\n !field.value && \"text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n {selectedOption?.label ?? placeholder}\r\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\r\n </Button>\r\n </PopoverTrigger>\r\n <PopoverContent className=\"w-[320px] p-0\" align=\"start\">\r\n <Command>\r\n <CommandInput placeholder={searchPlaceholder} />\r\n <CommandList>\r\n <CommandEmpty>{emptyText}</CommandEmpty>\r\n <CommandGroup>\r\n {options.map((option) => (\r\n <CommandItem\r\n key={option.value}\r\n value={option.label}\r\n disabled={option.disabled}\r\n onSelect={() => {\r\n field.onChange(option.value.toString());\r\n setOpen(false);\r\n }}\r\n >\r\n <Check\r\n className={cn(\r\n \"mr-2 h-4 w-4\",\r\n field.value?.toString() === option.value.toString()\r\n ? \"opacity-100\"\r\n : \"opacity-0\"\r\n )}\r\n />\r\n {option.label}\r\n </CommandItem>\r\n ))}\r\n </CommandGroup>\r\n </CommandList>\r\n </Command>\r\n </PopoverContent>\r\n </Popover>\r\n </FieldLayout>\r\n );\r\n}\r\n\r\nCombobox.displayName = \"Combobox\";\r\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CountryPicker.js","names":[],"sources":["../../../src/components/Form/CountryPicker.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useMemo, useState } from \"react\";\r\nimport { Check, ChevronsUpDown } from \"lucide-react\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Button } from \"../../primitives/button\";\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n} from \"../../primitives/command\";\r\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\r\nimport {\r\n COUNTRIES,\r\n filterCountries,\r\n getCountryByCode,\r\n getCountryFlag,\r\n sortCountriesWithPriority,\r\n type Country,\r\n} from \"../../data/countries\";\r\n\r\nexport interface CountryPickerProps {\r\n value?: string;\r\n onValueChange: (value: string) => void;\r\n placeholder?: string;\r\n disabled?: boolean;\r\n compact?: boolean;\r\n include?: string[];\r\n exclude?: string[];\r\n priorityCountries?: string[];\r\n className?: string;\r\n id?: string;\r\n required?: boolean;\r\n \"aria-invalid\"?: boolean;\r\n \"aria-describedby\"?: string;\r\n}\r\n\r\nfunction resolveCountries(\r\n include?: string[],\r\n exclude?: string[],\r\n priorityCountries?: string[]\r\n): Country[] {\r\n let countries = COUNTRIES;\r\n\r\n if (include?.length) {\r\n const includeSet = new Set(include.map((code) => code.toUpperCase()));\r\n countries = countries.filter((country) => includeSet.has(country.code));\r\n }\r\n\r\n if (exclude?.length) {\r\n const excludeSet = new Set(exclude.map((code) => code.toUpperCase()));\r\n countries = countries.filter((country) => !excludeSet.has(country.code));\r\n }\r\n\r\n return sortCountriesWithPriority(countries, priorityCountries);\r\n}\r\n\r\nexport function CountryPicker({\r\n value,\r\n onValueChange,\r\n placeholder = \"Select country\",\r\n disabled,\r\n compact = false,\r\n include,\r\n exclude,\r\n priorityCountries,\r\n className,\r\n id,\r\n required,\r\n \"aria-invalid\": ariaInvalid,\r\n \"aria-describedby\": ariaDescribedBy,\r\n}: CountryPickerProps) {\r\n const [open, setOpen] = useState(false);\r\n const countries = useMemo(\r\n () => resolveCountries(include, exclude, priorityCountries),\r\n [include, exclude, priorityCountries]\r\n );\r\n const selectedCountry = value ? getCountryByCode(value) : undefined;\r\n\r\n return (\r\n <Popover open={open} onOpenChange={setOpen}>\r\n <PopoverTrigger asChild>\r\n <Button\r\n id={id}\r\n type=\"button\"\r\n variant=\"outline\"\r\n role=\"combobox\"\r\n aria-expanded={open}\r\n aria-required={required}\r\n aria-invalid={ariaInvalid}\r\n aria-describedby={ariaDescribedBy}\r\n disabled={disabled}\r\n className={cn(\r\n \"justify-between font-normal\",\r\n compact ? \"h-full w-auto shrink-0 border-0 bg-transparent px-2 shadow-none hover:bg-transparent\" : \"w-full\",\r\n !value && \"text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n {selectedCountry ? (\r\n <span className=\"flex min-w-0 items-center gap-2 truncate\">\r\n <span aria-hidden=\"true\">{getCountryFlag(selectedCountry.code)}</span>\r\n {!compact && <span className=\"truncate\">{selectedCountry.name}</span>}\r\n </span>\r\n ) : (\r\n <span className=\"truncate\">{compact ? \"…\" : placeholder}</span>\r\n )}\r\n {!compact && <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />}\r\n </Button>\r\n </PopoverTrigger>\r\n <PopoverContent className=\"w-[320px] p-0\" align=\"start\">\r\n <Command\r\n filter={(itemValue, search) => {\r\n const country = countries.find(\r\n (entry) => entry.code.toLowerCase() === itemValue.toLowerCase()\r\n );\r\n if (!country) {\r\n return 0;\r\n }\r\n\r\n return filterCountries([country], search).length > 0 ? 1 : 0;\r\n }}\r\n >\r\n <CommandInput placeholder=\"Search country...\" />\r\n <CommandList>\r\n <CommandEmpty>No country found.</CommandEmpty>\r\n <CommandGroup>\r\n {countries.map((country) => (\r\n <CommandItem\r\n key={country.code}\r\n value={country.code}\r\n onSelect={(currentValue) => {\r\n onValueChange(currentValue.toUpperCase());\r\n setOpen(false);\r\n }}\r\n >\r\n <Check\r\n className={cn(\r\n \"mr-2 h-4 w-4\",\r\n value === country.code ? \"opacity-100\" : \"opacity-0\"\r\n )}\r\n />\r\n <span aria-hidden=\"true\" className=\"mr-2\">\r\n {getCountryFlag(country.code)}\r\n </span>\r\n <span className=\"truncate\">{country.name}</span>\r\n <span className=\"ml-auto text-xs text-muted-foreground\">\r\n {country.dialCode}\r\n </span>\r\n </CommandItem>\r\n ))}\r\n </CommandGroup>\r\n </CommandList>\r\n </Command>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n\r\n"],"mappings":";;;;;;;;;;;AAwCA,SAAS,iBACP,SACA,SACA,mBACW;CACX,IAAI,YAAY;CAEhB,IAAI,SAAS,QAAQ;EACnB,MAAM,aAAa,IAAI,IAAI,QAAQ,KAAK,SAAS,KAAK,YAAY,CAAC,CAAC;EACpE,YAAY,UAAU,QAAQ,YAAY,WAAW,IAAI,QAAQ,IAAI,CAAC;CACxE;CAEA,IAAI,SAAS,QAAQ;EACnB,MAAM,aAAa,IAAI,IAAI,QAAQ,KAAK,SAAS,KAAK,YAAY,CAAC,CAAC;EACpE,YAAY,UAAU,QAAQ,YAAY,CAAC,WAAW,IAAI,QAAQ,IAAI,CAAC;CACzE;CAEA,OAAO,0BAA0B,WAAW,iBAAiB;AAC/D;AAEA,SAAgB,cAAc,EAC5B,OACA,eACA,cAAc,kBACd,UACA,UAAU,OACV,SACA,SACA,mBACA,WACA,IACA,UACA,gBAAgB,aAChB,oBAAoB,mBACC;CACrB,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,YAAY,cACV,iBAAiB,SAAS,SAAS,iBAAiB,GAC1D;EAAC;EAAS;EAAS;CAAiB,CACtC;CACA,MAAM,kBAAkB,QAAQ,iBAAiB,KAAK,IAAI,KAAA;CAE1D,OACE,qBAAC,SAAD;EAAe;EAAM,cAAc;
|
|
1
|
+
{"version":3,"file":"CountryPicker.js","names":[],"sources":["../../../src/components/Form/CountryPicker.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useMemo, useState } from \"react\";\r\nimport { Check, ChevronsUpDown } from \"lucide-react\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Button } from \"../../primitives/button\";\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n} from \"../../primitives/command\";\r\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\r\nimport {\r\n COUNTRIES,\r\n filterCountries,\r\n getCountryByCode,\r\n getCountryFlag,\r\n sortCountriesWithPriority,\r\n type Country,\r\n} from \"../../data/countries\";\r\n\r\nexport interface CountryPickerProps {\r\n value?: string;\r\n onValueChange: (value: string) => void;\r\n placeholder?: string;\r\n disabled?: boolean;\r\n compact?: boolean;\r\n include?: string[];\r\n exclude?: string[];\r\n priorityCountries?: string[];\r\n className?: string;\r\n id?: string;\r\n required?: boolean;\r\n \"aria-invalid\"?: boolean;\r\n \"aria-describedby\"?: string;\r\n}\r\n\r\nfunction resolveCountries(\r\n include?: string[],\r\n exclude?: string[],\r\n priorityCountries?: string[]\r\n): Country[] {\r\n let countries = COUNTRIES;\r\n\r\n if (include?.length) {\r\n const includeSet = new Set(include.map((code) => code.toUpperCase()));\r\n countries = countries.filter((country) => includeSet.has(country.code));\r\n }\r\n\r\n if (exclude?.length) {\r\n const excludeSet = new Set(exclude.map((code) => code.toUpperCase()));\r\n countries = countries.filter((country) => !excludeSet.has(country.code));\r\n }\r\n\r\n return sortCountriesWithPriority(countries, priorityCountries);\r\n}\r\n\r\nexport function CountryPicker({\r\n value,\r\n onValueChange,\r\n placeholder = \"Select country\",\r\n disabled,\r\n compact = false,\r\n include,\r\n exclude,\r\n priorityCountries,\r\n className,\r\n id,\r\n required,\r\n \"aria-invalid\": ariaInvalid,\r\n \"aria-describedby\": ariaDescribedBy,\r\n}: CountryPickerProps) {\r\n const [open, setOpen] = useState(false);\r\n const countries = useMemo(\r\n () => resolveCountries(include, exclude, priorityCountries),\r\n [include, exclude, priorityCountries]\r\n );\r\n const selectedCountry = value ? getCountryByCode(value) : undefined;\r\n\r\n return (\r\n <Popover open={open} onOpenChange={setOpen}>\r\n <PopoverTrigger asChild>\r\n <Button\r\n id={id}\r\n type=\"button\"\r\n variant=\"outline\"\r\n role=\"combobox\"\r\n aria-expanded={open}\r\n aria-required={required}\r\n aria-invalid={ariaInvalid}\r\n aria-describedby={ariaDescribedBy}\r\n disabled={disabled}\r\n className={cn(\r\n \"justify-between font-normal\",\r\n compact ? \"h-full w-auto shrink-0 border-0 bg-transparent px-2 shadow-none hover:bg-transparent\" : \"w-full\",\r\n !value && \"text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n {selectedCountry ? (\r\n <span className=\"flex min-w-0 items-center gap-2 truncate\">\r\n <span aria-hidden=\"true\">{getCountryFlag(selectedCountry.code)}</span>\r\n {!compact && <span className=\"truncate\">{selectedCountry.name}</span>}\r\n </span>\r\n ) : (\r\n <span className=\"truncate\">{compact ? \"…\" : placeholder}</span>\r\n )}\r\n {!compact && <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />}\r\n </Button>\r\n </PopoverTrigger>\r\n <PopoverContent className=\"w-[320px] p-0\" align=\"start\">\r\n <Command\r\n filter={(itemValue, search) => {\r\n const country = countries.find(\r\n (entry) => entry.code.toLowerCase() === itemValue.toLowerCase()\r\n );\r\n if (!country) {\r\n return 0;\r\n }\r\n\r\n return filterCountries([country], search).length > 0 ? 1 : 0;\r\n }}\r\n >\r\n <CommandInput placeholder=\"Search country...\" />\r\n <CommandList>\r\n <CommandEmpty>No country found.</CommandEmpty>\r\n <CommandGroup>\r\n {countries.map((country) => (\r\n <CommandItem\r\n key={country.code}\r\n value={country.code}\r\n onSelect={(currentValue) => {\r\n onValueChange(currentValue.toUpperCase());\r\n setOpen(false);\r\n }}\r\n >\r\n <Check\r\n className={cn(\r\n \"mr-2 h-4 w-4\",\r\n value === country.code ? \"opacity-100\" : \"opacity-0\"\r\n )}\r\n />\r\n <span aria-hidden=\"true\" className=\"mr-2\">\r\n {getCountryFlag(country.code)}\r\n </span>\r\n <span className=\"truncate\">{country.name}</span>\r\n <span className=\"ml-auto text-xs text-muted-foreground\">\r\n {country.dialCode}\r\n </span>\r\n </CommandItem>\r\n ))}\r\n </CommandGroup>\r\n </CommandList>\r\n </Command>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n\r\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CountrySelect.js","names":[],"sources":["../../../src/components/Form/CountrySelect.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useContext, useEffect, useId } from \"react\";\r\nimport { useController, useFormContext as useRHFFormContext, type Control, type FieldPath, type FieldValues } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { FormConfigContext, type FieldValidationRules, type FormConfig } from \"./context\";\r\nimport { FieldLayout } from \"./FieldLayout\";\r\nimport { CountryPicker } from \"./CountryPicker\";\r\n\r\nconst countrySelectVariants = cva(\"\", {\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 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\nexport interface CountrySelectProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends VariantProps<typeof countrySelectVariants> {\r\n name: TName;\r\n label?: string;\r\n helperText?: string;\r\n showError?: boolean;\r\n error?: string;\r\n fullWidth?: boolean;\r\n placeholder?: string;\r\n allowClear?: boolean;\r\n disabled?: boolean;\r\n className?: string;\r\n id?: string;\r\n control?: Control<TFieldValues>;\r\n include?: string[];\r\n exclude?: string[];\r\n priorityCountries?: string[];\r\n /** Field is required (`true` or custom error message string) */\r\n required?: boolean | string;\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\nexport function CountrySelect<\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 placeholder = \"Select a country\",\r\n allowClear,\r\n disabled,\r\n className,\r\n id: providedId,\r\n control: externalControl,\r\n include,\r\n exclude,\r\n priorityCountries,\r\n required,\r\n validate,\r\n}: CountrySelectProps<TFieldValues, TName>) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n const registerFieldValidation = formConfigContext?.registerFieldValidation;\r\n const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;\r\n\r\n useEffect(() => {\r\n if (registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n if (required !== undefined) rules.required = required;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n registerFieldValidation({\r\n name: name as string,\r\n type: \"string\",\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 validate,\r\n ]);\r\n\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 const effectiveSize = size ?? formConfig.size ?? \"md\";\r\n const effectiveDisabled = disabled ?? formConfig.disabled;\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 <div className=\"flex gap-2\">\r\n <CountryPicker\r\n id={inputId}\r\n value={field.value ?? \"\"}\r\n onValueChange={(value) => field.onChange(value)}\r\n placeholder={placeholder}\r\n disabled={effectiveDisabled}\r\n include={include}\r\n exclude={exclude}\r\n priorityCountries={priorityCountries}\r\n required={!!required}\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 countrySelectVariants({ size: effectiveSize, variant: effectiveVariant }),\r\n className\r\n )}\r\n />\r\n {allowClear && field.value && (\r\n <button\r\n type=\"button\"\r\n className=\"text-sm text-muted-foreground hover:text-foreground\"\r\n onClick={() => field.onChange(\"\")}\r\n disabled={effectiveDisabled}\r\n >\r\n Clear\r\n </button>\r\n )}\r\n </div>\r\n </FieldLayout>\r\n );\r\n}\r\n\r\nCountrySelect.displayName = \"CountrySelect\";\r\n"],"mappings":";;;;;;;;;;;AAUA,IAAM,wBAAwB,IAAI,IAAI;CACpC,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,CAAC;AA0BD,SAAgB,cAGd,EACA,MACA,OACA,YACA,YAAY,MACZ,OAAO,aACP,MACA,SACA,YAAY,MACZ,cAAc,oBACd,YACA,UACA,WACA,IAAI,YACJ,SAAS,iBACT,SACA,SACA,mBACA,UACA,YAC0C;CAC1C,MAAM,cAAc,MAAM;CAC1B,MAAM,UAAU,cAAc;CAC9B,MAAM,oBAAoB,WAAW,iBAAiB;CACtD,MAAM,aAAyB,qBAAqB,CAAC;CACrD,MAAM,aAAa,eAAgC;CACnD,MAAM,UAAU,mBAAmB,YAAY;CAE/C,MAAM,0BAA0B,mBAAmB;CACnD,MAAM,4BAA4B,mBAAmB;CAErD,gBAAgB;EACd,IAAI,yBAAyB;GAC3B,MAAM,QAA8B,CAAC;GACrC,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAC7C,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAE7C,wBAAwB;IAChB;IACN,MAAM;IACN;GACF,CAAC;GAED,aAAa;IACX,4BAA4B,IAAc;GAC5C;EACF;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,OAAO,eAAe,cAAmC;EAC/D;EACA;CACF,CAAC;CAED,MAAM,aAAa,WAAW,OAAO;CACrC,MAAM,eAAe,eAAe;CACpC,MAAM,WAAW,CAAC,CAAC;CACnB,MAAM,gBAAgB,QAAQ,WAAW,QAAQ;CACjD,MAAM,oBAAoB,YAAY,WAAW;CACjD,MAAM,mBAAmB,WAAW,UAAU;CAE9C,OACE,oBAAC,aAAD;EACW;EACF;EACP,UAAU,CAAC,CAAC;EACA;EACZ,cAAc,YAAY,eAAe,KAAA;EAC9B;EACA;EACC;
|
|
1
|
+
{"version":3,"file":"CountrySelect.js","names":[],"sources":["../../../src/components/Form/CountrySelect.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useContext, useEffect, useId } from \"react\";\r\nimport { useController, useFormContext as useRHFFormContext, type Control, type FieldPath, type FieldValues } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { FormConfigContext, type FieldValidationRules, type FormConfig } from \"./context\";\r\nimport { FieldLayout } from \"./FieldLayout\";\r\nimport { CountryPicker } from \"./CountryPicker\";\r\n\r\nconst countrySelectVariants = cva(\"\", {\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 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\nexport interface CountrySelectProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends VariantProps<typeof countrySelectVariants> {\r\n name: TName;\r\n label?: string;\r\n helperText?: string;\r\n showError?: boolean;\r\n error?: string;\r\n fullWidth?: boolean;\r\n placeholder?: string;\r\n allowClear?: boolean;\r\n disabled?: boolean;\r\n className?: string;\r\n id?: string;\r\n control?: Control<TFieldValues>;\r\n include?: string[];\r\n exclude?: string[];\r\n priorityCountries?: string[];\r\n /** Field is required (`true` or custom error message string) */\r\n required?: boolean | string;\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\nexport function CountrySelect<\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 placeholder = \"Select a country\",\r\n allowClear,\r\n disabled,\r\n className,\r\n id: providedId,\r\n control: externalControl,\r\n include,\r\n exclude,\r\n priorityCountries,\r\n required,\r\n validate,\r\n}: CountrySelectProps<TFieldValues, TName>) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n const registerFieldValidation = formConfigContext?.registerFieldValidation;\r\n const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;\r\n\r\n useEffect(() => {\r\n if (registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n if (required !== undefined) rules.required = required;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n registerFieldValidation({\r\n name: name as string,\r\n type: \"string\",\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 validate,\r\n ]);\r\n\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 const effectiveSize = size ?? formConfig.size ?? \"md\";\r\n const effectiveDisabled = disabled ?? formConfig.disabled;\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 <div className=\"flex gap-2\">\r\n <CountryPicker\r\n id={inputId}\r\n value={field.value ?? \"\"}\r\n onValueChange={(value) => field.onChange(value)}\r\n placeholder={placeholder}\r\n disabled={effectiveDisabled}\r\n include={include}\r\n exclude={exclude}\r\n priorityCountries={priorityCountries}\r\n required={!!required}\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 countrySelectVariants({ size: effectiveSize, variant: effectiveVariant }),\r\n className\r\n )}\r\n />\r\n {allowClear && field.value && (\r\n <button\r\n type=\"button\"\r\n className=\"text-sm text-muted-foreground hover:text-foreground\"\r\n onClick={() => field.onChange(\"\")}\r\n disabled={effectiveDisabled}\r\n >\r\n Clear\r\n </button>\r\n )}\r\n </div>\r\n </FieldLayout>\r\n );\r\n}\r\n\r\nCountrySelect.displayName = \"CountrySelect\";\r\n"],"mappings":";;;;;;;;;;;AAUA,IAAM,wBAAwB,IAAI,IAAI;CACpC,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,CAAC;AA0BD,SAAgB,cAGd,EACA,MACA,OACA,YACA,YAAY,MACZ,OAAO,aACP,MACA,SACA,YAAY,MACZ,cAAc,oBACd,YACA,UACA,WACA,IAAI,YACJ,SAAS,iBACT,SACA,SACA,mBACA,UACA,YAC0C;CAC1C,MAAM,cAAc,MAAM;CAC1B,MAAM,UAAU,cAAc;CAC9B,MAAM,oBAAoB,WAAW,iBAAiB;CACtD,MAAM,aAAyB,qBAAqB,CAAC;CACrD,MAAM,aAAa,eAAgC;CACnD,MAAM,UAAU,mBAAmB,YAAY;CAE/C,MAAM,0BAA0B,mBAAmB;CACnD,MAAM,4BAA4B,mBAAmB;CAErD,gBAAgB;EACd,IAAI,yBAAyB;GAC3B,MAAM,QAA8B,CAAC;GACrC,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAC7C,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAE7C,wBAAwB;IAChB;IACN,MAAM;IACN;GACF,CAAC;GAED,aAAa;IACX,4BAA4B,IAAc;GAC5C;EACF;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,OAAO,eAAe,cAAmC;EAC/D;EACA;CACF,CAAC;CAED,MAAM,aAAa,WAAW,OAAO;CACrC,MAAM,eAAe,eAAe;CACpC,MAAM,WAAW,CAAC,CAAC;CACnB,MAAM,gBAAgB,QAAQ,WAAW,QAAQ;CACjD,MAAM,oBAAoB,YAAY,WAAW;CACjD,MAAM,mBAAmB,WAAW,UAAU;CAE9C,OACE,oBAAC,aAAD;EACW;EACF;EACP,UAAU,CAAC,CAAC;EACA;EACZ,cAAc,YAAY,eAAe,KAAA;EAC9B;EACA;EACC;EAEZ,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,eAAD;IACE,IAAI;IACJ,OAAO,MAAM,SAAS;IACtB,gBAAgB,UAAU,MAAM,SAAS,KAAK;IACjC;IACb,UAAU;IACD;IACA;IACU;IACnB,UAAU,CAAC,CAAC;IACZ,gBAAc;IACd,oBACE,WACI,GAAG,QAAQ,UACX,aACE,GAAG,QAAQ,WACX,KAAA;IAER,WAAW,GACT,sBAAsB;KAAE,MAAM;KAAe,SAAS;IAAiB,CAAC,GACxE,SACF;GACD,CAAA,GACA,cAAc,MAAM,SACnB,oBAAC,UAAD;IACE,MAAK;IACL,WAAU;IACV,eAAe,MAAM,SAAS,EAAE;IAChC,UAAU;IACX,UAAA;GAEO,CAAA,CAEP;;CACM,CAAA;AAEjB;AAEA,cAAc,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/Form/DatePicker.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAsD,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACrI,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/Form/DatePicker.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAsD,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACrI,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAqBlE,QAAA,MAAM,kBAAkB;;;8EAiBtB,CAAC;AAEH,MAAM,WAAW,eAAe,CAC9B,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC,CAC/D,SAAQ,YAAY,CAAC,OAAO,kBAAkB,CAAC;IAC/C,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC;CAC7E;AAED,wBAAgB,UAAU,CACxB,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC,EAC/D,EACA,IAAI,EACJ,KAAK,EACL,UAAU,EACV,SAAgB,EAChB,KAAK,EAAE,WAAW,EAClB,IAAI,EACJ,OAAO,EACP,SAAgB,EAChB,WAA2B,EAC3B,QAAQ,EACR,SAAS,EACT,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,eAAe,EACxB,QAAQ,EACR,QAAQ,GACT,EAAE,eAAe,CAAC,YAAY,EAAE,KAAK,CAAC,+BAkGtC;yBArHe,UAAU"}
|
|
@@ -11,8 +11,14 @@ import { cva } from "class-variance-authority";
|
|
|
11
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
import { useController, useFormContext } from "react-hook-form";
|
|
13
13
|
import { CalendarIcon } from "lucide-react";
|
|
14
|
-
import { format } from "date-fns";
|
|
14
|
+
import { format, startOfDay } from "date-fns";
|
|
15
15
|
//#region src/components/Form/DatePicker.tsx
|
|
16
|
+
function toStartOfDay(value) {
|
|
17
|
+
if (!value || value === "") return;
|
|
18
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
19
|
+
if (Number.isNaN(date.getTime())) return;
|
|
20
|
+
return startOfDay(date);
|
|
21
|
+
}
|
|
16
22
|
var datePickerVariants = cva("w-full justify-start text-left font-normal", {
|
|
17
23
|
variants: {
|
|
18
24
|
size: {
|
|
@@ -66,7 +72,7 @@ function DatePicker({ name, label, helperText, showError = true, error: customEr
|
|
|
66
72
|
name,
|
|
67
73
|
control
|
|
68
74
|
});
|
|
69
|
-
const selectedDate =
|
|
75
|
+
const selectedDate = toStartOfDay(field.value);
|
|
70
76
|
const fieldError = fieldState.error?.message;
|
|
71
77
|
const errorMessage = customError ?? fieldError;
|
|
72
78
|
const hasError = !!errorMessage;
|
|
@@ -107,7 +113,7 @@ function DatePicker({ name, label, helperText, showError = true, error: customEr
|
|
|
107
113
|
mode: "single",
|
|
108
114
|
selected: selectedDate,
|
|
109
115
|
onSelect: (date) => {
|
|
110
|
-
field.onChange(date
|
|
116
|
+
field.onChange(date ? startOfDay(date) : "");
|
|
111
117
|
setOpen(false);
|
|
112
118
|
}
|
|
113
119
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePicker.js","names":[],"sources":["../../../src/components/Form/DatePicker.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useContext, useEffect, useId, useState } from \"react\";\r\nimport { format } from \"date-fns\";\r\nimport { CalendarIcon } from \"lucide-react\";\r\nimport { useController, useFormContext as useRHFFormContext, type Control, type FieldPath, type FieldValues } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Button } from \"../../primitives/button\";\r\nimport { Calendar } from \"../../primitives/calendar\";\r\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\r\nimport { FormConfigContext, type FieldValidationRules, type FormConfig } from \"./context\";\r\nimport { FieldLayout } from \"./FieldLayout\";\r\n\r\nconst datePickerVariants = cva(\"w-full justify-start text-left font-normal\", {\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 variant: {\r\n default: \"border-input\",\r\n error: \"border-destructive\",\r\n success: \"border-green-500\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n variant: \"default\",\r\n },\r\n});\r\n\r\nexport interface DatePickerProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends VariantProps<typeof datePickerVariants> {\r\n name: TName;\r\n label?: string;\r\n helperText?: string;\r\n showError?: boolean;\r\n error?: string;\r\n fullWidth?: boolean;\r\n placeholder?: string;\r\n disabled?: boolean;\r\n className?: string;\r\n id?: string;\r\n control?: Control<TFieldValues>;\r\n required?: boolean | string;\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\nexport function DatePicker<\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 placeholder = \"Pick a date\",\r\n disabled,\r\n className,\r\n id: providedId,\r\n control: externalControl,\r\n required,\r\n validate,\r\n}: DatePickerProps<TFieldValues, TName>) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n const [open, setOpen] = useState(false);\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n const registerFieldValidation = formConfigContext?.registerFieldValidation;\r\n const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;\r\n\r\n useEffect(() => {\r\n if (registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n if (required !== undefined) rules.required = required;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n registerFieldValidation({\r\n name: name as string,\r\n type: \"date\",\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 validate,\r\n ]);\r\n\r\n const { field, fieldState } = useController<TFieldValues, TName>({\r\n name,\r\n control,\r\n });\r\n\r\n const selectedDate =
|
|
1
|
+
{"version":3,"file":"DatePicker.js","names":[],"sources":["../../../src/components/Form/DatePicker.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useContext, useEffect, useId, useState } from \"react\";\r\nimport { format, startOfDay } from \"date-fns\";\r\nimport { CalendarIcon } from \"lucide-react\";\r\nimport { useController, useFormContext as useRHFFormContext, type Control, type FieldPath, type FieldValues } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Button } from \"../../primitives/button\";\r\nimport { Calendar } from \"../../primitives/calendar\";\r\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\r\nimport { FormConfigContext, type FieldValidationRules, type FormConfig } from \"./context\";\r\nimport { FieldLayout } from \"./FieldLayout\";\r\n\r\nfunction toStartOfDay(value: unknown): Date | undefined {\r\n if (!value || value === \"\") {\r\n return undefined;\r\n }\r\n\r\n const date = value instanceof Date ? value : new Date(value as string | number);\r\n if (Number.isNaN(date.getTime())) {\r\n return undefined;\r\n }\r\n\r\n return startOfDay(date);\r\n}\r\n\r\nconst datePickerVariants = cva(\"w-full justify-start text-left font-normal\", {\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 variant: {\r\n default: \"border-input\",\r\n error: \"border-destructive\",\r\n success: \"border-green-500\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n variant: \"default\",\r\n },\r\n});\r\n\r\nexport interface DatePickerProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends VariantProps<typeof datePickerVariants> {\r\n name: TName;\r\n label?: string;\r\n helperText?: string;\r\n showError?: boolean;\r\n error?: string;\r\n fullWidth?: boolean;\r\n placeholder?: string;\r\n disabled?: boolean;\r\n className?: string;\r\n id?: string;\r\n control?: Control<TFieldValues>;\r\n required?: boolean | string;\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n}\r\n\r\nexport function DatePicker<\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 placeholder = \"Pick a date\",\r\n disabled,\r\n className,\r\n id: providedId,\r\n control: externalControl,\r\n required,\r\n validate,\r\n}: DatePickerProps<TFieldValues, TName>) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n const [open, setOpen] = useState(false);\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n const registerFieldValidation = formConfigContext?.registerFieldValidation;\r\n const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;\r\n\r\n useEffect(() => {\r\n if (registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n if (required !== undefined) rules.required = required;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n registerFieldValidation({\r\n name: name as string,\r\n type: \"date\",\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 validate,\r\n ]);\r\n\r\n const { field, fieldState } = useController<TFieldValues, TName>({\r\n name,\r\n control,\r\n });\r\n\r\n const selectedDate = toStartOfDay(field.value);\r\n const fieldError = fieldState.error?.message;\r\n const errorMessage = customError ?? fieldError;\r\n const hasError = !!errorMessage;\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 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 <Popover open={open} onOpenChange={setOpen}>\r\n <PopoverTrigger asChild>\r\n <Button\r\n id={inputId}\r\n type=\"button\"\r\n variant=\"outline\"\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 datePickerVariants({ size: effectiveSize, variant: effectiveVariant }),\r\n !selectedDate && \"text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n <CalendarIcon className=\"mr-2 h-4 w-4\" />\r\n {selectedDate ? format(selectedDate, \"PPP\") : placeholder}\r\n </Button>\r\n </PopoverTrigger>\r\n <PopoverContent className=\"w-auto p-0\" align=\"start\">\r\n <Calendar\r\n mode=\"single\"\r\n selected={selectedDate}\r\n onSelect={(date) => {\r\n field.onChange(date ? startOfDay(date) : \"\");\r\n setOpen(false);\r\n }}\r\n />\r\n </PopoverContent>\r\n </Popover>\r\n </FieldLayout>\r\n );\r\n}\r\n\r\nDatePicker.displayName = \"DatePicker\";\r\n"],"mappings":";;;;;;;;;;;;;;;AAcA,SAAS,aAAa,OAAkC;CACtD,IAAI,CAAC,SAAS,UAAU,IACtB;CAGF,MAAM,OAAO,iBAAiB,OAAO,QAAQ,IAAI,KAAK,KAAwB;CAC9E,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAC7B;CAGF,OAAO,WAAW,IAAI;AACxB;AAEA,IAAM,qBAAqB,IAAI,8CAA8C;CAC3E,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,CAAC;AAqBD,SAAgB,WAGd,EACA,MACA,OACA,YACA,YAAY,MACZ,OAAO,aACP,MACA,SACA,YAAY,MACZ,cAAc,eACd,UACA,WACA,IAAI,YACJ,SAAS,iBACT,UACA,YACuC;CACvC,MAAM,cAAc,MAAM;CAC1B,MAAM,UAAU,cAAc;CAC9B,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,oBAAoB,WAAW,iBAAiB;CACtD,MAAM,aAAyB,qBAAqB,CAAC;CACrD,MAAM,aAAa,eAAgC;CACnD,MAAM,UAAU,mBAAmB,YAAY;CAE/C,MAAM,0BAA0B,mBAAmB;CACnD,MAAM,4BAA4B,mBAAmB;CAErD,gBAAgB;EACd,IAAI,yBAAyB;GAC3B,MAAM,QAA8B,CAAC;GACrC,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAC7C,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;GAE7C,wBAAwB;IAChB;IACN,MAAM;IACN;GACF,CAAC;GAED,aAAa;IACX,4BAA4B,IAAc;GAC5C;EACF;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,OAAO,eAAe,cAAmC;EAC/D;EACA;CACF,CAAC;CAED,MAAM,eAAe,aAAa,MAAM,KAAK;CAC7C,MAAM,aAAa,WAAW,OAAO;CACrC,MAAM,eAAe,eAAe;CACpC,MAAM,WAAW,CAAC,CAAC;CACnB,MAAM,gBAAgB,QAAQ,WAAW,QAAQ;CACjD,MAAM,oBAAoB,YAAY,WAAW;CACjD,MAAM,mBAAmB,WAAW,UAAU;CAE9C,OACE,oBAAC,aAAD;EACW;EACF;EACP,UAAU,CAAC,CAAC;EACA;EACZ,cAAc,YAAY,eAAe,KAAA;EAC9B;EACA;EACC;EAEZ,UAAA,qBAAC,SAAD;GAAe;GAAM,cAAc;GAAnC,UAAA,CACE,oBAAC,gBAAD;IAAgB,SAAA;IACd,UAAA,qBAAC,QAAD;KACE,IAAI;KACJ,MAAK;KACL,SAAQ;KACR,UAAU;KACV,gBAAc;KACd,oBACE,WACI,GAAG,QAAQ,UACX,aACE,GAAG,QAAQ,WACX,KAAA;KAER,WAAW,GACT,mBAAmB;MAAE,MAAM;MAAe,SAAS;KAAiB,CAAC,GACrE,CAAC,gBAAgB,yBACjB,SACF;KAjBF,UAAA,CAmBE,oBAAC,cAAD,EAAc,WAAU,eAAgB,CAAA,GACvC,eAAe,OAAO,cAAc,KAAK,IAAI,WACxC;;GACM,CAAA,GAChB,oBAAC,gBAAD;IAAgB,WAAU;IAAa,OAAM;IAC3C,UAAA,oBAAC,UAAD;KACE,MAAK;KACL,UAAU;KACV,WAAW,SAAS;MAClB,MAAM,SAAS,OAAO,WAAW,IAAI,IAAI,EAAE;MAC3C,QAAQ,KAAK;KACf;IACD,CAAA;GACa,CAAA,CACT;;CACE,CAAA;AAEjB;AAEA,WAAW,cAAc"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Control, FieldPath, FieldValues } from 'react-hook-form';
|
|
2
|
+
import { VariantProps } from 'class-variance-authority';
|
|
3
|
+
declare const dateTimePickerVariants: (props?: ({
|
|
4
|
+
size?: "sm" | "lg" | "md" | null | undefined;
|
|
5
|
+
variant?: "default" | "error" | "success" | null | undefined;
|
|
6
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
7
|
+
export interface DateTimePickerProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> extends VariantProps<typeof dateTimePickerVariants> {
|
|
8
|
+
name: TName;
|
|
9
|
+
label?: string;
|
|
10
|
+
helperText?: string;
|
|
11
|
+
showError?: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
fullWidth?: boolean;
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
id?: string;
|
|
18
|
+
control?: Control<TFieldValues>;
|
|
19
|
+
required?: boolean | string;
|
|
20
|
+
validate?: (value: unknown) => boolean | string | Promise<boolean | string>;
|
|
21
|
+
minuteStep?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function DateTimePicker<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({ name, label, helperText, showError, error: customError, size, variant, fullWidth, placeholder, disabled, className, id: providedId, control: externalControl, required, validate, minuteStep, }: DateTimePickerProps<TFieldValues, TName>): import("react").JSX.Element;
|
|
24
|
+
export declare namespace DateTimePicker {
|
|
25
|
+
var displayName: string;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=DateTimePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateTimePicker.d.ts","sourceRoot":"","sources":["../../../src/components/Form/DateTimePicker.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAsD,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACrI,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAUlE,QAAA,MAAM,sBAAsB;;;8EAiB1B,CAAC;AAEH,MAAM,WAAW,mBAAmB,CAClC,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC,CAC/D,SAAQ,YAAY,CAAC,OAAO,sBAAsB,CAAC;IACnD,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAkCD,wBAAgB,cAAc,CAC5B,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,KAAK,SAAS,SAAS,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,YAAY,CAAC,EAC/D,EACA,IAAI,EACJ,KAAK,EACL,UAAU,EACV,SAAgB,EAChB,KAAK,EAAE,WAAW,EAClB,IAAI,EACJ,OAAO,EACP,SAAgB,EAChB,WAA2B,EAC3B,QAAQ,EACR,SAAS,EACT,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,eAAe,EACxB,QAAQ,EACR,QAAQ,EACR,UAAc,GACf,EAAE,mBAAmB,CAAC,YAAY,EAAE,KAAK,CAAC,+BAuL1C;yBA3Me,cAAc"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import { cn } from "../../utils/cn.js";
|
|
4
|
+
import { Button } from "../../primitives/button.js";
|
|
5
|
+
import { FormConfigContext } from "./context.js";
|
|
6
|
+
import { FieldLayout } from "./FieldLayout.js";
|
|
7
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../../primitives/popover.js";
|
|
8
|
+
import { Calendar } from "../../primitives/calendar.js";
|
|
9
|
+
import { Separator } from "../../primitives/separator.js";
|
|
10
|
+
import { TimePicker } from "./TimePicker.js";
|
|
11
|
+
import { useContext, useEffect, useId, useState } from "react";
|
|
12
|
+
import { cva } from "class-variance-authority";
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
import { useController, useFormContext } from "react-hook-form";
|
|
15
|
+
import { CalendarIcon, Clock } from "lucide-react";
|
|
16
|
+
import { format, startOfDay } from "date-fns";
|
|
17
|
+
//#region src/components/Form/DateTimePicker.tsx
|
|
18
|
+
var dateTimePickerVariants = cva("w-full justify-start text-left font-normal", {
|
|
19
|
+
variants: {
|
|
20
|
+
size: {
|
|
21
|
+
sm: "h-8 text-xs",
|
|
22
|
+
md: "h-10 text-sm",
|
|
23
|
+
lg: "h-12 text-base"
|
|
24
|
+
},
|
|
25
|
+
variant: {
|
|
26
|
+
default: "border-input",
|
|
27
|
+
error: "border-destructive",
|
|
28
|
+
success: "border-green-500"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
size: "md",
|
|
33
|
+
variant: "default"
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
function toValidDate(value) {
|
|
37
|
+
if (!value || value === "") return;
|
|
38
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
39
|
+
if (Number.isNaN(date.getTime())) return;
|
|
40
|
+
return date;
|
|
41
|
+
}
|
|
42
|
+
function hasTimePart(date) {
|
|
43
|
+
return date.getHours() !== 0 || date.getMinutes() !== 0 || date.getSeconds() !== 0 || date.getMilliseconds() !== 0;
|
|
44
|
+
}
|
|
45
|
+
function withPreservedTime(nextDay, previous) {
|
|
46
|
+
const next = new Date(nextDay);
|
|
47
|
+
next.setHours(previous.getHours(), previous.getMinutes(), previous.getSeconds(), previous.getMilliseconds());
|
|
48
|
+
return next;
|
|
49
|
+
}
|
|
50
|
+
function isSelectEventTarget(target) {
|
|
51
|
+
return target instanceof Element && Boolean(target.closest("[data-radix-select-content]"));
|
|
52
|
+
}
|
|
53
|
+
function DateTimePicker({ name, label, helperText, showError = true, error: customError, size, variant, fullWidth = true, placeholder = "Pick a date", disabled, className, id: providedId, control: externalControl, required, validate, minuteStep = 5 }) {
|
|
54
|
+
const generatedId = useId();
|
|
55
|
+
const inputId = providedId ?? generatedId;
|
|
56
|
+
const [open, setOpen] = useState(false);
|
|
57
|
+
const [timeOpen, setTimeOpen] = useState(false);
|
|
58
|
+
const [timeSet, setTimeSet] = useState(false);
|
|
59
|
+
const formConfigContext = useContext(FormConfigContext);
|
|
60
|
+
const formConfig = formConfigContext ?? {};
|
|
61
|
+
const rhfContext = useFormContext();
|
|
62
|
+
const control = externalControl ?? rhfContext?.control;
|
|
63
|
+
const registerFieldValidation = formConfigContext?.registerFieldValidation;
|
|
64
|
+
const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (registerFieldValidation) {
|
|
67
|
+
const rules = {};
|
|
68
|
+
if (required !== void 0) rules.required = required;
|
|
69
|
+
if (validate !== void 0) rules.validate = validate;
|
|
70
|
+
registerFieldValidation({
|
|
71
|
+
name,
|
|
72
|
+
type: "datetime",
|
|
73
|
+
rules
|
|
74
|
+
});
|
|
75
|
+
return () => {
|
|
76
|
+
unregisterFieldValidation?.(name);
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}, [
|
|
80
|
+
registerFieldValidation,
|
|
81
|
+
unregisterFieldValidation,
|
|
82
|
+
name,
|
|
83
|
+
required,
|
|
84
|
+
validate
|
|
85
|
+
]);
|
|
86
|
+
const { field, fieldState } = useController({
|
|
87
|
+
name,
|
|
88
|
+
control
|
|
89
|
+
});
|
|
90
|
+
const selectedDate = toValidDate(field.value);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
const date = toValidDate(field.value);
|
|
93
|
+
if (!date) {
|
|
94
|
+
setTimeSet(false);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (hasTimePart(date)) setTimeSet(true);
|
|
98
|
+
}, [field.value]);
|
|
99
|
+
const fieldError = fieldState.error?.message;
|
|
100
|
+
const errorMessage = customError ?? fieldError;
|
|
101
|
+
const hasError = !!errorMessage;
|
|
102
|
+
const effectiveSize = size ?? formConfig.size ?? "md";
|
|
103
|
+
const effectiveDisabled = disabled ?? formConfig.disabled;
|
|
104
|
+
const effectiveVariant = hasError ? "error" : variant;
|
|
105
|
+
const displayHasTime = timeSet && !!selectedDate;
|
|
106
|
+
const handleOpenChange = (nextOpen) => {
|
|
107
|
+
setOpen(nextOpen);
|
|
108
|
+
if (nextOpen && timeSet) {
|
|
109
|
+
setTimeOpen(true);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (!nextOpen) setTimeOpen(false);
|
|
113
|
+
};
|
|
114
|
+
return /* @__PURE__ */ jsx(FieldLayout, {
|
|
115
|
+
inputId,
|
|
116
|
+
label,
|
|
117
|
+
required: !!required,
|
|
118
|
+
helperText,
|
|
119
|
+
errorMessage: showError ? errorMessage : void 0,
|
|
120
|
+
showError,
|
|
121
|
+
fullWidth,
|
|
122
|
+
formConfig,
|
|
123
|
+
children: /* @__PURE__ */ jsxs(Popover, {
|
|
124
|
+
open,
|
|
125
|
+
onOpenChange: handleOpenChange,
|
|
126
|
+
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
127
|
+
asChild: true,
|
|
128
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
129
|
+
id: inputId,
|
|
130
|
+
type: "button",
|
|
131
|
+
variant: "outline",
|
|
132
|
+
disabled: effectiveDisabled,
|
|
133
|
+
"aria-invalid": hasError,
|
|
134
|
+
"aria-describedby": hasError ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0,
|
|
135
|
+
className: cn(dateTimePickerVariants({
|
|
136
|
+
size: effectiveSize,
|
|
137
|
+
variant: effectiveVariant
|
|
138
|
+
}), !selectedDate && "text-muted-foreground", className),
|
|
139
|
+
children: [/* @__PURE__ */ jsx(CalendarIcon, { className: "mr-2 h-4 w-4" }), selectedDate ? format(selectedDate, displayHasTime ? "PPP p" : "PPP") : placeholder]
|
|
140
|
+
})
|
|
141
|
+
}), /* @__PURE__ */ jsxs(PopoverContent, {
|
|
142
|
+
className: "w-auto p-0",
|
|
143
|
+
align: "start",
|
|
144
|
+
onPointerDownOutside: (event) => {
|
|
145
|
+
if (isSelectEventTarget(event.target)) event.preventDefault();
|
|
146
|
+
},
|
|
147
|
+
onFocusOutside: (event) => {
|
|
148
|
+
if (isSelectEventTarget(event.target)) event.preventDefault();
|
|
149
|
+
},
|
|
150
|
+
children: [
|
|
151
|
+
/* @__PURE__ */ jsx(Calendar, {
|
|
152
|
+
mode: "single",
|
|
153
|
+
selected: selectedDate,
|
|
154
|
+
onSelect: (date) => {
|
|
155
|
+
if (!date) {
|
|
156
|
+
field.onChange("");
|
|
157
|
+
setTimeSet(false);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (selectedDate && timeSet) {
|
|
161
|
+
field.onChange(withPreservedTime(date, selectedDate));
|
|
162
|
+
setOpen(false);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
field.onChange(startOfDay(date));
|
|
166
|
+
}
|
|
167
|
+
}),
|
|
168
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
169
|
+
/* @__PURE__ */ jsxs("div", {
|
|
170
|
+
className: "p-3",
|
|
171
|
+
children: [/* @__PURE__ */ jsxs(Button, {
|
|
172
|
+
type: "button",
|
|
173
|
+
variant: "ghost",
|
|
174
|
+
disabled: effectiveDisabled,
|
|
175
|
+
className: "h-8 w-full justify-start px-2 font-normal",
|
|
176
|
+
onClick: () => setTimeOpen((current) => !current),
|
|
177
|
+
children: [/* @__PURE__ */ jsx(Clock, { className: "mr-2 h-4 w-4" }), displayHasTime && selectedDate ? format(selectedDate, "p") : "Add time"]
|
|
178
|
+
}), timeOpen ? /* @__PURE__ */ jsx(TimePicker, {
|
|
179
|
+
className: "mt-2",
|
|
180
|
+
value: selectedDate,
|
|
181
|
+
minuteStep,
|
|
182
|
+
disabled: effectiveDisabled,
|
|
183
|
+
onChange: (date) => {
|
|
184
|
+
field.onChange(date);
|
|
185
|
+
setTimeSet(true);
|
|
186
|
+
},
|
|
187
|
+
onClear: () => {
|
|
188
|
+
if (selectedDate) field.onChange(startOfDay(selectedDate));
|
|
189
|
+
setTimeSet(false);
|
|
190
|
+
}
|
|
191
|
+
}) : null]
|
|
192
|
+
})
|
|
193
|
+
]
|
|
194
|
+
})]
|
|
195
|
+
})
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
DateTimePicker.displayName = "DateTimePicker";
|
|
199
|
+
//#endregion
|
|
200
|
+
export { DateTimePicker };
|
|
201
|
+
|
|
202
|
+
//# sourceMappingURL=DateTimePicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateTimePicker.js","names":[],"sources":["../../../src/components/Form/DateTimePicker.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useContext, useEffect, useId, useState } from \"react\";\r\nimport { format, startOfDay } from \"date-fns\";\r\nimport { CalendarIcon, Clock } from \"lucide-react\";\r\nimport { useController, useFormContext as useRHFFormContext, type Control, type FieldPath, type FieldValues } from \"react-hook-form\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Button } from \"../../primitives/button\";\r\nimport { Calendar } from \"../../primitives/calendar\";\r\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\r\nimport { Separator } from \"../../primitives/separator\";\r\nimport { FormConfigContext, type FieldValidationRules, type FormConfig } from \"./context\";\r\nimport { FieldLayout } from \"./FieldLayout\";\r\nimport { TimePicker } from \"./TimePicker\";\r\n\r\nconst dateTimePickerVariants = cva(\"w-full justify-start text-left font-normal\", {\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 variant: {\r\n default: \"border-input\",\r\n error: \"border-destructive\",\r\n success: \"border-green-500\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n variant: \"default\",\r\n },\r\n});\r\n\r\nexport interface DateTimePickerProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\r\n> extends VariantProps<typeof dateTimePickerVariants> {\r\n name: TName;\r\n label?: string;\r\n helperText?: string;\r\n showError?: boolean;\r\n error?: string;\r\n fullWidth?: boolean;\r\n placeholder?: string;\r\n disabled?: boolean;\r\n className?: string;\r\n id?: string;\r\n control?: Control<TFieldValues>;\r\n required?: boolean | string;\r\n validate?: (value: unknown) => boolean | string | Promise<boolean | string>;\r\n minuteStep?: number;\r\n}\r\n\r\nfunction toValidDate(value: unknown): Date | undefined {\r\n if (!value || value === \"\") {\r\n return undefined;\r\n }\r\n\r\n const date = value instanceof Date ? value : new Date(value as string | number);\r\n if (Number.isNaN(date.getTime())) {\r\n return undefined;\r\n }\r\n\r\n return date;\r\n}\r\n\r\nfunction hasTimePart(date: Date): boolean {\r\n return date.getHours() !== 0 || date.getMinutes() !== 0 || date.getSeconds() !== 0 || date.getMilliseconds() !== 0;\r\n}\r\n\r\nfunction withPreservedTime(nextDay: Date, previous: Date): Date {\r\n const next = new Date(nextDay);\r\n next.setHours(\r\n previous.getHours(),\r\n previous.getMinutes(),\r\n previous.getSeconds(),\r\n previous.getMilliseconds()\r\n );\r\n return next;\r\n}\r\n\r\nfunction isSelectEventTarget(target: EventTarget | null): boolean {\r\n return target instanceof Element && Boolean(target.closest(\"[data-radix-select-content]\"));\r\n}\r\n\r\nexport function DateTimePicker<\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 placeholder = \"Pick a date\",\r\n disabled,\r\n className,\r\n id: providedId,\r\n control: externalControl,\r\n required,\r\n validate,\r\n minuteStep = 5,\r\n}: DateTimePickerProps<TFieldValues, TName>) {\r\n const generatedId = useId();\r\n const inputId = providedId ?? generatedId;\r\n const [open, setOpen] = useState(false);\r\n const [timeOpen, setTimeOpen] = useState(false);\r\n const [timeSet, setTimeSet] = useState(false);\r\n const formConfigContext = useContext(FormConfigContext);\r\n const formConfig: FormConfig = formConfigContext ?? {};\r\n const rhfContext = useRHFFormContext<TFieldValues>();\r\n const control = externalControl ?? rhfContext?.control;\r\n\r\n const registerFieldValidation = formConfigContext?.registerFieldValidation;\r\n const unregisterFieldValidation = formConfigContext?.unregisterFieldValidation;\r\n\r\n useEffect(() => {\r\n if (registerFieldValidation) {\r\n const rules: FieldValidationRules = {};\r\n if (required !== undefined) rules.required = required;\r\n if (validate !== undefined) rules.validate = validate;\r\n\r\n registerFieldValidation({\r\n name: name as string,\r\n type: \"datetime\",\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 validate,\r\n ]);\r\n\r\n const { field, fieldState } = useController<TFieldValues, TName>({\r\n name,\r\n control,\r\n });\r\n\r\n const selectedDate = toValidDate(field.value);\r\n\r\n useEffect(() => {\r\n const date = toValidDate(field.value);\r\n if (!date) {\r\n setTimeSet(false);\r\n return;\r\n }\r\n\r\n if (hasTimePart(date)) {\r\n setTimeSet(true);\r\n }\r\n }, [field.value]);\r\n\r\n const fieldError = fieldState.error?.message;\r\n const errorMessage = customError ?? fieldError;\r\n const hasError = !!errorMessage;\r\n const effectiveSize = size ?? formConfig.size ?? \"md\";\r\n const effectiveDisabled = disabled ?? formConfig.disabled;\r\n const effectiveVariant = hasError ? \"error\" : variant;\r\n const displayHasTime = timeSet && !!selectedDate;\r\n\r\n const handleOpenChange = (nextOpen: boolean) => {\r\n setOpen(nextOpen);\r\n if (nextOpen && timeSet) {\r\n setTimeOpen(true);\r\n return;\r\n }\r\n\r\n if (!nextOpen) {\r\n setTimeOpen(false);\r\n }\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 <Popover open={open} onOpenChange={handleOpenChange}>\r\n <PopoverTrigger asChild>\r\n <Button\r\n id={inputId}\r\n type=\"button\"\r\n variant=\"outline\"\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 dateTimePickerVariants({ size: effectiveSize, variant: effectiveVariant }),\r\n !selectedDate && \"text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n <CalendarIcon className=\"mr-2 h-4 w-4\" />\r\n {selectedDate\r\n ? format(selectedDate, displayHasTime ? \"PPP p\" : \"PPP\")\r\n : placeholder}\r\n </Button>\r\n </PopoverTrigger>\r\n <PopoverContent\r\n className=\"w-auto p-0\"\r\n align=\"start\"\r\n onPointerDownOutside={(event) => {\r\n if (isSelectEventTarget(event.target)) {\r\n event.preventDefault();\r\n }\r\n }}\r\n onFocusOutside={(event) => {\r\n if (isSelectEventTarget(event.target)) {\r\n event.preventDefault();\r\n }\r\n }}\r\n >\r\n <Calendar\r\n mode=\"single\"\r\n selected={selectedDate}\r\n onSelect={(date) => {\r\n if (!date) {\r\n field.onChange(\"\");\r\n setTimeSet(false);\r\n return;\r\n }\r\n\r\n if (selectedDate && timeSet) {\r\n field.onChange(withPreservedTime(date, selectedDate));\r\n setOpen(false);\r\n return;\r\n }\r\n\r\n field.onChange(startOfDay(date));\r\n }}\r\n />\r\n <Separator />\r\n <div className=\"p-3\">\r\n <Button\r\n type=\"button\"\r\n variant=\"ghost\"\r\n disabled={effectiveDisabled}\r\n className=\"h-8 w-full justify-start px-2 font-normal\"\r\n onClick={() => setTimeOpen((current) => !current)}\r\n >\r\n <Clock className=\"mr-2 h-4 w-4\" />\r\n {displayHasTime && selectedDate ? format(selectedDate, \"p\") : \"Add time\"}\r\n </Button>\r\n {timeOpen ? (\r\n <TimePicker\r\n className=\"mt-2\"\r\n value={selectedDate}\r\n minuteStep={minuteStep}\r\n disabled={effectiveDisabled}\r\n onChange={(date) => {\r\n field.onChange(date);\r\n setTimeSet(true);\r\n }}\r\n onClear={() => {\r\n if (selectedDate) {\r\n field.onChange(startOfDay(selectedDate));\r\n }\r\n setTimeSet(false);\r\n }}\r\n />\r\n ) : null}\r\n </div>\r\n </PopoverContent>\r\n </Popover>\r\n </FieldLayout>\r\n );\r\n}\r\n\r\nDateTimePicker.displayName = \"DateTimePicker\";\r\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldLayout.js","names":[],"sources":["../../../src/components/Form/FieldLayout.tsx"],"sourcesContent":["'use client';\r\n\r\nimport type { ReactNode } from \"react\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Label } from \"../../primitives/label\";\r\nimport { labelVariants } from \"./variants\";\r\nimport type { FormConfig } from \"./context\";\r\n\r\nexport interface FieldLayoutProps {\r\n inputId: string;\r\n label?: string;\r\n required?: boolean;\r\n helperText?: string;\r\n errorMessage?: string;\r\n showError?: boolean;\r\n fullWidth?: boolean;\r\n formConfig?: FormConfig;\r\n children: ReactNode;\r\n}\r\n\r\nfunction resolveLabelWidth(labelWidth?: string | number): string | undefined {\r\n if (labelWidth === undefined) {\r\n return undefined;\r\n }\r\n\r\n return typeof labelWidth === \"number\" ? `${labelWidth}px` : labelWidth;\r\n}\r\n\r\nexport function FieldLayout({\r\n inputId,\r\n label,\r\n required,\r\n helperText,\r\n errorMessage,\r\n showError = true,\r\n fullWidth = true,\r\n formConfig = {},\r\n children,\r\n}: FieldLayoutProps) {\r\n const layout = formConfig.layout ?? \"vertical\";\r\n const labelWidth = resolveLabelWidth(formConfig.labelWidth);\r\n const hasError = !!errorMessage;\r\n const showHelper = !!helperText && !hasError;\r\n\r\n const labelNode = label ? (\r\n <Label\r\n htmlFor={inputId}\r\n className={cn(\r\n labelVariants({ required: !!required }),\r\n layout === \"horizontal\" && \"mb-0 shrink-0 pt-2\",\r\n layout === \"inline\" && \"mb-0 shrink-0\"\r\n )}\r\n style={layout === \"horizontal\" && labelWidth ? { width: labelWidth } : undefined}\r\n >\r\n {label}\r\n {formConfig.colon && \":\"}\r\n </Label>\r\n ) : null;\r\n\r\n const messages = (\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 {showHelper && (\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 </>\r\n );\r\n\r\n if (layout === \"horizontal\") {\r\n return (\r\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\r\n <div className=\"flex items-start gap-4\">\r\n {labelNode}\r\n <div className=\"min-w-0 flex-1 space-y-1.5\">\r\n {children}\r\n {messages}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n if (layout === \"inline\") {\r\n return (\r\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\r\n <div className=\"flex flex-wrap items-center gap-3\">\r\n {labelNode}\r\n <div className=\"min-w-0 flex-1\">{children}</div>\r\n </div>\r\n {messages}\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\r\n {labelNode}\r\n {children}\r\n {messages}\r\n </div>\r\n );\r\n}\r\n"],"mappings":";;;;;;;AAoBA,SAAS,kBAAkB,YAAkD;CAC3E,IAAI,eAAe,KAAA,GACjB;CAGF,OAAO,OAAO,eAAe,WAAW,GAAG,WAAW,MAAM;AAC9D;AAEA,SAAgB,YAAY,EAC1B,SACA,OACA,UACA,YACA,cACA,YAAY,MACZ,YAAY,MACZ,aAAa,CAAC,GACd,YACmB;CACnB,MAAM,SAAS,WAAW,UAAU;CACpC,MAAM,aAAa,kBAAkB,WAAW,UAAU;CAC1D,MAAM,WAAW,CAAC,CAAC;CACnB,MAAM,aAAa,CAAC,CAAC,cAAc,CAAC;CAEpC,MAAM,YAAY,QAChB,qBAAC,OAAD;EACE,SAAS;EACT,WAAW,GACT,cAAc,EAAE,UAAU,CAAC,CAAC,SAAS,CAAC,GACtC,WAAW,gBAAgB,sBAC3B,WAAW,YAAY,eACzB;EACA,OAAO,WAAW,gBAAgB,aAAa,EAAE,OAAO,WAAW,IAAI,KAAA;
|
|
1
|
+
{"version":3,"file":"FieldLayout.js","names":[],"sources":["../../../src/components/Form/FieldLayout.tsx"],"sourcesContent":["'use client';\r\n\r\nimport type { ReactNode } from \"react\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { Label } from \"../../primitives/label\";\r\nimport { labelVariants } from \"./variants\";\r\nimport type { FormConfig } from \"./context\";\r\n\r\nexport interface FieldLayoutProps {\r\n inputId: string;\r\n label?: string;\r\n required?: boolean;\r\n helperText?: string;\r\n errorMessage?: string;\r\n showError?: boolean;\r\n fullWidth?: boolean;\r\n formConfig?: FormConfig;\r\n children: ReactNode;\r\n}\r\n\r\nfunction resolveLabelWidth(labelWidth?: string | number): string | undefined {\r\n if (labelWidth === undefined) {\r\n return undefined;\r\n }\r\n\r\n return typeof labelWidth === \"number\" ? `${labelWidth}px` : labelWidth;\r\n}\r\n\r\nexport function FieldLayout({\r\n inputId,\r\n label,\r\n required,\r\n helperText,\r\n errorMessage,\r\n showError = true,\r\n fullWidth = true,\r\n formConfig = {},\r\n children,\r\n}: FieldLayoutProps) {\r\n const layout = formConfig.layout ?? \"vertical\";\r\n const labelWidth = resolveLabelWidth(formConfig.labelWidth);\r\n const hasError = !!errorMessage;\r\n const showHelper = !!helperText && !hasError;\r\n\r\n const labelNode = label ? (\r\n <Label\r\n htmlFor={inputId}\r\n className={cn(\r\n labelVariants({ required: !!required }),\r\n layout === \"horizontal\" && \"mb-0 shrink-0 pt-2\",\r\n layout === \"inline\" && \"mb-0 shrink-0\"\r\n )}\r\n style={layout === \"horizontal\" && labelWidth ? { width: labelWidth } : undefined}\r\n >\r\n {label}\r\n {formConfig.colon && \":\"}\r\n </Label>\r\n ) : null;\r\n\r\n const messages = (\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 {showHelper && (\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 </>\r\n );\r\n\r\n if (layout === \"horizontal\") {\r\n return (\r\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\r\n <div className=\"flex items-start gap-4\">\r\n {labelNode}\r\n <div className=\"min-w-0 flex-1 space-y-1.5\">\r\n {children}\r\n {messages}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n if (layout === \"inline\") {\r\n return (\r\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\r\n <div className=\"flex flex-wrap items-center gap-3\">\r\n {labelNode}\r\n <div className=\"min-w-0 flex-1\">{children}</div>\r\n </div>\r\n {messages}\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className={cn(\"space-y-1.5\", fullWidth && \"w-full\")}>\r\n {labelNode}\r\n {children}\r\n {messages}\r\n </div>\r\n );\r\n}\r\n"],"mappings":";;;;;;;AAoBA,SAAS,kBAAkB,YAAkD;CAC3E,IAAI,eAAe,KAAA,GACjB;CAGF,OAAO,OAAO,eAAe,WAAW,GAAG,WAAW,MAAM;AAC9D;AAEA,SAAgB,YAAY,EAC1B,SACA,OACA,UACA,YACA,cACA,YAAY,MACZ,YAAY,MACZ,aAAa,CAAC,GACd,YACmB;CACnB,MAAM,SAAS,WAAW,UAAU;CACpC,MAAM,aAAa,kBAAkB,WAAW,UAAU;CAC1D,MAAM,WAAW,CAAC,CAAC;CACnB,MAAM,aAAa,CAAC,CAAC,cAAc,CAAC;CAEpC,MAAM,YAAY,QAChB,qBAAC,OAAD;EACE,SAAS;EACT,WAAW,GACT,cAAc,EAAE,UAAU,CAAC,CAAC,SAAS,CAAC,GACtC,WAAW,gBAAgB,sBAC3B,WAAW,YAAY,eACzB;EACA,OAAO,WAAW,gBAAgB,aAAa,EAAE,OAAO,WAAW,IAAI,KAAA;EAPzE,UAAA,CASG,OACA,WAAW,SAAS,GAChB;CACL,CAAA,IAAA;CAEJ,MAAM,WACJ,qBAAA,UAAA,EAAA,UAAA,CACG,aAAa,YACZ,oBAAC,KAAD;EACE,IAAI,GAAG,QAAQ;EACf,WAAU;EACV,MAAK;EAEJ,UAAA;CACA,CAAA,GAGJ,cACC,oBAAC,KAAD;EACE,IAAI,GAAG,QAAQ;EACf,WAAU;EAET,UAAA;CACA,CAAA,CAEL,EAAA,CAAA;CAGJ,IAAI,WAAW,cACb,OACE,oBAAC,OAAD;EAAK,WAAW,GAAG,eAAe,aAAa,QAAQ;EACrD,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACG,WACD,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,UACA,QACE;GACF,CAAA,CAAA;;CACF,CAAA;CAIT,IAAI,WAAW,UACb,OACE,qBAAC,OAAD;EAAK,WAAW,GAAG,eAAe,aAAa,QAAQ;EAAvD,UAAA,CACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACG,WACD,oBAAC,OAAD;IAAK,WAAU;IAAkB;GAAc,CAAA,CAC5C;EACJ,CAAA,GAAA,QACE;;CAIT,OACE,qBAAC,OAAD;EAAK,WAAW,GAAG,eAAe,aAAa,QAAQ;EAAvD,UAAA;GACG;GACA;GACA;EACE;;AAET"}
|
|
@@ -41,15 +41,16 @@ function Form({ schema: baseSchema, defaultValues, values, onSubmit, onError, co
|
|
|
41
41
|
const mode = modeProp ?? (mergedConfig.validateOnChange ? "onChange" : mergedConfig.validateOnBlur !== false ? "onBlur" : "onSubmit");
|
|
42
42
|
const reValidateMode = reValidateModeProp ?? (mergedConfig.validateOnChange ? "onChange" : "onBlur");
|
|
43
43
|
const { registerFieldValidation, unregisterFieldValidation, getValidationSchema } = useFieldValidationRegistry();
|
|
44
|
+
const dynamicResolver = useCallback(async (vals, context, options) => {
|
|
45
|
+
if (customResolver) return customResolver(vals, context, options);
|
|
46
|
+
const fieldSchema = getValidationSchema();
|
|
47
|
+
let finalSchema;
|
|
48
|
+
if (baseSchema instanceof z.ZodObject) finalSchema = baseSchema.merge(fieldSchema);
|
|
49
|
+
else finalSchema = baseSchema ?? fieldSchema;
|
|
50
|
+
return zodResolver(finalSchema)(vals, context, options);
|
|
51
|
+
}, [baseSchema, customResolver]);
|
|
44
52
|
const internalForm = useForm({
|
|
45
|
-
resolver:
|
|
46
|
-
if (customResolver) return customResolver(vals, context, options);
|
|
47
|
-
const fieldSchema = getValidationSchema();
|
|
48
|
-
let finalSchema;
|
|
49
|
-
if (baseSchema instanceof z.ZodObject) finalSchema = baseSchema.merge(fieldSchema);
|
|
50
|
-
else finalSchema = baseSchema ?? fieldSchema;
|
|
51
|
-
return zodResolver(finalSchema)(vals, context, options);
|
|
52
|
-
}, [baseSchema, customResolver]),
|
|
53
|
+
resolver: dynamicResolver,
|
|
53
54
|
defaultValues,
|
|
54
55
|
values,
|
|
55
56
|
mode,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Form.js","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useCallback, useMemo, type ReactNode } from \"react\";\r\nimport {\r\n useForm,\r\n FormProvider as RHFFormProvider,\r\n type UseFormReturn,\r\n type FieldValues,\r\n type UseFormProps,\r\n type SubmitHandler,\r\n type SubmitErrorHandler,\r\n type Resolver,\r\n type Path,\r\n} from \"react-hook-form\";\r\nimport { zodResolver } from \"@hookform/resolvers/zod\";\r\nimport { z } from \"zod\";\r\nimport { \r\n FormConfigContext, \r\n defaultFormConfig, \r\n useFieldValidationRegistry,\r\n type FormConfig, \r\n type FormContextValue \r\n} from \"./context\";\r\n\r\n/**\r\n * Props for the Form component\r\n */\r\nexport interface FormProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TContext = unknown\r\n> extends Omit<React.FormHTMLAttributes<HTMLFormElement>, \"onSubmit\" | \"onError\"> {\r\n /** Base Zod schema for validation (will be extended by field props) */\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n schema?: z.ZodType<TFieldValues, any, any>;\r\n /** Default values for the form */\r\n defaultValues?: UseFormProps<TFieldValues, TContext>[\"defaultValues\"];\r\n /** Values to reset the form to */\r\n values?: UseFormProps<TFieldValues, TContext>[\"values\"];\r\n /** Submit handler */\r\n onSubmit?: SubmitHandler<TFieldValues>;\r\n /** Error handler */\r\n onError?: SubmitErrorHandler<TFieldValues>;\r\n /** Form configuration */\r\n config?: FormConfig;\r\n /** Children */\r\n children?: ReactNode;\r\n /** External form instance (for controlled forms) */\r\n form?: UseFormReturn<TFieldValues>;\r\n /** Validation mode */\r\n mode?: UseFormProps<TFieldValues, TContext>[\"mode\"];\r\n /** Revalidation mode */\r\n reValidateMode?: UseFormProps<TFieldValues, TContext>[\"reValidateMode\"];\r\n /** Custom resolver (overrides schema) */\r\n resolver?: Resolver<TFieldValues>;\r\n}\r\n\r\n/**\r\n * Form component that provides form context and validation\r\n * \r\n * Child components like TextBox can register their validation rules automatically.\r\n * \r\n * @example\r\n * ```tsx\r\n * // Validation is automatically built from component props\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 * <Button type=\"submit\">Submit</Button>\r\n * </Form>\r\n * \r\n * // Or with a base schema that gets extended\r\n * const baseSchema = z.object({\r\n * username: z.string(),\r\n * email: z.string(),\r\n * });\r\n * \r\n * <Form schema={baseSchema} onSubmit={handleSubmit}>\r\n * <TextBox name=\"username\" required minLength={3} /> // Adds required + minLength\r\n * <TextBox name=\"email\" required email /> // Adds required + email validation\r\n * </Form>\r\n * ```\r\n */\r\nexport function Form<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TContext = unknown\r\n>({\r\n schema: baseSchema,\r\n defaultValues,\r\n values,\r\n onSubmit,\r\n onError,\r\n config,\r\n children,\r\n form: externalForm,\r\n mode: modeProp,\r\n reValidateMode: reValidateModeProp,\r\n resolver: customResolver,\r\n ...formProps\r\n}: FormProps<TFieldValues, TContext>) {\r\n const mergedConfig = { ...defaultFormConfig, ...config };\r\n\r\n const mode =\r\n modeProp ??\r\n (mergedConfig.validateOnChange\r\n ? \"onChange\"\r\n : mergedConfig.validateOnBlur !== false\r\n ? \"onBlur\"\r\n : \"onSubmit\");\r\n\r\n const reValidateMode =\r\n reValidateModeProp ??\r\n (mergedConfig.validateOnChange ? \"onChange\" : \"onBlur\");\r\n\r\n const {\r\n registerFieldValidation,\r\n unregisterFieldValidation,\r\n getValidationSchema,\r\n } = useFieldValidationRegistry();\r\n\r\n // Stable resolver that reads from fieldsRef at validation time — no re-renders\r\n // needed on field registration, and no race condition with useEffect timing.\r\n const dynamicResolver = useCallback<Resolver<TFieldValues>>(\r\n async (vals, context, options) => {\r\n if (customResolver) {\r\n return customResolver(vals, context, options);\r\n }\r\n const fieldSchema = getValidationSchema();\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n let finalSchema: z.ZodType<any, any, any>;\r\n if (baseSchema instanceof z.ZodObject) {\r\n finalSchema = baseSchema.merge(fieldSchema);\r\n } else {\r\n finalSchema = baseSchema ?? fieldSchema;\r\n }\r\n return zodResolver(finalSchema)(vals, context, options);\r\n },\r\n // getValidationSchema reads a ref — always current, intentionally omitted.\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n [baseSchema, customResolver]\r\n );\r\n\r\n const internalForm = useForm<TFieldValues>({\r\n resolver: dynamicResolver,\r\n defaultValues,\r\n values,\r\n mode,\r\n reValidateMode,\r\n });\r\n\r\n const form = externalForm ?? internalForm;\r\n\r\n // Trigger validation for a specific field\r\n const triggerValidation = useCallback(async (name: string) => {\r\n return form.trigger(name as Path<TFieldValues>);\r\n }, [form]);\r\n\r\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\r\n e.preventDefault();\r\n if (onSubmit) {\r\n form.handleSubmit(onSubmit, onError)(e);\r\n }\r\n };\r\n\r\n const contextValue = useMemo<FormContextValue<TFieldValues>>(\r\n () => ({\r\n form,\r\n registerFieldValidation,\r\n unregisterFieldValidation,\r\n getValidationSchema,\r\n triggerValidation,\r\n showInlineErrors: mergedConfig.showInlineErrors,\r\n validateOnBlur: mergedConfig.validateOnBlur,\r\n validateOnChange: mergedConfig.validateOnChange,\r\n size: mergedConfig.size,\r\n layout: mergedConfig.layout,\r\n labelWidth: mergedConfig.labelWidth,\r\n disabled: mergedConfig.disabled,\r\n colon: mergedConfig.colon,\r\n }),\r\n [\r\n form,\r\n registerFieldValidation,\r\n unregisterFieldValidation,\r\n getValidationSchema,\r\n triggerValidation,\r\n mergedConfig.showInlineErrors,\r\n mergedConfig.validateOnBlur,\r\n mergedConfig.validateOnChange,\r\n mergedConfig.size,\r\n mergedConfig.layout,\r\n mergedConfig.labelWidth,\r\n mergedConfig.disabled,\r\n mergedConfig.colon,\r\n ]\r\n );\r\n\r\n return (\r\n <FormConfigContext.Provider value={contextValue as FormContextValue}>\r\n <RHFFormProvider {...form}>\r\n <form\r\n {...formProps}\r\n onSubmit={handleSubmit}\r\n noValidate\r\n >\r\n {children}\r\n </form>\r\n </RHFFormProvider>\r\n </FormConfigContext.Provider>\r\n );\r\n}\r\n\r\nForm.displayName = \"Form\";\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkFA,SAAgB,KAGd,EACA,QAAQ,YACR,eACA,QACA,UACA,SACA,QACA,UACA,MAAM,cACN,MAAM,UACN,gBAAgB,oBAChB,UAAU,gBACV,GAAG,aACiC;CACpC,MAAM,eAAe;EAAE,GAAG;EAAmB,GAAG;CAAO;CAEvD,MAAM,OACJ,aACC,aAAa,mBACV,aACA,aAAa,mBAAmB,QAC9B,WACA;CAER,MAAM,iBACJ,uBACC,aAAa,mBAAmB,aAAa;CAEhD,MAAM,EACJ,yBACA,2BACA,wBACE,2BAA2B;
|
|
1
|
+
{"version":3,"file":"Form.js","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useCallback, useMemo, type ReactNode } from \"react\";\r\nimport {\r\n useForm,\r\n FormProvider as RHFFormProvider,\r\n type UseFormReturn,\r\n type FieldValues,\r\n type UseFormProps,\r\n type SubmitHandler,\r\n type SubmitErrorHandler,\r\n type Resolver,\r\n type Path,\r\n} from \"react-hook-form\";\r\nimport { zodResolver } from \"@hookform/resolvers/zod\";\r\nimport { z } from \"zod\";\r\nimport { \r\n FormConfigContext, \r\n defaultFormConfig, \r\n useFieldValidationRegistry,\r\n type FormConfig, \r\n type FormContextValue \r\n} from \"./context\";\r\n\r\n/**\r\n * Props for the Form component\r\n */\r\nexport interface FormProps<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TContext = unknown\r\n> extends Omit<React.FormHTMLAttributes<HTMLFormElement>, \"onSubmit\" | \"onError\"> {\r\n /** Base Zod schema for validation (will be extended by field props) */\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n schema?: z.ZodType<TFieldValues, any, any>;\r\n /** Default values for the form */\r\n defaultValues?: UseFormProps<TFieldValues, TContext>[\"defaultValues\"];\r\n /** Values to reset the form to */\r\n values?: UseFormProps<TFieldValues, TContext>[\"values\"];\r\n /** Submit handler */\r\n onSubmit?: SubmitHandler<TFieldValues>;\r\n /** Error handler */\r\n onError?: SubmitErrorHandler<TFieldValues>;\r\n /** Form configuration */\r\n config?: FormConfig;\r\n /** Children */\r\n children?: ReactNode;\r\n /** External form instance (for controlled forms) */\r\n form?: UseFormReturn<TFieldValues>;\r\n /** Validation mode */\r\n mode?: UseFormProps<TFieldValues, TContext>[\"mode\"];\r\n /** Revalidation mode */\r\n reValidateMode?: UseFormProps<TFieldValues, TContext>[\"reValidateMode\"];\r\n /** Custom resolver (overrides schema) */\r\n resolver?: Resolver<TFieldValues>;\r\n}\r\n\r\n/**\r\n * Form component that provides form context and validation\r\n * \r\n * Child components like TextBox can register their validation rules automatically.\r\n * \r\n * @example\r\n * ```tsx\r\n * // Validation is automatically built from component props\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 * <Button type=\"submit\">Submit</Button>\r\n * </Form>\r\n * \r\n * // Or with a base schema that gets extended\r\n * const baseSchema = z.object({\r\n * username: z.string(),\r\n * email: z.string(),\r\n * });\r\n * \r\n * <Form schema={baseSchema} onSubmit={handleSubmit}>\r\n * <TextBox name=\"username\" required minLength={3} /> // Adds required + minLength\r\n * <TextBox name=\"email\" required email /> // Adds required + email validation\r\n * </Form>\r\n * ```\r\n */\r\nexport function Form<\r\n TFieldValues extends FieldValues = FieldValues,\r\n TContext = unknown\r\n>({\r\n schema: baseSchema,\r\n defaultValues,\r\n values,\r\n onSubmit,\r\n onError,\r\n config,\r\n children,\r\n form: externalForm,\r\n mode: modeProp,\r\n reValidateMode: reValidateModeProp,\r\n resolver: customResolver,\r\n ...formProps\r\n}: FormProps<TFieldValues, TContext>) {\r\n const mergedConfig = { ...defaultFormConfig, ...config };\r\n\r\n const mode =\r\n modeProp ??\r\n (mergedConfig.validateOnChange\r\n ? \"onChange\"\r\n : mergedConfig.validateOnBlur !== false\r\n ? \"onBlur\"\r\n : \"onSubmit\");\r\n\r\n const reValidateMode =\r\n reValidateModeProp ??\r\n (mergedConfig.validateOnChange ? \"onChange\" : \"onBlur\");\r\n\r\n const {\r\n registerFieldValidation,\r\n unregisterFieldValidation,\r\n getValidationSchema,\r\n } = useFieldValidationRegistry();\r\n\r\n // Stable resolver that reads from fieldsRef at validation time — no re-renders\r\n // needed on field registration, and no race condition with useEffect timing.\r\n const dynamicResolver = useCallback<Resolver<TFieldValues>>(\r\n async (vals, context, options) => {\r\n if (customResolver) {\r\n return customResolver(vals, context, options);\r\n }\r\n const fieldSchema = getValidationSchema();\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n let finalSchema: z.ZodType<any, any, any>;\r\n if (baseSchema instanceof z.ZodObject) {\r\n finalSchema = baseSchema.merge(fieldSchema);\r\n } else {\r\n finalSchema = baseSchema ?? fieldSchema;\r\n }\r\n return zodResolver(finalSchema)(vals, context, options);\r\n },\r\n // getValidationSchema reads a ref — always current, intentionally omitted.\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n [baseSchema, customResolver]\r\n );\r\n\r\n const internalForm = useForm<TFieldValues>({\r\n resolver: dynamicResolver,\r\n defaultValues,\r\n values,\r\n mode,\r\n reValidateMode,\r\n });\r\n\r\n const form = externalForm ?? internalForm;\r\n\r\n // Trigger validation for a specific field\r\n const triggerValidation = useCallback(async (name: string) => {\r\n return form.trigger(name as Path<TFieldValues>);\r\n }, [form]);\r\n\r\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\r\n e.preventDefault();\r\n if (onSubmit) {\r\n form.handleSubmit(onSubmit, onError)(e);\r\n }\r\n };\r\n\r\n const contextValue = useMemo<FormContextValue<TFieldValues>>(\r\n () => ({\r\n form,\r\n registerFieldValidation,\r\n unregisterFieldValidation,\r\n getValidationSchema,\r\n triggerValidation,\r\n showInlineErrors: mergedConfig.showInlineErrors,\r\n validateOnBlur: mergedConfig.validateOnBlur,\r\n validateOnChange: mergedConfig.validateOnChange,\r\n size: mergedConfig.size,\r\n layout: mergedConfig.layout,\r\n labelWidth: mergedConfig.labelWidth,\r\n disabled: mergedConfig.disabled,\r\n colon: mergedConfig.colon,\r\n }),\r\n [\r\n form,\r\n registerFieldValidation,\r\n unregisterFieldValidation,\r\n getValidationSchema,\r\n triggerValidation,\r\n mergedConfig.showInlineErrors,\r\n mergedConfig.validateOnBlur,\r\n mergedConfig.validateOnChange,\r\n mergedConfig.size,\r\n mergedConfig.layout,\r\n mergedConfig.labelWidth,\r\n mergedConfig.disabled,\r\n mergedConfig.colon,\r\n ]\r\n );\r\n\r\n return (\r\n <FormConfigContext.Provider value={contextValue as FormContextValue}>\r\n <RHFFormProvider {...form}>\r\n <form\r\n {...formProps}\r\n onSubmit={handleSubmit}\r\n noValidate\r\n >\r\n {children}\r\n </form>\r\n </RHFFormProvider>\r\n </FormConfigContext.Provider>\r\n );\r\n}\r\n\r\nForm.displayName = \"Form\";\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkFA,SAAgB,KAGd,EACA,QAAQ,YACR,eACA,QACA,UACA,SACA,QACA,UACA,MAAM,cACN,MAAM,UACN,gBAAgB,oBAChB,UAAU,gBACV,GAAG,aACiC;CACpC,MAAM,eAAe;EAAE,GAAG;EAAmB,GAAG;CAAO;CAEvD,MAAM,OACJ,aACC,aAAa,mBACV,aACA,aAAa,mBAAmB,QAC9B,WACA;CAER,MAAM,iBACJ,uBACC,aAAa,mBAAmB,aAAa;CAEhD,MAAM,EACJ,yBACA,2BACA,wBACE,2BAA2B;CAI/B,MAAM,kBAAkB,YACtB,OAAO,MAAM,SAAS,YAAY;EAChC,IAAI,gBACF,OAAO,eAAe,MAAM,SAAS,OAAO;EAE9C,MAAM,cAAc,oBAAoB;EAExC,IAAI;EACJ,IAAI,sBAAsB,EAAE,WAC1B,cAAc,WAAW,MAAM,WAAW;OAE1C,cAAc,cAAc;EAE9B,OAAO,YAAY,WAAW,CAAC,CAAC,MAAM,SAAS,OAAO;CACxD,GAGA,CAAC,YAAY,cAAc,CAC7B;CAEA,MAAM,eAAe,QAAsB;EACzC,UAAU;EACV;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,OAAO,gBAAgB;CAG7B,MAAM,oBAAoB,YAAY,OAAO,SAAiB;EAC5D,OAAO,KAAK,QAAQ,IAA0B;CAChD,GAAG,CAAC,IAAI,CAAC;CAET,MAAM,gBAAgB,MAAwC;EAC5D,EAAE,eAAe;EACjB,IAAI,UACF,KAAK,aAAa,UAAU,OAAO,CAAC,CAAC,CAAC;CAE1C;CAEA,MAAM,eAAe,eACZ;EACL;EACA;EACA;EACA;EACA;EACA,kBAAkB,aAAa;EAC/B,gBAAgB,aAAa;EAC7B,kBAAkB,aAAa;EAC/B,MAAM,aAAa;EACnB,QAAQ,aAAa;EACrB,YAAY,aAAa;EACzB,UAAU,aAAa;EACvB,OAAO,aAAa;CACtB,IACA;EACE;EACA;EACA;EACA;EACA;EACA,aAAa;EACb,aAAa;EACb,aAAa;EACb,aAAa;EACb,aAAa;EACb,aAAa;EACb,aAAa;EACb,aAAa;CACf,CACF;CAEA,OACE,oBAAC,kBAAkB,UAAnB;EAA4B,OAAO;EACjC,UAAA,oBAAC,cAAD;GAAiB,GAAI;GACnB,UAAA,oBAAC,QAAD;IACE,GAAI;IACJ,UAAU;IACV,YAAA;IAEC;GACG,CAAA;EACS,CAAA;CACS,CAAA;AAEhC;AAEA,KAAK,cAAc"}
|