@q1travel/design-system 0.23.0 → 0.25.0

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.
@@ -35,7 +35,7 @@ Package-owned semantics are applied after native props. `type`, `className`, `di
35
35
  | State | Button | ButtonLink | Label and status |
36
36
  | --- | --- | --- | --- |
37
37
  | `loading` | Keeps the existing `aria-disabled="true"` and `tabIndex=0` focusable contract; does not add `aria-busy` or native `disabled` unless `disabled` was also passed. | Removes `href`, keeps `aria-disabled="true"` and `tabIndex=0` so the loading state remains discoverable. | Keeps the original visible children and announces `loadingLabel` through the existing internal `role="status"` spinner. |
38
- | `busy` | Uses native `disabled`, sets `aria-busy="true"`, and blocks clicks. | Removes `href`, sets `aria-disabled="true"`, `aria-busy="true"`, `tabIndex=-1`, and blocks clicks. | Shows one spinner. A non-empty `busyLabel` replaces the visible label without replacing the stable accessible name; a separate polite `role="status"` announces `busyLabel`, then `loadingLabel`, then `处理中…`. |
38
+ | `busy` | Uses native `disabled`, sets `aria-busy="true"`, and blocks clicks. | Removes `href`, sets `aria-disabled="true"`, `aria-busy="true"`, `tabIndex=-1`, and blocks clicks. | Shows one spinner. A non-empty `busyLabel` replaces the visible label without replacing the stable accessible name; a separate polite `role="status"` announces `busyLabel`, then `loadingLabel`, then `正在处理…`. |
39
39
  | `busy + loading` | Busy wins; one spinner and the busy interaction contract apply. | Busy wins; the link is not navigable or focusable. | `busyLabel` wins for visible/status text; `loadingLabel` is only a fallback when busyLabel is empty. |
40
40
 
41
41
  `busyLabel` is an optional string. An empty string behaves as absent and never disables repeat-submission prevention. The original children remain the accessible-name source (and an explicit `aria-label` remains unchanged); the visible busy label is a separate decorative overlay, while the live status node is outside the button/anchor name calculation. The label slot reserves geometry for both values. Under `prefers-reduced-motion: reduce`, the spinner remains present but static; no rotation, pulse, scale, or spring animation is required to understand the state.
@@ -436,19 +436,22 @@ These components ship in the package. Compose from this list before writing new
436
436
 
437
437
  **Chat messages.** Bubble (incoming/outgoing, optional avatar/name/time, controlled pending/error and retry/actions slots) and MessageScroller (stable keyed items, near-bottom following, streaming growth, prepend anchor preservation, conversationKey reset, named native jump button and separate polite new-message announcements) are public components. They reuse existing tokens and Button; Message and Scroller APIs remain unchanged. Tier B uses native keyboard scrolling and buttons; callers own constrained height, message data, streaming, Markdown, tool cards, history cursors, permissions and network recovery.
438
438
 
439
- **Record activity.** Timeline, TimelineItem, TimelineCollapsedGroup, Marker, Message, Mention, Composer, Attachment. Timeline uses chronological ol/li with tone dots or Avatar; TimelineCollapsedGroup uses a native disclosure for consecutive system events; Marker keeps system events quiet and dates centered. Message supports pending/failed and caller actions; Mention renders caller-owned inline member references using action-text and the selected surface. Composer is a textarea combobox with listbox mentions, Enter sends and Shift+Enter inserts a newline; IME composition never sends or picks. Attachment reuses Progress and named removal. Network, permissions and notifications remain caller-owned.
439
+ **Record activity.** Timeline, TimelineItem, TimelineCollapsedGroup, Marker, Message, Mention, Composer, Attachment. Timeline uses chronological ol/li with tone dots or Avatar; TimelineCollapsedGroup uses a native disclosure for consecutive system events; Marker keeps system events quiet and dates centered. Message supports pending/failed and caller actions; Mention renders caller-owned inline member references using action-text and the selected surface. Composer is a textarea combobox with listbox mentions, Enter sends and Shift+Enter inserts a newline; IME composition never sends or picks. Attachment reuses Progress and named removal. Network, permissions and notifications remain caller-owned. Composer accepts optional `triggers` ({char,label,options?,onQuery?,emptyText?,errorText?,toToken?}); single-symbol triggers share debounce, abort/stale rejection, statuses, retry, combobox/listbox keyboard and synchronous caret insertion. Explicit @ overrides legacy mentions/onMentionQuery; otherwise they remain an implicit @ trigger. Slash is reserved for unchanged commands and rejected as a trigger with a development warning. Enabled triggers alone appear in the default hint. Han text may directly precede any trigger; word/email interiors do not trigger. Selection inserts toToken(item), defaulting to char + label, and surviving selections produce {char,id,label} references alongside existing text/mentionIds; references is optional in the type for legacy constructed submissions and always present on component submissions. Editing a token invalidates its reference.
440
440
 
441
441
  **Actions.** Button, ButtonLink, IconButton, SplitButton, LoadMoreButton, ClearButton, CopyButton, FilterChip, Link, Toolbar.
442
442
 
443
443
  - Button carries the action. ButtonLink navigates but reads as a button, for a page-level call to action. Link reads as text, inside a sentence. Substituting one for another makes the page read wrong.
444
444
  - SplitButton is a primary action with an adjacent menu whose first entry mirrors it. Do not use it to hide unrelated actions behind a chevron.
445
- - FilterChip opens a consumer-owned filter picker; undefined means unset, other values mean set. Its 28px pill uses a dashed border-strong outline with CirclePlus when unset, and a solid outline with label, border-token divider, action-text value and ChevronDown when set. The optional leading CircleX clear action is a separate named native button before the picker, with its own Tab stop and shared focus ring.
445
+ - FilterChip opens a consumer-owned filter picker; undefined means unset, other values mean set. Its default sm 32px pill uses a dashed border-strong outline with CirclePlus when unset, and a solid outline with label, border-token divider, action-text value and ChevronDown when set. The optional leading CircleX clear action is a separate named native button before the picker, with its own Tab stop and shared focus ring.
446
+ - FilterOptionPanel is searchable single-select content inside Popover, usually anchored by FilterChip. It owns initial search focus, named combobox/listbox, active-descendant arrow navigation with disabled skipping, loading/error/retry/empty/no-match states, and label/keywords includes filtering. Callers own selection, closing, business ranking and async queries through controlled query/onQueryChange and an injected filter; Escape dismissal and trigger focus return stay with Popover. It does not provide multiselect or an application footer.
446
447
  - IconButton requires an accessible name. An icon-only control without one is not deliverable.
447
448
 
448
449
  **Text fields.** FormField, Label, Input, ClearableInput, SearchInput, InputOTP, Textarea, Select, Fieldset, ErrorMessage.
449
450
 
450
451
  - InputOTP collects a fixed six-digit code in one joined group by default; `separator` explicitly enables 3+3 groups. VerificationCodeInput and VerificationCodeInputProps remain deprecated aliases for one minor version; migrate to InputOTP and InputOTPProps before their removal in the next minor version. The old `/components/verification-code-input` route redirects to `/components/input-otp`.
451
452
  - FormField owns the label, help text, and error slot. Do not assemble those three around a bare Input.
453
+ - `labelHidden` defaults to false. For a single inline field already named by context, it visually hides the real associated label through `q1-sr-only` without reserving a label row or gap; description, visible error, and `aria-describedby` remain unchanged. A label is still required; bare mode rejects `labelHidden`. Input’s existing string `hideLabel` still names the password hide action.
454
+ - FormField positions its visually hidden label and empty live status within its own containing block so an overflowing inline row cannot enlarge the page scroll width.
452
455
  - Select is for a short, fixed list. Anything searchable, or longer than roughly seven entries, is a Combobox.
453
456
 
454
457
  **Option fields.** ControlOption, Checkbox, Radio, Choicebox, Combobox, MultiSelect, Switch, Toggle, ToggleGroup, Slider, RangeSlider.
@@ -463,7 +466,7 @@ Static WCAG stroke contrast against canvas/panel (2026-10-07): light neutral 5.3
463
466
 
464
467
 
465
468
  - Toggle represents one on/off setting and reports a requested change immediately. Square Checkbox stages a form change that a submit applies; circle Checkbox marks task completion through the consumer’s change handler. Choosing the wrong one misstates when the change takes effect.
466
- - Switch selects among mutually exclusive views or modes.
469
+ - Switch selects among mutually exclusive views or modes; its outer sm / md / lg heights are 32 / 40 / 48px on fine pointers, defaulting to md.
467
470
  - ToggleGroup uses pressed buttons for single or multiple choices; arrow keys move focus without selecting. Icon-only items require an accessible name. See `implementation-map.md` for selection ownership.
468
471
  - RangeSlider is two thumbs over one interval, paired with numeric inputs; Slider is a single value.
469
472
 
@@ -619,3 +622,7 @@ Before delivery, confirm each of these. They are observable; none of them is a m
619
622
  In this repository, `npm run check` is the full gate; a partial run is not a pass. In consuming repositories, run their design and token gates before reporting completion.
620
623
 
621
624
  公开 Foundation 集成:`getOverlayCoordinator` 协调 package 与宿主 overlay 的栈序、inert 与滚动锁;契约见 [Overlay Foundation](./overlay-foundation.md#11-o3-公开-host-协调扩展2026-09-08)。
625
+
626
+ ### 单行控件尺寸
627
+
628
+ 显式 sm / md / lg 的单行控件与 Button 对齐为 32 / 40 / 48px;使用现有 `--q1-space-8`、`--q1-control-height-default` 与 `--q1-space-2`。SearchInput 与 Menu 文字触发器默认 md,FilterChip 默认 sm32,Switch 外框 sm / md / lg 同高 32 / 40 / 48px,默认 md。Calendar 的 size 只控制网格,触发器使用 fieldSize。空或缺省 label 不创建可见标签行,消费方须提供可访问名称。粗指针最小 44px 命中规则保持现有契约。
@@ -436,19 +436,22 @@ These components ship in the package. Compose from this list before writing new
436
436
 
437
437
  **Chat messages.** Bubble (incoming/outgoing, optional avatar/name/time, controlled pending/error and retry/actions slots) and MessageScroller (stable keyed items, near-bottom following, streaming growth, prepend anchor preservation, conversationKey reset, named native jump button and separate polite new-message announcements) are public components. They reuse existing tokens and Button; Message and Scroller APIs remain unchanged. Tier B uses native keyboard scrolling and buttons; callers own constrained height, message data, streaming, Markdown, tool cards, history cursors, permissions and network recovery.
438
438
 
439
- **Record activity.** Timeline, TimelineItem, TimelineCollapsedGroup, Marker, Message, Mention, Composer, Attachment. Timeline uses chronological ol/li with tone dots or Avatar; TimelineCollapsedGroup uses a native disclosure for consecutive system events; Marker keeps system events quiet and dates centered. Message supports pending/failed and caller actions; Mention renders caller-owned inline member references using action-text and the selected surface. Composer is a textarea combobox with listbox mentions, Enter sends and Shift+Enter inserts a newline; IME composition never sends or picks. Attachment reuses Progress and named removal. Network, permissions and notifications remain caller-owned.
439
+ **Record activity.** Timeline, TimelineItem, TimelineCollapsedGroup, Marker, Message, Mention, Composer, Attachment. Timeline uses chronological ol/li with tone dots or Avatar; TimelineCollapsedGroup uses a native disclosure for consecutive system events; Marker keeps system events quiet and dates centered. Message supports pending/failed and caller actions; Mention renders caller-owned inline member references using action-text and the selected surface. Composer is a textarea combobox with listbox mentions, Enter sends and Shift+Enter inserts a newline; IME composition never sends or picks. Composer also accepts `onMentionQuery(query, {signal})` with 200ms debounce, abort/stale-result rejection, loading/empty/error states and keyboard retry; async lookup takes precedence over static members. Optional `placeholder` and `hint` preserve the input label; member instructions appear only with mention support. Han text may directly precede @, while Unicode word/email interiors do not trigger. Selection inserts text and sets the caret synchronously. Attachment reuses Progress and named removal. Network, permissions and notifications remain caller-owned. Composer accepts optional `triggers` ({char,label,options?,onQuery?,emptyText?,errorText?,toToken?}); single-symbol triggers share debounce, abort/stale rejection, statuses, retry, combobox/listbox keyboard and synchronous caret insertion. Explicit @ overrides legacy mentions/onMentionQuery; otherwise they remain an implicit @ trigger. Slash is reserved for unchanged commands and rejected as a trigger with a development warning. Enabled triggers alone appear in the default hint. Han text may directly precede any trigger; word/email interiors do not trigger. Selection inserts toToken(item), defaulting to char + label, and surviving selections produce {char,id,label} references alongside existing text/mentionIds; references is optional in the type for legacy constructed submissions and always present on component submissions. Editing a token invalidates its reference.
440
440
 
441
441
  **Actions.** Button, ButtonLink, IconButton, SplitButton, LoadMoreButton, ClearButton, CopyButton, FilterChip, Link, Toolbar.
442
442
 
443
443
  - Button carries the action. ButtonLink navigates but reads as a button, for a page-level call to action. Link reads as text, inside a sentence. Substituting one for another makes the page read wrong.
444
444
  - SplitButton is a primary action with an adjacent menu whose first entry mirrors it. Do not use it to hide unrelated actions behind a chevron.
445
- - FilterChip opens a consumer-owned filter picker; undefined means unset, other values mean set. Its 28px pill uses a dashed border-strong outline with CirclePlus when unset, and a solid outline with label, border-token divider, action-text value and ChevronDown when set. The optional leading CircleX clear action is a separate named native button before the picker, with its own Tab stop and shared focus ring.
445
+ - FilterChip opens a consumer-owned filter picker; undefined means unset, other values mean set. Its default sm 32px pill uses a dashed border-strong outline with CirclePlus when unset, and a solid outline with label, border-token divider, action-text value and ChevronDown when set. The optional leading CircleX clear action is a separate named native button before the picker, with its own Tab stop and shared focus ring.
446
+ - FilterOptionPanel is searchable single-select content inside Popover, usually anchored by FilterChip. It owns initial search focus, named combobox/listbox, active-descendant arrow navigation with disabled skipping, loading/error/retry/empty/no-match states, and label/keywords includes filtering. Callers own selection, closing, business ranking and async queries through controlled query/onQueryChange and an injected filter; Escape dismissal and trigger focus return stay with Popover. It does not provide multiselect or an application footer.
446
447
  - IconButton requires an accessible name. An icon-only control without one is not deliverable.
447
448
 
448
449
  **Text fields.** FormField, Label, Input, ClearableInput, SearchInput, InputOTP, Textarea, Select, Fieldset, ErrorMessage.
449
450
 
450
451
  - InputOTP collects a fixed six-digit code in one joined group by default; `separator` explicitly enables 3+3 groups. VerificationCodeInput and VerificationCodeInputProps remain deprecated aliases for one minor version; migrate to InputOTP and InputOTPProps before their removal in the next minor version. The old `/components/verification-code-input` route redirects to `/components/input-otp`.
451
452
  - FormField owns the label, help text, and error slot. Do not assemble those three around a bare Input.
453
+ - `labelHidden` defaults to false. For a single inline field already named by context, it visually hides the real associated label through `q1-sr-only` without reserving a label row or gap; description, visible error, and `aria-describedby` remain unchanged. A label is still required; bare mode rejects `labelHidden`. Input’s existing string `hideLabel` still names the password hide action.
454
+ - FormField positions its visually hidden label and empty live status within its own containing block so an overflowing inline row cannot enlarge the page scroll width.
452
455
  - Select is for a short, fixed list. Anything searchable, or longer than roughly seven entries, is a Combobox.
453
456
 
454
457
  **Option fields.** ControlOption, Checkbox, Radio, Choicebox, Combobox, MultiSelect, Switch, Toggle, ToggleGroup, Slider, RangeSlider.
@@ -463,7 +466,7 @@ Static WCAG stroke contrast against canvas/panel (2026-10-07): light neutral 5.3
463
466
 
464
467
 
465
468
  - Toggle represents one on/off setting and reports a requested change immediately. Square Checkbox stages a form change that a submit applies; circle Checkbox marks task completion through the consumer’s change handler. Choosing the wrong one misstates when the change takes effect.
466
- - Switch selects among mutually exclusive views or modes.
469
+ - Switch selects among mutually exclusive views or modes; its outer sm / md / lg heights are 32 / 40 / 48px on fine pointers, defaulting to md.
467
470
  - ToggleGroup uses pressed buttons for single or multiple choices; arrow keys move focus without selecting. Icon-only items require an accessible name. See `implementation-map.md` for selection ownership.
468
471
  - RangeSlider is two thumbs over one interval, paired with numeric inputs; Slider is a single value.
469
472
 
@@ -475,7 +478,7 @@ Static WCAG stroke contrast against canvas/panel (2026-10-07): light neutral 5.3
475
478
  - Popover is a named anchored dialog for interactive content; it supports controlled/default open, four-side collision positioning plus controlled anchorRef placement, menu/listbox role focus, width matching, Escape focus return and outside pointer-down dismissal. Keyboard opening moves focus into content; pointer opening retains trigger focus and Tab enters the panel. It is nonmodal by default; opt-in modal locks the background and traps focus. ensurePopoverRoot exposes the same shared Foundation host for consumer-owned sibling portals; dismissExcludeRefs and nested panels preserve parent dismissal boundaries.
476
479
  - Modal blocks and demands an answer. Use it for confirmation, not for a long form; a long form belongs in a Drawer or its own route.
477
480
  - DestructiveActionModal is the required shape for irreversible actions. Do not rebuild that confirmation from a plain Modal.
478
- - Sheet slides in from an edge with a focus trap; opt-in `mobileFullscreen` fills narrow viewports with safe-area padding and no outer inset or radius, while default floating spacing remains unchanged; Drawer is the wider panel form. Menu is anchored and flips on collision; ContextMenu and DotsMenu share its keyboard engine.
481
+ - Sheet slides in from an edge with a focus trap; opt-in `mobileFullscreen` fills narrow viewports with safe-area padding and no outer inset or radius, while default floating spacing remains unchanged; Drawer is the wider panel form. Menu is anchored and flips on collision; ContextMenu and DotsMenu share its keyboard engine. DotsMenu accepts contextual `label` (default 更多操作) for trigger and menu, plus `{type:'separator'}` entries using the shared Menu separator; roving focus and typeahead skip separators and disabled items.
479
482
  - Tooltip carries a short label for a control. Anything a reader must read to decide belongs in the page or in a ContextCard.
480
483
 
481
484
  **Data and evidence.** Table, Pagination, DocsPagination, ShowMore, Chart, Gauge, Progress, JsonView, Entity, Description, RelativeTimeCard.
@@ -619,3 +622,7 @@ Before delivery, confirm each of these. They are observable; none of them is a m
619
622
  In this repository, `npm run check` is the full gate; a partial run is not a pass. In consuming repositories, run their design and token gates before reporting completion.
620
623
 
621
624
  公开 Foundation 集成:`getOverlayCoordinator` 协调 package 与宿主 overlay 的栈序、inert 与滚动锁;契约见 [Overlay Foundation](./overlay-foundation.md#11-o3-公开-host-协调扩展2026-09-08)。
625
+
626
+ ### 单行控件尺寸
627
+
628
+ 显式 sm / md / lg 的单行控件与 Button 对齐为 32 / 40 / 48px;使用现有 `--q1-space-8`、`--q1-control-height-default` 与 `--q1-space-2`。SearchInput 与 Menu 文字触发器默认 md,FilterChip 默认 sm32,Switch 外框 sm / md / lg 同高 32 / 40 / 48px,默认 md。Calendar 的 size 只控制网格,触发器使用 fieldSize。空或缺省 label 不创建可见标签行,消费方须提供可访问名称。粗指针最小 44px 命中规则保持现有契约。
@@ -15,7 +15,8 @@ README owns the repository inventory and generated-file boundary. This file owns
15
15
  | Mobile full-viewport details | Opt-in Sheet mobileFullscreen | `Sheet` | Existing spacing/radius/surface tokens and safe-area env | Default floating inset and overlay lifecycle preserved | Narrow viewport opt-in removes inset/radius and fills viewport | Existing focus trap, Escape and return focus |
16
16
  | Hoverable supplemental information | Read-only member or role preview | `HoverCard`, shared anchored overlay foundation | Panel background, popover shadow, radius, spacing and motion tokens | Fine-pointer hover or keyboard focus; configurable 0ms open / 90ms close; card entry cancels close; Escape dismissal; trigger click preserved | Shared collision positioning and portal; coarse/touch hover ignored | Named native trigger, aria-describedby tooltip, no focus transfer or trap, reduced motion |
17
17
  | Anchored interactive content | Consumer-owned inline dialog | `Popover`, `ensurePopoverRoot`, `FilterChip`, shared overlay foundation | Panel background, popover shadow, radius, spacing and motion tokens | Controlled/default open or external anchorRef (FilterChip ref forwards to picker); menu/listbox role focus; nested/excluded targets, focusout and anchor visibility dismissal; retained exit animation | Four-side collision plus auto/fixed placement; preferred-height flip, viewport clamp, matchWidth and ancestor scroll; fixed shared portal | Named dialog, expanded/controls wiring, focus return; opt-in modal trap |
18
- | Compact dashboard filters | Consumer-owned filter picker | `FilterChip` | `--q1-space-7` (28px), border-strong, text-secondary, action-text, shared focus | Unset dashed CirclePlus; set solid leading CircleX clear, label, divider, value and ChevronDown | Ellipsis bounds long values; shared TouchTarget preserves coarse 44px targets | Sibling native buttons, clear before picker in Tab order, focus returns to picker |
18
+ | Compact dashboard filters | Consumer-owned filter picker | `FilterChip` | `--q1-space-8` (default sm32), border-strong, text-secondary, action-text, shared focus | Unset dashed CirclePlus; set solid leading CircleX clear, label, divider, value and ChevronDown | Ellipsis bounds long values; shared TouchTarget preserves coarse 44px targets | Sibling native buttons, clear before picker in Tab order, focus returns to picker |
19
+ | Searchable filter choices | Consumer-owned single-select content | `FilterOptionPanel`, `Popover`, `FilterChip` | Existing control, surface, text, radius, spacing and focus tokens | Label/keywords includes or injected filter; controlled query; loading/error/retry/empty/no-match; select callback | Viewport-bound width and scroll list; coarse option height | Named combobox/listbox, initial search focus, aria-activedescendant, disabled skipping; Popover Escape returns to anchor |
19
20
  | Compact search and command menu | Fast documentation navigation | `CommandMenu`, `Topbar` search trigger | Surface, border, text, focus tokens | Open, active option, escape close | Dialog width clamps on small screens | `role="dialog"`, `aria-modal`, keyboard navigation |
20
21
  | Foundation page rhythm | Scannable reference pages | `PageHeader`, `SpecSection`, `SpecTable` | Heading, copy, border, spacing tokens | None beyond links and focus | Tables scroll horizontally when needed | Semantic headings and tables |
21
22
  | Introduction tile grid | Entry points into public groups | `IntroTileGrid`, `IntroTile` | Surface, border, text, spacing tokens | Hover, focus | Two columns on desktop, one column on small screens | Tile is a single link with hidden decorative visual |
@@ -75,7 +76,7 @@ Command Menu cycles Tab between its search input and sole Esc keycap close butto
75
76
  commands use text without leading arrows and space-8 + space-1 row height. Multi Select
76
77
  options use background-only focus feedback; its bulk text action is compact and neutral,
77
78
  with no divider. Coarse-pointer targets retain the existing 44px minimum; the compact
78
- Command Menu close button uses the shared TouchTarget hit region.
79
+ Command Menu close button uses the shared TouchTarget hit region. DotsMenu accepts contextual `label` (default 更多操作) for trigger and menu, plus `{type:'separator'}` entries using the shared Menu separator; roving focus and typeahead skip separators and disabled items.
79
80
 
80
81
  Context Switcher identifies the current context with a neutral check and regular-weight
81
82
  labels, without selected fill or a stronger selected press layer. File Tree starts with
@@ -99,7 +100,7 @@ does not pull focus from the activated button. Consumers own URL synchronization
99
100
 
100
101
  ## Record activity (owner approved 2026-10-06)
101
102
 
102
- Timeline / TimelineItem (ol/li, 8px token dot or Avatar), Marker (quiet actor/time, date separator), Message (default/pending/failed, caller actions) / Mention (inline action-text on selected surface), Composer (Tier A textarea combobox/listbox, IME guard, Enter send / Shift+Enter newline), Attachment (Progress, retry/remove) are public package components. TimelineCollapsedGroup uses a native disclosure button with aria-expanded and Enter/Space; callers group runs of consecutive system events (docs example uses three or more). Marker unread uses centered action text; caller places and scrolls to the boundary. Message acknowledgements and its caller-owned actions slot display receipt state. Composer commands share the mention combobox/listbox keyboard model and IME guard; known slash commands invoke onCommand instead of onSubmit. Attachment paste/drop passes File[] to onAttach; legacy clicks remain argument-free. Callers own the file picker and object URLs and revoke previews on removal or unmount. Existing tokens only; data, permissions, network and notifications remain caller-owned.
103
+ Timeline / TimelineItem (ol/li, 8px token dot or Avatar), Marker (quiet actor/time, date separator), Message (default/pending/failed, caller actions) / Mention (inline action-text on selected surface), Composer (Tier A textarea combobox/listbox, IME guard, Enter send / Shift+Enter newline), Attachment (Progress, retry/remove) are public package components. TimelineCollapsedGroup uses a native disclosure button with aria-expanded and Enter/Space; callers group runs of consecutive system events (docs example uses three or more). Marker unread uses centered action text; caller places and scrolls to the boundary. Message acknowledgements and its caller-owned actions slot display receipt state. Composer also accepts `onMentionQuery(query, {signal})` with 200ms debounce, abort/stale-result rejection, loading/empty/error states and keyboard retry; async lookup takes precedence over static members. Optional `placeholder` and `hint` preserve the input label; member instructions appear only with mention support. Han text may directly precede @, while Unicode word/email interiors do not trigger. Selection inserts text and sets the caret synchronously. Composer commands share the mention combobox/listbox keyboard model and IME guard; known slash commands invoke onCommand instead of onSubmit. Attachment paste/drop passes File[] to onAttach; legacy clicks remain argument-free. Callers own the file picker and object URLs and revoke previews on removal or unmount. Existing tokens only; data, permissions, network and notifications remain caller-owned. Composer accepts optional `triggers` ({char,label,options?,onQuery?,emptyText?,errorText?,toToken?}); single-symbol triggers share debounce, abort/stale rejection, statuses, retry, combobox/listbox keyboard and synchronous caret insertion. Explicit @ overrides legacy mentions/onMentionQuery; otherwise they remain an implicit @ trigger. Slash is reserved for unchanged commands and rejected as a trigger with a development warning. Enabled triggers alone appear in the default hint. Han text may directly precede any trigger; word/email interiors do not trigger. Selection inserts toToken(item), defaulting to char + label, and surviving selections produce {char,id,label} references alongside existing text/mentionIds; references is optional in the type for legacy constructed submissions and always present on component submissions. Editing a token invalidates its reference.
103
104
  Timeline / TimelineItem (ol/li, 8px token dot or Avatar), Marker (quiet actor/time, date separator), Message (default/pending/failed, caller actions) / Mention (inline action-text on selected surface), Composer (Tier A textarea combobox/listbox, IME guard, Enter send / Shift+Enter newline), Attachment (Progress, retry/remove) are public package components. `/patterns/record-activity` composes order facts, Switch, chronological activity and a pinned Composer. Existing tokens only; data, permissions, network and notifications remain caller-owned.
104
105
 
105
106
  ## ToggleGroup selection ownership
@@ -126,3 +127,11 @@ The consumer mapping was checked against q1travel-web origin/main: `src/componen
126
127
  | conversation switching / new conversation | conversationKey resets follow state, visible anchor and announcement |
127
128
  | scroll-to-latest and streaming narration | named jumpLabel button, labelled region, separate polite announcement; caller can pass completed-turn text or empty announcement to silence |
128
129
  Keyboard: native viewport Arrow/PageUp/PageDown/Home/End; Tab reaches the viewport and buttons; Enter/Space activates retry or jump. Jump moves focus to the viewport before its button disappears. No custom composite widget keyboard model is introduced.
130
+
131
+ ## Hidden field labels
132
+
133
+ Owner approved 2026-10-08: additive `labelHidden?: boolean` (default false) keeps a real associated label through `q1-sr-only` while removing its visual row and gap. Input, Textarea, Select, InputOTP and Checkbox/Radio (including circular Checkbox) expose the shell option; bare mode rejects it. SearchInput and Combobox compositions use `FormField labelHidden`, preserving their existing APIs. Calendar/RangeField does not consume FieldShellProps and retains its existing date-trigger behavior. Errors and descriptions remain visible and connected through `aria-describedby`. Input's existing string `hideLabel` remains the password hide-action copy.
134
+
135
+ `FormField` establishes a relative containing block for hidden labels and empty status regions. Package consumer fixtures enforce label ownership, SSR contracts cover names/messages, and `scripts/lib/check-label-hidden-browser.mjs` checks native labels, visible errors, inline Button alignment and a deterministic 390px scrollable max-content row without page overflow.
136
+ ## Control density scale
137
+ Owner approved 2026-10-08: explicitly sized single-line Button, ButtonLink, Input, SearchInput, Select, RangeField trigger, Menu text trigger and FilterChip share sm32 / md40 / lg48 on fine pointers. SearchInput defaults to md and retains native numeric size compatibility; FilterChip defaults to sm32. Menu text triggers default to md40 after the rendered fine-pointer audit confirmed the prior omitted-size trigger measured 38–39px; icon triggers retain their prior behavior. Calendar size remains grid-only; fieldSize controls its trigger. Switch outer sm / md / lg heights align to 32 / 40 / 48px, defaulting to md; coarse-pointer 44px rules remain unchanged. FormField and Select omit empty or absent visible labels; callers supply aria-label, aria-labelledby or a native external label. Select reuses the development-only bare-field accessible-name warning.
@@ -24,7 +24,7 @@ Adding a clause therefore means answering two questions before the wording: who
24
24
  - [both] MUST use native links for navigation and native buttons for actions.
25
25
  - [both] MUST keep visual and hit targets aligned; controls smaller than 24px need a larger interactive area.
26
26
  - [both] MUST keep mobile control targets at least 44px where touch is expected.
27
- - [both] MUST use `--q1-touch-target-min` (44px) for the shared centered invisible child-span hit region of Button (all sizes, including compact consumer overrides and icon-only), CopyButton, Menu/DotsMenu triggers, Description info/hint buttons, and the independent FilterChip picker/clear buttons only under `(pointer: coarse), (any-pointer: coarse)`. Preserve every existing coarse-pointer visual-size rule. Only axes still below the minimum receive extra hit area; existing 44px targets do not expand outside their visual frame. The region covers the complete border box: canonical Button/CopyButton/Menu/DotsMenu borders are 1px, while Description borders are none. Consumers overriding a control border width must also set its private `--touch-target-border-width` to the actual per-side width (including zero for `border: none`); asymmetric borders need their own hit-region sizing. FilterChip keeps its 28px visual height and existing gaps/margins; its picker and clear hit regions must not overlap. Menu item rows use a real `min-height: var(--q1-touch-target-min)` under the same coarse-pointer query so neighboring rows remain independent. Focus rings stay on the visual control; child hit-region events activate that native control without replacing its pseudo-elements or overflow rules.
27
+ - [both] MUST use `--q1-touch-target-min` (44px) for the shared centered invisible child-span hit region of Button (all sizes, including compact consumer overrides and icon-only), CopyButton, Menu/DotsMenu triggers, Description info/hint buttons, and the independent FilterChip picker/clear buttons only under `(pointer: coarse), (any-pointer: coarse)`. Preserve every existing coarse-pointer visual-size rule. Only axes still below the minimum receive extra hit area; existing 44px targets do not expand outside their visual frame. The region covers the complete border box: canonical Button/CopyButton/Menu/DotsMenu borders are 1px, while Description borders are none. Consumers overriding a control border width must also set its private `--touch-target-border-width` to the actual per-side width (including zero for `border: none`); asymmetric borders need their own hit-region sizing. FilterChip keeps its default sm32 visual height and existing gaps/margins; its picker and clear hit regions must not overlap. Menu item rows use a real `min-height: var(--q1-touch-target-min)` under the same coarse-pointer query so neighboring rows remain independent. Focus rings stay on the visual control; child hit-region events activate that native control without replacing its pseudo-elements or overflow rules.
28
28
  - [both] MUST leave enough space for expanded targets: dense neighbors must not overlap each other's visual frames. Consumers must reserve the expansion on each side and avoid clipping ancestors; if this is impossible, regroup controls or use larger visual controls. The shared region cannot infer neighbor gaps or escape control/ancestor clipping; clipped compact controls must use a visual size of at least 44px.
29
29
  - [both] SHOULD deliberately depart from Geist's measured 24–32px controls without coarse-pointer enlargement: Apple HIG's 44pt guidance and WCAG 2.5.5 motivate q1travel's 44×44 CSS-pixel mobile usability target; pt and CSS pixels are different units.
30
30
  - [both] NEVER disable browser zoom.
@@ -209,7 +209,7 @@ Theming owns tokens and `color-scheme`; the interaction-contrast rule lives in D
209
209
  - [both] SHOULD resolve data states in the order loading → error → empty → content.
210
210
  - [both] SHOULD give every flow a way forward and a way back (「取消」「返回」), and confirm costly or hard-to-reverse actions before running them.
211
211
 
212
- These copy clauses follow the actual Stripe Chinese Dashboard for reader address and empty-state copy: address the reader as 「您」, omit trailing punctuation from empty-state titles, and explain when content will appear in the description.
212
+ These copy clauses keep reader address and empty states consistent with a formal business console: address the reader as 「您」, omit trailing punctuation from empty-state titles, and explain when content will appear in the description.
213
213
 
214
214
  ### Component Naming
215
215
 
@@ -218,7 +218,7 @@ These copy clauses follow the actual Stripe Chinese Dashboard for reader address
218
218
 
219
219
  ### Component Documentation Pages
220
220
 
221
- Component pages follow one skeleton so a reader who has used one page can find the same thing on every other. The shape follows the Stripe Apps component reference: one sentence says what the component is for, the fixed sections sit in a fixed order, and only the feature sections in the middle vary by component. Shared terms live in `.agents/skills/product-design/references/glossary.md`.
221
+ Component pages follow one skeleton so a reader who has used one page can find the same thing on every other. The shape keeps every page predictable: one sentence says what the component is for, the fixed sections sit in a fixed order, and only the feature sections in the middle vary by component. Shared terms live in `.agents/skills/product-design/references/glossary.md`.
222
222
 
223
223
  - [repo] MUST open each component page with one sentence that says what a reader uses the component for. It names no props, no implementation, and no 「输入…输出…」 pairing.
224
224
  - [repo] MUST keep the fixed sections in this order: examples first, then feature sections, then 「API」, then 「使用原则」, then 「可访问性」 where the page has one, then 「另请参阅」 as the last section.
@@ -61,7 +61,7 @@ This contract applies to the current known-total and unknown-tail models. A futu
61
61
 
62
62
  ### Loading, focus, and completion
63
63
 
64
- - While `loading` is true, the pagination `nav` exposes `aria-busy="true"` and the existing Spinner exposes the polite status text `加载中…`.
64
+ - While `loading` is true, the pagination `nav` exposes `aria-busy="true"` and the existing Spinner exposes the polite status text `正在加载…`.
65
65
  - Structural boundary controls and empty-state controls remain natively disabled.
66
66
  - Actionable pagination controls remain focusable while loading and expose `aria-disabled="true"`. Their click and keyboard handlers are inert until loading ends. This preserves the user's current focus rather than moving focus to a newly rendered control.
67
67
  - The current-page marker and `aria-current="page"` remain stable while loading.
@@ -70,7 +70,7 @@ This contract applies to the current known-total and unknown-tail models. A futu
70
70
  ### Responsive and unavailable states
71
71
 
72
72
  - `compact` and the existing tokenized responsive layout own dense and narrow presentation; the shared semantics do not change at smaller widths.
73
- - `total={0}` exposes the existing `暂无数据` summary and does not fabricate page numbers.
73
+ - `total={0}` exposes the existing `没有数据` summary and does not fabricate page numbers.
74
74
  - Error or unavailable presentation is consumer-owned composition around `Pagination` (for example, an adjacent alert and a disabled/empty pagination state); #111 does not add an `error` or `unavailable` prop.
75
75
 
76
76
  ### Required evidence
@@ -40,7 +40,7 @@ export declare function AuthCard({ title, description, action, className }: Auth
40
40
  /** Focused presentational card for account entry and connection flows. */
41
41
  export declare interface AuthCardProps {
42
42
  title: ReactNode;
43
- description: ReactNode;
43
+ description?: ReactNode;
44
44
  action?: ReactNode;
45
45
  className?: string;
46
46
  }
@@ -307,7 +307,7 @@ declare type ButtonSharedProps = {
307
307
  selected?: boolean;
308
308
  /** 载入态:禁点 + 保留可聚焦 + spinner 的 role=status 播报;不改变控件尺寸。 */
309
309
  loading?: boolean;
310
- /** loading 时 role=status 播报的文案,默认"加载中…";仅供屏幕阅读器,不影响可见文案。 */
310
+ /** loading 时 role=status 播报的文案,默认"正在加载…";仅供屏幕阅读器,不影响可见文案。 */
311
311
  loadingLabel?: string;
312
312
  /** 已提交忙态:原生禁用 + aria-busy,阻止重复提交。 */
313
313
  busy?: boolean;
@@ -426,7 +426,7 @@ declare type CheckboxOnlyProps = {
426
426
  };
427
427
 
428
428
  /** Checkbox 的完整 props。消费方包一层时用它标注,无需知道内部由哪几块组合而成。 */
429
- export declare type CheckboxProps = ControlOptionOwnProps & (FieldShellProps | FieldBareProps) & CheckboxOnlyProps & {
429
+ export declare type CheckboxProps = ControlOptionOwnProps & (FieldShellProps | FieldBareProps) & FieldLabelVisibilityProps & CheckboxOnlyProps & {
430
430
  /** 圆形仅用于任务与清单完成;表单多选保留默认方形。 */
431
431
  shape?: 'square' | 'circle';
432
432
  /** 仅圆形生效;业务方自行映射优先级。 */
@@ -628,7 +628,7 @@ export declare type CommandMenuSection = {
628
628
  items: CommandMenuItem[];
629
629
  };
630
630
 
631
- export declare function Composer({ onSubmit, onAttach, attachments, mentions, commands, onCommand, disabled, }: ComposerProps): JSX.Element;
631
+ export declare function Composer({ onSubmit, onAttach, attachments, mentions, onMentionQuery, placeholder, triggers, hint, commands, onCommand, disabled, }: ComposerProps): JSX.Element;
632
632
 
633
633
  export declare type ComposerCommand = ComposerMention & {
634
634
  keywords?: string[];
@@ -647,12 +647,33 @@ export declare type ComposerProps = {
647
647
  onCommand?: (id: string, argumentText: string) => void;
648
648
  attachments?: ReactNode;
649
649
  mentions?: ComposerMention[];
650
+ triggers?: ComposerTrigger[];
651
+ onMentionQuery?: MentionQuery;
652
+ placeholder?: string;
653
+ hint?: ReactNode;
650
654
  disabled?: boolean;
651
655
  };
652
656
 
657
+ export declare type ComposerReference = {
658
+ char: string;
659
+ id: string;
660
+ label: string;
661
+ };
662
+
653
663
  export declare type ComposerSubmission = {
654
664
  text: string;
655
665
  mentionIds: string[];
666
+ references?: ComposerReference[];
667
+ };
668
+
669
+ export declare type ComposerTrigger = {
670
+ char: string;
671
+ label: string;
672
+ options?: ComposerMention[];
673
+ onQuery?: MentionQuery;
674
+ emptyText?: string;
675
+ errorText?: string;
676
+ toToken?: (item: ComposerMention) => string;
656
677
  };
657
678
 
658
679
  export declare function ContextCard({ name, identity, rows, action, onAction, actionHref, placement, align, children, }: ContextCardProps): JSX.Element;
@@ -798,7 +819,7 @@ export declare type ContextSwitcherSearch = {
798
819
  noResults: ContextSwitcherEmptyState;
799
820
  };
800
821
 
801
- export declare function ControlOption({ id, label, description, error, indeterminate, ref, type, 'aria-describedby': ariaDescribedBy, 'aria-invalid': ariaInvalid, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, onClick, ...rest }: ControlOptionProps): JSX.Element;
822
+ export declare function ControlOption({ id, label, labelHidden, description, error, indeterminate, ref, type, 'aria-describedby': ariaDescribedBy, 'aria-invalid': ariaInvalid, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, onClick, ...rest }: ControlOptionProps): JSX.Element;
802
823
 
803
824
  declare type ControlOptionNativeInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'id' | 'type'>;
804
825
 
@@ -810,7 +831,7 @@ declare type ControlOptionOwnProps = {
810
831
  };
811
832
 
812
833
  /** ControlOption 的完整 props(Checkbox / Radio 的共同底座,须显式给 type)。 */
813
- export declare type ControlOptionProps = ControlOptionOwnProps & (FieldShellProps | FieldBareProps) & CheckboxOnlyProps & {
834
+ export declare type ControlOptionProps = ControlOptionOwnProps & (FieldShellProps | FieldBareProps) & FieldLabelVisibilityProps & CheckboxOnlyProps & {
814
835
  type: 'checkbox' | 'radio';
815
836
  } & ControlOptionNativeInputProps;
816
837
 
@@ -868,14 +889,18 @@ export declare type DocsPaginationProps = {
868
889
  next?: DocsPageLink;
869
890
  };
870
891
 
871
- export declare function DotsMenu({ entries, size, disabled, align, }: {
892
+ export declare function DotsMenu({ entries, size, disabled, align, label, }: {
872
893
  entries: DotsMenuEntry[];
894
+ label?: string;
873
895
  size?: 'sm' | 'md' | 'lg';
874
896
  disabled?: boolean;
875
897
  align?: 'start' | 'end';
876
898
  }): JSX.Element;
877
899
 
878
900
  export declare type DotsMenuEntry = {
901
+ type: 'separator';
902
+ } | {
903
+ type?: 'item';
879
904
  label: string;
880
905
  disabled?: boolean;
881
906
  danger?: boolean;
@@ -967,9 +992,17 @@ declare type FieldBareProps = {
967
992
  error?: never;
968
993
  };
969
994
 
995
+ export declare type FieldLabelVisibilityProps = {
996
+ label: string;
997
+ labelHidden?: boolean;
998
+ } | {
999
+ label?: never;
1000
+ labelHidden?: never;
1001
+ };
1002
+
970
1003
  export declare function Fieldset({ title, subtitle, tone, footerStatus, footerAction, disabled, children, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, }: {
971
1004
  title?: string;
972
- subtitle: string;
1005
+ subtitle?: ReactNode;
973
1006
  tone?: FieldsetTone;
974
1007
  footerStatus?: ReactNode;
975
1008
  footerAction?: ReactNode;
@@ -1006,6 +1039,8 @@ export declare type FileTreeNode = {
1006
1039
  /** 筛选选择器入口;弹层、筛选值与 expanded 状态归调用方。 */
1007
1040
  export declare const FilterChip: ForwardRefExoticComponent< {
1008
1041
  label: string;
1042
+ /** 可选同高尺寸;默认 sm(32px)胶囊。 */
1043
+ size?: ButtonSize;
1009
1044
  /** undefined 表示未设置;0、空字符串和 null 仍是已设置。 */
1010
1045
  value?: ReactNode;
1011
1046
  onClear?: () => void;
@@ -1013,19 +1048,49 @@ onClear?: () => void;
1013
1048
 
1014
1049
  export declare type FilterChipProps = {
1015
1050
  label: string;
1051
+ /** 可选同高尺寸;默认 sm(32px)胶囊。 */
1052
+ size?: ButtonSize;
1016
1053
  /** undefined 表示未设置;0、空字符串和 null 仍是已设置。 */
1017
1054
  value?: ReactNode;
1018
1055
  onClear?: () => void;
1019
1056
  } & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'value'>;
1020
1057
 
1021
- export declare function FormField({ controlId, label, description, error, wide, children, }: {
1022
- controlId: string;
1058
+ export declare type FilterOption = {
1059
+ value: string;
1023
1060
  label: string;
1024
1061
  description?: string;
1062
+ keywords?: string[];
1063
+ disabled?: boolean;
1064
+ };
1065
+
1066
+ /** 可搜索单选内容;调用方通过 Popover 管理关闭和入口焦点。每次打开时面板自行把焦点放进搜索框,无需向 Popover 传 initialFocus。 */
1067
+ export declare function FilterOptionPanel({ options, value, onSelect, label, searchPlaceholder, loading, error, onRetry, emptyText, noMatchText, filter, query: controlledQuery, onQueryChange }: FilterOptionPanelProps): JSX.Element;
1068
+
1069
+ export declare type FilterOptionPanelProps = {
1070
+ options: FilterOption[];
1071
+ value?: string;
1072
+ onSelect: (value: string) => void;
1073
+ /** 搜索框与列表的可访问名称。 */
1074
+ label: string;
1075
+ searchPlaceholder?: string;
1076
+ loading?: boolean;
1077
+ error?: ReactNode;
1078
+ onRetry?: () => void;
1079
+ emptyText?: ReactNode;
1080
+ noMatchText?: (query: string) => ReactNode;
1081
+ filter?: (options: FilterOption[], query: string) => FilterOption[];
1082
+ query?: string;
1083
+ onQueryChange?: (query: string) => void;
1084
+ };
1085
+
1086
+ export declare function FormField({ controlId, label, labelHidden, description, error, wide, children, }: {
1087
+ controlId: string;
1088
+ label?: string;
1089
+ description?: string;
1025
1090
  error?: string;
1026
1091
  wide?: boolean;
1027
1092
  children: ReactNode;
1028
- }): JSX.Element;
1093
+ } & FieldLabelVisibilityProps): JSX.Element;
1029
1094
 
1030
1095
  export declare function Gauge({ value, size, showValue, tone, toneDirection, label, indeterminate, }: {
1031
1096
  value?: number;
@@ -1094,7 +1159,7 @@ export declare type IconButtonProps = IconButtonAccessibleName & IconButtonBaseP
1094
1159
  ref?: Ref<HTMLButtonElement>;
1095
1160
  };
1096
1161
 
1097
- export declare function Input({ id, label, description, error, invalid, errorId, ref, prefix, suffix, prefixStyling, suffixStyling, rounded, wide, size, className, revealable, revealed, onRevealedChange, revealLabel, hideLabel, disabled, ...rest }: {
1162
+ export declare function Input({ id, label, labelHidden, description, error, invalid, errorId, ref, prefix, suffix, prefixStyling, suffixStyling, rounded, wide, size, className, revealable, revealed, onRevealedChange, revealLabel, hideLabel, disabled, ...rest }: {
1098
1163
  /** 可选:未传时内部 useId 兜底(对齐 Combobox);显式传入时行为同 0.3.0。 */
1099
1164
  id?: string;
1100
1165
  /** 置 aria-invalid 的业务校验态,不渲染文案;与壳模式 error 并轨(invalid || Boolean(error))。 */
@@ -1131,9 +1196,9 @@ export declare function Input({ id, label, description, error, invalid, errorId,
1131
1196
  rounded?: boolean;
1132
1197
  wide?: boolean;
1133
1198
  size?: FieldSize;
1134
- } & (FieldShellProps | FieldBareProps) & Omit<InputHTMLAttributes<HTMLInputElement>, 'id' | 'size' | 'prefix'>): JSX.Element;
1199
+ } & (FieldShellProps | FieldBareProps) & FieldLabelVisibilityProps & Omit<InputHTMLAttributes<HTMLInputElement>, 'id' | 'size' | 'prefix'>): JSX.Element;
1135
1200
 
1136
- export declare function InputOTP({ id, name, value, onValueChange, disabled, readOnly, required, invalid, errorId, size, separator, ref, label, description, error, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': describedBy, }: InputOTPProps): JSX.Element;
1201
+ export declare function InputOTP({ id, name, value, onValueChange, disabled, readOnly, required, invalid, errorId, size, separator, ref, label, labelHidden, description, error, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': describedBy, }: InputOTPProps): JSX.Element;
1137
1202
 
1138
1203
  export declare type InputOTPProps = {
1139
1204
  id?: string;
@@ -1151,7 +1216,7 @@ export declare type InputOTPProps = {
1151
1216
  separator?: boolean;
1152
1217
  ref?: Ref<HTMLInputElement>;
1153
1218
  'aria-describedby'?: string;
1154
- } & ((FieldShellProps & {
1219
+ } & FieldLabelVisibilityProps & ((FieldShellProps & {
1155
1220
  'aria-label'?: never;
1156
1221
  'aria-labelledby'?: never;
1157
1222
  }) | (FieldBareProps & ({
@@ -1264,8 +1329,14 @@ export declare type MentionProps = {
1264
1329
  children: ReactNode;
1265
1330
  };
1266
1331
 
1267
- export declare function Menu({ label, entries, withChevron, align, triggerContent }: {
1332
+ declare type MentionQuery = (query: string, options: {
1333
+ signal: AbortSignal;
1334
+ }) => Promise<ComposerMention[]>;
1335
+
1336
+ export declare function Menu({ label, entries, withChevron, align, triggerContent, size }: {
1268
1337
  label: string;
1338
+ /** 文字触发器尺寸,默认 md;图标触发器保留原尺寸。 */
1339
+ size?: ButtonSize;
1269
1340
  entries: MenuEntry[];
1270
1341
  withChevron?: boolean;
1271
1342
  align?: 'start' | 'end';
@@ -1709,7 +1780,7 @@ export declare function Q1travelSymbol(props: SVGProps<SVGSVGElement>): JSX.Elem
1709
1780
  export declare function Radio({ ...props }: RadioProps): JSX.Element;
1710
1781
 
1711
1782
  /** Radio 的完整 props。 */
1712
- export declare type RadioProps = ControlOptionOwnProps & (FieldShellProps | FieldBareProps) & ControlOptionNativeInputProps;
1783
+ export declare type RadioProps = ControlOptionOwnProps & (FieldShellProps | FieldBareProps) & FieldLabelVisibilityProps & ControlOptionNativeInputProps;
1713
1784
 
1714
1785
  export declare function RangeField(props: CalendarSelectionProps & {
1715
1786
  layout?: PopoverLayout;
@@ -1819,10 +1890,12 @@ export declare type SearchDialogTriggerProps = {
1819
1890
  'aria-controls': string;
1820
1891
  };
1821
1892
 
1822
- export declare function SearchInput({ id, ariaLabel, value: controlledValue, defaultValue, onValueChange, loading, kbdHint, icon, ref, className, disabled, readOnly, autoComplete, spellCheck, onKeyDown: onInputKeyDown, ...inputProps }: SearchInputProps): JSX.Element;
1893
+ export declare function SearchInput({ id, size, ariaLabel, value: controlledValue, defaultValue, onValueChange, loading, kbdHint, icon, ref, className, disabled, readOnly, autoComplete, spellCheck, onKeyDown: onInputKeyDown, ...inputProps }: SearchInputProps): JSX.Element;
1823
1894
 
1824
1895
  export declare type SearchInputProps = {
1825
1896
  id: string;
1897
+ /** 与 Button 同高,默认 md;数字保留原生 input 的字符宽度语义。 */
1898
+ size?: ButtonSize | number;
1826
1899
  /** 无可见 label 时的可访问名;与 FormField 或外部 label 组合时留空。 */
1827
1900
  ariaLabel?: string;
1828
1901
  value?: string;
@@ -1835,11 +1908,11 @@ export declare type SearchInputProps = {
1835
1908
  icon?: ReactNode;
1836
1909
  /** React 19 ref-as-prop,指向原生 search input。 */
1837
1910
  ref?: Ref<HTMLInputElement>;
1838
- } & Omit<InputHTMLAttributes<HTMLInputElement>, 'aria-label' | 'defaultValue' | 'id' | 'onChange' | 'ref' | 'type' | 'value'>;
1911
+ } & Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'aria-label' | 'defaultValue' | 'id' | 'onChange' | 'ref' | 'type' | 'value'>;
1839
1912
 
1840
- export declare function Select({ id, label, description, error, ref, wide, size, prefix, suffix, className, children, value, defaultValue, multiple, 'aria-describedby': ariaDescribedBy, 'aria-invalid': ariaInvalid, ...rest }: {
1913
+ export declare function Select({ id, label, labelHidden, description, error, ref, wide, size, prefix, suffix, className, children, value, defaultValue, multiple, 'aria-describedby': ariaDescribedBy, 'aria-invalid': ariaInvalid, ...rest }: {
1841
1914
  id: string;
1842
- label: string;
1915
+ label?: string;
1843
1916
  description?: string;
1844
1917
  error?: string;
1845
1918
  /** 指向原生 select(React 19 ref-as-prop),供表单校验后聚焦等场景。 */
@@ -1847,7 +1920,7 @@ export declare function Select({ id, label, description, error, ref, wide, size,
1847
1920
  wide?: boolean;
1848
1921
  size?: FieldSize;
1849
1922
  prefix?: ReactNode;
1850
- /** 装饰性后缀图标(aria-hidden),渲染在下拉箭头左侧;跟 prefix 前缀一样不承载信息,可访问名称仍完全来自 label。 */
1923
+ /** 装饰性后缀图标(aria-hidden),渲染在下拉箭头左侧;跟 prefix 前缀一样不承载信息,可访问名称来自可见 label 或消费方提供的 ARIA / 外部 label。 */
1851
1924
  suffix?: ReactNode;
1852
1925
  children: ReactNode;
1853
1926
  /** Select 只接受单一值;多值选择使用 MultiSelect。 */
@@ -1856,7 +1929,7 @@ export declare function Select({ id, label, description, error, ref, wide, size,
1856
1929
  defaultValue?: string | number;
1857
1930
  /** Select 是单选字段;多值选择使用 MultiSelect。 */
1858
1931
  multiple?: never;
1859
- } & Omit<SelectHTMLAttributes<HTMLSelectElement>, 'id' | 'children' | 'size' | 'prefix' | 'multiple' | 'value' | 'defaultValue'>): JSX.Element;
1932
+ } & FieldLabelVisibilityProps & Omit<SelectHTMLAttributes<HTMLSelectElement>, 'id' | 'children' | 'size' | 'prefix' | 'multiple' | 'value' | 'defaultValue'>): JSX.Element;
1860
1933
 
1861
1934
  export declare function Separator({ orientation, decorative, className, }: {
1862
1935
  orientation?: SeparatorOrientation;
@@ -2147,7 +2220,7 @@ export declare function Tabs({ tabs, ariaLabel, variant, value, defaultValue, on
2147
2220
  onValueChange?: (id: string) => void;
2148
2221
  }): JSX.Element | null;
2149
2222
 
2150
- export declare function Textarea({ id, label, description, error, invalid, errorId, ref, wide, size, className, maxLength, onInput, ...rest }: TextareaProps): JSX.Element;
2223
+ export declare function Textarea({ id, label, labelHidden, description, error, invalid, errorId, ref, wide, size, className, maxLength, onInput, ...rest }: TextareaProps): JSX.Element;
2151
2224
 
2152
2225
  /** Textarea 的完整 props。消费方包一层时用它标注,无需知道内部由哪几块组合而成。 */
2153
2226
  export declare type TextareaProps = {
@@ -2161,7 +2234,7 @@ export declare type TextareaProps = {
2161
2234
  ref?: Ref<HTMLTextAreaElement>;
2162
2235
  wide?: boolean;
2163
2236
  size?: FieldSize;
2164
- } & (FieldShellProps | FieldBareProps) & Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'id'>;
2237
+ } & (FieldShellProps | FieldBareProps) & FieldLabelVisibilityProps & Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'id'>;
2165
2238
 
2166
2239
  export declare function TextWithCopyButton({ text, copyValue, successMessage, size, }: {
2167
2240
  text: string;