@lotics/ui 2.6.1 → 3.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/package.json +2 -15
- package/src/react_native.d.ts +2 -2
- package/src/segmented_control.tsx +201 -0
- package/src/cell_date.tsx +0 -30
- package/src/cell_date_format.test.ts +0 -32
- package/src/cell_date_format.ts +0 -73
- package/src/cell_number.test.ts +0 -42
- package/src/cell_number.tsx +0 -25
- package/src/cell_number_format.ts +0 -42
- package/src/cell_select.tsx +0 -68
- package/src/cell_text.tsx +0 -45
- package/src/grid/data_grid.tsx +0 -2003
- package/src/grid/data_grid_columns.test.ts +0 -72
- package/src/grid/data_grid_columns.ts +0 -30
- package/src/grid/data_grid_context.ts +0 -119
- package/src/grid/dispatch_safely.ts +0 -39
- package/src/grid/engine.module.css +0 -114
- package/src/grid/engine.tsx +0 -1042
- package/src/grid/helpers.ts +0 -205
- package/src/grid/layout.test.ts +0 -515
- package/src/grid/layout.ts +0 -425
- package/src/grid/recycling.test.ts +0 -236
- package/src/grid/recycling.ts +0 -172
- package/src/grid/row_cell.module.css +0 -105
- package/src/grid/row_cell.tsx +0 -313
- package/src/grid/search_highlight.ts +0 -71
- package/src/grid/select_cell.tsx +0 -58
- package/src/grid/select_group_summary_cell.tsx +0 -76
- package/src/grid/select_header_cell.tsx +0 -32
- package/src/grid/skeleton_row.module.css +0 -34
- package/src/grid/skeleton_row.tsx +0 -20
- package/src/grid/use_grid_groups.ts +0 -311
- package/src/grid/use_scroll_to_cell.ts +0 -135
- package/src/grid/use_virtual_grid.ts +0 -383
- package/src/grid/visibility.test.ts +0 -208
- package/src/grid/visibility.ts +0 -77
- package/src/kanban/constants.ts +0 -18
- package/src/kanban/default_renderers.tsx +0 -160
- package/src/kanban/drag_preview.tsx +0 -157
- package/src/kanban/index.ts +0 -13
- package/src/kanban/insert_card_zone.tsx +0 -135
- package/src/kanban/kanban_board.tsx +0 -635
- package/src/kanban/kanban_card.tsx +0 -321
- package/src/kanban/kanban_column.tsx +0 -499
- package/src/kanban/placeholders.tsx +0 -54
- package/src/kanban/types.ts +0 -116
package/src/grid/helpers.ts
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
export function isNumberString(value: string): boolean {
|
|
2
|
-
if (isNaN(Number(value.trim()))) {
|
|
3
|
-
return false;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
return true;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function isObject(o: unknown): o is Record<string, unknown> {
|
|
10
|
-
if (typeof o === "object") {
|
|
11
|
-
return (
|
|
12
|
-
(o === null || Array.isArray(o) || typeof o == "function" || o.constructor === Date) === false
|
|
13
|
-
);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function sum(numbers: number[]): number {
|
|
20
|
-
return numbers.reduce((previousValue, currentValue) => previousValue + currentValue, 0);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function maxBy<T>(a: T[], getValue: (item: T) => number): number {
|
|
24
|
-
if (a.length === 0) {
|
|
25
|
-
return -Infinity;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let maxVal = getValue(a[0]);
|
|
29
|
-
for (let i = 1; i < a.length; i++) {
|
|
30
|
-
const val = getValue(a[i]);
|
|
31
|
-
if (val > maxVal) {
|
|
32
|
-
maxVal = val;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return maxVal;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function sumBy<T>(a: T[], getValue: (item: T) => number): number {
|
|
39
|
-
let total = 0;
|
|
40
|
-
for (let i = 0; i < a.length; i++) {
|
|
41
|
-
total += getValue(a[i]);
|
|
42
|
-
}
|
|
43
|
-
return total;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function max(...args: number[]): number {
|
|
47
|
-
return Math.max(...args);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function min(...args: number[]): number {
|
|
51
|
-
return Math.min(...args);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function isEqual(a: unknown, b: unknown): boolean {
|
|
55
|
-
if (a === b) {
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (isArray(a) && isArray(b)) {
|
|
60
|
-
return isArrayEqual(a, b);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (isObject(a) && isObject(b)) {
|
|
64
|
-
return isObjectEqual(a, b);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return a !== a && b !== b;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function isArrayEqual<T>(a: T[], b: T[]): boolean {
|
|
71
|
-
if (a.length !== b.length) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
for (let i = 0; i < a.length; i++) {
|
|
76
|
-
const itemA = a[i];
|
|
77
|
-
const itemB = b[i];
|
|
78
|
-
|
|
79
|
-
if (isEqual(itemA, itemB) === false) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function isObjectEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {
|
|
88
|
-
if (a.constructor !== b.constructor) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (a.valueOf !== Object.prototype.valueOf) {
|
|
93
|
-
return a.valueOf() === b.valueOf();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (a.toString !== Object.prototype.toString) {
|
|
97
|
-
return a.toString() === b.toString();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const keys = Object.keys(a);
|
|
101
|
-
const length = keys.length;
|
|
102
|
-
if (length !== Object.keys(b).length) {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
for (let i = length; i-- !== 0; ) {
|
|
107
|
-
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
for (let i = length; i-- !== 0; ) {
|
|
113
|
-
const key = keys[i];
|
|
114
|
-
|
|
115
|
-
const subA = a[key];
|
|
116
|
-
const subB = b[key];
|
|
117
|
-
|
|
118
|
-
if (!isEqual(subA, subB)) {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return true;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export function isEmpty<T extends Record<string, unknown>>(data: T): boolean;
|
|
127
|
-
export function isEmpty<T>(data: T[]): boolean;
|
|
128
|
-
export function isEmpty(data: unknown[] | Record<string, unknown>): boolean {
|
|
129
|
-
if (isArray(data)) {
|
|
130
|
-
return data.length === 0;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return Object.keys(data).length === 0;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Returns array of values found in left and right array.
|
|
138
|
-
* Other values not intersected by, will be taken from left array.
|
|
139
|
-
*
|
|
140
|
-
* If `merge` is true, objects will be merged, with the objects from right array overriding the other array objects.
|
|
141
|
-
*/
|
|
142
|
-
export function intersectBy<T, K>(
|
|
143
|
-
a: T[],
|
|
144
|
-
b: K[],
|
|
145
|
-
getValue: (item: T | K) => string | number,
|
|
146
|
-
merge = false,
|
|
147
|
-
): T[] {
|
|
148
|
-
const bMap: { [key: string]: K } = {};
|
|
149
|
-
|
|
150
|
-
for (let i = 0; i < b.length; i++) {
|
|
151
|
-
const itemB = b[i];
|
|
152
|
-
const val = getValue(itemB);
|
|
153
|
-
bMap[val] = itemB;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const result: T[] = [];
|
|
157
|
-
|
|
158
|
-
for (let i = 0; i < a.length; i++) {
|
|
159
|
-
const itemA = a[i];
|
|
160
|
-
const val = getValue(itemA);
|
|
161
|
-
const itemB = bMap[val];
|
|
162
|
-
|
|
163
|
-
if (itemB !== undefined) {
|
|
164
|
-
if (merge) {
|
|
165
|
-
result.push({ ...itemA, ...itemB });
|
|
166
|
-
} else {
|
|
167
|
-
result.push(itemA);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return result;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/** Returns array of values in left array that are not in the right array */
|
|
176
|
-
export function differenceBy<T, K>(
|
|
177
|
-
a: T[],
|
|
178
|
-
b: K[],
|
|
179
|
-
getValue: (item: T | K) => string | number,
|
|
180
|
-
): T[] {
|
|
181
|
-
const bMap: { [key: string]: K } = {};
|
|
182
|
-
|
|
183
|
-
for (let i = 0; i < b.length; i++) {
|
|
184
|
-
const itemB = b[i];
|
|
185
|
-
const val = getValue(itemB);
|
|
186
|
-
bMap[val] = itemB;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const result: T[] = [];
|
|
190
|
-
|
|
191
|
-
for (let i = 0; i < a.length; i++) {
|
|
192
|
-
const itemA = a[i];
|
|
193
|
-
const val = getValue(itemA);
|
|
194
|
-
|
|
195
|
-
if (bMap[val] === undefined) {
|
|
196
|
-
result.push(itemA);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return result;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export function isArray<T>(arg: unknown): arg is T[] {
|
|
204
|
-
return Array.isArray(arg);
|
|
205
|
-
}
|
package/src/grid/layout.test.ts
DELETED
|
@@ -1,515 +0,0 @@
|
|
|
1
|
-
import { getColumns, getRows, GridGroup, GridRow, GridColumn, groupPathToKey } from "./layout";
|
|
2
|
-
|
|
3
|
-
test("getColumns - basic columns", () => {
|
|
4
|
-
const result = getColumns([100, 200, 100, 200, 100, 200]);
|
|
5
|
-
|
|
6
|
-
const expected: GridColumn[] = [
|
|
7
|
-
{ column: 0, width: 100, x: 0 },
|
|
8
|
-
{ column: 1, width: 200, x: 100 },
|
|
9
|
-
{ column: 2, width: 100, x: 300 },
|
|
10
|
-
{ column: 3, width: 200, x: 400 },
|
|
11
|
-
{ column: 4, width: 100, x: 600 },
|
|
12
|
-
{ column: 5, width: 200, x: 700 },
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
expect(result).toEqual(expected);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test("getRows - single flat group", () => {
|
|
19
|
-
const groups: GridGroup[] = [
|
|
20
|
-
{
|
|
21
|
-
type: "row_group",
|
|
22
|
-
rowCount: 2,
|
|
23
|
-
},
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
const rows = getRows(groups, 40, 40, 40, 72, null);
|
|
27
|
-
|
|
28
|
-
const expected: GridRow[] = [
|
|
29
|
-
{
|
|
30
|
-
type: "row",
|
|
31
|
-
height: 40,
|
|
32
|
-
y: 0,
|
|
33
|
-
rowPath: [0, 0],
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
type: "row",
|
|
37
|
-
height: 40,
|
|
38
|
-
y: 40,
|
|
39
|
-
rowPath: [0, 1],
|
|
40
|
-
},
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
expect(rows).toEqual(expected);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test("getRows - nested with leaf rows", () => {
|
|
47
|
-
const groups: GridGroup[] = [
|
|
48
|
-
{
|
|
49
|
-
type: "group",
|
|
50
|
-
children: [
|
|
51
|
-
{
|
|
52
|
-
type: "row_group",
|
|
53
|
-
rowCount: 2,
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
type: "group",
|
|
59
|
-
children: [
|
|
60
|
-
{
|
|
61
|
-
type: "row_group",
|
|
62
|
-
rowCount: 2,
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
type: "row_group",
|
|
66
|
-
rowCount: 2,
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
];
|
|
71
|
-
|
|
72
|
-
const rows = getRows(groups, 40, 40, 40, 72, null);
|
|
73
|
-
|
|
74
|
-
const expected: GridRow[] = [
|
|
75
|
-
{
|
|
76
|
-
type: "group_heading",
|
|
77
|
-
height: 40,
|
|
78
|
-
y: 0,
|
|
79
|
-
groupPath: [0],
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
type: "group_summary",
|
|
83
|
-
height: 40,
|
|
84
|
-
y: 40,
|
|
85
|
-
groupPath: [0],
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
type: "group_heading",
|
|
89
|
-
height: 40,
|
|
90
|
-
y: 80,
|
|
91
|
-
groupPath: [0, 0],
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
type: "group_summary",
|
|
95
|
-
height: 40,
|
|
96
|
-
y: 120,
|
|
97
|
-
groupPath: [0, 0],
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
type: "row",
|
|
101
|
-
height: 40,
|
|
102
|
-
y: 160,
|
|
103
|
-
rowPath: [0, 0, 0],
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
type: "row",
|
|
107
|
-
height: 40,
|
|
108
|
-
y: 200,
|
|
109
|
-
rowPath: [0, 0, 1],
|
|
110
|
-
},
|
|
111
|
-
{ type: "spacer", height: 72, y: 240 },
|
|
112
|
-
{
|
|
113
|
-
type: "group_heading",
|
|
114
|
-
height: 40,
|
|
115
|
-
y: 312,
|
|
116
|
-
groupPath: [1],
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
type: "group_summary",
|
|
120
|
-
height: 40,
|
|
121
|
-
y: 352,
|
|
122
|
-
groupPath: [1],
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
type: "group_heading",
|
|
126
|
-
height: 40,
|
|
127
|
-
y: 392,
|
|
128
|
-
groupPath: [1, 0],
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
type: "group_summary",
|
|
132
|
-
height: 40,
|
|
133
|
-
y: 432,
|
|
134
|
-
groupPath: [1, 0],
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
type: "row",
|
|
138
|
-
height: 40,
|
|
139
|
-
y: 472,
|
|
140
|
-
rowPath: [1, 0, 0],
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
type: "row",
|
|
144
|
-
height: 40,
|
|
145
|
-
y: 512,
|
|
146
|
-
rowPath: [1, 0, 1],
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
type: "group_heading",
|
|
150
|
-
height: 40,
|
|
151
|
-
y: 552,
|
|
152
|
-
groupPath: [1, 1],
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
type: "group_summary",
|
|
156
|
-
height: 40,
|
|
157
|
-
y: 592,
|
|
158
|
-
groupPath: [1, 1],
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
type: "row",
|
|
162
|
-
height: 40,
|
|
163
|
-
y: 632,
|
|
164
|
-
rowPath: [1, 1, 0],
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
type: "row",
|
|
168
|
-
height: 40,
|
|
169
|
-
y: 672,
|
|
170
|
-
rowPath: [1, 1, 1],
|
|
171
|
-
},
|
|
172
|
-
{ type: "spacer", height: 72, y: 712 },
|
|
173
|
-
];
|
|
174
|
-
|
|
175
|
-
expect(rows).toEqual(expected);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test("getRows - nested with empty leaf rows", () => {
|
|
179
|
-
const groups: GridGroup[] = [
|
|
180
|
-
{
|
|
181
|
-
type: "group",
|
|
182
|
-
children: [
|
|
183
|
-
{
|
|
184
|
-
type: "row_group",
|
|
185
|
-
rowCount: 0,
|
|
186
|
-
},
|
|
187
|
-
],
|
|
188
|
-
},
|
|
189
|
-
];
|
|
190
|
-
|
|
191
|
-
const rows = getRows(groups, 40, 40, 40, 72, null);
|
|
192
|
-
|
|
193
|
-
const expected: GridRow[] = [
|
|
194
|
-
{
|
|
195
|
-
type: "group_heading",
|
|
196
|
-
height: 40,
|
|
197
|
-
y: 0,
|
|
198
|
-
groupPath: [0],
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
type: "group_summary",
|
|
202
|
-
height: 40,
|
|
203
|
-
y: 40,
|
|
204
|
-
groupPath: [0],
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
type: "group_heading",
|
|
208
|
-
height: 40,
|
|
209
|
-
y: 80,
|
|
210
|
-
groupPath: [0, 0],
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
type: "group_summary",
|
|
214
|
-
height: 40,
|
|
215
|
-
y: 120,
|
|
216
|
-
groupPath: [0, 0],
|
|
217
|
-
},
|
|
218
|
-
{ type: "spacer", height: 72, y: 160 },
|
|
219
|
-
];
|
|
220
|
-
|
|
221
|
-
expect(rows).toEqual(expected);
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
test("getRows - nested with collapsed ancestor", () => {
|
|
225
|
-
const groups: GridGroup[] = [
|
|
226
|
-
{
|
|
227
|
-
type: "group",
|
|
228
|
-
children: [
|
|
229
|
-
{
|
|
230
|
-
type: "row_group",
|
|
231
|
-
rowCount: 1,
|
|
232
|
-
},
|
|
233
|
-
],
|
|
234
|
-
},
|
|
235
|
-
];
|
|
236
|
-
|
|
237
|
-
const rows = getRows(groups, 40, 40, 40, 72, [groupPathToKey([0])]);
|
|
238
|
-
|
|
239
|
-
// Group summary is always shown even when collapsed
|
|
240
|
-
const expected: GridRow[] = [
|
|
241
|
-
{
|
|
242
|
-
type: "group_heading",
|
|
243
|
-
height: 40,
|
|
244
|
-
y: 0,
|
|
245
|
-
groupPath: [0],
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
type: "group_summary",
|
|
249
|
-
height: 40,
|
|
250
|
-
y: 40,
|
|
251
|
-
groupPath: [0],
|
|
252
|
-
},
|
|
253
|
-
{ type: "spacer", height: 72, y: 80 },
|
|
254
|
-
];
|
|
255
|
-
|
|
256
|
-
expect(rows).toEqual(expected);
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
test("getRows - nested collapsed child", () => {
|
|
260
|
-
const groups: GridGroup[] = [
|
|
261
|
-
{
|
|
262
|
-
type: "group",
|
|
263
|
-
children: [
|
|
264
|
-
{
|
|
265
|
-
type: "row_group",
|
|
266
|
-
rowCount: 5,
|
|
267
|
-
},
|
|
268
|
-
],
|
|
269
|
-
},
|
|
270
|
-
];
|
|
271
|
-
|
|
272
|
-
const rows = getRows(groups, 40, 40, 40, 72, [groupPathToKey([0, 0])]);
|
|
273
|
-
|
|
274
|
-
// Group summary is always shown even when collapsed
|
|
275
|
-
const expected: GridRow[] = [
|
|
276
|
-
{
|
|
277
|
-
type: "group_heading",
|
|
278
|
-
height: 40,
|
|
279
|
-
y: 0,
|
|
280
|
-
groupPath: [0],
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
type: "group_summary",
|
|
284
|
-
height: 40,
|
|
285
|
-
y: 40,
|
|
286
|
-
groupPath: [0],
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
type: "group_heading",
|
|
290
|
-
height: 40,
|
|
291
|
-
y: 80,
|
|
292
|
-
groupPath: [0, 0],
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
type: "group_summary",
|
|
296
|
-
height: 40,
|
|
297
|
-
y: 120,
|
|
298
|
-
groupPath: [0, 0],
|
|
299
|
-
},
|
|
300
|
-
{ type: "spacer", height: 72, y: 160 },
|
|
301
|
-
];
|
|
302
|
-
|
|
303
|
-
expect(rows).toEqual(expected);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
test("getColumns - with offset", () => {
|
|
307
|
-
const result = getColumns([100, 200, 100], 3);
|
|
308
|
-
|
|
309
|
-
const expected: GridColumn[] = [
|
|
310
|
-
{ column: 3, width: 100, x: 0 },
|
|
311
|
-
{ column: 4, width: 200, x: 100 },
|
|
312
|
-
{ column: 5, width: 100, x: 300 },
|
|
313
|
-
];
|
|
314
|
-
|
|
315
|
-
expect(result).toEqual(expected);
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
test("getColumns - empty columns", () => {
|
|
319
|
-
const result = getColumns([]);
|
|
320
|
-
|
|
321
|
-
expect(result).toEqual([]);
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
test("getColumns - single column", () => {
|
|
325
|
-
const result = getColumns([150]);
|
|
326
|
-
|
|
327
|
-
const expected: GridColumn[] = [{ column: 0, width: 150, x: 0 }];
|
|
328
|
-
|
|
329
|
-
expect(result).toEqual(expected);
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
test("getRows - multiple top-level groups", () => {
|
|
333
|
-
const groups: GridGroup[] = [
|
|
334
|
-
{ type: "row_group", rowCount: 1 },
|
|
335
|
-
{ type: "row_group", rowCount: 1 },
|
|
336
|
-
{ type: "row_group", rowCount: 1 },
|
|
337
|
-
];
|
|
338
|
-
|
|
339
|
-
const rows = getRows(groups, 40, 40, 40, 72, null);
|
|
340
|
-
|
|
341
|
-
expect(rows).toHaveLength(12); // 3 headings + 3 summaries + 3 rows + 3 spacers
|
|
342
|
-
expect(rows.filter((r) => r.type === "group_heading")).toHaveLength(3);
|
|
343
|
-
expect(rows.filter((r) => r.type === "group_summary")).toHaveLength(3);
|
|
344
|
-
expect(rows.filter((r) => r.type === "row")).toHaveLength(3);
|
|
345
|
-
expect(rows.filter((r) => r.type === "spacer")).toHaveLength(3);
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
test("getRows - deeply nested groups", () => {
|
|
349
|
-
const groups: GridGroup[] = [
|
|
350
|
-
{
|
|
351
|
-
type: "group",
|
|
352
|
-
children: [
|
|
353
|
-
{
|
|
354
|
-
type: "group",
|
|
355
|
-
children: [
|
|
356
|
-
{
|
|
357
|
-
type: "group",
|
|
358
|
-
children: [
|
|
359
|
-
{
|
|
360
|
-
type: "row_group",
|
|
361
|
-
rowCount: 1,
|
|
362
|
-
},
|
|
363
|
-
],
|
|
364
|
-
},
|
|
365
|
-
],
|
|
366
|
-
},
|
|
367
|
-
],
|
|
368
|
-
},
|
|
369
|
-
];
|
|
370
|
-
|
|
371
|
-
const rows = getRows(groups, 40, 40, 40, 72, null);
|
|
372
|
-
|
|
373
|
-
const expected: GridRow[] = [
|
|
374
|
-
{ type: "group_heading", height: 40, y: 0, groupPath: [0] },
|
|
375
|
-
{ type: "group_summary", height: 40, y: 40, groupPath: [0] },
|
|
376
|
-
{ type: "group_heading", height: 40, y: 80, groupPath: [0, 0] },
|
|
377
|
-
{ type: "group_summary", height: 40, y: 120, groupPath: [0, 0] },
|
|
378
|
-
{ type: "group_heading", height: 40, y: 160, groupPath: [0, 0, 0] },
|
|
379
|
-
{ type: "group_summary", height: 40, y: 200, groupPath: [0, 0, 0] },
|
|
380
|
-
{ type: "group_heading", height: 40, y: 240, groupPath: [0, 0, 0, 0] },
|
|
381
|
-
{ type: "group_summary", height: 40, y: 280, groupPath: [0, 0, 0, 0] },
|
|
382
|
-
{ type: "row", height: 40, y: 320, rowPath: [0, 0, 0, 0, 0] },
|
|
383
|
-
{ type: "spacer", height: 72, y: 360 },
|
|
384
|
-
];
|
|
385
|
-
|
|
386
|
-
expect(rows).toEqual(expected);
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
test("getRows - multiple collapsed groups", () => {
|
|
390
|
-
const groups: GridGroup[] = [
|
|
391
|
-
{
|
|
392
|
-
type: "group",
|
|
393
|
-
children: [{ type: "row_group", rowCount: 2 }],
|
|
394
|
-
},
|
|
395
|
-
{
|
|
396
|
-
type: "group",
|
|
397
|
-
children: [{ type: "row_group", rowCount: 2 }],
|
|
398
|
-
},
|
|
399
|
-
{
|
|
400
|
-
type: "group",
|
|
401
|
-
children: [{ type: "row_group", rowCount: 2 }],
|
|
402
|
-
},
|
|
403
|
-
];
|
|
404
|
-
|
|
405
|
-
const rows = getRows(groups, 40, 40, 40, 72, [groupPathToKey([0]), groupPathToKey([2])]);
|
|
406
|
-
|
|
407
|
-
// Groups 0 and 2 are collapsed, group 1 is expanded
|
|
408
|
-
// Group summary rows are always shown even when collapsed
|
|
409
|
-
expect(rows.filter((r) => r.type === "row")).toHaveLength(2); // Only from group 1
|
|
410
|
-
expect(rows.filter((r) => r.type === "group_heading")).toHaveLength(4); // [0], [1], [1,0], [2]
|
|
411
|
-
expect(rows.filter((r) => r.type === "group_summary")).toHaveLength(4); // [0], [1], [1,0], [2] (all groups have summaries)
|
|
412
|
-
expect(rows.filter((r) => r.type === "spacer")).toHaveLength(3);
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
test("getRows - empty groups array", () => {
|
|
416
|
-
const rows = getRows([], 40, 40, 40, 72, null);
|
|
417
|
-
|
|
418
|
-
expect(rows).toEqual([]);
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
test("getRows - default spacerHeight emits a spacer after each top-level group", () => {
|
|
422
|
-
const groups: GridGroup[] = [
|
|
423
|
-
{ type: "row_group", rowCount: 1 },
|
|
424
|
-
{ type: "row_group", rowCount: 1 },
|
|
425
|
-
];
|
|
426
|
-
|
|
427
|
-
const rows = getRows(groups, 40, 40, 40, 56, null);
|
|
428
|
-
|
|
429
|
-
const expected: GridRow[] = [
|
|
430
|
-
{ type: "group_heading", height: 40, y: 0, groupPath: [0] },
|
|
431
|
-
{ type: "group_summary", height: 40, y: 40, groupPath: [0] },
|
|
432
|
-
{ type: "row", height: 40, y: 80, rowPath: [0, 0] },
|
|
433
|
-
{ type: "spacer", height: 56, y: 120 },
|
|
434
|
-
{ type: "group_heading", height: 40, y: 176, groupPath: [1] },
|
|
435
|
-
{ type: "group_summary", height: 40, y: 216, groupPath: [1] },
|
|
436
|
-
{ type: "row", height: 40, y: 256, rowPath: [1, 0] },
|
|
437
|
-
{ type: "spacer", height: 56, y: 296 },
|
|
438
|
-
];
|
|
439
|
-
|
|
440
|
-
expect(rows).toEqual(expected);
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
test("getRows - spacerHeight 0 emits no spacer descriptor", () => {
|
|
444
|
-
const groups: GridGroup[] = [
|
|
445
|
-
{ type: "row_group", rowCount: 1 },
|
|
446
|
-
{ type: "row_group", rowCount: 1 },
|
|
447
|
-
];
|
|
448
|
-
|
|
449
|
-
const rows = getRows(groups, 40, 40, 40, 0, null);
|
|
450
|
-
|
|
451
|
-
const expected: GridRow[] = [
|
|
452
|
-
{ type: "group_heading", height: 40, y: 0, groupPath: [0] },
|
|
453
|
-
{ type: "group_summary", height: 40, y: 40, groupPath: [0] },
|
|
454
|
-
{ type: "row", height: 40, y: 80, rowPath: [0, 0] },
|
|
455
|
-
{ type: "group_heading", height: 40, y: 120, groupPath: [1] },
|
|
456
|
-
{ type: "group_summary", height: 40, y: 160, groupPath: [1] },
|
|
457
|
-
{ type: "row", height: 40, y: 200, rowPath: [1, 0] },
|
|
458
|
-
];
|
|
459
|
-
|
|
460
|
-
expect(rows).toEqual(expected);
|
|
461
|
-
expect(rows.some((r) => r.type === "spacer")).toBe(false);
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
test("getRows - spacerHeight 0 with collapsed, single, and zero groups", () => {
|
|
465
|
-
// Collapsed top-level group: heading + summary only, no spacer
|
|
466
|
-
const collapsed = getRows(
|
|
467
|
-
[{ type: "group", children: [{ type: "row_group", rowCount: 3 }] }],
|
|
468
|
-
40,
|
|
469
|
-
40,
|
|
470
|
-
40,
|
|
471
|
-
0,
|
|
472
|
-
[groupPathToKey([0])],
|
|
473
|
-
);
|
|
474
|
-
expect(collapsed).toEqual([
|
|
475
|
-
{ type: "group_heading", height: 40, y: 0, groupPath: [0] },
|
|
476
|
-
{ type: "group_summary", height: 40, y: 40, groupPath: [0] },
|
|
477
|
-
]);
|
|
478
|
-
|
|
479
|
-
// Single top-level group: no trailing spacer
|
|
480
|
-
const single = getRows([{ type: "row_group", rowCount: 2 }], 40, 40, 40, 0, null);
|
|
481
|
-
expect(single).toEqual([
|
|
482
|
-
{ type: "row", height: 40, y: 0, rowPath: [0, 0] },
|
|
483
|
-
{ type: "row", height: 40, y: 40, rowPath: [0, 1] },
|
|
484
|
-
]);
|
|
485
|
-
|
|
486
|
-
// Zero groups: empty layout
|
|
487
|
-
expect(getRows([], 40, 40, 40, 0, null)).toEqual([]);
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
test("getRows - collapsed parent hides all descendants", () => {
|
|
491
|
-
const groups: GridGroup[] = [
|
|
492
|
-
{
|
|
493
|
-
type: "group",
|
|
494
|
-
children: [
|
|
495
|
-
{
|
|
496
|
-
type: "group",
|
|
497
|
-
children: [
|
|
498
|
-
{
|
|
499
|
-
type: "row_group",
|
|
500
|
-
rowCount: 5,
|
|
501
|
-
},
|
|
502
|
-
],
|
|
503
|
-
},
|
|
504
|
-
],
|
|
505
|
-
},
|
|
506
|
-
];
|
|
507
|
-
|
|
508
|
-
const rows = getRows(groups, 40, 40, 40, 72, [groupPathToKey([0])]);
|
|
509
|
-
|
|
510
|
-
// Top-level group heading, summary (always shown), and spacer should appear
|
|
511
|
-
expect(rows).toHaveLength(3);
|
|
512
|
-
expect(rows[0].type).toBe("group_heading");
|
|
513
|
-
expect(rows[1].type).toBe("group_summary");
|
|
514
|
-
expect(rows[2].type).toBe("spacer");
|
|
515
|
-
});
|