@portabletext/plugin-character-pair-decorator 8.0.24 → 8.0.25
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.js +22 -9
- package/dist/index.js.map +1 -1
- package/package.json +4 -5
package/dist/index.js
CHANGED
|
@@ -3,7 +3,6 @@ import { useEditor } from "@portabletext/editor";
|
|
|
3
3
|
import { defineBehavior, forward, raise, effect } from "@portabletext/editor/behaviors";
|
|
4
4
|
import * as utils from "@portabletext/editor/utils";
|
|
5
5
|
import { useActorRef } from "@xstate/react";
|
|
6
|
-
import { isDeepEqual } from "remeda";
|
|
7
6
|
import { setup, fromCallback, assign } from "xstate";
|
|
8
7
|
import * as selectors from "@portabletext/editor/selectors";
|
|
9
8
|
import { getPathSubSchema } from "@portabletext/editor/traversal";
|
|
@@ -182,7 +181,8 @@ const decorateListener = ({
|
|
|
182
181
|
if (!event.selection) {
|
|
183
182
|
sendBack({
|
|
184
183
|
type: "selection",
|
|
185
|
-
blockOffsets: void 0
|
|
184
|
+
blockOffsets: void 0,
|
|
185
|
+
selection: null
|
|
186
186
|
});
|
|
187
187
|
return;
|
|
188
188
|
}
|
|
@@ -196,7 +196,8 @@ const decorateListener = ({
|
|
|
196
196
|
if (!anchor || !focus) {
|
|
197
197
|
sendBack({
|
|
198
198
|
type: "selection",
|
|
199
|
-
blockOffsets: void 0
|
|
199
|
+
blockOffsets: void 0,
|
|
200
|
+
selection: event.selection
|
|
200
201
|
});
|
|
201
202
|
return;
|
|
202
203
|
}
|
|
@@ -205,7 +206,8 @@ const decorateListener = ({
|
|
|
205
206
|
blockOffsets: {
|
|
206
207
|
anchor,
|
|
207
208
|
focus
|
|
208
|
-
}
|
|
209
|
+
},
|
|
210
|
+
selection: event.selection
|
|
209
211
|
});
|
|
210
212
|
});
|
|
211
213
|
return () => subscription.unsubscribe();
|
|
@@ -241,6 +243,7 @@ const decorateListener = ({
|
|
|
241
243
|
}) => ({
|
|
242
244
|
decorator: input.decorator,
|
|
243
245
|
editor: input.editor,
|
|
246
|
+
endSelection: null,
|
|
244
247
|
pair: input.pair
|
|
245
248
|
}),
|
|
246
249
|
initial: "idle",
|
|
@@ -262,7 +265,10 @@ const decorateListener = ({
|
|
|
262
265
|
actions: assign({
|
|
263
266
|
offsetAfterDecorator: ({
|
|
264
267
|
event
|
|
265
|
-
}) => event.blockOffset
|
|
268
|
+
}) => event.blockOffset,
|
|
269
|
+
endSelection: ({
|
|
270
|
+
context
|
|
271
|
+
}) => context.editor.getSnapshot().context.selection
|
|
266
272
|
})
|
|
267
273
|
}
|
|
268
274
|
}
|
|
@@ -292,10 +298,17 @@ const decorateListener = ({
|
|
|
292
298
|
guard: ({
|
|
293
299
|
context,
|
|
294
300
|
event
|
|
295
|
-
}) =>
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
301
|
+
}) => {
|
|
302
|
+
const offsetAfterDecorator = context.offsetAfterDecorator;
|
|
303
|
+
if (event.blockOffsets && offsetAfterDecorator) {
|
|
304
|
+
const decoratorBlock = offsetAfterDecorator.path.at(-1), anchorBlock = event.blockOffsets.anchor.path.at(-1), focusBlock = event.blockOffsets.focus.path.at(-1);
|
|
305
|
+
if (!utils.isKeyedSegment(decoratorBlock) || !utils.isKeyedSegment(anchorBlock) || !utils.isKeyedSegment(focusBlock))
|
|
306
|
+
return !1;
|
|
307
|
+
const anchorChanged = decoratorBlock._key !== anchorBlock._key || offsetAfterDecorator.offset !== event.blockOffsets.anchor.offset, focusChanged = decoratorBlock._key !== focusBlock._key || offsetAfterDecorator.offset !== event.blockOffsets.focus.offset;
|
|
308
|
+
return anchorChanged || focusChanged;
|
|
309
|
+
}
|
|
310
|
+
return !utils.isEqualSelections(context.endSelection, event.selection);
|
|
311
|
+
}
|
|
299
312
|
},
|
|
300
313
|
"delete.backward": {
|
|
301
314
|
target: "idle"
|
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, EditorContext} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n forward,\n raise,\n} from '@portabletext/editor/behaviors'\nimport * as selectors from '@portabletext/editor/selectors'\nimport {getPathSubSchema} from '@portabletext/editor/traversal'\nimport * as utils from '@portabletext/editor/utils'\nimport {createCharacterPairRegex} from './regex.character-pair'\n\nexport function createCharacterPairDecoratorBehavior(config: {\n decorator: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => 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 focusTextBlock = selectors.getFocusTextBlock(snapshot)\n\n if (!focusTextBlock) {\n return false\n }\n\n const subSchema = getPathSubSchema(snapshot, focusTextBlock.path)\n const decorator = config.decorator({\n context: {schema: subSchema},\n schema: subSchema,\n })\n\n if (decorator === undefined) {\n return false\n }\n\n const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)\n const selectionStartOffset = selectionStartPoint\n ? utils.spanSelectionPointToBlockOffset({\n snapshot,\n selectionPoint: selectionStartPoint,\n })\n : undefined\n\n if (!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 snapshot,\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 snapshot,\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 snapshot,\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}) => [forward(event)],\n (_, {prefixOffsets, suffixOffsets, decorator}) => [\n // Decorate the text between the prefix and suffix\n raise({\n type: 'decorator.add',\n decorator,\n at: {\n anchor: prefixOffsets.focus,\n focus: suffixOffsets.anchor,\n },\n }),\n // Delete the suffix\n raise({\n type: 'delete.text',\n at: suffixOffsets,\n }),\n // Delete the prefix\n raise({\n type: 'delete.text',\n at: prefixOffsets,\n }),\n // Toggle the decorator off so the next inserted text isn't emphasized\n raise({\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, EditorContext} from '@portabletext/editor'\nimport {useEditor} from '@portabletext/editor'\nimport {defineBehavior, effect, raise} 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 * @public\n */\nexport function CharacterPairDecoratorPlugin(props: {\n decorator: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => string | undefined\n pair: {char: string; amount: number}\n}) {\n const editor = useEditor()\n\n useActorRef(decoratorPairMachine, {\n input: {\n editor,\n decorator: props.decorator,\n pair: props.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: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => 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 // Listen for the emitted 'selection' event which fires after ANY cursor\n // movement (typing, clicking, pasting, etc.) - not just explicit 'select'\n // behavior events.\n const subscription = input.editor.on('selection', (event) => {\n if (!event.selection) {\n sendBack({type: 'selection', blockOffsets: undefined})\n return\n }\n\n const snapshot = input.editor.getSnapshot()\n const anchor = utils.spanSelectionPointToBlockOffset({\n snapshot,\n selectionPoint: event.selection.anchor,\n })\n const focus = utils.spanSelectionPointToBlockOffset({\n snapshot,\n selectionPoint: event.selection.focus,\n })\n\n if (!anchor || !focus) {\n sendBack({type: 'selection', blockOffsets: undefined})\n return\n }\n\n sendBack({type: 'selection', blockOffsets: {anchor, focus}})\n })\n\n return () => subscription.unsubscribe()\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 raise({\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: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => string | undefined\n editor: Editor\n offsetAfterDecorator?: BlockOffset\n pair: {char: string; amount: number}\n },\n input: {} as {\n decorator: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => 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":["createCharacterPairRegex","char","amount","prePrefix","prefix","repeat","Math","max","postPrefix","content","preSuffix","suffix","postSuffix","createCharacterPairDecoratorBehavior","config","pair","console","warn","pairRegex","regEx","RegExp","defineBehavior","on","guard","snapshot","event","focusTextBlock","selectors","getFocusTextBlock","subSchema","getPathSubSchema","path","decorator","context","schema","undefined","selectionStartPoint","getSelectionStartPoint","selectionStartOffset","utils","spanSelectionPointToBlockOffset","selectionPoint","newText","getBlockTextBefore","text","textToDecorate","match","at","prefixOffsets","anchor","offset","length","focus","suffixOffsets","prefixSelection","blockOffsetsToSelection","offsets","inlineObjectBeforePrefixFocus","getPreviousInlineObject","selection","inlineObjectBeforePrefixFocusOffset","childSelectionPointToBlockOffset","previousInlineObject","previousInlineObjectOffset","actions","forward","_","raise","type","effect","onDecorate","CharacterPairDecoratorPlugin","props","$","_c","editor","useEditor","t0","input","useActorRef","decoratorPairMachine","decorateListener","sendBack","registerBehavior","behavior","blockOffset","selectionListenerCallback","subscription","blockOffsets","getSnapshot","unsubscribe","deleteBackwardListenerCallback","setup","types","events","actors","fromCallback","createMachine","id","initial","states","invoke","src","target","assign","offsetAfterDecorator","exit","isDeepEqual"],"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, EditorContext} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n forward,\n raise,\n} from '@portabletext/editor/behaviors'\nimport * as selectors from '@portabletext/editor/selectors'\nimport {getPathSubSchema} from '@portabletext/editor/traversal'\nimport * as utils from '@portabletext/editor/utils'\nimport {createCharacterPairRegex} from './regex.character-pair'\n\nexport function createCharacterPairDecoratorBehavior(config: {\n decorator: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => 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 focusTextBlock = selectors.getFocusTextBlock(snapshot)\n\n if (!focusTextBlock) {\n return false\n }\n\n const subSchema = getPathSubSchema(snapshot, focusTextBlock.path)\n const decorator = config.decorator({\n context: {schema: subSchema},\n schema: subSchema,\n })\n\n if (decorator === undefined) {\n return false\n }\n\n const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)\n const selectionStartOffset = selectionStartPoint\n ? utils.spanSelectionPointToBlockOffset({\n snapshot,\n selectionPoint: selectionStartPoint,\n })\n : undefined\n\n if (!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 snapshot,\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 snapshot,\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 snapshot,\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}) => [forward(event)],\n (_, {prefixOffsets, suffixOffsets, decorator}) => [\n // Decorate the text between the prefix and suffix\n raise({\n type: 'decorator.add',\n decorator,\n at: {\n anchor: prefixOffsets.focus,\n focus: suffixOffsets.anchor,\n },\n }),\n // Delete the suffix\n raise({\n type: 'delete.text',\n at: suffixOffsets,\n }),\n // Delete the prefix\n raise({\n type: 'delete.text',\n at: prefixOffsets,\n }),\n // Toggle the decorator off so the next inserted text isn't emphasized\n raise({\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 {\n BlockOffset,\n Editor,\n EditorContext,\n EditorSelection,\n} from '@portabletext/editor'\nimport {useEditor} from '@portabletext/editor'\nimport {defineBehavior, effect, raise} from '@portabletext/editor/behaviors'\nimport * as utils from '@portabletext/editor/utils'\nimport {useActorRef} from '@xstate/react'\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 * @public\n */\nexport function CharacterPairDecoratorPlugin(props: {\n decorator: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => string | undefined\n pair: {char: string; amount: number}\n}) {\n const editor = useEditor()\n\n useActorRef(decoratorPairMachine, {\n input: {\n editor,\n decorator: props.decorator,\n pair: props.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 selection: EditorSelection\n }\n | {\n type: 'delete.backward'\n }\n\nconst decorateListener: CallbackLogicFunction<\n AnyEventObject,\n DecoratorPairEvent,\n {\n decorator: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => 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 // Listen for the emitted 'selection' event which fires after ANY cursor\n // movement (typing, clicking, pasting, etc.) - not just explicit 'select'\n // behavior events.\n const subscription = input.editor.on('selection', (event) => {\n if (!event.selection) {\n sendBack({type: 'selection', blockOffsets: undefined, selection: null})\n return\n }\n\n const snapshot = input.editor.getSnapshot()\n const anchor = utils.spanSelectionPointToBlockOffset({\n snapshot,\n selectionPoint: event.selection.anchor,\n })\n const focus = utils.spanSelectionPointToBlockOffset({\n snapshot,\n selectionPoint: event.selection.focus,\n })\n\n if (!anchor || !focus) {\n sendBack({\n type: 'selection',\n blockOffsets: undefined,\n selection: event.selection,\n })\n return\n }\n\n sendBack({\n type: 'selection',\n blockOffsets: {anchor, focus},\n selection: event.selection,\n })\n })\n\n return () => subscription.unsubscribe()\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 raise({\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: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => string | undefined\n editor: Editor\n offsetAfterDecorator?: BlockOffset\n endSelection: EditorSelection\n pair: {char: string; amount: number}\n },\n input: {} as {\n decorator: ({\n context,\n schema,\n }: {\n context: Pick<EditorContext, 'schema'>\n /**\n * @deprecated Use `context.schema` instead\n */\n schema: EditorContext['schema']\n }) => 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 endSelection: null,\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 endSelection: ({context}) =>\n context.editor.getSnapshot().context.selection,\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 offsetAfterDecorator = context.offsetAfterDecorator\n\n if (event.blockOffsets && offsetAfterDecorator) {\n // Block offsets are compared rather than raw selection points\n // because they normalize away span-level differences (e.g. the\n // cursor at the same position but in a different span after\n // normalization).\n const decoratorBlock = offsetAfterDecorator.path.at(-1)\n const anchorBlock = event.blockOffsets.anchor.path.at(-1)\n const focusBlock = event.blockOffsets.focus.path.at(-1)\n\n if (\n !utils.isKeyedSegment(decoratorBlock) ||\n !utils.isKeyedSegment(anchorBlock) ||\n !utils.isKeyedSegment(focusBlock)\n ) {\n return false\n }\n\n const anchorChanged =\n decoratorBlock._key !== anchorBlock._key ||\n offsetAfterDecorator.offset !== event.blockOffsets.anchor.offset\n const focusChanged =\n decoratorBlock._key !== focusBlock._key ||\n offsetAfterDecorator.offset !== event.blockOffsets.focus.offset\n\n return anchorChanged || focusChanged\n }\n\n // Block offsets can't be computed when the cursor is on an inline\n // object, so fall back to comparing the raw selections.\n return !utils.isEqualSelections(\n context.endSelection,\n event.selection,\n )\n },\n },\n 'delete.backward': {\n target: 'idle',\n },\n },\n },\n },\n})\n"],"names":["createCharacterPairRegex","char","amount","prePrefix","prefix","repeat","Math","max","postPrefix","content","preSuffix","suffix","postSuffix","createCharacterPairDecoratorBehavior","config","pair","console","warn","pairRegex","regEx","RegExp","defineBehavior","on","guard","snapshot","event","focusTextBlock","selectors","getFocusTextBlock","subSchema","getPathSubSchema","path","decorator","context","schema","undefined","selectionStartPoint","getSelectionStartPoint","selectionStartOffset","utils","spanSelectionPointToBlockOffset","selectionPoint","newText","getBlockTextBefore","text","textToDecorate","match","at","prefixOffsets","anchor","offset","length","focus","suffixOffsets","prefixSelection","blockOffsetsToSelection","offsets","inlineObjectBeforePrefixFocus","getPreviousInlineObject","selection","inlineObjectBeforePrefixFocusOffset","childSelectionPointToBlockOffset","previousInlineObject","previousInlineObjectOffset","actions","forward","_","raise","type","effect","onDecorate","CharacterPairDecoratorPlugin","props","$","_c","editor","useEditor","t0","input","useActorRef","decoratorPairMachine","decorateListener","sendBack","registerBehavior","behavior","blockOffset","selectionListenerCallback","subscription","blockOffsets","getSnapshot","unsubscribe","deleteBackwardListenerCallback","setup","types","events","actors","fromCallback","createMachine","id","endSelection","initial","states","invoke","src","target","assign","offsetAfterDecorator","exit","decoratorBlock","anchorBlock","focusBlock","isKeyedSegment","anchorChanged","_key","focusChanged","isEqualSelections"],"mappings":";;;;;;;;AAAO,SAASA,yBAAyBC,MAAcC,QAAgB;AAErE,QAAMC,YAAY,SAASF,IAAI,KAGzBG,SAAS,KAAKH,IAAI,GAAGI,OAAOC,KAAKC,IAAIL,QAAQ,CAAC,CAAC,GAG/CM,aAAa,WAGbC,UAAU,MAAMR,IAAI,WAGpBS,YAAY,YAGZC,SAAS,KAAKV,IAAI,GAAGI,OAAOC,KAAKC,IAAIL,QAAQ,CAAC,CAAC,GAG/CU,aAAa,QAAQX,IAAI;AAE/B,SAAO,GAAGE,SAAS,GAAGC,MAAM,GAAGI,UAAU,GAAGC,OAAO,GAAGC,SAAS,GAAGC,MAAM,GAAGC,UAAU;AACvF;ACXO,SAASC,qCAAqCC,QAalD;AACGA,SAAOC,KAAKb,SAAS,KACvBc,QAAQC,KACN,+DACF;AAGF,QAAMC,YAAYlB,yBAChBc,OAAOC,KAAKd,MACZa,OAAOC,KAAKb,MACd,GACMiB,QAAQ,IAAIC,OAAO,IAAIF,SAAS,IAAI;AAE1C,SAAOG,eAAe;AAAA,IACpBC,IAAI;AAAA,IACJC,OAAOA,CAAC;AAAA,MAACC;AAAAA,MAAUC;AAAAA,IAAAA,MAAW;AAC5B,UAAIX,OAAOC,KAAKb,SAAS;AACvB,eAAO;AAGT,YAAMwB,iBAAiBC,UAAUC,kBAAkBJ,QAAQ;AAE3D,UAAI,CAACE;AACH,eAAO;AAGT,YAAMG,YAAYC,iBAAiBN,UAAUE,eAAeK,IAAI,GAC1DC,YAAYlB,OAAOkB,UAAU;AAAA,QACjCC,SAAS;AAAA,UAACC,QAAQL;AAAAA,QAAAA;AAAAA,QAClBK,QAAQL;AAAAA,MAAAA,CACT;AAED,UAAIG,cAAcG;AAChB,eAAO;AAGT,YAAMC,sBAAsBT,UAAUU,uBAAuBb,QAAQ,GAC/Dc,uBAAuBF,sBACzBG,MAAMC,gCAAgC;AAAA,QACpChB;AAAAA,QACAiB,gBAAgBL;AAAAA,MAAAA,CACjB,IACDD;AAEJ,UAAI,CAACG;AACH,eAAO;AAIT,YAAMI,UAAU,GADGf,UAAUgB,mBAAmBnB,QAAQ,CAC3B,GAAGC,MAAMmB,IAAI,IACpCC,iBAAiBH,QAAQI,MAAM3B,KAAK,GAAG4B,GAAG,CAAC;AAEjD,UAAIF,mBAAmBV;AACrB,eAAO;AAGT,YAAMa,gBAAgB;AAAA,QACpBC,QAAQ;AAAA,UACNlB,MAAML,eAAeK;AAAAA;AAAAA,UAErBmB,QAAQR,QAAQS,SAASN,eAAeM;AAAAA,QAAAA;AAAAA,QAE1CC,OAAO;AAAA,UACLrB,MAAML,eAAeK;AAAAA;AAAAA,UAErBmB,QACER,QAAQS,SACRN,eAAeM,SACfrC,OAAOC,KAAKd,KAAKkD,SAASrC,OAAOC,KAAKb;AAAAA,QAAAA;AAAAA,MAC1C,GAGImD,gBAAgB;AAAA,QACpBJ,QAAQ;AAAA,UACNlB,MAAML,eAAeK;AAAAA;AAAAA,UAErBmB,QACEZ,qBAAqBY,SACrBzB,MAAMmB,KAAKO,SACXrC,OAAOC,KAAKd,KAAKkD,SAASrC,OAAOC,KAAKb;AAAAA,QAAAA;AAAAA,QAE1CkD,OAAO;AAAA,UACLrB,MAAML,eAAeK;AAAAA;AAAAA,UAErBmB,QAAQZ,qBAAqBY,SAASzB,MAAMmB,KAAKO;AAAAA,QAAAA;AAAAA,MACnD;AAKF,UAAIH,cAAcI,MAAMF,SAASF,cAAcC,OAAOC,SAAS,GAAG;AAChE,cAAMI,kBAAkBf,MAAMgB,wBAAwB;AAAA,UACpD/B;AAAAA,UACAgC,SAASR;AAAAA,QAAAA,CACV,GACKS,gCAAgC9B,UAAU+B,wBAC9C;AAAA,UACE,GAAGlC;AAAAA,UACHS,SAAS;AAAA,YACP,GAAGT,SAASS;AAAAA,YACZ0B,WAAWL,kBACP;AAAA,cACEL,QAAQK,gBAAgBF;AAAAA,cACxBA,OAAOE,gBAAgBF;AAAAA,YAAAA,IAEzB;AAAA,UAAA;AAAA,QACN,CAEJ,GACMQ,sCACJH,gCACIlB,MAAMsB,iCAAiC;AAAA,UACrCrC;AAAAA,UACAiB,gBAAgB;AAAA,YACdV,MAAM0B,8BAA8B1B;AAAAA,YACpCmB,QAAQ;AAAA,UAAA;AAAA,QACV,CACD,IACDf;AAEN,YACEyB,uCACAA,oCAAoCV,SAClCF,cAAcC,OAAOC,UACvBU,oCAAoCV,SAClCF,cAAcI,MAAMF;AAEtB,iBAAO;AAAA,MAEX;AAIA,UAAIG,cAAcD,MAAMF,SAASG,cAAcJ,OAAOC,SAAS,GAAG;AAChE,cAAMY,uBAAuBnC,UAAU+B,wBAAwBlC,QAAQ,GACjEuC,6BAA6BD,uBAC/BvB,MAAMsB,iCAAiC;AAAA,UACrCrC;AAAAA,UACAiB,gBAAgB;AAAA,YACdV,MAAM+B,qBAAqB/B;AAAAA,YAC3BmB,QAAQ;AAAA,UAAA;AAAA,QACV,CACD,IACDf;AAEJ,YACE4B,8BACAA,2BAA2Bb,SAASG,cAAcJ,OAAOC,UACzDa,2BAA2Bb,SAASG,cAAcD,MAAMF;AAExD,iBAAO;AAAA,MAEX;AAEA,aAAO;AAAA,QACLF;AAAAA,QACAK;AAAAA,QACArB;AAAAA,MAAAA;AAAAA,IAEJ;AAAA,IACAgC,SAAS;AAAA;AAAA,MAEP,CAAC;AAAA,QAACvC;AAAAA,MAAAA,MAAW,CAACwC,QAAQxC,KAAK,CAAC;AAAA,MAC5B,CAACyC,GAAG;AAAA,QAAClB;AAAAA,QAAeK;AAAAA,QAAerB;AAAAA,MAAAA,MAAe;AAAA;AAAA,QAEhDmC,MAAM;AAAA,UACJC,MAAM;AAAA,UACNpC;AAAAA,UACAe,IAAI;AAAA,YACFE,QAAQD,cAAcI;AAAAA,YACtBA,OAAOC,cAAcJ;AAAAA,UAAAA;AAAAA,QACvB,CACD;AAAA;AAAA,QAEDkB,MAAM;AAAA,UACJC,MAAM;AAAA,UACNrB,IAAIM;AAAAA,QAAAA,CACL;AAAA;AAAA,QAEDc,MAAM;AAAA,UACJC,MAAM;AAAA,UACNrB,IAAIC;AAAAA,QAAAA,CACL;AAAA;AAAA,QAEDmB,MAAM;AAAA,UACJC,MAAM;AAAA,UACNpC;AAAAA,QAAAA,CACD;AAAA,QACDqC,OAAO,MAAM;AACXvD,iBAAOwD,WAAW;AAAA,YAChB,GAAGjB,cAAcJ;AAAAA,YACjBC,QACEG,cAAcJ,OAAOC,UACpBF,cAAcI,MAAMF,SAASF,cAAcC,OAAOC;AAAAA,UAAAA,CACtD;AAAA,QACH,CAAC;AAAA,MAAA;AAAA,IAAC;AAAA,EACH,CAEJ;AACH;AC1MO,SAAAqB,6BAAAC,OAAA;AAAA,QAAAC,IAAAC,EAAA,CAAA,GAaLC,SAAeC,UAAAA;AAAW,MAAAC;AAAA,SAAAJ,EAAA,CAAA,MAAAE,UAAAF,EAAA,CAAA,MAAAD,MAAAxC,aAAAyC,EAAA,CAAA,MAAAD,MAAAzD,QAEQ8D,KAAA;AAAA,IAAAC,OACzB;AAAA,MAAAH;AAAAA,MAAA3C,WAEMwC,MAAKxC;AAAAA,MAAUjB,MACpByD,MAAKzD;AAAAA,IAAAA;AAAAA,EACb,GACD0D,OAAAE,QAAAF,EAAA,CAAA,IAAAD,MAAAxC,WAAAyC,EAAA,CAAA,IAAAD,MAAAzD,MAAA0D,OAAAI,MAAAA,KAAAJ,EAAA,CAAA,GANDM,YAAYC,sBAAsBH,EAMjC,GAEM;AAAI;AAoBb,MAAMI,mBAiBFA,CAAC;AAAA,EAACC;AAAAA,EAAUJ;AAAK,MACAA,MAAMH,OAAOQ,iBAAiB;AAAA,EAC/CC,UAAUvE,qCAAqC;AAAA,IAC7CmB,WAAW8C,MAAM9C;AAAAA,IACjBjB,MAAM+D,MAAM/D;AAAAA,IACZuD,YAAapB,CAAAA,WAAW;AACtBgC,eAAS;AAAA,QAACd,MAAM;AAAA,QAAiBiB,aAAanC;AAAAA,MAAAA,CAAO;AAAA,IACvD;AAAA,EAAA,CACD;AACH,CAAC,GAKGoC,4BAIFA,CAAC;AAAA,EAACJ;AAAAA,EAAUJ;AAAK,MAAM;AAIzB,QAAMS,eAAeT,MAAMH,OAAOrD,GAAG,aAAcG,CAAAA,UAAU;AAC3D,QAAI,CAACA,MAAMkC,WAAW;AACpBuB,eAAS;AAAA,QAACd,MAAM;AAAA,QAAaoB,cAAcrD;AAAAA,QAAWwB,WAAW;AAAA,MAAA,CAAK;AACtE;AAAA,IACF;AAEA,UAAMnC,WAAWsD,MAAMH,OAAOc,eACxBxC,SAASV,MAAMC,gCAAgC;AAAA,MACnDhB;AAAAA,MACAiB,gBAAgBhB,MAAMkC,UAAUV;AAAAA,IAAAA,CACjC,GACKG,QAAQb,MAAMC,gCAAgC;AAAA,MAClDhB;AAAAA,MACAiB,gBAAgBhB,MAAMkC,UAAUP;AAAAA,IAAAA,CACjC;AAED,QAAI,CAACH,UAAU,CAACG,OAAO;AACrB8B,eAAS;AAAA,QACPd,MAAM;AAAA,QACNoB,cAAcrD;AAAAA,QACdwB,WAAWlC,MAAMkC;AAAAA,MAAAA,CAClB;AACD;AAAA,IACF;AAEAuB,aAAS;AAAA,MACPd,MAAM;AAAA,MACNoB,cAAc;AAAA,QAACvC;AAAAA,QAAQG;AAAAA,MAAAA;AAAAA,MACvBO,WAAWlC,MAAMkC;AAAAA,IAAAA,CAClB;AAAA,EACH,CAAC;AAED,SAAO,MAAM4B,aAAaG,YAAAA;AAC5B,GAEMC,iCAIFA,CAAC;AAAA,EAACT;AAAAA,EAAUJ;AAAK,MACAA,MAAMH,OAAOQ,iBAAiB;AAAA,EAC/CC,UAAU/D,eAAe;AAAA,IACvBC,IAAI;AAAA,IACJ0C,SAAS,CACP,MAAM,CACJG,MAAM;AAAA,MACJC,MAAM;AAAA,IAAA,CACP,GACDC,OAAO,MAAM;AACXa,eAAS;AAAA,QAACd,MAAM;AAAA,MAAA,CAAkB;AAAA,IACpC,CAAC,CAAC,CACH;AAAA,EAAA,CAEJ;AACH,CAAC,GAKGY,uBAAuBY,MAAM;AAAA,EACjCC,OAAO;AAAA,IACL5D,SAAS,CAAA;AAAA,IAgBT6C,OAAO,CAAA;AAAA,IAcPgB,QAAQ,CAAA;AAAA,EAAC;AAAA,EAEXC,QAAQ;AAAA,IACN,qBAAqBC,aAAaf,gBAAgB;AAAA,IAClD,4BAA4Be,aAAaL,8BAA8B;AAAA,IACvE,sBAAsBK,aAAaV,yBAAyB;AAAA,EAAA;AAEhE,CAAC,EAAEW,cAAc;AAAA,EACfC,IAAI;AAAA,EACJjE,SAASA,CAAC;AAAA,IAAC6C;AAAAA,EAAAA,OAAY;AAAA,IACrB9C,WAAW8C,MAAM9C;AAAAA,IACjB2C,QAAQG,MAAMH;AAAAA,IACdwB,cAAc;AAAA,IACdpF,MAAM+D,MAAM/D;AAAAA,EAAAA;AAAAA,EAEdqF,SAAS;AAAA,EACTC,QAAQ;AAAA,IACN,MAAQ;AAAA,MACNC,QAAQ,CACN;AAAA,QACEC,KAAK;AAAA,QACLzB,OAAOA,CAAC;AAAA,UAAC7C;AAAAA,QAAAA,OAAc;AAAA,UACrBD,WAAWC,QAAQD;AAAAA,UACnB2C,QAAQ1C,QAAQ0C;AAAAA,UAChB5D,MAAMkB,QAAQlB;AAAAA,QAAAA;AAAAA,MAChB,CACD;AAAA,MAEHO,IAAI;AAAA,QACF,iBAAiB;AAAA,UACfkF,QAAQ;AAAA,UACRxC,SAASyC,OAAO;AAAA,YACdC,sBAAsBA,CAAC;AAAA,cAACjF;AAAAA,YAAAA,MAAWA,MAAM4D;AAAAA,YACzCc,cAAcA,CAAC;AAAA,cAAClE;AAAAA,YAAAA,MACdA,QAAQ0C,OAAOc,YAAAA,EAAcxD,QAAQ0B;AAAAA,UAAAA,CACxC;AAAA,QAAA;AAAA,MACH;AAAA,IACF;AAAA,IAEF,mBAAmB;AAAA,MACjBgD,MAAM,CACJF,OAAO;AAAA,QACLC,sBAAsBvE;AAAAA,MAAAA,CACvB,CAAC;AAAA,MAEJmE,QAAQ,CACN;AAAA,QACEC,KAAK;AAAA,QACLzB,OAAOA,CAAC;AAAA,UAAC7C;AAAAA,QAAAA,OAAc;AAAA,UAAC0C,QAAQ1C,QAAQ0C;AAAAA,QAAAA;AAAAA,MAAM,GAEhD;AAAA,QACE4B,KAAK;AAAA,QACLzB,OAAOA,CAAC;AAAA,UAAC7C;AAAAA,QAAAA,OAAc;AAAA,UAAC0C,QAAQ1C,QAAQ0C;AAAAA,QAAAA;AAAAA,MAAM,CAC/C;AAAA,MAEHrD,IAAI;AAAA,QACF,WAAa;AAAA,UACXkF,QAAQ;AAAA,UACRjF,OAAOA,CAAC;AAAA,YAACU;AAAAA,YAASR;AAAAA,UAAAA,MAAW;AAC3B,kBAAMiF,uBAAuBzE,QAAQyE;AAErC,gBAAIjF,MAAM+D,gBAAgBkB,sBAAsB;AAK9C,oBAAME,iBAAiBF,qBAAqB3E,KAAKgB,GAAG,EAAE,GAChD8D,cAAcpF,MAAM+D,aAAavC,OAAOlB,KAAKgB,GAAG,EAAE,GAClD+D,aAAarF,MAAM+D,aAAapC,MAAMrB,KAAKgB,GAAG,EAAE;AAEtD,kBACE,CAACR,MAAMwE,eAAeH,cAAc,KACpC,CAACrE,MAAMwE,eAAeF,WAAW,KACjC,CAACtE,MAAMwE,eAAeD,UAAU;AAEhC,uBAAO;AAGT,oBAAME,gBACJJ,eAAeK,SAASJ,YAAYI,QACpCP,qBAAqBxD,WAAWzB,MAAM+D,aAAavC,OAAOC,QACtDgE,eACJN,eAAeK,SAASH,WAAWG,QACnCP,qBAAqBxD,WAAWzB,MAAM+D,aAAapC,MAAMF;AAE3D,qBAAO8D,iBAAiBE;AAAAA,YAC1B;AAIA,mBAAO,CAAC3E,MAAM4E,kBACZlF,QAAQkE,cACR1E,MAAMkC,SACR;AAAA,UACF;AAAA,QAAA;AAAA,QAEF,mBAAmB;AAAA,UACjB6C,QAAQ;AAAA,QAAA;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEJ,CAAC;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/plugin-character-pair-decorator",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.25",
|
|
4
4
|
"description": "Automatically match a pair of characters and decorate the text in between",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"portabletext",
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@xstate/react": "^6.1.0",
|
|
36
|
-
"
|
|
37
|
-
"xstate": "^5.32.1"
|
|
36
|
+
"xstate": "^5.32.2"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
39
|
"@sanity/tsconfig": "^2.1.0",
|
|
@@ -49,13 +48,13 @@
|
|
|
49
48
|
"typescript": "5.9.3",
|
|
50
49
|
"typescript-eslint": "^8.48.0",
|
|
51
50
|
"vitest": "^4.1.9",
|
|
52
|
-
"@portabletext/editor": "^7.8.
|
|
51
|
+
"@portabletext/editor": "^7.8.2",
|
|
53
52
|
"@portabletext/schema": "2.2.2",
|
|
54
53
|
"racejar": "2.0.9"
|
|
55
54
|
},
|
|
56
55
|
"peerDependencies": {
|
|
57
56
|
"react": "^19.2",
|
|
58
|
-
"@portabletext/editor": "^7.8.
|
|
57
|
+
"@portabletext/editor": "^7.8.2"
|
|
59
58
|
},
|
|
60
59
|
"engines": {
|
|
61
60
|
"node": ">=20.19 <22 || >=22.12"
|