@js-empire/emperor-ui 1.2.5 → 1.2.7

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 (112) hide show
  1. package/package.json +5 -2
  2. package/src/components/atoms/color-picker/color-picker.tsx +0 -1
  3. package/src/components/atoms/color-picker/free-color-picker.tsx +8 -10
  4. package/src/components/atoms/color-picker/preset-color-picker.tsx +5 -3
  5. package/src/components/atoms/color-picker/stories/color-picker.stories.tsx +25 -11
  6. package/src/components/atoms/field/field.tsx +75 -5
  7. package/src/components/atoms/field/index.ts +2 -0
  8. package/src/components/atoms/field/units/autocomplete-field.tsx +49 -0
  9. package/src/components/atoms/field/units/checkbox-field.tsx +35 -0
  10. package/src/components/atoms/field/units/index.ts +7 -0
  11. package/src/components/atoms/field/units/input-field.tsx +35 -0
  12. package/src/components/atoms/field/units/radio-field.tsx +43 -0
  13. package/src/components/atoms/field/units/select-field.tsx +50 -0
  14. package/src/components/atoms/field/units/switch-field.tsx +35 -0
  15. package/src/components/atoms/field/units/textarea-field.tsx +37 -0
  16. package/src/components/atoms/filter/filter.tsx +2 -1
  17. package/src/components/atoms/filter/stories/filter.stories.tsx +148 -7
  18. package/src/components/atoms/filter/units/autocomplete-filter.tsx +38 -11
  19. package/src/components/atoms/filter/units/checkbox-filter.tsx +16 -6
  20. package/src/components/atoms/filter/units/checkbox-group-filter.tsx +40 -9
  21. package/src/components/atoms/filter/units/date-filter.tsx +18 -22
  22. package/src/components/atoms/filter/units/numeric-filter.tsx +12 -7
  23. package/src/components/atoms/filter/units/range-filter.tsx +42 -13
  24. package/src/components/atoms/filter/units/search-filter.tsx +8 -7
  25. package/src/components/atoms/filter/units/select-filter.tsx +17 -9
  26. package/src/components/atoms/filter/units/switch-filter.tsx +6 -4
  27. package/src/components/atoms/uploader/{avatar-label.tsx → components/avatar-label.tsx} +17 -5
  28. package/src/components/atoms/uploader/components/index.ts +8 -0
  29. package/src/components/atoms/uploader/components/upload-file-error-box.tsx +40 -0
  30. package/src/components/atoms/uploader/{upload-file-label.tsx → components/upload-file-label.tsx} +18 -11
  31. package/src/components/atoms/uploader/index.ts +1 -8
  32. package/src/components/atoms/uploader/stories/uploader.stories.tsx +17 -10
  33. package/src/components/molecules/item-card/index.ts +2 -0
  34. package/src/components/molecules/item-card/item-actions-buttons.tsx +43 -0
  35. package/src/components/molecules/item-card/item-actions-overlay.tsx +41 -0
  36. package/src/components/molecules/item-card/item-card-body.tsx +8 -2
  37. package/src/components/molecules/item-card/item-card-footer.tsx +22 -1
  38. package/src/components/molecules/item-card/item-card-header.tsx +8 -2
  39. package/src/components/molecules/item-card/item-card.tsx +39 -1
  40. package/src/components/molecules/item-card/stories/item-card.stories.tsx +36 -0
  41. package/src/components/organisms/deletion-confirmor/deletion-confirmor.tsx +114 -0
  42. package/src/components/organisms/deletion-confirmor/index.ts +3 -0
  43. package/src/components/organisms/deletion-confirmor/stories/components.tsx +22 -0
  44. package/src/components/organisms/deletion-confirmor/stories/deletion-confirmor.stories.tsx +78 -0
  45. package/src/components/organisms/deletion-confirmor/styles/classes.ts +28 -0
  46. package/src/components/organisms/{filters → deletion-confirmor}/styles/index.ts +1 -0
  47. package/src/components/organisms/deletion-confirmor/styles/styles.ts +4 -0
  48. package/src/components/organisms/form-builder/form-builder.stories.tsx +144 -0
  49. package/src/components/organisms/form-builder/form-builder.tsx +75 -0
  50. package/src/components/organisms/form-builder/index.ts +1 -0
  51. package/src/components/organisms/index.ts +2 -1
  52. package/src/constants/card.tsx +5 -2
  53. package/src/constants/defaults.ts +40 -0
  54. package/src/context/form-builder-context.tsx +8 -0
  55. package/src/context/index.ts +1 -0
  56. package/src/hooks/index.ts +1 -0
  57. package/src/hooks/use-filters.ts +2 -2
  58. package/src/hooks/use-form-builder-context.ts +16 -0
  59. package/src/hooks/use-uploader.tsx +21 -9
  60. package/src/i18n/locales/atoms/ar.ts +1 -1
  61. package/src/i18n/locales/atoms/en.ts +1 -1
  62. package/src/i18n/locales/organisms/ar.ts +4 -0
  63. package/src/i18n/locales/organisms/en.ts +4 -0
  64. package/src/mocks/deletion-confirmor.ts +16 -0
  65. package/src/mocks/index.ts +2 -0
  66. package/src/mocks/locales/index.ts +1 -0
  67. package/src/mocks/locales/uploader.ts +33 -0
  68. package/src/providers/config-provider.tsx +8 -0
  69. package/src/providers/form-builder-provider-context.tsx +18 -0
  70. package/src/providers/index.ts +1 -0
  71. package/src/styles/globals.css +26 -1
  72. package/src/styles/hero.ts +1 -0
  73. package/src/styles/index.css +0 -5
  74. package/src/types/components/atoms/color-picker/color-picker.ts +10 -1
  75. package/src/types/components/atoms/field/field.ts +53 -1
  76. package/src/types/components/atoms/filter/filter.ts +26 -17
  77. package/src/types/components/atoms/uploader.ts +4 -0
  78. package/src/types/components/molecules/item-card/item-card.ts +14 -4
  79. package/src/types/components/organisms/deletion-confirmor/deletion-confirmor.ts +22 -0
  80. package/src/types/components/organisms/deletion-confirmor/index.ts +1 -0
  81. package/src/types/components/organisms/form-builder/context.ts +6 -0
  82. package/src/types/components/organisms/form-builder/form-builder.ts +39 -0
  83. package/src/types/components/organisms/form-builder/index.ts +2 -0
  84. package/src/types/components/organisms/index.ts +2 -0
  85. package/src/types/context/config.ts +2 -0
  86. package/src/types/context/index.ts +1 -0
  87. package/src/types/context/theme.ts +33 -0
  88. package/src/utils/uploader.ts +25 -7
  89. package/dist/emperor-ui.js +0 -123
  90. package/dist/emperor-ui.umd.cjs +0 -63
  91. package/dist/globals.css +0 -1
  92. package/dist/icons/emperor-ui-logo.ico +0 -0
  93. package/dist/images/avatar-female.jpg +0 -0
  94. package/dist/images/avatar-male.jpg +0 -0
  95. package/dist/images/emperor-ui-logo.png +0 -0
  96. package/dist/index-BXtdEByK.js +0 -5
  97. package/dist/index-CDB93OLO.js +0 -55965
  98. package/dist/index-CYORMghp.js +0 -290
  99. package/dist/index.d.ts +0 -1090
  100. package/dist/src-UW24ZMRV-C1Pn8-w8.js +0 -5
  101. package/src/components/atoms/color-picker/styles/color-picker.css +0 -23
  102. package/src/components/atoms/field/field.stories.tsx +0 -27
  103. package/src/components/atoms/uploader/upload-file-error-box.tsx +0 -29
  104. package/src/components/organisms/filters/filters.stories.tsx +0 -32
  105. package/src/components/organisms/filters/filters.tsx +0 -36
  106. package/src/components/organisms/filters/index.ts +0 -1
  107. package/src/components/organisms/filters/styles/classes.ts +0 -9
  108. /package/src/components/atoms/uploader/{upload-file-input.tsx → components/upload-file-input.tsx} +0 -0
  109. /package/src/components/atoms/uploader/{upload-file-listing.tsx → components/upload-file-listing.tsx} +0 -0
  110. /package/src/components/atoms/uploader/{uploader-title.tsx → components/uploader-title.tsx} +0 -0
  111. /package/src/components/atoms/uploader/{uploader.tsx → components/uploader.tsx} +0 -0
  112. /package/src/components/atoms/uploader/{view-image-modal.tsx → components/view-image-modal.tsx} +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@js-empire/emperor-ui",
3
3
  "description": "They provide the atoms, we provide the empire.",
4
- "version": "1.2.5",
4
+ "version": "1.2.7",
5
5
  "author": "JS Empire - Mustafa Alhasanat",
6
6
  "license": "ISC",
7
7
  "type": "module",
@@ -73,6 +73,8 @@
73
73
  "@heroui/system": "^2.4.27",
74
74
  "@heroui/theme": "^2.4.25",
75
75
  "@heroui/toast": "^2.0.21",
76
+ "@heroui/tooltip": "^2.2.28",
77
+ "@hookform/resolvers": "^5.2.2",
76
78
  "@internationalized/date": "^3.11.0",
77
79
  "@storybook/react": "^10.1.8",
78
80
  "@tailwindcss/vite": "^4.1.17",
@@ -96,7 +98,8 @@
96
98
  "tailwindcss": "^4.1.17",
97
99
  "use-debounce": "^10.1.0",
98
100
  "vite-tsconfig-paths": "^5.1.4",
99
- "xlsx": "^0.18.5"
101
+ "xlsx": "^0.18.5",
102
+ "zod": "^4.3.6"
100
103
  },
101
104
  "devDependencies": {
102
105
  "@chromatic-com/storybook": "^4.1.3",
@@ -2,7 +2,6 @@
2
2
 
3
3
  import type { ColorPickerProps } from "@/types";
4
4
  import { FreeColorPicker, PresetColorPicker } from "@/components";
5
- import "./styles/color-picker.css";
6
5
 
7
6
  export function ColorPicker({ ...props }: ColorPickerProps) {
8
7
  if (props?.inputType === "preset") {
@@ -7,13 +7,12 @@ import type { ColorPickerProps } from "@/types";
7
7
  import { CopyButton } from "@/components";
8
8
  import { useEmperorUI } from "@/hooks";
9
9
 
10
- const HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;
11
-
12
10
  export function FreeColorPicker({
13
11
  className,
14
12
  classNames,
15
13
  value = "#000000",
16
- onValueChange,
14
+ onChange,
15
+ defaultValue,
17
16
  inputType = "free",
18
17
  ...props
19
18
  }: ColorPickerProps) {
@@ -26,12 +25,10 @@ export function FreeColorPicker({
26
25
 
27
26
  const isInvalid = useMemo(() => {
28
27
  if (!value) return true;
29
- return HEX_COLOR_REGEX.test(value);
30
- }, [value]);
28
+ const HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;
31
29
 
32
- const handleValueChange = (newValue: string) => {
33
- onValueChange?.(newValue);
34
- };
30
+ return !HEX_COLOR_REGEX.test(value);
31
+ }, [value]);
35
32
 
36
33
  return (
37
34
  <Input
@@ -39,8 +36,9 @@ export function FreeColorPicker({
39
36
  variant="faded"
40
37
  className={cn(className)}
41
38
  classNames={{ label: "font-bold", input: "h-12", ...classNames }}
39
+ defaultValue={defaultValue}
42
40
  value={value}
43
- onValueChange={handleValueChange}
41
+ onValueChange={onChange}
44
42
  isInvalid={isInvalid}
45
43
  errorMessage={isInvalid ? errorMessage : undefined}
46
44
  endContent={<CopyButton value={value} />}
@@ -50,7 +48,7 @@ export function FreeColorPicker({
50
48
  className="color-swatch"
51
49
  value={value}
52
50
  onChange={(e) => {
53
- handleValueChange(e.target.value);
51
+ onChange?.(e.target.value as string);
54
52
  }}
55
53
  />
56
54
  }
@@ -9,7 +9,8 @@ export function PresetColorPicker({
9
9
  className,
10
10
  classNames,
11
11
  value = "#000000",
12
- onSelectionChange,
12
+ onChange,
13
+ defaultValue,
13
14
  inputType,
14
15
  presets = [],
15
16
  ...props
@@ -30,8 +31,9 @@ export function PresetColorPicker({
30
31
  trigger: "min-w-52",
31
32
  ...classNames,
32
33
  }}
33
- value={value}
34
- onSelectionChange={onSelectionChange}
34
+ selectedKeys={value ? [value] : undefined}
35
+ defaultSelectedKeys={defaultValue ? [defaultValue] : undefined}
36
+ onSelectionChange={(value) => onChange?.(value?.currentKey ?? "")}
35
37
  endContent={<CopyButton value={value} />}
36
38
  renderValue={() => {
37
39
  return (
@@ -24,9 +24,21 @@ export default meta;
24
24
  type Story = StoryObj<typeof meta>;
25
25
 
26
26
  export const Default: Story = {
27
- render: (args) => {
27
+ render: () => {
28
28
  const [value, setValue] = useState("#000000");
29
- return <ColorPicker {...args} value={value} onValueChange={setValue} />;
29
+
30
+ return (
31
+ <section className="flex flex-col gap-4">
32
+ <ColorPicker
33
+ inputType="free"
34
+ value={value}
35
+ onChange={setValue}
36
+ defaultValue="#000000"
37
+ />
38
+
39
+ <p className="text-xs text-gray-500">Value: {value}</p>
40
+ </section>
41
+ );
30
42
  },
31
43
  };
32
44
 
@@ -35,15 +47,17 @@ export const WithPresets: Story = {
35
47
  const [value, setValue] = useState("#000000");
36
48
 
37
49
  return (
38
- <ColorPicker
39
- inputType="preset"
40
- presets={["#000000", "#FFFFFF", "#FF0000", "#00FF00", "#0000FF"]}
41
- value={value}
42
- onSelectionChange={(keys) => {
43
- setValue(keys?.currentKey ?? "");
44
- }}
45
- defaultSelectedKeys={["#000000"]}
46
- />
50
+ <section className="flex flex-col gap-4">
51
+ <ColorPicker
52
+ inputType="preset"
53
+ presets={["#000000", "#FFFFFF", "#FF0000", "#00FF00", "#0000FF"]}
54
+ value={value}
55
+ onChange={setValue}
56
+ defaultValue="#000000"
57
+ />
58
+
59
+ <p className="text-xs text-gray-500">Value: {value}</p>
60
+ </section>
47
61
  );
48
62
  },
49
63
  };
@@ -1,11 +1,81 @@
1
+ import {
2
+ AutocompleteField,
3
+ CheckboxField,
4
+ InputField,
5
+ RadioField,
6
+ SelectField,
7
+ SwitchField,
8
+ TextareaField,
9
+ fieldClasses,
10
+ } from "@/components";
11
+ import type { FieldProps, FieldType } from "@/types";
1
12
  import { cn } from "@/utils";
2
- import { FieldProps } from "@/types";
3
- import { fieldClasses } from "./styles";
13
+ import type { FieldValues } from "react-hook-form";
14
+ import type { ReactNode } from "react";
15
+
16
+ export function Field<TSchema extends FieldValues>({
17
+ className,
18
+ classNames,
19
+ name,
20
+ type,
21
+ inputProps,
22
+ textareaProps,
23
+ checkboxProps,
24
+ selectProps,
25
+ selectItemProps,
26
+ autocompleteProps,
27
+ autocompleteItemProps,
28
+ switchProps,
29
+ radioGroupProps,
30
+ options,
31
+ children,
32
+ }: FieldProps<TSchema>) {
33
+ const components: Record<FieldType, ReactNode> = {
34
+ input: <InputField<TSchema> name={name} inputProps={inputProps} />,
35
+ textarea: (
36
+ <TextareaField<TSchema> name={name} textareaProps={textareaProps} />
37
+ ),
38
+ checkbox: (
39
+ <CheckboxField<TSchema> name={name} checkboxProps={checkboxProps}>
40
+ {children}
41
+ </CheckboxField>
42
+ ),
43
+ select: (
44
+ <SelectField<TSchema>
45
+ name={name}
46
+ options={options}
47
+ selectProps={selectProps}
48
+ selectItemProps={selectItemProps}
49
+ />
50
+ ),
51
+ autocomplete: (
52
+ <AutocompleteField<TSchema>
53
+ name={name}
54
+ options={options}
55
+ autocompleteProps={autocompleteProps}
56
+ autocompleteItemProps={autocompleteItemProps}
57
+ />
58
+ ),
59
+ switch: (
60
+ <SwitchField<TSchema> name={name} switchProps={switchProps}>
61
+ {children}
62
+ </SwitchField>
63
+ ),
64
+ radio: (
65
+ <RadioField<TSchema>
66
+ name={name}
67
+ options={options}
68
+ radioGroupProps={radioGroupProps}
69
+ />
70
+ ),
71
+ };
4
72
 
5
- export function Field({ className, classNames, ...props }: FieldProps) {
6
73
  return (
7
- <div className={cn(fieldClasses({}), className)} {...props}>
8
- Sorter Component
74
+ <div
75
+ data-slot="emperor-ui-field"
76
+ className={cn(fieldClasses({}), className, classNames?.base)}
77
+ >
78
+ {components[type]}
9
79
  </div>
10
80
  );
11
81
  }
@@ -1 +1,3 @@
1
1
  export * from "./field";
2
+ export * from "./styles";
3
+ export * from "./units";
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ import type { FieldProps } from "@/types";
4
+ import { Controller, type FieldValues } from "react-hook-form";
5
+ import { Autocomplete, AutocompleteItem } from "@heroui/autocomplete";
6
+ import { useEmperorUI, useFormBuilder } from "@/hooks";
7
+
8
+ export function AutocompleteField<TSchema extends FieldValues>({
9
+ autocompleteItemProps,
10
+ autocompleteProps,
11
+ options,
12
+ name,
13
+ }: Pick<
14
+ FieldProps<TSchema>,
15
+ "autocompleteItemProps" | "autocompleteProps" | "options" | "name"
16
+ >) {
17
+ const { config } = useEmperorUI();
18
+
19
+ const theme = config?.theme?.components?.autocomplete;
20
+
21
+ if (!options?.length) {
22
+ throw new Error("Field with type 'autocomplete' must include 'options'.");
23
+ }
24
+
25
+ const { control } = useFormBuilder<TSchema>();
26
+
27
+ return (
28
+ <Controller
29
+ control={control}
30
+ name={name}
31
+ render={({ field }) => (
32
+ <Autocomplete
33
+ {...theme}
34
+ {...autocompleteProps}
35
+ selectedKey={field.value ? String(field.value) : null}
36
+ onSelectionChange={(selectedKey) =>
37
+ field.onChange(selectedKey ? String(selectedKey) : "")
38
+ }
39
+ >
40
+ {options.map((option) => (
41
+ <AutocompleteItem key={option.key} {...autocompleteItemProps}>
42
+ {option.label}
43
+ </AutocompleteItem>
44
+ ))}
45
+ </Autocomplete>
46
+ )}
47
+ />
48
+ );
49
+ }
@@ -0,0 +1,35 @@
1
+ "use client";
2
+
3
+ import type { FieldProps } from "@/types";
4
+ import { Controller, type FieldValues } from "react-hook-form";
5
+ import { Checkbox } from "@heroui/checkbox";
6
+ import { useEmperorUI, useFormBuilder } from "@/hooks";
7
+
8
+ export function CheckboxField<TSchema extends FieldValues>({
9
+ checkboxProps,
10
+ name,
11
+ children,
12
+ }: Pick<FieldProps<TSchema>, "checkboxProps" | "name" | "children">) {
13
+ const { config } = useEmperorUI();
14
+
15
+ const theme = config?.theme?.components?.checkbox;
16
+
17
+ const { control } = useFormBuilder<TSchema>();
18
+
19
+ return (
20
+ <Controller
21
+ control={control}
22
+ name={name}
23
+ render={({ field: { value, onChange } }) => (
24
+ <Checkbox
25
+ {...theme}
26
+ {...checkboxProps}
27
+ isSelected={Boolean(value)}
28
+ onValueChange={onChange}
29
+ >
30
+ {children}
31
+ </Checkbox>
32
+ )}
33
+ />
34
+ );
35
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./input-field";
2
+ export * from "./textarea-field";
3
+ export * from "./checkbox-field";
4
+ export * from "./select-field";
5
+ export * from "./autocomplete-field";
6
+ export * from "./switch-field";
7
+ export * from "./radio-field";
@@ -0,0 +1,35 @@
1
+ "use client";
2
+
3
+ import type { FieldProps } from "@/types";
4
+ import { Controller, type FieldValues } from "react-hook-form";
5
+ import { Input } from "@heroui/input";
6
+ import { useEmperorUI, useFormBuilder } from "@/hooks";
7
+
8
+ export function InputField<TSchema extends FieldValues>({
9
+ inputProps,
10
+ name,
11
+ }: Pick<FieldProps<TSchema>, "inputProps" | "name">) {
12
+ const { config } = useEmperorUI();
13
+
14
+ const theme = config?.theme?.components?.input;
15
+
16
+ const { control } = useFormBuilder<TSchema>();
17
+
18
+ return (
19
+ <Controller
20
+ control={control}
21
+ name={name}
22
+ render={({ field, fieldState }) => (
23
+ <Input
24
+ {...theme}
25
+ {...inputProps}
26
+ value={field.value ? String(field.value) : ""}
27
+ onBlur={field.onBlur}
28
+ onValueChange={field.onChange}
29
+ isInvalid={inputProps?.isInvalid ?? Boolean(fieldState.error)}
30
+ errorMessage={inputProps?.errorMessage ?? fieldState.error?.message}
31
+ />
32
+ )}
33
+ />
34
+ );
35
+ }
@@ -0,0 +1,43 @@
1
+ "use client";
2
+
3
+ import type { FieldProps } from "@/types";
4
+ import { Controller, type FieldValues } from "react-hook-form";
5
+ import { Radio, RadioGroup } from "@heroui/radio";
6
+ import { useEmperorUI, useFormBuilder } from "@/hooks";
7
+
8
+ export function RadioField<TSchema extends FieldValues>({
9
+ options,
10
+ radioGroupProps,
11
+ name,
12
+ }: Pick<FieldProps<TSchema>, "options" | "radioGroupProps" | "name">) {
13
+ const { config } = useEmperorUI();
14
+
15
+ const theme = config?.theme?.components?.radio;
16
+
17
+ const { control } = useFormBuilder<TSchema>();
18
+
19
+ if (!options?.length) {
20
+ throw new Error("Field with type 'radio' must include 'options'.");
21
+ }
22
+
23
+ return (
24
+ <Controller
25
+ control={control}
26
+ name={name}
27
+ render={({ field }) => (
28
+ <RadioGroup
29
+ {...theme}
30
+ {...radioGroupProps}
31
+ value={field.value ? String(field.value) : ""}
32
+ onValueChange={field.onChange}
33
+ >
34
+ {options.map((option) => (
35
+ <Radio key={option.key} value={option.key}>
36
+ {option.label}
37
+ </Radio>
38
+ ))}
39
+ </RadioGroup>
40
+ )}
41
+ />
42
+ );
43
+ }
@@ -0,0 +1,50 @@
1
+ "use client";
2
+
3
+ import type { FieldProps } from "@/types";
4
+ import { Controller, type FieldValues } from "react-hook-form";
5
+ import { Select, SelectItem } from "@heroui/select";
6
+ import { useEmperorUI, useFormBuilder } from "@/hooks";
7
+
8
+ export function SelectField<TSchema extends FieldValues>({
9
+ options,
10
+ selectItemProps,
11
+ selectProps,
12
+ name,
13
+ }: Pick<
14
+ FieldProps<TSchema>,
15
+ "options" | "selectItemProps" | "selectProps" | "name"
16
+ >) {
17
+ const { config } = useEmperorUI();
18
+
19
+ const theme = config?.theme?.components?.select;
20
+
21
+ if (!options?.length) {
22
+ throw new Error("Field with type 'select' must include 'options'.");
23
+ }
24
+
25
+ const { control } = useFormBuilder<TSchema>();
26
+
27
+ return (
28
+ <Controller
29
+ control={control}
30
+ name={name}
31
+ render={({ field }) => (
32
+ <Select
33
+ {...theme}
34
+ {...selectProps}
35
+ selectedKeys={field.value ? [String(field.value)] : []}
36
+ onSelectionChange={(keys) => {
37
+ const selectedKey = Array.from(keys)[0];
38
+ field.onChange(selectedKey ? String(selectedKey) : "");
39
+ }}
40
+ >
41
+ {options.map((option) => (
42
+ <SelectItem key={option.key} {...selectItemProps}>
43
+ {option.label}
44
+ </SelectItem>
45
+ ))}
46
+ </Select>
47
+ )}
48
+ />
49
+ );
50
+ }
@@ -0,0 +1,35 @@
1
+ "use client";
2
+
3
+ import type { FieldProps } from "@/types";
4
+ import { Controller, type FieldValues } from "react-hook-form";
5
+ import { Switch } from "@heroui/switch";
6
+ import { useEmperorUI, useFormBuilder } from "@/hooks";
7
+
8
+ export function SwitchField<TSchema extends FieldValues>({
9
+ switchProps,
10
+ name,
11
+ children,
12
+ }: Pick<FieldProps<TSchema>, "switchProps" | "name" | "children">) {
13
+ const { config } = useEmperorUI();
14
+
15
+ const theme = config?.theme?.components?.switch;
16
+
17
+ const { control } = useFormBuilder<TSchema>();
18
+
19
+ return (
20
+ <Controller
21
+ control={control}
22
+ name={name}
23
+ render={({ field }) => (
24
+ <Switch
25
+ {...theme}
26
+ {...switchProps}
27
+ isSelected={Boolean(field.value)}
28
+ onValueChange={field.onChange}
29
+ >
30
+ {children}
31
+ </Switch>
32
+ )}
33
+ />
34
+ );
35
+ }
@@ -0,0 +1,37 @@
1
+ "use client";
2
+
3
+ import type { FieldProps } from "@/types";
4
+ import { Controller, type FieldValues } from "react-hook-form";
5
+ import { Textarea } from "@heroui/input";
6
+ import { useEmperorUI, useFormBuilder } from "@/hooks";
7
+
8
+ export function TextareaField<TSchema extends FieldValues>({
9
+ textareaProps,
10
+ name,
11
+ }: Pick<FieldProps<TSchema>, "textareaProps" | "name">) {
12
+ const { config } = useEmperorUI();
13
+
14
+ const theme = config?.theme?.components?.textarea;
15
+
16
+ const { control } = useFormBuilder<TSchema>();
17
+
18
+ return (
19
+ <Controller
20
+ control={control}
21
+ name={name}
22
+ render={({ field, fieldState }) => (
23
+ <Textarea
24
+ {...theme}
25
+ {...textareaProps}
26
+ value={field.value ? String(field.value) : ""}
27
+ onBlur={field.onBlur}
28
+ onValueChange={field.onChange}
29
+ isInvalid={textareaProps?.isInvalid ?? Boolean(fieldState.error)}
30
+ errorMessage={
31
+ textareaProps?.errorMessage ?? fieldState.error?.message
32
+ }
33
+ />
34
+ )}
35
+ />
36
+ );
37
+ }
@@ -48,6 +48,7 @@ export function Filter({
48
48
  autocomplete: (
49
49
  <AutocompleteFilter
50
50
  autocompleteProps={autocompleteProps}
51
+ options={options}
51
52
  {...sharedProps}
52
53
  {...props}
53
54
  />
@@ -66,6 +67,7 @@ export function Filter({
66
67
  checkboxGroup: (
67
68
  <CheckboxGroupFilter
68
69
  checkboxGroupProps={checkboxGroupProps}
70
+ options={options}
69
71
  {...sharedProps}
70
72
  {...props}
71
73
  />
@@ -84,7 +86,6 @@ export function Filter({
84
86
  className,
85
87
  props?.classNames?.base,
86
88
  )}
87
- {...props}
88
89
  >
89
90
  {components[type]}
90
91
  </div>