@lobehub/ui 5.46.3 → 5.47.0

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.
Files changed (47) hide show
  1. package/es/base-ui/Collapsible/Collapsible.d.mts +6 -0
  2. package/es/base-ui/Collapsible/Collapsible.mjs +25 -0
  3. package/es/base-ui/Collapsible/Collapsible.mjs.map +1 -0
  4. package/es/base-ui/Collapsible/index.d.mts +3 -0
  5. package/es/base-ui/Collapsible/type.d.mts +14 -0
  6. package/es/base-ui/FocusScope/FocusScope.d.mts +15 -0
  7. package/es/base-ui/FocusScope/FocusScope.mjs +36 -0
  8. package/es/base-ui/FocusScope/FocusScope.mjs.map +1 -0
  9. package/es/base-ui/FocusScope/domUtils.mjs +31 -0
  10. package/es/base-ui/FocusScope/domUtils.mjs.map +1 -0
  11. package/es/base-ui/FocusScope/index.d.mts +6 -0
  12. package/es/base-ui/FocusScope/store.d.mts +11 -0
  13. package/es/base-ui/FocusScope/store.mjs +76 -0
  14. package/es/base-ui/FocusScope/store.mjs.map +1 -0
  15. package/es/base-ui/FocusScope/style.d.mts +8 -0
  16. package/es/base-ui/FocusScope/style.mjs +18 -0
  17. package/es/base-ui/FocusScope/style.mjs.map +1 -0
  18. package/es/base-ui/FocusScope/useScopeArrowNav.d.mts +15 -0
  19. package/es/base-ui/FocusScope/useScopeArrowNav.mjs +111 -0
  20. package/es/base-ui/FocusScope/useScopeArrowNav.mjs.map +1 -0
  21. package/es/base-ui/FocusScope/useScopeSwitcher.d.mts +9 -0
  22. package/es/base-ui/FocusScope/useScopeSwitcher.mjs +47 -0
  23. package/es/base-ui/FocusScope/useScopeSwitcher.mjs.map +1 -0
  24. package/es/base-ui/Input/style.d.mts +1 -1
  25. package/es/base-ui/Text/style.d.mts +1 -1
  26. package/es/base-ui/Tree/Tree.d.mts +6 -0
  27. package/es/base-ui/Tree/Tree.mjs +175 -0
  28. package/es/base-ui/Tree/Tree.mjs.map +1 -0
  29. package/es/base-ui/Tree/TreeNode.mjs +124 -0
  30. package/es/base-ui/Tree/TreeNode.mjs.map +1 -0
  31. package/es/base-ui/Tree/context.mjs +12 -0
  32. package/es/base-ui/Tree/context.mjs.map +1 -0
  33. package/es/base-ui/Tree/index.d.mts +5 -0
  34. package/es/base-ui/Tree/style.d.mts +19 -0
  35. package/es/base-ui/Tree/style.mjs +149 -0
  36. package/es/base-ui/Tree/style.mjs.map +1 -0
  37. package/es/base-ui/Tree/type.d.mts +85 -0
  38. package/es/base-ui/Tree/utils.d.mts +11 -0
  39. package/es/base-ui/Tree/utils.mjs +73 -0
  40. package/es/base-ui/Tree/utils.mjs.map +1 -0
  41. package/es/base-ui/index.d.mts +22 -8
  42. package/es/base-ui/index.mjs +17 -8
  43. package/es/mdx/FileTree/File.mjs +3 -3
  44. package/es/mdx/FileTree/File.mjs.map +1 -1
  45. package/es/mdx/FileTree/Folder.mjs +3 -3
  46. package/es/mdx/FileTree/Folder.mjs.map +1 -1
  47. package/package.json +1 -1
@@ -0,0 +1,175 @@
1
+ "use client";
2
+ import { FocusScope } from "../FocusScope/FocusScope.mjs";
3
+ import { focusScopeItem, useScopeArrowNav } from "../FocusScope/useScopeArrowNav.mjs";
4
+ import { styles } from "./style.mjs";
5
+ import { TreeContext } from "./context.mjs";
6
+ import { conductCheck, flattenVisible, getAllKeys, getAncestorKeys, getSubtreeKeys } from "./utils.mjs";
7
+ import TreeNode from "./TreeNode.mjs";
8
+ import { memo, useId, useMemo, useRef, useState } from "react";
9
+ import { jsx } from "react/jsx-runtime";
10
+ import { cx } from "antd-style";
11
+ import useMergeState from "use-merge-value";
12
+ //#region src/base-ui/Tree/Tree.tsx
13
+ const EMPTY = [];
14
+ const Tree = memo(({ blockNode = false, checkStrictly = false, checkable = false, checkedKeys: checkedKeysProp, className, classNames = {}, defaultCheckedKeys = EMPTY, defaultExpandAll = false, defaultExpandedKeys = EMPTY, defaultSelectedKeys = EMPTY, disabled = false, expandedKeys: expandedKeysProp, indent = 20, multiple = false, onCheck, onExpand, onRightClick, onSelect, scopeId: scopeIdProp, selectedKeys: selectedKeysProp, showIcon = false, showLine = false, size = "middle", style, styles: customStyles = {}, switcherIcon, titleRender, treeData, vimKeys = false }) => {
15
+ const generatedId = useId();
16
+ const scopeId = scopeIdProp ?? generatedId;
17
+ const [expandedKeys, setExpandedKeys] = useMergeState(defaultExpandAll ? getAllKeys(treeData) : defaultExpandedKeys, { value: expandedKeysProp });
18
+ const [selectedKeys, setSelectedKeys] = useMergeState(defaultSelectedKeys, { value: selectedKeysProp });
19
+ const [checkedKeys, setCheckedKeys] = useMergeState(defaultCheckedKeys, { value: checkedKeysProp });
20
+ const expanded = useMemo(() => new Set(expandedKeys), [expandedKeys]);
21
+ const selected = useMemo(() => new Set(selectedKeys), [selectedKeys]);
22
+ const flat = useMemo(() => flattenVisible(treeData, expanded), [treeData, expanded]);
23
+ const { checked, halfChecked } = useMemo(() => checkStrictly ? {
24
+ checked: new Set(checkedKeys),
25
+ halfChecked: /* @__PURE__ */ new Set()
26
+ } : conductCheck(treeData, checkedKeys), [
27
+ checkStrictly,
28
+ treeData,
29
+ checkedKeys
30
+ ]);
31
+ const [activeKeyState, setActiveKeyState] = useState(null);
32
+ const setActiveKey = setActiveKeyState;
33
+ const activeKey = activeKeyState && flat.some((row) => row.node.key === activeKeyState) ? activeKeyState : selectedKeys.find((key) => flat.some((row) => row.node.key === key)) ?? flat[0]?.node.key ?? null;
34
+ const anchorRef = useRef(null);
35
+ const rowOf = (key) => document.querySelector(`[data-focus-scope="${scopeId}"] [data-id="${key}"]`);
36
+ const focusRow = (key) => {
37
+ setActiveKey(key);
38
+ const row = rowOf(key);
39
+ if (row) focusScopeItem(scopeId, row);
40
+ };
41
+ const isDisabled = (node) => disabled || !!node.disabled;
42
+ const toggleExpand = (node) => {
43
+ const willExpand = !expanded.has(node.key);
44
+ const next = willExpand ? [...expandedKeys, node.key] : expandedKeys.filter((key) => key !== node.key);
45
+ setExpandedKeys(next);
46
+ onExpand?.(next, {
47
+ expanded: willExpand,
48
+ node
49
+ });
50
+ };
51
+ const toggleSelect = (node, event) => {
52
+ if (isDisabled(node) || node.selectable === false) return;
53
+ let next;
54
+ if (multiple && event?.shiftKey && anchorRef.current) {
55
+ const a = flat.findIndex((row) => row.node.key === anchorRef.current);
56
+ const b = flat.findIndex((row) => row.node.key === node.key);
57
+ next = flat.slice(Math.min(a, b), Math.max(a, b) + 1).filter((row) => !isDisabled(row.node) && row.node.selectable !== false).map((row) => row.node.key);
58
+ } else if (multiple && (event?.metaKey || event?.ctrlKey)) {
59
+ next = selected.has(node.key) ? selectedKeys.filter((key) => key !== node.key) : [...selectedKeys, node.key];
60
+ anchorRef.current = node.key;
61
+ } else {
62
+ next = [node.key];
63
+ anchorRef.current = node.key;
64
+ }
65
+ setSelectedKeys(next);
66
+ setActiveKey(node.key);
67
+ onSelect?.(next, {
68
+ node,
69
+ selected: next.includes(node.key)
70
+ });
71
+ };
72
+ const toggleCheck = (node) => {
73
+ if (isDisabled(node) || node.checkable === false) return;
74
+ const willCheck = !checked.has(node.key);
75
+ const keys = checkStrictly ? [node.key] : getSubtreeKeys(node);
76
+ const base = new Set(checkStrictly ? checkedKeys : checked);
77
+ keys.forEach((key) => willCheck ? base.add(key) : base.delete(key));
78
+ if (!willCheck && !checkStrictly) getAncestorKeys(treeData, node.key).forEach((key) => base.delete(key));
79
+ const next = checkStrictly ? [...base] : [...conductCheck(treeData, base).checked];
80
+ setCheckedKeys(next);
81
+ setActiveKey(node.key);
82
+ onCheck?.(next, {
83
+ checked: willCheck,
84
+ node
85
+ });
86
+ };
87
+ const currentRow = () => {
88
+ const key = (document.activeElement?.closest("[role=\"treeitem\"]"))?.dataset.id ?? activeKey;
89
+ return flat.find((row) => row.node.key === key);
90
+ };
91
+ const withRow = (fn) => (event) => {
92
+ const row = currentRow();
93
+ if (row) fn(row, event);
94
+ };
95
+ useScopeArrowNav({
96
+ extra: {
97
+ " ": withRow((row, event) => {
98
+ if (checkable && row.node.checkable !== false) toggleCheck(row.node);
99
+ else toggleSelect(row.node, event);
100
+ }),
101
+ "*": withRow((row) => {
102
+ const siblings = flat.filter((r) => r.parentKey === row.parentKey && r.hasChildren && !expanded.has(r.node.key));
103
+ if (siblings.length === 0) return;
104
+ const next = [...expandedKeys, ...siblings.map((r) => r.node.key)];
105
+ setExpandedKeys(next);
106
+ onExpand?.(next, {
107
+ expanded: true,
108
+ node: row.node
109
+ });
110
+ }),
111
+ ArrowLeft: withRow((row) => {
112
+ if (row.hasChildren && expanded.has(row.node.key)) toggleExpand(row.node);
113
+ else if (row.parentKey) focusRow(row.parentKey);
114
+ }),
115
+ ArrowRight: withRow((row) => {
116
+ if (!row.hasChildren) return;
117
+ if (expanded.has(row.node.key)) focusRow(flat[row.index + 1].node.key);
118
+ else toggleExpand(row.node);
119
+ }),
120
+ Enter: withRow((row, event) => toggleSelect(row.node, event))
121
+ },
122
+ itemSelector: "[role=\"treeitem\"]",
123
+ onItemFocus: (el) => el.dataset.id && setActiveKey(el.dataset.id),
124
+ scopeId,
125
+ vimKeys
126
+ });
127
+ return /* @__PURE__ */ jsx(TreeContext, {
128
+ value: {
129
+ activeKey,
130
+ blockNode,
131
+ checkable,
132
+ checked,
133
+ classNames,
134
+ disabled,
135
+ expanded,
136
+ halfChecked,
137
+ indent,
138
+ onRightClick: (event, node) => onRightClick?.({
139
+ event,
140
+ node
141
+ }),
142
+ selected,
143
+ setActiveKey,
144
+ showIcon,
145
+ showLine,
146
+ size,
147
+ styles: customStyles,
148
+ switcherIcon,
149
+ titleRender,
150
+ toggleCheck,
151
+ toggleExpand,
152
+ toggleSelect
153
+ },
154
+ children: /* @__PURE__ */ jsx(FocusScope, {
155
+ className: cx(styles.root, classNames.root, className),
156
+ id: scopeId,
157
+ role: "tree",
158
+ style: {
159
+ ...customStyles.root,
160
+ ...style
161
+ },
162
+ children: treeData.map((node, i) => /* @__PURE__ */ jsx(TreeNode, {
163
+ depth: 0,
164
+ isLast: i === treeData.length - 1,
165
+ node,
166
+ trail: []
167
+ }, node.key))
168
+ })
169
+ });
170
+ });
171
+ Tree.displayName = "Tree";
172
+ //#endregion
173
+ export { Tree as default };
174
+
175
+ //# sourceMappingURL=Tree.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tree.mjs","names":["useControlledState"],"sources":["../../../src/base-ui/Tree/Tree.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { memo, useId, useMemo, useRef, useState } from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { FocusScope, focusScopeItem, useScopeArrowNav } from '@/base-ui/FocusScope';\n\nimport { TreeContext, type TreeContextValue } from './context';\nimport { styles } from './style';\nimport TreeNode from './TreeNode';\nimport type { TreeDataNode, TreeProps } from './type';\nimport { conductCheck, flattenVisible, getAllKeys, getAncestorKeys, getSubtreeKeys } from './utils';\n\nconst EMPTY: string[] = [];\n\nconst Tree = memo<TreeProps>(\n ({\n blockNode = false,\n checkStrictly = false,\n checkable = false,\n checkedKeys: checkedKeysProp,\n className,\n classNames = {},\n defaultCheckedKeys = EMPTY,\n defaultExpandAll = false,\n defaultExpandedKeys = EMPTY,\n defaultSelectedKeys = EMPTY,\n disabled = false,\n expandedKeys: expandedKeysProp,\n indent = 20,\n multiple = false,\n onCheck,\n onExpand,\n onRightClick,\n onSelect,\n scopeId: scopeIdProp,\n selectedKeys: selectedKeysProp,\n showIcon = false,\n showLine = false,\n size = 'middle',\n style,\n styles: customStyles = {},\n switcherIcon,\n titleRender,\n treeData,\n vimKeys = false,\n }) => {\n const generatedId = useId();\n const scopeId = scopeIdProp ?? generatedId;\n const [expandedKeys, setExpandedKeys] = useControlledState<string[]>(\n defaultExpandAll ? getAllKeys(treeData) : defaultExpandedKeys,\n { value: expandedKeysProp },\n );\n const [selectedKeys, setSelectedKeys] = useControlledState<string[]>(defaultSelectedKeys, {\n value: selectedKeysProp,\n });\n const [checkedKeys, setCheckedKeys] = useControlledState<string[]>(defaultCheckedKeys, {\n value: checkedKeysProp,\n });\n\n const expanded = useMemo(() => new Set(expandedKeys), [expandedKeys]);\n const selected = useMemo(() => new Set(selectedKeys), [selectedKeys]);\n const flat = useMemo(() => flattenVisible(treeData, expanded), [treeData, expanded]);\n const { checked, halfChecked } = useMemo(\n () =>\n checkStrictly\n ? { checked: new Set(checkedKeys), halfChecked: new Set<string>() }\n : conductCheck(treeData, checkedKeys),\n [checkStrictly, treeData, checkedKeys],\n );\n\n const [activeKeyState, setActiveKeyState] = useState<string | null>(null);\n const setActiveKey = setActiveKeyState;\n const activeKey =\n activeKeyState && flat.some((row) => row.node.key === activeKeyState)\n ? activeKeyState\n : (selectedKeys.find((key) => flat.some((row) => row.node.key === key)) ??\n flat[0]?.node.key ??\n null);\n\n const anchorRef = useRef<string | null>(null);\n\n const rowOf = (key: string) =>\n document.querySelector<HTMLElement>(`[data-focus-scope=\"${scopeId}\"] [data-id=\"${key}\"]`);\n const focusRow = (key: string) => {\n setActiveKey(key);\n const row = rowOf(key);\n if (row) focusScopeItem(scopeId, row);\n };\n\n const isDisabled = (node: TreeDataNode) => disabled || !!node.disabled;\n\n const toggleExpand = (node: TreeDataNode) => {\n const willExpand = !expanded.has(node.key);\n const next = willExpand\n ? [...expandedKeys, node.key]\n : expandedKeys.filter((key) => key !== node.key);\n setExpandedKeys(next);\n onExpand?.(next, { expanded: willExpand, node });\n };\n\n const toggleSelect: TreeContextValue['toggleSelect'] = (node, event) => {\n if (isDisabled(node) || node.selectable === false) return;\n let next: string[];\n if (multiple && event?.shiftKey && anchorRef.current) {\n const a = flat.findIndex((row) => row.node.key === anchorRef.current);\n const b = flat.findIndex((row) => row.node.key === node.key);\n next = flat\n .slice(Math.min(a, b), Math.max(a, b) + 1)\n .filter((row) => !isDisabled(row.node) && row.node.selectable !== false)\n .map((row) => row.node.key);\n } else if (multiple && (event?.metaKey || event?.ctrlKey)) {\n next = selected.has(node.key)\n ? selectedKeys.filter((key) => key !== node.key)\n : [...selectedKeys, node.key];\n anchorRef.current = node.key;\n } else {\n next = [node.key];\n anchorRef.current = node.key;\n }\n setSelectedKeys(next);\n setActiveKey(node.key);\n onSelect?.(next, { node, selected: next.includes(node.key) });\n };\n\n const toggleCheck = (node: TreeDataNode) => {\n if (isDisabled(node) || node.checkable === false) return;\n const willCheck = !checked.has(node.key);\n const keys = checkStrictly ? [node.key] : getSubtreeKeys(node);\n const base = new Set(checkStrictly ? checkedKeys : checked);\n keys.forEach((key) => (willCheck ? base.add(key) : base.delete(key)));\n if (!willCheck && !checkStrictly) getAncestorKeys(treeData, node.key).forEach((key) => base.delete(key));\n const next = checkStrictly ? [...base] : [...conductCheck(treeData, base).checked];\n setCheckedKeys(next);\n setActiveKey(node.key);\n onCheck?.(next, { checked: willCheck, node });\n };\n\n const currentRow = () => {\n const focused = document.activeElement?.closest<HTMLElement>('[role=\"treeitem\"]');\n const key = focused?.dataset.id ?? activeKey;\n return flat.find((row) => row.node.key === key);\n };\n\n const withRow = (fn: (row: (typeof flat)[number], event: KeyboardEvent) => void) =>\n (event: KeyboardEvent) => {\n const row = currentRow();\n if (row) fn(row, event);\n };\n\n useScopeArrowNav({\n extra: {\n ' ': withRow((row, event) => {\n if (checkable && row.node.checkable !== false) toggleCheck(row.node);\n else toggleSelect(row.node, event);\n }),\n '*': withRow((row) => {\n const siblings = flat.filter(\n (r) => r.parentKey === row.parentKey && r.hasChildren && !expanded.has(r.node.key),\n );\n if (siblings.length === 0) return;\n const next = [...expandedKeys, ...siblings.map((r) => r.node.key)];\n setExpandedKeys(next);\n onExpand?.(next, { expanded: true, node: row.node });\n }),\n ArrowLeft: withRow((row) => {\n if (row.hasChildren && expanded.has(row.node.key)) toggleExpand(row.node);\n else if (row.parentKey) focusRow(row.parentKey);\n }),\n ArrowRight: withRow((row) => {\n if (!row.hasChildren) return;\n if (expanded.has(row.node.key)) focusRow(flat[row.index + 1].node.key);\n else toggleExpand(row.node);\n }),\n Enter: withRow((row, event) => toggleSelect(row.node, event)),\n },\n itemSelector: '[role=\"treeitem\"]',\n onItemFocus: (el) => el.dataset.id && setActiveKey(el.dataset.id),\n scopeId,\n vimKeys,\n });\n\n const ctx: TreeContextValue = {\n activeKey,\n blockNode,\n checkable,\n checked,\n classNames,\n disabled,\n expanded,\n halfChecked,\n indent,\n onRightClick: (event, node) => onRightClick?.({ event, node }),\n selected,\n setActiveKey,\n showIcon,\n showLine,\n size,\n styles: customStyles,\n switcherIcon,\n titleRender,\n toggleCheck,\n toggleExpand,\n toggleSelect,\n };\n\n return (\n <TreeContext value={ctx}>\n <FocusScope\n className={cx(styles.root, classNames.root, className)}\n id={scopeId}\n role=\"tree\"\n style={{ ...customStyles.root, ...style }}\n >\n {treeData.map((node, i) => (\n <TreeNode\n depth={0}\n isLast={i === treeData.length - 1}\n key={node.key}\n node={node}\n trail={[]}\n />\n ))}\n </FocusScope>\n </TreeContext>\n );\n },\n);\n\nTree.displayName = 'Tree';\n\nexport default Tree;\n"],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ "use client";
2
+ import Icon from "../../Icon/Icon.mjs";
3
+ import { controlHeight } from "../controlSize.mjs";
4
+ import Checkbox from "../Checkbox/Checkbox.mjs";
5
+ import { styles } from "./style.mjs";
6
+ import { useTreeContext } from "./context.mjs";
7
+ import { hasChildren } from "./utils.mjs";
8
+ import { memo } from "react";
9
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
+ import { cx } from "antd-style";
11
+ import { ChevronRight, File, Folder } from "lucide-react";
12
+ import { Collapsible } from "@base-ui/react/collapsible";
13
+ //#region src/base-ui/Tree/TreeNode.tsx
14
+ const ARC = 6;
15
+ const SWITCHER_CENTER = 11.5;
16
+ const guidePath = (depth, isLast, trail, indent, height) => {
17
+ const cx = (i) => i * indent + SWITCHER_CENTER;
18
+ let d = "";
19
+ trail.forEach((more, i) => {
20
+ if (more && i > 0) d += `M${cx(i)} 0V${height}`;
21
+ });
22
+ const x = cx(depth - 1);
23
+ const y = height / 2;
24
+ const elbow = `M${x} ${y - ARC}A${ARC} ${ARC} 0 0 0 ${x + ARC} ${y}H${x + indent - 2}`;
25
+ d += isLast ? `M${x} 0V${y - ARC}${elbow.slice(elbow.indexOf("A"))}` : `M${x} 0V${height}${elbow}`;
26
+ return d;
27
+ };
28
+ const TreeNode = memo(({ node, depth, isLast, trail }) => {
29
+ const ctx = useTreeContext();
30
+ const expandable = hasChildren(node);
31
+ const expanded = expandable && ctx.expanded.has(node.key);
32
+ const disabled = ctx.disabled || !!node.disabled;
33
+ const checkable = ctx.checkable && node.checkable !== false;
34
+ const checkState = ctx.checked.has(node.key) ? "checked" : ctx.halfChecked.has(node.key) ? "mixed" : "unchecked";
35
+ const rowHeight = typeof ctx.styles.node?.height === "number" ? ctx.styles.node.height : controlHeight[ctx.size];
36
+ const switcherIcon = typeof ctx.switcherIcon === "function" ? ctx.switcherIcon({
37
+ expanded,
38
+ node
39
+ }) : ctx.switcherIcon ?? /* @__PURE__ */ jsx(Icon, {
40
+ icon: ChevronRight,
41
+ size: 14
42
+ });
43
+ const rowStyle = {
44
+ height: rowHeight,
45
+ paddingInlineStart: depth * ctx.indent,
46
+ ...ctx.styles.node
47
+ };
48
+ const select = (event) => ctx.toggleSelect(node, event);
49
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
50
+ "data-scope-item": true,
51
+ "aria-disabled": disabled || void 0,
52
+ "aria-expanded": expandable ? expanded : void 0,
53
+ "aria-level": depth + 1,
54
+ "aria-selected": ctx.selected.has(node.key),
55
+ "data-id": node.key,
56
+ role: "treeitem",
57
+ style: rowStyle,
58
+ tabIndex: ctx.activeKey === node.key ? 0 : -1,
59
+ "aria-checked": checkable ? checkState === "mixed" ? "mixed" : checkState === "checked" : void 0,
60
+ className: cx(styles.node, ctx.blockNode && styles.nodeBlock, disabled && styles.nodeDisabled, ctx.classNames.node),
61
+ onClick: ctx.blockNode ? select : void 0,
62
+ onContextMenu: (event) => ctx.onRightClick(event, node),
63
+ onFocus: () => ctx.setActiveKey(node.key),
64
+ children: [
65
+ ctx.showLine && depth > 0 && /* @__PURE__ */ jsx("svg", {
66
+ "aria-hidden": true,
67
+ className: cx(styles.guide, ctx.classNames.guide),
68
+ height: rowHeight,
69
+ style: ctx.styles.guide,
70
+ width: depth * ctx.indent,
71
+ children: /* @__PURE__ */ jsx("path", { d: guidePath(depth, isLast, trail, ctx.indent, rowHeight) })
72
+ }),
73
+ /* @__PURE__ */ jsx("button", {
74
+ "aria-hidden": true,
75
+ style: ctx.styles.switcher,
76
+ tabIndex: -1,
77
+ type: "button",
78
+ className: cx(styles.switcher, !expandable && styles.switcherLeaf, ctx.classNames.switcher),
79
+ onClick: (event) => {
80
+ event.stopPropagation();
81
+ ctx.toggleExpand(node);
82
+ },
83
+ children: switcherIcon
84
+ }),
85
+ checkable && /* @__PURE__ */ jsx(Checkbox, {
86
+ checked: checkState === "checked",
87
+ className: styles.checkbox,
88
+ disabled,
89
+ indeterminate: checkState === "mixed",
90
+ onChange: () => ctx.toggleCheck(node),
91
+ onClick: (event) => event.stopPropagation()
92
+ }),
93
+ ctx.showIcon && /* @__PURE__ */ jsx("span", {
94
+ className: styles.icon,
95
+ children: node.icon ?? /* @__PURE__ */ jsx(Icon, {
96
+ icon: expandable ? Folder : File,
97
+ size: 16
98
+ })
99
+ }),
100
+ /* @__PURE__ */ jsx("span", {
101
+ style: ctx.styles.title,
102
+ className: cx(styles.title, ctx.blockNode ? styles.titleBlock : styles.titleInline, ctx.classNames.title),
103
+ onClick: ctx.blockNode ? void 0 : select,
104
+ children: ctx.titleRender ? ctx.titleRender(node) : node.title
105
+ })
106
+ ]
107
+ }), expandable && /* @__PURE__ */ jsx(Collapsible.Root, {
108
+ open: expanded,
109
+ children: /* @__PURE__ */ jsx(Collapsible.Panel, {
110
+ className: styles.panel,
111
+ children: node.children.map((child, i) => /* @__PURE__ */ jsx(TreeNode, {
112
+ depth: depth + 1,
113
+ isLast: i === node.children.length - 1,
114
+ node: child,
115
+ trail: [...trail, !isLast]
116
+ }, child.key))
117
+ })
118
+ })] });
119
+ });
120
+ TreeNode.displayName = "TreeNode";
121
+ //#endregion
122
+ export { TreeNode as default };
123
+
124
+ //# sourceMappingURL=TreeNode.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TreeNode.mjs","names":["isExpandable"],"sources":["../../../src/base-ui/Tree/TreeNode.tsx"],"sourcesContent":["'use client';\n\nimport { Collapsible } from '@base-ui/react/collapsible';\nimport { cx } from 'antd-style';\nimport { ChevronRight, File, Folder } from 'lucide-react';\nimport { type CSSProperties, memo, type MouseEvent } from 'react';\n\nimport { Checkbox } from '@/base-ui/Checkbox';\nimport { controlHeight } from '@/base-ui/controlSize';\nimport Icon from '@/Icon';\n\nimport { useTreeContext } from './context';\nimport { styles } from './style';\nimport type { TreeDataNode } from './type';\nimport { hasChildren as isExpandable } from './utils';\n\ninterface TreeNodeProps {\n depth: number;\n isLast: boolean;\n node: TreeDataNode;\n trail: boolean[];\n}\n\nconst ARC = 6;\nconst SWITCHER_CENTER = 11.5;\n\nconst guidePath = (\n depth: number,\n isLast: boolean,\n trail: boolean[],\n indent: number,\n height: number,\n) => {\n const cx = (i: number) => i * indent + SWITCHER_CENTER;\n let d = '';\n trail.forEach((more, i) => {\n if (more && i > 0) d += `M${cx(i)} 0V${height}`;\n });\n const x = cx(depth - 1);\n const y = height / 2;\n const elbow = `M${x} ${y - ARC}A${ARC} ${ARC} 0 0 0 ${x + ARC} ${y}H${x + indent - 2}`;\n d += isLast\n ? `M${x} 0V${y - ARC}${elbow.slice(elbow.indexOf('A'))}`\n : `M${x} 0V${height}${elbow}`;\n return d;\n};\n\nconst TreeNode = memo<TreeNodeProps>(({ node, depth, isLast, trail }) => {\n const ctx = useTreeContext();\n const expandable = isExpandable(node);\n const expanded = expandable && ctx.expanded.has(node.key);\n const disabled = ctx.disabled || !!node.disabled;\n const checkable = ctx.checkable && node.checkable !== false;\n const checkState = ctx.checked.has(node.key)\n ? 'checked'\n : ctx.halfChecked.has(node.key)\n ? 'mixed'\n : 'unchecked';\n const rowHeight =\n typeof ctx.styles.node?.height === 'number' ? ctx.styles.node.height : controlHeight[ctx.size];\n\n const switcherIcon =\n typeof ctx.switcherIcon === 'function'\n ? ctx.switcherIcon({ expanded, node })\n : (ctx.switcherIcon ?? <Icon icon={ChevronRight} size={14} />);\n\n const rowStyle: CSSProperties = {\n height: rowHeight,\n paddingInlineStart: depth * ctx.indent,\n ...ctx.styles.node,\n };\n\n const select = (event: MouseEvent) => ctx.toggleSelect(node, event);\n\n return (\n <>\n <div\n data-scope-item\n aria-disabled={disabled || undefined}\n aria-expanded={expandable ? expanded : undefined}\n aria-level={depth + 1}\n aria-selected={ctx.selected.has(node.key)}\n data-id={node.key}\n role=\"treeitem\"\n style={rowStyle}\n tabIndex={ctx.activeKey === node.key ? 0 : -1}\n aria-checked={\n checkable ? (checkState === 'mixed' ? 'mixed' : checkState === 'checked') : undefined\n }\n className={cx(\n styles.node,\n ctx.blockNode && styles.nodeBlock,\n disabled && styles.nodeDisabled,\n ctx.classNames.node,\n )}\n onClick={ctx.blockNode ? select : undefined}\n onContextMenu={(event) => ctx.onRightClick(event, node)}\n onFocus={() => ctx.setActiveKey(node.key)}\n >\n {ctx.showLine && depth > 0 && (\n <svg\n aria-hidden\n className={cx(styles.guide, ctx.classNames.guide)}\n height={rowHeight}\n style={ctx.styles.guide}\n width={depth * ctx.indent}\n >\n <path d={guidePath(depth, isLast, trail, ctx.indent, rowHeight)} />\n </svg>\n )}\n <button\n aria-hidden\n style={ctx.styles.switcher}\n tabIndex={-1}\n type=\"button\"\n className={cx(\n styles.switcher,\n !expandable && styles.switcherLeaf,\n ctx.classNames.switcher,\n )}\n onClick={(event) => {\n event.stopPropagation();\n ctx.toggleExpand(node);\n }}\n >\n {switcherIcon}\n </button>\n {checkable && (\n <Checkbox\n checked={checkState === 'checked'}\n className={styles.checkbox}\n disabled={disabled}\n indeterminate={checkState === 'mixed'}\n onChange={() => ctx.toggleCheck(node)}\n onClick={(event) => event.stopPropagation()}\n />\n )}\n {ctx.showIcon && (\n <span className={styles.icon}>\n {node.icon ?? <Icon icon={expandable ? Folder : File} size={16} />}\n </span>\n )}\n <span\n style={ctx.styles.title}\n className={cx(\n styles.title,\n ctx.blockNode ? styles.titleBlock : styles.titleInline,\n ctx.classNames.title,\n )}\n onClick={ctx.blockNode ? undefined : select}\n >\n {ctx.titleRender ? ctx.titleRender(node) : node.title}\n </span>\n </div>\n {expandable && (\n <Collapsible.Root open={expanded}>\n <Collapsible.Panel className={styles.panel}>\n {node.children!.map((child, i) => (\n <TreeNode\n depth={depth + 1}\n isLast={i === node.children!.length - 1}\n key={child.key}\n node={child}\n trail={[...trail, !isLast]}\n />\n ))}\n </Collapsible.Panel>\n </Collapsible.Root>\n )}\n </>\n );\n});\n\nTreeNode.displayName = 'TreeNode';\n\nexport default TreeNode;\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { createContext, use } from "react";
2
+ //#region src/base-ui/Tree/context.ts
3
+ const TreeContext = createContext(null);
4
+ const useTreeContext = () => {
5
+ const ctx = use(TreeContext);
6
+ if (!ctx) throw new Error("Tree components must be rendered inside <Tree>");
7
+ return ctx;
8
+ };
9
+ //#endregion
10
+ export { TreeContext, useTreeContext };
11
+
12
+ //# sourceMappingURL=context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.mjs","names":[],"sources":["../../../src/base-ui/Tree/context.ts"],"sourcesContent":["import { createContext, type MouseEvent, type ReactNode, use } from 'react';\n\nimport type { ControlSize } from '../controlSize';\nimport type { TreeClassNames, TreeDataNode, TreeProps, TreeStyles } from './type';\n\nexport interface TreeContextValue {\n activeKey: string | null;\n blockNode: boolean;\n checkable: boolean;\n checked: Set<string>;\n classNames: TreeClassNames;\n disabled: boolean;\n expanded: Set<string>;\n halfChecked: Set<string>;\n indent: number;\n onRightClick: (event: MouseEvent<HTMLDivElement>, node: TreeDataNode) => void;\n selected: Set<string>;\n setActiveKey: (key: string) => void;\n showIcon: boolean;\n showLine: boolean;\n size: ControlSize;\n styles: TreeStyles;\n switcherIcon?: TreeProps['switcherIcon'];\n titleRender?: (node: TreeDataNode) => ReactNode;\n toggleCheck: (node: TreeDataNode) => void;\n toggleExpand: (node: TreeDataNode) => void;\n toggleSelect: (node: TreeDataNode, event?: { metaKey?: boolean; ctrlKey?: boolean; shiftKey?: boolean }) => void;\n}\n\nexport const TreeContext = createContext<TreeContextValue | null>(null);\n\nexport const useTreeContext = () => {\n const ctx = use(TreeContext);\n if (!ctx) throw new Error('Tree components must be rendered inside <Tree>');\n return ctx;\n};\n"],"mappings":";;AA6BA,MAAa,cAAc,cAAuC,IAAI;AAEtE,MAAa,uBAAuB;CAClC,MAAM,MAAM,IAAI,WAAW;CAC3B,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,gDAAgD;CAC1E,OAAO;AACT"}
@@ -0,0 +1,5 @@
1
+ import { styles } from "./style.mjs";
2
+ import { TreeClassNames, TreeDataNode, TreeFlatRow, TreeProps, TreeStyles } from "./type.mjs";
3
+ import Tree from "./Tree.mjs";
4
+ import { conductCheck, flattenVisible, getAllKeys } from "./utils.mjs";
5
+ export { type TreeClassNames, type TreeDataNode, type TreeFlatRow, type TreeProps, type TreeStyles, conductCheck, Tree as default, flattenVisible, getAllKeys, styles as treeStyles };
@@ -0,0 +1,19 @@
1
+ //#region src/base-ui/Tree/style.d.ts
2
+ declare const styles: {
3
+ checkbox: string;
4
+ guide: string;
5
+ icon: string;
6
+ node: string;
7
+ nodeBlock: string;
8
+ nodeDisabled: string;
9
+ panel: string;
10
+ root: string;
11
+ switcher: string;
12
+ switcherLeaf: string;
13
+ title: string;
14
+ titleBlock: string;
15
+ titleInline: string;
16
+ };
17
+ //#endregion
18
+ export { styles };
19
+ //# sourceMappingURL=style.d.mts.map
@@ -0,0 +1,149 @@
1
+ import { focusRing } from "../focusRing.mjs";
2
+ import { createStaticStyles } from "antd-style";
3
+ //#region src/base-ui/Tree/style.ts
4
+ const styles = createStaticStyles(({ css, cssVar }) => ({
5
+ checkbox: css`
6
+ margin-inline-end: 8px;
7
+ `,
8
+ guide: css`
9
+ pointer-events: none;
10
+ position: absolute;
11
+ inset-block-start: 0;
12
+ inset-inline-start: 0;
13
+ height: 100%;
14
+ overflow: visible;
15
+
16
+ path {
17
+ fill: none;
18
+ stroke: ${cssVar.colorBorderSecondary};
19
+ stroke-width: 1;
20
+ stroke-linecap: round;
21
+ }
22
+ `,
23
+ icon: css`
24
+ display: inline-flex;
25
+ flex: none;
26
+ align-items: center;
27
+ margin-inline-end: 6px;
28
+ color: ${cssVar.colorTextSecondary};
29
+ `,
30
+ node: css`
31
+ position: relative;
32
+ display: flex;
33
+ align-items: center;
34
+ border-radius: ${cssVar.borderRadius};
35
+ color: ${cssVar.colorText};
36
+ outline: none;
37
+ ${focusRing}
38
+ `,
39
+ nodeBlock: css`
40
+ cursor: pointer;
41
+
42
+ &:hover {
43
+ background: ${cssVar.colorFillTertiary};
44
+ }
45
+
46
+ &[aria-selected='true'] {
47
+ background: ${cssVar.colorFillSecondary};
48
+ }
49
+ `,
50
+ nodeDisabled: css`
51
+ cursor: not-allowed;
52
+ color: ${cssVar.colorTextDisabled};
53
+
54
+ &:hover {
55
+ background: transparent;
56
+ }
57
+ `,
58
+ panel: css`
59
+ height: var(--collapsible-panel-height);
60
+ overflow: hidden;
61
+ transition: height 200ms ${cssVar.motionEaseOut};
62
+
63
+ &[data-starting-style],
64
+ &[data-ending-style] {
65
+ height: 0;
66
+ }
67
+
68
+ @media (prefers-reduced-motion: reduce) {
69
+ transition-duration: 0s;
70
+ }
71
+ `,
72
+ root: css`
73
+ display: flex;
74
+ flex-direction: column;
75
+ user-select: none;
76
+ outline: none;
77
+ `,
78
+ switcher: css`
79
+ display: grid;
80
+ flex: none;
81
+ place-items: center;
82
+ width: 24px;
83
+ height: 24px;
84
+ padding: 0;
85
+ border: 0;
86
+ border-radius: ${cssVar.borderRadiusSM};
87
+ background: none;
88
+ color: ${cssVar.colorTextSecondary};
89
+ cursor: pointer;
90
+
91
+ &:hover {
92
+ background: ${cssVar.colorFillSecondary};
93
+ color: ${cssVar.colorText};
94
+ }
95
+
96
+ svg {
97
+ transition: transform 200ms ${cssVar.motionEaseOut};
98
+ }
99
+
100
+ [aria-expanded='true'] > & svg {
101
+ transform: rotate(90deg);
102
+ }
103
+
104
+ @media (prefers-reduced-motion: reduce) {
105
+ svg {
106
+ transition-duration: 0s;
107
+ }
108
+ }
109
+ `,
110
+ switcherLeaf: css`
111
+ visibility: hidden;
112
+ pointer-events: none;
113
+ `,
114
+ title: css`
115
+ display: inline-flex;
116
+ align-items: center;
117
+ gap: 6px;
118
+ min-width: 0;
119
+ padding-block: 2px;
120
+ padding-inline: 6px;
121
+ border-radius: ${cssVar.borderRadiusSM};
122
+ overflow: hidden;
123
+ white-space: nowrap;
124
+ text-overflow: ellipsis;
125
+ `,
126
+ titleBlock: css`
127
+ flex: 1;
128
+ `,
129
+ titleInline: css`
130
+ cursor: pointer;
131
+
132
+ &:hover {
133
+ background: ${cssVar.colorFillTertiary};
134
+ }
135
+
136
+ [aria-selected='true'] > & {
137
+ background: ${cssVar.colorFillSecondary};
138
+ }
139
+
140
+ [aria-disabled='true'] > & {
141
+ cursor: not-allowed;
142
+ background: transparent;
143
+ }
144
+ `
145
+ }));
146
+ //#endregion
147
+ export { styles };
148
+
149
+ //# sourceMappingURL=style.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.mjs","names":[],"sources":["../../../src/base-ui/Tree/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nimport { focusRing } from '@/base-ui/focusRing';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n checkbox: css`\n margin-inline-end: 8px;\n `,\n guide: css`\n pointer-events: none;\n position: absolute;\n inset-block-start: 0;\n inset-inline-start: 0;\n height: 100%;\n overflow: visible;\n\n path {\n fill: none;\n stroke: ${cssVar.colorBorderSecondary};\n stroke-width: 1;\n stroke-linecap: round;\n }\n `,\n icon: css`\n display: inline-flex;\n flex: none;\n align-items: center;\n margin-inline-end: 6px;\n color: ${cssVar.colorTextSecondary};\n `,\n node: css`\n position: relative;\n display: flex;\n align-items: center;\n border-radius: ${cssVar.borderRadius};\n color: ${cssVar.colorText};\n outline: none;\n ${focusRing}\n `,\n nodeBlock: css`\n cursor: pointer;\n\n &:hover {\n background: ${cssVar.colorFillTertiary};\n }\n\n &[aria-selected='true'] {\n background: ${cssVar.colorFillSecondary};\n }\n `,\n nodeDisabled: css`\n cursor: not-allowed;\n color: ${cssVar.colorTextDisabled};\n\n &:hover {\n background: transparent;\n }\n `,\n panel: css`\n height: var(--collapsible-panel-height);\n overflow: hidden;\n transition: height 200ms ${cssVar.motionEaseOut};\n\n &[data-starting-style],\n &[data-ending-style] {\n height: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition-duration: 0s;\n }\n `,\n root: css`\n display: flex;\n flex-direction: column;\n user-select: none;\n outline: none;\n `,\n switcher: css`\n display: grid;\n flex: none;\n place-items: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: 0;\n border-radius: ${cssVar.borderRadiusSM};\n background: none;\n color: ${cssVar.colorTextSecondary};\n cursor: pointer;\n\n &:hover {\n background: ${cssVar.colorFillSecondary};\n color: ${cssVar.colorText};\n }\n\n svg {\n transition: transform 200ms ${cssVar.motionEaseOut};\n }\n\n [aria-expanded='true'] > & svg {\n transform: rotate(90deg);\n }\n\n @media (prefers-reduced-motion: reduce) {\n svg {\n transition-duration: 0s;\n }\n }\n `,\n switcherLeaf: css`\n visibility: hidden;\n pointer-events: none;\n `,\n title: css`\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n padding-block: 2px;\n padding-inline: 6px;\n border-radius: ${cssVar.borderRadiusSM};\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n `,\n titleBlock: css`\n flex: 1;\n `,\n titleInline: css`\n cursor: pointer;\n\n &:hover {\n background: ${cssVar.colorFillTertiary};\n }\n\n [aria-selected='true'] > & {\n background: ${cssVar.colorFillSecondary};\n }\n\n [aria-disabled='true'] > & {\n cursor: not-allowed;\n background: transparent;\n }\n `,\n}));\n"],"mappings":";;;AAIA,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,UAAU,GAAG;;;CAGb,OAAO,GAAG;;;;;;;;;;gBAUI,OAAO,qBAAqB;;;;;CAK1C,MAAM,GAAG;;;;;aAKE,OAAO,mBAAmB;;CAErC,MAAM,GAAG;;;;qBAIU,OAAO,aAAa;aAC5B,OAAO,UAAU;;MAExB,UAAU;;CAEd,WAAW,GAAG;;;;oBAII,OAAO,kBAAkB;;;;oBAIzB,OAAO,mBAAmB;;;CAG5C,cAAc,GAAG;;aAEN,OAAO,kBAAkB;;;;;;CAMpC,OAAO,GAAG;;;+BAGmB,OAAO,cAAc;;;;;;;;;;;CAWlD,MAAM,GAAG;;;;;;CAMT,UAAU,GAAG;;;;;;;;qBAQM,OAAO,eAAe;;aAE9B,OAAO,mBAAmB;;;;oBAInB,OAAO,mBAAmB;eAC/B,OAAO,UAAU;;;;oCAII,OAAO,cAAc;;;;;;;;;;;;;CAavD,cAAc,GAAG;;;;CAIjB,OAAO,GAAG;;;;;;;qBAOS,OAAO,eAAe;;;;;CAKzC,YAAY,GAAG;;;CAGf,aAAa,GAAG;;;;oBAIE,OAAO,kBAAkB;;;;oBAIzB,OAAO,mBAAmB;;;;;;;;AAQ9C,EAAE"}
@@ -0,0 +1,85 @@
1
+ import { ControlSize } from "../controlSize.mjs";
2
+ import { CSSProperties, MouseEvent, ReactNode } from "react";
3
+ //#region src/base-ui/Tree/type.d.ts
4
+ interface TreeDataNode {
5
+ checkable?: boolean;
6
+ children?: TreeDataNode[];
7
+ disabled?: boolean;
8
+ icon?: ReactNode;
9
+ isLeaf?: boolean;
10
+ key: string;
11
+ selectable?: boolean;
12
+ title: ReactNode;
13
+ }
14
+ interface TreeFlatRow {
15
+ depth: number;
16
+ hasChildren: boolean;
17
+ index: number;
18
+ isLast: boolean;
19
+ node: TreeDataNode;
20
+ parentKey: string | null;
21
+ trail: boolean[];
22
+ }
23
+ interface TreeClassNames {
24
+ guide?: string;
25
+ node?: string;
26
+ root?: string;
27
+ switcher?: string;
28
+ title?: string;
29
+ }
30
+ interface TreeStyles {
31
+ guide?: CSSProperties;
32
+ node?: CSSProperties;
33
+ root?: CSSProperties;
34
+ switcher?: CSSProperties;
35
+ title?: CSSProperties;
36
+ }
37
+ interface TreeProps {
38
+ blockNode?: boolean;
39
+ checkable?: boolean;
40
+ checkedKeys?: string[];
41
+ checkStrictly?: boolean;
42
+ className?: string;
43
+ classNames?: TreeClassNames;
44
+ defaultCheckedKeys?: string[];
45
+ defaultExpandAll?: boolean;
46
+ defaultExpandedKeys?: string[];
47
+ defaultSelectedKeys?: string[];
48
+ disabled?: boolean;
49
+ expandedKeys?: string[];
50
+ indent?: number;
51
+ multiple?: boolean;
52
+ onCheck?: (keys: string[], info: {
53
+ checked: boolean;
54
+ node: TreeDataNode;
55
+ }) => void;
56
+ onExpand?: (keys: string[], info: {
57
+ expanded: boolean;
58
+ node: TreeDataNode;
59
+ }) => void;
60
+ onRightClick?: (info: {
61
+ event: MouseEvent<HTMLDivElement>;
62
+ node: TreeDataNode;
63
+ }) => void;
64
+ onSelect?: (keys: string[], info: {
65
+ node: TreeDataNode;
66
+ selected: boolean;
67
+ }) => void;
68
+ scopeId?: string;
69
+ selectedKeys?: string[];
70
+ showIcon?: boolean;
71
+ showLine?: boolean;
72
+ size?: ControlSize;
73
+ style?: CSSProperties;
74
+ styles?: TreeStyles;
75
+ switcherIcon?: ReactNode | ((info: {
76
+ expanded: boolean;
77
+ node: TreeDataNode;
78
+ }) => ReactNode);
79
+ titleRender?: (node: TreeDataNode) => ReactNode;
80
+ treeData: TreeDataNode[];
81
+ vimKeys?: boolean;
82
+ }
83
+ //#endregion
84
+ export { TreeClassNames, TreeDataNode, TreeFlatRow, TreeProps, TreeStyles };
85
+ //# sourceMappingURL=type.d.mts.map
@@ -0,0 +1,11 @@
1
+ import { TreeDataNode, TreeFlatRow } from "./type.mjs";
2
+ //#region src/base-ui/Tree/utils.d.ts
3
+ declare const flattenVisible: (data: TreeDataNode[], expanded: Set<string>, depth?: number, parentKey?: string | null, trail?: boolean[], out?: TreeFlatRow[]) => TreeFlatRow[];
4
+ declare const getAllKeys: (data: TreeDataNode[], out?: string[]) => string[];
5
+ declare const conductCheck: (data: TreeDataNode[], checkedKeys: Iterable<string>) => {
6
+ checked: Set<string>;
7
+ halfChecked: Set<string>;
8
+ };
9
+ //#endregion
10
+ export { conductCheck, flattenVisible, getAllKeys };
11
+ //# sourceMappingURL=utils.d.mts.map