@q1travel/design-system 0.14.1 → 0.15.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.
package/README.md CHANGED
@@ -8,7 +8,7 @@ q1travel 产品家族的设计权威上游仓,三件事集于一处:`@q1trav
8
8
 
9
9
  ## Sources
10
10
 
11
- - Source contracts(设计契约源,canonical):`contracts/design.md`、`contracts/design.dark.md`、`contracts/token-naming.md`、`contracts/icon-system.md`、`contracts/button-api-compatibility.md`、`contracts/interface-guidelines.md`、`contracts/design-engineering-principles.md`、`contracts/implementation-map.md`、`contracts/overlay-foundation.md`,以及迁移契约 `contracts/status-chip-badge-migration.md`、`contracts/pagination-migration.md`、`contracts/table-migration.md`、`contracts/overlay-shadow-migration.md`。独立 HTML 文档的有界 class 词汇表源为 `contracts/design.css`。
11
+ - Source contracts(设计契约源,canonical):`contracts/design.md`、`contracts/design.dark.md`、`contracts/token-naming.md`、`contracts/icon-system.md`、`contracts/button-api-compatibility.md`、`contracts/interface-guidelines.md`、`contracts/design-engineering-principles.md`、`contracts/implementation-map.md`、`contracts/overlay-foundation.md`,以及迁移契约 `contracts/context-contrast-migration.md`、`contracts/status-chip-badge-migration.md`、`contracts/pagination-migration.md`、`contracts/table-migration.md`、`contracts/overlay-shadow-migration.md`。独立 HTML 文档的有界 class 词汇表源为 `contracts/design.css`。
12
12
  - Generated mirrors(生成镜像,勿手改):`public/design.md`、`public/design.dark.md` 由 `scripts/sync-design-contracts.mjs` 从契约源逐字节复制;`public/design.css` 由 `scripts/build-design-css.mjs` 把两份契约 frontmatter 的取值注入 `contracts/design.css` 的类词汇后生成,因而自足、可被独立 HTML 页面直接加载。
13
13
  - Runtime tokens:`src/styles/tokens.css`(canonical `--q1-*`,仅 `:root` 与 `:root[data-theme='dark']` 两个扁平 selector)。
14
14
  - 发布台账:`contracts/releases/`(仅存于仓库,不进 npm 包)。
@@ -0,0 +1,85 @@
1
+ # Context and text contrast migration
2
+
3
+ ## Scope and approval
4
+
5
+ Issues #246, #245, and #244 share a package ownership boundary. The consumer
6
+ approved implementation on 2026-09-09 after reviewing the source audit and
7
+ correcting the original ramp interpretation. This plan covers the existing
8
+ `text-muted` semantic token, Navigation active text, and the `stacked`
9
+ ContextSwitcher presentation. The consumer accepted the rendered result and authorized commit and release on
10
+ 2026-09-11. The target patch release is 0.15.1; the starting consumer version is
11
+ 0.15.0. This migration does not include source edits in consuming repositories.
12
+
13
+ ## #246: readable supporting text
14
+
15
+ The reference ramps keep their existing values. In particular, gray-700 and
16
+ gray-800 are solid-background steps; they intentionally do not flip by theme.
17
+ There is no global monotonic-ramp requirement.
18
+
19
+ | Semantic token | Before | After | Supported surfaces |
20
+ | --- | --- | --- | --- |
21
+ | Light `--q1-color-text-muted` | gray-700, `#8f8f8f` | `#6b6b6b` | canvas, panel, subtle |
22
+ | Dark `--q1-color-text-muted` | gray-800, `#7d7d7d` | gray-700, `#8f8f8f` | canvas, panel, subtle |
23
+
24
+ Light supporting text needs its own semantic value between gray-800 and
25
+ gray-900: gray-800 misses normal-text AA, while gray-900 would collapse the
26
+ secondary/muted distinction. Dark supporting text can reuse gray-700. All three
27
+ text levels retain descending contrast on the supported surfaces and meet
28
+ WCAG 2 AA normal-text contrast (4.5:1). Arbitrary consumer surfaces, opacity,
29
+ blending, and disabled styling require their own effective-color checks.
30
+
31
+ Regenerate `public/design.md`, `public/design.dark.md`, and `public/design.css`
32
+ through `npm run sync:contracts`; runtime and contract values must agree.
33
+ The regression gate checks named text/surface pairs and button-label/solid
34
+ pairs. It must not treat every color as text or accept unsupported color syntax
35
+ silently. Existing browser checks cover composed component colors.
36
+
37
+ Consumer follow-up after upgrading: q1travel-web PR #998 introduced
38
+ `body.theme-dark .settings-appearance-layout { --text-tertiary: var(--q1-color-gray-700); }`.
39
+ Remove that workaround and resume the normal `--q1-color-text-muted` mapping.
40
+ Recheck the related appearance labels, docs supporting text, raw-color ratchet,
41
+ `check-contrast-contract`, and full Web gates. Other #998 text-secondary
42
+ substitutions should be reviewed individually, not mechanically reverted.
43
+
44
+ ## #245: Navigation active text
45
+
46
+ Both vertical and horizontal active items, including hover, use the existing
47
+ `--q1-color-primary-900` text-capable step (solution A). The label and decorative
48
+ icon inherit the same foreground. Preserve semibold, transparent resting
49
+ background, neutral hover, focus indication, native activation, and route-owned
50
+ `aria-current`. Do not change the action-primary button background.
51
+
52
+ This is a package-only CSS change. Web requires no source adjustment. A new
53
+ brand-text semantic token is not introduced in this migration.
54
+
55
+ ## #244: stacked current context
56
+
57
+ The existing `presentation: { type: 'stacked' }` adopts one consistent visual
58
+ behavior, without new props. Grouped and drilldown keep their presentations.
59
+
60
+ - A selected `menuitemradio` retains `aria-checked`, with a subtle full-row fill
61
+ and an inline-start accent rail instead of a trailing check. Pending feedback
62
+ remains visible. Focus and current-context indicators remain distinguishable.
63
+ - `depth: 1` uses a connector to the preceding depth-0 context within the same
64
+ group. The last child ends the branch at its center. Search results keep their
65
+ existing filtering behavior; when the parent is absent, retain indentation
66
+ without a misleading connector. These decorative lines do not create a Tree
67
+ widget or alter the menu keyboard model.
68
+ - Hover fades a background layer via opacity using duration-press (120ms).
69
+ Pointer opening introduces a short, capped list entrance whose last completion
70
+ is no later than duration-fast (150ms). Search, pending changes, and selection
71
+ updates do not replay the entrance. Keyboard opening and reduced motion are
72
+ immediate. Closing unmounts immediately.
73
+
74
+ Consumer follow-up: upgrade and verify the work-place map with real grouped
75
+ data, sparse/search results, pending/error states, long names, RTL, touch,
76
+ keyboard, and reduced motion. No package-private BEM overrides are required.
77
+ API #538 and #539 remain backend work and are not prerequisites for this change.
78
+
79
+ ## Acceptance and delivery boundary
80
+
81
+ Require failing-then-passing focused contrast and component assertions, light
82
+ and dark rendered proof, a 390px responsive check, and the full `npm run check`
83
+ on the final source. Keep unrelated baseline failures explicit. Source changes,
84
+ local verification, commit, published version, and consumer adoption are
85
+ separate delivery states.
@@ -18,7 +18,7 @@ colors:
18
18
  background-200: "#000000"
19
19
  text-primary: "#ededed"
20
20
  text-secondary: "#a0a0a0"
21
- text-muted: "#7d7d7d"
21
+ text-muted: "#8f8f8f"
22
22
  brand-preview-light-bg: "#ffffff"
23
23
  brand-preview-light-fg: "#171717"
24
24
  brand-preview-dark-bg: "#000000"
@@ -18,7 +18,7 @@ colors:
18
18
  background-200: "#fafafa"
19
19
  text-primary: "#171717"
20
20
  text-secondary: "#4d4d4d"
21
- text-muted: "#8f8f8f"
21
+ text-muted: "#6b6b6b"
22
22
  brand-preview-light-bg: "#ffffff"
23
23
  brand-preview-light-fg: "#171717"
24
24
  brand-preview-dark-bg: "#000000"
@@ -156,7 +156,7 @@ type OverlayRecord = {
156
156
  | --- | --- | --- | --- |
157
157
  | Modal | 公开 props、尺寸/布局、关闭策略、文档示例 | portal、stack、focus、blocking lock、统一 Escape/outside ownership | Foundation |
158
158
  | DestructiveActionModal | destructive/loading/confirm 语义与提交状态 | 同上;loading 时由 policy 禁止关闭 | Foundation |
159
- | Sheet | 现有 side、persistent-context 语义;blocking=true、outside pointer=false | 同上;不能让 CSS 注释与 ARIA 语义继续冲突 | Foundation |
159
+ | Sheet | side、persistent-context 语义;blocking=true、outside pointer=false;dismissable 默认 true,false 禁用 Escape 并隐藏内置关闭按钮 | 同上;不能让 CSS 注释与 ARIA 语义继续冲突 | Foundation |
160
160
  | Drawer | mobile bottom、gesture、outside/Escape 语义 | 同上;gesture 关闭仍必须服从 top-most 与 loading policy | Foundation |
161
161
 
162
162
  组件接入不得一次性重写四个组件,也不得在未有单独 contract 的情况下改变公开 DOM、默认 dismissal 或 accessibility tier。
@@ -259,3 +259,7 @@ D7 q1travel-web adoption/migration
259
259
  - 宿主每次 open 对应一次登记/释放;改变 blocking 策略应重新登记。idempotent disposer 支持 StrictMode 清理。不同 document 完全隔离。
260
260
 
261
261
  回归入口:`node --test scripts/check-overlay-coordination.test.mjs`;真实跨 root 的 Escape、焦点、快捷键与滚动锁由 Web consumer 浏览器测试验证。
262
+
263
+ ### Sheet sizing and dismissal
264
+
265
+ Sheet accepts optional `size: 'sm' | 'md' | 'lg' | 'xl'` for left/right panel widths of 360/480/640/860px, capped by the existing viewport gutters. Omitting size retains 512px. Top/bottom geometry, `title: string`, children, footer, and side remain unchanged. Dismissal policy updates take effect in the same commit as visible close controls, before consumer layout effects. `dismissable=false` retains its blocking coordinator entry, focus trap, inert background, and scroll lock; Escape cannot dismiss it or the underlying host overlay. Outside pointer never closes Sheet. Consumers retain ownership of controlled open and footer actions and restore dismissal when the temporary busy state ends.
@@ -1392,17 +1392,21 @@ export declare function Separator({ orientation, decorative, className, }: {
1392
1392
 
1393
1393
  export declare type SeparatorOrientation = 'horizontal' | 'vertical';
1394
1394
 
1395
- export declare function Sheet({ open, onClose, title, side, children, footer }: {
1395
+ export declare function Sheet({ open, onClose, title, side, size, dismissable, children, footer }: {
1396
1396
  open: boolean;
1397
1397
  onClose: () => void;
1398
1398
  title: string;
1399
1399
  side?: SheetSide;
1400
+ size?: SheetSize;
1401
+ dismissable?: boolean;
1400
1402
  children: ReactNode;
1401
1403
  footer?: ReactNode;
1402
1404
  }): ReactNode;
1403
1405
 
1404
1406
  export declare type SheetSide = 'top' | 'right' | 'bottom' | 'left';
1405
1407
 
1408
+ export declare type SheetSize = 'sm' | 'md' | 'lg' | 'xl';
1409
+
1406
1410
  export declare function ShowMore({ items, initial, noBorder, initialExpanded, }: {
1407
1411
  items: string[];
1408
1412
  initial?: number;