@morlay/dsh-client-ui-primitives 0.0.7 → 0.0.9
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 +32 -9
- package/dist/client-DYp99CgT.mjs +3730 -0
- package/dist/client-uyVkC7mu.cjs +17197 -0
- package/dist/client.cjs +54 -0
- package/dist/client.d.cts +4 -0
- package/dist/client.d.mts +3 -11680
- package/dist/client.mjs +3 -4575
- package/dist/index-AMHtcyMt.d.mts +647 -0
- package/dist/index.cjs +54 -0
- package/dist/index.d.mts +4 -5
- package/dist/index.mjs +4 -5
- package/dist/reference-hchCWm3z.cjs +482 -0
- package/dist/reference.cjs +4 -0
- package/dist/reference.d.mts +3 -0
- package/dist/reference.mjs +1 -0
- package/package.json +31 -35
- 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 +47 -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/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 +39 -0
- package/src/client/controls/Spinner.module.css +18 -0
- package/src/client/controls/Spinner.tsx +14 -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 +5 -0
- package/src/client/controls/index.ts +24 -0
- package/src/client/controls/tags.ts +24 -0
- package/src/client/index.ts +16 -2
- package/src/client/layout/Row.tsx +89 -0
- package/src/client/layout/Stack.tsx +82 -0
- package/src/client/layout/Text.tsx +61 -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 +65 -65
- package/src/client/schema-form/SchemaForm.tsx +9 -4
- package/src/client/schema-form/controller.ts +5 -2
- package/src/client/schema-form/geometry.ts +3 -0
- package/src/client/schema-form/index.ts +5 -0
- package/src/client/schema-form/schema-form.module.css +335 -0
- package/src/client/schema-form/testing/fake-scope.ts +0 -1
- package/src/client/schema-form/value.tsx +15 -9
- package/src/client/settings-form/SettingsFieldRow.module.css +93 -0
- package/src/client/settings-form/SettingsFieldRow.tsx +105 -0
- package/src/client/settings-form/index.ts +5 -18
- package/src/css-modules.d.ts +6 -0
- package/src/index.ts +6 -2
- package/src/reference-markdown.tsx +2 -6
- package/dist/rolldown-runtime-EAsCxrDo.mjs +0 -14
- package/locale/en.json +0 -6
- package/locale/zh.json +0 -6
- 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
- /package/src/{client/markdown-text.ts → markdown-text.ts} +0 -0
|
@@ -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,21 @@ 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
|
|
205
|
+
className={css.lineFold}
|
|
222
206
|
data-role="fold"
|
|
223
207
|
type="button"
|
|
224
208
|
aria-expanded={!line.collapsed}
|
|
@@ -232,11 +216,11 @@ function Row({
|
|
|
232
216
|
) : (
|
|
233
217
|
<IconChevronDownOutlineRegular size={ICON_SIZE} />
|
|
234
218
|
)}
|
|
235
|
-
</
|
|
219
|
+
</button>
|
|
236
220
|
<LinePrefix line={line} face={face} t={t} disabled={disabled} />
|
|
237
|
-
<
|
|
221
|
+
<span className={css.lineToken}>
|
|
238
222
|
{line.shape === "object" ? (line.collapsed ? "{…}" : "{") : line.collapsed ? "[…]" : "["}
|
|
239
|
-
</
|
|
223
|
+
</span>
|
|
240
224
|
<VariantSelect
|
|
241
225
|
control={line.variants}
|
|
242
226
|
path={line.path}
|
|
@@ -247,8 +231,8 @@ function Row({
|
|
|
247
231
|
</>
|
|
248
232
|
) : line.kind === "close" ? (
|
|
249
233
|
<>
|
|
250
|
-
<
|
|
251
|
-
<
|
|
234
|
+
<span className={css.lineFoldSpacer} data-role="fold" />
|
|
235
|
+
<span className={css.lineToken}>{line.shape === "object" ? "}" : "]"}</span>
|
|
252
236
|
<AddLine
|
|
253
237
|
line={line}
|
|
254
238
|
state={state}
|
|
@@ -275,7 +259,8 @@ function Row({
|
|
|
275
259
|
/>
|
|
276
260
|
);
|
|
277
261
|
return (
|
|
278
|
-
<
|
|
262
|
+
<div
|
|
263
|
+
className={css.lineRow}
|
|
279
264
|
data-line={line.kind}
|
|
280
265
|
data-field-path={line.path.join(".")}
|
|
281
266
|
data-selected={selected === key ? "true" : undefined}
|
|
@@ -289,18 +274,19 @@ function Row({
|
|
|
289
274
|
: undefined
|
|
290
275
|
}
|
|
291
276
|
>
|
|
292
|
-
<
|
|
277
|
+
<span
|
|
278
|
+
className={css.lineNumber}
|
|
293
279
|
data-role="number"
|
|
294
280
|
onClick={() => {
|
|
295
281
|
onSelect(line.path);
|
|
296
282
|
}}
|
|
297
283
|
>
|
|
298
284
|
{n}
|
|
299
|
-
</
|
|
300
|
-
<
|
|
285
|
+
</span>
|
|
286
|
+
<div className={css.lineBody} data-role="body" style={indent}>
|
|
301
287
|
{body}
|
|
302
|
-
</
|
|
303
|
-
</
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
304
290
|
);
|
|
305
291
|
}
|
|
306
292
|
|
|
@@ -378,19 +364,20 @@ function FieldLine({
|
|
|
378
364
|
const multiline = isMultiline(line.field.value) || /[\r\n]/.test(text);
|
|
379
365
|
return (
|
|
380
366
|
<>
|
|
381
|
-
<
|
|
382
|
-
<
|
|
367
|
+
<span className={css.lineFoldSpacer} data-role="fold" />
|
|
368
|
+
<span
|
|
369
|
+
className={css.lineKey}
|
|
383
370
|
data-role="key"
|
|
384
371
|
data-index={member?.index === undefined ? undefined : "true"}
|
|
385
372
|
title={member?.key ?? line.node.key}
|
|
386
373
|
>
|
|
387
374
|
{member?.key ?? line.node.key}
|
|
388
|
-
</
|
|
389
|
-
<
|
|
375
|
+
</span>
|
|
376
|
+
<span className={css.lineToken}>{member?.index === undefined ? ": " : " "}</span>
|
|
390
377
|
{isEditing ? (
|
|
391
378
|
// 带换行的值给多行输入(Enter 换行、Esc 撤销),其余是一行的官方输入框。
|
|
392
379
|
multiline ? (
|
|
393
|
-
<
|
|
380
|
+
<span className={css.compactTextField}>
|
|
394
381
|
<textarea
|
|
395
382
|
autoFocus={!missing}
|
|
396
383
|
rows={1}
|
|
@@ -406,9 +393,9 @@ function FieldLine({
|
|
|
406
393
|
}
|
|
407
394
|
}}
|
|
408
395
|
/>
|
|
409
|
-
</
|
|
396
|
+
</span>
|
|
410
397
|
) : (
|
|
411
|
-
<
|
|
398
|
+
<span className={css.compactInput}>
|
|
412
399
|
<Input
|
|
413
400
|
autoFocus={!missing}
|
|
414
401
|
type="text"
|
|
@@ -429,19 +416,20 @@ function FieldLine({
|
|
|
429
416
|
}
|
|
430
417
|
}}
|
|
431
418
|
/>
|
|
432
|
-
</
|
|
419
|
+
</span>
|
|
433
420
|
)
|
|
434
421
|
) : null}
|
|
435
422
|
{/* 编辑态只留输入框:原值不再在它旁边画一遍。 */}
|
|
436
423
|
{isEditing || line.variantsStandIn ? null : (
|
|
437
|
-
<
|
|
424
|
+
<span
|
|
425
|
+
className={css.valueSlot}
|
|
438
426
|
data-role="value"
|
|
439
427
|
onClick={() => {
|
|
440
428
|
if (editable) onEdit(key);
|
|
441
429
|
}}
|
|
442
430
|
>
|
|
443
431
|
{renderField(owner)}
|
|
444
|
-
</
|
|
432
|
+
</span>
|
|
445
433
|
)}
|
|
446
434
|
<VariantSelect
|
|
447
435
|
control={line.variants}
|
|
@@ -452,7 +440,11 @@ function FieldLine({
|
|
|
452
440
|
/>
|
|
453
441
|
{isEditing ? (
|
|
454
442
|
// 编辑态:确认收起这一格的编辑、取消把值退回去——都在输入框旁边,不用记快捷键。
|
|
455
|
-
<
|
|
443
|
+
<span
|
|
444
|
+
className={classes(css.lineActions, css.hoverActions)}
|
|
445
|
+
data-role="actions"
|
|
446
|
+
data-editing="true"
|
|
447
|
+
>
|
|
456
448
|
<button
|
|
457
449
|
type="button"
|
|
458
450
|
aria-label={t("confirmEdit")}
|
|
@@ -476,9 +468,9 @@ function FieldLine({
|
|
|
476
468
|
>
|
|
477
469
|
<IconCloseOutlineRegular size={ICON_SIZE} />
|
|
478
470
|
</button>
|
|
479
|
-
</
|
|
471
|
+
</span>
|
|
480
472
|
) : null}
|
|
481
|
-
<
|
|
473
|
+
<span className={classes(css.lineActions, css.hoverActions)} data-role="actions">
|
|
482
474
|
{line.field.staged && !disabled ? (
|
|
483
475
|
<button
|
|
484
476
|
type="button"
|
|
@@ -518,7 +510,7 @@ function FieldLine({
|
|
|
518
510
|
{member === undefined ? null : (
|
|
519
511
|
<RemoveLineButton member={member} face={face} t={t} disabled={disabled} />
|
|
520
512
|
)}
|
|
521
|
-
</
|
|
513
|
+
</span>
|
|
522
514
|
</>
|
|
523
515
|
);
|
|
524
516
|
}
|
|
@@ -566,7 +558,8 @@ function VariantSelect({
|
|
|
566
558
|
setOpen(false);
|
|
567
559
|
}}
|
|
568
560
|
anchor={
|
|
569
|
-
<
|
|
561
|
+
<button
|
|
562
|
+
className={css.valueTrigger}
|
|
570
563
|
type="button"
|
|
571
564
|
data-role="variant"
|
|
572
565
|
disabled={disabled}
|
|
@@ -575,9 +568,11 @@ function VariantSelect({
|
|
|
575
568
|
setOpen(true);
|
|
576
569
|
}}
|
|
577
570
|
>
|
|
578
|
-
<
|
|
571
|
+
<span className={css.lineValue} data-tone="empty">
|
|
572
|
+
{current?.label ?? ""}
|
|
573
|
+
</span>
|
|
579
574
|
<IconChevronDownOutlineRegular size={ICON_SIZE} />
|
|
580
|
-
</
|
|
575
|
+
</button>
|
|
581
576
|
}
|
|
582
577
|
/>
|
|
583
578
|
);
|
|
@@ -602,15 +597,20 @@ function LinePrefix({
|
|
|
602
597
|
const indexed = member !== undefined && member.index !== undefined;
|
|
603
598
|
return (
|
|
604
599
|
<>
|
|
605
|
-
<
|
|
600
|
+
<span
|
|
601
|
+
className={css.lineKey}
|
|
602
|
+
data-role="key"
|
|
603
|
+
data-index={indexed ? "true" : undefined}
|
|
604
|
+
title={key}
|
|
605
|
+
>
|
|
606
606
|
{key}
|
|
607
|
-
</
|
|
608
|
-
<
|
|
607
|
+
</span>
|
|
608
|
+
<span className={css.lineToken}>{indexed ? " " : ": "}</span>
|
|
609
609
|
{/* 值本身是容器(对象/数组)的成员:它也要能移除,否则这一项删不掉。 */}
|
|
610
610
|
{member === undefined ? null : (
|
|
611
|
-
<
|
|
611
|
+
<span className={classes(css.lineActions, css.hoverActions)} data-role="actions">
|
|
612
612
|
<RemoveLineButton member={member} face={face} t={t} disabled={disabled} />
|
|
613
|
-
</
|
|
613
|
+
</span>
|
|
614
614
|
)}
|
|
615
615
|
</>
|
|
616
616
|
);
|
|
@@ -713,7 +713,7 @@ function AddLine({
|
|
|
713
713
|
setOpen(false);
|
|
714
714
|
};
|
|
715
715
|
return (
|
|
716
|
-
<
|
|
716
|
+
<span className={css.addWrap} data-add={spec.kind} data-invalid={invalid ? "true" : undefined}>
|
|
717
717
|
<Menu
|
|
718
718
|
open={open && spec.kind !== "item" && matched.length > 0}
|
|
719
719
|
dense
|
|
@@ -728,7 +728,7 @@ function AddLine({
|
|
|
728
728
|
setOpen(false);
|
|
729
729
|
}}
|
|
730
730
|
anchor={
|
|
731
|
-
<
|
|
731
|
+
<span className={css.compactInput}>
|
|
732
732
|
<Input
|
|
733
733
|
value={text}
|
|
734
734
|
placeholder={label}
|
|
@@ -757,16 +757,16 @@ function AddLine({
|
|
|
757
757
|
}
|
|
758
758
|
}}
|
|
759
759
|
/>
|
|
760
|
-
</
|
|
760
|
+
</span>
|
|
761
761
|
}
|
|
762
762
|
/>
|
|
763
|
-
{invalid ? <
|
|
763
|
+
{invalid ? <span className={css.lineInvalid}>{t("unknownProperty")}</span> : null}
|
|
764
764
|
{/* 候选的说明:选中之前先看清"要加的是什么"(长了同样由 `Tooltip` 给全文,只有截断时才挂)。 */}
|
|
765
765
|
{!invalid && matched.length === 1 && matched[0]?.description !== undefined ? (
|
|
766
766
|
<TruncatedTooltip label={resolveText(matched[0].description)}>
|
|
767
|
-
<
|
|
767
|
+
<span className={css.lineComment}>{resolveText(matched[0].description)}</span>
|
|
768
768
|
</TruncatedTooltip>
|
|
769
769
|
) : null}
|
|
770
|
-
</
|
|
770
|
+
</span>
|
|
771
771
|
);
|
|
772
772
|
}
|
|
@@ -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,12 @@ export function SchemaForm(props: SchemaFormComponentProps): ReactNode {
|
|
|
26
26
|
save: t("save"),
|
|
27
27
|
saving: t("saving"),
|
|
28
28
|
};
|
|
29
|
-
if (!state.configured)
|
|
29
|
+
if (!state.configured)
|
|
30
|
+
return (
|
|
31
|
+
<p className={css.hint} role="status">
|
|
32
|
+
{t("noSchema")}
|
|
33
|
+
</p>
|
|
34
|
+
);
|
|
30
35
|
return (
|
|
31
36
|
<SettingsForm
|
|
32
37
|
labels={labels}
|
|
@@ -52,9 +57,9 @@ export function SchemaForm(props: SchemaFormComponentProps): ReactNode {
|
|
|
52
57
|
/>
|
|
53
58
|
{/* 本地整段校验挡下的保存要说出来:否则点保存"没有反应"看起来像按钮坏了。 */}
|
|
54
59
|
{state.violation === undefined ? null : (
|
|
55
|
-
<
|
|
60
|
+
<p className={css.hint} role="alert" data-violation="true">
|
|
56
61
|
{t("notSaved", { message: state.violation.message })}
|
|
57
|
-
</
|
|
62
|
+
</p>
|
|
58
63
|
)}
|
|
59
64
|
</SettingsForm>
|
|
60
65
|
);
|
|
@@ -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
|
// 释放订阅。
|
|
@@ -57,6 +57,11 @@ export { parseFor } from "./fields.tsx";
|
|
|
57
57
|
export { containerShape, editorLines, visibleFields } from "./lines.ts";
|
|
58
58
|
export type { EditorLine, FoldState } from "./lines.ts";
|
|
59
59
|
export { SchemaFormController, canRender, optionsFor, projectRoot } from "./controller.ts";
|
|
60
|
+
// 行投影的输入件:外部的「真配置验收」要按与控制器同一套算法自己排行(见各消费包 client 面的 __tests__)。
|
|
61
|
+
export { addableAt, fieldKey } from "./controller.ts";
|
|
62
|
+
export { readPath } from "./schema-node.ts";
|
|
63
|
+
export type { SchemaFormTranslate } from "./slot-contract.ts";
|
|
64
|
+
export { zh } from "./locales.ts";
|
|
60
65
|
export { failureOf } from "./draft.ts";
|
|
61
66
|
export type { ValidationFailure } from "./draft.ts";
|
|
62
67
|
export { walkFields, projectNode } from "./schema-node.ts";
|