@astryxdesign/core 0.7.1-canary.df75749 → 0.7.1-canary.e71c4e9
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/CommandPalette/CommandPalette.d.ts +6 -4
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +38 -20
- package/dist/CommandPalette/CommandPaletteEmpty.d.ts +4 -3
- package/dist/CommandPalette/CommandPaletteEmpty.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteEmpty.js +4 -3
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +11 -5
- package/dist/CommandPalette/CommandPaletteList.d.ts +4 -2
- package/dist/CommandPalette/CommandPaletteList.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteList.js +9 -4
- package/dist/ContextMenu/ContextMenu.d.ts +3 -3
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +62 -48
- package/dist/Layer/useLayerDismissal.d.ts +9 -9
- package/dist/Layer/useLayerDismissal.js +9 -9
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +14 -5
- package/locales/en.json +1 -1
- package/package.json +3 -3
- package/src/CommandPalette/CommandPalette.doc.mjs +31 -1
- package/src/CommandPalette/CommandPalette.spec.md +95 -46
- package/src/CommandPalette/CommandPalette.test.tsx +241 -2
- package/src/CommandPalette/CommandPalette.tsx +44 -20
- package/src/CommandPalette/CommandPaletteEmpty.tsx +4 -3
- package/src/CommandPalette/CommandPaletteInput.spec.md +7 -4
- package/src/CommandPalette/CommandPaletteInput.test.tsx +63 -2
- package/src/CommandPalette/CommandPaletteInput.tsx +15 -5
- package/src/CommandPalette/CommandPaletteItem.test.tsx +7 -0
- package/src/CommandPalette/CommandPaletteList.doc.mjs +3 -3
- package/src/CommandPalette/CommandPaletteList.spec.md +41 -36
- package/src/CommandPalette/CommandPaletteList.test.tsx +67 -0
- package/src/CommandPalette/CommandPaletteList.tsx +9 -4
- package/src/CommandPalette/__tests__/CommandPalette.a11y.chromium.spec.ts +599 -0
- package/src/ContextMenu/ContextMenu.doc.mjs +6 -0
- package/src/ContextMenu/ContextMenu.spec.md +51 -53
- package/src/ContextMenu/ContextMenu.test.tsx +132 -1
- package/src/ContextMenu/ContextMenu.tsx +78 -48
- package/src/Layer/useLayerDismissal.ts +9 -9
- package/src/utils/plainDate.test.ts +99 -0
- package/src/utils/plainDate.ts +23 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file CommandPalette.tsx
|
|
3
|
-
* @input Uses React, Dialog, Layout, CommandPaletteContext, SearchSource,
|
|
3
|
+
* @input Uses React, Dialog, Layout, CommandPaletteContext, SearchSource,
|
|
4
|
+
* useCombobox, useAnnounce, useAnnounceRenderedText
|
|
4
5
|
* @output Exports CommandPalette root component and props
|
|
5
6
|
* @position Core root component; dialog shell with searchSource-driven items
|
|
6
7
|
*
|
|
@@ -84,9 +85,10 @@ export interface CommandPaletteProps<T extends SearchableItem = SearchableItem>
|
|
|
84
85
|
* Uses `searchSource` for all search logic — same interface as Typeahead.
|
|
85
86
|
* For static lists, use `createStaticSource` from `@astryxdesign/core/Typeahead`.
|
|
86
87
|
*
|
|
87
|
-
* Keyboard navigation is handled by `useCombobox` from Selector,
|
|
88
|
-
*
|
|
89
|
-
*
|
|
88
|
+
* Keyboard navigation is handled by `useCombobox` from Selector for arrows,
|
|
89
|
+
* PageUp/PageDown, and Enter. Home/End remain native caret keys. Modal Escape
|
|
90
|
+
* dismissal delegates to Dialog's shared layer stack so nested surfaces handle
|
|
91
|
+
* the first press.
|
|
90
92
|
*
|
|
91
93
|
* Input and footer are rendered by default — only pass them to replace the defaults.
|
|
92
94
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandPalette.d.ts","sourceRoot":"","sources":["../../src/CommandPalette/CommandPalette.tsx"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"CommandPalette.d.ts","sourceRoot":"","sources":["../../src/CommandPalette/CommandPalette.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AAEH,OAAO,EASL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAC,YAAY,EAAE,cAAc,EAAC,MAAM,cAAc,CAAC;AAU/D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAK5C,MAAM,WAAW,mBAAmB,CAClC,CAAC,SAAS,cAAc,GAAG,cAAc,CACzC,SAAQ,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,EAAE,UAAU,CAAC;IACtD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC,2CAA2C;IAC3C,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,0DAA0D;IAC1D,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAExC;;;;OAIG;IACH,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAE9B;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,OAAO,KAAK,SAAS,CAAC;IAEzD;;;OAGG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC;IAE5B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,CAAC;IAE/B,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,8CAA8C;IAC9C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAExB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AAiID;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EAAE,EACxE,GAAG,EACH,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,KAAK,EACL,MAAM,EACN,UAAU,EACV,eAAe,EAAE,wBAAwB,EACzC,kBAAkB,EAAE,2BAA2B,EAC/C,KAAK,EAAE,eAAe,EACtB,aAAa,EACb,KAAK,EAAE,cAAc,EACrB,KAAW,EACX,SAAe,EACf,GAAG,IAAI,EACR,EAAE,mBAAmB,CAAC,CAAC,CAAC,+BA2YxB;yBA5Ze,cAAc"}
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file CommandPalette.tsx
|
|
7
|
-
* @input Uses React, Dialog, Layout, CommandPaletteContext, SearchSource,
|
|
7
|
+
* @input Uses React, Dialog, Layout, CommandPaletteContext, SearchSource,
|
|
8
|
+
* useCombobox, useAnnounce, useAnnounceRenderedText
|
|
8
9
|
* @output Exports CommandPalette root component and props
|
|
9
10
|
* @position Core root component; dialog shell with searchSource-driven items
|
|
10
11
|
*
|
|
@@ -24,6 +25,7 @@ import { CommandPaletteInput } from "./CommandPaletteInput.js";
|
|
|
24
25
|
import { CommandPaletteFooter } from "./CommandPaletteFooter.js";
|
|
25
26
|
import { CommandPaletteEmpty } from "./CommandPaletteEmpty.js";
|
|
26
27
|
import { useAnnounce } from "../hooks/useAnnounce.js";
|
|
28
|
+
import { useAnnounceRenderedText } from "../hooks/useAnnounceRenderedText.js";
|
|
27
29
|
import { useTranslator } from "../i18n/index.js";
|
|
28
30
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
29
31
|
function getGroup(item) {
|
|
@@ -145,9 +147,10 @@ function ItemRenderer({
|
|
|
145
147
|
* Uses `searchSource` for all search logic — same interface as Typeahead.
|
|
146
148
|
* For static lists, use `createStaticSource` from `@astryxdesign/core/Typeahead`.
|
|
147
149
|
*
|
|
148
|
-
* Keyboard navigation is handled by `useCombobox` from Selector,
|
|
149
|
-
*
|
|
150
|
-
*
|
|
150
|
+
* Keyboard navigation is handled by `useCombobox` from Selector for arrows,
|
|
151
|
+
* PageUp/PageDown, and Enter. Home/End remain native caret keys. Modal Escape
|
|
152
|
+
* dismissal delegates to Dialog's shared layer stack so nested surfaces handle
|
|
153
|
+
* the first press.
|
|
151
154
|
*
|
|
152
155
|
* Input and footer are rendered by default — only pass them to replace the defaults.
|
|
153
156
|
*
|
|
@@ -200,6 +203,7 @@ export function CommandPalette({
|
|
|
200
203
|
const [optimisticResults, setOptimisticResults] = useOptimistic(searchResults);
|
|
201
204
|
const isBusy = isPending;
|
|
202
205
|
const searchVersionRef = useRef(0);
|
|
206
|
+
const emptyStateRef = useRef(null);
|
|
203
207
|
|
|
204
208
|
// Announce search status to screen readers through the shared polite live
|
|
205
209
|
// region (comboboxes-7 announce path, mirroring Selector / BaseTypeahead).
|
|
@@ -267,6 +271,10 @@ export function CommandPalette({
|
|
|
267
271
|
const runSearch = useCallback(query => {
|
|
268
272
|
searchSource.cancel?.();
|
|
269
273
|
const version = ++searchVersionRef.current;
|
|
274
|
+
// A highlight belongs to the query that created it. Clear it before any
|
|
275
|
+
// optimistic narrowing so aria-activedescendant never shifts to a
|
|
276
|
+
// different command at the same index while the next result set loads.
|
|
277
|
+
combobox.setHighlightedIndex(-1);
|
|
270
278
|
startTransition(async () => {
|
|
271
279
|
const isBootstrap = query === '';
|
|
272
280
|
|
|
@@ -293,18 +301,12 @@ export function CommandPalette({
|
|
|
293
301
|
|
|
294
302
|
// Announce the outcome from the search commit (not a reactive
|
|
295
303
|
// effect), matching Selector / BaseTypeahead: exactly one
|
|
296
|
-
// announcement per committed query
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
// palette announces nothing; clearing the query only clears any
|
|
300
|
-
// lingering status text.
|
|
304
|
+
// announcement per committed non-empty query. Empty results are
|
|
305
|
+
// announced from their rendered content below so a caller-supplied
|
|
306
|
+
// ReactNode reaches assistive technology as written.
|
|
301
307
|
if (isBootstrap) {
|
|
302
308
|
announce('');
|
|
303
|
-
} else if (items.length
|
|
304
|
-
announce(t('@astryx.commandPalette.noResultsFor', {
|
|
305
|
-
query
|
|
306
|
-
}));
|
|
307
|
-
} else {
|
|
309
|
+
} else if (items.length > 0) {
|
|
308
310
|
announce(t('@astryx.commandPalette.resultCount', {
|
|
309
311
|
count: items.length
|
|
310
312
|
}));
|
|
@@ -346,13 +348,18 @@ export function CommandPalette({
|
|
|
346
348
|
}
|
|
347
349
|
}, [isOpen]);
|
|
348
350
|
|
|
349
|
-
// Wrap combobox's onKeyDown to
|
|
350
|
-
//
|
|
351
|
-
//
|
|
351
|
+
// Wrap combobox's onKeyDown to preserve inline-preview Escape handling and
|
|
352
|
+
// select + close on Enter. Modal Escape stays unclaimed here so Dialog's
|
|
353
|
+
// shared dismissal stack can route it to the topmost surface.
|
|
352
354
|
const handleKeyDown = useCallback(e => {
|
|
353
355
|
if (e.key === 'Escape') {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
+
// Modal CommandPalette delegates Escape to Dialog's shared dismissal
|
|
357
|
+
// stack so a nested layer handles the first press. Inline previews do
|
|
358
|
+
// not join that stack, so preserve their local close behavior.
|
|
359
|
+
if (isInline) {
|
|
360
|
+
e.preventDefault();
|
|
361
|
+
handleClose();
|
|
362
|
+
}
|
|
356
363
|
return;
|
|
357
364
|
}
|
|
358
365
|
if (e.key === 'Enter') {
|
|
@@ -366,12 +373,17 @@ export function CommandPalette({
|
|
|
366
373
|
}
|
|
367
374
|
return;
|
|
368
375
|
}
|
|
376
|
+
// Home and End remain native caret-movement keys for this editable
|
|
377
|
+
// combobox. PageUp/PageDown provide first/last result navigation.
|
|
378
|
+
if (e.key === 'Home' || e.key === 'End') {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
369
381
|
// Space should type in the input, not trigger selection
|
|
370
382
|
if (e.key === ' ') {
|
|
371
383
|
return;
|
|
372
384
|
}
|
|
373
385
|
combobox.onKeyDown(e);
|
|
374
|
-
}, [combobox, handleClose, selectableItems, selectItem]);
|
|
386
|
+
}, [combobox, handleClose, isInline, selectableItems, selectItem]);
|
|
375
387
|
|
|
376
388
|
// Hover highlight is owned here by a single delegated handler on the list
|
|
377
389
|
// container: it routes to useCombobox's hover-aware path, which moves the
|
|
@@ -427,13 +439,19 @@ export function CommandPalette({
|
|
|
427
439
|
// the empty state is never unmounted and re-added mid-search (which flashed).
|
|
428
440
|
const showEmptyBootstrap = search === '' && optimisticResults.length === 0;
|
|
429
441
|
const showEmptySearch = search !== '' && optimisticResults.length === 0;
|
|
442
|
+
// Announce only once the search settles: while it is pending, optimistic
|
|
443
|
+
// narrowing can empty the list before the source answers, which would
|
|
444
|
+
// speak "No results" early or wrongly.
|
|
445
|
+
useAnnounceRenderedText(emptyStateRef, showEmptySearch && !isPending, search);
|
|
430
446
|
let listContent;
|
|
431
447
|
if (showEmptyBootstrap) {
|
|
432
448
|
listContent = /*#__PURE__*/_jsx(CommandPaletteEmpty, {
|
|
449
|
+
ref: emptyStateRef,
|
|
433
450
|
children: emptyBootstrapText
|
|
434
451
|
});
|
|
435
452
|
} else if (showEmptySearch) {
|
|
436
453
|
listContent = /*#__PURE__*/_jsx(CommandPaletteEmpty, {
|
|
454
|
+
ref: emptyStateRef,
|
|
437
455
|
children: emptySearchText
|
|
438
456
|
});
|
|
439
457
|
} else {
|
|
@@ -12,13 +12,14 @@ export interface CommandPaletteEmptyProps extends BaseProps<HTMLDivElement> {
|
|
|
12
12
|
* - `emptyBootstrapText`: no search term and bootstrap() returns nothing
|
|
13
13
|
* - `emptySearchText`: a search query returned no results
|
|
14
14
|
*
|
|
15
|
-
* Can also be composed
|
|
15
|
+
* Can also be composed as a standalone empty result surface. Render actionable
|
|
16
|
+
* empty content outside listbox and option semantics.
|
|
16
17
|
*
|
|
17
18
|
* @example
|
|
18
19
|
* ```
|
|
19
20
|
* <CommandPalette
|
|
20
|
-
* emptyBootstrapText=
|
|
21
|
-
* emptySearchText=
|
|
21
|
+
* emptyBootstrapText="Start typing to search"
|
|
22
|
+
* emptySearchText="No results found"
|
|
22
23
|
* searchSource={source}
|
|
23
24
|
* />
|
|
24
25
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandPaletteEmpty.d.ts","sourceRoot":"","sources":["../../src/CommandPalette/CommandPaletteEmpty.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,EAAC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAS5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAkB5C,MAAM,WAAW,wBAAyB,SAAQ,SAAS,CAAC,cAAc,CAAC;IACzE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,yCAAyC;IACzC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED
|
|
1
|
+
{"version":3,"file":"CommandPaletteEmpty.d.ts","sourceRoot":"","sources":["../../src/CommandPalette/CommandPaletteEmpty.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,EAAC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAS5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAkB5C,MAAM,WAAW,wBAAyB,SAAQ,SAAS,CAAC,cAAc,CAAC;IACzE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,yCAAyC;IACzC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,GAAG,EACH,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,wBAAwB,qBAc1B;yBArBe,mBAAmB"}
|
|
@@ -41,13 +41,14 @@ const styles = {
|
|
|
41
41
|
* - `emptyBootstrapText`: no search term and bootstrap() returns nothing
|
|
42
42
|
* - `emptySearchText`: a search query returned no results
|
|
43
43
|
*
|
|
44
|
-
* Can also be composed
|
|
44
|
+
* Can also be composed as a standalone empty result surface. Render actionable
|
|
45
|
+
* empty content outside listbox and option semantics.
|
|
45
46
|
*
|
|
46
47
|
* @example
|
|
47
48
|
* ```
|
|
48
49
|
* <CommandPalette
|
|
49
|
-
* emptyBootstrapText=
|
|
50
|
-
* emptySearchText=
|
|
50
|
+
* emptyBootstrapText="Start typing to search"
|
|
51
|
+
* emptySearchText="No results found"
|
|
51
52
|
* searchSource={source}
|
|
52
53
|
* />
|
|
53
54
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandPaletteInput.d.ts","sourceRoot":"","sources":["../../src/CommandPalette/CommandPaletteInput.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAarE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAkE5C,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,SAAS,CAAC,gBAAgB,CAAC,EAC3B,UAAU,CACX;IACC,iEAAiE;IACjE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAElC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,KAAK,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EAAE,eAAe,EACtB,aAAa,EACb,WAAW,EAAE,oBAAoB,EACjC,KAAK,EACL,YAAmB,EACnB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,GAAG,EACH,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,wBAAwB,+
|
|
1
|
+
{"version":3,"file":"CommandPaletteInput.d.ts","sourceRoot":"","sources":["../../src/CommandPalette/CommandPaletteInput.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAarE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAkE5C,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,SAAS,CAAC,gBAAgB,CAAC,EAC3B,UAAU,CACX;IACC,iEAAiE;IACjE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAElC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,KAAK,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EAAE,eAAe,EACtB,aAAa,EACb,WAAW,EAAE,oBAAoB,EACjC,KAAK,EACL,YAAmB,EACnB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,GAAG,EACH,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,wBAAwB,+BA2I1B;yBAzJe,mBAAmB"}
|
|
@@ -17,7 +17,7 @@ import { useCallback, useEffect, useRef } from 'react';
|
|
|
17
17
|
import * as stylex from '@stylexjs/stylex';
|
|
18
18
|
import { Icon } from "../Icon/index.js";
|
|
19
19
|
import { Spinner } from "../Spinner/index.js";
|
|
20
|
-
import { isRenderable, mergeProps } from "../utils/index.js";
|
|
20
|
+
import { isImeKeyEvent, isRenderable, mergeProps } from "../utils/index.js";
|
|
21
21
|
import "../theme/tokens.stylex.js";
|
|
22
22
|
import { colorVars, typeScaleVars, spacingVars, typographyVars } from "../theme/tokens.stylex.js";
|
|
23
23
|
import { useCommandPaletteContext } from "./CommandPaletteContext.js";
|
|
@@ -74,6 +74,9 @@ export function CommandPaletteInput({
|
|
|
74
74
|
const t = useTranslator();
|
|
75
75
|
const placeholder = placeholderFromProps ?? t('@astryx.commandPalette.input.placeholder');
|
|
76
76
|
const ctx = useCommandPaletteContext();
|
|
77
|
+
// Inside CommandPalette the results surface is a listbox only while it holds
|
|
78
|
+
// selectable results; empty and pending states expose no popup.
|
|
79
|
+
const hasListbox = ctx ? ctx.selectableItems.length > 0 : true;
|
|
77
80
|
const dialogContext = useDialogContext();
|
|
78
81
|
const inputRef = useRef(null);
|
|
79
82
|
|
|
@@ -108,7 +111,10 @@ export function CommandPaletteInput({
|
|
|
108
111
|
// Keyboard navigation — delegates to useCombobox via context
|
|
109
112
|
const handleKeyDown = useCallback(e => {
|
|
110
113
|
onKeyDown?.(e);
|
|
111
|
-
if (e.defaultPrevented) {
|
|
114
|
+
if (e.defaultPrevented || isImeKeyEvent(e.nativeEvent)) {
|
|
115
|
+
// An in-progress IME composition owns Enter, Escape, and arrows. Let
|
|
116
|
+
// the input method finish or cancel composition without selecting or
|
|
117
|
+
// dismissing palette content.
|
|
112
118
|
return;
|
|
113
119
|
}
|
|
114
120
|
// Delegate to useCombobox's keyboard handler from context
|
|
@@ -133,10 +139,10 @@ export function CommandPaletteInput({
|
|
|
133
139
|
},
|
|
134
140
|
type: "text",
|
|
135
141
|
role: ctx ? 'combobox' : standaloneRole,
|
|
136
|
-
"aria-expanded": ctx ? ctx.isOpen : callerSets('aria-expanded') ? props['aria-expanded'] : callerOwnsPopup || undefined,
|
|
142
|
+
"aria-expanded": ctx ? ctx.isOpen && hasListbox : callerSets('aria-expanded') ? props['aria-expanded'] : callerOwnsPopup || undefined,
|
|
137
143
|
"aria-autocomplete": ctx ? 'list' : callerSets('aria-autocomplete') ? props['aria-autocomplete'] : callerOwnsPopup ? 'list' : undefined,
|
|
138
|
-
"aria-controls": ctx ? ctx.listId : props['aria-controls'],
|
|
139
|
-
"aria-activedescendant": ctx ? ctx.highlightedIndex >= 0 ? ctx.getItemId(ctx.highlightedIndex) : undefined : props['aria-activedescendant']
|
|
144
|
+
"aria-controls": ctx ? hasListbox ? ctx.listId : undefined : props['aria-controls'],
|
|
145
|
+
"aria-activedescendant": ctx ? hasListbox && ctx.highlightedIndex >= 0 && ctx.highlightedIndex < ctx.selectableItems.length ? ctx.getItemId(ctx.highlightedIndex) : undefined : props['aria-activedescendant']
|
|
140
146
|
// Placeholder text is never the field's name (AST-056 AR2).
|
|
141
147
|
,
|
|
142
148
|
"aria-label": accessibleLabel,
|
|
@@ -16,8 +16,10 @@ export interface CommandPaletteListProps extends BaseProps<HTMLDivElement> {
|
|
|
16
16
|
label?: string;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* Scrollable results container for the command palette.
|
|
20
|
-
*
|
|
19
|
+
* Scrollable results container for the command palette. Standalone composition
|
|
20
|
+
* renders as a listbox. Inside CommandPalette, listbox semantics are present
|
|
21
|
+
* only while selectable results exist; empty and pending states retain the same
|
|
22
|
+
* styled container without exposing an empty interactive popup.
|
|
21
23
|
*
|
|
22
24
|
* When used inside CommandPalette, automatically gets the correct
|
|
23
25
|
* ID for aria-controls linking with the input.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandPaletteList.d.ts","sourceRoot":"","sources":["../../src/CommandPalette/CommandPaletteList.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAErC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAmB5C,MAAM,WAAW,uBAAwB,SAAQ,SAAS,CAAC,cAAc,CAAC;IACxE;;OAEG;IACH,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAEhC;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED
|
|
1
|
+
{"version":3,"file":"CommandPaletteList.d.ts","sourceRoot":"","sources":["../../src/CommandPalette/CommandPaletteList.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAErC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAmB5C,MAAM,WAAW,uBAAwB,SAAQ,SAAS,CAAC,cAAc,CAAC;IACxE;;OAEG;IACH,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAEhC;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,KAAK,EAAE,cAAc,EACrB,GAAG,EACH,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,uBAAuB,+BAwBzB;yBAhCe,kBAAkB"}
|
|
@@ -34,8 +34,10 @@ const styles = {
|
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
36
|
/**
|
|
37
|
-
* Scrollable results container for the command palette.
|
|
38
|
-
*
|
|
37
|
+
* Scrollable results container for the command palette. Standalone composition
|
|
38
|
+
* renders as a listbox. Inside CommandPalette, listbox semantics are present
|
|
39
|
+
* only while selectable results exist; empty and pending states retain the same
|
|
40
|
+
* styled container without exposing an empty interactive popup.
|
|
39
41
|
*
|
|
40
42
|
* When used inside CommandPalette, automatically gets the correct
|
|
41
43
|
* ID for aria-controls linking with the input.
|
|
@@ -65,12 +67,15 @@ export function CommandPaletteList({
|
|
|
65
67
|
const t = useTranslator();
|
|
66
68
|
const label = labelFromProps ?? t('@astryx.commandPalette.list.label');
|
|
67
69
|
const ctx = useCommandPaletteContext();
|
|
70
|
+
// Inside CommandPalette the list is a listbox only while it holds selectable
|
|
71
|
+
// results; standalone composition is always a listbox.
|
|
72
|
+
const hasListbox = ctx ? ctx.selectableItems.length > 0 : true;
|
|
68
73
|
return /*#__PURE__*/_jsx("div", {
|
|
69
74
|
ref: ref,
|
|
70
75
|
...props,
|
|
71
76
|
id: ctx?.listId ?? props.id,
|
|
72
|
-
role:
|
|
73
|
-
"aria-label": label,
|
|
77
|
+
role: hasListbox ? 'listbox' : undefined,
|
|
78
|
+
"aria-label": hasListbox ? label : undefined,
|
|
74
79
|
...mergeProps(themeProps('command-palette-list'), stylex.props(styles.list, xstyle), className, style),
|
|
75
80
|
children: children
|
|
76
81
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file ContextMenu.tsx
|
|
3
|
-
* @input Uses React, StyleX, useLayer,
|
|
4
|
-
* shared menu-presentation resolver
|
|
3
|
+
* @input Uses React, StyleX, useLayer, shared layer dismissal, BottomSheet,
|
|
4
|
+
* useListFocus, and the shared menu-presentation resolver
|
|
5
5
|
* @output Exports ContextMenu with cursor-popover and touch-sheet presentations
|
|
6
6
|
* @position Core implementation; consumed by index.ts
|
|
7
7
|
*
|
|
@@ -117,7 +117,7 @@ export type ContextMenuProps = ContextMenuDataProps | ContextMenuCompoundProps;
|
|
|
117
117
|
* </ContextMenu>
|
|
118
118
|
* ```
|
|
119
119
|
*/
|
|
120
|
-
export declare function ContextMenu({ children, menuWidth, size, label: labelFromProps, isDisabled, onOpenChange, presentation, triggerAs, ref, className, style, xstyle, triggerXstyle, 'data-testid': testId, ...rest }: ContextMenuProps): React.JSX.Element;
|
|
120
|
+
export declare function ContextMenu({ children, menuWidth, size, label: labelFromProps, isDisabled, onOpenChange, presentation, triggerAs, ref, className, style, xstyle, triggerXstyle, onContextMenu: onContextMenuProp, onTouchStart: onTouchStartProp, onTouchMove: onTouchMoveProp, onTouchEnd: onTouchEndProp, onTouchCancel: onTouchCancelProp, 'data-testid': testId, ...rest }: ContextMenuProps): React.JSX.Element;
|
|
121
121
|
export declare namespace ContextMenu {
|
|
122
122
|
var displayName: string;
|
|
123
123
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContextMenu.d.ts","sourceRoot":"","sources":["../../src/ContextMenu/ContextMenu.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KASN,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ContextMenu.d.ts","sourceRoot":"","sources":["../../src/ContextMenu/ContextMenu.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KASN,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAoCrC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAGjD,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,kCAAkC,CAAC;AA6G1C,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AAEvD,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,CAAC;AAE7D,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAMnD,UAAU,oBAAqB,SAAQ,SAAS;IAC9C,oDAAoD;IACpD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAC;IAC9C,+DAA+D;IAC/D,QAAQ,EAAE,SAAS,CAAC;IACpB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,wCAAwC;IACxC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,oBAAqB,SAAQ,oBAAoB;IACzD,gDAAgD;IAChD,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED,UAAU,wBAAyB,SAAQ,oBAAoB;IAC7D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+CAA+C;IAC/C,WAAW,EAAE,SAAS,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,wBAAwB,CAAC;AAM/E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,SAAS,EACT,IAAW,EACX,KAAK,EAAE,cAAc,EACrB,UAAkB,EAClB,YAAY,EACZ,YAAwB,EACxB,SAAiB,EACjB,GAAG,EACH,SAAS,EACT,KAAK,EACL,MAAM,EACN,aAAa,EACb,aAAa,EAAE,iBAAiB,EAChC,YAAY,EAAE,gBAAgB,EAC9B,WAAW,EAAE,eAAe,EAC5B,UAAU,EAAE,cAAc,EAC1B,aAAa,EAAE,iBAAiB,EAChC,aAAa,EAAE,MAAM,EACrB,GAAG,IAAI,EACR,EAAE,gBAAgB,qBAoelB;yBAzfe,WAAW"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @file ContextMenu.tsx
|
|
6
|
-
* @input Uses React, StyleX, useLayer,
|
|
7
|
-
* shared menu-presentation resolver
|
|
6
|
+
* @input Uses React, StyleX, useLayer, shared layer dismissal, BottomSheet,
|
|
7
|
+
* useListFocus, and the shared menu-presentation resolver
|
|
8
8
|
* @output Exports ContextMenu with cursor-popover and touch-sheet presentations
|
|
9
9
|
* @position Core implementation; consumed by index.ts
|
|
10
10
|
*
|
|
@@ -39,6 +39,8 @@ import { Button } from "../Button/index.js";
|
|
|
39
39
|
import { Heading } from "../Heading/index.js";
|
|
40
40
|
import { Icon } from "../Icon/index.js";
|
|
41
41
|
import { useLayer } from "../Layer/useLayer.js";
|
|
42
|
+
import { LayerDepthProvider } from "../Layer/LayerDepthContext.js";
|
|
43
|
+
import { useLayerDismissal } from "../Layer/useLayerDismissal.js";
|
|
42
44
|
import { MenuBottomSheetActionList } from "../DropdownMenu/MenuBottomSheetActionList.js";
|
|
43
45
|
import { renderDropdownItems } from "../DropdownMenu/renderDropdownItems.js";
|
|
44
46
|
import { DropdownMenuContext } from "../DropdownMenu/DropdownMenuContext.js";
|
|
@@ -52,7 +54,7 @@ import { useLongPress } from "../hooks/useLongPress.js";
|
|
|
52
54
|
import { layerAnimations } from "../Layer/layerAnimations.stylex.js";
|
|
53
55
|
import "../theme/tokens.stylex.js";
|
|
54
56
|
import { colorVars, spacingVars, radiusVars, durationVars, easeVars, shadowVars } from "../theme/tokens.stylex.js";
|
|
55
|
-
import { mergeProps,
|
|
57
|
+
import { mergeProps, rtlStyles } from "../utils/index.js";
|
|
56
58
|
import { themeProps } from "../utils/themeProps.js";
|
|
57
59
|
import { useTranslator } from "../i18n/index.js";
|
|
58
60
|
import { useMergedRefs } from "../hooks/useMergedRefs.js";
|
|
@@ -194,6 +196,11 @@ export function ContextMenu({
|
|
|
194
196
|
style,
|
|
195
197
|
xstyle,
|
|
196
198
|
triggerXstyle,
|
|
199
|
+
onContextMenu: onContextMenuProp,
|
|
200
|
+
onTouchStart: onTouchStartProp,
|
|
201
|
+
onTouchMove: onTouchMoveProp,
|
|
202
|
+
onTouchEnd: onTouchEndProp,
|
|
203
|
+
onTouchCancel: onTouchCancelProp,
|
|
197
204
|
'data-testid': testId,
|
|
198
205
|
...rest
|
|
199
206
|
}) {
|
|
@@ -226,7 +233,6 @@ export function ContextMenu({
|
|
|
226
233
|
// Element focused before the menu opened, restored when it closes so focus
|
|
227
234
|
// does not fall to <body> after Escape or outside-click dismissal.
|
|
228
235
|
const triggerFocusRef = useRef(null);
|
|
229
|
-
const sheetHeadingRef = useRef(null);
|
|
230
236
|
const [isOpen, setIsOpen] = useState(false);
|
|
231
237
|
const [submenuPath, setSubmenuPath] = useState([]);
|
|
232
238
|
const currentSubmenu = submenuPath.at(-1);
|
|
@@ -274,16 +280,12 @@ export function ContextMenu({
|
|
|
274
280
|
closeMenu();
|
|
275
281
|
}
|
|
276
282
|
}, [closeMenu]);
|
|
277
|
-
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
const frame = requestAnimationFrame(() => {
|
|
282
|
-
sheetHeadingRef.current?.focus({
|
|
283
|
+
const setSheetHeadingRef = useCallback(node => {
|
|
284
|
+
if (node && isOpen && submenuPath.length > 0) {
|
|
285
|
+
node.focus({
|
|
283
286
|
preventScroll: true
|
|
284
287
|
});
|
|
285
|
-
}
|
|
286
|
-
return () => cancelAnimationFrame(frame);
|
|
288
|
+
}
|
|
287
289
|
}, [isOpen, submenuPath.length]);
|
|
288
290
|
const {
|
|
289
291
|
listRef,
|
|
@@ -297,8 +299,15 @@ export function ContextMenu({
|
|
|
297
299
|
boundarySelector: MENU_BOUNDARY_SELECTOR,
|
|
298
300
|
// Menus wrap from the last row to the first and back.
|
|
299
301
|
wrap: true,
|
|
300
|
-
hasPaging: true
|
|
301
|
-
|
|
302
|
+
hasPaging: true
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Join the shared stack so an Escape press dismisses exactly one top-most
|
|
306
|
+
// surface. BottomSheet owns its own dismissal path.
|
|
307
|
+
useLayerDismissal({
|
|
308
|
+
isActive: isOpen && !usesBottomSheet,
|
|
309
|
+
onDismiss: closeMenu,
|
|
310
|
+
getContainer: () => listRef.current
|
|
302
311
|
});
|
|
303
312
|
|
|
304
313
|
// Typeahead over the enabled menu items, matched on each row's LABEL alone.
|
|
@@ -329,32 +338,6 @@ export function ContextMenu({
|
|
|
329
338
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
330
339
|
};
|
|
331
340
|
}, [isOpen, closeMenu, listRef, usesBottomSheet]);
|
|
332
|
-
|
|
333
|
-
// Dismiss on Escape from anywhere while open. The menu div's own onKeyDown
|
|
334
|
-
// only fires when focus is inside the menu; a document-level listener is
|
|
335
|
-
// kept as a reliable fallback Escape path (e.g. if focus has moved out of
|
|
336
|
-
// the menu). Guards against IME composition-cancel.
|
|
337
|
-
useEffect(() => {
|
|
338
|
-
if (!isOpen || usesBottomSheet) {
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
const handleEscape = e => {
|
|
342
|
-
if (e.key !== 'Escape') {
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
if (isImeKeyEvent(e)) {
|
|
346
|
-
// Ignore Escape that is committing/cancelling an IME composition;
|
|
347
|
-
// see utils/ime.ts for why.
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
e.preventDefault();
|
|
351
|
-
closeMenu();
|
|
352
|
-
};
|
|
353
|
-
document.addEventListener('keydown', handleEscape);
|
|
354
|
-
return () => {
|
|
355
|
-
document.removeEventListener('keydown', handleEscape);
|
|
356
|
-
};
|
|
357
|
-
}, [isOpen, closeMenu, usesBottomSheet]);
|
|
358
341
|
const listKeyDown = useCallback(e => {
|
|
359
342
|
// A submenu flyout renders inline inside this menu; its key events bubble
|
|
360
343
|
// up here. Let that level own them — only handle events from this level.
|
|
@@ -447,13 +430,42 @@ export function ContextMenu({
|
|
|
447
430
|
// held long enough (see useLongPress for timer/move-cancel/cleanup logic).
|
|
448
431
|
// The hook also returns the imperative start/moveTo/cancel API the menu press
|
|
449
432
|
// model drives; only its four touch handlers belong on the trigger element.
|
|
450
|
-
const
|
|
433
|
+
const {
|
|
434
|
+
onTouchStart: handleLongPressTouchStart,
|
|
435
|
+
onTouchMove: handleLongPressTouchMove,
|
|
436
|
+
onTouchEnd: handleLongPressTouchEnd,
|
|
437
|
+
onTouchCancel: handleLongPressTouchCancel
|
|
438
|
+
} = useLongPress({
|
|
451
439
|
disabled: isDisabled,
|
|
452
440
|
onLongPress: useCallback(point => {
|
|
453
441
|
const rect = getAnchorBaseRect();
|
|
454
442
|
openAtLocalPoint(rect ? point.x - rect.left : point.x, rect ? point.y - rect.top : point.y, triggerRef.current);
|
|
455
443
|
}, [openAtLocalPoint, getAnchorBaseRect])
|
|
456
444
|
});
|
|
445
|
+
|
|
446
|
+
// ContextMenu owns invocation and long-press cleanup. Consumer handlers are
|
|
447
|
+
// notified too, but preventing their default does not cancel component-owned
|
|
448
|
+
// behavior that the public API does not promise as cancelable.
|
|
449
|
+
const handleTriggerContextMenu = useCallback(event => {
|
|
450
|
+
handleContextMenu(event);
|
|
451
|
+
onContextMenuProp?.(event);
|
|
452
|
+
}, [handleContextMenu, onContextMenuProp]);
|
|
453
|
+
const handleTriggerTouchStart = useCallback(event => {
|
|
454
|
+
handleLongPressTouchStart(event);
|
|
455
|
+
onTouchStartProp?.(event);
|
|
456
|
+
}, [handleLongPressTouchStart, onTouchStartProp]);
|
|
457
|
+
const handleTriggerTouchMove = useCallback(event => {
|
|
458
|
+
handleLongPressTouchMove(event);
|
|
459
|
+
onTouchMoveProp?.(event);
|
|
460
|
+
}, [handleLongPressTouchMove, onTouchMoveProp]);
|
|
461
|
+
const handleTriggerTouchEnd = useCallback(event => {
|
|
462
|
+
handleLongPressTouchEnd();
|
|
463
|
+
onTouchEndProp?.(event);
|
|
464
|
+
}, [handleLongPressTouchEnd, onTouchEndProp]);
|
|
465
|
+
const handleTriggerTouchCancel = useCallback(event => {
|
|
466
|
+
handleLongPressTouchCancel();
|
|
467
|
+
onTouchCancelProp?.(event);
|
|
468
|
+
}, [handleLongPressTouchCancel, onTouchCancelProp]);
|
|
457
469
|
const popoverXstyle = menuWidth ? styles.popoverCustomWidth(menuWidth) : styles.popover;
|
|
458
470
|
|
|
459
471
|
// The drill-in view stack for sub-menus on a phone; the bottom sheet has
|
|
@@ -517,7 +529,7 @@ export function ContextMenu({
|
|
|
517
529
|
isIconOnly: true,
|
|
518
530
|
onClick: () => setSubmenuPath(path => path.slice(0, -1))
|
|
519
531
|
}), /*#__PURE__*/_jsx(Heading, {
|
|
520
|
-
ref:
|
|
532
|
+
ref: setSheetHeadingRef,
|
|
521
533
|
level: 3,
|
|
522
534
|
tabIndex: -1,
|
|
523
535
|
xstyle: [styles.sheetViewHeading, submenuPath.length === 0 && styles.sheetRootHeading],
|
|
@@ -537,11 +549,11 @@ export function ContextMenu({
|
|
|
537
549
|
children: [/*#__PURE__*/_jsxs(TriggerElement, {
|
|
538
550
|
ref: useMergedRefs(ref, triggerRef),
|
|
539
551
|
...triggerProps,
|
|
540
|
-
onContextMenu:
|
|
541
|
-
onTouchStart:
|
|
542
|
-
onTouchMove:
|
|
543
|
-
onTouchEnd:
|
|
544
|
-
onTouchCancel:
|
|
552
|
+
onContextMenu: handleTriggerContextMenu,
|
|
553
|
+
onTouchStart: handleTriggerTouchStart,
|
|
554
|
+
onTouchMove: handleTriggerTouchMove,
|
|
555
|
+
onTouchEnd: handleTriggerTouchEnd,
|
|
556
|
+
onTouchCancel: handleTriggerTouchCancel,
|
|
545
557
|
"data-testid": testId,
|
|
546
558
|
...stylex.props(styles.trigger, ...(triggerXstyle ? Array.isArray(triggerXstyle) ? triggerXstyle : [triggerXstyle] : [])),
|
|
547
559
|
children: [children, /*#__PURE__*/_jsx("span", {
|
|
@@ -564,7 +576,9 @@ export function ContextMenu({
|
|
|
564
576
|
label: sheetLabel,
|
|
565
577
|
children: renderedBottomSheetContent
|
|
566
578
|
})
|
|
567
|
-
}) : layer.render(
|
|
579
|
+
}) : layer.render(/*#__PURE__*/_jsx(LayerDepthProvider, {
|
|
580
|
+
children: renderedMenu
|
|
581
|
+
}), {
|
|
568
582
|
placement: 'below',
|
|
569
583
|
alignment: 'start',
|
|
570
584
|
xstyle: [popoverXstyle, layerAnimations.below]
|
|
@@ -66,16 +66,16 @@ export interface UseLayerDismissalReturn {
|
|
|
66
66
|
*
|
|
67
67
|
* The layer does NOT attach a key listener — the stack owns one listener and
|
|
68
68
|
* routes each Escape press to the top-most REGISTERED layer, so one press
|
|
69
|
-
* dismisses exactly one of them. Dialog (and what is built on it
|
|
70
|
-
* the menus built on it,
|
|
71
|
-
* BottomSheetSwitcher and lab's
|
|
69
|
+
* dismisses exactly one of them. Dialog (and what is built on it, including
|
|
70
|
+
* CommandPalette), Popover and the menus built on it, ContextMenu, Tooltip,
|
|
71
|
+
* HoverCard, Lightbox, MobileNav, BottomSheet, BottomSheetSwitcher and lab's
|
|
72
|
+
* `Drawer` register today.
|
|
72
73
|
*
|
|
73
|
-
* `
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* fix.
|
|
74
|
+
* `DropdownMenuSubMenu` and `PowerSearchEditPopover` still run their own Escape
|
|
75
|
+
* listeners. They stay safe next to the stack only because each claims the press
|
|
76
|
+
* at element level, and the stack stands down on an already-`defaultPrevented`
|
|
77
|
+
* press — but a registered layer opened inside one of them does not get the
|
|
78
|
+
* press. Migrating them is the fix.
|
|
79
79
|
*
|
|
80
80
|
* Wrap the layer's own content in `LayerDepthProvider` so anything opened from
|
|
81
81
|
* inside it registers as nested.
|
|
@@ -23,16 +23,16 @@ import { isTextComposing, isTopmostLayer, registerLayer } from "./layerStack.js"
|
|
|
23
23
|
*
|
|
24
24
|
* The layer does NOT attach a key listener — the stack owns one listener and
|
|
25
25
|
* routes each Escape press to the top-most REGISTERED layer, so one press
|
|
26
|
-
* dismisses exactly one of them. Dialog (and what is built on it
|
|
27
|
-
* the menus built on it,
|
|
28
|
-
* BottomSheetSwitcher and lab's
|
|
26
|
+
* dismisses exactly one of them. Dialog (and what is built on it, including
|
|
27
|
+
* CommandPalette), Popover and the menus built on it, ContextMenu, Tooltip,
|
|
28
|
+
* HoverCard, Lightbox, MobileNav, BottomSheet, BottomSheetSwitcher and lab's
|
|
29
|
+
* `Drawer` register today.
|
|
29
30
|
*
|
|
30
|
-
* `
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* fix.
|
|
31
|
+
* `DropdownMenuSubMenu` and `PowerSearchEditPopover` still run their own Escape
|
|
32
|
+
* listeners. They stay safe next to the stack only because each claims the press
|
|
33
|
+
* at element level, and the stack stands down on an already-`defaultPrevented`
|
|
34
|
+
* press — but a registered layer opened inside one of them does not get the
|
|
35
|
+
* press. Migrating them is the fix.
|
|
36
36
|
*
|
|
37
37
|
* Wrap the layer's own content in `LayerDepthProvider` so anything opened from
|
|
38
38
|
* inside it registers as nested.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plainDate.d.ts","sourceRoot":"","sources":["../../src/utils/plainDate.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAE,SAAS,EAAC,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,eAAe,CAAC;AAE1C,YAAY,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAE3C,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACV,SAAS,CAcX;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,SAAS,CAG9D;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,aAAa,CAK3D;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAMnD;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,GAAG,SAAS,CAMpD;AAED,wBAAgB,cAAc,IAAI,SAAS,CAE1C;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlE;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAExD;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAStE;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAIpE;AAoBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAKpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB;IACD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CA2BA;
|
|
1
|
+
{"version":3,"file":"plainDate.d.ts","sourceRoot":"","sources":["../../src/utils/plainDate.ts"],"names":[],"mappings":"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"}
|