@portabletext/editor 1.15.2 → 1.16.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 (82) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs +30 -28
  2. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  3. package/lib/_chunks-cjs/selector.get-text-before.cjs +14 -14
  4. package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
  5. package/lib/_chunks-cjs/{selectors.cjs → selector.is-selection-collapsed.cjs} +8 -8
  6. package/lib/_chunks-cjs/selector.is-selection-collapsed.cjs.map +1 -0
  7. package/lib/_chunks-es/behavior.core.js +12 -10
  8. package/lib/_chunks-es/behavior.core.js.map +1 -1
  9. package/lib/_chunks-es/selector.get-text-before.js +14 -14
  10. package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
  11. package/lib/_chunks-es/{selectors.js → selector.is-selection-collapsed.js} +8 -8
  12. package/lib/_chunks-es/selector.is-selection-collapsed.js.map +1 -0
  13. package/lib/behaviors/index.cjs +35 -35
  14. package/lib/behaviors/index.cjs.map +1 -1
  15. package/lib/behaviors/index.d.cts +40 -45
  16. package/lib/behaviors/index.d.ts +40 -45
  17. package/lib/behaviors/index.js +20 -20
  18. package/lib/behaviors/index.js.map +1 -1
  19. package/lib/index.cjs +868 -542
  20. package/lib/index.cjs.map +1 -1
  21. package/lib/index.d.cts +3791 -4503
  22. package/lib/index.d.ts +3791 -4503
  23. package/lib/index.js +865 -541
  24. package/lib/index.js.map +1 -1
  25. package/lib/selectors/index.cjs +166 -16
  26. package/lib/selectors/index.cjs.map +1 -1
  27. package/lib/selectors/index.d.cts +62 -17
  28. package/lib/selectors/index.d.ts +62 -17
  29. package/lib/selectors/index.js +154 -3
  30. package/lib/selectors/index.js.map +1 -1
  31. package/package.json +11 -11
  32. package/src/behavior-actions/behavior.action-utils.insert-block.ts +3 -5
  33. package/src/behavior-actions/behavior.actions.ts +6 -6
  34. package/src/behavior-actions/behavior.guards.ts +2 -6
  35. package/src/behaviors/behavior.code-editor.ts +5 -9
  36. package/src/behaviors/behavior.core.block-objects.ts +14 -20
  37. package/src/behaviors/behavior.core.lists.ts +13 -19
  38. package/src/behaviors/behavior.links.ts +6 -6
  39. package/src/behaviors/behavior.markdown.ts +27 -40
  40. package/src/behaviors/behavior.types.ts +7 -7
  41. package/src/behaviors/index.ts +1 -0
  42. package/src/editor/Editable.tsx +11 -4
  43. package/src/editor/PortableTextEditor.tsx +4 -5
  44. package/src/editor/{hooks/useSyncValue.test.tsx → __tests__/sync-value.test.tsx} +42 -23
  45. package/src/editor/components/Synchronizer.tsx +53 -80
  46. package/src/{utils/getPortableTextMemberSchemaTypes.ts → editor/create-editor-schema.ts} +3 -3
  47. package/src/editor/create-editor.ts +2 -2
  48. package/src/editor/define-schema.ts +8 -3
  49. package/src/editor/editor-machine.ts +136 -104
  50. package/src/editor/editor-provider.tsx +0 -3
  51. package/src/editor/editor-selector.ts +6 -13
  52. package/src/editor/editor-snapshot.ts +5 -6
  53. package/src/editor/get-active-decorators.ts +20 -0
  54. package/src/editor/mutation-machine.ts +100 -0
  55. package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +21 -15
  56. package/src/editor/plugins/createWithMaxBlocks.ts +1 -1
  57. package/src/editor/plugins/createWithPatches.ts +0 -4
  58. package/src/editor/plugins/createWithPlaceholderBlock.ts +1 -1
  59. package/src/editor/plugins/createWithPortableTextSelections.ts +4 -1
  60. package/src/editor/plugins/createWithUndoRedo.ts +3 -3
  61. package/src/editor/sync-machine.ts +657 -0
  62. package/src/editor/withSyncRangeDecorations.ts +17 -5
  63. package/src/index.ts +3 -5
  64. package/src/selectors/_exports/index.ts +1 -0
  65. package/src/selectors/index.ts +10 -4
  66. package/src/selectors/selector.get-active-style.ts +37 -0
  67. package/src/selectors/selector.get-selected-spans.ts +136 -0
  68. package/src/selectors/selector.is-active-annotation.ts +49 -0
  69. package/src/selectors/selector.is-active-decorator.ts +21 -0
  70. package/src/selectors/selector.is-active-list-item.ts +13 -0
  71. package/src/selectors/selector.is-active-style.ts +13 -0
  72. package/src/selectors/selector.is-selection-collapsed.ts +12 -0
  73. package/src/selectors/selector.is-selection-expanded.ts +9 -0
  74. package/src/selectors/selectors.ts +0 -11
  75. package/src/utils/__tests__/operationToPatches.test.ts +2 -2
  76. package/src/utils/__tests__/patchToOperations.test.ts +2 -2
  77. package/src/utils/__tests__/values.test.ts +2 -2
  78. package/src/utils/weakMaps.ts +0 -3
  79. package/src/utils/withChanges.ts +1 -8
  80. package/lib/_chunks-cjs/selectors.cjs.map +0 -1
  81. package/lib/_chunks-es/selectors.js.map +0 -1
  82. package/src/editor/hooks/useSyncValue.ts +0 -426
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/selectors/selector.get-active-list-item.ts"],"sourcesContent":["import type {PortableTextListBlock} from '@sanity/types'\nimport {createGuards} from '../behavior-actions/behavior.guards'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport {getSelectedBlocks} from './selectors'\n\n/**\n * @alpha\n */\nexport const getActiveListItem: EditorSelector<\n PortableTextListBlock['listItem'] | undefined\n> = ({context}) => {\n if (!context.selection) {\n return undefined\n }\n\n const guards = createGuards(context)\n const selectedBlocks = getSelectedBlocks({context}).map((block) => block.node)\n const selectedTextBlocks = selectedBlocks.filter(guards.isTextBlock)\n\n const firstTextBlock = selectedTextBlocks.at(0)\n\n if (!firstTextBlock) {\n return undefined\n }\n\n const firstListItem = firstTextBlock.listItem\n\n if (!firstListItem) {\n return undefined\n }\n\n if (selectedTextBlocks.every((block) => block.listItem === firstListItem)) {\n return firstListItem\n }\n\n return undefined\n}\n"],"names":["getActiveListItem","context","selection","guards","createGuards","selectedTextBlocks","getSelectedBlocks","map","block","node","filter","isTextBlock","firstTextBlock","at","firstListItem","listItem","every"],"mappings":";;;AAQO,MAAMA,oBAETA,CAAC;AAAA,EAACC;AAAO,MAAM;AACjB,MAAI,CAACA,QAAQC;AACX;AAGF,QAAMC,SAASC,aAAaH,OAAO,GAE7BI,qBADiBC,kBAAkB;AAAA,IAACL;AAAAA,EAAQ,CAAA,EAAEM,IAAKC,CAAAA,UAAUA,MAAMC,IAAI,EACnCC,OAAOP,OAAOQ,WAAW,GAE7DC,iBAAiBP,mBAAmBQ,GAAG,CAAC;AAE9C,MAAI,CAACD;AACH;AAGF,QAAME,gBAAgBF,eAAeG;AAErC,MAAKD,iBAIDT,mBAAmBW,MAAOR,CAAUA,UAAAA,MAAMO,aAAaD,aAAa;AAC/DA,WAAAA;AAIX;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/selectors/selector.get-active-list-item.ts","../../src/selectors/selector.get-active-style.ts","../../src/selectors/selector.get-selected-spans.ts","../../src/selectors/selector.is-active-annotation.ts","../../src/selectors/selector.is-selection-expanded.ts","../../src/selectors/selector.is-active-decorator.ts","../../src/selectors/selector.is-active-list-item.ts","../../src/selectors/selector.is-active-style.ts"],"sourcesContent":["import type {PortableTextListBlock} from '@sanity/types'\nimport {createGuards} from '../behavior-actions/behavior.guards'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport {getSelectedBlocks} from './selectors'\n\n/**\n * @alpha\n */\nexport const getActiveListItem: EditorSelector<\n PortableTextListBlock['listItem'] | undefined\n> = ({context}) => {\n if (!context.selection) {\n return undefined\n }\n\n const guards = createGuards(context)\n const selectedBlocks = getSelectedBlocks({context}).map((block) => block.node)\n const selectedTextBlocks = selectedBlocks.filter(guards.isTextBlock)\n\n const firstTextBlock = selectedTextBlocks.at(0)\n\n if (!firstTextBlock) {\n return undefined\n }\n\n const firstListItem = firstTextBlock.listItem\n\n if (!firstListItem) {\n return undefined\n }\n\n if (selectedTextBlocks.every((block) => block.listItem === firstListItem)) {\n return firstListItem\n }\n\n return undefined\n}\n","import type {PortableTextTextBlock} from '@sanity/types'\nimport {createGuards} from '../behavior-actions/behavior.guards'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport {getSelectedBlocks} from './selectors'\n\n/**\n * @alpha\n */\nexport const getActiveStyle: EditorSelector<PortableTextTextBlock['style']> = ({\n context,\n}) => {\n if (!context.selection) {\n return undefined\n }\n\n const guards = createGuards(context)\n const selectedBlocks = getSelectedBlocks({context}).map((block) => block.node)\n const selectedTextBlocks = selectedBlocks.filter(guards.isTextBlock)\n\n const firstTextBlock = selectedTextBlocks.at(0)\n\n if (!firstTextBlock) {\n return undefined\n }\n\n const firstStyle = firstTextBlock.style\n\n if (!firstStyle) {\n return undefined\n }\n\n if (selectedTextBlocks.every((block) => block.style === firstStyle)) {\n return firstStyle\n }\n\n return undefined\n}\n","import {\n isKeySegment,\n isPortableTextSpan,\n isPortableTextTextBlock,\n type KeyedSegment,\n type PortableTextSpan,\n} from '@sanity/types'\nimport type {EditorSelector} from '../editor/editor-selector'\n\n/**\n * @alpha\n */\nexport const getSelectedSpans: EditorSelector<\n Array<{\n node: PortableTextSpan\n path: [KeyedSegment, 'children', KeyedSegment]\n }>\n> = ({context}) => {\n if (!context.selection) {\n return []\n }\n\n const selectedSpans: Array<{\n node: PortableTextSpan\n path: [KeyedSegment, 'children', KeyedSegment]\n }> = []\n\n const startPoint = context.selection.backward\n ? context.selection.focus\n : context.selection.anchor\n const endPoint = context.selection.backward\n ? context.selection.anchor\n : context.selection.focus\n\n const startBlockKey = isKeySegment(startPoint.path[0])\n ? startPoint.path[0]._key\n : undefined\n const endBlockKey = isKeySegment(endPoint.path[0])\n ? endPoint.path[0]._key\n : undefined\n\n if (!startBlockKey || !endBlockKey) {\n return selectedSpans\n }\n\n const startSpanKey = isKeySegment(startPoint.path[2])\n ? startPoint.path[2]._key\n : undefined\n const endSpanKey = isKeySegment(endPoint.path[2])\n ? endPoint.path[2]._key\n : undefined\n\n for (const block of context.value) {\n if (!isPortableTextTextBlock(block)) {\n continue\n }\n\n if (block._key === startBlockKey) {\n for (const child of block.children) {\n if (!isPortableTextSpan(child)) {\n continue\n }\n\n if (startSpanKey && child._key === startSpanKey) {\n selectedSpans.push({\n node: child,\n path: [{_key: block._key}, 'children', {_key: child._key}],\n })\n\n if (startBlockKey === endBlockKey) {\n break\n }\n }\n\n if (endSpanKey && child._key === endSpanKey) {\n selectedSpans.push({\n node: child,\n path: [{_key: block._key}, 'children', {_key: child._key}],\n })\n break\n }\n\n if (selectedSpans.length > 0) {\n selectedSpans.push({\n node: child,\n path: [{_key: block._key}, 'children', {_key: child._key}],\n })\n }\n }\n\n if (startBlockKey === endBlockKey) {\n break\n }\n\n continue\n }\n\n if (block._key === endBlockKey) {\n for (const child of block.children) {\n if (!isPortableTextSpan(child)) {\n continue\n }\n\n if (endSpanKey && child._key === endSpanKey) {\n selectedSpans.push({\n node: child,\n path: [{_key: block._key}, 'children', {_key: child._key}],\n })\n break\n }\n\n selectedSpans.push({\n node: child,\n path: [{_key: block._key}, 'children', {_key: child._key}],\n })\n }\n\n break\n }\n\n if (selectedSpans.length > 0) {\n for (const child of block.children) {\n if (!isPortableTextSpan(child)) {\n continue\n }\n\n selectedSpans.push({\n node: child,\n path: [{_key: block._key}, 'children', {_key: child._key}],\n })\n }\n }\n }\n\n return selectedSpans\n}\n","import {isPortableTextTextBlock} from '@sanity/types'\nimport type {EditorSelector} from '../editor/editor-selector'\nimport {getSelectedSpans} from './selector.get-selected-spans'\nimport {getSelectedBlocks} from './selectors'\n\n/**\n * @alpha\n */\nexport function isActiveAnnotation(\n annotation: string,\n): EditorSelector<boolean> {\n return (snapshot) => {\n if (!snapshot.context.selection) {\n return false\n }\n\n const selectedBlocks = getSelectedBlocks(snapshot)\n const selectedSpans = getSelectedSpans(snapshot)\n\n if (selectedSpans.length === 0) {\n return false\n }\n\n if (\n selectedSpans.some(\n (span) => !span.node.marks || span.node.marks?.length === 0,\n )\n ) {\n return false\n }\n\n const selectionMarkDefs = selectedBlocks.flatMap((block) =>\n isPortableTextTextBlock(block.node) ? (block.node.markDefs ?? []) : [],\n )\n\n return selectedSpans.every((span) => {\n const spanMarkDefs =\n span.node.marks?.flatMap((mark) => {\n const markDef = selectionMarkDefs.find(\n (markDef) => markDef._key === mark,\n )\n\n return markDef ? [markDef._type] : []\n }) ?? []\n\n return spanMarkDefs.includes(annotation)\n })\n }\n}\n","import type {EditorSelector} from '../editor/editor-selector'\nimport {isSelectionCollapsed} from './selector.is-selection-collapsed'\n\n/**\n * @alpha\n */\nexport const isSelectionExpanded: EditorSelector<boolean> = ({context}) => {\n return !isSelectionCollapsed({context})\n}\n","import type {EditorSelector} from '../editor/editor-selector'\nimport {getSelectedSpans} from './selector.get-selected-spans'\nimport {isSelectionExpanded} from './selector.is-selection-expanded'\n\n/**\n * @alpha\n */\nexport function isActiveDecorator(decorator: string): EditorSelector<boolean> {\n return (snapshot) => {\n if (isSelectionExpanded(snapshot)) {\n const selectedSpans = getSelectedSpans(snapshot)\n\n return (\n selectedSpans.length > 0 &&\n selectedSpans.every((span) => span.node.marks?.includes(decorator))\n )\n }\n\n return snapshot.context.activeDecorators.includes(decorator)\n }\n}\n","import type {EditorSelector} from '../editor/editor-selector'\nimport {getActiveListItem} from './selector.get-active-list-item'\n\n/**\n * @alpha\n */\nexport function isActiveListItem(listItem: string): EditorSelector<boolean> {\n return (snapshot) => {\n const activeListItem = getActiveListItem(snapshot)\n\n return activeListItem === listItem\n }\n}\n","import type {EditorSelector} from '../editor/editor-selector'\nimport {getActiveStyle} from './selector.get-active-style'\n\n/**\n * @alpha\n */\nexport function isActiveStyle(style: string): EditorSelector<boolean> {\n return (snapshot) => {\n const activeStyle = getActiveStyle(snapshot)\n\n return activeStyle === style\n }\n}\n"],"names":["getActiveListItem","context","selection","guards","createGuards","selectedTextBlocks","getSelectedBlocks","map","block","node","filter","isTextBlock","firstTextBlock","at","firstListItem","listItem","every","getActiveStyle","firstStyle","style","getSelectedSpans","selectedSpans","startPoint","backward","focus","anchor","endPoint","startBlockKey","isKeySegment","path","_key","undefined","endBlockKey","startSpanKey","endSpanKey","value","isPortableTextTextBlock","child","children","isPortableTextSpan","push","length","isActiveAnnotation","annotation","snapshot","selectedBlocks","some","span","marks","selectionMarkDefs","flatMap","markDefs","mark","markDef","find","_type","includes","isSelectionExpanded","isSelectionCollapsed","isActiveDecorator","decorator","activeDecorators","isActiveListItem","isActiveStyle"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "1.15.2",
3
+ "version": "1.16.0",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -40,7 +40,7 @@
40
40
  "default": "./lib/behaviors/index.js"
41
41
  },
42
42
  "./selectors": {
43
- "source": "./src/selectors/index.ts",
43
+ "source": "./src/selectors/_exports/index.ts",
44
44
  "import": "./lib/selectors/index.js",
45
45
  "require": "./lib/selectors/index.cjs",
46
46
  "default": "./lib/selectors/index.js"
@@ -70,18 +70,18 @@
70
70
  },
71
71
  "devDependencies": {
72
72
  "@portabletext/toolkit": "^2.0.16",
73
- "@sanity/block-tools": "^3.66.1",
73
+ "@sanity/block-tools": "^3.67.1",
74
74
  "@sanity/diff-match-patch": "^3.1.1",
75
- "@sanity/pkg-utils": "^6.11.14",
76
- "@sanity/schema": "^3.66.1",
77
- "@sanity/types": "^3.66.1",
75
+ "@sanity/pkg-utils": "^6.12.0",
76
+ "@sanity/schema": "^3.67.1",
77
+ "@sanity/types": "^3.67.1",
78
78
  "@testing-library/jest-dom": "^6.6.3",
79
79
  "@testing-library/react": "^16.1.0",
80
80
  "@types/debug": "^4.1.5",
81
81
  "@types/lodash": "^4.17.13",
82
82
  "@types/lodash.startcase": "^4.4.9",
83
83
  "@types/react": "^19.0.1",
84
- "@types/react-dom": "^19.0.1",
84
+ "@types/react-dom": "^19.0.2",
85
85
  "@typescript-eslint/eslint-plugin": "^8.17.0",
86
86
  "@typescript-eslint/parser": "^8.17.0",
87
87
  "@vitejs/plugin-react": "^4.3.4",
@@ -100,12 +100,12 @@
100
100
  "vite": "^6.0.3",
101
101
  "vitest": "^2.1.8",
102
102
  "vitest-browser-react": "^0.0.4",
103
- "racejar": "1.1.0"
103
+ "racejar": "1.1.1"
104
104
  },
105
105
  "peerDependencies": {
106
- "@sanity/block-tools": "^3.66.1",
107
- "@sanity/schema": "^3.66.1",
108
- "@sanity/types": "^3.66.1",
106
+ "@sanity/block-tools": "^3.67.1",
107
+ "@sanity/schema": "^3.67.1",
108
+ "@sanity/types": "^3.67.1",
109
109
  "react": "^16.9 || ^17 || ^18 || ^19",
110
110
  "rxjs": "^7.8.1",
111
111
  "styled-components": "^6.1.13"
@@ -1,8 +1,6 @@
1
1
  import {Editor, Transforms, type Descendant} from 'slate'
2
- import type {
3
- PortableTextMemberSchemaTypes,
4
- PortableTextSlateEditor,
5
- } from '../types/editor'
2
+ import type {EditorSchema} from '../editor/define-schema'
3
+ import type {PortableTextSlateEditor} from '../types/editor'
6
4
  import {isEqualToEmptyEditor} from '../utils/values'
7
5
 
8
6
  export function insertBlock({
@@ -14,7 +12,7 @@ export function insertBlock({
14
12
  block: Descendant
15
13
  placement: 'auto' | 'after' | 'before'
16
14
  editor: PortableTextSlateEditor
17
- schema: PortableTextMemberSchemaTypes
15
+ schema: EditorSchema
18
16
  }) {
19
17
  if (!editor.selection) {
20
18
  const lastBlock = Array.from(
@@ -233,7 +233,7 @@ const behaviorActionImplementations: BehaviorActionImplementations = {
233
233
  Transforms.deselect(action.editor)
234
234
  }
235
235
  },
236
- 'select previous block': ({action}) => {
236
+ 'select.previous block': ({action}) => {
237
237
  if (!action.editor.selection) {
238
238
  console.error('Unable to select previous block without a selection')
239
239
  return
@@ -250,7 +250,7 @@ const behaviorActionImplementations: BehaviorActionImplementations = {
250
250
 
251
251
  Transforms.select(action.editor, previousBlockPath)
252
252
  },
253
- 'select next block': ({action}) => {
253
+ 'select.next block': ({action}) => {
254
254
  if (!action.editor.selection) {
255
255
  console.error('Unable to select next block without a selection')
256
256
  return
@@ -370,15 +370,15 @@ export function performAction({
370
370
  })
371
371
  break
372
372
  }
373
- case 'select previous block': {
374
- behaviorActionImplementations['select previous block']({
373
+ case 'select.previous block': {
374
+ behaviorActionImplementations['select.previous block']({
375
375
  context,
376
376
  action,
377
377
  })
378
378
  break
379
379
  }
380
- case 'select next block': {
381
- behaviorActionImplementations['select next block']({
380
+ case 'select.next block': {
381
+ behaviorActionImplementations['select.next block']({
382
382
  context,
383
383
  action,
384
384
  })
@@ -4,18 +4,14 @@ import {
4
4
  type PortableTextListBlock,
5
5
  type PortableTextTextBlock,
6
6
  } from '@sanity/types'
7
- import type {PortableTextMemberSchemaTypes} from '../types/editor'
7
+ import type {EditorSchema} from '../editor/define-schema'
8
8
 
9
9
  /**
10
10
  * @alpha
11
11
  */
12
12
  export type BehaviorGuards = ReturnType<typeof createGuards>
13
13
 
14
- export function createGuards({
15
- schema,
16
- }: {
17
- schema: PortableTextMemberSchemaTypes
18
- }) {
14
+ export function createGuards({schema}: {schema: EditorSchema}) {
19
15
  function isListBlock(block: unknown): block is PortableTextListBlock {
20
16
  return isPortableTextListBlock(block) && block._type === schema.block.name
21
17
  }
@@ -1,8 +1,4 @@
1
- import {
2
- getFirstBlock,
3
- getLastBlock,
4
- getSelectedBlocks,
5
- } from '../selectors/selectors'
1
+ import * as selectors from '../selectors'
6
2
  import {isHotkey} from '../utils/is-hotkey'
7
3
  import {defineBehavior} from './behavior.types'
8
4
 
@@ -26,8 +22,8 @@ export function createCodeEditorBehaviors(config: CodeEditorBehaviorsConfig) {
26
22
  config.moveBlockUpShortcut,
27
23
  event.keyboardEvent,
28
24
  )
29
- const firstBlock = getFirstBlock({context})
30
- const selectedBlocks = getSelectedBlocks({context})
25
+ const firstBlock = selectors.getFirstBlock({context})
26
+ const selectedBlocks = selectors.getSelectedBlocks({context})
31
27
  const blocksAbove =
32
28
  firstBlock?.node._key !== selectedBlocks[0]?.node._key
33
29
 
@@ -52,8 +48,8 @@ export function createCodeEditorBehaviors(config: CodeEditorBehaviorsConfig) {
52
48
  config.moveBlockDownShortcut,
53
49
  event.keyboardEvent,
54
50
  )
55
- const lastBlock = getLastBlock({context})
56
- const selectedBlocks = getSelectedBlocks({context})
51
+ const lastBlock = selectors.getLastBlock({context})
52
+ const selectedBlocks = selectors.getSelectedBlocks({context})
57
53
  const blocksBelow =
58
54
  lastBlock?.node._key !==
59
55
  selectedBlocks[selectedBlocks.length - 1]?.node._key
@@ -1,12 +1,6 @@
1
1
  import {isPortableTextTextBlock} from '@sanity/types'
2
2
  import {isEmptyTextBlock} from '../editor/utils/utils'
3
- import {
4
- getFocusBlockObject,
5
- getFocusTextBlock,
6
- getNextBlock,
7
- getPreviousBlock,
8
- selectionIsCollapsed,
9
- } from '../selectors/selectors'
3
+ import * as selectors from '../selectors'
10
4
  import {isHotkey} from '../utils/is-hotkey'
11
5
  import {defineBehavior} from './behavior.types'
12
6
 
@@ -14,8 +8,8 @@ const arrowDownOnLonelyBlockObject = defineBehavior({
14
8
  on: 'key.down',
15
9
  guard: ({context, event}) => {
16
10
  const isArrowDown = isHotkey('ArrowDown', event.keyboardEvent)
17
- const focusBlockObject = getFocusBlockObject({context})
18
- const nextBlock = getNextBlock({context})
11
+ const focusBlockObject = selectors.getFocusBlockObject({context})
12
+ const nextBlock = selectors.getNextBlock({context})
19
13
 
20
14
  return isArrowDown && focusBlockObject && !nextBlock
21
15
  },
@@ -26,15 +20,15 @@ const arrowUpOnLonelyBlockObject = defineBehavior({
26
20
  on: 'key.down',
27
21
  guard: ({context, event}) => {
28
22
  const isArrowUp = isHotkey('ArrowUp', event.keyboardEvent)
29
- const focusBlockObject = getFocusBlockObject({context})
30
- const previousBlock = getPreviousBlock({context})
23
+ const focusBlockObject = selectors.getFocusBlockObject({context})
24
+ const previousBlock = selectors.getPreviousBlock({context})
31
25
 
32
26
  return isArrowUp && focusBlockObject && !previousBlock
33
27
  },
34
28
  actions: [
35
29
  () => [
36
30
  {type: 'insert.text block', placement: 'before'},
37
- {type: 'select previous block'},
31
+ {type: 'select.previous block'},
38
32
  ],
39
33
  ],
40
34
  })
@@ -42,8 +36,8 @@ const arrowUpOnLonelyBlockObject = defineBehavior({
42
36
  const breakingBlockObject = defineBehavior({
43
37
  on: 'insert.break',
44
38
  guard: ({context}) => {
45
- const focusBlockObject = getFocusBlockObject({context})
46
- const collapsedSelection = selectionIsCollapsed({context})
39
+ const focusBlockObject = selectors.getFocusBlockObject({context})
40
+ const collapsedSelection = selectors.isSelectionCollapsed({context})
47
41
 
48
42
  return collapsedSelection && focusBlockObject !== undefined
49
43
  },
@@ -53,9 +47,9 @@ const breakingBlockObject = defineBehavior({
53
47
  const deletingEmptyTextBlockAfterBlockObject = defineBehavior({
54
48
  on: 'delete.backward',
55
49
  guard: ({context}) => {
56
- const focusTextBlock = getFocusTextBlock({context})
57
- const selectionCollapsed = selectionIsCollapsed({context})
58
- const previousBlock = getPreviousBlock({context})
50
+ const focusTextBlock = selectors.getFocusTextBlock({context})
51
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
52
+ const previousBlock = selectors.getPreviousBlock({context})
59
53
 
60
54
  if (!focusTextBlock || !selectionCollapsed || !previousBlock) {
61
55
  return false
@@ -90,9 +84,9 @@ const deletingEmptyTextBlockAfterBlockObject = defineBehavior({
90
84
  const deletingEmptyTextBlockBeforeBlockObject = defineBehavior({
91
85
  on: 'delete.forward',
92
86
  guard: ({context}) => {
93
- const focusTextBlock = getFocusTextBlock({context})
94
- const selectionCollapsed = selectionIsCollapsed({context})
95
- const nextBlock = getNextBlock({context})
87
+ const focusTextBlock = selectors.getFocusTextBlock({context})
88
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
89
+ const nextBlock = selectors.getNextBlock({context})
96
90
 
97
91
  if (!focusTextBlock || !selectionCollapsed || !nextBlock) {
98
92
  return false
@@ -1,12 +1,6 @@
1
1
  import {createGuards} from '../behavior-actions/behavior.guards'
2
2
  import {isEmptyTextBlock} from '../editor/utils/utils'
3
- import {
4
- getFocusListBlock,
5
- getFocusSpan,
6
- getFocusTextBlock,
7
- getSelectedBlocks,
8
- selectionIsCollapsed,
9
- } from '../selectors/selectors'
3
+ import * as selectors from '../selectors'
10
4
  import {isHotkey} from '../utils/is-hotkey'
11
5
  import {defineBehavior} from './behavior.types'
12
6
 
@@ -15,9 +9,9 @@ const MAX_LIST_LEVEL = 10
15
9
  const clearListOnBackspace = defineBehavior({
16
10
  on: 'delete.backward',
17
11
  guard: ({context}) => {
18
- const selectionCollapsed = selectionIsCollapsed({context})
19
- const focusTextBlock = getFocusTextBlock({context})
20
- const focusSpan = getFocusSpan({context})
12
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
13
+ const focusTextBlock = selectors.getFocusTextBlock({context})
14
+ const focusSpan = selectors.getFocusSpan({context})
21
15
 
22
16
  if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
23
17
  return false
@@ -25,7 +19,7 @@ const clearListOnBackspace = defineBehavior({
25
19
 
26
20
  const atTheBeginningOfBLock =
27
21
  focusTextBlock.node.children[0]._key === focusSpan.node._key &&
28
- context.selection.focus.offset === 0
22
+ context.selection?.focus.offset === 0
29
23
 
30
24
  if (atTheBeginningOfBLock && focusTextBlock.node.level === 1) {
31
25
  return {focusTextBlock}
@@ -47,9 +41,9 @@ const clearListOnBackspace = defineBehavior({
47
41
  const unindentListOnBackspace = defineBehavior({
48
42
  on: 'delete.backward',
49
43
  guard: ({context}) => {
50
- const selectionCollapsed = selectionIsCollapsed({context})
51
- const focusTextBlock = getFocusTextBlock({context})
52
- const focusSpan = getFocusSpan({context})
44
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
45
+ const focusTextBlock = selectors.getFocusTextBlock({context})
46
+ const focusSpan = selectors.getFocusSpan({context})
53
47
 
54
48
  if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
55
49
  return false
@@ -57,7 +51,7 @@ const unindentListOnBackspace = defineBehavior({
57
51
 
58
52
  const atTheBeginningOfBLock =
59
53
  focusTextBlock.node.children[0]._key === focusSpan.node._key &&
60
- context.selection.focus.offset === 0
54
+ context.selection?.focus.offset === 0
61
55
 
62
56
  if (
63
57
  atTheBeginningOfBLock &&
@@ -83,8 +77,8 @@ const unindentListOnBackspace = defineBehavior({
83
77
  const clearListOnEnter = defineBehavior({
84
78
  on: 'insert.break',
85
79
  guard: ({context}) => {
86
- const selectionCollapsed = selectionIsCollapsed({context})
87
- const focusListBlock = getFocusListBlock({context})
80
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
81
+ const focusListBlock = selectors.getFocusListBlock({context})
88
82
 
89
83
  if (
90
84
  !selectionCollapsed ||
@@ -116,7 +110,7 @@ const indentListOnTab = defineBehavior({
116
110
  return false
117
111
  }
118
112
 
119
- const selectedBlocks = getSelectedBlocks({context})
113
+ const selectedBlocks = selectors.getSelectedBlocks({context})
120
114
  const guards = createGuards(context)
121
115
  const selectedListBlocks = selectedBlocks.flatMap((block) =>
122
116
  guards.isListBlock(block.node)
@@ -157,7 +151,7 @@ const unindentListOnShiftTab = defineBehavior({
157
151
  return false
158
152
  }
159
153
 
160
- const selectedBlocks = getSelectedBlocks({context})
154
+ const selectedBlocks = selectors.getSelectedBlocks({context})
161
155
  const guards = createGuards(context)
162
156
  const selectedListBlocks = selectedBlocks.flatMap((block) =>
163
157
  guards.isListBlock(block.node)
@@ -1,5 +1,5 @@
1
- import {getFocusSpan, selectionIsCollapsed} from '../selectors/selectors'
2
- import type {PortableTextMemberSchemaTypes} from '../types/editor'
1
+ import type {EditorSchema} from '../editor/define-schema'
2
+ import * as selectors from '../selectors'
3
3
  import {defineBehavior} from './behavior.types'
4
4
 
5
5
  /**
@@ -7,7 +7,7 @@ import {defineBehavior} from './behavior.types'
7
7
  */
8
8
  export type LinkBehaviorsConfig = {
9
9
  linkAnnotation?: (context: {
10
- schema: PortableTextMemberSchemaTypes
10
+ schema: EditorSchema
11
11
  url: string
12
12
  }) => {name: string; value: {[prop: string]: unknown}} | undefined
13
13
  }
@@ -19,7 +19,7 @@ export function createLinkBehaviors(config: LinkBehaviorsConfig) {
19
19
  const pasteLinkOnSelection = defineBehavior({
20
20
  on: 'paste',
21
21
  guard: ({context, event}) => {
22
- const selectionCollapsed = selectionIsCollapsed({context})
22
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
23
23
  const text = event.data.getData('text/plain')
24
24
  const url = looksLikeUrl(text) ? text : undefined
25
25
  const annotation =
@@ -45,8 +45,8 @@ export function createLinkBehaviors(config: LinkBehaviorsConfig) {
45
45
  const pasteLinkAtCaret = defineBehavior({
46
46
  on: 'paste',
47
47
  guard: ({context, event}) => {
48
- const focusSpan = getFocusSpan({context})
49
- const selectionCollapsed = selectionIsCollapsed({context})
48
+ const focusSpan = selectors.getFocusSpan({context})
49
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
50
50
 
51
51
  if (!focusSpan || !selectionCollapsed) {
52
52
  return false
@@ -1,14 +1,9 @@
1
1
  import {isPortableTextTextBlock} from '@sanity/types'
2
+ import type {EditorSchema} from '../editor/define-schema'
2
3
  import {getTextBlockText} from '../editor/utils/utils'
3
4
  import {spanSelectionPointToBlockOffset} from '../editor/utils/utils.block-offset'
5
+ import * as selectors from '../selectors'
4
6
  import {getBlockTextBefore} from '../selectors/selector.get-text-before'
5
- import {
6
- getFocusBlock,
7
- getFocusSpan,
8
- getFocusTextBlock,
9
- selectionIsCollapsed,
10
- } from '../selectors/selectors'
11
- import type {PortableTextMemberSchemaTypes} from '../types/editor'
12
7
  import {defineBehavior} from './behavior.types'
13
8
 
14
9
  /**
@@ -16,24 +11,16 @@ import {defineBehavior} from './behavior.types'
16
11
  */
17
12
  export type MarkdownBehaviorsConfig = {
18
13
  horizontalRuleObject?: (context: {
19
- schema: PortableTextMemberSchemaTypes
14
+ schema: EditorSchema
20
15
  }) => {name: string; value?: {[prop: string]: unknown}} | undefined
21
- defaultStyle?: (context: {
22
- schema: PortableTextMemberSchemaTypes
23
- }) => string | undefined
16
+ defaultStyle?: (context: {schema: EditorSchema}) => string | undefined
24
17
  headingStyle?: (context: {
25
- schema: PortableTextMemberSchemaTypes
18
+ schema: EditorSchema
26
19
  level: number
27
20
  }) => string | undefined
28
- blockquoteStyle?: (context: {
29
- schema: PortableTextMemberSchemaTypes
30
- }) => string | undefined
31
- unorderedListStyle?: (context: {
32
- schema: PortableTextMemberSchemaTypes
33
- }) => string | undefined
34
- orderedListStyle?: (context: {
35
- schema: PortableTextMemberSchemaTypes
36
- }) => string | undefined
21
+ blockquoteStyle?: (context: {schema: EditorSchema}) => string | undefined
22
+ unorderedListStyle?: (context: {schema: EditorSchema}) => string | undefined
23
+ orderedListStyle?: (context: {schema: EditorSchema}) => string | undefined
37
24
  }
38
25
 
39
26
  /**
@@ -49,9 +36,9 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
49
36
  return false
50
37
  }
51
38
 
52
- const selectionCollapsed = selectionIsCollapsed({context})
53
- const focusTextBlock = getFocusTextBlock({context})
54
- const focusSpan = getFocusSpan({context})
39
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
40
+ const focusTextBlock = selectors.getFocusTextBlock({context})
41
+ const focusSpan = selectors.getFocusSpan({context})
55
42
 
56
43
  if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
57
44
  return false
@@ -65,7 +52,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
65
52
  'children',
66
53
  {_key: focusSpan.node._key},
67
54
  ],
68
- offset: context.selection.focus.offset,
55
+ offset: context.selection?.focus.offset ?? 0,
69
56
  },
70
57
  })
71
58
 
@@ -137,8 +124,8 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
137
124
  }
138
125
 
139
126
  const hrObject = config.horizontalRuleObject?.(context)
140
- const focusBlock = getFocusTextBlock({context})
141
- const selectionCollapsed = selectionIsCollapsed({context})
127
+ const focusBlock = selectors.getFocusTextBlock({context})
128
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
142
129
 
143
130
  if (!hrObject || !focusBlock || !selectionCollapsed) {
144
131
  return false
@@ -189,7 +176,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
189
176
  const hrRegExp = /^(---)$|(___)$|(\*\*\*)$/gm
190
177
  const hrCharacters = text.match(hrRegExp)?.[0]
191
178
  const hrObject = config.horizontalRuleObject?.(context)
192
- const focusBlock = getFocusBlock({context})
179
+ const focusBlock = selectors.getFocusBlock({context})
193
180
 
194
181
  if (!hrCharacters || !hrObject || !focusBlock) {
195
182
  return false
@@ -237,9 +224,9 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
237
224
  return false
238
225
  }
239
226
 
240
- const selectionCollapsed = selectionIsCollapsed({context})
241
- const focusTextBlock = getFocusTextBlock({context})
242
- const focusSpan = getFocusSpan({context})
227
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
228
+ const focusTextBlock = selectors.getFocusTextBlock({context})
229
+ const focusSpan = selectors.getFocusSpan({context})
243
230
 
244
231
  if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
245
232
  return false
@@ -253,7 +240,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
253
240
  'children',
254
241
  {_key: focusSpan.node._key},
255
242
  ],
256
- offset: context.selection.focus.offset,
243
+ offset: context.selection?.focus.offset ?? 0,
257
244
  },
258
245
  })
259
246
 
@@ -317,9 +304,9 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
317
304
  const clearStyleOnBackspace = defineBehavior({
318
305
  on: 'delete.backward',
319
306
  guard: ({context}) => {
320
- const selectionCollapsed = selectionIsCollapsed({context})
321
- const focusTextBlock = getFocusTextBlock({context})
322
- const focusSpan = getFocusSpan({context})
307
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
308
+ const focusTextBlock = selectors.getFocusTextBlock({context})
309
+ const focusSpan = selectors.getFocusSpan({context})
323
310
 
324
311
  if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
325
312
  return false
@@ -327,7 +314,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
327
314
 
328
315
  const atTheBeginningOfBLock =
329
316
  focusTextBlock.node.children[0]._key === focusSpan.node._key &&
330
- context.selection.focus.offset === 0
317
+ context.selection?.focus.offset === 0
331
318
 
332
319
  const defaultStyle = config.defaultStyle?.(context)
333
320
 
@@ -360,9 +347,9 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
360
347
  return false
361
348
  }
362
349
 
363
- const selectionCollapsed = selectionIsCollapsed({context})
364
- const focusTextBlock = getFocusTextBlock({context})
365
- const focusSpan = getFocusSpan({context})
350
+ const selectionCollapsed = selectors.isSelectionCollapsed({context})
351
+ const focusTextBlock = selectors.getFocusTextBlock({context})
352
+ const focusSpan = selectors.getFocusSpan({context})
366
353
 
367
354
  if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
368
355
  return false
@@ -376,7 +363,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
376
363
  'children',
377
364
  {_key: focusSpan.node._key},
378
365
  ],
379
- offset: context.selection.focus.offset,
366
+ offset: context.selection?.focus.offset ?? 0,
380
367
  },
381
368
  })
382
369
 
@@ -71,10 +71,10 @@ export type SyntheticBehaviorEvent =
71
71
  }
72
72
  }
73
73
  | {
74
- type: 'insert.soft break'
74
+ type: 'insert.break'
75
75
  }
76
76
  | {
77
- type: 'insert.break'
77
+ type: 'insert.soft break'
78
78
  }
79
79
  | {
80
80
  type: 'insert.text'
@@ -176,17 +176,17 @@ export type BehaviorActionIntend =
176
176
  effect: () => void
177
177
  }
178
178
  | {
179
- type: 'select'
180
- selection: EditorSelection
179
+ type: 'reselect'
181
180
  }
182
181
  | {
183
- type: 'select previous block'
182
+ type: 'select'
183
+ selection: EditorSelection
184
184
  }
185
185
  | {
186
- type: 'select next block'
186
+ type: 'select.previous block'
187
187
  }
188
188
  | {
189
- type: 'reselect'
189
+ type: 'select.next block'
190
190
  }
191
191
  | {
192
192
  type: 'style.add'
@@ -1,3 +1,4 @@
1
+ export type {EditorSchema} from '../editor/define-schema'
1
2
  export type {EditorContext} from '../editor/editor-snapshot'
2
3
  export type {PickFromUnion} from '../type-utils'
3
4
  export type {
@@ -159,7 +159,9 @@ export const PortableTextEditable = forwardRef<
159
159
  const rangeDecorationsRef = useRef(rangeDecorations)
160
160
 
161
161
  const editorActor = useContext(EditorActorContext)
162
- const readOnly = useSelector(editorActor, (s) => s.context.readOnly)
162
+ const readOnly = useSelector(editorActor, (s) =>
163
+ s.matches({'edit mode': 'read only'}),
164
+ )
163
165
  const schemaTypes = useSelector(editorActor, (s) => s.context.schema)
164
166
  const slateEditor = useSlate()
165
167
 
@@ -366,6 +368,7 @@ export const PortableTextEditable = forwardRef<
366
368
  // Restore selection from props when the editor has been initialized properly with it's value
367
369
  useEffect(() => {
368
370
  const onReady = editorActor.on('ready', () => {
371
+ syncRangeDecorations()
369
372
  restoreSelectionFromProps()
370
373
  })
371
374
  const onInvalidValue = editorActor.on('invalid value', () => {
@@ -380,7 +383,7 @@ export const PortableTextEditable = forwardRef<
380
383
  onInvalidValue.unsubscribe()
381
384
  onValueChanged.unsubscribe()
382
385
  }
383
- }, [editorActor, restoreSelectionFromProps])
386
+ }, [editorActor, restoreSelectionFromProps, syncRangeDecorations])
384
387
 
385
388
  // Restore selection from props when it changes
386
389
  useEffect(() => {
@@ -407,9 +410,13 @@ export const PortableTextEditable = forwardRef<
407
410
 
408
411
  // Sync range decorations after an operation is applied
409
412
  useEffect(() => {
410
- const teardown = withSyncRangeDecorations(slateEditor, syncRangeDecorations)
413
+ const teardown = withSyncRangeDecorations({
414
+ editorActor,
415
+ slateEditor,
416
+ syncRangeDecorations,
417
+ })
411
418
  return () => teardown()
412
- }, [slateEditor, syncRangeDecorations])
419
+ }, [editorActor, slateEditor, syncRangeDecorations])
413
420
 
414
421
  // Handle from props onCopy function
415
422
  const handleCopy = useCallback(