@portabletext/editor 1.55.6 → 1.55.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.
Files changed (63) hide show
  1. package/lib/_chunks-cjs/selector.get-text-before.cjs +3 -3
  2. package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
  3. package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs +37 -37
  4. package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs.map +1 -1
  5. package/lib/_chunks-cjs/selector.is-selection-expanded.cjs +9 -9
  6. package/lib/_chunks-cjs/selector.is-selection-expanded.cjs.map +1 -1
  7. package/lib/_chunks-cjs/util.child-selection-point-to-block-offset.cjs +10 -10
  8. package/lib/_chunks-cjs/util.child-selection-point-to-block-offset.cjs.map +1 -1
  9. package/lib/_chunks-cjs/util.is-equal-selection-points.cjs +5 -5
  10. package/lib/_chunks-cjs/util.is-equal-selection-points.cjs.map +1 -1
  11. package/lib/_chunks-cjs/util.merge-text-blocks.cjs +3 -3
  12. package/lib/_chunks-cjs/util.merge-text-blocks.cjs.map +1 -1
  13. package/lib/_chunks-cjs/{selection-point.cjs → util.slice-blocks.cjs} +14 -14
  14. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -0
  15. package/lib/_chunks-cjs/util.slice-text-block.cjs +11 -11
  16. package/lib/_chunks-cjs/util.slice-text-block.cjs.map +1 -1
  17. package/lib/_chunks-es/selector.get-text-before.js +1 -1
  18. package/lib/_chunks-es/selector.is-selecting-entire-blocks.js +1 -1
  19. package/lib/_chunks-es/selector.is-selecting-entire-blocks.js.map +1 -1
  20. package/lib/_chunks-es/selector.is-selection-expanded.js +1 -1
  21. package/lib/_chunks-es/util.child-selection-point-to-block-offset.js +1 -1
  22. package/lib/_chunks-es/util.is-equal-selection-points.js +1 -1
  23. package/lib/_chunks-es/util.merge-text-blocks.js +1 -1
  24. package/lib/_chunks-es/{selection-point.js → util.slice-blocks.js} +14 -14
  25. package/lib/_chunks-es/util.slice-blocks.js.map +1 -0
  26. package/lib/_chunks-es/util.slice-text-block.js +1 -1
  27. package/lib/index.cjs +417 -194
  28. package/lib/index.cjs.map +1 -1
  29. package/lib/index.d.cts +6 -6
  30. package/lib/index.d.ts +6 -6
  31. package/lib/index.js +350 -127
  32. package/lib/index.js.map +1 -1
  33. package/lib/plugins/index.cjs +11 -11
  34. package/lib/plugins/index.cjs.map +1 -1
  35. package/lib/plugins/index.d.cts +2 -2
  36. package/lib/plugins/index.d.ts +2 -2
  37. package/lib/plugins/index.js +2 -2
  38. package/lib/selectors/index.cjs +7 -7
  39. package/lib/selectors/index.cjs.map +1 -1
  40. package/lib/selectors/index.js +1 -1
  41. package/lib/utils/index.cjs +11 -11
  42. package/lib/utils/index.cjs.map +1 -1
  43. package/lib/utils/index.d.cts +1 -1
  44. package/lib/utils/index.d.ts +1 -1
  45. package/lib/utils/index.js +2 -2
  46. package/package.json +13 -13
  47. package/src/behaviors/behavior.abstract.keyboard.ts +28 -3
  48. package/src/behaviors/behavior.core.block-objects.ts +5 -3
  49. package/src/behaviors/behavior.core.decorators.ts +5 -5
  50. package/src/behaviors/behavior.core.lists.ts +5 -3
  51. package/src/editor/relay-machine.ts +2 -2
  52. package/src/keyboard-shortcuts/default-keyboard-shortcuts.ts +207 -0
  53. package/src/keyboard-shortcuts/is-keyboard-shortcut.test.ts +93 -0
  54. package/src/keyboard-shortcuts/is-keyboard-shortcut.ts +28 -0
  55. package/src/keyboard-shortcuts/keyboard-shortcuts.ts +120 -0
  56. package/src/selection/selection-point.ts +1 -1
  57. package/src/selectors/selector.get-caret-word-selection.ts +3 -3
  58. package/src/types/editor.ts +1 -1
  59. package/src/utils/util.slice-blocks.ts +2 -1
  60. package/lib/_chunks-cjs/selection-point.cjs.map +0 -1
  61. package/lib/_chunks-es/selection-point.js.map +0 -1
  62. package/src/behaviors/behavior.emoji-picker.ts +0 -402
  63. package/src/internal-utils/key-is.ts +0 -11
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var selectionPoint = require("../_chunks-cjs/selection-point.cjs"), util_childSelectionPointToBlockOffset = require("../_chunks-cjs/util.child-selection-point-to-block-offset.cjs"), util_isEqualSelectionPoints = require("../_chunks-cjs/util.is-equal-selection-points.cjs"), util_sliceTextBlock = require("../_chunks-cjs/util.slice-text-block.cjs"), util_mergeTextBlocks = require("../_chunks-cjs/util.merge-text-blocks.cjs");
3
+ var util_sliceBlocks = require("../_chunks-cjs/util.slice-blocks.cjs"), util_childSelectionPointToBlockOffset = require("../_chunks-cjs/util.child-selection-point-to-block-offset.cjs"), util_isEqualSelectionPoints = require("../_chunks-cjs/util.is-equal-selection-points.cjs"), util_sliceTextBlock = require("../_chunks-cjs/util.slice-text-block.cjs"), util_mergeTextBlocks = require("../_chunks-cjs/util.merge-text-blocks.cjs");
4
4
  function isEqualSelections(a, b) {
5
5
  return !a && !b ? !0 : !a || !b ? !1 : util_isEqualSelectionPoints.isEqualSelectionPoints(a.anchor, b.anchor) && util_isEqualSelectionPoints.isEqualSelectionPoints(a.focus, b.focus);
6
6
  }
@@ -50,7 +50,7 @@ function splitTextBlock({
50
50
  }, "children", {
51
51
  _key: lastChild._key
52
52
  }],
53
- offset: selectionPoint.isSpan(context, lastChild) ? lastChild.text.length : 0
53
+ offset: util_sliceBlocks.isSpan(context, lastChild) ? lastChild.text.length : 0
54
54
  }
55
55
  }
56
56
  },
@@ -61,15 +61,15 @@ function splitTextBlock({
61
61
  after
62
62
  };
63
63
  }
64
- exports.blockOffsetToSpanSelectionPoint = selectionPoint.blockOffsetToSpanSelectionPoint;
65
- exports.getBlockStartPoint = selectionPoint.getBlockStartPoint;
66
- exports.getSelectionEndPoint = selectionPoint.getSelectionEndPoint;
67
- exports.getSelectionStartPoint = selectionPoint.getSelectionStartPoint;
68
- exports.getTextBlockText = selectionPoint.getTextBlockText;
69
- exports.isKeyedSegment = selectionPoint.isKeyedSegment;
70
- exports.isSpan = selectionPoint.isSpan;
71
- exports.sliceBlocks = selectionPoint.sliceBlocks;
72
- exports.spanSelectionPointToBlockOffset = selectionPoint.spanSelectionPointToBlockOffset;
64
+ exports.blockOffsetToSpanSelectionPoint = util_sliceBlocks.blockOffsetToSpanSelectionPoint;
65
+ exports.getBlockStartPoint = util_sliceBlocks.getBlockStartPoint;
66
+ exports.getSelectionEndPoint = util_sliceBlocks.getSelectionEndPoint;
67
+ exports.getSelectionStartPoint = util_sliceBlocks.getSelectionStartPoint;
68
+ exports.getTextBlockText = util_sliceBlocks.getTextBlockText;
69
+ exports.isKeyedSegment = util_sliceBlocks.isKeyedSegment;
70
+ exports.isSpan = util_sliceBlocks.isSpan;
71
+ exports.sliceBlocks = util_sliceBlocks.sliceBlocks;
72
+ exports.spanSelectionPointToBlockOffset = util_sliceBlocks.spanSelectionPointToBlockOffset;
73
73
  exports.blockOffsetToBlockSelectionPoint = util_childSelectionPointToBlockOffset.blockOffsetToBlockSelectionPoint;
74
74
  exports.blockOffsetToSelectionPoint = util_childSelectionPointToBlockOffset.blockOffsetToSelectionPoint;
75
75
  exports.blockOffsetsToSelection = util_childSelectionPointToBlockOffset.blockOffsetsToSelection;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/utils/util.is-equal-selections.ts","../../src/utils/util.reverse-selection.ts","../../src/utils/util.split-text-block.ts"],"sourcesContent":["import type {EditorSelection} from '../types/editor'\nimport {isEqualSelectionPoints} from './util.is-equal-selection-points'\n\n/**\n * @public\n */\nexport function isEqualSelections(a: EditorSelection, b: EditorSelection) {\n if (!a && !b) {\n return true\n }\n\n if (!a || !b) {\n return false\n }\n\n return (\n isEqualSelectionPoints(a.anchor, b.anchor) &&\n isEqualSelectionPoints(a.focus, b.focus)\n )\n}\n","import type {EditorSelection} from '../types/editor'\n\n/**\n * @public\n */\nexport function reverseSelection<\n TEditorSelection extends NonNullable<EditorSelection> | null,\n>(selection: TEditorSelection): TEditorSelection {\n if (!selection) {\n return selection\n }\n\n if (selection.backward) {\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: false,\n } as TEditorSelection\n }\n\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: true,\n } as TEditorSelection\n}\n","import type {PortableTextTextBlock} from '@sanity/types'\nimport type {EditorSelectionPoint} from '..'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport {isSpan} from './util.is-span'\nimport {sliceTextBlock} from './util.slice-text-block'\n\n/**\n * @beta\n */\nexport function splitTextBlock({\n context,\n block,\n point,\n}: {\n context: Pick<EditorContext, 'schema'>\n block: PortableTextTextBlock\n point: EditorSelectionPoint\n}): {before: PortableTextTextBlock; after: PortableTextTextBlock} | undefined {\n const firstChild = block.children.at(0)\n const lastChild = block.children.at(block.children.length - 1)\n\n if (!firstChild || !lastChild) {\n return undefined\n }\n\n const before = sliceTextBlock({\n context: {\n schema: context.schema,\n selection: {\n anchor: {\n path: [{_key: block._key}, 'children', {_key: firstChild._key}],\n offset: 0,\n },\n focus: point,\n },\n },\n block,\n })\n const after = sliceTextBlock({\n context: {\n schema: context.schema,\n selection: {\n anchor: point,\n focus: {\n path: [{_key: block._key}, 'children', {_key: lastChild._key}],\n offset: isSpan(context, lastChild) ? lastChild.text.length : 0,\n },\n },\n },\n block,\n })\n\n return {before, after}\n}\n"],"names":["isEqualSelections","a","b","isEqualSelectionPoints","anchor","focus","reverseSelection","selection","backward","splitTextBlock","context","block","point","firstChild","children","at","lastChild","length","before","sliceTextBlock","schema","path","_key","offset","after","isSpan","text"],"mappings":";;;AAMO,SAASA,kBAAkBC,GAAoBC,GAAoB;AACxE,SAAI,CAACD,KAAK,CAACC,IACF,KAGL,CAACD,KAAK,CAACC,IACF,KAIPC,4BAAAA,uBAAuBF,EAAEG,QAAQF,EAAEE,MAAM,KACzCD,4BAAAA,uBAAuBF,EAAEI,OAAOH,EAAEG,KAAK;AAE3C;ACdO,SAASC,iBAEdC,WAA+C;AAC/C,SAAKA,cAIDA,UAAUC,WACL;AAAA,IACLJ,QAAQG,UAAUF;AAAAA,IAClBA,OAAOE,UAAUH;AAAAA,IACjBI,UAAU;AAAA,EAAA,IAIP;AAAA,IACLJ,QAAQG,UAAUF;AAAAA,IAClBA,OAAOE,UAAUH;AAAAA,IACjBI,UAAU;AAAA,EAAA;AAEd;AChBO,SAASC,eAAe;AAAA,EAC7BC;AAAAA,EACAC;AAAAA,EACAC;AAKF,GAA8E;AAC5E,QAAMC,aAAaF,MAAMG,SAASC,GAAG,CAAC,GAChCC,YAAYL,MAAMG,SAASC,GAAGJ,MAAMG,SAASG,SAAS,CAAC;AAE7D,MAAI,CAACJ,cAAc,CAACG;AAClB;AAGF,QAAME,SAASC,oBAAAA,eAAe;AAAA,IAC5BT,SAAS;AAAA,MACPU,QAAQV,QAAQU;AAAAA,MAChBb,WAAW;AAAA,QACTH,QAAQ;AAAA,UACNiB,MAAM,CAAC;AAAA,YAACC,MAAMX,MAAMW;AAAAA,UAAAA,GAAO,YAAY;AAAA,YAACA,MAAMT,WAAWS;AAAAA,UAAAA,CAAK;AAAA,UAC9DC,QAAQ;AAAA,QAAA;AAAA,QAEVlB,OAAOO;AAAAA,MAAAA;AAAAA,IACT;AAAA,IAEFD;AAAAA,EAAAA,CACD,GACKa,QAAQL,mCAAe;AAAA,IAC3BT,SAAS;AAAA,MACPU,QAAQV,QAAQU;AAAAA,MAChBb,WAAW;AAAA,QACTH,QAAQQ;AAAAA,QACRP,OAAO;AAAA,UACLgB,MAAM,CAAC;AAAA,YAACC,MAAMX,MAAMW;AAAAA,UAAAA,GAAO,YAAY;AAAA,YAACA,MAAMN,UAAUM;AAAAA,UAAAA,CAAK;AAAA,UAC7DC,QAAQE,eAAAA,OAAOf,SAASM,SAAS,IAAIA,UAAUU,KAAKT,SAAS;AAAA,QAAA;AAAA,MAC/D;AAAA,IACF;AAAA,IAEFN;AAAAA,EAAAA,CACD;AAED,SAAO;AAAA,IAACO;AAAAA,IAAQM;AAAAA,EAAAA;AAClB;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/utils/util.is-equal-selections.ts","../../src/utils/util.reverse-selection.ts","../../src/utils/util.split-text-block.ts"],"sourcesContent":["import type {EditorSelection} from '../types/editor'\nimport {isEqualSelectionPoints} from './util.is-equal-selection-points'\n\n/**\n * @public\n */\nexport function isEqualSelections(a: EditorSelection, b: EditorSelection) {\n if (!a && !b) {\n return true\n }\n\n if (!a || !b) {\n return false\n }\n\n return (\n isEqualSelectionPoints(a.anchor, b.anchor) &&\n isEqualSelectionPoints(a.focus, b.focus)\n )\n}\n","import type {EditorSelection} from '../types/editor'\n\n/**\n * @public\n */\nexport function reverseSelection<\n TEditorSelection extends NonNullable<EditorSelection> | null,\n>(selection: TEditorSelection): TEditorSelection {\n if (!selection) {\n return selection\n }\n\n if (selection.backward) {\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: false,\n } as TEditorSelection\n }\n\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: true,\n } as TEditorSelection\n}\n","import type {PortableTextTextBlock} from '@sanity/types'\nimport type {EditorSelectionPoint} from '..'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport {isSpan} from './util.is-span'\nimport {sliceTextBlock} from './util.slice-text-block'\n\n/**\n * @beta\n */\nexport function splitTextBlock({\n context,\n block,\n point,\n}: {\n context: Pick<EditorContext, 'schema'>\n block: PortableTextTextBlock\n point: EditorSelectionPoint\n}): {before: PortableTextTextBlock; after: PortableTextTextBlock} | undefined {\n const firstChild = block.children.at(0)\n const lastChild = block.children.at(block.children.length - 1)\n\n if (!firstChild || !lastChild) {\n return undefined\n }\n\n const before = sliceTextBlock({\n context: {\n schema: context.schema,\n selection: {\n anchor: {\n path: [{_key: block._key}, 'children', {_key: firstChild._key}],\n offset: 0,\n },\n focus: point,\n },\n },\n block,\n })\n const after = sliceTextBlock({\n context: {\n schema: context.schema,\n selection: {\n anchor: point,\n focus: {\n path: [{_key: block._key}, 'children', {_key: lastChild._key}],\n offset: isSpan(context, lastChild) ? lastChild.text.length : 0,\n },\n },\n },\n block,\n })\n\n return {before, after}\n}\n"],"names":["isEqualSelections","a","b","isEqualSelectionPoints","anchor","focus","reverseSelection","selection","backward","splitTextBlock","context","block","point","firstChild","children","at","lastChild","length","before","sliceTextBlock","schema","path","_key","offset","after","isSpan","text"],"mappings":";;;AAMO,SAASA,kBAAkBC,GAAoBC,GAAoB;AACxE,SAAI,CAACD,KAAK,CAACC,IACF,KAGL,CAACD,KAAK,CAACC,IACF,KAIPC,4BAAAA,uBAAuBF,EAAEG,QAAQF,EAAEE,MAAM,KACzCD,4BAAAA,uBAAuBF,EAAEI,OAAOH,EAAEG,KAAK;AAE3C;ACdO,SAASC,iBAEdC,WAA+C;AAC/C,SAAKA,cAIDA,UAAUC,WACL;AAAA,IACLJ,QAAQG,UAAUF;AAAAA,IAClBA,OAAOE,UAAUH;AAAAA,IACjBI,UAAU;AAAA,EAAA,IAIP;AAAA,IACLJ,QAAQG,UAAUF;AAAAA,IAClBA,OAAOE,UAAUH;AAAAA,IACjBI,UAAU;AAAA,EAAA;AAEd;AChBO,SAASC,eAAe;AAAA,EAC7BC;AAAAA,EACAC;AAAAA,EACAC;AAKF,GAA8E;AAC5E,QAAMC,aAAaF,MAAMG,SAASC,GAAG,CAAC,GAChCC,YAAYL,MAAMG,SAASC,GAAGJ,MAAMG,SAASG,SAAS,CAAC;AAE7D,MAAI,CAACJ,cAAc,CAACG;AAClB;AAGF,QAAME,SAASC,oBAAAA,eAAe;AAAA,IAC5BT,SAAS;AAAA,MACPU,QAAQV,QAAQU;AAAAA,MAChBb,WAAW;AAAA,QACTH,QAAQ;AAAA,UACNiB,MAAM,CAAC;AAAA,YAACC,MAAMX,MAAMW;AAAAA,UAAAA,GAAO,YAAY;AAAA,YAACA,MAAMT,WAAWS;AAAAA,UAAAA,CAAK;AAAA,UAC9DC,QAAQ;AAAA,QAAA;AAAA,QAEVlB,OAAOO;AAAAA,MAAAA;AAAAA,IACT;AAAA,IAEFD;AAAAA,EAAAA,CACD,GACKa,QAAQL,mCAAe;AAAA,IAC3BT,SAAS;AAAA,MACPU,QAAQV,QAAQU;AAAAA,MAChBb,WAAW;AAAA,QACTH,QAAQQ;AAAAA,QACRP,OAAO;AAAA,UACLgB,MAAM,CAAC;AAAA,YAACC,MAAMX,MAAMW;AAAAA,UAAAA,GAAO,YAAY;AAAA,YAACA,MAAMN,UAAUM;AAAAA,UAAAA,CAAK;AAAA,UAC7DC,QAAQE,iBAAAA,OAAOf,SAASM,SAAS,IAAIA,UAAUU,KAAKT,SAAS;AAAA,QAAA;AAAA,MAC/D;AAAA,IACF;AAAA,IAEFN;AAAAA,EAAAA,CACD;AAED,SAAO;AAAA,IAACO;AAAAA,IAAQM;AAAAA,EAAAA;AAClB;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -394,7 +394,7 @@ export declare function mergeTextBlocks({
394
394
  context: Pick<EditorContext, 'keyGenerator' | 'schema'>
395
395
  targetBlock: PortableTextTextBlock
396
396
  incomingBlock: PortableTextTextBlock
397
- }): PortableTextTextBlock<PortableTextSpan | PortableTextObject>
397
+ }): PortableTextTextBlock<PortableTextObject | PortableTextSpan>
398
398
 
399
399
  declare type MIMEType = `${string}/${string}`
400
400
 
@@ -394,7 +394,7 @@ export declare function mergeTextBlocks({
394
394
  context: Pick<EditorContext, 'keyGenerator' | 'schema'>
395
395
  targetBlock: PortableTextTextBlock
396
396
  incomingBlock: PortableTextTextBlock
397
- }): PortableTextTextBlock<PortableTextSpan | PortableTextObject>
397
+ }): PortableTextTextBlock<PortableTextObject | PortableTextSpan>
398
398
 
399
399
  declare type MIMEType = `${string}/${string}`
400
400
 
@@ -1,5 +1,5 @@
1
- import { isSpan } from "../_chunks-es/selection-point.js";
2
- import { blockOffsetToSpanSelectionPoint, getBlockStartPoint, getSelectionEndPoint, getSelectionStartPoint, getTextBlockText, isKeyedSegment, sliceBlocks, spanSelectionPointToBlockOffset } from "../_chunks-es/selection-point.js";
1
+ import { isSpan } from "../_chunks-es/util.slice-blocks.js";
2
+ import { blockOffsetToSpanSelectionPoint, getBlockStartPoint, getSelectionEndPoint, getSelectionStartPoint, getTextBlockText, isKeyedSegment, sliceBlocks, spanSelectionPointToBlockOffset } from "../_chunks-es/util.slice-blocks.js";
3
3
  import { blockOffsetToBlockSelectionPoint, blockOffsetToSelectionPoint, blockOffsetsToSelection, childSelectionPointToBlockOffset } from "../_chunks-es/util.child-selection-point-to-block-offset.js";
4
4
  import { isEqualSelectionPoints } from "../_chunks-es/util.is-equal-selection-points.js";
5
5
  import { getBlockEndPoint, isEmptyTextBlock } from "../_chunks-es/util.is-equal-selection-points.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "1.55.6",
3
+ "version": "1.55.7",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -75,34 +75,34 @@
75
75
  "lodash": "^4.17.21",
76
76
  "lodash.startcase": "^4.4.0",
77
77
  "react-compiler-runtime": "19.1.0-rc.2",
78
- "slate": "0.117.0",
78
+ "slate": "0.117.2",
79
79
  "slate-dom": "^0.116.0",
80
- "slate-react": "0.117.1",
80
+ "slate-react": "0.117.2",
81
81
  "use-effect-event": "^1.0.2",
82
82
  "xstate": "^5.20.0",
83
- "@portabletext/patches": "1.1.5",
84
- "@portabletext/block-tools": "1.1.32"
83
+ "@portabletext/block-tools": "1.1.33",
84
+ "@portabletext/patches": "1.1.5"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@portabletext/toolkit": "^2.0.17",
88
88
  "@sanity/diff-match-patch": "^3.2.0",
89
- "@sanity/pkg-utils": "^7.8.6",
90
- "@sanity/schema": "^3.94.2",
91
- "@sanity/types": "^3.94.2",
89
+ "@sanity/pkg-utils": "^7.8.8",
90
+ "@sanity/schema": "^3.95.0",
91
+ "@sanity/types": "^3.95.0",
92
92
  "@testing-library/react": "^16.3.0",
93
93
  "@types/debug": "^4.1.12",
94
94
  "@types/lodash": "^4.17.16",
95
95
  "@types/lodash.startcase": "^4.4.9",
96
96
  "@types/react": "^19.1.8",
97
97
  "@types/react-dom": "^19.1.6",
98
- "@typescript-eslint/eslint-plugin": "^8.34.0",
99
- "@typescript-eslint/parser": "^8.34.0",
98
+ "@typescript-eslint/eslint-plugin": "^8.35.0",
99
+ "@typescript-eslint/parser": "^8.35.0",
100
100
  "@vitejs/plugin-react": "^4.6.0",
101
101
  "@vitest/browser": "^3.2.4",
102
102
  "@vitest/coverage-istanbul": "^3.2.4",
103
103
  "babel-plugin-react-compiler": "19.1.0-rc.2",
104
104
  "eslint": "8.57.1",
105
- "eslint-plugin-react-hooks": "0.0.0-experimental-12bc60f5-20250613",
105
+ "eslint-plugin-react-hooks": "0.0.0-experimental-cee7939b-20250625",
106
106
  "jsdom": "^26.0.0",
107
107
  "react": "^19.1.0",
108
108
  "react-dom": "^19.1.0",
@@ -114,8 +114,8 @@
114
114
  "racejar": "1.2.9"
115
115
  },
116
116
  "peerDependencies": {
117
- "@sanity/schema": "^3.94.2",
118
- "@sanity/types": "^3.94.2",
117
+ "@sanity/schema": "^3.95.0",
118
+ "@sanity/types": "^3.95.0",
119
119
  "react": "^16.9 || ^17 || ^18 || ^19",
120
120
  "rxjs": "^7.8.2"
121
121
  },
@@ -1,13 +1,17 @@
1
- import {keyIs} from '../internal-utils/key-is'
1
+ import {defaultKeyboardShortcuts} from '../keyboard-shortcuts/default-keyboard-shortcuts'
2
2
  import * as selectors from '../selectors'
3
3
  import {raise} from './behavior.types.action'
4
4
  import {defineBehavior} from './behavior.types.behavior'
5
5
 
6
6
  export const abstractKeyboardBehaviors = [
7
+ /**
8
+ * Allow raising an `insert.break` event when pressing Enter on an inline
9
+ * object.
10
+ */
7
11
  defineBehavior({
8
12
  on: 'keyboard.keydown',
9
13
  guard: ({snapshot, event}) =>
10
- keyIs.break(event.originEvent) &&
14
+ defaultKeyboardShortcuts.break.guard(event.originEvent) &&
11
15
  selectors.isSelectionCollapsed(snapshot) &&
12
16
  selectors.getFocusInlineObject(snapshot),
13
17
  actions: [() => [raise({type: 'insert.break'})]],
@@ -20,7 +24,28 @@ export const abstractKeyboardBehaviors = [
20
24
  */
21
25
  defineBehavior({
22
26
  on: 'keyboard.keydown',
23
- guard: ({event}) => keyIs.lineBreak(event.originEvent),
27
+ guard: ({event}) =>
28
+ defaultKeyboardShortcuts.lineBreak.guard(event.originEvent),
24
29
  actions: [() => [raise({type: 'insert.soft break'})]],
25
30
  }),
31
+
32
+ /**
33
+ * Manual handling of undo shortcuts.
34
+ */
35
+ defineBehavior({
36
+ on: 'keyboard.keydown',
37
+ guard: ({event}) =>
38
+ defaultKeyboardShortcuts.history.undo.guard(event.originEvent),
39
+ actions: [() => [raise({type: 'history.undo'})]],
40
+ }),
41
+
42
+ /**
43
+ * Manual handling of redo shortcuts.
44
+ */
45
+ defineBehavior({
46
+ on: 'keyboard.keydown',
47
+ guard: ({event}) =>
48
+ defaultKeyboardShortcuts.history.redo.guard(event.originEvent),
49
+ actions: [() => [raise({type: 'history.redo'})]],
50
+ }),
26
51
  ]
@@ -1,5 +1,5 @@
1
- import {isHotkey} from '../internal-utils/is-hotkey'
2
1
  import {isTextBlock} from '../internal-utils/parse-blocks'
2
+ import {defaultKeyboardShortcuts} from '../keyboard-shortcuts/default-keyboard-shortcuts'
3
3
  import * as selectors from '../selectors'
4
4
  import {isEmptyTextBlock} from '../utils/util.is-empty-text-block'
5
5
  import {raise} from './behavior.types.action'
@@ -8,7 +8,9 @@ import {defineBehavior} from './behavior.types.behavior'
8
8
  const arrowDownOnLonelyBlockObject = defineBehavior({
9
9
  on: 'keyboard.keydown',
10
10
  guard: ({snapshot, event}) => {
11
- const isArrowDown = isHotkey('ArrowDown', event.originEvent)
11
+ const isArrowDown = defaultKeyboardShortcuts.arrowDown.guard(
12
+ event.originEvent,
13
+ )
12
14
 
13
15
  if (!isArrowDown) {
14
16
  return false
@@ -41,7 +43,7 @@ const arrowDownOnLonelyBlockObject = defineBehavior({
41
43
  const arrowUpOnLonelyBlockObject = defineBehavior({
42
44
  on: 'keyboard.keydown',
43
45
  guard: ({snapshot, event}) => {
44
- const isArrowUp = isHotkey('ArrowUp', event.originEvent)
46
+ const isArrowUp = defaultKeyboardShortcuts.arrowUp.guard(event.originEvent)
45
47
 
46
48
  if (!isArrowUp) {
47
49
  return false
@@ -1,4 +1,4 @@
1
- import {isHotkey} from '../internal-utils/is-hotkey'
1
+ import {defaultKeyboardShortcuts} from '../keyboard-shortcuts/default-keyboard-shortcuts'
2
2
  import {raise} from './behavior.types.action'
3
3
  import {defineBehavior} from './behavior.types.behavior'
4
4
 
@@ -6,7 +6,7 @@ export const coreDecoratorBehaviors = {
6
6
  strongShortcut: defineBehavior({
7
7
  on: 'keyboard.keydown',
8
8
  guard: ({snapshot, event}) =>
9
- isHotkey('mod+b', event.originEvent) &&
9
+ defaultKeyboardShortcuts.decorators.strong.guard(event.originEvent) &&
10
10
  snapshot.context.schema.decorators.some(
11
11
  (decorator) => decorator.name === 'strong',
12
12
  ),
@@ -15,7 +15,7 @@ export const coreDecoratorBehaviors = {
15
15
  emShortcut: defineBehavior({
16
16
  on: 'keyboard.keydown',
17
17
  guard: ({snapshot, event}) =>
18
- isHotkey('mod+i', event.originEvent) &&
18
+ defaultKeyboardShortcuts.decorators.em.guard(event.originEvent) &&
19
19
  snapshot.context.schema.decorators.some(
20
20
  (decorator) => decorator.name === 'em',
21
21
  ),
@@ -24,7 +24,7 @@ export const coreDecoratorBehaviors = {
24
24
  underlineShortcut: defineBehavior({
25
25
  on: 'keyboard.keydown',
26
26
  guard: ({snapshot, event}) =>
27
- isHotkey('mod+u', event.originEvent) &&
27
+ defaultKeyboardShortcuts.decorators.underline.guard(event.originEvent) &&
28
28
  snapshot.context.schema.decorators.some(
29
29
  (decorator) => decorator.name === 'underline',
30
30
  ),
@@ -35,7 +35,7 @@ export const coreDecoratorBehaviors = {
35
35
  codeShortcut: defineBehavior({
36
36
  on: 'keyboard.keydown',
37
37
  guard: ({snapshot, event}) =>
38
- isHotkey("mod+'", event.originEvent) &&
38
+ defaultKeyboardShortcuts.decorators.code.guard(event.originEvent) &&
39
39
  snapshot.context.schema.decorators.some(
40
40
  (decorator) => decorator.name === 'code',
41
41
  ),
@@ -1,5 +1,5 @@
1
- import {isHotkey} from '../internal-utils/is-hotkey'
2
1
  import {isListBlock} from '../internal-utils/parse-blocks'
2
+ import {defaultKeyboardShortcuts} from '../keyboard-shortcuts/default-keyboard-shortcuts'
3
3
  import * as selectors from '../selectors'
4
4
  import {isEmptyTextBlock} from '../utils/util.is-empty-text-block'
5
5
  import {raise} from './behavior.types.action'
@@ -105,7 +105,7 @@ const clearListOnEnter = defineBehavior({
105
105
  const indentListOnTab = defineBehavior({
106
106
  on: 'keyboard.keydown',
107
107
  guard: ({snapshot, event}) => {
108
- const isTab = isHotkey('Tab', event.originEvent)
108
+ const isTab = defaultKeyboardShortcuts.tab.guard(event.originEvent)
109
109
 
110
110
  if (!isTab) {
111
111
  return false
@@ -149,7 +149,9 @@ const indentListOnTab = defineBehavior({
149
149
  const unindentListOnShiftTab = defineBehavior({
150
150
  on: 'keyboard.keydown',
151
151
  guard: ({snapshot, event}) => {
152
- const isShiftTab = isHotkey('Shift+Tab', event.originEvent)
152
+ const isShiftTab = defaultKeyboardShortcuts.shiftTab.guard(
153
+ event.originEvent,
154
+ )
153
155
 
154
156
  if (!isShiftTab) {
155
157
  return false
@@ -14,7 +14,7 @@ export type EditorEmittedEvent =
14
14
  }
15
15
  | {
16
16
  /**
17
- * @deprecated
17
+ * @deprecated Will be removed in the next major version
18
18
  */
19
19
  type: 'done loading'
20
20
  }
@@ -33,7 +33,7 @@ export type EditorEmittedEvent =
33
33
  }
34
34
  | {
35
35
  /**
36
- * @deprecated
36
+ * @deprecated Will be removed in the next major version
37
37
  */
38
38
  type: 'loading'
39
39
  }
@@ -0,0 +1,207 @@
1
+ import {isKeyboardShortcut} from './is-keyboard-shortcut'
2
+ import {createKeyboardShortcut} from './keyboard-shortcuts'
3
+
4
+ export const defaultKeyboardShortcuts = {
5
+ arrowDown: createKeyboardShortcut({
6
+ default: {
7
+ guard: (event) =>
8
+ isKeyboardShortcut(event, 'ArrowDown', {
9
+ ctrlKey: false,
10
+ metaKey: false,
11
+ shiftKey: false,
12
+ altKey: false,
13
+ }),
14
+ keys: ['ArrowDown'],
15
+ },
16
+ }),
17
+ arrowUp: createKeyboardShortcut({
18
+ default: {
19
+ guard: (event) =>
20
+ isKeyboardShortcut(event, 'ArrowUp', {
21
+ ctrlKey: false,
22
+ metaKey: false,
23
+ shiftKey: false,
24
+ altKey: false,
25
+ }),
26
+ keys: ['ArrowUp'],
27
+ },
28
+ }),
29
+ break: createKeyboardShortcut({
30
+ default: {
31
+ guard: (event) => isKeyboardShortcut(event, 'Enter', {shiftKey: false}),
32
+ keys: ['Enter'],
33
+ },
34
+ }),
35
+ lineBreak: createKeyboardShortcut({
36
+ default: {
37
+ guard: (event) => isKeyboardShortcut(event, 'Enter', {shiftKey: true}),
38
+ keys: ['Shift', 'Enter'],
39
+ },
40
+ }),
41
+ decorators: {
42
+ strong: createKeyboardShortcut({
43
+ default: {
44
+ guard: (event) =>
45
+ isKeyboardShortcut(event, 'b', {
46
+ altKey: false,
47
+ ctrlKey: true,
48
+ metaKey: false,
49
+ shiftKey: false,
50
+ }),
51
+ keys: ['Ctrl', 'B'],
52
+ },
53
+ apple: {
54
+ guard: (event) =>
55
+ isKeyboardShortcut(event, 'b', {
56
+ altKey: false,
57
+ ctrlKey: false,
58
+ metaKey: true,
59
+ shiftKey: false,
60
+ }),
61
+ keys: ['⌘', 'B'],
62
+ },
63
+ }),
64
+ em: createKeyboardShortcut({
65
+ default: {
66
+ guard: (event) =>
67
+ isKeyboardShortcut(event, 'i', {
68
+ altKey: false,
69
+ ctrlKey: true,
70
+ metaKey: false,
71
+ shiftKey: false,
72
+ }),
73
+ keys: ['Ctrl', 'I'],
74
+ },
75
+ apple: {
76
+ guard: (event) =>
77
+ isKeyboardShortcut(event, 'i', {
78
+ altKey: false,
79
+ ctrlKey: false,
80
+ metaKey: true,
81
+ shiftKey: false,
82
+ }),
83
+ keys: ['⌘', 'I'],
84
+ },
85
+ }),
86
+ underline: createKeyboardShortcut({
87
+ default: {
88
+ guard: (event) =>
89
+ isKeyboardShortcut(event, 'u', {
90
+ altKey: false,
91
+ ctrlKey: true,
92
+ metaKey: false,
93
+ shiftKey: false,
94
+ }),
95
+ keys: ['Ctrl', 'U'],
96
+ },
97
+ apple: {
98
+ guard: (event) =>
99
+ isKeyboardShortcut(event, 'u', {
100
+ altKey: false,
101
+ ctrlKey: false,
102
+ metaKey: true,
103
+ shiftKey: false,
104
+ }),
105
+ keys: ['⌘', 'U'],
106
+ },
107
+ }),
108
+ code: createKeyboardShortcut({
109
+ default: {
110
+ guard: (event) =>
111
+ isKeyboardShortcut(event, "'", {
112
+ altKey: false,
113
+ ctrlKey: true,
114
+ metaKey: false,
115
+ shiftKey: false,
116
+ }),
117
+ keys: ['Ctrl', "'"],
118
+ },
119
+ apple: {
120
+ guard: (event) =>
121
+ isKeyboardShortcut(event, "'", {
122
+ altKey: false,
123
+ ctrlKey: false,
124
+ metaKey: true,
125
+ shiftKey: false,
126
+ }),
127
+ keys: ['⌘', "'"],
128
+ },
129
+ }),
130
+ },
131
+ history: {
132
+ undo: createKeyboardShortcut({
133
+ default: {
134
+ guard: (event) =>
135
+ isKeyboardShortcut(event, 'z', {
136
+ altKey: false,
137
+ ctrlKey: true,
138
+ metaKey: false,
139
+ shiftKey: false,
140
+ }),
141
+ keys: ['Ctrl', 'Z'],
142
+ },
143
+ apple: {
144
+ guard: (event) =>
145
+ isKeyboardShortcut(event, 'z', {
146
+ altKey: false,
147
+ ctrlKey: false,
148
+ metaKey: true,
149
+ shiftKey: false,
150
+ }),
151
+ keys: ['⌘', 'Z'],
152
+ },
153
+ }),
154
+ redo: createKeyboardShortcut({
155
+ default: {
156
+ guard: (event) =>
157
+ isKeyboardShortcut(event, 'y', {
158
+ ctrlKey: true,
159
+ metaKey: false,
160
+ shiftKey: false,
161
+ altKey: false,
162
+ }) ||
163
+ isKeyboardShortcut(event, 'z', {
164
+ ctrlKey: true,
165
+ metaKey: false,
166
+ shiftKey: true,
167
+ altKey: false,
168
+ }),
169
+ keys: ['Ctrl', 'Y'],
170
+ },
171
+ apple: {
172
+ guard: (event) =>
173
+ isKeyboardShortcut(event, 'z', {
174
+ ctrlKey: false,
175
+ metaKey: true,
176
+ shiftKey: true,
177
+ altKey: false,
178
+ }),
179
+ keys: ['⌘', 'Shift', 'Z'],
180
+ },
181
+ }),
182
+ },
183
+ tab: createKeyboardShortcut({
184
+ default: {
185
+ guard: (event) =>
186
+ isKeyboardShortcut(event, 'Tab', {
187
+ ctrlKey: false,
188
+ metaKey: false,
189
+ shiftKey: false,
190
+ altKey: false,
191
+ }),
192
+ keys: ['Tab'],
193
+ },
194
+ }),
195
+ shiftTab: createKeyboardShortcut({
196
+ default: {
197
+ guard: (event) =>
198
+ isKeyboardShortcut(event, 'Tab', {
199
+ ctrlKey: false,
200
+ metaKey: false,
201
+ shiftKey: true,
202
+ altKey: false,
203
+ }),
204
+ keys: ['Shift', 'Tab'],
205
+ },
206
+ }),
207
+ }
@@ -0,0 +1,93 @@
1
+ import {expect, test} from 'vitest'
2
+ import {isKeyboardShortcut} from './is-keyboard-shortcut'
3
+
4
+ test(isKeyboardShortcut.name, () => {
5
+ expect(
6
+ isKeyboardShortcut(
7
+ {
8
+ key: 'Enter',
9
+ code: 'Enter',
10
+ metaKey: false,
11
+ ctrlKey: false,
12
+ altKey: false,
13
+ shiftKey: false,
14
+ },
15
+ 'Enter',
16
+ {shiftKey: false},
17
+ ),
18
+ ).toBe(true)
19
+
20
+ expect(
21
+ isKeyboardShortcut(
22
+ {
23
+ key: 'Enter',
24
+ code: 'Enter',
25
+ metaKey: false,
26
+ ctrlKey: false,
27
+ altKey: false,
28
+ shiftKey: true,
29
+ },
30
+ 'Enter',
31
+ {shiftKey: false},
32
+ ),
33
+ ).toBe(false)
34
+
35
+ expect(
36
+ isKeyboardShortcut(
37
+ {
38
+ key: 'Enter',
39
+ code: 'Enter',
40
+ metaKey: false,
41
+ ctrlKey: false,
42
+ altKey: false,
43
+ shiftKey: true,
44
+ },
45
+ 'Enter',
46
+ {shiftKey: true},
47
+ ),
48
+ ).toBe(true)
49
+
50
+ expect(
51
+ isKeyboardShortcut(
52
+ {
53
+ key: 'Enter',
54
+ code: 'Enter',
55
+ metaKey: false,
56
+ ctrlKey: false,
57
+ altKey: false,
58
+ shiftKey: true,
59
+ },
60
+ 'Enter',
61
+ ),
62
+ ).toBe(true)
63
+
64
+ expect(
65
+ isKeyboardShortcut(
66
+ {
67
+ key: 'b',
68
+ code: 'KeyB',
69
+ metaKey: false,
70
+ ctrlKey: true,
71
+ altKey: false,
72
+ shiftKey: false,
73
+ },
74
+ 'B',
75
+ {ctrlKey: true, metaKey: false},
76
+ ),
77
+ ).toBe(true)
78
+
79
+ expect(
80
+ isKeyboardShortcut(
81
+ {
82
+ key: 'b',
83
+ code: 'KeyB',
84
+ metaKey: false,
85
+ ctrlKey: true,
86
+ altKey: false,
87
+ shiftKey: false,
88
+ },
89
+ 'B',
90
+ {ctrlKey: false, metaKey: true},
91
+ ),
92
+ ).toBe(false)
93
+ })
@@ -0,0 +1,28 @@
1
+ type AllowedModifiers = {
2
+ ctrlKey?: boolean
3
+ metaKey?: boolean
4
+ shiftKey?: boolean
5
+ altKey?: boolean
6
+ }
7
+
8
+ export function isKeyboardShortcut<
9
+ TKeyboardEvent extends Pick<
10
+ KeyboardEvent,
11
+ 'key' | 'shiftKey' | 'altKey' | 'ctrlKey' | 'metaKey'
12
+ > = Pick<
13
+ KeyboardEvent,
14
+ 'key' | 'shiftKey' | 'altKey' | 'ctrlKey' | 'metaKey'
15
+ >,
16
+ >(event: TKeyboardEvent, key: string, allowedModifiers: AllowedModifiers = {}) {
17
+ return (
18
+ event.key.toLowerCase() === key.toLowerCase() &&
19
+ (allowedModifiers.ctrlKey === event.ctrlKey ||
20
+ allowedModifiers.ctrlKey === undefined) &&
21
+ (allowedModifiers.metaKey === event.metaKey ||
22
+ allowedModifiers.metaKey === undefined) &&
23
+ (allowedModifiers.shiftKey === event.shiftKey ||
24
+ allowedModifiers.shiftKey === undefined) &&
25
+ (allowedModifiers.altKey === event.altKey ||
26
+ allowedModifiers.altKey === undefined)
27
+ )
28
+ }