@luxfi/ui 1.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.
Files changed (124) hide show
  1. package/dist/accordion.cjs +213 -0
  2. package/dist/accordion.js +186 -0
  3. package/dist/alert.cjs +553 -0
  4. package/dist/alert.js +531 -0
  5. package/dist/avatar.cjs +149 -0
  6. package/dist/avatar.js +125 -0
  7. package/dist/badge.cjs +611 -0
  8. package/dist/badge.js +589 -0
  9. package/dist/button.cjs +689 -0
  10. package/dist/button.js +664 -0
  11. package/dist/checkbox.cjs +265 -0
  12. package/dist/checkbox.js +241 -0
  13. package/dist/close-button.cjs +73 -0
  14. package/dist/close-button.js +51 -0
  15. package/dist/collapsible.cjs +711 -0
  16. package/dist/collapsible.js +685 -0
  17. package/dist/color-mode.cjs +36 -0
  18. package/dist/color-mode.js +32 -0
  19. package/dist/dialog.cjs +279 -0
  20. package/dist/dialog.js +246 -0
  21. package/dist/drawer.cjs +207 -0
  22. package/dist/drawer.js +175 -0
  23. package/dist/empty-state.cjs +93 -0
  24. package/dist/empty-state.js +71 -0
  25. package/dist/field.cjs +183 -0
  26. package/dist/field.js +160 -0
  27. package/dist/heading.cjs +46 -0
  28. package/dist/heading.js +40 -0
  29. package/dist/icon-button.cjs +491 -0
  30. package/dist/icon-button.js +470 -0
  31. package/dist/image.cjs +572 -0
  32. package/dist/image.js +551 -0
  33. package/dist/index.cjs +5749 -0
  34. package/dist/index.js +5586 -0
  35. package/dist/input-group.cjs +155 -0
  36. package/dist/input-group.js +133 -0
  37. package/dist/input.cjs +65 -0
  38. package/dist/input.js +59 -0
  39. package/dist/link.cjs +639 -0
  40. package/dist/link.js +612 -0
  41. package/dist/menu.cjs +305 -0
  42. package/dist/menu.js +269 -0
  43. package/dist/pin-input.cjs +182 -0
  44. package/dist/pin-input.js +160 -0
  45. package/dist/popover.cjs +327 -0
  46. package/dist/popover.js +294 -0
  47. package/dist/progress-circle.cjs +152 -0
  48. package/dist/progress-circle.js +128 -0
  49. package/dist/progress.cjs +117 -0
  50. package/dist/progress.js +94 -0
  51. package/dist/provider.cjs +22 -0
  52. package/dist/provider.js +20 -0
  53. package/dist/radio.cjs +177 -0
  54. package/dist/radio.js +153 -0
  55. package/dist/rating.cjs +80 -0
  56. package/dist/rating.js +58 -0
  57. package/dist/select.cjs +791 -0
  58. package/dist/select.js +757 -0
  59. package/dist/separator.cjs +57 -0
  60. package/dist/separator.js +51 -0
  61. package/dist/skeleton.cjs +370 -0
  62. package/dist/skeleton.js +346 -0
  63. package/dist/slider.cjs +138 -0
  64. package/dist/slider.js +115 -0
  65. package/dist/switch.cjs +163 -0
  66. package/dist/switch.js +140 -0
  67. package/dist/table.cjs +1053 -0
  68. package/dist/table.js +1019 -0
  69. package/dist/tabs.cjs +240 -0
  70. package/dist/tabs.js +213 -0
  71. package/dist/tag.cjs +651 -0
  72. package/dist/tag.js +628 -0
  73. package/dist/textarea.cjs +65 -0
  74. package/dist/textarea.js +59 -0
  75. package/dist/toaster.cjs +99 -0
  76. package/dist/toaster.js +96 -0
  77. package/dist/tooltip.cjs +171 -0
  78. package/dist/tooltip.js +148 -0
  79. package/dist/utils.cjs +11 -0
  80. package/dist/utils.js +9 -0
  81. package/package.json +296 -0
  82. package/src/accordion.tsx +285 -0
  83. package/src/alert.tsx +221 -0
  84. package/src/avatar.tsx +174 -0
  85. package/src/badge.tsx +158 -0
  86. package/src/button.tsx +411 -0
  87. package/src/checkbox.tsx +307 -0
  88. package/src/close-button.tsx +51 -0
  89. package/src/collapsible.tsx +126 -0
  90. package/src/color-mode.tsx +37 -0
  91. package/src/dialog.tsx +356 -0
  92. package/src/drawer.tsx +186 -0
  93. package/src/empty-state.tsx +97 -0
  94. package/src/field.tsx +202 -0
  95. package/src/heading.tsx +55 -0
  96. package/src/icon-button.tsx +192 -0
  97. package/src/image.tsx +280 -0
  98. package/src/index.ts +192 -0
  99. package/src/input-group.tsx +159 -0
  100. package/src/input.tsx +60 -0
  101. package/src/link.tsx +333 -0
  102. package/src/menu.tsx +471 -0
  103. package/src/pin-input.tsx +187 -0
  104. package/src/popover.tsx +400 -0
  105. package/src/progress-circle.tsx +180 -0
  106. package/src/progress.tsx +109 -0
  107. package/src/provider.tsx +12 -0
  108. package/src/radio.tsx +175 -0
  109. package/src/rating.tsx +79 -0
  110. package/src/select.tsx +696 -0
  111. package/src/separator.tsx +59 -0
  112. package/src/skeleton.tsx +302 -0
  113. package/src/slider.tsx +152 -0
  114. package/src/switch.tsx +158 -0
  115. package/src/table.tsx +621 -0
  116. package/src/tabs.tsx +354 -0
  117. package/src/tag.tsx +159 -0
  118. package/src/textarea.tsx +60 -0
  119. package/src/toaster.tsx +117 -0
  120. package/src/tokens.css +438 -0
  121. package/src/tooltip.tsx +184 -0
  122. package/src/utils/cn.ts +7 -0
  123. package/src/utils.ts +6 -0
  124. package/tokens.css +438 -0
package/dist/select.js ADDED
@@ -0,0 +1,757 @@
1
+ "use client";
2
+ import * as RadixSelect from '@radix-ui/react-select';
3
+ import { useDebounce } from '@uidotdev/usehooks';
4
+ import * as React2 from 'react';
5
+ import { clsx } from 'clsx';
6
+ import { twMerge } from 'tailwind-merge';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+
9
+ function cn(...inputs) {
10
+ return twMerge(clsx(inputs));
11
+ }
12
+ var SPACING_SCALE = 4;
13
+ function toStylePx(value) {
14
+ if (value === void 0) return void 0;
15
+ if (typeof value === "string") return value;
16
+ return `${value * SPACING_SCALE}px`;
17
+ }
18
+ function extractSkeletonStyleProps(props) {
19
+ const style = {};
20
+ const rest = {};
21
+ function resolveDimension(value) {
22
+ if (value === void 0 || value === null) return void 0;
23
+ if (typeof value === "number") return `${value * SPACING_SCALE}px`;
24
+ if (typeof value === "string") return value;
25
+ if (typeof value === "object") {
26
+ const obj = value;
27
+ return obj.base ?? obj.lg ?? obj.xl ?? Object.values(obj)[0];
28
+ }
29
+ return void 0;
30
+ }
31
+ for (const [key, value] of Object.entries(props)) {
32
+ if (value === void 0) continue;
33
+ switch (key) {
34
+ case "w": {
35
+ const v = resolveDimension(value);
36
+ if (v) style.width = v;
37
+ break;
38
+ }
39
+ case "h": {
40
+ const v = resolveDimension(value);
41
+ if (v) style.height = v;
42
+ break;
43
+ }
44
+ case "minW": {
45
+ const v = resolveDimension(value);
46
+ if (v) style.minWidth = v;
47
+ break;
48
+ }
49
+ case "maxW": {
50
+ const v = resolveDimension(value);
51
+ if (v) style.maxWidth = v;
52
+ break;
53
+ }
54
+ case "height":
55
+ style.height = value;
56
+ break;
57
+ case "display":
58
+ style.display = value;
59
+ break;
60
+ case "flexGrow":
61
+ style.flexGrow = value;
62
+ break;
63
+ case "flexShrink":
64
+ style.flexShrink = value;
65
+ break;
66
+ case "flexBasis":
67
+ style.flexBasis = value;
68
+ break;
69
+ case "fontWeight":
70
+ style.fontWeight = value;
71
+ break;
72
+ case "borderRadius":
73
+ style.borderRadius = value;
74
+ break;
75
+ case "alignSelf":
76
+ style.alignSelf = value;
77
+ break;
78
+ case "alignItems":
79
+ style.alignItems = value;
80
+ break;
81
+ case "justifyContent":
82
+ style.justifyContent = value;
83
+ break;
84
+ case "color":
85
+ style.color = value;
86
+ break;
87
+ case "mt":
88
+ style.marginTop = toStylePx(value);
89
+ break;
90
+ case "mb":
91
+ style.marginBottom = toStylePx(value);
92
+ break;
93
+ case "ml":
94
+ style.marginLeft = toStylePx(value);
95
+ break;
96
+ case "mr":
97
+ style.marginRight = toStylePx(value);
98
+ break;
99
+ case "overflow":
100
+ style.overflow = value;
101
+ break;
102
+ case "whiteSpace":
103
+ style.whiteSpace = value;
104
+ break;
105
+ case "textOverflow":
106
+ style.textOverflow = value;
107
+ break;
108
+ case "textTransform":
109
+ style.textTransform = value;
110
+ break;
111
+ case "gap":
112
+ style.gap = typeof value === "number" ? `${value * SPACING_SCALE}px` : value;
113
+ break;
114
+ case "gridTemplateColumns":
115
+ style.gridTemplateColumns = value;
116
+ break;
117
+ case "minWidth":
118
+ style.minWidth = value;
119
+ break;
120
+ case "boxSize": {
121
+ const s = typeof value === "number" ? `${value * SPACING_SCALE}px` : value;
122
+ style.width = s;
123
+ style.height = s;
124
+ break;
125
+ }
126
+ case "py": {
127
+ const v = toStylePx(value);
128
+ style.paddingTop = v;
129
+ style.paddingBottom = v;
130
+ break;
131
+ }
132
+ case "px": {
133
+ const v = toStylePx(value);
134
+ style.paddingLeft = v;
135
+ style.paddingRight = v;
136
+ break;
137
+ }
138
+ case "p": {
139
+ const v = toStylePx(value);
140
+ style.padding = v;
141
+ break;
142
+ }
143
+ case "hideBelow":
144
+ break;
145
+ // handled via className
146
+ case "textStyle":
147
+ break;
148
+ // drop textStyle, not directly applicable
149
+ case "fontSize":
150
+ style.fontSize = value;
151
+ break;
152
+ case "flexWrap":
153
+ style.flexWrap = value;
154
+ break;
155
+ case "wordBreak":
156
+ style.wordBreak = value;
157
+ break;
158
+ case "lineHeight":
159
+ style.lineHeight = value;
160
+ break;
161
+ case "marginRight":
162
+ style.marginRight = value;
163
+ break;
164
+ case "position":
165
+ style.position = value;
166
+ break;
167
+ case "background":
168
+ style.background = value;
169
+ break;
170
+ default:
171
+ rest[key] = value;
172
+ break;
173
+ }
174
+ }
175
+ return { style, rest };
176
+ }
177
+ var Skeleton = React2.forwardRef(
178
+ function Skeleton2(props, ref) {
179
+ const {
180
+ loading = false,
181
+ asChild,
182
+ className,
183
+ children,
184
+ style: styleProp,
185
+ // Destructure style-prop shims so they don't leak into DOM
186
+ w: _w,
187
+ h: _h,
188
+ minW: _minW,
189
+ maxW: _maxW,
190
+ display: _display,
191
+ flexGrow: _flexGrow,
192
+ flexShrink: _flexShrink,
193
+ flexBasis: _flexBasis,
194
+ fontWeight: _fontWeight,
195
+ textStyle: _textStyle,
196
+ borderRadius: _borderRadius,
197
+ alignSelf: _alignSelf,
198
+ alignItems: _alignItems,
199
+ justifyContent: _justifyContent,
200
+ color: _color,
201
+ mt: _mt,
202
+ mb: _mb,
203
+ ml: _ml,
204
+ mr: _mr,
205
+ height: _height,
206
+ overflow: _overflow,
207
+ whiteSpace: _whiteSpace,
208
+ textOverflow: _textOverflow,
209
+ textTransform: _textTransform,
210
+ gap: _gap,
211
+ gridTemplateColumns: _gridTemplateColumns,
212
+ minWidth: _minWidth,
213
+ boxSize: _boxSize,
214
+ py: _py,
215
+ px: _px,
216
+ p: _p,
217
+ hideBelow: _hideBelow,
218
+ fontSize: _fontSize,
219
+ flexWrap: _flexWrap,
220
+ wordBreak: _wordBreak,
221
+ lineHeight: _lineHeight,
222
+ marginRight: _marginRight,
223
+ position: _position,
224
+ background: _background,
225
+ as: Component = "div",
226
+ ...htmlRest
227
+ } = props;
228
+ const { style: shimStyle } = extractSkeletonStyleProps({
229
+ w: _w,
230
+ h: _h,
231
+ minW: _minW,
232
+ maxW: _maxW,
233
+ display: _display,
234
+ flexGrow: _flexGrow,
235
+ flexShrink: _flexShrink,
236
+ flexBasis: _flexBasis,
237
+ fontWeight: _fontWeight,
238
+ textStyle: _textStyle,
239
+ borderRadius: _borderRadius,
240
+ alignSelf: _alignSelf,
241
+ alignItems: _alignItems,
242
+ justifyContent: _justifyContent,
243
+ color: _color,
244
+ mt: _mt,
245
+ mb: _mb,
246
+ ml: _ml,
247
+ mr: _mr,
248
+ height: _height,
249
+ overflow: _overflow,
250
+ whiteSpace: _whiteSpace,
251
+ textOverflow: _textOverflow,
252
+ textTransform: _textTransform,
253
+ gap: _gap,
254
+ gridTemplateColumns: _gridTemplateColumns,
255
+ minWidth: _minWidth,
256
+ boxSize: _boxSize,
257
+ py: _py,
258
+ px: _px,
259
+ p: _p,
260
+ hideBelow: _hideBelow,
261
+ fontSize: _fontSize,
262
+ flexWrap: _flexWrap,
263
+ wordBreak: _wordBreak,
264
+ lineHeight: _lineHeight,
265
+ marginRight: _marginRight,
266
+ position: _position,
267
+ background: _background
268
+ });
269
+ const mergedStyle = Object.keys(shimStyle).length > 0 || styleProp ? { ...shimStyle, ...styleProp } : void 0;
270
+ const HIDE_BELOW_MAP = { lg: "lg:hidden", md: "md:hidden", sm: "sm:hidden" };
271
+ const hideBelowClass = _hideBelow ? HIDE_BELOW_MAP[_hideBelow] : void 0;
272
+ const finalClassName = hideBelowClass ? cn(className, hideBelowClass) : className;
273
+ if (!loading) {
274
+ if (asChild && React2.isValidElement(children)) {
275
+ return children;
276
+ }
277
+ return /* @__PURE__ */ jsx(Component, { ref, className: finalClassName, style: mergedStyle, ...htmlRest, children });
278
+ }
279
+ if (asChild && React2.isValidElement(children)) {
280
+ return /* @__PURE__ */ jsx(
281
+ Component,
282
+ {
283
+ ref,
284
+ "data-loading": true,
285
+ className: cn(
286
+ "animate-skeleton-shimmer rounded-sm",
287
+ "bg-[linear-gradient(90deg,var(--color-skeleton-start)_0%,var(--color-skeleton-end)_50%,var(--color-skeleton-start)_100%)]",
288
+ "bg-[length:200%_100%]",
289
+ "text-transparent [&_*]:invisible",
290
+ finalClassName
291
+ ),
292
+ style: mergedStyle,
293
+ ...htmlRest,
294
+ children
295
+ }
296
+ );
297
+ }
298
+ return /* @__PURE__ */ jsx(
299
+ Component,
300
+ {
301
+ ref,
302
+ "data-loading": true,
303
+ className: cn(
304
+ "animate-skeleton-shimmer rounded-sm",
305
+ "bg-[linear-gradient(90deg,var(--color-skeleton-start)_0%,var(--color-skeleton-end)_50%,var(--color-skeleton-start)_100%)]",
306
+ "bg-[length:200%_100%]",
307
+ children ? "text-transparent [&_*]:invisible" : "min-h-5",
308
+ finalClassName
309
+ ),
310
+ style: mergedStyle,
311
+ ...htmlRest,
312
+ children
313
+ }
314
+ );
315
+ }
316
+ );
317
+ React2.forwardRef(
318
+ function SkeletonCircle2(props, ref) {
319
+ const { size = 40, loading = true, className, ...rest } = props;
320
+ const dimension = typeof size === "number" ? `${size}px` : size;
321
+ return /* @__PURE__ */ jsx(
322
+ Skeleton,
323
+ {
324
+ ref,
325
+ loading,
326
+ className: cn("rounded-full shrink-0", className),
327
+ style: { width: dimension, height: dimension, ...rest.style },
328
+ ...rest
329
+ }
330
+ );
331
+ }
332
+ );
333
+ React2.forwardRef(
334
+ function SkeletonText2(props, ref) {
335
+ const { noOfLines = 3, loading = true, className, ...rest } = props;
336
+ return /* @__PURE__ */ jsx("div", { ref, className: cn("flex w-full flex-col gap-2", className), ...rest, children: Array.from({ length: noOfLines }).map((_, index) => /* @__PURE__ */ jsx(
337
+ Skeleton,
338
+ {
339
+ loading,
340
+ className: cn("h-4", index === noOfLines - 1 && "max-w-[80%]")
341
+ },
342
+ index
343
+ )) });
344
+ }
345
+ );
346
+ function createListCollection(config) {
347
+ return { items: config.items };
348
+ }
349
+ var ArrowIcon = ({ className }) => /* @__PURE__ */ jsx("svg", { className, viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M7.5 15L12.5 10L7.5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) });
350
+ var CheckIcon = ({ className }) => /* @__PURE__ */ jsx("svg", { className, viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M16.667 5L7.5 14.167 3.333 10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) });
351
+ function FilterInput({ placeholder, initialValue = "", onChange }) {
352
+ const [value, setValue] = React2.useState(initialValue);
353
+ const handleChange = React2.useCallback((e) => {
354
+ setValue(e.target.value);
355
+ onChange?.(e.target.value);
356
+ }, [onChange]);
357
+ return /* @__PURE__ */ jsx(
358
+ "input",
359
+ {
360
+ type: "text",
361
+ placeholder,
362
+ value,
363
+ onChange: handleChange,
364
+ className: cn(
365
+ "w-full px-3 py-2 text-sm outline-none",
366
+ "bg-transparent border-b border-[var(--color-border-divider)]",
367
+ "placeholder:text-[var(--color-input-placeholder)]"
368
+ )
369
+ }
370
+ );
371
+ }
372
+ var SelectInternalContext = React2.createContext(null);
373
+ function useSelectInternalContext() {
374
+ const ctx = React2.useContext(SelectInternalContext);
375
+ if (!ctx) {
376
+ throw new Error("Select compound components must be rendered inside <SelectRoot>");
377
+ }
378
+ return ctx;
379
+ }
380
+ var SelectRoot = React2.forwardRef(
381
+ function SelectRoot2(props, ref) {
382
+ const {
383
+ children,
384
+ collection: collectionProp,
385
+ defaultValue: defaultValueArr,
386
+ value: valueProp,
387
+ onValueChange: onValueChangeProp,
388
+ onInteractOutside,
389
+ name,
390
+ disabled,
391
+ readOnly,
392
+ required,
393
+ invalid,
394
+ size,
395
+ variant,
396
+ open: openProp,
397
+ defaultOpen,
398
+ onOpenChange,
399
+ positioning: _positioning,
400
+ lazyMount: _lazyMount,
401
+ unmountOnExit: _unmountOnExit,
402
+ asChild: _asChild,
403
+ className,
404
+ style,
405
+ w,
406
+ maxW,
407
+ minW,
408
+ hideFrom: _hideFrom
409
+ } = props;
410
+ const collection = collectionProp ?? createListCollection({ items: [] });
411
+ const [internalValue, setInternalValue] = React2.useState(defaultValueArr ?? []);
412
+ const currentValue = valueProp ?? internalValue;
413
+ const selectedItems = React2.useMemo(() => {
414
+ return currentValue.map((v) => collection.items.find((item) => item.value === v)).filter(Boolean);
415
+ }, [currentValue, collection.items]);
416
+ const [open, setOpen] = React2.useState(defaultOpen ?? false);
417
+ const isOpen = openProp ?? open;
418
+ const handleOpenChange = React2.useCallback((nextOpen) => {
419
+ setOpen(nextOpen);
420
+ onOpenChange?.(nextOpen);
421
+ if (!nextOpen) {
422
+ onInteractOutside?.();
423
+ }
424
+ }, [onOpenChange, onInteractOutside]);
425
+ const handleRadixValueChange = React2.useCallback((radixValue) => {
426
+ const nextArr = [radixValue];
427
+ if (!valueProp) {
428
+ setInternalValue(nextArr);
429
+ }
430
+ const items = collection.items.filter((item) => nextArr.includes(item.value));
431
+ onValueChangeProp?.({ value: nextArr, items });
432
+ }, [valueProp, collection.items, onValueChangeProp]);
433
+ const ctxValue = React2.useMemo(() => ({
434
+ value: currentValue,
435
+ selectedItems,
436
+ collection,
437
+ onValueChange: (details) => {
438
+ if (!valueProp) {
439
+ setInternalValue(details.value);
440
+ }
441
+ onValueChangeProp?.(details);
442
+ },
443
+ open: isOpen,
444
+ size,
445
+ variant,
446
+ disabled
447
+ }), [currentValue, selectedItems, collection, valueProp, onValueChangeProp, isOpen, size, variant, disabled]);
448
+ const resolveVal = (v) => {
449
+ if (!v) return void 0;
450
+ if (typeof v === "string") return v;
451
+ return v.base ?? v.lg ?? Object.values(v)[0];
452
+ };
453
+ const inlineStyle = React2.useMemo(() => {
454
+ const s = { ...style };
455
+ const rw = resolveVal(w);
456
+ if (rw) s.width = rw;
457
+ const rmw = resolveVal(maxW);
458
+ if (rmw) s.maxWidth = rmw;
459
+ const rminw = resolveVal(minW);
460
+ if (rminw) s.minWidth = rminw;
461
+ return s;
462
+ }, [style, w, maxW, minW]);
463
+ return /* @__PURE__ */ jsx(SelectInternalContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx(
464
+ RadixSelect.Root,
465
+ {
466
+ value: currentValue[0] ?? "",
467
+ defaultValue: defaultValueArr?.[0],
468
+ onValueChange: handleRadixValueChange,
469
+ open: isOpen,
470
+ onOpenChange: handleOpenChange,
471
+ disabled: disabled || readOnly,
472
+ name,
473
+ required,
474
+ children: /* @__PURE__ */ jsx(
475
+ "div",
476
+ {
477
+ ref,
478
+ className: cn("relative inline-flex", className),
479
+ style: inlineStyle,
480
+ "data-invalid": invalid || void 0,
481
+ "data-disabled": disabled || void 0,
482
+ "data-variant": variant || void 0,
483
+ "data-size": size || void 0,
484
+ children
485
+ }
486
+ )
487
+ }
488
+ ) });
489
+ }
490
+ );
491
+ var SelectControl = React2.forwardRef(
492
+ function SelectControl2(props, ref) {
493
+ const { children, noIndicator, triggerProps, loading, defaultValue } = props;
494
+ const ctx = useSelectInternalContext();
495
+ const isDefaultValue = Array.isArray(defaultValue) ? ctx.value.every((item) => defaultValue.includes(item)) : false;
496
+ const { asChild, px: _px, className: triggerClassName, ...radixTriggerProps } = triggerProps ?? {};
497
+ const trigger = /* @__PURE__ */ jsx(
498
+ RadixSelect.Trigger,
499
+ {
500
+ ref,
501
+ asChild,
502
+ className: cn(
503
+ "group peer inline-flex items-center gap-2 cursor-pointer",
504
+ "rounded-lg text-sm transition-colors outline-none",
505
+ "border border-[var(--color-input-border)] bg-[var(--color-input-bg)] text-[var(--color-input-fg)]",
506
+ "hover:border-[var(--color-input-border-hover)]",
507
+ "focus-visible:border-[var(--color-input-border-focus)]",
508
+ "disabled:opacity-50 disabled:cursor-not-allowed",
509
+ ctx.variant === "plain" && "border-transparent bg-transparent px-1 py-0.5",
510
+ ctx.variant !== "plain" && ctx.size === "lg" && "px-4 py-2.5 min-h-[52px]",
511
+ ctx.variant !== "plain" && ctx.size !== "lg" && "px-3 py-1.5 min-h-[36px]",
512
+ triggerClassName
513
+ ),
514
+ "data-default-value": isDefaultValue || void 0,
515
+ ...radixTriggerProps,
516
+ children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
517
+ children,
518
+ !noIndicator && /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 transition-transform data-[state=open]:rotate-180 text-[var(--color-icon-secondary)]", children: /* @__PURE__ */ jsx(ArrowIcon, { className: "h-5 w-5 -rotate-90" }) })
519
+ ] })
520
+ }
521
+ );
522
+ if (loading) {
523
+ return /* @__PURE__ */ jsx(Skeleton, { loading, asChild: true, children: trigger });
524
+ }
525
+ return trigger;
526
+ }
527
+ );
528
+ var SelectClearTrigger = React2.forwardRef(
529
+ function SelectClearTrigger2(props, ref) {
530
+ const { className, ...rest } = props;
531
+ const ctx = useSelectInternalContext();
532
+ const handleClick = React2.useCallback(() => {
533
+ ctx.onValueChange({ value: [], items: [] });
534
+ }, [ctx]);
535
+ return /* @__PURE__ */ jsx(
536
+ "button",
537
+ {
538
+ ref,
539
+ type: "button",
540
+ onClick: handleClick,
541
+ className: cn("pointer-events-auto", className),
542
+ "aria-label": "Clear selection",
543
+ ...rest,
544
+ children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) })
545
+ }
546
+ );
547
+ }
548
+ );
549
+ var SelectContent = React2.forwardRef(
550
+ function SelectContent2(props, ref) {
551
+ const { portalled = true, portalRef, children, className, ...rest } = props;
552
+ const content = /* @__PURE__ */ jsx(
553
+ RadixSelect.Content,
554
+ {
555
+ ref,
556
+ position: "popper",
557
+ sideOffset: 4,
558
+ className: cn(
559
+ "z-50 min-w-[8rem] overflow-hidden rounded-lg",
560
+ "bg-[var(--color-popover-bg)] shadow-[var(--shadow-popover)]",
561
+ "border border-[var(--color-border-divider)]",
562
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
563
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
564
+ className
565
+ ),
566
+ ...rest,
567
+ children: /* @__PURE__ */ jsx(RadixSelect.Viewport, { className: "p-1", children })
568
+ }
569
+ );
570
+ if (portalled) {
571
+ return /* @__PURE__ */ jsx(RadixSelect.Portal, { container: portalRef?.current ?? void 0, children: content });
572
+ }
573
+ return content;
574
+ }
575
+ );
576
+ var SelectItem = React2.forwardRef(
577
+ function SelectItem2(props, ref) {
578
+ const { item, children, className, ...rest } = props;
579
+ return /* @__PURE__ */ jsxs(
580
+ RadixSelect.Item,
581
+ {
582
+ ref,
583
+ value: item.value,
584
+ textValue: item.label,
585
+ className: cn(
586
+ "relative flex cursor-pointer select-none items-center gap-2",
587
+ "rounded-md px-3 py-2 text-sm outline-none",
588
+ "text-[var(--color-text-primary)]",
589
+ "data-[highlighted]:bg-[var(--color-selected-control-bg)]",
590
+ "data-[state=checked]:font-medium",
591
+ "data-[disabled]:opacity-50 data-[disabled]:pointer-events-none",
592
+ className
593
+ ),
594
+ ...rest,
595
+ children: [
596
+ item.icon,
597
+ /* @__PURE__ */ jsx(RadixSelect.ItemText, { children }),
598
+ /* @__PURE__ */ jsx(RadixSelect.ItemIndicator, { className: "ml-auto shrink-0", children: /* @__PURE__ */ jsx(CheckIcon, { className: "h-5 w-5" }) })
599
+ ]
600
+ }
601
+ );
602
+ }
603
+ );
604
+ var SelectValueText = React2.forwardRef(
605
+ function SelectValueText2(props, ref) {
606
+ const { children, size, required, invalid, errorText, mode, className, style, placeholder: placeholderProp, ...rest } = props;
607
+ const ctx = useSelectInternalContext();
608
+ const placeholderText = `${placeholderProp ?? ""}${required ? "*" : ""}${invalid && errorText ? ` - ${errorText}` : ""}`;
609
+ const content = (() => {
610
+ const items = ctx.selectedItems;
611
+ if (items.length === 0) return null;
612
+ if (children) return children(items);
613
+ if (items.length === 1) {
614
+ const item = items[0];
615
+ if (!item) return null;
616
+ const label = size === "lg" ? /* @__PURE__ */ jsx(
617
+ "span",
618
+ {
619
+ className: cn(
620
+ "text-xs block",
621
+ invalid ? "text-[var(--color-text-error)]" : "text-[var(--color-input-placeholder)]"
622
+ ),
623
+ style: { display: "-webkit-box" },
624
+ children: placeholderText
625
+ }
626
+ ) : null;
627
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
628
+ label,
629
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center flex-nowrap gap-1", children: [
630
+ item.icon,
631
+ mode !== "compact" && /* @__PURE__ */ jsx(
632
+ "span",
633
+ {
634
+ style: {
635
+ WebkitLineClamp: 1,
636
+ WebkitBoxOrient: "vertical",
637
+ display: "-webkit-box",
638
+ overflow: "hidden"
639
+ },
640
+ children: item.renderLabel ? item.renderLabel("value-text") : item.label
641
+ }
642
+ )
643
+ ] })
644
+ ] });
645
+ }
646
+ return `${items.length} selected`;
647
+ })();
648
+ return /* @__PURE__ */ jsx(
649
+ RadixSelect.Value,
650
+ {
651
+ ref,
652
+ placeholder: placeholderText,
653
+ className: cn("flex flex-col justify-center min-w-0 truncate", className),
654
+ ...rest,
655
+ children: content
656
+ }
657
+ );
658
+ }
659
+ );
660
+ var SelectItemGroup = React2.forwardRef(
661
+ function SelectItemGroup2(props, ref) {
662
+ const { children, label, className, ...rest } = props;
663
+ return /* @__PURE__ */ jsxs(RadixSelect.Group, { ref, className: cn("py-1", className), ...rest, children: [
664
+ /* @__PURE__ */ jsx(RadixSelect.Label, { className: "px-3 py-1.5 text-xs font-medium text-[var(--color-text-secondary)]", children: label }),
665
+ children
666
+ ] });
667
+ }
668
+ );
669
+ var SelectLabel = RadixSelect.Label;
670
+ var SelectItemText = RadixSelect.ItemText;
671
+ var Select = React2.forwardRef((props, ref) => {
672
+ const { collection, placeholder, portalled = true, loading, errorText, contentProps, contentHeader, itemFilter, mode, ...rest } = props;
673
+ return /* @__PURE__ */ jsxs(
674
+ SelectRoot,
675
+ {
676
+ ref,
677
+ collection,
678
+ ...rest,
679
+ children: [
680
+ /* @__PURE__ */ jsx(SelectControl, { loading, children: /* @__PURE__ */ jsx(
681
+ SelectValueText,
682
+ {
683
+ placeholder,
684
+ size: props.size,
685
+ required: props.required,
686
+ invalid: props.invalid,
687
+ errorText,
688
+ mode
689
+ }
690
+ ) }),
691
+ /* @__PURE__ */ jsxs(SelectContent, { portalled, ...contentProps, children: [
692
+ contentHeader,
693
+ collection.items.filter(itemFilter ?? (() => true)).map((item) => /* @__PURE__ */ jsxs(React2.Fragment, { children: [
694
+ /* @__PURE__ */ jsx(SelectItem, { item, children: item.renderLabel ? item.renderLabel("item") : item.label }),
695
+ item.afterElement
696
+ ] }, item.value))
697
+ ] })
698
+ ]
699
+ }
700
+ );
701
+ });
702
+ var SelectAsync = React2.forwardRef((props, ref) => {
703
+ const { placeholder, portalled = true, loading, loadOptions, extraControls, onValueChange, errorText, mode, contentHeader, ...rest } = props;
704
+ const [collection, setCollection] = React2.useState(createListCollection({ items: [] }));
705
+ const [inputValue, setInputValue] = React2.useState("");
706
+ const [value, setValue] = React2.useState([]);
707
+ const debouncedInputValue = useDebounce(inputValue, 300);
708
+ React2.useEffect(() => {
709
+ loadOptions(debouncedInputValue, value).then(setCollection);
710
+ }, [debouncedInputValue, loadOptions, value]);
711
+ const handleFilterChange = React2.useCallback((val) => {
712
+ setInputValue(val);
713
+ }, []);
714
+ const handleValueChange = React2.useCallback(({ value: v, items }) => {
715
+ setValue(v);
716
+ onValueChange?.({ value: v, items });
717
+ }, [onValueChange]);
718
+ return /* @__PURE__ */ jsxs(
719
+ SelectRoot,
720
+ {
721
+ ref,
722
+ collection,
723
+ onValueChange: handleValueChange,
724
+ ...rest,
725
+ children: [
726
+ /* @__PURE__ */ jsx(SelectControl, { loading, children: /* @__PURE__ */ jsx(
727
+ SelectValueText,
728
+ {
729
+ placeholder,
730
+ size: props.size,
731
+ required: props.required,
732
+ invalid: props.invalid,
733
+ errorText,
734
+ mode
735
+ }
736
+ ) }),
737
+ /* @__PURE__ */ jsxs(SelectContent, { portalled, children: [
738
+ /* @__PURE__ */ jsxs("div", { className: "px-4", children: [
739
+ /* @__PURE__ */ jsx(
740
+ FilterInput,
741
+ {
742
+ placeholder: "Search",
743
+ initialValue: inputValue,
744
+ onChange: handleFilterChange
745
+ }
746
+ ),
747
+ extraControls
748
+ ] }),
749
+ contentHeader,
750
+ collection.items.map((item) => /* @__PURE__ */ jsx(SelectItem, { item, children: item.renderLabel ? item.renderLabel("item") : item.label }, item.value))
751
+ ] })
752
+ ]
753
+ }
754
+ );
755
+ });
756
+
757
+ export { Select, SelectAsync, SelectClearTrigger, SelectContent, SelectControl, SelectItem, SelectItemGroup, SelectItemText, SelectLabel, SelectRoot, SelectValueText, createListCollection };