@cloudscape-design/components 3.0.390 → 3.0.392
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app-layout/drawer/drawers-helpers.d.ts +1 -1
- package/app-layout/drawer/drawers-helpers.d.ts.map +1 -1
- package/app-layout/drawer/drawers-helpers.js +4 -8
- package/app-layout/drawer/drawers-helpers.js.map +1 -1
- package/app-layout/drawer/index.d.ts.map +1 -1
- package/app-layout/drawer/index.js +13 -4
- package/app-layout/drawer/index.js.map +1 -1
- package/app-layout/drawer/styles.css.js +11 -10
- package/app-layout/drawer/styles.scoped.css +24 -17
- package/app-layout/drawer/styles.selectors.js +11 -10
- package/app-layout/index.d.ts.map +1 -1
- package/app-layout/index.js +3 -0
- package/app-layout/index.js.map +1 -1
- package/app-layout/mobile-toolbar/index.js +1 -1
- package/app-layout/mobile-toolbar/index.js.map +1 -1
- package/app-layout/visual-refresh/drawers.js +1 -1
- package/app-layout/visual-refresh/drawers.js.map +1 -1
- package/autosuggest/internal.d.ts.map +1 -1
- package/autosuggest/internal.js +5 -3
- package/autosuggest/internal.js.map +1 -1
- package/button-dropdown/interfaces.d.ts +2 -1
- package/button-dropdown/interfaces.d.ts.map +1 -1
- package/button-dropdown/interfaces.js.map +1 -1
- package/button-dropdown/internal.js +4 -4
- package/button-dropdown/internal.js.map +1 -1
- package/internal/components/dropdown/index.d.ts.map +1 -1
- package/internal/components/dropdown/index.js +6 -8
- package/internal/components/dropdown/index.js.map +1 -1
- package/internal/components/dropdown/styles.css.js +20 -21
- package/internal/components/dropdown/styles.scoped.css +37 -41
- package/internal/components/dropdown/styles.selectors.js +20 -21
- package/internal/components/dropdown-status/index.d.ts +6 -1
- package/internal/components/dropdown-status/index.d.ts.map +1 -1
- package/internal/components/dropdown-status/index.js +2 -2
- package/internal/components/dropdown-status/index.js.map +1 -1
- package/internal/environment.js +1 -1
- package/internal/environment.json +1 -1
- package/internal/hooks/use-visual-mode/index.d.ts +0 -2
- package/internal/hooks/use-visual-mode/index.d.ts.map +1 -1
- package/internal/hooks/use-visual-mode/index.js +2 -31
- package/internal/hooks/use-visual-mode/index.js.map +1 -1
- package/internal/manifest.json +1 -1
- package/multiselect/internal.d.ts.map +1 -1
- package/multiselect/internal.js +7 -2
- package/multiselect/internal.js.map +1 -1
- package/package.json +1 -1
- package/property-filter/controller.d.ts.map +1 -1
- package/property-filter/controller.js +23 -11
- package/property-filter/controller.js.map +1 -1
- package/property-filter/index.d.ts.map +1 -1
- package/property-filter/index.js +26 -11
- package/property-filter/index.js.map +1 -1
- package/property-filter/property-filter-autosuggest.d.ts.map +1 -1
- package/property-filter/property-filter-autosuggest.js +1 -1
- package/property-filter/property-filter-autosuggest.js.map +1 -1
- package/select/internal.d.ts.map +1 -1
- package/select/internal.js +3 -1
- package/select/internal.js.map +1 -1
- package/table/sticky-scrollbar/sticky-scrollbar.js +1 -1
- package/table/sticky-scrollbar/sticky-scrollbar.js.map +1 -1
- package/table/sticky-scrollbar/use-sticky-scrollbar.d.ts +1 -1
- package/table/sticky-scrollbar/use-sticky-scrollbar.d.ts.map +1 -1
- package/table/sticky-scrollbar/use-sticky-scrollbar.js +10 -2
- package/table/sticky-scrollbar/use-sticky-scrollbar.js.map +1 -1
- package/table/table-role/index.d.ts +1 -1
- package/table/table-role/index.d.ts.map +1 -1
- package/table/table-role/index.js.map +1 -1
- package/table/table-role/interfaces.d.ts +2 -4
- package/table/table-role/interfaces.d.ts.map +1 -1
- package/table/table-role/interfaces.js.map +1 -1
- package/table/table-role/use-grid-navigation.d.ts +6 -3
- package/table/table-role/use-grid-navigation.d.ts.map +1 -1
- package/table/table-role/use-grid-navigation.js +71 -40
- package/table/table-role/use-grid-navigation.js.map +1 -1
- package/table/table-role/utils.d.ts +22 -4
- package/table/table-role/utils.d.ts.map +1 -1
- package/table/table-role/utils.js +86 -57
- package/table/table-role/utils.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-grid-navigation.js","sourceRoot":"lib/default/","sources":["table/table-role/use-grid-navigation.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { useEffect, useMemo } from 'react';\nimport { findFocusinCell, moveFocusBy, restoreTableFocusables, updateTableFocusables } from './utils';\nimport { FocusedCell, GridNavigationAPI, GridNavigationProps } from './interfaces';\nimport { KeyCode } from '../../internal/keycode';\nimport { nodeContains } from '@cloudscape-design/component-toolkit/dom';\n\n/**\n * Makes table with role=\"grid\" navigable with keyboard commands.\n * See https://www.w3.org/WAI/ARIA/apg/patterns/grid\n */\nexport function useGridNavigation({ tableRole, pageSize, getTable }: GridNavigationProps): GridNavigationAPI {\n const model = useMemo(() => new GridNavigationModel(), []);\n\n // Initialize the model with the table container assuming it is mounted synchronously and only once.\n useEffect(\n () => {\n if (tableRole === 'grid') {\n const table = getTable();\n table && model.init(table);\n }\n return () => model.destroy();\n },\n // Assuming getTable is stable.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [model, tableRole]\n );\n\n // Notify the model of the props change.\n useEffect(() => {\n model.update({ pageSize });\n }, [model, pageSize]);\n\n return {};\n}\n\nclass GridNavigationModel {\n // Props\n private _pageSize = 0;\n private _table: null | HTMLTableElement = null;\n\n // State\n private prevFocusedCell: null | FocusedCell = null;\n private focusedCell: null | FocusedCell = null;\n private cleanup = () => {};\n\n public init(table: HTMLTableElement) {\n this._table = table;\n\n this.table.addEventListener('focusin', this.onFocusin);\n this.table.addEventListener('focusout', this.onFocusout);\n this.table.addEventListener('keydown', this.onKeydown);\n\n const tableNodesObserver = new MutationObserver(this.onTableNodeMutation);\n tableNodesObserver.observe(table, { childList: true, subtree: true });\n\n updateTableFocusables(this.table, this.focusedCell ?? this.prevFocusedCell);\n\n this.cleanup = () => {\n this.table.removeEventListener('focusin', this.onFocusin);\n this.table.removeEventListener('focusout', this.onFocusout);\n this.table.removeEventListener('keydown', this.onKeydown);\n\n tableNodesObserver.disconnect();\n\n restoreTableFocusables(this.table);\n };\n }\n\n public destroy() {\n this.cleanup();\n }\n\n public update({ pageSize }: { pageSize: number }) {\n this._pageSize = pageSize;\n }\n\n private get pageSize() {\n return this._pageSize;\n }\n\n private get table(): HTMLTableElement {\n if (!this._table) {\n throw new Error('Invariant violation: GridNavigationModel is used before initialization.');\n }\n return this._table;\n }\n\n private onFocusin = (event: FocusEvent) => {\n const cell = findFocusinCell(event);\n\n if (!cell) {\n return;\n }\n\n if (cell.element !== event.target) {\n cell.element.focus();\n return;\n }\n\n this.prevFocusedCell = cell;\n this.focusedCell = cell;\n\n updateTableFocusables(this.table, cell);\n };\n\n private onFocusout = () => {\n this.focusedCell = null;\n };\n\n private onKeydown = (event: KeyboardEvent) => {\n if (!this.focusedCell) {\n return;\n }\n\n const ctrlKey = event.ctrlKey ? 1 : 0;\n const altKey = event.altKey ? 1 : 0;\n const shiftKey = event.shiftKey ? 1 : 0;\n const metaKey = event.metaKey ? 1 : 0;\n const numModifiersPressed = ctrlKey + altKey + shiftKey + metaKey;\n\n let key = event.keyCode;\n if (numModifiersPressed === 1 && event.ctrlKey) {\n key = -key;\n } else if (numModifiersPressed) {\n return;\n }\n\n const from = this.focusedCell;\n const minExtreme = Number.NEGATIVE_INFINITY;\n const maxExtreme = Number.POSITIVE_INFINITY;\n\n // When focus is inside a dialog do not intercept any keyboard input.\n if (from.dialog) {\n return;\n }\n\n switch (key) {\n case KeyCode.up:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: -1, x: 0 });\n\n case KeyCode.down:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 1, x: 0 });\n\n case KeyCode.left:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 0, x: -1 });\n\n case KeyCode.right:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 0, x: 1 });\n\n case KeyCode.pageUp:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: -this.pageSize, x: 0 });\n\n case KeyCode.pageDown:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: this.pageSize, x: 0 });\n\n case KeyCode.home:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 0, x: minExtreme });\n\n case KeyCode.end:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 0, x: maxExtreme });\n\n case -KeyCode.home:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: minExtreme, x: minExtreme });\n\n case -KeyCode.end:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: maxExtreme, x: maxExtreme });\n\n default:\n return;\n }\n };\n\n private onTableNodeMutation = (mutationRecords: MutationRecord[]) => {\n if (!this.prevFocusedCell) {\n return;\n }\n\n // When focused cell was un-mounted - re-apply focus to the same location.\n for (const record of mutationRecords) {\n if (record.type === 'childList') {\n for (const removedNode of Array.from(record.removedNodes)) {\n if (removedNode === this.prevFocusedCell.element || nodeContains(removedNode, this.prevFocusedCell.element)) {\n updateTableFocusables(this.table, this.focusedCell ?? this.prevFocusedCell);\n moveFocusBy(this.table, this.prevFocusedCell, { y: 0, x: 0 });\n }\n }\n }\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"use-grid-navigation.js","sourceRoot":"lib/default/","sources":["table/table-role/use-grid-navigation.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { useEffect, useMemo } from 'react';\nimport {\n defaultIsSuppressed,\n findFocusinCell,\n moveFocusBy,\n muteElementFocusables,\n restoreElementFocusables,\n ensureSingleFocusable,\n getFirstFocusable,\n} from './utils';\nimport { FocusedCell, GridNavigationProps } from './interfaces';\nimport { KeyCode } from '../../internal/keycode';\nimport { nodeContains } from '@cloudscape-design/component-toolkit/dom';\nimport { useStableCallback } from '@cloudscape-design/component-toolkit/internal';\n\n/**\n * Makes table navigable with keyboard commands.\n * See https://www.w3.org/WAI/ARIA/apg/patterns/grid\n *\n * The hook attaches the GridNavigationHelper helper when active=true.\n * See GridNavigationHelper for more details.\n */\nexport function useGridNavigation({ active, pageSize, getTable, isSuppressed }: GridNavigationProps) {\n const gridNavigation = useMemo(() => new GridNavigationHelper(), []);\n\n const getTableStable = useStableCallback(getTable);\n const isSuppressedStable = useStableCallback((element: HTMLElement) => isSuppressed?.(element) ?? false);\n\n // Initialize the model with the table container assuming it is mounted synchronously and only once.\n useEffect(() => {\n if (active) {\n const table = getTableStable();\n table && gridNavigation.init(table, isSuppressedStable);\n }\n return () => gridNavigation.cleanup();\n }, [active, gridNavigation, getTableStable, isSuppressedStable]);\n\n // Notify the model of the props change.\n useEffect(() => {\n gridNavigation.update({ pageSize });\n }, [gridNavigation, pageSize]);\n}\n\n/**\n * This helper encapsulates the grid navigation behaviors which are:\n * 1. Responding to keyboard commands and moving the focus accordingly;\n * 2. Muting table interactive elements for only one to be user-focusable at a time;\n * 3. Suppressing the above behaviors when focusing an element inside a dialog or when instructed by the isSuppressed callback.\n *\n * All behaviors are attached upon initialization and are re-evaluated with every focusin, focusout, and keydown events,\n * and also when a node removal inside the table is observed to ensure consistency at any given moment.\n *\n * When the navigation is suppressed the keyboard commands are no longer intercepted and all table interactive elements are made\n * user-focusable to unblock the Tab navigation. The suppression should only be used for interactive elements inside the table that would\n * otherwise conflict with the navigation. Once the interactive element is deactivated or lose focus the table navigation becomes active again.\n */\nclass GridNavigationHelper {\n // Props\n private _pageSize = 0;\n private _table: null | HTMLTableElement = null;\n private _isSuppressed: (focusedElement: HTMLElement) => boolean = () => false;\n\n // State\n private prevFocusedCell: null | FocusedCell = null;\n private focusedCell: null | FocusedCell = null;\n\n public init(table: HTMLTableElement, isSuppressed: (focusedElement: HTMLElement) => boolean) {\n this._table = table;\n this._isSuppressed = isSuppressed;\n\n this.table.addEventListener('focusin', this.onFocusin);\n this.table.addEventListener('focusout', this.onFocusout);\n this.table.addEventListener('keydown', this.onKeydown);\n\n const tableNodesObserver = new MutationObserver(this.onTableNodeMutation);\n tableNodesObserver.observe(table, { childList: true, subtree: true });\n\n muteElementFocusables(this.table, false);\n ensureSingleFocusable(this.table, null);\n\n this.cleanup = () => {\n this.table.removeEventListener('focusin', this.onFocusin);\n this.table.removeEventListener('focusout', this.onFocusout);\n this.table.removeEventListener('keydown', this.onKeydown);\n\n tableNodesObserver.disconnect();\n\n restoreElementFocusables(this.table);\n };\n }\n\n public cleanup() {\n // Do nothing before initialized.\n }\n\n public update({ pageSize }: { pageSize: number }) {\n this._pageSize = pageSize;\n }\n\n private get pageSize() {\n return this._pageSize;\n }\n\n private get table(): HTMLTableElement {\n if (!this._table) {\n throw new Error('Invariant violation: GridNavigationHelper is used before initialization.');\n }\n return this._table;\n }\n\n private isSuppressed(focusedElement: HTMLElement): boolean {\n return defaultIsSuppressed(focusedElement) || this._isSuppressed(focusedElement);\n }\n\n private onFocusin = (event: FocusEvent) => {\n const cell = findFocusinCell(event);\n if (!cell) {\n return;\n }\n\n this.prevFocusedCell = cell;\n this.focusedCell = cell;\n\n muteElementFocusables(this.table, this.isSuppressed(cell.element));\n ensureSingleFocusable(this.table, cell);\n\n // Focusing on cell is not eligible when it contains focusable elements in the content.\n // If content focusables are available - move the focus to the first one.\n if (cell.element === cell.cellElement) {\n getFirstFocusable(cell.cellElement)?.focus();\n }\n };\n\n private onFocusout = () => {\n this.focusedCell = null;\n };\n\n private onKeydown = (event: KeyboardEvent) => {\n if (!this.focusedCell) {\n return;\n }\n\n const ctrlKey = event.ctrlKey ? 1 : 0;\n const altKey = event.altKey ? 1 : 0;\n const shiftKey = event.shiftKey ? 1 : 0;\n const metaKey = event.metaKey ? 1 : 0;\n const numModifiersPressed = ctrlKey + altKey + shiftKey + metaKey;\n\n let key = event.keyCode;\n if (numModifiersPressed === 1 && event.ctrlKey) {\n key = -key;\n } else if (numModifiersPressed) {\n return;\n }\n\n const from = this.focusedCell;\n const minExtreme = Number.NEGATIVE_INFINITY;\n const maxExtreme = Number.POSITIVE_INFINITY;\n\n // Do not intercept any keys when the navigation is suppressed.\n if (this.isSuppressed(from.element)) {\n return;\n }\n\n switch (key) {\n case KeyCode.up:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: -1, x: 0 });\n\n case KeyCode.down:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 1, x: 0 });\n\n case KeyCode.left:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 0, x: -1 });\n\n case KeyCode.right:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 0, x: 1 });\n\n case KeyCode.pageUp:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: -this.pageSize, x: 0 });\n\n case KeyCode.pageDown:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: this.pageSize, x: 0 });\n\n case KeyCode.home:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 0, x: minExtreme });\n\n case KeyCode.end:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: 0, x: maxExtreme });\n\n case -KeyCode.home:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: minExtreme, x: minExtreme });\n\n case -KeyCode.end:\n event.preventDefault();\n return moveFocusBy(this.table, from, { y: maxExtreme, x: maxExtreme });\n\n default:\n return;\n }\n };\n\n private onTableNodeMutation = (mutationRecords: MutationRecord[]) => {\n // When focused cell is un-mounted the focusout event handler removes this.cell,\n // while this.prevFocusedCell is retained until the next focusin event.\n const cell = this.focusedCell ?? this.prevFocusedCell;\n const cellSuppressed = cell ? this.isSuppressed(cell.element) : false;\n\n // Update table elements focus if new nodes were added.\n if (mutationRecords.some(record => record.addedNodes.length > 0)) {\n muteElementFocusables(this.table, cellSuppressed);\n ensureSingleFocusable(this.table, cell);\n }\n\n if (cell) {\n for (const record of mutationRecords) {\n if (record.type === 'childList') {\n // The lost focus in an unmount event is reapplied to the table using the previous cell position.\n // The moveFocusBy takes care of finding the closest position if the previous one no longer exists.\n for (const removedNode of Array.from(record.removedNodes)) {\n if (removedNode === cell.element || nodeContains(removedNode, cell.element)) {\n ensureSingleFocusable(this.table, cell);\n moveFocusBy(this.table, cell, { y: 0, x: 0 });\n }\n }\n }\n }\n }\n };\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FocusedCell } from './interfaces';
|
|
2
2
|
/**
|
|
3
3
|
* Finds focused cell props corresponding the focused element inside the table.
|
|
4
|
-
* The function relies on ARIA colindex/rowindex attributes being
|
|
4
|
+
* The function relies on ARIA colindex/rowindex attributes being correctly applied.
|
|
5
5
|
*/
|
|
6
6
|
export declare function findFocusinCell(event: FocusEvent): null | FocusedCell;
|
|
7
7
|
/**
|
|
@@ -12,8 +12,26 @@ export declare function moveFocusBy(table: HTMLTableElement, from: FocusedCell,
|
|
|
12
12
|
x: number;
|
|
13
13
|
}): void;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Makes the cell element, the first interactive element or the first cell of the table user-focusable.
|
|
16
16
|
*/
|
|
17
|
-
export declare function
|
|
18
|
-
|
|
17
|
+
export declare function ensureSingleFocusable(table: HTMLElement, cell: null | FocusedCell): void;
|
|
18
|
+
/**
|
|
19
|
+
* Makes all element focusable children pseudo-focusable unless the grid navigation is suppressed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function muteElementFocusables(element: HTMLElement, suppressed: boolean): void;
|
|
22
|
+
/**
|
|
23
|
+
* This cleanup code ensures all cells are no longer focusable but the interactive elements are.
|
|
24
|
+
* Currently there are no use cases for it as we don't expect the navigation to be used conditionally.
|
|
25
|
+
*/
|
|
26
|
+
export declare function restoreElementFocusables(element: HTMLTableElement): void;
|
|
27
|
+
/**
|
|
28
|
+
* Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation attribute.
|
|
29
|
+
* This is used to suppress navigation for interactive content without a need to use a custom suppression check.
|
|
30
|
+
*/
|
|
31
|
+
export declare function defaultIsSuppressed(target: HTMLElement): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Returns actually focusable or pseudo-focusable elements to find navigation targets.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getFocusables(element: HTMLElement): HTMLElement[];
|
|
36
|
+
export declare function getFirstFocusable(element: HTMLElement): HTMLElement | null;
|
|
19
37
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAO3C;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,WAAW,CAuBrE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,QA4BtG;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,GAAG,WAAW,QAejF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,QAwB9E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,QAQjE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,WAiBtD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,iBAEjD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,sBAErD"}
|
|
@@ -4,101 +4,110 @@ import { getFocusables as getActualFocusables } from '../../internal/components/
|
|
|
4
4
|
// For the grid to have a single Tab stop all interactive element indices are updated to be -999.
|
|
5
5
|
// The elements having tab index -999 are eligible for keyboard navigation but not for Tab navigation.
|
|
6
6
|
const PSEUDO_FOCUSABLE_TAB_INDEX = -999;
|
|
7
|
+
const FOCUSABLES_SELECTOR = `[tabIndex="0"],[tabIndex="${PSEUDO_FOCUSABLE_TAB_INDEX}"]`;
|
|
7
8
|
/**
|
|
8
9
|
* Finds focused cell props corresponding the focused element inside the table.
|
|
9
|
-
* The function relies on ARIA colindex/rowindex attributes being
|
|
10
|
+
* The function relies on ARIA colindex/rowindex attributes being correctly applied.
|
|
10
11
|
*/
|
|
11
12
|
export function findFocusinCell(event) {
|
|
13
|
+
var _a, _b;
|
|
12
14
|
if (!(event.target instanceof HTMLElement)) {
|
|
13
15
|
return null;
|
|
14
16
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
const colIndex = parseInt((_a = cellElement.getAttribute('aria-colindex')) !== null && _a !== void 0 ? _a : '');
|
|
23
|
-
const rowIndex = parseInt((_b = rowElement.getAttribute('aria-rowindex')) !== null && _b !== void 0 ? _b : '');
|
|
24
|
-
if (isNaN(colIndex) || isNaN(rowIndex)) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
const cellFocusables = getFocusables(cellElement);
|
|
28
|
-
const elementIndex = cellFocusables.indexOf(element);
|
|
29
|
-
const dialog = isDialogElement(element);
|
|
30
|
-
// Focusing on the cell is not eligible when it contains focusable targets.
|
|
31
|
-
if (cellFocusables.length > 0 && elementIndex === -1) {
|
|
32
|
-
return focusOnElement(cellFocusables[0]);
|
|
33
|
-
}
|
|
34
|
-
return { rowIndex, colIndex, rowElement, cellElement, element, elementIndex, dialog };
|
|
17
|
+
const element = event.target;
|
|
18
|
+
const cellElement = element.closest('td,th');
|
|
19
|
+
const rowElement = cellElement === null || cellElement === void 0 ? void 0 : cellElement.closest('tr');
|
|
20
|
+
if (!cellElement || !rowElement) {
|
|
21
|
+
return null;
|
|
35
22
|
}
|
|
36
|
-
|
|
23
|
+
const colIndex = parseInt((_a = cellElement.getAttribute('aria-colindex')) !== null && _a !== void 0 ? _a : '');
|
|
24
|
+
const rowIndex = parseInt((_b = rowElement.getAttribute('aria-rowindex')) !== null && _b !== void 0 ? _b : '');
|
|
25
|
+
if (isNaN(colIndex) || isNaN(rowIndex)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const cellFocusables = getFocusables(cellElement);
|
|
29
|
+
const elementIndex = cellFocusables.indexOf(element);
|
|
30
|
+
return { rowIndex, colIndex, rowElement, cellElement, element, elementIndex };
|
|
37
31
|
}
|
|
38
32
|
/**
|
|
39
33
|
* Moves table focus in the provided direction. The focus can transition between cells or interactive elements inside cells.
|
|
40
34
|
*/
|
|
41
35
|
export function moveFocusBy(table, from, delta) {
|
|
42
36
|
var _a;
|
|
37
|
+
// Find next row to move focus into (can be null if the top/bottom is reached).
|
|
43
38
|
const targetAriaRowIndex = from.rowIndex + delta.y;
|
|
44
39
|
const targetRow = findTableRowByAriaRowIndex(table, targetAriaRowIndex, delta.y);
|
|
45
40
|
if (!targetRow) {
|
|
46
41
|
return;
|
|
47
42
|
}
|
|
48
|
-
// Move focus to the next interactive cell content element if
|
|
43
|
+
// Move focus to the next interactive cell content element if available.
|
|
49
44
|
const cellFocusables = getFocusables(from.cellElement);
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
focus(cellFocusables[targetElementIndex]);
|
|
45
|
+
const nextElementIndex = from.elementIndex + delta.x;
|
|
46
|
+
if (delta.x && from.elementIndex !== -1 && 0 <= nextElementIndex && nextElementIndex < cellFocusables.length) {
|
|
47
|
+
focus(cellFocusables[nextElementIndex]);
|
|
54
48
|
return;
|
|
55
49
|
}
|
|
56
|
-
// Find next cell
|
|
50
|
+
// Find next cell to focus or move focus into (can be null if the left/right edge is reached).
|
|
57
51
|
const targetAriaColIndex = from.colIndex + delta.x;
|
|
58
52
|
const targetCell = findTableRowCellByAriaColIndex(targetRow, targetAriaColIndex, delta.x);
|
|
59
53
|
if (!targetCell) {
|
|
60
54
|
return;
|
|
61
55
|
}
|
|
62
|
-
//
|
|
56
|
+
// Move focus on the cell interactive content or the cell itself.
|
|
63
57
|
const targetCellFocusables = getFocusables(targetCell);
|
|
64
58
|
const focusIndex = delta.x < 0 ? targetCellFocusables.length - 1 : delta.x > 0 ? 0 : from.elementIndex;
|
|
65
59
|
const focusTarget = (_a = targetCellFocusables[focusIndex]) !== null && _a !== void 0 ? _a : targetCell;
|
|
66
60
|
focus(focusTarget);
|
|
67
61
|
}
|
|
68
62
|
/**
|
|
69
|
-
*
|
|
63
|
+
* Makes the cell element, the first interactive element or the first cell of the table user-focusable.
|
|
70
64
|
*/
|
|
71
|
-
export function
|
|
65
|
+
export function ensureSingleFocusable(table, cell) {
|
|
72
66
|
var _a;
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
67
|
+
const firstTableCell = table.querySelector('td,th');
|
|
68
|
+
// A single element of the table is made user-focusable.
|
|
69
|
+
// It defaults to the first interactive element of the first cell or the first cell itself otherwise.
|
|
70
|
+
let focusTarget = (_a = (firstTableCell && getFocusables(firstTableCell)[0])) !== null && _a !== void 0 ? _a : firstTableCell;
|
|
71
|
+
// When a navigation-focused element is present in the table it is used for user-navigation instead.
|
|
72
|
+
if (cell && table.contains(cell.element)) {
|
|
73
|
+
focusTarget = cell.element;
|
|
74
|
+
}
|
|
75
|
+
if (focusTarget) {
|
|
76
|
+
focusTarget.tabIndex = 0;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Makes all element focusable children pseudo-focusable unless the grid navigation is suppressed.
|
|
81
|
+
*/
|
|
82
|
+
export function muteElementFocusables(element, suppressed) {
|
|
83
|
+
// When grid navigation is suppressed all interactive elements and all cells focus is unmuted to unblock Tab navigation.
|
|
84
|
+
// Leaving the interactive widget using Tab navigation moves the focus to the current or adjacent cell and un-suppresses
|
|
85
|
+
// the navigation when implemented correctly.
|
|
86
|
+
if (suppressed) {
|
|
87
|
+
for (const focusable of getFocusables(element)) {
|
|
77
88
|
focusable.tabIndex = 0;
|
|
78
89
|
}
|
|
79
90
|
return;
|
|
80
91
|
}
|
|
81
|
-
const tableCells =
|
|
92
|
+
const tableCells = queryTableCells(element);
|
|
93
|
+
// Assigning pseudo-focusable tab index to all cells and all interactive elements makes them focusable with grid navigation.
|
|
82
94
|
for (const cell of tableCells) {
|
|
83
|
-
cell.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
focusable.tabIndex = PSEUDO_FOCUSABLE_TAB_INDEX;
|
|
87
|
-
}
|
|
88
|
-
// The only focusable element of the table.
|
|
89
|
-
let focusTarget = tableCells[0];
|
|
90
|
-
if (cell && table.contains(cell.element)) {
|
|
91
|
-
focusTarget = cell.element;
|
|
92
|
-
}
|
|
93
|
-
else if (tableCells.length > 0) {
|
|
94
|
-
focusTarget = (_a = getFocusables(tableCells[0])[0]) !== null && _a !== void 0 ? _a : focusTarget;
|
|
95
|
+
if (cell !== document.activeElement) {
|
|
96
|
+
cell.tabIndex = PSEUDO_FOCUSABLE_TAB_INDEX;
|
|
97
|
+
}
|
|
95
98
|
}
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
for (const focusable of getActualFocusables(element)) {
|
|
100
|
+
if (focusable !== document.activeElement) {
|
|
101
|
+
focusable.tabIndex = PSEUDO_FOCUSABLE_TAB_INDEX;
|
|
102
|
+
}
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
/**
|
|
106
|
+
* This cleanup code ensures all cells are no longer focusable but the interactive elements are.
|
|
107
|
+
* Currently there are no use cases for it as we don't expect the navigation to be used conditionally.
|
|
108
|
+
*/
|
|
109
|
+
export function restoreElementFocusables(element) {
|
|
110
|
+
for (const focusable of getFocusables(element)) {
|
|
102
111
|
if (focusable instanceof HTMLTableCellElement) {
|
|
103
112
|
focusable.tabIndex = -1;
|
|
104
113
|
}
|
|
@@ -108,12 +117,13 @@ export function restoreTableFocusables(table) {
|
|
|
108
117
|
}
|
|
109
118
|
}
|
|
110
119
|
/**
|
|
111
|
-
* Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation.
|
|
112
|
-
*
|
|
120
|
+
* Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation attribute.
|
|
121
|
+
* This is used to suppress navigation for interactive content without a need to use a custom suppression check.
|
|
113
122
|
*/
|
|
114
|
-
function
|
|
123
|
+
export function defaultIsSuppressed(target) {
|
|
115
124
|
let current = target;
|
|
116
125
|
while (current) {
|
|
126
|
+
// Stop checking for parents upon reaching the cell element as the function only aims at the cell content.
|
|
117
127
|
const tagName = current.tagName.toLowerCase();
|
|
118
128
|
if (tagName === 'td' || tagName === 'th') {
|
|
119
129
|
return false;
|
|
@@ -126,9 +136,18 @@ function isDialogElement(target) {
|
|
|
126
136
|
}
|
|
127
137
|
return false;
|
|
128
138
|
}
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Returns actually focusable or pseudo-focusable elements to find navigation targets.
|
|
141
|
+
*/
|
|
142
|
+
export function getFocusables(element) {
|
|
143
|
+
return Array.from(element.querySelectorAll(FOCUSABLES_SELECTOR));
|
|
144
|
+
}
|
|
145
|
+
export function getFirstFocusable(element) {
|
|
146
|
+
return element.querySelector(FOCUSABLES_SELECTOR);
|
|
131
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Finds the closest row to the targetAriaRowIndex+delta in the direction of delta.
|
|
150
|
+
*/
|
|
132
151
|
function findTableRowByAriaRowIndex(table, targetAriaRowIndex, delta) {
|
|
133
152
|
var _a;
|
|
134
153
|
let targetRow = null;
|
|
@@ -151,6 +170,9 @@ function findTableRowByAriaRowIndex(table, targetAriaRowIndex, delta) {
|
|
|
151
170
|
}
|
|
152
171
|
return targetRow;
|
|
153
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Finds the closest column to the targetAriaColIndex+delta in the direction of delta.
|
|
175
|
+
*/
|
|
154
176
|
function findTableRowCellByAriaColIndex(tableRow, targetAriaColIndex, delta) {
|
|
155
177
|
var _a;
|
|
156
178
|
let targetCell = null;
|
|
@@ -179,4 +201,11 @@ function focus(element) {
|
|
|
179
201
|
element.focus();
|
|
180
202
|
}
|
|
181
203
|
}
|
|
204
|
+
function queryTableCells(element) {
|
|
205
|
+
const tableCells = Array.from(element.querySelectorAll('td,th'));
|
|
206
|
+
if (element instanceof HTMLTableCellElement) {
|
|
207
|
+
tableCells.push(element);
|
|
208
|
+
}
|
|
209
|
+
return tableCells;
|
|
210
|
+
}
|
|
182
211
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { getFocusables as getActualFocusables } from '../../internal/components/focus-lock/utils';\nimport { FocusedCell } from './interfaces';\n\n// For the grid to have a single Tab stop all interactive element indices are updated to be -999.\n// The elements having tab index -999 are eligible for keyboard navigation but not for Tab navigation.\nconst PSEUDO_FOCUSABLE_TAB_INDEX = -999;\n\n/**\n * Finds focused cell props corresponding the focused element inside the table.\n * The function relies on ARIA colindex/rowindex attributes being set.\n */\nexport function findFocusinCell(event: FocusEvent): null | FocusedCell {\n if (!(event.target instanceof HTMLElement)) {\n return null;\n }\n\n function focusOnElement(element: HTMLElement): null | FocusedCell {\n const cellElement = element.closest('td,th') as null | HTMLTableCellElement;\n const rowElement = cellElement?.closest('tr');\n\n if (!cellElement || !rowElement) {\n return null;\n }\n\n const colIndex = parseInt(cellElement.getAttribute('aria-colindex') ?? '');\n const rowIndex = parseInt(rowElement.getAttribute('aria-rowindex') ?? '');\n if (isNaN(colIndex) || isNaN(rowIndex)) {\n return null;\n }\n\n const cellFocusables = getFocusables(cellElement);\n const elementIndex = cellFocusables.indexOf(element);\n const dialog = isDialogElement(element);\n\n // Focusing on the cell is not eligible when it contains focusable targets.\n if (cellFocusables.length > 0 && elementIndex === -1) {\n return focusOnElement(cellFocusables[0]);\n }\n\n return { rowIndex, colIndex, rowElement, cellElement, element, elementIndex, dialog };\n }\n\n return focusOnElement(event.target);\n}\n\n/**\n * Moves table focus in the provided direction. The focus can transition between cells or interactive elements inside cells.\n */\nexport function moveFocusBy(table: HTMLTableElement, from: FocusedCell, delta: { y: number; x: number }) {\n const targetAriaRowIndex = from.rowIndex + delta.y;\n const targetRow = findTableRowByAriaRowIndex(table, targetAriaRowIndex, delta.y);\n if (!targetRow) {\n return;\n }\n\n // Move focus to the next interactive cell content element if eligible.\n const cellFocusables = getFocusables(from.cellElement);\n const eligibleForElementFocus = delta.x && cellFocusables.length > 0;\n const targetElementIndex = from.elementIndex === -1 ? -1 : from.elementIndex + delta.x;\n if (eligibleForElementFocus && 0 <= targetElementIndex && targetElementIndex < cellFocusables.length) {\n focus(cellFocusables[targetElementIndex]);\n return;\n }\n\n // Find next cell target to focus on.\n const targetAriaColIndex = from.colIndex + delta.x;\n const targetCell = findTableRowCellByAriaColIndex(targetRow, targetAriaColIndex, delta.x);\n if (!targetCell) {\n return;\n }\n\n // Focus on cell interactive content element if available or on the cell itself otherwise.\n const targetCellFocusables = getFocusables(targetCell);\n const focusIndex = delta.x < 0 ? targetCellFocusables.length - 1 : delta.x > 0 ? 0 : from.elementIndex;\n const focusTarget = targetCellFocusables[focusIndex] ?? targetCell;\n focus(focusTarget);\n}\n\n/**\n * Overrides focusability of the table elements to make focus targets controllable with keyboard commands.\n */\nexport function updateTableFocusables(table: HTMLTableElement, cell: null | FocusedCell) {\n // Restore default focus behavior and make all cells focusable when focus in on a dialog element.\n // This allows existing the dialog cell with Tab or Shift+Tab.\n if (cell && cell.dialog) {\n for (const focusable of getFocusables(table)) {\n focusable.tabIndex = 0;\n }\n return;\n }\n\n const tableCells = Array.from(table.querySelectorAll('td,th') as NodeListOf<HTMLTableCellElement>);\n\n for (const cell of tableCells) {\n cell.tabIndex = PSEUDO_FOCUSABLE_TAB_INDEX;\n }\n for (const focusable of getActualFocusables(table)) {\n focusable.tabIndex = PSEUDO_FOCUSABLE_TAB_INDEX;\n }\n\n // The only focusable element of the table.\n let focusTarget: undefined | HTMLElement = tableCells[0];\n\n if (cell && table.contains(cell.element)) {\n focusTarget = cell.element;\n } else if (tableCells.length > 0) {\n focusTarget = getFocusables(tableCells[0])[0] ?? focusTarget;\n }\n if (focusTarget) {\n focusTarget.tabIndex = 0;\n }\n}\n\nexport function restoreTableFocusables(table: HTMLTableElement) {\n for (const focusable of getFocusables(table)) {\n if (focusable instanceof HTMLTableCellElement) {\n focusable.tabIndex = -1;\n } else {\n focusable.tabIndex = 0;\n }\n }\n}\n\n/**\n * Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation.\n * For dialog cells when in focus the tab indices are not overridden and keyboard events are not intercepted.\n */\nfunction isDialogElement(target: HTMLElement) {\n let current: null | HTMLElement = target;\n while (current) {\n const tagName = current.tagName.toLowerCase();\n if (tagName === 'td' || tagName === 'th') {\n return false;\n }\n if (\n current.getAttribute('role') === 'dialog' ||\n current.getAttribute('data-awsui-table-suppress-navigation') === 'true'\n ) {\n return true;\n }\n current = current.parentElement;\n }\n return false;\n}\n\nfunction getFocusables(element: HTMLElement) {\n return Array.from(\n element.querySelectorAll(`[tabIndex=\"0\"],[tabIndex=\"${PSEUDO_FOCUSABLE_TAB_INDEX}\"]`)\n ) as HTMLElement[];\n}\n\nfunction findTableRowByAriaRowIndex(table: HTMLTableElement, targetAriaRowIndex: number, delta: number) {\n let targetRow: null | HTMLTableRowElement = null;\n const rowElements = Array.from(table.querySelectorAll('tr[aria-rowindex]'));\n if (delta < 0) {\n rowElements.reverse();\n }\n for (const element of rowElements) {\n const rowIndex = parseInt(element.getAttribute('aria-rowindex') ?? '');\n targetRow = element as HTMLTableRowElement;\n\n if (rowIndex === targetAriaRowIndex) {\n break;\n }\n if (delta >= 0 && rowIndex > targetAriaRowIndex) {\n break;\n }\n if (delta < 0 && rowIndex < targetAriaRowIndex) {\n break;\n }\n }\n return targetRow;\n}\n\nfunction findTableRowCellByAriaColIndex(tableRow: HTMLTableRowElement, targetAriaColIndex: number, delta: number) {\n let targetCell: null | HTMLTableCellElement = null;\n const cellElements = Array.from(tableRow.querySelectorAll('td[aria-colindex],th[aria-colindex]'));\n if (delta < 0) {\n cellElements.reverse();\n }\n for (const element of cellElements) {\n const columnIndex = parseInt(element.getAttribute('aria-colindex') ?? '');\n targetCell = element as HTMLTableCellElement;\n\n if (columnIndex === targetAriaColIndex) {\n break;\n }\n if (delta >= 0 && columnIndex > targetAriaColIndex) {\n break;\n }\n if (delta < 0 && columnIndex < targetAriaColIndex) {\n break;\n }\n }\n return targetCell;\n}\n\nfunction focus(element: null | HTMLElement) {\n if (element) {\n element.tabIndex = 0;\n element.focus();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { getFocusables as getActualFocusables } from '../../internal/components/focus-lock/utils';\nimport { FocusedCell } from './interfaces';\n\n// For the grid to have a single Tab stop all interactive element indices are updated to be -999.\n// The elements having tab index -999 are eligible for keyboard navigation but not for Tab navigation.\nconst PSEUDO_FOCUSABLE_TAB_INDEX = -999;\nconst FOCUSABLES_SELECTOR = `[tabIndex=\"0\"],[tabIndex=\"${PSEUDO_FOCUSABLE_TAB_INDEX}\"]`;\n\n/**\n * Finds focused cell props corresponding the focused element inside the table.\n * The function relies on ARIA colindex/rowindex attributes being correctly applied.\n */\nexport function findFocusinCell(event: FocusEvent): null | FocusedCell {\n if (!(event.target instanceof HTMLElement)) {\n return null;\n }\n const element = event.target;\n\n const cellElement = element.closest('td,th') as null | HTMLTableCellElement;\n const rowElement = cellElement?.closest('tr');\n\n if (!cellElement || !rowElement) {\n return null;\n }\n\n const colIndex = parseInt(cellElement.getAttribute('aria-colindex') ?? '');\n const rowIndex = parseInt(rowElement.getAttribute('aria-rowindex') ?? '');\n if (isNaN(colIndex) || isNaN(rowIndex)) {\n return null;\n }\n\n const cellFocusables = getFocusables(cellElement);\n const elementIndex = cellFocusables.indexOf(element);\n\n return { rowIndex, colIndex, rowElement, cellElement, element, elementIndex };\n}\n\n/**\n * Moves table focus in the provided direction. The focus can transition between cells or interactive elements inside cells.\n */\nexport function moveFocusBy(table: HTMLTableElement, from: FocusedCell, delta: { y: number; x: number }) {\n // Find next row to move focus into (can be null if the top/bottom is reached).\n const targetAriaRowIndex = from.rowIndex + delta.y;\n const targetRow = findTableRowByAriaRowIndex(table, targetAriaRowIndex, delta.y);\n if (!targetRow) {\n return;\n }\n\n // Move focus to the next interactive cell content element if available.\n const cellFocusables = getFocusables(from.cellElement);\n const nextElementIndex = from.elementIndex + delta.x;\n if (delta.x && from.elementIndex !== -1 && 0 <= nextElementIndex && nextElementIndex < cellFocusables.length) {\n focus(cellFocusables[nextElementIndex]);\n return;\n }\n\n // Find next cell to focus or move focus into (can be null if the left/right edge is reached).\n const targetAriaColIndex = from.colIndex + delta.x;\n const targetCell = findTableRowCellByAriaColIndex(targetRow, targetAriaColIndex, delta.x);\n if (!targetCell) {\n return;\n }\n\n // Move focus on the cell interactive content or the cell itself.\n const targetCellFocusables = getFocusables(targetCell);\n const focusIndex = delta.x < 0 ? targetCellFocusables.length - 1 : delta.x > 0 ? 0 : from.elementIndex;\n const focusTarget = targetCellFocusables[focusIndex] ?? targetCell;\n focus(focusTarget);\n}\n\n/**\n * Makes the cell element, the first interactive element or the first cell of the table user-focusable.\n */\nexport function ensureSingleFocusable(table: HTMLElement, cell: null | FocusedCell) {\n const firstTableCell = table.querySelector('td,th') as null | HTMLTableCellElement;\n\n // A single element of the table is made user-focusable.\n // It defaults to the first interactive element of the first cell or the first cell itself otherwise.\n let focusTarget: null | HTMLElement = (firstTableCell && getFocusables(firstTableCell)[0]) ?? firstTableCell;\n\n // When a navigation-focused element is present in the table it is used for user-navigation instead.\n if (cell && table.contains(cell.element)) {\n focusTarget = cell.element;\n }\n\n if (focusTarget) {\n focusTarget.tabIndex = 0;\n }\n}\n\n/**\n * Makes all element focusable children pseudo-focusable unless the grid navigation is suppressed.\n */\nexport function muteElementFocusables(element: HTMLElement, suppressed: boolean) {\n // When grid navigation is suppressed all interactive elements and all cells focus is unmuted to unblock Tab navigation.\n // Leaving the interactive widget using Tab navigation moves the focus to the current or adjacent cell and un-suppresses\n // the navigation when implemented correctly.\n if (suppressed) {\n for (const focusable of getFocusables(element)) {\n focusable.tabIndex = 0;\n }\n return;\n }\n\n const tableCells = queryTableCells(element);\n\n // Assigning pseudo-focusable tab index to all cells and all interactive elements makes them focusable with grid navigation.\n for (const cell of tableCells) {\n if (cell !== document.activeElement) {\n cell.tabIndex = PSEUDO_FOCUSABLE_TAB_INDEX;\n }\n }\n for (const focusable of getActualFocusables(element)) {\n if (focusable !== document.activeElement) {\n focusable.tabIndex = PSEUDO_FOCUSABLE_TAB_INDEX;\n }\n }\n}\n\n/**\n * This cleanup code ensures all cells are no longer focusable but the interactive elements are.\n * Currently there are no use cases for it as we don't expect the navigation to be used conditionally.\n */\nexport function restoreElementFocusables(element: HTMLTableElement) {\n for (const focusable of getFocusables(element)) {\n if (focusable instanceof HTMLTableCellElement) {\n focusable.tabIndex = -1;\n } else {\n focusable.tabIndex = 0;\n }\n }\n}\n\n/**\n * Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation attribute.\n * This is used to suppress navigation for interactive content without a need to use a custom suppression check.\n */\nexport function defaultIsSuppressed(target: HTMLElement) {\n let current: null | HTMLElement = target;\n while (current) {\n // Stop checking for parents upon reaching the cell element as the function only aims at the cell content.\n const tagName = current.tagName.toLowerCase();\n if (tagName === 'td' || tagName === 'th') {\n return false;\n }\n if (\n current.getAttribute('role') === 'dialog' ||\n current.getAttribute('data-awsui-table-suppress-navigation') === 'true'\n ) {\n return true;\n }\n current = current.parentElement;\n }\n return false;\n}\n\n/**\n * Returns actually focusable or pseudo-focusable elements to find navigation targets.\n */\nexport function getFocusables(element: HTMLElement) {\n return Array.from(element.querySelectorAll(FOCUSABLES_SELECTOR)) as HTMLElement[];\n}\n\nexport function getFirstFocusable(element: HTMLElement) {\n return element.querySelector(FOCUSABLES_SELECTOR) as null | HTMLElement;\n}\n\n/**\n * Finds the closest row to the targetAriaRowIndex+delta in the direction of delta.\n */\nfunction findTableRowByAriaRowIndex(table: HTMLTableElement, targetAriaRowIndex: number, delta: number) {\n let targetRow: null | HTMLTableRowElement = null;\n const rowElements = Array.from(table.querySelectorAll('tr[aria-rowindex]'));\n if (delta < 0) {\n rowElements.reverse();\n }\n for (const element of rowElements) {\n const rowIndex = parseInt(element.getAttribute('aria-rowindex') ?? '');\n targetRow = element as HTMLTableRowElement;\n\n if (rowIndex === targetAriaRowIndex) {\n break;\n }\n if (delta >= 0 && rowIndex > targetAriaRowIndex) {\n break;\n }\n if (delta < 0 && rowIndex < targetAriaRowIndex) {\n break;\n }\n }\n return targetRow;\n}\n\n/**\n * Finds the closest column to the targetAriaColIndex+delta in the direction of delta.\n */\nfunction findTableRowCellByAriaColIndex(tableRow: HTMLTableRowElement, targetAriaColIndex: number, delta: number) {\n let targetCell: null | HTMLTableCellElement = null;\n const cellElements = Array.from(tableRow.querySelectorAll('td[aria-colindex],th[aria-colindex]'));\n if (delta < 0) {\n cellElements.reverse();\n }\n for (const element of cellElements) {\n const columnIndex = parseInt(element.getAttribute('aria-colindex') ?? '');\n targetCell = element as HTMLTableCellElement;\n\n if (columnIndex === targetAriaColIndex) {\n break;\n }\n if (delta >= 0 && columnIndex > targetAriaColIndex) {\n break;\n }\n if (delta < 0 && columnIndex < targetAriaColIndex) {\n break;\n }\n }\n return targetCell;\n}\n\nfunction focus(element: null | HTMLElement) {\n if (element) {\n element.tabIndex = 0;\n element.focus();\n }\n}\n\nfunction queryTableCells(element: HTMLElement) {\n const tableCells = Array.from(element.querySelectorAll('td,th') as NodeListOf<HTMLTableCellElement>);\n if (element instanceof HTMLTableCellElement) {\n tableCells.push(element);\n }\n\n return tableCells;\n}\n"]}
|