@portabletext/editor 1.45.4 → 1.46.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.
Files changed (42) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs +20 -0
  2. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  3. package/lib/_chunks-cjs/behavior.markdown.cjs +25 -25
  4. package/lib/_chunks-cjs/behavior.markdown.cjs.map +1 -1
  5. package/lib/_chunks-cjs/editor-provider.cjs +37 -3
  6. package/lib/_chunks-cjs/editor-provider.cjs.map +1 -1
  7. package/lib/_chunks-es/behavior.core.js +20 -0
  8. package/lib/_chunks-es/behavior.core.js.map +1 -1
  9. package/lib/_chunks-es/behavior.markdown.js +26 -26
  10. package/lib/_chunks-es/behavior.markdown.js.map +1 -1
  11. package/lib/_chunks-es/editor-provider.js +37 -3
  12. package/lib/_chunks-es/editor-provider.js.map +1 -1
  13. package/lib/_chunks-es/selector.is-selecting-entire-blocks.js +1 -1
  14. package/lib/behaviors/index.cjs +37 -53
  15. package/lib/behaviors/index.cjs.map +1 -1
  16. package/lib/behaviors/index.d.cts +26 -1
  17. package/lib/behaviors/index.d.ts +26 -1
  18. package/lib/behaviors/index.js +38 -54
  19. package/lib/behaviors/index.js.map +1 -1
  20. package/lib/index.d.cts +7 -1
  21. package/lib/index.d.ts +7 -1
  22. package/lib/plugins/index.cjs +23 -29
  23. package/lib/plugins/index.cjs.map +1 -1
  24. package/lib/plugins/index.d.cts +7 -1
  25. package/lib/plugins/index.d.ts +7 -1
  26. package/lib/plugins/index.js +24 -30
  27. package/lib/plugins/index.js.map +1 -1
  28. package/lib/selectors/index.d.cts +7 -1
  29. package/lib/selectors/index.d.ts +7 -1
  30. package/lib/utils/index.d.cts +7 -1
  31. package/lib/utils/index.d.ts +7 -1
  32. package/package.json +1 -1
  33. package/src/behaviors/behavior.decorator-pair.ts +16 -19
  34. package/src/behaviors/behavior.emoji-picker.ts +26 -45
  35. package/src/behaviors/behavior.links.ts +5 -4
  36. package/src/behaviors/behavior.markdown.ts +37 -34
  37. package/src/behaviors/behavior.perform-event.ts +53 -2
  38. package/src/behaviors/behavior.types.action.ts +38 -7
  39. package/src/behaviors/index.ts +3 -0
  40. package/src/editor/editor-machine.ts +2 -2
  41. package/src/plugins/plugin.decorator-shortcut.ts +6 -8
  42. package/src/plugins/plugin.one-line.tsx +4 -4
@@ -3,7 +3,7 @@ import type {EditorSchema} from '../editor/define-schema'
3
3
  import * as selectors from '../selectors'
4
4
  import {spanSelectionPointToBlockOffset} from '../utils/util.block-offset'
5
5
  import {getTextBlockText} from '../utils/util.get-text-block-text'
6
- import {raise} from './behavior.types.action'
6
+ import {execute} from './behavior.types.action'
7
7
  import {defineBehavior} from './behavior.types.behavior'
8
8
 
9
9
  /**
@@ -120,23 +120,23 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
120
120
  },
121
121
  actions: [
122
122
  () => [
123
- {
123
+ execute({
124
124
  type: 'insert.text',
125
125
  text: ' ',
126
- },
126
+ }),
127
127
  ],
128
128
  (_, {focusTextBlock, style}) => [
129
- {
129
+ execute({
130
130
  type: 'block.unset',
131
131
  props: ['listItem', 'level'],
132
132
  at: focusTextBlock.path,
133
- },
134
- {
133
+ }),
134
+ execute({
135
135
  type: 'block.set',
136
136
  props: {style},
137
137
  at: focusTextBlock.path,
138
- },
139
- raise({
138
+ }),
139
+ execute({
140
140
  type: 'delete.text',
141
141
  at: {
142
142
  anchor: {
@@ -200,21 +200,21 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
200
200
  },
201
201
  actions: [
202
202
  (_, {hrCharacter}) => [
203
- {
203
+ execute({
204
204
  type: 'insert.text',
205
205
  text: hrCharacter,
206
- },
206
+ }),
207
207
  ],
208
208
  (_, {hrObject, hrBlockOffsets}) => [
209
- {
209
+ execute({
210
210
  type: 'insert.block',
211
211
  placement: 'before',
212
212
  block: {
213
213
  _type: hrObject.name,
214
214
  ...(hrObject.value ?? {}),
215
215
  },
216
- },
217
- raise({
216
+ }),
217
+ execute({
218
218
  type: 'delete.text',
219
219
  at: hrBlockOffsets,
220
220
  }),
@@ -238,41 +238,44 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
238
238
  },
239
239
  actions: [
240
240
  (_, {hrCharacters}) => [
241
- {
241
+ execute({
242
242
  type: 'insert.text',
243
243
  text: hrCharacters,
244
- },
244
+ }),
245
245
  ],
246
246
  ({snapshot}, {hrObject, focusBlock}) =>
247
247
  isPortableTextTextBlock(focusBlock.node)
248
248
  ? [
249
- {
249
+ execute({
250
250
  type: 'insert.block',
251
251
  block: {
252
252
  _type: snapshot.context.schema.block.name,
253
253
  children: focusBlock.node.children,
254
254
  },
255
255
  placement: 'after',
256
- },
257
- {
256
+ }),
257
+ execute({
258
258
  type: 'insert.block',
259
259
  block: {
260
260
  _type: hrObject.name,
261
261
  ...(hrObject.value ?? {}),
262
262
  },
263
263
  placement: 'after',
264
- },
265
- {type: 'delete.block', at: focusBlock.path},
264
+ }),
265
+ execute({
266
+ type: 'delete.block',
267
+ at: focusBlock.path,
268
+ }),
266
269
  ]
267
270
  : [
268
- {
271
+ execute({
269
272
  type: 'insert.block',
270
273
  block: {
271
274
  _type: hrObject.name,
272
275
  ...(hrObject.value ?? {}),
273
276
  },
274
277
  placement: 'after',
275
- },
278
+ }),
276
279
  ],
277
280
  ],
278
281
  })
@@ -337,19 +340,19 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
337
340
  return false
338
341
  },
339
342
  actions: [
340
- ({event}) => [event],
343
+ ({event}) => [execute(event)],
341
344
  (_, {focusTextBlock, style, level}) => [
342
- {
345
+ execute({
343
346
  type: 'block.unset',
344
347
  props: ['listItem', 'level'],
345
348
  at: focusTextBlock.path,
346
- },
347
- {
349
+ }),
350
+ execute({
348
351
  type: 'block.set',
349
352
  props: {style},
350
353
  at: focusTextBlock.path,
351
- },
352
- raise({
354
+ }),
355
+ execute({
353
356
  type: 'delete.text',
354
357
  at: {
355
358
  anchor: {
@@ -394,11 +397,11 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
394
397
  },
395
398
  actions: [
396
399
  (_, {defaultStyle, focusTextBlock}) => [
397
- {
400
+ execute({
398
401
  type: 'block.set',
399
402
  props: {style: defaultStyle},
400
403
  at: focusTextBlock.path,
401
- },
404
+ }),
402
405
  ],
403
406
  ],
404
407
  })
@@ -477,9 +480,9 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
477
480
  return false
478
481
  },
479
482
  actions: [
480
- ({event}) => [event],
483
+ ({event}) => [execute(event)],
481
484
  (_, {focusTextBlock, style, listItem, listItemLength}) => [
482
- {
485
+ execute({
483
486
  type: 'block.set',
484
487
  props: {
485
488
  listItem,
@@ -487,8 +490,8 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
487
490
  style,
488
491
  },
489
492
  at: focusTextBlock.path,
490
- },
491
- raise({
493
+ }),
494
+ execute({
492
495
  type: 'delete.text',
493
496
  at: {
494
497
  anchor: {
@@ -8,6 +8,7 @@ import {
8
8
  } from '../editor/with-applying-behavior-actions'
9
9
  import {debugWithName} from '../internal-utils/debug'
10
10
  import type {PortableTextSlateEditor} from '../types/editor'
11
+ import {defaultBehaviors} from './behavior.default'
11
12
  import type {InternalBehaviorAction} from './behavior.types.action'
12
13
  import {
13
14
  isAbstractBehaviorEvent,
@@ -28,6 +29,7 @@ function eventCategory(event: BehaviorEvent) {
28
29
  }
29
30
 
30
31
  export function performEvent({
32
+ mode,
31
33
  behaviors,
32
34
  event,
33
35
  editor,
@@ -37,6 +39,7 @@ export function performEvent({
37
39
  nativeEvent,
38
40
  defaultActionCallback,
39
41
  }: {
42
+ mode: 'raise' | 'execute'
40
43
  behaviors: Array<Behavior>
41
44
  event: BehaviorEvent
42
45
  editor: PortableTextSlateEditor
@@ -62,7 +65,9 @@ export function performEvent({
62
65
  editor,
63
66
  } satisfies InternalBehaviorAction)
64
67
 
65
- const eventBehaviors = behaviors.filter((behavior) => {
68
+ const eventBehaviors = (
69
+ mode === 'raise' ? [...behaviors, ...defaultBehaviors] : behaviors
70
+ ).filter((behavior) => {
66
71
  // Catches all events
67
72
  if (behavior.on === '*') {
68
73
  return true
@@ -179,7 +184,13 @@ export function performEvent({
179
184
  for (const action of actions) {
180
185
  if (action.type === 'raise') {
181
186
  performEvent({
182
- behaviors,
187
+ mode,
188
+ behaviors:
189
+ mode === 'execute'
190
+ ? isCustomBehaviorEvent(action.event)
191
+ ? [...behaviors, ...defaultBehaviors]
192
+ : defaultBehaviors
193
+ : [...behaviors, ...defaultBehaviors],
183
194
  event: action.event,
184
195
  editor,
185
196
  keyGenerator,
@@ -192,6 +203,46 @@ export function performEvent({
192
203
  continue
193
204
  }
194
205
 
206
+ if (action.type === 'execute') {
207
+ if (
208
+ isAbstractBehaviorEvent(action.event) ||
209
+ isCustomBehaviorEvent(action.event)
210
+ ) {
211
+ performEvent({
212
+ mode: 'execute',
213
+ behaviors: isCustomBehaviorEvent(action.event)
214
+ ? [...behaviors, ...defaultBehaviors]
215
+ : defaultBehaviors,
216
+ event: action.event,
217
+ editor,
218
+ keyGenerator,
219
+ schema,
220
+ getSnapshot,
221
+ defaultActionCallback: undefined,
222
+ nativeEvent: undefined,
223
+ })
224
+ } else {
225
+ try {
226
+ performAction({
227
+ context: {
228
+ keyGenerator,
229
+ schema,
230
+ },
231
+ action: {...action.event, editor},
232
+ })
233
+ } catch (error) {
234
+ console.error(
235
+ new Error(
236
+ `Performing action "${action.event.type}" as a result of "${event.type}" failed due to: ${error.message}`,
237
+ ),
238
+ )
239
+ break
240
+ }
241
+ }
242
+
243
+ continue
244
+ }
245
+
195
246
  const internalAction = {
196
247
  ...action,
197
248
  editor,
@@ -1,5 +1,5 @@
1
1
  import type {EditorSnapshot} from '../editor/editor-snapshot'
2
- import type {OmitFromUnion, PickFromUnion} from '../type-utils'
2
+ import type {PickFromUnion} from '../type-utils'
3
3
  import type {PortableTextSlateEditor} from '../types/editor'
4
4
  import type {
5
5
  AbstractBehaviorEvent,
@@ -11,7 +11,13 @@ import type {
11
11
  * @beta
12
12
  */
13
13
  export type BehaviorAction =
14
- | SyntheticBehaviorEvent
14
+ | {
15
+ type: 'execute'
16
+ event:
17
+ | AbstractBehaviorEvent
18
+ | SyntheticBehaviorEvent
19
+ | CustomBehaviorEvent
20
+ }
15
21
  | {
16
22
  type: 'raise'
17
23
  event:
@@ -27,6 +33,15 @@ export type BehaviorAction =
27
33
  effect: () => void
28
34
  }
29
35
 
36
+ /**
37
+ * @beta
38
+ */
39
+ export function execute(
40
+ event: AbstractBehaviorEvent | SyntheticBehaviorEvent | CustomBehaviorEvent,
41
+ ): PickFromUnion<BehaviorAction, 'type', 'execute'> {
42
+ return {type: 'execute', event}
43
+ }
44
+
30
45
  /**
31
46
  * @beta
32
47
  */
@@ -36,6 +51,22 @@ export function raise(
36
51
  return {type: 'raise', event}
37
52
  }
38
53
 
54
+ /**
55
+ * @beta
56
+ */
57
+ export function effect(
58
+ effect: () => void,
59
+ ): PickFromUnion<BehaviorAction, 'type', 'effect'> {
60
+ return {type: 'effect', effect}
61
+ }
62
+
63
+ /**
64
+ * @beta
65
+ */
66
+ export function noop(): PickFromUnion<BehaviorAction, 'type', 'noop'> {
67
+ return {type: 'noop'}
68
+ }
69
+
39
70
  /**
40
71
  * @beta
41
72
  */
@@ -47,10 +78,10 @@ export type BehaviorActionSet<TBehaviorEvent, TGuardResponse> = (
47
78
  guardResponse: TGuardResponse,
48
79
  ) => Array<BehaviorAction>
49
80
 
50
- export type InternalBehaviorAction = OmitFromUnion<
51
- BehaviorAction,
52
- 'type',
53
- 'raise'
54
- > & {
81
+ export type InternalBehaviorAction = (
82
+ | SyntheticBehaviorEvent
83
+ | {type: 'noop'}
84
+ | {type: 'effect'; effect: () => void}
85
+ ) & {
55
86
  editor: PortableTextSlateEditor
56
87
  }
@@ -14,7 +14,10 @@ export {
14
14
  } from './behavior.markdown'
15
15
 
16
16
  export {
17
+ execute,
18
+ noop,
17
19
  raise,
20
+ effect,
18
21
  type BehaviorAction,
19
22
  type BehaviorActionSet,
20
23
  } from './behavior.types.action'
@@ -10,7 +10,6 @@ import {
10
10
  type ActorRefFrom,
11
11
  } from 'xstate'
12
12
  import {coreBehaviors} from '../behaviors/behavior.core'
13
- import {defaultBehaviors} from '../behaviors/behavior.default'
14
13
  import {performEvent} from '../behaviors/behavior.perform-event'
15
14
  import type {Behavior} from '../behaviors/behavior.types.behavior'
16
15
  import type {BehaviorEvent} from '../behaviors/behavior.types.event'
@@ -297,7 +296,8 @@ export const editorMachine = setup({
297
296
  assertEvent(event, ['behavior event'])
298
297
 
299
298
  performEvent({
300
- behaviors: [...context.behaviors.values(), ...defaultBehaviors],
299
+ mode: 'raise',
300
+ behaviors: [...context.behaviors.values()],
301
301
  event: event.behaviorEvent,
302
302
  editor: event.editor,
303
303
  keyGenerator: context.keyGenerator,
@@ -8,6 +8,7 @@ import {
8
8
  type CallbackLogicFunction,
9
9
  } from 'xstate'
10
10
  import {createDecoratorPairBehavior} from '../behaviors/behavior.decorator-pair'
11
+ import {effect, execute} from '../behaviors/behavior.types.action'
11
12
  import {defineBehavior} from '../behaviors/behavior.types.behavior'
12
13
  import type {Editor} from '../editor/create-editor'
13
14
  import type {EditorSchema} from '../editor/define-schema'
@@ -132,15 +133,12 @@ const deleteBackwardListenerCallback: CallbackLogicFunction<
132
133
  on: 'delete.backward',
133
134
  actions: [
134
135
  () => [
135
- {
136
+ execute({
136
137
  type: 'history.undo',
137
- },
138
- {
139
- type: 'effect',
140
- effect: () => {
141
- sendBack({type: 'delete.backward'})
142
- },
143
- },
138
+ }),
139
+ effect(() => {
140
+ sendBack({type: 'delete.backward'})
141
+ }),
144
142
  ],
145
143
  ],
146
144
  }),
@@ -1,4 +1,4 @@
1
- import {defineBehavior, raise} from '../behaviors'
1
+ import {defineBehavior, execute, raise} from '../behaviors'
2
2
  import * as selectors from '../selectors'
3
3
  import * as utils from '../utils'
4
4
  import {BehaviorPlugin} from './plugin.behavior'
@@ -14,7 +14,7 @@ const oneLineBehaviors = [
14
14
  snapshot.context.selection && selectors.isSelectionExpanded(snapshot)
15
15
  ? {selection: snapshot.context.selection}
16
16
  : false,
17
- actions: [(_, {selection}) => [{type: 'delete', at: selection}]],
17
+ actions: [(_, {selection}) => [execute({type: 'delete', at: selection})]],
18
18
  }),
19
19
  /**
20
20
  * All other cases of `insert.break` should be aborted.
@@ -59,12 +59,12 @@ const oneLineBehaviors = [
59
59
  },
60
60
  actions: [
61
61
  ({event}) => [
62
- {
62
+ execute({
63
63
  type: 'insert.block',
64
64
  block: event.block,
65
65
  placement: 'auto',
66
66
  select: 'end',
67
- },
67
+ }),
68
68
  ],
69
69
  ],
70
70
  }),