@portabletext/plugin-character-pair-decorator 1.0.1 → 1.0.2

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.
package/dist/index.cjs CHANGED
@@ -38,7 +38,7 @@ function createCharacterPairDecoratorBehavior(config) {
38
38
  if (decorator === void 0)
39
39
  return !1;
40
40
  const focusTextBlock = selectors__namespace.getFocusTextBlock(snapshot), selectionStartPoint = selectors__namespace.getSelectionStartPoint(snapshot), selectionStartOffset = selectionStartPoint ? utils__namespace.spanSelectionPointToBlockOffset({
41
- value: snapshot.context.value,
41
+ context: snapshot.context,
42
42
  selectionPoint: selectionStartPoint
43
43
  }) : void 0;
44
44
  if (!focusTextBlock || !selectionStartOffset)
@@ -71,7 +71,7 @@ function createCharacterPairDecoratorBehavior(config) {
71
71
  };
72
72
  if (prefixOffsets.focus.offset - prefixOffsets.anchor.offset > 1) {
73
73
  const prefixSelection = utils__namespace.blockOffsetsToSelection({
74
- value: snapshot.context.value,
74
+ context: snapshot.context,
75
75
  offsets: prefixOffsets
76
76
  }), inlineObjectBeforePrefixFocus = selectors__namespace.getPreviousInlineObject(
77
77
  {
@@ -85,7 +85,7 @@ function createCharacterPairDecoratorBehavior(config) {
85
85
  }
86
86
  }
87
87
  ), inlineObjectBeforePrefixFocusOffset = inlineObjectBeforePrefixFocus ? utils__namespace.childSelectionPointToBlockOffset({
88
- value: snapshot.context.value,
88
+ context: snapshot.context,
89
89
  selectionPoint: {
90
90
  path: inlineObjectBeforePrefixFocus.path,
91
91
  offset: 0
@@ -96,7 +96,7 @@ function createCharacterPairDecoratorBehavior(config) {
96
96
  }
97
97
  if (suffixOffsets.focus.offset - suffixOffsets.anchor.offset > 1) {
98
98
  const previousInlineObject = selectors__namespace.getPreviousInlineObject(snapshot), previousInlineObjectOffset = previousInlineObject ? utils__namespace.childSelectionPointToBlockOffset({
99
- value: snapshot.context.value,
99
+ context: snapshot.context,
100
100
  selectionPoint: {
101
101
  path: previousInlineObject.path,
102
102
  offset: 0
@@ -174,10 +174,10 @@ const decorateListener = ({ sendBack, input }) => input.editor.registerBehavior(
174
174
  if (!event.at)
175
175
  return { blockOffsets: void 0 };
176
176
  const anchor = utils__namespace.spanSelectionPointToBlockOffset({
177
- value: snapshot.context.value,
177
+ context: snapshot.context,
178
178
  selectionPoint: event.at.anchor
179
179
  }), focus = utils__namespace.spanSelectionPointToBlockOffset({
180
- value: snapshot.context.value,
180
+ context: snapshot.context,
181
181
  selectionPoint: event.at.focus
182
182
  });
183
183
  return !anchor || !focus ? { blockOffsets: void 0 } : {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/regex.character-pair.ts","../src/behavior.character-pair-decorator.ts","../src/plugin.character-pair-decorator.ts"],"sourcesContent":["export function createCharacterPairRegex(char: string, amount: number) {\n // Negative lookbehind: Ensures that the matched sequence is not preceded by the same character\n const prePrefix = `(?<!\\\\${char})`\n\n // Repeats the character `amount` times\n const prefix = `\\\\${char}`.repeat(Math.max(amount, 1))\n\n // Negative lookahead: Ensures that the opening pair (**, *, etc.) is not followed by a space\n const postPrefix = `(?!\\\\s)`\n\n // Captures the content inside the pair\n const content = `([^${char}\\\\n]+?)`\n\n // Negative lookbehind: Ensures that the content is not followed by a space\n const preSuffix = `(?<!\\\\s)`\n\n // Repeats the character `amount` times\n const suffix = `\\\\${char}`.repeat(Math.max(amount, 1))\n\n // Negative lookahead: Ensures that the matched sequence is not followed by the same character\n const postSuffix = `(?!\\\\${char})`\n\n return `${prePrefix}${prefix}${postPrefix}${content}${preSuffix}${suffix}${postSuffix}`\n}\n","import type {BlockOffset, EditorSchema} from '@portabletext/editor'\nimport {defineBehavior, effect, execute} from '@portabletext/editor/behaviors'\nimport * as selectors from '@portabletext/editor/selectors'\nimport * as utils from '@portabletext/editor/utils'\nimport {createCharacterPairRegex} from './regex.character-pair'\n\nexport function createCharacterPairDecoratorBehavior(config: {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n pair: {char: string; amount: number}\n onDecorate: (offset: BlockOffset) => void\n}) {\n if (config.pair.amount < 1) {\n console.warn(\n `The amount of characters in the pair should be greater than 0`,\n )\n }\n\n const pairRegex = createCharacterPairRegex(\n config.pair.char,\n config.pair.amount,\n )\n const regEx = new RegExp(`(${pairRegex})$`)\n\n return defineBehavior({\n on: 'insert.text',\n guard: ({snapshot, event}) => {\n if (config.pair.amount < 1) {\n return false\n }\n\n const decorator = config.decorator({schema: snapshot.context.schema})\n\n if (decorator === undefined) {\n return false\n }\n\n const focusTextBlock = selectors.getFocusTextBlock(snapshot)\n const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)\n const selectionStartOffset = selectionStartPoint\n ? utils.spanSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: selectionStartPoint,\n })\n : undefined\n\n if (!focusTextBlock || !selectionStartOffset) {\n return false\n }\n\n const textBefore = selectors.getBlockTextBefore(snapshot)\n const newText = `${textBefore}${event.text}`\n const textToDecorate = newText.match(regEx)?.at(0)\n\n if (textToDecorate === undefined) {\n return false\n }\n\n const prefixOffsets = {\n anchor: {\n path: focusTextBlock.path,\n // Example: \"foo **bar**\".length - \"**bar**\".length = 4\n offset: newText.length - textToDecorate.length,\n },\n focus: {\n path: focusTextBlock.path,\n // Example: \"foo **bar**\".length - \"**bar**\".length + \"*\".length * 2 = 6\n offset:\n newText.length -\n textToDecorate.length +\n config.pair.char.length * config.pair.amount,\n },\n }\n\n const suffixOffsets = {\n anchor: {\n path: focusTextBlock.path,\n // Example: \"foo **bar*|\" (10) + \"*\".length - 2 = 9\n offset:\n selectionStartOffset.offset +\n event.text.length -\n config.pair.char.length * config.pair.amount,\n },\n focus: {\n path: focusTextBlock.path,\n // Example: \"foo **bar*|\" (10) + \"*\".length = 11\n offset: selectionStartOffset.offset + event.text.length,\n },\n }\n\n // If the prefix is more than one character, then we need to check if\n // there is an inline object inside it\n if (prefixOffsets.focus.offset - prefixOffsets.anchor.offset > 1) {\n const prefixSelection = utils.blockOffsetsToSelection({\n value: snapshot.context.value,\n offsets: prefixOffsets,\n })\n const inlineObjectBeforePrefixFocus = selectors.getPreviousInlineObject(\n {\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: prefixSelection\n ? {\n anchor: prefixSelection.focus,\n focus: prefixSelection.focus,\n }\n : null,\n },\n },\n )\n const inlineObjectBeforePrefixFocusOffset =\n inlineObjectBeforePrefixFocus\n ? utils.childSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: {\n path: inlineObjectBeforePrefixFocus.path,\n offset: 0,\n },\n })\n : undefined\n\n if (\n inlineObjectBeforePrefixFocusOffset &&\n inlineObjectBeforePrefixFocusOffset.offset >\n prefixOffsets.anchor.offset &&\n inlineObjectBeforePrefixFocusOffset.offset <\n prefixOffsets.focus.offset\n ) {\n return false\n }\n }\n\n // If the suffix is more than one character, then we need to check if\n // there is an inline object inside it\n if (suffixOffsets.focus.offset - suffixOffsets.anchor.offset > 1) {\n const previousInlineObject = selectors.getPreviousInlineObject(snapshot)\n const previousInlineObjectOffset = previousInlineObject\n ? utils.childSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: {\n path: previousInlineObject.path,\n offset: 0,\n },\n })\n : undefined\n\n if (\n previousInlineObjectOffset &&\n previousInlineObjectOffset.offset > suffixOffsets.anchor.offset &&\n previousInlineObjectOffset.offset < suffixOffsets.focus.offset\n ) {\n return false\n }\n }\n\n return {\n prefixOffsets,\n suffixOffsets,\n decorator,\n }\n },\n actions: [\n // Insert the text as usual in its own undo step\n ({event}) => [execute(event)],\n (_, {prefixOffsets, suffixOffsets, decorator}) => [\n // Decorate the text between the prefix and suffix\n execute({\n type: 'decorator.add',\n decorator,\n at: {\n anchor: prefixOffsets.focus,\n focus: suffixOffsets.anchor,\n },\n }),\n // Delete the suffix\n execute({\n type: 'delete.text',\n at: suffixOffsets,\n }),\n // Delete the prefix\n execute({\n type: 'delete.text',\n at: prefixOffsets,\n }),\n // Toggle the decorator off so the next inserted text isn't emphasized\n execute({\n type: 'decorator.remove',\n decorator,\n }),\n effect(() => {\n config.onDecorate({\n ...suffixOffsets.anchor,\n offset:\n suffixOffsets.anchor.offset -\n (prefixOffsets.focus.offset - prefixOffsets.anchor.offset),\n })\n }),\n ],\n ],\n })\n}\n","import type {BlockOffset, Editor, EditorSchema} from '@portabletext/editor'\nimport {useEditor} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n execute,\n forward,\n} from '@portabletext/editor/behaviors'\nimport * as utils from '@portabletext/editor/utils'\nimport {useActorRef} from '@xstate/react'\nimport {isDeepEqual} from 'remeda'\nimport {\n assign,\n fromCallback,\n setup,\n type AnyEventObject,\n type CallbackLogicFunction,\n} from 'xstate'\nimport {createCharacterPairDecoratorBehavior} from './behavior.character-pair-decorator'\n\n/**\n * @beta\n */\nexport function CharacterPairDecoratorPlugin(config: {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n pair: {char: string; amount: number}\n}) {\n const editor = useEditor()\n\n useActorRef(decoratorPairMachine, {\n input: {\n editor,\n decorator: config.decorator,\n pair: config.pair,\n },\n })\n\n return null\n}\n\ntype DecoratorPairEvent =\n | {\n type: 'decorator.add'\n blockOffset: BlockOffset\n }\n | {\n type: 'selection'\n blockOffsets?: {\n anchor: BlockOffset\n focus: BlockOffset\n }\n }\n | {\n type: 'delete.backward'\n }\n\nconst decorateListener: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n pair: {char: string; amount: number}\n }\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: createCharacterPairDecoratorBehavior({\n decorator: input.decorator,\n pair: input.pair,\n onDecorate: (offset) => {\n sendBack({type: 'decorator.add', blockOffset: offset})\n },\n }),\n })\n\n return unregister\n}\n\nconst selectionListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'select',\n guard: ({snapshot, event}) => {\n if (!event.at) {\n return {blockOffsets: undefined}\n }\n\n const anchor = utils.spanSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: event.at.anchor,\n })\n const focus = utils.spanSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: event.at.focus,\n })\n\n if (!anchor || !focus) {\n return {blockOffsets: undefined}\n }\n\n return {\n blockOffsets: {\n anchor,\n focus,\n },\n }\n },\n actions: [\n ({event}, {blockOffsets}) => [\n {\n type: 'effect',\n effect: () => {\n sendBack({type: 'selection', blockOffsets})\n },\n },\n forward(event),\n ],\n ],\n }),\n })\n\n return unregister\n}\n\nconst deleteBackwardListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'delete.backward',\n actions: [\n () => [\n execute({\n type: 'history.undo',\n }),\n effect(() => {\n sendBack({type: 'delete.backward'})\n }),\n ],\n ],\n }),\n })\n\n return unregister\n}\n\nconst decoratorPairMachine = setup({\n types: {\n context: {} as {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n offsetAfterDecorator?: BlockOffset\n pair: {char: string; amount: number}\n },\n input: {} as {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n pair: {char: string; amount: number}\n },\n events: {} as DecoratorPairEvent,\n },\n actors: {\n 'decorate listener': fromCallback(decorateListener),\n 'delete.backward listener': fromCallback(deleteBackwardListenerCallback),\n 'selection listener': fromCallback(selectionListenerCallback),\n },\n}).createMachine({\n id: 'decorator pair',\n context: ({input}) => ({\n decorator: input.decorator,\n editor: input.editor,\n pair: input.pair,\n }),\n initial: 'idle',\n states: {\n 'idle': {\n invoke: [\n {\n src: 'decorate listener',\n input: ({context}) => ({\n decorator: context.decorator,\n editor: context.editor,\n pair: context.pair,\n }),\n },\n ],\n on: {\n 'decorator.add': {\n target: 'decorator added',\n actions: assign({\n offsetAfterDecorator: ({event}) => event.blockOffset,\n }),\n },\n },\n },\n 'decorator added': {\n exit: [\n assign({\n offsetAfterDecorator: undefined,\n }),\n ],\n invoke: [\n {\n src: 'selection listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'delete.backward listener',\n input: ({context}) => ({editor: context.editor}),\n },\n ],\n on: {\n 'selection': {\n target: 'idle',\n guard: ({context, event}) => {\n const selectionChanged = !isDeepEqual(\n {\n anchor: context.offsetAfterDecorator,\n focus: context.offsetAfterDecorator,\n },\n event.blockOffsets,\n )\n\n return selectionChanged\n },\n },\n 'delete.backward': {\n target: 'idle',\n },\n },\n },\n },\n})\n"],"names":["defineBehavior","selectors","utils","execute","effect","editor","useEditor","useActorRef","forward","setup","fromCallback","assign","isDeepEqual"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/regex.character-pair.ts","../src/behavior.character-pair-decorator.ts","../src/plugin.character-pair-decorator.ts"],"sourcesContent":["export function createCharacterPairRegex(char: string, amount: number) {\n // Negative lookbehind: Ensures that the matched sequence is not preceded by the same character\n const prePrefix = `(?<!\\\\${char})`\n\n // Repeats the character `amount` times\n const prefix = `\\\\${char}`.repeat(Math.max(amount, 1))\n\n // Negative lookahead: Ensures that the opening pair (**, *, etc.) is not followed by a space\n const postPrefix = `(?!\\\\s)`\n\n // Captures the content inside the pair\n const content = `([^${char}\\\\n]+?)`\n\n // Negative lookbehind: Ensures that the content is not followed by a space\n const preSuffix = `(?<!\\\\s)`\n\n // Repeats the character `amount` times\n const suffix = `\\\\${char}`.repeat(Math.max(amount, 1))\n\n // Negative lookahead: Ensures that the matched sequence is not followed by the same character\n const postSuffix = `(?!\\\\${char})`\n\n return `${prePrefix}${prefix}${postPrefix}${content}${preSuffix}${suffix}${postSuffix}`\n}\n","import type {BlockOffset, EditorSchema} from '@portabletext/editor'\nimport {defineBehavior, effect, execute} from '@portabletext/editor/behaviors'\nimport * as selectors from '@portabletext/editor/selectors'\nimport * as utils from '@portabletext/editor/utils'\nimport {createCharacterPairRegex} from './regex.character-pair'\n\nexport function createCharacterPairDecoratorBehavior(config: {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n pair: {char: string; amount: number}\n onDecorate: (offset: BlockOffset) => void\n}) {\n if (config.pair.amount < 1) {\n console.warn(\n `The amount of characters in the pair should be greater than 0`,\n )\n }\n\n const pairRegex = createCharacterPairRegex(\n config.pair.char,\n config.pair.amount,\n )\n const regEx = new RegExp(`(${pairRegex})$`)\n\n return defineBehavior({\n on: 'insert.text',\n guard: ({snapshot, event}) => {\n if (config.pair.amount < 1) {\n return false\n }\n\n const decorator = config.decorator({schema: snapshot.context.schema})\n\n if (decorator === undefined) {\n return false\n }\n\n const focusTextBlock = selectors.getFocusTextBlock(snapshot)\n const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)\n const selectionStartOffset = selectionStartPoint\n ? utils.spanSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: selectionStartPoint,\n })\n : undefined\n\n if (!focusTextBlock || !selectionStartOffset) {\n return false\n }\n\n const textBefore = selectors.getBlockTextBefore(snapshot)\n const newText = `${textBefore}${event.text}`\n const textToDecorate = newText.match(regEx)?.at(0)\n\n if (textToDecorate === undefined) {\n return false\n }\n\n const prefixOffsets = {\n anchor: {\n path: focusTextBlock.path,\n // Example: \"foo **bar**\".length - \"**bar**\".length = 4\n offset: newText.length - textToDecorate.length,\n },\n focus: {\n path: focusTextBlock.path,\n // Example: \"foo **bar**\".length - \"**bar**\".length + \"*\".length * 2 = 6\n offset:\n newText.length -\n textToDecorate.length +\n config.pair.char.length * config.pair.amount,\n },\n }\n\n const suffixOffsets = {\n anchor: {\n path: focusTextBlock.path,\n // Example: \"foo **bar*|\" (10) + \"*\".length - 2 = 9\n offset:\n selectionStartOffset.offset +\n event.text.length -\n config.pair.char.length * config.pair.amount,\n },\n focus: {\n path: focusTextBlock.path,\n // Example: \"foo **bar*|\" (10) + \"*\".length = 11\n offset: selectionStartOffset.offset + event.text.length,\n },\n }\n\n // If the prefix is more than one character, then we need to check if\n // there is an inline object inside it\n if (prefixOffsets.focus.offset - prefixOffsets.anchor.offset > 1) {\n const prefixSelection = utils.blockOffsetsToSelection({\n context: snapshot.context,\n offsets: prefixOffsets,\n })\n const inlineObjectBeforePrefixFocus = selectors.getPreviousInlineObject(\n {\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: prefixSelection\n ? {\n anchor: prefixSelection.focus,\n focus: prefixSelection.focus,\n }\n : null,\n },\n },\n )\n const inlineObjectBeforePrefixFocusOffset =\n inlineObjectBeforePrefixFocus\n ? utils.childSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: {\n path: inlineObjectBeforePrefixFocus.path,\n offset: 0,\n },\n })\n : undefined\n\n if (\n inlineObjectBeforePrefixFocusOffset &&\n inlineObjectBeforePrefixFocusOffset.offset >\n prefixOffsets.anchor.offset &&\n inlineObjectBeforePrefixFocusOffset.offset <\n prefixOffsets.focus.offset\n ) {\n return false\n }\n }\n\n // If the suffix is more than one character, then we need to check if\n // there is an inline object inside it\n if (suffixOffsets.focus.offset - suffixOffsets.anchor.offset > 1) {\n const previousInlineObject = selectors.getPreviousInlineObject(snapshot)\n const previousInlineObjectOffset = previousInlineObject\n ? utils.childSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: {\n path: previousInlineObject.path,\n offset: 0,\n },\n })\n : undefined\n\n if (\n previousInlineObjectOffset &&\n previousInlineObjectOffset.offset > suffixOffsets.anchor.offset &&\n previousInlineObjectOffset.offset < suffixOffsets.focus.offset\n ) {\n return false\n }\n }\n\n return {\n prefixOffsets,\n suffixOffsets,\n decorator,\n }\n },\n actions: [\n // Insert the text as usual in its own undo step\n ({event}) => [execute(event)],\n (_, {prefixOffsets, suffixOffsets, decorator}) => [\n // Decorate the text between the prefix and suffix\n execute({\n type: 'decorator.add',\n decorator,\n at: {\n anchor: prefixOffsets.focus,\n focus: suffixOffsets.anchor,\n },\n }),\n // Delete the suffix\n execute({\n type: 'delete.text',\n at: suffixOffsets,\n }),\n // Delete the prefix\n execute({\n type: 'delete.text',\n at: prefixOffsets,\n }),\n // Toggle the decorator off so the next inserted text isn't emphasized\n execute({\n type: 'decorator.remove',\n decorator,\n }),\n effect(() => {\n config.onDecorate({\n ...suffixOffsets.anchor,\n offset:\n suffixOffsets.anchor.offset -\n (prefixOffsets.focus.offset - prefixOffsets.anchor.offset),\n })\n }),\n ],\n ],\n })\n}\n","import type {BlockOffset, Editor, EditorSchema} from '@portabletext/editor'\nimport {useEditor} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n execute,\n forward,\n} from '@portabletext/editor/behaviors'\nimport * as utils from '@portabletext/editor/utils'\nimport {useActorRef} from '@xstate/react'\nimport {isDeepEqual} from 'remeda'\nimport {\n assign,\n fromCallback,\n setup,\n type AnyEventObject,\n type CallbackLogicFunction,\n} from 'xstate'\nimport {createCharacterPairDecoratorBehavior} from './behavior.character-pair-decorator'\n\n/**\n * @beta\n */\nexport function CharacterPairDecoratorPlugin(config: {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n pair: {char: string; amount: number}\n}) {\n const editor = useEditor()\n\n useActorRef(decoratorPairMachine, {\n input: {\n editor,\n decorator: config.decorator,\n pair: config.pair,\n },\n })\n\n return null\n}\n\ntype DecoratorPairEvent =\n | {\n type: 'decorator.add'\n blockOffset: BlockOffset\n }\n | {\n type: 'selection'\n blockOffsets?: {\n anchor: BlockOffset\n focus: BlockOffset\n }\n }\n | {\n type: 'delete.backward'\n }\n\nconst decorateListener: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n pair: {char: string; amount: number}\n }\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: createCharacterPairDecoratorBehavior({\n decorator: input.decorator,\n pair: input.pair,\n onDecorate: (offset) => {\n sendBack({type: 'decorator.add', blockOffset: offset})\n },\n }),\n })\n\n return unregister\n}\n\nconst selectionListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'select',\n guard: ({snapshot, event}) => {\n if (!event.at) {\n return {blockOffsets: undefined}\n }\n\n const anchor = utils.spanSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: event.at.anchor,\n })\n const focus = utils.spanSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: event.at.focus,\n })\n\n if (!anchor || !focus) {\n return {blockOffsets: undefined}\n }\n\n return {\n blockOffsets: {\n anchor,\n focus,\n },\n }\n },\n actions: [\n ({event}, {blockOffsets}) => [\n {\n type: 'effect',\n effect: () => {\n sendBack({type: 'selection', blockOffsets})\n },\n },\n forward(event),\n ],\n ],\n }),\n })\n\n return unregister\n}\n\nconst deleteBackwardListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'delete.backward',\n actions: [\n () => [\n execute({\n type: 'history.undo',\n }),\n effect(() => {\n sendBack({type: 'delete.backward'})\n }),\n ],\n ],\n }),\n })\n\n return unregister\n}\n\nconst decoratorPairMachine = setup({\n types: {\n context: {} as {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n offsetAfterDecorator?: BlockOffset\n pair: {char: string; amount: number}\n },\n input: {} as {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n pair: {char: string; amount: number}\n },\n events: {} as DecoratorPairEvent,\n },\n actors: {\n 'decorate listener': fromCallback(decorateListener),\n 'delete.backward listener': fromCallback(deleteBackwardListenerCallback),\n 'selection listener': fromCallback(selectionListenerCallback),\n },\n}).createMachine({\n id: 'decorator pair',\n context: ({input}) => ({\n decorator: input.decorator,\n editor: input.editor,\n pair: input.pair,\n }),\n initial: 'idle',\n states: {\n 'idle': {\n invoke: [\n {\n src: 'decorate listener',\n input: ({context}) => ({\n decorator: context.decorator,\n editor: context.editor,\n pair: context.pair,\n }),\n },\n ],\n on: {\n 'decorator.add': {\n target: 'decorator added',\n actions: assign({\n offsetAfterDecorator: ({event}) => event.blockOffset,\n }),\n },\n },\n },\n 'decorator added': {\n exit: [\n assign({\n offsetAfterDecorator: undefined,\n }),\n ],\n invoke: [\n {\n src: 'selection listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'delete.backward listener',\n input: ({context}) => ({editor: context.editor}),\n },\n ],\n on: {\n 'selection': {\n target: 'idle',\n guard: ({context, event}) => {\n const selectionChanged = !isDeepEqual(\n {\n anchor: context.offsetAfterDecorator,\n focus: context.offsetAfterDecorator,\n },\n event.blockOffsets,\n )\n\n return selectionChanged\n },\n },\n 'delete.backward': {\n target: 'idle',\n },\n },\n },\n },\n})\n"],"names":["defineBehavior","selectors","utils","execute","effect","editor","useEditor","useActorRef","forward","setup","fromCallback","assign","isDeepEqual"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ function createCharacterPairDecoratorBehavior(config) {
26
26
  if (decorator === void 0)
27
27
  return !1;
28
28
  const focusTextBlock = selectors.getFocusTextBlock(snapshot), selectionStartPoint = selectors.getSelectionStartPoint(snapshot), selectionStartOffset = selectionStartPoint ? utils.spanSelectionPointToBlockOffset({
29
- value: snapshot.context.value,
29
+ context: snapshot.context,
30
30
  selectionPoint: selectionStartPoint
31
31
  }) : void 0;
32
32
  if (!focusTextBlock || !selectionStartOffset)
@@ -59,7 +59,7 @@ function createCharacterPairDecoratorBehavior(config) {
59
59
  };
60
60
  if (prefixOffsets.focus.offset - prefixOffsets.anchor.offset > 1) {
61
61
  const prefixSelection = utils.blockOffsetsToSelection({
62
- value: snapshot.context.value,
62
+ context: snapshot.context,
63
63
  offsets: prefixOffsets
64
64
  }), inlineObjectBeforePrefixFocus = selectors.getPreviousInlineObject(
65
65
  {
@@ -73,7 +73,7 @@ function createCharacterPairDecoratorBehavior(config) {
73
73
  }
74
74
  }
75
75
  ), inlineObjectBeforePrefixFocusOffset = inlineObjectBeforePrefixFocus ? utils.childSelectionPointToBlockOffset({
76
- value: snapshot.context.value,
76
+ context: snapshot.context,
77
77
  selectionPoint: {
78
78
  path: inlineObjectBeforePrefixFocus.path,
79
79
  offset: 0
@@ -84,7 +84,7 @@ function createCharacterPairDecoratorBehavior(config) {
84
84
  }
85
85
  if (suffixOffsets.focus.offset - suffixOffsets.anchor.offset > 1) {
86
86
  const previousInlineObject = selectors.getPreviousInlineObject(snapshot), previousInlineObjectOffset = previousInlineObject ? utils.childSelectionPointToBlockOffset({
87
- value: snapshot.context.value,
87
+ context: snapshot.context,
88
88
  selectionPoint: {
89
89
  path: previousInlineObject.path,
90
90
  offset: 0
@@ -162,10 +162,10 @@ const decorateListener = ({ sendBack, input }) => input.editor.registerBehavior(
162
162
  if (!event.at)
163
163
  return { blockOffsets: void 0 };
164
164
  const anchor = utils.spanSelectionPointToBlockOffset({
165
- value: snapshot.context.value,
165
+ context: snapshot.context,
166
166
  selectionPoint: event.at.anchor
167
167
  }), focus = utils.spanSelectionPointToBlockOffset({
168
- value: snapshot.context.value,
168
+ context: snapshot.context,
169
169
  selectionPoint: event.at.focus
170
170
  });
171
171
  return !anchor || !focus ? { blockOffsets: void 0 } : {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/regex.character-pair.ts","../src/behavior.character-pair-decorator.ts","../src/plugin.character-pair-decorator.ts"],"sourcesContent":["export function createCharacterPairRegex(char: string, amount: number) {\n // Negative lookbehind: Ensures that the matched sequence is not preceded by the same character\n const prePrefix = `(?<!\\\\${char})`\n\n // Repeats the character `amount` times\n const prefix = `\\\\${char}`.repeat(Math.max(amount, 1))\n\n // Negative lookahead: Ensures that the opening pair (**, *, etc.) is not followed by a space\n const postPrefix = `(?!\\\\s)`\n\n // Captures the content inside the pair\n const content = `([^${char}\\\\n]+?)`\n\n // Negative lookbehind: Ensures that the content is not followed by a space\n const preSuffix = `(?<!\\\\s)`\n\n // Repeats the character `amount` times\n const suffix = `\\\\${char}`.repeat(Math.max(amount, 1))\n\n // Negative lookahead: Ensures that the matched sequence is not followed by the same character\n const postSuffix = `(?!\\\\${char})`\n\n return `${prePrefix}${prefix}${postPrefix}${content}${preSuffix}${suffix}${postSuffix}`\n}\n","import type {BlockOffset, EditorSchema} from '@portabletext/editor'\nimport {defineBehavior, effect, execute} from '@portabletext/editor/behaviors'\nimport * as selectors from '@portabletext/editor/selectors'\nimport * as utils from '@portabletext/editor/utils'\nimport {createCharacterPairRegex} from './regex.character-pair'\n\nexport function createCharacterPairDecoratorBehavior(config: {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n pair: {char: string; amount: number}\n onDecorate: (offset: BlockOffset) => void\n}) {\n if (config.pair.amount < 1) {\n console.warn(\n `The amount of characters in the pair should be greater than 0`,\n )\n }\n\n const pairRegex = createCharacterPairRegex(\n config.pair.char,\n config.pair.amount,\n )\n const regEx = new RegExp(`(${pairRegex})$`)\n\n return defineBehavior({\n on: 'insert.text',\n guard: ({snapshot, event}) => {\n if (config.pair.amount < 1) {\n return false\n }\n\n const decorator = config.decorator({schema: snapshot.context.schema})\n\n if (decorator === undefined) {\n return false\n }\n\n const focusTextBlock = selectors.getFocusTextBlock(snapshot)\n const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)\n const selectionStartOffset = selectionStartPoint\n ? utils.spanSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: selectionStartPoint,\n })\n : undefined\n\n if (!focusTextBlock || !selectionStartOffset) {\n return false\n }\n\n const textBefore = selectors.getBlockTextBefore(snapshot)\n const newText = `${textBefore}${event.text}`\n const textToDecorate = newText.match(regEx)?.at(0)\n\n if (textToDecorate === undefined) {\n return false\n }\n\n const prefixOffsets = {\n anchor: {\n path: focusTextBlock.path,\n // Example: \"foo **bar**\".length - \"**bar**\".length = 4\n offset: newText.length - textToDecorate.length,\n },\n focus: {\n path: focusTextBlock.path,\n // Example: \"foo **bar**\".length - \"**bar**\".length + \"*\".length * 2 = 6\n offset:\n newText.length -\n textToDecorate.length +\n config.pair.char.length * config.pair.amount,\n },\n }\n\n const suffixOffsets = {\n anchor: {\n path: focusTextBlock.path,\n // Example: \"foo **bar*|\" (10) + \"*\".length - 2 = 9\n offset:\n selectionStartOffset.offset +\n event.text.length -\n config.pair.char.length * config.pair.amount,\n },\n focus: {\n path: focusTextBlock.path,\n // Example: \"foo **bar*|\" (10) + \"*\".length = 11\n offset: selectionStartOffset.offset + event.text.length,\n },\n }\n\n // If the prefix is more than one character, then we need to check if\n // there is an inline object inside it\n if (prefixOffsets.focus.offset - prefixOffsets.anchor.offset > 1) {\n const prefixSelection = utils.blockOffsetsToSelection({\n value: snapshot.context.value,\n offsets: prefixOffsets,\n })\n const inlineObjectBeforePrefixFocus = selectors.getPreviousInlineObject(\n {\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: prefixSelection\n ? {\n anchor: prefixSelection.focus,\n focus: prefixSelection.focus,\n }\n : null,\n },\n },\n )\n const inlineObjectBeforePrefixFocusOffset =\n inlineObjectBeforePrefixFocus\n ? utils.childSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: {\n path: inlineObjectBeforePrefixFocus.path,\n offset: 0,\n },\n })\n : undefined\n\n if (\n inlineObjectBeforePrefixFocusOffset &&\n inlineObjectBeforePrefixFocusOffset.offset >\n prefixOffsets.anchor.offset &&\n inlineObjectBeforePrefixFocusOffset.offset <\n prefixOffsets.focus.offset\n ) {\n return false\n }\n }\n\n // If the suffix is more than one character, then we need to check if\n // there is an inline object inside it\n if (suffixOffsets.focus.offset - suffixOffsets.anchor.offset > 1) {\n const previousInlineObject = selectors.getPreviousInlineObject(snapshot)\n const previousInlineObjectOffset = previousInlineObject\n ? utils.childSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: {\n path: previousInlineObject.path,\n offset: 0,\n },\n })\n : undefined\n\n if (\n previousInlineObjectOffset &&\n previousInlineObjectOffset.offset > suffixOffsets.anchor.offset &&\n previousInlineObjectOffset.offset < suffixOffsets.focus.offset\n ) {\n return false\n }\n }\n\n return {\n prefixOffsets,\n suffixOffsets,\n decorator,\n }\n },\n actions: [\n // Insert the text as usual in its own undo step\n ({event}) => [execute(event)],\n (_, {prefixOffsets, suffixOffsets, decorator}) => [\n // Decorate the text between the prefix and suffix\n execute({\n type: 'decorator.add',\n decorator,\n at: {\n anchor: prefixOffsets.focus,\n focus: suffixOffsets.anchor,\n },\n }),\n // Delete the suffix\n execute({\n type: 'delete.text',\n at: suffixOffsets,\n }),\n // Delete the prefix\n execute({\n type: 'delete.text',\n at: prefixOffsets,\n }),\n // Toggle the decorator off so the next inserted text isn't emphasized\n execute({\n type: 'decorator.remove',\n decorator,\n }),\n effect(() => {\n config.onDecorate({\n ...suffixOffsets.anchor,\n offset:\n suffixOffsets.anchor.offset -\n (prefixOffsets.focus.offset - prefixOffsets.anchor.offset),\n })\n }),\n ],\n ],\n })\n}\n","import type {BlockOffset, Editor, EditorSchema} from '@portabletext/editor'\nimport {useEditor} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n execute,\n forward,\n} from '@portabletext/editor/behaviors'\nimport * as utils from '@portabletext/editor/utils'\nimport {useActorRef} from '@xstate/react'\nimport {isDeepEqual} from 'remeda'\nimport {\n assign,\n fromCallback,\n setup,\n type AnyEventObject,\n type CallbackLogicFunction,\n} from 'xstate'\nimport {createCharacterPairDecoratorBehavior} from './behavior.character-pair-decorator'\n\n/**\n * @beta\n */\nexport function CharacterPairDecoratorPlugin(config: {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n pair: {char: string; amount: number}\n}) {\n const editor = useEditor()\n\n useActorRef(decoratorPairMachine, {\n input: {\n editor,\n decorator: config.decorator,\n pair: config.pair,\n },\n })\n\n return null\n}\n\ntype DecoratorPairEvent =\n | {\n type: 'decorator.add'\n blockOffset: BlockOffset\n }\n | {\n type: 'selection'\n blockOffsets?: {\n anchor: BlockOffset\n focus: BlockOffset\n }\n }\n | {\n type: 'delete.backward'\n }\n\nconst decorateListener: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n pair: {char: string; amount: number}\n }\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: createCharacterPairDecoratorBehavior({\n decorator: input.decorator,\n pair: input.pair,\n onDecorate: (offset) => {\n sendBack({type: 'decorator.add', blockOffset: offset})\n },\n }),\n })\n\n return unregister\n}\n\nconst selectionListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'select',\n guard: ({snapshot, event}) => {\n if (!event.at) {\n return {blockOffsets: undefined}\n }\n\n const anchor = utils.spanSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: event.at.anchor,\n })\n const focus = utils.spanSelectionPointToBlockOffset({\n value: snapshot.context.value,\n selectionPoint: event.at.focus,\n })\n\n if (!anchor || !focus) {\n return {blockOffsets: undefined}\n }\n\n return {\n blockOffsets: {\n anchor,\n focus,\n },\n }\n },\n actions: [\n ({event}, {blockOffsets}) => [\n {\n type: 'effect',\n effect: () => {\n sendBack({type: 'selection', blockOffsets})\n },\n },\n forward(event),\n ],\n ],\n }),\n })\n\n return unregister\n}\n\nconst deleteBackwardListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'delete.backward',\n actions: [\n () => [\n execute({\n type: 'history.undo',\n }),\n effect(() => {\n sendBack({type: 'delete.backward'})\n }),\n ],\n ],\n }),\n })\n\n return unregister\n}\n\nconst decoratorPairMachine = setup({\n types: {\n context: {} as {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n offsetAfterDecorator?: BlockOffset\n pair: {char: string; amount: number}\n },\n input: {} as {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n pair: {char: string; amount: number}\n },\n events: {} as DecoratorPairEvent,\n },\n actors: {\n 'decorate listener': fromCallback(decorateListener),\n 'delete.backward listener': fromCallback(deleteBackwardListenerCallback),\n 'selection listener': fromCallback(selectionListenerCallback),\n },\n}).createMachine({\n id: 'decorator pair',\n context: ({input}) => ({\n decorator: input.decorator,\n editor: input.editor,\n pair: input.pair,\n }),\n initial: 'idle',\n states: {\n 'idle': {\n invoke: [\n {\n src: 'decorate listener',\n input: ({context}) => ({\n decorator: context.decorator,\n editor: context.editor,\n pair: context.pair,\n }),\n },\n ],\n on: {\n 'decorator.add': {\n target: 'decorator added',\n actions: assign({\n offsetAfterDecorator: ({event}) => event.blockOffset,\n }),\n },\n },\n },\n 'decorator added': {\n exit: [\n assign({\n offsetAfterDecorator: undefined,\n }),\n ],\n invoke: [\n {\n src: 'selection listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'delete.backward listener',\n input: ({context}) => ({editor: context.editor}),\n },\n ],\n on: {\n 'selection': {\n target: 'idle',\n guard: ({context, event}) => {\n const selectionChanged = !isDeepEqual(\n {\n anchor: context.offsetAfterDecorator,\n focus: context.offsetAfterDecorator,\n },\n event.blockOffsets,\n )\n\n return selectionChanged\n },\n },\n 'delete.backward': {\n target: 'idle',\n },\n },\n },\n },\n})\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/regex.character-pair.ts","../src/behavior.character-pair-decorator.ts","../src/plugin.character-pair-decorator.ts"],"sourcesContent":["export function createCharacterPairRegex(char: string, amount: number) {\n // Negative lookbehind: Ensures that the matched sequence is not preceded by the same character\n const prePrefix = `(?<!\\\\${char})`\n\n // Repeats the character `amount` times\n const prefix = `\\\\${char}`.repeat(Math.max(amount, 1))\n\n // Negative lookahead: Ensures that the opening pair (**, *, etc.) is not followed by a space\n const postPrefix = `(?!\\\\s)`\n\n // Captures the content inside the pair\n const content = `([^${char}\\\\n]+?)`\n\n // Negative lookbehind: Ensures that the content is not followed by a space\n const preSuffix = `(?<!\\\\s)`\n\n // Repeats the character `amount` times\n const suffix = `\\\\${char}`.repeat(Math.max(amount, 1))\n\n // Negative lookahead: Ensures that the matched sequence is not followed by the same character\n const postSuffix = `(?!\\\\${char})`\n\n return `${prePrefix}${prefix}${postPrefix}${content}${preSuffix}${suffix}${postSuffix}`\n}\n","import type {BlockOffset, EditorSchema} from '@portabletext/editor'\nimport {defineBehavior, effect, execute} from '@portabletext/editor/behaviors'\nimport * as selectors from '@portabletext/editor/selectors'\nimport * as utils from '@portabletext/editor/utils'\nimport {createCharacterPairRegex} from './regex.character-pair'\n\nexport function createCharacterPairDecoratorBehavior(config: {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n pair: {char: string; amount: number}\n onDecorate: (offset: BlockOffset) => void\n}) {\n if (config.pair.amount < 1) {\n console.warn(\n `The amount of characters in the pair should be greater than 0`,\n )\n }\n\n const pairRegex = createCharacterPairRegex(\n config.pair.char,\n config.pair.amount,\n )\n const regEx = new RegExp(`(${pairRegex})$`)\n\n return defineBehavior({\n on: 'insert.text',\n guard: ({snapshot, event}) => {\n if (config.pair.amount < 1) {\n return false\n }\n\n const decorator = config.decorator({schema: snapshot.context.schema})\n\n if (decorator === undefined) {\n return false\n }\n\n const focusTextBlock = selectors.getFocusTextBlock(snapshot)\n const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)\n const selectionStartOffset = selectionStartPoint\n ? utils.spanSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: selectionStartPoint,\n })\n : undefined\n\n if (!focusTextBlock || !selectionStartOffset) {\n return false\n }\n\n const textBefore = selectors.getBlockTextBefore(snapshot)\n const newText = `${textBefore}${event.text}`\n const textToDecorate = newText.match(regEx)?.at(0)\n\n if (textToDecorate === undefined) {\n return false\n }\n\n const prefixOffsets = {\n anchor: {\n path: focusTextBlock.path,\n // Example: \"foo **bar**\".length - \"**bar**\".length = 4\n offset: newText.length - textToDecorate.length,\n },\n focus: {\n path: focusTextBlock.path,\n // Example: \"foo **bar**\".length - \"**bar**\".length + \"*\".length * 2 = 6\n offset:\n newText.length -\n textToDecorate.length +\n config.pair.char.length * config.pair.amount,\n },\n }\n\n const suffixOffsets = {\n anchor: {\n path: focusTextBlock.path,\n // Example: \"foo **bar*|\" (10) + \"*\".length - 2 = 9\n offset:\n selectionStartOffset.offset +\n event.text.length -\n config.pair.char.length * config.pair.amount,\n },\n focus: {\n path: focusTextBlock.path,\n // Example: \"foo **bar*|\" (10) + \"*\".length = 11\n offset: selectionStartOffset.offset + event.text.length,\n },\n }\n\n // If the prefix is more than one character, then we need to check if\n // there is an inline object inside it\n if (prefixOffsets.focus.offset - prefixOffsets.anchor.offset > 1) {\n const prefixSelection = utils.blockOffsetsToSelection({\n context: snapshot.context,\n offsets: prefixOffsets,\n })\n const inlineObjectBeforePrefixFocus = selectors.getPreviousInlineObject(\n {\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: prefixSelection\n ? {\n anchor: prefixSelection.focus,\n focus: prefixSelection.focus,\n }\n : null,\n },\n },\n )\n const inlineObjectBeforePrefixFocusOffset =\n inlineObjectBeforePrefixFocus\n ? utils.childSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: {\n path: inlineObjectBeforePrefixFocus.path,\n offset: 0,\n },\n })\n : undefined\n\n if (\n inlineObjectBeforePrefixFocusOffset &&\n inlineObjectBeforePrefixFocusOffset.offset >\n prefixOffsets.anchor.offset &&\n inlineObjectBeforePrefixFocusOffset.offset <\n prefixOffsets.focus.offset\n ) {\n return false\n }\n }\n\n // If the suffix is more than one character, then we need to check if\n // there is an inline object inside it\n if (suffixOffsets.focus.offset - suffixOffsets.anchor.offset > 1) {\n const previousInlineObject = selectors.getPreviousInlineObject(snapshot)\n const previousInlineObjectOffset = previousInlineObject\n ? utils.childSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: {\n path: previousInlineObject.path,\n offset: 0,\n },\n })\n : undefined\n\n if (\n previousInlineObjectOffset &&\n previousInlineObjectOffset.offset > suffixOffsets.anchor.offset &&\n previousInlineObjectOffset.offset < suffixOffsets.focus.offset\n ) {\n return false\n }\n }\n\n return {\n prefixOffsets,\n suffixOffsets,\n decorator,\n }\n },\n actions: [\n // Insert the text as usual in its own undo step\n ({event}) => [execute(event)],\n (_, {prefixOffsets, suffixOffsets, decorator}) => [\n // Decorate the text between the prefix and suffix\n execute({\n type: 'decorator.add',\n decorator,\n at: {\n anchor: prefixOffsets.focus,\n focus: suffixOffsets.anchor,\n },\n }),\n // Delete the suffix\n execute({\n type: 'delete.text',\n at: suffixOffsets,\n }),\n // Delete the prefix\n execute({\n type: 'delete.text',\n at: prefixOffsets,\n }),\n // Toggle the decorator off so the next inserted text isn't emphasized\n execute({\n type: 'decorator.remove',\n decorator,\n }),\n effect(() => {\n config.onDecorate({\n ...suffixOffsets.anchor,\n offset:\n suffixOffsets.anchor.offset -\n (prefixOffsets.focus.offset - prefixOffsets.anchor.offset),\n })\n }),\n ],\n ],\n })\n}\n","import type {BlockOffset, Editor, EditorSchema} from '@portabletext/editor'\nimport {useEditor} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n execute,\n forward,\n} from '@portabletext/editor/behaviors'\nimport * as utils from '@portabletext/editor/utils'\nimport {useActorRef} from '@xstate/react'\nimport {isDeepEqual} from 'remeda'\nimport {\n assign,\n fromCallback,\n setup,\n type AnyEventObject,\n type CallbackLogicFunction,\n} from 'xstate'\nimport {createCharacterPairDecoratorBehavior} from './behavior.character-pair-decorator'\n\n/**\n * @beta\n */\nexport function CharacterPairDecoratorPlugin(config: {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n pair: {char: string; amount: number}\n}) {\n const editor = useEditor()\n\n useActorRef(decoratorPairMachine, {\n input: {\n editor,\n decorator: config.decorator,\n pair: config.pair,\n },\n })\n\n return null\n}\n\ntype DecoratorPairEvent =\n | {\n type: 'decorator.add'\n blockOffset: BlockOffset\n }\n | {\n type: 'selection'\n blockOffsets?: {\n anchor: BlockOffset\n focus: BlockOffset\n }\n }\n | {\n type: 'delete.backward'\n }\n\nconst decorateListener: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n pair: {char: string; amount: number}\n }\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: createCharacterPairDecoratorBehavior({\n decorator: input.decorator,\n pair: input.pair,\n onDecorate: (offset) => {\n sendBack({type: 'decorator.add', blockOffset: offset})\n },\n }),\n })\n\n return unregister\n}\n\nconst selectionListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'select',\n guard: ({snapshot, event}) => {\n if (!event.at) {\n return {blockOffsets: undefined}\n }\n\n const anchor = utils.spanSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: event.at.anchor,\n })\n const focus = utils.spanSelectionPointToBlockOffset({\n context: snapshot.context,\n selectionPoint: event.at.focus,\n })\n\n if (!anchor || !focus) {\n return {blockOffsets: undefined}\n }\n\n return {\n blockOffsets: {\n anchor,\n focus,\n },\n }\n },\n actions: [\n ({event}, {blockOffsets}) => [\n {\n type: 'effect',\n effect: () => {\n sendBack({type: 'selection', blockOffsets})\n },\n },\n forward(event),\n ],\n ],\n }),\n })\n\n return unregister\n}\n\nconst deleteBackwardListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregister = input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'delete.backward',\n actions: [\n () => [\n execute({\n type: 'history.undo',\n }),\n effect(() => {\n sendBack({type: 'delete.backward'})\n }),\n ],\n ],\n }),\n })\n\n return unregister\n}\n\nconst decoratorPairMachine = setup({\n types: {\n context: {} as {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n offsetAfterDecorator?: BlockOffset\n pair: {char: string; amount: number}\n },\n input: {} as {\n decorator: ({schema}: {schema: EditorSchema}) => string | undefined\n editor: Editor\n pair: {char: string; amount: number}\n },\n events: {} as DecoratorPairEvent,\n },\n actors: {\n 'decorate listener': fromCallback(decorateListener),\n 'delete.backward listener': fromCallback(deleteBackwardListenerCallback),\n 'selection listener': fromCallback(selectionListenerCallback),\n },\n}).createMachine({\n id: 'decorator pair',\n context: ({input}) => ({\n decorator: input.decorator,\n editor: input.editor,\n pair: input.pair,\n }),\n initial: 'idle',\n states: {\n 'idle': {\n invoke: [\n {\n src: 'decorate listener',\n input: ({context}) => ({\n decorator: context.decorator,\n editor: context.editor,\n pair: context.pair,\n }),\n },\n ],\n on: {\n 'decorator.add': {\n target: 'decorator added',\n actions: assign({\n offsetAfterDecorator: ({event}) => event.blockOffset,\n }),\n },\n },\n },\n 'decorator added': {\n exit: [\n assign({\n offsetAfterDecorator: undefined,\n }),\n ],\n invoke: [\n {\n src: 'selection listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'delete.backward listener',\n input: ({context}) => ({editor: context.editor}),\n },\n ],\n on: {\n 'selection': {\n target: 'idle',\n guard: ({context, event}) => {\n const selectionChanged = !isDeepEqual(\n {\n anchor: context.offsetAfterDecorator,\n focus: context.offsetAfterDecorator,\n },\n event.blockOffsets,\n )\n\n return selectionChanged\n },\n },\n 'delete.backward': {\n target: 'idle',\n },\n },\n },\n },\n})\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/plugin-character-pair-decorator",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Automatically match a pair of characters and decorate the text in between",
5
5
  "keywords": [
6
6
  "portabletext",
@@ -39,7 +39,7 @@
39
39
  "dist"
40
40
  ],
41
41
  "devDependencies": {
42
- "@portabletext/editor": "^1.48.5",
42
+ "@portabletext/editor": "^1.48.8",
43
43
  "@types/react": "^19.1.2",
44
44
  "react": "^19.1.0"
45
45
  },
@@ -38,7 +38,7 @@ export function createCharacterPairDecoratorBehavior(config: {
38
38
  const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)
39
39
  const selectionStartOffset = selectionStartPoint
40
40
  ? utils.spanSelectionPointToBlockOffset({
41
- value: snapshot.context.value,
41
+ context: snapshot.context,
42
42
  selectionPoint: selectionStartPoint,
43
43
  })
44
44
  : undefined
@@ -91,7 +91,7 @@ export function createCharacterPairDecoratorBehavior(config: {
91
91
  // there is an inline object inside it
92
92
  if (prefixOffsets.focus.offset - prefixOffsets.anchor.offset > 1) {
93
93
  const prefixSelection = utils.blockOffsetsToSelection({
94
- value: snapshot.context.value,
94
+ context: snapshot.context,
95
95
  offsets: prefixOffsets,
96
96
  })
97
97
  const inlineObjectBeforePrefixFocus = selectors.getPreviousInlineObject(
@@ -111,7 +111,7 @@ export function createCharacterPairDecoratorBehavior(config: {
111
111
  const inlineObjectBeforePrefixFocusOffset =
112
112
  inlineObjectBeforePrefixFocus
113
113
  ? utils.childSelectionPointToBlockOffset({
114
- value: snapshot.context.value,
114
+ context: snapshot.context,
115
115
  selectionPoint: {
116
116
  path: inlineObjectBeforePrefixFocus.path,
117
117
  offset: 0,
@@ -136,7 +136,7 @@ export function createCharacterPairDecoratorBehavior(config: {
136
136
  const previousInlineObject = selectors.getPreviousInlineObject(snapshot)
137
137
  const previousInlineObjectOffset = previousInlineObject
138
138
  ? utils.childSelectionPointToBlockOffset({
139
- value: snapshot.context.value,
139
+ context: snapshot.context,
140
140
  selectionPoint: {
141
141
  path: previousInlineObject.path,
142
142
  offset: 0,
@@ -90,11 +90,11 @@ const selectionListenerCallback: CallbackLogicFunction<
90
90
  }
91
91
 
92
92
  const anchor = utils.spanSelectionPointToBlockOffset({
93
- value: snapshot.context.value,
93
+ context: snapshot.context,
94
94
  selectionPoint: event.at.anchor,
95
95
  })
96
96
  const focus = utils.spanSelectionPointToBlockOffset({
97
- value: snapshot.context.value,
97
+ context: snapshot.context,
98
98
  selectionPoint: event.at.focus,
99
99
  })
100
100