@portabletext/editor 2.7.2 → 2.8.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 (50) hide show
  1. package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs +3 -1
  2. package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs.map +1 -1
  3. package/lib/_chunks-cjs/util.slice-blocks.cjs +60 -6
  4. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
  5. package/lib/_chunks-dts/behavior.types.action.d.cts +95 -95
  6. package/lib/_chunks-dts/behavior.types.action.d.ts +95 -95
  7. package/lib/_chunks-es/selector.is-selecting-entire-blocks.js +4 -2
  8. package/lib/_chunks-es/selector.is-selecting-entire-blocks.js.map +1 -1
  9. package/lib/_chunks-es/util.slice-blocks.js +56 -5
  10. package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
  11. package/lib/index.cjs +94 -121
  12. package/lib/index.cjs.map +1 -1
  13. package/lib/index.js +90 -118
  14. package/lib/index.js.map +1 -1
  15. package/lib/plugins/index.d.cts +3 -3
  16. package/lib/plugins/index.d.ts +3 -3
  17. package/lib/selectors/index.d.cts +13 -3
  18. package/lib/selectors/index.d.ts +13 -3
  19. package/lib/utils/index.d.ts +2 -2
  20. package/package.json +13 -14
  21. package/src/behaviors/behavior.abstract.insert.ts +58 -1
  22. package/src/behaviors/behavior.core.annotations.ts +24 -2
  23. package/src/behaviors/behavior.core.ts +1 -1
  24. package/src/behaviors/behavior.types.event.ts +18 -18
  25. package/src/converters/converter.text-html.serialize.test.ts +27 -17
  26. package/src/converters/converter.text-plain.test.ts +1 -1
  27. package/src/editor/plugins/createWithEditableAPI.ts +16 -0
  28. package/src/internal-utils/parse-blocks.ts +2 -1
  29. package/src/operations/behavior.operation.annotation.add.ts +1 -12
  30. package/src/operations/behavior.operations.ts +0 -18
  31. package/src/selectors/selector.is-active-annotation.test.ts +320 -0
  32. package/src/selectors/selector.is-active-annotation.ts +24 -0
  33. package/src/utils/util.slice-blocks.test.ts +39 -5
  34. package/src/utils/util.slice-blocks.ts +36 -3
  35. package/src/editor/__tests__/PortableTextEditor.test.tsx +0 -430
  36. package/src/editor/__tests__/PortableTextEditorTester.tsx +0 -58
  37. package/src/editor/__tests__/RangeDecorations.test.tsx +0 -213
  38. package/src/editor/__tests__/insert-block.test.tsx +0 -224
  39. package/src/editor/__tests__/self-solving.test.tsx +0 -183
  40. package/src/editor/plugins/__tests__/withEditableAPIDelete.test.tsx +0 -298
  41. package/src/editor/plugins/__tests__/withEditableAPIGetFragment.test.tsx +0 -177
  42. package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +0 -538
  43. package/src/editor/plugins/__tests__/withEditableAPISelectionsOverlapping.test.tsx +0 -162
  44. package/src/editor/plugins/__tests__/withPortableTextLists.test.tsx +0 -65
  45. package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +0 -612
  46. package/src/editor/plugins/__tests__/withPortableTextSelections.test.tsx +0 -103
  47. package/src/editor/plugins/__tests__/withUndoRedo.test.tsx +0 -147
  48. package/src/internal-utils/__tests__/valueNormalization.test.tsx +0 -79
  49. package/src/operations/behavior.operation.insert-inline-object.ts +0 -59
  50. package/src/operations/behavior.operation.insert-span.ts +0 -48
package/lib/index.js CHANGED
@@ -8,15 +8,14 @@ import { Element as Element$1, Text, Range, Editor, Node, Point, Path, Transform
8
8
  import { useSelected, useSlateSelector, useSlateStatic, useSlate, Editable, ReactEditor, withReact, Slate } from "slate-react";
9
9
  import debug$f from "debug";
10
10
  import { DOMEditor, isDOMNode, EDITOR_TO_PENDING_SELECTION, IS_FOCUSED, IS_READ_ONLY } from "slate-dom";
11
- import { getBlockStartPoint, getBlockKeyFromSelectionPoint, getChildKeyFromSelectionPoint, blockOffsetToSpanSelectionPoint, parseBlocks, parseBlock, parseAnnotation, parseInlineObject, isKeyedSegment, isListBlock, isTypedObject, getSelectionStartPoint, getSelectionEndPoint, getTextBlockText } from "./_chunks-es/util.slice-blocks.js";
11
+ import { getBlockStartPoint, getBlockKeyFromSelectionPoint, getChildKeyFromSelectionPoint, blockOffsetToSpanSelectionPoint, defaultKeyGenerator, parseBlocks, parseBlock, parseAnnotation, isKeyedSegment, isListBlock, isTypedObject, getSelectionStartPoint, getSelectionEndPoint, getTextBlockText } from "./_chunks-es/util.slice-blocks.js";
12
12
  import { getBlockEndPoint, isSelectionCollapsed, isEqualSelectionPoints, isEmptyTextBlock } from "./_chunks-es/util.is-selection-collapsed.js";
13
13
  import isEqual from "lodash/isEqual.js";
14
14
  import { isTextBlock, isSpan, compileSchema } from "@portabletext/schema";
15
15
  import { defineSchema } from "@portabletext/schema";
16
16
  import { isSelectionCollapsed as isSelectionCollapsed$1, getFocusTextBlock, getFocusSpan as getFocusSpan$1, isSelectionExpanded, getFocusBlock as getFocusBlock$1, getSelectedValue, getSelectionStartPoint as getSelectionStartPoint$1, getFocusChild as getFocusChild$1 } from "./_chunks-es/selector.is-selection-expanded.js";
17
- import { getFocusInlineObject, getSelectedBlocks, getSelectionStartBlock as getSelectionStartBlock$1, getSelectionEndBlock as getSelectionEndBlock$1, isOverlappingSelection, isSelectingEntireBlocks, getMarkState, getActiveDecorators, getActiveAnnotationsMarks, getTrimmedSelection, getCaretWordSelection, getFocusBlockObject, getPreviousBlock, getNextBlock, isAtTheEndOfBlock, isAtTheStartOfBlock, getFirstBlock as getFirstBlock$1, getLastBlock as getLastBlock$1, getFocusListBlock, getSelectionEndPoint as getSelectionEndPoint$1, isActiveAnnotation, isActiveDecorator, getActiveAnnotations, getSelectedTextBlocks, isActiveListItem, isActiveStyle } from "./_chunks-es/selector.is-selecting-entire-blocks.js";
18
- import getRandomValues from "get-random-values-esm";
19
- import { defineBehavior, forward, raise, effect } from "./behaviors/index.js";
17
+ import { getFocusInlineObject, getSelectedBlocks, getSelectionStartBlock as getSelectionStartBlock$1, getSelectionEndBlock as getSelectionEndBlock$1, isOverlappingSelection, isSelectingEntireBlocks, getMarkState, getActiveDecorators, getActiveAnnotationsMarks, getTrimmedSelection, isActiveAnnotation, getCaretWordSelection, getFocusBlockObject, getPreviousBlock, getNextBlock, isAtTheEndOfBlock, isAtTheStartOfBlock, getFirstBlock as getFirstBlock$1, getLastBlock as getLastBlock$1, getFocusListBlock, getSelectionEndPoint as getSelectionEndPoint$1, isActiveDecorator, getActiveAnnotations, getSelectedTextBlocks, isActiveListItem, isActiveStyle } from "./_chunks-es/selector.is-selecting-entire-blocks.js";
18
+ import { defineBehavior, forward, raise, effect, execute } from "./behaviors/index.js";
20
19
  import uniq from "lodash/uniq.js";
21
20
  import { setup, fromCallback, assign, and, enqueueActions, emit, assertEvent, raise as raise$1, not, createActor } from "xstate";
22
21
  import { compileSchemaDefinitionToPortableTextMemberSchemaTypes, createPortableTextMemberSchemaTypes, portableTextMemberSchemaTypesToSchema } from "@portabletext/sanity-bridge";
@@ -770,25 +769,6 @@ function getDragSelection({
770
769
  }
771
770
  return dragSelection;
772
771
  }
773
- const defaultKeyGenerator = () => randomKey(12), getByteHexTable = /* @__PURE__ */ (() => {
774
- let table;
775
- return () => {
776
- if (table)
777
- return table;
778
- table = [];
779
- for (let i = 0; i < 256; ++i)
780
- table[i] = (i + 256).toString(16).slice(1);
781
- return table;
782
- };
783
- })();
784
- function whatwgRNG(length = 16) {
785
- const rnds8 = new Uint8Array(length);
786
- return getRandomValues(rnds8), rnds8;
787
- }
788
- function randomKey(length) {
789
- const table = getByteHexTable();
790
- return whatwgRNG(length).reduce((str, n) => str + table[n], "").slice(0, length);
791
- }
792
772
  function createEditorPriority(config) {
793
773
  return {
794
774
  id: defaultKeyGenerator(),
@@ -4046,9 +4026,9 @@ const addAnnotationOperationImplementation = ({
4046
4026
  for (const [span, path] of children) {
4047
4027
  if (!editor.isTextSpan(span) || !Range.includes(editor.selection, path))
4048
4028
  continue;
4049
- const marks = span.marks ?? [], existingSameTypeAnnotations = marks.filter((mark) => markDefs.some((markDef) => markDef._key === mark && markDef._type === parsedAnnotation._type));
4029
+ const marks = span.marks ?? [];
4050
4030
  Transforms.setNodes(editor, {
4051
- marks: [...marks.filter((mark) => !existingSameTypeAnnotations.includes(mark)), annotationKey]
4031
+ marks: [...marks, annotationKey]
4052
4032
  }, {
4053
4033
  at: path
4054
4034
  }), spanPath = [{
@@ -4619,77 +4599,7 @@ function domRectsIntersect(rect, compareRect) {
4619
4599
  const middle = (compareRect.top + compareRect.bottom) / 2;
4620
4600
  return rect.top <= middle && rect.bottom >= middle;
4621
4601
  }
4622
- const insertInlineObjectOperationImplementation = ({
4623
- context,
4624
- operation
4625
- }) => {
4626
- const parsedInlineObject = parseInlineObject({
4627
- context,
4628
- inlineObject: {
4629
- _type: operation.inlineObject.name,
4630
- ...operation.inlineObject.value ?? {}
4631
- },
4632
- options: {
4633
- refreshKeys: !1,
4634
- validateFields: !0
4635
- }
4636
- });
4637
- if (!parsedInlineObject)
4638
- throw new Error(`Failed to parse inline object ${JSON.stringify(operation.inlineObject)}`);
4639
- if (!operation.editor.selection) {
4640
- console.error("Unable to insert inline object without selection");
4641
- return;
4642
- }
4643
- const [focusTextBlock] = Array.from(Editor.nodes(operation.editor, {
4644
- at: operation.editor.selection.focus.path,
4645
- match: (node) => operation.editor.isTextBlock(node)
4646
- })).at(0) ?? [void 0, void 0];
4647
- if (!focusTextBlock) {
4648
- console.error("Unable to perform action without focus text block");
4649
- return;
4650
- }
4651
- const child = toSlateValue([{
4652
- _type: context.schema.block.name,
4653
- _key: context.keyGenerator(),
4654
- children: [parsedInlineObject]
4655
- }], {
4656
- schemaTypes: context.schema
4657
- }).at(0)?.children.at(0);
4658
- if (!child) {
4659
- console.error("Unable to insert inline object");
4660
- return;
4661
- }
4662
- Transforms.insertNodes(operation.editor, child);
4663
- }, insertSpanOperationImplementation = ({
4664
- context,
4665
- operation
4666
- }) => {
4667
- if (!operation.editor.selection) {
4668
- console.error("Unable to perform action without selection", operation);
4669
- return;
4670
- }
4671
- const [focusBlock, focusBlockPath] = Array.from(Editor.nodes(operation.editor, {
4672
- at: operation.editor.selection.focus.path,
4673
- match: (node) => operation.editor.isTextBlock(node)
4674
- }))[0] ?? [void 0, void 0];
4675
- if (!focusBlock || !focusBlockPath) {
4676
- console.error("Unable to perform action without focus block", operation);
4677
- return;
4678
- }
4679
- const markDefs = focusBlock.markDefs ?? [], annotations = operation.annotations ? operation.annotations.map((annotation) => ({
4680
- _type: annotation.name,
4681
- _key: context.keyGenerator(),
4682
- ...annotation.value
4683
- })) : void 0;
4684
- annotations && annotations.length > 0 && Transforms.setNodes(operation.editor, {
4685
- markDefs: [...markDefs, ...annotations]
4686
- }), Transforms.insertNodes(operation.editor, {
4687
- _type: "span",
4688
- _key: context.keyGenerator(),
4689
- text: operation.text,
4690
- marks: [...annotations?.map((annotation) => annotation._key) ?? [], ...operation.decorators ?? []]
4691
- });
4692
- }, insertBlockOperationImplementation = ({
4602
+ const insertBlockOperationImplementation = ({
4693
4603
  context,
4694
4604
  operation
4695
4605
  }) => {
@@ -4973,8 +4883,6 @@ const moveBackwardOperationImplementation = ({
4973
4883
  "history.redo": historyRedoOperationImplementation,
4974
4884
  "history.undo": historyUndoOperationImplementation,
4975
4885
  "insert.block": insertBlockOperationImplementation,
4976
- "insert.inline object": insertInlineObjectOperationImplementation,
4977
- "insert.span": insertSpanOperationImplementation,
4978
4886
  "insert.text": insertTextOperationImplementation,
4979
4887
  "move.backward": moveBackwardOperationImplementation,
4980
4888
  "move.block": moveBlockOperationImplementation,
@@ -5071,20 +4979,6 @@ function performOperation({
5071
4979
  });
5072
4980
  break;
5073
4981
  }
5074
- case "insert.inline object": {
5075
- behaviorOperationImplementations["insert.inline object"]({
5076
- context,
5077
- operation
5078
- });
5079
- break;
5080
- }
5081
- case "insert.span": {
5082
- behaviorOperationImplementations["insert.span"]({
5083
- context,
5084
- operation
5085
- });
5086
- break;
5087
- }
5088
4982
  case "insert.text": {
5089
4983
  behaviorOperationImplementations["insert.text"]({
5090
4984
  context,
@@ -6713,9 +6607,24 @@ const addAnnotationOnCollapsedSelection = defineBehavior({
6713
6607
  type: "annotation.add",
6714
6608
  annotation: event.annotation
6715
6609
  })]]
6716
- }), coreAnnotationBehaviors = {
6717
- addAnnotationOnCollapsedSelection
6718
- }, defaultKeyboardShortcuts = {
6610
+ }), preventOverlappingAnnotations = defineBehavior({
6611
+ // Given an `annotation.add` event
6612
+ on: "annotation.add",
6613
+ // When the annotation is active in the selection
6614
+ guard: ({
6615
+ snapshot,
6616
+ event
6617
+ }) => isActiveAnnotation(event.annotation.name, {
6618
+ mode: "partial"
6619
+ })(snapshot),
6620
+ // Then the existing annotation is removed
6621
+ actions: [({
6622
+ event
6623
+ }) => [raise({
6624
+ type: "annotation.remove",
6625
+ annotation: event.annotation
6626
+ }), raise(event)]]
6627
+ }), coreAnnotationBehaviors = [addAnnotationOnCollapsedSelection, preventOverlappingAnnotations], defaultKeyboardShortcuts = {
6719
6628
  arrowDown: createKeyboardShortcut({
6720
6629
  default: [{
6721
6630
  key: "ArrowDown",
@@ -7843,7 +7752,7 @@ const MAX_LIST_LEVEL = 10, clearListOnBackspace = defineBehavior({
7843
7752
  inheritListLevel,
7844
7753
  inheritListItem,
7845
7754
  inheritListProperties
7846
- }, coreBehaviorsConfig = [coreAnnotationBehaviors.addAnnotationOnCollapsedSelection, coreDecoratorBehaviors.strongShortcut, coreDecoratorBehaviors.emShortcut, coreDecoratorBehaviors.underlineShortcut, coreDecoratorBehaviors.codeShortcut, ...coreDndBehaviors, coreBlockObjectBehaviors.clickingAboveLonelyBlockObject, coreBlockObjectBehaviors.clickingBelowLonelyBlockObject, coreBlockObjectBehaviors.arrowDownOnLonelyBlockObject, coreBlockObjectBehaviors.arrowUpOnLonelyBlockObject, coreBlockObjectBehaviors.breakingBlockObject, coreBlockObjectBehaviors.deletingEmptyTextBlockAfterBlockObject, coreBlockObjectBehaviors.deletingEmptyTextBlockBeforeBlockObject, coreListBehaviors.clearListOnBackspace, coreListBehaviors.unindentListOnBackspace, coreListBehaviors.mergeTextIntoListOnDelete, coreListBehaviors.mergeTextIntoListOnBackspace, coreListBehaviors.deletingListFromStart, coreListBehaviors.clearListOnEnter, coreListBehaviors.indentListOnTab, coreListBehaviors.unindentListOnShiftTab, coreListBehaviors.inheritListLevel, coreListBehaviors.inheritListItem, coreListBehaviors.inheritListProperties, coreInsertBreakBehaviors.breakingAtTheEndOfTextBlock, coreInsertBreakBehaviors.breakingAtTheStartOfTextBlock, coreInsertBreakBehaviors.breakingEntireDocument, coreInsertBreakBehaviors.breakingEntireBlocks, coreInsertBreakBehaviors.breakingInlineObject].map((behavior) => ({
7755
+ }, coreBehaviorsConfig = [...coreAnnotationBehaviors, coreDecoratorBehaviors.strongShortcut, coreDecoratorBehaviors.emShortcut, coreDecoratorBehaviors.underlineShortcut, coreDecoratorBehaviors.codeShortcut, ...coreDndBehaviors, coreBlockObjectBehaviors.clickingAboveLonelyBlockObject, coreBlockObjectBehaviors.clickingBelowLonelyBlockObject, coreBlockObjectBehaviors.arrowDownOnLonelyBlockObject, coreBlockObjectBehaviors.arrowUpOnLonelyBlockObject, coreBlockObjectBehaviors.breakingBlockObject, coreBlockObjectBehaviors.deletingEmptyTextBlockAfterBlockObject, coreBlockObjectBehaviors.deletingEmptyTextBlockBeforeBlockObject, coreListBehaviors.clearListOnBackspace, coreListBehaviors.unindentListOnBackspace, coreListBehaviors.mergeTextIntoListOnDelete, coreListBehaviors.mergeTextIntoListOnBackspace, coreListBehaviors.deletingListFromStart, coreListBehaviors.clearListOnEnter, coreListBehaviors.indentListOnTab, coreListBehaviors.unindentListOnShiftTab, coreListBehaviors.inheritListLevel, coreListBehaviors.inheritListItem, coreListBehaviors.inheritListProperties, coreInsertBreakBehaviors.breakingAtTheEndOfTextBlock, coreInsertBreakBehaviors.breakingAtTheStartOfTextBlock, coreInsertBreakBehaviors.breakingEntireDocument, coreInsertBreakBehaviors.breakingEntireBlocks, coreInsertBreakBehaviors.breakingInlineObject].map((behavior) => ({
7847
7756
  behavior,
7848
7757
  priority: corePriority
7849
7758
  })), abstractAnnotationBehaviors = [defineBehavior({
@@ -8477,6 +8386,23 @@ const MAX_LIST_LEVEL = 10, clearListOnBackspace = defineBehavior({
8477
8386
  actions: [() => [raise({
8478
8387
  type: "split"
8479
8388
  })]]
8389
+ }), defineBehavior({
8390
+ on: "insert.inline object",
8391
+ actions: [({
8392
+ snapshot,
8393
+ event
8394
+ }) => [execute({
8395
+ type: "insert.block",
8396
+ block: {
8397
+ _type: snapshot.context.schema.block.name,
8398
+ children: [{
8399
+ _type: event.inlineObject.name,
8400
+ ...event.inlineObject.value
8401
+ }]
8402
+ },
8403
+ placement: "auto",
8404
+ select: "end"
8405
+ })]]
8480
8406
  }), defineBehavior({
8481
8407
  on: "insert.soft break",
8482
8408
  actions: [() => [raise({
@@ -8484,6 +8410,37 @@ const MAX_LIST_LEVEL = 10, clearListOnBackspace = defineBehavior({
8484
8410
  text: `
8485
8411
  `
8486
8412
  })]]
8413
+ }), defineBehavior({
8414
+ on: "insert.span",
8415
+ guard: ({
8416
+ snapshot,
8417
+ event
8418
+ }) => ({
8419
+ markDefs: event.annotations?.map((annotation) => ({
8420
+ _type: annotation.name,
8421
+ _key: snapshot.context.keyGenerator(),
8422
+ ...annotation.value
8423
+ })) ?? []
8424
+ }),
8425
+ actions: [({
8426
+ snapshot,
8427
+ event
8428
+ }, {
8429
+ markDefs
8430
+ }) => [execute({
8431
+ type: "insert.block",
8432
+ block: {
8433
+ _type: snapshot.context.schema.block.name,
8434
+ children: [{
8435
+ _type: snapshot.context.schema.span.name,
8436
+ text: event.text,
8437
+ marks: [...event.decorators ?? [], ...markDefs.map((markDef) => markDef._key)]
8438
+ }],
8439
+ markDefs
8440
+ },
8441
+ placement: "auto",
8442
+ select: "end"
8443
+ })]]
8487
8444
  })], abstractKeyboardBehaviors = [
8488
8445
  /**
8489
8446
  * Allow raising an `insert.break` event when pressing Enter on an inline
@@ -9096,7 +9053,7 @@ const MAX_LIST_LEVEL = 10, clearListOnBackspace = defineBehavior({
9096
9053
  function isSyntheticBehaviorEvent(event) {
9097
9054
  return !isCustomBehaviorEvent(event) && !isNativeBehaviorEvent(event) && !isAbstractBehaviorEvent(event);
9098
9055
  }
9099
- const abstractBehaviorEventTypes = ["annotation.set", "annotation.toggle", "decorator.toggle", "delete.backward", "delete.block", "delete.child", "delete.forward", "delete.text", "deserialize", "deserialize.data", "deserialization.success", "deserialization.failure", "insert.blocks", "insert.break", "insert.soft break", "list item.add", "list item.remove", "list item.toggle", "move.block down", "move.block up", "select.previous block", "select.next block", "serialize", "serialize.data", "serialization.success", "serialization.failure", "split", "style.add", "style.remove", "style.toggle"];
9056
+ const abstractBehaviorEventTypes = ["annotation.set", "annotation.toggle", "decorator.toggle", "delete.backward", "delete.block", "delete.child", "delete.forward", "delete.text", "deserialize", "deserialize.data", "deserialization.success", "deserialization.failure", "insert.blocks", "insert.break", "insert.inline object", "insert.soft break", "insert.span", "list item.add", "list item.remove", "list item.toggle", "move.block down", "move.block up", "select.previous block", "select.next block", "serialize", "serialize.data", "serialization.success", "serialization.failure", "split", "style.add", "style.remove", "style.toggle"];
9100
9057
  function isAbstractBehaviorEvent(event) {
9101
9058
  return abstractBehaviorEventTypes.includes(event.type);
9102
9059
  }
@@ -10371,7 +10328,22 @@ function createEditableAPI(editor, editorActor) {
10371
10328
  },
10372
10329
  addAnnotation: (type, value) => {
10373
10330
  let paths;
10374
- return Editor.withoutNormalizing(editor, () => {
10331
+ const snapshot = getEditorSnapshot({
10332
+ editorActorSnapshot: editorActor.getSnapshot(),
10333
+ slateEditorInstance: editor
10334
+ });
10335
+ return isActiveAnnotation(type.name, {
10336
+ mode: "partial"
10337
+ })(snapshot) && editorActor.send({
10338
+ type: "behavior event",
10339
+ behaviorEvent: {
10340
+ type: "annotation.remove",
10341
+ annotation: {
10342
+ name: type.name
10343
+ }
10344
+ },
10345
+ editor
10346
+ }), Editor.withoutNormalizing(editor, () => {
10375
10347
  paths = addAnnotationOperationImplementation({
10376
10348
  context: {
10377
10349
  keyGenerator: editorActor.getSnapshot().context.keyGenerator,