@astryxdesign/core 0.1.2-canary.bd8c3d3 → 0.1.2-canary.bfcbf64
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/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +11 -5
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +20 -4
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +11 -11
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +4 -2
- package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxList.js +12 -4
- package/dist/ContextMenu/ContextMenu.d.ts +6 -1
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +58 -7
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +17 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +9 -4
- package/dist/DateTimeInput/DateTimeInput.d.ts +7 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +15 -3
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +12 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +25 -4
- package/dist/Field/Field.d.ts +19 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +4 -0
- package/dist/Field/FieldLabel.d.ts +21 -2
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +37 -22
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +27 -6
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +4 -1
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +33 -1
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +36 -5
- package/dist/Layout/padding.stylex.d.ts +51 -0
- package/dist/Layout/padding.stylex.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.js +63 -0
- package/dist/Link/Link.d.ts +7 -1
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +12 -4
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +35 -6
- package/dist/MultiSelector/hooks.d.ts +12 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +14 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +17 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +7 -1
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +8 -0
- package/dist/ProgressBar/ProgressBar.js +1 -1
- package/dist/RadioList/RadioList.d.ts +1 -1
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +76 -3
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +6 -2
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +15 -8
- package/dist/Selector/hooks.d.ts +8 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +14 -1
- package/dist/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +8 -2
- package/dist/Stack/Stack.d.ts +28 -1
- package/dist/Stack/Stack.d.ts.map +1 -1
- package/dist/Stack/Stack.js +17 -1
- package/dist/Stack/StackItem.d.ts +12 -1
- package/dist/Stack/StackItem.d.ts.map +1 -1
- package/dist/Stack/StackItem.js +8 -1
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +6 -0
- package/dist/TabList/TabList.d.ts +15 -4
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +58 -4
- package/dist/TabList/TabListContext.d.ts +5 -0
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +5 -0
- package/dist/TabList/TabMenu.js +2 -0
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +14 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +132 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +7 -3
- package/dist/TreeList/TreeList.d.ts +1 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +78 -2
- package/dist/TreeList/TreeListItem.d.ts +10 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +44 -10
- package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
- package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
- package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +41 -3
- package/dist/astryx.css +3 -0
- package/dist/astryx.umd.js +47 -47
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/index.d.ts +10 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +6 -2
- package/dist/hooks/useAnnounce.d.ts +40 -0
- package/dist/hooks/useAnnounce.d.ts.map +1 -0
- package/dist/hooks/useAnnounce.js +142 -0
- package/dist/hooks/useClickableContainer.d.ts +16 -1
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +16 -4
- package/dist/hooks/useFocusTrap.d.ts +18 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +65 -0
- package/dist/hooks/useListFocus.d.ts +79 -8
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +262 -48
- package/dist/hooks/useLongPress.d.ts +21 -0
- package/dist/hooks/useLongPress.d.ts.map +1 -0
- package/dist/hooks/useLongPress.js +89 -0
- package/dist/hooks/useTreeFocus.d.ts +133 -0
- package/dist/hooks/useTreeFocus.d.ts.map +1 -0
- package/dist/hooks/useTreeFocus.js +274 -0
- package/dist/hooks/useTypeahead.d.ts +63 -0
- package/dist/hooks/useTypeahead.d.ts.map +1 -0
- package/dist/hooks/useTypeahead.js +117 -0
- package/package.json +1 -1
- package/src/Avatar/Avatar.test.tsx +37 -0
- package/src/Avatar/Avatar.tsx +10 -5
- package/src/Breadcrumbs/BreadcrumbItem.tsx +20 -5
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
- package/src/Calendar/Calendar.test.tsx +25 -0
- package/src/Calendar/Calendar.tsx +10 -12
- package/src/CheckboxInput/CheckboxInput.test.tsx +14 -25
- package/src/CheckboxInput/CheckboxInput.tsx +4 -2
- package/src/CheckboxList/CheckboxList.test.tsx +30 -14
- package/src/CheckboxList/CheckboxList.tsx +18 -3
- package/src/ContextMenu/ContextMenu.doc.mjs +6 -0
- package/src/ContextMenu/ContextMenu.test.tsx +115 -1
- package/src/ContextMenu/ContextMenu.tsx +75 -4
- package/src/DateInput/DateInput.test.tsx +59 -0
- package/src/DateInput/DateInput.tsx +24 -7
- package/src/DateRangeInput/DateRangeInput.test.tsx +69 -18
- package/src/DateRangeInput/DateRangeInput.tsx +7 -3
- package/src/DateTimeInput/DateTimeInput.doc.mjs +7 -0
- package/src/DateTimeInput/DateTimeInput.test.tsx +99 -6
- package/src/DateTimeInput/DateTimeInput.tsx +32 -3
- package/src/Dialog/Dialog.tsx +12 -0
- package/src/DropdownMenu/DropdownMenu.test.tsx +26 -4
- package/src/DropdownMenu/DropdownMenu.tsx +36 -2
- package/src/Field/Field.test.tsx +32 -0
- package/src/Field/Field.tsx +23 -5
- package/src/Field/FieldLabel.tsx +53 -17
- package/src/FileInput/FileInput.test.tsx +104 -49
- package/src/FileInput/FileInput.tsx +27 -3
- package/src/InputGroup/InputGroup.test.tsx +21 -63
- package/src/InputGroup/InputGroup.tsx +4 -1
- package/src/Kbd/Kbd.test.tsx +22 -4
- package/src/Kbd/Kbd.tsx +35 -3
- package/src/Layer/useLayer.tsx +52 -5
- package/src/Layout/padding.stylex.ts +52 -0
- package/src/Link/Link.doc.mjs +14 -0
- package/src/Link/Link.test.tsx +32 -0
- package/src/Link/Link.tsx +23 -1
- package/src/MultiSelector/MultiSelector.test.tsx +124 -2
- package/src/MultiSelector/MultiSelector.tsx +50 -9
- package/src/MultiSelector/hooks.ts +27 -0
- package/src/NavMenu/NavHeadingMenu.test.tsx +32 -1
- package/src/NavMenu/NavHeadingMenu.tsx +30 -2
- package/src/NumberInput/NumberInput.test.tsx +72 -38
- package/src/NumberInput/NumberInput.tsx +12 -1
- package/src/Pagination/Pagination.test.tsx +58 -5
- package/src/Pagination/Pagination.tsx +12 -0
- package/src/ProgressBar/ProgressBar.test.tsx +34 -26
- package/src/ProgressBar/ProgressBar.tsx +1 -1
- package/src/RadioList/RadioList.test.tsx +129 -14
- package/src/RadioList/RadioList.tsx +103 -8
- package/src/SegmentedControl/SegmentedControl.test.tsx +35 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +4 -1
- package/src/Selector/Selector.test.tsx +53 -0
- package/src/Selector/Selector.tsx +15 -8
- package/src/Selector/hooks.ts +23 -0
- package/src/Skeleton/Skeleton.test.tsx +25 -0
- package/src/Skeleton/Skeleton.tsx +11 -1
- package/src/Stack/Stack.doc.mjs +57 -0
- package/src/Stack/Stack.test.tsx +55 -5
- package/src/Stack/Stack.tsx +53 -1
- package/src/Stack/StackItem.test.tsx +23 -0
- package/src/Stack/StackItem.tsx +20 -0
- package/src/TabList/Tab.tsx +6 -0
- package/src/TabList/TabList.doc.mjs +6 -0
- package/src/TabList/TabList.test.tsx +167 -0
- package/src/TabList/TabList.tsx +72 -9
- package/src/TabList/TabListContext.ts +7 -3
- package/src/TabList/TabMenu.tsx +3 -3
- package/src/Toast/Toast.tsx +14 -0
- package/src/Toast/ToastViewport.test.tsx +204 -0
- package/src/Toast/ToastViewport.tsx +167 -21
- package/src/Toolbar/Toolbar.test.tsx +45 -0
- package/src/Toolbar/Toolbar.tsx +5 -2
- package/src/TreeList/TreeList.test.tsx +273 -0
- package/src/TreeList/TreeList.tsx +84 -1
- package/src/TreeList/TreeListItem.tsx +42 -2
- package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
- package/src/Typeahead/BaseTypeahead.tsx +48 -2
- package/src/Typeahead/Typeahead.test.tsx +125 -0
- package/src/hooks/index.ts +21 -2
- package/src/hooks/useAnnounce.test.tsx +101 -0
- package/src/hooks/useAnnounce.ts +168 -0
- package/src/hooks/useClickableContainer.ts +16 -4
- package/src/hooks/useFocusTrap.test.tsx +67 -3
- package/src/hooks/useFocusTrap.ts +75 -0
- package/src/hooks/useListFocus.doc.mjs +49 -10
- package/src/hooks/useListFocus.test.tsx +269 -0
- package/src/hooks/useListFocus.ts +339 -54
- package/src/hooks/useLongPress.test.tsx +134 -0
- package/src/hooks/useLongPress.ts +119 -0
- package/src/hooks/useTreeFocus.doc.mjs +126 -0
- package/src/hooks/useTreeFocus.test.tsx +214 -0
- package/src/hooks/useTreeFocus.ts +464 -0
- package/src/hooks/useTypeahead.test.tsx +109 -0
- package/src/hooks/useTypeahead.ts +183 -0
|
@@ -372,6 +372,69 @@ export const layoutPaddingOuterYVarStyles = {
|
|
|
372
372
|
}
|
|
373
373
|
};
|
|
374
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Inline-only padding styles.
|
|
377
|
+
* Use when a component needs to set inline (horizontal) padding independently
|
|
378
|
+
* of block padding — e.g. the `paddingX` prop on Stack.
|
|
379
|
+
*/
|
|
380
|
+
export const paddingInlineStyles = {
|
|
381
|
+
"0": {
|
|
382
|
+
kZCmMZ: "x18gyask",
|
|
383
|
+
kwRFfy: "x1s0aq8i",
|
|
384
|
+
$$css: true
|
|
385
|
+
},
|
|
386
|
+
"1": {
|
|
387
|
+
kZCmMZ: "x1vsv5vr",
|
|
388
|
+
kwRFfy: "x1nryj5t",
|
|
389
|
+
$$css: true
|
|
390
|
+
},
|
|
391
|
+
"2": {
|
|
392
|
+
kZCmMZ: "x12gdq22",
|
|
393
|
+
kwRFfy: "x1djylfy",
|
|
394
|
+
$$css: true
|
|
395
|
+
},
|
|
396
|
+
"3": {
|
|
397
|
+
kZCmMZ: "x126nfab",
|
|
398
|
+
kwRFfy: "x1t818jl",
|
|
399
|
+
$$css: true
|
|
400
|
+
},
|
|
401
|
+
"4": {
|
|
402
|
+
kZCmMZ: "x1rey3nv",
|
|
403
|
+
kwRFfy: "xnjyzlh",
|
|
404
|
+
$$css: true
|
|
405
|
+
},
|
|
406
|
+
"5": {
|
|
407
|
+
kZCmMZ: "x1blguxw",
|
|
408
|
+
kwRFfy: "xdbrk9v",
|
|
409
|
+
$$css: true
|
|
410
|
+
},
|
|
411
|
+
"6": {
|
|
412
|
+
kZCmMZ: "x31w388",
|
|
413
|
+
kwRFfy: "x1we12cn",
|
|
414
|
+
$$css: true
|
|
415
|
+
},
|
|
416
|
+
"8": {
|
|
417
|
+
kZCmMZ: "x1j3hnjz",
|
|
418
|
+
kwRFfy: "x1q91b2g",
|
|
419
|
+
$$css: true
|
|
420
|
+
},
|
|
421
|
+
"10": {
|
|
422
|
+
kZCmMZ: "xqp078j",
|
|
423
|
+
kwRFfy: "x160ivqr",
|
|
424
|
+
$$css: true
|
|
425
|
+
},
|
|
426
|
+
"0.5": {
|
|
427
|
+
kZCmMZ: "x138rykx",
|
|
428
|
+
kwRFfy: "x1le3yxw",
|
|
429
|
+
$$css: true
|
|
430
|
+
},
|
|
431
|
+
"1.5": {
|
|
432
|
+
kZCmMZ: "xfti1ec",
|
|
433
|
+
kwRFfy: "x17hk9do",
|
|
434
|
+
$$css: true
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
|
|
375
438
|
/**
|
|
376
439
|
* Block-only padding override styles.
|
|
377
440
|
* Use when a component needs to override block padding independently
|
package/dist/Link/Link.d.ts
CHANGED
|
@@ -55,6 +55,12 @@ export interface LinkProps extends BaseProps<HTMLAnchorElement | HTMLButtonEleme
|
|
|
55
55
|
* @default false
|
|
56
56
|
*/
|
|
57
57
|
isExternalLink?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Screen-reader text appended to an external link to announce that it opens
|
|
60
|
+
* in a new tab (the visual icon is decorative). Override for localization.
|
|
61
|
+
* @default '(opens in new tab)'
|
|
62
|
+
*/
|
|
63
|
+
newTabLabel?: string;
|
|
58
64
|
/**
|
|
59
65
|
* Where to open the linked document.
|
|
60
66
|
* Overridden to "_blank" when isExternalLink is true.
|
|
@@ -146,7 +152,7 @@ export interface LinkProps extends BaseProps<HTMLAnchorElement | HTMLButtonEleme
|
|
|
146
152
|
* </Text>
|
|
147
153
|
* ```
|
|
148
154
|
*/
|
|
149
|
-
export declare function Link({ as, label, href, hasUnderline, isDisabled, isExternalLink, target: targetFromProps, onClick, tooltip, isStandalone, type, size, weight, color, display, maxLines, children, rel: relFromProps, xstyle, className, style, ref, ...props }: LinkProps): import("react").JSX.Element;
|
|
155
|
+
export declare function Link({ as, label, href, hasUnderline, isDisabled, isExternalLink, newTabLabel, target: targetFromProps, onClick, tooltip, isStandalone, type, size, weight, color, display, maxLines, children, rel: relFromProps, xstyle, className, style, ref, ...props }: LinkProps): import("react").JSX.Element;
|
|
150
156
|
export declare namespace Link {
|
|
151
157
|
var displayName: string;
|
|
152
158
|
}
|
package/dist/Link/Link.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../src/Link/Link.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AACrC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAa5C,OAAO,KAAK,EACV,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,UAAU,EACV,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../src/Link/Link.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AACrC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAa5C,OAAO,KAAK,EACV,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,UAAU,EACV,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,SAAS,CAAC;AAkH/C,MAAM,WAAW,SAAU,SAAQ,SAAS,CAC1C,iBAAiB,GAAG,iBAAiB,CACtC;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;IACvD;;;;;OAKG;IACH,EAAE,CAAC,EAAE,iBAAiB,CAAC;IACvB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B;;OAEG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,2BAA2B,CAAC;IACnD;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;IACzE;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;OAEG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,IAAI,CAAC,EACnB,EAAE,EACF,KAAK,EACL,IAAI,EACJ,YAAoB,EACpB,UAAkB,EAClB,cAAsB,EACtB,WAAkC,EAClC,MAAM,EAAE,eAAe,EACvB,OAAO,EACP,OAAO,EACP,YAAoB,EACpB,IAAa,EACb,IAAI,EACJ,MAAM,EACN,KAAgB,EAChB,OAAkB,EAClB,QAAY,EACZ,QAAQ,EACR,GAAG,EAAE,YAAY,EACjB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,SAAS,+BAwGX;yBAjIe,IAAI"}
|
package/dist/Link/Link.js
CHANGED
|
@@ -131,6 +131,7 @@ export function Link({
|
|
|
131
131
|
hasUnderline = false,
|
|
132
132
|
isDisabled = false,
|
|
133
133
|
isExternalLink = false,
|
|
134
|
+
newTabLabel = '(opens in new tab)',
|
|
134
135
|
target: targetFromProps,
|
|
135
136
|
onClick,
|
|
136
137
|
tooltip,
|
|
@@ -173,10 +174,17 @@ export function Link({
|
|
|
173
174
|
display: display,
|
|
174
175
|
maxLines: maxLines,
|
|
175
176
|
children: children
|
|
176
|
-
}), isExternalLink && !renderAsButton && /*#__PURE__*/
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
}), isExternalLink && !renderAsButton && /*#__PURE__*/_jsxs(_Fragment, {
|
|
178
|
+
children: [/*#__PURE__*/_jsx(Icon, {
|
|
179
|
+
icon: "externalLink",
|
|
180
|
+
size: "xsm",
|
|
181
|
+
color: "inherit"
|
|
182
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
183
|
+
...{
|
|
184
|
+
className: "x10l6tqk x1i1rx1s xjm9jq1 xkdpibf x1717udv xb3r6kr xzpqnlu xuxw1ft xng3xce"
|
|
185
|
+
},
|
|
186
|
+
children: newTabLabel
|
|
187
|
+
})]
|
|
180
188
|
})]
|
|
181
189
|
});
|
|
182
190
|
let linkElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiSelector.d.ts","sourceRoot":"","sources":["../../src/MultiSelector/MultiSelector.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,EASZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,OAAO,EAAuB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAwB5D,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"MultiSelector.d.ts","sourceRoot":"","sources":["../../src/MultiSelector/MultiSelector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,7 @@ import { colorVars, sizeVars, spacingVars, radiusVars, durationVars, easeVars, t
|
|
|
27
27
|
import { isOptionData, isDivider, isSection, normalizeOption, getSelectableOptions } from "../Selector/utils.js";
|
|
28
28
|
import { useMultiCombobox } from "./hooks.js";
|
|
29
29
|
import { mergeProps } from "../utils/index.js";
|
|
30
|
+
import { useAnnounce } from "../hooks/useAnnounce.js";
|
|
30
31
|
import { useSize } from "../SizeContext/SizeContext.js";
|
|
31
32
|
import { themeProps } from "../utils/themeProps.js";
|
|
32
33
|
|
|
@@ -223,6 +224,22 @@ export function MultiSelector({
|
|
|
223
224
|
// Flatten options for keyboard navigation
|
|
224
225
|
const selectableItems = useMemo(() => getSelectableOptions(options), [options]);
|
|
225
226
|
|
|
227
|
+
// Announce selection-count changes politely (comboboxes-7 announce path).
|
|
228
|
+
// Toggling options / select-all previously produced no audible feedback.
|
|
229
|
+
const announce = useAnnounce();
|
|
230
|
+
const announceSelection = useCallback(nextValue => {
|
|
231
|
+
const total = selectableItems.length;
|
|
232
|
+
const selectableSet = new Set(selectableItems.map(item => item.value));
|
|
233
|
+
const selectedCount = nextValue.filter(v => selectableSet.has(v)).length;
|
|
234
|
+
if (selectedCount === 0) {
|
|
235
|
+
announce('Selection cleared');
|
|
236
|
+
} else if (total > 0 && selectedCount === total) {
|
|
237
|
+
announce('All selected');
|
|
238
|
+
} else {
|
|
239
|
+
announce(`${selectedCount} of ${total} selected`);
|
|
240
|
+
}
|
|
241
|
+
}, [announce, selectableItems]);
|
|
242
|
+
|
|
226
243
|
// Filter items by search query
|
|
227
244
|
const filteredItems = useMemo(() => {
|
|
228
245
|
if (!searchQuery) {
|
|
@@ -309,27 +326,36 @@ export function MultiSelector({
|
|
|
309
326
|
}, []);
|
|
310
327
|
|
|
311
328
|
// Handle toggle
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
329
|
+
// Clear all selected values. Shared by the clear button and the keyboard
|
|
330
|
+
// Delete/Backspace path so clearing is reachable without a mouse.
|
|
331
|
+
const clearValues = useCallback(() => {
|
|
315
332
|
onChange([]);
|
|
333
|
+
announceSelection([]);
|
|
316
334
|
if (changeAction) {
|
|
317
335
|
startTransition(async () => {
|
|
318
336
|
setOptimisticValue([]);
|
|
319
337
|
await changeAction([]);
|
|
320
338
|
});
|
|
321
339
|
}
|
|
322
|
-
}, [onChange, changeAction, startTransition, setOptimisticValue]);
|
|
340
|
+
}, [onChange, changeAction, startTransition, setOptimisticValue, announceSelection]);
|
|
341
|
+
|
|
342
|
+
// Whether there is at least one selected value (clearing is meaningful).
|
|
343
|
+
const hasValue = optimisticValue.length > 0;
|
|
344
|
+
const handleClear = useCallback(e => {
|
|
345
|
+
e.stopPropagation(); // Don't open dropdown
|
|
346
|
+
clearValues();
|
|
347
|
+
}, [clearValues]);
|
|
323
348
|
const handleToggle = useCallback(itemValue => {
|
|
324
349
|
const newValue = optimisticValue.includes(itemValue) ? optimisticValue.filter(v => v !== itemValue) : [...optimisticValue, itemValue];
|
|
325
350
|
onChange(newValue);
|
|
351
|
+
announceSelection(newValue);
|
|
326
352
|
if (changeAction) {
|
|
327
353
|
startTransition(async () => {
|
|
328
354
|
setOptimisticValue(newValue);
|
|
329
355
|
await changeAction(newValue);
|
|
330
356
|
});
|
|
331
357
|
}
|
|
332
|
-
}, [optimisticValue, onChange, changeAction, startTransition, setOptimisticValue]);
|
|
358
|
+
}, [optimisticValue, onChange, changeAction, startTransition, setOptimisticValue, announceSelection]);
|
|
333
359
|
|
|
334
360
|
// Select-all logic
|
|
335
361
|
const enabledItems = useMemo(() => filteredItems.filter(item => !item.disabled), [filteredItems]);
|
|
@@ -353,13 +379,14 @@ export function MultiSelector({
|
|
|
353
379
|
}
|
|
354
380
|
}
|
|
355
381
|
onChange(newValue);
|
|
382
|
+
announceSelection(newValue);
|
|
356
383
|
if (changeAction) {
|
|
357
384
|
startTransition(async () => {
|
|
358
385
|
setOptimisticValue(newValue);
|
|
359
386
|
await changeAction(newValue);
|
|
360
387
|
});
|
|
361
388
|
}
|
|
362
|
-
}, [allEnabledSelected, enabledItems, optimisticValue, onChange, changeAction, startTransition, setOptimisticValue]);
|
|
389
|
+
}, [allEnabledSelected, enabledItems, optimisticValue, onChange, changeAction, startTransition, setOptimisticValue, announceSelection]);
|
|
363
390
|
|
|
364
391
|
// Route toggle: select-all sentinel → handleSelectAll, everything else → handleToggle
|
|
365
392
|
const handleNavigableToggle = useCallback(itemValue => {
|
|
@@ -396,6 +423,8 @@ export function MultiSelector({
|
|
|
396
423
|
}, [popover, hasSearch, optimisticValue]),
|
|
397
424
|
onClose: popover.hide,
|
|
398
425
|
onToggle: handleNavigableToggle,
|
|
426
|
+
onClear: hasClear ? clearValues : undefined,
|
|
427
|
+
hasValue,
|
|
399
428
|
listboxId
|
|
400
429
|
});
|
|
401
430
|
|
|
@@ -7,6 +7,17 @@ interface UseMultiComboboxOptions {
|
|
|
7
7
|
onOpen: () => void;
|
|
8
8
|
onClose: () => void;
|
|
9
9
|
onToggle: (itemValue: string) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Clear all selected values. When provided, pressing Delete or Backspace on
|
|
12
|
+
* the closed trigger clears the selection — a keyboard equivalent of the
|
|
13
|
+
* clear button (comboboxes-2). No-op when the popup is open or search is on.
|
|
14
|
+
*/
|
|
15
|
+
onClear?: () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Whether at least one value is selected (i.e. there is something to clear).
|
|
18
|
+
* The Delete/Backspace clear path is skipped when false.
|
|
19
|
+
*/
|
|
20
|
+
hasValue?: boolean;
|
|
10
21
|
listboxId: string;
|
|
11
22
|
}
|
|
12
23
|
interface UseMultiComboboxResult {
|
|
@@ -23,6 +34,6 @@ interface UseMultiComboboxResult {
|
|
|
23
34
|
*
|
|
24
35
|
* The caller must ensure selectableItems is in the same order as the rendered DOM.
|
|
25
36
|
*/
|
|
26
|
-
export declare function useMultiCombobox({ selectableItems, isDisabled, isOpen, hasSearch, onOpen, onClose, onToggle, listboxId, }: UseMultiComboboxOptions): UseMultiComboboxResult;
|
|
37
|
+
export declare function useMultiCombobox({ selectableItems, isDisabled, isOpen, hasSearch, onOpen, onClose, onToggle, onClear, hasValue, listboxId, }: UseMultiComboboxOptions): UseMultiComboboxResult;
|
|
27
38
|
export {};
|
|
28
39
|
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/MultiSelector/hooks.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,SAAS,CAAC;AAErD,UAAU,uBAAuB;IAC/B,eAAe,EAAE,uBAAuB,EAAE,CAAC;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,sBAAsB;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAC5C,gBAAgB,EAAE,CAAC,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,eAAe,EACf,UAAkB,EAClB,MAAM,EACN,SAAiB,EACjB,MAAM,EACN,OAAO,EACP,QAAQ,EACR,SAAS,GACV,EAAE,uBAAuB,GAAG,sBAAsB,
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/MultiSelector/hooks.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,SAAS,CAAC;AAErD,UAAU,uBAAuB;IAC/B,eAAe,EAAE,uBAAuB,EAAE,CAAC;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,sBAAsB;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAC5C,gBAAgB,EAAE,CAAC,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,eAAe,EACf,UAAkB,EAClB,MAAM,EACN,SAAiB,EACjB,MAAM,EACN,OAAO,EACP,QAAQ,EACR,OAAO,EACP,QAAgB,EAChB,SAAS,GACV,EAAE,uBAAuB,GAAG,sBAAsB,CAiMlD"}
|
|
@@ -26,6 +26,8 @@ export function useMultiCombobox({
|
|
|
26
26
|
onOpen,
|
|
27
27
|
onClose,
|
|
28
28
|
onToggle,
|
|
29
|
+
onClear,
|
|
30
|
+
hasValue = false,
|
|
29
31
|
listboxId
|
|
30
32
|
}) {
|
|
31
33
|
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
|
@@ -127,6 +129,17 @@ export function useMultiCombobox({
|
|
|
127
129
|
setHighlightedIndex(enabledIndices[enabledIndices.length - 1]);
|
|
128
130
|
}
|
|
129
131
|
break;
|
|
132
|
+
case 'Delete':
|
|
133
|
+
case 'Backspace':
|
|
134
|
+
// Keyboard equivalent of the clear button (comboboxes-2): clear all
|
|
135
|
+
// selected values from the closed trigger so clearing is not
|
|
136
|
+
// mouse-only. Skipped in search mode (keys edit the query) and while
|
|
137
|
+
// the popup is open (arrow navigation owns interaction).
|
|
138
|
+
if (!hasSearch && !isOpen && onClear != null && hasValue) {
|
|
139
|
+
e.preventDefault();
|
|
140
|
+
onClear();
|
|
141
|
+
}
|
|
142
|
+
break;
|
|
130
143
|
default:
|
|
131
144
|
// Typeahead only when search is not present
|
|
132
145
|
if (!hasSearch && e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
|
|
@@ -148,7 +161,7 @@ export function useMultiCombobox({
|
|
|
148
161
|
}
|
|
149
162
|
break;
|
|
150
163
|
}
|
|
151
|
-
}, [isDisabled, isOpen, onOpen, closeAndReset, selectableItems, highlightedIndex, onToggle, getEnabledIndices, typeahead, hasSearch]);
|
|
164
|
+
}, [isDisabled, isOpen, onOpen, closeAndReset, selectableItems, highlightedIndex, onToggle, getEnabledIndices, typeahead, hasSearch, onClear, hasValue]);
|
|
152
165
|
return {
|
|
153
166
|
highlightedIndex,
|
|
154
167
|
setHighlightedIndex,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NavHeadingMenu.d.ts","sourceRoot":"","sources":["../../src/NavMenu/NavHeadingMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAuB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAIlE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"NavHeadingMenu.d.ts","sourceRoot":"","sources":["../../src/NavMenu/NavHeadingMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAuB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAIlE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAC;AAsB1B,MAAM,WAAW,mBAAoB,SAAQ,SAAS,CAAC,cAAc,CAAC;IACpE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,iEAAiE;IACjE,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;OAGG;IACH,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,GAAG,EACH,QAAQ,EACR,IAAW,EACX,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EAAE,SAAS,EAChB,aAAa,EAAE,MAAM,GACtB,EAAE,mBAAmB,qBAiFrB;yBA1Fe,cAAc"}
|
|
@@ -17,6 +17,7 @@ import "../theme/tokens.stylex.js";
|
|
|
17
17
|
import { spacingVars } from "../theme/tokens.stylex.js";
|
|
18
18
|
import { mergeProps, mergeRefs } from "../utils/index.js";
|
|
19
19
|
import { useListFocus } from "../hooks/useListFocus.js";
|
|
20
|
+
import { useTypeahead } from "../hooks/useTypeahead.js";
|
|
20
21
|
import { themeProps } from "../utils/themeProps.js";
|
|
21
22
|
import { NavHeadingMenuContext, useNavHeadingCloseContext } from "./NavMenuContext.js";
|
|
22
23
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -79,11 +80,21 @@ export function NavHeadingMenu({
|
|
|
79
80
|
const closeMenu = closeCtx?.closeMenu;
|
|
80
81
|
const {
|
|
81
82
|
listRef,
|
|
82
|
-
handleKeyDown
|
|
83
|
+
handleKeyDown,
|
|
84
|
+
focusItem
|
|
83
85
|
} = useListFocus({
|
|
86
|
+
itemSelector: '[role="menuitem"]:not([aria-disabled="true"])',
|
|
84
87
|
onEscape: closeMenu
|
|
85
88
|
});
|
|
86
89
|
|
|
90
|
+
// First-character typeahead over the (enabled) menu items (menus-11).
|
|
91
|
+
const getMenuItems = useCallback(() => listRef.current ? Array.from(listRef.current.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')) : [], [listRef]);
|
|
92
|
+
const typeahead = useTypeahead({
|
|
93
|
+
getItemLabels: () => getMenuItems().map(el => el.textContent),
|
|
94
|
+
onMatch: focusItem,
|
|
95
|
+
getCurrentIndex: () => getMenuItems().findIndex(el => el === document.activeElement || el.contains(document.activeElement))
|
|
96
|
+
});
|
|
97
|
+
|
|
87
98
|
// Extend useListFocus with Enter/Space activation. Items rendered without an
|
|
88
99
|
// `href` are `<div role="menuitem">` elements, which have no native keyboard
|
|
89
100
|
// activation — without this, Enter/Space on a focused onClick-only item does
|
|
@@ -97,8 +108,12 @@ export function NavHeadingMenu({
|
|
|
97
108
|
return;
|
|
98
109
|
}
|
|
99
110
|
}
|
|
111
|
+
if (typeahead.onKeyDown(e)) {
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
100
115
|
handleKeyDown(e);
|
|
101
|
-
}, [handleKeyDown]);
|
|
116
|
+
}, [handleKeyDown, typeahead]);
|
|
102
117
|
const ctx = useMemo(() => ({
|
|
103
118
|
closeMenu: closeMenu ?? (() => {}),
|
|
104
119
|
size
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NumberInput.d.ts","sourceRoot":"","sources":["../../src/NumberInput/NumberInput.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAML,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAU3C,OAAO,EAEL,KAAK,WAAW,EAMjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAuB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"NumberInput.d.ts","sourceRoot":"","sources":["../../src/NumberInput/NumberInput.tsx"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,7 @@ import "../theme/tokens.stylex.js";
|
|
|
21
21
|
import { colorVars, sizeVars, radiusVars, typographyVars, typeScaleVars, borderVars } from "../theme/tokens.stylex.js";
|
|
22
22
|
import { Field, inputWrapperStyles, inputStatusBorderStyles, inputStatusHoverShadowStyles, inputStatusFocusWithinStyles } from "../Field/index.js";
|
|
23
23
|
import { Icon, renderIconSlot } from "../Icon/index.js";
|
|
24
|
+
import { VisuallyHidden } from "../VisuallyHidden/index.js";
|
|
24
25
|
import { useSize } from "../SizeContext/SizeContext.js";
|
|
25
26
|
import { useInputContainer } from "../hooks/useInputContainer.js";
|
|
26
27
|
import { useInputGroup } from "../InputGroup/InputGroupContext.js";
|
|
@@ -286,7 +287,7 @@ export function NumberInput({
|
|
|
286
287
|
step: step ?? undefined,
|
|
287
288
|
"aria-describedby": ariaDescribedBy,
|
|
288
289
|
"aria-required": isRequired === true ? 'true' : undefined,
|
|
289
|
-
"aria-invalid": status?.type === 'error' ? 'true' : undefined,
|
|
290
|
+
"aria-invalid": status?.type === 'error' || !isInputValid ? 'true' : undefined,
|
|
290
291
|
"aria-label": inputGroup ? label : undefined,
|
|
291
292
|
...{
|
|
292
293
|
0: {
|
|
@@ -307,6 +308,11 @@ export function NumberInput({
|
|
|
307
308
|
className: "x9ynric xjm74w1 xw6l6zx xv1l7n4 x2lah0s"
|
|
308
309
|
},
|
|
309
310
|
children: units
|
|
311
|
+
}), /*#__PURE__*/_jsx(VisuallyHidden, {
|
|
312
|
+
as: "div",
|
|
313
|
+
role: "alert",
|
|
314
|
+
"aria-live": "assertive",
|
|
315
|
+
children: !isInputValid ? 'Invalid number' : ''
|
|
310
316
|
}), hasClear && value != null && !isDisabled && /*#__PURE__*/_jsx("button", {
|
|
311
317
|
type: "button",
|
|
312
318
|
onClick: handleClear,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../src/Pagination/Pagination.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../src/Pagination/Pagination.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAO5C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,IAAI,CAAC;IACZ,KAAK,EAAE,IAAI,CAAC;IACZ,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,oBAAoB,CAAC;AAE3D,uCAAuC;AACvC,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,WAAW,CAAC,EACtB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE7B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGtD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAG9C;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IAGtB,wDAAwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAC;IAGrB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAiGD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CA6CpB;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,UAAU,EAAE,cAAc,EAC1B,OAAO,EACP,QAAQ,EAAE,YAAiB,EAC3B,eAAe,EACf,gBAAgB,EAChB,OAAiB,EACjB,YAAgB,EAChB,IAAW,EACX,UAAkB,EAClB,KAAoB,EACpB,aAAa,EAAE,MAAM,EACrB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,GACJ,EAAE,eAAe,sCAiQjB;yBArRe,UAAU"}
|
|
@@ -26,6 +26,7 @@ import { Button } from "../Button/index.js";
|
|
|
26
26
|
import { Icon } from "../Icon/index.js";
|
|
27
27
|
import { Selector } from "../Selector/index.js";
|
|
28
28
|
import { Text } from "../Text/index.js";
|
|
29
|
+
import { useAnnounce } from "../hooks/useAnnounce.js";
|
|
29
30
|
import { mergeProps } from "../utils/index.js";
|
|
30
31
|
import { themeProps } from "../utils/themeProps.js";
|
|
31
32
|
|
|
@@ -181,6 +182,12 @@ export function Pagination({
|
|
|
181
182
|
// positive integer; non-finite values fall back to the default.
|
|
182
183
|
const pageSize = Number.isFinite(pageSizeProp) ? Math.max(1, Math.floor(pageSizeProp)) : 10;
|
|
183
184
|
|
|
185
|
+
// Announce page changes politely (navigation-10). The controls carry no
|
|
186
|
+
// live region, so page transitions were previously silent to screen readers.
|
|
187
|
+
// Only user-driven changes go through handlePageChange, so initial mount is
|
|
188
|
+
// never announced.
|
|
189
|
+
const announce = useAnnounce();
|
|
190
|
+
|
|
184
191
|
// Track the page optimistically so rapid prev/next clicks advance from the
|
|
185
192
|
// in-flight target instead of stalling on the last committed page.
|
|
186
193
|
const [optimisticPage, setOptimisticPage] = useOptimistic(page);
|
|
@@ -208,6 +215,7 @@ export function Pagination({
|
|
|
208
215
|
// Keep onChange urgent so controlled page state updates in the same commit
|
|
209
216
|
// as the click; only the optimistic indicator and changeAction defer.
|
|
210
217
|
onChange(newPage);
|
|
218
|
+
announce(computedTotalPages != null ? `Page ${newPage} of ${computedTotalPages}` : `Page ${newPage}`);
|
|
211
219
|
startTransition(async () => {
|
|
212
220
|
setOptimisticPage(newPage);
|
|
213
221
|
await changeAction?.(newPage);
|
|
@@ -201,7 +201,7 @@ export function ProgressBar({
|
|
|
201
201
|
},
|
|
202
202
|
children: label
|
|
203
203
|
}), /*#__PURE__*/_jsx("div", {
|
|
204
|
-
role:
|
|
204
|
+
role: "progressbar",
|
|
205
205
|
"aria-valuenow": isIndeterminate ? undefined : clampedValue,
|
|
206
206
|
"aria-valuemin": isIndeterminate ? undefined : 0,
|
|
207
207
|
"aria-valuemax": isIndeterminate ? undefined : max,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file RadioList.tsx
|
|
3
|
-
* @input Uses React useId, createContext, ReactNode, Field, InputStatus
|
|
3
|
+
* @input Uses React useId, useCallback, useRef, createContext, ReactNode, Field, InputStatus
|
|
4
4
|
* @output Exports RadioList component, RadioListProps, RadioListContext
|
|
5
5
|
* @position Core implementation; consumed by index.ts, tested by RadioList.test.tsx
|
|
6
6
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioList.d.ts","sourceRoot":"","sources":["../../src/RadioList/RadioList.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"RadioList.d.ts","sourceRoot":"","sources":["../../src/RadioList/RadioList.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,EAMZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAG9C;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,CAAC;AAExC,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,6CAE5B,CAAC;AAiBF,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,SAAS,CAAC,WAAW,CAAC,EACtB,UAAU,CACX;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACxC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,EACxB,GAAG,EACH,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,KAAK,EACL,QAAQ,EACR,WAAwB,EACxB,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,IAAW,EACX,MAAM,EACN,YAAY,EACZ,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,aAAa,EAAE,UAAU,EACzB,QAAQ,GACT,EAAE,cAAc,qBAuJhB;yBA3Ke,SAAS"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file RadioList.tsx
|
|
7
|
-
* @input Uses React useId, createContext, ReactNode, Field, InputStatus
|
|
7
|
+
* @input Uses React useId, useCallback, useRef, createContext, ReactNode, Field, InputStatus
|
|
8
8
|
* @output Exports RadioList component, RadioListProps, RadioListContext
|
|
9
9
|
* @position Core implementation; consumed by index.ts, tested by RadioList.test.tsx
|
|
10
10
|
*
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* - /apps/storybook/stories/RadioList.stories.tsx
|
|
16
16
|
* - /packages/cli/templates/blocks/components/RadioList/ (showcase blocks)
|
|
17
17
|
*/
|
|
18
|
-
import React, { createContext, useId, useMemo } from 'react';
|
|
18
|
+
import React, { createContext, useCallback, useId, useMemo, useRef } from 'react';
|
|
19
19
|
import * as stylex from '@stylexjs/stylex';
|
|
20
20
|
import "../theme/tokens.stylex.js";
|
|
21
21
|
import { spacingVars } from "../theme/tokens.stylex.js";
|
|
@@ -67,8 +67,10 @@ export function RadioList({
|
|
|
67
67
|
}) {
|
|
68
68
|
const name = useId();
|
|
69
69
|
const inputID = useId();
|
|
70
|
+
const labelElementID = useId();
|
|
70
71
|
const descriptionID = useId();
|
|
71
72
|
const statusMessageID = useId();
|
|
73
|
+
const groupRef = useRef(null);
|
|
72
74
|
const contextValue = useMemo(() => ({
|
|
73
75
|
name,
|
|
74
76
|
value,
|
|
@@ -78,6 +80,73 @@ export function RadioList({
|
|
|
78
80
|
size,
|
|
79
81
|
status
|
|
80
82
|
}), [name, value, onChange, isDisabled, isRequired, size, status]);
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Make the tab stop deterministic when a radio group has no selected value.
|
|
86
|
+
*
|
|
87
|
+
* Native `<input type="radio">` groups (same `name`) implement roving
|
|
88
|
+
* tabindex for free: when a value is selected, that radio is the single tab
|
|
89
|
+
* stop and receives focus, so no correction is needed there. But the ARIA
|
|
90
|
+
* radio-group pattern (APG) also requires a deterministic tab stop when the
|
|
91
|
+
* group has *no* selection — and browsers disagree here. Chrome, when
|
|
92
|
+
* Shift+Tab moves focus backward into an unselected group, lands on the
|
|
93
|
+
* *last* radio; forward Tab lands on the *first*. To keep the entry point
|
|
94
|
+
* predictable we redirect focus:
|
|
95
|
+
* - forward entry → first enabled radio (APG default)
|
|
96
|
+
* - backward entry → last enabled radio (matches Chrome's backward tab)
|
|
97
|
+
*
|
|
98
|
+
* The redirect only runs when focus arrives from *outside* the group's own
|
|
99
|
+
* radios (guarded via `relatedTarget` containment). Moving between radios
|
|
100
|
+
* inside the group — arrow keys, clicks, programmatic focus of a sibling —
|
|
101
|
+
* is never hijacked.
|
|
102
|
+
*/
|
|
103
|
+
const handleFocus = useCallback(e => {
|
|
104
|
+
// Only correct the no-selection case; a selected value already provides
|
|
105
|
+
// a deterministic native tab stop.
|
|
106
|
+
if (value !== '') {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const group = groupRef.current;
|
|
110
|
+
if (!group) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Ignore focus moving *within* the group. `relatedTarget` is the element
|
|
115
|
+
// losing focus; if it was inside the group, this is intra-group movement
|
|
116
|
+
// (arrow keys, clicking a sibling) and must not be hijacked. Some browsers
|
|
117
|
+
// report a null `relatedTarget`; fall back to checking whether the group
|
|
118
|
+
// already contained the active element before this focus landed.
|
|
119
|
+
const relatedTarget = e.relatedTarget;
|
|
120
|
+
if (relatedTarget) {
|
|
121
|
+
if (group.contains(relatedTarget)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
} else if (document.activeElement && document.activeElement !== e.target && group.contains(document.activeElement)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const radios = Array.from(group.querySelectorAll('input[type="radio"]:not([disabled])'));
|
|
128
|
+
if (radios.length === 0) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const target = e.target;
|
|
132
|
+
const targetIndex = radios.findIndex(radio => radio === target);
|
|
133
|
+
// Only correct when the focus target is one of our enabled radios (not a
|
|
134
|
+
// nested control such as end-content).
|
|
135
|
+
if (targetIndex === -1) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Infer tab direction from which end the browser chose. On a backward
|
|
140
|
+
// (Shift+Tab) entry into an unselected group, browsers focus the *last*
|
|
141
|
+
// radio; keep it as the deterministic backward tab stop. Any other entry
|
|
142
|
+
// (forward Tab, or a browser that lands mid-group) is normalized to the
|
|
143
|
+
// *first* enabled radio, the APG default.
|
|
144
|
+
const isBackwardEntry = targetIndex === radios.length - 1;
|
|
145
|
+
const intended = isBackwardEntry ? radios[radios.length - 1] : radios[0];
|
|
146
|
+
if (target !== intended) {
|
|
147
|
+
intended.focus();
|
|
148
|
+
}
|
|
149
|
+
}, [value]);
|
|
81
150
|
return /*#__PURE__*/_jsx(Field, {
|
|
82
151
|
ref: ref,
|
|
83
152
|
"data-testid": dataTestId,
|
|
@@ -85,6 +154,8 @@ export function RadioList({
|
|
|
85
154
|
isLabelHidden: isLabelHidden,
|
|
86
155
|
description: description,
|
|
87
156
|
inputID: inputID,
|
|
157
|
+
labelElementID: labelElementID,
|
|
158
|
+
isGroupLabel: true,
|
|
88
159
|
descriptionID: description ? descriptionID : undefined,
|
|
89
160
|
isOptional: isOptional,
|
|
90
161
|
isRequired: isRequired,
|
|
@@ -101,8 +172,10 @@ export function RadioList({
|
|
|
101
172
|
className: className,
|
|
102
173
|
style: style,
|
|
103
174
|
children: /*#__PURE__*/_jsx("div", {
|
|
175
|
+
ref: groupRef,
|
|
104
176
|
role: "radiogroup",
|
|
105
|
-
"aria-
|
|
177
|
+
"aria-labelledby": labelElementID,
|
|
178
|
+
onFocus: handleFocus,
|
|
106
179
|
"aria-describedby": [description ? descriptionID : null, status?.message ? statusMessageID : null].filter(Boolean).join(' ') || undefined,
|
|
107
180
|
"aria-invalid": status?.type === 'error' ? true : undefined,
|
|
108
181
|
"aria-required": isRequired || undefined,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedControlItem.d.ts","sourceRoot":"","sources":["../../src/SegmentedControl/SegmentedControlItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,EAAc,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAezD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,MAAM,WAAW,yBAA0B,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IAC7E,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA6FD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,GAAG,EACH,KAAK,EACL,KAAK,EACL,aAAqB,EACrB,IAAI,EACJ,UAAkB,GACnB,EAAE,yBAAyB,
|
|
1
|
+
{"version":3,"file":"SegmentedControlItem.d.ts","sourceRoot":"","sources":["../../src/SegmentedControl/SegmentedControlItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,EAAc,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAezD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,MAAM,WAAW,yBAA0B,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IAC7E,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA6FD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,GAAG,EACH,KAAK,EACL,KAAK,EACL,aAAqB,EACrB,IAAI,EACJ,UAAkB,GACnB,EAAE,yBAAyB,qBAmD3B;yBA1De,oBAAoB"}
|
|
@@ -157,8 +157,12 @@ export function SegmentedControlItem({
|
|
|
157
157
|
"aria-checked": isSelected,
|
|
158
158
|
"aria-disabled": isItemDisabled || undefined,
|
|
159
159
|
"aria-label": isLabelHidden ? label : undefined,
|
|
160
|
-
"data-value": value
|
|
161
|
-
|
|
160
|
+
"data-value": value
|
|
161
|
+
// Disabled items (including when the whole group is disabled) are not tab
|
|
162
|
+
// stops — otherwise the selected segment stays keyboard-focusable but is
|
|
163
|
+
// silently dead (arrows and activation are no-ops) (navigation-13).
|
|
164
|
+
,
|
|
165
|
+
tabIndex: isSelected && !isItemDisabled ? 0 : -1,
|
|
162
166
|
onClick: handleClick,
|
|
163
167
|
...mergeProps(themeProps('segmented-control-item', {
|
|
164
168
|
size,
|