@etsoo/react 1.2.13 → 1.2.17

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.
@@ -16,7 +16,6 @@ import {
16
16
  Button,
17
17
  CircularProgress,
18
18
  CircularProgressProps,
19
- ClassNameMap,
20
19
  Dialog,
21
20
  DialogActions,
22
21
  DialogContent,
@@ -35,10 +34,10 @@ import { Labels } from '../app/Labels';
35
34
  import {
36
35
  INotificationReact,
37
36
  NotificationReact,
37
+ NotificationReactCallProps,
38
38
  NotifierReact
39
39
  } from '../notifier/Notifier';
40
40
  import { DraggablePaperComponent } from './DraggablePaperComponent';
41
- import { NotifierPromptProps } from './NotifierPromptProps';
42
41
  import { LoadingButton } from './LoadingButton';
43
42
 
44
43
  // Custom icon dialog title bar
@@ -69,13 +68,16 @@ export class NotificationMU extends NotificationReact {
69
68
  }
70
69
 
71
70
  // Create alert
72
- private createAlert(
73
- _props: NotificationRenderProps,
74
- className: string,
75
- classes: ClassNameMap<string>
76
- ) {
71
+ private createAlert(_props: NotificationRenderProps, className: string) {
77
72
  const labels = Labels.NotificationMU;
78
73
 
74
+ const {
75
+ inputs,
76
+ fullScreen,
77
+ fullWidth = true,
78
+ maxWidth
79
+ } = this.inputProps ?? {};
80
+
79
81
  let title = this.title;
80
82
  let icon: React.ReactNode;
81
83
  if (this.type === NotificationMessageType.Success) {
@@ -98,16 +100,17 @@ export class NotificationMU extends NotificationReact {
98
100
  open={this.open}
99
101
  PaperComponent={DraggablePaperComponent}
100
102
  className={className}
103
+ fullWidth={fullWidth}
104
+ maxWidth={maxWidth}
105
+ fullScreen={fullScreen}
101
106
  >
102
- <IconDialogTitle
103
- className={classes.iconTitle}
104
- id="draggable-dialog-title"
105
- >
107
+ <IconDialogTitle id="draggable-dialog-title">
106
108
  {icon}
107
109
  <span className="dialogTitle">{title}</span>
108
110
  </IconDialogTitle>
109
111
  <DialogContent>
110
112
  <DialogContentText>{this.content}</DialogContentText>
113
+ {inputs}
111
114
  </DialogContent>
112
115
  <DialogActions>
113
116
  <LoadingButton
@@ -123,16 +126,21 @@ export class NotificationMU extends NotificationReact {
123
126
  }
124
127
 
125
128
  // Create confirm
126
- private createConfirm(
127
- _props: NotificationRenderProps,
128
- className: string,
129
- classes: ClassNameMap<string>
130
- ) {
129
+ private createConfirm(_props: NotificationRenderProps, className: string) {
131
130
  const labels = Labels.NotificationMU;
132
131
  const title = this.title ?? labels.confirmTitle;
133
132
 
134
- const noLabel = labels.confirmNo;
135
- const yesLabel = labels.confirmYes;
133
+ const {
134
+ okLabel,
135
+ cancelLabel,
136
+ inputs,
137
+ fullScreen,
138
+ fullWidth = true,
139
+ maxWidth
140
+ } = this.inputProps ?? {};
141
+
142
+ const noLabel = cancelLabel ?? labels.confirmNo;
143
+ const yesLabel = okLabel ?? labels.confirmYes;
136
144
 
137
145
  return (
138
146
  <Dialog
@@ -140,16 +148,17 @@ export class NotificationMU extends NotificationReact {
140
148
  open={this.open}
141
149
  PaperComponent={DraggablePaperComponent}
142
150
  className={className}
151
+ fullWidth={fullWidth}
152
+ maxWidth={maxWidth}
153
+ fullScreen={fullScreen}
143
154
  >
144
- <IconDialogTitle
145
- className={classes.iconTitle}
146
- id="draggable-dialog-title"
147
- >
155
+ <IconDialogTitle id="draggable-dialog-title">
148
156
  <Help color="action" />
149
157
  <span className="dialogTitle">{title}</span>
150
158
  </IconDialogTitle>
151
159
  <DialogContent>
152
160
  <DialogContentText>{this.content}</DialogContentText>
161
+ {inputs}
153
162
  </DialogContent>
154
163
  <DialogActions>
155
164
  <LoadingButton
@@ -178,11 +187,7 @@ export class NotificationMU extends NotificationReact {
178
187
  }
179
188
 
180
189
  // Create message
181
- private createMessage(
182
- _props: NotificationRenderProps,
183
- className: string,
184
- _classes: ClassNameMap<string>
185
- ) {
190
+ private createMessage(_props: NotificationRenderProps, className: string) {
186
191
  if (!this.open) return <React.Fragment key={this.id}></React.Fragment>;
187
192
 
188
193
  const setupProps: AlertProps = {
@@ -208,11 +213,7 @@ export class NotificationMU extends NotificationReact {
208
213
  }
209
214
 
210
215
  // Create prompt
211
- private createPrompt(
212
- _props: NotificationRenderProps,
213
- className: string,
214
- classes: ClassNameMap<string>
215
- ) {
216
+ private createPrompt(_props: NotificationRenderProps, className: string) {
216
217
  const labels = Labels.NotificationMU;
217
218
  const title = this.title ?? labels.promptTitle;
218
219
 
@@ -221,8 +222,11 @@ export class NotificationMU extends NotificationReact {
221
222
  okLabel = labels.promptOK,
222
223
  inputs,
223
224
  type,
225
+ fullScreen,
226
+ fullWidth = true,
227
+ maxWidth,
224
228
  ...rest
225
- } = this.inputProps as NotifierPromptProps;
229
+ } = this.inputProps ?? {};
226
230
 
227
231
  const handleSubmit = async (
228
232
  event: React.MouseEvent<HTMLButtonElement>
@@ -286,6 +290,7 @@ export class NotificationMU extends NotificationReact {
286
290
  {...rest}
287
291
  value="true"
288
292
  autoFocus
293
+ required
289
294
  />
290
295
  );
291
296
  } else if (type === 'slider') {
@@ -297,6 +302,7 @@ export class NotificationMU extends NotificationReact {
297
302
  autoFocus
298
303
  fullWidth
299
304
  type={type}
305
+ required
300
306
  {...rest}
301
307
  />
302
308
  );
@@ -311,12 +317,12 @@ export class NotificationMU extends NotificationReact {
311
317
  open={this.open}
312
318
  PaperComponent={DraggablePaperComponent}
313
319
  className={className}
320
+ fullWidth={fullWidth}
321
+ maxWidth={maxWidth}
322
+ fullScreen={fullScreen}
314
323
  >
315
324
  <form>
316
- <IconDialogTitle
317
- className={classes.iconTitle}
318
- id="draggable-dialog-title"
319
- >
325
+ <IconDialogTitle id="draggable-dialog-title">
320
326
  <Info color="primary" />
321
327
  <span className="dialogTitle">{title}</span>
322
328
  </IconDialogTitle>
@@ -345,16 +351,15 @@ export class NotificationMU extends NotificationReact {
345
351
  }
346
352
 
347
353
  // Create loading
348
- private createLoading(
349
- _props: NotificationRenderProps,
350
- className: string,
351
- _classes: ClassNameMap<string>
352
- ) {
354
+ private createLoading(_props: NotificationRenderProps, className: string) {
353
355
  // Properties
354
356
  const setupProps: CircularProgressProps = { color: 'primary' };
355
357
 
356
358
  const labels = Labels.NotificationMU;
357
359
 
360
+ // Input props
361
+ const { maxWidth = 'xs' } = this.inputProps ?? {};
362
+
358
363
  // Content
359
364
  let content = this.content;
360
365
  if (content === '@') content = labels.loading.toString();
@@ -384,7 +389,13 @@ export class NotificationMU extends NotificationReact {
384
389
  }}
385
390
  >
386
391
  <CircularProgress {...setupProps} />
387
- {content && <Box maxWidth={640}>{content}</Box>}
392
+ {content && (
393
+ <Box
394
+ maxWidth={maxWidth === false ? undefined : maxWidth}
395
+ >
396
+ {content}
397
+ </Box>
398
+ )}
388
399
  </Box>
389
400
  </Backdrop>
390
401
  );
@@ -396,26 +407,22 @@ export class NotificationMU extends NotificationReact {
396
407
  * @param className Style class name
397
408
  * @param classes Style classes
398
409
  */
399
- render(
400
- props: NotificationRenderProps,
401
- className: string,
402
- classes: ClassNameMap<string>
403
- ) {
410
+ render(props: NotificationRenderProps, className: string) {
404
411
  // Loading bar
405
412
  if (this.type === NotificationType.Loading) {
406
- return this.createLoading(props, className, classes);
413
+ return this.createLoading(props, className);
407
414
  } else if (this.type === NotificationType.Confirm) {
408
- return this.createConfirm(props, className, classes);
415
+ return this.createConfirm(props, className);
409
416
  } else if (this.type === NotificationType.Prompt) {
410
- return this.createPrompt(props, className, classes);
417
+ return this.createPrompt(props, className);
411
418
  } else if (
412
419
  this.type === NotificationType.Error ||
413
420
  (this.modal && this.type in NotificationMessageType)
414
421
  ) {
415
422
  // Alert or modal message
416
- return this.createAlert(props, className, classes);
423
+ return this.createAlert(props, className);
417
424
  } else {
418
- return this.createMessage(props, className, classes);
425
+ return this.createMessage(props, className);
419
426
  }
420
427
  }
421
428
  }
@@ -499,8 +506,7 @@ export class NotifierMU extends NotifierReact {
499
506
  */
500
507
  protected createContainer = (
501
508
  align: NotificationAlign,
502
- children: React.ReactNode[],
503
- _options: ClassNameMap<string>
509
+ children: React.ReactNode[]
504
510
  ) => {
505
511
  // Each align group, class equal to something similar to 'align-topleft'
506
512
  const alignText = NotificationAlign[align].toLowerCase();
@@ -555,7 +561,7 @@ export class NotifierMU extends NotifierReact {
555
561
  * @param modal Show as modal
556
562
  */
557
563
  protected addRaw(
558
- data: INotificaseBase,
564
+ data: INotificaseBase<NotificationReactCallProps>,
559
565
  modal?: boolean
560
566
  ): INotificationReact {
561
567
  // Destruct
@@ -1,3 +1,5 @@
1
+ import { Breakpoint } from '@mui/material';
2
+
1
3
  /**
2
4
  * Notifier prompt props
3
5
  */
@@ -28,6 +28,11 @@ export interface SelectExProps<T = any>
28
28
  */
29
29
  labelField?: ((option: T) => string) | string;
30
30
 
31
+ /**
32
+ * Load data callback
33
+ */
34
+ loadData?: () => PromiseLike<T[] | null | undefined>;
35
+
31
36
  /**
32
37
  * Array of options.
33
38
  */
@@ -51,6 +56,7 @@ export function SelectEx<T = any>(props: SelectExProps<T>) {
51
56
  idField = 'id',
52
57
  label,
53
58
  labelField = 'label',
59
+ loadData,
54
60
  multiple = false,
55
61
  name,
56
62
  options = [],
@@ -59,6 +65,10 @@ export function SelectEx<T = any>(props: SelectExProps<T>) {
59
65
  ...rest
60
66
  } = props;
61
67
 
68
+ // Options state
69
+ const [localOptions, setOptions] = React.useState(options);
70
+ const isMounted = React.useRef(true);
71
+
62
72
  // Local value
63
73
  const valueSource = defaultValue ?? value ?? '';
64
74
  let localValue: unknown | unknown[];
@@ -69,7 +79,7 @@ export function SelectEx<T = any>(props: SelectExProps<T>) {
69
79
  localValue = valueSource;
70
80
  }
71
81
 
72
- // State
82
+ // Value state
73
83
  const [valueState, setValueState] = React.useState(localValue);
74
84
 
75
85
  // Label id
@@ -107,11 +117,23 @@ export function SelectEx<T = any>(props: SelectExProps<T>) {
107
117
  // When layout ready
108
118
  React.useEffect(() => {
109
119
  const input = divRef.current?.querySelector('input');
110
- if (input)
111
- input.addEventListener('change', (event) => {
112
- // Reset case
113
- if (event.cancelable) setValueState(multiple ? [] : '');
120
+ const inputChange = (event: Event) => {
121
+ // Reset case
122
+ if (event.cancelable) setValueState(multiple ? [] : '');
123
+ };
124
+ input?.addEventListener('change', inputChange);
125
+
126
+ if (loadData) {
127
+ loadData().then((result) => {
128
+ if (result == null || !isMounted.current) return;
129
+ setOptions(result);
114
130
  });
131
+ }
132
+
133
+ return () => {
134
+ isMounted.current = false;
135
+ input?.removeEventListener('change', inputChange);
136
+ };
115
137
  }, []);
116
138
 
117
139
  // Layout
@@ -139,7 +161,7 @@ export function SelectEx<T = any>(props: SelectExProps<T>) {
139
161
  onChange={multiple ? handleChange : undefined}
140
162
  renderValue={(selected) => {
141
163
  // The text shows up
142
- return options
164
+ return localOptions
143
165
  .filter((option: any) =>
144
166
  Array.isArray(selected)
145
167
  ? selected.indexOf(option.id) !== -1
@@ -151,7 +173,7 @@ export function SelectEx<T = any>(props: SelectExProps<T>) {
151
173
  sx={{ minWidth: '150px' }}
152
174
  {...rest}
153
175
  >
154
- {options.map((option: any) => {
176
+ {localOptions.map((option: any) => {
155
177
  // Option id
156
178
  const id = option[idField];
157
179
 
@@ -10,7 +10,7 @@ import { SearchField } from './SearchField';
10
10
  * Tiplist props
11
11
  */
12
12
  export interface TiplistProps<T extends Record<string, any>>
13
- extends Omit<AutocompleteExtendedProps<T>, 'options' | 'open'> {
13
+ extends Omit<AutocompleteExtendedProps<T>, 'open'> {
14
14
  /**
15
15
  * Load data callback
16
16
  */
@@ -4,6 +4,7 @@ import {
4
4
  INotifier,
5
5
  Notification,
6
6
  NotificationAlign,
7
+ NotificationCallProps,
7
8
  NotificationContainer,
8
9
  NotificationDictionary,
9
10
  NotificationRenderProps
@@ -11,13 +12,59 @@ import {
11
12
  import { IAction } from '@etsoo/appscript';
12
13
  import { State } from '../states/State';
13
14
  import { IProviderProps, IUpdate } from '../states/IState';
15
+ import { Breakpoint } from '@mui/material';
16
+
17
+ /**
18
+ * React notification call props
19
+ */
20
+ export interface NotificationReactCallProps extends NotificationCallProps {
21
+ /**
22
+ * Full width
23
+ */
24
+ fullWidth?: boolean;
25
+
26
+ /**
27
+ * Full screen
28
+ */
29
+ fullScreen?: boolean;
30
+
31
+ /**
32
+ * Inputs layout
33
+ */
34
+ inputs?: React.ReactNode;
35
+
36
+ /**
37
+ * Max width
38
+ */
39
+ maxWidth?: Breakpoint | false;
40
+
41
+ /**
42
+ * OK label
43
+ */
44
+ okLabel?: string;
45
+
46
+ /**
47
+ * Cancel label
48
+ */
49
+ cancelLabel?: string;
50
+
51
+ /**
52
+ * Type
53
+ */
54
+ type?: string;
55
+ }
14
56
 
15
57
  /**
16
58
  * React notification interface
17
59
  */
18
- export interface INotificationReact extends INotification<React.ReactNode> {}
60
+ export interface INotificationReact
61
+ extends INotification<React.ReactNode, NotificationReactCallProps> {}
19
62
 
20
- interface ReactNotifications extends NotificationDictionary<React.ReactNode> {}
63
+ interface ReactNotifications
64
+ extends NotificationDictionary<
65
+ React.ReactNode,
66
+ NotificationReactCallProps
67
+ > {}
21
68
 
22
69
  /**
23
70
  * Action to manage the notifier
@@ -37,7 +84,10 @@ interface INotifierAction extends IAction {
37
84
  /**
38
85
  * React notification
39
86
  */
40
- export abstract class NotificationReact extends Notification<React.ReactNode> {}
87
+ export abstract class NotificationReact extends Notification<
88
+ React.ReactNode,
89
+ NotificationReactCallProps
90
+ > {}
41
91
 
42
92
  /**
43
93
  * React notification render props
@@ -49,7 +99,8 @@ export interface NotificationReactRenderProps
49
99
  /**
50
100
  * Notifier interface
51
101
  */
52
- export interface INotifierReact extends INotifier<React.ReactNode> {
102
+ export interface INotifierReact
103
+ extends INotifier<React.ReactNode, NotificationReactCallProps> {
53
104
  /**
54
105
  * Create state provider
55
106
  * @param className Style class name
@@ -73,7 +124,7 @@ export interface INotifierOptions {
73
124
  * Notifier for React
74
125
  */
75
126
  export abstract class NotifierReact
76
- extends NotificationContainer<React.ReactNode>
127
+ extends NotificationContainer<React.ReactNode, NotificationReactCallProps>
77
128
  implements INotifierReact
78
129
  {
79
130
  // Instance
@@ -117,17 +168,15 @@ export abstract class NotifierReact
117
168
  */
118
169
  protected abstract createContainer(
119
170
  align: NotificationAlign,
120
- children: React.ReactNode[],
121
- options: any
171
+ children: React.ReactNode[]
122
172
  ): React.ReactElement;
123
173
 
124
174
  /**
125
175
  * Create state provider
126
176
  * @param className Style class name
127
- * @param optionGenerator Options generator
128
177
  * @returns Provider
129
178
  */
130
- createProvider(className?: string, optionGenerator?: INotifierOptions) {
179
+ createProvider(className?: string) {
131
180
  // Custom creator
132
181
  const creator = (
133
182
  state: ReactNotifications,
@@ -137,9 +186,6 @@ export abstract class NotifierReact
137
186
  // Hold the current state update
138
187
  this.stateUpdate = update;
139
188
 
140
- // Options
141
- const options = optionGenerator ? optionGenerator() : {};
142
-
143
189
  // Aligns collection
144
190
  const aligns: React.ReactNode[] = [];
145
191
  for (const align in state) {
@@ -148,11 +194,11 @@ export abstract class NotifierReact
148
194
 
149
195
  // UI collections
150
196
  const ui = notifications.map((notification) =>
151
- notification.render(props, className + '-item', options)
197
+ notification.render(props, className + '-item')
152
198
  );
153
199
 
154
200
  // Add to the collection
155
- aligns.push(this.createContainer(Number(align), ui, options));
201
+ aligns.push(this.createContainer(Number(align), ui));
156
202
  }
157
203
 
158
204
  // Generate the component
@@ -162,7 +208,10 @@ export abstract class NotifierReact
162
208
  // Create state
163
209
  const { provider } = State.create(
164
210
  (
165
- state: NotificationDictionary<React.ReactNode>,
211
+ state: NotificationDictionary<
212
+ React.ReactNode,
213
+ NotificationReactCallProps
214
+ >,
166
215
  _action: INotifierAction
167
216
  ) => {
168
217
  // Collection update is done with NotificationContainer
@@ -170,7 +219,10 @@ export abstract class NotifierReact
170
219
  },
171
220
  this.notifications,
172
221
  {} as IUpdate<
173
- NotificationDictionary<React.ReactNode>,
222
+ NotificationDictionary<
223
+ React.ReactNode,
224
+ NotificationReactCallProps
225
+ >,
174
226
  INotifierAction
175
227
  >,
176
228
  creator