@komensal/ui 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/index.d.ts +420 -0
  2. package/dist/index.js +1710 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/locales/index.d.ts +34 -0
  5. package/dist/locales/index.js +40 -0
  6. package/dist/locales/index.js.map +1 -0
  7. package/package.json +24 -8
  8. package/src/components/alert.tsx +0 -45
  9. package/src/components/auth-header.tsx +0 -26
  10. package/src/components/button.tsx +0 -121
  11. package/src/components/command.tsx +0 -125
  12. package/src/components/dialog.tsx +0 -118
  13. package/src/components/form-fields/index.ts +0 -5
  14. package/src/components/form-fields/input-field.tsx +0 -131
  15. package/src/components/form-fields/label-field.tsx +0 -20
  16. package/src/components/form-fields/map-picker-field.tsx +0 -49
  17. package/src/components/form-fields/otp-field.tsx +0 -76
  18. package/src/components/form-fields/select-field.tsx +0 -77
  19. package/src/components/form.tsx +0 -138
  20. package/src/components/google-map-picker.tsx +0 -243
  21. package/src/components/input.tsx +0 -40
  22. package/src/components/label.tsx +0 -17
  23. package/src/components/loading.tsx +0 -19
  24. package/src/components/otp-input.tsx +0 -62
  25. package/src/components/password-checklist.tsx +0 -37
  26. package/src/components/popover.tsx +0 -31
  27. package/src/components/select-input.tsx +0 -236
  28. package/src/components/select.tsx +0 -143
  29. package/src/components/spinner.tsx +0 -61
  30. package/src/components/step-header.tsx +0 -16
  31. package/src/components/stepper.tsx +0 -69
  32. package/src/components/toast/index.ts +0 -2
  33. package/src/components/toast/toast-provider.tsx +0 -123
  34. package/src/components/toast/toast.tsx +0 -106
  35. package/src/components/tooltip.tsx +0 -56
  36. package/src/components/wrapper.tsx +0 -12
  37. package/src/index.ts +0 -27
  38. package/src/locales/es/ui.json +0 -28
  39. package/src/locales/index.ts +0 -7
  40. package/src/types/password.ts +0 -12
  41. package/src/types/toast.ts +0 -19
  42. package/src/utils/cn.ts +0 -6
  43. package/src/utils/index.ts +0 -3
  44. package/src/utils/styles.ts +0 -19
  45. package/src/utils/toast-emitter.ts +0 -37
  46. package/src/vite-env.d.ts +0 -3
  47. /package/{src → dist}/styles/index.css +0 -0
  48. /package/{src → dist}/styles/theme.css +0 -0
@@ -1,125 +0,0 @@
1
- import { type DialogProps } from '@radix-ui/react-dialog'
2
- import { MagnifyingGlassIcon } from '@radix-ui/react-icons'
3
- import { Command as CommandPrimitive } from 'cmdk'
4
- import * as React from 'react'
5
-
6
- import { cn } from '../utils'
7
- import { Dialog, DialogContent } from './dialog'
8
-
9
- const Command = React.forwardRef<
10
- React.ElementRef<typeof CommandPrimitive>,
11
- React.ComponentPropsWithoutRef<typeof CommandPrimitive>
12
- >(({ className, ...props }, ref) => (
13
- <CommandPrimitive
14
- className={cn('bg-surface text-foreground flex h-full w-full flex-col overflow-hidden rounded-md', className)}
15
- ref={ref}
16
- {...props}
17
- />
18
- ))
19
- Command.displayName = CommandPrimitive.displayName
20
-
21
- type CommandDialogProps = DialogProps
22
-
23
- const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
24
- return (
25
- <Dialog {...props}>
26
- <DialogContent className='overflow-hidden p-0'>
27
- <Command className='**:[[cmdk-group-heading]]:text-muted [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5 **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:font-medium **:[[cmdk-group]]:px-2 **:[[cmdk-input]]:h-12 **:[[cmdk-item]]:px-2 **:[[cmdk-item]]:py-3'>
28
- {children}
29
- </Command>
30
- </DialogContent>
31
- </Dialog>
32
- )
33
- }
34
-
35
- const CommandInput = React.forwardRef<
36
- React.ElementRef<typeof CommandPrimitive.Input>,
37
- React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
38
- >(({ className, ...props }, ref) => (
39
- <div className='flex items-center border-b px-3' cmdk-input-wrapper=''>
40
- <MagnifyingGlassIcon className='mr-2 h-4 w-4 shrink-0 opacity-50' />
41
- <CommandPrimitive.Input
42
- className={cn(
43
- 'placeholder:text-placeholder flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50',
44
- className
45
- )}
46
- ref={ref}
47
- {...props}
48
- />
49
- </div>
50
- ))
51
-
52
- CommandInput.displayName = CommandPrimitive.Input.displayName
53
-
54
- const CommandList = React.forwardRef<
55
- React.ElementRef<typeof CommandPrimitive.List>,
56
- React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
57
- >(({ className, ...props }, ref) => (
58
- <CommandPrimitive.List className={cn('max-h-75 overflow-x-hidden overflow-y-auto', className)} ref={ref} {...props} />
59
- ))
60
-
61
- CommandList.displayName = CommandPrimitive.List.displayName
62
-
63
- const CommandEmpty = React.forwardRef<
64
- React.ElementRef<typeof CommandPrimitive.Empty>,
65
- React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
66
- >((props, ref) => <CommandPrimitive.Empty className='py-6 text-center text-sm' ref={ref} {...props} />)
67
-
68
- CommandEmpty.displayName = CommandPrimitive.Empty.displayName
69
-
70
- const CommandGroup = React.forwardRef<
71
- React.ElementRef<typeof CommandPrimitive.Group>,
72
- React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
73
- >(({ className, ...props }, ref) => (
74
- <CommandPrimitive.Group
75
- className={cn(
76
- 'text-foreground **:[[cmdk-group-heading]]:text-muted overflow-hidden p-1 **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:py-1.5 **:[[cmdk-group-heading]]:text-xs **:[[cmdk-group-heading]]:font-medium',
77
- className
78
- )}
79
- ref={ref}
80
- {...props}
81
- />
82
- ))
83
-
84
- CommandGroup.displayName = CommandPrimitive.Group.displayName
85
-
86
- const CommandSeparator = React.forwardRef<
87
- React.ElementRef<typeof CommandPrimitive.Separator>,
88
- React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
89
- >(({ className, ...props }, ref) => (
90
- <CommandPrimitive.Separator className={cn('bg-border -mx-1 h-px', className)} ref={ref} {...props} />
91
- ))
92
- CommandSeparator.displayName = CommandPrimitive.Separator.displayName
93
-
94
- const CommandItem = React.forwardRef<
95
- React.ElementRef<typeof CommandPrimitive.Item>,
96
- React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
97
- >(({ className, ...props }, ref) => (
98
- <CommandPrimitive.Item
99
- className={cn(
100
- 'relative flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',
101
- className
102
- )}
103
- ref={ref}
104
- {...props}
105
- />
106
- ))
107
-
108
- CommandItem.displayName = CommandPrimitive.Item.displayName
109
-
110
- const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
111
- return <span className={cn('text-muted ml-auto text-xs tracking-widest', className)} {...props} />
112
- }
113
- CommandShortcut.displayName = 'CommandShortcut'
114
-
115
- export {
116
- Command,
117
- CommandDialog,
118
- CommandEmpty,
119
- CommandGroup,
120
- CommandInput,
121
- CommandItem,
122
- CommandList,
123
- CommandSeparator,
124
- CommandShortcut
125
- }
@@ -1,118 +0,0 @@
1
- import * as DialogPrimitive from '@radix-ui/react-dialog'
2
- import { Cross2Icon } from '@radix-ui/react-icons'
3
- import * as React from 'react'
4
- import { useTranslation } from 'react-i18next'
5
-
6
- import { cn } from '../utils'
7
-
8
- const Dialog = DialogPrimitive.Root
9
-
10
- const DialogTrigger = DialogPrimitive.Trigger
11
-
12
- const DialogPortal = DialogPrimitive.Portal
13
-
14
- const DialogClose = DialogPrimitive.Close
15
-
16
- const DialogOverlay = React.forwardRef<
17
- React.ElementRef<typeof DialogPrimitive.Overlay>,
18
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & { isAbsolute?: boolean }
19
- >(({ className, isAbsolute = false, ...props }, ref) => (
20
- <DialogPrimitive.Overlay
21
- className={cn(
22
- 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 bg-foreground/10 z-60 backdrop-blur-xs',
23
- isAbsolute ? 'absolute inset-0' : 'fixed inset-0',
24
- className
25
- )}
26
- ref={ref}
27
- {...props}
28
- />
29
- ))
30
- DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
31
-
32
- interface DialogContentProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
33
- container?: HTMLElement | null
34
- isAbsolute?: boolean
35
- isCloseIcon?: boolean
36
- overlayClassName?: string
37
- }
38
-
39
- const DialogContent = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Content>, DialogContentProps>(
40
- ({ children, className, container, isAbsolute = false, isCloseIcon = false, overlayClassName, ...props }, ref) => {
41
- const { t } = useTranslation('ui')
42
-
43
- return (
44
- <DialogPortal container={container}>
45
- <DialogOverlay className={overlayClassName} isAbsolute={isAbsolute} />
46
-
47
- <DialogPrimitive.Content
48
- className={cn(
49
- 'bg-surface data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] z-70 grid w-[calc(100%-2rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] gap-0 rounded-2xl p-6 px-0 shadow-lg duration-200 outline-none lg:px-0',
50
- isAbsolute ? 'absolute top-[50%] left-[50%]' : 'fixed top-[50%] left-[50%]',
51
- className
52
- )}
53
- ref={ref}
54
- {...props}
55
- >
56
- {children}
57
- {isCloseIcon && (
58
- <DialogPrimitive.Close className='data-[state=open]:text-muted ring-offset-surface focus:ring-ring data-[state=open]:bg-hover border-border bg-border absolute top-11 right-8 flex h-8 w-8 min-w-8 cursor-pointer items-center justify-center rounded-full opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none'>
59
- <Cross2Icon className='text-body hover:text-primary-dark h-4 w-4' />
60
- <span className='sr-only'>{t('dialog.close')}</span>
61
- </DialogPrimitive.Close>
62
- )}
63
- </DialogPrimitive.Content>
64
- </DialogPortal>
65
- )
66
- }
67
- )
68
- DialogContent.displayName = DialogPrimitive.Content.displayName
69
-
70
- const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
71
- <div className={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)} {...props} />
72
- )
73
- DialogHeader.displayName = 'DialogHeader'
74
-
75
- const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
76
- <div
77
- className={cn('flex flex-col-reverse justify-center rounded-2xl sm:flex-row sm:space-x-2', className)}
78
- {...props}
79
- />
80
- )
81
- DialogFooter.displayName = 'DialogFooter'
82
-
83
- const DialogTitle = React.forwardRef<
84
- React.ElementRef<typeof DialogPrimitive.Title>,
85
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
86
- >(({ className, ...props }, ref) => (
87
- <DialogPrimitive.Title
88
- className={cn('text-lg leading-none font-semibold tracking-tight', className)}
89
- ref={ref}
90
- {...props}
91
- >
92
- <span>{props.children}</span>
93
- </DialogPrimitive.Title>
94
- ))
95
- DialogTitle.displayName = DialogPrimitive.Title.displayName
96
-
97
- const DialogDescription = React.forwardRef<
98
- React.ElementRef<typeof DialogPrimitive.Description>,
99
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
100
- >(({ className, ...props }, ref) => (
101
- <DialogPrimitive.Description className={cn('text-muted text-sm', className)} ref={ref} {...props}>
102
- <span>{props.children}</span>
103
- </DialogPrimitive.Description>
104
- ))
105
- DialogDescription.displayName = DialogPrimitive.Description.displayName
106
-
107
- export {
108
- Dialog,
109
- DialogClose,
110
- DialogContent,
111
- DialogDescription,
112
- DialogFooter,
113
- DialogHeader,
114
- DialogOverlay,
115
- DialogPortal,
116
- DialogTitle,
117
- DialogTrigger
118
- }
@@ -1,5 +0,0 @@
1
- export * from './input-field'
2
- export * from './label-field'
3
- export * from './map-picker-field'
4
- export * from './otp-field'
5
- export * from './select-field'
@@ -1,131 +0,0 @@
1
- import { useState } from 'react'
2
- import { Control, FieldValues, Path } from 'react-hook-form'
3
- import { useTranslation } from 'react-i18next'
4
- import { FaRegEye, FaRegEyeSlash } from 'react-icons/fa6'
5
- import { RxCross2 } from 'react-icons/rx'
6
-
7
- import { cn } from '../../utils'
8
- import { FormControl, FormField, FormItem, FormMessage } from '../form'
9
- import { Input } from '../input'
10
- import { LabelField } from './label-field'
11
-
12
- interface InputFieldProps<T extends FieldValues = FieldValues> {
13
- control: Control<T>
14
- disabled?: boolean
15
- inputClassName?: string
16
- isClearable?: boolean
17
- label?: string
18
- labelClassName?: string
19
- mainClassName?: string
20
- name: Path<T>
21
- onClear?: () => void
22
- placeholder?: string
23
- type?: string
24
- visualRequired?: boolean
25
- }
26
-
27
- export const InputField = <T extends FieldValues = FieldValues>({
28
- control,
29
- disabled,
30
- inputClassName,
31
- isClearable,
32
- label,
33
- labelClassName,
34
- mainClassName,
35
- name,
36
- onClear,
37
- placeholder,
38
- type = 'text',
39
- visualRequired
40
- }: InputFieldProps<T>) => {
41
- const { t } = useTranslation('ui')
42
- const [isPasswordVisible, setIsPasswordVisible] = useState(false)
43
-
44
- const togglePasswordVisibility = () => {
45
- setIsPasswordVisible((prev) => !prev)
46
- }
47
-
48
- const isPassword = type === 'password'
49
- const inputType = isPassword ? (isPasswordVisible ? 'text' : 'password') : type === 'plate' ? 'text' : type
50
-
51
- const isPlate = type === 'plate'
52
-
53
- return (
54
- <FormField
55
- control={control}
56
- name={name}
57
- render={({ field, fieldState }) => {
58
- const hasError = !!fieldState.error
59
-
60
- return (
61
- <FormItem className={cn('flex flex-col', mainClassName)}>
62
- <LabelField
63
- label={label}
64
- labelClassName={cn(labelClassName, hasError && 'text-destructive')}
65
- name={name}
66
- visualRequired={visualRequired}
67
- />
68
- <FormControl>
69
- <div className='relative'>
70
- <Input
71
- {...field}
72
- autoComplete={isPassword ? 'current-password' : undefined}
73
- className={cn(
74
- inputClassName,
75
- isPlate && 'uppercase',
76
- hasError && 'border-destructive',
77
- isPassword && 'pr-10 [&::-ms-reveal]:hidden'
78
- )}
79
- data-no-password-toggle
80
- disabled={disabled}
81
- maxLength={isPlate ? 6 : undefined}
82
- min={type === 'number' ? 0 : undefined}
83
- onChange={(e) => {
84
- let value = e.target.value
85
-
86
- if (isPlate) {
87
- value = value
88
- .toUpperCase()
89
- .replace(/[^A-Z0-9]/g, '')
90
- .slice(0, 6)
91
- }
92
-
93
- field.onChange(value)
94
- }}
95
- placeholder={placeholder}
96
- type={inputType}
97
- value={field.value ?? ''}
98
- />
99
-
100
- <div className='absolute inset-y-0 right-0 flex items-center space-x-2 pr-2'>
101
- {field.value && isClearable && (
102
- <button
103
- className='focus:outline-none'
104
- onClick={onClear}
105
- title={t('inputField.clear')}
106
- type='button'
107
- >
108
- <RxCross2 size={18} />
109
- </button>
110
- )}
111
-
112
- {type === 'password' && (
113
- <button
114
- className='focus:outline-none'
115
- onClick={togglePasswordVisibility}
116
- title={isPasswordVisible ? t('inputField.hidePassword') : t('inputField.showPassword')}
117
- type='button'
118
- >
119
- {isPasswordVisible ? <FaRegEye size={18} /> : <FaRegEyeSlash size={20} />}
120
- </button>
121
- )}
122
- </div>
123
- </div>
124
- </FormControl>
125
- <FormMessage />
126
- </FormItem>
127
- )
128
- }}
129
- />
130
- )
131
- }
@@ -1,20 +0,0 @@
1
- import { cn } from '../../utils'
2
- import { Label } from '../label'
3
-
4
- interface LabelFieldProps {
5
- label?: string
6
- labelClassName?: string
7
- name: string
8
- visualRequired?: boolean
9
- }
10
-
11
- export const LabelField = ({ label, labelClassName, name, visualRequired }: LabelFieldProps) => {
12
- return (
13
- <Label
14
- className={cn('text-body mb-2 text-start text-sm leading-none font-normal tracking-normal', labelClassName)}
15
- htmlFor={name}
16
- >
17
- <span>{label}</span> {visualRequired && <span className='text-destructive'> *</span>}
18
- </Label>
19
- )
20
- }
@@ -1,49 +0,0 @@
1
- import type { Control, FieldValues, Path } from 'react-hook-form'
2
-
3
- import { cn } from '../../utils'
4
- import { FormControl, FormField, FormItem, FormMessage } from '../form'
5
- import { GoogleMapPicker, type GoogleMapPickerProps } from '../google-map-picker'
6
- import { LabelField } from './label-field'
7
-
8
- type MapPickerFieldProps<T extends FieldValues> = Omit<GoogleMapPickerProps, 'hasError' | 'onChange' | 'value'> & {
9
- control: Control<T>
10
- label?: string
11
- labelClassName?: string
12
- mainClassName?: string
13
- name: Path<T>
14
- visualRequired?: boolean
15
- }
16
-
17
- export const MapPickerField = <T extends FieldValues>({
18
- control,
19
- label,
20
- labelClassName,
21
- mainClassName,
22
- name,
23
- visualRequired,
24
- ...pickerProps
25
- }: MapPickerFieldProps<T>) => (
26
- <FormField
27
- control={control}
28
- name={name}
29
- render={({ field, fieldState }) => (
30
- <FormItem className={cn('flex flex-col', mainClassName)}>
31
- <LabelField
32
- label={label}
33
- labelClassName={cn(labelClassName, fieldState.error && 'text-destructive')}
34
- name={name}
35
- visualRequired={visualRequired}
36
- />
37
- <FormControl>
38
- <GoogleMapPicker
39
- {...pickerProps}
40
- hasError={!!fieldState.error}
41
- onChange={field.onChange}
42
- value={field.value ?? ''}
43
- />
44
- </FormControl>
45
- <FormMessage />
46
- </FormItem>
47
- )}
48
- />
49
- )
@@ -1,76 +0,0 @@
1
- import React from 'react'
2
- import { Control, FieldPath, FieldValues } from 'react-hook-form'
3
-
4
- import { cn } from '../../utils'
5
- import { FormControl, FormField, FormItem, FormMessage } from '../form'
6
- import { Label } from '../label'
7
- import { InputOTP, InputOTPGroup, InputOTPSlot } from '../otp-input'
8
-
9
- interface OtpInputFormFieldProps<
10
- TFieldValues extends FieldValues = FieldValues,
11
- TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
12
- > {
13
- autoFocus?: boolean
14
- className?: string
15
- containerClassName?: string
16
- control: Control<TFieldValues>
17
- disabled?: boolean
18
- label?: string
19
- labelClassName?: string
20
- name: TName
21
- otpLength?: number
22
- }
23
-
24
- export function OTPField<
25
- TFieldValues extends FieldValues = FieldValues,
26
- TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
27
- >({
28
- autoFocus,
29
- className,
30
- containerClassName,
31
- control,
32
- disabled,
33
- label,
34
- labelClassName,
35
- name,
36
- otpLength = 6
37
- }: OtpInputFormFieldProps<TFieldValues, TName>) {
38
- return (
39
- <FormField
40
- control={control}
41
- name={name}
42
- render={({ field, fieldState }) => (
43
- <FormItem className={cn('flex flex-col', className)}>
44
- {label ? (
45
- <Label className={cn('text-start text-sm font-semibold', labelClassName)} htmlFor={name}>
46
- {label}
47
- </Label>
48
- ) : null}
49
- <FormControl>
50
- <InputOTP
51
- aria-invalid={fieldState.invalid || undefined}
52
- autoComplete='one-time-code'
53
- autoFocus={autoFocus}
54
- containerClassName={cn('justify-center', containerClassName)}
55
- disabled={disabled}
56
- id={name}
57
- inputMode='numeric'
58
- maxLength={otpLength}
59
- onChange={(val: string) => field.onChange(val)}
60
- onPaste={(e: React.ClipboardEvent<HTMLInputElement>) => field.onChange(e.clipboardData.getData('text'))}
61
- pattern='[0-9]*'
62
- value={field.value ?? ''}
63
- >
64
- <InputOTPGroup>
65
- {Array.from({ length: otpLength }).map((_, i) => (
66
- <InputOTPSlot aria-invalid={fieldState.invalid || undefined} index={i} key={i} />
67
- ))}
68
- </InputOTPGroup>
69
- </InputOTP>
70
- </FormControl>
71
- <FormMessage />
72
- </FormItem>
73
- )}
74
- />
75
- )
76
- }
@@ -1,77 +0,0 @@
1
- import { Control, FieldValues, Path } from 'react-hook-form'
2
-
3
- import { cn } from '../../utils'
4
- import { FormControl, FormField, FormItem, FormMessage } from '../form'
5
- import { SelectInput } from '../select-input'
6
- import { LabelField } from './label-field'
7
-
8
- export interface Options {
9
- label: string
10
- value: number | string
11
- }
12
-
13
- interface SelectFieldProps<T extends FieldValues = FieldValues> {
14
- ableDeleteOption?: boolean
15
- className?: string
16
- control: Control<T>
17
- disabled?: boolean
18
- label?: string
19
- labelClassName?: string
20
- mainClassName?: string
21
- name: Path<T>
22
- onChange?: (...event: unknown[]) => void
23
- options: Options[] | undefined
24
- placeholder?: string
25
- search?: boolean
26
- visualRequired?: boolean
27
- }
28
-
29
- export const SelectField = <T extends FieldValues = FieldValues>({
30
- ableDeleteOption,
31
- className,
32
- control,
33
- disabled,
34
- label,
35
- labelClassName,
36
- mainClassName,
37
- name,
38
- options,
39
- placeholder,
40
- search,
41
- visualRequired
42
- }: SelectFieldProps<T>) => {
43
- return (
44
- <FormField
45
- control={control}
46
- name={name}
47
- render={({ field, fieldState }) => {
48
- const hasError = !!fieldState.error
49
-
50
- return (
51
- <FormItem className={cn('flex flex-col', mainClassName)}>
52
- <LabelField
53
- label={label}
54
- labelClassName={cn(labelClassName, hasError && 'text-destructive')}
55
- name={name}
56
- visualRequired={visualRequired}
57
- />
58
- <FormControl>
59
- <SelectInput
60
- ableDeleteOption={ableDeleteOption}
61
- className={className}
62
- disabled={disabled}
63
- error={fieldState.error}
64
- items={options}
65
- onChange={field.onChange}
66
- placeholder={placeholder}
67
- search={search}
68
- value={typeof field.value === 'number' ? `${field.value}` : field.value}
69
- />
70
- </FormControl>
71
- <FormMessage />
72
- </FormItem>
73
- )
74
- }}
75
- />
76
- )
77
- }