@react-fabric/data 1.0.0-beta.54 → 1.0.0-beta.56
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/cjs/hooks/useFilteredList.js +68 -10
- package/dist/cjs/table/HeaderCell.js +3 -2
- package/dist/cjs/table/Table.js +7 -1
- package/dist/cjs/table/useVirtualTable.js +18 -0
- package/dist/cjs/tree/TreeNode.js +3 -2
- package/dist/cjs/tree/TreePanel.js +18 -4
- package/dist/cjs/tree/useTree.js +107 -39
- package/dist/cjs/tree/utils.js +5 -4
- package/dist/cjs/virtual/Gallery.js +2 -2
- package/dist/cjs/virtual/List.js +2 -2
- package/dist/esm/hooks/useFilteredList.js +69 -11
- package/dist/esm/table/HeaderCell.js +3 -2
- package/dist/esm/table/Table.js +7 -1
- package/dist/esm/table/useVirtualTable.js +19 -1
- package/dist/esm/tree/TreeNode.js +3 -2
- package/dist/esm/tree/TreePanel.js +19 -5
- package/dist/esm/tree/useTree.js +109 -41
- package/dist/esm/tree/utils.js +5 -4
- package/dist/esm/virtual/Gallery.js +2 -2
- package/dist/esm/virtual/List.js +2 -2
- package/dist/types/hooks/useFilteredList.d.ts +49 -6
- package/dist/types/table/HeaderCell.d.ts +1 -1
- package/dist/types/table/Table.d.ts +1 -1
- package/dist/types/table/types.d.ts +3 -0
- package/dist/types/table/useVirtualTable.d.ts +3 -0
- package/dist/types/tree/TreePanel.d.ts +1 -1
- package/dist/types/tree/types.d.ts +12 -13
- package/dist/types/tree/useTree.d.ts +3 -0
- package/dist/types/tree/utils.d.ts +2 -2
- package/package.json +5 -5
- package/src/hooks/useFilteredList.tsx +90 -9
- package/src/table/HeaderCell.tsx +3 -2
- package/src/table/Table.tsx +5 -0
- package/src/table/types.ts +4 -0
- package/src/table/useVirtualTable.ts +24 -1
- package/src/tree/TreeNode.tsx +4 -5
- package/src/tree/TreePanel.tsx +12 -4
- package/src/tree/types.ts +12 -13
- package/src/tree/useTree.ts +105 -35
- package/src/tree/utils.ts +11 -5
- package/src/virtual/Gallery.tsx +1 -1
- package/src/virtual/List.tsx +1 -1
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
interface RetType<T, Q> {
|
|
2
|
+
onSearch: (query?: Q) => void;
|
|
3
|
+
query: Q;
|
|
4
|
+
filteredList: T[];
|
|
5
|
+
isSearching: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Custom hook to filter a list of items based on a query.
|
|
9
|
+
* It provides a way to search through the items and returns the filtered list.
|
|
10
|
+
* The hook uses a deferred value to optimize performance during transitions.
|
|
11
|
+
* It also allows for a custom matcher function to define how items should be matched against the query.
|
|
12
|
+
*
|
|
13
|
+
* @param items - The list of items to filter.
|
|
14
|
+
* @param matchAll - Match all phrases in the query list against the items.
|
|
15
|
+
* @returns An object containing the search function, current query, filtered list, and a boolean indicating if a search is in progress.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```jsx
|
|
19
|
+
* useFilteredList(items, (item, query) => {
|
|
20
|
+
* return item.name.includes(query);
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @see {@link https://adarshpastakia.github.io/react-fabric/?path=/docs/data-usefilteredlist--docs}
|
|
25
|
+
*/
|
|
26
|
+
export declare function useFilteredList<T extends AnyObject = KeyValue, Q extends AnyObject = string>(items: T[], matchAll?: boolean): RetType<T, Q>;
|
|
1
27
|
/**
|
|
2
28
|
* Custom hook to filter a list of items based on a query.
|
|
3
29
|
* It provides a way to search through the items and returns the filtered list.
|
|
@@ -17,9 +43,26 @@
|
|
|
17
43
|
*
|
|
18
44
|
* @see {@link https://adarshpastakia.github.io/react-fabric/?path=/docs/data-usefilteredlist--docs}
|
|
19
45
|
*/
|
|
20
|
-
export declare
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
46
|
+
export declare function useFilteredList<T extends AnyObject = KeyValue, Q extends AnyObject = string>(items: T[], matcher?: (item: T, query: Q) => boolean): RetType<T, Q>;
|
|
47
|
+
/**
|
|
48
|
+
* Custom hook to filter a list of items based on a query.
|
|
49
|
+
* It provides a way to search through the items and returns the filtered list.
|
|
50
|
+
* The hook uses a deferred value to optimize performance during transitions.
|
|
51
|
+
* It also allows for a custom matcher function to define how items should be matched against the query.
|
|
52
|
+
*
|
|
53
|
+
* @param items - The list of items to filter.
|
|
54
|
+
* @param matchAll - Match all phrases in the query list against the items.
|
|
55
|
+
* @param matcher - An optional function to match items against the query.
|
|
56
|
+
* @returns An object containing the search function, current query, filtered list, and a boolean indicating if a search is in progress.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```jsx
|
|
60
|
+
* useFilteredList(items, (item, query) => {
|
|
61
|
+
* return item.name.includes(query);
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @see {@link https://adarshpastakia.github.io/react-fabric/?path=/docs/data-usefilteredlist--docs}
|
|
66
|
+
*/
|
|
67
|
+
export declare function useFilteredList<T extends AnyObject = KeyValue, Q extends AnyObject = string>(items: T[], matchAll?: boolean, matcher?: (item: T, query: Q) => boolean): RetType<T, Q>;
|
|
68
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type TableColumn, type TableProps } from "./types";
|
|
2
|
-
export declare const HeaderCell: ({ id, dataType, label, icon, iconBg, iconColor, rtlFlip, actions, locked, filter, filterable, filterOptions, tooltip, sortable, resizable, width: _width, maxWidth, minWidth, sort, onSort, onFilter, }: TableColumn & Pick<TableProps, "sort" | "onSort" | "onFilter">) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare const HeaderCell: ({ id, field, dataType, label, icon, iconBg, iconColor, rtlFlip, actions, locked, filter, filterable, filterOptions, tooltip, sortable, resizable, width: _width, maxWidth, minWidth, sort, onSort, onFilter, }: TableColumn & Pick<TableProps, "sort" | "onSort" | "onFilter">) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -12,4 +12,4 @@ import { type TableProps } from "./types";
|
|
|
12
12
|
* @see {@link https://adarshpastakia.github.io/react-fabric/?path=/story/data-table--table}
|
|
13
13
|
* @see {@link https://tanstack.com/table/v8/docs/api/virtual}
|
|
14
14
|
*/
|
|
15
|
-
export declare const Table: <T extends KeyValue = KeyValue>({ ref, data, columns, keyProperty, groupProperty, checkableRows, initialScroll, hideableColumns, sort, loading, checked, emptyDisplay, groupRenderer, canExpand, children, onSort, onFilter, onScroll, onRowClick, onCheckedChanged, }: TableProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare const Table: <T extends KeyValue = KeyValue>({ ref, data, columns, keyProperty, groupProperty, checkableRows, initialScroll, hideableColumns, sort, loading, checked, emptyDisplay, groupRenderer, canExpand, children, onSort, onFilter, onScroll, onRowClick, onCheckedChanged, total, onLoadMore, }: TableProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -33,6 +33,7 @@ export declare const COL_DEFAULT_WIDTH = "12rem";
|
|
|
33
33
|
*/
|
|
34
34
|
export interface TableColumn<T = KeyValue> extends CssProp, IconProps, TestProps {
|
|
35
35
|
id: keyof T | string;
|
|
36
|
+
field?: string;
|
|
36
37
|
label?: string;
|
|
37
38
|
tooltip?: string;
|
|
38
39
|
actions?: ReactElement[];
|
|
@@ -91,4 +92,6 @@ export interface TableProps<T = KeyValue> extends RefProp<TableRef> {
|
|
|
91
92
|
canExpand?: (record: T) => boolean;
|
|
92
93
|
children?: (record: T) => Elements<AnyObject>;
|
|
93
94
|
onFilter?: (id: keyof T | string, value?: AnyObject) => void;
|
|
95
|
+
total?: number;
|
|
96
|
+
onLoadMore?: (lastIndex?: number) => void;
|
|
94
97
|
}
|
|
@@ -11,6 +11,9 @@ export declare const useVirtualTable: <T extends KeyValue = KeyValue>(data: T[],
|
|
|
11
11
|
checked?: AnyObject[];
|
|
12
12
|
keyProperty: keyof T;
|
|
13
13
|
groupProperty?: keyof T;
|
|
14
|
+
loading?: boolean;
|
|
15
|
+
total: number;
|
|
16
|
+
onLoadMore?: (startIndex: number) => void;
|
|
14
17
|
onCheckChanged?: (checked: AnyObject[]) => void;
|
|
15
18
|
}) => {
|
|
16
19
|
scrollerRef: import("react").RefObject<HTMLDivElement | null>;
|
|
@@ -40,4 +40,4 @@ import { type TreePanelProps } from "./types";
|
|
|
40
40
|
*
|
|
41
41
|
* @see {@link https://adarshpastakia.github.io/react-fabric/?path=/docs/data-treepanel--docs}
|
|
42
42
|
*/
|
|
43
|
-
export declare const TreePanel: <T extends KeyValue>({ ref, items, selected, checked, checkable, noLines,
|
|
43
|
+
export declare const TreePanel: <T extends KeyValue>({ ref, items, selected, checked, checkable, noLines, searchable, selectable, matcher, filterPlaceholder, defaultLeafIcon, defaultNodeIcon, expander, onChecked, onLoad, onQuery, onSelect, onClick, sorter, makeLabel, makeIcon, defaultExpanded, onExpandToggle, leafClassName, nodeClassName, ...aria }: TreePanelProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type BadgeType, type ChildProp, type CssProp, type Elements, type IconProps, type RefProp, type TestProps } from "@react-fabric/core/dist/types/types";
|
|
2
|
-
import { type ElementType } from "react";
|
|
3
2
|
interface TreeBaseNode<T> extends Omit<IconProps, "icon">, CssProp, TestProps {
|
|
4
3
|
id: string;
|
|
5
4
|
/**
|
|
@@ -23,7 +22,7 @@ interface TreeBaseNode<T> extends Omit<IconProps, "icon">, CssProp, TestProps {
|
|
|
23
22
|
*/
|
|
24
23
|
disabled?: boolean;
|
|
25
24
|
data?: T;
|
|
26
|
-
icon?:
|
|
25
|
+
icon?: Elements<JSX.Element>;
|
|
27
26
|
}
|
|
28
27
|
export type TreeNodeType<T extends KeyValue = KeyValue> = TreeBaseNode<T> & ({
|
|
29
28
|
leaf: true;
|
|
@@ -51,7 +50,7 @@ export interface InternalNode extends Omit<IconProps, "icon">, CssProp, TestProp
|
|
|
51
50
|
loaded: boolean;
|
|
52
51
|
parent?: string;
|
|
53
52
|
empty?: boolean;
|
|
54
|
-
icon?:
|
|
53
|
+
icon?: Elements<JSX.Element>;
|
|
55
54
|
errored?: string;
|
|
56
55
|
selected?: true;
|
|
57
56
|
childSelected?: true;
|
|
@@ -63,8 +62,8 @@ export interface InternalNode extends Omit<IconProps, "icon">, CssProp, TestProp
|
|
|
63
62
|
export interface TreeNodeProps extends ChildProp {
|
|
64
63
|
node: InternalNode;
|
|
65
64
|
expanders: [string, string];
|
|
66
|
-
defaultNodeIcon?:
|
|
67
|
-
defaultLeafIcon?:
|
|
65
|
+
defaultNodeIcon?: Elements<JSX.Element>;
|
|
66
|
+
defaultLeafIcon?: Elements<JSX.Element>;
|
|
68
67
|
noLines?: boolean;
|
|
69
68
|
selectable?: true | "leafOnly";
|
|
70
69
|
checkable?: true | "leafOnly";
|
|
@@ -78,6 +77,7 @@ export interface TreeNodeProps extends ChildProp {
|
|
|
78
77
|
export interface TreeRef {
|
|
79
78
|
select: (id: string) => void;
|
|
80
79
|
open: (id: string) => void;
|
|
80
|
+
openAndLoad: (list: string[]) => void;
|
|
81
81
|
}
|
|
82
82
|
export interface TreePanelProps<T extends KeyValue = KeyValue> extends TestProps, RefProp<TreeRef> {
|
|
83
83
|
items?: Array<TreeNodeType<T>>;
|
|
@@ -136,22 +136,21 @@ export interface TreePanelProps<T extends KeyValue = KeyValue> extends TestProps
|
|
|
136
136
|
/**
|
|
137
137
|
* callback on selection of tree node
|
|
138
138
|
*/
|
|
139
|
-
onSelect?: (id: string, data: T) =>
|
|
139
|
+
onSelect?: (id: string, data: T) => boolean | undefined;
|
|
140
140
|
/**
|
|
141
141
|
* callback on change of checked list
|
|
142
|
+
* @param leafs - list of checked leaf nodes
|
|
143
|
+
* @param nodes - list of checked nodes
|
|
144
|
+
* @param partials - list of partially checked nodes
|
|
142
145
|
*/
|
|
143
|
-
onChecked?: (leafs: string[], nodes: string[]) => void;
|
|
144
|
-
/**
|
|
145
|
-
* item label renderer
|
|
146
|
-
*/
|
|
147
|
-
renderer?: (data: T) => JSX.Element;
|
|
146
|
+
onChecked?: (leafs: string[], nodes: string[], partials: string[]) => void;
|
|
148
147
|
/**
|
|
149
148
|
* item filter matcher
|
|
150
149
|
*/
|
|
151
150
|
matcher?: (data: T, query: string) => boolean;
|
|
152
151
|
sorter?: false | ((a: T, b: T) => number);
|
|
153
|
-
makeLabel?: (node: T) =>
|
|
154
|
-
makeIcon?: (node: T) =>
|
|
152
|
+
makeLabel?: (node: T) => Elements<JSX.Element>;
|
|
153
|
+
makeIcon?: (node: T) => Elements<JSX.Element>;
|
|
155
154
|
defaultExpanded?: string[];
|
|
156
155
|
onExpandToggle?: (id: string[]) => void;
|
|
157
156
|
leafClassName?: string;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { type InternalNode, type TreePanelProps } from "./types";
|
|
2
2
|
export declare const useTree: <T extends KeyValue>({ items, checked, selected, sorter, matcher, onLoad, onQuery, onSelect, onChecked, defaultExpanded, onExpandToggle, }: Partial<TreePanelProps<T>>) => {
|
|
3
3
|
tree: InternalNode[];
|
|
4
|
+
query: string | undefined;
|
|
5
|
+
selected: string | undefined;
|
|
4
6
|
toggleExpand: (id: string) => void;
|
|
5
7
|
expandAll: () => void;
|
|
6
8
|
collapseAll: () => void;
|
|
7
9
|
toggleCheck: (id: string) => void;
|
|
10
|
+
expandAndLoad: (expandList: string[]) => void;
|
|
8
11
|
select: (id: string) => void;
|
|
9
12
|
expand: (id: string) => void;
|
|
10
13
|
onFilter: {
|
|
@@ -8,6 +8,6 @@ export declare const refactorTree: (nodes: TreeNodeType[], { sorter, defaultExpa
|
|
|
8
8
|
}) => InternalNode[];
|
|
9
9
|
export declare const makeTreeMap: (nodes: InternalNode[], map?: Map<any, any>) => Map<any, any>;
|
|
10
10
|
export declare const flattenTree: (nodes: InternalNode[], lines?: Array<0 | 1 | 2 | 3>) => InternalNode[];
|
|
11
|
-
export declare const updateSelection: (nodes: Map<string, InternalNode>, id
|
|
12
|
-
export declare const updateChecked: (list: Map<string, AnyObject>, id: string) => void;
|
|
11
|
+
export declare const updateSelection: (nodes: Map<string, InternalNode>, id?: string, selected?: true) => string | undefined;
|
|
12
|
+
export declare const updateChecked: (list: Map<string, AnyObject>, id: string, checked?: 0 | 1 | 2) => void;
|
|
13
13
|
export declare const filterTree: (nodes: Map<string, InternalNode>, query?: string, matcher?: AnyObject) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-fabric/data",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.56",
|
|
4
4
|
"description": "RUF: Data package",
|
|
5
5
|
"author": "Adarsh Pastakia <adarshpastakia@outlook.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"watch": "npm-run-all -p watch:rollup watch:dts"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@react-fabric/core": "^1.0.0-beta.
|
|
39
|
-
"@react-fabric/date": "^1.0.0-beta.
|
|
40
|
-
"@react-fabric/form": "^1.0.0-beta.
|
|
38
|
+
"@react-fabric/core": "^1.0.0-beta.55",
|
|
39
|
+
"@react-fabric/date": "^1.0.0-beta.55",
|
|
40
|
+
"@react-fabric/form": "^1.0.0-beta.56",
|
|
41
41
|
"@react-fabric/utilities": "^1.0.0-beta.52",
|
|
42
42
|
"@tanstack/react-virtual": "^3.13.9",
|
|
43
43
|
"classnames": "^2.5.1",
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"node": ">=18.12.0",
|
|
55
55
|
"npm": ">=8.19.0"
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "fd9dd6cfd1a58efb5c4bfb6446928a78cb4f4266"
|
|
58
58
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
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 { isString, matchString } from "@react-fabric/utilities";
|
|
24
|
+
import { isArray, isString, matchString } from "@react-fabric/utilities";
|
|
25
25
|
import {
|
|
26
26
|
useCallback,
|
|
27
27
|
useDeferredValue,
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
const filterList = (
|
|
34
34
|
items: AnyObject[],
|
|
35
35
|
query: AnyObject = "",
|
|
36
|
+
matchAll: boolean = true,
|
|
36
37
|
matcher?: AnyObject,
|
|
37
38
|
) => {
|
|
38
39
|
const newList: AnyObject[] = [];
|
|
@@ -40,7 +41,20 @@ const filterList = (
|
|
|
40
41
|
if (matcher) {
|
|
41
42
|
return matcher?.(item, query) && newList.push(item);
|
|
42
43
|
}
|
|
43
|
-
if (query &&
|
|
44
|
+
if (query && isArray(query) && query.length > 0) {
|
|
45
|
+
if (
|
|
46
|
+
matchAll &&
|
|
47
|
+
query.every((q) => matchString(item.label ?? item.toString(), q))
|
|
48
|
+
) {
|
|
49
|
+
return newList.push(item);
|
|
50
|
+
}
|
|
51
|
+
if (
|
|
52
|
+
!matchAll &&
|
|
53
|
+
query.some((q) => matchString(item.label ?? item.toString(), q))
|
|
54
|
+
) {
|
|
55
|
+
return newList.push(item);
|
|
56
|
+
}
|
|
57
|
+
} else if (query && isString(query)) {
|
|
44
58
|
if (matchString(item.label ?? item.toString(), query)) {
|
|
45
59
|
return newList.push(item);
|
|
46
60
|
}
|
|
@@ -51,6 +65,61 @@ const filterList = (
|
|
|
51
65
|
return newList;
|
|
52
66
|
};
|
|
53
67
|
|
|
68
|
+
interface RetType<T, Q> {
|
|
69
|
+
onSearch: (query?: Q) => void;
|
|
70
|
+
query: Q;
|
|
71
|
+
filteredList: T[];
|
|
72
|
+
isSearching: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Custom hook to filter a list of items based on a query.
|
|
77
|
+
* It provides a way to search through the items and returns the filtered list.
|
|
78
|
+
* The hook uses a deferred value to optimize performance during transitions.
|
|
79
|
+
* It also allows for a custom matcher function to define how items should be matched against the query.
|
|
80
|
+
*
|
|
81
|
+
* @param items - The list of items to filter.
|
|
82
|
+
* @param matchAll - Match all phrases in the query list against the items.
|
|
83
|
+
* @returns An object containing the search function, current query, filtered list, and a boolean indicating if a search is in progress.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```jsx
|
|
87
|
+
* useFilteredList(items, (item, query) => {
|
|
88
|
+
* return item.name.includes(query);
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @see {@link https://adarshpastakia.github.io/react-fabric/?path=/docs/data-usefilteredlist--docs}
|
|
93
|
+
*/
|
|
94
|
+
export function useFilteredList<
|
|
95
|
+
T extends AnyObject = KeyValue,
|
|
96
|
+
Q extends AnyObject = string,
|
|
97
|
+
>(items: T[], matchAll?: boolean): RetType<T, Q>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Custom hook to filter a list of items based on a query.
|
|
101
|
+
* It provides a way to search through the items and returns the filtered list.
|
|
102
|
+
* The hook uses a deferred value to optimize performance during transitions.
|
|
103
|
+
* It also allows for a custom matcher function to define how items should be matched against the query.
|
|
104
|
+
*
|
|
105
|
+
* @param items - The list of items to filter.
|
|
106
|
+
* @param matcher - An optional function to match items against the query.
|
|
107
|
+
* @returns An object containing the search function, current query, filtered list, and a boolean indicating if a search is in progress.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```jsx
|
|
111
|
+
* useFilteredList(items, (item, query) => {
|
|
112
|
+
* return item.name.includes(query);
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @see {@link https://adarshpastakia.github.io/react-fabric/?path=/docs/data-usefilteredlist--docs}
|
|
117
|
+
*/
|
|
118
|
+
export function useFilteredList<
|
|
119
|
+
T extends AnyObject = KeyValue,
|
|
120
|
+
Q extends AnyObject = string,
|
|
121
|
+
>(items: T[], matcher?: (item: T, query: Q) => boolean): RetType<T, Q>;
|
|
122
|
+
|
|
54
123
|
/**
|
|
55
124
|
* Custom hook to filter a list of items based on a query.
|
|
56
125
|
* It provides a way to search through the items and returns the filtered list.
|
|
@@ -58,6 +127,7 @@ const filterList = (
|
|
|
58
127
|
* It also allows for a custom matcher function to define how items should be matched against the query.
|
|
59
128
|
*
|
|
60
129
|
* @param items - The list of items to filter.
|
|
130
|
+
* @param matchAll - Match all phrases in the query list against the items.
|
|
61
131
|
* @param matcher - An optional function to match items against the query.
|
|
62
132
|
* @returns An object containing the search function, current query, filtered list, and a boolean indicating if a search is in progress.
|
|
63
133
|
*
|
|
@@ -70,28 +140,39 @@ const filterList = (
|
|
|
70
140
|
*
|
|
71
141
|
* @see {@link https://adarshpastakia.github.io/react-fabric/?path=/docs/data-usefilteredlist--docs}
|
|
72
142
|
*/
|
|
73
|
-
export
|
|
143
|
+
export function useFilteredList<
|
|
74
144
|
T extends AnyObject = KeyValue,
|
|
75
145
|
Q extends AnyObject = string,
|
|
76
146
|
>(
|
|
77
147
|
items: T[],
|
|
148
|
+
matchAll?: boolean,
|
|
78
149
|
matcher?: (item: T, query: Q) => boolean,
|
|
79
|
-
)
|
|
150
|
+
): RetType<T, Q>;
|
|
151
|
+
|
|
152
|
+
export function useFilteredList<
|
|
153
|
+
T extends AnyObject = KeyValue,
|
|
154
|
+
Q extends AnyObject = string,
|
|
155
|
+
>(items: T[], matchAll?: AnyObject, matcher?: (item: T, query: Q) => boolean) {
|
|
80
156
|
const [query, setQuery] = useState<Q>();
|
|
81
157
|
const _items = useDeferredValue(items ?? []);
|
|
82
158
|
const [filteredList, setFilteredList] = useState<T[]>([]);
|
|
83
159
|
const [isSearching, startTransition] = useTransition();
|
|
84
160
|
|
|
161
|
+
const matchingAll = typeof matchAll === "boolean" ? matchAll : true;
|
|
162
|
+
const matcherFn = typeof matchAll === "function" ? matchAll : matcher;
|
|
163
|
+
|
|
85
164
|
const filterItems = useCallback(
|
|
86
|
-
(items: T[], query?: Q) =>
|
|
87
|
-
startTransition(() =>
|
|
165
|
+
(items: T[], query?: Q, matchingAll?: boolean) =>
|
|
166
|
+
startTransition(() =>
|
|
167
|
+
setFilteredList(filterList(items, query, matchingAll, matcherFn)),
|
|
168
|
+
),
|
|
88
169
|
[],
|
|
89
170
|
);
|
|
90
171
|
|
|
91
172
|
useEffect(() => {
|
|
92
|
-
if (query) filterItems(_items, query);
|
|
173
|
+
if (query) filterItems(_items, query, matchingAll);
|
|
93
174
|
else setFilteredList(items);
|
|
94
|
-
}, [query, _items]);
|
|
175
|
+
}, [query, matchingAll, _items]);
|
|
95
176
|
|
|
96
177
|
return { onSearch: setQuery, query, filteredList, isSearching };
|
|
97
|
-
}
|
|
178
|
+
}
|
package/src/table/HeaderCell.tsx
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
|
|
46
46
|
export const HeaderCell = ({
|
|
47
47
|
id,
|
|
48
|
+
field,
|
|
48
49
|
dataType,
|
|
49
50
|
label,
|
|
50
51
|
icon,
|
|
@@ -99,7 +100,7 @@ export const HeaderCell = ({
|
|
|
99
100
|
type={dataType}
|
|
100
101
|
list={filterOptions}
|
|
101
102
|
filter={filter}
|
|
102
|
-
onFilter={(value) => onFilter?.(id, value)}
|
|
103
|
+
onFilter={(value) => onFilter?.(field ?? id, value)}
|
|
103
104
|
/>
|
|
104
105
|
</Menu>,
|
|
105
106
|
);
|
|
@@ -131,7 +132,7 @@ export const HeaderCell = ({
|
|
|
131
132
|
type={dataType}
|
|
132
133
|
list={filterOptions}
|
|
133
134
|
filter={filter}
|
|
134
|
-
onFilter={(value) => onFilter?.(id, value)}
|
|
135
|
+
onFilter={(value) => onFilter?.(field ?? id, value)}
|
|
135
136
|
/>,
|
|
136
137
|
];
|
|
137
138
|
}
|
package/src/table/Table.tsx
CHANGED
|
@@ -82,6 +82,8 @@ export const Table = <T extends KeyValue = KeyValue>({
|
|
|
82
82
|
onScroll,
|
|
83
83
|
onRowClick,
|
|
84
84
|
onCheckedChanged,
|
|
85
|
+
total = 0,
|
|
86
|
+
onLoadMore,
|
|
85
87
|
}: TableProps<T>) => {
|
|
86
88
|
const { t } = useTranslation("data");
|
|
87
89
|
const fireCheckChanged = useDebounce(
|
|
@@ -109,6 +111,9 @@ export const Table = <T extends KeyValue = KeyValue>({
|
|
|
109
111
|
checked,
|
|
110
112
|
keyProperty,
|
|
111
113
|
groupProperty,
|
|
114
|
+
total,
|
|
115
|
+
loading,
|
|
116
|
+
onLoadMore,
|
|
112
117
|
onCheckChanged: fireCheckChanged,
|
|
113
118
|
});
|
|
114
119
|
const refBody = useRef<HTMLDivElement>(null);
|
package/src/table/types.ts
CHANGED
|
@@ -67,6 +67,7 @@ export interface TableColumn<T = KeyValue>
|
|
|
67
67
|
IconProps,
|
|
68
68
|
TestProps {
|
|
69
69
|
id: keyof T | string;
|
|
70
|
+
field?: string;
|
|
70
71
|
label?: string;
|
|
71
72
|
tooltip?: string;
|
|
72
73
|
actions?: ReactElement[];
|
|
@@ -134,4 +135,7 @@ export interface TableProps<T = KeyValue> extends RefProp<TableRef> {
|
|
|
134
135
|
children?: (record: T) => Elements<AnyObject>;
|
|
135
136
|
|
|
136
137
|
onFilter?: (id: keyof T | string, value?: AnyObject) => void;
|
|
138
|
+
|
|
139
|
+
total?: number;
|
|
140
|
+
onLoadMore?: (lastIndex?: number) => void;
|
|
137
141
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
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 { compareValues, groupBy } from "@react-fabric/utilities";
|
|
24
|
+
import { compareValues, debounce, groupBy } from "@react-fabric/utilities";
|
|
25
25
|
import {
|
|
26
26
|
defaultRangeExtractor,
|
|
27
27
|
type Range,
|
|
@@ -60,6 +60,9 @@ export const useVirtualTable = <T extends KeyValue = KeyValue>(
|
|
|
60
60
|
checked?: AnyObject[];
|
|
61
61
|
keyProperty: keyof T;
|
|
62
62
|
groupProperty?: keyof T;
|
|
63
|
+
loading?: boolean;
|
|
64
|
+
total: number;
|
|
65
|
+
onLoadMore?: (startIndex: number) => void;
|
|
63
66
|
onCheckChanged?: (checked: AnyObject[]) => void;
|
|
64
67
|
},
|
|
65
68
|
) => {
|
|
@@ -202,6 +205,26 @@ export const useVirtualTable = <T extends KeyValue = KeyValue>(
|
|
|
202
205
|
dispatch({ type: "updateState", checked: options.checked ?? [] });
|
|
203
206
|
}, [options.checked]);
|
|
204
207
|
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
if (options.onLoadMore) {
|
|
210
|
+
const firstItem = virtualItems[0]?.index;
|
|
211
|
+
const lastItem = virtualItems?.slice(-1).pop()?.index;
|
|
212
|
+
const canLoadPrevPage =
|
|
213
|
+
firstItem !== undefined && state.items[firstItem] === null;
|
|
214
|
+
const canLoadNextPage =
|
|
215
|
+
lastItem !== undefined &&
|
|
216
|
+
lastItem === state.items.length - 1 &&
|
|
217
|
+
state.items.length < options.total;
|
|
218
|
+
const db = debounce(options.onLoadMore);
|
|
219
|
+
if (canLoadPrevPage) {
|
|
220
|
+
db(firstItem);
|
|
221
|
+
} else if (!options.loading && canLoadNextPage) {
|
|
222
|
+
db(lastItem + 1);
|
|
223
|
+
}
|
|
224
|
+
return () => db.cancel();
|
|
225
|
+
}
|
|
226
|
+
}, [options.onLoadMore, virtualItems]);
|
|
227
|
+
|
|
205
228
|
return {
|
|
206
229
|
scrollerRef,
|
|
207
230
|
items: virtualItems,
|
package/src/tree/TreeNode.tsx
CHANGED
|
@@ -97,13 +97,10 @@ export const TreeNode = ({
|
|
|
97
97
|
<div
|
|
98
98
|
role="treeitem"
|
|
99
99
|
aria-selected={node.selected}
|
|
100
|
-
className={classNames(
|
|
101
|
-
"flex flex-nowrap items-center",
|
|
102
|
-
node.className,
|
|
103
|
-
node.leaf ? leafClassName : nodeClassName,
|
|
104
|
-
)}
|
|
100
|
+
className={classNames("flex flex-nowrap items-center")}
|
|
105
101
|
data-testid={node["data-testid"]}
|
|
106
102
|
data-test-value={node["data-test-value"]}
|
|
103
|
+
data-id={node.id}
|
|
107
104
|
>
|
|
108
105
|
{filler}
|
|
109
106
|
{node.loading && (
|
|
@@ -147,6 +144,8 @@ export const TreeNode = ({
|
|
|
147
144
|
"group/tool data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none",
|
|
148
145
|
node.childSelected && "font-medium",
|
|
149
146
|
node.disabled && "text-muted opacity-65",
|
|
147
|
+
node.className,
|
|
148
|
+
node.leaf ? leafClassName : nodeClassName,
|
|
150
149
|
!node.disabled &&
|
|
151
150
|
(canSelect || onClick) &&
|
|
152
151
|
"hover:bg-primary-50 cursor-pointer",
|
package/src/tree/TreePanel.tsx
CHANGED
|
@@ -31,7 +31,7 @@ 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";
|
|
@@ -86,7 +86,6 @@ export const TreePanel = <T extends KeyValue>({
|
|
|
86
86
|
checked,
|
|
87
87
|
checkable,
|
|
88
88
|
noLines,
|
|
89
|
-
renderer,
|
|
90
89
|
searchable,
|
|
91
90
|
selectable,
|
|
92
91
|
matcher,
|
|
@@ -110,10 +109,13 @@ export const TreePanel = <T extends KeyValue>({
|
|
|
110
109
|
}: TreePanelProps<T>) => {
|
|
111
110
|
const {
|
|
112
111
|
tree,
|
|
112
|
+
query,
|
|
113
|
+
selected: currentSelected,
|
|
113
114
|
toggleExpand,
|
|
114
115
|
toggleCheck,
|
|
115
116
|
expandAll,
|
|
116
117
|
collapseAll,
|
|
118
|
+
expandAndLoad,
|
|
117
119
|
select,
|
|
118
120
|
expand,
|
|
119
121
|
onFilter,
|
|
@@ -154,11 +156,17 @@ export const TreePanel = <T extends KeyValue>({
|
|
|
154
156
|
ref,
|
|
155
157
|
() => ({
|
|
156
158
|
open: (id: string) => expand(id),
|
|
159
|
+
openAndLoad: (list: string[]) => expandAndLoad(list),
|
|
157
160
|
select: (id: string) => select(id),
|
|
158
161
|
}),
|
|
159
162
|
[],
|
|
160
163
|
);
|
|
161
164
|
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
const index = tree.findIndex((n) => n.id === currentSelected);
|
|
167
|
+
virtualizer.scrollToIndex(index, { align: "auto" });
|
|
168
|
+
}, [currentSelected]);
|
|
169
|
+
|
|
162
170
|
return (
|
|
163
171
|
<Section>
|
|
164
172
|
<Header
|
|
@@ -167,6 +175,7 @@ export const TreePanel = <T extends KeyValue>({
|
|
|
167
175
|
>
|
|
168
176
|
{searchable && (
|
|
169
177
|
<Search
|
|
178
|
+
value={query}
|
|
170
179
|
onSearch={onFilter}
|
|
171
180
|
allowClear
|
|
172
181
|
placeholder={filterPlaceholder}
|
|
@@ -216,8 +225,7 @@ export const TreePanel = <T extends KeyValue>({
|
|
|
216
225
|
leafClassName={leafClassName}
|
|
217
226
|
nodeClassName={nodeClassName}
|
|
218
227
|
>
|
|
219
|
-
{(tree[index].data &&
|
|
220
|
-
makeLabel?.(tree[index].data) ??
|
|
228
|
+
{(tree[index].data && makeLabel?.(tree[index].data)) ??
|
|
221
229
|
tree[index].label}
|
|
222
230
|
</TreeNode>
|
|
223
231
|
</div>
|
package/src/tree/types.ts
CHANGED
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
type RefProp,
|
|
31
31
|
type TestProps,
|
|
32
32
|
} from "@react-fabric/core/dist/types/types";
|
|
33
|
-
import { type ElementType } from "react";
|
|
34
33
|
|
|
35
34
|
interface TreeBaseNode<T> extends Omit<IconProps, "icon">, CssProp, TestProps {
|
|
36
35
|
id: string;
|
|
@@ -56,7 +55,7 @@ interface TreeBaseNode<T> extends Omit<IconProps, "icon">, CssProp, TestProps {
|
|
|
56
55
|
disabled?: boolean;
|
|
57
56
|
data?: T;
|
|
58
57
|
|
|
59
|
-
icon?:
|
|
58
|
+
icon?: Elements<JSX.Element>;
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
export type TreeNodeType<T extends KeyValue = KeyValue> = TreeBaseNode<T> &
|
|
@@ -90,7 +89,7 @@ export interface InternalNode
|
|
|
90
89
|
loaded: boolean;
|
|
91
90
|
parent?: string;
|
|
92
91
|
empty?: boolean;
|
|
93
|
-
icon?:
|
|
92
|
+
icon?: Elements<JSX.Element>;
|
|
94
93
|
errored?: string;
|
|
95
94
|
selected?: true;
|
|
96
95
|
childSelected?: true;
|
|
@@ -103,8 +102,8 @@ export interface InternalNode
|
|
|
103
102
|
export interface TreeNodeProps extends ChildProp {
|
|
104
103
|
node: InternalNode;
|
|
105
104
|
expanders: [string, string];
|
|
106
|
-
defaultNodeIcon?:
|
|
107
|
-
defaultLeafIcon?:
|
|
105
|
+
defaultNodeIcon?: Elements<JSX.Element>;
|
|
106
|
+
defaultLeafIcon?: Elements<JSX.Element>;
|
|
108
107
|
noLines?: boolean;
|
|
109
108
|
selectable?: true | "leafOnly";
|
|
110
109
|
checkable?: true | "leafOnly";
|
|
@@ -119,6 +118,7 @@ export interface TreeNodeProps extends ChildProp {
|
|
|
119
118
|
export interface TreeRef {
|
|
120
119
|
select: (id: string) => void;
|
|
121
120
|
open: (id: string) => void;
|
|
121
|
+
openAndLoad: (list: string[]) => void;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
export interface TreePanelProps<T extends KeyValue = KeyValue>
|
|
@@ -185,23 +185,22 @@ export interface TreePanelProps<T extends KeyValue = KeyValue>
|
|
|
185
185
|
/**
|
|
186
186
|
* callback on selection of tree node
|
|
187
187
|
*/
|
|
188
|
-
onSelect?: (id: string, data: T) =>
|
|
188
|
+
onSelect?: (id: string, data: T) => boolean | undefined;
|
|
189
189
|
/**
|
|
190
190
|
* callback on change of checked list
|
|
191
|
+
* @param leafs - list of checked leaf nodes
|
|
192
|
+
* @param nodes - list of checked nodes
|
|
193
|
+
* @param partials - list of partially checked nodes
|
|
191
194
|
*/
|
|
192
|
-
onChecked?: (leafs: string[], nodes: string[]) => void;
|
|
193
|
-
/**
|
|
194
|
-
* item label renderer
|
|
195
|
-
*/
|
|
196
|
-
renderer?: (data: T) => JSX.Element;
|
|
195
|
+
onChecked?: (leafs: string[], nodes: string[], partials: string[]) => void;
|
|
197
196
|
/**
|
|
198
197
|
* item filter matcher
|
|
199
198
|
*/
|
|
200
199
|
matcher?: (data: T, query: string) => boolean;
|
|
201
200
|
|
|
202
201
|
sorter?: false | ((a: T, b: T) => number);
|
|
203
|
-
makeLabel?: (node: T) =>
|
|
204
|
-
makeIcon?: (node: T) =>
|
|
202
|
+
makeLabel?: (node: T) => Elements<JSX.Element>;
|
|
203
|
+
makeIcon?: (node: T) => Elements<JSX.Element>;
|
|
205
204
|
|
|
206
205
|
defaultExpanded?: string[];
|
|
207
206
|
onExpandToggle?: (id: string[]) => void;
|