diff --git a/src/internal/components/portal/index.tsx b/src/internal/components/portal/index.tsx index 0bf4fb54ae..8fcb445b34 100644 --- a/src/internal/components/portal/index.tsx +++ b/src/internal/components/portal/index.tsx @@ -4,7 +4,7 @@ import React, { useLayoutEffect, useState } from 'react'; import { createPortal } from 'react-dom'; export interface PortalProps { - container?: Element; + container?: null | Element; children: React.ReactNode; } diff --git a/src/table/__tests__/resizable-columns.test.tsx b/src/table/__tests__/resizable-columns.test.tsx index 46ef29179b..4b4e7596bf 100644 --- a/src/table/__tests__/resizable-columns.test.tsx +++ b/src/table/__tests__/resizable-columns.test.tsx @@ -365,3 +365,10 @@ describe('resize with keyboard', () => { expect(onChange).toHaveBeenCalledTimes(0); }); }); + +test('resizable columns headers have expected text content', () => { + const { wrapper } = renderTable(); + + expect(wrapper.findColumnHeaders()[0].getElement()!.textContent).toEqual('Id'); + expect(wrapper.findColumnHeaders()[1].getElement()!.textContent).toEqual('Description'); +}); diff --git a/src/table/header-cell/index.tsx b/src/table/header-cell/index.tsx index ce45566126..72fe206eb2 100644 --- a/src/table/header-cell/index.tsx +++ b/src/table/header-cell/index.tsx @@ -37,6 +37,7 @@ interface TableHeaderCellProps { cellRef: React.RefCallback; focusedComponent?: null | string; tableRole: TableRole; + getDescriptionRoot?: () => null | HTMLElement; } export function TableHeaderCell({ @@ -60,6 +61,7 @@ export function TableHeaderCell({ stickyState, cellRef, tableRole, + getDescriptionRoot, }: TableHeaderCellProps) { const i18n = useInternalI18n('table'); const sortable = !!column.sortingComparator || !!column.sortingField; @@ -140,17 +142,16 @@ export function TableHeaderCell({ )} {resizableColumns && ( - <> - updateColumn(columnId, newWidth)} - onFinish={onResizeFinish} - ariaLabelledby={headerId} - minWidth={typeof column.minWidth === 'string' ? parseInt(column.minWidth) : column.minWidth} - /> - + updateColumn(columnId, newWidth)} + onFinish={onResizeFinish} + ariaLabelledby={headerId} + minWidth={typeof column.minWidth === 'string' ? parseInt(column.minWidth) : column.minWidth} + getDescriptionRoot={getDescriptionRoot} + /> )} ); diff --git a/src/table/internal.tsx b/src/table/internal.tsx index f23af672d8..97772dfa15 100644 --- a/src/table/internal.tsx +++ b/src/table/internal.tsx @@ -39,6 +39,7 @@ import { getTableRoleProps, getTableRowRoleProps, getTableWrapperRoleProps } fro import { useCellEditing } from './use-cell-editing'; import { LinkDefaultVariantContext } from '../internal/context/link-default-variant-context'; import { CollectionLabelContext } from '../internal/context/collection-label-context'; +import ScreenreaderOnly from '../internal/components/screenreader-only'; const SELECTION_COLUMN_WIDTH = 54; const selectionColumnId = Symbol('selection-column-id'); @@ -102,6 +103,10 @@ const InternalTable = React.forwardRef( const [tableWidth, tableMeasureRef] = useContainerQuery(rect => rect.contentBoxWidth); const tableRefObject = useRef(null); + // Used to render table's ARIA description nodes into. + const descriptionRef = useRef(null); + const getDescriptionRoot = useCallback(() => descriptionRef.current, []); + const secondaryWrapperRef = React.useRef(null); const theadRef = useRef(null); const stickyHeaderRef = React.useRef(null); @@ -214,6 +219,7 @@ const InternalTable = React.forwardRef( stickyState, selectionColumnId, tableRole, + getDescriptionRoot, }; const wrapperRef = useMergeRefs(wrapperMeasureRef, wrapperRefObject, stickyState.refs.wrapper); @@ -471,6 +477,7 @@ const InternalTable = React.forwardRef(
{resizableColumns && } + + + + + diff --git a/src/table/resizer/index.tsx b/src/table/resizer/index.tsx index 9124f9b90f..18a9427759 100644 --- a/src/table/resizer/index.tsx +++ b/src/table/resizer/index.tsx @@ -9,9 +9,9 @@ import styles from './styles.css.js'; import { KeyCode } from '../../internal/keycode'; import { DEFAULT_COLUMN_WIDTH } from '../use-column-widths'; import { useStableCallback } from '@cloudscape-design/component-toolkit/internal'; -import ScreenreaderOnly from '../../internal/components/screenreader-only'; import { useUniqueId } from '../../internal/hooks/use-unique-id'; import { joinStrings } from '../../internal/utils/strings'; +import Portal from '../../internal/components/portal'; interface ResizerProps { onDragMove: (newWidth: number) => void; @@ -23,6 +23,7 @@ interface ResizerProps { showFocusRing?: boolean; onFocus?: () => void; onBlur?: () => void; + getDescriptionRoot?: () => null | HTMLElement; } const AUTO_GROW_START_TIME = 10; @@ -39,6 +40,7 @@ export function Resizer({ focusId, onFocus, onBlur, + getDescriptionRoot, }: ResizerProps) { const [isDragging, setIsDragging] = useState(false); const [isKeyboardDragging, setIsKeyboardDragging] = useState(false); @@ -238,7 +240,9 @@ export function Resizer({ tabIndex={tabIndex} data-focus-id={focusId} /> - {headerCellWidthString} + + {headerCellWidthString} + ); } diff --git a/src/table/thead.tsx b/src/table/thead.tsx index 04a0f73083..0b035db8e5 100644 --- a/src/table/thead.tsx +++ b/src/table/thead.tsx @@ -41,6 +41,7 @@ export interface TheadProps { focusedComponent?: null | string; onFocusedComponentChange?: (focusId: null | string) => void; tableRole: TableRole; + getDescriptionRoot?: () => null | HTMLElement; } const Thead = React.forwardRef( @@ -69,6 +70,7 @@ const Thead = React.forwardRef( focusedComponent, onFocusedComponentChange, tableRole, + getDescriptionRoot, }: TheadProps, outerRef: React.Ref ) => { @@ -170,6 +172,7 @@ const Thead = React.forwardRef( stickyState={stickyState} cellRef={node => setCell(columnId, node)} tableRole={tableRole} + getDescriptionRoot={getDescriptionRoot} /> ); })}