@portabletext/editor 2.21.3 → 3.0.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 (78) hide show
  1. package/lib/_chunks-dts/index.d.ts +49 -209
  2. package/lib/_chunks-es/selector.is-at-the-start-of-block.js +103 -20
  3. package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +1 -1
  4. package/lib/_chunks-es/{util.get-text-block-text.js → util.slice-blocks.js} +29 -5
  5. package/lib/_chunks-es/util.slice-blocks.js.map +1 -0
  6. package/lib/_chunks-es/util.slice-text-block.js +13 -2
  7. package/lib/_chunks-es/util.slice-text-block.js.map +1 -1
  8. package/lib/behaviors/index.d.ts +1 -1
  9. package/lib/index.d.ts +2 -2
  10. package/lib/index.js +297 -320
  11. package/lib/index.js.map +1 -1
  12. package/lib/plugins/index.d.ts +2 -133
  13. package/lib/plugins/index.js +2 -796
  14. package/lib/plugins/index.js.map +1 -1
  15. package/lib/selectors/index.d.ts +2 -24
  16. package/lib/selectors/index.js +28 -130
  17. package/lib/selectors/index.js.map +1 -1
  18. package/lib/utils/index.d.ts +3 -3
  19. package/lib/utils/index.js +97 -9
  20. package/lib/utils/index.js.map +1 -1
  21. package/package.json +3 -5
  22. package/src/behaviors/behavior.perform-event.ts +7 -7
  23. package/src/editor/PortableTextEditor.tsx +0 -19
  24. package/src/editor/create-editor.ts +0 -3
  25. package/src/editor/editor-machine.ts +0 -10
  26. package/src/editor/event-to-change.tsx +5 -1
  27. package/src/editor/plugins/create-with-event-listeners.ts +0 -4
  28. package/src/editor/plugins/createWithObjectKeys.ts +2 -1
  29. package/src/editor/plugins/createWithPatches.ts +3 -3
  30. package/src/editor/plugins/createWithPlaceholderBlock.ts +2 -1
  31. package/src/editor/plugins/createWithPortableTextMarkModel.ts +2 -1
  32. package/src/editor/plugins/with-plugins.ts +10 -14
  33. package/src/editor/relay-machine.ts +0 -4
  34. package/src/editor/sync-machine.ts +2 -2
  35. package/src/editor.ts +0 -4
  36. package/src/history/behavior.operation.history.redo.ts +67 -0
  37. package/src/history/behavior.operation.history.undo.ts +71 -0
  38. package/src/history/event.history.undo.test.tsx +672 -0
  39. package/src/history/history.preserving-keys.test.tsx +112 -0
  40. package/src/history/remote-patches.ts +20 -0
  41. package/src/history/slate-plugin.history.ts +146 -0
  42. package/src/history/slate-plugin.redoing.ts +21 -0
  43. package/src/history/slate-plugin.undoing.ts +21 -0
  44. package/src/history/slate-plugin.without-history.ts +23 -0
  45. package/src/history/transform-operation.ts +245 -0
  46. package/src/history/undo-redo-collaboration.test.tsx +541 -0
  47. package/src/history/undo-redo.feature +125 -0
  48. package/src/history/undo-redo.test.tsx +195 -0
  49. package/src/history/undo-step.ts +148 -0
  50. package/src/index.ts +0 -1
  51. package/src/operations/behavior.operations.ts +2 -4
  52. package/src/plugins/index.ts +0 -3
  53. package/src/selectors/index.ts +0 -3
  54. package/src/test/vitest/step-definitions.tsx +55 -0
  55. package/src/test/vitest/test-editor.tsx +1 -1
  56. package/lib/_chunks-es/selector.get-selection-text.js +0 -92
  57. package/lib/_chunks-es/selector.get-selection-text.js.map +0 -1
  58. package/lib/_chunks-es/selector.get-text-before.js +0 -36
  59. package/lib/_chunks-es/selector.get-text-before.js.map +0 -1
  60. package/lib/_chunks-es/util.get-text-block-text.js.map +0 -1
  61. package/lib/_chunks-es/util.is-empty-text-block.js +0 -40
  62. package/lib/_chunks-es/util.is-empty-text-block.js.map +0 -1
  63. package/lib/_chunks-es/util.merge-text-blocks.js +0 -101
  64. package/lib/_chunks-es/util.merge-text-blocks.js.map +0 -1
  65. package/src/editor/plugins/createWithMaxBlocks.ts +0 -53
  66. package/src/editor/plugins/createWithUndoRedo.ts +0 -628
  67. package/src/editor/with-undo-step.ts +0 -37
  68. package/src/editor/withUndoRedo.ts +0 -34
  69. package/src/editor-event-listener.tsx +0 -28
  70. package/src/plugins/plugin.decorator-shortcut.ts +0 -238
  71. package/src/plugins/plugin.markdown.test.tsx +0 -42
  72. package/src/plugins/plugin.markdown.tsx +0 -131
  73. package/src/plugins/plugin.one-line.tsx +0 -123
  74. package/src/selectors/selector.get-list-state.test.ts +0 -189
  75. package/src/selectors/selector.get-list-state.ts +0 -96
  76. package/src/selectors/selector.get-selected-slice.ts +0 -13
  77. package/src/selectors/selector.get-trimmed-selection.test.ts +0 -657
  78. package/src/selectors/selector.get-trimmed-selection.ts +0 -189
@@ -0,0 +1,195 @@
1
+ import {Before} from 'racejar'
2
+ import {Feature} from 'racejar/vitest'
3
+ import {defineSchema} from '..'
4
+ import {defineBehavior, forward, raise} from '../behaviors'
5
+ import {BehaviorPlugin} from '../plugins/plugin.behavior'
6
+ import {getFocusTextBlock, isSelectionExpanded} from '../selectors'
7
+ import {parameterTypes} from '../test'
8
+ import {createTestEditor, stepDefinitions, type Context} from '../test/vitest'
9
+ import undoRedoFeature from './undo-redo.feature?raw'
10
+
11
+ Feature({
12
+ featureText: undoRedoFeature,
13
+ stepDefinitions,
14
+ parameterTypes,
15
+ hooks: [
16
+ Before(async (context: Context) => {
17
+ const {editor, locator} = await createTestEditor({
18
+ schemaDefinition: defineSchema({
19
+ annotations: [{name: 'link'}, {name: 'comment'}],
20
+ }),
21
+ children: (
22
+ <>
23
+ <ArrowTransformPlugin />
24
+ <CopyrightTransformPlugin />
25
+ </>
26
+ ),
27
+ })
28
+
29
+ context.locator = locator
30
+ context.editor = editor
31
+ }),
32
+ ],
33
+ })
34
+
35
+ /**
36
+ * Native behavior to transform `>` into `→`.
37
+ * Ony for testing purposes.
38
+ */
39
+ function ArrowTransformPlugin() {
40
+ return (
41
+ <BehaviorPlugin
42
+ behaviors={[
43
+ defineBehavior({
44
+ on: 'insert.text',
45
+ guard: ({snapshot, event}) => {
46
+ if (event.text !== '>' || isSelectionExpanded(snapshot)) {
47
+ return false
48
+ }
49
+
50
+ const focusTextBlock = getFocusTextBlock(snapshot)
51
+
52
+ if (!focusTextBlock) {
53
+ return false
54
+ }
55
+
56
+ return {focusTextBlock}
57
+ },
58
+ actions: [
59
+ ({event}) => [forward(event)],
60
+ ({snapshot}, {focusTextBlock}) => [
61
+ raise({
62
+ type: 'select',
63
+ at: {
64
+ anchor: {
65
+ path: focusTextBlock.path,
66
+ offset: 0,
67
+ },
68
+ focus: {
69
+ path: focusTextBlock.path,
70
+ offset: 2,
71
+ },
72
+ },
73
+ }),
74
+ raise({
75
+ type: 'delete',
76
+ at: {
77
+ anchor: {
78
+ path: focusTextBlock.path,
79
+ offset: 0,
80
+ },
81
+ focus: {
82
+ path: focusTextBlock.path,
83
+ offset: 2,
84
+ },
85
+ },
86
+ }),
87
+ raise({
88
+ type: 'insert.child',
89
+ child: {
90
+ _type: snapshot.context.schema.span.name,
91
+ text: '→',
92
+ marks: [],
93
+ },
94
+ }),
95
+ raise({
96
+ type: 'select',
97
+ at: {
98
+ anchor: {
99
+ path: focusTextBlock.path,
100
+ offset: 2,
101
+ },
102
+ focus: {
103
+ path: focusTextBlock.path,
104
+ offset: 2,
105
+ },
106
+ },
107
+ }),
108
+ ],
109
+ ],
110
+ }),
111
+ ]}
112
+ />
113
+ )
114
+ }
115
+
116
+ /**
117
+ * Native behavior to transform `(c)` into `©`.
118
+ * Ony for testing purposes.
119
+ */
120
+ function CopyrightTransformPlugin() {
121
+ return (
122
+ <BehaviorPlugin
123
+ behaviors={[
124
+ defineBehavior({
125
+ on: 'insert.text',
126
+ guard: ({snapshot, event}) => {
127
+ if (event.text !== ')' || isSelectionExpanded(snapshot)) {
128
+ return false
129
+ }
130
+
131
+ const focusTextBlock = getFocusTextBlock(snapshot)
132
+
133
+ if (!focusTextBlock) {
134
+ return false
135
+ }
136
+
137
+ return {focusTextBlock}
138
+ },
139
+ actions: [
140
+ ({event}) => [forward(event)],
141
+ ({snapshot}, {focusTextBlock}) => [
142
+ raise({
143
+ type: 'select',
144
+ at: {
145
+ anchor: {
146
+ path: focusTextBlock.path,
147
+ offset: 0,
148
+ },
149
+ focus: {
150
+ path: focusTextBlock.path,
151
+ offset: 3,
152
+ },
153
+ },
154
+ }),
155
+ raise({
156
+ type: 'delete',
157
+ at: {
158
+ anchor: {
159
+ path: focusTextBlock.path,
160
+ offset: 0,
161
+ },
162
+ focus: {
163
+ path: focusTextBlock.path,
164
+ offset: 3,
165
+ },
166
+ },
167
+ }),
168
+ raise({
169
+ type: 'insert.child',
170
+ child: {
171
+ _type: snapshot.context.schema.span.name,
172
+ text: '©',
173
+ marks: [],
174
+ },
175
+ }),
176
+ raise({
177
+ type: 'select',
178
+ at: {
179
+ anchor: {
180
+ path: focusTextBlock.path,
181
+ offset: 3,
182
+ },
183
+ focus: {
184
+ path: focusTextBlock.path,
185
+ offset: 3,
186
+ },
187
+ },
188
+ }),
189
+ ],
190
+ ],
191
+ }),
192
+ ]}
193
+ />
194
+ )
195
+ }
@@ -0,0 +1,148 @@
1
+ import {Path, type Editor, type Operation} from 'slate'
2
+ import {isNormalizingNode} from '../editor/with-normalizing-node'
3
+ import {defaultKeyGenerator} from '../utils/key-generator'
4
+
5
+ const CURRENT_UNDO_STEP_ID: WeakMap<Editor, {undoStepId: string} | undefined> =
6
+ new WeakMap()
7
+
8
+ export function getCurrentUndoStepId(editor: Editor) {
9
+ return CURRENT_UNDO_STEP_ID.get(editor)?.undoStepId
10
+ }
11
+
12
+ export function createUndoStepId(editor: Editor) {
13
+ CURRENT_UNDO_STEP_ID.set(editor, {
14
+ undoStepId: defaultKeyGenerator(),
15
+ })
16
+ }
17
+
18
+ export function clearUndoStepId(editor: Editor) {
19
+ CURRENT_UNDO_STEP_ID.set(editor, undefined)
20
+ }
21
+
22
+ type UndoStep = {
23
+ operations: Array<Operation>
24
+ timestamp: Date
25
+ }
26
+
27
+ export function createUndoSteps({
28
+ steps,
29
+ op,
30
+ editor,
31
+ currentUndoStepId,
32
+ previousUndoStepId,
33
+ }: {
34
+ steps: Array<UndoStep>
35
+ op: Operation
36
+ editor: Editor
37
+ currentUndoStepId: string | undefined
38
+ previousUndoStepId: string | undefined
39
+ }): Array<UndoStep> {
40
+ const lastStep = steps.at(-1)
41
+
42
+ if (!lastStep) {
43
+ return createNewStep(steps, op, editor)
44
+ }
45
+
46
+ if (editor.operations.length > 0) {
47
+ // The editor has operations in progress
48
+
49
+ if (currentUndoStepId === previousUndoStepId || isNormalizingNode(editor)) {
50
+ return mergeIntoLastStep(steps, lastStep, op)
51
+ }
52
+
53
+ return createNewStep(steps, op, editor)
54
+ }
55
+
56
+ if (
57
+ op.type === 'set_selection' &&
58
+ currentUndoStepId === undefined &&
59
+ previousUndoStepId !== undefined
60
+ ) {
61
+ // Selecting without undo step ID
62
+ return mergeIntoLastStep(steps, lastStep, op)
63
+ }
64
+
65
+ if (
66
+ op.type === 'set_selection' &&
67
+ currentUndoStepId !== undefined &&
68
+ previousUndoStepId !== undefined &&
69
+ previousUndoStepId !== currentUndoStepId
70
+ ) {
71
+ // Selecting with different undo step ID
72
+ return mergeIntoLastStep(steps, lastStep, op)
73
+ }
74
+
75
+ // Handle case when both IDs are undefined
76
+ if (currentUndoStepId === undefined && previousUndoStepId === undefined) {
77
+ if (op.type === 'set_selection') {
78
+ return mergeIntoLastStep(steps, lastStep, op)
79
+ }
80
+
81
+ const lastOp = lastStep.operations.at(-1)
82
+
83
+ if (
84
+ lastOp &&
85
+ op.type === 'insert_text' &&
86
+ lastOp.type === 'insert_text' &&
87
+ op.offset === lastOp.offset + lastOp.text.length &&
88
+ Path.equals(op.path, lastOp.path) &&
89
+ op.text !== ' '
90
+ ) {
91
+ return mergeIntoLastStep(steps, lastStep, op)
92
+ }
93
+
94
+ if (
95
+ lastOp &&
96
+ op.type === 'remove_text' &&
97
+ lastOp.type === 'remove_text' &&
98
+ op.offset + op.text.length === lastOp.offset &&
99
+ Path.equals(op.path, lastOp.path)
100
+ ) {
101
+ return mergeIntoLastStep(steps, lastStep, op)
102
+ }
103
+
104
+ return createNewStep(steps, op, editor)
105
+ }
106
+
107
+ return createNewStep(steps, op, editor)
108
+ }
109
+
110
+ function createNewStep(
111
+ steps: Array<UndoStep>,
112
+ op: Operation,
113
+ editor: Editor,
114
+ ): Array<UndoStep> {
115
+ const operations =
116
+ editor.selection === null
117
+ ? [op]
118
+ : [
119
+ {
120
+ type: 'set_selection' as const,
121
+ properties: {...editor.selection},
122
+ newProperties: {...editor.selection},
123
+ },
124
+ op,
125
+ ]
126
+
127
+ return [
128
+ ...steps,
129
+ {
130
+ operations,
131
+ timestamp: new Date(),
132
+ },
133
+ ]
134
+ }
135
+
136
+ function mergeIntoLastStep(
137
+ steps: Array<UndoStep>,
138
+ lastStep: UndoStep,
139
+ op: Operation,
140
+ ): Array<UndoStep> {
141
+ return [
142
+ ...steps.slice(0, -1),
143
+ {
144
+ timestamp: lastStep.timestamp,
145
+ operations: [...lastStep.operations, op],
146
+ },
147
+ ]
148
+ }
package/src/index.ts CHANGED
@@ -7,7 +7,6 @@ export type {
7
7
  PortableTextSpan,
8
8
  } from '@sanity/types'
9
9
  export type {Editor, EditorConfig, EditorEvent} from './editor'
10
- export {EditorEventListener} from './editor-event-listener'
11
10
  export {PortableTextEditable} from './editor/Editable'
12
11
  export type {PortableTextEditableProps} from './editor/Editable'
13
12
  export type {PatchesEvent} from './editor/editor-machine'
@@ -5,10 +5,8 @@ import type {
5
5
  } from '../behaviors/behavior.types.event'
6
6
  import type {EditorContext} from '../editor/editor-snapshot'
7
7
  import {removeDecoratorOperationImplementation} from '../editor/plugins/createWithPortableTextMarkModel'
8
- import {
9
- historyRedoOperationImplementation,
10
- historyUndoOperationImplementation,
11
- } from '../editor/plugins/createWithUndoRedo'
8
+ import {historyRedoOperationImplementation} from '../history/behavior.operation.history.redo'
9
+ import {historyUndoOperationImplementation} from '../history/behavior.operation.history.undo'
12
10
  import type {OmitFromUnion, PickFromUnion} from '../type-utils'
13
11
  import type {PortableTextSlateEditor} from '../types/editor'
14
12
  import {addAnnotationOperationImplementation} from './behavior.operation.annotation.add'
@@ -1,6 +1,3 @@
1
1
  export {BehaviorPlugin} from './plugin.behavior'
2
- export {DecoratorShortcutPlugin} from './plugin.decorator-shortcut'
3
2
  export {EditorRefPlugin} from './plugin.editor-ref'
4
3
  export {EventListenerPlugin} from './plugin.event-listener'
5
- export {MarkdownPlugin, type MarkdownPluginConfig} from './plugin.markdown'
6
- export {OneLinePlugin} from './plugin.one-line'
@@ -16,7 +16,6 @@ export {getFocusListBlock} from './selector.get-focus-list-block'
16
16
  export {getFocusSpan} from './selector.get-focus-span'
17
17
  export {getFocusTextBlock} from './selector.get-focus-text-block'
18
18
  export {getLastBlock} from './selector.get-last-block'
19
- export {getListIndex} from './selector.get-list-state'
20
19
  export {getMarkState, type MarkState} from './selector.get-mark-state'
21
20
  export {getNextBlock} from './selector.get-next-block'
22
21
  export {getNextInlineObject} from './selector.get-next-inline-object'
@@ -27,7 +26,6 @@ export {getPreviousInlineObject} from './selector.get-previous-inline-object'
27
26
  export {getPreviousInlineObjects} from './selector.get-previous-inline-objects'
28
27
  export {getPreviousSpan} from './selector.get-previous-span'
29
28
  export {getSelectedBlocks} from './selector.get-selected-blocks'
30
- export {getSelectedSlice} from './selector.get-selected-slice'
31
29
  export {getSelectedSpans} from './selector.get-selected-spans'
32
30
  export {getSelectedTextBlocks} from './selector.get-selected-text-blocks'
33
31
  export {getSelectedValue} from './selector.get-selected-value'
@@ -41,7 +39,6 @@ export {getSelectionStartPoint} from './selector.get-selection-start-point'
41
39
  export {getSelectionText} from './selector.get-selection-text'
42
40
  export {getBlockTextAfter} from './selector.get-text-after'
43
41
  export {getBlockTextBefore} from './selector.get-text-before'
44
- export {getTrimmedSelection} from './selector.get-trimmed-selection'
45
42
  export {getValue} from './selector.get-value'
46
43
  export {isActiveAnnotation} from './selector.is-active-annotation'
47
44
  export {isActiveDecorator} from './selector.is-active-decorator'
@@ -235,6 +235,21 @@ export const stepDefinitions = [
235
235
  })
236
236
  },
237
237
  ),
238
+ When(
239
+ '{button} is pressed in Editor B',
240
+ async (context: Context, button: Parameter['button']) => {
241
+ const previousSelection = context.editorB.getSnapshot().context.selection
242
+ await userEvent.keyboard(button)
243
+
244
+ await vi.waitFor(() => {
245
+ const currentSelection = context.editorB.getSnapshot().context.selection
246
+
247
+ if (currentSelection) {
248
+ expect(currentSelection).not.toBe(previousSelection)
249
+ }
250
+ })
251
+ },
252
+ ),
238
253
  When(
239
254
  '{button} is pressed {int} times',
240
255
  async (context: Context, button: Parameter['button'], times: number) => {
@@ -253,6 +268,25 @@ export const stepDefinitions = [
253
268
  }
254
269
  },
255
270
  ),
271
+ When(
272
+ '{button} is pressed {int} times in Editor B',
273
+ async (context: Context, button: Parameter['button'], times: number) => {
274
+ for (let i = 0; i < times; i++) {
275
+ const previousSelection =
276
+ context.editorB.getSnapshot().context.selection
277
+ await userEvent.keyboard(button)
278
+
279
+ await vi.waitFor(() => {
280
+ const currentSelection =
281
+ context.editorB.getSnapshot().context.selection
282
+
283
+ if (currentSelection) {
284
+ expect(currentSelection).not.toBe(previousSelection)
285
+ }
286
+ })
287
+ }
288
+ },
289
+ ),
256
290
  When(
257
291
  '{shortcut} is pressed',
258
292
  async (context: Context, shortcut: Parameter['shortcut']) => {
@@ -302,6 +336,27 @@ export const stepDefinitions = [
302
336
  })
303
337
  },
304
338
  ),
339
+ When(
340
+ 'the caret is put before {string} in Editor B',
341
+ async (context: Context, text: string) => {
342
+ await vi.waitFor(() => {
343
+ const selection = getSelectionBeforeText(
344
+ context.editorB.getSnapshot().context,
345
+ text,
346
+ )
347
+ expect(selection).not.toBeNull()
348
+
349
+ context.editorB.send({
350
+ type: 'select',
351
+ at: selection,
352
+ })
353
+
354
+ expect(context.editorB.getSnapshot().context.selection).toEqual(
355
+ selection,
356
+ )
357
+ })
358
+ },
359
+ ),
305
360
  Then(
306
361
  'the caret is before {string}',
307
362
  async (context: Context, text: string) => {
@@ -134,7 +134,7 @@ export async function createTestEditors(
134
134
  ...patch,
135
135
  origin: 'remote',
136
136
  })),
137
- snapshot: event.snapshot,
137
+ snapshot: event.value,
138
138
  })
139
139
  editorBRef.current?.send({
140
140
  type: 'update value',
@@ -1,92 +0,0 @@
1
- import { isTextBlock, isSpan } from "@portabletext/schema";
2
- import { getBlockKeyFromSelectionPoint, getChildKeyFromSelectionPoint, getSelectionStartPoint as getSelectionStartPoint$1, getSelectionEndPoint, sliceBlocks } from "./util.get-text-block-text.js";
3
- import { isKeySegment } from "@sanity/types";
4
- const getFocusBlock = (snapshot) => {
5
- if (!snapshot.context.selection)
6
- return;
7
- const key = getBlockKeyFromSelectionPoint(snapshot.context.selection.focus), index = key ? snapshot.blockIndexMap.get(key) : void 0, node = index !== void 0 ? snapshot.context.value.at(index) : void 0;
8
- return node && key ? {
9
- node,
10
- path: [{
11
- _key: key
12
- }]
13
- } : void 0;
14
- }, getFocusTextBlock = (snapshot) => {
15
- const focusBlock = getFocusBlock(snapshot);
16
- return focusBlock && isTextBlock(snapshot.context, focusBlock.node) ? {
17
- node: focusBlock.node,
18
- path: focusBlock.path
19
- } : void 0;
20
- }, getFocusChild = (snapshot) => {
21
- if (!snapshot.context.selection)
22
- return;
23
- const focusBlock = getFocusTextBlock(snapshot);
24
- if (!focusBlock)
25
- return;
26
- const key = getChildKeyFromSelectionPoint(snapshot.context.selection.focus), node = key ? focusBlock.node.children.find((span) => span._key === key) : void 0;
27
- return node && key ? {
28
- node,
29
- path: [...focusBlock.path, "children", {
30
- _key: key
31
- }]
32
- } : void 0;
33
- }, getFocusSpan = (snapshot) => {
34
- const focusChild = getFocusChild(snapshot);
35
- return focusChild && isSpan(snapshot.context, focusChild.node) ? {
36
- node: focusChild.node,
37
- path: focusChild.path
38
- } : void 0;
39
- }, getSelectionStartPoint = (snapshot) => {
40
- if (snapshot.context.selection)
41
- return snapshot.context.selection.backward ? snapshot.context.selection.focus : snapshot.context.selection.anchor;
42
- }, isSelectionCollapsed = (snapshot) => snapshot.context.selection ? JSON.stringify(snapshot.context.selection.anchor.path) === JSON.stringify(snapshot.context.selection.focus.path) && snapshot.context.selection?.anchor.offset === snapshot.context.selection?.focus.offset : !1, isSelectionExpanded = (snapshot) => snapshot.context.selection !== null && !isSelectionCollapsed(snapshot), getSelectedValue = (snapshot) => {
43
- const selection = snapshot.context.selection;
44
- if (!selection)
45
- return [];
46
- const startPoint = getSelectionStartPoint$1(selection), endPoint = getSelectionEndPoint(selection), startBlockKey = getBlockKeyFromSelectionPoint(startPoint), endBlockKey = getBlockKeyFromSelectionPoint(endPoint);
47
- if (!startBlockKey || !endBlockKey)
48
- return [];
49
- const startBlockIndex = snapshot.blockIndexMap.get(startBlockKey), endBlockIndex = snapshot.blockIndexMap.get(endBlockKey);
50
- if (startBlockIndex === void 0 || endBlockIndex === void 0)
51
- return [];
52
- const startBlock = snapshot.context.value.at(startBlockIndex), slicedStartBlock = startBlock ? sliceBlocks({
53
- context: snapshot.context,
54
- blocks: [startBlock]
55
- }).at(0) : void 0;
56
- if (startBlockIndex === endBlockIndex)
57
- return slicedStartBlock ? [slicedStartBlock] : [];
58
- const endBlock = snapshot.context.value.at(endBlockIndex), slicedEndBlock = endBlock ? sliceBlocks({
59
- context: snapshot.context,
60
- blocks: [endBlock]
61
- }).at(0) : void 0, middleBlocks = snapshot.context.value.slice(startBlockIndex + 1, endBlockIndex);
62
- return [...slicedStartBlock ? [slicedStartBlock] : [], ...middleBlocks, ...slicedEndBlock ? [slicedEndBlock] : []];
63
- }, getPreviousInlineObject = (snapshot) => {
64
- const focusTextBlock = getFocusTextBlock(snapshot), selectionStartPoint = getSelectionStartPoint(snapshot), selectionStartPointChildKey = selectionStartPoint && isKeySegment(selectionStartPoint.path[2]) ? selectionStartPoint.path[2]._key : void 0;
65
- if (!focusTextBlock || !selectionStartPointChildKey)
66
- return;
67
- let inlineObject;
68
- for (const child of focusTextBlock.node.children) {
69
- if (child._key === selectionStartPointChildKey)
70
- break;
71
- isSpan(snapshot.context, child) || (inlineObject = {
72
- node: child,
73
- path: [...focusTextBlock.path, "children", {
74
- _key: child._key
75
- }]
76
- });
77
- }
78
- return inlineObject;
79
- }, getSelectionText = (snapshot) => getSelectedValue(snapshot).reduce((text, block) => isTextBlock(snapshot.context, block) ? text + block.children.reduce((text2, child) => isSpan(snapshot.context, child) ? text2 + child.text : text2, "") : text, "");
80
- export {
81
- getFocusBlock,
82
- getFocusChild,
83
- getFocusSpan,
84
- getFocusTextBlock,
85
- getPreviousInlineObject,
86
- getSelectedValue,
87
- getSelectionStartPoint,
88
- getSelectionText,
89
- isSelectionCollapsed,
90
- isSelectionExpanded
91
- };
92
- //# sourceMappingURL=selector.get-selection-text.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"selector.get-selection-text.js","sources":["../../src/selectors/selector.get-focus-block.ts","../../src/selectors/selector.get-focus-text-block.ts","../../src/selectors/selector.get-focus-child.ts","../../src/selectors/selector.get-focus-span.ts","../../src/selectors/selector.get-selection-start-point.ts","../../src/selectors/selector.is-selection-collapsed.ts","../../src/selectors/selector.is-selection-expanded.ts","../../src/selectors/selector.get-selected-value.ts","../../src/selectors/selector.get-previous-inline-object.ts","../../src/selectors/selector.get-selection-text.ts"],"sourcesContent":["import type {PortableTextBlock} from '@sanity/types'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport type {BlockPath} from '../types/paths'\nimport {getBlockKeyFromSelectionPoint} from '../utils/util.selection-point'\n\n/**\n * @public\n */\nexport const getFocusBlock: EditorSelector<\n {node: PortableTextBlock; path: BlockPath} | undefined\n> = (snapshot) => {\n if (!snapshot.context.selection) {\n return undefined\n }\n\n const key = getBlockKeyFromSelectionPoint(snapshot.context.selection.focus)\n const index = key ? snapshot.blockIndexMap.get(key) : undefined\n\n const node =\n index !== undefined ? snapshot.context.value.at(index) : undefined\n\n return node && key ? {node, path: [{_key: key}]} : undefined\n}\n","import {isTextBlock} from '@portabletext/schema'\nimport type {PortableTextTextBlock} from '@sanity/types'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport type {BlockPath} from '../types/paths'\nimport {getFocusBlock} from './selector.get-focus-block'\n\n/**\n * @public\n */\nexport const getFocusTextBlock: EditorSelector<\n {node: PortableTextTextBlock; path: BlockPath} | undefined\n> = (snapshot) => {\n const focusBlock = getFocusBlock(snapshot)\n\n return focusBlock && isTextBlock(snapshot.context, focusBlock.node)\n ? {node: focusBlock.node, path: focusBlock.path}\n : undefined\n}\n","import type {PortableTextObject, PortableTextSpan} from '@sanity/types'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport type {ChildPath} from '../types/paths'\nimport {getChildKeyFromSelectionPoint} from '../utils/util.selection-point'\nimport {getFocusTextBlock} from './selector.get-focus-text-block'\n\n/**\n * @public\n */\nexport const getFocusChild: EditorSelector<\n | {\n node: PortableTextObject | PortableTextSpan\n path: ChildPath\n }\n | undefined\n> = (snapshot) => {\n if (!snapshot.context.selection) {\n return undefined\n }\n\n const focusBlock = getFocusTextBlock(snapshot)\n\n if (!focusBlock) {\n return undefined\n }\n\n const key = getChildKeyFromSelectionPoint(snapshot.context.selection.focus)\n\n const node = key\n ? focusBlock.node.children.find((span) => span._key === key)\n : undefined\n\n return node && key\n ? {node, path: [...focusBlock.path, 'children', {_key: key}]}\n : undefined\n}\n","import {isSpan} from '@portabletext/schema'\nimport type {PortableTextSpan} from '@sanity/types'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport type {ChildPath} from '../types/paths'\nimport {getFocusChild} from './selector.get-focus-child'\n\n/**\n * @public\n */\nexport const getFocusSpan: EditorSelector<\n {node: PortableTextSpan; path: ChildPath} | undefined\n> = (snapshot) => {\n const focusChild = getFocusChild(snapshot)\n\n return focusChild && isSpan(snapshot.context, focusChild.node)\n ? {node: focusChild.node, path: focusChild.path}\n : undefined\n}\n","import type {EditorSelector} from '../editor/editor-selector'\nimport type {EditorSelectionPoint} from '../types/editor'\n\n/**\n * @public\n */\nexport const getSelectionStartPoint: EditorSelector<\n EditorSelectionPoint | undefined\n> = (snapshot) => {\n if (!snapshot.context.selection) {\n return undefined\n }\n\n return snapshot.context.selection.backward\n ? snapshot.context.selection.focus\n : snapshot.context.selection.anchor\n}\n","import type {EditorSelector} from '../editor/editor-selector'\n\n/**\n * @public\n */\nexport const isSelectionCollapsed: EditorSelector<boolean> = (snapshot) => {\n if (!snapshot.context.selection) {\n return false\n }\n\n return (\n JSON.stringify(snapshot.context.selection.anchor.path) ===\n JSON.stringify(snapshot.context.selection.focus.path) &&\n snapshot.context.selection?.anchor.offset ===\n snapshot.context.selection?.focus.offset\n )\n}\n","import type {EditorSelector} from '../editor/editor-selector'\nimport {isSelectionCollapsed} from './selector.is-selection-collapsed'\n\n/**\n * @public\n */\nexport const isSelectionExpanded: EditorSelector<boolean> = (snapshot) => {\n return snapshot.context.selection !== null && !isSelectionCollapsed(snapshot)\n}\n","import type {PortableTextBlock} from '@sanity/types'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport {getSelectionEndPoint} from '../utils/util.get-selection-end-point'\nimport {getSelectionStartPoint} from '../utils/util.get-selection-start-point'\nimport {getBlockKeyFromSelectionPoint} from '../utils/util.selection-point'\nimport {sliceBlocks} from '../utils/util.slice-blocks'\n\n/**\n * @public\n */\nexport const getSelectedValue: EditorSelector<Array<PortableTextBlock>> = (\n snapshot,\n) => {\n const selection = snapshot.context.selection\n\n if (!selection) {\n return []\n }\n\n const startPoint = getSelectionStartPoint(selection)\n const endPoint = getSelectionEndPoint(selection)\n const startBlockKey = getBlockKeyFromSelectionPoint(startPoint)\n const endBlockKey = getBlockKeyFromSelectionPoint(endPoint)\n\n if (!startBlockKey || !endBlockKey) {\n return []\n }\n\n const startBlockIndex = snapshot.blockIndexMap.get(startBlockKey)\n const endBlockIndex = snapshot.blockIndexMap.get(endBlockKey)\n\n if (startBlockIndex === undefined || endBlockIndex === undefined) {\n return []\n }\n\n const startBlock = snapshot.context.value.at(startBlockIndex)\n const slicedStartBlock = startBlock\n ? sliceBlocks({\n context: snapshot.context,\n blocks: [startBlock],\n }).at(0)\n : undefined\n\n if (startBlockIndex === endBlockIndex) {\n return slicedStartBlock ? [slicedStartBlock] : []\n }\n\n const endBlock = snapshot.context.value.at(endBlockIndex)\n const slicedEndBlock = endBlock\n ? sliceBlocks({\n context: snapshot.context,\n blocks: [endBlock],\n }).at(0)\n : undefined\n\n const middleBlocks = snapshot.context.value.slice(\n startBlockIndex + 1,\n endBlockIndex,\n )\n\n return [\n ...(slicedStartBlock ? [slicedStartBlock] : []),\n ...middleBlocks,\n ...(slicedEndBlock ? [slicedEndBlock] : []),\n ]\n}\n","import {isSpan} from '@portabletext/schema'\nimport {isKeySegment, type PortableTextObject} from '@sanity/types'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport type {ChildPath} from '../types/paths'\nimport {getFocusTextBlock} from './selector.get-focus-text-block'\nimport {getSelectionStartPoint} from './selector.get-selection-start-point'\n\n/**\n * @public\n */\nexport const getPreviousInlineObject: EditorSelector<\n | {\n node: PortableTextObject\n path: ChildPath\n }\n | undefined\n> = (snapshot) => {\n const focusTextBlock = getFocusTextBlock(snapshot)\n const selectionStartPoint = getSelectionStartPoint(snapshot)\n const selectionStartPointChildKey =\n selectionStartPoint && isKeySegment(selectionStartPoint.path[2])\n ? selectionStartPoint.path[2]._key\n : undefined\n\n if (!focusTextBlock || !selectionStartPointChildKey) {\n return undefined\n }\n\n let inlineObject:\n | {\n node: PortableTextObject\n path: ChildPath\n }\n | undefined\n\n for (const child of focusTextBlock.node.children) {\n if (child._key === selectionStartPointChildKey) {\n break\n }\n\n if (!isSpan(snapshot.context, child)) {\n inlineObject = {\n node: child,\n path: [...focusTextBlock.path, 'children', {_key: child._key}],\n }\n }\n }\n\n return inlineObject\n}\n","import {isSpan, isTextBlock} from '@portabletext/schema'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport {getSelectedValue} from './selector.get-selected-value'\n\n/**\n * @public\n */\nexport const getSelectionText: EditorSelector<string> = (snapshot) => {\n const selectedValue = getSelectedValue(snapshot)\n\n return selectedValue.reduce((text, block) => {\n if (!isTextBlock(snapshot.context, block)) {\n return text\n }\n\n return (\n text +\n block.children.reduce((text, child) => {\n if (isSpan(snapshot.context, child)) {\n return text + child.text\n }\n\n return text\n }, '')\n )\n }, '')\n}\n"],"names":["getFocusBlock","snapshot","context","selection","key","getBlockKeyFromSelectionPoint","focus","index","blockIndexMap","get","undefined","node","value","at","path","_key","getFocusTextBlock","focusBlock","isTextBlock","getFocusChild","getChildKeyFromSelectionPoint","children","find","span","getFocusSpan","focusChild","isSpan","getSelectionStartPoint","backward","anchor","isSelectionCollapsed","JSON","stringify","offset","isSelectionExpanded","getSelectedValue","startPoint","endPoint","getSelectionEndPoint","startBlockKey","endBlockKey","startBlockIndex","endBlockIndex","startBlock","slicedStartBlock","sliceBlocks","blocks","endBlock","slicedEndBlock","middleBlocks","slice","getPreviousInlineObject","focusTextBlock","selectionStartPoint","selectionStartPointChildKey","isKeySegment","inlineObject","child","getSelectionText","reduce","text","block"],"mappings":";;;AAQO,MAAMA,gBAERC,CAAAA,aAAa;AAChB,MAAI,CAACA,SAASC,QAAQC;AACpB;AAGF,QAAMC,MAAMC,8BAA8BJ,SAASC,QAAQC,UAAUG,KAAK,GACpEC,QAAQH,MAAMH,SAASO,cAAcC,IAAIL,GAAG,IAAIM,QAEhDC,OACJJ,UAAUG,SAAYT,SAASC,QAAQU,MAAMC,GAAGN,KAAK,IAAIG;AAE3D,SAAOC,QAAQP,MAAM;AAAA,IAACO;AAAAA,IAAMG,MAAM,CAAC;AAAA,MAACC,MAAMX;AAAAA,IAAAA,CAAI;AAAA,EAAA,IAAKM;AACrD,GCbaM,oBAERf,CAAAA,aAAa;AAChB,QAAMgB,aAAajB,cAAcC,QAAQ;AAEzC,SAAOgB,cAAcC,YAAYjB,SAASC,SAASe,WAAWN,IAAI,IAC9D;AAAA,IAACA,MAAMM,WAAWN;AAAAA,IAAMG,MAAMG,WAAWH;AAAAA,EAAAA,IACzCJ;AACN,GCRaS,gBAMRlB,CAAAA,aAAa;AAChB,MAAI,CAACA,SAASC,QAAQC;AACpB;AAGF,QAAMc,aAAaD,kBAAkBf,QAAQ;AAE7C,MAAI,CAACgB;AACH;AAGF,QAAMb,MAAMgB,8BAA8BnB,SAASC,QAAQC,UAAUG,KAAK,GAEpEK,OAAOP,MACTa,WAAWN,KAAKU,SAASC,KAAMC,UAASA,KAAKR,SAASX,GAAG,IACzDM;AAEJ,SAAOC,QAAQP,MACX;AAAA,IAACO;AAAAA,IAAMG,MAAM,CAAC,GAAGG,WAAWH,MAAM,YAAY;AAAA,MAACC,MAAMX;AAAAA,IAAAA,CAAI;AAAA,EAAA,IACzDM;AACN,GC1Bac,eAERvB,CAAAA,aAAa;AAChB,QAAMwB,aAAaN,cAAclB,QAAQ;AAEzC,SAAOwB,cAAcC,OAAOzB,SAASC,SAASuB,WAAWd,IAAI,IACzD;AAAA,IAACA,MAAMc,WAAWd;AAAAA,IAAMG,MAAMW,WAAWX;AAAAA,EAAAA,IACzCJ;AACN,GCXaiB,yBAER1B,CAAAA,aAAa;AAChB,MAAKA,SAASC,QAAQC;AAItB,WAAOF,SAASC,QAAQC,UAAUyB,WAC9B3B,SAASC,QAAQC,UAAUG,QAC3BL,SAASC,QAAQC,UAAU0B;AACjC,GCXaC,uBAAiD7B,CAAAA,aACvDA,SAASC,QAAQC,YAKpB4B,KAAKC,UAAU/B,SAASC,QAAQC,UAAU0B,OAAOf,IAAI,MACnDiB,KAAKC,UAAU/B,SAASC,QAAQC,UAAUG,MAAMQ,IAAI,KACtDb,SAASC,QAAQC,WAAW0B,OAAOI,WACjChC,SAASC,QAAQC,WAAWG,MAAM2B,SAP7B,ICDEC,sBAAgDjC,cACpDA,SAASC,QAAQC,cAAc,QAAQ,CAAC2B,qBAAqB7B,QAAQ,GCGjEkC,mBACXlC,CAAAA,aACG;AACH,QAAME,YAAYF,SAASC,QAAQC;AAEnC,MAAI,CAACA;AACH,WAAO,CAAA;AAGT,QAAMiC,aAAaT,yBAAuBxB,SAAS,GAC7CkC,WAAWC,qBAAqBnC,SAAS,GACzCoC,gBAAgBlC,8BAA8B+B,UAAU,GACxDI,cAAcnC,8BAA8BgC,QAAQ;AAE1D,MAAI,CAACE,iBAAiB,CAACC;AACrB,WAAO,CAAA;AAGT,QAAMC,kBAAkBxC,SAASO,cAAcC,IAAI8B,aAAa,GAC1DG,gBAAgBzC,SAASO,cAAcC,IAAI+B,WAAW;AAE5D,MAAIC,oBAAoB/B,UAAagC,kBAAkBhC;AACrD,WAAO,CAAA;AAGT,QAAMiC,aAAa1C,SAASC,QAAQU,MAAMC,GAAG4B,eAAe,GACtDG,mBAAmBD,aACrBE,YAAY;AAAA,IACV3C,SAASD,SAASC;AAAAA,IAClB4C,QAAQ,CAACH,UAAU;AAAA,EAAA,CACpB,EAAE9B,GAAG,CAAC,IACPH;AAEJ,MAAI+B,oBAAoBC;AACtB,WAAOE,mBAAmB,CAACA,gBAAgB,IAAI,CAAA;AAGjD,QAAMG,WAAW9C,SAASC,QAAQU,MAAMC,GAAG6B,aAAa,GAClDM,iBAAiBD,WACnBF,YAAY;AAAA,IACV3C,SAASD,SAASC;AAAAA,IAClB4C,QAAQ,CAACC,QAAQ;AAAA,EAAA,CAClB,EAAElC,GAAG,CAAC,IACPH,QAEEuC,eAAehD,SAASC,QAAQU,MAAMsC,MAC1CT,kBAAkB,GAClBC,aACF;AAEA,SAAO,CACL,GAAIE,mBAAmB,CAACA,gBAAgB,IAAI,CAAA,GAC5C,GAAGK,cACH,GAAID,iBAAiB,CAACA,cAAc,IAAI,CAAA,CAAG;AAE/C,GCvDaG,0BAMRlD,CAAAA,aAAa;AAChB,QAAMmD,iBAAiBpC,kBAAkBf,QAAQ,GAC3CoD,sBAAsB1B,uBAAuB1B,QAAQ,GACrDqD,8BACJD,uBAAuBE,aAAaF,oBAAoBvC,KAAK,CAAC,CAAC,IAC3DuC,oBAAoBvC,KAAK,CAAC,EAAEC,OAC5BL;AAEN,MAAI,CAAC0C,kBAAkB,CAACE;AACtB;AAGF,MAAIE;AAOJ,aAAWC,SAASL,eAAezC,KAAKU,UAAU;AAChD,QAAIoC,MAAM1C,SAASuC;AACjB;AAGG5B,WAAOzB,SAASC,SAASuD,KAAK,MACjCD,eAAe;AAAA,MACb7C,MAAM8C;AAAAA,MACN3C,MAAM,CAAC,GAAGsC,eAAetC,MAAM,YAAY;AAAA,QAACC,MAAM0C,MAAM1C;AAAAA,MAAAA,CAAK;AAAA,IAAA;AAAA,EAGnE;AAEA,SAAOyC;AACT,GC1CaE,mBAA4CzD,CAAAA,aACjCkC,iBAAiBlC,QAAQ,EAE1B0D,OAAO,CAACC,MAAMC,UAC5B3C,YAAYjB,SAASC,SAAS2D,KAAK,IAKtCD,OACAC,MAAMxC,SAASsC,OAAO,CAACC,OAAMH,UACvB/B,OAAOzB,SAASC,SAASuD,KAAK,IACzBG,QAAOH,MAAMG,OAGfA,OACN,EAAE,IAXEA,MAaR,EAAE;"}
@@ -1,36 +0,0 @@
1
- import { getSelectionStartPoint, getBlockStartPoint } from "./util.get-text-block-text.js";
2
- import { getFocusBlock, getSelectionText } from "./selector.get-selection-text.js";
3
- const getBlockTextBefore = (snapshot) => {
4
- if (!snapshot.context.selection)
5
- return "";
6
- const startPoint = getSelectionStartPoint(snapshot.context.selection), block = getFocusBlock({
7
- ...snapshot,
8
- context: {
9
- ...snapshot.context,
10
- selection: {
11
- anchor: startPoint,
12
- focus: startPoint
13
- }
14
- }
15
- });
16
- if (!block)
17
- return "";
18
- const startOfBlock = getBlockStartPoint({
19
- context: snapshot.context,
20
- block
21
- });
22
- return getSelectionText({
23
- ...snapshot,
24
- context: {
25
- ...snapshot.context,
26
- selection: {
27
- anchor: startOfBlock,
28
- focus: startPoint
29
- }
30
- }
31
- });
32
- };
33
- export {
34
- getBlockTextBefore
35
- };
36
- //# sourceMappingURL=selector.get-text-before.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"selector.get-text-before.js","sources":["../../src/selectors/selector.get-text-before.ts"],"sourcesContent":["import type {EditorSelector} from '../editor/editor-selector'\nimport {getBlockStartPoint} from '../utils/util.get-block-start-point'\nimport {getSelectionStartPoint} from '../utils/util.get-selection-start-point'\nimport {getFocusBlock} from './selector.get-focus-block'\nimport {getSelectionText} from './selector.get-selection-text'\n\n/**\n * @public\n */\nexport const getBlockTextBefore: EditorSelector<string> = (snapshot) => {\n if (!snapshot.context.selection) {\n return ''\n }\n\n const startPoint = getSelectionStartPoint(snapshot.context.selection)\n const block = getFocusBlock({\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: {\n anchor: startPoint,\n focus: startPoint,\n },\n },\n })\n\n if (!block) {\n return ''\n }\n\n const startOfBlock = getBlockStartPoint({\n context: snapshot.context,\n block,\n })\n\n return getSelectionText({\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: {\n anchor: startOfBlock,\n focus: startPoint,\n },\n },\n })\n}\n"],"names":["getBlockTextBefore","snapshot","context","selection","startPoint","getSelectionStartPoint","block","getFocusBlock","anchor","focus","startOfBlock","getBlockStartPoint","getSelectionText"],"mappings":";;AASO,MAAMA,qBAA8CC,CAAAA,aAAa;AACtE,MAAI,CAACA,SAASC,QAAQC;AACpB,WAAO;AAGT,QAAMC,aAAaC,uBAAuBJ,SAASC,QAAQC,SAAS,GAC9DG,QAAQC,cAAc;AAAA,IAC1B,GAAGN;AAAAA,IACHC,SAAS;AAAA,MACP,GAAGD,SAASC;AAAAA,MACZC,WAAW;AAAA,QACTK,QAAQJ;AAAAA,QACRK,OAAOL;AAAAA,MAAAA;AAAAA,IACT;AAAA,EACF,CACD;AAED,MAAI,CAACE;AACH,WAAO;AAGT,QAAMI,eAAeC,mBAAmB;AAAA,IACtCT,SAASD,SAASC;AAAAA,IAClBI;AAAAA,EAAAA,CACD;AAED,SAAOM,iBAAiB;AAAA,IACtB,GAAGX;AAAAA,IACHC,SAAS;AAAA,MACP,GAAGD,SAASC;AAAAA,MACZC,WAAW;AAAA,QACTK,QAAQE;AAAAA,QACRD,OAAOL;AAAAA,MAAAA;AAAAA,IACT;AAAA,EACF,CACD;AACH;"}