@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.js
CHANGED
|
@@ -474,9 +474,13 @@ function ReactPopup(props) {
|
|
|
474
474
|
)
|
|
475
475
|
}
|
|
476
476
|
),
|
|
477
|
-
|
|
477
|
+
resolvePopupContainer(anchorRef?.current)
|
|
478
478
|
);
|
|
479
479
|
}
|
|
480
|
+
function resolvePopupContainer(anchor) {
|
|
481
|
+
const fullscreenElement = document.fullscreenElement;
|
|
482
|
+
return fullscreenElement instanceof HTMLElement && (!anchor || fullscreenElement.contains(anchor)) ? fullscreenElement : document.body;
|
|
483
|
+
}
|
|
480
484
|
function resolvePopupPosition(params) {
|
|
481
485
|
const {
|
|
482
486
|
anchor,
|
|
@@ -7239,8 +7243,84 @@ function clamp3(value, min, max) {
|
|
|
7239
7243
|
return Math.min(Math.max(value, min), max);
|
|
7240
7244
|
}
|
|
7241
7245
|
|
|
7246
|
+
// src/components/cascader/cascader-selection.ts
|
|
7247
|
+
function createCascaderSelection(options) {
|
|
7248
|
+
const entries = /* @__PURE__ */ new Map();
|
|
7249
|
+
const visit = (items, parents, disabled = false) => items.map((item) => {
|
|
7250
|
+
const nodes = [...parents, item];
|
|
7251
|
+
const path = nodes.map((node) => node.value);
|
|
7252
|
+
const key = JSON.stringify(path);
|
|
7253
|
+
const entry = {
|
|
7254
|
+
path,
|
|
7255
|
+
children: [],
|
|
7256
|
+
leaves: [],
|
|
7257
|
+
disabled: disabled || !!item.disabled
|
|
7258
|
+
};
|
|
7259
|
+
entries.set(key, entry);
|
|
7260
|
+
entry.children = visit(item.children ?? [], nodes, entry.disabled);
|
|
7261
|
+
entry.leaves = entry.disabled ? [] : entry.children.length ? entry.children.flatMap((child) => child.leaves) : [key];
|
|
7262
|
+
return entry;
|
|
7263
|
+
});
|
|
7264
|
+
const roots = visit(options, []);
|
|
7265
|
+
const expand = (value) => {
|
|
7266
|
+
const checked = /* @__PURE__ */ new Set();
|
|
7267
|
+
const preserved = /* @__PURE__ */ new Map();
|
|
7268
|
+
for (const path of value) {
|
|
7269
|
+
const key = JSON.stringify(path);
|
|
7270
|
+
const entry = entries.get(key);
|
|
7271
|
+
if (!entry || entry.disabled || !entry.leaves.length)
|
|
7272
|
+
preserved.set(key, path);
|
|
7273
|
+
else entry.leaves.forEach((leaf) => checked.add(leaf));
|
|
7274
|
+
}
|
|
7275
|
+
return { checked, preserved };
|
|
7276
|
+
};
|
|
7277
|
+
const state = (entry, checked) => {
|
|
7278
|
+
const count = entry?.leaves.filter((leaf) => checked.has(leaf)).length ?? 0;
|
|
7279
|
+
return {
|
|
7280
|
+
checked: count > 0 && count === entry?.leaves.length,
|
|
7281
|
+
indeterminate: count > 0 && count < (entry?.leaves.length ?? 0)
|
|
7282
|
+
};
|
|
7283
|
+
};
|
|
7284
|
+
const collect = (checked, preserved, strategy) => {
|
|
7285
|
+
const paths = [];
|
|
7286
|
+
const walk = (entry) => {
|
|
7287
|
+
if (entry.disabled) return;
|
|
7288
|
+
if (state(entry, checked).checked && (strategy === "SHOW_PARENT" || !entry.children.length))
|
|
7289
|
+
paths.push(entry.path);
|
|
7290
|
+
else entry.children.forEach(walk);
|
|
7291
|
+
};
|
|
7292
|
+
roots.forEach(walk);
|
|
7293
|
+
return [...paths, ...preserved.values()];
|
|
7294
|
+
};
|
|
7295
|
+
return {
|
|
7296
|
+
/** 归一化回填值,去重并应用父级/末级策略。 */
|
|
7297
|
+
normalize(value, strategy) {
|
|
7298
|
+
const { checked, preserved } = expand(value);
|
|
7299
|
+
return collect(checked, preserved, strategy);
|
|
7300
|
+
},
|
|
7301
|
+
/** 计算某一路径的全选和半选状态。 */
|
|
7302
|
+
getState(value, path) {
|
|
7303
|
+
const { checked, preserved } = expand(value);
|
|
7304
|
+
if (preserved.has(JSON.stringify(path)))
|
|
7305
|
+
return { checked: true, indeterminate: false };
|
|
7306
|
+
return state(entries.get(JSON.stringify(path)), checked);
|
|
7307
|
+
},
|
|
7308
|
+
/** 切换某个节点以及全部可用后代,不修改入参。 */
|
|
7309
|
+
toggle(value, path, strategy) {
|
|
7310
|
+
const entry = entries.get(JSON.stringify(path));
|
|
7311
|
+
if (!entry || entry.disabled || !entry.leaves.length) return value;
|
|
7312
|
+
const { checked, preserved } = expand(value);
|
|
7313
|
+
const remove = state(entry, checked).checked;
|
|
7314
|
+
entry.leaves.forEach(
|
|
7315
|
+
(leaf) => remove ? checked.delete(leaf) : checked.add(leaf)
|
|
7316
|
+
);
|
|
7317
|
+
return collect(checked, preserved, strategy);
|
|
7318
|
+
}
|
|
7319
|
+
};
|
|
7320
|
+
}
|
|
7321
|
+
|
|
7242
7322
|
// src/components/cascader/style.css
|
|
7243
|
-
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[
|
|
7323
|
+
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');
|
|
7244
7324
|
function resolvePath(options, value) {
|
|
7245
7325
|
const path = [];
|
|
7246
7326
|
for (const part of value) {
|
|
@@ -7258,6 +7338,8 @@ function ReactCascader(props) {
|
|
|
7258
7338
|
value = EMPTY_VALUE,
|
|
7259
7339
|
options = EMPTY_OPTIONS,
|
|
7260
7340
|
showSearch = false,
|
|
7341
|
+
multiple = false,
|
|
7342
|
+
showCheckedStrategy = "SHOW_PARENT",
|
|
7261
7343
|
changeOnSelect = false,
|
|
7262
7344
|
expandTrigger = "click",
|
|
7263
7345
|
displayRender,
|
|
@@ -7275,7 +7357,13 @@ function ReactCascader(props) {
|
|
|
7275
7357
|
const inputRef = useRef(null);
|
|
7276
7358
|
const popupRef = useRef(null);
|
|
7277
7359
|
const popupId = useId();
|
|
7278
|
-
const
|
|
7360
|
+
const selection = useMemo(() => createCascaderSelection(options), [options]);
|
|
7361
|
+
const singleValue = multiple ? EMPTY_VALUE : value;
|
|
7362
|
+
const multipleValue = multiple ? value.filter(Array.isArray) : [];
|
|
7363
|
+
const selected = useMemo(
|
|
7364
|
+
() => resolvePath(options, singleValue),
|
|
7365
|
+
[options, singleValue]
|
|
7366
|
+
);
|
|
7279
7367
|
const [path, setPath] = useState(selected);
|
|
7280
7368
|
const [open, setOpen] = useState(false);
|
|
7281
7369
|
const [keyword, setKeyword] = useState("");
|
|
@@ -7285,10 +7373,14 @@ function ReactCascader(props) {
|
|
|
7285
7373
|
useEffect(() => {
|
|
7286
7374
|
setPath(selected);
|
|
7287
7375
|
}, [selected]);
|
|
7288
|
-
const
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7376
|
+
const displayPath = (valuePath) => {
|
|
7377
|
+
const nodes = resolvePath(options, valuePath);
|
|
7378
|
+
const labels = valuePath.map(
|
|
7379
|
+
(part, index) => nodes[index]?.label ?? String(part)
|
|
7380
|
+
);
|
|
7381
|
+
return displayRender?.(labels, nodes) ?? labels.join(" / ");
|
|
7382
|
+
};
|
|
7383
|
+
const text = multiple ? selection.normalize(multipleValue, showCheckedStrategy).map(displayPath).join("\uFF1B") : displayPath(singleValue);
|
|
7292
7384
|
const columns = [options];
|
|
7293
7385
|
for (const item of path) {
|
|
7294
7386
|
if (!item.children?.length) break;
|
|
@@ -7302,21 +7394,37 @@ function ReactCascader(props) {
|
|
|
7302
7394
|
for (const item of items) {
|
|
7303
7395
|
if (item.disabled) continue;
|
|
7304
7396
|
const next = [...parents, item];
|
|
7305
|
-
if ((!item.children?.length || changeOnSelect) && next.map((part) => part.label).join(" / ").toLocaleLowerCase().includes(keyword.trim().toLocaleLowerCase()))
|
|
7397
|
+
if ((!item.children?.length || changeOnSelect || multiple) && next.map((part) => part.label).join(" / ").toLocaleLowerCase().includes(keyword.trim().toLocaleLowerCase()))
|
|
7306
7398
|
matches.push(next);
|
|
7307
7399
|
if (item.children?.length) visit(item.children, next);
|
|
7308
7400
|
}
|
|
7309
7401
|
};
|
|
7310
7402
|
visit(options, []);
|
|
7311
7403
|
return matches;
|
|
7312
|
-
}, [options, keyword, changeOnSelect]);
|
|
7404
|
+
}, [options, keyword, changeOnSelect, multiple]);
|
|
7313
7405
|
useEffect(() => {
|
|
7314
7406
|
popupRef.current?.querySelector("[data-active='true']")?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
|
|
7315
7407
|
}, [focus, open]);
|
|
7408
|
+
const toggle = (next, trigger) => {
|
|
7409
|
+
const updated = selection.toggle(
|
|
7410
|
+
multipleValue,
|
|
7411
|
+
next.map((item) => item.value),
|
|
7412
|
+
showCheckedStrategy
|
|
7413
|
+
);
|
|
7414
|
+
onChange?.(
|
|
7415
|
+
updated,
|
|
7416
|
+
updated.map((parts) => resolvePath(options, parts)),
|
|
7417
|
+
{ trigger, complete: false }
|
|
7418
|
+
);
|
|
7419
|
+
};
|
|
7316
7420
|
const choose = (next, trigger, fromSearch = false) => {
|
|
7317
7421
|
const item = next[next.length - 1];
|
|
7318
7422
|
if (!item || next.some((option) => option.disabled)) return;
|
|
7319
7423
|
setPath(next);
|
|
7424
|
+
if (multiple) {
|
|
7425
|
+
if (!item.children?.length || fromSearch) toggle(next, trigger);
|
|
7426
|
+
return;
|
|
7427
|
+
}
|
|
7320
7428
|
const complete = !item.children?.length || fromSearch;
|
|
7321
7429
|
if (complete || changeOnSelect)
|
|
7322
7430
|
onChange?.(
|
|
@@ -7333,7 +7441,7 @@ function ReactCascader(props) {
|
|
|
7333
7441
|
const show = () => {
|
|
7334
7442
|
if (!interactive) return;
|
|
7335
7443
|
setOpen(true);
|
|
7336
|
-
setPath(selected);
|
|
7444
|
+
if (!multiple) setPath(selected);
|
|
7337
7445
|
};
|
|
7338
7446
|
return /* @__PURE__ */ jsxs(
|
|
7339
7447
|
"div",
|
|
@@ -7385,7 +7493,7 @@ function ReactCascader(props) {
|
|
|
7385
7493
|
setTyping(false);
|
|
7386
7494
|
return;
|
|
7387
7495
|
}
|
|
7388
|
-
if (![
|
|
7496
|
+
if (!(multiple && event.key === " " && (!showSearch || !typing)) && ![
|
|
7389
7497
|
"ArrowDown",
|
|
7390
7498
|
"ArrowUp",
|
|
7391
7499
|
"ArrowRight",
|
|
@@ -7418,7 +7526,9 @@ function ReactCascader(props) {
|
|
|
7418
7526
|
const item = items[focus.index];
|
|
7419
7527
|
if (!item || item.disabled) return;
|
|
7420
7528
|
const next = searching ? results[focus.index] : [...path.slice(0, column), item];
|
|
7421
|
-
if (event.key === "Enter"
|
|
7529
|
+
if (multiple && (event.key === "Enter" || event.key === " "))
|
|
7530
|
+
toggle(next, "keyboard");
|
|
7531
|
+
else if (event.key === "Enter") choose(next, "keyboard", searching);
|
|
7422
7532
|
else if (event.key !== "ArrowRight") return;
|
|
7423
7533
|
if (!searching && item.children?.length) {
|
|
7424
7534
|
setPath(next);
|
|
@@ -7515,20 +7625,26 @@ function ReactCascader(props) {
|
|
|
7515
7625
|
"div",
|
|
7516
7626
|
{
|
|
7517
7627
|
role: "listbox",
|
|
7628
|
+
"aria-multiselectable": multiple || void 0,
|
|
7518
7629
|
"aria-label": searching ? "\u641C\u7D22\u7ED3\u679C" : `\u7B2C ${column + 1} \u7EA7\u9009\u9879`,
|
|
7519
7630
|
className: "canvas-react-cascader-menu",
|
|
7520
7631
|
children: items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "canvas-react-cascader-empty", children: "\u6682\u65E0\u6570\u636E" }) : items.map((item, index) => {
|
|
7521
7632
|
const next = searching ? results[index] : [...path.slice(0, column), item];
|
|
7522
7633
|
const active = focus.column === column && focus.index === index;
|
|
7634
|
+
const checkedState = multiple ? selection.getState(
|
|
7635
|
+
multipleValue,
|
|
7636
|
+
next.map((node) => node.value)
|
|
7637
|
+
) : { checked: false, indeterminate: false };
|
|
7523
7638
|
return /* @__PURE__ */ jsxs(
|
|
7524
7639
|
"div",
|
|
7525
7640
|
{
|
|
7526
7641
|
id: `${popupId}-${column}-${index}`,
|
|
7527
7642
|
role: "option",
|
|
7528
|
-
"aria-selected": path[column] === item,
|
|
7643
|
+
"aria-selected": multiple ? checkedState.checked : path[column] === item,
|
|
7529
7644
|
"aria-disabled": !!item.disabled,
|
|
7530
7645
|
"data-active": active,
|
|
7531
7646
|
className: "canvas-react-cascader-option",
|
|
7647
|
+
"data-expanded": !!item.children?.length && path[column] === item,
|
|
7532
7648
|
onMouseDown: (event) => event.preventDefault(),
|
|
7533
7649
|
onMouseEnter: () => {
|
|
7534
7650
|
if (item.disabled) return;
|
|
@@ -7541,6 +7657,32 @@ function ReactCascader(props) {
|
|
|
7541
7657
|
choose(next, "mouse", searching);
|
|
7542
7658
|
},
|
|
7543
7659
|
children: [
|
|
7660
|
+
multiple ? /* @__PURE__ */ jsx(
|
|
7661
|
+
"span",
|
|
7662
|
+
{
|
|
7663
|
+
className: "canvas-react-cascader-check",
|
|
7664
|
+
role: "checkbox",
|
|
7665
|
+
"aria-checked": checkedState.indeterminate ? "mixed" : checkedState.checked,
|
|
7666
|
+
"aria-label": `\u9009\u62E9 ${next.map((node) => node.label).join(" / ")}`,
|
|
7667
|
+
"aria-disabled": !!item.disabled,
|
|
7668
|
+
onClick: (event) => {
|
|
7669
|
+
event.preventDefault();
|
|
7670
|
+
event.stopPropagation();
|
|
7671
|
+
if (!item.disabled) toggle(next, "mouse");
|
|
7672
|
+
},
|
|
7673
|
+
children: /* @__PURE__ */ jsx(
|
|
7674
|
+
ReactCheckbox,
|
|
7675
|
+
{
|
|
7676
|
+
tabIndex: -1,
|
|
7677
|
+
"aria-hidden": "true",
|
|
7678
|
+
readOnly: true,
|
|
7679
|
+
checked: checkedState.checked,
|
|
7680
|
+
indeterminate: checkedState.indeterminate,
|
|
7681
|
+
disabled: item.disabled
|
|
7682
|
+
}
|
|
7683
|
+
)
|
|
7684
|
+
}
|
|
7685
|
+
) : null,
|
|
7544
7686
|
/* @__PURE__ */ jsx("span", { children: searching ? next.map((part) => part.label).join(" / ") : item.label }),
|
|
7545
7687
|
!searching && item.children?.length ? /* @__PURE__ */ jsx(
|
|
7546
7688
|
"span",
|
|
@@ -7565,6 +7707,371 @@ function ReactCascader(props) {
|
|
|
7565
7707
|
}
|
|
7566
7708
|
);
|
|
7567
7709
|
}
|
|
7710
|
+
|
|
7711
|
+
// src/components/tree-select/tree-select-utils.ts
|
|
7712
|
+
function createTreeSelectIndex(treeData) {
|
|
7713
|
+
const entries = [];
|
|
7714
|
+
const byValue = /* @__PURE__ */ new Map();
|
|
7715
|
+
const visit = (nodes, parents) => {
|
|
7716
|
+
for (const node of nodes) {
|
|
7717
|
+
const entry = {
|
|
7718
|
+
node,
|
|
7719
|
+
key: node.key ?? node.value,
|
|
7720
|
+
parents,
|
|
7721
|
+
depth: parents.length
|
|
7722
|
+
};
|
|
7723
|
+
entries.push(entry);
|
|
7724
|
+
byValue.set(node.value, entry);
|
|
7725
|
+
if (node.children?.length) visit(node.children, [...parents, entry]);
|
|
7726
|
+
}
|
|
7727
|
+
};
|
|
7728
|
+
visit(treeData, []);
|
|
7729
|
+
return { entries, byValue };
|
|
7730
|
+
}
|
|
7731
|
+
function normalizeTreeSelectValue(value, multiple) {
|
|
7732
|
+
const values = multiple ? Array.isArray(value) ? value : [] : [value];
|
|
7733
|
+
return [
|
|
7734
|
+
...new Set(
|
|
7735
|
+
values.filter(
|
|
7736
|
+
(part) => typeof part === "string" || typeof part === "number"
|
|
7737
|
+
)
|
|
7738
|
+
)
|
|
7739
|
+
];
|
|
7740
|
+
}
|
|
7741
|
+
|
|
7742
|
+
// src/components/tree-select/style.css
|
|
7743
|
+
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');
|
|
7744
|
+
var EMPTY_TREE = [];
|
|
7745
|
+
function ReactTreeSelect(props) {
|
|
7746
|
+
const {
|
|
7747
|
+
value = null,
|
|
7748
|
+
treeData = EMPTY_TREE,
|
|
7749
|
+
multiple = false,
|
|
7750
|
+
showSearch = multiple,
|
|
7751
|
+
treeDefaultExpandAll = false,
|
|
7752
|
+
treeDefaultExpandedKeys,
|
|
7753
|
+
allowClear = true,
|
|
7754
|
+
onChange,
|
|
7755
|
+
disabled,
|
|
7756
|
+
readOnly,
|
|
7757
|
+
onFocus,
|
|
7758
|
+
onBlur,
|
|
7759
|
+
onClick,
|
|
7760
|
+
onKeyDown,
|
|
7761
|
+
...inputProps
|
|
7762
|
+
} = props;
|
|
7763
|
+
const index = useMemo(() => createTreeSelectIndex(treeData), [treeData]);
|
|
7764
|
+
const selected = useMemo(
|
|
7765
|
+
() => normalizeTreeSelectValue(value, multiple),
|
|
7766
|
+
[value, multiple]
|
|
7767
|
+
);
|
|
7768
|
+
const selectedSet = useMemo(() => new Set(selected), [selected]);
|
|
7769
|
+
const [expanded, setExpanded] = useState(
|
|
7770
|
+
() => /* @__PURE__ */ new Set([
|
|
7771
|
+
...treeDefaultExpandAll ? index.entries.filter((entry) => entry.node.children?.length).map((entry) => entry.key) : treeDefaultExpandedKeys ?? [],
|
|
7772
|
+
...selected.flatMap(
|
|
7773
|
+
(part) => index.byValue.get(part)?.parents.map((parent) => parent.key) ?? []
|
|
7774
|
+
)
|
|
7775
|
+
])
|
|
7776
|
+
);
|
|
7777
|
+
const [open, setOpen] = useState(false);
|
|
7778
|
+
const [keyword, setKeyword] = useState(null);
|
|
7779
|
+
const [active, setActive] = useState(
|
|
7780
|
+
selected[0] ?? null
|
|
7781
|
+
);
|
|
7782
|
+
const anchorRef = useRef(null);
|
|
7783
|
+
const inputRef = useRef(null);
|
|
7784
|
+
const treeRef = useRef(null);
|
|
7785
|
+
const treeId = useId();
|
|
7786
|
+
const interactive = !disabled && !readOnly;
|
|
7787
|
+
const query = (keyword ?? "").trim().toLocaleLowerCase();
|
|
7788
|
+
const text = selected.map((part) => index.byValue.get(part)?.node.title ?? String(part)).join("\uFF1B");
|
|
7789
|
+
const visible = useMemo(() => {
|
|
7790
|
+
if (!query)
|
|
7791
|
+
return index.entries.filter(
|
|
7792
|
+
(entry) => entry.parents.every((parent) => expanded.has(parent.key))
|
|
7793
|
+
);
|
|
7794
|
+
const matches = /* @__PURE__ */ new Set();
|
|
7795
|
+
for (const entry of index.entries) {
|
|
7796
|
+
if (!entry.node.title.toLocaleLowerCase().includes(query)) continue;
|
|
7797
|
+
matches.add(entry);
|
|
7798
|
+
entry.parents.forEach((parent) => matches.add(parent));
|
|
7799
|
+
}
|
|
7800
|
+
return index.entries.filter((entry) => matches.has(entry));
|
|
7801
|
+
}, [index, query, expanded]);
|
|
7802
|
+
useEffect(() => {
|
|
7803
|
+
setExpanded((previous) => {
|
|
7804
|
+
const next = new Set(previous);
|
|
7805
|
+
selected.forEach(
|
|
7806
|
+
(part) => index.byValue.get(part)?.parents.forEach((parent) => next.add(parent.key))
|
|
7807
|
+
);
|
|
7808
|
+
return next;
|
|
7809
|
+
});
|
|
7810
|
+
}, [index, selected]);
|
|
7811
|
+
useEffect(() => {
|
|
7812
|
+
treeRef.current?.querySelector('[data-active="true"]')?.scrollIntoView?.({ block: "nearest" });
|
|
7813
|
+
}, [active, open]);
|
|
7814
|
+
const expand = (entry, next) => {
|
|
7815
|
+
if (!entry.node.children?.length || query) return;
|
|
7816
|
+
setExpanded((previous) => {
|
|
7817
|
+
const keys = new Set(previous);
|
|
7818
|
+
if (next ?? !keys.has(entry.key)) keys.add(entry.key);
|
|
7819
|
+
else keys.delete(entry.key);
|
|
7820
|
+
return keys;
|
|
7821
|
+
});
|
|
7822
|
+
};
|
|
7823
|
+
const choose = (entry, trigger) => {
|
|
7824
|
+
if (entry.node.disabled) return;
|
|
7825
|
+
if (entry.node.selectable === false) {
|
|
7826
|
+
expand(entry);
|
|
7827
|
+
return;
|
|
7828
|
+
}
|
|
7829
|
+
const next = multiple ? selectedSet.has(entry.node.value) ? selected.filter((part) => part !== entry.node.value) : [...selected, entry.node.value] : [entry.node.value];
|
|
7830
|
+
onChange?.(
|
|
7831
|
+
multiple ? next : entry.node.value,
|
|
7832
|
+
next.flatMap((part) => index.byValue.get(part)?.node ?? []),
|
|
7833
|
+
{ trigger, complete: !multiple }
|
|
7834
|
+
);
|
|
7835
|
+
if (!multiple) {
|
|
7836
|
+
setOpen(false);
|
|
7837
|
+
setKeyword(null);
|
|
7838
|
+
}
|
|
7839
|
+
};
|
|
7840
|
+
const show = () => {
|
|
7841
|
+
if (interactive) setOpen(true);
|
|
7842
|
+
};
|
|
7843
|
+
const activeIndex = visible.findIndex((entry) => entry.node.value === active);
|
|
7844
|
+
return /* @__PURE__ */ jsxs(
|
|
7845
|
+
"div",
|
|
7846
|
+
{
|
|
7847
|
+
ref: anchorRef,
|
|
7848
|
+
className: `canvas-react-tree-select${open && interactive ? " canvas-react-tree-select-open" : ""}`,
|
|
7849
|
+
children: [
|
|
7850
|
+
/* @__PURE__ */ jsx(
|
|
7851
|
+
ReactInput,
|
|
7852
|
+
{
|
|
7853
|
+
...inputProps,
|
|
7854
|
+
ref: inputRef,
|
|
7855
|
+
disabled,
|
|
7856
|
+
readOnly: readOnly || !showSearch,
|
|
7857
|
+
allowClear: false,
|
|
7858
|
+
role: "combobox",
|
|
7859
|
+
"aria-haspopup": "tree",
|
|
7860
|
+
"aria-expanded": open && interactive,
|
|
7861
|
+
"aria-controls": open ? treeId : void 0,
|
|
7862
|
+
"aria-activedescendant": open && activeIndex >= 0 ? `${treeId}-${activeIndex}` : void 0,
|
|
7863
|
+
value: open && keyword !== null ? keyword : text,
|
|
7864
|
+
onFocus: (event) => {
|
|
7865
|
+
show();
|
|
7866
|
+
onFocus?.(event);
|
|
7867
|
+
},
|
|
7868
|
+
onClick: (event) => {
|
|
7869
|
+
show();
|
|
7870
|
+
onClick?.(event);
|
|
7871
|
+
},
|
|
7872
|
+
onBlur: (event) => {
|
|
7873
|
+
setOpen(false);
|
|
7874
|
+
setKeyword(null);
|
|
7875
|
+
onBlur?.(event);
|
|
7876
|
+
},
|
|
7877
|
+
onChange: (event) => {
|
|
7878
|
+
setKeyword(event.target.value);
|
|
7879
|
+
setActive(null);
|
|
7880
|
+
show();
|
|
7881
|
+
},
|
|
7882
|
+
onKeyDown: (event) => {
|
|
7883
|
+
onKeyDown?.(event);
|
|
7884
|
+
if (event.defaultPrevented || !interactive) return;
|
|
7885
|
+
if (event.key === "Escape") {
|
|
7886
|
+
event.preventDefault();
|
|
7887
|
+
setOpen(false);
|
|
7888
|
+
setKeyword(null);
|
|
7889
|
+
return;
|
|
7890
|
+
}
|
|
7891
|
+
const space = event.key === " " && (!showSearch || keyword === null);
|
|
7892
|
+
if (!space && ![
|
|
7893
|
+
"ArrowDown",
|
|
7894
|
+
"ArrowUp",
|
|
7895
|
+
"ArrowLeft",
|
|
7896
|
+
"ArrowRight",
|
|
7897
|
+
"Enter",
|
|
7898
|
+
"Home",
|
|
7899
|
+
"End"
|
|
7900
|
+
].includes(event.key))
|
|
7901
|
+
return;
|
|
7902
|
+
event.preventDefault();
|
|
7903
|
+
show();
|
|
7904
|
+
if (!visible.length) return;
|
|
7905
|
+
const entry = visible[activeIndex];
|
|
7906
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
7907
|
+
const next = activeIndex < 0 ? event.key === "ArrowDown" ? 0 : visible.length - 1 : (activeIndex + (event.key === "ArrowDown" ? 1 : -1) + visible.length) % visible.length;
|
|
7908
|
+
setActive(visible[next].node.value);
|
|
7909
|
+
} else if (event.key === "Home" || event.key === "End")
|
|
7910
|
+
setActive(
|
|
7911
|
+
visible[event.key === "Home" ? 0 : visible.length - 1].node.value
|
|
7912
|
+
);
|
|
7913
|
+
else if (entry) {
|
|
7914
|
+
if (event.key === "ArrowRight") {
|
|
7915
|
+
if (entry.node.children?.length && !expanded.has(entry.key) && !query)
|
|
7916
|
+
expand(entry, true);
|
|
7917
|
+
else if (visible[activeIndex + 1]?.depth > entry.depth)
|
|
7918
|
+
setActive(visible[activeIndex + 1].node.value);
|
|
7919
|
+
} else if (event.key === "ArrowLeft") {
|
|
7920
|
+
if (expanded.has(entry.key) && !query) expand(entry, false);
|
|
7921
|
+
else
|
|
7922
|
+
setActive(
|
|
7923
|
+
entry.parents[entry.parents.length - 1]?.node.value ?? entry.node.value
|
|
7924
|
+
);
|
|
7925
|
+
} else choose(entry, "keyboard");
|
|
7926
|
+
}
|
|
7927
|
+
},
|
|
7928
|
+
suffix: /* @__PURE__ */ jsxs(
|
|
7929
|
+
"span",
|
|
7930
|
+
{
|
|
7931
|
+
className: `canvas-react-select-actions${allowClear && interactive && selected.length ? " canvas-react-select-actions-clearable" : ""}`,
|
|
7932
|
+
onPointerDown: (event) => {
|
|
7933
|
+
if (interactive) {
|
|
7934
|
+
event.preventDefault();
|
|
7935
|
+
event.stopPropagation();
|
|
7936
|
+
}
|
|
7937
|
+
},
|
|
7938
|
+
onMouseDown: (event) => {
|
|
7939
|
+
if (interactive) {
|
|
7940
|
+
event.preventDefault();
|
|
7941
|
+
event.stopPropagation();
|
|
7942
|
+
}
|
|
7943
|
+
},
|
|
7944
|
+
onClick: (event) => {
|
|
7945
|
+
event.stopPropagation();
|
|
7946
|
+
if (interactive) {
|
|
7947
|
+
inputRef.current?.focus({ preventScroll: true });
|
|
7948
|
+
show();
|
|
7949
|
+
}
|
|
7950
|
+
},
|
|
7951
|
+
children: [
|
|
7952
|
+
allowClear && interactive && selected.length > 0 ? /* @__PURE__ */ jsx(
|
|
7953
|
+
"button",
|
|
7954
|
+
{
|
|
7955
|
+
type: "button",
|
|
7956
|
+
tabIndex: -1,
|
|
7957
|
+
"aria-label": "\u6E05\u7A7A\u6811\u9009\u62E9",
|
|
7958
|
+
className: "canvas-react-select-clear",
|
|
7959
|
+
onClick: (event) => {
|
|
7960
|
+
event.preventDefault();
|
|
7961
|
+
event.stopPropagation();
|
|
7962
|
+
inputRef.current?.focus({ preventScroll: true });
|
|
7963
|
+
setKeyword(null);
|
|
7964
|
+
setActive(null);
|
|
7965
|
+
setOpen(true);
|
|
7966
|
+
onChange?.(multiple ? [] : null, [], {
|
|
7967
|
+
trigger: "clear",
|
|
7968
|
+
complete: false
|
|
7969
|
+
});
|
|
7970
|
+
},
|
|
7971
|
+
children: /* @__PURE__ */ jsx(
|
|
7972
|
+
"span",
|
|
7973
|
+
{
|
|
7974
|
+
className: "canvas-react-select-clear-icon",
|
|
7975
|
+
"aria-hidden": "true"
|
|
7976
|
+
}
|
|
7977
|
+
)
|
|
7978
|
+
}
|
|
7979
|
+
) : null,
|
|
7980
|
+
/* @__PURE__ */ jsx(
|
|
7981
|
+
"span",
|
|
7982
|
+
{
|
|
7983
|
+
className: `canvas-react-select-arrow${open ? " canvas-react-select-arrow-open" : ""}`,
|
|
7984
|
+
"aria-hidden": "true"
|
|
7985
|
+
}
|
|
7986
|
+
)
|
|
7987
|
+
]
|
|
7988
|
+
}
|
|
7989
|
+
)
|
|
7990
|
+
}
|
|
7991
|
+
),
|
|
7992
|
+
/* @__PURE__ */ jsx(
|
|
7993
|
+
ReactPopup,
|
|
7994
|
+
{
|
|
7995
|
+
open: open && interactive,
|
|
7996
|
+
anchorRef,
|
|
7997
|
+
onOpenChange: setOpen,
|
|
7998
|
+
matchAnchorWidth: true,
|
|
7999
|
+
constrainHeight: true,
|
|
8000
|
+
surfaceClassName: "canvas-react-tree-select-popup",
|
|
8001
|
+
children: /* @__PURE__ */ jsx(
|
|
8002
|
+
"div",
|
|
8003
|
+
{
|
|
8004
|
+
ref: treeRef,
|
|
8005
|
+
id: treeId,
|
|
8006
|
+
role: "tree",
|
|
8007
|
+
"aria-label": "\u6811\u9009\u62E9\u9009\u9879",
|
|
8008
|
+
"aria-multiselectable": multiple || void 0,
|
|
8009
|
+
className: "canvas-react-tree-select-tree",
|
|
8010
|
+
children: visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "canvas-react-tree-select-empty", children: "\u6682\u65E0\u6570\u636E" }) : visible.map((entry, position) => {
|
|
8011
|
+
const isExpanded = !!query || expanded.has(entry.key);
|
|
8012
|
+
const hasChildren = !!entry.node.children?.length;
|
|
8013
|
+
return /* @__PURE__ */ jsxs(
|
|
8014
|
+
"div",
|
|
8015
|
+
{
|
|
8016
|
+
id: `${treeId}-${position}`,
|
|
8017
|
+
role: "treeitem",
|
|
8018
|
+
"aria-level": entry.depth + 1,
|
|
8019
|
+
"aria-expanded": hasChildren ? isExpanded : void 0,
|
|
8020
|
+
"aria-selected": selectedSet.has(entry.node.value),
|
|
8021
|
+
"aria-disabled": !!entry.node.disabled,
|
|
8022
|
+
"data-active": entry.node.value === active,
|
|
8023
|
+
className: "canvas-react-tree-select-node",
|
|
8024
|
+
style: { paddingLeft: 6 + entry.depth * 18 },
|
|
8025
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
8026
|
+
onMouseEnter: () => setActive(entry.node.value),
|
|
8027
|
+
onClick: () => {
|
|
8028
|
+
setActive(entry.node.value);
|
|
8029
|
+
choose(entry, "mouse");
|
|
8030
|
+
},
|
|
8031
|
+
children: [
|
|
8032
|
+
hasChildren ? /* @__PURE__ */ jsx(
|
|
8033
|
+
"button",
|
|
8034
|
+
{
|
|
8035
|
+
type: "button",
|
|
8036
|
+
tabIndex: -1,
|
|
8037
|
+
"aria-label": `${isExpanded ? "\u6536\u8D77" : "\u5C55\u5F00"} ${entry.node.title}`,
|
|
8038
|
+
className: "canvas-react-tree-select-switcher",
|
|
8039
|
+
onClick: (event) => {
|
|
8040
|
+
event.preventDefault();
|
|
8041
|
+
event.stopPropagation();
|
|
8042
|
+
expand(entry);
|
|
8043
|
+
},
|
|
8044
|
+
children: /* @__PURE__ */ jsx(
|
|
8045
|
+
"span",
|
|
8046
|
+
{
|
|
8047
|
+
className: `canvas-react-tree-select-chevron${isExpanded ? " canvas-react-tree-select-chevron-open" : ""}`,
|
|
8048
|
+
"aria-hidden": "true"
|
|
8049
|
+
}
|
|
8050
|
+
)
|
|
8051
|
+
}
|
|
8052
|
+
) : /* @__PURE__ */ jsx("span", { className: "canvas-react-tree-select-switcher" }),
|
|
8053
|
+
/* @__PURE__ */ jsx("span", { className: "canvas-react-tree-select-title", children: entry.node.title }),
|
|
8054
|
+
multiple && selectedSet.has(entry.node.value) ? /* @__PURE__ */ jsx(
|
|
8055
|
+
"span",
|
|
8056
|
+
{
|
|
8057
|
+
className: "canvas-react-tree-select-check",
|
|
8058
|
+
"aria-hidden": "true",
|
|
8059
|
+
children: "\u2713"
|
|
8060
|
+
}
|
|
8061
|
+
) : null
|
|
8062
|
+
]
|
|
8063
|
+
},
|
|
8064
|
+
JSON.stringify(entry.node.value)
|
|
8065
|
+
);
|
|
8066
|
+
})
|
|
8067
|
+
}
|
|
8068
|
+
)
|
|
8069
|
+
}
|
|
8070
|
+
)
|
|
8071
|
+
]
|
|
8072
|
+
}
|
|
8073
|
+
);
|
|
8074
|
+
}
|
|
7568
8075
|
var ReactAutoComplete = forwardRef(function ReactAutoComplete2(props, ref) {
|
|
7569
8076
|
const {
|
|
7570
8077
|
onChange,
|
|
@@ -8852,6 +9359,6 @@ var reactMessage = {
|
|
|
8852
9359
|
error: (content) => showMessage("error", content)
|
|
8853
9360
|
};
|
|
8854
9361
|
|
|
8855
|
-
export { REACT_COMPONENT_PREFIX, ReactAutoComplete, ReactButton, ReactCascader, ReactCheckbox, ReactCol, ReactColorPicker, ReactContentScaleProvider, ReactDatePicker, ReactDateRangePicker, ReactDateTimePicker, ReactDateTimeRangePicker, ReactFilterPanel, ReactFlex, ReactForm, ReactImagePreview, ReactInput, ReactInputNumber, ReactInputRange, ReactModal, ReactMonthPicker, ReactNumberInput, ReactPagination, ReactPopconfirm, ReactPopup, ReactQuarterPicker, ReactRadio, ReactResizablePanels, ReactRow, ReactSelect, ReactTextArea, ReactTimePicker, ReactTimeRangePicker, ReactTooltip, ReactTransition, ReactVirtualList, ReactYearPicker, reactMessage, resolveResizablePanelSizes, useReactContentScale, useReactForm, useReactFormWatch, useReactTransition };
|
|
9362
|
+
export { REACT_COMPONENT_PREFIX, ReactAutoComplete, ReactButton, ReactCascader, ReactCheckbox, ReactCol, ReactColorPicker, ReactContentScaleProvider, ReactDatePicker, ReactDateRangePicker, ReactDateTimePicker, ReactDateTimeRangePicker, ReactFilterPanel, ReactFlex, ReactForm, ReactImagePreview, ReactInput, ReactInputNumber, ReactInputRange, ReactModal, ReactMonthPicker, ReactNumberInput, ReactPagination, ReactPopconfirm, ReactPopup, ReactQuarterPicker, ReactRadio, ReactResizablePanels, ReactRow, ReactSelect, ReactTextArea, ReactTimePicker, ReactTimeRangePicker, ReactTooltip, ReactTransition, ReactTreeSelect, ReactVirtualList, ReactYearPicker, reactMessage, resolveResizablePanelSizes, useReactContentScale, useReactForm, useReactFormWatch, useReactTransition };
|
|
8856
9363
|
//# sourceMappingURL=index.js.map
|
|
8857
9364
|
//# sourceMappingURL=index.js.map
|