@supernova-studio/client 0.0.15 → 0.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supernova-studio/client",
3
- "version": "0.0.15",
3
+ "version": "0.1.0",
4
4
  "description": "Supernova Data Models",
5
5
  "source": "src/index.ts",
6
6
  "main": "dist/index.js",
@@ -24,7 +24,9 @@
24
24
  ],
25
25
  "scripts": {
26
26
  "build": "tsc",
27
- "typecheck": "tsc --noEmit"
27
+ "typecheck": "tsc --noEmit",
28
+ "test:unit": "vitest run",
29
+ "test:unit:watch": "vitest watch"
28
30
  },
29
31
  "author": "",
30
32
  "license": "ISC",
@@ -6,7 +6,9 @@ import {
6
6
  PageBlockText,
7
7
  PageBlockTextSpan,
8
8
  PageBlockTextSpanAttribute,
9
- PageBlockDefinitionRichTextPropertyStyle,
9
+ PageBlockItemRichTextPropertyValue,
10
+ PageBlockCalloutType,
11
+ PageBlockItemMultiRichTextPropertyValue,
10
12
  } from "@supernova-studio/model";
11
13
  import { PageBlockEditorModel } from "./model/block";
12
14
  import {
@@ -20,16 +22,28 @@ import { DocumentationPageEditorModel } from "./model";
20
22
  import { prosemirrorJSONToYXmlFragment } from "y-prosemirror";
21
23
  import { pmSchema } from "./prosemirror";
22
24
 
25
+ //
26
+ // Types
27
+ //
28
+
23
29
  type Input = {
24
30
  block: PageBlockEditorModel;
25
31
  definition: PageBlockDefinition;
26
- richTextProperty: PageBlockDefinitionProperty;
32
+ property: PageBlockDefinitionProperty;
33
+ };
34
+
35
+ type RichTextInputWithValue = Input & {
36
+ richTextPropertyValue: PageBlockItemRichTextPropertyValue;
27
37
  };
28
38
 
29
- type InputWithValue = Input & {
30
- richTextPropertyValue: PageBlockText;
39
+ type MultiRichTextInputWithValue = Input & {
40
+ multiRichTextPropertyValue: PageBlockItemMultiRichTextPropertyValue;
31
41
  };
32
42
 
43
+ //
44
+ // Implementation
45
+ //
46
+
33
47
  export function pageToYXmlFragment(
34
48
  page: DocumentationPageEditorModel,
35
49
  definitions: PageBlockDefinition[],
@@ -66,25 +80,37 @@ export function blockToProsemirrorNode(
66
80
  definition: PageBlockDefinition
67
81
  ): ProsemirrorNode | null {
68
82
  const richTextProperty = BlockDefinitionUtils.firstRichTextProperty(definition);
69
-
70
83
  if (richTextProperty) {
71
84
  return serializeAsRichTextBlock({
72
85
  block: block,
73
86
  definition: definition,
74
- richTextProperty: richTextProperty,
87
+ property: richTextProperty,
88
+ });
89
+ }
90
+
91
+ const multiRichTextProperty = BlockDefinitionUtils.firstMultiRichTextProperty(definition);
92
+ if (multiRichTextProperty) {
93
+ return serializeAsMultiRichTextBlock({
94
+ block: block,
95
+ definition: definition,
96
+ property: multiRichTextProperty,
75
97
  });
76
98
  }
77
99
 
78
100
  return serializeAsCustomBlock(block, definition);
79
101
  }
80
102
 
103
+ //
104
+ // Single rich text blocks
105
+ //
106
+
81
107
  export function serializeAsRichTextBlock(input: Input): ProsemirrorNode {
82
- const { block, definition, richTextProperty } = input;
108
+ const { block, definition, property: richTextProperty } = input;
83
109
 
84
110
  const blockItem = BlockParsingUtils.singleBlockItem(block);
85
111
  const textPropertyValue = BlockParsingUtils.richTextPropertyValue(blockItem, richTextProperty.id);
86
112
 
87
- const enrichedInput: InputWithValue = { ...input, richTextPropertyValue: textPropertyValue };
113
+ const enrichedInput: RichTextInputWithValue = { ...input, richTextPropertyValue: textPropertyValue };
88
114
 
89
115
  const style = richTextProperty.options?.richTextStyle ?? "Default";
90
116
 
@@ -103,55 +129,115 @@ export function serializeAsRichTextBlock(input: Input): ProsemirrorNode {
103
129
  case "Title4":
104
130
  case "Title5":
105
131
  return serializeAsHeading(enrichedInput);
106
-
107
- // Todo: verify
108
- case "OL":
109
- case "UL":
110
- throw new Error(`Not allowed!`);
111
132
  }
112
133
  }
113
134
 
114
- //
115
- // Blocks
116
- //
117
-
118
- function serializeAsParagraph(input: InputWithValue): ProsemirrorNode {
135
+ function serializeAsParagraph(input: RichTextInputWithValue): ProsemirrorNode {
119
136
  return {
120
137
  type: "paragraph",
121
138
  attrs: serializeBlockNodeAttributes(input),
122
- content: serializeRichText(input.richTextPropertyValue),
139
+ content: serializeRichText(input.richTextPropertyValue.value),
123
140
  };
124
141
  }
125
142
 
126
- function serializeAsHeading(input: InputWithValue): ProsemirrorNode {
143
+ function serializeAsHeading(input: RichTextInputWithValue): ProsemirrorNode {
127
144
  return {
128
145
  type: "heading",
129
146
  attrs: {
130
147
  ...serializeBlockNodeAttributes(input),
131
- level: richTextHeadingLevel(input.richTextProperty),
148
+ level: richTextHeadingLevel(input.property),
132
149
  },
133
- content: serializeRichText(input.richTextPropertyValue),
150
+ content: serializeRichText(input.richTextPropertyValue.value),
134
151
  };
135
152
  }
136
153
 
137
- function serializeAsBlockquote(input: InputWithValue): ProsemirrorNode {
154
+ function serializeAsBlockquote(input: RichTextInputWithValue): ProsemirrorNode {
138
155
  return {
139
156
  type: "blockquote",
140
157
  attrs: serializeBlockNodeAttributes(input),
141
- content: serializeRichText(input.richTextPropertyValue),
158
+ content: serializeRichText(input.richTextPropertyValue.value),
142
159
  };
143
160
  }
144
161
 
145
- function serializeAsCallout(input: InputWithValue): ProsemirrorNode {
162
+ function serializeAsCallout(input: RichTextInputWithValue): ProsemirrorNode {
163
+ const calloutType = input.richTextPropertyValue.calloutType ?? "Info";
164
+
146
165
  return {
147
166
  type: "callout",
148
167
  attrs: {
149
168
  ...serializeBlockNodeAttributes(input),
169
+ type: serializeCalloutType(calloutType),
170
+ },
171
+ content: serializeRichText(input.richTextPropertyValue.value),
172
+ };
173
+ }
174
+
175
+ //
176
+ // Multi rich text blocks
177
+ //
178
+
179
+ export function serializeAsMultiRichTextBlock(input: Input): ProsemirrorNode {
180
+ const { block, definition, property: richTextProperty } = input;
181
+
182
+ const blockItem = BlockParsingUtils.singleBlockItem(block);
183
+ const textPropertyValue = BlockParsingUtils.multiRichTextPropertyValue(blockItem, richTextProperty.id);
150
184
 
151
- // TODO Docs: type
152
- type: "neutral",
185
+ const enrichedInput: MultiRichTextInputWithValue = { ...input, multiRichTextPropertyValue: textPropertyValue };
186
+
187
+ const style = richTextProperty.options?.multiRichTextStyle ?? "Default";
188
+
189
+ switch (style) {
190
+ case "Default":
191
+ return serializeAsMultiParagraph(enrichedInput);
192
+
193
+ case "OL":
194
+ return serializeAsOrderedList(enrichedInput);
195
+
196
+ case "UL":
197
+ return serializeAsUnorderedList(enrichedInput);
198
+ }
199
+ }
200
+
201
+ function serializeAsMultiParagraph(input: MultiRichTextInputWithValue): ProsemirrorNode {
202
+ return {
203
+ type: "bulletlist",
204
+ attrs: {
205
+ ...serializeBlockNodeAttributes(input),
206
+ },
207
+ content: input.multiRichTextPropertyValue.value.map(serializeAsListItem),
208
+ };
209
+ }
210
+
211
+ function serializeAsOrderedList(input: MultiRichTextInputWithValue): ProsemirrorNode {
212
+ return {
213
+ type: "orderedlist",
214
+ attrs: {
215
+ ...serializeBlockNodeAttributes(input),
216
+ start: "1",
217
+ },
218
+ content: input.multiRichTextPropertyValue.value.map(serializeAsListItem),
219
+ };
220
+ }
221
+
222
+ function serializeAsUnorderedList(input: MultiRichTextInputWithValue): ProsemirrorNode {
223
+ return {
224
+ type: "bulletlist",
225
+ attrs: {
226
+ ...serializeBlockNodeAttributes(input),
153
227
  },
154
- content: serializeRichText(input.richTextPropertyValue),
228
+ content: input.multiRichTextPropertyValue.value.map(serializeAsListItem),
229
+ };
230
+ }
231
+
232
+ function serializeAsListItem(text: PageBlockText): ProsemirrorNode {
233
+ return {
234
+ type: "listitem",
235
+ content: [
236
+ {
237
+ type: "paragraph",
238
+ content: serializeRichText(text),
239
+ },
240
+ ],
155
241
  };
156
242
  }
157
243
 
@@ -159,18 +245,18 @@ function serializeAsCallout(input: InputWithValue): ProsemirrorNode {
159
245
  // Attributes
160
246
  //
161
247
 
162
- function serializeBlockNodeAttributes(input: InputWithValue) {
248
+ function serializeBlockNodeAttributes(input: Input) {
163
249
  const { block } = input;
164
250
 
165
251
  return {
166
252
  id: block.id,
167
253
  definitionId: block.data.packageId,
168
- ...(input.block.data.variantId && { variantId: input.block.data.variantId }),
254
+ ...(block.data.variantId && { variantId: block.data.variantId }),
169
255
  };
170
256
  }
171
257
 
172
258
  function richTextHeadingLevel(property: PageBlockDefinitionProperty): number | undefined {
173
- const style = property.options?.style;
259
+ const style = property.options?.richTextStyle;
174
260
  if (!style) return undefined;
175
261
 
176
262
  switch (style) {
@@ -184,9 +270,6 @@ function richTextHeadingLevel(property: PageBlockDefinitionProperty): number | u
184
270
  return 4;
185
271
  case "Title5":
186
272
  return 5;
187
-
188
- case "OL":
189
- case "UL":
190
273
  case "Callout":
191
274
  case "Default":
192
275
  case "Quote":
@@ -194,6 +277,19 @@ function richTextHeadingLevel(property: PageBlockDefinitionProperty): number | u
194
277
  }
195
278
  }
196
279
 
280
+ function serializeCalloutType(calloutType: PageBlockCalloutType) {
281
+ switch (calloutType) {
282
+ case "Error":
283
+ return "error";
284
+ case "Info":
285
+ return "neutral";
286
+ case "Success":
287
+ return "success";
288
+ case "Warning":
289
+ return "warning";
290
+ }
291
+ }
292
+
197
293
  //
198
294
  // Rich text
199
295
  //
@@ -21,7 +21,7 @@ const blocks: PageBlockDefinition[] = [
21
21
  description: undefined,
22
22
  options: {
23
23
  placeholder: "Start writing with plain text",
24
- style: "Default",
24
+ richTextStyle: "Default",
25
25
  },
26
26
  variantOptions: undefined,
27
27
  },
@@ -67,7 +67,7 @@ const blocks: PageBlockDefinition[] = [
67
67
  id: "text",
68
68
  name: "Text",
69
69
  type: "RichText",
70
- options: { placeholder: "Title 1", style: "Title1" },
70
+ options: { placeholder: "Title 1", richTextStyle: "Title1" },
71
71
  },
72
72
  ],
73
73
  appearance: { isBordered: false, hasBackground: false },
@@ -112,7 +112,7 @@ const blocks: PageBlockDefinition[] = [
112
112
  name: "Text",
113
113
  type: "RichText",
114
114
  description: undefined,
115
- options: { placeholder: "Title 2", style: "Title2" },
115
+ options: { placeholder: "Title 2", richTextStyle: "Title2" },
116
116
  variantOptions: undefined,
117
117
  },
118
118
  ],
@@ -160,7 +160,7 @@ const blocks: PageBlockDefinition[] = [
160
160
  name: "Text",
161
161
  type: "RichText",
162
162
  description: undefined,
163
- options: { placeholder: "Title 3", style: "Title3" },
163
+ options: { placeholder: "Title 3", richTextStyle: "Title3" },
164
164
  variantOptions: undefined,
165
165
  },
166
166
  ],
@@ -208,7 +208,7 @@ const blocks: PageBlockDefinition[] = [
208
208
  name: "Text",
209
209
  type: "RichText",
210
210
  description: undefined,
211
- options: { placeholder: "Title 4", style: "Title4" },
211
+ options: { placeholder: "Title 4", richTextStyle: "Title4" },
212
212
  variantOptions: undefined,
213
213
  },
214
214
  ],
@@ -256,7 +256,7 @@ const blocks: PageBlockDefinition[] = [
256
256
  name: "Text",
257
257
  type: "RichText",
258
258
  description: undefined,
259
- options: { placeholder: "Title 5", style: "Title5" },
259
+ options: { placeholder: "Title 5", richTextStyle: "Title5" },
260
260
  variantOptions: undefined,
261
261
  },
262
262
  ],
@@ -302,9 +302,9 @@ const blocks: PageBlockDefinition[] = [
302
302
  {
303
303
  id: "text",
304
304
  name: "Text",
305
- type: "RichText",
305
+ type: "MultiRichText",
306
306
  description: undefined,
307
- options: { style: "OL" },
307
+ options: { multiRichTextStyle: "OL" },
308
308
  variantOptions: undefined,
309
309
  },
310
310
  ],
@@ -350,9 +350,9 @@ const blocks: PageBlockDefinition[] = [
350
350
  {
351
351
  id: "text",
352
352
  name: "Text",
353
- type: "RichText",
353
+ type: "MultiRichText",
354
354
  description: undefined,
355
- options: { style: "UL" },
355
+ options: { multiRichTextStyle: "UL" },
356
356
  variantOptions: undefined,
357
357
  },
358
358
  ],
@@ -448,7 +448,7 @@ const blocks: PageBlockDefinition[] = [
448
448
  name: "Text",
449
449
  type: "RichText",
450
450
  description: undefined,
451
- options: { placeholder: "Empty quote", style: "Quote" },
451
+ options: { placeholder: "Empty quote", richTextStyle: "Quote" },
452
452
  variantOptions: undefined,
453
453
  },
454
454
  ],
@@ -496,7 +496,7 @@ const blocks: PageBlockDefinition[] = [
496
496
  name: "Text",
497
497
  type: "RichText",
498
498
  description: undefined,
499
- options: { style: "Callout" },
499
+ options: { richTextStyle: "Callout" },
500
500
  variantOptions: undefined,
501
501
  },
502
502
  ],
@@ -593,7 +593,7 @@ const blocks: PageBlockDefinition[] = [
593
593
  name: "Title",
594
594
  type: "RichText",
595
595
  description: undefined,
596
- options: { style: "Title5" },
596
+ options: { textStyle: "Title5" },
597
597
  variantOptions: undefined,
598
598
  },
599
599
  {
@@ -601,7 +601,7 @@ const blocks: PageBlockDefinition[] = [
601
601
  name: "Short description",
602
602
  type: "RichText",
603
603
  description: undefined,
604
- options: { style: "Default", color: "NeutralFaded" },
604
+ options: { textStyle: "Default", color: "NeutralFaded" },
605
605
  variantOptions: undefined,
606
606
  },
607
607
  {
@@ -2,6 +2,9 @@ import { PageBlockEditorModel } from "./model/block";
2
2
  import {
3
3
  PageBlockDefinition,
4
4
  PageBlockDefinitionPropertyType,
5
+ PageBlockItemMultiRichTextPropertyValue,
6
+ PageBlockItemRichTextPropertyValue,
7
+ PageBlockItemUntypedPropertyValue,
5
8
  PageBlockItemV2,
6
9
  PageBlockText,
7
10
  } from "@supernova-studio/model";
@@ -14,15 +17,22 @@ export const BlockParsingUtils = {
14
17
  return block.data.items[0]!;
15
18
  },
16
19
 
17
- richTextPropertyValue(item: PageBlockItemV2, propertyKey: string) {
20
+ richTextPropertyValue(item: PageBlockItemV2, propertyKey: string): PageBlockItemRichTextPropertyValue {
18
21
  const objectValue = this.objectPropertyValue(item, propertyKey);
19
- const richText = PageBlockText.parse(objectValue.value);
22
+ const richText = PageBlockItemRichTextPropertyValue.parse(objectValue);
23
+
24
+ return richText;
25
+ },
26
+
27
+ multiRichTextPropertyValue(item: PageBlockItemV2, propertyKey: string): PageBlockItemMultiRichTextPropertyValue {
28
+ const objectValue = this.objectPropertyValue(item, propertyKey);
29
+ const richText = PageBlockItemMultiRichTextPropertyValue.parse(objectValue);
20
30
 
21
31
  return richText;
22
32
  },
23
33
 
24
34
  objectPropertyValue(item: PageBlockItemV2, propertyKey: string) {
25
- const value = this.propertyValue(item, propertyKey);
35
+ const value = this.propertyValueOrThrow(item, propertyKey);
26
36
 
27
37
  if (typeof value !== "object") {
28
38
  throw new Error(`Value for property ${propertyKey} is expected to be an object, but instead is ${typeof value}`);
@@ -31,16 +41,12 @@ export const BlockParsingUtils = {
31
41
  return value;
32
42
  },
33
43
 
34
- propertyValue(item: PageBlockItemV2, propertyKey: string) {
35
- const value = this.safePropertyValue(item, propertyKey);
44
+ propertyValueOrThrow(item: PageBlockItemV2, propertyKey: string): PageBlockItemUntypedPropertyValue {
45
+ const value = item.props[propertyKey];
36
46
  if (!value) throw new Error(`Property ${propertyKey} is not defined on block item`);
37
47
 
38
48
  return value;
39
49
  },
40
-
41
- safePropertyValue(item: PageBlockItemV2, propertyKey: string) {
42
- return item.props[propertyKey] ?? undefined;
43
- },
44
50
  };
45
51
 
46
52
  export const BlockDefinitionUtils = {
@@ -50,6 +56,12 @@ export const BlockDefinitionUtils = {
50
56
  return undefined;
51
57
  },
52
58
 
59
+ firstMultiRichTextProperty(definition: PageBlockDefinition) {
60
+ const property = definition.item.properties.find(p => p.type === "MultiRichText");
61
+ if (property) return property;
62
+ return undefined;
63
+ },
64
+
53
65
  firstTableProperty(definition: PageBlockDefinition) {
54
66
  const property = definition.item.properties.find(p => p.type === "RichText");
55
67
  if (property) return property;