@optigrit/optigrit-ui 0.0.1

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.
@@ -0,0 +1,8 @@
1
+ // src/theme/utils.ts
2
+ function colorMix(primaryColor = "", colorRatio = 100, secondaryColor = "transparent", secondaryColorRatio = 100) {
3
+ return `color-mix(in srgb, ${primaryColor} ${colorRatio}%, ${secondaryColor} ${secondaryColorRatio}%)`;
4
+ }
5
+
6
+ export {
7
+ colorMix
8
+ };
@@ -0,0 +1,48 @@
1
+ // src/theme/ThemeProvider.tsx
2
+ import { createContext, useContext, useEffect, useState } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var initialState = {
5
+ theme: "system",
6
+ setTheme: () => null
7
+ };
8
+ var ThemeProviderContext = createContext(initialState);
9
+ function ThemeProvider({
10
+ children,
11
+ defaultTheme = "system",
12
+ storageKey = "optigrit-ui-theme",
13
+ ...props
14
+ }) {
15
+ const [theme, setTheme] = useState(
16
+ () => localStorage.getItem(storageKey) || defaultTheme
17
+ );
18
+ useEffect(() => {
19
+ const root = window.document.documentElement;
20
+ root.classList.remove("light", "dark");
21
+ if (theme === "system") {
22
+ const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
23
+ root.classList.add(systemTheme);
24
+ return;
25
+ }
26
+ root.classList.add(theme);
27
+ }, [theme]);
28
+ const value = {
29
+ theme,
30
+ setTheme: (theme2) => {
31
+ localStorage.setItem(storageKey, theme2);
32
+ setTheme(theme2);
33
+ }
34
+ };
35
+ const Provider = ThemeProviderContext.Provider;
36
+ return /* @__PURE__ */ jsx(Provider, { ...props, value, children });
37
+ }
38
+ var useTheme = () => {
39
+ const context = useContext(ThemeProviderContext);
40
+ if (context === void 0)
41
+ throw new Error("useTheme must be used within a ThemeProvider");
42
+ return context;
43
+ };
44
+
45
+ export {
46
+ ThemeProvider,
47
+ useTheme
48
+ };
@@ -0,0 +1,69 @@
1
+ import * as react from 'react';
2
+ import { ButtonHTMLAttributes, ReactNode, HTMLAttributes, RefObject } from 'react';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { P as PopoverProps, a as InputProps } from '../Input-CL3wQvR_.js';
5
+
6
+ type ButtonVariant = "primary" | "secondary" | "outline" | "ghost" | "destructive" | "link";
7
+ type ButtonSize = "xs" | "sm" | "md" | "lg" | "xl";
8
+ type ButtonRoundness = "none" | "sm" | "md" | "lg" | "full";
9
+ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
10
+ variant?: ButtonVariant;
11
+ size?: ButtonSize;
12
+ roundness?: ButtonRoundness;
13
+ fullWidth?: boolean;
14
+ loading?: boolean;
15
+ leftIcon?: ReactNode;
16
+ rightIcon?: ReactNode;
17
+ iconOnly?: boolean;
18
+ disableRipple?: boolean;
19
+ }
20
+ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
21
+
22
+ type SIZE = "xs" | "sm" | "md" | "lg" | "xl";
23
+
24
+ type TooltipProps = HTMLAttributes<HTMLDivElement> & {
25
+ children: ReactNode;
26
+ label: ReactNode;
27
+ labelPosition?: PopoverProps['position'];
28
+ size?: SIZE | 'none';
29
+ labelContainerProps?: HTMLAttributes<HTMLDivElement>;
30
+ popoverProps?: Omit<PopoverProps, 'targetRef' | 'open' | 'onClose' | 'position' | 'children'>;
31
+ };
32
+ declare function Tooltip(props: TooltipProps): react_jsx_runtime.JSX.Element;
33
+
34
+ type InputFieldProps = {
35
+ value?: string;
36
+ errorColor?: string;
37
+ validateValue?: (value: string) => string | null;
38
+ onChangeValue?: (value: string) => void;
39
+ containerProps?: HTMLAttributes<HTMLDivElement> & {
40
+ ref: RefObject<HTMLDivElement | null>;
41
+ };
42
+ } & Omit<InputProps, 'value'>;
43
+ declare function InputField(props: InputFieldProps): react_jsx_runtime.JSX.Element;
44
+
45
+ type OPTION$1 = {
46
+ label: string;
47
+ value: string;
48
+ };
49
+ type SelectProps = {
50
+ options: OPTION$1[];
51
+ optionsPosition?: PopoverProps['position'];
52
+ renderOption?: (option: OPTION$1, isActive: boolean) => React.ReactNode;
53
+ } & Omit<InputFieldProps, 'readOnly' | 'onChange'>;
54
+ declare function Select(props: SelectProps): react_jsx_runtime.JSX.Element;
55
+
56
+ type OPTION = {
57
+ label: string;
58
+ value: string;
59
+ };
60
+ type MultiSelectProps = {
61
+ options: OPTION[];
62
+ value?: string[];
63
+ onChangeValue?: (value: string[]) => void;
64
+ optionsPosition?: PopoverProps['position'];
65
+ renderOption?: (option: OPTION, isActive: boolean) => React.ReactNode;
66
+ } & Omit<InputFieldProps, 'readOnly' | 'value' | 'onChange' | 'onChangeValue'>;
67
+ declare function MultiSelect(props: MultiSelectProps): react_jsx_runtime.JSX.Element;
68
+
69
+ export { Button, type ButtonProps, type ButtonRoundness, type ButtonSize, type ButtonVariant, InputField, type InputFieldProps, MultiSelect, type MultiSelectProps, Select, type SelectProps, Tooltip, type TooltipProps };
@@ -0,0 +1,575 @@
1
+ import {
2
+ Input,
3
+ Popover,
4
+ cn
5
+ } from "../chunk-2LJSVQ6B.js";
6
+ import "../chunk-MCQS3QNN.js";
7
+ import {
8
+ useKeyboardShortcuts
9
+ } from "../chunk-KBOYMK4Y.js";
10
+ import "../chunk-U65NGM6F.js";
11
+
12
+ // src/components/Buttons/Button/index.tsx
13
+ import {
14
+ forwardRef,
15
+ useCallback
16
+ } from "react";
17
+ import { jsx, jsxs } from "react/jsx-runtime";
18
+ var variantClasses = {
19
+ primary: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
20
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
21
+ outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
22
+ ghost: "hover:bg-accent hover:text-accent-foreground",
23
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
24
+ link: "text-primary underline-offset-4 hover:underline"
25
+ };
26
+ var sizeClasses = {
27
+ xs: "text-xs px-2 py-1 gap-1",
28
+ sm: "text-sm px-3 py-1.5 gap-1.5",
29
+ md: "text-sm px-4 py-2 gap-2",
30
+ lg: "text-base px-5 py-2.5 gap-2.5",
31
+ xl: "text-lg px-6 py-3 gap-3"
32
+ };
33
+ var iconOnlySizeClasses = {
34
+ xs: "text-xs p-1",
35
+ sm: "text-sm p-1.5",
36
+ md: "text-sm p-2",
37
+ lg: "text-base p-2.5",
38
+ xl: "text-lg p-3"
39
+ };
40
+ var roundnessClasses = {
41
+ none: "rounded-none",
42
+ sm: "rounded-sm",
43
+ md: "rounded-md",
44
+ lg: "rounded-lg",
45
+ full: "rounded-full"
46
+ };
47
+ function Spinner({ className = "" }) {
48
+ return /* @__PURE__ */ jsxs(
49
+ "svg",
50
+ {
51
+ className: `animate-spin ${className}`,
52
+ xmlns: "http://www.w3.org/2000/svg",
53
+ fill: "none",
54
+ viewBox: "0 0 24 24",
55
+ "aria-hidden": "true",
56
+ children: [
57
+ /* @__PURE__ */ jsx(
58
+ "circle",
59
+ {
60
+ className: "opacity-25",
61
+ cx: "12",
62
+ cy: "12",
63
+ r: "10",
64
+ stroke: "currentColor",
65
+ strokeWidth: "4"
66
+ }
67
+ ),
68
+ /* @__PURE__ */ jsx(
69
+ "path",
70
+ {
71
+ className: "opacity-75",
72
+ fill: "currentColor",
73
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
74
+ }
75
+ )
76
+ ]
77
+ }
78
+ );
79
+ }
80
+ function cn2(...classes) {
81
+ return classes.filter(Boolean).join(" ");
82
+ }
83
+ var rippleColor = {
84
+ primary: "rgba(255, 255, 255, 0.45)",
85
+ secondary: "rgba(0, 0, 0, 0.12)",
86
+ outline: "rgba(0, 0, 0, 0.10)",
87
+ ghost: "rgba(0, 0, 0, 0.10)",
88
+ destructive: "rgba(255, 255, 255, 0.45)",
89
+ link: "rgba(0, 0, 0, 0.10)"
90
+ };
91
+ var Button = forwardRef(
92
+ ({
93
+ variant = "primary",
94
+ size = "md",
95
+ roundness = "md",
96
+ fullWidth = false,
97
+ loading = false,
98
+ leftIcon,
99
+ rightIcon,
100
+ iconOnly = false,
101
+ disableRipple = false,
102
+ disabled,
103
+ className,
104
+ children,
105
+ type = "button",
106
+ onClick,
107
+ ...rest
108
+ }, ref) => {
109
+ const isDisabled = disabled || loading;
110
+ const spinnerSize = {
111
+ xs: "h-3 w-3",
112
+ sm: "h-3.5 w-3.5",
113
+ md: "h-4 w-4",
114
+ lg: "h-5 w-5",
115
+ xl: "h-5 w-5"
116
+ };
117
+ const handleClick = useCallback(
118
+ (e) => {
119
+ if (!disableRipple) {
120
+ const button = e.currentTarget;
121
+ const rect = button.getBoundingClientRect();
122
+ const diameter = Math.max(button.clientWidth, button.clientHeight);
123
+ const radius = diameter / 2;
124
+ const circle = document.createElement("span");
125
+ circle.style.position = "absolute";
126
+ circle.style.width = `${diameter}px`;
127
+ circle.style.height = `${diameter}px`;
128
+ circle.style.left = `${e.clientX - rect.left - radius}px`;
129
+ circle.style.top = `${e.clientY - rect.top - radius}px`;
130
+ circle.style.borderRadius = "9999px";
131
+ circle.style.pointerEvents = "none";
132
+ circle.style.backgroundColor = rippleColor[variant];
133
+ button.appendChild(circle);
134
+ const anim = circle.animate(
135
+ [
136
+ { transform: "scale(0)", opacity: "1" },
137
+ { transform: "scale(4)", opacity: "0" }
138
+ ],
139
+ { duration: 600, easing: "linear" }
140
+ );
141
+ anim.onfinish = () => circle.remove();
142
+ }
143
+ onClick?.(e);
144
+ },
145
+ [disableRipple, variant, onClick]
146
+ );
147
+ return /* @__PURE__ */ jsxs(
148
+ "button",
149
+ {
150
+ ref,
151
+ type,
152
+ disabled: isDisabled,
153
+ "aria-busy": loading || void 0,
154
+ onClick: handleClick,
155
+ className: cn2(
156
+ "relative overflow-hidden inline-flex items-center justify-center font-medium transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
157
+ isDisabled && "pointer-events-none opacity-50",
158
+ variantClasses[variant],
159
+ iconOnly ? iconOnlySizeClasses[size] : sizeClasses[size],
160
+ roundnessClasses[roundness],
161
+ fullWidth && "w-full",
162
+ className
163
+ ),
164
+ ...rest,
165
+ children: [
166
+ loading && /* @__PURE__ */ jsx(Spinner, { className: spinnerSize[size] }),
167
+ !loading && leftIcon && /* @__PURE__ */ jsx("span", { className: "inline-flex shrink-0", children: leftIcon }),
168
+ children,
169
+ !loading && rightIcon && /* @__PURE__ */ jsx("span", { className: "inline-flex shrink-0", children: rightIcon })
170
+ ]
171
+ }
172
+ );
173
+ }
174
+ );
175
+ Button.displayName = "Button";
176
+ var Button_default = Button;
177
+
178
+ // src/components/Feedback/Tooltip/Tooltip.tsx
179
+ import { useRef, useState } from "react";
180
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
181
+ function Tooltip(props) {
182
+ const {
183
+ label,
184
+ labelPosition = "bottom-center",
185
+ children,
186
+ className,
187
+ size = "sm",
188
+ labelContainerProps = {},
189
+ popoverProps = {},
190
+ ...containerProps
191
+ } = props;
192
+ const container = useRef(null);
193
+ const [open, setOpen] = useState(false);
194
+ return /* @__PURE__ */ jsxs2(
195
+ "div",
196
+ {
197
+ ...containerProps,
198
+ ref: container,
199
+ className: cn("cursor-pointer", className),
200
+ onMouseEnter: () => setOpen(true),
201
+ onMouseLeave: () => setOpen(false),
202
+ children: [
203
+ children,
204
+ /* @__PURE__ */ jsx2(
205
+ Popover,
206
+ {
207
+ ...popoverProps,
208
+ open,
209
+ targetRef: container,
210
+ position: labelPosition,
211
+ className: cn("p-1", popoverProps.className),
212
+ children: /* @__PURE__ */ jsx2(
213
+ "div",
214
+ {
215
+ ...labelContainerProps,
216
+ className: cn(
217
+ "bg-black text-white",
218
+ size !== "none" ? `text-${size} rounded-${size}` : "",
219
+ {
220
+ xs: "py-1 px-2",
221
+ sm: "py-2 px-4",
222
+ md: "py-3 px-6",
223
+ lg: "py-4 px-8",
224
+ xl: "py-5 px-10",
225
+ none: "py-0 px-0"
226
+ }[size],
227
+ labelContainerProps.className
228
+ ),
229
+ children: label
230
+ }
231
+ )
232
+ }
233
+ )
234
+ ]
235
+ }
236
+ );
237
+ }
238
+
239
+ // src/components/Forms/InputField/InputField.tsx
240
+ import { useLayoutEffect, useRef as useRef2, useState as useState2 } from "react";
241
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
242
+ function InputField(props) {
243
+ const {
244
+ validateValue,
245
+ onChangeValue,
246
+ containerProps = {},
247
+ errorColor = "rgb(240, 70, 70)",
248
+ ...inputProps
249
+ } = props;
250
+ const initRef = useRef2({ isUserTyped: false });
251
+ const [error, setError] = useState2("");
252
+ function handleError(value) {
253
+ if (!initRef.current.isUserTyped) return;
254
+ setError(() => {
255
+ const error2 = validateValue?.(value);
256
+ if (error2) return error2;
257
+ if (props.required && !value)
258
+ return "This field is required!";
259
+ return "";
260
+ });
261
+ }
262
+ function handleOnChange(event) {
263
+ onChangeValue?.(event.target.value);
264
+ handleError(event.target.value);
265
+ props.onChange?.(event);
266
+ }
267
+ function handleOnBlur(event) {
268
+ initRef.current.isUserTyped = true;
269
+ handleError(event.target.value);
270
+ props.onBlur?.(event);
271
+ }
272
+ function handleOnFocus(event) {
273
+ props.onFocus?.(event);
274
+ }
275
+ useLayoutEffect(() => {
276
+ if (props.value) {
277
+ initRef.current.isUserTyped = true;
278
+ handleError(props.value);
279
+ }
280
+ }, [props.value]);
281
+ return /* @__PURE__ */ jsxs3("div", { ...containerProps, children: [
282
+ /* @__PURE__ */ jsx3(
283
+ Input,
284
+ {
285
+ ...inputProps,
286
+ textColor: error ? errorColor : inputProps.textColor,
287
+ borderColor: error ? errorColor : inputProps.borderColor,
288
+ primaryColor: error ? errorColor : inputProps.primaryColor,
289
+ onChange: handleOnChange,
290
+ onFocus: handleOnFocus,
291
+ onBlur: handleOnBlur
292
+ }
293
+ ),
294
+ /* @__PURE__ */ jsx3("p", { className: "pl-1 text-xs", style: { color: errorColor, display: error ? "block" : "none" }, children: error })
295
+ ] });
296
+ }
297
+
298
+ // src/components/Forms/Select/index.tsx
299
+ import { Fragment, useRef as useRef3, useState as useState3 } from "react";
300
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
301
+ function Select(props) {
302
+ const {
303
+ options = [{ label: "None", value: "" }],
304
+ renderOption,
305
+ optionsPosition = "bottom-start",
306
+ ...inputProps
307
+ } = props;
308
+ const container = useRef3(null);
309
+ const optionsContainer = useRef3(null);
310
+ const [isOpen, setIsOpen] = useState3(false);
311
+ const [activeOption, setActiveOption] = useState3("");
312
+ useKeyboardShortcuts([
313
+ {
314
+ key: "ArrowDown",
315
+ callback: () => handleKeyboardNavigation("ArrowDown"),
316
+ options: { preventDefault: isOpen }
317
+ },
318
+ {
319
+ key: "ArrowUp",
320
+ callback: () => handleKeyboardNavigation("ArrowUp"),
321
+ options: { preventDefault: isOpen }
322
+ },
323
+ {
324
+ key: "Enter",
325
+ callback: () => {
326
+ if (isOpen) {
327
+ const option = options.find((option2) => option2.value === activeOption);
328
+ if (option) handleOnChange(option);
329
+ setActiveOption("");
330
+ }
331
+ },
332
+ options: { preventDefault: isOpen }
333
+ },
334
+ {
335
+ key: "Escape",
336
+ callback: () => {
337
+ if (isOpen) {
338
+ setIsOpen(false);
339
+ setActiveOption("");
340
+ }
341
+ },
342
+ options: { preventDefault: isOpen }
343
+ }
344
+ ]);
345
+ function handleKeyboardNavigation(key) {
346
+ if (isOpen) {
347
+ setActiveOption((pre) => {
348
+ const currentIndex = options.findIndex((option) => option.value === pre);
349
+ const nextIndex = (currentIndex + (key === "ArrowDown" ? 1 : -1) + options.length) % options.length;
350
+ const optionNode = optionsContainer.current?.querySelector(`#${options[nextIndex].value}`);
351
+ optionNode?.scrollIntoView({ block: "nearest" });
352
+ const value = options[nextIndex].value;
353
+ setActiveOption(value);
354
+ return value;
355
+ });
356
+ }
357
+ }
358
+ function handleOnChange(options2) {
359
+ setIsOpen(false);
360
+ props.onChangeValue?.(options2.value);
361
+ setActiveOption("");
362
+ const input = container.current?.querySelector("input");
363
+ if (input) input.value = options2.label;
364
+ }
365
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
366
+ /* @__PURE__ */ jsx4(
367
+ InputField,
368
+ {
369
+ ...inputProps,
370
+ readOnly: true,
371
+ value: options.find((option) => option.value === props.value)?.label || void 0,
372
+ containerProps: {
373
+ ref: container,
374
+ className: "[&_*]:cursor-pointer",
375
+ onClick: () => setIsOpen(true)
376
+ },
377
+ onBlur: (event) => {
378
+ setIsOpen(false);
379
+ inputProps.onBlur?.(event);
380
+ },
381
+ endIcon: props.endIcon ? props.endIcon : /* @__PURE__ */ jsx4("div", { className: "relative h-full aspect-square pr-1 flex items-center justify-center", children: /* @__PURE__ */ jsx4("div", { className: cn(
382
+ "w-0 h-0 border-l-[5px] border-r-[5px] border-t-[5px] border-l-transparent border-r-transparent border-t-gray-600",
383
+ isOpen ? "rotate-180" : ""
384
+ ) }) })
385
+ }
386
+ ),
387
+ /* @__PURE__ */ jsx4(
388
+ Popover,
389
+ {
390
+ open: isOpen,
391
+ targetRef: container,
392
+ position: optionsPosition,
393
+ className: "p-1 min-h-[100px]",
394
+ onClose: () => {
395
+ setIsOpen(false);
396
+ },
397
+ onOpen: (node) => {
398
+ node.style.minWidth = `${container.current?.offsetWidth ?? 0}px`;
399
+ },
400
+ children: /* @__PURE__ */ jsx4(
401
+ "div",
402
+ {
403
+ ref: optionsContainer,
404
+ className: "w-full max-h-[200px] overflow-y-scroll scrollbar-hide [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden bg-zinc-200 p-1 rounded-md flex flex-col gap-1",
405
+ onMouseDown: (event) => {
406
+ event.preventDefault();
407
+ },
408
+ children: options.map((option) => renderOption ? renderOption(option, activeOption === option.value) : /* @__PURE__ */ jsx4(
409
+ "div",
410
+ {
411
+ id: option.value,
412
+ onClick: () => handleOnChange(option),
413
+ className: cn(
414
+ "p-2 hover:bg-gray-100 rounded cursor-pointer w-full",
415
+ activeOption === option.value ? "border-2 border-blue-500" : "",
416
+ option.value === props.value ? "bg-white" : ""
417
+ ),
418
+ children: option.label
419
+ },
420
+ option.value
421
+ ))
422
+ }
423
+ )
424
+ }
425
+ )
426
+ ] });
427
+ }
428
+
429
+ // src/components/Forms/MultiSelect/index.tsx
430
+ import { Fragment as Fragment2, useRef as useRef4, useState as useState4 } from "react";
431
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
432
+ function MultiSelect(props) {
433
+ const {
434
+ renderOption,
435
+ onChangeValue,
436
+ value = [],
437
+ options = [{ label: "None", value: "" }],
438
+ optionsPosition = "bottom-start",
439
+ ...inputProps
440
+ } = props;
441
+ const labelMap = new Map(options.map((option) => [option.value, option.label]));
442
+ const container = useRef4(null);
443
+ const optionsContainer = useRef4(null);
444
+ const [isOpen, setIsOpen] = useState4(false);
445
+ const [activeOption, setActiveOption] = useState4("");
446
+ useKeyboardShortcuts([
447
+ {
448
+ key: "ArrowDown",
449
+ callback: () => handleKeyboardNavigation("ArrowDown"),
450
+ options: { preventDefault: isOpen }
451
+ },
452
+ {
453
+ key: "ArrowUp",
454
+ callback: () => handleKeyboardNavigation("ArrowUp"),
455
+ options: { preventDefault: isOpen }
456
+ },
457
+ {
458
+ key: "Enter",
459
+ callback: () => {
460
+ if (isOpen) {
461
+ const option = options?.find((option2) => option2.value === activeOption);
462
+ if (option) handleOnChange(option);
463
+ setActiveOption("");
464
+ }
465
+ },
466
+ options: { preventDefault: isOpen }
467
+ },
468
+ {
469
+ key: "Escape",
470
+ callback: () => {
471
+ if (isOpen) {
472
+ setIsOpen(false);
473
+ setActiveOption("");
474
+ }
475
+ },
476
+ options: { preventDefault: isOpen }
477
+ }
478
+ ]);
479
+ function handleKeyboardNavigation(key) {
480
+ if (isOpen) {
481
+ setActiveOption((pre) => {
482
+ const currentIndex = options.findIndex((option) => option.value === pre);
483
+ const nextIndex = (currentIndex + (key === "ArrowDown" ? 1 : -1) + options.length) % options.length;
484
+ const optionNode = optionsContainer.current?.querySelector(`#${options[nextIndex].value}`);
485
+ optionNode?.scrollIntoView({ block: "nearest" });
486
+ const value2 = options[nextIndex].value;
487
+ setActiveOption(value2);
488
+ return value2;
489
+ });
490
+ }
491
+ }
492
+ function handleOnChange(option) {
493
+ setIsOpen(false);
494
+ const newValue = (() => {
495
+ if (props.value?.includes(option.value)) {
496
+ return props.value?.filter((val) => val !== option.value);
497
+ } else {
498
+ return [...props.value || [], option.value];
499
+ }
500
+ })();
501
+ onChangeValue?.(newValue);
502
+ setActiveOption("");
503
+ const input = container.current?.querySelector("input");
504
+ if (input) input.value = newValue.map((value2) => labelMap.get(value2)).join(", ") || "";
505
+ }
506
+ return /* @__PURE__ */ jsxs5(Fragment2, { children: [
507
+ /* @__PURE__ */ jsx5(
508
+ InputField,
509
+ {
510
+ ...inputProps,
511
+ readOnly: true,
512
+ value: props.value?.map((value2) => labelMap.get(value2)).join(", ") || void 0,
513
+ containerProps: {
514
+ ref: container,
515
+ className: "[&_*]:cursor-pointer",
516
+ onClick: () => setIsOpen(true)
517
+ },
518
+ onBlur: (event) => {
519
+ setIsOpen(false);
520
+ inputProps.onBlur?.(event);
521
+ },
522
+ endIcon: props.endIcon ? props.endIcon : /* @__PURE__ */ jsx5("div", { className: "relative h-full aspect-square pr-1 flex items-center justify-center", children: /* @__PURE__ */ jsx5("div", { className: cn(
523
+ "w-0 h-0 border-l-[5px] border-r-[5px] border-t-[5px] border-l-transparent border-r-transparent border-t-gray-600",
524
+ isOpen ? "rotate-180" : ""
525
+ ) }) })
526
+ }
527
+ ),
528
+ /* @__PURE__ */ jsx5(
529
+ Popover,
530
+ {
531
+ open: isOpen,
532
+ targetRef: container,
533
+ position: optionsPosition,
534
+ className: "p-1 min-h-[100px]",
535
+ onClose: () => {
536
+ setIsOpen(false);
537
+ },
538
+ onOpen: (node) => {
539
+ node.style.minWidth = `${container.current?.offsetWidth ?? 0}px`;
540
+ },
541
+ children: /* @__PURE__ */ jsx5(
542
+ "div",
543
+ {
544
+ ref: optionsContainer,
545
+ className: "w-full max-h-[200px] overflow-y-scroll scrollbar-hide [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden bg-zinc-200 p-1 rounded-md flex flex-col gap-1",
546
+ onMouseDown: (event) => {
547
+ event.preventDefault();
548
+ },
549
+ children: options.map((option) => renderOption ? renderOption(option, activeOption === option.value) : /* @__PURE__ */ jsx5(
550
+ "div",
551
+ {
552
+ id: option.value,
553
+ onClick: () => handleOnChange(option),
554
+ className: cn(
555
+ "p-2 hover:bg-gray-100 rounded cursor-pointer w-full",
556
+ activeOption === option.value ? "border-2 border-blue-500" : "",
557
+ props.value?.includes(option.value) ? "bg-white" : ""
558
+ ),
559
+ children: option.label
560
+ },
561
+ option.value
562
+ ))
563
+ }
564
+ )
565
+ }
566
+ )
567
+ ] });
568
+ }
569
+ export {
570
+ Button_default as Button,
571
+ InputField,
572
+ MultiSelect,
573
+ Select,
574
+ Tooltip
575
+ };