@astryxdesign/core 0.1.7-canary.fb9c68c → 0.1.7
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/README.md +15 -24
- package/dist/Collapsible/Collapsible.d.ts +1 -11
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +4 -36
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +3 -4
- package/dist/ContextMenu/index.d.ts +0 -3
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +1 -7
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +4 -8
- package/dist/DropdownMenu/DropdownMenuContext.d.ts +1 -17
- package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.js +0 -18
- package/dist/DropdownMenu/index.d.ts +1 -5
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +1 -10
- package/dist/Icon/Icon.d.ts +12 -17
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +20 -28
- package/dist/Outline/Outline.d.ts +3 -69
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +26 -129
- package/dist/Outline/useScrollSpy.d.ts +7 -27
- package/dist/Outline/useScrollSpy.d.ts.map +1 -1
- package/dist/Outline/useScrollSpy.js +70 -202
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +2 -2
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +0 -2
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/index.d.ts +0 -2
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +0 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +2 -24
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +7 -18
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +3 -6
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +1 -8
- package/dist/astryx.css +2 -18
- package/dist/astryx.umd.js +48 -48
- package/dist/astryx.umd.js.map +4 -4
- package/dist/theme/Theme.js +1 -1
- package/dist/theme/defineTheme.d.ts +1 -1
- package/dist/theme/defineTheme.js +1 -1
- package/dist/theme/hct.d.ts +1 -0
- package/dist/theme/hct.d.ts.map +1 -1
- package/dist/theme/hct.js +3 -0
- package/locales/en.json +0 -28
- package/locales/pseudo.json +0 -21
- package/package.json +1 -3
- package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
- package/src/Collapsible/Collapsible.doc.mjs +0 -7
- package/src/Collapsible/Collapsible.test.tsx +0 -80
- package/src/Collapsible/Collapsible.tsx +5 -58
- package/src/ContextMenu/ContextMenu.test.tsx +1 -75
- package/src/ContextMenu/ContextMenu.tsx +5 -10
- package/src/ContextMenu/index.ts +0 -15
- package/src/DropdownMenu/DropdownMenu.doc.mjs +0 -23
- package/src/DropdownMenu/DropdownMenu.tsx +6 -11
- package/src/DropdownMenu/DropdownMenuContext.tsx +1 -29
- package/src/DropdownMenu/DropdownMenuItem.doc.mjs +1 -7
- package/src/DropdownMenu/index.ts +3 -23
- package/src/Field/Field.doc.mjs +1 -1
- package/src/Field/FieldLabel.doc.mjs +1 -1
- package/src/Icon/Icon.test.tsx +0 -46
- package/src/Icon/Icon.tsx +24 -37
- package/src/NumberInput/NumberInput.doc.mjs +2 -2
- package/src/Outline/Outline.doc.mjs +3 -123
- package/src/Outline/Outline.test.tsx +0 -735
- package/src/Outline/Outline.tsx +33 -184
- package/src/Outline/useScrollSpy.ts +72 -248
- package/src/Selector/SelectorOption.doc.mjs +1 -1
- package/src/SideNav/SideNavItem.doc.mjs +2 -2
- package/src/Switch/Switch.doc.mjs +1 -1
- package/src/TabList/Tab.tsx +1 -5
- package/src/TabList/TabList.doc.mjs +3 -3
- package/src/TabList/TabList.test.tsx +0 -66
- package/src/TabList/TabList.tsx +0 -8
- package/src/TabList/TabMenu.tsx +1 -4
- package/src/Table/Table.doc.mjs +0 -2
- package/src/Table/index.ts +0 -7
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +1 -90
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +5 -37
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +9 -95
- package/src/Table/plugins/sortable/useTableSortable.tsx +7 -23
- package/src/Table/useBaseTablePlugins.ts +2 -6
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextInput/TextInput.doc.mjs +1 -1
- package/src/Toolbar/Toolbar.tsx +3 -10
- package/src/theme/Theme.doc.mjs +4 -4
- package/src/theme/Theme.tsx +1 -1
- package/src/theme/defineTheme.ts +1 -1
- package/src/theme/hct.ts +4 -0
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +0 -89
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +0 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +0 -170
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +0 -69
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +0 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +0 -70
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +0 -69
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +0 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +0 -178
- package/dist/DropdownMenu/menuItemRoles.d.ts +0 -13
- package/dist/DropdownMenu/menuItemRoles.d.ts.map +0 -1
- package/dist/DropdownMenu/menuItemRoles.js +0 -15
- package/dist/Table/plugins/tree/index.d.ts +0 -5
- package/dist/Table/plugins/tree/index.d.ts.map +0 -1
- package/dist/Table/plugins/tree/index.js +0 -4
- package/dist/Table/plugins/tree/useTableTreeData.d.ts +0 -38
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +0 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +0 -358
- package/dist/Table/plugins/tree/useTableTreeState.d.ts +0 -51
- package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +0 -1
- package/dist/Table/plugins/tree/useTableTreeState.js +0 -175
- package/scripts/postinstall.mjs +0 -93
- package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +0 -95
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +0 -237
- package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +0 -80
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +0 -119
- package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +0 -80
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +0 -232
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +0 -163
- package/src/DropdownMenu/menuItemRoles.ts +0 -22
- package/src/Table/plugins/tree/index.ts +0 -12
- package/src/Table/plugins/tree/useTableTreeData-perf.test.tsx +0 -163
- package/src/Table/plugins/tree/useTableTreeData.test.tsx +0 -594
- package/src/Table/plugins/tree/useTableTreeData.tsx +0 -495
- package/src/Table/plugins/tree/useTableTreeState.test.tsx +0 -636
- package/src/Table/plugins/tree/useTableTreeState.tsx +0 -253
- package/src/Table/useTableTreeData.doc.mjs +0 -75
- package/src/Table/useTableTreeState.doc.mjs +0 -98
- package/src/postinstall.test.mjs +0 -71
|
@@ -19,50 +19,6 @@ export interface OutlineProps extends BaseProps<HTMLElement> {
|
|
|
19
19
|
* @default 'default'
|
|
20
20
|
*/
|
|
21
21
|
density?: 'default' | 'compact';
|
|
22
|
-
/**
|
|
23
|
-
* Called when navigation to an item begins, before the scroll starts.
|
|
24
|
-
* Receives the item `id`. Pair with `onNavigateEnd` to drive an arrival
|
|
25
|
-
* effect (flash, ring, pulse) on the target heading.
|
|
26
|
-
*/
|
|
27
|
-
onNavigateStart?: (id: string) => void;
|
|
28
|
-
/**
|
|
29
|
-
* Called once when navigation to an item resolves — when the smooth scroll
|
|
30
|
-
* settles, or immediately-ish when reduced motion turns it into a jump.
|
|
31
|
-
*
|
|
32
|
-
* Fires exactly once for every `onNavigateStart`, including when the user
|
|
33
|
-
* interrupts the scroll by scrolling manually, so a "navigating" state can
|
|
34
|
-
* never leak. It does not fire if the Outline unmounts mid-scroll.
|
|
35
|
-
*/
|
|
36
|
-
onNavigateEnd?: (id: string) => void;
|
|
37
|
-
/**
|
|
38
|
-
* Height in px of a fixed header overlaying the top of the scroll root.
|
|
39
|
-
*
|
|
40
|
-
* Shifts both the activation line *and* the scroll landing by the same
|
|
41
|
-
* amount, so a heading activates exactly where navigating to it puts it —
|
|
42
|
-
* below the header rather than hidden underneath it.
|
|
43
|
-
*
|
|
44
|
-
* It composes with each heading's own `scroll-margin-top` (the header, then
|
|
45
|
-
* the breathing room below it) rather than replacing it. When nothing
|
|
46
|
-
* overlays the content, leave this at 0 and let `scroll-margin-top` do the
|
|
47
|
-
* work — the browser already honors it.
|
|
48
|
-
*
|
|
49
|
-
* @default 0
|
|
50
|
-
*/
|
|
51
|
-
offset?: number;
|
|
52
|
-
/**
|
|
53
|
-
* Scroll container to track, instead of auto-detecting the nearest scrollable
|
|
54
|
-
* ancestor. Use this when the content scrolls inside a split pane, modal, or
|
|
55
|
-
* dashboard panel rather than the viewport.
|
|
56
|
-
*/
|
|
57
|
-
scrollContainerRef?: React.RefObject<HTMLElement | null>;
|
|
58
|
-
/**
|
|
59
|
-
* Whether activating an item smooth-scrolls to it. Set to false to own the
|
|
60
|
-
* scrolling yourself (virtualized content, a router) — the Outline still
|
|
61
|
-
* updates the active item, the hash, and the navigate callbacks, but performs
|
|
62
|
-
* no scroll and suppresses the anchor's default jump.
|
|
63
|
-
* @default true
|
|
64
|
-
*/
|
|
65
|
-
hasScrollOnClick?: boolean;
|
|
66
22
|
/** Test ID for testing frameworks. */
|
|
67
23
|
'data-testid'?: string;
|
|
68
24
|
}
|
|
@@ -74,15 +30,8 @@ export interface OutlineProps extends BaseProps<HTMLElement> {
|
|
|
74
30
|
* track that animates to the active item.
|
|
75
31
|
*
|
|
76
32
|
* When `activeId` is omitted, it tracks scroll position and marks the last
|
|
77
|
-
* heading whose top has passed its activation line
|
|
78
|
-
*
|
|
79
|
-
* scroll root) plus the heading's own `scroll-margin-top`. It defaults to the
|
|
80
|
-
* first item at the top and the last at the bottom.
|
|
81
|
-
*
|
|
82
|
-
* Keyboard: the list is a single tab stop (roving tabindex), seated on the
|
|
83
|
-
* active heading. Arrow keys move between headings, Home/End jump to the ends,
|
|
84
|
-
* and Enter/Space activate — so a long table of contents costs one Tab press,
|
|
85
|
-
* not one per heading.
|
|
33
|
+
* heading whose top has passed its activation line (its scroll-margin-top)
|
|
34
|
+
* active — defaulting to the first item at the top and the last at the bottom.
|
|
86
35
|
*
|
|
87
36
|
* @example
|
|
88
37
|
* ```
|
|
@@ -94,23 +43,8 @@ export interface OutlineProps extends BaseProps<HTMLElement> {
|
|
|
94
43
|
* ]}
|
|
95
44
|
* />
|
|
96
45
|
* ```
|
|
97
|
-
*
|
|
98
|
-
* Scoped to a custom scroll container, under a fixed header:
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* ```
|
|
102
|
-
* const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
103
|
-
*
|
|
104
|
-
* <div ref={scrollContainerRef} style={{overflowY: 'auto'}}>...</div>
|
|
105
|
-
* <Outline
|
|
106
|
-
* items={items}
|
|
107
|
-
* scrollContainerRef={scrollContainerRef}
|
|
108
|
-
* offset={64}
|
|
109
|
-
* onNavigateEnd={id => flashHeading(id)}
|
|
110
|
-
* />
|
|
111
|
-
* ```
|
|
112
46
|
*/
|
|
113
|
-
export declare function Outline({ items, activeId, onActiveIdChange, label: labelFromProps, density,
|
|
47
|
+
export declare function Outline({ items, activeId, onActiveIdChange, label: labelFromProps, density, xstyle, className, style, ref, 'data-testid': testId, ...props }: OutlineProps): import("react").JSX.Element;
|
|
114
48
|
export declare namespace Outline {
|
|
115
49
|
var displayName: string;
|
|
116
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Outline.d.ts","sourceRoot":"","sources":["../../src/Outline/Outline.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Outline.d.ts","sourceRoot":"","sources":["../../src/Outline/Outline.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,SAAS,CAAC;AAIzC,YAAY,EAAC,WAAW,EAAC,MAAM,SAAS,CAAC;AAEzC,MAAM,WAAW,YAAa,SAAQ,SAAS,CAAC,WAAW,CAAC;IAC1D,6CAA6C;IAC7C,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE7B,+CAA+C;IAC/C,KAAK,EAAE,WAAW,EAAE,CAAC;IAErB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;OAKG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAEhC,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgJD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,QAAQ,EACR,gBAAgB,EAChB,KAAK,EAAE,cAAc,EACrB,OAAmB,EACnB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,aAAa,EAAE,MAAM,EACrB,GAAG,KAAK,EACT,EAAE,YAAY,+BA2Gd;yBAvHe,OAAO"}
|
package/dist/Outline/Outline.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file Outline.tsx
|
|
7
|
-
* @input Uses React, StyleX, Astryx link provider integration, Outline hooks/types
|
|
7
|
+
* @input Uses React, StyleX, Astryx link provider integration, Outline hooks/types
|
|
8
8
|
* @output Exports Outline component and OutlineProps type
|
|
9
9
|
* @position Core implementation; consumed by index.ts
|
|
10
10
|
*
|
|
@@ -12,9 +12,6 @@
|
|
|
12
12
|
* - Sliding indicator track (vertical divider + animated active bar)
|
|
13
13
|
* - Density variant (default/compact)
|
|
14
14
|
* - Scroll-spy active state when uncontrolled
|
|
15
|
-
* - Roving-tabindex keyboard navigation (Arrow/Home/End, Enter/Space activate)
|
|
16
|
-
* - onNavigateStart / onNavigateEnd callbacks around the smooth scroll
|
|
17
|
-
* - Scroll scoping (offset, scrollContainerRef, hasScrollOnClick)
|
|
18
15
|
*
|
|
19
16
|
* SYNC: When modified, update these files to stay in sync:
|
|
20
17
|
* - /packages/core/src/Outline/Outline.doc.mjs
|
|
@@ -27,8 +24,6 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
27
24
|
import "../theme/tokens.stylex.js";
|
|
28
25
|
import { colorVars, durationVars, easeVars, radiusVars, spacingVars, typeScaleVars, fontWeightVars } from "../theme/tokens.stylex.js";
|
|
29
26
|
import { useLinkComponent } from "../Link/useLinkComponent.js";
|
|
30
|
-
import { useListFocus } from "../hooks/useListFocus.js";
|
|
31
|
-
import { useIsomorphicLayoutEffect } from "../hooks/useIsomorphicLayoutEffect.js";
|
|
32
27
|
import { mergeProps, mergeRefs } from "../utils/index.js";
|
|
33
28
|
import { useScrollSpy } from "./useScrollSpy.js";
|
|
34
29
|
import { themeProps } from "../utils/themeProps.js";
|
|
@@ -140,15 +135,8 @@ function getIndentStyle(level) {
|
|
|
140
135
|
* track that animates to the active item.
|
|
141
136
|
*
|
|
142
137
|
* When `activeId` is omitted, it tracks scroll position and marks the last
|
|
143
|
-
* heading whose top has passed its activation line
|
|
144
|
-
*
|
|
145
|
-
* scroll root) plus the heading's own `scroll-margin-top`. It defaults to the
|
|
146
|
-
* first item at the top and the last at the bottom.
|
|
147
|
-
*
|
|
148
|
-
* Keyboard: the list is a single tab stop (roving tabindex), seated on the
|
|
149
|
-
* active heading. Arrow keys move between headings, Home/End jump to the ends,
|
|
150
|
-
* and Enter/Space activate — so a long table of contents costs one Tab press,
|
|
151
|
-
* not one per heading.
|
|
138
|
+
* heading whose top has passed its activation line (its scroll-margin-top)
|
|
139
|
+
* active — defaulting to the first item at the top and the last at the bottom.
|
|
152
140
|
*
|
|
153
141
|
* @example
|
|
154
142
|
* ```
|
|
@@ -160,21 +148,6 @@ function getIndentStyle(level) {
|
|
|
160
148
|
* ]}
|
|
161
149
|
* />
|
|
162
150
|
* ```
|
|
163
|
-
*
|
|
164
|
-
* Scoped to a custom scroll container, under a fixed header:
|
|
165
|
-
*
|
|
166
|
-
* @example
|
|
167
|
-
* ```
|
|
168
|
-
* const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
169
|
-
*
|
|
170
|
-
* <div ref={scrollContainerRef} style={{overflowY: 'auto'}}>...</div>
|
|
171
|
-
* <Outline
|
|
172
|
-
* items={items}
|
|
173
|
-
* scrollContainerRef={scrollContainerRef}
|
|
174
|
-
* offset={64}
|
|
175
|
-
* onNavigateEnd={id => flashHeading(id)}
|
|
176
|
-
* />
|
|
177
|
-
* ```
|
|
178
151
|
*/
|
|
179
152
|
export function Outline({
|
|
180
153
|
items,
|
|
@@ -182,11 +155,6 @@ export function Outline({
|
|
|
182
155
|
onActiveIdChange,
|
|
183
156
|
label: labelFromProps,
|
|
184
157
|
density = 'default',
|
|
185
|
-
onNavigateStart,
|
|
186
|
-
onNavigateEnd,
|
|
187
|
-
offset = 0,
|
|
188
|
-
scrollContainerRef,
|
|
189
|
-
hasScrollOnClick = true,
|
|
190
158
|
xstyle,
|
|
191
159
|
className,
|
|
192
160
|
style,
|
|
@@ -198,109 +166,42 @@ export function Outline({
|
|
|
198
166
|
const label = labelFromProps ?? t('@astryx.outline.label');
|
|
199
167
|
const rootRef = useRef(null);
|
|
200
168
|
const LinkComponent = useLinkComponent();
|
|
169
|
+
const isControlled = activeId !== undefined;
|
|
201
170
|
const {
|
|
202
171
|
activeId: resolvedActiveId,
|
|
203
|
-
|
|
172
|
+
setActiveId,
|
|
173
|
+
lockActiveId
|
|
204
174
|
} = useScrollSpy({
|
|
205
175
|
activeId,
|
|
206
176
|
items,
|
|
207
177
|
onActiveIdChange,
|
|
208
|
-
rootRef
|
|
209
|
-
offset,
|
|
210
|
-
scrollContainerRef,
|
|
211
|
-
hasScrollOnClick,
|
|
212
|
-
onNavigateStart,
|
|
213
|
-
onNavigateEnd
|
|
178
|
+
rootRef
|
|
214
179
|
});
|
|
215
|
-
|
|
216
|
-
// Roving tabindex over the links: the whole outline is one tab stop, and
|
|
217
|
-
// arrows move between headings. The hook owns `tabindex` on the items.
|
|
218
|
-
const {
|
|
219
|
-
listRef,
|
|
220
|
-
handleKeyDown: handleListKeyDown,
|
|
221
|
-
handleFocus
|
|
222
|
-
} = useListFocus({
|
|
223
|
-
itemSelector: 'a[href]',
|
|
224
|
-
orientation: 'vertical',
|
|
225
|
-
hasRovingTabIndex: true
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
// Seat the tab stop on the *active* heading. WAI-ARIA puts the single tab
|
|
229
|
-
// stop on the current item, so tabbing into a table of contents while
|
|
230
|
-
// reading section 7 lands on section 7 — not back at section 1, which is
|
|
231
|
-
// where useListFocus would otherwise leave it (it promotes the first item on
|
|
232
|
-
// mount and then keeps whichever item already holds the stop).
|
|
233
|
-
//
|
|
234
|
-
// Only while focus is outside the list: once the reader has arrowed to an
|
|
235
|
-
// item, the stop is theirs and scroll-spy must not yank it away. Sets
|
|
236
|
-
// `tabindex` only — it never steals focus. Registered after useListFocus so
|
|
237
|
-
// it runs after the hook's own layout effect and wins; on later commits the
|
|
238
|
-
// hook then finds this item already holding the stop and keeps it.
|
|
239
|
-
useIsomorphicLayoutEffect(() => {
|
|
240
|
-
const list = listRef.current;
|
|
241
|
-
if (list == null || list.contains(document.activeElement)) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
const links = Array.from(list.querySelectorAll('a[href]'));
|
|
245
|
-
const active = links.find(link => link.getAttribute('aria-current') === 'true');
|
|
246
|
-
if (active == null) {
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
for (const link of links) {
|
|
250
|
-
const tabIndex = link === active ? '0' : '-1';
|
|
251
|
-
if (link.getAttribute('tabindex') !== tabIndex) {
|
|
252
|
-
link.setAttribute('tabindex', tabIndex);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* The single navigation path, shared by click and keyboard activation:
|
|
259
|
-
* push the hash, then hand off to the scroll-spy's `scrollTo`, which fires
|
|
260
|
-
* the navigate callbacks and moves the indicator when the scroll settles.
|
|
261
|
-
*/
|
|
262
|
-
const navigate = id => {
|
|
263
|
-
if (scrollTo(id)) {
|
|
264
|
-
window.history.pushState(null, '', `#${id}`);
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
/** Whether an event carries a modifier chord we must leave to the browser. */
|
|
269
|
-
const hasModifier = event => event.metaKey || event.altKey || event.ctrlKey || event.shiftKey;
|
|
270
180
|
const handleClick = id => event => {
|
|
271
|
-
|
|
272
|
-
// touching the active state.
|
|
273
|
-
if (event.defaultPrevented || hasModifier(event)) {
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
181
|
+
const target = document.getElementById(id);
|
|
276
182
|
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
|
|
280
|
-
// updates the URL) rather than swallowing the click into a dead link.
|
|
281
|
-
if (document.getElementById(id) == null) {
|
|
183
|
+
// Let the browser handle modified clicks (open in new tab, etc.) and
|
|
184
|
+
// missing targets without touching the active state.
|
|
185
|
+
if (target == null || event.defaultPrevented || event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) {
|
|
282
186
|
return;
|
|
283
187
|
}
|
|
284
|
-
|
|
285
|
-
// Suppress the anchor's default jump: we own the scroll (or, with
|
|
286
|
-
// `hasScrollOnClick={false}`, deliberately leave it to the consumer).
|
|
287
188
|
event.preventDefault();
|
|
288
|
-
|
|
289
|
-
};
|
|
290
|
-
const handleKeyDown = id => event => {
|
|
291
|
-
// Enter is a link's native activation and already produces a click.
|
|
292
|
-
// Space is not, so wire it up here to match the button-like affordance.
|
|
293
|
-
if (event.key !== ' ' && event.key !== 'Spacebar') {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
if (event.defaultPrevented || hasModifier(event)) {
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
189
|
+
window.history.pushState(null, '', `#${id}`);
|
|
299
190
|
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
|
|
303
|
-
|
|
191
|
+
// Move the indicator to the clicked item in a single step. Controlled
|
|
192
|
+
// consumers own the active state (notify only); uncontrolled mode pins
|
|
193
|
+
// the active id and suppresses scroll-spy until the next manual scroll,
|
|
194
|
+
// so the click is honored — even for short/last sections — and the
|
|
195
|
+
// indicator doesn't chase the smooth scroll through other sections.
|
|
196
|
+
if (isControlled) {
|
|
197
|
+
setActiveId(id);
|
|
198
|
+
} else {
|
|
199
|
+
lockActiveId(id);
|
|
200
|
+
}
|
|
201
|
+
target.scrollIntoView({
|
|
202
|
+
behavior: 'smooth',
|
|
203
|
+
block: 'start'
|
|
204
|
+
});
|
|
304
205
|
};
|
|
305
206
|
return /*#__PURE__*/_jsxs("nav", {
|
|
306
207
|
...props,
|
|
@@ -314,10 +215,7 @@ export function Outline({
|
|
|
314
215
|
...{
|
|
315
216
|
className: "x78zum5 xdt5ytf x1lsbc85 x1ghz6dp x1717udv xe8uvvx x98rzlu xeuugli"
|
|
316
217
|
},
|
|
317
|
-
ref: listRef,
|
|
318
218
|
role: "list",
|
|
319
|
-
onKeyDown: handleListKeyDown,
|
|
320
|
-
onFocus: handleFocus,
|
|
321
219
|
children: items.map(item => {
|
|
322
220
|
const isActive = item.id === resolvedActiveId;
|
|
323
221
|
return /*#__PURE__*/_jsx("li", {
|
|
@@ -329,7 +227,6 @@ export function Outline({
|
|
|
329
227
|
href: `#${item.id}`,
|
|
330
228
|
"aria-current": isActive ? 'true' : undefined,
|
|
331
229
|
onClick: handleClick(item.id),
|
|
332
|
-
onKeyDown: handleKeyDown(item.id),
|
|
333
230
|
...mergeProps(themeProps('outline-item', {
|
|
334
231
|
active: isActive ? 'active' : null,
|
|
335
232
|
level: item.level
|
|
@@ -4,40 +4,20 @@ interface UseScrollSpyOptions {
|
|
|
4
4
|
items: OutlineItem[];
|
|
5
5
|
onActiveIdChange?: (id: string) => void;
|
|
6
6
|
rootRef: React.RefObject<HTMLElement | null>;
|
|
7
|
-
/**
|
|
8
|
-
* Height in px of a fixed header overlaying the top of the scroll root.
|
|
9
|
-
* Shifts both the activation line and the scroll landing by the same amount,
|
|
10
|
-
* on top of each heading's own `scroll-margin-top`.
|
|
11
|
-
*/
|
|
12
|
-
offset?: number;
|
|
13
|
-
/** Scroll container to track, instead of the nearest scrollable ancestor. */
|
|
14
|
-
scrollContainerRef?: React.RefObject<HTMLElement | null>;
|
|
15
|
-
/** Whether {@link UseScrollSpyResult.scrollTo} performs the smooth scroll. */
|
|
16
|
-
hasScrollOnClick?: boolean;
|
|
17
|
-
/** Called when a navigation begins, before the scroll starts. */
|
|
18
|
-
onNavigateStart?: (id: string) => void;
|
|
19
|
-
/** Called once per navigation, when the scroll settles or is interrupted. */
|
|
20
|
-
onNavigateEnd?: (id: string) => void;
|
|
21
7
|
}
|
|
22
8
|
interface UseScrollSpyResult {
|
|
23
9
|
activeId: string | undefined;
|
|
24
10
|
/** Set the active id (notifies onActiveIdChange). For controlled consumers. */
|
|
25
11
|
setActiveId: (id: string) => void;
|
|
26
12
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* user interrupts it. While uncontrolled, scroll-spy is suppressed for the
|
|
33
|
-
* duration so the indicator doesn't chase the scroll through intervening
|
|
34
|
-
* sections; it lands on the target once the scroll settles, or resumes
|
|
35
|
-
* position tracking if the user scrolls away mid-flight.
|
|
36
|
-
*
|
|
37
|
-
* Returns false (and does nothing) when no element with `id` exists.
|
|
13
|
+
* Handle a click on the outline item with id `id`. Delays moving the
|
|
14
|
+
* indicator: scroll-spy is suppressed during the programmatic smooth scroll
|
|
15
|
+
* so the indicator doesn't chase it, then the indicator moves once to the
|
|
16
|
+
* clicked item when the scroll settles. If the user scrolls manually mid-way,
|
|
17
|
+
* scroll-position tracking resumes immediately instead.
|
|
38
18
|
*/
|
|
39
|
-
|
|
19
|
+
lockActiveId: (id: string) => void;
|
|
40
20
|
}
|
|
41
|
-
export declare function useScrollSpy({ activeId, items, onActiveIdChange, rootRef,
|
|
21
|
+
export declare function useScrollSpy({ activeId, items, onActiveIdChange, rootRef, }: UseScrollSpyOptions): UseScrollSpyResult;
|
|
42
22
|
export {};
|
|
43
23
|
//# sourceMappingURL=useScrollSpy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScrollSpy.d.ts","sourceRoot":"","sources":["../../src/Outline/useScrollSpy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useScrollSpy.d.ts","sourceRoot":"","sources":["../../src/Outline/useScrollSpy.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,SAAS,CAAC;AAuFzC,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC9C;AAED,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,+EAA+E;IAC/E,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;;;;OAMG;IACH,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,KAAK,EACL,gBAAgB,EAChB,OAAO,GACR,EAAE,mBAAmB,GAAG,kBAAkB,CA2I1C"}
|