@rovula/ui 0.0.7 → 0.0.9

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 (37) hide show
  1. package/dist/cjs/bundle.css +136 -33
  2. package/dist/cjs/bundle.js +1 -1
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/Dropdown/Dropdown.d.ts +26 -0
  5. package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +367 -0
  6. package/dist/cjs/types/components/Dropdown/Dropdown.styles.d.ts +11 -0
  7. package/dist/cjs/types/components/TextInput/TextInput.d.ts +3 -2
  8. package/dist/cjs/types/components/TextInput/TextInput.stories.d.ts +2 -16
  9. package/dist/cjs/types/components/TextInput/TextInput.styles.d.ts +0 -1
  10. package/dist/cjs/types/index.d.ts +1 -0
  11. package/dist/components/Dropdown/Dropdown.js +58 -0
  12. package/dist/components/Dropdown/Dropdown.stories.js +43 -0
  13. package/dist/components/Dropdown/Dropdown.styles.js +47 -0
  14. package/dist/components/TextInput/TextInput.js +3 -5
  15. package/dist/components/TextInput/TextInput.stories.js +1 -1
  16. package/dist/components/TextInput/TextInput.styles.js +13 -21
  17. package/dist/esm/bundle.css +136 -33
  18. package/dist/esm/bundle.js +1 -1
  19. package/dist/esm/bundle.js.map +1 -1
  20. package/dist/esm/types/components/Dropdown/Dropdown.d.ts +26 -0
  21. package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +367 -0
  22. package/dist/esm/types/components/Dropdown/Dropdown.styles.d.ts +11 -0
  23. package/dist/esm/types/components/TextInput/TextInput.d.ts +3 -2
  24. package/dist/esm/types/components/TextInput/TextInput.stories.d.ts +2 -16
  25. package/dist/esm/types/components/TextInput/TextInput.styles.d.ts +0 -1
  26. package/dist/esm/types/index.d.ts +1 -0
  27. package/dist/index.d.ts +29 -2
  28. package/dist/index.js +1 -0
  29. package/dist/src/theme/global.css +170 -38
  30. package/package.json +1 -1
  31. package/src/components/Dropdown/Dropdown.stories.tsx +49 -0
  32. package/src/components/Dropdown/Dropdown.styles.ts +54 -0
  33. package/src/components/Dropdown/Dropdown.tsx +151 -0
  34. package/src/components/TextInput/TextInput.stories.tsx +3 -3
  35. package/src/components/TextInput/TextInput.styles.ts +13 -21
  36. package/src/components/TextInput/TextInput.tsx +14 -5
  37. package/src/index.ts +1 -0
@@ -812,12 +812,8 @@ video {
812
812
  right: 0px;
813
813
  }
814
814
 
815
- .top-2 {
816
- top: 0.5rem;
817
- }
818
-
819
- .top-4 {
820
- top: 1rem;
815
+ .z-10 {
816
+ z-index: 10;
821
817
  }
822
818
 
823
819
  .z-50 {
@@ -854,6 +850,10 @@ video {
854
850
  margin-top: 6px;
855
851
  }
856
852
 
853
+ .box-border {
854
+ box-sizing: border-box;
855
+ }
856
+
857
857
  .block {
858
858
  display: block;
859
859
  }
@@ -893,6 +893,20 @@ video {
893
893
  height: 1.25rem;
894
894
  }
895
895
 
896
+ .size-6 {
897
+ width: 1.5rem;
898
+ height: 1.5rem;
899
+ }
900
+
901
+ .size-\[14px\] {
902
+ width: 14px;
903
+ height: 14px;
904
+ }
905
+
906
+ .max-h-60 {
907
+ max-height: 15rem;
908
+ }
909
+
896
910
  .w-\[200px\] {
897
911
  width: 200px;
898
912
  }
@@ -901,6 +915,10 @@ video {
901
915
  width: 400px;
902
916
  }
903
917
 
918
+ .w-auto {
919
+ width: auto;
920
+ }
921
+
904
922
  .w-full {
905
923
  width: 100%;
906
924
  }
@@ -909,6 +927,11 @@ video {
909
927
  max-width: 48rem;
910
928
  }
911
929
 
930
+ .rotate-180 {
931
+ --tw-rotate: 180deg;
932
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
933
+ }
934
+
912
935
  .cursor-pointer {
913
936
  cursor: pointer;
914
937
  }
@@ -974,6 +997,10 @@ video {
974
997
  overflow-x: auto;
975
998
  }
976
999
 
1000
+ .overflow-y-auto {
1001
+ overflow-y: auto;
1002
+ }
1003
+
977
1004
  .whitespace-nowrap {
978
1005
  white-space: nowrap;
979
1006
  }
@@ -1002,6 +1029,10 @@ video {
1002
1029
  border-radius: 0.5rem;
1003
1030
  }
1004
1031
 
1032
+ .rounded-md {
1033
+ border-radius: 0.375rem;
1034
+ }
1035
+
1005
1036
  .rounded-none {
1006
1037
  border-radius: 0px;
1007
1038
  }
@@ -1031,6 +1062,11 @@ video {
1031
1062
  border-color: rgb(var(--error-100) / var(--tw-border-opacity));
1032
1063
  }
1033
1064
 
1065
+ .border-gray-300 {
1066
+ --tw-border-opacity: 1;
1067
+ border-color: rgb(209 213 219 / var(--tw-border-opacity));
1068
+ }
1069
+
1034
1070
  .border-info {
1035
1071
  --tw-border-opacity: 1;
1036
1072
  border-color: rgb(var(--info-default) / var(--tw-border-opacity));
@@ -1075,6 +1111,11 @@ video {
1075
1111
  background-color: rgb(var(--error-100) / var(--tw-bg-opacity));
1076
1112
  }
1077
1113
 
1114
+ .bg-gray-200 {
1115
+ --tw-bg-opacity: 1;
1116
+ background-color: rgb(229 231 235 / var(--tw-bg-opacity));
1117
+ }
1118
+
1078
1119
  .bg-info {
1079
1120
  --tw-bg-opacity: 1;
1080
1121
  background-color: rgb(var(--info-default) / var(--tw-bg-opacity));
@@ -1119,6 +1160,11 @@ video {
1119
1160
  background-color: rgb(var(--warning-default) / var(--tw-bg-opacity));
1120
1161
  }
1121
1162
 
1163
+ .bg-white {
1164
+ --tw-bg-opacity: 1;
1165
+ background-color: rgb(255 255 255 / var(--tw-bg-opacity));
1166
+ }
1167
+
1122
1168
  .fill-error {
1123
1169
  fill: rgb(var(--error-100) / 1);
1124
1170
  }
@@ -1127,6 +1173,18 @@ video {
1127
1173
  fill: rgb(var(--input-active-stroke-color) / 1);
1128
1174
  }
1129
1175
 
1176
+ .fill-input-text {
1177
+ fill: rgb(var(--input-default-text-color) / 1);
1178
+ }
1179
+
1180
+ .fill-input-text-active {
1181
+ fill: rgb(var(--input-active-text-color) / 1);
1182
+ }
1183
+
1184
+ .fill-input-text-disabled {
1185
+ fill: rgb(var(--input-disabled-text-color) / 1);
1186
+ }
1187
+
1130
1188
  .p-1 {
1131
1189
  padding: 0.25rem;
1132
1190
  }
@@ -1168,6 +1226,11 @@ video {
1168
1226
  padding-bottom: 0.25rem;
1169
1227
  }
1170
1228
 
1229
+ .py-14 {
1230
+ padding-top: 3.5rem;
1231
+ padding-bottom: 3.5rem;
1232
+ }
1233
+
1171
1234
  .py-2 {
1172
1235
  padding-top: 0.5rem;
1173
1236
  padding-bottom: 0.5rem;
@@ -1178,6 +1241,22 @@ video {
1178
1241
  padding-bottom: 1rem;
1179
1242
  }
1180
1243
 
1244
+ .pe-\[30px\] {
1245
+ padding-inline-end: 30px;
1246
+ }
1247
+
1248
+ .pe-\[40px\] {
1249
+ padding-inline-end: 40px;
1250
+ }
1251
+
1252
+ .pe-\[48px\] {
1253
+ padding-inline-end: 48px;
1254
+ }
1255
+
1256
+ .text-center {
1257
+ text-align: center;
1258
+ }
1259
+
1181
1260
  .align-middle {
1182
1261
  vertical-align: middle;
1183
1262
  }
@@ -1445,6 +1524,12 @@ video {
1445
1524
  text-underline-offset: 4px;
1446
1525
  }
1447
1526
 
1527
+ .shadow-md {
1528
+ --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
1529
+ --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
1530
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
1531
+ }
1532
+
1448
1533
  .outline-none {
1449
1534
  outline: 2px solid transparent;
1450
1535
  outline-offset: 2px;
@@ -1479,6 +1564,10 @@ video {
1479
1564
  --tw-ring-color: rgb(var(--input-disabled-stroke-color) / var(--tw-ring-opacity));
1480
1565
  }
1481
1566
 
1567
+ .filter {
1568
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
1569
+ }
1570
+
1482
1571
  .transition-all {
1483
1572
  transition-property: all;
1484
1573
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
@@ -1663,6 +1752,11 @@ video {
1663
1752
  background-color: rgb(var(--error-120) / var(--tw-bg-opacity));
1664
1753
  }
1665
1754
 
1755
+ .hover\:bg-gray-100:hover {
1756
+ --tw-bg-opacity: 1;
1757
+ background-color: rgb(243 244 246 / var(--tw-bg-opacity));
1758
+ }
1759
+
1666
1760
  .hover\:bg-info-100:hover {
1667
1761
  --tw-bg-opacity: 1;
1668
1762
  background-color: rgb(var(--info-100)) / var(--tw-bg-opacity));
@@ -1730,9 +1824,9 @@ video {
1730
1824
  padding-inline-end: 2rem;
1731
1825
  }
1732
1826
 
1733
- .focus\:ring-2:focus {
1827
+ .focus\:ring-1:focus {
1734
1828
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
1735
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
1829
+ --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
1736
1830
  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
1737
1831
  }
1738
1832
 
@@ -1740,73 +1834,111 @@ video {
1740
1834
  --tw-ring-inset: inset;
1741
1835
  }
1742
1836
 
1837
+ .focus\:ring-error:focus {
1838
+ --tw-ring-opacity: 1;
1839
+ --tw-ring-color: rgb(var(--error-100) / var(--tw-ring-opacity));
1840
+ }
1841
+
1842
+ .focus\:ring-input-stroke-active:focus {
1843
+ --tw-ring-opacity: 1;
1844
+ --tw-ring-color: rgb(var(--input-active-stroke-color) / var(--tw-ring-opacity));
1845
+ }
1846
+
1743
1847
  .active\:scale-\[98\%\]:active {
1744
1848
  --tw-scale-x: 98%;
1745
1849
  --tw-scale-y: 98%;
1746
1850
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1747
1851
  }
1748
1852
 
1749
- .peer:focus ~ .peer-focus\:-top-1 {
1750
- top: -0.25rem;
1853
+ .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:top-2 {
1854
+ top: 0.5rem;
1751
1855
  }
1752
1856
 
1753
- .peer:focus ~ .peer-focus\:-top-1\.5 {
1754
- top: -0.375rem;
1857
+ .peer:placeholder-shown ~ .peer-placeholder-shown\:top-2 {
1858
+ top: 0.5rem;
1755
1859
  }
1756
1860
 
1757
- .peer:focus ~ .peer-focus\:flex {
1758
- display: flex;
1861
+ .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:top-4 {
1862
+ top: 1rem;
1759
1863
  }
1760
1864
 
1761
- .peer:focus ~ .peer-focus\:bg-input-label-background {
1762
- --tw-bg-opacity: 1;
1763
- background-color: rgb(var(--input-label-background-color) / var(--tw-bg-opacity));
1865
+ .peer:placeholder-shown ~ .peer-placeholder-shown\:top-4 {
1866
+ top: 1rem;
1764
1867
  }
1765
1868
 
1766
- .peer:focus ~ .peer-focus\:text-input-text-active {
1767
- --tw-text-opacity: 1;
1768
- color: rgb(var(--input-active-text-color) / var(--tw-text-opacity));
1869
+ .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:bg-transparent {
1870
+ background-color: transparent;
1769
1871
  }
1770
1872
 
1771
- .peer:focus ~ .peer-focus\:typography-label1 {
1772
- font-size: 12px;
1773
- line-height: 12px;
1873
+ .peer:placeholder-shown ~ .peer-placeholder-shown\:bg-transparent {
1874
+ background-color: transparent;
1875
+ }
1876
+
1877
+ .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:typography-subtitile1 {
1878
+ font-size: 16px;
1879
+ line-height: 24px;
1774
1880
  font-weight: 400;
1775
1881
  }
1776
1882
 
1777
- .peer:focus ~ .peer-focus\:typography-label2 {
1778
- font-size: 10px;
1779
- line-height: 10px;
1883
+ .peer:placeholder-shown ~ .peer-placeholder-shown\:typography-subtitile1 {
1884
+ font-size: 16px;
1885
+ line-height: 24px;
1780
1886
  font-weight: 400;
1781
1887
  }
1782
1888
 
1783
- .peer:not(:-moz-placeholder-shown) ~ .peer-\[\:not\(\:-moz-placeholder-shown\)\]\:-top-1\.5 {
1784
- top: -0.375rem;
1889
+ .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:typography-subtitile4 {
1890
+ font-size: 14px;
1891
+ line-height: 22px;
1892
+ font-weight: 400;
1785
1893
  }
1786
1894
 
1787
- .peer:not(:placeholder-shown) ~ .peer-\[\:not\(\:placeholder-shown\)\]\:-top-1\.5 {
1788
- top: -0.375rem;
1895
+ .peer:placeholder-shown ~ .peer-placeholder-shown\:typography-subtitile4 {
1896
+ font-size: 14px;
1897
+ line-height: 22px;
1898
+ font-weight: 400;
1789
1899
  }
1790
1900
 
1791
- .peer:not(:-moz-placeholder-shown) ~ .peer-\[\:not\(\:-moz-placeholder-shown\)\]\:typography-label1 {
1901
+ .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:typography-small1 {
1792
1902
  font-size: 12px;
1793
- line-height: 12px;
1903
+ line-height: 14px;
1794
1904
  font-weight: 400;
1795
1905
  }
1796
1906
 
1797
- .peer:not(:placeholder-shown) ~ .peer-\[\:not\(\:placeholder-shown\)\]\:typography-label1 {
1907
+ .peer:placeholder-shown ~ .peer-placeholder-shown\:typography-small1 {
1798
1908
  font-size: 12px;
1799
- line-height: 12px;
1909
+ line-height: 14px;
1800
1910
  font-weight: 400;
1801
1911
  }
1802
1912
 
1803
- .peer:not(:-moz-placeholder-shown) ~ .peer-\[\:not\(\:-moz-placeholder-shown\)\]\:typography-label2 {
1804
- font-size: 10px;
1805
- line-height: 10px;
1913
+ .peer:focus ~ .peer-focus\:-top-1 {
1914
+ top: -0.25rem;
1915
+ }
1916
+
1917
+ .peer:focus ~ .peer-focus\:-top-1\.5 {
1918
+ top: -0.375rem;
1919
+ }
1920
+
1921
+ .peer:focus ~ .peer-focus\:flex {
1922
+ display: flex;
1923
+ }
1924
+
1925
+ .peer:focus ~ .peer-focus\:bg-input-label-background {
1926
+ --tw-bg-opacity: 1;
1927
+ background-color: rgb(var(--input-label-background-color) / var(--tw-bg-opacity));
1928
+ }
1929
+
1930
+ .peer:focus ~ .peer-focus\:text-input-text-active {
1931
+ --tw-text-opacity: 1;
1932
+ color: rgb(var(--input-active-text-color) / var(--tw-text-opacity));
1933
+ }
1934
+
1935
+ .peer:focus ~ .peer-focus\:typography-label1 {
1936
+ font-size: 12px;
1937
+ line-height: 12px;
1806
1938
  font-weight: 400;
1807
1939
  }
1808
1940
 
1809
- .peer:not(:placeholder-shown) ~ .peer-\[\:not\(\:placeholder-shown\)\]\:typography-label2 {
1941
+ .peer:focus ~ .peer-focus\:typography-label2 {
1810
1942
  font-size: 10px;
1811
1943
  line-height: 10px;
1812
1944
  font-weight: 400;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rovula/ui",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "main": "dist/cjs/bundle.js",
5
5
  "module": "dist/esm/bundle.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,49 @@
1
+ import React from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import Dropdown from "./Dropdown";
4
+
5
+ // More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
6
+ const meta = {
7
+ title: "Components/Dropdown",
8
+ component: Dropdown,
9
+ tags: ["autodocs"],
10
+ parameters: {
11
+ // More on how to position stories at: https://storybook.js.org/docs/7.0/react/configure/story-layout
12
+ layout: "fullscreen",
13
+ },
14
+ decorators: [
15
+ (Story) => (
16
+ <div className="p-5 flex w-full">
17
+ <Story />
18
+ </div>
19
+ ),
20
+ ],
21
+ } satisfies Meta<typeof Dropdown>;
22
+
23
+ export default meta;
24
+
25
+ const options = new Array(100).fill("").map((__, index) => ({
26
+ value: `option${index + 1}`,
27
+ label: `Option ${index + 1}`,
28
+ }));
29
+
30
+ export const Default = {
31
+ args: {
32
+ label: "Choose an option:",
33
+ fullwidth: true,
34
+ options,
35
+ },
36
+ render: (args) => {
37
+ console.log("args ", args);
38
+ const props: typeof args = {
39
+ ...args,
40
+ };
41
+ return (
42
+ <div className="flex flex-row gap-4 w-full">
43
+ <Dropdown id="1" size="lg" options={options} {...args} />
44
+ <Dropdown id="2" size="md" options={options} {...args} />
45
+ <Dropdown id="3" size="sm" options={options} {...args} />
46
+ </div>
47
+ );
48
+ },
49
+ } satisfies StoryObj;
@@ -0,0 +1,54 @@
1
+ import React from "react";
2
+ import { cva } from "class-variance-authority";
3
+
4
+ export const iconWrapperVariant = cva(
5
+ ["absolute inset-y-0 right-0 flex items-center justify-center"],
6
+ {
7
+ variants: {
8
+ size: {
9
+ sm: "mr-2",
10
+ md: "mr-3",
11
+ lg: "mr-4",
12
+ },
13
+ },
14
+ defaultVariants: {
15
+ size: "md",
16
+ },
17
+ }
18
+ );
19
+
20
+ export const dropdownIconVariant = cva(["transition-all"], {
21
+ variants: {
22
+ size: {
23
+ sm: "size-[14px]",
24
+ md: "size-5",
25
+ lg: "size-6",
26
+ },
27
+ disabled: {
28
+ true: "fill-input-text-disabled",
29
+ false: "fill-input-text",
30
+ },
31
+ isFocus: {
32
+ true: "fill-input-text-active rotate-180",
33
+ false: "",
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ size: "md",
38
+ disabled: false,
39
+ isFocus: false,
40
+ },
41
+ });
42
+
43
+ export const customInputVariant = cva([], {
44
+ variants: {
45
+ size: {
46
+ sm: "pe-[30px]",
47
+ md: "pe-[40px]",
48
+ lg: "pe-[48px]",
49
+ },
50
+ },
51
+ defaultVariants: {
52
+ size: "md",
53
+ },
54
+ });
@@ -0,0 +1,151 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from "react";
2
+
3
+ import TextInput, { InputProps } from "../TextInput/TextInput";
4
+ import {
5
+ customInputVariant,
6
+ dropdownIconVariant,
7
+ iconWrapperVariant,
8
+ } from "./Dropdown.styles";
9
+
10
+ import { ChevronDownIcon } from "@heroicons/react/16/solid";
11
+
12
+ type Options = {
13
+ value: string;
14
+ label: string;
15
+ };
16
+
17
+ type DropdownProps = {
18
+ id?: string;
19
+ label?: string;
20
+ size?: "sm" | "md" | "lg";
21
+ rounded?: "none" | "normal" | "full";
22
+ variant?: "flat" | "outline" | "underline";
23
+ helperText?: string;
24
+ errorMessage?: string;
25
+ filterMode?: boolean;
26
+ fullwidth?: boolean;
27
+ disabled?: boolean;
28
+ error?: boolean;
29
+ required?: boolean;
30
+ className?: string;
31
+ options: Options[];
32
+ value?: Options;
33
+ onChangeText?: InputProps["onChange"];
34
+ onSelect?: (value: Options) => void;
35
+ } & Omit<InputProps, "value">;
36
+
37
+ const Dropdown = ({
38
+ id,
39
+ options,
40
+ value,
41
+ label,
42
+ size = "md",
43
+ rounded = "normal",
44
+ variant = "outline",
45
+ helperText,
46
+ errorMessage,
47
+ fullwidth = true,
48
+ disabled = false,
49
+ error = false,
50
+ filterMode = false,
51
+ required = true,
52
+ onChangeText,
53
+ onSelect,
54
+ ...props
55
+ }: DropdownProps) => {
56
+ const _id = id || `${label}-select`;
57
+
58
+ const [isFocused, setIsFocused] = useState(false);
59
+ const [selectedOption, setSelectedOption] = useState<
60
+ Options | null | undefined
61
+ >(null);
62
+ const [textValue, setTextValue] = useState("");
63
+
64
+ useEffect(() => {
65
+ if (value && !selectedOption) {
66
+ setSelectedOption(value);
67
+ }
68
+ }, [value, selectedOption]);
69
+
70
+ const handleOnChangeText = useCallback(
71
+ (event: React.ChangeEvent<HTMLInputElement>) => {
72
+ onChangeText?.(event);
73
+ setTextValue(event.target.value);
74
+ },
75
+ [onChangeText]
76
+ );
77
+
78
+ const handleOptionClick = useCallback(
79
+ (option: Options) => {
80
+ setSelectedOption(option);
81
+ setTextValue(option.label);
82
+ onSelect?.(option);
83
+ },
84
+ [onSelect]
85
+ );
86
+
87
+ const optionsFiltered = useMemo(() => {
88
+ return options.filter(
89
+ (option) =>
90
+ !filterMode ||
91
+ option.label?.toLowerCase().includes(textValue?.toLowerCase())
92
+ );
93
+ }, [options, filterMode, textValue]);
94
+
95
+ const renderOptions = () => (
96
+ <ul className="absolute mt-1 w-full bg-white border border-gray-300 rounded-md shadow-md z-10 max-h-60 overflow-y-auto">
97
+ {optionsFiltered.map((option) => (
98
+ <li
99
+ key={option.value}
100
+ onMouseDown={() => handleOptionClick(option)}
101
+ className={`px-4 py-2 hover:bg-gray-100 cursor-pointer ${
102
+ selectedOption?.value === option.value ? " bg-gray-200" : ""
103
+ }`}
104
+ >
105
+ {option.label}
106
+ </li>
107
+ ))}
108
+ {optionsFiltered.length === 0 && (
109
+ <li className="px-4 py-14 text-center text-input-text">Not found</li>
110
+ )}
111
+ </ul>
112
+ );
113
+
114
+ return (
115
+ <div className={`relative ${fullwidth ? "w-full" : ""}`}>
116
+ <TextInput
117
+ {...props}
118
+ readOnly={!filterMode}
119
+ value={textValue}
120
+ onChange={handleOnChangeText}
121
+ label={label}
122
+ placeholder=" "
123
+ type="text"
124
+ rounded={rounded}
125
+ variant={variant}
126
+ helperText={helperText}
127
+ errorMessage={errorMessage}
128
+ fullwidth={fullwidth}
129
+ error={error}
130
+ required={required}
131
+ id={_id}
132
+ disabled={disabled}
133
+ hasClearIcon={false}
134
+ size={size}
135
+ className={customInputVariant({ size })}
136
+ onFocus={() => setIsFocused(true)}
137
+ onBlur={() => setIsFocused(false)}
138
+ endIcon={
139
+ <div className={iconWrapperVariant({ size })}>
140
+ <ChevronDownIcon
141
+ className={dropdownIconVariant({ size, isFocus: isFocused })}
142
+ />
143
+ </div>
144
+ }
145
+ />
146
+ {isFocused && renderOptions()}
147
+ </div>
148
+ );
149
+ };
150
+
151
+ export default Dropdown;
@@ -35,9 +35,9 @@ export const Default = {
35
35
  };
36
36
  return (
37
37
  <div className="flex flex-row gap-4 w-full">
38
- <TextInput id="1" placeholder="placeholder" size="lg" {...args} />
39
- <TextInput id="2" placeholder="placeholder" size="md" {...args} />
40
- <TextInput id="3" placeholder="placeholder" size="sm" {...args} />
38
+ <TextInput id="1" size="lg" {...args} />
39
+ <TextInput id="2" size="md" {...args} />
40
+ <TextInput id="3" size="sm" {...args} />
41
41
  </div>
42
42
  );
43
43
  },