@etsoo/react 1.3.98 → 1.4.2
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/lib/mu/DnDList.d.ts +2 -2
- package/lib/mu/DnDList.js +17 -3
- package/lib/mu/NotifierMU.js +20 -6
- package/lib/mu/pages/EditPage.js +2 -2
- package/package.json +9 -9
- package/src/mu/DnDList.tsx +27 -5
- package/src/mu/NotifierMU.tsx +33 -6
- package/src/mu/pages/EditPage.tsx +2 -2
package/lib/mu/DnDList.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface DnDListProps<D extends {}, E extends React.ElementType> {
|
|
|
6
6
|
/**
|
|
7
7
|
* Item renderer
|
|
8
8
|
*/
|
|
9
|
-
children: (item: D, index: number, deleteItem: (index: number) => void) => React.ReactNode;
|
|
9
|
+
children: (item: D, index: number, deleteItem: (index: number) => void, editItem: (newItem: D, index: number) => boolean) => React.ReactNode;
|
|
10
10
|
/**
|
|
11
11
|
* List container component
|
|
12
12
|
* https://javascript.plainenglish.io/building-a-polymorphic-component-in-react-and-typescript-d9f236950af4
|
|
@@ -19,7 +19,7 @@ export interface DnDListProps<D extends {}, E extends React.ElementType> {
|
|
|
19
19
|
/**
|
|
20
20
|
* Get list item style callback
|
|
21
21
|
*/
|
|
22
|
-
getItemStyle?: (isDragging: boolean) => CSSProperties;
|
|
22
|
+
getItemStyle?: (isDragging: boolean, index: number) => CSSProperties;
|
|
23
23
|
/**
|
|
24
24
|
* Get list style callback
|
|
25
25
|
*/
|
package/lib/mu/DnDList.js
CHANGED
|
@@ -30,7 +30,7 @@ export function DnDList(props) {
|
|
|
30
30
|
// Add item
|
|
31
31
|
const addItem = (newItem) => {
|
|
32
32
|
// Existence check
|
|
33
|
-
if (items.some((item) => item[labelField]
|
|
33
|
+
if (items.some((item) => item[labelField] === newItem[labelField])) {
|
|
34
34
|
return false;
|
|
35
35
|
}
|
|
36
36
|
// Clone
|
|
@@ -39,6 +39,20 @@ export function DnDList(props) {
|
|
|
39
39
|
setItems(newItems);
|
|
40
40
|
return true;
|
|
41
41
|
};
|
|
42
|
+
// Edit item
|
|
43
|
+
const editItem = (newItem, index) => {
|
|
44
|
+
// Existence check
|
|
45
|
+
if (items.some((item) => item[labelField] === newItem[labelField])) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
// Clone
|
|
49
|
+
const newItems = [...items];
|
|
50
|
+
// Remove the item
|
|
51
|
+
newItems.splice(index, 1, newItem);
|
|
52
|
+
// Update the state
|
|
53
|
+
setItems(newItems);
|
|
54
|
+
return true;
|
|
55
|
+
};
|
|
42
56
|
// Add items
|
|
43
57
|
const addItems = (inputItems) => {
|
|
44
58
|
// Clone
|
|
@@ -79,11 +93,11 @@ export function DnDList(props) {
|
|
|
79
93
|
if (id == null)
|
|
80
94
|
return;
|
|
81
95
|
return (React.createElement(Draggable, { key: id, draggableId: id, index: index }, (provided, snapshot) => (React.createElement("div", { ref: provided.innerRef, ...provided.draggableProps, ...provided.dragHandleProps, style: {
|
|
82
|
-
...getItemStyle(snapshot.isDragging),
|
|
96
|
+
...getItemStyle(snapshot.isDragging, index),
|
|
83
97
|
...provided
|
|
84
98
|
.draggableProps
|
|
85
99
|
.style
|
|
86
|
-
} }, children(item, index, deleteItem)))));
|
|
100
|
+
} }, children(item, index, deleteItem, editItem)))));
|
|
87
101
|
}),
|
|
88
102
|
provided.placeholder))))),
|
|
89
103
|
sideRenderer && sideRenderer(false, addItem, addItems)));
|
package/lib/mu/NotifierMU.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NotificationAlign, NotificationMessageType, NotificationType } from '@etsoo/notificationbase';
|
|
2
|
-
import { Alert, AlertTitle, Backdrop, Box, Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Fade, Slider, Snackbar, styled, Switch, TextField } from '@mui/material';
|
|
2
|
+
import { Alert, AlertTitle, Backdrop, Box, Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Fade, Slider, Snackbar, styled, Switch, TextField, Typography } from '@mui/material';
|
|
3
3
|
import { Error, Info, Help, Warning, Done } from '@mui/icons-material';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { Labels } from '../app/Labels';
|
|
@@ -120,14 +120,21 @@ export class NotificationMU extends NotificationReact {
|
|
|
120
120
|
const labels = Labels.NotificationMU;
|
|
121
121
|
const title = (_a = this.title) !== null && _a !== void 0 ? _a : labels.promptTitle;
|
|
122
122
|
const { cancelLabel = labels.promptCancel, okLabel = labels.promptOK, inputs, type, fullScreen, fullWidth = true, maxWidth, primaryButton, ...rest } = (_b = this.inputProps) !== null && _b !== void 0 ? _b : {};
|
|
123
|
+
const inputRef = React.createRef();
|
|
124
|
+
const errorRef = React.createRef();
|
|
125
|
+
const setError = (error) => {
|
|
126
|
+
if (errorRef.current == null)
|
|
127
|
+
return;
|
|
128
|
+
errorRef.current.innerText = error !== null && error !== void 0 ? error : '';
|
|
129
|
+
};
|
|
123
130
|
const handleSubmit = async (event) => {
|
|
124
131
|
// Result
|
|
125
132
|
let result = undefined;
|
|
133
|
+
const input = inputRef.current;
|
|
126
134
|
if (this.onReturn) {
|
|
127
135
|
// Inputs case, no HTMLForm set to value, set the current form
|
|
128
136
|
if (inputs && value == null)
|
|
129
137
|
value = event.currentTarget.form;
|
|
130
|
-
const input = inputRef.current;
|
|
131
138
|
if (input) {
|
|
132
139
|
if (type === 'date') {
|
|
133
140
|
const dateValue = input.valueAsDate;
|
|
@@ -165,12 +172,18 @@ export class NotificationMU extends NotificationReact {
|
|
|
165
172
|
// Get the value
|
|
166
173
|
// returns false to prevent default dismiss
|
|
167
174
|
const v = await result;
|
|
168
|
-
if (v === false)
|
|
175
|
+
if (v === false) {
|
|
176
|
+
input === null || input === void 0 ? void 0 : input.focus();
|
|
169
177
|
return;
|
|
178
|
+
}
|
|
179
|
+
if (typeof v === 'string') {
|
|
180
|
+
setError(v);
|
|
181
|
+
input === null || input === void 0 ? void 0 : input.focus();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
170
184
|
this.dismiss();
|
|
171
185
|
};
|
|
172
186
|
let localInputs;
|
|
173
|
-
let inputRef = React.createRef();
|
|
174
187
|
let value = undefined;
|
|
175
188
|
if (inputs == null) {
|
|
176
189
|
if (type === 'switch') {
|
|
@@ -180,7 +193,7 @@ export class NotificationMU extends NotificationReact {
|
|
|
180
193
|
localInputs = React.createElement(Slider, { onChange: (_e, v) => (value = v) });
|
|
181
194
|
}
|
|
182
195
|
else {
|
|
183
|
-
localInputs = (React.createElement(TextField, { inputRef: inputRef, autoFocus: true, margin: "dense", fullWidth: true, type: type, required: true, ...rest }));
|
|
196
|
+
localInputs = (React.createElement(TextField, { inputRef: inputRef, onChange: () => setError(undefined), autoFocus: true, margin: "dense", fullWidth: true, type: type, required: true, ...rest }));
|
|
184
197
|
}
|
|
185
198
|
}
|
|
186
199
|
else {
|
|
@@ -193,7 +206,8 @@ export class NotificationMU extends NotificationReact {
|
|
|
193
206
|
React.createElement("span", { className: "dialogTitle" }, title)),
|
|
194
207
|
React.createElement(DialogContent, null,
|
|
195
208
|
React.createElement(DialogContentText, null, this.content),
|
|
196
|
-
localInputs
|
|
209
|
+
localInputs,
|
|
210
|
+
React.createElement(Typography, { variant: "caption", display: "block", ref: errorRef, color: (theme) => theme.palette.error.main })),
|
|
197
211
|
React.createElement(DialogActions, null,
|
|
198
212
|
React.createElement(Button, { color: "secondary", onClick: () => {
|
|
199
213
|
if (this.onReturn)
|
package/lib/mu/pages/EditPage.js
CHANGED
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { Labels } from '../../app/Labels';
|
|
4
4
|
import { MUGlobal } from '../MUGlobal';
|
|
5
5
|
import { CommonPage, CommonPageScrollContainer } from './CommonPage';
|
|
6
|
-
import
|
|
6
|
+
import SaveIcon from '@mui/icons-material/Save';
|
|
7
7
|
/**
|
|
8
8
|
* Edit page
|
|
9
9
|
* @param props Props
|
|
@@ -21,5 +21,5 @@ export function EditPage(props) {
|
|
|
21
21
|
bottom: (theme) => MUGlobal.updateWithTheme(paddings, theme.spacing),
|
|
22
22
|
paddingTop: paddings
|
|
23
23
|
} },
|
|
24
|
-
React.createElement(Button, { variant: "contained", type: "submit", fullWidth: true, startIcon: React.createElement(
|
|
24
|
+
React.createElement(Button, { variant: "contained", type: "submit", fullWidth: true, startIcon: React.createElement(SaveIcon, null) }, labels.save)))));
|
|
25
25
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "TypeScript ReactJs framework",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"@emotion/react": "^11.7.1",
|
|
51
51
|
"@emotion/style": "^0.8.0",
|
|
52
52
|
"@emotion/styled": "^11.6.0",
|
|
53
|
-
"@etsoo/appscript": "^1.2.
|
|
54
|
-
"@etsoo/notificationbase": "^1.0
|
|
53
|
+
"@etsoo/appscript": "^1.2.15",
|
|
54
|
+
"@etsoo/notificationbase": "^1.1.0",
|
|
55
55
|
"@etsoo/shared": "^1.0.97",
|
|
56
56
|
"@mui/icons-material": "^5.2.5",
|
|
57
57
|
"@mui/material": "^5.2.6",
|
|
@@ -76,12 +76,12 @@
|
|
|
76
76
|
"react-window": "^1.8.6"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
-
"@babel/cli": "^7.16.
|
|
80
|
-
"@babel/core": "^7.16.
|
|
81
|
-
"@babel/plugin-transform-runtime": "^7.16.
|
|
82
|
-
"@babel/preset-env": "^7.16.
|
|
83
|
-
"@babel/runtime-corejs3": "^7.16.
|
|
84
|
-
"@types/jest": "^27.0
|
|
79
|
+
"@babel/cli": "^7.16.7",
|
|
80
|
+
"@babel/core": "^7.16.7",
|
|
81
|
+
"@babel/plugin-transform-runtime": "^7.16.7",
|
|
82
|
+
"@babel/preset-env": "^7.16.7",
|
|
83
|
+
"@babel/runtime-corejs3": "^7.16.7",
|
|
84
|
+
"@types/jest": "^27.4.0",
|
|
85
85
|
"@types/react-test-renderer": "^17.0.1",
|
|
86
86
|
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
|
87
87
|
"@typescript-eslint/parser": "^5.8.1",
|
package/src/mu/DnDList.tsx
CHANGED
|
@@ -17,7 +17,8 @@ export interface DnDListProps<D extends {}, E extends React.ElementType> {
|
|
|
17
17
|
children: (
|
|
18
18
|
item: D,
|
|
19
19
|
index: number,
|
|
20
|
-
deleteItem: (index: number) => void
|
|
20
|
+
deleteItem: (index: number) => void,
|
|
21
|
+
editItem: (newItem: D, index: number) => boolean
|
|
21
22
|
) => React.ReactNode;
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -34,7 +35,7 @@ export interface DnDListProps<D extends {}, E extends React.ElementType> {
|
|
|
34
35
|
/**
|
|
35
36
|
* Get list item style callback
|
|
36
37
|
*/
|
|
37
|
-
getItemStyle?: (isDragging: boolean) => CSSProperties;
|
|
38
|
+
getItemStyle?: (isDragging: boolean, index: number) => CSSProperties;
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* Get list style callback
|
|
@@ -115,7 +116,7 @@ export function DnDList<
|
|
|
115
116
|
// Add item
|
|
116
117
|
const addItem = (newItem: D) => {
|
|
117
118
|
// Existence check
|
|
118
|
-
if (items.some((item) => item[labelField]
|
|
119
|
+
if (items.some((item) => item[labelField] === newItem[labelField])) {
|
|
119
120
|
return false;
|
|
120
121
|
}
|
|
121
122
|
|
|
@@ -128,6 +129,25 @@ export function DnDList<
|
|
|
128
129
|
return true;
|
|
129
130
|
};
|
|
130
131
|
|
|
132
|
+
// Edit item
|
|
133
|
+
const editItem = (newItem: D, index: number) => {
|
|
134
|
+
// Existence check
|
|
135
|
+
if (items.some((item) => item[labelField] === newItem[labelField])) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Clone
|
|
140
|
+
const newItems = [...items];
|
|
141
|
+
|
|
142
|
+
// Remove the item
|
|
143
|
+
newItems.splice(index, 1, newItem);
|
|
144
|
+
|
|
145
|
+
// Update the state
|
|
146
|
+
setItems(newItems);
|
|
147
|
+
|
|
148
|
+
return true;
|
|
149
|
+
};
|
|
150
|
+
|
|
131
151
|
// Add items
|
|
132
152
|
const addItems = (inputItems: D[]) => {
|
|
133
153
|
// Clone
|
|
@@ -201,7 +221,8 @@ export function DnDList<
|
|
|
201
221
|
{...provided.dragHandleProps}
|
|
202
222
|
style={{
|
|
203
223
|
...getItemStyle(
|
|
204
|
-
snapshot.isDragging
|
|
224
|
+
snapshot.isDragging,
|
|
225
|
+
index
|
|
205
226
|
),
|
|
206
227
|
...provided
|
|
207
228
|
.draggableProps
|
|
@@ -211,7 +232,8 @@ export function DnDList<
|
|
|
211
232
|
{children(
|
|
212
233
|
item,
|
|
213
234
|
index,
|
|
214
|
-
deleteItem
|
|
235
|
+
deleteItem,
|
|
236
|
+
editItem
|
|
215
237
|
)}
|
|
216
238
|
</div>
|
|
217
239
|
)}
|
package/src/mu/NotifierMU.tsx
CHANGED
|
@@ -25,7 +25,8 @@ import {
|
|
|
25
25
|
Snackbar,
|
|
26
26
|
styled,
|
|
27
27
|
Switch,
|
|
28
|
-
TextField
|
|
28
|
+
TextField,
|
|
29
|
+
Typography
|
|
29
30
|
} from '@mui/material';
|
|
30
31
|
import { Error, Info, Help, Warning, Done } from '@mui/icons-material';
|
|
31
32
|
import React from 'react';
|
|
@@ -238,18 +239,30 @@ export class NotificationMU extends NotificationReact {
|
|
|
238
239
|
...rest
|
|
239
240
|
} = this.inputProps ?? {};
|
|
240
241
|
|
|
242
|
+
const inputRef = React.createRef<HTMLInputElement>();
|
|
243
|
+
const errorRef = React.createRef<HTMLSpanElement>();
|
|
244
|
+
|
|
245
|
+
const setError = (error?: string) => {
|
|
246
|
+
if (errorRef.current == null) return;
|
|
247
|
+
errorRef.current.innerText = error ?? '';
|
|
248
|
+
};
|
|
249
|
+
|
|
241
250
|
const handleSubmit = async (
|
|
242
251
|
event: React.MouseEvent<HTMLButtonElement>
|
|
243
252
|
) => {
|
|
244
253
|
// Result
|
|
245
|
-
let result:
|
|
246
|
-
|
|
254
|
+
let result:
|
|
255
|
+
| boolean
|
|
256
|
+
| string
|
|
257
|
+
| void
|
|
258
|
+
| PromiseLike<boolean | string | void> = undefined;
|
|
259
|
+
|
|
260
|
+
const input = inputRef.current;
|
|
247
261
|
|
|
248
262
|
if (this.onReturn) {
|
|
249
263
|
// Inputs case, no HTMLForm set to value, set the current form
|
|
250
264
|
if (inputs && value == null) value = event.currentTarget.form;
|
|
251
265
|
|
|
252
|
-
const input = inputRef.current;
|
|
253
266
|
if (input) {
|
|
254
267
|
if (type === 'date') {
|
|
255
268
|
const dateValue = input.valueAsDate;
|
|
@@ -284,13 +297,20 @@ export class NotificationMU extends NotificationReact {
|
|
|
284
297
|
// Get the value
|
|
285
298
|
// returns false to prevent default dismiss
|
|
286
299
|
const v = await result;
|
|
287
|
-
if (v === false)
|
|
300
|
+
if (v === false) {
|
|
301
|
+
input?.focus();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (typeof v === 'string') {
|
|
305
|
+
setError(v);
|
|
306
|
+
input?.focus();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
288
309
|
|
|
289
310
|
this.dismiss();
|
|
290
311
|
};
|
|
291
312
|
|
|
292
313
|
let localInputs: React.ReactNode;
|
|
293
|
-
let inputRef = React.createRef<HTMLInputElement>();
|
|
294
314
|
let value: any = undefined;
|
|
295
315
|
|
|
296
316
|
if (inputs == null) {
|
|
@@ -310,6 +330,7 @@ export class NotificationMU extends NotificationReact {
|
|
|
310
330
|
localInputs = (
|
|
311
331
|
<TextField
|
|
312
332
|
inputRef={inputRef}
|
|
333
|
+
onChange={() => setError(undefined)}
|
|
313
334
|
autoFocus
|
|
314
335
|
margin="dense"
|
|
315
336
|
fullWidth
|
|
@@ -341,6 +362,12 @@ export class NotificationMU extends NotificationReact {
|
|
|
341
362
|
<DialogContent>
|
|
342
363
|
<DialogContentText>{this.content}</DialogContentText>
|
|
343
364
|
{localInputs}
|
|
365
|
+
<Typography
|
|
366
|
+
variant="caption"
|
|
367
|
+
display="block"
|
|
368
|
+
ref={errorRef}
|
|
369
|
+
color={(theme) => theme.palette.error.main}
|
|
370
|
+
/>
|
|
344
371
|
</DialogContent>
|
|
345
372
|
<DialogActions>
|
|
346
373
|
<Button
|
|
@@ -6,7 +6,7 @@ import { Labels } from '../../app/Labels';
|
|
|
6
6
|
import { MUGlobal } from '../MUGlobal';
|
|
7
7
|
import { CommonPage, CommonPageScrollContainer } from './CommonPage';
|
|
8
8
|
import { CommonPageProps } from './CommonPageProps';
|
|
9
|
-
import
|
|
9
|
+
import SaveIcon from '@mui/icons-material/Save';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Edit page router props, include 'id' (/:id) query parameter
|
|
@@ -70,7 +70,7 @@ export function EditPage(props: EditPageProps) {
|
|
|
70
70
|
variant="contained"
|
|
71
71
|
type="submit"
|
|
72
72
|
fullWidth
|
|
73
|
-
startIcon={<
|
|
73
|
+
startIcon={<SaveIcon />}
|
|
74
74
|
>
|
|
75
75
|
{labels.save}
|
|
76
76
|
</Button>
|