@astryxdesign/core 0.7.7-canary.f9ac85f → 0.7.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/CHANGELOG.md +104 -0
- package/dist/AppShell/useCloseMobileDrawerOnActivate.d.ts +13 -0
- package/dist/AppShell/useCloseMobileDrawerOnActivate.d.ts.map +1 -0
- package/dist/AppShell/useCloseMobileDrawerOnActivate.js +45 -0
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +79 -9
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +1 -1
- package/dist/BottomSheet/bottomSheetStack.d.ts.map +1 -1
- package/dist/BottomSheet/bottomSheetStack.js +5 -4
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +2 -1
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +7 -3
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +30 -2
- package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxList.js +7 -1
- package/dist/CheckboxList/CheckboxListContext.d.ts +6 -0
- package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +10 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +5 -2
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +13 -27
- package/dist/DateInput/Wheel.d.ts.map +1 -1
- package/dist/DateInput/Wheel.js +22 -41
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +5 -2
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +4 -3
- package/dist/Drawer/Drawer.js +0 -1
- package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
- package/dist/Drawer/useDrawerDialogPresence.js +5 -1
- package/dist/Field/PanelSearchInput.d.ts +9 -1
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +3 -1
- package/dist/InfoTip/InfoTip.d.ts +2 -2
- package/dist/InfoTip/InfoTip.js +4 -4
- package/dist/Layer/layerAnimations.stylex.d.ts +7 -8
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +25 -20
- package/dist/Layer/usePressPin.d.ts +3 -5
- package/dist/Layer/usePressPin.d.ts.map +1 -1
- package/dist/Layer/usePressPin.js +4 -6
- package/dist/MobileNav/MobileNav.js +0 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +2 -4
- package/dist/Outline/Outline.d.ts +2 -4
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +4 -52
- package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/useOutlineFromMarkdown.js +1 -0
- package/dist/Outline/useScrollSpy.js +3 -3
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +134 -179
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +5 -0
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +118 -260
- package/dist/Resizable/resizeGesture.d.ts +91 -0
- package/dist/Resizable/resizeGesture.d.ts.map +1 -0
- package/dist/Resizable/resizeGesture.js +251 -0
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +3 -9
- package/dist/Token/Token.d.ts +2 -2
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +12 -4
- package/dist/Token/TokenNamingContext.d.ts +14 -0
- package/dist/Token/TokenNamingContext.d.ts.map +1 -0
- package/dist/Token/TokenNamingContext.js +23 -0
- package/dist/Tokenizer/Tokenizer.d.ts +46 -59
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +35 -58
- package/dist/Tokenizer/TokenizerBottomSheet.d.ts +25 -28
- package/dist/Tokenizer/TokenizerBottomSheet.d.ts.map +1 -1
- package/dist/Tokenizer/TokenizerBottomSheet.js +157 -54
- package/dist/Tokenizer/TokenizerItemRemovableContext.d.ts.map +1 -1
- package/dist/Tokenizer/TokenizerItemRemovableContext.js +5 -3
- package/dist/Tooltip/Tooltip.d.ts +25 -30
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/Tooltip.js +24 -5
- package/dist/Tooltip/index.d.ts +1 -1
- package/dist/Tooltip/index.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.d.ts +28 -29
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +20 -8
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +4 -7
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +4 -7
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +4 -7
- package/dist/astryx.css +5 -5
- package/dist/gestures/GestureHost.d.ts +27 -1
- package/dist/gestures/GestureHost.d.ts.map +1 -1
- package/dist/gestures/GestureHost.js +90 -8
- package/dist/hooks/useHighlightedOptionScroll.d.ts +11 -1
- package/dist/hooks/useHighlightedOptionScroll.d.ts.map +1 -1
- package/dist/hooks/useHighlightedOptionScroll.js +103 -5
- package/dist/hooks/useMenuPress.d.ts.map +1 -1
- package/dist/hooks/useMenuPress.js +4 -2
- package/dist/i18n/generated-english/PowerSearch/PowerSearch.generated.d.ts.map +1 -1
- package/dist/i18n/generated-english/PowerSearch/PowerSearch.generated.js +1 -0
- package/dist/i18n/generated-english/Tokenizer/TokenizerBottomSheet.generated.d.ts.map +1 -1
- package/dist/i18n/generated-english/Tokenizer/TokenizerBottomSheet.generated.js +7 -1
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +1 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +1 -0
- package/dist/internal/SheetConfirmation.d.ts +11 -0
- package/dist/internal/SheetConfirmation.d.ts.map +1 -0
- package/dist/internal/SheetConfirmation.js +92 -0
- package/dist/internal/sheetDraft.d.ts +35 -0
- package/dist/internal/sheetDraft.d.ts.map +1 -0
- package/dist/internal/sheetDraft.js +65 -0
- package/dist/internal/touch-sheet.d.ts +21 -0
- package/dist/internal/touch-sheet.d.ts.map +1 -0
- package/dist/internal/touch-sheet.js +19 -0
- package/dist/internal/useDismissSearchOnTouchDrag.d.ts +24 -0
- package/dist/internal/useDismissSearchOnTouchDrag.d.ts.map +1 -0
- package/dist/internal/useDismissSearchOnTouchDrag.js +56 -0
- package/dist/motion/reducedMotion.d.ts +24 -0
- package/dist/motion/reducedMotion.d.ts.map +1 -1
- package/dist/motion/reducedMotion.js +78 -1
- package/dist/utils/clickGuard.d.ts +8 -1
- package/dist/utils/clickGuard.d.ts.map +1 -1
- package/dist/utils/clickGuard.js +24 -1
- package/locales/en.json +4 -0
- package/locales/pseudo.json +3 -0
- package/package.json +9 -9
- package/src/AppShell/useCloseMobileDrawerOnActivate.ts +52 -0
- package/src/BottomSheet/BottomSheet.tsx +95 -10
- package/src/BottomSheet/BottomSheetPanel.tsx +7 -2
- package/src/BottomSheet/bottomSheetStack.ts +8 -4
- package/src/Breadcrumbs/BreadcrumbItem.tsx +13 -3
- package/src/Button/Button.tsx +37 -1
- package/src/CheckboxList/CheckboxList.doc.mjs +4 -2
- package/src/CheckboxList/CheckboxList.tsx +6 -0
- package/src/CheckboxList/CheckboxListContext.tsx +6 -0
- package/src/CheckboxList/CheckboxListItem.tsx +11 -2
- package/src/DateInput/DateInput.tsx +8 -2
- package/src/DateInput/MonthScroller.tsx +18 -22
- package/src/DateInput/Wheel.tsx +30 -32
- package/src/DateTimeInput/DateTimeInput.tsx +8 -2
- package/src/Dialog/Dialog.tsx +19 -4
- package/src/Drawer/Drawer.tsx +1 -1
- package/src/Drawer/useDrawerDialogPresence.ts +5 -1
- package/src/Field/PanelSearchInput.tsx +11 -0
- package/src/InfoTip/InfoTip.doc.mjs +3 -3
- package/src/InfoTip/InfoTip.tsx +5 -5
- package/src/Layer/layerAnimations.stylex.ts +24 -16
- package/src/Layer/usePressPin.ts +5 -11
- package/src/MobileNav/MobileNav.tsx +1 -1
- package/src/MultiSelector/hooks.ts +2 -4
- package/src/Outline/Outline.doc.mjs +177 -51
- package/src/Outline/Outline.tsx +5 -57
- package/src/Outline/useOutlineFromMarkdown.doc.mjs +157 -0
- package/src/Outline/useOutlineFromMarkdown.ts +1 -0
- package/src/Outline/useScrollSpy.ts +3 -3
- package/src/PowerSearch/PowerSearch.doc.mjs +3 -3
- package/src/PowerSearch/PowerSearch.tsx +196 -183
- package/src/RadioList/RadioList.doc.mjs +4 -2
- package/src/RadioList/RadioList.tsx +4 -0
- package/src/Resizable/ResizeHandle.tsx +133 -328
- package/src/Resizable/resizeGesture.ts +368 -0
- package/src/SideNav/SideNavItem.tsx +3 -7
- package/src/Token/Token.tsx +13 -4
- package/src/Token/TokenNamingContext.ts +28 -0
- package/src/Tokenizer/Tokenizer.doc.mjs +16 -0
- package/src/Tokenizer/Tokenizer.tsx +81 -86
- package/src/Tokenizer/TokenizerBottomSheet.tsx +219 -93
- package/src/Tokenizer/TokenizerItemRemovableContext.ts +5 -3
- package/src/Tooltip/Tooltip.doc.mjs +123 -54
- package/src/Tooltip/Tooltip.tsx +36 -39
- package/src/Tooltip/index.ts +0 -1
- package/src/Tooltip/useTooltip.doc.mjs +147 -33
- package/src/Tooltip/useTooltip.tsx +39 -32
- package/src/TopNav/TopNavItem.tsx +6 -5
- package/src/TopNav/TopNavMegaMenuItem.tsx +6 -5
- package/src/TopNav/TopNavMenu.tsx +6 -5
- package/src/gestures/GestureHost.ts +105 -10
- package/src/hooks/useHighlightedOptionScroll.ts +113 -9
- package/src/hooks/useMenuPress.ts +8 -2
- package/src/i18n/generated-english/PowerSearch/PowerSearch.generated.ts +1 -0
- package/src/i18n/generated-english/Tokenizer/TokenizerBottomSheet.generated.ts +7 -1
- package/src/i18n/generated-locales/en.generated.ts +1 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +1 -0
- package/src/internal/SheetConfirmation.tsx +101 -0
- package/src/internal/sheetDraft.ts +80 -0
- package/src/internal/touch-sheet.ts +21 -0
- package/src/internal/useDismissSearchOnTouchDrag.ts +69 -0
- package/src/motion/reducedMotion.ts +79 -1
- package/src/utils/clickGuard.ts +37 -1
- package/dist/internal/tokenizer-presentation.d.ts +0 -21
- package/dist/internal/tokenizer-presentation.d.ts.map +0 -1
- package/dist/internal/tokenizer-presentation.js +0 -21
- package/src/internal/tokenizer-presentation.ts +0 -25
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @file layerAnimations.stylex.ts
|
|
5
|
-
* @input Uses StyleX, theme duration/easing tokens
|
|
5
|
+
* @input Uses StyleX, theme duration/easing tokens, the Reduce Motion fade
|
|
6
|
+
* constants
|
|
6
7
|
* @output Exports shared entry animation styles for layer-based components
|
|
7
8
|
* @position Shared animation primitives; consumed by DropdownMenu, Popover,
|
|
8
9
|
* HoverCard, Tooltip, Selector, and any component using useLayer
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import * as stylex from '@stylexjs/stylex';
|
|
31
|
+
import {reducedMotionFadeConsts} from '../motion/reducedMotion.stylex';
|
|
30
32
|
import {durationVars, easeVars, spacingVars} from '../theme/tokens.stylex';
|
|
31
33
|
|
|
32
34
|
const enterBelow = stylex.keyframes({
|
|
@@ -84,17 +86,21 @@ const enterStartRtl = stylex.keyframes({
|
|
|
84
86
|
|
|
85
87
|
// Reduce Motion under a finger: the same entrance without its travel. A touch
|
|
86
88
|
// presentation substitutes a cross-fade for motion, never a jump.
|
|
89
|
+
// The fade's curve rides in its first keyframe, so the published class type
|
|
90
|
+
// of `animationTimingFunction` stays the theme ease's.
|
|
87
91
|
const fadeIn = stylex.keyframes({
|
|
88
|
-
from: {opacity: 0},
|
|
92
|
+
from: {opacity: 0, animationTimingFunction: reducedMotionFadeConsts.easing},
|
|
89
93
|
to: {opacity: 1},
|
|
90
94
|
});
|
|
91
95
|
|
|
96
|
+
// No theme value lengthens the Reduce Motion fade, so its values are constants.
|
|
97
|
+
// The media keys stay literal: StyleX gives an imported at-rule key a later
|
|
98
|
+
// priority layer (see reducedMotionKeys).
|
|
92
99
|
const animationBase = {
|
|
93
100
|
animationDuration: {
|
|
94
101
|
default: durationVars['--duration-fast-max'],
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)': `min(${durationVars['--duration-fast-max']}, 200ms)`,
|
|
102
|
+
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)':
|
|
103
|
+
reducedMotionFadeConsts.duration,
|
|
98
104
|
},
|
|
99
105
|
animationTimingFunction: easeVars['--ease-standard'],
|
|
100
106
|
animationFillMode: 'backwards' as const,
|
|
@@ -106,19 +112,18 @@ const animationBase = {
|
|
|
106
112
|
* Keyed by LayerPlacement ('above' | 'below' | 'start' | 'end')
|
|
107
113
|
* for easy lookup: `layerAnimations[placement]`.
|
|
108
114
|
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* (design:reduced-motion DR2, DR3), as iOS does for its menus, popovers and
|
|
115
|
-
* tips.
|
|
115
|
+
* Under `prefers-reduced-motion: reduce` each entry drops its travel and
|
|
116
|
+
* scale. Under a finger (the primary pointer is coarse) the layer fades in,
|
|
117
|
+
* opacity only, in 200 ms on easeInOut: on a touch screen Reduce Motion
|
|
118
|
+
* replaces motion with a cross-fade rather than a jump; under any other
|
|
119
|
+
* pointer it appears at once.
|
|
116
120
|
*/
|
|
117
121
|
export const layerAnimations = stylex.create({
|
|
118
122
|
below: {
|
|
119
123
|
animationName: {
|
|
120
124
|
default: enterBelow,
|
|
121
|
-
'@media (prefers-reduced-motion: reduce)
|
|
125
|
+
'@media (prefers-reduced-motion: reduce) and (not (pointer: coarse))':
|
|
126
|
+
'none',
|
|
122
127
|
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)': fadeIn,
|
|
123
128
|
},
|
|
124
129
|
...animationBase,
|
|
@@ -126,7 +131,8 @@ export const layerAnimations = stylex.create({
|
|
|
126
131
|
above: {
|
|
127
132
|
animationName: {
|
|
128
133
|
default: enterAbove,
|
|
129
|
-
'@media (prefers-reduced-motion: reduce)
|
|
134
|
+
'@media (prefers-reduced-motion: reduce) and (not (pointer: coarse))':
|
|
135
|
+
'none',
|
|
130
136
|
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)': fadeIn,
|
|
131
137
|
},
|
|
132
138
|
...animationBase,
|
|
@@ -135,7 +141,8 @@ export const layerAnimations = stylex.create({
|
|
|
135
141
|
animationName: {
|
|
136
142
|
default: enterEnd,
|
|
137
143
|
':is([dir="rtl"] *)': enterEndRtl,
|
|
138
|
-
'@media (prefers-reduced-motion: reduce)
|
|
144
|
+
'@media (prefers-reduced-motion: reduce) and (not (pointer: coarse))':
|
|
145
|
+
'none',
|
|
139
146
|
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)': fadeIn,
|
|
140
147
|
},
|
|
141
148
|
...animationBase,
|
|
@@ -144,7 +151,8 @@ export const layerAnimations = stylex.create({
|
|
|
144
151
|
animationName: {
|
|
145
152
|
default: enterStart,
|
|
146
153
|
':is([dir="rtl"] *)': enterStartRtl,
|
|
147
|
-
'@media (prefers-reduced-motion: reduce)
|
|
154
|
+
'@media (prefers-reduced-motion: reduce) and (not (pointer: coarse))':
|
|
155
|
+
'none',
|
|
148
156
|
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)': fadeIn,
|
|
149
157
|
},
|
|
150
158
|
...animationBase,
|
package/src/Layer/usePressPin.ts
CHANGED
|
@@ -35,12 +35,10 @@ import {
|
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* How the trigger opens the layer. `adaptive`, the default, previews it on
|
|
38
|
-
* hover and focus, and
|
|
39
|
-
*
|
|
40
|
-
* and focus, and no touch or pen tap opens it. `toggle` pins it on every
|
|
41
|
-
* press of a button trigger.
|
|
38
|
+
* hover and focus, and `touchTrigger` decides taps. `toggle` pins it on every
|
|
39
|
+
* press of a button trigger. Internal: InfoTip's press-to-pin uses `toggle`.
|
|
42
40
|
*/
|
|
43
|
-
export type LayerTriggerBehavior = 'adaptive' | '
|
|
41
|
+
export type LayerTriggerBehavior = 'adaptive' | 'toggle';
|
|
44
42
|
|
|
45
43
|
/** The clicks a press pin answered, so the wrapper can stop them (`stopPressPinClick`). */
|
|
46
44
|
const pressPinClicks = new WeakSet<Event>();
|
|
@@ -214,11 +212,7 @@ export function usePressPin(options: UsePressPinOptions): UsePressPinReturn {
|
|
|
214
212
|
clearTapOpen,
|
|
215
213
|
armOutsideDismiss,
|
|
216
214
|
} = useTouchTriggerInternal({
|
|
217
|
-
touchTrigger: isToggleMode
|
|
218
|
-
? 'tap'
|
|
219
|
-
: triggerBehavior === 'hover'
|
|
220
|
-
? 'none'
|
|
221
|
-
: options.touchTrigger,
|
|
215
|
+
touchTrigger: isToggleMode ? 'tap' : options.touchTrigger,
|
|
222
216
|
isEnabled: options.isEnabled,
|
|
223
217
|
isControlled: isOpen !== undefined,
|
|
224
218
|
isOpen: isLayerOpen,
|
|
@@ -466,7 +460,7 @@ export function usePressPin(options: UsePressPinOptions): UsePressPinReturn {
|
|
|
466
460
|
const isWired = isToggleMode && offeredKind === 'button';
|
|
467
461
|
useDevWarning(
|
|
468
462
|
options.component,
|
|
469
|
-
'
|
|
463
|
+
'A press-to-pin tooltip pins only a button trigger (a <button> or role="button"); this trigger keeps tap-only opening.',
|
|
470
464
|
isToggleMode && offeredKind === 'other',
|
|
471
465
|
);
|
|
472
466
|
|
|
@@ -143,8 +143,8 @@ const styles = stylex.create({
|
|
|
143
143
|
// ::backdrop is provided by the browser's top layer
|
|
144
144
|
backdrop: {
|
|
145
145
|
'::backdrop': {
|
|
146
|
+
// No backdrop-filter: a full-viewport blur is costly to repaint.
|
|
146
147
|
backgroundColor: colorVars['--color-overlay'],
|
|
147
|
-
backdropFilter: 'blur(2px)',
|
|
148
148
|
opacity: 0,
|
|
149
149
|
transitionProperty: 'opacity',
|
|
150
150
|
transitionDuration: durationVars['--duration-medium'],
|
|
@@ -174,13 +174,11 @@ export function useMultiCombobox({
|
|
|
174
174
|
// The action cell is the caller's control, usable whether or not the
|
|
175
175
|
// option itself is disabled (spec:AST-058 FR4).
|
|
176
176
|
if (cell === 'action') {
|
|
177
|
-
highlightOnHover(index);
|
|
178
|
-
setHighlightedCell('action');
|
|
177
|
+
highlightOnHover(index, () => setHighlightedCell('action'));
|
|
179
178
|
return;
|
|
180
179
|
}
|
|
181
180
|
if (!item.disabled) {
|
|
182
|
-
highlightOnHover(index);
|
|
183
|
-
setHighlightedCell('option');
|
|
181
|
+
highlightOnHover(index, () => setHighlightedCell('option'));
|
|
184
182
|
}
|
|
185
183
|
},
|
|
186
184
|
[highlightOnHover],
|
|
@@ -63,7 +63,11 @@ export const docs = {
|
|
|
63
63
|
targets: [
|
|
64
64
|
{className: 'astryx-outline', visualProps: ['density']},
|
|
65
65
|
{className: 'astryx-outline-indicator'},
|
|
66
|
-
{
|
|
66
|
+
{
|
|
67
|
+
className: 'astryx-outline-item',
|
|
68
|
+
visualProps: ['level'],
|
|
69
|
+
states: ['active'],
|
|
70
|
+
},
|
|
67
71
|
],
|
|
68
72
|
},
|
|
69
73
|
components: [
|
|
@@ -101,7 +105,8 @@ export const docs = {
|
|
|
101
105
|
{
|
|
102
106
|
name: 'density',
|
|
103
107
|
type: "'default' | 'compact'",
|
|
104
|
-
description:
|
|
108
|
+
description:
|
|
109
|
+
"Density variant controlling item padding. 'compact' for dense UIs, 'default' for standard spacing.",
|
|
105
110
|
default: "'default'",
|
|
106
111
|
},
|
|
107
112
|
{
|
|
@@ -271,17 +276,53 @@ function FlashOnArrival() {
|
|
|
271
276
|
usage: {
|
|
272
277
|
anatomy,
|
|
273
278
|
description:
|
|
274
|
-
'A table-of-contents sidebar for documentation pages, help centers, wikis, and long settings pages. Use it for navigation within a single page, not for app routes. Features a sliding indicator track that animates to the active heading.
|
|
279
|
+
'A table-of-contents sidebar for documentation pages, help centers, wikis, and long settings pages. Use it for navigation within a single page, not for app routes. Features a sliding indicator track that animates to the active heading. Each link is in the normal Tab order, and Enter/Space activate.',
|
|
275
280
|
bestPractices: [
|
|
276
|
-
{
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
{
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
281
|
+
{
|
|
282
|
+
guidance: true,
|
|
283
|
+
description:
|
|
284
|
+
'Pass a flat ordered list of headings and let level control indentation.',
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
guidance: true,
|
|
288
|
+
description:
|
|
289
|
+
'Use activeId when custom scroll logic owns the active section.',
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
guidance: true,
|
|
293
|
+
description:
|
|
294
|
+
'Use density="compact" in dense sidebars where vertical space is tight.',
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
guidance: true,
|
|
298
|
+
description:
|
|
299
|
+
'Use useOutlineFromMarkdown or useOutlineFromDOM when headings are generated from content. For linkable Markdown headings, pass the same createMarkdownHeadingLinks() entry to Markdown and Outline; configure headingIdPrefix on that plugin for multiple roots.',
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
guidance: true,
|
|
303
|
+
description:
|
|
304
|
+
'Pass scrollContainerRef when the content scrolls in a split pane, modal, or panel instead of the viewport.',
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
guidance: true,
|
|
308
|
+
description:
|
|
309
|
+
'Set offset to the height of a fixed header that overlays the content, so headings land below it instead of underneath it.',
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
guidance: false,
|
|
313
|
+
description:
|
|
314
|
+
'Use Outline for application navigation - use SideNav or TopNav for routes.',
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
guidance: false,
|
|
318
|
+
description:
|
|
319
|
+
'Use Outline for expandable hierarchy - use TreeList when nodes need expand and collapse.',
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
guidance: false,
|
|
323
|
+
description:
|
|
324
|
+
'Rely on onNavigateEnd to mean "arrived" - it also fires when the user interrupts the scroll.',
|
|
325
|
+
},
|
|
285
326
|
],
|
|
286
327
|
},
|
|
287
328
|
};
|
|
@@ -295,7 +336,11 @@ export const docsZh = {
|
|
|
295
336
|
targets: [
|
|
296
337
|
{className: 'astryx-outline', visualProps: ['density']},
|
|
297
338
|
{className: 'astryx-outline-indicator'},
|
|
298
|
-
{
|
|
339
|
+
{
|
|
340
|
+
className: 'astryx-outline-item',
|
|
341
|
+
visualProps: ['level'],
|
|
342
|
+
states: ['active'],
|
|
343
|
+
},
|
|
299
344
|
],
|
|
300
345
|
},
|
|
301
346
|
components: [
|
|
@@ -332,40 +377,47 @@ export const docsZh = {
|
|
|
332
377
|
{
|
|
333
378
|
name: 'density',
|
|
334
379
|
type: "'default' | 'compact'",
|
|
335
|
-
description:
|
|
380
|
+
description:
|
|
381
|
+
"控制项目内边距的密度变体。'compact' 用于紧凑界面,'default' 为标准间距。",
|
|
336
382
|
default: "'default'",
|
|
337
383
|
},
|
|
338
384
|
{
|
|
339
385
|
name: 'onNavigateStart',
|
|
340
386
|
type: '(id: string) => void',
|
|
341
|
-
description:
|
|
387
|
+
description:
|
|
388
|
+
'导航开始时(滚动前)调用,传入项目 id。与 onNavigateEnd 搭配可在目标标题上实现到达效果(闪烁、描边、脉冲)。',
|
|
342
389
|
},
|
|
343
390
|
{
|
|
344
391
|
name: 'onNavigateEnd',
|
|
345
392
|
type: '(id: string) => void',
|
|
346
|
-
description:
|
|
393
|
+
description:
|
|
394
|
+
'导航结束时调用(平滑滚动停止,或减弱动效将其变为瞬时跳转)。每次 onNavigateStart 必定对应一次调用,包括用户中途手动滚动打断的情况,因此“导航中”状态不会泄漏。',
|
|
347
395
|
},
|
|
348
396
|
{
|
|
349
397
|
name: 'offset',
|
|
350
398
|
type: 'number',
|
|
351
|
-
description:
|
|
399
|
+
description:
|
|
400
|
+
'覆盖滚动根顶部的固定顶栏高度(px)。同时位移激活线与滚动落点,因此标题被激活的位置正是点击后停留的位置——落在顶栏下方,而非被顶栏遮住。它与每个标题自身的 scroll-margin-top 叠加(先顶栏,再留白),而非取代它。若没有元素覆盖内容,保持 0,交给 scroll-margin-top 处理。',
|
|
352
401
|
default: '0',
|
|
353
402
|
},
|
|
354
403
|
{
|
|
355
404
|
name: 'scrollContainerRef',
|
|
356
405
|
type: 'React.RefObject<HTMLElement | null>',
|
|
357
|
-
description:
|
|
406
|
+
description:
|
|
407
|
+
'要跟踪的滚动容器,替代自动探测最近的可滚动祖先。当内容在分栏、弹窗或面板中滚动而非视口时使用。',
|
|
358
408
|
},
|
|
359
409
|
{
|
|
360
410
|
name: 'hasScrollOnClick',
|
|
361
411
|
type: 'boolean',
|
|
362
|
-
description:
|
|
412
|
+
description:
|
|
413
|
+
'激活项目时是否平滑滚动。设为 false 可自行接管滚动(虚拟列表、路由):Outline 仍会更新激活项、hash 和导航回调,但不执行滚动。',
|
|
363
414
|
default: 'true',
|
|
364
415
|
},
|
|
365
416
|
{
|
|
366
417
|
name: 'xstyle',
|
|
367
418
|
type: 'StyleXStyles',
|
|
368
|
-
description:
|
|
419
|
+
description:
|
|
420
|
+
'用于布局自定义的 StyleX 样式。必须是 stylex.create() 值。',
|
|
369
421
|
},
|
|
370
422
|
],
|
|
371
423
|
},
|
|
@@ -375,12 +427,36 @@ export const docsZh = {
|
|
|
375
427
|
description:
|
|
376
428
|
'A table-of-contents sidebar for documentation pages, help centers, wikis, and long settings pages. Use it for navigation within a single page, not for app routes.',
|
|
377
429
|
bestPractices: [
|
|
378
|
-
{
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
{
|
|
430
|
+
{
|
|
431
|
+
guidance: true,
|
|
432
|
+
description:
|
|
433
|
+
'Pass a flat ordered list of headings and let level control indentation.',
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
guidance: true,
|
|
437
|
+
description:
|
|
438
|
+
'Use activeId when custom scroll logic owns the active section.',
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
guidance: true,
|
|
442
|
+
description:
|
|
443
|
+
'Use density="compact" in dense sidebars where vertical space is tight.',
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
guidance: true,
|
|
447
|
+
description:
|
|
448
|
+
'Use useOutlineFromMarkdown or useOutlineFromDOM when headings are generated from content. For linkable Markdown headings, pass the same createMarkdownHeadingLinks() entry to Markdown and Outline; configure headingIdPrefix on that plugin for multiple roots.',
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
guidance: false,
|
|
452
|
+
description:
|
|
453
|
+
'Use Outline for application navigation - use SideNav or TopNav for routes.',
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
guidance: false,
|
|
457
|
+
description:
|
|
458
|
+
'Use Outline for expandable hierarchy - use TreeList when nodes need expand and collapse.',
|
|
459
|
+
},
|
|
384
460
|
],
|
|
385
461
|
},
|
|
386
462
|
};
|
|
@@ -388,34 +464,77 @@ export const docsZh = {
|
|
|
388
464
|
/** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
|
|
389
465
|
export const docsDense = {
|
|
390
466
|
description:
|
|
391
|
-
'Document outline/table-of-contents nav with sliding indicator track. Flat items array {id,label,level}; anchor links; density variant (default/compact); uncontrolled scroll-spy by scroll position (last heading past its resting line = offset + its own scroll-margin-top; first item at top, last at bottom); controlled with activeId; smooth-scroll on click that pins the active item until the next manual scroll.
|
|
467
|
+
'Document outline/table-of-contents nav with sliding indicator track. Flat items array {id,label,level}; anchor links; density variant (default/compact); uncontrolled scroll-spy by scroll position (last heading past its resting line = offset + its own scroll-margin-top; first item at top, last at bottom); controlled with activeId; smooth-scroll on click that pins the active item until the next manual scroll. Each link is a Tab stop; Enter/Space activate; no arrow/Home/End movement. onNavigateStart/onNavigateEnd fire around the scroll. Scroll scoping via offset / scrollContainerRef / hasScrollOnClick.',
|
|
392
468
|
usage: {
|
|
393
469
|
anatomy,
|
|
394
470
|
description:
|
|
395
471
|
'A table-of-contents sidebar for documentation pages, help centers, wikis, and long settings pages. Use it for navigation within a single page, not for app routes.',
|
|
396
472
|
bestPractices: [
|
|
397
|
-
{
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
{
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
473
|
+
{
|
|
474
|
+
guidance: true,
|
|
475
|
+
description:
|
|
476
|
+
'Pass a flat ordered list of headings and let level control indentation.',
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
guidance: true,
|
|
480
|
+
description:
|
|
481
|
+
'Use activeId when custom scroll logic owns the active section.',
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
guidance: true,
|
|
485
|
+
description:
|
|
486
|
+
'Use density="compact" in dense sidebars where vertical space is tight.',
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
guidance: true,
|
|
490
|
+
description:
|
|
491
|
+
'Use useOutlineFromMarkdown or useOutlineFromDOM when headings are generated from content. For linkable Markdown headings, pass the same createMarkdownHeadingLinks() entry to Markdown and Outline; configure headingIdPrefix on that plugin for multiple roots.',
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
guidance: true,
|
|
495
|
+
description:
|
|
496
|
+
'Pass scrollContainerRef when the content scrolls in a split pane, modal, or panel instead of the viewport.',
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
guidance: true,
|
|
500
|
+
description:
|
|
501
|
+
'Set offset to the height of a fixed header that overlays the content, so headings land below it instead of underneath it.',
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
guidance: false,
|
|
505
|
+
description:
|
|
506
|
+
'Use Outline for application navigation - use SideNav or TopNav for routes.',
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
guidance: false,
|
|
510
|
+
description:
|
|
511
|
+
'Use Outline for expandable hierarchy - use TreeList when nodes need expand and collapse.',
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
guidance: false,
|
|
515
|
+
description:
|
|
516
|
+
'Rely on onNavigateEnd to mean "arrived" - it also fires when the user interrupts the scroll.',
|
|
517
|
+
},
|
|
406
518
|
],
|
|
407
519
|
},
|
|
408
520
|
propDescriptions: {
|
|
409
|
-
items:
|
|
521
|
+
items:
|
|
522
|
+
'Ordered OutlineItem[]: {id,label,level}. id should match target heading DOM id.',
|
|
410
523
|
activeId: 'Controlled active heading id. Disables built-in scroll-spy.',
|
|
411
524
|
onActiveIdChange: 'Called when active id changes from scroll-spy or click.',
|
|
412
525
|
label: "Accessible nav label. Default: 'Table of contents'.",
|
|
413
|
-
density:
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
526
|
+
density:
|
|
527
|
+
"Density variant: 'default' (standard) or 'compact'. Default: 'default'.",
|
|
528
|
+
onNavigateStart:
|
|
529
|
+
'Called with the id when navigation begins, before the scroll.',
|
|
530
|
+
onNavigateEnd:
|
|
531
|
+
'Called with the id once the scroll settles. Fires exactly once per onNavigateStart, including on user interruption.',
|
|
532
|
+
offset:
|
|
533
|
+
'Height in px of a fixed header overlaying the scroll root. Shifts BOTH the activation line and the scroll landing, so a heading activates where navigating to it lands it. Composes with (does not replace) each heading scroll-margin-top. Default: 0.',
|
|
534
|
+
scrollContainerRef:
|
|
535
|
+
'RefObject of the scroll container to track, instead of the nearest scrollable ancestor. For split panes, modals, panels.',
|
|
536
|
+
hasScrollOnClick:
|
|
537
|
+
'Whether activating an item smooth-scrolls to it. false = you own scrolling; active id, hash and callbacks still update. Default: true.',
|
|
419
538
|
xstyle: 'StyleX styles for layout. Must be stylex.create() value.',
|
|
420
539
|
},
|
|
421
540
|
components: [
|
|
@@ -423,18 +542,25 @@ export const docsDense = {
|
|
|
423
542
|
name: 'Outline',
|
|
424
543
|
displayName: 'Outline',
|
|
425
544
|
description:
|
|
426
|
-
'Document outline nav with sliding indicator. Renders heading anchors with a density variant,
|
|
545
|
+
'Document outline nav with sliding indicator. Renders heading anchors with a density variant, links in the normal Tab order, navigate callbacks, and scroll-spy active state when uncontrolled.',
|
|
427
546
|
propDescriptions: {
|
|
428
|
-
items:
|
|
547
|
+
items:
|
|
548
|
+
'Ordered OutlineItem[]: {id,label,level}. id should match target heading DOM id.',
|
|
429
549
|
activeId: 'Controlled active heading id. Disables built-in scroll-spy.',
|
|
430
|
-
onActiveIdChange:
|
|
550
|
+
onActiveIdChange:
|
|
551
|
+
'Called when active id changes from scroll-spy or click.',
|
|
431
552
|
label: "Accessible nav label. Default: 'Table of contents'.",
|
|
432
553
|
density: "Density variant: 'default' | 'compact'. Default: 'default'.",
|
|
433
|
-
onNavigateStart:
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
554
|
+
onNavigateStart:
|
|
555
|
+
'Called with the id when navigation begins, before the scroll.',
|
|
556
|
+
onNavigateEnd:
|
|
557
|
+
'Called with the id once the scroll settles. Fires exactly once per onNavigateStart, including on user interruption.',
|
|
558
|
+
offset:
|
|
559
|
+
'Height in px of a fixed header overlaying the scroll root. Shifts both the activation line and the scroll landing. Composes with scroll-margin-top. Default: 0.',
|
|
560
|
+
scrollContainerRef:
|
|
561
|
+
'RefObject of the scroll container to track, instead of the nearest scrollable ancestor.',
|
|
562
|
+
hasScrollOnClick:
|
|
563
|
+
'Whether activating an item smooth-scrolls to it. Default: true.',
|
|
438
564
|
xstyle: 'StyleX styles for layout. Must be stylex.create() value.',
|
|
439
565
|
},
|
|
440
566
|
},
|
package/src/Outline/Outline.tsx
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,7 +12,7 @@
|
|
|
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
|
-
* -
|
|
15
|
+
* - Each link in the normal Tab order (Enter/Space activate)
|
|
16
16
|
* - onNavigateStart / onNavigateEnd callbacks around the smooth scroll
|
|
17
17
|
* - Scroll scoping (offset, scrollContainerRef, hasScrollOnClick)
|
|
18
18
|
*
|
|
@@ -35,8 +35,6 @@ import {
|
|
|
35
35
|
fontWeightVars,
|
|
36
36
|
} from '../theme/tokens.stylex';
|
|
37
37
|
import {useLinkComponent} from '../Link/useLinkComponent';
|
|
38
|
-
import {useListFocus} from '../hooks/useListFocus';
|
|
39
|
-
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
40
38
|
import {mergeProps} from '../utils';
|
|
41
39
|
import type {BaseProps} from '../BaseProps';
|
|
42
40
|
import {useScrollSpy} from './useScrollSpy';
|
|
@@ -304,10 +302,8 @@ function moveFocusTo(id: string) {
|
|
|
304
302
|
* scroll root) plus the heading's own `scroll-margin-top`. It defaults to the
|
|
305
303
|
* first item at the top and the last at the bottom.
|
|
306
304
|
*
|
|
307
|
-
* Keyboard:
|
|
308
|
-
*
|
|
309
|
-
* and Enter/Space activate — so a long table of contents costs one Tab press,
|
|
310
|
-
* not one per heading.
|
|
305
|
+
* Keyboard: each link is in the normal Tab order, and Enter/Space activate.
|
|
306
|
+
* There is no arrow, Home, or End movement between links.
|
|
311
307
|
*
|
|
312
308
|
* @example
|
|
313
309
|
* ```
|
|
@@ -369,49 +365,6 @@ export function Outline({
|
|
|
369
365
|
onNavigateEnd,
|
|
370
366
|
});
|
|
371
367
|
|
|
372
|
-
// Roving tabindex over the links: the whole outline is one tab stop, and
|
|
373
|
-
// arrows move between headings. The hook owns `tabindex` on the items.
|
|
374
|
-
const {
|
|
375
|
-
listRef,
|
|
376
|
-
handleKeyDown: handleListKeyDown,
|
|
377
|
-
handleFocus,
|
|
378
|
-
} = useListFocus<HTMLUListElement>({
|
|
379
|
-
itemSelector: 'a[href]',
|
|
380
|
-
orientation: 'vertical',
|
|
381
|
-
hasRovingTabIndex: true,
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
// Seat the tab stop on the *active* heading. WAI-ARIA puts the single tab
|
|
385
|
-
// stop on the current item, so tabbing into a table of contents while
|
|
386
|
-
// reading section 7 lands on section 7 — not back at section 1, which is
|
|
387
|
-
// where useListFocus would otherwise leave it (it promotes the first item on
|
|
388
|
-
// mount and then keeps whichever item already holds the stop).
|
|
389
|
-
//
|
|
390
|
-
// Only while focus is outside the list: once the reader has arrowed to an
|
|
391
|
-
// item, the stop is theirs and scroll-spy must not yank it away. Sets
|
|
392
|
-
// `tabindex` only — it never steals focus. Registered after useListFocus so
|
|
393
|
-
// it runs after the hook's own layout effect and wins; on later commits the
|
|
394
|
-
// hook then finds this item already holding the stop and keeps it.
|
|
395
|
-
useIsomorphicLayoutEffect(() => {
|
|
396
|
-
const list = listRef.current;
|
|
397
|
-
if (list == null || list.contains(document.activeElement)) {
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
const links = Array.from(list.querySelectorAll<HTMLElement>('a[href]'));
|
|
401
|
-
const active = links.find(
|
|
402
|
-
link => link.getAttribute('aria-current') === 'location',
|
|
403
|
-
);
|
|
404
|
-
if (active == null) {
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
for (const link of links) {
|
|
408
|
-
const tabIndex = link === active ? '0' : '-1';
|
|
409
|
-
if (link.getAttribute('tabindex') !== tabIndex) {
|
|
410
|
-
link.setAttribute('tabindex', tabIndex);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
});
|
|
414
|
-
|
|
415
368
|
/**
|
|
416
369
|
* The single navigation path, shared by click and keyboard activation:
|
|
417
370
|
* push the hash, then hand off to the scroll-spy's `scrollTo`, which fires
|
|
@@ -480,12 +433,7 @@ export function Outline({
|
|
|
480
433
|
className,
|
|
481
434
|
style,
|
|
482
435
|
)}>
|
|
483
|
-
<ul
|
|
484
|
-
{...stylex.props(styles.list)}
|
|
485
|
-
ref={listRef}
|
|
486
|
-
role="list"
|
|
487
|
-
onKeyDown={handleListKeyDown}
|
|
488
|
-
onFocus={handleFocus}>
|
|
436
|
+
<ul {...stylex.props(styles.list)} role="list">
|
|
489
437
|
{items.map(item => {
|
|
490
438
|
const isActive = item.id === resolvedActiveId;
|
|
491
439
|
|