@morlay/dsh-client-ui-primitives 0.0.7 → 0.0.8
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 +29 -5
- package/dist/client.d.mts +186 -11201
- package/dist/client.mjs +981 -1827
- package/package.json +5 -7
- package/src/client/controls/Bubble.module.css +17 -0
- package/src/client/controls/Bubble.tsx +17 -0
- package/src/client/controls/Button.module.css +10 -0
- package/src/client/controls/Button.tsx +29 -0
- package/src/client/controls/DisclosureRow.module.css +22 -0
- package/src/client/controls/DisclosureRow.tsx +20 -0
- package/src/client/controls/IconButton.module.css +50 -0
- package/src/client/controls/IconButton.tsx +45 -0
- package/src/client/controls/ModelRouteList.module.css +100 -0
- package/src/client/controls/ModelRouteList.tsx +118 -0
- package/src/client/controls/MultilineField.module.css +26 -0
- package/src/client/controls/MultilineField.tsx +19 -0
- package/src/client/controls/SearchInput.module.css +11 -0
- package/src/client/controls/SearchInput.tsx +22 -0
- package/src/client/controls/SearchSelect.module.css +34 -0
- package/src/client/controls/SearchSelect.tsx +138 -0
- package/src/client/controls/SeatButton.module.css +53 -0
- package/src/client/controls/SeatButton.tsx +40 -0
- package/src/client/controls/Spinner.module.css +18 -0
- package/src/client/controls/Spinner.tsx +14 -0
- package/src/client/controls/Tabs.module.css +48 -0
- package/src/client/controls/Tabs.tsx +57 -0
- package/src/client/controls/TagInput.module.css +105 -0
- package/src/client/controls/TagInput.tsx +152 -0
- package/src/client/controls/TimeLabel.module.css +16 -0
- package/src/client/controls/TimeLabel.tsx +15 -0
- package/src/client/controls/VisuallyHidden.module.css +9 -0
- package/src/client/controls/VisuallyHidden.tsx +16 -0
- package/src/client/controls/classes.ts +7 -0
- package/src/client/controls/index.ts +30 -0
- package/src/client/controls/tags.ts +24 -0
- package/src/client/index.ts +10 -2
- package/src/client/layout/Row.tsx +86 -0
- package/src/client/layout/Stack.tsx +79 -0
- package/src/client/layout/Text.tsx +54 -0
- package/src/client/layout/index.ts +16 -0
- package/src/client/layout/layout.module.css +217 -0
- package/src/client/layout/scales.ts +91 -0
- package/src/client/schema-form/Editor.tsx +48 -65
- package/src/client/schema-form/SchemaForm.tsx +4 -4
- package/src/client/schema-form/controller.ts +5 -2
- package/src/client/schema-form/geometry.ts +3 -0
- package/src/client/schema-form/schema-form.module.css +335 -0
- package/src/client/schema-form/value.tsx +10 -9
- package/src/client/settings-form/SettingsFieldRow.module.css +93 -0
- package/src/client/settings-form/SettingsFieldRow.tsx +103 -0
- package/src/client/settings-form/index.ts +5 -18
- package/src/css-modules.d.ts +6 -0
- package/src/client/schema-form/styles.ts +0 -321
- package/src/client/settings-form/SettingsForm.styles.ts +0 -58
- package/src/client/settings-form/SettingsForm.tsx +0 -68
- package/src/client/settings-form/fields.styles.ts +0 -158
- package/src/client/settings-form/fields.tsx +0 -184
- package/src/client/settings-form/form-model.ts +0 -339
- package/src/client/styling/css.ts +0 -27
- package/src/client/styling/focus.ts +0 -9
- package/src/client/styling/index.ts +0 -6
- package/src/client/styling/styled.tsx +0 -54
- package/src/client/styling/styling.ts +0 -142
- package/src/client/styling/token.ts +0 -275
- package/src/client/styling/toolkit.ts +0 -37
- package/src/client/theme.generated.ts +0 -846
- package/src/client/theme.ts +0 -5
|
@@ -34,26 +34,9 @@ import type { ResolveText } from "./labels.ts";
|
|
|
34
34
|
import { TruncatedTooltip } from "./TruncatedTooltip.tsx";
|
|
35
35
|
import { isMultiline, valueText } from "./value.tsx";
|
|
36
36
|
import type { SchemaFieldOwnerProps, SchemaFormTranslate } from "./slot-contract.ts";
|
|
37
|
-
import {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
CompactTextField,
|
|
41
|
-
EditorRoot,
|
|
42
|
-
HoverActions,
|
|
43
|
-
ICON_SIZE,
|
|
44
|
-
LineBody,
|
|
45
|
-
LineComment,
|
|
46
|
-
LineFold,
|
|
47
|
-
LineFoldSpacer,
|
|
48
|
-
LineInvalid,
|
|
49
|
-
LineKey,
|
|
50
|
-
LineNumber,
|
|
51
|
-
LineRow,
|
|
52
|
-
LineToken,
|
|
53
|
-
LineValue,
|
|
54
|
-
ValueSlot,
|
|
55
|
-
ValueTrigger,
|
|
56
|
-
} from "./styles.ts";
|
|
37
|
+
import { classes } from "../controls/classes.ts";
|
|
38
|
+
import { ICON_SIZE } from "./geometry.ts";
|
|
39
|
+
import css from "./schema-form.module.css";
|
|
57
40
|
|
|
58
41
|
// 编辑器要的一切。
|
|
59
42
|
export interface EditorProps {
|
|
@@ -85,7 +68,7 @@ export function Editor(props: EditorProps): ReactNode {
|
|
|
85
68
|
);
|
|
86
69
|
const disabled = !state.writable || !state.available;
|
|
87
70
|
return (
|
|
88
|
-
<
|
|
71
|
+
<div className={css.editorRoot} data-editor="schema-form">
|
|
89
72
|
{lines.map((line, index) => (
|
|
90
73
|
<Row
|
|
91
74
|
key={`${line.kind}:${fieldKey(line.path)}:${String(index)}`}
|
|
@@ -124,7 +107,7 @@ export function Editor(props: EditorProps): ReactNode {
|
|
|
124
107
|
renderField={renderField}
|
|
125
108
|
/>
|
|
126
109
|
))}
|
|
127
|
-
</
|
|
110
|
+
</div>
|
|
128
111
|
);
|
|
129
112
|
}
|
|
130
113
|
|
|
@@ -205,20 +188,20 @@ function Row({
|
|
|
205
188
|
const body =
|
|
206
189
|
line.kind === "comment" ? (
|
|
207
190
|
<>
|
|
208
|
-
<
|
|
191
|
+
<span className={css.lineFoldSpacer} data-role="fold" />
|
|
209
192
|
{/* 这一行有问题时注释位装的就是那条消息:红字,别整行铺红。
|
|
210
193
|
注释被 `ellipsis` 截断时全文交给官方 `Tooltip`——**只有真的截断才挂**,放得下就原样画。 */}
|
|
211
194
|
<TruncatedTooltip label={line.text}>
|
|
212
195
|
{line.invalid ? (
|
|
213
|
-
<
|
|
196
|
+
<span className={css.lineInvalid} data-role="comment">{`// ${line.text}`}</span>
|
|
214
197
|
) : (
|
|
215
|
-
<
|
|
198
|
+
<span className={css.lineComment} data-role="comment">{`// ${line.text}`}</span>
|
|
216
199
|
)}
|
|
217
200
|
</TruncatedTooltip>
|
|
218
201
|
</>
|
|
219
202
|
) : line.kind === "open" ? (
|
|
220
203
|
<>
|
|
221
|
-
<
|
|
204
|
+
<button className={css.lineFold}
|
|
222
205
|
data-role="fold"
|
|
223
206
|
type="button"
|
|
224
207
|
aria-expanded={!line.collapsed}
|
|
@@ -232,11 +215,11 @@ function Row({
|
|
|
232
215
|
) : (
|
|
233
216
|
<IconChevronDownOutlineRegular size={ICON_SIZE} />
|
|
234
217
|
)}
|
|
235
|
-
</
|
|
218
|
+
</button>
|
|
236
219
|
<LinePrefix line={line} face={face} t={t} disabled={disabled} />
|
|
237
|
-
<
|
|
220
|
+
<span className={css.lineToken}>
|
|
238
221
|
{line.shape === "object" ? (line.collapsed ? "{…}" : "{") : line.collapsed ? "[…]" : "["}
|
|
239
|
-
</
|
|
222
|
+
</span>
|
|
240
223
|
<VariantSelect
|
|
241
224
|
control={line.variants}
|
|
242
225
|
path={line.path}
|
|
@@ -247,8 +230,8 @@ function Row({
|
|
|
247
230
|
</>
|
|
248
231
|
) : line.kind === "close" ? (
|
|
249
232
|
<>
|
|
250
|
-
<
|
|
251
|
-
<
|
|
233
|
+
<span className={css.lineFoldSpacer} data-role="fold" />
|
|
234
|
+
<span className={css.lineToken}>{line.shape === "object" ? "}" : "]"}</span>
|
|
252
235
|
<AddLine
|
|
253
236
|
line={line}
|
|
254
237
|
state={state}
|
|
@@ -275,7 +258,7 @@ function Row({
|
|
|
275
258
|
/>
|
|
276
259
|
);
|
|
277
260
|
return (
|
|
278
|
-
<
|
|
261
|
+
<div className={css.lineRow}
|
|
279
262
|
data-line={line.kind}
|
|
280
263
|
data-field-path={line.path.join(".")}
|
|
281
264
|
data-selected={selected === key ? "true" : undefined}
|
|
@@ -289,18 +272,18 @@ function Row({
|
|
|
289
272
|
: undefined
|
|
290
273
|
}
|
|
291
274
|
>
|
|
292
|
-
<
|
|
275
|
+
<span className={css.lineNumber}
|
|
293
276
|
data-role="number"
|
|
294
277
|
onClick={() => {
|
|
295
278
|
onSelect(line.path);
|
|
296
279
|
}}
|
|
297
280
|
>
|
|
298
281
|
{n}
|
|
299
|
-
</
|
|
300
|
-
<
|
|
282
|
+
</span>
|
|
283
|
+
<div className={css.lineBody} data-role="body" style={indent}>
|
|
301
284
|
{body}
|
|
302
|
-
</
|
|
303
|
-
</
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
304
287
|
);
|
|
305
288
|
}
|
|
306
289
|
|
|
@@ -378,19 +361,19 @@ function FieldLine({
|
|
|
378
361
|
const multiline = isMultiline(line.field.value) || /[\r\n]/.test(text);
|
|
379
362
|
return (
|
|
380
363
|
<>
|
|
381
|
-
<
|
|
382
|
-
<
|
|
364
|
+
<span className={css.lineFoldSpacer} data-role="fold" />
|
|
365
|
+
<span className={css.lineKey}
|
|
383
366
|
data-role="key"
|
|
384
367
|
data-index={member?.index === undefined ? undefined : "true"}
|
|
385
368
|
title={member?.key ?? line.node.key}
|
|
386
369
|
>
|
|
387
370
|
{member?.key ?? line.node.key}
|
|
388
|
-
</
|
|
389
|
-
<
|
|
371
|
+
</span>
|
|
372
|
+
<span className={css.lineToken}>{member?.index === undefined ? ": " : " "}</span>
|
|
390
373
|
{isEditing ? (
|
|
391
374
|
// 带换行的值给多行输入(Enter 换行、Esc 撤销),其余是一行的官方输入框。
|
|
392
375
|
multiline ? (
|
|
393
|
-
<
|
|
376
|
+
<span className={css.compactTextField}>
|
|
394
377
|
<textarea
|
|
395
378
|
autoFocus={!missing}
|
|
396
379
|
rows={1}
|
|
@@ -406,9 +389,9 @@ function FieldLine({
|
|
|
406
389
|
}
|
|
407
390
|
}}
|
|
408
391
|
/>
|
|
409
|
-
</
|
|
392
|
+
</span>
|
|
410
393
|
) : (
|
|
411
|
-
<
|
|
394
|
+
<span className={css.compactInput}>
|
|
412
395
|
<Input
|
|
413
396
|
autoFocus={!missing}
|
|
414
397
|
type="text"
|
|
@@ -429,19 +412,19 @@ function FieldLine({
|
|
|
429
412
|
}
|
|
430
413
|
}}
|
|
431
414
|
/>
|
|
432
|
-
</
|
|
415
|
+
</span>
|
|
433
416
|
)
|
|
434
417
|
) : null}
|
|
435
418
|
{/* 编辑态只留输入框:原值不再在它旁边画一遍。 */}
|
|
436
419
|
{isEditing || line.variantsStandIn ? null : (
|
|
437
|
-
<
|
|
420
|
+
<span className={css.valueSlot}
|
|
438
421
|
data-role="value"
|
|
439
422
|
onClick={() => {
|
|
440
423
|
if (editable) onEdit(key);
|
|
441
424
|
}}
|
|
442
425
|
>
|
|
443
426
|
{renderField(owner)}
|
|
444
|
-
</
|
|
427
|
+
</span>
|
|
445
428
|
)}
|
|
446
429
|
<VariantSelect
|
|
447
430
|
control={line.variants}
|
|
@@ -452,7 +435,7 @@ function FieldLine({
|
|
|
452
435
|
/>
|
|
453
436
|
{isEditing ? (
|
|
454
437
|
// 编辑态:确认收起这一格的编辑、取消把值退回去——都在输入框旁边,不用记快捷键。
|
|
455
|
-
<
|
|
438
|
+
<span className={classes(css.lineActions, css.hoverActions)} data-role="actions" data-editing="true">
|
|
456
439
|
<button
|
|
457
440
|
type="button"
|
|
458
441
|
aria-label={t("confirmEdit")}
|
|
@@ -476,9 +459,9 @@ function FieldLine({
|
|
|
476
459
|
>
|
|
477
460
|
<IconCloseOutlineRegular size={ICON_SIZE} />
|
|
478
461
|
</button>
|
|
479
|
-
</
|
|
462
|
+
</span>
|
|
480
463
|
) : null}
|
|
481
|
-
<
|
|
464
|
+
<span className={classes(css.lineActions, css.hoverActions)} data-role="actions">
|
|
482
465
|
{line.field.staged && !disabled ? (
|
|
483
466
|
<button
|
|
484
467
|
type="button"
|
|
@@ -518,7 +501,7 @@ function FieldLine({
|
|
|
518
501
|
{member === undefined ? null : (
|
|
519
502
|
<RemoveLineButton member={member} face={face} t={t} disabled={disabled} />
|
|
520
503
|
)}
|
|
521
|
-
</
|
|
504
|
+
</span>
|
|
522
505
|
</>
|
|
523
506
|
);
|
|
524
507
|
}
|
|
@@ -566,7 +549,7 @@ function VariantSelect({
|
|
|
566
549
|
setOpen(false);
|
|
567
550
|
}}
|
|
568
551
|
anchor={
|
|
569
|
-
<
|
|
552
|
+
<button className={css.valueTrigger}
|
|
570
553
|
type="button"
|
|
571
554
|
data-role="variant"
|
|
572
555
|
disabled={disabled}
|
|
@@ -575,9 +558,9 @@ function VariantSelect({
|
|
|
575
558
|
setOpen(true);
|
|
576
559
|
}}
|
|
577
560
|
>
|
|
578
|
-
<
|
|
561
|
+
<span className={css.lineValue} data-tone="empty">{current?.label ?? ""}</span>
|
|
579
562
|
<IconChevronDownOutlineRegular size={ICON_SIZE} />
|
|
580
|
-
</
|
|
563
|
+
</button>
|
|
581
564
|
}
|
|
582
565
|
/>
|
|
583
566
|
);
|
|
@@ -602,15 +585,15 @@ function LinePrefix({
|
|
|
602
585
|
const indexed = member !== undefined && member.index !== undefined;
|
|
603
586
|
return (
|
|
604
587
|
<>
|
|
605
|
-
<
|
|
588
|
+
<span className={css.lineKey} data-role="key" data-index={indexed ? "true" : undefined} title={key}>
|
|
606
589
|
{key}
|
|
607
|
-
</
|
|
608
|
-
<
|
|
590
|
+
</span>
|
|
591
|
+
<span className={css.lineToken}>{indexed ? " " : ": "}</span>
|
|
609
592
|
{/* 值本身是容器(对象/数组)的成员:它也要能移除,否则这一项删不掉。 */}
|
|
610
593
|
{member === undefined ? null : (
|
|
611
|
-
<
|
|
594
|
+
<span className={classes(css.lineActions, css.hoverActions)} data-role="actions">
|
|
612
595
|
<RemoveLineButton member={member} face={face} t={t} disabled={disabled} />
|
|
613
|
-
</
|
|
596
|
+
</span>
|
|
614
597
|
)}
|
|
615
598
|
</>
|
|
616
599
|
);
|
|
@@ -713,7 +696,7 @@ function AddLine({
|
|
|
713
696
|
setOpen(false);
|
|
714
697
|
};
|
|
715
698
|
return (
|
|
716
|
-
<
|
|
699
|
+
<span className={css.addWrap} data-add={spec.kind} data-invalid={invalid ? "true" : undefined}>
|
|
717
700
|
<Menu
|
|
718
701
|
open={open && spec.kind !== "item" && matched.length > 0}
|
|
719
702
|
dense
|
|
@@ -728,7 +711,7 @@ function AddLine({
|
|
|
728
711
|
setOpen(false);
|
|
729
712
|
}}
|
|
730
713
|
anchor={
|
|
731
|
-
<
|
|
714
|
+
<span className={css.compactInput}>
|
|
732
715
|
<Input
|
|
733
716
|
value={text}
|
|
734
717
|
placeholder={label}
|
|
@@ -757,16 +740,16 @@ function AddLine({
|
|
|
757
740
|
}
|
|
758
741
|
}}
|
|
759
742
|
/>
|
|
760
|
-
</
|
|
743
|
+
</span>
|
|
761
744
|
}
|
|
762
745
|
/>
|
|
763
|
-
{invalid ? <
|
|
746
|
+
{invalid ? <span className={css.lineInvalid}>{t("unknownProperty")}</span> : null}
|
|
764
747
|
{/* 候选的说明:选中之前先看清"要加的是什么"(长了同样由 `Tooltip` 给全文,只有截断时才挂)。 */}
|
|
765
748
|
{!invalid && matched.length === 1 && matched[0]?.description !== undefined ? (
|
|
766
749
|
<TruncatedTooltip label={resolveText(matched[0].description)}>
|
|
767
|
-
<
|
|
750
|
+
<span className={css.lineComment}>{resolveText(matched[0].description)}</span>
|
|
768
751
|
</TruncatedTooltip>
|
|
769
752
|
) : null}
|
|
770
|
-
</
|
|
753
|
+
</span>
|
|
771
754
|
);
|
|
772
755
|
}
|
|
@@ -8,7 +8,7 @@ import { SettingsForm, type SettingsFormLabels } from "@deepseek-ai/dsh-client-u
|
|
|
8
8
|
import { Editor } from "./Editor.tsx";
|
|
9
9
|
import { parseFor } from "./fields.tsx";
|
|
10
10
|
import type { SchemaFieldOwnerProps, SchemaFormComponentProps } from "./slot-contract.ts";
|
|
11
|
-
import
|
|
11
|
+
import css from "./schema-form.module.css";
|
|
12
12
|
import { SchemaFieldDefault } from "./value.tsx";
|
|
13
13
|
|
|
14
14
|
// 渲染一行的配置页。
|
|
@@ -26,7 +26,7 @@ export function SchemaForm(props: SchemaFormComponentProps): ReactNode {
|
|
|
26
26
|
save: t("save"),
|
|
27
27
|
saving: t("saving"),
|
|
28
28
|
};
|
|
29
|
-
if (!state.configured) return <
|
|
29
|
+
if (!state.configured) return <p className={css.hint} role="status">{t("noSchema")}</p>;
|
|
30
30
|
return (
|
|
31
31
|
<SettingsForm
|
|
32
32
|
labels={labels}
|
|
@@ -52,9 +52,9 @@ export function SchemaForm(props: SchemaFormComponentProps): ReactNode {
|
|
|
52
52
|
/>
|
|
53
53
|
{/* 本地整段校验挡下的保存要说出来:否则点保存"没有反应"看起来像按钮坏了。 */}
|
|
54
54
|
{state.violation === undefined ? null : (
|
|
55
|
-
<
|
|
55
|
+
<p className={css.hint} role="alert" data-violation="true">
|
|
56
56
|
{t("notSaved", { message: state.violation.message })}
|
|
57
|
-
</
|
|
57
|
+
</p>
|
|
58
58
|
)}
|
|
59
59
|
</SettingsForm>
|
|
60
60
|
);
|
|
@@ -304,9 +304,12 @@ export class SchemaFormController {
|
|
|
304
304
|
return this.#ns;
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
-
//
|
|
307
|
+
// 外部读数变了(提示面的候选、或 describe 里的 schema 本身):**重读一次 describe** 再投影。
|
|
308
|
+
//
|
|
309
|
+
// 只重投影是不够的:行页在 describe 变化时会重建控制器,而"这一行常驻、只订阅 describe"的消费方(bundle 配置页)
|
|
310
|
+
// 依赖这次重读——否则视图晚到、通知没落上时,字段树会停在"还没有"的那一次投影上。
|
|
308
311
|
refresh(): void {
|
|
309
|
-
this.#
|
|
312
|
+
this.#sync();
|
|
310
313
|
}
|
|
311
314
|
|
|
312
315
|
// 释放订阅。
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/* 行式编辑器的样式:等宽、行号、语法色、悬停行为——全部消费官方 `--dsw-*` token。
|
|
2
|
+
几何只有一套:行高 22px、行内间距 6px、动作键 20px、折叠列 14px、行号列 32px,行与行之间不各自决定。 */
|
|
3
|
+
|
|
4
|
+
.editorRoot {
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
width: 100%;
|
|
8
|
+
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
|
|
9
|
+
font-size: 14px;
|
|
10
|
+
line-height: 22px;
|
|
11
|
+
color: var(--dsw-alias-label-primary);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* 一行:行号 + 折进 + 行内容。悬停给一层浅底。 */
|
|
15
|
+
.lineRow {
|
|
16
|
+
display: flex;
|
|
17
|
+
/* 顶部对齐:行里出现输入框或多行值时,内容不跟着上下跳。 */
|
|
18
|
+
align-items: flex-start;
|
|
19
|
+
gap: 6px;
|
|
20
|
+
min-height: 22px;
|
|
21
|
+
padding-right: 8px;
|
|
22
|
+
white-space: nowrap;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.lineRow:hover {
|
|
26
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* 选中一行(点行号):整行留一层底色,便于对着行号找内容。 */
|
|
30
|
+
.lineRow[data-selected='true'] {
|
|
31
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* 本页改过还没保存:左边一道强调色,和「已经存进用户层」的浅灰区分开。 */
|
|
35
|
+
.lineRow[data-dirty='true'] {
|
|
36
|
+
box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.lineRow[data-overridden='true'] {
|
|
40
|
+
box-shadow: inset 2px 0 0 var(--dsw-elevation-stroke-color);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* 改过的字段名用强调色(存没存看左边那道条);出错时红优先。 */
|
|
44
|
+
.lineRow[data-dirty='true'] [data-role='key'] {
|
|
45
|
+
color: var(--dsw-alias-brand-primary);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.lineRow[data-overridden='true'] [data-role='key'] {
|
|
49
|
+
color: var(--dsw-alias-brand-primary);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* 有问题的行:半透明红底 + 左侧一道实红条,字段名与注释位那句都是红字。 */
|
|
53
|
+
.lineRow[data-invalid='true'] {
|
|
54
|
+
background: color-mix(in srgb, var(--dsw-alias-state-error-secondary) 12%, transparent);
|
|
55
|
+
box-shadow: inset 2px 0 0 var(--dsw-alias-state-error-primary);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.lineRow[data-invalid='true'] [data-role='key'] {
|
|
59
|
+
color: var(--dsw-alias-state-error-primary);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* 行内的行为按钮(撤回 / 恢复默认 / 复制 / 移除):平时透明,悬停这一行才显形。 */
|
|
63
|
+
.lineRow:hover [data-role='actions'] {
|
|
64
|
+
opacity: 1;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* 一行的内容区:**缩进只作用在这里**——行号列固定在左边,缩进不推它。 */
|
|
68
|
+
.lineBody {
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
gap: 6px;
|
|
72
|
+
flex: 1;
|
|
73
|
+
min-width: 0;
|
|
74
|
+
min-height: 22px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* 行号列:右对齐、不可选、淡色。 */
|
|
78
|
+
.lineNumber {
|
|
79
|
+
flex: none;
|
|
80
|
+
width: 32px;
|
|
81
|
+
line-height: 22px;
|
|
82
|
+
text-align: right;
|
|
83
|
+
color: var(--dsw-alias-label-caption);
|
|
84
|
+
user-select: none;
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* 折叠 chevron(官方箭头图标,尺寸与别的行内图标同源)。 */
|
|
89
|
+
.lineFold {
|
|
90
|
+
display: inline-flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
flex: none;
|
|
94
|
+
width: 14px;
|
|
95
|
+
height: 22px;
|
|
96
|
+
padding: 0;
|
|
97
|
+
border: 0;
|
|
98
|
+
background: none;
|
|
99
|
+
color: var(--dsw-alias-label-caption);
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.lineFold:hover {
|
|
104
|
+
color: var(--dsw-alias-label-secondary);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* 叶子行的折叠占位(保持列对齐)。 */
|
|
108
|
+
.lineFoldSpacer {
|
|
109
|
+
flex: none;
|
|
110
|
+
width: 14px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* 键名(配置键原样;数组下标淡一些)。 */
|
|
114
|
+
.lineKey {
|
|
115
|
+
flex: none;
|
|
116
|
+
color: var(--dsw-alias-label-primary);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.lineKey[data-index='true'] {
|
|
120
|
+
color: var(--dsw-alias-label-caption);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* 结构符与标点(`{` `}` `[` `]` `:`)。 */
|
|
124
|
+
.lineToken {
|
|
125
|
+
flex: none;
|
|
126
|
+
color: var(--dsw-alias-label-caption);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* 值(token):字符串 / 数字 / 布尔各有语法色。
|
|
130
|
+
**必须是块级盒**:`overflow` / `text-overflow` 对 inline 盒不生效,inline 的 token 无论多长都不会截断,
|
|
131
|
+
只会把行撑宽。 */
|
|
132
|
+
.lineValue {
|
|
133
|
+
display: block;
|
|
134
|
+
min-width: 0;
|
|
135
|
+
overflow: hidden;
|
|
136
|
+
text-overflow: ellipsis;
|
|
137
|
+
cursor: text;
|
|
138
|
+
color: var(--dsw-alias-state-business-primary);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.lineValue[data-tone='number'] {
|
|
142
|
+
color: var(--dsw-alias-state-warn-primary);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.lineValue[data-tone='boolean'] {
|
|
146
|
+
color: var(--dsw-alias-state-success-primary);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.lineValue[data-tone='empty'] {
|
|
150
|
+
color: var(--dsw-alias-label-caption);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* 值在行里的位置(字段槽的宿主):键名与结构符都是 `flex: none`,它是行里**唯一可收缩**的那一项。
|
|
154
|
+
不生长:短值保持自然宽度,长值才收缩到行尾并自己截断。 */
|
|
155
|
+
.valueSlot {
|
|
156
|
+
display: block;
|
|
157
|
+
flex: 0 1 auto;
|
|
158
|
+
min-width: 0;
|
|
159
|
+
overflow: hidden;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* 值上的下拉触发:**它自己就是值的呈现**(不再是「值 + 一个下拉」两遍),点开才出菜单。 */
|
|
163
|
+
.valueTrigger {
|
|
164
|
+
display: inline-flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
gap: 2px;
|
|
167
|
+
min-width: 0;
|
|
168
|
+
padding: 0;
|
|
169
|
+
border: 0;
|
|
170
|
+
background: none;
|
|
171
|
+
font: inherit;
|
|
172
|
+
text-align: left;
|
|
173
|
+
cursor: pointer;
|
|
174
|
+
color: var(--dsw-alias-label-caption);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.valueTrigger:disabled {
|
|
178
|
+
cursor: default;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.valueTrigger:focus-visible {
|
|
182
|
+
outline: none;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* 行内输入的外壳:官方 `Input` 压到与值同一行高,并**吃掉剩下的宽度**。
|
|
186
|
+
行内编辑与容器闭合行的添加输入共用它——两处的输入框因此长得一模一样。 */
|
|
187
|
+
.compactInput {
|
|
188
|
+
display: inline-flex;
|
|
189
|
+
flex: 1 1 auto;
|
|
190
|
+
min-width: 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.compactInput > span {
|
|
194
|
+
width: 100%;
|
|
195
|
+
height: 22px;
|
|
196
|
+
padding: 0 6px;
|
|
197
|
+
border-radius: 4px;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.compactInput input {
|
|
201
|
+
font-size: 14px;
|
|
202
|
+
line-height: 22px;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* 多行值的行内输入:官方没有多行原子,所以这里用同一套观感的字段壳(同边框、同圆角、同焦点色),
|
|
206
|
+
高度跟着内容长、宽度同样撑满剩下的位置。 */
|
|
207
|
+
.compactTextField {
|
|
208
|
+
display: inline-flex;
|
|
209
|
+
flex: 1 1 auto;
|
|
210
|
+
min-width: 0;
|
|
211
|
+
padding: 0 6px;
|
|
212
|
+
border-radius: 4px;
|
|
213
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
214
|
+
/* 细线走 theme 的描边(0.5px 与颜色都由 token 给)。 */
|
|
215
|
+
border: 0;
|
|
216
|
+
box-shadow: 0 0 0 0.5px var(--dsw-elevation-stroke-color);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.compactTextField:focus-within {
|
|
220
|
+
--dsw-elevation-stroke-color: var(--dsw-alias-brand-primary);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.compactTextField > textarea {
|
|
224
|
+
flex: 1;
|
|
225
|
+
width: 100%;
|
|
226
|
+
min-height: 20px;
|
|
227
|
+
max-height: 240px;
|
|
228
|
+
padding: 0;
|
|
229
|
+
border: 0;
|
|
230
|
+
outline: none;
|
|
231
|
+
background: transparent;
|
|
232
|
+
resize: none;
|
|
233
|
+
field-sizing: content;
|
|
234
|
+
font-family: inherit;
|
|
235
|
+
font-size: 14px;
|
|
236
|
+
line-height: 22px;
|
|
237
|
+
color: var(--dsw-alias-label-primary);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* 行内注释(schema 说明与业务文案):比配置值小一档、tertiary 色,占满这一行剩下的宽度,长了就截断——
|
|
241
|
+
**真的被截断时**才由官方 `Tooltip` 给全文。 */
|
|
242
|
+
.lineComment {
|
|
243
|
+
flex: 1 1 auto;
|
|
244
|
+
min-width: 0;
|
|
245
|
+
overflow: hidden;
|
|
246
|
+
text-overflow: ellipsis;
|
|
247
|
+
color: var(--dsw-alias-label-tertiary);
|
|
248
|
+
font-family: inherit;
|
|
249
|
+
font-size: 12px;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* 行内的校验消息(与注释放同一档字号):可收缩、自己截断、**截断了**才由官方 `Tooltip` 给全文。
|
|
253
|
+
`flex: 0 1 auto`(不生长):短消息别铺满整行,添加入口那一行里也不跟输入框抢剩下的宽度。 */
|
|
254
|
+
.lineInvalid {
|
|
255
|
+
flex: 0 1 auto;
|
|
256
|
+
min-width: 0;
|
|
257
|
+
overflow: hidden;
|
|
258
|
+
text-overflow: ellipsis;
|
|
259
|
+
color: var(--dsw-alias-state-error-primary);
|
|
260
|
+
font-family: inherit;
|
|
261
|
+
font-size: 12px;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* 行尾的动作组:方形图标键(默认透明,悬停时显形,显形规则写在行上)。 */
|
|
265
|
+
.lineActions {
|
|
266
|
+
display: inline-flex;
|
|
267
|
+
align-items: center;
|
|
268
|
+
gap: 4px;
|
|
269
|
+
flex: none;
|
|
270
|
+
opacity: 0;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.lineActions > button {
|
|
274
|
+
display: inline-flex;
|
|
275
|
+
align-items: center;
|
|
276
|
+
justify-content: center;
|
|
277
|
+
width: 20px;
|
|
278
|
+
height: 20px;
|
|
279
|
+
padding: 0;
|
|
280
|
+
border: 0;
|
|
281
|
+
border-radius: 4px;
|
|
282
|
+
background: none;
|
|
283
|
+
color: var(--dsw-alias-label-secondary);
|
|
284
|
+
cursor: pointer;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.lineActions > button:hover {
|
|
288
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
289
|
+
color: var(--dsw-alias-label-primary);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.lineActions > button:disabled {
|
|
293
|
+
cursor: not-allowed;
|
|
294
|
+
color: var(--dsw-alias-label-dimmed);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* 编辑态的两个按钮常显,而且**要有底色与描边**:行底色上只有淡色图标是看不见的,
|
|
298
|
+
所以这里给实体按钮(theme 的描边 + 一层底),确认用成功档、取消用中性档。 */
|
|
299
|
+
.hoverActions[data-editing='true'] {
|
|
300
|
+
opacity: 1;
|
|
301
|
+
gap: 6px;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.hoverActions[data-editing='true'] > button {
|
|
305
|
+
box-shadow: 0 0 0 0.5px var(--dsw-elevation-stroke-color);
|
|
306
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
307
|
+
color: var(--dsw-alias-label-primary);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.hoverActions[data-editing='true'] > button:first-of-type {
|
|
311
|
+
color: var(--dsw-alias-state-success-primary);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* 添加输入:**跟在容器的闭合括号同一行**(菜单锚在它上面),宽度吃掉剩下的位置。 */
|
|
315
|
+
.addWrap {
|
|
316
|
+
position: relative;
|
|
317
|
+
display: inline-flex;
|
|
318
|
+
align-items: center;
|
|
319
|
+
gap: 6px;
|
|
320
|
+
flex: 1 1 auto;
|
|
321
|
+
min-width: 0;
|
|
322
|
+
margin-left: 6px;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.addWrap[data-invalid='true'] input {
|
|
326
|
+
border-color: var(--dsw-alias-state-error-primary);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* 一行说明(不可用 / 没有可生成项时用)。 */
|
|
330
|
+
.hint {
|
|
331
|
+
margin: 0;
|
|
332
|
+
font-size: 12px;
|
|
333
|
+
line-height: 1.5;
|
|
334
|
+
color: var(--dsw-alias-label-tertiary);
|
|
335
|
+
}
|