@supernova-studio/client 0.0.15 → 0.2.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/dist/index.d.mts +190 -191
- package/dist/index.d.ts +190 -191
- package/dist/index.js +388 -86
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +382 -80
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/docs-editor/blocks-to-prosemirror.ts +214 -144
- package/src/docs-editor/mock.ts +16 -16
- package/src/docs-editor/prosemirror/types.ts +3 -7
- package/src/docs-editor/prosemirror-to-blocks.ts +226 -3
- package/src/docs-editor/utils.ts +35 -9
|
@@ -6,6 +6,14 @@ import {
|
|
|
6
6
|
PageBlockTextSpan,
|
|
7
7
|
PageBlockTextSpanAttribute,
|
|
8
8
|
PageBlockDefinitionProperty,
|
|
9
|
+
PageBlockCalloutType,
|
|
10
|
+
PageBlockItemRichTextPropertyValue,
|
|
11
|
+
PageBlockItemMultiRichTextPropertyValue,
|
|
12
|
+
PageBlockItemEmbedPropertyValue,
|
|
13
|
+
PageBlockItemV2,
|
|
14
|
+
PageBlockItemTextPropertyValue,
|
|
15
|
+
PageBlockItemUntypedPropertyValue,
|
|
16
|
+
PageBlockItemImageValue,
|
|
9
17
|
} from "@supernova-studio/model";
|
|
10
18
|
import { PageBlockEditorModel } from "./model/block";
|
|
11
19
|
import { DocumentationPageEditorModel } from "./model/page";
|
|
@@ -52,9 +60,27 @@ export function prosemirrorNodeToBlock(
|
|
|
52
60
|
return parseAsRichText(prosemirrorNode, definition, richTextProperty);
|
|
53
61
|
}
|
|
54
62
|
|
|
63
|
+
const multiRichTextProperty = BlockDefinitionUtils.firstMultiRichTextProperty(definition);
|
|
64
|
+
if (multiRichTextProperty) {
|
|
65
|
+
return parseAsMultiRichText(prosemirrorNode, definition, multiRichTextProperty);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const embedProperty = BlockDefinitionUtils.firstEmbedProperty(definition);
|
|
69
|
+
if (prosemirrorNode.type === "embed" && embedProperty) {
|
|
70
|
+
return parseAsEmbed(prosemirrorNode, definition, embedProperty);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (definition.id === "io.supernova.block.divider") {
|
|
74
|
+
return parseAsDivider(prosemirrorNode, definition);
|
|
75
|
+
}
|
|
76
|
+
|
|
55
77
|
return parseAsCustomBlock(prosemirrorNode, definition);
|
|
56
78
|
}
|
|
57
79
|
|
|
80
|
+
//
|
|
81
|
+
// Single rich text
|
|
82
|
+
//
|
|
83
|
+
|
|
58
84
|
function parseAsRichText(
|
|
59
85
|
prosemirrorNode: ProsemirrorNode,
|
|
60
86
|
definition: PageBlockDefinition,
|
|
@@ -62,21 +88,89 @@ function parseAsRichText(
|
|
|
62
88
|
): PageBlockEditorModel {
|
|
63
89
|
const id = parseProsemirrorBlockAttribute(prosemirrorNode, "id");
|
|
64
90
|
const variantId = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "variantId");
|
|
91
|
+
const calloutType = parseCalloutType(parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "type"));
|
|
65
92
|
|
|
66
93
|
return {
|
|
67
94
|
// TODO Artem: indent
|
|
68
95
|
id: id,
|
|
96
|
+
|
|
97
|
+
...(variantId && { variantId: variantId }),
|
|
98
|
+
|
|
69
99
|
data: {
|
|
70
100
|
packageId: definition.id,
|
|
71
101
|
indentLevel: 0,
|
|
72
|
-
variantId: variantId,
|
|
73
102
|
items: [
|
|
74
103
|
{
|
|
75
104
|
id: id,
|
|
76
105
|
props: {
|
|
77
106
|
[property.id]: {
|
|
107
|
+
// Required
|
|
78
108
|
value: parseRichText(prosemirrorNode.content ?? []),
|
|
79
|
-
|
|
109
|
+
|
|
110
|
+
// Optional
|
|
111
|
+
...(calloutType && { calloutType: calloutType }),
|
|
112
|
+
} satisfies PageBlockItemRichTextPropertyValue,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function parseCalloutType(prosemirrorCalloutType: string | undefined): PageBlockCalloutType | undefined {
|
|
121
|
+
if (!prosemirrorCalloutType) return undefined;
|
|
122
|
+
|
|
123
|
+
switch (prosemirrorCalloutType) {
|
|
124
|
+
case "error":
|
|
125
|
+
return "Error";
|
|
126
|
+
case "neutral":
|
|
127
|
+
return "Info";
|
|
128
|
+
case "success":
|
|
129
|
+
return "Success";
|
|
130
|
+
case "warning":
|
|
131
|
+
return "Warning";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//
|
|
136
|
+
// Multi rich text
|
|
137
|
+
//
|
|
138
|
+
|
|
139
|
+
function parseAsMultiRichText(
|
|
140
|
+
prosemirrorNode: ProsemirrorNode,
|
|
141
|
+
definition: PageBlockDefinition,
|
|
142
|
+
property: PageBlockDefinitionProperty
|
|
143
|
+
) {
|
|
144
|
+
const id = parseProsemirrorBlockAttribute(prosemirrorNode, "id");
|
|
145
|
+
const variantId = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "variantId");
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
// TODO Artem: indent
|
|
149
|
+
id: id,
|
|
150
|
+
data: {
|
|
151
|
+
packageId: definition.id,
|
|
152
|
+
indentLevel: 0,
|
|
153
|
+
|
|
154
|
+
...(variantId && { variantId: variantId }),
|
|
155
|
+
|
|
156
|
+
items: [
|
|
157
|
+
{
|
|
158
|
+
id: id,
|
|
159
|
+
props: {
|
|
160
|
+
[property.id]: {
|
|
161
|
+
// Required
|
|
162
|
+
value: (prosemirrorNode.content ?? [])
|
|
163
|
+
.map(listItem => {
|
|
164
|
+
if (listItem.type !== "listitem") return null;
|
|
165
|
+
if (!listItem.content?.length) return parseRichText([]);
|
|
166
|
+
|
|
167
|
+
const paragraph = listItem.content[0];
|
|
168
|
+
if (paragraph.type !== "paragraph") return parseRichText([]);
|
|
169
|
+
|
|
170
|
+
return parseRichText(paragraph.content ?? []);
|
|
171
|
+
})
|
|
172
|
+
.filter(nonNullFilter),
|
|
173
|
+
} satisfies PageBlockItemMultiRichTextPropertyValue,
|
|
80
174
|
},
|
|
81
175
|
},
|
|
82
176
|
],
|
|
@@ -84,6 +178,10 @@ function parseAsRichText(
|
|
|
84
178
|
};
|
|
85
179
|
}
|
|
86
180
|
|
|
181
|
+
//
|
|
182
|
+
// Rich text
|
|
183
|
+
//
|
|
184
|
+
|
|
87
185
|
function parseRichText(spans: ProsemirrorNode[]): PageBlockText {
|
|
88
186
|
return {
|
|
89
187
|
spans: spans.map(parseRichTextSpan).filter(nonNullFilter),
|
|
@@ -126,6 +224,67 @@ function parseRichTextAttribute(mark: ProsemirrorMark): PageBlockTextSpanAttribu
|
|
|
126
224
|
return null;
|
|
127
225
|
}
|
|
128
226
|
|
|
227
|
+
//
|
|
228
|
+
// Embed
|
|
229
|
+
//
|
|
230
|
+
|
|
231
|
+
function parseAsEmbed(
|
|
232
|
+
prosemirrorNode: ProsemirrorNode,
|
|
233
|
+
definition: PageBlockDefinition,
|
|
234
|
+
property: PageBlockDefinitionProperty
|
|
235
|
+
): PageBlockEditorModel {
|
|
236
|
+
const id = parseProsemirrorBlockAttribute(prosemirrorNode, "id");
|
|
237
|
+
const variantId = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "variantId");
|
|
238
|
+
|
|
239
|
+
const url = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "url");
|
|
240
|
+
const caption = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "caption");
|
|
241
|
+
const height = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "height");
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
id: id,
|
|
245
|
+
data: {
|
|
246
|
+
packageId: definition.id,
|
|
247
|
+
indentLevel: 0,
|
|
248
|
+
|
|
249
|
+
...(variantId && { variantId: variantId }),
|
|
250
|
+
|
|
251
|
+
items: [
|
|
252
|
+
{
|
|
253
|
+
id: id,
|
|
254
|
+
props: {
|
|
255
|
+
[property.id]: {
|
|
256
|
+
value: url,
|
|
257
|
+
caption: caption,
|
|
258
|
+
height: height,
|
|
259
|
+
} as PageBlockItemEmbedPropertyValue,
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
//
|
|
268
|
+
// Divider
|
|
269
|
+
//
|
|
270
|
+
|
|
271
|
+
function parseAsDivider(prosemirrorNode: ProsemirrorNode, definition: PageBlockDefinition): PageBlockEditorModel {
|
|
272
|
+
const id = parseProsemirrorBlockAttribute(prosemirrorNode, "id");
|
|
273
|
+
const variantId = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "variantId");
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
id: id,
|
|
277
|
+
data: {
|
|
278
|
+
packageId: definition.id,
|
|
279
|
+
indentLevel: 0,
|
|
280
|
+
|
|
281
|
+
...(variantId && { variantId: variantId }),
|
|
282
|
+
|
|
283
|
+
items: [{ id: id, props: {} }],
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
129
288
|
//
|
|
130
289
|
// Custom block
|
|
131
290
|
//
|
|
@@ -134,7 +293,71 @@ function parseAsCustomBlock(
|
|
|
134
293
|
prosemirrorNode: ProsemirrorNode,
|
|
135
294
|
definition: PageBlockDefinition
|
|
136
295
|
): PageBlockEditorModel | null {
|
|
137
|
-
|
|
296
|
+
const id = parseProsemirrorBlockAttribute(prosemirrorNode, "id");
|
|
297
|
+
const variantId = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "variantId");
|
|
298
|
+
|
|
299
|
+
const itemsString = parseProsemirrorBlockAttribute(prosemirrorNode, "items");
|
|
300
|
+
const itemsJson = JSON.parse(itemsString);
|
|
301
|
+
if (!Array.isArray(itemsJson)) {
|
|
302
|
+
console.error("Block `items` property must be a json array");
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const parsedItems = itemsJson.map(i => parseItem(i, definition));
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
id: id,
|
|
310
|
+
data: {
|
|
311
|
+
packageId: definition.id,
|
|
312
|
+
indentLevel: 0,
|
|
313
|
+
|
|
314
|
+
...(variantId && { variantId: variantId }),
|
|
315
|
+
|
|
316
|
+
items: parsedItems,
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function parseItem(rawItem: unknown, definition: PageBlockDefinition): PageBlockItemV2 | null {
|
|
322
|
+
const parsedItem = PageBlockItemV2.safeParse(rawItem);
|
|
323
|
+
if (!parsedItem.success) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const sanitizedProps: Record<string, PageBlockItemUntypedPropertyValue> = {};
|
|
328
|
+
|
|
329
|
+
for (const property of definition.item.properties) {
|
|
330
|
+
const value = parsedItem.data.props[property.id];
|
|
331
|
+
if (!value) {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Validate
|
|
336
|
+
switch (property.type) {
|
|
337
|
+
case "Text":
|
|
338
|
+
PageBlockItemTextPropertyValue.parse(value);
|
|
339
|
+
break;
|
|
340
|
+
|
|
341
|
+
case "EmbedURL":
|
|
342
|
+
PageBlockItemEmbedPropertyValue.parse(value);
|
|
343
|
+
break;
|
|
344
|
+
|
|
345
|
+
case "Image":
|
|
346
|
+
PageBlockItemImageValue.parse(value);
|
|
347
|
+
break;
|
|
348
|
+
|
|
349
|
+
default:
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
sanitizedProps[property.id] = value;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
id: parsedItem.data.id,
|
|
358
|
+
linksTo: parsedItem.data.linksTo,
|
|
359
|
+
props: sanitizedProps,
|
|
360
|
+
};
|
|
138
361
|
}
|
|
139
362
|
|
|
140
363
|
//
|
package/src/docs-editor/utils.ts
CHANGED
|
@@ -2,6 +2,10 @@ import { PageBlockEditorModel } from "./model/block";
|
|
|
2
2
|
import {
|
|
3
3
|
PageBlockDefinition,
|
|
4
4
|
PageBlockDefinitionPropertyType,
|
|
5
|
+
PageBlockItemEmbedPropertyValue,
|
|
6
|
+
PageBlockItemMultiRichTextPropertyValue,
|
|
7
|
+
PageBlockItemRichTextPropertyValue,
|
|
8
|
+
PageBlockItemUntypedPropertyValue,
|
|
5
9
|
PageBlockItemV2,
|
|
6
10
|
PageBlockText,
|
|
7
11
|
} from "@supernova-studio/model";
|
|
@@ -14,15 +18,29 @@ export const BlockParsingUtils = {
|
|
|
14
18
|
return block.data.items[0]!;
|
|
15
19
|
},
|
|
16
20
|
|
|
17
|
-
richTextPropertyValue(item: PageBlockItemV2, propertyKey: string) {
|
|
21
|
+
richTextPropertyValue(item: PageBlockItemV2, propertyKey: string): PageBlockItemRichTextPropertyValue {
|
|
18
22
|
const objectValue = this.objectPropertyValue(item, propertyKey);
|
|
19
|
-
const richText =
|
|
23
|
+
const richText = PageBlockItemRichTextPropertyValue.parse(objectValue);
|
|
20
24
|
|
|
21
25
|
return richText;
|
|
22
26
|
},
|
|
23
27
|
|
|
28
|
+
multiRichTextPropertyValue(item: PageBlockItemV2, propertyKey: string): PageBlockItemMultiRichTextPropertyValue {
|
|
29
|
+
const objectValue = this.objectPropertyValue(item, propertyKey);
|
|
30
|
+
const richText = PageBlockItemMultiRichTextPropertyValue.parse(objectValue);
|
|
31
|
+
|
|
32
|
+
return richText;
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
embedPropertyValue(item: PageBlockItemV2, propertyKey: string): PageBlockItemEmbedPropertyValue {
|
|
36
|
+
const objectValue = this.objectPropertyValue(item, propertyKey);
|
|
37
|
+
const embed = PageBlockItemEmbedPropertyValue.parse(objectValue);
|
|
38
|
+
|
|
39
|
+
return embed;
|
|
40
|
+
},
|
|
41
|
+
|
|
24
42
|
objectPropertyValue(item: PageBlockItemV2, propertyKey: string) {
|
|
25
|
-
const value = this.
|
|
43
|
+
const value = this.propertyValueOrThrow(item, propertyKey);
|
|
26
44
|
|
|
27
45
|
if (typeof value !== "object") {
|
|
28
46
|
throw new Error(`Value for property ${propertyKey} is expected to be an object, but instead is ${typeof value}`);
|
|
@@ -31,16 +49,12 @@ export const BlockParsingUtils = {
|
|
|
31
49
|
return value;
|
|
32
50
|
},
|
|
33
51
|
|
|
34
|
-
|
|
35
|
-
const value =
|
|
52
|
+
propertyValueOrThrow(item: PageBlockItemV2, propertyKey: string): PageBlockItemUntypedPropertyValue {
|
|
53
|
+
const value = item.props[propertyKey];
|
|
36
54
|
if (!value) throw new Error(`Property ${propertyKey} is not defined on block item`);
|
|
37
55
|
|
|
38
56
|
return value;
|
|
39
57
|
},
|
|
40
|
-
|
|
41
|
-
safePropertyValue(item: PageBlockItemV2, propertyKey: string) {
|
|
42
|
-
return item.props[propertyKey] ?? undefined;
|
|
43
|
-
},
|
|
44
58
|
};
|
|
45
59
|
|
|
46
60
|
export const BlockDefinitionUtils = {
|
|
@@ -50,12 +64,24 @@ export const BlockDefinitionUtils = {
|
|
|
50
64
|
return undefined;
|
|
51
65
|
},
|
|
52
66
|
|
|
67
|
+
firstMultiRichTextProperty(definition: PageBlockDefinition) {
|
|
68
|
+
const property = definition.item.properties.find(p => p.type === "MultiRichText");
|
|
69
|
+
if (property) return property;
|
|
70
|
+
return undefined;
|
|
71
|
+
},
|
|
72
|
+
|
|
53
73
|
firstTableProperty(definition: PageBlockDefinition) {
|
|
54
74
|
const property = definition.item.properties.find(p => p.type === "RichText");
|
|
55
75
|
if (property) return property;
|
|
56
76
|
return undefined;
|
|
57
77
|
},
|
|
58
78
|
|
|
79
|
+
firstEmbedProperty(definition: PageBlockDefinition) {
|
|
80
|
+
const property = definition.item.properties.find(p => p.type === "EmbedURL");
|
|
81
|
+
if (property) return property;
|
|
82
|
+
return undefined;
|
|
83
|
+
},
|
|
84
|
+
|
|
59
85
|
richTextProperty(definition: PageBlockDefinition, propertyKey: string) {
|
|
60
86
|
return this.property(definition, propertyKey, "RichText");
|
|
61
87
|
},
|