@stack-spot/portal-layout 0.0.64 → 1.0.0
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/dist/Layout.d.ts +57 -5
- package/dist/Layout.d.ts.map +1 -1
- package/dist/Layout.js +12 -5
- package/dist/Layout.js.map +1 -1
- package/dist/LayoutOverlayManager.d.ts +173 -6
- package/dist/LayoutOverlayManager.d.ts.map +1 -1
- package/dist/LayoutOverlayManager.js +118 -9
- package/dist/LayoutOverlayManager.js.map +1 -1
- package/dist/components/Dialog.d.ts +48 -5
- package/dist/components/Dialog.d.ts.map +1 -1
- package/dist/components/Dialog.js +7 -2
- package/dist/components/Dialog.js.map +1 -1
- package/dist/components/Header.d.ts +29 -1
- package/dist/components/Header.d.ts.map +1 -1
- package/dist/components/Header.js +6 -2
- package/dist/components/Header.js.map +1 -1
- package/dist/components/OverlayContent.d.ts +22 -0
- package/dist/components/OverlayContent.d.ts.map +1 -1
- package/dist/components/OverlayContent.js +4 -0
- package/dist/components/OverlayContent.js.map +1 -1
- package/dist/components/PortalSwitcher.d.ts +14 -0
- package/dist/components/PortalSwitcher.d.ts.map +1 -1
- package/dist/components/PortalSwitcher.js +9 -6
- package/dist/components/PortalSwitcher.js.map +1 -1
- package/dist/components/Toaster.d.ts +4 -0
- package/dist/components/Toaster.d.ts.map +1 -1
- package/dist/components/Toaster.js +5 -1
- package/dist/components/Toaster.js.map +1 -1
- package/dist/components/UserMenu.d.ts +14 -1
- package/dist/components/UserMenu.d.ts.map +1 -1
- package/dist/components/UserMenu.js +5 -1
- package/dist/components/UserMenu.js.map +1 -1
- package/dist/components/error/ErrorBoundary.d.ts +10 -1
- package/dist/components/error/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/error/ErrorBoundary.js +10 -1
- package/dist/components/error/ErrorBoundary.js.map +1 -1
- package/dist/components/error/ErrorManager.d.ts +22 -6
- package/dist/components/error/ErrorManager.d.ts.map +1 -1
- package/dist/components/error/ErrorManager.js +21 -1
- package/dist/components/error/ErrorManager.js.map +1 -1
- package/dist/components/error/SilentErrorBoundary.d.ts +11 -2
- package/dist/components/error/SilentErrorBoundary.d.ts.map +1 -1
- package/dist/components/error/SilentErrorBoundary.js +10 -0
- package/dist/components/error/SilentErrorBoundary.js.map +1 -1
- package/dist/components/menu/MenuContent.d.ts +19 -545
- package/dist/components/menu/MenuContent.d.ts.map +1 -1
- package/dist/components/menu/MenuContent.js +33 -35
- package/dist/components/menu/MenuContent.js.map +1 -1
- package/dist/components/menu/MenuSections.d.ts +10 -0
- package/dist/components/menu/MenuSections.d.ts.map +1 -1
- package/dist/components/menu/MenuSections.js +70 -16
- package/dist/components/menu/MenuSections.js.map +1 -1
- package/dist/components/menu/PageSelector.d.ts +5 -0
- package/dist/components/menu/PageSelector.d.ts.map +1 -1
- package/dist/components/menu/PageSelector.js +8 -3
- package/dist/components/menu/PageSelector.js.map +1 -1
- package/dist/components/menu/types.d.ts +100 -7
- package/dist/components/menu/types.d.ts.map +1 -1
- package/dist/components/tour/PortalSwitcherStep.d.ts +6 -1
- package/dist/components/tour/PortalSwitcherStep.d.ts.map +1 -1
- package/dist/components/tour/PortalSwitcherStep.js +6 -1
- package/dist/components/tour/PortalSwitcherStep.js.map +1 -1
- package/dist/components/types.d.ts +0 -13
- package/dist/components/types.d.ts.map +1 -1
- package/dist/dictionary.d.ts +3 -0
- package/dist/dictionary.d.ts.map +1 -1
- package/dist/dictionary.js +3 -0
- package/dist/dictionary.js.map +1 -1
- package/dist/elements.d.ts +6 -0
- package/dist/elements.d.ts.map +1 -1
- package/dist/elements.js +6 -0
- package/dist/elements.js.map +1 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/dist/layout.css +1 -5
- package/dist/toaster.d.ts +74 -9
- package/dist/toaster.d.ts.map +1 -1
- package/dist/toaster.js +32 -6
- package/dist/toaster.js.map +1 -1
- package/dist/utils.d.ts +6 -69
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +9 -130
- package/dist/utils.js.map +1 -1
- package/package.json +12 -11
- package/readme.md +146 -0
- package/src/Layout.tsx +78 -28
- package/src/LayoutOverlayManager.tsx +184 -9
- package/src/components/Dialog.tsx +49 -6
- package/src/components/Header.tsx +31 -3
- package/src/components/OverlayContent.tsx +22 -0
- package/src/components/PortalSwitcher.tsx +22 -8
- package/src/components/Toaster.tsx +10 -2
- package/src/components/UserMenu.tsx +14 -1
- package/src/components/error/ErrorBoundary.tsx +11 -2
- package/src/components/error/ErrorManager.ts +22 -6
- package/src/components/error/SilentErrorBoundary.tsx +12 -2
- package/src/components/menu/MenuContent.tsx +33 -52
- package/src/components/menu/MenuSections.tsx +99 -49
- package/src/components/menu/PageSelector.tsx +8 -3
- package/src/components/menu/types.ts +100 -8
- package/src/components/tour/PortalSwitcherStep.tsx +7 -4
- package/src/components/types.ts +0 -14
- package/src/dictionary.ts +3 -0
- package/src/elements.ts +6 -0
- package/src/index.ts +0 -3
- package/src/layout.css +1 -5
- package/src/toaster.tsx +125 -14
- package/src/utils.ts +9 -142
- package/dist/components/BottomNotification.d.ts +0 -1
- package/dist/components/BottomNotification.d.ts.map +0 -1
- package/dist/components/BottomNotification.js +0 -2
- package/dist/components/BottomNotification.js.map +0 -1
- package/dist/components/BottomPanel.d.ts +0 -1
- package/dist/components/BottomPanel.d.ts.map +0 -1
- package/dist/components/BottomPanel.js +0 -2
- package/dist/components/BottomPanel.js.map +0 -1
- package/dist/components/SelectionList.d.ts +0 -36
- package/dist/components/SelectionList.d.ts.map +0 -1
- package/dist/components/SelectionList.js +0 -140
- package/dist/components/SelectionList.js.map +0 -1
- package/dist/components/error/ErrorDescriptor.d.ts +0 -12
- package/dist/components/error/ErrorDescriptor.d.ts.map +0 -1
- package/dist/components/error/ErrorDescriptor.js +0 -17
- package/dist/components/error/ErrorDescriptor.js.map +0 -1
- package/dist/components/error/ErrorFeedback.d.ts +0 -3
- package/dist/components/error/ErrorFeedback.d.ts.map +0 -1
- package/dist/components/error/ErrorFeedback.js +0 -66
- package/dist/components/error/ErrorFeedback.js.map +0 -1
- package/dist/components/menu/use-check-text-overflow.d.ts +0 -6
- package/dist/components/menu/use-check-text-overflow.d.ts.map +0 -1
- package/dist/components/menu/use-check-text-overflow.js +0 -20
- package/dist/components/menu/use-check-text-overflow.js.map +0 -1
- package/dist/components/menu/use-keyboard-controls.d.ts +0 -23
- package/dist/components/menu/use-keyboard-controls.d.ts.map +0 -1
- package/dist/components/menu/use-keyboard-controls.js +0 -49
- package/dist/components/menu/use-keyboard-controls.js.map +0 -1
- package/dist/components/menu/useCheckTextOverflow.d.ts +0 -6
- package/dist/components/menu/useCheckTextOverflow.d.ts.map +0 -1
- package/dist/components/menu/useCheckTextOverflow.js +0 -20
- package/dist/components/menu/useCheckTextOverflow.js.map +0 -1
- package/dist/components/tour/Navigation.d.ts +0 -8
- package/dist/components/tour/Navigation.d.ts.map +0 -1
- package/dist/components/tour/Navigation.js +0 -15
- package/dist/components/tour/Navigation.js.map +0 -1
- package/dist/components/tour/config.d.ts +0 -3
- package/dist/components/tour/config.d.ts.map +0 -1
- package/dist/components/tour/config.js +0 -22
- package/dist/components/tour/config.js.map +0 -1
- package/dist/components/tour/steps/PortalSwitcherStep.d.ts +0 -3
- package/dist/components/tour/steps/PortalSwitcherStep.d.ts.map +0 -1
- package/dist/components/tour/steps/PortalSwitcherStep.js +0 -30
- package/dist/components/tour/steps/PortalSwitcherStep.js.map +0 -1
- package/dist/components/tour/utils.d.ts +0 -9
- package/dist/components/tour/utils.d.ts.map +0 -1
- package/dist/components/tour/utils.js +0 -48
- package/dist/components/tour/utils.js.map +0 -1
- package/dist/layout-context.d.ts +0 -10
- package/dist/layout-context.d.ts.map +0 -1
- package/dist/layout-context.js +0 -11
- package/dist/layout-context.js.map +0 -1
- package/dist/svg/AI.d.ts +0 -6
- package/dist/svg/AI.d.ts.map +0 -1
- package/dist/svg/AI.js +0 -9
- package/dist/svg/AI.js.map +0 -1
- package/dist/svg/EDP.d.ts +0 -6
- package/dist/svg/EDP.d.ts.map +0 -1
- package/dist/svg/EDP.js +0 -5
- package/dist/svg/EDP.js.map +0 -1
- package/dist/svg/Forbidden.d.ts +0 -6
- package/dist/svg/Forbidden.d.ts.map +0 -1
- package/dist/svg/Forbidden.js +0 -4
- package/dist/svg/Forbidden.js.map +0 -1
- package/dist/svg/HUB.d.ts +0 -6
- package/dist/svg/HUB.d.ts.map +0 -1
- package/dist/svg/HUB.js +0 -5
- package/dist/svg/HUB.js.map +0 -1
- package/dist/svg/Logo.d.ts +0 -2
- package/dist/svg/Logo.d.ts.map +0 -1
- package/dist/svg/Logo.js +0 -4
- package/dist/svg/Logo.js.map +0 -1
- package/dist/svg/NotFound.d.ts +0 -6
- package/dist/svg/NotFound.d.ts.map +0 -1
- package/dist/svg/NotFound.js +0 -4
- package/dist/svg/NotFound.js.map +0 -1
- package/dist/svg/ServerError.d.ts +0 -6
- package/dist/svg/ServerError.d.ts.map +0 -1
- package/dist/svg/ServerError.js +0 -4
- package/dist/svg/ServerError.js.map +0 -1
- package/dist/svg/Unauthenticated.d.ts +0 -6
- package/dist/svg/Unauthenticated.d.ts.map +0 -1
- package/dist/svg/Unauthenticated.js +0 -4
- package/dist/svg/Unauthenticated.js.map +0 -1
- package/src/components/BottomNotification.tsx +0 -0
- package/src/components/BottomPanel.tsx +0 -0
- package/src/components/SelectionList.tsx +0 -272
- package/src/components/error/ErrorFeedback.tsx +0 -114
- package/src/components/menu/use-check-text-overflow.tsx +0 -26
- package/src/components/menu/use-keyboard-controls.tsx +0 -70
- package/src/layout-context.tsx +0 -22
- package/src/svg/AI.tsx +0 -37
- package/src/svg/EDP.tsx +0 -35
- package/src/svg/Forbidden.tsx +0 -22
- package/src/svg/HUB.tsx +0 -35
- package/src/svg/Logo.tsx +0 -35
- package/src/svg/NotFound.tsx +0 -16
- package/src/svg/ServerError.tsx +0 -33
- package/src/svg/Unauthenticated.tsx +0 -16
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
2
|
|
|
3
3
|
import { Button } from '@citric/core'
|
|
4
|
+
import { focusAccessibleElement, focusFirstChild } from '@stack-spot/portal-components'
|
|
4
5
|
import { ReactElement, useLayoutEffect, useState } from 'react'
|
|
5
6
|
import { Dialog, DialogOptions } from './components/Dialog'
|
|
6
7
|
import { CLOSE_OVERLAY_ID, OverlayContent, OverlayContentProps } from './components/OverlayContent'
|
|
7
8
|
import { getDictionary } from './dictionary'
|
|
8
9
|
import { LayoutElements, elementIds, getLayoutElements } from './elements'
|
|
9
10
|
import { ElementNotFound, LayoutError } from './errors'
|
|
10
|
-
import { showToaster as showReactToaster } from './toaster'
|
|
11
|
-
import {
|
|
11
|
+
import { CustomToasterOptions, DefaultToasterOptions, closeReactToaster, showToaster as showReactToaster } from './toaster'
|
|
12
|
+
import { valueOfLayoutVar } from './utils'
|
|
12
13
|
|
|
13
14
|
interface AlertOptions extends Omit<DialogOptions, 'cancel'> {
|
|
15
|
+
/**
|
|
16
|
+
* Whether or not to show an "ok" button. If false, the dialog can still be closed through the close button, by clicking outside it or by
|
|
17
|
+
* pressing ESC.
|
|
18
|
+
*/
|
|
14
19
|
showButton?: boolean,
|
|
15
20
|
}
|
|
16
21
|
|
|
@@ -26,12 +31,24 @@ interface OverlayContentSetter {
|
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
interface CustomModalOptions {
|
|
34
|
+
/**
|
|
35
|
+
* The size of the modal.
|
|
36
|
+
*/
|
|
29
37
|
size?: ModalSize,
|
|
38
|
+
/**
|
|
39
|
+
* A function to call when the modal closes.
|
|
40
|
+
*/
|
|
30
41
|
onClose?: () => void,
|
|
31
42
|
}
|
|
32
43
|
|
|
33
44
|
interface CustomRightPanelOptions {
|
|
45
|
+
/**
|
|
46
|
+
* The size of the right panel.
|
|
47
|
+
*/
|
|
34
48
|
size?: OverlaySize,
|
|
49
|
+
/**
|
|
50
|
+
* A function to call when the right panel closes.
|
|
51
|
+
*/
|
|
35
52
|
onClose?: () => void,
|
|
36
53
|
}
|
|
37
54
|
|
|
@@ -72,9 +89,12 @@ class LayoutOverlayManager {
|
|
|
72
89
|
this.setInteractivity(this.elements?.rightPanel, false)
|
|
73
90
|
this.setInteractivity(this.elements?.bottomDialog, false)
|
|
74
91
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Setup the overlay layout elements.
|
|
95
|
+
* @returns the content for the modal, rightPanel and bottomDialog.
|
|
96
|
+
*/
|
|
97
|
+
// @ts-ignore: this should actually be like Kotlin's "internal", i.e. private to any user of the lib, but public to the lib itself.
|
|
78
98
|
private useOverlays() {
|
|
79
99
|
useLayoutEffect(() => {
|
|
80
100
|
if (!this.elements) this.setupElements()
|
|
@@ -88,6 +108,11 @@ class LayoutOverlayManager {
|
|
|
88
108
|
return { modal, rightPanel, bottomDialog }
|
|
89
109
|
}
|
|
90
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Enables or disables the interactivity of an element.
|
|
113
|
+
* @param element the element to have its interactivity changed.
|
|
114
|
+
* @param interactive false to disable interactivity, true to enable.
|
|
115
|
+
*/
|
|
91
116
|
private setInteractivity(element: HTMLElement | null | undefined, interactive: boolean) {
|
|
92
117
|
if (interactive) {
|
|
93
118
|
element?.removeAttribute('inert')
|
|
@@ -122,18 +147,36 @@ class LayoutOverlayManager {
|
|
|
122
147
|
this.setMainContentInteractivity(true)
|
|
123
148
|
}
|
|
124
149
|
|
|
150
|
+
/**
|
|
151
|
+
* @returns true if the modal is currently opened. False otherwise.
|
|
152
|
+
*/
|
|
125
153
|
isModalOpen() {
|
|
126
154
|
return this.elements?.modal?.classList.contains('visible') ?? false
|
|
127
155
|
}
|
|
128
156
|
|
|
157
|
+
/**
|
|
158
|
+
* @returns true if the right panel is currently opened. False otherwise.
|
|
159
|
+
*/
|
|
129
160
|
isRightPanelOpen() {
|
|
130
161
|
return this.elements?.rightPanel?.classList.contains('visible') ?? false
|
|
131
162
|
}
|
|
132
163
|
|
|
164
|
+
/**
|
|
165
|
+
* @returns true if the bottom dialog is currently opened. False otherwise.
|
|
166
|
+
*/
|
|
133
167
|
isBottomDialogOpen() {
|
|
134
168
|
return this.elements?.bottomDialog?.classList.contains('visible') ?? false
|
|
135
169
|
}
|
|
136
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Opens a modal with custom content.
|
|
173
|
+
*
|
|
174
|
+
* Attention: the modal state must be declared within the modal. If the state is declared outside the modal, its content won't be updated
|
|
175
|
+
* accordingly. To force an update of an outside state, you need to call `showCustomModal` again with the new state value.
|
|
176
|
+
*
|
|
177
|
+
* @param content a react element with the modal content.
|
|
178
|
+
* @param options the modal options {@link CustomModalOptions}.
|
|
179
|
+
*/
|
|
137
180
|
showCustomModal(content: React.ReactElement, { size = 'medium', onClose }: CustomModalOptions = {}) {
|
|
138
181
|
if (!this.elements?.modal) throw new ElementNotFound('modal', elementIds.modal)
|
|
139
182
|
if (!this.setContent.modal) throw new LayoutError('unable to show modal, because it has not been setup yet.')
|
|
@@ -142,6 +185,14 @@ class LayoutOverlayManager {
|
|
|
142
185
|
this.showOverlay(this.elements.modal, [size])
|
|
143
186
|
}
|
|
144
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Opens a modal.
|
|
190
|
+
*
|
|
191
|
+
* Attention: the modal state must be declared within the modal. If the state is declared outside the modal, its content won't be updated
|
|
192
|
+
* accordingly. To force an update of an outside state, you need to call `showModal` again with the new state value.
|
|
193
|
+
*
|
|
194
|
+
* @param options the modal options: {@link OverlayContentProps} & { size: {@link ModalSize} }.
|
|
195
|
+
*/
|
|
145
196
|
showModal({ size, ...props }: OverlayContentProps & { size?: ModalSize }) {
|
|
146
197
|
this.showCustomModal(<OverlayContent {...props} onClose={() => this.closeModal()} type="modal" />, { size, onClose: props.onClose })
|
|
147
198
|
}
|
|
@@ -167,23 +218,47 @@ class LayoutOverlayManager {
|
|
|
167
218
|
})
|
|
168
219
|
}
|
|
169
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Shows a confirmation dialog and returns a promise that resolves as soon as the dialog is closed. The result of the promise is true if
|
|
223
|
+
* the user confirms and false otherwise.
|
|
224
|
+
*
|
|
225
|
+
* If you need the user to type something to confirm the action, use the property `validate` in the options parameter.
|
|
226
|
+
* @param options the dialog options: {@link DialogOptions}.
|
|
227
|
+
* @returns a promise that resolves with the user's answer.
|
|
228
|
+
*/
|
|
170
229
|
confirm({ confirm, cancel, ...options }: DialogOptions): Promise<boolean> {
|
|
171
230
|
const t = getDictionary()
|
|
172
231
|
return this.showDialog({ ...options, confirm: confirm || t.confirm, cancel: cancel || t.cancel })
|
|
173
232
|
}
|
|
174
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Shows an alert dialog and returns a promise that resolves as soon as the dialog is closed.
|
|
236
|
+
*
|
|
237
|
+
* @param options the dialog options: {@link AlertOptions}.
|
|
238
|
+
* @returns a promise that resolves to undefined as soon as the dialog is closed.
|
|
239
|
+
*/
|
|
175
240
|
async alert({ confirm, showButton = true, ...options }: AlertOptions): Promise<void> {
|
|
176
241
|
const t = getDictionary()
|
|
177
242
|
await this.showDialog({ ...options, confirm: showButton ? (confirm || t.confirm) : undefined })
|
|
178
243
|
}
|
|
179
244
|
|
|
180
|
-
|
|
245
|
+
/**
|
|
246
|
+
* Shows a message at the bottom of the window and asks the user to confirm or decline it. The return value is a promise that resolves as
|
|
247
|
+
* soon as the user presses one of the buttons. The result of the promise is true if the user confirms and false otherwise.
|
|
248
|
+
*
|
|
249
|
+
* Differently than `confirm` and `alert`, this message can only be closed if the user clicks one of the buttons or `closeBottomDialog`
|
|
250
|
+
* is called.
|
|
251
|
+
*
|
|
252
|
+
* @param options the dialog options: {@link BottomDialogOptions}.
|
|
253
|
+
* @returns a promise that resolves with the user's answer.
|
|
254
|
+
*/
|
|
255
|
+
showBottomDialog({ children, cancel, confirm }: BottomDialogOptions): Promise<boolean> {
|
|
181
256
|
if (!this.elements?.bottomDialog) throw new ElementNotFound('bottom dialog', elementIds.bottomDialog)
|
|
182
257
|
if (!this.setContent.bottomDialog) throw new LayoutError('unable to show bottom dialog, because it has not been setup yet.')
|
|
183
258
|
return new Promise((resolve) => {
|
|
184
259
|
this.setContent.bottomDialog?.(
|
|
185
260
|
<>
|
|
186
|
-
{
|
|
261
|
+
{children}
|
|
187
262
|
<div className="btn-group">
|
|
188
263
|
{cancel && <Button onClick={() => resolve(false)} colorScheme="light" appearance="outlined">{cancel}</Button>}
|
|
189
264
|
{confirm && <Button onClick={() => resolve(true)} colorScheme="light">{confirm}</Button>}
|
|
@@ -194,6 +269,16 @@ class LayoutOverlayManager {
|
|
|
194
269
|
})
|
|
195
270
|
}
|
|
196
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Opens a right panel with custom content.
|
|
274
|
+
*
|
|
275
|
+
* Attention: the right panel state must be declared within the right panel. If the state is declared outside the right panel, its content
|
|
276
|
+
* won't be updated accordingly. To force an update of an outside state, you need to call `showCustomRightPanel` again with the new state
|
|
277
|
+
* value.
|
|
278
|
+
*
|
|
279
|
+
* @param content a react element with the modal content.
|
|
280
|
+
* @param options the modal options {@link CustomModalOptions}.
|
|
281
|
+
*/
|
|
197
282
|
showCustomRightPanel(content: ReactElement, { size = 'medium', onClose }: CustomRightPanelOptions = {}) {
|
|
198
283
|
if (!this.elements?.rightPanel) throw new ElementNotFound('right panel overlay', elementIds.rightPanel)
|
|
199
284
|
if (!this.setContent.rightPanel) throw new LayoutError('unable to show right panel overlay, because it has not been setup yet.')
|
|
@@ -205,6 +290,14 @@ class LayoutOverlayManager {
|
|
|
205
290
|
})
|
|
206
291
|
}
|
|
207
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Opens a right panel.
|
|
295
|
+
*
|
|
296
|
+
* Attention: the right panel state must be declared within the right panel. If the state is declared outside the right panel, its content
|
|
297
|
+
* won't be updated accordingly. To force an update of an outside state, you need to call `showRightPanel` again with the new state value.
|
|
298
|
+
*
|
|
299
|
+
* @param options the modal options: {@link OverlayContentProps} & { size: {@link ModalSize} }.
|
|
300
|
+
*/
|
|
208
301
|
showRightPanel({ size, ...props }: OverlayContentProps & { size?: OverlaySize }) {
|
|
209
302
|
this.showCustomRightPanel(
|
|
210
303
|
<OverlayContent {...props} onClose={() => this.closeRightPanel()} type="panel" />,
|
|
@@ -212,7 +305,7 @@ class LayoutOverlayManager {
|
|
|
212
305
|
)
|
|
213
306
|
}
|
|
214
307
|
|
|
215
|
-
|
|
308
|
+
/*
|
|
216
309
|
* Focus the element that had focus before the last overlay was opened. If the element is not visible anymore, another one that makes
|
|
217
310
|
* sense (accessibility-wise) is focused.
|
|
218
311
|
*/
|
|
@@ -221,6 +314,10 @@ class LayoutOverlayManager {
|
|
|
221
314
|
this.lastActiveElement = null
|
|
222
315
|
}
|
|
223
316
|
|
|
317
|
+
/**
|
|
318
|
+
* Closes the modal if it's open.
|
|
319
|
+
* @param runCloseListener whether or not to run the function `onClose` passed to `showModal` or `showCustomModal`. Defaults to true.
|
|
320
|
+
*/
|
|
224
321
|
closeModal(runCloseListener = true) {
|
|
225
322
|
this.elements?.modal?.classList.remove('visible')
|
|
226
323
|
this.elements?.backdrop?.setAttribute('class', '')
|
|
@@ -246,6 +343,11 @@ class LayoutOverlayManager {
|
|
|
246
343
|
)
|
|
247
344
|
}
|
|
248
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Closes the right panel if it's open.
|
|
348
|
+
* @param runCloseListener whether or not to run the function `onClose` passed to `showRightPanel` or `showCustomRightPanel`. Defaults to
|
|
349
|
+
* true.
|
|
350
|
+
*/
|
|
249
351
|
closeRightPanel(runCloseListener = true) {
|
|
250
352
|
this.elements?.rightPanel?.classList.remove('visible')
|
|
251
353
|
this.elements?.backdrop?.setAttribute('class', '')
|
|
@@ -271,19 +373,92 @@ class LayoutOverlayManager {
|
|
|
271
373
|
)
|
|
272
374
|
}
|
|
273
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Closes the bottom dialog if it's open.
|
|
378
|
+
*/
|
|
274
379
|
closeBottomDialog() {
|
|
275
380
|
this.hideOverlay(this.elements?.bottomDialog)
|
|
276
381
|
}
|
|
277
382
|
|
|
383
|
+
/**
|
|
384
|
+
* Verifies if the HTML element passed as parameter is inside the modal.
|
|
385
|
+
* @param element the HTML element to check.
|
|
386
|
+
* @returns true if `element` is inside the modal; false otherwise.
|
|
387
|
+
*/
|
|
278
388
|
isInsideModal(element: HTMLElement) {
|
|
279
389
|
return !!this.elements?.modal?.contains(element)
|
|
280
390
|
}
|
|
281
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Verifies if the HTML element passed as parameter is inside the right panel.
|
|
394
|
+
* @param element the HTML element to check.
|
|
395
|
+
* @returns true if `element` is inside the right panel; false otherwise.
|
|
396
|
+
*/
|
|
282
397
|
isInsideRightPanel(element: HTMLElement) {
|
|
283
398
|
return !!this.elements?.rightPanel?.contains(element)
|
|
284
399
|
}
|
|
285
400
|
|
|
286
|
-
|
|
401
|
+
/**
|
|
402
|
+
* Shows a new toaster on the top right corner of the layout.
|
|
403
|
+
* @example
|
|
404
|
+
* ```
|
|
405
|
+
* overlay.showToaster({ title: 'Welcome', message: 'Hello World' })
|
|
406
|
+
* overlay.showToaster({
|
|
407
|
+
* title: 'Welcome',
|
|
408
|
+
* message: 'Hello World',
|
|
409
|
+
* actions: [
|
|
410
|
+
* { label: 'Got it!' },
|
|
411
|
+
* {
|
|
412
|
+
* label: 'Tell me more',
|
|
413
|
+
* closeOnClick: false,
|
|
414
|
+
* onClick: (event) => {
|
|
415
|
+
* // do something...
|
|
416
|
+
* },
|
|
417
|
+
* },
|
|
418
|
+
* ]
|
|
419
|
+
* })
|
|
420
|
+
* ```
|
|
421
|
+
* @param options the options for the toaster: {@link DefaultToasterOptions}.
|
|
422
|
+
* @returns the toaster's id.
|
|
423
|
+
*/
|
|
424
|
+
showToaster(defaultToasterConfig: DefaultToasterOptions): number | string
|
|
425
|
+
/**
|
|
426
|
+
* Shows a fully customized toaster on the top right corner of the layout.
|
|
427
|
+
* @example
|
|
428
|
+
* ```
|
|
429
|
+
* overlay.showToaster({
|
|
430
|
+
* custom: true,
|
|
431
|
+
* message: <MyCustomToasterContent />,
|
|
432
|
+
* closeButton: <MyCustomCloseButton />,
|
|
433
|
+
* })
|
|
434
|
+
* ```
|
|
435
|
+
* @param options the options for the toaster: {@link CustomToasterOptions}.
|
|
436
|
+
* @returns the toaster's id.
|
|
437
|
+
*/
|
|
438
|
+
showToaster(customToasterConfig: CustomToasterOptions): number | string
|
|
439
|
+
/**
|
|
440
|
+
* Shows the message passed as parameter in a new toaster on the top right corner of the layout.
|
|
441
|
+
* @example
|
|
442
|
+
* ```
|
|
443
|
+
* overlay.showToaster('Hello World!')
|
|
444
|
+
* overlay.showToaster(<p>Hello World</p>)
|
|
445
|
+
* ```
|
|
446
|
+
* @param message the message to show, can be either a string or React Element.
|
|
447
|
+
* @returns the toaster's id.
|
|
448
|
+
*/
|
|
449
|
+
showToaster(message: React.ReactNode): number | string
|
|
450
|
+
showToaster(options: any): number | string {
|
|
451
|
+
return showReactToaster(options)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Closes the toaster with the specified id.
|
|
456
|
+
* @param id the id of the toaster to close.
|
|
457
|
+
*/
|
|
458
|
+
closeToaster = closeReactToaster
|
|
287
459
|
}
|
|
288
460
|
|
|
461
|
+
/**
|
|
462
|
+
* Manages overlay components of the layout like: modal, rightPanel, bottomDialog and toaster.
|
|
463
|
+
*/
|
|
289
464
|
export const overlay = new LayoutOverlayManager()
|
|
@@ -6,35 +6,73 @@ import { useDictionary } from '../dictionary'
|
|
|
6
6
|
import { OverlayContent } from './OverlayContent'
|
|
7
7
|
|
|
8
8
|
interface Validation {
|
|
9
|
+
/**
|
|
10
|
+
* The expected value of the field.
|
|
11
|
+
*/
|
|
9
12
|
value: string,
|
|
13
|
+
/**
|
|
14
|
+
* A custom label for the input field.
|
|
15
|
+
*/
|
|
10
16
|
label?: string | ReactNode,
|
|
17
|
+
/**
|
|
18
|
+
* A placeholder for the input field.
|
|
19
|
+
*/
|
|
11
20
|
placeholder?: string,
|
|
12
21
|
}
|
|
13
22
|
|
|
14
23
|
export interface DialogOptions {
|
|
24
|
+
/**
|
|
25
|
+
* The dialog's title.
|
|
26
|
+
*/
|
|
15
27
|
title: string,
|
|
28
|
+
/**
|
|
29
|
+
* The dialog's subtitle.
|
|
30
|
+
*/
|
|
16
31
|
subtitle?: string,
|
|
17
|
-
|
|
32
|
+
/**
|
|
33
|
+
* The dialog's content.
|
|
34
|
+
*/
|
|
35
|
+
children: ReactNode,
|
|
36
|
+
/**
|
|
37
|
+
* A text for the confirm button. If left blank, the confirm button won't render.
|
|
38
|
+
*/
|
|
18
39
|
confirm?: string,
|
|
40
|
+
/**
|
|
41
|
+
* A text for the cancel button. If left blank, the cancel button won't render.
|
|
42
|
+
*/
|
|
19
43
|
cancel?: string,
|
|
44
|
+
/**
|
|
45
|
+
* A validation input field. If the validation is incorrect, the confirm button is disabled.
|
|
46
|
+
* If this is a string, the validation input's value must be equal to this string in order to enable the confirm button.
|
|
47
|
+
* If this is an object, a value, label and placeholder may be specified.
|
|
48
|
+
* Use false or undefined to not include a validation field.
|
|
49
|
+
*/
|
|
20
50
|
validation?: false | string | Validation,
|
|
21
51
|
/**
|
|
52
|
+
* If this is a modal or a rightPanel.
|
|
22
53
|
* @default modal
|
|
23
54
|
*/
|
|
24
55
|
type?: 'modal' | 'panel',
|
|
25
56
|
/**
|
|
26
|
-
*
|
|
57
|
+
* The placement for the confirm/cancel buttons.
|
|
58
|
+
* @default "left" if type is "panel", "right" otherwise.
|
|
27
59
|
*/
|
|
28
60
|
buttonPlacement?: 'left' | 'center' | 'right',
|
|
29
61
|
/**
|
|
30
62
|
* The color of the primary button.
|
|
31
|
-
* @default primary
|
|
63
|
+
* @default "primary"
|
|
32
64
|
*/
|
|
33
65
|
buttonColor?: ColorSchemeName,
|
|
34
66
|
}
|
|
35
67
|
|
|
36
|
-
interface Props extends DialogOptions {
|
|
68
|
+
interface Props extends Omit<DialogOptions, 'message'> {
|
|
69
|
+
/**
|
|
70
|
+
* Function to run when the confirm button is clicked.
|
|
71
|
+
*/
|
|
37
72
|
onConfirm: () => void,
|
|
73
|
+
/**
|
|
74
|
+
* Function to run when the cancel button is clicked.
|
|
75
|
+
*/
|
|
38
76
|
onCancel: () => void,
|
|
39
77
|
}
|
|
40
78
|
|
|
@@ -44,8 +82,13 @@ const justifyButtons: Record<Required<DialogOptions>['buttonPlacement'], React.C
|
|
|
44
82
|
right: 'end',
|
|
45
83
|
}
|
|
46
84
|
|
|
85
|
+
/**
|
|
86
|
+
* A dialog, i.e. A UI with title, subtitle, close button, content and a set of buttons: cancel and confirm. May be placed under a Modal or
|
|
87
|
+
* RightPanel.
|
|
88
|
+
* @param props the React props of the component {@link Props}.
|
|
89
|
+
*/
|
|
47
90
|
export const Dialog = ({
|
|
48
|
-
|
|
91
|
+
children,
|
|
49
92
|
title,
|
|
50
93
|
subtitle,
|
|
51
94
|
cancel,
|
|
@@ -83,7 +126,7 @@ export const Dialog = ({
|
|
|
83
126
|
return (
|
|
84
127
|
<OverlayContent title={title} subtitle={subtitle} onClose={onCancel} type={type}>
|
|
85
128
|
<Flex flexDirection="column" flex={1}>
|
|
86
|
-
{
|
|
129
|
+
{children}
|
|
87
130
|
{renderValidation()}
|
|
88
131
|
</Flex>
|
|
89
132
|
{(cancel || confirm) && <Flex gap justifyContent={justifyButtons[buttonPlacement]} alignItems="center" sx={{ mt: 6 }}>
|
|
@@ -1,22 +1,50 @@
|
|
|
1
1
|
import { Flex } from '@citric/core'
|
|
2
|
+
import { SelectionListProps } from '@stack-spot/portal-components/SelectionList'
|
|
3
|
+
import { useAnchorTag } from '@stack-spot/portal-components/anchor'
|
|
4
|
+
import { Logo } from '@stack-spot/portal-components/svg'
|
|
2
5
|
import { ReactNode } from 'react'
|
|
3
|
-
import { useAnchorTag } from '../layout-context'
|
|
4
|
-
import { Logo } from '../svg/Logo'
|
|
5
6
|
import { PortalSwitcher, PortalSwitcherProps } from './PortalSwitcher'
|
|
6
|
-
import { SelectionListProps } from './SelectionList'
|
|
7
7
|
import { UserMenu } from './UserMenu'
|
|
8
8
|
|
|
9
9
|
export interface HeaderProps {
|
|
10
|
+
/**
|
|
11
|
+
* The logo to show in the header, if the portal switch feature is disabled.
|
|
12
|
+
*/
|
|
10
13
|
logo?: ReactNode,
|
|
14
|
+
/**
|
|
15
|
+
* The url the logo links to, if the portal switch feature is disabled.
|
|
16
|
+
*/
|
|
11
17
|
logoHref?: string,
|
|
18
|
+
/**
|
|
19
|
+
* The username to show in the user menu.
|
|
20
|
+
*/
|
|
12
21
|
userName?: string,
|
|
22
|
+
/**
|
|
23
|
+
* The email to show in the user menu.
|
|
24
|
+
*/
|
|
13
25
|
email?: string,
|
|
26
|
+
/**
|
|
27
|
+
* A portal switch config. If not specified, disables the portal switch feature.
|
|
28
|
+
*/
|
|
14
29
|
portalSwitch?: PortalSwitcherProps['portals'],
|
|
30
|
+
/**
|
|
31
|
+
* The options to show in the user menu.
|
|
32
|
+
*/
|
|
15
33
|
options?: SelectionListProps['items'],
|
|
34
|
+
/**
|
|
35
|
+
* A custom React Node to show at the center of the header. This is a good place for a search field, for instance.
|
|
36
|
+
*/
|
|
16
37
|
center?: ReactNode,
|
|
38
|
+
/**
|
|
39
|
+
* A custom React Node to show at the right (end) of the header.
|
|
40
|
+
*/
|
|
17
41
|
right?: ReactNode,
|
|
18
42
|
}
|
|
19
43
|
|
|
44
|
+
/**
|
|
45
|
+
* The page header.
|
|
46
|
+
* @param props the React props for the header {@link HeaderProps}.
|
|
47
|
+
*/
|
|
20
48
|
export const Header = ({ logo, logoHref, center, right, userName, email, options, portalSwitch }: HeaderProps) => {
|
|
21
49
|
const Link = useAnchorTag()
|
|
22
50
|
|
|
@@ -9,14 +9,32 @@ import { useDictionary } from '../dictionary'
|
|
|
9
9
|
export const CLOSE_OVERLAY_ID = 'close-overlay'
|
|
10
10
|
|
|
11
11
|
export interface OverlayContentProps extends WithStyle {
|
|
12
|
+
/**
|
|
13
|
+
* The title for the modal or right panel.
|
|
14
|
+
*/
|
|
12
15
|
title: string,
|
|
16
|
+
/**
|
|
17
|
+
* The subtitle for the modal or right panel.
|
|
18
|
+
*/
|
|
13
19
|
subtitle?: string,
|
|
20
|
+
/**
|
|
21
|
+
* The content for the modal or right panel.
|
|
22
|
+
*/
|
|
14
23
|
children: ReactNode,
|
|
24
|
+
/**
|
|
25
|
+
* A function to run when the close button is pressed.
|
|
26
|
+
*/
|
|
15
27
|
onClose?: () => void,
|
|
16
28
|
}
|
|
17
29
|
|
|
18
30
|
interface Props extends OverlayContentProps {
|
|
31
|
+
/**
|
|
32
|
+
* A function to run when the close button is pressed.
|
|
33
|
+
*/
|
|
19
34
|
onClose: () => void,
|
|
35
|
+
/**
|
|
36
|
+
* Whether this is a modal or a right panel.
|
|
37
|
+
*/
|
|
20
38
|
type: 'modal' | 'panel',
|
|
21
39
|
}
|
|
22
40
|
|
|
@@ -41,6 +59,10 @@ const ContentBox = styled.section`
|
|
|
41
59
|
}
|
|
42
60
|
`
|
|
43
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Renders a modal or right panel with title, subtitle, close button and content.
|
|
64
|
+
* @param props the React props for the component {@link Props}.
|
|
65
|
+
*/
|
|
44
66
|
export const OverlayContent = ({ children, title, subtitle, className, style, onClose, type }: Props) => {
|
|
45
67
|
const t = useDictionary()
|
|
46
68
|
return (
|
|
@@ -1,26 +1,35 @@
|
|
|
1
1
|
import { Button, Flex, IconBox, Text } from '@citric/core'
|
|
2
2
|
import { ArrowRight, CheckCircleFill, Select } from '@citric/icons'
|
|
3
|
+
import { SelectionList } from '@stack-spot/portal-components/SelectionList'
|
|
4
|
+
import { AI, EDP, HUB, Logo } from '@stack-spot/portal-components/svg'
|
|
3
5
|
import { theme } from '@stack-spot/portal-theme'
|
|
4
6
|
import { useTranslate } from '@stack-spot/portal-translate'
|
|
5
7
|
import { ReactNode, useState } from 'react'
|
|
6
8
|
import styled from 'styled-components'
|
|
7
|
-
import {
|
|
8
|
-
import { AI } from '../svg/AI'
|
|
9
|
-
import { EDP } from '../svg/EDP'
|
|
10
|
-
import { HUB } from '../svg/HUB'
|
|
11
|
-
import { Logo } from '../svg/Logo'
|
|
9
|
+
import { announce } from '../utils'
|
|
12
10
|
import { PortalAcronym } from './types'
|
|
13
11
|
|
|
14
|
-
|
|
15
12
|
const Logos: Record<PortalAcronym, ReactNode> = {
|
|
16
13
|
'AI': <AI />,
|
|
17
14
|
'EDP': <EDP />,
|
|
18
15
|
'HUB': <HUB />,
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
export interface Portal {
|
|
18
|
+
export interface Portal {
|
|
19
|
+
/**
|
|
20
|
+
* A Stackspot Portal.
|
|
21
|
+
*/
|
|
22
|
+
acronym: PortalAcronym,
|
|
23
|
+
/**
|
|
24
|
+
* The URL to the Stackspot Portal.
|
|
25
|
+
*/
|
|
26
|
+
url: string,
|
|
27
|
+
}
|
|
22
28
|
|
|
23
29
|
export interface PortalSwitcherProps {
|
|
30
|
+
/**
|
|
31
|
+
* The Stackspot portals to show in the selector.
|
|
32
|
+
*/
|
|
24
33
|
portals?: Portal[],
|
|
25
34
|
}
|
|
26
35
|
|
|
@@ -80,6 +89,11 @@ const PortalSwitcherBox = styled(Flex)`
|
|
|
80
89
|
`
|
|
81
90
|
const PORTAL_SWITCHER_ID = 'PortalSwitcher'
|
|
82
91
|
|
|
92
|
+
/**
|
|
93
|
+
* A selector with different Stackspot portals.
|
|
94
|
+
* Each item contains a logo with a link to the portal.
|
|
95
|
+
* @param props the component Props {@link PortalSwitcherProps}.
|
|
96
|
+
*/
|
|
83
97
|
export const PortalSwitcher = ({ portals = [] }: PortalSwitcherProps) => {
|
|
84
98
|
const [visible, setVisible] = useState<boolean>(false)
|
|
85
99
|
const t = useTranslate(translations)
|
|
@@ -140,7 +154,7 @@ const translations = {
|
|
|
140
154
|
pt: {
|
|
141
155
|
EDP: 'Soluções eficientes e seguras do código até a implantação em produção.',
|
|
142
156
|
AI: 'Acelere o desenvolvimento com sugestões eficientes e resultados de alta qualidade.',
|
|
143
|
-
HUB: 'Descubra AI Stacks,
|
|
157
|
+
HUB: 'Descubra AI Stacks, knowledge sources e quick commands, tudo em um hub simplificado.',
|
|
144
158
|
portalSwitcher: 'Seletor de portais',
|
|
145
159
|
selected: 'selecionado',
|
|
146
160
|
},
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import { TimesMini } from '@citric/icons'
|
|
2
2
|
import { IconButton } from '@citric/ui'
|
|
3
|
-
import {
|
|
3
|
+
import type { CloseButton as DefaultCloseButton } from 'react-toastify'
|
|
4
|
+
import { ToastContainer } from 'react-toastify'
|
|
4
5
|
import 'react-toastify/dist/ReactToastify.css'
|
|
5
6
|
import { useDictionary } from '../dictionary'
|
|
6
7
|
|
|
8
|
+
type CloseButtonProps = Parameters<typeof DefaultCloseButton>[0]
|
|
9
|
+
|
|
10
|
+
export const TOASTER_CLOSE_BTN_CLASS = 'btn-close'
|
|
11
|
+
|
|
7
12
|
const CloseButton = ({ closeToast }: CloseButtonProps) => {
|
|
8
13
|
const t = useDictionary()
|
|
9
14
|
return (
|
|
10
|
-
<IconButton onClick={
|
|
15
|
+
<IconButton className={TOASTER_CLOSE_BTN_CLASS} onClick={closeToast} title={t.dismiss}>
|
|
11
16
|
<TimesMini />
|
|
12
17
|
</IconButton>
|
|
13
18
|
)
|
|
14
19
|
}
|
|
15
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Uses react-toastify to render a Toaster based on the Citric DS.
|
|
23
|
+
*/
|
|
16
24
|
export const Toaster = () => <ToastContainer closeButton={CloseButton} />
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import { Flex, IconBox, LinkBox, Text } from '@citric/core'
|
|
2
2
|
import { ChevronDown } from '@citric/icons'
|
|
3
3
|
import { Avatar } from '@citric/ui'
|
|
4
|
+
import { SelectionList, SelectionListProps } from '@stack-spot/portal-components/SelectionList'
|
|
4
5
|
import { theme } from '@stack-spot/portal-theme'
|
|
5
6
|
import { Dictionary, interpolate, useTranslate } from '@stack-spot/portal-translate'
|
|
6
7
|
import { useState } from 'react'
|
|
7
8
|
import { styled } from 'styled-components'
|
|
8
|
-
import { SelectionList, SelectionListProps } from './SelectionList'
|
|
9
9
|
|
|
10
10
|
interface Props {
|
|
11
|
+
/**
|
|
12
|
+
* The user name.
|
|
13
|
+
*/
|
|
11
14
|
userName: string,
|
|
15
|
+
/**
|
|
16
|
+
* The user email.
|
|
17
|
+
*/
|
|
12
18
|
email?: string,
|
|
19
|
+
/**
|
|
20
|
+
* The menu options.
|
|
21
|
+
*/
|
|
13
22
|
options?: SelectionListProps['items'],
|
|
14
23
|
}
|
|
15
24
|
|
|
@@ -65,6 +74,10 @@ const UserMenuHeader = ({ userName, email }: Omit<Props, 'options'>) => (
|
|
|
65
74
|
</div>
|
|
66
75
|
)
|
|
67
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Renders the user menu.
|
|
79
|
+
* @param props the component's props {@link Props}.
|
|
80
|
+
*/
|
|
68
81
|
export const UserMenu = ({ userName, email, options }: Props) => {
|
|
69
82
|
const t = useTranslate(dictionary)
|
|
70
83
|
const [visible, setVisible] = useState(false)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { ErrorDescription, ErrorFeedback } from '@stack-spot/portal-components/ErrorFeedback'
|
|
1
2
|
import { Component } from 'react'
|
|
2
|
-
import {
|
|
3
|
-
import { ErrorDescription, ErrorManager } from './ErrorManager'
|
|
3
|
+
import { ErrorManager } from './ErrorManager'
|
|
4
4
|
|
|
5
5
|
interface State extends ErrorDescription {
|
|
6
6
|
hasError: boolean,
|
|
@@ -10,6 +10,15 @@ interface Props {
|
|
|
10
10
|
children: React.ReactNode,
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* An Error Boundary that renders an ErrorFeedback instead of its content if any of its children throws.
|
|
15
|
+
*
|
|
16
|
+
* To customize what properties are passed to the ErrorFeedback component, setup an error descriptor for the ErrorManager class. If you're
|
|
17
|
+
* using the component `Layout` or `RawLayout`, you can use the property `errorDescriptor`.
|
|
18
|
+
*
|
|
19
|
+
* To run an error handler every time an error is catch by this boundary, setup an error handler for the ErrorManager class. If you're
|
|
20
|
+
* using the component `Layout` or `RawLayout`, you can use the property `onError`.
|
|
21
|
+
*/
|
|
13
22
|
export class ErrorBoundary extends Component<Props, State> {
|
|
14
23
|
constructor(props: Props) {
|
|
15
24
|
super(props)
|