@react-fabric/data 1.0.0-beta.47 → 1.0.0-beta.49
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/table/AddColumn.js +1 -1
- package/dist/cjs/table/ColumnFilters.js +97 -0
- package/dist/cjs/table/HeaderCell.js +47 -7
- package/dist/cjs/table/Table.js +8 -4
- package/dist/cjs/tree/TreeNode.js +5 -5
- package/dist/cjs/virtual/Gallery.js +9 -8
- package/dist/cjs/virtual/List.js +2 -1
- package/dist/esm/table/AddColumn.js +1 -1
- package/dist/esm/table/ColumnFilters.js +97 -0
- package/dist/esm/table/HeaderCell.js +48 -8
- package/dist/esm/table/Table.js +8 -4
- package/dist/esm/tree/TreeNode.js +5 -5
- package/dist/esm/virtual/Gallery.js +9 -8
- package/dist/esm/virtual/List.js +2 -1
- package/dist/types/table/ColumnFilters.d.ts +9 -0
- 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 -1
- package/dist/types/table/useVirtualTable.d.ts +1 -1
- package/dist/types/virtual/Gallery.d.ts +2 -2
- package/dist/types/virtual/List.d.ts +2 -2
- package/package.json +7 -7
- package/src/table/AddColumn.tsx +1 -1
- package/src/table/ColumnFilters.tsx +105 -0
- package/src/table/HeaderCell.tsx +50 -6
- package/src/table/Table.tsx +23 -4
- package/src/table/types.ts +4 -1
- package/src/tree/TreeNode.tsx +17 -9
- package/src/virtual/Gallery.tsx +10 -10
- package/src/virtual/List.tsx +4 -5
|
@@ -30,7 +30,7 @@ var AddColumn = function AddColumn(_ref) {
|
|
|
30
30
|
var columns = _ref.columns,
|
|
31
31
|
onClick = _ref.onClick;
|
|
32
32
|
return /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
33
|
-
className: "group font-medium w-6 flex flex-nowrap text-start items-
|
|
33
|
+
className: "group font-medium w-6 flex flex-nowrap text-start items-center",
|
|
34
34
|
children: /*#__PURE__*/jsxRuntime.jsxs(core.Dropdown, {
|
|
35
35
|
placement: "bottom-end",
|
|
36
36
|
children: [/*#__PURE__*/jsxRuntime.jsx(core.Icon, {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
|
|
4
|
+
var core = require('@react-fabric/core');
|
|
5
|
+
var form = require('@react-fabric/form');
|
|
6
|
+
var utilities = require('@react-fabric/utilities');
|
|
7
|
+
var react = require('react');
|
|
8
|
+
var useFilteredList = require('../hooks/useFilteredList.js');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
|
|
11
|
+
var ListFilter = function ListFilter(_ref) {
|
|
12
|
+
var _ref$list = _ref.list,
|
|
13
|
+
list = _ref$list === void 0 ? utilities.EMPTY_ARRAY : _ref$list,
|
|
14
|
+
filter = _ref.filter,
|
|
15
|
+
onFilter = _ref.onFilter;
|
|
16
|
+
var _useState = react.useState(new Set(filter)),
|
|
17
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
18
|
+
selected = _useState2[0],
|
|
19
|
+
setSelected = _useState2[1];
|
|
20
|
+
var _useFilteredList = useFilteredList.useFilteredList(list, function (item, query) {
|
|
21
|
+
var _item$id;
|
|
22
|
+
return utilities.matchString((_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : item, query);
|
|
23
|
+
}),
|
|
24
|
+
filteredList = _useFilteredList.filteredList,
|
|
25
|
+
query = _useFilteredList.query,
|
|
26
|
+
onSearch = _useFilteredList.onSearch;
|
|
27
|
+
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
28
|
+
className: "flex flex-col",
|
|
29
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
30
|
+
children: /*#__PURE__*/jsxRuntime.jsx(form.Search, {
|
|
31
|
+
autoFocus: true,
|
|
32
|
+
value: query,
|
|
33
|
+
onSearch: onSearch,
|
|
34
|
+
searchOnChange: true
|
|
35
|
+
})
|
|
36
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
37
|
+
className: "flex-1 overflow-auto scroll-thin",
|
|
38
|
+
children: [filteredList.map(function (v, idx) {
|
|
39
|
+
var _v$id, _v$label;
|
|
40
|
+
return /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
41
|
+
className: "flex gap-x-1 text-xs items-center",
|
|
42
|
+
children: /*#__PURE__*/jsxRuntime.jsx(form.Checkbox, {
|
|
43
|
+
checked: selected.has((_v$id = v.id) !== null && _v$id !== void 0 ? _v$id : v),
|
|
44
|
+
onChange: function onChange(b) {
|
|
45
|
+
var _v$id2, _v$id3;
|
|
46
|
+
var set = new Set(Array.from(selected.values()));
|
|
47
|
+
b ? set.add((_v$id2 = v.id) !== null && _v$id2 !== void 0 ? _v$id2 : v) : set["delete"]((_v$id3 = v.id) !== null && _v$id3 !== void 0 ? _v$id3 : v);
|
|
48
|
+
setSelected(set);
|
|
49
|
+
},
|
|
50
|
+
label: /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
51
|
+
className: "truncate",
|
|
52
|
+
children: (_v$label = v.label) !== null && _v$label !== void 0 ? _v$label : v
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
}, idx);
|
|
56
|
+
}), filteredList.length === 0 && /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
57
|
+
className: "text-muted text-xs",
|
|
58
|
+
children: "No items found"
|
|
59
|
+
})]
|
|
60
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
61
|
+
className: "flex justify-end",
|
|
62
|
+
children: /*#__PURE__*/jsxRuntime.jsx(core.DropdownDismiss, {
|
|
63
|
+
children: /*#__PURE__*/jsxRuntime.jsx(core.Button, {
|
|
64
|
+
size: "xs",
|
|
65
|
+
onClick: function onClick() {
|
|
66
|
+
return onFilter === null || onFilter === void 0 ? void 0 : onFilter(Array.from(selected));
|
|
67
|
+
},
|
|
68
|
+
children: "Apply"
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
})]
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
var ColumnFilters = function ColumnFilters(_ref2) {
|
|
75
|
+
var type = _ref2.type,
|
|
76
|
+
list = _ref2.list,
|
|
77
|
+
filter = _ref2.filter,
|
|
78
|
+
onFilter = _ref2.onFilter;
|
|
79
|
+
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
80
|
+
className: "flex flex-col min-w-[16rem]",
|
|
81
|
+
children: [list && /*#__PURE__*/jsxRuntime.jsx(ListFilter, {
|
|
82
|
+
list: list,
|
|
83
|
+
filter: filter,
|
|
84
|
+
onFilter: onFilter
|
|
85
|
+
}), !list && type === "string" && /*#__PURE__*/jsxRuntime.jsx(form.Input, {
|
|
86
|
+
autoFocus: true,
|
|
87
|
+
allowClear: true,
|
|
88
|
+
value: filter,
|
|
89
|
+
onEnterPressed: function onEnterPressed(e) {
|
|
90
|
+
var _e$target$value;
|
|
91
|
+
return onFilter((_e$target$value = e.target.value) !== null && _e$target$value !== void 0 ? _e$target$value : "");
|
|
92
|
+
}
|
|
93
|
+
})]
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
exports.ColumnFilters = ColumnFilters;
|
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
|
|
4
4
|
var core = require('@react-fabric/core');
|
|
5
|
+
var utilities = require('@react-fabric/utilities');
|
|
5
6
|
var react = require('react');
|
|
7
|
+
var ColumnFilters = require('./ColumnFilters.js');
|
|
6
8
|
var Context = require('./Context.js');
|
|
7
9
|
var types = require('./types.js');
|
|
8
10
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
11
|
|
|
10
12
|
var HeaderCell = function HeaderCell(_ref) {
|
|
11
13
|
var id = _ref.id,
|
|
14
|
+
dataType = _ref.dataType,
|
|
12
15
|
label = _ref.label,
|
|
13
16
|
icon = _ref.icon,
|
|
14
17
|
iconBg = _ref.iconBg,
|
|
@@ -16,14 +19,18 @@ var HeaderCell = function HeaderCell(_ref) {
|
|
|
16
19
|
rtlFlip = _ref.rtlFlip,
|
|
17
20
|
actions = _ref.actions;
|
|
18
21
|
_ref.locked;
|
|
19
|
-
var
|
|
22
|
+
var filter = _ref.filter,
|
|
23
|
+
filterable = _ref.filterable,
|
|
24
|
+
filterOptions = _ref.filterOptions,
|
|
25
|
+
tooltip = _ref.tooltip,
|
|
20
26
|
sortable = _ref.sortable,
|
|
21
27
|
resizable = _ref.resizable,
|
|
22
28
|
_width = _ref.width,
|
|
23
29
|
maxWidth = _ref.maxWidth,
|
|
24
30
|
minWidth = _ref.minWidth,
|
|
25
31
|
sort = _ref.sort,
|
|
26
|
-
onSort = _ref.onSort
|
|
32
|
+
onSort = _ref.onSort,
|
|
33
|
+
_onFilter = _ref.onFilter;
|
|
27
34
|
var _useTableContext = Context.useTableContext(),
|
|
28
35
|
startResize = _useTableContext.startResize,
|
|
29
36
|
widths = _useTableContext.widths;
|
|
@@ -39,6 +46,21 @@ var HeaderCell = function HeaderCell(_ref) {
|
|
|
39
46
|
}, [onSort, sort, sortable]);
|
|
40
47
|
var menus = react.useMemo(function () {
|
|
41
48
|
var ret = [];
|
|
49
|
+
if (filterable && (dataType !== null && dataType !== void 0 ? dataType : filterOptions)) {
|
|
50
|
+
ret.push( /*#__PURE__*/jsxRuntime.jsx(core.Menu, {
|
|
51
|
+
label: "Filter",
|
|
52
|
+
icon: filter ? core.CoreIcons.tick : "",
|
|
53
|
+
trigger: "click",
|
|
54
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ColumnFilters.ColumnFilters, {
|
|
55
|
+
type: dataType,
|
|
56
|
+
list: filterOptions,
|
|
57
|
+
filter: filter,
|
|
58
|
+
onFilter: function onFilter(value) {
|
|
59
|
+
return _onFilter === null || _onFilter === void 0 ? void 0 : _onFilter(id, value);
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}, "filters"));
|
|
63
|
+
}
|
|
42
64
|
if (sortable) {
|
|
43
65
|
ret.push( /*#__PURE__*/jsxRuntime.jsx(core.MenuItem, {
|
|
44
66
|
label: "Sort ascending",
|
|
@@ -54,14 +76,23 @@ var HeaderCell = function HeaderCell(_ref) {
|
|
|
54
76
|
}
|
|
55
77
|
}, "sort-desc"));
|
|
56
78
|
}
|
|
57
|
-
if (sortable && actions) {
|
|
58
|
-
ret.push( /*#__PURE__*/jsxRuntime.jsx(core.Divider, {}));
|
|
59
|
-
}
|
|
60
79
|
if (actions) {
|
|
61
|
-
|
|
80
|
+
var _ret;
|
|
81
|
+
ret.push( /*#__PURE__*/jsxRuntime.jsx(core.Divider, {}, "div"));
|
|
82
|
+
(_ret = ret).push.apply(_ret, _toConsumableArray(actions));
|
|
83
|
+
}
|
|
84
|
+
if (ret.length === 1) {
|
|
85
|
+
ret = [/*#__PURE__*/jsxRuntime.jsx(ColumnFilters.ColumnFilters, {
|
|
86
|
+
type: dataType,
|
|
87
|
+
list: filterOptions,
|
|
88
|
+
filter: filter,
|
|
89
|
+
onFilter: function onFilter(value) {
|
|
90
|
+
return _onFilter === null || _onFilter === void 0 ? void 0 : _onFilter(id, value);
|
|
91
|
+
}
|
|
92
|
+
}, "filters")];
|
|
62
93
|
}
|
|
63
94
|
return ret;
|
|
64
|
-
}, [sortable, actions]);
|
|
95
|
+
}, [sortable, actions, _onFilter, handleSort]);
|
|
65
96
|
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
66
97
|
role: "none",
|
|
67
98
|
"data-id": id,
|
|
@@ -104,6 +135,15 @@ var HeaderCell = function HeaderCell(_ref) {
|
|
|
104
135
|
className: "text-sm",
|
|
105
136
|
children: menus
|
|
106
137
|
})
|
|
138
|
+
}), filterable && !utilities.isEmpty(filter) && /*#__PURE__*/jsxRuntime.jsx(core.Button, {
|
|
139
|
+
size: "sm",
|
|
140
|
+
variant: "link",
|
|
141
|
+
"aria-label": "clear filter",
|
|
142
|
+
stopPropagation: true,
|
|
143
|
+
icon: core.CoreIcons.funnelRemove,
|
|
144
|
+
onClick: function onClick() {
|
|
145
|
+
return _onFilter === null || _onFilter === void 0 ? void 0 : _onFilter(id);
|
|
146
|
+
}
|
|
107
147
|
}), resizable && /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
108
148
|
role: "none",
|
|
109
149
|
className: "cursor-col-resize border-e bg-transparent border-tint-200 w-[5px] self-stretch",
|
package/dist/cjs/table/Table.js
CHANGED
|
@@ -37,6 +37,7 @@ var Table = function Table(_ref) {
|
|
|
37
37
|
canExpand = _ref.canExpand,
|
|
38
38
|
children = _ref.children,
|
|
39
39
|
onSort = _ref.onSort,
|
|
40
|
+
onFilter = _ref.onFilter,
|
|
40
41
|
onScroll = _ref.onScroll,
|
|
41
42
|
onRowClick = _ref.onRowClick,
|
|
42
43
|
onCheckedChanged = _ref.onCheckedChanged;
|
|
@@ -136,20 +137,23 @@ var Table = function Table(_ref) {
|
|
|
136
137
|
}), (_state$start = state.start) === null || _state$start === void 0 ? void 0 : _state$start.map(function (col, idx) {
|
|
137
138
|
return /*#__PURE__*/jsxRuntime.jsx(HeaderCell.HeaderCell, _objectSpread(_objectSpread({}, col), {}, {
|
|
138
139
|
sort: sort,
|
|
139
|
-
onSort: onSort
|
|
140
|
+
onSort: onSort,
|
|
141
|
+
onFilter: onFilter
|
|
140
142
|
}), idx);
|
|
141
143
|
})]
|
|
142
144
|
}), (_state$cols = state.cols) === null || _state$cols === void 0 ? void 0 : _state$cols.map(function (col, idx) {
|
|
143
145
|
return /*#__PURE__*/jsxRuntime.jsx(HeaderCell.HeaderCell, _objectSpread(_objectSpread({}, col), {}, {
|
|
144
146
|
sort: sort,
|
|
145
|
-
onSort: onSort
|
|
147
|
+
onSort: onSort,
|
|
148
|
+
onFilter: onFilter
|
|
146
149
|
}), idx);
|
|
147
150
|
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
148
151
|
className: wrapperEnd,
|
|
149
152
|
children: [(_state$end = state.end) === null || _state$end === void 0 ? void 0 : _state$end.map(function (col, idx) {
|
|
150
153
|
return /*#__PURE__*/jsxRuntime.jsx(HeaderCell.HeaderCell, _objectSpread(_objectSpread({}, col), {}, {
|
|
151
154
|
sort: sort,
|
|
152
|
-
onSort: onSort
|
|
155
|
+
onSort: onSort,
|
|
156
|
+
onFilter: onFilter
|
|
153
157
|
}), idx);
|
|
154
158
|
}), hideableColumns && /*#__PURE__*/jsxRuntime.jsx(AddColumn.AddColumn, {
|
|
155
159
|
onClick: onHide,
|
|
@@ -194,7 +198,7 @@ var Table = function Table(_ref) {
|
|
|
194
198
|
})]
|
|
195
199
|
})]
|
|
196
200
|
}, key) : /*#__PURE__*/jsxRuntime.jsx(BodyRow.BodyRow, {
|
|
197
|
-
rowKey: key,
|
|
201
|
+
rowKey: key.toString(),
|
|
198
202
|
index: index,
|
|
199
203
|
checkableRows: checkableRows,
|
|
200
204
|
checked: keyProperty && checkState.checked.includes(data[keyProperty]) ? 1 : 0,
|
|
@@ -19,7 +19,7 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
19
19
|
defaultLeafIcon = _ref.defaultLeafIcon,
|
|
20
20
|
defaultNodeIcon = _ref.defaultNodeIcon,
|
|
21
21
|
onToggle = _ref.onToggle,
|
|
22
|
-
|
|
22
|
+
onClick = _ref.onClick,
|
|
23
23
|
onSelect = _ref.onSelect,
|
|
24
24
|
onChecked = _ref.onChecked,
|
|
25
25
|
children = _ref.children,
|
|
@@ -63,7 +63,7 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
63
63
|
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
64
64
|
role: "treeitem",
|
|
65
65
|
"aria-selected": node.selected,
|
|
66
|
-
className: classNames("flex flex-nowrap items-center", node.leaf ? leafClassName : nodeClassName),
|
|
66
|
+
className: classNames("flex flex-nowrap items-center", node.className, node.leaf ? leafClassName : nodeClassName),
|
|
67
67
|
"data-testid": node["data-testid"],
|
|
68
68
|
"data-test-value": node["data-test-value"],
|
|
69
69
|
children: [filler, node.loading && /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
@@ -93,10 +93,10 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
93
93
|
})
|
|
94
94
|
}), !node.empty && /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
95
95
|
role: "none",
|
|
96
|
-
className: classNames("group/tool data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none", node.childSelected && "font-medium", (canSelect ||
|
|
96
|
+
className: classNames("group/tool data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none", node.childSelected && "font-medium", node.disabled && "text-muted opacity-65", !node.disabled && (canSelect || onClick) && "hover:bg-primary-50 cursor-pointer"),
|
|
97
97
|
"data-selected": node.selected,
|
|
98
|
-
onClick: function
|
|
99
|
-
|
|
98
|
+
onClick: node.disabled ? undefined : function () {
|
|
99
|
+
onClick === null || onClick === void 0 || onClick(node.id, node.data);
|
|
100
100
|
canSelect ? onSelect(node.id) : canCheck ? onChecked(node.id) : onToggle(node.id);
|
|
101
101
|
},
|
|
102
102
|
children: [nodeIcon && /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
@@ -85,7 +85,8 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
|
|
|
85
85
|
},
|
|
86
86
|
estimateSize: function estimateSize() {
|
|
87
87
|
return height;
|
|
88
|
-
}
|
|
88
|
+
},
|
|
89
|
+
overscan: 2
|
|
89
90
|
});
|
|
90
91
|
var virtualItems = virtualizer.getVirtualItems();
|
|
91
92
|
var currentIndex = react.useRef(0);
|
|
@@ -127,14 +128,15 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
|
|
|
127
128
|
var _virtualItems$2, _virtualItems$slice$p;
|
|
128
129
|
var firstItem = (_virtualItems$2 = virtualItems[0]) === null || _virtualItems$2 === void 0 ? void 0 : _virtualItems$2.index;
|
|
129
130
|
var lastItem = virtualItems === null || virtualItems === void 0 || (_virtualItems$slice$p = virtualItems.slice(-1).pop()) === null || _virtualItems$slice$p === void 0 ? void 0 : _virtualItems$slice$p.index;
|
|
131
|
+
var firstIndex = firstItem * columnCount;
|
|
130
132
|
var lastIndex = (lastItem !== null && lastItem !== void 0 ? lastItem : 0) * columnCount + columnCount;
|
|
131
|
-
var canLoadPrevPage = firstItem !== undefined && items[
|
|
133
|
+
var canLoadPrevPage = firstItem !== undefined && items[firstIndex] === null;
|
|
132
134
|
var canLoadNextPage = lastItem !== undefined && lastIndex >= count - 1 && count < total;
|
|
133
135
|
var db = utilities.debounce(onLoadMore);
|
|
134
136
|
if (canLoadPrevPage) {
|
|
135
|
-
db(
|
|
137
|
+
db(firstIndex);
|
|
136
138
|
} else if (!loading && canLoadNextPage) {
|
|
137
|
-
db(
|
|
139
|
+
db(lastIndex + 1);
|
|
138
140
|
}
|
|
139
141
|
return function () {
|
|
140
142
|
return db.cancel();
|
|
@@ -175,7 +177,7 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
|
|
|
175
177
|
return /*#__PURE__*/jsxRuntime.jsx("div", _objectSpread(_objectSpread({
|
|
176
178
|
ref: scrollerRef,
|
|
177
179
|
onScroll: handleScroll,
|
|
178
|
-
className: classNames("area-content bg-base overflow-auto
|
|
180
|
+
className: classNames("area-content bg-base overflow-auto")
|
|
179
181
|
}, aria), {}, {
|
|
180
182
|
children: /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
181
183
|
className: classNames("inline-flex flex-nowrap gap-2 justify-center min-h-full min-w-full"),
|
|
@@ -195,12 +197,11 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
|
|
|
195
197
|
}
|
|
196
198
|
}), virtualItems.map(function (_ref3) {
|
|
197
199
|
var key = _ref3.key,
|
|
198
|
-
index = _ref3.index
|
|
199
|
-
measureElement = _ref3.measureElement;
|
|
200
|
+
index = _ref3.index;
|
|
200
201
|
return /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
201
202
|
className: "flex justify-start",
|
|
202
203
|
"data-index": index,
|
|
203
|
-
ref: measureElement,
|
|
204
|
+
ref: virtualizer.measureElement,
|
|
204
205
|
children: columnMap.map(function (col) {
|
|
205
206
|
return /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
206
207
|
"data-index": index * columnCount + col,
|
package/dist/cjs/virtual/List.js
CHANGED
|
@@ -56,6 +56,7 @@ var _VirtualList = function _VirtualList(_ref) {
|
|
|
56
56
|
var scrollerRef = react.useRef(null);
|
|
57
57
|
var virtualizer = reactVirtual.useVirtualizer({
|
|
58
58
|
count: count,
|
|
59
|
+
overscan: 2,
|
|
59
60
|
horizontal: orientation === "horizontal",
|
|
60
61
|
getScrollElement: function getScrollElement() {
|
|
61
62
|
return scrollerRef.current;
|
|
@@ -164,7 +165,7 @@ var _VirtualList = function _VirtualList(_ref) {
|
|
|
164
165
|
return /*#__PURE__*/jsxRuntime.jsx("div", _objectSpread(_objectSpread({
|
|
165
166
|
ref: scrollerRef,
|
|
166
167
|
onScroll: handleScroll,
|
|
167
|
-
className: classNames("area-content bg-base overflow-auto
|
|
168
|
+
className: classNames("area-content bg-base overflow-auto")
|
|
168
169
|
}, aria), {}, {
|
|
169
170
|
children: /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
170
171
|
className: classNames("inline-flex flex-nowrap gap-2 justify-center min-h-full min-w-full", orientation === "horizontal" && "flex-col"),
|
|
@@ -30,7 +30,7 @@ var AddColumn = function AddColumn(_ref) {
|
|
|
30
30
|
var columns = _ref.columns,
|
|
31
31
|
onClick = _ref.onClick;
|
|
32
32
|
return /*#__PURE__*/jsx("div", {
|
|
33
|
-
className: "group font-medium w-6 flex flex-nowrap text-start items-
|
|
33
|
+
className: "group font-medium w-6 flex flex-nowrap text-start items-center",
|
|
34
34
|
children: /*#__PURE__*/jsxs(Dropdown, {
|
|
35
35
|
placement: "bottom-end",
|
|
36
36
|
children: [/*#__PURE__*/jsx(Icon, {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
|
|
4
|
+
import { DropdownDismiss, Button } from '@react-fabric/core';
|
|
5
|
+
import { Input, Search, Checkbox } from '@react-fabric/form';
|
|
6
|
+
import { matchString, EMPTY_ARRAY } from '@react-fabric/utilities';
|
|
7
|
+
import { useState } from 'react';
|
|
8
|
+
import { useFilteredList } from '../hooks/useFilteredList.js';
|
|
9
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
10
|
+
|
|
11
|
+
var ListFilter = function ListFilter(_ref) {
|
|
12
|
+
var _ref$list = _ref.list,
|
|
13
|
+
list = _ref$list === void 0 ? EMPTY_ARRAY : _ref$list,
|
|
14
|
+
filter = _ref.filter,
|
|
15
|
+
onFilter = _ref.onFilter;
|
|
16
|
+
var _useState = useState(new Set(filter)),
|
|
17
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
18
|
+
selected = _useState2[0],
|
|
19
|
+
setSelected = _useState2[1];
|
|
20
|
+
var _useFilteredList = useFilteredList(list, function (item, query) {
|
|
21
|
+
var _item$id;
|
|
22
|
+
return matchString((_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : item, query);
|
|
23
|
+
}),
|
|
24
|
+
filteredList = _useFilteredList.filteredList,
|
|
25
|
+
query = _useFilteredList.query,
|
|
26
|
+
onSearch = _useFilteredList.onSearch;
|
|
27
|
+
return /*#__PURE__*/jsxs("div", {
|
|
28
|
+
className: "flex flex-col",
|
|
29
|
+
children: [/*#__PURE__*/jsx("div", {
|
|
30
|
+
children: /*#__PURE__*/jsx(Search, {
|
|
31
|
+
autoFocus: true,
|
|
32
|
+
value: query,
|
|
33
|
+
onSearch: onSearch,
|
|
34
|
+
searchOnChange: true
|
|
35
|
+
})
|
|
36
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
37
|
+
className: "flex-1 overflow-auto scroll-thin",
|
|
38
|
+
children: [filteredList.map(function (v, idx) {
|
|
39
|
+
var _v$id, _v$label;
|
|
40
|
+
return /*#__PURE__*/jsx("div", {
|
|
41
|
+
className: "flex gap-x-1 text-xs items-center",
|
|
42
|
+
children: /*#__PURE__*/jsx(Checkbox, {
|
|
43
|
+
checked: selected.has((_v$id = v.id) !== null && _v$id !== void 0 ? _v$id : v),
|
|
44
|
+
onChange: function onChange(b) {
|
|
45
|
+
var _v$id2, _v$id3;
|
|
46
|
+
var set = new Set(Array.from(selected.values()));
|
|
47
|
+
b ? set.add((_v$id2 = v.id) !== null && _v$id2 !== void 0 ? _v$id2 : v) : set["delete"]((_v$id3 = v.id) !== null && _v$id3 !== void 0 ? _v$id3 : v);
|
|
48
|
+
setSelected(set);
|
|
49
|
+
},
|
|
50
|
+
label: /*#__PURE__*/jsx("span", {
|
|
51
|
+
className: "truncate",
|
|
52
|
+
children: (_v$label = v.label) !== null && _v$label !== void 0 ? _v$label : v
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
}, idx);
|
|
56
|
+
}), filteredList.length === 0 && /*#__PURE__*/jsx("span", {
|
|
57
|
+
className: "text-muted text-xs",
|
|
58
|
+
children: "No items found"
|
|
59
|
+
})]
|
|
60
|
+
}), /*#__PURE__*/jsx("div", {
|
|
61
|
+
className: "flex justify-end",
|
|
62
|
+
children: /*#__PURE__*/jsx(DropdownDismiss, {
|
|
63
|
+
children: /*#__PURE__*/jsx(Button, {
|
|
64
|
+
size: "xs",
|
|
65
|
+
onClick: function onClick() {
|
|
66
|
+
return onFilter === null || onFilter === void 0 ? void 0 : onFilter(Array.from(selected));
|
|
67
|
+
},
|
|
68
|
+
children: "Apply"
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
})]
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
var ColumnFilters = function ColumnFilters(_ref2) {
|
|
75
|
+
var type = _ref2.type,
|
|
76
|
+
list = _ref2.list,
|
|
77
|
+
filter = _ref2.filter,
|
|
78
|
+
onFilter = _ref2.onFilter;
|
|
79
|
+
return /*#__PURE__*/jsxs("div", {
|
|
80
|
+
className: "flex flex-col min-w-[16rem]",
|
|
81
|
+
children: [list && /*#__PURE__*/jsx(ListFilter, {
|
|
82
|
+
list: list,
|
|
83
|
+
filter: filter,
|
|
84
|
+
onFilter: onFilter
|
|
85
|
+
}), !list && type === "string" && /*#__PURE__*/jsx(Input, {
|
|
86
|
+
autoFocus: true,
|
|
87
|
+
allowClear: true,
|
|
88
|
+
value: filter,
|
|
89
|
+
onEnterPressed: function onEnterPressed(e) {
|
|
90
|
+
var _e$target$value;
|
|
91
|
+
return onFilter((_e$target$value = e.target.value) !== null && _e$target$value !== void 0 ? _e$target$value : "");
|
|
92
|
+
}
|
|
93
|
+
})]
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export { ColumnFilters };
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
|
|
4
|
-
import {
|
|
4
|
+
import { Menu, CoreIcons, MenuItem, Divider, Tooltip, Icon, DropdownTool, Button } from '@react-fabric/core';
|
|
5
|
+
import { isEmpty } from '@react-fabric/utilities';
|
|
5
6
|
import { useMemo, useCallback } from 'react';
|
|
7
|
+
import { ColumnFilters } from './ColumnFilters.js';
|
|
6
8
|
import { useTableContext } from './Context.js';
|
|
7
9
|
import { COL_DEFAULT_WIDTH, COL_MIN_WIDTH, COL_MAX_WIDTH } from './types.js';
|
|
8
10
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
9
11
|
|
|
10
12
|
var HeaderCell = function HeaderCell(_ref) {
|
|
11
13
|
var id = _ref.id,
|
|
14
|
+
dataType = _ref.dataType,
|
|
12
15
|
label = _ref.label,
|
|
13
16
|
icon = _ref.icon,
|
|
14
17
|
iconBg = _ref.iconBg,
|
|
@@ -16,14 +19,18 @@ var HeaderCell = function HeaderCell(_ref) {
|
|
|
16
19
|
rtlFlip = _ref.rtlFlip,
|
|
17
20
|
actions = _ref.actions;
|
|
18
21
|
_ref.locked;
|
|
19
|
-
var
|
|
22
|
+
var filter = _ref.filter,
|
|
23
|
+
filterable = _ref.filterable,
|
|
24
|
+
filterOptions = _ref.filterOptions,
|
|
25
|
+
tooltip = _ref.tooltip,
|
|
20
26
|
sortable = _ref.sortable,
|
|
21
27
|
resizable = _ref.resizable,
|
|
22
28
|
_width = _ref.width,
|
|
23
29
|
maxWidth = _ref.maxWidth,
|
|
24
30
|
minWidth = _ref.minWidth,
|
|
25
31
|
sort = _ref.sort,
|
|
26
|
-
onSort = _ref.onSort
|
|
32
|
+
onSort = _ref.onSort,
|
|
33
|
+
_onFilter = _ref.onFilter;
|
|
27
34
|
var _useTableContext = useTableContext(),
|
|
28
35
|
startResize = _useTableContext.startResize,
|
|
29
36
|
widths = _useTableContext.widths;
|
|
@@ -39,6 +46,21 @@ var HeaderCell = function HeaderCell(_ref) {
|
|
|
39
46
|
}, [onSort, sort, sortable]);
|
|
40
47
|
var menus = useMemo(function () {
|
|
41
48
|
var ret = [];
|
|
49
|
+
if (filterable && (dataType !== null && dataType !== void 0 ? dataType : filterOptions)) {
|
|
50
|
+
ret.push( /*#__PURE__*/jsx(Menu, {
|
|
51
|
+
label: "Filter",
|
|
52
|
+
icon: filter ? CoreIcons.tick : "",
|
|
53
|
+
trigger: "click",
|
|
54
|
+
children: /*#__PURE__*/jsx(ColumnFilters, {
|
|
55
|
+
type: dataType,
|
|
56
|
+
list: filterOptions,
|
|
57
|
+
filter: filter,
|
|
58
|
+
onFilter: function onFilter(value) {
|
|
59
|
+
return _onFilter === null || _onFilter === void 0 ? void 0 : _onFilter(id, value);
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}, "filters"));
|
|
63
|
+
}
|
|
42
64
|
if (sortable) {
|
|
43
65
|
ret.push( /*#__PURE__*/jsx(MenuItem, {
|
|
44
66
|
label: "Sort ascending",
|
|
@@ -54,14 +76,23 @@ var HeaderCell = function HeaderCell(_ref) {
|
|
|
54
76
|
}
|
|
55
77
|
}, "sort-desc"));
|
|
56
78
|
}
|
|
57
|
-
if (sortable && actions) {
|
|
58
|
-
ret.push( /*#__PURE__*/jsx(Divider, {}));
|
|
59
|
-
}
|
|
60
79
|
if (actions) {
|
|
61
|
-
|
|
80
|
+
var _ret;
|
|
81
|
+
ret.push( /*#__PURE__*/jsx(Divider, {}, "div"));
|
|
82
|
+
(_ret = ret).push.apply(_ret, _toConsumableArray(actions));
|
|
83
|
+
}
|
|
84
|
+
if (ret.length === 1) {
|
|
85
|
+
ret = [/*#__PURE__*/jsx(ColumnFilters, {
|
|
86
|
+
type: dataType,
|
|
87
|
+
list: filterOptions,
|
|
88
|
+
filter: filter,
|
|
89
|
+
onFilter: function onFilter(value) {
|
|
90
|
+
return _onFilter === null || _onFilter === void 0 ? void 0 : _onFilter(id, value);
|
|
91
|
+
}
|
|
92
|
+
}, "filters")];
|
|
62
93
|
}
|
|
63
94
|
return ret;
|
|
64
|
-
}, [sortable, actions]);
|
|
95
|
+
}, [sortable, actions, _onFilter, handleSort]);
|
|
65
96
|
return /*#__PURE__*/jsxs("div", {
|
|
66
97
|
role: "none",
|
|
67
98
|
"data-id": id,
|
|
@@ -104,6 +135,15 @@ var HeaderCell = function HeaderCell(_ref) {
|
|
|
104
135
|
className: "text-sm",
|
|
105
136
|
children: menus
|
|
106
137
|
})
|
|
138
|
+
}), filterable && !isEmpty(filter) && /*#__PURE__*/jsx(Button, {
|
|
139
|
+
size: "sm",
|
|
140
|
+
variant: "link",
|
|
141
|
+
"aria-label": "clear filter",
|
|
142
|
+
stopPropagation: true,
|
|
143
|
+
icon: CoreIcons.funnelRemove,
|
|
144
|
+
onClick: function onClick() {
|
|
145
|
+
return _onFilter === null || _onFilter === void 0 ? void 0 : _onFilter(id);
|
|
146
|
+
}
|
|
107
147
|
}), resizable && /*#__PURE__*/jsx("div", {
|
|
108
148
|
role: "none",
|
|
109
149
|
className: "cursor-col-resize border-e bg-transparent border-tint-200 w-[5px] self-stretch",
|
package/dist/esm/table/Table.js
CHANGED
|
@@ -37,6 +37,7 @@ var Table = function Table(_ref) {
|
|
|
37
37
|
canExpand = _ref.canExpand,
|
|
38
38
|
children = _ref.children,
|
|
39
39
|
onSort = _ref.onSort,
|
|
40
|
+
onFilter = _ref.onFilter,
|
|
40
41
|
onScroll = _ref.onScroll,
|
|
41
42
|
onRowClick = _ref.onRowClick,
|
|
42
43
|
onCheckedChanged = _ref.onCheckedChanged;
|
|
@@ -136,20 +137,23 @@ var Table = function Table(_ref) {
|
|
|
136
137
|
}), (_state$start = state.start) === null || _state$start === void 0 ? void 0 : _state$start.map(function (col, idx) {
|
|
137
138
|
return /*#__PURE__*/jsx(HeaderCell, _objectSpread(_objectSpread({}, col), {}, {
|
|
138
139
|
sort: sort,
|
|
139
|
-
onSort: onSort
|
|
140
|
+
onSort: onSort,
|
|
141
|
+
onFilter: onFilter
|
|
140
142
|
}), idx);
|
|
141
143
|
})]
|
|
142
144
|
}), (_state$cols = state.cols) === null || _state$cols === void 0 ? void 0 : _state$cols.map(function (col, idx) {
|
|
143
145
|
return /*#__PURE__*/jsx(HeaderCell, _objectSpread(_objectSpread({}, col), {}, {
|
|
144
146
|
sort: sort,
|
|
145
|
-
onSort: onSort
|
|
147
|
+
onSort: onSort,
|
|
148
|
+
onFilter: onFilter
|
|
146
149
|
}), idx);
|
|
147
150
|
}), /*#__PURE__*/jsxs("div", {
|
|
148
151
|
className: wrapperEnd,
|
|
149
152
|
children: [(_state$end = state.end) === null || _state$end === void 0 ? void 0 : _state$end.map(function (col, idx) {
|
|
150
153
|
return /*#__PURE__*/jsx(HeaderCell, _objectSpread(_objectSpread({}, col), {}, {
|
|
151
154
|
sort: sort,
|
|
152
|
-
onSort: onSort
|
|
155
|
+
onSort: onSort,
|
|
156
|
+
onFilter: onFilter
|
|
153
157
|
}), idx);
|
|
154
158
|
}), hideableColumns && /*#__PURE__*/jsx(AddColumn, {
|
|
155
159
|
onClick: onHide,
|
|
@@ -194,7 +198,7 @@ var Table = function Table(_ref) {
|
|
|
194
198
|
})]
|
|
195
199
|
})]
|
|
196
200
|
}, key) : /*#__PURE__*/jsx(BodyRow, {
|
|
197
|
-
rowKey: key,
|
|
201
|
+
rowKey: key.toString(),
|
|
198
202
|
index: index,
|
|
199
203
|
checkableRows: checkableRows,
|
|
200
204
|
checked: keyProperty && checkState.checked.includes(data[keyProperty]) ? 1 : 0,
|
|
@@ -19,7 +19,7 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
19
19
|
defaultLeafIcon = _ref.defaultLeafIcon,
|
|
20
20
|
defaultNodeIcon = _ref.defaultNodeIcon,
|
|
21
21
|
onToggle = _ref.onToggle,
|
|
22
|
-
|
|
22
|
+
onClick = _ref.onClick,
|
|
23
23
|
onSelect = _ref.onSelect,
|
|
24
24
|
onChecked = _ref.onChecked,
|
|
25
25
|
children = _ref.children,
|
|
@@ -63,7 +63,7 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
63
63
|
return /*#__PURE__*/jsxs("div", {
|
|
64
64
|
role: "treeitem",
|
|
65
65
|
"aria-selected": node.selected,
|
|
66
|
-
className: classNames("flex flex-nowrap items-center", node.leaf ? leafClassName : nodeClassName),
|
|
66
|
+
className: classNames("flex flex-nowrap items-center", node.className, node.leaf ? leafClassName : nodeClassName),
|
|
67
67
|
"data-testid": node["data-testid"],
|
|
68
68
|
"data-test-value": node["data-test-value"],
|
|
69
69
|
children: [filler, node.loading && /*#__PURE__*/jsx("div", {
|
|
@@ -93,10 +93,10 @@ var TreeNode = function TreeNode(_ref) {
|
|
|
93
93
|
})
|
|
94
94
|
}), !node.empty && /*#__PURE__*/jsxs("div", {
|
|
95
95
|
role: "none",
|
|
96
|
-
className: classNames("group/tool data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none", node.childSelected && "font-medium", (canSelect ||
|
|
96
|
+
className: classNames("group/tool data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none", node.childSelected && "font-medium", node.disabled && "text-muted opacity-65", !node.disabled && (canSelect || onClick) && "hover:bg-primary-50 cursor-pointer"),
|
|
97
97
|
"data-selected": node.selected,
|
|
98
|
-
onClick: function
|
|
99
|
-
|
|
98
|
+
onClick: node.disabled ? undefined : function () {
|
|
99
|
+
onClick === null || onClick === void 0 || onClick(node.id, node.data);
|
|
100
100
|
canSelect ? onSelect(node.id) : canCheck ? onChecked(node.id) : onToggle(node.id);
|
|
101
101
|
},
|
|
102
102
|
children: [nodeIcon && /*#__PURE__*/jsxs("div", {
|
|
@@ -85,7 +85,8 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
|
|
|
85
85
|
},
|
|
86
86
|
estimateSize: function estimateSize() {
|
|
87
87
|
return height;
|
|
88
|
-
}
|
|
88
|
+
},
|
|
89
|
+
overscan: 2
|
|
89
90
|
});
|
|
90
91
|
var virtualItems = virtualizer.getVirtualItems();
|
|
91
92
|
var currentIndex = useRef(0);
|
|
@@ -127,14 +128,15 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
|
|
|
127
128
|
var _virtualItems$2, _virtualItems$slice$p;
|
|
128
129
|
var firstItem = (_virtualItems$2 = virtualItems[0]) === null || _virtualItems$2 === void 0 ? void 0 : _virtualItems$2.index;
|
|
129
130
|
var lastItem = virtualItems === null || virtualItems === void 0 || (_virtualItems$slice$p = virtualItems.slice(-1).pop()) === null || _virtualItems$slice$p === void 0 ? void 0 : _virtualItems$slice$p.index;
|
|
131
|
+
var firstIndex = firstItem * columnCount;
|
|
130
132
|
var lastIndex = (lastItem !== null && lastItem !== void 0 ? lastItem : 0) * columnCount + columnCount;
|
|
131
|
-
var canLoadPrevPage = firstItem !== undefined && items[
|
|
133
|
+
var canLoadPrevPage = firstItem !== undefined && items[firstIndex] === null;
|
|
132
134
|
var canLoadNextPage = lastItem !== undefined && lastIndex >= count - 1 && count < total;
|
|
133
135
|
var db = debounce(onLoadMore);
|
|
134
136
|
if (canLoadPrevPage) {
|
|
135
|
-
db(
|
|
137
|
+
db(firstIndex);
|
|
136
138
|
} else if (!loading && canLoadNextPage) {
|
|
137
|
-
db(
|
|
139
|
+
db(lastIndex + 1);
|
|
138
140
|
}
|
|
139
141
|
return function () {
|
|
140
142
|
return db.cancel();
|
|
@@ -175,7 +177,7 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
|
|
|
175
177
|
return /*#__PURE__*/jsx("div", _objectSpread(_objectSpread({
|
|
176
178
|
ref: scrollerRef,
|
|
177
179
|
onScroll: handleScroll,
|
|
178
|
-
className: classNames("area-content bg-base overflow-auto
|
|
180
|
+
className: classNames("area-content bg-base overflow-auto")
|
|
179
181
|
}, aria), {}, {
|
|
180
182
|
children: /*#__PURE__*/jsxs("div", {
|
|
181
183
|
className: classNames("inline-flex flex-nowrap gap-2 justify-center min-h-full min-w-full"),
|
|
@@ -195,12 +197,11 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
|
|
|
195
197
|
}
|
|
196
198
|
}), virtualItems.map(function (_ref3) {
|
|
197
199
|
var key = _ref3.key,
|
|
198
|
-
index = _ref3.index
|
|
199
|
-
measureElement = _ref3.measureElement;
|
|
200
|
+
index = _ref3.index;
|
|
200
201
|
return /*#__PURE__*/jsx("div", {
|
|
201
202
|
className: "flex justify-start",
|
|
202
203
|
"data-index": index,
|
|
203
|
-
ref: measureElement,
|
|
204
|
+
ref: virtualizer.measureElement,
|
|
204
205
|
children: columnMap.map(function (col) {
|
|
205
206
|
return /*#__PURE__*/jsx("div", {
|
|
206
207
|
"data-index": index * columnCount + col,
|
package/dist/esm/virtual/List.js
CHANGED
|
@@ -56,6 +56,7 @@ var _VirtualList = function _VirtualList(_ref) {
|
|
|
56
56
|
var scrollerRef = useRef(null);
|
|
57
57
|
var virtualizer = useVirtualizer({
|
|
58
58
|
count: count,
|
|
59
|
+
overscan: 2,
|
|
59
60
|
horizontal: orientation === "horizontal",
|
|
60
61
|
getScrollElement: function getScrollElement() {
|
|
61
62
|
return scrollerRef.current;
|
|
@@ -164,7 +165,7 @@ var _VirtualList = function _VirtualList(_ref) {
|
|
|
164
165
|
return /*#__PURE__*/jsx("div", _objectSpread(_objectSpread({
|
|
165
166
|
ref: scrollerRef,
|
|
166
167
|
onScroll: handleScroll,
|
|
167
|
-
className: classNames("area-content bg-base overflow-auto
|
|
168
|
+
className: classNames("area-content bg-base overflow-auto")
|
|
168
169
|
}, aria), {}, {
|
|
169
170
|
children: /*#__PURE__*/jsxs("div", {
|
|
170
171
|
className: classNames("inline-flex flex-nowrap gap-2 justify-center min-h-full min-w-full", orientation === "horizontal" && "flex-col"),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type TableColumn } from "./types";
|
|
2
|
+
interface FilterProps {
|
|
3
|
+
type: TableColumn["dataType"];
|
|
4
|
+
onFilter: (value: AnyObject) => void;
|
|
5
|
+
list?: AnyObject[];
|
|
6
|
+
filter: AnyObject;
|
|
7
|
+
}
|
|
8
|
+
export declare const ColumnFilters: ({ type, list, filter, onFilter, }: FilterProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type TableColumn, type TableProps } from "./types";
|
|
2
|
-
export declare const HeaderCell: ({ id, label, icon, iconBg, iconColor, rtlFlip, actions, locked, tooltip, sortable, resizable, width: _width, maxWidth, minWidth, sort, onSort, }: TableColumn & Pick<TableProps, "sort" | "onSort">) => import("react/jsx-runtime").JSX.Element;
|
|
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;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type TableProps } from "./types";
|
|
2
|
-
export declare const Table: <T extends KeyValue<any> = KeyValue<any>>({ ref, data, columns, keyProperty, groupProperty, checkableRows, initialScroll, hideableColumns, sort, loading, checked, emptyDisplay, groupRenderer, canExpand, children, onSort, onScroll, onRowClick, onCheckedChanged, }: TableProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare const Table: <T extends KeyValue<any> = KeyValue<any>>({ 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;
|
|
@@ -16,7 +16,8 @@ export interface TableColumn<T = KeyValue> extends CssProp, IconProps, TestProps
|
|
|
16
16
|
resizable?: boolean;
|
|
17
17
|
sortable?: boolean;
|
|
18
18
|
filterable?: boolean;
|
|
19
|
-
|
|
19
|
+
filter?: AnyObject;
|
|
20
|
+
filterOptions?: AnyObject[];
|
|
20
21
|
width?: string | number;
|
|
21
22
|
minWidth?: string | number;
|
|
22
23
|
maxWidth?: string | number;
|
|
@@ -61,4 +62,5 @@ export interface TableProps<T = KeyValue> extends RefProp<TableRef> {
|
|
|
61
62
|
onScroll?: (firstItem: number) => void;
|
|
62
63
|
canExpand?: (record: T) => boolean;
|
|
63
64
|
children?: (record: T) => Elements<AnyObject>;
|
|
65
|
+
onFilter?: (id: keyof T | string, value?: AnyObject) => void;
|
|
64
66
|
}
|
|
@@ -15,7 +15,7 @@ export declare const useVirtualTable: <T extends KeyValue<any> = KeyValue<any>>(
|
|
|
15
15
|
onCheckChanged?: (checked: AnyObject[]) => void;
|
|
16
16
|
}) => {
|
|
17
17
|
scrollerRef: import("react").RefObject<HTMLDivElement>;
|
|
18
|
-
items: import("@tanstack/virtual-core").VirtualItem
|
|
18
|
+
items: import("@tanstack/virtual-core").VirtualItem[];
|
|
19
19
|
checkState: DataState<T>;
|
|
20
20
|
getData: (index: number) => T;
|
|
21
21
|
virtualizer: import("@tanstack/virtual-core").Virtualizer<HTMLDivElement, Element>;
|
|
@@ -51,13 +51,13 @@ export interface VirtualGalleryProps<T> extends TestProps {
|
|
|
51
51
|
/**
|
|
52
52
|
* load more callback
|
|
53
53
|
*/
|
|
54
|
-
onLoadMore?: (
|
|
54
|
+
onLoadMore?: (lastIndex?: number) => void;
|
|
55
55
|
/**
|
|
56
56
|
* scroll handler
|
|
57
57
|
*/
|
|
58
58
|
onScroll?: (top: number) => void;
|
|
59
59
|
}
|
|
60
60
|
export declare const VirtualGallery: {
|
|
61
|
-
<T extends
|
|
61
|
+
<T extends unknown>({ items, children, columns, fullWidth, maxWidth, minWidth, total, padding, defaultHeight: height, defaultWidth: width, hideScroller, initialScroll, loading, onLoadMore, onScroll, galleryRef, ...aria }: VirtualGalleryProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
62
62
|
displayName: string;
|
|
63
63
|
};
|
|
@@ -51,13 +51,13 @@ export interface VirtualListProps<T> extends TestProps {
|
|
|
51
51
|
/**
|
|
52
52
|
* load more callback
|
|
53
53
|
*/
|
|
54
|
-
onLoadMore?: (
|
|
54
|
+
onLoadMore?: (lastIndex?: number) => void;
|
|
55
55
|
/**
|
|
56
56
|
* scroll handler
|
|
57
57
|
*/
|
|
58
58
|
onScroll?: (top: number) => void;
|
|
59
59
|
}
|
|
60
60
|
export declare const VirtualList: {
|
|
61
|
-
<T extends
|
|
61
|
+
<T extends unknown>({ items, total, children, fullWidth, maxWidth, minWidth, padding, orientation, defaultHeight: height, defaultWidth: width, hideScroller, initialScroll, loading, onLoadMore, onScroll, listRef, ...aria }: VirtualListProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
62
62
|
displayName: string;
|
|
63
63
|
};
|
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.49",
|
|
4
4
|
"description": "RUF: Data package",
|
|
5
5
|
"author": "Adarsh Pastakia <adarshpastakia@outlook.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,11 +35,11 @@
|
|
|
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.
|
|
41
|
-
"@react-fabric/utilities": "^1.0.0-beta.
|
|
42
|
-
"@tanstack/react-virtual": "^3.
|
|
38
|
+
"@react-fabric/core": "^1.0.0-beta.49",
|
|
39
|
+
"@react-fabric/date": "^1.0.0-beta.49",
|
|
40
|
+
"@react-fabric/form": "^1.0.0-beta.49",
|
|
41
|
+
"@react-fabric/utilities": "^1.0.0-beta.49",
|
|
42
|
+
"@tanstack/react-virtual": "^3.13.9",
|
|
43
43
|
"classnames": "^2.5.1",
|
|
44
44
|
"color": "^4.2.3",
|
|
45
45
|
"memoize-one": "^6.0.0"
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"node": ">=18.12.0",
|
|
55
55
|
"npm": ">=8.19.0"
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "29b3ed65e9f9687d738dd7c6facdb9fedafb4219"
|
|
58
58
|
}
|
package/src/table/AddColumn.tsx
CHANGED
|
@@ -32,7 +32,7 @@ export const AddColumn = ({
|
|
|
32
32
|
onClick: (id: string) => void;
|
|
33
33
|
}) => {
|
|
34
34
|
return (
|
|
35
|
-
<div className="group font-medium w-6 flex flex-nowrap text-start items-
|
|
35
|
+
<div className="group font-medium w-6 flex flex-nowrap text-start items-center">
|
|
36
36
|
<Dropdown placement="bottom-end">
|
|
37
37
|
<Icon
|
|
38
38
|
icon={CoreIcons.insert}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* React Fabric
|
|
3
|
+
* @version: 1.0.0
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* The MIT License (MIT)
|
|
7
|
+
* Copyright (c) 2025 Adarsh Pastakia
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
10
|
+
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
11
|
+
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
12
|
+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
13
|
+
* subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
16
|
+
* portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
19
|
+
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
20
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { Button, DropdownDismiss } from "@react-fabric/core";
|
|
25
|
+
import { Checkbox, Input, Search } from "@react-fabric/form";
|
|
26
|
+
import { EMPTY_ARRAY, matchString } from "@react-fabric/utilities";
|
|
27
|
+
import { useState } from "react";
|
|
28
|
+
import { useFilteredList } from "../hooks/useFilteredList";
|
|
29
|
+
import { type TableColumn } from "./types";
|
|
30
|
+
|
|
31
|
+
interface FilterProps {
|
|
32
|
+
type: TableColumn["dataType"];
|
|
33
|
+
onFilter: (value: AnyObject) => void;
|
|
34
|
+
list?: AnyObject[];
|
|
35
|
+
filter: AnyObject;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const ListFilter = ({
|
|
39
|
+
list = EMPTY_ARRAY,
|
|
40
|
+
filter,
|
|
41
|
+
onFilter,
|
|
42
|
+
}: Partial<FilterProps>) => {
|
|
43
|
+
const [selected, setSelected] = useState<Set<string>>(new Set(filter));
|
|
44
|
+
|
|
45
|
+
const { filteredList, query, onSearch } = useFilteredList(
|
|
46
|
+
list,
|
|
47
|
+
(item, query) => {
|
|
48
|
+
return matchString(item.id ?? item, query);
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className="flex flex-col">
|
|
54
|
+
<div>
|
|
55
|
+
<Search autoFocus value={query} onSearch={onSearch} searchOnChange />
|
|
56
|
+
</div>
|
|
57
|
+
<div className="flex-1 overflow-auto scroll-thin">
|
|
58
|
+
{filteredList.map((v, idx) => (
|
|
59
|
+
<div key={idx} className="flex gap-x-1 text-xs items-center">
|
|
60
|
+
<Checkbox
|
|
61
|
+
checked={selected.has(v.id ?? v)}
|
|
62
|
+
onChange={(b) => {
|
|
63
|
+
const set = new Set(Array.from(selected.values()));
|
|
64
|
+
b ? set.add(v.id ?? v) : set.delete(v.id ?? v);
|
|
65
|
+
setSelected(set);
|
|
66
|
+
}}
|
|
67
|
+
label={<span className="truncate">{v.label ?? v}</span>}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
))}
|
|
71
|
+
{filteredList.length === 0 && (
|
|
72
|
+
<span className="text-muted text-xs">No items found</span>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
<div className="flex justify-end">
|
|
76
|
+
<DropdownDismiss>
|
|
77
|
+
<Button size="xs" onClick={() => onFilter?.(Array.from(selected))}>
|
|
78
|
+
Apply
|
|
79
|
+
</Button>
|
|
80
|
+
</DropdownDismiss>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const ColumnFilters = ({
|
|
87
|
+
type,
|
|
88
|
+
list,
|
|
89
|
+
filter,
|
|
90
|
+
onFilter,
|
|
91
|
+
}: FilterProps) => {
|
|
92
|
+
return (
|
|
93
|
+
<div className="flex flex-col min-w-[16rem]">
|
|
94
|
+
{list && <ListFilter list={list} filter={filter} onFilter={onFilter} />}
|
|
95
|
+
{!list && type === "string" && (
|
|
96
|
+
<Input
|
|
97
|
+
autoFocus
|
|
98
|
+
allowClear
|
|
99
|
+
value={filter}
|
|
100
|
+
onEnterPressed={(e: AnyObject) => onFilter(e.target.value ?? "")}
|
|
101
|
+
/>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
};
|
package/src/table/HeaderCell.tsx
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import {
|
|
25
|
+
Button,
|
|
25
26
|
CoreIcons,
|
|
26
27
|
Divider,
|
|
27
28
|
DropdownTool,
|
|
@@ -30,7 +31,9 @@ import {
|
|
|
30
31
|
MenuItem,
|
|
31
32
|
Tooltip,
|
|
32
33
|
} from "@react-fabric/core";
|
|
34
|
+
import { isEmpty } from "@react-fabric/utilities";
|
|
33
35
|
import { useCallback, useMemo } from "react";
|
|
36
|
+
import { ColumnFilters } from "./ColumnFilters";
|
|
34
37
|
import { useTableContext } from "./Context";
|
|
35
38
|
import {
|
|
36
39
|
COL_DEFAULT_WIDTH,
|
|
@@ -42,6 +45,7 @@ import {
|
|
|
42
45
|
|
|
43
46
|
export const HeaderCell = ({
|
|
44
47
|
id,
|
|
48
|
+
dataType,
|
|
45
49
|
label,
|
|
46
50
|
icon,
|
|
47
51
|
iconBg,
|
|
@@ -49,6 +53,9 @@ export const HeaderCell = ({
|
|
|
49
53
|
rtlFlip,
|
|
50
54
|
actions,
|
|
51
55
|
locked,
|
|
56
|
+
filter,
|
|
57
|
+
filterable,
|
|
58
|
+
filterOptions,
|
|
52
59
|
tooltip,
|
|
53
60
|
sortable,
|
|
54
61
|
resizable,
|
|
@@ -57,7 +64,8 @@ export const HeaderCell = ({
|
|
|
57
64
|
minWidth,
|
|
58
65
|
sort,
|
|
59
66
|
onSort,
|
|
60
|
-
|
|
67
|
+
onFilter,
|
|
68
|
+
}: TableColumn & Pick<TableProps, "sort" | "onSort" | "onFilter">) => {
|
|
61
69
|
const { startResize, widths } = useTableContext();
|
|
62
70
|
|
|
63
71
|
const width = useMemo(
|
|
@@ -78,7 +86,24 @@ export const HeaderCell = ({
|
|
|
78
86
|
);
|
|
79
87
|
|
|
80
88
|
const menus = useMemo(() => {
|
|
81
|
-
|
|
89
|
+
let ret = [];
|
|
90
|
+
if (filterable && (dataType ?? filterOptions)) {
|
|
91
|
+
ret.push(
|
|
92
|
+
<Menu
|
|
93
|
+
key="filters"
|
|
94
|
+
label="Filter"
|
|
95
|
+
icon={filter ? CoreIcons.tick : ""}
|
|
96
|
+
trigger="click"
|
|
97
|
+
>
|
|
98
|
+
<ColumnFilters
|
|
99
|
+
type={dataType}
|
|
100
|
+
list={filterOptions}
|
|
101
|
+
filter={filter}
|
|
102
|
+
onFilter={(value) => onFilter?.(id, value)}
|
|
103
|
+
/>
|
|
104
|
+
</Menu>,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
82
107
|
if (sortable) {
|
|
83
108
|
ret.push(
|
|
84
109
|
<MenuItem
|
|
@@ -95,14 +120,23 @@ export const HeaderCell = ({
|
|
|
95
120
|
/>,
|
|
96
121
|
);
|
|
97
122
|
}
|
|
98
|
-
if (sortable && actions) {
|
|
99
|
-
ret.push(<Divider />);
|
|
100
|
-
}
|
|
101
123
|
if (actions) {
|
|
124
|
+
ret.push(<Divider key="div" />);
|
|
102
125
|
ret.push(...actions);
|
|
103
126
|
}
|
|
127
|
+
if (ret.length === 1) {
|
|
128
|
+
ret = [
|
|
129
|
+
<ColumnFilters
|
|
130
|
+
key="filters"
|
|
131
|
+
type={dataType}
|
|
132
|
+
list={filterOptions}
|
|
133
|
+
filter={filter}
|
|
134
|
+
onFilter={(value) => onFilter?.(id, value)}
|
|
135
|
+
/>,
|
|
136
|
+
];
|
|
137
|
+
}
|
|
104
138
|
return ret;
|
|
105
|
-
}, [sortable, actions]);
|
|
139
|
+
}, [sortable, actions, onFilter, handleSort]);
|
|
106
140
|
|
|
107
141
|
return (
|
|
108
142
|
<div
|
|
@@ -136,6 +170,16 @@ export const HeaderCell = ({
|
|
|
136
170
|
<Menu className="text-sm">{menus}</Menu>
|
|
137
171
|
</DropdownTool>
|
|
138
172
|
)}
|
|
173
|
+
{filterable && !isEmpty(filter) && (
|
|
174
|
+
<Button
|
|
175
|
+
size="sm"
|
|
176
|
+
variant="link"
|
|
177
|
+
aria-label="clear filter"
|
|
178
|
+
stopPropagation
|
|
179
|
+
icon={CoreIcons.funnelRemove}
|
|
180
|
+
onClick={() => onFilter?.(id)}
|
|
181
|
+
/>
|
|
182
|
+
)}
|
|
139
183
|
{resizable && (
|
|
140
184
|
<div
|
|
141
185
|
role="none"
|
package/src/table/Table.tsx
CHANGED
|
@@ -65,6 +65,7 @@ export const Table = <T extends KeyValue = KeyValue>({
|
|
|
65
65
|
canExpand,
|
|
66
66
|
children,
|
|
67
67
|
onSort,
|
|
68
|
+
onFilter,
|
|
68
69
|
onScroll,
|
|
69
70
|
onRowClick,
|
|
70
71
|
onCheckedChanged,
|
|
@@ -176,15 +177,33 @@ export const Table = <T extends KeyValue = KeyValue>({
|
|
|
176
177
|
/>
|
|
177
178
|
)}
|
|
178
179
|
{state.start?.map((col, idx) => (
|
|
179
|
-
<HeaderCell
|
|
180
|
+
<HeaderCell
|
|
181
|
+
key={idx}
|
|
182
|
+
{...col}
|
|
183
|
+
sort={sort}
|
|
184
|
+
onSort={onSort}
|
|
185
|
+
onFilter={onFilter}
|
|
186
|
+
/>
|
|
180
187
|
))}
|
|
181
188
|
</div>
|
|
182
189
|
{state.cols?.map((col, idx) => (
|
|
183
|
-
<HeaderCell
|
|
190
|
+
<HeaderCell
|
|
191
|
+
key={idx}
|
|
192
|
+
{...col}
|
|
193
|
+
sort={sort}
|
|
194
|
+
onSort={onSort}
|
|
195
|
+
onFilter={onFilter}
|
|
196
|
+
/>
|
|
184
197
|
))}
|
|
185
198
|
<div className={wrapperEnd}>
|
|
186
199
|
{state.end?.map((col, idx) => (
|
|
187
|
-
<HeaderCell
|
|
200
|
+
<HeaderCell
|
|
201
|
+
key={idx}
|
|
202
|
+
{...col}
|
|
203
|
+
sort={sort}
|
|
204
|
+
onSort={onSort}
|
|
205
|
+
onFilter={onFilter}
|
|
206
|
+
/>
|
|
188
207
|
))}
|
|
189
208
|
|
|
190
209
|
{hideableColumns && (
|
|
@@ -236,7 +255,7 @@ export const Table = <T extends KeyValue = KeyValue>({
|
|
|
236
255
|
</div>
|
|
237
256
|
) : (
|
|
238
257
|
<BodyRow
|
|
239
|
-
rowKey={key}
|
|
258
|
+
rowKey={key.toString()}
|
|
240
259
|
index={index}
|
|
241
260
|
checkableRows={checkableRows}
|
|
242
261
|
checked={
|
package/src/table/types.ts
CHANGED
|
@@ -50,7 +50,8 @@ export interface TableColumn<T = KeyValue>
|
|
|
50
50
|
resizable?: boolean;
|
|
51
51
|
sortable?: boolean;
|
|
52
52
|
filterable?: boolean;
|
|
53
|
-
|
|
53
|
+
filter?: AnyObject;
|
|
54
|
+
filterOptions?: AnyObject[];
|
|
54
55
|
width?: string | number;
|
|
55
56
|
minWidth?: string | number;
|
|
56
57
|
maxWidth?: string | number;
|
|
@@ -103,4 +104,6 @@ export interface TableProps<T = KeyValue> extends RefProp<TableRef> {
|
|
|
103
104
|
|
|
104
105
|
canExpand?: (record: T) => boolean;
|
|
105
106
|
children?: (record: T) => Elements<AnyObject>;
|
|
107
|
+
|
|
108
|
+
onFilter?: (id: keyof T | string, value?: AnyObject) => void;
|
|
106
109
|
}
|
package/src/tree/TreeNode.tsx
CHANGED
|
@@ -99,6 +99,7 @@ export const TreeNode = ({
|
|
|
99
99
|
aria-selected={node.selected}
|
|
100
100
|
className={classNames(
|
|
101
101
|
"flex flex-nowrap items-center",
|
|
102
|
+
node.className,
|
|
102
103
|
node.leaf ? leafClassName : nodeClassName,
|
|
103
104
|
)}
|
|
104
105
|
data-testid={node["data-testid"]}
|
|
@@ -145,17 +146,24 @@ export const TreeNode = ({
|
|
|
145
146
|
className={classNames(
|
|
146
147
|
"group/tool data-[selected]:bg-primary-100 flex flex-nowrap flex-1 overflow-hidden select-none",
|
|
147
148
|
node.childSelected && "font-medium",
|
|
148
|
-
|
|
149
|
+
node.disabled && "text-muted opacity-65",
|
|
150
|
+
!node.disabled &&
|
|
151
|
+
(canSelect || onClick) &&
|
|
152
|
+
"hover:bg-primary-50 cursor-pointer",
|
|
149
153
|
)}
|
|
150
154
|
data-selected={node.selected}
|
|
151
|
-
onClick={
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
onClick={
|
|
156
|
+
node.disabled
|
|
157
|
+
? undefined
|
|
158
|
+
: () => {
|
|
159
|
+
onClick?.(node.id, node.data);
|
|
160
|
+
canSelect
|
|
161
|
+
? onSelect(node.id)
|
|
162
|
+
: canCheck
|
|
163
|
+
? onChecked(node.id)
|
|
164
|
+
: onToggle(node.id);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
159
167
|
>
|
|
160
168
|
{nodeIcon && (
|
|
161
169
|
<div className="flex-content w-6 self-center leading-none">
|
package/src/virtual/Gallery.tsx
CHANGED
|
@@ -94,7 +94,7 @@ export interface VirtualGalleryProps<T> extends TestProps {
|
|
|
94
94
|
/**
|
|
95
95
|
* load more callback
|
|
96
96
|
*/
|
|
97
|
-
onLoadMore?: (
|
|
97
|
+
onLoadMore?: (lastIndex?: number) => void;
|
|
98
98
|
/**
|
|
99
99
|
* scroll handler
|
|
100
100
|
*/
|
|
@@ -103,7 +103,7 @@ export interface VirtualGalleryProps<T> extends TestProps {
|
|
|
103
103
|
|
|
104
104
|
const createItemList = memoize((items) => items);
|
|
105
105
|
|
|
106
|
-
const _VirtualGallery = <T extends
|
|
106
|
+
const _VirtualGallery = <T extends AnyObject>({
|
|
107
107
|
items,
|
|
108
108
|
children,
|
|
109
109
|
columns,
|
|
@@ -172,6 +172,7 @@ const _VirtualGallery = <T extends KeyValue>({
|
|
|
172
172
|
count: Math.ceil(count / columnCount),
|
|
173
173
|
getScrollElement: () => scrollerRef.current,
|
|
174
174
|
estimateSize: () => height,
|
|
175
|
+
overscan: 2,
|
|
175
176
|
});
|
|
176
177
|
|
|
177
178
|
const virtualItems = virtualizer.getVirtualItems();
|
|
@@ -219,16 +220,17 @@ const _VirtualGallery = <T extends KeyValue>({
|
|
|
219
220
|
if (onLoadMore) {
|
|
220
221
|
const firstItem = virtualItems[0]?.index;
|
|
221
222
|
const lastItem = virtualItems?.slice(-1).pop()?.index;
|
|
223
|
+
const firstIndex = firstItem * columnCount;
|
|
222
224
|
const lastIndex = (lastItem ?? 0) * columnCount + columnCount;
|
|
223
225
|
const canLoadPrevPage =
|
|
224
|
-
firstItem !== undefined && items[
|
|
226
|
+
firstItem !== undefined && items[firstIndex] === null;
|
|
225
227
|
const canLoadNextPage =
|
|
226
228
|
lastItem !== undefined && lastIndex >= count - 1 && count < total;
|
|
227
229
|
const db = debounce(onLoadMore);
|
|
228
230
|
if (canLoadPrevPage) {
|
|
229
|
-
db(
|
|
231
|
+
db(firstIndex);
|
|
230
232
|
} else if (!loading && canLoadNextPage) {
|
|
231
|
-
db(
|
|
233
|
+
db(lastIndex + 1);
|
|
232
234
|
}
|
|
233
235
|
return () => db.cancel();
|
|
234
236
|
}
|
|
@@ -277,9 +279,7 @@ const _VirtualGallery = <T extends KeyValue>({
|
|
|
277
279
|
<div
|
|
278
280
|
ref={scrollerRef}
|
|
279
281
|
onScroll={handleScroll}
|
|
280
|
-
className={classNames(
|
|
281
|
-
"area-content bg-base overflow-auto contain-strict",
|
|
282
|
-
)}
|
|
282
|
+
className={classNames("area-content bg-base overflow-auto")}
|
|
283
283
|
{...aria}
|
|
284
284
|
>
|
|
285
285
|
<div
|
|
@@ -306,12 +306,12 @@ const _VirtualGallery = <T extends KeyValue>({
|
|
|
306
306
|
}}
|
|
307
307
|
>
|
|
308
308
|
<div style={{ height: virtualItems[0]?.start }} />
|
|
309
|
-
{virtualItems.map(({ key, index
|
|
309
|
+
{virtualItems.map(({ key, index }) => (
|
|
310
310
|
<div
|
|
311
311
|
className="flex justify-start"
|
|
312
312
|
key={key}
|
|
313
313
|
data-index={index}
|
|
314
|
-
ref={measureElement}
|
|
314
|
+
ref={virtualizer.measureElement}
|
|
315
315
|
>
|
|
316
316
|
{columnMap.map((col) => (
|
|
317
317
|
<div
|
package/src/virtual/List.tsx
CHANGED
|
@@ -101,7 +101,7 @@ export interface VirtualListProps<T> extends TestProps {
|
|
|
101
101
|
/**
|
|
102
102
|
* load more callback
|
|
103
103
|
*/
|
|
104
|
-
onLoadMore?: (
|
|
104
|
+
onLoadMore?: (lastIndex?: number) => void;
|
|
105
105
|
/**
|
|
106
106
|
* scroll handler
|
|
107
107
|
*/
|
|
@@ -110,7 +110,7 @@ export interface VirtualListProps<T> extends TestProps {
|
|
|
110
110
|
|
|
111
111
|
const createItemList = memoizeOne((items) => items);
|
|
112
112
|
|
|
113
|
-
const _VirtualList = <T extends
|
|
113
|
+
const _VirtualList = <T extends AnyObject>({
|
|
114
114
|
items,
|
|
115
115
|
total = 0,
|
|
116
116
|
children,
|
|
@@ -149,6 +149,7 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
149
149
|
const scrollerRef = useRef<HTMLDivElement>(null);
|
|
150
150
|
const virtualizer = useVirtualizer({
|
|
151
151
|
count,
|
|
152
|
+
overscan: 2,
|
|
152
153
|
horizontal: orientation === "horizontal",
|
|
153
154
|
getScrollElement: () => scrollerRef.current,
|
|
154
155
|
estimateSize: () => (orientation === "horizontal" ? width : height),
|
|
@@ -263,9 +264,7 @@ const _VirtualList = <T extends KeyValue>({
|
|
|
263
264
|
<div
|
|
264
265
|
ref={scrollerRef}
|
|
265
266
|
onScroll={handleScroll}
|
|
266
|
-
className={classNames(
|
|
267
|
-
"area-content bg-base overflow-auto contain-strict",
|
|
268
|
-
)}
|
|
267
|
+
className={classNames("area-content bg-base overflow-auto")}
|
|
269
268
|
{...aria}
|
|
270
269
|
>
|
|
271
270
|
<div
|