@portabletext/editor 1.23.0 → 1.25.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 (71) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs +249 -62
  2. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  3. package/lib/_chunks-cjs/{selector.is-selection-collapsed.cjs → selector.is-active-style.cjs} +158 -3
  4. package/lib/_chunks-cjs/selector.is-active-style.cjs.map +1 -0
  5. package/lib/_chunks-cjs/util.slice-blocks.cjs +23 -9
  6. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
  7. package/lib/_chunks-es/behavior.core.js +225 -38
  8. package/lib/_chunks-es/behavior.core.js.map +1 -1
  9. package/lib/_chunks-es/{selector.is-selection-collapsed.js → selector.is-active-style.js} +159 -4
  10. package/lib/_chunks-es/selector.is-active-style.js.map +1 -0
  11. package/lib/_chunks-es/util.slice-blocks.js +23 -9
  12. package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
  13. package/lib/behaviors/index.cjs +27 -27
  14. package/lib/behaviors/index.cjs.map +1 -1
  15. package/lib/behaviors/index.d.cts +2830 -139
  16. package/lib/behaviors/index.d.ts +2830 -139
  17. package/lib/behaviors/index.js +1 -1
  18. package/lib/index.cjs +695 -526
  19. package/lib/index.cjs.map +1 -1
  20. package/lib/index.d.cts +8950 -246
  21. package/lib/index.d.ts +8950 -246
  22. package/lib/index.js +696 -525
  23. package/lib/index.js.map +1 -1
  24. package/lib/selectors/index.cjs +24 -171
  25. package/lib/selectors/index.cjs.map +1 -1
  26. package/lib/selectors/index.d.cts +73 -0
  27. package/lib/selectors/index.d.ts +73 -0
  28. package/lib/selectors/index.js +3 -151
  29. package/lib/selectors/index.js.map +1 -1
  30. package/package.json +11 -10
  31. package/src/behavior-actions/behavior.action.data-transfer-set.ts +7 -0
  32. package/src/behavior-actions/behavior.action.insert-blocks.ts +61 -0
  33. package/src/behavior-actions/behavior.actions.ts +159 -83
  34. package/src/behaviors/behavior.core.annotations.ts +29 -0
  35. package/src/behaviors/behavior.core.block-objects.ts +13 -13
  36. package/src/behaviors/behavior.core.decorators.ts +19 -0
  37. package/src/behaviors/behavior.core.deserialize.ts +46 -0
  38. package/src/behaviors/behavior.core.lists.ts +57 -23
  39. package/src/behaviors/behavior.core.serialize.ts +44 -0
  40. package/src/behaviors/behavior.core.style.ts +19 -0
  41. package/src/behaviors/behavior.core.ts +19 -0
  42. package/src/behaviors/behavior.types.ts +126 -89
  43. package/src/converters/converter.json.ts +53 -0
  44. package/src/converters/converter.portable-text.deserialize.test.ts +686 -0
  45. package/src/converters/converter.portable-text.ts +59 -0
  46. package/src/converters/converter.text-html.deserialize.test.ts +349 -0
  47. package/src/converters/converter.text-html.serialize.test.ts +233 -0
  48. package/src/converters/converter.text-html.ts +61 -0
  49. package/src/converters/converter.text-plain.test.ts +241 -0
  50. package/src/converters/converter.text-plain.ts +91 -0
  51. package/src/converters/converter.ts +65 -0
  52. package/src/converters/converters.ts +11 -0
  53. package/src/editor/Editable.tsx +3 -13
  54. package/src/editor/create-editor.ts +48 -6
  55. package/src/editor/editor-machine.ts +56 -2
  56. package/src/editor/editor-selector.ts +1 -0
  57. package/src/editor/editor-snapshot.ts +5 -0
  58. package/src/editor/plugins/create-with-event-listeners.ts +82 -106
  59. package/src/internal-utils/asserters.ts +9 -0
  60. package/src/internal-utils/mime-type.ts +1 -0
  61. package/src/internal-utils/parse-blocks.ts +136 -0
  62. package/src/internal-utils/test-key-generator.ts +9 -0
  63. package/src/selectors/selector.get-selected-spans.test.ts +1 -0
  64. package/src/selectors/selector.get-selection-text.test.ts +1 -0
  65. package/src/selectors/selector.is-active-decorator.test.ts +1 -0
  66. package/src/utils/util.slice-blocks.test.ts +87 -0
  67. package/src/utils/util.slice-blocks.ts +27 -10
  68. package/lib/_chunks-cjs/selector.is-selection-collapsed.cjs.map +0 -1
  69. package/lib/_chunks-es/selector.is-selection-collapsed.js.map +0 -1
  70. package/src/editor/plugins/__tests__/createWithInsertData.test.tsx +0 -181
  71. package/src/editor/plugins/createWithInsertData.ts +0 -425
@@ -1,7 +1,13 @@
1
- import type {KeyedSegment, PortableTextTextBlock} from '@sanity/types'
1
+ import type {
2
+ KeyedSegment,
3
+ PortableTextBlock,
4
+ PortableTextTextBlock,
5
+ } from '@sanity/types'
2
6
  import type {TextUnit} from 'slate'
3
7
  import type {TextInsertTextOptions} from 'slate/dist/interfaces/transforms/text'
8
+ import type {ConverterEvent} from '../converters/converter'
4
9
  import type {EditorContext} from '../editor/editor-snapshot'
10
+ import type {MIMEType} from '../internal-utils/mime-type'
5
11
  import type {OmitFromUnion, PickFromUnion} from '../type-utils'
6
12
  import type {EditorSelection, PortableTextSlateEditor} from '../types/editor'
7
13
 
@@ -22,9 +28,30 @@ export type SyntheticBehaviorEvent =
22
28
  name: string
23
29
  }
24
30
  }
31
+ | {
32
+ type: 'annotation.toggle'
33
+ annotation: {
34
+ name: string
35
+ value: {[prop: string]: unknown}
36
+ }
37
+ }
25
38
  | {
26
39
  type: 'blur'
27
40
  }
41
+ | {
42
+ type: 'data transfer.set'
43
+ data: string
44
+ dataTransfer: DataTransfer
45
+ mimeType: MIMEType
46
+ }
47
+ | {
48
+ type: 'decorator.add'
49
+ decorator: string
50
+ }
51
+ | {
52
+ type: 'decorator.remove'
53
+ decorator: string
54
+ }
28
55
  | {
29
56
  type: 'decorator.toggle'
30
57
  decorator: string
@@ -33,13 +60,26 @@ export type SyntheticBehaviorEvent =
33
60
  type: 'delete.backward'
34
61
  unit: TextUnit
35
62
  }
63
+ | {
64
+ type: 'delete.block'
65
+ blockPath: [KeyedSegment]
66
+ }
36
67
  | {
37
68
  type: 'delete.forward'
38
69
  unit: TextUnit
39
70
  }
71
+ | {
72
+ type: 'delete.text'
73
+ anchor: BlockOffset
74
+ focus: BlockOffset
75
+ }
40
76
  | {
41
77
  type: 'focus'
42
78
  }
79
+ | {
80
+ type: 'insert.blocks'
81
+ blocks: Array<PortableTextBlock>
82
+ }
43
83
  | {
44
84
  type: 'insert.block object'
45
85
  placement: 'auto' | 'after' | 'before'
@@ -61,23 +101,94 @@ export type SyntheticBehaviorEvent =
61
101
  | {
62
102
  type: 'insert.soft break'
63
103
  }
104
+ | {
105
+ type: 'insert.span'
106
+ text: string
107
+ annotations?: Array<{
108
+ name: string
109
+ value: {[prop: string]: unknown}
110
+ }>
111
+ decorators?: Array<string>
112
+ }
64
113
  | {
65
114
  type: 'insert.text'
66
115
  text: string
67
116
  options?: TextInsertTextOptions
68
117
  }
118
+ | {
119
+ type: 'insert.text block'
120
+ placement: 'auto' | 'after' | 'before'
121
+ textBlock?: {
122
+ children?: PortableTextTextBlock['children']
123
+ }
124
+ }
125
+ | {
126
+ type: 'list item.add'
127
+ listItem: string
128
+ }
129
+ | {
130
+ type: 'list item.remove'
131
+ listItem: string
132
+ }
69
133
  | {
70
134
  type: 'list item.toggle'
71
135
  listItem: string
72
136
  }
137
+ | {
138
+ type: 'move.block'
139
+ at: [KeyedSegment]
140
+ to: [KeyedSegment]
141
+ }
142
+ | {
143
+ type: 'move.block down'
144
+ at: [KeyedSegment]
145
+ }
146
+ | {
147
+ type: 'move.block up'
148
+ at: [KeyedSegment]
149
+ }
73
150
  | {
74
151
  type: 'select'
75
152
  selection: EditorSelection
76
153
  }
154
+ | {
155
+ type: 'select.previous block'
156
+ }
157
+ | {
158
+ type: 'select.next block'
159
+ }
160
+ | {
161
+ type: 'style.add'
162
+ style: string
163
+ }
164
+ | {
165
+ type: 'style.remove'
166
+ style: string
167
+ }
77
168
  | {
78
169
  type: 'style.toggle'
79
170
  style: string
80
171
  }
172
+ | {
173
+ type: 'text block.set'
174
+ at: [KeyedSegment]
175
+ level?: number
176
+ listItem?: string
177
+ style?: string
178
+ }
179
+ | {
180
+ type: 'text block.unset'
181
+ at: [KeyedSegment]
182
+ props: Array<'level' | 'listItem' | 'style'>
183
+ }
184
+ | (PickFromUnion<
185
+ ConverterEvent,
186
+ 'type',
187
+ | 'deserialization.failure'
188
+ | 'deserialization.success'
189
+ | 'serialization.failure'
190
+ | 'serialization.success'
191
+ > & {dataTransfer: DataTransfer})
81
192
 
82
193
  /**
83
194
  * @beta
@@ -87,6 +198,10 @@ export type NativeBehaviorEvent =
87
198
  type: 'copy'
88
199
  data: DataTransfer
89
200
  }
201
+ | {
202
+ type: 'deserialize'
203
+ dataTransfer: DataTransfer
204
+ }
90
205
  | {
91
206
  type: 'key.down'
92
207
  keyboardEvent: Pick<
@@ -105,6 +220,11 @@ export type NativeBehaviorEvent =
105
220
  type: 'paste'
106
221
  data: DataTransfer
107
222
  }
223
+ | {
224
+ type: 'serialize'
225
+ originEvent: 'copy' | 'cut' | 'unknown'
226
+ dataTransfer: DataTransfer
227
+ }
108
228
 
109
229
  /**
110
230
  * @beta
@@ -132,100 +252,13 @@ export type BehaviorActionIntend =
132
252
  type: 'raise'
133
253
  event: SyntheticBehaviorEvent | CustomBehaviorEvent
134
254
  }
135
- | {
136
- type: 'annotation.toggle'
137
- annotation: {
138
- name: string
139
- value: {[prop: string]: unknown}
140
- }
141
- }
142
- | {
143
- type: 'decorator.add'
144
- decorator: string
145
- }
146
- | {
147
- type: 'decorator.remove'
148
- decorator: string
149
- }
150
- | {
151
- type: 'insert.span'
152
- text: string
153
- annotations?: Array<{
154
- name: string
155
- value: {[prop: string]: unknown}
156
- }>
157
- decorators?: Array<string>
158
- }
159
- | {
160
- type: 'insert.text block'
161
- placement: 'auto' | 'after' | 'before'
162
- textBlock?: {
163
- children?: PortableTextTextBlock['children']
164
- }
165
- }
166
- | {
167
- type: 'list item.add'
168
- listItem: string
169
- }
170
- | {
171
- type: 'list item.remove'
172
- listItem: string
173
- }
174
- | {
175
- type: 'move.block'
176
- at: [KeyedSegment]
177
- to: [KeyedSegment]
178
- }
179
- | {
180
- type: 'move.block down'
181
- at: [KeyedSegment]
182
- }
183
- | {
184
- type: 'move.block up'
185
- at: [KeyedSegment]
186
- }
187
255
  | {
188
256
  type: 'noop'
189
257
  }
190
- | {
191
- type: 'delete.block'
192
- blockPath: [KeyedSegment]
193
- }
194
- | {
195
- type: 'delete.text'
196
- anchor: BlockOffset
197
- focus: BlockOffset
198
- }
199
258
  | {
200
259
  type: 'effect'
201
260
  effect: () => void
202
261
  }
203
- | {
204
- type: 'select.previous block'
205
- }
206
- | {
207
- type: 'select.next block'
208
- }
209
- | {
210
- type: 'style.add'
211
- style: string
212
- }
213
- | {
214
- type: 'style.remove'
215
- style: string
216
- }
217
- | {
218
- type: 'text block.set'
219
- at: [KeyedSegment]
220
- level?: number
221
- listItem?: string
222
- style?: string
223
- }
224
- | {
225
- type: 'text block.unset'
226
- at: [KeyedSegment]
227
- props: Array<'level' | 'listItem' | 'style'>
228
- }
229
262
 
230
263
  /**
231
264
  * @beta
@@ -261,7 +294,11 @@ export type BehaviorEvent =
261
294
  export type Behavior<
262
295
  TBehaviorEventType extends BehaviorEvent['type'] = BehaviorEvent['type'],
263
296
  TGuardResponse = true,
264
- TBehaviorEvent extends BehaviorEvent = BehaviorEvent,
297
+ TBehaviorEvent extends BehaviorEvent = PickFromUnion<
298
+ BehaviorEvent,
299
+ 'type',
300
+ TBehaviorEventType
301
+ >,
265
302
  > = {
266
303
  /**
267
304
  * The internal editor event that triggers this behavior.
@@ -0,0 +1,53 @@
1
+ import type {Converter} from './converter'
2
+
3
+ export const converterJson: Converter<'application/json'> = {
4
+ serialize: ({context, event}) => {
5
+ const portableTextConverter = context.converters.find(
6
+ (converter) => converter.mimeType === 'application/x-portable-text',
7
+ )
8
+
9
+ if (!portableTextConverter) {
10
+ return {
11
+ type: 'serialization.failure',
12
+ mimeType: 'application/json',
13
+ originEvent: event.originEvent,
14
+ reason: 'No application/x-portable-text Converter found',
15
+ }
16
+ }
17
+
18
+ const serializationEvent = portableTextConverter.serialize({
19
+ context,
20
+ event,
21
+ })
22
+
23
+ return {
24
+ ...serializationEvent,
25
+ mimeType: 'application/json',
26
+ originEvent: event.originEvent,
27
+ }
28
+ },
29
+ deserialize: ({context, event}) => {
30
+ const portableTextConverter = context.converters.find(
31
+ (converter) => converter.mimeType === 'application/x-portable-text',
32
+ )
33
+
34
+ if (!portableTextConverter) {
35
+ return {
36
+ type: 'deserialization.failure',
37
+ mimeType: 'application/json',
38
+ reason: 'No application/x-portable-text Converter found',
39
+ }
40
+ }
41
+
42
+ const deserializationEvent = portableTextConverter.deserialize({
43
+ context,
44
+ event,
45
+ })
46
+
47
+ return {
48
+ ...deserializationEvent,
49
+ mimeType: 'application/json',
50
+ }
51
+ },
52
+ mimeType: 'application/json',
53
+ }