diff --git a/package.json b/package.json
index 368682e67d..ac9888bb64 100644
--- a/package.json
+++ b/package.json
@@ -53,8 +53,11 @@
"devDependencies": {
"@babel/core": "^7.23.7",
"@babel/plugin-syntax-typescript": "^7.23.3",
+ "@cloudscape-design/board-components": "^3.0.191",
"@cloudscape-design/browser-test-tools": "^3.0.0",
"@cloudscape-design/build-tools": "github:cloudscape-design/build-tools#main",
+ "@cloudscape-design/chat-components": "^1.0.140",
+ "@cloudscape-design/code-view": "^3.0.142",
"@cloudscape-design/documenter": "^1.0.0",
"@cloudscape-design/global-styles": "^1.0.0",
"@cloudscape-design/jest-preset": "^2.0.0",
diff --git a/pages/components-overview/board-section.tsx b/pages/components-overview/board-section.tsx
new file mode 100644
index 0000000000..7dc311becd
--- /dev/null
+++ b/pages/components-overview/board-section.tsx
@@ -0,0 +1,52 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React from 'react';
+
+import Board from '@cloudscape-design/board-components/board';
+import BoardItem from '@cloudscape-design/board-components/board-item';
+
+import Header from '~components/header';
+import SpaceBetween from '~components/space-between';
+
+import { Section } from './utils';
+
+export default function BoardSection() {
+ return (
+
+ (
+ {item.data.title}}
+ i18nStrings={{
+ dragHandleAriaLabel: 'Drag handle',
+ dragHandleAriaDescription: 'Use arrow keys to move, space to confirm, escape to cancel',
+ resizeHandleAriaLabel: 'Resize handle',
+ resizeHandleAriaDescription: 'Use arrow keys to resize, space to confirm, escape to cancel',
+ }}
+ >
+ {item.data.content}
+
+ )}
+ onItemsChange={() => {}}
+ empty="No items"
+ i18nStrings={{
+ liveAnnouncementDndStarted: () => '',
+ liveAnnouncementDndItemReordered: () => '',
+ liveAnnouncementDndItemResized: () => '',
+ liveAnnouncementDndItemInserted: () => '',
+ liveAnnouncementDndCommitted: () => '',
+ liveAnnouncementDndDiscarded: () => '',
+ liveAnnouncementItemRemoved: () => '',
+ navigationAriaLabel: 'Board navigation',
+ navigationAriaDescription: 'Click on non-empty item to move focus',
+ navigationItemAriaLabel: () => '',
+ }}
+ />
+
+ );
+}
diff --git a/pages/components-overview/buttons-inputs-dropdowns.tsx b/pages/components-overview/buttons-inputs-dropdowns.tsx
new file mode 100644
index 0000000000..da888b93f9
--- /dev/null
+++ b/pages/components-overview/buttons-inputs-dropdowns.tsx
@@ -0,0 +1,361 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React, { useState } from 'react';
+
+import Autosuggest from '~components/autosuggest';
+import Box from '~components/box';
+import Button from '~components/button';
+import ButtonDropdown from '~components/button-dropdown';
+import ButtonGroup from '~components/button-group';
+import Container from '~components/container';
+import DatePicker from '~components/date-picker';
+import DateRangePicker, { DateRangePickerProps } from '~components/date-range-picker';
+import Grid from '~components/grid';
+import Header from '~components/header';
+import Modal from '~components/modal';
+import Multiselect, { MultiselectProps } from '~components/multiselect';
+import Popover from '~components/popover';
+import PropertyFilter, { PropertyFilterProps } from '~components/property-filter';
+import SegmentedControl from '~components/segmented-control';
+import SpaceBetween from '~components/space-between';
+import StatusIndicator from '~components/status-indicator';
+import ToggleButton from '~components/toggle-button';
+
+import { generateDropdownOptions } from './component-data';
+
+function Buttons() {
+ const [selectedSegment, setSelectedSegment] = useState('seg-1');
+ const [toggle1, setToggle1] = useState(true);
+ const [toggle2, setToggle2] = useState(false);
+ const [toggle3, setToggle3] = useState(false);
+ const [toggle4, setToggle4] = useState(true);
+ const [toggle5, setToggle5] = useState(false);
+ const [toggle6, setToggle6] = useState(true);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setToggle1(detail.pressed)}
+ pressed={toggle1}
+ iconName="star"
+ pressedIconName="star-filled"
+ >
+ Toggle button
+
+ setToggle2(detail.pressed)}
+ pressed={toggle2}
+ iconName="star"
+ pressedIconName="star-filled"
+ >
+ Toggle button
+
+ setToggle3(detail.pressed)}
+ pressed={toggle3}
+ iconName="star"
+ pressedIconName="star-filled"
+ ariaLabel="Toggle button"
+ />
+ setToggle4(detail.pressed)}
+ pressed={toggle4}
+ iconName="star"
+ pressedIconName="star-filled"
+ ariaLabel="Toggle button pressed"
+ />
+ setToggle5(detail.pressed)}
+ pressed={toggle5}
+ iconName="star"
+ pressedIconName="star-filled"
+ ariaLabel="Toggle button icon"
+ />
+ setToggle6(detail.pressed)}
+ pressed={toggle6}
+ iconName="star"
+ pressedIconName="star-filled"
+ ariaLabel="Toggle button icon pressed"
+ />
+
+ setSelectedSegment(detail.selectedId)}
+ label="Default segmented control"
+ options={[
+ { text: 'Segment 1', id: 'seg-1' },
+ { text: 'Segment 2', id: 'seg-2' },
+ { text: 'Segment 3', id: 'seg-3' },
+ ]}
+ />
+
+ );
+}
+
+function Inputs() {
+ const multiSelectOptions = generateDropdownOptions() as MultiselectProps.Options;
+ const [selectedItems, setSelectedItems] = useState([
+ multiSelectOptions[1],
+ multiSelectOptions[3],
+ ] as MultiselectProps.Options);
+ const [dateValue, setDateValue] = useState('2018-01-02');
+ const [dateRangeValue, setDateRangeValue] = useState(null);
+ const [autosuggestValue, setAutosuggestValue] = useState('');
+
+ return (
+
+
+ setSelectedItems(detail.selectedOptions)}
+ />
+
+
+
+
+ setAutosuggestValue(detail.value)}
+ options={[
+ { value: 'us-east-1', label: 'US East (N. Virginia)' },
+ { value: 'us-west-2', label: 'US West (Oregon)' },
+ { value: 'eu-west-1', label: 'Europe (Ireland)' },
+ ]}
+ placeholder="Autosuggest"
+ ariaLabel="Autosuggest example"
+ />
+ {}}
+ options={[]}
+ disabled={true}
+ placeholder="Disabled"
+ ariaLabel="Disabled autosuggest"
+ />
+ {}}
+ options={[]}
+ readOnly={true}
+ placeholder="Read-only"
+ ariaLabel="Read-only autosuggest"
+ />
+
+
+ 'Open calendar'}
+ onChange={({ detail }) => setDateValue(detail.value)}
+ />
+ setDateRangeValue(detail.value)}
+ relativeOptions={[
+ { key: 'previous-5-minutes', amount: 5, unit: 'minute', type: 'relative' },
+ { key: 'previous-30-minutes', amount: 30, unit: 'minute', type: 'relative' },
+ { key: 'previous-1-hour', amount: 1, unit: 'hour', type: 'relative' },
+ ]}
+ isValidRange={range => {
+ if (range?.type === 'absolute') {
+ const [startDateWithoutTime] = range.startDate.split('T');
+ const [endDateWithoutTime] = range.endDate.split('T');
+ if (!startDateWithoutTime || !endDateWithoutTime) {
+ return { valid: false, errorMessage: 'The selected date range is incomplete.' };
+ }
+ }
+ return { valid: true };
+ }}
+ i18nStrings={{}}
+ placeholder="Filter by a date and time range"
+ />
+
+
+ );
+}
+
+export default function ButtonsInputsDropdowns() {
+ const [query, setQuery] = React.useState({ tokens: [], operation: 'and' });
+ const [modalVisible, setModalVisible] = React.useState(false);
+ return (
+
+ Buttons, inputs, and dropdowns
+
+
+
+
+
+
+
+ setQuery(detail)}
+ countText="5 matches"
+ enableTokenGroups={true}
+ expandToViewport={true}
+ filteringAriaLabel="Find distributions"
+ filteringOptions={[
+ { propertyKey: 'instanceid', value: 'i-2dc5ce28a0328391' },
+ { propertyKey: 'instanceid', value: 'i-d0312e022392efa0' },
+ { propertyKey: 'state', value: 'Stopped' },
+ { propertyKey: 'state', value: 'Running' },
+ { propertyKey: 'instancetype', value: 't3.small' },
+ { propertyKey: 'instancetype', value: 't2.small' },
+ ]}
+ filteringPlaceholder="Find distributions"
+ filteringProperties={[
+ {
+ key: 'instanceid',
+ operators: ['=', '!=', ':', '!:'],
+ propertyLabel: 'Instance ID',
+ groupValuesLabel: 'Instance ID values',
+ },
+ {
+ key: 'state',
+ operators: [{ operator: '=', tokenType: 'enum' }, { operator: '!=', tokenType: 'enum' }, ':', '!:'],
+ propertyLabel: 'State',
+ groupValuesLabel: 'State values',
+ },
+ {
+ key: 'instancetype',
+ operators: [{ operator: '=', tokenType: 'enum' }, { operator: '!=', tokenType: 'enum' }, ':', '!:'],
+ propertyLabel: 'Instance type',
+ groupValuesLabel: 'Instance type values',
+ },
+ ]}
+ />
+
+
+
+
+
+
+ Actions
+
+
+ Primary dropdown
+
+
+ Disabled dropdown
+
+
+
+
+
+ High memory
+
+
+ Normal latency
+
+ Normal latency
+ Error latency
+ Pending instance
+
+
+
+
+
+
+
+ setModalVisible(false)}
+ header="Delete resource"
+ footer={
+
+
+
+
+
+
+ }
+ >
+ Are you sure you want to delete this resource? This action cannot be undone.
+
+
+
+
+
+
+ );
+}
diff --git a/pages/components-overview/charts.tsx b/pages/components-overview/charts.tsx
new file mode 100644
index 0000000000..ae59823aa5
--- /dev/null
+++ b/pages/components-overview/charts.tsx
@@ -0,0 +1,155 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React from 'react';
+
+import BarChart from '~components/bar-chart';
+import Box from '~components/box';
+import Button from '~components/button';
+import ColumnLayout from '~components/column-layout';
+import LineChart from '~components/line-chart';
+import PieChart from '~components/pie-chart';
+
+import { Section, SubSection } from './utils';
+
+const formatLargeNumber = (value: number): string => {
+ if (Math.abs(value) >= 1e6) {
+ return (value / 1e6).toFixed(1).replace(/\.0$/, '') + 'M';
+ }
+ if (Math.abs(value) >= 1e3) {
+ return (value / 1e3).toFixed(1).replace(/\.0$/, '') + 'K';
+ }
+ return value.toFixed(2);
+};
+
+const formatDateTick = (date: Date): string =>
+ date
+ .toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: false })
+ .split(',')
+ .join('\n');
+
+const emptyState = (
+
+ No data available
+
+ There is no data available
+
+
+);
+
+const noMatchState = (
+
+ No matching data
+
+ There is no matching data to display
+
+
+
+);
+
+const barChartDates = [
+ new Date(1601071200000),
+ new Date(1601078400000),
+ new Date(1601085600000),
+ new Date(1601092800000),
+ new Date(1601100000000),
+];
+
+const lineChartDomain: [Date, Date] = [new Date(1600984800000), new Date(1601013600000)];
+
+const lineChartSite1 = [
+ { x: new Date(1600984800000), y: 58020 },
+ { x: new Date(1600988400000), y: 125021 },
+ { x: new Date(1600992000000), y: 274021 },
+ { x: new Date(1600995600000), y: 257306 },
+ { x: new Date(1600999200000), y: 486039 },
+ { x: new Date(1601002800000), y: 298028 },
+ { x: new Date(1601006400000), y: 102839 },
+ { x: new Date(1601010000000), y: 183570 },
+ { x: new Date(1601013600000), y: 293910 },
+];
+
+const lineChartSite2 = [
+ { x: new Date(1600984800000), y: 151023 },
+ { x: new Date(1600988400000), y: 149130 },
+ { x: new Date(1600992000000), y: 154091 },
+ { x: new Date(1600995600000), y: 181635 },
+ { x: new Date(1600999200000), y: 220516 },
+ { x: new Date(1601002800000), y: 172331 },
+ { x: new Date(1601006400000), y: 194091 },
+ { x: new Date(1601010000000), y: 179130 },
+ { x: new Date(1601013600000), y: 157299 },
+];
+
+export default function Charts() {
+ return (
+
+
+
+ ({ x, y: [12, 18, 15, 9, 18][i] })) },
+ { title: 'Moderate', type: 'bar', data: barChartDates.map((x, i) => ({ x, y: [8, 11, 12, 11, 13][i] })) },
+ { title: 'Low', type: 'bar', data: barChartDates.map((x, i) => ({ x, y: [7, 9, 8, 7, 5][i] })) },
+ {
+ title: 'Unclassified',
+ type: 'bar',
+ data: barChartDates.map((x, i) => ({ x, y: [14, 8, 6, 4, 6][i] })),
+ },
+ ]}
+ xDomain={barChartDates}
+ yDomain={[0, 50]}
+ i18nStrings={{ xTickFormatter: formatDateTick }}
+ ariaLabel="Stacked bar chart"
+ height={300}
+ stackedBars={true}
+ xTitle="Time (UTC)"
+ yTitle="Error count"
+ empty={emptyState}
+ noMatch={noMatchState}
+ />
+
+
+
+
+
+
+
+ [
+ { key: 'Resource count', value: datum.value },
+ { key: 'Percentage', value: `${((datum.value / sum) * 100).toFixed(0)}%` },
+ { key: 'Last update on', value: datum.lastUpdate },
+ ]}
+ segmentDescription={(datum, sum) => `${datum.value} units, ${((datum.value / sum) * 100).toFixed(0)}%`}
+ ariaDescription="Pie chart showing resource states."
+ ariaLabel="Pie chart"
+ empty={emptyState}
+ noMatch={noMatchState}
+ />
+
+
+
+ );
+}
diff --git a/pages/components-overview/chat.tsx b/pages/components-overview/chat.tsx
new file mode 100644
index 0000000000..08e89dd6cf
--- /dev/null
+++ b/pages/components-overview/chat.tsx
@@ -0,0 +1,119 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React, { useState } from 'react';
+
+import Avatar from '@cloudscape-design/chat-components/avatar';
+import ChatBubble from '@cloudscape-design/chat-components/chat-bubble';
+import SupportPromptGroup from '@cloudscape-design/chat-components/support-prompt-group';
+
+import Box from '~components/box';
+import ButtonGroup from '~components/button-group';
+import FileTokenGroup from '~components/file-token-group';
+import Grid from '~components/grid';
+import PromptInput from '~components/prompt-input';
+import SpaceBetween from '~components/space-between';
+
+import { Section } from './utils';
+
+export default function Chat() {
+ const [value, setValue] = useState('');
+ const [files, setFiles] = React.useState([
+ new File([new Blob(['Test content'])], 'file-1.pdf', { type: 'application/pdf', lastModified: 1590962400000 }),
+ new File([new Blob(['Test content'])], 'file-2.pdf', { type: 'application/pdf', lastModified: 1590962400000 }),
+ ]);
+ return (
+
+
+
+ }
+ ariaLabel="Jane Doe message"
+ type="outgoing"
+ >
+ This is an outgoing message from a user.
+
+ }
+ ariaLabel="AI Assistant message"
+ type="incoming"
+ >
+ This is an incoming message from the AI assistant.
+
+
+ }
+ >
+ Generating response
+
+
+
+
+ {}}
+ />
+
+
+ setValue(detail.value)}
+ value={value}
+ actionButtonAriaLabel="Send message"
+ actionButtonIconName="send"
+ disableSecondaryActionsPaddings={true}
+ placeholder="Ask a question"
+ ariaLabel="Prompt input with files"
+ secondaryActions={
+
+
+
+ }
+ secondaryContent={
+ ({ file }))}
+ onDismiss={({ detail }) => setFiles(f => f.filter((_, i) => i !== detail.fileIndex))}
+ alignment="horizontal"
+ showFileSize={true}
+ showFileLastModified={true}
+ showFileThumbnail={true}
+ i18nStrings={{
+ removeFileAriaLabel: () => 'Remove file',
+ limitShowFewer: 'Show fewer files',
+ limitShowMore: 'Show more files',
+ errorIconAriaLabel: 'Error',
+ warningIconAriaLabel: 'Warning',
+ }}
+ />
+ }
+ />
+
+
+ );
+}
diff --git a/pages/components-overview/code-view-section.tsx b/pages/components-overview/code-view-section.tsx
new file mode 100644
index 0000000000..7809b3f8c7
--- /dev/null
+++ b/pages/components-overview/code-view-section.tsx
@@ -0,0 +1,26 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React from 'react';
+
+import CodeView from '@cloudscape-design/code-view/code-view';
+
+import { Section } from './utils';
+
+const codeSnippet = `import { applyTheme } from '@cloudscape-design/components/theming';
+
+applyTheme({
+ theme: {
+ tokens: {
+ colorBackgroundLayoutMain: '#f5f5f5',
+ borderRadiusContainer: '8px',
+ },
+ },
+});`;
+
+export default function CodeViewSection() {
+ return (
+
+ );
+}
diff --git a/pages/components-overview/component-data.tsx b/pages/components-overview/component-data.tsx
new file mode 100644
index 0000000000..4d1948a093
--- /dev/null
+++ b/pages/components-overview/component-data.tsx
@@ -0,0 +1,143 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React from 'react';
+
+import { FlashbarProps } from '~components/flashbar';
+import { MultiselectProps } from '~components/multiselect';
+import ProgressBar from '~components/progress-bar';
+import { SelectProps } from '~components/select';
+
+let seed = 1;
+export default function pseudoRandom() {
+ const x = Math.sin(seed++) * 10000;
+ return x - Math.floor(x);
+}
+
+export interface RandomData {
+ description: string;
+ name: string;
+ amount: string;
+ increase: boolean;
+}
+
+const collectionData: RandomData[] = [
+ {
+ description: 'volutpat. Nulla dignissim. Maecenas ornare egestas ligula.',
+ name: 'Velit Egestas LLP',
+ amount: '$68.54',
+ increase: true,
+ },
+ {
+ description: 'vestibulum lorem, sit amet ultricies sem magna nec quam.',
+ name: 'Mattis Velit Justo Company',
+ amount: '$80.38',
+ increase: true,
+ },
+ {
+ description: 'aliquet odio. Etiam ligula tortor, dictum eu, placerat eget.',
+ name: 'Tempor LLP',
+ amount: '$1.66',
+ increase: false,
+ },
+ {
+ description: 'ridiculus mus. Donec dignissim magna a tortor. Nunc commodo.',
+ name: 'Egestas Hendrerit Neque Corporation',
+ amount: '$31.74',
+ increase: true,
+ },
+ {
+ description: 'Vivamus molestie dapibus ligula. Aliquam erat volutpat.',
+ name: 'Aenean Incorporated',
+ amount: '$53.61',
+ increase: true,
+ },
+ {
+ description: 'Cras sed leo. Cras vehicula aliquet libero. Integer in magna.',
+ name: 'Proin Ltd',
+ amount: '$42.19',
+ increase: false,
+ },
+ {
+ description: 'Phasellus at augue id ante dictum cursus. Nunc mauris elit.',
+ name: 'Nulla Facilisi Foundation',
+ amount: '$97.03',
+ increase: true,
+ },
+ {
+ description: 'Sed nec metus facilisis lorem tristique aliquet.',
+ name: 'Donec Vitae Corp',
+ amount: '$15.88',
+ increase: false,
+ },
+];
+
+export const cardItems = collectionData.slice(0, 2);
+export const tableItems = collectionData;
+
+export const flashbarItems: FlashbarProps.MessageDefinition[] = [
+ {
+ header: 'Success',
+ type: 'success',
+ content: 'This is a success message.',
+ dismissible: true,
+ dismissLabel: 'Dismiss success message',
+ id: 'success',
+ },
+ {
+ header: 'Warning',
+ type: 'warning',
+ content: 'This is a warning message.',
+ dismissible: true,
+ dismissLabel: 'Dismiss warning message',
+ id: 'warning',
+ },
+ {
+ header: 'Error',
+ type: 'error',
+ content: 'This is an error message.',
+ dismissible: true,
+ dismissLabel: 'Dismiss error message',
+ id: 'error',
+ },
+ {
+ header: 'Info',
+ type: 'info',
+ content: 'This is an info message.',
+ dismissible: true,
+ dismissLabel: 'Dismiss info message',
+ id: 'info',
+ },
+ {
+ header: 'In-progress',
+ type: 'in-progress',
+ content: (
+ <>
+ This is an in-progress flash.
+
+ >
+ ),
+ dismissible: true,
+ dismissLabel: 'Dismiss in-progress message',
+ id: 'in-progress',
+ },
+ {
+ header: 'Loading',
+ type: 'in-progress',
+ loading: true,
+ content: 'This is a loading flash.',
+ dismissible: true,
+ dismissLabel: 'Dismiss loading message',
+ id: 'loading',
+ },
+];
+
+export const generateDropdownOptions = (count = 25): SelectProps.Options | MultiselectProps.Options => {
+ return [...Array(count).keys()].map(n => {
+ const numberToDisplay = (n + 1).toString();
+ const baseOption = { id: numberToDisplay, value: numberToDisplay, label: `Option ${numberToDisplay}` };
+ if (n === 0 || n === 24 || n === 49) {
+ return { ...baseOption, disabled: true, disabledReason: 'disabled reason' };
+ }
+ return baseOption;
+ });
+};
diff --git a/pages/components-overview/components-overview.page.tsx b/pages/components-overview/components-overview.page.tsx
new file mode 100644
index 0000000000..833f3658f4
--- /dev/null
+++ b/pages/components-overview/components-overview.page.tsx
@@ -0,0 +1,67 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React from 'react';
+
+import Box from '~components/box';
+import SpaceBetween from '~components/space-between';
+
+import BoardSection from './board-section';
+import ButtonsInputsDropdowns from './buttons-inputs-dropdowns';
+import Charts from './charts';
+import Chat from './chat';
+import CodeViewSection from './code-view-section';
+import FormControls from './form-controls';
+import KvpForm from './kvp-form';
+import NavigationComponents from './navigation-components';
+import OverlaysAndPatterns from './overlays-and-patterns';
+import StatusComponents from './status-components';
+import TableAndCards from './table-and-cards';
+import Typography from './typography';
+
+export default function ComponentsOverviewPage() {
+ return (
+
+
+
+ Components overview page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/pages/components-overview/form-controls.tsx b/pages/components-overview/form-controls.tsx
new file mode 100644
index 0000000000..6790958d04
--- /dev/null
+++ b/pages/components-overview/form-controls.tsx
@@ -0,0 +1,144 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React from 'react';
+
+import Checkbox from '~components/checkbox';
+import ColumnLayout from '~components/column-layout';
+import Grid from '~components/grid';
+import RadioGroup from '~components/radio-group';
+import Slider from '~components/slider';
+import SpaceBetween from '~components/space-between';
+import Tiles from '~components/tiles';
+import Toggle from '~components/toggle';
+
+import { Section } from './utils';
+
+export default function FormControls() {
+ return (
+
+
+
+
+
+ Checked
+
+
+ Unchecked
+
+
+ Disabled
+
+
+ Disabled
+
+
+ Read-only
+
+
+ Read-only
+
+
+
+
+
+
+
+
+
+
+
+ Checked
+
+
+ Unchecked
+
+
+ Disabled
+
+
+ Disabled
+
+
+ Read-only
+
+
+ Read-only
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/pages/components-overview/kvp-form.tsx b/pages/components-overview/kvp-form.tsx
new file mode 100644
index 0000000000..120b658c96
--- /dev/null
+++ b/pages/components-overview/kvp-form.tsx
@@ -0,0 +1,132 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React from 'react';
+
+import Box from '~components/box';
+import Button from '~components/button';
+import ColumnLayout from '~components/column-layout';
+import CopyToClipboard from '~components/copy-to-clipboard';
+import Form from '~components/form';
+import FormField from '~components/form-field';
+import Grid from '~components/grid';
+import Header from '~components/header';
+import Icon from '~components/icon';
+import Input from '~components/input';
+import KeyValuePairs from '~components/key-value-pairs';
+import Link from '~components/link';
+import SpaceBetween from '~components/space-between';
+import StatusIndicator from '~components/status-indicator';
+import Textarea from '~components/textarea';
+import Tiles from '~components/tiles';
+
+import { Section } from './utils';
+
+export default function KvpForm() {
+ const [value, setValue] = React.useState('standard');
+ return (
+
+
+
+
+
+
+ Info
+
+ ),
+ },
+ { label: 'Status', value: Available },
+ { label: 'Price class', value: 'Use only US, Canada, Europe, and Asia' },
+ { label: 'CNAMEs', value: example.com },
+ {
+ label: 'ARN',
+ value: (
+
+ ),
+ },
+ ]}
+ />
+
+
+
+
+
+
+ }
+ header={}
+ >
+
+
+
+
+ setValue(e.detail.value)}
+ columns={4}
+ items={[
+ {
+ value: 'standard',
+ label: 'Standard',
+ description: 'Recommended for most workloads',
+ image: ,
+ },
+ {
+ value: 'optimized',
+ label: 'Optimized',
+ description: 'Best for dynamic content',
+ image: ,
+ },
+ {
+ value: 'custom',
+ label: 'Custom',
+ description: 'Configure your own policy',
+ image: ,
+ },
+ {
+ value: 'disabled',
+ label: 'Disabled',
+ description: 'No caching applied',
+ image: ,
+ },
+ ]}
+ ariaLabel="Cache policy"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/pages/components-overview/navigation-components.tsx b/pages/components-overview/navigation-components.tsx
new file mode 100644
index 0000000000..4a6a693700
--- /dev/null
+++ b/pages/components-overview/navigation-components.tsx
@@ -0,0 +1,93 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React, { useState } from 'react';
+
+import AnchorNavigation from '~components/anchor-navigation';
+import BreadcrumbGroup from '~components/breadcrumb-group';
+import Grid from '~components/grid';
+import Link from '~components/link';
+import SideNavigation from '~components/side-navigation';
+import SpaceBetween from '~components/space-between';
+import Tabs from '~components/tabs';
+
+import { Section } from './utils';
+
+export default function NavigationComponents() {
+ const [activeTabId, setActiveTabId] = useState('tab1');
+ const [activeHref, setActiveHref] = useState('#/parent-page/child-page1');
+
+ return (
+
+
+
+
+ {
+ if (!event.detail.external) {
+ event.preventDefault();
+ setActiveHref(event.detail.href);
+ }
+ }}
+ items={[
+ { type: 'link', text: 'Page 1', href: '#/page1' },
+ {
+ type: 'expandable-link-group',
+ text: 'Parent page',
+ href: '#/parent-page',
+ items: [
+ { type: 'link', text: 'Child page 1', href: '#/parent-page/child-page1' },
+ { type: 'link', text: 'Child page 2', href: '#/parent-page/child-page2' },
+ ],
+ },
+ { type: 'link', text: 'Page 2', href: '#/page2' },
+ { type: 'link', text: 'Page 3', href: '#/page3' },
+ ]}
+ />
+
+ setActiveTabId(detail.activeTabId)}
+ tabs={[
+ { id: 'tab1', label: 'Tab 1', content: 'Tab 1 Content' },
+ { id: 'tab2', label: 'Tab 2', content: 'Tab 2 Content' },
+ { id: 'tab3', label: 'Tab 3', content: 'Tab 3 Content', disabled: true },
+ ]}
+ />
+
+
+
+
+ Primary anchor link
+
+
+ Secondary anchor link
+
+ {}}>Button link
+
+
+
+ );
+}
diff --git a/pages/components-overview/overlays-and-patterns.tsx b/pages/components-overview/overlays-and-patterns.tsx
new file mode 100644
index 0000000000..c945f16cdc
--- /dev/null
+++ b/pages/components-overview/overlays-and-patterns.tsx
@@ -0,0 +1,83 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React, { useState } from 'react';
+
+import Box from '~components/box';
+import ColumnLayout from '~components/column-layout';
+import TokenGroup from '~components/token-group';
+import Wizard from '~components/wizard';
+
+import { Section, SubSection } from './utils';
+
+export default function OverlaysAndPatterns() {
+ const [tokens, setTokens] = useState([
+ { label: 'us-east-1', dismissLabel: 'Remove us-east-1' },
+ { label: 'eu-west-1', dismissLabel: 'Remove eu-west-1' },
+ { label: 'ap-southeast-1', dismissLabel: 'Remove ap-southeast-1' },
+ ]);
+ const [activeWizardStep, setActiveWizardStep] = useState(0);
+
+ return (
+
+ <>
+
+
+ setTokens(tokens.filter((_, i) => i !== detail.itemIndex))}
+ />
+
+
+
+
+
+
+ `Step ${stepNumber}`,
+ collapsedStepsLabel: (stepNumber, stepsCount) => `Step ${stepNumber} of ${stepsCount}`,
+ cancelButton: 'Cancel',
+ previousButton: 'Previous',
+ nextButton: 'Next',
+ submitButton: 'Create distribution',
+ optional: 'optional',
+ }}
+ activeStepIndex={activeWizardStep}
+ onNavigate={({ detail }) => setActiveWizardStep(detail.requestedStepIndex)}
+ steps={[
+ {
+ title: 'Choose origin',
+ description: 'Select the origin for your distribution.',
+ content: (
+
+ Configure the origin settings for your CloudFront distribution.
+
+ ),
+ },
+ {
+ title: 'Configure behaviors',
+ description: 'Set up cache behaviors and path patterns.',
+ content: (
+
+ Define how CloudFront handles requests for different URL paths.
+
+ ),
+ },
+ {
+ title: 'Review and create',
+ description: 'Review your configuration before creating.',
+ content: (
+ Review all settings and confirm the distribution creation.
+ ),
+ },
+ ]}
+ />
+
+
+ >
+
+ );
+}
diff --git a/pages/components-overview/status-components.tsx b/pages/components-overview/status-components.tsx
new file mode 100644
index 0000000000..312dd28f70
--- /dev/null
+++ b/pages/components-overview/status-components.tsx
@@ -0,0 +1,249 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React from 'react';
+
+import Alert from '~components/alert';
+import Badge from '~components/badge';
+import Button from '~components/button';
+import ButtonGroup from '~components/button-group';
+import ColumnLayout from '~components/column-layout';
+import FileTokenGroup from '~components/file-token-group';
+import Flashbar, { FlashbarProps } from '~components/flashbar';
+import FormField from '~components/form-field';
+import Grid from '~components/grid';
+import Input from '~components/input';
+import ProgressBar from '~components/progress-bar';
+import Slider from '~components/slider';
+import SpaceBetween from '~components/space-between';
+import Spinner from '~components/spinner';
+import StatusIndicator from '~components/status-indicator';
+import Steps from '~components/steps';
+
+import { flashbarItems } from './component-data';
+import { Section, SubSection } from './utils';
+
+export default function StatusComponents() {
+ return (
+
+ <>
+
+
+ item.type === 'error') as FlashbarProps.MessageDefinition]} />
+
+ This is an error alert.
+
+
+
+
+
+
+
+
+
+ Error Status
+ Badge
+
+
+
+
+
+
+
+ item.type === 'warning') as FlashbarProps.MessageDefinition]}
+ />
+
+ This is a warning alert.
+
+
+
+
+
+
+
+
+ Warning Status
+
+
+
+
+
+
+ item.type === 'success') as FlashbarProps.MessageDefinition]}
+ />
+
+ This is a success alert.
+
+
+
+
+ Success Status
+ Badge
+
+
+
+
+
+
+
+ item.type === 'info') as FlashbarProps.MessageDefinition]} />
+
+ This is an info alert.
+
+
+
+
+ Info Status
+ Badge
+
+
+
+
+
+
+
+
+ This is an in-progress flash.
+
+ >
+ ),
+ dismissible: true,
+ dismissLabel: 'Dismiss in-progress message',
+ id: 'in-progress',
+ },
+ {
+ header: 'Loading',
+ type: 'in-progress',
+ loading: true,
+ content: 'This is a loading flash.',
+ dismissible: true,
+ dismissLabel: 'Dismiss loading message',
+ id: 'loading',
+ },
+ ]}
+ />
+
+ {}}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ In-progress Status
+ Loading
+ Stopped Status
+ Pending Status
+ Badge
+
+
+
+
+ >
+
+ );
+}
diff --git a/pages/components-overview/table-and-cards.tsx b/pages/components-overview/table-and-cards.tsx
new file mode 100644
index 0000000000..6e8872529d
--- /dev/null
+++ b/pages/components-overview/table-and-cards.tsx
@@ -0,0 +1,184 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React, { useState } from 'react';
+
+import Badge from '~components/badge';
+import Cards from '~components/cards';
+import CollectionPreferences from '~components/collection-preferences';
+import Header from '~components/header';
+import KeyValuePairs from '~components/key-value-pairs';
+import Link from '~components/link';
+import Pagination from '~components/pagination';
+import SpaceBetween from '~components/space-between';
+import Table from '~components/table';
+import TextFilter from '~components/text-filter';
+
+import { cardItems, RandomData, tableItems } from './component-data';
+import { Section } from './utils';
+
+export default function TableAndCards() {
+ const [selectedItems, setSelectedItems] = useState({
+ table: [tableItems[2]],
+ cards: [cardItems[1]],
+ });
+ const [filteringText, setFilteringText] = useState('');
+ const [currentPage, setCurrentPage] = useState(1);
+ const [preferences, setPreferences] = useState({
+ pageSize: 5,
+ visibleContent: ['name', 'category', 'description'],
+ });
+
+ return (
+
+
+ (
+
+ {item.name}
+
+ ),
+ sections: [
+ {
+ id: 'key-value-pairs',
+ content: item => (
+
+ ),
+ },
+ ],
+ }}
+ selectionType="multi"
+ selectedItems={selectedItems.cards}
+ onSelectionChange={({ detail }) => setSelectedItems(prev => ({ ...prev, cards: detail.selectedItems }))}
+ ariaLabels={{
+ itemSelectionLabel: (e, item) => `Select ${item.name}`,
+ selectionGroupLabel: 'Item selection',
+ }}
+ />
+
+
+
+ Info
+
+ }
+ >
+ Table with common features
+
+ }
+ filter={
+ setFilteringText(detail.filteringText)}
+ />
+ }
+ pagination={
+ setCurrentPage(detail.currentPageIndex)}
+ ariaLabels={{
+ nextPageLabel: 'Next page',
+ previousPageLabel: 'Previous page',
+ pageLabel: pageNumber => `Page ${pageNumber}`,
+ }}
+ />
+ }
+ preferences={
+
+ setPreferences({
+ pageSize: detail.pageSize ?? 5,
+ visibleContent: (detail.visibleContent as string[]) ?? [],
+ })
+ }
+ pageSizePreference={{
+ title: 'Page size',
+ options: [
+ { value: 5, label: '5 resources' },
+ { value: 10, label: '10 resources' },
+ ],
+ }}
+ visibleContentPreference={{
+ title: 'Select visible content',
+ options: [
+ {
+ label: 'Main properties',
+ options: [
+ { id: 'name', label: 'Name' },
+ { id: 'category', label: 'Category' },
+ { id: 'description', label: 'Description' },
+ ],
+ },
+ ],
+ }}
+ />
+ }
+ resizableColumns={true}
+ columnDefinitions={[
+ {
+ id: 'name',
+ header: 'Name',
+ cell: (item: RandomData) => (
+
+ {item.name}
+
+ ),
+ sortingField: 'name',
+ width: 200,
+ minWidth: 150,
+ },
+ {
+ id: 'category',
+ header: 'Category',
+ cell: (item: RandomData) => {
+ const categories = ['green', 'grey', 'blue'] as const;
+ const labels = ['Serverless', 'Security', 'Agentic AI'];
+ const index = item.name.length % 3;
+ return {labels[index]};
+ },
+ sortingField: 'category',
+ width: 150,
+ minWidth: 100,
+ },
+ {
+ id: 'description',
+ header: 'Description',
+ cell: (item: RandomData) => item.description,
+ width: 300,
+ minWidth: 200,
+ },
+ ]}
+ selectionType="single"
+ selectedItems={selectedItems.table}
+ onSelectionChange={({ detail }) => setSelectedItems(prev => ({ ...prev, table: detail.selectedItems }))}
+ ariaLabels={{
+ itemSelectionLabel: (e, item) => `Select ${item.name}`,
+ allItemsSelectionLabel: () => 'Select all items',
+ selectionGroupLabel: 'Item selection',
+ }}
+ />
+
+
+ );
+}
diff --git a/pages/components-overview/typography.tsx b/pages/components-overview/typography.tsx
new file mode 100644
index 0000000000..5536e51369
--- /dev/null
+++ b/pages/components-overview/typography.tsx
@@ -0,0 +1,114 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React, { useState } from 'react';
+
+import Box from '~components/box';
+import ColumnLayout from '~components/column-layout';
+import Container from '~components/container';
+import Header from '~components/header';
+import Icon from '~components/icon';
+import Link from '~components/link';
+import SpaceBetween from '~components/space-between';
+import TextContent from '~components/text-content';
+import Toggle from '~components/toggle';
+
+export default function Typography() {
+ const [longText, setLongText] = useState(false);
+ return (
+ <>
+
+ setLongText(detail.checked)} checked={longText}>
+ Long text
+
+ }
+ >
+ Typography & Iconography
+
+
+
+
+
+ {longText ? (
+ <>
+ Heading 1: The instance type you specify determines the hardware of the host computer.
+ Heading 2: The instance type you specify determines the hardware of the host computer.
+ Heading 3: The instance type you specify determines the hardware of the host computer.
+ Heading 4: The instance type you specify determines the hardware of the host computer.
+ Heading 5: The instance type you specify determines the hardware of the host computer.
+ >
+ ) : (
+ <>
+ Heading 1
+ Heading 2
+ Heading 3
+ Heading 4
+ Heading 5
+ >
+ )}
+
+
+
+ {longText ? (
+ <>
+ Paragraph - The instance type you specify determines the hardware of the host computer used for your
+ instance. Each instance type offers different compute, memory, and storage capabilities.{' '}
+
+ Amazon EC2
+ {' '}
+ provides each instance with a consistent and predictable amount of CPU capacity, regardless of its{' '}
+
+ underlying hardware
+
+ .
+ >
+ ) : (
+ <>
+ Paragraph -{' '}
+
+ Amazon EC2
+ {' '}
+ provides each instance with a consistent and predictable amount of CPU capacity, regardless of its{' '}
+
+ underlying hardware
+
+ .
+ >
+ )}
+
+
+ {longText ? (
+ <>Small - Daily instance hours by instance type, aggregated across all regions and availability zones.>
+ ) : (
+ <>Small - Requirements and constraints for the field.>
+ )}
+
+
+ Icon - Normal size
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/pages/components-overview/utils.tsx b/pages/components-overview/utils.tsx
new file mode 100644
index 0000000000..bf7c5bcd28
--- /dev/null
+++ b/pages/components-overview/utils.tsx
@@ -0,0 +1,39 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React, { ReactElement } from 'react';
+
+import Box from '~components/box';
+import Container from '~components/container';
+import Header from '~components/header';
+import SpaceBetween from '~components/space-between';
+
+interface SectionProps {
+ header?: string;
+ description?: string;
+ level?: 'h2' | 'h3';
+ container?: boolean;
+ children: ReactElement;
+}
+
+export const Section = ({ header, description, level = 'h2', container = true, children }: SectionProps) => {
+ const content = {children};
+ return (
+
+ {header && (
+
+ )}
+ {container ? {content} : content}
+
+ );
+};
+
+export const SubSection = ({ header, level = 'h3', children }: SectionProps) => {
+ return (
+
+ {header && {header}}
+ {children}
+
+ );
+};
diff --git a/pages/webpack.config.base.cjs b/pages/webpack.config.base.cjs
index f359318eb4..a6811a7bbe 100644
--- a/pages/webpack.config.base.cjs
+++ b/pages/webpack.config.base.cjs
@@ -153,6 +153,7 @@ module.exports = ({
}),
replaceModule(/~components/, componentsPath),
replaceModule(/~design-tokens/, designTokensPath),
+ replaceModule(/@cloudscape-design\/components(?!\w)/, componentsPath),
globalStylesPath
? replaceModule(/@cloudscape-design\/global-styles\/index\.css/, `${globalStylesPath}/${globalStylesIndex}.css`)
: noop,