@axinom/mosaic-ui 0.66.0-rc.13 → 0.66.0-rc.15
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/components/DynamicDataList/DynamicListHeader/DynamicListHeader.d.ts.map +1 -1
- package/dist/components/List/ListHeader/ColumnLabel/ColumnLabel.d.ts.map +1 -1
- package/dist/components/List/ListHeader/ListHeader.d.ts.map +1 -1
- package/dist/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/components/List/ListRow/ListRowCell/ListRowCell.d.ts +15 -0
- package/dist/components/List/ListRow/ListRowCell/ListRowCell.d.ts.map +1 -0
- package/dist/components/List/ListRow/ListRowCell/renderData.d.ts +9 -0
- package/dist/components/List/ListRow/ListRowCell/renderData.d.ts.map +1 -0
- package/dist/components/List/ListRow/Renderers/TagsRenderer/TagsRenderer.d.ts.map +1 -1
- package/dist/components/Utils/Postgraphile/CreateConnectionRenderer.d.ts +1 -1
- package/dist/components/Utils/Postgraphile/CreateConnectionRenderer.d.ts.map +1 -1
- package/dist/helpers/idleCallbackHelpers.d.ts +42 -0
- package/dist/helpers/idleCallbackHelpers.d.ts.map +1 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.d.ts.map +1 -1
- package/dist/hooks/useResize/useResize.d.ts +3 -0
- package/dist/hooks/useResize/useResize.d.ts.map +1 -1
- package/dist/index.es.js +4 -4
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/DynamicDataList/DynamicDataList.scss +1 -0
- package/src/components/DynamicDataList/DynamicListHeader/DynamicListHeader.scss +10 -0
- package/src/components/DynamicDataList/DynamicListHeader/DynamicListHeader.spec.tsx +2 -0
- package/src/components/DynamicDataList/DynamicListHeader/DynamicListHeader.tsx +65 -49
- package/src/components/List/List.scss +1 -0
- package/src/components/List/ListHeader/ColumnLabel/ColumnLabel.spec.tsx +4 -4
- package/src/components/List/ListHeader/ColumnLabel/ColumnLabel.tsx +5 -1
- package/src/components/List/ListHeader/ListHeader.scss +10 -1
- package/src/components/List/ListHeader/ListHeader.spec.tsx +2 -0
- package/src/components/List/ListHeader/ListHeader.tsx +60 -50
- package/src/components/List/ListRow/ListRow.scss +0 -27
- package/src/components/List/ListRow/ListRow.spec.tsx +10 -8
- package/src/components/List/ListRow/ListRow.tsx +20 -152
- package/src/components/List/ListRow/ListRowCell/ListRowCell.scss +26 -0
- package/src/components/List/ListRow/ListRowCell/ListRowCell.spec.tsx +491 -0
- package/src/components/List/ListRow/ListRowCell/ListRowCell.tsx +57 -0
- package/src/components/List/ListRow/ListRowCell/renderData.tsx +124 -0
- package/src/components/List/ListRow/Renderers/TagsRenderer/TagsRenderer.spec.tsx +191 -80
- package/src/components/List/ListRow/Renderers/TagsRenderer/TagsRenderer.tsx +63 -34
- package/src/components/Utils/Postgraphile/CreateConnectionRenderer.spec.ts +48 -12
- package/src/components/Utils/Postgraphile/CreateConnectionRenderer.tsx +5 -4
- package/src/helpers/idleCallbackHelpers.ts +66 -0
- package/src/helpers/index.ts +5 -0
- package/src/hooks/useResize/useResize.ts +36 -4
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import { mount, shallow } from 'enzyme';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Column } from '../..';
|
|
4
|
+
import { Data } from '../../../..';
|
|
5
|
+
import { ListRowCell } from './ListRowCell';
|
|
6
|
+
|
|
7
|
+
interface TestData extends Data {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
age: number;
|
|
11
|
+
date: Date;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const mockData: TestData = {
|
|
15
|
+
id: '123',
|
|
16
|
+
name: 'Test User',
|
|
17
|
+
age: 30,
|
|
18
|
+
date: new Date('2023-01-15T10:30:00'),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const dateFormatter = new Intl.DateTimeFormat('en-US', {
|
|
22
|
+
year: 'numeric',
|
|
23
|
+
month: 'numeric',
|
|
24
|
+
day: 'numeric',
|
|
25
|
+
hour: 'numeric',
|
|
26
|
+
minute: 'numeric',
|
|
27
|
+
second: 'numeric',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const numberFormatter = new Intl.NumberFormat('en-US');
|
|
31
|
+
|
|
32
|
+
describe('ListRowCell', () => {
|
|
33
|
+
it('renders the component without crashing', () => {
|
|
34
|
+
const column: Column<TestData> = {
|
|
35
|
+
propertyName: 'name',
|
|
36
|
+
label: 'Name',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const wrapper = shallow(
|
|
40
|
+
<ListRowCell
|
|
41
|
+
column={column}
|
|
42
|
+
data={mockData}
|
|
43
|
+
dateFormatter={dateFormatter}
|
|
44
|
+
numberFormatter={numberFormatter}
|
|
45
|
+
/>,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(wrapper).toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('renders a string value correctly', () => {
|
|
52
|
+
const column: Column<TestData> = {
|
|
53
|
+
propertyName: 'name',
|
|
54
|
+
label: 'Name',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const wrapper = mount(
|
|
58
|
+
<ListRowCell
|
|
59
|
+
column={column}
|
|
60
|
+
data={mockData}
|
|
61
|
+
dateFormatter={dateFormatter}
|
|
62
|
+
numberFormatter={numberFormatter}
|
|
63
|
+
/>,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
expect(wrapper.text()).toBe('Test User');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('renders a number value with number formatter', () => {
|
|
70
|
+
const column: Column<TestData> = {
|
|
71
|
+
propertyName: 'age',
|
|
72
|
+
label: 'Age',
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const wrapper = mount(
|
|
76
|
+
<ListRowCell
|
|
77
|
+
column={column}
|
|
78
|
+
data={mockData}
|
|
79
|
+
dateFormatter={dateFormatter}
|
|
80
|
+
numberFormatter={numberFormatter}
|
|
81
|
+
/>,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(wrapper.text()).toBe(numberFormatter.format(30));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('renders a date value with date formatter', () => {
|
|
88
|
+
const column: Column<TestData> = {
|
|
89
|
+
propertyName: 'date',
|
|
90
|
+
label: 'Date',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const wrapper = mount(
|
|
94
|
+
<ListRowCell
|
|
95
|
+
column={column}
|
|
96
|
+
data={mockData}
|
|
97
|
+
dateFormatter={dateFormatter}
|
|
98
|
+
numberFormatter={numberFormatter}
|
|
99
|
+
/>,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
expect(wrapper.text()).toBe(dateFormatter.format(mockData.date));
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('uses custom renderer when provided', () => {
|
|
106
|
+
const column: Column<TestData> = {
|
|
107
|
+
propertyName: 'name',
|
|
108
|
+
label: 'Name',
|
|
109
|
+
render: (value) => `Custom: ${value}`,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const wrapper = mount(
|
|
113
|
+
<ListRowCell
|
|
114
|
+
column={column}
|
|
115
|
+
data={mockData}
|
|
116
|
+
dateFormatter={dateFormatter}
|
|
117
|
+
numberFormatter={numberFormatter}
|
|
118
|
+
/>,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
expect(wrapper.text()).toBe('Custom: Test User');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('handles null values', () => {
|
|
125
|
+
const nullData = { ...mockData, name: null as unknown as string };
|
|
126
|
+
const column: Column<TestData> = {
|
|
127
|
+
propertyName: 'name',
|
|
128
|
+
label: 'Name',
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const wrapper = mount(
|
|
132
|
+
<ListRowCell
|
|
133
|
+
column={column}
|
|
134
|
+
data={nullData}
|
|
135
|
+
dateFormatter={dateFormatter}
|
|
136
|
+
numberFormatter={numberFormatter}
|
|
137
|
+
/>,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
expect(wrapper.text()).toBe('');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('handles undefined values', () => {
|
|
144
|
+
const undefinedData = { ...mockData, name: undefined as unknown as string };
|
|
145
|
+
const column: Column<TestData> = {
|
|
146
|
+
propertyName: 'name',
|
|
147
|
+
label: 'Name',
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const wrapper = mount(
|
|
151
|
+
<ListRowCell
|
|
152
|
+
column={column}
|
|
153
|
+
data={undefinedData}
|
|
154
|
+
dateFormatter={dateFormatter}
|
|
155
|
+
numberFormatter={numberFormatter}
|
|
156
|
+
/>,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
expect(wrapper.text()).toBe('');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('renders tooltip with column text by default', () => {
|
|
163
|
+
const column: Column<TestData> = {
|
|
164
|
+
propertyName: 'name',
|
|
165
|
+
label: 'Name',
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const wrapper = mount(
|
|
169
|
+
<ListRowCell
|
|
170
|
+
column={column}
|
|
171
|
+
data={mockData}
|
|
172
|
+
dateFormatter={dateFormatter}
|
|
173
|
+
numberFormatter={numberFormatter}
|
|
174
|
+
/>,
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const cell = wrapper.find('.cell');
|
|
178
|
+
expect(cell.prop('title')).toBe('Test User');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('does not render tooltip when column.tooltip is false', () => {
|
|
182
|
+
const column: Column<TestData> = {
|
|
183
|
+
propertyName: 'name',
|
|
184
|
+
label: 'Name',
|
|
185
|
+
tooltip: false,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const wrapper = mount(
|
|
189
|
+
<ListRowCell
|
|
190
|
+
column={column}
|
|
191
|
+
data={mockData}
|
|
192
|
+
dateFormatter={dateFormatter}
|
|
193
|
+
numberFormatter={numberFormatter}
|
|
194
|
+
/>,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const cell = wrapper.find('.cell');
|
|
198
|
+
expect(cell.prop('title')).toBeUndefined();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('text alignment', () => {
|
|
202
|
+
it('applies default horizontal text alignment (left)', () => {
|
|
203
|
+
const column: Column<TestData> = {
|
|
204
|
+
propertyName: 'name',
|
|
205
|
+
label: 'Name',
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const wrapper = mount(
|
|
209
|
+
<ListRowCell
|
|
210
|
+
column={column}
|
|
211
|
+
data={mockData}
|
|
212
|
+
dateFormatter={dateFormatter}
|
|
213
|
+
numberFormatter={numberFormatter}
|
|
214
|
+
/>,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const cell = wrapper.find('.cell');
|
|
218
|
+
expect(cell.prop('style')).toHaveProperty('textAlign', 'left');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('applies custom horizontal text alignment', () => {
|
|
222
|
+
const column: Column<TestData> = {
|
|
223
|
+
propertyName: 'name',
|
|
224
|
+
label: 'Name',
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const wrapper = mount(
|
|
228
|
+
<ListRowCell
|
|
229
|
+
column={column}
|
|
230
|
+
data={mockData}
|
|
231
|
+
horizontalTextAlign="right"
|
|
232
|
+
dateFormatter={dateFormatter}
|
|
233
|
+
numberFormatter={numberFormatter}
|
|
234
|
+
/>,
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const cell = wrapper.find('.cell');
|
|
238
|
+
expect(cell.prop('style')).toHaveProperty('textAlign', 'right');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('applies default vertical text alignment (center)', () => {
|
|
242
|
+
const column: Column<TestData> = {
|
|
243
|
+
propertyName: 'name',
|
|
244
|
+
label: 'Name',
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const wrapper = mount(
|
|
248
|
+
<ListRowCell
|
|
249
|
+
column={column}
|
|
250
|
+
data={mockData}
|
|
251
|
+
dateFormatter={dateFormatter}
|
|
252
|
+
numberFormatter={numberFormatter}
|
|
253
|
+
/>,
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
const cell = wrapper.find('.cell');
|
|
257
|
+
expect(cell.prop('style')).toHaveProperty('alignSelf', 'center');
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('applies custom vertical text alignment', () => {
|
|
261
|
+
const column: Column<TestData> = {
|
|
262
|
+
propertyName: 'name',
|
|
263
|
+
label: 'Name',
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const wrapper = mount(
|
|
267
|
+
<ListRowCell
|
|
268
|
+
column={column}
|
|
269
|
+
data={mockData}
|
|
270
|
+
verticalTextAlign="start"
|
|
271
|
+
dateFormatter={dateFormatter}
|
|
272
|
+
numberFormatter={numberFormatter}
|
|
273
|
+
/>,
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const cell = wrapper.find('.cell');
|
|
277
|
+
expect(cell.prop('style')).toHaveProperty('alignSelf', 'start');
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('applies horizontal column alignment from column config', () => {
|
|
281
|
+
const column: Column<TestData> = {
|
|
282
|
+
propertyName: 'name',
|
|
283
|
+
label: 'Name',
|
|
284
|
+
horizontalColumnAlign: 'right',
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const wrapper = mount(
|
|
288
|
+
<ListRowCell
|
|
289
|
+
column={column}
|
|
290
|
+
data={mockData}
|
|
291
|
+
dateFormatter={dateFormatter}
|
|
292
|
+
numberFormatter={numberFormatter}
|
|
293
|
+
/>,
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const cell = wrapper.find('.cell');
|
|
297
|
+
expect(cell.prop('style')).toHaveProperty('justifySelf', 'right');
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
describe('text wrapping', () => {
|
|
302
|
+
it('applies nowrap class by default (textWrap = false)', () => {
|
|
303
|
+
const column: Column<TestData> = {
|
|
304
|
+
propertyName: 'name',
|
|
305
|
+
label: 'Name',
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const wrapper = mount(
|
|
309
|
+
<ListRowCell
|
|
310
|
+
column={column}
|
|
311
|
+
data={mockData}
|
|
312
|
+
dateFormatter={dateFormatter}
|
|
313
|
+
numberFormatter={numberFormatter}
|
|
314
|
+
/>,
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
const cell = wrapper.find('.cell');
|
|
318
|
+
expect(cell.hasClass('nowrap')).toBe(true);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('does not apply nowrap class when textWrap is true', () => {
|
|
322
|
+
const column: Column<TestData> = {
|
|
323
|
+
propertyName: 'name',
|
|
324
|
+
label: 'Name',
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const wrapper = mount(
|
|
328
|
+
<ListRowCell
|
|
329
|
+
column={column}
|
|
330
|
+
data={mockData}
|
|
331
|
+
textWrap={true}
|
|
332
|
+
dateFormatter={dateFormatter}
|
|
333
|
+
numberFormatter={numberFormatter}
|
|
334
|
+
/>,
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
const cell = wrapper.find('.cell');
|
|
338
|
+
expect(cell.hasClass('nowrap')).toBe(false);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
describe('data-test-id', () => {
|
|
343
|
+
it('sets data-test-id based on propertyName when render returns a string', () => {
|
|
344
|
+
const column: Column<TestData> = {
|
|
345
|
+
propertyName: 'name',
|
|
346
|
+
label: 'Name',
|
|
347
|
+
render: (value) => `Custom: ${value}`,
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const wrapper = mount(
|
|
351
|
+
<ListRowCell
|
|
352
|
+
column={column}
|
|
353
|
+
data={mockData}
|
|
354
|
+
dateFormatter={dateFormatter}
|
|
355
|
+
numberFormatter={numberFormatter}
|
|
356
|
+
/>,
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
const cell = wrapper.find('.cell');
|
|
360
|
+
expect(cell.prop('data-test-id')).toBeNull();
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('sets data-test-id on inner span for standard values', () => {
|
|
364
|
+
const column: Column<TestData> = {
|
|
365
|
+
propertyName: 'name',
|
|
366
|
+
label: 'Name',
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const wrapper = mount(
|
|
370
|
+
<ListRowCell
|
|
371
|
+
column={column}
|
|
372
|
+
data={mockData}
|
|
373
|
+
dateFormatter={dateFormatter}
|
|
374
|
+
numberFormatter={numberFormatter}
|
|
375
|
+
/>,
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
// For standard values, data-test-id is on the inner span, not the cell div
|
|
379
|
+
const cell = wrapper.find('.cell');
|
|
380
|
+
expect(cell.prop('data-test-id')).toBeNull();
|
|
381
|
+
|
|
382
|
+
// Check that the span inside has the data-test-id
|
|
383
|
+
const span = wrapper.find(
|
|
384
|
+
'span[data-test-id="list-entry-property:name"]',
|
|
385
|
+
);
|
|
386
|
+
expect(span).toHaveLength(1);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it('sets data-test-id on cell when custom renderer returns JSX', () => {
|
|
390
|
+
const column: Column<TestData> = {
|
|
391
|
+
propertyName: 'name',
|
|
392
|
+
label: 'Name',
|
|
393
|
+
render: (value) => <div className="custom-render">{value}</div>,
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
const wrapper = mount(
|
|
397
|
+
<ListRowCell
|
|
398
|
+
column={column}
|
|
399
|
+
data={mockData}
|
|
400
|
+
dateFormatter={dateFormatter}
|
|
401
|
+
numberFormatter={numberFormatter}
|
|
402
|
+
/>,
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
// For custom JSX renderers, data-test-id is on the cell div
|
|
406
|
+
const cell = wrapper.find('.cell');
|
|
407
|
+
expect(cell.prop('data-test-id')).toBe('list-entry-property:name');
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
describe('column key handling', () => {
|
|
412
|
+
it('uses propertyName as key when key is not provided', () => {
|
|
413
|
+
const column: Column<TestData> = {
|
|
414
|
+
propertyName: 'name',
|
|
415
|
+
label: 'Name',
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
const wrapper = shallow(
|
|
419
|
+
<ListRowCell
|
|
420
|
+
column={column}
|
|
421
|
+
data={mockData}
|
|
422
|
+
dateFormatter={dateFormatter}
|
|
423
|
+
numberFormatter={numberFormatter}
|
|
424
|
+
/>,
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
const cellWrapper = wrapper.find('.cellWrapper');
|
|
428
|
+
expect(cellWrapper.key()).toBe('name');
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('uses custom key when provided', () => {
|
|
432
|
+
const column: Column<TestData> = {
|
|
433
|
+
propertyName: 'name',
|
|
434
|
+
label: 'Name',
|
|
435
|
+
key: 'custom-key',
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
const wrapper = shallow(
|
|
439
|
+
<ListRowCell
|
|
440
|
+
column={column}
|
|
441
|
+
data={mockData}
|
|
442
|
+
dateFormatter={dateFormatter}
|
|
443
|
+
numberFormatter={numberFormatter}
|
|
444
|
+
/>,
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
const cellWrapper = wrapper.find('.cellWrapper');
|
|
448
|
+
expect(cellWrapper.key()).toBe('custom-key');
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
describe('unbound columns (no propertyName)', () => {
|
|
453
|
+
it('renders custom renderer for unbound column', () => {
|
|
454
|
+
const column: Column<TestData> = {
|
|
455
|
+
key: 'actions',
|
|
456
|
+
label: 'Actions',
|
|
457
|
+
render: (_value, data) => <button>Edit {data.name}</button>,
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
const wrapper = mount(
|
|
461
|
+
<ListRowCell
|
|
462
|
+
column={column}
|
|
463
|
+
data={mockData}
|
|
464
|
+
dateFormatter={dateFormatter}
|
|
465
|
+
numberFormatter={numberFormatter}
|
|
466
|
+
/>,
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
expect(wrapper.find('button').text()).toBe('Edit Test User');
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it('handles unbound column with string render result', () => {
|
|
473
|
+
const column: Column<TestData> = {
|
|
474
|
+
key: 'status',
|
|
475
|
+
label: 'Status',
|
|
476
|
+
render: () => 'Active',
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const wrapper = mount(
|
|
480
|
+
<ListRowCell
|
|
481
|
+
column={column}
|
|
482
|
+
data={mockData}
|
|
483
|
+
dateFormatter={dateFormatter}
|
|
484
|
+
numberFormatter={numberFormatter}
|
|
485
|
+
/>,
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
expect(wrapper.text()).toBe('Active');
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import type { Data } from '../../../../types/data';
|
|
4
|
+
import type { Column } from '../../List.model';
|
|
5
|
+
import classes from './ListRowCell.scss';
|
|
6
|
+
import { renderData } from './renderData';
|
|
7
|
+
|
|
8
|
+
interface ListRowCellProps<T extends Data> {
|
|
9
|
+
column: Column<T>;
|
|
10
|
+
data: T;
|
|
11
|
+
horizontalTextAlign?: 'left' | 'right' | 'center';
|
|
12
|
+
verticalTextAlign?: 'start' | 'center' | 'end';
|
|
13
|
+
textWrap?: boolean;
|
|
14
|
+
dateFormatter: Intl.DateTimeFormat;
|
|
15
|
+
numberFormatter: Intl.NumberFormat;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const ListRowCell = <T extends Data>({
|
|
19
|
+
column,
|
|
20
|
+
data,
|
|
21
|
+
horizontalTextAlign = 'left',
|
|
22
|
+
verticalTextAlign = 'center',
|
|
23
|
+
textWrap = false,
|
|
24
|
+
dateFormatter,
|
|
25
|
+
numberFormatter,
|
|
26
|
+
}: ListRowCellProps<T>): JSX.Element => {
|
|
27
|
+
const { columnData, tooltip, isDataTestIdSet } = renderData<T>(
|
|
28
|
+
column,
|
|
29
|
+
data,
|
|
30
|
+
dateFormatter,
|
|
31
|
+
numberFormatter,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
key={column.key ?? (column.propertyName as string)}
|
|
37
|
+
className={classes.cellWrapper}
|
|
38
|
+
>
|
|
39
|
+
<div
|
|
40
|
+
className={clsx(classes.cell, { [classes.nowrap]: !textWrap })}
|
|
41
|
+
title={tooltip}
|
|
42
|
+
style={{
|
|
43
|
+
justifySelf: column.horizontalColumnAlign, // Horizontal alignment based on column config
|
|
44
|
+
alignSelf: verticalTextAlign, // Vertical alignment based on props
|
|
45
|
+
textAlign: horizontalTextAlign, // Additional text alignment inside the cell
|
|
46
|
+
}}
|
|
47
|
+
data-test-id={
|
|
48
|
+
isDataTestIdSet
|
|
49
|
+
? null
|
|
50
|
+
: `list-entry-property:${column.propertyName as string}`
|
|
51
|
+
}
|
|
52
|
+
>
|
|
53
|
+
{columnData}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Data } from '../../../../types';
|
|
3
|
+
import { getTooltipText } from '../../../../utils/ToolTipHelpers';
|
|
4
|
+
import { Column } from '../../List.model';
|
|
5
|
+
|
|
6
|
+
export const renderData = <T extends Data>(
|
|
7
|
+
column: Column<T>,
|
|
8
|
+
rowData: T,
|
|
9
|
+
dateFormatter: Intl.DateTimeFormat,
|
|
10
|
+
numberFormatter: Intl.NumberFormat,
|
|
11
|
+
): {
|
|
12
|
+
columnData: React.ReactNode;
|
|
13
|
+
tooltip: string | undefined;
|
|
14
|
+
isDataTestIdSet: boolean;
|
|
15
|
+
} => {
|
|
16
|
+
const getTooltip = (value: unknown): string | undefined =>
|
|
17
|
+
column.tooltip !== false ? getTooltipText(value) : undefined;
|
|
18
|
+
|
|
19
|
+
if (!column.propertyName) {
|
|
20
|
+
const columnData = column.render?.(undefined, rowData);
|
|
21
|
+
|
|
22
|
+
if (typeof columnData === 'string') {
|
|
23
|
+
return {
|
|
24
|
+
columnData: (
|
|
25
|
+
<span
|
|
26
|
+
data-test-id={`list-entry-property:${
|
|
27
|
+
column.propertyName as string
|
|
28
|
+
}`}
|
|
29
|
+
>
|
|
30
|
+
{columnData}
|
|
31
|
+
</span>
|
|
32
|
+
),
|
|
33
|
+
isDataTestIdSet: true,
|
|
34
|
+
tooltip: getTooltip(columnData),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
columnData,
|
|
40
|
+
tooltip: getTooltip(columnData),
|
|
41
|
+
isDataTestIdSet: false,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const value: unknown = rowData[column.propertyName];
|
|
45
|
+
if (column.render) {
|
|
46
|
+
const columnData = column.render(value, rowData);
|
|
47
|
+
|
|
48
|
+
if (typeof columnData === 'string') {
|
|
49
|
+
return {
|
|
50
|
+
columnData: (
|
|
51
|
+
<span
|
|
52
|
+
data-test-id={`list-entry-property:${
|
|
53
|
+
column.propertyName as string
|
|
54
|
+
}`}
|
|
55
|
+
>
|
|
56
|
+
{columnData}
|
|
57
|
+
</span>
|
|
58
|
+
),
|
|
59
|
+
isDataTestIdSet: true,
|
|
60
|
+
tooltip: getTooltip(columnData),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
columnData,
|
|
66
|
+
tooltip: getTooltip(columnData),
|
|
67
|
+
isDataTestIdSet: false,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (value === null || value === undefined) {
|
|
72
|
+
return {
|
|
73
|
+
columnData: (
|
|
74
|
+
<span
|
|
75
|
+
data-test-id={`list-entry-property:${column.propertyName as string}`}
|
|
76
|
+
/>
|
|
77
|
+
),
|
|
78
|
+
tooltip: undefined,
|
|
79
|
+
isDataTestIdSet: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (typeof value === 'number') {
|
|
84
|
+
const columnData = numberFormatter.format(value);
|
|
85
|
+
return {
|
|
86
|
+
columnData: (
|
|
87
|
+
<span
|
|
88
|
+
data-test-id={`list-entry-property:${column.propertyName as string}`}
|
|
89
|
+
>
|
|
90
|
+
{columnData}
|
|
91
|
+
</span>
|
|
92
|
+
),
|
|
93
|
+
tooltip: getTooltip(columnData),
|
|
94
|
+
isDataTestIdSet: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (value instanceof Date) {
|
|
99
|
+
const columnData = dateFormatter.format(value);
|
|
100
|
+
return {
|
|
101
|
+
columnData: (
|
|
102
|
+
<span
|
|
103
|
+
data-test-id={`list-entry-property:${column.propertyName as string}`}
|
|
104
|
+
>
|
|
105
|
+
{columnData}
|
|
106
|
+
</span>
|
|
107
|
+
),
|
|
108
|
+
tooltip: getTooltip(columnData),
|
|
109
|
+
isDataTestIdSet: true,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
columnData: (
|
|
115
|
+
<span
|
|
116
|
+
data-test-id={`list-entry-property:${column.propertyName as string}`}
|
|
117
|
+
>
|
|
118
|
+
{String(value)}
|
|
119
|
+
</span>
|
|
120
|
+
),
|
|
121
|
+
tooltip: getTooltip(String(value)),
|
|
122
|
+
isDataTestIdSet: true,
|
|
123
|
+
};
|
|
124
|
+
};
|