@cloudscape-design/components 3.0.1073 → 3.0.1074
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app-layout/visual-refresh-toolbar/state/props-merger.js +3 -3
- package/app-layout/visual-refresh-toolbar/state/props-merger.js.map +1 -1
- package/internal/base-component/styles.scoped.css +1 -1
- package/internal/context/single-tab-stop-navigation-context.d.ts +2 -0
- package/internal/context/single-tab-stop-navigation-context.d.ts.map +1 -1
- package/internal/context/single-tab-stop-navigation-context.js +35 -4
- package/internal/context/single-tab-stop-navigation-context.js.map +1 -1
- package/internal/environment.js +2 -2
- package/internal/environment.json +2 -2
- package/internal/hooks/use-virtual/index.d.ts.map +1 -1
- package/internal/hooks/use-virtual/index.js +5 -1
- package/internal/hooks/use-virtual/index.js.map +1 -1
- package/internal/manifest.json +1 -1
- package/package.json +1 -1
|
@@ -9,10 +9,10 @@ function checkAlreadyExists(value, propName) {
|
|
|
9
9
|
return false;
|
|
10
10
|
}
|
|
11
11
|
export const mergeProps = (ownProps, additionalProps) => {
|
|
12
|
-
var _a
|
|
12
|
+
var _a;
|
|
13
13
|
const toolbar = {};
|
|
14
14
|
for (const props of [ownProps, ...additionalProps]) {
|
|
15
|
-
toolbar.ariaLabels = Object.assign((
|
|
15
|
+
toolbar.ariaLabels = Object.assign(Object.assign({}, toolbar.ariaLabels), props.ariaLabels);
|
|
16
16
|
if (props.drawers &&
|
|
17
17
|
props.drawers.some(drawer => drawer.trigger) &&
|
|
18
18
|
!checkAlreadyExists(!!toolbar.drawers, 'tools or drawers')) {
|
|
@@ -34,7 +34,7 @@ export const mergeProps = (ownProps, additionalProps) => {
|
|
|
34
34
|
toolbar.onNavigationToggle = props.onNavigationToggle;
|
|
35
35
|
}
|
|
36
36
|
if (props.splitPanel &&
|
|
37
|
-
((
|
|
37
|
+
((_a = props.splitPanelToggleProps) === null || _a === void 0 ? void 0 : _a.displayed) &&
|
|
38
38
|
!checkAlreadyExists(!!toolbar.hasSplitPanel, 'splitPanel')) {
|
|
39
39
|
toolbar.hasSplitPanel = true;
|
|
40
40
|
toolbar.splitPanelFocusRef = props.splitPanelFocusRef;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"props-merger.js","sourceRoot":"","sources":["../../../../../src/app-layout/visual-refresh-toolbar/state/props-merger.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,+CAA+C,CAAC;AAMzE,SAAS,kBAAkB,CAAC,KAAc,EAAE,QAAgB;IAC1D,IAAI,KAAK,EAAE;QACT,QAAQ,CACN,WAAW,EACX,4DAA4D,QAAQ,2CAA2C,CAChH,CAAC;QACF,OAAO,IAAI,CAAC;KACb;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE;;IAClE,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,CAAC,QAAQ,EAAE,GAAG,eAAe,CAAC,EAAE;QAClD,OAAO,CAAC,UAAU,
|
|
1
|
+
{"version":3,"file":"props-merger.js","sourceRoot":"","sources":["../../../../../src/app-layout/visual-refresh-toolbar/state/props-merger.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\nimport { warnOnce } from '@cloudscape-design/component-toolkit/internal';\n\nimport { AppLayoutInternalProps, AppLayoutPendingState } from '../interfaces';\nimport { ToolbarProps } from '../toolbar';\nimport { MergeProps, SharedProps } from './interfaces';\n\nfunction checkAlreadyExists(value: boolean, propName: string) {\n if (value) {\n warnOnce(\n 'AppLayout',\n `Another app layout instance on this page already defines ${propName} property. This instance will be ignored.`\n );\n return true;\n }\n return false;\n}\n\nexport const mergeProps: MergeProps = (ownProps, additionalProps) => {\n const toolbar: ToolbarProps = {};\n for (const props of [ownProps, ...additionalProps]) {\n toolbar.ariaLabels = { ...toolbar.ariaLabels, ...props.ariaLabels };\n if (\n props.drawers &&\n props.drawers.some(drawer => drawer.trigger) &&\n !checkAlreadyExists(!!toolbar.drawers, 'tools or drawers')\n ) {\n toolbar.drawers = props.drawers;\n toolbar.activeDrawerId = props.activeDrawerId;\n toolbar.drawersFocusRef = props.drawersFocusRef;\n toolbar.onActiveDrawerChange = props.onActiveDrawerChange;\n }\n if (props.globalDrawers && !checkAlreadyExists(!!toolbar.globalDrawers, 'globalDrawers')) {\n toolbar.globalDrawersFocusControl = props.globalDrawersFocusControl;\n toolbar.globalDrawers = props.globalDrawers;\n toolbar.activeGlobalDrawersIds = props.activeGlobalDrawersIds;\n toolbar.onActiveGlobalDrawersChange = props.onActiveGlobalDrawersChange;\n }\n if (props.navigation && !checkAlreadyExists(!!toolbar.hasNavigation, 'navigation')) {\n toolbar.hasNavigation = true;\n toolbar.navigationOpen = props.navigationOpen;\n toolbar.navigationFocusRef = props.navigationFocusRef;\n toolbar.onNavigationToggle = props.onNavigationToggle;\n }\n if (\n props.splitPanel &&\n props.splitPanelToggleProps?.displayed &&\n !checkAlreadyExists(!!toolbar.hasSplitPanel, 'splitPanel')\n ) {\n toolbar.hasSplitPanel = true;\n toolbar.splitPanelFocusRef = props.splitPanelFocusRef;\n toolbar.splitPanelToggleProps = props.splitPanelToggleProps;\n toolbar.onSplitPanelToggle = props.onSplitPanelToggle;\n }\n if (props.breadcrumbs && !checkAlreadyExists(!!toolbar.hasBreadcrumbsPortal, 'hasBreadcrumbsPortal')) {\n toolbar.hasBreadcrumbsPortal = true;\n }\n if (props.expandedDrawerId && !checkAlreadyExists(!!toolbar.expandedDrawerId, 'expandedDrawerId')) {\n toolbar.expandedDrawerId = props.expandedDrawerId;\n toolbar.setExpandedDrawerId = props.setExpandedDrawerId;\n }\n }\n // do not render toolbar if no fields are defined, except ariaLabels, which are always there\n return Object.keys(toolbar).filter(key => key !== 'ariaLabels').length > 0 ? toolbar : null;\n};\n\nexport const getPropsToMerge = (props: AppLayoutInternalProps, appLayoutState: AppLayoutPendingState): SharedProps => {\n const state = appLayoutState.widgetizedState;\n return {\n breadcrumbs: props.breadcrumbs,\n ariaLabels: state ? state.ariaLabels : props.ariaLabels,\n navigation: !props.navigationTriggerHide && !props.navigationHide,\n navigationOpen: state ? state.navigationOpen : props.navigationOpen,\n onNavigationToggle: state?.onNavigationToggle,\n navigationFocusRef: state?.navigationFocusControl.refs.toggle,\n activeDrawerId: state?.activeDrawer?.id ?? null,\n // only pass it down if there are non-empty drawers or tools\n drawers: state?.drawers?.length || !props.toolsHide ? state?.drawers : undefined,\n globalDrawersFocusControl: state?.globalDrawersFocusControl,\n globalDrawers: state?.globalDrawers?.length ? state.globalDrawers : undefined,\n activeGlobalDrawersIds: state?.activeGlobalDrawersIds,\n onActiveGlobalDrawersChange: state?.onActiveGlobalDrawersChange,\n onActiveDrawerChange: state?.onActiveDrawerChange,\n drawersFocusRef: state?.drawersFocusControl.refs.toggle,\n splitPanel: props.splitPanel,\n splitPanelToggleProps: state?.splitPanelToggleConfig && {\n ...state.splitPanelToggleConfig,\n active: state?.splitPanelOpen,\n controlId: state?.splitPanelControlId,\n position: state?.splitPanelPosition,\n },\n splitPanelFocusRef: state?.splitPanelFocusControl.refs.toggle,\n onSplitPanelToggle: state?.onSplitPanelToggle,\n expandedDrawerId: state?.expandedDrawerId,\n setExpandedDrawerId: state?.setExpandedDrawerId,\n };\n};\n"]}
|
|
@@ -3,6 +3,7 @@ export type FocusableChangeHandler = (isFocusable: boolean) => void;
|
|
|
3
3
|
export declare const defaultValue: {
|
|
4
4
|
navigationActive: boolean;
|
|
5
5
|
registerFocusable(focusable: HTMLElement, handler: FocusableChangeHandler): () => void;
|
|
6
|
+
resetFocusTarget(): void;
|
|
6
7
|
};
|
|
7
8
|
/**
|
|
8
9
|
* Single tab stop navigation context is used together with keyboard navigation that requires a single tab stop.
|
|
@@ -11,6 +12,7 @@ export declare const defaultValue: {
|
|
|
11
12
|
export declare const SingleTabStopNavigationContext: React.Context<{
|
|
12
13
|
navigationActive: boolean;
|
|
13
14
|
registerFocusable(focusable: HTMLElement, handler: FocusableChangeHandler): () => void;
|
|
15
|
+
resetFocusTarget(): void;
|
|
14
16
|
}>;
|
|
15
17
|
export declare function useSingleTabStopNavigation(focusable: null | React.RefObject<HTMLElement>, options?: {
|
|
16
18
|
tabIndex?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-tab-stop-navigation-context.d.ts","sourceRoot":"","sources":["../../../../src/internal/context/single-tab-stop-navigation-context.tsx"],"names":[],"mappings":"AAGA,OAAO,KAQN,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"single-tab-stop-navigation-context.d.ts","sourceRoot":"","sources":["../../../../src/internal/context/single-tab-stop-navigation-context.tsx"],"names":[],"mappings":"AAGA,OAAO,KAQN,MAAM,OAAO,CAAC;AAKf,MAAM,MAAM,sBAAsB,GAAG,CAAC,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;AAEpE,eAAO,MAAM,YAAY,EAAE;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,sBAAsB,GAAG,MAAM,IAAI,CAAC;IACvF,gBAAgB,IAAI,IAAI,CAAC;CAK1B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,8BAA8B;sBAbvB,OAAO;iCACI,WAAW,WAAW,sBAAsB,GAAG,MAAM,IAAI;wBAClE,IAAI;EAW+C,CAAC;AAE1E,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,EAC9C,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;;;EAoBhC;AAED,UAAU,oCAAoC;IAC5C,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,kBAAkB,EAAE,MAAM,IAAI,GAAG,WAAW,CAAC;IAC7C,mBAAmB,CAAC,CAAC,gBAAgB,EAAE,OAAO,GAAG,OAAO,CAAC;IACzD,mBAAmB,CAAC,CAAC,gBAAgB,EAAE,OAAO,GAAG,IAAI,CAAC;IACtD,kBAAkB,CAAC,CAAC,gBAAgB,EAAE,OAAO,GAAG,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,0BAA0B;IACzC,iBAAiB,IAAI,IAAI,CAAC;IAC1B,cAAc,IAAI,IAAI,GAAG,WAAW,CAAC;IACrC,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;CACzC;AAED,eAAO,MAAM,+BAA+B,yHAuG3C,CAAC"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import React, { createContext, forwardRef, useContext, useImperativeHandle, useLayoutEffect, useRef, useState, } from 'react';
|
|
4
|
+
import { useEffectOnUpdate } from '../hooks/use-effect-on-update';
|
|
4
5
|
import { nodeBelongs } from '../utils/node-belongs';
|
|
5
6
|
export const defaultValue = {
|
|
6
7
|
navigationActive: false,
|
|
7
8
|
registerFocusable: () => () => { },
|
|
9
|
+
resetFocusTarget: () => { },
|
|
8
10
|
};
|
|
9
11
|
/**
|
|
10
12
|
* Single tab stop navigation context is used together with keyboard navigation that requires a single tab stop.
|
|
@@ -48,6 +50,9 @@ export const SingleTabStopNavigationProvider = forwardRef(({ navigationActive, c
|
|
|
48
50
|
// Register a focusable element to allow navigating into it.
|
|
49
51
|
// The focusable element tabIndex is only set to 0 if the element matches the focus target.
|
|
50
52
|
function registerFocusable(focusableElement, changeHandler) {
|
|
53
|
+
// In case the contexts are nested, we must that the components register to all of them,
|
|
54
|
+
// so that switching between contexts dynamically is possible.
|
|
55
|
+
const parentUnregister = parentContext.registerFocusable(focusableElement, changeHandler);
|
|
51
56
|
focusables.current.add(focusableElement);
|
|
52
57
|
focusHandlers.current.set(focusableElement, changeHandler);
|
|
53
58
|
const isFocusable = !!focusablesState.current.get(focusableElement);
|
|
@@ -57,7 +62,10 @@ export const SingleTabStopNavigationProvider = forwardRef(({ navigationActive, c
|
|
|
57
62
|
changeHandler(newIsFocusable);
|
|
58
63
|
}
|
|
59
64
|
onRegisterFocusable === null || onRegisterFocusable === void 0 ? void 0 : onRegisterFocusable(focusableElement);
|
|
60
|
-
return () =>
|
|
65
|
+
return () => {
|
|
66
|
+
parentUnregister();
|
|
67
|
+
unregisterFocusable(focusableElement);
|
|
68
|
+
};
|
|
61
69
|
}
|
|
62
70
|
function unregisterFocusable(focusableElement) {
|
|
63
71
|
focusables.current.delete(focusableElement);
|
|
@@ -65,18 +73,21 @@ export const SingleTabStopNavigationProvider = forwardRef(({ navigationActive, c
|
|
|
65
73
|
onUnregisterFocusable === null || onUnregisterFocusable === void 0 ? void 0 : onUnregisterFocusable(focusableElement);
|
|
66
74
|
}
|
|
67
75
|
// Update focus target with next single focusable element and notify all registered focusables of a change.
|
|
68
|
-
function updateFocusTarget() {
|
|
76
|
+
function updateFocusTarget(forceUpdate = false) {
|
|
69
77
|
var _a;
|
|
70
78
|
focusTarget.current = getNextFocusTarget();
|
|
71
79
|
for (const focusableElement of focusables.current) {
|
|
72
80
|
const isFocusable = (_a = focusablesState.current.get(focusableElement)) !== null && _a !== void 0 ? _a : false;
|
|
73
81
|
const newIsFocusable = focusTarget.current === focusableElement || !!(isElementSuppressed === null || isElementSuppressed === void 0 ? void 0 : isElementSuppressed(focusableElement));
|
|
74
|
-
if (newIsFocusable !== isFocusable) {
|
|
82
|
+
if (newIsFocusable !== isFocusable || forceUpdate) {
|
|
75
83
|
focusablesState.current.set(focusableElement, newIsFocusable);
|
|
76
84
|
focusHandlers.current.get(focusableElement)(newIsFocusable);
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
87
|
}
|
|
88
|
+
function resetFocusTarget() {
|
|
89
|
+
updateFocusTarget(true);
|
|
90
|
+
}
|
|
80
91
|
function getFocusTarget() {
|
|
81
92
|
return focusTarget.current;
|
|
82
93
|
}
|
|
@@ -84,6 +95,26 @@ export const SingleTabStopNavigationProvider = forwardRef(({ navigationActive, c
|
|
|
84
95
|
return focusables.current.has(element);
|
|
85
96
|
}
|
|
86
97
|
useImperativeHandle(ref, () => ({ updateFocusTarget, getFocusTarget, isRegistered }));
|
|
87
|
-
|
|
98
|
+
// Only one STSN context should be active at a time.
|
|
99
|
+
// The outer context is preferred over the inners. The components using STSN
|
|
100
|
+
// must either work with either outer or inner context, or an explicit switch mechanism
|
|
101
|
+
// needs to be implemented (that turns the outer context on and off based on user interaction).
|
|
102
|
+
const parentContext = useContext(SingleTabStopNavigationContext);
|
|
103
|
+
const value = parentContext.navigationActive
|
|
104
|
+
? parentContext
|
|
105
|
+
: { navigationActive, registerFocusable, updateFocusTarget, resetFocusTarget };
|
|
106
|
+
// When contexts switching occurs, it is essential that the now-active one updates the focus target
|
|
107
|
+
// to ensure the tab indices are correctly set.
|
|
108
|
+
useEffectOnUpdate(() => {
|
|
109
|
+
if (parentContext.navigationActive) {
|
|
110
|
+
parentContext.resetFocusTarget();
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
resetFocusTarget();
|
|
114
|
+
}
|
|
115
|
+
// The updateFocusTarget and its dependencies must be pure.
|
|
116
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
117
|
+
}, [parentContext.navigationActive]);
|
|
118
|
+
return React.createElement(SingleTabStopNavigationContext.Provider, { value: value }, children);
|
|
88
119
|
});
|
|
89
120
|
//# sourceMappingURL=single-tab-stop-navigation-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-tab-stop-navigation-context.js","sourceRoot":"","sources":["../../../../src/internal/context/single-tab-stop-navigation-context.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, {\n createContext,\n forwardRef,\n useContext,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport { nodeBelongs } from '../utils/node-belongs';\n\nexport type FocusableChangeHandler = (isFocusable: boolean) => void;\n\nexport const defaultValue: {\n navigationActive: boolean;\n registerFocusable(focusable: HTMLElement, handler: FocusableChangeHandler): () => void;\n} = {\n navigationActive: false,\n registerFocusable: () => () => {},\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(defaultValue);\n\nexport function useSingleTabStopNavigation(\n focusable: null | React.RefObject<HTMLElement>,\n options?: { tabIndex?: number }\n) {\n const { navigationActive: contextNavigationActive, registerFocusable } = useContext(SingleTabStopNavigationContext);\n const [focusTargetActive, setFocusTargetActive] = useState(false);\n const navigationDisabled = options?.tabIndex && options?.tabIndex < 0;\n const navigationActive = contextNavigationActive && !navigationDisabled;\n\n useLayoutEffect(() => {\n if (navigationActive && focusable && focusable.current) {\n const unregister = registerFocusable(focusable.current, isFocusable => setFocusTargetActive(isFocusable));\n return () => unregister();\n }\n });\n\n let tabIndex = options?.tabIndex;\n if (navigationActive) {\n tabIndex = !focusTargetActive ? -1 : (options?.tabIndex ?? 0);\n }\n\n return { navigationActive, tabIndex };\n}\n\ninterface SingleTabStopNavigationProviderProps {\n navigationActive: boolean;\n children: React.ReactNode;\n getNextFocusTarget: () => null | HTMLElement;\n isElementSuppressed?(focusableElement: Element): boolean;\n onRegisterFocusable?(focusableElement: Element): void;\n onUnregisterActive?(focusableElement: Element): void;\n}\n\nexport interface SingleTabStopNavigationAPI {\n updateFocusTarget(): void;\n getFocusTarget(): null | HTMLElement;\n isRegistered(element: Element): boolean;\n}\n\nexport const SingleTabStopNavigationProvider = forwardRef(\n (\n {\n navigationActive,\n children,\n getNextFocusTarget,\n isElementSuppressed,\n onRegisterFocusable,\n onUnregisterActive,\n }: SingleTabStopNavigationProviderProps,\n ref: React.Ref<SingleTabStopNavigationAPI>\n ) => {\n // A set of registered focusable elements that can use keyboard navigation.\n const focusables = useRef(new Set<Element>());\n // A map of registered focusable element handlers to update the respective tab indices.\n const focusHandlers = useRef(new Map<Element, FocusableChangeHandler>());\n // A map of focusable element states to avoid issuing unnecessary updates to registered elements.\n const focusablesState = useRef(new WeakMap<Element, boolean>());\n // A reference to the currently focused element.\n const focusTarget = useRef<null | HTMLElement>(null);\n\n function onUnregisterFocusable(focusableElement: Element) {\n const isUnregisteringFocusedNode = nodeBelongs(focusableElement, document.activeElement);\n if (isUnregisteringFocusedNode) {\n // Wait for unmounted node to get removed from the DOM.\n setTimeout(() => onUnregisterActive?.(focusableElement), 0);\n }\n }\n\n // Register a focusable element to allow navigating into it.\n // The focusable element tabIndex is only set to 0 if the element matches the focus target.\n function registerFocusable(focusableElement: Element, changeHandler: FocusableChangeHandler) {\n focusables.current.add(focusableElement);\n focusHandlers.current.set(focusableElement, changeHandler);\n const isFocusable = !!focusablesState.current.get(focusableElement);\n const newIsFocusable = focusTarget.current === focusableElement || !!isElementSuppressed?.(focusableElement);\n if (newIsFocusable !== isFocusable) {\n focusablesState.current.set(focusableElement, newIsFocusable);\n changeHandler(newIsFocusable);\n }\n onRegisterFocusable?.(focusableElement);\n return () => unregisterFocusable(focusableElement);\n }\n function unregisterFocusable(focusableElement: Element) {\n focusables.current.delete(focusableElement);\n focusHandlers.current.delete(focusableElement);\n onUnregisterFocusable?.(focusableElement);\n }\n\n // Update focus target with next single focusable element and notify all registered focusables of a change.\n function updateFocusTarget() {\n focusTarget.current = getNextFocusTarget();\n for (const focusableElement of focusables.current) {\n const isFocusable = focusablesState.current.get(focusableElement) ?? false;\n const newIsFocusable = focusTarget.current === focusableElement || !!isElementSuppressed?.(focusableElement);\n if (newIsFocusable !== isFocusable) {\n focusablesState.current.set(focusableElement, newIsFocusable);\n focusHandlers.current.get(focusableElement)!(newIsFocusable);\n }\n }\n }\n\n function getFocusTarget() {\n return focusTarget.current;\n }\n\n function isRegistered(element: Element) {\n return focusables.current.has(element);\n }\n\n useImperativeHandle(ref, () => ({ updateFocusTarget, getFocusTarget, isRegistered }));\n\n return (\n <SingleTabStopNavigationContext.Provider value={{ navigationActive, registerFocusable }}>\n {children}\n </SingleTabStopNavigationContext.Provider>\n );\n }\n);\n"]}
|
|
1
|
+
{"version":3,"file":"single-tab-stop-navigation-context.js","sourceRoot":"","sources":["../../../../src/internal/context/single-tab-stop-navigation-context.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, {\n createContext,\n forwardRef,\n useContext,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport { useEffectOnUpdate } from '../hooks/use-effect-on-update';\nimport { nodeBelongs } from '../utils/node-belongs';\n\nexport type FocusableChangeHandler = (isFocusable: boolean) => void;\n\nexport const defaultValue: {\n navigationActive: boolean;\n registerFocusable(focusable: HTMLElement, handler: FocusableChangeHandler): () => void;\n resetFocusTarget(): void;\n} = {\n navigationActive: false,\n registerFocusable: () => () => {},\n resetFocusTarget: () => {},\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(defaultValue);\n\nexport function useSingleTabStopNavigation(\n focusable: null | React.RefObject<HTMLElement>,\n options?: { tabIndex?: number }\n) {\n const { navigationActive: contextNavigationActive, registerFocusable } = useContext(SingleTabStopNavigationContext);\n const [focusTargetActive, setFocusTargetActive] = useState(false);\n const navigationDisabled = options?.tabIndex && options?.tabIndex < 0;\n const navigationActive = contextNavigationActive && !navigationDisabled;\n\n useLayoutEffect(() => {\n if (navigationActive && focusable && focusable.current) {\n const unregister = registerFocusable(focusable.current, isFocusable => setFocusTargetActive(isFocusable));\n return () => unregister();\n }\n });\n\n let tabIndex = options?.tabIndex;\n if (navigationActive) {\n tabIndex = !focusTargetActive ? -1 : (options?.tabIndex ?? 0);\n }\n\n return { navigationActive, tabIndex };\n}\n\ninterface SingleTabStopNavigationProviderProps {\n navigationActive: boolean;\n children: React.ReactNode;\n getNextFocusTarget: () => null | HTMLElement;\n isElementSuppressed?(focusableElement: Element): boolean;\n onRegisterFocusable?(focusableElement: Element): void;\n onUnregisterActive?(focusableElement: Element): void;\n}\n\nexport interface SingleTabStopNavigationAPI {\n updateFocusTarget(): void;\n getFocusTarget(): null | HTMLElement;\n isRegistered(element: Element): boolean;\n}\n\nexport const SingleTabStopNavigationProvider = forwardRef(\n (\n {\n navigationActive,\n children,\n getNextFocusTarget,\n isElementSuppressed,\n onRegisterFocusable,\n onUnregisterActive,\n }: SingleTabStopNavigationProviderProps,\n ref: React.Ref<SingleTabStopNavigationAPI>\n ) => {\n // A set of registered focusable elements that can use keyboard navigation.\n const focusables = useRef(new Set<Element>());\n // A map of registered focusable element handlers to update the respective tab indices.\n const focusHandlers = useRef(new Map<Element, FocusableChangeHandler>());\n // A map of focusable element states to avoid issuing unnecessary updates to registered elements.\n const focusablesState = useRef(new WeakMap<Element, boolean>());\n // A reference to the currently focused element.\n const focusTarget = useRef<null | HTMLElement>(null);\n\n function onUnregisterFocusable(focusableElement: Element) {\n const isUnregisteringFocusedNode = nodeBelongs(focusableElement, document.activeElement);\n if (isUnregisteringFocusedNode) {\n // Wait for unmounted node to get removed from the DOM.\n setTimeout(() => onUnregisterActive?.(focusableElement), 0);\n }\n }\n\n // Register a focusable element to allow navigating into it.\n // The focusable element tabIndex is only set to 0 if the element matches the focus target.\n function registerFocusable(focusableElement: HTMLElement, changeHandler: FocusableChangeHandler) {\n // In case the contexts are nested, we must that the components register to all of them,\n // so that switching between contexts dynamically is possible.\n const parentUnregister = parentContext.registerFocusable(focusableElement, changeHandler);\n\n focusables.current.add(focusableElement);\n focusHandlers.current.set(focusableElement, changeHandler);\n const isFocusable = !!focusablesState.current.get(focusableElement);\n const newIsFocusable = focusTarget.current === focusableElement || !!isElementSuppressed?.(focusableElement);\n if (newIsFocusable !== isFocusable) {\n focusablesState.current.set(focusableElement, newIsFocusable);\n changeHandler(newIsFocusable);\n }\n onRegisterFocusable?.(focusableElement);\n\n return () => {\n parentUnregister();\n unregisterFocusable(focusableElement);\n };\n }\n function unregisterFocusable(focusableElement: Element) {\n focusables.current.delete(focusableElement);\n focusHandlers.current.delete(focusableElement);\n onUnregisterFocusable?.(focusableElement);\n }\n\n // Update focus target with next single focusable element and notify all registered focusables of a change.\n function updateFocusTarget(forceUpdate = false) {\n focusTarget.current = getNextFocusTarget();\n for (const focusableElement of focusables.current) {\n const isFocusable = focusablesState.current.get(focusableElement) ?? false;\n const newIsFocusable = focusTarget.current === focusableElement || !!isElementSuppressed?.(focusableElement);\n if (newIsFocusable !== isFocusable || forceUpdate) {\n focusablesState.current.set(focusableElement, newIsFocusable);\n focusHandlers.current.get(focusableElement)!(newIsFocusable);\n }\n }\n }\n function resetFocusTarget() {\n updateFocusTarget(true);\n }\n function getFocusTarget() {\n return focusTarget.current;\n }\n function isRegistered(element: Element) {\n return focusables.current.has(element);\n }\n useImperativeHandle(ref, () => ({ updateFocusTarget, getFocusTarget, isRegistered }));\n\n // Only one STSN context should be active at a time.\n // The outer context is preferred over the inners. The components using STSN\n // must either work with either outer or inner context, or an explicit switch mechanism\n // needs to be implemented (that turns the outer context on and off based on user interaction).\n const parentContext = useContext(SingleTabStopNavigationContext);\n const value = parentContext.navigationActive\n ? parentContext\n : { navigationActive, registerFocusable, updateFocusTarget, resetFocusTarget };\n\n // When contexts switching occurs, it is essential that the now-active one updates the focus target\n // to ensure the tab indices are correctly set.\n useEffectOnUpdate(() => {\n if (parentContext.navigationActive) {\n parentContext.resetFocusTarget();\n } else {\n resetFocusTarget();\n }\n // The updateFocusTarget and its dependencies must be pure.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [parentContext.navigationActive]);\n\n return <SingleTabStopNavigationContext.Provider value={value}>{children}</SingleTabStopNavigationContext.Provider>;\n }\n);\n"]}
|
package/internal/environment.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export var PACKAGE_SOURCE = "components";
|
|
2
|
-
export var PACKAGE_VERSION = "3.0.0 (
|
|
3
|
-
export var GIT_SHA = "
|
|
2
|
+
export var PACKAGE_VERSION = "3.0.0 (bcd2b51d)";
|
|
3
|
+
export var GIT_SHA = "bcd2b51d";
|
|
4
4
|
export var THEME = "open-source-visual-refresh";
|
|
5
5
|
export var SYSTEM = "console";
|
|
6
6
|
export var ALWAYS_VISUAL_REFRESH = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/internal/hooks/use-virtual/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAE1D,OAAO,EAAmC,WAAW,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/internal/hooks/use-virtual/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAE1D,OAAO,EAAmC,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAS1F,UAAU,eAAe,CAAC,IAAI;IAC5B,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IACvB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACxC,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,UAAU,cAAc;IACtB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,IAAI,SAAS,MAAM,EAAE,EAC9C,KAAK,EACL,SAAS,EACT,YAAY,EACZ,eAAe,GAChB,EAAE,eAAe,CAAC,IAAI,CAAC,GAAG,cAAc,CAsCxC"}
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
import { useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { useVirtual as useVirtualDefault } from '../../vendor/react-virtual';
|
|
5
5
|
import stickyRangeExtractor from './sticky-range-extractor';
|
|
6
|
-
|
|
6
|
+
// Maximum allowed synchronous (nested) item mounts before forcing a bail-out.
|
|
7
|
+
// Mirrors React’s internal safeguard for nested updates: React throws
|
|
8
|
+
// "Maximum update depth exceeded" once >50 sync updates occur within a single commit.
|
|
9
|
+
// See: https://github.com/facebook/react/commit/d8c90fa48d3addefe4b805ec56a3c65e4ee39127
|
|
10
|
+
const MAX_ITEM_MOUNTS = 50 - 1;
|
|
7
11
|
/**
|
|
8
12
|
* The useVirtual from react-virtual@2 might produce an infinite update loop caused by setting
|
|
9
13
|
* measured item sizes in the render cycle (as part of the measureRef assignment):
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/internal/hooks/use-virtual/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AACtC,OAAc,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE1D,OAAO,EAAE,UAAU,IAAI,iBAAiB,EAAe,MAAM,4BAA4B,CAAC;AAC1F,OAAO,oBAAoB,MAAM,0BAA0B,CAAC;AAE5D,MAAM,eAAe,GAAG,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/internal/hooks/use-virtual/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AACtC,OAAc,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE1D,OAAO,EAAE,UAAU,IAAI,iBAAiB,EAAe,MAAM,4BAA4B,CAAC;AAC1F,OAAO,oBAAoB,MAAM,0BAA0B,CAAC;AAE5D,8EAA8E;AAC9E,sEAAsE;AACtE,sFAAsF;AACtF,yFAAyF;AACzF,MAAM,eAAe,GAAG,EAAE,GAAG,CAAC,CAAC;AAe/B;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAsB,EAC9C,KAAK,EACL,SAAS,EACT,YAAY,EACZ,eAAe,GACO;IACtB,MAAM,cAAc,GAAG,iBAAiB,CAAC;QACvC,IAAI,EAAE,KAAK,CAAC,MAAM;QAClB,SAAS;QACT,YAAY;QACZ,QAAQ,EAAE,CAAC;QACX,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,SAAS;KACnE,CAAC,CAAC;IAEH,oEAAoE;IACpE,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,OAAO,EAAgB,CAAC,CAAC;IAE1D,yEAAyE;IACzE,MAAM,UAAU,GAAG,cAAc,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtF,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IACxC,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAEtC,MAAM,YAAY,GAAG,OAAO,CAC1B,GAAG,EAAE,CACH,cAAc,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,iCAC1C,WAAW,KACd,UAAU,EAAE,CAAC,IAAwB,EAAE,EAAE;;YACvC,MAAM,YAAY,GAAG,MAAA,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,mCAAI,CAAC,CAAC;YAC9E,IAAI,YAAY,GAAG,eAAe,EAAE;gBAClC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAC7B,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,CAAC,CAAC,CAAC;aACvE;QACH,CAAC,IACD,CAAC,EACL,CAAC,KAAK,EAAE,cAAc,CAAC,YAAY,CAAC,CACrC,CAAC;IAEF,OAAO;QACL,YAAY;QACZ,SAAS,EAAE,cAAc,CAAC,SAAS;QACnC,aAAa,EAAE,cAAc,CAAC,aAAa;KAC5C,CAAC;AACJ,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport React, { useEffect, useMemo, useRef } from 'react';\n\nimport { useVirtual as useVirtualDefault, VirtualItem } from '../../vendor/react-virtual';\nimport stickyRangeExtractor from './sticky-range-extractor';\n\n// Maximum allowed synchronous (nested) item mounts before forcing a bail-out.\n// Mirrors React’s internal safeguard for nested updates: React throws\n// \"Maximum update depth exceeded\" once >50 sync updates occur within a single commit.\n// See: https://github.com/facebook/react/commit/d8c90fa48d3addefe4b805ec56a3c65e4ee39127\nconst MAX_ITEM_MOUNTS = 50 - 1;\n\ninterface UseVirtualProps<Item> {\n items: readonly Item[];\n parentRef: React.RefObject<HTMLElement>;\n estimateSize: () => number;\n firstItemSticky?: boolean;\n}\n\ninterface RowVirtualizer {\n virtualItems: VirtualItem[];\n totalSize: number;\n scrollToIndex: (index: number) => void;\n}\n\n/**\n * The useVirtual from react-virtual@2 might produce an infinite update loop caused by setting\n * measured item sizes in the render cycle (as part of the measureRef assignment):\n * The sum of all measured item sizes is returned as totalSize which is then set on the list container.\n * Enforcing new container height might result in an items size change e.g. when the content wraps.\n *\n * The infinite update cycle causes React \"Maximum update depth exceeded\" error and can be additionally confirmed\n * by logging the totalSize which should then bounce between two values.\n *\n * The number of item refs assignments is limited to MAX_ITEM_MOUNTS unless items or indices change.\n * That is based on the assumption the item height stays constant after its first render.\n */\nexport function useVirtual<Item extends object>({\n items,\n parentRef,\n estimateSize,\n firstItemSticky,\n}: UseVirtualProps<Item>): RowVirtualizer {\n const rowVirtualizer = useVirtualDefault({\n size: items.length,\n parentRef,\n estimateSize,\n overscan: 5,\n rangeExtractor: firstItemSticky ? stickyRangeExtractor : undefined,\n });\n\n // Cache virtual item mounts to limit the amount of mounts per item.\n const measuresCache = useRef(new WeakMap<Item, number>());\n\n // Clear mounts cache every time indices, items, or size estimate change.\n const indicesKey = rowVirtualizer.virtualItems.map(item => `${item.index}`).join(':');\n useEffect(() => {\n measuresCache.current = new WeakMap();\n }, [indicesKey, items, estimateSize]);\n\n const virtualItems = useMemo(\n () =>\n rowVirtualizer.virtualItems.map(virtualItem => ({\n ...virtualItem,\n measureRef: (node: null | HTMLElement) => {\n const mountedCount = measuresCache.current.get(items[virtualItem.index]) ?? 0;\n if (mountedCount < MAX_ITEM_MOUNTS) {\n virtualItem.measureRef(node);\n measuresCache.current.set(items[virtualItem.index], mountedCount + 1);\n }\n },\n })),\n [items, rowVirtualizer.virtualItems]\n );\n\n return {\n virtualItems,\n totalSize: rowVirtualizer.totalSize,\n scrollToIndex: rowVirtualizer.scrollToIndex,\n };\n}\n"]}
|
package/internal/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
"./internal/base-component/index.js",
|
|
151
151
|
"./internal/base-component/styles.css.js"
|
|
152
152
|
],
|
|
153
|
-
"version": "3.0.
|
|
153
|
+
"version": "3.0.1074",
|
|
154
154
|
"repository": {
|
|
155
155
|
"type": "git",
|
|
156
156
|
"url": "https://github.com/cloudscape-design/components.git"
|