@axinom/mosaic-ui 0.49.0-rc.9 → 0.49.1
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/DynamicDataList.d.ts +3 -1
- package/dist/components/DynamicDataList/DynamicDataList.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListRow/DynamicListRow.d.ts +3 -1
- package/dist/components/DynamicDataList/DynamicListRow/DynamicListRow.d.ts.map +1 -1
- package/dist/components/EmptyStation/EmptyStation.d.ts +1 -1
- package/dist/components/EmptyStation/EmptyStation.d.ts.map +1 -1
- package/dist/components/Explorer/Explorer.d.ts +2 -0
- package/dist/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/components/List/List.d.ts +2 -0
- package/dist/components/List/List.d.ts.map +1 -1
- package/dist/components/List/ListRow/ListRow.d.ts +4 -2
- package/dist/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/components/List/ListRow/ListRowLoader.d.ts +1 -1
- package/dist/components/List/ListRow/ListRowLoader.d.ts.map +1 -1
- package/dist/index.es.js +5 -4
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/DynamicDataList/DynamicDataList.stories.tsx +2 -1
- package/src/components/DynamicDataList/DynamicDataList.tsx +4 -0
- package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.scss +11 -5
- package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.spec.tsx +37 -0
- package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.tsx +23 -14
- package/src/components/EmptyStation/EmptyStation.stories.tsx +12 -21
- package/src/components/EmptyStation/EmptyStation.tsx +1 -1
- package/src/components/Explorer/Explorer.stories.tsx +1 -0
- package/src/components/Explorer/Explorer.tsx +5 -0
- package/src/components/List/List.stories.tsx +2 -1
- package/src/components/List/List.tsx +5 -1
- package/src/components/List/ListRow/ListRow.scss +11 -4
- package/src/components/List/ListRow/ListRow.spec.tsx +33 -0
- package/src/components/List/ListRow/ListRow.tsx +69 -18
- package/src/components/List/ListRow/ListRowLoader.tsx +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-ui",
|
|
3
|
-
"version": "0.49.
|
|
3
|
+
"version": "0.49.1",
|
|
4
4
|
"description": "UI components for building Axinom Mosaic applications",
|
|
5
5
|
"author": "Axinom",
|
|
6
6
|
"license": "PROPRIETARY",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"build-storybook": "storybook build"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@axinom/mosaic-core": "^0.4.22
|
|
35
|
+
"@axinom/mosaic-core": "^0.4.22",
|
|
36
36
|
"@faker-js/faker": "^7.4.0",
|
|
37
37
|
"@popperjs/core": "^2.11.8",
|
|
38
38
|
"clsx": "^1.1.0",
|
|
@@ -105,5 +105,5 @@
|
|
|
105
105
|
"publishConfig": {
|
|
106
106
|
"access": "public"
|
|
107
107
|
},
|
|
108
|
-
"gitHead": "
|
|
108
|
+
"gitHead": "57b0efd7943d6a3f8bfb0d3cc33417e5be5b2171"
|
|
109
109
|
}
|
|
@@ -44,7 +44,7 @@ const generateData = (amount: number): DynamicListStoryData[] =>
|
|
|
44
44
|
position: amount - index, // Position and ID is jumbled for demonstration purposes
|
|
45
45
|
id: index,
|
|
46
46
|
desc: `Description ${index}: ${faker.lorem.words(
|
|
47
|
-
faker.datatype.number({ min: 10, max:
|
|
47
|
+
faker.datatype.number({ min: 10, max: 50 }),
|
|
48
48
|
)}`,
|
|
49
49
|
title: `Item ${index}: ${faker.random.words(
|
|
50
50
|
faker.datatype.number({ min: 1, max: 3 }),
|
|
@@ -87,6 +87,7 @@ const groups = createGroups({
|
|
|
87
87
|
'headerRowActionSize',
|
|
88
88
|
'horizontalTextAlign',
|
|
89
89
|
'verticalTextAlign',
|
|
90
|
+
'textWrap',
|
|
90
91
|
'rowClassNameProvider',
|
|
91
92
|
],
|
|
92
93
|
});
|
|
@@ -53,6 +53,8 @@ export interface DynamicDataListProps<T extends Data> {
|
|
|
53
53
|
horizontalTextAlign?: 'left' | 'right' | 'center';
|
|
54
54
|
/** Vertical alignment of text */
|
|
55
55
|
verticalTextAlign?: 'start' | 'center' | 'end';
|
|
56
|
+
/** If set to true, column text overflow will be wrapped to a new line. Otherwise, it will be truncated with an ellipsis (default: false) */
|
|
57
|
+
textWrap?: boolean;
|
|
56
58
|
/** Property that contains the value used in reordering the list (default: undefined) */
|
|
57
59
|
positionPropertyName?: keyof T;
|
|
58
60
|
/** If sets, sets the label for the position column (default: 'Position') */
|
|
@@ -127,6 +129,7 @@ export const DynamicDataList = <T extends Data>({
|
|
|
127
129
|
stickyHeader = true,
|
|
128
130
|
disabled = false,
|
|
129
131
|
className = '',
|
|
132
|
+
textWrap = false,
|
|
130
133
|
onChange = noop,
|
|
131
134
|
onAddTransformData = (data) => data as T,
|
|
132
135
|
rowClassNameProvider,
|
|
@@ -233,6 +236,7 @@ export const DynamicDataList = <T extends Data>({
|
|
|
233
236
|
actionSize={listRowActionSize}
|
|
234
237
|
horizontalTextAlign={horizontalTextAlign}
|
|
235
238
|
verticalTextAlign={verticalTextAlign}
|
|
239
|
+
textWrap={textWrap}
|
|
236
240
|
allowRemove={allowNewData}
|
|
237
241
|
positionKey={positionPropertyName}
|
|
238
242
|
allowDragging={allowRowDragging}
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
display: grid;
|
|
11
11
|
padding: 1px 0px 1px 0px;
|
|
12
|
-
grid-auto-rows: var(--dynamic-list-row-height, $dynamic-list-row-height);
|
|
13
12
|
column-gap: var(--dynamic-list-column-gap, $dynamic-list-column-gap);
|
|
14
13
|
|
|
15
14
|
border-bottom: var(--dynamic-list-row-border, $dynamic-list-row-border);
|
|
@@ -26,7 +25,7 @@
|
|
|
26
25
|
align-items: center;
|
|
27
26
|
|
|
28
27
|
.wrapper {
|
|
29
|
-
min-height:
|
|
28
|
+
min-height: var(--dynamic-list-row-height, $dynamic-list-row-height);
|
|
30
29
|
min-width: 100%;
|
|
31
30
|
display: grid;
|
|
32
31
|
align-items: center;
|
|
@@ -41,9 +40,16 @@
|
|
|
41
40
|
max-width: 100%;
|
|
42
41
|
max-height: 100%;
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
span {
|
|
44
|
+
padding: 5px 0;
|
|
45
|
+
display: grid;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&.nowrap {
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
text-overflow: ellipsis;
|
|
51
|
+
overflow: hidden;
|
|
52
|
+
}
|
|
47
53
|
}
|
|
48
54
|
|
|
49
55
|
.position,
|
|
@@ -407,6 +407,43 @@ describe('DynamicListRow', () => {
|
|
|
407
407
|
expect(input.prop('value')).toBe(dataWithPosition.position);
|
|
408
408
|
});
|
|
409
409
|
|
|
410
|
+
describe('DynamicListRow column text alignments', () => {
|
|
411
|
+
const alignments: {
|
|
412
|
+
horizontal: 'left' | 'right' | 'center' | undefined;
|
|
413
|
+
vertical: 'center' | 'start' | 'end' | undefined;
|
|
414
|
+
}[] = [
|
|
415
|
+
{ horizontal: 'center', vertical: 'center' },
|
|
416
|
+
{ horizontal: 'left', vertical: 'start' },
|
|
417
|
+
{ horizontal: 'right', vertical: 'end' },
|
|
418
|
+
{ horizontal: undefined, vertical: undefined },
|
|
419
|
+
];
|
|
420
|
+
|
|
421
|
+
alignments.forEach(({ horizontal, vertical }) => {
|
|
422
|
+
it(`should apply the correct styles for justify-content: ${horizontal}, align-items: ${vertical}`, () => {
|
|
423
|
+
const wrapper = mount(
|
|
424
|
+
<DynamicListRow
|
|
425
|
+
columns={defaultColumns}
|
|
426
|
+
columnSizes={defaultProps.columnSizes}
|
|
427
|
+
data={dataWithPosition}
|
|
428
|
+
positionKey={'position'}
|
|
429
|
+
showPositionColumn={true}
|
|
430
|
+
horizontalTextAlign={horizontal}
|
|
431
|
+
verticalTextAlign={vertical}
|
|
432
|
+
/>,
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
const wrapperDivs = wrapper.find('.wrapper');
|
|
436
|
+
|
|
437
|
+
wrapperDivs.forEach((node) => {
|
|
438
|
+
const style = node.prop('style');
|
|
439
|
+
|
|
440
|
+
expect(style).toHaveProperty('justifyContent', horizontal);
|
|
441
|
+
expect(style).toHaveProperty('alignItems', vertical);
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
|
|
410
447
|
describe('tooltip', () => {
|
|
411
448
|
it(`renders a tooltip using the 'title' html attribute by default`, () => {
|
|
412
449
|
const wrapper = shallow(
|
|
@@ -28,6 +28,8 @@ export interface DynamicListRowProps<T extends Data> {
|
|
|
28
28
|
horizontalTextAlign?: 'left' | 'right' | 'center';
|
|
29
29
|
/** Vertical alignment of text */
|
|
30
30
|
verticalTextAlign?: 'start' | 'center' | 'end';
|
|
31
|
+
/** If set to true, column text overflow will be wrapped to a new line. Otherwise, it will be truncated with an ellipsis (default: false) */
|
|
32
|
+
textWrap?: boolean;
|
|
31
33
|
/** If set to true, the remove action button will be rendered (default: undefined) */
|
|
32
34
|
allowRemove?: boolean;
|
|
33
35
|
/** If set to true, editable fields will be highlighted and row click events will be fired (default: false) */
|
|
@@ -85,6 +87,7 @@ export const DynamicListRow = <T extends Data>({
|
|
|
85
87
|
showPositionColumn = false,
|
|
86
88
|
showActionColumn = false,
|
|
87
89
|
allowEditing = false,
|
|
90
|
+
textWrap = false,
|
|
88
91
|
}: PropsWithChildren<DynamicListRowProps<T>>): JSX.Element => {
|
|
89
92
|
const customStyles = {
|
|
90
93
|
gridAutoRows: `minmax(50px, ${rowHeight})`,
|
|
@@ -170,7 +173,7 @@ export const DynamicListRow = <T extends Data>({
|
|
|
170
173
|
</div>
|
|
171
174
|
)}
|
|
172
175
|
{columns.map((column: DynamicListColumn<T>) => {
|
|
173
|
-
const columnData
|
|
176
|
+
const { columnData, tooltip } = renderData<T>(column, data);
|
|
174
177
|
|
|
175
178
|
return (
|
|
176
179
|
<div
|
|
@@ -179,14 +182,16 @@ export const DynamicListRow = <T extends Data>({
|
|
|
179
182
|
column.dataEntryRender !== undefined && allowEditing,
|
|
180
183
|
})}
|
|
181
184
|
key={column.key ?? (column.propertyName as string)}
|
|
185
|
+
style={{
|
|
186
|
+
justifyContent: horizontalTextAlign,
|
|
187
|
+
alignItems: verticalTextAlign,
|
|
188
|
+
}}
|
|
182
189
|
>
|
|
183
190
|
<div
|
|
184
|
-
className={classes.column
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
: undefined
|
|
189
|
-
}
|
|
191
|
+
className={clsx(classes.column, {
|
|
192
|
+
[classes.nowrap]: !textWrap,
|
|
193
|
+
})}
|
|
194
|
+
title={tooltip}
|
|
190
195
|
data-test-id={`dynamic-list-property:${
|
|
191
196
|
column.propertyName as string
|
|
192
197
|
}`}
|
|
@@ -226,22 +231,26 @@ export const DynamicListRow = <T extends Data>({
|
|
|
226
231
|
</div>
|
|
227
232
|
);
|
|
228
233
|
};
|
|
229
|
-
|
|
230
|
-
const renderData = function <T extends Data>(
|
|
234
|
+
const renderData = <T extends Data>(
|
|
231
235
|
column: DynamicListColumn<T>,
|
|
232
236
|
data: T,
|
|
233
|
-
): React.ReactNode {
|
|
237
|
+
): { columnData: React.ReactNode; tooltip: string | undefined } => {
|
|
238
|
+
const getTooltip = (value: unknown): string | undefined =>
|
|
239
|
+
column.tooltip !== false ? getTooltipText(value) : undefined;
|
|
240
|
+
|
|
234
241
|
if (!column.propertyName) {
|
|
235
|
-
|
|
242
|
+
const columnData = column.render?.(undefined, data);
|
|
243
|
+
return { columnData, tooltip: getTooltip(columnData) };
|
|
236
244
|
}
|
|
237
245
|
const value: unknown = data[column.propertyName];
|
|
238
246
|
if (column.render) {
|
|
239
|
-
|
|
247
|
+
const columnData = column.render(value, data);
|
|
248
|
+
return { columnData, tooltip: getTooltip(columnData) };
|
|
240
249
|
}
|
|
241
250
|
|
|
242
251
|
if (value === null || value === undefined) {
|
|
243
|
-
return
|
|
252
|
+
return { columnData: <span />, tooltip: undefined };
|
|
244
253
|
}
|
|
245
254
|
|
|
246
|
-
return String(value);
|
|
255
|
+
return { columnData: String(value), tooltip: getTooltip(String(value)) };
|
|
247
256
|
};
|
|
@@ -15,14 +15,7 @@ const groups = createGroups({
|
|
|
15
15
|
'onBulkActionsToggled',
|
|
16
16
|
'setTabTitle',
|
|
17
17
|
],
|
|
18
|
-
Content: [
|
|
19
|
-
'title',
|
|
20
|
-
'subtitle',
|
|
21
|
-
'children',
|
|
22
|
-
'bulkActions',
|
|
23
|
-
'stationError',
|
|
24
|
-
'actions',
|
|
25
|
-
],
|
|
18
|
+
Content: ['title', 'subtitle', 'children', 'stationError', 'actions'],
|
|
26
19
|
Styling: ['className'],
|
|
27
20
|
});
|
|
28
21
|
|
|
@@ -35,10 +28,6 @@ const meta: Meta<typeof EmptyStation> = {
|
|
|
35
28
|
...groups.actions,
|
|
36
29
|
control: 'boolean',
|
|
37
30
|
},
|
|
38
|
-
bulkActions: {
|
|
39
|
-
...groups.bulkActions,
|
|
40
|
-
control: 'boolean',
|
|
41
|
-
},
|
|
42
31
|
stationError: {
|
|
43
32
|
...groups.stationError,
|
|
44
33
|
control: 'boolean',
|
|
@@ -56,19 +45,21 @@ export const Default: StoryObj<typeof EmptyStation> = {
|
|
|
56
45
|
? [
|
|
57
46
|
{
|
|
58
47
|
label: 'Test Action',
|
|
48
|
+
kind: 'action',
|
|
59
49
|
onClick: action('Action.onClick'),
|
|
60
50
|
icon: IconName.X,
|
|
61
51
|
},
|
|
62
|
-
]
|
|
63
|
-
: undefined
|
|
64
|
-
}
|
|
65
|
-
bulkActions={
|
|
66
|
-
args.bulkActions
|
|
67
|
-
? [
|
|
68
52
|
{
|
|
69
|
-
label: '
|
|
70
|
-
|
|
71
|
-
|
|
53
|
+
label: 'Bulk Actions',
|
|
54
|
+
icon: IconName.Bulk,
|
|
55
|
+
kind: 'group',
|
|
56
|
+
actions: [
|
|
57
|
+
{
|
|
58
|
+
label: 'Test Bulk Action',
|
|
59
|
+
onClick: action('BulkAction.onClick'),
|
|
60
|
+
icon: IconName.X,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
72
63
|
},
|
|
73
64
|
]
|
|
74
65
|
: undefined
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import React, { PropsWithChildren } from 'react';
|
|
3
3
|
import { MessageBar, MessageBarProps } from '../MessageBar';
|
|
4
|
-
import { StationError } from '../models';
|
|
5
4
|
import { PageHeader, PageHeaderProps } from '../PageHeader';
|
|
5
|
+
import { StationError } from '../models';
|
|
6
6
|
import classes from './EmptyStation.scss';
|
|
7
7
|
|
|
8
8
|
export type EmptyStationProps = PageHeaderProps & {
|
|
@@ -92,6 +92,9 @@ export interface ExplorerProps<T extends Data> {
|
|
|
92
92
|
/** Vertical alignment of text */
|
|
93
93
|
verticalTextAlign?: 'start' | 'center' | 'end';
|
|
94
94
|
|
|
95
|
+
/** If set to true, column text overflow will be wrapped to a new line. Otherwise, it will be truncated with an ellipsis (default: true) */
|
|
96
|
+
textWrap?: boolean;
|
|
97
|
+
|
|
95
98
|
/** Defines when the loading of the next page is triggered. The number represents the number of row left, before a load is triggered. (default: 10) */
|
|
96
99
|
loadingTriggerOffset?: number;
|
|
97
100
|
|
|
@@ -183,6 +186,7 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
|
|
|
183
186
|
headerRowActionSize,
|
|
184
187
|
horizontalTextAlign,
|
|
185
188
|
verticalTextAlign,
|
|
189
|
+
textWrap,
|
|
186
190
|
|
|
187
191
|
columns,
|
|
188
192
|
filterOptions,
|
|
@@ -479,6 +483,7 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
|
|
|
479
483
|
headerRowActionSize={headerRowActionSize}
|
|
480
484
|
horizontalTextAlign={horizontalTextAlign}
|
|
481
485
|
verticalTextAlign={verticalTextAlign}
|
|
486
|
+
textWrap={textWrap}
|
|
482
487
|
keyProperty={keyProperty}
|
|
483
488
|
showActionButton={Boolean(generateItemLink) || Boolean(onItemClicked)} // or hard code to `true`?
|
|
484
489
|
selectionMode={mode}
|
|
@@ -54,7 +54,7 @@ const generateData = (amount: number): ListStoryData[] =>
|
|
|
54
54
|
generateItemArray(amount, (index) => ({
|
|
55
55
|
id: index + 1,
|
|
56
56
|
desc: `Description ${index + 1}: ${faker.lorem.words(
|
|
57
|
-
faker.datatype.number({ min: 10, max:
|
|
57
|
+
faker.datatype.number({ min: 10, max: 50 }),
|
|
58
58
|
)}`,
|
|
59
59
|
title: `Item ${index + 1}: ${faker.random.words(
|
|
60
60
|
faker.datatype.number({ min: 1, max: 3 }),
|
|
@@ -92,6 +92,7 @@ const groups = createGroups({
|
|
|
92
92
|
Styling: [
|
|
93
93
|
'horizontalTextAlign',
|
|
94
94
|
'verticalTextAlign',
|
|
95
|
+
'textWrap',
|
|
95
96
|
'minimumWidth',
|
|
96
97
|
'columnGap',
|
|
97
98
|
'rowGap',
|
|
@@ -65,6 +65,8 @@ export interface ListProps<T extends Data> {
|
|
|
65
65
|
horizontalTextAlign?: 'left' | 'right' | 'center';
|
|
66
66
|
/** Vertical alignment of text */
|
|
67
67
|
verticalTextAlign?: 'start' | 'center' | 'end';
|
|
68
|
+
/** If set to true, column text overflow will be wrapped to a new line. Otherwise, it will be truncated with an ellipsis (default: false) */
|
|
69
|
+
textWrap?: boolean;
|
|
68
70
|
/**
|
|
69
71
|
* Determines which select mode the list is in. (default: ListSelectMode.None)
|
|
70
72
|
* If 'Single' is selected, a check mark will be rendered for each row of data
|
|
@@ -122,7 +124,7 @@ const ListRenderer = <T extends Data>(
|
|
|
122
124
|
columnGap = '5px',
|
|
123
125
|
rowGap = '0px',
|
|
124
126
|
headerRowHeight = '44px',
|
|
125
|
-
listRowHeight
|
|
127
|
+
listRowHeight,
|
|
126
128
|
listRowActionSize = '50px',
|
|
127
129
|
headerRowActionSize = '28px',
|
|
128
130
|
horizontalTextAlign = 'left',
|
|
@@ -134,6 +136,7 @@ const ListRenderer = <T extends Data>(
|
|
|
134
136
|
selectionMode = ListSelectMode.None,
|
|
135
137
|
enableSelectAll = true,
|
|
136
138
|
enableSelectAllDeselect = false,
|
|
139
|
+
textWrap,
|
|
137
140
|
onItemClicked = noop,
|
|
138
141
|
onItemSelected = noop,
|
|
139
142
|
onRequestMoreData = noop,
|
|
@@ -300,6 +303,7 @@ const ListRenderer = <T extends Data>(
|
|
|
300
303
|
actionSize={listRowActionSize}
|
|
301
304
|
horizontalTextAlign={horizontalTextAlign}
|
|
302
305
|
verticalTextAlign={verticalTextAlign}
|
|
306
|
+
textWrap={textWrap}
|
|
303
307
|
selectionMode={selectionMode}
|
|
304
308
|
showActionButton={
|
|
305
309
|
selectionMode === ListSelectMode.None &&
|
|
@@ -29,17 +29,24 @@
|
|
|
29
29
|
|
|
30
30
|
.cellWrapper {
|
|
31
31
|
display: grid;
|
|
32
|
-
align-content: center;
|
|
33
32
|
width: 100%;
|
|
34
33
|
height: 100%;
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
.cell {
|
|
38
|
-
white-space: nowrap;
|
|
39
|
-
text-overflow: ellipsis;
|
|
40
|
-
overflow: hidden;
|
|
41
37
|
max-width: 100%;
|
|
42
38
|
max-height: 100%;
|
|
39
|
+
|
|
40
|
+
span {
|
|
41
|
+
padding: 5px 0;
|
|
42
|
+
display: grid;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&.nowrap {
|
|
46
|
+
white-space: nowrap;
|
|
47
|
+
text-overflow: ellipsis;
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
}
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
.actions {
|
|
@@ -566,4 +566,37 @@ describe('ListRow', () => {
|
|
|
566
566
|
expect(cell.prop('title')).toBe(mockValue);
|
|
567
567
|
});
|
|
568
568
|
});
|
|
569
|
+
|
|
570
|
+
describe('column text alignments', () => {
|
|
571
|
+
const alignments: {
|
|
572
|
+
horizontal: 'left' | 'right' | 'center';
|
|
573
|
+
vertical: 'center' | 'start' | 'end';
|
|
574
|
+
}[] = [
|
|
575
|
+
{ horizontal: 'center', vertical: 'center' },
|
|
576
|
+
{ horizontal: 'left', vertical: 'start' },
|
|
577
|
+
{ horizontal: 'right', vertical: 'end' },
|
|
578
|
+
];
|
|
579
|
+
|
|
580
|
+
alignments.forEach(({ horizontal, vertical }) => {
|
|
581
|
+
it(`should apply the correct styles for textAlign: ${horizontal}, alignSelf: ${vertical}`, () => {
|
|
582
|
+
const wrapper = mount(
|
|
583
|
+
<ListRow
|
|
584
|
+
{...mockProps}
|
|
585
|
+
columns={[{ propertyName: 'id', size: '1fr', label: 'id' }]}
|
|
586
|
+
horizontalTextAlign={horizontal}
|
|
587
|
+
verticalTextAlign={vertical}
|
|
588
|
+
/>,
|
|
589
|
+
);
|
|
590
|
+
|
|
591
|
+
const wrapperDivs = wrapper.find('.cell');
|
|
592
|
+
|
|
593
|
+
wrapperDivs.forEach((node) => {
|
|
594
|
+
const style = node.prop('style');
|
|
595
|
+
|
|
596
|
+
expect(style).toHaveProperty('textAlign', horizontal);
|
|
597
|
+
expect(style).toHaveProperty('alignSelf', vertical);
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
});
|
|
569
602
|
});
|
|
@@ -19,13 +19,15 @@ export interface ListRowProps<T extends Data> {
|
|
|
19
19
|
/** Header row height */
|
|
20
20
|
columnGap: string;
|
|
21
21
|
/** List row height */
|
|
22
|
-
rowHeight
|
|
22
|
+
rowHeight?: string;
|
|
23
23
|
/** Size of action button and checkbox */
|
|
24
24
|
actionSize: string;
|
|
25
25
|
/** Horizontal alignment of text */
|
|
26
26
|
horizontalTextAlign: 'left' | 'right' | 'center';
|
|
27
27
|
/** Vertical alignment of text */
|
|
28
28
|
verticalTextAlign: 'start' | 'center' | 'end';
|
|
29
|
+
/** If set to true, column text overflow will be wrapped to a new line. Otherwise, it will be truncated with an ellipsis (default: false) */
|
|
30
|
+
textWrap?: boolean;
|
|
29
31
|
/** List data */
|
|
30
32
|
data: T;
|
|
31
33
|
/** The column definition */
|
|
@@ -81,32 +83,79 @@ export const setLocale = (locale: string): void => {
|
|
|
81
83
|
|
|
82
84
|
setLocale(navigator.language);
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
const renderData = <T extends Data>(
|
|
85
87
|
column: Column<T>,
|
|
86
88
|
rowData: T,
|
|
87
|
-
): React.ReactNode {
|
|
89
|
+
): { columnData: React.ReactNode; tooltip: string | undefined } => {
|
|
90
|
+
const getTooltip = (value: unknown): string | undefined =>
|
|
91
|
+
column.tooltip !== false ? getTooltipText(value) : undefined;
|
|
92
|
+
|
|
88
93
|
if (!column.propertyName) {
|
|
89
|
-
|
|
94
|
+
const columnData = column.render?.(undefined, rowData);
|
|
95
|
+
return {
|
|
96
|
+
columnData,
|
|
97
|
+
tooltip: getTooltip(columnData),
|
|
98
|
+
};
|
|
90
99
|
}
|
|
91
100
|
const value: unknown = rowData[column.propertyName];
|
|
92
101
|
if (column.render) {
|
|
93
|
-
|
|
102
|
+
const columnData = column.render(value, rowData);
|
|
103
|
+
return {
|
|
104
|
+
columnData,
|
|
105
|
+
tooltip: getTooltip(columnData),
|
|
106
|
+
};
|
|
94
107
|
}
|
|
95
108
|
|
|
96
109
|
if (value === null || value === undefined) {
|
|
97
|
-
return
|
|
110
|
+
return {
|
|
111
|
+
columnData: (
|
|
112
|
+
<span
|
|
113
|
+
data-test-id={`list-entry-property:${column.propertyName as string}`}
|
|
114
|
+
/>
|
|
115
|
+
),
|
|
116
|
+
tooltip: undefined,
|
|
117
|
+
};
|
|
98
118
|
}
|
|
99
119
|
|
|
100
120
|
if (typeof value === 'number') {
|
|
101
|
-
|
|
121
|
+
const columnData = numberFormatter.format(value);
|
|
122
|
+
return {
|
|
123
|
+
columnData: (
|
|
124
|
+
<span
|
|
125
|
+
data-test-id={`list-entry-property:${column.propertyName as string}`}
|
|
126
|
+
>
|
|
127
|
+
{columnData}
|
|
128
|
+
</span>
|
|
129
|
+
),
|
|
130
|
+
tooltip: getTooltip(columnData),
|
|
131
|
+
};
|
|
102
132
|
}
|
|
103
133
|
|
|
104
134
|
if (value instanceof Date) {
|
|
105
|
-
|
|
135
|
+
const columnData = dateFormatter.format(value);
|
|
136
|
+
return {
|
|
137
|
+
columnData: (
|
|
138
|
+
<span
|
|
139
|
+
data-test-id={`list-entry-property:${column.propertyName as string}`}
|
|
140
|
+
>
|
|
141
|
+
{columnData}
|
|
142
|
+
</span>
|
|
143
|
+
),
|
|
144
|
+
tooltip: getTooltip(columnData),
|
|
145
|
+
};
|
|
106
146
|
}
|
|
107
147
|
|
|
108
|
-
return
|
|
109
|
-
|
|
148
|
+
return {
|
|
149
|
+
columnData: (
|
|
150
|
+
<span
|
|
151
|
+
data-test-id={`list-entry-property:${column.propertyName as string}`}
|
|
152
|
+
>
|
|
153
|
+
{String(value)}
|
|
154
|
+
</span>
|
|
155
|
+
),
|
|
156
|
+
tooltip: getTooltip(String(value)),
|
|
157
|
+
};
|
|
158
|
+
};
|
|
110
159
|
|
|
111
160
|
/**
|
|
112
161
|
* Renders the rows for the list component
|
|
@@ -128,6 +177,7 @@ export const ListRow = <T extends Data>({
|
|
|
128
177
|
actionSize,
|
|
129
178
|
horizontalTextAlign,
|
|
130
179
|
verticalTextAlign,
|
|
180
|
+
textWrap = false,
|
|
131
181
|
data,
|
|
132
182
|
itemSelected = false,
|
|
133
183
|
isTrigger = false,
|
|
@@ -143,7 +193,7 @@ export const ListRow = <T extends Data>({
|
|
|
143
193
|
inlineMenuActions,
|
|
144
194
|
}: PropsWithChildren<ListRowProps<T>>): JSX.Element => {
|
|
145
195
|
const customRootStyles = {
|
|
146
|
-
gridAutoRows: rowHeight
|
|
196
|
+
gridAutoRows: `minmax(50px, ${rowHeight})`,
|
|
147
197
|
gridColumnGap: columnGap,
|
|
148
198
|
justifyItems: horizontalTextAlign,
|
|
149
199
|
alignItems: verticalTextAlign,
|
|
@@ -199,7 +249,7 @@ export const ListRow = <T extends Data>({
|
|
|
199
249
|
typeof onItemClicked !== 'function';
|
|
200
250
|
|
|
201
251
|
const generateCells: JSX.Element[] = columns.map((column: Column<T>) => {
|
|
202
|
-
const columnData
|
|
252
|
+
const { columnData, tooltip } = renderData<T>(column, data);
|
|
203
253
|
|
|
204
254
|
return (
|
|
205
255
|
<div
|
|
@@ -207,12 +257,13 @@ export const ListRow = <T extends Data>({
|
|
|
207
257
|
className={classes.cellWrapper}
|
|
208
258
|
>
|
|
209
259
|
<div
|
|
210
|
-
className={classes.cell}
|
|
211
|
-
title={
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
260
|
+
className={clsx(classes.cell, { [classes.nowrap]: !textWrap })}
|
|
261
|
+
title={tooltip}
|
|
262
|
+
style={{
|
|
263
|
+
justifySelf: column.horizontalColumnAlign, // Horizontal alignment based on column config
|
|
264
|
+
alignSelf: verticalTextAlign, // Vertical alignment based on props
|
|
265
|
+
textAlign: horizontalTextAlign, // Additional text alignment inside the cell
|
|
266
|
+
}}
|
|
216
267
|
>
|
|
217
268
|
{columnData}
|
|
218
269
|
</div>
|
|
@@ -10,7 +10,7 @@ export interface ListRowLoaderProps<T extends Data> {
|
|
|
10
10
|
/** Space between columns */
|
|
11
11
|
columnGap: string;
|
|
12
12
|
/** List row height */
|
|
13
|
-
rowHeight
|
|
13
|
+
rowHeight?: string;
|
|
14
14
|
/** The column definition */
|
|
15
15
|
columns: Column<T>[];
|
|
16
16
|
}
|
|
@@ -25,7 +25,7 @@ export const ListRowLoader = <T extends Data>({
|
|
|
25
25
|
const rows = 5;
|
|
26
26
|
|
|
27
27
|
const customRowStyles = {
|
|
28
|
-
gridAutoRows: rowHeight
|
|
28
|
+
gridAutoRows: `minmax(50px, ${rowHeight})`,
|
|
29
29
|
gridTemplateColumns: columnSizes,
|
|
30
30
|
gridColumnGap: columnGap,
|
|
31
31
|
} as React.CSSProperties;
|