@axinom/mosaic-ui 0.35.0-rc.7 → 0.35.0-rc.9
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 +5 -14
- package/dist/components/DynamicDataList/DynamicDataList.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.d.ts +3 -1
- package/dist/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListHeader/DynamicListHeader.d.ts +5 -1
- package/dist/components/DynamicDataList/DynamicListHeader/DynamicListHeader.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListRow/DynamicListRow.d.ts +9 -10
- package/dist/components/DynamicDataList/DynamicListRow/DynamicListRow.d.ts.map +1 -1
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.actions.d.ts +5 -0
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.actions.d.ts.map +1 -0
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.d.ts +4 -0
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.d.ts.map +1 -0
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.init.d.ts +4 -0
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.init.d.ts.map +1 -0
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.types.d.ts +38 -0
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.types.d.ts.map +1 -0
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/index.d.ts +4 -0
- package/dist/components/DynamicDataList/helpers/DynamicListReducer/index.d.ts.map +1 -0
- package/dist/components/DynamicDataList/helpers/generateId.d.ts +6 -0
- package/dist/components/DynamicDataList/helpers/generateId.d.ts.map +1 -0
- package/dist/components/DynamicDataList/helpers/useColumnDefs.d.ts +14 -0
- package/dist/components/DynamicDataList/helpers/useColumnDefs.d.ts.map +1 -0
- package/dist/components/DynamicDataList/helpers/useDataHandler.d.ts +9 -0
- package/dist/components/DynamicDataList/helpers/useDataHandler.d.ts.map +1 -0
- package/dist/components/DynamicDataList/helpers/useRowAnimation.d.ts +12 -0
- package/dist/components/DynamicDataList/helpers/useRowAnimation.d.ts.map +1 -0
- package/dist/components/DynamicDataList/index.d.ts +1 -1
- package/dist/components/DynamicDataList/index.d.ts.map +1 -1
- package/dist/index.es.js +11 -3
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/components/DynamicDataList/DynamicDataList.scss +0 -61
- package/src/components/DynamicDataList/DynamicDataList.spec.tsx +126 -393
- package/src/components/DynamicDataList/DynamicDataList.stories.tsx +0 -5
- package/src/components/DynamicDataList/DynamicDataList.tsx +133 -600
- package/src/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.scss +4 -2
- package/src/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.spec.tsx +17 -44
- package/src/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.tsx +15 -22
- package/src/components/DynamicDataList/DynamicListHeader/DynamicListHeader.scss +15 -10
- package/src/components/DynamicDataList/DynamicListHeader/DynamicListHeader.spec.tsx +4 -1
- package/src/components/DynamicDataList/DynamicListHeader/DynamicListHeader.tsx +16 -14
- package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.scss +16 -24
- package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.spec.tsx +26 -253
- package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.tsx +45 -139
- package/src/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.actions.spec.ts +276 -0
- package/src/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.actions.ts +86 -0
- package/src/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.init.spec.ts +118 -0
- package/src/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.init.ts +40 -0
- package/src/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.spec.ts +89 -0
- package/src/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.ts +42 -0
- package/src/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.types.ts +46 -0
- package/src/components/DynamicDataList/helpers/DynamicListReducer/index.ts +3 -0
- package/src/components/DynamicDataList/helpers/generateId.ts +10 -0
- package/src/components/DynamicDataList/helpers/useColumnDefs.ts +56 -0
- package/src/components/DynamicDataList/helpers/useDataHandler.ts +77 -0
- package/src/components/DynamicDataList/helpers/useRowAnimation.tsx +38 -0
- package/src/components/DynamicDataList/index.ts +2 -2
- package/src/components/DynamicDataList/DynamicDataList.reposition.spec.tsx +0 -816
package/src/components/DynamicDataList/helpers/DynamicListReducer/DynamicListReducer.init.spec.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { DynamicListReducerInit } from './DynamicListReducer.init';
|
|
2
|
+
|
|
3
|
+
interface Data {
|
|
4
|
+
position?: number;
|
|
5
|
+
id: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const dataSet: Data[] = [
|
|
9
|
+
{ position: 1, id: 1 },
|
|
10
|
+
{ position: 2, id: 2 },
|
|
11
|
+
{ position: 5, id: 5 },
|
|
12
|
+
{ position: 6, id: 6 },
|
|
13
|
+
{ position: 7, id: 7 },
|
|
14
|
+
{ position: 8, id: 8 },
|
|
15
|
+
{ position: 20, id: 20 },
|
|
16
|
+
{ position: 100, id: 100 },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
describe('Dynamic List Reducer Init', () => {
|
|
20
|
+
it('generates the initial state', () => {
|
|
21
|
+
const result = DynamicListReducerInit({
|
|
22
|
+
initialValue: dataSet,
|
|
23
|
+
positionPropertyName: 'position',
|
|
24
|
+
allowNewData: true,
|
|
25
|
+
maxItemLimit: 10,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(result).toStrictEqual({
|
|
29
|
+
items: dataSet,
|
|
30
|
+
nextPosition: 101,
|
|
31
|
+
canAddItems: true,
|
|
32
|
+
positionPropertyName: 'position',
|
|
33
|
+
maxItemLimit: 10,
|
|
34
|
+
allowNewData: true,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('sorts the data when positionPropertyName is defined', () => {
|
|
39
|
+
const data = [
|
|
40
|
+
{ position: 5, id: 5 },
|
|
41
|
+
{ position: 2, id: 2 },
|
|
42
|
+
{ position: 6, id: 6 },
|
|
43
|
+
{ position: 1, id: 1 },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const result = DynamicListReducerInit({
|
|
47
|
+
initialValue: data,
|
|
48
|
+
positionPropertyName: 'position',
|
|
49
|
+
allowNewData: true,
|
|
50
|
+
maxItemLimit: 10,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(result.items).toEqual([
|
|
54
|
+
{ position: 1, id: 1 },
|
|
55
|
+
{ position: 2, id: 2 },
|
|
56
|
+
{ position: 5, id: 5 },
|
|
57
|
+
{ position: 6, id: 6 },
|
|
58
|
+
]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('calculates the next position', () => {
|
|
62
|
+
expect(
|
|
63
|
+
DynamicListReducerInit({
|
|
64
|
+
initialValue: dataSet,
|
|
65
|
+
positionPropertyName: 'position',
|
|
66
|
+
allowNewData: true,
|
|
67
|
+
maxItemLimit: 10,
|
|
68
|
+
}).nextPosition,
|
|
69
|
+
).toBe(101);
|
|
70
|
+
|
|
71
|
+
expect(
|
|
72
|
+
DynamicListReducerInit({
|
|
73
|
+
initialValue: dataSet.slice(0, dataSet.length - 1),
|
|
74
|
+
positionPropertyName: 'position',
|
|
75
|
+
allowNewData: true,
|
|
76
|
+
maxItemLimit: 10,
|
|
77
|
+
}).nextPosition,
|
|
78
|
+
).toBe(21);
|
|
79
|
+
|
|
80
|
+
expect(
|
|
81
|
+
DynamicListReducerInit({
|
|
82
|
+
initialValue: [],
|
|
83
|
+
positionPropertyName: 'position',
|
|
84
|
+
allowNewData: true,
|
|
85
|
+
maxItemLimit: 10,
|
|
86
|
+
}).nextPosition,
|
|
87
|
+
).toBe(1);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('calculates canAddItems', () => {
|
|
91
|
+
expect(
|
|
92
|
+
DynamicListReducerInit({
|
|
93
|
+
initialValue: dataSet,
|
|
94
|
+
positionPropertyName: 'position',
|
|
95
|
+
allowNewData: true,
|
|
96
|
+
maxItemLimit: 10,
|
|
97
|
+
}).canAddItems,
|
|
98
|
+
).toBe(true);
|
|
99
|
+
|
|
100
|
+
expect(
|
|
101
|
+
DynamicListReducerInit({
|
|
102
|
+
initialValue: dataSet,
|
|
103
|
+
positionPropertyName: 'position',
|
|
104
|
+
allowNewData: true,
|
|
105
|
+
maxItemLimit: 5,
|
|
106
|
+
}).canAddItems,
|
|
107
|
+
).toBe(false);
|
|
108
|
+
|
|
109
|
+
expect(
|
|
110
|
+
DynamicListReducerInit({
|
|
111
|
+
initialValue: dataSet,
|
|
112
|
+
positionPropertyName: 'position',
|
|
113
|
+
allowNewData: false,
|
|
114
|
+
maxItemLimit: 10,
|
|
115
|
+
}).canAddItems,
|
|
116
|
+
).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Data } from '../../../../types';
|
|
2
|
+
import {
|
|
3
|
+
DynamicListReducerInitArgs,
|
|
4
|
+
DynamicListReducerState,
|
|
5
|
+
} from './DynamicListReducer.types';
|
|
6
|
+
|
|
7
|
+
export const DynamicListReducerInit = <T extends Data>(
|
|
8
|
+
args: DynamicListReducerInitArgs<T>,
|
|
9
|
+
): DynamicListReducerState<T> => {
|
|
10
|
+
const { initialValue, positionPropertyName, maxItemLimit, allowNewData } =
|
|
11
|
+
args;
|
|
12
|
+
|
|
13
|
+
const newState: DynamicListReducerState<T> = {
|
|
14
|
+
items: initialValue,
|
|
15
|
+
nextPosition: 1,
|
|
16
|
+
canAddItems: false,
|
|
17
|
+
positionPropertyName,
|
|
18
|
+
maxItemLimit,
|
|
19
|
+
allowNewData,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (positionPropertyName !== undefined && initialValue.length > 0) {
|
|
23
|
+
const sortedValue = [...initialValue].sort(
|
|
24
|
+
(a, b) =>
|
|
25
|
+
Number(a[positionPropertyName]) - Number(b[positionPropertyName]),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
newState.nextPosition =
|
|
29
|
+
sortedValue[sortedValue.length - 1][positionPropertyName] + 1;
|
|
30
|
+
|
|
31
|
+
newState.items = sortedValue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
newState.canAddItems =
|
|
35
|
+
allowNewData &&
|
|
36
|
+
((maxItemLimit !== undefined && newState.items.length < maxItemLimit) ||
|
|
37
|
+
maxItemLimit === undefined);
|
|
38
|
+
|
|
39
|
+
return newState;
|
|
40
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { DynamicListReducer } from './DynamicListReducer';
|
|
2
|
+
import { addItem, removeItem } from './DynamicListReducer.actions';
|
|
3
|
+
import { DynamicListReducerInit } from './DynamicListReducer.init';
|
|
4
|
+
import {
|
|
5
|
+
DynamicListReducerActionType,
|
|
6
|
+
DynamicListReducerState,
|
|
7
|
+
} from './DynamicListReducer.types';
|
|
8
|
+
|
|
9
|
+
jest.mock('./DynamicListReducer.init');
|
|
10
|
+
jest.mock('./DynamicListReducer.actions');
|
|
11
|
+
|
|
12
|
+
interface Data {
|
|
13
|
+
position?: number;
|
|
14
|
+
id: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const dataSet: Data[] = [
|
|
18
|
+
{ position: 1, id: 1 },
|
|
19
|
+
{ position: 2, id: 2 },
|
|
20
|
+
{ position: 5, id: 5 },
|
|
21
|
+
{ position: 6, id: 6 },
|
|
22
|
+
{ position: 7, id: 7 },
|
|
23
|
+
{ position: 8, id: 8 },
|
|
24
|
+
{ position: 20, id: 20 },
|
|
25
|
+
{ position: 100, id: 100 },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const initialState: DynamicListReducerState<Data> = {
|
|
29
|
+
items: dataSet,
|
|
30
|
+
nextPosition: 1,
|
|
31
|
+
canAddItems: false,
|
|
32
|
+
positionPropertyName: 'position',
|
|
33
|
+
maxItemLimit: 10,
|
|
34
|
+
allowNewData: true,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
describe('Dynamic List Reducer', () => {
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
jest.clearAllMocks();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('calls addItem and DynamicListReducerInit when action is add', () => {
|
|
43
|
+
DynamicListReducer(initialState, {
|
|
44
|
+
type: DynamicListReducerActionType.Add,
|
|
45
|
+
item: { id: 10, position: 10 },
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(addItem).toHaveBeenCalledTimes(1);
|
|
49
|
+
expect(addItem).toHaveBeenCalledWith(
|
|
50
|
+
{ id: 10, position: 10 },
|
|
51
|
+
dataSet,
|
|
52
|
+
'position',
|
|
53
|
+
);
|
|
54
|
+
expect(DynamicListReducerInit).toHaveBeenCalledTimes(1);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('calls removeItem and DynamicListReducerInit when action is remove', () => {
|
|
58
|
+
DynamicListReducer(initialState, {
|
|
59
|
+
type: DynamicListReducerActionType.Remove,
|
|
60
|
+
item: { id: 10, position: 10 },
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(removeItem).toHaveBeenCalledTimes(1);
|
|
64
|
+
expect(removeItem).toHaveBeenCalledWith(
|
|
65
|
+
{ id: 10, position: 10 },
|
|
66
|
+
dataSet,
|
|
67
|
+
'position',
|
|
68
|
+
);
|
|
69
|
+
expect(DynamicListReducerInit).toHaveBeenCalledTimes(1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('calls DynamicListReducerInit with new items when action is reset', () => {
|
|
73
|
+
DynamicListReducer(initialState, {
|
|
74
|
+
type: DynamicListReducerActionType.Reset,
|
|
75
|
+
items: dataSet,
|
|
76
|
+
positionPropertyName: 'id',
|
|
77
|
+
maxItemLimit: 5,
|
|
78
|
+
allowNewData: false,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
expect(DynamicListReducerInit).toHaveBeenCalledTimes(1);
|
|
82
|
+
expect(DynamicListReducerInit).toHaveBeenCalledWith({
|
|
83
|
+
initialValue: dataSet,
|
|
84
|
+
positionPropertyName: 'id',
|
|
85
|
+
maxItemLimit: 5,
|
|
86
|
+
allowNewData: false,
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Data } from '../../../../types';
|
|
2
|
+
import { addItem, removeItem } from './DynamicListReducer.actions';
|
|
3
|
+
import { DynamicListReducerInit } from './DynamicListReducer.init';
|
|
4
|
+
import {
|
|
5
|
+
DynamicListReducerAction,
|
|
6
|
+
DynamicListReducerActionType,
|
|
7
|
+
DynamicListReducerState,
|
|
8
|
+
} from './DynamicListReducer.types';
|
|
9
|
+
|
|
10
|
+
export const DynamicListReducer = <T extends Data>(
|
|
11
|
+
state: DynamicListReducerState<T>,
|
|
12
|
+
action: DynamicListReducerAction<T>,
|
|
13
|
+
): DynamicListReducerState<T> => {
|
|
14
|
+
let { positionPropertyName, allowNewData, maxItemLimit } = state;
|
|
15
|
+
|
|
16
|
+
let newItems: T[] = [];
|
|
17
|
+
|
|
18
|
+
switch (action.type) {
|
|
19
|
+
case DynamicListReducerActionType.Add:
|
|
20
|
+
newItems = addItem(action.item, state.items, positionPropertyName);
|
|
21
|
+
break;
|
|
22
|
+
case DynamicListReducerActionType.Remove:
|
|
23
|
+
newItems = removeItem(action.item, state.items, positionPropertyName);
|
|
24
|
+
break;
|
|
25
|
+
case DynamicListReducerActionType.Reset:
|
|
26
|
+
newItems = action.items;
|
|
27
|
+
positionPropertyName = action.positionPropertyName;
|
|
28
|
+
maxItemLimit = action.maxItemLimit;
|
|
29
|
+
allowNewData = action.allowNewData;
|
|
30
|
+
break;
|
|
31
|
+
default:
|
|
32
|
+
throw new Error();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Init function can also be used as a refresher. This re-orders the items and re-calculates the next position and canAddItems
|
|
36
|
+
return DynamicListReducerInit({
|
|
37
|
+
initialValue: newItems,
|
|
38
|
+
positionPropertyName,
|
|
39
|
+
maxItemLimit,
|
|
40
|
+
allowNewData,
|
|
41
|
+
});
|
|
42
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Data } from '../../../../types';
|
|
2
|
+
|
|
3
|
+
export interface DynamicListReducerInitArgs<T extends Data> {
|
|
4
|
+
initialValue: T[];
|
|
5
|
+
positionPropertyName: keyof T | undefined;
|
|
6
|
+
maxItemLimit: number | undefined;
|
|
7
|
+
allowNewData: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export enum DynamicListReducerActionType {
|
|
11
|
+
Add = 'add',
|
|
12
|
+
Remove = 'remove',
|
|
13
|
+
Reset = 'reset',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type DynamicListReducerAction<T extends Data> =
|
|
17
|
+
| DynamicListReducerAddAction<T>
|
|
18
|
+
| DynamicListReducerRemoveAction<T>
|
|
19
|
+
| DynamicListReducerResetAction<T>;
|
|
20
|
+
|
|
21
|
+
interface DynamicListReducerAddAction<T extends Data> {
|
|
22
|
+
type: DynamicListReducerActionType.Add;
|
|
23
|
+
item: T;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface DynamicListReducerRemoveAction<T extends Data> {
|
|
27
|
+
type: DynamicListReducerActionType.Remove;
|
|
28
|
+
item: T;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface DynamicListReducerResetAction<T extends Data> {
|
|
32
|
+
type: DynamicListReducerActionType.Reset;
|
|
33
|
+
items: T[];
|
|
34
|
+
allowNewData: boolean;
|
|
35
|
+
maxItemLimit: number | undefined;
|
|
36
|
+
positionPropertyName: keyof T | undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DynamicListReducerState<T extends Data> {
|
|
40
|
+
items: T[];
|
|
41
|
+
nextPosition: number;
|
|
42
|
+
canAddItems: boolean;
|
|
43
|
+
positionPropertyName: keyof T | undefined;
|
|
44
|
+
maxItemLimit: number | undefined;
|
|
45
|
+
allowNewData: boolean;
|
|
46
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple UUID generator. This is not a cryptographically secure generator.
|
|
3
|
+
* @returns UUID
|
|
4
|
+
*/
|
|
5
|
+
export const uuid = (): string => {
|
|
6
|
+
const url = URL.createObjectURL(new Blob());
|
|
7
|
+
const [id] = url.toString().split('/').reverse();
|
|
8
|
+
URL.revokeObjectURL(url);
|
|
9
|
+
return id;
|
|
10
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Data } from '../../../types';
|
|
2
|
+
import { DynamicListColumn } from '../DynamicDataList.model';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generates a combined string of all columns.columnSize values, to be used as CSS value
|
|
6
|
+
* Also produces property key which is used for positioning
|
|
7
|
+
* @param columns The list of columns that should be used
|
|
8
|
+
* @returns a string that consists of defined column sizes and a position key that maps to a data property
|
|
9
|
+
*/
|
|
10
|
+
export const useColumnDefs = function <T extends Data>(
|
|
11
|
+
columns: DynamicListColumn<T>[],
|
|
12
|
+
allowReordering: boolean,
|
|
13
|
+
allowNewData: boolean,
|
|
14
|
+
allowRowDragging: boolean,
|
|
15
|
+
positionKey?: keyof T,
|
|
16
|
+
showInlineMenu?: boolean,
|
|
17
|
+
): {
|
|
18
|
+
readonly columnSizes: string;
|
|
19
|
+
readonly showPositionColumn: boolean;
|
|
20
|
+
readonly showActionColumn: boolean;
|
|
21
|
+
} {
|
|
22
|
+
let positionColumn = '';
|
|
23
|
+
let actionColumn = '';
|
|
24
|
+
let showPositionColumn = false;
|
|
25
|
+
let showActionColumn = false;
|
|
26
|
+
|
|
27
|
+
const columnDefinition = columns
|
|
28
|
+
.filter((columns) => columns.propertyName !== positionKey) // do not allow a column to be created for 'position'
|
|
29
|
+
.reduce((prev, current) => `${prev} ${current.size ?? '1fr'}`, '')
|
|
30
|
+
.trim();
|
|
31
|
+
|
|
32
|
+
// only show position column if allowReordering is true and the positionKey exists
|
|
33
|
+
if (allowReordering && positionKey !== undefined) {
|
|
34
|
+
if (allowRowDragging === true) {
|
|
35
|
+
positionColumn = '100px';
|
|
36
|
+
} else {
|
|
37
|
+
positionColumn = '50px';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
showPositionColumn = true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (allowNewData || showInlineMenu) {
|
|
44
|
+
actionColumn = '50px';
|
|
45
|
+
showActionColumn = true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const columnSizes =
|
|
49
|
+
`${positionColumn} ${columnDefinition} ${actionColumn}`.trim();
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
columnSizes,
|
|
53
|
+
showPositionColumn,
|
|
54
|
+
showActionColumn,
|
|
55
|
+
} as const;
|
|
56
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Reducer, useEffect, useReducer, useState } from 'react';
|
|
2
|
+
import { Data } from '../../../types';
|
|
3
|
+
import {
|
|
4
|
+
DynamicListReducer,
|
|
5
|
+
DynamicListReducerAction,
|
|
6
|
+
DynamicListReducerActionType,
|
|
7
|
+
DynamicListReducerInit,
|
|
8
|
+
DynamicListReducerInitArgs,
|
|
9
|
+
DynamicListReducerState,
|
|
10
|
+
} from './DynamicListReducer';
|
|
11
|
+
|
|
12
|
+
export const useDataHandler = <T extends Data>(
|
|
13
|
+
initialValue: T[],
|
|
14
|
+
positionPropertyName: keyof T | undefined,
|
|
15
|
+
maxItemLimit: number | undefined,
|
|
16
|
+
allowNewData: boolean,
|
|
17
|
+
onChange: (value: T[]) => void,
|
|
18
|
+
onAddTransformData?: (data: Partial<T>) => T,
|
|
19
|
+
): {
|
|
20
|
+
readonly items: T[];
|
|
21
|
+
readonly nextPosition: number;
|
|
22
|
+
readonly canAddItems: boolean;
|
|
23
|
+
readonly addItem: (item: T) => void;
|
|
24
|
+
readonly removeItem: (item: T) => void;
|
|
25
|
+
} => {
|
|
26
|
+
const [shouldTriggerOnChange, setShouldTriggerOnChange] = useState(false);
|
|
27
|
+
|
|
28
|
+
const [state, dispatch] = useReducer<
|
|
29
|
+
Reducer<DynamicListReducerState<T>, DynamicListReducerAction<T>>,
|
|
30
|
+
DynamicListReducerInitArgs<T>
|
|
31
|
+
>(
|
|
32
|
+
DynamicListReducer,
|
|
33
|
+
{
|
|
34
|
+
initialValue,
|
|
35
|
+
positionPropertyName,
|
|
36
|
+
maxItemLimit,
|
|
37
|
+
allowNewData,
|
|
38
|
+
},
|
|
39
|
+
DynamicListReducerInit,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
// Reset the reducer data to new initial value
|
|
44
|
+
dispatch({
|
|
45
|
+
type: DynamicListReducerActionType.Reset,
|
|
46
|
+
items: initialValue,
|
|
47
|
+
positionPropertyName,
|
|
48
|
+
maxItemLimit,
|
|
49
|
+
allowNewData,
|
|
50
|
+
});
|
|
51
|
+
}, [allowNewData, initialValue, maxItemLimit, positionPropertyName]);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
// This is to prevent the onChange from being triggered on the initial render
|
|
55
|
+
if (shouldTriggerOnChange) {
|
|
56
|
+
onChange(state.items);
|
|
57
|
+
setShouldTriggerOnChange(false);
|
|
58
|
+
}
|
|
59
|
+
}, [onChange, shouldTriggerOnChange, state.items]);
|
|
60
|
+
|
|
61
|
+
const addItem = (item: T): void => {
|
|
62
|
+
dispatch({
|
|
63
|
+
type: DynamicListReducerActionType.Add,
|
|
64
|
+
item: onAddTransformData ? onAddTransformData(item) : item,
|
|
65
|
+
});
|
|
66
|
+
setShouldTriggerOnChange(true);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const removeItem = (item: T): void => {
|
|
70
|
+
dispatch({ type: DynamicListReducerActionType.Remove, item });
|
|
71
|
+
setShouldTriggerOnChange(true);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const { items, nextPosition, canAddItems } = state;
|
|
75
|
+
|
|
76
|
+
return { items, nextPosition, canAddItems, addItem, removeItem };
|
|
77
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { Data } from '../../../types';
|
|
3
|
+
|
|
4
|
+
interface RowAnimationProps<T> {
|
|
5
|
+
data: T;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const useRowAnimation = <T extends Data>(): {
|
|
9
|
+
AnimatedRow: React.FC<RowAnimationProps<T>>;
|
|
10
|
+
setLastAddedItem: React.Dispatch<React.SetStateAction<T | undefined>>;
|
|
11
|
+
setShouldAnimate: React.Dispatch<React.SetStateAction<boolean>>;
|
|
12
|
+
} => {
|
|
13
|
+
const [lastAddedItem, setLastAddedItem] = React.useState<T | undefined>();
|
|
14
|
+
const [shouldAnimate, setShouldAnimate] = React.useState<boolean>(false);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (shouldAnimate && lastRowRef.current) {
|
|
18
|
+
lastRowRef.current.scrollIntoView({
|
|
19
|
+
behavior: 'smooth',
|
|
20
|
+
block: 'nearest',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
setShouldAnimate(false);
|
|
24
|
+
}
|
|
25
|
+
}, [shouldAnimate]);
|
|
26
|
+
|
|
27
|
+
const lastRowRef = React.useRef<HTMLDivElement>(null);
|
|
28
|
+
|
|
29
|
+
const AnimatedRow: React.FC<RowAnimationProps<T>> = ({ data, children }) => {
|
|
30
|
+
return (
|
|
31
|
+
<div ref={lastAddedItem === data ? lastRowRef : undefined}>
|
|
32
|
+
{children}
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return { AnimatedRow, setLastAddedItem, setShouldAnimate };
|
|
38
|
+
};
|
|
@@ -2,8 +2,8 @@ export * from './DynamicDataList';
|
|
|
2
2
|
export * from './DynamicDataList.model';
|
|
3
3
|
export * from './DynamicListDataEntry';
|
|
4
4
|
export {
|
|
5
|
-
createInputRenderer,
|
|
6
5
|
CreateInputRendererConfig,
|
|
7
|
-
createSelectRenderer,
|
|
8
6
|
CreateSelectRendererConfig,
|
|
7
|
+
createInputRenderer,
|
|
8
|
+
createSelectRenderer,
|
|
9
9
|
} from './DynamicListDataEntry/Renderers';
|