@portabletext/editor 3.0.2 → 3.0.4

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.
@@ -0,0 +1,289 @@
1
+ import {compileSchema, defineSchema} from '@portabletext/schema'
2
+ import {createTestKeyGenerator} from '@portabletext/test'
3
+ import {describe, expect, test} from 'vitest'
4
+ import {toSlateBlock, VOID_CHILD_KEY} from './values'
5
+
6
+ describe(toSlateBlock.name, () => {
7
+ describe('text block', () => {
8
+ describe('with span', () => {
9
+ test('with _type', () => {
10
+ const keyGenerator = createTestKeyGenerator()
11
+ const blockKey = keyGenerator()
12
+ const spanKey = keyGenerator()
13
+
14
+ expect(
15
+ toSlateBlock(
16
+ {
17
+ _type: 'block',
18
+ _key: blockKey,
19
+ children: [{_key: spanKey, _type: 'span', text: 'foo'}],
20
+ },
21
+ {
22
+ schemaTypes: compileSchema(defineSchema({})),
23
+ },
24
+ ),
25
+ ).toEqual({
26
+ _type: 'block',
27
+ _key: blockKey,
28
+ children: [
29
+ {
30
+ _key: spanKey,
31
+ _type: 'span',
32
+ text: 'foo',
33
+ },
34
+ ],
35
+ style: 'normal',
36
+ })
37
+ })
38
+
39
+ test('without _type', () => {
40
+ const keyGenerator = createTestKeyGenerator()
41
+ const blockKey = keyGenerator()
42
+ const spanKey = keyGenerator()
43
+
44
+ expect(
45
+ toSlateBlock(
46
+ {
47
+ _type: 'block',
48
+ _key: blockKey,
49
+ children: [{_key: spanKey, text: 'foo'}],
50
+ },
51
+ {
52
+ schemaTypes: compileSchema(defineSchema({})),
53
+ },
54
+ ),
55
+ ).toEqual({
56
+ _type: 'block',
57
+ _key: blockKey,
58
+ children: [
59
+ {
60
+ _key: spanKey,
61
+ _type: 'span',
62
+ text: 'foo',
63
+ },
64
+ ],
65
+ style: 'normal',
66
+ })
67
+ })
68
+
69
+ test('wrong _type', () => {
70
+ const keyGenerator = createTestKeyGenerator()
71
+ const blockKey = keyGenerator()
72
+ const spanKey = keyGenerator()
73
+
74
+ expect(
75
+ toSlateBlock(
76
+ {
77
+ _type: 'block',
78
+ _key: blockKey,
79
+ children: [{_key: spanKey, _type: 'stock-ticker', text: 'foo'}],
80
+ },
81
+ {
82
+ schemaTypes: compileSchema(defineSchema({})),
83
+ },
84
+ ),
85
+ ).toEqual({
86
+ _type: 'block',
87
+ _key: blockKey,
88
+ children: [
89
+ {
90
+ _key: spanKey,
91
+ _type: 'stock-ticker',
92
+ children: [
93
+ {
94
+ _key: VOID_CHILD_KEY,
95
+ _type: 'span',
96
+ text: '',
97
+ marks: [],
98
+ },
99
+ ],
100
+ value: {text: 'foo'},
101
+ __inline: true,
102
+ },
103
+ ],
104
+ style: 'normal',
105
+ })
106
+ })
107
+ })
108
+
109
+ describe('with inline object', () => {
110
+ test('known inline object _type', () => {
111
+ const keyGenerator = createTestKeyGenerator()
112
+ const blockKey = keyGenerator()
113
+ const stockTickerKey = keyGenerator()
114
+
115
+ expect(
116
+ toSlateBlock(
117
+ {
118
+ _type: 'block',
119
+ _key: blockKey,
120
+ children: [
121
+ {_type: 'stock-ticker', _key: stockTickerKey, symbol: 'AAPL'},
122
+ ],
123
+ },
124
+ {
125
+ schemaTypes: compileSchema(
126
+ defineSchema({inlineObjects: [{name: 'stock-ticker'}]}),
127
+ ),
128
+ },
129
+ ),
130
+ ).toEqual({
131
+ _type: 'block',
132
+ _key: blockKey,
133
+ children: [
134
+ {
135
+ __inline: true,
136
+ _key: stockTickerKey,
137
+ _type: 'stock-ticker',
138
+ children: [
139
+ {
140
+ _key: VOID_CHILD_KEY,
141
+ _type: 'span',
142
+ text: '',
143
+ marks: [],
144
+ },
145
+ ],
146
+ value: {
147
+ symbol: 'AAPL',
148
+ },
149
+ },
150
+ ],
151
+ style: 'normal',
152
+ })
153
+ })
154
+
155
+ test('unknown inline object _type', () => {
156
+ const keyGenerator = createTestKeyGenerator()
157
+ const blockKey = keyGenerator()
158
+ const stockTickerKey = keyGenerator()
159
+
160
+ expect(
161
+ toSlateBlock(
162
+ {
163
+ _type: 'block',
164
+ _key: blockKey,
165
+ children: [
166
+ {_type: 'stock-ticker', _key: stockTickerKey, symbol: 'AAPL'},
167
+ ],
168
+ },
169
+ {
170
+ schemaTypes: compileSchema(defineSchema({})),
171
+ },
172
+ ),
173
+ ).toEqual({
174
+ _type: 'block',
175
+ _key: blockKey,
176
+ children: [
177
+ {
178
+ __inline: true,
179
+ _key: stockTickerKey,
180
+ _type: 'stock-ticker',
181
+ children: [
182
+ {
183
+ _key: VOID_CHILD_KEY,
184
+ _type: 'span',
185
+ text: '',
186
+ marks: [],
187
+ },
188
+ ],
189
+ value: {
190
+ symbol: 'AAPL',
191
+ },
192
+ },
193
+ ],
194
+ style: 'normal',
195
+ })
196
+ })
197
+ })
198
+
199
+ describe('with inline object with text prop', () => {
200
+ test('known inline object _type', () => {
201
+ const keyGenerator = createTestKeyGenerator()
202
+ const blockKey = keyGenerator()
203
+ const stockTickerKey = keyGenerator()
204
+
205
+ expect(
206
+ toSlateBlock(
207
+ {
208
+ _type: 'block',
209
+ _key: blockKey,
210
+ children: [
211
+ {_type: 'stock-ticker', _key: stockTickerKey, text: 'foo'},
212
+ ],
213
+ },
214
+ {
215
+ schemaTypes: compileSchema(
216
+ defineSchema({inlineObjects: [{name: 'stock-ticker'}]}),
217
+ ),
218
+ },
219
+ ),
220
+ ).toEqual({
221
+ _type: 'block',
222
+ _key: blockKey,
223
+ children: [
224
+ {
225
+ __inline: true,
226
+ _key: stockTickerKey,
227
+ _type: 'stock-ticker',
228
+ children: [
229
+ {
230
+ _key: VOID_CHILD_KEY,
231
+ _type: 'span',
232
+ text: '',
233
+ marks: [],
234
+ },
235
+ ],
236
+ value: {
237
+ text: 'foo',
238
+ },
239
+ },
240
+ ],
241
+ style: 'normal',
242
+ })
243
+ })
244
+
245
+ test('unknown inline object _type', () => {
246
+ const keyGenerator = createTestKeyGenerator()
247
+ const blockKey = keyGenerator()
248
+ const stockTickerKey = keyGenerator()
249
+
250
+ expect(
251
+ toSlateBlock(
252
+ {
253
+ _type: 'block',
254
+ _key: blockKey,
255
+ children: [
256
+ {_type: 'stock-ticker', _key: stockTickerKey, text: 'foo'},
257
+ ],
258
+ },
259
+ {
260
+ schemaTypes: compileSchema(defineSchema({})),
261
+ },
262
+ ),
263
+ ).toEqual({
264
+ _type: 'block',
265
+ _key: blockKey,
266
+ children: [
267
+ {
268
+ __inline: true,
269
+ _key: stockTickerKey,
270
+ _type: 'stock-ticker',
271
+ children: [
272
+ {
273
+ _key: VOID_CHILD_KEY,
274
+ _type: 'span',
275
+ text: '',
276
+ marks: [],
277
+ },
278
+ ],
279
+ value: {
280
+ text: 'foo',
281
+ },
282
+ },
283
+ ],
284
+ style: 'normal',
285
+ })
286
+ })
287
+ })
288
+ })
289
+ })
@@ -24,17 +24,6 @@ function keepObjectEquality(
24
24
  return object
25
25
  }
26
26
 
27
- export function toSlateValue(
28
- value: PortableTextBlock[] | undefined,
29
- {schemaTypes}: {schemaTypes: EditorSchema},
30
- keyMap: Record<string, any> = {},
31
- ): Descendant[] {
32
- if (value && Array.isArray(value)) {
33
- return value.map((block) => toSlateBlock(block, {schemaTypes}, keyMap))
34
- }
35
- return []
36
- }
37
-
38
27
  export function toSlateBlock(
39
28
  block: PortableTextBlock,
40
29
  {schemaTypes}: {schemaTypes: EditorSchema},
@@ -54,11 +43,17 @@ export function toSlateBlock(
54
43
  const {_type: childType, _key: childKey, ...childProps} = child
55
44
  const propKeys = Object.keys(childProps)
56
45
 
57
- if (childType !== schemaTypes.span.name) {
46
+ if (childType === undefined) {
58
47
  if (propKeys.length === 1 && propKeys.at(0) === 'text') {
59
- return child
48
+ return {
49
+ _key: childKey,
50
+ _type: schemaTypes.span.name,
51
+ text: childProps.text,
52
+ }
60
53
  }
54
+ }
61
55
 
56
+ if (childType !== schemaTypes.span.name) {
62
57
  // Return 'slate' version of inline object where the actual
63
58
  // value is stored in the `value` property.
64
59
  // In slate, inline objects are represented as regular
@@ -135,51 +130,57 @@ export function fromSlateValue(
135
130
  textBlockType: string,
136
131
  keyMap: Record<string, PortableTextBlock | PortableTextChild> = {},
137
132
  ): PortableTextBlock[] {
138
- return value.map((block) => {
139
- const {_key, _type} = block
140
- if (!_key || !_type) {
141
- throw new Error('Not a valid block')
142
- }
143
- if (
144
- _type === textBlockType &&
145
- 'children' in block &&
146
- Array.isArray(block.children) &&
147
- _key
148
- ) {
149
- let hasInlines = false
150
- const children = block.children.map((child) => {
151
- const {_type: _cType} = child
152
- if ('value' in child && _cType !== 'span') {
153
- hasInlines = true
154
- const {
155
- value: v,
156
- _key: k,
157
- _type: t,
158
- __inline: _i,
159
- children: _c,
160
- ...rest
161
- } = child
162
- return keepObjectEquality(
163
- {...rest, ...v, _key: k as string, _type: t as string},
164
- keyMap,
165
- )
166
- }
167
- return child
168
- })
169
- if (!hasInlines) {
170
- return block as PortableTextBlock // Original object
133
+ return value.map((block) => fromSlateBlock(block, textBlockType, keyMap))
134
+ }
135
+
136
+ export function fromSlateBlock(
137
+ block: Descendant,
138
+ textBlockType: string,
139
+ keyMap: Record<string, PortableTextBlock | PortableTextChild> = {},
140
+ ) {
141
+ const {_key, _type} = block
142
+ if (!_key || !_type) {
143
+ throw new Error('Not a valid block')
144
+ }
145
+ if (
146
+ _type === textBlockType &&
147
+ 'children' in block &&
148
+ Array.isArray(block.children) &&
149
+ _key
150
+ ) {
151
+ let hasInlines = false
152
+ const children = block.children.map((child) => {
153
+ const {_type: _cType} = child
154
+ if ('value' in child && _cType !== 'span') {
155
+ hasInlines = true
156
+ const {
157
+ value: v,
158
+ _key: k,
159
+ _type: t,
160
+ __inline: _i,
161
+ children: _c,
162
+ ...rest
163
+ } = child
164
+ return keepObjectEquality(
165
+ {...rest, ...v, _key: k as string, _type: t as string},
166
+ keyMap,
167
+ )
171
168
  }
172
- return keepObjectEquality(
173
- {...block, children, _key, _type},
174
- keyMap,
175
- ) as PortableTextBlock
169
+ return child
170
+ })
171
+ if (!hasInlines) {
172
+ return block as PortableTextBlock // Original object
176
173
  }
177
- const blockValue = 'value' in block && block.value
178
174
  return keepObjectEquality(
179
- {_key, _type, ...(typeof blockValue === 'object' ? blockValue : {})},
175
+ {...block, children, _key, _type},
180
176
  keyMap,
181
177
  ) as PortableTextBlock
182
- })
178
+ }
179
+ const blockValue = 'value' in block && block.value
180
+ return keepObjectEquality(
181
+ {_key, _type, ...(typeof blockValue === 'object' ? blockValue : {})},
182
+ keyMap,
183
+ ) as PortableTextBlock
183
184
  }
184
185
 
185
186
  export function isEqualToEmptyEditor(
@@ -3,7 +3,7 @@ import {omit} from 'lodash'
3
3
  import {Editor, Transforms} from 'slate'
4
4
  import {KEY_TO_VALUE_ELEMENT} from '../editor/weakMaps'
5
5
  import {toSlateRange} from '../internal-utils/to-slate-range'
6
- import {fromSlateValue} from '../internal-utils/values'
6
+ import {fromSlateBlock} from '../internal-utils/values'
7
7
  import {parseBlock} from '../utils/parse-blocks'
8
8
  import type {BehaviorOperationImplementation} from './behavior.operations'
9
9
 
@@ -35,11 +35,11 @@ export const blockUnsetOperationImplementation: BehaviorOperationImplementation<
35
35
  throw new Error(`Unable to find block at ${JSON.stringify(operation.at)}`)
36
36
  }
37
37
 
38
- const parsedBlock = fromSlateValue(
39
- [block],
38
+ const parsedBlock = fromSlateBlock(
39
+ block,
40
40
  context.schema.block.name,
41
41
  KEY_TO_VALUE_ELEMENT.get(operation.editor),
42
- ).at(0)
42
+ )
43
43
 
44
44
  if (!parsedBlock) {
45
45
  throw new Error(`Unable to parse block at ${JSON.stringify(operation.at)}`)