@portabletext/editor 2.3.5 → 2.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { Behavior, Editor, EditorEmittedEvent, EditorSchema } from "../_chunks-dts/behavior.types.action.cjs";
2
- import * as react12 from "react";
2
+ import * as react22 from "react";
3
3
  import React from "react";
4
4
  /**
5
5
  * @beta
@@ -181,7 +181,7 @@ type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
181
181
  */
182
182
  declare function MarkdownPlugin(props: {
183
183
  config: MarkdownPluginConfig;
184
- }): react12.JSX.Element;
184
+ }): react22.JSX.Element;
185
185
  /**
186
186
  * @beta
187
187
  * Restrict the editor to one line. The plugin takes care of blocking
@@ -192,5 +192,5 @@ declare function MarkdownPlugin(props: {
192
192
  *
193
193
  * @deprecated Install the plugin from `@portabletext/plugin-one-line`
194
194
  */
195
- declare function OneLinePlugin(): react12.JSX.Element;
195
+ declare function OneLinePlugin(): react22.JSX.Element;
196
196
  export { BehaviorPlugin, DecoratorShortcutPlugin, EditorRefPlugin, EventListenerPlugin, MarkdownPlugin, type MarkdownPluginConfig, OneLinePlugin };
@@ -1,5 +1,5 @@
1
1
  import { BlockOffset, BlockPath, ChildPath, EditorContext, EditorSelection, EditorSelectionPoint } from "../_chunks-dts/behavior.types.action.js";
2
- import * as _sanity_types8 from "@sanity/types";
2
+ import * as _sanity_types9 from "@sanity/types";
3
3
  import { KeyedSegment, PortableTextBlock, PortableTextChild, PortableTextSpan, PortableTextTextBlock } from "@sanity/types";
4
4
  /**
5
5
  * @public
@@ -150,7 +150,7 @@ declare function mergeTextBlocks({
150
150
  context: Pick<EditorContext, 'keyGenerator' | 'schema'>;
151
151
  targetBlock: PortableTextTextBlock;
152
152
  incomingBlock: PortableTextTextBlock;
153
- }): PortableTextTextBlock<_sanity_types8.PortableTextObject | _sanity_types8.PortableTextSpan>;
153
+ }): PortableTextTextBlock<_sanity_types9.PortableTextObject | _sanity_types9.PortableTextSpan>;
154
154
  /**
155
155
  * @public
156
156
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "2.3.5",
3
+ "version": "2.3.7",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -79,18 +79,16 @@
79
79
  "slate-dom": "^0.117.4",
80
80
  "slate-react": "0.117.4",
81
81
  "xstate": "^5.20.2",
82
- "@portabletext/block-tools": "3.0.0",
83
- "@portabletext/patches": "1.1.6",
82
+ "@portabletext/block-tools": "3.2.0",
84
83
  "@portabletext/keyboard-shortcuts": "1.1.1",
85
- "@portabletext/schema": "1.0.0",
86
- "@portabletext/sanity-bridge": "1.1.0"
84
+ "@portabletext/patches": "1.1.6",
85
+ "@portabletext/schema": "1.0.0"
87
86
  },
88
87
  "devDependencies": {
89
- "@portabletext/toolkit": "^2.0.17",
90
88
  "@sanity/diff-match-patch": "^3.2.0",
91
89
  "@sanity/pkg-utils": "^7.11.1",
92
- "@sanity/schema": "^4.3.0",
93
- "@sanity/types": "^4.3.0",
90
+ "@sanity/schema": "^4.4.1",
91
+ "@sanity/types": "^4.4.1",
94
92
  "@testing-library/react": "^16.3.0",
95
93
  "@types/debug": "^4.1.12",
96
94
  "@types/lodash": "^4.17.16",
@@ -113,13 +111,15 @@
113
111
  "vite": "^7.0.6",
114
112
  "vitest": "^3.2.4",
115
113
  "vitest-browser-react": "^1.0.1",
114
+ "@portabletext/sanity-bridge": "1.1.1",
116
115
  "racejar": "1.2.12"
117
116
  },
118
117
  "peerDependencies": {
119
- "@sanity/schema": "^4.3.0",
120
- "@sanity/types": "^4.3.0",
118
+ "@sanity/schema": "^4.4.1",
119
+ "@sanity/types": "^4.4.1",
121
120
  "react": "^18.3 || ^19",
122
- "rxjs": "^7.8.2"
121
+ "rxjs": "^7.8.2",
122
+ "@portabletext/sanity-bridge": "1.1.1"
123
123
  },
124
124
  "engines": {
125
125
  "node": ">=20.19"
@@ -1,4 +1,5 @@
1
1
  import type {JSONValue, Patch} from '@portabletext/patches'
2
+ import {compileSchema, defineSchema} from '@portabletext/schema'
2
3
  import type {PortableTextBlock, PortableTextSpan} from '@sanity/types'
3
4
  import {render, waitFor} from '@testing-library/react'
4
5
  import {createRef, type ComponentProps, type RefObject} from 'react'
@@ -30,6 +31,7 @@ function span(
30
31
 
31
32
  describe('Feature: Self-solving', () => {
32
33
  it('Scenario: Missing .markDefs and .marks are added after the editor is made dirty', async () => {
34
+ const schemaDefinition = defineSchema({decorators: [{name: 'strong'}]})
33
35
  const editorRef: RefObject<PortableTextEditor | null> = createRef()
34
36
  const onChange = vi.fn<OnChange>()
35
37
  const initialValue = [
@@ -77,6 +79,7 @@ describe('Feature: Self-solving', () => {
77
79
  render(
78
80
  <PortableTextEditorTester
79
81
  ref={editorRef}
82
+ schemaDefinition={schemaDefinition}
80
83
  keyGenerator={createTestKeyGenerator()}
81
84
  value={initialValue}
82
85
  onChange={onChange}
@@ -99,7 +102,10 @@ describe('Feature: Self-solving', () => {
99
102
  if (editorRef.current) {
100
103
  PortableTextEditor.select(
101
104
  editorRef.current,
102
- getTextSelection(initialValue, 'foo'),
105
+ getTextSelection(
106
+ {schema: compileSchema(schemaDefinition), value: initialValue},
107
+ 'foo',
108
+ ),
103
109
  )
104
110
  PortableTextEditor.toggleMark(editorRef.current, 'strong')
105
111
  }
@@ -110,7 +116,10 @@ describe('Feature: Self-solving', () => {
110
116
  expect(onChange).toHaveBeenNthCalledWith(3, {
111
117
  type: 'selection',
112
118
  selection: {
113
- ...getTextSelection(initialValue, 'foo'),
119
+ ...getTextSelection(
120
+ {schema: compileSchema(schemaDefinition), value: initialValue},
121
+ 'foo',
122
+ ),
114
123
  backward: false,
115
124
  },
116
125
  })
@@ -129,7 +138,10 @@ describe('Feature: Self-solving', () => {
129
138
  expect(onChange).toHaveBeenNthCalledWith(7, {
130
139
  type: 'selection',
131
140
  selection: {
132
- ...getTextSelection(initialValue, 'foo'),
141
+ ...getTextSelection(
142
+ {schema: compileSchema(schemaDefinition), value: initialValue},
143
+ 'foo',
144
+ ),
133
145
  backward: false,
134
146
  },
135
147
  })
@@ -4,11 +4,11 @@
4
4
  *
5
5
  */
6
6
 
7
- import {isPortableTextBlock, isPortableTextSpan} from '@portabletext/toolkit'
8
7
  import type {PortableTextObject, PortableTextSpan} from '@sanity/types'
9
8
  import {isEqual, uniq} from 'lodash'
10
9
  import {Editor, Element, Node, Path, Range, Text, Transforms} from 'slate'
11
10
  import {debugWithName} from '../../internal-utils/debug'
11
+ import {isSpan, isTextBlock} from '../../internal-utils/parse-blocks'
12
12
  import {getNextSpan, getPreviousSpan} from '../../internal-utils/sibling-utils'
13
13
  import {isChangingRemotely} from '../../internal-utils/withChanges'
14
14
  import {isRedoing, isUndoing} from '../../internal-utils/withUndoRedo'
@@ -356,7 +356,7 @@ export function createWithPortableTextMarkModel(
356
356
 
357
357
  if (
358
358
  atTheEndOfAnnotation &&
359
- isPortableTextSpan(op.node) &&
359
+ isSpan(editorActor.getSnapshot().context, op.node) &&
360
360
  op.node.marks?.some((mark) => annotationsEnding.includes(mark))
361
361
  ) {
362
362
  Transforms.insertNodes(editor, {
@@ -378,7 +378,7 @@ export function createWithPortableTextMarkModel(
378
378
 
379
379
  if (
380
380
  atTheStartOfAnnotation &&
381
- isPortableTextSpan(op.node) &&
381
+ isSpan(editorActor.getSnapshot().context, op.node) &&
382
382
  op.node.marks?.some((mark) => annotationsStarting.includes(mark))
383
383
  ) {
384
384
  Transforms.insertNodes(editor, {
@@ -400,7 +400,7 @@ export function createWithPortableTextMarkModel(
400
400
  decoratorStarting &&
401
401
  atTheEndOfAnnotation &&
402
402
  !atTheStartOfAnnotation &&
403
- isPortableTextSpan(op.node) &&
403
+ isSpan(editorActor.getSnapshot().context, op.node) &&
404
404
  op.node.marks?.length === 0
405
405
  ) {
406
406
  Transforms.insertNodes(editor, {
@@ -458,7 +458,11 @@ export function createWithPortableTextMarkModel(
458
458
  }),
459
459
  )[0] ?? ([undefined, undefined] as const)
460
460
 
461
- if (span && block && isPortableTextBlock(block)) {
461
+ if (
462
+ span &&
463
+ block &&
464
+ isTextBlock(editorActor.getSnapshot().context, block)
465
+ ) {
462
466
  const markDefs = block.markDefs ?? []
463
467
  const marks = span.marks ?? []
464
468
  const spanHasAnnotations = marks.some((mark) =>
@@ -1,7 +1,9 @@
1
+ import {compileSchema, defineSchema} from '@portabletext/schema'
1
2
  import {expect, test} from 'vitest'
2
3
  import {getEditorSelection} from './editor-selection'
3
4
 
4
5
  test(getEditorSelection.name, () => {
6
+ const schema = compileSchema(defineSchema({}))
5
7
  const image = {
6
8
  _type: 'image',
7
9
  _key: 'i1',
@@ -25,15 +27,17 @@ test(getEditorSelection.name, () => {
25
27
  ],
26
28
  }
27
29
 
28
- expect(getEditorSelection([image, splitBlock])).toEqual({
30
+ expect(getEditorSelection({schema, value: [image, splitBlock]})).toEqual({
29
31
  anchor: {path: [{_key: 'i1'}], offset: 0},
30
32
  focus: {path: [{_key: 'b1'}, 'children', {_key: 's3'}], offset: 4},
31
33
  })
32
- expect(getEditorSelection([splitBlock, image])).toEqual({
34
+ expect(getEditorSelection({schema, value: [splitBlock, image]})).toEqual({
33
35
  anchor: {path: [{_key: 'b1'}, 'children', {_key: 's1'}], offset: 0},
34
36
  focus: {path: [{_key: 'i1'}], offset: 0},
35
37
  })
36
- expect(getEditorSelection([blockWithStockTicker, splitBlock])).toEqual({
38
+ expect(
39
+ getEditorSelection({schema, value: [blockWithStockTicker, splitBlock]}),
40
+ ).toEqual({
37
41
  anchor: {path: [{_key: 'b2'}, 'children', {_key: 's1'}], offset: 0},
38
42
  focus: {path: [{_key: 'b1'}, 'children', {_key: 's3'}], offset: 4},
39
43
  })
@@ -1,20 +1,16 @@
1
- import {isPortableTextBlock, isPortableTextSpan} from '@portabletext/toolkit'
2
- import type {PortableTextBlock} from '@sanity/types'
1
+ import type {EditorContext} from '../editor/editor-snapshot'
3
2
  import type {EditorSelection, EditorSelectionPoint} from '../types/editor'
3
+ import {isSpan, isTextBlock} from './parse-blocks'
4
4
 
5
5
  export function getEditorSelection(
6
- blocks: Array<PortableTextBlock> | undefined,
6
+ context: Pick<EditorContext, 'schema' | 'value'>,
7
7
  ): EditorSelection {
8
- if (!blocks) {
9
- throw new Error('No value found')
10
- }
11
-
12
8
  let anchor: EditorSelectionPoint | undefined
13
9
  let focus: EditorSelectionPoint | undefined
14
- const firstBlock = blocks[0]
15
- const lastBlock = blocks[blocks.length - 1]
10
+ const firstBlock = context.value[0]
11
+ const lastBlock = context.value[context.value.length - 1]
16
12
 
17
- if (isPortableTextBlock(firstBlock)) {
13
+ if (isTextBlock(context, firstBlock)) {
18
14
  anchor = {
19
15
  path: [
20
16
  {_key: firstBlock._key},
@@ -30,13 +26,13 @@ export function getEditorSelection(
30
26
  }
31
27
  }
32
28
 
33
- const lastChild = isPortableTextBlock(lastBlock)
29
+ const lastChild = isTextBlock(context, lastBlock)
34
30
  ? lastBlock.children[lastBlock.children.length - 1]
35
31
  : undefined
36
32
  if (
37
- isPortableTextBlock(lastBlock) &&
33
+ isTextBlock(context, lastBlock) &&
38
34
  lastChild &&
39
- isPortableTextSpan(lastChild)
35
+ isSpan(context, lastChild)
40
36
  ) {
41
37
  focus = {
42
38
  path: [{_key: lastBlock._key}, 'children', {_key: lastChild._key}],
@@ -1,21 +1,19 @@
1
- import {isPortableTextBlock, isPortableTextSpan} from '@portabletext/toolkit'
2
- import type {PortableTextBlock} from '@sanity/types'
1
+ import type {EditorContext} from '../editor/editor-snapshot'
3
2
  import {
4
3
  getBlockKeyFromSelectionPoint,
5
4
  getChildKeyFromSelectionPoint,
6
5
  } from '../selection/selection-point'
7
- import type {EditorSelection} from '../types/editor'
6
+ import {isSpan, isTextBlock} from './parse-blocks'
8
7
 
9
8
  export function getSelectionFocusText(
10
- value: Array<PortableTextBlock> | undefined,
11
- selection: EditorSelection,
9
+ context: Pick<EditorContext, 'schema' | 'value' | 'selection'>,
12
10
  ) {
13
- if (!value || !selection) {
11
+ if (!context.selection) {
14
12
  return undefined
15
13
  }
16
14
 
17
- const focusBlockKey = getBlockKeyFromSelectionPoint(selection.focus)
18
- const focusChildKey = getChildKeyFromSelectionPoint(selection.focus)
15
+ const focusBlockKey = getBlockKeyFromSelectionPoint(context.selection.focus)
16
+ const focusChildKey = getChildKeyFromSelectionPoint(context.selection.focus)
19
17
 
20
18
  if (focusBlockKey === undefined || focusChildKey === undefined) {
21
19
  return undefined
@@ -23,11 +21,11 @@ export function getSelectionFocusText(
23
21
 
24
22
  let text: string | undefined
25
23
 
26
- for (const block of value) {
27
- if (isPortableTextBlock(block)) {
24
+ for (const block of context.value) {
25
+ if (isTextBlock(context, block)) {
28
26
  if (block._key === focusBlockKey) {
29
27
  for (const child of block.children) {
30
- if (isPortableTextSpan(child)) {
28
+ if (isSpan(context, child)) {
31
29
  if (child._key === focusChildKey) {
32
30
  text = child.text
33
31
  break
@@ -1,7 +1,9 @@
1
+ import {compileSchema, defineSchema} from '@portabletext/schema'
1
2
  import {expect, test} from 'vitest'
2
3
  import {getSelectionText} from './selection-text'
3
4
 
4
5
  test(getSelectionText.name, () => {
6
+ const schema = compileSchema(defineSchema({}))
5
7
  const splitBlock = {
6
8
  _type: 'block',
7
9
  _key: 'A-4',
@@ -15,9 +17,13 @@ test(getSelectionText.name, () => {
15
17
  }
16
18
 
17
19
  expect(
18
- getSelectionText([splitBlock], {
19
- anchor: {path: [{_key: 'A-4'}, 'children', {_key: 'A-7'}], offset: 0},
20
- focus: {path: [{_key: 'A-4'}, 'children', {_key: 'A-7'}], offset: 3},
20
+ getSelectionText({
21
+ schema,
22
+ value: [splitBlock],
23
+ selection: {
24
+ anchor: {path: [{_key: 'A-4'}, 'children', {_key: 'A-7'}], offset: 0},
25
+ focus: {path: [{_key: 'A-4'}, 'children', {_key: 'A-7'}], offset: 3},
26
+ },
21
27
  }),
22
28
  ).toEqual(['bar'])
23
29
  })
@@ -1,21 +1,18 @@
1
- import {compileSchema, defineSchema} from '@portabletext/schema'
2
- import type {PortableTextBlock} from '@sanity/types'
3
- import type {EditorSelection} from '../types/editor'
1
+ import type {EditorContext} from '../editor/editor-snapshot'
4
2
  import {sliceBlocks} from '../utils/util.slice-blocks'
5
3
  import {getTersePt} from './terse-pt'
6
4
 
7
5
  export function getSelectionText(
8
- value: Array<PortableTextBlock> | undefined,
9
- selection: EditorSelection,
6
+ context: Pick<EditorContext, 'schema' | 'value' | 'selection'>,
10
7
  ) {
11
- if (!value || !selection) {
8
+ if (!context.selection) {
12
9
  return []
13
10
  }
14
11
 
15
12
  const slice = sliceBlocks({
16
- context: {schema: compileSchema(defineSchema({})), selection},
17
- blocks: value,
13
+ context: {schema: context.schema, selection: context.selection},
14
+ blocks: context.value,
18
15
  })
19
16
 
20
- return getTersePt(slice)
17
+ return getTersePt({schema: context.schema, value: slice})
21
18
  }
@@ -6,6 +6,7 @@ import {getTersePt, parseTersePt, parseTersePtString} from './terse-pt'
6
6
  const keyGenerator = createTestKeyGenerator()
7
7
 
8
8
  test(getTersePt.name, () => {
9
+ const schema = compileSchema(defineSchema({}))
9
10
  const fooBlock = {
10
11
  _key: 'b1',
11
12
  _type: 'block',
@@ -27,66 +28,88 @@ test(getTersePt.name, () => {
27
28
  children: [{_key: 's4', _type: 'span', text: 'foo\nbar'}],
28
29
  }
29
30
 
30
- expect(getTersePt([fooBlock, barBlock])).toEqual(['foo', 'bar'])
31
- expect(getTersePt([emptyBlock, barBlock])).toEqual(['', 'bar'])
32
- expect(getTersePt([fooBlock, emptyBlock, barBlock])).toEqual([
31
+ expect(getTersePt({schema, value: [fooBlock, barBlock]})).toEqual([
33
32
  'foo',
33
+ 'bar',
34
+ ])
35
+ expect(getTersePt({schema, value: [emptyBlock, barBlock]})).toEqual([
34
36
  '',
35
37
  'bar',
36
38
  ])
37
- expect(getTersePt([fooBlock, softReturnBlock])).toEqual(['foo', 'foo\nbar'])
39
+ expect(getTersePt({schema, value: [fooBlock, emptyBlock, barBlock]})).toEqual(
40
+ ['foo', '', 'bar'],
41
+ )
42
+ expect(getTersePt({schema, value: [fooBlock, softReturnBlock]})).toEqual([
43
+ 'foo',
44
+ 'foo\nbar',
45
+ ])
38
46
 
39
47
  expect(
40
- getTersePt([
41
- {
42
- _key: keyGenerator(),
43
- _type: 'block',
44
- children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
45
- },
46
- ]),
48
+ getTersePt({
49
+ schema,
50
+ value: [
51
+ {
52
+ _key: keyGenerator(),
53
+ _type: 'block',
54
+ children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
55
+ },
56
+ ],
57
+ }),
47
58
  ).toEqual(['foo'])
48
59
  expect(
49
- getTersePt([
50
- {
51
- _key: keyGenerator(),
52
- _type: 'block',
53
- children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
54
- listItem: 'number',
55
- },
56
- ]),
60
+ getTersePt({
61
+ schema,
62
+ value: [
63
+ {
64
+ _key: keyGenerator(),
65
+ _type: 'block',
66
+ children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
67
+ listItem: 'number',
68
+ },
69
+ ],
70
+ }),
57
71
  ).toEqual(['#:foo'])
58
72
  expect(
59
- getTersePt([
60
- {
61
- _key: keyGenerator(),
62
- _type: 'block',
63
- children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
64
- listItem: 'number',
65
- style: 'h3',
66
- },
67
- ]),
73
+ getTersePt({
74
+ schema,
75
+ value: [
76
+ {
77
+ _key: keyGenerator(),
78
+ _type: 'block',
79
+ children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
80
+ listItem: 'number',
81
+ style: 'h3',
82
+ },
83
+ ],
84
+ }),
68
85
  ).toEqual(['#h3:foo'])
69
86
  expect(
70
- getTersePt([
71
- {
72
- _key: keyGenerator(),
73
- _type: 'block',
74
- children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
75
- level: 2,
76
- listItem: 'number',
77
- style: 'h3',
78
- },
79
- ]),
87
+ getTersePt({
88
+ schema,
89
+ value: [
90
+ {
91
+ _key: keyGenerator(),
92
+ _type: 'block',
93
+ children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
94
+ level: 2,
95
+ listItem: 'number',
96
+ style: 'h3',
97
+ },
98
+ ],
99
+ }),
80
100
  ).toEqual(['>>#h3:foo'])
81
101
  expect(
82
- getTersePt([
83
- {
84
- _key: keyGenerator(),
85
- _type: 'block',
86
- children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
87
- style: 'h3',
88
- },
89
- ]),
102
+ getTersePt({
103
+ schema,
104
+ value: [
105
+ {
106
+ _key: keyGenerator(),
107
+ _type: 'block',
108
+ children: [{_key: keyGenerator(), _type: 'span', text: 'foo'}],
109
+ style: 'h3',
110
+ },
111
+ ],
112
+ }),
90
113
  ).toEqual(['h3:foo'])
91
114
  })
92
115
 
@@ -1,6 +1,6 @@
1
- import {isPortableTextBlock, isPortableTextSpan} from '@portabletext/toolkit'
2
1
  import type {PortableTextBlock, PortableTextTextBlock} from '@sanity/types'
3
2
  import type {EditorContext} from '../editor/editor-snapshot'
3
+ import {isSpan, isTextBlock} from './parse-blocks'
4
4
 
5
5
  type TersePtConfig = {
6
6
  style: (name?: string) => string
@@ -20,18 +20,14 @@ const defaultConfig: TersePtConfig = {
20
20
  }
21
21
 
22
22
  export function getTersePt(
23
- value: Array<PortableTextBlock> | undefined,
23
+ context: Pick<EditorContext, 'schema' | 'value'>,
24
24
  ): Array<string> {
25
- if (!value) {
26
- return []
27
- }
28
-
29
25
  const blocks: Array<string> = []
30
26
 
31
- for (const block of value) {
27
+ for (const block of context.value) {
32
28
  let terseBlock = ''
33
29
 
34
- if (isPortableTextBlock(block)) {
30
+ if (isTextBlock(context, block)) {
35
31
  const blockPrefix = `${defaultConfig.level(block.level)}${defaultConfig.listItem(block.listItem)}${defaultConfig.style(block.style)}`
36
32
 
37
33
  if (blockPrefix) {
@@ -42,7 +38,7 @@ export function getTersePt(
42
38
  for (const child of block.children) {
43
39
  index++
44
40
 
45
- if (isPortableTextSpan(child)) {
41
+ if (isSpan(context, child)) {
46
42
  terseBlock = `${terseBlock}${index > 0 ? ',' : ''}${child.text}`
47
43
  } else {
48
44
  terseBlock = `${terseBlock}${index > 0 ? ',' : ''}{${child._type}}`
@@ -1,7 +1,9 @@
1
+ import {compileSchema, defineSchema} from '@portabletext/schema'
1
2
  import {expect, test} from 'vitest'
2
3
  import {getTextBlockKey} from './text-block-key'
3
4
 
4
5
  test(getTextBlockKey.name, () => {
6
+ const schema = compileSchema(defineSchema({}))
5
7
  const emptyBlock = {
6
8
  _key: 'b1',
7
9
  _type: 'block',
@@ -18,13 +20,22 @@ test(getTextBlockKey.name, () => {
18
20
  children: [{_key: 's3', _type: 'span', text: 'foo\nbar'}],
19
21
  }
20
22
 
21
- expect(getTextBlockKey([emptyBlock, fooBlock, softReturnBlock], '')).toBe(
22
- 'b1',
23
- )
24
- expect(getTextBlockKey([emptyBlock, fooBlock, softReturnBlock], 'foo')).toBe(
25
- 'b2',
26
- )
27
23
  expect(
28
- getTextBlockKey([emptyBlock, fooBlock, softReturnBlock], 'foo\nbar'),
24
+ getTextBlockKey(
25
+ {schema, value: [emptyBlock, fooBlock, softReturnBlock]},
26
+ '',
27
+ ),
28
+ ).toBe('b1')
29
+ expect(
30
+ getTextBlockKey(
31
+ {schema, value: [emptyBlock, fooBlock, softReturnBlock]},
32
+ 'foo',
33
+ ),
34
+ ).toBe('b2')
35
+ expect(
36
+ getTextBlockKey(
37
+ {schema, value: [emptyBlock, fooBlock, softReturnBlock]},
38
+ 'foo\nbar',
39
+ ),
29
40
  ).toBe('b3')
30
41
  })
@@ -1,20 +1,16 @@
1
- import {isPortableTextBlock} from '@portabletext/toolkit'
2
- import {isPortableTextSpan, type PortableTextBlock} from '@sanity/types'
1
+ import type {EditorContext} from '../editor/editor-snapshot'
2
+ import {isSpan, isTextBlock} from './parse-blocks'
3
3
 
4
4
  export function getTextBlockKey(
5
- value: Array<PortableTextBlock> | undefined,
5
+ context: Pick<EditorContext, 'schema' | 'value'>,
6
6
  text: string,
7
7
  ) {
8
- if (!value) {
9
- throw new Error(`Unable to find block key for text "${text}"`)
10
- }
11
-
12
8
  let blockKey: string | undefined
13
9
 
14
- for (const block of value) {
15
- if (isPortableTextBlock(block)) {
10
+ for (const block of context.value) {
11
+ if (isTextBlock(context, block)) {
16
12
  for (const child of block.children) {
17
- if (isPortableTextSpan(child) && child.text === text) {
13
+ if (isSpan(context, child) && child.text === text) {
18
14
  blockKey = block._key
19
15
  break
20
16
  }
@@ -1,7 +1,9 @@
1
+ import {compileSchema, defineSchema} from '@portabletext/schema'
1
2
  import {expect, test} from 'vitest'
2
3
  import {getTextMarks} from './text-marks'
3
4
 
4
5
  test(getTextMarks.name, () => {
6
+ const schema = compileSchema(defineSchema({}))
5
7
  const fooBlock = {
6
8
  _key: 'b1',
7
9
  _type: 'block',
@@ -26,8 +28,14 @@ test(getTextMarks.name, () => {
26
28
  ],
27
29
  }
28
30
 
29
- expect(getTextMarks([fooBlock, splitBarBlock], 'ba')).toEqual(['strong'])
30
- expect(getTextMarks([splitFooBarBazBlock], 'bar')).toEqual(['strong'])
31
- expect(getTextMarks([splitFooBarBazBlock], ' ')).toEqual([])
32
- expect(getTextMarks([splitFooBarBazBlock], 'baz')).toEqual(['l1'])
31
+ expect(
32
+ getTextMarks({schema, value: [fooBlock, splitBarBlock]}, 'ba'),
33
+ ).toEqual(['strong'])
34
+ expect(getTextMarks({schema, value: [splitFooBarBazBlock]}, 'bar')).toEqual([
35
+ 'strong',
36
+ ])
37
+ expect(getTextMarks({schema, value: [splitFooBarBazBlock]}, ' ')).toEqual([])
38
+ expect(getTextMarks({schema, value: [splitFooBarBazBlock]}, 'baz')).toEqual([
39
+ 'l1',
40
+ ])
33
41
  })