analytica-frontend-lib 1.0.37 → 1.0.39

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 (100) hide show
  1. package/README.md +1 -2
  2. package/dist/Alert/index.js.map +1 -1
  3. package/dist/Alert/index.mjs.map +1 -1
  4. package/dist/Badge/index.d.mts +0 -1
  5. package/dist/Badge/index.d.ts +0 -1
  6. package/dist/Badge/index.js.map +1 -1
  7. package/dist/Badge/index.mjs.map +1 -1
  8. package/dist/Button/index.d.mts +0 -1
  9. package/dist/Button/index.d.ts +0 -1
  10. package/dist/Button/index.js.map +1 -1
  11. package/dist/Button/index.mjs.map +1 -1
  12. package/dist/CheckBox/index.js +0 -1
  13. package/dist/CheckBox/index.js.map +1 -1
  14. package/dist/CheckBox/index.mjs +0 -2
  15. package/dist/CheckBox/index.mjs.map +1 -1
  16. package/dist/Chips/index.d.mts +41 -0
  17. package/dist/Chips/index.d.ts +41 -0
  18. package/dist/Chips/index.js +57 -0
  19. package/dist/Chips/index.js.map +1 -0
  20. package/dist/Chips/index.mjs +36 -0
  21. package/dist/Chips/index.mjs.map +1 -0
  22. package/dist/Divider/index.d.mts +32 -0
  23. package/dist/Divider/index.d.ts +32 -0
  24. package/dist/Divider/index.js +47 -0
  25. package/dist/Divider/index.js.map +1 -0
  26. package/dist/Divider/index.mjs +26 -0
  27. package/dist/Divider/index.mjs.map +1 -0
  28. package/dist/DropdownMenu/index.d.mts +16 -8
  29. package/dist/DropdownMenu/index.d.ts +16 -8
  30. package/dist/DropdownMenu/index.js +122 -46
  31. package/dist/DropdownMenu/index.js.map +1 -1
  32. package/dist/DropdownMenu/index.mjs +122 -47
  33. package/dist/DropdownMenu/index.mjs.map +1 -1
  34. package/dist/IconButton/index.d.mts +0 -1
  35. package/dist/IconButton/index.d.ts +0 -1
  36. package/dist/IconButton/index.js.map +1 -1
  37. package/dist/IconButton/index.mjs.map +1 -1
  38. package/dist/IconRoundedButton/index.d.mts +0 -1
  39. package/dist/IconRoundedButton/index.d.ts +0 -1
  40. package/dist/IconRoundedButton/index.js.map +1 -1
  41. package/dist/IconRoundedButton/index.mjs.map +1 -1
  42. package/dist/Input/index.d.mts +27 -0
  43. package/dist/Input/index.d.ts +27 -0
  44. package/dist/Input/index.js +184 -0
  45. package/dist/Input/index.js.map +1 -0
  46. package/dist/Input/index.mjs +168 -0
  47. package/dist/Input/index.mjs.map +1 -0
  48. package/dist/NavButton/index.d.mts +0 -1
  49. package/dist/NavButton/index.d.ts +0 -1
  50. package/dist/NavButton/index.js.map +1 -1
  51. package/dist/NavButton/index.mjs.map +1 -1
  52. package/dist/ProgressBar/index.js +0 -1
  53. package/dist/ProgressBar/index.js.map +1 -1
  54. package/dist/ProgressBar/index.mjs +0 -2
  55. package/dist/ProgressBar/index.mjs.map +1 -1
  56. package/dist/ProgressCircle/index.js +0 -1
  57. package/dist/ProgressCircle/index.js.map +1 -1
  58. package/dist/ProgressCircle/index.mjs +0 -2
  59. package/dist/ProgressCircle/index.mjs.map +1 -1
  60. package/dist/Radio/index.js +0 -1
  61. package/dist/Radio/index.js.map +1 -1
  62. package/dist/Radio/index.mjs +0 -2
  63. package/dist/Radio/index.mjs.map +1 -1
  64. package/dist/Select/index.d.mts +51 -0
  65. package/dist/Select/index.d.ts +51 -0
  66. package/dist/Select/index.js +322 -0
  67. package/dist/Select/index.js.map +1 -0
  68. package/dist/Select/index.mjs +298 -0
  69. package/dist/Select/index.mjs.map +1 -0
  70. package/dist/SelectionButton/index.d.mts +0 -1
  71. package/dist/SelectionButton/index.d.ts +0 -1
  72. package/dist/SelectionButton/index.js.map +1 -1
  73. package/dist/SelectionButton/index.mjs.map +1 -1
  74. package/dist/Text/index.d.mts +0 -1
  75. package/dist/Text/index.d.ts +0 -1
  76. package/dist/Text/index.js.map +1 -1
  77. package/dist/Text/index.mjs.map +1 -1
  78. package/dist/TextArea/index.js +0 -1
  79. package/dist/TextArea/index.js.map +1 -1
  80. package/dist/TextArea/index.mjs +0 -2
  81. package/dist/TextArea/index.mjs.map +1 -1
  82. package/dist/Toast/Toaster/index.js +0 -1
  83. package/dist/Toast/Toaster/index.js.map +1 -1
  84. package/dist/Toast/Toaster/index.mjs +0 -2
  85. package/dist/Toast/Toaster/index.mjs.map +1 -1
  86. package/dist/Toast/index.js +0 -1
  87. package/dist/Toast/index.js.map +1 -1
  88. package/dist/Toast/index.mjs +0 -2
  89. package/dist/Toast/index.mjs.map +1 -1
  90. package/dist/index.css +5 -9
  91. package/dist/index.css.map +1 -1
  92. package/dist/index.d.mts +7 -136
  93. package/dist/index.d.ts +7 -136
  94. package/dist/index.js +52 -34
  95. package/dist/index.js.map +1 -1
  96. package/dist/index.mjs +52 -34
  97. package/dist/index.mjs.map +1 -1
  98. package/dist/styles.css +5 -9
  99. package/dist/styles.css.map +1 -1
  100. package/package.json +1 -5
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/components/Select/Select.tsx
21
+ var Select_exports = {};
22
+ __export(Select_exports, {
23
+ SelectContent: () => SelectContent,
24
+ SelectItem: () => SelectItem,
25
+ SelectTrigger: () => SelectTrigger,
26
+ SelectValue: () => SelectValue,
27
+ createSelectStore: () => createSelectStore,
28
+ default: () => Select_default,
29
+ getLabelAsNode: () => getLabelAsNode,
30
+ useSelectStore: () => useSelectStore
31
+ });
32
+ module.exports = __toCommonJS(Select_exports);
33
+ var import_zustand = require("zustand");
34
+ var import_react = require("react");
35
+ var import_phosphor_react = require("phosphor-react");
36
+ var import_jsx_runtime = require("react/jsx-runtime");
37
+ var VARIANT_CLASSES = {
38
+ outlined: "border-2 rounded-sm focus:border-primary-950",
39
+ underlined: "border-b-2 focus:border-primary-950",
40
+ rounded: "border-2 rounded-4xl focus:border-primary-950"
41
+ };
42
+ var SIZE_CLASSES = {
43
+ small: "text-sm",
44
+ medium: "text-md",
45
+ large: "text-lg"
46
+ };
47
+ var SIDE_CLASSES = {
48
+ top: "bottom-full -translate-y-1",
49
+ right: "top-full translate-y-1",
50
+ bottom: "top-full translate-y-1",
51
+ left: "top-full translate-y-1"
52
+ };
53
+ var ALIGN_CLASSES = {
54
+ start: "left-0",
55
+ center: "left-1/2 -translate-x-1/2",
56
+ end: "right-0"
57
+ };
58
+ function createSelectStore() {
59
+ return (0, import_zustand.create)((set) => ({
60
+ open: false,
61
+ setOpen: (open) => set({ open }),
62
+ value: "",
63
+ setValue: (value) => set({ value }),
64
+ selectedLabel: "",
65
+ setSelectedLabel: (label) => set({ selectedLabel: label })
66
+ }));
67
+ }
68
+ var useSelectStore = (externalStore) => {
69
+ if (!externalStore) {
70
+ throw new Error(
71
+ "Component must be used within a Select (store is missing)"
72
+ );
73
+ }
74
+ return externalStore;
75
+ };
76
+ function getLabelAsNode(children) {
77
+ if (typeof children === "string" || typeof children === "number") {
78
+ return children;
79
+ }
80
+ const flattened = import_react.Children.toArray(children);
81
+ if (flattened.length === 1) return flattened[0];
82
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: flattened });
83
+ }
84
+ var injectStore = (children, store) => {
85
+ return import_react.Children.map(children, (child) => {
86
+ if ((0, import_react.isValidElement)(child)) {
87
+ const typedChild = child;
88
+ const newProps = {
89
+ store
90
+ };
91
+ if (typedChild.props.children) {
92
+ newProps.children = injectStore(typedChild.props.children, store);
93
+ }
94
+ return (0, import_react.cloneElement)(typedChild, newProps);
95
+ }
96
+ return child;
97
+ });
98
+ };
99
+ var Select = ({
100
+ children,
101
+ defaultValue = "",
102
+ value: propValue,
103
+ onValueChange,
104
+ size = "small"
105
+ }) => {
106
+ const storeRef = (0, import_react.useRef)(null);
107
+ storeRef.current ??= createSelectStore();
108
+ const store = storeRef.current;
109
+ const selectRef = (0, import_react.useRef)(null);
110
+ const { open, setOpen, setValue, value, selectedLabel } = (0, import_zustand.useStore)(
111
+ store,
112
+ (s) => s
113
+ );
114
+ const isControlled = propValue !== void 0;
115
+ const currentValue = isControlled ? propValue : value;
116
+ const findLabelForValue = (children2, targetValue) => {
117
+ let found = null;
118
+ const search = (nodes) => {
119
+ import_react.Children.forEach(nodes, (child) => {
120
+ if (!(0, import_react.isValidElement)(child)) return;
121
+ const typedChild = child;
122
+ if (typedChild.type === SelectItem && typedChild.props.value === targetValue) {
123
+ if (typeof typedChild.props.children === "string")
124
+ found = typedChild.props.children;
125
+ }
126
+ if (typedChild.props.children && !found)
127
+ search(typedChild.props.children);
128
+ });
129
+ };
130
+ search(children2);
131
+ return found;
132
+ };
133
+ (0, import_react.useEffect)(() => {
134
+ if (!selectedLabel && defaultValue) {
135
+ const label = findLabelForValue(children, defaultValue);
136
+ if (label) store.setState({ selectedLabel: label });
137
+ }
138
+ }, [children, defaultValue, selectedLabel]);
139
+ (0, import_react.useEffect)(() => {
140
+ setValue(currentValue);
141
+ const handleClickOutside = (event) => {
142
+ if (selectRef.current && !selectRef.current.contains(event.target)) {
143
+ setOpen(false);
144
+ }
145
+ };
146
+ const handleArrowKeys = (event) => {
147
+ const selectContent = selectRef.current?.querySelector('[role="menu"]');
148
+ if (selectContent) {
149
+ event.preventDefault();
150
+ const items = Array.from(
151
+ selectContent.querySelectorAll(
152
+ '[role="menuitem"]:not([aria-disabled="true"])'
153
+ )
154
+ ).filter((el) => el instanceof HTMLElement);
155
+ const focused = document.activeElement;
156
+ const currentIndex = items.findIndex((item) => item === focused);
157
+ let nextIndex = 0;
158
+ if (event.key === "ArrowDown") {
159
+ nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % items.length;
160
+ } else {
161
+ nextIndex = currentIndex === -1 ? items.length - 1 : (currentIndex - 1 + items.length) % items.length;
162
+ }
163
+ items[nextIndex]?.focus();
164
+ }
165
+ };
166
+ if (open) {
167
+ document.addEventListener("mousedown", handleClickOutside);
168
+ document.addEventListener("keydown", handleArrowKeys);
169
+ }
170
+ return () => {
171
+ document.removeEventListener("mousedown", handleClickOutside);
172
+ document.removeEventListener("keydown", handleArrowKeys);
173
+ };
174
+ }, [open]);
175
+ (0, import_react.useEffect)(() => {
176
+ if (onValueChange) {
177
+ onValueChange(value);
178
+ }
179
+ }, [value]);
180
+ const sizeClasses = SIZE_CLASSES[size];
181
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `relative ${sizeClasses} w-[288px]`, ref: selectRef, children: injectStore(children, store) });
182
+ };
183
+ var SelectValue = ({
184
+ placeholder,
185
+ store: externalStore
186
+ }) => {
187
+ const store = useSelectStore(externalStore);
188
+ const selectedLabel = (0, import_zustand.useStore)(store, (s) => s.selectedLabel);
189
+ const value = (0, import_zustand.useStore)(store, (s) => s.value);
190
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-inherit", children: selectedLabel || placeholder || value });
191
+ };
192
+ var SelectTrigger = (0, import_react.forwardRef)(
193
+ ({
194
+ className,
195
+ invalid = false,
196
+ variant = "outlined",
197
+ store: externalStore,
198
+ disabled,
199
+ ...props
200
+ }, ref) => {
201
+ const store = useSelectStore(externalStore);
202
+ const open = (0, import_zustand.useStore)(store, (s) => s.open);
203
+ const toggleOpen = () => store.setState({ open: !open });
204
+ const variantClasses = VARIANT_CLASSES[variant];
205
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
206
+ "button",
207
+ {
208
+ ref,
209
+ className: `
210
+ flex h-9 min-w-[220px] w-full items-center justify-between border-border-300 px-3 py-2
211
+ ${invalid && "border-indicator-error text-text-600"}
212
+ ${disabled ? "cursor-not-allowed text-text-400 pointer-events-none opacity-50" : "cursor-pointer hover:bg-background-50 focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground"}
213
+ ${!invalid && !disabled ? "text-text-700" : ""}
214
+ ${variantClasses}
215
+ ${className}
216
+ `,
217
+ onClick: toggleOpen,
218
+ "aria-expanded": open,
219
+ "aria-haspopup": "listbox",
220
+ "aria-controls": open ? "select-content" : void 0,
221
+ ...props,
222
+ children: [
223
+ props.children,
224
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
225
+ import_phosphor_react.CaretDown,
226
+ {
227
+ className: `h-[1em] w-[1em] opacity-50 transition-transform ${open ? "rotate-180" : ""}`
228
+ }
229
+ )
230
+ ]
231
+ }
232
+ );
233
+ }
234
+ );
235
+ SelectTrigger.displayName = "SelectTrigger";
236
+ var SelectContent = (0, import_react.forwardRef)(
237
+ ({
238
+ children,
239
+ className,
240
+ align = "start",
241
+ side = "bottom",
242
+ store: externalStore,
243
+ ...props
244
+ }, ref) => {
245
+ const store = useSelectStore(externalStore);
246
+ const open = (0, import_zustand.useStore)(store, (s) => s.open);
247
+ if (!open) return null;
248
+ const getPositionClasses = () => `w-full min-w-full absolute ${SIDE_CLASSES[side]} ${ALIGN_CLASSES[align]}`;
249
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
250
+ "div",
251
+ {
252
+ role: "menu",
253
+ ref,
254
+ className: `bg-background z-50 min-w-[210px] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md border-border-100 ${getPositionClasses()} ${className}`,
255
+ ...props,
256
+ children
257
+ }
258
+ );
259
+ }
260
+ );
261
+ SelectContent.displayName = "SelectContent";
262
+ var SelectItem = (0, import_react.forwardRef)(
263
+ ({
264
+ className,
265
+ children,
266
+ value,
267
+ disabled = false,
268
+ store: externalStore,
269
+ ...props
270
+ }, ref) => {
271
+ const store = useSelectStore(externalStore);
272
+ const selectedValue = (0, import_zustand.useStore)(store, (s) => s.value);
273
+ const { setValue, setSelectedLabel, setOpen } = store.getState();
274
+ const handleClick = (e) => {
275
+ const labelNode = getLabelAsNode(children);
276
+ if (!disabled) {
277
+ setValue(value);
278
+ setSelectedLabel(labelNode);
279
+ setOpen(false);
280
+ }
281
+ props.onClick?.(e);
282
+ };
283
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
284
+ "div",
285
+ {
286
+ role: "menuitem",
287
+ "aria-disabled": disabled,
288
+ ref,
289
+ className: `
290
+ focus-visible:bg-background-50
291
+ relative flex select-none items-center gap-2 rounded-sm p-3 outline-none transition-colors [&>svg]:size-4 [&>svg]:shrink-0
292
+ ${className}
293
+ ${disabled ? "cursor-not-allowed text-text-400 pointer-events-none opacity-50" : "cursor-pointer hover:bg-background-50 text-text-700 focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground"}
294
+ ${selectedValue === value && "bg-background-50"}
295
+ `,
296
+ onClick: handleClick,
297
+ onKeyDown: (e) => {
298
+ if (e.key === "Enter" || e.key === " ") handleClick(e);
299
+ },
300
+ tabIndex: disabled ? -1 : 0,
301
+ ...props,
302
+ children: [
303
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: selectedValue === value && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_phosphor_react.Check, { className: "" }) }),
304
+ children
305
+ ]
306
+ }
307
+ );
308
+ }
309
+ );
310
+ SelectItem.displayName = "SelectItem";
311
+ var Select_default = Select;
312
+ // Annotate the CommonJS export names for ESM import in node:
313
+ 0 && (module.exports = {
314
+ SelectContent,
315
+ SelectItem,
316
+ SelectTrigger,
317
+ SelectValue,
318
+ createSelectStore,
319
+ getLabelAsNode,
320
+ useSelectStore
321
+ });
322
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/Select/Select.tsx"],"sourcesContent":["import { create, StoreApi, useStore } from 'zustand';\nimport {\n ReactNode,\n useEffect,\n useRef,\n ButtonHTMLAttributes,\n forwardRef,\n HTMLAttributes,\n KeyboardEvent,\n MouseEvent,\n ReactElement,\n isValidElement,\n Children,\n cloneElement,\n} from 'react';\nimport { CaretDown, Check } from 'phosphor-react';\n\nconst VARIANT_CLASSES = {\n outlined: 'border-2 rounded-sm focus:border-primary-950',\n underlined: 'border-b-2 focus:border-primary-950',\n rounded: 'border-2 rounded-4xl focus:border-primary-950',\n} as const;\n\nconst SIZE_CLASSES = {\n small: 'text-sm',\n medium: 'text-md',\n large: 'text-lg',\n} as const;\n\nconst SIDE_CLASSES = {\n top: 'bottom-full -translate-y-1',\n right: 'top-full translate-y-1',\n bottom: 'top-full translate-y-1',\n left: 'top-full translate-y-1',\n};\nconst ALIGN_CLASSES = {\n start: 'left-0',\n center: 'left-1/2 -translate-x-1/2',\n end: 'right-0',\n};\n\ninterface SelectStore {\n open: boolean;\n setOpen: (open: boolean) => void;\n value: string;\n setValue: (value: string) => void;\n selectedLabel: ReactNode;\n setSelectedLabel: (label: ReactNode) => void;\n}\n\ntype SelectStoreApi = StoreApi<SelectStore>;\n\nexport function createSelectStore(): SelectStoreApi {\n return create<SelectStore>((set) => ({\n open: false,\n setOpen: (open) => set({ open }),\n value: '',\n setValue: (value) => set({ value }),\n selectedLabel: '',\n setSelectedLabel: (label) => set({ selectedLabel: label }),\n }));\n}\n\nexport const useSelectStore = (externalStore?: SelectStoreApi) => {\n if (!externalStore) {\n throw new Error(\n 'Component must be used within a Select (store is missing)'\n );\n }\n\n return externalStore;\n};\n\nexport function getLabelAsNode(children: ReactNode): ReactNode {\n if (typeof children === 'string' || typeof children === 'number') {\n return children;\n }\n const flattened = Children.toArray(children);\n\n if (flattened.length === 1) return flattened[0];\n\n return <>{flattened}</>;\n}\n\ninterface SelectProps {\n children: ReactNode;\n defaultValue?: string;\n value?: string;\n onValueChange?: (value: string) => void;\n size?: 'small' | 'medium' | 'large';\n}\n\nconst injectStore = (children: ReactNode, store: SelectStoreApi): ReactNode => {\n return Children.map(children, (child) => {\n if (isValidElement(child)) {\n const typedChild = child as ReactElement<{\n store?: SelectStoreApi;\n children?: ReactNode;\n }>;\n\n const newProps: Partial<{ store: SelectStoreApi; children: ReactNode }> =\n {\n store,\n };\n\n if (typedChild.props.children) {\n newProps.children = injectStore(typedChild.props.children, store);\n }\n\n return cloneElement(typedChild, newProps);\n }\n return child;\n });\n};\n\nconst Select = ({\n children,\n defaultValue = '',\n value: propValue,\n onValueChange,\n size = 'small',\n}: SelectProps) => {\n const storeRef = useRef<SelectStoreApi | null>(null);\n storeRef.current ??= createSelectStore();\n const store = storeRef.current;\n\n const selectRef = useRef<HTMLDivElement>(null);\n const { open, setOpen, setValue, value, selectedLabel } = useStore(\n store,\n (s) => s\n );\n\n const isControlled = propValue !== undefined;\n const currentValue = isControlled ? propValue : value;\n\n const findLabelForValue = (\n children: ReactNode,\n targetValue: string\n ): string | null => {\n let found: string | null = null;\n const search = (nodes: ReactNode) => {\n Children.forEach(nodes, (child) => {\n if (!isValidElement(child)) return;\n const typedChild = child as ReactElement<{\n value?: string;\n children?: ReactNode;\n }>;\n if (\n typedChild.type === SelectItem &&\n typedChild.props.value === targetValue\n ) {\n if (typeof typedChild.props.children === 'string')\n found = typedChild.props.children;\n }\n if (typedChild.props.children && !found)\n search(typedChild.props.children);\n });\n };\n search(children);\n return found;\n };\n\n useEffect(() => {\n if (!selectedLabel && defaultValue) {\n const label = findLabelForValue(children, defaultValue);\n if (label) store.setState({ selectedLabel: label });\n }\n }, [children, defaultValue, selectedLabel]);\n\n useEffect(() => {\n setValue(currentValue);\n const handleClickOutside = (event: globalThis.MouseEvent) => {\n if (\n selectRef.current &&\n !selectRef.current.contains(event.target as Node)\n ) {\n setOpen(false);\n }\n };\n\n const handleArrowKeys = (event: globalThis.KeyboardEvent) => {\n const selectContent = selectRef.current?.querySelector('[role=\"menu\"]');\n if (selectContent) {\n event.preventDefault();\n const items = Array.from(\n selectContent.querySelectorAll(\n '[role=\"menuitem\"]:not([aria-disabled=\"true\"])'\n )\n ).filter((el): el is HTMLElement => el instanceof HTMLElement);\n\n const focused = document.activeElement as HTMLElement;\n const currentIndex = items.findIndex((item) => item === focused);\n\n let nextIndex = 0;\n if (event.key === 'ArrowDown') {\n nextIndex =\n currentIndex === -1 ? 0 : (currentIndex + 1) % items.length;\n } else {\n nextIndex =\n currentIndex === -1\n ? items.length - 1\n : (currentIndex - 1 + items.length) % items.length;\n }\n items[nextIndex]?.focus();\n }\n };\n\n if (open) {\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleArrowKeys);\n }\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleArrowKeys);\n };\n }, [open]);\n\n useEffect(() => {\n if (onValueChange) {\n onValueChange(value);\n }\n }, [value]);\n\n const sizeClasses = SIZE_CLASSES[size];\n\n return (\n <div className={`relative ${sizeClasses} w-[288px]`} ref={selectRef}>\n {injectStore(children, store)}\n </div>\n );\n};\n\nconst SelectValue = ({\n placeholder,\n store: externalStore,\n}: {\n placeholder?: string;\n store?: SelectStoreApi;\n}) => {\n const store = useSelectStore(externalStore);\n\n const selectedLabel = useStore(store, (s) => s.selectedLabel);\n const value = useStore(store, (s) => s.value);\n return (\n <span className=\"text-inherit\">\n {selectedLabel || placeholder || value}\n </span>\n );\n};\n\ninterface SelectTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n className?: string;\n invalid?: boolean;\n variant?: 'outlined' | 'underlined' | 'rounded';\n store?: SelectStoreApi;\n}\n\nconst SelectTrigger = forwardRef<HTMLButtonElement, SelectTriggerProps>(\n (\n {\n className,\n invalid = false,\n variant = 'outlined',\n store: externalStore,\n disabled,\n ...props\n },\n ref\n ) => {\n const store = useSelectStore(externalStore);\n\n const open = useStore(store, (s) => s.open);\n const toggleOpen = () => store.setState({ open: !open });\n\n const variantClasses = VARIANT_CLASSES[variant];\n\n return (\n <button\n ref={ref}\n className={`\n flex h-9 min-w-[220px] w-full items-center justify-between border-border-300 px-3 py-2\n ${invalid && 'border-indicator-error text-text-600'}\n ${\n disabled\n ? 'cursor-not-allowed text-text-400 pointer-events-none opacity-50'\n : 'cursor-pointer hover:bg-background-50 focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground'\n }\n ${!invalid && !disabled ? 'text-text-700' : ''}\n ${variantClasses}\n ${className}\n `}\n onClick={toggleOpen}\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n aria-controls={open ? 'select-content' : undefined}\n {...props}\n >\n {props.children}\n <CaretDown\n className={`h-[1em] w-[1em] opacity-50 transition-transform ${open ? 'rotate-180' : ''}`}\n />\n </button>\n );\n }\n);\nSelectTrigger.displayName = 'SelectTrigger';\n\ninterface SelectContentProps extends HTMLAttributes<HTMLDivElement> {\n className?: string;\n align?: 'start' | 'center' | 'end';\n side?: 'top' | 'right' | 'bottom' | 'left';\n store?: SelectStoreApi;\n}\n\nconst SelectContent = forwardRef<HTMLDivElement, SelectContentProps>(\n (\n {\n children,\n className,\n align = 'start',\n side = 'bottom',\n store: externalStore,\n ...props\n },\n ref\n ) => {\n const store = useSelectStore(externalStore);\n\n const open = useStore(store, (s) => s.open);\n if (!open) return null;\n\n const getPositionClasses = () =>\n `w-full min-w-full absolute ${SIDE_CLASSES[side]} ${ALIGN_CLASSES[align]}`;\n\n return (\n <div\n role=\"menu\"\n ref={ref}\n className={`bg-background z-50 min-w-[210px] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md border-border-100 ${getPositionClasses()} ${className}`}\n {...props}\n >\n {children}\n </div>\n );\n }\n);\nSelectContent.displayName = 'SelectContent';\n\ninterface SelectItemProps extends HTMLAttributes<HTMLDivElement> {\n value: string;\n disabled?: boolean;\n store?: SelectStoreApi;\n}\n\nconst SelectItem = forwardRef<HTMLDivElement, SelectItemProps>(\n (\n {\n className,\n children,\n value,\n disabled = false,\n store: externalStore,\n ...props\n },\n ref\n ) => {\n const store = useSelectStore(externalStore);\n\n const selectedValue = useStore(store, (s) => s.value);\n const { setValue, setSelectedLabel, setOpen } = store.getState();\n\n const handleClick = (\n e: MouseEvent<HTMLDivElement> | KeyboardEvent<HTMLDivElement>\n ) => {\n const labelNode = getLabelAsNode(children);\n if (!disabled) {\n setValue(value);\n setSelectedLabel(labelNode);\n setOpen(false);\n }\n props.onClick?.(e as MouseEvent<HTMLDivElement>);\n };\n\n return (\n <div\n role=\"menuitem\"\n aria-disabled={disabled}\n ref={ref}\n className={`\n focus-visible:bg-background-50\n relative flex select-none items-center gap-2 rounded-sm p-3 outline-none transition-colors [&>svg]:size-4 [&>svg]:shrink-0\n ${className}\n ${\n disabled\n ? 'cursor-not-allowed text-text-400 pointer-events-none opacity-50'\n : 'cursor-pointer hover:bg-background-50 text-text-700 focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground'\n }\n ${selectedValue === value && 'bg-background-50'}\n `}\n onClick={handleClick}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') handleClick(e);\n }}\n tabIndex={disabled ? -1 : 0}\n {...props}\n >\n <span className=\"absolute right-2 flex h-3.5 w-3.5 items-center justify-center\">\n {selectedValue === value && <Check className=\"\" />}\n </span>\n {children}\n </div>\n );\n }\n);\n\nSelectItem.displayName = 'SelectItem';\n\nexport default Select;\nexport { SelectTrigger, SelectContent, SelectItem, SelectValue };\n"],"mappings":"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","names":["children"]}
@@ -0,0 +1,298 @@
1
+ // src/components/Select/Select.tsx
2
+ import { create, useStore } from "zustand";
3
+ import {
4
+ useEffect,
5
+ useRef,
6
+ forwardRef,
7
+ isValidElement,
8
+ Children,
9
+ cloneElement
10
+ } from "react";
11
+ import { CaretDown, Check } from "phosphor-react";
12
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
+ var VARIANT_CLASSES = {
14
+ outlined: "border-2 rounded-sm focus:border-primary-950",
15
+ underlined: "border-b-2 focus:border-primary-950",
16
+ rounded: "border-2 rounded-4xl focus:border-primary-950"
17
+ };
18
+ var SIZE_CLASSES = {
19
+ small: "text-sm",
20
+ medium: "text-md",
21
+ large: "text-lg"
22
+ };
23
+ var SIDE_CLASSES = {
24
+ top: "bottom-full -translate-y-1",
25
+ right: "top-full translate-y-1",
26
+ bottom: "top-full translate-y-1",
27
+ left: "top-full translate-y-1"
28
+ };
29
+ var ALIGN_CLASSES = {
30
+ start: "left-0",
31
+ center: "left-1/2 -translate-x-1/2",
32
+ end: "right-0"
33
+ };
34
+ function createSelectStore() {
35
+ return create((set) => ({
36
+ open: false,
37
+ setOpen: (open) => set({ open }),
38
+ value: "",
39
+ setValue: (value) => set({ value }),
40
+ selectedLabel: "",
41
+ setSelectedLabel: (label) => set({ selectedLabel: label })
42
+ }));
43
+ }
44
+ var useSelectStore = (externalStore) => {
45
+ if (!externalStore) {
46
+ throw new Error(
47
+ "Component must be used within a Select (store is missing)"
48
+ );
49
+ }
50
+ return externalStore;
51
+ };
52
+ function getLabelAsNode(children) {
53
+ if (typeof children === "string" || typeof children === "number") {
54
+ return children;
55
+ }
56
+ const flattened = Children.toArray(children);
57
+ if (flattened.length === 1) return flattened[0];
58
+ return /* @__PURE__ */ jsx(Fragment, { children: flattened });
59
+ }
60
+ var injectStore = (children, store) => {
61
+ return Children.map(children, (child) => {
62
+ if (isValidElement(child)) {
63
+ const typedChild = child;
64
+ const newProps = {
65
+ store
66
+ };
67
+ if (typedChild.props.children) {
68
+ newProps.children = injectStore(typedChild.props.children, store);
69
+ }
70
+ return cloneElement(typedChild, newProps);
71
+ }
72
+ return child;
73
+ });
74
+ };
75
+ var Select = ({
76
+ children,
77
+ defaultValue = "",
78
+ value: propValue,
79
+ onValueChange,
80
+ size = "small"
81
+ }) => {
82
+ const storeRef = useRef(null);
83
+ storeRef.current ??= createSelectStore();
84
+ const store = storeRef.current;
85
+ const selectRef = useRef(null);
86
+ const { open, setOpen, setValue, value, selectedLabel } = useStore(
87
+ store,
88
+ (s) => s
89
+ );
90
+ const isControlled = propValue !== void 0;
91
+ const currentValue = isControlled ? propValue : value;
92
+ const findLabelForValue = (children2, targetValue) => {
93
+ let found = null;
94
+ const search = (nodes) => {
95
+ Children.forEach(nodes, (child) => {
96
+ if (!isValidElement(child)) return;
97
+ const typedChild = child;
98
+ if (typedChild.type === SelectItem && typedChild.props.value === targetValue) {
99
+ if (typeof typedChild.props.children === "string")
100
+ found = typedChild.props.children;
101
+ }
102
+ if (typedChild.props.children && !found)
103
+ search(typedChild.props.children);
104
+ });
105
+ };
106
+ search(children2);
107
+ return found;
108
+ };
109
+ useEffect(() => {
110
+ if (!selectedLabel && defaultValue) {
111
+ const label = findLabelForValue(children, defaultValue);
112
+ if (label) store.setState({ selectedLabel: label });
113
+ }
114
+ }, [children, defaultValue, selectedLabel]);
115
+ useEffect(() => {
116
+ setValue(currentValue);
117
+ const handleClickOutside = (event) => {
118
+ if (selectRef.current && !selectRef.current.contains(event.target)) {
119
+ setOpen(false);
120
+ }
121
+ };
122
+ const handleArrowKeys = (event) => {
123
+ const selectContent = selectRef.current?.querySelector('[role="menu"]');
124
+ if (selectContent) {
125
+ event.preventDefault();
126
+ const items = Array.from(
127
+ selectContent.querySelectorAll(
128
+ '[role="menuitem"]:not([aria-disabled="true"])'
129
+ )
130
+ ).filter((el) => el instanceof HTMLElement);
131
+ const focused = document.activeElement;
132
+ const currentIndex = items.findIndex((item) => item === focused);
133
+ let nextIndex = 0;
134
+ if (event.key === "ArrowDown") {
135
+ nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % items.length;
136
+ } else {
137
+ nextIndex = currentIndex === -1 ? items.length - 1 : (currentIndex - 1 + items.length) % items.length;
138
+ }
139
+ items[nextIndex]?.focus();
140
+ }
141
+ };
142
+ if (open) {
143
+ document.addEventListener("mousedown", handleClickOutside);
144
+ document.addEventListener("keydown", handleArrowKeys);
145
+ }
146
+ return () => {
147
+ document.removeEventListener("mousedown", handleClickOutside);
148
+ document.removeEventListener("keydown", handleArrowKeys);
149
+ };
150
+ }, [open]);
151
+ useEffect(() => {
152
+ if (onValueChange) {
153
+ onValueChange(value);
154
+ }
155
+ }, [value]);
156
+ const sizeClasses = SIZE_CLASSES[size];
157
+ return /* @__PURE__ */ jsx("div", { className: `relative ${sizeClasses} w-[288px]`, ref: selectRef, children: injectStore(children, store) });
158
+ };
159
+ var SelectValue = ({
160
+ placeholder,
161
+ store: externalStore
162
+ }) => {
163
+ const store = useSelectStore(externalStore);
164
+ const selectedLabel = useStore(store, (s) => s.selectedLabel);
165
+ const value = useStore(store, (s) => s.value);
166
+ return /* @__PURE__ */ jsx("span", { className: "text-inherit", children: selectedLabel || placeholder || value });
167
+ };
168
+ var SelectTrigger = forwardRef(
169
+ ({
170
+ className,
171
+ invalid = false,
172
+ variant = "outlined",
173
+ store: externalStore,
174
+ disabled,
175
+ ...props
176
+ }, ref) => {
177
+ const store = useSelectStore(externalStore);
178
+ const open = useStore(store, (s) => s.open);
179
+ const toggleOpen = () => store.setState({ open: !open });
180
+ const variantClasses = VARIANT_CLASSES[variant];
181
+ return /* @__PURE__ */ jsxs(
182
+ "button",
183
+ {
184
+ ref,
185
+ className: `
186
+ flex h-9 min-w-[220px] w-full items-center justify-between border-border-300 px-3 py-2
187
+ ${invalid && "border-indicator-error text-text-600"}
188
+ ${disabled ? "cursor-not-allowed text-text-400 pointer-events-none opacity-50" : "cursor-pointer hover:bg-background-50 focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground"}
189
+ ${!invalid && !disabled ? "text-text-700" : ""}
190
+ ${variantClasses}
191
+ ${className}
192
+ `,
193
+ onClick: toggleOpen,
194
+ "aria-expanded": open,
195
+ "aria-haspopup": "listbox",
196
+ "aria-controls": open ? "select-content" : void 0,
197
+ ...props,
198
+ children: [
199
+ props.children,
200
+ /* @__PURE__ */ jsx(
201
+ CaretDown,
202
+ {
203
+ className: `h-[1em] w-[1em] opacity-50 transition-transform ${open ? "rotate-180" : ""}`
204
+ }
205
+ )
206
+ ]
207
+ }
208
+ );
209
+ }
210
+ );
211
+ SelectTrigger.displayName = "SelectTrigger";
212
+ var SelectContent = forwardRef(
213
+ ({
214
+ children,
215
+ className,
216
+ align = "start",
217
+ side = "bottom",
218
+ store: externalStore,
219
+ ...props
220
+ }, ref) => {
221
+ const store = useSelectStore(externalStore);
222
+ const open = useStore(store, (s) => s.open);
223
+ if (!open) return null;
224
+ const getPositionClasses = () => `w-full min-w-full absolute ${SIDE_CLASSES[side]} ${ALIGN_CLASSES[align]}`;
225
+ return /* @__PURE__ */ jsx(
226
+ "div",
227
+ {
228
+ role: "menu",
229
+ ref,
230
+ className: `bg-background z-50 min-w-[210px] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md border-border-100 ${getPositionClasses()} ${className}`,
231
+ ...props,
232
+ children
233
+ }
234
+ );
235
+ }
236
+ );
237
+ SelectContent.displayName = "SelectContent";
238
+ var SelectItem = forwardRef(
239
+ ({
240
+ className,
241
+ children,
242
+ value,
243
+ disabled = false,
244
+ store: externalStore,
245
+ ...props
246
+ }, ref) => {
247
+ const store = useSelectStore(externalStore);
248
+ const selectedValue = useStore(store, (s) => s.value);
249
+ const { setValue, setSelectedLabel, setOpen } = store.getState();
250
+ const handleClick = (e) => {
251
+ const labelNode = getLabelAsNode(children);
252
+ if (!disabled) {
253
+ setValue(value);
254
+ setSelectedLabel(labelNode);
255
+ setOpen(false);
256
+ }
257
+ props.onClick?.(e);
258
+ };
259
+ return /* @__PURE__ */ jsxs(
260
+ "div",
261
+ {
262
+ role: "menuitem",
263
+ "aria-disabled": disabled,
264
+ ref,
265
+ className: `
266
+ focus-visible:bg-background-50
267
+ relative flex select-none items-center gap-2 rounded-sm p-3 outline-none transition-colors [&>svg]:size-4 [&>svg]:shrink-0
268
+ ${className}
269
+ ${disabled ? "cursor-not-allowed text-text-400 pointer-events-none opacity-50" : "cursor-pointer hover:bg-background-50 text-text-700 focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground"}
270
+ ${selectedValue === value && "bg-background-50"}
271
+ `,
272
+ onClick: handleClick,
273
+ onKeyDown: (e) => {
274
+ if (e.key === "Enter" || e.key === " ") handleClick(e);
275
+ },
276
+ tabIndex: disabled ? -1 : 0,
277
+ ...props,
278
+ children: [
279
+ /* @__PURE__ */ jsx("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: selectedValue === value && /* @__PURE__ */ jsx(Check, { className: "" }) }),
280
+ children
281
+ ]
282
+ }
283
+ );
284
+ }
285
+ );
286
+ SelectItem.displayName = "SelectItem";
287
+ var Select_default = Select;
288
+ export {
289
+ SelectContent,
290
+ SelectItem,
291
+ SelectTrigger,
292
+ SelectValue,
293
+ createSelectStore,
294
+ Select_default as default,
295
+ getLabelAsNode,
296
+ useSelectStore
297
+ };
298
+ //# sourceMappingURL=index.mjs.map