@axinom/mosaic-ui 0.34.0-rc.3 → 0.34.0-rc.30
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/Explorer/Explorer.d.ts.map +1 -1
- package/dist/components/Filters/Filter/Filter.d.ts +2 -1
- package/dist/components/Filters/Filter/Filter.d.ts.map +1 -1
- package/dist/components/Filters/Filters.d.ts.map +1 -1
- package/dist/components/Filters/Filters.model.d.ts +2 -0
- package/dist/components/Filters/Filters.model.d.ts.map +1 -1
- package/dist/components/FormElements/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/FormElements/Checkbox/CheckboxField.d.ts +1 -1
- package/dist/components/FormElements/Checkbox/CheckboxField.d.ts.map +1 -1
- package/dist/components/FormElements/CustomTags/CustomTagsField.d.ts.map +1 -1
- package/dist/components/FormElements/DateTimeField/DateTimeTextField.d.ts +1 -1
- package/dist/components/FormElements/DateTimeField/DateTimeTextField.d.ts.map +1 -1
- package/dist/components/FormElements/DynamicDataListControl/DynamicDataListField.d.ts.map +1 -1
- package/dist/components/FormElements/FileUploadControl/FileUploadControl.d.ts.map +1 -1
- package/dist/components/FormElements/FileUploadControl/FileUploadField.d.ts.map +1 -1
- package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.d.ts +1 -1
- package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.d.ts.map +1 -1
- package/dist/components/FormElements/SingleLineText/SingleLineText.d.ts.map +1 -1
- package/dist/components/List/List.d.ts.map +1 -1
- package/dist/components/List/List.model.d.ts +2 -0
- package/dist/components/List/List.model.d.ts.map +1 -1
- package/dist/components/List/ListHeader/ListHeader.d.ts +7 -1
- package/dist/components/List/ListHeader/ListHeader.d.ts.map +1 -1
- package/dist/components/List/ListHeader/useResize.d.ts +18 -0
- package/dist/components/List/ListHeader/useResize.d.ts.map +1 -0
- package/dist/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/components/List/ListRow/ListRowLoader.d.ts +2 -2
- package/dist/components/List/ListRow/ListRowLoader.d.ts.map +1 -1
- package/dist/components/List/ListRow/Renderers/BooleanDotRenderer/BooleanDotRenderer.d.ts.map +1 -1
- package/dist/components/List/useColumnsSize.d.ts +21 -0
- package/dist/components/List/useColumnsSize.d.ts.map +1 -0
- package/dist/index.es.js +3 -3
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/initialize.d.ts +3 -3
- package/dist/initialize.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.spec.tsx +2 -2
- package/src/components/Explorer/Explorer.stories.tsx +16 -0
- package/src/components/Explorer/Explorer.tsx +33 -31
- package/src/components/Filters/Filter/Filter.spec.tsx +24 -1
- package/src/components/Filters/Filter/Filter.tsx +6 -0
- package/src/components/Filters/Filters.model.ts +3 -0
- package/src/components/Filters/Filters.stories.tsx +9 -0
- package/src/components/Filters/Filters.tsx +1 -0
- package/src/components/FormElements/BooleanView/BooleanViewField.scss +4 -6
- package/src/components/FormElements/BooleanView/BooleanViewField.spec.tsx +6 -6
- package/src/components/FormElements/BooleanView/BooleanViewField.tsx +1 -1
- package/src/components/FormElements/Checkbox/Checkbox.tsx +1 -1
- package/src/components/FormElements/Checkbox/CheckboxField.tsx +4 -5
- package/src/components/FormElements/CustomTags/CustomTags.scss +15 -4
- package/src/components/FormElements/CustomTags/CustomTags.spec.tsx +3 -3
- package/src/components/FormElements/CustomTags/CustomTags.tsx +3 -3
- package/src/components/FormElements/CustomTags/CustomTagsField.tsx +1 -2
- package/src/components/FormElements/DateTimeField/DateTimeTextField.tsx +3 -3
- package/src/components/FormElements/DynamicDataListControl/DynamicDataListField.tsx +1 -2
- package/src/components/FormElements/FileUploadControl/FileUploadControl.spec.tsx +35 -0
- package/src/components/FormElements/FileUploadControl/FileUploadControl.tsx +2 -0
- package/src/components/FormElements/FileUploadControl/FileUploadField.tsx +1 -2
- package/src/components/FormElements/FormElementContainer/FormElementContainer.scss +2 -0
- package/src/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.tsx +1 -1
- package/src/components/FormElements/Radio/RadioField.tsx +2 -2
- package/src/components/FormElements/SingleLineText/SingleLineText.spec.tsx +5 -4
- package/src/components/FormElements/SingleLineText/SingleLineText.tsx +6 -1
- package/src/components/FormElements/Tags/Tags.scss +1 -1
- package/src/components/FormElements/ToggleButton/ToggleButton.scss +18 -7
- package/src/components/FormStation/FormStation.spec.tsx +12 -6
- package/src/components/FormStation/FormStation.tsx +6 -6
- package/src/components/InlineMenu/InlineMenu.scss +20 -5
- package/src/components/LandingPageTiles/TileLarge/TileLarge.scss +11 -6
- package/src/components/List/List.model.ts +3 -0
- package/src/components/List/List.scss +0 -2
- package/src/components/List/List.stories.tsx +1 -1
- package/src/components/List/List.tsx +17 -55
- package/src/components/List/ListHeader/ListHeader.scss +23 -10
- package/src/components/List/ListHeader/ListHeader.spec.tsx +56 -0
- package/src/components/List/ListHeader/ListHeader.tsx +43 -9
- package/src/components/List/ListHeader/useResize.ts +108 -0
- package/src/components/List/ListRow/ListRow.scss +8 -12
- package/src/components/List/ListRow/ListRow.spec.tsx +5 -21
- package/src/components/List/ListRow/ListRow.tsx +16 -32
- package/src/components/List/ListRow/ListRowLoader.tsx +14 -4
- package/src/components/List/ListRow/Renderers/BooleanDotRenderer/BooleanDotRenderer.scss +10 -8
- package/src/components/List/ListRow/Renderers/BooleanDotRenderer/BooleanDotRenderer.tsx +3 -1
- package/src/components/List/useColumnsSize.ts +120 -0
- package/src/initialize.ts +4 -4
- package/src/styles/variables.scss +11 -0
|
@@ -57,6 +57,12 @@ export const SingleLineText: React.FC<SingleLineTextProps> = ({
|
|
|
57
57
|
const DUMMY_PWD = '0000000000';
|
|
58
58
|
const isPasswordField = type === 'password' ? true : false;
|
|
59
59
|
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (innerRef.current) {
|
|
62
|
+
innerRef.current.value = String(value || '');
|
|
63
|
+
}
|
|
64
|
+
}, [innerRef, value]);
|
|
65
|
+
|
|
60
66
|
useEffect(() => {
|
|
61
67
|
if (isPasswordField && isSet) {
|
|
62
68
|
executeIfRefAvailable(innerRef, (input) => {
|
|
@@ -99,7 +105,6 @@ export const SingleLineText: React.FC<SingleLineTextProps> = ({
|
|
|
99
105
|
name={name}
|
|
100
106
|
type={type}
|
|
101
107
|
ref={innerRef}
|
|
102
|
-
value={value ?? ''}
|
|
103
108
|
defaultValue={defaultValue}
|
|
104
109
|
disabled={disabled}
|
|
105
110
|
placeholder={disabled ? undefined : placeholder}
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
|
|
19
19
|
&:hover:enabled {
|
|
20
20
|
transition: box-shadow 0.15s ease-in-out 0s;
|
|
21
|
-
box-shadow: 0 0 0 2px
|
|
21
|
+
box-shadow: 0 0 0 2px
|
|
22
|
+
var(--toggle-button-stroke-color, $toggle-button-stroke-color);
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
div {
|
|
@@ -44,25 +45,35 @@
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
&.off {
|
|
47
|
-
border-top: 1px solid
|
|
48
|
-
|
|
49
|
-
border-
|
|
48
|
+
border-top: 1px solid
|
|
49
|
+
var(--toggle-button-stroke-color, $toggle-button-stroke-color);
|
|
50
|
+
border-bottom: 1px solid
|
|
51
|
+
var(--toggle-button-stroke-color, $toggle-button-stroke-color);
|
|
52
|
+
border-left: 1px solid
|
|
53
|
+
var(--toggle-button-stroke-color, $toggle-button-stroke-color);
|
|
50
54
|
}
|
|
51
55
|
&.on {
|
|
52
|
-
border: 1px solid
|
|
56
|
+
border: 1px solid
|
|
57
|
+
var(--toggle-button-stroke-color, $toggle-button-stroke-color);
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
div.active.off {
|
|
57
62
|
svg {
|
|
58
63
|
.svgText {
|
|
59
|
-
fill:
|
|
64
|
+
fill: var(
|
|
65
|
+
--toggle-button-off-text-color,
|
|
66
|
+
$toggle-button-off-text-color
|
|
67
|
+
);
|
|
60
68
|
}
|
|
61
69
|
}
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
div.active.on {
|
|
65
|
-
background-color:
|
|
73
|
+
background-color: var(
|
|
74
|
+
--toggle-button-on-bg-color,
|
|
75
|
+
$toggle-button-on-bg-color
|
|
76
|
+
) !important;
|
|
66
77
|
}
|
|
67
78
|
|
|
68
79
|
&:disabled {
|
|
@@ -5,7 +5,7 @@ import { act } from 'react-dom/test-utils';
|
|
|
5
5
|
import { MemoryRouter, Route } from 'react-router-dom';
|
|
6
6
|
import * as Yup from 'yup';
|
|
7
7
|
import { noop } from '../../helpers/utils';
|
|
8
|
-
import {
|
|
8
|
+
import { SaveIndicatorType, setSaveIndicator } from '../../initialize';
|
|
9
9
|
import { ActionData, Actions } from '../Actions';
|
|
10
10
|
import { Action } from '../Actions/Action';
|
|
11
11
|
import { MessageBar } from '../MessageBar/MessageBar';
|
|
@@ -677,9 +677,12 @@ describe('Details', () => {
|
|
|
677
677
|
);
|
|
678
678
|
expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
679
679
|
1,
|
|
680
|
-
|
|
681
|
-
); // 1. inactive
|
|
682
|
-
expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
680
|
+
SaveIndicatorType.Inactive,
|
|
681
|
+
); // 1. inactive
|
|
682
|
+
expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
683
|
+
3,
|
|
684
|
+
SaveIndicatorType.Dirty,
|
|
685
|
+
); // 3. dirty
|
|
683
686
|
|
|
684
687
|
// submit form
|
|
685
688
|
const actionSelected = wrapper
|
|
@@ -697,7 +700,10 @@ describe('Details', () => {
|
|
|
697
700
|
|
|
698
701
|
wrapper.update();
|
|
699
702
|
|
|
700
|
-
expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
703
|
+
expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
704
|
+
4,
|
|
705
|
+
SaveIndicatorType.Saving,
|
|
706
|
+
);
|
|
701
707
|
|
|
702
708
|
// complete form submission
|
|
703
709
|
await act(async () => {
|
|
@@ -707,7 +713,7 @@ describe('Details', () => {
|
|
|
707
713
|
|
|
708
714
|
expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
709
715
|
5,
|
|
710
|
-
|
|
716
|
+
SaveIndicatorType.Inactive,
|
|
711
717
|
);
|
|
712
718
|
|
|
713
719
|
console.warn((setSaveIndicator as jest.Mock).mock.calls);
|
|
@@ -16,7 +16,7 @@ import React, {
|
|
|
16
16
|
} from 'react';
|
|
17
17
|
import { useHistory } from 'react-router-dom';
|
|
18
18
|
import { OptionalObjectSchema } from 'yup/lib/object';
|
|
19
|
-
import {
|
|
19
|
+
import { SaveIndicatorType, setSaveIndicator } from '../../initialize';
|
|
20
20
|
import { Data } from '../../types/data';
|
|
21
21
|
import { ErrorTypeToStationError } from '../../utils/ErrorTypeToStationError';
|
|
22
22
|
import { Actions, ActionsProps } from '../Actions';
|
|
@@ -155,7 +155,7 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
155
155
|
|
|
156
156
|
try {
|
|
157
157
|
setIsFormSubmitting(true);
|
|
158
|
-
setSaveIndicator(
|
|
158
|
+
setSaveIndicator(SaveIndicatorType.Saving);
|
|
159
159
|
setStationError(undefined);
|
|
160
160
|
if (!initialData.loading && saveData) {
|
|
161
161
|
const response = await saveData(values, initialData, formikHelpers);
|
|
@@ -171,7 +171,7 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
171
171
|
),
|
|
172
172
|
);
|
|
173
173
|
|
|
174
|
-
setSaveIndicator(
|
|
174
|
+
setSaveIndicator(SaveIndicatorType.Dirty);
|
|
175
175
|
|
|
176
176
|
// We still throw the error, to make sure that navigation or action execution
|
|
177
177
|
// will not continue after a failed save.
|
|
@@ -449,15 +449,15 @@ const FormStationHeader: React.FC<
|
|
|
449
449
|
useEffect(() => {
|
|
450
450
|
// Set the save indicator to dirty depending on the form state
|
|
451
451
|
if (dirty) {
|
|
452
|
-
setSaveIndicator(
|
|
452
|
+
setSaveIndicator(SaveIndicatorType.Dirty);
|
|
453
453
|
} else {
|
|
454
|
-
setSaveIndicator(
|
|
454
|
+
setSaveIndicator(SaveIndicatorType.Inactive);
|
|
455
455
|
}
|
|
456
456
|
return () => {
|
|
457
457
|
// The form is not always considered "not dirty" after the save
|
|
458
458
|
// so this code will make sure that the indicator is set to inactive
|
|
459
459
|
// when the station is left.
|
|
460
|
-
setSaveIndicator(
|
|
460
|
+
setSaveIndicator(SaveIndicatorType.Inactive);
|
|
461
461
|
};
|
|
462
462
|
}, [dirty]);
|
|
463
463
|
|
|
@@ -85,10 +85,16 @@ $pop-up-arrow-extrusion: -7px;
|
|
|
85
85
|
.buttonDefault {
|
|
86
86
|
background-color: transparent !important;
|
|
87
87
|
svg * {
|
|
88
|
-
stroke:
|
|
88
|
+
stroke: var(
|
|
89
|
+
--inline-menu-button-stroke-color,
|
|
90
|
+
$inline-menu-button-stroke-color
|
|
91
|
+
) !important;
|
|
89
92
|
}
|
|
90
93
|
&:hover {
|
|
91
|
-
background-color:
|
|
94
|
+
background-color: var(
|
|
95
|
+
--inline-menu-button-hover-bg-color,
|
|
96
|
+
$inline-menu-button-hover-bg-color
|
|
97
|
+
) !important;
|
|
92
98
|
svg * {
|
|
93
99
|
stroke: white !important;
|
|
94
100
|
}
|
|
@@ -98,10 +104,16 @@ $pop-up-arrow-extrusion: -7px;
|
|
|
98
104
|
.buttonDefaultOpacity {
|
|
99
105
|
background-color: rgba(white, 0.7) !important;
|
|
100
106
|
svg * {
|
|
101
|
-
stroke:
|
|
107
|
+
stroke: var(
|
|
108
|
+
--inline-menu-button-stroke-color,
|
|
109
|
+
$inline-menu-button-stroke-color
|
|
110
|
+
) !important;
|
|
102
111
|
}
|
|
103
112
|
&:hover {
|
|
104
|
-
background-color:
|
|
113
|
+
background-color: var(
|
|
114
|
+
--inline-menu-button-hover-bg-color,
|
|
115
|
+
$inline-menu-button-hover-bg-color
|
|
116
|
+
) !important;
|
|
105
117
|
svg * {
|
|
106
118
|
stroke: white !important;
|
|
107
119
|
}
|
|
@@ -109,7 +121,10 @@ $pop-up-arrow-extrusion: -7px;
|
|
|
109
121
|
}
|
|
110
122
|
|
|
111
123
|
.buttonSelected {
|
|
112
|
-
background-color:
|
|
124
|
+
background-color: var(
|
|
125
|
+
--inline-menu-button-selected-bg-color,
|
|
126
|
+
$inline-menu-button-selected-bg-color
|
|
127
|
+
) !important;
|
|
113
128
|
svg * {
|
|
114
129
|
stroke: white !important;
|
|
115
130
|
}
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
height: 100%;
|
|
5
5
|
display: grid;
|
|
6
6
|
grid-template-columns: 1fr;
|
|
7
|
-
grid-template-rows:
|
|
7
|
+
grid-template-rows: 130px 1fr;
|
|
8
8
|
grid-column: span 4;
|
|
9
9
|
grid-row: span 2;
|
|
10
10
|
place-items: center;
|
|
11
11
|
|
|
12
12
|
text-decoration: none;
|
|
13
|
+
overflow: hidden;
|
|
13
14
|
|
|
14
15
|
color: var(--landingpage-largetile-color, $landingpage-largetile-color);
|
|
15
16
|
background-color: var(
|
|
@@ -41,25 +42,29 @@
|
|
|
41
42
|
$landingpage-largetile-stroke-color
|
|
42
43
|
);
|
|
43
44
|
}
|
|
45
|
+
|
|
46
|
+
> * {
|
|
47
|
+
width: 100%;
|
|
48
|
+
height: 100%;
|
|
49
|
+
}
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
.titlesSection {
|
|
47
53
|
display: grid;
|
|
48
|
-
|
|
49
|
-
grid-template-rows: 1fr 1fr;
|
|
54
|
+
padding: 0 15px 15px 15px;
|
|
50
55
|
place-items: center;
|
|
51
56
|
align-self: stretch;
|
|
52
57
|
|
|
53
58
|
text-align: center;
|
|
54
59
|
|
|
55
60
|
.label {
|
|
56
|
-
font-size:
|
|
57
|
-
|
|
61
|
+
font-size: 23px;
|
|
62
|
+
overflow: hidden;
|
|
58
63
|
}
|
|
59
64
|
|
|
60
65
|
.subtitle {
|
|
61
66
|
font-size: 16px;
|
|
62
|
-
|
|
67
|
+
align-self: end;
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
}
|
|
@@ -46,6 +46,9 @@ export interface Column<T extends Data> {
|
|
|
46
46
|
|
|
47
47
|
/** Specify the horizontal text alignment of the column */
|
|
48
48
|
horizontalColumnAlign?: 'left' | 'center' | 'right';
|
|
49
|
+
|
|
50
|
+
/** If set to true, the column will not be resizable */
|
|
51
|
+
disableResizing?: boolean;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
export interface ColumnMap {
|
|
@@ -248,7 +248,7 @@ export const NotSortableColumn: StoryObj<StoryListType> = {
|
|
|
248
248
|
args: {
|
|
249
249
|
columns: [
|
|
250
250
|
defaultColumns[0],
|
|
251
|
-
{ ...defaultColumns[1], sortable: false },
|
|
251
|
+
{ ...defaultColumns[1], sortable: false, disableResizing: true },
|
|
252
252
|
...defaultColumns.slice(2),
|
|
253
253
|
],
|
|
254
254
|
},
|
|
@@ -24,6 +24,7 @@ import classes from './List.scss';
|
|
|
24
24
|
import { ListHeader } from './ListHeader/ListHeader';
|
|
25
25
|
import { ListRow } from './ListRow/ListRow';
|
|
26
26
|
import { ListRowLoader } from './ListRow/ListRowLoader';
|
|
27
|
+
import { useColumnsSize } from './useColumnsSize';
|
|
27
28
|
|
|
28
29
|
export interface ListProps<T extends Data> {
|
|
29
30
|
/**
|
|
@@ -104,53 +105,6 @@ export interface ListProps<T extends Data> {
|
|
|
104
105
|
inlineMenuActions?: (data: T) => ActionData[];
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
/**
|
|
108
|
-
* Generates a combined string of all columns.columnSize values, to be used as CSS value
|
|
109
|
-
* @param columns The list of columns that should be used
|
|
110
|
-
* @returns a string of all column sizes of the array, combined
|
|
111
|
-
*/
|
|
112
|
-
const getColumnsSizeDefinition = function <T extends Data>(
|
|
113
|
-
columns: Column<T>[],
|
|
114
|
-
showActionButton: boolean,
|
|
115
|
-
selectMode: ListSelectMode,
|
|
116
|
-
showInlineMenu: boolean,
|
|
117
|
-
): string {
|
|
118
|
-
const columnSizeDefinition = columns.map((column) => column.size ?? '1fr');
|
|
119
|
-
|
|
120
|
-
const hasActionsColumn =
|
|
121
|
-
selectMode !== ListSelectMode.None || showActionButton || showInlineMenu;
|
|
122
|
-
|
|
123
|
-
if (hasActionsColumn) {
|
|
124
|
-
columnSizeDefinition.push(
|
|
125
|
-
getActionsColumnSizePx(showInlineMenu, showActionButton),
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return columnSizeDefinition.join(' ');
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const getActionsColumnSizePx = (...enableActions: boolean[]): string => {
|
|
133
|
-
const enabledActionsCount = enableActions.filter(
|
|
134
|
-
(actionEnabled) => actionEnabled,
|
|
135
|
-
).length;
|
|
136
|
-
|
|
137
|
-
const defaultActionSizePx = 50;
|
|
138
|
-
const defaultActionsRawGapPx = 8;
|
|
139
|
-
const calculateMultiActionsColumnSizePx = (actionsCount: number): number => {
|
|
140
|
-
return (
|
|
141
|
-
defaultActionSizePx * actionsCount +
|
|
142
|
-
defaultActionsRawGapPx * (actionsCount - 1)
|
|
143
|
-
);
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const sizePx =
|
|
147
|
-
enabledActionsCount > 1
|
|
148
|
-
? calculateMultiActionsColumnSizePx(enabledActionsCount)
|
|
149
|
-
: defaultActionSizePx;
|
|
150
|
-
|
|
151
|
-
return `${sizePx}px`;
|
|
152
|
-
};
|
|
153
|
-
|
|
154
108
|
const noItemsMessage = (
|
|
155
109
|
itemsCount: number,
|
|
156
110
|
isLoading: boolean,
|
|
@@ -206,7 +160,7 @@ export const List = <T extends Data>({
|
|
|
206
160
|
isError = false,
|
|
207
161
|
errorMsg = 'There was an error.',
|
|
208
162
|
handleRetry = true,
|
|
209
|
-
minimumWidth = '
|
|
163
|
+
minimumWidth = 'fit-content',
|
|
210
164
|
columnGap = '5px',
|
|
211
165
|
rowGap = '0px',
|
|
212
166
|
headerRowHeight = '44px',
|
|
@@ -243,14 +197,19 @@ export const List = <T extends Data>({
|
|
|
243
197
|
});
|
|
244
198
|
}, [data]);
|
|
245
199
|
|
|
246
|
-
const columnSizes =
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
200
|
+
const { columnSizes, resetColumnSizes, setColumnSizes, hasActionColumn } =
|
|
201
|
+
useColumnsSize(
|
|
202
|
+
columns,
|
|
203
|
+
Boolean(showActionButton),
|
|
204
|
+
selectionMode,
|
|
205
|
+
Boolean(inlineMenuActions),
|
|
206
|
+
);
|
|
252
207
|
|
|
253
|
-
const customStyles = {
|
|
208
|
+
const customStyles = {
|
|
209
|
+
gridRowGap: rowGap,
|
|
210
|
+
minWidth: minimumWidth,
|
|
211
|
+
width: '100%',
|
|
212
|
+
};
|
|
254
213
|
|
|
255
214
|
const itemSelectionHandler = useCallback(
|
|
256
215
|
(items: ListItem<T>[]) => {
|
|
@@ -327,6 +286,9 @@ export const List = <T extends Data>({
|
|
|
327
286
|
isCheckboxDisabled={listItems.length === 0}
|
|
328
287
|
onCheckboxToggled={headerCheckboxHandler}
|
|
329
288
|
onSortChanged={sortChangedHandler}
|
|
289
|
+
onResetColumnSizes={resetColumnSizes}
|
|
290
|
+
onColumnSizesChanged={setColumnSizes}
|
|
291
|
+
hasActionColumn={hasActionColumn}
|
|
330
292
|
/>
|
|
331
293
|
{/* Rows */}
|
|
332
294
|
{listItems.map((item: ListItem<T>, index) => (
|
|
@@ -3,14 +3,9 @@
|
|
|
3
3
|
.container {
|
|
4
4
|
padding-left: 5px;
|
|
5
5
|
display: grid;
|
|
6
|
-
grid-template-columns: repeat(auto-fit, minmax(20px, 1fr));
|
|
7
|
-
grid-auto-rows: 44px;
|
|
8
|
-
column-gap: 5px;
|
|
9
|
-
justify-items: left;
|
|
10
|
-
align-items: center;
|
|
11
6
|
position: sticky;
|
|
12
7
|
top: 0;
|
|
13
|
-
z-index: 1;
|
|
8
|
+
//z-index: 1;
|
|
14
9
|
|
|
15
10
|
background-color: var(
|
|
16
11
|
--explorer-header-background-color,
|
|
@@ -22,11 +17,29 @@
|
|
|
22
17
|
|
|
23
18
|
.columnLabel {
|
|
24
19
|
box-sizing: border-box;
|
|
25
|
-
width:
|
|
20
|
+
width: 100%;
|
|
26
21
|
height: 100%;
|
|
27
22
|
display: grid;
|
|
28
|
-
grid-template-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
grid-template-columns: 1fr auto;
|
|
24
|
+
position: relative;
|
|
25
|
+
|
|
26
|
+
.resizeHandle {
|
|
27
|
+
cursor: col-resize;
|
|
28
|
+
width: 7px;
|
|
29
|
+
height: 100%;
|
|
30
|
+
|
|
31
|
+
z-index: 1;
|
|
32
|
+
border-right: var(--explorer-list-row-border, 1px solid #dddddd);
|
|
33
|
+
position: absolute;
|
|
34
|
+
right: 0;
|
|
35
|
+
|
|
36
|
+
&:hover:not(.resizeHandleDisabled) {
|
|
37
|
+
border-width: 3px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&.resizeHandleDisabled {
|
|
41
|
+
cursor: default;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
31
44
|
}
|
|
32
45
|
}
|
|
@@ -40,6 +40,9 @@ const mockProps: ListHeaderProps<TestListHeaderData> = {
|
|
|
40
40
|
actionSize: '50px',
|
|
41
41
|
horizontalTextAlign: 'left',
|
|
42
42
|
verticalTextAlign: 'center',
|
|
43
|
+
hasActionColumn: true,
|
|
44
|
+
onResetColumnSizes: jest.fn(),
|
|
45
|
+
onColumnSizesChanged: jest.fn(),
|
|
43
46
|
};
|
|
44
47
|
|
|
45
48
|
describe('ListHeader', () => {
|
|
@@ -155,4 +158,57 @@ describe('ListHeader', () => {
|
|
|
155
158
|
});
|
|
156
159
|
|
|
157
160
|
it.todo('reacts meaningfully when the columns are empty');
|
|
161
|
+
|
|
162
|
+
describe('Column Resizing', () => {
|
|
163
|
+
it('calls onResetColumnSizes when the reset button is clicked', () => {
|
|
164
|
+
const spy = jest.fn();
|
|
165
|
+
const wrapper = shallow(
|
|
166
|
+
<ListHeader {...mockProps} onResetColumnSizes={spy} />,
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const resetButton = wrapper.find('.resizeHandle').first();
|
|
170
|
+
resetButton.simulate('doubleClick');
|
|
171
|
+
|
|
172
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('calls onResetColumnSizes when the reset button is clicked also on non-resizable column', () => {
|
|
176
|
+
const spy = jest.fn();
|
|
177
|
+
const wrapper = shallow(
|
|
178
|
+
<ListHeader
|
|
179
|
+
{...mockProps}
|
|
180
|
+
columns={[
|
|
181
|
+
{ ...mockListColumns[0], disableResizing: true },
|
|
182
|
+
...mockListColumns.slice(1),
|
|
183
|
+
]}
|
|
184
|
+
onResetColumnSizes={spy}
|
|
185
|
+
/>,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const resetButton = wrapper.find('.resizeHandle').first();
|
|
189
|
+
resetButton.simulate('doubleClick');
|
|
190
|
+
|
|
191
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('calls onColumnSizesChanged when the column is resized', () => {
|
|
195
|
+
const spy = jest.fn();
|
|
196
|
+
const wrapper = mount(
|
|
197
|
+
<ListHeader {...mockProps} onColumnSizesChanged={spy} />,
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const resizeHandle = wrapper.find('.resizeHandle').first();
|
|
201
|
+
resizeHandle.invoke('onMouseDown')!({
|
|
202
|
+
preventDefault: jest.fn(),
|
|
203
|
+
} as any);
|
|
204
|
+
|
|
205
|
+
window.dispatchEvent(
|
|
206
|
+
new Event('mousemove', {
|
|
207
|
+
clientX: 100,
|
|
208
|
+
} as any),
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
158
214
|
});
|
|
@@ -5,6 +5,7 @@ import { Column, SortData } from '../List.model';
|
|
|
5
5
|
import { ListCheckBox } from '../ListCheckBox/ListCheckBox';
|
|
6
6
|
import { ColumnLabel } from './ColumnLabel/ColumnLabel';
|
|
7
7
|
import classes from './ListHeader.scss';
|
|
8
|
+
import { useResize } from './useResize';
|
|
8
9
|
|
|
9
10
|
export interface ListHeaderProps<T extends Data> {
|
|
10
11
|
/** Column definitions */
|
|
@@ -37,6 +38,12 @@ export interface ListHeaderProps<T extends Data> {
|
|
|
37
38
|
onSortChanged?: (sort: SortData<T>) => void;
|
|
38
39
|
/** CSS Class name for additional styles */
|
|
39
40
|
className?: string;
|
|
41
|
+
/** called when the column sizes should be reset */
|
|
42
|
+
onResetColumnSizes: () => void;
|
|
43
|
+
/** called when the column sizes should be updated */
|
|
44
|
+
onColumnSizesChanged: (columnSizes: string) => void;
|
|
45
|
+
/** Whether or not the list has an action column */
|
|
46
|
+
hasActionColumn: boolean;
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
/**
|
|
@@ -66,6 +73,9 @@ export const ListHeader = <T extends Data>({
|
|
|
66
73
|
onCheckboxToggled,
|
|
67
74
|
onSortChanged,
|
|
68
75
|
className = '',
|
|
76
|
+
onResetColumnSizes,
|
|
77
|
+
onColumnSizesChanged,
|
|
78
|
+
hasActionColumn,
|
|
69
79
|
}: PropsWithChildren<ListHeaderProps<T>>): JSX.Element => {
|
|
70
80
|
const customStyles = {
|
|
71
81
|
gridAutoRows: rowHeight,
|
|
@@ -75,15 +85,18 @@ export const ListHeader = <T extends Data>({
|
|
|
75
85
|
alignItems: verticalTextAlign,
|
|
76
86
|
} as React.CSSProperties;
|
|
77
87
|
|
|
88
|
+
const { cols, mouseDown } = useResize(columns, onColumnSizesChanged);
|
|
89
|
+
|
|
78
90
|
return (
|
|
79
91
|
<div
|
|
80
92
|
className={clsx(classes.container, 'list-header-container', className)}
|
|
81
93
|
style={customStyles}
|
|
82
94
|
data-test-id="list-header"
|
|
83
95
|
>
|
|
84
|
-
{columns.map((column) => (
|
|
96
|
+
{columns.map((column, i) => (
|
|
85
97
|
<div
|
|
86
98
|
key={column.propertyName as string}
|
|
99
|
+
ref={cols[i].ref}
|
|
87
100
|
className={clsx(classes.columnLabel)}
|
|
88
101
|
>
|
|
89
102
|
<ColumnLabel<T>
|
|
@@ -94,16 +107,37 @@ export const ListHeader = <T extends Data>({
|
|
|
94
107
|
sortData={sortData}
|
|
95
108
|
onSortChanged={onSortChanged}
|
|
96
109
|
/>
|
|
110
|
+
<div
|
|
111
|
+
onMouseDown={
|
|
112
|
+
!column.disableResizing
|
|
113
|
+
? (e) => {
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
mouseDown(i);
|
|
116
|
+
}
|
|
117
|
+
: undefined
|
|
118
|
+
}
|
|
119
|
+
onDoubleClick={() => onResetColumnSizes()}
|
|
120
|
+
className={clsx(classes.resizeHandle, {
|
|
121
|
+
[classes.resizeHandleDisabled]: column.disableResizing,
|
|
122
|
+
})}
|
|
123
|
+
/>
|
|
97
124
|
</div>
|
|
98
125
|
))}
|
|
99
|
-
{
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
126
|
+
{hasActionColumn && (
|
|
127
|
+
<div
|
|
128
|
+
ref={cols[cols.length - 1].ref}
|
|
129
|
+
className={clsx(classes.columnLabel)}
|
|
130
|
+
>
|
|
131
|
+
{showItemCheckbox && (
|
|
132
|
+
<ListCheckBox
|
|
133
|
+
height={actionSize}
|
|
134
|
+
width={actionSize}
|
|
135
|
+
isChecked={itemSelected}
|
|
136
|
+
isDisabled={isCheckboxDisabled}
|
|
137
|
+
onCheckBoxToggled={onCheckboxToggled}
|
|
138
|
+
/>
|
|
139
|
+
)}
|
|
140
|
+
</div>
|
|
107
141
|
)}
|
|
108
142
|
</div>
|
|
109
143
|
);
|