@astryxdesign/core 0.5.0-canary.b79f0db → 0.5.0-canary.c04ec04
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/AlertDialog/AlertDialog.d.ts +1 -1
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +45 -20
- package/dist/Card/Card.d.ts +6 -9
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +6 -6
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +42 -13
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +55 -3
- package/dist/HoverCard/useHoverCard.d.ts +4 -1
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.d.ts +18 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +46 -5
- package/dist/Selector/Selector.d.ts +17 -0
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +71 -13
- package/locales/en.json +11 -3
- package/locales/pseudo.json +6 -0
- package/package.json +2 -2
- package/src/AlertDialog/AlertDialog.doc.mjs +114 -30
- package/src/AlertDialog/AlertDialog.test.tsx +211 -2
- package/src/AlertDialog/AlertDialog.tsx +62 -20
- package/src/Card/Card.doc.mjs +10 -7
- package/src/Card/Card.test.tsx +44 -19
- package/src/Card/Card.tsx +12 -32
- package/src/DateInput/DateInput.doc.mjs +2 -2
- package/src/DateInput/DateInputTouch.test.tsx +20 -12
- package/src/DateInput/TouchDateField.tsx +67 -13
- package/src/HoverCard/HoverCard.test.tsx +54 -1
- package/src/HoverCard/HoverCard.tsx +74 -2
- package/src/HoverCard/useHoverCard.tsx +4 -1
- package/src/MultiSelector/MultiSelector.doc.mjs +22 -1
- package/src/MultiSelector/MultiSelector.test.tsx +171 -0
- package/src/MultiSelector/MultiSelector.tsx +92 -5
- package/src/Selector/Selector.doc.mjs +14 -0
- package/src/Selector/Selector.test.tsx +217 -0
- package/src/Selector/Selector.tsx +123 -14
- package/src/Table/TableBody.doc.mjs +2 -2
- package/src/Table/TableHeader.doc.mjs +1 -1
- package/src/Timestamp/Timestamp.test.tsx +18 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file AlertDialog.tsx
|
|
3
|
-
* @input Uses React, Dialog, Layout, Heading, Text, Button
|
|
3
|
+
* @input Uses React, StyleX, Dialog, Layout, Heading, Text, Button
|
|
4
4
|
* @output Exports AlertDialog component, AlertDialogProps type
|
|
5
5
|
* @position Core implementation; consumed by index.ts, tested by AlertDialog.test.tsx
|
|
6
6
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlertDialog.d.ts","sourceRoot":"","sources":["../../src/AlertDialog/AlertDialog.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAA2B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"AlertDialog.d.ts","sourceRoot":"","sources":["../../src/AlertDialog/AlertDialog.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAA2B,MAAM,OAAO,CAAC;AAShD,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,WAAW,CAAC;AACrD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAkB5C,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IACpE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAE3C;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAE9B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,QAAQ,EAAE,MAAM,OAAO,CAAC;IAExB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,WAAW,EACX,WAAW,EAAE,oBAAoB,EACjC,WAAW,EACX,aAA6B,EAC7B,eAAe,EACf,QAAQ,EACR,KAAW,EACX,MAAM,EACN,SAAS,EACT,KAAK,EACL,aAAa,EAAE,MAAM,EACrB,GAAG,IAAI,EACR,EAAE,gBAAgB,qBA8FlB;yBAhHe,WAAW"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file AlertDialog.tsx
|
|
7
|
-
* @input Uses React, Dialog, Layout, Heading, Text, Button
|
|
7
|
+
* @input Uses React, StyleX, Dialog, Layout, Heading, Text, Button
|
|
8
8
|
* @output Exports AlertDialog component, AlertDialogProps type
|
|
9
9
|
* @position Core implementation; consumed by index.ts, tested by AlertDialog.test.tsx
|
|
10
10
|
*
|
|
@@ -16,18 +16,32 @@
|
|
|
16
16
|
* - /packages/cli/assets/templates/blocks/components/AlertDialog/ (showcase blocks)
|
|
17
17
|
*/
|
|
18
18
|
import React, { useId, useCallback } from 'react';
|
|
19
|
+
import * as stylex from '@stylexjs/stylex';
|
|
19
20
|
import { Dialog } from "../Dialog/index.js";
|
|
20
21
|
import { Layout } from "../Layout/Layout.js";
|
|
21
22
|
import { LayoutContent } from "../Layout/LayoutContent.js";
|
|
22
23
|
import { LayoutFooter } from "../Layout/LayoutFooter.js";
|
|
23
|
-
import {
|
|
24
|
+
import { Stack } from "../Stack/index.js";
|
|
24
25
|
import { Heading } from "../Heading/Heading.js";
|
|
25
26
|
import { Text } from "../Text/Text.js";
|
|
26
27
|
import { Button } from "../Button/index.js";
|
|
27
28
|
import { mergeProps } from "../utils/index.js";
|
|
28
29
|
import { themeProps } from "../utils/themeProps.js";
|
|
29
30
|
import { useTranslator } from "../i18n/index.js";
|
|
31
|
+
import { useMediaQuery } from "../hooks/index.js";
|
|
30
32
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
33
|
+
const SMALL_SCREEN_QUERY = '(max-width: 640px)';
|
|
34
|
+
const styles = {
|
|
35
|
+
action: {
|
|
36
|
+
ks0D6T: "x193iq5w",
|
|
37
|
+
k7Eaqz: "xeuugli",
|
|
38
|
+
$$css: true
|
|
39
|
+
},
|
|
40
|
+
stackedAction: {
|
|
41
|
+
kzqmXN: "xh8yej3",
|
|
42
|
+
$$css: true
|
|
43
|
+
}
|
|
44
|
+
};
|
|
31
45
|
/**
|
|
32
46
|
* A confirmation dialog for destructive or irreversible actions.
|
|
33
47
|
*
|
|
@@ -77,9 +91,33 @@ export function AlertDialog({
|
|
|
77
91
|
const cancelLabel = cancelLabelFromProps ?? t('@astryx.alertDialog.cancel');
|
|
78
92
|
const titleId = useId();
|
|
79
93
|
const descriptionId = useId();
|
|
94
|
+
// Width stays delegated to Dialog: this query exists only so AlertDialog can
|
|
95
|
+
// keep narrow visual, DOM, and tab order aligned for its destructive/cancel
|
|
96
|
+
// semantics without coupling action order to pointer or hover capability.
|
|
97
|
+
const isSmallScreen = useMediaQuery(SMALL_SCREEN_QUERY);
|
|
80
98
|
const handleCancel = useCallback(() => {
|
|
81
99
|
onOpenChange(false);
|
|
82
100
|
}, [onOpenChange]);
|
|
101
|
+
const buttonActionStyle = [styles.action, isSmallScreen && styles.stackedAction];
|
|
102
|
+
const cancelButton = /*#__PURE__*/_jsx(Button, {
|
|
103
|
+
variant: "ghost",
|
|
104
|
+
label: cancelLabel,
|
|
105
|
+
onClick: handleCancel,
|
|
106
|
+
xstyle: buttonActionStyle
|
|
107
|
+
// Dialog focuses [data-autofocus] itself after showModal(), because
|
|
108
|
+
// React's autoFocus runs during commit while the dialog is invisible.
|
|
109
|
+
// Cancel is least destructive, so it remains the autofocus target even
|
|
110
|
+
// when small-screen visual order places the destructive action above it.
|
|
111
|
+
,
|
|
112
|
+
"data-autofocus": true
|
|
113
|
+
}, "cancel");
|
|
114
|
+
const actionButton = /*#__PURE__*/_jsx(Button, {
|
|
115
|
+
variant: actionVariant,
|
|
116
|
+
label: actionLabel,
|
|
117
|
+
onClick: onAction,
|
|
118
|
+
isLoading: isActionLoading,
|
|
119
|
+
xstyle: buttonActionStyle
|
|
120
|
+
}, "action");
|
|
83
121
|
return /*#__PURE__*/_jsx(Dialog, {
|
|
84
122
|
...rest,
|
|
85
123
|
ref: ref,
|
|
@@ -117,25 +155,12 @@ export function AlertDialog({
|
|
|
117
155
|
})]
|
|
118
156
|
}),
|
|
119
157
|
footer: /*#__PURE__*/_jsx(LayoutFooter, {
|
|
120
|
-
children: /*#__PURE__*/
|
|
158
|
+
children: /*#__PURE__*/_jsx(Stack, {
|
|
159
|
+
direction: isSmallScreen ? 'vertical' : 'horizontal',
|
|
121
160
|
gap: 2,
|
|
122
|
-
hAlign:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
label: cancelLabel,
|
|
126
|
-
onClick: handleCancel
|
|
127
|
-
// Dialog focuses [data-autofocus] itself after showModal(),
|
|
128
|
-
// because React's autoFocus runs during commit while the
|
|
129
|
-
// dialog is still invisible. Cancel is the least destructive
|
|
130
|
-
// choice, so it is the one that should be preselected.
|
|
131
|
-
,
|
|
132
|
-
"data-autofocus": true
|
|
133
|
-
}), /*#__PURE__*/_jsx(Button, {
|
|
134
|
-
variant: actionVariant,
|
|
135
|
-
label: actionLabel,
|
|
136
|
-
onClick: onAction,
|
|
137
|
-
isLoading: isActionLoading
|
|
138
|
-
})]
|
|
161
|
+
hAlign: isSmallScreen ? 'stretch' : 'end',
|
|
162
|
+
wrap: isSmallScreen ? 'nowrap' : 'wrap',
|
|
163
|
+
children: isSmallScreen ? [actionButton, cancelButton] : [cancelButton, actionButton]
|
|
139
164
|
})
|
|
140
165
|
})
|
|
141
166
|
})
|
package/dist/Card/Card.d.ts
CHANGED
|
@@ -30,14 +30,6 @@ export type CardVariant = 'default' | 'transparent' | 'muted' | 'blue' | 'cyan'
|
|
|
30
30
|
export type { SizeValue } from '../utils/types';
|
|
31
31
|
export interface CardProps extends BaseProps<HTMLDivElement> {
|
|
32
32
|
ref?: React.Ref<HTMLDivElement>;
|
|
33
|
-
/**
|
|
34
|
-
* CSS class name(s) appended to the root element.
|
|
35
|
-
*/
|
|
36
|
-
className?: string;
|
|
37
|
-
/**
|
|
38
|
-
* Inline styles to apply to the root element.
|
|
39
|
-
*/
|
|
40
|
-
style?: React.CSSProperties;
|
|
41
33
|
/**
|
|
42
34
|
* Width of the card.
|
|
43
35
|
* Numbers are treated as pixels, strings are used as-is.
|
|
@@ -66,7 +58,12 @@ export interface CardProps extends BaseProps<HTMLDivElement> {
|
|
|
66
58
|
/**
|
|
67
59
|
* Internal padding of the card using the spacing scale.
|
|
68
60
|
* Accepts numeric spacing steps: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10.
|
|
69
|
-
*
|
|
61
|
+
*
|
|
62
|
+
* Omit it and the card takes the theme's card padding rather than a step, so
|
|
63
|
+
* passing a step is a decision to override the theme, not a way to restate
|
|
64
|
+
* the default.
|
|
65
|
+
*
|
|
66
|
+
* @default the theme's card padding (spacing step 4 with no theme)
|
|
70
67
|
*/
|
|
71
68
|
padding?: SpacingStep;
|
|
72
69
|
/**
|
package/dist/Card/Card.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../src/Card/Card.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../src/Card/Card.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAWrC,OAAO,KAAK,EAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAEtE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAO5C;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GACnB,SAAS,GACT,aAAa,GACb,OAAO,GACP,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,KAAK,GACL,MAAM,GACN,QAAQ,CAAC;AA2Gb,YAAY,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAE9C,MAAM,WAAW,SAAU,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC1D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IAEtB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IAEtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,IAAI,CAAC,EACnB,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,OAAO,EACP,OAAmB,EACnB,SAAkB,EAClB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,SAAS,+BAgDX;yBA9De,IAAI"}
|
package/dist/Card/Card.js
CHANGED
|
@@ -17,7 +17,7 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
17
17
|
import "../theme/tokens.stylex.js";
|
|
18
18
|
import { borderVars, colorVars, radiusVars, shadowVars } from "../theme/tokens.stylex.js";
|
|
19
19
|
import { container } from "../Layout/container.stylex.js";
|
|
20
|
-
import {
|
|
20
|
+
import { spacingStepToToken } from "../Layout/padding.stylex.js";
|
|
21
21
|
import { mergeProps } from "../utils/index.js";
|
|
22
22
|
import { themeProps } from "../utils/themeProps.js";
|
|
23
23
|
|
|
@@ -216,20 +216,20 @@ export function Card({
|
|
|
216
216
|
|
|
217
217
|
// When no explicit padding prop, use theme default (set via container tokens)
|
|
218
218
|
const useThemeDefault = padding == null;
|
|
219
|
-
const
|
|
220
|
-
const paddingToken = spacingStepToToken[effectivePadding];
|
|
219
|
+
const paddingToken = useThemeDefault ? undefined : spacingStepToToken[padding];
|
|
221
220
|
return /*#__PURE__*/_jsx("div", {
|
|
222
221
|
ref: ref,
|
|
223
222
|
...mergeProps(themeProps('card', {
|
|
224
|
-
variant
|
|
225
|
-
|
|
223
|
+
variant,
|
|
224
|
+
elevation
|
|
225
|
+
}), stylex.props(styles.card, variantStyles[variant], elevationStyles[elevation], hasFixedHeight && styles.scrollable, dynamicStyles.sizing(width ?? null, height ?? null, maxWidth ?? null, minHeight ?? null), ...container(paddingToken == null ? {
|
|
226
226
|
useThemeDefault: 'card'
|
|
227
227
|
} : {
|
|
228
228
|
paddingInnerX: paddingToken,
|
|
229
229
|
paddingInnerY: paddingToken,
|
|
230
230
|
paddingOuterX: paddingToken,
|
|
231
231
|
paddingOuterY: paddingToken
|
|
232
|
-
}),
|
|
232
|
+
}),
|
|
233
233
|
// Applied after the container padding so the border-inset calc wins;
|
|
234
234
|
// it reads the --container-padding-* vars set above.
|
|
235
235
|
variant === 'default' && styles.withBorder, xstyle), className, style),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TouchDateField.d.ts","sourceRoot":"","sources":["../../src/DateInput/TouchDateField.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TouchDateField.d.ts","sourceRoot":"","sources":["../../src/DateInput/TouchDateField.tsx"],"names":[],"mappings":"AAgEA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAoehD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,eAAe,EACf,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,SAAiB,EACjB,GAAG,EACH,GAAG,EACH,eAAe,EACf,WAAW,EAAE,oBAAoB,EACjC,IAAI,EAAE,QAAQ,EACd,MAAM,EACN,aAA0B,EAC1B,YAAY,EACZ,QAAgB,EAIhB,cAAc,EAAE,eAAe,EAC/B,YAAY,EAAE,gBAAoB,EAClC,MAAoB,EACpB,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,cAAc,+BAmtBhB;yBApvBe,cAAc"}
|
|
@@ -38,6 +38,10 @@
|
|
|
38
38
|
* 3. The title is the escape hatch. Tap it and the same box becomes a month
|
|
39
39
|
* wheel and a year wheel — a flick each to reach 2019 instead of forty.
|
|
40
40
|
*
|
|
41
|
+
* Reset is chrome, so it sits in the header beside the arrows rather than in
|
|
42
|
+
* the footer: the footer is where the task ends, and an undo of equal weight
|
|
43
|
+
* beside Save is a mis-tap that throws away the date just chosen.
|
|
44
|
+
*
|
|
41
45
|
* SYNC: When modified, update these files to stay in sync:
|
|
42
46
|
* - /packages/core/src/DateInput/DateInput.tsx
|
|
43
47
|
* - /packages/core/src/DateInput/DateInput.doc.mjs
|
|
@@ -152,6 +156,10 @@ const styles = {
|
|
|
152
156
|
k1xSpc: "x3nfvp2",
|
|
153
157
|
$$css: true
|
|
154
158
|
},
|
|
159
|
+
resetButton: {
|
|
160
|
+
kAzted: "xygd9yz",
|
|
161
|
+
$$css: true
|
|
162
|
+
},
|
|
155
163
|
title: {
|
|
156
164
|
k1xSpc: "x78zum5",
|
|
157
165
|
kGNEyG: "x6s0dn4",
|
|
@@ -168,10 +176,13 @@ const styles = {
|
|
|
168
176
|
k63SB2: "x2mo6ok",
|
|
169
177
|
kkrTdU: "x1ypdohk x16khyan",
|
|
170
178
|
khDVqt: "xuxw1ft",
|
|
179
|
+
k7Eaqz: "xeuugli",
|
|
180
|
+
kVQacm: "xb3r6kr",
|
|
171
181
|
$$css: true
|
|
172
182
|
},
|
|
173
183
|
titleChevron: {
|
|
174
184
|
k1xSpc: "x3nfvp2",
|
|
185
|
+
kmuXW: "x2lah0s",
|
|
175
186
|
k1ekBW: "x11xpdln",
|
|
176
187
|
kIyJzY: "xuedmi6",
|
|
177
188
|
kAMwcw: "xlr8y92",
|
|
@@ -547,6 +558,9 @@ export function TouchDateField({
|
|
|
547
558
|
"data-title": "month-year",
|
|
548
559
|
...stylex.props(styles.title, focusOutlineStyles.focusVisible),
|
|
549
560
|
children: [/*#__PURE__*/_jsx("span", {
|
|
561
|
+
...{
|
|
562
|
+
className: "xeuugli xb3r6kr xlyipyv"
|
|
563
|
+
},
|
|
550
564
|
children: monthYearLabel
|
|
551
565
|
}), /*#__PURE__*/_jsx(Icon, {
|
|
552
566
|
icon: "chevronDown",
|
|
@@ -603,6 +617,27 @@ export function TouchDateField({
|
|
|
603
617
|
})
|
|
604
618
|
})
|
|
605
619
|
})]
|
|
620
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
621
|
+
"data-action": "reset",
|
|
622
|
+
inert: isWheelOpen ? true : undefined,
|
|
623
|
+
...{
|
|
624
|
+
0: {
|
|
625
|
+
className: "x78zum5 x6s0dn4 x1jl3cmp xuedmi6 xcj1dhv xzg1mie"
|
|
626
|
+
},
|
|
627
|
+
1: {
|
|
628
|
+
className: "x78zum5 x6s0dn4 x1jl3cmp xuedmi6 xcj1dhv xzg1mie xlshs6z xg01cxk x47corl"
|
|
629
|
+
}
|
|
630
|
+
}[!!isWheelOpen << 0],
|
|
631
|
+
children: /*#__PURE__*/_jsx(Button
|
|
632
|
+
// ghost: a filled button up here would outrank the Save that
|
|
633
|
+
// finishes the task.
|
|
634
|
+
, {
|
|
635
|
+
variant: "ghost",
|
|
636
|
+
size: "sm",
|
|
637
|
+
xstyle: styles.resetButton,
|
|
638
|
+
label: t('@astryx.dateInput.resetPicking'),
|
|
639
|
+
onClick: handleResetInSheet
|
|
640
|
+
})
|
|
606
641
|
})]
|
|
607
642
|
}), /*#__PURE__*/_jsx("div", {
|
|
608
643
|
"aria-hidden": "true",
|
|
@@ -677,23 +712,17 @@ export function TouchDateField({
|
|
|
677
712
|
...{
|
|
678
713
|
className: "x1xye8es xrvj5dj x1y6fwsi"
|
|
679
714
|
},
|
|
680
|
-
children: [/*#__PURE__*/
|
|
715
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
681
716
|
inert: isWheelOpen ? true : undefined,
|
|
682
717
|
...{
|
|
683
718
|
0: {
|
|
684
|
-
className: "x15r89dc x78zum5
|
|
719
|
+
className: "x15r89dc x78zum5 x74b7sa xuedmi6 xzg1mie"
|
|
685
720
|
},
|
|
686
721
|
1: {
|
|
687
|
-
className: "x15r89dc x78zum5
|
|
722
|
+
className: "x15r89dc x78zum5 x74b7sa xuedmi6 xzg1mie xlshs6z x47corl"
|
|
688
723
|
}
|
|
689
724
|
}[!!isWheelOpen << 0],
|
|
690
|
-
children:
|
|
691
|
-
variant: "secondary",
|
|
692
|
-
size: "md",
|
|
693
|
-
width: "100%",
|
|
694
|
-
label: t('@astryx.dateInput.resetPicking'),
|
|
695
|
-
onClick: handleResetInSheet
|
|
696
|
-
}), /*#__PURE__*/_jsx(Button, {
|
|
725
|
+
children: /*#__PURE__*/_jsx(Button, {
|
|
697
726
|
variant: "primary"
|
|
698
727
|
// md, not sm: it is the action a thumb reaches for, so it gets
|
|
699
728
|
// the comfortable size rather than the compact one the header's
|
|
@@ -703,15 +732,15 @@ export function TouchDateField({
|
|
|
703
732
|
width: "100%",
|
|
704
733
|
label: t('@astryx.dateInput.savePicking'),
|
|
705
734
|
onClick: () => setIsSheetOpen(false)
|
|
706
|
-
})
|
|
735
|
+
})
|
|
707
736
|
}), /*#__PURE__*/_jsx("div", {
|
|
708
737
|
inert: isWheelOpen ? undefined : true,
|
|
709
738
|
...{
|
|
710
739
|
0: {
|
|
711
|
-
className: "x15r89dc x78zum5
|
|
740
|
+
className: "x15r89dc x78zum5 x10xzikg xc8icb0 x1jl3cmp xuedmi6 xcj1dhv xzg1mie"
|
|
712
741
|
},
|
|
713
742
|
1: {
|
|
714
|
-
className: "x15r89dc x78zum5
|
|
743
|
+
className: "x15r89dc x78zum5 x10xzikg xc8icb0 x1jl3cmp xuedmi6 xcj1dhv xzg1mie xlshs6z xg01cxk x47corl"
|
|
715
744
|
}
|
|
716
745
|
}[!!!isWheelOpen << 0],
|
|
717
746
|
children: /*#__PURE__*/_jsx(Button
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverCard.d.ts","sourceRoot":"","sources":["../../src/HoverCard/HoverCard.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAsB,KAAK,YAAY,EAAE,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAG7E,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAC,cAAc,EAAE,cAAc,EAAC,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,YAAY,EACV,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"HoverCard.d.ts","sourceRoot":"","sources":["../../src/HoverCard/HoverCard.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAsB,KAAK,YAAY,EAAE,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAG7E,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAC,cAAc,EAAE,cAAc,EAAC,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,YAAY,EACV,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AA6ExB,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,SAAS,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAEtC;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAiBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,OAAO,EACP,SAAmB,EACnB,SAAoB,EACpB,KAAW,EACX,SAAe,EACf,YAAqB,EACrB,YAAqB,EACrB,SAAgB,EAChB,KAAK,EACL,YAAY,EACZ,kBAA2B,EAC3B,MAAM,EACN,aAAa,EACb,MAAM,EACN,SAAS,EACT,KAAK,GACN,EAAE,cAAc,GAAG,YAAY,CAoL/B;yBAtMe,SAAS"}
|
|
@@ -21,6 +21,45 @@ import { useHoverCard } from "./useHoverCard.js";
|
|
|
21
21
|
import "../theme/tokens.stylex.js";
|
|
22
22
|
import { colorVars, spacingVars } from "../theme/tokens.stylex.js";
|
|
23
23
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
24
|
+
// `aria-haspopup` and `aria-controls` are global, so any trigger may carry
|
|
25
|
+
// them. `aria-expanded` is not. This is the ARIA 1.2 "Supported States and
|
|
26
|
+
// Properties" list for it — deliberately the narrow reading: axe accepts the
|
|
27
|
+
// attribute on rather more roles, since it also allows every subclass of these,
|
|
28
|
+
// so a role outside this set is not necessarily a violation. Widening it is
|
|
29
|
+
// safe; the set is a floor, not the spec's ceiling. The same rule is applied in
|
|
30
|
+
// Chat/useTriggerMenu.tsx, which only emits the combobox attributes once the
|
|
31
|
+
// element is actually a combobox.
|
|
32
|
+
const EXPANDABLE_ROLES = new Set(['application', 'button', 'checkbox', 'columnheader', 'combobox', 'gridcell', 'link', 'listbox', 'menuitem', 'menuitemcheckbox', 'menuitemradio', 'row', 'rowheader', 'switch', 'tab', 'treeitem']);
|
|
33
|
+
const BUTTON_INPUT_TYPES = new Set(['button', 'submit', 'reset', 'image']);
|
|
34
|
+
|
|
35
|
+
// Deliberately partial, and unlisted elements are read as role-less: dropping
|
|
36
|
+
// aria-expanded where it might have been legal costs an AT user a state they
|
|
37
|
+
// can still infer, whereas emitting it where it is illegal is a critical
|
|
38
|
+
// aria-allowed-attr defect.
|
|
39
|
+
function supportsAriaExpanded(el) {
|
|
40
|
+
const explicit = el.getAttribute('role')?.trim().split(/\s+/)[0];
|
|
41
|
+
if (explicit) {
|
|
42
|
+
return EXPANDABLE_ROLES.has(explicit);
|
|
43
|
+
}
|
|
44
|
+
switch (el.tagName) {
|
|
45
|
+
case 'BUTTON':
|
|
46
|
+
case 'SUMMARY':
|
|
47
|
+
return true;
|
|
48
|
+
case 'A':
|
|
49
|
+
case 'AREA':
|
|
50
|
+
return el.hasAttribute('href');
|
|
51
|
+
case 'INPUT':
|
|
52
|
+
// The button-flavoured input types map to role="button"; every other
|
|
53
|
+
// type maps to a textbox-family role, which does not take it.
|
|
54
|
+
return BUTTON_INPUT_TYPES.has(el.type?.toLowerCase());
|
|
55
|
+
case 'SELECT':
|
|
56
|
+
// combobox when it is a single-line picker, listbox otherwise; both
|
|
57
|
+
// support aria-expanded.
|
|
58
|
+
return true;
|
|
59
|
+
default:
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
24
63
|
/**
|
|
25
64
|
* Check if children are text-only (no React elements)
|
|
26
65
|
*/
|
|
@@ -121,12 +160,17 @@ export function HoverCard({
|
|
|
121
160
|
// trigger with the dialog's content (aria-describedby is for plain-text
|
|
122
161
|
// descriptions, not navigable regions). See #5049.
|
|
123
162
|
//
|
|
163
|
+
// aria-expanded only goes on a trigger whose role permits it. A role-less
|
|
164
|
+
// trigger (Timestamp's <time>/<span>) gets haspopup + controls, which are
|
|
165
|
+
// global, and no expanded state.
|
|
166
|
+
//
|
|
124
167
|
// Merge rather than overwrite: the trigger may already carry its own
|
|
125
168
|
// popup semantics (e.g. a menu button wrapped in a labelled HoverCard),
|
|
126
169
|
// so preserve the existing values and restore them on cleanup.
|
|
127
170
|
const existingHaspopup = firstChild.getAttribute('aria-haspopup');
|
|
128
171
|
const existingControls = firstChild.getAttribute('aria-controls');
|
|
129
172
|
const existingExpanded = firstChild.getAttribute('aria-expanded');
|
|
173
|
+
const canExpand = supportsAriaExpanded(firstChild);
|
|
130
174
|
firstChild.setAttribute('aria-haspopup', 'dialog');
|
|
131
175
|
// Only point aria-controls at the layer while it is open and in the DOM.
|
|
132
176
|
// While closed, useLayer leaves only an inert <template> marker, so the
|
|
@@ -139,7 +183,13 @@ export function HoverCard({
|
|
|
139
183
|
} else {
|
|
140
184
|
firstChild.removeAttribute('aria-controls');
|
|
141
185
|
}
|
|
142
|
-
|
|
186
|
+
if (canExpand) {
|
|
187
|
+
firstChild.setAttribute('aria-expanded', String(hoverCard.isOpen));
|
|
188
|
+
} else if (existingExpanded) {
|
|
189
|
+
firstChild.setAttribute('aria-expanded', existingExpanded);
|
|
190
|
+
} else {
|
|
191
|
+
firstChild.removeAttribute('aria-expanded');
|
|
192
|
+
}
|
|
143
193
|
return () => {
|
|
144
194
|
hoverCard.ref(null);
|
|
145
195
|
if (existingHaspopup) {
|
|
@@ -192,8 +242,10 @@ export function HoverCard({
|
|
|
192
242
|
ref: hoverCard.ref,
|
|
193
243
|
tabIndex: 0,
|
|
194
244
|
"aria-haspopup": label ? 'dialog' : undefined,
|
|
195
|
-
"aria-controls": label && hoverCard.isOpen ? hoverCard.id : undefined
|
|
196
|
-
|
|
245
|
+
"aria-controls": label && hoverCard.isOpen ? hoverCard.id : undefined
|
|
246
|
+
// No aria-expanded: this wrapper is a role-less <span>, and
|
|
247
|
+
// aria-expanded is invalid on it (see EXPANDABLE_ROLES above).
|
|
248
|
+
,
|
|
197
249
|
"aria-describedby": label ? undefined : hoverCard.describedBy,
|
|
198
250
|
...{
|
|
199
251
|
0: {
|
|
@@ -134,7 +134,10 @@ export interface HoverCardReturn {
|
|
|
134
134
|
describedBy: string;
|
|
135
135
|
/**
|
|
136
136
|
* Whether the hover card is currently open.
|
|
137
|
-
* Useful for driving `aria-expanded` on the trigger
|
|
137
|
+
* Useful for driving `aria-expanded` on the trigger — but only when the
|
|
138
|
+
* trigger's role permits it (`button`, `link`, `combobox`, …). On a role-less
|
|
139
|
+
* trigger `aria-expanded` is invalid; use `aria-haspopup`/`aria-controls`
|
|
140
|
+
* alone there.
|
|
138
141
|
*/
|
|
139
142
|
isOpen: boolean;
|
|
140
143
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useHoverCard.d.ts","sourceRoot":"","sources":["../../src/HoverCard/useHoverCard.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AA6BlC;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AAEtD,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,GAAG,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAE9B;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEtC;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEzC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB
|
|
1
|
+
{"version":3,"file":"useHoverCard.d.ts","sourceRoot":"","sources":["../../src/HoverCard/useHoverCard.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AA6BlC;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AAEtD,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,GAAG,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAE9B;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEtC;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEzC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;;;;OAOG;IACH,eAAe,EAAE,CACf,QAAQ,EAAE,SAAS,EACnB,KAAK,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,KAC5C,SAAS,CAAC;IAEf;;OAEG;IACH,IAAI,EAAE,MAAM,IAAI,CAAC;IAEjB;;OAEG;IACH,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAyBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAib5E"}
|
|
@@ -175,6 +175,23 @@ export interface MultiSelectorProps<T extends MultiSelectorOptionType = MultiSel
|
|
|
175
175
|
* @default 'Search...'
|
|
176
176
|
*/
|
|
177
177
|
searchPlaceholder?: string;
|
|
178
|
+
/**
|
|
179
|
+
* Content shown in the panel when there are no options to show, and
|
|
180
|
+
* announced in a polite live region when the panel opens. Not shown while
|
|
181
|
+
* `isLoading` — the options have not arrived yet.
|
|
182
|
+
* @default 'No options'
|
|
183
|
+
*/
|
|
184
|
+
emptyText?: ReactNode;
|
|
185
|
+
/**
|
|
186
|
+
* Content shown in the panel when a search query matches no options, and
|
|
187
|
+
* announced in a polite live region at the same time.
|
|
188
|
+
*
|
|
189
|
+
* The panel message is `role="presentation"`, so the live region is the only
|
|
190
|
+
* route to assistive tech: a string is announced verbatim, a richer node
|
|
191
|
+
* falls back to the default text since it cannot be spoken.
|
|
192
|
+
* @default 'No results found'
|
|
193
|
+
*/
|
|
194
|
+
emptySearchText?: ReactNode;
|
|
178
195
|
/**
|
|
179
196
|
* How to display selected items in the trigger.
|
|
180
197
|
* - 'count': "3 selected"
|
|
@@ -236,7 +253,7 @@ export interface MultiSelectorProps<T extends MultiSelectorOptionType = MultiSel
|
|
|
236
253
|
* />
|
|
237
254
|
* ```
|
|
238
255
|
*/
|
|
239
|
-
export declare function MultiSelector<T extends MultiSelectorOptionType>({ label, isLabelHidden, description, isOptional, isRequired, isDisabled, disabledMessage, options, value, onChange, changeAction, isLoading, placeholder: placeholderFromProps, size: sizeProp, variant, status, statusVariant, labelTooltip, startIcon, hasClear, hasSelectAll, selectAllLabel: selectAllLabelFromProps, hasSearch, searchPlaceholder: searchPlaceholderFromProps, triggerDisplay, formatValue, maxBadges, renderOption, indicatorPosition, isDefaultOpen, 'data-testid': testId, htmlName, width, xstyle, className, style, }: MultiSelectorProps<T>): React.JSX.Element;
|
|
256
|
+
export declare function MultiSelector<T extends MultiSelectorOptionType>({ label, isLabelHidden, description, isOptional, isRequired, isDisabled, disabledMessage, options, value, onChange, changeAction, isLoading, placeholder: placeholderFromProps, size: sizeProp, variant, status, statusVariant, labelTooltip, startIcon, hasClear, hasSelectAll, selectAllLabel: selectAllLabelFromProps, hasSearch, searchPlaceholder: searchPlaceholderFromProps, emptyText: emptyTextFromProps, emptySearchText: emptySearchTextFromProps, triggerDisplay, formatValue, maxBadges, renderOption, indicatorPosition, isDefaultOpen, 'data-testid': testId, htmlName, width, xstyle, className, style, }: MultiSelectorProps<T>): React.JSX.Element;
|
|
240
257
|
export declare namespace MultiSelector {
|
|
241
258
|
var displayName: string;
|
|
242
259
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiSelector.d.ts","sourceRoot":"","sources":["../../src/MultiSelector/MultiSelector.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"MultiSelector.d.ts","sourceRoot":"","sources":["../../src/MultiSelector/MultiSelector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -275,6 +275,8 @@ export function MultiSelector({
|
|
|
275
275
|
selectAllLabel: selectAllLabelFromProps,
|
|
276
276
|
hasSearch = false,
|
|
277
277
|
searchPlaceholder: searchPlaceholderFromProps,
|
|
278
|
+
emptyText: emptyTextFromProps,
|
|
279
|
+
emptySearchText: emptySearchTextFromProps,
|
|
278
280
|
triggerDisplay = 'count',
|
|
279
281
|
formatValue,
|
|
280
282
|
maxBadges = 3,
|
|
@@ -296,6 +298,8 @@ export function MultiSelector({
|
|
|
296
298
|
const placeholder = placeholderFromProps ?? t('@astryx.multiSelector.selectPlaceholder');
|
|
297
299
|
const selectAllLabel = selectAllLabelFromProps ?? t('@astryx.multiSelector.selectAll');
|
|
298
300
|
const searchPlaceholder = searchPlaceholderFromProps ?? t('@astryx.multiSelector.searchPlaceholder');
|
|
301
|
+
const emptyText = emptyTextFromProps ?? t('@astryx.multiSelector.empty');
|
|
302
|
+
const emptySearchText = emptySearchTextFromProps ?? t('@astryx.multiSelector.emptySearchResults');
|
|
299
303
|
const size = useSize(sizeProp, 'md');
|
|
300
304
|
const effectiveStatusVariant = variant === 'ghost' && statusVariant === 'attached' ? 'detached' : statusVariant;
|
|
301
305
|
const triggerId = useId();
|
|
@@ -348,6 +352,13 @@ export function MultiSelector({
|
|
|
348
352
|
// Announce selection-count changes politely (comboboxes-7 announce path).
|
|
349
353
|
// Toggling options / select-all previously produced no audible feedback.
|
|
350
354
|
const announce = useAnnounce();
|
|
355
|
+
|
|
356
|
+
// The panel's empty message is role="presentation" and reaches assistive tech
|
|
357
|
+
// only through this live region, so the region has to speak whatever the
|
|
358
|
+
// panel shows. A ReactNode override cannot be spoken; fall back to the
|
|
359
|
+
// catalog copy for that case rather than announcing nothing.
|
|
360
|
+
const emptyAnnouncement = typeof emptyText === 'string' ? emptyText : t('@astryx.multiSelector.empty');
|
|
361
|
+
const emptySearchAnnouncement = typeof emptySearchText === 'string' ? emptySearchText : t('@astryx.multiSelector.emptySearchResults');
|
|
351
362
|
const announceSelection = useCallback(nextValue => {
|
|
352
363
|
const total = selectableItems.length;
|
|
353
364
|
const selectableSet = new Set(selectableItems.map(item => item.value));
|
|
@@ -454,11 +465,38 @@ export function MultiSelector({
|
|
|
454
465
|
announce('');
|
|
455
466
|
return;
|
|
456
467
|
}
|
|
468
|
+
// While isLoading the panel deliberately shows nothing, so announcing a
|
|
469
|
+
// result would put a claim in the one channel the screen has gone quiet
|
|
470
|
+
// for.
|
|
471
|
+
if (isLoading) {
|
|
472
|
+
announce('');
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
457
475
|
const count = filterOptionsByQuery(selectableItems, nextQuery).length;
|
|
458
|
-
announce(count === 0 ?
|
|
476
|
+
announce(count === 0 ? emptySearchAnnouncement : t('@astryx.multiSelector.resultCount', {
|
|
459
477
|
count
|
|
460
478
|
}));
|
|
461
|
-
}, [announce, selectableItems, t]);
|
|
479
|
+
}, [announce, isLoading, selectableItems, emptySearchAnnouncement, t]);
|
|
480
|
+
|
|
481
|
+
// The panel's empty message is role="presentation", so this region is the
|
|
482
|
+
// only route to assistive tech. It has to watch the STATE rather than the
|
|
483
|
+
// open event: the panel can become empty either on open or when a fetch
|
|
484
|
+
// lands with nothing in it, and an open-only announcement leaves the second
|
|
485
|
+
// case silent while the message sits on screen. The ref makes it fire once
|
|
486
|
+
// per arrival at that state rather than on every re-render.
|
|
487
|
+
const announcedEmptyRef = useRef(null);
|
|
488
|
+
useEffect(() => {
|
|
489
|
+
const isPanelEmpty = popover.isOpen && !isLoading && searchQuery === '' && selectableItems.length === 0;
|
|
490
|
+
if (!isPanelEmpty) {
|
|
491
|
+
announcedEmptyRef.current = null;
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (announcedEmptyRef.current === emptyAnnouncement) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
announcedEmptyRef.current = emptyAnnouncement;
|
|
498
|
+
announce(emptyAnnouncement);
|
|
499
|
+
}, [popover.isOpen, isLoading, searchQuery, selectableItems.length, emptyAnnouncement, announce]);
|
|
462
500
|
|
|
463
501
|
// Handle toggle
|
|
464
502
|
// Clear all selected values. Shared by the clear button and the keyboard
|
|
@@ -800,13 +838,16 @@ export function MultiSelector({
|
|
|
800
838
|
// message out of the listbox's accessibility tree (role="listbox" only
|
|
801
839
|
// permits option/group children); the no-results outcome is announced
|
|
802
840
|
// via the result-count live region instead.
|
|
803
|
-
|
|
841
|
+
// While isLoading the options have not arrived yet, so asserting either
|
|
842
|
+
// message would be a claim the component cannot make; the trigger's
|
|
843
|
+
// spinner covers it.
|
|
844
|
+
if (realItemCount === 0 && !isLoading) {
|
|
804
845
|
elements.push(/*#__PURE__*/_jsx("div", {
|
|
805
846
|
role: "presentation",
|
|
806
847
|
...mergeProps(themeProps('multi-selector-empty-state'), {
|
|
807
848
|
className: "x1b2ylru x2b8uid xv1l7n4 x9ynric xcr08ib"
|
|
808
849
|
}),
|
|
809
|
-
children:
|
|
850
|
+
children: searchQuery ? emptySearchText : emptyText
|
|
810
851
|
}, "empty"));
|
|
811
852
|
return elements;
|
|
812
853
|
}
|
|
@@ -877,7 +918,7 @@ export function MultiSelector({
|
|
|
877
918
|
}
|
|
878
919
|
flushPending();
|
|
879
920
|
return elements;
|
|
880
|
-
}, [options, renderItem, sortedItems, searchQuery, hasSelectAll]);
|
|
921
|
+
}, [options, renderItem, sortedItems, searchQuery, hasSelectAll, isLoading, emptyText, emptySearchText]);
|
|
881
922
|
|
|
882
923
|
// The detached message box renders its own leading status icon, so the
|
|
883
924
|
// on-field icon would duplicate it — keep the chevron indicator instead.
|
|
@@ -189,6 +189,23 @@ interface SelectorPropsBase<T extends SelectorOptionType = SelectorOptionType> e
|
|
|
189
189
|
* @default 'Search...'
|
|
190
190
|
*/
|
|
191
191
|
searchPlaceholder?: string;
|
|
192
|
+
/**
|
|
193
|
+
* Content shown in the panel when there are no options to show, and
|
|
194
|
+
* announced in a polite live region when the panel opens. Not shown while
|
|
195
|
+
* `isLoading` — the options have not arrived yet.
|
|
196
|
+
* @default 'No options'
|
|
197
|
+
*/
|
|
198
|
+
emptyText?: ReactNode;
|
|
199
|
+
/**
|
|
200
|
+
* Content shown in the panel when a search query matches no options, and
|
|
201
|
+
* announced in a polite live region at the same time.
|
|
202
|
+
*
|
|
203
|
+
* The panel message is `role="presentation"`, so the live region is the only
|
|
204
|
+
* route to assistive tech: a string is announced verbatim, a richer node
|
|
205
|
+
* falls back to the default text since it cannot be spoken.
|
|
206
|
+
* @default 'No results found'
|
|
207
|
+
*/
|
|
208
|
+
emptySearchText?: ReactNode;
|
|
192
209
|
/**
|
|
193
210
|
* Position placement relative to the trigger.
|
|
194
211
|
*
|