@optilogic/core 1.2.2 → 1.2.3
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 +662 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +143 -5
- package/dist/index.d.ts +143 -5
- package/dist/index.js +658 -53
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/combobox.tsx +340 -0
- package/src/components/data-grid/DataGrid.tsx +66 -24
- package/src/components/data-grid/components/HeaderCell.tsx +5 -1
- package/src/components/data-grid/hooks/useColumnResize.ts +30 -1
- package/src/components/data-grid/types.ts +5 -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.js
CHANGED
|
@@ -351,17 +351,26 @@ var SelectItem = React20.forwardRef(({ className, children, ...props }, ref) =>
|
|
|
351
351
|
{
|
|
352
352
|
ref,
|
|
353
353
|
className: cn(
|
|
354
|
-
"relative flex w-full cursor-default select-none items-
|
|
354
|
+
"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",
|
|
355
355
|
className
|
|
356
356
|
),
|
|
357
357
|
...props,
|
|
358
358
|
children: [
|
|
359
|
-
/* @__PURE__ */ jsx("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
|
|
359
|
+
/* @__PURE__ */ jsx("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center mt-0.5", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
|
|
360
360
|
/* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
|
|
361
361
|
]
|
|
362
362
|
}
|
|
363
363
|
));
|
|
364
364
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
365
|
+
var SelectItemDescription = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
366
|
+
"span",
|
|
367
|
+
{
|
|
368
|
+
ref,
|
|
369
|
+
className: cn("text-xs text-muted-foreground", className),
|
|
370
|
+
...props
|
|
371
|
+
}
|
|
372
|
+
));
|
|
373
|
+
SelectItemDescription.displayName = "SelectItemDescription";
|
|
365
374
|
var SelectSeparator = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
366
375
|
SelectPrimitive.Separator,
|
|
367
376
|
{
|
|
@@ -372,41 +381,85 @@ var SelectSeparator = React20.forwardRef(({ className, ...props }, ref) => /* @_
|
|
|
372
381
|
));
|
|
373
382
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
374
383
|
var Tabs = TabsPrimitive.Root;
|
|
375
|
-
var
|
|
384
|
+
var tabsListVariants = cva(
|
|
385
|
+
"inline-flex h-10 items-center justify-start bg-transparent",
|
|
386
|
+
{
|
|
387
|
+
variants: {
|
|
388
|
+
variant: {
|
|
389
|
+
default: "border-b border-border",
|
|
390
|
+
pill: "gap-1 rounded-lg bg-muted p-1",
|
|
391
|
+
unstyled: ""
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
defaultVariants: {
|
|
395
|
+
variant: "default"
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
);
|
|
399
|
+
var tabsTriggerVariants = cva(
|
|
400
|
+
[
|
|
401
|
+
"inline-flex items-center justify-center whitespace-nowrap",
|
|
402
|
+
"px-4 py-2.5 text-sm font-medium",
|
|
403
|
+
"transition-colors",
|
|
404
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
405
|
+
"disabled:pointer-events-none disabled:opacity-50"
|
|
406
|
+
],
|
|
407
|
+
{
|
|
408
|
+
variants: {
|
|
409
|
+
variant: {
|
|
410
|
+
default: [
|
|
411
|
+
"-mb-px",
|
|
412
|
+
"border-transparent text-muted-foreground",
|
|
413
|
+
"hover:text-foreground hover:border-muted-foreground/50",
|
|
414
|
+
"data-[state=active]:border-foreground data-[state=active]:text-foreground"
|
|
415
|
+
],
|
|
416
|
+
pill: [
|
|
417
|
+
"rounded-md",
|
|
418
|
+
"text-muted-foreground",
|
|
419
|
+
"hover:text-foreground",
|
|
420
|
+
"data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm"
|
|
421
|
+
],
|
|
422
|
+
unstyled: [
|
|
423
|
+
"text-muted-foreground",
|
|
424
|
+
"hover:text-foreground",
|
|
425
|
+
"data-[state=active]:text-foreground"
|
|
426
|
+
]
|
|
427
|
+
},
|
|
428
|
+
indicatorSize: {
|
|
429
|
+
sm: "border-b",
|
|
430
|
+
default: "border-b-2",
|
|
431
|
+
lg: "border-b-[3px]"
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
compoundVariants: [
|
|
435
|
+
{ variant: "pill", indicatorSize: "sm", className: "border-b-0" },
|
|
436
|
+
{ variant: "pill", indicatorSize: "default", className: "border-b-0" },
|
|
437
|
+
{ variant: "pill", indicatorSize: "lg", className: "border-b-0" },
|
|
438
|
+
{ variant: "unstyled", indicatorSize: "sm", className: "border-b-0" },
|
|
439
|
+
{ variant: "unstyled", indicatorSize: "default", className: "border-b-0" },
|
|
440
|
+
{ variant: "unstyled", indicatorSize: "lg", className: "border-b-0" }
|
|
441
|
+
],
|
|
442
|
+
defaultVariants: {
|
|
443
|
+
variant: "default",
|
|
444
|
+
indicatorSize: "default"
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
var TabsList = React20.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
376
449
|
TabsPrimitive.List,
|
|
377
450
|
{
|
|
378
451
|
ref,
|
|
379
|
-
className: cn(
|
|
380
|
-
"inline-flex h-10 items-center justify-start",
|
|
381
|
-
"border-b border-border",
|
|
382
|
-
"bg-transparent",
|
|
383
|
-
className
|
|
384
|
-
),
|
|
452
|
+
className: cn(tabsListVariants({ variant }), className),
|
|
385
453
|
...props
|
|
386
454
|
}
|
|
387
455
|
));
|
|
388
456
|
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
389
|
-
var TabsTrigger = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
457
|
+
var TabsTrigger = React20.forwardRef(({ className, variant, indicatorSize, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
390
458
|
TabsPrimitive.Trigger,
|
|
391
459
|
{
|
|
392
460
|
ref,
|
|
393
461
|
className: cn(
|
|
394
|
-
|
|
395
|
-
"inline-flex items-center justify-center whitespace-nowrap",
|
|
396
|
-
"px-4 py-2.5 text-sm font-medium",
|
|
397
|
-
"transition-colors",
|
|
398
|
-
// Border-bottom indicator style
|
|
399
|
-
"border-b-2 -mb-px",
|
|
400
|
-
// Default state
|
|
401
|
-
"border-transparent text-muted-foreground",
|
|
402
|
-
// Hover state
|
|
403
|
-
"hover:text-foreground hover:border-muted-foreground/50",
|
|
404
|
-
// Active/selected state
|
|
405
|
-
"data-[state=active]:border-foreground data-[state=active]:text-foreground",
|
|
406
|
-
// Focus styles
|
|
407
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
408
|
-
// Disabled styles
|
|
409
|
-
"disabled:pointer-events-none disabled:opacity-50",
|
|
462
|
+
tabsTriggerVariants({ variant, indicatorSize }),
|
|
410
463
|
className
|
|
411
464
|
),
|
|
412
465
|
...props
|
|
@@ -419,7 +472,6 @@ var TabsContent = React20.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
419
472
|
ref,
|
|
420
473
|
className: cn(
|
|
421
474
|
"mt-2",
|
|
422
|
-
// Focus styles
|
|
423
475
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
424
476
|
className
|
|
425
477
|
),
|
|
@@ -3382,6 +3434,7 @@ function HeaderCell({
|
|
|
3382
3434
|
sorting,
|
|
3383
3435
|
filter,
|
|
3384
3436
|
isResizable,
|
|
3437
|
+
fillWidth,
|
|
3385
3438
|
onSort,
|
|
3386
3439
|
onFilterChange,
|
|
3387
3440
|
onResizeMouseDown,
|
|
@@ -3425,7 +3478,8 @@ function HeaderCell({
|
|
|
3425
3478
|
"div",
|
|
3426
3479
|
{
|
|
3427
3480
|
className: cn(
|
|
3428
|
-
"relative
|
|
3481
|
+
"relative border-r border-border last:border-r-0",
|
|
3482
|
+
!fillWidth && "flex-shrink-0",
|
|
3429
3483
|
"bg-muted select-none",
|
|
3430
3484
|
isResizing && "bg-accent/20"
|
|
3431
3485
|
),
|
|
@@ -4365,11 +4419,15 @@ function useColumnResizeManager(options) {
|
|
|
4365
4419
|
resizableColumns,
|
|
4366
4420
|
onColumnResize,
|
|
4367
4421
|
onColumnResizeStart,
|
|
4368
|
-
onColumnResizeEnd
|
|
4422
|
+
onColumnResizeEnd,
|
|
4423
|
+
fillWidth,
|
|
4424
|
+
containerWidth,
|
|
4425
|
+
effectiveColumnWidths
|
|
4369
4426
|
} = options;
|
|
4370
4427
|
const [resizingColumn, setResizingColumn] = useState(null);
|
|
4371
4428
|
const startXRef = useRef(0);
|
|
4372
4429
|
const startWidthRef = useRef(0);
|
|
4430
|
+
const startEffectiveWidthsRef = useRef({});
|
|
4373
4431
|
const getColumn = useCallback(
|
|
4374
4432
|
(columnKey) => {
|
|
4375
4433
|
return columns.find((c) => c.key === columnKey);
|
|
@@ -4393,9 +4451,20 @@ function useColumnResizeManager(options) {
|
|
|
4393
4451
|
resizingColumn,
|
|
4394
4452
|
startWidthRef.current + deltaX
|
|
4395
4453
|
);
|
|
4454
|
+
if (fillWidth && containerWidth) {
|
|
4455
|
+
const otherCols = columns.filter((c) => c.key !== resizingColumn);
|
|
4456
|
+
const startEffective = startEffectiveWidthsRef.current;
|
|
4457
|
+
const otherTotal = otherCols.reduce((s, c) => s + (startEffective[c.key] || 0), 0);
|
|
4458
|
+
const remaining = containerWidth - newWidth;
|
|
4459
|
+
for (const col of otherCols) {
|
|
4460
|
+
const proportion = (startEffective[col.key] || 0) / otherTotal;
|
|
4461
|
+
const adjusted = clampWidth(col.key, Math.floor(remaining * proportion));
|
|
4462
|
+
onColumnResize(col.key, adjusted);
|
|
4463
|
+
}
|
|
4464
|
+
}
|
|
4396
4465
|
onColumnResize(resizingColumn, newWidth);
|
|
4397
4466
|
},
|
|
4398
|
-
[resizingColumn, clampWidth, onColumnResize]
|
|
4467
|
+
[resizingColumn, clampWidth, onColumnResize, fillWidth, containerWidth, columns]
|
|
4399
4468
|
);
|
|
4400
4469
|
const handleMouseUp = useCallback(() => {
|
|
4401
4470
|
if (!resizingColumn) return;
|
|
@@ -4429,6 +4498,9 @@ function useColumnResizeManager(options) {
|
|
|
4429
4498
|
document.body.style.userSelect = "none";
|
|
4430
4499
|
document.body.style.cursor = "col-resize";
|
|
4431
4500
|
onColumnResizeStart?.(columnKey);
|
|
4501
|
+
if (fillWidth && effectiveColumnWidths) {
|
|
4502
|
+
startEffectiveWidthsRef.current = { ...effectiveColumnWidths };
|
|
4503
|
+
}
|
|
4432
4504
|
};
|
|
4433
4505
|
const handleDoubleClick = (event) => {
|
|
4434
4506
|
if (!isResizable) return;
|
|
@@ -4454,7 +4526,9 @@ function useColumnResizeManager(options) {
|
|
|
4454
4526
|
resizingColumn,
|
|
4455
4527
|
onColumnResize,
|
|
4456
4528
|
onColumnResizeStart,
|
|
4457
|
-
onColumnResizeEnd
|
|
4529
|
+
onColumnResizeEnd,
|
|
4530
|
+
fillWidth,
|
|
4531
|
+
effectiveColumnWidths
|
|
4458
4532
|
]
|
|
4459
4533
|
);
|
|
4460
4534
|
return {
|
|
@@ -4679,6 +4753,7 @@ function DataGrid({
|
|
|
4679
4753
|
tooltipMinLength = 30,
|
|
4680
4754
|
enableKeyboardNavigation = true,
|
|
4681
4755
|
showColumnBorders = true,
|
|
4756
|
+
fillWidth,
|
|
4682
4757
|
enableInternalSorting = true,
|
|
4683
4758
|
enableInternalFiltering = true,
|
|
4684
4759
|
// Controlled sorting
|
|
@@ -4733,6 +4808,16 @@ function DataGrid({
|
|
|
4733
4808
|
const headerRef = React20.useRef(null);
|
|
4734
4809
|
const [headerHeight, setHeaderHeight] = React20.useState(40);
|
|
4735
4810
|
const [hoveredCell, setHoveredCell] = React20.useState(null);
|
|
4811
|
+
const [containerWidth, setContainerWidth] = React20.useState(0);
|
|
4812
|
+
React20.useLayoutEffect(() => {
|
|
4813
|
+
if (!fillWidth || !parentRef.current) return;
|
|
4814
|
+
const observer = new ResizeObserver((entries) => {
|
|
4815
|
+
const w = entries[0]?.contentRect.width;
|
|
4816
|
+
if (w && w > 0) setContainerWidth(w);
|
|
4817
|
+
});
|
|
4818
|
+
observer.observe(parentRef.current);
|
|
4819
|
+
return () => observer.disconnect();
|
|
4820
|
+
}, [fillWidth]);
|
|
4736
4821
|
const visibleColumns = React20.useMemo(
|
|
4737
4822
|
() => columns.filter((col) => !col.hidden),
|
|
4738
4823
|
[columns]
|
|
@@ -4786,14 +4871,6 @@ function DataGrid({
|
|
|
4786
4871
|
visibleColumns
|
|
4787
4872
|
]);
|
|
4788
4873
|
processedDataRef.current = processedData;
|
|
4789
|
-
const { resizingColumn, getResizeProps } = useColumnResizeManager({
|
|
4790
|
-
columns: visibleColumns,
|
|
4791
|
-
columnWidths: state.columnWidths,
|
|
4792
|
-
resizableColumns,
|
|
4793
|
-
onColumnResize: actions.setColumnWidth,
|
|
4794
|
-
onColumnResizeStart,
|
|
4795
|
-
onColumnResizeEnd
|
|
4796
|
-
});
|
|
4797
4874
|
const shouldVirtualize = virtualized ?? processedData.length > 100;
|
|
4798
4875
|
React20.useLayoutEffect(() => {
|
|
4799
4876
|
if (headerRef.current && shouldVirtualize) {
|
|
@@ -4807,12 +4884,38 @@ function DataGrid({
|
|
|
4807
4884
|
overscan: DEFAULT_OVERSCAN,
|
|
4808
4885
|
enabled: shouldVirtualize
|
|
4809
4886
|
});
|
|
4810
|
-
const tableWidth = React20.useMemo(() => {
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4887
|
+
const { tableWidth, effectiveColumnWidths } = React20.useMemo(() => {
|
|
4888
|
+
const rawWidths = {};
|
|
4889
|
+
let rawTotal = 0;
|
|
4890
|
+
for (const col of visibleColumns) {
|
|
4891
|
+
const w = state.columnWidths[col.key] || col.width || estimateColumnWidth(col);
|
|
4892
|
+
rawWidths[col.key] = w;
|
|
4893
|
+
rawTotal += w;
|
|
4894
|
+
}
|
|
4895
|
+
if (!fillWidth || !containerWidth || rawTotal >= containerWidth) {
|
|
4896
|
+
return { tableWidth: rawTotal, effectiveColumnWidths: rawWidths };
|
|
4897
|
+
}
|
|
4898
|
+
const scale = containerWidth / rawTotal;
|
|
4899
|
+
const scaled = {};
|
|
4900
|
+
for (const col of visibleColumns) {
|
|
4901
|
+
let w = Math.floor(rawWidths[col.key] * scale);
|
|
4902
|
+
if (col.minWidth) w = Math.max(w, col.minWidth);
|
|
4903
|
+
if (col.maxWidth) w = Math.min(w, col.maxWidth);
|
|
4904
|
+
scaled[col.key] = w;
|
|
4905
|
+
}
|
|
4906
|
+
return { tableWidth: containerWidth, effectiveColumnWidths: scaled };
|
|
4907
|
+
}, [visibleColumns, state.columnWidths, fillWidth, containerWidth]);
|
|
4908
|
+
const { resizingColumn, getResizeProps } = useColumnResizeManager({
|
|
4909
|
+
columns: visibleColumns,
|
|
4910
|
+
columnWidths: state.columnWidths,
|
|
4911
|
+
resizableColumns,
|
|
4912
|
+
onColumnResize: actions.setColumnWidth,
|
|
4913
|
+
onColumnResizeStart,
|
|
4914
|
+
onColumnResizeEnd,
|
|
4915
|
+
fillWidth,
|
|
4916
|
+
containerWidth,
|
|
4917
|
+
effectiveColumnWidths
|
|
4918
|
+
});
|
|
4816
4919
|
const visibleRowCount = React20.useMemo(() => {
|
|
4817
4920
|
if (!parentRef.current) return 10;
|
|
4818
4921
|
return Math.floor(parentRef.current.clientHeight / DEFAULT_ROW_HEIGHT);
|
|
@@ -5044,7 +5147,7 @@ function DataGrid({
|
|
|
5044
5147
|
},
|
|
5045
5148
|
role: "row",
|
|
5046
5149
|
children: visibleColumns.map((column, colIndex) => {
|
|
5047
|
-
const width =
|
|
5150
|
+
const width = effectiveColumnWidths[column.key];
|
|
5048
5151
|
const resizeProps = getResizeProps(column.key);
|
|
5049
5152
|
return /* @__PURE__ */ jsx(
|
|
5050
5153
|
HeaderCell,
|
|
@@ -5055,6 +5158,7 @@ function DataGrid({
|
|
|
5055
5158
|
sorting: getColumnSort(column.key),
|
|
5056
5159
|
filter: getColumnFilter(column.key),
|
|
5057
5160
|
isResizable: resizableColumns && column.resizable !== false,
|
|
5161
|
+
fillWidth,
|
|
5058
5162
|
onSort: () => handleSort(column.key),
|
|
5059
5163
|
onFilterChange: (filter) => handleFilterChange(column.key, filter),
|
|
5060
5164
|
onResizeMouseDown: resizeProps.handleMouseDown,
|
|
@@ -5103,7 +5207,7 @@ function DataGrid({
|
|
|
5103
5207
|
"aria-rowindex": virtualRow.index + 1,
|
|
5104
5208
|
"aria-selected": isSelected,
|
|
5105
5209
|
children: visibleColumns.map((column, colIndex) => {
|
|
5106
|
-
const width =
|
|
5210
|
+
const width = effectiveColumnWidths[column.key];
|
|
5107
5211
|
const isEditingThisCell = state.editingCell?.rowIndex === virtualRow.index && state.editingCell?.columnKey === column.key;
|
|
5108
5212
|
const isFocused = state.focusedCell?.rowIndex === virtualRow.index && state.focusedCell?.columnKey === column.key;
|
|
5109
5213
|
const cellContent = renderCell(
|
|
@@ -5118,7 +5222,8 @@ function DataGrid({
|
|
|
5118
5222
|
"div",
|
|
5119
5223
|
{
|
|
5120
5224
|
className: cn(
|
|
5121
|
-
"
|
|
5225
|
+
"px-3 py-2 text-sm overflow-hidden",
|
|
5226
|
+
!fillWidth && "flex-shrink-0",
|
|
5122
5227
|
showColumnBorders && "border-r border-border last:border-r-0",
|
|
5123
5228
|
isFocused && !isEditingThisCell && "ring-2 ring-inset ring-primary",
|
|
5124
5229
|
isEditingThisCell && "ring-2 ring-inset ring-primary bg-background",
|
|
@@ -5230,7 +5335,7 @@ function DataGrid({
|
|
|
5230
5335
|
}
|
|
5231
5336
|
)
|
|
5232
5337
|
] }) }),
|
|
5233
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-auto min-h-0", children: [
|
|
5338
|
+
/* @__PURE__ */ jsxs("div", { ref: parentRef, className: "flex-1 overflow-auto min-h-0", children: [
|
|
5234
5339
|
/* @__PURE__ */ jsx(
|
|
5235
5340
|
"div",
|
|
5236
5341
|
{
|
|
@@ -5241,7 +5346,7 @@ function DataGrid({
|
|
|
5241
5346
|
style: { width: tableWidth ? `${tableWidth}px` : "100%" },
|
|
5242
5347
|
role: "row",
|
|
5243
5348
|
children: visibleColumns.map((column, colIndex) => {
|
|
5244
|
-
const width =
|
|
5349
|
+
const width = effectiveColumnWidths[column.key];
|
|
5245
5350
|
const resizeProps = getResizeProps(column.key);
|
|
5246
5351
|
return /* @__PURE__ */ jsx(
|
|
5247
5352
|
HeaderCell,
|
|
@@ -5252,6 +5357,7 @@ function DataGrid({
|
|
|
5252
5357
|
sorting: getColumnSort(column.key),
|
|
5253
5358
|
filter: getColumnFilter(column.key),
|
|
5254
5359
|
isResizable: resizableColumns && column.resizable !== false,
|
|
5360
|
+
fillWidth,
|
|
5255
5361
|
onSort: () => handleSort(column.key),
|
|
5256
5362
|
onFilterChange: (filter) => handleFilterChange(column.key, filter),
|
|
5257
5363
|
onResizeMouseDown: resizeProps.handleMouseDown,
|
|
@@ -5281,14 +5387,15 @@ function DataGrid({
|
|
|
5281
5387
|
onDoubleClick: () => onRowDoubleClick?.(row, rowIndex),
|
|
5282
5388
|
role: "row",
|
|
5283
5389
|
children: visibleColumns.map((column) => {
|
|
5284
|
-
const width =
|
|
5390
|
+
const width = effectiveColumnWidths[column.key];
|
|
5285
5391
|
const isEditingThisCell = state.editingCell?.rowIndex === rowIndex && state.editingCell?.columnKey === column.key;
|
|
5286
5392
|
const isFocused = state.focusedCell?.rowIndex === rowIndex && state.focusedCell?.columnKey === column.key;
|
|
5287
5393
|
return /* @__PURE__ */ jsx(
|
|
5288
5394
|
"div",
|
|
5289
5395
|
{
|
|
5290
5396
|
className: cn(
|
|
5291
|
-
"
|
|
5397
|
+
"px-3 py-2 text-sm overflow-hidden",
|
|
5398
|
+
!fillWidth && "flex-shrink-0",
|
|
5292
5399
|
showColumnBorders && "border-r border-border last:border-r-0",
|
|
5293
5400
|
isFocused && !isEditingThisCell && "ring-2 ring-inset ring-primary",
|
|
5294
5401
|
isEditingThisCell && "ring-2 ring-inset ring-primary bg-background",
|
|
@@ -5613,6 +5720,504 @@ function Autocomplete({
|
|
|
5613
5720
|
)
|
|
5614
5721
|
] });
|
|
5615
5722
|
}
|
|
5723
|
+
function MultiSelect({
|
|
5724
|
+
options,
|
|
5725
|
+
value,
|
|
5726
|
+
onChange,
|
|
5727
|
+
placeholder = "Select items...",
|
|
5728
|
+
searchPlaceholder = "Search...",
|
|
5729
|
+
emptyText = "No options found.",
|
|
5730
|
+
disabled = false,
|
|
5731
|
+
className,
|
|
5732
|
+
clearable = true,
|
|
5733
|
+
maxDisplayItems = 3,
|
|
5734
|
+
showSelectAll = false,
|
|
5735
|
+
selectAllLabel = "Select all"
|
|
5736
|
+
}) {
|
|
5737
|
+
const [open, setOpen] = React20.useState(false);
|
|
5738
|
+
const [search, setSearch] = React20.useState("");
|
|
5739
|
+
const inputRef = React20.useRef(null);
|
|
5740
|
+
const safeOptions = options ?? [];
|
|
5741
|
+
const safeValue = value ?? [];
|
|
5742
|
+
const selectedSet = React20.useMemo(() => new Set(safeValue), [safeValue]);
|
|
5743
|
+
const filteredOptions = React20.useMemo(() => {
|
|
5744
|
+
if (!search.trim()) return safeOptions;
|
|
5745
|
+
const searchLower = search.toLowerCase();
|
|
5746
|
+
return safeOptions.filter(
|
|
5747
|
+
(opt) => opt.label.toLowerCase().includes(searchLower) || opt.description?.toLowerCase().includes(searchLower)
|
|
5748
|
+
);
|
|
5749
|
+
}, [safeOptions, search]);
|
|
5750
|
+
const groupedOptions = React20.useMemo(() => {
|
|
5751
|
+
const groups = {};
|
|
5752
|
+
const ungrouped = [];
|
|
5753
|
+
filteredOptions.forEach((opt) => {
|
|
5754
|
+
if (opt.group) {
|
|
5755
|
+
if (!groups[opt.group]) groups[opt.group] = [];
|
|
5756
|
+
groups[opt.group].push(opt);
|
|
5757
|
+
} else {
|
|
5758
|
+
ungrouped.push(opt);
|
|
5759
|
+
}
|
|
5760
|
+
});
|
|
5761
|
+
return { groups, ungrouped };
|
|
5762
|
+
}, [filteredOptions]);
|
|
5763
|
+
const hasGroups = Object.keys(groupedOptions.groups).length > 0;
|
|
5764
|
+
const selectableFiltered = React20.useMemo(
|
|
5765
|
+
() => filteredOptions.filter((opt) => !opt.disabled),
|
|
5766
|
+
[filteredOptions]
|
|
5767
|
+
);
|
|
5768
|
+
const allFilteredSelected = React20.useMemo(
|
|
5769
|
+
() => selectableFiltered.length > 0 && selectableFiltered.every((opt) => selectedSet.has(opt.value)),
|
|
5770
|
+
[selectableFiltered, selectedSet]
|
|
5771
|
+
);
|
|
5772
|
+
const someFilteredSelected = React20.useMemo(
|
|
5773
|
+
() => !allFilteredSelected && selectableFiltered.some((opt) => selectedSet.has(opt.value)),
|
|
5774
|
+
[selectableFiltered, selectedSet, allFilteredSelected]
|
|
5775
|
+
);
|
|
5776
|
+
const handleToggle = React20.useCallback(
|
|
5777
|
+
(optionValue) => {
|
|
5778
|
+
const next = selectedSet.has(optionValue) ? safeValue.filter((v) => v !== optionValue) : [...safeValue, optionValue];
|
|
5779
|
+
onChange?.(next);
|
|
5780
|
+
},
|
|
5781
|
+
[onChange, safeValue, selectedSet]
|
|
5782
|
+
);
|
|
5783
|
+
const handleRemove = React20.useCallback(
|
|
5784
|
+
(optionValue, e) => {
|
|
5785
|
+
e.stopPropagation();
|
|
5786
|
+
onChange?.(safeValue.filter((v) => v !== optionValue));
|
|
5787
|
+
},
|
|
5788
|
+
[onChange, safeValue]
|
|
5789
|
+
);
|
|
5790
|
+
const handleClearAll = React20.useCallback(
|
|
5791
|
+
(e) => {
|
|
5792
|
+
e.stopPropagation();
|
|
5793
|
+
onChange?.([]);
|
|
5794
|
+
},
|
|
5795
|
+
[onChange]
|
|
5796
|
+
);
|
|
5797
|
+
const handleSelectAll = React20.useCallback(() => {
|
|
5798
|
+
if (allFilteredSelected) {
|
|
5799
|
+
const filteredValues = new Set(selectableFiltered.map((o) => o.value));
|
|
5800
|
+
onChange?.(safeValue.filter((v) => !filteredValues.has(v)));
|
|
5801
|
+
} else {
|
|
5802
|
+
const existing = new Set(safeValue);
|
|
5803
|
+
const next = [...safeValue];
|
|
5804
|
+
for (const opt of selectableFiltered) {
|
|
5805
|
+
if (!existing.has(opt.value)) {
|
|
5806
|
+
next.push(opt.value);
|
|
5807
|
+
}
|
|
5808
|
+
}
|
|
5809
|
+
onChange?.(next);
|
|
5810
|
+
}
|
|
5811
|
+
}, [allFilteredSelected, selectableFiltered, safeValue, onChange]);
|
|
5812
|
+
React20.useEffect(() => {
|
|
5813
|
+
if (open) {
|
|
5814
|
+
const timeout = setTimeout(() => inputRef.current?.focus(), 0);
|
|
5815
|
+
return () => clearTimeout(timeout);
|
|
5816
|
+
} else {
|
|
5817
|
+
setSearch("");
|
|
5818
|
+
}
|
|
5819
|
+
}, [open]);
|
|
5820
|
+
const handleKeyDown = React20.useCallback((e) => {
|
|
5821
|
+
if (e.key === "Escape") setOpen(false);
|
|
5822
|
+
}, []);
|
|
5823
|
+
const selectedLabels = React20.useMemo(
|
|
5824
|
+
() => safeValue.map((v) => safeOptions.find((o) => o.value === v)?.label ?? v).slice(0, maxDisplayItems),
|
|
5825
|
+
[safeValue, safeOptions, maxDisplayItems]
|
|
5826
|
+
);
|
|
5827
|
+
const overflow = safeValue.length - maxDisplayItems;
|
|
5828
|
+
const isSearching = search.trim().length > 0;
|
|
5829
|
+
const renderOption = (option) => /* @__PURE__ */ jsxs(
|
|
5830
|
+
"button",
|
|
5831
|
+
{
|
|
5832
|
+
type: "button",
|
|
5833
|
+
disabled: option.disabled,
|
|
5834
|
+
onClick: () => handleToggle(option.value),
|
|
5835
|
+
className: cn(
|
|
5836
|
+
"relative flex w-full cursor-pointer select-none items-start gap-2 rounded-sm px-2 py-1.5 text-sm outline-none",
|
|
5837
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
5838
|
+
option.disabled && "pointer-events-none opacity-50"
|
|
5839
|
+
),
|
|
5840
|
+
children: [
|
|
5841
|
+
/* @__PURE__ */ jsx(
|
|
5842
|
+
Checkbox,
|
|
5843
|
+
{
|
|
5844
|
+
checked: selectedSet.has(option.value),
|
|
5845
|
+
tabIndex: -1,
|
|
5846
|
+
className: "mt-0.5 pointer-events-none"
|
|
5847
|
+
}
|
|
5848
|
+
),
|
|
5849
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
5850
|
+
/* @__PURE__ */ jsx("div", { className: "truncate", children: option.label }),
|
|
5851
|
+
option.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground truncate", children: option.description })
|
|
5852
|
+
] })
|
|
5853
|
+
]
|
|
5854
|
+
},
|
|
5855
|
+
option.value
|
|
5856
|
+
);
|
|
5857
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
5858
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(
|
|
5859
|
+
"button",
|
|
5860
|
+
{
|
|
5861
|
+
type: "button",
|
|
5862
|
+
role: "combobox",
|
|
5863
|
+
"aria-expanded": open,
|
|
5864
|
+
"aria-haspopup": "listbox",
|
|
5865
|
+
disabled,
|
|
5866
|
+
className: cn(
|
|
5867
|
+
"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",
|
|
5868
|
+
"hover:border-input-hover",
|
|
5869
|
+
"focus:outline-none focus:ring-1 focus:ring-ring",
|
|
5870
|
+
"disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-input",
|
|
5871
|
+
className
|
|
5872
|
+
),
|
|
5873
|
+
children: [
|
|
5874
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-wrap gap-1 items-center min-w-0", children: safeValue.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5875
|
+
selectedLabels.map((label, i) => /* @__PURE__ */ jsxs(
|
|
5876
|
+
"span",
|
|
5877
|
+
{
|
|
5878
|
+
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",
|
|
5879
|
+
children: [
|
|
5880
|
+
/* @__PURE__ */ jsx("span", { className: "truncate max-w-[100px]", children: label }),
|
|
5881
|
+
/* @__PURE__ */ jsx(
|
|
5882
|
+
"span",
|
|
5883
|
+
{
|
|
5884
|
+
role: "button",
|
|
5885
|
+
tabIndex: -1,
|
|
5886
|
+
onClick: (e) => handleRemove(safeValue[i], e),
|
|
5887
|
+
className: "rounded-sm hover:bg-foreground/10 p-0.5",
|
|
5888
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
|
|
5889
|
+
}
|
|
5890
|
+
)
|
|
5891
|
+
]
|
|
5892
|
+
},
|
|
5893
|
+
safeValue[i]
|
|
5894
|
+
)),
|
|
5895
|
+
overflow > 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
5896
|
+
"+",
|
|
5897
|
+
overflow
|
|
5898
|
+
] })
|
|
5899
|
+
] }) }),
|
|
5900
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
|
|
5901
|
+
clearable && safeValue.length > 0 && /* @__PURE__ */ jsx(
|
|
5902
|
+
"span",
|
|
5903
|
+
{
|
|
5904
|
+
role: "button",
|
|
5905
|
+
tabIndex: -1,
|
|
5906
|
+
onClick: handleClearAll,
|
|
5907
|
+
className: "rounded-sm hover:bg-muted p-0.5",
|
|
5908
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
5909
|
+
}
|
|
5910
|
+
),
|
|
5911
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 opacity-50" })
|
|
5912
|
+
] })
|
|
5913
|
+
]
|
|
5914
|
+
}
|
|
5915
|
+
) }),
|
|
5916
|
+
/* @__PURE__ */ jsxs(
|
|
5917
|
+
PopoverContent,
|
|
5918
|
+
{
|
|
5919
|
+
className: "w-[--radix-popover-trigger-width] p-0",
|
|
5920
|
+
align: "start",
|
|
5921
|
+
sideOffset: 4,
|
|
5922
|
+
onKeyDown: handleKeyDown,
|
|
5923
|
+
children: [
|
|
5924
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center border-b border-border px-3", children: [
|
|
5925
|
+
/* @__PURE__ */ jsx(
|
|
5926
|
+
"input",
|
|
5927
|
+
{
|
|
5928
|
+
ref: inputRef,
|
|
5929
|
+
type: "text",
|
|
5930
|
+
value: search,
|
|
5931
|
+
onChange: (e) => setSearch(e.target.value),
|
|
5932
|
+
placeholder: searchPlaceholder,
|
|
5933
|
+
className: "flex h-9 w-full bg-transparent py-2 text-sm outline-none placeholder:text-muted-foreground"
|
|
5934
|
+
}
|
|
5935
|
+
),
|
|
5936
|
+
search && /* @__PURE__ */ jsx(
|
|
5937
|
+
"button",
|
|
5938
|
+
{
|
|
5939
|
+
type: "button",
|
|
5940
|
+
onClick: () => setSearch(""),
|
|
5941
|
+
className: "p-1 hover:bg-muted rounded-sm",
|
|
5942
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
5943
|
+
}
|
|
5944
|
+
)
|
|
5945
|
+
] }),
|
|
5946
|
+
/* @__PURE__ */ jsxs("div", { className: "max-h-[300px] overflow-y-auto p-1", children: [
|
|
5947
|
+
showSelectAll && selectableFiltered.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5948
|
+
/* @__PURE__ */ jsxs(
|
|
5949
|
+
"button",
|
|
5950
|
+
{
|
|
5951
|
+
type: "button",
|
|
5952
|
+
onClick: handleSelectAll,
|
|
5953
|
+
className: cn(
|
|
5954
|
+
"relative flex w-full cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none",
|
|
5955
|
+
"hover:bg-accent hover:text-accent-foreground"
|
|
5956
|
+
),
|
|
5957
|
+
children: [
|
|
5958
|
+
/* @__PURE__ */ jsx(
|
|
5959
|
+
Checkbox,
|
|
5960
|
+
{
|
|
5961
|
+
checked: allFilteredSelected ? true : someFilteredSelected ? "indeterminate" : false,
|
|
5962
|
+
tabIndex: -1,
|
|
5963
|
+
className: "pointer-events-none"
|
|
5964
|
+
}
|
|
5965
|
+
),
|
|
5966
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: isSearching ? `${selectAllLabel} (filtered)` : selectAllLabel })
|
|
5967
|
+
]
|
|
5968
|
+
}
|
|
5969
|
+
),
|
|
5970
|
+
/* @__PURE__ */ jsx("div", { className: "-mx-1 my-1 h-px bg-border" })
|
|
5971
|
+
] }),
|
|
5972
|
+
filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyText }) : hasGroups ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5973
|
+
groupedOptions.ungrouped.map(renderOption),
|
|
5974
|
+
Object.entries(groupedOptions.groups).map(([group, opts]) => /* @__PURE__ */ jsxs("div", { children: [
|
|
5975
|
+
/* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs font-semibold text-muted-foreground", children: group }),
|
|
5976
|
+
opts.map(renderOption)
|
|
5977
|
+
] }, group))
|
|
5978
|
+
] }) : filteredOptions.map(renderOption)
|
|
5979
|
+
] })
|
|
5980
|
+
]
|
|
5981
|
+
}
|
|
5982
|
+
)
|
|
5983
|
+
] });
|
|
5984
|
+
}
|
|
5985
|
+
MultiSelect.displayName = "MultiSelect";
|
|
5986
|
+
function Combobox({
|
|
5987
|
+
options,
|
|
5988
|
+
value,
|
|
5989
|
+
onChange,
|
|
5990
|
+
onInputChange,
|
|
5991
|
+
placeholder = "Type or select...",
|
|
5992
|
+
emptyText = "No options found.",
|
|
5993
|
+
disabled = false,
|
|
5994
|
+
className,
|
|
5995
|
+
clearable = false,
|
|
5996
|
+
allowCustomValue = true
|
|
5997
|
+
}) {
|
|
5998
|
+
const [open, setOpen] = React20.useState(false);
|
|
5999
|
+
const [inputValue, setInputValue] = React20.useState("");
|
|
6000
|
+
const inputRef = React20.useRef(null);
|
|
6001
|
+
const wrapperRef = React20.useRef(null);
|
|
6002
|
+
const selectedOption = React20.useMemo(
|
|
6003
|
+
() => options.find((opt) => opt.value === value),
|
|
6004
|
+
[options, value]
|
|
6005
|
+
);
|
|
6006
|
+
React20.useEffect(() => {
|
|
6007
|
+
if (!open) {
|
|
6008
|
+
setInputValue(selectedOption?.label ?? value ?? "");
|
|
6009
|
+
}
|
|
6010
|
+
}, [value, selectedOption, open]);
|
|
6011
|
+
const filteredOptions = React20.useMemo(() => {
|
|
6012
|
+
if (!inputValue.trim()) return options;
|
|
6013
|
+
const searchLower = inputValue.toLowerCase();
|
|
6014
|
+
return options.filter(
|
|
6015
|
+
(opt) => opt.label.toLowerCase().includes(searchLower) || opt.description?.toLowerCase().includes(searchLower)
|
|
6016
|
+
);
|
|
6017
|
+
}, [options, inputValue]);
|
|
6018
|
+
const groupedOptions = React20.useMemo(() => {
|
|
6019
|
+
const groups = {};
|
|
6020
|
+
const ungrouped = [];
|
|
6021
|
+
filteredOptions.forEach((opt) => {
|
|
6022
|
+
if (opt.group) {
|
|
6023
|
+
if (!groups[opt.group]) groups[opt.group] = [];
|
|
6024
|
+
groups[opt.group].push(opt);
|
|
6025
|
+
} else {
|
|
6026
|
+
ungrouped.push(opt);
|
|
6027
|
+
}
|
|
6028
|
+
});
|
|
6029
|
+
return { groups, ungrouped };
|
|
6030
|
+
}, [filteredOptions]);
|
|
6031
|
+
const hasGroups = Object.keys(groupedOptions.groups).length > 0;
|
|
6032
|
+
const handleInputChange = React20.useCallback(
|
|
6033
|
+
(e) => {
|
|
6034
|
+
const newValue = e.target.value;
|
|
6035
|
+
setInputValue(newValue);
|
|
6036
|
+
onInputChange?.(newValue);
|
|
6037
|
+
if (!open) setOpen(true);
|
|
6038
|
+
},
|
|
6039
|
+
[onInputChange, open]
|
|
6040
|
+
);
|
|
6041
|
+
const handleSelect = React20.useCallback(
|
|
6042
|
+
(optionValue) => {
|
|
6043
|
+
const option = options.find((o) => o.value === optionValue);
|
|
6044
|
+
onChange?.(optionValue);
|
|
6045
|
+
setInputValue(option?.label ?? optionValue);
|
|
6046
|
+
setOpen(false);
|
|
6047
|
+
},
|
|
6048
|
+
[onChange, options]
|
|
6049
|
+
);
|
|
6050
|
+
const handleClear = React20.useCallback(
|
|
6051
|
+
(e) => {
|
|
6052
|
+
e.stopPropagation();
|
|
6053
|
+
e.preventDefault();
|
|
6054
|
+
onChange?.(void 0);
|
|
6055
|
+
setInputValue("");
|
|
6056
|
+
inputRef.current?.focus();
|
|
6057
|
+
},
|
|
6058
|
+
[onChange]
|
|
6059
|
+
);
|
|
6060
|
+
const handleFocus = React20.useCallback(() => {
|
|
6061
|
+
setOpen(true);
|
|
6062
|
+
inputRef.current?.select();
|
|
6063
|
+
}, []);
|
|
6064
|
+
const handleBlur = React20.useCallback(() => {
|
|
6065
|
+
setTimeout(() => {
|
|
6066
|
+
if (!wrapperRef.current?.contains(document.activeElement)) {
|
|
6067
|
+
setOpen(false);
|
|
6068
|
+
}
|
|
6069
|
+
if (allowCustomValue && inputValue.trim()) {
|
|
6070
|
+
const matchingOption = options.find(
|
|
6071
|
+
(opt) => opt.label.toLowerCase() === inputValue.toLowerCase()
|
|
6072
|
+
);
|
|
6073
|
+
if (matchingOption) {
|
|
6074
|
+
onChange?.(matchingOption.value);
|
|
6075
|
+
setInputValue(matchingOption.label);
|
|
6076
|
+
} else {
|
|
6077
|
+
onChange?.(inputValue.trim());
|
|
6078
|
+
}
|
|
6079
|
+
} else if (!allowCustomValue) {
|
|
6080
|
+
setInputValue(selectedOption?.label ?? "");
|
|
6081
|
+
}
|
|
6082
|
+
}, 200);
|
|
6083
|
+
}, [allowCustomValue, inputValue, options, onChange, selectedOption]);
|
|
6084
|
+
const handleKeyDown = React20.useCallback(
|
|
6085
|
+
(e) => {
|
|
6086
|
+
if (e.key === "Escape") {
|
|
6087
|
+
setOpen(false);
|
|
6088
|
+
setInputValue(selectedOption?.label ?? value ?? "");
|
|
6089
|
+
inputRef.current?.blur();
|
|
6090
|
+
} else if (e.key === "Enter" && open) {
|
|
6091
|
+
e.preventDefault();
|
|
6092
|
+
if (filteredOptions.length === 1) {
|
|
6093
|
+
handleSelect(filteredOptions[0].value);
|
|
6094
|
+
} else if (allowCustomValue && inputValue.trim()) {
|
|
6095
|
+
const exactMatch = filteredOptions.find(
|
|
6096
|
+
(opt) => opt.label.toLowerCase() === inputValue.toLowerCase()
|
|
6097
|
+
);
|
|
6098
|
+
if (exactMatch) {
|
|
6099
|
+
handleSelect(exactMatch.value);
|
|
6100
|
+
} else {
|
|
6101
|
+
onChange?.(inputValue.trim());
|
|
6102
|
+
setOpen(false);
|
|
6103
|
+
}
|
|
6104
|
+
}
|
|
6105
|
+
}
|
|
6106
|
+
},
|
|
6107
|
+
[
|
|
6108
|
+
open,
|
|
6109
|
+
filteredOptions,
|
|
6110
|
+
handleSelect,
|
|
6111
|
+
allowCustomValue,
|
|
6112
|
+
inputValue,
|
|
6113
|
+
onChange,
|
|
6114
|
+
selectedOption,
|
|
6115
|
+
value
|
|
6116
|
+
]
|
|
6117
|
+
);
|
|
6118
|
+
const renderOption = (option) => /* @__PURE__ */ jsxs(
|
|
6119
|
+
"button",
|
|
6120
|
+
{
|
|
6121
|
+
type: "button",
|
|
6122
|
+
disabled: option.disabled,
|
|
6123
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
6124
|
+
onClick: () => handleSelect(option.value),
|
|
6125
|
+
className: cn(
|
|
6126
|
+
"relative flex w-full cursor-pointer select-none items-start gap-2 rounded-sm px-2 py-1.5 text-sm outline-none",
|
|
6127
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
6128
|
+
"focus:bg-accent focus:text-accent-foreground",
|
|
6129
|
+
option.disabled && "pointer-events-none opacity-50",
|
|
6130
|
+
value === option.value && "bg-accent/50"
|
|
6131
|
+
),
|
|
6132
|
+
children: [
|
|
6133
|
+
/* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 items-center justify-center flex-shrink-0 mt-0.5", children: value === option.value && /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }),
|
|
6134
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
6135
|
+
/* @__PURE__ */ jsx("div", { className: "truncate", children: option.label }),
|
|
6136
|
+
option.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground truncate", children: option.description })
|
|
6137
|
+
] })
|
|
6138
|
+
]
|
|
6139
|
+
},
|
|
6140
|
+
option.value
|
|
6141
|
+
);
|
|
6142
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
6143
|
+
/* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
6144
|
+
"div",
|
|
6145
|
+
{
|
|
6146
|
+
ref: wrapperRef,
|
|
6147
|
+
className: cn(
|
|
6148
|
+
"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",
|
|
6149
|
+
"hover:border-input-hover",
|
|
6150
|
+
"focus-within:outline-none focus-within:ring-1 focus-within:ring-ring",
|
|
6151
|
+
disabled && "cursor-not-allowed opacity-50 hover:border-input",
|
|
6152
|
+
className
|
|
6153
|
+
),
|
|
6154
|
+
children: [
|
|
6155
|
+
/* @__PURE__ */ jsx(
|
|
6156
|
+
"input",
|
|
6157
|
+
{
|
|
6158
|
+
ref: inputRef,
|
|
6159
|
+
type: "text",
|
|
6160
|
+
value: inputValue,
|
|
6161
|
+
onChange: handleInputChange,
|
|
6162
|
+
onFocus: handleFocus,
|
|
6163
|
+
onBlur: handleBlur,
|
|
6164
|
+
onKeyDown: handleKeyDown,
|
|
6165
|
+
placeholder,
|
|
6166
|
+
disabled,
|
|
6167
|
+
className: "flex-1 min-w-0 bg-transparent py-2 outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed",
|
|
6168
|
+
role: "combobox",
|
|
6169
|
+
"aria-expanded": open,
|
|
6170
|
+
"aria-haspopup": "listbox",
|
|
6171
|
+
"aria-autocomplete": "list"
|
|
6172
|
+
}
|
|
6173
|
+
),
|
|
6174
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
|
|
6175
|
+
clearable && value && /* @__PURE__ */ jsx(
|
|
6176
|
+
"span",
|
|
6177
|
+
{
|
|
6178
|
+
role: "button",
|
|
6179
|
+
tabIndex: -1,
|
|
6180
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
6181
|
+
onClick: handleClear,
|
|
6182
|
+
className: "rounded-sm hover:bg-muted p-0.5",
|
|
6183
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
6184
|
+
}
|
|
6185
|
+
),
|
|
6186
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 opacity-50" })
|
|
6187
|
+
] })
|
|
6188
|
+
]
|
|
6189
|
+
}
|
|
6190
|
+
) }),
|
|
6191
|
+
/* @__PURE__ */ jsx(
|
|
6192
|
+
PopoverContent,
|
|
6193
|
+
{
|
|
6194
|
+
className: "p-0",
|
|
6195
|
+
style: { width: wrapperRef.current?.offsetWidth },
|
|
6196
|
+
align: "start",
|
|
6197
|
+
sideOffset: 4,
|
|
6198
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
6199
|
+
onFocusOutside: (e) => {
|
|
6200
|
+
if (wrapperRef.current?.contains(e.target)) {
|
|
6201
|
+
e.preventDefault();
|
|
6202
|
+
}
|
|
6203
|
+
},
|
|
6204
|
+
onInteractOutside: (e) => {
|
|
6205
|
+
if (wrapperRef.current?.contains(e.target)) {
|
|
6206
|
+
e.preventDefault();
|
|
6207
|
+
}
|
|
6208
|
+
},
|
|
6209
|
+
children: /* @__PURE__ */ jsx("div", { className: "max-h-[300px] overflow-y-auto p-1", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyText }) : hasGroups ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6210
|
+
groupedOptions.ungrouped.map(renderOption),
|
|
6211
|
+
Object.entries(groupedOptions.groups).map(([group, opts]) => /* @__PURE__ */ jsxs("div", { children: [
|
|
6212
|
+
/* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs font-semibold text-muted-foreground", children: group }),
|
|
6213
|
+
opts.map(renderOption)
|
|
6214
|
+
] }, group))
|
|
6215
|
+
] }) : filteredOptions.map(renderOption) })
|
|
6216
|
+
}
|
|
6217
|
+
)
|
|
6218
|
+
] });
|
|
6219
|
+
}
|
|
6220
|
+
Combobox.displayName = "Combobox";
|
|
5616
6221
|
var iconButtonVariants = cva(
|
|
5617
6222
|
// Base styles
|
|
5618
6223
|
[
|
|
@@ -7889,6 +8494,6 @@ var DataStarIcon = forwardRef(
|
|
|
7889
8494
|
);
|
|
7890
8495
|
DataStarIcon.displayName = "DataStarIcon";
|
|
7891
8496
|
|
|
7892
|
-
export { ALL_THEMES, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Autocomplete, Badge, Board, BoardContent, BoardHeader, Button, Calendar, Card, CardActions, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardImage, CardList, CardTitle, CellEditor, Checkbox, Chip, CodeRenderer, ConfirmationModal, ContextMenu, CopyButton, CosmicFrogIcon, CsvRenderer, DARK_ELEGANT_THEME, DEFAULT_RENDERERS, DataGrid, DataStarIcon, DataTable, DatePicker, DatePickerInput, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FileView, FilterPopover, HeaderCell, HtmlRenderer, IconButton, ImageRenderer, Input, Label, LoadingSpinner, MINIMALIST_LIGHT_THEME, MODERN_DARK_THEME, MODERN_LIGHT_THEME, MarkdownRenderer, Modal, ModalButton, OPTILOGIC_DARK_THEME, OPTILOGIC_LEGACY_THEME, OptilogicLogo, OptilogicLogoWithText, PRESET_THEMES, PlainTextRenderer, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, ResizablePanel, ResizeHandle, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectableCard, Separator, Skeleton, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemePicker, Toaster, Tooltip, TooltipArrow, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger, accordionContentVariants, accordionItemVariants, accordionTriggerVariants, applyFilterOperator, applyFilters, applySorting, applyTheme, areThemesEqual, badgeVariants, boardVariants, buttonVariants, cardActionsVariants, cardGridVariants, cardImageVariants, cardListVariants, cardVariants, cloneTheme, cn, detectContentType, exportTheme, getCellValue, getCurrentTheme, getDefaultTheme, getFileExtension, getPresetTheme, hexToHsl, iconButtonVariants, importTheme, isPresetTheme, isTextContentType, isUrlContentType, labelVariants, loadingSpinnerVariants, mergeRenderers, resolveRenderer, themeToHsl, useColumnResize, useColumnResizeManager, useConfirmation, useContentType, useContextMenu, useDataGridState, useKeyboardNavigation, validateTheme };
|
|
8497
|
+
export { ALL_THEMES, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Autocomplete, Badge, Board, BoardContent, BoardHeader, Button, Calendar, Card, CardActions, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardImage, CardList, CardTitle, CellEditor, Checkbox, Chip, CodeRenderer, Combobox, ConfirmationModal, ContextMenu, CopyButton, CosmicFrogIcon, CsvRenderer, DARK_ELEGANT_THEME, DEFAULT_RENDERERS, DataGrid, DataStarIcon, DataTable, DatePicker, DatePickerInput, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FileView, FilterPopover, HeaderCell, HtmlRenderer, IconButton, ImageRenderer, Input, Label, LoadingSpinner, MINIMALIST_LIGHT_THEME, MODERN_DARK_THEME, MODERN_LIGHT_THEME, MarkdownRenderer, Modal, ModalButton, MultiSelect, OPTILOGIC_DARK_THEME, OPTILOGIC_LEGACY_THEME, OptilogicLogo, OptilogicLogoWithText, PRESET_THEMES, PlainTextRenderer, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, ResizablePanel, ResizeHandle, Select, SelectContent, SelectGroup, SelectItem, SelectItemDescription, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectableCard, Separator, Skeleton, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemePicker, Toaster, Tooltip, TooltipArrow, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger, accordionContentVariants, accordionItemVariants, accordionTriggerVariants, applyFilterOperator, applyFilters, applySorting, applyTheme, areThemesEqual, badgeVariants, boardVariants, buttonVariants, cardActionsVariants, cardGridVariants, cardImageVariants, cardListVariants, cardVariants, cloneTheme, cn, detectContentType, exportTheme, getCellValue, getCurrentTheme, getDefaultTheme, getFileExtension, getPresetTheme, hexToHsl, iconButtonVariants, importTheme, isPresetTheme, isTextContentType, isUrlContentType, labelVariants, loadingSpinnerVariants, mergeRenderers, resolveRenderer, tabsListVariants, tabsTriggerVariants, themeToHsl, useColumnResize, useColumnResizeManager, useConfirmation, useContentType, useContextMenu, useDataGridState, useKeyboardNavigation, validateTheme };
|
|
7893
8498
|
//# sourceMappingURL=index.js.map
|
|
7894
8499
|
//# sourceMappingURL=index.js.map
|