@astryxdesign/core 0.1.2-canary.bfcbf64 → 0.1.2-canary.c395fca
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/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +4 -1
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +2 -4
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +33 -14
- package/dist/Calendar/hooks/index.d.ts +0 -2
- package/dist/Calendar/hooks/index.d.ts.map +1 -1
- package/dist/Calendar/hooks/index.js +1 -2
- package/dist/Calendar/index.d.ts +2 -2
- package/dist/Calendar/index.d.ts.map +1 -1
- package/dist/Calendar/index.js +1 -1
- package/dist/CheckboxList/CheckboxList.js +3 -3
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +3 -3
- package/dist/ContextMenu/ContextMenu.d.ts +1 -7
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +7 -13
- package/dist/DropdownMenu/DropdownMenu.d.ts +1 -8
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +4 -9
- package/dist/Field/Field.d.ts +4 -4
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +2 -2
- package/dist/Field/FieldLabel.d.ts +4 -4
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +2 -2
- package/dist/InputGroup/InputGroup.js +3 -3
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +2 -4
- package/dist/MoreMenu/MoreMenu.d.ts +1 -7
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/MoreMenu/MoreMenu.js +0 -2
- package/dist/MultiSelector/MultiSelector.d.ts +25 -2
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +31 -6
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +2 -4
- package/dist/RadioList/RadioList.js +3 -3
- package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +51 -61
- package/dist/Selector/Selector.d.ts +22 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +31 -6
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +2 -4
- package/dist/TabList/TabList.d.ts +3 -2
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +55 -33
- package/dist/Table/tableContextMenu.d.ts.map +1 -1
- package/dist/Table/tableContextMenu.js +0 -3
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +2 -4
- package/dist/Toolbar/Toolbar.d.ts +3 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +46 -6
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +16 -22
- package/dist/TreeList/TreeListItem.d.ts +3 -2
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- 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 +4 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useGridFocus.d.ts +56 -0
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +138 -24
- package/dist/hooks/useKeyboardHint.d.ts +82 -0
- package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
- package/dist/hooks/useKeyboardHint.js +220 -0
- package/dist/hooks/useTreeFocus.d.ts +27 -3
- package/dist/hooks/useTreeFocus.d.ts.map +1 -1
- package/dist/hooks/useTreeFocus.js +69 -6
- package/package.json +1 -1
- package/src/Breadcrumbs/BreadcrumbItem.tsx +5 -2
- package/src/Button/Button.tsx +3 -16
- package/src/Calendar/Calendar.tsx +52 -22
- package/src/Calendar/hooks/index.ts +0 -6
- package/src/Calendar/index.ts +0 -3
- package/src/CheckboxList/CheckboxList.tsx +3 -3
- package/src/Citation/Citation.doc.mjs +10 -0
- package/src/Citation/Citation.test.tsx +117 -0
- package/src/Citation/Citation.tsx +9 -1
- package/src/ContextMenu/ContextMenu.doc.mjs +0 -6
- package/src/ContextMenu/ContextMenu.test.tsx +4 -6
- package/src/ContextMenu/ContextMenu.tsx +7 -19
- package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
- package/src/DropdownMenu/DropdownMenu.test.tsx +0 -23
- package/src/DropdownMenu/DropdownMenu.tsx +4 -16
- package/src/Field/Field.test.tsx +2 -2
- package/src/Field/Field.tsx +5 -5
- package/src/Field/FieldLabel.tsx +5 -5
- package/src/InputGroup/InputGroup.tsx +3 -3
- package/src/Link/Link.tsx +2 -13
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
- package/src/MoreMenu/MoreMenu.tsx +0 -9
- package/src/MultiSelector/MultiSelector.doc.mjs +25 -0
- package/src/MultiSelector/MultiSelector.test.tsx +150 -1
- package/src/MultiSelector/MultiSelector.tsx +55 -3
- package/src/ProgressBar/ProgressBar.tsx +2 -3
- package/src/RadioList/RadioList.tsx +3 -3
- package/src/SegmentedControl/SegmentedControl.tsx +51 -77
- package/src/Selector/Selector.doc.mjs +21 -0
- package/src/Selector/Selector.test.tsx +123 -1
- package/src/Selector/Selector.tsx +53 -3
- package/src/Switch/Switch.tsx +2 -16
- package/src/TabList/TabList.test.tsx +41 -0
- package/src/TabList/TabList.tsx +66 -39
- package/src/Table/tableContextMenu.tsx +1 -5
- package/src/TextArea/TextArea.tsx +3 -13
- package/src/Toolbar/Toolbar.test.tsx +64 -6
- package/src/Toolbar/Toolbar.tsx +55 -4
- package/src/TreeList/TreeList.tsx +17 -28
- package/src/TreeList/TreeListItem.tsx +3 -2
- package/src/VisuallyHidden/VisuallyHidden.doc.mjs +7 -7
- package/src/hooks/index.ts +12 -5
- package/src/hooks/useGridFocus.doc.mjs +40 -2
- package/src/hooks/useGridFocus.test.tsx +132 -0
- package/src/hooks/useGridFocus.ts +179 -23
- package/src/hooks/useKeyboardHint.doc.mjs +101 -0
- package/src/hooks/useKeyboardHint.test.tsx +70 -0
- package/src/hooks/useKeyboardHint.tsx +332 -0
- package/src/hooks/useTreeFocus.doc.mjs +15 -1
- package/src/hooks/useTreeFocus.ts +101 -6
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
- package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
- package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
package/dist/Link/Link.js
CHANGED
|
@@ -21,6 +21,7 @@ import { colorVars, durationVars, easeVars, spacingVars, typeScaleVars } from ".
|
|
|
21
21
|
import { Icon } from "../Icon/index.js";
|
|
22
22
|
import { Tooltip } from "../Tooltip/index.js";
|
|
23
23
|
import { Text } from "../Text/index.js";
|
|
24
|
+
import { VisuallyHidden } from "../VisuallyHidden/index.js";
|
|
24
25
|
import { useLinkComponent } from "./useLinkComponent.js";
|
|
25
26
|
import { mergeProps } from "../utils/index.js";
|
|
26
27
|
import { computeTargetAndRel } from "./computeTargetAndRel.js";
|
|
@@ -179,10 +180,7 @@ export function Link({
|
|
|
179
180
|
icon: "externalLink",
|
|
180
181
|
size: "xsm",
|
|
181
182
|
color: "inherit"
|
|
182
|
-
}), /*#__PURE__*/_jsx(
|
|
183
|
-
...{
|
|
184
|
-
className: "x10l6tqk x1i1rx1s xjm9jq1 xkdpibf x1717udv xb3r6kr xzpqnlu xuxw1ft xng3xce"
|
|
185
|
-
},
|
|
183
|
+
}), /*#__PURE__*/_jsx(VisuallyHidden, {
|
|
186
184
|
children: newTabLabel
|
|
187
185
|
})]
|
|
188
186
|
})]
|
|
@@ -59,12 +59,6 @@ export interface MoreMenuProps extends Pick<BaseProps, 'xstyle' | 'className' |
|
|
|
59
59
|
* Callback fired when the menu visibility changes.
|
|
60
60
|
*/
|
|
61
61
|
onOpenChange?: (isOpen: boolean) => void;
|
|
62
|
-
/**
|
|
63
|
-
* Whether to auto-focus the first menu item when the menu opens.
|
|
64
|
-
* Set to `false` for inline showcases or documentation previews.
|
|
65
|
-
* @default true
|
|
66
|
-
*/
|
|
67
|
-
hasAutoFocus?: boolean;
|
|
68
62
|
/** Test ID for testing frameworks. */
|
|
69
63
|
'data-testid'?: string;
|
|
70
64
|
}
|
|
@@ -83,7 +77,7 @@ export interface MoreMenuProps extends Pick<BaseProps, 'xstyle' | 'className' |
|
|
|
83
77
|
* />
|
|
84
78
|
* ```
|
|
85
79
|
*/
|
|
86
|
-
export declare function MoreMenu({ items, label, variant, size: sizeProp, icon, isDisabled, isMenuOpen, onOpenChange,
|
|
80
|
+
export declare function MoreMenu({ items, label, variant, size: sizeProp, icon, isDisabled, isMenuOpen, onOpenChange, xstyle, className: classNameProp, style, 'data-testid': testId, ref, }: MoreMenuProps): import("react").JSX.Element;
|
|
87
81
|
export declare namespace MoreMenu {
|
|
88
82
|
var displayName: string;
|
|
89
83
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MoreMenu.d.ts","sourceRoot":"","sources":["../../src/MoreMenu/MoreMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAIrC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAC,aAAa,EAAE,UAAU,EAAC,MAAM,WAAW,CAAC;AACzD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,MAAM,WAAW,aAAc,SAAQ,IAAI,CACzC,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAEnC;;;OAGG;IACH,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAE5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAElB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC
|
|
1
|
+
{"version":3,"file":"MoreMenu.d.ts","sourceRoot":"","sources":["../../src/MoreMenu/MoreMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAIrC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAC,aAAa,EAAE,UAAU,EAAC,MAAM,WAAW,CAAC;AACzD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,MAAM,WAAW,aAAc,SAAQ,IAAI,CACzC,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAEnC;;;OAGG;IACH,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAE5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAElB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAsB,EACtB,OAAiB,EACjB,IAAI,EAAE,QAAQ,EACd,IAAI,EACJ,UAAkB,EAClB,UAAU,EACV,YAAY,EACZ,MAAM,EACN,SAAS,EAAE,aAAa,EACxB,KAAK,EACL,aAAa,EAAE,MAAM,EACrB,GAAG,GACJ,EAAE,aAAa,+BA8Bf;yBA5Ce,QAAQ"}
|
|
@@ -46,7 +46,6 @@ export function MoreMenu({
|
|
|
46
46
|
isDisabled = false,
|
|
47
47
|
isMenuOpen,
|
|
48
48
|
onOpenChange,
|
|
49
|
-
hasAutoFocus,
|
|
50
49
|
xstyle,
|
|
51
50
|
className: classNameProp,
|
|
52
51
|
style,
|
|
@@ -73,7 +72,6 @@ export function MoreMenu({
|
|
|
73
72
|
},
|
|
74
73
|
items: items,
|
|
75
74
|
hasChevron: false,
|
|
76
|
-
hasAutoFocus: hasAutoFocus,
|
|
77
75
|
"data-testid": testId
|
|
78
76
|
});
|
|
79
77
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file MultiSelector.tsx
|
|
3
|
-
* @input Uses React, StyleX, usePopover, CheckboxInput, Field, Badge, Icon
|
|
3
|
+
* @input Uses React, StyleX, usePopover, useTooltip, CheckboxInput, Field, Badge, Icon
|
|
4
4
|
* @output Exports MultiSelector component
|
|
5
5
|
* @position Core implementation; consumed by index.ts
|
|
6
6
|
*
|
|
@@ -46,6 +46,29 @@ export interface MultiSelectorProps<T extends MultiSelectorOptionType = MultiSel
|
|
|
46
46
|
* @default false
|
|
47
47
|
*/
|
|
48
48
|
isDisabled?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Explains why the selector is disabled. When set together with
|
|
51
|
+
* `isDisabled`, the selector shows a tooltip with this text on hover and
|
|
52
|
+
* keyboard focus, and the trigger stays focusable (via `aria-disabled`)
|
|
53
|
+
* so the reason is discoverable by keyboard and assistive technology.
|
|
54
|
+
* Activation stays blocked.
|
|
55
|
+
*
|
|
56
|
+
* Use this instead of wrapping a disabled selector in `Tooltip` — disabled
|
|
57
|
+
* controls don't emit the pointer events an external tooltip needs.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```
|
|
61
|
+
* <MultiSelector
|
|
62
|
+
* label="Columns"
|
|
63
|
+
* options={columns}
|
|
64
|
+
* value={selected}
|
|
65
|
+
* onChange={setSelected}
|
|
66
|
+
* isDisabled
|
|
67
|
+
* disabledMessage="Select a table first"
|
|
68
|
+
* />
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
disabledMessage?: string;
|
|
49
72
|
/**
|
|
50
73
|
* The options to display in the selector.
|
|
51
74
|
* Can be strings, objects, dividers, or sections.
|
|
@@ -167,7 +190,7 @@ export interface MultiSelectorProps<T extends MultiSelectorOptionType = MultiSel
|
|
|
167
190
|
* />
|
|
168
191
|
* ```
|
|
169
192
|
*/
|
|
170
|
-
export declare function MultiSelector<T extends MultiSelectorOptionType>({ label, isLabelHidden, description, isOptional, isRequired, isDisabled, options, value, onChange, changeAction, isLoading, placeholder, size: sizeProp, status, labelTooltip, startIcon, hasClear, hasSelectAll, selectAllLabel, hasSearch, searchPlaceholder, triggerDisplay, maxBadges, renderOption, isDefaultOpen, 'data-testid': testId, width, xstyle, className, style, }: MultiSelectorProps<T>): React.JSX.Element;
|
|
193
|
+
export declare function MultiSelector<T extends MultiSelectorOptionType>({ label, isLabelHidden, description, isOptional, isRequired, isDisabled, disabledMessage, options, value, onChange, changeAction, isLoading, placeholder, size: sizeProp, status, labelTooltip, startIcon, hasClear, hasSelectAll, selectAllLabel, hasSearch, searchPlaceholder, triggerDisplay, maxBadges, renderOption, isDefaultOpen, 'data-testid': testId, width, xstyle, className, style, }: MultiSelectorProps<T>): React.JSX.Element;
|
|
171
194
|
export declare namespace MultiSelector {
|
|
172
195
|
var displayName: string;
|
|
173
196
|
}
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"MultiSelector.d.ts","sourceRoot":"","sources":["../../src/MultiSelector/MultiSelector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file MultiSelector.tsx
|
|
7
|
-
* @input Uses React, StyleX, usePopover, CheckboxInput, Field, Badge, Icon
|
|
7
|
+
* @input Uses React, StyleX, usePopover, useTooltip, CheckboxInput, Field, Badge, Icon
|
|
8
8
|
* @output Exports MultiSelector component
|
|
9
9
|
* @position Core implementation; consumed by index.ts
|
|
10
10
|
*
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import React, { useCallback, useEffect, useId, useMemo, useOptimistic, useRef, useState, useTransition } from 'react';
|
|
17
17
|
import * as stylex from '@stylexjs/stylex';
|
|
18
18
|
import { usePopover } from "../Popover/usePopover.js";
|
|
19
|
+
import { useTooltip } from "../Tooltip/index.js";
|
|
19
20
|
import { Icon, renderIconSlot } from "../Icon/index.js";
|
|
20
21
|
import { Field, inputStatusBorderStyles, inputStatusHoverShadowStyles, inputWrapperStyles } from "../Field/index.js";
|
|
21
22
|
import { Divider } from "../Divider/index.js";
|
|
@@ -175,6 +176,7 @@ export function MultiSelector({
|
|
|
175
176
|
isOptional = false,
|
|
176
177
|
isRequired = false,
|
|
177
178
|
isDisabled = false,
|
|
179
|
+
disabledMessage,
|
|
178
180
|
options,
|
|
179
181
|
value,
|
|
180
182
|
onChange,
|
|
@@ -218,8 +220,22 @@ export function MultiSelector({
|
|
|
218
220
|
const [optimisticValue, setOptimisticValue] = useOptimistic(value);
|
|
219
221
|
const isBusy = isLoading || optimisticValue !== value;
|
|
220
222
|
|
|
223
|
+
// Disabled-reason tooltip. Disabled controls swallow pointer events, so the
|
|
224
|
+
// tooltip listeners attach to the trigger container (which already exists)
|
|
225
|
+
// and the trigger button stays perceivable via aria-disabled instead of the
|
|
226
|
+
// disabled attribute. Activation is blocked by the isDisabled guards in
|
|
227
|
+
// useMultiCombobox (onTriggerClick / onKeyDown).
|
|
228
|
+
const showsDisabledMessage = isDisabled && !!disabledMessage;
|
|
229
|
+
const disabledMessageTooltip = useTooltip({
|
|
230
|
+
placement: 'above',
|
|
231
|
+
// The container div is not naturally focusable; focusin bubbles up from
|
|
232
|
+
// the trigger button, so always attach focus listeners.
|
|
233
|
+
focusTrigger: 'always',
|
|
234
|
+
isEnabled: showsDisabledMessage
|
|
235
|
+
});
|
|
236
|
+
|
|
221
237
|
// Build aria-describedby
|
|
222
|
-
const ariaDescribedBy = [description ? descriptionId : null, status?.message ? statusMessageId : null].filter(Boolean).join(' ') || undefined;
|
|
238
|
+
const ariaDescribedBy = [description ? descriptionId : null, status?.message ? statusMessageId : null, showsDisabledMessage ? disabledMessageTooltip.describedBy : null].filter(Boolean).join(' ') || undefined;
|
|
223
239
|
|
|
224
240
|
// Flatten options for keyboard navigation
|
|
225
241
|
const selectableItems = useMemo(() => getSelectableOptions(options), [options]);
|
|
@@ -686,6 +702,10 @@ export function MultiSelector({
|
|
|
686
702
|
children: [/*#__PURE__*/_jsxs("div", {
|
|
687
703
|
ref: el => {
|
|
688
704
|
popover.triggerRef(el);
|
|
705
|
+
// Anchor + hover/focus listeners for the disabled-message tooltip.
|
|
706
|
+
// Handlers are gated internally by isEnabled, and anchor names
|
|
707
|
+
// compose, so attaching unconditionally is safe.
|
|
708
|
+
disabledMessageTooltip.ref(el);
|
|
689
709
|
},
|
|
690
710
|
onClick: onTriggerClick,
|
|
691
711
|
"data-testid": testId,
|
|
@@ -712,10 +732,15 @@ export function MultiSelector({
|
|
|
712
732
|
"aria-describedby": ariaDescribedBy,
|
|
713
733
|
"aria-required": isRequired ? 'true' : undefined,
|
|
714
734
|
"aria-invalid": status?.type === 'error' ? 'true' : undefined,
|
|
715
|
-
"aria-busy": isBusy || undefined
|
|
716
|
-
|
|
735
|
+
"aria-busy": isBusy || undefined
|
|
736
|
+
// With a disabledMessage the trigger keeps focusability via
|
|
737
|
+
// aria-disabled so the reason is focus-discoverable; activation is
|
|
738
|
+
// still blocked by the isDisabled guards in useMultiCombobox.
|
|
739
|
+
,
|
|
740
|
+
disabled: isDisabled && !showsDisabledMessage,
|
|
741
|
+
"aria-disabled": showsDisabledMessage ? 'true' : undefined,
|
|
717
742
|
onKeyDown: onKeyDown,
|
|
718
|
-
tabIndex: isDisabled ? -1 : 0,
|
|
743
|
+
tabIndex: isDisabled && !showsDisabledMessage ? -1 : 0,
|
|
719
744
|
...{
|
|
720
745
|
className: "x78zum5 x6s0dn4 x1qughib x1txdalj x1iyjqo2 xs83m0k x1r8uery xeuugli x1717udv x1ghz6dp xc342km xng3xce xjbqb8w xjb2p0i x1qlqyl8 x15bjb6t x1heor9g x1ypdohk x1a2a7pz x1p25gnr x1wfwxd8 xh6dtrn"
|
|
721
746
|
},
|
|
@@ -779,7 +804,7 @@ export function MultiSelector({
|
|
|
779
804
|
placement: 'below',
|
|
780
805
|
alignment: 'start',
|
|
781
806
|
xstyle: styles.popover
|
|
782
|
-
})]
|
|
807
|
+
}), showsDisabledMessage && disabledMessageTooltip.renderTooltip(disabledMessage)]
|
|
783
808
|
});
|
|
784
809
|
}
|
|
785
810
|
MultiSelector.displayName = 'MultiSelector';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProgressBar.d.ts","sourceRoot":"","sources":["../../src/ProgressBar/ProgressBar.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"ProgressBar.d.ts","sourceRoot":"","sources":["../../src/ProgressBar/ProgressBar.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,IAAI,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,IAAI,CAAC;CACb;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,qBAAqB,CAAC;AAE7D,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,cAAc,CAAC;IACjE,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1D;;;OAGG;IACH,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAkHD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAS,EACT,GAAS,EACT,KAAK,EACL,aAAqB,EACrB,aAAqB,EACrB,gBAA0C,EAC1C,OAAkB,EAClB,eAAuB,EACvB,UAAkB,EAClB,MAAM,EACN,SAAS,EACT,KAAK,EACL,aAAa,EAAE,UAAU,EACzB,GAAG,EACH,GAAG,IAAI,EACR,EAAE,gBAAgB,+BAiFlB;yBAjGe,WAAW"}
|
|
@@ -21,6 +21,7 @@ import "../theme/tokens.stylex.js";
|
|
|
21
21
|
import { colorVars, spacingVars, radiusVars, fontWeightVars, durationVars, easeVars, typeScaleVars } from "../theme/tokens.stylex.js";
|
|
22
22
|
import { mergeProps } from "../utils/index.js";
|
|
23
23
|
import { themeProps } from "../utils/themeProps.js";
|
|
24
|
+
import { VisuallyHidden } from "../VisuallyHidden/index.js";
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Extensible variant map for ProgressBar.
|
|
@@ -194,11 +195,8 @@ export function ProgressBar({
|
|
|
194
195
|
}[!!isDisabled << 0],
|
|
195
196
|
children: valueText
|
|
196
197
|
})]
|
|
197
|
-
}) : /*#__PURE__*/_jsx(
|
|
198
|
+
}) : /*#__PURE__*/_jsx(VisuallyHidden, {
|
|
198
199
|
id: labelId,
|
|
199
|
-
...{
|
|
200
|
-
className: "x10l6tqk x1i1rx1s xjm9jq1 x1717udv xkdpibf xb3r6kr xzpqnlu xuxw1ft xc342km"
|
|
201
|
-
},
|
|
202
200
|
children: label
|
|
203
201
|
}), /*#__PURE__*/_jsx("div", {
|
|
204
202
|
role: "progressbar",
|
|
@@ -67,7 +67,7 @@ export function RadioList({
|
|
|
67
67
|
}) {
|
|
68
68
|
const name = useId();
|
|
69
69
|
const inputID = useId();
|
|
70
|
-
const
|
|
70
|
+
const labelID = useId();
|
|
71
71
|
const descriptionID = useId();
|
|
72
72
|
const statusMessageID = useId();
|
|
73
73
|
const groupRef = useRef(null);
|
|
@@ -154,7 +154,7 @@ export function RadioList({
|
|
|
154
154
|
isLabelHidden: isLabelHidden,
|
|
155
155
|
description: description,
|
|
156
156
|
inputID: inputID,
|
|
157
|
-
|
|
157
|
+
labelID: labelID,
|
|
158
158
|
isGroupLabel: true,
|
|
159
159
|
descriptionID: description ? descriptionID : undefined,
|
|
160
160
|
isOptional: isOptional,
|
|
@@ -174,7 +174,7 @@ export function RadioList({
|
|
|
174
174
|
children: /*#__PURE__*/_jsx("div", {
|
|
175
175
|
ref: groupRef,
|
|
176
176
|
role: "radiogroup",
|
|
177
|
-
"aria-labelledby":
|
|
177
|
+
"aria-labelledby": labelID,
|
|
178
178
|
onFocus: handleFocus,
|
|
179
179
|
"aria-describedby": [description ? descriptionID : null, status?.message ? statusMessageID : null].filter(Boolean).join(' ') || undefined,
|
|
180
180
|
"aria-invalid": status?.type === 'error' ? true : undefined,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file SegmentedControl.tsx
|
|
3
|
-
* @input Uses React, StyleX, SegmentedControlContext
|
|
3
|
+
* @input Uses React, StyleX, SegmentedControlContext, useListFocus, useKeyboardHint
|
|
4
4
|
* @output Exports SegmentedControl component and SegmentedControlProps type
|
|
5
5
|
* @position Container wrapper; provides context to SegmentedControlItem children
|
|
6
6
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedControl.d.ts","sourceRoot":"","sources":["../../src/SegmentedControl/SegmentedControl.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"SegmentedControl.d.ts","sourceRoot":"","sources":["../../src/SegmentedControl/SegmentedControl.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,EAAuB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAMlE,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CACjD,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,sBAAsB,CAAC;IAChC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAwCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,KAAK,EACL,QAAQ,EACR,KAAK,EACL,IAAI,EAAE,QAAQ,EACd,MAAc,EACd,UAAkB,EAClB,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,GACN,EAAE,qBAAqB,qBAwFvB;yBApGe,gBAAgB"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file SegmentedControl.tsx
|
|
7
|
-
* @input Uses React, StyleX, SegmentedControlContext
|
|
7
|
+
* @input Uses React, StyleX, SegmentedControlContext, useListFocus, useKeyboardHint
|
|
8
8
|
* @output Exports SegmentedControl component and SegmentedControlProps type
|
|
9
9
|
* @position Container wrapper; provides context to SegmentedControlItem children
|
|
10
10
|
*
|
|
@@ -14,16 +14,17 @@
|
|
|
14
14
|
* - /packages/core/src/SegmentedControl/SegmentedControl.test.tsx
|
|
15
15
|
* - /packages/cli/templates/blocks/components/SegmentedControl/ (showcase blocks)
|
|
16
16
|
*/
|
|
17
|
-
import React, { useMemo,
|
|
17
|
+
import React, { useMemo, useCallback } from 'react';
|
|
18
18
|
import * as stylex from '@stylexjs/stylex';
|
|
19
19
|
import "../theme/tokens.stylex.js";
|
|
20
20
|
import { colorVars, spacingVars, radiusVars } from "../theme/tokens.stylex.js";
|
|
21
21
|
import { SegmentedControlContext } from "./SegmentedControlContext.js";
|
|
22
|
-
import {
|
|
22
|
+
import { useListFocus } from "../hooks/useListFocus.js";
|
|
23
|
+
import { useKeyboardHint } from "../hooks/useKeyboardHint.js";
|
|
23
24
|
import { mergeProps, mergeRefs } from "../utils/index.js";
|
|
24
25
|
import { useSize } from "../SizeContext/SizeContext.js";
|
|
25
26
|
import { themeProps } from "../utils/themeProps.js";
|
|
26
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
27
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
27
28
|
// =============================================================================
|
|
28
29
|
// Styles
|
|
29
30
|
// =============================================================================
|
|
@@ -94,45 +95,53 @@ export function SegmentedControl({
|
|
|
94
95
|
style
|
|
95
96
|
}) {
|
|
96
97
|
const size = useSize(sizeProp, 'md');
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
|
|
99
|
+
// Roving tabindex + arrow/Home/End navigation is owned by the shared
|
|
100
|
+
// useListFocus primitive: it stamps a single tab stop (tabIndex 0/-1) across
|
|
101
|
+
// the radios, skips disabled ones, wraps at the ends, handles Home/End, and
|
|
102
|
+
// repairs the tab stop on mount and whenever items mount/disable — replacing
|
|
103
|
+
// the component's former inline keyboard handler and tab-stop repair effect.
|
|
104
|
+
const {
|
|
105
|
+
listRef,
|
|
106
|
+
handleKeyDown,
|
|
107
|
+
handleFocus
|
|
108
|
+
} = useListFocus({
|
|
109
|
+
itemSelector: '[role="radio"]:not([aria-disabled="true"])',
|
|
110
|
+
hasRovingTabIndex: true,
|
|
111
|
+
wrap: true,
|
|
112
|
+
orientation: 'horizontal'
|
|
113
|
+
});
|
|
114
|
+
const hint = useKeyboardHint({
|
|
115
|
+
orientation: 'horizontal',
|
|
116
|
+
isEnabled: !isDisabled
|
|
117
|
+
});
|
|
118
|
+
const handleContainerKeyDown = useCallback(e => {
|
|
119
|
+
hint.onKeyDown(e);
|
|
120
|
+
handleKeyDown(e);
|
|
121
|
+
}, [hint, handleKeyDown]);
|
|
122
|
+
|
|
123
|
+
// Selection-follows-focus (APG radiogroup): useListFocus only *moves* focus,
|
|
124
|
+
// so whenever it lands focus on a new radio (arrow/Home/End, or a click) we
|
|
125
|
+
// select that radio's value. Reading the focused element's data-value here
|
|
126
|
+
// keeps selection in lockstep with focus without duplicating the navigation
|
|
127
|
+
// logic. Disabled radios are ignored (they should never become the value),
|
|
128
|
+
// and the already-selected value is skipped so an initial Tab-in (or a click
|
|
129
|
+
// on the current segment) is a no-op, matching click behavior.
|
|
130
|
+
const handleContainerFocus = useCallback(e => {
|
|
131
|
+
hint.onFocus(e);
|
|
132
|
+
handleFocus(e);
|
|
99
133
|
if (isDisabled) {
|
|
100
134
|
return;
|
|
101
135
|
}
|
|
102
|
-
const
|
|
103
|
-
if (!
|
|
136
|
+
const focused = e.target?.closest('[role="radio"][data-value]');
|
|
137
|
+
if (!focused || focused.getAttribute('aria-disabled') === 'true') {
|
|
104
138
|
return;
|
|
105
139
|
}
|
|
106
|
-
const
|
|
107
|
-
if (
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
const currentIndex = items.findIndex(item => item === document.activeElement);
|
|
111
|
-
let nextIndex;
|
|
112
|
-
switch (e.key) {
|
|
113
|
-
case 'ArrowRight':
|
|
114
|
-
nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % items.length;
|
|
115
|
-
break;
|
|
116
|
-
case 'ArrowLeft':
|
|
117
|
-
nextIndex = currentIndex === -1 ? items.length - 1 : (currentIndex - 1 + items.length) % items.length;
|
|
118
|
-
break;
|
|
119
|
-
case 'Home':
|
|
120
|
-
nextIndex = 0;
|
|
121
|
-
break;
|
|
122
|
-
case 'End':
|
|
123
|
-
nextIndex = items.length - 1;
|
|
124
|
-
break;
|
|
125
|
-
default:
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
e.preventDefault();
|
|
129
|
-
const nextItem = items[nextIndex];
|
|
130
|
-
nextItem.focus();
|
|
131
|
-
const nextValue = nextItem.dataset.value;
|
|
132
|
-
if (nextValue != null) {
|
|
140
|
+
const nextValue = focused.dataset.value;
|
|
141
|
+
if (nextValue != null && nextValue !== value) {
|
|
133
142
|
onChange(nextValue);
|
|
134
143
|
}
|
|
135
|
-
}, [isDisabled, onChange]);
|
|
144
|
+
}, [hint, handleFocus, isDisabled, onChange, value]);
|
|
136
145
|
const contextValue = useMemo(() => ({
|
|
137
146
|
value,
|
|
138
147
|
onChange,
|
|
@@ -140,39 +149,20 @@ export function SegmentedControl({
|
|
|
140
149
|
layout,
|
|
141
150
|
isDisabled
|
|
142
151
|
}), [value, onChange, size, layout, isDisabled]);
|
|
143
|
-
|
|
144
|
-
// Tab-stop repair (navigation-6): each item sets tabIndex=0 only when its
|
|
145
|
-
// value matches the group value, so a stale/unmatched `value` (or a disabled
|
|
146
|
-
// selected item) can leave every segment at tabIndex=-1 — making the whole
|
|
147
|
-
// radiogroup unreachable by Tab. After render, if no enabled radio is
|
|
148
|
-
// tabbable, promote the first enabled radio to tabIndex=0 so the group always
|
|
149
|
-
// has exactly one tab stop. Mirrors Base UI's Composite tab-stop repair.
|
|
150
|
-
useIsomorphicLayoutEffect(() => {
|
|
151
|
-
const container = containerRef.current;
|
|
152
|
-
if (!container) {
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const enabled = Array.from(container.querySelectorAll('[role="radio"]:not([aria-disabled="true"])'));
|
|
156
|
-
if (enabled.length === 0) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
const hasTabStop = enabled.some(el => el.tabIndex === 0);
|
|
160
|
-
if (!hasTabStop) {
|
|
161
|
-
enabled[0].tabIndex = 0;
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
152
|
return /*#__PURE__*/_jsx(SegmentedControlContext, {
|
|
165
153
|
value: contextValue,
|
|
166
|
-
children: /*#__PURE__*/
|
|
167
|
-
ref: mergeRefs(ref,
|
|
154
|
+
children: /*#__PURE__*/_jsxs("div", {
|
|
155
|
+
ref: mergeRefs(ref, listRef),
|
|
168
156
|
role: "radiogroup",
|
|
169
157
|
"aria-label": label,
|
|
170
158
|
"aria-disabled": isDisabled || undefined,
|
|
171
|
-
onKeyDown:
|
|
159
|
+
onKeyDown: handleContainerKeyDown,
|
|
160
|
+
onFocus: handleContainerFocus,
|
|
161
|
+
onBlur: hint.onBlur,
|
|
172
162
|
...mergeProps(themeProps('segmented-control', {
|
|
173
163
|
size
|
|
174
164
|
}), stylex.props(styles.container, sizeStyles[size], layout === 'fill' && styles.fill, isDisabled && styles.disabled, xstyle), className, style),
|
|
175
|
-
children: children
|
|
165
|
+
children: [children, hint.hintElement]
|
|
176
166
|
})
|
|
177
167
|
});
|
|
178
168
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file Selector.tsx
|
|
3
|
-
* @input Uses React, StyleX, usePopover, Icon
|
|
3
|
+
* @input Uses React, StyleX, usePopover, useTooltip, Icon
|
|
4
4
|
* @output Exports Selector component
|
|
5
5
|
* @position Core implementation; consumed by index.ts
|
|
6
6
|
*
|
|
@@ -56,6 +56,27 @@ interface SelectorPropsBase<T extends SelectorOptionType = SelectorOptionType> e
|
|
|
56
56
|
* @default false
|
|
57
57
|
*/
|
|
58
58
|
isDisabled?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Explains why the selector is disabled. When set together with
|
|
61
|
+
* `isDisabled`, the selector shows a tooltip with this text on hover and
|
|
62
|
+
* keyboard focus, and the trigger stays focusable (via `aria-disabled`)
|
|
63
|
+
* so the reason is discoverable by keyboard and assistive technology.
|
|
64
|
+
* Activation stays blocked.
|
|
65
|
+
*
|
|
66
|
+
* Use this instead of wrapping a disabled selector in `Tooltip` — disabled
|
|
67
|
+
* controls don't emit the pointer events an external tooltip needs.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```
|
|
71
|
+
* <Selector
|
|
72
|
+
* label="Owner"
|
|
73
|
+
* options={owners}
|
|
74
|
+
* isDisabled
|
|
75
|
+
* disabledMessage="You need the Editor role to change this"
|
|
76
|
+
* />
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
disabledMessage?: string;
|
|
59
80
|
/**
|
|
60
81
|
* The options to display in the selector.
|
|
61
82
|
* Can be strings, objects, dividers, or sections.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Selector.d.ts","sourceRoot":"","sources":["../../src/Selector/Selector.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,EASZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Selector.d.ts","sourceRoot":"","sources":["../../src/Selector/Selector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file Selector.tsx
|
|
7
|
-
* @input Uses React, StyleX, usePopover, Icon
|
|
7
|
+
* @input Uses React, StyleX, usePopover, useTooltip, Icon
|
|
8
8
|
* @output Exports Selector component
|
|
9
9
|
* @position Core implementation; consumed by index.ts
|
|
10
10
|
*
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import React, { useCallback, useEffect, useId, useMemo, useOptimistic, useRef, useState, useTransition } from 'react';
|
|
17
17
|
import * as stylex from '@stylexjs/stylex';
|
|
18
18
|
import { usePopover } from "../Popover/usePopover.js";
|
|
19
|
+
import { useTooltip } from "../Tooltip/index.js";
|
|
19
20
|
import { Icon, renderIconSlot } from "../Icon/index.js";
|
|
20
21
|
import { Field, inputStatusBorderStyles, inputStatusHoverShadowStyles, inputWrapperStyles } from "../Field/index.js";
|
|
21
22
|
import { Divider } from "../Divider/index.js";
|
|
@@ -180,6 +181,7 @@ export function Selector(props) {
|
|
|
180
181
|
isOptional = false,
|
|
181
182
|
isRequired = false,
|
|
182
183
|
isDisabled = false,
|
|
184
|
+
disabledMessage,
|
|
183
185
|
options,
|
|
184
186
|
value,
|
|
185
187
|
onChange,
|
|
@@ -220,8 +222,22 @@ export function Selector(props) {
|
|
|
220
222
|
const [optimisticValue, setOptimisticValue] = useOptimistic(normalizedValue);
|
|
221
223
|
const isBusy = isLoading || optimisticValue !== normalizedValue;
|
|
222
224
|
|
|
225
|
+
// Disabled-reason tooltip. Disabled controls swallow pointer events, so the
|
|
226
|
+
// tooltip listeners attach to the trigger container (which already exists)
|
|
227
|
+
// and the trigger button stays perceivable via aria-disabled instead of the
|
|
228
|
+
// disabled attribute. Activation is blocked by the isDisabled guards in
|
|
229
|
+
// useCombobox (onTriggerClick / onKeyDown).
|
|
230
|
+
const showsDisabledMessage = isDisabled && !!disabledMessage;
|
|
231
|
+
const disabledMessageTooltip = useTooltip({
|
|
232
|
+
placement: 'above',
|
|
233
|
+
// The container div is not naturally focusable; focusin bubbles up from
|
|
234
|
+
// the trigger button, so always attach focus listeners.
|
|
235
|
+
focusTrigger: 'always',
|
|
236
|
+
isEnabled: showsDisabledMessage
|
|
237
|
+
});
|
|
238
|
+
|
|
223
239
|
// Build aria-describedby
|
|
224
|
-
const ariaDescribedBy = [description ? descriptionId : null, status?.message ? statusMessageId : null].filter(Boolean).join(' ') || undefined;
|
|
240
|
+
const ariaDescribedBy = [description ? descriptionId : null, status?.message ? statusMessageId : null, showsDisabledMessage ? disabledMessageTooltip.describedBy : null].filter(Boolean).join(' ') || undefined;
|
|
225
241
|
|
|
226
242
|
// Flatten options for keyboard navigation
|
|
227
243
|
const selectableItems = useMemo(() => getSelectableOptions(options), [options]);
|
|
@@ -491,6 +507,10 @@ export function Selector(props) {
|
|
|
491
507
|
children: [/*#__PURE__*/_jsxs("div", {
|
|
492
508
|
ref: el => {
|
|
493
509
|
popover.triggerRef(el);
|
|
510
|
+
// Anchor + hover/focus listeners for the disabled-message tooltip.
|
|
511
|
+
// Handlers are gated internally by isEnabled, and anchor names
|
|
512
|
+
// compose, so attaching unconditionally is safe.
|
|
513
|
+
disabledMessageTooltip.ref(el);
|
|
494
514
|
},
|
|
495
515
|
onClick: onTriggerClick,
|
|
496
516
|
"data-testid": testId,
|
|
@@ -518,10 +538,15 @@ export function Selector(props) {
|
|
|
518
538
|
"aria-describedby": ariaDescribedBy,
|
|
519
539
|
"aria-required": isRequired ? 'true' : undefined,
|
|
520
540
|
"aria-invalid": status?.type === 'error' ? 'true' : undefined,
|
|
521
|
-
"aria-busy": isBusy || undefined
|
|
522
|
-
|
|
541
|
+
"aria-busy": isBusy || undefined
|
|
542
|
+
// With a disabledMessage the trigger keeps focusability via
|
|
543
|
+
// aria-disabled so the reason is focus-discoverable; activation is
|
|
544
|
+
// still blocked by the isDisabled guards in useCombobox.
|
|
545
|
+
,
|
|
546
|
+
disabled: isDisabled && !showsDisabledMessage,
|
|
547
|
+
"aria-disabled": showsDisabledMessage ? 'true' : undefined,
|
|
523
548
|
onKeyDown: onKeyDown,
|
|
524
|
-
tabIndex: isDisabled ? -1 : 0,
|
|
549
|
+
tabIndex: isDisabled && !showsDisabledMessage ? -1 : 0,
|
|
525
550
|
...{
|
|
526
551
|
className: "x78zum5 x6s0dn4 x1qughib x1txdalj x1iyjqo2 xs83m0k x1r8uery xeuugli x1717udv x1ghz6dp xc342km xng3xce xjbqb8w xjb2p0i x1qlqyl8 x15bjb6t x1heor9g x1ypdohk x1a2a7pz"
|
|
527
552
|
},
|
|
@@ -600,7 +625,7 @@ export function Selector(props) {
|
|
|
600
625
|
alignment: 'start',
|
|
601
626
|
xstyle: [styles.popover, layerAnimations[popoverPlacement]],
|
|
602
627
|
style: popoverOffsetStyle
|
|
603
|
-
})]
|
|
628
|
+
}), showsDisabledMessage && disabledMessageTooltip.renderTooltip(disabledMessage)]
|
|
604
629
|
});
|
|
605
630
|
}
|
|
606
631
|
Selector.displayName = 'Selector';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../src/Switch/Switch.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAaf,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AACtC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAIhD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../src/Switch/Switch.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAaf,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AACtC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAIhD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AA4I9C,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,KAAK,CAAC;AAElD,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEtD,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC9D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClC;;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,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACxE;;OAEG;IACH,YAAY,CAAC,EAAE,CACb,OAAO,EAAE,OAAO,EAChB,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAC7B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACpD;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACjC;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAOD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAiB,EACjB,KAAK,EACL,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,OAAO,EACP,MAAM,EACN,SAAS,EACT,YAAY,EACZ,aAAqB,EACrB,YAAwB,EACxB,MAAM,EACN,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,GACJ,EAAE,WAAW,+BA+Ib;yBAtKe,MAAM"}
|
package/dist/Switch/Switch.js
CHANGED
|
@@ -26,6 +26,7 @@ import { mergeProps } from "../utils/index.js";
|
|
|
26
26
|
import "./switch.markers.stylex.js";
|
|
27
27
|
import { switchScope } from "./switch.markers.stylex.js";
|
|
28
28
|
import { themeProps } from "../utils/themeProps.js";
|
|
29
|
+
import { VisuallyHidden } from "../VisuallyHidden/index.js";
|
|
29
30
|
|
|
30
31
|
// Fixed dimensions: 40px width, 24px height, 16px thumb (off), 20px thumb (on)
|
|
31
32
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
@@ -235,10 +236,7 @@ export function Switch({
|
|
|
235
236
|
size: "sm"
|
|
236
237
|
})
|
|
237
238
|
})
|
|
238
|
-
}), isBusy && /*#__PURE__*/_jsx(
|
|
239
|
-
...{
|
|
240
|
-
className: "x10l6tqk x1i1rx1s xjm9jq1 x1717udv xkdpibf xb3r6kr xzpqnlu xuxw1ft xc342km"
|
|
241
|
-
},
|
|
239
|
+
}), isBusy && /*#__PURE__*/_jsx(VisuallyHidden, {
|
|
242
240
|
role: "status",
|
|
243
241
|
children: "Loading"
|
|
244
242
|
})]
|