@supernova-studio/client 0.9.0 → 0.9.2
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.js +77 -62
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +77 -62
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/docs-editor/blocks-to-prosemirror.ts +3 -1
- package/src/docs-editor/prosemirror-to-blocks.ts +80 -64
package/package.json
CHANGED
|
@@ -72,7 +72,9 @@ export function pageToProsemirrorDoc(
|
|
|
72
72
|
|
|
73
73
|
export function blockDefinitionForBlock(block: PageBlockEditorModel, definitions: PageBlockDefinition[]) {
|
|
74
74
|
const definition = definitions.find(d => d.id === block.data.packageId);
|
|
75
|
-
if (!definition)
|
|
75
|
+
if (!definition) {
|
|
76
|
+
throw new Error(`Could not find definition for ${block.id} (${block.data.packageId})`);
|
|
77
|
+
}
|
|
76
78
|
|
|
77
79
|
return definition;
|
|
78
80
|
}
|
|
@@ -37,15 +37,14 @@ import {
|
|
|
37
37
|
PageBlockItemTableNode,
|
|
38
38
|
PageBlockItemTableCell,
|
|
39
39
|
PageBlockTableCellAlignment,
|
|
40
|
-
DocumentationItemConfiguration,
|
|
41
40
|
PageBlockAppearanceV2,
|
|
42
|
-
PageBlockEditorModelV2,
|
|
43
41
|
ColorValue,
|
|
44
42
|
} from "@supernova-studio/model";
|
|
45
43
|
import { PageBlockEditorModel } from "./model/block";
|
|
46
44
|
import { DocumentationPageEditorModel } from "./model/page";
|
|
47
45
|
import { BlockDefinitionUtils } from "./utils";
|
|
48
46
|
import { yXmlFragmentToProsemirrorJSON } from "y-prosemirror";
|
|
47
|
+
import { ZodSchema, z } from "zod";
|
|
49
48
|
|
|
50
49
|
export function yDocToPage(yDoc: Y.Doc, definitions: PageBlockDefinition[]): DocumentationPageEditorModel {
|
|
51
50
|
return yXmlFragmentToPage(yDoc.getXmlFragment("default"), definitions);
|
|
@@ -68,13 +67,23 @@ export function prosemirrorDocToPage(
|
|
|
68
67
|
return {
|
|
69
68
|
blocks: (prosemirrorDoc.content ?? [])
|
|
70
69
|
.map(prosemirrorNode => {
|
|
71
|
-
const definitionId =
|
|
72
|
-
if (!definitionId)
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
const definitionId = getProsemirrorAttribute(prosemirrorNode, "definitionId", z.string());
|
|
71
|
+
if (!definitionId) {
|
|
72
|
+
console.warn(
|
|
73
|
+
`definitionId on ${prosemirrorNode.type} is required to be interpreted as a block, skipping node`
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
75
78
|
|
|
76
79
|
const definition = definitionsById.get(definitionId);
|
|
77
|
-
if (!definition)
|
|
80
|
+
if (!definition) {
|
|
81
|
+
console.warn(
|
|
82
|
+
`Block definitionId "${definitionId}" (prosemirror node ${prosemirrorNode.type}) is not among available definitions`
|
|
83
|
+
);
|
|
84
|
+
console.warn(prosemirrorNode);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
78
87
|
|
|
79
88
|
return prosemirrorNodeToBlock(prosemirrorNode, definition);
|
|
80
89
|
})
|
|
@@ -122,13 +131,11 @@ function parseAsRichText(
|
|
|
122
131
|
definition: PageBlockDefinition,
|
|
123
132
|
property: PageBlockDefinitionProperty
|
|
124
133
|
): PageBlockEditorModel | null {
|
|
125
|
-
const id =
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
const variantIdRaw = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "variantId");
|
|
129
|
-
const variantId = typeof variantIdRaw === "string" ? variantIdRaw : undefined;
|
|
134
|
+
const id = getProsemirrorBlockId(prosemirrorNode);
|
|
135
|
+
if (!id) return null;
|
|
130
136
|
|
|
131
|
-
const
|
|
137
|
+
const variantId = getProsemirrorBlockVariantId(prosemirrorNode);
|
|
138
|
+
const calloutType = parseCalloutType(getProsemirrorAttribute(prosemirrorNode, "type", z.string()));
|
|
132
139
|
|
|
133
140
|
return {
|
|
134
141
|
// TODO Artem: indent
|
|
@@ -181,11 +188,10 @@ function parseAsMultiRichText(
|
|
|
181
188
|
definition: PageBlockDefinition,
|
|
182
189
|
property: PageBlockDefinitionProperty
|
|
183
190
|
): PageBlockEditorModel | null {
|
|
184
|
-
const id =
|
|
185
|
-
if (
|
|
191
|
+
const id = getProsemirrorBlockId(prosemirrorNode);
|
|
192
|
+
if (!id) return null;
|
|
186
193
|
|
|
187
|
-
const
|
|
188
|
-
const variantId = typeof variantIdRaw === "string" ? variantIdRaw : undefined;
|
|
194
|
+
const variantId = getProsemirrorBlockVariantId(prosemirrorNode);
|
|
189
195
|
|
|
190
196
|
return {
|
|
191
197
|
// TODO Artem: indent
|
|
@@ -253,11 +259,8 @@ function parseRichTextAttribute(mark: ProsemirrorMark): PageBlockTextSpanAttribu
|
|
|
253
259
|
case "code":
|
|
254
260
|
return { type: "Code" };
|
|
255
261
|
case "link":
|
|
256
|
-
const
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
const hrefRaw = parseProsemirrorBlockAttribute(mark, "href");
|
|
260
|
-
const href = typeof hrefRaw === "string" ? hrefRaw : undefined;
|
|
262
|
+
const itemId = getProsemirrorAttribute(mark, "itemId", z.string());
|
|
263
|
+
const href = getProsemirrorAttribute(mark, "href", z.string());
|
|
261
264
|
|
|
262
265
|
return {
|
|
263
266
|
type: "Link",
|
|
@@ -279,13 +282,11 @@ function parseAsTable(
|
|
|
279
282
|
definition: PageBlockDefinition,
|
|
280
283
|
property: PageBlockDefinitionProperty
|
|
281
284
|
): PageBlockEditorModel | null {
|
|
282
|
-
const id =
|
|
283
|
-
if (
|
|
285
|
+
const id = getProsemirrorBlockId(prosemirrorNode);
|
|
286
|
+
if (!id) return null;
|
|
284
287
|
|
|
285
|
-
const
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
const hasBorder = parseProsemirrorOptionalBlockAttribute(prosemirrorNode, "hasBorder") !== false;
|
|
288
|
+
const variantId = getProsemirrorBlockVariantId(prosemirrorNode);
|
|
289
|
+
const hasBorder = getProsemirrorAttribute(prosemirrorNode, "hasBorder", z.boolean()) !== false;
|
|
289
290
|
|
|
290
291
|
const tableChild = prosemirrorNode.content?.find(c => c.type === "table");
|
|
291
292
|
if (!tableChild) {
|
|
@@ -338,14 +339,14 @@ function parseAsTable(
|
|
|
338
339
|
}
|
|
339
340
|
|
|
340
341
|
function parseAsTableCell(prosemirrorNode: ProsemirrorNode): PageBlockItemTableCell | null {
|
|
341
|
-
const id =
|
|
342
|
-
if (
|
|
342
|
+
const id = getProsemirrorBlockId(prosemirrorNode);
|
|
343
|
+
if (!id) return null;
|
|
343
344
|
|
|
344
|
-
const textAlign =
|
|
345
|
+
const textAlign = getProsemirrorAttribute(prosemirrorNode, "textAlign", z.string());
|
|
345
346
|
|
|
346
347
|
let columnWidth: number | undefined;
|
|
347
|
-
const columnWidthArray =
|
|
348
|
-
if (
|
|
348
|
+
const columnWidthArray = getProsemirrorAttribute(prosemirrorNode, "colwidth", z.array(z.number()));
|
|
349
|
+
if (columnWidthArray) {
|
|
349
350
|
columnWidth = columnWidthArray[0];
|
|
350
351
|
}
|
|
351
352
|
|
|
@@ -384,8 +385,8 @@ function parseAsTableNode(prosemirrorNode: ProsemirrorNode): PageBlockItemTableN
|
|
|
384
385
|
};
|
|
385
386
|
|
|
386
387
|
case "image":
|
|
387
|
-
const url =
|
|
388
|
-
if (!url
|
|
388
|
+
const url = getProsemirrorAttribute(prosemirrorNode, "src", z.string());
|
|
389
|
+
if (!url) return null;
|
|
389
390
|
|
|
390
391
|
return {
|
|
391
392
|
type: "Image",
|
|
@@ -458,15 +459,14 @@ function parseAsEmbed(
|
|
|
458
459
|
definition: PageBlockDefinition,
|
|
459
460
|
property: PageBlockDefinitionProperty
|
|
460
461
|
): PageBlockEditorModel | null {
|
|
461
|
-
const id =
|
|
462
|
-
if (
|
|
462
|
+
const id = getProsemirrorBlockId(prosemirrorNode);
|
|
463
|
+
if (!id) return null;
|
|
463
464
|
|
|
464
|
-
const
|
|
465
|
-
const variantId = typeof variantIdRaw === "string" ? variantIdRaw : undefined;
|
|
465
|
+
const variantId = getProsemirrorBlockVariantId(prosemirrorNode);
|
|
466
466
|
|
|
467
|
-
const url =
|
|
468
|
-
const caption =
|
|
469
|
-
const height =
|
|
467
|
+
const url = getProsemirrorAttribute(prosemirrorNode, "url", z.string());
|
|
468
|
+
const caption = getProsemirrorAttribute(prosemirrorNode, "caption", z.string());
|
|
469
|
+
const height = getProsemirrorAttribute(prosemirrorNode, "height", z.number());
|
|
470
470
|
|
|
471
471
|
return {
|
|
472
472
|
id: id,
|
|
@@ -500,11 +500,10 @@ function parseAsDivider(
|
|
|
500
500
|
prosemirrorNode: ProsemirrorNode,
|
|
501
501
|
definition: PageBlockDefinition
|
|
502
502
|
): PageBlockEditorModel | null {
|
|
503
|
-
const id =
|
|
504
|
-
if (
|
|
503
|
+
const id = getProsemirrorBlockId(prosemirrorNode);
|
|
504
|
+
if (!id) return null;
|
|
505
505
|
|
|
506
|
-
const
|
|
507
|
-
const variantId = typeof variantIdRaw === "string" ? variantIdRaw : undefined;
|
|
506
|
+
const variantId = getProsemirrorBlockVariantId(prosemirrorNode);
|
|
508
507
|
|
|
509
508
|
return {
|
|
510
509
|
id: id,
|
|
@@ -527,11 +526,10 @@ function parseAsCustomBlock(
|
|
|
527
526
|
prosemirrorNode: ProsemirrorNode,
|
|
528
527
|
definition: PageBlockDefinition
|
|
529
528
|
): PageBlockEditorModel | null {
|
|
530
|
-
const id =
|
|
531
|
-
if (
|
|
529
|
+
const id = getProsemirrorBlockId(prosemirrorNode);
|
|
530
|
+
if (!id) return null;
|
|
532
531
|
|
|
533
|
-
const
|
|
534
|
-
const variantId = typeof variantIdRaw === "string" ? variantIdRaw : undefined;
|
|
532
|
+
const variantId = getProsemirrorBlockVariantId(prosemirrorNode);
|
|
535
533
|
|
|
536
534
|
const appearance = parseAppearance(prosemirrorNode);
|
|
537
535
|
const parsedItems = parseBlockItems(prosemirrorNode, definition);
|
|
@@ -552,8 +550,8 @@ function parseAsCustomBlock(
|
|
|
552
550
|
}
|
|
553
551
|
|
|
554
552
|
function parseBlockItems(prosemirrorNode: ProsemirrorNode, definition: PageBlockDefinition): PageBlockItemV2[] | null {
|
|
555
|
-
const itemsString =
|
|
556
|
-
if (
|
|
553
|
+
const itemsString = getProsemirrorAttribute(prosemirrorNode, "items", z.string());
|
|
554
|
+
if (!itemsString) return null;
|
|
557
555
|
|
|
558
556
|
const itemsJson: unknown = JSON.parse(itemsString);
|
|
559
557
|
if (!Array.isArray(itemsJson)) {
|
|
@@ -567,13 +565,13 @@ function parseBlockItems(prosemirrorNode: ProsemirrorNode, definition: PageBlock
|
|
|
567
565
|
function parseAppearance(prosemirrorNode: ProsemirrorNode): PageBlockAppearanceV2 | undefined {
|
|
568
566
|
const appearance: PageBlockAppearanceV2 = {};
|
|
569
567
|
|
|
570
|
-
const columns
|
|
571
|
-
if (
|
|
568
|
+
const columns = getProsemirrorAttribute(prosemirrorNode, "columns", z.number());
|
|
569
|
+
if (columns) {
|
|
572
570
|
appearance.numberOfColumns = columns;
|
|
573
571
|
}
|
|
574
572
|
|
|
575
|
-
const backgroundColor
|
|
576
|
-
if (
|
|
573
|
+
const backgroundColor = getProsemirrorAttribute(prosemirrorNode, "backgroundColor", z.string());
|
|
574
|
+
if (backgroundColor) {
|
|
577
575
|
const parsedColor = ColorValue.safeParse(JSON.parse(backgroundColor));
|
|
578
576
|
if (parsedColor.success) {
|
|
579
577
|
appearance.itemBackgroundColor = parsedColor.data;
|
|
@@ -673,17 +671,35 @@ function valueSchemaForPropertyType(type: PageBlockDefinitionPropertyType) {
|
|
|
673
671
|
// Attributes
|
|
674
672
|
//
|
|
675
673
|
|
|
676
|
-
function
|
|
677
|
-
const
|
|
678
|
-
if (!
|
|
679
|
-
|
|
680
|
-
|
|
674
|
+
function getProsemirrorBlockId(prosemirrorNode: ProsemirrorNode): string | undefined {
|
|
675
|
+
const id = getProsemirrorAttribute(prosemirrorNode, "id", z.string());
|
|
676
|
+
if (!id) console.warn(`Prosemirror attribute "id" on ${prosemirrorNode.type} is required`);
|
|
677
|
+
return id;
|
|
678
|
+
}
|
|
681
679
|
|
|
682
|
-
|
|
680
|
+
function getProsemirrorBlockVariantId(prosemirrorNode: ProsemirrorNode): string | undefined {
|
|
681
|
+
return getProsemirrorAttribute(prosemirrorNode, "variantId", z.string());
|
|
683
682
|
}
|
|
684
683
|
|
|
685
|
-
function
|
|
686
|
-
|
|
684
|
+
function getProsemirrorAttribute<O>(
|
|
685
|
+
prosemirrorNode: ProsemirrorNode,
|
|
686
|
+
attributeName: string,
|
|
687
|
+
validationSchema: ZodSchema<O>
|
|
688
|
+
): O | undefined {
|
|
689
|
+
const attr: unknown = prosemirrorNode.attrs?.[attributeName] ?? undefined;
|
|
690
|
+
if (!attr) {
|
|
691
|
+
console.warn(`Prosemirror attribute ${attributeName} on ${prosemirrorNode.type} was not defined`);
|
|
692
|
+
return undefined;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const parsedAttr = validationSchema.safeParse(attr);
|
|
696
|
+
if (parsedAttr.success) {
|
|
697
|
+
return parsedAttr.data;
|
|
698
|
+
} else {
|
|
699
|
+
console.warn(`Prosemirror attribute ${attributeName} on ${prosemirrorNode.type} is not valid and will be ignored`);
|
|
700
|
+
console.warn(parsedAttr.error.flatten());
|
|
701
|
+
return undefined;
|
|
702
|
+
}
|
|
687
703
|
}
|
|
688
704
|
|
|
689
705
|
//
|