@atlaskit/navigation-system 9.3.1 → 9.4.1
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/CHANGELOG.md +15 -0
- package/constellation/index/migration-guide.mdx +338 -150
- package/dist/cjs/components/skip-links/focus-element.js +54 -0
- package/dist/cjs/components/skip-links/skip-link.js +32 -65
- package/dist/cjs/components/skip-links/skip-links-popup.js +26 -4
- package/dist/cjs/context/skip-links/use-skip-link-internal.js +5 -3
- package/dist/cjs/ui/page-layout/side-nav/side-nav.js +16 -5
- package/dist/cjs/ui/page-layout/side-nav/use-expand-side-nav.js +104 -38
- package/dist/cjs/ui/page-layout/side-nav/use-toggle-side-nav.js +33 -3
- package/dist/es2019/components/skip-links/focus-element.js +49 -0
- package/dist/es2019/components/skip-links/skip-link.js +32 -65
- package/dist/es2019/components/skip-links/skip-links-popup.js +26 -4
- package/dist/es2019/context/skip-links/use-skip-link-internal.js +5 -3
- package/dist/es2019/ui/page-layout/side-nav/side-nav.js +16 -5
- package/dist/es2019/ui/page-layout/side-nav/use-expand-side-nav.js +104 -38
- package/dist/es2019/ui/page-layout/side-nav/use-toggle-side-nav.js +33 -3
- package/dist/esm/components/skip-links/focus-element.js +49 -0
- package/dist/esm/components/skip-links/skip-link.js +32 -65
- package/dist/esm/components/skip-links/skip-links-popup.js +26 -4
- package/dist/esm/context/skip-links/use-skip-link-internal.js +5 -3
- package/dist/esm/ui/page-layout/side-nav/side-nav.js +16 -5
- package/dist/esm/ui/page-layout/side-nav/use-expand-side-nav.js +104 -38
- package/dist/esm/ui/page-layout/side-nav/use-toggle-side-nav.js +33 -3
- package/dist/types/components/skip-links/focus-element.d.ts +4 -0
- package/dist/types/components/skip-links/skip-link.d.ts +2 -1
- package/dist/types/context/skip-links/types.d.ts +18 -1
- package/dist/types/context/skip-links/use-skip-link-internal.d.ts +3 -3
- package/dist/types-ts4.5/components/skip-links/focus-element.d.ts +4 -0
- package/dist/types-ts4.5/components/skip-links/skip-link.d.ts +2 -1
- package/dist/types-ts4.5/context/skip-links/types.d.ts +18 -1
- package/dist/types-ts4.5/context/skip-links/use-skip-link-internal.d.ts +3 -3
- package/package.json +4 -4
|
@@ -9,6 +9,7 @@ import { flushSync } from 'react-dom';
|
|
|
9
9
|
import Button from '@atlaskit/button/new';
|
|
10
10
|
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
11
11
|
import Popup from '@atlaskit/popup';
|
|
12
|
+
import { focusElement } from './focus-element';
|
|
12
13
|
import { SkipLink } from './skip-link';
|
|
13
14
|
var contentStyles = {
|
|
14
15
|
root: "_1rjcu2gc _18zrpxbi _1e0c1txw _2lx21bp4 _1pbyjh3g",
|
|
@@ -89,13 +90,34 @@ export function SkipLinksPopup(_ref) {
|
|
|
89
90
|
}, links.map(function (_ref2) {
|
|
90
91
|
var id = _ref2.id,
|
|
91
92
|
label = _ref2.label,
|
|
92
|
-
|
|
93
|
+
_navigate = _ref2.navigate;
|
|
93
94
|
return /*#__PURE__*/React.createElement(SkipLink, {
|
|
94
95
|
key: id,
|
|
95
|
-
id: id
|
|
96
|
-
|
|
96
|
+
id: id
|
|
97
|
+
/**
|
|
98
|
+
* The popup always owns the navigation effect under the
|
|
99
|
+
* `platform_dst_nav4_skip_link_a11y_1` gate (the only path
|
|
100
|
+
* that renders `SkipLinksPopup`). It first closes itself
|
|
101
|
+
* synchronously so its focus lock is released, then either:
|
|
102
|
+
*
|
|
103
|
+
* - delegates to the consumer's `navigate` (e.g. SideNav
|
|
104
|
+
* expanding and focusing its first nav item), or
|
|
105
|
+
* - falls back to focusing the slot element with `id`.
|
|
106
|
+
*
|
|
107
|
+
* This means `SkipLink`'s `onBeforeNavigate` hook is never
|
|
108
|
+
* needed under the gate and can be removed on cleanup.
|
|
109
|
+
*/,
|
|
110
|
+
navigate: function navigate() {
|
|
97
111
|
closePopup();
|
|
98
|
-
|
|
112
|
+
if (_navigate) {
|
|
113
|
+
_navigate();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Intentionally not using `document.querySelector` because many valid IDs are not valid selectors.
|
|
117
|
+
var target = document.getElementById(id);
|
|
118
|
+
if (target) {
|
|
119
|
+
focusElement(target);
|
|
120
|
+
}
|
|
99
121
|
}
|
|
100
122
|
}, label);
|
|
101
123
|
})));
|
|
@@ -5,14 +5,15 @@ import { SkipLinksContext } from './skip-links-context';
|
|
|
5
5
|
*
|
|
6
6
|
* `useSkipLink` is the public API wrapper of this.
|
|
7
7
|
*
|
|
8
|
-
* This private version exists for us to support `onBeforeNavigate` for the side nav use case,
|
|
9
|
-
* where we might need to expand it before moving focus, without having to support
|
|
8
|
+
* This private version exists for us to support `onBeforeNavigate` / `navigate` for the side nav use case,
|
|
9
|
+
* where we might need to expand it before moving focus, without having to support those publicly.
|
|
10
10
|
*/
|
|
11
11
|
export var useSkipLinkInternal = function useSkipLinkInternal(_ref) {
|
|
12
12
|
var id = _ref.id,
|
|
13
13
|
label = _ref.label,
|
|
14
14
|
listIndex = _ref.listIndex,
|
|
15
15
|
onBeforeNavigate = _ref.onBeforeNavigate,
|
|
16
|
+
navigate = _ref.navigate,
|
|
16
17
|
isHidden = _ref.isHidden;
|
|
17
18
|
var _useContext = useContext(SkipLinksContext),
|
|
18
19
|
registerSkipLink = _useContext.registerSkipLink,
|
|
@@ -30,10 +31,11 @@ export var useSkipLinkInternal = function useSkipLinkInternal(_ref) {
|
|
|
30
31
|
label: label,
|
|
31
32
|
listIndex: listIndex,
|
|
32
33
|
onBeforeNavigate: onBeforeNavigate,
|
|
34
|
+
navigate: navigate,
|
|
33
35
|
isHidden: isHidden
|
|
34
36
|
});
|
|
35
37
|
return function () {
|
|
36
38
|
unregisterSkipLink(id);
|
|
37
39
|
};
|
|
38
|
-
}, [id, isHidden, label, listIndex, onBeforeNavigate, registerSkipLink, unregisterSkipLink]);
|
|
40
|
+
}, [id, isHidden, label, listIndex, onBeforeNavigate, navigate, registerSkipLink, unregisterSkipLink]);
|
|
39
41
|
};
|
|
@@ -13,6 +13,7 @@ import { useAnalyticsEvents } from '@atlaskit/analytics-next';
|
|
|
13
13
|
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
14
14
|
import useStableRef from '@atlaskit/ds-lib/use-stable-ref';
|
|
15
15
|
import { OpenLayerObserverNamespaceProvider, useOpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer';
|
|
16
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
16
17
|
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
17
18
|
import { media } from '@atlaskit/primitives/responsive';
|
|
18
19
|
import { useSkipLinkInternal } from '../../../context/skip-links/use-skip-link-internal';
|
|
@@ -104,28 +105,38 @@ function SideNavInternal(_ref) {
|
|
|
104
105
|
var id = useLayoutId({
|
|
105
106
|
providedId: providedId
|
|
106
107
|
});
|
|
107
|
-
var
|
|
108
|
+
var expandAndFocusSideNav = useExpandSideNav({
|
|
108
109
|
trigger: 'skip-link'
|
|
109
110
|
});
|
|
110
111
|
/**
|
|
111
112
|
* Called after clicking on the side nav skip link, and ensures the side nav is expanded so that it is focusable.
|
|
112
113
|
*
|
|
113
114
|
* We need to update the DOM synchronously because `.focus()` is called synchronously after this state update.
|
|
115
|
+
*
|
|
116
|
+
* Only used when `platform_dst_nav4_skip_link_a11y_1` is OFF; can be removed on gate cleanup.
|
|
114
117
|
*/
|
|
115
118
|
var synchronouslyExpandSideNav = useCallback(function () {
|
|
116
119
|
flushSync(function () {
|
|
117
120
|
/**
|
|
118
121
|
* Calling this unconditionally and relying on it to avoid no-op renders.
|
|
119
122
|
*
|
|
120
|
-
* We _could_ call it conditionally, but we'd be duplicating the screen size checks `
|
|
123
|
+
* We _could_ call it conditionally, but we'd be duplicating the screen size checks `expandAndFocusSideNav` makes.
|
|
121
124
|
*/
|
|
122
|
-
|
|
125
|
+
expandAndFocusSideNav();
|
|
123
126
|
});
|
|
124
|
-
}, [
|
|
127
|
+
}, [expandAndFocusSideNav]);
|
|
125
128
|
useSkipLinkInternal({
|
|
126
129
|
id: id,
|
|
127
130
|
label: skipLinkLabel,
|
|
128
|
-
|
|
131
|
+
/**
|
|
132
|
+
* `navigate` is the gate-on contract: it owns expanding the side nav AND moving
|
|
133
|
+
* focus to the first nav item, atomically (via `useExpandSideNav`'s `flushSync`).
|
|
134
|
+
*
|
|
135
|
+
* `onBeforeNavigate` is the legacy contract used only when the gate is OFF.
|
|
136
|
+
* On gate cleanup, drop `onBeforeNavigate` and `synchronouslyExpandSideNav` here.
|
|
137
|
+
*/
|
|
138
|
+
navigate: fg('platform_dst_nav4_skip_link_a11y_1') ? expandAndFocusSideNav : undefined,
|
|
139
|
+
onBeforeNavigate: fg('platform_dst_nav4_skip_link_a11y_1') ? undefined : synchronouslyExpandSideNav
|
|
129
140
|
});
|
|
130
141
|
var sideNavState = useContext(SideNavVisibilityState);
|
|
131
142
|
var setSideNavState = useContext(SetSideNavVisibilityState);
|
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
import { useCallback, useContext } from 'react';
|
|
2
|
+
import { bind } from 'bind-event-listener';
|
|
3
|
+
import { flushSync } from 'react-dom';
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
2
5
|
import { SetSideNavVisibilityState } from './set-side-nav-visibility-state';
|
|
6
|
+
import { useSideNavRef } from './use-side-nav-ref';
|
|
7
|
+
/**
|
|
8
|
+
* Moves focus to the first focusable item in the side nav, or the side nav element itself as a fallback.
|
|
9
|
+
*/
|
|
10
|
+
function focusFirstNavItem(sideNavElement) {
|
|
11
|
+
var _firstNavItem$checkVi, _firstNavItem$checkVi2;
|
|
12
|
+
/**
|
|
13
|
+
* Try to get the first focusable item in the side nav.
|
|
14
|
+
* The selector is not very broad, but should be appropriate for items from this package.
|
|
15
|
+
*/
|
|
16
|
+
var firstNavItem = sideNavElement.querySelector('a, button');
|
|
17
|
+
var isFirstNavItemVisible = firstNavItem !== null && ((_firstNavItem$checkVi = (_firstNavItem$checkVi2 = firstNavItem.checkVisibility) === null || _firstNavItem$checkVi2 === void 0 ? void 0 : _firstNavItem$checkVi2.call(firstNavItem)) !== null && _firstNavItem$checkVi !== void 0 ? _firstNavItem$checkVi : false);
|
|
18
|
+
var itemToFocus = isFirstNavItemVisible ? firstNavItem : sideNavElement;
|
|
19
|
+
if (itemToFocus === sideNavElement) {
|
|
20
|
+
/**
|
|
21
|
+
* Elements without an explicit `tabindex` attribute are not guaranteed to be focusable:
|
|
22
|
+
* https://html.spec.whatwg.org/multipage/interaction.html#attr-tabindex
|
|
23
|
+
*
|
|
24
|
+
* Our slots are not interactive, so this is required.
|
|
25
|
+
*
|
|
26
|
+
* In the future we may want to check if there is an existing `tabindex` attribute,
|
|
27
|
+
* as custom skip linked elements might already have one.
|
|
28
|
+
*/
|
|
29
|
+
sideNavElement.setAttribute('tabindex', '-1');
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Cleanup the `tabindex` attribute we set when the slot or custom target loses focus.
|
|
33
|
+
*
|
|
34
|
+
* This is preferable to always having `tabindex="-1"` because always applying the tab index can:
|
|
35
|
+
*
|
|
36
|
+
* - mess with click events
|
|
37
|
+
* - potentially cause a focus ring to be always visible
|
|
38
|
+
*/
|
|
39
|
+
bind(sideNavElement, {
|
|
40
|
+
type: 'blur',
|
|
41
|
+
listener: function listener() {
|
|
42
|
+
sideNavElement.removeAttribute('tabindex');
|
|
43
|
+
},
|
|
44
|
+
options: {
|
|
45
|
+
once: true
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Not using `focusVisible` option because we don't want clicks on the toggle button to show a focus ring.
|
|
52
|
+
*/
|
|
53
|
+
itemToFocus.focus();
|
|
54
|
+
}
|
|
55
|
+
var triggersWithFocusOnExpand = new Set(['toggle-button', 'skip-link']);
|
|
56
|
+
|
|
3
57
|
/**
|
|
4
58
|
* __useExpandSideNav__
|
|
5
59
|
*
|
|
@@ -14,48 +68,60 @@ export function useExpandSideNav() {
|
|
|
14
68
|
_ref$trigger = _ref.trigger,
|
|
15
69
|
trigger = _ref$trigger === void 0 ? 'programmatic' : _ref$trigger;
|
|
16
70
|
var setSideNavState = useContext(SetSideNavVisibilityState);
|
|
71
|
+
var sideNavRef = useSideNavRef();
|
|
17
72
|
var expandSideNav = useCallback(function () {
|
|
18
73
|
var _window$matchMedia = window.matchMedia('(min-width: 64rem)'),
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
74
|
+
isDesktop = _window$matchMedia.matches;
|
|
75
|
+
var runUpdate = function runUpdate() {
|
|
76
|
+
if (isDesktop) {
|
|
77
|
+
setSideNavState(function (currentState) {
|
|
78
|
+
// No-op if the side nav state has not been initialised yet
|
|
79
|
+
// e.g. if the SideNav has not been mounted yet
|
|
80
|
+
if (!currentState) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
27
83
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
84
|
+
// Skip the re-render if it's a no-op change
|
|
85
|
+
if (currentState.desktop === 'expanded' && currentState.flyout === 'closed') {
|
|
86
|
+
return currentState;
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
mobile: currentState.mobile,
|
|
90
|
+
desktop: 'expanded',
|
|
91
|
+
flyout: 'closed',
|
|
92
|
+
lastTrigger: trigger
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
} else {
|
|
96
|
+
setSideNavState(function (currentState) {
|
|
97
|
+
// No-op if the side nav state has not been initialised yet
|
|
98
|
+
// e.g. if the SideNav has not been mounted yet
|
|
99
|
+
if (!currentState) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
46
102
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
103
|
+
// Skip the re-render if it's a no-op change
|
|
104
|
+
if (currentState.mobile === 'expanded' && currentState.flyout === 'closed') {
|
|
105
|
+
return currentState;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
desktop: currentState.desktop,
|
|
109
|
+
mobile: 'expanded',
|
|
110
|
+
flyout: 'closed',
|
|
111
|
+
lastTrigger: trigger
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
if (triggersWithFocusOnExpand.has(trigger) && fg('platform_dst_nav4_skip_link_a11y_1')) {
|
|
117
|
+
flushSync(runUpdate);
|
|
118
|
+
var sideNavElement = sideNavRef.current;
|
|
119
|
+
if (sideNavElement) {
|
|
120
|
+
focusFirstNavItem(sideNavElement);
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
runUpdate();
|
|
58
124
|
}
|
|
59
|
-
}, [setSideNavState, trigger]);
|
|
125
|
+
}, [setSideNavState, sideNavRef, trigger]);
|
|
60
126
|
return expandSideNav;
|
|
61
127
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { useCallback, useContext } from 'react';
|
|
2
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
2
3
|
import { SetSideNavVisibilityState } from './set-side-nav-visibility-state';
|
|
4
|
+
import { SideNavVisibilityState } from './side-nav-visibility-state';
|
|
5
|
+
import { useExpandSideNav } from './use-expand-side-nav';
|
|
3
6
|
/**
|
|
4
7
|
* __useToggleSideNav__
|
|
5
8
|
*
|
|
@@ -14,10 +17,37 @@ export function useToggleSideNav() {
|
|
|
14
17
|
_ref$trigger = _ref.trigger,
|
|
15
18
|
trigger = _ref$trigger === void 0 ? 'programmatic' : _ref$trigger;
|
|
16
19
|
var setSideNavState = useContext(SetSideNavVisibilityState);
|
|
20
|
+
var sideNavState = useContext(SideNavVisibilityState);
|
|
21
|
+
var expandSideNav = useExpandSideNav({
|
|
22
|
+
trigger: trigger
|
|
23
|
+
});
|
|
24
|
+
var isCollapsedOnDesktop = (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.desktop) === 'collapsed';
|
|
25
|
+
var isCollapsedOnMobile = (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.mobile) === 'collapsed';
|
|
17
26
|
var toggleSideNav = useCallback(function () {
|
|
18
27
|
var _window$matchMedia = window.matchMedia('(min-width: 64rem)'),
|
|
19
|
-
|
|
20
|
-
if (
|
|
28
|
+
isDesktop = _window$matchMedia.matches;
|
|
29
|
+
if (fg('platform_dst_nav4_skip_link_a11y_1')) {
|
|
30
|
+
var isExpanding = isDesktop ? isCollapsedOnDesktop : isCollapsedOnMobile;
|
|
31
|
+
if (isExpanding) {
|
|
32
|
+
expandSideNav();
|
|
33
|
+
} else {
|
|
34
|
+
setSideNavState(function (currentState) {
|
|
35
|
+
// No-op if the side nav state has not been initialised yet
|
|
36
|
+
// e.g. if the SideNav has not been mounted yet
|
|
37
|
+
if (!currentState) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
mobile: isDesktop ? currentState.mobile : 'collapsed',
|
|
42
|
+
desktop: isDesktop ? 'collapsed' : currentState.desktop,
|
|
43
|
+
flyout: 'closed',
|
|
44
|
+
lastTrigger: trigger
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (isDesktop) {
|
|
21
51
|
setSideNavState(function (currentState) {
|
|
22
52
|
// No-op if the side nav state has not been initialised yet
|
|
23
53
|
// e.g. if the SideNav has not been mounted yet
|
|
@@ -46,6 +76,6 @@ export function useToggleSideNav() {
|
|
|
46
76
|
};
|
|
47
77
|
});
|
|
48
78
|
}
|
|
49
|
-
}, [setSideNavState, trigger]);
|
|
79
|
+
}, [expandSideNav, isCollapsedOnDesktop, isCollapsedOnMobile, setSideNavState, trigger]);
|
|
50
80
|
return toggleSideNav;
|
|
51
81
|
}
|
|
@@ -8,11 +8,12 @@ type SkipLinkProps = {
|
|
|
8
8
|
id: string;
|
|
9
9
|
children: ReactNode;
|
|
10
10
|
onBeforeNavigate?: SkipLinkData['onBeforeNavigate'];
|
|
11
|
+
navigate?: SkipLinkData['navigate'];
|
|
11
12
|
};
|
|
12
13
|
/**
|
|
13
14
|
* A link that moves current tab position to a different element
|
|
14
15
|
*
|
|
15
16
|
* This component is rendered internally and is not exported publicly.
|
|
16
17
|
*/
|
|
17
|
-
export declare const SkipLink: ({ id, children, onBeforeNavigate }: SkipLinkProps) => JSX.Element;
|
|
18
|
+
export declare const SkipLink: ({ id, children, onBeforeNavigate, navigate, }: SkipLinkProps) => JSX.Element;
|
|
18
19
|
export {};
|
|
@@ -16,10 +16,27 @@ export type SkipLinkData = {
|
|
|
16
16
|
* immediately before focus is moved to the associated element.
|
|
17
17
|
*
|
|
18
18
|
* This can be used to update state, such as to show a hidden element.
|
|
19
|
+
*
|
|
20
|
+
* @deprecated Only used when `platform_dst_nav4_skip_link_a11y_1` is OFF.
|
|
21
|
+
* When the gate is on, prefer `navigate` for consumers that need to atomically
|
|
22
|
+
* commit state and move focus somewhere other than the slot element with id `id`.
|
|
23
|
+
* This callback can be removed once the gate is fully enabled and cleaned up.
|
|
19
24
|
*/
|
|
20
25
|
onBeforeNavigate?: () => void;
|
|
21
26
|
/**
|
|
22
|
-
*
|
|
27
|
+
* Replaces the default "focus the element with `id`" behavior when the skip link is activated.
|
|
28
|
+
*
|
|
29
|
+
* Use this when the consumer needs to atomically commit state and move focus to
|
|
30
|
+
* a different element (e.g. SideNav expanding and focusing the first nav item).
|
|
31
|
+
*
|
|
32
|
+
* The universal pre/post work owned by `SkipLink` (e.g. `event.preventDefault`,
|
|
33
|
+
* `window.scrollTo`) still runs around this callback. Only the focus step is replaced.
|
|
34
|
+
*
|
|
35
|
+
* Only consumed when `platform_dst_nav4_skip_link_a11y_1` is enabled.
|
|
36
|
+
*/
|
|
37
|
+
navigate?: () => void;
|
|
38
|
+
/**
|
|
39
|
+
* Used to hide skip links for slots with 0 height or width.
|
|
23
40
|
*
|
|
24
41
|
* We can remove this once products conditionally render slots correctly.
|
|
25
42
|
*/
|
|
@@ -4,7 +4,7 @@ import { type SkipLinkData } from './types';
|
|
|
4
4
|
*
|
|
5
5
|
* `useSkipLink` is the public API wrapper of this.
|
|
6
6
|
*
|
|
7
|
-
* This private version exists for us to support `onBeforeNavigate` for the side nav use case,
|
|
8
|
-
* where we might need to expand it before moving focus, without having to support
|
|
7
|
+
* This private version exists for us to support `onBeforeNavigate` / `navigate` for the side nav use case,
|
|
8
|
+
* where we might need to expand it before moving focus, without having to support those publicly.
|
|
9
9
|
*/
|
|
10
|
-
export declare const useSkipLinkInternal: ({ id, label, listIndex, onBeforeNavigate, isHidden, }: SkipLinkData) => void;
|
|
10
|
+
export declare const useSkipLinkInternal: ({ id, label, listIndex, onBeforeNavigate, navigate, isHidden, }: SkipLinkData) => void;
|
|
@@ -8,11 +8,12 @@ type SkipLinkProps = {
|
|
|
8
8
|
id: string;
|
|
9
9
|
children: ReactNode;
|
|
10
10
|
onBeforeNavigate?: SkipLinkData['onBeforeNavigate'];
|
|
11
|
+
navigate?: SkipLinkData['navigate'];
|
|
11
12
|
};
|
|
12
13
|
/**
|
|
13
14
|
* A link that moves current tab position to a different element
|
|
14
15
|
*
|
|
15
16
|
* This component is rendered internally and is not exported publicly.
|
|
16
17
|
*/
|
|
17
|
-
export declare const SkipLink: ({ id, children, onBeforeNavigate }: SkipLinkProps) => JSX.Element;
|
|
18
|
+
export declare const SkipLink: ({ id, children, onBeforeNavigate, navigate, }: SkipLinkProps) => JSX.Element;
|
|
18
19
|
export {};
|
|
@@ -16,10 +16,27 @@ export type SkipLinkData = {
|
|
|
16
16
|
* immediately before focus is moved to the associated element.
|
|
17
17
|
*
|
|
18
18
|
* This can be used to update state, such as to show a hidden element.
|
|
19
|
+
*
|
|
20
|
+
* @deprecated Only used when `platform_dst_nav4_skip_link_a11y_1` is OFF.
|
|
21
|
+
* When the gate is on, prefer `navigate` for consumers that need to atomically
|
|
22
|
+
* commit state and move focus somewhere other than the slot element with id `id`.
|
|
23
|
+
* This callback can be removed once the gate is fully enabled and cleaned up.
|
|
19
24
|
*/
|
|
20
25
|
onBeforeNavigate?: () => void;
|
|
21
26
|
/**
|
|
22
|
-
*
|
|
27
|
+
* Replaces the default "focus the element with `id`" behavior when the skip link is activated.
|
|
28
|
+
*
|
|
29
|
+
* Use this when the consumer needs to atomically commit state and move focus to
|
|
30
|
+
* a different element (e.g. SideNav expanding and focusing the first nav item).
|
|
31
|
+
*
|
|
32
|
+
* The universal pre/post work owned by `SkipLink` (e.g. `event.preventDefault`,
|
|
33
|
+
* `window.scrollTo`) still runs around this callback. Only the focus step is replaced.
|
|
34
|
+
*
|
|
35
|
+
* Only consumed when `platform_dst_nav4_skip_link_a11y_1` is enabled.
|
|
36
|
+
*/
|
|
37
|
+
navigate?: () => void;
|
|
38
|
+
/**
|
|
39
|
+
* Used to hide skip links for slots with 0 height or width.
|
|
23
40
|
*
|
|
24
41
|
* We can remove this once products conditionally render slots correctly.
|
|
25
42
|
*/
|
|
@@ -4,7 +4,7 @@ import { type SkipLinkData } from './types';
|
|
|
4
4
|
*
|
|
5
5
|
* `useSkipLink` is the public API wrapper of this.
|
|
6
6
|
*
|
|
7
|
-
* This private version exists for us to support `onBeforeNavigate` for the side nav use case,
|
|
8
|
-
* where we might need to expand it before moving focus, without having to support
|
|
7
|
+
* This private version exists for us to support `onBeforeNavigate` / `navigate` for the side nav use case,
|
|
8
|
+
* where we might need to expand it before moving focus, without having to support those publicly.
|
|
9
9
|
*/
|
|
10
|
-
export declare const useSkipLinkInternal: ({ id, label, listIndex, onBeforeNavigate, isHidden, }: SkipLinkData) => void;
|
|
10
|
+
export declare const useSkipLinkInternal: ({ id, label, listIndex, onBeforeNavigate, navigate, isHidden, }: SkipLinkData) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/navigation-system",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.4.1",
|
|
4
4
|
"description": "The latest navigation system for Atlassian apps.",
|
|
5
5
|
"repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",
|
|
6
6
|
"author": "Atlassian Pty Ltd",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@atlaskit/button": "^23.11.0",
|
|
77
77
|
"@atlaskit/css": "^0.19.0",
|
|
78
78
|
"@atlaskit/ds-lib": "^7.0.0",
|
|
79
|
-
"@atlaskit/icon": "^
|
|
79
|
+
"@atlaskit/icon": "^35.0.0",
|
|
80
80
|
"@atlaskit/layering": "^3.7.0",
|
|
81
81
|
"@atlaskit/logo": "^20.1.0",
|
|
82
82
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
@@ -125,12 +125,12 @@
|
|
|
125
125
|
"@atlaskit/textfield": "^8.3.0",
|
|
126
126
|
"@atlaskit/top-layer": "^0.6.0",
|
|
127
127
|
"@atlassian/feature-flags-test-utils": "^1.1.0",
|
|
128
|
-
"@atlassian/gemini": "^1.
|
|
128
|
+
"@atlassian/gemini": "^1.45.0",
|
|
129
129
|
"@atlassian/react-compiler-gating": "workspace:^",
|
|
130
130
|
"@atlassian/search-dialog": "^10.3.0",
|
|
131
131
|
"@atlassian/ssr-tests": "workspace:^",
|
|
132
132
|
"@atlassian/test-utils": "^1.0.0",
|
|
133
|
-
"@atlassian/testing-library": "^0.
|
|
133
|
+
"@atlassian/testing-library": "^0.6.0",
|
|
134
134
|
"@axe-core/playwright": "^4.11.1",
|
|
135
135
|
"@testing-library/react": "^16.3.0",
|
|
136
136
|
"@testing-library/user-event": "^14.4.3",
|