Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
2248f56
feat: Modify interfaces
NathanZlion Feb 19, 2026
4a1ae58
feat: Add Test Pages
NathanZlion Feb 19, 2026
b7d321d
feat: Add column grouping util functions to create tree
NathanZlion Feb 19, 2026
f4b12b7
chore: Update snapshots
NathanZlion Feb 21, 2026
2257180
chore: Add colSpan, rowSpan, and scope to th-element
NathanZlion Feb 23, 2026
e6379ee
fix: Add SimplePage for test page
NathanZlion Feb 23, 2026
3d44715
fix: Fix Axe violation for heading one availability, and AriaLabel vi…
NathanZlion Feb 23, 2026
b3efd25
chore: Add fields for first and last for sticky
NathanZlion Feb 25, 2026
060ee4f
feat: Add column grouping support with nested headers, colspan/rowspa…
NathanZlion Feb 25, 2026
5974101
fix: Fix failing unit tests for row count and single row render condi…
NathanZlion Feb 26, 2026
f004535
fix: Address some A11Y and codecov issues
NathanZlion Feb 26, 2026
5f2f666
feat: Add empty cells to push column down
NathanZlion Feb 26, 2026
ceaf91e
fix: Unit tests pass
NathanZlion Feb 26, 2026
cd0f349
chore: Make page easy to test
NathanZlion Feb 26, 2026
1d7a4ca
feat: Implement Collection Preference for hierarchical lists
NathanZlion Feb 26, 2026
824f971
fix: Ensure collection preference works for multi-depth
NathanZlion Feb 26, 2026
94af8b9
test
NathanZlion Mar 3, 2026
f42d119
chore: Minor design updates
NathanZlion Mar 6, 2026
b9a0f9a
chore: Add playground style controls and customer pages for demo
NathanZlion Mar 6, 2026
f82c138
chore: Minor changes to focus cell
NathanZlion Mar 6, 2026
8ad3024
fix: Focus ring issue
NathanZlion Mar 9, 2026
687c850
fix: Move selectin cell down to a single row span for grouped
NathanZlion Mar 9, 2026
a183fcb
chore: default resizer block gap to 9 on each sizde
NathanZlion Mar 10, 2026
4316c90
chore: Modify API separate definitino from display
NathanZlion Mar 12, 2026
0e30e3d
chore: Modify pages to use new API
NathanZlion Mar 12, 2026
c17640e
chore: Modify tests
NathanZlion Mar 12, 2026
dfce4ec
fix: Fix linting error due to in operator
NathanZlion Mar 12, 2026
38f99ae
chore: Modify APIs for backwards compatibility
NathanZlion Mar 12, 2026
cf36953
chore: API Change concepts
NathanZlion Mar 13, 2026
8576581
chore: Update test util
NathanZlion Mar 13, 2026
d5ecaeb
chore: Update documentor
NathanZlion Mar 13, 2026
7158a1f
chore: update table tests
NathanZlion Mar 17, 2026
1f63287
chore: Add visible api to ContentDisplayGroup for dry run purposes
NathanZlion Mar 17, 2026
04db254
fix: Typing issue with backwards compatibility
NathanZlion Mar 18, 2026
38b5cd1
feat: Stretch spanning header cells to full rowspan height with botto…
NathanZlion Mar 19, 2026
37eab4f
chore: Update snapshot
NathanZlion Mar 19, 2026
43b75a5
chore: fix tests
NathanZlion Mar 19, 2026
521bd21
chore: Modify test page
NathanZlion Mar 19, 2026
ca8e2ec
chore: Update table resizer heights depending on cell type
NathanZlion Mar 23, 2026
b1a2419
fix: Sticky columns start side works now
NathanZlion Mar 30, 2026
4574b7b
chore: Update documenter
NathanZlion Mar 30, 2026
44e64a9
chore: Update snapshot
NathanZlion Mar 30, 2026
ccad898
chore: Add doc-string, make enableColumnFiltering toggerable
NathanZlion Mar 30, 2026
bd30e31
chore: Fix findResizer util code
NathanZlion Mar 30, 2026
14fef4f
chore: Update snapshot
NathanZlion Mar 30, 2026
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
110 changes: 110 additions & 0 deletions pages/collection-preferences/multi-level-reorder.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';

import CollectionPreferences, { CollectionPreferencesProps } from '~components/collection-preferences';

import { contentDisplayPreferenceI18nStrings } from '../common/i18n-strings';
import {
baseProperties,
contentDensityPreference,
customPreference,
pageSizePreference,
wrapLinesPreference,
} from './shared-configs';

const columnOptions: CollectionPreferencesProps.ContentDisplayOption[] = [
// ungrouped
{ id: 'name', label: 'Name', alwaysVisible: true },
{ id: 'status', label: 'Status' },

// performance
{ id: 'cpuUtilization', label: 'CPU (%)' },
{ id: 'memoryUtilization', label: 'Memory (%)' },
{ id: 'networkIn', label: 'Network In (MB/s)' },
{ id: 'networkOut', label: 'Network Out (MB/s)' },

// config
{ id: 'instanceType', label: 'Instance Type' },
{ id: 'availabilityZone', label: 'Availability Zone' },
{ id: 'region', label: 'Region' },

// cost
{ id: 'monthlyCost', label: 'Monthly Cost ($)' },
{ id: 'spotPrice', label: 'Spot Price ($/hr)' },
{
id: 'reservedCost',
label:
'Reserved Instance Cost - Long text to verify wrapping behavior and ensure the reordering feature works correctly with extended content',
},
];

const columnGroups: CollectionPreferencesProps.ContentDisplayOptionGroup[] = [
{ id: 'performance', label: 'Performance' },
{ id: 'configuration', label: 'Configuration' },
{ id: 'cost', label: 'Cost' },
];

const defaultContentDisplay: CollectionPreferencesProps.ContentDisplayItem[] = [
{ id: 'name', visible: true },
{ id: 'status', visible: true },
{
type: 'group',
id: 'performance',
visible: true,
children: [
{ id: 'cpuUtilization', visible: true },
{ id: 'memoryUtilization', visible: true },
{ id: 'networkIn', visible: true },
{ id: 'networkOut', visible: true },
],
},
{
type: 'group',
id: 'configuration',
visible: true,
children: [
{ id: 'instanceType', visible: true },
{ id: 'availabilityZone', visible: true },
{ id: 'region', visible: true },
],
},
{
type: 'group',
id: 'cost',
visible: true,
children: [
{ id: 'monthlyCost', visible: true },
{ id: 'spotPrice', visible: true },
{ id: 'reservedCost', visible: true },
],
},
];

export default function App() {
const [preferences, setPreferences] = React.useState<CollectionPreferencesProps.Preferences>({
contentDisplay: defaultContentDisplay,
});

return (
<>
<h1>Multi-level Reorder Preferences</h1>
<CollectionPreferences
{...baseProperties}
pageSizePreference={pageSizePreference}
wrapLinesPreference={wrapLinesPreference}
contentDensityPreference={contentDensityPreference}
customPreference={customPreference}
preferences={preferences}
onConfirm={({ detail }) => setPreferences(detail)}
contentDisplayPreference={{
title: 'Column preferences',
description: 'Customize the columns visibility and order.',
options: columnOptions,
groups: columnGroups,
...contentDisplayPreferenceI18nStrings,
}}
/>
</>
);
}
155 changes: 155 additions & 0 deletions pages/list/nested-sortable.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useState } from 'react';

import { Box, Container, Header, SpaceBetween } from '~components';
import List from '~components/list';

interface TreeItem {
id: string;
content: string;
children?: TreeItem[];
}

const initialData: TreeItem[] = [
{
id: 'item-1',
content: 'Group 1',
children: [
{ id: 'item-1-1', content: 'Item 1.1' },
{
id: 'item-1-2',
content: 'Item 1.2',
children: [
{ id: 'item-1-2-1', content: 'Item 1.2.1' },
{
id: 'item-1-2-2',
content: 'Item 1.2.2',
children: [
{ id: 'item-1-2-2-1', content: 'Item 1.2.2.1' },
{ id: 'item-1-2-2-2', content: 'Item 1.2.2.2' },
],
},
{ id: 'item-1-2-3', content: 'Item 1.2.3' },
],
},
{ id: 'item-1-3', content: 'Item 1.3' },
],
},
{
id: 'item-2',
content: 'Group 2',
children: [
{ id: 'item-2-1', content: 'Item 2.1' },
{
id: 'item-2-2',
content: 'Item 2.2',
children: [
{ id: 'item-2-2-1', content: 'Item 2.2.1' },
{ id: 'item-2-2-2', content: 'Item 2.2.2' },
],
},
],
},
{
id: 'item-3',
content: 'Group 3',
children: [
{ id: 'item-3-1', content: 'Item 3.1' },
{ id: 'item-3-2', content: 'Item 3.2' },
{ id: 'item-3-3', content: 'Item 3.3' },
],
},
];

export default function NestedSortableListPage() {
const [items, setItems] = useState(initialData);

const updateItemChildren = (items: TreeItem[], targetId: string, newChildren: TreeItem[]): TreeItem[] => {
return items.map(item => {
if (item.id === targetId) {
return { ...item, children: newChildren };
}
if (item.children) {
return {
...item,
children: updateItemChildren(item.children, targetId, newChildren),
};
}
return item;
});
};

const handleChildSort = (itemId: string, newChildren: TreeItem[]) => {
setItems(prev => updateItemChildren(prev, itemId, newChildren));
};

return (
<Box padding="l">
<SpaceBetween size="l">
<Header variant="h1">Recursive Nested Sortable Lists</Header>

<Container header={<Header variant="h2">Tree Structure with Recursive Sorting</Header>}>
<RecursiveList
items={items}
onSortingChange={newItems => setItems(newItems)}
depth={0}
onChildSort={handleChildSort}
/>
</Container>

<Container header={<Header variant="h2">Debug: Current Data Structure</Header>}>
<pre style={{ fontSize: '12px', overflow: 'auto', maxHeight: '400px' }}>{JSON.stringify(items, null, 2)}</pre>
</Container>
</SpaceBetween>
</Box>
);
}

interface RecursiveListProps {
items: TreeItem[];
onSortingChange: (items: TreeItem[]) => void;
depth: number;
onChildSort: (itemId: string, newChildren: TreeItem[]) => void;
}

function RecursiveList({ items, onSortingChange, depth, onChildSort }: RecursiveListProps) {
const [localItems, setLocalItems] = useState(items);

React.useEffect(() => {
setLocalItems(items);
}, [items]);

const handleSort = (e: { detail: { items: ReadonlyArray<TreeItem> } }) => {
const newItems = [...e.detail.items];
setLocalItems(newItems);
onSortingChange(newItems);
};

return (
<List
items={localItems}
sortable={true}
onSortingChange={handleSort}
disableItemPaddings={false}
renderItem={item => ({
id: item.id,
content: (
<SpaceBetween size="s">
<Box variant={depth === 0 ? 'h3' : 'span'}>{item.content}</Box>
{item.children && item.children.length > 0 && (
<Box padding={{ left: 'l' }}>
<RecursiveList
items={item.children}
onSortingChange={newChildren => onChildSort(item.id, newChildren)}
depth={depth + 1}
onChildSort={onChildSort}
/>
</Box>
)}
</SpaceBetween>
),
})}
/>
);
}
2 changes: 1 addition & 1 deletion pages/table-fragments/grid-navigation-custom.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export default function Page() {
onConfirm={({ detail }) =>
setUrlParams({
visibleColumns: (detail.contentDisplay ?? [])
.filter(column => column.visible)
.filter(column => column.type !== 'group' && column.visible)
.map(column => column.id)
.join(','),
})
Expand Down
Loading
Loading