@rc-component/listy 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +110 -0
- package/assets/index.css +36 -0
- package/assets/index.less +44 -0
- package/es/GroupHeader.d.ts +15 -0
- package/es/GroupHeader.js +32 -0
- package/es/List.d.ts +49 -0
- package/es/List.js +33 -0
- package/es/RawList/index.d.ts +5 -0
- package/es/RawList/index.js +90 -0
- package/es/RawList/useRawListScroll.d.ts +3 -0
- package/es/RawList/useRawListScroll.js +71 -0
- package/es/VirtualList/index.d.ts +5 -0
- package/es/VirtualList/index.js +151 -0
- package/es/VirtualList/useFlattenRows.d.ts +21 -0
- package/es/VirtualList/useFlattenRows.js +62 -0
- package/es/VirtualList/useStickyGroupHeader.d.ts +14 -0
- package/es/VirtualList/useStickyGroupHeader.js +82 -0
- package/es/hooks/useGroupSegments.d.ts +16 -0
- package/es/hooks/useGroupSegments.js +39 -0
- package/es/index.d.ts +3 -0
- package/es/index.js +2 -0
- package/lib/GroupHeader.d.ts +15 -0
- package/lib/GroupHeader.js +40 -0
- package/lib/List.d.ts +49 -0
- package/lib/List.js +41 -0
- package/lib/RawList/index.d.ts +5 -0
- package/lib/RawList/index.js +98 -0
- package/lib/RawList/useRawListScroll.d.ts +3 -0
- package/lib/RawList/useRawListScroll.js +79 -0
- package/lib/VirtualList/index.d.ts +5 -0
- package/lib/VirtualList/index.js +159 -0
- package/lib/VirtualList/useFlattenRows.d.ts +21 -0
- package/lib/VirtualList/useFlattenRows.js +69 -0
- package/lib/VirtualList/useStickyGroupHeader.d.ts +14 -0
- package/lib/VirtualList/useStickyGroupHeader.js +90 -0
- package/lib/hooks/useGroupSegments.d.ts +16 -0
- package/lib/hooks/useGroupSegments.js +46 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +9 -0
- package/package.json +76 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var React = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _virtualList = _interopRequireDefault(require("@rc-component/virtual-list"));
|
|
9
|
+
var _util = require("@rc-component/util");
|
|
10
|
+
var _GroupHeader = _interopRequireDefault(require("../GroupHeader"));
|
|
11
|
+
var _useGroupSegments = _interopRequireDefault(require("../hooks/useGroupSegments"));
|
|
12
|
+
var _useFlattenRows = _interopRequireDefault(require("./useFlattenRows"));
|
|
13
|
+
var _useStickyGroupHeader = _interopRequireDefault(require("./useStickyGroupHeader"));
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
16
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
17
|
+
// ============================== Types ===============================
|
|
18
|
+
|
|
19
|
+
function VirtualList(props, ref) {
|
|
20
|
+
// ============================== Props ==============================
|
|
21
|
+
const {
|
|
22
|
+
data,
|
|
23
|
+
group,
|
|
24
|
+
height,
|
|
25
|
+
itemHeight,
|
|
26
|
+
itemRender,
|
|
27
|
+
onScroll,
|
|
28
|
+
prefixCls,
|
|
29
|
+
rowKey,
|
|
30
|
+
sticky
|
|
31
|
+
} = props;
|
|
32
|
+
|
|
33
|
+
// =============================== Refs ===============================
|
|
34
|
+
const listRef = React.useRef(null);
|
|
35
|
+
|
|
36
|
+
// =============================== Data ===============================
|
|
37
|
+
const groupData = (0, _useGroupSegments.default)(data, group);
|
|
38
|
+
|
|
39
|
+
// =============================== Keys ===============================
|
|
40
|
+
const getItemKey = (0, _util.useEvent)(item => {
|
|
41
|
+
if (typeof rowKey === 'function') {
|
|
42
|
+
return rowKey(item);
|
|
43
|
+
}
|
|
44
|
+
return item[rowKey];
|
|
45
|
+
});
|
|
46
|
+
const getKey = (0, _util.useEvent)(row => {
|
|
47
|
+
if (row.type === 'header') {
|
|
48
|
+
return row.groupKey;
|
|
49
|
+
}
|
|
50
|
+
return getItemKey(row.item);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// ============================== Rows ================================
|
|
54
|
+
const {
|
|
55
|
+
rows,
|
|
56
|
+
groupKeys,
|
|
57
|
+
groupKeyToItems
|
|
58
|
+
} = (0, _useFlattenRows.default)(data, groupData, group);
|
|
59
|
+
|
|
60
|
+
// ============================== Lookup ==============================
|
|
61
|
+
const itemKeyToGroupKey = React.useMemo(() => {
|
|
62
|
+
const itemGroupMap = new Map();
|
|
63
|
+
groupData.forEach((groupItems, groupKey) => {
|
|
64
|
+
groupItems.forEach(({
|
|
65
|
+
item
|
|
66
|
+
}) => {
|
|
67
|
+
itemGroupMap.set(getItemKey(item), groupKey);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
return itemGroupMap;
|
|
71
|
+
}, [getItemKey, groupData]);
|
|
72
|
+
|
|
73
|
+
// ============================== Scroll ==============================
|
|
74
|
+
const scrollTo = (0, _util.useEvent)(config => {
|
|
75
|
+
// Group headers are rows in the virtual data, so group scroll maps to key scroll.
|
|
76
|
+
if (config && typeof config === 'object' && 'groupKey' in config) {
|
|
77
|
+
const {
|
|
78
|
+
groupKey,
|
|
79
|
+
align,
|
|
80
|
+
offset
|
|
81
|
+
} = config;
|
|
82
|
+
listRef.current?.scrollTo({
|
|
83
|
+
key: groupKey,
|
|
84
|
+
align,
|
|
85
|
+
offset
|
|
86
|
+
});
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// For sticky grouped lists, top-aligned item scroll should land below its header.
|
|
91
|
+
if (config && typeof config === 'object' && 'key' in config && sticky && group && config.align === 'top') {
|
|
92
|
+
const groupKey = itemKeyToGroupKey.get(config.key);
|
|
93
|
+
if (groupKey !== undefined) {
|
|
94
|
+
const {
|
|
95
|
+
offset = 0
|
|
96
|
+
} = config;
|
|
97
|
+
listRef.current?.scrollTo({
|
|
98
|
+
...config,
|
|
99
|
+
// Use the measured header height so top-aligned items stay below it.
|
|
100
|
+
offset: ({
|
|
101
|
+
getSize
|
|
102
|
+
}) => {
|
|
103
|
+
const headerSize = getSize(groupKey);
|
|
104
|
+
const headerHeight = headerSize.bottom - headerSize.top;
|
|
105
|
+
return offset + (Number.isFinite(headerHeight) ? headerHeight : 0);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Other scroll shapes are already supported by the underlying virtual list.
|
|
113
|
+
listRef.current?.scrollTo(config);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// ============================ Imperative ============================
|
|
117
|
+
React.useImperativeHandle(ref, () => ({
|
|
118
|
+
scrollTo
|
|
119
|
+
}), [scrollTo]);
|
|
120
|
+
|
|
121
|
+
// ============================== Sticky ==============================
|
|
122
|
+
const extraRender = (0, _useStickyGroupHeader.default)({
|
|
123
|
+
enabled: !!(sticky && group),
|
|
124
|
+
group,
|
|
125
|
+
groupKeys,
|
|
126
|
+
groupKeyToItems,
|
|
127
|
+
prefixCls,
|
|
128
|
+
listRef
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ============================ Render Row ============================
|
|
132
|
+
const renderHeaderRow = React.useCallback(groupKey => {
|
|
133
|
+
const groupItems = groupKeyToItems.get(groupKey) || [];
|
|
134
|
+
return /*#__PURE__*/React.createElement(_GroupHeader.default, {
|
|
135
|
+
group: group,
|
|
136
|
+
groupKey: groupKey,
|
|
137
|
+
groupItems: groupItems,
|
|
138
|
+
prefixCls: prefixCls
|
|
139
|
+
});
|
|
140
|
+
}, [group, groupKeyToItems, prefixCls]);
|
|
141
|
+
|
|
142
|
+
// ============================== Render ==============================
|
|
143
|
+
return /*#__PURE__*/React.createElement(_virtualList.default, {
|
|
144
|
+
ref: listRef,
|
|
145
|
+
data: rows,
|
|
146
|
+
fullHeight: false,
|
|
147
|
+
height: height,
|
|
148
|
+
itemHeight: itemHeight,
|
|
149
|
+
itemKey: getKey,
|
|
150
|
+
onScroll: onScroll,
|
|
151
|
+
prefixCls: prefixCls,
|
|
152
|
+
virtual: true,
|
|
153
|
+
extraRender: extraRender
|
|
154
|
+
}, row => row.type === 'header' ? renderHeaderRow(row.groupKey) : /*#__PURE__*/React.createElement("div", {
|
|
155
|
+
className: `${prefixCls}-item`
|
|
156
|
+
}, itemRender(row.item, row.index)));
|
|
157
|
+
}
|
|
158
|
+
const VirtualListWithRef = /*#__PURE__*/React.forwardRef(VirtualList);
|
|
159
|
+
var _default = exports.default = VirtualListWithRef;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { Group, GroupSegmentItem } from '../hooks/useGroupSegments';
|
|
3
|
+
export type Row<T, K extends React.Key = React.Key> = {
|
|
4
|
+
type: 'header';
|
|
5
|
+
groupKey: K;
|
|
6
|
+
} | {
|
|
7
|
+
type: 'item';
|
|
8
|
+
item: T;
|
|
9
|
+
index: number;
|
|
10
|
+
};
|
|
11
|
+
export interface FlattenRowsResult<T, K extends React.Key = React.Key> {
|
|
12
|
+
rows: Row<T, K>[];
|
|
13
|
+
groupKeys: K[];
|
|
14
|
+
groupKeyToItems: Map<K, T[]>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Flatten grouped data into header and item rows.
|
|
18
|
+
* When grouping is enabled, items follow the insertion order of the group map
|
|
19
|
+
* while preserving their original indexes.
|
|
20
|
+
*/
|
|
21
|
+
export default function useFlattenRows<T, K extends React.Key = React.Key>(data: T[], groupData: Map<K, GroupSegmentItem<T>[]>, group?: Group<T, K>): FlattenRowsResult<T, K>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = useFlattenRows;
|
|
7
|
+
var React = _interopRequireWildcard(require("react"));
|
|
8
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
9
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
10
|
+
// ============================== Types ===============================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Flatten grouped data into header and item rows.
|
|
14
|
+
* When grouping is enabled, items follow the insertion order of the group map
|
|
15
|
+
* while preserving their original indexes.
|
|
16
|
+
*/
|
|
17
|
+
function useFlattenRows(data, groupData, group) {
|
|
18
|
+
return React.useMemo(() => {
|
|
19
|
+
// ============================== Init ================================
|
|
20
|
+
const flatRows = [];
|
|
21
|
+
const groupKeys = [];
|
|
22
|
+
const groupKeyToItems = new Map();
|
|
23
|
+
|
|
24
|
+
// ============================ No Group ==============================
|
|
25
|
+
if (!group) {
|
|
26
|
+
data.forEach((item, index) => {
|
|
27
|
+
flatRows.push({
|
|
28
|
+
type: 'item',
|
|
29
|
+
item,
|
|
30
|
+
index
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
rows: flatRows,
|
|
35
|
+
groupKeys,
|
|
36
|
+
groupKeyToItems
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============================= Flatten ==============================
|
|
41
|
+
groupData.forEach((groupItems, groupKey) => {
|
|
42
|
+
groupKeyToItems.set(groupKey, groupItems.map(({
|
|
43
|
+
item
|
|
44
|
+
}) => item));
|
|
45
|
+
groupKeys.push(groupKey);
|
|
46
|
+
flatRows.push({
|
|
47
|
+
type: 'header',
|
|
48
|
+
groupKey
|
|
49
|
+
});
|
|
50
|
+
groupItems.forEach(({
|
|
51
|
+
item,
|
|
52
|
+
index
|
|
53
|
+
}) => {
|
|
54
|
+
flatRows.push({
|
|
55
|
+
type: 'item',
|
|
56
|
+
item,
|
|
57
|
+
index
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// ============================== Return ==============================
|
|
63
|
+
return {
|
|
64
|
+
rows: flatRows,
|
|
65
|
+
groupKeys,
|
|
66
|
+
groupKeyToItems
|
|
67
|
+
};
|
|
68
|
+
}, [data, group, groupData]);
|
|
69
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { ListProps as VirtualListProps, ListRef as RcVirtualListRef } from '@rc-component/virtual-list';
|
|
3
|
+
import type { Group } from '../hooks/useGroupSegments';
|
|
4
|
+
type ExtraRenderInfo = Parameters<NonNullable<VirtualListProps<unknown>['extraRender']>>[0];
|
|
5
|
+
export interface StickyHeaderParams<T, K extends React.Key = React.Key> {
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
group: Group<T, K> | undefined;
|
|
8
|
+
groupKeys: K[];
|
|
9
|
+
groupKeyToItems: Map<K, T[]>;
|
|
10
|
+
prefixCls: string;
|
|
11
|
+
listRef: React.RefObject<RcVirtualListRef | null>;
|
|
12
|
+
}
|
|
13
|
+
export default function useStickyGroupHeader<T, K extends React.Key = React.Key>(params: StickyHeaderParams<T, K>): (info: ExtraRenderInfo) => React.JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = useStickyGroupHeader;
|
|
7
|
+
var React = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _portal = _interopRequireDefault(require("@rc-component/portal"));
|
|
9
|
+
var _GroupHeader = _interopRequireDefault(require("../GroupHeader"));
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
12
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
13
|
+
// ============================== Types ===============================
|
|
14
|
+
|
|
15
|
+
// ============================== Utils ===============================
|
|
16
|
+
const HEADER_TOP_TOLERANCE = 1;
|
|
17
|
+
function findActiveHeaderIndex(groupKeys, getHeaderTop, scrollTop) {
|
|
18
|
+
let left = 0;
|
|
19
|
+
let right = groupKeys.length - 1;
|
|
20
|
+
let activeIndex = 0;
|
|
21
|
+
while (left <= right) {
|
|
22
|
+
const mid = Math.floor((left + right) / 2);
|
|
23
|
+
if (getHeaderTop(groupKeys[mid]) <= scrollTop + HEADER_TOP_TOLERANCE) {
|
|
24
|
+
activeIndex = mid;
|
|
25
|
+
left = mid + 1;
|
|
26
|
+
} else {
|
|
27
|
+
right = mid - 1;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return activeIndex;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ============================== Params ==============================
|
|
34
|
+
|
|
35
|
+
function useStickyGroupHeader(params) {
|
|
36
|
+
// ============================== Props ==============================
|
|
37
|
+
const {
|
|
38
|
+
enabled,
|
|
39
|
+
group,
|
|
40
|
+
groupKeys,
|
|
41
|
+
groupKeyToItems,
|
|
42
|
+
prefixCls,
|
|
43
|
+
listRef
|
|
44
|
+
} = params;
|
|
45
|
+
|
|
46
|
+
// ============================ Extra Render ==========================
|
|
47
|
+
const extraRender = React.useCallback(info => {
|
|
48
|
+
const {
|
|
49
|
+
getSize,
|
|
50
|
+
scrollTop,
|
|
51
|
+
virtual
|
|
52
|
+
} = info;
|
|
53
|
+
if (!enabled || !group || !groupKeys.length || !virtual) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const container = listRef.current?.nativeElement;
|
|
57
|
+
if (!container) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// The sticky header is the group whose section the viewport top sits in.
|
|
62
|
+
const activeHeaderIdx = findActiveHeaderIndex(groupKeys, groupKey => getSize(groupKey).top, scrollTop);
|
|
63
|
+
const currGroupKey = groupKeys[activeHeaderIdx];
|
|
64
|
+
const groupItems = groupKeyToItems.get(currGroupKey) || [];
|
|
65
|
+
const currentSize = getSize(currGroupKey);
|
|
66
|
+
const headerHeight = currentSize.bottom - currentSize.top;
|
|
67
|
+
const nextGroupKey = groupKeys[activeHeaderIdx + 1];
|
|
68
|
+
const top = nextGroupKey ? Math.min(0, getSize(nextGroupKey).top - headerHeight - scrollTop) : 0;
|
|
69
|
+
|
|
70
|
+
// Render a cloned header pinned over the virtual list.
|
|
71
|
+
return /*#__PURE__*/React.createElement(_portal.default, {
|
|
72
|
+
open: true,
|
|
73
|
+
getContainer: () => container
|
|
74
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
75
|
+
className: `${prefixCls}-group-header-holder`
|
|
76
|
+
}, /*#__PURE__*/React.createElement(_GroupHeader.default, {
|
|
77
|
+
fixed: true,
|
|
78
|
+
group: group,
|
|
79
|
+
groupKey: currGroupKey,
|
|
80
|
+
groupItems: groupItems,
|
|
81
|
+
prefixCls: prefixCls,
|
|
82
|
+
style: {
|
|
83
|
+
top
|
|
84
|
+
}
|
|
85
|
+
})));
|
|
86
|
+
}, [enabled, group, groupKeys, groupKeyToItems, prefixCls, listRef]);
|
|
87
|
+
|
|
88
|
+
// ============================== Return ==============================
|
|
89
|
+
return extraRender;
|
|
90
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface Group<T, K extends React.Key = React.Key> {
|
|
3
|
+
key: (item: T) => K;
|
|
4
|
+
title: (groupKey: K, items: T[]) => React.ReactNode;
|
|
5
|
+
}
|
|
6
|
+
export interface GroupSegmentItem<T> {
|
|
7
|
+
item: T;
|
|
8
|
+
index: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Build a lookup map from group key to all matching data items and their
|
|
12
|
+
* original indexes.
|
|
13
|
+
* This groups by key across the full data set and does not require items with
|
|
14
|
+
* the same key to be contiguous.
|
|
15
|
+
*/
|
|
16
|
+
export default function useGroupSegments<T, K extends React.Key = React.Key>(data: T[], group?: Group<T, K>): Map<K, GroupSegmentItem<T>[]>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = useGroupSegments;
|
|
7
|
+
var React = _interopRequireWildcard(require("react"));
|
|
8
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
9
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
10
|
+
// ============================== Types ===============================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Build a lookup map from group key to all matching data items and their
|
|
14
|
+
* original indexes.
|
|
15
|
+
* This groups by key across the full data set and does not require items with
|
|
16
|
+
* the same key to be contiguous.
|
|
17
|
+
*/
|
|
18
|
+
function useGroupSegments(data, group) {
|
|
19
|
+
return React.useMemo(() => {
|
|
20
|
+
// ============================== Init ================================
|
|
21
|
+
const map = new Map();
|
|
22
|
+
|
|
23
|
+
// ============================ No Group ==============================
|
|
24
|
+
if (!group) {
|
|
25
|
+
return map;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ============================= Collect ==============================
|
|
29
|
+
data.forEach((item, index) => {
|
|
30
|
+
const groupKey = group.key(item);
|
|
31
|
+
const groupItems = map.get(groupKey);
|
|
32
|
+
const groupSegmentItem = {
|
|
33
|
+
item,
|
|
34
|
+
index
|
|
35
|
+
};
|
|
36
|
+
if (groupItems) {
|
|
37
|
+
groupItems.push(groupSegmentItem);
|
|
38
|
+
} else {
|
|
39
|
+
map.set(groupKey, [groupSegmentItem]);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// ============================== Return ==============================
|
|
44
|
+
return map;
|
|
45
|
+
}, [data, group]);
|
|
46
|
+
}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _List = _interopRequireDefault(require("./List"));
|
|
8
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
|
+
var _default = exports.default = _List.default;
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rc-component/listy",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "React Listy Component",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"react-component",
|
|
8
|
+
"list",
|
|
9
|
+
"high performance",
|
|
10
|
+
"headless ui"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/react-component/listy",
|
|
13
|
+
"author": "",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/react-component/listy.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/react-component/listy/issues"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"es",
|
|
23
|
+
"lib",
|
|
24
|
+
"assets/**/*.css",
|
|
25
|
+
"assets/**/*.less"
|
|
26
|
+
],
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"main": "./lib/index",
|
|
29
|
+
"module": "./es/index",
|
|
30
|
+
"scripts": {
|
|
31
|
+
"start": "dumi dev",
|
|
32
|
+
"build": "dumi build",
|
|
33
|
+
"compile": "father build && lessc assets/index.less assets/index.css",
|
|
34
|
+
"prepublishOnly": "npm run compile && rc-np",
|
|
35
|
+
"lint": "eslint src/ docs/examples/ --ext .tsx,.ts,.jsx,.js",
|
|
36
|
+
"test": "rc-test",
|
|
37
|
+
"prettier": "prettier --write .",
|
|
38
|
+
"coverage": "rc-test --coverage",
|
|
39
|
+
"now-build": "npm run build"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@rc-component/motion": "^1.1.4",
|
|
43
|
+
"@rc-component/portal": "^2.0.0",
|
|
44
|
+
"@rc-component/resize-observer": "^1.0.0",
|
|
45
|
+
"@rc-component/util": "^1.3.1",
|
|
46
|
+
"clsx": "^2.1.1",
|
|
47
|
+
"@rc-component/virtual-list": "^1.2.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@rc-component/father-plugin": "^2.1.3",
|
|
51
|
+
"@rc-component/np": "^1.0.4",
|
|
52
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
53
|
+
"@testing-library/react": "^16.3.0",
|
|
54
|
+
"@types/classnames": "^2.3.4",
|
|
55
|
+
"@types/jest": "^30.0.0",
|
|
56
|
+
"@types/node": "^24.10.0",
|
|
57
|
+
"@types/react": "^19.2.2",
|
|
58
|
+
"@types/react-dom": "^19.2.2",
|
|
59
|
+
"@umijs/fabric": "^4.0.1",
|
|
60
|
+
"cross-env": "^10.1.0",
|
|
61
|
+
"dumi": "^2.4.21",
|
|
62
|
+
"eslint": "^8.57.1",
|
|
63
|
+
"father": "^4.6.7",
|
|
64
|
+
"less": "^4.4.2",
|
|
65
|
+
"prettier": "^3.6.2",
|
|
66
|
+
"rc-test": "^7.1.2",
|
|
67
|
+
"react": "^19.2.0",
|
|
68
|
+
"react-dom": "^19.2.0",
|
|
69
|
+
"regenerator-runtime": "^0.14.1",
|
|
70
|
+
"typescript": "^6.0.3"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"react": ">=18.0.0",
|
|
74
|
+
"react-dom": ">=18.0.0"
|
|
75
|
+
}
|
|
76
|
+
}
|