@portabletext/editor 1.34.1 → 1.35.1

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 (131) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs +57 -118
  2. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  3. package/lib/_chunks-cjs/behavior.markdown.cjs +27 -67
  4. package/lib/_chunks-cjs/behavior.markdown.cjs.map +1 -1
  5. package/lib/_chunks-cjs/{plugin.event-listener.cjs → editor-provider.cjs} +101 -87
  6. package/lib/_chunks-cjs/editor-provider.cjs.map +1 -0
  7. package/lib/_chunks-cjs/selector.get-text-before.cjs +5 -7
  8. package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
  9. package/lib/_chunks-cjs/selector.is-active-style.cjs +22 -36
  10. package/lib/_chunks-cjs/selector.is-active-style.cjs.map +1 -1
  11. package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs +68 -153
  12. package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs.map +1 -1
  13. package/lib/_chunks-cjs/util.block-offsets-to-selection.cjs.map +1 -1
  14. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
  15. package/lib/_chunks-es/behavior.core.js +57 -118
  16. package/lib/_chunks-es/behavior.core.js.map +1 -1
  17. package/lib/_chunks-es/behavior.markdown.js +27 -67
  18. package/lib/_chunks-es/behavior.markdown.js.map +1 -1
  19. package/lib/_chunks-es/{plugin.event-listener.js → editor-provider.js} +102 -88
  20. package/lib/_chunks-es/editor-provider.js.map +1 -0
  21. package/lib/_chunks-es/selector.get-text-before.js +5 -7
  22. package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
  23. package/lib/_chunks-es/selector.is-active-style.js +22 -36
  24. package/lib/_chunks-es/selector.is-active-style.js.map +1 -1
  25. package/lib/_chunks-es/selector.is-at-the-start-of-block.js +68 -153
  26. package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +1 -1
  27. package/lib/_chunks-es/util.block-offsets-to-selection.js.map +1 -1
  28. package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
  29. package/lib/behaviors/index.cjs +18 -48
  30. package/lib/behaviors/index.cjs.map +1 -1
  31. package/lib/behaviors/index.d.cts +19392 -214
  32. package/lib/behaviors/index.d.ts +19392 -214
  33. package/lib/behaviors/index.js +18 -48
  34. package/lib/behaviors/index.js.map +1 -1
  35. package/lib/index.cjs +81 -51
  36. package/lib/index.cjs.map +1 -1
  37. package/lib/index.d.cts +334 -59
  38. package/lib/index.d.ts +334 -59
  39. package/lib/index.js +35 -4
  40. package/lib/index.js.map +1 -1
  41. package/lib/plugins/index.cjs +200 -189
  42. package/lib/plugins/index.cjs.map +1 -1
  43. package/lib/plugins/index.d.cts +344 -25
  44. package/lib/plugins/index.d.ts +344 -25
  45. package/lib/plugins/index.js +198 -187
  46. package/lib/plugins/index.js.map +1 -1
  47. package/lib/selectors/index.cjs +22 -50
  48. package/lib/selectors/index.cjs.map +1 -1
  49. package/lib/selectors/index.d.cts +19485 -174
  50. package/lib/selectors/index.d.ts +19485 -174
  51. package/lib/selectors/index.js +22 -50
  52. package/lib/selectors/index.js.map +1 -1
  53. package/lib/utils/index.cjs.map +1 -1
  54. package/lib/utils/index.d.cts +19518 -7
  55. package/lib/utils/index.d.ts +19518 -7
  56. package/lib/utils/index.js.map +1 -1
  57. package/package.json +7 -7
  58. package/src/behavior-actions/behavior.action.decorator.add.ts +1 -0
  59. package/src/behavior-actions/behavior.action.delete.text.ts +1 -0
  60. package/src/behaviors/behavior.code-editor.ts +6 -6
  61. package/src/behaviors/behavior.core.annotations.ts +5 -4
  62. package/src/behaviors/behavior.core.block-objects.ts +17 -17
  63. package/src/behaviors/behavior.core.decorators.ts +12 -8
  64. package/src/behaviors/behavior.core.insert-break.ts +27 -29
  65. package/src/behaviors/behavior.core.lists.ts +19 -19
  66. package/src/behaviors/behavior.decorator-pair.ts +201 -0
  67. package/src/behaviors/behavior.default.ts +35 -30
  68. package/src/behaviors/behavior.emoji-picker.ts +12 -12
  69. package/src/behaviors/behavior.links.ts +7 -7
  70. package/src/behaviors/behavior.markdown.ts +41 -42
  71. package/src/behaviors/behavior.types.ts +14 -17
  72. package/src/behaviors/index.ts +0 -1
  73. package/src/converters/converter.json.ts +6 -6
  74. package/src/converters/converter.portable-text.deserialize.test.ts +27 -29
  75. package/src/converters/converter.portable-text.ts +13 -7
  76. package/src/converters/converter.text-html.deserialize.test.ts +16 -18
  77. package/src/converters/converter.text-html.serialize.test.ts +56 -57
  78. package/src/converters/converter.text-html.ts +14 -10
  79. package/src/converters/converter.text-plain.test.ts +17 -17
  80. package/src/converters/converter.text-plain.ts +15 -11
  81. package/src/converters/converter.types.ts +5 -5
  82. package/src/editor/Editable.tsx +26 -0
  83. package/src/editor/editor-machine.ts +170 -142
  84. package/src/editor/editor-selector.ts +3 -0
  85. package/src/editor/editor-snapshot.ts +13 -0
  86. package/src/editor-event-listener.tsx +30 -0
  87. package/src/index.ts +3 -3
  88. package/src/internal-utils/create-test-snapshot.ts +23 -0
  89. package/src/internal-utils/get-text-to-emphasize.ts +29 -7
  90. package/src/plugins/plugin.decorator-shortcut.ts +235 -0
  91. package/src/plugins/plugin.markdown.tsx +56 -8
  92. package/src/plugins/plugin.one-line.tsx +17 -17
  93. package/src/selectors/selector.get-active-annotations.test.ts +4 -13
  94. package/src/selectors/selector.get-active-list-item.ts +4 -4
  95. package/src/selectors/selector.get-active-style.ts +6 -6
  96. package/src/selectors/selector.get-anchor-block.ts +5 -5
  97. package/src/selectors/selector.get-anchor-child.ts +5 -5
  98. package/src/selectors/selector.get-anchor-span.ts +2 -2
  99. package/src/selectors/selector.get-anchor-text-block.ts +2 -2
  100. package/src/selectors/selector.get-block-offsets.ts +8 -7
  101. package/src/selectors/selector.get-caret-word-selection.test.ts +3 -7
  102. package/src/selectors/selector.get-caret-word-selection.ts +19 -16
  103. package/src/selectors/selector.get-next-inline-object.ts +4 -4
  104. package/src/selectors/selector.get-previous-inline-object.ts +4 -4
  105. package/src/selectors/selector.get-selected-slice.ts +7 -4
  106. package/src/selectors/selector.get-selected-spans.test.ts +5 -9
  107. package/src/selectors/selector.get-selected-spans.ts +9 -9
  108. package/src/selectors/selector.get-selection-end-point.ts +5 -5
  109. package/src/selectors/selector.get-selection-start-point.ts +5 -5
  110. package/src/selectors/selector.get-selection-text.test.ts +5 -7
  111. package/src/selectors/selector.get-selection-text.ts +2 -2
  112. package/src/selectors/selector.get-selection.ts +2 -2
  113. package/src/selectors/selector.get-text-before.ts +8 -8
  114. package/src/selectors/selector.get-trimmed-selection.test.ts +3 -5
  115. package/src/selectors/selector.get-trimmed-selection.ts +15 -13
  116. package/src/selectors/selector.get-value.ts +4 -4
  117. package/src/selectors/selector.is-active-decorator.test.ts +5 -9
  118. package/src/selectors/selector.is-at-the-end-of-block.ts +6 -3
  119. package/src/selectors/selector.is-at-the-start-of-block.ts +3 -3
  120. package/src/selectors/selector.is-overlapping-selection.ts +8 -6
  121. package/src/selectors/selector.is-selection-collapsed.ts +6 -5
  122. package/src/selectors/selector.is-selection-expanded.ts +2 -2
  123. package/src/selectors/selectors.ts +59 -59
  124. package/src/types/block-offset.ts +9 -0
  125. package/src/utils/index.ts +0 -1
  126. package/src/utils/util.block-offset.ts +1 -1
  127. package/src/utils/util.block-offsets-to-selection.ts +1 -1
  128. package/src/utils/util.child-selection-point-to-block-offset.ts +1 -1
  129. package/lib/_chunks-cjs/plugin.event-listener.cjs.map +0 -1
  130. package/lib/_chunks-es/plugin.event-listener.js.map +0 -1
  131. package/src/behaviors/behavior.markdown-emphasis.ts +0 -437
@@ -0,0 +1,235 @@
1
+ import {useActorRef} from '@xstate/react'
2
+ import {isEqual} from 'lodash'
3
+ import {
4
+ assign,
5
+ fromCallback,
6
+ setup,
7
+ type AnyEventObject,
8
+ type CallbackLogicFunction,
9
+ } from 'xstate'
10
+ import {createDecoratorPairBehavior} from '../behaviors/behavior.decorator-pair'
11
+ import {defineBehavior} from '../behaviors/behavior.types'
12
+ import type {Editor} from '../editor/create-editor'
13
+ import {useEditor} from '../editor/editor-provider'
14
+ import type {EditorSchema} from '../selectors'
15
+ import type {BlockOffset} from '../types/block-offset'
16
+ import * as utils from '../utils'
17
+
18
+ export function DecoratorShortcutPlugin(config: {
19
+ decorator: ({schema}: {schema: EditorSchema}) => string | undefined
20
+ pair: {char: string; amount: number}
21
+ }) {
22
+ const editor = useEditor()
23
+
24
+ useActorRef(decoratorPairMachine, {
25
+ input: {
26
+ editor,
27
+ decorator: config.decorator,
28
+ pair: config.pair,
29
+ },
30
+ })
31
+
32
+ return null
33
+ }
34
+
35
+ type MarkdownEmphasisEvent =
36
+ | {
37
+ type: 'emphasis.add'
38
+ blockOffset: BlockOffset
39
+ }
40
+ | {
41
+ type: 'selection'
42
+ blockOffsets?: {
43
+ anchor: BlockOffset
44
+ focus: BlockOffset
45
+ }
46
+ }
47
+ | {
48
+ type: 'delete.backward'
49
+ }
50
+
51
+ const emphasisListener: CallbackLogicFunction<
52
+ AnyEventObject,
53
+ MarkdownEmphasisEvent,
54
+ {
55
+ decorator: ({schema}: {schema: EditorSchema}) => string | undefined
56
+ editor: Editor
57
+ pair: {char: string; amount: number}
58
+ }
59
+ > = ({sendBack, input}) => {
60
+ const unregister = input.editor.registerBehavior({
61
+ behavior: createDecoratorPairBehavior({
62
+ decorator: input.decorator,
63
+ pair: input.pair,
64
+ onDecorate: (offset) => {
65
+ sendBack({type: 'emphasis.add', blockOffset: offset})
66
+ },
67
+ }),
68
+ })
69
+
70
+ return unregister
71
+ }
72
+
73
+ const selectionListenerCallback: CallbackLogicFunction<
74
+ AnyEventObject,
75
+ MarkdownEmphasisEvent,
76
+ {editor: Editor}
77
+ > = ({sendBack, input}) => {
78
+ const unregister = input.editor.registerBehavior({
79
+ behavior: defineBehavior({
80
+ on: 'select',
81
+ guard: ({snapshot, event}) => {
82
+ if (!event.selection) {
83
+ return {blockOffsets: undefined}
84
+ }
85
+
86
+ const anchor = utils.spanSelectionPointToBlockOffset({
87
+ value: snapshot.context.value,
88
+ selectionPoint: event.selection.anchor,
89
+ })
90
+ const focus = utils.spanSelectionPointToBlockOffset({
91
+ value: snapshot.context.value,
92
+ selectionPoint: event.selection.focus,
93
+ })
94
+
95
+ if (!anchor || !focus) {
96
+ return {blockOffsets: undefined}
97
+ }
98
+
99
+ return {
100
+ blockOffsets: {
101
+ anchor,
102
+ focus,
103
+ },
104
+ }
105
+ },
106
+ actions: [
107
+ (_, {blockOffsets}) => [
108
+ {
109
+ type: 'effect',
110
+ effect: () => {
111
+ sendBack({type: 'selection', blockOffsets})
112
+ },
113
+ },
114
+ ],
115
+ ],
116
+ }),
117
+ })
118
+
119
+ return unregister
120
+ }
121
+
122
+ const deleteBackwardListenerCallback: CallbackLogicFunction<
123
+ AnyEventObject,
124
+ MarkdownEmphasisEvent,
125
+ {editor: Editor}
126
+ > = ({sendBack, input}) => {
127
+ const unregister = input.editor.registerBehavior({
128
+ behavior: defineBehavior({
129
+ on: 'delete.backward',
130
+ actions: [
131
+ () => [
132
+ {
133
+ type: 'history.undo',
134
+ },
135
+ {
136
+ type: 'effect',
137
+ effect: () => {
138
+ sendBack({type: 'delete.backward'})
139
+ },
140
+ },
141
+ ],
142
+ ],
143
+ }),
144
+ })
145
+
146
+ return unregister
147
+ }
148
+
149
+ const decoratorPairMachine = setup({
150
+ types: {
151
+ context: {} as {
152
+ decorator: ({schema}: {schema: EditorSchema}) => string | undefined
153
+ editor: Editor
154
+ offsetAfterEmphasis?: BlockOffset
155
+ pair: {char: string; amount: number}
156
+ },
157
+ input: {} as {
158
+ decorator: ({schema}: {schema: EditorSchema}) => string | undefined
159
+ editor: Editor
160
+ pair: {char: string; amount: number}
161
+ },
162
+ events: {} as MarkdownEmphasisEvent,
163
+ },
164
+ actors: {
165
+ 'emphasis listener': fromCallback(emphasisListener),
166
+ 'delete.backward listener': fromCallback(deleteBackwardListenerCallback),
167
+ 'selection listener': fromCallback(selectionListenerCallback),
168
+ },
169
+ }).createMachine({
170
+ id: 'decorator pair',
171
+ context: ({input}) => ({
172
+ decorator: input.decorator,
173
+ editor: input.editor,
174
+ pair: input.pair,
175
+ }),
176
+ initial: 'idle',
177
+ states: {
178
+ 'idle': {
179
+ invoke: [
180
+ {
181
+ src: 'emphasis listener',
182
+ input: ({context}) => ({
183
+ decorator: context.decorator,
184
+ editor: context.editor,
185
+ pair: context.pair,
186
+ }),
187
+ },
188
+ ],
189
+ on: {
190
+ 'emphasis.add': {
191
+ target: 'emphasis added',
192
+ actions: assign({
193
+ offsetAfterEmphasis: ({event}) => event.blockOffset,
194
+ }),
195
+ },
196
+ },
197
+ },
198
+ 'emphasis added': {
199
+ exit: [
200
+ assign({
201
+ offsetAfterEmphasis: undefined,
202
+ }),
203
+ ],
204
+ invoke: [
205
+ {
206
+ src: 'selection listener',
207
+ input: ({context}) => ({editor: context.editor}),
208
+ },
209
+ {
210
+ src: 'delete.backward listener',
211
+ input: ({context}) => ({editor: context.editor}),
212
+ },
213
+ ],
214
+ on: {
215
+ 'selection': {
216
+ target: 'idle',
217
+ guard: ({context, event}) => {
218
+ const selectionChanged = !isEqual(
219
+ {
220
+ anchor: context.offsetAfterEmphasis,
221
+ focus: context.offsetAfterEmphasis,
222
+ },
223
+ event.blockOffsets,
224
+ )
225
+
226
+ return selectionChanged
227
+ },
228
+ },
229
+ 'delete.backward': {
230
+ target: 'idle',
231
+ },
232
+ },
233
+ },
234
+ },
235
+ })
@@ -3,17 +3,23 @@ import {
3
3
  createMarkdownBehaviors,
4
4
  type MarkdownBehaviorsConfig,
5
5
  } from '../behaviors/behavior.markdown'
6
- import {
7
- useMarkdownEmphasisBehaviors,
8
- type MarkdownEmphasisBehaviorsConfig,
9
- } from '../behaviors/behavior.markdown-emphasis'
6
+ import type {EditorSchema} from '../editor/define-schema'
10
7
  import {useEditor} from '../editor/editor-provider'
8
+ import {DecoratorShortcutPlugin} from './plugin.decorator-shortcut'
11
9
 
12
10
  /**
13
11
  * @beta
14
12
  */
15
- export type MarkdownPluginConfig = MarkdownBehaviorsConfig &
16
- MarkdownEmphasisBehaviorsConfig
13
+ export type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
14
+ boldDecorator?: ({schema}: {schema: EditorSchema}) => string | undefined
15
+ codeDecorator?: ({schema}: {schema: EditorSchema}) => string | undefined
16
+ italicDecorator?: ({schema}: {schema: EditorSchema}) => string | undefined
17
+ strikeThroughDecorator?: ({
18
+ schema,
19
+ }: {
20
+ schema: EditorSchema
21
+ }) => string | undefined
22
+ }
17
23
 
18
24
  /**
19
25
  * @beta
@@ -32,8 +38,12 @@ export type MarkdownPluginConfig = MarkdownBehaviorsConfig &
32
38
  * config={{
33
39
  * boldDecorator: ({schema}) =>
34
40
  * schema.decorators.find((decorator) => decorator.value === 'strong')?.value,
41
+ * codeDecorator: ({schema}) =>
42
+ * schema.decorators.find((decorator) => decorator.value === 'code')?.value,
35
43
  * italicDecorator: ({schema}) =>
36
44
  * schema.decorators.find((decorator) => decorator.value === 'em')?.value,
45
+ * strikeThroughDecorator: ({schema}) =>
46
+ * schema.decorators.find((decorator) => decorator.value === 'strike-through')?.value,
37
47
  * horizontalRuleObject: ({schema}) => {
38
48
  * const name = schema.blockObjects.find(
39
49
  * (object) => object.name === 'break',
@@ -60,7 +70,6 @@ export type MarkdownPluginConfig = MarkdownBehaviorsConfig &
60
70
  */
61
71
  export function MarkdownPlugin(props: {config: MarkdownPluginConfig}) {
62
72
  const editor = useEditor()
63
- useMarkdownEmphasisBehaviors({config: props.config})
64
73
 
65
74
  useEffect(() => {
66
75
  const behaviors = createMarkdownBehaviors(props.config)
@@ -76,5 +85,44 @@ export function MarkdownPlugin(props: {config: MarkdownPluginConfig}) {
76
85
  }
77
86
  }, [editor, props.config])
78
87
 
79
- return null
88
+ return (
89
+ <>
90
+ {props.config.boldDecorator ? (
91
+ <>
92
+ <DecoratorShortcutPlugin
93
+ decorator={props.config.boldDecorator}
94
+ pair={{char: '*', amount: 2}}
95
+ />
96
+ <DecoratorShortcutPlugin
97
+ decorator={props.config.boldDecorator}
98
+ pair={{char: '_', amount: 2}}
99
+ />
100
+ </>
101
+ ) : null}
102
+ {props.config.codeDecorator ? (
103
+ <DecoratorShortcutPlugin
104
+ decorator={props.config.codeDecorator}
105
+ pair={{char: '`', amount: 1}}
106
+ />
107
+ ) : null}
108
+ {props.config.italicDecorator ? (
109
+ <>
110
+ <DecoratorShortcutPlugin
111
+ decorator={props.config.italicDecorator}
112
+ pair={{char: '*', amount: 1}}
113
+ />
114
+ <DecoratorShortcutPlugin
115
+ decorator={props.config.italicDecorator}
116
+ pair={{char: '_', amount: 1}}
117
+ />
118
+ </>
119
+ ) : null}
120
+ {props.config.strikeThroughDecorator ? (
121
+ <DecoratorShortcutPlugin
122
+ decorator={props.config.strikeThroughDecorator}
123
+ pair={{char: '~', amount: 2}}
124
+ />
125
+ ) : null}
126
+ </>
127
+ )
80
128
  }
@@ -10,9 +10,9 @@ const oneLineBehaviors = [
10
10
  */
11
11
  defineBehavior({
12
12
  on: 'insert.break',
13
- guard: ({context}) =>
14
- context.selection && selectors.isSelectionExpanded({context})
15
- ? {selection: context.selection}
13
+ guard: ({snapshot}) =>
14
+ snapshot.context.selection && selectors.isSelectionExpanded(snapshot)
15
+ ? {selection: snapshot.context.selection}
16
16
  : false,
17
17
  actions: [(_, {selection}) => [{type: 'delete', selection}]],
18
18
  }),
@@ -40,14 +40,14 @@ const oneLineBehaviors = [
40
40
  */
41
41
  defineBehavior({
42
42
  on: 'insert.block',
43
- guard: ({context, event}) => {
44
- const focusTextBlock = selectors.getFocusTextBlock({context})
45
- const selectionStartPoint = selectors.getSelectionStartPoint({context})
46
- const selectionEndPoint = selectors.getSelectionEndPoint({context})
43
+ guard: ({snapshot, event}) => {
44
+ const focusTextBlock = selectors.getFocusTextBlock(snapshot)
45
+ const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)
46
+ const selectionEndPoint = selectors.getSelectionEndPoint(snapshot)
47
47
 
48
48
  if (
49
49
  !focusTextBlock ||
50
- !utils.isTextBlock(context, event.block) ||
50
+ !utils.isTextBlock(snapshot.context, event.block) ||
51
51
  !selectionStartPoint ||
52
52
  !selectionEndPoint
53
53
  ) {
@@ -90,14 +90,14 @@ const oneLineBehaviors = [
90
90
  */
91
91
  defineBehavior({
92
92
  on: 'insert.block',
93
- guard: ({context, event}) => {
94
- const focusTextBlock = selectors.getFocusTextBlock({context})
95
- const selectionStartPoint = selectors.getSelectionStartPoint({context})
96
- const selectionEndPoint = selectors.getSelectionEndPoint({context})
93
+ guard: ({snapshot, event}) => {
94
+ const focusTextBlock = selectors.getFocusTextBlock(snapshot)
95
+ const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)
96
+ const selectionEndPoint = selectors.getSelectionEndPoint(snapshot)
97
97
 
98
98
  if (
99
99
  !focusTextBlock ||
100
- !utils.isTextBlock(context, event.block) ||
100
+ !utils.isTextBlock(snapshot.context, event.block) ||
101
101
  !selectionStartPoint ||
102
102
  !selectionEndPoint
103
103
  ) {
@@ -105,12 +105,12 @@ const oneLineBehaviors = [
105
105
  }
106
106
 
107
107
  const blockBeforeStartPoint = utils.splitTextBlock({
108
- context,
108
+ context: snapshot.context,
109
109
  block: focusTextBlock.node,
110
110
  point: selectionStartPoint,
111
111
  })?.before
112
112
  const blockAfterEndPoint = utils.splitTextBlock({
113
- context,
113
+ context: snapshot.context,
114
114
  block: focusTextBlock.node,
115
115
  point: selectionEndPoint,
116
116
  })?.after
@@ -120,7 +120,7 @@ const oneLineBehaviors = [
120
120
  }
121
121
 
122
122
  const targetBlock = utils.mergeTextBlocks({
123
- context,
123
+ context: snapshot.context,
124
124
  targetBlock: blockBeforeStartPoint,
125
125
  incomingBlock: event.block,
126
126
  })
@@ -131,7 +131,7 @@ const oneLineBehaviors = [
131
131
  })
132
132
 
133
133
  const mergedBlock = utils.mergeTextBlocks({
134
- context,
134
+ context: snapshot.context,
135
135
  targetBlock,
136
136
  incomingBlock: blockAfterEndPoint,
137
137
  })
@@ -1,25 +1,16 @@
1
1
  import type {PortableTextBlock} from '@sanity/types'
2
2
  import {expect, test} from 'vitest'
3
- import type {EditorSchema} from '../editor/define-schema'
4
- import type {EditorSnapshot} from '../editor/editor-snapshot'
5
- import {createTestKeyGenerator} from '../internal-utils/test-key-generator'
3
+ import {createTestSnapshot} from '../internal-utils/create-test-snapshot'
6
4
  import type {EditorSelection} from '../utils'
7
5
  import {getActiveAnnotations} from './selector.get-active-annotations'
8
6
 
9
- function snapshot(
10
- value: Array<PortableTextBlock>,
11
- selection: EditorSelection,
12
- ): EditorSnapshot {
13
- return {
7
+ function snapshot(value: Array<PortableTextBlock>, selection: EditorSelection) {
8
+ return createTestSnapshot({
14
9
  context: {
15
- converters: [],
16
- schema: {} as EditorSchema,
17
- keyGenerator: createTestKeyGenerator(),
18
- activeDecorators: [],
19
10
  value,
20
11
  selection,
21
12
  },
22
- }
13
+ })
23
14
  }
24
15
 
25
16
  const link = {
@@ -8,13 +8,13 @@ import {getSelectedBlocks} from './selectors'
8
8
  */
9
9
  export const getActiveListItem: EditorSelector<
10
10
  PortableTextListBlock['listItem'] | undefined
11
- > = ({context}) => {
12
- if (!context.selection) {
11
+ > = (snapshot) => {
12
+ if (!snapshot.context.selection) {
13
13
  return undefined
14
14
  }
15
15
 
16
- const guards = createGuards(context)
17
- const selectedBlocks = getSelectedBlocks({context}).map((block) => block.node)
16
+ const guards = createGuards(snapshot.context)
17
+ const selectedBlocks = getSelectedBlocks(snapshot).map((block) => block.node)
18
18
  const selectedTextBlocks = selectedBlocks.filter(guards.isTextBlock)
19
19
 
20
20
  const firstTextBlock = selectedTextBlocks.at(0)
@@ -6,15 +6,15 @@ import {getSelectedBlocks} from './selectors'
6
6
  /**
7
7
  * @public
8
8
  */
9
- export const getActiveStyle: EditorSelector<PortableTextTextBlock['style']> = ({
10
- context,
11
- }) => {
12
- if (!context.selection) {
9
+ export const getActiveStyle: EditorSelector<PortableTextTextBlock['style']> = (
10
+ snapshot,
11
+ ) => {
12
+ if (!snapshot.context.selection) {
13
13
  return undefined
14
14
  }
15
15
 
16
- const guards = createGuards(context)
17
- const selectedBlocks = getSelectedBlocks({context}).map((block) => block.node)
16
+ const guards = createGuards(snapshot.context)
17
+ const selectedBlocks = getSelectedBlocks(snapshot).map((block) => block.node)
18
18
  const selectedTextBlocks = selectedBlocks.filter(guards.isTextBlock)
19
19
 
20
20
  const firstTextBlock = selectedTextBlocks.at(0)
@@ -7,15 +7,15 @@ import {isKeyedSegment} from '../utils'
7
7
  */
8
8
  export const getAnchorBlock: EditorSelector<
9
9
  {node: PortableTextBlock; path: [KeyedSegment]} | undefined
10
- > = ({context}) => {
11
- const key = context.selection
12
- ? isKeyedSegment(context.selection.anchor.path[0])
13
- ? context.selection.anchor.path[0]._key
10
+ > = (snapshot) => {
11
+ const key = snapshot.context.selection
12
+ ? isKeyedSegment(snapshot.context.selection.anchor.path[0])
13
+ ? snapshot.context.selection.anchor.path[0]._key
14
14
  : undefined
15
15
  : undefined
16
16
 
17
17
  const node = key
18
- ? context.value.find((block) => block._key === key)
18
+ ? snapshot.context.value.find((block) => block._key === key)
19
19
  : undefined
20
20
 
21
21
  return node && key ? {node, path: [{_key: key}]} : undefined
@@ -13,16 +13,16 @@ export const getAnchorChild: EditorSelector<
13
13
  path: [KeyedSegment, 'children', KeyedSegment]
14
14
  }
15
15
  | undefined
16
- > = ({context}) => {
17
- const anchorBlock = getAnchorTextBlock({context})
16
+ > = (snapshot) => {
17
+ const anchorBlock = getAnchorTextBlock(snapshot)
18
18
 
19
19
  if (!anchorBlock) {
20
20
  return undefined
21
21
  }
22
22
 
23
- const key = context.selection
24
- ? isKeyedSegment(context.selection.anchor.path[2])
25
- ? context.selection.anchor.path[2]._key
23
+ const key = snapshot.context.selection
24
+ ? isKeyedSegment(snapshot.context.selection.anchor.path[2])
25
+ ? snapshot.context.selection.anchor.path[2]._key
26
26
  : undefined
27
27
  : undefined
28
28
 
@@ -9,8 +9,8 @@ import {getAnchorChild} from './selector.get-anchor-child'
9
9
  export const getAnchorSpan: EditorSelector<
10
10
  | {node: PortableTextSpan; path: [KeyedSegment, 'children', KeyedSegment]}
11
11
  | undefined
12
- > = ({context}) => {
13
- const anchorChild = getAnchorChild({context})
12
+ > = (snapshot) => {
13
+ const anchorChild = getAnchorChild(snapshot)
14
14
 
15
15
  return anchorChild && isPortableTextSpan(anchorChild.node)
16
16
  ? {node: anchorChild.node, path: anchorChild.path}
@@ -11,8 +11,8 @@ import {getAnchorBlock} from './selector.get-anchor-block'
11
11
  */
12
12
  export const getAnchorTextBlock: EditorSelector<
13
13
  {node: PortableTextTextBlock; path: [KeyedSegment]} | undefined
14
- > = ({context}) => {
15
- const anchorBlock = getAnchorBlock({context})
14
+ > = (snapshot) => {
15
+ const anchorBlock = getAnchorBlock(snapshot)
16
16
 
17
17
  return anchorBlock && isPortableTextTextBlock(anchorBlock.node)
18
18
  ? {node: anchorBlock.node, path: anchorBlock.path}
@@ -1,4 +1,5 @@
1
1
  import type {EditorSelector} from '../editor/editor-selector'
2
+ import type {BlockOffset} from '../types/block-offset'
2
3
  import * as utils from '../utils'
3
4
  import {getSelectionEndPoint} from './selector.get-selection-end-point'
4
5
  import {getSelectionStartPoint} from './selector.get-selection-start-point'
@@ -7,25 +8,25 @@ import {getSelectionStartPoint} from './selector.get-selection-start-point'
7
8
  * @public
8
9
  */
9
10
  export const getBlockOffsets: EditorSelector<
10
- {start: utils.BlockOffset; end: utils.BlockOffset} | undefined
11
- > = ({context}) => {
12
- if (!context.selection) {
11
+ {start: BlockOffset; end: BlockOffset} | undefined
12
+ > = (snapshot) => {
13
+ if (!snapshot.context.selection) {
13
14
  return undefined
14
15
  }
15
16
 
16
- const selectionStartPoint = getSelectionStartPoint({context})
17
- const selectionEndPoint = getSelectionEndPoint({context})
17
+ const selectionStartPoint = getSelectionStartPoint(snapshot)
18
+ const selectionEndPoint = getSelectionEndPoint(snapshot)
18
19
 
19
20
  if (!selectionStartPoint || !selectionEndPoint) {
20
21
  return undefined
21
22
  }
22
23
 
23
24
  const start = utils.spanSelectionPointToBlockOffset({
24
- value: context.value,
25
+ value: snapshot.context.value,
25
26
  selectionPoint: selectionStartPoint,
26
27
  })
27
28
  const end = utils.spanSelectionPointToBlockOffset({
28
- value: context.value,
29
+ value: snapshot.context.value,
29
30
  selectionPoint: selectionEndPoint,
30
31
  })
31
32
 
@@ -1,7 +1,6 @@
1
1
  import type {PortableTextBlock} from '@sanity/types'
2
2
  import {describe, expect, test} from 'vitest'
3
- import {compileSchemaDefinition, defineSchema} from '../editor/define-schema'
4
- import type {EditorSnapshot} from '../editor/editor-snapshot'
3
+ import {createTestSnapshot} from '../internal-utils/create-test-snapshot'
5
4
  import {createTestKeyGenerator} from '../internal-utils/test-key-generator'
6
5
  import type {EditorSelection} from '../utils'
7
6
  import {getCaretWordSelection} from './selector.get-caret-word-selection'
@@ -9,16 +8,13 @@ import {getCaretWordSelection} from './selector.get-caret-word-selection'
9
8
  const keyGenerator = createTestKeyGenerator()
10
9
 
11
10
  function snapshot(value: Array<PortableTextBlock>, selection: EditorSelection) {
12
- return {
11
+ return createTestSnapshot({
13
12
  context: {
14
13
  value,
15
14
  selection,
16
15
  keyGenerator,
17
- activeDecorators: [],
18
- converters: [],
19
- schema: compileSchemaDefinition(defineSchema({})),
20
16
  },
21
- } satisfies EditorSnapshot
17
+ })
22
18
  }
23
19
 
24
20
  describe(getCaretWordSelection.name, () => {