@canvas-components/react-components 0.3.8 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +521 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -4
- package/dist/index.d.ts +43 -4
- package/dist/index.js +521 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -495,9 +495,13 @@ function ReactPopup(props) {
|
|
|
495
495
|
)
|
|
496
496
|
}
|
|
497
497
|
),
|
|
498
|
-
|
|
498
|
+
resolvePopupContainer(anchorRef?.current)
|
|
499
499
|
);
|
|
500
500
|
}
|
|
501
|
+
function resolvePopupContainer(anchor) {
|
|
502
|
+
const fullscreenElement = document.fullscreenElement;
|
|
503
|
+
return fullscreenElement instanceof HTMLElement && (!anchor || fullscreenElement.contains(anchor)) ? fullscreenElement : document.body;
|
|
504
|
+
}
|
|
501
505
|
function resolvePopupPosition(params) {
|
|
502
506
|
const {
|
|
503
507
|
anchor,
|
|
@@ -7260,8 +7264,84 @@ function clamp3(value, min, max) {
|
|
|
7260
7264
|
return Math.min(Math.max(value, min), max);
|
|
7261
7265
|
}
|
|
7262
7266
|
|
|
7267
|
+
// src/components/cascader/cascader-selection.ts
|
|
7268
|
+
function createCascaderSelection(options) {
|
|
7269
|
+
const entries = /* @__PURE__ */ new Map();
|
|
7270
|
+
const visit = (items, parents, disabled = false) => items.map((item) => {
|
|
7271
|
+
const nodes = [...parents, item];
|
|
7272
|
+
const path = nodes.map((node) => node.value);
|
|
7273
|
+
const key = JSON.stringify(path);
|
|
7274
|
+
const entry = {
|
|
7275
|
+
path,
|
|
7276
|
+
children: [],
|
|
7277
|
+
leaves: [],
|
|
7278
|
+
disabled: disabled || !!item.disabled
|
|
7279
|
+
};
|
|
7280
|
+
entries.set(key, entry);
|
|
7281
|
+
entry.children = visit(item.children ?? [], nodes, entry.disabled);
|
|
7282
|
+
entry.leaves = entry.disabled ? [] : entry.children.length ? entry.children.flatMap((child) => child.leaves) : [key];
|
|
7283
|
+
return entry;
|
|
7284
|
+
});
|
|
7285
|
+
const roots = visit(options, []);
|
|
7286
|
+
const expand = (value) => {
|
|
7287
|
+
const checked = /* @__PURE__ */ new Set();
|
|
7288
|
+
const preserved = /* @__PURE__ */ new Map();
|
|
7289
|
+
for (const path of value) {
|
|
7290
|
+
const key = JSON.stringify(path);
|
|
7291
|
+
const entry = entries.get(key);
|
|
7292
|
+
if (!entry || entry.disabled || !entry.leaves.length)
|
|
7293
|
+
preserved.set(key, path);
|
|
7294
|
+
else entry.leaves.forEach((leaf) => checked.add(leaf));
|
|
7295
|
+
}
|
|
7296
|
+
return { checked, preserved };
|
|
7297
|
+
};
|
|
7298
|
+
const state = (entry, checked) => {
|
|
7299
|
+
const count = entry?.leaves.filter((leaf) => checked.has(leaf)).length ?? 0;
|
|
7300
|
+
return {
|
|
7301
|
+
checked: count > 0 && count === entry?.leaves.length,
|
|
7302
|
+
indeterminate: count > 0 && count < (entry?.leaves.length ?? 0)
|
|
7303
|
+
};
|
|
7304
|
+
};
|
|
7305
|
+
const collect = (checked, preserved, strategy) => {
|
|
7306
|
+
const paths = [];
|
|
7307
|
+
const walk = (entry) => {
|
|
7308
|
+
if (entry.disabled) return;
|
|
7309
|
+
if (state(entry, checked).checked && (strategy === "SHOW_PARENT" || !entry.children.length))
|
|
7310
|
+
paths.push(entry.path);
|
|
7311
|
+
else entry.children.forEach(walk);
|
|
7312
|
+
};
|
|
7313
|
+
roots.forEach(walk);
|
|
7314
|
+
return [...paths, ...preserved.values()];
|
|
7315
|
+
};
|
|
7316
|
+
return {
|
|
7317
|
+
/** 归一化回填值,去重并应用父级/末级策略。 */
|
|
7318
|
+
normalize(value, strategy) {
|
|
7319
|
+
const { checked, preserved } = expand(value);
|
|
7320
|
+
return collect(checked, preserved, strategy);
|
|
7321
|
+
},
|
|
7322
|
+
/** 计算某一路径的全选和半选状态。 */
|
|
7323
|
+
getState(value, path) {
|
|
7324
|
+
const { checked, preserved } = expand(value);
|
|
7325
|
+
if (preserved.has(JSON.stringify(path)))
|
|
7326
|
+
return { checked: true, indeterminate: false };
|
|
7327
|
+
return state(entries.get(JSON.stringify(path)), checked);
|
|
7328
|
+
},
|
|
7329
|
+
/** 切换某个节点以及全部可用后代,不修改入参。 */
|
|
7330
|
+
toggle(value, path, strategy) {
|
|
7331
|
+
const entry = entries.get(JSON.stringify(path));
|
|
7332
|
+
if (!entry || entry.disabled || !entry.leaves.length) return value;
|
|
7333
|
+
const { checked, preserved } = expand(value);
|
|
7334
|
+
const remove = state(entry, checked).checked;
|
|
7335
|
+
entry.leaves.forEach(
|
|
7336
|
+
(leaf) => remove ? checked.delete(leaf) : checked.add(leaf)
|
|
7337
|
+
);
|
|
7338
|
+
return collect(checked, preserved, strategy);
|
|
7339
|
+
}
|
|
7340
|
+
};
|
|
7341
|
+
}
|
|
7342
|
+
|
|
7263
7343
|
// src/components/cascader/style.css
|
|
7264
|
-
styleInject('@import "../../styles/variables.css";\n.canvas-react-cascader {\n width: 100%;\n min-width: 0;\n}\n.canvas-react-cascader > .canvas-react-input-affix-wrapper {\n width: 100%;\n}\n.canvas-react-cascader-menus {\n display: flex;\n max-width: calc(100vw - 24px);\n overflow: auto;\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n}\n.canvas-react-cascader-menu {\n flex: 0 0 auto;\n min-width: 120px;\n max-width: 320px;\n max-height: min(256px, calc(100vh - 48px));\n overflow: auto;\n padding: 4px;\n}\n.canvas-react-cascader-menu + .canvas-react-cascader-menu {\n border-left: 1px solid var(--canvas-react-color-border);\n}\n.canvas-react-cascader-option {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 20px;\n padding: 5px 10px;\n line-height: 22px;\n border-radius: var(--canvas-react-radius-sm);\n cursor: pointer;\n white-space: nowrap;\n}\n.canvas-react-cascader-option[aria-selected=true] {\n color: var(--canvas-react-color-primary);\n background: var(--canvas-react-color-bg-active);\n}\n.canvas-react-cascader-option[data-active=true] {\n background: var(--canvas-react-color-bg-hover, #f5f5f5);\n}\n.canvas-react-cascader-option[aria-disabled=true] {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.canvas-react-cascader-empty {\n padding: 8px 10px;\n color: var(--canvas-react-color-text-muted);\n}\n.canvas-react-cascader-chevron {\n width: 7px;\n height: 7px;\n flex: 0 0 auto;\n margin-left: 8px;\n border-top: 1.5px solid #9ca3af;\n border-right: 1.5px solid #9ca3af;\n transform: rotate(45deg);\n transform-origin: center;\n transition: transform 0.18s ease, border-color 0.18s ease;\n}\n.canvas-react-cascader-option:not([aria-disabled=true]):hover .canvas-react-cascader-chevron,\n.canvas-react-cascader-option[
|
|
7344
|
+
styleInject('@import "../../styles/variables.css";\n.canvas-react-cascader {\n width: 100%;\n min-width: 0;\n}\n.canvas-react-cascader > .canvas-react-input-affix-wrapper {\n width: 100%;\n}\n.canvas-react-cascader-menus {\n display: flex;\n max-width: calc(100vw - 24px);\n overflow: auto;\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n}\n.canvas-react-cascader-menu {\n flex: 0 0 auto;\n min-width: 120px;\n max-width: 320px;\n max-height: min(256px, calc(100vh - 48px));\n overflow: auto;\n padding: 4px;\n}\n.canvas-react-cascader-menu + .canvas-react-cascader-menu {\n border-left: 1px solid var(--canvas-react-color-border);\n}\n.canvas-react-cascader-option {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 20px;\n padding: 5px 10px;\n line-height: 22px;\n border-radius: var(--canvas-react-radius-sm);\n cursor: pointer;\n white-space: nowrap;\n}\n.canvas-react-cascader-check {\n display: inline-flex;\n flex: 0 0 auto;\n margin-right: -12px;\n}\n.canvas-react-cascader-check > * {\n pointer-events: none;\n}\n.canvas-react-cascader-option > span:not(.canvas-react-cascader-check):not(.canvas-react-cascader-chevron) {\n flex: 1;\n}\n.canvas-react-cascader-option[aria-selected=true] {\n color: var(--canvas-react-color-primary);\n background: var(--canvas-react-color-bg-active);\n}\n.canvas-react-cascader-option[data-active=true] {\n background: var(--canvas-react-color-bg-hover, #f5f5f5);\n}\n.canvas-react-cascader-option[aria-disabled=true] {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.canvas-react-cascader-empty {\n padding: 8px 10px;\n color: var(--canvas-react-color-text-muted);\n}\n.canvas-react-cascader-chevron {\n width: 7px;\n height: 7px;\n flex: 0 0 auto;\n margin-left: 8px;\n border-top: 1.5px solid #9ca3af;\n border-right: 1.5px solid #9ca3af;\n transform: rotate(45deg);\n transform-origin: center;\n transition: transform 0.18s ease, border-color 0.18s ease;\n}\n.canvas-react-cascader-option:not([aria-disabled=true]):hover .canvas-react-cascader-chevron,\n.canvas-react-cascader-option[data-expanded=true] .canvas-react-cascader-chevron {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n');
|
|
7265
7345
|
function resolvePath(options, value) {
|
|
7266
7346
|
const path = [];
|
|
7267
7347
|
for (const part of value) {
|
|
@@ -7279,6 +7359,8 @@ function ReactCascader(props) {
|
|
|
7279
7359
|
value = EMPTY_VALUE,
|
|
7280
7360
|
options = EMPTY_OPTIONS,
|
|
7281
7361
|
showSearch = false,
|
|
7362
|
+
multiple = false,
|
|
7363
|
+
showCheckedStrategy = "SHOW_PARENT",
|
|
7282
7364
|
changeOnSelect = false,
|
|
7283
7365
|
expandTrigger = "click",
|
|
7284
7366
|
displayRender,
|
|
@@ -7296,7 +7378,13 @@ function ReactCascader(props) {
|
|
|
7296
7378
|
const inputRef = React.useRef(null);
|
|
7297
7379
|
const popupRef = React.useRef(null);
|
|
7298
7380
|
const popupId = React.useId();
|
|
7299
|
-
const
|
|
7381
|
+
const selection = React.useMemo(() => createCascaderSelection(options), [options]);
|
|
7382
|
+
const singleValue = multiple ? EMPTY_VALUE : value;
|
|
7383
|
+
const multipleValue = multiple ? value.filter(Array.isArray) : [];
|
|
7384
|
+
const selected = React.useMemo(
|
|
7385
|
+
() => resolvePath(options, singleValue),
|
|
7386
|
+
[options, singleValue]
|
|
7387
|
+
);
|
|
7300
7388
|
const [path, setPath] = React.useState(selected);
|
|
7301
7389
|
const [open, setOpen] = React.useState(false);
|
|
7302
7390
|
const [keyword, setKeyword] = React.useState("");
|
|
@@ -7306,10 +7394,14 @@ function ReactCascader(props) {
|
|
|
7306
7394
|
React.useEffect(() => {
|
|
7307
7395
|
setPath(selected);
|
|
7308
7396
|
}, [selected]);
|
|
7309
|
-
const
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7397
|
+
const displayPath = (valuePath) => {
|
|
7398
|
+
const nodes = resolvePath(options, valuePath);
|
|
7399
|
+
const labels = valuePath.map(
|
|
7400
|
+
(part, index) => nodes[index]?.label ?? String(part)
|
|
7401
|
+
);
|
|
7402
|
+
return displayRender?.(labels, nodes) ?? labels.join(" / ");
|
|
7403
|
+
};
|
|
7404
|
+
const text = multiple ? selection.normalize(multipleValue, showCheckedStrategy).map(displayPath).join("\uFF1B") : displayPath(singleValue);
|
|
7313
7405
|
const columns = [options];
|
|
7314
7406
|
for (const item of path) {
|
|
7315
7407
|
if (!item.children?.length) break;
|
|
@@ -7323,21 +7415,37 @@ function ReactCascader(props) {
|
|
|
7323
7415
|
for (const item of items) {
|
|
7324
7416
|
if (item.disabled) continue;
|
|
7325
7417
|
const next = [...parents, item];
|
|
7326
|
-
if ((!item.children?.length || changeOnSelect) && next.map((part) => part.label).join(" / ").toLocaleLowerCase().includes(keyword.trim().toLocaleLowerCase()))
|
|
7418
|
+
if ((!item.children?.length || changeOnSelect || multiple) && next.map((part) => part.label).join(" / ").toLocaleLowerCase().includes(keyword.trim().toLocaleLowerCase()))
|
|
7327
7419
|
matches.push(next);
|
|
7328
7420
|
if (item.children?.length) visit(item.children, next);
|
|
7329
7421
|
}
|
|
7330
7422
|
};
|
|
7331
7423
|
visit(options, []);
|
|
7332
7424
|
return matches;
|
|
7333
|
-
}, [options, keyword, changeOnSelect]);
|
|
7425
|
+
}, [options, keyword, changeOnSelect, multiple]);
|
|
7334
7426
|
React.useEffect(() => {
|
|
7335
7427
|
popupRef.current?.querySelector("[data-active='true']")?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
|
|
7336
7428
|
}, [focus, open]);
|
|
7429
|
+
const toggle = (next, trigger) => {
|
|
7430
|
+
const updated = selection.toggle(
|
|
7431
|
+
multipleValue,
|
|
7432
|
+
next.map((item) => item.value),
|
|
7433
|
+
showCheckedStrategy
|
|
7434
|
+
);
|
|
7435
|
+
onChange?.(
|
|
7436
|
+
updated,
|
|
7437
|
+
updated.map((parts) => resolvePath(options, parts)),
|
|
7438
|
+
{ trigger, complete: false }
|
|
7439
|
+
);
|
|
7440
|
+
};
|
|
7337
7441
|
const choose = (next, trigger, fromSearch = false) => {
|
|
7338
7442
|
const item = next[next.length - 1];
|
|
7339
7443
|
if (!item || next.some((option) => option.disabled)) return;
|
|
7340
7444
|
setPath(next);
|
|
7445
|
+
if (multiple) {
|
|
7446
|
+
if (!item.children?.length || fromSearch) toggle(next, trigger);
|
|
7447
|
+
return;
|
|
7448
|
+
}
|
|
7341
7449
|
const complete = !item.children?.length || fromSearch;
|
|
7342
7450
|
if (complete || changeOnSelect)
|
|
7343
7451
|
onChange?.(
|
|
@@ -7354,7 +7462,7 @@ function ReactCascader(props) {
|
|
|
7354
7462
|
const show = () => {
|
|
7355
7463
|
if (!interactive) return;
|
|
7356
7464
|
setOpen(true);
|
|
7357
|
-
setPath(selected);
|
|
7465
|
+
if (!multiple) setPath(selected);
|
|
7358
7466
|
};
|
|
7359
7467
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7360
7468
|
"div",
|
|
@@ -7406,7 +7514,7 @@ function ReactCascader(props) {
|
|
|
7406
7514
|
setTyping(false);
|
|
7407
7515
|
return;
|
|
7408
7516
|
}
|
|
7409
|
-
if (![
|
|
7517
|
+
if (!(multiple && event.key === " " && (!showSearch || !typing)) && ![
|
|
7410
7518
|
"ArrowDown",
|
|
7411
7519
|
"ArrowUp",
|
|
7412
7520
|
"ArrowRight",
|
|
@@ -7439,7 +7547,9 @@ function ReactCascader(props) {
|
|
|
7439
7547
|
const item = items[focus.index];
|
|
7440
7548
|
if (!item || item.disabled) return;
|
|
7441
7549
|
const next = searching ? results[focus.index] : [...path.slice(0, column), item];
|
|
7442
|
-
if (event.key === "Enter"
|
|
7550
|
+
if (multiple && (event.key === "Enter" || event.key === " "))
|
|
7551
|
+
toggle(next, "keyboard");
|
|
7552
|
+
else if (event.key === "Enter") choose(next, "keyboard", searching);
|
|
7443
7553
|
else if (event.key !== "ArrowRight") return;
|
|
7444
7554
|
if (!searching && item.children?.length) {
|
|
7445
7555
|
setPath(next);
|
|
@@ -7536,20 +7646,26 @@ function ReactCascader(props) {
|
|
|
7536
7646
|
"div",
|
|
7537
7647
|
{
|
|
7538
7648
|
role: "listbox",
|
|
7649
|
+
"aria-multiselectable": multiple || void 0,
|
|
7539
7650
|
"aria-label": searching ? "\u641C\u7D22\u7ED3\u679C" : `\u7B2C ${column + 1} \u7EA7\u9009\u9879`,
|
|
7540
7651
|
className: "canvas-react-cascader-menu",
|
|
7541
7652
|
children: items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-react-cascader-empty", children: "\u6682\u65E0\u6570\u636E" }) : items.map((item, index) => {
|
|
7542
7653
|
const next = searching ? results[index] : [...path.slice(0, column), item];
|
|
7543
7654
|
const active = focus.column === column && focus.index === index;
|
|
7655
|
+
const checkedState = multiple ? selection.getState(
|
|
7656
|
+
multipleValue,
|
|
7657
|
+
next.map((node) => node.value)
|
|
7658
|
+
) : { checked: false, indeterminate: false };
|
|
7544
7659
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7545
7660
|
"div",
|
|
7546
7661
|
{
|
|
7547
7662
|
id: `${popupId}-${column}-${index}`,
|
|
7548
7663
|
role: "option",
|
|
7549
|
-
"aria-selected": path[column] === item,
|
|
7664
|
+
"aria-selected": multiple ? checkedState.checked : path[column] === item,
|
|
7550
7665
|
"aria-disabled": !!item.disabled,
|
|
7551
7666
|
"data-active": active,
|
|
7552
7667
|
className: "canvas-react-cascader-option",
|
|
7668
|
+
"data-expanded": !!item.children?.length && path[column] === item,
|
|
7553
7669
|
onMouseDown: (event) => event.preventDefault(),
|
|
7554
7670
|
onMouseEnter: () => {
|
|
7555
7671
|
if (item.disabled) return;
|
|
@@ -7562,6 +7678,32 @@ function ReactCascader(props) {
|
|
|
7562
7678
|
choose(next, "mouse", searching);
|
|
7563
7679
|
},
|
|
7564
7680
|
children: [
|
|
7681
|
+
multiple ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7682
|
+
"span",
|
|
7683
|
+
{
|
|
7684
|
+
className: "canvas-react-cascader-check",
|
|
7685
|
+
role: "checkbox",
|
|
7686
|
+
"aria-checked": checkedState.indeterminate ? "mixed" : checkedState.checked,
|
|
7687
|
+
"aria-label": `\u9009\u62E9 ${next.map((node) => node.label).join(" / ")}`,
|
|
7688
|
+
"aria-disabled": !!item.disabled,
|
|
7689
|
+
onClick: (event) => {
|
|
7690
|
+
event.preventDefault();
|
|
7691
|
+
event.stopPropagation();
|
|
7692
|
+
if (!item.disabled) toggle(next, "mouse");
|
|
7693
|
+
},
|
|
7694
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7695
|
+
ReactCheckbox,
|
|
7696
|
+
{
|
|
7697
|
+
tabIndex: -1,
|
|
7698
|
+
"aria-hidden": "true",
|
|
7699
|
+
readOnly: true,
|
|
7700
|
+
checked: checkedState.checked,
|
|
7701
|
+
indeterminate: checkedState.indeterminate,
|
|
7702
|
+
disabled: item.disabled
|
|
7703
|
+
}
|
|
7704
|
+
)
|
|
7705
|
+
}
|
|
7706
|
+
) : null,
|
|
7565
7707
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: searching ? next.map((part) => part.label).join(" / ") : item.label }),
|
|
7566
7708
|
!searching && item.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7567
7709
|
"span",
|
|
@@ -7586,6 +7728,371 @@ function ReactCascader(props) {
|
|
|
7586
7728
|
}
|
|
7587
7729
|
);
|
|
7588
7730
|
}
|
|
7731
|
+
|
|
7732
|
+
// src/components/tree-select/tree-select-utils.ts
|
|
7733
|
+
function createTreeSelectIndex(treeData) {
|
|
7734
|
+
const entries = [];
|
|
7735
|
+
const byValue = /* @__PURE__ */ new Map();
|
|
7736
|
+
const visit = (nodes, parents) => {
|
|
7737
|
+
for (const node of nodes) {
|
|
7738
|
+
const entry = {
|
|
7739
|
+
node,
|
|
7740
|
+
key: node.key ?? node.value,
|
|
7741
|
+
parents,
|
|
7742
|
+
depth: parents.length
|
|
7743
|
+
};
|
|
7744
|
+
entries.push(entry);
|
|
7745
|
+
byValue.set(node.value, entry);
|
|
7746
|
+
if (node.children?.length) visit(node.children, [...parents, entry]);
|
|
7747
|
+
}
|
|
7748
|
+
};
|
|
7749
|
+
visit(treeData, []);
|
|
7750
|
+
return { entries, byValue };
|
|
7751
|
+
}
|
|
7752
|
+
function normalizeTreeSelectValue(value, multiple) {
|
|
7753
|
+
const values = multiple ? Array.isArray(value) ? value : [] : [value];
|
|
7754
|
+
return [
|
|
7755
|
+
...new Set(
|
|
7756
|
+
values.filter(
|
|
7757
|
+
(part) => typeof part === "string" || typeof part === "number"
|
|
7758
|
+
)
|
|
7759
|
+
)
|
|
7760
|
+
];
|
|
7761
|
+
}
|
|
7762
|
+
|
|
7763
|
+
// src/components/tree-select/style.css
|
|
7764
|
+
styleInject('@import "../../styles/variables.css";\n.canvas-react-tree-select {\n width: 100%;\n min-width: 0;\n}\n.canvas-react-tree-select-tree {\n max-height: min(280px, calc(100vh - 48px));\n overflow: auto;\n padding: 4px;\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n}\n.canvas-react-tree-select-node {\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: 30px;\n padding: 2px 10px 2px 6px;\n box-sizing: border-box;\n line-height: 22px;\n border-radius: var(--canvas-react-radius-sm);\n cursor: pointer;\n}\n.canvas-react-tree-select-node[data-active=true] {\n background: var(--canvas-react-color-bg-hover);\n}\n.canvas-react-tree-select-node[aria-selected=true] {\n background: var(--canvas-react-color-bg-active);\n color: var(--canvas-react-color-primary);\n}\n.canvas-react-tree-select-node[aria-disabled=true] .canvas-react-tree-select-title {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.canvas-react-tree-select-switcher {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 18px;\n width: 18px;\n height: 24px;\n border: 0;\n padding: 0;\n background: transparent;\n cursor: pointer;\n}\n.canvas-react-tree-select-chevron {\n width: 7px;\n height: 7px;\n border-top: 1.5px solid #9ca3af;\n border-right: 1.5px solid #9ca3af;\n transform: rotate(45deg);\n transition: transform 0.18s ease, border-color 0.18s ease;\n pointer-events: none;\n}\n.canvas-react-tree-select-chevron-open {\n transform: rotate(135deg);\n border-color: #6b7280;\n}\n.canvas-react-tree-select-title {\n flex: 1;\n white-space: nowrap;\n}\n.canvas-react-tree-select-check {\n color: var(--canvas-react-color-primary);\n}\n.canvas-react-tree-select-empty {\n padding: 8px 10px;\n color: var(--canvas-react-color-text-muted);\n}\n.canvas-react-tree-select:hover .canvas-react-select-clear,\n.canvas-react-tree-select-open .canvas-react-select-clear,\n.canvas-react-tree-select:focus-within .canvas-react-select-clear {\n opacity: 1;\n pointer-events: auto;\n}\n.canvas-react-tree-select:hover .canvas-react-select-actions-clearable .canvas-react-select-arrow,\n.canvas-react-tree-select-open .canvas-react-select-actions-clearable .canvas-react-select-arrow,\n.canvas-react-tree-select:focus-within .canvas-react-select-actions-clearable .canvas-react-select-arrow {\n opacity: 0;\n}\n');
|
|
7765
|
+
var EMPTY_TREE = [];
|
|
7766
|
+
function ReactTreeSelect(props) {
|
|
7767
|
+
const {
|
|
7768
|
+
value = null,
|
|
7769
|
+
treeData = EMPTY_TREE,
|
|
7770
|
+
multiple = false,
|
|
7771
|
+
showSearch = multiple,
|
|
7772
|
+
treeDefaultExpandAll = false,
|
|
7773
|
+
treeDefaultExpandedKeys,
|
|
7774
|
+
allowClear = true,
|
|
7775
|
+
onChange,
|
|
7776
|
+
disabled,
|
|
7777
|
+
readOnly,
|
|
7778
|
+
onFocus,
|
|
7779
|
+
onBlur,
|
|
7780
|
+
onClick,
|
|
7781
|
+
onKeyDown,
|
|
7782
|
+
...inputProps
|
|
7783
|
+
} = props;
|
|
7784
|
+
const index = React.useMemo(() => createTreeSelectIndex(treeData), [treeData]);
|
|
7785
|
+
const selected = React.useMemo(
|
|
7786
|
+
() => normalizeTreeSelectValue(value, multiple),
|
|
7787
|
+
[value, multiple]
|
|
7788
|
+
);
|
|
7789
|
+
const selectedSet = React.useMemo(() => new Set(selected), [selected]);
|
|
7790
|
+
const [expanded, setExpanded] = React.useState(
|
|
7791
|
+
() => /* @__PURE__ */ new Set([
|
|
7792
|
+
...treeDefaultExpandAll ? index.entries.filter((entry) => entry.node.children?.length).map((entry) => entry.key) : treeDefaultExpandedKeys ?? [],
|
|
7793
|
+
...selected.flatMap(
|
|
7794
|
+
(part) => index.byValue.get(part)?.parents.map((parent) => parent.key) ?? []
|
|
7795
|
+
)
|
|
7796
|
+
])
|
|
7797
|
+
);
|
|
7798
|
+
const [open, setOpen] = React.useState(false);
|
|
7799
|
+
const [keyword, setKeyword] = React.useState(null);
|
|
7800
|
+
const [active, setActive] = React.useState(
|
|
7801
|
+
selected[0] ?? null
|
|
7802
|
+
);
|
|
7803
|
+
const anchorRef = React.useRef(null);
|
|
7804
|
+
const inputRef = React.useRef(null);
|
|
7805
|
+
const treeRef = React.useRef(null);
|
|
7806
|
+
const treeId = React.useId();
|
|
7807
|
+
const interactive = !disabled && !readOnly;
|
|
7808
|
+
const query = (keyword ?? "").trim().toLocaleLowerCase();
|
|
7809
|
+
const text = selected.map((part) => index.byValue.get(part)?.node.title ?? String(part)).join("\uFF1B");
|
|
7810
|
+
const visible = React.useMemo(() => {
|
|
7811
|
+
if (!query)
|
|
7812
|
+
return index.entries.filter(
|
|
7813
|
+
(entry) => entry.parents.every((parent) => expanded.has(parent.key))
|
|
7814
|
+
);
|
|
7815
|
+
const matches = /* @__PURE__ */ new Set();
|
|
7816
|
+
for (const entry of index.entries) {
|
|
7817
|
+
if (!entry.node.title.toLocaleLowerCase().includes(query)) continue;
|
|
7818
|
+
matches.add(entry);
|
|
7819
|
+
entry.parents.forEach((parent) => matches.add(parent));
|
|
7820
|
+
}
|
|
7821
|
+
return index.entries.filter((entry) => matches.has(entry));
|
|
7822
|
+
}, [index, query, expanded]);
|
|
7823
|
+
React.useEffect(() => {
|
|
7824
|
+
setExpanded((previous) => {
|
|
7825
|
+
const next = new Set(previous);
|
|
7826
|
+
selected.forEach(
|
|
7827
|
+
(part) => index.byValue.get(part)?.parents.forEach((parent) => next.add(parent.key))
|
|
7828
|
+
);
|
|
7829
|
+
return next;
|
|
7830
|
+
});
|
|
7831
|
+
}, [index, selected]);
|
|
7832
|
+
React.useEffect(() => {
|
|
7833
|
+
treeRef.current?.querySelector('[data-active="true"]')?.scrollIntoView?.({ block: "nearest" });
|
|
7834
|
+
}, [active, open]);
|
|
7835
|
+
const expand = (entry, next) => {
|
|
7836
|
+
if (!entry.node.children?.length || query) return;
|
|
7837
|
+
setExpanded((previous) => {
|
|
7838
|
+
const keys = new Set(previous);
|
|
7839
|
+
if (next ?? !keys.has(entry.key)) keys.add(entry.key);
|
|
7840
|
+
else keys.delete(entry.key);
|
|
7841
|
+
return keys;
|
|
7842
|
+
});
|
|
7843
|
+
};
|
|
7844
|
+
const choose = (entry, trigger) => {
|
|
7845
|
+
if (entry.node.disabled) return;
|
|
7846
|
+
if (entry.node.selectable === false) {
|
|
7847
|
+
expand(entry);
|
|
7848
|
+
return;
|
|
7849
|
+
}
|
|
7850
|
+
const next = multiple ? selectedSet.has(entry.node.value) ? selected.filter((part) => part !== entry.node.value) : [...selected, entry.node.value] : [entry.node.value];
|
|
7851
|
+
onChange?.(
|
|
7852
|
+
multiple ? next : entry.node.value,
|
|
7853
|
+
next.flatMap((part) => index.byValue.get(part)?.node ?? []),
|
|
7854
|
+
{ trigger, complete: !multiple }
|
|
7855
|
+
);
|
|
7856
|
+
if (!multiple) {
|
|
7857
|
+
setOpen(false);
|
|
7858
|
+
setKeyword(null);
|
|
7859
|
+
}
|
|
7860
|
+
};
|
|
7861
|
+
const show = () => {
|
|
7862
|
+
if (interactive) setOpen(true);
|
|
7863
|
+
};
|
|
7864
|
+
const activeIndex = visible.findIndex((entry) => entry.node.value === active);
|
|
7865
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7866
|
+
"div",
|
|
7867
|
+
{
|
|
7868
|
+
ref: anchorRef,
|
|
7869
|
+
className: `canvas-react-tree-select${open && interactive ? " canvas-react-tree-select-open" : ""}`,
|
|
7870
|
+
children: [
|
|
7871
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7872
|
+
ReactInput,
|
|
7873
|
+
{
|
|
7874
|
+
...inputProps,
|
|
7875
|
+
ref: inputRef,
|
|
7876
|
+
disabled,
|
|
7877
|
+
readOnly: readOnly || !showSearch,
|
|
7878
|
+
allowClear: false,
|
|
7879
|
+
role: "combobox",
|
|
7880
|
+
"aria-haspopup": "tree",
|
|
7881
|
+
"aria-expanded": open && interactive,
|
|
7882
|
+
"aria-controls": open ? treeId : void 0,
|
|
7883
|
+
"aria-activedescendant": open && activeIndex >= 0 ? `${treeId}-${activeIndex}` : void 0,
|
|
7884
|
+
value: open && keyword !== null ? keyword : text,
|
|
7885
|
+
onFocus: (event) => {
|
|
7886
|
+
show();
|
|
7887
|
+
onFocus?.(event);
|
|
7888
|
+
},
|
|
7889
|
+
onClick: (event) => {
|
|
7890
|
+
show();
|
|
7891
|
+
onClick?.(event);
|
|
7892
|
+
},
|
|
7893
|
+
onBlur: (event) => {
|
|
7894
|
+
setOpen(false);
|
|
7895
|
+
setKeyword(null);
|
|
7896
|
+
onBlur?.(event);
|
|
7897
|
+
},
|
|
7898
|
+
onChange: (event) => {
|
|
7899
|
+
setKeyword(event.target.value);
|
|
7900
|
+
setActive(null);
|
|
7901
|
+
show();
|
|
7902
|
+
},
|
|
7903
|
+
onKeyDown: (event) => {
|
|
7904
|
+
onKeyDown?.(event);
|
|
7905
|
+
if (event.defaultPrevented || !interactive) return;
|
|
7906
|
+
if (event.key === "Escape") {
|
|
7907
|
+
event.preventDefault();
|
|
7908
|
+
setOpen(false);
|
|
7909
|
+
setKeyword(null);
|
|
7910
|
+
return;
|
|
7911
|
+
}
|
|
7912
|
+
const space = event.key === " " && (!showSearch || keyword === null);
|
|
7913
|
+
if (!space && ![
|
|
7914
|
+
"ArrowDown",
|
|
7915
|
+
"ArrowUp",
|
|
7916
|
+
"ArrowLeft",
|
|
7917
|
+
"ArrowRight",
|
|
7918
|
+
"Enter",
|
|
7919
|
+
"Home",
|
|
7920
|
+
"End"
|
|
7921
|
+
].includes(event.key))
|
|
7922
|
+
return;
|
|
7923
|
+
event.preventDefault();
|
|
7924
|
+
show();
|
|
7925
|
+
if (!visible.length) return;
|
|
7926
|
+
const entry = visible[activeIndex];
|
|
7927
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
7928
|
+
const next = activeIndex < 0 ? event.key === "ArrowDown" ? 0 : visible.length - 1 : (activeIndex + (event.key === "ArrowDown" ? 1 : -1) + visible.length) % visible.length;
|
|
7929
|
+
setActive(visible[next].node.value);
|
|
7930
|
+
} else if (event.key === "Home" || event.key === "End")
|
|
7931
|
+
setActive(
|
|
7932
|
+
visible[event.key === "Home" ? 0 : visible.length - 1].node.value
|
|
7933
|
+
);
|
|
7934
|
+
else if (entry) {
|
|
7935
|
+
if (event.key === "ArrowRight") {
|
|
7936
|
+
if (entry.node.children?.length && !expanded.has(entry.key) && !query)
|
|
7937
|
+
expand(entry, true);
|
|
7938
|
+
else if (visible[activeIndex + 1]?.depth > entry.depth)
|
|
7939
|
+
setActive(visible[activeIndex + 1].node.value);
|
|
7940
|
+
} else if (event.key === "ArrowLeft") {
|
|
7941
|
+
if (expanded.has(entry.key) && !query) expand(entry, false);
|
|
7942
|
+
else
|
|
7943
|
+
setActive(
|
|
7944
|
+
entry.parents[entry.parents.length - 1]?.node.value ?? entry.node.value
|
|
7945
|
+
);
|
|
7946
|
+
} else choose(entry, "keyboard");
|
|
7947
|
+
}
|
|
7948
|
+
},
|
|
7949
|
+
suffix: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7950
|
+
"span",
|
|
7951
|
+
{
|
|
7952
|
+
className: `canvas-react-select-actions${allowClear && interactive && selected.length ? " canvas-react-select-actions-clearable" : ""}`,
|
|
7953
|
+
onPointerDown: (event) => {
|
|
7954
|
+
if (interactive) {
|
|
7955
|
+
event.preventDefault();
|
|
7956
|
+
event.stopPropagation();
|
|
7957
|
+
}
|
|
7958
|
+
},
|
|
7959
|
+
onMouseDown: (event) => {
|
|
7960
|
+
if (interactive) {
|
|
7961
|
+
event.preventDefault();
|
|
7962
|
+
event.stopPropagation();
|
|
7963
|
+
}
|
|
7964
|
+
},
|
|
7965
|
+
onClick: (event) => {
|
|
7966
|
+
event.stopPropagation();
|
|
7967
|
+
if (interactive) {
|
|
7968
|
+
inputRef.current?.focus({ preventScroll: true });
|
|
7969
|
+
show();
|
|
7970
|
+
}
|
|
7971
|
+
},
|
|
7972
|
+
children: [
|
|
7973
|
+
allowClear && interactive && selected.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7974
|
+
"button",
|
|
7975
|
+
{
|
|
7976
|
+
type: "button",
|
|
7977
|
+
tabIndex: -1,
|
|
7978
|
+
"aria-label": "\u6E05\u7A7A\u6811\u9009\u62E9",
|
|
7979
|
+
className: "canvas-react-select-clear",
|
|
7980
|
+
onClick: (event) => {
|
|
7981
|
+
event.preventDefault();
|
|
7982
|
+
event.stopPropagation();
|
|
7983
|
+
inputRef.current?.focus({ preventScroll: true });
|
|
7984
|
+
setKeyword(null);
|
|
7985
|
+
setActive(null);
|
|
7986
|
+
setOpen(true);
|
|
7987
|
+
onChange?.(multiple ? [] : null, [], {
|
|
7988
|
+
trigger: "clear",
|
|
7989
|
+
complete: false
|
|
7990
|
+
});
|
|
7991
|
+
},
|
|
7992
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7993
|
+
"span",
|
|
7994
|
+
{
|
|
7995
|
+
className: "canvas-react-select-clear-icon",
|
|
7996
|
+
"aria-hidden": "true"
|
|
7997
|
+
}
|
|
7998
|
+
)
|
|
7999
|
+
}
|
|
8000
|
+
) : null,
|
|
8001
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8002
|
+
"span",
|
|
8003
|
+
{
|
|
8004
|
+
className: `canvas-react-select-arrow${open ? " canvas-react-select-arrow-open" : ""}`,
|
|
8005
|
+
"aria-hidden": "true"
|
|
8006
|
+
}
|
|
8007
|
+
)
|
|
8008
|
+
]
|
|
8009
|
+
}
|
|
8010
|
+
)
|
|
8011
|
+
}
|
|
8012
|
+
),
|
|
8013
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8014
|
+
ReactPopup,
|
|
8015
|
+
{
|
|
8016
|
+
open: open && interactive,
|
|
8017
|
+
anchorRef,
|
|
8018
|
+
onOpenChange: setOpen,
|
|
8019
|
+
matchAnchorWidth: true,
|
|
8020
|
+
constrainHeight: true,
|
|
8021
|
+
surfaceClassName: "canvas-react-tree-select-popup",
|
|
8022
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8023
|
+
"div",
|
|
8024
|
+
{
|
|
8025
|
+
ref: treeRef,
|
|
8026
|
+
id: treeId,
|
|
8027
|
+
role: "tree",
|
|
8028
|
+
"aria-label": "\u6811\u9009\u62E9\u9009\u9879",
|
|
8029
|
+
"aria-multiselectable": multiple || void 0,
|
|
8030
|
+
className: "canvas-react-tree-select-tree",
|
|
8031
|
+
children: visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-react-tree-select-empty", children: "\u6682\u65E0\u6570\u636E" }) : visible.map((entry, position) => {
|
|
8032
|
+
const isExpanded = !!query || expanded.has(entry.key);
|
|
8033
|
+
const hasChildren = !!entry.node.children?.length;
|
|
8034
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8035
|
+
"div",
|
|
8036
|
+
{
|
|
8037
|
+
id: `${treeId}-${position}`,
|
|
8038
|
+
role: "treeitem",
|
|
8039
|
+
"aria-level": entry.depth + 1,
|
|
8040
|
+
"aria-expanded": hasChildren ? isExpanded : void 0,
|
|
8041
|
+
"aria-selected": selectedSet.has(entry.node.value),
|
|
8042
|
+
"aria-disabled": !!entry.node.disabled,
|
|
8043
|
+
"data-active": entry.node.value === active,
|
|
8044
|
+
className: "canvas-react-tree-select-node",
|
|
8045
|
+
style: { paddingLeft: 6 + entry.depth * 18 },
|
|
8046
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
8047
|
+
onMouseEnter: () => setActive(entry.node.value),
|
|
8048
|
+
onClick: () => {
|
|
8049
|
+
setActive(entry.node.value);
|
|
8050
|
+
choose(entry, "mouse");
|
|
8051
|
+
},
|
|
8052
|
+
children: [
|
|
8053
|
+
hasChildren ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8054
|
+
"button",
|
|
8055
|
+
{
|
|
8056
|
+
type: "button",
|
|
8057
|
+
tabIndex: -1,
|
|
8058
|
+
"aria-label": `${isExpanded ? "\u6536\u8D77" : "\u5C55\u5F00"} ${entry.node.title}`,
|
|
8059
|
+
className: "canvas-react-tree-select-switcher",
|
|
8060
|
+
onClick: (event) => {
|
|
8061
|
+
event.preventDefault();
|
|
8062
|
+
event.stopPropagation();
|
|
8063
|
+
expand(entry);
|
|
8064
|
+
},
|
|
8065
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8066
|
+
"span",
|
|
8067
|
+
{
|
|
8068
|
+
className: `canvas-react-tree-select-chevron${isExpanded ? " canvas-react-tree-select-chevron-open" : ""}`,
|
|
8069
|
+
"aria-hidden": "true"
|
|
8070
|
+
}
|
|
8071
|
+
)
|
|
8072
|
+
}
|
|
8073
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "canvas-react-tree-select-switcher" }),
|
|
8074
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "canvas-react-tree-select-title", children: entry.node.title }),
|
|
8075
|
+
multiple && selectedSet.has(entry.node.value) ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8076
|
+
"span",
|
|
8077
|
+
{
|
|
8078
|
+
className: "canvas-react-tree-select-check",
|
|
8079
|
+
"aria-hidden": "true",
|
|
8080
|
+
children: "\u2713"
|
|
8081
|
+
}
|
|
8082
|
+
) : null
|
|
8083
|
+
]
|
|
8084
|
+
},
|
|
8085
|
+
JSON.stringify(entry.node.value)
|
|
8086
|
+
);
|
|
8087
|
+
})
|
|
8088
|
+
}
|
|
8089
|
+
)
|
|
8090
|
+
}
|
|
8091
|
+
)
|
|
8092
|
+
]
|
|
8093
|
+
}
|
|
8094
|
+
);
|
|
8095
|
+
}
|
|
7589
8096
|
var ReactAutoComplete = React.forwardRef(function ReactAutoComplete2(props, ref) {
|
|
7590
8097
|
const {
|
|
7591
8098
|
onChange,
|
|
@@ -8908,6 +9415,7 @@ exports.ReactTimePicker = ReactTimePicker;
|
|
|
8908
9415
|
exports.ReactTimeRangePicker = ReactTimeRangePicker;
|
|
8909
9416
|
exports.ReactTooltip = ReactTooltip;
|
|
8910
9417
|
exports.ReactTransition = ReactTransition;
|
|
9418
|
+
exports.ReactTreeSelect = ReactTreeSelect;
|
|
8911
9419
|
exports.ReactVirtualList = ReactVirtualList;
|
|
8912
9420
|
exports.ReactYearPicker = ReactYearPicker;
|
|
8913
9421
|
exports.reactMessage = reactMessage;
|