@rovula/ui 0.0.28 → 0.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/cjs/bundle.css +40 -0
  2. package/dist/cjs/bundle.js +3 -3
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/DatePicker/DatePicker.d.ts +2 -1
  5. package/dist/cjs/types/components/DatePicker/DatePicker.stories.d.ts +720 -1
  6. package/dist/cjs/types/components/Dropdown/Dropdown.d.ts +2 -0
  7. package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +8 -0
  8. package/dist/cjs/types/components/InputFilter/InputFilter.d.ts +5 -0
  9. package/dist/cjs/types/components/InputFilter/InputFilter.stories.d.ts +334 -0
  10. package/dist/cjs/types/components/InputFilter/InputFilter.styles.d.ts +7 -0
  11. package/dist/cjs/types/components/Search/Search.d.ts +2 -20
  12. package/dist/cjs/types/components/Search/Search.stories.d.ts +20 -38
  13. package/dist/cjs/types/components/TextInput/TextInput.d.ts +10 -0
  14. package/dist/cjs/types/components/TextInput/TextInput.stories.d.ts +10 -0
  15. package/dist/cjs/types/components/TextInput/TextInput.styles.d.ts +1 -0
  16. package/dist/cjs/types/index.d.ts +1 -0
  17. package/dist/components/DatePicker/DatePicker.js +16 -3
  18. package/dist/components/Dropdown/Dropdown.js +26 -15
  19. package/dist/components/Dropdown/Dropdown.stories.js +1 -0
  20. package/dist/components/InputFilter/InputFilter.js +18 -0
  21. package/dist/components/InputFilter/InputFilter.stories.js +33 -0
  22. package/dist/components/InputFilter/InputFilter.styles.js +60 -0
  23. package/dist/components/Search/Search.js +1 -1
  24. package/dist/components/TextInput/TextInput.js +22 -6
  25. package/dist/components/TextInput/TextInput.styles.js +84 -11
  26. package/dist/esm/bundle.css +40 -0
  27. package/dist/esm/bundle.js +3 -3
  28. package/dist/esm/bundle.js.map +1 -1
  29. package/dist/esm/types/components/DatePicker/DatePicker.d.ts +2 -1
  30. package/dist/esm/types/components/DatePicker/DatePicker.stories.d.ts +720 -1
  31. package/dist/esm/types/components/Dropdown/Dropdown.d.ts +2 -0
  32. package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +8 -0
  33. package/dist/esm/types/components/InputFilter/InputFilter.d.ts +5 -0
  34. package/dist/esm/types/components/InputFilter/InputFilter.stories.d.ts +334 -0
  35. package/dist/esm/types/components/InputFilter/InputFilter.styles.d.ts +7 -0
  36. package/dist/esm/types/components/Search/Search.d.ts +2 -20
  37. package/dist/esm/types/components/Search/Search.stories.d.ts +20 -38
  38. package/dist/esm/types/components/TextInput/TextInput.d.ts +10 -0
  39. package/dist/esm/types/components/TextInput/TextInput.stories.d.ts +10 -0
  40. package/dist/esm/types/components/TextInput/TextInput.styles.d.ts +1 -0
  41. package/dist/esm/types/index.d.ts +1 -0
  42. package/dist/index.d.ts +19 -22
  43. package/dist/index.js +1 -0
  44. package/dist/src/theme/global.css +65 -0
  45. package/dist/theme/tokens/components/action-button.css +13 -0
  46. package/package.json +1 -1
  47. package/src/components/DatePicker/DatePicker.tsx +8 -3
  48. package/src/components/Dropdown/Dropdown.stories.tsx +1 -0
  49. package/src/components/Dropdown/Dropdown.tsx +51 -34
  50. package/src/components/InputFilter/InputFilter.stories.tsx +71 -0
  51. package/src/components/InputFilter/InputFilter.styles.ts +69 -0
  52. package/src/components/InputFilter/InputFilter.tsx +55 -0
  53. package/src/components/Search/Search.stories.tsx +1 -1
  54. package/src/components/Search/Search.tsx +13 -2
  55. package/src/components/TextInput/TextInput.styles.ts +84 -11
  56. package/src/components/TextInput/TextInput.tsx +51 -10
  57. package/src/index.ts +1 -0
  58. package/src/theme/tokens/components/action-button.css +13 -0
package/dist/index.d.ts CHANGED
@@ -55,12 +55,17 @@ type InputProps = {
55
55
  disabled?: boolean;
56
56
  error?: boolean;
57
57
  required?: boolean;
58
+ isFloatingLabel?: boolean;
59
+ keepCloseIconOnValue?: boolean;
58
60
  hasClearIcon?: boolean;
59
61
  hasSearchIcon?: boolean;
60
62
  startIcon?: ReactNode;
61
63
  endIcon?: ReactNode;
62
64
  className?: string;
63
65
  labelClassName?: string;
66
+ onClickStartIcon?: () => void;
67
+ onClickEndIcon?: () => void;
68
+ renderEndIcon?: () => ReactNode;
64
69
  } & Omit<React__default.InputHTMLAttributes<HTMLInputElement>, "size">;
65
70
  declare const TextInput: React__default.ForwardRefExoticComponent<{
66
71
  id?: string | undefined;
@@ -75,12 +80,17 @@ declare const TextInput: React__default.ForwardRefExoticComponent<{
75
80
  disabled?: boolean | undefined;
76
81
  error?: boolean | undefined;
77
82
  required?: boolean | undefined;
83
+ isFloatingLabel?: boolean | undefined;
84
+ keepCloseIconOnValue?: boolean | undefined;
78
85
  hasClearIcon?: boolean | undefined;
79
86
  hasSearchIcon?: boolean | undefined;
80
87
  startIcon?: ReactNode;
81
88
  endIcon?: ReactNode;
82
89
  className?: string | undefined;
83
90
  labelClassName?: string | undefined;
91
+ onClickStartIcon?: (() => void) | undefined;
92
+ onClickEndIcon?: (() => void) | undefined;
93
+ renderEndIcon?: (() => ReactNode) | undefined;
84
94
  } & Omit<React__default.InputHTMLAttributes<HTMLInputElement>, "size"> & React__default.RefAttributes<HTMLInputElement>>;
85
95
 
86
96
  type TextProps = {
@@ -144,6 +154,7 @@ type DropdownProps = {
144
154
  value?: Options;
145
155
  onChangeText?: InputProps["onChange"];
146
156
  onSelect?: (value: Options) => void;
157
+ renderOptions?: (optionsFiltered: Options[]) => ReactNode;
147
158
  } & Omit<InputProps, "value">;
148
159
  declare const Dropdown: React__default.ForwardRefExoticComponent<{
149
160
  id?: string | undefined;
@@ -163,6 +174,7 @@ declare const Dropdown: React__default.ForwardRefExoticComponent<{
163
174
  value?: Options | undefined;
164
175
  onChangeText?: InputProps["onChange"];
165
176
  onSelect?: ((value: Options) => void) | undefined;
177
+ renderOptions?: ((optionsFiltered: Options[]) => ReactNode) | undefined;
166
178
  } & Omit<InputProps, "value"> & React__default.RefAttributes<HTMLInputElement>>;
167
179
 
168
180
  declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxPrimitive.CheckboxProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
@@ -281,7 +293,7 @@ type DatePickerProps = {
281
293
  date: Date | undefined;
282
294
  onSelect: (selected: Date | undefined, triggerDate: Date, modifiers: Modifiers, e: React__default.MouseEvent | React__default.KeyboardEvent) => void | undefined;
283
295
  textInputProps?: Partial<InputProps>;
284
- };
296
+ } & React__default.ComponentPropsWithoutRef<typeof Calendar>;
285
297
  declare const DatePicker: FC<DatePickerProps>;
286
298
 
287
299
  declare const Popover: React.FC<PopoverPrimitive.PopoverProps>;
@@ -378,26 +390,11 @@ declare const AlertDialogDescription: React.ForwardRefExoticComponent<Omit<Alert
378
390
  declare const AlertDialogAction: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogActionProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
379
391
  declare const AlertDialogCancel: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogCancelProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
380
392
 
381
- type SearchProps = DropdownProps;
382
- declare const Search: React__default.ForwardRefExoticComponent<{
383
- id?: string | undefined;
384
- label?: string | undefined;
385
- size?: "sm" | "md" | "lg" | undefined;
386
- rounded?: "none" | "normal" | "full" | undefined;
387
- variant?: "outline" | "flat" | "underline" | undefined;
388
- helperText?: string | undefined;
389
- errorMessage?: string | undefined;
390
- filterMode?: boolean | undefined;
391
- fullwidth?: boolean | undefined;
392
- disabled?: boolean | undefined;
393
- error?: boolean | undefined;
394
- required?: boolean | undefined;
395
- className?: string | undefined;
396
- options: Options[];
397
- value?: Options | undefined;
398
- onChangeText?: React__default.ChangeEventHandler<HTMLInputElement> | undefined;
399
- onSelect?: ((value: Options) => void) | undefined;
400
- } & Omit<InputProps, "value"> & React__default.RefAttributes<HTMLInputElement>>;
393
+ type SearchProps = Omit<DropdownProps, "isFloatingLabel" | "keepCloseIconOnValue" | "hasClearIcon" | "hasSearchIcon" | "endIcon" | "filterMode" | "isFloatingLabel">;
394
+ declare const Search: React__default.ForwardRefExoticComponent<SearchProps & React__default.RefAttributes<HTMLInputElement>>;
395
+
396
+ type InputFilterProps = Omit<DropdownProps, "isFloatingLabel" | "keepCloseIconOnValue" | "hasClearIcon" | "hasSearchIcon" | "endIcon" | "filterMode" | "isFloatingLabel">;
397
+ declare const InputFilter: React__default.ForwardRefExoticComponent<InputFilterProps & React__default.RefAttributes<HTMLInputElement>>;
401
398
 
402
399
  declare const Slider: React.ForwardRefExoticComponent<Omit<SliderPrimitive.SliderProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
403
400
  type SliderProps = React.ComponentProps<typeof Slider>;
@@ -527,4 +524,4 @@ declare const getTimestampUTC: (date: Date) => number;
527
524
 
528
525
  declare function cn(...inputs: ClassValue[]): string;
529
526
 
530
- export { ActionButton, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Button, type ButtonProps, Calendar, Checkbox, Collapsible, DataTable, type DataTableProps, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Dropdown, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type DropdownProps, Icon, Input, type InputProps, Label, Loading, Navbar, type NavbarProps, type Options, Popover, PopoverContent, PopoverTrigger, ProgressBar, Search, type SearchProps, Slider, type SliderProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, Text, TextInput, Toast$1 as Toast, ToastAction, type ToastActionElement, ToastClose, ToastDescription, type ToastProps, ToastProvider, ToastTitle, ToastViewport, Toaster, Tooltip, TooltipArrow, TooltipContent, TooltipProvider, TooltipSimple, TooltipTrigger, cn, getEndDateOfDay, getStartDateOfDay, getStartEndTimestampOfDay, getTimestampUTC, reducer, resloveTimestamp, toast, useToast };
527
+ export { ActionButton, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Button, type ButtonProps, Calendar, Checkbox, Collapsible, DataTable, type DataTableProps, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Dropdown, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type DropdownProps, Icon, Input, InputFilter, type InputFilterProps, type InputProps, Label, Loading, Navbar, type NavbarProps, type Options, Popover, PopoverContent, PopoverTrigger, ProgressBar, Search, type SearchProps, Slider, type SliderProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, Text, TextInput, Toast$1 as Toast, ToastAction, type ToastActionElement, ToastClose, ToastDescription, type ToastProps, ToastProvider, ToastTitle, ToastViewport, Toaster, Tooltip, TooltipArrow, TooltipContent, TooltipProvider, TooltipSimple, TooltipTrigger, cn, getEndDateOfDay, getStartDateOfDay, getStartEndTimestampOfDay, getTimestampUTC, reducer, resloveTimestamp, toast, useToast };
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ export * from "./components/DataTable/DataTable";
25
25
  export * from "./components/Dialog/Dialog";
26
26
  export * from "./components/AlertDialog/AlertDialog";
27
27
  export * from "./components/Search/Search";
28
+ export * from "./components/InputFilter/InputFilter";
28
29
  export * from "./components/Slider/Slider";
29
30
  export * from "./components/Switch/Switch";
30
31
  export * from "./components/DropdownMenu/DropdownMenu";
@@ -953,6 +953,18 @@
953
953
  /* ------------------------------------------------------------------ */
954
954
  /* Solid Mode Tokens */
955
955
  /* ------------------------------------------------------------------ */
956
+ /* TODO */
957
+ --function-default-solid: #ececec;
958
+ --function-default-hover: #fafafa;
959
+ --function-default-hover-bg: rgba(250 250 250 / 0.08);
960
+ --function-default-stroke: rgba(158 158 158 / 0.24);
961
+ --function-default-icon: #212b36;
962
+ --function-default-outline-icon: #9e9e9e;
963
+ --function-active-solid: #b1a400;
964
+ --function-active-hover: #ddcd00;
965
+ --function-active-hover-bg: rgba(221 205 0 / 0.08);
966
+ --function-active-stroke: rgba(177 164 0 / 0.48);
967
+ --function-active-icon: #212b36;
956
968
  /* Default State */
957
969
  --action-button-solid-default-bg: var(--state-color-primary-default);
958
970
  --action-button-solid-default-border: var(--state-color-primary-default);
@@ -3215,6 +3227,11 @@ body {
3215
3227
  background-color: color-mix(in srgb, var(--background) calc(100% * var(--tw-bg-opacity)), transparent);
3216
3228
  }
3217
3229
 
3230
+ .bg-base-bg2 {
3231
+ --tw-bg-opacity: 1;
3232
+ background-color: color-mix(in srgb, var(--base-color-bg2) calc(100% * var(--tw-bg-opacity)), transparent);
3233
+ }
3234
+
3218
3235
  .bg-base-popup {
3219
3236
  --tw-bg-opacity: 1;
3220
3237
  background-color: color-mix(in srgb, var(--base-color-popup) calc(100% * var(--tw-bg-opacity)), transparent);
@@ -3583,6 +3600,18 @@ body {
3583
3600
  fill: color-mix(in srgb, var(--state-color-primary-default) calc(100% * 1), transparent);
3584
3601
  }
3585
3602
 
3603
+ .fill-primary-default {
3604
+ fill: color-mix(in srgb, var(--state-color-primary-default) calc(100% * 1), transparent);
3605
+ }
3606
+
3607
+ .stroke-input-default-stroke {
3608
+ stroke: color-mix(in srgb, var(--input-color-default-stroke) calc(100% * 1), transparent);
3609
+ }
3610
+
3611
+ .stroke-primary-default {
3612
+ stroke: color-mix(in srgb, var(--state-color-primary-default) calc(100% * 1), transparent);
3613
+ }
3614
+
3586
3615
  .p-0 {
3587
3616
  padding: 0px;
3588
3617
  }
@@ -6392,6 +6421,14 @@ body {
6392
6421
  top: 1rem;
6393
6422
  }
6394
6423
 
6424
+ .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:block {
6425
+ display: block;
6426
+ }
6427
+
6428
+ .peer:placeholder-shown ~ .peer-placeholder-shown\:block {
6429
+ display: block;
6430
+ }
6431
+
6395
6432
  .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:bg-transparent {
6396
6433
  background-color: transparent;
6397
6434
  }
@@ -6445,6 +6482,18 @@ body {
6445
6482
  fill: color-mix(in srgb, var(--input-color-filled-text) calc(100% * 1), transparent);
6446
6483
  }
6447
6484
 
6485
+ .peer:hover ~ .peer-hover\:fill-primary-default {
6486
+ fill: color-mix(in srgb, var(--state-color-primary-default) calc(100% * 1), transparent);
6487
+ }
6488
+
6489
+ .peer:hover ~ .peer-hover\:stroke-input-active-stroke {
6490
+ stroke: color-mix(in srgb, var(--input-color-active-stroke) calc(100% * 1), transparent);
6491
+ }
6492
+
6493
+ .peer:hover ~ .peer-hover\:stroke-primary-default {
6494
+ stroke: color-mix(in srgb, var(--state-color-primary-default) calc(100% * 1), transparent);
6495
+ }
6496
+
6448
6497
  .peer:focus ~ .peer-focus\:-top-1 {
6449
6498
  top: -0.25rem;
6450
6499
  }
@@ -6472,10 +6521,26 @@ body {
6472
6521
  background-color: rgb(239 68 68 / var(--tw-bg-opacity));
6473
6522
  }
6474
6523
 
6524
+ .peer:focus ~ .peer-focus\:bg-transparent {
6525
+ background-color: transparent;
6526
+ }
6527
+
6475
6528
  .peer:focus ~ .peer-focus\:fill-input-filled-text {
6476
6529
  fill: color-mix(in srgb, var(--input-color-filled-text) calc(100% * 1), transparent);
6477
6530
  }
6478
6531
 
6532
+ .peer:focus ~ .peer-focus\:fill-primary-hover {
6533
+ fill: color-mix(in srgb, var(--state-color-primary-hover) calc(100% * 1), transparent);
6534
+ }
6535
+
6536
+ .peer:focus ~ .peer-focus\:stroke-input-filled-text {
6537
+ stroke: color-mix(in srgb, var(--input-color-filled-text) calc(100% * 1), transparent);
6538
+ }
6539
+
6540
+ .peer:focus ~ .peer-focus\:stroke-primary-hover {
6541
+ stroke: color-mix(in srgb, var(--state-color-primary-hover) calc(100% * 1), transparent);
6542
+ }
6543
+
6479
6544
  .peer:focus ~ .peer-focus\:text-input-filled-text {
6480
6545
  --tw-text-opacity: 1;
6481
6546
  color: color-mix(in srgb, var(--input-color-filled-text) calc(100% * var(--tw-text-opacity)), transparent);
@@ -11,6 +11,19 @@
11
11
  /* Solid Mode Tokens */
12
12
  /* ------------------------------------------------------------------ */
13
13
 
14
+ /* TODO */
15
+ --function-default-solid: #ececec;
16
+ --function-default-hover: #fafafa;
17
+ --function-default-hover-bg: rgba(250 250 250 / 0.08);
18
+ --function-default-stroke: rgba(158 158 158 / 0.24);
19
+ --function-default-icon: #212b36;
20
+ --function-default-outline-icon: #9e9e9e;
21
+ --function-active-solid: #b1a400;
22
+ --function-active-hover: #ddcd00;
23
+ --function-active-hover-bg: rgba(221 205 0 / 0.08);
24
+ --function-active-stroke: rgba(177 164 0 / 0.48);
25
+ --function-active-icon: #212b36;
26
+
14
27
  /* Default State */
15
28
  --action-button-solid-default-bg: var(--state-color-primary-default);
16
29
  --action-button-solid-default-border: var(--state-color-primary-default);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rovula/ui",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
4
4
  "main": "dist/cjs/bundle.js",
5
5
  "module": "dist/esm/bundle.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,12 +18,13 @@ type DatePickerProps = {
18
18
  e: React.MouseEvent | React.KeyboardEvent
19
19
  ) => void | undefined;
20
20
  textInputProps?: Partial<InputProps>;
21
- };
21
+ } & React.ComponentPropsWithoutRef<typeof Calendar>;
22
22
 
23
23
  const DatePicker: FC<DatePickerProps> = ({
24
24
  date,
25
25
  onSelect,
26
26
  textInputProps,
27
+ ...props
27
28
  }) => {
28
29
  const [isOpen, setIsOpen] = useState(false);
29
30
 
@@ -34,19 +35,23 @@ const DatePicker: FC<DatePickerProps> = ({
34
35
  <div className="flex">
35
36
  <TextInput
36
37
  fullwidth
37
- id="2"
38
+ id="2" // TODO
38
39
  readOnly
39
40
  label="Date"
40
41
  size="md"
41
42
  value={date ? format(date, "dd MMM yyyy") : isOpen ? " " : ""}
42
43
  hasClearIcon={false}
43
- endIcon={<CalendarIcon fill="inherit" />}
44
+ endIcon={
45
+ <CalendarIcon fill="inherit" className="cursor-pointer" />
46
+ }
44
47
  {...textInputProps}
45
48
  />
46
49
  </div>
47
50
  </PopoverTrigger>
48
51
  <PopoverContent className="w-auto p-0">
49
52
  <Calendar
53
+ defaultMonth={date}
54
+ {...props}
50
55
  mode="single"
51
56
  selected={date}
52
57
  onSelect={(...value) => {
@@ -33,6 +33,7 @@ export const Default = {
33
33
  args: {
34
34
  label: "Choose an option:",
35
35
  fullwidth: true,
36
+ isFloatingLabel: true,
36
37
  options,
37
38
  },
38
39
  render: (args) => {
@@ -49,6 +49,7 @@ export type DropdownProps = {
49
49
  value?: Options;
50
50
  onChangeText?: InputProps["onChange"];
51
51
  onSelect?: (value: Options) => void;
52
+ renderOptions?: (optionsFiltered: Options[]) => ReactNode;
52
53
  } & Omit<InputProps, "value">;
53
54
 
54
55
  const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
@@ -70,6 +71,7 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
70
71
  required = true,
71
72
  onChangeText,
72
73
  onSelect,
74
+ renderOptions: customRenderOptions,
73
75
  ...props
74
76
  },
75
77
  ref
@@ -86,6 +88,7 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
86
88
  useEffect(() => {
87
89
  if (value && !selectedOption) {
88
90
  setSelectedOption(value);
91
+ setTextValue(value.label);
89
92
  }
90
93
  }, [value, selectedOption]);
91
94
 
@@ -93,6 +96,10 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
93
96
  (event: React.ChangeEvent<HTMLInputElement>) => {
94
97
  onChangeText?.(event);
95
98
  setTextValue(event.target.value);
99
+
100
+ if (!event.target.value) {
101
+ clearMismatchValue(event as any);
102
+ }
96
103
  },
97
104
  [onChangeText]
98
105
  );
@@ -114,42 +121,52 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
114
121
  );
115
122
  }, [options, filterMode, textValue]);
116
123
 
117
- const renderOptions = () => (
118
- <ul className="absolute mt-1 w-full bg-base-popup border border-base-popup text-base-popup-foreground rounded-md shadow-md z-10 max-h-60 overflow-y-auto">
119
- {optionsFiltered.map((option) => {
120
- if (option.renderLabel) {
124
+ const renderOptions = () => {
125
+ if (customRenderOptions) {
126
+ return customRenderOptions(optionsFiltered);
127
+ }
128
+
129
+ return (
130
+ <ul className="absolute mt-1 w-full bg-base-popup border border-base-popup text-base-popup-foreground rounded-md shadow-md z-10 max-h-60 overflow-y-auto">
131
+ {optionsFiltered.map((option) => {
132
+ if (option.renderLabel) {
133
+ return (
134
+ <Fragment key={option.value}>
135
+ {option.renderLabel({
136
+ value: option.value,
137
+ label: option.label,
138
+ handleOnClick: () => handleOptionClick(option),
139
+ className: `px-4 py-2 hover:bg-gray-100 cursor-pointer ${
140
+ selectedOption?.value === option.value
141
+ ? " bg-gray-200"
142
+ : ""
143
+ }`,
144
+ })}
145
+ </Fragment>
146
+ );
147
+ }
121
148
  return (
122
- <Fragment key={option.value}>
123
- {option.renderLabel({
124
- value: option.value,
125
- label: option.label,
126
- handleOnClick: () => handleOptionClick(option),
127
- className: `px-4 py-2 hover:bg-gray-100 cursor-pointer ${
128
- selectedOption?.value === option.value ? " bg-gray-200" : ""
129
- }`,
130
- })}
131
- </Fragment>
149
+ <li
150
+ key={option.value}
151
+ onMouseDown={() => handleOptionClick(option)}
152
+ className={`px-4 py-2 hover:bg-primary-hover-bg cursor-pointer ${
153
+ selectedOption?.value === option.value
154
+ ? "bg-base-popup-highligh"
155
+ : ""
156
+ }`}
157
+ >
158
+ {option.label}
159
+ </li>
132
160
  );
133
- }
134
- return (
135
- <li
136
- key={option.value}
137
- onMouseDown={() => handleOptionClick(option)}
138
- className={`px-4 py-2 hover:bg-primary-hover-bg cursor-pointer ${
139
- selectedOption?.value === option.value
140
- ? "bg-base-popup-highligh"
141
- : ""
142
- }`}
143
- >
144
- {option.label}
161
+ })}
162
+ {optionsFiltered.length === 0 && (
163
+ <li className="px-4 py-14 text-center text-input-text">
164
+ Not found
145
165
  </li>
146
- );
147
- })}
148
- {optionsFiltered.length === 0 && (
149
- <li className="px-4 py-14 text-center text-input-text">Not found</li>
150
- )}
151
- </ul>
152
- );
166
+ )}
167
+ </ul>
168
+ );
169
+ };
153
170
 
154
171
  const handleOnFocus = useCallback(
155
172
  (e: React.FocusEvent<HTMLInputElement, Element>) => {
@@ -196,7 +213,7 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
196
213
  clearMismatchValue(e);
197
214
  props?.onBlur?.(e);
198
215
  },
199
- [props?.onBlur]
216
+ [props?.onBlur, clearMismatchValue]
200
217
  );
201
218
 
202
219
  const handleOnKeyDown = useCallback(
@@ -0,0 +1,71 @@
1
+ import React, { useState } from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import { InputFilter } from "./InputFilter";
4
+ import { Options } from "../Dropdown/Dropdown";
5
+
6
+ const meta = {
7
+ title: "Components/InputFilter",
8
+ component: InputFilter,
9
+ tags: ["autodocs"],
10
+ parameters: {
11
+ layout: "fullscreen",
12
+ },
13
+ decorators: [
14
+ (Story) => (
15
+ <div className="p-5 flex w-full bg-base-bg2">
16
+ <Story />
17
+ </div>
18
+ ),
19
+ ],
20
+ } satisfies Meta<typeof InputFilter>;
21
+
22
+ export default meta;
23
+
24
+ const options: Options[] = new Array(100).fill("").map((__, index) => ({
25
+ value: `option${index + 1}`,
26
+ label: `Option ${index + 1}`,
27
+ }));
28
+
29
+ export const Default = {
30
+ args: {
31
+ label: "Choose an option:",
32
+ fullwidth: true,
33
+ options,
34
+ },
35
+ render: (args) => {
36
+ const [value, setValue] = useState();
37
+
38
+ const handleOnSelect = (e: any) => {
39
+ setValue(e);
40
+ };
41
+
42
+ return (
43
+ <div className="flex flex-row gap-4 w-full">
44
+ <InputFilter
45
+ id="1"
46
+ size="lg"
47
+ options={options}
48
+ value={value}
49
+ onSelect={handleOnSelect}
50
+ {...args}
51
+ />
52
+ <InputFilter
53
+ id="2"
54
+ size="md"
55
+ options={options}
56
+ value={value}
57
+ onSelect={handleOnSelect}
58
+ {...args}
59
+ />
60
+ <InputFilter
61
+ id="3"
62
+ size="sm"
63
+ options={options}
64
+ value={value}
65
+ onSelect={handleOnSelect}
66
+ {...args}
67
+ />
68
+ </div>
69
+ );
70
+ },
71
+ } satisfies StoryObj;
@@ -0,0 +1,69 @@
1
+ import React from "react";
2
+ import { cva } from "class-variance-authority";
3
+
4
+ export const filterIconVariant = cva(
5
+ [
6
+ // Base styles
7
+ "absolute flex items-center justify-center cursor-pointer",
8
+
9
+ // Border styles
10
+ "border-l border-l-input-default-stroke",
11
+ "peer-hover:border-l-input-active-stroke",
12
+ "peer-focus:border-l-input-active-stroke",
13
+ "peer-disabled:border-l-input-disable-stroke",
14
+
15
+ // Fill styles
16
+ "fill-primary",
17
+ "peer-hover:fill-input-filled-text",
18
+ "peer-focus:fill-input-filled-text",
19
+ "peer-disabled:fill-input-disable-stroke",
20
+
21
+ // Stroke styles
22
+ "stroke-input-default-stroke",
23
+ "peer-hover:stroke-input-active-stroke",
24
+ "peer-focus:stroke-input-filled-text",
25
+ ],
26
+ {
27
+ variants: {
28
+ size: {
29
+ sm: "p-1 size-[30px]",
30
+ md: "p-2 size-[38px]",
31
+ lg: "p-3 size-14",
32
+ },
33
+ rounded: {
34
+ none: "rounded-r-none",
35
+ normal: "rounded-r-xl",
36
+ full: "rounded-r-full",
37
+ },
38
+ error: {
39
+ true: "border-l-input-error",
40
+ },
41
+ position: {
42
+ start: "inset-y-0 left-0",
43
+ end: "inset-y-0 right-0",
44
+ },
45
+ active: {
46
+ false: "",
47
+ true: [
48
+ // Fill styles
49
+ "fill-primary-default",
50
+ "peer-hover:fill-primary-default", // TODO wait for refactor color after change function button colors
51
+ "peer-focus:fill-primary-hover", // TODO wait for refactor color after change function button colors
52
+ // "peer-disabled:fill-input-disable-stroke",
53
+
54
+ // Stroke styles
55
+ "stroke-primary-default",
56
+ "peer-hover:stroke-primary-default",
57
+ "peer-focus:stroke-primary-hover",
58
+ ],
59
+ },
60
+ },
61
+ defaultVariants: {
62
+ size: "md",
63
+ rounded: "normal",
64
+ error: false,
65
+ position: "end",
66
+ active: false,
67
+ },
68
+ }
69
+ );
@@ -0,0 +1,55 @@
1
+ import React, { forwardRef } from "react";
2
+ import Dropdown, { DropdownProps } from "../Dropdown/Dropdown";
3
+ import Icon from "../Icon/Icon";
4
+ import { filterIconVariant } from "./InputFilter.styles";
5
+ import { AdjustmentsHorizontalIcon } from "@heroicons/react/16/solid";
6
+
7
+ export type InputFilterProps = Omit<
8
+ DropdownProps,
9
+ | "isFloatingLabel"
10
+ | "keepCloseIconOnValue"
11
+ | "hasClearIcon"
12
+ | "hasSearchIcon"
13
+ | "endIcon"
14
+ | "filterMode"
15
+ | "isFloatingLabel"
16
+ >;
17
+
18
+ const InputFilter = forwardRef<HTMLInputElement, InputFilterProps>(
19
+ (props, ref) => {
20
+ const filterIconClassName = filterIconVariant({
21
+ size: props.size,
22
+ rounded: props.rounded,
23
+ error: props.error,
24
+ active: !!props.value?.value,
25
+ });
26
+
27
+ return (
28
+ <Dropdown
29
+ label="Placeholder Text"
30
+ required={false}
31
+ {...props}
32
+ ref={ref}
33
+ renderEndIcon={() => (
34
+ <div className={filterIconClassName}>
35
+ <Icon
36
+ type="heroicons"
37
+ name="adjustments-horizontal"
38
+ variant="outline"
39
+ color="inherit"
40
+ stroke="inherit"
41
+ fill="transparent"
42
+ />
43
+ </div>
44
+ )}
45
+ renderOptions={(optionsFiltered) => {
46
+ return "";
47
+ }}
48
+ filterMode
49
+ isFloatingLabel={false}
50
+ />
51
+ );
52
+ }
53
+ );
54
+
55
+ export { InputFilter };
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useState } from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
  import { Search } from "./Search";
4
4
  import { Options } from "../Dropdown/Dropdown";
@@ -1,18 +1,29 @@
1
1
  import React, { forwardRef } from "react";
2
2
  import Dropdown, { DropdownProps } from "../Dropdown/Dropdown";
3
3
 
4
- export type SearchProps = DropdownProps;
4
+ export type SearchProps = Omit<
5
+ DropdownProps,
6
+ | "isFloatingLabel"
7
+ | "keepCloseIconOnValue"
8
+ | "hasClearIcon"
9
+ | "hasSearchIcon"
10
+ | "endIcon"
11
+ | "filterMode"
12
+ | "isFloatingLabel"
13
+ >;
5
14
 
6
15
  const Search = forwardRef<HTMLInputElement, SearchProps>((props, ref) => {
7
16
  return (
8
17
  <Dropdown
18
+ label="Search"
9
19
  {...props}
10
20
  ref={ref}
21
+ keepCloseIconOnValue
11
22
  hasClearIcon
12
23
  hasSearchIcon
13
- label="Search"
14
24
  endIcon={null}
15
25
  filterMode
26
+ isFloatingLabel={false}
16
27
  />
17
28
  );
18
29
  });