@portabletext/editor 2.6.7 → 2.6.9

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.
@@ -1,5 +1,5 @@
1
1
  import { Behavior, Editor, EditorEmittedEvent, EditorSchema } from "../_chunks-dts/behavior.types.action.cjs";
2
- import * as react12 from "react";
2
+ import * as react22 from "react";
3
3
  import React from "react";
4
4
  /**
5
5
  * @beta
@@ -181,7 +181,7 @@ type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
181
181
  */
182
182
  declare function MarkdownPlugin(props: {
183
183
  config: MarkdownPluginConfig;
184
- }): react12.JSX.Element;
184
+ }): react22.JSX.Element;
185
185
  /**
186
186
  * @beta
187
187
  * Restrict the editor to one line. The plugin takes care of blocking
@@ -192,5 +192,5 @@ declare function MarkdownPlugin(props: {
192
192
  *
193
193
  * @deprecated Install the plugin from `@portabletext/plugin-one-line`
194
194
  */
195
- declare function OneLinePlugin(): react12.JSX.Element;
195
+ declare function OneLinePlugin(): react22.JSX.Element;
196
196
  export { BehaviorPlugin, DecoratorShortcutPlugin, EditorRefPlugin, EventListenerPlugin, MarkdownPlugin, type MarkdownPluginConfig, OneLinePlugin };
@@ -1,5 +1,5 @@
1
1
  import { Behavior, Editor, EditorEmittedEvent, EditorSchema } from "../_chunks-dts/behavior.types.action.js";
2
- import * as react22 from "react";
2
+ import * as react12 from "react";
3
3
  import React from "react";
4
4
  /**
5
5
  * @beta
@@ -181,7 +181,7 @@ type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
181
181
  */
182
182
  declare function MarkdownPlugin(props: {
183
183
  config: MarkdownPluginConfig;
184
- }): react22.JSX.Element;
184
+ }): react12.JSX.Element;
185
185
  /**
186
186
  * @beta
187
187
  * Restrict the editor to one line. The plugin takes care of blocking
@@ -192,5 +192,5 @@ declare function MarkdownPlugin(props: {
192
192
  *
193
193
  * @deprecated Install the plugin from `@portabletext/plugin-one-line`
194
194
  */
195
- declare function OneLinePlugin(): react22.JSX.Element;
195
+ declare function OneLinePlugin(): react12.JSX.Element;
196
196
  export { BehaviorPlugin, DecoratorShortcutPlugin, EditorRefPlugin, EventListenerPlugin, MarkdownPlugin, type MarkdownPluginConfig, OneLinePlugin };
@@ -1,5 +1,5 @@
1
1
  import { BlockOffset, BlockPath, ChildPath, EditorContext, EditorSelection, EditorSelectionPoint } from "../_chunks-dts/behavior.types.action.cjs";
2
- import * as _sanity_types9 from "@sanity/types";
2
+ import * as _sanity_types8 from "@sanity/types";
3
3
  import { KeyedSegment, PortableTextBlock, PortableTextTextBlock } from "@sanity/types";
4
4
  import { isSpan, isTextBlock } from "@portabletext/schema";
5
5
  /**
@@ -143,7 +143,7 @@ declare function mergeTextBlocks({
143
143
  context: Pick<EditorContext, 'keyGenerator' | 'schema'>;
144
144
  targetBlock: PortableTextTextBlock;
145
145
  incomingBlock: PortableTextTextBlock;
146
- }): PortableTextTextBlock<_sanity_types9.PortableTextObject | _sanity_types9.PortableTextSpan>;
146
+ }): PortableTextTextBlock<_sanity_types8.PortableTextObject | _sanity_types8.PortableTextSpan>;
147
147
  /**
148
148
  * @public
149
149
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "2.6.7",
3
+ "version": "2.6.9",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -78,7 +78,7 @@
78
78
  "slate": "0.118.1",
79
79
  "slate-dom": "^0.118.1",
80
80
  "slate-react": "0.117.4",
81
- "xstate": "^5.20.2",
81
+ "xstate": "^5.21.0",
82
82
  "@portabletext/block-tools": "^3.5.1",
83
83
  "@portabletext/keyboard-shortcuts": "^1.1.1",
84
84
  "@portabletext/schema": "^1.2.0",
@@ -103,6 +103,59 @@ export const abstractDeleteBehaviors = [
103
103
  return false
104
104
  }
105
105
 
106
+ const nextBlock = selectors.getNextBlock({
107
+ ...snapshot,
108
+ context: {
109
+ ...snapshot.context,
110
+ selection: event.at,
111
+ },
112
+ })
113
+ const focusTextBlock = selectors.getFocusTextBlock({
114
+ ...snapshot,
115
+ context: {
116
+ ...snapshot.context,
117
+ selection: event.at,
118
+ },
119
+ })
120
+
121
+ if (!nextBlock || !focusTextBlock) {
122
+ return false
123
+ }
124
+
125
+ if (!utils.isEmptyTextBlock(snapshot.context, focusTextBlock.node)) {
126
+ return false
127
+ }
128
+
129
+ const nextBlockStartPoint = utils.getBlockStartPoint({
130
+ context: snapshot.context,
131
+ block: nextBlock,
132
+ })
133
+
134
+ return {focusTextBlock, nextBlockStartPoint}
135
+ },
136
+ actions: [
137
+ (_, {focusTextBlock, nextBlockStartPoint}) => [
138
+ raise({
139
+ type: 'delete.block',
140
+ at: focusTextBlock.path,
141
+ }),
142
+ raise({
143
+ type: 'select',
144
+ at: {
145
+ anchor: nextBlockStartPoint,
146
+ focus: nextBlockStartPoint,
147
+ },
148
+ }),
149
+ ],
150
+ ],
151
+ }),
152
+ defineBehavior({
153
+ on: 'delete',
154
+ guard: ({snapshot, event}) => {
155
+ if (event.direction !== 'forward') {
156
+ return false
157
+ }
158
+
106
159
  const nextBlock = selectors.getNextBlock(snapshot)
107
160
  const focusTextBlock = selectors.getFocusTextBlock(snapshot)
108
161
 
@@ -147,39 +147,7 @@ describe('Feature: Self-solving', () => {
147
147
  })
148
148
  expect(onChange).toHaveBeenNthCalledWith(8, {
149
149
  type: 'mutation',
150
- patches: [spanPatch, blockPatch],
151
- snapshot: [
152
- block({
153
- _key: 'b1',
154
- children: [
155
- span({
156
- _key: 's1',
157
- text: 'foo',
158
- marks: [],
159
- }),
160
- ],
161
- style: 'normal',
162
- markDefs: [],
163
- }),
164
- ],
165
- value: [
166
- block({
167
- _key: 'b1',
168
- children: [
169
- span({
170
- _key: 's1',
171
- text: 'foo',
172
- marks: [],
173
- }),
174
- ],
175
- style: 'normal',
176
- markDefs: [],
177
- }),
178
- ],
179
- })
180
- expect(onChange).toHaveBeenNthCalledWith(9, {
181
- type: 'mutation',
182
- patches: [strongPatch],
150
+ patches: [spanPatch, blockPatch, strongPatch],
183
151
  snapshot: [
184
152
  block({
185
153
  _key: 'b1',
@@ -10,8 +10,8 @@ import {
10
10
  enqueueActions,
11
11
  fromCallback,
12
12
  not,
13
+ raise,
13
14
  setup,
14
- stateIn,
15
15
  type AnyEventObject,
16
16
  } from 'xstate'
17
17
  import {debugWithName} from '../internal-utils/debug'
@@ -41,7 +41,7 @@ export const mutationMachine = setup({
41
41
  },
42
42
  events: {} as
43
43
  | {
44
- type: 'mutation delay passed'
44
+ type: 'emit changes'
45
45
  }
46
46
  | {
47
47
  type: 'patch'
@@ -164,12 +164,12 @@ export const mutationMachine = setup({
164
164
  input.slateEditor.apply = originalApply
165
165
  }
166
166
  }),
167
- 'mutation debouncer': fromCallback(({sendBack}) => {
167
+ 'mutation interval': fromCallback(({sendBack}) => {
168
168
  const interval = setInterval(
169
169
  () => {
170
- sendBack({type: 'mutation delay passed'})
170
+ sendBack({type: 'emit changes'})
171
171
  },
172
- process.env.NODE_ENV === 'test' ? 250 : 0,
172
+ process.env.NODE_ENV === 'test' ? 250 : 1000,
173
173
  )
174
174
 
175
175
  return () => {
@@ -179,12 +179,11 @@ export const mutationMachine = setup({
179
179
  },
180
180
  guards: {
181
181
  'is read-only': ({context}) => context.readOnly,
182
- 'is typing': stateIn({typing: 'typing'}),
183
182
  'slate is normalizing': ({context}) =>
184
183
  Editor.isNormalizing(context.slateEditor),
185
184
  },
186
185
  delays: {
187
- 'type debounce': process.env.NODE_ENV === 'test' ? 0 : 250,
186
+ 'type debounce': 250,
188
187
  },
189
188
  }).createMachine({
190
189
  id: 'mutation',
@@ -232,6 +231,7 @@ export const mutationMachine = setup({
232
231
  'type debounce': {
233
232
  target: 'idle',
234
233
  actions: [
234
+ raise({type: 'emit changes'}),
235
235
  () => {
236
236
  debug('exit: typing->typing')
237
237
  },
@@ -241,6 +241,7 @@ export const mutationMachine = setup({
241
241
  on: {
242
242
  'not typing': {
243
243
  target: 'idle',
244
+ actions: [raise({type: 'emit changes'})],
244
245
  },
245
246
  'typing': {
246
247
  target: 'typing',
@@ -291,15 +292,11 @@ export const mutationMachine = setup({
291
292
  },
292
293
  ],
293
294
  invoke: {
294
- src: 'mutation debouncer',
295
+ src: 'mutation interval',
295
296
  },
296
297
  on: {
297
- 'mutation delay passed': {
298
- guard: and([
299
- not('is read-only'),
300
- not('is typing'),
301
- 'slate is normalizing',
302
- ]),
298
+ 'emit changes': {
299
+ guard: and([not('is read-only'), 'slate is normalizing']),
303
300
  target: 'idle',
304
301
  actions: [
305
302
  'emit pending patch events',
@@ -26,7 +26,7 @@ import {
26
26
  import type {PortableTextSlateEditor} from '../../types/editor'
27
27
  import type {EditorActor} from '../editor-machine'
28
28
  import type {RelayActor} from '../relay-machine'
29
- import {getCurrentOperationId} from '../with-applying-behavior-operations'
29
+ import {getCurrentUndoStepId} from '../with-undo-step'
30
30
  import {withoutSaving} from './createWithUndoRedo'
31
31
 
32
32
  const debug = debugWithName('plugin:withPatches')
@@ -266,7 +266,7 @@ export function createWithPatches({
266
266
  editorActor.send({
267
267
  type: 'internal.patch',
268
268
  patch: {...patch, origin: 'local'},
269
- operationId: getCurrentOperationId(editor),
269
+ operationId: getCurrentUndoStepId(editor),
270
270
  value: editor.value,
271
271
  })
272
272
  }
@@ -53,6 +53,9 @@ describe(buildIndexMaps.name, () => {
53
53
  expect(listIndexMap).toEqual(new Map())
54
54
  })
55
55
 
56
+ /**
57
+ * #
58
+ */
56
59
  test('single list item', () => {
57
60
  buildIndexMaps(
58
61
  {schema, value: [textBlock('k0', {listItem: 'number', level: 1})]},
@@ -62,6 +65,9 @@ describe(buildIndexMaps.name, () => {
62
65
  expect(listIndexMap).toEqual(new Map([['k0', 1]]))
63
66
  })
64
67
 
68
+ /**
69
+ * #
70
+ */
65
71
  test('single indented list item', () => {
66
72
  buildIndexMaps(
67
73
  {schema, value: [textBlock('k0', {listItem: 'number', level: 2})]},
@@ -71,6 +77,13 @@ describe(buildIndexMaps.name, () => {
71
77
  expect(listIndexMap).toEqual(new Map([['k0', 1]]))
72
78
  })
73
79
 
80
+ /**
81
+ * #
82
+ * #
83
+ *
84
+ * #
85
+ * #
86
+ */
74
87
  test('two lists broken up by a paragraph', () => {
75
88
  buildIndexMaps(
76
89
  {
@@ -104,6 +117,13 @@ describe(buildIndexMaps.name, () => {
104
117
  )
105
118
  })
106
119
 
120
+ /**
121
+ * #
122
+ * #
123
+ * {image}
124
+ * #
125
+ * #
126
+ */
107
127
  test('two lists broken up by an image', () => {
108
128
  buildIndexMaps(
109
129
  {
@@ -137,6 +157,11 @@ describe(buildIndexMaps.name, () => {
137
157
  )
138
158
  })
139
159
 
160
+ /**
161
+ * #
162
+ * -
163
+ * #
164
+ */
140
165
  test('numbered lists broken up by a bulleted list', () => {
141
166
  buildIndexMaps(
142
167
  {
@@ -165,6 +190,11 @@ describe(buildIndexMaps.name, () => {
165
190
  )
166
191
  })
167
192
 
193
+ /**
194
+ * #
195
+ * -
196
+ * #
197
+ */
168
198
  test('numbered list broken up by an indented bulleted list', () => {
169
199
  buildIndexMaps(
170
200
  {
@@ -186,6 +216,13 @@ describe(buildIndexMaps.name, () => {
186
216
  )
187
217
  })
188
218
 
219
+ /**
220
+ * #
221
+ * #
222
+ * -
223
+ * -
224
+ * #
225
+ */
189
226
  test('numbered list broken up by a nested bulleted list', () => {
190
227
  buildIndexMaps(
191
228
  {
@@ -211,6 +248,14 @@ describe(buildIndexMaps.name, () => {
211
248
  )
212
249
  })
213
250
 
251
+ /**
252
+ * #
253
+ * #
254
+ * -
255
+ * -
256
+ * -
257
+ * #
258
+ */
214
259
  test('numbered list broken up by an inverse-indented bulleted list', () => {
215
260
  buildIndexMaps(
216
261
  {
@@ -238,6 +283,12 @@ describe(buildIndexMaps.name, () => {
238
283
  )
239
284
  })
240
285
 
286
+ /**
287
+ * #
288
+ * #
289
+ * #
290
+ * #
291
+ */
241
292
  test('simple indented list', () => {
242
293
  buildIndexMaps(
243
294
  {
@@ -269,6 +320,11 @@ describe(buildIndexMaps.name, () => {
269
320
  )
270
321
  })
271
322
 
323
+ /**
324
+ * #
325
+ * #
326
+ * #
327
+ */
272
328
  test('reverse indented list', () => {
273
329
  buildIndexMaps(
274
330
  {
@@ -297,6 +353,17 @@ describe(buildIndexMaps.name, () => {
297
353
  )
298
354
  })
299
355
 
356
+ /**
357
+ * #
358
+ * #
359
+ * #
360
+ * #
361
+ * #
362
+ * #
363
+ * #
364
+ * #
365
+ * #
366
+ */
300
367
  test('complex list', () => {
301
368
  buildIndexMaps(
302
369
  {
@@ -342,4 +409,56 @@ describe(buildIndexMaps.name, () => {
342
409
  ]),
343
410
  )
344
411
  })
412
+
413
+ /**
414
+ * -
415
+ * #
416
+ * #
417
+ */
418
+ test('bulleted list with indented numbered list', () => {
419
+ buildIndexMaps(
420
+ {
421
+ schema,
422
+ value: [
423
+ textBlock('k0', {listItem: 'bullet', level: 1}),
424
+ textBlock('k1', {listItem: 'number', level: 2}),
425
+ textBlock('k2', {listItem: 'number', level: 2}),
426
+ ],
427
+ },
428
+ {blockIndexMap, listIndexMap},
429
+ )
430
+ expect(listIndexMap).toEqual(
431
+ new Map([
432
+ ['k0', 1],
433
+ ['k1', 1],
434
+ ['k2', 2],
435
+ ]),
436
+ )
437
+ })
438
+
439
+ /**
440
+ * #
441
+ * -
442
+ * #
443
+ */
444
+ test('indented numbered list broken up by outdented bulleted list', () => {
445
+ buildIndexMaps(
446
+ {
447
+ schema,
448
+ value: [
449
+ textBlock('k0', {listItem: 'number', level: 2}),
450
+ textBlock('k1', {listItem: 'bullet', level: 1}),
451
+ textBlock('k3', {listItem: 'number', level: 2}),
452
+ ],
453
+ },
454
+ {blockIndexMap, listIndexMap},
455
+ )
456
+ expect(listIndexMap).toEqual(
457
+ new Map([
458
+ ['k0', 1],
459
+ ['k1', 1],
460
+ ['k3', 1],
461
+ ]),
462
+ )
463
+ })
345
464
  })
@@ -95,19 +95,31 @@ export function buildIndexMaps(
95
95
  continue
96
96
  }
97
97
 
98
- // Reset all other list items on this level
98
+ // Reset other list types at current level and deeper
99
99
  levelIndexMaps.forEach((levelIndexMap, listItem) => {
100
100
  if (listItem === block.listItem) {
101
101
  return
102
102
  }
103
103
 
104
- levelIndexMap.set(block.level!, 0)
104
+ // Reset all levels that are >= current level
105
+ const levelsToDelete: number[] = []
106
+
107
+ levelIndexMap.forEach((_, level) => {
108
+ if (level >= block.level!) {
109
+ levelsToDelete.push(level)
110
+ }
111
+ })
112
+
113
+ levelsToDelete.forEach((level) => {
114
+ levelIndexMap.delete(level)
115
+ })
105
116
  })
106
117
 
107
118
  const levelIndexMap =
108
119
  levelIndexMaps.get(block.listItem) ?? new Map<number, number>()
109
120
  const levelCounter = levelIndexMap.get(block.level) ?? 0
110
121
  levelIndexMap.set(block.level, levelCounter + 1)
122
+ levelIndexMaps.set(block.listItem, levelIndexMap)
111
123
 
112
124
  listIndexMap.set(block._key, levelCounter + 1)
113
125
 
@@ -12,7 +12,7 @@ import {createPlaceholderBlock} from '../internal-utils/create-placeholder-block
12
12
  import {getBlockPath} from '../internal-utils/slate-utils'
13
13
  import {toSlateRange} from '../internal-utils/to-slate-range'
14
14
  import {getBlockKeyFromSelectionPoint} from '../selection/selection-point'
15
- import {PortableTextSlateEditor} from '../types/editor'
15
+ import type {PortableTextSlateEditor} from '../types/editor'
16
16
  import type {BehaviorOperationImplementation} from './behavior.operations'
17
17
 
18
18
  export const deleteOperationImplementation: BehaviorOperationImplementation<