Repository navigation
Conversation
… an open handle BaseTypeahead takes `menu`, which chooses what its anchored menu shows while Astryx keeps the layer (position, top layer, outside press, Escape, focus return, ARIA). The listbox role may put information around the result list; anything a person acts on stays a result, and a control outside the list warns in development. The dialog role shows content that takes focus in a dialog named by `label`; closing it returns focus to the element focused when it opened, or to the input, and it does not close on an empty query or an input blur. `handleRef` exposes open() and close(); onOpenChange reports changes; there is no controlled open state. open() runs after the commit it is called in, and a pick whose onChange calls open() keeps the menu open, so a role switch keeps the same layer with no close in between. Typeahead and Tokenizer forward the menu (Tokenizer in its inline presentation, with onOpenChange and open/close on its handle). Records: BaseTypeahead FR13-FR16, AR6, ORD3 and DEC-1 (row 49 A), Typeahead FR11, Tokenizer FR28. Adds the BaseTypeaheadMenu CLI block (the docsite example), a Menu story and a Chromium spec.
…n() opens it Addresses review on the menu config: - An outside press closes a dialog-role menu: the outside-press watch finds the layer from the element the input controls, in its own root, instead of the list the dialog replaces. - Only the handle opens a dialog-role menu; a search, focus load, focus or ArrowDown leaves it closed, so typing stays in the field. - The dialog role drives usePopover (role, dialogLabel, hasAutoFocus): the popover is the named, modal dialog, takes initial focus and restores it. The shared focus trap gains a restore fallback, used when the element focused at open is gone or was the page, and BaseTypeahead passes its input. - A pick that calls open() and stays a listbox returns focus to the input and loads the focus entries, or closes when there are none. - `hasNoResults` is now `isEmptySearch` (spec:AST-056 vocabulary); the outside-list warning runs in development only. - Records: contract-at-a-glance and compatibility say the change is additive; FR1, FR4 and AR1 are qualified by role; FR14 and FR16 state the open and pick rules; anatomy names Menu content and Menu dialog; verification rows name the new tests and the Chromium outside-press case.
… CI fixes - Closing a dialog-role menu that a pick opened (Escape, close(), an outside press) returns focus to the input without opening the list again, decided in the close callback, as a pick's own focus return already does. Tests cover Escape, close() and an outside press in a hasEntriesOnFocus field. - The outside-list warning gates on a declared build flag, as utils/devWarning.ts does, so processEnvTypes passes. - Tokenizer.spec: the Public contract row is main's, with the FR28 sentence appended; FR28 gains its Status cell. - BaseTypeahead.spec: AR6 says aria-controls names the layer that holds the dialog; FR14 names what the dialog render receives; FR15 says a focus return does not open the list. - The BaseTypeaheadMenu block joins the ShadCN route lock and the CLI search goldens.
… open(); Tokenizer and CLI block move out - The dialog's close moves focus through the focus trap's new internal restoreFocusTo hook, so BaseTypeahead knows which focus is the return and keeps the list closed, however late close() runs (after an await). - open() records the element focused when it is called, and the menu returns focus there (usePopover's internal getOpener), so a click's own handlers that move focus first no longer take the opener. - To stay within the size limit, Tokenizer's forwarding (menu, onOpenChange, the handle's open and close, FR28) and the BaseTypeaheadMenu CLI block, with its route-lock and golden entries, move to follow-up pull requests. The Menu story keeps the example. - Test: close() after an await.
…handle Tokenizer's inline presentation forwards `menu` and `onOpenChange` to BaseTypeahead, and TokenizerHandle gains `open()` and `close()`. A token whose button calls `open()` with a dialog-role menu opens the dialog, and Escape returns focus to that token: Tokenizer keeps focus where a press, or the menu's focus return, put it, instead of redirecting to the input. The sheet presentation keeps its own sheet; `menu` and `onOpenChange` join its development warning. Record: Tokenizer FR28, the public-contract line. Part of the BaseTypeahead menu stack.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
|
/approve-spec 91f2921 |
There was a problem hiding this comment.
Changes requested. The menu and onOpenChange forwarding and the new open()/close() handle match component:Tokenizer FR28, but both new focus flags need rework before this lands.
- A press that starts on a token's control and is released outside the field leaves
isPressingRefset (Tokenizer.tsx:1541–1549clears it only on a pointerup inside the field), so the next Tab into the field stops on the first token's Remove button instead of the input; read the shared interaction-modality tracker instead, or end the press wherever it is released, and drop the wrapper's own pointer handlers. handleMenuOpenChange(Tokenizer.tsx:1186–1205) guesses the menu's focus return with documentfocusin/keydown/pointerdownlisteners that outlive an unmount, while the shared focus trap'srestoreFocusTo, which BaseTypeahead already uses, marks exactly that focus, so have BaseTypeahead report the return to Tokenizer through that hook and delete the listeners and the flag.
A TokenizerBottomSheet.test.tsx case for the sheet's menu/onOpenChange warning and its no-op open() would also close the test gap FR28 records.
[Automated review]
The owner decided TextInput exposes no ref to its control box for anchoring a Popover: that route handles none of the accessibility a typeahead needs. A custom typeahead uses BaseTypeahead with anchorRef and the menu config.
Tokenizer.spec.md: main's requirement table (FR16) with FR28 added.
There was a problem hiding this comment.
This review waits on an engineering owner's spec decision, and two focus fixes are needed.
component:Tokenizer FR28 is new, and the earlier /approve-spec named the previous commit, whose spec content the base merges have since changed, so it no longer covers this head. An engineering owner records the decision by commenting /approve-spec <full head SHA> on this pull request (the author may, as an engineering owner) or asks for changes to FR28 and its four API rows; FR28 also relies on component:BaseTypeahead FR13–FR16, which land with #10544.
Blocking, whatever the spec decision:
- A press that starts on a token's control and is released outside the field leaves
isPressingRefset (Tokenizer.tsx:1544–1552clears it only on a pointerup inside the field), so the next Tab into the field stops on the first token's Remove button instead of the input; derive this from the shareduseInteractionModalityTracking()or end the press wherever it is released, and drop the wrapper's pointer handlers. handleMenuOpenChange(Tokenizer.tsx:1186–1205) guesses the menu's focus return by arming a flag on every close and clearing it from three document listeners that outlive an unmount; have BaseTypeahead report the return it already performs inrestoreFocusTothrough a package-internal option, and remove the listeners.
The fixed head needs its own /approve-spec.
[Automated review]
|
/approve-spec 863f6fa |
There was a problem hiding this comment.
Changes requested: component:Tokenizer FR28 and its four API rows are approved for this head, so the forwarding, the handle and the token-focus direction are settled, but three focus defects in Tokenizer.tsx block.
- A press on a token's control that is released outside the field leaves
isPressingRefset (Tokenizer.tsx:930,:1544–1552), so the next Tab into the field stops on the first token's Remove button instead of the input; keep focus only when the shared modality tracker (useInteractionModalityTracking()) reads'pointer', or at least clear the flag when focus leaves the field. handleMenuOpenChange(Tokenizer.tsx:1186–1205) arms the focus-return flag on every menu close and clears it with three document listeners, so after a result-list close a focus that reaches a token with no key or press stays there and an unmount leaves the listeners registered until the next focus, key or press; have BaseTypeahead report its focus return (it already passes the focus trap'srestoreFocusTo) through a package-internal option and drop the listeners.- Miss: in Safari a click does not focus the token's button, so
open()never records the token as the opener and Escape returns focus to the input instead of the token that FR28 and the Changeset promise; record the pressed token control as the opener and add a test that clicks without focusing.
Non-blocking: FR28's sheet sentence (the warning for menu and onOpenChange, and open()/close() ignored) has no test.
A fixed head needs a fresh /approve-spec, and this pull request lands only together with #10544 and #10625.
[Automated review]
…s own return - Focus a pointer puts on a token's control stays there because the shared interaction-modality tracker reads "pointer", not a press flag that a press released outside the field left set. Test: a press on a token released outside the field still lets the next Tab land on the input (fails on the previous head). - BaseTypeahead marks its dialog menu's focus return through a package-internal __menuFocusReturnRef, set by the focus trap's restoreFocusTo, so Tokenizer keeps that focus on the token without the three document listeners it armed on every close.
There was a problem hiding this comment.
Approval waits on an engineering owner, and two fixes are needed whatever that decision is.
component:TokenizerFR28, its public-contract line and its handle paragraph are new, and the earlier/approve-specnamed the previous commit: an engineering owner records the decision by commenting/approve-spec <full head SHA>on this pull request (the author may do so as an engineering owner), or says what to change.- BaseTypeahead's new
__menuFocusReturnRefis tagged internal but reachable throughBaseTypeaheadProps, and no record decides it, so an owner needs to accept it on the public props or ask for it to move behind a non-exported boundary.
Blocking findings:
- Miss: in Safari, where a click or tap does not focus the token's button,
open()records the page or the input as the opener, so Escape returns focus to the input instead of the token that FR28 and the Changeset promise; record the pressed token control as the opener and add a test that clicks without focusing. - Miss: FR28, the Changeset and the comment at
Tokenizer.tsx:928–929say focus a press puts on a token's control stays there instead of moving to the input, buthandleWrapperClickstill moves it to the input when the click completes, so reword them to what holds (focus stays until the click runs, soopen()returns focus to that token on Escape).
Fixed since the last review: Tab entry after a press released outside the field lands on the input again, and the menu's focus return now comes from BaseTypeahead instead of document listeners. Non-blocking: FR28's sheet sentence has no test. This pull request lands together with #10544 and #10625.
[Automated review]
|
/approve-spec 944e86f |
There was a problem hiding this comment.
Changes requested: the spec is approved, and two focus fixes remain.
An engineering owner approved component:Tokenizer FR28 for this head, so the new menu, onOpenChange and handle open()/close() have their governing record, and BaseTypeahead's internal __menuFocusReturnRef was accepted with it.
Blocking findings:
- Miss: in Safari, where a click or tap does not focus the token's button,
open()records the page as the opener, so Escape returns focus to the search input instead of the token that FR28 and the Changeset promise; record the pressed token control as the opener and add a test that clicks without focusing. - Miss: FR28, the Changeset and the comment at
Tokenizer.tsx:928–929say focus a press puts on a token's control stays there instead of moving to the input, buthandleWrapperClickstill moves it to the input when the click completes; make the click handler leave focus on a token's own control, or reword those three to what holds (a reworded FR28 needs a new/approve-spec).
Non-blocking: FR28's sheet sentence has no test. This pull request lands together with #10544 and #10625.
[Automated review]
…ntrol keeps focus - In Safari a click does not focus a button, so open() recorded the page as the opener and Escape returned focus to the input. Tokenizer now records the control a press lands on inside a custom token, and BaseTypeahead's open() reads it (internal __pressedOpenerRef) before the focused element. - A click on a custom token's own control no longer moves focus to the input, as FR28 and the changeset say. Tests: Escape returns to a token whose click did not focus it; a click on a custom token's control leaves focus on it (both fail on the previous head).
There was a problem hiding this comment.
Approval waits on an engineering owner's spec decision, and two fixes are needed whatever that decision is.
component:Tokenizer FR28, its public-contract line and handle paragraph are unchanged, but the new commit ends the earlier approval, and BaseTypeahead's public props now also reach the internal __pressedOpenerRef, which no record decides. An engineering owner records the decision by commenting /approve-spec <full head SHA> on this pull request (the author may do so as an engineering owner), or says what to change.
Blocking findings:
- In Safari, the blur that a press on a token's button causes clears the pressed control (
Tokenizer.tsx:1254) before the click callsopen(), so Escape still returns focus to the search input whenever focus was in the field, the usual state after typing or picking a value; keep the pressed control through that blur and add a test that focuses the input before the press. findTokenControlre-declares a focusable selector (Tokenizer.tsx:954–956) instead of using the canonicalFOCUSABLE_SELECTORfromhooks/focusableSelector.ts, and the two already differ (acontenteditableorsummarycontrol inside a token is missed); import it, or add the click-target variant beside it and import that.
The click fix from the last review holds: a click on a custom token's control now keeps focus there. Non-blocking: in Safari that click leaves focus on the page, and FR28's sheet sentence has no test. This pull request lands together with #10544 and #10625.
[Automated review]
|
/approve-spec 9716e63 |
BaseTypeaheadFocusContext now carries Typeahead's inputReturnTarget beside Tokenizer's two refs; the restore point uses the stand-in and still sets menuFocusReturn around the focus.
There was a problem hiding this comment.
Approval waits on an engineering owner's spec decision for this head: component:Tokenizer FR28, with its public-contract line, handle paragraph and the four API rows it adds (Tokenizer menu and onOpenChange, TokenizerHandle.open() and close()), was approved for the previous commit, and this merge of #10544's Typeahead fix ends that approval although the pull request's own changes are the same. An engineering owner records the decision by commenting /approve-spec <full head SHA> on this pull request; the author may do so if they are an engineering owner. No blocking issue remains, and this pull request lands only together with #10544 and #10625, because FR28 relies on BaseTypeahead's menu from #10544.
Non-blocking:
- Under Safari's click model, a click on a custom token's control that opens nothing leaves focus on the page instead of the input (
Tokenizer.tsx:1506–1509). - FR28's sheet sentence (the development warning for
menuandonOpenChange;open()andclose()ignored) has no test.
[Automated review]
|
/approve-spec 3a17bfd |
There was a problem hiding this comment.
Approved: an engineering owner approved component:Tokenizer FR28 for this head, with its public-contract line, handle paragraph and the four API rows it adds (Tokenizer menu and onOpenChange, TokenizerHandle.open() and close()), and no blocking issue remains after this merge of #10544's restore-point fix. This pull request lands only together with #10544 and #10625, because FR28 relies on BaseTypeahead's menu from #10544.
Non-blocking:
- Under Safari's click model, a click on a custom token's control that opens nothing leaves focus on the page instead of the input (
Tokenizer.tsx:1506–1509). - FR28's sheet sentence (the development warning for
menuandonOpenChange;open()andclose()ignored) has no test. - The merged
BaseTypeaheadFocusContext.tsheader grows to 16 lines, with one long sentence for both refs; a shorter header is suggested inline.
[Automated review]
| * Tokenizer provides two refs: `menuFocusReturn` is `true` while a | ||
| * dialog-role menu's close returns focus, so the field keeps that focus on | ||
| * the token; and `pressedOpener` holds the token control a click activates, | ||
| * which `open()` records as the menu's opener even when the click did not | ||
| * focus it (a click does not focus a button in Safari). |
There was a problem hiding this comment.
Non-blocking (INV29): with the merge this header grows to 16 lines, past the limit of about 12, and these lines put both refs into one 56-word sentence. A shorter header keeps the reasons:
/**
* @file BaseTypeaheadFocusContext.ts
* @input Uses createSharedContext
* @output Exports BaseTypeaheadFocusContext (internal; not re-exported)
* @position Internal to Typeahead; provided by Typeahead and Tokenizer, read
* by BaseTypeahead
*
* A dialog menu's close returns focus to `inputReturnTarget` in place of a
* hidden input. `menuFocusReturn` is true while that close returns focus.
* `pressedOpener` is the control a click activates. Safari does not focus a
* clicked button.
*/
PR Analysis Report🔎 Preview ·
|
| Component | Size | LoC | Visual · A11y · RTL |
|---|---|---|---|
| PowerSearch | 288.6 kB (+1.3 kB) · 24.1 kB CSS (0) | — | — · — · — |
| Tokenizer · Storybook | 92.7 kB (+1.2 kB) · 18.8 kB CSS (0) | 2,331 (+92) | ✓ · ✓ · ✓ |
| Typeahead | 80.9 kB (+1.1 kB) · 12.4 kB CSS (0) | — | ✓ · ✓ · ✓ |
48 more components
| Component | Size | LoC | Visual · A11y · RTL |
|---|---|---|---|
| BaseTypeahead | 72.2 kB (+953 B) · 10.9 kB CSS (0) | — | ✓ · ✓ · ✓ |
| Selector | 100.1 kB (+191 B) · 17.4 kB CSS (0) | — | — · — · — |
| MultiSelector | 95.1 kB (+190 B) · 16.8 kB CSS (0) | — | — · — · — |
| TopNavMenu | 74.9 kB (+188 B) · 11.2 kB CSS (0) | — | — · — · — |
| TabMenu | 72.1 kB (+181 B) · 11.1 kB CSS (0) | — | — · — · — |
| DateInput | 187.2 kB (+175 B) · 17.0 kB CSS (0) | — | — · — · — |
| DateTimeInput | 208.9 kB (+175 B) · 18.7 kB CSS (0) | — | — · — · — |
| SideNavItem | 70.8 kB (+175 B) · 11.1 kB CSS (0) | — | — · — · — |
| TopNavHeading | 75.5 kB (+173 B) · 11.2 kB CSS (0) | — | — · — · — |
| ChatComposerInput | 76.4 kB (+169 B) · 11.3 kB CSS (0) | — | — · — · — |
| SideNavHeading | 75.9 kB (+169 B) · 11.3 kB CSS (0) | — | — · — · — |
| BreadcrumbItem | 85.0 kB (+168 B) · 12.1 kB CSS (0) | — | — · — · — |
| ChatComposerTokenElement | 76.4 kB (+167 B) · 11.3 kB CSS (0) | — | — · — · — |
| Pagination | 110.1 kB (+165 B) · 17.8 kB CSS (0) | — | — · — · — |
| ChatComposer | 78.7 kB (+162 B) · 12.0 kB CSS (0) | — | — · — · — |
| DateRangeInput | 93.0 kB (+161 B) · 12.5 kB CSS (0) | — | — · — · — |
| MoreMenu | 97.7 kB (+157 B) · 17.6 kB CSS (0) | — | — · — · — |
| TopNavMegaMenu | 70.0 kB (+157 B) · 11.8 kB CSS (0) | — | — · — · — |
| Popover · Storybook | 91.2 kB (+145 B) · 14.2 kB CSS (0) | 1,549 (+9) | ✓ · ✓ · ✓ |
| ComplexSelector | 71.3 kB (+139 B) · 11.8 kB CSS (0) | — | — · — · — |
| DropdownMenu | 97.4 kB (+135 B) · 17.6 kB CSS (0) | — | — · — · — |
| Drawer | 50.8 kB (+116 B) · 8.3 kB CSS (0) | — | — · — · — |
| ContextMenu | 108.4 kB (+3 B) · 17.4 kB CSS (0) | — | — · — · — |
| TableHeaderCell | 109.2 kB (+2 B) · 17.7 kB CSS (0) | — | — · — · — |
| TableCell | 109.7 kB (+1 B) · 17.9 kB CSS (0) | — | — · — · — |
| AlertDialog | 105.6 kB (0) · 14.6 kB CSS (0) | — | — · — · — |
| AppShell | 91.1 kB (0) · 13.5 kB CSS (0) | — | — · — · — |
| BottomSheet | 68.3 kB (0) · 7.7 kB CSS (0) | — | — · — · — |
| CommandPalette | 73.3 kB (0) · 12.7 kB CSS (0) | — | — · — · — |
| Dialog | 24.0 kB (0) · 6.9 kB CSS (0) | — | — · — · — |
| DropdownMenuSubMenu | 70.4 kB (0) · 9.7 kB CSS (0) | — | — · — · — |
| Lightbox | 122.6 kB (0) · 10.6 kB CSS (0) | — | — · — · — |
| MobileNav | 70.7 kB (0) · 10.6 kB CSS (0) | — | — · — · — |
| TimeInput | 162.5 kB (0) · 16.0 kB CSS (0) | — | — · — · — |
| TopNav | 72.4 kB (0) · 10.9 kB CSS (0) | — | — · — · — |
| TypeaheadItem | 6.4 kB (0) · 3.6 kB CSS (0) | — | ✓ · ✓ · ✓ |
| BottomSheetSwitcher | 17.9 kB (−1 B) · 3.4 kB CSS (0) | — | — · — · — |
| Markdown | 187.7 kB (−1 B) · 20.6 kB CSS (0) | — | — · — · — |
| Table | 125.0 kB (−1 B) · 18.3 kB CSS (0) | — | — · — · — |
| SideNav | 114.2 kB (−5 B) · 11.4 kB CSS (0) | — | — · — · — |
| lab/ChatEmojiPicker | 106.3 kB (new) · 773 B CSS (new) | — | — · — · — |
| lab/ChatReactionBar | 107.4 kB (new) · 1.1 kB CSS (new) | — | — · — · — |
| lab/CommentComposer | 152.3 kB (new) · 1.9 kB CSS (new) | — | — · — · — |
| lab/Comments | 351.5 kB (new) · 2.5 kB CSS (new) | — | — · — · — |
| lab/CommentThread | 344.6 kB (new) · 2.4 kB CSS (new) | — | — · — · — |
| lab/TourStep | 97.6 kB (new) · 590 B CSS (new) | — | — · — · — |
| lab/TransferListSelector | 109.3 kB (new) · 1.4 kB CSS (new) | — | — · — · — |
| richtext/RichTextEditorToolbar | 278.4 kB (new) · 454 B CSS (new) | — | — · — · — |
Package size: measured; main has no measurement of the merge base to compare yet.
API changes: cli +22 · ~7 · −0 (against the merge base's committed report); core +16 · ~0 · −0; theme-butter +1 · ~0 · −0 (against the merge base's committed report); theme-y2k +1 · ~0 · −0 (against the merge base's committed report)
Committed API report behind this build: cli 29 rows, core 36 rows, theme-butter 1 row, theme-y2k 1 row; run pnpm api:report.
47 API changes (advisory)
| Package | Where | Signature | Usage | |
|---|---|---|---|---|
| + | cli |
./api · Functions · function exportSearchIndex |
function exportSearchIndex @experimental: (options?: { cwd?: string | undefined; package?: string | undefined }) => Promise<SearchIndex> |
import {exportSearchIndex} from '@astryxdesign/cli/api'; exportSearchIndex(…) |
| + | cli |
./api · Functions · function rankSearchIndex |
function rankSearchIndex @experimental: (query: string, indexes: SearchIndex | SearchIndex[], options?: { type?: SearchDomain | undefined; limit?: number | undefined }) => Promise<SearchResponse> |
import {rankSearchIndex} from '@astryxdesign/cli/api'; rankSearchIndex(…) |
| + | cli |
./api · Types · type DocsListChild |
type DocsListChild = DocsNodeChild & { topic: string; description: string; children?: DocsListChild[]; childCount?: number } |
import type {DocsListChild} from '@astryxdesign/cli/api' |
| + | cli |
./api · Types · type DocsListNamespace |
childCount?: number | undefined |
import type {DocsListNamespace} from '@astryxdesign/cli/api'; const x: DocsListNamespace = {childCount: …} |
| + | cli |
./api · Types · type DocsListNamespace |
children?: DocsListChild[] | undefined |
import type {DocsListNamespace} from '@astryxdesign/cli/api'; const x: DocsListNamespace = {children: …} |
| + | cli |
./api · Types · type SearchIndex |
type SearchIndex |
import type {SearchIndex} from '@astryxdesign/cli/api' |
| + | cli |
./api · Types · type SearchResultEntry |
deprecated?: ComponentDeprecation | undefined |
import type {SearchResultEntry} from '@astryxdesign/cli/api'; const x: SearchResultEntry = {deprecated: …} |
| + | cli |
./authoring · Types · interface ComponentDeprecation |
interface ComponentDeprecation |
import type {ComponentDeprecation} from '@astryxdesign/cli/authoring' |
| + | cli |
./authoring · Types · interface ComponentIconSlotDoc |
interface ComponentIconSlotDoc |
import type {ComponentIconSlotDoc} from '@astryxdesign/cli/authoring' |
| + | cli |
./authoring · Types · interface ComponentIconSlotStateDoc |
interface ComponentIconSlotStateDoc |
import type {ComponentIconSlotStateDoc} from '@astryxdesign/cli/authoring' |
| + | cli |
./authoring · Types · interface MultiComponentDoc |
deprecated?: ComponentDeprecation |
import type {MultiComponentDoc} from '@astryxdesign/cli/authoring'; const x: MultiComponentDoc = {deprecated: …} |
| + | cli |
./authoring · Types · interface SingleComponentDoc |
deprecated?: ComponentDeprecation |
import type {SingleComponentDoc} from '@astryxdesign/cli/authoring'; const x: SingleComponentDoc = {deprecated: …} |
| + | cli |
./doc · Types · interface ComponentBaseDoc |
deprecated?: ComponentDeprecation |
import type {ComponentBaseDoc} from '@astryxdesign/cli/doc'; const x: ComponentBaseDoc = {deprecated: …} |
| + | cli |
./doc · Types · interface SubComponentDoc |
deprecated?: ComponentDeprecation |
import type {SubComponentDoc} from '@astryxdesign/cli/doc'; const x: SubComponentDoc = {deprecated: …} |
| + | cli |
./doc · Also exported from an earlier entry point · ComponentDeprecation |
ComponentDeprecation (./authoring) |
import {ComponentDeprecation} from '@astryxdesign/cli/doc' |
| + | cli |
./doc · Also exported from an earlier entry point · ComponentIconSlotDoc |
ComponentIconSlotDoc (./authoring) |
import {ComponentIconSlotDoc} from '@astryxdesign/cli/doc' |
| + | cli |
./doc · Also exported from an earlier entry point · ComponentIconSlotStateDoc |
ComponentIconSlotStateDoc (./authoring) |
import {ComponentIconSlotStateDoc} from '@astryxdesign/cli/doc' |
| + | cli |
./json · Also exported from an earlier entry point · DocsListChild |
DocsListChild (./api) |
import {DocsListChild} from '@astryxdesign/cli/json' |
| + | cli |
./json · Also exported from an earlier entry point · SearchIndex |
SearchIndex (./api) |
import {SearchIndex} from '@astryxdesign/cli/json' |
| + | cli |
./template · Also exported from an earlier entry point · ComponentDeprecation |
ComponentDeprecation (./authoring) |
import {ComponentDeprecation} from '@astryxdesign/cli/template' |
| + | cli |
./template · Also exported from an earlier entry point · ComponentIconSlotDoc |
ComponentIconSlotDoc (./authoring) |
import {ComponentIconSlotDoc} from '@astryxdesign/cli/template' |
| + | cli |
./template · Also exported from an earlier entry point · ComponentIconSlotStateDoc |
ComponentIconSlotStateDoc (./authoring) |
import {ComponentIconSlotStateDoc} from '@astryxdesign/cli/template' |
| ~ | cli |
./api · Functions · function search |
function search: (query: string, options?: { cwd?: string | undefined; type?: "template" | "component" | "hook" | "theme" | "doc" | undefined; limit?: number | undefined }) => Promise<SearchResponse> → function search: (query: string, options?: { cwd?: string | undefined; type?: "template" | "component" | "doc" | "theme" | "hook" | undefined; limit?: number | undefined }) => Promise<SearchResponse> |
import {search} from '@astryxdesign/cli/api'; search(…) |
| ~ | cli |
./api · Types · type SwizzleCopyResponse |
data: { component: string; package: string; outputDir: string; filesCopied: number; files: string[]; usesStyleX: boolean; feedback?: SwizzleFeedback | undefined } → data: { component: string; package: string; outputDir: string; filesCopied: number; files: string[]; usesStyleX: boolean; dependencies: Record<string, string>; marker … #84d9505b |
import type {SwizzleCopyResponse} from '@astryxdesign/cli/api'; const x: SwizzleCopyResponse = {data: …} |
| ~ | cli |
./authoring · Types · interface MultiComponentDoc |
theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[] } → theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[]; componentIcons?: ComponentIconSlotDoc[] } |
import type {MultiComponentDoc} from '@astryxdesign/cli/authoring'; const x: MultiComponentDoc = {theming: …} |
| ~ | cli |
./authoring · Types · interface SingleComponentDoc |
theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[] } → theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[]; componentIcons?: ComponentIconSlotDoc[] } |
import type {SingleComponentDoc} from '@astryxdesign/cli/authoring'; const x: SingleComponentDoc = {theming: …} |
| ~ | cli |
./authoring · Types · type TemplateCategory |
type TemplateCategory = | 'Dashboard - Analytics' | 'Dashboard - Comparison' | 'Dashboard - KPI Summary' | 'Dashboard - Monitoring' | 'Dashboard - Executive Summary' | 'Dashboard - Sco … #e7c18378 → type TemplateCategory = | 'Dashboard - Analytics' | 'Dashboard - Comparison' | 'Dashboard - KPI Summary' | 'Dashboard - Monitoring' | 'Dashboard - Executive Summary' | 'Dashboard - Sco … #a8be998f |
import type {TemplateCategory} from '@astryxdesign/cli/authoring' |
| ~ | cli |
./doc · Types · interface ComponentBaseDoc |
theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[] } → theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[]; componentIcons?: ComponentIconSlotDoc[] } |
import type {ComponentBaseDoc} from '@astryxdesign/cli/doc'; const x: ComponentBaseDoc = {theming: …} |
| ~ | cli |
./doc · Types · interface SubComponentDoc |
theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[] } → theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[]; componentIcons?: ComponentIconSlotDoc[] } |
import type {SubComponentDoc} from '@astryxdesign/cli/doc'; const x: SubComponentDoc = {theming: …} |
| + | core |
. · Components · component BaseTypeahead |
prop handleRef?: React.Ref<BaseTypeaheadHandle> |
<BaseTypeahead handleRef={…} /> |
| + | core |
. · Components · component BaseTypeahead |
prop menu?: BaseTypeaheadMenu |
<BaseTypeahead menu={…} /> |
| + | core |
. · Components · component Tokenizer |
prop menu?: BaseTypeaheadMenu |
<Tokenizer menu={…} /> |
| + | core |
. · Components · component Tokenizer |
prop onOpenChange?: (isOpen: boolean) => void |
<Tokenizer onOpenChange /> |
| + | core |
. · Components · component Typeahead |
prop handleRef?: React.Ref<BaseTypeaheadHandle> |
<Typeahead handleRef={…} /> |
| + | core |
. · Components · component Typeahead |
prop menu?: BaseTypeaheadMenu |
<Typeahead menu={…} /> |
| + | core |
. · Types · interface BaseTypeaheadDialogMenuInfo |
interface BaseTypeaheadDialogMenuInfo |
import type {BaseTypeaheadDialogMenuInfo} from '@astryxdesign/core' |
| + | core |
. · Types · interface BaseTypeaheadHandle |
interface BaseTypeaheadHandle |
import type {BaseTypeaheadHandle} from '@astryxdesign/core' |
| + | core |
. · Types · interface BaseTypeaheadListboxMenuInfo |
interface BaseTypeaheadListboxMenuInfo |
import type {BaseTypeaheadListboxMenuInfo} from '@astryxdesign/core' |
| + | core |
. · Types · type BaseTypeaheadMenu |
type BaseTypeaheadMenu = { role: 'listbox'; render?: (info: BaseTypeaheadListboxMenuInfo) => ReactNode } | { role: 'dialog'; label: string; render: (info: BaseTypeaheadDialogMenuInfo) => ReactNode } |
import type {BaseTypeaheadMenu} from '@astryxdesign/core' |
| + | core |
. · Types · interface TokenizerHandle |
close: () => void |
import type {TokenizerHandle} from '@astryxdesign/core'; const x: TokenizerHandle = {close: …} |
| + | core |
. · Types · interface TokenizerHandle |
open: () => void |
import type {TokenizerHandle} from '@astryxdesign/core'; const x: TokenizerHandle = {open: …} |
| + | core |
./Typeahead · Also exported from an earlier entry point · BaseTypeaheadDialogMenuInfo |
BaseTypeaheadDialogMenuInfo (.) |
import {BaseTypeaheadDialogMenuInfo} from '@astryxdesign/core/Typeahead' |
| + | core |
./Typeahead · Also exported from an earlier entry point · BaseTypeaheadHandle |
BaseTypeaheadHandle (.) |
import {BaseTypeaheadHandle} from '@astryxdesign/core/Typeahead' |
| + | core |
./Typeahead · Also exported from an earlier entry point · BaseTypeaheadListboxMenuInfo |
BaseTypeaheadListboxMenuInfo (.) |
import {BaseTypeaheadListboxMenuInfo} from '@astryxdesign/core/Typeahead' |
| + | core |
./Typeahead · Also exported from an earlier entry point · BaseTypeaheadMenu |
BaseTypeaheadMenu (.) |
import {BaseTypeaheadMenu} from '@astryxdesign/core/Typeahead' |
| + | theme-butter |
Public attributes · attr data-astryx-pressable |
attr data-astryx-pressable (public data attribute) |
[data-astryx-pressable] { … } |
| + | theme-y2k |
Public attributes · attr data-astryx-pressable |
attr data-astryx-pressable (public data attribute) |
[data-astryx-pressable] { … } |
Touched components checked; add ci:run-visual or ci:run-rtl to run the full suites.
Accessibility: 1 violation(s)
Accessibility Audit
Status: 1 accessibility violation(s) found — 1 serious.
Tokenizer - 1 issue(s)
- 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
- Rule:
color-contrast· Affects 2/31 stories · Learn more - WCAG: 1.4.3 (Level AA)
- Rule:
Generated by PR Enrichment workflow | View full report
…ctive option The list loads its entries after the click, and Enter and the arrow keys act on the active option, so the sibling pick tests raced the same way the Escape test did. A shared openList() waits for the 'Status' option to be marked active before any key. Test-only: no product source changes.
|
/approve-spec ff4d67a |
There was a problem hiding this comment.
This pull request is reviewed as part of its stack; see the review on #10625.
…angeset sentence CI's strict promise-function-async rule rejected the non-async callbacks passed to expect.poll. Test and changeset text only.
There was a problem hiding this comment.
This pull request is reviewed as part of its stack; see the review on #10625.
The stack's top conflicted with main in the CLI goldens; main is merged at the bottom and carried up, so each PR's increment over the one below stays its own change.
|
/approve-spec 8aa37d5 |
There was a problem hiding this comment.
Changes requested: one scope fix, then nothing else blocks.
- Regression: this head no longer contains #10544's head, because #10544 merged
mainafter this push, so the declared stack #10544 → #10624 → #10625 does not hold and this pull request's 2,829 authored lines againstmainare over the 2,000-line limit; merge #10544's current head into this branch, then this branch into #10625, so the stack holds again and the size becomes a non-blocking note.
An engineering owner approved the record changes for this head, and the forwarded menu, the open handle and the token focus return behave as component:Tokenizer FR28 and component:BaseTypeahead FR13–FR16 describe, in the tests and in Chromium. Optional, if you touch the branch: the comment at Tokenizer.tsx:1579-1582 and the 16-line header of BaseTypeaheadFocusContext.ts could be shorter, and FR28's sheet sentence has no test.
[Automated review]
|
/approve-spec 9f908c0 |
There was a problem hiding this comment.
Changes requested: the stack has to hold again before this pull request can be judged on its Tokenizer increment.
- The pull request is 2,829 authored lines against
mainbecause #10625 does not yet contain this head, so the declared stack #10544 → #10624 → #10625 does not hold and its size exemption does not apply; mergefeat/tokenizer-menuinto #10625's branch. - Newly live check:
BaseTypeaheadProps.handleRefandBaseTypeaheadProps.menuare outside this pull request's scope (Tokenizer): name them in the scope and get an owner decision, or split them into their own pull request. - Newly live check:
BaseTypeaheadMenuis outside this pull request's scope (Tokenizer): name it in the scope and get an owner decision, or split it into its own pull request. - Newly live check:
BaseTypeaheadHandleis outside this pull request's scope (Tokenizer): name it in the scope and get an owner decision, or split it into its own pull request. - Newly live check:
BaseTypeaheadListboxMenuInfois outside this pull request's scope (Tokenizer): name it in the scope and get an owner decision, or split it into its own pull request. - Newly live check:
BaseTypeaheadDialogMenuInfois outside this pull request's scope (Tokenizer): name it in the scope and get an owner decision, or split it into its own pull request. - Newly live check:
TypeaheadProps.handleRefandTypeaheadProps.menuare outside this pull request's scope (Tokenizer): name them in the scope and get an owner decision, or split them into their own pull request.
These rows are #10544's, so the same merge fixes them: once the stack holds, this pull request's own increment changes only Tokenizer rows. The record changes are owner-approved for this head, and the forwarded menu, the open handle and the token focus return behave as component:Tokenizer FR28 and component:BaseTypeahead FR13–FR16 describe. Optional, if you touch the branch: the comment at Tokenizer.tsx:1579-1582 and the header of BaseTypeaheadFocusContext.ts could be shorter, and FR28's sheet sentence has no test.
[Automated review]
There was a problem hiding this comment.
Approved; CI passes on this head.
#10625 now contains this head, so the declared stack #10544 → #10624 → #10625 holds again and this pull request is judged on its own Tokenizer increment; the size and the BaseTypeahead and Typeahead API rows behind the earlier request for changes belong to #10544. An engineering owner approved component:Tokenizer FR28 for this head, and the forwarded menu and onOpenChange, the handle's open()/close() and the focus return to a token behave as it describes, by mouse, by keyboard and with a click that does not focus the button, as in Safari. This pull request lands only together with #10544 and #10625, once #10544 is approved too.
- Optional, if you touch the branch: an active-voice comment at
Tokenizer.tsx:1579-1582, a shorterBaseTypeaheadFocusContext.tsheader, and a test for FR28's sheet sentence.
[Automated review]
|
/approve-spec 9f908c0 |
|
/approve-spec 9f908c0 |
Stack: #10544 → #10624 → #10625 → #10847
Merge group: #10544, #10624, #10625 (lands together; none merges alone)
Who this helps
People using Tokenizer fields (for example a filter bar whose tokens open an editor). Tokenizer can now use BaseTypeahead's
menu(#10544): a token's own button can open a dialog-role menu on the field's anchored layer, and Escape returns focus to that token.What changed
menuandonOpenChangeto BaseTypeahead;TokenizerHandlegainsopen()andclose().menuandonOpenChangejoin its development warning, and the handle'sopen()/close()do nothing there.component:TokenizerFR28 and its public-contract line; docs for the new props.Changeset:
[feat]patch for Core.Verification
BaseTypeahead.menu.test.tsx"Tokenizer forwards the menu, the handle and onOpenChange" and "Escape returns focus to a Tokenizer token whose button opened the dialog" (mouse and keyboard; the second fails without the token-focus change). Tokenizer and PowerSearch suites pass (766).Writing rubric results
Covers
component:TokenizerFR28 and the public-contract line.R1 narration: none; FR28 states what Tokenizer does.
R2 research: none in the record.
R3 evidence: the verification cell names tests, not pull requests.
R4 rejected alternatives: none recorded.
R5 pull request or issue references: none added.
R6 open questions: none touched.