@cloudscape-design/components 3.0.495 → 3.0.496
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/internal/components/focus-lock/utils.d.ts +1 -0
- package/internal/components/focus-lock/utils.d.ts.map +1 -1
- package/internal/components/focus-lock/utils.js +4 -3
- package/internal/components/focus-lock/utils.js.map +1 -1
- package/internal/context/single-tab-stop-navigation-context.d.ts +9 -4
- package/internal/context/single-tab-stop-navigation-context.d.ts.map +1 -1
- package/internal/context/single-tab-stop-navigation-context.js +15 -5
- package/internal/context/single-tab-stop-navigation-context.js.map +1 -1
- package/internal/environment.js +1 -1
- package/internal/environment.json +1 -1
- package/internal/manifest.json +1 -1
- package/internal/utils/scrollable-containers.d.ts +2 -1
- package/internal/utils/scrollable-containers.d.ts.map +1 -1
- package/internal/utils/scrollable-containers.js +11 -2
- package/internal/utils/scrollable-containers.js.map +1 -1
- package/package.json +1 -1
- package/popover/use-popover-position.d.ts.map +1 -1
- package/popover/use-popover-position.js +4 -2
- package/popover/use-popover-position.js.map +1 -1
- package/table/table-role/grid-navigation.d.ts.map +1 -1
- package/table/table-role/grid-navigation.js +73 -41
- package/table/table-role/grid-navigation.js.map +1 -1
- package/table/table-role/utils.d.ts +1 -16
- package/table/table-role/utils.d.ts.map +1 -1
- package/table/table-role/utils.js +0 -53
- package/table/table-role/utils.js.map +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare function getAllFocusables(container: HTMLElement): HTMLElement[];
|
|
1
2
|
export declare function getFocusables(container: HTMLElement): HTMLElement[];
|
|
2
3
|
export declare function getFirstFocusable(container: HTMLElement): null | HTMLElement;
|
|
3
4
|
export declare function getLastFocusable(container: HTMLElement): null | HTMLElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"lib/default/","sources":["internal/components/focus-lock/utils.ts"],"names":[],"mappings":"AA2BA,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"lib/default/","sources":["internal/components/focus-lock/utils.ts"],"names":[],"mappings":"AA2BA,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,EAAE,CAEtE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,EAAE,CAEnE;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,GAAG,WAAW,CAG5E;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,GAAG,WAAW,CAG3E"}
|
|
@@ -19,10 +19,11 @@ const tabbables = [
|
|
|
19
19
|
'[contenteditable]',
|
|
20
20
|
'[autofocus]',
|
|
21
21
|
].join(',');
|
|
22
|
+
export function getAllFocusables(container) {
|
|
23
|
+
return Array.prototype.slice.call(container.querySelectorAll(tabbables));
|
|
24
|
+
}
|
|
22
25
|
export function getFocusables(container) {
|
|
23
|
-
return
|
|
24
|
-
.call(container.querySelectorAll(tabbables))
|
|
25
|
-
.filter((element) => element.tabIndex !== -1);
|
|
26
|
+
return getAllFocusables(container).filter((element) => element.tabIndex !== -1);
|
|
26
27
|
}
|
|
27
28
|
export function getFirstFocusable(container) {
|
|
28
29
|
var _a;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"lib/default/","sources":["internal/components/focus-lock/utils.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC,aAAa;AACb,+GAA+G;AAC/G,MAAM,SAAS,GAAG;IAChB,gBAAgB;IAChB,gBAAgB;IAChB,kBAAkB;IAClB,eAAe;IAEf,SAAS;IACT,YAAY;IAEZ,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,OAAO;IAEP,iBAAiB;IACjB,iBAAiB;IAEjB,YAAY;IACZ,mBAAmB;IACnB,aAAa;CACd,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"lib/default/","sources":["internal/components/focus-lock/utils.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC,aAAa;AACb,+GAA+G;AAC/G,MAAM,SAAS,GAAG;IAChB,gBAAgB;IAChB,gBAAgB;IAChB,kBAAkB;IAClB,eAAe;IAEf,SAAS;IACT,YAAY;IAEZ,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,OAAO;IAEP,iBAAiB;IACjB,iBAAiB;IAEjB,YAAY;IACZ,mBAAmB;IACnB,aAAa;CACd,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,UAAU,gBAAgB,CAAC,SAAsB;IACrD,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAAsB;IAClD,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,OAAoB,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAsB;;IACtD,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC5C,OAAO,MAAA,UAAU,CAAC,CAAC,CAAC,mCAAI,IAAI,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAsB;;IACrD,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC5C,OAAO,MAAA,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,mCAAI,IAAI,CAAC;AACnD,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n// Credits to\n// https://github.com/theKashey/focus-lock/blob/33f8b4bd9675d2605b15e2e4015b77fe35fbd6d0/src/utils/tabbables.ts\nconst tabbables = [\n 'button:enabled',\n 'select:enabled',\n 'textarea:enabled',\n 'input:enabled',\n\n 'a[href]',\n 'area[href]',\n\n 'summary',\n 'iframe',\n 'object',\n 'embed',\n\n 'audio[controls]',\n 'video[controls]',\n\n '[tabindex]',\n '[contenteditable]',\n '[autofocus]',\n].join(',');\n\nexport function getAllFocusables(container: HTMLElement): HTMLElement[] {\n return Array.prototype.slice.call(container.querySelectorAll(tabbables));\n}\n\nexport function getFocusables(container: HTMLElement): HTMLElement[] {\n return getAllFocusables(container).filter((element: HTMLElement) => element.tabIndex !== -1);\n}\n\nexport function getFirstFocusable(container: HTMLElement): null | HTMLElement {\n const focusables = getFocusables(container);\n return focusables[0] ?? null;\n}\n\nexport function getLastFocusable(container: HTMLElement): null | HTMLElement {\n const focusables = getFocusables(container);\n return focusables[focusables.length - 1] ?? null;\n}\n"]}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type FocusableDefinition = React.RefObject<Element>;
|
|
3
|
+
export type FocusableChangeHandler = (focusTarget: null | Element, suppressed: boolean) => void;
|
|
4
|
+
export interface SingleTabStopNavigationOptions {
|
|
5
|
+
tabIndex?: number;
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
8
|
* Single tab stop navigation context is used together with keyboard navigation that requires a single tab stop.
|
|
4
9
|
* It instructs interactive elements to override tab indices for just a single one to remain user-focusable.
|
|
5
10
|
*/
|
|
6
|
-
export declare const SingleTabStopNavigationContext:
|
|
7
|
-
focusTarget: null | Element;
|
|
11
|
+
export declare const SingleTabStopNavigationContext: React.Context<{
|
|
8
12
|
navigationActive: boolean;
|
|
13
|
+
registerFocusable(focusable: FocusableDefinition, handler: FocusableChangeHandler): () => void;
|
|
9
14
|
}>;
|
|
10
|
-
export declare function useSingleTabStopNavigation(focusable: null |
|
|
15
|
+
export declare function useSingleTabStopNavigation(focusable: null | FocusableDefinition, options?: {
|
|
11
16
|
tabIndex?: number;
|
|
12
17
|
}): {
|
|
13
18
|
navigationActive: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-tab-stop-navigation-context.d.ts","sourceRoot":"lib/default/","sources":["internal/context/single-tab-stop-navigation-context.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"single-tab-stop-navigation-context.d.ts","sourceRoot":"lib/default/","sources":["internal/context/single-tab-stop-navigation-context.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAE3F,MAAM,MAAM,mBAAmB,GAAG,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AAE3D,MAAM,MAAM,sBAAsB,GAAG,CAAC,WAAW,EAAE,IAAI,GAAG,OAAO,EAAE,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;AAEhG,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,8BAA8B;sBACvB,OAAO;+DACkC,sBAAsB,GAAG,MAAM,IAAI;EAI9F,CAAC;AAEH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,IAAI,GAAG,mBAAmB,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;;;EA2BhH"}
|
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { createContext, useContext } from 'react';
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
|
4
4
|
/**
|
|
5
5
|
* Single tab stop navigation context is used together with keyboard navigation that requires a single tab stop.
|
|
6
6
|
* It instructs interactive elements to override tab indices for just a single one to remain user-focusable.
|
|
7
7
|
*/
|
|
8
8
|
export const SingleTabStopNavigationContext = createContext({
|
|
9
|
-
focusTarget: null,
|
|
10
9
|
navigationActive: false,
|
|
10
|
+
registerFocusable: () => () => { },
|
|
11
11
|
});
|
|
12
12
|
export function useSingleTabStopNavigation(focusable, options) {
|
|
13
|
-
|
|
14
|
-
const
|
|
13
|
+
var _a;
|
|
14
|
+
const { navigationActive: contextNavigationActive, registerFocusable: contextRegisterFocusable } = useContext(SingleTabStopNavigationContext);
|
|
15
|
+
const [focusTargetActive, setFocusTargetActive] = useState(false);
|
|
16
|
+
const navigationActive = contextNavigationActive && (!(options === null || options === void 0 ? void 0 : options.tabIndex) || (options === null || options === void 0 ? void 0 : options.tabIndex) >= 0);
|
|
17
|
+
const registerFocusable = useCallback((focusable, changeHandler) => navigationActive ? contextRegisterFocusable(focusable, changeHandler) : () => { }, [navigationActive, contextRegisterFocusable]);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (focusable) {
|
|
20
|
+
const changeHandler = (element, suppressed) => setFocusTargetActive(focusable.current === element || suppressed);
|
|
21
|
+
const unregister = registerFocusable(focusable, changeHandler);
|
|
22
|
+
return () => unregister();
|
|
23
|
+
}
|
|
24
|
+
}, [focusable, registerFocusable]);
|
|
15
25
|
let tabIndex = options === null || options === void 0 ? void 0 : options.tabIndex;
|
|
16
26
|
if (navigationActive) {
|
|
17
|
-
tabIndex = !focusTargetActive ? -1 : tabIndex !== null &&
|
|
27
|
+
tabIndex = !focusTargetActive ? -1 : (_a = options === null || options === void 0 ? void 0 : options.tabIndex) !== null && _a !== void 0 ? _a : 0;
|
|
18
28
|
}
|
|
19
29
|
return { navigationActive, tabIndex };
|
|
20
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-tab-stop-navigation-context.js","sourceRoot":"lib/default/","sources":["internal/context/single-tab-stop-navigation-context.tsx"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC,
|
|
1
|
+
{"version":3,"file":"single-tab-stop-navigation-context.js","sourceRoot":"lib/default/","sources":["internal/context/single-tab-stop-navigation-context.tsx"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC,OAAc,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAU3F;;;GAGG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,aAAa,CAGxD;IACD,gBAAgB,EAAE,KAAK;IACvB,iBAAiB,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC;CAClC,CAAC,CAAC;AAEH,MAAM,UAAU,0BAA0B,CAAC,SAAqC,EAAE,OAA+B;;IAC/G,MAAM,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,GAC9F,UAAU,CAAC,8BAA8B,CAAC,CAAC;IAC7C,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElE,MAAM,gBAAgB,GAAG,uBAAuB,IAAI,CAAC,CAAC,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,CAAA,IAAI,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,KAAI,CAAC,CAAC,CAAC;IACnG,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,SAA8B,EAAE,aAAqC,EAAE,EAAE,CACxE,gBAAgB,CAAC,CAAC,CAAC,wBAAwB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAE,CAAC,EAClF,CAAC,gBAAgB,EAAE,wBAAwB,CAAC,CAC7C,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,EAAE;YACb,MAAM,aAAa,GAAG,CAAC,OAAuB,EAAE,UAAmB,EAAE,EAAE,CACrE,oBAAoB,CAAC,SAAS,CAAC,OAAO,KAAK,OAAO,IAAI,UAAU,CAAC,CAAC;YACpE,MAAM,UAAU,GAAG,iBAAiB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;YAC/D,OAAO,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC;SAC3B;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAEnC,IAAI,QAAQ,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,CAAC;IACjC,IAAI,gBAAgB,EAAE;QACpB,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,mCAAI,CAAC,CAAC;KAC7D;IAED,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;AACxC,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport React, { createContext, useCallback, useContext, useEffect, useState } from 'react';\n\nexport type FocusableDefinition = React.RefObject<Element>;\n\nexport type FocusableChangeHandler = (focusTarget: null | Element, suppressed: boolean) => void;\n\nexport interface SingleTabStopNavigationOptions {\n tabIndex?: number;\n}\n\n/**\n * Single tab stop navigation context is used together with keyboard navigation that requires a single tab stop.\n * It instructs interactive elements to override tab indices for just a single one to remain user-focusable.\n */\nexport const SingleTabStopNavigationContext = createContext<{\n navigationActive: boolean;\n registerFocusable(focusable: FocusableDefinition, handler: FocusableChangeHandler): () => void;\n}>({\n navigationActive: false,\n registerFocusable: () => () => {},\n});\n\nexport function useSingleTabStopNavigation(focusable: null | FocusableDefinition, options?: { tabIndex?: number }) {\n const { navigationActive: contextNavigationActive, registerFocusable: contextRegisterFocusable } =\n useContext(SingleTabStopNavigationContext);\n const [focusTargetActive, setFocusTargetActive] = useState(false);\n\n const navigationActive = contextNavigationActive && (!options?.tabIndex || options?.tabIndex >= 0);\n const registerFocusable = useCallback(\n (focusable: FocusableDefinition, changeHandler: FocusableChangeHandler) =>\n navigationActive ? contextRegisterFocusable(focusable, changeHandler) : () => {},\n [navigationActive, contextRegisterFocusable]\n );\n\n useEffect(() => {\n if (focusable) {\n const changeHandler = (element: null | Element, suppressed: boolean) =>\n setFocusTargetActive(focusable.current === element || suppressed);\n const unregister = registerFocusable(focusable, changeHandler);\n return () => unregister();\n }\n }, [focusable, registerFocusable]);\n\n let tabIndex = options?.tabIndex;\n if (navigationActive) {\n tabIndex = !focusTargetActive ? -1 : options?.tabIndex ?? 0;\n }\n\n return { navigationActive, tabIndex };\n}\n"]}
|
package/internal/environment.js
CHANGED
package/internal/manifest.json
CHANGED
|
@@ -29,6 +29,7 @@ export declare function calculateScroll({ top, height }: BoundingBox): number;
|
|
|
29
29
|
* so we need to manually scroll to the element's position.
|
|
30
30
|
* Supports only vertical scrolling.
|
|
31
31
|
*/
|
|
32
|
-
export declare function scrollRectangleIntoView(box: BoundingBox): void;
|
|
32
|
+
export declare function scrollRectangleIntoView(box: BoundingBox, scrollableParent?: HTMLElement): void;
|
|
33
|
+
export declare function getFirstScrollableParent(element: HTMLElement): HTMLElement | undefined;
|
|
33
34
|
export {};
|
|
34
35
|
//# sourceMappingURL=scrollable-containers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scrollable-containers.d.ts","sourceRoot":"lib/default/","sources":["internal/utils/scrollable-containers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scrollable-containers.d.ts","sourceRoot":"lib/default/","sources":["internal/utils/scrollable-containers.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,kBAAkB,YAAa,WAAW,KAAG,WAAW,EAQpE,CAAC;AAEF,eAAO,MAAM,2BAA2B;aAM7B,WAAW;0BACE,OAAO;sBACX,OAAO;8BACC,OAAO;MAC/B,WAAW,EAqCd,CAAC;AAEF,KAAK,qBAAqB,GAAG,UAAU,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1E;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,OAAO,GAAE,qBAA+D,QAGzE;AAED,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,WAAW,UAW3D;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,WAAW,EAAE,gBAAgB,CAAC,EAAE,WAAW,QAKvF;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,GAAG,SAAS,CAOtF"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { findUpUntil } from './dom';
|
|
1
4
|
export const getOverflowParents = (element) => {
|
|
2
5
|
const parents = [];
|
|
3
6
|
let node = element;
|
|
@@ -75,10 +78,16 @@ export function calculateScroll({ top, height }) {
|
|
|
75
78
|
* so we need to manually scroll to the element's position.
|
|
76
79
|
* Supports only vertical scrolling.
|
|
77
80
|
*/
|
|
78
|
-
export function scrollRectangleIntoView(box) {
|
|
81
|
+
export function scrollRectangleIntoView(box, scrollableParent) {
|
|
79
82
|
const scrollAmount = calculateScroll(box);
|
|
80
83
|
if (scrollAmount) {
|
|
81
|
-
window.scrollBy(0, scrollAmount);
|
|
84
|
+
(scrollableParent || window).scrollBy(0, scrollAmount);
|
|
82
85
|
}
|
|
83
86
|
}
|
|
87
|
+
export function getFirstScrollableParent(element) {
|
|
88
|
+
return (findUpUntil(element, el => {
|
|
89
|
+
const overflows = el.scrollHeight > el.clientHeight;
|
|
90
|
+
return overflows && ['scroll', 'auto'].includes(getComputedStyle(el).overflowY);
|
|
91
|
+
}) || undefined);
|
|
92
|
+
}
|
|
84
93
|
//# sourceMappingURL=scrollable-containers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scrollable-containers.js","sourceRoot":"lib/default/","sources":["internal/utils/scrollable-containers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scrollable-containers.js","sourceRoot":"lib/default/","sources":["internal/utils/scrollable-containers.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 { findUpUntil } from './dom';\nexport interface BoundingBox {\n height: number;\n width: number;\n top: number;\n left: number;\n}\n\nexport const getOverflowParents = (element: HTMLElement): HTMLElement[] => {\n const parents = [];\n let node: HTMLElement | null = element;\n\n while ((node = node.parentElement) && node !== document.body) {\n getComputedStyle(node).overflow !== 'visible' && parents.push(node);\n }\n return parents;\n};\n\nexport const getOverflowParentDimensions = ({\n element,\n excludeClosestParent = false,\n expandToViewport = false,\n canExpandOutsideViewport = false,\n}: {\n element: HTMLElement;\n excludeClosestParent: boolean;\n expandToViewport: boolean;\n canExpandOutsideViewport: boolean;\n}): BoundingBox[] => {\n const parents = expandToViewport\n ? []\n : getOverflowParents(element).map(el => {\n const { height, width, top, left } = el.getBoundingClientRect();\n return {\n // Treat the whole scrollable area as the available height\n // if we're allowed to expand past the viewport.\n height: canExpandOutsideViewport ? el.scrollHeight : height,\n width,\n top,\n left,\n };\n });\n\n if (canExpandOutsideViewport && !expandToViewport) {\n const documentDimensions = document.documentElement.getBoundingClientRect();\n parents.push({\n width: Math.max(documentDimensions.width, document.documentElement.clientWidth),\n height: Math.max(documentDimensions.height, document.documentElement.clientHeight),\n top: documentDimensions.top,\n left: documentDimensions.left,\n });\n } else {\n parents.push({\n height: window.innerHeight,\n width: window.innerWidth,\n top: 0,\n left: 0,\n });\n }\n\n if (excludeClosestParent && !expandToViewport) {\n parents.shift();\n }\n\n return parents;\n};\n\ntype ScrollIntoViewOptions = Parameters<HTMLElement['scrollIntoView']>[0];\n\n/**\n * Calls `scrollIntoView` on the provided element with sensible defaults. If\n * the element does not existed or does not support the `scrollIntoView`\n * method, it will do nothing. This wrapper is created to support environments\n * where the native function is not available like JSDom (feature request:\n * https://github.com/jsdom/jsdom/issues/1422).\n *\n * @param element to be scrolled into view\n * @param options native options for `scrollIntoView`\n */\nexport function scrollElementIntoView(\n element: HTMLElement | undefined,\n options: ScrollIntoViewOptions = { block: 'nearest', inline: 'nearest' }\n) {\n element?.scrollIntoView?.(options);\n}\n\nexport function calculateScroll({ top, height }: BoundingBox) {\n if (top < 0) {\n return top;\n } else if (top + height > window.innerHeight) {\n if (height > window.innerHeight) {\n return top;\n } else {\n return top + height - window.innerHeight;\n }\n }\n return 0;\n}\n\n/**\n * For elements with fixed position, the browser's native scrollIntoView API doesn't work,\n * so we need to manually scroll to the element's position.\n * Supports only vertical scrolling.\n */\nexport function scrollRectangleIntoView(box: BoundingBox, scrollableParent?: HTMLElement) {\n const scrollAmount = calculateScroll(box);\n if (scrollAmount) {\n (scrollableParent || window).scrollBy(0, scrollAmount);\n }\n}\n\nexport function getFirstScrollableParent(element: HTMLElement): HTMLElement | undefined {\n return (\n findUpUntil(element, el => {\n const overflows = el.scrollHeight > el.clientHeight;\n return overflows && ['scroll', 'auto'].includes(getComputedStyle(el).overflowY);\n }) || undefined\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@cloudscape-design/components","main":"./index.js","exports":{".":"./index.js","./package.json":"./package.json","./theming":"./theming/index.js","./test-utils/dom":"./test-utils/dom/index.js","./test-utils/selectors":"./test-utils/selectors/index.js","./interfaces":"./interfaces.js","./contexts/form-field":"./contexts/form-field.js","./alert":"./alert/index.js","./anchor-navigation":"./anchor-navigation/index.js","./annotation-context":"./annotation-context/index.js","./app-layout":"./app-layout/index.js","./area-chart":"./area-chart/index.js","./attribute-editor":"./attribute-editor/index.js","./autosuggest":"./autosuggest/index.js","./badge":"./badge/index.js","./bar-chart":"./bar-chart/index.js","./box":"./box/index.js","./breadcrumb-group":"./breadcrumb-group/index.js","./button":"./button/index.js","./button-dropdown":"./button-dropdown/index.js","./calendar":"./calendar/index.js","./cards":"./cards/index.js","./checkbox":"./checkbox/index.js","./code-editor":"./code-editor/index.js","./collection-preferences":"./collection-preferences/index.js","./column-layout":"./column-layout/index.js","./container":"./container/index.js","./content-layout":"./content-layout/index.js","./date-input":"./date-input/index.js","./date-picker":"./date-picker/index.js","./date-range-picker":"./date-range-picker/index.js","./drawer":"./drawer/index.js","./expandable-section":"./expandable-section/index.js","./file-upload":"./file-upload/index.js","./flashbar":"./flashbar/index.js","./form":"./form/index.js","./form-field":"./form-field/index.js","./grid":"./grid/index.js","./header":"./header/index.js","./help-panel":"./help-panel/index.js","./hotspot":"./hotspot/index.js","./icon":"./icon/index.js","./input":"./input/index.js","./line-chart":"./line-chart/index.js","./link":"./link/index.js","./mixed-line-bar-chart":"./mixed-line-bar-chart/index.js","./modal":"./modal/index.js","./multiselect":"./multiselect/index.js","./pagination":"./pagination/index.js","./pie-chart":"./pie-chart/index.js","./popover":"./popover/index.js","./progress-bar":"./progress-bar/index.js","./property-filter":"./property-filter/index.js","./radio-group":"./radio-group/index.js","./s3-resource-selector":"./s3-resource-selector/index.js","./segmented-control":"./segmented-control/index.js","./select":"./select/index.js","./side-navigation":"./side-navigation/index.js","./space-between":"./space-between/index.js","./spinner":"./spinner/index.js","./split-panel":"./split-panel/index.js","./status-indicator":"./status-indicator/index.js","./table":"./table/index.js","./tabs":"./tabs/index.js","./tag-editor":"./tag-editor/index.js","./text-content":"./text-content/index.js","./text-filter":"./text-filter/index.js","./textarea":"./textarea/index.js","./tiles":"./tiles/index.js","./time-input":"./time-input/index.js","./toggle":"./toggle/index.js","./token-group":"./token-group/index.js","./top-navigation":"./top-navigation/index.js","./tutorial-panel":"./tutorial-panel/index.js","./wizard":"./wizard/index.js","./top-navigation/1.0-beta":"./top-navigation/1.0-beta/index.js","./i18n":"./i18n/index.js","./i18n/messages/all.all":"./i18n/messages/all.all.js","./i18n/messages/all.all.json":"./i18n/messages/all.all.json","./i18n/messages/all.de":"./i18n/messages/all.de.js","./i18n/messages/all.de.json":"./i18n/messages/all.de.json","./i18n/messages/all.en-GB":"./i18n/messages/all.en-GB.js","./i18n/messages/all.en-GB.json":"./i18n/messages/all.en-GB.json","./i18n/messages/all.en":"./i18n/messages/all.en.js","./i18n/messages/all.en.json":"./i18n/messages/all.en.json","./i18n/messages/all.es":"./i18n/messages/all.es.js","./i18n/messages/all.es.json":"./i18n/messages/all.es.json","./i18n/messages/all.fr":"./i18n/messages/all.fr.js","./i18n/messages/all.fr.json":"./i18n/messages/all.fr.json","./i18n/messages/all.id":"./i18n/messages/all.id.js","./i18n/messages/all.id.json":"./i18n/messages/all.id.json","./i18n/messages/all.it":"./i18n/messages/all.it.js","./i18n/messages/all.it.json":"./i18n/messages/all.it.json","./i18n/messages/all.ja":"./i18n/messages/all.ja.js","./i18n/messages/all.ja.json":"./i18n/messages/all.ja.json","./i18n/messages/all.ko":"./i18n/messages/all.ko.js","./i18n/messages/all.ko.json":"./i18n/messages/all.ko.json","./i18n/messages/all.pt-BR":"./i18n/messages/all.pt-BR.js","./i18n/messages/all.pt-BR.json":"./i18n/messages/all.pt-BR.json","./i18n/messages/all.th":"./i18n/messages/all.th.js","./i18n/messages/all.th.json":"./i18n/messages/all.th.json","./i18n/messages/all.tr":"./i18n/messages/all.tr.js","./i18n/messages/all.tr.json":"./i18n/messages/all.tr.json","./i18n/messages/all.zh-CN":"./i18n/messages/all.zh-CN.js","./i18n/messages/all.zh-CN.json":"./i18n/messages/all.zh-CN.json","./i18n/messages/all.zh-TW":"./i18n/messages/all.zh-TW.js","./i18n/messages/all.zh-TW.json":"./i18n/messages/all.zh-TW.json"},"sideEffects":["*.css","./internal/base-component/index.js","./internal/base-component/styles.css.js"],"version":"3.0.
|
|
1
|
+
{"name":"@cloudscape-design/components","main":"./index.js","exports":{".":"./index.js","./package.json":"./package.json","./theming":"./theming/index.js","./test-utils/dom":"./test-utils/dom/index.js","./test-utils/selectors":"./test-utils/selectors/index.js","./interfaces":"./interfaces.js","./contexts/form-field":"./contexts/form-field.js","./alert":"./alert/index.js","./anchor-navigation":"./anchor-navigation/index.js","./annotation-context":"./annotation-context/index.js","./app-layout":"./app-layout/index.js","./area-chart":"./area-chart/index.js","./attribute-editor":"./attribute-editor/index.js","./autosuggest":"./autosuggest/index.js","./badge":"./badge/index.js","./bar-chart":"./bar-chart/index.js","./box":"./box/index.js","./breadcrumb-group":"./breadcrumb-group/index.js","./button":"./button/index.js","./button-dropdown":"./button-dropdown/index.js","./calendar":"./calendar/index.js","./cards":"./cards/index.js","./checkbox":"./checkbox/index.js","./code-editor":"./code-editor/index.js","./collection-preferences":"./collection-preferences/index.js","./column-layout":"./column-layout/index.js","./container":"./container/index.js","./content-layout":"./content-layout/index.js","./date-input":"./date-input/index.js","./date-picker":"./date-picker/index.js","./date-range-picker":"./date-range-picker/index.js","./drawer":"./drawer/index.js","./expandable-section":"./expandable-section/index.js","./file-upload":"./file-upload/index.js","./flashbar":"./flashbar/index.js","./form":"./form/index.js","./form-field":"./form-field/index.js","./grid":"./grid/index.js","./header":"./header/index.js","./help-panel":"./help-panel/index.js","./hotspot":"./hotspot/index.js","./icon":"./icon/index.js","./input":"./input/index.js","./line-chart":"./line-chart/index.js","./link":"./link/index.js","./mixed-line-bar-chart":"./mixed-line-bar-chart/index.js","./modal":"./modal/index.js","./multiselect":"./multiselect/index.js","./pagination":"./pagination/index.js","./pie-chart":"./pie-chart/index.js","./popover":"./popover/index.js","./progress-bar":"./progress-bar/index.js","./property-filter":"./property-filter/index.js","./radio-group":"./radio-group/index.js","./s3-resource-selector":"./s3-resource-selector/index.js","./segmented-control":"./segmented-control/index.js","./select":"./select/index.js","./side-navigation":"./side-navigation/index.js","./space-between":"./space-between/index.js","./spinner":"./spinner/index.js","./split-panel":"./split-panel/index.js","./status-indicator":"./status-indicator/index.js","./table":"./table/index.js","./tabs":"./tabs/index.js","./tag-editor":"./tag-editor/index.js","./text-content":"./text-content/index.js","./text-filter":"./text-filter/index.js","./textarea":"./textarea/index.js","./tiles":"./tiles/index.js","./time-input":"./time-input/index.js","./toggle":"./toggle/index.js","./token-group":"./token-group/index.js","./top-navigation":"./top-navigation/index.js","./tutorial-panel":"./tutorial-panel/index.js","./wizard":"./wizard/index.js","./top-navigation/1.0-beta":"./top-navigation/1.0-beta/index.js","./i18n":"./i18n/index.js","./i18n/messages/all.all":"./i18n/messages/all.all.js","./i18n/messages/all.all.json":"./i18n/messages/all.all.json","./i18n/messages/all.de":"./i18n/messages/all.de.js","./i18n/messages/all.de.json":"./i18n/messages/all.de.json","./i18n/messages/all.en-GB":"./i18n/messages/all.en-GB.js","./i18n/messages/all.en-GB.json":"./i18n/messages/all.en-GB.json","./i18n/messages/all.en":"./i18n/messages/all.en.js","./i18n/messages/all.en.json":"./i18n/messages/all.en.json","./i18n/messages/all.es":"./i18n/messages/all.es.js","./i18n/messages/all.es.json":"./i18n/messages/all.es.json","./i18n/messages/all.fr":"./i18n/messages/all.fr.js","./i18n/messages/all.fr.json":"./i18n/messages/all.fr.json","./i18n/messages/all.id":"./i18n/messages/all.id.js","./i18n/messages/all.id.json":"./i18n/messages/all.id.json","./i18n/messages/all.it":"./i18n/messages/all.it.js","./i18n/messages/all.it.json":"./i18n/messages/all.it.json","./i18n/messages/all.ja":"./i18n/messages/all.ja.js","./i18n/messages/all.ja.json":"./i18n/messages/all.ja.json","./i18n/messages/all.ko":"./i18n/messages/all.ko.js","./i18n/messages/all.ko.json":"./i18n/messages/all.ko.json","./i18n/messages/all.pt-BR":"./i18n/messages/all.pt-BR.js","./i18n/messages/all.pt-BR.json":"./i18n/messages/all.pt-BR.json","./i18n/messages/all.th":"./i18n/messages/all.th.js","./i18n/messages/all.th.json":"./i18n/messages/all.th.json","./i18n/messages/all.tr":"./i18n/messages/all.tr.js","./i18n/messages/all.tr.json":"./i18n/messages/all.tr.json","./i18n/messages/all.zh-CN":"./i18n/messages/all.zh-CN.js","./i18n/messages/all.zh-CN.json":"./i18n/messages/all.zh-CN.json","./i18n/messages/all.zh-TW":"./i18n/messages/all.zh-TW.js","./i18n/messages/all.zh-TW.json":"./i18n/messages/all.zh-TW.json"},"sideEffects":["*.css","./internal/base-component/index.js","./internal/base-component/styles.css.js"],"version":"3.0.496","repository":{"type":"git","url":"https://github.com/cloudscape-design/components.git"},"homepage":"https://cloudscape.design","dependencies":{"@cloudscape-design/collection-hooks":"^1.0.0","@cloudscape-design/component-toolkit":"^1.0.0-beta","@cloudscape-design/test-utils-core":"^1.0.0","@cloudscape-design/theming-runtime":"^1.0.0","@dnd-kit/core":"^6.0.8","@dnd-kit/sortable":"^7.0.2","@dnd-kit/utilities":"^3.2.1","@juggle/resize-observer":"^3.3.1","ace-builds":"^1.23.0","balanced-match":"^1.0.2","clsx":"^1.1.0","d3-shape":"^1.3.7","date-fns":"^2.25.0","intl-messageformat":"^10.3.1","mnth":"^2.0.0","react-keyed-flatten-children":"^1.3.0","react-transition-group":"^4.4.2","react-virtual":"^2.8.2","tslib":"^2.4.0","weekstart":"^1.1.0"},"peerDependencies":{"react":"^16.8 || ^17 || ^18","react-dom":"^16.8 || ^17 || ^18"},"license":"Apache-2.0"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-popover-position.d.ts","sourceRoot":"lib/default/","sources":["popover/use-popover-position.ts"],"names":[],"mappings":"AAGA,OAAO,KAAwC,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAe,gBAAgB,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"use-popover-position.d.ts","sourceRoot":"lib/default/","sources":["popover/use-popover-position.ts"],"names":[],"mappings":"AAGA,OAAO,KAAwC,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAe,gBAAgB,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAUnF,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EACzC,UAAU,EACV,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,GACb,EAAE;IACD,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACnD,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAChD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC1C,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACnD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iBAAiB,EAAE,YAAY,CAAC,QAAQ,CAAC;IACzC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;;;;qDAMyC,IAAI;EAoI7C"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { useCallback, useRef, useState } from 'react';
|
|
4
4
|
import { calculatePosition, getDimensions, getOffsetDimensions } from './utils/positions';
|
|
5
5
|
import { nodeContains } from '@cloudscape-design/component-toolkit/dom';
|
|
6
|
-
import { calculateScroll, scrollRectangleIntoView } from '../internal/utils/scrollable-containers';
|
|
6
|
+
import { calculateScroll, getFirstScrollableParent, scrollRectangleIntoView, } from '../internal/utils/scrollable-containers';
|
|
7
7
|
import { getContainingBlock } from '../internal/utils/dom';
|
|
8
8
|
export default function usePopoverPosition({ popoverRef, bodyRef, arrowRef, trackRef, contentRef, allowScrollToFit, allowVerticalOverflow, preferredPosition, renderWithPortal, keepPosition, }) {
|
|
9
9
|
const previousInternalPositionRef = useRef(null);
|
|
@@ -90,8 +90,10 @@ export default function usePopoverPosition({ popoverRef, bodyRef, arrowRef, trac
|
|
|
90
90
|
// Position the popover
|
|
91
91
|
const top = shouldScroll ? popoverOffset.top + calculateScroll(rect) : popoverOffset.top;
|
|
92
92
|
setPopoverStyle({ top, left: popoverOffset.left });
|
|
93
|
+
// Scroll if necessary
|
|
93
94
|
if (shouldScroll) {
|
|
94
|
-
|
|
95
|
+
const scrollableParent = getFirstScrollableParent(popover);
|
|
96
|
+
scrollRectangleIntoView(rect, scrollableParent);
|
|
95
97
|
}
|
|
96
98
|
positionHandlerRef.current = () => {
|
|
97
99
|
const newTrackOffset = toRelativePosition(track.getBoundingClientRect(), containingBlock ? containingBlock.getBoundingClientRect() : viewportRect);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-popover-position.js","sourceRoot":"lib/default/","sources":["popover/use-popover-position.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 React, { useCallback, useRef, useState } from 'react';\nimport { BoundingBox, InternalPosition, Offset, PopoverProps } from './interfaces';\nimport { calculatePosition, getDimensions, getOffsetDimensions } from './utils/positions';\nimport { nodeContains } from '@cloudscape-design/component-toolkit/dom';\nimport { calculateScroll, scrollRectangleIntoView } from '../internal/utils/scrollable-containers';\nimport { getContainingBlock } from '../internal/utils/dom';\n\nexport default function usePopoverPosition({\n popoverRef,\n bodyRef,\n arrowRef,\n trackRef,\n contentRef,\n allowScrollToFit,\n allowVerticalOverflow,\n preferredPosition,\n renderWithPortal,\n keepPosition,\n}: {\n popoverRef: React.RefObject<HTMLDivElement | null>;\n bodyRef: React.RefObject<HTMLDivElement | null>;\n arrowRef: React.RefObject<HTMLDivElement | null>;\n trackRef: React.RefObject<Element | null>;\n contentRef: React.RefObject<HTMLDivElement | null>;\n allowScrollToFit?: boolean;\n allowVerticalOverflow?: boolean;\n preferredPosition: PopoverProps.Position;\n renderWithPortal?: boolean;\n keepPosition?: boolean;\n}) {\n const previousInternalPositionRef = useRef<InternalPosition | null>(null);\n const [popoverStyle, setPopoverStyle] = useState<Partial<Offset>>({});\n const [internalPosition, setInternalPosition] = useState<InternalPosition | null>(null);\n\n // Store the handler in a ref so that it can still be replaced from outside of the listener closure.\n const positionHandlerRef = useRef<() => void>(() => {});\n\n const updatePositionHandler = useCallback(\n (onContentResize = false) => {\n if (!trackRef.current || !popoverRef.current || !bodyRef.current || !contentRef.current || !arrowRef.current) {\n return;\n }\n\n // Get important elements\n const popover = popoverRef.current;\n const body = bodyRef.current;\n const arrow = arrowRef.current;\n const document = popover.ownerDocument;\n const track = trackRef.current;\n\n // If the popover body isn't being rendered for whatever reason (e.g. \"display: none\" or JSDOM),\n // or track does not belong to the document - bail on calculating dimensions.\n const { offsetWidth, offsetHeight } = getOffsetDimensions(popover);\n if (offsetWidth === 0 || offsetHeight === 0 || !nodeContains(document.body, track)) {\n return;\n }\n\n // Imperatively move body off-screen to give it room to expand.\n // Not doing this in React because this recalculation should happen\n // in the span of a single frame without rerendering anything.\n const prevTop = popover.style.top;\n const prevLeft = popover.style.left;\n\n popover.style.top = '0';\n popover.style.left = '0';\n // Imperatively remove body styles that can remain from the previous computation.\n body.style.maxHeight = '';\n body.style.overflowX = '';\n body.style.overflowY = '';\n\n // Get rects representing key elements\n // Use getComputedStyle for arrowRect to avoid modifications made by transform\n const viewportRect = getViewportRect(document.defaultView!);\n const trackRect = track.getBoundingClientRect();\n const arrowRect = getDimensions(arrow);\n const containingBlock = getContainingBlock(popover);\n const containingBlockRect = containingBlock ? containingBlock.getBoundingClientRect() : viewportRect;\n\n const bodyBorderWidth = getBorderWidth(body);\n const contentRect = contentRef.current.getBoundingClientRect();\n const contentBoundingBox = {\n width: contentRect.width + 2 * bodyBorderWidth,\n height: contentRect.height + 2 * bodyBorderWidth,\n };\n\n // When keepPosition is true and the recalculation was triggered by a resize of the popover content,\n // we maintain the previously defined internal position,\n // but we still call calculatePosition to know if the popover should be scrollable.\n const shouldKeepPosition = keepPosition && onContentResize && !!previousInternalPositionRef.current;\n const fixedInternalPosition = (shouldKeepPosition && previousInternalPositionRef.current) ?? undefined;\n\n // Calculate the arrow direction and viewport-relative position of the popover.\n const {\n scrollable,\n internalPosition: newInternalPosition,\n rect,\n } = calculatePosition({\n preferredPosition,\n fixedInternalPosition,\n trigger: trackRect,\n arrow: arrowRect,\n body: contentBoundingBox,\n container: containingBlock ? containingBlockRect : getDocumentRect(document),\n viewport: viewportRect,\n renderWithPortal,\n allowVerticalOverflow,\n });\n\n // Get the position of the popover relative to the offset parent.\n const popoverOffset = toRelativePosition(rect, containingBlockRect);\n\n // Cache the distance between the trigger and the popover (which stays the same as you scroll),\n // and use that to recalculate the new popover position.\n const trackRelativeOffset = toRelativePosition(popoverOffset, toRelativePosition(trackRect, containingBlockRect));\n\n // Bring back the container to its original position to prevent any flashing.\n popover.style.top = prevTop;\n popover.style.left = prevLeft;\n\n // Allow popover body to scroll if can't fit the popover into the container/viewport otherwise.\n if (scrollable) {\n body.style.maxHeight = rect.height + 'px';\n body.style.overflowX = 'hidden';\n body.style.overflowY = 'auto';\n }\n\n // Remember the internal position in case we want to keep it later.\n previousInternalPositionRef.current = newInternalPosition;\n setInternalPosition(newInternalPosition);\n\n const shouldScroll = allowScrollToFit && !shouldKeepPosition;\n\n // Position the popover\n const top = shouldScroll ? popoverOffset.top + calculateScroll(rect) : popoverOffset.top;\n setPopoverStyle({ top, left: popoverOffset.left });\n if (shouldScroll) {\n scrollRectangleIntoView(rect);\n }\n\n positionHandlerRef.current = () => {\n const newTrackOffset = toRelativePosition(\n track.getBoundingClientRect(),\n containingBlock ? containingBlock.getBoundingClientRect() : viewportRect\n );\n setPopoverStyle({\n top: newTrackOffset.top + trackRelativeOffset.top,\n left: newTrackOffset.left + trackRelativeOffset.left,\n });\n };\n },\n [\n trackRef,\n popoverRef,\n bodyRef,\n contentRef,\n arrowRef,\n keepPosition,\n allowScrollToFit,\n preferredPosition,\n renderWithPortal,\n allowVerticalOverflow,\n ]\n );\n return { updatePositionHandler, popoverStyle, internalPosition, positionHandlerRef };\n}\n\nfunction getBorderWidth(element: HTMLElement) {\n return parseInt(getComputedStyle(element).borderWidth) || 0;\n}\n\n/**\n * Convert a viewport-relative offset to an element-relative offset.\n */\nfunction toRelativePosition(element: Offset, parent: Offset): Offset {\n return {\n top: element.top - parent.top,\n left: element.left - parent.left,\n };\n}\n\n/**\n * Get a BoundingBox that represents the visible viewport.\n */\nfunction getViewportRect(window: Window): BoundingBox {\n return {\n top: 0,\n left: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n}\n\nfunction getDocumentRect(document: Document): BoundingBox {\n const { top, left } = document.documentElement.getBoundingClientRect();\n return {\n top,\n left,\n width: document.documentElement.scrollWidth,\n height: document.documentElement.scrollHeight,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"use-popover-position.js","sourceRoot":"lib/default/","sources":["popover/use-popover-position.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 React, { useCallback, useRef, useState } from 'react';\nimport { BoundingBox, InternalPosition, Offset, PopoverProps } from './interfaces';\nimport { calculatePosition, getDimensions, getOffsetDimensions } from './utils/positions';\nimport { nodeContains } from '@cloudscape-design/component-toolkit/dom';\nimport {\n calculateScroll,\n getFirstScrollableParent,\n scrollRectangleIntoView,\n} from '../internal/utils/scrollable-containers';\nimport { getContainingBlock } from '../internal/utils/dom';\n\nexport default function usePopoverPosition({\n popoverRef,\n bodyRef,\n arrowRef,\n trackRef,\n contentRef,\n allowScrollToFit,\n allowVerticalOverflow,\n preferredPosition,\n renderWithPortal,\n keepPosition,\n}: {\n popoverRef: React.RefObject<HTMLDivElement | null>;\n bodyRef: React.RefObject<HTMLDivElement | null>;\n arrowRef: React.RefObject<HTMLDivElement | null>;\n trackRef: React.RefObject<Element | null>;\n contentRef: React.RefObject<HTMLDivElement | null>;\n allowScrollToFit?: boolean;\n allowVerticalOverflow?: boolean;\n preferredPosition: PopoverProps.Position;\n renderWithPortal?: boolean;\n keepPosition?: boolean;\n}) {\n const previousInternalPositionRef = useRef<InternalPosition | null>(null);\n const [popoverStyle, setPopoverStyle] = useState<Partial<Offset>>({});\n const [internalPosition, setInternalPosition] = useState<InternalPosition | null>(null);\n\n // Store the handler in a ref so that it can still be replaced from outside of the listener closure.\n const positionHandlerRef = useRef<() => void>(() => {});\n\n const updatePositionHandler = useCallback(\n (onContentResize = false) => {\n if (!trackRef.current || !popoverRef.current || !bodyRef.current || !contentRef.current || !arrowRef.current) {\n return;\n }\n\n // Get important elements\n const popover = popoverRef.current;\n const body = bodyRef.current;\n const arrow = arrowRef.current;\n const document = popover.ownerDocument;\n const track = trackRef.current;\n\n // If the popover body isn't being rendered for whatever reason (e.g. \"display: none\" or JSDOM),\n // or track does not belong to the document - bail on calculating dimensions.\n const { offsetWidth, offsetHeight } = getOffsetDimensions(popover);\n if (offsetWidth === 0 || offsetHeight === 0 || !nodeContains(document.body, track)) {\n return;\n }\n\n // Imperatively move body off-screen to give it room to expand.\n // Not doing this in React because this recalculation should happen\n // in the span of a single frame without rerendering anything.\n const prevTop = popover.style.top;\n const prevLeft = popover.style.left;\n\n popover.style.top = '0';\n popover.style.left = '0';\n // Imperatively remove body styles that can remain from the previous computation.\n body.style.maxHeight = '';\n body.style.overflowX = '';\n body.style.overflowY = '';\n\n // Get rects representing key elements\n // Use getComputedStyle for arrowRect to avoid modifications made by transform\n const viewportRect = getViewportRect(document.defaultView!);\n const trackRect = track.getBoundingClientRect();\n const arrowRect = getDimensions(arrow);\n const containingBlock = getContainingBlock(popover);\n const containingBlockRect = containingBlock ? containingBlock.getBoundingClientRect() : viewportRect;\n\n const bodyBorderWidth = getBorderWidth(body);\n const contentRect = contentRef.current.getBoundingClientRect();\n const contentBoundingBox = {\n width: contentRect.width + 2 * bodyBorderWidth,\n height: contentRect.height + 2 * bodyBorderWidth,\n };\n\n // When keepPosition is true and the recalculation was triggered by a resize of the popover content,\n // we maintain the previously defined internal position,\n // but we still call calculatePosition to know if the popover should be scrollable.\n const shouldKeepPosition = keepPosition && onContentResize && !!previousInternalPositionRef.current;\n const fixedInternalPosition = (shouldKeepPosition && previousInternalPositionRef.current) ?? undefined;\n\n // Calculate the arrow direction and viewport-relative position of the popover.\n const {\n scrollable,\n internalPosition: newInternalPosition,\n rect,\n } = calculatePosition({\n preferredPosition,\n fixedInternalPosition,\n trigger: trackRect,\n arrow: arrowRect,\n body: contentBoundingBox,\n container: containingBlock ? containingBlockRect : getDocumentRect(document),\n viewport: viewportRect,\n renderWithPortal,\n allowVerticalOverflow,\n });\n\n // Get the position of the popover relative to the offset parent.\n const popoverOffset = toRelativePosition(rect, containingBlockRect);\n\n // Cache the distance between the trigger and the popover (which stays the same as you scroll),\n // and use that to recalculate the new popover position.\n const trackRelativeOffset = toRelativePosition(popoverOffset, toRelativePosition(trackRect, containingBlockRect));\n\n // Bring back the container to its original position to prevent any flashing.\n popover.style.top = prevTop;\n popover.style.left = prevLeft;\n\n // Allow popover body to scroll if can't fit the popover into the container/viewport otherwise.\n if (scrollable) {\n body.style.maxHeight = rect.height + 'px';\n body.style.overflowX = 'hidden';\n body.style.overflowY = 'auto';\n }\n\n // Remember the internal position in case we want to keep it later.\n previousInternalPositionRef.current = newInternalPosition;\n setInternalPosition(newInternalPosition);\n\n const shouldScroll = allowScrollToFit && !shouldKeepPosition;\n\n // Position the popover\n const top = shouldScroll ? popoverOffset.top + calculateScroll(rect) : popoverOffset.top;\n setPopoverStyle({ top, left: popoverOffset.left });\n\n // Scroll if necessary\n if (shouldScroll) {\n const scrollableParent = getFirstScrollableParent(popover);\n scrollRectangleIntoView(rect, scrollableParent);\n }\n\n positionHandlerRef.current = () => {\n const newTrackOffset = toRelativePosition(\n track.getBoundingClientRect(),\n containingBlock ? containingBlock.getBoundingClientRect() : viewportRect\n );\n setPopoverStyle({\n top: newTrackOffset.top + trackRelativeOffset.top,\n left: newTrackOffset.left + trackRelativeOffset.left,\n });\n };\n },\n [\n trackRef,\n popoverRef,\n bodyRef,\n contentRef,\n arrowRef,\n keepPosition,\n allowScrollToFit,\n preferredPosition,\n renderWithPortal,\n allowVerticalOverflow,\n ]\n );\n return { updatePositionHandler, popoverStyle, internalPosition, positionHandlerRef };\n}\n\nfunction getBorderWidth(element: HTMLElement) {\n return parseInt(getComputedStyle(element).borderWidth) || 0;\n}\n\n/**\n * Convert a viewport-relative offset to an element-relative offset.\n */\nfunction toRelativePosition(element: Offset, parent: Offset): Offset {\n return {\n top: element.top - parent.top,\n left: element.left - parent.left,\n };\n}\n\n/**\n * Get a BoundingBox that represents the visible viewport.\n */\nfunction getViewportRect(window: Window): BoundingBox {\n return {\n top: 0,\n left: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n}\n\nfunction getDocumentRect(document: Document): BoundingBox {\n const { top, left } = document.documentElement.getBoundingClientRect();\n return {\n top,\n left,\n width: document.documentElement.scrollWidth,\n height: document.documentElement.scrollHeight,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid-navigation.d.ts","sourceRoot":"lib/default/","sources":["table/table-role/grid-navigation.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"grid-navigation.d.ts","sourceRoot":"lib/default/","sources":["table/table-role/grid-navigation.tsx"],"names":[],"mappings":";AAMA,OAAO,EAAe,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAWhE;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,mBAAmB,eAoC/G"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import React from 'react';
|
|
3
4
|
import { useEffect, useMemo } from 'react';
|
|
4
|
-
import { defaultIsSuppressed,
|
|
5
|
+
import { defaultIsSuppressed, findTableRowByAriaRowIndex, findTableRowCellByAriaColIndex } from './utils';
|
|
5
6
|
import { KeyCode } from '../../internal/keycode';
|
|
6
7
|
import { useStableCallback } from '@cloudscape-design/component-toolkit/internal';
|
|
7
|
-
import React from 'react';
|
|
8
8
|
import { nodeBelongs } from '../../internal/utils/node-belongs';
|
|
9
|
+
import { getAllFocusables } from '../../internal/components/focus-lock/utils';
|
|
10
|
+
import { SingleTabStopNavigationContext, } from '../../internal/context/single-tab-stop-navigation-context';
|
|
9
11
|
/**
|
|
10
12
|
* Makes table navigable with keyboard commands.
|
|
11
13
|
* See grid-navigation.md
|
|
@@ -31,7 +33,10 @@ export function GridNavigationProvider({ keyboardNavigation, pageSize, getTable,
|
|
|
31
33
|
gridNavigation.refresh();
|
|
32
34
|
}
|
|
33
35
|
});
|
|
34
|
-
return React.createElement(
|
|
36
|
+
return (React.createElement(SingleTabStopNavigationContext.Provider, { value: {
|
|
37
|
+
navigationActive: keyboardNavigation,
|
|
38
|
+
registerFocusable: gridNavigation.registerFocusable,
|
|
39
|
+
} }, children));
|
|
35
40
|
}
|
|
36
41
|
/**
|
|
37
42
|
* This helper encapsulates the grid navigation behaviors which are:
|
|
@@ -46,6 +51,19 @@ class GridNavigationProcessor {
|
|
|
46
51
|
this._table = null;
|
|
47
52
|
// State
|
|
48
53
|
this.focusedCell = null;
|
|
54
|
+
this.focusables = new Set();
|
|
55
|
+
this.focusHandlers = new Map();
|
|
56
|
+
this.focusTarget = null;
|
|
57
|
+
this.registerFocusable = (focusable, changeHandler) => {
|
|
58
|
+
this.focusables.add(focusable);
|
|
59
|
+
this.focusHandlers.set(focusable, changeHandler);
|
|
60
|
+
changeHandler(this.focusTarget, this.isSuppressed(focusable.current));
|
|
61
|
+
return () => this.unregisterFocusable(focusable);
|
|
62
|
+
};
|
|
63
|
+
this.unregisterFocusable = (focusable) => {
|
|
64
|
+
this.focusables.delete(focusable);
|
|
65
|
+
this.focusHandlers.delete(focusable);
|
|
66
|
+
};
|
|
49
67
|
this.onFocusin = (event) => {
|
|
50
68
|
var _a;
|
|
51
69
|
if (!(event.target instanceof HTMLElement)) {
|
|
@@ -56,11 +74,11 @@ class GridNavigationProcessor {
|
|
|
56
74
|
return;
|
|
57
75
|
}
|
|
58
76
|
this.focusedCell = cell;
|
|
59
|
-
this.
|
|
77
|
+
this.updateFocusTarget();
|
|
60
78
|
// Focusing on cell is not eligible when it contains focusable elements in the content.
|
|
61
79
|
// If content focusables are available - move the focus to the first one.
|
|
62
80
|
if (cell.element === cell.cellElement) {
|
|
63
|
-
(_a =
|
|
81
|
+
(_a = this.getFocusablesFrom(cell.cellElement)[0]) === null || _a === void 0 ? void 0 : _a.focus();
|
|
64
82
|
}
|
|
65
83
|
};
|
|
66
84
|
this.onFocusout = () => {
|
|
@@ -91,8 +109,7 @@ class GridNavigationProcessor {
|
|
|
91
109
|
const from = this.focusedCell;
|
|
92
110
|
const minExtreme = Number.NEGATIVE_INFINITY;
|
|
93
111
|
const maxExtreme = Number.POSITIVE_INFINITY;
|
|
94
|
-
|
|
95
|
-
if (this.isSuppressed(from.element)) {
|
|
112
|
+
if (this.isSuppressed(document.activeElement) || !this.isRegistered(document.activeElement)) {
|
|
96
113
|
return;
|
|
97
114
|
}
|
|
98
115
|
switch (key) {
|
|
@@ -130,18 +147,27 @@ class GridNavigationProcessor {
|
|
|
130
147
|
return;
|
|
131
148
|
}
|
|
132
149
|
};
|
|
150
|
+
this.getRegisteredElements = () => {
|
|
151
|
+
const registeredElements = new Set();
|
|
152
|
+
for (const focusable of this.focusables) {
|
|
153
|
+
if (focusable.current) {
|
|
154
|
+
registeredElements.add(focusable.current);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return registeredElements;
|
|
158
|
+
};
|
|
133
159
|
}
|
|
134
160
|
init(table) {
|
|
135
161
|
this._table = table;
|
|
136
162
|
this.table.addEventListener('focusin', this.onFocusin);
|
|
137
163
|
this.table.addEventListener('focusout', this.onFocusout);
|
|
138
164
|
this.table.addEventListener('keydown', this.onKeydown);
|
|
139
|
-
this.
|
|
165
|
+
this.updateFocusTarget();
|
|
140
166
|
this.cleanup = () => {
|
|
141
167
|
this.table.removeEventListener('focusin', this.onFocusin);
|
|
142
168
|
this.table.removeEventListener('focusout', this.onFocusout);
|
|
143
169
|
this.table.removeEventListener('keydown', this.onKeydown);
|
|
144
|
-
|
|
170
|
+
this.focusables.forEach(this.unregisterFocusable);
|
|
145
171
|
};
|
|
146
172
|
}
|
|
147
173
|
cleanup() {
|
|
@@ -151,14 +177,16 @@ class GridNavigationProcessor {
|
|
|
151
177
|
this._pageSize = pageSize;
|
|
152
178
|
}
|
|
153
179
|
refresh() {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (this.
|
|
157
|
-
|
|
180
|
+
// Timeout ensures the newly rendered content elements are registered.
|
|
181
|
+
setTimeout(() => {
|
|
182
|
+
if (this._table) {
|
|
183
|
+
// Update focused cell indices in case table rows, columns, or firstIndex change.
|
|
184
|
+
if (this.focusedCell) {
|
|
185
|
+
this.focusedCell = this.findFocusedCell(this.focusedCell.element);
|
|
186
|
+
}
|
|
187
|
+
this.updateFocusTarget();
|
|
158
188
|
}
|
|
159
|
-
|
|
160
|
-
this.ensureSingleFocusable();
|
|
161
|
-
}
|
|
189
|
+
}, 0);
|
|
162
190
|
}
|
|
163
191
|
get pageSize() {
|
|
164
192
|
return this._pageSize;
|
|
@@ -169,36 +197,40 @@ class GridNavigationProcessor {
|
|
|
169
197
|
}
|
|
170
198
|
return this._table;
|
|
171
199
|
}
|
|
172
|
-
isSuppressed(focusedElement) {
|
|
173
|
-
return defaultIsSuppressed(focusedElement);
|
|
174
|
-
}
|
|
175
200
|
moveFocusBy(cell, delta) {
|
|
176
201
|
var _a;
|
|
177
202
|
(_a = this.getNextFocusable(cell, delta)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
178
203
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
204
|
+
updateFocusTarget() {
|
|
205
|
+
this.focusTarget = this.getSingleFocusable();
|
|
206
|
+
this.focusables.forEach(focusable => {
|
|
207
|
+
const element = focusable.current;
|
|
208
|
+
const handler = this.focusHandlers.get(focusable);
|
|
209
|
+
handler(this.focusTarget, this.isSuppressed(element));
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
isSuppressed(element) {
|
|
213
|
+
return !element || defaultIsSuppressed(element);
|
|
214
|
+
}
|
|
215
|
+
isRegistered(element) {
|
|
216
|
+
return !element || this.getRegisteredElements().has(element);
|
|
217
|
+
}
|
|
183
218
|
findFocusedCell(focusedElement) {
|
|
184
219
|
var _a, _b;
|
|
185
220
|
const cellElement = focusedElement.closest('td,th');
|
|
186
221
|
const rowElement = cellElement === null || cellElement === void 0 ? void 0 : cellElement.closest('tr');
|
|
187
222
|
if (!cellElement || !rowElement) {
|
|
188
|
-
return
|
|
223
|
+
return this.focusedCell;
|
|
189
224
|
}
|
|
190
225
|
const colIndex = parseInt((_a = cellElement.getAttribute('aria-colindex')) !== null && _a !== void 0 ? _a : '');
|
|
191
226
|
const rowIndex = parseInt((_b = rowElement.getAttribute('aria-rowindex')) !== null && _b !== void 0 ? _b : '');
|
|
192
227
|
if (isNaN(colIndex) || isNaN(rowIndex)) {
|
|
193
|
-
return
|
|
228
|
+
return this.focusedCell;
|
|
194
229
|
}
|
|
195
|
-
const cellFocusables =
|
|
230
|
+
const cellFocusables = this.getFocusablesFrom(cellElement);
|
|
196
231
|
const elementIndex = cellFocusables.indexOf(focusedElement);
|
|
197
232
|
return { rowIndex, colIndex, rowElement, cellElement, element: focusedElement, elementIndex };
|
|
198
233
|
}
|
|
199
|
-
/**
|
|
200
|
-
* Finds element to be focused next. The focus can transition between cells or interactive elements inside cells.
|
|
201
|
-
*/
|
|
202
234
|
getNextFocusable(from, delta) {
|
|
203
235
|
var _a;
|
|
204
236
|
// Find next row to move focus into (can be null if the top/bottom is reached).
|
|
@@ -208,7 +240,7 @@ class GridNavigationProcessor {
|
|
|
208
240
|
return null;
|
|
209
241
|
}
|
|
210
242
|
// Return next interactive cell content element if available.
|
|
211
|
-
const cellFocusables =
|
|
243
|
+
const cellFocusables = this.getFocusablesFrom(from.cellElement);
|
|
212
244
|
const nextElementIndex = from.elementIndex + delta.x;
|
|
213
245
|
if (delta.x && from.elementIndex !== -1 && 0 <= nextElementIndex && nextElementIndex < cellFocusables.length) {
|
|
214
246
|
return cellFocusables[nextElementIndex];
|
|
@@ -224,27 +256,27 @@ class GridNavigationProcessor {
|
|
|
224
256
|
return null;
|
|
225
257
|
}
|
|
226
258
|
// Return cell interactive content or the cell itself.
|
|
227
|
-
const targetCellFocusables =
|
|
259
|
+
const targetCellFocusables = this.getFocusablesFrom(targetCell);
|
|
228
260
|
const focusIndex = delta.x < 0 ? targetCellFocusables.length - 1 : delta.x > 0 ? 0 : from.elementIndex;
|
|
229
261
|
const focusTarget = (_a = targetCellFocusables[focusIndex]) !== null && _a !== void 0 ? _a : targetCell;
|
|
230
262
|
return focusTarget;
|
|
231
263
|
}
|
|
232
|
-
|
|
233
|
-
* Makes the cell element, the first interactive element or the first cell of the table user-focusable.
|
|
234
|
-
*/
|
|
235
|
-
ensureSingleFocusable() {
|
|
264
|
+
getSingleFocusable() {
|
|
236
265
|
var _a;
|
|
237
|
-
const
|
|
238
|
-
muteElementFocusables(this.table, cellSuppressed);
|
|
266
|
+
const cell = this.focusedCell;
|
|
239
267
|
const firstTableCell = this.table.querySelector('td,th');
|
|
240
268
|
// A single element of the table is made user-focusable.
|
|
241
269
|
// It defaults to the first interactive element of the first cell or the first cell itself otherwise.
|
|
242
|
-
let focusTarget = (_a = (firstTableCell &&
|
|
270
|
+
let focusTarget = (_a = (firstTableCell && this.getFocusablesFrom(firstTableCell)[0])) !== null && _a !== void 0 ? _a : firstTableCell;
|
|
243
271
|
// When a navigation-focused element is present in the table it is used for user-navigation instead.
|
|
244
|
-
if (
|
|
245
|
-
focusTarget = this.getNextFocusable(
|
|
272
|
+
if (cell) {
|
|
273
|
+
focusTarget = this.getNextFocusable(cell, { x: 0, y: 0 });
|
|
246
274
|
}
|
|
247
|
-
|
|
275
|
+
return focusTarget;
|
|
276
|
+
}
|
|
277
|
+
getFocusablesFrom(target) {
|
|
278
|
+
const registeredElements = this.getRegisteredElements();
|
|
279
|
+
return getAllFocusables(target).filter(el => registeredElements.has(el));
|
|
248
280
|
}
|
|
249
281
|
}
|
|
250
282
|
//# sourceMappingURL=grid-navigation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid-navigation.js","sourceRoot":"lib/default/","sources":["table/table-role/grid-navigation.tsx"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,0BAA0B,EAC1B,8BAA8B,EAC9B,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAClF,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAEhE;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAuB;IAC9G,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,uBAAuB,EAAE,EAAE,EAAE,CAAC,CAAC;IAExE,MAAM,cAAc,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAEnD,wGAAwG;IACxG,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,kBAAkB,EAAE;YACtB,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;YAC/B,KAAK,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SACrC;QACD,OAAO,GAAG,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;IACxC,CAAC,EAAE,CAAC,kBAAkB,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC,CAAC;IAEzD,4CAA4C;IAC5C,SAAS,CAAC,GAAG,EAAE;QACb,cAAc,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtC,CAAC,EAAE,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE/B,0CAA0C;IAC1C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,kBAAkB,EAAE;YACtB,cAAc,CAAC,OAAO,EAAE,CAAC;SAC1B;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,0CAAG,QAAQ,CAAI,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,uBAAuB;IAA7B;QACE,QAAQ;QACA,cAAS,GAAG,CAAC,CAAC;QACd,WAAM,GAA4B,IAAI,CAAC;QAE/C,QAAQ;QACA,gBAAW,GAAuB,IAAI,CAAC;QAuDvC,cAAS,GAAG,CAAC,KAAiB,EAAE,EAAE;;YACxC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,YAAY,WAAW,CAAC,EAAE;gBAC1C,OAAO;aACR;YAED,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAChD,IAAI,CAAC,IAAI,EAAE;gBACT,OAAO;aACR;YAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YAExB,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAE7B,uFAAuF;YACvF,yEAAyE;YACzE,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,WAAW,EAAE;gBACrC,MAAA,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,0CAAE,KAAK,EAAE,CAAC;aAC9C;QACH,CAAC,CAAC;QAEM,eAAU,GAAG,GAAG,EAAE;YACxB,6HAA6H;YAC7H,uEAAuE;YACvE,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE;oBAC1E,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;iBACpD;YACH,CAAC,EAAE,CAAC,CAAC,CAAC;QACR,CAAC,CAAC;QAEM,cAAS,GAAG,CAAC,KAAoB,EAAE,EAAE;YAC3C,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;gBACrB,OAAO;aACR;YAED,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,mBAAmB,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;YAElE,IAAI,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC;YACxB,IAAI,mBAAmB,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE;gBAC9C,GAAG,GAAG,CAAC,GAAG,CAAC;aACZ;iBAAM,IAAI,mBAAmB,EAAE;gBAC9B,OAAO;aACR;YAED,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;YAC9B,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAC;YAC5C,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAC;YAE5C,+DAA+D;YAC/D,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;gBACnC,OAAO;aACR;YAED,QAAQ,GAAG,EAAE;gBACX,KAAK,OAAO,CAAC,EAAE;oBACb,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAEjD,KAAK,OAAO,CAAC,IAAI;oBACf,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAEhD,KAAK,OAAO,CAAC,IAAI;oBACf,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAEjD,KAAK,OAAO,CAAC,KAAK;oBAChB,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAEhD,KAAK,OAAO,CAAC,MAAM;oBACjB,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAE7D,KAAK,OAAO,CAAC,QAAQ;oBACnB,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAE5D,KAAK,OAAO,CAAC,IAAI;oBACf,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;gBAEzD,KAAK,OAAO,CAAC,GAAG;oBACd,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;gBAEzD,KAAK,CAAC,OAAO,CAAC,IAAI;oBAChB,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;gBAElE,KAAK,CAAC,OAAO,CAAC,GAAG;oBACf,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;gBAElE;oBACE,OAAO;aACV;QACH,CAAC,CAAC;IAuFJ,CAAC;IAlPQ,IAAI,CAAC,KAAuB;QACjC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QAEpB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAEvD,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAE7B,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE;YAClB,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1D,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAC5D,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YAE1D,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC,CAAC;IACJ,CAAC;IAEM,OAAO;QACZ,iCAAiC;IACnC,CAAC;IAEM,MAAM,CAAC,EAAE,QAAQ,EAAwB;QAC9C,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC5B,CAAC;IAEM,OAAO;QACZ,IAAI,IAAI,CAAC,MAAM,EAAE;YACf,iFAAiF;YACjF,IAAI,IAAI,CAAC,WAAW,EAAE;gBACpB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;aACnE;YAED,gDAAgD;YAChD,IAAI,CAAC,qBAAqB,EAAE,CAAC;SAC9B;IACH,CAAC;IAED,IAAY,QAAQ;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,IAAY,KAAK;QACf,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;SAChG;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAEO,YAAY,CAAC,cAA2B;QAC9C,OAAO,mBAAmB,CAAC,cAAc,CAAC,CAAC;IAC7C,CAAC;IA0GO,WAAW,CAAC,IAAiB,EAAE,KAA+B;;QACpE,MAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,0CAAE,KAAK,EAAE,CAAC;IAC9C,CAAC;IAED;;;OAGG;IACK,eAAe,CAAC,cAA2B;;QACjD,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,CAAgC,CAAC;QACnF,MAAM,UAAU,GAAG,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAE9C,IAAI,CAAC,WAAW,IAAI,CAAC,UAAU,EAAE;YAC/B,OAAO,IAAI,CAAC;SACb;QAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAA,WAAW,CAAC,YAAY,CAAC,eAAe,CAAC,mCAAI,EAAE,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAA,UAAU,CAAC,YAAY,CAAC,eAAe,CAAC,mCAAI,EAAE,CAAC,CAAC;QAC1E,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE;YACtC,OAAO,IAAI,CAAC;SACb;QAED,MAAM,cAAc,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;QAClD,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAE5D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC;IAChG,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,IAAiB,EAAE,KAA+B;;QACzE,+EAA+E;QAC/E,MAAM,kBAAkB,GAAG,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,0BAA0B,CAAC,IAAI,CAAC,KAAK,EAAE,kBAAkB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QACtF,IAAI,CAAC,SAAS,EAAE;YACd,OAAO,IAAI,CAAC;SACb;QAED,6DAA6D;QAC7D,MAAM,cAAc,GAAG,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvD,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC;QACrD,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,YAAY,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,gBAAgB,IAAI,gBAAgB,GAAG,cAAc,CAAC,MAAM,EAAE;YAC5G,OAAO,cAAc,CAAC,gBAAgB,CAAC,CAAC;SACzC;QAED,8FAA8F;QAC9F,MAAM,kBAAkB,GAAG,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,8BAA8B,CAAC,SAAS,EAAE,kBAAkB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC1F,IAAI,CAAC,UAAU,EAAE;YACf,OAAO,IAAI,CAAC;SACb;QAED,4FAA4F;QAC5F,IAAI,UAAU,KAAK,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;YACpD,OAAO,IAAI,CAAC;SACb;QAED,sDAAsD;QACtD,MAAM,oBAAoB,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;QACvG,MAAM,WAAW,GAAG,MAAA,oBAAoB,CAAC,UAAU,CAAC,mCAAI,UAAU,CAAC;QACnE,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;OAEG;IACK,qBAAqB;;QAC3B,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC9F,qBAAqB,CAAC,IAAI,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;QAElD,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAgC,CAAC;QAExF,wDAAwD;QACxD,qGAAqG;QACrG,IAAI,WAAW,GAAuB,MAAA,CAAC,cAAc,IAAI,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,mCAAI,cAAc,CAAC;QAE7G,oGAAoG;QACpG,IAAI,IAAI,CAAC,WAAW,EAAE;YACpB,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACvE;QAED,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC9B,CAAC;CACF","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 muteElementFocusables,\n restoreElementFocusables,\n getFirstFocusable,\n getFocusables,\n findTableRowByAriaRowIndex,\n findTableRowCellByAriaColIndex,\n setTabIndex,\n} from './utils';\nimport { FocusedCell, GridNavigationProps } from './interfaces';\nimport { KeyCode } from '../../internal/keycode';\nimport { useStableCallback } from '@cloudscape-design/component-toolkit/internal';\nimport React from 'react';\nimport { nodeBelongs } from '../../internal/utils/node-belongs';\n\n/**\n * Makes table navigable with keyboard commands.\n * See grid-navigation.md\n */\nexport function GridNavigationProvider({ keyboardNavigation, pageSize, getTable, children }: GridNavigationProps) {\n const gridNavigation = useMemo(() => new GridNavigationProcessor(), []);\n\n const getTableStable = useStableCallback(getTable);\n\n // Initialize the processor with the table container assuming it is mounted synchronously and only once.\n useEffect(() => {\n if (keyboardNavigation) {\n const table = getTableStable();\n table && gridNavigation.init(table);\n }\n return () => gridNavigation.cleanup();\n }, [keyboardNavigation, gridNavigation, getTableStable]);\n\n // Notify the processor of the props change.\n useEffect(() => {\n gridNavigation.update({ pageSize });\n }, [gridNavigation, pageSize]);\n\n // Notify the processor of the new render.\n useEffect(() => {\n if (keyboardNavigation) {\n gridNavigation.refresh();\n }\n });\n\n return <>{children}</>;\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 explicitly.\n */\nclass GridNavigationProcessor {\n // Props\n private _pageSize = 0;\n private _table: null | HTMLTableElement = null;\n\n // State\n private focusedCell: null | FocusedCell = null;\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 this.ensureSingleFocusable();\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 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 public refresh() {\n if (this._table) {\n // Update focused cell indices in case table rows, columns, or firstIndex change.\n if (this.focusedCell) {\n this.focusedCell = this.findFocusedCell(this.focusedCell.element);\n }\n\n // Ensure newly added elements if any are muted.\n this.ensureSingleFocusable();\n }\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: GridNavigationProcessor is used before initialization.');\n }\n return this._table;\n }\n\n private isSuppressed(focusedElement: HTMLElement): boolean {\n return defaultIsSuppressed(focusedElement);\n }\n\n private onFocusin = (event: FocusEvent) => {\n if (!(event.target instanceof HTMLElement)) {\n return;\n }\n\n const cell = this.findFocusedCell(event.target);\n if (!cell) {\n return;\n }\n\n this.focusedCell = cell;\n\n this.ensureSingleFocusable();\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 // When focus leaves the cell and the cell no longer belong to the table it indicates the focused element has been unmounted.\n // In that case the focus needs to be restored on the same coordinates.\n setTimeout(() => {\n if (this.focusedCell && !nodeBelongs(this.table, this.focusedCell.element)) {\n this.moveFocusBy(this.focusedCell, { x: 0, y: 0 });\n }\n }, 0);\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 this.moveFocusBy(from, { y: -1, x: 0 });\n\n case KeyCode.down:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 1, x: 0 });\n\n case KeyCode.left:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: -1 });\n\n case KeyCode.right:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: 1 });\n\n case KeyCode.pageUp:\n event.preventDefault();\n return this.moveFocusBy(from, { y: -this.pageSize, x: 0 });\n\n case KeyCode.pageDown:\n event.preventDefault();\n return this.moveFocusBy(from, { y: this.pageSize, x: 0 });\n\n case KeyCode.home:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: minExtreme });\n\n case KeyCode.end:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: maxExtreme });\n\n case -KeyCode.home:\n event.preventDefault();\n return this.moveFocusBy(from, { y: minExtreme, x: minExtreme });\n\n case -KeyCode.end:\n event.preventDefault();\n return this.moveFocusBy(from, { y: maxExtreme, x: maxExtreme });\n\n default:\n return;\n }\n };\n\n private moveFocusBy(cell: FocusedCell, delta: { x: number; y: number }) {\n this.getNextFocusable(cell, delta)?.focus();\n }\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 */\n private findFocusedCell(focusedElement: HTMLElement): null | FocusedCell {\n const cellElement = focusedElement.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(focusedElement);\n\n return { rowIndex, colIndex, rowElement, cellElement, element: focusedElement, elementIndex };\n }\n\n /**\n * Finds element to be focused next. The focus can transition between cells or interactive elements inside cells.\n */\n private getNextFocusable(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(this.table, targetAriaRowIndex, delta.y);\n if (!targetRow) {\n return null;\n }\n\n // Return 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 return cellFocusables[nextElementIndex];\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 null;\n }\n\n // When target cell matches the current cell it means we reached the left or right boundary.\n if (targetCell === from.cellElement && delta.x !== 0) {\n return null;\n }\n\n // Return 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 return focusTarget;\n }\n\n /**\n * Makes the cell element, the first interactive element or the first cell of the table user-focusable.\n */\n private ensureSingleFocusable() {\n const cellSuppressed = this.focusedCell ? this.isSuppressed(this.focusedCell.element) : false;\n muteElementFocusables(this.table, cellSuppressed);\n\n const firstTableCell = this.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 (this.focusedCell) {\n focusTarget = this.getNextFocusable(this.focusedCell, { x: 0, y: 0 });\n }\n\n setTabIndex(focusTarget, 0);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"grid-navigation.js","sourceRoot":"lib/default/","sources":["table/table-role/grid-navigation.tsx"],"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 React from 'react';\nimport { useEffect, useMemo } from 'react';\nimport { defaultIsSuppressed, findTableRowByAriaRowIndex, findTableRowCellByAriaColIndex } from './utils';\nimport { FocusedCell, GridNavigationProps } from './interfaces';\nimport { KeyCode } from '../../internal/keycode';\nimport { useStableCallback } from '@cloudscape-design/component-toolkit/internal';\nimport { nodeBelongs } from '../../internal/utils/node-belongs';\nimport { getAllFocusables } from '../../internal/components/focus-lock/utils';\nimport {\n SingleTabStopNavigationContext,\n FocusableDefinition,\n FocusableChangeHandler,\n} from '../../internal/context/single-tab-stop-navigation-context';\n\n/**\n * Makes table navigable with keyboard commands.\n * See grid-navigation.md\n */\nexport function GridNavigationProvider({ keyboardNavigation, pageSize, getTable, children }: GridNavigationProps) {\n const gridNavigation = useMemo(() => new GridNavigationProcessor(), []);\n\n const getTableStable = useStableCallback(getTable);\n\n // Initialize the processor with the table container assuming it is mounted synchronously and only once.\n useEffect(() => {\n if (keyboardNavigation) {\n const table = getTableStable();\n table && gridNavigation.init(table);\n }\n return () => gridNavigation.cleanup();\n }, [keyboardNavigation, gridNavigation, getTableStable]);\n\n // Notify the processor of the props change.\n useEffect(() => {\n gridNavigation.update({ pageSize });\n }, [gridNavigation, pageSize]);\n\n // Notify the processor of the new render.\n useEffect(() => {\n if (keyboardNavigation) {\n gridNavigation.refresh();\n }\n });\n\n return (\n <SingleTabStopNavigationContext.Provider\n value={{\n navigationActive: keyboardNavigation,\n registerFocusable: gridNavigation.registerFocusable,\n }}\n >\n {children}\n </SingleTabStopNavigationContext.Provider>\n );\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 explicitly.\n */\nclass GridNavigationProcessor {\n // Props\n private _pageSize = 0;\n private _table: null | HTMLTableElement = null;\n\n // State\n private focusedCell: null | FocusedCell = null;\n private focusables = new Set<FocusableDefinition>();\n private focusHandlers = new Map<FocusableDefinition, FocusableChangeHandler>();\n private focusTarget: null | Element = null;\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 this.updateFocusTarget();\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 this.focusables.forEach(this.unregisterFocusable);\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 public refresh() {\n // Timeout ensures the newly rendered content elements are registered.\n setTimeout(() => {\n if (this._table) {\n // Update focused cell indices in case table rows, columns, or firstIndex change.\n if (this.focusedCell) {\n this.focusedCell = this.findFocusedCell(this.focusedCell.element);\n }\n this.updateFocusTarget();\n }\n }, 0);\n }\n\n public registerFocusable = (focusable: FocusableDefinition, changeHandler: FocusableChangeHandler) => {\n this.focusables.add(focusable);\n this.focusHandlers.set(focusable, changeHandler);\n changeHandler(this.focusTarget, this.isSuppressed(focusable.current));\n return () => this.unregisterFocusable(focusable);\n };\n\n public unregisterFocusable = (focusable: FocusableDefinition) => {\n this.focusables.delete(focusable);\n this.focusHandlers.delete(focusable);\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: GridNavigationProcessor is used before initialization.');\n }\n return this._table;\n }\n\n private onFocusin = (event: FocusEvent) => {\n if (!(event.target instanceof HTMLElement)) {\n return;\n }\n\n const cell = this.findFocusedCell(event.target);\n if (!cell) {\n return;\n }\n\n this.focusedCell = cell;\n\n this.updateFocusTarget();\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 this.getFocusablesFrom(cell.cellElement)[0]?.focus();\n }\n };\n\n private onFocusout = () => {\n // When focus leaves the cell and the cell no longer belong to the table it indicates the focused element has been unmounted.\n // In that case the focus needs to be restored on the same coordinates.\n setTimeout(() => {\n if (this.focusedCell && !nodeBelongs(this.table, this.focusedCell.element)) {\n this.moveFocusBy(this.focusedCell, { x: 0, y: 0 });\n }\n }, 0);\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 if (this.isSuppressed(document.activeElement) || !this.isRegistered(document.activeElement)) {\n return;\n }\n\n switch (key) {\n case KeyCode.up:\n event.preventDefault();\n return this.moveFocusBy(from, { y: -1, x: 0 });\n\n case KeyCode.down:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 1, x: 0 });\n\n case KeyCode.left:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: -1 });\n\n case KeyCode.right:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: 1 });\n\n case KeyCode.pageUp:\n event.preventDefault();\n return this.moveFocusBy(from, { y: -this.pageSize, x: 0 });\n\n case KeyCode.pageDown:\n event.preventDefault();\n return this.moveFocusBy(from, { y: this.pageSize, x: 0 });\n\n case KeyCode.home:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: minExtreme });\n\n case KeyCode.end:\n event.preventDefault();\n return this.moveFocusBy(from, { y: 0, x: maxExtreme });\n\n case -KeyCode.home:\n event.preventDefault();\n return this.moveFocusBy(from, { y: minExtreme, x: minExtreme });\n\n case -KeyCode.end:\n event.preventDefault();\n return this.moveFocusBy(from, { y: maxExtreme, x: maxExtreme });\n\n default:\n return;\n }\n };\n\n private moveFocusBy(cell: FocusedCell, delta: { x: number; y: number }) {\n this.getNextFocusable(cell, delta)?.focus();\n }\n\n private updateFocusTarget() {\n this.focusTarget = this.getSingleFocusable();\n this.focusables.forEach(focusable => {\n const element = focusable.current;\n const handler = this.focusHandlers.get(focusable)!;\n handler(this.focusTarget, this.isSuppressed(element));\n });\n }\n\n private isSuppressed(element: null | Element) {\n return !element || defaultIsSuppressed(element);\n }\n\n private isRegistered(element: null | Element) {\n return !element || this.getRegisteredElements().has(element);\n }\n\n private getRegisteredElements = (): Set<Element> => {\n const registeredElements = new Set<Element>();\n for (const focusable of this.focusables) {\n if (focusable.current) {\n registeredElements.add(focusable.current);\n }\n }\n return registeredElements;\n };\n\n private findFocusedCell(focusedElement: HTMLElement): null | FocusedCell {\n const cellElement = focusedElement.closest('td,th') as null | HTMLTableCellElement;\n const rowElement = cellElement?.closest('tr');\n\n if (!cellElement || !rowElement) {\n return this.focusedCell;\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 this.focusedCell;\n }\n\n const cellFocusables = this.getFocusablesFrom(cellElement);\n const elementIndex = cellFocusables.indexOf(focusedElement);\n\n return { rowIndex, colIndex, rowElement, cellElement, element: focusedElement, elementIndex };\n }\n\n private getNextFocusable(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(this.table, targetAriaRowIndex, delta.y);\n if (!targetRow) {\n return null;\n }\n\n // Return next interactive cell content element if available.\n const cellFocusables = this.getFocusablesFrom(from.cellElement);\n const nextElementIndex = from.elementIndex + delta.x;\n if (delta.x && from.elementIndex !== -1 && 0 <= nextElementIndex && nextElementIndex < cellFocusables.length) {\n return cellFocusables[nextElementIndex];\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 null;\n }\n\n // When target cell matches the current cell it means we reached the left or right boundary.\n if (targetCell === from.cellElement && delta.x !== 0) {\n return null;\n }\n\n // Return cell interactive content or the cell itself.\n const targetCellFocusables = this.getFocusablesFrom(targetCell);\n const focusIndex = delta.x < 0 ? targetCellFocusables.length - 1 : delta.x > 0 ? 0 : from.elementIndex;\n const focusTarget = targetCellFocusables[focusIndex] ?? targetCell;\n return focusTarget;\n }\n\n private getSingleFocusable() {\n const cell = this.focusedCell;\n const firstTableCell = this.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 =\n (firstTableCell && this.getFocusablesFrom(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) {\n focusTarget = this.getNextFocusable(cell, { x: 0, y: 0 });\n }\n\n return focusTarget;\n }\n\n private getFocusablesFrom(target: HTMLElement) {\n const registeredElements = this.getRegisteredElements();\n return getAllFocusables(target).filter(el => registeredElements.has(el));\n }\n}\n"]}
|
|
@@ -1,22 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Makes all element focusable children pseudo-focusable unless the grid navigation is suppressed.
|
|
3
|
-
*/
|
|
4
|
-
export declare function muteElementFocusables(element: HTMLElement, suppressed: boolean): void;
|
|
5
|
-
/**
|
|
6
|
-
* This cleanup code ensures all cells are no longer focusable but the interactive elements are.
|
|
7
|
-
* Currently there are no use cases for it as we don't expect the navigation to be used conditionally.
|
|
8
|
-
*/
|
|
9
|
-
export declare function restoreElementFocusables(element: HTMLTableElement): void;
|
|
10
1
|
/**
|
|
11
2
|
* Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation attribute.
|
|
12
3
|
* This is used to suppress navigation for interactive content without a need to use a custom suppression check.
|
|
13
4
|
*/
|
|
14
|
-
export declare function defaultIsSuppressed(target:
|
|
15
|
-
/**
|
|
16
|
-
* Returns actually focusable or pseudo-focusable elements to find navigation targets.
|
|
17
|
-
*/
|
|
18
|
-
export declare function getFocusables(element: HTMLElement): HTMLElement[];
|
|
19
|
-
export declare function getFirstFocusable(element: HTMLElement): HTMLElement | null;
|
|
5
|
+
export declare function defaultIsSuppressed(target: Element): boolean;
|
|
20
6
|
/**
|
|
21
7
|
* Finds the closest row to the targetAriaRowIndex+delta in the direction of delta.
|
|
22
8
|
*/
|
|
@@ -25,5 +11,4 @@ export declare function findTableRowByAriaRowIndex(table: HTMLTableElement, targ
|
|
|
25
11
|
* Finds the closest column to the targetAriaColIndex+delta in the direction of delta.
|
|
26
12
|
*/
|
|
27
13
|
export declare function findTableRowCellByAriaColIndex(tableRow: HTMLTableRowElement, targetAriaColIndex: number, delta: number): HTMLTableCellElement | null;
|
|
28
|
-
export declare function setTabIndex(element: null | HTMLElement, tabIndex: number): void;
|
|
29
14
|
//# 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":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,WAiBlD;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,8BAqB5G;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,mBAAmB,EAC7B,kBAAkB,EAAE,MAAM,EAC1B,KAAK,EAAE,MAAM,+BAsBd"}
|
|
@@ -1,44 +1,5 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { getFocusables as getActualFocusables } from '../../internal/components/focus-lock/utils';
|
|
4
|
-
// For the grid to have a single Tab stop all interactive element indices are updated to be -999.
|
|
5
|
-
// The elements having tab index -999 are eligible for keyboard navigation but not for Tab navigation.
|
|
6
|
-
const PSEUDO_FOCUSABLE_TAB_INDEX = -999;
|
|
7
|
-
const FOCUSABLES_SELECTOR = `[tabIndex="0"],[tabIndex="${PSEUDO_FOCUSABLE_TAB_INDEX}"]`;
|
|
8
|
-
/**
|
|
9
|
-
* Makes all element focusable children pseudo-focusable unless the grid navigation is suppressed.
|
|
10
|
-
*/
|
|
11
|
-
export function muteElementFocusables(element, suppressed) {
|
|
12
|
-
// When grid navigation is suppressed all interactive elements and all cells focus is unmuted to unblock Tab navigation.
|
|
13
|
-
// Leaving the interactive widget using Tab navigation moves the focus to the current or adjacent cell and un-suppresses
|
|
14
|
-
// the navigation when implemented correctly.
|
|
15
|
-
if (suppressed) {
|
|
16
|
-
for (const focusable of getFocusables(element)) {
|
|
17
|
-
setTabIndex(focusable, 0);
|
|
18
|
-
}
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
// Assigning pseudo-focusable tab index to all cells and all interactive elements makes them focusable with grid navigation.
|
|
22
|
-
for (const focusable of getActualFocusables(element)) {
|
|
23
|
-
if (focusable !== document.activeElement) {
|
|
24
|
-
setTabIndex(focusable, PSEUDO_FOCUSABLE_TAB_INDEX);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* This cleanup code ensures all cells are no longer focusable but the interactive elements are.
|
|
30
|
-
* Currently there are no use cases for it as we don't expect the navigation to be used conditionally.
|
|
31
|
-
*/
|
|
32
|
-
export function restoreElementFocusables(element) {
|
|
33
|
-
for (const focusable of getFocusables(element)) {
|
|
34
|
-
if (focusable instanceof HTMLTableCellElement) {
|
|
35
|
-
setTabIndex(focusable, -1);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
setTabIndex(focusable, 0);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
3
|
/**
|
|
43
4
|
* Returns true if the target element or one of its parents is a dialog or is marked with data-awsui-table-suppress-navigation attribute.
|
|
44
5
|
* This is used to suppress navigation for interactive content without a need to use a custom suppression check.
|
|
@@ -59,15 +20,6 @@ export function defaultIsSuppressed(target) {
|
|
|
59
20
|
}
|
|
60
21
|
return false;
|
|
61
22
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Returns actually focusable or pseudo-focusable elements to find navigation targets.
|
|
64
|
-
*/
|
|
65
|
-
export function getFocusables(element) {
|
|
66
|
-
return Array.from(element.querySelectorAll(FOCUSABLES_SELECTOR));
|
|
67
|
-
}
|
|
68
|
-
export function getFirstFocusable(element) {
|
|
69
|
-
return element.querySelector(FOCUSABLES_SELECTOR);
|
|
70
|
-
}
|
|
71
23
|
/**
|
|
72
24
|
* Finds the closest row to the targetAriaRowIndex+delta in the direction of delta.
|
|
73
25
|
*/
|
|
@@ -118,9 +70,4 @@ export function findTableRowCellByAriaColIndex(tableRow, targetAriaColIndex, del
|
|
|
118
70
|
}
|
|
119
71
|
return targetCell;
|
|
120
72
|
}
|
|
121
|
-
export function setTabIndex(element, tabIndex) {
|
|
122
|
-
if (element && element.tabIndex !== tabIndex) {
|
|
123
|
-
element.tabIndex = tabIndex;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
73
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"lib/default/","sources":["table/table-role/utils.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAe;IACjD,IAAI,OAAO,GAAmB,MAAM,CAAC;IACrC,OAAO,OAAO,EAAE;QACd,0GAA0G;QAC1G,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAC9C,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI,EAAE;YACxC,OAAO,KAAK,CAAC;SACd;QACD,IACE,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,QAAQ;YACzC,OAAO,CAAC,YAAY,CAAC,sCAAsC,CAAC,KAAK,MAAM,EACvE;YACA,OAAO,IAAI,CAAC;SACb;QACD,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC;KACjC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAAuB,EAAE,kBAA0B,EAAE,KAAa;;IAC3G,IAAI,SAAS,GAA+B,IAAI,CAAC;IACjD,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC5E,IAAI,KAAK,GAAG,CAAC,EAAE;QACb,WAAW,CAAC,OAAO,EAAE,CAAC;KACvB;IACD,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE;QACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAA,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,mCAAI,EAAE,CAAC,CAAC;QACvE,SAAS,GAAG,OAA8B,CAAC;QAE3C,IAAI,QAAQ,KAAK,kBAAkB,EAAE;YACnC,MAAM;SACP;QACD,IAAI,KAAK,IAAI,CAAC,IAAI,QAAQ,GAAG,kBAAkB,EAAE;YAC/C,MAAM;SACP;QACD,IAAI,KAAK,GAAG,CAAC,IAAI,QAAQ,GAAG,kBAAkB,EAAE;YAC9C,MAAM;SACP;KACF;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,8BAA8B,CAC5C,QAA6B,EAC7B,kBAA0B,EAC1B,KAAa;;IAEb,IAAI,UAAU,GAAgC,IAAI,CAAC;IACnD,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,qCAAqC,CAAC,CAAC,CAAC;IAClG,IAAI,KAAK,GAAG,CAAC,EAAE;QACb,YAAY,CAAC,OAAO,EAAE,CAAC;KACxB;IACD,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE;QAClC,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAA,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,mCAAI,EAAE,CAAC,CAAC;QAC1E,UAAU,GAAG,OAA+B,CAAC;QAE7C,IAAI,WAAW,KAAK,kBAAkB,EAAE;YACtC,MAAM;SACP;QACD,IAAI,KAAK,IAAI,CAAC,IAAI,WAAW,GAAG,kBAAkB,EAAE;YAClD,MAAM;SACP;QACD,IAAI,KAAK,GAAG,CAAC,IAAI,WAAW,GAAG,kBAAkB,EAAE;YACjD,MAAM;SACP;KACF;IACD,OAAO,UAAU,CAAC;AACpB,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\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: Element) {\n let current: null | Element = 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 * Finds the closest row to the targetAriaRowIndex+delta in the direction of delta.\n */\nexport function 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 */\nexport function findTableRowCellByAriaColIndex(\n tableRow: HTMLTableRowElement,\n targetAriaColIndex: number,\n delta: number\n) {\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"]}
|