@parity-app/cli 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +65 -2
- package/dist/bin.mjs +831 -0
- package/dist/client-DsTLQ2lT.mjs +286 -0
- package/dist/in-app.json +10 -0
- package/dist/index.d.mts +160 -0
- package/dist/index.mjs +1 -0
- package/dist/libraries/aria.lib.par +14516 -0
- package/dist/libraries/baseui.lib.par +8298 -0
- package/dist/libraries/buildkit-baseui.edits.json +3 -0
- package/dist/libraries/chakra.lib.par +539186 -0
- package/dist/libraries/fluent-icons.lib.par +2674 -0
- package/dist/libraries/fluent.lib.par +33703 -0
- package/dist/libraries/heroicons.lib.par +33 -0
- package/dist/libraries/hugeicons.lib.par +708 -0
- package/dist/libraries/lucide.lib.par +2123 -0
- package/dist/libraries/luma.lib.par +16362 -0
- package/dist/libraries/lyra.lib.par +16362 -0
- package/dist/libraries/maia.lib.par +16362 -0
- package/dist/libraries/mantine.lib.par +32935 -0
- package/dist/libraries/mira.lib.par +16362 -0
- package/dist/libraries/mui.lib.par +9817 -0
- package/dist/libraries/nova.lib.par +16363 -0
- package/dist/libraries/phosphor.lib.par +3060 -0
- package/dist/libraries/radix.lib.par +6890 -0
- package/dist/libraries/rhea.lib.par +16362 -0
- package/dist/libraries/sera.lib.par +16362 -0
- package/dist/libraries/tabler.lib.par +5325 -0
- package/dist/libraries/vega.lib.par +16362 -0
- package/dist/published-BtL8RM6W.mjs +1 -0
- package/dist/published-CdXoUgfD.mjs +200 -0
- package/dist/src-C8DCd2a1.mjs +1 -0
- package/dist/src-CSeISXoZ.mjs +1298 -0
- package/dist/src-WcAfq6g1.mjs +2 -0
- package/dist/src-rlZNC2MU.mjs +4690 -0
- package/dist/src-uPmBVSsB.mjs +53 -0
- package/package.json +50 -3
- package/skills/SKILL.md +96 -0
- package/skills/document.md +166 -0
- package/skills/execute.md +276 -0
- package/skills/guide/checking.md +56 -0
- package/skills/guide/components.md +48 -0
- package/skills/guide/design-system.md +52 -0
- package/skills/guide/mobile.md +32 -0
- package/skills/guide/states-and-modes.md +55 -0
- package/skills/guide/web-app.md +43 -0
|
@@ -0,0 +1,1298 @@
|
|
|
1
|
+
// ../core/src/css.ts
|
|
2
|
+
/**
|
|
3
|
+
* Custom properties holding 1% of a frame's viewport width and height, which viewport units are rewritten to: in a frame,
|
|
4
|
+
* `100vh` is the height of the screen the frame stands for, not of Parity's window.
|
|
5
|
+
*/
|
|
6
|
+
const viewportWidthProperty = "--canvas-vw";
|
|
7
|
+
const viewportHeightProperty = "--canvas-vh";
|
|
8
|
+
new RegExp(String.raw`"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|url\([^)]*\)|var\((?:${viewportWidthProperty}|${viewportHeightProperty}),[^)]*\)`, "g");
|
|
9
|
+
// ../core/src/devices.ts
|
|
10
|
+
const deviceKinds = [
|
|
11
|
+
"phone",
|
|
12
|
+
"tablet",
|
|
13
|
+
"laptop",
|
|
14
|
+
"desktop"
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* A CSS length in pixels, for breakpoints written in rem or em (16px each, the browser default) or px. Undefined for
|
|
18
|
+
* anything else.
|
|
19
|
+
*/
|
|
20
|
+
function lengthToPixels(value) {
|
|
21
|
+
const match = /^\s*(-?[\d.]+)(px|rem|em)?\s*$/.exec(value);
|
|
22
|
+
if (!match) return void 0;
|
|
23
|
+
const number = Number(match[1]);
|
|
24
|
+
if (!Number.isFinite(number)) return void 0;
|
|
25
|
+
return match[2] === "rem" || match[2] === "em" ? number * 16 : number;
|
|
26
|
+
}
|
|
27
|
+
// ../core/src/validate.ts
|
|
28
|
+
function expectObject(value, path) {
|
|
29
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError(`${path || "/"}: expected an object`);
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
function expectString(value, path) {
|
|
33
|
+
if (typeof value !== "string") throw new TypeError(`${path}: expected a string`);
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
function expectNumber(value, path) {
|
|
37
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new TypeError(`${path}: expected a number`);
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function expectBoolean(value, path) {
|
|
41
|
+
if (typeof value !== "boolean") throw new TypeError(`${path}: expected true or false`);
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
function expectArray(value, path) {
|
|
45
|
+
if (!Array.isArray(value)) throw new TypeError(`${path}: expected an array`);
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
function expectOneOf(value, options, path) {
|
|
49
|
+
if (typeof value !== "string" || !options.includes(value)) throw new TypeError(`${path}: expected one of ${options.map((option) => `"${option}"`).join(", ")}`);
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
function optional(value, parse) {
|
|
53
|
+
return value === void 0 ? void 0 : parse(value);
|
|
54
|
+
}
|
|
55
|
+
/** Drops `undefined` entries, so parsed patches can be spread over defaults without erasing them. */
|
|
56
|
+
function compact(value) {
|
|
57
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
58
|
+
}
|
|
59
|
+
function expectKnownKeys(value, keys, path) {
|
|
60
|
+
for (const key of Object.keys(value)) if (!keys.includes(key)) throw new TypeError(`${path}/${key}: unknown property`);
|
|
61
|
+
}
|
|
62
|
+
// ../core/src/modes.ts
|
|
63
|
+
const variableKinds = [
|
|
64
|
+
"viewport",
|
|
65
|
+
"theme",
|
|
66
|
+
"locale",
|
|
67
|
+
"custom"
|
|
68
|
+
];
|
|
69
|
+
function parseModeSettings(value) {
|
|
70
|
+
const settings = expectObject(value, "");
|
|
71
|
+
expectKnownKeys(settings, [
|
|
72
|
+
"$schema",
|
|
73
|
+
"version",
|
|
74
|
+
"variables",
|
|
75
|
+
"modes"
|
|
76
|
+
], "");
|
|
77
|
+
if (settings.version !== 1) throw new TypeError("/version: expected 1");
|
|
78
|
+
const variables = expectArray(settings.variables, "/variables").map((item, index) => {
|
|
79
|
+
const at = `/variables/${index}`;
|
|
80
|
+
const variable = expectObject(item, at);
|
|
81
|
+
expectKnownKeys(variable, [
|
|
82
|
+
"id",
|
|
83
|
+
"name",
|
|
84
|
+
"kind",
|
|
85
|
+
"options"
|
|
86
|
+
], at);
|
|
87
|
+
const options = expectArray(variable.options, `${at}/options`).map((entry, optionIndex) => {
|
|
88
|
+
const optionAt = `${at}/options/${optionIndex}`;
|
|
89
|
+
const option = expectObject(entry, optionAt);
|
|
90
|
+
expectKnownKeys(option, [
|
|
91
|
+
"id",
|
|
92
|
+
"name",
|
|
93
|
+
"width",
|
|
94
|
+
"height",
|
|
95
|
+
"device",
|
|
96
|
+
"className",
|
|
97
|
+
"attributes"
|
|
98
|
+
], optionAt);
|
|
99
|
+
return compact({
|
|
100
|
+
id: expectString(option.id, `${optionAt}/id`),
|
|
101
|
+
name: expectString(option.name, `${optionAt}/name`),
|
|
102
|
+
width: optional(option.width, (v) => expectNumber(v, `${optionAt}/width`)),
|
|
103
|
+
height: optional(option.height, (v) => expectNumber(v, `${optionAt}/height`)),
|
|
104
|
+
device: optional(option.device, (v) => expectOneOf(v, deviceKinds, `${optionAt}/device`)),
|
|
105
|
+
className: optional(option.className, (v) => expectString(v, `${optionAt}/className`)),
|
|
106
|
+
attributes: optional(option.attributes, (v) => {
|
|
107
|
+
const attributes = expectObject(v, `${optionAt}/attributes`);
|
|
108
|
+
for (const [name, attribute] of Object.entries(attributes)) expectString(attribute, `${optionAt}/attributes/${name}`);
|
|
109
|
+
return attributes;
|
|
110
|
+
})
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
if (options.length === 0) throw new TypeError(`${at}/options: expected at least one option`);
|
|
114
|
+
return {
|
|
115
|
+
id: expectString(variable.id, `${at}/id`),
|
|
116
|
+
name: expectString(variable.name, `${at}/name`),
|
|
117
|
+
kind: expectOneOf(variable.kind, variableKinds, `${at}/kind`),
|
|
118
|
+
options
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
const modes = expectArray(settings.modes, "/modes").map((item, index) => {
|
|
122
|
+
const at = `/modes/${index}`;
|
|
123
|
+
const mode = expectObject(item, at);
|
|
124
|
+
expectKnownKeys(mode, [
|
|
125
|
+
"id",
|
|
126
|
+
"name",
|
|
127
|
+
"values"
|
|
128
|
+
], at);
|
|
129
|
+
const values = {};
|
|
130
|
+
for (const [variableId, optionId] of Object.entries(expectObject(mode.values, `${at}/values`))) {
|
|
131
|
+
const variable = variables.find((candidate) => candidate.id === variableId);
|
|
132
|
+
if (!variable) throw new TypeError(`${at}/values/${variableId}: unknown variable`);
|
|
133
|
+
const option = expectString(optionId, `${at}/values/${variableId}`);
|
|
134
|
+
if (!variable.options.some((candidate) => candidate.id === option)) throw new TypeError(`${at}/values/${variableId}: "${option}" is not an option of ${variable.name}`);
|
|
135
|
+
values[variableId] = option;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
id: expectString(mode.id, `${at}/id`),
|
|
139
|
+
name: expectString(mode.name, `${at}/name`),
|
|
140
|
+
values
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
if (modes.length === 0) throw new TypeError("/modes: expected at least one mode");
|
|
144
|
+
return {
|
|
145
|
+
version: 1,
|
|
146
|
+
variables,
|
|
147
|
+
modes
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// ../core/src/edit.ts
|
|
151
|
+
const idAlphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
152
|
+
/** A short random id that isn't in `taken`, for nodes and designs created in the editor or by agents. */
|
|
153
|
+
function generateId(taken, length = 5) {
|
|
154
|
+
for (;;) {
|
|
155
|
+
let id = idAlphabet[Math.floor(Math.random() * 52)];
|
|
156
|
+
while (id.length < length) id += idAlphabet[Math.floor(Math.random() * 62)];
|
|
157
|
+
if (!taken.has(id)) return id;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// ../core/src/document.ts
|
|
161
|
+
const textTags = [
|
|
162
|
+
"p",
|
|
163
|
+
"span",
|
|
164
|
+
"h1",
|
|
165
|
+
"h2",
|
|
166
|
+
"h3",
|
|
167
|
+
"h4",
|
|
168
|
+
"strong"
|
|
169
|
+
];
|
|
170
|
+
const imageFits = [
|
|
171
|
+
"cover",
|
|
172
|
+
"contain",
|
|
173
|
+
"fill"
|
|
174
|
+
];
|
|
175
|
+
const paramTypes = [
|
|
176
|
+
"text",
|
|
177
|
+
"boolean",
|
|
178
|
+
"number",
|
|
179
|
+
"value",
|
|
180
|
+
"variant"
|
|
181
|
+
];
|
|
182
|
+
const alignments = [
|
|
183
|
+
"start",
|
|
184
|
+
"center",
|
|
185
|
+
"end",
|
|
186
|
+
"stretch"
|
|
187
|
+
];
|
|
188
|
+
const justifications = [
|
|
189
|
+
"start",
|
|
190
|
+
"center",
|
|
191
|
+
"end",
|
|
192
|
+
"between",
|
|
193
|
+
"around",
|
|
194
|
+
"evenly"
|
|
195
|
+
];
|
|
196
|
+
/** Every style key, in the order panels show them. */
|
|
197
|
+
const styleKeys = [
|
|
198
|
+
"display",
|
|
199
|
+
"direction",
|
|
200
|
+
"columns",
|
|
201
|
+
"rows",
|
|
202
|
+
"gap",
|
|
203
|
+
"rowGap",
|
|
204
|
+
"padding",
|
|
205
|
+
"margin",
|
|
206
|
+
"align",
|
|
207
|
+
"justify",
|
|
208
|
+
"wrap",
|
|
209
|
+
"width",
|
|
210
|
+
"height",
|
|
211
|
+
"minWidth",
|
|
212
|
+
"maxWidth",
|
|
213
|
+
"minHeight",
|
|
214
|
+
"maxHeight",
|
|
215
|
+
"colSpan",
|
|
216
|
+
"rowSpan",
|
|
217
|
+
"grow",
|
|
218
|
+
"self",
|
|
219
|
+
"position",
|
|
220
|
+
"top",
|
|
221
|
+
"right",
|
|
222
|
+
"bottom",
|
|
223
|
+
"left",
|
|
224
|
+
"background",
|
|
225
|
+
"foreground",
|
|
226
|
+
"border",
|
|
227
|
+
"borderWidth",
|
|
228
|
+
"borderStyle",
|
|
229
|
+
"radius",
|
|
230
|
+
"shadow",
|
|
231
|
+
"opacity",
|
|
232
|
+
"overflow",
|
|
233
|
+
"font",
|
|
234
|
+
"size",
|
|
235
|
+
"weight",
|
|
236
|
+
"leading",
|
|
237
|
+
"tracking",
|
|
238
|
+
"textAlign",
|
|
239
|
+
"transform",
|
|
240
|
+
"decoration",
|
|
241
|
+
"italic",
|
|
242
|
+
"lines"
|
|
243
|
+
];
|
|
244
|
+
function parseCanvasDocument(value) {
|
|
245
|
+
const document = expectObject(value, "");
|
|
246
|
+
if (document.version !== 3) throw new TypeError("/version: expected 3");
|
|
247
|
+
expectKnownKeys(document, [
|
|
248
|
+
"version",
|
|
249
|
+
"containers",
|
|
250
|
+
"notes",
|
|
251
|
+
"modes",
|
|
252
|
+
"detection"
|
|
253
|
+
], "");
|
|
254
|
+
return compact({
|
|
255
|
+
version: 3,
|
|
256
|
+
containers: expectArray(document.containers, "/containers").map((item, index) => parseContainer(item, `/containers/${index}`)),
|
|
257
|
+
modes: optional(document.modes, (value) => parseModeSettings(value)),
|
|
258
|
+
notes: optional(document.notes, (value) => expectArray(value, "/notes").map((item, index) => parseNote(item, `/notes/${index}`))),
|
|
259
|
+
detection: optional(document.detection, (value) => parseDetection(value, "/detection"))
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
function parseDetection(value, path) {
|
|
263
|
+
const detection = expectObject(value, path);
|
|
264
|
+
expectKnownKeys(detection, ["include", "exclude"], path);
|
|
265
|
+
const refs = (list, at) => expectArray(list, at).map((item, index) => {
|
|
266
|
+
const ref = expectObject(item, `${at}/${index}`);
|
|
267
|
+
expectKnownKeys(ref, ["path", "export"], `${at}/${index}`);
|
|
268
|
+
return {
|
|
269
|
+
path: expectString(ref.path, `${at}/${index}/path`),
|
|
270
|
+
export: expectString(ref.export, `${at}/${index}/export`)
|
|
271
|
+
};
|
|
272
|
+
});
|
|
273
|
+
return compact({
|
|
274
|
+
include: optional(detection.include, (list) => refs(list, `${path}/include`)),
|
|
275
|
+
exclude: optional(detection.exclude, (list) => refs(list, `${path}/exclude`))
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
function parseNote(value, path) {
|
|
279
|
+
const note = expectObject(value, path);
|
|
280
|
+
expectKnownKeys(note, [
|
|
281
|
+
"id",
|
|
282
|
+
"text",
|
|
283
|
+
"position",
|
|
284
|
+
"width"
|
|
285
|
+
], path);
|
|
286
|
+
const position = expectObject(note.position, `${path}/position`);
|
|
287
|
+
return compact({
|
|
288
|
+
id: expectString(note.id, `${path}/id`),
|
|
289
|
+
text: expectString(note.text, `${path}/text`),
|
|
290
|
+
position: {
|
|
291
|
+
x: expectNumber(position.x, `${path}/position/x`),
|
|
292
|
+
y: expectNumber(position.y, `${path}/position/y`)
|
|
293
|
+
},
|
|
294
|
+
width: optional(note.width, (v) => expectNumber(v, `${path}/width`))
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
function parseContainer(value, path) {
|
|
298
|
+
const container = expectObject(value, path);
|
|
299
|
+
expectKnownKeys(container, [
|
|
300
|
+
"id",
|
|
301
|
+
"name",
|
|
302
|
+
"kind",
|
|
303
|
+
"position",
|
|
304
|
+
"root",
|
|
305
|
+
"states",
|
|
306
|
+
"view",
|
|
307
|
+
"params",
|
|
308
|
+
"context",
|
|
309
|
+
"frames"
|
|
310
|
+
], path);
|
|
311
|
+
const position = expectObject(container.position, `${path}/position`);
|
|
312
|
+
const view = optional(container.view, (v) => {
|
|
313
|
+
const settings = expectObject(v, `${path}/view`);
|
|
314
|
+
expectKnownKeys(settings, [
|
|
315
|
+
"mode",
|
|
316
|
+
"modes",
|
|
317
|
+
"state",
|
|
318
|
+
"allStates",
|
|
319
|
+
"variants"
|
|
320
|
+
], `${path}/view`);
|
|
321
|
+
return compact({
|
|
322
|
+
mode: optional(settings.mode, (mode) => expectString(mode, `${path}/view/mode`)),
|
|
323
|
+
modes: optional(settings.modes, (list) => expectArray(list, `${path}/view/modes`).map((mode, index) => expectString(mode, `${path}/view/modes/${index}`))),
|
|
324
|
+
state: optional(settings.state, (state) => expectString(state, `${path}/view/state`)),
|
|
325
|
+
allStates: optional(settings.allStates, (all) => expectBoolean(all, `${path}/view/allStates`)),
|
|
326
|
+
variants: optional(settings.variants, (choices) => {
|
|
327
|
+
const variants = {};
|
|
328
|
+
for (const [param, option] of Object.entries(expectObject(choices, `${path}/view/variants`))) variants[param] = expectString(option, `${path}/view/variants/${param}`);
|
|
329
|
+
return variants;
|
|
330
|
+
})
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
const ids = /* @__PURE__ */ new Set();
|
|
334
|
+
const root = parseNode(container.root, `${path}/root`, ids);
|
|
335
|
+
const states = expectArray(container.states, `${path}/states`).map((item, index) => {
|
|
336
|
+
const at = `${path}/states/${index}`;
|
|
337
|
+
const state = expectObject(item, at);
|
|
338
|
+
expectKnownKeys(state, [
|
|
339
|
+
"id",
|
|
340
|
+
"name",
|
|
341
|
+
"overrides"
|
|
342
|
+
], at);
|
|
343
|
+
return {
|
|
344
|
+
id: expectString(state.id, `${at}/id`),
|
|
345
|
+
name: expectString(state.name, `${at}/name`),
|
|
346
|
+
overrides: optional(state.overrides, (v) => parsePatches(v, `${at}/overrides`, ids))
|
|
347
|
+
};
|
|
348
|
+
});
|
|
349
|
+
if (states.length === 0) throw new TypeError(`${path}/states: expected at least one state`);
|
|
350
|
+
return compact({
|
|
351
|
+
id: expectString(container.id, `${path}/id`),
|
|
352
|
+
name: expectString(container.name, `${path}/name`),
|
|
353
|
+
kind: optional(container.kind, (v) => expectOneOf(v, ["screen", "component"], `${path}/kind`)),
|
|
354
|
+
context: optional(container.context, (v) => expectArray(v, `${path}/context`).map((item, index) => {
|
|
355
|
+
const at = `${path}/context/${index}`;
|
|
356
|
+
const wrapper = expectObject(item, at);
|
|
357
|
+
expectKnownKeys(wrapper, ["component", "props"], at);
|
|
358
|
+
return compact({
|
|
359
|
+
component: expectString(wrapper.component, `${at}/component`),
|
|
360
|
+
props: optional(wrapper.props, (p) => expectObject(p, `${at}/props`))
|
|
361
|
+
});
|
|
362
|
+
})),
|
|
363
|
+
params: optional(container.params, (v) => {
|
|
364
|
+
const params = {};
|
|
365
|
+
for (const [name, entry] of Object.entries(expectObject(v, `${path}/params`))) {
|
|
366
|
+
const at = `${path}/params/${name}`;
|
|
367
|
+
const param = expectObject(entry, at);
|
|
368
|
+
expectKnownKeys(param, [
|
|
369
|
+
"type",
|
|
370
|
+
"default",
|
|
371
|
+
"description",
|
|
372
|
+
"options"
|
|
373
|
+
], at);
|
|
374
|
+
const type = expectOneOf(param.type, paramTypes, `${at}/type`);
|
|
375
|
+
const options = optional(param.options, (list) => {
|
|
376
|
+
const seen = /* @__PURE__ */ new Set();
|
|
377
|
+
return expectArray(list, `${at}/options`).map((item, index) => {
|
|
378
|
+
const where = `${at}/options/${index}`;
|
|
379
|
+
const option = expectObject(item, where);
|
|
380
|
+
expectKnownKeys(option, [
|
|
381
|
+
"id",
|
|
382
|
+
"name",
|
|
383
|
+
"overrides"
|
|
384
|
+
], where);
|
|
385
|
+
const id = expectString(option.id, `${where}/id`);
|
|
386
|
+
if (seen.has(id)) throw new TypeError(`${where}/id: duplicate option id "${id}"`);
|
|
387
|
+
seen.add(id);
|
|
388
|
+
return compact({
|
|
389
|
+
id,
|
|
390
|
+
name: expectString(option.name, `${where}/name`),
|
|
391
|
+
overrides: optional(option.overrides, (v) => parsePatches(v, `${where}/overrides`, ids))
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
if (type === "variant" && !options?.length) throw new TypeError(`${at}/options: a variant needs options`);
|
|
396
|
+
if (type !== "variant" && options) throw new TypeError(`${at}/options: only variants have options`);
|
|
397
|
+
params[name] = compact({
|
|
398
|
+
type,
|
|
399
|
+
default: param.default,
|
|
400
|
+
description: optional(param.description, (d) => expectString(d, `${at}/description`)),
|
|
401
|
+
options
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
return params;
|
|
405
|
+
}),
|
|
406
|
+
frames: optional(container.frames, (v) => {
|
|
407
|
+
const frames = {};
|
|
408
|
+
for (const [viewport, entry] of Object.entries(expectObject(v, `${path}/frames`))) {
|
|
409
|
+
const at = `${path}/frames/${viewport}`;
|
|
410
|
+
const size = expectObject(entry, at);
|
|
411
|
+
expectKnownKeys(size, ["width", "height"], at);
|
|
412
|
+
frames[viewport] = compact({
|
|
413
|
+
width: optional(size.width, (w) => expectNumber(w, `${at}/width`)),
|
|
414
|
+
height: optional(size.height, (h) => expectNumber(h, `${at}/height`))
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
return frames;
|
|
418
|
+
}),
|
|
419
|
+
position: {
|
|
420
|
+
x: expectNumber(position.x, `${path}/position/x`),
|
|
421
|
+
y: expectNumber(position.y, `${path}/position/y`)
|
|
422
|
+
},
|
|
423
|
+
root,
|
|
424
|
+
states,
|
|
425
|
+
view
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
function parseNode(value, path, ids) {
|
|
429
|
+
const node = expectObject(value, path);
|
|
430
|
+
const type = expectOneOf(node.type, [
|
|
431
|
+
"layout",
|
|
432
|
+
"component",
|
|
433
|
+
"text",
|
|
434
|
+
"instance",
|
|
435
|
+
"image"
|
|
436
|
+
], `${path}/type`);
|
|
437
|
+
const id = expectString(node.id, `${path}/id`);
|
|
438
|
+
if (ids.has(id)) throw new TypeError(`${path}/id: duplicate node id "${id}"`);
|
|
439
|
+
ids.add(id);
|
|
440
|
+
const base = compact({
|
|
441
|
+
id,
|
|
442
|
+
name: optional(node.name, (v) => expectString(v, `${path}/name`)),
|
|
443
|
+
hidden: optional(node.hidden, (v) => expectBoolean(v, `${path}/hidden`)),
|
|
444
|
+
style: optional(node.style, (v) => parseStyle(v, `${path}/style`)),
|
|
445
|
+
responsive: optional(node.responsive, (v) => parsePatches(v, `${path}/responsive`)),
|
|
446
|
+
bind: optional(node.bind, (v) => parseBinding(v, `${path}/bind`))
|
|
447
|
+
});
|
|
448
|
+
const common = [
|
|
449
|
+
"type",
|
|
450
|
+
"id",
|
|
451
|
+
"name",
|
|
452
|
+
"hidden",
|
|
453
|
+
"style",
|
|
454
|
+
"responsive",
|
|
455
|
+
"bind"
|
|
456
|
+
];
|
|
457
|
+
switch (type) {
|
|
458
|
+
case "layout":
|
|
459
|
+
expectKnownKeys(node, [...common, "children"], path);
|
|
460
|
+
return {
|
|
461
|
+
...base,
|
|
462
|
+
type,
|
|
463
|
+
children: expectArray(node.children, `${path}/children`).map((child, index) => parseNode(child, `${path}/children/${index}`, ids))
|
|
464
|
+
};
|
|
465
|
+
case "component": {
|
|
466
|
+
expectKnownKeys(node, [
|
|
467
|
+
...common,
|
|
468
|
+
"component",
|
|
469
|
+
"props",
|
|
470
|
+
"slots"
|
|
471
|
+
], path);
|
|
472
|
+
const slots = optional(node.slots, (v) => {
|
|
473
|
+
const result = {};
|
|
474
|
+
for (const [slot, children] of Object.entries(expectObject(v, `${path}/slots`))) result[slot] = expectArray(children, `${path}/slots/${slot}`).map((child, index) => parseNode(child, `${path}/slots/${slot}/${index}`, ids));
|
|
475
|
+
return result;
|
|
476
|
+
});
|
|
477
|
+
return {
|
|
478
|
+
...base,
|
|
479
|
+
type,
|
|
480
|
+
component: expectString(node.component, `${path}/component`),
|
|
481
|
+
props: optional(node.props, (v) => expectObject(v, `${path}/props`)),
|
|
482
|
+
slots
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
case "instance":
|
|
486
|
+
expectKnownKeys(node, [
|
|
487
|
+
...common,
|
|
488
|
+
"design",
|
|
489
|
+
"args",
|
|
490
|
+
"state",
|
|
491
|
+
"overrides"
|
|
492
|
+
], path);
|
|
493
|
+
return compact({
|
|
494
|
+
...base,
|
|
495
|
+
type,
|
|
496
|
+
design: expectString(node.design, `${path}/design`),
|
|
497
|
+
args: optional(node.args, (v) => expectObject(v, `${path}/args`)),
|
|
498
|
+
state: optional(node.state, (v) => expectString(v, `${path}/state`)),
|
|
499
|
+
overrides: optional(node.overrides, (v) => parsePatches(v, `${path}/overrides`))
|
|
500
|
+
});
|
|
501
|
+
case "text":
|
|
502
|
+
expectKnownKeys(node, [
|
|
503
|
+
...common,
|
|
504
|
+
"text",
|
|
505
|
+
"tag"
|
|
506
|
+
], path);
|
|
507
|
+
return {
|
|
508
|
+
...base,
|
|
509
|
+
type,
|
|
510
|
+
text: expectString(node.text, `${path}/text`),
|
|
511
|
+
tag: optional(node.tag, (v) => expectOneOf(v, textTags, `${path}/tag`))
|
|
512
|
+
};
|
|
513
|
+
case "image":
|
|
514
|
+
expectKnownKeys(node, [
|
|
515
|
+
...common,
|
|
516
|
+
"src",
|
|
517
|
+
"alt",
|
|
518
|
+
"fit",
|
|
519
|
+
"credit"
|
|
520
|
+
], path);
|
|
521
|
+
return compact({
|
|
522
|
+
...base,
|
|
523
|
+
type,
|
|
524
|
+
src: expectString(node.src, `${path}/src`),
|
|
525
|
+
alt: optional(node.alt, (v) => expectString(v, `${path}/alt`)),
|
|
526
|
+
fit: optional(node.fit, (v) => expectOneOf(v, imageFits, `${path}/fit`)),
|
|
527
|
+
credit: optional(node.credit, (v) => {
|
|
528
|
+
const credit = expectObject(v, `${path}/credit`);
|
|
529
|
+
expectKnownKeys(credit, [
|
|
530
|
+
"name",
|
|
531
|
+
"url",
|
|
532
|
+
"source"
|
|
533
|
+
], `${path}/credit`);
|
|
534
|
+
return compact({
|
|
535
|
+
name: expectString(credit.name, `${path}/credit/name`),
|
|
536
|
+
url: expectString(credit.url, `${path}/credit/url`),
|
|
537
|
+
source: optional(credit.source, (s) => expectString(s, `${path}/credit/source`))
|
|
538
|
+
});
|
|
539
|
+
})
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
function parseBinding(value, path) {
|
|
544
|
+
const binding = expectObject(value, path);
|
|
545
|
+
expectKnownKeys(binding, [
|
|
546
|
+
"text",
|
|
547
|
+
"props",
|
|
548
|
+
"visible"
|
|
549
|
+
], path);
|
|
550
|
+
return compact({
|
|
551
|
+
text: optional(binding.text, (v) => expectString(v, `${path}/text`)),
|
|
552
|
+
visible: optional(binding.visible, (v) => expectString(v, `${path}/visible`)),
|
|
553
|
+
props: optional(binding.props, (v) => {
|
|
554
|
+
const props = {};
|
|
555
|
+
for (const [prop, param] of Object.entries(expectObject(v, `${path}/props`))) props[prop] = expectString(param, `${path}/props/${prop}`);
|
|
556
|
+
return props;
|
|
557
|
+
})
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Patches keyed by node id. With `ids`, each key must name a node of the design, or start with one: `instance/inner`
|
|
562
|
+
* reaches inside an instance, which can't be checked without the component.
|
|
563
|
+
*/
|
|
564
|
+
function parsePatches(value, path, ids) {
|
|
565
|
+
const patches = {};
|
|
566
|
+
for (const [key, entry] of Object.entries(expectObject(value, path))) {
|
|
567
|
+
if (ids && !ids.has(key.split("/")[0])) throw new TypeError(`${path}/${key}: no node has this id`);
|
|
568
|
+
patches[key] = parsePatch(entry, `${path}/${key}`);
|
|
569
|
+
}
|
|
570
|
+
return patches;
|
|
571
|
+
}
|
|
572
|
+
function parsePatch(value, path) {
|
|
573
|
+
const patch = expectObject(value, path);
|
|
574
|
+
expectKnownKeys(patch, [
|
|
575
|
+
"hidden",
|
|
576
|
+
"text",
|
|
577
|
+
"props",
|
|
578
|
+
"style"
|
|
579
|
+
], path);
|
|
580
|
+
return compact({
|
|
581
|
+
hidden: optional(patch.hidden, (v) => expectBoolean(v, `${path}/hidden`)),
|
|
582
|
+
text: optional(patch.text, (v) => expectString(v, `${path}/text`)),
|
|
583
|
+
props: optional(patch.props, (v) => expectObject(v, `${path}/props`)),
|
|
584
|
+
style: optional(patch.style, (v) => parseStyle(v, `${path}/style`))
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
function parseStyle(value, path) {
|
|
588
|
+
const style = expectObject(value, path);
|
|
589
|
+
const at = (key) => `${path}/${key}`;
|
|
590
|
+
const token = (key) => optional(style[key], (v) => expectString(v, at(key)));
|
|
591
|
+
const number = (key) => optional(style[key], (v) => expectNumber(v, at(key)));
|
|
592
|
+
const flag = (key) => optional(style[key], (v) => expectBoolean(v, at(key)));
|
|
593
|
+
const lengthAt = (v, where) => typeof v === "number" ? v : expectString(v, where);
|
|
594
|
+
const length = (key) => optional(style[key], (v) => lengthAt(v, at(key)));
|
|
595
|
+
const size = (key) => optional(style[key], (v) => lengthAt(v, at(key)));
|
|
596
|
+
const sides = (key) => optional(style[key], (v) => {
|
|
597
|
+
if (!Array.isArray(v)) return lengthAt(v, at(key));
|
|
598
|
+
if (v.length !== 2 && v.length !== 4) throw new TypeError(`${at(key)}: expected a length, [vertical, horizontal] or [top, right, bottom, left]`);
|
|
599
|
+
return v.map((side, index) => lengthAt(side, `${at(key)}/${index}`));
|
|
600
|
+
});
|
|
601
|
+
expectKnownKeys(style, styleKeys, path);
|
|
602
|
+
return compact({
|
|
603
|
+
display: optional(style.display, (v) => expectOneOf(v, ["flex", "grid"], at("display"))),
|
|
604
|
+
direction: optional(style.direction, (v) => expectOneOf(v, ["row", "column"], at("direction"))),
|
|
605
|
+
columns: number("columns"),
|
|
606
|
+
rows: number("rows"),
|
|
607
|
+
gap: length("gap"),
|
|
608
|
+
rowGap: length("rowGap"),
|
|
609
|
+
padding: sides("padding"),
|
|
610
|
+
margin: sides("margin"),
|
|
611
|
+
align: optional(style.align, (v) => expectOneOf(v, alignments, at("align"))),
|
|
612
|
+
justify: optional(style.justify, (v) => expectOneOf(v, justifications, at("justify"))),
|
|
613
|
+
wrap: flag("wrap"),
|
|
614
|
+
width: size("width"),
|
|
615
|
+
height: size("height"),
|
|
616
|
+
minWidth: length("minWidth"),
|
|
617
|
+
maxWidth: length("maxWidth"),
|
|
618
|
+
minHeight: length("minHeight"),
|
|
619
|
+
maxHeight: length("maxHeight"),
|
|
620
|
+
colSpan: number("colSpan"),
|
|
621
|
+
rowSpan: number("rowSpan"),
|
|
622
|
+
grow: flag("grow"),
|
|
623
|
+
self: optional(style.self, (v) => expectOneOf(v, alignments, at("self"))),
|
|
624
|
+
position: optional(style.position, (v) => expectOneOf(v, ["absolute"], at("position"))),
|
|
625
|
+
top: length("top"),
|
|
626
|
+
right: length("right"),
|
|
627
|
+
bottom: length("bottom"),
|
|
628
|
+
left: length("left"),
|
|
629
|
+
background: token("background"),
|
|
630
|
+
foreground: token("foreground"),
|
|
631
|
+
border: token("border"),
|
|
632
|
+
borderWidth: number("borderWidth"),
|
|
633
|
+
borderStyle: optional(style.borderStyle, (v) => expectOneOf(v, [
|
|
634
|
+
"solid",
|
|
635
|
+
"dashed",
|
|
636
|
+
"dotted"
|
|
637
|
+
], at("borderStyle"))),
|
|
638
|
+
radius: token("radius"),
|
|
639
|
+
shadow: token("shadow"),
|
|
640
|
+
opacity: number("opacity"),
|
|
641
|
+
overflow: optional(style.overflow, (v) => expectOneOf(v, [
|
|
642
|
+
"visible",
|
|
643
|
+
"hidden",
|
|
644
|
+
"scroll"
|
|
645
|
+
], at("overflow"))),
|
|
646
|
+
font: token("font"),
|
|
647
|
+
size: token("size"),
|
|
648
|
+
weight: number("weight"),
|
|
649
|
+
leading: token("leading"),
|
|
650
|
+
tracking: token("tracking"),
|
|
651
|
+
textAlign: optional(style.textAlign, (v) => expectOneOf(v, [
|
|
652
|
+
"start",
|
|
653
|
+
"center",
|
|
654
|
+
"end",
|
|
655
|
+
"justify"
|
|
656
|
+
], at("textAlign"))),
|
|
657
|
+
transform: optional(style.transform, (v) => expectOneOf(v, [
|
|
658
|
+
"uppercase",
|
|
659
|
+
"lowercase",
|
|
660
|
+
"capitalize"
|
|
661
|
+
], at("transform"))),
|
|
662
|
+
decoration: optional(style.decoration, (v) => expectOneOf(v, ["underline", "line-through"], at("decoration"))),
|
|
663
|
+
italic: flag("italic"),
|
|
664
|
+
lines: number("lines")
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
// ../core/src/library.ts
|
|
668
|
+
/** How a component was recognised, which is also why it's believed to be one. */
|
|
669
|
+
const componentEvidence = [
|
|
670
|
+
"function",
|
|
671
|
+
"forwardRef",
|
|
672
|
+
"memo",
|
|
673
|
+
"lazy",
|
|
674
|
+
"class",
|
|
675
|
+
"exotic"
|
|
676
|
+
];
|
|
677
|
+
/**
|
|
678
|
+
* Where a part's parents came from: the library's own examples and stories, the namespace it's exported in
|
|
679
|
+
* (`Accordion.Item`), the error it throws alone ("must be used within `Accordion`"), a shared name prefix
|
|
680
|
+
* (`AccordionItem` under `Accordion`), or a hand edit.
|
|
681
|
+
*/
|
|
682
|
+
const parentSignals = [
|
|
683
|
+
"example",
|
|
684
|
+
"source",
|
|
685
|
+
"namespace",
|
|
686
|
+
"error",
|
|
687
|
+
"prefix",
|
|
688
|
+
"edit",
|
|
689
|
+
"app"
|
|
690
|
+
];
|
|
691
|
+
/** Whether a sample's prop value is elements. */
|
|
692
|
+
function isSampleElement(value) {
|
|
693
|
+
return typeof value === "object" && value !== null && Array.isArray(value.$element);
|
|
694
|
+
}
|
|
695
|
+
/** Whether a sample's prop value is one the package makes. */
|
|
696
|
+
function isMadeValue(value) {
|
|
697
|
+
const call = typeof value === "object" && value !== null ? value.$call : void 0;
|
|
698
|
+
return typeof call === "object" && call !== null && typeof call.import === "string";
|
|
699
|
+
}
|
|
700
|
+
/** Whether a sample's child or prop value is a render function. */
|
|
701
|
+
function isSampleRender(value) {
|
|
702
|
+
return typeof value === "object" && value !== null && Array.isArray(value.$render);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Where a part's sample calls what's inside it: its function children, else a render prop (Chakra's `TreeView.Node`
|
|
706
|
+
* `render`), with the render function.
|
|
707
|
+
*/
|
|
708
|
+
function renderSlotOf(sample) {
|
|
709
|
+
const children = sample?.children?.find(isSampleRender);
|
|
710
|
+
if (children) return {
|
|
711
|
+
prop: "children",
|
|
712
|
+
render: children
|
|
713
|
+
};
|
|
714
|
+
const entry = Object.entries(sample?.props ?? {}).find(([, value]) => isSampleRender(value));
|
|
715
|
+
return entry ? {
|
|
716
|
+
prop: entry[0],
|
|
717
|
+
render: entry[1]
|
|
718
|
+
} : void 0;
|
|
719
|
+
}
|
|
720
|
+
const decoratorKeys = [
|
|
721
|
+
"when",
|
|
722
|
+
"wrap",
|
|
723
|
+
"add",
|
|
724
|
+
"class",
|
|
725
|
+
"attributes",
|
|
726
|
+
"style"
|
|
727
|
+
];
|
|
728
|
+
/** A library manifest's extension. It describes a library, and its `canvas` holds the library's own designs. */
|
|
729
|
+
const libraryManifestExtension = ".lib.par";
|
|
730
|
+
function parseLibraryManifest(value) {
|
|
731
|
+
const manifest = expectObject(value, "");
|
|
732
|
+
const keys = [
|
|
733
|
+
"$schema",
|
|
734
|
+
"version",
|
|
735
|
+
"id",
|
|
736
|
+
"name",
|
|
737
|
+
"description",
|
|
738
|
+
"styles",
|
|
739
|
+
"breakpoints",
|
|
740
|
+
"tokens",
|
|
741
|
+
"canvas"
|
|
742
|
+
];
|
|
743
|
+
if (manifest.version === 3) keys.push("package", "components", "icons", "decorators", "edits");
|
|
744
|
+
expectKnownKeys(manifest, keys, "");
|
|
745
|
+
if (manifest.version !== 1 && manifest.version !== 2 && manifest.version !== 3) throw new TypeError("/version: expected 1, 2 or 3");
|
|
746
|
+
return compact({
|
|
747
|
+
version: manifest.version,
|
|
748
|
+
id: optional(manifest.id, (v) => expectString(v, "/id")),
|
|
749
|
+
name: expectString(manifest.name, "/name"),
|
|
750
|
+
description: optional(manifest.description, (v) => expectString(v, "/description")),
|
|
751
|
+
package: optional(manifest.package, parsePackage),
|
|
752
|
+
styles: optional(manifest.styles, (v) => expectString(v, "/styles")),
|
|
753
|
+
breakpoints: optional(manifest.breakpoints, (v) => expectArray(v, "/breakpoints").map((item, index) => {
|
|
754
|
+
const at = `/breakpoints/${index}`;
|
|
755
|
+
const breakpoint = expectObject(item, at);
|
|
756
|
+
expectKnownKeys(breakpoint, [
|
|
757
|
+
"id",
|
|
758
|
+
"name",
|
|
759
|
+
"width"
|
|
760
|
+
], at);
|
|
761
|
+
return {
|
|
762
|
+
id: expectString(breakpoint.id, `${at}/id`),
|
|
763
|
+
name: expectString(breakpoint.name, `${at}/name`),
|
|
764
|
+
width: expectNumber(breakpoint.width, `${at}/width`)
|
|
765
|
+
};
|
|
766
|
+
}).sort((a, b) => a.width - b.width)),
|
|
767
|
+
tokens: optional(manifest.tokens, (v) => typeof v === "string" ? v : expectObject(v, "/tokens")),
|
|
768
|
+
components: optional(manifest.components, parseComponents),
|
|
769
|
+
icons: optional(manifest.icons, parseIcons),
|
|
770
|
+
decorators: optional(manifest.decorators, (v) => expectArray(v, "/decorators").map(parseDecorator)),
|
|
771
|
+
edits: optional(manifest.edits, (v) => typeof v === "string" ? v : parseLibraryEdits(v, "/edits")),
|
|
772
|
+
canvas: optional(manifest.canvas, (v) => {
|
|
773
|
+
try {
|
|
774
|
+
return parseCanvasDocument(v);
|
|
775
|
+
} catch (error) {
|
|
776
|
+
throw new TypeError(`/canvas${error instanceof Error ? error.message : String(error)}`);
|
|
777
|
+
}
|
|
778
|
+
})
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
function parsePackage(value) {
|
|
782
|
+
const pkg = expectObject(value, "/package");
|
|
783
|
+
expectKnownKeys(pkg, [
|
|
784
|
+
"name",
|
|
785
|
+
"version",
|
|
786
|
+
"range"
|
|
787
|
+
], "/package");
|
|
788
|
+
return compact({
|
|
789
|
+
name: expectString(pkg.name, "/package/name"),
|
|
790
|
+
version: optional(pkg.version, (v) => expectString(v, "/package/version")),
|
|
791
|
+
range: optional(pkg.range, (v) => expectString(v, "/package/range"))
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
function parseComponents(value) {
|
|
795
|
+
const components = expectObject(value, "/components");
|
|
796
|
+
expectKnownKeys(components, ["import", "list"], "/components");
|
|
797
|
+
const list = {};
|
|
798
|
+
for (const [name, entry] of Object.entries(expectObject(components.list, "/components/list"))) {
|
|
799
|
+
const at = `/components/list/${name}`;
|
|
800
|
+
const component = expectObject(entry, at);
|
|
801
|
+
expectKnownKeys(component, [
|
|
802
|
+
...componentKeys,
|
|
803
|
+
"fingerprint",
|
|
804
|
+
"props"
|
|
805
|
+
], at);
|
|
806
|
+
list[name] = compact({
|
|
807
|
+
...parseComponentFields(component, at),
|
|
808
|
+
as: expectOneOf(component.as, componentEvidence, `${at}/as`),
|
|
809
|
+
fingerprint: optional(component.fingerprint, (v) => expectString(v, `${at}/fingerprint`)),
|
|
810
|
+
props: optional(component.props, (v) => expectStringRecord(v, `${at}/props`))
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
return compact({
|
|
814
|
+
import: optional(components.import, (v) => expectString(v, "/components/import")),
|
|
815
|
+
list
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
const componentKeys = [
|
|
819
|
+
"as",
|
|
820
|
+
"declaration",
|
|
821
|
+
"group",
|
|
822
|
+
"parents",
|
|
823
|
+
"parentsFrom",
|
|
824
|
+
"optionalParents",
|
|
825
|
+
"parentParts",
|
|
826
|
+
"visual",
|
|
827
|
+
"internal",
|
|
828
|
+
"sample"
|
|
829
|
+
];
|
|
830
|
+
function parseComponentFields(component, at) {
|
|
831
|
+
return compact({
|
|
832
|
+
as: optional(component.as, (v) => expectOneOf(v, componentEvidence, `${at}/as`)),
|
|
833
|
+
declaration: optional(component.declaration, (v) => expectString(v, `${at}/declaration`)),
|
|
834
|
+
group: optional(component.group, (v) => expectString(v, `${at}/group`)),
|
|
835
|
+
parents: optional(component.parents, (v) => expectArray(v, `${at}/parents`).map((name, index) => expectString(name, `${at}/parents/${index}`))),
|
|
836
|
+
parentsFrom: optional(component.parentsFrom, (v) => expectOneOf(v, parentSignals, `${at}/parentsFrom`)),
|
|
837
|
+
optionalParents: optional(component.optionalParents, (v) => expectArray(v, `${at}/optionalParents`).map((name, index) => expectString(name, `${at}/optionalParents/${index}`))),
|
|
838
|
+
parentParts: optional(component.parentParts, (v) => {
|
|
839
|
+
if (typeof v !== "boolean") throw new TypeError(`${at}/parentParts: expected a boolean`);
|
|
840
|
+
return v;
|
|
841
|
+
}),
|
|
842
|
+
visual: optional(component.visual, (v) => {
|
|
843
|
+
if (typeof v !== "boolean") throw new TypeError(`${at}/visual: expected a boolean`);
|
|
844
|
+
return v;
|
|
845
|
+
}),
|
|
846
|
+
internal: optional(component.internal, (v) => {
|
|
847
|
+
if (typeof v !== "boolean") throw new TypeError(`${at}/internal: expected a boolean`);
|
|
848
|
+
return v;
|
|
849
|
+
}),
|
|
850
|
+
sample: optional(component.sample, (v) => parseSample(v, `${at}/sample`))
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
function parseSample(value, at) {
|
|
854
|
+
const sample = expectObject(value, at);
|
|
855
|
+
expectKnownKeys(sample, ["props", "children"], at);
|
|
856
|
+
return compact({
|
|
857
|
+
props: optional(sample.props, (v) => expectObject(v, `${at}/props`)),
|
|
858
|
+
children: optional(sample.children, (v) => parseSampleChildren(v, `${at}/children`))
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
function parseSampleChildren(value, at) {
|
|
862
|
+
return expectArray(value, at).map((item, index) => {
|
|
863
|
+
const here = `${at}/${index}`;
|
|
864
|
+
if (typeof item === "string") return item;
|
|
865
|
+
const child = expectObject(item, here);
|
|
866
|
+
if ("$render" in child) {
|
|
867
|
+
expectKnownKeys(child, [
|
|
868
|
+
"$render",
|
|
869
|
+
"spread",
|
|
870
|
+
"pass"
|
|
871
|
+
], here);
|
|
872
|
+
if (child.spread !== void 0 && child.spread !== true) throw new TypeError(`${here}/spread: expected true`);
|
|
873
|
+
const render = { $render: parseSampleChildren(child.$render, `${here}/$render`) };
|
|
874
|
+
if (child.spread) render.spread = true;
|
|
875
|
+
if (child.pass !== void 0) render.pass = expectArray(child.pass, `${here}/pass`).map((prop, index) => expectString(prop, `${here}/pass/${index}`));
|
|
876
|
+
return render;
|
|
877
|
+
}
|
|
878
|
+
expectKnownKeys(child, [
|
|
879
|
+
"component",
|
|
880
|
+
"props",
|
|
881
|
+
"children"
|
|
882
|
+
], here);
|
|
883
|
+
return compact({
|
|
884
|
+
component: expectString(child.component, `${here}/component`),
|
|
885
|
+
props: optional(child.props, (v) => expectObject(v, `${here}/props`)),
|
|
886
|
+
children: optional(child.children, (v) => parseSampleChildren(v, `${here}/children`))
|
|
887
|
+
});
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
/** Reads hand edits to a library file, from its `edits` or a shared file of them. */
|
|
891
|
+
function parseLibraryEdits(value, at = "") {
|
|
892
|
+
const edits = expectObject(value, at);
|
|
893
|
+
expectKnownKeys(edits, [
|
|
894
|
+
"$schema",
|
|
895
|
+
"components",
|
|
896
|
+
"decorators"
|
|
897
|
+
], at);
|
|
898
|
+
return compact({
|
|
899
|
+
components: optional(edits.components, (v) => {
|
|
900
|
+
const result = {};
|
|
901
|
+
for (const [name, entry] of Object.entries(expectObject(v, `${at}/components`))) {
|
|
902
|
+
const here = `${at}/components/${name}`;
|
|
903
|
+
if (entry === false) {
|
|
904
|
+
result[name] = false;
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
const component = expectObject(entry, here);
|
|
908
|
+
expectKnownKeys(component, componentKeys, here);
|
|
909
|
+
result[name] = parseComponentFields(component, here);
|
|
910
|
+
}
|
|
911
|
+
return result;
|
|
912
|
+
}),
|
|
913
|
+
decorators: optional(edits.decorators, (v) => expectArray(v, `${at}/decorators`).map(parseDecorator))
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* The manifest with hand edits merged over what was generated, and the edited exports it no longer has, which are
|
|
918
|
+
* reported rather than dropped silently. An edit can add a component the checker missed, if it says what it's `as`.
|
|
919
|
+
*/
|
|
920
|
+
function applyLibraryEdits(manifest, edits) {
|
|
921
|
+
if (!edits) return {
|
|
922
|
+
manifest,
|
|
923
|
+
orphans: []
|
|
924
|
+
};
|
|
925
|
+
const orphans = [];
|
|
926
|
+
let components = manifest.components;
|
|
927
|
+
if (edits.components) {
|
|
928
|
+
const list = { ...components?.list };
|
|
929
|
+
for (const [name, edit] of Object.entries(edits.components)) {
|
|
930
|
+
const generated = list[name];
|
|
931
|
+
if (edit === false) {
|
|
932
|
+
if (generated) delete list[name];
|
|
933
|
+
else orphans.push(name);
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
if (!generated && !edit.as) {
|
|
937
|
+
orphans.push(name);
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
940
|
+
const merged = {
|
|
941
|
+
...generated,
|
|
942
|
+
...edit
|
|
943
|
+
};
|
|
944
|
+
if (edit.parents && !edit.parentsFrom) merged.parentsFrom = "edit";
|
|
945
|
+
if (edit.parents && !edit.optionalParents) delete merged.optionalParents;
|
|
946
|
+
list[name] = merged;
|
|
947
|
+
}
|
|
948
|
+
components = {
|
|
949
|
+
...components,
|
|
950
|
+
list
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
return {
|
|
954
|
+
manifest: compact({
|
|
955
|
+
...manifest,
|
|
956
|
+
components,
|
|
957
|
+
decorators: edits.decorators ?? manifest.decorators
|
|
958
|
+
}),
|
|
959
|
+
orphans
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
function parseIcons(value) {
|
|
963
|
+
const icons = expectObject(value, "/icons");
|
|
964
|
+
expectKnownKeys(icons, [
|
|
965
|
+
"import",
|
|
966
|
+
"render",
|
|
967
|
+
"match",
|
|
968
|
+
"exclude",
|
|
969
|
+
"prefer",
|
|
970
|
+
"variants",
|
|
971
|
+
"count",
|
|
972
|
+
"tags",
|
|
973
|
+
"tagSource"
|
|
974
|
+
], "/icons");
|
|
975
|
+
let render;
|
|
976
|
+
if (icons.render === "export") render = "export";
|
|
977
|
+
else {
|
|
978
|
+
const renderer = expectObject(icons.render, "/icons/render");
|
|
979
|
+
expectKnownKeys(renderer, [
|
|
980
|
+
"import",
|
|
981
|
+
"component",
|
|
982
|
+
"prop"
|
|
983
|
+
], "/icons/render");
|
|
984
|
+
render = {
|
|
985
|
+
import: expectString(renderer.import, "/icons/render/import"),
|
|
986
|
+
component: expectString(renderer.component, "/icons/render/component"),
|
|
987
|
+
prop: expectString(renderer.prop, "/icons/render/prop")
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
return compact({
|
|
991
|
+
import: optional(icons.import, (v) => expectString(v, "/icons/import")),
|
|
992
|
+
render,
|
|
993
|
+
match: optional(icons.match, (v) => expectPattern(v, "/icons/match")),
|
|
994
|
+
exclude: optional(icons.exclude, (v) => expectArray(v, "/icons/exclude").map((name, index) => expectString(name, `/icons/exclude/${index}`))),
|
|
995
|
+
prefer: optional(icons.prefer, (v) => expectArray(v, "/icons/prefer").map((name, index) => expectString(name, `/icons/prefer/${index}`))),
|
|
996
|
+
variants: optional(icons.variants, (v) => {
|
|
997
|
+
const variants = expectObject(v, "/icons/variants");
|
|
998
|
+
expectKnownKeys(variants, [
|
|
999
|
+
"pattern",
|
|
1000
|
+
"prop",
|
|
1001
|
+
"modules",
|
|
1002
|
+
"styles",
|
|
1003
|
+
"sizes",
|
|
1004
|
+
"default"
|
|
1005
|
+
], "/icons/variants");
|
|
1006
|
+
return compact({
|
|
1007
|
+
pattern: optional(variants.pattern, (pattern) => expectPattern(pattern, "/icons/variants/pattern")),
|
|
1008
|
+
prop: optional(variants.prop, (prop) => expectString(prop, "/icons/variants/prop")),
|
|
1009
|
+
modules: optional(variants.modules, (modules) => expectStringRecord(modules, "/icons/variants/modules")),
|
|
1010
|
+
styles: optional(variants.styles, (list) => expectArray(list, "/icons/variants/styles").map((style, index) => expectString(style, `/icons/variants/styles/${index}`))),
|
|
1011
|
+
sizes: optional(variants.sizes, (list) => expectArray(list, "/icons/variants/sizes").map((size, index) => expectNumber(size, `/icons/variants/sizes/${index}`))),
|
|
1012
|
+
default: optional(variants.default, (d) => {
|
|
1013
|
+
const fallback = expectObject(d, "/icons/variants/default");
|
|
1014
|
+
expectKnownKeys(fallback, ["style", "size"], "/icons/variants/default");
|
|
1015
|
+
return compact({
|
|
1016
|
+
style: optional(fallback.style, (s) => expectString(s, "/icons/variants/default/style")),
|
|
1017
|
+
size: optional(fallback.size, (s) => expectNumber(s, "/icons/variants/default/size"))
|
|
1018
|
+
});
|
|
1019
|
+
})
|
|
1020
|
+
});
|
|
1021
|
+
}),
|
|
1022
|
+
count: optional(icons.count, (v) => expectNumber(v, "/icons/count")),
|
|
1023
|
+
tags: optional(icons.tags, (v) => Object.fromEntries(Object.entries(expectObject(v, "/icons/tags")).map(([name, list]) => [name, expectArray(list, `/icons/tags/${name}`).map((tag, index) => expectString(tag, `/icons/tags/${name}/${index}`))]))),
|
|
1024
|
+
tagSource: optional(icons.tagSource, (v) => expectString(v, "/icons/tagSource"))
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
function parseDecorator(value, index) {
|
|
1028
|
+
const at = `/decorators/${index}`;
|
|
1029
|
+
const decorator = expectObject(value, at);
|
|
1030
|
+
expectKnownKeys(decorator, decoratorKeys, at);
|
|
1031
|
+
if (decoratorKeys.filter((key) => key !== "when" && decorator[key] !== void 0).length !== 1) throw new TypeError(`${at}: expected one of wrap, add, class, attributes or style`);
|
|
1032
|
+
const element = (v, path) => {
|
|
1033
|
+
const spec = expectObject(v, path);
|
|
1034
|
+
expectKnownKeys(spec, [
|
|
1035
|
+
"import",
|
|
1036
|
+
"component",
|
|
1037
|
+
"props"
|
|
1038
|
+
], path);
|
|
1039
|
+
return compact({
|
|
1040
|
+
import: expectString(spec.import, `${path}/import`),
|
|
1041
|
+
component: expectString(spec.component, `${path}/component`),
|
|
1042
|
+
props: optional(spec.props, (props) => expectObject(props, `${path}/props`))
|
|
1043
|
+
});
|
|
1044
|
+
};
|
|
1045
|
+
return compact({
|
|
1046
|
+
when: optional(decorator.when, (v) => {
|
|
1047
|
+
const when = expectObject(v, `${at}/when`);
|
|
1048
|
+
for (const [name, option] of Object.entries(when)) expectString(option, `${at}/when/${name}`);
|
|
1049
|
+
return when;
|
|
1050
|
+
}),
|
|
1051
|
+
wrap: optional(decorator.wrap, (v) => element(v, `${at}/wrap`)),
|
|
1052
|
+
add: optional(decorator.add, (v) => element(v, `${at}/add`)),
|
|
1053
|
+
class: decorator.class,
|
|
1054
|
+
attributes: optional(decorator.attributes, (v) => expectObject(v, `${at}/attributes`)),
|
|
1055
|
+
style: optional(decorator.style, (v) => expectObject(v, `${at}/style`))
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
function expectPattern(value, path) {
|
|
1059
|
+
const pattern = expectString(value, path);
|
|
1060
|
+
try {
|
|
1061
|
+
new RegExp(pattern);
|
|
1062
|
+
} catch {
|
|
1063
|
+
throw new TypeError(`${path}: expected a regular expression`);
|
|
1064
|
+
}
|
|
1065
|
+
return pattern;
|
|
1066
|
+
}
|
|
1067
|
+
function expectStringRecord(value, path) {
|
|
1068
|
+
const record = expectObject(value, path);
|
|
1069
|
+
for (const [key, item] of Object.entries(record)) expectString(item, `${path}/${key}`);
|
|
1070
|
+
return record;
|
|
1071
|
+
}
|
|
1072
|
+
// ../core/src/library-insert.ts
|
|
1073
|
+
/**
|
|
1074
|
+
* A new node for a component, ready to show something: required props get their default or first option, and a
|
|
1075
|
+
* component that takes children gets its own name as text, so it isn't an empty box.
|
|
1076
|
+
*/
|
|
1077
|
+
function componentNode(component, info, taken, given = {}) {
|
|
1078
|
+
const props = { ...given };
|
|
1079
|
+
for (const prop of info?.props ?? []) {
|
|
1080
|
+
if (prop.name in props) continue;
|
|
1081
|
+
if (!prop.required || prop.default !== void 0 || prop.name === "children") continue;
|
|
1082
|
+
if (prop.kind === "enum") props[prop.name] = prop.options?.[0];
|
|
1083
|
+
else if (prop.kind === "boolean") props[prop.name] = false;
|
|
1084
|
+
else if (prop.kind === "number") props[prop.name] = 0;
|
|
1085
|
+
else if (prop.kind === "string") props[prop.name] = prop.name;
|
|
1086
|
+
}
|
|
1087
|
+
if (info?.props.some((prop) => prop.name === "children" && prop.kind === "node")) props.children = component.split("/").at(-1) ?? component;
|
|
1088
|
+
return {
|
|
1089
|
+
type: "component",
|
|
1090
|
+
id: generateId(taken),
|
|
1091
|
+
component,
|
|
1092
|
+
...Object.keys(props).length > 0 ? { props } : {}
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* A library component as its library file says it's used: with its sample (a collection's items, an Accordion's
|
|
1097
|
+
* item), and, for a part, inside the parents it needs that aren't around the drop target already. An
|
|
1098
|
+
* `AccordionTrigger` dropped into an empty layout comes inside an Accordion and an AccordionItem; dropped into an
|
|
1099
|
+
* AccordionItem, it comes alone.
|
|
1100
|
+
*/
|
|
1101
|
+
function withLibraryContext(node, sources, around, taken) {
|
|
1102
|
+
if (node.type !== "component") return node;
|
|
1103
|
+
const source = sources[node.component];
|
|
1104
|
+
if (!source) return node;
|
|
1105
|
+
const id = () => {
|
|
1106
|
+
const next = generateId(taken);
|
|
1107
|
+
taken.add(next);
|
|
1108
|
+
return next;
|
|
1109
|
+
};
|
|
1110
|
+
const build = (child) => {
|
|
1111
|
+
if (typeof child === "string") return {
|
|
1112
|
+
type: "text",
|
|
1113
|
+
id: id(),
|
|
1114
|
+
text: child
|
|
1115
|
+
};
|
|
1116
|
+
if (!child.component.includes("/")) {
|
|
1117
|
+
const text = child.children?.find((item) => typeof item === "string") ?? "Text";
|
|
1118
|
+
return {
|
|
1119
|
+
type: "text",
|
|
1120
|
+
id: id(),
|
|
1121
|
+
text
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
return component(child.component, child.props, child.children, !child.props && !child.children);
|
|
1125
|
+
};
|
|
1126
|
+
const nodes = (children) => children.flatMap((child) => isSampleRender(child) ? [] : [build(child)]);
|
|
1127
|
+
/**
|
|
1128
|
+
* Props and children as a node holds them. A render function (`renderInput`, function children) is a `$render:`
|
|
1129
|
+
* slot of the nodes it returns, `$renderWith:` when what it's called with is spread onto them, so its nodes can be
|
|
1130
|
+
* edited like any others.
|
|
1131
|
+
*/
|
|
1132
|
+
const held = (props, children = []) => {
|
|
1133
|
+
const plain = {};
|
|
1134
|
+
const slots = {};
|
|
1135
|
+
const renderSlot = (prop, render) => {
|
|
1136
|
+
const pass = render.pass ? `?pass=${render.pass.join(",")}` : "";
|
|
1137
|
+
slots[`${render.spread ? "$renderWith" : "$render"}:${prop}${pass}`] = nodes(render.$render);
|
|
1138
|
+
};
|
|
1139
|
+
for (const [key, value] of Object.entries(props)) if (isSampleRender(value)) renderSlot(key, value);
|
|
1140
|
+
else if (isSampleElement(value)) slots[key] = nodes(value.$element);
|
|
1141
|
+
else plain[key] = value;
|
|
1142
|
+
const render = children.find(isSampleRender);
|
|
1143
|
+
if (render) renderSlot("children", render);
|
|
1144
|
+
const rest = nodes(children);
|
|
1145
|
+
if (rest.length > 0) slots.children = rest;
|
|
1146
|
+
return {
|
|
1147
|
+
props: plain,
|
|
1148
|
+
slots
|
|
1149
|
+
};
|
|
1150
|
+
};
|
|
1151
|
+
const component = (name, props, children, defaults = true) => {
|
|
1152
|
+
const { props: merged, slots } = held({
|
|
1153
|
+
...defaults ? sources[name]?.sample?.props : {},
|
|
1154
|
+
...props
|
|
1155
|
+
}, children);
|
|
1156
|
+
return {
|
|
1157
|
+
type: "component",
|
|
1158
|
+
id: id(),
|
|
1159
|
+
component: name,
|
|
1160
|
+
...Object.keys(merged).length > 0 ? { props: merged } : {},
|
|
1161
|
+
...Object.keys(slots).length > 0 ? { slots } : {}
|
|
1162
|
+
};
|
|
1163
|
+
};
|
|
1164
|
+
let placed = node;
|
|
1165
|
+
const sample = source.sample;
|
|
1166
|
+
if (sample) {
|
|
1167
|
+
const { props, slots } = held({
|
|
1168
|
+
...sample.props,
|
|
1169
|
+
...node.props
|
|
1170
|
+
}, sample.children);
|
|
1171
|
+
if (sample.children) delete props.children;
|
|
1172
|
+
const { props: _label, ...rest } = node;
|
|
1173
|
+
placed = {
|
|
1174
|
+
...rest,
|
|
1175
|
+
...Object.keys(props).length > 0 ? { props } : {},
|
|
1176
|
+
...Object.keys(slots).length > 0 ? { slots: {
|
|
1177
|
+
...node.slots,
|
|
1178
|
+
...slots
|
|
1179
|
+
} } : {}
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
const parents = source.parents ?? [];
|
|
1183
|
+
const nearest = parents.findLastIndex((parent) => around.includes(parent));
|
|
1184
|
+
const optional = new Set(source.optionalParents ?? []);
|
|
1185
|
+
const missing = parents.slice(nearest + 1);
|
|
1186
|
+
const added = missing.filter((parent, index) => !optional.has(parent) || missing.slice(0, index).some((outer) => !optional.has(outer)));
|
|
1187
|
+
const calling = added.some((parent) => renderSlotOf(sources[parent]?.sample));
|
|
1188
|
+
if (source.parentParts && added.length > 0 && !calling) return inOuterSample(added, placed);
|
|
1189
|
+
for (const parent of added.reverse()) {
|
|
1190
|
+
const wrapper = component(parent);
|
|
1191
|
+
const calls = renderSlotOf(sources[parent]?.sample);
|
|
1192
|
+
const slot = calls ? `$render:${calls.prop}${calls.render.pass ? `?pass=${calls.render.pass.join(",")}` : ""}` : "children";
|
|
1193
|
+
const kept = Object.fromEntries(Object.entries(wrapper.type === "component" ? wrapper.slots ?? {} : {}).filter(([name]) => !calls || !name.startsWith(`$render:${calls.prop}`)));
|
|
1194
|
+
placed = wrapper.type === "component" ? {
|
|
1195
|
+
...wrapper,
|
|
1196
|
+
slots: {
|
|
1197
|
+
...calls ? kept : {},
|
|
1198
|
+
[slot]: [placed]
|
|
1199
|
+
}
|
|
1200
|
+
} : placed;
|
|
1201
|
+
}
|
|
1202
|
+
return placed;
|
|
1203
|
+
/**
|
|
1204
|
+
* A part that needs what's around it (a table's header beside the body a row is in) goes into the outermost
|
|
1205
|
+
* parent's whole sample, each level in place of the first like it there and the part in place of the first like it
|
|
1206
|
+
* at the bottom, so the row it's in keeps its other cells. A level the sample doesn't hold comes alone.
|
|
1207
|
+
*/
|
|
1208
|
+
function inOuterSample(chain, part) {
|
|
1209
|
+
const inside = (level, given) => {
|
|
1210
|
+
let name = "";
|
|
1211
|
+
if (level < chain.length) name = chain[level];
|
|
1212
|
+
else if (part.type === "component") name = part.component;
|
|
1213
|
+
const items = (given ?? []).filter((item) => !isSampleRender(item));
|
|
1214
|
+
const at = items.findIndex((item) => typeof item === "object" && item.component === name);
|
|
1215
|
+
const found = at === -1 ? void 0 : items[at];
|
|
1216
|
+
let here = part;
|
|
1217
|
+
if (level < chain.length) {
|
|
1218
|
+
const written = found && (found.props || found.children);
|
|
1219
|
+
const wrapper = component(name, found?.props, void 0, !written);
|
|
1220
|
+
const children = inside(level + 1, written ? found.children : sources[name]?.sample?.children);
|
|
1221
|
+
here = wrapper.type === "component" ? {
|
|
1222
|
+
...wrapper,
|
|
1223
|
+
slots: {
|
|
1224
|
+
...wrapper.slots,
|
|
1225
|
+
children
|
|
1226
|
+
}
|
|
1227
|
+
} : wrapper;
|
|
1228
|
+
}
|
|
1229
|
+
return at === -1 ? [here] : items.map((item, index) => index === at ? here : build(item));
|
|
1230
|
+
};
|
|
1231
|
+
const outer = component(chain[0]);
|
|
1232
|
+
const children = inside(1, sources[chain[0]]?.sample?.children);
|
|
1233
|
+
return outer.type === "component" ? {
|
|
1234
|
+
...outer,
|
|
1235
|
+
slots: {
|
|
1236
|
+
...outer.slots,
|
|
1237
|
+
children
|
|
1238
|
+
}
|
|
1239
|
+
} : outer;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* A library file's component as the canvas inserts it, but for where it's declared: its import, its parents and sample
|
|
1244
|
+
* by component id (`nova/AccordionItem`), and `imported` naming the package the way the project depends on it.
|
|
1245
|
+
*/
|
|
1246
|
+
function librarySource(library, name, component, path, imported = (specifier) => specifier) {
|
|
1247
|
+
return {
|
|
1248
|
+
path,
|
|
1249
|
+
export: name,
|
|
1250
|
+
library,
|
|
1251
|
+
...component.group ? { group: component.group } : {},
|
|
1252
|
+
...component.parents ? { parents: component.parents.map((parent) => `${library}/${parent}`) } : {},
|
|
1253
|
+
...component.internal ? { internal: true } : {},
|
|
1254
|
+
...component.optionalParents ? { optionalParents: component.optionalParents.map((parent) => `${library}/${parent}`) } : {},
|
|
1255
|
+
...component.parentParts ? { parentParts: true } : {},
|
|
1256
|
+
...component.sample ? { sample: sampleIds(component.sample, library, imported) } : {}
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* A sample with its children's components named by id, as `nova/AccordionItem`; HTML elements keep their tag. A value the
|
|
1261
|
+
* package makes (`{ $call: { import: "@chakra-ui/react", ... } }`) imports it by the name the project depends on.
|
|
1262
|
+
*/
|
|
1263
|
+
function sampleIds(sample, library, imported = (specifier) => specifier) {
|
|
1264
|
+
const child = (node) => {
|
|
1265
|
+
if (typeof node === "string") return node;
|
|
1266
|
+
if (isSampleRender(node)) return {
|
|
1267
|
+
...node,
|
|
1268
|
+
$render: node.$render.map(child)
|
|
1269
|
+
};
|
|
1270
|
+
return {
|
|
1271
|
+
...node,
|
|
1272
|
+
component: /^[a-z]/.test(node.component) ? node.component : `${library}/${node.component}`,
|
|
1273
|
+
...node.props ? { props: propIds(node.props) } : {},
|
|
1274
|
+
...node.children ? { children: node.children.map(child) } : {}
|
|
1275
|
+
};
|
|
1276
|
+
};
|
|
1277
|
+
const propId = (item) => {
|
|
1278
|
+
if (isSampleRender(item)) return {
|
|
1279
|
+
...item,
|
|
1280
|
+
$render: item.$render.map(child)
|
|
1281
|
+
};
|
|
1282
|
+
if (isSampleElement(item)) return { $element: item.$element.map(child) };
|
|
1283
|
+
return isMadeValue(item) ? {
|
|
1284
|
+
...item,
|
|
1285
|
+
$call: {
|
|
1286
|
+
...item.$call,
|
|
1287
|
+
import: imported(item.$call.import)
|
|
1288
|
+
}
|
|
1289
|
+
} : item;
|
|
1290
|
+
};
|
|
1291
|
+
const propIds = (props) => Object.fromEntries(Object.entries(props).map(([key, item]) => [key, propId(item)]));
|
|
1292
|
+
return {
|
|
1293
|
+
...sample,
|
|
1294
|
+
...sample.props ? { props: propIds(sample.props) } : {},
|
|
1295
|
+
...sample.children ? { children: sample.children.map(child) } : {}
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
export { viewportHeightProperty as C, lengthToPixels as S, parseCanvasDocument as _, applyLibraryEdits as a, parseModeSettings as b, isSampleElement as c, parentSignals as d, parseLibraryEdits as f, paramTypes as g, imageFits as h, withLibraryContext as i, isSampleRender as l, renderSlotOf as m, librarySource as n, componentEvidence as o, parseLibraryManifest as p, sampleIds as r, isMadeValue as s, componentNode as t, libraryManifestExtension as u, styleKeys as v, viewportWidthProperty as w, deviceKinds as x, generateId as y };
|