@dsh-plugin/dsh-ui-components 0.0.1 → 0.1.0-dev.43616582648

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 (65) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +21 -21
  3. package/README.md +136 -136
  4. package/README.zh_CN.md +136 -136
  5. package/docs/tokens.md +67 -67
  6. package/lib/basic/form.js +49 -49
  7. package/lib/basic/styles.js +391 -391
  8. package/lib/composites/styles.js +427 -427
  9. package/lib/data/styles.js +257 -257
  10. package/lib/display/styles.js +310 -310
  11. package/lib/feedback/styles.js +228 -228
  12. package/lib/foundation/bridge.js +203 -203
  13. package/lib/navigation/styles.js +417 -417
  14. package/package.json +104 -104
  15. package/scripts/check-size.mjs +69 -69
  16. package/scripts/dump-npm-latest.mjs +59 -59
  17. package/scripts/gen-host-tokens.mjs +61 -61
  18. package/scripts/gen-icons.mjs +188 -178
  19. package/scripts/verify-no-literal-colors.mjs +63 -63
  20. package/scripts/verify-tokens.mjs +135 -135
  21. package/src/basic/button.tsx +76 -76
  22. package/src/basic/form.tsx +187 -187
  23. package/src/basic/icon-button.tsx +66 -66
  24. package/src/basic/index.ts +38 -38
  25. package/src/basic/input.tsx +140 -140
  26. package/src/basic/select.tsx +120 -120
  27. package/src/basic/styles.ts +412 -412
  28. package/src/basic/toggle.tsx +116 -116
  29. package/src/composites/data-view.tsx +189 -189
  30. package/src/composites/index.ts +11 -11
  31. package/src/composites/indicator.tsx +90 -90
  32. package/src/composites/menu-select.tsx +230 -230
  33. package/src/composites/panel.tsx +72 -72
  34. package/src/composites/settings.tsx +80 -80
  35. package/src/composites/styles.ts +450 -450
  36. package/src/data/collection.tsx +71 -71
  37. package/src/data/index.ts +39 -39
  38. package/src/data/info.tsx +89 -89
  39. package/src/data/picker.tsx +113 -113
  40. package/src/data/styles.ts +278 -278
  41. package/src/display/container.tsx +67 -67
  42. package/src/display/feedback.tsx +92 -92
  43. package/src/display/index.ts +44 -44
  44. package/src/display/label.tsx +165 -165
  45. package/src/display/overlay.tsx +103 -103
  46. package/src/display/styles.ts +332 -332
  47. package/src/feedback/global.tsx +110 -110
  48. package/src/feedback/index.ts +19 -19
  49. package/src/feedback/inline.tsx +50 -50
  50. package/src/feedback/panel.tsx +93 -93
  51. package/src/feedback/styles.ts +250 -250
  52. package/src/foundation/bridge.ts +318 -318
  53. package/src/foundation/icons.tsx +315 -315
  54. package/src/foundation/index.ts +33 -33
  55. package/src/foundation/palette.ts +153 -153
  56. package/src/foundation/provider.tsx +62 -62
  57. package/src/foundation/style.ts +63 -63
  58. package/src/foundation/tokens.ts +62 -62
  59. package/src/index.ts +18 -18
  60. package/src/navigation/hierarchy.tsx +82 -82
  61. package/src/navigation/index.ts +21 -21
  62. package/src/navigation/indicator.tsx +125 -125
  63. package/src/navigation/menu.tsx +94 -94
  64. package/src/navigation/segmented.tsx +136 -136
  65. package/src/navigation/styles.ts +438 -438
@@ -1,318 +1,318 @@
1
- /**
2
- * Arco 变量到 DSH 令牌的桥接样式表。
3
- *
4
- * Arco 的外观有两层取值:`body` 上的原始色阶(`--primary-6` 这类 `R,G,B`
5
- * 三元组)与语义变量(`--color-text-1` 这类颜色字符串),组件规则同时直接
6
- * 引用这两层。自定义属性在声明它的元素上完成替换后才会向下继承,因此在
7
- * 后代元素上改 `--arcoblue-6` 不会影响已从 `body` 继承到的 `--primary-6`。
8
- * 桥接表因此在 `.dsh-ui` 容器上同时重绑两层,而不是只改一层。
9
- *
10
- * 语义层指向 `--dsw-alias-*` 令牌,随宿主深浅主题自动切换,无需在本文件
11
- * 另写深色分支;原始色阶需要三元组,深浅主题各写一份。
12
- *
13
- * 本文件是本包唯一允许出现字面色值的样式文件(色阶三元组与圆角像素),
14
- * `scripts/verify-no-literal-colors.mjs` 对本文件放行。
15
- *
16
- * @module @dsh-plugin/dsh-ui-components/foundation/bridge
17
- */
18
- import { BLACK, STATIC, WHITE, declareRamp, mixTriple, ramp, type Triple } from './palette.js'
19
-
20
- /** 把一组静态色值按顺序取成一个色阶。 */
21
- function pick(steps: readonly Triple[]): Triple[] {
22
- return [...steps]
23
- }
24
-
25
- /**
26
- * 以第 6 级为基准展开深色主题的十级色阶。
27
- *
28
- * Arco 的深色色板把色阶顺序反转:`-1` 最深、`-10` 最浅。直接反转浅色色阶
29
- * 即可得到同样的走向,`-6` 仍是基准色。
30
- *
31
- * @param base - 第 6 级取值。
32
- * @returns 长度为 10 的反转色阶。
33
- */
34
- function rampDark(base: Triple): Triple[] {
35
- return [...ramp(base)].reverse()
36
- }
37
-
38
- /** `b` 分组:Arco 原始色阶,浅色主题。 */
39
- const RAMP_LIGHT: ReadonlyArray<readonly [string, Triple[]]> = [
40
- // DSH 的主色是中性近黑色(亮色)与近白色(暗色),蓝色只用于强调与链接。
41
- ['primary', ramp(STATIC.bluish[1000])],
42
- ['gray', pick([STATIC.bluish[50], STATIC.bluish[60], STATIC.bluish[100], STATIC.bluish[150], STATIC.bluish[200], STATIC.bluish[300], STATIC.bluish[400], STATIC.bluish[500], STATIC.bluish[600], STATIC.bluish[1000]])],
43
- ['arcoblue', ramp(STATIC.deepseek[500])],
44
- ['blue', ramp(STATIC.blue[500])],
45
- ['green', ramp(STATIC.green[500])],
46
- ['red', ramp(STATIC.red[600])],
47
- ['orange', ramp(STATIC.amber[500])],
48
- ['orangered', ramp(STATIC.amber[600])],
49
- ['gold', ramp(STATIC.amber[400])],
50
- ['success', ramp(STATIC.green[500])],
51
- ['warning', ramp(STATIC.amber[500])],
52
- ['danger', ramp(STATIC.red[600])],
53
- ['link', ramp(STATIC.deepseek[500])],
54
- ]
55
-
56
- /** Arco 原始色阶,深色主题。 */
57
- const RAMP_DARK: ReadonlyArray<readonly [string, Triple[]]> = [
58
- ['primary', rampDark(STATIC.bluish[50])],
59
- ['gray', pick([STATIC.bluish[900], STATIC.bluish[875], STATIC.bluish[850], STATIC.bluish[800], STATIC.bluish[750], STATIC.bluish[700], STATIC.bluish[600], STATIC.bluish[500], STATIC.bluish[400], STATIC.bluish[200]])],
60
- ['arcoblue', rampDark(STATIC.deepseek[400])],
61
- ['blue', rampDark(STATIC.blue[400])],
62
- ['green', rampDark(STATIC.green[400])],
63
- ['red', rampDark(STATIC.red[400])],
64
- ['orange', rampDark(STATIC.amber[400])],
65
- ['orangered', rampDark(STATIC.amber[500])],
66
- ['gold', rampDark(STATIC.amber[400])],
67
- ['success', rampDark(STATIC.green[400])],
68
- ['warning', rampDark(STATIC.amber[400])],
69
- ['danger', rampDark(STATIC.red[400])],
70
- ['link', rampDark(STATIC.deepseek[400])],
71
- ]
72
-
73
- /** 把色阶组序列化为一份声明块。 */
74
- function rampsDeclarations(ramps: ReadonlyArray<readonly [string, Triple[]]>): string {
75
- return ramps.map(([prefix, steps]) => declareRamp(prefix, steps)).join('\n')
76
- }
77
-
78
- /**
79
- * 语义变量桥接。
80
- *
81
- * 每条都指向 DSH 的语义令牌而不是具体色值,因此深浅主题切换由宿主的
82
- * `body[data-ds-dark-theme]` 驱动,本包不维护主题分支。
83
- */
84
- const SEMANTIC = `
85
- /* 文字层级 */
86
- --color-text-1: var(--dsw-alias-label-primary, rgba(0, 0, 0, 0.9));
87
- --color-text-2: var(--dsw-alias-label-secondary, rgba(0, 0, 0, 0.7));
88
- --color-text-3: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, 0.55));
89
- --color-text-4: var(--dsw-alias-label-caption, rgba(0, 0, 0, 0.35));
90
- --color-text-white: var(--dsw-alias-label-primary-foreground, #fff);
91
-
92
- /* 中性色:组件规则直接引用 --color-neutral-*,此处重绑指向文字与分割层级,
93
- 避免再走一层原始色阶。 */
94
- --color-neutral-1: var(--dsw-alias-bg-layer-1);
95
- --color-neutral-2: var(--dsw-alias-bg-layer-2);
96
- --color-neutral-3: var(--dsw-alias-border-l2);
97
- --color-neutral-4: var(--dsw-alias-border-l3);
98
- --color-neutral-5: var(--dsw-alias-label-caption);
99
- --color-neutral-6: var(--dsw-alias-label-tertiary);
100
- --color-neutral-7: var(--dsw-alias-label-secondary);
101
- --color-neutral-8: var(--dsw-alias-label-secondary);
102
- --color-neutral-9: var(--dsw-alias-label-primary);
103
- --color-neutral-10: var(--dsw-alias-label-primary);
104
-
105
- /* 背景层级 */
106
- --color-bg-1: var(--dsw-alias-bg-base);
107
- --color-bg-2: var(--dsw-alias-bg-layer-1);
108
- --color-bg-3: var(--dsw-alias-bg-layer-2);
109
- --color-bg-4: var(--dsw-alias-bg-layer-3);
110
- --color-bg-5: var(--dsw-alias-bg-layer-3);
111
- --color-bg-white: var(--dsw-alias-bg-layer-1);
112
- --color-bg-popup: var(--dsw-alias-bg-layer-2);
113
- --color-white: var(--dsw-alias-label-primary-foreground);
114
- --color-black: var(--dsw-alias-label-primary);
115
-
116
- /* 边框与填充 */
117
- --color-border: var(--dsw-alias-border-l2);
118
- --color-border-1: var(--dsw-alias-border-l1);
119
- --color-border-2: var(--dsw-alias-border-l2);
120
- --color-border-3: var(--dsw-alias-border-l3);
121
- --color-border-4: var(--dsw-alias-border-l4);
122
- --color-fill-1: var(--dsw-alias-bg-layer-1);
123
- --color-fill-2: var(--dsw-alias-interactive-bg-hover);
124
- --color-fill-3: var(--dsw-alias-interactive-bg-hover-solid);
125
- --color-fill-4: var(--dsw-alias-interactive-bg-active);
126
- --color-secondary: var(--dsw-alias-interactive-bg-hover);
127
- --color-secondary-hover: var(--dsw-alias-interactive-bg-hover-solid);
128
- --color-secondary-active: var(--dsw-alias-interactive-bg-active);
129
- --color-secondary-disabled: var(--dsw-alias-bg-layer-1);
130
-
131
- /* 状态浅色填充,用于禁用态与提示背景 */
132
- --color-primary-light-1: color-mix(in srgb, var(--dsw-alias-state-business-primary) 8%, transparent);
133
- --color-primary-light-2: color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, transparent);
134
- --color-primary-light-3: color-mix(in srgb, var(--dsw-alias-state-business-primary) 22%, transparent);
135
- --color-primary-light-4: color-mix(in srgb, var(--dsw-alias-state-business-primary) 32%, transparent);
136
- --color-success-light-1: color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent);
137
- --color-success-light-2: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);
138
- --color-success-light-3: color-mix(in srgb, var(--dsw-alias-state-success-primary) 22%, transparent);
139
- --color-success-light-4: color-mix(in srgb, var(--dsw-alias-state-success-primary) 32%, transparent);
140
- --color-warning-light-1: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);
141
- --color-warning-light-2: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);
142
- --color-warning-light-3: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 22%, transparent);
143
- --color-warning-light-4: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 32%, transparent);
144
- --color-danger-light-1: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);
145
- --color-danger-light-2: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);
146
- --color-danger-light-3: color-mix(in srgb, var(--dsw-alias-state-error-primary) 22%, transparent);
147
- --color-danger-light-4: color-mix(in srgb, var(--dsw-alias-state-error-primary) 32%, transparent);
148
- --color-link-light-1: color-mix(in srgb, var(--dsw-alias-link) 8%, transparent);
149
- --color-link-light-2: color-mix(in srgb, var(--dsw-alias-link) 14%, transparent);
150
- --color-link-light-3: color-mix(in srgb, var(--dsw-alias-link) 22%, transparent);
151
- --color-link-light-4: color-mix(in srgb, var(--dsw-alias-link) 32%, transparent);
152
-
153
- /* 浮层表面与遮罩 */
154
- --color-menu-light-bg: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-2));
155
- --color-menu-dark-bg: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-2));
156
- --color-menu-dark-hover: var(--dsw-alias-interactive-bg-hover);
157
- --color-tooltip-bg: var(--dsw-alias-tooltip-bg);
158
- --color-tooltip-text: var(--dsw-alias-tooltip-label);
159
- --color-mask-bg: var(--dsw-alias-bg-mask-1);
160
- --color-spin-layer-bg: var(--dsw-alias-bg-mask-2);
161
-
162
- /* 圆角:按 DSH 圆角标准重绑。small 对应 28px 高的紧凑控件,medium 对应
163
- 32–40px 的标准控件,large 对应分组内容。 */
164
- --border-radius-none: 0;
165
- --border-radius-small: var(--dsw-radius-sm, 8px);
166
- --border-radius-medium: var(--dsw-radius-md, 12px);
167
- --border-radius-large: var(--dsw-radius-lg, 16px);
168
- --border-radius-circle: 50%;
169
- `
170
-
171
- /**
172
- * 针对 DSH 具体控件契约的规则级覆盖。
173
- *
174
- * 变量桥接能覆盖绝大多数外观,但按钮填充在 DSH 里另有专门令牌(主按钮是
175
- * 中性近黑色,而非品牌蓝),且 Arco 在规则里写死了白字与蓝色焦点环,这两处
176
- * 需要直接改规则。
177
- */
178
- const RULES = `
179
- .dsh-ui .arco-btn {
180
- font-family: inherit;
181
- border-radius: var(--dsw-radius-md, 12px);
182
- transition: background-color 120ms ease, color 120ms ease, opacity 120ms ease;
183
- }
184
-
185
- .dsh-ui .arco-btn-size-mini,
186
- .dsh-ui .arco-btn-size-small {
187
- border-radius: var(--dsw-radius-sm, 8px);
188
- }
189
-
190
- .dsh-ui .arco-btn-primary:not(.arco-btn-disabled) {
191
- background-color: var(--dsw-alias-button-primary-fill);
192
- color: var(--dsw-alias-label-primary-foreground);
193
- }
194
-
195
- /* Arco 的 hover 规则把文字硬编码成白色;DSH 的主色在深色主题下是浅色填充,
196
- 白字会失去对比,因此背景与文字必须成对覆盖。 */
197
- .dsh-ui .arco-btn-primary:not(.arco-btn-disabled):not(.arco-btn-loading):hover,
198
- .dsh-ui .arco-btn-primary:not(.arco-btn-disabled):not(.arco-btn-loading):active {
199
- background-color: var(--dsw-alias-button-primary-hover);
200
- color: var(--dsw-alias-label-primary-foreground);
201
- }
202
-
203
- .dsh-ui .arco-btn-primary:not(.arco-btn-disabled):not(.arco-btn-loading):active {
204
- background-color: var(--dsw-alias-button-primary-hover);
205
- }
206
-
207
- .dsh-ui .arco-btn-primary.arco-btn-disabled {
208
- background-color: var(--dsw-alias-button-primary-dimmed);
209
- color: var(--dsw-alias-label-tertiary);
210
- }
211
-
212
- .dsh-ui .arco-btn-secondary:not(.arco-btn-disabled) {
213
- background-color: var(--dsw-alias-interactive-bg-hover);
214
- color: var(--dsw-alias-label-primary);
215
- }
216
-
217
- .dsh-ui .arco-btn-secondary:not(.arco-btn-disabled):hover {
218
- background-color: var(--dsw-alias-interactive-bg-hover-solid);
219
- }
220
-
221
- .dsh-ui .arco-btn-text:not(.arco-btn-disabled) {
222
- color: var(--dsw-alias-label-secondary);
223
- }
224
-
225
- .dsh-ui .arco-btn-text:not(.arco-btn-disabled):hover {
226
- background-color: var(--dsw-alias-interactive-bg-hover);
227
- color: var(--dsw-alias-label-primary);
228
- }
229
-
230
- .dsh-ui .arco-btn-status-danger:not(.arco-btn-disabled) {
231
- color: var(--dsw-alias-state-error-primary);
232
- }
233
-
234
- /* 危险操作的主按钮在 DSH 里是淡红色填充配错误色文字,而不是整块高饱和红底:
235
- 后者在深色主题下会变成一块亮粉色,与宿主的删除确认弹窗不一致。 */
236
- .dsh-ui .arco-btn-primary.arco-btn-status-danger:not(.arco-btn-disabled) {
237
- background-color: var(--dsw-alias-interactive-bg-hover-danger);
238
- color: var(--dsw-alias-state-error-primary);
239
- }
240
-
241
- .dsh-ui .arco-btn-primary.arco-btn-status-danger:not(.arco-btn-disabled):not(.arco-btn-loading):hover,
242
- .dsh-ui .arco-btn-primary.arco-btn-status-danger:not(.arco-btn-disabled):not(.arco-btn-loading):active {
243
- background-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 16%, transparent);
244
- color: var(--dsw-alias-state-error-primary);
245
- }
246
-
247
- .dsh-ui :focus-visible {
248
- outline-color: var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
249
- outline-width: var(--dsw-focus-ring-width);
250
- }
251
-
252
- /* 输入类控件的聚焦用描边表达,与宿主 Input 的边框变色一致;不叠加外扩焦点
253
- 环,否则边框外会多出一圈比控件本身更大的蓝框。这里必须显式写 outline-style
254
- 与 outline-width,单写 outline: none 会被上面的 :focus-visible 规则盖掉。 */
255
- .dsh-ui .arco-input:focus-visible,
256
- .dsh-ui .arco-textarea:focus-visible,
257
- .dsh-ui .arco-input-inner-wrapper:focus-within,
258
- .dsh-ui .arco-input-number:focus-within,
259
- .dsh-ui .arco-select-view:focus-visible,
260
- .dsh-ui .arco-select-view:focus-within {
261
- box-shadow: none;
262
- outline-style: none;
263
- outline-width: 0;
264
- border-color: var(--dsw-alias-state-business-primary);
265
- }
266
-
267
- .dsh-ui .arco-btn:focus-visible {
268
- box-shadow: none;
269
- outline: var(--dsw-focus-ring-width) solid var(--dsw-alias-state-business-primary);
270
- outline-offset: 2px;
271
- }
272
-
273
- /* 浮层表面统一承载菜单材质,避免逐组件重复声明。 */
274
- .dsh-ui-overlay .arco-dropdown-menu,
275
- .dsh-ui-overlay .arco-select-popup,
276
- .dsh-ui-overlay .arco-trigger-popup .arco-dropdown,
277
- .dsh-ui-overlay .arco-picker-container {
278
- background: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-2));
279
- backdrop-filter: var(--dsw-menu-backdrop-filter, none);
280
- border: 0;
281
- box-shadow: var(--dsw-elevation-panel);
282
- }
283
- `
284
-
285
- /**
286
- * 完整桥接样式表。
287
- *
288
- * 容器类 `.dsh-ui` 由 {@link DshProvider} 加在包裹元素上,浮层容器同时带
289
- * `.dsh-ui-overlay`,因此弹出层即使挂在 `body` 下也能拿到同一套变量。
290
- */
291
- export const BRIDGE_CSS = `
292
- .${'dsh-ui'},
293
- .dsh-ui-overlay {
294
- ${SEMANTIC}
295
- ${rampsDeclarations(RAMP_LIGHT)}
296
- }
297
-
298
- body[data-ds-dark-theme] .dsh-ui,
299
- body[data-ds-dark-theme] .dsh-ui-overlay {
300
- ${rampsDeclarations(RAMP_DARK)}
301
- }
302
-
303
- ${RULES}
304
- `
305
-
306
- /**
307
- * 供测试与门禁使用的深色基准色,避免在样式字符串之外再次写字面量。
308
- *
309
- * 导出它们只为让 `scripts/verify-tokens.mjs` 能核对桥接使用的 DSH 令牌名,
310
- * 组件代码不应直接引用。
311
- */
312
- export const BRIDGE_PALETTE = {
313
- lightPrimaryBase: STATIC.bluish[1000],
314
- darkPrimaryBase: STATIC.bluish[50],
315
- white: WHITE,
316
- black: BLACK,
317
- mix: mixTriple,
318
- } as const
1
+ /**
2
+ * Arco 变量到 DSH 令牌的桥接样式表。
3
+ *
4
+ * Arco 的外观有两层取值:`body` 上的原始色阶(`--primary-6` 这类 `R,G,B`
5
+ * 三元组)与语义变量(`--color-text-1` 这类颜色字符串),组件规则同时直接
6
+ * 引用这两层。自定义属性在声明它的元素上完成替换后才会向下继承,因此在
7
+ * 后代元素上改 `--arcoblue-6` 不会影响已从 `body` 继承到的 `--primary-6`。
8
+ * 桥接表因此在 `.dsh-ui` 容器上同时重绑两层,而不是只改一层。
9
+ *
10
+ * 语义层指向 `--dsw-alias-*` 令牌,随宿主深浅主题自动切换,无需在本文件
11
+ * 另写深色分支;原始色阶需要三元组,深浅主题各写一份。
12
+ *
13
+ * 本文件是本包唯一允许出现字面色值的样式文件(色阶三元组与圆角像素),
14
+ * `scripts/verify-no-literal-colors.mjs` 对本文件放行。
15
+ *
16
+ * @module @dsh-plugin/dsh-ui-components/foundation/bridge
17
+ */
18
+ import { BLACK, STATIC, WHITE, declareRamp, mixTriple, ramp, type Triple } from './palette.js'
19
+
20
+ /** 把一组静态色值按顺序取成一个色阶。 */
21
+ function pick(steps: readonly Triple[]): Triple[] {
22
+ return [...steps]
23
+ }
24
+
25
+ /**
26
+ * 以第 6 级为基准展开深色主题的十级色阶。
27
+ *
28
+ * Arco 的深色色板把色阶顺序反转:`-1` 最深、`-10` 最浅。直接反转浅色色阶
29
+ * 即可得到同样的走向,`-6` 仍是基准色。
30
+ *
31
+ * @param base - 第 6 级取值。
32
+ * @returns 长度为 10 的反转色阶。
33
+ */
34
+ function rampDark(base: Triple): Triple[] {
35
+ return [...ramp(base)].reverse()
36
+ }
37
+
38
+ /** `b` 分组:Arco 原始色阶,浅色主题。 */
39
+ const RAMP_LIGHT: ReadonlyArray<readonly [string, Triple[]]> = [
40
+ // DSH 的主色是中性近黑色(亮色)与近白色(暗色),蓝色只用于强调与链接。
41
+ ['primary', ramp(STATIC.bluish[1000])],
42
+ ['gray', pick([STATIC.bluish[50], STATIC.bluish[60], STATIC.bluish[100], STATIC.bluish[150], STATIC.bluish[200], STATIC.bluish[300], STATIC.bluish[400], STATIC.bluish[500], STATIC.bluish[600], STATIC.bluish[1000]])],
43
+ ['arcoblue', ramp(STATIC.deepseek[500])],
44
+ ['blue', ramp(STATIC.blue[500])],
45
+ ['green', ramp(STATIC.green[500])],
46
+ ['red', ramp(STATIC.red[600])],
47
+ ['orange', ramp(STATIC.amber[500])],
48
+ ['orangered', ramp(STATIC.amber[600])],
49
+ ['gold', ramp(STATIC.amber[400])],
50
+ ['success', ramp(STATIC.green[500])],
51
+ ['warning', ramp(STATIC.amber[500])],
52
+ ['danger', ramp(STATIC.red[600])],
53
+ ['link', ramp(STATIC.deepseek[500])],
54
+ ]
55
+
56
+ /** Arco 原始色阶,深色主题。 */
57
+ const RAMP_DARK: ReadonlyArray<readonly [string, Triple[]]> = [
58
+ ['primary', rampDark(STATIC.bluish[50])],
59
+ ['gray', pick([STATIC.bluish[900], STATIC.bluish[875], STATIC.bluish[850], STATIC.bluish[800], STATIC.bluish[750], STATIC.bluish[700], STATIC.bluish[600], STATIC.bluish[500], STATIC.bluish[400], STATIC.bluish[200]])],
60
+ ['arcoblue', rampDark(STATIC.deepseek[400])],
61
+ ['blue', rampDark(STATIC.blue[400])],
62
+ ['green', rampDark(STATIC.green[400])],
63
+ ['red', rampDark(STATIC.red[400])],
64
+ ['orange', rampDark(STATIC.amber[400])],
65
+ ['orangered', rampDark(STATIC.amber[500])],
66
+ ['gold', rampDark(STATIC.amber[400])],
67
+ ['success', rampDark(STATIC.green[400])],
68
+ ['warning', rampDark(STATIC.amber[400])],
69
+ ['danger', rampDark(STATIC.red[400])],
70
+ ['link', rampDark(STATIC.deepseek[400])],
71
+ ]
72
+
73
+ /** 把色阶组序列化为一份声明块。 */
74
+ function rampsDeclarations(ramps: ReadonlyArray<readonly [string, Triple[]]>): string {
75
+ return ramps.map(([prefix, steps]) => declareRamp(prefix, steps)).join('\n')
76
+ }
77
+
78
+ /**
79
+ * 语义变量桥接。
80
+ *
81
+ * 每条都指向 DSH 的语义令牌而不是具体色值,因此深浅主题切换由宿主的
82
+ * `body[data-ds-dark-theme]` 驱动,本包不维护主题分支。
83
+ */
84
+ const SEMANTIC = `
85
+ /* 文字层级 */
86
+ --color-text-1: var(--dsw-alias-label-primary, rgba(0, 0, 0, 0.9));
87
+ --color-text-2: var(--dsw-alias-label-secondary, rgba(0, 0, 0, 0.7));
88
+ --color-text-3: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, 0.55));
89
+ --color-text-4: var(--dsw-alias-label-caption, rgba(0, 0, 0, 0.35));
90
+ --color-text-white: var(--dsw-alias-label-primary-foreground, #fff);
91
+
92
+ /* 中性色:组件规则直接引用 --color-neutral-*,此处重绑指向文字与分割层级,
93
+ 避免再走一层原始色阶。 */
94
+ --color-neutral-1: var(--dsw-alias-bg-layer-1);
95
+ --color-neutral-2: var(--dsw-alias-bg-layer-2);
96
+ --color-neutral-3: var(--dsw-alias-border-l2);
97
+ --color-neutral-4: var(--dsw-alias-border-l3);
98
+ --color-neutral-5: var(--dsw-alias-label-caption);
99
+ --color-neutral-6: var(--dsw-alias-label-tertiary);
100
+ --color-neutral-7: var(--dsw-alias-label-secondary);
101
+ --color-neutral-8: var(--dsw-alias-label-secondary);
102
+ --color-neutral-9: var(--dsw-alias-label-primary);
103
+ --color-neutral-10: var(--dsw-alias-label-primary);
104
+
105
+ /* 背景层级 */
106
+ --color-bg-1: var(--dsw-alias-bg-base);
107
+ --color-bg-2: var(--dsw-alias-bg-layer-1);
108
+ --color-bg-3: var(--dsw-alias-bg-layer-2);
109
+ --color-bg-4: var(--dsw-alias-bg-layer-3);
110
+ --color-bg-5: var(--dsw-alias-bg-layer-3);
111
+ --color-bg-white: var(--dsw-alias-bg-layer-1);
112
+ --color-bg-popup: var(--dsw-alias-bg-layer-2);
113
+ --color-white: var(--dsw-alias-label-primary-foreground);
114
+ --color-black: var(--dsw-alias-label-primary);
115
+
116
+ /* 边框与填充 */
117
+ --color-border: var(--dsw-alias-border-l2);
118
+ --color-border-1: var(--dsw-alias-border-l1);
119
+ --color-border-2: var(--dsw-alias-border-l2);
120
+ --color-border-3: var(--dsw-alias-border-l3);
121
+ --color-border-4: var(--dsw-alias-border-l4);
122
+ --color-fill-1: var(--dsw-alias-bg-layer-1);
123
+ --color-fill-2: var(--dsw-alias-interactive-bg-hover);
124
+ --color-fill-3: var(--dsw-alias-interactive-bg-hover-solid);
125
+ --color-fill-4: var(--dsw-alias-interactive-bg-active);
126
+ --color-secondary: var(--dsw-alias-interactive-bg-hover);
127
+ --color-secondary-hover: var(--dsw-alias-interactive-bg-hover-solid);
128
+ --color-secondary-active: var(--dsw-alias-interactive-bg-active);
129
+ --color-secondary-disabled: var(--dsw-alias-bg-layer-1);
130
+
131
+ /* 状态浅色填充,用于禁用态与提示背景 */
132
+ --color-primary-light-1: color-mix(in srgb, var(--dsw-alias-state-business-primary) 8%, transparent);
133
+ --color-primary-light-2: color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, transparent);
134
+ --color-primary-light-3: color-mix(in srgb, var(--dsw-alias-state-business-primary) 22%, transparent);
135
+ --color-primary-light-4: color-mix(in srgb, var(--dsw-alias-state-business-primary) 32%, transparent);
136
+ --color-success-light-1: color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent);
137
+ --color-success-light-2: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);
138
+ --color-success-light-3: color-mix(in srgb, var(--dsw-alias-state-success-primary) 22%, transparent);
139
+ --color-success-light-4: color-mix(in srgb, var(--dsw-alias-state-success-primary) 32%, transparent);
140
+ --color-warning-light-1: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);
141
+ --color-warning-light-2: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);
142
+ --color-warning-light-3: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 22%, transparent);
143
+ --color-warning-light-4: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 32%, transparent);
144
+ --color-danger-light-1: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);
145
+ --color-danger-light-2: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);
146
+ --color-danger-light-3: color-mix(in srgb, var(--dsw-alias-state-error-primary) 22%, transparent);
147
+ --color-danger-light-4: color-mix(in srgb, var(--dsw-alias-state-error-primary) 32%, transparent);
148
+ --color-link-light-1: color-mix(in srgb, var(--dsw-alias-link) 8%, transparent);
149
+ --color-link-light-2: color-mix(in srgb, var(--dsw-alias-link) 14%, transparent);
150
+ --color-link-light-3: color-mix(in srgb, var(--dsw-alias-link) 22%, transparent);
151
+ --color-link-light-4: color-mix(in srgb, var(--dsw-alias-link) 32%, transparent);
152
+
153
+ /* 浮层表面与遮罩 */
154
+ --color-menu-light-bg: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-2));
155
+ --color-menu-dark-bg: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-2));
156
+ --color-menu-dark-hover: var(--dsw-alias-interactive-bg-hover);
157
+ --color-tooltip-bg: var(--dsw-alias-tooltip-bg);
158
+ --color-tooltip-text: var(--dsw-alias-tooltip-label);
159
+ --color-mask-bg: var(--dsw-alias-bg-mask-1);
160
+ --color-spin-layer-bg: var(--dsw-alias-bg-mask-2);
161
+
162
+ /* 圆角:按 DSH 圆角标准重绑。small 对应 28px 高的紧凑控件,medium 对应
163
+ 32–40px 的标准控件,large 对应分组内容。 */
164
+ --border-radius-none: 0;
165
+ --border-radius-small: var(--dsw-radius-sm, 8px);
166
+ --border-radius-medium: var(--dsw-radius-md, 12px);
167
+ --border-radius-large: var(--dsw-radius-lg, 16px);
168
+ --border-radius-circle: 50%;
169
+ `
170
+
171
+ /**
172
+ * 针对 DSH 具体控件契约的规则级覆盖。
173
+ *
174
+ * 变量桥接能覆盖绝大多数外观,但按钮填充在 DSH 里另有专门令牌(主按钮是
175
+ * 中性近黑色,而非品牌蓝),且 Arco 在规则里写死了白字与蓝色焦点环,这两处
176
+ * 需要直接改规则。
177
+ */
178
+ const RULES = `
179
+ .dsh-ui .arco-btn {
180
+ font-family: inherit;
181
+ border-radius: var(--dsw-radius-md, 12px);
182
+ transition: background-color 120ms ease, color 120ms ease, opacity 120ms ease;
183
+ }
184
+
185
+ .dsh-ui .arco-btn-size-mini,
186
+ .dsh-ui .arco-btn-size-small {
187
+ border-radius: var(--dsw-radius-sm, 8px);
188
+ }
189
+
190
+ .dsh-ui .arco-btn-primary:not(.arco-btn-disabled) {
191
+ background-color: var(--dsw-alias-button-primary-fill);
192
+ color: var(--dsw-alias-label-primary-foreground);
193
+ }
194
+
195
+ /* Arco 的 hover 规则把文字硬编码成白色;DSH 的主色在深色主题下是浅色填充,
196
+ 白字会失去对比,因此背景与文字必须成对覆盖。 */
197
+ .dsh-ui .arco-btn-primary:not(.arco-btn-disabled):not(.arco-btn-loading):hover,
198
+ .dsh-ui .arco-btn-primary:not(.arco-btn-disabled):not(.arco-btn-loading):active {
199
+ background-color: var(--dsw-alias-button-primary-hover);
200
+ color: var(--dsw-alias-label-primary-foreground);
201
+ }
202
+
203
+ .dsh-ui .arco-btn-primary:not(.arco-btn-disabled):not(.arco-btn-loading):active {
204
+ background-color: var(--dsw-alias-button-primary-hover);
205
+ }
206
+
207
+ .dsh-ui .arco-btn-primary.arco-btn-disabled {
208
+ background-color: var(--dsw-alias-button-primary-dimmed);
209
+ color: var(--dsw-alias-label-tertiary);
210
+ }
211
+
212
+ .dsh-ui .arco-btn-secondary:not(.arco-btn-disabled) {
213
+ background-color: var(--dsw-alias-interactive-bg-hover);
214
+ color: var(--dsw-alias-label-primary);
215
+ }
216
+
217
+ .dsh-ui .arco-btn-secondary:not(.arco-btn-disabled):hover {
218
+ background-color: var(--dsw-alias-interactive-bg-hover-solid);
219
+ }
220
+
221
+ .dsh-ui .arco-btn-text:not(.arco-btn-disabled) {
222
+ color: var(--dsw-alias-label-secondary);
223
+ }
224
+
225
+ .dsh-ui .arco-btn-text:not(.arco-btn-disabled):hover {
226
+ background-color: var(--dsw-alias-interactive-bg-hover);
227
+ color: var(--dsw-alias-label-primary);
228
+ }
229
+
230
+ .dsh-ui .arco-btn-status-danger:not(.arco-btn-disabled) {
231
+ color: var(--dsw-alias-state-error-primary);
232
+ }
233
+
234
+ /* 危险操作的主按钮在 DSH 里是淡红色填充配错误色文字,而不是整块高饱和红底:
235
+ 后者在深色主题下会变成一块亮粉色,与宿主的删除确认弹窗不一致。 */
236
+ .dsh-ui .arco-btn-primary.arco-btn-status-danger:not(.arco-btn-disabled) {
237
+ background-color: var(--dsw-alias-interactive-bg-hover-danger);
238
+ color: var(--dsw-alias-state-error-primary);
239
+ }
240
+
241
+ .dsh-ui .arco-btn-primary.arco-btn-status-danger:not(.arco-btn-disabled):not(.arco-btn-loading):hover,
242
+ .dsh-ui .arco-btn-primary.arco-btn-status-danger:not(.arco-btn-disabled):not(.arco-btn-loading):active {
243
+ background-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 16%, transparent);
244
+ color: var(--dsw-alias-state-error-primary);
245
+ }
246
+
247
+ .dsh-ui :focus-visible {
248
+ outline-color: var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
249
+ outline-width: var(--dsw-focus-ring-width);
250
+ }
251
+
252
+ /* 输入类控件的聚焦用描边表达,与宿主 Input 的边框变色一致;不叠加外扩焦点
253
+ 环,否则边框外会多出一圈比控件本身更大的蓝框。这里必须显式写 outline-style
254
+ 与 outline-width,单写 outline: none 会被上面的 :focus-visible 规则盖掉。 */
255
+ .dsh-ui .arco-input:focus-visible,
256
+ .dsh-ui .arco-textarea:focus-visible,
257
+ .dsh-ui .arco-input-inner-wrapper:focus-within,
258
+ .dsh-ui .arco-input-number:focus-within,
259
+ .dsh-ui .arco-select-view:focus-visible,
260
+ .dsh-ui .arco-select-view:focus-within {
261
+ box-shadow: none;
262
+ outline-style: none;
263
+ outline-width: 0;
264
+ border-color: var(--dsw-alias-state-business-primary);
265
+ }
266
+
267
+ .dsh-ui .arco-btn:focus-visible {
268
+ box-shadow: none;
269
+ outline: var(--dsw-focus-ring-width) solid var(--dsw-alias-state-business-primary);
270
+ outline-offset: 2px;
271
+ }
272
+
273
+ /* 浮层表面统一承载菜单材质,避免逐组件重复声明。 */
274
+ .dsh-ui-overlay .arco-dropdown-menu,
275
+ .dsh-ui-overlay .arco-select-popup,
276
+ .dsh-ui-overlay .arco-trigger-popup .arco-dropdown,
277
+ .dsh-ui-overlay .arco-picker-container {
278
+ background: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-2));
279
+ backdrop-filter: var(--dsw-menu-backdrop-filter, none);
280
+ border: 0;
281
+ box-shadow: var(--dsw-elevation-panel);
282
+ }
283
+ `
284
+
285
+ /**
286
+ * 完整桥接样式表。
287
+ *
288
+ * 容器类 `.dsh-ui` 由 {@link DshProvider} 加在包裹元素上,浮层容器同时带
289
+ * `.dsh-ui-overlay`,因此弹出层即使挂在 `body` 下也能拿到同一套变量。
290
+ */
291
+ export const BRIDGE_CSS = `
292
+ .${'dsh-ui'},
293
+ .dsh-ui-overlay {
294
+ ${SEMANTIC}
295
+ ${rampsDeclarations(RAMP_LIGHT)}
296
+ }
297
+
298
+ body[data-ds-dark-theme] .dsh-ui,
299
+ body[data-ds-dark-theme] .dsh-ui-overlay {
300
+ ${rampsDeclarations(RAMP_DARK)}
301
+ }
302
+
303
+ ${RULES}
304
+ `
305
+
306
+ /**
307
+ * 供测试与门禁使用的深色基准色,避免在样式字符串之外再次写字面量。
308
+ *
309
+ * 导出它们只为让 `scripts/verify-tokens.mjs` 能核对桥接使用的 DSH 令牌名,
310
+ * 组件代码不应直接引用。
311
+ */
312
+ export const BRIDGE_PALETTE = {
313
+ lightPrimaryBase: STATIC.bluish[1000],
314
+ darkPrimaryBase: STATIC.bluish[50],
315
+ white: WHITE,
316
+ black: BLACK,
317
+ mix: mixTriple,
318
+ } as const