@react-fabric/data 1.0.0-beta.6 → 1.0.0-beta.60

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 (103) 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 +23 -0
  4. package/dist/cjs/histogram/Histogram.js +37 -7
  5. package/dist/cjs/hooks/useFilteredList.js +88 -10
  6. package/dist/cjs/hooks/usePagination.js +27 -4
  7. package/dist/cjs/hooks/useSelectableList.js +29 -0
  8. package/dist/cjs/i18n/ar.json.js +8 -1
  9. package/dist/cjs/i18n/en.json.js +8 -1
  10. package/dist/cjs/json/JsonViewer.js +67 -27
  11. package/dist/cjs/pagination/Pagination.js +10 -0
  12. package/dist/cjs/table/AddColumn.js +1 -1
  13. package/dist/cjs/table/BodyCell.js +5 -4
  14. package/dist/cjs/table/BodyRow.js +2 -2
  15. package/dist/cjs/table/CheckboxCell.js +1 -1
  16. package/dist/cjs/table/ColumnFilters.js +97 -0
  17. package/dist/cjs/table/HeaderCell.js +71 -43
  18. package/dist/cjs/table/Table.js +58 -12
  19. package/dist/cjs/table/types.js +29 -0
  20. package/dist/cjs/table/useResizer.js +4 -4
  21. package/dist/cjs/table/useVirtualTable.js +127 -19
  22. package/dist/cjs/tree/TreeNode.js +48 -30
  23. package/dist/cjs/tree/TreePanel.js +45 -11
  24. package/dist/cjs/tree/useTree.js +199 -38
  25. package/dist/cjs/tree/utils.js +39 -12
  26. package/dist/cjs/virtual/Gallery.js +97 -45
  27. package/dist/cjs/virtual/List.js +93 -39
  28. package/dist/cjs/virtual/Scroller.js +16 -8
  29. package/dist/esm/checklist/CheckList.js +23 -0
  30. package/dist/esm/histogram/Histogram.js +38 -8
  31. package/dist/esm/hooks/useFilteredList.js +89 -11
  32. package/dist/esm/hooks/usePagination.js +27 -4
  33. package/dist/esm/hooks/useSelectableList.js +29 -0
  34. package/dist/esm/i18n/ar.json.js +8 -2
  35. package/dist/esm/i18n/en.json.js +8 -2
  36. package/dist/esm/json/JsonViewer.js +68 -28
  37. package/dist/esm/pagination/Pagination.js +10 -0
  38. package/dist/esm/table/AddColumn.js +1 -1
  39. package/dist/esm/table/BodyCell.js +5 -4
  40. package/dist/esm/table/BodyRow.js +2 -2
  41. package/dist/esm/table/CheckboxCell.js +1 -1
  42. package/dist/esm/table/ColumnFilters.js +97 -0
  43. package/dist/esm/table/HeaderCell.js +72 -44
  44. package/dist/esm/table/Table.js +59 -13
  45. package/dist/esm/table/types.js +29 -0
  46. package/dist/esm/table/useResizer.js +4 -4
  47. package/dist/esm/table/useVirtualTable.js +129 -21
  48. package/dist/esm/tree/TreeNode.js +51 -33
  49. package/dist/esm/tree/TreePanel.js +46 -12
  50. package/dist/esm/tree/useTree.js +202 -41
  51. package/dist/esm/tree/utils.js +40 -13
  52. package/dist/esm/virtual/Gallery.js +97 -45
  53. package/dist/esm/virtual/List.js +93 -39
  54. package/dist/esm/virtual/Scroller.js +16 -8
  55. package/dist/types/checklist/CheckList.d.ts +22 -0
  56. package/dist/types/histogram/Histogram.d.ts +28 -1
  57. package/dist/types/hooks/useFilteredList.d.ts +66 -5
  58. package/dist/types/hooks/usePagination.d.ts +19 -0
  59. package/dist/types/hooks/useSelectableList.d.ts +29 -0
  60. package/dist/types/json/JsonViewer.d.ts +27 -2
  61. package/dist/types/pagination/Pagination.d.ts +10 -1
  62. package/dist/types/table/ColumnFilters.d.ts +9 -0
  63. package/dist/types/table/HeaderCell.d.ts +1 -1
  64. package/dist/types/table/Table.d.ts +14 -1
  65. package/dist/types/table/types.d.ts +44 -5
  66. package/dist/types/table/useVirtualTable.d.ts +23 -9
  67. package/dist/types/tree/TreeNode.d.ts +1 -1
  68. package/dist/types/tree/TreePanel.d.ts +42 -1
  69. package/dist/types/tree/types.d.ts +65 -19
  70. package/dist/types/tree/useTree.d.ts +9 -10
  71. package/dist/types/tree/utils.d.ts +10 -3
  72. package/dist/types/virtual/Gallery.d.ts +42 -3
  73. package/dist/types/virtual/List.d.ts +42 -3
  74. package/package.json +16 -14
  75. package/src/checklist/CheckList.tsx +22 -0
  76. package/src/histogram/Histogram.tsx +40 -10
  77. package/src/hooks/useFilteredList.tsx +109 -9
  78. package/src/hooks/usePagination.tsx +32 -7
  79. package/src/hooks/useSelectableList.ts +29 -0
  80. package/src/i18n/ar.json +5 -0
  81. package/src/i18n/en.json +5 -0
  82. package/src/json/JsonViewer.tsx +71 -35
  83. package/src/pagination/Pagination.tsx +10 -0
  84. package/src/table/AddColumn.tsx +1 -1
  85. package/src/table/BodyCell.tsx +6 -4
  86. package/src/table/BodyRow.tsx +3 -2
  87. package/src/table/CheckboxCell.tsx +1 -1
  88. package/src/table/ColumnFilters.tsx +105 -0
  89. package/src/table/HeaderCell.tsx +72 -18
  90. package/src/table/Table.tsx +99 -11
  91. package/src/table/types.ts +46 -8
  92. package/src/table/useResizer.ts +5 -3
  93. package/src/table/useVirtualTable.ts +158 -27
  94. package/src/tree/TreeNode.tsx +98 -58
  95. package/src/tree/TreePanel.tsx +77 -6
  96. package/src/tree/types.ts +73 -18
  97. package/src/tree/useTree.ts +220 -44
  98. package/src/tree/utils.ts +58 -20
  99. package/src/virtual/Gallery.tsx +118 -54
  100. package/src/virtual/List.tsx +99 -39
  101. package/src/virtual/Scroller.tsx +16 -8
  102. package/dist/cjs/histogram/Histogram.module.css +0 -1
  103. package/dist/esm/histogram/Histogram.module.css +0 -1
@@ -21,9 +21,17 @@
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";
24
+ import {
25
+ Badge,
26
+ CoreIcons,
27
+ getBadgeProps,
28
+ getIconProps,
29
+ Icon,
30
+ } from "@react-fabric/core";
31
+ import { isEmpty, isString } from "@react-fabric/utilities";
25
32
  import classNames from "classnames";
26
- import { useMemo } from "react";
33
+ import { isValidElement, useMemo } from "react";
34
+ import { useTranslation } from "react-i18next";
27
35
  import { type TreeNodeProps } from "./types";
28
36
 
29
37
  export const TreeNode = ({
@@ -35,36 +43,49 @@ export const TreeNode = ({
35
43
  defaultLeafIcon,
36
44
  defaultNodeIcon,
37
45
  onToggle,
46
+ onClick,
38
47
  onSelect,
39
48
  onChecked,
40
49
  children,
50
+ leafClassName,
51
+ nodeClassName,
41
52
  }: TreeNodeProps) => {
53
+ const { t } = useTranslation("data");
42
54
  const badgeProps = useMemo(() => {
43
55
  return getBadgeProps(node.badge);
44
56
  }, [node.badge]);
45
57
 
46
58
  const filler = useMemo(() => {
47
- return node.lines.slice(noLines ? 1 : 0).map((line, idx) => (
48
- <svg
59
+ return node.lines.slice(1).map((line, idx) => (
60
+ <div
49
61
  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" />
62
+ className={classNames(
63
+ "flex-initial self-stretch flex items-center w-6 relative",
64
+ !noLines &&
65
+ line > 0 &&
66
+ "before:absolute before:top-0 before:start-[7px] before:bg-tint-200 before:min-h-[50%] before:w-0.5 before:scale-x-[.625]",
67
+ !noLines && line !== 2 && "before:h-full",
60
68
  )}
61
- </svg>
69
+ >
70
+ <svg viewBox="0 0 24 24" className="fill-tint-200 rtl:-scale-x-100">
71
+ {line === 0 && <path d="" />}
72
+ {!noLines && line === 1 && (
73
+ <path d="M7.45 26.1v-28.2h1.1v28.2h-1.1z" />
74
+ )}
75
+ {!noLines && line === 2 && (
76
+ <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" />
77
+ )}
78
+ {!noLines && line === 3 && (
79
+ <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" />
80
+ )}
81
+ </svg>
82
+ </div>
62
83
  ));
63
84
  }, [noLines, node.lines]);
64
85
 
65
86
  const nodeIcon = useMemo(() => {
66
87
  if (node.icon) return node.icon;
67
- return node.leaf ? defaultLeafIcon : defaultNodeIcon;
88
+ return { icon: node.leaf ? defaultLeafIcon : defaultNodeIcon };
68
89
  }, [defaultLeafIcon, defaultNodeIcon, node.icon]);
69
90
 
70
91
  const canCheck = useMemo(() => {
@@ -82,12 +103,18 @@ export const TreeNode = ({
82
103
  <div
83
104
  role="treeitem"
84
105
  aria-selected={node.selected}
85
- className="flex flex-nowrap"
106
+ className={classNames("flex flex-nowrap items-center")}
86
107
  data-testid={node["data-testid"]}
87
108
  data-test-value={node["data-test-value"]}
109
+ data-id={node.id}
88
110
  >
89
111
  {filler}
90
- {!node.leaf && !node.childFiltered && (
112
+ {node.loading && (
113
+ <div className="flex-initial w-6">
114
+ <Icon icon={CoreIcons.spinner} className="animate-spin text-muted" />
115
+ </div>
116
+ )}
117
+ {!node.leaf && !node.childFiltered && !node.loading && (
91
118
  <div className="flex-initial w-6">
92
119
  <Icon
93
120
  rtlFlip
@@ -116,48 +143,61 @@ export const TreeNode = ({
116
143
  />
117
144
  </div>
118
145
  )}
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
- />
146
+ {!node.empty && (
147
+ <div
148
+ role="none"
149
+ className={classNames(
150
+ "group/tool data-selected:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none",
151
+ node.childSelected && "font-medium",
152
+ node.disabled && "text-muted opacity-65",
153
+ node.className,
154
+ node.leaf ? leafClassName : nodeClassName,
155
+ !node.disabled &&
156
+ (canSelect || onClick) &&
157
+ "hover:bg-primary-50 cursor-pointer",
158
+ )}
159
+ data-selected={node.selected}
160
+ onClick={
161
+ node.disabled
162
+ ? undefined
163
+ : (e) => {
164
+ onClick?.(node.id, node.data);
165
+ canSelect
166
+ ? onSelect(node.id, e.shiftKey)
167
+ : canCheck
168
+ ? onChecked(node.id)
169
+ : onToggle(node.id);
170
+ }
171
+ }
172
+ >
173
+ {nodeIcon && (
174
+ <div className="flex-content max-w-6 me-1 self-center leading-none">
175
+ {isValidElement(nodeIcon) && nodeIcon}
176
+ {isString(nodeIcon) && <Icon {...getIconProps(nodeIcon)} />}
177
+ </div>
178
+ )}
179
+ {node.childSelected && !node.open && (
180
+ <span className=" flex-content text-primary-500">•</span>
181
+ )}
182
+ <div role="none" className="flex-1 truncate">
183
+ {children}
143
184
  </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}
185
+ {!isEmpty(node.badge) && (
186
+ <Badge
187
+ {...badgeProps}
188
+ className={classNames(
189
+ "me-1 self-center flex-content bg-opacity-50",
190
+ badgeProps.className,
191
+ )}
192
+ />
193
+ )}
150
194
  </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>
195
+ )}
196
+ {node.empty && (
197
+ <div className="text-muted text-sm select-none">
198
+ {t("tree.noItems")}
199
+ </div>
200
+ )}
161
201
  </div>
162
202
  );
163
203
  };
@@ -31,13 +31,54 @@ import {
31
31
  } from "@react-fabric/core";
32
32
  import { Search } from "@react-fabric/form";
33
33
  import { useVirtualizer } from "@tanstack/react-virtual";
34
- import { useImperativeHandle, useMemo, useRef } from "react";
34
+ import { useEffect, useImperativeHandle, useMemo, useRef } from "react";
35
35
  import { TreeNode } from "./TreeNode";
36
36
  import { iconCollapseAll, iconExpandAll, type TreePanelProps } from "./types";
37
37
  import { useTree } from "./useTree";
38
38
 
39
39
  // TODO: implement keyboard handler for navigating tree
40
40
 
41
+ /**
42
+ * TreePanel component renders a virtualized tree structure with support for
43
+ * selection, expansion, and filtering. It allows for custom rendering of tree
44
+ * nodes and supports checkable nodes.
45
+ *
46
+ * @param {TreePanelProps<T>} props - The properties for the TreePanel component.
47
+ * @returns {JSX.Element} The rendered TreePanel component.
48
+ * @template T - The type of items in the tree, extending KeyValue.
49
+ *
50
+ * @example
51
+ * ```jsx
52
+ * <TreePanel
53
+ * items={items}
54
+ * selected={selectedItem}
55
+ * checked={checkedItems}
56
+ * checkable={true}
57
+ * renderer={(item) => <span>{item.name}</span>}
58
+ * searchable={true}
59
+ * selectable={true}
60
+ * matcher={(item, query) => item.name.toLowerCase().includes(query.toLowerCase())}
61
+ * filterPlaceholder="Search..."
62
+ * defaultLeafIcon={<Icon icon={CoreIcons.file} />}
63
+ * defaultNodeIcon={<Icon icon={CoreIcons.folder} />}
64
+ * expander="caret"
65
+ * onChecked={(checkedItems) => console.log(checkedItems)}
66
+ * onLoad={(id) => console.log(`Load children for ${id}`)}
67
+ * onQuery={(query) => console.log(`Query: ${query}`)}
68
+ * onSelect={(selectedItem) => console.log(selectedItem)}
69
+ * onClick={(item) => console.log(`Clicked on ${item.id}`)}
70
+ * sorter={(a, b) => a.label.localeCompare(b.label)}
71
+ * makeLabel={(item) => item.name}
72
+ * makeIcon={(item) => item.icon ? <Icon icon={item.icon} /> : null}
73
+ * defaultExpanded={["root"]}
74
+ * onExpandToggle={(id, expanded) => console.log(`Toggle expand for ${id}: ${expanded}`)}
75
+ * leafClassName="leaf-node"
76
+ * nodeClassName="tree-node"
77
+ * />
78
+ * ```
79
+ *
80
+ * @see {@link https://adarshpastakia.github.io/react-fabric/?path=/docs/data-treepanel--docs}
81
+ */
41
82
  export const TreePanel = <T extends KeyValue>({
42
83
  ref,
43
84
  items,
@@ -45,9 +86,9 @@ export const TreePanel = <T extends KeyValue>({
45
86
  checked,
46
87
  checkable,
47
88
  noLines,
48
- renderer,
49
89
  searchable,
50
90
  selectable,
91
+ multiple,
51
92
  matcher,
52
93
  filterPlaceholder,
53
94
  defaultLeafIcon,
@@ -55,15 +96,27 @@ export const TreePanel = <T extends KeyValue>({
55
96
  expander = "box",
56
97
  onChecked,
57
98
  onLoad,
99
+ onQuery,
58
100
  onSelect,
101
+ onClick,
102
+ sorter,
103
+ makeLabel,
104
+ makeIcon,
105
+ defaultExpanded,
106
+ onExpandToggle,
107
+ leafClassName,
108
+ nodeClassName,
59
109
  ...aria
60
110
  }: TreePanelProps<T>) => {
61
111
  const {
62
112
  tree,
113
+ query,
114
+ selected: currentSelected,
63
115
  toggleExpand,
64
116
  toggleCheck,
65
117
  expandAll,
66
118
  collapseAll,
119
+ expandAndLoad,
67
120
  select,
68
121
  expand,
69
122
  onFilter,
@@ -71,10 +124,16 @@ export const TreePanel = <T extends KeyValue>({
71
124
  items,
72
125
  checked,
73
126
  selected,
127
+ multiple,
74
128
  matcher,
129
+ sorter,
130
+ onLoad,
131
+ onQuery,
75
132
  onSelect,
76
133
  onChecked,
77
- });
134
+ defaultExpanded,
135
+ onExpandToggle,
136
+ } as any);
78
137
 
79
138
  const scrollerRef = useRef<HTMLDivElement>(null);
80
139
  const virtualizer = useVirtualizer({
@@ -99,11 +158,17 @@ export const TreePanel = <T extends KeyValue>({
99
158
  ref,
100
159
  () => ({
101
160
  open: (id: string) => expand(id),
102
- select: (id: string) => expand(id),
161
+ openAndLoad: (list: string[]) => expandAndLoad(list),
162
+ select: (id: string) => select(id),
103
163
  }),
104
164
  [],
105
165
  );
106
166
 
167
+ useEffect(() => {
168
+ const index = tree.findIndex((n) => n.id === currentSelected);
169
+ virtualizer.scrollToIndex(index, { align: "auto" });
170
+ }, [currentSelected]);
171
+
107
172
  return (
108
173
  <Section>
109
174
  <Header
@@ -112,6 +177,7 @@ export const TreePanel = <T extends KeyValue>({
112
177
  >
113
178
  {searchable && (
114
179
  <Search
180
+ value={query}
115
181
  onSearch={onFilter}
116
182
  allowClear
117
183
  placeholder={filterPlaceholder}
@@ -151,12 +217,17 @@ export const TreePanel = <T extends KeyValue>({
151
217
  checkable={checkable}
152
218
  selectable={selectable}
153
219
  defaultLeafIcon={defaultLeafIcon}
154
- defaultNodeIcon={defaultNodeIcon}
220
+ defaultNodeIcon={
221
+ makeIcon?.(tree[index].data) ?? defaultNodeIcon
222
+ }
155
223
  onToggle={toggleExpand}
156
224
  onChecked={toggleCheck}
157
225
  onSelect={select}
226
+ onClick={onClick}
227
+ leafClassName={leafClassName}
228
+ nodeClassName={nodeClassName}
158
229
  >
159
- {(tree[index].data && renderer?.(tree[index].data)) ||
230
+ {(tree[index].data && makeLabel?.(tree[index].data)) ??
160
231
  tree[index].label}
161
232
  </TreeNode>
162
233
  </div>
package/src/tree/types.ts CHANGED
@@ -21,22 +21,26 @@
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 { type IconProps } from "@react-fabric/core/dist/types/components/icon/Icon";
24
25
  import {
25
26
  type BadgeType,
26
27
  type ChildProp,
27
28
  type CssProp,
28
29
  type Elements,
29
- type IconProps,
30
30
  type RefProp,
31
31
  type TestProps,
32
32
  } from "@react-fabric/core/dist/types/types";
33
33
 
34
- interface TreeBaseNode<T> extends IconProps, CssProp, TestProps {
34
+ interface TreeBaseNode<T> extends CssProp, TestProps {
35
35
  id: string;
36
36
  /**
37
37
  * display label
38
38
  */
39
39
  label: Elements<JSX.Element>;
40
+ /**
41
+ * icon path or props
42
+ */
43
+ icon?: IconProps;
40
44
  /**
41
45
  * full text to be used for querying purposes
42
46
  */
@@ -60,14 +64,14 @@ export type TreeNodeType<T extends KeyValue = KeyValue> = TreeBaseNode<T> &
60
64
  (
61
65
  | { leaf: true; children?: never }
62
66
  | {
63
- leaf?: false;
67
+ leaf?: boolean;
64
68
  children?: Array<TreeNodeType<T>>;
65
69
  open?: boolean;
66
70
  iconOpen?: string;
67
71
  }
68
72
  );
69
73
 
70
- export interface InternalNode extends IconProps, CssProp, TestProps {
74
+ export interface InternalNode extends CssProp, TestProps {
71
75
  id: string;
72
76
  label: Elements<JSX.Element>;
73
77
  queryable?: string;
@@ -84,6 +88,7 @@ export interface InternalNode extends IconProps, CssProp, TestProps {
84
88
  loaded: boolean;
85
89
  parent?: string;
86
90
  empty?: boolean;
91
+ icon?: IconProps;
87
92
  errored?: string;
88
93
  selected?: true;
89
94
  childSelected?: true;
@@ -96,22 +101,59 @@ export interface InternalNode extends IconProps, CssProp, TestProps {
96
101
  export interface TreeNodeProps extends ChildProp {
97
102
  node: InternalNode;
98
103
  expanders: [string, string];
99
- defaultNodeIcon?: string;
100
- defaultLeafIcon?: string;
104
+ defaultNodeIcon?: Elements<JSX.Element>;
105
+ defaultLeafIcon?: Elements<JSX.Element>;
101
106
  noLines?: boolean;
102
107
  selectable?: true | "leafOnly";
103
108
  checkable?: true | "leafOnly";
109
+ leafClassName?: string;
110
+ nodeClassName?: string;
104
111
  onToggle: (id: string) => void;
105
- onSelect: (id: string) => void;
112
+ onSelect: (id: string, shiftKey?: boolean) => void;
106
113
  onChecked: (id: string) => void;
114
+ onClick?: (id: string, node: any) => void;
107
115
  }
108
116
 
109
117
  export interface TreeRef {
110
118
  select: (id: string) => void;
111
119
  open: (id: string) => void;
120
+ openAndLoad: (list: string[]) => void;
112
121
  }
113
122
 
114
- export interface TreePanelProps<T extends KeyValue = KeyValue>
123
+ export type TreePanelProps<T extends KeyValue = KeyValue> =
124
+ BaseTreePanelProps<T> &
125
+ (
126
+ | {
127
+ /**
128
+ * enable multi select
129
+ */
130
+ multiple?: never | false;
131
+ /**
132
+ * selected item id
133
+ */
134
+ selected?: string;
135
+ /**
136
+ * callback on selection of tree node
137
+ */
138
+ onSelect?: (id: string, data: T) => void;
139
+ }
140
+ | {
141
+ /**
142
+ * enable multi select
143
+ */
144
+ multiple: true;
145
+ /**
146
+ * selected item id
147
+ */
148
+ selected?: string[];
149
+ /**
150
+ * callback on selection of tree node
151
+ */
152
+ onSelect?: (id: string[], data: T) => void;
153
+ }
154
+ );
155
+
156
+ interface BaseTreePanelProps<T extends KeyValue = KeyValue>
115
157
  extends TestProps,
116
158
  RefProp<TreeRef> {
117
159
  items?: Array<TreeNodeType<T>>;
@@ -128,13 +170,13 @@ export interface TreePanelProps<T extends KeyValue = KeyValue>
128
170
  */
129
171
  selectable?: true | "leafOnly";
130
172
  /**
131
- * enable checkable
173
+ * enable multi select
132
174
  */
133
- checkable?: true | "leafOnly";
175
+ multiple?: boolean;
134
176
  /**
135
- * selected item id
177
+ * enable checkable
136
178
  */
137
- selected?: string;
179
+ checkable?: true | "leafOnly";
138
180
  /**
139
181
  * checked items
140
182
  */
@@ -165,21 +207,34 @@ export interface TreePanelProps<T extends KeyValue = KeyValue>
165
207
  | Array<TreeNodeType<T>>
166
208
  | undefined;
167
209
  /**
168
- * callback on selection of tree node
210
+ * callback to load tree using search query
169
211
  */
170
- onSelect?: (id: string) => void;
212
+ onQuery?: (query: string) => void;
171
213
  /**
172
- * callback on change of checked list
214
+ * callback on click of tree node
173
215
  */
174
- onChecked?: (leafs: string[], nodes: string[]) => void;
216
+ onClick?: (id: string, data: T) => void;
175
217
  /**
176
- * item label renderer
218
+ * callback on change of checked list
219
+ * @param leafs - list of checked leaf nodes
220
+ * @param nodes - list of checked nodes
221
+ * @param partials - list of partially checked nodes
177
222
  */
178
- renderer?: (data: T) => JSX.Element;
223
+ onChecked?: (leafs: string[], nodes: string[], partials: string[]) => void;
179
224
  /**
180
225
  * item filter matcher
181
226
  */
182
227
  matcher?: (data: T, query: string) => boolean;
228
+
229
+ sorter?: false | ((a: T, b: T) => number);
230
+ makeLabel?: (node: T) => Elements<JSX.Element>;
231
+ makeIcon?: (node: T) => Elements<JSX.Element>;
232
+
233
+ defaultExpanded?: string[];
234
+ onExpandToggle?: (id: string[]) => void;
235
+
236
+ leafClassName?: string;
237
+ nodeClassName?: string;
183
238
  }
184
239
 
185
240
  export const iconExpandAll =