@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.
Files changed (83) hide show
  1. package/README.md +32 -9
  2. package/dist/client-DYp99CgT.mjs +3730 -0
  3. package/dist/client-uyVkC7mu.cjs +17197 -0
  4. package/dist/client.cjs +54 -0
  5. package/dist/client.d.cts +4 -0
  6. package/dist/client.d.mts +3 -11680
  7. package/dist/client.mjs +3 -4575
  8. package/dist/index-AMHtcyMt.d.mts +647 -0
  9. package/dist/index.cjs +54 -0
  10. package/dist/index.d.mts +4 -5
  11. package/dist/index.mjs +4 -5
  12. package/dist/reference-hchCWm3z.cjs +482 -0
  13. package/dist/reference.cjs +4 -0
  14. package/dist/reference.d.mts +3 -0
  15. package/dist/reference.mjs +1 -0
  16. package/package.json +31 -35
  17. package/src/client/controls/Bubble.module.css +17 -0
  18. package/src/client/controls/Bubble.tsx +17 -0
  19. package/src/client/controls/Button.module.css +10 -0
  20. package/src/client/controls/Button.tsx +29 -0
  21. package/src/client/controls/DisclosureRow.module.css +22 -0
  22. package/src/client/controls/DisclosureRow.tsx +20 -0
  23. package/src/client/controls/IconButton.module.css +50 -0
  24. package/src/client/controls/IconButton.tsx +47 -0
  25. package/src/client/controls/ModelRouteList.module.css +100 -0
  26. package/src/client/controls/ModelRouteList.tsx +118 -0
  27. package/src/client/controls/MultilineField.module.css +26 -0
  28. package/src/client/controls/MultilineField.tsx +19 -0
  29. package/src/client/controls/SearchSelect.module.css +34 -0
  30. package/src/client/controls/SearchSelect.tsx +138 -0
  31. package/src/client/controls/SeatButton.module.css +53 -0
  32. package/src/client/controls/SeatButton.tsx +39 -0
  33. package/src/client/controls/Spinner.module.css +18 -0
  34. package/src/client/controls/Spinner.tsx +14 -0
  35. package/src/client/controls/TagInput.module.css +105 -0
  36. package/src/client/controls/TagInput.tsx +152 -0
  37. package/src/client/controls/TimeLabel.module.css +16 -0
  38. package/src/client/controls/TimeLabel.tsx +15 -0
  39. package/src/client/controls/VisuallyHidden.module.css +9 -0
  40. package/src/client/controls/VisuallyHidden.tsx +16 -0
  41. package/src/client/controls/classes.ts +5 -0
  42. package/src/client/controls/index.ts +24 -0
  43. package/src/client/controls/tags.ts +24 -0
  44. package/src/client/index.ts +16 -2
  45. package/src/client/layout/Row.tsx +89 -0
  46. package/src/client/layout/Stack.tsx +82 -0
  47. package/src/client/layout/Text.tsx +61 -0
  48. package/src/client/layout/index.ts +16 -0
  49. package/src/client/layout/layout.module.css +217 -0
  50. package/src/client/layout/scales.ts +91 -0
  51. package/src/client/schema-form/Editor.tsx +65 -65
  52. package/src/client/schema-form/SchemaForm.tsx +9 -4
  53. package/src/client/schema-form/controller.ts +5 -2
  54. package/src/client/schema-form/geometry.ts +3 -0
  55. package/src/client/schema-form/index.ts +5 -0
  56. package/src/client/schema-form/schema-form.module.css +335 -0
  57. package/src/client/schema-form/testing/fake-scope.ts +0 -1
  58. package/src/client/schema-form/value.tsx +15 -9
  59. package/src/client/settings-form/SettingsFieldRow.module.css +93 -0
  60. package/src/client/settings-form/SettingsFieldRow.tsx +105 -0
  61. package/src/client/settings-form/index.ts +5 -18
  62. package/src/css-modules.d.ts +6 -0
  63. package/src/index.ts +6 -2
  64. package/src/reference-markdown.tsx +2 -6
  65. package/dist/rolldown-runtime-EAsCxrDo.mjs +0 -14
  66. package/locale/en.json +0 -6
  67. package/locale/zh.json +0 -6
  68. package/src/client/schema-form/styles.ts +0 -321
  69. package/src/client/settings-form/SettingsForm.styles.ts +0 -58
  70. package/src/client/settings-form/SettingsForm.tsx +0 -68
  71. package/src/client/settings-form/fields.styles.ts +0 -158
  72. package/src/client/settings-form/fields.tsx +0 -184
  73. package/src/client/settings-form/form-model.ts +0 -339
  74. package/src/client/styling/css.ts +0 -27
  75. package/src/client/styling/focus.ts +0 -9
  76. package/src/client/styling/index.ts +0 -6
  77. package/src/client/styling/styled.tsx +0 -54
  78. package/src/client/styling/styling.ts +0 -142
  79. package/src/client/styling/token.ts +0 -275
  80. package/src/client/styling/toolkit.ts +0 -37
  81. package/src/client/theme.generated.ts +0 -846
  82. package/src/client/theme.ts +0 -5
  83. /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
- AddWrap,
39
- CompactInput,
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
- <EditorRoot data-editor="schema-form">
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
- </EditorRoot>
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
- <LineFoldSpacer data-role="fold" />
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
- <LineInvalid data-role="comment">{`// ${line.text}`}</LineInvalid>
196
+ <span className={css.lineInvalid} data-role="comment">{`// ${line.text}`}</span>
214
197
  ) : (
215
- <LineComment data-role="comment">{`// ${line.text}`}</LineComment>
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
- <LineFold
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
- </LineFold>
219
+ </button>
236
220
  <LinePrefix line={line} face={face} t={t} disabled={disabled} />
237
- <LineToken>
221
+ <span className={css.lineToken}>
238
222
  {line.shape === "object" ? (line.collapsed ? "{…}" : "{") : line.collapsed ? "[…]" : "["}
239
- </LineToken>
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
- <LineFoldSpacer data-role="fold" />
251
- <LineToken>{line.shape === "object" ? "}" : "]"}</LineToken>
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
- <LineRow
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
- <LineNumber
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
- </LineNumber>
300
- <LineBody data-role="body" style={indent}>
285
+ </span>
286
+ <div className={css.lineBody} data-role="body" style={indent}>
301
287
  {body}
302
- </LineBody>
303
- </LineRow>
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
- <LineFoldSpacer data-role="fold" />
382
- <LineKey
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
- </LineKey>
389
- <LineToken>{member?.index === undefined ? ": " : " "}</LineToken>
375
+ </span>
376
+ <span className={css.lineToken}>{member?.index === undefined ? ": " : " "}</span>
390
377
  {isEditing ? (
391
378
  // 带换行的值给多行输入(Enter 换行、Esc 撤销),其余是一行的官方输入框。
392
379
  multiline ? (
393
- <CompactTextField>
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
- </CompactTextField>
396
+ </span>
410
397
  ) : (
411
- <CompactInput>
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
- </CompactInput>
419
+ </span>
433
420
  )
434
421
  ) : null}
435
422
  {/* 编辑态只留输入框:原值不再在它旁边画一遍。 */}
436
423
  {isEditing || line.variantsStandIn ? null : (
437
- <ValueSlot
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
- </ValueSlot>
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
- <HoverActions data-role="actions" data-editing="true">
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
- </HoverActions>
471
+ </span>
480
472
  ) : null}
481
- <HoverActions data-role="actions">
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
- </HoverActions>
513
+ </span>
522
514
  </>
523
515
  );
524
516
  }
@@ -566,7 +558,8 @@ function VariantSelect({
566
558
  setOpen(false);
567
559
  }}
568
560
  anchor={
569
- <ValueTrigger
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
- <LineValue data-tone="empty">{current?.label ?? ""}</LineValue>
571
+ <span className={css.lineValue} data-tone="empty">
572
+ {current?.label ?? ""}
573
+ </span>
579
574
  <IconChevronDownOutlineRegular size={ICON_SIZE} />
580
- </ValueTrigger>
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
- <LineKey data-role="key" data-index={indexed ? "true" : undefined} title={key}>
600
+ <span
601
+ className={css.lineKey}
602
+ data-role="key"
603
+ data-index={indexed ? "true" : undefined}
604
+ title={key}
605
+ >
606
606
  {key}
607
- </LineKey>
608
- <LineToken>{indexed ? " " : ": "}</LineToken>
607
+ </span>
608
+ <span className={css.lineToken}>{indexed ? " " : ": "}</span>
609
609
  {/* 值本身是容器(对象/数组)的成员:它也要能移除,否则这一项删不掉。 */}
610
610
  {member === undefined ? null : (
611
- <HoverActions data-role="actions">
611
+ <span className={classes(css.lineActions, css.hoverActions)} data-role="actions">
612
612
  <RemoveLineButton member={member} face={face} t={t} disabled={disabled} />
613
- </HoverActions>
613
+ </span>
614
614
  )}
615
615
  </>
616
616
  );
@@ -713,7 +713,7 @@ function AddLine({
713
713
  setOpen(false);
714
714
  };
715
715
  return (
716
- <AddWrap data-add={spec.kind} data-invalid={invalid ? "true" : undefined}>
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
- <CompactInput>
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
- </CompactInput>
760
+ </span>
761
761
  }
762
762
  />
763
- {invalid ? <LineInvalid>{t("unknownProperty")}</LineInvalid> : null}
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
- <LineComment>{resolveText(matched[0].description)}</LineComment>
767
+ <span className={css.lineComment}>{resolveText(matched[0].description)}</span>
768
768
  </TruncatedTooltip>
769
769
  ) : null}
770
- </AddWrap>
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 { Hint } from "./styles.ts";
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) return <Hint role="status">{t("noSchema")}</Hint>;
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
- <Hint role="alert" data-violation="true">
60
+ <p className={css.hint} role="alert" data-violation="true">
56
61
  {t("notSaved", { message: state.violation.message })}
57
- </Hint>
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.#store.set(this.#project());
312
+ this.#sync();
310
313
  }
311
314
 
312
315
  // 释放订阅。
@@ -0,0 +1,3 @@
1
+ // 行内图标的边长:与 `schema-form.module.css` 里行高 / 折叠列同一档(14px)。组件用 `size={ICON_SIZE}`,
2
+ // 样式表用像素——两处同源,改就一起改。
3
+ export const ICON_SIZE = 14;
@@ -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";