@react-fabric/data 1.0.0-beta.8 → 1.0.1

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 (141) hide show
  1. package/{src/histogram/Histogram.module.css → css/_histogram.css} +16 -13
  2. package/css/styles.css +24 -0
  3. package/dist/cjs/checklist/CheckList.js +59 -33
  4. package/dist/cjs/histogram/Histogram.js +41 -26
  5. package/dist/cjs/hooks/useFilteredList.js +100 -17
  6. package/dist/cjs/hooks/usePagination.js +29 -8
  7. package/dist/cjs/hooks/useSelectableList.js +30 -5
  8. package/dist/cjs/i18n/{ar.json.js → ar/data.json.js} +8 -1
  9. package/dist/cjs/i18n/{en.json.js → en/data.json.js} +8 -1
  10. package/dist/cjs/i18n/index.js +4 -4
  11. package/dist/cjs/index.js +30 -0
  12. package/dist/cjs/json/JsonViewer.js +80 -43
  13. package/dist/cjs/pagination/Pagination.js +24 -15
  14. package/dist/cjs/table/AddColumn.js +5 -5
  15. package/dist/cjs/table/BodyCell.js +20 -13
  16. package/dist/cjs/table/BodyRow.js +41 -28
  17. package/dist/cjs/table/CheckboxCell.js +10 -9
  18. package/dist/cjs/table/ColumnFilters.js +100 -0
  19. package/dist/cjs/table/EmptyCell.js +4 -4
  20. package/dist/cjs/table/HeaderCell.js +79 -53
  21. package/dist/cjs/table/HtmlTable.js +84 -0
  22. package/dist/cjs/table/{Context.js → Provider.js} +8 -10
  23. package/dist/cjs/table/Table.js +99 -33
  24. package/dist/cjs/{tree/types.js → table/context.js} +9 -5
  25. package/dist/cjs/table/types.js +29 -0
  26. package/dist/cjs/table/useResizer.js +10 -10
  27. package/dist/cjs/table/useTableColumns.js +4 -4
  28. package/dist/cjs/table/useVirtualTable.js +129 -22
  29. package/dist/cjs/tree/TreeNode.js +66 -46
  30. package/dist/cjs/tree/TreePanel.js +60 -24
  31. package/dist/cjs/tree/useTree.js +212 -47
  32. package/dist/cjs/tree/utils.js +63 -34
  33. package/dist/cjs/utils/getColor.js +58 -0
  34. package/dist/cjs/virtual/Gallery.js +119 -61
  35. package/dist/cjs/virtual/List.js +116 -55
  36. package/dist/cjs/virtual/Scroller.js +16 -8
  37. package/dist/esm/checklist/CheckList.js +61 -35
  38. package/dist/esm/histogram/Histogram.js +43 -28
  39. package/dist/esm/hooks/useFilteredList.js +101 -18
  40. package/dist/esm/hooks/usePagination.js +29 -8
  41. package/dist/esm/hooks/useSelectableList.js +30 -5
  42. package/dist/esm/i18n/{ar.json.js → ar/data.json.js} +8 -2
  43. package/dist/esm/i18n/{en.json.js → en/data.json.js} +8 -2
  44. package/dist/esm/i18n/index.js +2 -2
  45. package/dist/esm/index.js +31 -0
  46. package/dist/esm/json/JsonViewer.js +82 -45
  47. package/dist/esm/pagination/Pagination.js +25 -16
  48. package/dist/esm/table/AddColumn.js +6 -6
  49. package/dist/esm/table/BodyCell.js +21 -14
  50. package/dist/esm/table/BodyRow.js +41 -28
  51. package/dist/esm/table/CheckboxCell.js +11 -10
  52. package/dist/esm/table/ColumnFilters.js +100 -0
  53. package/dist/esm/table/EmptyCell.js +4 -4
  54. package/dist/esm/table/HeaderCell.js +80 -54
  55. package/dist/esm/table/HtmlTable.js +84 -0
  56. package/dist/esm/table/{Context.js → Provider.js} +11 -12
  57. package/dist/esm/table/Table.js +100 -34
  58. package/dist/esm/{tree/types.js → table/context.js} +8 -4
  59. package/dist/esm/table/types.js +29 -0
  60. package/dist/esm/table/useResizer.js +10 -10
  61. package/dist/esm/table/useTableColumns.js +4 -4
  62. package/dist/esm/table/useVirtualTable.js +131 -24
  63. package/dist/esm/tree/TreeNode.js +69 -49
  64. package/dist/esm/tree/TreePanel.js +62 -26
  65. package/dist/esm/tree/useTree.js +215 -50
  66. package/dist/esm/tree/utils.js +64 -35
  67. package/dist/esm/utils/getColor.js +58 -0
  68. package/dist/esm/virtual/Gallery.js +121 -63
  69. package/dist/esm/virtual/List.js +118 -57
  70. package/dist/esm/virtual/Scroller.js +17 -9
  71. package/dist/types/checklist/CheckList.d.ts +25 -6
  72. package/dist/types/histogram/Histogram.d.ts +28 -6
  73. package/dist/types/hooks/useFilteredList.d.ts +62 -5
  74. package/dist/types/hooks/usePagination.d.ts +18 -2
  75. package/dist/types/hooks/useSelectableList.d.ts +24 -1
  76. package/dist/types/index.d.ts +27 -0
  77. package/dist/types/json/JsonViewer.d.ts +23 -3
  78. package/dist/types/pagination/Pagination.d.ts +8 -2
  79. package/dist/types/table/AddColumn.d.ts +2 -2
  80. package/dist/types/table/BodyCell.d.ts +2 -2
  81. package/dist/types/table/BodyRow.d.ts +9 -9
  82. package/dist/types/table/CheckboxCell.d.ts +3 -3
  83. package/dist/types/table/ColumnFilters.d.ts +12 -0
  84. package/dist/types/table/EmptyCell.d.ts +1 -1
  85. package/dist/types/table/HeaderCell.d.ts +1 -1
  86. package/dist/types/table/HtmlTable.d.ts +21 -0
  87. package/dist/types/table/Provider.d.ts +2 -0
  88. package/dist/types/table/Table.d.ts +10 -1
  89. package/dist/types/table/context.d.ts +7 -0
  90. package/dist/types/table/types.d.ts +52 -10
  91. package/dist/types/table/useResizer.d.ts +1 -1
  92. package/dist/types/table/useTableColumns.d.ts +1 -1
  93. package/dist/types/table/useVirtualTable.d.ts +31 -12
  94. package/dist/types/tree/TreeNode.d.ts +1 -1
  95. package/dist/types/tree/TreePanel.d.ts +36 -1
  96. package/dist/types/tree/types.d.ts +75 -28
  97. package/dist/types/tree/useTree.d.ts +8 -12
  98. package/dist/types/tree/utils.d.ts +15 -8
  99. package/dist/types/utils/getColor.d.ts +43 -0
  100. package/dist/types/virtual/Gallery.d.ts +37 -6
  101. package/dist/types/virtual/List.d.ts +38 -6
  102. package/dist/types/virtual/Scroller.d.ts +1 -1
  103. package/package.json +17 -19
  104. package/src/checklist/CheckList.tsx +68 -71
  105. package/src/histogram/Histogram.tsx +47 -48
  106. package/src/hooks/useFilteredList.tsx +111 -28
  107. package/src/hooks/usePagination.tsx +39 -39
  108. package/src/hooks/useSelectableList.ts +45 -33
  109. package/src/i18n/{ar.json → ar/data.json} +5 -0
  110. package/src/i18n/{en.json → en/data.json} +5 -0
  111. package/src/i18n/index.ts +2 -2
  112. package/src/index.ts +23 -17
  113. package/src/json/JsonViewer.tsx +89 -120
  114. package/src/pagination/Pagination.tsx +104 -105
  115. package/src/table/AddColumn.tsx +6 -15
  116. package/src/table/BodyCell.tsx +27 -36
  117. package/src/table/BodyRow.tsx +36 -59
  118. package/src/table/CheckboxCell.tsx +12 -15
  119. package/src/table/ColumnFilters.tsx +93 -0
  120. package/src/table/EmptyCell.tsx +5 -18
  121. package/src/table/HeaderCell.tsx +72 -53
  122. package/src/table/HtmlTable.tsx +106 -0
  123. package/src/table/{Context.tsx → Provider.tsx} +11 -28
  124. package/src/table/Table.tsx +98 -83
  125. package/src/table/context.ts +33 -0
  126. package/src/table/types.ts +53 -27
  127. package/src/table/useResizer.ts +5 -9
  128. package/src/table/useTableColumns.ts +4 -6
  129. package/src/table/useVirtualTable.ts +136 -37
  130. package/src/tree/TreeNode.tsx +91 -86
  131. package/src/tree/TreePanel.tsx +87 -51
  132. package/src/tree/types.ts +85 -46
  133. package/src/tree/useTree.ts +210 -65
  134. package/src/tree/utils.ts +81 -62
  135. package/src/utils/getColor.ts +55 -0
  136. package/src/virtual/Gallery.tsx +129 -120
  137. package/src/virtual/List.tsx +124 -91
  138. package/src/virtual/Scroller.tsx +25 -9
  139. package/dist/cjs/histogram/Histogram.module.css +0 -1
  140. package/dist/esm/histogram/Histogram.module.css +0 -1
  141. package/dist/types/table/Context.d.ts +0 -8
@@ -21,12 +21,13 @@
21
21
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  */
23
23
 
24
- import { Badge, CoreIcons, getBadgeProps, Icon } from "@react-fabric/core";
25
- import classNames from "classnames";
26
- import { useMemo } from "react";
24
+ import { Badge, getBadgeProps, getIconProps, Icon } from "@react-fabric/core";
25
+ import { cn, isEmpty, isString, isTrue } from "@react-fabric/utilities";
26
+ import { isValidElement, useMemo } from "react";
27
+ import { useTranslation } from "react-i18next";
27
28
  import { type TreeNodeProps } from "./types";
28
29
 
29
- export const TreeNode = ({
30
+ export function TreeNode<T extends KeyValue>({
30
31
  node,
31
32
  noLines,
32
33
  expanders,
@@ -35,129 +36,133 @@ export const TreeNode = ({
35
36
  defaultLeafIcon,
36
37
  defaultNodeIcon,
37
38
  onToggle,
39
+ onClick,
38
40
  onSelect,
39
41
  onChecked,
40
42
  children,
41
- }: TreeNodeProps) => {
43
+ leafClassName,
44
+ nodeClassName,
45
+ }: TreeNodeProps<T>) {
46
+ const { t } = useTranslation("data");
42
47
  const badgeProps = useMemo(() => {
43
- return getBadgeProps(node.badge);
48
+ return getBadgeProps(node.badge) as KeyValue;
44
49
  }, [node.badge]);
45
50
 
46
51
  const filler = useMemo(() => {
47
- return node.lines.slice(noLines ? 1 : 0).map((line, idx) => (
48
- <svg
52
+ return node.lines.slice(1).map((line, idx) => (
53
+ <div
54
+ // eslint-disable-next-line @eslint-react/no-array-index-key
49
55
  key={idx}
50
- viewBox="0 0 24 24"
51
- className="flex-initial w-6 fill-tint-200"
52
- >
53
- {line === 0 && <path d="" />}
54
- {!noLines && line === 1 && <path d="M7.45 26.1v-28.2h1.1v28.2h-1.1z" />}
55
- {!noLines && line === 2 && (
56
- <path d="M14.989 12.389l0.161-0.389-0.161-0.389-0.389-0.161h-6.050v-13.55h-1.1v14.1l0.161 0.389 0.389 0.161h6.6z" />
57
- )}
58
- {!noLines && line === 3 && (
59
- <path d="M8.55 12.55h6.050l0.389-0.161 0.161-0.389-0.161-0.389-0.389-0.161h-6.050v-13.55h-1.1v28.2h1.1z" />
56
+ className={cn(
57
+ "flex-initial self-stretch flex items-center w-6 relative",
58
+ !noLines &&
59
+ line > 0 &&
60
+ "before:absolute before:top-0 before:inset-s-[calc(7px)] before:bg-tint-200 before:min-h-[50%] before:w-0.5 before:scale-x-[.625]",
61
+ !noLines && line !== 2 && "before:h-full",
60
62
  )}
61
- </svg>
63
+ >
64
+ <svg viewBox="0 0 24 24" className="fill-tint-200 rtl:-scale-x-100">
65
+ {line === 0 && <path d="" />}
66
+ {!noLines && line === 1 && <path d="M7.45 26.1v-28.2h1.1v28.2h-1.1z" />}
67
+ {!noLines && line === 2 && (
68
+ <path d="M14.989 12.389l0.161-0.389-0.161-0.389-0.389-0.161h-6.050v-13.55h-1.1v14.1l0.161 0.389 0.389 0.161h6.6z" />
69
+ )}
70
+ {!noLines && line === 3 && (
71
+ <path d="M8.55 12.55h6.050l0.389-0.161 0.161-0.389-0.161-0.389-0.389-0.161h-6.050v-13.55h-1.1v28.2h1.1z" />
72
+ )}
73
+ </svg>
74
+ </div>
62
75
  ));
63
76
  }, [noLines, node.lines]);
64
77
 
65
78
  const nodeIcon = useMemo(() => {
66
79
  if (node.icon) return node.icon;
67
- return node.leaf ? defaultLeafIcon : defaultNodeIcon;
68
- }, [defaultLeafIcon, defaultNodeIcon, node.icon]);
80
+ return { icon: node.leaf ? defaultLeafIcon : defaultNodeIcon };
81
+ }, [defaultLeafIcon, defaultNodeIcon, node.icon, node.leaf]);
69
82
 
70
83
  const canCheck = useMemo(() => {
71
- return checkable === true || (checkable === "leafOnly" && node.leaf);
84
+ return isTrue(checkable) || (checkable === "leafOnly" && node.leaf);
72
85
  }, [node.leaf, checkable]);
73
86
 
74
87
  const canSelect = useMemo(() => {
75
- return (
76
- !node.disabled &&
77
- (selectable === true || (selectable === "leafOnly" && node.leaf))
78
- );
88
+ return !node.disabled && (selectable === true || (selectable === "leafOnly" && node.leaf));
79
89
  }, [node.leaf, node.disabled, selectable]);
80
90
 
81
91
  return (
82
92
  <div
83
93
  role="treeitem"
84
94
  aria-selected={node.selected}
85
- className="flex flex-nowrap"
95
+ className={cn("flex flex-nowrap items-center")}
86
96
  data-testid={node["data-testid"]}
87
97
  data-test-value={node["data-test-value"]}
98
+ data-id={node.id}
88
99
  >
89
100
  {filler}
90
- {!node.leaf && !node.childFiltered && (
101
+ {node.loading && (
91
102
  <div className="flex-initial w-6">
92
- <Icon
93
- rtlFlip
94
- onClick={() => !node.leaf && onToggle(node.id)}
95
- icon={node.open ? expanders[1] : expanders[0]}
96
- className="text-tint-600 hover:text-primary-600"
97
- />
103
+ <Icon icon="icon-[svg-spinners--eclipse]" className="text-muted" />
98
104
  </div>
99
105
  )}
106
+ {!node.leaf && !node.childFiltered && !node.loading && (
107
+ <button type="button" className="flex-initial w-6" onClick={() => !node.leaf && onToggle(node.id)}>
108
+ <Icon rtlFlip icon={node.open ? expanders[1] : expanders[0]} className="text-tint-600 hover:text-primary-600" />
109
+ </button>
110
+ )}
100
111
  {canCheck && (
101
- <div className="flex-initial w-6">
112
+ <button type="button" className="flex-initial w-6" onClick={() => !node.disabled && onChecked(node.id)}>
102
113
  <Icon
103
- onClick={() => !node.disabled && onChecked(node.id)}
104
114
  icon={
105
115
  node.checked === 2
106
- ? CoreIcons.checkboxInt
116
+ ? "icon-[mdi--checkbox-intermediate]"
107
117
  : node.checked === 1
108
- ? CoreIcons.checkboxOn
109
- : CoreIcons.checkboxOff
118
+ ? "icon-[mdi--checkbox-marked]"
119
+ : "icon-[mdi--checkbox-blank-outline]"
110
120
  }
111
- className={classNames(
112
- node.disabled
113
- ? "text-muted"
114
- : "text-primary-500 hover:text-primary-600",
115
- )}
121
+ className={cn(node.disabled ? "text-muted" : "text-primary-500 hover:text-primary-600")}
116
122
  />
117
- </div>
123
+ </button>
118
124
  )}
119
- <div
120
- role="none"
121
- className={classNames(
122
- "group data-[selected]:bg-primary-100 flex flex-nowrap flex-1 items-center overflow-hidden select-none",
123
- node.childSelected && "font-medium",
124
- canSelect && "hover:bg-primary-50 cursor-pointer",
125
- )}
126
- data-selected={node.selected}
127
- onClick={() =>
128
- canSelect
129
- ? onSelect(node.id)
130
- : canCheck
131
- ? onChecked(node.id)
132
- : onToggle(node.id)
133
- }
134
- >
135
- {nodeIcon && (
136
- <div className="flex-content w-6">
137
- <Icon
138
- icon={nodeIcon}
139
- bg={node.iconBg}
140
- color={node.iconColor}
141
- rtlFlip={node.rtlFlip}
142
- />
125
+ {!node.empty && (
126
+ <div
127
+ role="none"
128
+ className={cn(
129
+ "group/tool data-selected:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none",
130
+ node.childSelected && "font-medium",
131
+ node.disabled && "text-muted opacity-65",
132
+ node.className,
133
+ node.leaf ? leafClassName : nodeClassName,
134
+ !node.disabled && (canSelect || onClick) && "hover:bg-primary-50 cursor-pointer",
135
+ )}
136
+ data-selected={node.selected}
137
+ onClick={
138
+ node.disabled
139
+ ? undefined
140
+ : (e) => {
141
+ onClick?.(node.id, node.data);
142
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
143
+ canSelect ? onSelect(node.id, e.shiftKey) : canCheck ? onChecked(node.id) : onToggle(node.id);
144
+ }
145
+ }
146
+ >
147
+ {nodeIcon && (
148
+ <div className="flex-content max-w-6 me-1 self-center leading-none">
149
+ {isValidElement(nodeIcon) && nodeIcon}
150
+ {isString(nodeIcon) && <Icon {...getIconProps(nodeIcon)} />}
151
+ </div>
152
+ )}
153
+ {node.childSelected && !node.open && <span className=" flex-content text-primary-500">•</span>}
154
+ <div role="none" className="flex-1 truncate">
155
+ {children}
143
156
  </div>
144
- )}
145
- {node.childSelected && !node.open && (
146
- <span className=" flex-content text-primary-500">•</span>
147
- )}
148
- <div role="none" className="flex-1 truncate">
149
- {children}
157
+ {!isEmpty(node.badge) && (
158
+ <Badge
159
+ {...badgeProps}
160
+ className={cn("me-1 self-center flex-content bg-opacity-50", badgeProps.className as string)}
161
+ />
162
+ )}
150
163
  </div>
151
- {node.badge && (
152
- <Badge
153
- {...badgeProps}
154
- className={classNames(
155
- "me-1 self-center flex-content bg-opacity-50",
156
- badgeProps.className,
157
- )}
158
- />
159
- )}
160
- </div>
164
+ )}
165
+ {node.empty && <div className="text-muted text-sm select-none">{t("tree.noItems")}</div>}
161
166
  </div>
162
167
  );
163
- };
168
+ }
@@ -21,33 +21,61 @@
21
21
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  */
23
23
 
24
- import {
25
- Button,
26
- ButtonGroup,
27
- CoreIcons,
28
- Header,
29
- Icon,
30
- Section,
31
- } from "@react-fabric/core";
24
+ import { Button, ButtonGroup, Header, Icon, Layout } from "@react-fabric/core";
32
25
  import { Search } from "@react-fabric/form";
33
26
  import { useVirtualizer } from "@tanstack/react-virtual";
34
- import { useImperativeHandle, useMemo, useRef } from "react";
27
+ import { useEffect, useImperativeHandle, useMemo, useRef } from "react";
35
28
  import { TreeNode } from "./TreeNode";
36
- import { iconCollapseAll, iconExpandAll, type TreePanelProps } from "./types";
29
+ import { type TreePanelProps } from "./types";
37
30
  import { useTree } from "./useTree";
38
31
 
39
32
  // TODO: implement keyboard handler for navigating tree
40
33
 
41
- export const TreePanel = <T extends KeyValue>({
34
+ /**
35
+ * TreePanel component renders a virtualized tree structure with support for
36
+ * selection, expansion, and filtering. It allows for custom rendering of tree
37
+ * nodes and supports checkable nodes.
38
+ *
39
+ * @example
40
+ * ```jsx
41
+ * <TreePanel
42
+ * items={items}
43
+ * selected={selectedItem}
44
+ * checked={checkedItems}
45
+ * checkable={true}
46
+ * renderer={(item) => <span>{item.name}</span>}
47
+ * searchable={true}
48
+ * selectable={true}
49
+ * matcher={(item, query) => item.name.toLowerCase().includes(query.toLowerCase())}
50
+ * filterPlaceholder="Search..."
51
+ * defaultLeafIcon={<Icon icon="icon-[mdi--file]" />}
52
+ * defaultNodeIcon={<Icon icon="icon-[mdi--folder]" />}
53
+ * expander="caret"
54
+ * onChecked={(checkedItems) => console.log(checkedItems)}
55
+ * onLoad={(id) => console.log(`Load children for ${id}`)}
56
+ * onQuery={(query) => console.log(`Query: ${query}`)}
57
+ * onSelect={(selectedItem) => console.log(selectedItem)}
58
+ * onClick={(item) => console.log(`Clicked on ${item.id}`)}
59
+ * sorter={(a, b) => a.label.localeCompare(b.label)}
60
+ * makeLabel={(item) => item.name}
61
+ * makeIcon={(item) => item.icon ? <Icon icon={item.icon} /> : null}
62
+ * defaultExpanded={["root"]}
63
+ * onExpandToggle={(id, expanded) => console.log(`Toggle expand for ${id}: ${expanded}`)}
64
+ * leafClassName="leaf-node"
65
+ * nodeClassName="tree-node"
66
+ * />
67
+ * ```
68
+ */
69
+ export function TreePanel<T extends KeyValue>({
42
70
  ref,
43
71
  items,
44
72
  selected,
45
73
  checked,
46
74
  checkable,
47
75
  noLines,
48
- renderer,
49
76
  searchable,
50
77
  selectable,
78
+ multiple,
51
79
  matcher,
52
80
  filterPlaceholder,
53
81
  defaultLeafIcon,
@@ -55,25 +83,43 @@ export const TreePanel = <T extends KeyValue>({
55
83
  expander = "box",
56
84
  onChecked,
57
85
  onLoad,
86
+ onQuery,
58
87
  onSelect,
88
+ onClick,
89
+ sorter,
90
+ makeLabel,
91
+ makeIcon,
92
+ defaultExpanded,
93
+ onExpandToggle,
94
+ leafClassName,
95
+ nodeClassName,
59
96
  ...aria
60
- }: TreePanelProps<T>) => {
97
+ }: TreePanelProps<T>) {
61
98
  const {
62
99
  tree,
100
+ query,
101
+ selected: currentSelected,
63
102
  toggleExpand,
64
103
  toggleCheck,
65
104
  expandAll,
66
105
  collapseAll,
106
+ expandAndLoad,
67
107
  select,
68
108
  expand,
69
109
  onFilter,
70
- } = useTree({
110
+ } = useTree<T>({
71
111
  items,
72
112
  checked,
73
113
  selected,
114
+ multiple,
74
115
  matcher,
116
+ sorter,
117
+ onLoad,
118
+ onQuery,
75
119
  onSelect,
76
120
  onChecked,
121
+ defaultExpanded,
122
+ onExpandToggle,
77
123
  });
78
124
 
79
125
  const scrollerRef = useRef<HTMLDivElement>(null);
@@ -86,60 +132,48 @@ export const TreePanel = <T extends KeyValue>({
86
132
  const virtualItems = virtualizer.getVirtualItems();
87
133
 
88
134
  const expanders = useMemo<[string, string]>(() => {
89
- if (expander === "caret")
90
- return [CoreIcons.caretRight, CoreIcons.caretDown];
91
- if (expander === "chevron")
92
- return [CoreIcons.chevronRight, CoreIcons.chevronDown];
93
- if (expander === "folder")
94
- return [CoreIcons.folderClosed, CoreIcons.folderOpen];
95
- return [CoreIcons.expand, CoreIcons.collapse];
135
+ if (expander === "caret") return ["icon-[mdi--menu-right]", "icon-[mdi--menu-down]"];
136
+ if (expander === "chevron") return ["icon-[mdi--chevron-right]", "icon-[mdi--chevron-down]"];
137
+ if (expander === "folder") return ["icon-[mdi--folder-outline]", "icon-[mdi--folder-open-outline]"];
138
+ return ["icon-[mdi--plus-box-outline]", "icon-[mdi--minus-box-outline]"];
96
139
  }, [expander]);
97
140
 
98
141
  useImperativeHandle(
99
142
  ref,
100
143
  () => ({
101
144
  open: (id: string) => expand(id),
102
- select: (id: string) => expand(id),
145
+ openAndLoad: (list: string[]) => expandAndLoad(list),
146
+ select: (id: string) => select(id),
103
147
  }),
148
+ // eslint-disable-next-line @eslint-react/exhaustive-deps
104
149
  [],
105
150
  );
106
151
 
152
+ useEffect(() => {
153
+ const index = tree.findIndex((n) => n.id === currentSelected);
154
+ virtualizer.scrollToIndex(index, { align: "auto" });
155
+ // eslint-disable-next-line @eslint-react/exhaustive-deps
156
+ }, [currentSelected]);
157
+
107
158
  return (
108
- <Section>
109
- <Header
110
- flex
111
- className="items-center p-px justify-end overflow-hidden border-b"
112
- >
159
+ <Layout>
160
+ <Header flex className="items-center p-px justify-end overflow-hidden border-b">
113
161
  {searchable && (
114
162
  <Search
163
+ value={query}
115
164
  onSearch={onFilter}
116
165
  allowClear
117
166
  placeholder={filterPlaceholder}
118
167
  {...{ noBorder: true }}
119
- decorateStart={<Icon icon={CoreIcons.filter} className="p-1" />}
168
+ decorateStart={<Icon icon="icon-[mdi--filter-variant]" className="p-1" />}
120
169
  />
121
170
  )}
122
171
  <ButtonGroup variant="link" className="m-0">
123
- <Button
124
- size="sm"
125
- aria-label="expand all"
126
- icon={iconExpandAll}
127
- onClick={expandAll}
128
- />
129
- <Button
130
- size="sm"
131
- aria-label="collapse all"
132
- icon={iconCollapseAll}
133
- onClick={collapseAll}
134
- />
172
+ <Button size="sm" aria-label="expand all" icon="icon-[mdi--arrow-expand-vertical]" onClick={expandAll} />
173
+ <Button size="sm" aria-label="collapse all" icon="icon-[mdi--arrow-collapse-vertical]" onClick={collapseAll} />
135
174
  </ButtonGroup>
136
175
  </Header>
137
- <div
138
- ref={scrollerRef}
139
- role="tree"
140
- className="area-content overflow-auto p-1"
141
- {...aria}
142
- >
176
+ <div ref={scrollerRef} role="tree" className="area-content overflow-auto p-1" {...aria}>
143
177
  <div style={{ height: virtualizer.getTotalSize() }}>
144
178
  <div style={{ height: virtualItems[0]?.start }} />
145
179
  {virtualItems.map(({ index, key }) => (
@@ -151,18 +185,20 @@ export const TreePanel = <T extends KeyValue>({
151
185
  checkable={checkable}
152
186
  selectable={selectable}
153
187
  defaultLeafIcon={defaultLeafIcon}
154
- defaultNodeIcon={defaultNodeIcon}
188
+ defaultNodeIcon={makeIcon?.(tree[index].data) ?? defaultNodeIcon}
155
189
  onToggle={toggleExpand}
156
190
  onChecked={toggleCheck}
157
191
  onSelect={select}
192
+ onClick={onClick}
193
+ leafClassName={leafClassName}
194
+ nodeClassName={nodeClassName}
158
195
  >
159
- {(tree[index].data && renderer?.(tree[index].data)) ||
160
- tree[index].label}
196
+ {(tree[index].data && makeLabel?.(tree[index].data)) ?? tree[index].label}
161
197
  </TreeNode>
162
198
  </div>
163
199
  ))}
164
200
  </div>
165
201
  </div>
166
- </Section>
202
+ </Layout>
167
203
  );
168
- };
204
+ }