@portabletext/plugin-emoji-picker 4.0.14 → 4.0.15
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 +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { useEditor } from "@portabletext/editor";
|
|
|
3
3
|
import { useActorRef, useSelector } from "@xstate/react";
|
|
4
4
|
import { raise, defineBehavior, forward, effect } from "@portabletext/editor/behaviors";
|
|
5
5
|
import { getFocusSpan, getNextSpan, isPointAfterSelection, isPointBeforeSelection, getMarkState, getPreviousSpan } from "@portabletext/editor/selectors";
|
|
6
|
-
import { isSelectionCollapsed, isEqualSelectionPoints } from "@portabletext/editor/utils";
|
|
6
|
+
import { isEqualPaths, isSelectionCollapsed, isEqualSelectionPoints } from "@portabletext/editor/utils";
|
|
7
7
|
import { createKeyboardShortcut } from "@portabletext/keyboard-shortcuts";
|
|
8
8
|
import { defineInputRule, defineInputRuleBehavior } from "@portabletext/plugin-input-rule";
|
|
9
9
|
import { setup, not, assign, sendTo, fromCallback, assertEvent } from "xstate";
|
|
@@ -481,7 +481,7 @@ const triggerListenerCallback = ({
|
|
|
481
481
|
}
|
|
482
482
|
}
|
|
483
483
|
});
|
|
484
|
-
if (
|
|
484
|
+
if (!isEqualPaths(focusSpan.path, context.focusSpan.path))
|
|
485
485
|
return nextSpan && context.focusSpan.textAfter.length === 0 && snapshot.context.selection.focus.offset === 0 && isSelectionCollapsed(snapshot.context.selection) ? context.focusSpan : void 0;
|
|
486
486
|
if (!focusSpan.node.text.startsWith(context.focusSpan.textBefore) || !focusSpan.node.text.endsWith(context.focusSpan.textAfter))
|
|
487
487
|
return;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/create-match-emojis.ts","../src/emoji-picker-machine.tsx","../src/use-emoji-picker.ts"],"sourcesContent":["import type {MatchEmojis} from './match-emojis'\n\n/**\n * Proposed, but not required type, to represent an emoji match.\n *\n * @example\n * ```tsx\n * {\n * type: 'exact',\n * key: '😂-joy',\n * emoji: '😂',\n * keyword: 'joy',\n * }\n * ```\n * @example\n * ```tsx\n * {\n * type: 'partial',\n * key: '😹-joy-_cat',\n * emoji: '😹',\n * keyword: 'joy',\n * startSlice: '',\n * endSlice: '_cat',\n * }\n * ```\n *\n * @beta\n */\nexport type EmojiMatch =\n | {\n type: 'exact'\n key: string\n emoji: string\n keyword: string\n }\n | {\n type: 'partial'\n key: string\n emoji: string\n keyword: string\n startSlice: string\n endSlice: string\n }\n\n/**\n * Proposed, but not required, function to create a `MatchEmojis` function.\n *\n * @example\n * ```ts\n * const matchEmojis = createMatchEmojis({\n * emojis: {\n * '😂': ['joy'],\n * '😹': ['joy_cat'],\n * },\n * })\n * ```\n *\n * @beta\n */\nexport function createMatchEmojis(config: {\n emojis: Record<string, ReadonlyArray<string>>\n}): MatchEmojis<EmojiMatch> {\n return ({keyword}: {keyword: string}) => {\n const foundEmojis: Array<EmojiMatch> = []\n\n if (keyword.length < 1) {\n return foundEmojis\n }\n\n for (const emoji in config.emojis) {\n const emojiKeywords = config.emojis[emoji] ?? []\n\n for (const emojiKeyword of emojiKeywords) {\n const keywordIndex = emojiKeyword.indexOf(keyword)\n\n if (keywordIndex === -1) {\n continue\n }\n\n if (emojiKeyword === keyword) {\n foundEmojis.push({\n type: 'exact',\n key: `${emoji}-${keyword}`,\n emoji,\n keyword,\n })\n } else {\n const start = emojiKeyword.slice(0, keywordIndex)\n const end = emojiKeyword.slice(keywordIndex + keyword.length)\n\n foundEmojis.push({\n type: 'partial',\n key: `${emoji}-${start}${keyword}${end}`,\n emoji,\n keyword,\n startSlice: start,\n endSlice: end,\n })\n }\n }\n }\n\n return foundEmojis\n }\n}\n","import type {\n ChildPath,\n Editor,\n EditorSelector,\n EditorSnapshot,\n PortableTextSpan,\n} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n forward,\n raise,\n} from '@portabletext/editor/behaviors'\nimport {\n getFocusSpan,\n getMarkState,\n getNextSpan,\n getPreviousSpan,\n isPointAfterSelection,\n isPointBeforeSelection,\n type MarkState,\n} from '@portabletext/editor/selectors'\nimport {\n isEqualSelectionPoints,\n isSelectionCollapsed,\n} from '@portabletext/editor/utils'\nimport {createKeyboardShortcut} from '@portabletext/keyboard-shortcuts'\nimport {\n defineInputRule,\n defineInputRuleBehavior,\n type InputRuleMatch,\n} from '@portabletext/plugin-input-rule'\nimport {\n assertEvent,\n assign,\n fromCallback,\n not,\n sendTo,\n setup,\n type AnyEventObject,\n type CallbackLogicFunction,\n} from 'xstate'\nimport type {BaseEmojiMatch, MatchEmojis} from './match-emojis'\n\n/*******************\n * Keyboard shortcuts\n *******************/\nconst arrowUpShortcut = createKeyboardShortcut({\n default: [{key: 'ArrowUp'}],\n})\nconst arrowDownShortcut = createKeyboardShortcut({\n default: [{key: 'ArrowDown'}],\n})\nconst enterShortcut = createKeyboardShortcut({\n default: [{key: 'Enter'}],\n})\nconst tabShortcut = createKeyboardShortcut({\n default: [{key: 'Tab'}],\n})\nconst escapeShortcut = createKeyboardShortcut({\n default: [{key: 'Escape'}],\n})\n\nconst getTriggerState: EditorSelector<\n | {\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n }\n markState: MarkState\n focusSpanTextBefore: string\n focusSpanTextAfter: string\n previousSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n }\n | undefined\n nextSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n }\n | undefined\n }\n | undefined\n> = (snapshot) => {\n const focusSpan = getFocusSpan(snapshot)\n const markState = getMarkState(snapshot)\n\n if (!focusSpan || !markState || !snapshot.context.selection) {\n return undefined\n }\n\n const focusSpanTextBefore = focusSpan.node.text.slice(\n 0,\n snapshot.context.selection.focus.offset,\n )\n const focusSpanTextAfter = focusSpan.node.text.slice(\n snapshot.context.selection.focus.offset,\n )\n const previousSpan = getPreviousSpan(snapshot)\n const nextSpan = getNextSpan(snapshot)\n\n return {\n focusSpan,\n markState,\n focusSpanTextBefore,\n focusSpanTextAfter,\n previousSpan,\n nextSpan,\n }\n}\n\nfunction createTriggerActions({\n snapshot,\n payload,\n keywordState,\n}: {\n snapshot: EditorSnapshot\n payload: ReturnType<typeof getTriggerState> & {lastMatch: InputRuleMatch}\n keywordState: 'partial' | 'complete'\n}) {\n if (payload.markState.state === 'unchanged') {\n const focusSpan = {\n node: {\n _key: payload.focusSpan.node._key,\n _type: payload.focusSpan.node._type,\n text: `${payload.focusSpanTextBefore}${payload.lastMatch.text}${payload.focusSpanTextAfter}`,\n marks: payload.markState.marks,\n },\n path: payload.focusSpan.path,\n textBefore: payload.focusSpanTextBefore,\n textAfter: payload.focusSpanTextAfter,\n }\n\n if (keywordState === 'complete') {\n return [\n raise(\n createKeywordFoundEvent({\n focusSpan,\n }),\n ),\n ]\n }\n\n return [\n raise(\n createTriggerFoundEvent({\n focusSpan,\n }),\n ),\n ]\n }\n\n const newSpan = {\n _key: snapshot.context.keyGenerator(),\n _type: payload.focusSpan.node._type,\n text: payload.lastMatch.text,\n marks: payload.markState.marks,\n }\n\n let focusSpan = {\n node: {\n _key: newSpan._key,\n _type: newSpan._type,\n text: `${newSpan.text}${payload.nextSpan?.node.text ?? payload.focusSpanTextAfter}`,\n marks: payload.markState.marks,\n },\n path: [\n {_key: payload.focusSpan.path[0]._key},\n 'children',\n {_key: newSpan._key},\n ] satisfies ChildPath,\n textBefore: '',\n textAfter: payload.nextSpan?.node.text ?? payload.focusSpanTextAfter,\n }\n\n if (\n payload.previousSpan &&\n payload.focusSpanTextBefore.length === 0 &&\n JSON.stringify(payload.previousSpan.node.marks ?? []) ===\n JSON.stringify(payload.markState.marks)\n ) {\n // The text will be inserted into the previous span, so we'll treat that\n // as the focus span\n\n focusSpan = {\n node: {\n _key: payload.previousSpan.node._key,\n _type: newSpan._type,\n text: `${payload.previousSpan.node.text}${newSpan.text}`,\n marks: newSpan.marks,\n },\n path: payload.previousSpan.path,\n textBefore: payload.previousSpan.node.text,\n textAfter: '',\n }\n }\n\n return [\n raise({type: 'select', at: payload.lastMatch.targetOffsets}),\n raise({type: 'delete', at: payload.lastMatch.targetOffsets}),\n raise({type: 'insert.child', child: newSpan}),\n ...(keywordState === 'complete'\n ? [\n raise(\n createKeywordFoundEvent({\n focusSpan,\n }),\n ),\n ]\n : [\n raise(\n createTriggerFoundEvent({\n focusSpan,\n }),\n ),\n ]),\n ]\n}\n\n/*******************\n * Input Rules\n *******************/\n\n/**\n * Listen for a single colon insertion\n */\nconst triggerRule = defineInputRule({\n on: /:/,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n lastMatch,\n ...triggerState,\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({snapshot, payload, keywordState: 'partial'}),\n ],\n})\n\ntype TriggerFoundEvent = ReturnType<typeof createTriggerFoundEvent>\n\nfunction createTriggerFoundEvent(payload: {\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n }\n}) {\n return {\n type: 'custom.trigger found',\n ...payload,\n } as const\n}\n\n/**\n * Listen for a partial keyword like \":joy\"\n */\nconst partialKeywordRule = defineInputRule({\n on: /:[\\S]+/,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (lastMatch.targetOffsets.anchor.offset < event.textBefore.length) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({snapshot, payload, keywordState: 'partial'}),\n ],\n})\n\n/**\n * Listen for a complete keyword like \":joy:\"\n */\nconst keywordRule = defineInputRule({\n on: /:[\\S]+:/,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (lastMatch.targetOffsets.anchor.offset < event.textBefore.length) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({snapshot, payload, keywordState: 'complete'}),\n ],\n})\n\ntype KeywordFoundEvent = ReturnType<typeof createKeywordFoundEvent>\n\nfunction createKeywordFoundEvent(payload: {\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n }\n}) {\n return {\n type: 'custom.keyword found',\n ...payload,\n } as const\n}\n\ntype EmojiPickerContext = {\n editor: Editor\n matches: ReadonlyArray<BaseEmojiMatch>\n matchEmojis: MatchEmojis<BaseEmojiMatch>\n selectedIndex: number\n focusSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n }\n | undefined\n incompleteKeywordRegex: RegExp\n keyword: string\n}\n\ntype EmojiPickerEvent =\n | TriggerFoundEvent\n | KeywordFoundEvent\n | {\n type: 'selection changed'\n }\n | {\n type: 'dismiss'\n }\n | {\n type: 'navigate down'\n }\n | {\n type: 'navigate up'\n }\n | {\n type: 'navigate to'\n index: number\n }\n | {\n type: 'insert selected match'\n }\n\nconst triggerListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregisterBehaviors = [\n input.editor.registerBehavior({\n behavior: defineInputRuleBehavior({\n rules: [keywordRule, partialKeywordRule, triggerRule],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior<KeywordFoundEvent, KeywordFoundEvent['type']>({\n on: 'custom.keyword found',\n actions: [\n ({event}) => [\n effect(() => {\n sendBack(event)\n }),\n ],\n ],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior<TriggerFoundEvent, TriggerFoundEvent['type']>({\n on: 'custom.trigger found',\n actions: [\n ({event}) => [\n effect(() => {\n sendBack(event)\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n}\n\nconst escapeListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n return input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => escapeShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n })\n}\n\nconst arrowListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregisterBehaviors = [\n input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => arrowDownShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'navigate down'})\n }),\n ],\n ],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => arrowUpShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'navigate up'})\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n}\n\nconst emojiInsertListener: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {context: EmojiPickerContext}\n> = ({sendBack, input}) => {\n return input.context.editor.registerBehavior({\n behavior: defineBehavior<{\n emoji: string\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n }\n }>({\n on: 'custom.insert emoji',\n actions: [\n ({event}) => [\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n raise({\n type: 'delete',\n at: {\n anchor: {\n path: event.focusSpan.path,\n offset: event.focusSpan.textBefore.length,\n },\n focus: {\n path: event.focusSpan.path,\n offset:\n event.focusSpan.node.text.length -\n event.focusSpan.textAfter.length,\n },\n },\n }),\n raise({\n type: 'insert.text',\n text: event.emoji,\n }),\n ],\n ],\n }),\n })\n}\n\nconst submitListenerCallback: CallbackLogicFunction<\n {type: 'context changed'; context: EmojiPickerContext},\n EmojiPickerEvent,\n {context: EmojiPickerContext}\n> = ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n const unregisterBehaviors = [\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => {\n if (\n !enterShortcut.guard(event.originEvent) &&\n !tabShortcut.guard(event.originEvent)\n ) {\n return false\n }\n\n const focusSpan = context.focusSpan\n const match = context.matches[context.selectedIndex]\n\n return match && focusSpan ? {focusSpan, emoji: match.emoji} : false\n },\n actions: [\n (_, {focusSpan, emoji}) => [\n raise({\n type: 'custom.insert emoji',\n emoji,\n focusSpan,\n }),\n ],\n ],\n }),\n }),\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) =>\n (enterShortcut.guard(event.originEvent) ||\n tabShortcut.guard(event.originEvent)) &&\n context.keyword.length === 1,\n actions: [\n ({event}) => [\n forward(event),\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n }),\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) =>\n (enterShortcut.guard(event.originEvent) ||\n tabShortcut.guard(event.originEvent)) &&\n context.keyword.length > 1,\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n}\n\nconst selectionListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const subscription = input.editor.on('selection', () => {\n sendBack({type: 'selection changed'})\n })\n\n return subscription.unsubscribe\n}\n\nconst textInsertionListenerCallback: CallbackLogicFunction<\n {type: 'context changed'; context: EmojiPickerContext},\n EmojiPickerEvent,\n {context: EmojiPickerContext}\n> = ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n return input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'insert.text',\n guard: ({snapshot}) => {\n if (!context.focusSpan) {\n return false\n }\n\n if (!snapshot.context.selection) {\n return false\n }\n\n const keywordAnchor = {\n path: context.focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n }\n\n return isEqualSelectionPoints(\n snapshot.context.selection.focus,\n keywordAnchor,\n )\n },\n actions: [\n ({event}) => [\n forward(event),\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n })\n}\n\nexport const emojiPickerMachine = setup({\n types: {\n context: {} as EmojiPickerContext,\n input: {} as {\n editor: Editor\n matchEmojis: MatchEmojis\n },\n events: {} as EmojiPickerEvent,\n },\n actors: {\n 'emoji insert listener': fromCallback(emojiInsertListener),\n 'submit listener': fromCallback(submitListenerCallback),\n 'arrow listener': fromCallback(arrowListenerCallback),\n 'trigger listener': fromCallback(triggerListenerCallback),\n 'escape listener': fromCallback(escapeListenerCallback),\n 'selection listener': fromCallback(selectionListenerCallback),\n 'text insertion listener': fromCallback(textInsertionListenerCallback),\n },\n actions: {\n 'set focus span': assign({\n focusSpan: ({context, event}) => {\n if (\n event.type !== 'custom.trigger found' &&\n event.type !== 'custom.keyword found'\n ) {\n return context.focusSpan\n }\n\n return event.focusSpan\n },\n }),\n 'update focus span': assign({\n focusSpan: ({context}) => {\n if (!context.focusSpan) {\n return undefined\n }\n\n const snapshot = context.editor.getSnapshot()\n const focusSpan = getFocusSpan(snapshot)\n\n if (!snapshot.context.selection) {\n return undefined\n }\n\n if (!focusSpan) {\n return undefined\n }\n\n const nextSpan = getNextSpan({\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: {\n anchor: {\n path: context.focusSpan.path,\n offset: 0,\n },\n focus: {\n path: context.focusSpan.path,\n offset: 0,\n },\n },\n },\n })\n\n if (\n JSON.stringify(focusSpan.path) !==\n JSON.stringify(context.focusSpan.path)\n ) {\n if (\n nextSpan &&\n context.focusSpan.textAfter.length === 0 &&\n snapshot.context.selection.focus.offset === 0 &&\n isSelectionCollapsed(snapshot.context.selection)\n ) {\n // This is an edge case where the caret is moved from the end of\n // the focus span to the start of the next span.\n return context.focusSpan\n }\n\n return undefined\n }\n\n if (!focusSpan.node.text.startsWith(context.focusSpan.textBefore)) {\n return undefined\n }\n\n if (!focusSpan.node.text.endsWith(context.focusSpan.textAfter)) {\n return undefined\n }\n\n const keywordAnchor = {\n path: focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n }\n const keywordFocus = {\n path: focusSpan.path,\n offset:\n focusSpan.node.text.length - context.focusSpan.textAfter.length,\n }\n\n const selectionIsBeforeKeyword =\n isPointAfterSelection(keywordAnchor)(snapshot)\n\n const selectionIsAfterKeyword =\n isPointBeforeSelection(keywordFocus)(snapshot)\n\n if (selectionIsBeforeKeyword || selectionIsAfterKeyword) {\n return undefined\n }\n\n return {\n node: focusSpan.node,\n path: focusSpan.path,\n textBefore: context.focusSpan.textBefore,\n textAfter: context.focusSpan.textAfter,\n }\n },\n }),\n 'update keyword': assign({\n keyword: ({context}) => {\n if (!context.focusSpan) {\n return ''\n }\n\n if (\n context.focusSpan.textBefore.length > 0 &&\n context.focusSpan.textAfter.length > 0\n ) {\n return context.focusSpan.node.text.slice(\n context.focusSpan.textBefore.length,\n -context.focusSpan.textAfter.length,\n )\n }\n\n if (context.focusSpan.textBefore.length > 0) {\n return context.focusSpan.node.text.slice(\n context.focusSpan.textBefore.length,\n )\n }\n\n if (context.focusSpan.textAfter.length > 0) {\n return context.focusSpan.node.text.slice(\n 0,\n -context.focusSpan.textAfter.length,\n )\n }\n\n return context.focusSpan.node.text\n },\n }),\n 'update matches': assign({\n matches: ({context}) => {\n // Strip leading colon\n let rawKeyword = context.keyword.startsWith(':')\n ? context.keyword.slice(1)\n : context.keyword\n // Strip trailing colon\n rawKeyword =\n rawKeyword.length > 1 && rawKeyword.endsWith(':')\n ? rawKeyword.slice(0, -1)\n : rawKeyword\n\n if (rawKeyword === undefined) {\n return []\n }\n\n return context.matchEmojis({keyword: rawKeyword})\n },\n }),\n 'reset selected index': assign({\n selectedIndex: 0,\n }),\n 'increment selected index': assign({\n selectedIndex: ({context}) => {\n if (context.selectedIndex === context.matches.length - 1) {\n return 0\n }\n return context.selectedIndex + 1\n },\n }),\n 'decrement selected index': assign({\n selectedIndex: ({context}) => {\n if (context.selectedIndex === 0) {\n return context.matches.length - 1\n }\n return context.selectedIndex - 1\n },\n }),\n 'set selected index': assign({\n selectedIndex: ({event}) => {\n assertEvent(event, 'navigate to')\n\n return event.index\n },\n }),\n 'update submit listener context': sendTo(\n 'submit listener',\n ({context}) => ({\n type: 'context changed',\n context,\n }),\n ),\n 'update text insertion listener context': sendTo(\n 'text insertion listener',\n ({context}) => ({\n type: 'context changed',\n context,\n }),\n ),\n 'insert selected match': ({context}) => {\n const match = context.matches[context.selectedIndex]\n\n if (!match || !context.focusSpan) {\n return\n }\n\n context.editor.send({\n type: 'custom.insert emoji',\n emoji: match.emoji,\n focusSpan: context.focusSpan,\n })\n },\n 'reset': assign({\n focusSpan: undefined,\n keyword: '',\n matches: [],\n selectedIndex: 0,\n }),\n },\n guards: {\n 'no focus span': ({context}) => {\n return !context.focusSpan\n },\n 'has matches': ({context}) => {\n return context.matches.length > 0\n },\n 'no matches': not('has matches'),\n 'keyword is malformed': ({context}) => {\n return !context.incompleteKeywordRegex.test(context.keyword)\n },\n 'keyword is direct match': ({context}) => {\n const fullKeywordRegex = /^:[\\S]+:$/\n\n if (!fullKeywordRegex.test(context.keyword)) {\n return false\n }\n\n const match = context.matches.at(context.selectedIndex)\n\n if (!match || match.type !== 'exact') {\n return false\n }\n\n return true\n },\n },\n}).createMachine({\n id: 'emoji picker',\n context: ({input}) => ({\n editor: input.editor,\n keyword: '',\n focusSpan: undefined,\n matchEmojis: input.matchEmojis,\n incompleteKeywordRegex: /^:[\\S]*$/,\n matches: [],\n selectedIndex: 0,\n }),\n initial: 'idle',\n invoke: [\n {\n src: 'emoji insert listener',\n id: 'emoji insert listener',\n input: ({context}) => ({context}),\n },\n ],\n states: {\n idle: {\n entry: ['reset'],\n invoke: {\n src: 'trigger listener',\n input: ({context}) => ({editor: context.editor}),\n },\n on: {\n 'custom.trigger found': {\n target: 'searching',\n actions: ['set focus span', 'update keyword'],\n },\n 'custom.keyword found': {\n actions: [\n 'set focus span',\n 'update keyword',\n 'update matches',\n 'insert selected match',\n ],\n target: 'idle',\n reenter: true,\n },\n },\n },\n searching: {\n invoke: [\n {\n src: 'submit listener',\n id: 'submit listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'escape listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'selection listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'text insertion listener',\n id: 'text insertion listener',\n input: ({context}) => ({context}),\n },\n ],\n on: {\n 'dismiss': {\n target: 'idle',\n },\n 'selection changed': [\n {\n actions: [\n 'update focus span',\n 'update keyword',\n 'update matches',\n 'reset selected index',\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n },\n ],\n },\n always: [\n {\n guard: 'no focus span',\n target: 'idle',\n },\n {\n guard: 'keyword is malformed',\n target: 'idle',\n },\n {\n guard: 'keyword is direct match',\n actions: ['insert selected match'],\n target: 'idle',\n },\n ],\n initial: 'no matches showing',\n states: {\n 'no matches showing': {\n entry: ['reset selected index'],\n always: {\n guard: 'has matches',\n target: 'showing matches',\n },\n },\n 'showing matches': {\n invoke: {\n src: 'arrow listener',\n input: ({context}) => ({editor: context.editor}),\n },\n always: [\n {\n guard: 'no matches',\n target: 'no matches showing',\n },\n ],\n on: {\n 'navigate down': {\n actions: [\n 'increment selected index',\n 'update submit listener context',\n ],\n },\n 'navigate up': {\n actions: [\n 'decrement selected index',\n 'update submit listener context',\n ],\n },\n 'navigate to': {\n actions: ['set selected index', 'update submit listener context'],\n },\n 'insert selected match': {\n actions: ['insert selected match'],\n },\n },\n },\n },\n },\n },\n})\n","import {useEditor} from '@portabletext/editor'\nimport {useActorRef, useSelector} from '@xstate/react'\nimport {useCallback} from 'react'\nimport {emojiPickerMachine} from './emoji-picker-machine'\nimport type {BaseEmojiMatch, MatchEmojis} from './match-emojis'\n\n/**\n * @beta\n */\nexport type EmojiPicker<TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch> = {\n /**\n * The matched keyword.\n *\n * Can be used to display the keyword in the UI or conditionally render the\n * list of matches.\n *\n * @example\n * ```tsx\n * if (keyword.length < 1) {\n * return null\n * }\n * ```\n */\n keyword: string\n\n /**\n * Emoji matches found for the current keyword.\n *\n * Can be used to display the matches in a list.\n */\n matches: ReadonlyArray<TEmojiMatch>\n\n /**\n * The index of the selected match.\n *\n * Can be used to highlight the selected match in the list.\n *\n * @example\n * ```tsx\n * <EmojiListItem\n * key={match.key}\n * match={match}\n * selected={selectedIndex === index}\n * />\n * ```\n */\n selectedIndex: number\n\n /**\n * Navigate to a specific match by index.\n *\n * Can be used to control the `selectedIndex`. For example, using\n * `onMouseEnter`.\n *\n * @example\n * ```tsx\n * <EmojiListItem\n * key={match.key}\n * match={match}\n * selected={selectedIndex === index}\n * onMouseEnter={() => {onNavigateTo(index)}}\n * />\n * ```\n */\n onNavigateTo: (index: number) => void\n\n /**\n * Select the current match.\n *\n * Can be used to insert the currently selected match.\n *\n *\n * @example\n * ```tsx\n * <EmojiListItem\n * key={match.key}\n * match={match}\n * selected={selectedIndex === index}\n * onMouseEnter={() => {onNavigateTo(index)}}\n * onSelect={() => {onSelect()}}\n * />\n * ```\n *\n * Note: The currently selected match is automatically inserted on Enter or\n * Tab.\n */\n onSelect: () => void\n\n /**\n * Dismiss the emoji picker. Can be used to let the user dismiss the picker\n * by clicking a button.\n *\n * @example\n * ```tsx\n * {matches.length === 0 ? (\n * <Button onPress={onDismiss}>Dismiss</Button>\n * ) : <EmojiListBox {...props} />}\n * ```\n *\n * Note: The emoji picker is automatically dismissed on Escape.\n */\n onDismiss: () => void\n}\n\n/**\n * @beta\n */\nexport type EmojiPickerProps<\n TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch,\n> = {\n matchEmojis: MatchEmojis<TEmojiMatch>\n}\n\n/**\n * Handles the state and logic needed to create an emoji picker.\n *\n * The `matchEmojis` function is generic and can return any shape of emoji\n * match required for the emoji picker.\n *\n * However, the default implementation of `matchEmojis` returns an array of\n * `EmojiMatch` objects and can be created using the `createMatchEmojis`\n * function.\n *\n * @example\n *\n * ```tsx\n * const matchEmojis = createMatchEmojis({emojis: {\n * '😂': ['joy'],\n * '😹': ['joy_cat'],\n * }})\n *\n * const {keyword, matches, selectedIndex, onDismiss, onNavigateTo, onSelect} =\n * useEmojiPicker({matchEmojis})\n * ```\n *\n * Note: This hook is not concerned with the UI, how the emoji picker is\n * rendered or positioned in the document.\n *\n * @beta\n */\nexport function useEmojiPicker<\n TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch,\n>(props: EmojiPickerProps<TEmojiMatch>): EmojiPicker<TEmojiMatch> {\n const editor = useEditor()\n const emojiPickerActor = useActorRef(emojiPickerMachine, {\n input: {editor, matchEmojis: props.matchEmojis},\n })\n const keyword = useSelector(emojiPickerActor, (snapshot) => {\n const rawKeyword = snapshot.context.keyword.startsWith(':')\n ? snapshot.context.keyword.slice(1)\n : snapshot.context.keyword\n return rawKeyword.length > 1 && rawKeyword.endsWith(':')\n ? rawKeyword.slice(0, -1)\n : rawKeyword\n })\n const matches = useSelector(\n emojiPickerActor,\n (snapshot) => snapshot.context.matches as ReadonlyArray<TEmojiMatch>,\n )\n const selectedIndex = useSelector(\n emojiPickerActor,\n (snapshot) => snapshot.context.selectedIndex,\n )\n\n const onDismiss = useCallback(() => {\n emojiPickerActor.send({type: 'dismiss'})\n }, [emojiPickerActor])\n const onNavigateTo = useCallback(\n (index: number) => {\n emojiPickerActor.send({type: 'navigate to', index})\n },\n [emojiPickerActor],\n )\n const onSelect = useCallback(() => {\n emojiPickerActor.send({type: 'insert selected match'})\n editor.send({type: 'focus'})\n }, [emojiPickerActor, editor])\n\n return {\n keyword,\n matches,\n selectedIndex,\n onDismiss,\n onNavigateTo,\n onSelect,\n }\n}\n"],"names":["createMatchEmojis","config","keyword","foundEmojis","length","emoji","emojis","emojiKeywords","emojiKeyword","keywordIndex","indexOf","push","type","key","start","slice","end","startSlice","endSlice","arrowUpShortcut","createKeyboardShortcut","default","arrowDownShortcut","enterShortcut","tabShortcut","escapeShortcut","getTriggerState","snapshot","focusSpan","getFocusSpan","markState","getMarkState","context","selection","focusSpanTextBefore","node","text","focus","offset","focusSpanTextAfter","previousSpan","getPreviousSpan","nextSpan","getNextSpan","createTriggerActions","payload","keywordState","state","_key","_type","lastMatch","marks","path","textBefore","textAfter","raise","createKeywordFoundEvent","createTriggerFoundEvent","newSpan","keyGenerator","JSON","stringify","at","targetOffsets","child","triggerRule","defineInputRule","on","guard","event","matches","undefined","triggerState","actions","partialKeywordRule","anchor","keywordRule","triggerListenerCallback","sendBack","input","unregisterBehaviors","editor","registerBehavior","behavior","defineInputRuleBehavior","rules","defineBehavior","effect","unregister","escapeListenerCallback","originEvent","arrowListenerCallback","emojiInsertListener","submitListenerCallback","receive","match","selectedIndex","_","forward","selectionListenerCallback","unsubscribe","textInsertionListenerCallback","keywordAnchor","isEqualSelectionPoints","emojiPickerMachine","setup","types","events","actors","fromCallback","assign","getSnapshot","isSelectionCollapsed","startsWith","endsWith","keywordFocus","selectionIsBeforeKeyword","isPointAfterSelection","selectionIsAfterKeyword","isPointBeforeSelection","rawKeyword","matchEmojis","assertEvent","index","sendTo","insert selected match","send","guards","no focus span","has matches","not","keyword is malformed","incompleteKeywordRegex","test","keyword is direct match","createMachine","id","initial","invoke","src","states","idle","entry","target","reenter","searching","always","useEmojiPicker","props","$","_c","useEditor","t0","emojiPickerActor","useActorRef","useSelector","_temp","_temp2","_temp3","t1","onDismiss","t2","onNavigateTo","t3","onSelect","t4","snapshot_1","snapshot_0"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/create-match-emojis.ts","../src/emoji-picker-machine.tsx","../src/use-emoji-picker.ts"],"sourcesContent":["import type {MatchEmojis} from './match-emojis'\n\n/**\n * Proposed, but not required type, to represent an emoji match.\n *\n * @example\n * ```tsx\n * {\n * type: 'exact',\n * key: '😂-joy',\n * emoji: '😂',\n * keyword: 'joy',\n * }\n * ```\n * @example\n * ```tsx\n * {\n * type: 'partial',\n * key: '😹-joy-_cat',\n * emoji: '😹',\n * keyword: 'joy',\n * startSlice: '',\n * endSlice: '_cat',\n * }\n * ```\n *\n * @beta\n */\nexport type EmojiMatch =\n | {\n type: 'exact'\n key: string\n emoji: string\n keyword: string\n }\n | {\n type: 'partial'\n key: string\n emoji: string\n keyword: string\n startSlice: string\n endSlice: string\n }\n\n/**\n * Proposed, but not required, function to create a `MatchEmojis` function.\n *\n * @example\n * ```ts\n * const matchEmojis = createMatchEmojis({\n * emojis: {\n * '😂': ['joy'],\n * '😹': ['joy_cat'],\n * },\n * })\n * ```\n *\n * @beta\n */\nexport function createMatchEmojis(config: {\n emojis: Record<string, ReadonlyArray<string>>\n}): MatchEmojis<EmojiMatch> {\n return ({keyword}: {keyword: string}) => {\n const foundEmojis: Array<EmojiMatch> = []\n\n if (keyword.length < 1) {\n return foundEmojis\n }\n\n for (const emoji in config.emojis) {\n const emojiKeywords = config.emojis[emoji] ?? []\n\n for (const emojiKeyword of emojiKeywords) {\n const keywordIndex = emojiKeyword.indexOf(keyword)\n\n if (keywordIndex === -1) {\n continue\n }\n\n if (emojiKeyword === keyword) {\n foundEmojis.push({\n type: 'exact',\n key: `${emoji}-${keyword}`,\n emoji,\n keyword,\n })\n } else {\n const start = emojiKeyword.slice(0, keywordIndex)\n const end = emojiKeyword.slice(keywordIndex + keyword.length)\n\n foundEmojis.push({\n type: 'partial',\n key: `${emoji}-${start}${keyword}${end}`,\n emoji,\n keyword,\n startSlice: start,\n endSlice: end,\n })\n }\n }\n }\n\n return foundEmojis\n }\n}\n","import type {\n ChildPath,\n Editor,\n EditorSelector,\n EditorSnapshot,\n PortableTextSpan,\n} from '@portabletext/editor'\nimport {\n defineBehavior,\n effect,\n forward,\n raise,\n} from '@portabletext/editor/behaviors'\nimport {\n getFocusSpan,\n getMarkState,\n getNextSpan,\n getPreviousSpan,\n isPointAfterSelection,\n isPointBeforeSelection,\n type MarkState,\n} from '@portabletext/editor/selectors'\nimport {\n isEqualPaths,\n isEqualSelectionPoints,\n isSelectionCollapsed,\n} from '@portabletext/editor/utils'\nimport {createKeyboardShortcut} from '@portabletext/keyboard-shortcuts'\nimport {\n defineInputRule,\n defineInputRuleBehavior,\n type InputRuleMatch,\n} from '@portabletext/plugin-input-rule'\nimport {\n assertEvent,\n assign,\n fromCallback,\n not,\n sendTo,\n setup,\n type AnyEventObject,\n type CallbackLogicFunction,\n} from 'xstate'\nimport type {BaseEmojiMatch, MatchEmojis} from './match-emojis'\n\n/*******************\n * Keyboard shortcuts\n *******************/\nconst arrowUpShortcut = createKeyboardShortcut({\n default: [{key: 'ArrowUp'}],\n})\nconst arrowDownShortcut = createKeyboardShortcut({\n default: [{key: 'ArrowDown'}],\n})\nconst enterShortcut = createKeyboardShortcut({\n default: [{key: 'Enter'}],\n})\nconst tabShortcut = createKeyboardShortcut({\n default: [{key: 'Tab'}],\n})\nconst escapeShortcut = createKeyboardShortcut({\n default: [{key: 'Escape'}],\n})\n\nconst getTriggerState: EditorSelector<\n | {\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n }\n markState: MarkState\n focusSpanTextBefore: string\n focusSpanTextAfter: string\n previousSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n }\n | undefined\n nextSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n }\n | undefined\n }\n | undefined\n> = (snapshot) => {\n const focusSpan = getFocusSpan(snapshot)\n const markState = getMarkState(snapshot)\n\n if (!focusSpan || !markState || !snapshot.context.selection) {\n return undefined\n }\n\n const focusSpanTextBefore = focusSpan.node.text.slice(\n 0,\n snapshot.context.selection.focus.offset,\n )\n const focusSpanTextAfter = focusSpan.node.text.slice(\n snapshot.context.selection.focus.offset,\n )\n const previousSpan = getPreviousSpan(snapshot)\n const nextSpan = getNextSpan(snapshot)\n\n return {\n focusSpan,\n markState,\n focusSpanTextBefore,\n focusSpanTextAfter,\n previousSpan,\n nextSpan,\n }\n}\n\nfunction createTriggerActions({\n snapshot,\n payload,\n keywordState,\n}: {\n snapshot: EditorSnapshot\n payload: ReturnType<typeof getTriggerState> & {lastMatch: InputRuleMatch}\n keywordState: 'partial' | 'complete'\n}) {\n if (payload.markState.state === 'unchanged') {\n const focusSpan = {\n node: {\n _key: payload.focusSpan.node._key,\n _type: payload.focusSpan.node._type,\n text: `${payload.focusSpanTextBefore}${payload.lastMatch.text}${payload.focusSpanTextAfter}`,\n marks: payload.markState.marks,\n },\n path: payload.focusSpan.path,\n textBefore: payload.focusSpanTextBefore,\n textAfter: payload.focusSpanTextAfter,\n }\n\n if (keywordState === 'complete') {\n return [\n raise(\n createKeywordFoundEvent({\n focusSpan,\n }),\n ),\n ]\n }\n\n return [\n raise(\n createTriggerFoundEvent({\n focusSpan,\n }),\n ),\n ]\n }\n\n const newSpan = {\n _key: snapshot.context.keyGenerator(),\n _type: payload.focusSpan.node._type,\n text: payload.lastMatch.text,\n marks: payload.markState.marks,\n }\n\n let focusSpan = {\n node: {\n _key: newSpan._key,\n _type: newSpan._type,\n text: `${newSpan.text}${payload.nextSpan?.node.text ?? payload.focusSpanTextAfter}`,\n marks: payload.markState.marks,\n },\n path: [\n {_key: payload.focusSpan.path[0]._key},\n 'children',\n {_key: newSpan._key},\n ] satisfies ChildPath,\n textBefore: '',\n textAfter: payload.nextSpan?.node.text ?? payload.focusSpanTextAfter,\n }\n\n if (\n payload.previousSpan &&\n payload.focusSpanTextBefore.length === 0 &&\n JSON.stringify(payload.previousSpan.node.marks ?? []) ===\n JSON.stringify(payload.markState.marks)\n ) {\n // The text will be inserted into the previous span, so we'll treat that\n // as the focus span\n\n focusSpan = {\n node: {\n _key: payload.previousSpan.node._key,\n _type: newSpan._type,\n text: `${payload.previousSpan.node.text}${newSpan.text}`,\n marks: newSpan.marks,\n },\n path: payload.previousSpan.path,\n textBefore: payload.previousSpan.node.text,\n textAfter: '',\n }\n }\n\n return [\n raise({type: 'select', at: payload.lastMatch.targetOffsets}),\n raise({type: 'delete', at: payload.lastMatch.targetOffsets}),\n raise({type: 'insert.child', child: newSpan}),\n ...(keywordState === 'complete'\n ? [\n raise(\n createKeywordFoundEvent({\n focusSpan,\n }),\n ),\n ]\n : [\n raise(\n createTriggerFoundEvent({\n focusSpan,\n }),\n ),\n ]),\n ]\n}\n\n/*******************\n * Input Rules\n *******************/\n\n/**\n * Listen for a single colon insertion\n */\nconst triggerRule = defineInputRule({\n on: /:/,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n lastMatch,\n ...triggerState,\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({snapshot, payload, keywordState: 'partial'}),\n ],\n})\n\ntype TriggerFoundEvent = ReturnType<typeof createTriggerFoundEvent>\n\nfunction createTriggerFoundEvent(payload: {\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n }\n}) {\n return {\n type: 'custom.trigger found',\n ...payload,\n } as const\n}\n\n/**\n * Listen for a partial keyword like \":joy\"\n */\nconst partialKeywordRule = defineInputRule({\n on: /:[\\S]+/,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (lastMatch.targetOffsets.anchor.offset < event.textBefore.length) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({snapshot, payload, keywordState: 'partial'}),\n ],\n})\n\n/**\n * Listen for a complete keyword like \":joy:\"\n */\nconst keywordRule = defineInputRule({\n on: /:[\\S]+:/,\n guard: ({snapshot, event}) => {\n const lastMatch = event.matches.at(-1)\n\n if (lastMatch === undefined) {\n return false\n }\n\n if (lastMatch.targetOffsets.anchor.offset < event.textBefore.length) {\n return false\n }\n\n const triggerState = getTriggerState(snapshot)\n\n if (!triggerState) {\n return false\n }\n\n return {\n ...triggerState,\n lastMatch,\n }\n },\n actions: [\n ({snapshot}, payload) =>\n createTriggerActions({snapshot, payload, keywordState: 'complete'}),\n ],\n})\n\ntype KeywordFoundEvent = ReturnType<typeof createKeywordFoundEvent>\n\nfunction createKeywordFoundEvent(payload: {\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n }\n}) {\n return {\n type: 'custom.keyword found',\n ...payload,\n } as const\n}\n\ntype EmojiPickerContext = {\n editor: Editor\n matches: ReadonlyArray<BaseEmojiMatch>\n matchEmojis: MatchEmojis<BaseEmojiMatch>\n selectedIndex: number\n focusSpan:\n | {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n }\n | undefined\n incompleteKeywordRegex: RegExp\n keyword: string\n}\n\ntype EmojiPickerEvent =\n | TriggerFoundEvent\n | KeywordFoundEvent\n | {\n type: 'selection changed'\n }\n | {\n type: 'dismiss'\n }\n | {\n type: 'navigate down'\n }\n | {\n type: 'navigate up'\n }\n | {\n type: 'navigate to'\n index: number\n }\n | {\n type: 'insert selected match'\n }\n\nconst triggerListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregisterBehaviors = [\n input.editor.registerBehavior({\n behavior: defineInputRuleBehavior({\n rules: [keywordRule, partialKeywordRule, triggerRule],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior<KeywordFoundEvent, KeywordFoundEvent['type']>({\n on: 'custom.keyword found',\n actions: [\n ({event}) => [\n effect(() => {\n sendBack(event)\n }),\n ],\n ],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior<TriggerFoundEvent, TriggerFoundEvent['type']>({\n on: 'custom.trigger found',\n actions: [\n ({event}) => [\n effect(() => {\n sendBack(event)\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n}\n\nconst escapeListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n return input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => escapeShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n })\n}\n\nconst arrowListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const unregisterBehaviors = [\n input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => arrowDownShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'navigate down'})\n }),\n ],\n ],\n }),\n }),\n input.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => arrowUpShortcut.guard(event.originEvent),\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'navigate up'})\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n}\n\nconst emojiInsertListener: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {context: EmojiPickerContext}\n> = ({sendBack, input}) => {\n return input.context.editor.registerBehavior({\n behavior: defineBehavior<{\n emoji: string\n focusSpan: {\n node: PortableTextSpan\n path: ChildPath\n textBefore: string\n textAfter: string\n }\n }>({\n on: 'custom.insert emoji',\n actions: [\n ({event}) => [\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n raise({\n type: 'delete',\n at: {\n anchor: {\n path: event.focusSpan.path,\n offset: event.focusSpan.textBefore.length,\n },\n focus: {\n path: event.focusSpan.path,\n offset:\n event.focusSpan.node.text.length -\n event.focusSpan.textAfter.length,\n },\n },\n }),\n raise({\n type: 'insert.text',\n text: event.emoji,\n }),\n ],\n ],\n }),\n })\n}\n\nconst submitListenerCallback: CallbackLogicFunction<\n {type: 'context changed'; context: EmojiPickerContext},\n EmojiPickerEvent,\n {context: EmojiPickerContext}\n> = ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n const unregisterBehaviors = [\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) => {\n if (\n !enterShortcut.guard(event.originEvent) &&\n !tabShortcut.guard(event.originEvent)\n ) {\n return false\n }\n\n const focusSpan = context.focusSpan\n const match = context.matches[context.selectedIndex]\n\n return match && focusSpan ? {focusSpan, emoji: match.emoji} : false\n },\n actions: [\n (_, {focusSpan, emoji}) => [\n raise({\n type: 'custom.insert emoji',\n emoji,\n focusSpan,\n }),\n ],\n ],\n }),\n }),\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) =>\n (enterShortcut.guard(event.originEvent) ||\n tabShortcut.guard(event.originEvent)) &&\n context.keyword.length === 1,\n actions: [\n ({event}) => [\n forward(event),\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n }),\n input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'keyboard.keydown',\n guard: ({event}) =>\n (enterShortcut.guard(event.originEvent) ||\n tabShortcut.guard(event.originEvent)) &&\n context.keyword.length > 1,\n actions: [\n () => [\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n }),\n ]\n\n return () => {\n for (const unregister of unregisterBehaviors) {\n unregister()\n }\n }\n}\n\nconst selectionListenerCallback: CallbackLogicFunction<\n AnyEventObject,\n EmojiPickerEvent,\n {editor: Editor}\n> = ({sendBack, input}) => {\n const subscription = input.editor.on('selection', () => {\n sendBack({type: 'selection changed'})\n })\n\n return subscription.unsubscribe\n}\n\nconst textInsertionListenerCallback: CallbackLogicFunction<\n {type: 'context changed'; context: EmojiPickerContext},\n EmojiPickerEvent,\n {context: EmojiPickerContext}\n> = ({sendBack, input, receive}) => {\n let context = input.context\n\n receive((event) => {\n context = event.context\n })\n\n return input.context.editor.registerBehavior({\n behavior: defineBehavior({\n on: 'insert.text',\n guard: ({snapshot}) => {\n if (!context.focusSpan) {\n return false\n }\n\n if (!snapshot.context.selection) {\n return false\n }\n\n const keywordAnchor = {\n path: context.focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n }\n\n return isEqualSelectionPoints(\n snapshot.context.selection.focus,\n keywordAnchor,\n )\n },\n actions: [\n ({event}) => [\n forward(event),\n effect(() => {\n sendBack({type: 'dismiss'})\n }),\n ],\n ],\n }),\n })\n}\n\nexport const emojiPickerMachine = setup({\n types: {\n context: {} as EmojiPickerContext,\n input: {} as {\n editor: Editor\n matchEmojis: MatchEmojis\n },\n events: {} as EmojiPickerEvent,\n },\n actors: {\n 'emoji insert listener': fromCallback(emojiInsertListener),\n 'submit listener': fromCallback(submitListenerCallback),\n 'arrow listener': fromCallback(arrowListenerCallback),\n 'trigger listener': fromCallback(triggerListenerCallback),\n 'escape listener': fromCallback(escapeListenerCallback),\n 'selection listener': fromCallback(selectionListenerCallback),\n 'text insertion listener': fromCallback(textInsertionListenerCallback),\n },\n actions: {\n 'set focus span': assign({\n focusSpan: ({context, event}) => {\n if (\n event.type !== 'custom.trigger found' &&\n event.type !== 'custom.keyword found'\n ) {\n return context.focusSpan\n }\n\n return event.focusSpan\n },\n }),\n 'update focus span': assign({\n focusSpan: ({context}) => {\n if (!context.focusSpan) {\n return undefined\n }\n\n const snapshot = context.editor.getSnapshot()\n const focusSpan = getFocusSpan(snapshot)\n\n if (!snapshot.context.selection) {\n return undefined\n }\n\n if (!focusSpan) {\n return undefined\n }\n\n const nextSpan = getNextSpan({\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: {\n anchor: {\n path: context.focusSpan.path,\n offset: 0,\n },\n focus: {\n path: context.focusSpan.path,\n offset: 0,\n },\n },\n },\n })\n\n if (!isEqualPaths(focusSpan.path, context.focusSpan.path)) {\n if (\n nextSpan &&\n context.focusSpan.textAfter.length === 0 &&\n snapshot.context.selection.focus.offset === 0 &&\n isSelectionCollapsed(snapshot.context.selection)\n ) {\n // This is an edge case where the caret is moved from the end of\n // the focus span to the start of the next span.\n return context.focusSpan\n }\n\n return undefined\n }\n\n if (!focusSpan.node.text.startsWith(context.focusSpan.textBefore)) {\n return undefined\n }\n\n if (!focusSpan.node.text.endsWith(context.focusSpan.textAfter)) {\n return undefined\n }\n\n const keywordAnchor = {\n path: focusSpan.path,\n offset: context.focusSpan.textBefore.length,\n }\n const keywordFocus = {\n path: focusSpan.path,\n offset:\n focusSpan.node.text.length - context.focusSpan.textAfter.length,\n }\n\n const selectionIsBeforeKeyword =\n isPointAfterSelection(keywordAnchor)(snapshot)\n\n const selectionIsAfterKeyword =\n isPointBeforeSelection(keywordFocus)(snapshot)\n\n if (selectionIsBeforeKeyword || selectionIsAfterKeyword) {\n return undefined\n }\n\n return {\n node: focusSpan.node,\n path: focusSpan.path,\n textBefore: context.focusSpan.textBefore,\n textAfter: context.focusSpan.textAfter,\n }\n },\n }),\n 'update keyword': assign({\n keyword: ({context}) => {\n if (!context.focusSpan) {\n return ''\n }\n\n if (\n context.focusSpan.textBefore.length > 0 &&\n context.focusSpan.textAfter.length > 0\n ) {\n return context.focusSpan.node.text.slice(\n context.focusSpan.textBefore.length,\n -context.focusSpan.textAfter.length,\n )\n }\n\n if (context.focusSpan.textBefore.length > 0) {\n return context.focusSpan.node.text.slice(\n context.focusSpan.textBefore.length,\n )\n }\n\n if (context.focusSpan.textAfter.length > 0) {\n return context.focusSpan.node.text.slice(\n 0,\n -context.focusSpan.textAfter.length,\n )\n }\n\n return context.focusSpan.node.text\n },\n }),\n 'update matches': assign({\n matches: ({context}) => {\n // Strip leading colon\n let rawKeyword = context.keyword.startsWith(':')\n ? context.keyword.slice(1)\n : context.keyword\n // Strip trailing colon\n rawKeyword =\n rawKeyword.length > 1 && rawKeyword.endsWith(':')\n ? rawKeyword.slice(0, -1)\n : rawKeyword\n\n if (rawKeyword === undefined) {\n return []\n }\n\n return context.matchEmojis({keyword: rawKeyword})\n },\n }),\n 'reset selected index': assign({\n selectedIndex: 0,\n }),\n 'increment selected index': assign({\n selectedIndex: ({context}) => {\n if (context.selectedIndex === context.matches.length - 1) {\n return 0\n }\n return context.selectedIndex + 1\n },\n }),\n 'decrement selected index': assign({\n selectedIndex: ({context}) => {\n if (context.selectedIndex === 0) {\n return context.matches.length - 1\n }\n return context.selectedIndex - 1\n },\n }),\n 'set selected index': assign({\n selectedIndex: ({event}) => {\n assertEvent(event, 'navigate to')\n\n return event.index\n },\n }),\n 'update submit listener context': sendTo(\n 'submit listener',\n ({context}) => ({\n type: 'context changed',\n context,\n }),\n ),\n 'update text insertion listener context': sendTo(\n 'text insertion listener',\n ({context}) => ({\n type: 'context changed',\n context,\n }),\n ),\n 'insert selected match': ({context}) => {\n const match = context.matches[context.selectedIndex]\n\n if (!match || !context.focusSpan) {\n return\n }\n\n context.editor.send({\n type: 'custom.insert emoji',\n emoji: match.emoji,\n focusSpan: context.focusSpan,\n })\n },\n 'reset': assign({\n focusSpan: undefined,\n keyword: '',\n matches: [],\n selectedIndex: 0,\n }),\n },\n guards: {\n 'no focus span': ({context}) => {\n return !context.focusSpan\n },\n 'has matches': ({context}) => {\n return context.matches.length > 0\n },\n 'no matches': not('has matches'),\n 'keyword is malformed': ({context}) => {\n return !context.incompleteKeywordRegex.test(context.keyword)\n },\n 'keyword is direct match': ({context}) => {\n const fullKeywordRegex = /^:[\\S]+:$/\n\n if (!fullKeywordRegex.test(context.keyword)) {\n return false\n }\n\n const match = context.matches.at(context.selectedIndex)\n\n if (!match || match.type !== 'exact') {\n return false\n }\n\n return true\n },\n },\n}).createMachine({\n id: 'emoji picker',\n context: ({input}) => ({\n editor: input.editor,\n keyword: '',\n focusSpan: undefined,\n matchEmojis: input.matchEmojis,\n incompleteKeywordRegex: /^:[\\S]*$/,\n matches: [],\n selectedIndex: 0,\n }),\n initial: 'idle',\n invoke: [\n {\n src: 'emoji insert listener',\n id: 'emoji insert listener',\n input: ({context}) => ({context}),\n },\n ],\n states: {\n idle: {\n entry: ['reset'],\n invoke: {\n src: 'trigger listener',\n input: ({context}) => ({editor: context.editor}),\n },\n on: {\n 'custom.trigger found': {\n target: 'searching',\n actions: ['set focus span', 'update keyword'],\n },\n 'custom.keyword found': {\n actions: [\n 'set focus span',\n 'update keyword',\n 'update matches',\n 'insert selected match',\n ],\n target: 'idle',\n reenter: true,\n },\n },\n },\n searching: {\n invoke: [\n {\n src: 'submit listener',\n id: 'submit listener',\n input: ({context}) => ({context}),\n },\n {\n src: 'escape listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'selection listener',\n input: ({context}) => ({editor: context.editor}),\n },\n {\n src: 'text insertion listener',\n id: 'text insertion listener',\n input: ({context}) => ({context}),\n },\n ],\n on: {\n 'dismiss': {\n target: 'idle',\n },\n 'selection changed': [\n {\n actions: [\n 'update focus span',\n 'update keyword',\n 'update matches',\n 'reset selected index',\n 'update submit listener context',\n 'update text insertion listener context',\n ],\n },\n ],\n },\n always: [\n {\n guard: 'no focus span',\n target: 'idle',\n },\n {\n guard: 'keyword is malformed',\n target: 'idle',\n },\n {\n guard: 'keyword is direct match',\n actions: ['insert selected match'],\n target: 'idle',\n },\n ],\n initial: 'no matches showing',\n states: {\n 'no matches showing': {\n entry: ['reset selected index'],\n always: {\n guard: 'has matches',\n target: 'showing matches',\n },\n },\n 'showing matches': {\n invoke: {\n src: 'arrow listener',\n input: ({context}) => ({editor: context.editor}),\n },\n always: [\n {\n guard: 'no matches',\n target: 'no matches showing',\n },\n ],\n on: {\n 'navigate down': {\n actions: [\n 'increment selected index',\n 'update submit listener context',\n ],\n },\n 'navigate up': {\n actions: [\n 'decrement selected index',\n 'update submit listener context',\n ],\n },\n 'navigate to': {\n actions: ['set selected index', 'update submit listener context'],\n },\n 'insert selected match': {\n actions: ['insert selected match'],\n },\n },\n },\n },\n },\n },\n})\n","import {useEditor} from '@portabletext/editor'\nimport {useActorRef, useSelector} from '@xstate/react'\nimport {useCallback} from 'react'\nimport {emojiPickerMachine} from './emoji-picker-machine'\nimport type {BaseEmojiMatch, MatchEmojis} from './match-emojis'\n\n/**\n * @beta\n */\nexport type EmojiPicker<TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch> = {\n /**\n * The matched keyword.\n *\n * Can be used to display the keyword in the UI or conditionally render the\n * list of matches.\n *\n * @example\n * ```tsx\n * if (keyword.length < 1) {\n * return null\n * }\n * ```\n */\n keyword: string\n\n /**\n * Emoji matches found for the current keyword.\n *\n * Can be used to display the matches in a list.\n */\n matches: ReadonlyArray<TEmojiMatch>\n\n /**\n * The index of the selected match.\n *\n * Can be used to highlight the selected match in the list.\n *\n * @example\n * ```tsx\n * <EmojiListItem\n * key={match.key}\n * match={match}\n * selected={selectedIndex === index}\n * />\n * ```\n */\n selectedIndex: number\n\n /**\n * Navigate to a specific match by index.\n *\n * Can be used to control the `selectedIndex`. For example, using\n * `onMouseEnter`.\n *\n * @example\n * ```tsx\n * <EmojiListItem\n * key={match.key}\n * match={match}\n * selected={selectedIndex === index}\n * onMouseEnter={() => {onNavigateTo(index)}}\n * />\n * ```\n */\n onNavigateTo: (index: number) => void\n\n /**\n * Select the current match.\n *\n * Can be used to insert the currently selected match.\n *\n *\n * @example\n * ```tsx\n * <EmojiListItem\n * key={match.key}\n * match={match}\n * selected={selectedIndex === index}\n * onMouseEnter={() => {onNavigateTo(index)}}\n * onSelect={() => {onSelect()}}\n * />\n * ```\n *\n * Note: The currently selected match is automatically inserted on Enter or\n * Tab.\n */\n onSelect: () => void\n\n /**\n * Dismiss the emoji picker. Can be used to let the user dismiss the picker\n * by clicking a button.\n *\n * @example\n * ```tsx\n * {matches.length === 0 ? (\n * <Button onPress={onDismiss}>Dismiss</Button>\n * ) : <EmojiListBox {...props} />}\n * ```\n *\n * Note: The emoji picker is automatically dismissed on Escape.\n */\n onDismiss: () => void\n}\n\n/**\n * @beta\n */\nexport type EmojiPickerProps<\n TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch,\n> = {\n matchEmojis: MatchEmojis<TEmojiMatch>\n}\n\n/**\n * Handles the state and logic needed to create an emoji picker.\n *\n * The `matchEmojis` function is generic and can return any shape of emoji\n * match required for the emoji picker.\n *\n * However, the default implementation of `matchEmojis` returns an array of\n * `EmojiMatch` objects and can be created using the `createMatchEmojis`\n * function.\n *\n * @example\n *\n * ```tsx\n * const matchEmojis = createMatchEmojis({emojis: {\n * '😂': ['joy'],\n * '😹': ['joy_cat'],\n * }})\n *\n * const {keyword, matches, selectedIndex, onDismiss, onNavigateTo, onSelect} =\n * useEmojiPicker({matchEmojis})\n * ```\n *\n * Note: This hook is not concerned with the UI, how the emoji picker is\n * rendered or positioned in the document.\n *\n * @beta\n */\nexport function useEmojiPicker<\n TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch,\n>(props: EmojiPickerProps<TEmojiMatch>): EmojiPicker<TEmojiMatch> {\n const editor = useEditor()\n const emojiPickerActor = useActorRef(emojiPickerMachine, {\n input: {editor, matchEmojis: props.matchEmojis},\n })\n const keyword = useSelector(emojiPickerActor, (snapshot) => {\n const rawKeyword = snapshot.context.keyword.startsWith(':')\n ? snapshot.context.keyword.slice(1)\n : snapshot.context.keyword\n return rawKeyword.length > 1 && rawKeyword.endsWith(':')\n ? rawKeyword.slice(0, -1)\n : rawKeyword\n })\n const matches = useSelector(\n emojiPickerActor,\n (snapshot) => snapshot.context.matches as ReadonlyArray<TEmojiMatch>,\n )\n const selectedIndex = useSelector(\n emojiPickerActor,\n (snapshot) => snapshot.context.selectedIndex,\n )\n\n const onDismiss = useCallback(() => {\n emojiPickerActor.send({type: 'dismiss'})\n }, [emojiPickerActor])\n const onNavigateTo = useCallback(\n (index: number) => {\n emojiPickerActor.send({type: 'navigate to', index})\n },\n [emojiPickerActor],\n )\n const onSelect = useCallback(() => {\n emojiPickerActor.send({type: 'insert selected match'})\n editor.send({type: 'focus'})\n }, [emojiPickerActor, editor])\n\n return {\n keyword,\n matches,\n selectedIndex,\n onDismiss,\n onNavigateTo,\n onSelect,\n }\n}\n"],"names":["createMatchEmojis","config","keyword","foundEmojis","length","emoji","emojis","emojiKeywords","emojiKeyword","keywordIndex","indexOf","push","type","key","start","slice","end","startSlice","endSlice","arrowUpShortcut","createKeyboardShortcut","default","arrowDownShortcut","enterShortcut","tabShortcut","escapeShortcut","getTriggerState","snapshot","focusSpan","getFocusSpan","markState","getMarkState","context","selection","focusSpanTextBefore","node","text","focus","offset","focusSpanTextAfter","previousSpan","getPreviousSpan","nextSpan","getNextSpan","createTriggerActions","payload","keywordState","state","_key","_type","lastMatch","marks","path","textBefore","textAfter","raise","createKeywordFoundEvent","createTriggerFoundEvent","newSpan","keyGenerator","JSON","stringify","at","targetOffsets","child","triggerRule","defineInputRule","on","guard","event","matches","undefined","triggerState","actions","partialKeywordRule","anchor","keywordRule","triggerListenerCallback","sendBack","input","unregisterBehaviors","editor","registerBehavior","behavior","defineInputRuleBehavior","rules","defineBehavior","effect","unregister","escapeListenerCallback","originEvent","arrowListenerCallback","emojiInsertListener","submitListenerCallback","receive","match","selectedIndex","_","forward","selectionListenerCallback","unsubscribe","textInsertionListenerCallback","keywordAnchor","isEqualSelectionPoints","emojiPickerMachine","setup","types","events","actors","fromCallback","assign","getSnapshot","isEqualPaths","isSelectionCollapsed","startsWith","endsWith","keywordFocus","selectionIsBeforeKeyword","isPointAfterSelection","selectionIsAfterKeyword","isPointBeforeSelection","rawKeyword","matchEmojis","assertEvent","index","sendTo","insert selected match","send","guards","no focus span","has matches","not","keyword is malformed","incompleteKeywordRegex","test","keyword is direct match","createMachine","id","initial","invoke","src","states","idle","entry","target","reenter","searching","always","useEmojiPicker","props","$","_c","useEditor","t0","emojiPickerActor","useActorRef","useSelector","_temp","_temp2","_temp3","t1","onDismiss","t2","onNavigateTo","t3","onSelect","t4","snapshot_1","snapshot_0"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/plugin-emoji-picker",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.15",
|
|
4
4
|
"description": "Easily configure an Emoji Picker for the Portable Text Editor",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"portabletext",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@xstate/react": "^6.0.0",
|
|
34
34
|
"xstate": "^5.25.0",
|
|
35
35
|
"@portabletext/keyboard-shortcuts": "^2.1.2",
|
|
36
|
-
"@portabletext/plugin-input-rule": "^2.0.
|
|
36
|
+
"@portabletext/plugin-input-rule": "^2.0.15"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@sanity/pkg-utils": "^10.2.1",
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
"typescript": "5.9.3",
|
|
51
51
|
"typescript-eslint": "^8.48.0",
|
|
52
52
|
"vitest": "^4.0.16",
|
|
53
|
-
"@portabletext/editor": "4.
|
|
53
|
+
"@portabletext/editor": "4.3.0",
|
|
54
54
|
"@portabletext/schema": "2.1.1",
|
|
55
55
|
"racejar": "2.0.2"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@portabletext/editor": "^4.
|
|
58
|
+
"@portabletext/editor": "^4.3.0",
|
|
59
59
|
"react": "^19.2"
|
|
60
60
|
},
|
|
61
61
|
"engines": {
|