Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Table grid navigation #1893

Merged
merged 26 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cbac4fd
feat: Table grid navigation
pan-kot Jan 16, 2024
4bba423
code cleanup
pan-kot Jan 17, 2024
730bf95
update documenter
pan-kot Jan 17, 2024
cb564e0
enhance table editable tests
pan-kot Jan 17, 2024
63343c0
enhance more table tests
pan-kot Jan 17, 2024
b8e0ab2
fix cell outline when stick
pan-kot Jan 17, 2024
fa52417
performance fix
pan-kot Jan 18, 2024
abf57c2
simplify focusedCell interface
pan-kot Jan 19, 2024
addf55f
Merge branch 'main' of github.com:cloudscape-design/components into t…
pan-kot Jan 22, 2024
36268e7
refactor: use scrollElementIntoView util
pan-kot Jan 22, 2024
8495ae5
revert unintended change
pan-kot Jan 22, 2024
b30765d
fix unit test
pan-kot Jan 22, 2024
39f8f99
skip registration when navigation is not active
pan-kot Jan 23, 2024
53b6aa9
performance optimisations
pan-kot Jan 23, 2024
6f3f5de
ignore disabled elements and existing selection navigation
pan-kot Jan 23, 2024
cfd91ad
Merge branch 'main' of github.com:cloudscape-design/components into t…
pan-kot Jan 23, 2024
45a8534
Merge branch 'main' of github.com:cloudscape-design/components into t…
pan-kot Jan 25, 2024
57fe0e1
fix focus outline for the first cell
pan-kot Jan 25, 2024
e0cec0d
remove cell scroll on focus
pan-kot Jan 25, 2024
fbbaecd
Fix navigation to extremes
pan-kot Jan 25, 2024
0820404
Merge branch 'main' of github.com:cloudscape-design/components into t…
pan-kot Feb 12, 2024
798aae3
minor change to api docs
pan-kot Feb 15, 2024
9aa3216
refactor keyboard focus nav util api
pan-kot Feb 15, 2024
c05a1d7
fix keyboard nav with empty state
pan-kot Feb 15, 2024
7c2ec9c
Merge branch 'main' of github.com:cloudscape-design/components into t…
pan-kot Feb 15, 2024
2e6e5ee
minor change to api docs
pan-kot Feb 15, 2024
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
93 changes: 59 additions & 34 deletions pages/table/editable.page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { ForwardedRef, forwardRef, useEffect, useRef, useState } from 'react';
import React, { ForwardedRef, forwardRef, useContext, useEffect, useRef, useState } from 'react';
import Header from '~components/header';
import Input from '~components/input';
import Alert from '~components/alert';
Expand All @@ -9,9 +9,16 @@ import Select, { SelectProps } from '~components/select';
import TimeInput, { TimeInputProps } from '~components/time-input';
import Autosuggest, { AutosuggestProps } from '~components/autosuggest';
import Multiselect, { MultiselectProps } from '~components/multiselect';
import { Link, Box, Button, Modal, SpaceBetween } from '~components';
import { Link, Box, Button, Modal, SpaceBetween, Checkbox } from '~components';
import { initialItems, DistributionInfo, tlsVersions, originSuggestions, tagOptions } from './editable-data';
import ScreenshotArea from '../utils/screenshot-area';
import AppContext, { AppContextType } from '../app/app-context';

type PageContext = React.Context<
AppContextType<{
enableKeyboardNavigation: boolean;
}>
>;

let __editStateDirty = false;

Expand Down Expand Up @@ -205,6 +212,7 @@ const Demo = forwardRef(
tableRef: ForwardedRef<TableProps.Ref>
) => {
const [items, setItems] = useState(initialItems);
const { urlParams } = useContext(AppContext as PageContext);

const handleSubmit: TableProps.SubmitEditFunction<DistributionInfo> = async (currentItem, column, newValue) => {
let value = newValue;
Expand Down Expand Up @@ -253,12 +261,14 @@ const Demo = forwardRef(
resizableColumns={true}
ariaLabels={ariaLabels}
stickyHeader={true}
enableKeyboardNavigation={urlParams.enableKeyboardNavigation}
/>
);
}
);

export default function () {
const { urlParams, setUrlParams } = useContext(AppContext as PageContext);
const [modalVisible, setModalVisible] = useState(false);
const tableRef = useRef<TableProps.Ref>(null);

Expand All @@ -275,37 +285,52 @@ export default function () {
});

return (
<ScreenshotArea disableAnimations={true}>
<input data-testid="focus" aria-label="focus input" />
<Demo setModalVisible={setModalVisible} ref={tableRef} />
<Modal
visible={modalVisible}
header="Discard changes"
closeAriaLabel="Close modal"
onDismiss={withCleanState(() => setModalVisible(false))}
footer={
<Box float="right">
<SpaceBetween direction="horizontal" size="xs">
<Button variant="link" onClick={withCleanState(() => setModalVisible(false))}>
Cancel
</Button>
<Button
variant="primary"
onClick={withCleanState(() => {
setModalVisible(false);
tableRef.current?.cancelEdit?.();
})}
>
Discard
</Button>
</SpaceBetween>
</Box>
}
>
<Alert type="warning" statusIconAriaLabel="Warning">
Are you sure you want to discard any unsaved changes?
</Alert>
</Modal>
</ScreenshotArea>
<Box margin="s">
<SpaceBetween size="s">
<Checkbox
checked={urlParams.enableKeyboardNavigation}
onChange={event => {
setUrlParams({ enableKeyboardNavigation: event.detail.checked });
window.location.reload();
}}
>
Keyboard navigation
</Checkbox>

<input data-testid="focus" aria-label="focus input" />
</SpaceBetween>

<ScreenshotArea disableAnimations={true}>
<Demo setModalVisible={setModalVisible} ref={tableRef} />
<Modal
visible={modalVisible}
header="Discard changes"
closeAriaLabel="Close modal"
onDismiss={withCleanState(() => setModalVisible(false))}
footer={
<Box float="right">
<SpaceBetween direction="horizontal" size="xs">
<Button variant="link" onClick={withCleanState(() => setModalVisible(false))}>
Cancel
</Button>
<Button
variant="primary"
onClick={withCleanState(() => {
setModalVisible(false);
tableRef.current?.cancelEdit?.();
})}
>
Discard
</Button>
</SpaceBetween>
</Box>
}
>
<Alert type="warning" statusIconAriaLabel="Warning">
Are you sure you want to discard any unsaved changes?
</Alert>
</Modal>
</ScreenshotArea>
</Box>
);
}
27 changes: 26 additions & 1 deletion pages/table/inline-actions.page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import React, { useContext } from 'react';
import Box from '~components/box';
import Button from '~components/button';
import ButtonDropdown from '~components/button-dropdown';
Expand All @@ -11,6 +11,14 @@ import ScreenshotArea from '../utils/screenshot-area';
import { Instance, generateItems } from './generate-data';
import { columnsConfig, selectionLabels } from './shared-configs';
import Link from '~components/link';
import AppContext, { AppContextType } from '../app/app-context';
import { Checkbox } from '~components';

type PageContext = React.Context<
AppContextType<{
enableKeyboardNavigation: boolean;
}>
>;

const items = generateItems(10);

Expand Down Expand Up @@ -148,8 +156,20 @@ const columnDefinitionsOnlyIcons: TableProps.ColumnDefinition<Instance>[] = [
];

export default function () {
const { urlParams, setUrlParams } = useContext(AppContext as PageContext);

return (
<ScreenshotArea style={{ padding: '10px 50px' }}>
<Checkbox
checked={urlParams.enableKeyboardNavigation}
onChange={event => {
setUrlParams({ enableKeyboardNavigation: event.detail.checked });
window.location.reload();
}}
>
Keyboard navigation
</Checkbox>

<Box padding="l">
<h1>Tables with inline actions</h1>
<SpaceBetween size="l">
Expand All @@ -158,12 +178,14 @@ export default function () {
header={<Header>Table with single actions</Header>}
columnDefinitions={columnDefinitionsSingle}
items={items}
enableKeyboardNavigation={urlParams.enableKeyboardNavigation}
/>
<Table
ariaLabels={selectionLabels}
header={<Header>Table with multiple actions</Header>}
columnDefinitions={columnDefinitionsMultiple}
items={items}
enableKeyboardNavigation={urlParams.enableKeyboardNavigation}
/>
<Table
ariaLabels={selectionLabels}
Expand All @@ -190,18 +212,21 @@ export default function () {
selectionType="multi"
columnDefinitions={columnDefinitionsDropdown}
items={items}
enableKeyboardNavigation={urlParams.enableKeyboardNavigation}
/>
<Table
ariaLabels={selectionLabels}
header={<Header>Table with mixed actions</Header>}
columnDefinitions={columnDefinitionsMixed}
items={items}
enableKeyboardNavigation={urlParams.enableKeyboardNavigation}
/>
<Table
ariaLabels={selectionLabels}
header={<Header>Table with only icon actions</Header>}
columnDefinitions={columnDefinitionsOnlyIcons}
items={items}
enableKeyboardNavigation={urlParams.enableKeyboardNavigation}
/>
</SpaceBetween>
</Box>
Expand Down
40 changes: 30 additions & 10 deletions pages/table/performance.page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useState } from 'react';
import React, { useContext, useState } from 'react';
import Button from '~components/button';
import Box from '~components/box';
import Header from '~components/header';
import Input from '~components/input';
import Table, { TableProps } from '~components/table';
import ScreenshotArea from '../utils/screenshot-area';
import AppContext, { AppContextType } from '../app/app-context';
import { Checkbox, SpaceBetween } from '~components';

type PageContext = React.Context<
AppContextType<{
enableKeyboardNavigation: boolean;
}>
>;

const COLUMN_COUNT = 100;

Expand Down Expand Up @@ -49,9 +57,11 @@ const columnDefinitions: Array<TableProps.ColumnDefinition<Item>> = [...new Arra

export default function App() {
const [isActive, setIsActive] = useState(false);
const { urlParams, setUrlParams } = useContext(AppContext as PageContext);
return (
<ScreenshotArea>
<h1>Table performance test</h1>

{isActive ? (
<Table
columnDefinitions={columnDefinitions}
Expand All @@ -71,17 +81,27 @@ export default function App() {
</Box>
}
header={<Header>Table with inline editing</Header>}
enableKeyboardNavigation={urlParams.enableKeyboardNavigation}
/>
) : (
<Button
onClick={() => {
setIsActive(true);
console.time('render');
requestAnimationFrame(() => console.timeEnd('render'));
}}
>
Render Table
</Button>
<SpaceBetween size="s">
<Checkbox
checked={urlParams.enableKeyboardNavigation}
onChange={event => setUrlParams({ enableKeyboardNavigation: event.detail.checked })}
>
Keyboard navigation
</Checkbox>

<Button
onClick={() => {
setIsActive(true);
console.time('render');
requestAnimationFrame(() => console.timeEnd('render'));
}}
>
Render Table
</Button>
</SpaceBetween>
)}
</ScreenshotArea>
);
Expand Down
12 changes: 12 additions & 0 deletions pages/table/resizable-columns.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ type PageContext = React.Context<
fullPage: boolean;
withColumnIds?: boolean;
withSelection?: boolean;
enableKeyboardNavigation?: boolean;
}>
>;

Expand All @@ -111,6 +112,7 @@ export default function App() {
fullPage = false,
withColumnIds = true,
withSelection = false,
enableKeyboardNavigation = false,
} = urlParams;

const [renderKey, setRenderKey] = useState(0);
Expand Down Expand Up @@ -173,6 +175,15 @@ export default function App() {
<Checkbox checked={withSelection} onChange={event => setUrlParams({ withSelection: event.detail.checked })}>
With row selection
</Checkbox>
<Checkbox
checked={enableKeyboardNavigation}
onChange={event => {
setUrlParams({ enableKeyboardNavigation: event.detail.checked });
jperals marked this conversation as resolved.
Show resolved Hide resolved
window.location.reload();
}}
>
Keyboard navigation
</Checkbox>
</div>
<div>
{columnsConfig.map(column => (
Expand Down Expand Up @@ -213,6 +224,7 @@ export default function App() {
onSortingChange={event => setSorting(event.detail)}
onColumnWidthsChange={handleWidthChange}
variant={fullPage ? 'full-page' : undefined}
enableKeyboardNavigation={enableKeyboardNavigation}
/>
</ScreenshotArea>
</SpaceBetween>
Expand Down
28 changes: 26 additions & 2 deletions pages/table/selection.page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useState } from 'react';
import React, { useContext, useState } from 'react';
import SpaceBetween from '~components/space-between';
import Table from '~components/table';
import ScreenshotArea from '../utils/screenshot-area';
import { ariaLabels, createSimpleItems, simpleColumns } from './shared-configs';
import { Checkbox } from '~components';
import AppContext, { AppContextType } from '../app/app-context';

export default function () {
type PageContext = React.Context<
AppContextType<{
enableKeyboardNavigation: boolean;
}>
>;

export default function Page() {
const { urlParams, setUrlParams } = useContext(AppContext as PageContext);
return (
<>
<h1>Table selection</h1>

<Checkbox
checked={urlParams.enableKeyboardNavigation}
onChange={event => {
setUrlParams({ enableKeyboardNavigation: event.detail.checked });
window.location.reload();
}}
>
Keyboard navigation
</Checkbox>

<ScreenshotArea disableAnimations={true}>
<SpaceBetween size="m">
<MultiSelection />
Expand All @@ -21,6 +41,7 @@ export default function () {
}

const MultiSelection = () => {
const { urlParams } = useContext(AppContext as PageContext);
const [selectedItems, setSelectedItems] = useState([{ number: 2, text: 'Two' }]);
return (
<Table
Expand All @@ -32,11 +53,13 @@ const MultiSelection = () => {
onSelectionChange={({ detail: { selectedItems } }) => setSelectedItems(selectedItems)}
isItemDisabled={({ text }) => text === 'Two'}
ariaLabels={ariaLabels}
enableKeyboardNavigation={urlParams.enableKeyboardNavigation}
/>
);
};

const SingleSelection = () => {
const { urlParams } = useContext(AppContext as PageContext);
const [selectedItems, setSelectedItems] = useState([{ number: 1, text: 'One' }]);
return (
<Table
Expand All @@ -47,6 +70,7 @@ const SingleSelection = () => {
trackBy={'text'}
onSelectionChange={({ detail: { selectedItems } }) => setSelectedItems(selectedItems)}
ariaLabels={ariaLabels}
enableKeyboardNavigation={urlParams.enableKeyboardNavigation}
/>
);
};
Loading
Loading