Skip to content

Commit ea228b0

Browse files
committed
feat: Add list component
1 parent f92611f commit ea228b0

File tree

24 files changed

+519
-130
lines changed

24 files changed

+519
-130
lines changed

build-tools/utils/pluralize.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const pluralizationMap = {
4545
KeyValuePairs: 'KeyValuePairs',
4646
LineChart: 'LineCharts',
4747
Link: 'Links',
48+
List: 'Lists',
4849
LiveRegion: 'LiveRegions',
4950
MixedLineBarChart: 'MixedLineBarCharts',
5051
Modal: 'Modals',
@@ -67,6 +68,7 @@ const pluralizationMap = {
6768
SplitPanel: 'SplitPanels',
6869
StatusIndicator: 'StatusIndicators',
6970
Steps: 'Steps',
71+
StructuredItem: 'StructuredItems',
7072
Table: 'Tables',
7173
Tabs: 'Tabs',
7274
TagEditor: 'TagEditors',

pages/app-layout/landing-page.page.tsx

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,48 +28,50 @@ export default function () {
2828
notifications={<Notifications />}
2929
ariaLabels={labels}
3030
content={
31-
<Box margin={{ bottom: 'l' }}>
32-
<div className={styles.header}>
33-
<Box padding={{ vertical: 'xxxl', horizontal: 's' }}>
31+
<div style={{ overflow: 'auto' }}>
32+
<Box margin={{ bottom: 'l' }}>
33+
<div className={styles.header}>
34+
<Box padding={{ vertical: 'xxxl', horizontal: 's' }}>
35+
<Grid
36+
gridDefinition={[
37+
{ colspan: { xl: 6, l: 5, s: 6, xxs: 10 }, offset: { l: 2, xxs: 1 } },
38+
{ colspan: { xl: 2, l: 3, s: 4, xxs: 10 }, offset: { s: 0, xxs: 1 } },
39+
]}
40+
>
41+
<div className={styles['header-title']}>
42+
<Box variant="h1" fontWeight="heavy" fontSize="display-l" color="inherit">
43+
Service name
44+
</Box>
45+
<Box fontWeight="light" padding={{ bottom: 's' }} fontSize="display-l" color="inherit">
46+
Name sub-title
47+
</Box>
48+
<Box variant="p" fontWeight="light">
49+
<span className={styles['header-sub-title']}>Some information about this service</span>
50+
</Box>
51+
</div>
52+
</Grid>
53+
</Box>
54+
</div>
55+
<Box padding={{ top: 'xxxl', horizontal: 's' }}>
3456
<Grid
3557
gridDefinition={[
3658
{ colspan: { xl: 6, l: 5, s: 6, xxs: 10 }, offset: { l: 2, xxs: 1 } },
3759
{ colspan: { xl: 2, l: 3, s: 4, xxs: 10 }, offset: { s: 0, xxs: 1 } },
3860
]}
3961
>
40-
<div className={styles['header-title']}>
41-
<Box variant="h1" fontWeight="heavy" fontSize="display-l" color="inherit">
42-
Service name
43-
</Box>
44-
<Box fontWeight="light" padding={{ bottom: 's' }} fontSize="display-l" color="inherit">
45-
Name sub-title
46-
</Box>
47-
<Box variant="p" fontWeight="light">
48-
<span className={styles['header-sub-title']}>Some information about this service</span>
62+
<div>
63+
<Box variant="h1" tagOverride="h2" padding={{ bottom: 's', top: 'n' }}>
64+
Features
4965
</Box>
66+
<Containers />
5067
</div>
68+
<Container header={<Header>Getting started</Header>}>
69+
Some information to learn about this service
70+
</Container>
5171
</Grid>
5272
</Box>
53-
</div>
54-
<Box padding={{ top: 'xxxl', horizontal: 's' }}>
55-
<Grid
56-
gridDefinition={[
57-
{ colspan: { xl: 6, l: 5, s: 6, xxs: 10 }, offset: { l: 2, xxs: 1 } },
58-
{ colspan: { xl: 2, l: 3, s: 4, xxs: 10 }, offset: { s: 0, xxs: 1 } },
59-
]}
60-
>
61-
<div>
62-
<Box variant="h1" tagOverride="h2" padding={{ bottom: 's', top: 'n' }}>
63-
Features
64-
</Box>
65-
<Containers />
66-
</div>
67-
<Container header={<Header>Getting started</Header>}>
68-
Some information to learn about this service
69-
</Container>
70-
</Grid>
7173
</Box>
72-
</Box>
74+
</div>
7375
}
7476
/>
7577
</ScreenshotArea>

pages/dnd/reorderable-containers.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ export function ReorderableContainers({
4242
borderRadius: 'container',
4343
}}
4444
onItemsChange={({ detail }) => onReorder(detail.items)}
45-
renderItem={({ item, ref, className, style, dragHandleProps }) => (
46-
<div ref={ref} className={clsx(className, styles.container)} style={style}>
45+
renderItem={({ item, ref, style, dragHandleProps }) => (
46+
<div ref={ref} className={clsx(styles.container)} style={style}>
4747
<Container
4848
header={
4949
<SpaceBetween size="xs" direction="horizontal" alignItems="center">

pages/dnd/reorderable-list.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ export function ReorderableList({
3636
items={sortableOptions}
3737
itemDefinition={{ id: option => option.id, label: option => option.id }}
3838
onItemsChange={({ detail }) => onReorder([...staticOptions, ...detail.items])}
39-
renderItem={({ item, ref, className, style, dragHandleProps, ...props }) => {
40-
className = clsx(className, styles.option, props.isSortingActive && styles.sorting);
39+
renderItem={({ item, ref, style, dragHandleProps, ...props }) => {
40+
const className = clsx(styles.option, props.isSortingActive && styles.sorting);
4141
return (
4242
<li ref={ref} className={className} style={style}>
4343
<InstanceOption dragHandleProps={dragHandleProps} option={item} />

pages/dnd/reorderable-table.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ export function ReorderableTable<Item extends { id: string }>({
7070
items={items}
7171
itemDefinition={{ id: item => item.id, label: item => item.id }}
7272
onItemsChange={({ detail }) => onReorder(detail.items)}
73-
renderItem={({ item, ref, className, style, isDragGhost, dragHandleProps }) => {
73+
renderItem={({ item, ref, style, isDragGhost, dragHandleProps }) => {
7474
const row = (
7575
<tr
7676
ref={ref}
77-
className={clsx(className, styles.row, isDragGhost && styles['active-row'])}
77+
className={clsx(styles.row, isDragGhost && styles['active-row'])}
7878
style={isDragGhost ? {} : style}
7979
>
8080
{getColumnDefinitions({ dragHandleProps }).map((column, index) => (

pages/list/permutations.page.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import React from 'react';
4+
5+
import List, { ListProps } from '~components/list';
6+
import ListItem from '~components/structured-item';
7+
8+
import createPermutations from '../utils/permutations';
9+
import PermutationsView from '../utils/permutations-view';
10+
import ScreenshotArea from '../utils/screenshot-area';
11+
12+
/* eslint-disable react/jsx-key */
13+
const permutations = createPermutations<ListProps>([
14+
{
15+
items: [[{ label: 'Item 1' }, { label: 'Item 2' }, { label: 'Item 3' }, { label: 'Item 4' }]],
16+
},
17+
{
18+
children: [
19+
[
20+
<li>Custom li child</li>,
21+
<div>Custom non-li child</div>,
22+
<li>Custom li child</li>,
23+
<div>Custom non-li child</div>,
24+
<ListItem label="List item child" />,
25+
],
26+
],
27+
},
28+
]);
29+
/* eslint-enable react/jsx-key */
30+
31+
export default function ListItemPermutations() {
32+
return (
33+
<>
34+
<h1>List item permutations</h1>
35+
<ScreenshotArea>
36+
<PermutationsView permutations={permutations} render={permutation => <List {...permutation} />} />
37+
</ScreenshotArea>
38+
</>
39+
);
40+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import React, { useContext } from 'react';
4+
5+
import { Button, Checkbox, Icon, Link } from '~components';
6+
import StructuredItem, { StructuredItemProps } from '~components/structured-item';
7+
8+
import AppContext, { AppContextType } from '../app/app-context';
9+
import createPermutations from '../utils/permutations';
10+
import PermutationsView from '../utils/permutations-view';
11+
import ScreenshotArea from '../utils/screenshot-area';
12+
13+
const longBreakable =
14+
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.';
15+
const longUnbreakable =
16+
'Duis aute irure dolor in reprehenderitinvoluptatevelitessereprehenderitinvoluptatevelitessereprehenderitinvoluptatevelitessereprehenderitinvoluptatevelitesse';
17+
18+
/* eslint-disable react/jsx-key */
19+
const permutations = createPermutations<StructuredItemProps & { viewportWidth: number }>([
20+
{
21+
label: [
22+
'Label',
23+
'Label that is a bit longer',
24+
<div>
25+
Label with info link | <Link variant="info">Info</Link>
26+
</div>,
27+
],
28+
description: [null, 'Description', 'Description that is a bit longer', longBreakable, longUnbreakable],
29+
actions: [<Button variant="icon" iconName="settings" />, <Button>Longer button</Button>],
30+
icon: [<Icon name="star" />],
31+
// disableTypography: [true, false],
32+
viewportWidth: [100, 200, 300, 600],
33+
},
34+
]);
35+
/* eslint-enable react/jsx-key */
36+
37+
type PageContext = React.Context<
38+
AppContextType<{
39+
percentageWrapping: boolean;
40+
}>
41+
>;
42+
43+
export default function ListItemPermutations() {
44+
const { urlParams, setUrlParams } = useContext(AppContext as PageContext);
45+
return (
46+
<>
47+
<h1>List item permutations</h1>
48+
49+
<Checkbox
50+
checked={urlParams.percentageWrapping}
51+
onChange={event => {
52+
setUrlParams({ percentageWrapping: event.detail.checked });
53+
window.location.reload();
54+
}}
55+
>
56+
Percentage-based wrapping
57+
</Checkbox>
58+
59+
<ScreenshotArea>
60+
<PermutationsView
61+
permutations={permutations}
62+
render={({ viewportWidth, ...permutation }) => (
63+
<div style={{ width: viewportWidth, borderRight: '1px solid red', overflow: 'hidden' }}>
64+
<StructuredItem {...permutation} percentageWrapping={urlParams.percentageWrapping} />
65+
</div>
66+
)}
67+
/>
68+
</ScreenshotArea>
69+
</>
70+
);
71+
}

src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11401,6 +11401,35 @@ The default is \`secondary\`, except inside the following components where it de
1140111401
}
1140211402
`;
1140311403

11404+
exports[`Documenter definition for list matches the snapshot: list 1`] = `
11405+
{
11406+
"dashCaseName": "list",
11407+
"events": [],
11408+
"functions": [],
11409+
"name": "List",
11410+
"properties": [
11411+
{
11412+
"name": "items",
11413+
"optional": true,
11414+
"type": "Array<StructuredItemProps>",
11415+
},
11416+
],
11417+
"regions": [
11418+
{
11419+
"isDefault": true,
11420+
"name": "children",
11421+
"systemTags": [
11422+
"core",
11423+
],
11424+
},
11425+
],
11426+
"releaseStatus": "stable",
11427+
"systemTags": [
11428+
"core",
11429+
],
11430+
}
11431+
`;
11432+
1140411433
exports[`Documenter definition for live-region matches the snapshot: live-region 1`] = `
1140511434
{
1140611435
"dashCaseName": "live-region",
@@ -17126,6 +17155,50 @@ Each step definition has the following properties:
1712617155
}
1712717156
`;
1712817157

17158+
exports[`Documenter definition for structured-item matches the snapshot: structured-item 1`] = `
17159+
{
17160+
"dashCaseName": "structured-item",
17161+
"events": [],
17162+
"functions": [],
17163+
"name": "StructuredItem",
17164+
"properties": [
17165+
{
17166+
"defaultValue": "false",
17167+
"name": "disableTypography",
17168+
"optional": true,
17169+
"type": "boolean",
17170+
},
17171+
{
17172+
"name": "percentageWrapping",
17173+
"optional": true,
17174+
"type": "boolean",
17175+
},
17176+
],
17177+
"regions": [
17178+
{
17179+
"isDefault": false,
17180+
"name": "actions",
17181+
},
17182+
{
17183+
"isDefault": false,
17184+
"name": "description",
17185+
},
17186+
{
17187+
"isDefault": false,
17188+
"name": "icon",
17189+
},
17190+
{
17191+
"isDefault": false,
17192+
"name": "label",
17193+
},
17194+
],
17195+
"releaseStatus": "stable",
17196+
"systemTags": [
17197+
"core",
17198+
],
17199+
}
17200+
`;
17201+
1712917202
exports[`Documenter definition for table matches the snapshot: table 1`] = `
1713017203
{
1713117204
"dashCaseName": "table",

src/collection-preferences/content-display/index.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,13 @@ export default function ContentDisplayPreference({
134134
itemDefinition={{ id: item => item.id, label: item => item.label }}
135135
onItemsChange={({ detail }) => onChange(detail.items)}
136136
disableReorder={columnFilteringText.trim().length > 0}
137-
renderItem={({ ref, item, style, className, dragHandleProps, isDragGhost }) => {
138-
className = clsx(className, getOptionClassName());
137+
dragOverlayClassName={styles['drag-overlay']}
138+
renderItem={({ ref, item, style, dragHandleProps, isDragGhost, isDropPlaceholder, isSortingActive }) => {
139+
const className = clsx(
140+
isDropPlaceholder && styles['drag-placeholder'],
141+
isSortingActive && styles['drag-sorting'],
142+
getOptionClassName()
143+
);
139144
const content = (
140145
<ContentDisplayOption ref={ref} option={item} onToggle={onToggle} dragHandleProps={dragHandleProps} />
141146
);

src/collection-preferences/content-display/styles.scss

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
@use '../../internal/styles' as styles;
77
@use '../../internal/styles/tokens' as awsui;
8+
@use '@cloudscape-design/component-toolkit/internal/focus-visible' as focus-visible;
89

910
@import 'content-display-option';
1011

@@ -32,3 +33,36 @@
3233
padding-block: 0;
3334
padding-inline: 0;
3435
}
36+
37+
.drag-overlay {
38+
box-shadow: awsui.$shadow-container-active;
39+
40+
border-start-start-radius: awsui.$border-radius-item;
41+
border-start-end-radius: awsui.$border-radius-item;
42+
border-end-start-radius: awsui.$border-radius-item;
43+
border-end-end-radius: awsui.$border-radius-item;
44+
45+
@include focus-visible.when-visible-unfocused {
46+
@include styles.focus-highlight(0px, awsui.$border-radius-item);
47+
}
48+
}
49+
50+
.drag-sorting {
51+
@include styles.with-motion {
52+
transition: transform awsui.$motion-duration-transition-quick awsui.$motion-easing-transition-quick;
53+
}
54+
}
55+
56+
.drag-placeholder {
57+
position: relative;
58+
&:after {
59+
content: ' ';
60+
position: absolute;
61+
inset: 0;
62+
background: awsui.$color-drag-placeholder-hover;
63+
border-start-start-radius: awsui.$border-radius-item;
64+
border-start-end-radius: awsui.$border-radius-item;
65+
border-end-start-radius: awsui.$border-radius-item;
66+
border-end-end-radius: awsui.$border-radius-item;
67+
}
68+
}

0 commit comments

Comments
 (0)