@stack-spot/portal-layout 1.0.2 → 1.1.1
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/CHANGELOG.md +18 -0
- package/dist/Layout.d.ts +2 -2
- package/dist/Layout.js +1 -1
- package/dist/LayoutOverlayManager.js +6 -6
- package/dist/components/Dialog.d.ts +1 -1
- package/dist/components/Dialog.js +1 -1
- package/dist/components/Header.d.ts +1 -1
- package/dist/components/Header.js +1 -1
- package/dist/components/OverlayContent.d.ts +1 -1
- package/dist/components/OverlayContent.js +20 -20
- package/dist/components/PortalSwitcher.d.ts +1 -1
- package/dist/components/PortalSwitcher.js +54 -54
- package/dist/components/Toaster.d.ts +2 -2
- package/dist/components/Toaster.js +1 -1
- package/dist/components/UserMenu.d.ts +1 -1
- package/dist/components/UserMenu.d.ts.map +1 -1
- package/dist/components/UserMenu.js +44 -42
- package/dist/components/UserMenu.js.map +1 -1
- package/dist/components/error/ErrorBoundary.d.ts +1 -1
- package/dist/components/error/ErrorBoundary.js +1 -1
- package/dist/components/error/SilentErrorBoundary.d.ts +1 -1
- package/dist/components/error/SilentErrorBoundary.js +1 -1
- package/dist/components/menu/MenuContent.d.ts +5 -5
- package/dist/components/menu/MenuContent.d.ts.map +1 -1
- package/dist/components/menu/MenuContent.js +126 -124
- package/dist/components/menu/MenuContent.js.map +1 -1
- package/dist/components/menu/MenuSections.d.ts +8 -1
- package/dist/components/menu/MenuSections.d.ts.map +1 -1
- package/dist/components/menu/MenuSections.js +14 -2
- package/dist/components/menu/MenuSections.js.map +1 -1
- package/dist/components/menu/PageSelector.d.ts +1 -1
- package/dist/components/menu/PageSelector.js +69 -69
- package/dist/components/tour/PortalSwitcherStep.js +1 -1
- package/dist/components/user-menu-manager.d.ts +13 -0
- package/dist/components/user-menu-manager.d.ts.map +1 -0
- package/dist/components/user-menu-manager.js +36 -0
- package/dist/components/user-menu-manager.js.map +1 -0
- package/dist/layout.css +477 -477
- package/dist/toaster.js +1 -1
- package/package.json +9 -6
- package/readme.md +146 -146
- package/src/Layout.tsx +171 -171
- package/src/LayoutOverlayManager.tsx +464 -464
- package/src/components/Dialog.tsx +140 -140
- package/src/components/Header.tsx +62 -62
- package/src/components/OverlayContent.tsx +80 -80
- package/src/components/PortalSwitcher.tsx +161 -161
- package/src/components/Toaster.tsx +95 -95
- package/src/components/UserMenu.tsx +127 -124
- package/src/components/error/ErrorBoundary.tsx +47 -47
- package/src/components/error/ErrorManager.ts +47 -47
- package/src/components/error/SilentErrorBoundary.tsx +64 -64
- package/src/components/menu/MenuContent.tsx +272 -270
- package/src/components/menu/MenuSections.tsx +334 -320
- package/src/components/menu/PageSelector.tsx +164 -164
- package/src/components/menu/constants.ts +2 -2
- package/src/components/menu/types.ts +205 -205
- package/src/components/tour/PortalSwitcherStep.tsx +39 -39
- package/src/components/types.ts +1 -1
- package/src/components/user-menu-manager.ts +31 -0
- package/src/dictionary.ts +28 -28
- package/src/elements.ts +30 -30
- package/src/errors.ts +11 -11
- package/src/index.ts +14 -14
- package/src/layout.css +477 -477
- package/src/toaster.tsx +153 -153
- package/src/utils.ts +29 -29
- package/tsconfig.json +8 -8
|
@@ -1,124 +1,127 @@
|
|
|
1
|
-
import { Flex, IconBox, LinkBox, Text } from '@citric/core'
|
|
2
|
-
import { ChevronDown } from '@citric/icons'
|
|
3
|
-
import { Avatar } from '@citric/ui'
|
|
4
|
-
import { SelectionList, SelectionListProps } from '@stack-spot/portal-components/SelectionList'
|
|
5
|
-
import { theme } from '@stack-spot/portal-theme'
|
|
6
|
-
import { Dictionary, interpolate, useTranslate } from '@stack-spot/portal-translate'
|
|
7
|
-
import { useState } from 'react'
|
|
8
|
-
import { styled } from 'styled-components'
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
*
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
</
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
accountMenu: '
|
|
123
|
-
},
|
|
124
|
-
|
|
1
|
+
import { Flex, IconBox, LinkBox, Text } from '@citric/core'
|
|
2
|
+
import { ChevronDown } from '@citric/icons'
|
|
3
|
+
import { Avatar } from '@citric/ui'
|
|
4
|
+
import { SelectionList, SelectionListProps } from '@stack-spot/portal-components/SelectionList'
|
|
5
|
+
import { theme } from '@stack-spot/portal-theme'
|
|
6
|
+
import { Dictionary, interpolate, useTranslate } from '@stack-spot/portal-translate'
|
|
7
|
+
import { useEffect, useState } from 'react'
|
|
8
|
+
import { styled } from 'styled-components'
|
|
9
|
+
import { userMenuManager } from './user-menu-manager'
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
/**
|
|
13
|
+
* The user name.
|
|
14
|
+
*/
|
|
15
|
+
userName: string,
|
|
16
|
+
/**
|
|
17
|
+
* The user email.
|
|
18
|
+
*/
|
|
19
|
+
email?: string,
|
|
20
|
+
/**
|
|
21
|
+
* The menu options.
|
|
22
|
+
*/
|
|
23
|
+
options?: SelectionListProps['items'],
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const USER_MENU_ID = 'userMenu'
|
|
27
|
+
|
|
28
|
+
const UserMenuBox = styled.div`
|
|
29
|
+
.user-menu-header {
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
align-items: center;
|
|
34
|
+
padding: 12px;
|
|
35
|
+
border-bottom: 2px solid ${theme.color.light['600']};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.selection-list {
|
|
39
|
+
position: absolute;
|
|
40
|
+
top: var(--header-height);
|
|
41
|
+
right: 20px;
|
|
42
|
+
width: 266px;
|
|
43
|
+
|
|
44
|
+
.selection-list-content {
|
|
45
|
+
border: none;
|
|
46
|
+
padding: 16px 16px 8px;
|
|
47
|
+
background-color: ${theme.color.light['400']};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
li {
|
|
51
|
+
margin: 8px 0;
|
|
52
|
+
& > a {
|
|
53
|
+
border-radius: 6px;
|
|
54
|
+
&:hover, &:focus {
|
|
55
|
+
background: ${theme.color.light['500']};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.username {
|
|
62
|
+
margin: 5px 0 2px 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.chevron {
|
|
66
|
+
transition: transform ease-out 0.3s;
|
|
67
|
+
}
|
|
68
|
+
`
|
|
69
|
+
|
|
70
|
+
const UserMenuHeader = ({ userName, email }: Omit<Props, 'options'>) => (
|
|
71
|
+
<div className="user-menu-header">
|
|
72
|
+
<Avatar size="xs">{userName}</Avatar>
|
|
73
|
+
<Text appearance="body1" className="username">{userName}</Text>
|
|
74
|
+
{email && <Text appearance="microtext1" className="email" colorScheme="light.700">{email}</Text>}
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Renders the user menu.
|
|
80
|
+
* @param props the component's props {@link Props}.
|
|
81
|
+
*/
|
|
82
|
+
export const UserMenu = ({ userName, email, options }: Props) => {
|
|
83
|
+
const t = useTranslate(dictionary)
|
|
84
|
+
const [visible, setVisible] = useState(false)
|
|
85
|
+
|
|
86
|
+
useEffect(() => userMenuManager.subscribe(setVisible), [])
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<UserMenuBox>
|
|
90
|
+
<LinkBox
|
|
91
|
+
as="button"
|
|
92
|
+
onClick={() => setVisible(v => !v)}
|
|
93
|
+
aria-controls={USER_MENU_ID}
|
|
94
|
+
aria-expanded={visible}
|
|
95
|
+
aria-label={interpolate(t.accountMenu, [userName])}
|
|
96
|
+
>
|
|
97
|
+
<Flex alignItems="center">
|
|
98
|
+
<Avatar size="xs" aria-label={interpolate(t.accountMenu, [userName])}>{userName}</Avatar>
|
|
99
|
+
<IconBox colorIcon="inverse.500" className="chevron" style={visible ? { transform: 'rotate(180deg)' } : undefined}>
|
|
100
|
+
<ChevronDown />
|
|
101
|
+
</IconBox>
|
|
102
|
+
</Flex>
|
|
103
|
+
</LinkBox>
|
|
104
|
+
|
|
105
|
+
{options?.length
|
|
106
|
+
? <SelectionList
|
|
107
|
+
id={USER_MENU_ID}
|
|
108
|
+
visible={visible}
|
|
109
|
+
before={<UserMenuHeader userName={userName} email={email} />}
|
|
110
|
+
items={options!}
|
|
111
|
+
onHide={() => setVisible(false)}
|
|
112
|
+
maxHeight="600px"
|
|
113
|
+
/>
|
|
114
|
+
: null
|
|
115
|
+
}
|
|
116
|
+
</UserMenuBox>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const dictionary = {
|
|
121
|
+
en: {
|
|
122
|
+
accountMenu: 'Profile menu of $0',
|
|
123
|
+
},
|
|
124
|
+
pt: {
|
|
125
|
+
accountMenu: 'Menu do perfil $0',
|
|
126
|
+
},
|
|
127
|
+
} satisfies Dictionary
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import { ErrorDescription, ErrorFeedback } from '@stack-spot/portal-components/ErrorFeedback'
|
|
2
|
-
import { Component } from 'react'
|
|
3
|
-
import { ErrorManager } from './ErrorManager'
|
|
4
|
-
|
|
5
|
-
interface State extends ErrorDescription {
|
|
6
|
-
hasError: boolean,
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface Props {
|
|
10
|
-
children: React.ReactNode,
|
|
11
|
-
}
|
|
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
|
-
*/
|
|
22
|
-
export class ErrorBoundary extends Component<Props, State> {
|
|
23
|
-
constructor(props: Props) {
|
|
24
|
-
super(props)
|
|
25
|
-
this.state = { hasError: false }
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static getDerivedStateFromError(error: any) {
|
|
29
|
-
return { hasError: true, ...ErrorManager.describe(error) }
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
componentDidCatch(error: any, errorInfo: any) {
|
|
33
|
-
// eslint-disable-next-line no-console
|
|
34
|
-
console.error(error, errorInfo)
|
|
35
|
-
ErrorManager.runErrorHandler(error)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
39
|
-
if (this.props.children !== prevProps.children) this.setState({ hasError: false })
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
render() {
|
|
43
|
-
return this.state.hasError
|
|
44
|
-
? <ErrorFeedback code={this.state.code} message={this.state.message} debug={this.state.debug} />
|
|
45
|
-
: this.props.children
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
import { ErrorDescription, ErrorFeedback } from '@stack-spot/portal-components/ErrorFeedback'
|
|
2
|
+
import { Component } from 'react'
|
|
3
|
+
import { ErrorManager } from './ErrorManager'
|
|
4
|
+
|
|
5
|
+
interface State extends ErrorDescription {
|
|
6
|
+
hasError: boolean,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
children: React.ReactNode,
|
|
11
|
+
}
|
|
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
|
+
*/
|
|
22
|
+
export class ErrorBoundary extends Component<Props, State> {
|
|
23
|
+
constructor(props: Props) {
|
|
24
|
+
super(props)
|
|
25
|
+
this.state = { hasError: false }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static getDerivedStateFromError(error: any) {
|
|
29
|
+
return { hasError: true, ...ErrorManager.describe(error) }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
componentDidCatch(error: any, errorInfo: any) {
|
|
33
|
+
// eslint-disable-next-line no-console
|
|
34
|
+
console.error(error, errorInfo)
|
|
35
|
+
ErrorManager.runErrorHandler(error)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
39
|
+
if (this.props.children !== prevProps.children) this.setState({ hasError: false })
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
render() {
|
|
43
|
+
return this.state.hasError
|
|
44
|
+
? <ErrorFeedback code={this.state.code} message={this.state.message} debug={this.state.debug} />
|
|
45
|
+
: this.props.children
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import { ErrorDescription } from '@stack-spot/portal-components/ErrorFeedback'
|
|
2
|
-
|
|
3
|
-
export type DescriptionFn = (error: any) => ErrorDescription
|
|
4
|
-
export type ErrorHandler = (error: any) => void
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Setup how the Error Boundaries deal with errors.
|
|
8
|
-
*/
|
|
9
|
-
export class ErrorManager {
|
|
10
|
-
private static descriptionFunction: DescriptionFn = error => ({
|
|
11
|
-
message: error.message || `${error}`,
|
|
12
|
-
})
|
|
13
|
-
private static errorHandler: ErrorHandler | undefined
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Sets a custom logic for generating error messages and codes. Also setups the environment (debug or not).
|
|
17
|
-
* @param fn a function that, given an error, generates its description.
|
|
18
|
-
*/
|
|
19
|
-
static setDescriptionFunction(fn: DescriptionFn) {
|
|
20
|
-
this.descriptionFunction = fn
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Sets a custom error handler, i.e. a function to run every time an error is catch by an ErrorBoundary.
|
|
25
|
-
* @param fn a function that receives the error.
|
|
26
|
-
*/
|
|
27
|
-
static setErrorHandler(handler: ErrorHandler) {
|
|
28
|
-
this.errorHandler = handler
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Uses the error descriptor to describe an error.
|
|
33
|
-
* @param error the error
|
|
34
|
-
* @returns the error description
|
|
35
|
-
*/
|
|
36
|
-
static describe(error: any) {
|
|
37
|
-
return this.descriptionFunction(error)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Runs the error handler, if any has been setup.
|
|
42
|
-
* @param error the error
|
|
43
|
-
*/
|
|
44
|
-
static runErrorHandler(error: any) {
|
|
45
|
-
this.errorHandler?.(error)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
import { ErrorDescription } from '@stack-spot/portal-components/ErrorFeedback'
|
|
2
|
+
|
|
3
|
+
export type DescriptionFn = (error: any) => ErrorDescription
|
|
4
|
+
export type ErrorHandler = (error: any) => void
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Setup how the Error Boundaries deal with errors.
|
|
8
|
+
*/
|
|
9
|
+
export class ErrorManager {
|
|
10
|
+
private static descriptionFunction: DescriptionFn = error => ({
|
|
11
|
+
message: error.message || `${error}`,
|
|
12
|
+
})
|
|
13
|
+
private static errorHandler: ErrorHandler | undefined
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Sets a custom logic for generating error messages and codes. Also setups the environment (debug or not).
|
|
17
|
+
* @param fn a function that, given an error, generates its description.
|
|
18
|
+
*/
|
|
19
|
+
static setDescriptionFunction(fn: DescriptionFn) {
|
|
20
|
+
this.descriptionFunction = fn
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Sets a custom error handler, i.e. a function to run every time an error is catch by an ErrorBoundary.
|
|
25
|
+
* @param fn a function that receives the error.
|
|
26
|
+
*/
|
|
27
|
+
static setErrorHandler(handler: ErrorHandler) {
|
|
28
|
+
this.errorHandler = handler
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Uses the error descriptor to describe an error.
|
|
33
|
+
* @param error the error
|
|
34
|
+
* @returns the error description
|
|
35
|
+
*/
|
|
36
|
+
static describe(error: any) {
|
|
37
|
+
return this.descriptionFunction(error)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Runs the error handler, if any has been setup.
|
|
42
|
+
* @param error the error
|
|
43
|
+
*/
|
|
44
|
+
static runErrorHandler(error: any) {
|
|
45
|
+
this.errorHandler?.(error)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
import { ErrorDescription } from '@stack-spot/portal-components/ErrorFeedback'
|
|
2
|
-
import { theme } from '@stack-spot/portal-theme'
|
|
3
|
-
import { Component } from 'react'
|
|
4
|
-
import { ErrorManager } from './ErrorManager'
|
|
5
|
-
|
|
6
|
-
interface State extends ErrorDescription {
|
|
7
|
-
hasError: boolean,
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface Props {
|
|
11
|
-
children: React.ReactNode,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* An Error Boundary that doesn't render anything if any of its children throws. If the environment is not production, a small error icon
|
|
16
|
-
* is rendered instead of nothing.
|
|
17
|
-
*
|
|
18
|
-
* To customize how the error is logged, setup an error descriptor for the ErrorManager class. If you're using the component `Layout` or
|
|
19
|
-
* `RawLayout`, you can use the property `errorDescriptor`.
|
|
20
|
-
*
|
|
21
|
-
* 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
|
|
22
|
-
* using the component `Layout` or `RawLayout`, you can use the property `onError`.
|
|
23
|
-
*/
|
|
24
|
-
export class SilentErrorBoundary extends Component<Props, State> {
|
|
25
|
-
constructor(props: Props) {
|
|
26
|
-
super(props)
|
|
27
|
-
this.state = { hasError: false }
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
static getDerivedStateFromError(error: any) {
|
|
31
|
-
return { hasError: true, ...ErrorManager.describe(error) }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
componentDidCatch(error: any, errorInfo: any) {
|
|
35
|
-
// eslint-disable-next-line no-console
|
|
36
|
-
console.error(error, errorInfo)
|
|
37
|
-
ErrorManager.runErrorHandler(error)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
41
|
-
if (this.props.children !== prevProps.children) this.setState({ hasError: false })
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
render() {
|
|
45
|
-
return this.state.hasError
|
|
46
|
-
? <div
|
|
47
|
-
title={this.state.message ? `Error: ${this.state.message}` : undefined}
|
|
48
|
-
style={{
|
|
49
|
-
width: '16px',
|
|
50
|
-
height: '16px',
|
|
51
|
-
margin: '16px',
|
|
52
|
-
background: theme.color.danger[500],
|
|
53
|
-
color: theme.color.danger.contrastText,
|
|
54
|
-
display: this.state.debug ? 'flex' : 'none',
|
|
55
|
-
justifyContent: 'center',
|
|
56
|
-
alignItems: 'center',
|
|
57
|
-
fontWeight: 'bold',
|
|
58
|
-
fontSize: '10px',
|
|
59
|
-
borderRadius: '50%',
|
|
60
|
-
}}
|
|
61
|
-
>!</div>
|
|
62
|
-
: this.props.children
|
|
63
|
-
}
|
|
64
|
-
}
|
|
1
|
+
import { ErrorDescription } from '@stack-spot/portal-components/ErrorFeedback'
|
|
2
|
+
import { theme } from '@stack-spot/portal-theme'
|
|
3
|
+
import { Component } from 'react'
|
|
4
|
+
import { ErrorManager } from './ErrorManager'
|
|
5
|
+
|
|
6
|
+
interface State extends ErrorDescription {
|
|
7
|
+
hasError: boolean,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
children: React.ReactNode,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* An Error Boundary that doesn't render anything if any of its children throws. If the environment is not production, a small error icon
|
|
16
|
+
* is rendered instead of nothing.
|
|
17
|
+
*
|
|
18
|
+
* To customize how the error is logged, setup an error descriptor for the ErrorManager class. If you're using the component `Layout` or
|
|
19
|
+
* `RawLayout`, you can use the property `errorDescriptor`.
|
|
20
|
+
*
|
|
21
|
+
* 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
|
|
22
|
+
* using the component `Layout` or `RawLayout`, you can use the property `onError`.
|
|
23
|
+
*/
|
|
24
|
+
export class SilentErrorBoundary extends Component<Props, State> {
|
|
25
|
+
constructor(props: Props) {
|
|
26
|
+
super(props)
|
|
27
|
+
this.state = { hasError: false }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static getDerivedStateFromError(error: any) {
|
|
31
|
+
return { hasError: true, ...ErrorManager.describe(error) }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
componentDidCatch(error: any, errorInfo: any) {
|
|
35
|
+
// eslint-disable-next-line no-console
|
|
36
|
+
console.error(error, errorInfo)
|
|
37
|
+
ErrorManager.runErrorHandler(error)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
41
|
+
if (this.props.children !== prevProps.children) this.setState({ hasError: false })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
render() {
|
|
45
|
+
return this.state.hasError
|
|
46
|
+
? <div
|
|
47
|
+
title={this.state.message ? `Error: ${this.state.message}` : undefined}
|
|
48
|
+
style={{
|
|
49
|
+
width: '16px',
|
|
50
|
+
height: '16px',
|
|
51
|
+
margin: '16px',
|
|
52
|
+
background: theme.color.danger[500],
|
|
53
|
+
color: theme.color.danger.contrastText,
|
|
54
|
+
display: this.state.debug ? 'flex' : 'none',
|
|
55
|
+
justifyContent: 'center',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
fontWeight: 'bold',
|
|
58
|
+
fontSize: '10px',
|
|
59
|
+
borderRadius: '50%',
|
|
60
|
+
}}
|
|
61
|
+
>!</div>
|
|
62
|
+
: this.props.children
|
|
63
|
+
}
|
|
64
|
+
}
|