@underverse-ui/underverse 1.0.112 → 1.0.115
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/api-reference.json +1 -1
- package/dist/index.cjs +359 -118
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +375 -134
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7692,6 +7692,7 @@ var Combobox = ({
|
|
|
7692
7692
|
id: `${resolvedId}-listbox`,
|
|
7693
7693
|
role: "listbox",
|
|
7694
7694
|
"aria-labelledby": labelId,
|
|
7695
|
+
"data-os-ignore": virtualized ? "" : void 0,
|
|
7695
7696
|
className: cn("overflow-y-auto overscroll-contain", (!useOverlayScrollbar || virtualized) && comboboxScrollClassName),
|
|
7696
7697
|
style: { maxHeight },
|
|
7697
7698
|
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: cn(size === "sm" ? "p-1" : size === "lg" ? "p-2" : "p-1.5"), children: loading2 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "px-3 py-10 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col items-center gap-3 animate-in fade-in-0 zoom-in-95 duration-300", children: [
|
|
@@ -15948,19 +15949,19 @@ var MultiCombobox = ({
|
|
|
15948
15949
|
},
|
|
15949
15950
|
"data-index": virtualItem?.index,
|
|
15950
15951
|
style: itemStyle,
|
|
15952
|
+
className: cn(virtualItem && "list-none"),
|
|
15951
15953
|
onClick: (e) => {
|
|
15952
15954
|
e.preventDefault();
|
|
15953
15955
|
e.stopPropagation();
|
|
15954
15956
|
if (!isDisabled) toggleSelect(item.value);
|
|
15955
15957
|
inputRef.current?.focus();
|
|
15956
15958
|
},
|
|
15957
|
-
className: cn("dropdown-item", isDisabled && "opacity-50 cursor-not-allowed pointer-events-none"),
|
|
15958
|
-
children: renderOption(item, isSelected)
|
|
15959
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: cn("dropdown-item", isDisabled && "opacity-50 cursor-not-allowed pointer-events-none"), children: renderOption(item, isSelected) })
|
|
15959
15960
|
},
|
|
15960
15961
|
item.value
|
|
15961
15962
|
);
|
|
15962
15963
|
}
|
|
15963
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.
|
|
15964
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
15964
15965
|
"li",
|
|
15965
15966
|
{
|
|
15966
15967
|
ref: (node) => {
|
|
@@ -15969,37 +15970,43 @@ var MultiCombobox = ({
|
|
|
15969
15970
|
},
|
|
15970
15971
|
"data-index": virtualItem?.index,
|
|
15971
15972
|
style: itemStyle,
|
|
15973
|
+
className: cn(virtualItem && "list-none"),
|
|
15972
15974
|
onClick: (e) => {
|
|
15973
15975
|
e.preventDefault();
|
|
15974
15976
|
e.stopPropagation();
|
|
15975
15977
|
if (!isDisabled) toggleSelect(item.value);
|
|
15976
15978
|
inputRef.current?.focus();
|
|
15977
15979
|
},
|
|
15978
|
-
|
|
15979
|
-
"
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
"
|
|
15992
|
-
|
|
15980
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
15981
|
+
"div",
|
|
15982
|
+
{
|
|
15983
|
+
className: cn(
|
|
15984
|
+
"dropdown-item flex cursor-pointer items-center gap-3 rounded-full transition-all duration-200",
|
|
15985
|
+
sizeStyles8[size].item,
|
|
15986
|
+
"hover:bg-accent/70 hover:shadow-sm",
|
|
15987
|
+
index === activeIndex && "bg-accent/60",
|
|
15988
|
+
isSelected && "bg-primary/10 text-primary font-medium",
|
|
15989
|
+
isDisabled && "opacity-40 cursor-not-allowed pointer-events-none"
|
|
15990
|
+
),
|
|
15991
|
+
children: [
|
|
15992
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
15993
|
+
"span",
|
|
15994
|
+
{
|
|
15995
|
+
className: cn(
|
|
15996
|
+
"shrink-0 w-5 h-5 flex items-center justify-center rounded-md border-2 transition-all duration-200",
|
|
15997
|
+
isSelected ? "bg-primary border-primary text-primary-foreground" : "border-muted-foreground/30 bg-transparent"
|
|
15998
|
+
),
|
|
15999
|
+
children: isSelected && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react24.Check, { className: "w-3 h-3" })
|
|
16000
|
+
}
|
|
15993
16001
|
),
|
|
15994
|
-
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
]
|
|
16002
|
+
optionIcon && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "shrink-0 w-5 h-5 flex items-center justify-center text-muted-foreground", children: optionIcon }),
|
|
16003
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
16004
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: cn("truncate", isSelected && "font-medium text-primary"), children: item.label }),
|
|
16005
|
+
optionDesc && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "text-xs text-muted-foreground truncate mt-0.5", children: optionDesc })
|
|
16006
|
+
] })
|
|
16007
|
+
]
|
|
16008
|
+
}
|
|
16009
|
+
)
|
|
16003
16010
|
},
|
|
16004
16011
|
item.value
|
|
16005
16012
|
);
|
|
@@ -16065,6 +16072,7 @@ var MultiCombobox = ({
|
|
|
16065
16072
|
role: "listbox",
|
|
16066
16073
|
"aria-multiselectable": "true",
|
|
16067
16074
|
ref: optionsListRef,
|
|
16075
|
+
"data-os-ignore": virtualized ? "" : void 0,
|
|
16068
16076
|
style: { maxHeight },
|
|
16069
16077
|
className: cn(
|
|
16070
16078
|
"overflow-y-auto p-1.5",
|
|
@@ -17467,6 +17475,7 @@ function OverlayControls({
|
|
|
17467
17475
|
|
|
17468
17476
|
// src/components/CategoryTreeSelect.tsx
|
|
17469
17477
|
var import_react22 = require("react");
|
|
17478
|
+
var import_react_virtual3 = require("@tanstack/react-virtual");
|
|
17470
17479
|
var import_lucide_react26 = require("lucide-react");
|
|
17471
17480
|
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
17472
17481
|
var defaultLabels = {
|
|
@@ -17480,6 +17489,7 @@ var TREE_NODE_INDENT_REM = 1;
|
|
|
17480
17489
|
var TREE_BRANCH_OFFSET_CLASS = "ml-1.5 pl-1.5";
|
|
17481
17490
|
var TREE_NODE_GAP_CLASS = "gap-1.5";
|
|
17482
17491
|
var TREE_EXPANDER_PLACEHOLDER_CLASS = "w-5";
|
|
17492
|
+
var CATEGORY_TREE_DROPDOWN_MAX_HEIGHT = 320;
|
|
17483
17493
|
function getAncestorPathIds(categories, targetId) {
|
|
17484
17494
|
const byId = new Map(categories.map((category) => [category.id, category]));
|
|
17485
17495
|
const expanded = /* @__PURE__ */ new Set();
|
|
@@ -17558,6 +17568,24 @@ function pruneAncestorSelection(categories, childrenMap, selected, fromCategoryI
|
|
|
17558
17568
|
function toCategoryOrderSelection(categories, selected) {
|
|
17559
17569
|
return categories.map((category) => category.id).filter((categoryId) => selected.has(categoryId));
|
|
17560
17570
|
}
|
|
17571
|
+
function flattenVisibleCategories(roots, childrenMap, expandedNodes, expandAllVisibleBranches) {
|
|
17572
|
+
const rows = [];
|
|
17573
|
+
const stack = roots.map((category) => ({ category, level: 0, path: /* @__PURE__ */ new Set() })).reverse();
|
|
17574
|
+
while (stack.length > 0) {
|
|
17575
|
+
const { category, level, path } = stack.pop();
|
|
17576
|
+
if (path.has(category.id)) continue;
|
|
17577
|
+
rows.push({ category, level });
|
|
17578
|
+
const children = childrenMap.get(category.id) ?? [];
|
|
17579
|
+
const isExpanded = children.length > 0 && (expandAllVisibleBranches || expandedNodes.has(category.id));
|
|
17580
|
+
if (!isExpanded) continue;
|
|
17581
|
+
const nextPath = new Set(path);
|
|
17582
|
+
nextPath.add(category.id);
|
|
17583
|
+
for (let index = children.length - 1; index >= 0; index -= 1) {
|
|
17584
|
+
stack.push({ category: children[index], level: level + 1, path: nextPath });
|
|
17585
|
+
}
|
|
17586
|
+
}
|
|
17587
|
+
return rows;
|
|
17588
|
+
}
|
|
17561
17589
|
function CategoryTreeSelect(props) {
|
|
17562
17590
|
const tv = useSmartTranslations("ValidationInput");
|
|
17563
17591
|
const {
|
|
@@ -17586,6 +17614,15 @@ function CategoryTreeSelect(props) {
|
|
|
17586
17614
|
className,
|
|
17587
17615
|
useOverlayScrollbar = false,
|
|
17588
17616
|
leafOnlySelect = false,
|
|
17617
|
+
virtualized = false,
|
|
17618
|
+
estimatedItemHeight = 44,
|
|
17619
|
+
overscan = 8,
|
|
17620
|
+
maxInitialOptions,
|
|
17621
|
+
searchMode = "auto",
|
|
17622
|
+
onSearchChange,
|
|
17623
|
+
searchDebounceMs = 0,
|
|
17624
|
+
minSearchLength = 0,
|
|
17625
|
+
showSearchPromptWhenEmptyQuery = false,
|
|
17589
17626
|
singleSelect = false
|
|
17590
17627
|
} = props;
|
|
17591
17628
|
const [isOpen, setIsOpen] = (0, import_react22.useState)(false);
|
|
@@ -17593,10 +17630,13 @@ function CategoryTreeSelect(props) {
|
|
|
17593
17630
|
() => getInitialExpandedNodes(categories, { defaultExpanded, defaultExpandedIds, expandToId, viewOnly, inline })
|
|
17594
17631
|
);
|
|
17595
17632
|
const [query, setQuery] = (0, import_react22.useState)("");
|
|
17633
|
+
const [activeIndex, setActiveIndex] = (0, import_react22.useState)(null);
|
|
17596
17634
|
const [localRequiredError, setLocalRequiredError] = (0, import_react22.useState)();
|
|
17597
17635
|
const searchInputRef = (0, import_react22.useRef)(null);
|
|
17598
17636
|
const dropdownViewportRef = (0, import_react22.useRef)(null);
|
|
17599
|
-
useOverlayScrollbarTarget(dropdownViewportRef, {
|
|
17637
|
+
useOverlayScrollbarTarget(dropdownViewportRef, {
|
|
17638
|
+
enabled: isOpen && useOverlayScrollbar && !virtualized && !inline && !viewOnly
|
|
17639
|
+
});
|
|
17600
17640
|
const autoId = (0, import_react22.useId)();
|
|
17601
17641
|
const resolvedId = id ? String(id) : `category-tree-select-${autoId}`;
|
|
17602
17642
|
const labelId = label ? `${resolvedId}-label` : void 0;
|
|
@@ -17616,7 +17656,7 @@ function CategoryTreeSelect(props) {
|
|
|
17616
17656
|
const parentCategories2 = [];
|
|
17617
17657
|
for (const cat of categories) byId2.set(cat.id, cat);
|
|
17618
17658
|
for (const cat of categories) {
|
|
17619
|
-
if (cat.parent_id == null) {
|
|
17659
|
+
if (cat.parent_id == null || !byId2.has(cat.parent_id)) {
|
|
17620
17660
|
parentCategories2.push(cat);
|
|
17621
17661
|
continue;
|
|
17622
17662
|
}
|
|
@@ -17625,12 +17665,19 @@ function CategoryTreeSelect(props) {
|
|
|
17625
17665
|
}
|
|
17626
17666
|
return { parentCategories: parentCategories2, childrenMap: childrenMap2, byId: byId2 };
|
|
17627
17667
|
}, [categories]);
|
|
17628
|
-
const isSearchEnabled = (0, import_react22.useMemo)(
|
|
17629
|
-
|
|
17668
|
+
const isSearchEnabled = (0, import_react22.useMemo)(
|
|
17669
|
+
() => enableSearch ?? (categories.length > 10 || searchMode === "manual" || minSearchLength > 0 || !!onSearchChange),
|
|
17670
|
+
[categories.length, enableSearch, minSearchLength, onSearchChange, searchMode]
|
|
17671
|
+
);
|
|
17672
|
+
const trimmedQuery = (0, import_react22.useMemo)(() => query.trim(), [query]);
|
|
17673
|
+
const normalizedQuery = (0, import_react22.useMemo)(() => trimmedQuery.toLowerCase(), [trimmedQuery]);
|
|
17674
|
+
const queryMeetsMinimum = trimmedQuery.length >= minSearchLength;
|
|
17675
|
+
const shouldPromptForSearch = minSearchLength > 0 && !queryMeetsMinimum && (searchMode === "manual" || showSearchPromptWhenEmptyQuery);
|
|
17630
17676
|
const isSearchMode = isSearchEnabled && normalizedQuery.length > 0;
|
|
17677
|
+
const shouldAutoExpandSearchResults = searchMode === "auto" && isSearchMode;
|
|
17631
17678
|
const effectiveExpandedNodes = (0, import_react22.useMemo)(() => getExpandedNodesState(expandedIds, expandedNodes), [expandedIds, expandedNodes]);
|
|
17632
17679
|
const visibleIds = (0, import_react22.useMemo)(() => {
|
|
17633
|
-
if (!isSearchMode) return null;
|
|
17680
|
+
if (shouldPromptForSearch || !isSearchMode || searchMode === "manual") return null;
|
|
17634
17681
|
const matches = categories.filter((c) => c.name.toLowerCase().includes(normalizedQuery));
|
|
17635
17682
|
if (matches.length === 0) return /* @__PURE__ */ new Set();
|
|
17636
17683
|
const visible = /* @__PURE__ */ new Set();
|
|
@@ -17667,7 +17714,14 @@ function CategoryTreeSelect(props) {
|
|
|
17667
17714
|
addDescendants(m.id);
|
|
17668
17715
|
}
|
|
17669
17716
|
return visible;
|
|
17670
|
-
}, [byId, categories, childrenMap, isSearchMode, normalizedQuery]);
|
|
17717
|
+
}, [byId, categories, childrenMap, isSearchMode, normalizedQuery, searchMode, shouldPromptForSearch]);
|
|
17718
|
+
(0, import_react22.useEffect)(() => {
|
|
17719
|
+
if (!onSearchChange) return;
|
|
17720
|
+
const timeoutId = window.setTimeout(() => {
|
|
17721
|
+
onSearchChange(trimmedQuery);
|
|
17722
|
+
}, Math.max(0, searchDebounceMs));
|
|
17723
|
+
return () => window.clearTimeout(timeoutId);
|
|
17724
|
+
}, [onSearchChange, searchDebounceMs, trimmedQuery]);
|
|
17671
17725
|
(0, import_react22.useEffect)(() => {
|
|
17672
17726
|
if (!isOpen) return;
|
|
17673
17727
|
if (!isSearchEnabled) return;
|
|
@@ -17680,7 +17734,7 @@ function CategoryTreeSelect(props) {
|
|
|
17680
17734
|
}
|
|
17681
17735
|
}, [disabled, required, valueArray.length]);
|
|
17682
17736
|
const toggleExpand = (id2) => {
|
|
17683
|
-
if (
|
|
17737
|
+
if (shouldAutoExpandSearchResults) return;
|
|
17684
17738
|
const newExpanded = new Set(effectiveExpandedNodes);
|
|
17685
17739
|
if (newExpanded.has(id2)) {
|
|
17686
17740
|
newExpanded.delete(id2);
|
|
@@ -17731,27 +17785,137 @@ function CategoryTreeSelect(props) {
|
|
|
17731
17785
|
onChange(toCategoryOrderSelection(categories, newSelected));
|
|
17732
17786
|
}
|
|
17733
17787
|
};
|
|
17734
|
-
const
|
|
17788
|
+
const effectiveParentCategories = (0, import_react22.useMemo)(() => {
|
|
17789
|
+
if (shouldPromptForSearch) return [];
|
|
17790
|
+
if (!isSearchMode || searchMode === "manual") return parentCategories;
|
|
17791
|
+
return parentCategories.filter((c) => visibleIds?.has(c.id));
|
|
17792
|
+
}, [isSearchMode, parentCategories, searchMode, shouldPromptForSearch, visibleIds]);
|
|
17793
|
+
const effectiveChildrenMap = (0, import_react22.useMemo)(() => {
|
|
17794
|
+
if (shouldPromptForSearch || !isSearchMode || !visibleIds || searchMode === "manual") return childrenMap;
|
|
17795
|
+
const nextChildrenMap = /* @__PURE__ */ new Map();
|
|
17796
|
+
for (const [parentId, children] of childrenMap.entries()) {
|
|
17797
|
+
nextChildrenMap.set(
|
|
17798
|
+
parentId,
|
|
17799
|
+
children.filter((child) => visibleIds.has(child.id))
|
|
17800
|
+
);
|
|
17801
|
+
}
|
|
17802
|
+
return nextChildrenMap;
|
|
17803
|
+
}, [childrenMap, isSearchMode, searchMode, shouldPromptForSearch, visibleIds]);
|
|
17804
|
+
const flattenedRows = (0, import_react22.useMemo)(() => {
|
|
17805
|
+
if (shouldPromptForSearch) return [];
|
|
17806
|
+
const rows = flattenVisibleCategories(effectiveParentCategories, effectiveChildrenMap, effectiveExpandedNodes, shouldAutoExpandSearchResults);
|
|
17807
|
+
if (trimmedQuery || maxInitialOptions === void 0 || maxInitialOptions < 1) {
|
|
17808
|
+
return rows;
|
|
17809
|
+
}
|
|
17810
|
+
const limitedRows = rows.slice(0, maxInitialOptions);
|
|
17811
|
+
const includedIds = new Set(limitedRows.map((row) => row.category.id));
|
|
17812
|
+
const pinnedIds = /* @__PURE__ */ new Set();
|
|
17813
|
+
for (const selectedId of selectedIds) {
|
|
17814
|
+
for (const ancestorId of getAncestorPathIds(categories, selectedId)) {
|
|
17815
|
+
pinnedIds.add(ancestorId);
|
|
17816
|
+
}
|
|
17817
|
+
}
|
|
17818
|
+
if (typeof expandToId === "number") {
|
|
17819
|
+
for (const ancestorId of getAncestorPathIds(categories, expandToId)) {
|
|
17820
|
+
pinnedIds.add(ancestorId);
|
|
17821
|
+
}
|
|
17822
|
+
}
|
|
17823
|
+
for (const row of rows) {
|
|
17824
|
+
if (!pinnedIds.has(row.category.id) || includedIds.has(row.category.id)) continue;
|
|
17825
|
+
limitedRows.push(row);
|
|
17826
|
+
includedIds.add(row.category.id);
|
|
17827
|
+
}
|
|
17828
|
+
return limitedRows;
|
|
17829
|
+
}, [
|
|
17830
|
+
categories,
|
|
17831
|
+
effectiveChildrenMap,
|
|
17832
|
+
effectiveExpandedNodes,
|
|
17833
|
+
effectiveParentCategories,
|
|
17834
|
+
expandToId,
|
|
17835
|
+
maxInitialOptions,
|
|
17836
|
+
selectedIds,
|
|
17837
|
+
shouldAutoExpandSearchResults,
|
|
17838
|
+
shouldPromptForSearch,
|
|
17839
|
+
trimmedQuery
|
|
17840
|
+
]);
|
|
17841
|
+
const canVirtualize = virtualized && !inline && !viewOnly;
|
|
17842
|
+
const treeVirtualizer = (0, import_react_virtual3.useVirtualizer)({
|
|
17843
|
+
count: canVirtualize ? flattenedRows.length : 0,
|
|
17844
|
+
getScrollElement: () => dropdownViewportRef.current,
|
|
17845
|
+
estimateSize: () => estimatedItemHeight,
|
|
17846
|
+
initialRect: { width: 0, height: CATEGORY_TREE_DROPDOWN_MAX_HEIGHT },
|
|
17847
|
+
overscan,
|
|
17848
|
+
enabled: canVirtualize
|
|
17849
|
+
});
|
|
17850
|
+
const virtualRows = canVirtualize ? treeVirtualizer.getVirtualItems() : [];
|
|
17851
|
+
const scrollVirtualTreeToStart = () => {
|
|
17852
|
+
if (!canVirtualize || flattenedRows.length === 0) return;
|
|
17853
|
+
treeVirtualizer.scrollToIndex(0, { align: "start" });
|
|
17854
|
+
};
|
|
17855
|
+
const moveActiveVirtualRow = (direction) => {
|
|
17856
|
+
if (!canVirtualize || flattenedRows.length === 0) return;
|
|
17857
|
+
const nextIndex = activeIndex === null ? direction === 1 ? 0 : flattenedRows.length - 1 : (activeIndex + direction + flattenedRows.length) % flattenedRows.length;
|
|
17858
|
+
setActiveIndex(nextIndex);
|
|
17859
|
+
treeVirtualizer.scrollToIndex(nextIndex, { align: "auto" });
|
|
17860
|
+
};
|
|
17861
|
+
const handleVirtualTreeKeyDown = (event) => {
|
|
17862
|
+
if (!canVirtualize) return;
|
|
17863
|
+
if (event.key === "ArrowDown") {
|
|
17864
|
+
event.preventDefault();
|
|
17865
|
+
moveActiveVirtualRow(1);
|
|
17866
|
+
return;
|
|
17867
|
+
}
|
|
17868
|
+
if (event.key === "ArrowUp") {
|
|
17869
|
+
event.preventDefault();
|
|
17870
|
+
moveActiveVirtualRow(-1);
|
|
17871
|
+
return;
|
|
17872
|
+
}
|
|
17873
|
+
if (event.key === "Enter" && activeIndex !== null) {
|
|
17874
|
+
const row = flattenedRows[activeIndex];
|
|
17875
|
+
if (!row) return;
|
|
17876
|
+
event.preventDefault();
|
|
17877
|
+
handleSelect(row.category.id, row.category);
|
|
17878
|
+
}
|
|
17879
|
+
};
|
|
17880
|
+
(0, import_react22.useEffect)(() => {
|
|
17881
|
+
setActiveIndex(null);
|
|
17882
|
+
}, [flattenedRows]);
|
|
17883
|
+
const renderCategoryRow = (category, level = 0, virtualItem) => {
|
|
17735
17884
|
const children = effectiveChildrenMap.get(category.id) || [];
|
|
17736
17885
|
const hasChildren = children.length > 0;
|
|
17737
|
-
const isExpanded = hasChildren && (
|
|
17886
|
+
const isExpanded = hasChildren && (shouldAutoExpandSearchResults || effectiveExpandedNodes.has(category.id));
|
|
17738
17887
|
const isSelected = selectedIds.has(category.id);
|
|
17739
17888
|
const isSelectable = !viewOnly && (!leafOnlySelect || !hasChildren);
|
|
17889
|
+
const isActive = virtualItem?.index === activeIndex;
|
|
17890
|
+
const rowStyle = virtualItem ? {
|
|
17891
|
+
position: "absolute",
|
|
17892
|
+
top: 0,
|
|
17893
|
+
left: 0,
|
|
17894
|
+
width: "100%",
|
|
17895
|
+
transform: `translateY(${virtualItem.start}px)`
|
|
17896
|
+
} : void 0;
|
|
17740
17897
|
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
17741
17898
|
"div",
|
|
17742
17899
|
{
|
|
17743
|
-
|
|
17744
|
-
|
|
17900
|
+
ref: virtualItem ? treeVirtualizer.measureElement : void 0,
|
|
17901
|
+
"data-index": virtualItem?.index,
|
|
17902
|
+
className: cn("min-w-0 [content-visibility:auto] [contain-intrinsic-size:44px]", !virtualItem && "animate-in fade-in-50 duration-200"),
|
|
17903
|
+
style: { animationDelay: virtualItem ? void 0 : `${level * 30}ms`, ...rowStyle },
|
|
17745
17904
|
children: [
|
|
17746
17905
|
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
17747
17906
|
"div",
|
|
17748
17907
|
{
|
|
17908
|
+
role: "treeitem",
|
|
17909
|
+
"aria-level": level + 1,
|
|
17910
|
+
"aria-expanded": hasChildren ? isExpanded : void 0,
|
|
17911
|
+
"aria-selected": viewOnly ? void 0 : isSelected,
|
|
17749
17912
|
onClick: () => !viewOnly && handleSelect(category.id, category),
|
|
17750
17913
|
className: cn(
|
|
17751
17914
|
"relative flex min-w-0 items-center px-3 py-2.5 min-h-11 transition-all duration-200 rounded-3xl",
|
|
17752
17915
|
TREE_NODE_GAP_CLASS,
|
|
17753
17916
|
!viewOnly && (isSelectable ? "cursor-pointer" : "cursor-default"),
|
|
17754
17917
|
isSelectable && !isSelected && "hover:bg-accent/50",
|
|
17918
|
+
canVirtualize && isActive && "bg-accent/50",
|
|
17755
17919
|
// Selected state - đồng bộ cho tất cả
|
|
17756
17920
|
!viewOnly && isSelected && "bg-accent/40"
|
|
17757
17921
|
),
|
|
@@ -17761,6 +17925,7 @@ function CategoryTreeSelect(props) {
|
|
|
17761
17925
|
"button",
|
|
17762
17926
|
{
|
|
17763
17927
|
type: "button",
|
|
17928
|
+
"aria-label": isExpanded ? `Collapse ${category.name}` : `Expand ${category.name}`,
|
|
17764
17929
|
onClick: (e) => {
|
|
17765
17930
|
e.stopPropagation();
|
|
17766
17931
|
toggleExpand(category.id);
|
|
@@ -17770,9 +17935,9 @@ function CategoryTreeSelect(props) {
|
|
|
17770
17935
|
"hover:scale-110 active:scale-95",
|
|
17771
17936
|
"focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50",
|
|
17772
17937
|
isExpanded && "text-primary",
|
|
17773
|
-
|
|
17938
|
+
shouldAutoExpandSearchResults && "opacity-60 cursor-not-allowed hover:scale-100 active:scale-100"
|
|
17774
17939
|
),
|
|
17775
|
-
disabled:
|
|
17940
|
+
disabled: shouldAutoExpandSearchResults,
|
|
17776
17941
|
children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: cn("transition-transform duration-200", isExpanded && "rotate-90"), children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react26.ChevronRight, { className: "w-4 h-4" }) })
|
|
17777
17942
|
}
|
|
17778
17943
|
) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: TREE_EXPANDER_PLACEHOLDER_CLASS }),
|
|
@@ -17803,15 +17968,16 @@ function CategoryTreeSelect(props) {
|
|
|
17803
17968
|
]
|
|
17804
17969
|
}
|
|
17805
17970
|
),
|
|
17806
|
-
hasChildren && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
17971
|
+
!virtualItem && hasChildren && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
17807
17972
|
"div",
|
|
17808
17973
|
{
|
|
17974
|
+
role: "group",
|
|
17809
17975
|
className: cn(
|
|
17810
17976
|
TREE_BRANCH_OFFSET_CLASS,
|
|
17811
17977
|
"border-l-2 border-dashed border-border/50",
|
|
17812
17978
|
"animate-in slide-in-from-top-2 fade-in-50 duration-200"
|
|
17813
17979
|
),
|
|
17814
|
-
children: children.map((child) =>
|
|
17980
|
+
children: children.map((child) => renderCategoryRow(child, level + 1))
|
|
17815
17981
|
}
|
|
17816
17982
|
)
|
|
17817
17983
|
]
|
|
@@ -17828,7 +17994,11 @@ function CategoryTreeSelect(props) {
|
|
|
17828
17994
|
{
|
|
17829
17995
|
ref: searchInputRef,
|
|
17830
17996
|
value: query,
|
|
17831
|
-
onChange: (e) =>
|
|
17997
|
+
onChange: (e) => {
|
|
17998
|
+
setQuery(e.target.value);
|
|
17999
|
+
scrollVirtualTreeToStart();
|
|
18000
|
+
},
|
|
18001
|
+
onKeyDown: handleVirtualTreeKeyDown,
|
|
17832
18002
|
placeholder: mergedLabels.searchPlaceholder,
|
|
17833
18003
|
className: cn(
|
|
17834
18004
|
"peer w-full rounded-full bg-background/90 py-2.5 pl-10 pr-10 text-sm shadow-sm",
|
|
@@ -17845,6 +18015,7 @@ function CategoryTreeSelect(props) {
|
|
|
17845
18015
|
type: "button",
|
|
17846
18016
|
onClick: () => {
|
|
17847
18017
|
setQuery("");
|
|
18018
|
+
scrollVirtualTreeToStart();
|
|
17848
18019
|
searchInputRef.current?.focus();
|
|
17849
18020
|
},
|
|
17850
18021
|
className: cn(
|
|
@@ -17859,24 +18030,40 @@ function CategoryTreeSelect(props) {
|
|
|
17859
18030
|
)
|
|
17860
18031
|
] }) });
|
|
17861
18032
|
};
|
|
17862
|
-
const
|
|
17863
|
-
|
|
17864
|
-
|
|
17865
|
-
|
|
17866
|
-
|
|
17867
|
-
|
|
17868
|
-
|
|
17869
|
-
|
|
17870
|
-
effectiveChildrenMap.set(
|
|
17871
|
-
parentId,
|
|
17872
|
-
children.filter((child) => visibleIds.has(child.id))
|
|
17873
|
-
);
|
|
17874
|
-
}
|
|
17875
|
-
}
|
|
17876
|
-
const renderTreeContent = () => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "space-y-0.5 overflow-x-hidden", children: effectiveParentCategories.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
18033
|
+
const renderTreeContent = () => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "space-y-0.5 overflow-x-hidden", children: shouldPromptForSearch ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
18034
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "w-12 h-12 rounded-2xl bg-muted/50 flex items-center justify-center mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react26.Search, { className: "w-6 h-6 text-muted-foreground/50" }) }),
|
|
18035
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "text-sm text-muted-foreground", children: [
|
|
18036
|
+
"Type at least ",
|
|
18037
|
+
minSearchLength,
|
|
18038
|
+
" characters to search"
|
|
18039
|
+
] })
|
|
18040
|
+
] }) : effectiveParentCategories.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
17877
18041
|
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "w-12 h-12 rounded-2xl bg-muted/50 flex items-center justify-center mb-3", children: isSearchMode ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react26.SearchX, { className: "w-6 h-6 text-muted-foreground/50" }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react26.Layers, { className: "w-6 h-6 text-muted-foreground/50" }) }),
|
|
17878
18042
|
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-sm text-muted-foreground", children: isSearchMode ? mergedLabels.noResultsText : mergedLabels.emptyText })
|
|
17879
|
-
] }) : effectiveParentCategories.map((cat) =>
|
|
18043
|
+
] }) : effectiveParentCategories.map((cat) => renderCategoryRow(cat)) });
|
|
18044
|
+
const renderVirtualTreeContent = () => {
|
|
18045
|
+
if (shouldPromptForSearch) {
|
|
18046
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
18047
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "w-12 h-12 rounded-2xl bg-muted/50 flex items-center justify-center mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react26.Search, { className: "w-6 h-6 text-muted-foreground/50" }) }),
|
|
18048
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "text-sm text-muted-foreground", children: [
|
|
18049
|
+
"Type at least ",
|
|
18050
|
+
minSearchLength,
|
|
18051
|
+
" characters to search"
|
|
18052
|
+
] })
|
|
18053
|
+
] });
|
|
18054
|
+
}
|
|
18055
|
+
if (flattenedRows.length === 0) {
|
|
18056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
18057
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "w-12 h-12 rounded-2xl bg-muted/50 flex items-center justify-center mb-3", children: isSearchMode ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react26.SearchX, { className: "w-6 h-6 text-muted-foreground/50" }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react26.Layers, { className: "w-6 h-6 text-muted-foreground/50" }) }),
|
|
18058
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-sm text-muted-foreground", children: isSearchMode ? mergedLabels.noResultsText : mergedLabels.emptyText })
|
|
18059
|
+
] });
|
|
18060
|
+
}
|
|
18061
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "relative overflow-x-hidden", style: { height: `${treeVirtualizer.getTotalSize()}px` }, children: virtualRows.map((virtualRow) => {
|
|
18062
|
+
const row = flattenedRows[virtualRow.index];
|
|
18063
|
+
if (!row) return null;
|
|
18064
|
+
return renderCategoryRow(row.category, row.level, virtualRow);
|
|
18065
|
+
}) });
|
|
18066
|
+
};
|
|
17880
18067
|
const renderLabel = () => label ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
17881
18068
|
Label,
|
|
17882
18069
|
{
|
|
@@ -17919,8 +18106,10 @@ function CategoryTreeSelect(props) {
|
|
|
17919
18106
|
"div",
|
|
17920
18107
|
{
|
|
17921
18108
|
id: resolvedId,
|
|
18109
|
+
role: "tree",
|
|
17922
18110
|
"aria-labelledby": labelId,
|
|
17923
18111
|
"aria-describedby": describedBy,
|
|
18112
|
+
"aria-multiselectable": singleSelect ? void 0 : true,
|
|
17924
18113
|
className: cn("rounded-2xl border border-border/60 bg-card/50 backdrop-blur-sm p-3 shadow-sm", disabled && "opacity-50"),
|
|
17925
18114
|
children: [
|
|
17926
18115
|
renderSearch(),
|
|
@@ -17955,8 +18144,10 @@ function CategoryTreeSelect(props) {
|
|
|
17955
18144
|
"div",
|
|
17956
18145
|
{
|
|
17957
18146
|
id: resolvedId,
|
|
18147
|
+
role: "tree",
|
|
17958
18148
|
"aria-labelledby": labelId,
|
|
17959
18149
|
"aria-describedby": describedBy,
|
|
18150
|
+
"aria-multiselectable": singleSelect ? void 0 : true,
|
|
17960
18151
|
className: cn("rounded-2xl border border-border/60 bg-card/50 backdrop-blur-sm p-3 shadow-sm", disabled && "opacity-50 pointer-events-none"),
|
|
17961
18152
|
children: [
|
|
17962
18153
|
renderSearch(),
|
|
@@ -18021,6 +18212,7 @@ function CategoryTreeSelect(props) {
|
|
|
18021
18212
|
setIsOpen(nextOpen);
|
|
18022
18213
|
if (!nextOpen) {
|
|
18023
18214
|
setQuery("");
|
|
18215
|
+
scrollVirtualTreeToStart();
|
|
18024
18216
|
}
|
|
18025
18217
|
};
|
|
18026
18218
|
let displayText;
|
|
@@ -18036,15 +18228,20 @@ function CategoryTreeSelect(props) {
|
|
|
18036
18228
|
displayText = mergedLabels.selectedText(selectedCount);
|
|
18037
18229
|
}
|
|
18038
18230
|
}
|
|
18039
|
-
const dropdownBody = /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex
|
|
18231
|
+
const dropdownBody = /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex flex-col overflow-hidden", style: { maxHeight: CATEGORY_TREE_DROPDOWN_MAX_HEIGHT }, children: [
|
|
18040
18232
|
renderSearch({ sticky: false, className: "border-b border-border/30 p-2 pb-2" }),
|
|
18041
18233
|
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
18042
18234
|
"div",
|
|
18043
18235
|
{
|
|
18044
18236
|
ref: dropdownViewportRef,
|
|
18045
18237
|
id: `${resolvedId}-tree`,
|
|
18238
|
+
role: "tree",
|
|
18239
|
+
"aria-multiselectable": singleSelect ? void 0 : true,
|
|
18240
|
+
"data-os-ignore": virtualized ? "" : void 0,
|
|
18241
|
+
tabIndex: canVirtualize ? 0 : void 0,
|
|
18242
|
+
onKeyDown: handleVirtualTreeKeyDown,
|
|
18046
18243
|
className: cn("min-h-0 flex-1 overflow-auto overflow-x-hidden p-2 pt-2"),
|
|
18047
|
-
children: renderTreeContent()
|
|
18244
|
+
children: canVirtualize ? renderVirtualTreeContent() : renderTreeContent()
|
|
18048
18245
|
}
|
|
18049
18246
|
)
|
|
18050
18247
|
] });
|
|
@@ -18099,6 +18296,10 @@ function CategoryTreeSelect(props) {
|
|
|
18099
18296
|
if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown") {
|
|
18100
18297
|
event.preventDefault();
|
|
18101
18298
|
handleOpenChange(!isOpen);
|
|
18299
|
+
if (event.key === "ArrowDown" && canVirtualize && flattenedRows.length > 0) {
|
|
18300
|
+
setActiveIndex(0);
|
|
18301
|
+
treeVirtualizer.scrollToIndex(0, { align: "start" });
|
|
18302
|
+
}
|
|
18102
18303
|
}
|
|
18103
18304
|
},
|
|
18104
18305
|
className: cn(
|
|
@@ -21718,6 +21919,7 @@ var TableCaption = import_react28.default.forwardRef(({ className, ...props }, r
|
|
|
21718
21919
|
TableCaption.displayName = "TableCaption";
|
|
21719
21920
|
|
|
21720
21921
|
// src/components/DataTable/DataTable.tsx
|
|
21922
|
+
var import_react_virtual4 = require("@tanstack/react-virtual");
|
|
21721
21923
|
var import_react38 = __toESM(require("react"), 1);
|
|
21722
21924
|
|
|
21723
21925
|
// src/components/DataTable/components/DataTableBody.tsx
|
|
@@ -21790,8 +21992,17 @@ function DataTableBodyRows({
|
|
|
21790
21992
|
getStickyColumnStyle,
|
|
21791
21993
|
getStickyCellClass,
|
|
21792
21994
|
t,
|
|
21793
|
-
labels
|
|
21995
|
+
labels,
|
|
21996
|
+
virtualRows,
|
|
21997
|
+
virtualPaddingTop = 0,
|
|
21998
|
+
virtualPaddingBottom = 0,
|
|
21999
|
+
measureVirtualRow
|
|
21794
22000
|
}) {
|
|
22001
|
+
const rowsToRender = virtualRows ? virtualRows.map((virtualRow) => ({
|
|
22002
|
+
row: displayedData[virtualRow.index],
|
|
22003
|
+
idx: virtualRow.index,
|
|
22004
|
+
virtualRow
|
|
22005
|
+
})).filter((item) => Boolean(item.row)) : displayedData.map((row, idx) => ({ row, idx, virtualRow: void 0 }));
|
|
21795
22006
|
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableBody, { children: loading2 ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableCell, { colSpan: leafColumns.length, className: "text-center py-8", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "flex items-center justify-center gap-2 text-muted-foreground", children: [
|
|
21796
22007
|
/* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("svg", { className: "animate-spin h-4 w-4", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
21797
22008
|
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
@@ -21808,42 +22019,48 @@ function DataTableBodyRows({
|
|
|
21808
22019
|
t("loading"),
|
|
21809
22020
|
"\u2026"
|
|
21810
22021
|
] })
|
|
21811
|
-
] }) }) }) : displayedData.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableCell, { colSpan: leafColumns.length, className: "text-center py-6 text-muted-foreground", children: labels?.noData || t("noData") }) }) :
|
|
21812
|
-
|
|
21813
|
-
|
|
21814
|
-
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
|
|
21818
|
-
|
|
21819
|
-
|
|
22022
|
+
] }) }) }) : displayedData.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableCell, { colSpan: leafColumns.length, className: "text-center py-6 text-muted-foreground", children: labels?.noData || t("noData") }) }) : /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_jsx_runtime63.Fragment, { children: [
|
|
22023
|
+
virtualPaddingTop > 0 && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableRow, { "aria-hidden": "true", className: "border-0 hover:bg-transparent hover:shadow-none", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableCell, { colSpan: leafColumns.length, className: "p-0", style: { height: virtualPaddingTop } }) }),
|
|
22024
|
+
rowsToRender.map(({ row, idx, virtualRow }) => {
|
|
22025
|
+
const isStripedRow = striped && idx % 2 === 0;
|
|
22026
|
+
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
22027
|
+
TableRow,
|
|
22028
|
+
{
|
|
22029
|
+
ref: virtualRow ? measureVirtualRow : void 0,
|
|
22030
|
+
"data-index": virtualRow?.index,
|
|
22031
|
+
className: cn(densityRowClass, isStripedRow ? "bg-surface-1" : "bg-surface-0"),
|
|
22032
|
+
style: {
|
|
22033
|
+
contentVisibility: "auto",
|
|
22034
|
+
containIntrinsicSize: density === "compact" ? "0 36px" : density === "comfortable" ? "0 56px" : "0 48px"
|
|
22035
|
+
},
|
|
22036
|
+
children: leafColumns.map((col, colIdx) => {
|
|
22037
|
+
const value = col.dataIndex ? row[col.dataIndex] : void 0;
|
|
22038
|
+
const prevCol = colIdx > 0 ? leafColumns[colIdx - 1] : null;
|
|
22039
|
+
const isAfterFixedLeft = prevCol?.fixed === "left";
|
|
22040
|
+
const showBorderLeft = columnDividers && colIdx > 0 && !isAfterFixedLeft && !col.fixed;
|
|
22041
|
+
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
22042
|
+
TableCell,
|
|
22043
|
+
{
|
|
22044
|
+
"data-underverse-column-key": col.key,
|
|
22045
|
+
style: getStickyColumnStyle(col),
|
|
22046
|
+
className: cn(
|
|
22047
|
+
cellPadding,
|
|
22048
|
+
col.align === "right" && "text-right",
|
|
22049
|
+
col.align === "center" && "text-center",
|
|
22050
|
+
showBorderLeft && "border-l border-border/60",
|
|
22051
|
+
getStickyCellClass(col, isStripedRow)
|
|
22052
|
+
),
|
|
22053
|
+
children: col.render ? col.render(value, row, idx) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(DataTableOverflowText, { text: String(value ?? ""), align: col.align })
|
|
22054
|
+
},
|
|
22055
|
+
col.key
|
|
22056
|
+
);
|
|
22057
|
+
})
|
|
21820
22058
|
},
|
|
21821
|
-
|
|
21822
|
-
|
|
21823
|
-
|
|
21824
|
-
|
|
21825
|
-
|
|
21826
|
-
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
21827
|
-
TableCell,
|
|
21828
|
-
{
|
|
21829
|
-
"data-underverse-column-key": col.key,
|
|
21830
|
-
style: getStickyColumnStyle(col),
|
|
21831
|
-
className: cn(
|
|
21832
|
-
cellPadding,
|
|
21833
|
-
col.align === "right" && "text-right",
|
|
21834
|
-
col.align === "center" && "text-center",
|
|
21835
|
-
showBorderLeft && "border-l border-border/60",
|
|
21836
|
-
getStickyCellClass(col, isStripedRow)
|
|
21837
|
-
),
|
|
21838
|
-
children: col.render ? col.render(value, row, idx) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(DataTableOverflowText, { text: String(value ?? ""), align: col.align })
|
|
21839
|
-
},
|
|
21840
|
-
col.key
|
|
21841
|
-
);
|
|
21842
|
-
})
|
|
21843
|
-
},
|
|
21844
|
-
getRowKey(row, idx)
|
|
21845
|
-
);
|
|
21846
|
-
}) });
|
|
22059
|
+
getRowKey(row, idx)
|
|
22060
|
+
);
|
|
22061
|
+
}),
|
|
22062
|
+
virtualPaddingBottom > 0 && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableRow, { "aria-hidden": "true", className: "border-0 hover:bg-transparent hover:shadow-none", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableCell, { colSpan: leafColumns.length, className: "p-0", style: { height: virtualPaddingBottom } }) })
|
|
22063
|
+
] }) });
|
|
21847
22064
|
}
|
|
21848
22065
|
|
|
21849
22066
|
// src/components/DataTable/components/DataTableHeader.tsx
|
|
@@ -22910,6 +23127,9 @@ function DataTable({
|
|
|
22910
23127
|
horizontalMode = "auto",
|
|
22911
23128
|
overflowHidden = true,
|
|
22912
23129
|
useOverlayScrollbar = false,
|
|
23130
|
+
virtualizedRows = false,
|
|
23131
|
+
estimatedRowHeight,
|
|
23132
|
+
overscan = 8,
|
|
22913
23133
|
enableHeaderAutoFit = true,
|
|
22914
23134
|
labels
|
|
22915
23135
|
}) {
|
|
@@ -22965,6 +23185,7 @@ function DataTable({
|
|
|
22965
23185
|
console.warn("[DataTable] `rowKey` should be provided when using sort/filter/pagination to keep row identity stable.");
|
|
22966
23186
|
}, [columns, isServerMode, pageSizeOptions, rowKey]);
|
|
22967
23187
|
const densityRowClass = density === "compact" ? "h-9" : density === "comfortable" ? "h-14" : "h-12";
|
|
23188
|
+
const defaultEstimatedRowHeight = density === "compact" ? 36 : density === "comfortable" ? 56 : 48;
|
|
22968
23189
|
const cellPadding = density === "compact" ? "py-1.5 px-3" : density === "comfortable" ? "py-3 px-4" : "py-2.5 px-4";
|
|
22969
23190
|
const headerTitleClass = size === "sm" ? "text-xs" : size === "lg" ? "text-[15px]" : "text-sm";
|
|
22970
23191
|
const headerMinHeightClass = size === "sm" ? "min-h-9" : size === "lg" ? "min-h-11" : "min-h-10";
|
|
@@ -22992,8 +23213,23 @@ function DataTable({
|
|
|
22992
23213
|
};
|
|
22993
23214
|
const viewportRef = import_react38.default.useRef(null);
|
|
22994
23215
|
const tableRef = import_react38.default.useRef(null);
|
|
23216
|
+
const canVirtualizeRows = virtualizedRows && !loading2 && displayedData.length > 0;
|
|
23217
|
+
const rowVirtualizer = (0, import_react_virtual4.useVirtualizer)({
|
|
23218
|
+
count: canVirtualizeRows ? displayedData.length : 0,
|
|
23219
|
+
getScrollElement: () => viewportRef.current,
|
|
23220
|
+
estimateSize: () => estimatedRowHeight ?? defaultEstimatedRowHeight,
|
|
23221
|
+
initialRect: {
|
|
23222
|
+
width: 0,
|
|
23223
|
+
height: typeof maxHeight === "number" ? maxHeight : 500
|
|
23224
|
+
},
|
|
23225
|
+
overscan,
|
|
23226
|
+
enabled: canVirtualizeRows
|
|
23227
|
+
});
|
|
23228
|
+
const virtualRows = canVirtualizeRows ? rowVirtualizer.getVirtualItems() : [];
|
|
23229
|
+
const virtualPaddingTop = canVirtualizeRows && virtualRows.length > 0 ? virtualRows[0]?.start ?? 0 : 0;
|
|
23230
|
+
const virtualPaddingBottom = canVirtualizeRows && virtualRows.length > 0 ? Math.max(0, rowVirtualizer.getTotalSize() - (virtualRows[virtualRows.length - 1]?.end ?? 0)) : 0;
|
|
22995
23231
|
useOverlayScrollbarTarget(viewportRef, {
|
|
22996
|
-
enabled: useOverlayScrollbar,
|
|
23232
|
+
enabled: useOverlayScrollbar && !canVirtualizeRows,
|
|
22997
23233
|
overflowX: overlayOverflowX
|
|
22998
23234
|
});
|
|
22999
23235
|
const autoFitColumn = import_react38.default.useCallback((columnKey) => {
|
|
@@ -23057,6 +23293,7 @@ function DataTable({
|
|
|
23057
23293
|
"div",
|
|
23058
23294
|
{
|
|
23059
23295
|
ref: viewportRef,
|
|
23296
|
+
"data-os-ignore": canVirtualizeRows ? "" : void 0,
|
|
23060
23297
|
className: cn("w-full", viewportOverflowXClass, stickyHeader && "overflow-y-auto"),
|
|
23061
23298
|
style: stickyHeader ? { maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight } : void 0,
|
|
23062
23299
|
children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
|
|
@@ -23108,7 +23345,11 @@ function DataTable({
|
|
|
23108
23345
|
getStickyColumnStyle,
|
|
23109
23346
|
getStickyCellClass,
|
|
23110
23347
|
t,
|
|
23111
|
-
labels
|
|
23348
|
+
labels,
|
|
23349
|
+
virtualRows: canVirtualizeRows ? virtualRows : void 0,
|
|
23350
|
+
virtualPaddingTop: canVirtualizeRows ? virtualPaddingTop : void 0,
|
|
23351
|
+
virtualPaddingBottom: canVirtualizeRows ? virtualPaddingBottom : void 0,
|
|
23352
|
+
measureVirtualRow: canVirtualizeRows ? rowVirtualizer.measureElement : void 0
|
|
23112
23353
|
}
|
|
23113
23354
|
)
|
|
23114
23355
|
]
|
|
@@ -27046,7 +27287,7 @@ function findDiffEnd(a, b, posA, posB) {
|
|
|
27046
27287
|
posB -= size;
|
|
27047
27288
|
}
|
|
27048
27289
|
}
|
|
27049
|
-
var
|
|
27290
|
+
var Fragment27 = class _Fragment {
|
|
27050
27291
|
/**
|
|
27051
27292
|
@internal
|
|
27052
27293
|
*/
|
|
@@ -27338,7 +27579,7 @@ var Fragment26 = class _Fragment {
|
|
|
27338
27579
|
throw new RangeError("Can not convert " + nodes + " to a Fragment" + (nodes.nodesBetween ? " (looks like multiple versions of prosemirror-model were loaded)" : ""));
|
|
27339
27580
|
}
|
|
27340
27581
|
};
|
|
27341
|
-
|
|
27582
|
+
Fragment27.empty = new Fragment27([], 0);
|
|
27342
27583
|
var found = { index: 0, offset: 0 };
|
|
27343
27584
|
function retIndex(index, offset) {
|
|
27344
27585
|
found.index = index;
|
|
@@ -27563,7 +27804,7 @@ var Slice = class _Slice {
|
|
|
27563
27804
|
let openStart = json.openStart || 0, openEnd = json.openEnd || 0;
|
|
27564
27805
|
if (typeof openStart != "number" || typeof openEnd != "number")
|
|
27565
27806
|
throw new RangeError("Invalid input for Slice.fromJSON");
|
|
27566
|
-
return new _Slice(
|
|
27807
|
+
return new _Slice(Fragment27.fromJSON(schema, json.content), openStart, openEnd);
|
|
27567
27808
|
}
|
|
27568
27809
|
/**
|
|
27569
27810
|
Create a slice from a fragment by taking the maximum possible
|
|
@@ -27578,7 +27819,7 @@ var Slice = class _Slice {
|
|
|
27578
27819
|
return new _Slice(fragment, openStart, openEnd);
|
|
27579
27820
|
}
|
|
27580
27821
|
};
|
|
27581
|
-
Slice.empty = new Slice(
|
|
27822
|
+
Slice.empty = new Slice(Fragment27.empty, 0, 0);
|
|
27582
27823
|
function removeRange(content, from, to) {
|
|
27583
27824
|
let { index, offset } = content.findIndex(from), child = content.maybeChild(index);
|
|
27584
27825
|
let { index: indexTo, offset: offsetTo } = content.findIndex(to);
|
|
@@ -27676,7 +27917,7 @@ function replaceThreeWay($from, $start, $end, $to, depth) {
|
|
|
27676
27917
|
addNode(close(openEnd, replaceTwoWay($end, $to, depth + 1)), content);
|
|
27677
27918
|
}
|
|
27678
27919
|
addRange($to, null, depth, content);
|
|
27679
|
-
return new
|
|
27920
|
+
return new Fragment27(content);
|
|
27680
27921
|
}
|
|
27681
27922
|
function replaceTwoWay($from, $to, depth) {
|
|
27682
27923
|
let content = [];
|
|
@@ -27686,13 +27927,13 @@ function replaceTwoWay($from, $to, depth) {
|
|
|
27686
27927
|
addNode(close(type, replaceTwoWay($from, $to, depth + 1)), content);
|
|
27687
27928
|
}
|
|
27688
27929
|
addRange($to, null, depth, content);
|
|
27689
|
-
return new
|
|
27930
|
+
return new Fragment27(content);
|
|
27690
27931
|
}
|
|
27691
27932
|
function prepareSliceForReplace(slice, $along) {
|
|
27692
27933
|
let extra = $along.depth - slice.openStart, parent = $along.node(extra);
|
|
27693
27934
|
let node = parent.copy(slice.content);
|
|
27694
27935
|
for (let i = extra - 1; i >= 0; i--)
|
|
27695
|
-
node = $along.node(i).copy(
|
|
27936
|
+
node = $along.node(i).copy(Fragment27.from(node));
|
|
27696
27937
|
return {
|
|
27697
27938
|
start: node.resolveNoCache(slice.openStart + extra),
|
|
27698
27939
|
end: node.resolveNoCache(node.content.size - slice.openEnd - extra)
|
|
@@ -28031,7 +28272,7 @@ var Node2 = class _Node {
|
|
|
28031
28272
|
this.type = type;
|
|
28032
28273
|
this.attrs = attrs;
|
|
28033
28274
|
this.marks = marks;
|
|
28034
|
-
this.content = content ||
|
|
28275
|
+
this.content = content || Fragment27.empty;
|
|
28035
28276
|
}
|
|
28036
28277
|
/**
|
|
28037
28278
|
The array of this node's child nodes.
|
|
@@ -28336,7 +28577,7 @@ var Node2 = class _Node {
|
|
|
28336
28577
|
can optionally pass `start` and `end` indices into the
|
|
28337
28578
|
replacement fragment.
|
|
28338
28579
|
*/
|
|
28339
|
-
canReplace(from, to, replacement =
|
|
28580
|
+
canReplace(from, to, replacement = Fragment27.empty, start = 0, end = replacement.childCount) {
|
|
28340
28581
|
let one = this.contentMatchAt(from).matchFragment(replacement, start, end);
|
|
28341
28582
|
let two = one && one.matchFragment(this.content, to);
|
|
28342
28583
|
if (!two || !two.validEnd)
|
|
@@ -28418,7 +28659,7 @@ var Node2 = class _Node {
|
|
|
28418
28659
|
throw new RangeError("Invalid text node in JSON");
|
|
28419
28660
|
return schema.text(json.text, marks);
|
|
28420
28661
|
}
|
|
28421
|
-
let content =
|
|
28662
|
+
let content = Fragment27.fromJSON(schema, json.content);
|
|
28422
28663
|
let node = schema.nodeType(json.type).create(json.attrs, content, marks);
|
|
28423
28664
|
node.type.checkAttrs(node.attrs);
|
|
28424
28665
|
return node;
|
|
@@ -28514,7 +28755,7 @@ var ContentMatch = class _ContentMatch {
|
|
|
28514
28755
|
function search(match, types) {
|
|
28515
28756
|
let finished = match.matchFragment(after, startIndex);
|
|
28516
28757
|
if (finished && (!toEnd || finished.validEnd))
|
|
28517
|
-
return
|
|
28758
|
+
return Fragment27.from(types.map((tp) => tp.createAndFill()));
|
|
28518
28759
|
for (let i = 0; i < match.next.length; i++) {
|
|
28519
28760
|
let { type, next } = match.next[i];
|
|
28520
28761
|
if (!(type.isText || type.hasRequiredAttrs()) && seen.indexOf(next) == -1) {
|
|
@@ -29082,7 +29323,7 @@ function mapFragment(fragment, f, parent) {
|
|
|
29082
29323
|
child = f(child, parent, i);
|
|
29083
29324
|
mapped.push(child);
|
|
29084
29325
|
}
|
|
29085
|
-
return
|
|
29326
|
+
return Fragment27.fromArray(mapped);
|
|
29086
29327
|
}
|
|
29087
29328
|
var AddMarkStep = class _AddMarkStep extends Step {
|
|
29088
29329
|
/**
|
|
@@ -29199,7 +29440,7 @@ var AddNodeMarkStep = class _AddNodeMarkStep extends Step {
|
|
|
29199
29440
|
if (!node)
|
|
29200
29441
|
return StepResult.fail("No node at mark step's position");
|
|
29201
29442
|
let updated = node.type.create(node.attrs, null, this.mark.addToSet(node.marks));
|
|
29202
|
-
return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(
|
|
29443
|
+
return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment27.from(updated), 0, node.isLeaf ? 0 : 1));
|
|
29203
29444
|
}
|
|
29204
29445
|
invert(doc) {
|
|
29205
29446
|
let node = doc.nodeAt(this.pos);
|
|
@@ -29245,7 +29486,7 @@ var RemoveNodeMarkStep = class _RemoveNodeMarkStep extends Step {
|
|
|
29245
29486
|
if (!node)
|
|
29246
29487
|
return StepResult.fail("No node at mark step's position");
|
|
29247
29488
|
let updated = node.type.create(node.attrs, null, this.mark.removeFromSet(node.marks));
|
|
29248
|
-
return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(
|
|
29489
|
+
return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment27.from(updated), 0, node.isLeaf ? 0 : 1));
|
|
29249
29490
|
}
|
|
29250
29491
|
invert(doc) {
|
|
29251
29492
|
let node = doc.nodeAt(this.pos);
|
|
@@ -29446,7 +29687,7 @@ var AttrStep = class _AttrStep extends Step {
|
|
|
29446
29687
|
attrs[name] = node.attrs[name];
|
|
29447
29688
|
attrs[this.attr] = this.value;
|
|
29448
29689
|
let updated = node.type.create(attrs, null, node.marks);
|
|
29449
|
-
return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(
|
|
29690
|
+
return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment27.from(updated), 0, node.isLeaf ? 0 : 1));
|
|
29450
29691
|
}
|
|
29451
29692
|
getMap() {
|
|
29452
29693
|
return StepMap.empty;
|
|
@@ -29830,7 +30071,7 @@ var NodeSelection2 = class _NodeSelection extends Selection {
|
|
|
29830
30071
|
return new _NodeSelection($pos);
|
|
29831
30072
|
}
|
|
29832
30073
|
content() {
|
|
29833
|
-
return new Slice(
|
|
30074
|
+
return new Slice(Fragment27.from(this.node), 0, 0);
|
|
29834
30075
|
}
|
|
29835
30076
|
eq(other) {
|
|
29836
30077
|
return other instanceof _NodeSelection && other.anchor == this.anchor;
|
|
@@ -30558,10 +30799,10 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
30558
30799
|
}
|
|
30559
30800
|
rowContent.push(cell);
|
|
30560
30801
|
}
|
|
30561
|
-
rows.push(table.child(row).copy(
|
|
30802
|
+
rows.push(table.child(row).copy(Fragment27.from(rowContent)));
|
|
30562
30803
|
}
|
|
30563
30804
|
const fragment = this.isColSelection() && this.isRowSelection() ? table : rows;
|
|
30564
|
-
return new Slice(
|
|
30805
|
+
return new Slice(Fragment27.from(fragment), 1, 1);
|
|
30565
30806
|
}
|
|
30566
30807
|
replace(tr, content = Slice.empty) {
|
|
30567
30808
|
const mapFrom = tr.steps.length, ranges = this.ranges;
|
|
@@ -30573,7 +30814,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
30573
30814
|
if (sel) tr.setSelection(sel);
|
|
30574
30815
|
}
|
|
30575
30816
|
replaceWith(tr, node) {
|
|
30576
|
-
this.replace(tr, new Slice(
|
|
30817
|
+
this.replace(tr, new Slice(Fragment27.from(node), 0, 0));
|
|
30577
30818
|
}
|
|
30578
30819
|
forEachCell(f) {
|
|
30579
30820
|
const table = this.$anchorCell.node(-1);
|