@q1travel/design-system 0.28.1 → 0.29.1

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.
@@ -522,7 +522,7 @@ Static WCAG stroke contrast against canvas/panel (2026-10-07): light neutral 5.3
522
522
  - Gauge is one ratio as a ring. Progress is advancement along a task, and takes segment stops.
523
523
  - RelativeTimeCard reveals the absolute time behind a relative one. Prefer it to printing both.
524
524
 
525
- **Status and feedback.** Banner, ProjectBanner, Note, ErrorCard, RegionErrorState, ErrorMessage, EmptyState, Badge, Pill, StatusDot, ToastProvider, useToast, Feedback, PageFeedback, Spinner, LoadingDots, Skeleton.
525
+ **Status and feedback.** Banner, ProjectBanner, Note, ErrorCard, RegionErrorState, ErrorMessage, EmptyState, Badge, Pill, CheckCircleFill, StatusDot, ToastProvider, useToast, Feedback, PageFeedback, Spinner, LoadingDots, Skeleton.
526
526
 
527
527
  - Banner announces at page scope. Note is an inline aside. ErrorMessage sits against one field. ErrorCard replaces a region that failed to load. Picking the widest one available overstates the problem.
528
528
  - RegionErrorState replaces only the failed region in place (table body under a kept header, card body, page section) while the rest of the page stays usable: neutral surface, danger color on the icon only, polite `role=status` by default, built-in retry that keeps focus while `retrying`. ErrorCard is for a failure that blocks the current task (danger card, assertive `role=alert`). EmptyState is a successful load with no data. See `implementation-map.md` for the retry and announcement boundary.
@@ -522,7 +522,7 @@ Static WCAG stroke contrast against canvas/panel (2026-10-07): light neutral 5.3
522
522
  - Gauge is one ratio as a ring. Progress is advancement along a task, and takes segment stops.
523
523
  - RelativeTimeCard reveals the absolute time behind a relative one. Prefer it to printing both.
524
524
 
525
- **Status and feedback.** Banner, ProjectBanner, Note, ErrorCard, RegionErrorState, ErrorMessage, EmptyState, Badge, Pill, StatusDot, ToastProvider, useToast, Feedback, PageFeedback, Spinner, LoadingDots, Skeleton.
525
+ **Status and feedback.** Banner, ProjectBanner, Note, ErrorCard, RegionErrorState, ErrorMessage, EmptyState, Badge, Pill, CheckCircleFill, StatusDot, ToastProvider, useToast, Feedback, PageFeedback, Spinner, LoadingDots, Skeleton.
526
526
 
527
527
  - Banner announces at page scope. Note is an inline aside. ErrorMessage sits against one field. ErrorCard replaces a region that failed to load. Picking the widest one available overstates the problem.
528
528
  - RegionErrorState replaces only the failed region in place (table body under a kept header, card body, page section) while the rest of the page stays usable: neutral surface, danger color on the icon only, polite `role=status` by default, built-in retry that keeps focus while `retrying`. ErrorCard is for a failure that blocks the current task (danger card, assertive `role=alert`). EmptyState is a successful load with no data. See `implementation-map.md` for the retry and announcement boundary.
@@ -105,7 +105,7 @@ Timeline / TimelineItem (ol/li, 8px token dot or Avatar), Marker (quiet actor/ti
105
105
 
106
106
  ## ToggleGroup selection ownership
107
107
 
108
- Accepted 2026-10-07: public `ToggleGroup` uses the shadcn/Radix name (no corresponding industry-common component). Its `items` API exposes `value`, `label`, optional `icon`, `disabled`, and `ariaLabel`; icon-only items require an icon and `ariaLabel`. `type="single"` accepts string `value` / `defaultValue` and `onValueChange`; `allowEmpty` defaults to false. `type="multiple"` accepts string arrays. Controlled values remain caller-owned; uncontrolled single selection falls back to the first enabled item when its value is absent or unknown and empty selection is disallowed. Disabling an existing selected item retains its pressed state and moves only the tabstop. No existing Switch consumer is migrated.
108
+ Accepted 2026-10-07: public `ToggleGroup` names a group of pressable controls with single or multiple selection. Its `items` API exposes `value`, `label`, optional `icon`, `disabled`, and `ariaLabel`; icon-only items require an icon and `ariaLabel`. `type="single"` accepts string `value` / `defaultValue` and `onValueChange`; `allowEmpty` defaults to false. `type="multiple"` accepts string arrays. Controlled values remain caller-owned; uncontrolled single selection falls back to the first enabled item when its value is absent or unknown and empty selection is disallowed. Disabling an existing selected item retains its pressed state and moves only the tabstop. No existing Switch consumer is migrated.
109
109
 
110
110
  Native buttons expose `aria-pressed` within `role="group"`. Roving tabindex and Arrow / Home / End move focus without selecting; Enter / Space activate through native clicks. Disabled items are skipped. Button-aligned sm32 / md40 / lg48 sizes use existing tokens, quiet selected background and primary text without a selected ring, shared focus shadow, and the shared coarse-pointer 44px TouchTarget with reserved neighbor space. The Tier A keyboard contract lives on `/components/toggle-group`; Switch retains radio semantics and Tabs retains panel semantics.
111
111
  ## Checkbox task completion circle
@@ -113,7 +113,7 @@ Native buttons expose `aria-pressed` within `role="group"`. Roving tabindex and
113
113
  - Documentation: `src/pages/CheckboxPage.tsx`, `CheckboxCircleDemo.tsx`, `src/styles/checkbox-circle-specimen.css`; circle completion is restricted to tasks/checklists and row completion treatment stays consumer-owned.
114
114
  - Verification: `scripts/check-checkbox-circle-contract.test.mjs`, `scripts/fixtures/checkbox-circle-api-consumer.tsx`, `scripts/lib/checkbox-circle-contrast.mjs`, `scripts/lib/check-checkbox-circle-browser.mjs`. Package gate covers API/default/native markup/readonly semantics/token existence and both-theme contrast; browser gate covers native toggles, focus without preview, readonly, tone fill, reduced motion and coarse hit targets.
115
115
  ## Chat messages
116
- Bubble is separate from Message: chat has optional identity and direction, while Message retains its required author, comment attachments and receipt API unchanged. MessageScroller is separate from Scroller: keyed prepend anchors and message following need ownership of the viewport; the general Scroller API remains unchanged. The shadcn chat reference supplies conversation intent only; quiet chat surfaces map to existing q1travel panel/selected backgrounds, borders, spacing, radii and Button. No reference CSS, motion background or private tokens are shipped.
116
+ Bubble is separate from Message: chat has optional identity and direction, while Message retains its required author, comment attachments and receipt API unchanged. MessageScroller is separate from Scroller: keyed prepend anchors and message following need ownership of the viewport; the general Scroller API remains unchanged. Quiet chat surfaces use existing q1travel panel/selected backgrounds, borders, spacing, radii and Button. No reference CSS, motion background or private tokens are shipped.
117
117
  The consumer mapping was checked against downstream chat-style implementations (read-only, no downstream edits).
118
118
  | Web capability | Package support / caller boundary |
119
119
  | --- | --- |
@@ -26,7 +26,7 @@ Adding a clause therefore means answering two questions before the wording: who
26
26
  - [both] MUST keep mobile control targets at least 44px where touch is expected.
27
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
- - [both] SHOULD NOT ship dense measured 24–32px controls to coarse pointers without 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.
29
+ - [both] SHOULD NOT ship dense measured 24–32px controls to coarse pointers without enlargement: q1travel uses a 44×44 CSS-pixel mobile usability target, informed by WCAG 2.5.5.
30
30
  - [both] NEVER disable browser zoom.
31
31
  - [both] MUST avoid dead zones: if a region looks clickable, the clickable element must cover it.
32
32
  - [both] MUST show a loading indicator on in-flight buttons while keeping the original label.
@@ -191,7 +191,7 @@ Theming owns tokens and `color-scheme`; the interaction-contrast rule lives in D
191
191
  - [both] MUST separate Chinese characters from adjacent Latin letters or digits with a half-width space in authored prose; code contents, URLs, literal UI quotations, and code samples are excluded.
192
192
  - [both] MUST use full-width `,。:;` immediately after Chinese characters in authored Chinese sentences; code contents, URLs, literal UI quotations, and code samples are excluded.
193
193
  - [both] SHOULD use full-width `,。:;` throughout Chinese sentences, including after Latin words or inline code; identifying sentence language across mixed JSX nodes remains an editorial review item.
194
- - [both] SHOULD follow common Chinese technical-writing practice for mixed-language wording; Microsoft's Chinese localization guidance is a reference example, not a proprietary q1travel rule. Semantic choices and text whose rendered role cannot be reliably inferred remain editorial review items rather than machine-enforced requirements.
194
+ - [both] SHOULD follow common Chinese technical-writing practice for mixed-language wording. Semantic choices and text whose rendered role cannot be reliably inferred remain editorial review items rather than machine-enforced requirements.
195
195
  - [both] SHOULD prefer short action-oriented labels.
196
196
  - [both] MUST use active voice.
197
197
  - [both] MUST use unambiguous action labels (「保存 API Key」, not 「继续」).
@@ -213,7 +213,7 @@ These copy clauses keep reader address and empty states consistent with a formal
213
213
 
214
214
  ### Component Naming
215
215
 
216
- - [repo] SHOULD use the industry-common component name when one exists, preferring shadcn/ui, then Radix. Invent a name only when neither has one. Name what the component is, not how it is built.
216
+ - [repo] SHOULD use the industry-common component name when one exists. Invent a name only when no established name fits. Name what the component is, not how it is built.
217
217
  - [repo] MUST switch public names directly to the new export without deprecated aliases or old documentation route redirects; record the removal as a breaking change in CHANGELOG.
218
218
 
219
219
  ### Component Documentation Pages
@@ -461,6 +461,15 @@ export declare type CheckboxProps = ControlOptionOwnProps & (FieldShellProps | F
461
461
  size?: 'sm' | 'md';
462
462
  } & Omit<ControlOptionNativeInputProps, 'size'>;
463
463
 
464
+ /** 装饰性圆底勾;当前或选中语义由宿主表达。 */
465
+ export declare function CheckCircleFill({ className, ...props }: CheckCircleFillProps): JSX.Element;
466
+
467
+ export declare type CheckCircleFillProps = {
468
+ className?: string;
469
+ children?: never;
470
+ [attribute: `data-${string}`]: string | number | boolean | undefined;
471
+ };
472
+
464
473
  export declare function Choicebox({ type, label, description, extra, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, ...rest }: ChoiceboxProps): JSX.Element;
465
474
 
466
475
  declare type ChoiceboxNativeInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'type'>;
@@ -1578,7 +1587,7 @@ export declare type MultiSelectProps = {
1578
1587
  preserveSelectionOrder?: boolean;
1579
1588
  };
1580
1589
 
1581
- export declare function Navigation({ className, orientation, ...props }: NavigationProps): JSX.Element;
1590
+ export declare function Navigation({ className, orientation, variant, ...props }: NavigationProps): JSX.Element;
1582
1591
 
1583
1592
  export declare function NavigationGroup({ label, icon, expanded, defaultExpanded, onExpandedChange, children, }: NavigationGroupProps): JSX.Element;
1584
1593
 
@@ -1617,6 +1626,8 @@ export declare type NavigationItemProps = NavigationItemAsLink | NavigationItemA
1617
1626
  export declare type NavigationProps = HTMLAttributes<HTMLElement> & {
1618
1627
  'aria-label': string;
1619
1628
  orientation?: 'vertical' | 'horizontal';
1629
+ /** Line styling applies only to horizontal navigation; vertical navigation ignores it. */
1630
+ variant?: 'default' | 'line';
1620
1631
  };
1621
1632
 
1622
1633
  export declare function NavigationSection({ label, action, children, className, ...props }: NavigationSectionProps): JSX.Element;