@astryxdesign/lab 0.4.7-canary.94c2d8b → 0.4.7-canary.98ea5ba
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/CodeEditor/CodeEditor.d.ts +3 -0
- package/dist/CodeEditor/CodeEditor.d.ts.map +1 -1
- package/dist/CodeEditor/CodeEditor.js +11 -1
- package/dist/InfoTip/InfoTip.d.ts.map +1 -1
- package/dist/InfoTip/InfoTip.js +4 -26
- package/dist/Schedule/MonthlyView.d.ts.map +1 -1
- package/dist/Schedule/MonthlyView.js +6 -1
- package/dist/Schedule/plugins/PaginationPlugin.d.ts.map +1 -1
- package/dist/Schedule/plugins/PaginationPlugin.js +5 -2
- package/dist/Schedule/shared.d.ts +4 -1
- package/dist/Schedule/shared.d.ts.map +1 -1
- package/dist/Schedule/shared.js +15 -11
- package/package.json +3 -3
- package/src/CodeEditor/CodeEditor.test.tsx +36 -0
- package/src/CodeEditor/CodeEditor.tsx +9 -0
- package/src/InfoTip/InfoTip.tsx +6 -34
- package/src/Schedule/MonthlyView.tsx +14 -2
- package/src/Schedule/Schedule.test.tsx +27 -6
- package/src/Schedule/plugins/PaginationPlugin.tsx +19 -8
- package/src/Schedule/shared.tsx +16 -3
- package/src/__tests__/labApiContractDrift.test.tsx +0 -51
|
@@ -42,6 +42,9 @@ export interface CodeEditorProps extends Omit<BaseProps<HTMLDivElement>, 'onChan
|
|
|
42
42
|
* The escape is advertised to assistive technology via a visually hidden
|
|
43
43
|
* aria-describedby hint (see `escapeHint`).
|
|
44
44
|
*
|
|
45
|
+
* The editor carries an explicit tabindex="0" (including when read-only) so
|
|
46
|
+
* the scrollable container passes axe's scrollable-region-focusable check.
|
|
47
|
+
*
|
|
45
48
|
* @example
|
|
46
49
|
* ```
|
|
47
50
|
* const [code, setCode] = useState('');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeEditor.d.ts","sourceRoot":"","sources":["../../src/CodeEditor/CodeEditor.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAkBlD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,8BAA8B,CAAC;AAuF5D,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qCAAqC;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,+BAA+B;IAC/B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,uBAAuB;IACvB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;IAC5D;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsED
|
|
1
|
+
{"version":3,"file":"CodeEditor.d.ts","sourceRoot":"","sources":["../../src/CodeEditor/CodeEditor.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAkBlD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,8BAA8B,CAAC;AAuF5D,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qCAAqC;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,+BAA+B;IAC/B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,uBAAuB;IACvB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;IAC5D;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,QAAsB,EACtB,cAAsB,EACtB,UAAkB,EAClB,WAAW,EACX,SAAS,EACT,IAAW,EACX,SAAS,EAAE,eAAe,EAC1B,KAAK,EACL,UAAqE,EACrE,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,eAAe,+BA8UjB;yBA/Ve,UAAU"}
|
|
@@ -170,6 +170,9 @@ let editorInstanceCounter = 0;
|
|
|
170
170
|
* The escape is advertised to assistive technology via a visually hidden
|
|
171
171
|
* aria-describedby hint (see `escapeHint`).
|
|
172
172
|
*
|
|
173
|
+
* The editor carries an explicit tabindex="0" (including when read-only) so
|
|
174
|
+
* the scrollable container passes axe's scrollable-region-focusable check.
|
|
175
|
+
*
|
|
173
176
|
* @example
|
|
174
177
|
* ```
|
|
175
178
|
* const [code, setCode] = useState('');
|
|
@@ -472,7 +475,14 @@ export function CodeEditor({
|
|
|
472
475
|
ref: editorRef
|
|
473
476
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
474
477
|
,
|
|
475
|
-
contentEditable: isReadOnly ? false : 'plaintext-only'
|
|
478
|
+
contentEditable: isReadOnly ? false : 'plaintext-only'
|
|
479
|
+
// Explicit tabindex: editing hosts have an effective tabIndex of 0
|
|
480
|
+
// already, but axe reads the attribute, and contenteditable is not
|
|
481
|
+
// on its natively-focusable whitelist — without it a maxHeight
|
|
482
|
+
// editor fails scrollable-region-focusable. Also keeps read-only
|
|
483
|
+
// editors keyboard-focusable, like a readonly textarea.
|
|
484
|
+
,
|
|
485
|
+
tabIndex: 0,
|
|
476
486
|
role: "textbox",
|
|
477
487
|
"aria-multiline": "true",
|
|
478
488
|
"aria-label": label,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfoTip.d.ts","sourceRoot":"","sources":["../../src/InfoTip/InfoTip.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"InfoTip.d.ts","sourceRoot":"","sources":["../../src/InfoTip/InfoTip.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrC,OAAO,EAAO,KAAK,QAAQ,EAAC,MAAM,yBAAyB,CAAC;AAW5D;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;AAEnC,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,OAAO,EAAE,SAAS,CAAC;IACnB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AA8BD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,KAA0B,EAC1B,IAAW,GACZ,EAAE,YAAY,GAAG,SAAS,CAqB1B;yBAzBe,OAAO"}
|
package/dist/InfoTip/InfoTip.js
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
* - /packages/lab/src/InfoTip/InfoTip.test.tsx (tests for new/changed behavior)
|
|
14
14
|
* - /packages/lab/src/InfoTip/index.ts (exports if types change)
|
|
15
15
|
*/
|
|
16
|
-
import { useCallback, useRef, useState } from 'react';
|
|
17
16
|
import * as stylex from '@stylexjs/stylex';
|
|
18
17
|
import { Icon } from '@astryxdesign/core/Icon';
|
|
19
18
|
import { Tooltip } from '@astryxdesign/core/Tooltip';
|
|
@@ -69,26 +68,10 @@ export function InfoTip({
|
|
|
69
68
|
label = 'More information',
|
|
70
69
|
size = 'sm'
|
|
71
70
|
}) {
|
|
72
|
-
// Escape
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
const [isDismissed, setIsDismissed] = useState(false);
|
|
77
|
-
const isOpenRef = useRef(false);
|
|
78
|
-
const handleOpenChange = useCallback(isOpen => {
|
|
79
|
-
isOpenRef.current = isOpen;
|
|
80
|
-
}, []);
|
|
81
|
-
const handleKeyDown = useCallback(event => {
|
|
82
|
-
if (event.key === 'Escape' && isOpenRef.current) {
|
|
83
|
-
// Only swallow Escape when it actually dismissed the tooltip, so an
|
|
84
|
-
// enclosing dialog still closes on the next press.
|
|
85
|
-
event.stopPropagation();
|
|
86
|
-
setIsDismissed(true);
|
|
87
|
-
}
|
|
88
|
-
}, []);
|
|
89
|
-
const handleReset = useCallback(() => {
|
|
90
|
-
setIsDismissed(false);
|
|
91
|
-
}, []);
|
|
71
|
+
// No local Escape handler: the trigger used to stopPropagation the press,
|
|
72
|
+
// which hid the tip but left the browser's close watcher to fire `cancel` on
|
|
73
|
+
// an enclosing Dialog, so one press took both (#5168). Tooltip's own entry in
|
|
74
|
+
// the shared dismissal stack takes it instead.
|
|
92
75
|
return /*#__PURE__*/_jsx(Tooltip, {
|
|
93
76
|
content: content
|
|
94
77
|
// The trigger is a real button, so Tooltip's `auto` touch rule would
|
|
@@ -97,14 +80,9 @@ export function InfoTip({
|
|
|
97
80
|
// an InfoTip's content is unreachable on a phone.
|
|
98
81
|
,
|
|
99
82
|
touchTrigger: "tap",
|
|
100
|
-
isOpen: isDismissed ? false : undefined,
|
|
101
|
-
onOpenChange: handleOpenChange,
|
|
102
83
|
children: /*#__PURE__*/_jsx("button", {
|
|
103
84
|
type: "button",
|
|
104
85
|
"aria-label": label,
|
|
105
|
-
onKeyDown: handleKeyDown,
|
|
106
|
-
onBlur: handleReset,
|
|
107
|
-
onMouseLeave: handleReset,
|
|
108
86
|
...stylex.props(focusOutlineStyles.focusVisible, styles.trigger),
|
|
109
87
|
children: /*#__PURE__*/_jsx(Icon, {
|
|
110
88
|
icon: "info",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MonthlyView.d.ts","sourceRoot":"","sources":["../../src/Schedule/MonthlyView.tsx"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAEV,YAAY,EAEb,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,0BAA0B;IACzC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC1C;
|
|
1
|
+
{"version":3,"file":"MonthlyView.d.ts","sourceRoot":"","sources":["../../src/Schedule/MonthlyView.tsx"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAEV,YAAY,EAEb,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,0BAA0B;IACzC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC1C;AA4SD,wBAAgB,yBAAyB,CAAC,EACxC,YAAgB,GACjB,GAAE,0BAA+B,GAAG,YAAY,CAAC,0BAA0B,CAAC,CAmC5E"}
|
|
@@ -45,7 +45,12 @@ function ScheduleMonthlyView(_props) {
|
|
|
45
45
|
children: /*#__PURE__*/_jsxs("div", {
|
|
46
46
|
role: "grid",
|
|
47
47
|
"aria-label": formatMonthTitle(rangeDate, timezoneID),
|
|
48
|
-
"aria-readonly": true
|
|
48
|
+
"aria-readonly": true
|
|
49
|
+
// The grid scrolls horizontally at narrow viewports and contains no
|
|
50
|
+
// focusable descendants, so it must be focusable itself for keyboard
|
|
51
|
+
// scrolling (axe: scrollable-region-focusable).
|
|
52
|
+
,
|
|
53
|
+
tabIndex: 0,
|
|
49
54
|
...stylex.props(styles.monthGrid),
|
|
50
55
|
children: [/*#__PURE__*/_jsx("div", {
|
|
51
56
|
role: "row",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PaginationPlugin.d.ts","sourceRoot":"","sources":["../../../src/Schedule/plugins/PaginationPlugin.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PaginationPlugin.d.ts","sourceRoot":"","sources":["../../../src/Schedule/plugins/PaginationPlugin.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAEV,cAAc,EACd,sBAAsB,EACvB,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CACnC;AA4ED,eAAO,MAAM,+BAA+B,gBAAmC,CAAC;AAEhF,wBAAgB,2BAA2B,CAAC,EAC1C,QAAkB,GACnB,GAAE,+BAAoC,GAAG,cAAc,CAEvD"}
|
|
@@ -13,6 +13,7 @@ import { Button } from '@astryxdesign/core/Button';
|
|
|
13
13
|
import { ButtonGroup } from '@astryxdesign/core/ButtonGroup';
|
|
14
14
|
import { Icon } from '@astryxdesign/core/Icon';
|
|
15
15
|
import { IconButton } from '@astryxdesign/core/IconButton';
|
|
16
|
+
import { rtlStyles } from '@astryxdesign/core/utils';
|
|
16
17
|
import { useScheduleContext } from "../context.js";
|
|
17
18
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
18
19
|
function SchedulePaginationControls() {
|
|
@@ -31,7 +32,8 @@ function SchedulePaginationControls() {
|
|
|
31
32
|
icon: /*#__PURE__*/_jsx(Icon, {
|
|
32
33
|
icon: "chevronLeft",
|
|
33
34
|
size: "sm",
|
|
34
|
-
color: "inherit"
|
|
35
|
+
color: "inherit",
|
|
36
|
+
xstyle: rtlStyles.mirror
|
|
35
37
|
}),
|
|
36
38
|
onClick: onPreviousDate
|
|
37
39
|
}), /*#__PURE__*/_jsx(Button, {
|
|
@@ -43,7 +45,8 @@ function SchedulePaginationControls() {
|
|
|
43
45
|
icon: /*#__PURE__*/_jsx(Icon, {
|
|
44
46
|
icon: "chevronRight",
|
|
45
47
|
size: "sm",
|
|
46
|
-
color: "inherit"
|
|
48
|
+
color: "inherit",
|
|
49
|
+
xstyle: rtlStyles.mirror
|
|
47
50
|
}),
|
|
48
51
|
onClick: onNextDate
|
|
49
52
|
})]
|
|
@@ -693,7 +693,10 @@ export declare const styles: Readonly<{
|
|
|
693
693
|
readonly fontFamily: stylex.StyleXClassNameFor<"fontFamily", "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif">;
|
|
694
694
|
readonly color: stylex.StyleXClassNameFor<"color", "light-dark(#0A1317, #DFE2E5)">;
|
|
695
695
|
}>;
|
|
696
|
-
readonly
|
|
696
|
+
readonly listEventTitlePast: Readonly<{
|
|
697
|
+
readonly color: stylex.StyleXClassNameFor<"color", "light-dark(#4E606F, #AAAFB5)">;
|
|
698
|
+
}>;
|
|
699
|
+
readonly listEventDotPast: Readonly<{
|
|
697
700
|
readonly opacity: stylex.StyleXClassNameFor<"opacity", 0.5>;
|
|
698
701
|
}>;
|
|
699
702
|
readonly eventBlue: Readonly<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/Schedule/shared.tsx"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AACrC,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAa3C,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,OAAO,EACP,gBAAgB,EAEhB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAOjB,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,UAAU,EACV,SAAS,EACT,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,+BAgDA;AAED,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,UAAU,GACX,EAAE;IACD,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,+BAUA;AAED,wBAAgB,uBAAuB,CAAC,EACtC,KAAK,EACL,GAAG,EACH,UAAU,GACX,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,GAAG,EAAE,SAAS,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,+BAmBA;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,GAAG,EACH,UAAU,EACV,MAAc,GACf,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,+BA6BA;AAED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,UAAU,EACV,MAAc,GACf,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,+BA4BA;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,UAAU,EACV,MAAc,GACf,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,+
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/Schedule/shared.tsx"],"names":[],"mappings":"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"}
|
package/dist/Schedule/shared.js
CHANGED
|
@@ -211,16 +211,11 @@ export function ListEventRow({
|
|
|
211
211
|
const category = getEventCategory(event, categories);
|
|
212
212
|
return /*#__PURE__*/_jsxs("div", {
|
|
213
213
|
...{
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
},
|
|
217
|
-
1: {
|
|
218
|
-
className: "xrvj5dj x857yr4 x6s0dn4 x1txdalj xeuugli xbyyjgo"
|
|
219
|
-
}
|
|
220
|
-
}[!!isPast << 0],
|
|
214
|
+
className: "xrvj5dj x857yr4 x6s0dn4 x1txdalj xeuugli"
|
|
215
|
+
},
|
|
221
216
|
children: [/*#__PURE__*/_jsx("span", {
|
|
222
217
|
"aria-hidden": true,
|
|
223
|
-
...stylex.props(styles.listEventDot, eventDotColorStyle(category.color))
|
|
218
|
+
...stylex.props(styles.listEventDot, eventDotColorStyle(category.color), isPast && styles.listEventDotPast)
|
|
224
219
|
}), /*#__PURE__*/_jsx("span", {
|
|
225
220
|
...{
|
|
226
221
|
className: "x9ynric xv1l7n4 x141an7d x1ltkj2j xuxw1ft"
|
|
@@ -228,8 +223,13 @@ export function ListEventRow({
|
|
|
228
223
|
children: isDayEvent(event) ? 'All day' : formatEventTimeRange(event, timezoneID)
|
|
229
224
|
}), /*#__PURE__*/_jsx("span", {
|
|
230
225
|
...{
|
|
231
|
-
|
|
232
|
-
|
|
226
|
+
0: {
|
|
227
|
+
className: "x9ynric x1tgivj0 xeuugli xb3r6kr xlyipyv xuxw1ft xjm74w1 xw6l6zx x1e4wzip"
|
|
228
|
+
},
|
|
229
|
+
1: {
|
|
230
|
+
className: "x9ynric xeuugli xb3r6kr xlyipyv xuxw1ft xjm74w1 xw6l6zx x1e4wzip xv1l7n4"
|
|
231
|
+
}
|
|
232
|
+
}[!!isPast << 0],
|
|
233
233
|
children: event.title
|
|
234
234
|
})]
|
|
235
235
|
});
|
|
@@ -1064,7 +1064,11 @@ export const styles = {
|
|
|
1064
1064
|
k63SB2: "x1e4wzip",
|
|
1065
1065
|
$$css: true
|
|
1066
1066
|
},
|
|
1067
|
-
|
|
1067
|
+
listEventTitlePast: {
|
|
1068
|
+
kMwMTN: "xv1l7n4",
|
|
1069
|
+
$$css: true
|
|
1070
|
+
},
|
|
1071
|
+
listEventDotPast: {
|
|
1068
1072
|
kSiTet: "xbyyjgo",
|
|
1069
1073
|
$$css: true
|
|
1070
1074
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/lab",
|
|
3
|
-
"version": "0.4.7-canary.
|
|
3
|
+
"version": "0.4.7-canary.98ea5ba",
|
|
4
4
|
"description": "Experimental Astryx components — published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
|
|
5
5
|
"author": "Meta Open Source",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@stylexjs/stylex": ">=0.10.0",
|
|
48
|
-
"@astryxdesign/core": "0.4.7-canary.
|
|
48
|
+
"@astryxdesign/core": "0.4.7-canary.98ea5ba",
|
|
49
49
|
"react": ">=19.0.0",
|
|
50
50
|
"react-dom": ">=19.0.0"
|
|
51
51
|
},
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"d3-shape": "^3.2.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@astryxdesign/cli": "0.4.7-canary.
|
|
58
|
+
"@astryxdesign/cli": "0.4.7-canary.98ea5ba",
|
|
59
59
|
"@types/d3-array": "^3.2.2",
|
|
60
60
|
"@types/d3-scale": "^4.0.9",
|
|
61
61
|
"@types/d3-shape": "^3.1.8",
|
|
@@ -188,4 +188,40 @@ describe('CodeEditor', () => {
|
|
|
188
188
|
|
|
189
189
|
expect(onChange).toHaveBeenCalledWith(' a;\nb;');
|
|
190
190
|
});
|
|
191
|
+
|
|
192
|
+
it('exposes an explicit tabindex so scrollable editors count as focusable content', () => {
|
|
193
|
+
// contenteditable is not on axe's natively-focusable whitelist, and axe
|
|
194
|
+
// reads the tabindex ATTRIBUTE (not the browser's effective tabIndex),
|
|
195
|
+
// so the scrollable editorContainer only passes scrollable-region-focusable
|
|
196
|
+
// when the <code> editor materializes tabindex="0" explicitly.
|
|
197
|
+
render(
|
|
198
|
+
<CodeEditor
|
|
199
|
+
value={Array.from({length: 30}, (_, i) => `line ${i + 1};`).join('\n')}
|
|
200
|
+
onChange={() => {}}
|
|
201
|
+
language="typescript"
|
|
202
|
+
label="Edit snippet"
|
|
203
|
+
maxHeight={200}
|
|
204
|
+
/>,
|
|
205
|
+
);
|
|
206
|
+
expect(screen.getByRole('textbox', {name: 'Edit snippet'})).toHaveAttribute(
|
|
207
|
+
'tabindex',
|
|
208
|
+
'0',
|
|
209
|
+
);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('keeps read-only editors keyboard-focusable, like a readonly textarea', () => {
|
|
213
|
+
render(
|
|
214
|
+
<CodeEditor
|
|
215
|
+
value="const x = 1;"
|
|
216
|
+
onChange={() => {}}
|
|
217
|
+
language="typescript"
|
|
218
|
+
label="Edit snippet"
|
|
219
|
+
isReadOnly
|
|
220
|
+
/>,
|
|
221
|
+
);
|
|
222
|
+
expect(screen.getByRole('textbox', {name: 'Edit snippet'})).toHaveAttribute(
|
|
223
|
+
'tabindex',
|
|
224
|
+
'0',
|
|
225
|
+
);
|
|
226
|
+
});
|
|
191
227
|
});
|
|
@@ -242,6 +242,9 @@ let editorInstanceCounter = 0;
|
|
|
242
242
|
* The escape is advertised to assistive technology via a visually hidden
|
|
243
243
|
* aria-describedby hint (see `escapeHint`).
|
|
244
244
|
*
|
|
245
|
+
* The editor carries an explicit tabindex="0" (including when read-only) so
|
|
246
|
+
* the scrollable container passes axe's scrollable-region-focusable check.
|
|
247
|
+
*
|
|
245
248
|
* @example
|
|
246
249
|
* ```
|
|
247
250
|
* const [code, setCode] = useState('');
|
|
@@ -575,6 +578,12 @@ export function CodeEditor({
|
|
|
575
578
|
ref={editorRef}
|
|
576
579
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
577
580
|
contentEditable={isReadOnly ? false : ('plaintext-only' as any)}
|
|
581
|
+
// Explicit tabindex: editing hosts have an effective tabIndex of 0
|
|
582
|
+
// already, but axe reads the attribute, and contenteditable is not
|
|
583
|
+
// on its natively-focusable whitelist — without it a maxHeight
|
|
584
|
+
// editor fails scrollable-region-focusable. Also keeps read-only
|
|
585
|
+
// editors keyboard-focusable, like a readonly textarea.
|
|
586
|
+
tabIndex={0}
|
|
578
587
|
role="textbox"
|
|
579
588
|
aria-multiline="true"
|
|
580
589
|
aria-label={label}
|
package/src/InfoTip/InfoTip.tsx
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - /packages/lab/src/InfoTip/index.ts (exports if types change)
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import {type ReactNode} from 'react';
|
|
18
18
|
import * as stylex from '@stylexjs/stylex';
|
|
19
19
|
|
|
20
20
|
import {Icon, type IconSize} from '@astryxdesign/core/Icon';
|
|
@@ -103,33 +103,10 @@ export function InfoTip({
|
|
|
103
103
|
label = 'More information',
|
|
104
104
|
size = 'sm',
|
|
105
105
|
}: InfoTipProps): ReactNode {
|
|
106
|
-
// Escape
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
const [isDismissed, setIsDismissed] = useState(false);
|
|
111
|
-
const isOpenRef = useRef(false);
|
|
112
|
-
|
|
113
|
-
const handleOpenChange = useCallback((isOpen: boolean) => {
|
|
114
|
-
isOpenRef.current = isOpen;
|
|
115
|
-
}, []);
|
|
116
|
-
|
|
117
|
-
const handleKeyDown = useCallback(
|
|
118
|
-
(event: React.KeyboardEvent<HTMLButtonElement>) => {
|
|
119
|
-
if (event.key === 'Escape' && isOpenRef.current) {
|
|
120
|
-
// Only swallow Escape when it actually dismissed the tooltip, so an
|
|
121
|
-
// enclosing dialog still closes on the next press.
|
|
122
|
-
event.stopPropagation();
|
|
123
|
-
setIsDismissed(true);
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
[],
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
const handleReset = useCallback(() => {
|
|
130
|
-
setIsDismissed(false);
|
|
131
|
-
}, []);
|
|
132
|
-
|
|
106
|
+
// No local Escape handler: the trigger used to stopPropagation the press,
|
|
107
|
+
// which hid the tip but left the browser's close watcher to fire `cancel` on
|
|
108
|
+
// an enclosing Dialog, so one press took both (#5168). Tooltip's own entry in
|
|
109
|
+
// the shared dismissal stack takes it instead.
|
|
133
110
|
return (
|
|
134
111
|
<Tooltip
|
|
135
112
|
content={content}
|
|
@@ -137,15 +114,10 @@ export function InfoTip({
|
|
|
137
114
|
// give the tap to the control and suppress the tooltip. Here the tooltip
|
|
138
115
|
// IS the control's only purpose, so the tap has to open it — otherwise
|
|
139
116
|
// an InfoTip's content is unreachable on a phone.
|
|
140
|
-
touchTrigger="tap"
|
|
141
|
-
isOpen={isDismissed ? false : undefined}
|
|
142
|
-
onOpenChange={handleOpenChange}>
|
|
117
|
+
touchTrigger="tap">
|
|
143
118
|
<button
|
|
144
119
|
type="button"
|
|
145
120
|
aria-label={label}
|
|
146
|
-
onKeyDown={handleKeyDown}
|
|
147
|
-
onBlur={handleReset}
|
|
148
|
-
onMouseLeave={handleReset}
|
|
149
121
|
{...stylex.props(focusOutlineStyles.focusVisible, styles.trigger)}>
|
|
150
122
|
<Icon icon="info" size={size} />
|
|
151
123
|
</button>
|
|
@@ -57,8 +57,16 @@ export interface ScheduleMonthlyViewOptions {
|
|
|
57
57
|
function ScheduleMonthlyView(
|
|
58
58
|
_props: ScheduleViewComponentProps<ScheduleMonthlyViewOptions>,
|
|
59
59
|
) {
|
|
60
|
-
const {
|
|
61
|
-
|
|
60
|
+
const {
|
|
61
|
+
events,
|
|
62
|
+
categories,
|
|
63
|
+
date,
|
|
64
|
+
focusDate,
|
|
65
|
+
timezoneID,
|
|
66
|
+
range,
|
|
67
|
+
isLoading,
|
|
68
|
+
headingLevel,
|
|
69
|
+
} = useScheduleContext();
|
|
62
70
|
const rangeDate = date.toPlainDate();
|
|
63
71
|
const highlightedDate = focusDate.toPlainDate();
|
|
64
72
|
const currentTime = useCurrentTime();
|
|
@@ -76,6 +84,10 @@ function ScheduleMonthlyView(
|
|
|
76
84
|
role="grid"
|
|
77
85
|
aria-label={formatMonthTitle(rangeDate, timezoneID)}
|
|
78
86
|
aria-readonly
|
|
87
|
+
// The grid scrolls horizontally at narrow viewports and contains no
|
|
88
|
+
// focusable descendants, so it must be focusable itself for keyboard
|
|
89
|
+
// scrolling (axe: scrollable-region-focusable).
|
|
90
|
+
tabIndex={0}
|
|
79
91
|
{...stylex.props(styles.monthGrid)}>
|
|
80
92
|
<div role="row" {...stylex.props(styles.weekHeader)}>
|
|
81
93
|
{days.slice(0, 7).map((day, index) => (
|
|
@@ -114,9 +114,9 @@ describe('Schedule', () => {
|
|
|
114
114
|
await waitFor(() => {
|
|
115
115
|
expect(screen.getByText('Visible sync')).toBeInTheDocument();
|
|
116
116
|
});
|
|
117
|
-
expect(
|
|
118
|
-
|
|
119
|
-
)
|
|
117
|
+
expect(screen.getAllByRole('heading', {level: 3}).length).toBeGreaterThan(
|
|
118
|
+
0,
|
|
119
|
+
);
|
|
120
120
|
});
|
|
121
121
|
|
|
122
122
|
it('renders list day headings at the configured headingLevel (default 3)', async () => {
|
|
@@ -133,9 +133,9 @@ describe('Schedule', () => {
|
|
|
133
133
|
await waitFor(() => {
|
|
134
134
|
expect(screen.getByText('Visible sync')).toBeInTheDocument();
|
|
135
135
|
});
|
|
136
|
-
expect(
|
|
137
|
-
|
|
138
|
-
)
|
|
136
|
+
expect(screen.getAllByRole('heading', {level: 3}).length).toBeGreaterThan(
|
|
137
|
+
0,
|
|
138
|
+
);
|
|
139
139
|
});
|
|
140
140
|
|
|
141
141
|
it('loads async events with Instant range boundaries', async () => {
|
|
@@ -249,6 +249,27 @@ describe('Schedule', () => {
|
|
|
249
249
|
).toBeInTheDocument();
|
|
250
250
|
});
|
|
251
251
|
|
|
252
|
+
it('makes the scrollable monthly grid keyboard-focusable', () => {
|
|
253
|
+
// The month grid is a horizontal scroll container with no focusable
|
|
254
|
+
// descendants, so it needs tabindex="0" itself for
|
|
255
|
+
// scrollable-region-focusable to pass and for keyboard scrolling.
|
|
256
|
+
render(
|
|
257
|
+
<Schedule
|
|
258
|
+
view={createScheduleMonthlyView()}
|
|
259
|
+
events={events}
|
|
260
|
+
categories={categories}
|
|
261
|
+
date={Date.UTC(2026, 4, 13)}
|
|
262
|
+
focusDate={Date.UTC(2026, 4, 13)}
|
|
263
|
+
timezoneID="UTC"
|
|
264
|
+
/>,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
expect(screen.getByRole('grid', {name: 'May 2026'})).toHaveAttribute(
|
|
268
|
+
'tabindex',
|
|
269
|
+
'0',
|
|
270
|
+
);
|
|
271
|
+
});
|
|
272
|
+
|
|
252
273
|
it('exposes time grid views as ARIA grids', () => {
|
|
253
274
|
render(
|
|
254
275
|
<Schedule
|
|
@@ -14,6 +14,7 @@ import {Button} from '@astryxdesign/core/Button';
|
|
|
14
14
|
import {ButtonGroup} from '@astryxdesign/core/ButtonGroup';
|
|
15
15
|
import {Icon} from '@astryxdesign/core/Icon';
|
|
16
16
|
import {IconButton} from '@astryxdesign/core/IconButton';
|
|
17
|
+
import {rtlStyles} from '@astryxdesign/core/utils';
|
|
17
18
|
import {useScheduleContext} from '../context';
|
|
18
19
|
import type {
|
|
19
20
|
ScheduleHeaderContent,
|
|
@@ -37,13 +38,27 @@ function SchedulePaginationControls() {
|
|
|
37
38
|
<ButtonGroup label="Schedule pagination" size="sm">
|
|
38
39
|
<IconButton
|
|
39
40
|
label={previousDateLabel}
|
|
40
|
-
icon={
|
|
41
|
+
icon={
|
|
42
|
+
<Icon
|
|
43
|
+
icon="chevronLeft"
|
|
44
|
+
size="sm"
|
|
45
|
+
color="inherit"
|
|
46
|
+
xstyle={rtlStyles.mirror}
|
|
47
|
+
/>
|
|
48
|
+
}
|
|
41
49
|
onClick={onPreviousDate}
|
|
42
50
|
/>
|
|
43
51
|
<Button label="Today" size="sm" onClick={onToday} />
|
|
44
52
|
<IconButton
|
|
45
53
|
label={nextDateLabel}
|
|
46
|
-
icon={
|
|
54
|
+
icon={
|
|
55
|
+
<Icon
|
|
56
|
+
icon="chevronRight"
|
|
57
|
+
size="sm"
|
|
58
|
+
color="inherit"
|
|
59
|
+
xstyle={rtlStyles.mirror}
|
|
60
|
+
/>
|
|
61
|
+
}
|
|
47
62
|
onClick={onNextDate}
|
|
48
63
|
/>
|
|
49
64
|
</ButtonGroup>
|
|
@@ -85,14 +100,10 @@ function createSchedulePaginationPlugin({
|
|
|
85
100
|
};
|
|
86
101
|
}
|
|
87
102
|
|
|
88
|
-
export const defaultSchedulePaginationPlugin =
|
|
89
|
-
createSchedulePaginationPlugin();
|
|
103
|
+
export const defaultSchedulePaginationPlugin = createSchedulePaginationPlugin();
|
|
90
104
|
|
|
91
105
|
export function useSchedulePaginationPlugin({
|
|
92
106
|
position = 'start',
|
|
93
107
|
}: SchedulePaginationPluginOptions = {}): SchedulePlugin {
|
|
94
|
-
return useMemo(
|
|
95
|
-
() => createSchedulePaginationPlugin({position}),
|
|
96
|
-
[position],
|
|
97
|
-
);
|
|
108
|
+
return useMemo(() => createSchedulePaginationPlugin({position}), [position]);
|
|
98
109
|
}
|
package/src/Schedule/shared.tsx
CHANGED
|
@@ -244,12 +244,13 @@ export function ListEventRow({
|
|
|
244
244
|
const {categories} = useScheduleContext();
|
|
245
245
|
const category = getEventCategory(event, categories);
|
|
246
246
|
return (
|
|
247
|
-
<div {...stylex.props(styles.listEventRow
|
|
247
|
+
<div {...stylex.props(styles.listEventRow)}>
|
|
248
248
|
<span
|
|
249
249
|
aria-hidden
|
|
250
250
|
{...stylex.props(
|
|
251
251
|
styles.listEventDot,
|
|
252
252
|
eventDotColorStyle(category.color),
|
|
253
|
+
isPast && styles.listEventDotPast,
|
|
253
254
|
)}
|
|
254
255
|
/>
|
|
255
256
|
<span {...stylex.props(styles.listEventTime)}>
|
|
@@ -257,7 +258,13 @@ export function ListEventRow({
|
|
|
257
258
|
? 'All day'
|
|
258
259
|
: formatEventTimeRange(event, timezoneID)}
|
|
259
260
|
</span>
|
|
260
|
-
<span
|
|
261
|
+
<span
|
|
262
|
+
{...stylex.props(
|
|
263
|
+
styles.listEventTitle,
|
|
264
|
+
isPast && styles.listEventTitlePast,
|
|
265
|
+
)}>
|
|
266
|
+
{event.title}
|
|
267
|
+
</span>
|
|
261
268
|
</div>
|
|
262
269
|
);
|
|
263
270
|
}
|
|
@@ -1072,7 +1079,13 @@ export const styles = stylex.create({
|
|
|
1072
1079
|
lineHeight: typeScaleVars['--text-body-leading'],
|
|
1073
1080
|
fontWeight: fontWeightVars['--font-weight-medium'],
|
|
1074
1081
|
},
|
|
1075
|
-
|
|
1082
|
+
// A past row is muted with the secondary text token, which the theme
|
|
1083
|
+
// guarantees at AA. Fading the whole row with opacity instead pulled its
|
|
1084
|
+
// text toward the surface behind it — 2.35:1 on the light theme.
|
|
1085
|
+
listEventTitlePast: {
|
|
1086
|
+
color: colorVars['--color-text-secondary'],
|
|
1087
|
+
},
|
|
1088
|
+
listEventDotPast: {
|
|
1076
1089
|
opacity: 0.5,
|
|
1077
1090
|
},
|
|
1078
1091
|
eventBlue: {
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
import {describe, it, expect} from 'vitest';
|
|
4
|
-
|
|
5
|
-
import {docs as ChatReasoningDocs} from '../ChatReasoning/ChatReasoning.doc.mjs';
|
|
6
|
-
import {docs as CodeEditorDocs} from '../CodeEditor/CodeEditor.doc.mjs';
|
|
7
|
-
import {docs as LogStreamDocs} from '../LogStream/LogStream.doc.mjs';
|
|
8
|
-
|
|
9
|
-
function getProps(docs: Record<string, unknown>): Array<{name: string}> {
|
|
10
|
-
return (
|
|
11
|
-
(docs.props as Array<{name: string}>) ||
|
|
12
|
-
(
|
|
13
|
-
docs.components as Array<{
|
|
14
|
-
props: Array<{name: string}>;
|
|
15
|
-
}>
|
|
16
|
-
)?.[0]?.props ||
|
|
17
|
-
[]
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
describe('Lab API Contract Drift (#4163)', () => {
|
|
22
|
-
it('documents ChatReasoning props', () => {
|
|
23
|
-
const props = getProps(ChatReasoningDocs).map(p => p.name);
|
|
24
|
-
expect(props).toContain('duration');
|
|
25
|
-
expect(props).toContain('isStreaming');
|
|
26
|
-
expect(props).toContain('isExpanded');
|
|
27
|
-
expect(props).toContain('defaultIsExpanded');
|
|
28
|
-
expect(props).toContain('onExpandedChange');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('documents CodeEditor props', () => {
|
|
32
|
-
const props = getProps(CodeEditorDocs).map(p => p.name);
|
|
33
|
-
expect(props).toContain('language');
|
|
34
|
-
expect(props).toContain('hasLineNumbers');
|
|
35
|
-
expect(props).toContain('isReadOnly');
|
|
36
|
-
expect(props).toContain('placeholder');
|
|
37
|
-
expect(props).toContain('maxHeight');
|
|
38
|
-
expect(props).toContain('size');
|
|
39
|
-
expect(props).toContain('tokenizer');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('documents LogStream props', () => {
|
|
43
|
-
const props = getProps(LogStreamDocs).map(p => p.name);
|
|
44
|
-
expect(props).toContain('variant');
|
|
45
|
-
expect(props).toContain('isFollowing');
|
|
46
|
-
expect(props).toContain('onFollowChange');
|
|
47
|
-
expect(props).toContain('maxHeight');
|
|
48
|
-
expect(props).toContain('hasTimestamps');
|
|
49
|
-
expect(props).toContain('renderEntry');
|
|
50
|
-
});
|
|
51
|
-
});
|