@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
@@ -0,0 +1,3730 @@
1
+ import { createSnapshotStore } from "@deepseek-ai/dsh-client-store";
2
+ import { Service } from "@deepseek-ai/cordis";
3
+ import { cloneElement, forwardRef, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
4
+ import { Button as Button$1, DisclosureRow as DisclosureRow$1, IconCheckOutlineRegular, IconChevronDownOutlineRegular, IconChevronRightOutlineRegular, IconCloseOutlineRegular, IconCopyOutlineRegular, IconRefreshOutlineRegular, IconTrashOutlineRegular, Input, MarkdownText, Menu, MenuItemButton, SettingsForm, Tooltip, rankByName } from "@deepseek-ai/dsh-client-ui-primitives";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { fromMarkdown } from "mdast-util-from-markdown";
7
+ import { gfmFromMarkdown } from "mdast-util-gfm";
8
+ import { asciiAlpha, asciiAlphanumeric, asciiDigit, markdownLineEnding, markdownLineEndingOrSpace, unicodePunctuation, unicodeWhitespace } from "micromark-util-character";
9
+ import { gfm } from "micromark-extension-gfm";
10
+ import { codes, types } from "micromark-util-symbol";
11
+ export * from "@deepseek-ai/dsh-client-ui-primitives";
12
+ //#region \0rolldown/runtime.js
13
+ var __defProp = Object.defineProperty;
14
+ var __exportAll = (all, no_symbols) => {
15
+ let target = {};
16
+ for (var name in all) __defProp(target, name, {
17
+ get: all[name],
18
+ enumerable: true
19
+ });
20
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
21
+ return target;
22
+ };
23
+ function emptyMeta() {
24
+ return {
25
+ description: void 0,
26
+ comment: void 0,
27
+ link: void 0,
28
+ role: void 0,
29
+ secret: false,
30
+ required: false,
31
+ disabled: false,
32
+ collapse: false,
33
+ badges: [],
34
+ pattern: void 0,
35
+ min: void 0,
36
+ max: void 0,
37
+ step: void 0,
38
+ hasDefault: false,
39
+ defaultValue: void 0,
40
+ extra: void 0
41
+ };
42
+ }
43
+ function badgesOf(meta) {
44
+ return (meta.badges ?? []).map((badge) => badge.text);
45
+ }
46
+ function metaOf(schema) {
47
+ const meta = schema.meta ?? {};
48
+ return {
49
+ description: meta.description,
50
+ comment: meta.comment,
51
+ link: meta.link,
52
+ role: meta.role,
53
+ secret: meta.role === "secret",
54
+ required: meta.required === true,
55
+ disabled: meta.disabled === true,
56
+ collapse: meta.collapse === true,
57
+ badges: badgesOf(meta),
58
+ pattern: typeof meta.pattern === "string" ? meta.pattern : meta.pattern?.source ?? void 0,
59
+ min: meta.min,
60
+ max: meta.max,
61
+ step: meta.step,
62
+ hasDefault: meta.default !== void 0,
63
+ defaultValue: meta.default,
64
+ extra: meta.extra
65
+ };
66
+ }
67
+ function mergeMeta(inner, outer) {
68
+ const merged = { ...inner };
69
+ for (const [key, value] of Object.entries(outer)) if (value !== void 0) merged[key] = value;
70
+ return merged;
71
+ }
72
+ function keyOf(path) {
73
+ return path[path.length - 1] ?? "";
74
+ }
75
+ function stringLeaf(path, meta) {
76
+ return {
77
+ key: keyOf(path),
78
+ path,
79
+ label: void 0,
80
+ meta,
81
+ readOnly: null,
82
+ type: "string"
83
+ };
84
+ }
85
+ function leafTypeOf(type) {
86
+ switch (type) {
87
+ case "string": return "string";
88
+ case "number": return "number";
89
+ case "boolean": return "boolean";
90
+ case "function": return "function";
91
+ case "never": return "never";
92
+ default: return "any";
93
+ }
94
+ }
95
+ function projectNode(schema, path = []) {
96
+ return project(schema, path, []);
97
+ }
98
+ function project(schema, path, ancestors) {
99
+ const base = {
100
+ key: keyOf(path),
101
+ path,
102
+ label: void 0,
103
+ meta: metaOf(schema),
104
+ readOnly: null
105
+ };
106
+ if (ancestors.includes(schema)) return {
107
+ ...base,
108
+ type: "recursive",
109
+ origin: schema.type
110
+ };
111
+ const chain = [...ancestors, schema];
112
+ switch (schema.type) {
113
+ case "object": {
114
+ const fields = Object.entries(schema.dict ?? {}).filter(([, child]) => child.meta?.hidden !== true).map(([key, child]) => project(child, [...path, key], chain));
115
+ return {
116
+ ...base,
117
+ type: "object",
118
+ fields
119
+ };
120
+ }
121
+ case "dict": {
122
+ const segment = [...path, "*"];
123
+ const keyNode = schema.sKey === void 0 ? stringLeaf(segment, emptyMeta()) : project(schema.sKey, segment, chain);
124
+ return {
125
+ ...base,
126
+ type: "dict",
127
+ keyNode,
128
+ valueNode: project(schema.inner ?? schema, segment, chain)
129
+ };
130
+ }
131
+ case "array": {
132
+ const item = project(schema.inner ?? schema, [...path, "*"], chain);
133
+ return {
134
+ ...base,
135
+ type: "array",
136
+ item,
137
+ mergeKey: mergeKeyOf(schema, item)
138
+ };
139
+ }
140
+ case "tuple": {
141
+ const items = (schema.list ?? []).map((child, index) => project(child, [...path, String(index)], chain));
142
+ return {
143
+ ...base,
144
+ type: "tuple",
145
+ items
146
+ };
147
+ }
148
+ case "union": {
149
+ const members = schema.list ?? [];
150
+ const variants = members.map((child) => project(child, path, chain));
151
+ const literals = members.every((child) => child.type === "const") ? members.map((child) => child.value) : void 0;
152
+ return {
153
+ ...base,
154
+ type: "union",
155
+ choices: literals,
156
+ variants,
157
+ tagKey: tagKeyOf(schema, variants)
158
+ };
159
+ }
160
+ case "intersect": return {
161
+ ...base,
162
+ type: "intersect",
163
+ members: (schema.list ?? []).map((child) => project(child, path, chain))
164
+ };
165
+ case "bitset": {
166
+ const bits = Object.entries(schema.bits ?? {}).map(([name, bit]) => ({
167
+ name,
168
+ bit
169
+ }));
170
+ return {
171
+ ...base,
172
+ type: "bitset",
173
+ bits
174
+ };
175
+ }
176
+ case "const": return {
177
+ ...base,
178
+ type: "const",
179
+ value: schema.value
180
+ };
181
+ case "transform": {
182
+ const projected = project(schema.inner ?? schema, path, chain);
183
+ return {
184
+ ...projected,
185
+ meta: mergeMeta(projected.meta, base.meta),
186
+ readOnly: "transform"
187
+ };
188
+ }
189
+ case "lazy": {
190
+ const inner = schema.inner;
191
+ return inner === void 0 ? {
192
+ ...base,
193
+ type: "any"
194
+ } : {
195
+ ...base,
196
+ type: "lazy",
197
+ inner: project(inner, path, chain)
198
+ };
199
+ }
200
+ case "is": return {
201
+ ...base,
202
+ type: "any",
203
+ readOnly: "constructor"
204
+ };
205
+ default: return {
206
+ ...base,
207
+ type: leafTypeOf(schema.type),
208
+ readOnly: schema.type === "function" ? "function" : null
209
+ };
210
+ }
211
+ }
212
+ function unwrapLazy(node) {
213
+ let current = node;
214
+ while (current?.type === "lazy") current = current.inner;
215
+ return current;
216
+ }
217
+ function fieldsOf(node) {
218
+ const current = unwrapLazy(node);
219
+ switch (current?.type) {
220
+ case "object": return current.fields;
221
+ case "union": return current.variants.flatMap((variant) => fieldsOf(variant));
222
+ case "intersect": return current.members.flatMap((member) => fieldsOf(member));
223
+ default: return [];
224
+ }
225
+ }
226
+ function seekNode(root, path) {
227
+ let current = root;
228
+ for (const segment of path) {
229
+ const node = unwrapLazy(current);
230
+ if (node === void 0) return void 0;
231
+ switch (node.type) {
232
+ case "object":
233
+ case "union":
234
+ case "intersect":
235
+ current = fieldsOf(node).find((field) => field.key === segment);
236
+ break;
237
+ case "dict":
238
+ current = node.valueNode;
239
+ break;
240
+ case "array":
241
+ current = node.item;
242
+ break;
243
+ case "tuple":
244
+ current = node.items[Number(segment)];
245
+ break;
246
+ default: return;
247
+ }
248
+ }
249
+ return unwrapLazy(current);
250
+ }
251
+ function walkFields(root, value) {
252
+ const out = [];
253
+ visit(root, root.path, value, out, true, void 0, /* @__PURE__ */ new Set(), void 0);
254
+ return out;
255
+ }
256
+ function visit(node, path, value, out, emit, label, emitted, member) {
257
+ const current = unwrapLazy(node);
258
+ if (current === void 0) return;
259
+ const positioned = {
260
+ ...current,
261
+ path,
262
+ ...member === void 0 ? {} : { key: member.key },
263
+ ...label === void 0 ? {} : { label }
264
+ };
265
+ const key = JSON.stringify(path);
266
+ if (emit && !emitted.has(key)) {
267
+ emitted.add(key);
268
+ out.push({
269
+ path,
270
+ node: positioned,
271
+ ...member === void 0 ? {} : { member }
272
+ });
273
+ }
274
+ switch (positioned.type) {
275
+ case "object":
276
+ for (const field of positioned.fields) {
277
+ const child = memberOf(value, field.key);
278
+ if (child === void 0 && field.meta.required !== true) continue;
279
+ visit(field, [...path, field.key], child, out, true, void 0, emitted, void 0);
280
+ }
281
+ return;
282
+ case "dict":
283
+ for (const [key, child] of entriesOf(value)) visit(positioned.valueNode, [...path, key], child, out, true, void 0, emitted, {
284
+ parent: path,
285
+ key,
286
+ index: void 0
287
+ });
288
+ return;
289
+ case "array":
290
+ for (const [key, child] of entriesOf(value)) {
291
+ const label = positioned.mergeKey === void 0 ? void 0 : memberLabel(child, positioned.mergeKey);
292
+ visit(positioned.item, [...path, key], child, out, true, label, emitted, {
293
+ parent: path,
294
+ key,
295
+ index: Number(key)
296
+ });
297
+ }
298
+ return;
299
+ case "tuple":
300
+ positioned.items.forEach((item, index) => {
301
+ visit(item, [...path, String(index)], memberOf(value, index), out, true, void 0, emitted, void 0);
302
+ });
303
+ return;
304
+ case "union": {
305
+ if (positioned.choices !== void 0) return;
306
+ const variant = pickVariant(positioned, value);
307
+ if (variant !== void 0) visit(variant, path, value, out, false, void 0, emitted, member);
308
+ return;
309
+ }
310
+ case "intersect":
311
+ for (const part of positioned.members) visit(part, path, value, out, false, void 0, emitted, member);
312
+ return;
313
+ default: return;
314
+ }
315
+ }
316
+ function mergeKeyOf(schema, item) {
317
+ const declared = declaredExtra(schema, "mergeKey");
318
+ if (declared !== void 0) return declared;
319
+ const current = unwrapLazy(item);
320
+ return current?.type === "object" && current.fields.some((field) => field.key === "id") ? "id" : void 0;
321
+ }
322
+ function tagKeyOf(schema, variants) {
323
+ const declared = declaredExtra(schema, "tag");
324
+ if (declared !== void 0) return declared;
325
+ const members = variants.map((variant) => unwrapLazy(variant));
326
+ if (members.length === 0 || members.some((member) => member?.type !== "object")) return void 0;
327
+ const objects = members;
328
+ const candidates = (objects[0]?.fields ?? []).map((field) => unwrapLazy(field)).filter((field) => field?.type === "const").map((field) => field.key).filter((key) => objects.every((object) => unwrapLazy(object.fields.find((field) => field.key === key))?.type === "const"));
329
+ return candidates.length === 1 ? candidates[0] : void 0;
330
+ }
331
+ function declaredExtra(schema, name) {
332
+ const extra = schema.meta?.extra;
333
+ if (typeof extra !== "object" || extra === null) return void 0;
334
+ const value = Reflect.get(extra, name);
335
+ return typeof value === "string" && value.length > 0 ? value : void 0;
336
+ }
337
+ function memberLabel(value, mergeKey) {
338
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
339
+ const member = Reflect.get(value, mergeKey);
340
+ if (typeof member === "string") return member;
341
+ if (typeof member === "number" && Number.isFinite(member)) return String(member);
342
+ }
343
+ function mergeKeyConflict(root, value) {
344
+ return scanConflict(root, root.path, value);
345
+ }
346
+ function scanConflict(node, path, value) {
347
+ const current = unwrapLazy(node);
348
+ if (current === void 0) return void 0;
349
+ switch (current.type) {
350
+ case "object":
351
+ for (const field of current.fields) {
352
+ const conflict = scanConflict(field, [...path, field.key], memberOf(value, field.key));
353
+ if (conflict !== void 0) return conflict;
354
+ }
355
+ return;
356
+ case "dict":
357
+ for (const [key, child] of entriesOf(value)) {
358
+ const conflict = scanConflict(current.valueNode, [...path, key], child);
359
+ if (conflict !== void 0) return conflict;
360
+ }
361
+ return;
362
+ case "array": {
363
+ const names = /* @__PURE__ */ new Set();
364
+ for (const [key, child] of entriesOf(value)) {
365
+ const itemPath = [...path, key];
366
+ if (current.mergeKey !== void 0) {
367
+ const label = memberLabel(child, current.mergeKey);
368
+ if (label === void 0 || label.trim() === "") return {
369
+ kind: "missing",
370
+ path: itemPath,
371
+ mergeKey: current.mergeKey,
372
+ value: ""
373
+ };
374
+ if (names.has(label)) return {
375
+ kind: "duplicate",
376
+ path: itemPath,
377
+ mergeKey: current.mergeKey,
378
+ value: label
379
+ };
380
+ names.add(label);
381
+ }
382
+ const conflict = scanConflict(current.item, itemPath, child);
383
+ if (conflict !== void 0) return conflict;
384
+ }
385
+ return;
386
+ }
387
+ case "tuple":
388
+ for (const [index, item] of current.items.entries()) {
389
+ const conflict = scanConflict(item, [...path, String(index)], memberOf(value, index));
390
+ if (conflict !== void 0) return conflict;
391
+ }
392
+ return;
393
+ case "union": {
394
+ if (current.choices !== void 0) return void 0;
395
+ const variant = pickVariant(current, value);
396
+ return variant === void 0 ? void 0 : scanConflict(variant, path, value);
397
+ }
398
+ case "intersect":
399
+ for (const member of current.members) {
400
+ const conflict = scanConflict(member, path, value);
401
+ if (conflict !== void 0) return conflict;
402
+ }
403
+ return;
404
+ default: return;
405
+ }
406
+ }
407
+ function entriesOf(value) {
408
+ if (Array.isArray(value)) return value.map((item, index) => [String(index), item]);
409
+ if (typeof value === "object" && value !== null) return Object.entries(value);
410
+ return [];
411
+ }
412
+ function memberOf(value, key) {
413
+ if (Array.isArray(value)) return value[Number(key)];
414
+ if (typeof value === "object" && value !== null) return value[String(key)];
415
+ }
416
+ function unionOf(node) {
417
+ const current = unwrapLazy(node);
418
+ return current?.type === "union" ? current : void 0;
419
+ }
420
+ function variantOf(node, value) {
421
+ const union = unionOf(node);
422
+ if (union === void 0) return unwrapLazy(node) ?? node;
423
+ return pickVariant(union, value) ?? union;
424
+ }
425
+ function tagValueOf(variant, tagKey) {
426
+ const current = unwrapLazy(variant);
427
+ if (current?.type !== "object" && current?.type !== "intersect") return {
428
+ found: false,
429
+ value: void 0
430
+ };
431
+ for (const field of fieldsOf(current)) {
432
+ if (field.key !== tagKey) continue;
433
+ const candidate = unwrapLazy(field);
434
+ if (candidate?.type === "const") return {
435
+ found: true,
436
+ value: candidate.value
437
+ };
438
+ }
439
+ return {
440
+ found: false,
441
+ value: void 0
442
+ };
443
+ }
444
+ function variantLabel(variant, tag) {
445
+ if (tag.found) return JSON.stringify(tag.value);
446
+ switch (unwrapLazy(variant)?.type) {
447
+ case "string": return "\"\"";
448
+ case "number": return "0";
449
+ case "boolean": return "true";
450
+ case "array":
451
+ case "tuple": return "[ ]";
452
+ case "object":
453
+ case "dict":
454
+ case "intersect": return "{ }";
455
+ default: return unwrapLazy(variant)?.type ?? "any";
456
+ }
457
+ }
458
+ function variantChoices(union) {
459
+ return union.variants.map((variant) => {
460
+ const tag = union.tagKey === void 0 ? {
461
+ found: false,
462
+ value: void 0
463
+ } : tagValueOf(variant, union.tagKey);
464
+ return {
465
+ label: variantLabel(variant, tag),
466
+ value: tag.found ? tag.value : emptyValueOf(variant)
467
+ };
468
+ });
469
+ }
470
+ function readPath(root, path) {
471
+ return path.reduce((node, segment) => {
472
+ if (Array.isArray(node)) return node[Number(segment)];
473
+ if (typeof node !== "object" || node === null) return void 0;
474
+ return node[segment];
475
+ }, root);
476
+ }
477
+ function isBlankDefault(node) {
478
+ const value = node.meta.defaultValue;
479
+ if (value === null) return true;
480
+ if (node.type !== "object" && node.type !== "intersect") return false;
481
+ return typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0;
482
+ }
483
+ function emptyValueOf(node) {
484
+ if (node.meta.hasDefault && !isBlankDefault(node)) return structuredClone(node.meta.defaultValue);
485
+ switch (node.type) {
486
+ case "array": return [];
487
+ case "tuple": return node.items.map((item) => emptyValueOf(item));
488
+ case "dict": return {};
489
+ case "object":
490
+ case "intersect": return Object.fromEntries(fieldsOf(node).map((field) => [field.key, emptyValueOf(field)]));
491
+ case "const": return node.value;
492
+ case "bitset": return 0;
493
+ case "lazy": return emptyValueOf(node.inner);
494
+ default: return null;
495
+ }
496
+ }
497
+ function pickVariant(node, value) {
498
+ if (node.tagKey !== void 0 && typeof value === "object" && value !== null && !Array.isArray(value)) {
499
+ const tagValue = Reflect.get(value, node.tagKey);
500
+ for (const variant of node.variants) {
501
+ const current = unwrapLazy(variant);
502
+ if (current?.type !== "object") continue;
503
+ const field = unwrapLazy(current.fields.find((candidate) => candidate.key === node.tagKey));
504
+ if (field?.type === "const" && field.value === tagValue) return variant;
505
+ }
506
+ }
507
+ for (const variant of node.variants) {
508
+ const current = unwrapLazy(variant);
509
+ if (current?.type === "string" && typeof value === "string") return variant;
510
+ if (current?.type === "number" && typeof value === "number") return variant;
511
+ if (current?.type === "boolean" && typeof value === "boolean") return variant;
512
+ if (current?.type === "array" && Array.isArray(value)) return variant;
513
+ }
514
+ return node.variants[0];
515
+ }
516
+ //#endregion
517
+ //#region src/client/schema-form/draft.ts
518
+ function failureOf(error) {
519
+ const raw = error instanceof Error ? error.message : String(error);
520
+ const path = (error.options?.path ?? []).filter((segment) => typeof segment === "string" || typeof segment === "number").map(String);
521
+ const message = raw.replace(/^\$\S*\s/, "").trim();
522
+ return {
523
+ message: message === "" ? raw : message,
524
+ path
525
+ };
526
+ }
527
+ var SchemaDraftModel = class {
528
+ #scope;
529
+ #root;
530
+ #validate;
531
+ #staged = /* @__PURE__ */ new Map();
532
+ #listeners = /* @__PURE__ */ new Set();
533
+ #unsubscribe;
534
+ #baseline;
535
+ #saving = false;
536
+ #failed = false;
537
+ #violation;
538
+ constructor(options) {
539
+ this.#scope = options.scope;
540
+ this.#root = options.root;
541
+ this.#validate = options.validate;
542
+ this.#unsubscribe = this.#scope.subscribe(() => {
543
+ this.#publish();
544
+ });
545
+ }
546
+ setRoot(root) {
547
+ this.#root = root;
548
+ }
549
+ subscribe(listener) {
550
+ this.#listeners.add(listener);
551
+ return () => {
552
+ this.#listeners.delete(listener);
553
+ };
554
+ }
555
+ bind(project) {
556
+ const store = createSnapshotStore(project());
557
+ this.subscribe(() => {
558
+ store.set(project());
559
+ });
560
+ return store;
561
+ }
562
+ shell() {
563
+ const { writes, blocked } = this.#plan();
564
+ return {
565
+ available: this.#scope.getSnapshot().status === "ready",
566
+ writable: this.#scope.getSnapshot().writable,
567
+ dirty: writes.some((item) => item.op !== void 0) || blocked,
568
+ invalid: blocked || this.#violation !== void 0,
569
+ saving: this.#saving,
570
+ failed: this.#failed
571
+ };
572
+ }
573
+ violation() {
574
+ return this.#violation;
575
+ }
576
+ field(path, preview) {
577
+ const snapshot = this.#scope.getSnapshot();
578
+ const staged = this.#staged.get(pathKey(path));
579
+ const stored = hasPath(snapshot.user, path);
580
+ if (staged === void 0) return {
581
+ value: readPath(preview ?? snapshot.value, path),
582
+ text: void 0,
583
+ invalid: void 0,
584
+ overridden: stored,
585
+ staged: false
586
+ };
587
+ switch (staged.edit.kind) {
588
+ case "value": return {
589
+ value: staged.edit.value,
590
+ text: void 0,
591
+ invalid: void 0,
592
+ overridden: true,
593
+ staged: true
594
+ };
595
+ case "text": {
596
+ const parsed = staged.edit.parse(staged.edit.text);
597
+ return {
598
+ value: parsed.kind === "value" ? parsed.value : readPath(snapshot.value, path),
599
+ text: staged.edit.text,
600
+ invalid: parsed.kind === "invalid" ? parsed.message : void 0,
601
+ overridden: true,
602
+ staged: true
603
+ };
604
+ }
605
+ case "clear": return {
606
+ value: readPath(snapshot.base, path),
607
+ text: void 0,
608
+ invalid: void 0,
609
+ overridden: false,
610
+ staged: true
611
+ };
612
+ case "drop": return {
613
+ value: void 0,
614
+ text: void 0,
615
+ invalid: void 0,
616
+ overridden: false,
617
+ staged: true
618
+ };
619
+ }
620
+ }
621
+ set(path, value) {
622
+ this.#stage(path, {
623
+ kind: "value",
624
+ value
625
+ });
626
+ }
627
+ setText(path, text, parse) {
628
+ this.#stage(path, {
629
+ kind: "text",
630
+ text,
631
+ parse
632
+ });
633
+ }
634
+ clear(path) {
635
+ this.#stage(path, { kind: "clear" });
636
+ }
637
+ appendItem(path) {
638
+ const node = seekNode(this.#root, path);
639
+ if (node?.type !== "array") return;
640
+ const current = readPath(this.preview(), path);
641
+ const index = Array.isArray(current) ? current.length : 0;
642
+ this.set([...path, String(index)], emptyValueOf(node.item));
643
+ }
644
+ removeItem(path, index) {
645
+ this.#stage([...path, String(index)], { kind: "drop" });
646
+ }
647
+ addKey(path, key) {
648
+ const node = seekNode(this.#root, path);
649
+ if (node === void 0) return;
650
+ if (node.type === "dict") {
651
+ this.set([...path, key], emptyValueOf(node.valueNode));
652
+ return;
653
+ }
654
+ const field = fieldsOf(node).find((candidate) => candidate.key === key);
655
+ if (field === void 0) return;
656
+ this.set([...path, key], emptyValueOf(field));
657
+ }
658
+ removeKey(path, key) {
659
+ this.#stage([...path, key], { kind: "drop" });
660
+ }
661
+ revert(path) {
662
+ if (!this.#staged.delete(pathKey(path))) return;
663
+ this.#failed = false;
664
+ this.#violation = void 0;
665
+ this.#publish();
666
+ }
667
+ discard() {
668
+ if (this.#staged.size === 0 && !this.#failed && this.#violation === void 0) return;
669
+ this.#staged.clear();
670
+ this.#baseline = void 0;
671
+ this.#failed = false;
672
+ this.#violation = void 0;
673
+ this.#publish();
674
+ }
675
+ async save() {
676
+ const snapshot = this.#scope.getSnapshot();
677
+ if (this.#saving || !snapshot.writable) return;
678
+ const { writes, blocked } = this.#plan();
679
+ if (blocked) return;
680
+ const ops = writes.flatMap((item) => item.op === void 0 ? [] : [item.op]);
681
+ if (ops.length === 0) {
682
+ this.#violation = void 0;
683
+ this.#publish();
684
+ return;
685
+ }
686
+ const failure = this.#validate(applyOps(snapshot.value ?? {}, ops));
687
+ if (failure !== void 0) {
688
+ this.#violation = failure;
689
+ this.#publish();
690
+ return;
691
+ }
692
+ this.#violation = void 0;
693
+ this.#saving = true;
694
+ this.#failed = false;
695
+ this.#publish();
696
+ try {
697
+ const landed = await this.#scope.mutate(ops, this.#baseline?.revision);
698
+ if (landed) {
699
+ this.#staged.clear();
700
+ this.#baseline = void 0;
701
+ }
702
+ this.#failed = !landed;
703
+ } catch {
704
+ this.#failed = true;
705
+ } finally {
706
+ this.#saving = false;
707
+ this.#publish();
708
+ }
709
+ }
710
+ dispose() {
711
+ this.#unsubscribe();
712
+ this.#listeners.clear();
713
+ }
714
+ #plan() {
715
+ const snapshot = this.#scope.getSnapshot();
716
+ const writes = [];
717
+ let blocked = false;
718
+ for (const { path, edit } of this.#staged.values()) {
719
+ if (edit.kind === "drop") {
720
+ writes.push({ op: {
721
+ op: "unset",
722
+ path: [...path]
723
+ } });
724
+ continue;
725
+ }
726
+ if (edit.kind === "clear") {
727
+ if (hasPath(snapshot.user, path)) writes.push({ op: {
728
+ op: "unset",
729
+ path: [...path]
730
+ } });
731
+ continue;
732
+ }
733
+ const parsed = edit.kind === "value" ? {
734
+ kind: "value",
735
+ value: edit.value
736
+ } : edit.parse(edit.text);
737
+ if (parsed.kind === "invalid") {
738
+ blocked = true;
739
+ continue;
740
+ }
741
+ if (parsed.kind === "skip") continue;
742
+ if (sameValue$1(readPath(snapshot.value, path), parsed.value)) continue;
743
+ writes.push({ op: {
744
+ op: "set",
745
+ path: [...path],
746
+ value: parsed.value
747
+ } });
748
+ }
749
+ return {
750
+ writes,
751
+ blocked
752
+ };
753
+ }
754
+ preview() {
755
+ const ops = this.#plan().writes.flatMap((item) => item.op === void 0 ? [] : [item.op]);
756
+ return applyOps(this.#scope.getSnapshot().value ?? {}, ops);
757
+ }
758
+ #stage(path, edit) {
759
+ this.#baseline ??= this.#scope.getSnapshot();
760
+ this.#staged.set(pathKey(path), {
761
+ path: [...path],
762
+ edit
763
+ });
764
+ this.#failed = false;
765
+ this.#violation = void 0;
766
+ this.#publish();
767
+ }
768
+ #publish() {
769
+ for (const listener of this.#listeners) listener();
770
+ }
771
+ };
772
+ function sameValue$1(left, right) {
773
+ if (Object.is(left, right)) return true;
774
+ if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) return false;
775
+ return JSON.stringify(left) === JSON.stringify(right);
776
+ }
777
+ function pathKey(path) {
778
+ return JSON.stringify(path);
779
+ }
780
+ function hasPath(root, path) {
781
+ if (path.length === 0) return root !== void 0;
782
+ const parent = readPath(root, path.slice(0, -1));
783
+ const leaf = path[path.length - 1] ?? "";
784
+ if (Array.isArray(parent)) return Number(leaf) < parent.length;
785
+ if (typeof parent !== "object" || parent === null) return false;
786
+ return leaf in parent;
787
+ }
788
+ function applyOps(section, ops) {
789
+ const next = structuredClone(section);
790
+ for (const op of ops) {
791
+ const parent = readPath(next, op.path.slice(0, -1));
792
+ const leaf = op.path[op.path.length - 1] ?? "";
793
+ if (Array.isArray(parent)) {
794
+ if (op.op === "set") parent[Number(leaf)] = op.value;
795
+ else parent.splice(Number(leaf), 1);
796
+ continue;
797
+ }
798
+ if (typeof parent !== "object" || parent === null) continue;
799
+ if (op.op === "set") parent[leaf] = op.value;
800
+ else Reflect.deleteProperty(parent, leaf);
801
+ }
802
+ return next;
803
+ }
804
+ //#endregion
805
+ //#region src/client/schema-form/controller.ts
806
+ function declaredSource(node) {
807
+ const extra = node?.meta.extra;
808
+ if (typeof extra !== "object" || extra === null) return void 0;
809
+ const name = Reflect.get(extra, "source");
810
+ return typeof name === "string" && name.length > 0 ? name : void 0;
811
+ }
812
+ function fieldKey(path) {
813
+ return JSON.stringify(path);
814
+ }
815
+ function projectRoot(serialized, rehydrate) {
816
+ try {
817
+ const schema = rehydrate(serialized);
818
+ const root = projectNode(schema);
819
+ if (root.type === "object" || root.type === "intersect") return {
820
+ schema,
821
+ root
822
+ };
823
+ if (root.type === "union" && root.tagKey !== void 0 && root.choices === void 0) return {
824
+ schema,
825
+ root
826
+ };
827
+ return;
828
+ } catch {
829
+ return;
830
+ }
831
+ }
832
+ function canRender(view, rehydrate) {
833
+ return view !== void 0 && projectRoot(view.schema, rehydrate) !== void 0;
834
+ }
835
+ const NO_FIELDS = {
836
+ key: "",
837
+ path: [],
838
+ label: void 0,
839
+ meta: emptyMeta(),
840
+ readOnly: null,
841
+ type: "object",
842
+ fields: []
843
+ };
844
+ function keysOf(value) {
845
+ if (Array.isArray(value)) return value.map((_item, index) => String(index));
846
+ if (typeof value === "object" && value !== null) return Object.keys(value);
847
+ return [];
848
+ }
849
+ function addableAt(node, path, value, hints) {
850
+ const current = variantOf(node, value);
851
+ if (current.type === "dict") {
852
+ const present = new Set(keysOf(value));
853
+ return (hints?.keysFor(path) ?? []).flatMap((key) => present.has(key) ? [] : [{
854
+ key,
855
+ description: void 0
856
+ }]);
857
+ }
858
+ if (current.type !== "object" && current.type !== "intersect") return [];
859
+ return fieldsOf(current).flatMap((field) => field.meta.required !== true && readPath(value, [field.key]) === void 0 ? [{
860
+ key: field.key,
861
+ description: field.meta.description ?? field.meta.comment
862
+ }] : []);
863
+ }
864
+ function optionsFor(node, path, value, hints) {
865
+ const current = unwrapLazy(node);
866
+ if (current?.type === "union" && current.choices !== void 0) return current.choices.map((choice) => ({ value: choice }));
867
+ const source = declaredSource(current);
868
+ const spec = source === void 0 ? hints?.selectFor?.(path) : hints?.sourceFor?.(source);
869
+ if (spec === void 0) return void 0;
870
+ const parent = path.slice(0, -1);
871
+ const options = spec.options((relative) => readPath(value, [...parent, ...relative]));
872
+ return options.length === 0 ? void 0 : options;
873
+ }
874
+ var SchemaFormController = class {
875
+ #ns;
876
+ #deps;
877
+ #model;
878
+ #store;
879
+ #disposers = [];
880
+ #view;
881
+ #schema;
882
+ #root;
883
+ constructor(ns, deps) {
884
+ this.#ns = ns;
885
+ this.#deps = deps;
886
+ this.#model = new SchemaDraftModel({
887
+ scope: deps.form,
888
+ root: NO_FIELDS,
889
+ validate: (value) => this.#validate(deps, value)
890
+ });
891
+ this.#store = createSnapshotStore(this.#project());
892
+ this.#disposers.push(this.#model.subscribe(() => {
893
+ this.#store.set(this.#project());
894
+ }));
895
+ this.#disposers.push(deps.describe.subscribe(() => {
896
+ this.#sync();
897
+ }));
898
+ deps.describe.ensure();
899
+ this.#sync();
900
+ }
901
+ face() {
902
+ return {
903
+ hooks: { schemaForm: this.#store },
904
+ set: (path, value) => {
905
+ this.#model.set(path, value);
906
+ },
907
+ setText: (path, text, parse) => {
908
+ this.#model.setText(path, text, parse);
909
+ },
910
+ clear: (path) => {
911
+ this.#model.clear(path);
912
+ },
913
+ appendItem: (path) => {
914
+ this.#model.appendItem(path);
915
+ },
916
+ removeItem: (path, index) => {
917
+ this.#model.removeItem(path, index);
918
+ },
919
+ addKey: (path, key) => {
920
+ this.#model.addKey(path, key);
921
+ },
922
+ removeKey: (path, key) => {
923
+ this.#model.removeKey(path, key);
924
+ },
925
+ save: () => {
926
+ this.#model.save();
927
+ },
928
+ revert: (path) => {
929
+ this.#model.revert(path);
930
+ },
931
+ discard: () => {
932
+ this.#model.discard();
933
+ }
934
+ };
935
+ }
936
+ namespace() {
937
+ return this.#ns;
938
+ }
939
+ refresh() {
940
+ this.#sync();
941
+ }
942
+ dispose() {
943
+ for (const dispose of this.#disposers.splice(0)) dispose();
944
+ this.#model.dispose();
945
+ }
946
+ #sync() {
947
+ const view = this.#deps.describe.getSnapshot().view?.namespaces.find((row) => row.ns === this.#ns);
948
+ this.#view = view;
949
+ const projected = view === void 0 ? void 0 : projectRoot(view.schema, this.#deps.rehydrate);
950
+ this.#schema = projected?.schema;
951
+ this.#root = projected?.root;
952
+ this.#model.setRoot(projected?.root ?? NO_FIELDS);
953
+ this.#store.set(this.#project());
954
+ }
955
+ #validate(deps, value) {
956
+ if (this.#schema !== void 0) {
957
+ const failure = deps.validate(this.#schema, value);
958
+ if (failure !== void 0) return failure;
959
+ }
960
+ if (this.#root === void 0) return void 0;
961
+ const conflict = mergeKeyConflict(this.#root, value);
962
+ if (conflict === void 0) return void 0;
963
+ return {
964
+ message: conflict.kind === "duplicate" ? deps.t("duplicateItem", {
965
+ key: conflict.mergeKey,
966
+ value: conflict.value
967
+ }) : deps.t("missingItem", { key: conflict.mergeKey }),
968
+ path: conflict.path
969
+ };
970
+ }
971
+ #project() {
972
+ const fields = /* @__PURE__ */ new Map();
973
+ const root = this.#root;
974
+ const preview = this.#model.preview();
975
+ const walked = root === void 0 ? [] : walkFields(root, preview);
976
+ for (const item of walked) fields.set(fieldKey(item.path), this.#model.field(item.path, preview));
977
+ const secrets = /* @__PURE__ */ new Map();
978
+ for (const secret of this.#view?.secrets ?? []) secrets.set(fieldKey(secret.path), secret.set);
979
+ const texts = /* @__PURE__ */ new Map();
980
+ const options = /* @__PURE__ */ new Map();
981
+ const addable = /* @__PURE__ */ new Map();
982
+ for (const item of walked) {
983
+ const text = this.#deps.hints?.textFor(item.path);
984
+ if (text !== void 0) texts.set(fieldKey(item.path), text);
985
+ const candidates = optionsFor(item.node, item.path, preview, this.#deps.hints);
986
+ if (candidates !== void 0) options.set(fieldKey(item.path), candidates);
987
+ const addableHere = addableAt(item.node, item.path, readPath(preview, item.path), this.#deps.hints);
988
+ if (addableHere.length > 0) addable.set(fieldKey(item.path), addableHere);
989
+ }
990
+ const violation = this.#model.violation();
991
+ const invalidAt = /* @__PURE__ */ new Map();
992
+ if (violation !== void 0 && violation.path.length > 0) invalidAt.set(fieldKey(violation.path), violation.message);
993
+ return {
994
+ ...this.#model.shell(),
995
+ configured: root !== void 0,
996
+ root: root ?? NO_FIELDS,
997
+ walked,
998
+ fields,
999
+ secrets,
1000
+ texts,
1001
+ options,
1002
+ addable,
1003
+ violation,
1004
+ invalidAt
1005
+ };
1006
+ }
1007
+ };
1008
+ //#endregion
1009
+ //#region src/client/schema-form/hints.ts
1010
+ var SchemaFormHints = class extends Service {
1011
+ #readers = /* @__PURE__ */ new Map();
1012
+ #texts = /* @__PURE__ */ new Map();
1013
+ #selects = /* @__PURE__ */ new Map();
1014
+ #sources = /* @__PURE__ */ new Map();
1015
+ #listeners = /* @__PURE__ */ new Set();
1016
+ constructor(ctx) {
1017
+ super(ctx, "schemaFormHints");
1018
+ }
1019
+ keysFor(ns, path) {
1020
+ return lookup(this.#readers, ns, path)?.() ?? [];
1021
+ }
1022
+ textFor(ns, path) {
1023
+ return lookup(this.#texts, ns, path)?.() ?? {};
1024
+ }
1025
+ select(ns, path, spec) {
1026
+ const key = locationKey(ns, path);
1027
+ this.#selects.set(key, spec);
1028
+ this.#publish();
1029
+ return () => {
1030
+ if (this.#selects.get(key) !== spec) return;
1031
+ this.#selects.delete(key);
1032
+ this.#publish();
1033
+ };
1034
+ }
1035
+ selectFor(ns, path) {
1036
+ return lookup(this.#selects, ns, path);
1037
+ }
1038
+ source(name, spec) {
1039
+ this.#sources.set(name, spec);
1040
+ this.#publish();
1041
+ return () => {
1042
+ if (this.#sources.get(name) !== spec) return;
1043
+ this.#sources.delete(name);
1044
+ this.#publish();
1045
+ };
1046
+ }
1047
+ sourceFor(name) {
1048
+ return this.#sources.get(name);
1049
+ }
1050
+ describe(ns, path, read) {
1051
+ const key = locationKey(ns, path);
1052
+ this.#texts.set(key, read);
1053
+ this.#publish();
1054
+ return () => {
1055
+ if (this.#texts.get(key) !== read) return;
1056
+ this.#texts.delete(key);
1057
+ this.#publish();
1058
+ };
1059
+ }
1060
+ suggestKeys(ns, path, read) {
1061
+ const key = locationKey(ns, path);
1062
+ this.#readers.set(key, read);
1063
+ this.#publish();
1064
+ return () => {
1065
+ if (this.#readers.get(key) !== read) return;
1066
+ this.#readers.delete(key);
1067
+ this.#publish();
1068
+ };
1069
+ }
1070
+ subscribe(listener) {
1071
+ this.#listeners.add(listener);
1072
+ return () => {
1073
+ this.#listeners.delete(listener);
1074
+ };
1075
+ }
1076
+ refresh() {
1077
+ this.#publish();
1078
+ }
1079
+ #publish() {
1080
+ for (const listener of this.#listeners) listener();
1081
+ }
1082
+ };
1083
+ function locationKey(ns, path) {
1084
+ return `${ns}\u0000${path.join("\0")}`;
1085
+ }
1086
+ function lookup(map, ns, path) {
1087
+ const exact = map.get(locationKey(ns, path));
1088
+ if (exact !== void 0) return exact;
1089
+ for (const masked of templates(path)) {
1090
+ const hit = map.get(locationKey(ns, masked));
1091
+ if (hit !== void 0) return hit;
1092
+ }
1093
+ }
1094
+ function* templates(path) {
1095
+ const wildcardable = Math.max(0, path.length - 1);
1096
+ for (let bits = (1 << wildcardable) - 1; bits > 0; bits--) yield path.map((segment, index) => index > 0 && (bits & 1 << index - 1) !== 0 ? "*" : segment);
1097
+ }
1098
+ //#endregion
1099
+ //#region src/client/schema-form/locales.ts
1100
+ const zh = {
1101
+ unavailable: "该插件当前未加载,暂时无法配置。",
1102
+ readOnly: "本部署的设置为只读。",
1103
+ save: "保存",
1104
+ confirmEdit: "确认",
1105
+ cancelEdit: "取消",
1106
+ saving: "保存中…",
1107
+ saveFailed: "本部署没有接受这些值,已保留供你修改。",
1108
+ notSaved: "没有保存:{message}",
1109
+ noSchema: "这一行没有可自动生成的配置项。",
1110
+ reset: "恢复默认",
1111
+ revert: "撤回",
1112
+ invalid: "这个值不被接受。",
1113
+ invalidNumber: "需要一个数字。",
1114
+ invalidInteger: "需要一个整数。",
1115
+ invalidJson: "需要一段合法的 JSON。",
1116
+ invalidBoolean: "需要 true 或 false。",
1117
+ invalidConst: "这个字段只接受固定值。",
1118
+ invalidPattern: "要匹配 {pattern}。",
1119
+ invalidRange: "要在 {min} 与 {max} 之间。",
1120
+ invalidMin: "不能小于 {min}。",
1121
+ invalidMax: "不能大于 {max}。",
1122
+ invalidChoice: "只能是 {choices} 之一。",
1123
+ unknownProperty: "这一层没有这个字段:从上面的候选里选,或换个键名。",
1124
+ empty: "(空)",
1125
+ toggleGroup: "展开 / 收起这一层",
1126
+ switchVariant: "切换这一层的形状或分支",
1127
+ copyValue: "复制值",
1128
+ copied: "已复制",
1129
+ addProperty: "添加属性",
1130
+ addItemPaste: "添加数组项(可粘贴 JSON 字符串)",
1131
+ addItem: "添加一项",
1132
+ removeItem: "移除",
1133
+ addKey: "添加键(可粘贴 JSON 字符串)",
1134
+ keyName: "键名",
1135
+ noKeys: "还没有键。",
1136
+ noItems: "还没有项。",
1137
+ deprecated: "已废弃",
1138
+ experimental: "试验中",
1139
+ secretSet: "已配置",
1140
+ secretUnset: "未配置",
1141
+ secretHint: "留空即保留已存的值。",
1142
+ constValue: "固定值",
1143
+ notEditable: "这一项由插件在运行时提供,不能在页面上编辑。",
1144
+ recursive: "递归结构:展开到这一层为止。",
1145
+ fixedLength: "固定长度",
1146
+ bitsetHint: "可多选。",
1147
+ unconfigured: "未配置",
1148
+ readOnlyField: "只读",
1149
+ noDescription: "(无说明)",
1150
+ required: "必填",
1151
+ duplicateItem: "重复的 {key}:{value}",
1152
+ missingItem: "每一项都需要一个 {key}"
1153
+ };
1154
+ const en = {
1155
+ unavailable: "This plugin is not loaded, so it cannot be configured right now.",
1156
+ readOnly: "This deployment stores settings read-only.",
1157
+ save: "Save",
1158
+ confirmEdit: "Confirm",
1159
+ cancelEdit: "Cancel",
1160
+ saving: "Saving…",
1161
+ saveFailed: "This deployment did not accept these values; they are kept for you to fix.",
1162
+ notSaved: "Not saved: {message}",
1163
+ noSchema: "This row has no configuration to generate.",
1164
+ reset: "Reset",
1165
+ revert: "Revert",
1166
+ invalid: "This value is not accepted.",
1167
+ invalidNumber: "Enter a number.",
1168
+ invalidInteger: "Enter a whole number.",
1169
+ invalidJson: "Enter valid JSON.",
1170
+ invalidBoolean: "Enter true or false.",
1171
+ invalidConst: "This field only accepts its fixed value.",
1172
+ invalidPattern: "Must match {pattern}.",
1173
+ invalidRange: "Must be between {min} and {max}.",
1174
+ invalidMin: "Must not be less than {min}.",
1175
+ invalidMax: "Must not be greater than {max}.",
1176
+ invalidChoice: "Must be one of {choices}.",
1177
+ unknownProperty: "No such field at this level: pick one of the candidates above.",
1178
+ empty: "(empty)",
1179
+ toggleGroup: "Expand or collapse this level",
1180
+ switchVariant: "Switch this level's shape or branch",
1181
+ copyValue: "Copy value",
1182
+ copied: "Copied",
1183
+ addProperty: "Add property",
1184
+ addItemPaste: "Add item (a JSON string can be pasted)",
1185
+ addItem: "Add item",
1186
+ removeItem: "Remove",
1187
+ addKey: "Add key (a JSON string can be pasted)",
1188
+ keyName: "Key",
1189
+ noKeys: "No keys yet.",
1190
+ noItems: "No items yet.",
1191
+ deprecated: "deprecated",
1192
+ experimental: "experimental",
1193
+ secretSet: "configured",
1194
+ secretUnset: "not set",
1195
+ secretHint: "Leave blank to keep the stored value.",
1196
+ constValue: "fixed",
1197
+ notEditable: "This entry is provided by the plugin at runtime and cannot be edited here.",
1198
+ recursive: "Recursive structure: expanded down to this level.",
1199
+ fixedLength: "fixed length",
1200
+ bitsetHint: "Multiple choices.",
1201
+ unconfigured: "not configured",
1202
+ readOnlyField: "read-only",
1203
+ noDescription: "(no description)",
1204
+ required: "required",
1205
+ duplicateItem: "Duplicate {key}: {value}",
1206
+ missingItem: "Every item needs a {key}"
1207
+ };
1208
+ //#endregion
1209
+ //#region src/client/schema-form/rows.ts
1210
+ function rowRegistrations(namespaces, bundles) {
1211
+ const owners = /* @__PURE__ */ new Map();
1212
+ for (const bundle of bundles) for (const row of bundle.rows) owners.set(row.rowId, bundle.name);
1213
+ const plans = [];
1214
+ for (const view of namespaces) {
1215
+ if (view.autoGenerate !== true) continue;
1216
+ const owner = owners.get(view.ns);
1217
+ if (owner === void 0) continue;
1218
+ plans.push({
1219
+ key: `${owner}#${view.ns}`,
1220
+ ns: view.ns
1221
+ });
1222
+ }
1223
+ return plans;
1224
+ }
1225
+ const FALLBACK_PRIORITY = 100;
1226
+ var RowRegistration = class {
1227
+ #deps;
1228
+ #live = /* @__PURE__ */ new Map();
1229
+ #pending;
1230
+ #disposed = false;
1231
+ constructor(deps) {
1232
+ this.#deps = deps;
1233
+ }
1234
+ sync() {
1235
+ if (this.#disposed) return Promise.resolve();
1236
+ this.#pending ??= this.#run().finally(() => {
1237
+ this.#pending = void 0;
1238
+ });
1239
+ return this.#pending;
1240
+ }
1241
+ dispose() {
1242
+ this.#disposed = true;
1243
+ this.#release();
1244
+ }
1245
+ async #run() {
1246
+ const bundles = await this.#deps.bundles();
1247
+ if (this.#disposed) return;
1248
+ const namespaces = this.#deps.describe.getSnapshot().view?.namespaces ?? [];
1249
+ const wanted = /* @__PURE__ */ new Map();
1250
+ for (const plan of rowRegistrations(namespaces, bundles)) {
1251
+ if (this.#deps.entryFor(plan.ns) === void 0) continue;
1252
+ wanted.set(plan.ns, plan);
1253
+ }
1254
+ for (const [ns, dispose] of this.#live) {
1255
+ if (wanted.has(ns)) continue;
1256
+ dispose();
1257
+ this.#live.delete(ns);
1258
+ this.#deps.release(ns);
1259
+ }
1260
+ for (const [ns, plan] of wanted) {
1261
+ if (this.#live.has(ns)) continue;
1262
+ const entry = this.#deps.entryFor(ns);
1263
+ if (entry === void 0) continue;
1264
+ const dispose = this.#deps.slots.register({
1265
+ name: "plugins.row.config",
1266
+ key: plan.key,
1267
+ priority: FALLBACK_PRIORITY,
1268
+ locale: this.#deps.locale
1269
+ }, entry.component);
1270
+ this.#live.set(ns, dispose);
1271
+ }
1272
+ }
1273
+ #release() {
1274
+ for (const [ns, dispose] of this.#live) {
1275
+ dispose();
1276
+ this.#live.delete(ns);
1277
+ this.#deps.release(ns);
1278
+ }
1279
+ }
1280
+ };
1281
+ function fieldHint(node, resolveText) {
1282
+ const parts = [];
1283
+ if (node.meta.description !== void 0) parts.push(resolveText(node.meta.description));
1284
+ if (node.meta.comment !== void 0) parts.push(node.meta.comment);
1285
+ return parts.length === 0 ? void 0 : parts.join(" ");
1286
+ }
1287
+ //#endregion
1288
+ //#region src/client/schema-form/lines.ts
1289
+ function containerShape(node, value) {
1290
+ switch (variantOf(node, value).type) {
1291
+ case "object":
1292
+ case "dict":
1293
+ case "intersect": return "object";
1294
+ case "array":
1295
+ case "tuple": return "array";
1296
+ default: return;
1297
+ }
1298
+ }
1299
+ function visibleFields(state, fold) {
1300
+ const containers = new Set(state.walked.filter((item) => containerShape(item.node, valueAt(state, item.path)) !== void 0).map((item) => fieldKey(item.path)));
1301
+ return state.walked.filter((item) => {
1302
+ for (let depth = 1; depth < item.path.length; depth++) {
1303
+ const ancestor = item.path.slice(0, depth);
1304
+ if (containers.has(fieldKey(ancestor)) && fold.collapsed(ancestor)) return false;
1305
+ }
1306
+ return true;
1307
+ });
1308
+ }
1309
+ function valueAt(state, path) {
1310
+ return state.fields.get(fieldKey(path))?.value;
1311
+ }
1312
+ function addOf(node, shape, options) {
1313
+ if (shape === "array") return { kind: "item" };
1314
+ if (unwrapLazy(node)?.type === "dict") return {
1315
+ kind: "key",
1316
+ options
1317
+ };
1318
+ return options.length === 0 ? void 0 : {
1319
+ kind: "prop",
1320
+ options
1321
+ };
1322
+ }
1323
+ function variantsOf(node, value) {
1324
+ const union = unionOf(node);
1325
+ if (union === void 0 || union.choices !== void 0 || union.variants.length < 2) return void 0;
1326
+ return {
1327
+ choices: variantChoices(union),
1328
+ selected: union.variants.indexOf(variantOf(union, value))
1329
+ };
1330
+ }
1331
+ function editorLines(state, fold, resolveText, t) {
1332
+ const lines = [];
1333
+ const open = [];
1334
+ const closeOpenUntil = (path) => {
1335
+ while (open.length > 0) {
1336
+ const top = open[open.length - 1];
1337
+ if (isPrefix(top.path, path)) return;
1338
+ open.pop();
1339
+ lines.push({
1340
+ kind: "close",
1341
+ path: top.path,
1342
+ node: top.node,
1343
+ shape: top.shape,
1344
+ depth: top.depth,
1345
+ add: top.add,
1346
+ member: top.member
1347
+ });
1348
+ }
1349
+ };
1350
+ for (const item of visibleFields(state, fold)) {
1351
+ closeOpenUntil(item.path);
1352
+ const node = unwrapLazy(item.node) ?? item.node;
1353
+ const value = valueAt(state, item.path);
1354
+ const depth = item.path.length;
1355
+ const comment = commentFor(state, item, resolveText, t);
1356
+ if (comment !== void 0) lines.push({
1357
+ kind: "comment",
1358
+ path: item.path,
1359
+ depth,
1360
+ text: comment.text,
1361
+ invalid: comment.invalid
1362
+ });
1363
+ const variants = variantsOf(node, value);
1364
+ const shape = containerShape(node, value);
1365
+ if (shape !== void 0) {
1366
+ const collapsed = fold.collapsed(item.path);
1367
+ const add = addOf(node, shape, state.addable.get(fieldKey(item.path)) ?? []);
1368
+ lines.push({
1369
+ kind: "open",
1370
+ path: item.path,
1371
+ node,
1372
+ shape,
1373
+ depth,
1374
+ collapsed,
1375
+ member: item.member,
1376
+ variants
1377
+ });
1378
+ if (!collapsed) open.push({
1379
+ path: item.path,
1380
+ node,
1381
+ shape,
1382
+ depth,
1383
+ add,
1384
+ member: item.member
1385
+ });
1386
+ continue;
1387
+ }
1388
+ lines.push({
1389
+ kind: "field",
1390
+ path: item.path,
1391
+ node,
1392
+ depth,
1393
+ field: state.fields.get(fieldKey(item.path)) ?? {
1394
+ value: void 0,
1395
+ text: void 0,
1396
+ invalid: void 0,
1397
+ overridden: false,
1398
+ staged: false
1399
+ },
1400
+ member: item.member,
1401
+ variants,
1402
+ variantsStandIn: false
1403
+ });
1404
+ }
1405
+ while (open.length > 0) {
1406
+ const top = open.pop();
1407
+ lines.push({
1408
+ kind: "close",
1409
+ path: top.path,
1410
+ node: top.node,
1411
+ shape: top.shape,
1412
+ depth: top.depth,
1413
+ add: top.add,
1414
+ member: top.member
1415
+ });
1416
+ }
1417
+ return moveVariantControlToTag(lines);
1418
+ }
1419
+ function moveVariantControlToTag(lines) {
1420
+ for (const line of lines) {
1421
+ if (line.kind === "comment" || line.kind === "close") continue;
1422
+ if (line.variants === void 0) continue;
1423
+ const tagKey = unionOf(line.node)?.tagKey;
1424
+ if (tagKey === void 0) continue;
1425
+ const tagPath = [...line.path, tagKey];
1426
+ const tagLine = lines.find((candidate) => candidate.kind === "field" && candidate.path.length === tagPath.length && candidate.path.every((segment, index) => segment === tagPath[index]));
1427
+ if (tagLine === void 0 || tagLine.kind !== "field") continue;
1428
+ tagLine.variants = line.variants;
1429
+ tagLine.variantsStandIn = true;
1430
+ line.variants = void 0;
1431
+ }
1432
+ return lines;
1433
+ }
1434
+ function commentFor(state, item, resolveText, t) {
1435
+ const key = fieldKey(item.path);
1436
+ const failure = state.fields.get(key)?.invalid ?? state.invalidAt.get(key);
1437
+ if (failure !== void 0) return {
1438
+ text: failure,
1439
+ invalid: true
1440
+ };
1441
+ const node = unwrapLazy(item.node) ?? item.node;
1442
+ const parts = [];
1443
+ const text = state.texts.get(fieldKey(item.path));
1444
+ const hint = [text?.label, text?.hint].filter((part) => part !== void 0 && part !== "").join(":") || fieldHint(node, resolveText);
1445
+ if (hint !== void 0 && hint !== "") parts.push(hint);
1446
+ if (node.meta.disabled) parts.push(t("readOnlyField"));
1447
+ if (node.meta.badges.length > 0) parts.push(node.meta.badges.join(" / "));
1448
+ return parts.length === 0 ? void 0 : {
1449
+ text: parts.join(" · "),
1450
+ invalid: false
1451
+ };
1452
+ }
1453
+ function isPrefix(prefix, path) {
1454
+ if (prefix.length > path.length) return false;
1455
+ return prefix.every((segment, index) => path[index] === segment);
1456
+ }
1457
+ //#endregion
1458
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/schema-form/schema-form.module.css.mjs
1459
+ const css$14 = ".N3kx7G_editorRoot{width:100%;color:var(--dsw-alias-label-primary);flex-direction:column;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:14px;line-height:22px;display:flex}.N3kx7G_lineRow{white-space:nowrap;align-items:flex-start;gap:6px;min-height:22px;padding-right:8px;display:flex}.N3kx7G_lineRow:hover{background:var(--dsw-alias-bg-layer-2)}.N3kx7G_lineRow[data-selected=true]{background:var(--dsw-alias-bg-layer-3)}.N3kx7G_lineRow[data-dirty=true]{box-shadow:inset 2px 0 0 var(--dsw-alias-brand-primary)}.N3kx7G_lineRow[data-overridden=true]{box-shadow:inset 2px 0 0 var(--dsw-elevation-stroke-color)}.N3kx7G_lineRow[data-dirty=true] [data-role=key],.N3kx7G_lineRow[data-overridden=true] [data-role=key]{color:var(--dsw-alias-brand-primary)}.N3kx7G_lineRow[data-invalid=true]{background:color-mix(in srgb, var(--dsw-alias-state-error-secondary) 12%, transparent);box-shadow:inset 2px 0 0 var(--dsw-alias-state-error-primary)}.N3kx7G_lineRow[data-invalid=true] [data-role=key]{color:var(--dsw-alias-state-error-primary)}.N3kx7G_lineRow:hover [data-role=actions]{opacity:1}.N3kx7G_lineBody{flex:1;align-items:center;gap:6px;min-width:0;min-height:22px;display:flex}.N3kx7G_lineNumber{text-align:right;width:32px;color:var(--dsw-alias-label-caption);user-select:none;cursor:pointer;flex:none;line-height:22px}.N3kx7G_lineFold{width:14px;height:22px;color:var(--dsw-alias-label-caption);cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.N3kx7G_lineFold:hover{color:var(--dsw-alias-label-secondary)}.N3kx7G_lineFoldSpacer{flex:none;width:14px}.N3kx7G_lineKey{color:var(--dsw-alias-label-primary);flex:none}.N3kx7G_lineKey[data-index=true]{color:var(--dsw-alias-label-caption)}.N3kx7G_lineToken{color:var(--dsw-alias-label-caption);flex:none}.N3kx7G_lineValue{text-overflow:ellipsis;cursor:text;min-width:0;color:var(--dsw-alias-state-business-primary);display:block;overflow:hidden}.N3kx7G_lineValue[data-tone=number]{color:var(--dsw-alias-state-warn-primary)}.N3kx7G_lineValue[data-tone=boolean]{color:var(--dsw-alias-state-success-primary)}.N3kx7G_lineValue[data-tone=empty]{color:var(--dsw-alias-label-caption)}.N3kx7G_valueSlot{flex:0 auto;min-width:0;display:block;overflow:hidden}.N3kx7G_valueTrigger{min-width:0;font:inherit;text-align:left;cursor:pointer;color:var(--dsw-alias-label-caption);background:0 0;border:0;align-items:center;gap:2px;padding:0;display:inline-flex}.N3kx7G_valueTrigger:disabled{cursor:default}.N3kx7G_valueTrigger:focus-visible{outline:none}.N3kx7G_compactInput{flex:auto;min-width:0;display:inline-flex}.N3kx7G_compactInput>span{border-radius:4px;width:100%;height:22px;padding:0 6px}.N3kx7G_compactInput input{font-size:14px;line-height:22px}.N3kx7G_compactTextField{background:var(--dsw-alias-bg-layer-1);min-width:0;box-shadow:0 0 0 .5px var(--dsw-elevation-stroke-color);border:0;border-radius:4px;flex:auto;padding:0 6px;display:inline-flex}.N3kx7G_compactTextField:focus-within{--dsw-elevation-stroke-color:var(--dsw-alias-brand-primary)}.N3kx7G_compactTextField>textarea{resize:none;field-sizing:content;width:100%;min-height:20px;max-height:240px;color:var(--dsw-alias-label-primary);background:0 0;border:0;outline:none;flex:1;padding:0;font-family:inherit;font-size:14px;line-height:22px}.N3kx7G_lineComment{text-overflow:ellipsis;min-width:0;color:var(--dsw-alias-label-tertiary);flex:auto;font-family:inherit;font-size:12px;overflow:hidden}.N3kx7G_lineInvalid{text-overflow:ellipsis;min-width:0;color:var(--dsw-alias-state-error-primary);flex:0 auto;font-family:inherit;font-size:12px;overflow:hidden}.N3kx7G_lineActions{opacity:0;flex:none;align-items:center;gap:4px;display:inline-flex}.N3kx7G_lineActions>button{width:20px;height:20px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;padding:0;display:inline-flex}.N3kx7G_lineActions>button:hover{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary)}.N3kx7G_lineActions>button:disabled{cursor:not-allowed;color:var(--dsw-alias-label-dimmed)}.N3kx7G_hoverActions[data-editing=true]{opacity:1;gap:6px}.N3kx7G_hoverActions[data-editing=true]>button{box-shadow:0 0 0 .5px var(--dsw-elevation-stroke-color);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.N3kx7G_hoverActions[data-editing=true]>button:first-of-type{color:var(--dsw-alias-state-success-primary)}.N3kx7G_addWrap{flex:auto;align-items:center;gap:6px;min-width:0;margin-left:6px;display:inline-flex;position:relative}.N3kx7G_addWrap[data-invalid=true] input{border-color:var(--dsw-alias-state-error-primary)}.N3kx7G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}";
1460
+ const tagId$14 = "@morlay/dsh-client-ui-primitives/schema-form.module.css";
1461
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/schema-form.module.css\"]") === null) {
1462
+ const tag = document.createElement("style");
1463
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
1464
+ tag.dataset.pluginCss = tagId$14;
1465
+ tag.textContent = css$14;
1466
+ document.head.appendChild(tag);
1467
+ }
1468
+ var schema_form_module_css_default = {
1469
+ "lineRow": "N3kx7G_lineRow",
1470
+ "valueSlot": "N3kx7G_valueSlot",
1471
+ "lineValue": "N3kx7G_lineValue",
1472
+ "valueTrigger": "N3kx7G_valueTrigger",
1473
+ "compactInput": "N3kx7G_compactInput",
1474
+ "compactTextField": "N3kx7G_compactTextField",
1475
+ "hoverActions": "N3kx7G_hoverActions",
1476
+ "hint": "N3kx7G_hint",
1477
+ "lineToken": "N3kx7G_lineToken",
1478
+ "lineInvalid": "N3kx7G_lineInvalid",
1479
+ "lineNumber": "N3kx7G_lineNumber",
1480
+ "editorRoot": "N3kx7G_editorRoot",
1481
+ "lineComment": "N3kx7G_lineComment",
1482
+ "addWrap": "N3kx7G_addWrap",
1483
+ "lineFoldSpacer": "N3kx7G_lineFoldSpacer",
1484
+ "lineActions": "N3kx7G_lineActions",
1485
+ "lineFold": "N3kx7G_lineFold",
1486
+ "lineKey": "N3kx7G_lineKey",
1487
+ "lineBody": "N3kx7G_lineBody"
1488
+ };
1489
+ //#endregion
1490
+ //#region src/client/schema-form/TruncatedTooltip.tsx
1491
+ function TruncatedTooltip({ label, children }) {
1492
+ const node = useRef(null);
1493
+ const watch = useRef(null);
1494
+ const [truncated, setTruncated] = useState(false);
1495
+ const measure = useCallback(() => {
1496
+ const el = node.current;
1497
+ if (el === null) return;
1498
+ setTruncated(el.scrollWidth > el.clientWidth);
1499
+ }, []);
1500
+ const anchor = useCallback((el) => {
1501
+ watch.current?.disconnect();
1502
+ watch.current = null;
1503
+ node.current = el;
1504
+ if (el === null) return;
1505
+ const observer = new ResizeObserver(measure);
1506
+ observer.observe(el);
1507
+ watch.current = observer;
1508
+ }, [measure]);
1509
+ useLayoutEffect(measure);
1510
+ return /* @__PURE__ */ jsx(Tooltip, {
1511
+ label,
1512
+ side: "bottom",
1513
+ portal: true,
1514
+ disabled: !truncated,
1515
+ children: cloneElement(children, { ref: anchor })
1516
+ });
1517
+ }
1518
+ //#endregion
1519
+ //#region src/client/schema-form/value.tsx
1520
+ function valueText(value) {
1521
+ if (value === void 0 || value === null) return "";
1522
+ if (typeof value === "string") return value;
1523
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
1524
+ return JSON.stringify(value);
1525
+ }
1526
+ function isMultiline(value) {
1527
+ return typeof value === "string" && /[\r\n]/.test(value);
1528
+ }
1529
+ function tokenText(value) {
1530
+ if (value === void 0 || value === null) return "null";
1531
+ if (typeof value === "string") return JSON.stringify(value);
1532
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
1533
+ return JSON.stringify(value);
1534
+ }
1535
+ function tokenTone(value) {
1536
+ if (value === void 0 || value === null) return "empty";
1537
+ if (typeof value === "number") return "number";
1538
+ if (typeof value === "boolean") return "boolean";
1539
+ return "string";
1540
+ }
1541
+ function InlineValue({ owner }) {
1542
+ if (owner.options !== void 0) return /* @__PURE__ */ jsx(OptionSelect, {
1543
+ owner,
1544
+ options: owner.options
1545
+ });
1546
+ if (owner.node.meta.secret) return /* @__PURE__ */ jsx("span", {
1547
+ className: schema_form_module_css_default.lineValue,
1548
+ "data-tone": "empty",
1549
+ title: owner.hint,
1550
+ children: owner.secretConfigured ? "••••••" : ""
1551
+ });
1552
+ const text = tokenText(owner.value);
1553
+ return /* @__PURE__ */ jsx(TruncatedTooltip, {
1554
+ label: text,
1555
+ children: /* @__PURE__ */ jsx("span", {
1556
+ className: schema_form_module_css_default.lineValue,
1557
+ "data-tone": owner.node.readOnly === null ? tokenTone(owner.value) : "empty",
1558
+ children: text
1559
+ })
1560
+ });
1561
+ }
1562
+ function OptionSelect({ owner, options }) {
1563
+ const [open, setOpen] = useState(false);
1564
+ const selected = options.findIndex((option) => sameValue(option.value, owner.value));
1565
+ const current = selected < 0 ? void 0 : options[selected];
1566
+ const label = current?.label ?? (owner.value === void 0 ? owner.t("unconfigured") : tokenText(current?.value ?? owner.value));
1567
+ return /* @__PURE__ */ jsx(Menu, {
1568
+ open,
1569
+ dense: true,
1570
+ compact: true,
1571
+ portal: true,
1572
+ align: "start",
1573
+ items: options.map((option, index) => ({
1574
+ id: String(index),
1575
+ label: option.label ?? tokenText(option.value)
1576
+ })),
1577
+ selectedId: selected < 0 ? void 0 : String(selected),
1578
+ onSelect: (id) => {
1579
+ setOpen(false);
1580
+ const option = options[Number(id)];
1581
+ if (option !== void 0) owner.onChange(option.value);
1582
+ },
1583
+ onClose: () => {
1584
+ setOpen(false);
1585
+ },
1586
+ anchor: /* @__PURE__ */ jsxs("button", {
1587
+ className: schema_form_module_css_default.valueTrigger,
1588
+ type: "button",
1589
+ disabled: owner.disabled,
1590
+ "aria-label": owner.label,
1591
+ onClick: () => {
1592
+ setOpen(true);
1593
+ },
1594
+ children: [/* @__PURE__ */ jsx("span", {
1595
+ className: schema_form_module_css_default.lineValue,
1596
+ "data-tone": current === void 0 ? tokenTone(owner.value) : tokenTone(current.value),
1597
+ children: label
1598
+ }), /* @__PURE__ */ jsx(IconChevronDownOutlineRegular, { size: 14 })]
1599
+ })
1600
+ });
1601
+ }
1602
+ function sameValue(left, right) {
1603
+ if (Object.is(left, right)) return true;
1604
+ if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) return false;
1605
+ return JSON.stringify(left) === JSON.stringify(right);
1606
+ }
1607
+ function SchemaFieldDefault({ owner }) {
1608
+ return /* @__PURE__ */ jsx(InlineValue, { owner });
1609
+ }
1610
+ //#endregion
1611
+ //#region src/client/schema-form/fields.tsx
1612
+ function parseFor(node, t) {
1613
+ switch (node.type) {
1614
+ case "number": return (text) => {
1615
+ const trimmed = text.trim();
1616
+ const value = Number(trimmed);
1617
+ if (trimmed === "" || !Number.isFinite(value)) return {
1618
+ kind: "invalid",
1619
+ message: t("invalidNumber")
1620
+ };
1621
+ if (node.meta.step === 1 && !Number.isInteger(value)) return {
1622
+ kind: "invalid",
1623
+ message: t("invalidInteger")
1624
+ };
1625
+ const { min, max } = node.meta;
1626
+ if (min !== void 0 && max !== void 0 && (value < min || value > max)) return {
1627
+ kind: "invalid",
1628
+ message: t("invalidRange", {
1629
+ min,
1630
+ max
1631
+ })
1632
+ };
1633
+ if (min !== void 0 && value < min) return {
1634
+ kind: "invalid",
1635
+ message: t("invalidMin", { min })
1636
+ };
1637
+ if (max !== void 0 && value > max) return {
1638
+ kind: "invalid",
1639
+ message: t("invalidMax", { max })
1640
+ };
1641
+ return {
1642
+ kind: "value",
1643
+ value
1644
+ };
1645
+ };
1646
+ case "string": {
1647
+ const pattern = node.meta.pattern;
1648
+ if (pattern === void 0) return (text) => ({
1649
+ kind: "value",
1650
+ value: text
1651
+ });
1652
+ return (text) => new RegExp(pattern).test(text) ? {
1653
+ kind: "value",
1654
+ value: text
1655
+ } : {
1656
+ kind: "invalid",
1657
+ message: t("invalidPattern", { pattern })
1658
+ };
1659
+ }
1660
+ case "boolean": return (text) => {
1661
+ const trimmed = text.trim();
1662
+ if (trimmed === "true") return {
1663
+ kind: "value",
1664
+ value: true
1665
+ };
1666
+ if (trimmed === "false") return {
1667
+ kind: "value",
1668
+ value: false
1669
+ };
1670
+ return {
1671
+ kind: "invalid",
1672
+ message: t("invalidBoolean")
1673
+ };
1674
+ };
1675
+ case "const": return (text) => text === String(node.type === "const" ? node.value : "") || text.trim() === JSON.stringify(node.value) ? {
1676
+ kind: "value",
1677
+ value: node.value
1678
+ } : {
1679
+ kind: "invalid",
1680
+ message: t("invalidConst")
1681
+ };
1682
+ case "bitset": return (text) => {
1683
+ const value = Number(text.trim());
1684
+ return Number.isFinite(value) ? {
1685
+ kind: "value",
1686
+ value
1687
+ } : {
1688
+ kind: "invalid",
1689
+ message: t("invalidNumber")
1690
+ };
1691
+ };
1692
+ case "any": return (text) => {
1693
+ try {
1694
+ return {
1695
+ kind: "value",
1696
+ value: JSON.parse(text)
1697
+ };
1698
+ } catch {
1699
+ return {
1700
+ kind: "invalid",
1701
+ message: t("invalidJson")
1702
+ };
1703
+ }
1704
+ };
1705
+ default:
1706
+ if (node.type === "union" && node.choices !== void 0) {
1707
+ const choices = node.choices;
1708
+ const options = choices.map((choice) => String(choice)).join(" / ");
1709
+ return (text) => choices.some((choice) => String(choice) === text) ? {
1710
+ kind: "value",
1711
+ value: text
1712
+ } : {
1713
+ kind: "invalid",
1714
+ message: t("invalidChoice", { choices: options })
1715
+ };
1716
+ }
1717
+ return (text) => ({
1718
+ kind: "value",
1719
+ value: text
1720
+ });
1721
+ }
1722
+ }
1723
+ //#endregion
1724
+ //#region src/client/controls/classes.ts
1725
+ function classes(...names) {
1726
+ return names.filter((name) => typeof name === "string" && name !== "").join(" ");
1727
+ }
1728
+ //#endregion
1729
+ //#region src/client/schema-form/Editor.tsx
1730
+ function Editor(props) {
1731
+ const { ns, state, face, t, resolveText, renderField } = props;
1732
+ const [toggled, setToggled] = useState(() => /* @__PURE__ */ new Set());
1733
+ const [editing, setEditing] = useState(void 0);
1734
+ const [selected, setSelected] = useState(void 0);
1735
+ const [dismissed, setDismissed] = useState(() => /* @__PURE__ */ new Set());
1736
+ const fold = useFold(state, toggled, setToggled);
1737
+ const lines = useMemo(() => editorLines(state, fold, resolveText, t), [
1738
+ state,
1739
+ fold,
1740
+ resolveText,
1741
+ t
1742
+ ]);
1743
+ const disabled = !state.writable || !state.available;
1744
+ return /* @__PURE__ */ jsx("div", {
1745
+ className: schema_form_module_css_default.editorRoot,
1746
+ "data-editor": "schema-form",
1747
+ children: lines.map((line, index) => /* @__PURE__ */ jsx(Row$1, {
1748
+ line,
1749
+ n: index + 1,
1750
+ ns,
1751
+ state,
1752
+ face,
1753
+ fold,
1754
+ t,
1755
+ resolveText,
1756
+ disabled,
1757
+ editing,
1758
+ selected,
1759
+ onEdit: (key) => {
1760
+ setEditing(key);
1761
+ if (key !== void 0) setDismissed((previous) => {
1762
+ const next = new Set(previous);
1763
+ next.delete(key);
1764
+ return next;
1765
+ });
1766
+ },
1767
+ onAdded: (path) => {
1768
+ setEditing(fieldKey(path));
1769
+ },
1770
+ dismissed,
1771
+ onDismiss: (key) => {
1772
+ setDismissed((previous) => new Set(previous).add(key));
1773
+ },
1774
+ onSelect: (path) => {
1775
+ setSelected(fieldKey(path));
1776
+ },
1777
+ renderField
1778
+ }, `${line.kind}:${fieldKey(line.path)}:${String(index)}`))
1779
+ });
1780
+ }
1781
+ function useFold(state, toggled, setToggled) {
1782
+ const defaults = useMemo(() => {
1783
+ const collapsed = /* @__PURE__ */ new Set();
1784
+ for (const item of state.walked) {
1785
+ const value = state.fields.get(fieldKey(item.path))?.value;
1786
+ if (item.node.meta.collapse && containerShape(item.node, value) !== void 0) collapsed.add(fieldKey(item.path));
1787
+ }
1788
+ return collapsed;
1789
+ }, [state.walked, state.fields]);
1790
+ return useMemo(() => ({
1791
+ collapsed: (path) => {
1792
+ const key = fieldKey(path);
1793
+ return toggled.has(key) !== defaults.has(key);
1794
+ },
1795
+ toggle: (path) => {
1796
+ const key = fieldKey(path);
1797
+ const next = new Set(toggled);
1798
+ if (next.has(key)) next.delete(key);
1799
+ else next.add(key);
1800
+ setToggled(next);
1801
+ }
1802
+ }), [
1803
+ defaults,
1804
+ setToggled,
1805
+ toggled
1806
+ ]);
1807
+ }
1808
+ function Row$1({ line, n, ns, state, face, fold, t, resolveText, disabled, editing, selected, dismissed, onEdit, onAdded, onDismiss, onSelect, renderField }) {
1809
+ const key = fieldKey(line.path);
1810
+ const indent = { paddingLeft: `${String(line.depth * 14)}px` };
1811
+ const body = line.kind === "comment" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1812
+ className: schema_form_module_css_default.lineFoldSpacer,
1813
+ "data-role": "fold"
1814
+ }), /* @__PURE__ */ jsx(TruncatedTooltip, {
1815
+ label: line.text,
1816
+ children: line.invalid ? /* @__PURE__ */ jsx("span", {
1817
+ className: schema_form_module_css_default.lineInvalid,
1818
+ "data-role": "comment",
1819
+ children: `// ${line.text}`
1820
+ }) : /* @__PURE__ */ jsx("span", {
1821
+ className: schema_form_module_css_default.lineComment,
1822
+ "data-role": "comment",
1823
+ children: `// ${line.text}`
1824
+ })
1825
+ })] }) : line.kind === "open" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1826
+ /* @__PURE__ */ jsx("button", {
1827
+ className: schema_form_module_css_default.lineFold,
1828
+ "data-role": "fold",
1829
+ type: "button",
1830
+ "aria-expanded": !line.collapsed,
1831
+ "aria-label": t("toggleGroup"),
1832
+ onClick: () => {
1833
+ fold.toggle(line.path);
1834
+ },
1835
+ children: line.collapsed ? /* @__PURE__ */ jsx(IconChevronRightOutlineRegular, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronDownOutlineRegular, { size: 14 })
1836
+ }),
1837
+ /* @__PURE__ */ jsx(LinePrefix, {
1838
+ line,
1839
+ face,
1840
+ t,
1841
+ disabled
1842
+ }),
1843
+ /* @__PURE__ */ jsx("span", {
1844
+ className: schema_form_module_css_default.lineToken,
1845
+ children: line.shape === "object" ? line.collapsed ? "{…}" : "{" : line.collapsed ? "[…]" : "["
1846
+ }),
1847
+ /* @__PURE__ */ jsx(VariantSelect, {
1848
+ control: line.variants,
1849
+ path: line.path,
1850
+ face,
1851
+ disabled,
1852
+ t
1853
+ })
1854
+ ] }) : line.kind === "close" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1855
+ /* @__PURE__ */ jsx("span", {
1856
+ className: schema_form_module_css_default.lineFoldSpacer,
1857
+ "data-role": "fold"
1858
+ }),
1859
+ /* @__PURE__ */ jsx("span", {
1860
+ className: schema_form_module_css_default.lineToken,
1861
+ children: line.shape === "object" ? "}" : "]"
1862
+ }),
1863
+ /* @__PURE__ */ jsx(AddLine, {
1864
+ line,
1865
+ state,
1866
+ face,
1867
+ t,
1868
+ resolveText,
1869
+ disabled,
1870
+ onAdded
1871
+ })
1872
+ ] }) : /* @__PURE__ */ jsx(FieldLine, {
1873
+ line,
1874
+ ns,
1875
+ state,
1876
+ face,
1877
+ t,
1878
+ disabled,
1879
+ editing,
1880
+ dismissed,
1881
+ onEdit,
1882
+ onDismiss,
1883
+ renderField
1884
+ });
1885
+ return /* @__PURE__ */ jsxs("div", {
1886
+ className: schema_form_module_css_default.lineRow,
1887
+ "data-line": line.kind,
1888
+ "data-field-path": line.path.join("."),
1889
+ "data-selected": selected === key ? "true" : void 0,
1890
+ "data-dirty": line.kind === "field" && line.field.staged ? "true" : void 0,
1891
+ "data-overridden": line.kind === "field" && line.field.overridden && !line.field.staged ? "true" : void 0,
1892
+ "data-invalid": line.kind === "field" && (line.field.invalid !== void 0 || state.invalidAt.has(key)) ? "true" : void 0,
1893
+ children: [/* @__PURE__ */ jsx("span", {
1894
+ className: schema_form_module_css_default.lineNumber,
1895
+ "data-role": "number",
1896
+ onClick: () => {
1897
+ onSelect(line.path);
1898
+ },
1899
+ children: n
1900
+ }), /* @__PURE__ */ jsx("div", {
1901
+ className: schema_form_module_css_default.lineBody,
1902
+ "data-role": "body",
1903
+ style: indent,
1904
+ children: body
1905
+ })]
1906
+ });
1907
+ }
1908
+ function FieldLine({ line, ns, state, face, t, disabled, editing, dismissed, onEdit, onDismiss, renderField }) {
1909
+ const key = fieldKey(line.path);
1910
+ const member = line.member;
1911
+ const owner = {
1912
+ ns,
1913
+ path: line.path,
1914
+ node: line.node,
1915
+ label: line.node.label ?? member?.key ?? line.node.key,
1916
+ hint: void 0,
1917
+ value: line.field.value,
1918
+ options: state.options.get(key),
1919
+ text: line.field.text,
1920
+ secretConfigured: state.secrets.get(key) === true,
1921
+ depth: line.depth,
1922
+ overridden: line.field.overridden,
1923
+ invalid: line.field.invalid,
1924
+ disabled,
1925
+ t,
1926
+ actions: face,
1927
+ group: void 0,
1928
+ member,
1929
+ onChange: (value) => {
1930
+ face.set(line.path, value);
1931
+ },
1932
+ onEditText: (text, parse) => {
1933
+ face.setText(line.path, text, parse ?? parseFor(line.node, t));
1934
+ },
1935
+ onReset: () => {
1936
+ face.clear(line.path);
1937
+ }
1938
+ };
1939
+ const readOnly = line.node.meta.disabled || line.node.readOnly !== null;
1940
+ const editable = !disabled && !readOnly && line.node.type !== "const" && owner.options === void 0 && !line.variantsStandIn;
1941
+ const missing = line.field.value === null || line.field.value === void 0;
1942
+ const isEditing = editable && (editing === key || missing && !dismissed.has(key));
1943
+ const text = line.field.text ?? valueText(line.field.value);
1944
+ const multiline = isMultiline(line.field.value) || /[\r\n]/.test(text);
1945
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1946
+ /* @__PURE__ */ jsx("span", {
1947
+ className: schema_form_module_css_default.lineFoldSpacer,
1948
+ "data-role": "fold"
1949
+ }),
1950
+ /* @__PURE__ */ jsx("span", {
1951
+ className: schema_form_module_css_default.lineKey,
1952
+ "data-role": "key",
1953
+ "data-index": member?.index === void 0 ? void 0 : "true",
1954
+ title: member?.key ?? line.node.key,
1955
+ children: member?.key ?? line.node.key
1956
+ }),
1957
+ /* @__PURE__ */ jsx("span", {
1958
+ className: schema_form_module_css_default.lineToken,
1959
+ children: member?.index === void 0 ? ": " : " "
1960
+ }),
1961
+ isEditing ? multiline ? /* @__PURE__ */ jsx("span", {
1962
+ className: schema_form_module_css_default.compactTextField,
1963
+ children: /* @__PURE__ */ jsx("textarea", {
1964
+ autoFocus: !missing,
1965
+ rows: 1,
1966
+ "aria-label": owner.label,
1967
+ value: text,
1968
+ onChange: (event) => {
1969
+ owner.onEditText(event.target.value);
1970
+ },
1971
+ onKeyDown: (event) => {
1972
+ if (event.key === "Escape") {
1973
+ face.revert(line.path);
1974
+ onEdit(void 0);
1975
+ }
1976
+ }
1977
+ })
1978
+ }) : /* @__PURE__ */ jsx("span", {
1979
+ className: schema_form_module_css_default.compactInput,
1980
+ children: /* @__PURE__ */ jsx(Input, {
1981
+ autoFocus: !missing,
1982
+ type: "text",
1983
+ "aria-label": owner.label,
1984
+ placeholder: missing ? t("empty") : "",
1985
+ value: text,
1986
+ onBlur: () => {
1987
+ if (!missing) onEdit(void 0);
1988
+ },
1989
+ onChange: (event) => {
1990
+ owner.onEditText(event.target.value);
1991
+ },
1992
+ onKeyDown: (event) => {
1993
+ if (event.key === "Enter" && !missing) onEdit(void 0);
1994
+ if (event.key === "Escape") {
1995
+ face.revert(line.path);
1996
+ onEdit(void 0);
1997
+ }
1998
+ }
1999
+ })
2000
+ }) : null,
2001
+ isEditing || line.variantsStandIn ? null : /* @__PURE__ */ jsx("span", {
2002
+ className: schema_form_module_css_default.valueSlot,
2003
+ "data-role": "value",
2004
+ onClick: () => {
2005
+ if (editable) onEdit(key);
2006
+ },
2007
+ children: renderField(owner)
2008
+ }),
2009
+ /* @__PURE__ */ jsx(VariantSelect, {
2010
+ control: line.variants,
2011
+ path: line.path,
2012
+ face,
2013
+ disabled,
2014
+ t
2015
+ }),
2016
+ isEditing ? /* @__PURE__ */ jsxs("span", {
2017
+ className: classes(schema_form_module_css_default.lineActions, schema_form_module_css_default.hoverActions),
2018
+ "data-role": "actions",
2019
+ "data-editing": "true",
2020
+ children: [/* @__PURE__ */ jsx("button", {
2021
+ type: "button",
2022
+ "aria-label": t("confirmEdit"),
2023
+ title: t("confirmEdit"),
2024
+ onClick: () => {
2025
+ onEdit(void 0);
2026
+ },
2027
+ children: /* @__PURE__ */ jsx(IconCheckOutlineRegular, { size: 14 })
2028
+ }), /* @__PURE__ */ jsx("button", {
2029
+ type: "button",
2030
+ "aria-label": t("cancelEdit"),
2031
+ title: t("cancelEdit"),
2032
+ onClick: () => {
2033
+ face.revert(line.path);
2034
+ onEdit(void 0);
2035
+ onDismiss(key);
2036
+ },
2037
+ children: /* @__PURE__ */ jsx(IconCloseOutlineRegular, { size: 14 })
2038
+ })]
2039
+ }) : null,
2040
+ /* @__PURE__ */ jsxs("span", {
2041
+ className: classes(schema_form_module_css_default.lineActions, schema_form_module_css_default.hoverActions),
2042
+ "data-role": "actions",
2043
+ children: [
2044
+ line.field.staged && !disabled ? /* @__PURE__ */ jsx("button", {
2045
+ type: "button",
2046
+ "aria-label": t("revert"),
2047
+ title: t("revert"),
2048
+ onClick: () => {
2049
+ face.revert(line.path);
2050
+ },
2051
+ children: /* @__PURE__ */ jsx(IconRefreshOutlineRegular, { size: 14 })
2052
+ }) : null,
2053
+ line.field.overridden && !line.field.staged && !disabled ? /* @__PURE__ */ jsx("button", {
2054
+ type: "button",
2055
+ "aria-label": t("reset"),
2056
+ title: t("reset"),
2057
+ onClick: () => {
2058
+ face.clear(line.path);
2059
+ },
2060
+ children: /* @__PURE__ */ jsx(IconRefreshOutlineRegular, { size: 14 })
2061
+ }) : null,
2062
+ /* @__PURE__ */ jsx("button", {
2063
+ type: "button",
2064
+ "aria-label": t("copyValue"),
2065
+ title: t("copyValue"),
2066
+ onClick: () => {
2067
+ navigator.clipboard?.writeText(line.field.text ?? tokenFor(line.field.value)).catch(() => {});
2068
+ },
2069
+ children: /* @__PURE__ */ jsx(IconCopyOutlineRegular, { size: 14 })
2070
+ }),
2071
+ member === void 0 ? null : /* @__PURE__ */ jsx(RemoveLineButton, {
2072
+ member,
2073
+ face,
2074
+ t,
2075
+ disabled
2076
+ })
2077
+ ]
2078
+ })
2079
+ ] });
2080
+ }
2081
+ function tokenFor(value) {
2082
+ return typeof value === "string" ? JSON.stringify(value) : JSON.stringify(value ?? null);
2083
+ }
2084
+ function VariantSelect({ control, path, face, disabled, t }) {
2085
+ const [open, setOpen] = useState(false);
2086
+ if (control === void 0) return null;
2087
+ const current = control.choices[control.selected];
2088
+ return /* @__PURE__ */ jsx(Menu, {
2089
+ open,
2090
+ dense: true,
2091
+ compact: true,
2092
+ portal: true,
2093
+ align: "start",
2094
+ items: control.choices.map((choice, index) => ({
2095
+ id: String(index),
2096
+ label: choice.label
2097
+ })),
2098
+ selectedId: String(control.selected),
2099
+ onSelect: (id) => {
2100
+ setOpen(false);
2101
+ const choice = control.choices[Number(id)];
2102
+ if (choice !== void 0) face.set(path, choice.value);
2103
+ },
2104
+ onClose: () => {
2105
+ setOpen(false);
2106
+ },
2107
+ anchor: /* @__PURE__ */ jsxs("button", {
2108
+ className: schema_form_module_css_default.valueTrigger,
2109
+ type: "button",
2110
+ "data-role": "variant",
2111
+ disabled,
2112
+ "aria-label": t("switchVariant"),
2113
+ onClick: () => {
2114
+ setOpen(true);
2115
+ },
2116
+ children: [/* @__PURE__ */ jsx("span", {
2117
+ className: schema_form_module_css_default.lineValue,
2118
+ "data-tone": "empty",
2119
+ children: current?.label ?? ""
2120
+ }), /* @__PURE__ */ jsx(IconChevronDownOutlineRegular, { size: 14 })]
2121
+ })
2122
+ });
2123
+ }
2124
+ function LinePrefix({ line, face, t, disabled }) {
2125
+ const member = line.member;
2126
+ const key = member?.key ?? line.node.key;
2127
+ if (key === "") return null;
2128
+ const indexed = member !== void 0 && member.index !== void 0;
2129
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2130
+ /* @__PURE__ */ jsx("span", {
2131
+ className: schema_form_module_css_default.lineKey,
2132
+ "data-role": "key",
2133
+ "data-index": indexed ? "true" : void 0,
2134
+ title: key,
2135
+ children: key
2136
+ }),
2137
+ /* @__PURE__ */ jsx("span", {
2138
+ className: schema_form_module_css_default.lineToken,
2139
+ children: indexed ? " " : ": "
2140
+ }),
2141
+ member === void 0 ? null : /* @__PURE__ */ jsx("span", {
2142
+ className: classes(schema_form_module_css_default.lineActions, schema_form_module_css_default.hoverActions),
2143
+ "data-role": "actions",
2144
+ children: /* @__PURE__ */ jsx(RemoveLineButton, {
2145
+ member,
2146
+ face,
2147
+ t,
2148
+ disabled
2149
+ })
2150
+ })
2151
+ ] });
2152
+ }
2153
+ function RemoveLineButton({ member, face, t, disabled }) {
2154
+ return /* @__PURE__ */ jsx("button", {
2155
+ type: "button",
2156
+ "aria-label": t("removeItem"),
2157
+ title: t("removeItem"),
2158
+ disabled,
2159
+ onClick: () => {
2160
+ if (member.index === void 0) face.removeKey(member.parent, member.key);
2161
+ else face.removeItem(member.parent, member.index);
2162
+ },
2163
+ children: /* @__PURE__ */ jsx(IconTrashOutlineRegular, { size: 14 })
2164
+ });
2165
+ }
2166
+ function AddLine({ line, state, face, t, resolveText, disabled, onAdded }) {
2167
+ const spec = line.add;
2168
+ const [text, setText] = useState("");
2169
+ const [open, setOpen] = useState(false);
2170
+ const [invalid, setInvalid] = useState(false);
2171
+ if (spec === void 0 || disabled) return null;
2172
+ const options = spec.kind === "item" ? [] : spec.options;
2173
+ const query = text.trim().toLowerCase();
2174
+ const matched = options.filter((option) => query === "" || option.key.toLowerCase().includes(query));
2175
+ const label = spec.kind === "item" ? t("addItemPaste") : spec.kind === "key" ? t("addKey") : t("addProperty");
2176
+ const commit = (picked) => {
2177
+ const raw = (picked ?? text).trim();
2178
+ if (raw === "") return;
2179
+ setInvalid(false);
2180
+ if (raw.startsWith("{") || raw.startsWith("[")) try {
2181
+ face.set(line.path, JSON.parse(raw));
2182
+ setText("");
2183
+ setOpen(false);
2184
+ return;
2185
+ } catch {}
2186
+ if (spec.kind === "key") {
2187
+ face.addKey(line.path, raw);
2188
+ onAdded([...line.path, raw]);
2189
+ } else if (spec.kind === "item") {
2190
+ const current = state.fields.get(fieldKey(line.path))?.value;
2191
+ const index = Array.isArray(current) ? current.length : 0;
2192
+ face.appendItem(line.path);
2193
+ onAdded([...line.path, String(index)]);
2194
+ } else {
2195
+ if (!spec.options.some((option) => option.key === raw)) {
2196
+ setInvalid(true);
2197
+ return;
2198
+ }
2199
+ face.addKey(line.path, raw);
2200
+ onAdded([...line.path, raw]);
2201
+ }
2202
+ setText("");
2203
+ setOpen(false);
2204
+ };
2205
+ return /* @__PURE__ */ jsxs("span", {
2206
+ className: schema_form_module_css_default.addWrap,
2207
+ "data-add": spec.kind,
2208
+ "data-invalid": invalid ? "true" : void 0,
2209
+ children: [
2210
+ /* @__PURE__ */ jsx(Menu, {
2211
+ open: open && spec.kind !== "item" && matched.length > 0,
2212
+ dense: true,
2213
+ compact: true,
2214
+ portal: true,
2215
+ align: "start",
2216
+ items: matched.map((option) => ({
2217
+ id: option.key,
2218
+ label: option.key
2219
+ })),
2220
+ onSelect: (key) => {
2221
+ commit(key);
2222
+ },
2223
+ onClose: () => {
2224
+ setOpen(false);
2225
+ },
2226
+ anchor: /* @__PURE__ */ jsx("span", {
2227
+ className: schema_form_module_css_default.compactInput,
2228
+ children: /* @__PURE__ */ jsx(Input, {
2229
+ value: text,
2230
+ placeholder: label,
2231
+ "aria-label": label,
2232
+ disabled,
2233
+ onFocus: () => {
2234
+ setOpen(true);
2235
+ },
2236
+ onChange: (event) => {
2237
+ setText(event.target.value);
2238
+ setInvalid(false);
2239
+ setOpen(true);
2240
+ },
2241
+ onKeyDown: (event) => {
2242
+ if (event.key === "Enter") {
2243
+ event.preventDefault();
2244
+ commit(matched.length === 1 && spec.kind === "prop" ? matched[0]?.key : void 0);
2245
+ }
2246
+ if (event.key === "Escape") {
2247
+ setText("");
2248
+ setOpen(false);
2249
+ }
2250
+ }
2251
+ })
2252
+ })
2253
+ }),
2254
+ invalid ? /* @__PURE__ */ jsx("span", {
2255
+ className: schema_form_module_css_default.lineInvalid,
2256
+ children: t("unknownProperty")
2257
+ }) : null,
2258
+ !invalid && matched.length === 1 && matched[0]?.description !== void 0 ? /* @__PURE__ */ jsx(TruncatedTooltip, {
2259
+ label: resolveText(matched[0].description),
2260
+ children: /* @__PURE__ */ jsx("span", {
2261
+ className: schema_form_module_css_default.lineComment,
2262
+ children: resolveText(matched[0].description)
2263
+ })
2264
+ }) : null
2265
+ ]
2266
+ });
2267
+ }
2268
+ //#endregion
2269
+ //#region src/client/schema-form/SchemaForm.tsx
2270
+ function SchemaForm(props) {
2271
+ const { ns, face, t, resolveText, renderSlotChain } = props;
2272
+ const store = face.hooks.schemaForm;
2273
+ const state = useSyncExternalStore((listener) => store.subscribe(listener), () => store.getSnapshot());
2274
+ const labels = {
2275
+ unavailable: t("unavailable"),
2276
+ readOnly: t("readOnly"),
2277
+ saveFailed: t("saveFailed"),
2278
+ save: t("save"),
2279
+ saving: t("saving")
2280
+ };
2281
+ if (!state.configured) return /* @__PURE__ */ jsx("p", {
2282
+ className: schema_form_module_css_default.hint,
2283
+ role: "status",
2284
+ children: t("noSchema")
2285
+ });
2286
+ return /* @__PURE__ */ jsxs(SettingsForm, {
2287
+ labels,
2288
+ state,
2289
+ onSave: () => {
2290
+ face.save();
2291
+ },
2292
+ onDiscard: () => {
2293
+ face.discard();
2294
+ },
2295
+ children: [/* @__PURE__ */ jsx(Editor, {
2296
+ ns,
2297
+ state,
2298
+ face,
2299
+ t,
2300
+ resolveText,
2301
+ renderField: (owner) => renderSlotChain("settings.schema-form.field", owner, { fallback: /* @__PURE__ */ jsx(SchemaFieldDefault, { owner: {
2302
+ ...owner,
2303
+ onEditText: withParse(owner, t)
2304
+ } }) })
2305
+ }), state.violation === void 0 ? null : /* @__PURE__ */ jsx("p", {
2306
+ className: schema_form_module_css_default.hint,
2307
+ role: "alert",
2308
+ "data-violation": "true",
2309
+ children: t("notSaved", { message: state.violation.message })
2310
+ })]
2311
+ });
2312
+ }
2313
+ function withParse(owner, t) {
2314
+ return (text, parse) => {
2315
+ owner.onEditText(text, parse ?? parseFor(owner.node, t));
2316
+ };
2317
+ }
2318
+ //#endregion
2319
+ //#region src/client/schema-form/index.ts
2320
+ var schema_form_exports = /* @__PURE__ */ __exportAll({
2321
+ InlineValue: () => InlineValue,
2322
+ NS: () => NS,
2323
+ SchemaFieldDefault: () => SchemaFieldDefault,
2324
+ SchemaFormController: () => SchemaFormController,
2325
+ SchemaFormHints: () => SchemaFormHints,
2326
+ addableAt: () => addableAt,
2327
+ apply: () => apply$1,
2328
+ canRender: () => canRender,
2329
+ containerShape: () => containerShape,
2330
+ editorLines: () => editorLines,
2331
+ failureOf: () => failureOf,
2332
+ fieldKey: () => fieldKey,
2333
+ inject: () => inject$1,
2334
+ optionsFor: () => optionsFor,
2335
+ parseFor: () => parseFor,
2336
+ projectNode: () => projectNode,
2337
+ projectRoot: () => projectRoot,
2338
+ readPath: () => readPath,
2339
+ rowRegistrations: () => rowRegistrations,
2340
+ tokenText: () => tokenText,
2341
+ tokenTone: () => tokenTone,
2342
+ valueText: () => valueText,
2343
+ visibleFields: () => visibleFields,
2344
+ walkFields: () => walkFields,
2345
+ zh: () => zh
2346
+ });
2347
+ const NS = "settings.schema-form";
2348
+ const inject$1 = [
2349
+ "slots",
2350
+ "locale",
2351
+ "configForms",
2352
+ "settingsSchema",
2353
+ "remote",
2354
+ "remote.pluginManager"
2355
+ ];
2356
+ function apply$1(ctx) {
2357
+ ctx.inject([...inject$1], (scope) => {
2358
+ if (scope.get("schemaFormHints") !== void 0) return;
2359
+ install(scope);
2360
+ });
2361
+ }
2362
+ function install(ctx) {
2363
+ ctx.effect(() => ctx.locale.register(NS, {
2364
+ zh,
2365
+ en
2366
+ }), "ui-schema-form: dictionaries");
2367
+ const hints = new SchemaFormHints(ctx);
2368
+ ctx.effect(() => ctx.slots.registerFactory({
2369
+ name: "settings.schema-form.form",
2370
+ scope: "root",
2371
+ children: { "settings.schema-form.field": {
2372
+ kind: "chain",
2373
+ scope: "root"
2374
+ } },
2375
+ locale: NS
2376
+ }, SchemaForm), "ui-schema-form: form factory");
2377
+ const rehydrate = (serialized) => ctx.settingsSchema.rehydrate(serialized);
2378
+ const validate = (schema, value) => {
2379
+ try {
2380
+ schema(value);
2381
+ return;
2382
+ } catch (error) {
2383
+ return failureOf(error);
2384
+ }
2385
+ };
2386
+ const resolveText = (text) => typeof text === "string" ? text : ctx.locale.resolveText(text);
2387
+ const entries = /* @__PURE__ */ new Map();
2388
+ const entryFor = (ns) => {
2389
+ const describe = ctx.configForms.describe();
2390
+ const view = describe.getSnapshot().view?.namespaces.find((row) => row.ns === ns);
2391
+ if (!canRender(view, rehydrate)) return void 0;
2392
+ const existing = entries.get(ns);
2393
+ if (existing !== void 0) return existing;
2394
+ const controller = new SchemaFormController(ns, {
2395
+ form: ctx.configForms.get(ns),
2396
+ describe,
2397
+ rehydrate,
2398
+ validate,
2399
+ t: ctx.locale.bind(NS),
2400
+ hints: {
2401
+ keysFor: (path) => hints.keysFor(ns, path),
2402
+ textFor: (path) => hints.textFor(ns, path),
2403
+ selectFor: (path) => hints.selectFor(ns, path),
2404
+ sourceFor: (name) => hints.sourceFor(name)
2405
+ }
2406
+ });
2407
+ const face = controller.face();
2408
+ const props = {
2409
+ ns,
2410
+ face,
2411
+ resolveText
2412
+ };
2413
+ const component = (entryProps) => entryProps.view === "page" ? entryProps.renderFactorySlot("settings.schema-form.form", props) : null;
2414
+ const entry = {
2415
+ controller,
2416
+ face,
2417
+ component
2418
+ };
2419
+ entries.set(ns, entry);
2420
+ return entry;
2421
+ };
2422
+ const registration = new RowRegistration({
2423
+ slots: ctx.slots,
2424
+ describe: ctx.configForms.describe(),
2425
+ bundles: async () => {
2426
+ const response = await ctx.remote.pluginManager.listBundles();
2427
+ return response.ok ? response.value : [];
2428
+ },
2429
+ subscribeBundles: (listener) => ctx.remote.$on("plugin-manager/changed", listener),
2430
+ entryFor,
2431
+ locale: NS,
2432
+ release: (ns) => {
2433
+ const entry = entries.get(ns);
2434
+ entries.delete(ns);
2435
+ entry?.controller.dispose();
2436
+ }
2437
+ });
2438
+ ctx.effect(() => {
2439
+ const offDescribe = ctx.configForms.describe().subscribe(() => {
2440
+ registration.sync();
2441
+ });
2442
+ const offHints = hints.subscribe(() => {
2443
+ for (const entry of entries.values()) entry.controller.refresh();
2444
+ });
2445
+ registration.sync();
2446
+ return () => {
2447
+ offDescribe();
2448
+ offHints();
2449
+ registration.dispose();
2450
+ for (const [ns, entry] of entries) {
2451
+ entries.delete(ns);
2452
+ entry.controller.dispose();
2453
+ }
2454
+ };
2455
+ }, "ui-schema-form: row registrations");
2456
+ }
2457
+ //#endregion
2458
+ //#region src/client/markdown-labels.ts
2459
+ function markdownLabels(t) {
2460
+ return {
2461
+ code: {
2462
+ copyLabel: t("copy"),
2463
+ copiedLabel: t("copied")
2464
+ },
2465
+ footnotes: t("markdown.footnotes")
2466
+ };
2467
+ }
2468
+ //#endregion
2469
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/layout/layout.module.css.mjs
2470
+ const css$13 = "._7Ar2dq_stack{flex-direction:column;min-width:0;display:flex}._7Ar2dq_row{flex-direction:row;align-items:center;min-width:0;display:flex}._7Ar2dq_gap0{gap:0}._7Ar2dq_gap2{gap:2px}._7Ar2dq_gap4{gap:4px}._7Ar2dq_gap6{gap:6px}._7Ar2dq_gap8{gap:8px}._7Ar2dq_gap10{gap:10px}._7Ar2dq_gap12{gap:12px}._7Ar2dq_gap14{gap:14px}._7Ar2dq_gap16{gap:16px}._7Ar2dq_alignStart{align-items:flex-start}._7Ar2dq_alignCenter{align-items:center}._7Ar2dq_alignEnd{align-items:flex-end}._7Ar2dq_justifyBetween{justify-content:space-between}._7Ar2dq_justifyEnd{justify-content:flex-end}._7Ar2dq_justifyCenter{justify-content:center}._7Ar2dq_wrap{flex-wrap:wrap}._7Ar2dq_grow{flex:auto;min-width:0}._7Ar2dq_push{margin-left:auto}._7Ar2dq_fill{box-sizing:border-box;width:100%;height:100%;overflow:hidden}._7Ar2dq_scroll{flex:auto;min-height:0;overflow-y:auto}._7Ar2dq_plain{margin:0;padding:0;list-style:none}._7Ar2dq_padNone{padding:0}._7Ar2dq_padCard{padding:8px 12px}._7Ar2dq_padBody{padding:8px 0}._7Ar2dq_padPage{padding:24px 28px}._7Ar2dq_padRow{padding:10px 12px}._7Ar2dq_padBlocking{padding:32px 40px}._7Ar2dq_text{margin:0}._7Ar2dq_sizeXs{font-size:11px;line-height:1.5}._7Ar2dq_sizeSm{font-size:12px;line-height:18px}._7Ar2dq_sizeMd{font-size:13px;line-height:20px}._7Ar2dq_sizeBase{font-size:14px;line-height:24px}._7Ar2dq_sizeLg{font-size:16px;line-height:24px}._7Ar2dq_tonePrimary{color:var(--dsw-alias-label-primary)}._7Ar2dq_toneSecondary{color:var(--dsw-alias-label-secondary)}._7Ar2dq_toneTertiary{color:var(--dsw-alias-label-tertiary)}._7Ar2dq_toneDanger{color:var(--dsw-alias-label-error,var(--dsw-alias-label-primary))}._7Ar2dq_weightMedium{font-weight:500}._7Ar2dq_strong{font-weight:600}._7Ar2dq_mono{word-break:break-all;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace}._7Ar2dq_truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._7Ar2dq_tabular{font-variant-numeric:tabular-nums}._7Ar2dq_boxed{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);border-radius:10px}._7Ar2dq_fixed{flex:none}._7Ar2dq_gapWide{gap:6px 20px}._7Ar2dq_narrow{min-width:0;max-width:min(calc(var(--dsh-chat-content-width,748px) * .702), 82%)}._7Ar2dq_wSearch{flex:none;width:360px;max-width:100%}";
2471
+ const tagId$13 = "@morlay/dsh-client-ui-primitives/layout.module.css";
2472
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/layout.module.css\"]") === null) {
2473
+ const tag = document.createElement("style");
2474
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2475
+ tag.dataset.pluginCss = tagId$13;
2476
+ tag.textContent = css$13;
2477
+ document.head.appendChild(tag);
2478
+ }
2479
+ var layout_module_css_default = {
2480
+ "toneSecondary": "_7Ar2dq_toneSecondary",
2481
+ "alignCenter": "_7Ar2dq_alignCenter",
2482
+ "toneTertiary": "_7Ar2dq_toneTertiary",
2483
+ "justifyBetween": "_7Ar2dq_justifyBetween",
2484
+ "grow": "_7Ar2dq_grow",
2485
+ "text": "_7Ar2dq_text",
2486
+ "padBlocking": "_7Ar2dq_padBlocking",
2487
+ "sizeMd": "_7Ar2dq_sizeMd",
2488
+ "narrow": "_7Ar2dq_narrow",
2489
+ "wrap": "_7Ar2dq_wrap",
2490
+ "strong": "_7Ar2dq_strong",
2491
+ "fill": "_7Ar2dq_fill",
2492
+ "gap8": "_7Ar2dq_gap8",
2493
+ "padPage": "_7Ar2dq_padPage",
2494
+ "sizeXs": "_7Ar2dq_sizeXs",
2495
+ "row": "_7Ar2dq_row",
2496
+ "sizeSm": "_7Ar2dq_sizeSm",
2497
+ "gap0": "_7Ar2dq_gap0",
2498
+ "toneDanger": "_7Ar2dq_toneDanger",
2499
+ "tonePrimary": "_7Ar2dq_tonePrimary",
2500
+ "weightMedium": "_7Ar2dq_weightMedium",
2501
+ "tabular": "_7Ar2dq_tabular",
2502
+ "sizeBase": "_7Ar2dq_sizeBase",
2503
+ "gap6": "_7Ar2dq_gap6",
2504
+ "mono": "_7Ar2dq_mono",
2505
+ "wSearch": "_7Ar2dq_wSearch",
2506
+ "gap12": "_7Ar2dq_gap12",
2507
+ "gap14": "_7Ar2dq_gap14",
2508
+ "alignStart": "_7Ar2dq_alignStart",
2509
+ "padBody": "_7Ar2dq_padBody",
2510
+ "scroll": "_7Ar2dq_scroll",
2511
+ "truncate": "_7Ar2dq_truncate",
2512
+ "padNone": "_7Ar2dq_padNone",
2513
+ "fixed": "_7Ar2dq_fixed",
2514
+ "padRow": "_7Ar2dq_padRow",
2515
+ "stack": "_7Ar2dq_stack",
2516
+ "gap4": "_7Ar2dq_gap4",
2517
+ "padCard": "_7Ar2dq_padCard",
2518
+ "push": "_7Ar2dq_push",
2519
+ "boxed": "_7Ar2dq_boxed",
2520
+ "gapWide": "_7Ar2dq_gapWide",
2521
+ "justifyCenter": "_7Ar2dq_justifyCenter",
2522
+ "plain": "_7Ar2dq_plain",
2523
+ "justifyEnd": "_7Ar2dq_justifyEnd",
2524
+ "gap10": "_7Ar2dq_gap10",
2525
+ "gap2": "_7Ar2dq_gap2",
2526
+ "sizeLg": "_7Ar2dq_sizeLg",
2527
+ "alignEnd": "_7Ar2dq_alignEnd",
2528
+ "gap16": "_7Ar2dq_gap16"
2529
+ };
2530
+ //#endregion
2531
+ //#region src/client/layout/scales.ts
2532
+ function gapClass(css, gap) {
2533
+ if (gap === void 0) return void 0;
2534
+ return gap === "wide" ? css.gapWide : css[`gap${gap}`];
2535
+ }
2536
+ function alignClass(css, align) {
2537
+ if (align === void 0 || align === "stretch") return void 0;
2538
+ if (align === "start") return css.alignStart;
2539
+ return align === "center" ? css.alignCenter : css.alignEnd;
2540
+ }
2541
+ function justifyClass(css, justify) {
2542
+ if (justify === void 0) return void 0;
2543
+ if (justify === "between") return css.justifyBetween;
2544
+ if (justify === "end") return css.justifyEnd;
2545
+ return justify === "center" ? css.justifyCenter : void 0;
2546
+ }
2547
+ function padClass(css, pad) {
2548
+ if (pad === void 0 || pad === "none") return void 0;
2549
+ if (pad === "card") return css.padCard;
2550
+ if (pad === "body") return css.padBody;
2551
+ if (pad === "page") return css.padPage;
2552
+ return pad === "row" ? css.padRow : css.padBlocking;
2553
+ }
2554
+ function sizeClass(css, size) {
2555
+ if (size === void 0) return void 0;
2556
+ if (size === "xs") return css.sizeXs;
2557
+ if (size === "sm") return css.sizeSm;
2558
+ if (size === "md") return css.sizeMd;
2559
+ return size === "base" ? css.sizeBase : css.sizeLg;
2560
+ }
2561
+ function toneClass(css, tone) {
2562
+ if (tone === void 0) return void 0;
2563
+ if (tone === "primary") return css.tonePrimary;
2564
+ if (tone === "secondary") return css.toneSecondary;
2565
+ return tone === "tertiary" ? css.toneTertiary : css.toneDanger;
2566
+ }
2567
+ function weightClass(css, weight) {
2568
+ if (weight === void 0) return void 0;
2569
+ return weight === "medium" ? css.weightMedium : css.strong;
2570
+ }
2571
+ //#endregion
2572
+ //#region src/client/layout/Row.tsx
2573
+ const Row = forwardRef(function Row({ as: Element = "div", gap, align, justify, wrap = false, grow = false, boxed = false, fixed = false, narrow = false, push = false, plain = false, pad, className, children, ...rest }, ref) {
2574
+ return /* @__PURE__ */ jsx(Element, {
2575
+ ref,
2576
+ className: classes(layout_module_css_default.row, gapClass(layout_module_css_default, gap), alignClass(layout_module_css_default, align), justifyClass(layout_module_css_default, justify), padClass(layout_module_css_default, pad), wrap ? layout_module_css_default.wrap : void 0, grow ? layout_module_css_default.grow : void 0, boxed ? layout_module_css_default.boxed : void 0, fixed ? layout_module_css_default.fixed : void 0, narrow ? layout_module_css_default.narrow : void 0, push ? layout_module_css_default.push : void 0, boxed ? layout_module_css_default.boxed : void 0, fixed ? layout_module_css_default.fixed : void 0, plain ? layout_module_css_default.plain : void 0, className),
2577
+ ...rest,
2578
+ children
2579
+ });
2580
+ });
2581
+ //#endregion
2582
+ //#region src/client/layout/Stack.tsx
2583
+ const Stack = forwardRef(function Stack({ as: Element = "div", gap, align, pad, grow = false, boxed = false, fixed = false, narrow = false, fill = false, scroll = false, plain = false, className, children, ...rest }, ref) {
2584
+ return /* @__PURE__ */ jsx(Element, {
2585
+ ref,
2586
+ className: classes(layout_module_css_default.stack, gapClass(layout_module_css_default, gap), alignClass(layout_module_css_default, align), padClass(layout_module_css_default, pad), grow ? layout_module_css_default.grow : void 0, boxed ? layout_module_css_default.boxed : void 0, fixed ? layout_module_css_default.fixed : void 0, narrow ? layout_module_css_default.narrow : void 0, fill ? layout_module_css_default.fill : void 0, scroll ? layout_module_css_default.scroll : void 0, plain ? layout_module_css_default.plain : void 0, className),
2587
+ ...rest,
2588
+ children
2589
+ });
2590
+ });
2591
+ //#endregion
2592
+ //#region src/client/layout/Text.tsx
2593
+ function Text({ as: Element = "span", size, tone, weight, mono = false, truncate = false, tabular = false, className, children }) {
2594
+ return /* @__PURE__ */ jsx(Element, {
2595
+ className: classes(layout_module_css_default.text, sizeClass(layout_module_css_default, size), toneClass(layout_module_css_default, tone), weightClass(layout_module_css_default, weight), mono ? layout_module_css_default.mono : void 0, truncate ? layout_module_css_default.truncate : void 0, tabular ? layout_module_css_default.tabular : void 0, className),
2596
+ children
2597
+ });
2598
+ }
2599
+ //#endregion
2600
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/settings-form/SettingsFieldRow.module.css.mjs
2601
+ const css$12 = ".Il1Dtq_row{flex-direction:column;display:flex}.Il1Dtq_row[data-divider=true]{border-top:.5px solid var(--dsw-alias-border-l2)}.Il1Dtq_body{flex-direction:column;gap:6px;padding:12px 0;display:flex}.Il1Dtq_inline{flex-direction:row;justify-content:space-between;align-items:center;gap:16px;padding:12px 0;display:flex}.Il1Dtq_text{flex-direction:column;gap:2px;min-width:0;display:flex}.Il1Dtq_label{color:var(--dsw-alias-label-primary);align-items:center;gap:8px;font-size:13px;font-weight:500;line-height:1.5;display:flex}.Il1Dtq_badge{corner-shape:round;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;align-items:center;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.Il1Dtq_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.Il1Dtq_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Il1Dtq_reset:disabled{cursor:default}.Il1Dtq_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.Il1Dtq_invalid{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}";
2602
+ const tagId$12 = "@morlay/dsh-client-ui-primitives/SettingsFieldRow.module.css";
2603
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/SettingsFieldRow.module.css\"]") === null) {
2604
+ const tag = document.createElement("style");
2605
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2606
+ tag.dataset.pluginCss = tagId$12;
2607
+ tag.textContent = css$12;
2608
+ document.head.appendChild(tag);
2609
+ }
2610
+ var SettingsFieldRow_module_css_default = {
2611
+ "inline": "Il1Dtq_inline",
2612
+ "reset": "Il1Dtq_reset",
2613
+ "hint": "Il1Dtq_hint",
2614
+ "text": "Il1Dtq_text",
2615
+ "badge": "Il1Dtq_badge",
2616
+ "body": "Il1Dtq_body",
2617
+ "row": "Il1Dtq_row",
2618
+ "label": "Il1Dtq_label",
2619
+ "invalid": "Il1Dtq_invalid"
2620
+ };
2621
+ //#endregion
2622
+ //#region src/client/settings-form/SettingsFieldRow.tsx
2623
+ function SettingsFieldRow({ label, hint, layout = "stack", divider = false, overriddenLabel, resetLabel, onReset, invalid, children, className, ...rest }) {
2624
+ const labelNode = /* @__PURE__ */ jsxs("span", {
2625
+ className: SettingsFieldRow_module_css_default.label,
2626
+ children: [label, overriddenLabel === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
2627
+ className: SettingsFieldRow_module_css_default.badge,
2628
+ children: overriddenLabel
2629
+ }), resetLabel === void 0 || onReset === void 0 ? null : /* @__PURE__ */ jsx("button", {
2630
+ type: "button",
2631
+ className: SettingsFieldRow_module_css_default.reset,
2632
+ onClick: () => {
2633
+ onReset();
2634
+ },
2635
+ children: resetLabel
2636
+ })] })]
2637
+ });
2638
+ const invalidNode = invalid === void 0 ? null : /* @__PURE__ */ jsx("p", {
2639
+ className: SettingsFieldRow_module_css_default.invalid,
2640
+ role: "alert",
2641
+ children: invalid
2642
+ });
2643
+ if (layout === "inline") return /* @__PURE__ */ jsxs("div", {
2644
+ className: classes(SettingsFieldRow_module_css_default.row, className),
2645
+ "data-role": "field-row",
2646
+ "data-divider": divider ? "true" : "false",
2647
+ ...rest,
2648
+ children: [/* @__PURE__ */ jsxs("div", {
2649
+ className: SettingsFieldRow_module_css_default.inline,
2650
+ children: [/* @__PURE__ */ jsxs("div", {
2651
+ className: SettingsFieldRow_module_css_default.text,
2652
+ children: [labelNode, /* @__PURE__ */ jsx("p", {
2653
+ className: SettingsFieldRow_module_css_default.hint,
2654
+ children: hint
2655
+ })]
2656
+ }), children]
2657
+ }), invalidNode]
2658
+ });
2659
+ return /* @__PURE__ */ jsxs("div", {
2660
+ className: classes(SettingsFieldRow_module_css_default.row, className),
2661
+ "data-role": "field-row",
2662
+ "data-divider": divider ? "true" : "false",
2663
+ ...rest,
2664
+ children: [/* @__PURE__ */ jsxs("div", {
2665
+ className: SettingsFieldRow_module_css_default.body,
2666
+ children: [
2667
+ labelNode,
2668
+ children,
2669
+ /* @__PURE__ */ jsx("p", {
2670
+ className: SettingsFieldRow_module_css_default.hint,
2671
+ children: hint
2672
+ })
2673
+ ]
2674
+ }), invalidNode]
2675
+ });
2676
+ }
2677
+ //#endregion
2678
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/Bubble.module.css.mjs
2679
+ const css$11 = ".Iy2DYG_bubble{background:var(--dsw-specific-bubble);border-radius:var(--dsw-radius-xl);max-width:100%;font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;padding:10px 16px}";
2680
+ const tagId$11 = "@morlay/dsh-client-ui-primitives/Bubble.module.css";
2681
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/Bubble.module.css\"]") === null) {
2682
+ const tag = document.createElement("style");
2683
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2684
+ tag.dataset.pluginCss = tagId$11;
2685
+ tag.textContent = css$11;
2686
+ document.head.appendChild(tag);
2687
+ }
2688
+ var Bubble_module_css_default = { "bubble": "Iy2DYG_bubble" };
2689
+ //#endregion
2690
+ //#region src/client/controls/Bubble.tsx
2691
+ function Bubble({ className, children, ...rest }) {
2692
+ return /* @__PURE__ */ jsx("div", {
2693
+ className: classes(Bubble_module_css_default.bubble, className),
2694
+ ...rest,
2695
+ children
2696
+ });
2697
+ }
2698
+ //#endregion
2699
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/Button.module.css.mjs
2700
+ const css$10 = ".LWgVXW_label{white-space:nowrap}.LWgVXW_danger{--dsw-alias-button-primary-fill:var(--dsw-alias-state-error-primary)}";
2701
+ const tagId$10 = "@morlay/dsh-client-ui-primitives/Button.module.css";
2702
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/Button.module.css\"]") === null) {
2703
+ const tag = document.createElement("style");
2704
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2705
+ tag.dataset.pluginCss = tagId$10;
2706
+ tag.textContent = css$10;
2707
+ document.head.appendChild(tag);
2708
+ }
2709
+ var Button_module_css_default = {
2710
+ "danger": "LWgVXW_danger",
2711
+ "label": "LWgVXW_label"
2712
+ };
2713
+ //#endregion
2714
+ //#region src/client/controls/Button.tsx
2715
+ const Button = forwardRef(function Button({ className, tone, ...rest }, ref) {
2716
+ return /* @__PURE__ */ jsx(Button$1, {
2717
+ ref,
2718
+ "data-role": "button",
2719
+ className: classes(className, Button_module_css_default.label, tone === "danger" ? Button_module_css_default.danger : void 0),
2720
+ ...rest
2721
+ });
2722
+ });
2723
+ //#endregion
2724
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/DisclosureRow.module.css.mjs
2725
+ const css$9 = "._2HN-kW_content{flex:auto;min-width:0}._2HN-kW_contentLayout{align-items:center;gap:8px;width:100%;min-width:0;display:flex}";
2726
+ const tagId$9 = "@morlay/dsh-client-ui-primitives/DisclosureRow.module.css";
2727
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/DisclosureRow.module.css\"]") === null) {
2728
+ const tag = document.createElement("style");
2729
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2730
+ tag.dataset.pluginCss = tagId$9;
2731
+ tag.textContent = css$9;
2732
+ document.head.appendChild(tag);
2733
+ }
2734
+ var DisclosureRow_module_css_default = {
2735
+ "contentLayout": "_2HN-kW_contentLayout",
2736
+ "content": "_2HN-kW_content"
2737
+ };
2738
+ //#endregion
2739
+ //#region src/client/controls/DisclosureRow.tsx
2740
+ function DisclosureRow(props) {
2741
+ return /* @__PURE__ */ jsx(DisclosureRow$1, {
2742
+ contentClassName: DisclosureRow_module_css_default.content,
2743
+ contentLayoutClassName: DisclosureRow_module_css_default.contentLayout,
2744
+ ...props
2745
+ });
2746
+ }
2747
+ //#endregion
2748
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/SeatButton.module.css.mjs
2749
+ const css$8 = ".JqQ4qG_seat{border-radius:var(--dsw-radius-sm);min-width:0;max-width:min(100%,240px);min-height:28px;color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border:none;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.JqQ4qG_seat:not(:disabled):hover,.JqQ4qG_seat[aria-expanded=true],.JqQ4qG_expanded{background:var(--dsw-alias-interactive-bg-hover)}.JqQ4qG_seat:disabled{cursor:default;color:var(--dsw-alias-label-quaternary)}.JqQ4qG_icon{color:var(--dsw-alias-label-primary);flex:none;align-items:center;display:inline-flex}.JqQ4qG_label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.JqQ4qG_chevron{color:var(--dsw-alias-label-caption);flex:none;display:inline-flex}";
2750
+ const tagId$8 = "@morlay/dsh-client-ui-primitives/SeatButton.module.css";
2751
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/SeatButton.module.css\"]") === null) {
2752
+ const tag = document.createElement("style");
2753
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2754
+ tag.dataset.pluginCss = tagId$8;
2755
+ tag.textContent = css$8;
2756
+ document.head.appendChild(tag);
2757
+ }
2758
+ var SeatButton_module_css_default = {
2759
+ "icon": "JqQ4qG_icon",
2760
+ "chevron": "JqQ4qG_chevron",
2761
+ "seat": "JqQ4qG_seat",
2762
+ "expanded": "JqQ4qG_expanded",
2763
+ "label": "JqQ4qG_label"
2764
+ };
2765
+ //#endregion
2766
+ //#region src/client/controls/SeatButton.tsx
2767
+ function SeatButton({ icon, label, expanded = false, chevron, type = "button", className, ...rest }) {
2768
+ return /* @__PURE__ */ jsxs("button", {
2769
+ type,
2770
+ className: classes(SeatButton_module_css_default.seat, expanded ? SeatButton_module_css_default.expanded : void 0, className),
2771
+ ...rest,
2772
+ children: [
2773
+ /* @__PURE__ */ jsx("span", {
2774
+ className: SeatButton_module_css_default.icon,
2775
+ children: icon
2776
+ }),
2777
+ /* @__PURE__ */ jsx("span", {
2778
+ className: SeatButton_module_css_default.label,
2779
+ children: label
2780
+ }),
2781
+ chevron === void 0 ? null : /* @__PURE__ */ jsx("span", {
2782
+ className: SeatButton_module_css_default.chevron,
2783
+ children: chevron
2784
+ })
2785
+ ]
2786
+ });
2787
+ }
2788
+ //#endregion
2789
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/Spinner.module.css.mjs
2790
+ const css$7 = "._1uNobG_spinner{border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;animation:.9s linear infinite _1uNobG_spin}@keyframes _1uNobG_spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}";
2791
+ const tagId$7 = "@morlay/dsh-client-ui-primitives/Spinner.module.css";
2792
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/Spinner.module.css\"]") === null) {
2793
+ const tag = document.createElement("style");
2794
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2795
+ tag.dataset.pluginCss = tagId$7;
2796
+ tag.textContent = css$7;
2797
+ document.head.appendChild(tag);
2798
+ }
2799
+ var Spinner_module_css_default = {
2800
+ "spinner": "_1uNobG_spinner",
2801
+ "spin": "_1uNobG_spin"
2802
+ };
2803
+ //#endregion
2804
+ //#region src/client/controls/Spinner.tsx
2805
+ function Spinner({ label }) {
2806
+ return /* @__PURE__ */ jsx("span", {
2807
+ className: Spinner_module_css_default.spinner,
2808
+ role: "status",
2809
+ "aria-label": label
2810
+ });
2811
+ }
2812
+ //#endregion
2813
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/TimeLabel.module.css.mjs
2814
+ const css$6 = ".P8Yiia_label{color:var(--dsw-alias-label-tertiary);white-space:nowrap;opacity:0;padding:0;font-size:14px;line-height:24px;transition:opacity 80ms}[data-time-hover-root]:hover .P8Yiia_label,[data-time-hover-root]:focus-within .P8Yiia_label{opacity:1}";
2815
+ const tagId$6 = "@morlay/dsh-client-ui-primitives/TimeLabel.module.css";
2816
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/TimeLabel.module.css\"]") === null) {
2817
+ const tag = document.createElement("style");
2818
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2819
+ tag.dataset.pluginCss = tagId$6;
2820
+ tag.textContent = css$6;
2821
+ document.head.appendChild(tag);
2822
+ }
2823
+ var TimeLabel_module_css_default = { "label": "P8Yiia_label" };
2824
+ //#endregion
2825
+ //#region src/client/controls/TimeLabel.tsx
2826
+ function TimeLabel({ className, children, ...rest }) {
2827
+ return /* @__PURE__ */ jsx("span", {
2828
+ className: classes(TimeLabel_module_css_default.label, className),
2829
+ ...rest,
2830
+ children
2831
+ });
2832
+ }
2833
+ //#endregion
2834
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/VisuallyHidden.module.css.mjs
2835
+ const css$5 = ".d5ueOG_hidden{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
2836
+ const tagId$5 = "@morlay/dsh-client-ui-primitives/VisuallyHidden.module.css";
2837
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/VisuallyHidden.module.css\"]") === null) {
2838
+ const tag = document.createElement("style");
2839
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2840
+ tag.dataset.pluginCss = tagId$5;
2841
+ tag.textContent = css$5;
2842
+ document.head.appendChild(tag);
2843
+ }
2844
+ var VisuallyHidden_module_css_default = { "hidden": "d5ueOG_hidden" };
2845
+ //#endregion
2846
+ //#region src/client/controls/VisuallyHidden.tsx
2847
+ function VisuallyHidden({ children, ...rest }) {
2848
+ return /* @__PURE__ */ jsx("span", {
2849
+ className: VisuallyHidden_module_css_default.hidden,
2850
+ ...rest,
2851
+ children
2852
+ });
2853
+ }
2854
+ //#endregion
2855
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/IconButton.module.css.mjs
2856
+ const css$4 = ".AibFna_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-secondary);border-radius:var(--dsw-radius-sm);cursor:pointer;background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.AibFna_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.AibFna_iconButton:disabled{cursor:not-allowed;opacity:.4}.AibFna_iconButton:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.AibFna_sm{width:20px;height:20px;padding:0}.AibFna_circle{color:var(--dsw-alias-label-tertiary);border-radius:28px;padding:6px}.AibFna_circle:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}";
2857
+ const tagId$4 = "@morlay/dsh-client-ui-primitives/IconButton.module.css";
2858
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/IconButton.module.css\"]") === null) {
2859
+ const tag = document.createElement("style");
2860
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2861
+ tag.dataset.pluginCss = tagId$4;
2862
+ tag.textContent = css$4;
2863
+ document.head.appendChild(tag);
2864
+ }
2865
+ var IconButton_module_css_default = {
2866
+ "circle": "AibFna_circle",
2867
+ "iconButton": "AibFna_iconButton",
2868
+ "sm": "AibFna_sm"
2869
+ };
2870
+ //#endregion
2871
+ //#region src/client/controls/IconButton.tsx
2872
+ function IconButton({ label, children, type = "button", shape = "square", size = "md", className, ...rest }) {
2873
+ return /* @__PURE__ */ jsx("button", {
2874
+ type,
2875
+ "data-role": "icon-button",
2876
+ "aria-label": label,
2877
+ className: classes(IconButton_module_css_default.iconButton, size === "sm" ? IconButton_module_css_default.sm : void 0, shape === "circle" ? IconButton_module_css_default.circle : void 0, className),
2878
+ ...rest,
2879
+ children
2880
+ });
2881
+ }
2882
+ //#endregion
2883
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/ModelRouteList.module.css.mjs
2884
+ const css$3 = "._1vK46q_list{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-lg);gap:6px;min-width:0;max-height:280px;margin:0;padding:10px;display:grid;overflow:auto}._1vK46q_group{gap:6px;display:grid}._1vK46q_group+._1vK46q_group{border-top:.5px solid var(--dsw-alias-border-l3);margin-top:4px;padding-top:10px}._1vK46q_provider{color:var(--dsw-alias-label-tertiary);padding:0 6px;font-size:11px;font-weight:500}._1vK46q_item{border-radius:var(--dsw-radius-md);cursor:pointer;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:8px;min-width:0;padding:6px;display:grid}._1vK46q_item:hover{background:var(--dsw-alias-bg-layer-4)}._1vK46q_item:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}._1vK46q_item[aria-disabled=true]{cursor:not-allowed;opacity:.4}._1vK46q_picked{background:var(--dsw-alias-interactive-bg-hover)}._1vK46q_text{min-width:0}._1vK46q_name{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);font-size:13px;display:block;overflow:hidden}._1vK46q_id{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:11px;display:block;overflow:hidden}._1vK46q_notice{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}._1vK46q_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}";
2885
+ const tagId$3 = "@morlay/dsh-client-ui-primitives/ModelRouteList.module.css";
2886
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/ModelRouteList.module.css\"]") === null) {
2887
+ const tag = document.createElement("style");
2888
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2889
+ tag.dataset.pluginCss = tagId$3;
2890
+ tag.textContent = css$3;
2891
+ document.head.appendChild(tag);
2892
+ }
2893
+ var ModelRouteList_module_css_default = {
2894
+ "group": "_1vK46q_group",
2895
+ "notice": "_1vK46q_notice",
2896
+ "error": "_1vK46q_error",
2897
+ "id": "_1vK46q_id",
2898
+ "text": "_1vK46q_text",
2899
+ "item": "_1vK46q_item",
2900
+ "provider": "_1vK46q_provider",
2901
+ "list": "_1vK46q_list",
2902
+ "name": "_1vK46q_name",
2903
+ "picked": "_1vK46q_picked"
2904
+ };
2905
+ //#endregion
2906
+ //#region src/client/controls/ModelRouteList.tsx
2907
+ function ModelRouteList({ label, candidates, selectedKey, disabled = false, status, loadingLabel, errorLabel, emptyLabel, onSelect }) {
2908
+ if (status === "loading") return /* @__PURE__ */ jsx("p", {
2909
+ className: ModelRouteList_module_css_default.notice,
2910
+ role: "status",
2911
+ children: loadingLabel
2912
+ });
2913
+ if (status === "error") return /* @__PURE__ */ jsx("p", {
2914
+ className: ModelRouteList_module_css_default.error,
2915
+ role: "alert",
2916
+ children: errorLabel
2917
+ });
2918
+ if (candidates.length === 0) return /* @__PURE__ */ jsx("p", {
2919
+ className: ModelRouteList_module_css_default.notice,
2920
+ children: emptyLabel
2921
+ });
2922
+ const groups = /* @__PURE__ */ new Map();
2923
+ for (const candidate of candidates) {
2924
+ const group = groups.get(candidate.provider);
2925
+ if (group === void 0) groups.set(candidate.provider, {
2926
+ name: candidate.providerName,
2927
+ items: [candidate]
2928
+ });
2929
+ else group.items.push(candidate);
2930
+ }
2931
+ return /* @__PURE__ */ jsx("div", {
2932
+ className: ModelRouteList_module_css_default.list,
2933
+ "data-role": "model-route-list",
2934
+ role: "radiogroup",
2935
+ "aria-label": label,
2936
+ "data-control": "model-routes",
2937
+ children: [...groups].map(([provider, group]) => /* @__PURE__ */ jsxs("div", {
2938
+ className: ModelRouteList_module_css_default.group,
2939
+ "data-route-group": provider,
2940
+ children: [/* @__PURE__ */ jsx("span", {
2941
+ className: ModelRouteList_module_css_default.provider,
2942
+ children: group.name
2943
+ }), group.items.map((candidate) => {
2944
+ const picked = candidate.key === selectedKey;
2945
+ return /* @__PURE__ */ jsxs("div", {
2946
+ className: classes(ModelRouteList_module_css_default.item, picked ? ModelRouteList_module_css_default.picked : void 0),
2947
+ role: "radio",
2948
+ "aria-checked": picked,
2949
+ "aria-label": `${candidate.modelName} ${candidate.provider}/${candidate.model}`,
2950
+ "aria-disabled": disabled ? true : void 0,
2951
+ tabIndex: disabled ? -1 : 0,
2952
+ "data-route": candidate.key,
2953
+ onClick: () => {
2954
+ if (!disabled) onSelect(candidate);
2955
+ },
2956
+ onKeyDown: (event) => {
2957
+ if (event.key !== "Enter" && event.key !== " ") return;
2958
+ event.preventDefault();
2959
+ if (!disabled) onSelect(candidate);
2960
+ },
2961
+ children: [picked ? /* @__PURE__ */ jsx(IconCheckOutlineRegular, {}) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true" }), /* @__PURE__ */ jsxs("span", {
2962
+ className: ModelRouteList_module_css_default.text,
2963
+ children: [/* @__PURE__ */ jsx("span", {
2964
+ className: ModelRouteList_module_css_default.name,
2965
+ children: candidate.modelName
2966
+ }), /* @__PURE__ */ jsx("span", {
2967
+ className: ModelRouteList_module_css_default.id,
2968
+ children: `${candidate.providerName} · ${candidate.provider}/${candidate.model}`
2969
+ })]
2970
+ })]
2971
+ }, candidate.key);
2972
+ })]
2973
+ }, provider))
2974
+ });
2975
+ }
2976
+ //#endregion
2977
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/MultilineField.module.css.mjs
2978
+ const css$2 = ".V0rRdq_multiline{box-sizing:border-box;width:100%;min-height:64px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);resize:vertical;padding:6px 12px;font-family:inherit;font-size:13px;line-height:1.5}.V0rRdq_multiline:disabled{cursor:not-allowed;opacity:.4}.V0rRdq_multiline:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}";
2979
+ const tagId$2 = "@morlay/dsh-client-ui-primitives/MultilineField.module.css";
2980
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/MultilineField.module.css\"]") === null) {
2981
+ const tag = document.createElement("style");
2982
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
2983
+ tag.dataset.pluginCss = tagId$2;
2984
+ tag.textContent = css$2;
2985
+ document.head.appendChild(tag);
2986
+ }
2987
+ var MultilineField_module_css_default = { "multiline": "V0rRdq_multiline" };
2988
+ //#endregion
2989
+ //#region src/client/controls/MultilineField.tsx
2990
+ function MultilineField({ rows = 3, className, ...rest }) {
2991
+ return /* @__PURE__ */ jsx("textarea", {
2992
+ rows,
2993
+ "data-role": "multiline-field",
2994
+ className: classes(MultilineField_module_css_default.multiline, className),
2995
+ ...rest
2996
+ });
2997
+ }
2998
+ //#endregion
2999
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/SearchSelect.module.css.mjs
3000
+ const css$1 = ".kEYv4q_trigger{white-space:nowrap;height:32px}.kEYv4q_searchRow{border-bottom:.5px solid var(--dsw-alias-border-l2);align-items:center;padding:4px 8px 8px;display:flex}.kEYv4q_searchInput{width:100%;color:var(--dsw-alias-label-primary);background:0 0;border:none;outline:none;padding:2px 0;font-family:inherit;font-size:13px;line-height:1.5}.kEYv4q_empty{color:var(--dsw-alias-label-tertiary);margin:0;padding:8px;font-size:12px;line-height:1.5}";
3001
+ const tagId$1 = "@morlay/dsh-client-ui-primitives/SearchSelect.module.css";
3002
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/SearchSelect.module.css\"]") === null) {
3003
+ const tag = document.createElement("style");
3004
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
3005
+ tag.dataset.pluginCss = tagId$1;
3006
+ tag.textContent = css$1;
3007
+ document.head.appendChild(tag);
3008
+ }
3009
+ var SearchSelect_module_css_default = {
3010
+ "searchRow": "kEYv4q_searchRow",
3011
+ "empty": "kEYv4q_empty",
3012
+ "searchInput": "kEYv4q_searchInput",
3013
+ "trigger": "kEYv4q_trigger"
3014
+ };
3015
+ //#endregion
3016
+ //#region src/client/controls/SearchSelect.tsx
3017
+ function SearchSelect({ label, value, emptyLabel, options, disabled = false, searchLabel, noMatchLabel, onSelect }) {
3018
+ const [open, setOpen] = useState(false);
3019
+ const [query, setQuery] = useState("");
3020
+ const searchRef = useRef(null);
3021
+ useEffect(() => {
3022
+ if (open) searchRef.current?.focus();
3023
+ }, [open]);
3024
+ const matches = useMemo(() => rankByName(options.map((option) => ({
3025
+ value: option.value,
3026
+ name: option.label ?? option.value,
3027
+ label: option.value
3028
+ })), query), [options, query]);
3029
+ const current = options.find((option) => option.value === value);
3030
+ const close = () => {
3031
+ setOpen(false);
3032
+ setQuery("");
3033
+ };
3034
+ const pick = (next) => {
3035
+ close();
3036
+ onSelect(next);
3037
+ };
3038
+ return /* @__PURE__ */ jsxs(Menu, {
3039
+ open,
3040
+ anchor: /* @__PURE__ */ jsx(Button$1, {
3041
+ variant: "outline",
3042
+ size: "sm",
3043
+ "data-role": "search-select",
3044
+ className: classes(SearchSelect_module_css_default.trigger),
3045
+ "data-action": "pick",
3046
+ disabled,
3047
+ "aria-haspopup": "menu",
3048
+ "aria-label": label,
3049
+ onClick: () => {
3050
+ if (open) close();
3051
+ else setOpen(true);
3052
+ },
3053
+ children: value === "" ? emptyLabel : current?.label ?? value
3054
+ }),
3055
+ selectedId: value,
3056
+ onSelect: pick,
3057
+ onClose: close,
3058
+ children: [
3059
+ /* @__PURE__ */ jsx("div", {
3060
+ className: SearchSelect_module_css_default.searchRow,
3061
+ children: /* @__PURE__ */ jsx("input", {
3062
+ className: SearchSelect_module_css_default.searchInput,
3063
+ ref: searchRef,
3064
+ value: query,
3065
+ "aria-label": searchLabel,
3066
+ placeholder: searchLabel,
3067
+ onChange: (event) => {
3068
+ setQuery(event.currentTarget.value);
3069
+ }
3070
+ })
3071
+ }),
3072
+ /* @__PURE__ */ jsx(MenuItemButton, {
3073
+ icon: value === "" ? /* @__PURE__ */ jsx(IconCheckOutlineRegular, {}) : void 0,
3074
+ onSelect: () => {
3075
+ pick("");
3076
+ },
3077
+ children: emptyLabel
3078
+ }),
3079
+ matches.map((option) => /* @__PURE__ */ jsx(MenuItemButton, {
3080
+ icon: option.value === value ? /* @__PURE__ */ jsx(IconCheckOutlineRegular, {}) : void 0,
3081
+ onSelect: () => {
3082
+ pick(option.value);
3083
+ },
3084
+ children: option.name
3085
+ }, option.value)),
3086
+ matches.length === 0 ? /* @__PURE__ */ jsx("p", {
3087
+ className: SearchSelect_module_css_default.empty,
3088
+ children: noMatchLabel
3089
+ }) : null
3090
+ ]
3091
+ });
3092
+ }
3093
+ //#endregion
3094
+ //#region src/client/controls/tags.ts
3095
+ function parseTagList(text) {
3096
+ const seen = /* @__PURE__ */ new Set();
3097
+ const names = [];
3098
+ for (const raw of text.split(/[,,;;\t\n\r]+/u)) {
3099
+ const name = raw.trim();
3100
+ if (name === "" || seen.has(name)) continue;
3101
+ seen.add(name);
3102
+ names.push(name);
3103
+ }
3104
+ return names;
3105
+ }
3106
+ function mergeTags(current, incoming) {
3107
+ const merged = [...current];
3108
+ for (const name of incoming) {
3109
+ if (name === "" || merged.includes(name)) continue;
3110
+ merged.push(name);
3111
+ }
3112
+ return merged;
3113
+ }
3114
+ //#endregion
3115
+ //#region \0dsh-css-modules:/Users/morlay/src/github.com/morlay/dsh-plugin/packages/client/dsh-client-ui-primitives/src/client/controls/TagInput.module.css.mjs
3116
+ const css = ".Qg7I9G_row{align-items:flex-start;gap:8px;width:100%;display:flex}.Qg7I9G_anchor{flex:auto;width:100%;min-width:0;display:flex}.Qg7I9G_box{box-sizing:border-box;background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);flex-flow:wrap;align-items:center;gap:4px 6px;width:100%;min-height:32px;padding:4px 8px;display:flex}.Qg7I9G_input{min-width:120px;color:var(--dsw-alias-label-primary);background:0 0;border:none;outline:none;flex:120px;padding:2px 0;font-family:inherit;font-size:13px;line-height:1.5}.Qg7I9G_chip{corner-shape:round;white-space:nowrap;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;align-items:center;gap:2px;padding:1px 4px 1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.Qg7I9G_chipRemove{box-sizing:border-box;width:14px;height:14px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:999px;flex:none;justify-content:center;align-items:center;padding:0;line-height:1;display:inline-flex}.Qg7I9G_chipRemove:hover:not(:disabled){color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.Qg7I9G_chipRemove:disabled{cursor:not-allowed;opacity:.4}.Qg7I9G_chipRemove:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:0}.Qg7I9G_empty{color:var(--dsw-alias-label-tertiary);margin:0;padding:8px;font-size:12px;line-height:1.5}";
3117
+ const tagId = "@morlay/dsh-client-ui-primitives/TagInput.module.css";
3118
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@morlay/dsh-client-ui-primitives/TagInput.module.css\"]") === null) {
3119
+ const tag = document.createElement("style");
3120
+ tag.dataset.plugin = "@morlay/dsh-client-ui-primitives";
3121
+ tag.dataset.pluginCss = tagId;
3122
+ tag.textContent = css;
3123
+ document.head.appendChild(tag);
3124
+ }
3125
+ var TagInput_module_css_default = {
3126
+ "input": "Qg7I9G_input",
3127
+ "row": "Qg7I9G_row",
3128
+ "box": "Qg7I9G_box",
3129
+ "chip": "Qg7I9G_chip",
3130
+ "anchor": "Qg7I9G_anchor",
3131
+ "chipRemove": "Qg7I9G_chipRemove",
3132
+ "empty": "Qg7I9G_empty"
3133
+ };
3134
+ //#endregion
3135
+ //#region src/client/controls/TagInput.tsx
3136
+ function TagInput({ value, onChange, options, placeholder, label, disabled = false, noMatchLabel = "", removeLabel }) {
3137
+ const [draft, setDraft] = useState("");
3138
+ const [open, setOpen] = useState(false);
3139
+ const commit = (text) => {
3140
+ const names = parseTagList(text);
3141
+ if (names.length === 0) return;
3142
+ onChange(mergeTags(value, names));
3143
+ setDraft("");
3144
+ };
3145
+ const remaining = useMemo(() => (options ?? []).filter((option) => !value.includes(option.value)).map((option) => ({
3146
+ value: option.value,
3147
+ name: option.label ?? option.value,
3148
+ label: option.value
3149
+ })), [options, value]);
3150
+ const matches = useMemo(() => rankByName(remaining, draft), [remaining, draft]);
3151
+ return /* @__PURE__ */ jsx("div", {
3152
+ className: TagInput_module_css_default.row,
3153
+ "data-role": "tag-input",
3154
+ "data-control": "tags",
3155
+ children: /* @__PURE__ */ jsxs(Menu, {
3156
+ open: open && remaining.length > 0,
3157
+ className: TagInput_module_css_default.anchor,
3158
+ anchor: /* @__PURE__ */ jsxs("div", {
3159
+ className: TagInput_module_css_default.box,
3160
+ children: [value.map((name) => /* @__PURE__ */ jsxs("span", {
3161
+ className: TagInput_module_css_default.chip,
3162
+ "data-tag": name,
3163
+ children: [name, /* @__PURE__ */ jsx("button", {
3164
+ type: "button",
3165
+ className: TagInput_module_css_default.chipRemove,
3166
+ "data-action": "remove-tag",
3167
+ disabled,
3168
+ "aria-label": removeLabel(name),
3169
+ onClick: () => {
3170
+ onChange(value.filter((candidate) => candidate !== name));
3171
+ },
3172
+ children: /* @__PURE__ */ jsx(IconCloseOutlineRegular, { size: 10 })
3173
+ })]
3174
+ }, name)), /* @__PURE__ */ jsx("input", {
3175
+ className: TagInput_module_css_default.input,
3176
+ value: draft,
3177
+ placeholder: value.length === 0 ? placeholder : "",
3178
+ "aria-label": label,
3179
+ disabled,
3180
+ onFocus: () => {
3181
+ setOpen(true);
3182
+ },
3183
+ onBlur: () => {
3184
+ setOpen(false);
3185
+ },
3186
+ onChange: (event) => {
3187
+ setDraft(event.currentTarget.value);
3188
+ },
3189
+ onKeyDown: (event) => {
3190
+ if (event.key !== "Enter") return;
3191
+ event.preventDefault();
3192
+ commit(draft);
3193
+ },
3194
+ onPaste: (event) => {
3195
+ const text = event.clipboardData.getData("text");
3196
+ if (parseTagList(text).length < 2) return;
3197
+ event.preventDefault();
3198
+ commit(text);
3199
+ }
3200
+ })]
3201
+ }),
3202
+ onClose: () => {
3203
+ setOpen(false);
3204
+ },
3205
+ children: [matches.map((candidate) => /* @__PURE__ */ jsx("span", {
3206
+ onMouseDown: (event) => {
3207
+ event.preventDefault();
3208
+ },
3209
+ children: /* @__PURE__ */ jsx(MenuItemButton, {
3210
+ onSelect: () => {
3211
+ commit(candidate.value);
3212
+ },
3213
+ children: candidate.name
3214
+ })
3215
+ }, candidate.value)), matches.length === 0 ? /* @__PURE__ */ jsx("p", {
3216
+ className: TagInput_module_css_default.empty,
3217
+ "data-role": "tag-input-empty",
3218
+ children: noMatchLabel
3219
+ }) : null]
3220
+ })
3221
+ });
3222
+ }
3223
+ //#endregion
3224
+ //#region src/reference.ts
3225
+ const DEFAULT_PROTOCOL = "file";
3226
+ const EXTERNAL_PROTOCOLS = [
3227
+ "http",
3228
+ "https",
3229
+ "mailto"
3230
+ ];
3231
+ const LINE_FRAGMENT = /^L(\d+)(?:C(\d+))?(?:-L(\d+))?$/u;
3232
+ const SCHEME = /^([A-Za-z][A-Za-z0-9+.-]*):/u;
3233
+ const BARE_PATH = /^([^:]+):(\d+)(?::(\d+))?$/u;
3234
+ const MENTION_WHITESPACE = /\s/u;
3235
+ const URI_UNSAFE = /[%#()\s<>"`]/gu;
3236
+ const PATH_PUNCTUATION = [
3237
+ codes.slash,
3238
+ codes.dash,
3239
+ codes.underscore,
3240
+ codes.dot,
3241
+ codes.plusSign,
3242
+ codes.percentSign,
3243
+ codes.atSign,
3244
+ codes.tilde,
3245
+ codes.equalsTo
3246
+ ];
3247
+ const TRIGGERS = [
3248
+ ":",
3249
+ "[",
3250
+ "@"
3251
+ ];
3252
+ function parseReference(value, title) {
3253
+ const raw = value.trim();
3254
+ if (raw === "") return void 0;
3255
+ const matched = SCHEME.exec(raw);
3256
+ const protocol = matched === null ? DEFAULT_PROTOCOL : matched[1].toLowerCase();
3257
+ let rest = matched === null ? raw : raw.slice(matched[0].length);
3258
+ if (matched !== null && /\s/u.test(rest)) return void 0;
3259
+ const fragment = splitLineFragment(rest);
3260
+ rest = fragment.head;
3261
+ let origin;
3262
+ if (rest.startsWith("//")) {
3263
+ const end = authorityEnd(rest);
3264
+ const authority = rest.slice(2, end);
3265
+ if (authority === "") return void 0;
3266
+ origin = `${protocol}://${authority}`;
3267
+ rest = rest.slice(end).replace(/^\//u, "");
3268
+ }
3269
+ const decoded = protocol === DEFAULT_PROTOCOL ? decodeUri(rest) : rest;
3270
+ if (decoded === void 0 || decoded === "" && origin === void 0) return void 0;
3271
+ return {
3272
+ protocol,
3273
+ ...origin === void 0 ? {} : { origin },
3274
+ ...decoded === "" ? {} : { path: decoded },
3275
+ ...title === void 0 || title === "" ? {} : { title },
3276
+ ...fragment.lines
3277
+ };
3278
+ }
3279
+ function parseReferenceToken(value) {
3280
+ return SCHEME.test(value) ? parseReference(value) : void 0;
3281
+ }
3282
+ function formatReference(reference) {
3283
+ const protocol = reference.protocol === "" ? DEFAULT_PROTOCOL : reference.protocol;
3284
+ const path = reference.path ?? "";
3285
+ if (reference.origin !== void 0) return `${reference.origin}${path === "" ? "" : `/${path}`}`;
3286
+ return `${protocol}:${encodeUri(path)}${lineFragmentOf(reference)}`;
3287
+ }
3288
+ function isLocalReference(reference) {
3289
+ return !EXTERNAL_PROTOCOLS.includes(reference.protocol);
3290
+ }
3291
+ function formatReferenceMention(reference) {
3292
+ const path = reference.path ?? "";
3293
+ return MENTION_WHITESPACE.test(path) ? `@"${path}"` : `@${path}`;
3294
+ }
3295
+ function findReferences(text) {
3296
+ const spans = [];
3297
+ if (text === "" || !TRIGGERS.some((trigger) => text.includes(trigger))) return spans;
3298
+ collectReferences(parseReferenceDocument(text), spans);
3299
+ return spans;
3300
+ }
3301
+ function parseReferenceDocument(text) {
3302
+ return fromMarkdown(text, {
3303
+ extensions: [gfm(), referenceSyntax()],
3304
+ mdastExtensions: [gfmFromMarkdown(), referenceFromMarkdown()]
3305
+ });
3306
+ }
3307
+ function collectReferences(node, spans) {
3308
+ const position = node.position;
3309
+ if (node.type === "reference" && position !== void 0) {
3310
+ const reference = referenceOfNode(node);
3311
+ if (reference !== void 0) spans.push({
3312
+ start: position.start.offset,
3313
+ end: position.end.offset,
3314
+ reference
3315
+ });
3316
+ }
3317
+ for (const child of node.children ?? []) collectReferences(child, spans);
3318
+ }
3319
+ function referenceOfNode(node) {
3320
+ const protocol = node.protocol;
3321
+ if (protocol === void 0) return void 0;
3322
+ return {
3323
+ protocol,
3324
+ ...node.origin === void 0 ? {} : { origin: node.origin },
3325
+ ...node.path === void 0 ? {} : { path: node.path },
3326
+ ...node.title === void 0 ? {} : { title: node.title },
3327
+ ...node.lineStart === void 0 ? {} : { lineStart: node.lineStart },
3328
+ ...node.lineEnd === void 0 ? {} : { lineEnd: node.lineEnd },
3329
+ ...node.column === void 0 ? {} : { column: node.column }
3330
+ };
3331
+ }
3332
+ const previousReference = function(code) {
3333
+ return isBoundary(code);
3334
+ };
3335
+ const tokenizeReference = function(effects, ok, nok) {
3336
+ const { events } = this;
3337
+ let at = false;
3338
+ let head = "";
3339
+ return start;
3340
+ function start(code) {
3341
+ if (insideLabel(events)) return nok(code);
3342
+ effects.enter("reference");
3343
+ if (code === codes.atSign) {
3344
+ at = true;
3345
+ effects.consume(code);
3346
+ return afterAt;
3347
+ }
3348
+ return headStart(code);
3349
+ }
3350
+ function afterAt(code) {
3351
+ if (code === codes.quotationMark) {
3352
+ effects.consume(code);
3353
+ return quotedPath;
3354
+ }
3355
+ return asciiAlpha(code) ? headStart(code) : pathStart(code);
3356
+ }
3357
+ function quotedPath(code) {
3358
+ if (code === null || markdownLineEnding(code)) return nok(code);
3359
+ effects.consume(code);
3360
+ return code === codes.quotationMark ? afterQuotedPath : quotedPath;
3361
+ }
3362
+ function afterQuotedPath(code) {
3363
+ if (code !== codes.numberSign) return finish(code);
3364
+ effects.consume(code);
3365
+ return fragmentInside;
3366
+ }
3367
+ function fragmentInside(code) {
3368
+ if (isPathCode(code) || code === codes.numberSign) {
3369
+ effects.consume(code);
3370
+ return fragmentInside;
3371
+ }
3372
+ return finish(code);
3373
+ }
3374
+ function headStart(code) {
3375
+ if (!asciiAlpha(code)) return nok(code);
3376
+ head = "";
3377
+ return headInside(code);
3378
+ }
3379
+ function headInside(code) {
3380
+ if (code === null || !asciiAlpha(code)) return afterHead(code);
3381
+ head += String.fromCodePoint(code);
3382
+ effects.consume(code);
3383
+ return headInside;
3384
+ }
3385
+ function afterHead(code) {
3386
+ if (code === codes.colon && isKnownScheme(head)) {
3387
+ effects.consume(code);
3388
+ return head.toLowerCase() === "skill" ? skillInside : fileInside;
3389
+ }
3390
+ return at ? pathInside(code) : nok(code);
3391
+ }
3392
+ function pathStart(code) {
3393
+ if (!isPathCode(code) || code === codes.atSign) return nok(code);
3394
+ effects.consume(code);
3395
+ return pathInside;
3396
+ }
3397
+ function fileInside(code) {
3398
+ if (!isFileCode(code)) return nok(code);
3399
+ effects.consume(code);
3400
+ return fileRest;
3401
+ }
3402
+ function fileRest(code) {
3403
+ if (isFileCode(code)) {
3404
+ effects.consume(code);
3405
+ return fileRest;
3406
+ }
3407
+ return finish(code);
3408
+ }
3409
+ function skillInside(code) {
3410
+ if (!isSkillCode(code)) return nok(code);
3411
+ effects.consume(code);
3412
+ return skillRest;
3413
+ }
3414
+ function skillRest(code) {
3415
+ if (isSkillCode(code)) {
3416
+ effects.consume(code);
3417
+ return skillRest;
3418
+ }
3419
+ return finish(code);
3420
+ }
3421
+ function pathInside(code) {
3422
+ if (isPathCode(code) || code === codes.numberSign) {
3423
+ effects.consume(code);
3424
+ return pathInside;
3425
+ }
3426
+ if (code !== codes.colon) return isBoundary(code) ? finish(code) : nok(code);
3427
+ effects.consume(code);
3428
+ return lineInside;
3429
+ }
3430
+ function lineInside(code) {
3431
+ if (!asciiDigit(code)) return nok(code);
3432
+ effects.consume(code);
3433
+ return lineRest;
3434
+ }
3435
+ function lineRest(code) {
3436
+ if (asciiDigit(code)) {
3437
+ effects.consume(code);
3438
+ return lineRest;
3439
+ }
3440
+ if (code !== codes.colon) return finish(code);
3441
+ effects.consume(code);
3442
+ return columnInside;
3443
+ }
3444
+ function columnInside(code) {
3445
+ if (!asciiDigit(code)) return nok(code);
3446
+ effects.consume(code);
3447
+ return columnRest;
3448
+ }
3449
+ function columnRest(code) {
3450
+ if (asciiDigit(code)) {
3451
+ effects.consume(code);
3452
+ return columnRest;
3453
+ }
3454
+ return finish(code);
3455
+ }
3456
+ function finish(code) {
3457
+ if (!isBoundary(code)) return nok(code);
3458
+ effects.exit("reference");
3459
+ return ok(code);
3460
+ }
3461
+ };
3462
+ const referenceConstruct = {
3463
+ name: "reference",
3464
+ previous: previousReference,
3465
+ tokenize: tokenizeReference
3466
+ };
3467
+ const referenceSyntaxExtension = { text: {
3468
+ [codes.atSign]: referenceConstruct,
3469
+ [codes.lowercaseF]: referenceConstruct,
3470
+ [codes.uppercaseF]: referenceConstruct,
3471
+ [codes.lowercaseS]: referenceConstruct,
3472
+ [codes.uppercaseS]: referenceConstruct
3473
+ } };
3474
+ function referenceSyntax() {
3475
+ return referenceSyntaxExtension;
3476
+ }
3477
+ function insideLabel(events) {
3478
+ for (let index = events.length - 1; index >= 0; index -= 1) {
3479
+ const token = events[index]?.[1];
3480
+ if (token === void 0) continue;
3481
+ if ((token.type === types.labelLink || token.type === types.labelImage) && token._balanced !== true) return true;
3482
+ }
3483
+ return false;
3484
+ }
3485
+ function isBoundary(code) {
3486
+ return code === null || markdownLineEndingOrSpace(code) || unicodeWhitespace(code) || unicodePunctuation(code);
3487
+ }
3488
+ function isPathCode(code) {
3489
+ if (code === null || markdownLineEndingOrSpace(code)) return false;
3490
+ if (!unicodePunctuation(code)) return true;
3491
+ return PATH_PUNCTUATION.includes(code);
3492
+ }
3493
+ function isFileCode(code) {
3494
+ return isPathCode(code) || code === codes.numberSign || code === codes.colon;
3495
+ }
3496
+ function isSkillCode(code) {
3497
+ return asciiAlphanumeric(code) || code === codes.dash || code === codes.underscore || code === codes.dot;
3498
+ }
3499
+ function enterReference(token) {
3500
+ this.enter({ type: "reference" }, token);
3501
+ }
3502
+ function exitReference(token) {
3503
+ const node = this.stack[this.stack.length - 1];
3504
+ const raw = this.sliceSerialize(token);
3505
+ const reference = parseBareReference(raw);
3506
+ if (node !== void 0) {
3507
+ if (reference === void 0) {
3508
+ node.type = "text";
3509
+ node.value = raw;
3510
+ } else Object.assign(node, reference);
3511
+ }
3512
+ this.exit(token);
3513
+ }
3514
+ const transformLinks = function(tree) {
3515
+ convertLinks(tree);
3516
+ };
3517
+ function convertLinks(parent) {
3518
+ const children = parent.children;
3519
+ if (children === void 0) return;
3520
+ for (let index = 0; index < children.length; index += 1) {
3521
+ const child = children[index];
3522
+ if (child === void 0) continue;
3523
+ if (child.type === "link") {
3524
+ const reference = parseReference(child.url ?? "", labelOf(child));
3525
+ if (reference !== void 0) {
3526
+ children[index] = referenceNodeOf(reference, child, children[index - 1]);
3527
+ continue;
3528
+ }
3529
+ }
3530
+ convertLinks(child);
3531
+ }
3532
+ }
3533
+ function referenceNodeOf(reference, link, previous) {
3534
+ const node = {
3535
+ type: "reference",
3536
+ ...reference
3537
+ };
3538
+ const position = link.position;
3539
+ if (position === void 0) return node;
3540
+ node.position = startsAfterAt(previous, position.start) ? atStart(position) : position;
3541
+ return node;
3542
+ }
3543
+ function startsAfterAt(previous, start) {
3544
+ if (previous?.type !== "text" || previous.value?.endsWith("@") !== true) return false;
3545
+ const position = previous.position;
3546
+ if (position === void 0 || position.end.offset !== start.offset) return false;
3547
+ return position.end.offset - position.start.offset === previous.value.length;
3548
+ }
3549
+ function atStart(position) {
3550
+ return {
3551
+ start: {
3552
+ line: position.start.line,
3553
+ column: position.start.column - 1,
3554
+ offset: position.start.offset - 1
3555
+ },
3556
+ end: position.end
3557
+ };
3558
+ }
3559
+ function labelOf(node) {
3560
+ const label = textOf(node);
3561
+ return label === "" ? void 0 : label;
3562
+ }
3563
+ function textOf(node) {
3564
+ if (node.value !== void 0) return node.value;
3565
+ let text = "";
3566
+ for (const child of node.children ?? []) text += textOf(child);
3567
+ return text;
3568
+ }
3569
+ function parseBareReference(raw) {
3570
+ const body = raw.startsWith("@") ? raw.slice(1) : raw;
3571
+ if (body === "") return void 0;
3572
+ if (body.startsWith(QUOTED_PATH)) return parseQuotedReference(body);
3573
+ const scheme = SCHEME.exec(body);
3574
+ if (scheme !== null && isKnownScheme(scheme[1])) return parseReference(body);
3575
+ const matched = BARE_PATH.exec(body);
3576
+ const path = matched?.[1];
3577
+ const line = matched?.[2];
3578
+ if (path === void 0 || line === void 0) return parseReference(body);
3579
+ const decoded = decodeUri(path);
3580
+ if (decoded === void 0 || decoded === "") return void 0;
3581
+ const column = matched?.[3];
3582
+ return {
3583
+ protocol: DEFAULT_PROTOCOL,
3584
+ path: decoded,
3585
+ lineStart: Number(line),
3586
+ ...column === void 0 ? {} : { column: Number(column) }
3587
+ };
3588
+ }
3589
+ const QUOTED_PATH = "\"";
3590
+ function parseQuotedReference(body) {
3591
+ const end = body.indexOf(QUOTED_PATH, 1);
3592
+ if (end === -1) return void 0;
3593
+ const path = body.slice(1, end);
3594
+ if (path === "") return void 0;
3595
+ const fragment = splitLineFragment(body.slice(end + 1));
3596
+ if (fragment.head !== "") return void 0;
3597
+ return {
3598
+ protocol: DEFAULT_PROTOCOL,
3599
+ path,
3600
+ ...fragment.lines
3601
+ };
3602
+ }
3603
+ function referenceFromMarkdown() {
3604
+ return {
3605
+ enter: { reference: enterReference },
3606
+ exit: { reference: exitReference },
3607
+ transforms: [transformLinks]
3608
+ };
3609
+ }
3610
+ function isKnownScheme(name) {
3611
+ const protocol = name.toLowerCase();
3612
+ return protocol === "file" || protocol === "skill";
3613
+ }
3614
+ function splitLineFragment(value) {
3615
+ const hashAt = value.indexOf("#");
3616
+ if (hashAt === -1) return {
3617
+ head: value,
3618
+ lines: {}
3619
+ };
3620
+ const matched = LINE_FRAGMENT.exec(value.slice(hashAt + 1));
3621
+ if (matched === null) return {
3622
+ head: value,
3623
+ lines: {}
3624
+ };
3625
+ const lineStart = matched[1];
3626
+ if (lineStart === void 0) return {
3627
+ head: value,
3628
+ lines: {}
3629
+ };
3630
+ const column = matched[2];
3631
+ const lineEnd = matched[3];
3632
+ return {
3633
+ head: value.slice(0, hashAt),
3634
+ lines: {
3635
+ lineStart: Number(lineStart),
3636
+ ...column === void 0 ? {} : { column: Number(column) },
3637
+ ...lineEnd === void 0 ? {} : { lineEnd: Number(lineEnd) }
3638
+ }
3639
+ };
3640
+ }
3641
+ function lineFragmentOf(reference) {
3642
+ if (reference.lineStart === void 0) return "";
3643
+ const column = reference.column === void 0 ? "" : `C${String(reference.column)}`;
3644
+ const lineEnd = reference.lineEnd === void 0 ? "" : `-L${String(reference.lineEnd)}`;
3645
+ return `#L${String(reference.lineStart)}${column}${lineEnd}`;
3646
+ }
3647
+ function authorityEnd(value) {
3648
+ for (let index = 2; index < value.length; index += 1) {
3649
+ const char = value[index];
3650
+ if (char === "/" || char === "?" || char === "#") return index;
3651
+ }
3652
+ return value.length;
3653
+ }
3654
+ function encodeUri(uri) {
3655
+ return uri.replace(URI_UNSAFE, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`);
3656
+ }
3657
+ function decodeUri(value) {
3658
+ try {
3659
+ return decodeURIComponent(value);
3660
+ } catch {
3661
+ return;
3662
+ }
3663
+ }
3664
+ //#endregion
3665
+ //#region src/reference-markdown.tsx
3666
+ function referenceMentions(actions, tokens) {
3667
+ return { resolve: (value) => {
3668
+ const reference = tokens?.get(value) ?? parseReferenceToken(value);
3669
+ if (reference === void 0) return void 0;
3670
+ return {
3671
+ label: value,
3672
+ title: formatReference(reference),
3673
+ open: () => {
3674
+ openReference(reference, actions);
3675
+ }
3676
+ };
3677
+ } };
3678
+ }
3679
+ const ReferenceMarkdown = memo(function ReferenceMarkdown({ text, labels, actions, streaming = false, pathImages }) {
3680
+ const { source, tokens } = useMemo(() => tokenizeReferences(text), [text]);
3681
+ const mentions = useMemo(() => referenceMentions(actions, tokens), [actions, tokens]);
3682
+ return /* @__PURE__ */ jsx(MarkdownText, {
3683
+ text: source,
3684
+ streaming,
3685
+ labels,
3686
+ fileMentions: mentions,
3687
+ pathImages
3688
+ });
3689
+ });
3690
+ function displayTextOf(reference) {
3691
+ return (reference.title ?? `${reference.path ?? ""}${rangeOf(reference)}`).replaceAll("`", "'");
3692
+ }
3693
+ function rangeOf(reference) {
3694
+ if (reference.lineStart === void 0) return "";
3695
+ const column = reference.column === void 0 ? "" : `C${String(reference.column)}`;
3696
+ return reference.lineEnd === void 0 ? `#L${String(reference.lineStart)}${column}` : `#L${String(reference.lineStart)}${column}-L${String(reference.lineEnd)}`;
3697
+ }
3698
+ function tokenizeReferences(text) {
3699
+ const tokens = /* @__PURE__ */ new Map();
3700
+ let out = "";
3701
+ let cursor = 0;
3702
+ for (const span of findReferences(text)) {
3703
+ if (!isLocalReference(span.reference) || span.start < cursor) continue;
3704
+ const display = displayTextOf(span.reference);
3705
+ tokens.set(display, span.reference);
3706
+ out += `${text.slice(cursor, span.start)}\`${display}\``;
3707
+ cursor = span.end;
3708
+ }
3709
+ return {
3710
+ source: cursor === 0 ? text : out + text.slice(cursor),
3711
+ tokens
3712
+ };
3713
+ }
3714
+ function openReference(reference, actions) {
3715
+ const path = reference.path;
3716
+ if (actions === void 0 || path === void 0) return;
3717
+ if (reference.protocol === "skill") {
3718
+ actions.openSkill(path);
3719
+ return;
3720
+ }
3721
+ if (reference.protocol === "file") actions.openFile(path);
3722
+ }
3723
+ //#endregion
3724
+ //#region src/client/index.ts
3725
+ const inject = [...inject$1];
3726
+ function apply(ctx) {
3727
+ apply$1(ctx);
3728
+ }
3729
+ //#endregion
3730
+ export { Bubble, Button, DisclosureRow, IconButton, ModelRouteList, MultilineField, ReferenceMarkdown, Row, NS as SCHEMA_FORM_NS, SchemaFormController, SchemaFormHints, SearchSelect, SeatButton, SettingsFieldRow, Spinner, Stack, TagInput, Text, TimeLabel, VisuallyHidden, apply, failureOf, findReferences, formatReference, formatReferenceMention, inject, isLocalReference, markdownLabels, mergeTags, parseReference, parseReferenceToken, parseTagList, projectRoot, referenceMentions, rowRegistrations, schema_form_exports as schemaForm, walkFields };