machinalayout 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +295 -49
- package/dist/chunk-2ZQ2RFFI.js +400 -0
- package/dist/chunk-33CKBEJH.js +186 -0
- package/dist/chunk-BJOQRPPX.js +382 -0
- package/dist/chunk-KYWOCAHK.js +205 -0
- package/dist/chunk-RJYRJ3LD.js +0 -0
- package/dist/chunk-SVWYWI7I.js +59 -0
- package/dist/chunk-VREK57S3.js +13 -0
- package/dist/chunk-ZVDE7PX4.js +222 -0
- package/dist/debugOverlay-pJpj0n5H.d.ts +125 -0
- package/dist/deus/index.d.ts +14 -0
- package/dist/deus/index.js +26 -0
- package/dist/dispatch/index.d.ts +49 -0
- package/dist/dispatch/index.js +217 -0
- package/dist/handoff/index.d.ts +44 -0
- package/dist/handoff/index.js +83 -0
- package/dist/index.d.ts +54 -236
- package/dist/index.js +753 -583
- package/dist/inspect/index.d.ts +8 -0
- package/dist/inspect/index.js +97 -0
- package/dist/react/index.d.ts +41 -0
- package/dist/react/index.js +9 -0
- package/dist/react-native/index.d.ts +30 -0
- package/dist/react-native/index.js +84 -0
- package/dist/screenCatalog-ZjonGiOi.d.ts +46 -0
- package/dist/text/index.d.ts +10 -0
- package/dist/text/index.js +9 -0
- package/dist/text/react/index.d.ts +14 -0
- package/dist/text/react/index.js +7 -0
- package/dist/text/react-native/index.d.ts +16 -0
- package/dist/text/react-native/index.js +155 -0
- package/dist/text/vue/index.d.ts +113 -0
- package/dist/text/vue/index.js +202 -0
- package/dist/types-B90jb3RW.d.ts +184 -0
- package/dist/types-C4poVJpR.d.ts +74 -0
- package/dist/types-DLYAhNXw.d.ts +32 -0
- package/dist/vue/index.d.ts +173 -0
- package/dist/vue/index.js +112 -0
- package/docs/adapter-packaging-a0-plan.md +352 -0
- package/docs/adapters.md +19 -0
- package/docs/api-coherence-m8-audit.md +397 -0
- package/docs/deusmachina.md +108 -0
- package/docs/error-codes.md +95 -0
- package/docs/grid-arrange-m5a-contract.md +480 -0
- package/docs/grid-arrange.md +51 -0
- package/docs/inspection-and-handoff.md +126 -0
- package/docs/layout-interpolation.md +52 -0
- package/docs/machina-dispatch-d0-contract.md +496 -0
- package/docs/machina-dispatch.md +143 -0
- package/docs/named-layers.md +40 -0
- package/docs/react-adapter.md +63 -58
- package/docs/react-native-adapter.md +56 -0
- package/docs/react-native-text-renderer.md +50 -0
- package/docs/reference-alignment-m7a-contract.md +384 -0
- package/docs/reference-alignment.md +44 -0
- package/docs/responsive-variants.md +54 -0
- package/docs/screen-catalog-and-viewports.md +124 -0
- package/docs/stack-geometry-helpers.md +115 -0
- package/docs/vue-adapter.md +55 -0
- package/docs/vue-text-renderer.md +55 -0
- package/package.json +127 -60
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
// src/text/parseMachinaText.ts
|
|
2
|
+
function makeDiagnostic(code, message, index, length, line, column) {
|
|
3
|
+
return { code, message, index, length, line, column, level: "error" };
|
|
4
|
+
}
|
|
5
|
+
function toLines(source) {
|
|
6
|
+
const lines = [];
|
|
7
|
+
let i = 0;
|
|
8
|
+
let line = 1;
|
|
9
|
+
while (i <= source.length) {
|
|
10
|
+
const start = i;
|
|
11
|
+
while (i < source.length && source[i] !== "\n" && source[i] !== "\r") i += 1;
|
|
12
|
+
const text = source.slice(start, i);
|
|
13
|
+
lines.push({ text, index: start, line });
|
|
14
|
+
if (i >= source.length) break;
|
|
15
|
+
if (source[i] === "\r" && source[i + 1] === "\n") i += 2;
|
|
16
|
+
else i += 1;
|
|
17
|
+
line += 1;
|
|
18
|
+
}
|
|
19
|
+
return lines;
|
|
20
|
+
}
|
|
21
|
+
function parseInline(text, lineIndex, line) {
|
|
22
|
+
const diagnostics = [];
|
|
23
|
+
const inline = [];
|
|
24
|
+
let cursor = 0;
|
|
25
|
+
const pushText = (t) => {
|
|
26
|
+
if (!t) return;
|
|
27
|
+
const prev = inline[inline.length - 1];
|
|
28
|
+
if (prev?.kind === "text") prev.text += t;
|
|
29
|
+
else inline.push({ kind: "text", text: t });
|
|
30
|
+
};
|
|
31
|
+
const allowedEscapes = /* @__PURE__ */ new Set(["\\", "*", "`", "[", "]", "(", ")", "-"]);
|
|
32
|
+
const consumeEscape = () => {
|
|
33
|
+
if (text[cursor] !== "\\") return false;
|
|
34
|
+
if (cursor === text.length - 1) {
|
|
35
|
+
diagnostics.push(
|
|
36
|
+
makeDiagnostic(
|
|
37
|
+
"invalid_escape",
|
|
38
|
+
"Dangling escape sequence.",
|
|
39
|
+
lineIndex + cursor,
|
|
40
|
+
1,
|
|
41
|
+
line,
|
|
42
|
+
cursor + 1
|
|
43
|
+
)
|
|
44
|
+
);
|
|
45
|
+
pushText("\\");
|
|
46
|
+
cursor += 1;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
const escaped = text[cursor + 1];
|
|
50
|
+
if (allowedEscapes.has(escaped)) {
|
|
51
|
+
pushText(escaped);
|
|
52
|
+
cursor += 2;
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
diagnostics.push(
|
|
56
|
+
makeDiagnostic(
|
|
57
|
+
"invalid_escape",
|
|
58
|
+
`Unsupported escape sequence: \\${escaped}`,
|
|
59
|
+
lineIndex + cursor,
|
|
60
|
+
2,
|
|
61
|
+
line,
|
|
62
|
+
cursor + 1
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
pushText(escaped);
|
|
66
|
+
cursor += 2;
|
|
67
|
+
return true;
|
|
68
|
+
};
|
|
69
|
+
while (cursor < text.length) {
|
|
70
|
+
if (consumeEscape()) continue;
|
|
71
|
+
if (text.startsWith("![", cursor)) {
|
|
72
|
+
diagnostics.push(
|
|
73
|
+
makeDiagnostic(
|
|
74
|
+
"unsupported_syntax",
|
|
75
|
+
"Images are not supported.",
|
|
76
|
+
lineIndex + cursor,
|
|
77
|
+
2,
|
|
78
|
+
line,
|
|
79
|
+
cursor + 1
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
pushText("![");
|
|
83
|
+
cursor += 2;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (text[cursor] === "`") {
|
|
87
|
+
const close = text.indexOf("`", cursor + 1);
|
|
88
|
+
if (close < 0) {
|
|
89
|
+
diagnostics.push(
|
|
90
|
+
makeDiagnostic(
|
|
91
|
+
"unclosed_inline",
|
|
92
|
+
"Unclosed inline code marker.",
|
|
93
|
+
lineIndex + cursor,
|
|
94
|
+
text.length - cursor,
|
|
95
|
+
line,
|
|
96
|
+
cursor + 1
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
pushText(text.slice(cursor));
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
inline.push({ kind: "code", text: text.slice(cursor + 1, close) });
|
|
103
|
+
cursor = close + 1;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (text.startsWith("**", cursor)) {
|
|
107
|
+
const close = text.indexOf("**", cursor + 2);
|
|
108
|
+
if (close < 0) {
|
|
109
|
+
diagnostics.push(
|
|
110
|
+
makeDiagnostic(
|
|
111
|
+
"unclosed_inline",
|
|
112
|
+
"Unclosed strong marker.",
|
|
113
|
+
lineIndex + cursor,
|
|
114
|
+
text.length - cursor,
|
|
115
|
+
line,
|
|
116
|
+
cursor + 1
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
pushText(text.slice(cursor));
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
const children = parseInline(text.slice(cursor + 2, close), lineIndex + cursor + 2, line);
|
|
123
|
+
diagnostics.push(...children.diagnostics);
|
|
124
|
+
inline.push({ kind: "strong", children: children.inline });
|
|
125
|
+
cursor = close + 2;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (text[cursor] === "*") {
|
|
129
|
+
const close = text.indexOf("*", cursor + 1);
|
|
130
|
+
if (close < 0) {
|
|
131
|
+
diagnostics.push(
|
|
132
|
+
makeDiagnostic(
|
|
133
|
+
"unclosed_inline",
|
|
134
|
+
"Unclosed emphasis marker.",
|
|
135
|
+
lineIndex + cursor,
|
|
136
|
+
text.length - cursor,
|
|
137
|
+
line,
|
|
138
|
+
cursor + 1
|
|
139
|
+
)
|
|
140
|
+
);
|
|
141
|
+
pushText(text.slice(cursor));
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
const children = parseInline(text.slice(cursor + 1, close), lineIndex + cursor + 1, line);
|
|
145
|
+
diagnostics.push(...children.diagnostics);
|
|
146
|
+
inline.push({ kind: "emphasis", children: children.inline });
|
|
147
|
+
cursor = close + 1;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (text[cursor] === "[") {
|
|
151
|
+
const closeBracket = text.indexOf("]", cursor + 1);
|
|
152
|
+
if (closeBracket < 0 || text[closeBracket + 1] !== "(") {
|
|
153
|
+
diagnostics.push(
|
|
154
|
+
makeDiagnostic(
|
|
155
|
+
"malformed_link",
|
|
156
|
+
"Malformed link syntax.",
|
|
157
|
+
lineIndex + cursor,
|
|
158
|
+
Math.max(1, text.length - cursor),
|
|
159
|
+
line,
|
|
160
|
+
cursor + 1
|
|
161
|
+
)
|
|
162
|
+
);
|
|
163
|
+
pushText("[");
|
|
164
|
+
cursor += 1;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const closeParen = text.indexOf(")", closeBracket + 2);
|
|
168
|
+
if (closeParen < 0) {
|
|
169
|
+
diagnostics.push(
|
|
170
|
+
makeDiagnostic(
|
|
171
|
+
"malformed_link",
|
|
172
|
+
"Malformed link syntax.",
|
|
173
|
+
lineIndex + cursor,
|
|
174
|
+
text.length - cursor,
|
|
175
|
+
line,
|
|
176
|
+
cursor + 1
|
|
177
|
+
)
|
|
178
|
+
);
|
|
179
|
+
pushText(text.slice(cursor));
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
const label = text.slice(cursor + 1, closeBracket);
|
|
183
|
+
const href = text.slice(closeBracket + 2, closeParen);
|
|
184
|
+
if (label.length === 0) {
|
|
185
|
+
diagnostics.push(
|
|
186
|
+
makeDiagnostic(
|
|
187
|
+
"malformed_link",
|
|
188
|
+
"Link label cannot be empty.",
|
|
189
|
+
lineIndex + cursor,
|
|
190
|
+
closeParen - cursor + 1,
|
|
191
|
+
line,
|
|
192
|
+
cursor + 1
|
|
193
|
+
)
|
|
194
|
+
);
|
|
195
|
+
pushText(text.slice(cursor, closeParen + 1));
|
|
196
|
+
cursor = closeParen + 1;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const labelInline = parseInline(label, lineIndex + cursor + 1, line);
|
|
200
|
+
diagnostics.push(...labelInline.diagnostics);
|
|
201
|
+
inline.push({ kind: "link", href, children: labelInline.inline });
|
|
202
|
+
cursor = closeParen + 1;
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const specials = ["![", "`", "**", "*", "[", "\\"];
|
|
206
|
+
let next = text.length;
|
|
207
|
+
for (const special of specials) {
|
|
208
|
+
const p = text.indexOf(special, cursor);
|
|
209
|
+
if (p >= 0 && p < next) next = p;
|
|
210
|
+
}
|
|
211
|
+
if (next === cursor) {
|
|
212
|
+
pushText(text[cursor]);
|
|
213
|
+
cursor += 1;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
pushText(text.slice(cursor, next));
|
|
217
|
+
cursor = next;
|
|
218
|
+
}
|
|
219
|
+
return { inline, diagnostics };
|
|
220
|
+
}
|
|
221
|
+
function classifyForbiddenBlock(line) {
|
|
222
|
+
if (/^#{1,6}\s+/.test(line)) return "heading_forbidden";
|
|
223
|
+
if (/^\d+\.\s+/.test(line)) return "unsupported_syntax";
|
|
224
|
+
if (/^\s*-\s+\[[ xX]\]\s+/.test(line)) return "unsupported_syntax";
|
|
225
|
+
if (/^>\s+/.test(line)) return "unsupported_syntax";
|
|
226
|
+
if (/^```/.test(line)) return "unsupported_syntax";
|
|
227
|
+
if (/^\s*<\/?[a-zA-Z][^>]*>/.test(line)) return "unsupported_syntax";
|
|
228
|
+
if (/^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(line)) return "unsupported_syntax";
|
|
229
|
+
return void 0;
|
|
230
|
+
}
|
|
231
|
+
function parseBulletLine(line) {
|
|
232
|
+
if (line.startsWith("\\- ")) return void 0;
|
|
233
|
+
if (line.startsWith("- ")) return { depth: 1, text: line.slice(2) };
|
|
234
|
+
if (line.startsWith(" - ")) return { depth: 2, text: line.slice(4) };
|
|
235
|
+
if (line.startsWith(" - ")) return { depth: 3, text: line.slice(6) };
|
|
236
|
+
return void 0;
|
|
237
|
+
}
|
|
238
|
+
function parseMachinaTextInline(text) {
|
|
239
|
+
return parseInline(text, 0, 1);
|
|
240
|
+
}
|
|
241
|
+
function parseMachinaText(source) {
|
|
242
|
+
const src = typeof source === "string" ? { kind: "machina-text", text: source } : source;
|
|
243
|
+
if (src?.kind !== "plain" && src?.kind !== "machina-text") {
|
|
244
|
+
const diagnostic = makeDiagnostic(
|
|
245
|
+
"unsupported_syntax",
|
|
246
|
+
"Unsupported MachinaText source kind.",
|
|
247
|
+
0,
|
|
248
|
+
0,
|
|
249
|
+
1,
|
|
250
|
+
1
|
|
251
|
+
);
|
|
252
|
+
return { ok: false, document: { blocks: [] }, diagnostics: [diagnostic] };
|
|
253
|
+
}
|
|
254
|
+
if (src.kind === "plain") {
|
|
255
|
+
return {
|
|
256
|
+
ok: true,
|
|
257
|
+
document: { blocks: [{ kind: "paragraph", inline: [{ kind: "text", text: src.text }] }] },
|
|
258
|
+
diagnostics: []
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
const blocks = [];
|
|
262
|
+
const diagnostics = [];
|
|
263
|
+
const lines = toLines(src.text);
|
|
264
|
+
let i = 0;
|
|
265
|
+
while (i < lines.length) {
|
|
266
|
+
const lineInfo = lines[i];
|
|
267
|
+
const trimmed = lineInfo.text.trim();
|
|
268
|
+
if (trimmed.length === 0) {
|
|
269
|
+
i += 1;
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const forbiddenCode = classifyForbiddenBlock(lineInfo.text);
|
|
273
|
+
if (forbiddenCode) {
|
|
274
|
+
const code = forbiddenCode;
|
|
275
|
+
diagnostics.push(
|
|
276
|
+
makeDiagnostic(
|
|
277
|
+
code,
|
|
278
|
+
"Unsupported block syntax.",
|
|
279
|
+
lineInfo.index,
|
|
280
|
+
lineInfo.text.length || 1,
|
|
281
|
+
lineInfo.line,
|
|
282
|
+
1
|
|
283
|
+
)
|
|
284
|
+
);
|
|
285
|
+
blocks.push({ kind: "paragraph", inline: [{ kind: "text", text: lineInfo.text }] });
|
|
286
|
+
i += 1;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const bullet = parseBulletLine(lineInfo.text);
|
|
290
|
+
if (bullet) {
|
|
291
|
+
const items = [];
|
|
292
|
+
let lastTop;
|
|
293
|
+
while (i < lines.length) {
|
|
294
|
+
const current = lines[i];
|
|
295
|
+
if (current.text.trim().length === 0) break;
|
|
296
|
+
const currentBullet = parseBulletLine(current.text);
|
|
297
|
+
if (!currentBullet) break;
|
|
298
|
+
if (/^\s*-\s+\[[ xX]\]\s+/.test(current.text)) {
|
|
299
|
+
diagnostics.push(
|
|
300
|
+
makeDiagnostic(
|
|
301
|
+
"unsupported_syntax",
|
|
302
|
+
"Task lists are not supported.",
|
|
303
|
+
current.index,
|
|
304
|
+
current.text.length || 1,
|
|
305
|
+
current.line,
|
|
306
|
+
1
|
|
307
|
+
)
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
if (currentBullet.depth > 2) {
|
|
311
|
+
diagnostics.push(
|
|
312
|
+
makeDiagnostic(
|
|
313
|
+
"max_list_depth_exceeded",
|
|
314
|
+
"Maximum bullet depth is 2.",
|
|
315
|
+
current.index,
|
|
316
|
+
current.text.length || 1,
|
|
317
|
+
current.line,
|
|
318
|
+
1
|
|
319
|
+
)
|
|
320
|
+
);
|
|
321
|
+
const parsed3 = parseInline(
|
|
322
|
+
current.text.trim(),
|
|
323
|
+
current.index + (current.text.length - current.text.trimStart().length),
|
|
324
|
+
current.line
|
|
325
|
+
);
|
|
326
|
+
diagnostics.push(...parsed3.diagnostics);
|
|
327
|
+
blocks.push({
|
|
328
|
+
kind: "paragraph",
|
|
329
|
+
inline: parsed3.inline.length ? parsed3.inline : [{ kind: "text", text: current.text }]
|
|
330
|
+
});
|
|
331
|
+
i += 1;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
const parsed2 = parseInline(
|
|
335
|
+
currentBullet.text,
|
|
336
|
+
current.index + (currentBullet.depth === 1 ? 2 : 4),
|
|
337
|
+
current.line
|
|
338
|
+
);
|
|
339
|
+
diagnostics.push(...parsed2.diagnostics);
|
|
340
|
+
const item = { inline: parsed2.inline };
|
|
341
|
+
if (currentBullet.depth === 1) {
|
|
342
|
+
items.push(item);
|
|
343
|
+
lastTop = item;
|
|
344
|
+
} else if (lastTop) {
|
|
345
|
+
if (!lastTop.children) lastTop.children = [];
|
|
346
|
+
lastTop.children.push(item);
|
|
347
|
+
} else {
|
|
348
|
+
diagnostics.push(
|
|
349
|
+
makeDiagnostic(
|
|
350
|
+
"unsupported_syntax",
|
|
351
|
+
"Nested bullet requires a parent bullet.",
|
|
352
|
+
current.index,
|
|
353
|
+
current.text.length || 1,
|
|
354
|
+
current.line,
|
|
355
|
+
1
|
|
356
|
+
)
|
|
357
|
+
);
|
|
358
|
+
blocks.push({ kind: "paragraph", inline: [{ kind: "text", text: current.text }] });
|
|
359
|
+
}
|
|
360
|
+
i += 1;
|
|
361
|
+
}
|
|
362
|
+
blocks.push({ kind: "bulletList", items });
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
const paragraphLines = [];
|
|
366
|
+
while (i < lines.length && lines[i].text.trim().length > 0 && !parseBulletLine(lines[i].text) && !classifyForbiddenBlock(lines[i].text)) {
|
|
367
|
+
paragraphLines.push(lines[i]);
|
|
368
|
+
i += 1;
|
|
369
|
+
}
|
|
370
|
+
const paragraphText = paragraphLines.map((line) => line.text).join("\n");
|
|
371
|
+
const first = paragraphLines[0];
|
|
372
|
+
const parsed = parseInline(paragraphText, first?.index ?? 0, first?.line ?? 1);
|
|
373
|
+
diagnostics.push(...parsed.diagnostics);
|
|
374
|
+
blocks.push({ kind: "paragraph", inline: parsed.inline });
|
|
375
|
+
}
|
|
376
|
+
return { ok: diagnostics.every((d) => d.level !== "error"), document: { blocks }, diagnostics };
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export {
|
|
380
|
+
parseMachinaTextInline,
|
|
381
|
+
parseMachinaText
|
|
382
|
+
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseMachinaText
|
|
3
|
+
} from "./chunk-BJOQRPPX.js";
|
|
4
|
+
|
|
5
|
+
// src/text/react/MachinaTextView.tsx
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var DEFAULT_POLICY = {
|
|
9
|
+
variant: "body",
|
|
10
|
+
wrap: "word",
|
|
11
|
+
overflow: "clip",
|
|
12
|
+
align: "start",
|
|
13
|
+
leading: "normal",
|
|
14
|
+
blockGap: 8,
|
|
15
|
+
listGap: 2,
|
|
16
|
+
valign: "top"
|
|
17
|
+
};
|
|
18
|
+
var INLINE_CODE_FONT = 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
|
|
19
|
+
var VARIANT_STYLE = {
|
|
20
|
+
body: { fontSize: "14px", fontWeight: 400, lineHeight: 1.4 },
|
|
21
|
+
label: { fontSize: "12px", fontWeight: 500, lineHeight: 1.3 },
|
|
22
|
+
caption: { fontSize: "11px", fontWeight: 400, lineHeight: 1.25, opacity: 0.8 },
|
|
23
|
+
title: { fontSize: "18px", fontWeight: 700, lineHeight: 1.25 },
|
|
24
|
+
mono: { fontSize: "12px", lineHeight: 1.35, fontFamily: INLINE_CODE_FONT }
|
|
25
|
+
};
|
|
26
|
+
function isMachinaTextDocument(value) {
|
|
27
|
+
return typeof value === "object" && value !== null && "blocks" in value;
|
|
28
|
+
}
|
|
29
|
+
function isMachinaTextSpec(value) {
|
|
30
|
+
return typeof value === "object" && value !== null && "kind" in value && value.kind === "text";
|
|
31
|
+
}
|
|
32
|
+
function normalizePositive(value, fallback) {
|
|
33
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
34
|
+
}
|
|
35
|
+
function normalizeNonNegative(value, fallback) {
|
|
36
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
|
|
37
|
+
}
|
|
38
|
+
function normalizeLeading(value) {
|
|
39
|
+
if (value === void 0) return DEFAULT_POLICY.leading;
|
|
40
|
+
if (value === "tight" || value === "normal" || value === "loose") return value;
|
|
41
|
+
return normalizePositive(value, resolveLineHeight(DEFAULT_POLICY));
|
|
42
|
+
}
|
|
43
|
+
function normalizeSpecPolicy(spec) {
|
|
44
|
+
return {
|
|
45
|
+
variant: spec.variant ?? DEFAULT_POLICY.variant,
|
|
46
|
+
wrap: spec.wrap ?? DEFAULT_POLICY.wrap,
|
|
47
|
+
overflow: spec.overflow ?? DEFAULT_POLICY.overflow,
|
|
48
|
+
align: spec.align ?? DEFAULT_POLICY.align,
|
|
49
|
+
leading: normalizeLeading(spec.leading),
|
|
50
|
+
blockGap: normalizeNonNegative(spec.blockGap, DEFAULT_POLICY.blockGap),
|
|
51
|
+
listGap: normalizeNonNegative(spec.listGap, DEFAULT_POLICY.listGap),
|
|
52
|
+
valign: spec.valign ?? DEFAULT_POLICY.valign
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function normalizeText(text) {
|
|
56
|
+
if (isMachinaTextDocument(text))
|
|
57
|
+
return { document: text, diagnostics: [], policy: DEFAULT_POLICY };
|
|
58
|
+
if (isMachinaTextSpec(text)) {
|
|
59
|
+
const result2 = parseMachinaText(text.source);
|
|
60
|
+
return {
|
|
61
|
+
document: result2.document,
|
|
62
|
+
diagnostics: result2.diagnostics,
|
|
63
|
+
policy: normalizeSpecPolicy(text)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const result = parseMachinaText(typeof text === "string" ? { kind: "machina-text", text } : text);
|
|
67
|
+
return { document: result.document, diagnostics: result.diagnostics, policy: DEFAULT_POLICY };
|
|
68
|
+
}
|
|
69
|
+
function resolveLineHeight(policy) {
|
|
70
|
+
if (policy.leading === "tight") return 1.15;
|
|
71
|
+
if (policy.leading === "loose") return 1.6;
|
|
72
|
+
if (typeof policy.leading === "number") return policy.leading;
|
|
73
|
+
return VARIANT_STYLE[policy.variant].lineHeight;
|
|
74
|
+
}
|
|
75
|
+
function policyStyle(policy) {
|
|
76
|
+
const wrapStyle = {
|
|
77
|
+
word: { whiteSpace: "normal", overflowWrap: "anywhere" },
|
|
78
|
+
none: { whiteSpace: "nowrap" }
|
|
79
|
+
};
|
|
80
|
+
const overflowStyle = {
|
|
81
|
+
clip: { overflow: "hidden" },
|
|
82
|
+
ellipsis: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
|
|
83
|
+
scroll: { overflow: "auto" }
|
|
84
|
+
};
|
|
85
|
+
const alignStyle = {
|
|
86
|
+
start: { textAlign: "left" },
|
|
87
|
+
center: { textAlign: "center" },
|
|
88
|
+
end: { textAlign: "right" }
|
|
89
|
+
};
|
|
90
|
+
const justifyContent = {
|
|
91
|
+
top: "flex-start",
|
|
92
|
+
center: "center",
|
|
93
|
+
bottom: "flex-end"
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
width: "100%",
|
|
97
|
+
height: "100%",
|
|
98
|
+
boxSizing: "border-box",
|
|
99
|
+
display: "flex",
|
|
100
|
+
flexDirection: "column",
|
|
101
|
+
justifyContent: justifyContent[policy.valign],
|
|
102
|
+
minWidth: 0,
|
|
103
|
+
...VARIANT_STYLE[policy.variant],
|
|
104
|
+
lineHeight: resolveLineHeight(policy),
|
|
105
|
+
...wrapStyle[policy.wrap],
|
|
106
|
+
...overflowStyle[policy.overflow],
|
|
107
|
+
...alignStyle[policy.align]
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function renderInline(inline, key, props) {
|
|
111
|
+
switch (inline.kind) {
|
|
112
|
+
case "text":
|
|
113
|
+
return /* @__PURE__ */ jsx(React.Fragment, { children: inline.text }, key);
|
|
114
|
+
case "strong":
|
|
115
|
+
return /* @__PURE__ */ jsx("strong", { children: inline.children.map((c, i) => renderInline(c, `${key}-s-${i}`, props)) }, key);
|
|
116
|
+
case "emphasis":
|
|
117
|
+
return /* @__PURE__ */ jsx("em", { children: inline.children.map((c, i) => renderInline(c, `${key}-e-${i}`, props)) }, key);
|
|
118
|
+
case "code":
|
|
119
|
+
return /* @__PURE__ */ jsx(
|
|
120
|
+
"code",
|
|
121
|
+
{
|
|
122
|
+
style: {
|
|
123
|
+
fontFamily: INLINE_CODE_FONT,
|
|
124
|
+
backgroundColor: "rgba(127, 127, 127, 0.15)",
|
|
125
|
+
borderRadius: 3,
|
|
126
|
+
padding: "0 0.25em"
|
|
127
|
+
},
|
|
128
|
+
children: inline.text
|
|
129
|
+
},
|
|
130
|
+
key
|
|
131
|
+
);
|
|
132
|
+
case "link": {
|
|
133
|
+
const rel = props.linkTarget === "_blank" ? "noreferrer noopener" : void 0;
|
|
134
|
+
return /* @__PURE__ */ jsx(
|
|
135
|
+
"a",
|
|
136
|
+
{
|
|
137
|
+
href: inline.href,
|
|
138
|
+
target: props.linkTarget,
|
|
139
|
+
rel,
|
|
140
|
+
onClick: (event) => props.onLinkClick?.(inline.href, event),
|
|
141
|
+
children: inline.children.map((c, i) => renderInline(c, `${key}-l-${i}`, props))
|
|
142
|
+
},
|
|
143
|
+
key
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function renderBulletItem(item, path, props, listGap) {
|
|
149
|
+
return /* @__PURE__ */ jsxs("li", { style: { marginBottom: listGap }, children: [
|
|
150
|
+
item.inline.map((i, idx) => renderInline(i, `${path}-i-${idx}`, props)),
|
|
151
|
+
item.children?.length ? /* @__PURE__ */ jsx("ul", { style: { margin: "0.25em 0 0 0", paddingLeft: "1.25em" }, children: item.children.map((c, idx) => renderBulletItem(c, `${path}-c-${idx}`, props, listGap)) }) : null
|
|
152
|
+
] }, path);
|
|
153
|
+
}
|
|
154
|
+
function MachinaTextView(props) {
|
|
155
|
+
const normalized = normalizeText(props.text);
|
|
156
|
+
return /* @__PURE__ */ jsx("div", { className: props.className, style: { ...policyStyle(normalized.policy), ...props.style }, children: /* @__PURE__ */ jsxs("div", { style: { minWidth: 0 }, children: [
|
|
157
|
+
normalized.document.blocks.map(
|
|
158
|
+
(block, index) => block.kind === "paragraph" ? /* @__PURE__ */ jsx(
|
|
159
|
+
"p",
|
|
160
|
+
{
|
|
161
|
+
style: {
|
|
162
|
+
margin: index === normalized.document.blocks.length - 1 ? "0" : `0 0 ${normalized.policy.blockGap}px 0`
|
|
163
|
+
},
|
|
164
|
+
children: block.inline.map((i, idx) => renderInline(i, `b-${index}-${idx}`, props))
|
|
165
|
+
},
|
|
166
|
+
`b-${index}`
|
|
167
|
+
) : /* @__PURE__ */ jsx(
|
|
168
|
+
"ul",
|
|
169
|
+
{
|
|
170
|
+
style: {
|
|
171
|
+
margin: index === normalized.document.blocks.length - 1 ? "0" : `0 0 ${normalized.policy.blockGap}px 0`,
|
|
172
|
+
paddingLeft: "1.25em"
|
|
173
|
+
},
|
|
174
|
+
children: block.items.map(
|
|
175
|
+
(item, itemIndex) => renderBulletItem(
|
|
176
|
+
item,
|
|
177
|
+
`b-${index}-item-${itemIndex}`,
|
|
178
|
+
props,
|
|
179
|
+
normalized.policy.listGap
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
},
|
|
183
|
+
`b-${index}`
|
|
184
|
+
)
|
|
185
|
+
),
|
|
186
|
+
props.showDiagnostics && normalized.diagnostics.length > 0 ? /* @__PURE__ */ jsx(
|
|
187
|
+
"pre",
|
|
188
|
+
{
|
|
189
|
+
style: {
|
|
190
|
+
margin: `${normalized.policy.blockGap}px 0 0 0`,
|
|
191
|
+
padding: "0.5em",
|
|
192
|
+
fontSize: "11px",
|
|
193
|
+
fontFamily: INLINE_CODE_FONT,
|
|
194
|
+
whiteSpace: "pre-wrap",
|
|
195
|
+
background: "rgba(127, 127, 127, 0.12)"
|
|
196
|
+
},
|
|
197
|
+
children: normalized.diagnostics.map((d) => `${d.code} (${d.line}:${d.column}) ${d.message}`).join("\n")
|
|
198
|
+
}
|
|
199
|
+
) : null
|
|
200
|
+
] }) });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export {
|
|
204
|
+
MachinaTextView
|
|
205
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MachinaLayoutError
|
|
3
|
+
} from "./chunk-VREK57S3.js";
|
|
4
|
+
|
|
5
|
+
// src/toResolvedTree.ts
|
|
6
|
+
function toResolvedTree(document) {
|
|
7
|
+
const root = document.nodes[document.rootId];
|
|
8
|
+
if (!root) {
|
|
9
|
+
throw new MachinaLayoutError("MissingRoot", `root node '${document.rootId}' is missing`);
|
|
10
|
+
}
|
|
11
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
12
|
+
const visited = /* @__PURE__ */ new Set();
|
|
13
|
+
const build = (node) => {
|
|
14
|
+
if (visiting.has(node.id)) {
|
|
15
|
+
throw new MachinaLayoutError("Cycle", `cycle detected at '${node.id}'`);
|
|
16
|
+
}
|
|
17
|
+
visiting.add(node.id);
|
|
18
|
+
visited.add(node.id);
|
|
19
|
+
const childIds = document.children[node.id] ?? [];
|
|
20
|
+
const children = childIds.map((childId) => {
|
|
21
|
+
const child = document.nodes[childId];
|
|
22
|
+
if (!child) {
|
|
23
|
+
throw new MachinaLayoutError(
|
|
24
|
+
"UnknownParent",
|
|
25
|
+
`missing child node '${childId}' referenced by '${node.id}'`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return build(child);
|
|
29
|
+
});
|
|
30
|
+
visiting.delete(node.id);
|
|
31
|
+
return {
|
|
32
|
+
id: node.id,
|
|
33
|
+
z: node.z,
|
|
34
|
+
rect: { ...node.rect },
|
|
35
|
+
frame: node.frame,
|
|
36
|
+
arrange: node.arrange,
|
|
37
|
+
view: node.view,
|
|
38
|
+
slot: node.slot,
|
|
39
|
+
debugLabel: node.debugLabel,
|
|
40
|
+
layer: node.layer,
|
|
41
|
+
offset: node.offset,
|
|
42
|
+
children
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const tree = build(root);
|
|
46
|
+
for (const nodeId of Object.keys(document.nodes)) {
|
|
47
|
+
if (!visited.has(nodeId)) {
|
|
48
|
+
throw new MachinaLayoutError(
|
|
49
|
+
"UnreachableNode",
|
|
50
|
+
`node '${nodeId}' is unreachable from root '${document.rootId}'`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return tree;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
toResolvedTree
|
|
59
|
+
};
|