WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build-tools/utils/pluralize.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const pluralizationMap = {
SpaceBetween: 'SpaceBetweens',
Spinner: 'Spinners',
SplitPanel: 'SplitPanels',
SplitView: 'SplitViews',
StatusIndicator: 'StatusIndicators',
Steps: 'Steps',
Table: 'Tables',
Expand Down
71 changes: 65 additions & 6 deletions pages/app-layout/utils/external-global-left-panel-widget.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,49 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import React, { useState } from 'react';

import { Box, Button } from '~components';
import { useContainerQuery } from '@cloudscape-design/component-toolkit';

import { Box, Button, SplitView } from '~components';
import { registerLeftDrawer, updateDrawer } from '~components/internal/plugins/widget';
import { mount, unmount } from '~mount';

import styles from '../styles.scss';

const DEFAULT_SIZE = 360;
const CHAT_SIZE = 280;
const MIN_CHAT_SIZE = 150;
const MIN_ARTIFACT_SIZE = 360;

const AIDrawer = () => {
return (
<Box padding="m">
const [hasArtifact, setHasArtifact] = useState(false);
const [artifactLoaded, setArtifactLoaded] = useState(false);
const [chatSize, setChatSize] = useState(CHAT_SIZE);
const [_maxPanelSize, ref] = useContainerQuery(entry => entry.contentBoxWidth - MIN_ARTIFACT_SIZE);
const maxPanelSize = _maxPanelSize ?? Number.MAX_SAFE_INTEGER;
const constrainedChatSize = Math.min(chatSize, maxPanelSize);
const collapsed = constrainedChatSize < MIN_CHAT_SIZE;

const chatContent = (
<>
<Box variant="h2" padding={{ bottom: 'm' }}>
Chat demo
</Box>
<Button
onClick={() => {
setHasArtifact(true);
updateDrawer({ type: 'expandDrawer', payload: { id: 'ai-panel' } });
updateDrawer({
type: 'updateDrawerConfig',
payload: {
id: 'ai-panel',
defaultSize: DEFAULT_SIZE + CHAT_SIZE,
minSize: DEFAULT_SIZE + CHAT_SIZE,
} as any,
});
}}
>
expand programmatically
Open artifact
</Button>
<Button
onClick={() => {
Expand All @@ -39,15 +63,50 @@ const AIDrawer = () => {
{new Array(100).fill(null).map((_, index) => (
<div key={index}>Tela content</div>
))}
</>
);
const artifactContent = (
<Box padding="m">
<Box variant="h2" padding={{ bottom: 'm' }}>
Artifact
</Box>
<Button
onClick={() => {
setHasArtifact(false);
updateDrawer({ type: 'exitExpandedMode' });
updateDrawer({
type: 'updateDrawerConfig',
payload: { id: 'ai-panel', defaultSize: DEFAULT_SIZE, minSize: DEFAULT_SIZE } as any,
});
}}
>
Close artifact panel
</Button>
<Button onClick={() => setArtifactLoaded(true)}>Load artifact details</Button>
{artifactLoaded && new Array(100).fill(null).map((_, index) => <div key={index}>Tela content</div>)}
</Box>
);
return (
<div ref={ref} style={{ width: '100%', overflow: 'hidden' }}>
<SplitView
resizable={true}
panelSize={constrainedChatSize}
maxPanelSize={maxPanelSize}
minPanelSize={MIN_CHAT_SIZE}
onPanelResize={({ detail }) => setChatSize(detail.panelSize)}
panelContent={chatContent}
mainContent={<div className={styles['ai-artifact-panel']}>{artifactContent}</div>}
display={hasArtifact ? (collapsed ? 'main-only' : 'all') : 'panel-only'}
/>
</div>
);
};

registerLeftDrawer({
id: 'ai-panel',
resizable: true,
isExpandable: true,
defaultSize: 420,
defaultSize: DEFAULT_SIZE,
preserveInactiveContent: true,

ariaLabels: {
Expand Down
203 changes: 203 additions & 0 deletions pages/split-view/app-layout-panel.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useContext, useState } from 'react';

import { useContainerQuery } from '@cloudscape-design/component-toolkit';

import { Checkbox, Drawer, FormField, Header, Input, SegmentedControl, SpaceBetween } from '~components';
import AppLayout from '~components/app-layout';
import Button from '~components/button';
import { I18nProvider } from '~components/i18n';
import messages from '~components/i18n/messages/all.en';
import SplitView, { SplitViewProps } from '~components/split-view';

import AppContext, { AppContextType } from '../app/app-context';
import labels from '../app-layout/utils/labels';
import ScreenshotArea from '../utils/screenshot-area';

interface SplitViewContentProps {
longPanelContent: boolean;
longMainContent: boolean;
minPanelSize: number;
maxPanelSize: number;
minContentSize: number;
display: SplitViewProps.Display;
panelPosition: SplitViewProps.PanelPosition;
}
type PageContext = React.Context<AppContextType<Partial<SplitViewContentProps>>>;

const SplitViewContent = ({
longPanelContent,
longMainContent,
minContentSize,
minPanelSize,
maxPanelSize,
display,
panelPosition,
}: SplitViewContentProps) => {
const [size, setSize] = useState(Math.max(200, minPanelSize));

const [_actualMaxPanelSize, ref] = useContainerQuery(
entry => Math.min(entry.contentBoxWidth - minContentSize, maxPanelSize),
[minContentSize, maxPanelSize]
);
const actualMaxPanelSize = _actualMaxPanelSize ?? maxPanelSize;
const actualSize = Math.min(size, actualMaxPanelSize);

const collapsed = actualMaxPanelSize < minPanelSize;

return (
<div ref={ref} style={{ height: '100%', overflow: 'hidden', backgroundColor: 'lightgrey' }}>
{collapsed ? (
'Collapsed view'
) : (
<SplitView
panelSize={actualSize}
minPanelSize={minPanelSize}
maxPanelSize={actualMaxPanelSize}
resizable={true}
onPanelResize={({ detail }) => setSize(detail.panelSize)}
display={display}
panelPosition={panelPosition}
panelContent={
<>
<Header>Panel content</Header>
{new Array(longPanelContent ? 20 : 1)
.fill('Lorem ipsum dolor sit amet, consectetur adipiscing elit.')
.map((t, i) => (
<div key={i}>{t}</div>
))}
<Button>Button</Button>
</>
}
mainContent={
<>
<Header>Main content</Header>
{new Array(longMainContent ? 200 : 1)
.fill('Lorem ipsum dolor sit amet, consectetur adipiscing elit.')
.map((t, i) => (
<div key={i}>{t}</div>
))}
<Button>button</Button>
</>
}
/>
)}
</div>
);
};

export default function SplitViewPage() {
const {
urlParams: {
longPanelContent = false,
longMainContent = false,
minPanelSize = 200,
maxPanelSize = 600,
minContentSize = 600,
display = 'all',
panelPosition = 'side-start',
},
setUrlParams,
} = useContext(AppContext as PageContext);

return (
<I18nProvider messages={[messages]} locale="en">
<ScreenshotArea disableAnimations={true} gutters={false}>
<AppLayout
ariaLabels={labels}
navigation={
<Drawer header="Settings">
<SpaceBetween direction="vertical" size="m">
<Checkbox
checked={longMainContent}
onChange={({ detail }) => setUrlParams({ longMainContent: detail.checked })}
>
Long main content
</Checkbox>
<Checkbox
checked={longPanelContent}
onChange={({ detail }) => setUrlParams({ longPanelContent: detail.checked })}
>
Long panel content
</Checkbox>
<FormField label="Minimum panel size">
<Input
type="number"
value={minPanelSize.toString()}
onChange={({ detail }) => setUrlParams({ minPanelSize: detail.value ? parseInt(detail.value) : 0 })}
/>
</FormField>
<FormField label="Maximum panel size">
<Input
type="number"
value={maxPanelSize.toString()}
onChange={({ detail }) =>
setUrlParams({ maxPanelSize: detail.value ? parseInt(detail.value) : Number.MAX_SAFE_INTEGER })
}
/>
</FormField>
<FormField label="Minimum content size">
<Input
type="number"
value={minContentSize.toString()}
onChange={({ detail }) =>
setUrlParams({ minContentSize: detail.value ? parseInt(detail.value) : 0 })
}
/>
</FormField>
<FormField label="Panel position">
<SegmentedControl
options={[
{ id: 'side-start', text: 'side-start' },
{ id: 'side-end', text: 'side-end' },
]}
selectedId={panelPosition}
onChange={({ detail }) => setUrlParams({ panelPosition: detail.selectedId as any })}
/>
</FormField>
<FormField label="Display">
<SegmentedControl
options={[
{ id: 'all', text: 'all' },
{ id: 'panel-only', text: 'panel-only' },
{ id: 'main-only', text: 'main-only' },
]}
selectedId={display}
onChange={({ detail }) => setUrlParams({ display: detail.selectedId as any })}
/>
</FormField>
</SpaceBetween>
</Drawer>
}
content={<Header variant="h1">Split view in drawer demo</Header>}
drawers={[
{
id: 'panel',
content: (
<SplitViewContent
longMainContent={longMainContent}
longPanelContent={longPanelContent}
minPanelSize={minPanelSize}
maxPanelSize={maxPanelSize}
minContentSize={minContentSize}
display={display}
panelPosition={panelPosition}
/>
),
resizable: true,
defaultSize: 1000,
ariaLabels: {
drawerName: 'Panel',
triggerButton: 'Open panel',
closeButton: 'Close panel',
resizeHandle: 'Resize drawer',
},
trigger: { iconName: 'contact' },
},
]}
/>
</ScreenshotArea>
</I18nProvider>
);
}
Loading
Loading