-
Notifications
You must be signed in to change notification settings - Fork 167
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'refs/heads/feat/public-layout-component' into dev-v3-gl…
…obko
- Loading branch information
Showing
29 changed files
with
1,609 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
import React, { useContext, useRef, useState } from 'react'; | ||
|
||
import { | ||
AppLayoutToolbar, | ||
Button, | ||
ContentLayout, | ||
Header, | ||
HelpPanel, | ||
Link, | ||
SpaceBetween, | ||
SplitPanel, | ||
Toggle, | ||
} from '~components'; | ||
import { AppLayoutToolbarProps } from '~components/app-layout-toolbar'; | ||
|
||
import AppContext, { AppContextType } from '../app/app-context'; | ||
import { Breadcrumbs, Containers, CustomDrawerContent, Navigation } from '../app-layout/utils/content-blocks'; | ||
import { drawerLabels } from '../app-layout/utils/drawers'; | ||
import appLayoutLabels from '../app-layout/utils/labels'; | ||
|
||
type DemoContext = React.Context< | ||
AppContextType<{ | ||
navigationTriggerHide: boolean | undefined; | ||
drawerTriggerHide: boolean | undefined; | ||
splitPanelTriggerHide: boolean | undefined; | ||
breadcrumbsHide: boolean | undefined; | ||
splitPanelPosition: AppLayoutToolbarProps.SplitPanelPreferences['position']; | ||
}> | ||
>; | ||
|
||
export default function WithDrawers() { | ||
const [activeDrawerId, setActiveDrawerId] = useState<string | null>(null); | ||
const [helpPathSlug, setHelpPathSlug] = useState<string>('default'); | ||
const { urlParams, setUrlParams } = useContext(AppContext as DemoContext); | ||
const navigationTriggerHide = urlParams.navigationTriggerHide ?? false; | ||
const drawerTriggerHide = urlParams.drawerTriggerHide ?? false; | ||
const splitPanelTriggerHide = urlParams.splitPanelTriggerHide ?? false; | ||
const breadcrumbsHide = urlParams.breadcrumbsHide ?? false; | ||
const [isToolsOpen, setIsToolsOpen] = useState(false); | ||
const [isNavigationOpen, setIsNavigationOpen] = useState(true); | ||
const [splitPanelOpen, setSplitPanelOpen] = useState(false); | ||
const pageLayoutRef = useRef<AppLayoutToolbarProps.Ref>(null); | ||
|
||
const drawersProps: Pick<AppLayoutToolbarProps, 'activeDrawerId' | 'onDrawerChange' | 'drawers'> | null = { | ||
activeDrawerId: activeDrawerId, | ||
drawers: [ | ||
{ | ||
ariaLabels: { | ||
closeButton: 'ProHelp close button', | ||
drawerName: 'ProHelp drawer content', | ||
triggerButton: 'ProHelp trigger button', | ||
resizeHandle: 'ProHelp resize handle', | ||
}, | ||
content: <CustomDrawerContent />, | ||
id: 'pro-help', | ||
trigger: drawerTriggerHide | ||
? undefined | ||
: { | ||
iconName: 'contact', | ||
}, | ||
}, | ||
], | ||
onDrawerChange: event => { | ||
setActiveDrawerId(event.detail.activeDrawerId); | ||
}, | ||
}; | ||
|
||
return ( | ||
<AppLayoutToolbar | ||
ariaLabels={{ ...appLayoutLabels, ...drawerLabels }} | ||
breadcrumbs={breadcrumbsHide ? undefined : <Breadcrumbs />} | ||
ref={pageLayoutRef} | ||
content={ | ||
<ContentLayout | ||
disableOverlap={true} | ||
header={ | ||
<SpaceBetween size="m"> | ||
<Header | ||
variant="h1" | ||
description="Sometimes you need custom triggers for drawers and navigation to get the job done." | ||
info={ | ||
<Link | ||
data-testid="info-link-header" | ||
variant="info" | ||
onFollow={() => { | ||
setHelpPathSlug('header'); | ||
setIsToolsOpen(true); | ||
pageLayoutRef.current?.focusToolsClose(); | ||
}} | ||
> | ||
Info | ||
</Link> | ||
} | ||
> | ||
Page layout | ||
</Header> | ||
|
||
<SpaceBetween size="xs"> | ||
<Toggle | ||
checked={navigationTriggerHide} | ||
onChange={({ detail }) => setUrlParams({ navigationTriggerHide: detail.checked })} | ||
> | ||
Hide navigation trigger | ||
</Toggle> | ||
<Toggle | ||
checked={drawerTriggerHide} | ||
onChange={({ detail }) => setUrlParams({ drawerTriggerHide: detail.checked })} | ||
> | ||
Hide drawer trigger | ||
</Toggle> | ||
<Toggle | ||
checked={splitPanelTriggerHide} | ||
onChange={({ detail }) => setUrlParams({ splitPanelTriggerHide: detail.checked })} | ||
> | ||
Hide split panel trigger | ||
</Toggle> | ||
<Toggle | ||
checked={breadcrumbsHide} | ||
onChange={({ detail }) => setUrlParams({ breadcrumbsHide: detail.checked })} | ||
> | ||
Hide breadcrumbs | ||
</Toggle> | ||
|
||
<Button | ||
onClick={() => { | ||
setIsNavigationOpen(current => !current); | ||
pageLayoutRef.current?.focusNavigation(); | ||
}} | ||
> | ||
Toggle navigation | ||
</Button> | ||
|
||
<Button | ||
onClick={() => { | ||
setActiveDrawerId('pro-help'); | ||
pageLayoutRef.current?.focusActiveDrawer(); | ||
}} | ||
> | ||
Open a drawer without trigger | ||
</Button> | ||
<Button onClick={() => setActiveDrawerId(null)}>Close a drawer without trigger</Button> | ||
<Button onClick={() => setSplitPanelOpen(true)}>Open split panel</Button> | ||
</SpaceBetween> | ||
</SpaceBetween> | ||
} | ||
> | ||
<Header | ||
info={ | ||
<Link | ||
data-testid="info-link-content" | ||
variant="info" | ||
onFollow={() => { | ||
setHelpPathSlug('content'); | ||
setIsToolsOpen(true); | ||
}} | ||
> | ||
Info | ||
</Link> | ||
} | ||
> | ||
Content | ||
</Header> | ||
<Containers /> | ||
</ContentLayout> | ||
} | ||
splitPanel={ | ||
<SplitPanel | ||
closeBehavior={splitPanelTriggerHide ? 'hide' : undefined} | ||
header="Split panel header" | ||
i18nStrings={{ | ||
preferencesTitle: 'Preferences', | ||
preferencesPositionLabel: 'Split panel position', | ||
preferencesPositionDescription: 'Choose the default split panel position for the service.', | ||
preferencesPositionSide: 'Side', | ||
preferencesPositionBottom: 'Bottom', | ||
preferencesConfirm: 'Confirm', | ||
preferencesCancel: 'Cancel', | ||
closeButtonAriaLabel: 'Close panel', | ||
openButtonAriaLabel: 'Open panel', | ||
resizeHandleAriaLabel: 'Slider', | ||
}} | ||
> | ||
This is the Split Panel! | ||
</SplitPanel> | ||
} | ||
splitPanelOpen={splitPanelOpen} | ||
splitPanelPreferences={{ | ||
position: urlParams.splitPanelPosition, | ||
}} | ||
onSplitPanelToggle={event => setSplitPanelOpen(event.detail.open)} | ||
onSplitPanelPreferencesChange={event => { | ||
const { position } = event.detail; | ||
setUrlParams({ splitPanelPosition: position === 'side' ? position : undefined }); | ||
}} | ||
onToolsChange={event => { | ||
setIsToolsOpen(event.detail.open); | ||
}} | ||
tools={<Info helpPathSlug={helpPathSlug} />} | ||
toolsOpen={isToolsOpen} | ||
navigationOpen={isNavigationOpen} | ||
navigation={<Navigation />} | ||
onNavigationChange={event => setIsNavigationOpen(event.detail.open)} | ||
navigationTriggerHide={navigationTriggerHide} | ||
{...drawersProps} | ||
/> | ||
); | ||
} | ||
|
||
function Info({ helpPathSlug }: { helpPathSlug: string }) { | ||
return <HelpPanel header={<h2>Info</h2>}>Here is some info for you: {helpPathSlug}</HelpPanel>; | ||
} |
104 changes: 104 additions & 0 deletions
104
pages/app-layout-toolbar/multi-layout-with-hidden-instances.page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
import React, { useRef, useState } from 'react'; | ||
|
||
import AppLayoutToolbar from '~components/app-layout-toolbar'; | ||
import BreadcrumbGroup from '~components/breadcrumb-group'; | ||
import Header from '~components/header'; | ||
import ScreenreaderOnly from '~components/internal/components/screenreader-only'; | ||
import Link from '~components/link'; | ||
import SideNavigation, { SideNavigationProps } from '~components/side-navigation'; | ||
import SpaceBetween from '~components/space-between'; | ||
|
||
import { Tools } from '../app-layout/utils/content-blocks'; | ||
import labels from '../app-layout/utils/labels'; | ||
import { IframeWrapper } from '../utils/iframe-wrapper'; | ||
import ScreenshotArea from '../utils/screenshot-area'; | ||
|
||
function createView(name: string) { | ||
return function View() { | ||
return ( | ||
<AppLayoutToolbar | ||
data-testid="secondary-layout" | ||
ariaLabels={labels} | ||
breadcrumbs={ | ||
name !== 'page2' && ( | ||
<BreadcrumbGroup | ||
onFollow={event => event.preventDefault()} | ||
items={[ | ||
{ text: 'Home', href: '#' }, | ||
{ text: name, href: `#${name}` }, | ||
]} | ||
/> | ||
) | ||
} | ||
navigationHide={true} | ||
content={ | ||
<SpaceBetween size="s"> | ||
<Header variant="h1" description="This page contains nested app layout instances"> | ||
Multiple page layouts | ||
</Header> | ||
|
||
<Link external={true} href="#"> | ||
External link | ||
</Link> | ||
|
||
<div>Page content: {name}</div> | ||
</SpaceBetween> | ||
} | ||
tools={<Tools>Tools content: {name}</Tools>} | ||
/> | ||
); | ||
}; | ||
} | ||
|
||
const ROUTES: Array<{ navLink: SideNavigationProps.Link; View: React.ComponentType }> = [ | ||
{ navLink: { type: 'link', text: 'Page 1', href: 'page1' }, View: createView('page1') }, | ||
{ navLink: { type: 'link', text: 'Page 2', href: 'page2' }, View: createView('page2') }, | ||
{ navLink: { type: 'link', text: 'Page 3', href: 'page3' }, View: createView('page3') }, | ||
]; | ||
|
||
export default function () { | ||
const [activeHref, setActiveHref] = useState('page1'); | ||
const openPagesHistory = useRef<Set<string>>(new Set([activeHref])); | ||
|
||
return ( | ||
<ScreenshotArea gutters={false}> | ||
<AppLayoutToolbar | ||
{...{ __disableRuntimeDrawers: true }} | ||
data-testid="main-layout" | ||
ariaLabels={labels} | ||
navigation={ | ||
<SideNavigation | ||
activeHref={activeHref} | ||
header={{ href: '#/', text: 'Service name' }} | ||
onFollow={event => { | ||
if (!event.detail.external) { | ||
event.preventDefault(); | ||
openPagesHistory.current.add(event.detail.href); | ||
setActiveHref(event.detail.href); | ||
} | ||
}} | ||
items={ROUTES.map(route => route.navLink)} | ||
/> | ||
} | ||
toolsHide={true} | ||
disableContentPaddings={true} | ||
content={ | ||
<> | ||
<ScreenreaderOnly> | ||
<h1>Multiple app layouts with iframe</h1> | ||
</ScreenreaderOnly> | ||
{ROUTES.filter( | ||
item => item.navLink.href === activeHref || openPagesHistory.current.has(item.navLink.href) | ||
).map(item => ( | ||
<div key={item.navLink.href} style={{ display: item.navLink.href !== activeHref ? 'none' : '' }}> | ||
<IframeWrapper id={item.navLink.href} AppComponent={item.View} /> | ||
</div> | ||
))} | ||
</> | ||
} | ||
/> | ||
</ScreenshotArea> | ||
); | ||
} |
Oops, something went wrong.