@optilogic/core 1.2.1 → 1.3.0
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.
- package/dist/index.cjs +584 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +128 -3
- package/dist/index.d.ts +128 -3
- package/dist/index.js +580 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/combobox.tsx +340 -0
- package/src/components/file-view/components/HtmlRenderer.tsx +2 -0
- package/src/components/multi-select.tsx +375 -0
- package/src/components/select.tsx +18 -2
- package/src/components/tabs.tsx +92 -28
- package/src/index.ts +16 -0
package/dist/index.cjs
CHANGED
|
@@ -388,17 +388,26 @@ var SelectItem = React20__namespace.forwardRef(({ className, children, ...props
|
|
|
388
388
|
{
|
|
389
389
|
ref,
|
|
390
390
|
className: cn(
|
|
391
|
-
"relative flex w-full cursor-default select-none items-
|
|
391
|
+
"relative flex w-full cursor-default select-none items-start rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
392
392
|
className
|
|
393
393
|
),
|
|
394
394
|
...props,
|
|
395
395
|
children: [
|
|
396
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }) }) }),
|
|
396
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center mt-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }) }) }),
|
|
397
397
|
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children })
|
|
398
398
|
]
|
|
399
399
|
}
|
|
400
400
|
));
|
|
401
401
|
SelectItem.displayName = SelectPrimitive__namespace.Item.displayName;
|
|
402
|
+
var SelectItemDescription = React20__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
403
|
+
"span",
|
|
404
|
+
{
|
|
405
|
+
ref,
|
|
406
|
+
className: cn("text-xs text-muted-foreground", className),
|
|
407
|
+
...props
|
|
408
|
+
}
|
|
409
|
+
));
|
|
410
|
+
SelectItemDescription.displayName = "SelectItemDescription";
|
|
402
411
|
var SelectSeparator = React20__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
403
412
|
SelectPrimitive__namespace.Separator,
|
|
404
413
|
{
|
|
@@ -409,41 +418,85 @@ var SelectSeparator = React20__namespace.forwardRef(({ className, ...props }, re
|
|
|
409
418
|
));
|
|
410
419
|
SelectSeparator.displayName = SelectPrimitive__namespace.Separator.displayName;
|
|
411
420
|
var Tabs = TabsPrimitive__namespace.Root;
|
|
412
|
-
var
|
|
421
|
+
var tabsListVariants = classVarianceAuthority.cva(
|
|
422
|
+
"inline-flex h-10 items-center justify-start bg-transparent",
|
|
423
|
+
{
|
|
424
|
+
variants: {
|
|
425
|
+
variant: {
|
|
426
|
+
default: "border-b border-border",
|
|
427
|
+
pill: "gap-1 rounded-lg bg-muted p-1",
|
|
428
|
+
unstyled: ""
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
defaultVariants: {
|
|
432
|
+
variant: "default"
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
);
|
|
436
|
+
var tabsTriggerVariants = classVarianceAuthority.cva(
|
|
437
|
+
[
|
|
438
|
+
"inline-flex items-center justify-center whitespace-nowrap",
|
|
439
|
+
"px-4 py-2.5 text-sm font-medium",
|
|
440
|
+
"transition-colors",
|
|
441
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
442
|
+
"disabled:pointer-events-none disabled:opacity-50"
|
|
443
|
+
],
|
|
444
|
+
{
|
|
445
|
+
variants: {
|
|
446
|
+
variant: {
|
|
447
|
+
default: [
|
|
448
|
+
"-mb-px",
|
|
449
|
+
"border-transparent text-muted-foreground",
|
|
450
|
+
"hover:text-foreground hover:border-muted-foreground/50",
|
|
451
|
+
"data-[state=active]:border-foreground data-[state=active]:text-foreground"
|
|
452
|
+
],
|
|
453
|
+
pill: [
|
|
454
|
+
"rounded-md",
|
|
455
|
+
"text-muted-foreground",
|
|
456
|
+
"hover:text-foreground",
|
|
457
|
+
"data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm"
|
|
458
|
+
],
|
|
459
|
+
unstyled: [
|
|
460
|
+
"text-muted-foreground",
|
|
461
|
+
"hover:text-foreground",
|
|
462
|
+
"data-[state=active]:text-foreground"
|
|
463
|
+
]
|
|
464
|
+
},
|
|
465
|
+
indicatorSize: {
|
|
466
|
+
sm: "border-b",
|
|
467
|
+
default: "border-b-2",
|
|
468
|
+
lg: "border-b-[3px]"
|
|
469
|
+
}
|
|
470
|
+
},
|
|
471
|
+
compoundVariants: [
|
|
472
|
+
{ variant: "pill", indicatorSize: "sm", className: "border-b-0" },
|
|
473
|
+
{ variant: "pill", indicatorSize: "default", className: "border-b-0" },
|
|
474
|
+
{ variant: "pill", indicatorSize: "lg", className: "border-b-0" },
|
|
475
|
+
{ variant: "unstyled", indicatorSize: "sm", className: "border-b-0" },
|
|
476
|
+
{ variant: "unstyled", indicatorSize: "default", className: "border-b-0" },
|
|
477
|
+
{ variant: "unstyled", indicatorSize: "lg", className: "border-b-0" }
|
|
478
|
+
],
|
|
479
|
+
defaultVariants: {
|
|
480
|
+
variant: "default",
|
|
481
|
+
indicatorSize: "default"
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
);
|
|
485
|
+
var TabsList = React20__namespace.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
413
486
|
TabsPrimitive__namespace.List,
|
|
414
487
|
{
|
|
415
488
|
ref,
|
|
416
|
-
className: cn(
|
|
417
|
-
"inline-flex h-10 items-center justify-start",
|
|
418
|
-
"border-b border-border",
|
|
419
|
-
"bg-transparent",
|
|
420
|
-
className
|
|
421
|
-
),
|
|
489
|
+
className: cn(tabsListVariants({ variant }), className),
|
|
422
490
|
...props
|
|
423
491
|
}
|
|
424
492
|
));
|
|
425
493
|
TabsList.displayName = TabsPrimitive__namespace.List.displayName;
|
|
426
|
-
var TabsTrigger = React20__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
494
|
+
var TabsTrigger = React20__namespace.forwardRef(({ className, variant, indicatorSize, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
427
495
|
TabsPrimitive__namespace.Trigger,
|
|
428
496
|
{
|
|
429
497
|
ref,
|
|
430
498
|
className: cn(
|
|
431
|
-
|
|
432
|
-
"inline-flex items-center justify-center whitespace-nowrap",
|
|
433
|
-
"px-4 py-2.5 text-sm font-medium",
|
|
434
|
-
"transition-colors",
|
|
435
|
-
// Border-bottom indicator style
|
|
436
|
-
"border-b-2 -mb-px",
|
|
437
|
-
// Default state
|
|
438
|
-
"border-transparent text-muted-foreground",
|
|
439
|
-
// Hover state
|
|
440
|
-
"hover:text-foreground hover:border-muted-foreground/50",
|
|
441
|
-
// Active/selected state
|
|
442
|
-
"data-[state=active]:border-foreground data-[state=active]:text-foreground",
|
|
443
|
-
// Focus styles
|
|
444
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
445
|
-
// Disabled styles
|
|
446
|
-
"disabled:pointer-events-none disabled:opacity-50",
|
|
499
|
+
tabsTriggerVariants({ variant, indicatorSize }),
|
|
447
500
|
className
|
|
448
501
|
),
|
|
449
502
|
...props
|
|
@@ -456,7 +509,6 @@ var TabsContent = React20__namespace.forwardRef(({ className, ...props }, ref) =
|
|
|
456
509
|
ref,
|
|
457
510
|
className: cn(
|
|
458
511
|
"mt-2",
|
|
459
|
-
// Focus styles
|
|
460
512
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
461
513
|
className
|
|
462
514
|
),
|
|
@@ -5650,6 +5702,504 @@ function Autocomplete({
|
|
|
5650
5702
|
)
|
|
5651
5703
|
] });
|
|
5652
5704
|
}
|
|
5705
|
+
function MultiSelect({
|
|
5706
|
+
options,
|
|
5707
|
+
value,
|
|
5708
|
+
onChange,
|
|
5709
|
+
placeholder = "Select items...",
|
|
5710
|
+
searchPlaceholder = "Search...",
|
|
5711
|
+
emptyText = "No options found.",
|
|
5712
|
+
disabled = false,
|
|
5713
|
+
className,
|
|
5714
|
+
clearable = true,
|
|
5715
|
+
maxDisplayItems = 3,
|
|
5716
|
+
showSelectAll = false,
|
|
5717
|
+
selectAllLabel = "Select all"
|
|
5718
|
+
}) {
|
|
5719
|
+
const [open, setOpen] = React20__namespace.useState(false);
|
|
5720
|
+
const [search, setSearch] = React20__namespace.useState("");
|
|
5721
|
+
const inputRef = React20__namespace.useRef(null);
|
|
5722
|
+
const safeOptions = options ?? [];
|
|
5723
|
+
const safeValue = value ?? [];
|
|
5724
|
+
const selectedSet = React20__namespace.useMemo(() => new Set(safeValue), [safeValue]);
|
|
5725
|
+
const filteredOptions = React20__namespace.useMemo(() => {
|
|
5726
|
+
if (!search.trim()) return safeOptions;
|
|
5727
|
+
const searchLower = search.toLowerCase();
|
|
5728
|
+
return safeOptions.filter(
|
|
5729
|
+
(opt) => opt.label.toLowerCase().includes(searchLower) || opt.description?.toLowerCase().includes(searchLower)
|
|
5730
|
+
);
|
|
5731
|
+
}, [safeOptions, search]);
|
|
5732
|
+
const groupedOptions = React20__namespace.useMemo(() => {
|
|
5733
|
+
const groups = {};
|
|
5734
|
+
const ungrouped = [];
|
|
5735
|
+
filteredOptions.forEach((opt) => {
|
|
5736
|
+
if (opt.group) {
|
|
5737
|
+
if (!groups[opt.group]) groups[opt.group] = [];
|
|
5738
|
+
groups[opt.group].push(opt);
|
|
5739
|
+
} else {
|
|
5740
|
+
ungrouped.push(opt);
|
|
5741
|
+
}
|
|
5742
|
+
});
|
|
5743
|
+
return { groups, ungrouped };
|
|
5744
|
+
}, [filteredOptions]);
|
|
5745
|
+
const hasGroups = Object.keys(groupedOptions.groups).length > 0;
|
|
5746
|
+
const selectableFiltered = React20__namespace.useMemo(
|
|
5747
|
+
() => filteredOptions.filter((opt) => !opt.disabled),
|
|
5748
|
+
[filteredOptions]
|
|
5749
|
+
);
|
|
5750
|
+
const allFilteredSelected = React20__namespace.useMemo(
|
|
5751
|
+
() => selectableFiltered.length > 0 && selectableFiltered.every((opt) => selectedSet.has(opt.value)),
|
|
5752
|
+
[selectableFiltered, selectedSet]
|
|
5753
|
+
);
|
|
5754
|
+
const someFilteredSelected = React20__namespace.useMemo(
|
|
5755
|
+
() => !allFilteredSelected && selectableFiltered.some((opt) => selectedSet.has(opt.value)),
|
|
5756
|
+
[selectableFiltered, selectedSet, allFilteredSelected]
|
|
5757
|
+
);
|
|
5758
|
+
const handleToggle = React20__namespace.useCallback(
|
|
5759
|
+
(optionValue) => {
|
|
5760
|
+
const next = selectedSet.has(optionValue) ? safeValue.filter((v) => v !== optionValue) : [...safeValue, optionValue];
|
|
5761
|
+
onChange?.(next);
|
|
5762
|
+
},
|
|
5763
|
+
[onChange, safeValue, selectedSet]
|
|
5764
|
+
);
|
|
5765
|
+
const handleRemove = React20__namespace.useCallback(
|
|
5766
|
+
(optionValue, e) => {
|
|
5767
|
+
e.stopPropagation();
|
|
5768
|
+
onChange?.(safeValue.filter((v) => v !== optionValue));
|
|
5769
|
+
},
|
|
5770
|
+
[onChange, safeValue]
|
|
5771
|
+
);
|
|
5772
|
+
const handleClearAll = React20__namespace.useCallback(
|
|
5773
|
+
(e) => {
|
|
5774
|
+
e.stopPropagation();
|
|
5775
|
+
onChange?.([]);
|
|
5776
|
+
},
|
|
5777
|
+
[onChange]
|
|
5778
|
+
);
|
|
5779
|
+
const handleSelectAll = React20__namespace.useCallback(() => {
|
|
5780
|
+
if (allFilteredSelected) {
|
|
5781
|
+
const filteredValues = new Set(selectableFiltered.map((o) => o.value));
|
|
5782
|
+
onChange?.(safeValue.filter((v) => !filteredValues.has(v)));
|
|
5783
|
+
} else {
|
|
5784
|
+
const existing = new Set(safeValue);
|
|
5785
|
+
const next = [...safeValue];
|
|
5786
|
+
for (const opt of selectableFiltered) {
|
|
5787
|
+
if (!existing.has(opt.value)) {
|
|
5788
|
+
next.push(opt.value);
|
|
5789
|
+
}
|
|
5790
|
+
}
|
|
5791
|
+
onChange?.(next);
|
|
5792
|
+
}
|
|
5793
|
+
}, [allFilteredSelected, selectableFiltered, safeValue, onChange]);
|
|
5794
|
+
React20__namespace.useEffect(() => {
|
|
5795
|
+
if (open) {
|
|
5796
|
+
const timeout = setTimeout(() => inputRef.current?.focus(), 0);
|
|
5797
|
+
return () => clearTimeout(timeout);
|
|
5798
|
+
} else {
|
|
5799
|
+
setSearch("");
|
|
5800
|
+
}
|
|
5801
|
+
}, [open]);
|
|
5802
|
+
const handleKeyDown = React20__namespace.useCallback((e) => {
|
|
5803
|
+
if (e.key === "Escape") setOpen(false);
|
|
5804
|
+
}, []);
|
|
5805
|
+
const selectedLabels = React20__namespace.useMemo(
|
|
5806
|
+
() => safeValue.map((v) => safeOptions.find((o) => o.value === v)?.label ?? v).slice(0, maxDisplayItems),
|
|
5807
|
+
[safeValue, safeOptions, maxDisplayItems]
|
|
5808
|
+
);
|
|
5809
|
+
const overflow = safeValue.length - maxDisplayItems;
|
|
5810
|
+
const isSearching = search.trim().length > 0;
|
|
5811
|
+
const renderOption = (option) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5812
|
+
"button",
|
|
5813
|
+
{
|
|
5814
|
+
type: "button",
|
|
5815
|
+
disabled: option.disabled,
|
|
5816
|
+
onClick: () => handleToggle(option.value),
|
|
5817
|
+
className: cn(
|
|
5818
|
+
"relative flex w-full cursor-pointer select-none items-start gap-2 rounded-sm px-2 py-1.5 text-sm outline-none",
|
|
5819
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
5820
|
+
option.disabled && "pointer-events-none opacity-50"
|
|
5821
|
+
),
|
|
5822
|
+
children: [
|
|
5823
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5824
|
+
Checkbox,
|
|
5825
|
+
{
|
|
5826
|
+
checked: selectedSet.has(option.value),
|
|
5827
|
+
tabIndex: -1,
|
|
5828
|
+
className: "mt-0.5 pointer-events-none"
|
|
5829
|
+
}
|
|
5830
|
+
),
|
|
5831
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
5832
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate", children: option.label }),
|
|
5833
|
+
option.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground truncate", children: option.description })
|
|
5834
|
+
] })
|
|
5835
|
+
]
|
|
5836
|
+
},
|
|
5837
|
+
option.value
|
|
5838
|
+
);
|
|
5839
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
5840
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5841
|
+
"button",
|
|
5842
|
+
{
|
|
5843
|
+
type: "button",
|
|
5844
|
+
role: "combobox",
|
|
5845
|
+
"aria-expanded": open,
|
|
5846
|
+
"aria-haspopup": "listbox",
|
|
5847
|
+
disabled,
|
|
5848
|
+
className: cn(
|
|
5849
|
+
"flex min-h-9 w-full items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-1.5 text-sm shadow-sm ring-offset-background",
|
|
5850
|
+
"hover:border-input-hover",
|
|
5851
|
+
"focus:outline-none focus:ring-1 focus:ring-ring",
|
|
5852
|
+
"disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-input",
|
|
5853
|
+
className
|
|
5854
|
+
),
|
|
5855
|
+
children: [
|
|
5856
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-wrap gap-1 items-center min-w-0", children: safeValue.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: placeholder }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5857
|
+
selectedLabels.map((label, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5858
|
+
"span",
|
|
5859
|
+
{
|
|
5860
|
+
className: "inline-flex items-center gap-0.5 rounded-sm bg-accent px-1.5 py-0.5 text-xs font-medium text-accent-foreground",
|
|
5861
|
+
children: [
|
|
5862
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate max-w-[100px]", children: label }),
|
|
5863
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5864
|
+
"span",
|
|
5865
|
+
{
|
|
5866
|
+
role: "button",
|
|
5867
|
+
tabIndex: -1,
|
|
5868
|
+
onClick: (e) => handleRemove(safeValue[i], e),
|
|
5869
|
+
className: "rounded-sm hover:bg-foreground/10 p-0.5",
|
|
5870
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" })
|
|
5871
|
+
}
|
|
5872
|
+
)
|
|
5873
|
+
]
|
|
5874
|
+
},
|
|
5875
|
+
safeValue[i]
|
|
5876
|
+
)),
|
|
5877
|
+
overflow > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
5878
|
+
"+",
|
|
5879
|
+
overflow
|
|
5880
|
+
] })
|
|
5881
|
+
] }) }),
|
|
5882
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
|
|
5883
|
+
clearable && safeValue.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5884
|
+
"span",
|
|
5885
|
+
{
|
|
5886
|
+
role: "button",
|
|
5887
|
+
tabIndex: -1,
|
|
5888
|
+
onClick: handleClearAll,
|
|
5889
|
+
className: "rounded-sm hover:bg-muted p-0.5",
|
|
5890
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
5891
|
+
}
|
|
5892
|
+
),
|
|
5893
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4 opacity-50" })
|
|
5894
|
+
] })
|
|
5895
|
+
]
|
|
5896
|
+
}
|
|
5897
|
+
) }),
|
|
5898
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5899
|
+
PopoverContent,
|
|
5900
|
+
{
|
|
5901
|
+
className: "w-[--radix-popover-trigger-width] p-0",
|
|
5902
|
+
align: "start",
|
|
5903
|
+
sideOffset: 4,
|
|
5904
|
+
onKeyDown: handleKeyDown,
|
|
5905
|
+
children: [
|
|
5906
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center border-b border-border px-3", children: [
|
|
5907
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5908
|
+
"input",
|
|
5909
|
+
{
|
|
5910
|
+
ref: inputRef,
|
|
5911
|
+
type: "text",
|
|
5912
|
+
value: search,
|
|
5913
|
+
onChange: (e) => setSearch(e.target.value),
|
|
5914
|
+
placeholder: searchPlaceholder,
|
|
5915
|
+
className: "flex h-9 w-full bg-transparent py-2 text-sm outline-none placeholder:text-muted-foreground"
|
|
5916
|
+
}
|
|
5917
|
+
),
|
|
5918
|
+
search && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5919
|
+
"button",
|
|
5920
|
+
{
|
|
5921
|
+
type: "button",
|
|
5922
|
+
onClick: () => setSearch(""),
|
|
5923
|
+
className: "p-1 hover:bg-muted rounded-sm",
|
|
5924
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
5925
|
+
}
|
|
5926
|
+
)
|
|
5927
|
+
] }),
|
|
5928
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[300px] overflow-y-auto p-1", children: [
|
|
5929
|
+
showSelectAll && selectableFiltered.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5930
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5931
|
+
"button",
|
|
5932
|
+
{
|
|
5933
|
+
type: "button",
|
|
5934
|
+
onClick: handleSelectAll,
|
|
5935
|
+
className: cn(
|
|
5936
|
+
"relative flex w-full cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none",
|
|
5937
|
+
"hover:bg-accent hover:text-accent-foreground"
|
|
5938
|
+
),
|
|
5939
|
+
children: [
|
|
5940
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5941
|
+
Checkbox,
|
|
5942
|
+
{
|
|
5943
|
+
checked: allFilteredSelected ? true : someFilteredSelected ? "indeterminate" : false,
|
|
5944
|
+
tabIndex: -1,
|
|
5945
|
+
className: "pointer-events-none"
|
|
5946
|
+
}
|
|
5947
|
+
),
|
|
5948
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: isSearching ? `${selectAllLabel} (filtered)` : selectAllLabel })
|
|
5949
|
+
]
|
|
5950
|
+
}
|
|
5951
|
+
),
|
|
5952
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "-mx-1 my-1 h-px bg-border" })
|
|
5953
|
+
] }),
|
|
5954
|
+
filteredOptions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyText }) : hasGroups ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5955
|
+
groupedOptions.ungrouped.map(renderOption),
|
|
5956
|
+
Object.entries(groupedOptions.groups).map(([group, opts]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5957
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1.5 text-xs font-semibold text-muted-foreground", children: group }),
|
|
5958
|
+
opts.map(renderOption)
|
|
5959
|
+
] }, group))
|
|
5960
|
+
] }) : filteredOptions.map(renderOption)
|
|
5961
|
+
] })
|
|
5962
|
+
]
|
|
5963
|
+
}
|
|
5964
|
+
)
|
|
5965
|
+
] });
|
|
5966
|
+
}
|
|
5967
|
+
MultiSelect.displayName = "MultiSelect";
|
|
5968
|
+
function Combobox({
|
|
5969
|
+
options,
|
|
5970
|
+
value,
|
|
5971
|
+
onChange,
|
|
5972
|
+
onInputChange,
|
|
5973
|
+
placeholder = "Type or select...",
|
|
5974
|
+
emptyText = "No options found.",
|
|
5975
|
+
disabled = false,
|
|
5976
|
+
className,
|
|
5977
|
+
clearable = false,
|
|
5978
|
+
allowCustomValue = true
|
|
5979
|
+
}) {
|
|
5980
|
+
const [open, setOpen] = React20__namespace.useState(false);
|
|
5981
|
+
const [inputValue, setInputValue] = React20__namespace.useState("");
|
|
5982
|
+
const inputRef = React20__namespace.useRef(null);
|
|
5983
|
+
const wrapperRef = React20__namespace.useRef(null);
|
|
5984
|
+
const selectedOption = React20__namespace.useMemo(
|
|
5985
|
+
() => options.find((opt) => opt.value === value),
|
|
5986
|
+
[options, value]
|
|
5987
|
+
);
|
|
5988
|
+
React20__namespace.useEffect(() => {
|
|
5989
|
+
if (!open) {
|
|
5990
|
+
setInputValue(selectedOption?.label ?? value ?? "");
|
|
5991
|
+
}
|
|
5992
|
+
}, [value, selectedOption, open]);
|
|
5993
|
+
const filteredOptions = React20__namespace.useMemo(() => {
|
|
5994
|
+
if (!inputValue.trim()) return options;
|
|
5995
|
+
const searchLower = inputValue.toLowerCase();
|
|
5996
|
+
return options.filter(
|
|
5997
|
+
(opt) => opt.label.toLowerCase().includes(searchLower) || opt.description?.toLowerCase().includes(searchLower)
|
|
5998
|
+
);
|
|
5999
|
+
}, [options, inputValue]);
|
|
6000
|
+
const groupedOptions = React20__namespace.useMemo(() => {
|
|
6001
|
+
const groups = {};
|
|
6002
|
+
const ungrouped = [];
|
|
6003
|
+
filteredOptions.forEach((opt) => {
|
|
6004
|
+
if (opt.group) {
|
|
6005
|
+
if (!groups[opt.group]) groups[opt.group] = [];
|
|
6006
|
+
groups[opt.group].push(opt);
|
|
6007
|
+
} else {
|
|
6008
|
+
ungrouped.push(opt);
|
|
6009
|
+
}
|
|
6010
|
+
});
|
|
6011
|
+
return { groups, ungrouped };
|
|
6012
|
+
}, [filteredOptions]);
|
|
6013
|
+
const hasGroups = Object.keys(groupedOptions.groups).length > 0;
|
|
6014
|
+
const handleInputChange = React20__namespace.useCallback(
|
|
6015
|
+
(e) => {
|
|
6016
|
+
const newValue = e.target.value;
|
|
6017
|
+
setInputValue(newValue);
|
|
6018
|
+
onInputChange?.(newValue);
|
|
6019
|
+
if (!open) setOpen(true);
|
|
6020
|
+
},
|
|
6021
|
+
[onInputChange, open]
|
|
6022
|
+
);
|
|
6023
|
+
const handleSelect = React20__namespace.useCallback(
|
|
6024
|
+
(optionValue) => {
|
|
6025
|
+
const option = options.find((o) => o.value === optionValue);
|
|
6026
|
+
onChange?.(optionValue);
|
|
6027
|
+
setInputValue(option?.label ?? optionValue);
|
|
6028
|
+
setOpen(false);
|
|
6029
|
+
},
|
|
6030
|
+
[onChange, options]
|
|
6031
|
+
);
|
|
6032
|
+
const handleClear = React20__namespace.useCallback(
|
|
6033
|
+
(e) => {
|
|
6034
|
+
e.stopPropagation();
|
|
6035
|
+
e.preventDefault();
|
|
6036
|
+
onChange?.(void 0);
|
|
6037
|
+
setInputValue("");
|
|
6038
|
+
inputRef.current?.focus();
|
|
6039
|
+
},
|
|
6040
|
+
[onChange]
|
|
6041
|
+
);
|
|
6042
|
+
const handleFocus = React20__namespace.useCallback(() => {
|
|
6043
|
+
setOpen(true);
|
|
6044
|
+
inputRef.current?.select();
|
|
6045
|
+
}, []);
|
|
6046
|
+
const handleBlur = React20__namespace.useCallback(() => {
|
|
6047
|
+
setTimeout(() => {
|
|
6048
|
+
if (!wrapperRef.current?.contains(document.activeElement)) {
|
|
6049
|
+
setOpen(false);
|
|
6050
|
+
}
|
|
6051
|
+
if (allowCustomValue && inputValue.trim()) {
|
|
6052
|
+
const matchingOption = options.find(
|
|
6053
|
+
(opt) => opt.label.toLowerCase() === inputValue.toLowerCase()
|
|
6054
|
+
);
|
|
6055
|
+
if (matchingOption) {
|
|
6056
|
+
onChange?.(matchingOption.value);
|
|
6057
|
+
setInputValue(matchingOption.label);
|
|
6058
|
+
} else {
|
|
6059
|
+
onChange?.(inputValue.trim());
|
|
6060
|
+
}
|
|
6061
|
+
} else if (!allowCustomValue) {
|
|
6062
|
+
setInputValue(selectedOption?.label ?? "");
|
|
6063
|
+
}
|
|
6064
|
+
}, 200);
|
|
6065
|
+
}, [allowCustomValue, inputValue, options, onChange, selectedOption]);
|
|
6066
|
+
const handleKeyDown = React20__namespace.useCallback(
|
|
6067
|
+
(e) => {
|
|
6068
|
+
if (e.key === "Escape") {
|
|
6069
|
+
setOpen(false);
|
|
6070
|
+
setInputValue(selectedOption?.label ?? value ?? "");
|
|
6071
|
+
inputRef.current?.blur();
|
|
6072
|
+
} else if (e.key === "Enter" && open) {
|
|
6073
|
+
e.preventDefault();
|
|
6074
|
+
if (filteredOptions.length === 1) {
|
|
6075
|
+
handleSelect(filteredOptions[0].value);
|
|
6076
|
+
} else if (allowCustomValue && inputValue.trim()) {
|
|
6077
|
+
const exactMatch = filteredOptions.find(
|
|
6078
|
+
(opt) => opt.label.toLowerCase() === inputValue.toLowerCase()
|
|
6079
|
+
);
|
|
6080
|
+
if (exactMatch) {
|
|
6081
|
+
handleSelect(exactMatch.value);
|
|
6082
|
+
} else {
|
|
6083
|
+
onChange?.(inputValue.trim());
|
|
6084
|
+
setOpen(false);
|
|
6085
|
+
}
|
|
6086
|
+
}
|
|
6087
|
+
}
|
|
6088
|
+
},
|
|
6089
|
+
[
|
|
6090
|
+
open,
|
|
6091
|
+
filteredOptions,
|
|
6092
|
+
handleSelect,
|
|
6093
|
+
allowCustomValue,
|
|
6094
|
+
inputValue,
|
|
6095
|
+
onChange,
|
|
6096
|
+
selectedOption,
|
|
6097
|
+
value
|
|
6098
|
+
]
|
|
6099
|
+
);
|
|
6100
|
+
const renderOption = (option) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6101
|
+
"button",
|
|
6102
|
+
{
|
|
6103
|
+
type: "button",
|
|
6104
|
+
disabled: option.disabled,
|
|
6105
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
6106
|
+
onClick: () => handleSelect(option.value),
|
|
6107
|
+
className: cn(
|
|
6108
|
+
"relative flex w-full cursor-pointer select-none items-start gap-2 rounded-sm px-2 py-1.5 text-sm outline-none",
|
|
6109
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
6110
|
+
"focus:bg-accent focus:text-accent-foreground",
|
|
6111
|
+
option.disabled && "pointer-events-none opacity-50",
|
|
6112
|
+
value === option.value && "bg-accent/50"
|
|
6113
|
+
),
|
|
6114
|
+
children: [
|
|
6115
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4 w-4 items-center justify-center flex-shrink-0 mt-0.5", children: value === option.value && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }) }),
|
|
6116
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
6117
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate", children: option.label }),
|
|
6118
|
+
option.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground truncate", children: option.description })
|
|
6119
|
+
] })
|
|
6120
|
+
]
|
|
6121
|
+
},
|
|
6122
|
+
option.value
|
|
6123
|
+
);
|
|
6124
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
6125
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6126
|
+
"div",
|
|
6127
|
+
{
|
|
6128
|
+
ref: wrapperRef,
|
|
6129
|
+
className: cn(
|
|
6130
|
+
"flex h-9 w-full items-center gap-2 rounded-md border border-input bg-transparent px-3 text-sm shadow-sm ring-offset-background",
|
|
6131
|
+
"hover:border-input-hover",
|
|
6132
|
+
"focus-within:outline-none focus-within:ring-1 focus-within:ring-ring",
|
|
6133
|
+
disabled && "cursor-not-allowed opacity-50 hover:border-input",
|
|
6134
|
+
className
|
|
6135
|
+
),
|
|
6136
|
+
children: [
|
|
6137
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6138
|
+
"input",
|
|
6139
|
+
{
|
|
6140
|
+
ref: inputRef,
|
|
6141
|
+
type: "text",
|
|
6142
|
+
value: inputValue,
|
|
6143
|
+
onChange: handleInputChange,
|
|
6144
|
+
onFocus: handleFocus,
|
|
6145
|
+
onBlur: handleBlur,
|
|
6146
|
+
onKeyDown: handleKeyDown,
|
|
6147
|
+
placeholder,
|
|
6148
|
+
disabled,
|
|
6149
|
+
className: "flex-1 min-w-0 bg-transparent py-2 outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed",
|
|
6150
|
+
role: "combobox",
|
|
6151
|
+
"aria-expanded": open,
|
|
6152
|
+
"aria-haspopup": "listbox",
|
|
6153
|
+
"aria-autocomplete": "list"
|
|
6154
|
+
}
|
|
6155
|
+
),
|
|
6156
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
|
|
6157
|
+
clearable && value && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6158
|
+
"span",
|
|
6159
|
+
{
|
|
6160
|
+
role: "button",
|
|
6161
|
+
tabIndex: -1,
|
|
6162
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
6163
|
+
onClick: handleClear,
|
|
6164
|
+
className: "rounded-sm hover:bg-muted p-0.5",
|
|
6165
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
6166
|
+
}
|
|
6167
|
+
),
|
|
6168
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4 opacity-50" })
|
|
6169
|
+
] })
|
|
6170
|
+
]
|
|
6171
|
+
}
|
|
6172
|
+
) }),
|
|
6173
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6174
|
+
PopoverContent,
|
|
6175
|
+
{
|
|
6176
|
+
className: "p-0",
|
|
6177
|
+
style: { width: wrapperRef.current?.offsetWidth },
|
|
6178
|
+
align: "start",
|
|
6179
|
+
sideOffset: 4,
|
|
6180
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
6181
|
+
onFocusOutside: (e) => {
|
|
6182
|
+
if (wrapperRef.current?.contains(e.target)) {
|
|
6183
|
+
e.preventDefault();
|
|
6184
|
+
}
|
|
6185
|
+
},
|
|
6186
|
+
onInteractOutside: (e) => {
|
|
6187
|
+
if (wrapperRef.current?.contains(e.target)) {
|
|
6188
|
+
e.preventDefault();
|
|
6189
|
+
}
|
|
6190
|
+
},
|
|
6191
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-[300px] overflow-y-auto p-1", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyText }) : hasGroups ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6192
|
+
groupedOptions.ungrouped.map(renderOption),
|
|
6193
|
+
Object.entries(groupedOptions.groups).map(([group, opts]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6194
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1.5 text-xs font-semibold text-muted-foreground", children: group }),
|
|
6195
|
+
opts.map(renderOption)
|
|
6196
|
+
] }, group))
|
|
6197
|
+
] }) : filteredOptions.map(renderOption) })
|
|
6198
|
+
}
|
|
6199
|
+
)
|
|
6200
|
+
] });
|
|
6201
|
+
}
|
|
6202
|
+
Combobox.displayName = "Combobox";
|
|
5653
6203
|
var iconButtonVariants = classVarianceAuthority.cva(
|
|
5654
6204
|
// Base styles
|
|
5655
6205
|
[
|
|
@@ -7499,6 +8049,8 @@ var PERMISSIONS_POLICY = [
|
|
|
7499
8049
|
"geolocation=()",
|
|
7500
8050
|
"payment=()",
|
|
7501
8051
|
"usb=()",
|
|
8052
|
+
"clipboard-read=()",
|
|
8053
|
+
"clipboard-write=()",
|
|
7502
8054
|
"display-capture=()",
|
|
7503
8055
|
"fullscreen=()",
|
|
7504
8056
|
"autoplay=()",
|
|
@@ -7961,6 +8513,7 @@ exports.CellEditor = CellEditor;
|
|
|
7961
8513
|
exports.Checkbox = Checkbox;
|
|
7962
8514
|
exports.Chip = Chip;
|
|
7963
8515
|
exports.CodeRenderer = CodeRenderer;
|
|
8516
|
+
exports.Combobox = Combobox;
|
|
7964
8517
|
exports.ConfirmationModal = ConfirmationModal;
|
|
7965
8518
|
exports.ContextMenu = ContextMenu;
|
|
7966
8519
|
exports.CopyButton = CopyButton;
|
|
@@ -8003,6 +8556,7 @@ exports.MODERN_LIGHT_THEME = MODERN_LIGHT_THEME;
|
|
|
8003
8556
|
exports.MarkdownRenderer = MarkdownRenderer;
|
|
8004
8557
|
exports.Modal = Modal;
|
|
8005
8558
|
exports.ModalButton = ModalButton;
|
|
8559
|
+
exports.MultiSelect = MultiSelect;
|
|
8006
8560
|
exports.OPTILOGIC_DARK_THEME = OPTILOGIC_DARK_THEME;
|
|
8007
8561
|
exports.OPTILOGIC_LEGACY_THEME = OPTILOGIC_LEGACY_THEME;
|
|
8008
8562
|
exports.OptilogicLogo = OptilogicLogo;
|
|
@@ -8020,6 +8574,7 @@ exports.Select = Select;
|
|
|
8020
8574
|
exports.SelectContent = SelectContent;
|
|
8021
8575
|
exports.SelectGroup = SelectGroup;
|
|
8022
8576
|
exports.SelectItem = SelectItem;
|
|
8577
|
+
exports.SelectItemDescription = SelectItemDescription;
|
|
8023
8578
|
exports.SelectLabel = SelectLabel;
|
|
8024
8579
|
exports.SelectScrollDownButton = SelectScrollDownButton;
|
|
8025
8580
|
exports.SelectScrollUpButton = SelectScrollUpButton;
|
|
@@ -8087,6 +8642,8 @@ exports.labelVariants = labelVariants;
|
|
|
8087
8642
|
exports.loadingSpinnerVariants = loadingSpinnerVariants;
|
|
8088
8643
|
exports.mergeRenderers = mergeRenderers;
|
|
8089
8644
|
exports.resolveRenderer = resolveRenderer;
|
|
8645
|
+
exports.tabsListVariants = tabsListVariants;
|
|
8646
|
+
exports.tabsTriggerVariants = tabsTriggerVariants;
|
|
8090
8647
|
exports.themeToHsl = themeToHsl;
|
|
8091
8648
|
exports.useColumnResize = useColumnResize;
|
|
8092
8649
|
exports.useColumnResizeManager = useColumnResizeManager;
|