@morlay/dsh-client-ui-primitives 0.0.4 → 0.0.6
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 +18 -266
- package/dist/client.cjs +1 -611
- package/dist/client.d.cts +37 -684
- package/dist/client.d.mts +37 -684
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{reference-Dxy9uQYz.mjs → reference-Cjcn21uW.mjs} +0 -1
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +2 -2
- package/src/client/index.ts +7 -9
- package/src/client/schema-form/Editor.tsx +25 -38
- package/src/client/schema-form/SchemaForm.tsx +6 -12
- package/src/client/schema-form/controller.ts +65 -123
- package/src/client/schema-form/draft.ts +55 -138
- package/src/client/schema-form/fields.tsx +5 -14
- package/src/client/schema-form/hints.ts +31 -131
- package/src/client/schema-form/index.ts +15 -20
- package/src/client/schema-form/labels.ts +7 -9
- package/src/client/schema-form/lines.ts +36 -60
- package/src/client/schema-form/locales.ts +6 -8
- package/src/client/schema-form/rows.ts +22 -41
- package/src/client/schema-form/schema-node.ts +87 -150
- package/src/client/schema-form/slot-contract.ts +55 -76
- package/src/client/schema-form/styles.ts +39 -51
- package/src/client/schema-form/testing/fake-describe.ts +3 -9
- package/src/client/schema-form/testing/fake-scope.ts +8 -10
- package/src/client/schema-form/value.tsx +14 -26
- package/src/client/settings-form/SettingsForm.tsx +13 -17
- package/src/client/settings-form/fields.tsx +25 -35
- package/src/client/settings-form/form-model.ts +63 -145
- package/src/client/styling/styled.tsx +3 -5
- package/src/client/theme.generated.ts +6 -7
- package/src/reference-markdown.tsx +1 -1
- package/src/reference.ts +1 -1
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* 每次保存都是 host 上一次带 revision 栅栏的持久写,所以控件**不直接写盘**:编辑先落在草稿上(屏幕上看到的
|
|
5
|
-
* 就是要保存的内容),`save()` 是唯一的写盘点,且先过一遍整段校验——schema 挡下的值不发请求。字段的「已覆盖」
|
|
6
|
-
* 由用户层的 presence 决定(覆盖值恰好等于默认值也是覆盖),不是值比较。
|
|
7
|
-
*
|
|
8
|
-
* 与渲染无关:控件读 `field(path)`、调 `set/setText/clear/appendItem/…`;文案与控件形状在 `fields/`。
|
|
9
|
-
*/
|
|
1
|
+
// 暂存式草稿模型:编辑先落草稿,`save()` 是唯一的写盘点(先过整段校验,schema 挡下的值不发请求)。
|
|
2
|
+
//
|
|
3
|
+
// 「已覆盖」由用户层 presence 决定(值恰好等于默认值也算覆盖);本模块与渲染无关,文案与控件形状在 `fields/`。
|
|
10
4
|
|
|
11
5
|
import type { SettingsPathOpView } from "@deepseek-ai/dsh-api-remotes/client";
|
|
12
6
|
import { createSnapshotStore, type SnapshotStore } from "@deepseek-ai/dsh-client-store";
|
|
@@ -14,37 +8,30 @@ import type { ConfigForm, ConfigFormSnapshot } from "@deepseek-ai/dsh-client-ui-
|
|
|
14
8
|
import type { SettingsFormShell } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
15
9
|
import { emptyValueOf, fieldsOf, readPath, seekNode, type FieldNode } from "./schema-node.ts";
|
|
16
10
|
|
|
17
|
-
|
|
11
|
+
// 命名空间段(一段配置)的值。
|
|
18
12
|
export type Section = Record<string, unknown>;
|
|
19
13
|
|
|
20
|
-
|
|
14
|
+
// 文本草稿的解析结果:控件把用户输入交给保存那一刻解析。
|
|
21
15
|
export type TextParseResult =
|
|
22
|
-
|
|
16
|
+
// 得到一个值。
|
|
23
17
|
| { kind: "value"; value: unknown }
|
|
24
|
-
|
|
18
|
+
// 这段文本不产生写(例如 secret 留空=保留已存的值)。
|
|
25
19
|
| { kind: "skip" }
|
|
26
|
-
|
|
20
|
+
// 不是这个字段接受的值:留在屏幕上并挡住保存。
|
|
27
21
|
| { kind: "invalid"; message: string };
|
|
28
22
|
|
|
29
|
-
|
|
23
|
+
// 控件给文本草稿的解析规则。
|
|
30
24
|
export type TextParse = (text: string) => TextParseResult;
|
|
31
25
|
|
|
32
|
-
|
|
26
|
+
// 整段校验失败:消息 + 它落在哪一层(页面把消息画在**出错的那一行**上)。
|
|
33
27
|
export interface ValidationFailure {
|
|
34
|
-
|
|
28
|
+
// 面向用户的消息(已去掉 schemastery 拼的 `$…` 位置前缀)。
|
|
35
29
|
message: string;
|
|
36
|
-
|
|
30
|
+
// 具体路径(段根起);空数组表示错误在整段上。
|
|
37
31
|
path: readonly string[];
|
|
38
32
|
}
|
|
39
33
|
|
|
40
|
-
|
|
41
|
-
* 把校验器抛出的错误收成一条失败。
|
|
42
|
-
*
|
|
43
|
-
* schemastery 的 `ValidationError` 把路径留在 `options.path` 上(消息里的 `$…` 前缀是给命令行看的),所以这里
|
|
44
|
-
* 取路径、去前缀——行内报错据此知道挂在哪一行。
|
|
45
|
-
* @param error - 校验器抛出的错误。
|
|
46
|
-
* @returns 消息与路径。
|
|
47
|
-
*/
|
|
34
|
+
// 把校验器抛出的错误收成一条失败:路径取 `options.path`,并去掉 schemastery 拼的 `$…` 位置前缀。
|
|
48
35
|
export function failureOf(error: unknown): ValidationFailure {
|
|
49
36
|
const raw = error instanceof Error ? error.message : String(error);
|
|
50
37
|
const options = (error as { options?: { path?: readonly (string | number | symbol)[] } }).options;
|
|
@@ -58,51 +45,49 @@ export function failureOf(error: unknown): ValidationFailure {
|
|
|
58
45
|
return { message: message === "" ? raw : message, path };
|
|
59
46
|
}
|
|
60
47
|
|
|
61
|
-
|
|
48
|
+
// 一字段的草稿。
|
|
62
49
|
type DraftEdit =
|
|
63
|
-
|
|
50
|
+
// 控件已经给出合法值(开关、选择器、数字步进、增删项)。
|
|
64
51
|
| { kind: "value"; value: unknown }
|
|
65
|
-
|
|
52
|
+
// 文本输入:`parse` 在保存时跑,解析失败挡住保存。
|
|
66
53
|
| { kind: "text"; text: string; parse: TextParse }
|
|
67
|
-
|
|
54
|
+
// 恢复默认:把字段交回组成层(用户层没有它时不算写)。
|
|
68
55
|
| { kind: "clear" }
|
|
69
|
-
|
|
56
|
+
// 移除:无条件 unset(数组项与字典键,host 语义是删掉这一项)。
|
|
70
57
|
| { kind: "drop" };
|
|
71
58
|
|
|
72
|
-
|
|
59
|
+
// 一字段渲染时要读的状态。
|
|
73
60
|
export interface DraftFieldState {
|
|
74
|
-
|
|
61
|
+
// 控件要显示的值:草稿优先,否则生效层。
|
|
75
62
|
value: unknown;
|
|
76
|
-
|
|
63
|
+
// 文本草稿(文本控件显示它而不是重新格式化值)。
|
|
77
64
|
text: string | undefined;
|
|
78
|
-
|
|
65
|
+
// 草稿不合法时的消息(控件显示,同时挡住保存)。
|
|
79
66
|
invalid: string | undefined;
|
|
80
|
-
|
|
67
|
+
// 保存后这一字段是否会留下用户层条目。
|
|
81
68
|
overridden: boolean;
|
|
82
|
-
|
|
69
|
+
// 这一字段在本页有还没保存的编辑(页面上给它一处高亮与一个「撤回」)。
|
|
83
70
|
staged: boolean;
|
|
84
71
|
}
|
|
85
72
|
|
|
86
|
-
|
|
73
|
+
// 模型要读要写的那个命名空间。
|
|
87
74
|
export type DraftScope = ConfigForm<Section>;
|
|
88
75
|
|
|
89
|
-
|
|
76
|
+
// 构造参数。
|
|
90
77
|
export interface SchemaDraftOptions {
|
|
91
78
|
scope: DraftScope;
|
|
92
|
-
|
|
79
|
+
// 段根的字段树(`projectNode` 的结果):增删项要按它取节点默认值。
|
|
93
80
|
root: FieldNode;
|
|
94
|
-
|
|
81
|
+
// 整段校验:返回失败(消息 + 位置),或 `undefined`。
|
|
95
82
|
validate: (value: Section) => ValidationFailure | undefined;
|
|
96
83
|
}
|
|
97
84
|
|
|
98
|
-
|
|
85
|
+
// 一条草稿编辑要写的 op(`undefined` 表示这条草稿不该产生写)。
|
|
99
86
|
interface PlannedWrite {
|
|
100
87
|
op: SettingsPathOpView | undefined;
|
|
101
88
|
}
|
|
102
89
|
|
|
103
|
-
|
|
104
|
-
* 一页配置的草稿。一个命名空间一个实例:它订阅共享配置表单,投影给渲染层读。
|
|
105
|
-
*/
|
|
90
|
+
// 一页配置的草稿。一个命名空间一个实例:它订阅共享配置表单,投影给渲染层读。
|
|
106
91
|
export class SchemaDraftModel {
|
|
107
92
|
readonly #scope: DraftScope;
|
|
108
93
|
#root: FieldNode;
|
|
@@ -115,9 +100,6 @@ export class SchemaDraftModel {
|
|
|
115
100
|
#failed = false;
|
|
116
101
|
#violation: ValidationFailure | undefined;
|
|
117
102
|
|
|
118
|
-
/**
|
|
119
|
-
* @param options - 本页的共享配置表单、字段树与整段校验。
|
|
120
|
-
*/
|
|
121
103
|
constructor(options: SchemaDraftOptions) {
|
|
122
104
|
this.#scope = options.scope;
|
|
123
105
|
this.#root = options.root;
|
|
@@ -127,22 +109,12 @@ export class SchemaDraftModel {
|
|
|
127
109
|
});
|
|
128
110
|
}
|
|
129
111
|
|
|
130
|
-
|
|
131
|
-
* 换一份字段树。
|
|
132
|
-
*
|
|
133
|
-
* 增删项要按它取节点默认值,而 schema 可能随 describe 变(行的 Config 改了)——所以控制器每次投影都同步一次,
|
|
134
|
-
* 否则加进来的项会取不到默认值。
|
|
135
|
-
* @param root - 段根的字段树。
|
|
136
|
-
*/
|
|
112
|
+
// 换一份字段树:schema 可能随 describe 变,控制器每次投影同步一次(增删项按它取节点默认值)。
|
|
137
113
|
setRoot(root: FieldNode): void {
|
|
138
114
|
this.#root = root;
|
|
139
115
|
}
|
|
140
116
|
|
|
141
|
-
|
|
142
|
-
* 观察草稿与读数的变化。
|
|
143
|
-
* @param listener - 每次投影都调一次的回调。
|
|
144
|
-
* @returns 取消订阅。
|
|
145
|
-
*/
|
|
117
|
+
// 观察草稿与读数的变化;返回取消订阅。
|
|
146
118
|
subscribe(listener: () => void): () => void {
|
|
147
119
|
this.#listeners.add(listener);
|
|
148
120
|
return () => {
|
|
@@ -150,11 +122,7 @@ export class SchemaDraftModel {
|
|
|
150
122
|
};
|
|
151
123
|
}
|
|
152
124
|
|
|
153
|
-
|
|
154
|
-
* 投影一份读数给渲染层。
|
|
155
|
-
* @param project - 用模型的当前读数造渲染要的状态。
|
|
156
|
-
* @returns 渲染层按选择器读的 store。
|
|
157
|
-
*/
|
|
125
|
+
// 投影一份读数给渲染层;返回渲染层按选择器读的 store。
|
|
158
126
|
bind<S>(project: () => S): SnapshotStore<S> {
|
|
159
127
|
const store = createSnapshotStore(project());
|
|
160
128
|
this.subscribe(() => {
|
|
@@ -163,10 +131,7 @@ export class SchemaDraftModel {
|
|
|
163
131
|
return store;
|
|
164
132
|
}
|
|
165
133
|
|
|
166
|
-
|
|
167
|
-
* 表单级状态(与上游 `SettingsForm` 的壳同形)。
|
|
168
|
-
* @returns 可用性、可写性、脏、非法、保存中、上次保存失败。
|
|
169
|
-
*/
|
|
134
|
+
// 表单级状态(与上游 `SettingsForm` 的壳同形):可用性、可写性、脏、非法、保存中、上次保存失败。
|
|
170
135
|
shell(): SettingsFormShell {
|
|
171
136
|
const { writes, blocked } = this.#plan();
|
|
172
137
|
return {
|
|
@@ -179,23 +144,12 @@ export class SchemaDraftModel {
|
|
|
179
144
|
};
|
|
180
145
|
}
|
|
181
146
|
|
|
182
|
-
|
|
183
|
-
* 保存前的整段校验(保存被 schema 挡下时非空)。
|
|
184
|
-
* @returns 失败消息与它的位置,或 `undefined`。
|
|
185
|
-
*/
|
|
147
|
+
// 保存前的整段校验(保存被 schema 挡下时非空)。
|
|
186
148
|
violation(): ValidationFailure | undefined {
|
|
187
149
|
return this.#violation;
|
|
188
150
|
}
|
|
189
151
|
|
|
190
|
-
|
|
191
|
-
* 读一个字段的草稿状态。
|
|
192
|
-
* @param path - 具体路径(动态段已按真实键或索引替换)。
|
|
193
|
-
* @param preview - 本轮已经算好的读数(`preview()` 的结果)。
|
|
194
|
-
*
|
|
195
|
-
* **容器的值要跟着别处的草稿走**:判别式 union 的选支就是容器的值,若这里读生效层,`type` 的切换控件会显示旧
|
|
196
|
-
* 的那一支(字段树却已经换了)。所以有 `preview` 就用它——控制器一次投影里只算一份。
|
|
197
|
-
* @returns 显示值、文本草稿、非法消息、是否覆盖。
|
|
198
|
-
*/
|
|
152
|
+
// 读一个字段的草稿状态:容器值要跟着别处的草稿走(判别式 union 的选支就是容器值),所以传了 `preview` 就用它。
|
|
199
153
|
field(path: readonly string[], preview?: Section): DraftFieldState {
|
|
200
154
|
const snapshot = this.#scope.getSnapshot();
|
|
201
155
|
const staged = this.#staged.get(pathKey(path));
|
|
@@ -247,37 +201,22 @@ export class SchemaDraftModel {
|
|
|
247
201
|
}
|
|
248
202
|
}
|
|
249
203
|
|
|
250
|
-
|
|
251
|
-
* 暂存一个合法值。
|
|
252
|
-
* @param path - 具体路径。
|
|
253
|
-
* @param value - 控件给出的值。
|
|
254
|
-
*/
|
|
204
|
+
// 暂存一个合法值。
|
|
255
205
|
set(path: readonly string[], value: unknown): void {
|
|
256
206
|
this.#stage(path, { kind: "value", value });
|
|
257
207
|
}
|
|
258
208
|
|
|
259
|
-
|
|
260
|
-
* 暂存一段文本,保存时才解析。
|
|
261
|
-
* @param path - 具体路径。
|
|
262
|
-
* @param text - 用户输入的原文。
|
|
263
|
-
* @param parse - 解析规则;失败时给出消息并挡住保存。
|
|
264
|
-
*/
|
|
209
|
+
// 暂存一段文本,保存时才解析(解析失败给消息并挡住保存)。
|
|
265
210
|
setText(path: readonly string[], text: string, parse: TextParse): void {
|
|
266
211
|
this.#stage(path, { kind: "text", text, parse });
|
|
267
212
|
}
|
|
268
213
|
|
|
269
|
-
|
|
270
|
-
* 暂存「恢复默认」。
|
|
271
|
-
* @param path - 具体路径。
|
|
272
|
-
*/
|
|
214
|
+
// 暂存「恢复默认」。
|
|
273
215
|
clear(path: readonly string[]): void {
|
|
274
216
|
this.#stage(path, { kind: "clear" });
|
|
275
217
|
}
|
|
276
218
|
|
|
277
|
-
|
|
278
|
-
* 追加一个数组项,值取该项节点的默认值。
|
|
279
|
-
* @param path - 数组字段的具体路径。
|
|
280
|
-
*/
|
|
219
|
+
// 追加一个数组项,值取该项节点的默认值。
|
|
281
220
|
appendItem(path: readonly string[]): void {
|
|
282
221
|
const node = seekNode(this.#root, path);
|
|
283
222
|
if (node?.type !== "array") return;
|
|
@@ -286,22 +225,12 @@ export class SchemaDraftModel {
|
|
|
286
225
|
this.set([...path, String(index)], emptyValueOf(node.item));
|
|
287
226
|
}
|
|
288
227
|
|
|
289
|
-
|
|
290
|
-
* 移除一个数组项。
|
|
291
|
-
* @param path - 数组字段的具体路径。
|
|
292
|
-
* @param index - 项在数组里的位置。
|
|
293
|
-
*/
|
|
228
|
+
// 移除一个数组项。
|
|
294
229
|
removeItem(path: readonly string[], index: number): void {
|
|
295
230
|
this.#stage([...path, String(index)], { kind: "drop" });
|
|
296
231
|
}
|
|
297
232
|
|
|
298
|
-
|
|
299
|
-
* 给一层加一项,值取它的默认值。
|
|
300
|
-
*
|
|
301
|
-
* 字典认任意键;对象只认 schema 声明过的字段(写一个没声明的键会被 host 挡下,所以这里直接不写)。
|
|
302
|
-
* @param path - 容器的具体路径。
|
|
303
|
-
* @param key - 要加的键。
|
|
304
|
-
*/
|
|
233
|
+
// 给一层加一项(值取它的默认值):字典认任意键,对象只认 schema 声明过的字段(没声明的键 host 会挡下,直接不写)。
|
|
305
234
|
addKey(path: readonly string[], key: string): void {
|
|
306
235
|
const node = seekNode(this.#root, path);
|
|
307
236
|
if (node === undefined) return;
|
|
@@ -314,19 +243,12 @@ export class SchemaDraftModel {
|
|
|
314
243
|
this.set([...path, key], emptyValueOf(field));
|
|
315
244
|
}
|
|
316
245
|
|
|
317
|
-
|
|
318
|
-
* 删一个字典键。
|
|
319
|
-
* @param path - 字典字段的具体路径。
|
|
320
|
-
* @param key - 要删的键。
|
|
321
|
-
*/
|
|
246
|
+
// 删一个字典键。
|
|
322
247
|
removeKey(path: readonly string[], key: string): void {
|
|
323
248
|
this.#stage([...path, key], { kind: "drop" });
|
|
324
249
|
}
|
|
325
250
|
|
|
326
|
-
|
|
327
|
-
* 撤销一个字段的草稿(回到它当前的生效值)——行内编辑取消时用。
|
|
328
|
-
* @param path - 具体路径。
|
|
329
|
-
*/
|
|
251
|
+
// 撤销一个字段的草稿(回到它当前的生效值)——行内编辑取消时用。
|
|
330
252
|
revert(path: readonly string[]): void {
|
|
331
253
|
if (!this.#staged.delete(pathKey(path))) return;
|
|
332
254
|
this.#failed = false;
|
|
@@ -334,7 +256,7 @@ export class SchemaDraftModel {
|
|
|
334
256
|
this.#publish();
|
|
335
257
|
}
|
|
336
258
|
|
|
337
|
-
|
|
259
|
+
// 丢弃全部草稿,回到 host 的读数。
|
|
338
260
|
discard(): void {
|
|
339
261
|
if (this.#staged.size === 0 && !this.#failed && this.#violation === undefined) return;
|
|
340
262
|
this.#staged.clear();
|
|
@@ -344,13 +266,8 @@ export class SchemaDraftModel {
|
|
|
344
266
|
this.#publish();
|
|
345
267
|
}
|
|
346
268
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
*
|
|
350
|
-
* host 是「值是否被接受」的唯一权威(有些约束 schema 表达不出来),所以落盘与否读回来决定,而不是在这里
|
|
351
|
-
* 预测;没落盘的保存保留草稿,让用户改而不是重打。
|
|
352
|
-
* @returns 写完与读回之后的收束。
|
|
353
|
-
*/
|
|
269
|
+
// 把全部草稿写成一次带 revision 栅栏的提交:落盘与否读回来决定(host 是值是否被接受的唯一权威),
|
|
270
|
+
// 没落盘的保存保留草稿让用户改,而不是在这里预测。
|
|
354
271
|
async save(): Promise<void> {
|
|
355
272
|
const snapshot = this.#scope.getSnapshot();
|
|
356
273
|
if (this.#saving || !snapshot.writable) return;
|
|
@@ -387,13 +304,13 @@ export class SchemaDraftModel {
|
|
|
387
304
|
}
|
|
388
305
|
}
|
|
389
306
|
|
|
390
|
-
|
|
307
|
+
// 释放对共享配置表单的订阅。
|
|
391
308
|
dispose(): void {
|
|
392
309
|
this.#unsubscribe();
|
|
393
310
|
this.#listeners.clear();
|
|
394
311
|
}
|
|
395
312
|
|
|
396
|
-
|
|
313
|
+
// 每条草稿这一轮会写什么;被 schema 挡下的草稿没有 op,但仍然是脏的。
|
|
397
314
|
#plan(): { writes: PlannedWrite[]; blocked: boolean } {
|
|
398
315
|
const snapshot = this.#scope.getSnapshot();
|
|
399
316
|
const writes: PlannedWrite[] = [];
|
|
@@ -423,7 +340,7 @@ export class SchemaDraftModel {
|
|
|
423
340
|
return { writes, blocked };
|
|
424
341
|
}
|
|
425
342
|
|
|
426
|
-
|
|
343
|
+
// 生效值套上本轮草稿后的段值:字段树按它展开(追加的数组项立刻出现),整段校验也看它。
|
|
427
344
|
preview(): Section {
|
|
428
345
|
const ops = this.#plan().writes.flatMap((item) => (item.op === undefined ? [] : [item.op]));
|
|
429
346
|
return applyOps(this.#scope.getSnapshot().value ?? {}, ops);
|
|
@@ -442,7 +359,7 @@ export class SchemaDraftModel {
|
|
|
442
359
|
}
|
|
443
360
|
}
|
|
444
361
|
|
|
445
|
-
|
|
362
|
+
// 深比较:值相等就不写(避免把「改回原值」也当成一次写)。
|
|
446
363
|
function sameValue(left: unknown, right: unknown): boolean {
|
|
447
364
|
if (Object.is(left, right)) return true;
|
|
448
365
|
if (typeof left !== "object" || typeof right !== "object" || left === null || right === null)
|
|
@@ -450,12 +367,12 @@ function sameValue(left: unknown, right: unknown): boolean {
|
|
|
450
367
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
451
368
|
}
|
|
452
369
|
|
|
453
|
-
|
|
370
|
+
// 路径的 map 键。
|
|
454
371
|
function pathKey(path: readonly string[]): string {
|
|
455
372
|
return JSON.stringify(path);
|
|
456
373
|
}
|
|
457
374
|
|
|
458
|
-
|
|
375
|
+
// 路径末段是否在用户层里存在(覆盖判据)。
|
|
459
376
|
function hasPath(root: unknown, path: readonly string[]): boolean {
|
|
460
377
|
if (path.length === 0) return root !== undefined;
|
|
461
378
|
const parent = readPath(root, path.slice(0, -1));
|
|
@@ -465,7 +382,7 @@ function hasPath(root: unknown, path: readonly string[]): boolean {
|
|
|
465
382
|
return leaf in parent;
|
|
466
383
|
}
|
|
467
384
|
|
|
468
|
-
|
|
385
|
+
// 把一组 op 套到一个段值上(本地读数用,不写 host)。
|
|
469
386
|
function applyOps(section: Section, ops: readonly SettingsPathOpView[]): Section {
|
|
470
387
|
const next = structuredClone(section);
|
|
471
388
|
for (const op of ops) {
|
|
@@ -483,5 +400,5 @@ function applyOps(section: Section, ops: readonly SettingsPathOpView[]): Section
|
|
|
483
400
|
return next;
|
|
484
401
|
}
|
|
485
402
|
|
|
486
|
-
|
|
403
|
+
// 一个新子节点的初值:字段树的读法在 `schema-node.ts`(变体切换也要它)。
|
|
487
404
|
export { emptyValueOf } from "./schema-node.ts";
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* 行式视图里值在行内点开编辑,编辑的文本交给草稿模型、保存那一刻才按这里的规则解析。
|
|
5
|
-
*/
|
|
1
|
+
// 字段默认值与文本解析:默认值就是行内值(`value.tsx`),这里只剩"什么文本算这个字段接受的值"的规则。
|
|
2
|
+
//
|
|
3
|
+
// 行式视图里值在行内点开编辑,编辑的文本交给草稿模型、保存那一刻才按这里的规则解析。
|
|
6
4
|
|
|
7
5
|
export {
|
|
8
6
|
InlineValue,
|
|
@@ -16,15 +14,8 @@ import type { TextParse } from "./draft.ts";
|
|
|
16
14
|
import type { FieldNode } from "./schema-node.ts";
|
|
17
15
|
import type { SchemaFormTranslate } from "./slot-contract.ts";
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*
|
|
22
|
-
* 解析不只看类型:schema 上声明的界限(`pattern` / `min` / `max` / `step`)与字面量集合都在这里说话——
|
|
23
|
-
* 用户敲完当场就知道对不对,而不是等保存时被整段校验退回。
|
|
24
|
-
* @param node - 字段节点(`meta` 是约束的来源)。
|
|
25
|
-
* @param t - 本包字典。
|
|
26
|
-
* @returns 这段文本的解析规则。
|
|
27
|
-
*/
|
|
17
|
+
// 各类型的文本解析规则(消息来自本包字典):schema 上声明的界限(`pattern` / `min` / `max` / `step`)与字面量集合
|
|
18
|
+
// 也在这里判,用户敲完当场就知道对不对,而不是等保存时被整段校验退回。
|
|
28
19
|
export function parseFor(node: FieldNode, t: SchemaFormTranslate): TextParse {
|
|
29
20
|
switch (node.type) {
|
|
30
21
|
case "number":
|