• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SAP / ui5-webcomponents-react / 4665890316

pending completion
4665890316

Pull #4476

github

GitHub
Merge b149fd751 into 0999a8e97
Pull Request #4476: fix(TreeItemCustom - TypeScript): omit `content` HTMLAttribute from PropTypes

2621 of 3596 branches covered (72.89%)

5086 of 5880 relevant lines covered (86.5%)

13215.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.74
/packages/main/src/components/Modals/index.tsx
1
'use client';
2,590✔
2

3
import { createRef, Dispatch, MutableRefObject, RefObject, useCallback } from 'react';
4
import { getRandomId } from '../../internal/getRandomId';
5
import { UpdateModalStateAction, useModalsContext } from '../../internal/ModalsContext';
6
import {
7
  Dialog,
8
  DialogDomRef,
9
  DialogPropTypes,
10
  Menu,
11
  MenuDomRef,
12
  MenuPropTypes,
13
  Popover,
14
  PopoverDomRef,
15
  PopoverPropTypes,
16
  ResponsivePopover,
17
  ResponsivePopoverDomRef,
18
  ResponsivePopoverPropTypes,
19
  Toast,
20
  ToastDomRef,
21
  ToastPropTypes
22
} from '../../webComponents';
23
import { MessageBox, MessageBoxPropTypes } from '../MessageBox';
24

25
type ModalReturnType<DomRef> = {
26
  ref: RefObject<DomRef>;
27
};
28

29
type ClosableModalReturnType<DomRef> = ModalReturnType<DomRef> & {
30
  close: () => void;
31
};
32

33
type ModalHookReturnType<Props, DomRef, ContainerElement = HTMLElement> = (
34
  props: Props,
35
  container?: ContainerElement
36
) => ModalReturnType<DomRef>;
37
type CloseableModalHookReturnType<Props, DomRef, ContainerElement = HTMLElement> = (
38
  props: Props,
39
  container?: ContainerElement
40
) => ClosableModalReturnType<DomRef>;
41

42
const checkContext = (context: any): void => {
370✔
43
  if (!context) {
57!
44
    // eslint-disable-next-line no-console
45
    console.error(`Please make sure that your application is wrapped in the '<ThemeProvider />' component.`);
×
46
  }
47
};
48

49
function showDialog<ContainerElement>(
50
  props: DialogPropTypes,
51
  setModal: Dispatch<UpdateModalStateAction<DialogPropTypes, DialogDomRef, ContainerElement>>,
52
  container?: ContainerElement
53
) {
54
  checkContext(setModal);
20✔
55
  const id = getRandomId();
20✔
56
  const ref = createRef<DialogDomRef>();
20✔
57
  setModal?.({
20✔
58
    type: 'set',
59
    payload: {
60
      Component: Dialog,
61
      props: {
62
        ...props,
63
        open: true,
64
        onAfterClose: (event) => {
65
          if (typeof props.onAfterClose === 'function') {
20!
66
            props.onAfterClose(event);
×
67
          }
68
          setModal({
20✔
69
            type: 'reset',
70
            payload: { id }
71
          });
72
        }
73
      },
74
      ref,
75
      container,
76
      id
77
    }
78
  });
79

80
  return { ref };
20✔
81
}
82

83
function showPopover<ContainerElement>(
84
  props: PopoverPropTypes,
85
  setModal: Dispatch<UpdateModalStateAction<PopoverPropTypes, PopoverDomRef, ContainerElement>>,
86
  container?: ContainerElement
87
) {
88
  checkContext(setModal);
6✔
89
  const id = getRandomId();
6✔
90
  const ref = createRef<PopoverDomRef>();
6✔
91
  setModal?.({
6✔
92
    type: 'set',
93
    payload: {
94
      Component: Popover,
95
      props: {
96
        ...props,
97

98
        open: true,
99
        onAfterClose: (event) => {
100
          if (typeof props.onAfterClose === 'function') {
6!
101
            props.onAfterClose(event);
×
102
          }
103
          setModal({
6✔
104
            type: 'reset',
105
            payload: { id }
106
          });
107
        }
108
      },
109
      ref,
110
      container,
111
      id
112
    }
113
  });
114
  return { ref };
6✔
115
}
116

117
function showResponsivePopover<ContainerElement>(
118
  props: ResponsivePopoverPropTypes,
119
  setModal: Dispatch<UpdateModalStateAction<ResponsivePopoverPropTypes, ResponsivePopoverDomRef, ContainerElement>>,
120
  container?: ContainerElement
121
) {
122
  checkContext(setModal);
5✔
123
  const id = getRandomId();
5✔
124
  const ref = createRef<ResponsivePopoverDomRef>();
5✔
125
  setModal?.({
5✔
126
    type: 'set',
127
    payload: {
128
      Component: ResponsivePopover,
129
      props: {
130
        ...props,
131
        open: true,
132
        onAfterClose: (event) => {
133
          if (typeof props.onAfterClose === 'function') {
5!
134
            props.onAfterClose(event);
×
135
          }
136
          setModal({
5✔
137
            type: 'reset',
138
            payload: { id }
139
          });
140
        }
141
      },
142
      ref,
143
      container,
144
      id
145
    }
146
  });
147
  return { ref };
5✔
148
}
149

150
function showMenu<ContainerElement>(
151
  props: MenuPropTypes,
152
  setModal: Dispatch<UpdateModalStateAction<MenuPropTypes, MenuDomRef, ContainerElement>>,
153
  container?: ContainerElement
154
) {
155
  checkContext(setModal);
4✔
156
  const id = getRandomId();
4✔
157
  const ref = createRef<MenuDomRef>();
4✔
158
  setModal?.({
4✔
159
    type: 'set',
160
    payload: {
161
      Component: Menu,
162
      props: {
163
        ...props,
164
        open: true,
165
        onAfterClose: (event) => {
166
          if (typeof props.onAfterClose === 'function') {
4!
167
            props.onAfterClose(event);
×
168
          }
169
          setModal({
4✔
170
            type: 'reset',
171
            payload: { id }
172
          });
173
        }
174
      },
175
      ref,
176
      container,
177
      id
178
    }
179
  });
180
  return { ref };
4✔
181
}
182

183
function showMessageBox<ContainerElement>(
184
  props: MessageBoxPropTypes,
185
  setModal: Dispatch<UpdateModalStateAction<MessageBoxPropTypes, DialogDomRef, ContainerElement>>,
186
  container?: ContainerElement
187
) {
188
  checkContext(setModal);
14✔
189
  const id = getRandomId();
14✔
190
  const ref = createRef<DialogDomRef>();
14✔
191
  setModal?.({
14✔
192
    type: 'set',
193
    payload: {
194
      // @ts-expect-error: props type safety is covered by the `props` property
195
      Component: MessageBox,
196
      props: {
197
        ...props,
198
        open: true,
199
        onClose: (event) => {
200
          if (typeof props.onClose === 'function') {
12!
201
            props.onClose(event);
×
202
          }
203
          setModal({
12✔
204
            type: 'reset',
205
            payload: { id }
206
          });
207
        }
208
      },
209
      ref,
210
      container,
211
      id
212
    }
213
  });
214
  return { ref };
14✔
215
}
216

217
function showToast<ContainerElement>(
218
  props: ToastPropTypes,
219
  setModal: Dispatch<UpdateModalStateAction<ToastPropTypes, ToastDomRef, ContainerElement>>,
220
  container?: ContainerElement
221
) {
222
  const ref = createRef<ToastDomRef>() as MutableRefObject<ToastDomRef>;
8✔
223
  checkContext(setModal);
8✔
224
  const id = getRandomId();
8✔
225
  setModal?.({
8✔
226
    type: 'set',
227
    payload: {
228
      Component: Toast,
229
      props: {
230
        ...props
231
      },
232
      ref: (el: ToastDomRef & { open: boolean }) => {
233
        ref.current = el;
15✔
234
        if (el && !el.open) {
15✔
235
          el.show();
8✔
236
          setTimeout(() => {
8✔
237
            setModal({
×
238
              type: 'reset',
239
              payload: { id }
240
            });
241
          }, props.duration ?? Toast.defaultProps.duration);
16✔
242
        }
243
      },
244
      container,
245
      id
246
    }
247
  });
248
  return { ref };
8✔
249
}
250

251
function showDialogFn<ContainerElement = HTMLElement>(
252
  props: DialogPropTypes,
253
  container?: ContainerElement
254
): ClosableModalReturnType<DialogDomRef> {
255
  const setModal = window['@ui5/webcomponents-react']?.setModal;
13✔
256

257
  const { ref } = showDialog<ContainerElement>(props, setModal, container);
13✔
258

259
  return {
13✔
260
    ref,
261
    close: () => {
262
      ref.current?.close();
13✔
263
    }
264
  };
265
}
266

267
function useShowDialogHook<ContainerElement>(): CloseableModalHookReturnType<
7✔
268
  DialogPropTypes,
269
  DialogDomRef,
270
  ContainerElement
271
> {
21✔
272
  const { setModal } = useModalsContext();
21✔
273

274
  return useCallback(
21✔
275
    (props, container) => {
276
      const { ref } = showDialog<ContainerElement>(props, setModal, container);
7✔
277

278
      return {
7✔
279
        ref,
280
        close: () => {
281
          ref.current?.close();
7✔
282
        }
283
      };
284
    },
285
    [setModal]
286
  );
287
}
370✔
288

289
function showPopoverFn<ContainerElement>(
290
  props: PopoverPropTypes,
291
  container?: ContainerElement
292
): ClosableModalReturnType<PopoverDomRef> {
293
  const setModal = window['@ui5/webcomponents-react']?.setModal;
×
294
  const { ref } = showPopover(props, setModal, container);
×
295

296
  return {
×
297
    ref,
298
    close: () => {
299
      ref.current?.close();
×
300
    }
301
  };
302
}
303

304
function useShowPopoverHook<ContainerElement>(): CloseableModalHookReturnType<
6✔
305
  PopoverPropTypes,
306
  PopoverDomRef,
307
  ContainerElement
308
> {
18✔
309
  const { setModal } = useModalsContext();
18✔
310
  return useCallback(
18✔
311
    (props, container) => {
312
      const { ref } = showPopover<ContainerElement>(props, setModal, container);
6✔
313

314
      return {
6✔
315
        ref,
316
        close: () => {
317
          ref.current?.close();
6✔
318
        }
319
      };
320
    },
321
    [setModal]
322
  );
323
}
370✔
324

325
function showResponsivePopoverFn<ContainerElement>(
326
  props: ResponsivePopoverPropTypes,
327
  container?: ContainerElement
328
): ClosableModalReturnType<ResponsivePopoverDomRef> {
329
  const setModal = window['@ui5/webcomponents-react']?.setModal;
×
330
  const { ref } = showResponsivePopover<ContainerElement>(props, setModal, container);
×
331

332
  return {
×
333
    ref,
334
    close: () => {
335
      ref.current?.close();
×
336
    }
337
  };
338
}
339

340
function useShowResponsivePopoverHook<ContainerElement>(): CloseableModalHookReturnType<
5✔
341
  ResponsivePopoverPropTypes,
342
  ResponsivePopoverDomRef,
343
  ContainerElement
344
> {
15✔
345
  const { setModal } = useModalsContext();
15✔
346
  return useCallback(
15✔
347
    (props, container) => {
348
      const { ref } = showResponsivePopover<ContainerElement>(props, setModal, container);
5✔
349

350
      return {
5✔
351
        ref,
352
        close: () => {
353
          ref.current?.close();
5✔
354
        }
355
      };
356
    },
357
    [setModal]
358
  );
359
}
370✔
360

361
function showMenuFn<ContainerElement>(
362
  props: MenuPropTypes,
363
  container?: ContainerElement
364
): ClosableModalReturnType<MenuDomRef> {
365
  const setModal = window['@ui5/webcomponents-react']?.setModal;
×
366
  const { ref } = showMenu<ContainerElement>(props, setModal, container);
×
367

368
  return {
×
369
    ref,
370
    close: () => {
371
      ref.current?.close();
×
372
    }
373
  };
374
}
375

376
function useShowMenuHook<ContainerElement>(): CloseableModalHookReturnType<
4✔
377
  MenuPropTypes,
378
  MenuDomRef,
379
  ContainerElement
380
> {
12✔
381
  const { setModal } = useModalsContext();
12✔
382
  return useCallback(
12✔
383
    (props, container) => {
384
      const { ref } = showMenu<ContainerElement>(props, setModal, container);
4✔
385

386
      return {
4✔
387
        ref,
388
        close: () => {
389
          ref.current?.close();
×
390
        }
391
      };
392
    },
393
    [setModal]
394
  );
395
}
370✔
396

397
function showMessageBoxFn<ContainerElement>(
398
  props: MessageBoxPropTypes,
399
  container?: ContainerElement
400
): ClosableModalReturnType<DialogDomRef> {
401
  const setModal = window['@ui5/webcomponents-react']?.setModal;
9✔
402
  const { ref } = showMessageBox<ContainerElement>(props, setModal, container);
9✔
403

404
  return {
9✔
405
    ref,
406
    close: () => {
407
      ref.current?.close();
×
408
    }
409
  };
410
}
411
function useShowMessageBox<ContainerElement>(): CloseableModalHookReturnType<
3✔
412
  MessageBoxPropTypes,
413
  DialogDomRef,
414
  ContainerElement
415
> {
13✔
416
  const { setModal } = useModalsContext();
13✔
417
  return useCallback(
13✔
418
    (props, container) => {
419
      const { ref } = showMessageBox<ContainerElement>(props, setModal, container);
5✔
420

421
      return {
5✔
422
        ref,
423
        close: () => {
424
          ref.current?.close();
×
425
        }
426
      };
427
    },
428
    [setModal]
429
  );
430
}
370✔
431

432
function showToastFn<ContainerElement>(
433
  props: ToastPropTypes,
434
  container?: ContainerElement
435
): ModalReturnType<ToastDomRef> {
436
  const setModal = window['@ui5/webcomponents-react']?.setModal;
8✔
437
  const { ref } = showToast<ContainerElement>(props, setModal, container);
8✔
438

439
  return {
8✔
440
    ref
441
  };
442
}
443

444
function useShowToastHook<ContainerElement>(): ModalHookReturnType<ToastPropTypes, ToastDomRef, ContainerElement> {
×
445
  const { setModal } = useModalsContext();
×
446

447
  return useCallback(
×
448
    (props: ToastPropTypes, container?) => {
449
      const { ref } = showToast<ContainerElement>(props, setModal, container);
×
450
      return {
×
451
        ref
452
      };
453
    },
454
    [setModal]
455
  );
456
}
457

458
/**
370✔
459
 * Utility class for opening modals in an imperative way.
460
 *
461
 * These static helper methods might be useful for showing e.g. Toasts or MessageBoxes after successful or failed
462
 * network calls.
463
 *
464
 * @since 0.22.2
465
 */
466
export const Modals = {
370✔
467
  showDialog: showDialogFn,
468
  useShowDialog: useShowDialogHook,
469
  showPopover: showPopoverFn,
470
  useShowPopover: useShowPopoverHook,
471
  showResponsivePopover: showResponsivePopoverFn,
472
  useShowResponsivePopover: useShowResponsivePopoverHook,
473
  /**
474
   * @since 1.8.0
475
   */
476
  showMenu: showMenuFn,
477
  /**
478
   * @since 1.8.0
479
   */
480
  useShowMenu: useShowMenuHook,
481
  showMessageBox: showMessageBoxFn,
482
  useShowMessageBox: useShowMessageBox,
483
  showToast: showToastFn,
484
  useShowToast: useShowToastHook
485
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc