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

SAP / ui5-webcomponents-react / 12009185407

25 Nov 2024 11:35AM CUT coverage: 87.142% (-0.02%) from 87.16%
12009185407

push

github

web-flow
fix(NavigationLayout): add root export (#6657)

2901 of 3864 branches covered (75.08%)

5056 of 5802 relevant lines covered (87.14%)

50139.75 hits per line

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

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

3
import type { RefObject } from 'react';
4
import { createRef, useSyncExternalStore } from 'react';
5
import { createPortal } from 'react-dom';
6
import { getRandomId } from '../../internal/getRandomId.js';
7
import { ModalStore } from '../../internal/ModalStore.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
function showDialogFn(
33
  props: DialogPropTypes,
34
  container?: Element | DocumentFragment
35
): ClosableModalReturnType<DialogDomRef> {
36
  const id = getRandomId();
7✔
37
  const ref = createRef<DialogDomRef>();
7✔
38
  ModalStore.addModal({
7✔
39
    Component: Dialog,
40
    props: {
41
      ...props,
42
      open: true,
43
      onClose: (event) => {
44
        if (typeof props.onClose === 'function') {
7!
45
          props.onClose(event);
×
46
        }
47
        ModalStore.removeModal(id);
7✔
48
      }
49
    },
50
    ref,
51
    container,
52
    id
53
  });
54

55
  return {
7✔
56
    ref,
57
    close: () => {
58
      if (ref.current) {
7✔
59
        ref.current.open = false;
7✔
60
      }
61
    }
62
  };
63
}
64

65
function showPopoverFn(
66
  props: PopoverPropTypes,
67
  container?: Element | DocumentFragment
68
): ClosableModalReturnType<PopoverDomRef> {
69
  const id = getRandomId();
×
70
  const ref = createRef<PopoverDomRef>();
×
71
  ModalStore.addModal({
×
72
    Component: Popover,
73
    props: {
74
      ...props,
75

76
      open: true,
77
      onClose: (event) => {
78
        if (typeof props.onClose === 'function') {
×
79
          props.onClose(event);
×
80
        }
81
        ModalStore.removeModal(id);
×
82
      }
83
    },
84
    ref,
85
    container,
86
    id
87
  });
88

89
  return {
×
90
    ref,
91
    close: () => {
92
      if (ref.current) {
×
93
        ref.current.open = false;
×
94
      }
95
    }
96
  };
97
}
98

99
function showResponsivePopoverFn(
100
  props: ResponsivePopoverPropTypes,
101
  container?: Element | DocumentFragment
102
): ClosableModalReturnType<ResponsivePopoverDomRef> {
103
  const id = getRandomId();
×
104
  const ref = createRef<ResponsivePopoverDomRef>();
×
105
  ModalStore.addModal({
×
106
    Component: ResponsivePopover,
107
    props: {
108
      ...props,
109
      open: true,
110
      onClose: (event) => {
111
        if (typeof props.onClose === 'function') {
×
112
          props.onClose(event);
×
113
        }
114
        ModalStore.removeModal(id);
×
115
      }
116
    },
117
    ref,
118
    container,
119
    id
120
  });
121

122
  return {
×
123
    ref,
124
    close: () => {
125
      if (ref.current) {
×
126
        ref.current.open = false;
×
127
      }
128
    }
129
  };
130
}
131

132
function showMenuFn(props: MenuPropTypes, container?: Element | DocumentFragment): ClosableModalReturnType<MenuDomRef> {
133
  const id = getRandomId();
×
134
  const ref = createRef<MenuDomRef>();
×
135
  ModalStore.addModal({
×
136
    Component: Menu,
137
    props: {
138
      ...props,
139
      open: true,
140
      onClose: (event) => {
141
        if (typeof props.onClose === 'function') {
×
142
          props.onClose(event);
×
143
        }
144
        ModalStore.removeModal(id);
×
145
      }
146
    },
147
    ref,
148
    container,
149
    id
150
  });
151

152
  return {
×
153
    ref,
154
    close: () => {
155
      if (ref.current) {
×
156
        ref.current.open = false;
×
157
      }
158
    }
159
  };
160
}
161

162
function showMessageBoxFn(
163
  props: MessageBoxPropTypes,
164
  container?: Element | DocumentFragment
165
): ClosableModalReturnType<DialogDomRef> {
166
  const id = getRandomId();
3✔
167
  const ref = createRef<DialogDomRef>();
3✔
168
  ModalStore.addModal({
3✔
169
    // @ts-expect-error: props type safety is covered by the `props` property
170
    Component: MessageBox,
171
    props: {
172
      ...props,
173
      open: true,
174
      onClose: (event) => {
175
        if (typeof props.onClose === 'function') {
3!
176
          props.onClose(event);
×
177
        }
178
        ModalStore.removeModal(id);
3✔
179
      }
180
    },
181
    ref,
182
    container,
183
    id
184
  });
185

186
  return {
3✔
187
    ref,
188
    close: () => {
189
      if (ref.current) {
×
190
        ref.current.open = false;
×
191
      }
192
    }
193
  };
194
}
195

196
function showToastFn(props: ToastPropTypes, container?: Element | DocumentFragment): ModalReturnType<ToastDomRef> {
197
  const ref = createRef<ToastDomRef>();
2✔
198
  const id = getRandomId();
2✔
199
  ModalStore.addModal({
2✔
200
    Component: Toast,
201
    props: {
202
      ...props,
203
      open: true,
204
      onClose: (event) => {
205
        if (typeof props.onClose === 'function') {
×
206
          props.onClose(event);
×
207
        }
208
        ModalStore.removeModal(id);
×
209
      }
210
    },
211
    ref,
212
    container,
213
    id
214
  });
215

216
  return {
2✔
217
    ref
218
  };
219
}
220

221
/**
222
 * Utility class for opening modals in an imperative way.
223
 *
224
 * These static helper methods might be useful for showing e.g. Toasts or MessageBoxes after successful or failed
225
 * network calls.
226
 *
227
 * **In order to use these helpers, please make sure to render the `Modals` component somewhere in your application tree.**
228
 *
229
 * @since 0.22.2
230
 */
231
export function Modals() {
232
  const modals = useSyncExternalStore(ModalStore.subscribe, ModalStore.getSnapshot, ModalStore.getServerSnapshot);
34✔
233

234
  return (
34✔
235
    <>
236
      {modals.map((modal) => {
237
        if (modal?.Component) {
12✔
238
          if (modal.container) {
12✔
239
            return createPortal(
2✔
240
              // @ts-expect-error: ref is supported by all supported modals
241
              <modal.Component {...modal.props} ref={modal.ref} key={modal.id} data-id={modal.id} />,
242
              modal.container
243
            );
244
          }
245
          // @ts-expect-error: ref is supported by all supported modals
246
          return <modal.Component {...modal.props} ref={modal.ref} key={modal.id} data-id={modal.id} />;
10✔
247
        }
248
      })}
249
    </>
250
  );
251
}
252

253
Modals.displayName = 'Modals';
418✔
254

255
Modals.showDialog = showDialogFn;
418✔
256
Modals.showPopover = showPopoverFn;
418✔
257
Modals.showResponsivePopover = showResponsivePopoverFn;
418✔
258
Modals.showMenu = showMenuFn;
418✔
259
Modals.showMessageBox = showMessageBoxFn;
418✔
260
Modals.showToast = showToastFn;
418✔
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