Skip to content
Merged
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
2 changes: 1 addition & 1 deletion pages/table/cell-permutations.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ function TableCellsDemo() {
sortingField: index === 2 ? 'field-1' : index === 3 ? 'field-2' : undefined,
activeSorting: index === 3,
cell: item => cellRenderer.render(item),
verticalAlign: settings.verticalAlign,
editConfig: settings.isEditable
? {
ariaLabel: 'Edit dialog aria label',
Expand Down Expand Up @@ -288,6 +287,7 @@ function TableCellsDemo() {
stickyColumns={{ first: settings.stickyColumnsFirst, last: settings.stickyColumnsLast }}
selectionType={selectionType}
selectedItems={selectedItems}
cellVerticalAlign={settings.verticalAlign}
empty="Empty"
loading={settings.tableLoading}
loadingText="Loading"
Expand Down
13 changes: 11 additions & 2 deletions pages/table/permutations.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,17 @@ const VERTICAL_ALIGN_COLUMNS: TableProps.ColumnDefinition<any>[] = [
verticalAlign: 'top',
},
{
id: 'type-2',
header: 'Value',
id: 'value-top',
header: 'Value (top)',
cell: item => item.text,
verticalAlign: 'top',
},
{
id: 'value-middle',
header: 'Value (middle)',
cell: item => item.text,
verticalAlign: 'middle',
},
];

/* eslint-disable react/jsx-key */
Expand Down Expand Up @@ -314,9 +320,12 @@ const permutations = createPermutations<TableProps>([
items: [createSimpleItems(3)],
},
{
header: ['Vertical align'],
columnDefinitions: [VERTICAL_ALIGN_COLUMNS],
cellVerticalAlign: ['top'],
items: [createSimpleItems(3)],
variant: [undefined, 'full-page'],
selectionType: ['multi'],
},
{
columnDefinitions: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16034,6 +16034,23 @@ add a meaningful description to the whole selection.
"optional": true,
"type": "TableProps.AriaLabels<T>",
},
{
"defaultValue": "'middle'",
"description": "Determines the alignment of the content inside table cells.
This property affects all cells, including the ones in the selection column.
To target individual cells use \`columnDefinitions.verticalAlign\`, that takes precedence over \`cellVerticalAlign\`.",
"inlineType": {
"name": "",
"type": "union",
"values": [
"middle",
"top",
],
},
"name": "cellVerticalAlign",
"optional": true,
"type": "string",
},
{
"deprecatedTag": "Custom CSS is not supported. For testing and other use cases, use [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes).",
"description": "Adds the specified classes to the root element of the component.",
Expand Down
46 changes: 46 additions & 0 deletions src/table/__tests__/table-feature-metrics.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';
import { render } from '@testing-library/react';

import * as baseComponentHooks from '../../../lib/components/internal/hooks/use-base-component';
import Table from '../../../lib/components/table';

const useBaseComponentSpy = jest.spyOn(baseComponentHooks, 'default');

test('reports cellVerticalAlign and columnDefinitionsVerticalAlign correctly', () => {
const def = (id: string, verticalAlign: 'middle' | 'top') => ({ id, header: '', cell: () => null, verticalAlign });

render(<Table columnDefinitions={[def('1', 'middle')]} items={[]} />);

expect(useBaseComponentSpy).toHaveBeenCalledWith(
'Table',
{
props: expect.objectContaining({ cellVerticalAlign: 'middle' }),
metadata: expect.objectContaining({ usesColumnDefinitionsVerticalAlign: false }),
},
expect.anything()
);

render(<Table columnDefinitions={[def('1', 'middle')]} items={[]} cellVerticalAlign="top" />);

expect(useBaseComponentSpy).toHaveBeenCalledWith(
'Table',
{
props: expect.objectContaining({ cellVerticalAlign: 'top' }),
metadata: expect.objectContaining({ usesColumnDefinitionsVerticalAlign: true }),
},
expect.anything()
);

render(<Table columnDefinitions={[def('1', 'top'), def('2', 'top')]} items={[]} cellVerticalAlign="top" />);

expect(useBaseComponentSpy).toHaveBeenCalledWith(
'Table',
{
props: expect.objectContaining({ cellVerticalAlign: 'top' }),
metadata: expect.objectContaining({ usesColumnDefinitionsVerticalAlign: false }),
},
expect.anything()
);
});
6 changes: 6 additions & 0 deletions src/table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const Table = React.forwardRef(
selectedItems = [],
variant = 'container',
contentDensity = 'comfortable',
cellVerticalAlign = 'middle',
firstIndex = 1,
...props
}: TableProps<T>,
Expand All @@ -46,6 +47,7 @@ const Table = React.forwardRef(
enableKeyboardNavigation: props.enableKeyboardNavigation,
totalItemsCount: props.totalItemsCount,
flowType: analyticsMetadata.flowType,
cellVerticalAlign,
},
metadata: {
expandableRows: !!props.expandableRows,
Expand All @@ -61,6 +63,9 @@ const Table = React.forwardRef(
hasInstanceIdentifier: Boolean(analyticsMetadata?.instanceIdentifier),
usesVisibleColumns: !!props.visibleColumns,
usesColumnDisplay: !!props.columnDisplay,
usesColumnDefinitionsVerticalAlign: props.columnDefinitions.some(
def => def.verticalAlign !== cellVerticalAlign
),
},
},
analyticsMetadata
Expand Down Expand Up @@ -89,6 +94,7 @@ const Table = React.forwardRef(
variant,
contentDensity,
firstIndex,
cellVerticalAlign,
...props,
...baseComponentProps,
ref,
Expand Down
8 changes: 8 additions & 0 deletions src/table/interfaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ export interface TableProps<T = any> extends BaseComponentProps {
* * `verticalAlign` ('middle' | 'top') - Determines the alignment of the content in the table cell.
*/
columnDefinitions: ReadonlyArray<TableProps.ColumnDefinition<T>>;

/**
* Determines the alignment of the content inside table cells.
* This property affects all cells, including the ones in the selection column.
* To target individual cells use `columnDefinitions.verticalAlign`, that takes precedence over `cellVerticalAlign`.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be a good idea to mention which one takes precedence here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the columnDefinitions.verticalAlign taking precedence is the only reasonable assumption because otherwise it won't work at all if cellVerticalAlign is set.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's reasonable to assume but making it explicit and clear would be even better in my opinion.

cellVerticalAlign?: 'middle' | 'top';

/**
* Specifies the selection type (`'single' | 'multi'`).
*/
Expand Down
15 changes: 12 additions & 3 deletions src/table/internal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ const GRID_NAVIGATION_PAGE_SIZE = 10;
const SELECTION_COLUMN_WIDTH = 54;
const selectionColumnId = Symbol('selection-column-id');

type InternalTableProps<T> = SomeRequired<TableProps<T>, 'items' | 'selectedItems' | 'variant' | 'firstIndex'> &
type InternalTableProps<T> = SomeRequired<
TableProps<T>,
'items' | 'selectedItems' | 'variant' | 'firstIndex' | 'cellVerticalAlign'
> &
InternalBaseComponentProps & {
__funnelSubStepProps?: InternalContainerProps['__funnelSubStepProps'];
};
Expand Down Expand Up @@ -135,6 +138,7 @@ const InternalTable = React.forwardRef(
renderLoaderLoading,
renderLoaderError,
renderLoaderEmpty,
cellVerticalAlign,
__funnelSubStepProps,
...rest
}: InternalTableProps<T>,
Expand Down Expand Up @@ -595,6 +599,7 @@ const InternalTable = React.forwardRef(
rowIndex,
itemKey: `${getTableItemKey(row.item)}`,
}}
verticalAlign={cellVerticalAlign}
/>
)}

Expand Down Expand Up @@ -644,7 +649,7 @@ const InternalTable = React.forwardRef(
submitEdit={cellEditing.submitEdit}
columnId={column.id ?? colIndex}
colIndex={colIndex + colIndexOffset}
verticalAlign={column.verticalAlign}
verticalAlign={column.verticalAlign ?? cellVerticalAlign}
{...cellExpandableProps}
{...getAnalyticsMetadataAttribute(analyticsMetadata)}
/>
Expand All @@ -670,7 +675,11 @@ const InternalTable = React.forwardRef(
{...rowRoleProps}
>
{getItemSelectionProps && (
<TableBodySelectionCell {...sharedCellProps} columnId={selectionColumnId} />
<TableBodySelectionCell
{...sharedCellProps}
columnId={selectionColumnId}
verticalAlign={cellVerticalAlign}
/>
)}
{visibleColumnDefinitions.map((column, colIndex) => (
<TableLoaderCell
Expand Down
4 changes: 3 additions & 1 deletion src/table/selection/selection-cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export function TableHeaderSelectionCell({
export function TableBodySelectionCell({ selectionControlProps, ...props }: TableBodySelectionCellProps) {
return (
<TableTdElement {...props} isSelection={true} wrapLines={false} isEditable={false} isEditing={false} colIndex={0}>
{selectionControlProps ? <SelectionControl {...selectionControlProps} /> : null}
{selectionControlProps ? (
<SelectionControl {...selectionControlProps} verticalAlign={props.verticalAlign} />
) : null}
</TableTdElement>
);
}
10 changes: 6 additions & 4 deletions src/table/selection/selection-control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface SelectionControlProps extends SelectionProps {
focusedComponent?: null | string;
rowIndex?: number;
itemKey?: string;
verticalAlign?: 'middle' | 'top';
}

export function SelectionControl({
Expand All @@ -37,6 +38,7 @@ export function SelectionControl({
focusedComponent,
rowIndex,
itemKey,
verticalAlign = 'middle',
...sharedProps
}: SelectionControlProps) {
const controlId = useUniqueId();
Expand All @@ -45,7 +47,7 @@ export function SelectionControl({

const setShiftState = (event: KeyboardEvent | MouseEvent) => {
if (isMultiSelection) {
onShiftToggle && onShiftToggle(event.shiftKey);
onShiftToggle?.(event.shiftKey);
}
};

Expand All @@ -65,11 +67,11 @@ export function SelectionControl({
if (isMultiSelection && !navigationActive) {
if (event.keyCode === KeyCode.up) {
event.preventDefault();
onFocusUp && onFocusUp(event);
onFocusUp?.(event);
}
if (event.keyCode === KeyCode.down) {
event.preventDefault();
onFocusDown && onFocusDown(event);
onFocusDown?.(event);
}
}
};
Expand Down Expand Up @@ -102,7 +104,7 @@ export function SelectionControl({
onMouseUp={setShiftState}
onClick={handleClick}
htmlFor={controlId}
className={clsx(styles.label, styles.root)}
className={clsx(styles.label, styles.root, verticalAlign === 'top' && styles['label-top'])}
aria-label={ariaLabel}
title={ariaLabel}
{...(rowIndex !== undefined && !sharedProps.disabled
Expand Down
5 changes: 5 additions & 0 deletions src/table/selection/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
border-inline-end: 0.1 * styles.$base-size solid transparent;
}

.label-top {
align-items: baseline;
padding-block-start: awsui.$space-xs;
}

.stud {
visibility: hidden;
}
Loading