Skip to content

Commit 4bc6709

Browse files
committed
poc
1 parent a0595cc commit 4bc6709

File tree

20 files changed

+591
-92
lines changed

20 files changed

+591
-92
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@
167167
{
168168
"path": "lib/components/internal/widget-exports.js",
169169
"brotli": false,
170-
"limit": "810 kB",
170+
"limit": "840 kB",
171171
"ignore": "react-dom"
172172
}
173173
],

pages/app/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ function isAppLayoutPage(pageId?: string) {
4242
'prompt-input/simple',
4343
'funnel-analytics/static-single-page-flow',
4444
'funnel-analytics/static-multi-page-flow',
45+
'error-boundaries',
4546
];
4647
return pageId !== undefined && appLayoutPages.some(match => pageId.includes(match));
4748
}

pages/error-boundary/demo.page.tsx

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import React, { useContext, useState } from 'react';
5+
6+
import {
7+
AppLayout,
8+
Box,
9+
Button,
10+
Checkbox,
11+
Container,
12+
Drawer,
13+
ExpandableSection,
14+
Header,
15+
Modal,
16+
Popover,
17+
SpaceBetween,
18+
SplitPanel,
19+
Table,
20+
} from '~components';
21+
import { ErrorBoundariesProvider } from '~components/error-boundary/context';
22+
import I18nProvider from '~components/i18n';
23+
import messages from '~components/i18n/messages/all.en';
24+
import {
25+
colorBackgroundStatusError,
26+
colorBorderStatusError,
27+
colorTextInteractiveInvertedHover,
28+
colorTextStatusError,
29+
} from '~design-tokens';
30+
31+
import AppContext, { AppContextType } from '../app/app-context';
32+
import ScreenshotArea from '../utils/screenshot-area';
33+
34+
type PageContext = React.Context<AppContextType<{ errorBoundariesActive: boolean }>>;
35+
36+
export default function () {
37+
const {
38+
urlParams: { errorBoundariesActive = true },
39+
setUrlParams,
40+
} = useContext(AppContext as PageContext);
41+
const [splitPanelOpen, setSplitPanelOpen] = useState(true);
42+
const [activeDrawerId, setActiveDrawerId] = useState<null | string>('d1');
43+
const [modalOpen, setModalOpen] = useState(false);
44+
return (
45+
<ScreenshotArea gutters={false}>
46+
<I18nProvider messages={[messages]} locale="en">
47+
<ErrorBoundariesProvider active={errorBoundariesActive} value={{ feedbackLink: '/#' }}>
48+
<AppLayout
49+
navigationHide={true}
50+
activeDrawerId={activeDrawerId}
51+
onDrawerChange={({ detail }) => setActiveDrawerId(detail.activeDrawerId)}
52+
splitPanel={
53+
<SplitPanel header="Split panel">
54+
<BrokenButton />
55+
</SplitPanel>
56+
}
57+
splitPanelOpen={splitPanelOpen}
58+
onSplitPanelToggle={({ detail }) => setSplitPanelOpen(detail.open)}
59+
drawers={[
60+
{
61+
id: 'd1',
62+
content: (
63+
<Drawer header={<Header variant="h2">Drawer 1</Header>}>
64+
<BrokenButton />
65+
</Drawer>
66+
),
67+
trigger: { iconName: 'bug' },
68+
ariaLabels: { drawerName: 'Drawer 1', triggerButton: 'Open drawer 1', closeButton: 'Close drawer 1' },
69+
},
70+
{
71+
id: 'd2',
72+
content: (
73+
<Drawer header={<Header variant="h2">Drawer 2</Header>}>
74+
<BrokenButton />
75+
</Drawer>
76+
),
77+
trigger: { iconName: 'call' },
78+
ariaLabels: { drawerName: 'Drawer 2', triggerButton: 'Open drawer 2', closeButton: 'Close drawer 2' },
79+
},
80+
]}
81+
content={
82+
<Box>
83+
<h1>Error boundary demo</h1>
84+
<Box margin={{ bottom: 'm' }}>
85+
<Checkbox
86+
checked={errorBoundariesActive}
87+
onChange={({ detail }) => setUrlParams({ errorBoundariesActive: detail.checked })}
88+
>
89+
Error boundaries on
90+
</Checkbox>
91+
</Box>
92+
93+
<SpaceBetween size="m">
94+
<SpaceBetween size="m" direction="horizontal">
95+
<BrokenButton />
96+
97+
<Box>
98+
<Button onClick={() => setModalOpen(true)}>Show modal</Button>
99+
<Modal visible={modalOpen} header="Modal" onDismiss={() => setModalOpen(false)}>
100+
<BrokenButton />
101+
</Modal>
102+
</Box>
103+
104+
<Popover header="Header" content={<BrokenButton />} triggerType="custom">
105+
<Button>Show popover</Button>
106+
</Popover>
107+
</SpaceBetween>
108+
109+
<Container header={<Header>Container 1</Header>}>
110+
<BrokenButton />
111+
</Container>
112+
113+
<Container header={<Header>Container 2</Header>}>
114+
<BrokenButton />
115+
</Container>
116+
117+
<ExpandableSection
118+
variant="container"
119+
headerText="Expandable section"
120+
headerActions={<BrokenButton />}
121+
defaultExpanded={true}
122+
>
123+
<BrokenButton />
124+
</ExpandableSection>
125+
126+
<Table
127+
header={<Header>Table</Header>}
128+
columnDefinitions={[
129+
{ header: 'Column 1', cell: item => `Content 1:${item}` },
130+
{ header: 'Column 2', cell: item => `Content 2:${item}` },
131+
{ header: 'Column 3', cell: item => `Content 3:${item}` },
132+
{ header: 'Actions', cell: () => <BrokenButton /> },
133+
]}
134+
items={[1, 2, 3]}
135+
></Table>
136+
</SpaceBetween>
137+
</Box>
138+
}
139+
/>
140+
</ErrorBoundariesProvider>
141+
</I18nProvider>
142+
</ScreenshotArea>
143+
);
144+
}
145+
146+
function BrokenButton() {
147+
const [errorState, setErrorState] = useState(false);
148+
const colorsDefault = [colorTextStatusError, colorBorderStatusError, undefined];
149+
const colorsHover = [colorTextStatusError, colorBorderStatusError, colorBackgroundStatusError];
150+
const colorsActive = [colorTextInteractiveInvertedHover, colorBorderStatusError, colorTextStatusError];
151+
return (
152+
<Button
153+
style={{
154+
root: {
155+
color: { default: colorsDefault[0], hover: colorsHover[0], active: colorsActive[0] },
156+
borderColor: { default: colorsDefault[1], hover: colorsHover[1], active: colorsActive[1] },
157+
background: { default: colorsDefault[2], hover: colorsHover[2], active: colorsActive[2] },
158+
},
159+
}}
160+
onClick={() => setErrorState(true)}
161+
>
162+
Broken button {errorState ? {} : ''}
163+
</Button>
164+
);
165+
}

src/app-layout/error-boundary.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import React from 'react';
5+
6+
import InternalErrorBoundary from '../error-boundary/internal';
7+
8+
import styles from './styles.css.js';
9+
10+
export function ErrorBoundaryMain({ children }: { children: React.ReactNode }) {
11+
return (
12+
<InternalErrorBoundary wrapper={content => <div className={styles['error-boundary-wrapper']}>{content}</div>}>
13+
{children}
14+
</InternalErrorBoundary>
15+
);
16+
}

src/app-layout/styles.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
min-inline-size: 0;
3636
background-color: awsui.$color-background-layout-main;
3737
position: relative;
38+
3839
&-scrollable {
3940
overflow: auto;
4041
}
@@ -68,3 +69,10 @@
6869
// applied to content or content header, whatever comes first
6970
padding-block-start: awsui.$space-scaled-m;
7071
}
72+
73+
.error-boundary-wrapper {
74+
block-size: 100%;
75+
display: flex;
76+
align-items: center;
77+
justify-content: center;
78+
}

src/app-layout/visual-refresh-toolbar/drawer/local-drawer.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export function AppLayoutDrawerImplementation({ appLayoutInternals }: AppLayoutD
128128
/>
129129
</div>
130130
<div
131+
key={TOOLS_DRAWER_ID}
131132
className={clsx(
132133
styles['drawer-content'],
133134
activeDrawerId !== TOOLS_DRAWER_ID && styles['drawer-content-hidden']
@@ -137,7 +138,7 @@ export function AppLayoutDrawerImplementation({ appLayoutInternals }: AppLayoutD
137138
{toolsContent}
138139
</div>
139140
{activeDrawerId !== TOOLS_DRAWER_ID && (
140-
<div className={styles['drawer-content']} style={{ blockSize: drawerHeight }}>
141+
<div key={activeDrawerId} className={styles['drawer-content']} style={{ blockSize: drawerHeight }}>
141142
{activeDrawer?.content}
142143
</div>
143144
)}

src/app-layout/visual-refresh-toolbar/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useMobile } from '../../internal/hooks/use-mobile';
1313
import { useGetGlobalBreadcrumbs } from '../../internal/plugins/helpers/use-global-breadcrumbs';
1414
import globalVars from '../../internal/styles/global-vars';
1515
import { getSplitPanelDefaultSize } from '../../split-panel/utils/size-utils';
16+
import { ErrorBoundaryMain } from '../error-boundary';
1617
import { AppLayoutProps } from '../interfaces';
1718
import { SplitPanelProviderProps } from '../split-panel';
1819
import { MIN_DRAWER_SIZE, OnChangeParams, useDrawers } from '../utils/use-drawers';
@@ -517,7 +518,7 @@ const AppLayoutVisualRefreshToolbar = React.forwardRef<AppLayoutProps.Ref, AppLa
517518
headerVariant={headerVariant}
518519
contentHeader={contentHeader}
519520
// delay rendering the content until registration of this instance is complete
520-
content={registered ? content : null}
521+
content={registered ? <ErrorBoundaryMain>{content}</ErrorBoundaryMain> : null}
521522
navigation={resolvedNavigation && <AppLayoutNavigation appLayoutInternals={appLayoutInternals} />}
522523
navigationOpen={resolvedNavigationOpen}
523524
navigationWidth={navigationWidth}

src/app-layout/visual-refresh/drawers.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ function ActiveDrawer() {
143143
</div>
144144
{toolsContent && (
145145
<div
146+
key={TOOLS_DRAWER_ID}
146147
className={clsx(
147148
styles['drawer-content'],
148149
activeDrawerId !== TOOLS_DRAWER_ID && styles['drawer-content-hidden']
@@ -152,7 +153,9 @@ function ActiveDrawer() {
152153
</div>
153154
)}
154155
{activeDrawerId !== TOOLS_DRAWER_ID && (
155-
<div className={styles['drawer-content']}>{activeDrawerId && activeDrawer?.content}</div>
156+
<div key={activeDrawerId} className={styles['drawer-content']}>
157+
{activeDrawerId && activeDrawer?.content}
158+
</div>
156159
)}
157160
</div>
158161
</aside>

src/app-layout/visual-refresh/main.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import clsx from 'clsx';
55

66
import customCssProps from '../../internal/generated/custom-css-properties';
77
import * as tokens from '../../internal/generated/styles/tokens';
8+
import { ErrorBoundaryMain } from '../error-boundary';
89
import { getStickyOffsetVars } from '../utils/sticky-offsets';
910
import { useAppLayoutInternals } from './context';
1011

@@ -63,7 +64,7 @@ export default function Main() {
6364
),
6465
}}
6566
>
66-
{content}
67+
<ErrorBoundaryMain>{content}</ErrorBoundaryMain>
6768
</div>
6869
);
6970
}

0 commit comments

Comments
 (0)