@q1travel/design-system 0.30.12 → 0.30.13
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 +1 -1
- package/bin/lint-component-enums.mjs +42 -0
- package/bin/q1-design.mjs +28 -2
- package/contracts/implementation-map.md +5 -1
- package/dist-pkg/component-enums.json +284 -0
- package/dist-pkg/design-system.js +1 -1
- package/dist-pkg/style.css +47 -13
- package/package.json +4 -4
- package/tooling/README.md +7 -1
- package/tooling/scripts/evals/rules-checklist.json +2 -1
package/README.md
CHANGED
|
@@ -71,7 +71,7 @@ root.render(
|
|
|
71
71
|
| --- | --- |
|
|
72
72
|
| `npx q1-design ls` | 列出包内提供的组件、hook 与应用模板 |
|
|
73
73
|
| `npx q1-design doc <组件名>` | 打印组件的公共 API;`doc app-base` 查看应用基础样式模板 |
|
|
74
|
-
| `npx q1-design lint [路径...]` | 按 `Q1-DS-*`
|
|
74
|
+
| `npx q1-design lint [路径...]` | 按 `Q1-DS-*` 规则检查样式和组件枚举字面量,默认扫描 `src` |
|
|
75
75
|
| `npx q1-design lint --diff <base-ref>` | 只检查相对 `base-ref` 有改动的文件 |
|
|
76
76
|
| `npx q1-design overrides [路径...]` | 统计对组件外观的 `className` 覆写 |
|
|
77
77
|
| `npx q1-design sync` | 将设计契约与 AI 编码指南同步为项目内的只读缓存 |
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const COMPONENT_ENUM_RULE = 'Q1-DS-002';
|
|
2
|
+
|
|
3
|
+
// Match the CLI's import-based scan; only literal JSX attributes are checked.
|
|
4
|
+
export function lintComponentEnums(source, filename, loadSchema) {
|
|
5
|
+
const imports = new Map();
|
|
6
|
+
const importPattern = /import\s*\{([^{}]*?)\}\s*from\s*["']@q1travel\/design-system["']/gs;
|
|
7
|
+
for (const match of source.matchAll(importPattern)) {
|
|
8
|
+
for (const part of match[1].split(',')) {
|
|
9
|
+
if (/^\s*type\s/.test(part)) continue;
|
|
10
|
+
const [component, local = component] = part.trim().split(/\s+as\s+/);
|
|
11
|
+
if (/^[A-Z][A-Za-z0-9_]*$/.test(local)) imports.set(local, component);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
for (const match of source.matchAll(/import\s*\*\s*as\s+(\w+)\s*from\s*["']@q1travel\/design-system["']/g)) {
|
|
15
|
+
imports.set(`${match[1]}.*`, '*');
|
|
16
|
+
}
|
|
17
|
+
if (!imports.size) return [];
|
|
18
|
+
const hits = [];
|
|
19
|
+
const tagPattern = /<([A-Z][\w.]*)\b((?:"[^"]*"|'[^']*'|\{(?:[^{}]|\{[^{}]*\})*\}|[^>"'{}])*)>/g;
|
|
20
|
+
for (const tag of source.matchAll(tagPattern)) {
|
|
21
|
+
const [namespace, member] = tag[1].split('.');
|
|
22
|
+
const component = member && imports.has(`${namespace}.*`) ? member : imports.get(tag[1]);
|
|
23
|
+
if (!component) continue;
|
|
24
|
+
const attributes = /(?:^|\s)(variant|size)\s*=\s*(?:"([^"]*)"|'([^']*)'|\{\s*(?:"([^"]*)"|'([^']*)')\s*\})/g;
|
|
25
|
+
for (const attribute of tag[2].matchAll(attributes)) {
|
|
26
|
+
let value = attribute[2] ?? attribute[3] ?? attribute[4] ?? attribute[5];
|
|
27
|
+
if (attribute[2] !== undefined || attribute[3] !== undefined) {
|
|
28
|
+
value = value.replace(/&#(x[\da-f]+|\d+);/gi, (_, code) => String.fromCodePoint(code[0].toLowerCase() === 'x' ? parseInt(code.slice(1), 16) : Number(code)));
|
|
29
|
+
}
|
|
30
|
+
const allowed = loadSchema()[component]?.[attribute[1]];
|
|
31
|
+
if (allowed && !allowed.includes(value)) {
|
|
32
|
+
const offset = tag.index + tag[0].indexOf(tag[2]) + attribute.index;
|
|
33
|
+
hits.push({
|
|
34
|
+
ruleId: COMPONENT_ENUM_RULE,
|
|
35
|
+
lineNumber: source.slice(0, offset + attribute[0].search(/\S/)).split('\n').length,
|
|
36
|
+
lineContent: `error ${component}.${attribute[1]}=${JSON.stringify(value)}; 允许值: ${allowed.join(' | ')}`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return hits;
|
|
42
|
+
}
|
package/bin/q1-design.mjs
CHANGED
|
@@ -22,6 +22,8 @@ import { createHash } from 'node:crypto';
|
|
|
22
22
|
import { dirname, extname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
23
23
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
24
24
|
|
|
25
|
+
import { COMPONENT_ENUM_RULE, lintComponentEnums } from './lint-component-enums.mjs';
|
|
26
|
+
|
|
25
27
|
const PACKAGE_NAME = '@q1travel/design-system';
|
|
26
28
|
const SKILL_RELATIVE_DIR = '.claude/skills/product-design';
|
|
27
29
|
const MANIFEST_FILE_NAME = '.q1-design-manifest.json';
|
|
@@ -644,6 +646,17 @@ const LINT_RULES = [
|
|
|
644
646
|
function collectLintHits(inputPaths, baseDir) {
|
|
645
647
|
const targetFiles = collectLintTargetFiles(inputPaths, baseDir);
|
|
646
648
|
const hits = [];
|
|
649
|
+
let enumSchema;
|
|
650
|
+
const loadEnumSchema = () => {
|
|
651
|
+
if (!enumSchema) {
|
|
652
|
+
const relativePath = 'dist-pkg/component-enums.json';
|
|
653
|
+
const packageRoot = resolveInstalledPackageRoot(baseDir) ?? baseDir;
|
|
654
|
+
const schemaPath = join(packageRoot, relativePath);
|
|
655
|
+
if (!existsSync(schemaPath)) throw new Error(`[q1-design] 找不到 ${relativePath},无法检查组件枚举;请安装 ${PACKAGE_NAME} 或先运行 npm run build:lib。`);
|
|
656
|
+
enumSchema = JSON.parse(readFileSync(schemaPath, 'utf8'));
|
|
657
|
+
}
|
|
658
|
+
return enumSchema;
|
|
659
|
+
};
|
|
647
660
|
|
|
648
661
|
for (const absoluteFilePath of targetFiles) {
|
|
649
662
|
const fileContent = readFileSync(absoluteFilePath, 'utf8');
|
|
@@ -653,6 +666,14 @@ function collectLintHits(inputPaths, baseDir) {
|
|
|
653
666
|
isTokens: isTokensPath(absoluteFilePath, baseDir),
|
|
654
667
|
};
|
|
655
668
|
|
|
669
|
+
if (!fileFacts.isCssFile && !hasFileDisablePragma(fileContent, COMPONENT_ENUM_RULE)) {
|
|
670
|
+
const isSuppressed = createSuppressionTracker(COMPONENT_ENUM_RULE);
|
|
671
|
+
const suppressedLines = fileContent.split('\n').map((line) => isSuppressed(line));
|
|
672
|
+
for (const hit of lintComponentEnums(fileContent, absoluteFilePath, loadEnumSchema)) {
|
|
673
|
+
if (!suppressedLines[hit.lineNumber - 1]) hits.push({ ...hit, filePath: relativeFilePath });
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
656
677
|
const activeRules = LINT_RULES.map((rule) => ({
|
|
657
678
|
rule,
|
|
658
679
|
applicable: rule.appliesToFile(fileFacts) && !hasFileDisablePragma(fileContent, rule.ruleId),
|
|
@@ -717,7 +738,7 @@ function runLint(inputPaths, consumerRootDir, diffBaseRef) {
|
|
|
717
738
|
|
|
718
739
|
for (const hit of hits) {
|
|
719
740
|
console.log(
|
|
720
|
-
`${hit.ruleId} ${hit.filePath}:${hit.lineNumber} ${truncateLine(hit.lineContent)}`,
|
|
741
|
+
`${hit.ruleId} ${hit.filePath}:${hit.lineNumber} ${hit.ruleId === COMPONENT_ENUM_RULE ? hit.lineContent : truncateLine(hit.lineContent)}`,
|
|
721
742
|
);
|
|
722
743
|
}
|
|
723
744
|
console.log(`[q1-design] 共 ${hits.length} 处命中`);
|
|
@@ -1109,7 +1130,12 @@ if (isDirectRun) {
|
|
|
1109
1130
|
}
|
|
1110
1131
|
args.splice(diffIndex, 2);
|
|
1111
1132
|
}
|
|
1112
|
-
|
|
1133
|
+
try {
|
|
1134
|
+
runLint(args.length > 0 ? args : ['src'], consumerRootDir, diffBaseRef);
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
console.error(error.message);
|
|
1137
|
+
process.exit(1);
|
|
1138
|
+
}
|
|
1113
1139
|
} else if (subcommand === 'eval') {
|
|
1114
1140
|
runEval();
|
|
1115
1141
|
} else if (subcommand === 'overrides') {
|
|
@@ -112,7 +112,7 @@ Timeline / TimelineItem (ol/li, 8px token dot or Avatar), Marker (quiet actor/ti
|
|
|
112
112
|
|
|
113
113
|
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.
|
|
114
114
|
|
|
115
|
-
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
|
|
115
|
+
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 with the shared `selection-recipe.css` inset border-strong selection edge (bg-subtle in light, bg-raised in dark); keyboard focus replaces that edge with the 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.
|
|
116
116
|
## Checkbox task completion circle
|
|
117
117
|
- Native base: `src/components/ui/ControlOption.tsx`; circle-only readonly/warning module: `src/components/ui/CircleCheckbox.tsx`; independent style: `src/styles/checkbox-circle.css`, imported at the top of global.css and included by build-style.mjs. Square defaults remain unchanged.
|
|
118
118
|
- 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.
|
|
@@ -150,3 +150,7 @@ The announcement region wraps only the icon, the `q1-sr-only` 「错误:」 pr
|
|
|
150
150
|
## Cascader 层级选择
|
|
151
151
|
|
|
152
152
|
`Cascader`(`src/components/ui/Cascader.tsx`)负责字段及触发器;`cascader/` 的 Types、model、window、Panel 分别负责受控边界、路径与独立选择、测量窗口、关联 listbox 与搜索。复用 Popover/useOverlay、RegionErrorState 和 Spinner;样式来自既有 surface、text、control、space、radius 与 focus token。窄屏同一弹层单列钻取,亮暗继承 anchor。完整约束、可选省略、公开面与回滚见 [Cascader](./cascader.md)。文档入口 `/components/cascader`,不迁移既有选择器。
|
|
153
|
+
|
|
154
|
+
## ThemeSwitcher selection appearance
|
|
155
|
+
|
|
156
|
+
Accepted 2026-11-02 (#761): ThemeSwitcher keeps a single outer group border. Options have no border; selection uses `--q1-color-bg-selected-neutral` and primary text, with no inset selection edge. Unselected options keep secondary text and the container background. Light and dark selected and unselected text meet 4.5:1 contrast; the selected background differs from the container. Native labeled radios retain their keyboard behavior, hover changes enabled option text to primary, and keyboard focus uses the shared focus shadow. Public props, class names, DOM structure, exports, and tokens are unchanged.
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Badge": {
|
|
3
|
+
"size": [
|
|
4
|
+
"sm",
|
|
5
|
+
"md",
|
|
6
|
+
"lg"
|
|
7
|
+
]
|
|
8
|
+
},
|
|
9
|
+
"Book": {
|
|
10
|
+
"variant": [
|
|
11
|
+
"stripe",
|
|
12
|
+
"simple"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"Browser": {
|
|
16
|
+
"variant": [
|
|
17
|
+
"light",
|
|
18
|
+
"dark"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"Button": {
|
|
22
|
+
"variant": [
|
|
23
|
+
"primary",
|
|
24
|
+
"secondary",
|
|
25
|
+
"ghost",
|
|
26
|
+
"warning",
|
|
27
|
+
"danger"
|
|
28
|
+
],
|
|
29
|
+
"size": [
|
|
30
|
+
"sm",
|
|
31
|
+
"md",
|
|
32
|
+
"lg"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"ButtonLink": {
|
|
36
|
+
"variant": [
|
|
37
|
+
"primary",
|
|
38
|
+
"secondary",
|
|
39
|
+
"ghost",
|
|
40
|
+
"warning",
|
|
41
|
+
"danger"
|
|
42
|
+
],
|
|
43
|
+
"size": [
|
|
44
|
+
"sm",
|
|
45
|
+
"md",
|
|
46
|
+
"lg"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"CalendarGrid": {
|
|
50
|
+
"size": [
|
|
51
|
+
"large",
|
|
52
|
+
"small"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"Checkbox": {
|
|
56
|
+
"size": [
|
|
57
|
+
"sm",
|
|
58
|
+
"md"
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
"CodeBlock": {
|
|
62
|
+
"variant": [
|
|
63
|
+
"default",
|
|
64
|
+
"flush"
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
"Combobox": {
|
|
68
|
+
"size": [
|
|
69
|
+
"sm",
|
|
70
|
+
"md",
|
|
71
|
+
"lg"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
"DotsMenu": {
|
|
75
|
+
"size": [
|
|
76
|
+
"sm",
|
|
77
|
+
"md",
|
|
78
|
+
"lg"
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
"ErrorMessage": {
|
|
82
|
+
"size": [
|
|
83
|
+
"sm",
|
|
84
|
+
"md",
|
|
85
|
+
"lg"
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
"FilterChip": {
|
|
89
|
+
"size": [
|
|
90
|
+
"sm",
|
|
91
|
+
"md",
|
|
92
|
+
"lg"
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
"Gauge": {
|
|
96
|
+
"size": [
|
|
97
|
+
"xs",
|
|
98
|
+
"sm",
|
|
99
|
+
"md",
|
|
100
|
+
"lg"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
"IconButton": {
|
|
104
|
+
"variant": [
|
|
105
|
+
"primary",
|
|
106
|
+
"secondary",
|
|
107
|
+
"ghost",
|
|
108
|
+
"warning",
|
|
109
|
+
"danger"
|
|
110
|
+
],
|
|
111
|
+
"size": [
|
|
112
|
+
"sm",
|
|
113
|
+
"md",
|
|
114
|
+
"lg"
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
"Input": {
|
|
118
|
+
"size": [
|
|
119
|
+
"xs",
|
|
120
|
+
"sm",
|
|
121
|
+
"md",
|
|
122
|
+
"lg"
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"InputOTP": {
|
|
126
|
+
"size": [
|
|
127
|
+
"md",
|
|
128
|
+
"lg"
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
"Marker": {
|
|
132
|
+
"variant": [
|
|
133
|
+
"default",
|
|
134
|
+
"separator",
|
|
135
|
+
"unread"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
"Menu": {
|
|
139
|
+
"size": [
|
|
140
|
+
"sm",
|
|
141
|
+
"md",
|
|
142
|
+
"lg"
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
"Navigation": {
|
|
146
|
+
"variant": [
|
|
147
|
+
"default",
|
|
148
|
+
"line"
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
"Note": {
|
|
152
|
+
"size": [
|
|
153
|
+
"small",
|
|
154
|
+
"default",
|
|
155
|
+
"large"
|
|
156
|
+
]
|
|
157
|
+
},
|
|
158
|
+
"PageFeedback": {
|
|
159
|
+
"variant": [
|
|
160
|
+
"rating",
|
|
161
|
+
"helpful"
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
"Pill": {
|
|
165
|
+
"size": [
|
|
166
|
+
"sm",
|
|
167
|
+
"md",
|
|
168
|
+
"lg"
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
"ProductLockup": {
|
|
172
|
+
"size": [
|
|
173
|
+
"sm",
|
|
174
|
+
"md"
|
|
175
|
+
]
|
|
176
|
+
},
|
|
177
|
+
"ProjectBanner": {
|
|
178
|
+
"variant": [
|
|
179
|
+
"default",
|
|
180
|
+
"success",
|
|
181
|
+
"warning",
|
|
182
|
+
"error"
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
"RangeField": {
|
|
186
|
+
"size": [
|
|
187
|
+
"large",
|
|
188
|
+
"small"
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
"Select": {
|
|
192
|
+
"size": [
|
|
193
|
+
"xs",
|
|
194
|
+
"sm",
|
|
195
|
+
"md",
|
|
196
|
+
"lg"
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
"Sheet": {
|
|
200
|
+
"size": [
|
|
201
|
+
"sm",
|
|
202
|
+
"md",
|
|
203
|
+
"lg",
|
|
204
|
+
"xl"
|
|
205
|
+
]
|
|
206
|
+
},
|
|
207
|
+
"SidebarDrawer": {
|
|
208
|
+
"variant": [
|
|
209
|
+
"panel",
|
|
210
|
+
"plain"
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
"Spinner": {
|
|
214
|
+
"size": [
|
|
215
|
+
"sm",
|
|
216
|
+
"md",
|
|
217
|
+
"lg",
|
|
218
|
+
"xl"
|
|
219
|
+
]
|
|
220
|
+
},
|
|
221
|
+
"SplitButton": {
|
|
222
|
+
"variant": [
|
|
223
|
+
"default",
|
|
224
|
+
"secondary"
|
|
225
|
+
],
|
|
226
|
+
"size": [
|
|
227
|
+
"sm",
|
|
228
|
+
"md",
|
|
229
|
+
"lg"
|
|
230
|
+
]
|
|
231
|
+
},
|
|
232
|
+
"StatusPage": {
|
|
233
|
+
"size": [
|
|
234
|
+
"page",
|
|
235
|
+
"region"
|
|
236
|
+
]
|
|
237
|
+
},
|
|
238
|
+
"Switch": {
|
|
239
|
+
"variant": [
|
|
240
|
+
"segmented",
|
|
241
|
+
"cards"
|
|
242
|
+
],
|
|
243
|
+
"size": [
|
|
244
|
+
"sm",
|
|
245
|
+
"md",
|
|
246
|
+
"lg"
|
|
247
|
+
]
|
|
248
|
+
},
|
|
249
|
+
"Tabs": {
|
|
250
|
+
"variant": [
|
|
251
|
+
"default",
|
|
252
|
+
"secondary",
|
|
253
|
+
"line"
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
"Textarea": {
|
|
257
|
+
"size": [
|
|
258
|
+
"xs",
|
|
259
|
+
"sm",
|
|
260
|
+
"md",
|
|
261
|
+
"lg"
|
|
262
|
+
]
|
|
263
|
+
},
|
|
264
|
+
"TextWithCopyButton": {
|
|
265
|
+
"size": [
|
|
266
|
+
"default",
|
|
267
|
+
"small"
|
|
268
|
+
]
|
|
269
|
+
},
|
|
270
|
+
"Toggle": {
|
|
271
|
+
"size": [
|
|
272
|
+
"sm",
|
|
273
|
+
"md",
|
|
274
|
+
"lg"
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
"ToggleGroup": {
|
|
278
|
+
"size": [
|
|
279
|
+
"sm",
|
|
280
|
+
"md",
|
|
281
|
+
"lg"
|
|
282
|
+
]
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -14283,7 +14283,7 @@ function Gd(e) {
|
|
|
14283
14283
|
),
|
|
14284
14284
|
e.mode === "multiple" && J.length ? /* @__PURE__ */ n("div", { className: "q1-cascader__tags", role: "list", "aria-label": "已选项", children: J.map((ce) => /* @__PURE__ */ _("span", { className: "q1-cascader__tag", role: "listitem", children: [
|
|
14285
14285
|
/* @__PURE__ */ n("span", { children: U(ce) }),
|
|
14286
|
-
w ? /* @__PURE__ */ n("button", { type: "button", className: "q1-cascader__remove", disabled: !F, "aria-label": `移除 ${ne(ce)}`, onClick: () => Me(ce), children: /* @__PURE__ */ n(Ue, { size:
|
|
14286
|
+
w ? /* @__PURE__ */ n("button", { type: "button", className: "q1-cascader__remove", disabled: !F, "aria-label": `移除 ${ne(ce)}`, onClick: () => Me(ce), children: /* @__PURE__ */ n(Ue, { size: 12, strokeWidth: oe, "aria-hidden": "true" }) }) : null
|
|
14287
14287
|
] }, ce)) }) : null,
|
|
14288
14288
|
w && J.length ? /* @__PURE__ */ n("button", { type: "button", className: "q1-cascader__remove", disabled: !F, "aria-label": "全部清除", onClick: () => Me(), children: /* @__PURE__ */ n(Ue, { size: 16, strokeWidth: oe, "aria-hidden": "true" }) }) : null
|
|
14289
14289
|
] }),
|
package/dist-pkg/style.css
CHANGED
|
@@ -2894,6 +2894,7 @@
|
|
|
2894
2894
|
}
|
|
2895
2895
|
|
|
2896
2896
|
.banner__close {
|
|
2897
|
+
font: inherit;
|
|
2897
2898
|
box-sizing: border-box;
|
|
2898
2899
|
display: inline-flex;
|
|
2899
2900
|
align-items: center;
|
|
@@ -3095,6 +3096,7 @@ a.breadcrumb__link:hover {
|
|
|
3095
3096
|
}
|
|
3096
3097
|
|
|
3097
3098
|
.breadcrumb__toggle {
|
|
3099
|
+
font: inherit;
|
|
3098
3100
|
display: inline-flex;
|
|
3099
3101
|
align-items: center;
|
|
3100
3102
|
justify-content: center;
|
|
@@ -3388,6 +3390,7 @@ a.breadcrumb__link:hover {
|
|
|
3388
3390
|
可见焦点环——它可聚焦,chrome 整体不再 aria-hidden 正是为了让它可达。
|
|
3389
3391
|
点击目标 24×24(WCAG 2.2 最小目标),图标仍 12px 居中——负 margin 抵消撑高,不改地址栏高度。 */
|
|
3390
3392
|
.browser__address-copy {
|
|
3393
|
+
font: inherit;
|
|
3391
3394
|
flex-shrink: 0;
|
|
3392
3395
|
display: grid;
|
|
3393
3396
|
place-items: center;
|
|
@@ -4338,6 +4341,7 @@ a[href]:has(> .book):focus-visible {
|
|
|
4338
4341
|
}
|
|
4339
4342
|
|
|
4340
4343
|
.cal-field__trigger {
|
|
4344
|
+
font: inherit;
|
|
4341
4345
|
display: inline-flex;
|
|
4342
4346
|
align-items: center;
|
|
4343
4347
|
gap: var(--q1-space-2);
|
|
@@ -4360,6 +4364,7 @@ a[href]:has(> .book):focus-visible {
|
|
|
4360
4364
|
|
|
4361
4365
|
.cal-field__clear,
|
|
4362
4366
|
.cal-field__caret {
|
|
4367
|
+
font: inherit;
|
|
4363
4368
|
display: grid;
|
|
4364
4369
|
place-items: center;
|
|
4365
4370
|
min-height: var(--q1-space-6);
|
|
@@ -4479,6 +4484,7 @@ a[href]:has(> .book):focus-visible {
|
|
|
4479
4484
|
}
|
|
4480
4485
|
|
|
4481
4486
|
.calendar__nav-btn {
|
|
4487
|
+
font: inherit;
|
|
4482
4488
|
display: grid;
|
|
4483
4489
|
place-items: center;
|
|
4484
4490
|
width: 28px;
|
|
@@ -4540,6 +4546,7 @@ a[href]:has(> .book):focus-visible {
|
|
|
4540
4546
|
}
|
|
4541
4547
|
|
|
4542
4548
|
.calendar__day {
|
|
4549
|
+
font: inherit;
|
|
4543
4550
|
position: relative;
|
|
4544
4551
|
display: grid;
|
|
4545
4552
|
place-items: center;
|
|
@@ -4601,6 +4608,7 @@ a[href]:has(> .book):focus-visible {
|
|
|
4601
4608
|
}
|
|
4602
4609
|
|
|
4603
4610
|
.cal-period__trigger {
|
|
4611
|
+
font: inherit;
|
|
4604
4612
|
display: inline-flex;
|
|
4605
4613
|
align-items: center;
|
|
4606
4614
|
gap: var(--q1-space-2);
|
|
@@ -4638,6 +4646,7 @@ a[href]:has(> .book):focus-visible {
|
|
|
4638
4646
|
}
|
|
4639
4647
|
|
|
4640
4648
|
.cal-period__option {
|
|
4649
|
+
font: inherit;
|
|
4641
4650
|
width: 100%;
|
|
4642
4651
|
text-align: left;
|
|
4643
4652
|
padding: var(--q1-space-2) var(--q1-space-3);
|
|
@@ -5062,6 +5071,7 @@ a[href]:has(> .book):focus-visible {
|
|
|
5062
5071
|
}
|
|
5063
5072
|
|
|
5064
5073
|
.snippet__copy {
|
|
5074
|
+
font: inherit;
|
|
5065
5075
|
position: absolute;
|
|
5066
5076
|
top: 50%;
|
|
5067
5077
|
right: var(--q1-space-1);
|
|
@@ -5335,6 +5345,7 @@ a[href]:has(> .book):focus-visible {
|
|
|
5335
5345
|
|
|
5336
5346
|
/* 行动按钮。 */
|
|
5337
5347
|
.note__action {
|
|
5348
|
+
font: inherit;
|
|
5338
5349
|
flex-shrink: 0;
|
|
5339
5350
|
display: inline-flex;
|
|
5340
5351
|
align-items: center;
|
|
@@ -6417,6 +6428,7 @@ a.q1-card:focus-visible {
|
|
|
6417
6428
|
}
|
|
6418
6429
|
|
|
6419
6430
|
.twc__copy {
|
|
6431
|
+
font: inherit;
|
|
6420
6432
|
display: grid;
|
|
6421
6433
|
place-items: center;
|
|
6422
6434
|
width: 24px;
|
|
@@ -6532,6 +6544,7 @@ a.q1-card:focus-visible {
|
|
|
6532
6544
|
|
|
6533
6545
|
/* 清除按钮:视觉走字段家族的通用 X;Esc 仍是即时键盘路径。 */
|
|
6534
6546
|
.search-input__clear {
|
|
6547
|
+
font: inherit;
|
|
6535
6548
|
position: absolute;
|
|
6536
6549
|
top: 50%;
|
|
6537
6550
|
right: var(--q1-space-2);
|
|
@@ -6741,6 +6754,7 @@ a.q1-card:focus-visible {
|
|
|
6741
6754
|
|
|
6742
6755
|
/* 药丸触发器:h32 / font 14/500 / 全圆角;颜色走家族 panel+border。 */
|
|
6743
6756
|
.show-more__trigger {
|
|
6757
|
+
font: inherit;
|
|
6744
6758
|
display: inline-flex;
|
|
6745
6759
|
align-items: center;
|
|
6746
6760
|
gap: var(--q1-space-1);
|
|
@@ -7537,6 +7551,7 @@ a.q1-card:focus-visible {
|
|
|
7537
7551
|
min-height: 0;
|
|
7538
7552
|
}
|
|
7539
7553
|
.scroller-buttons__control {
|
|
7554
|
+
font: inherit;
|
|
7540
7555
|
flex: none;
|
|
7541
7556
|
display: grid;
|
|
7542
7557
|
place-items: center;
|
|
@@ -7601,9 +7616,8 @@ a.q1-card:focus-visible {
|
|
|
7601
7616
|
place-items: center;
|
|
7602
7617
|
}
|
|
7603
7618
|
.theme-switcher__option:has(input:checked) {
|
|
7604
|
-
background: var(--q1-color-bg-
|
|
7619
|
+
background: var(--q1-color-bg-selected-neutral);
|
|
7605
7620
|
color: var(--q1-color-text-primary);
|
|
7606
|
-
box-shadow: inset 0 0 0 1px var(--q1-color-gray-400);
|
|
7607
7621
|
}
|
|
7608
7622
|
.theme-switcher__option:has(input:focus-visible) {
|
|
7609
7623
|
outline: none;
|
|
@@ -7960,6 +7974,7 @@ a.q1-card:focus-visible {
|
|
|
7960
7974
|
box-shadow: var(--q1-shadow-focus);
|
|
7961
7975
|
}
|
|
7962
7976
|
.q1-toast__close {
|
|
7977
|
+
font: inherit;
|
|
7963
7978
|
flex: none;
|
|
7964
7979
|
display: grid;
|
|
7965
7980
|
place-items: center;
|
|
@@ -8268,6 +8283,7 @@ a.q1-card:focus-visible {
|
|
|
8268
8283
|
display: inline-block;
|
|
8269
8284
|
}
|
|
8270
8285
|
.dots-menu__trigger {
|
|
8286
|
+
font: inherit;
|
|
8271
8287
|
display: grid;
|
|
8272
8288
|
place-items: center;
|
|
8273
8289
|
border: 0;
|
|
@@ -8573,6 +8589,7 @@ a.q1-card:focus-visible {
|
|
|
8573
8589
|
outline: none;
|
|
8574
8590
|
}
|
|
8575
8591
|
.combobox__clear {
|
|
8592
|
+
font: inherit;
|
|
8576
8593
|
flex: none;
|
|
8577
8594
|
display: grid;
|
|
8578
8595
|
place-items: center;
|
|
@@ -8887,6 +8904,7 @@ a.q1-card:focus-visible {
|
|
|
8887
8904
|
}
|
|
8888
8905
|
/* 遮罩颜色与 Modal 同源,见 overlay-surfaces.css:浅色为白纱,暗色压暗。 */
|
|
8889
8906
|
.search-dialog__backdrop {
|
|
8907
|
+
font: inherit;
|
|
8890
8908
|
position: absolute;
|
|
8891
8909
|
inset: 0;
|
|
8892
8910
|
border: 0;
|
|
@@ -8938,6 +8956,7 @@ a.q1-card:focus-visible {
|
|
|
8938
8956
|
}
|
|
8939
8957
|
/* 关闭入口以 Esc 键帽呈现:键盘优先、视觉更轻;粗指针下由 TouchTarget 扩展到 44px 命中区。 */
|
|
8940
8958
|
.search-dialog__close {
|
|
8959
|
+
font: inherit;
|
|
8941
8960
|
position: relative;
|
|
8942
8961
|
display: inline-flex;
|
|
8943
8962
|
flex: none;
|
|
@@ -9171,6 +9190,7 @@ a.q1-card:focus-visible {
|
|
|
9171
9190
|
padding: var(--q1-space-4);
|
|
9172
9191
|
}
|
|
9173
9192
|
.modal__backdrop {
|
|
9193
|
+
font: inherit;
|
|
9174
9194
|
position: absolute;
|
|
9175
9195
|
inset: 0;
|
|
9176
9196
|
border: 0;
|
|
@@ -9354,6 +9374,7 @@ a.q1-card:focus-visible {
|
|
|
9354
9374
|
align-items: center;
|
|
9355
9375
|
}
|
|
9356
9376
|
.drawer__backdrop {
|
|
9377
|
+
font: inherit;
|
|
9357
9378
|
position: absolute;
|
|
9358
9379
|
inset: 0;
|
|
9359
9380
|
border: 0;
|
|
@@ -9373,6 +9394,7 @@ a.q1-card:focus-visible {
|
|
|
9373
9394
|
/* 抓手把是真按钮(点击/Enter/Space 关闭,下滑手势保留给触屏)——原 role=button+tabIndex=-1
|
|
9374
9395
|
是读屏能发现却无法激活的矛盾信号。清按钮默认样式,触控目标保持至少 44px。 */
|
|
9375
9396
|
.drawer__handle {
|
|
9397
|
+
font: inherit;
|
|
9376
9398
|
display: grid;
|
|
9377
9399
|
place-items: center;
|
|
9378
9400
|
width: 100%;
|
|
@@ -9688,6 +9710,7 @@ a.q1-card:focus-visible {
|
|
|
9688
9710
|
color: var(--q1-color-text-primary);
|
|
9689
9711
|
}
|
|
9690
9712
|
.sheet__close {
|
|
9713
|
+
font: inherit;
|
|
9691
9714
|
flex: none;
|
|
9692
9715
|
display: grid;
|
|
9693
9716
|
place-items: center;
|
|
@@ -10557,6 +10580,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
10557
10580
|
|
|
10558
10581
|
.q1-context-switcher__popup[role='dialog'] input[type='search'],
|
|
10559
10582
|
.q1-context-switcher__popup--stacked input[type='search'] {
|
|
10583
|
+
font: inherit;
|
|
10560
10584
|
width: 100%;
|
|
10561
10585
|
min-width: 0;
|
|
10562
10586
|
min-height: var(--q1-space-8);
|
|
@@ -11491,7 +11515,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
11491
11515
|
|
|
11492
11516
|
.q1-cascader { display: grid; gap: var(--q1-space-2); min-inline-size: 0; }
|
|
11493
11517
|
.q1-cascader__label { color: var(--q1-color-text-primary); font-size: var(--q1-font-size-label-14); line-height: var(--q1-line-height-label-14); }
|
|
11494
|
-
.q1-cascader__control { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: var(--q1-space-2); border: calc(var(--q1-space-1) / 4) solid var(--q1-color-border); border-radius: var(--q1-radius-2); background: var(--q1-color-bg-sunken); }
|
|
11518
|
+
.q1-cascader__control { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: var(--q1-space-2); border: calc(var(--q1-space-1) / 4) solid var(--q1-color-border-control); border-radius: var(--q1-radius-2); background: var(--q1-color-bg-sunken); }
|
|
11495
11519
|
.q1-cascader__trigger { display: flex; align-items: center; justify-content: space-between; flex: 1; gap: var(--q1-space-2); min-inline-size: 0; min-block-size: var(--q1-control-height-default); padding: var(--q1-space-2) var(--q1-space-3); border: none; background: none; border-radius: var(--q1-radius-2); color: var(--q1-color-text-primary); font: inherit; font-size: var(--q1-font-size-label-14); line-height: var(--q1-line-height-label-14); cursor: pointer; text-align: start; overflow-wrap: anywhere; }
|
|
11496
11520
|
.q1-cascader__trigger svg, .q1-cascader__option svg { flex: none; }
|
|
11497
11521
|
.q1-cascader__control:focus-within { box-shadow: var(--q1-shadow-focus-input); }
|
|
@@ -11500,25 +11524,26 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
11500
11524
|
.q1-cascader__trigger:focus-visible { outline: none; }
|
|
11501
11525
|
.q1-cascader__placeholder, .q1-cascader__path { color: var(--q1-color-text-muted); }
|
|
11502
11526
|
.q1-cascader__control[data-disabled], .q1-cascader__trigger[aria-disabled], .q1-cascader__option[aria-disabled] { color: var(--q1-color-text-disabled); cursor: default; }
|
|
11527
|
+
.q1-cascader__control[data-disabled]:not([data-invalid]) { border-color: var(--q1-color-border); }
|
|
11503
11528
|
.q1-cascader__control[data-disabled] .q1-cascader__trigger { color: inherit; }
|
|
11504
11529
|
.q1-cascader__control[data-tags] { align-items: start; flex-wrap: nowrap; padding-inline-end: calc(var(--q1-control-height-default) + var(--q1-space-3)); }
|
|
11505
11530
|
.q1-cascader__control[data-tags] .q1-cascader__trigger { position: absolute; inset: 0; inline-size: 100%; padding: 0; }
|
|
11506
11531
|
.q1-cascader__control[data-tags][data-clearable] { padding-inline-end: calc(var(--q1-control-height-default) * 2 + var(--q1-space-3)); }
|
|
11507
11532
|
.q1-cascader__control[data-clearable]:not([data-tags]) .q1-cascader__trigger { margin-inline-end: var(--q1-control-height-default); }
|
|
11508
|
-
.q1-cascader__control[data-tags] .q1-cascader__trigger > svg { position: absolute; inset-block-start: var(--q1-space-2); inset-inline-end: var(--q1-space-2); }
|
|
11533
|
+
.q1-cascader__control[data-tags] .q1-cascader__trigger > svg { position: absolute; inset-block-start: calc((var(--q1-control-height-default) - var(--q1-space-4)) / 2); inset-inline-end: var(--q1-space-2); }
|
|
11509
11534
|
.q1-cascader__control[data-tags][data-clearable] .q1-cascader__trigger > svg { inset-inline-end: calc(var(--q1-control-height-default) + var(--q1-space-2)); }
|
|
11510
11535
|
.q1-cascader__remove { position: relative; z-index: 1; pointer-events: auto; }
|
|
11511
11536
|
.q1-cascader__control > .q1-cascader__remove { position: absolute; inset-block-start: 0; inset-inline-end: 0; }
|
|
11512
|
-
.q1-cascader__tags { position: relative; pointer-events: none; min-inline-size: 0; flex: 1; display: flex; flex-wrap: wrap; gap: var(--q1-space-
|
|
11513
|
-
.q1-cascader__tag { max-inline-size: 100%; min-inline-size: 0; display: inline-flex; align-items: center; gap: var(--q1-space-
|
|
11537
|
+
.q1-cascader__tags { position: relative; pointer-events: none; min-inline-size: 0; flex: 1; display: flex; flex-wrap: wrap; gap: var(--q1-space-1); padding: var(--q1-space-2); }
|
|
11538
|
+
.q1-cascader__tag { font-size: var(--q1-font-size-label-14); line-height: var(--q1-line-height-label-14); max-inline-size: 100%; min-inline-size: 0; display: inline-flex; align-items: center; gap: var(--q1-space-1); background: var(--q1-color-bg-hover); border-radius: var(--q1-radius-1); padding-inline-start: var(--q1-space-2); overflow-wrap: anywhere; }
|
|
11514
11539
|
.q1-cascader__tag > span { min-inline-size: 0; }
|
|
11515
|
-
.q1-cascader__tag .q1-cascader__remove { pointer-events: auto; flex: none; }
|
|
11540
|
+
.q1-cascader__tag .q1-cascader__remove { pointer-events: auto; flex: none; min-block-size: var(--q1-space-6); min-inline-size: var(--q1-space-6); padding: 0; border-radius: var(--q1-radius-1); color: inherit; }
|
|
11516
11541
|
.q1-cascader__option [data-selection-area] { display: inline-flex; align-items: center; justify-content: center; flex: none; align-self: stretch; inline-size: var(--q1-control-height-default); margin: calc(var(--q1-space-2) * -1) 0 calc(var(--q1-space-2) * -1) calc(var(--q1-space-3) * -1); }
|
|
11517
11542
|
.q1-cascader__remove, .q1-cascader__back { display: inline-flex; align-items: center; justify-content: center; min-block-size: var(--q1-control-height-default); min-inline-size: var(--q1-control-height-default); padding: var(--q1-space-2); border: none; border-radius: var(--q1-radius-2); background: none; color: var(--q1-color-text-secondary); font: inherit; cursor: pointer; }
|
|
11518
11543
|
.q1-cascader__remove:focus-visible, .q1-cascader__back:focus-visible, .q1-cascader__search:focus-visible, .q1-cascader__list:focus-visible { outline: none; box-shadow: var(--q1-shadow-focus-input); }
|
|
11519
11544
|
.q1-cascader__popup.popover-panel { max-inline-size: calc(100vw - var(--q1-space-6)); padding: var(--q1-space-2); border-radius: var(--q1-radius-3); background: var(--q1-color-bg-overlay); }
|
|
11520
11545
|
.q1-cascader__panel { display: grid; gap: var(--q1-space-2); min-inline-size: 0; }
|
|
11521
|
-
.q1-cascader__search { box-sizing: border-box; inline-size: 100%; min-block-size: var(--q1-control-height-default); padding: var(--q1-space-2) var(--q1-space-3); border: calc(var(--q1-space-1) / 4) solid var(--q1-color-border); border-radius: var(--q1-radius-2); background: var(--q1-color-bg-sunken); color: var(--q1-color-text-primary); font: inherit; font-size: var(--q1-font-size-label-14); }
|
|
11546
|
+
.q1-cascader__search { box-sizing: border-box; inline-size: 100%; min-block-size: var(--q1-control-height-default); padding: var(--q1-space-2) var(--q1-space-3); border: calc(var(--q1-space-1) / 4) solid var(--q1-color-border-control); border-radius: var(--q1-radius-2); background: var(--q1-color-bg-sunken); color: var(--q1-color-text-primary); font: inherit; font-size: var(--q1-font-size-label-14); }
|
|
11522
11547
|
.q1-cascader__columns { display: flex; overflow-x: auto; min-inline-size: 0; max-inline-size: calc(100vw - var(--q1-space-6) * 2); }
|
|
11523
11548
|
.q1-cascader__column { flex: 0 0 auto; inline-size: calc(var(--q1-space-10) * 6); min-inline-size: 0; max-inline-size: 100%; }
|
|
11524
11549
|
.q1-cascader__column[hidden] { display: none; }
|
|
@@ -11544,7 +11569,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
11544
11569
|
.q1-cascader__control[data-clearable]:not([data-tags]) .q1-cascader__trigger { margin-inline-end: var(--q1-touch-target-min); }
|
|
11545
11570
|
.q1-cascader__control[data-tags] .q1-cascader__trigger > svg { inset-block-start: calc((var(--q1-touch-target-min) - var(--q1-space-4)) / 2); }
|
|
11546
11571
|
.q1-cascader__control[data-tags][data-clearable] .q1-cascader__trigger > svg { inset-inline-end: calc(var(--q1-touch-target-min) + var(--q1-space-2)); }
|
|
11547
|
-
.q1-cascader__remove { min-inline-size: var(--q1-touch-target-min); }
|
|
11572
|
+
.q1-cascader__remove, .q1-cascader__tag .q1-cascader__remove { min-inline-size: var(--q1-touch-target-min); min-block-size: var(--q1-touch-target-min); }
|
|
11548
11573
|
}
|
|
11549
11574
|
|
|
11550
11575
|
/* 未知总量以往返移动表示持续等待;减弱动态时保留居中填充段,不伪装完成比例。 */
|
|
@@ -12474,7 +12499,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
12474
12499
|
|
|
12475
12500
|
.multi-combobox { min-width: 0; }
|
|
12476
12501
|
.multi-combobox__control { box-sizing: border-box; position: relative; display: flex; align-items: center; gap: var(--q1-space-2); min-height: var(--q1-control-height-default); padding: var(--q1-space-1) var(--q1-space-3); border: calc(var(--q1-space-1) / 4) solid var(--q1-color-border-control); border-radius: var(--q1-radius-2); background: var(--q1-color-bg-sunken); }
|
|
12477
|
-
.multi-combobox__trigger { position: absolute; inset: 0; width: 100%; border: 0; border-radius: inherit; background: transparent; cursor: pointer; }
|
|
12502
|
+
.multi-combobox__trigger { font: inherit; position: absolute; inset: 0; width: 100%; border: 0; border-radius: inherit; background: transparent; cursor: pointer; }
|
|
12478
12503
|
.multi-combobox__trigger:focus { outline: none; }
|
|
12479
12504
|
.multi-combobox__control:has(.multi-combobox__trigger:focus-visible) { box-shadow: var(--q1-shadow-focus); }
|
|
12480
12505
|
.multi-combobox__control[data-invalid] { border-color: var(--q1-color-status-danger); box-shadow: 0 0 0 calc(var(--q1-space-1) / 4) var(--q1-color-status-danger), 0 0 0 var(--q1-space-1) var(--q1-color-red-100); }
|
|
@@ -12484,7 +12509,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
12484
12509
|
.multi-combobox__values { display: flex; flex: 1; flex-wrap: wrap; align-items: center; gap: var(--q1-space-1); min-width: 0; pointer-events: none; font-size: var(--q1-font-size-label-14); line-height: var(--q1-line-height-label-14); }
|
|
12485
12510
|
.multi-combobox__tag { position: relative; display: inline-flex; align-items: center; gap: var(--q1-space-1); max-width: 100%; padding-inline-start: var(--q1-space-2); border-radius: var(--q1-radius-1); background: var(--q1-color-bg-hover); color: var(--q1-color-text-primary); }
|
|
12486
12511
|
.multi-combobox__tag > span { min-width: 0; overflow-wrap: anywhere; }
|
|
12487
|
-
.multi-combobox__remove { position: relative; display: inline-flex; align-items: center; justify-content: center; flex: none; min-width: var(--q1-space-6); min-height: var(--q1-space-6); padding: 0; border: 0; border-radius: var(--q1-radius-1); background: transparent; color: inherit; pointer-events: auto; cursor: pointer; }
|
|
12512
|
+
.multi-combobox__remove { font: inherit; position: relative; display: inline-flex; align-items: center; justify-content: center; flex: none; min-width: var(--q1-space-6); min-height: var(--q1-space-6); padding: 0; border: 0; border-radius: var(--q1-radius-1); background: transparent; color: inherit; pointer-events: auto; cursor: pointer; }
|
|
12488
12513
|
.multi-combobox__remove:disabled { cursor: default; }
|
|
12489
12514
|
.multi-combobox__remove:focus-visible { outline: none; box-shadow: var(--q1-shadow-focus); }
|
|
12490
12515
|
.multi-combobox__placeholder { color: var(--q1-color-text-muted); }
|
|
@@ -12560,6 +12585,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
12560
12585
|
.command-palette__hint,
|
|
12561
12586
|
.command-palette__close,
|
|
12562
12587
|
.command-palette__kbd {
|
|
12588
|
+
font: inherit;
|
|
12563
12589
|
border-radius: var(--q1-radius-1);
|
|
12564
12590
|
background: color-mix(in srgb, var(--q1-color-text-primary) 8%, transparent);
|
|
12565
12591
|
color: var(--q1-color-text-secondary);
|
|
@@ -12583,6 +12609,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
12583
12609
|
}
|
|
12584
12610
|
|
|
12585
12611
|
.command-palette__backdrop {
|
|
12612
|
+
font: inherit;
|
|
12586
12613
|
position: absolute;
|
|
12587
12614
|
inset: 0;
|
|
12588
12615
|
border: 0;
|
|
@@ -13073,6 +13100,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
13073
13100
|
}
|
|
13074
13101
|
|
|
13075
13102
|
.copy-button {
|
|
13103
|
+
font: inherit;
|
|
13076
13104
|
display: grid;
|
|
13077
13105
|
place-items: center;
|
|
13078
13106
|
width: var(--q1-space-8);
|
|
@@ -13197,6 +13225,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
13197
13225
|
}
|
|
13198
13226
|
|
|
13199
13227
|
.clearable__clear {
|
|
13228
|
+
font: inherit;
|
|
13200
13229
|
display: grid;
|
|
13201
13230
|
place-items: center;
|
|
13202
13231
|
width: var(--q1-space-6);
|
|
@@ -13290,6 +13319,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
13290
13319
|
}
|
|
13291
13320
|
|
|
13292
13321
|
.codeblock__tab {
|
|
13322
|
+
font: inherit;
|
|
13293
13323
|
min-height: var(--q1-space-6);
|
|
13294
13324
|
padding: calc(var(--q1-space-1) / 2) var(--q1-space-3);
|
|
13295
13325
|
border: none;
|
|
@@ -13486,6 +13516,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
13486
13516
|
}
|
|
13487
13517
|
|
|
13488
13518
|
.description__hint {
|
|
13519
|
+
font: inherit;
|
|
13489
13520
|
display: inline-grid;
|
|
13490
13521
|
place-items: center;
|
|
13491
13522
|
width: var(--q1-space-6);
|
|
@@ -13639,6 +13670,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
13639
13670
|
触屏下 TouchTarget 再扩到 --q1-touch-target-min。 */
|
|
13640
13671
|
.info-tip__trigger,
|
|
13641
13672
|
.info-tip__close {
|
|
13673
|
+
font: inherit;
|
|
13642
13674
|
position: relative;
|
|
13643
13675
|
display: inline-grid;
|
|
13644
13676
|
place-items: center;
|
|
@@ -13959,6 +13991,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
13959
13991
|
}
|
|
13960
13992
|
|
|
13961
13993
|
.corner-remove-button {
|
|
13994
|
+
font: inherit;
|
|
13962
13995
|
position: absolute;
|
|
13963
13996
|
top: 0;
|
|
13964
13997
|
right: 0;
|
|
@@ -14881,7 +14914,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
14881
14914
|
.composer textarea::placeholder { color: var(--q1-color-text-muted); }
|
|
14882
14915
|
.composer__tools { display: flex; align-items: center; gap: var(--q1-space-3); padding: var(--q1-space-2); }
|
|
14883
14916
|
.composer__tools > .button { margin-left: auto; }
|
|
14884
|
-
.composer__icon { position: relative; --touch-target-border-width: 0px; display: grid; place-items: center; border: 0; background: transparent; color: var(--q1-color-text-secondary); width: var(--q1-space-7); height: var(--q1-space-7); border-radius: var(--q1-radius-2); }
|
|
14917
|
+
.composer__icon { font: inherit; position: relative; --touch-target-border-width: 0px; display: grid; place-items: center; border: 0; background: transparent; color: var(--q1-color-text-secondary); width: var(--q1-space-7); height: var(--q1-space-7); border-radius: var(--q1-radius-2); }
|
|
14885
14918
|
.composer__icon:hover { background: var(--q1-color-bg-hover); }
|
|
14886
14919
|
.composer__icon:focus-visible { outline: none; box-shadow: var(--q1-shadow-focus); }
|
|
14887
14920
|
.composer__attachments { display: flex; flex-wrap: wrap; gap: var(--q1-space-2); padding: var(--q1-space-2); }
|
|
@@ -14909,7 +14942,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
14909
14942
|
.attachment__retry { position: relative; --touch-target-border-width: 0px; border: 0; padding: 0; background: transparent; color: var(--q1-color-text-primary); font: inherit; font-weight: var(--q1-font-weight-medium); border-radius: var(--q1-radius-1); cursor: pointer; }
|
|
14910
14943
|
.attachment__retry:hover { text-decoration: underline; }
|
|
14911
14944
|
.attachment__retry:focus-visible { outline: none; box-shadow: var(--q1-shadow-focus); }
|
|
14912
|
-
.attachment__remove { position: relative; --touch-target-border-width: 0px; border: 0; background: transparent; color: var(--q1-color-text-muted); display: grid; place-items: center; width: var(--q1-space-6); height: var(--q1-space-6); border-radius: var(--q1-radius-1); flex-shrink: 0; }
|
|
14945
|
+
.attachment__remove { font: inherit; position: relative; --touch-target-border-width: 0px; border: 0; background: transparent; color: var(--q1-color-text-muted); display: grid; place-items: center; width: var(--q1-space-6); height: var(--q1-space-6); border-radius: var(--q1-radius-1); flex-shrink: 0; }
|
|
14913
14946
|
.attachment__remove:hover { background: var(--q1-color-bg-hover); }
|
|
14914
14947
|
.attachment__remove:focus-visible { outline: none; box-shadow: var(--q1-shadow-focus); }
|
|
14915
14948
|
@media (pointer: coarse), (any-pointer: coarse) { .attachment { gap: var(--q1-space-4); padding: var(--q1-space-3); } }
|
|
@@ -15001,6 +15034,7 @@ a.q1-navigation__item[aria-disabled='true'] {
|
|
|
15001
15034
|
}
|
|
15002
15035
|
|
|
15003
15036
|
.feedback__emotion {
|
|
15037
|
+
font: inherit;
|
|
15004
15038
|
display: grid;
|
|
15005
15039
|
place-items: center;
|
|
15006
15040
|
width: var(--q1-space-8);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@q1travel/design-system",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.13",
|
|
4
4
|
"description": "React components, design tokens, and interface contracts for q1travel products.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -55,15 +55,15 @@
|
|
|
55
55
|
"preview": "vite preview --host 127.0.0.1",
|
|
56
56
|
"check:shell": "npm run sync:contracts && node scripts/check-shell.mjs && node scripts/check-token-package.mjs && npm run check:release-provenance",
|
|
57
57
|
"check:browser:strictmode": "node scripts/check-browser.mjs --strictmode-ref",
|
|
58
|
-
"check:browser": "node --test scripts/devtools-connection.test.mjs scripts/browser-exit-deadline.test.mjs scripts/chromium-teardown.test.mjs scripts/vite-server-lifecycle.test.mjs scripts/chromium-launch.test.mjs scripts/chromium-recovery.test.mjs scripts/chromium-ownership.test.mjs scripts/cdp-recovery.test.mjs && npm run check:browser:strictmode && node scripts/check-browser.mjs --note && node scripts/check-browser.mjs --combobox-panel && node scripts/check-browser.mjs && node scripts/check-clearable-input-browser.mjs && node scripts/check-calendar-browser.mjs && node scripts/check-banner-browser.mjs && node scripts/check-button-link-browser.mjs && node scripts/check-button-browser.mjs && node scripts/check-trailing-icon-padding-browser.mjs && node scripts/check-overlay-theme-browser.mjs && node scripts/check-browser-component-browser.mjs",
|
|
59
|
-
"check:package-api": "node scripts/check-package-api.mjs && node --test scripts/check-public-type-global-augmentations.test.mjs && node --test scripts/check-combobox-required.test.mjs scripts/check-multi-combobox-contract.test.mjs && node --test scripts/check-q1-design-lint.test.mjs scripts/check-q1-design-bin-entry.test.mjs && node --test scripts/check-json-view-contract.test.mjs && node --test scripts/check-verification-code-input.test.mjs && node --test scripts/check-bare-field-error.test.mjs scripts/check-label-hidden-contract.test.mjs scripts/check-required-indicator-contract.test.mjs scripts/check-spinner-inherit-contract.test.mjs && node --test scripts/check-controls-contract.test.mjs && node --test scripts/check-pagination-contract.test.mjs && node --test scripts/check-table-core.test.mjs scripts/check-table-interaction.test.mjs scripts/check-table-layout.test.mjs && node --test scripts/check-contrast-contract.test.mjs && node --test scripts/check-optical-alignment-contract.test.mjs && node --test scripts/check-overlay-coordination.test.mjs scripts/check-sheet-contract.test.mjs && node --test scripts/check-choicebox-contract.test.mjs && node --test scripts/check-radio-group-contract.test.mjs && node --test scripts/check-clearable-input-contract.test.mjs && node --test scripts/check-card-contract.test.mjs && node --test scripts/check-book-contract.test.mjs && node --test scripts/check-breadcrumbs-contract.test.mjs && node --test scripts/check-description-contract.test.mjs && node --test scripts/check-error-message-contract.test.mjs && node --test scripts/check-show-more-contract.test.mjs && node --test scripts/check-load-more-button-contract.test.mjs && node --test scripts/check-banner-contract.test.mjs && node --test scripts/check-project-banner-contract.test.mjs && node --test scripts/check-note-contract.test.mjs && node --test scripts/check-feedback-contract.test.mjs && node --test scripts/check-page-feedback-contract.test.mjs && node --test scripts/check-drawer-gesture.test.mjs && node --test scripts/check-checkbox-circle-contract.test.mjs && node --test scripts/check-chat-contract.test.mjs && node --test scripts/check-calendar-single-contract.test.mjs && node --test scripts/check-hover-card-contract.test.mjs && node --test scripts/check-bare-field-error.test.mjs && node --test scripts/check-controls-contract.test.mjs scripts/check-control-size-contract.test.mjs && node --test scripts/check-composer-dots-menu-contract.test.mjs && node --test scripts/check-filter-option-panel-contract.test.mjs && npm run check:release-diff",
|
|
58
|
+
"check:browser": "node --test scripts/cascader-browser-lifecycle.test.mjs scripts/devtools-connection.test.mjs scripts/browser-exit-deadline.test.mjs scripts/chromium-teardown.test.mjs scripts/vite-server-lifecycle.test.mjs scripts/chromium-launch.test.mjs scripts/chromium-recovery.test.mjs scripts/chromium-ownership.test.mjs scripts/cdp-recovery.test.mjs && npm run check:browser:strictmode && node scripts/check-browser.mjs --note && node scripts/check-browser.mjs --combobox-panel && node scripts/check-browser.mjs && node scripts/check-clearable-input-browser.mjs && node scripts/check-calendar-browser.mjs && node scripts/check-banner-browser.mjs && node scripts/check-button-link-browser.mjs && node scripts/check-button-browser.mjs && node scripts/check-trailing-icon-padding-browser.mjs && node scripts/check-overlay-theme-browser.mjs && node scripts/check-browser-component-browser.mjs",
|
|
59
|
+
"check:package-api": "node scripts/check-package-api.mjs && node --test scripts/check-public-type-global-augmentations.test.mjs && node --test scripts/check-combobox-required.test.mjs scripts/check-multi-combobox-contract.test.mjs && node --test scripts/check-q1-design-lint.test.mjs scripts/check-q1-design-component-enums.test.mjs scripts/check-q1-design-bin-entry.test.mjs && node --test scripts/check-json-view-contract.test.mjs && node --test scripts/check-verification-code-input.test.mjs && node --test scripts/check-bare-field-error.test.mjs scripts/check-label-hidden-contract.test.mjs scripts/check-required-indicator-contract.test.mjs scripts/check-spinner-inherit-contract.test.mjs && node --test scripts/check-controls-contract.test.mjs && node --test scripts/check-pagination-contract.test.mjs && node --test scripts/check-table-core.test.mjs scripts/check-table-interaction.test.mjs scripts/check-table-layout.test.mjs && node --test scripts/check-contrast-contract.test.mjs && node --test scripts/check-optical-alignment-contract.test.mjs && node --test scripts/check-overlay-coordination.test.mjs scripts/check-sheet-contract.test.mjs && node --test scripts/check-choicebox-contract.test.mjs && node --test scripts/check-radio-group-contract.test.mjs && node --test scripts/check-clearable-input-contract.test.mjs && node --test scripts/check-card-contract.test.mjs && node --test scripts/check-book-contract.test.mjs && node --test scripts/check-breadcrumbs-contract.test.mjs && node --test scripts/check-description-contract.test.mjs && node --test scripts/check-error-message-contract.test.mjs && node --test scripts/check-show-more-contract.test.mjs && node --test scripts/check-load-more-button-contract.test.mjs && node --test scripts/check-banner-contract.test.mjs && node --test scripts/check-project-banner-contract.test.mjs && node --test scripts/check-note-contract.test.mjs && node --test scripts/check-feedback-contract.test.mjs && node --test scripts/check-page-feedback-contract.test.mjs && node --test scripts/check-drawer-gesture.test.mjs && node --test scripts/check-checkbox-circle-contract.test.mjs && node --test scripts/check-chat-contract.test.mjs && node --test scripts/check-calendar-single-contract.test.mjs && node --test scripts/check-hover-card-contract.test.mjs && node --test scripts/check-bare-field-error.test.mjs && node --test scripts/check-controls-contract.test.mjs scripts/check-control-size-contract.test.mjs && node --test scripts/check-composer-dots-menu-contract.test.mjs && node --test scripts/check-filter-option-panel-contract.test.mjs && npm run check:release-diff",
|
|
60
60
|
"check:release-diff": "node --test scripts/check-release-artifact-diff.test.mjs && node scripts/check-release-artifact-diff.mjs",
|
|
61
61
|
"check:release-provenance": "node --test scripts/check-release-provenance.test.mjs && node scripts/check-release-provenance.mjs",
|
|
62
62
|
"check:release-sync": "node --test scripts/release-sync.test.mjs scripts/release-preview-version.test.mjs",
|
|
63
63
|
"release:verify": "node scripts/release-sync.mjs --verify-only",
|
|
64
64
|
"release:sync": "node scripts/release-sync.mjs",
|
|
65
65
|
"check": "npm run check:release-sync && npm run build && npm run check:shell && npm run check:browser && npm run build:pkg",
|
|
66
|
-
"build:lib": "vite build --config vite.lib.config.ts",
|
|
66
|
+
"build:lib": "vite build --config vite.lib.config.ts && node scripts/build-component-enums.mjs",
|
|
67
67
|
"build:style": "node scripts/build-style.mjs",
|
|
68
68
|
"build:pkg": "npm run build:lib && npm run build:style && npm run check:package-api",
|
|
69
69
|
"prepack": "npm run build:pkg"
|
package/tooling/README.md
CHANGED
|
@@ -6,4 +6,10 @@
|
|
|
6
6
|
- `evals/fixtures.json` —— eval fixture 索引。
|
|
7
7
|
- `evals/<fixture>/{before,after}/` —— 每条规则的前后态样例,用来测 skill / linter 是否产出预期改动。
|
|
8
8
|
|
|
9
|
-
**现状**:`q1-design lint` 已实现 `Q1-DS-001`(`--ds-*`)/`Q1-DS-401`(`transition: all`)/`Q1-DS-404`(裸 duration/easing)/`Q1-DS-501`(裸颜色字面量)
|
|
9
|
+
**现状**:`q1-design lint` 已实现 `Q1-DS-001`(`--ds-*`)/`Q1-DS-401`(`transition: all`)/`Q1-DS-404`(裸 duration/easing)/`Q1-DS-501`(裸颜色字面量)与 `Q1-DS-002`(组件 `variant` / `size` 非法字符串字面量)五条纯机械规则;`q1-design eval` 已实现,对每个 fixture 校验 before 命中且 after 零命中。`q1-design overrides` 统计消费方对组件的 className 覆写并按「重画外观/仅布局」分类——它不是 pass/fail 规则,因为覆写布局是正当用法,拦它的规则最后会被整体关掉。其余 `kind=deterministic` 规则(含判断成分)与全部 `kind=judgment` 规则待后续批次。见 `../.agents/skills/product-design/references/coverage-gaps.md`。
|
|
10
|
+
|
|
11
|
+
`Q1-DS-002` 为 error:仅检查直接从 `@q1travel/design-system` 导入的组件(含命名别名、命名空间),不追踪消费方再导出或运行时赋值;局部同名组件不受影响。允许值来自随包 `dist-pkg/design-system.d.ts` 中组件 props 的有限字符串联合,覆盖 `Button` 及其他声明了此类 `variant` / `size` 的导出组件。`variant="quiet"`、`variant={'quiet'}` 会检查,`variant={value}` 与条件表达式交给消费方类型检查。诊断包含文件、行号、组件、属性、非法值和允许值;命中退出 1,支持现有文件、区间和下一行 pragma。检测到相关字面量却缺少类型声明时退出 1 并提示修复,不能静默跳过。
|
|
12
|
+
|
|
13
|
+
CLI 通过运行时依赖 TypeScript 解析 JSX 与词法绑定,避免把注释、字符串或被遮蔽的同名组件误当成包组件;不依赖消费方开发依赖或本仓源码。
|
|
14
|
+
|
|
15
|
+
在本仓直跑组件规则或对应 CLI 测试前,运行 `npm run build:lib` 生成类型声明;仅扫描 CSS 不要求该产物。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"note": "q1travel 产品设计确定性规则清单。每条带稳定 ID + canonical 出处。kind=deterministic 的可由 linter 静态强制;kind=judgment 的留给 product-design skill / Review。linter CLI 与 eval runner 已实现:`q1-design lint`(Q1-DS-001/401/501)与 `q1-design eval`(bin/q1-design.mjs);覆盖缺口见 ../../../.agents/skills/product-design/references/coverage-gaps.md。",
|
|
2
|
+
"note": "q1travel 产品设计确定性规则清单。每条带稳定 ID + canonical 出处。kind=deterministic 的可由 linter 静态强制;kind=judgment 的留给 product-design skill / Review。linter CLI 与 eval runner 已实现:`q1-design lint`(Q1-DS-001/002/401/404/501)与 `q1-design eval`(bin/q1-design.mjs);覆盖缺口见 ../../../.agents/skills/product-design/references/coverage-gaps.md。",
|
|
3
3
|
"version": 0,
|
|
4
4
|
"idScheme": {
|
|
5
5
|
"0xx": "token 与事实源",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"rules": [
|
|
13
13
|
{ "id": "Q1-DS-001", "title": "新代码用 --q1-*,不用 --ds-*", "source": "contracts/token-naming.md", "severity": "error", "kind": "deterministic", "detect": "新增/改动代码里出现 --ds-* 声明或作为新决策源名", "fix": "改用 --q1-* canonical token" },
|
|
14
|
+
{ "id": "Q1-DS-002", "title": "组件枚举属性仅使用公开值", "source": "dist-pkg/design-system.d.ts", "severity": "error", "kind": "deterministic", "detect": "直接从包导入的组件,其 variant / size 字符串字面量不在 props 有限联合中", "fix": "使用诊断列出的公开允许值,动态表达式交给类型检查" },
|
|
14
15
|
{ "id": "Q1-DS-101", "title": "导航用原生 link、动作用原生 button", "source": "contracts/interface-guidelines.md#interactions", "severity": "error", "kind": "judgment", "detect": "用 div/span + onClick 承载导航或动作", "fix": "导航用 <a href>,动作用 <button>" },
|
|
15
16
|
{ "id": "Q1-DS-102", "title": "命中区 ≥24px(触摸 44px)", "source": "contracts/interface-guidelines.md#interactions", "severity": "warn", "kind": "judgment", "detect": "可点击元素视觉/命中区小于 24px 且未扩大命中区", "fix": "min-width/height + 负 margin 扩大命中区,不撑高容器" },
|
|
16
17
|
{ "id": "Q1-DS-301", "title": "icon-only 控件必须有可访问名", "source": "contracts/interface-guidelines.md#content-and-accessibility", "severity": "error", "kind": "judgment", "detect": "只含图标的 button/link 无 aria-label / 可访问名", "fix": "补 aria-label 或视觉隐藏文本" },
|