@rufous/ui 0.3.20 → 0.3.22
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/main.cjs +104 -63
- package/dist/main.css +14 -47
- package/dist/main.d.cts +25 -6
- package/dist/main.d.ts +25 -6
- package/dist/main.js +105 -64
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -4773,6 +4773,7 @@ function DataGrid({
|
|
|
4773
4773
|
const menuRef = (0, import_react23.useRef)(null);
|
|
4774
4774
|
const [showManageColumns, setShowManageColumns] = (0, import_react23.useState)(false);
|
|
4775
4775
|
const [showAdvancedFilter, setShowAdvancedFilter] = (0, import_react23.useState)(false);
|
|
4776
|
+
const [focusFilterIdx, setFocusFilterIdx] = (0, import_react23.useState)(-1);
|
|
4776
4777
|
const filterableColumnsProp = initialColumnsProp.filter((c) => c.filterable !== false);
|
|
4777
4778
|
const initialFilterCol = String(filterableColumnsProp[0]?.field || filterableColumnsProp[0]?.key || "");
|
|
4778
4779
|
const [advancedFilters, setAdvancedFilters] = (0, import_react23.useState)([
|
|
@@ -4821,9 +4822,13 @@ function DataGrid({
|
|
|
4821
4822
|
return next;
|
|
4822
4823
|
});
|
|
4823
4824
|
}, [initialColumnsProp]);
|
|
4825
|
+
const onFiltersChangeRef = (0, import_react23.useRef)(onFiltersChange);
|
|
4824
4826
|
(0, import_react23.useEffect)(() => {
|
|
4825
|
-
onFiltersChange
|
|
4826
|
-
}
|
|
4827
|
+
onFiltersChangeRef.current = onFiltersChange;
|
|
4828
|
+
});
|
|
4829
|
+
(0, import_react23.useEffect)(() => {
|
|
4830
|
+
onFiltersChangeRef.current?.(advancedFilters);
|
|
4831
|
+
}, [advancedFilters]);
|
|
4827
4832
|
const handleSort = (fieldKey, dir) => {
|
|
4828
4833
|
if (dir !== void 0) {
|
|
4829
4834
|
setSortField(fieldKey);
|
|
@@ -5092,6 +5097,7 @@ function DataGrid({
|
|
|
5092
5097
|
if (!firstCol) return prev;
|
|
5093
5098
|
return [{ column: String(firstCol.field), operator: getDefaultOperator(firstCol.type), value: "", logic: "AND" }];
|
|
5094
5099
|
});
|
|
5100
|
+
setFocusFilterIdx(-1);
|
|
5095
5101
|
setShowAdvancedFilter(false);
|
|
5096
5102
|
};
|
|
5097
5103
|
const activeMenuCol = activeMenu ? resolvedColumns.find((c) => String(c.field) === activeMenu) : null;
|
|
@@ -5143,7 +5149,18 @@ function DataGrid({
|
|
|
5143
5149
|
},
|
|
5144
5150
|
col.headerName,
|
|
5145
5151
|
col.sortable !== false && /* @__PURE__ */ import_react23.default.createElement("span", { className: `dg-sort-icon${isSorted ? " dg-sort-icon--active" : ""}` }, isSorted && sortDirection === "asc" && /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.ChevronUp, { size: 14 }), isSorted && sortDirection === "desc" && /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.ChevronDown, { size: 14 }), !isSorted && /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.ChevronsUpDown, { size: 14 }))
|
|
5146
|
-
), /* @__PURE__ */ import_react23.default.createElement("div", { className: `dg-th-actions${isFiltered ? " dg-th-actions--filtered" : ""}` }, isFiltered && /* @__PURE__ */ import_react23.default.createElement(
|
|
5152
|
+
), /* @__PURE__ */ import_react23.default.createElement("div", { className: `dg-th-actions${isFiltered ? " dg-th-actions--filtered" : ""}` }, isFiltered && /* @__PURE__ */ import_react23.default.createElement(
|
|
5153
|
+
"button",
|
|
5154
|
+
{
|
|
5155
|
+
className: "dg-th-filter-btn",
|
|
5156
|
+
onClick: () => {
|
|
5157
|
+
const idx2 = advancedFilters.findIndex((f) => f.column === colField);
|
|
5158
|
+
setFocusFilterIdx(idx2);
|
|
5159
|
+
setShowAdvancedFilter(true);
|
|
5160
|
+
}
|
|
5161
|
+
},
|
|
5162
|
+
/* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Filter, { size: 11 })
|
|
5163
|
+
), !col.disableColumnMenu && /* @__PURE__ */ import_react23.default.createElement(
|
|
5147
5164
|
"button",
|
|
5148
5165
|
{
|
|
5149
5166
|
className: "dg-th-menu-btn",
|
|
@@ -5372,7 +5389,7 @@ function DataGrid({
|
|
|
5372
5389
|
className: "dg-filter-input",
|
|
5373
5390
|
placeholder: "Value\u2026",
|
|
5374
5391
|
value: f.value,
|
|
5375
|
-
autoFocus: idx === advancedFilters.length - 1,
|
|
5392
|
+
autoFocus: focusFilterIdx >= 0 ? idx === focusFilterIdx : idx === advancedFilters.length - 1,
|
|
5376
5393
|
onChange: (e) => setAdvancedFilters((p) => p.map((fi, i) => i === idx ? { ...fi, value: e.target.value } : fi))
|
|
5377
5394
|
}
|
|
5378
5395
|
));
|
|
@@ -9071,6 +9088,14 @@ function getTopLevelSelected(nodes, selected) {
|
|
|
9071
9088
|
}
|
|
9072
9089
|
return result;
|
|
9073
9090
|
}
|
|
9091
|
+
function getAllSelected(nodes, selected) {
|
|
9092
|
+
const result = [];
|
|
9093
|
+
for (const node of nodes) {
|
|
9094
|
+
if (selected.has(String(node.id))) result.push(node);
|
|
9095
|
+
if (node.children?.length) result.push(...getAllSelected(node.children, selected));
|
|
9096
|
+
}
|
|
9097
|
+
return result;
|
|
9098
|
+
}
|
|
9074
9099
|
function filterTree(nodes, query) {
|
|
9075
9100
|
if (!query) return nodes;
|
|
9076
9101
|
const q = query.toLowerCase();
|
|
@@ -9099,6 +9124,7 @@ function TreeNodeItem({
|
|
|
9099
9124
|
selected,
|
|
9100
9125
|
expanded,
|
|
9101
9126
|
selectionMode,
|
|
9127
|
+
allowChildSelection,
|
|
9102
9128
|
onToggleExpand,
|
|
9103
9129
|
onSelect,
|
|
9104
9130
|
isFiltering
|
|
@@ -9106,7 +9132,7 @@ function TreeNodeItem({
|
|
|
9106
9132
|
const nodeId = String(node.id);
|
|
9107
9133
|
const hasChildren = !!node.children?.length;
|
|
9108
9134
|
const isExpanded = isFiltering || expanded.has(nodeId);
|
|
9109
|
-
const state = getNodeState(node, selected);
|
|
9135
|
+
const state = allowChildSelection ? getNodeState(node, selected) : selected.has(nodeId) ? "checked" : "unchecked";
|
|
9110
9136
|
return /* @__PURE__ */ import_react49.default.createElement("div", { className: "rf-tsn" }, /* @__PURE__ */ import_react49.default.createElement(
|
|
9111
9137
|
"div",
|
|
9112
9138
|
{
|
|
@@ -9126,16 +9152,8 @@ function TreeNodeItem({
|
|
|
9126
9152
|
},
|
|
9127
9153
|
isExpanded ? /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.ChevronDown, { size: 14 }) : /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.ChevronRight, { size: 14 })
|
|
9128
9154
|
) : /* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__expand-ph" }),
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
{
|
|
9132
|
-
className: `rf-tsn__cb${state === "checked" ? " rf-tsn__cb--checked" : state === "partial" ? " rf-tsn__cb--partial" : ""}`
|
|
9133
|
-
},
|
|
9134
|
-
state === "checked" && /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.Check, { size: 10, strokeWidth: 3 }),
|
|
9135
|
-
state === "partial" && /* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__cb-dash" })
|
|
9136
|
-
),
|
|
9137
|
-
selectionMode === "single" && /* @__PURE__ */ import_react49.default.createElement("span", { className: `rf-tsn__radio${state === "checked" ? " rf-tsn__radio--checked" : ""}` }),
|
|
9138
|
-
/* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__label" }, node.label)
|
|
9155
|
+
/* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__label" }, node.label),
|
|
9156
|
+
/* @__PURE__ */ import_react49.default.createElement("span", { className: "rf-tsn__check", "aria-hidden": "true" }, state === "partial" ? /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.Minus, { size: 13, strokeWidth: 2.5 }) : /* @__PURE__ */ import_react49.default.createElement(import_lucide_react3.Check, { size: 13, strokeWidth: 2.5 }))
|
|
9139
9157
|
), hasChildren && isExpanded && /* @__PURE__ */ import_react49.default.createElement("div", null, node.children.map((child) => /* @__PURE__ */ import_react49.default.createElement(
|
|
9140
9158
|
TreeNodeItem,
|
|
9141
9159
|
{
|
|
@@ -9145,6 +9163,7 @@ function TreeNodeItem({
|
|
|
9145
9163
|
selected,
|
|
9146
9164
|
expanded,
|
|
9147
9165
|
selectionMode,
|
|
9166
|
+
allowChildSelection,
|
|
9148
9167
|
onToggleExpand,
|
|
9149
9168
|
onSelect,
|
|
9150
9169
|
isFiltering
|
|
@@ -9158,6 +9177,7 @@ function TreeSelect({
|
|
|
9158
9177
|
onNodeSelect,
|
|
9159
9178
|
onNodeUnselect,
|
|
9160
9179
|
selectionMode = "single",
|
|
9180
|
+
allowChildSelection = false,
|
|
9161
9181
|
placeholder = "Select",
|
|
9162
9182
|
filter = false,
|
|
9163
9183
|
filterInputAutoFocus = false,
|
|
@@ -9278,15 +9298,25 @@ function TreeSelect({
|
|
|
9278
9298
|
const handleSelect = (node) => {
|
|
9279
9299
|
const nodeId = String(node.id);
|
|
9280
9300
|
if (isMultiple) {
|
|
9281
|
-
const state = getNodeState(node, selectedSet);
|
|
9282
|
-
const descendants = collectDescendants(node);
|
|
9283
9301
|
const newSet = new Set(selectedSet);
|
|
9284
|
-
if (
|
|
9285
|
-
|
|
9286
|
-
|
|
9302
|
+
if (allowChildSelection) {
|
|
9303
|
+
const state = getNodeState(node, selectedSet);
|
|
9304
|
+
const descendants = collectDescendants(node);
|
|
9305
|
+
if (state === "checked" || state === "partial") {
|
|
9306
|
+
descendants.forEach((id) => newSet.delete(id));
|
|
9307
|
+
onNodeUnselect?.({ node });
|
|
9308
|
+
} else {
|
|
9309
|
+
descendants.forEach((id) => newSet.add(id));
|
|
9310
|
+
onNodeSelect?.({ node });
|
|
9311
|
+
}
|
|
9287
9312
|
} else {
|
|
9288
|
-
|
|
9289
|
-
|
|
9313
|
+
if (newSet.has(nodeId)) {
|
|
9314
|
+
newSet.delete(nodeId);
|
|
9315
|
+
onNodeUnselect?.({ node });
|
|
9316
|
+
} else {
|
|
9317
|
+
newSet.add(nodeId);
|
|
9318
|
+
onNodeSelect?.({ node });
|
|
9319
|
+
}
|
|
9290
9320
|
}
|
|
9291
9321
|
onChange?.({ value: setToRecord(newSet) });
|
|
9292
9322
|
} else {
|
|
@@ -9319,7 +9349,7 @@ function TreeSelect({
|
|
|
9319
9349
|
onNodeUnselect?.({ node });
|
|
9320
9350
|
};
|
|
9321
9351
|
const filteredTree = filterTree(options, filterQuery);
|
|
9322
|
-
const tagNodes = isMultiple ? getTopLevelSelected(options, selectedSet) : value != null ? findNodeById(options, String(value)) ? [findNodeById(options, String(value))] : [] : [];
|
|
9352
|
+
const tagNodes = isMultiple ? allowChildSelection ? getTopLevelSelected(options, selectedSet) : getAllSelected(options, selectedSet) : value != null ? findNodeById(options, String(value)) ? [findNodeById(options, String(value))] : [] : [];
|
|
9323
9353
|
const hasValue = tagNodes.length > 0;
|
|
9324
9354
|
const isFloating = open || hasValue || focused;
|
|
9325
9355
|
const rootClasses = [
|
|
@@ -9417,6 +9447,7 @@ function TreeSelect({
|
|
|
9417
9447
|
selected: selectedSet,
|
|
9418
9448
|
expanded: expandedKeys,
|
|
9419
9449
|
selectionMode,
|
|
9450
|
+
allowChildSelection,
|
|
9420
9451
|
onToggleExpand: handleToggleExpand,
|
|
9421
9452
|
onSelect: handleSelect,
|
|
9422
9453
|
isFiltering: !!filterQuery
|
|
@@ -9550,7 +9581,9 @@ function SmartSelect({
|
|
|
9550
9581
|
value,
|
|
9551
9582
|
onChange,
|
|
9552
9583
|
onSearchChange,
|
|
9584
|
+
searchResults = [],
|
|
9553
9585
|
debounceMs = 300,
|
|
9586
|
+
searchThreshold = 10,
|
|
9554
9587
|
getOptionLabel,
|
|
9555
9588
|
getOptionValue,
|
|
9556
9589
|
getOptionSubLabel,
|
|
@@ -9588,14 +9621,20 @@ function SmartSelect({
|
|
|
9588
9621
|
return flattenTree(options, getOptionChildren);
|
|
9589
9622
|
}, [options, getOptionChildren]);
|
|
9590
9623
|
const flatOptionsList = (0, import_react51.useMemo)(() => flatItems.map((f) => f.option), [flatItems]);
|
|
9624
|
+
const displayOptions = (0, import_react51.useMemo)(() => {
|
|
9625
|
+
if (!searchResults.length) return flatOptionsList;
|
|
9626
|
+
const localKeys = new Set(flatOptionsList.map((o) => getValue(o)));
|
|
9627
|
+
const serverOnly = searchResults.filter((o) => !localKeys.has(getValue(o)));
|
|
9628
|
+
return [...flatOptionsList, ...serverOnly];
|
|
9629
|
+
}, [flatOptionsList, searchResults, getValue]);
|
|
9591
9630
|
const depthMap = (0, import_react51.useMemo)(() => {
|
|
9592
9631
|
const map = /* @__PURE__ */ new Map();
|
|
9593
9632
|
flatItems.forEach(({ option, depth }) => map.set(getValue(option), depth));
|
|
9594
9633
|
return map;
|
|
9595
9634
|
}, [flatItems, getValue]);
|
|
9596
9635
|
const lookup = (0, import_react51.useMemo)(
|
|
9597
|
-
() => buildLookup(
|
|
9598
|
-
[
|
|
9636
|
+
() => buildLookup(displayOptions, getOptionChildren, getValue),
|
|
9637
|
+
[displayOptions, getOptionChildren, getValue]
|
|
9599
9638
|
);
|
|
9600
9639
|
const selectedKeys = (0, import_react51.useMemo)(() => {
|
|
9601
9640
|
if (multiple) {
|
|
@@ -9607,21 +9646,27 @@ function SmartSelect({
|
|
|
9607
9646
|
if (!onSearchChange) return;
|
|
9608
9647
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
9609
9648
|
if (!inputValue) {
|
|
9610
|
-
onSearchChange("");
|
|
9649
|
+
onSearchChange("", 0);
|
|
9611
9650
|
return;
|
|
9612
9651
|
}
|
|
9613
|
-
const
|
|
9614
|
-
|
|
9615
|
-
)
|
|
9616
|
-
|
|
9652
|
+
const q = inputValue.toLowerCase();
|
|
9653
|
+
let localCount = 0;
|
|
9654
|
+
for (const opt of flatOptionsList) {
|
|
9655
|
+
if (getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)) {
|
|
9656
|
+
localCount++;
|
|
9657
|
+
if (localCount >= searchThreshold) break;
|
|
9658
|
+
}
|
|
9659
|
+
}
|
|
9660
|
+
if (localCount >= searchThreshold) return;
|
|
9661
|
+
const needed = searchThreshold - localCount;
|
|
9617
9662
|
if (debounceMs <= 0) {
|
|
9618
|
-
onSearchChange(inputValue);
|
|
9663
|
+
onSearchChange(inputValue, needed);
|
|
9619
9664
|
} else {
|
|
9620
9665
|
debounceTimer.current = setTimeout(() => {
|
|
9621
|
-
onSearchChange(inputValue);
|
|
9666
|
+
onSearchChange(inputValue, needed);
|
|
9622
9667
|
}, debounceMs);
|
|
9623
9668
|
}
|
|
9624
|
-
}, [onSearchChange, debounceMs, flatOptionsList, getOptionLabel, getOptionSubLabel]);
|
|
9669
|
+
}, [onSearchChange, debounceMs, searchThreshold, flatOptionsList, getOptionLabel, getOptionSubLabel]);
|
|
9625
9670
|
const handleChange = (0, import_react51.useCallback)((_, newValue) => {
|
|
9626
9671
|
if (!multiple || !allowChildNodesSelection || !getOptionChildren) {
|
|
9627
9672
|
onChange?.(newValue);
|
|
@@ -9673,34 +9718,28 @@ function SmartSelect({
|
|
|
9673
9718
|
{
|
|
9674
9719
|
key,
|
|
9675
9720
|
...rest,
|
|
9676
|
-
className:
|
|
9721
|
+
className: [
|
|
9722
|
+
muiClass,
|
|
9723
|
+
"rf-select__option",
|
|
9724
|
+
isSelected ? "rf-select__option--selected" : ""
|
|
9725
|
+
].filter(Boolean).join(" "),
|
|
9677
9726
|
style: {
|
|
9678
9727
|
...muiStyle,
|
|
9679
|
-
display: "flex",
|
|
9680
|
-
alignItems: "center",
|
|
9681
|
-
gap: 10,
|
|
9682
|
-
padding: "8px 16px",
|
|
9683
9728
|
paddingLeft: 16 + depth * 20,
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
cursor: "pointer",
|
|
9687
|
-
userSelect: "none",
|
|
9688
|
-
minHeight: 40,
|
|
9689
|
-
boxSizing: "border-box",
|
|
9690
|
-
fontWeight: isSelected ? 500 : void 0,
|
|
9691
|
-
backgroundColor: isSelected ? "rgba(164,27,6,0.08)" : void 0,
|
|
9692
|
-
listStyle: "none"
|
|
9729
|
+
listStyle: "none",
|
|
9730
|
+
alignItems: subLabel ? "flex-start" : void 0
|
|
9693
9731
|
}
|
|
9694
9732
|
},
|
|
9695
|
-
/* @__PURE__ */ import_react51.default.createElement(
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9733
|
+
/* @__PURE__ */ import_react51.default.createElement(
|
|
9734
|
+
"span",
|
|
9735
|
+
{
|
|
9736
|
+
className: "rf-select__option-label",
|
|
9737
|
+
style: subLabel ? { display: "flex", flexDirection: "column", whiteSpace: "normal" } : void 0
|
|
9738
|
+
},
|
|
9739
|
+
/* @__PURE__ */ import_react51.default.createElement("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", lineHeight: 1.3 } }, getOptionLabel(option)),
|
|
9740
|
+
subLabel && /* @__PURE__ */ import_react51.default.createElement("span", { style: { fontSize: "0.75rem", color: "var(--text-secondary)", lineHeight: 1.3, marginTop: 1 } }, subLabel)
|
|
9741
|
+
),
|
|
9742
|
+
/* @__PURE__ */ import_react51.default.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ import_react51.default.createElement(CheckIcon3, null))
|
|
9704
9743
|
);
|
|
9705
9744
|
}, [depthMap, getValue, getOptionLabel, getOptionSubLabel, selectedKeys]);
|
|
9706
9745
|
const computedFilterOptions = (0, import_react51.useCallback)((opts, inputValue) => {
|
|
@@ -9708,10 +9747,12 @@ function SmartSelect({
|
|
|
9708
9747
|
if (multiple) {
|
|
9709
9748
|
const selected = opts.filter((o) => selectedKeys.has(getValue(o)));
|
|
9710
9749
|
const unselected = opts.filter((o) => !selectedKeys.has(getValue(o)));
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
|
|
9750
|
+
if (!inputValue) return [...selected, ...unselected];
|
|
9751
|
+
const q2 = inputValue.toLowerCase();
|
|
9752
|
+
const filteredUnselected = unselected.filter(
|
|
9753
|
+
(opt) => getOptionLabel(opt).toLowerCase().includes(q2) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q2)
|
|
9754
|
+
).slice(0, searchThreshold);
|
|
9755
|
+
return [...selected, ...filteredUnselected];
|
|
9715
9756
|
}
|
|
9716
9757
|
if (value != null) {
|
|
9717
9758
|
const selectedLabel = getOptionLabel(value);
|
|
@@ -9727,12 +9768,12 @@ function SmartSelect({
|
|
|
9727
9768
|
const q = inputValue.toLowerCase();
|
|
9728
9769
|
return opts.filter(
|
|
9729
9770
|
(opt) => getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)
|
|
9730
|
-
);
|
|
9731
|
-
}, [filterOptionsProp, multiple, selectedKeys, getValue, getOptionLabel, getOptionSubLabel, value]);
|
|
9771
|
+
).slice(0, searchThreshold);
|
|
9772
|
+
}, [filterOptionsProp, multiple, selectedKeys, getValue, getOptionLabel, getOptionSubLabel, value, searchThreshold]);
|
|
9732
9773
|
return /* @__PURE__ */ import_react51.default.createElement(
|
|
9733
9774
|
Autocomplete,
|
|
9734
9775
|
{
|
|
9735
|
-
options:
|
|
9776
|
+
options: displayOptions,
|
|
9736
9777
|
value: value ?? (multiple ? [] : null),
|
|
9737
9778
|
onChange: handleChange,
|
|
9738
9779
|
onInputChange: handleInputChange,
|
package/dist/main.css
CHANGED
|
@@ -1370,6 +1370,12 @@ pre {
|
|
|
1370
1370
|
.rf-tsn__row:hover {
|
|
1371
1371
|
background: rgba(241, 91, 36, 0.06);
|
|
1372
1372
|
}
|
|
1373
|
+
.rf-tsn__row--active {
|
|
1374
|
+
background: rgba(164, 27, 6, 0.08);
|
|
1375
|
+
}
|
|
1376
|
+
.rf-tsn__row--active:hover {
|
|
1377
|
+
background: rgba(164, 27, 6, 0.12);
|
|
1378
|
+
}
|
|
1373
1379
|
.rf-tsn__row--active .rf-tsn__label {
|
|
1374
1380
|
color: rgba(0, 0, 0, 0.87);
|
|
1375
1381
|
font-weight: 500;
|
|
@@ -1397,56 +1403,17 @@ pre {
|
|
|
1397
1403
|
flex-shrink: 0;
|
|
1398
1404
|
display: inline-block;
|
|
1399
1405
|
}
|
|
1400
|
-
.rf-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
border: 2px solid var(--border-color);
|
|
1404
|
-
border-radius: 4px;
|
|
1406
|
+
.rf-tsn__check {
|
|
1407
|
+
color: var(--primary-color, #a41b06);
|
|
1408
|
+
flex-shrink: 0;
|
|
1405
1409
|
display: flex;
|
|
1406
1410
|
align-items: center;
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
transition:
|
|
1410
|
-
background: var(--surface-color);
|
|
1411
|
-
color: transparent;
|
|
1412
|
-
}
|
|
1413
|
-
.rf-tsn__cb--checked {
|
|
1414
|
-
background: var(--primary-color);
|
|
1415
|
-
border-color: var(--primary-color);
|
|
1416
|
-
color: #fff;
|
|
1417
|
-
}
|
|
1418
|
-
.rf-tsn__cb--partial {
|
|
1419
|
-
border-color: var(--primary-color);
|
|
1420
|
-
}
|
|
1421
|
-
.rf-tsn__cb-dash {
|
|
1422
|
-
display: block;
|
|
1423
|
-
width: 8px;
|
|
1424
|
-
height: 2px;
|
|
1425
|
-
background: var(--primary-color);
|
|
1426
|
-
border-radius: 1px;
|
|
1427
|
-
}
|
|
1428
|
-
.rf-tsn__radio {
|
|
1429
|
-
width: 16px;
|
|
1430
|
-
height: 16px;
|
|
1431
|
-
border: 2px solid var(--border-color);
|
|
1432
|
-
border-radius: 50%;
|
|
1433
|
-
flex-shrink: 0;
|
|
1434
|
-
transition: border-color 0.15s;
|
|
1435
|
-
position: relative;
|
|
1436
|
-
}
|
|
1437
|
-
.rf-tsn__radio--checked {
|
|
1438
|
-
border-color: var(--primary-color);
|
|
1411
|
+
margin-left: auto;
|
|
1412
|
+
opacity: 0;
|
|
1413
|
+
transition: opacity 0.1s;
|
|
1439
1414
|
}
|
|
1440
|
-
.rf-
|
|
1441
|
-
|
|
1442
|
-
position: absolute;
|
|
1443
|
-
top: 50%;
|
|
1444
|
-
left: 50%;
|
|
1445
|
-
transform: translate(-50%, -50%);
|
|
1446
|
-
width: 8px;
|
|
1447
|
-
height: 8px;
|
|
1448
|
-
background: var(--primary-color);
|
|
1449
|
-
border-radius: 50%;
|
|
1415
|
+
.rf-tsn__row--active .rf-tsn__check {
|
|
1416
|
+
opacity: 1;
|
|
1450
1417
|
}
|
|
1451
1418
|
.rf-tsn__label {
|
|
1452
1419
|
font-size: 0.875rem;
|
package/dist/main.d.cts
CHANGED
|
@@ -1830,7 +1830,13 @@ interface TreeSelectProps {
|
|
|
1830
1830
|
filterInputAutoFocus?: boolean;
|
|
1831
1831
|
/** Clear filter text when the dropdown closes */
|
|
1832
1832
|
resetFilterOnHide?: boolean;
|
|
1833
|
-
/**
|
|
1833
|
+
/**
|
|
1834
|
+
* When **true**, selecting a parent selects all its descendants and vice-versa (cascade).
|
|
1835
|
+
* When **false** (default), every node is selected/deselected independently — no cascade.
|
|
1836
|
+
* Only relevant in `multiple` mode.
|
|
1837
|
+
*/
|
|
1838
|
+
allowChildSelection?: boolean;
|
|
1839
|
+
/** PrimeReact compat — accepted but not used */
|
|
1834
1840
|
metaKeySelection?: boolean;
|
|
1835
1841
|
/** Disable the whole control */
|
|
1836
1842
|
disabled?: boolean;
|
|
@@ -1854,7 +1860,7 @@ interface TreeSelectProps {
|
|
|
1854
1860
|
className?: string;
|
|
1855
1861
|
sx?: SxProp;
|
|
1856
1862
|
}
|
|
1857
|
-
declare function TreeSelect({ options, value, onChange, onNodeSelect, onNodeUnselect, selectionMode, placeholder, filter, filterInputAutoFocus, resetFilterOnHide, metaKeySelection: _metaKeySelection, disabled, label, variant, size, error, helperText, fullWidth, clearable, required, style, className, sx, }: TreeSelectProps): React__default.JSX.Element;
|
|
1863
|
+
declare function TreeSelect({ options, value, onChange, onNodeSelect, onNodeUnselect, selectionMode, allowChildSelection, placeholder, filter, filterInputAutoFocus, resetFilterOnHide, metaKeySelection: _metaKeySelection, disabled, label, variant, size, error, helperText, fullWidth, clearable, required, style, className, sx, }: TreeSelectProps): React__default.JSX.Element;
|
|
1858
1864
|
|
|
1859
1865
|
interface UserOption {
|
|
1860
1866
|
id?: string | number;
|
|
@@ -1909,15 +1915,28 @@ interface SmartSelectProps<T = any> {
|
|
|
1909
1915
|
/** Called when selection changes */
|
|
1910
1916
|
onChange?: (value: T | T[] | null) => void;
|
|
1911
1917
|
/**
|
|
1912
|
-
* Called when
|
|
1913
|
-
*
|
|
1918
|
+
* Called when local matches fall below `searchThreshold`.
|
|
1919
|
+
* Receives the current query and how many more records are needed to fill the threshold.
|
|
1920
|
+
* Use this to trigger an API / server search and update `searchResults`.
|
|
1914
1921
|
*/
|
|
1915
|
-
onSearchChange?: (query: string) => void;
|
|
1922
|
+
onSearchChange?: (query: string, needed: number) => void;
|
|
1923
|
+
/**
|
|
1924
|
+
* Results returned by the API for the current query.
|
|
1925
|
+
* Merged with local matches (duplicates excluded) to fill up to `searchThreshold`.
|
|
1926
|
+
* Reset this to [] when the query is cleared.
|
|
1927
|
+
*/
|
|
1928
|
+
searchResults?: T[];
|
|
1916
1929
|
/**
|
|
1917
1930
|
* Debounce delay in ms before `onSearchChange` fires.
|
|
1918
1931
|
* Defaults to 300 ms. Pass 0 to disable debouncing.
|
|
1919
1932
|
*/
|
|
1920
1933
|
debounceMs?: number;
|
|
1934
|
+
/**
|
|
1935
|
+
* Max results to show when a query is active.
|
|
1936
|
+
* If local matches are fewer than this, `onSearchChange` fires with how many more are needed.
|
|
1937
|
+
* Defaults to 10. Pass 0 to always call the API.
|
|
1938
|
+
*/
|
|
1939
|
+
searchThreshold?: number;
|
|
1921
1940
|
/** Primary display label for an option (required) */
|
|
1922
1941
|
getOptionLabel: (option: T) => string;
|
|
1923
1942
|
/** Unique key for an option — defaults to the label string */
|
|
@@ -1971,7 +1990,7 @@ interface SmartSelectProps<T = any> {
|
|
|
1971
1990
|
style?: CSSProperties;
|
|
1972
1991
|
sx?: SxProp;
|
|
1973
1992
|
}
|
|
1974
|
-
declare function SmartSelect<T = any>({ options, value, onChange, onSearchChange, debounceMs, getOptionLabel, getOptionValue, getOptionSubLabel, getOptionChildren, multiple, allowChildNodesSelection, loading, loadingText, filterOptions: filterOptionsProp, renderOption: renderOptionProp, limitTags, label, placeholder, variant, size, disabled, error, helperText, fullWidth, required, className, style, sx, }: SmartSelectProps<T>): React__default.JSX.Element;
|
|
1993
|
+
declare function SmartSelect<T = any>({ options, value, onChange, onSearchChange, searchResults, debounceMs, searchThreshold, getOptionLabel, getOptionValue, getOptionSubLabel, getOptionChildren, multiple, allowChildNodesSelection, loading, loadingText, filterOptions: filterOptionsProp, renderOption: renderOptionProp, limitTags, label, placeholder, variant, size, disabled, error, helperText, fullWidth, required, className, style, sx, }: SmartSelectProps<T>): React__default.JSX.Element;
|
|
1975
1994
|
|
|
1976
1995
|
type ToolbarButton = 'undo' | 'redo' | 'ai' | 'paragraph' | 'fontsize' | 'font' | 'color' | 'bold' | 'italic' | 'strike' | 'link' | 'lineheight' | 'ul' | 'ol' | 'align' | 'indent' | 'outdent' | 'table' | 'image' | 'video' | 'cut' | 'copy' | 'paste' | 'specialchars' | 'code' | 'fullscreen' | 'tts' | 'stt' | 'translate' | 'todo' | '|';
|
|
1977
1996
|
type EditorVariant = 'default' | 'basic';
|
package/dist/main.d.ts
CHANGED
|
@@ -1830,7 +1830,13 @@ interface TreeSelectProps {
|
|
|
1830
1830
|
filterInputAutoFocus?: boolean;
|
|
1831
1831
|
/** Clear filter text when the dropdown closes */
|
|
1832
1832
|
resetFilterOnHide?: boolean;
|
|
1833
|
-
/**
|
|
1833
|
+
/**
|
|
1834
|
+
* When **true**, selecting a parent selects all its descendants and vice-versa (cascade).
|
|
1835
|
+
* When **false** (default), every node is selected/deselected independently — no cascade.
|
|
1836
|
+
* Only relevant in `multiple` mode.
|
|
1837
|
+
*/
|
|
1838
|
+
allowChildSelection?: boolean;
|
|
1839
|
+
/** PrimeReact compat — accepted but not used */
|
|
1834
1840
|
metaKeySelection?: boolean;
|
|
1835
1841
|
/** Disable the whole control */
|
|
1836
1842
|
disabled?: boolean;
|
|
@@ -1854,7 +1860,7 @@ interface TreeSelectProps {
|
|
|
1854
1860
|
className?: string;
|
|
1855
1861
|
sx?: SxProp;
|
|
1856
1862
|
}
|
|
1857
|
-
declare function TreeSelect({ options, value, onChange, onNodeSelect, onNodeUnselect, selectionMode, placeholder, filter, filterInputAutoFocus, resetFilterOnHide, metaKeySelection: _metaKeySelection, disabled, label, variant, size, error, helperText, fullWidth, clearable, required, style, className, sx, }: TreeSelectProps): React__default.JSX.Element;
|
|
1863
|
+
declare function TreeSelect({ options, value, onChange, onNodeSelect, onNodeUnselect, selectionMode, allowChildSelection, placeholder, filter, filterInputAutoFocus, resetFilterOnHide, metaKeySelection: _metaKeySelection, disabled, label, variant, size, error, helperText, fullWidth, clearable, required, style, className, sx, }: TreeSelectProps): React__default.JSX.Element;
|
|
1858
1864
|
|
|
1859
1865
|
interface UserOption {
|
|
1860
1866
|
id?: string | number;
|
|
@@ -1909,15 +1915,28 @@ interface SmartSelectProps<T = any> {
|
|
|
1909
1915
|
/** Called when selection changes */
|
|
1910
1916
|
onChange?: (value: T | T[] | null) => void;
|
|
1911
1917
|
/**
|
|
1912
|
-
* Called when
|
|
1913
|
-
*
|
|
1918
|
+
* Called when local matches fall below `searchThreshold`.
|
|
1919
|
+
* Receives the current query and how many more records are needed to fill the threshold.
|
|
1920
|
+
* Use this to trigger an API / server search and update `searchResults`.
|
|
1914
1921
|
*/
|
|
1915
|
-
onSearchChange?: (query: string) => void;
|
|
1922
|
+
onSearchChange?: (query: string, needed: number) => void;
|
|
1923
|
+
/**
|
|
1924
|
+
* Results returned by the API for the current query.
|
|
1925
|
+
* Merged with local matches (duplicates excluded) to fill up to `searchThreshold`.
|
|
1926
|
+
* Reset this to [] when the query is cleared.
|
|
1927
|
+
*/
|
|
1928
|
+
searchResults?: T[];
|
|
1916
1929
|
/**
|
|
1917
1930
|
* Debounce delay in ms before `onSearchChange` fires.
|
|
1918
1931
|
* Defaults to 300 ms. Pass 0 to disable debouncing.
|
|
1919
1932
|
*/
|
|
1920
1933
|
debounceMs?: number;
|
|
1934
|
+
/**
|
|
1935
|
+
* Max results to show when a query is active.
|
|
1936
|
+
* If local matches are fewer than this, `onSearchChange` fires with how many more are needed.
|
|
1937
|
+
* Defaults to 10. Pass 0 to always call the API.
|
|
1938
|
+
*/
|
|
1939
|
+
searchThreshold?: number;
|
|
1921
1940
|
/** Primary display label for an option (required) */
|
|
1922
1941
|
getOptionLabel: (option: T) => string;
|
|
1923
1942
|
/** Unique key for an option — defaults to the label string */
|
|
@@ -1971,7 +1990,7 @@ interface SmartSelectProps<T = any> {
|
|
|
1971
1990
|
style?: CSSProperties;
|
|
1972
1991
|
sx?: SxProp;
|
|
1973
1992
|
}
|
|
1974
|
-
declare function SmartSelect<T = any>({ options, value, onChange, onSearchChange, debounceMs, getOptionLabel, getOptionValue, getOptionSubLabel, getOptionChildren, multiple, allowChildNodesSelection, loading, loadingText, filterOptions: filterOptionsProp, renderOption: renderOptionProp, limitTags, label, placeholder, variant, size, disabled, error, helperText, fullWidth, required, className, style, sx, }: SmartSelectProps<T>): React__default.JSX.Element;
|
|
1993
|
+
declare function SmartSelect<T = any>({ options, value, onChange, onSearchChange, searchResults, debounceMs, searchThreshold, getOptionLabel, getOptionValue, getOptionSubLabel, getOptionChildren, multiple, allowChildNodesSelection, loading, loadingText, filterOptions: filterOptionsProp, renderOption: renderOptionProp, limitTags, label, placeholder, variant, size, disabled, error, helperText, fullWidth, required, className, style, sx, }: SmartSelectProps<T>): React__default.JSX.Element;
|
|
1975
1994
|
|
|
1976
1995
|
type ToolbarButton = 'undo' | 'redo' | 'ai' | 'paragraph' | 'fontsize' | 'font' | 'color' | 'bold' | 'italic' | 'strike' | 'link' | 'lineheight' | 'ul' | 'ol' | 'align' | 'indent' | 'outdent' | 'table' | 'image' | 'video' | 'cut' | 'copy' | 'paste' | 'specialchars' | 'code' | 'fullscreen' | 'tts' | 'stt' | 'translate' | 'todo' | '|';
|
|
1977
1996
|
type EditorVariant = 'default' | 'basic';
|
package/dist/main.js
CHANGED
|
@@ -4628,6 +4628,7 @@ function DataGrid({
|
|
|
4628
4628
|
const menuRef = useRef10(null);
|
|
4629
4629
|
const [showManageColumns, setShowManageColumns] = useState9(false);
|
|
4630
4630
|
const [showAdvancedFilter, setShowAdvancedFilter] = useState9(false);
|
|
4631
|
+
const [focusFilterIdx, setFocusFilterIdx] = useState9(-1);
|
|
4631
4632
|
const filterableColumnsProp = initialColumnsProp.filter((c) => c.filterable !== false);
|
|
4632
4633
|
const initialFilterCol = String(filterableColumnsProp[0]?.field || filterableColumnsProp[0]?.key || "");
|
|
4633
4634
|
const [advancedFilters, setAdvancedFilters] = useState9([
|
|
@@ -4676,9 +4677,13 @@ function DataGrid({
|
|
|
4676
4677
|
return next;
|
|
4677
4678
|
});
|
|
4678
4679
|
}, [initialColumnsProp]);
|
|
4680
|
+
const onFiltersChangeRef = useRef10(onFiltersChange);
|
|
4679
4681
|
useEffect9(() => {
|
|
4680
|
-
onFiltersChange
|
|
4681
|
-
}
|
|
4682
|
+
onFiltersChangeRef.current = onFiltersChange;
|
|
4683
|
+
});
|
|
4684
|
+
useEffect9(() => {
|
|
4685
|
+
onFiltersChangeRef.current?.(advancedFilters);
|
|
4686
|
+
}, [advancedFilters]);
|
|
4682
4687
|
const handleSort = (fieldKey, dir) => {
|
|
4683
4688
|
if (dir !== void 0) {
|
|
4684
4689
|
setSortField(fieldKey);
|
|
@@ -4947,6 +4952,7 @@ function DataGrid({
|
|
|
4947
4952
|
if (!firstCol) return prev;
|
|
4948
4953
|
return [{ column: String(firstCol.field), operator: getDefaultOperator(firstCol.type), value: "", logic: "AND" }];
|
|
4949
4954
|
});
|
|
4955
|
+
setFocusFilterIdx(-1);
|
|
4950
4956
|
setShowAdvancedFilter(false);
|
|
4951
4957
|
};
|
|
4952
4958
|
const activeMenuCol = activeMenu ? resolvedColumns.find((c) => String(c.field) === activeMenu) : null;
|
|
@@ -4998,7 +5004,18 @@ function DataGrid({
|
|
|
4998
5004
|
},
|
|
4999
5005
|
col.headerName,
|
|
5000
5006
|
col.sortable !== false && /* @__PURE__ */ React75.createElement("span", { className: `dg-sort-icon${isSorted ? " dg-sort-icon--active" : ""}` }, isSorted && sortDirection === "asc" && /* @__PURE__ */ React75.createElement(ChevronUp, { size: 14 }), isSorted && sortDirection === "desc" && /* @__PURE__ */ React75.createElement(ChevronDown, { size: 14 }), !isSorted && /* @__PURE__ */ React75.createElement(ChevronsUpDown, { size: 14 }))
|
|
5001
|
-
), /* @__PURE__ */ React75.createElement("div", { className: `dg-th-actions${isFiltered ? " dg-th-actions--filtered" : ""}` }, isFiltered && /* @__PURE__ */ React75.createElement(
|
|
5007
|
+
), /* @__PURE__ */ React75.createElement("div", { className: `dg-th-actions${isFiltered ? " dg-th-actions--filtered" : ""}` }, isFiltered && /* @__PURE__ */ React75.createElement(
|
|
5008
|
+
"button",
|
|
5009
|
+
{
|
|
5010
|
+
className: "dg-th-filter-btn",
|
|
5011
|
+
onClick: () => {
|
|
5012
|
+
const idx2 = advancedFilters.findIndex((f) => f.column === colField);
|
|
5013
|
+
setFocusFilterIdx(idx2);
|
|
5014
|
+
setShowAdvancedFilter(true);
|
|
5015
|
+
}
|
|
5016
|
+
},
|
|
5017
|
+
/* @__PURE__ */ React75.createElement(Filter, { size: 11 })
|
|
5018
|
+
), !col.disableColumnMenu && /* @__PURE__ */ React75.createElement(
|
|
5002
5019
|
"button",
|
|
5003
5020
|
{
|
|
5004
5021
|
className: "dg-th-menu-btn",
|
|
@@ -5227,7 +5244,7 @@ function DataGrid({
|
|
|
5227
5244
|
className: "dg-filter-input",
|
|
5228
5245
|
placeholder: "Value\u2026",
|
|
5229
5246
|
value: f.value,
|
|
5230
|
-
autoFocus: idx === advancedFilters.length - 1,
|
|
5247
|
+
autoFocus: focusFilterIdx >= 0 ? idx === focusFilterIdx : idx === advancedFilters.length - 1,
|
|
5231
5248
|
onChange: (e) => setAdvancedFilters((p) => p.map((fi, i) => i === idx ? { ...fi, value: e.target.value } : fi))
|
|
5232
5249
|
}
|
|
5233
5250
|
));
|
|
@@ -8961,7 +8978,7 @@ import React106, {
|
|
|
8961
8978
|
useCallback as useCallback10
|
|
8962
8979
|
} from "react";
|
|
8963
8980
|
import ReactDOM10 from "react-dom";
|
|
8964
|
-
import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight2, X as X3, Search as Search2, Check } from "lucide-react";
|
|
8981
|
+
import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight2, X as X3, Search as Search2, Check, Minus } from "lucide-react";
|
|
8965
8982
|
function collectDescendants(node) {
|
|
8966
8983
|
const ids = [String(node.id)];
|
|
8967
8984
|
node.children?.forEach((c) => ids.push(...collectDescendants(c)));
|
|
@@ -8995,6 +9012,14 @@ function getTopLevelSelected(nodes, selected) {
|
|
|
8995
9012
|
}
|
|
8996
9013
|
return result;
|
|
8997
9014
|
}
|
|
9015
|
+
function getAllSelected(nodes, selected) {
|
|
9016
|
+
const result = [];
|
|
9017
|
+
for (const node of nodes) {
|
|
9018
|
+
if (selected.has(String(node.id))) result.push(node);
|
|
9019
|
+
if (node.children?.length) result.push(...getAllSelected(node.children, selected));
|
|
9020
|
+
}
|
|
9021
|
+
return result;
|
|
9022
|
+
}
|
|
8998
9023
|
function filterTree(nodes, query) {
|
|
8999
9024
|
if (!query) return nodes;
|
|
9000
9025
|
const q = query.toLowerCase();
|
|
@@ -9023,6 +9048,7 @@ function TreeNodeItem({
|
|
|
9023
9048
|
selected,
|
|
9024
9049
|
expanded,
|
|
9025
9050
|
selectionMode,
|
|
9051
|
+
allowChildSelection,
|
|
9026
9052
|
onToggleExpand,
|
|
9027
9053
|
onSelect,
|
|
9028
9054
|
isFiltering
|
|
@@ -9030,7 +9056,7 @@ function TreeNodeItem({
|
|
|
9030
9056
|
const nodeId = String(node.id);
|
|
9031
9057
|
const hasChildren = !!node.children?.length;
|
|
9032
9058
|
const isExpanded = isFiltering || expanded.has(nodeId);
|
|
9033
|
-
const state = getNodeState(node, selected);
|
|
9059
|
+
const state = allowChildSelection ? getNodeState(node, selected) : selected.has(nodeId) ? "checked" : "unchecked";
|
|
9034
9060
|
return /* @__PURE__ */ React106.createElement("div", { className: "rf-tsn" }, /* @__PURE__ */ React106.createElement(
|
|
9035
9061
|
"div",
|
|
9036
9062
|
{
|
|
@@ -9050,16 +9076,8 @@ function TreeNodeItem({
|
|
|
9050
9076
|
},
|
|
9051
9077
|
isExpanded ? /* @__PURE__ */ React106.createElement(ChevronDown2, { size: 14 }) : /* @__PURE__ */ React106.createElement(ChevronRight2, { size: 14 })
|
|
9052
9078
|
) : /* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__expand-ph" }),
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
{
|
|
9056
|
-
className: `rf-tsn__cb${state === "checked" ? " rf-tsn__cb--checked" : state === "partial" ? " rf-tsn__cb--partial" : ""}`
|
|
9057
|
-
},
|
|
9058
|
-
state === "checked" && /* @__PURE__ */ React106.createElement(Check, { size: 10, strokeWidth: 3 }),
|
|
9059
|
-
state === "partial" && /* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__cb-dash" })
|
|
9060
|
-
),
|
|
9061
|
-
selectionMode === "single" && /* @__PURE__ */ React106.createElement("span", { className: `rf-tsn__radio${state === "checked" ? " rf-tsn__radio--checked" : ""}` }),
|
|
9062
|
-
/* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__label" }, node.label)
|
|
9079
|
+
/* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__label" }, node.label),
|
|
9080
|
+
/* @__PURE__ */ React106.createElement("span", { className: "rf-tsn__check", "aria-hidden": "true" }, state === "partial" ? /* @__PURE__ */ React106.createElement(Minus, { size: 13, strokeWidth: 2.5 }) : /* @__PURE__ */ React106.createElement(Check, { size: 13, strokeWidth: 2.5 }))
|
|
9063
9081
|
), hasChildren && isExpanded && /* @__PURE__ */ React106.createElement("div", null, node.children.map((child) => /* @__PURE__ */ React106.createElement(
|
|
9064
9082
|
TreeNodeItem,
|
|
9065
9083
|
{
|
|
@@ -9069,6 +9087,7 @@ function TreeNodeItem({
|
|
|
9069
9087
|
selected,
|
|
9070
9088
|
expanded,
|
|
9071
9089
|
selectionMode,
|
|
9090
|
+
allowChildSelection,
|
|
9072
9091
|
onToggleExpand,
|
|
9073
9092
|
onSelect,
|
|
9074
9093
|
isFiltering
|
|
@@ -9082,6 +9101,7 @@ function TreeSelect({
|
|
|
9082
9101
|
onNodeSelect,
|
|
9083
9102
|
onNodeUnselect,
|
|
9084
9103
|
selectionMode = "single",
|
|
9104
|
+
allowChildSelection = false,
|
|
9085
9105
|
placeholder = "Select",
|
|
9086
9106
|
filter = false,
|
|
9087
9107
|
filterInputAutoFocus = false,
|
|
@@ -9202,15 +9222,25 @@ function TreeSelect({
|
|
|
9202
9222
|
const handleSelect = (node) => {
|
|
9203
9223
|
const nodeId = String(node.id);
|
|
9204
9224
|
if (isMultiple) {
|
|
9205
|
-
const state = getNodeState(node, selectedSet);
|
|
9206
|
-
const descendants = collectDescendants(node);
|
|
9207
9225
|
const newSet = new Set(selectedSet);
|
|
9208
|
-
if (
|
|
9209
|
-
|
|
9210
|
-
|
|
9226
|
+
if (allowChildSelection) {
|
|
9227
|
+
const state = getNodeState(node, selectedSet);
|
|
9228
|
+
const descendants = collectDescendants(node);
|
|
9229
|
+
if (state === "checked" || state === "partial") {
|
|
9230
|
+
descendants.forEach((id) => newSet.delete(id));
|
|
9231
|
+
onNodeUnselect?.({ node });
|
|
9232
|
+
} else {
|
|
9233
|
+
descendants.forEach((id) => newSet.add(id));
|
|
9234
|
+
onNodeSelect?.({ node });
|
|
9235
|
+
}
|
|
9211
9236
|
} else {
|
|
9212
|
-
|
|
9213
|
-
|
|
9237
|
+
if (newSet.has(nodeId)) {
|
|
9238
|
+
newSet.delete(nodeId);
|
|
9239
|
+
onNodeUnselect?.({ node });
|
|
9240
|
+
} else {
|
|
9241
|
+
newSet.add(nodeId);
|
|
9242
|
+
onNodeSelect?.({ node });
|
|
9243
|
+
}
|
|
9214
9244
|
}
|
|
9215
9245
|
onChange?.({ value: setToRecord(newSet) });
|
|
9216
9246
|
} else {
|
|
@@ -9243,7 +9273,7 @@ function TreeSelect({
|
|
|
9243
9273
|
onNodeUnselect?.({ node });
|
|
9244
9274
|
};
|
|
9245
9275
|
const filteredTree = filterTree(options, filterQuery);
|
|
9246
|
-
const tagNodes = isMultiple ? getTopLevelSelected(options, selectedSet) : value != null ? findNodeById(options, String(value)) ? [findNodeById(options, String(value))] : [] : [];
|
|
9276
|
+
const tagNodes = isMultiple ? allowChildSelection ? getTopLevelSelected(options, selectedSet) : getAllSelected(options, selectedSet) : value != null ? findNodeById(options, String(value)) ? [findNodeById(options, String(value))] : [] : [];
|
|
9247
9277
|
const hasValue = tagNodes.length > 0;
|
|
9248
9278
|
const isFloating = open || hasValue || focused;
|
|
9249
9279
|
const rootClasses = [
|
|
@@ -9341,6 +9371,7 @@ function TreeSelect({
|
|
|
9341
9371
|
selected: selectedSet,
|
|
9342
9372
|
expanded: expandedKeys,
|
|
9343
9373
|
selectionMode,
|
|
9374
|
+
allowChildSelection,
|
|
9344
9375
|
onToggleExpand: handleToggleExpand,
|
|
9345
9376
|
onSelect: handleSelect,
|
|
9346
9377
|
isFiltering: !!filterQuery
|
|
@@ -9474,7 +9505,9 @@ function SmartSelect({
|
|
|
9474
9505
|
value,
|
|
9475
9506
|
onChange,
|
|
9476
9507
|
onSearchChange,
|
|
9508
|
+
searchResults = [],
|
|
9477
9509
|
debounceMs = 300,
|
|
9510
|
+
searchThreshold = 10,
|
|
9478
9511
|
getOptionLabel,
|
|
9479
9512
|
getOptionValue,
|
|
9480
9513
|
getOptionSubLabel,
|
|
@@ -9512,14 +9545,20 @@ function SmartSelect({
|
|
|
9512
9545
|
return flattenTree(options, getOptionChildren);
|
|
9513
9546
|
}, [options, getOptionChildren]);
|
|
9514
9547
|
const flatOptionsList = useMemo3(() => flatItems.map((f) => f.option), [flatItems]);
|
|
9548
|
+
const displayOptions = useMemo3(() => {
|
|
9549
|
+
if (!searchResults.length) return flatOptionsList;
|
|
9550
|
+
const localKeys = new Set(flatOptionsList.map((o) => getValue(o)));
|
|
9551
|
+
const serverOnly = searchResults.filter((o) => !localKeys.has(getValue(o)));
|
|
9552
|
+
return [...flatOptionsList, ...serverOnly];
|
|
9553
|
+
}, [flatOptionsList, searchResults, getValue]);
|
|
9515
9554
|
const depthMap = useMemo3(() => {
|
|
9516
9555
|
const map = /* @__PURE__ */ new Map();
|
|
9517
9556
|
flatItems.forEach(({ option, depth }) => map.set(getValue(option), depth));
|
|
9518
9557
|
return map;
|
|
9519
9558
|
}, [flatItems, getValue]);
|
|
9520
9559
|
const lookup = useMemo3(
|
|
9521
|
-
() => buildLookup(
|
|
9522
|
-
[
|
|
9560
|
+
() => buildLookup(displayOptions, getOptionChildren, getValue),
|
|
9561
|
+
[displayOptions, getOptionChildren, getValue]
|
|
9523
9562
|
);
|
|
9524
9563
|
const selectedKeys = useMemo3(() => {
|
|
9525
9564
|
if (multiple) {
|
|
@@ -9531,21 +9570,27 @@ function SmartSelect({
|
|
|
9531
9570
|
if (!onSearchChange) return;
|
|
9532
9571
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
9533
9572
|
if (!inputValue) {
|
|
9534
|
-
onSearchChange("");
|
|
9573
|
+
onSearchChange("", 0);
|
|
9535
9574
|
return;
|
|
9536
9575
|
}
|
|
9537
|
-
const
|
|
9538
|
-
|
|
9539
|
-
)
|
|
9540
|
-
|
|
9576
|
+
const q = inputValue.toLowerCase();
|
|
9577
|
+
let localCount = 0;
|
|
9578
|
+
for (const opt of flatOptionsList) {
|
|
9579
|
+
if (getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)) {
|
|
9580
|
+
localCount++;
|
|
9581
|
+
if (localCount >= searchThreshold) break;
|
|
9582
|
+
}
|
|
9583
|
+
}
|
|
9584
|
+
if (localCount >= searchThreshold) return;
|
|
9585
|
+
const needed = searchThreshold - localCount;
|
|
9541
9586
|
if (debounceMs <= 0) {
|
|
9542
|
-
onSearchChange(inputValue);
|
|
9587
|
+
onSearchChange(inputValue, needed);
|
|
9543
9588
|
} else {
|
|
9544
9589
|
debounceTimer.current = setTimeout(() => {
|
|
9545
|
-
onSearchChange(inputValue);
|
|
9590
|
+
onSearchChange(inputValue, needed);
|
|
9546
9591
|
}, debounceMs);
|
|
9547
9592
|
}
|
|
9548
|
-
}, [onSearchChange, debounceMs, flatOptionsList, getOptionLabel, getOptionSubLabel]);
|
|
9593
|
+
}, [onSearchChange, debounceMs, searchThreshold, flatOptionsList, getOptionLabel, getOptionSubLabel]);
|
|
9549
9594
|
const handleChange = useCallback11((_, newValue) => {
|
|
9550
9595
|
if (!multiple || !allowChildNodesSelection || !getOptionChildren) {
|
|
9551
9596
|
onChange?.(newValue);
|
|
@@ -9597,34 +9642,28 @@ function SmartSelect({
|
|
|
9597
9642
|
{
|
|
9598
9643
|
key,
|
|
9599
9644
|
...rest,
|
|
9600
|
-
className:
|
|
9645
|
+
className: [
|
|
9646
|
+
muiClass,
|
|
9647
|
+
"rf-select__option",
|
|
9648
|
+
isSelected ? "rf-select__option--selected" : ""
|
|
9649
|
+
].filter(Boolean).join(" "),
|
|
9601
9650
|
style: {
|
|
9602
9651
|
...muiStyle,
|
|
9603
|
-
display: "flex",
|
|
9604
|
-
alignItems: "center",
|
|
9605
|
-
gap: 10,
|
|
9606
|
-
padding: "8px 16px",
|
|
9607
9652
|
paddingLeft: 16 + depth * 20,
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
cursor: "pointer",
|
|
9611
|
-
userSelect: "none",
|
|
9612
|
-
minHeight: 40,
|
|
9613
|
-
boxSizing: "border-box",
|
|
9614
|
-
fontWeight: isSelected ? 500 : void 0,
|
|
9615
|
-
backgroundColor: isSelected ? "rgba(164,27,6,0.08)" : void 0,
|
|
9616
|
-
listStyle: "none"
|
|
9653
|
+
listStyle: "none",
|
|
9654
|
+
alignItems: subLabel ? "flex-start" : void 0
|
|
9617
9655
|
}
|
|
9618
9656
|
},
|
|
9619
|
-
/* @__PURE__ */ React108.createElement(
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
9657
|
+
/* @__PURE__ */ React108.createElement(
|
|
9658
|
+
"span",
|
|
9659
|
+
{
|
|
9660
|
+
className: "rf-select__option-label",
|
|
9661
|
+
style: subLabel ? { display: "flex", flexDirection: "column", whiteSpace: "normal" } : void 0
|
|
9662
|
+
},
|
|
9663
|
+
/* @__PURE__ */ React108.createElement("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", lineHeight: 1.3 } }, getOptionLabel(option)),
|
|
9664
|
+
subLabel && /* @__PURE__ */ React108.createElement("span", { style: { fontSize: "0.75rem", color: "var(--text-secondary)", lineHeight: 1.3, marginTop: 1 } }, subLabel)
|
|
9665
|
+
),
|
|
9666
|
+
/* @__PURE__ */ React108.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ React108.createElement(CheckIcon3, null))
|
|
9628
9667
|
);
|
|
9629
9668
|
}, [depthMap, getValue, getOptionLabel, getOptionSubLabel, selectedKeys]);
|
|
9630
9669
|
const computedFilterOptions = useCallback11((opts, inputValue) => {
|
|
@@ -9632,10 +9671,12 @@ function SmartSelect({
|
|
|
9632
9671
|
if (multiple) {
|
|
9633
9672
|
const selected = opts.filter((o) => selectedKeys.has(getValue(o)));
|
|
9634
9673
|
const unselected = opts.filter((o) => !selectedKeys.has(getValue(o)));
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9674
|
+
if (!inputValue) return [...selected, ...unselected];
|
|
9675
|
+
const q2 = inputValue.toLowerCase();
|
|
9676
|
+
const filteredUnselected = unselected.filter(
|
|
9677
|
+
(opt) => getOptionLabel(opt).toLowerCase().includes(q2) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q2)
|
|
9678
|
+
).slice(0, searchThreshold);
|
|
9679
|
+
return [...selected, ...filteredUnselected];
|
|
9639
9680
|
}
|
|
9640
9681
|
if (value != null) {
|
|
9641
9682
|
const selectedLabel = getOptionLabel(value);
|
|
@@ -9651,12 +9692,12 @@ function SmartSelect({
|
|
|
9651
9692
|
const q = inputValue.toLowerCase();
|
|
9652
9693
|
return opts.filter(
|
|
9653
9694
|
(opt) => getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)
|
|
9654
|
-
);
|
|
9655
|
-
}, [filterOptionsProp, multiple, selectedKeys, getValue, getOptionLabel, getOptionSubLabel, value]);
|
|
9695
|
+
).slice(0, searchThreshold);
|
|
9696
|
+
}, [filterOptionsProp, multiple, selectedKeys, getValue, getOptionLabel, getOptionSubLabel, value, searchThreshold]);
|
|
9656
9697
|
return /* @__PURE__ */ React108.createElement(
|
|
9657
9698
|
Autocomplete,
|
|
9658
9699
|
{
|
|
9659
|
-
options:
|
|
9700
|
+
options: displayOptions,
|
|
9660
9701
|
value: value ?? (multiple ? [] : null),
|
|
9661
9702
|
onChange: handleChange,
|
|
9662
9703
|
onInputChange: handleInputChange,
|