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

SAP / ui5-webcomponents-react / 5901578059

18 Aug 2023 10:26AM CUT coverage: 87.786%. Remained the same
5901578059

Pull #4979

github

web-flow
Merge ec8329320 into 9c9a93d6e
Pull Request #4979: fix(AnalyticalTable): fix scrollbars for Firefox and Safari

2669 of 3608 branches covered (73.97%)

4952 of 5641 relevant lines covered (87.79%)

19350.48 hits per line

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

72.65
/packages/main/src/components/Modals/index.tsx
1
'use client';
2

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

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

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

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

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

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

79
  return { ref };
20✔
80
}
81

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

457
/**
458
 * Utility class for opening modals in an imperative way.
459
 *
460
 * These static helper methods might be useful for showing e.g. Toasts or MessageBoxes after successful or failed
461
 * network calls.
462
 *
463
 * @since 0.22.2
464
 */
465
export const Modals = {
380✔
466
  showDialog: showDialogFn,
467
  useShowDialog: useShowDialogHook,
468
  showPopover: showPopoverFn,
469
  useShowPopover: useShowPopoverHook,
470
  showResponsivePopover: showResponsivePopoverFn,
471
  useShowResponsivePopover: useShowResponsivePopoverHook,
472
  /**
473
   * @since 1.8.0
474
   */
475
  showMenu: showMenuFn,
476
  /**
477
   * @since 1.8.0
478
   */
479
  useShowMenu: useShowMenuHook,
480
  showMessageBox: showMessageBoxFn,
481
  useShowMessageBox: useShowMessageBox,
482
  showToast: showToastFn,
483
  useShowToast: useShowToastHook
484
};
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