@manohub/app-kit 0.1.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.
Files changed (103) hide show
  1. package/CONTRACT.md +592 -0
  2. package/README.md +27 -0
  3. package/dist/atoms/app-button.d.ts +90 -0
  4. package/dist/atoms/app-button.js +74 -0
  5. package/dist/atoms/app-checkbox.d.ts +86 -0
  6. package/dist/atoms/app-checkbox.js +78 -0
  7. package/dist/atoms/app-icon-button.d.ts +79 -0
  8. package/dist/atoms/app-icon-button.js +54 -0
  9. package/dist/atoms/app-input.d.ts +118 -0
  10. package/dist/atoms/app-input.js +83 -0
  11. package/dist/atoms/app-layout.d.ts +348 -0
  12. package/dist/atoms/app-layout.js +102 -0
  13. package/dist/atoms/app-notice.d.ts +90 -0
  14. package/dist/atoms/app-notice.js +59 -0
  15. package/dist/atoms/app-query-state.d.ts +191 -0
  16. package/dist/atoms/app-query-state.js +161 -0
  17. package/dist/atoms/app-radio-card.d.ts +80 -0
  18. package/dist/atoms/app-radio-card.js +72 -0
  19. package/dist/atoms/app-search-box.d.ts +80 -0
  20. package/dist/atoms/app-search-box.js +64 -0
  21. package/dist/atoms/app-select.d.ts +106 -0
  22. package/dist/atoms/app-select.js +74 -0
  23. package/dist/atoms/app-switch.d.ts +72 -0
  24. package/dist/atoms/app-switch.js +66 -0
  25. package/dist/atoms/app-textarea.d.ts +89 -0
  26. package/dist/atoms/app-textarea.js +61 -0
  27. package/dist/atoms/app-tooltip.d.ts +70 -0
  28. package/dist/atoms/app-tooltip.js +48 -0
  29. package/dist/atoms/atoms.css +679 -0
  30. package/dist/atoms/state-illustration.d.ts +21 -0
  31. package/dist/atoms/state-illustration.js +101 -0
  32. package/dist/components/app-badge.d.ts +72 -0
  33. package/dist/components/app-badge.js +40 -0
  34. package/dist/components/app-dialog.d.ts +164 -0
  35. package/dist/components/app-dialog.js +121 -0
  36. package/dist/components/app-filter.d.ts +173 -0
  37. package/dist/components/app-filter.js +200 -0
  38. package/dist/components/app-form.d.ts +446 -0
  39. package/dist/components/app-form.js +159 -0
  40. package/dist/components/app-pagination.d.ts +78 -0
  41. package/dist/components/app-pagination.js +57 -0
  42. package/dist/components/app-panel.d.ts +399 -0
  43. package/dist/components/app-panel.js +213 -0
  44. package/dist/components/app-section.d.ts +68 -0
  45. package/dist/components/app-section.js +28 -0
  46. package/dist/components/app-steps.d.ts +115 -0
  47. package/dist/components/app-steps.js +108 -0
  48. package/dist/components/app-table.d.ts +415 -0
  49. package/dist/components/app-table.js +479 -0
  50. package/dist/components/app-tabs.d.ts +58 -0
  51. package/dist/components/app-tabs.js +54 -0
  52. package/dist/components/app-tree.d.ts +273 -0
  53. package/dist/components/app-tree.js +222 -0
  54. package/dist/components/components.css +597 -0
  55. package/dist/composables/use-client-pagination.d.ts +39 -0
  56. package/dist/composables/use-client-pagination.js +29 -0
  57. package/dist/entry/create-query-client.d.ts +8 -0
  58. package/dist/entry/create-query-client.js +14 -0
  59. package/dist/entry/create-sub-app.d.ts +45 -0
  60. package/dist/entry/create-sub-app.js +110 -0
  61. package/dist/entry/index.d.ts +4 -0
  62. package/dist/entry/index.js +12 -0
  63. package/dist/entry/initial-guard.d.ts +12 -0
  64. package/dist/entry/initial-guard.js +23 -0
  65. package/dist/index.d.ts +37 -0
  66. package/dist/index.js +67 -0
  67. package/dist/providers/setup-i18n.d.ts +19 -0
  68. package/dist/providers/setup-i18n.js +24 -0
  69. package/dist/services/app-container.d.ts +15 -0
  70. package/dist/services/app-container.js +7 -0
  71. package/dist/services/app-context.d.ts +4 -0
  72. package/dist/services/app-context.js +17 -0
  73. package/dist/services/index.d.ts +5 -0
  74. package/dist/services/loading.d.ts +16 -0
  75. package/dist/services/loading.js +27 -0
  76. package/dist/services/message-box.d.ts +84 -0
  77. package/dist/services/message-box.js +65 -0
  78. package/dist/services/modal.d.ts +51 -0
  79. package/dist/services/modal.js +51 -0
  80. package/dist/services/notify.d.ts +24 -0
  81. package/dist/services/notify.js +22 -0
  82. package/dist/shell/AppShell.d.ts +139 -0
  83. package/dist/shell/AppShell.js +171 -0
  84. package/dist/shell/shell.css +153 -0
  85. package/dist/styles/farris-bridge.css +129 -0
  86. package/dist/styles/index.css +16 -0
  87. package/dist/styles/markdown.css +85 -0
  88. package/dist/styles/reset.css +74 -0
  89. package/dist/styles/tokens.css +111 -0
  90. package/lint/__tests__/fixtures/clean-src/styles.css +14 -0
  91. package/lint/__tests__/fixtures/clean-src/views/good-page.tsx +15 -0
  92. package/lint/__tests__/fixtures/violations-src/styles.css +18 -0
  93. package/lint/__tests__/fixtures/violations-src/views/bad-page.tsx +38 -0
  94. package/lint/__tests__/fixtures/violations-src/views/no-shell-page.tsx +4 -0
  95. package/lint/__tests__/guardrails.spec.mjs +144 -0
  96. package/lint/component-audit.mjs +131 -0
  97. package/lint/guardrails.config.schema.json +74 -0
  98. package/lint/pre-commit.sample +26 -0
  99. package/lint/run-all.mjs +59 -0
  100. package/lint/shared.mjs +347 -0
  101. package/lint/structure-audit.mjs +254 -0
  102. package/lint/style-audit.mjs +200 -0
  103. package/package.json +78 -0
@@ -0,0 +1,679 @@
1
+ /**
2
+ * app-kit 组件样式(.ak-*)+ 骨架屏动画。
3
+ * 允许的视觉声明集中在 app-kit;apps 侧业务 CSS 只写布局。
4
+ */
5
+
6
+ /* ===== 骨架屏 ===== */
7
+ @keyframes ak-shimmer {
8
+ 0% { background-position: -200% 0; }
9
+ 100% { background-position: 200% 0; }
10
+ }
11
+
12
+ .ak-skeleton-block {
13
+ border-radius: var(--ui-radius-md);
14
+ background: linear-gradient(90deg, var(--ui-base-200) 25%, var(--ui-base-300) 37%, var(--ui-base-200) 63%);
15
+ background-size: 200% 100%;
16
+ animation: ak-shimmer 1.5s infinite linear;
17
+ }
18
+
19
+ /* ===== 三态(AppQueryState)=====
20
+ 构成顺序固定:**插画 → 主文案 → 副文案 → 操作区**(整块垂直居中)。
21
+ 留白节奏同控制台空态一档:插画下 16、标题下 4、副文案下 16;文案层级用字号 + 字重 + 灰度拉开,
22
+ 不靠多色分隔 —— 状态块是页面的「静默区」,视觉噪音要低。 */
23
+ .ak-state {
24
+ height: 100%;
25
+ min-height: 200px;
26
+ display: flex;
27
+ flex-direction: column;
28
+ align-items: center;
29
+ justify-content: center;
30
+ padding: var(--ui-space-6);
31
+ text-align: center;
32
+ }
33
+
34
+ /* 插画:宽度定死、高度按比例;窄容器(如侧栏)里按百分比收缩,不撑破面板 */
35
+ .ak-state-illustration {
36
+ width: 180px;
37
+ max-width: 70%;
38
+ height: auto;
39
+ margin-bottom: var(--ui-space-4);
40
+ }
41
+
42
+ /* 插画元素配色:几何在 state-illustration.tsx,颜色只在本文件(换皮只动样式)。
43
+ 描边统一用 base-400:基础阶里 base-300 及以下在白底上几乎看不见,插画会「化」掉。 */
44
+ .ak-ill-shadow {
45
+ fill: var(--ui-base-200);
46
+ }
47
+
48
+ .ak-ill-face {
49
+ stroke: var(--ui-base-400);
50
+ stroke-width: 1.5;
51
+ stroke-linejoin: round;
52
+ }
53
+
54
+ .ak-ill-face--top {
55
+ fill: var(--ui-base-200);
56
+ }
57
+
58
+ /* 正面白色:三面靠明度差(白 / 浅灰 / 中灰)读体感,不用投影 */
59
+ .ak-ill-face--front {
60
+ fill: var(--ui-base-100);
61
+ }
62
+
63
+ .ak-ill-face--side {
64
+ fill: var(--ui-base-300);
65
+ }
66
+
67
+ .ak-ill-line {
68
+ stroke: var(--ui-base-400);
69
+ stroke-width: 1.5;
70
+ stroke-linecap: round;
71
+ }
72
+
73
+ /* 错误态:箱内线条中断(与空态的实线成对语义) */
74
+ .ak-ill-line--broken {
75
+ stroke-dasharray: 5 5;
76
+ }
77
+
78
+ .ak-ill-dot {
79
+ fill: var(--ui-base-400);
80
+ }
81
+
82
+ .ak-ill-dot--accent {
83
+ fill: var(--ui-primary);
84
+ opacity: 0.45;
85
+ }
86
+
87
+ .ak-ill-badge__disc {
88
+ fill: var(--ui-primary-subtle);
89
+ stroke: var(--ui-primary);
90
+ stroke-width: 1.5;
91
+ }
92
+
93
+ .ak-ill-badge__mark {
94
+ stroke: var(--ui-primary);
95
+ stroke-width: 2;
96
+ stroke-linecap: round;
97
+ }
98
+
99
+ .ak-ill-badge--error .ak-ill-badge__disc {
100
+ fill: var(--ui-error-weak);
101
+ stroke: var(--ui-error);
102
+ }
103
+
104
+ .ak-ill-badge--error .ak-ill-badge__mark {
105
+ stroke: var(--ui-error);
106
+ }
107
+
108
+ .ak-ill-badge--error .ak-ill-badge__dot {
109
+ fill: var(--ui-error);
110
+ }
111
+
112
+ .ak-state-title {
113
+ font-size: var(--ui-font-heading);
114
+ font-weight: var(--ui-weight-medium);
115
+ color: var(--ui-base-content);
116
+ margin: 0;
117
+ }
118
+
119
+ .ak-state-description {
120
+ font-size: var(--ui-font-caption);
121
+ line-height: var(--ui-line-caption);
122
+ color: var(--ui-base-content-subtle);
123
+ max-width: 420px;
124
+ word-break: break-word;
125
+ margin: var(--ui-space-1) 0 0;
126
+ }
127
+
128
+ /* 操作区:默认一颗主按钮;用 actions 插槽时可放多颗(横向排列) */
129
+ .ak-state-actions {
130
+ display: flex;
131
+ align-items: center;
132
+ justify-content: center;
133
+ gap: var(--ui-space-2);
134
+ margin-top: var(--ui-space-4);
135
+ }
136
+
137
+ .ak-state-skeletons {
138
+ width: 100%;
139
+ display: flex;
140
+ flex-direction: column;
141
+ gap: var(--ui-space-3);
142
+ }
143
+
144
+ /* ===== AppTooltip(.ak-tooltip 为浮层钩子类)=====
145
+ 原先各应用各写 tooltip-dark 补丁,此处统一为令牌化外观(深底浅字)。 */
146
+ .app-container .fv-tooltip.ak-tooltip .tooltip-inner {
147
+ background: var(--ui-base-content);
148
+ color: var(--ui-base-100);
149
+ }
150
+
151
+ /* 浮层宽度约束:内容为长文本时避免撑破视口 */
152
+ .app-container .fv-tooltip.ak-tooltip .tooltip-inner {
153
+ max-width: 420px;
154
+ word-break: break-word;
155
+ }
156
+
157
+ /* ===== AppButton shape="ghost":图标按钮的标准形态 =====
158
+ 原先 skill-topic / repository / skill-admission 各自手搓「透明底 + 无边框 + hover 变色」的图标按钮
159
+ (含 !important 军备竞赛),此处一次性上收。两段式 + 形态类压过 farris 的 .btn-secondary 外观。 */
160
+ .app-container .ak-btn--ghost {
161
+ background: transparent;
162
+ border-color: transparent;
163
+ box-shadow: none;
164
+ color: var(--ui-base-content-subtle);
165
+ }
166
+
167
+ .app-container .ak-btn--ghost:hover,
168
+ .app-container .ak-btn--ghost:focus-visible {
169
+ background: transparent;
170
+ border-color: transparent;
171
+ box-shadow: none;
172
+ color: var(--ui-primary);
173
+ outline: none;
174
+ }
175
+
176
+ .app-container .ak-btn--ghost.ak-btn--error:hover,
177
+ .app-container .ak-btn--ghost.ak-btn--error:focus-visible {
178
+ color: var(--ui-error);
179
+ }
180
+
181
+ .app-container .ak-btn--ghost:disabled,
182
+ .app-container .ak-btn--ghost:disabled:hover {
183
+ color: var(--ui-base-content-subtle);
184
+ opacity: 0.4;
185
+ }
186
+
187
+ /* ===== AppIconButton(纯图标按钮):方形点击区 =====
188
+ 形态与色彩继承 .ak-btn--ghost,这里只统一尺寸与内距(图标居中、无文字内距)。 */
189
+ .ak-icon-btn {
190
+ display: inline-flex;
191
+ align-items: center;
192
+ justify-content: center;
193
+ padding: 0;
194
+ }
195
+
196
+ .ak-icon-btn--sm {
197
+ min-width: 28px;
198
+ height: 28px;
199
+ }
200
+
201
+ .ak-icon-btn--md {
202
+ min-width: 32px;
203
+ height: 32px;
204
+ }
205
+
206
+ .ak-icon-btn--lg {
207
+ min-width: 36px;
208
+ height: 36px;
209
+ }
210
+
211
+ /* ===== AppCheckbox(自建复选框,不封装 farris)=====
212
+ 真实 input 负责可访问性与键盘(Tab / Space),方块视觉自绘;
213
+ 状态走 data-state 协议(checked / indeterminate / unchecked),与 AppTable 自绘选择列一致。 */
214
+ .ak-checkbox {
215
+ display: inline-flex;
216
+ align-items: center;
217
+ gap: var(--ui-space-2);
218
+ font-size: var(--ui-font-body);
219
+ color: var(--ui-base-content);
220
+ cursor: pointer;
221
+ user-select: none;
222
+ }
223
+
224
+ .ak-checkbox__input {
225
+ position: absolute;
226
+ width: 1px;
227
+ height: 1px;
228
+ margin: 0;
229
+ padding: 0;
230
+ opacity: 0;
231
+ pointer-events: none;
232
+ }
233
+
234
+ .ak-checkbox__box {
235
+ display: inline-flex;
236
+ align-items: center;
237
+ justify-content: center;
238
+ flex-shrink: 0;
239
+ width: 16px;
240
+ height: 16px;
241
+ border: 1px solid var(--ui-base-400);
242
+ border-radius: var(--ui-radius-sm);
243
+ background: var(--ui-base-100);
244
+ color: var(--ui-base-100);
245
+ transition: background-color 0.15s, border-color 0.15s, color 0.15s;
246
+ }
247
+
248
+ .ak-checkbox--sm .ak-checkbox__box {
249
+ width: 14px;
250
+ height: 14px;
251
+ }
252
+
253
+ .ak-checkbox--lg .ak-checkbox__box {
254
+ width: 18px;
255
+ height: 18px;
256
+ }
257
+
258
+ /*
259
+ * 选中 / 半选:填充**主色**,勾与横杠用 currentColor 绘制。
260
+ *
261
+ * 全库"选中"只有主色一种表达,这里原先填 `--ui-base-content`(近黑)是唯一的例外 ——
262
+ * 一屏里会出现「蓝色开关(farris 走 `--f-theme-*` → 主色)+ 蓝色表格自选列(`accent-color`)+ 黑色勾选框」
263
+ * 三种叫法;`@aihub/theme` 的 checkbox 口径也是「已选择背景取主色 `--f-primary`」。
264
+ * 要再引入中性面填充,做成 `tone` 的第二档(如 `tone="neutral"`),**不要**把默认改回深色。
265
+ */
266
+ .ak-checkbox__box[data-state='checked'],
267
+ .ak-checkbox__box[data-state='indeterminate'] {
268
+ background: var(--ui-primary);
269
+ border-color: var(--ui-primary);
270
+ color: var(--ui-primary-content);
271
+ }
272
+
273
+ .ak-checkbox__dash {
274
+ width: 8px;
275
+ height: 2px;
276
+ border-radius: 1px;
277
+ background: currentColor;
278
+ }
279
+
280
+ .ak-checkbox:hover .ak-checkbox__box {
281
+ border-color: var(--ui-primary);
282
+ }
283
+
284
+ .ak-checkbox:focus-within .ak-checkbox__box {
285
+ outline: 2px solid var(--ui-primary-weak);
286
+ outline-offset: 1px;
287
+ }
288
+
289
+ .ak-checkbox.is-disabled {
290
+ cursor: not-allowed;
291
+ color: var(--ui-base-content-subtle);
292
+ }
293
+
294
+ .ak-checkbox.is-disabled .ak-checkbox__box {
295
+ background: var(--ui-base-200);
296
+ border-color: var(--ui-base-300);
297
+ color: var(--ui-base-content-subtle);
298
+ }
299
+
300
+ .ak-checkbox.is-disabled:hover .ak-checkbox__box {
301
+ border-color: var(--ui-base-300);
302
+ }
303
+
304
+ /* ===== AppNotice(说明条 / 警告提示,自建)=====
305
+ 规范对齐 `@aihub/theme` 的 Alert(`.sem-bar`):通栏 100% 宽、高 42、圆角 6、
306
+ 投影 0 2 10 黑 8%、文案 15px、语义「底 / 边 / 字」三件套;操作位为文字按钮。
307
+
308
+ 与主题包的两处有意差异(都不改结构,只保可读性):
309
+ 1. 文案色:success/warning 取 `-strong` 档(主题包调色板另给了该槽位)——直接用 500 档主色
310
+ 在浅底上对比度不足(如 #22C55E on #ECFDF5 ≈ 1.9:1),属可读性缺陷;
311
+ 2. 警示 / 错误的底色仍按主题包 Alert 专页实测值(#FDF4EA / #FDECEC),不用语义 03 档。 */
312
+ .ak-notice {
313
+ display: flex;
314
+ align-items: center;
315
+ gap: var(--ui-space-2);
316
+ width: 100%;
317
+ min-height: var(--ui-notice-height);
318
+ padding: var(--ui-space-3) var(--ui-space-4);
319
+ border-radius: var(--ui-radius-control);
320
+ box-shadow: var(--ui-notice-shadow);
321
+ font-size: var(--ui-notice-font);
322
+ line-height: var(--ui-line-body);
323
+ }
324
+
325
+ .ak-notice__body {
326
+ flex: 1;
327
+ min-width: 0;
328
+ }
329
+
330
+ /* 说明文案可能是多段(原页面按段落渲染),块间距交给容器,避免与外层再叠一层间距 */
331
+ .ak-notice__body p {
332
+ margin: 0;
333
+ }
334
+
335
+ .ak-notice__action {
336
+ flex-shrink: 0;
337
+ margin-left: auto;
338
+ border: none;
339
+ background: transparent;
340
+ padding: 0;
341
+ font: inherit;
342
+ /* 文字按钮取主色(主题包 --f-alert-action-text = --f-primary) */
343
+ color: var(--ui-primary);
344
+ cursor: pointer;
345
+ }
346
+
347
+ .ak-notice__close {
348
+ flex-shrink: 0;
349
+ margin-left: auto;
350
+ border: none;
351
+ background: transparent;
352
+ padding: 0;
353
+ font-size: var(--ui-font-caption);
354
+ /* 主题包为 --f-text-muted(Te07),本仓对应 --ui-base-content-muted */
355
+ color: var(--ui-base-content-muted);
356
+ cursor: pointer;
357
+ }
358
+
359
+ .ak-notice--info {
360
+ background: var(--ui-info-weak);
361
+ border: 1px solid var(--ui-info-border);
362
+ color: var(--ui-info);
363
+ }
364
+
365
+ .ak-notice--success {
366
+ background: var(--ui-success-weak);
367
+ border: 1px solid var(--ui-success-border);
368
+ color: var(--ui-success-strong);
369
+ }
370
+
371
+ .ak-notice--warning {
372
+ background: var(--ui-notice-warning-bg);
373
+ border: 1px solid var(--ui-warning-border);
374
+ color: var(--ui-warning-strong);
375
+ }
376
+
377
+ .ak-notice--error {
378
+ background: var(--ui-notice-error-bg);
379
+ border: 1px solid var(--ui-error-border);
380
+ color: var(--ui-error);
381
+ }
382
+
383
+ /* ===== AppRadioCard(卡片式单选组,自建)=====
384
+ 一个选项一张卡、整卡可点;选中态由描边 + 浅底 + 圆点三件一起表达(只靠颜色会看不出可点)。
385
+ 真实 input 只保留可访问性与键盘(同 name 成组 ⇒ 方向键即换选),视觉全在卡片上。
386
+ 卡片宽度取 flex 基准 240、上限 360:窄容器自动一列,宽容器两列并排且不无限拉伸。 */
387
+ .ak-radio-card {
388
+ display: flex;
389
+ flex-wrap: wrap;
390
+ gap: var(--ui-space-3);
391
+ }
392
+
393
+ .ak-radio-card__item {
394
+ position: relative;
395
+ flex: 1 1 240px;
396
+ max-width: 360px;
397
+ box-sizing: border-box;
398
+ display: flex;
399
+ align-items: flex-start;
400
+ gap: var(--ui-space-2);
401
+ padding: var(--ui-space-3) var(--ui-space-4);
402
+ border: 1px solid var(--ui-base-300);
403
+ border-radius: var(--ui-radius-md);
404
+ background: var(--ui-base-100);
405
+ cursor: pointer;
406
+ transition: border-color 0.15s, background-color 0.15s;
407
+ }
408
+
409
+ .ak-radio-card__item:hover {
410
+ border-color: var(--ui-primary);
411
+ }
412
+
413
+ .ak-radio-card__item[data-state='checked'] {
414
+ border-color: var(--ui-primary);
415
+ background: var(--ui-primary-subtle);
416
+ }
417
+
418
+ .ak-radio-card__item:focus-within {
419
+ outline: 2px solid var(--ui-primary-weak);
420
+ outline-offset: 1px;
421
+ }
422
+
423
+ .ak-radio-card__item[data-disabled='true'] {
424
+ cursor: not-allowed;
425
+ border-color: var(--ui-base-300);
426
+ background: var(--ui-base-200);
427
+ }
428
+
429
+ .ak-radio-card__item[data-disabled='true']:hover {
430
+ border-color: var(--ui-base-300);
431
+ }
432
+
433
+ /* 原生 radio:视觉由卡片承担(隐藏方式与 AppCheckbox 同款) */
434
+ .ak-radio-card__input {
435
+ position: absolute;
436
+ width: 1px;
437
+ height: 1px;
438
+ margin: 0;
439
+ padding: 0;
440
+ opacity: 0;
441
+ pointer-events: none;
442
+ }
443
+
444
+ .ak-radio-card__radio {
445
+ position: relative;
446
+ flex: 0 0 auto;
447
+ width: 16px;
448
+ height: 16px;
449
+ box-sizing: border-box;
450
+ /* 与标题首行(14px 字 / 22px 行高)视觉居中 */
451
+ margin-top: 3px;
452
+ border: 1px solid var(--ui-base-400);
453
+ border-radius: var(--ui-radius-full);
454
+ background: var(--ui-base-100);
455
+ transition: background-color 0.15s, border-color 0.15s;
456
+ }
457
+
458
+ .ak-radio-card__item[data-state='checked'] .ak-radio-card__radio {
459
+ border-color: var(--ui-primary);
460
+ background: var(--ui-primary);
461
+ }
462
+
463
+ .ak-radio-card__item[data-state='checked'] .ak-radio-card__radio::after {
464
+ content: '';
465
+ position: absolute;
466
+ inset: 0;
467
+ margin: auto;
468
+ width: 6px;
469
+ height: 6px;
470
+ border-radius: var(--ui-radius-full);
471
+ background: var(--ui-primary-content);
472
+ }
473
+
474
+ .ak-radio-card__item[data-disabled='true'] .ak-radio-card__radio {
475
+ border-color: var(--ui-base-400);
476
+ background: var(--ui-base-200);
477
+ }
478
+
479
+ .ak-radio-card__body {
480
+ display: flex;
481
+ flex-direction: column;
482
+ gap: 2px;
483
+ min-width: 0;
484
+ }
485
+
486
+ .ak-radio-card__label {
487
+ font-size: var(--ui-font-body);
488
+ font-weight: var(--ui-weight-medium);
489
+ color: var(--ui-base-content);
490
+ }
491
+
492
+ .ak-radio-card__desc {
493
+ font-size: var(--ui-font-caption);
494
+ line-height: var(--ui-line-caption);
495
+ color: var(--ui-base-content-subtle);
496
+ }
497
+
498
+ .ak-radio-card__item[data-disabled='true'] .ak-radio-card__label,
499
+ .ak-radio-card__item[data-disabled='true'] .ak-radio-card__desc {
500
+ color: var(--ui-base-content-subtle);
501
+ }
502
+
503
+ /* ===== AppLayout(布局原子件)=====
504
+ 应用侧 CSS 只允许写布局,但「布局」也不该各页面各写一套 ——
505
+ `display:flex; align-items:center; gap:8px` 抄十遍之后,间距档与居中口径必然各页不同。
506
+ 两件只做三件事:**轴向**、**间距档**(令牌档位)、**对齐**。
507
+ 分工(**按表格语义,不按 CSS 语义**):
508
+ Row = 排「行」:行与行是上下关系 ⇒ **竖排容器**(不传 columns)/ 一行分 n 列(传了 columns);
509
+ Column = 排「列」:列与列是左右关系 ⇒ **水平容器**(一行里的一格)。
510
+ 所以 `.ak-column` 的 flex-direction 是 **row**、`.ak-row` 是 **column** —— 名字与 CSS 属性正好相反,
511
+ 是刻意的:`<tr>` 一行行往下堆、一行里的格子左右并排,才符合读表格的直觉。 */
512
+
513
+ /* --- 行:竖排容器(默认形态:子项一条一行往下排) --- */
514
+ .ak-row {
515
+ display: flex;
516
+ flex-direction: column;
517
+ gap: var(--ak-row-gap, var(--ui-space-2));
518
+ /* 交叉轴(水平)不声明 = CSS 默认的 stretch(子项齐宽);要居中写 align="center" */
519
+ /* 放开 min-width:行常被塞进窄格子(表格单元格、限宽控件列)——
520
+ 不放开的 flex 容器压不进窄格,会把外层撑破(真实踩过:列编辑表格的「帮助元数据」格) */
521
+ min-width: 0;
522
+ }
523
+
524
+ /* --- 行:一行分 n 列(传了 columns)—— 栅格轨道横向铺,这一行的子项并排 --- */
525
+ .ak-row--grid {
526
+ display: grid;
527
+ /* 交叉轴默认回到 stretch(单元等高);显式 align 的规则排在本条之后,能压过它 */
528
+ align-items: stretch;
529
+ /* 列数上限(--ak-row-columns) + 最小列宽(--ak-row-min):
530
+ auto-fit 决定实际列数,track 下限取「最小列宽」与「按上限等分」的**较大者**
531
+ —— 于是"最多 N 列"与"窄了自动减列"同时成立(实测 N=2/最小 260:1400→2、600→2、500→1 列)。
532
+ 公式里的 `%` 解析的是**栅格容器自己的内联尺寸**(不是视口),所以放进弹窗/分栏同样成立
533
+ —— 这也是不用媒体查询断点的原因。 */
534
+ grid-template-columns: repeat(
535
+ auto-fit,
536
+ minmax(
537
+ max(
538
+ var(--ak-row-min, var(--ui-grid-column-min)),
539
+ calc(
540
+ (100% - (var(--ak-row-columns, 2) - 1) * var(--ak-row-gap, var(--ui-space-2))) /
541
+ var(--ak-row-columns, 2)
542
+ )
543
+ ),
544
+ 1fr
545
+ )
546
+ );
547
+ }
548
+
549
+ /* 折行属于**水平容器**(列里的内容太宽要折行);竖排容器没有"折行"这回事,
550
+ 栅格形态的"折行"由自动减列承担 */
551
+
552
+ /* 列数上限 → 变量(供栅格公式取用)。columns-1 = 一行一列 */
553
+ .ak-row--columns-1 {
554
+ --ak-row-columns: 1;
555
+ }
556
+
557
+ .ak-row--columns-2 {
558
+ --ak-row-columns: 2;
559
+ }
560
+
561
+ .ak-row--columns-3 {
562
+ --ak-row-columns: 3;
563
+ }
564
+
565
+ .ak-row--columns-4 {
566
+ --ak-row-columns: 4;
567
+ }
568
+
569
+ /* --- 列:水平容器(一行里的一格;同时是栅格单元) --- */
570
+ .ak-column {
571
+ display: flex;
572
+ flex-direction: row;
573
+ /* 默认**垂直居中**:列里多是「徽标 + 文本」「标签 + 值」「控件 + 按钮」这类内容要齐中线;
574
+ 要贴顶/齐宽写 align="start" / align="stretch" */
575
+ align-items: center;
576
+ gap: var(--ak-column-gap, var(--ui-space-2));
577
+ min-width: 0;
578
+ }
579
+
580
+ /* 折行:列里的内容太宽要折行(表格单元格里的「按钮 + 摘要」靠它不撑破外层) */
581
+ .ak-column--wrap {
582
+ flex-wrap: wrap;
583
+ }
584
+
585
+ /* 栅格单元跨格(span 不要超过所在行的 columns,超了 auto-fit 会为它多开轨道) */
586
+ .ak-column--span-2 {
587
+ grid-column: span 2;
588
+ }
589
+
590
+ .ak-column--span-3 {
591
+ grid-column: span 3;
592
+ }
593
+
594
+ .ak-column--span-4 {
595
+ grid-column: span 4;
596
+ }
597
+
598
+ /* 间距档 → 令牌(落到变量上:行那份栅格公式里要用同一个间距值算轨道下限)。
599
+ sm/md/lg/xl = --ui-space-1/2/3/4 = 4/8/12/16;none = 0 */
600
+ .ak-row--gap-none {
601
+ --ak-row-gap: 0;
602
+ }
603
+
604
+ .ak-row--gap-sm {
605
+ --ak-row-gap: var(--ui-space-1);
606
+ }
607
+
608
+ .ak-row--gap-md {
609
+ --ak-row-gap: var(--ui-space-2);
610
+ }
611
+
612
+ .ak-row--gap-lg {
613
+ --ak-row-gap: var(--ui-space-3);
614
+ }
615
+
616
+ .ak-row--gap-xl {
617
+ --ak-row-gap: var(--ui-space-4);
618
+ }
619
+
620
+ .ak-column--gap-none {
621
+ --ak-column-gap: 0;
622
+ }
623
+
624
+ .ak-column--gap-sm {
625
+ --ak-column-gap: var(--ui-space-1);
626
+ }
627
+
628
+ .ak-column--gap-md {
629
+ --ak-column-gap: var(--ui-space-2);
630
+ }
631
+
632
+ .ak-column--gap-lg {
633
+ --ak-column-gap: var(--ui-space-3);
634
+ }
635
+
636
+ .ak-column--gap-xl {
637
+ --ak-column-gap: var(--ui-space-4);
638
+ }
639
+
640
+ /* 对齐(排在 .ak-row--grid 之后:显式 align 要能压过栅格形态的 stretch 默认) */
641
+ .ak-row--align-start,
642
+ .ak-column--align-start {
643
+ align-items: flex-start;
644
+ }
645
+
646
+ .ak-row--align-center,
647
+ .ak-column--align-center {
648
+ align-items: center;
649
+ }
650
+
651
+ .ak-row--align-end,
652
+ .ak-column--align-end {
653
+ align-items: flex-end;
654
+ }
655
+
656
+ .ak-row--align-baseline,
657
+ .ak-column--align-baseline {
658
+ align-items: baseline;
659
+ }
660
+
661
+ .ak-row--align-stretch,
662
+ .ak-column--align-stretch {
663
+ align-items: stretch;
664
+ }
665
+
666
+ .ak-row--justify-center,
667
+ .ak-column--justify-center {
668
+ justify-content: center;
669
+ }
670
+
671
+ .ak-row--justify-end,
672
+ .ak-column--justify-end {
673
+ justify-content: flex-end;
674
+ }
675
+
676
+ .ak-row--justify-between,
677
+ .ak-column--justify-between {
678
+ justify-content: space-between;
679
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * 三态插画(`AppQueryState` 内建):空态与错误态共用一套「箱体」几何 —— 同族图形让两个状态
3
+ * 在页面里读起来是「同一件事的两种情况」,而不是两种互不相干的贴图。
4
+ * 差异只有两处:徽标语义(空 → 主色「+」;错误 → 危险色「!」)与箱内线条(实线 / 断线)。
5
+ *
6
+ * ## 为什么内建 SVG,而不是引一张插画位图
7
+ *
8
+ * 1. **交付形态**:app-kit 以源码交付(`exports` 指向 `./src/index.ts`),若用 `?inline` / `?raw`
9
+ * 取图,每个消费方都要在 tsconfig 里补 `*.svg?inline` 的模块声明;非 Vite 宿主直接失效。
10
+ * 2. **跟随主题**:配色必须是令牌(`--ui-*`),换主题/深色域自动跟随;位图做不到。
11
+ * 3. **体积**:两态合计不到 1KB 标记。若内联外部插画(参考量级 150KB → data URI 约 200KB),
12
+ * 会被复制进每个接入应用的产物。
13
+ *
14
+ * 需要换成应用自己的插画(如控制台那套大图)时,走 `AppQueryState` 的 `illustration` 插槽或
15
+ * `illustration` 属性,不必改本件。**几何(`d`)在 TSX、配色只在 CSS**(`atoms.css` 的 `.ak-ill-*`):
16
+ * 这样换皮只动样式,不动结构。
17
+ */
18
+ /** 空态插画:空箱 + 主色「+」徽标(暗示「这里可以新建」) */
19
+ export declare const AppStateIllustrationEmpty: import("vue").DefineComponent<{}, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
20
+ /** 错误态插画:同款箱体 + 危险色「!」徽标,箱内线条改虚线(中断语义) */
21
+ export declare const AppStateIllustrationError: import("vue").DefineComponent<{}, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;