@baasix/lexical 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +281 -0
  2. package/dist/DateTimeComponent-4MX2IKXK.css +45 -0
  3. package/dist/DateTimeComponent-4MX2IKXK.css.map +1 -0
  4. package/dist/DateTimeComponent-7V5RW3AE.js +2928 -0
  5. package/dist/DateTimeComponent-7V5RW3AE.js.map +1 -0
  6. package/dist/EquationComponent-3IW3ONJD.js +159 -0
  7. package/dist/EquationComponent-3IW3ONJD.js.map +1 -0
  8. package/dist/EquationComponent-C2C6477P.css +28 -0
  9. package/dist/EquationComponent-C2C6477P.css.map +1 -0
  10. package/dist/ExcalidrawComponent-GZYLHNOY.js +267 -0
  11. package/dist/ExcalidrawComponent-GZYLHNOY.js.map +1 -0
  12. package/dist/ExcalidrawComponent-U6BD7DUB.css +152 -0
  13. package/dist/ExcalidrawComponent-U6BD7DUB.css.map +1 -0
  14. package/dist/ImageComponent-IYUGOT6O.css +73 -0
  15. package/dist/ImageComponent-IYUGOT6O.css.map +1 -0
  16. package/dist/ImageComponent-TTUYUG3M.js +429 -0
  17. package/dist/ImageComponent-TTUYUG3M.js.map +1 -0
  18. package/dist/PollComponent-CWI5UJF5.css +187 -0
  19. package/dist/PollComponent-CWI5UJF5.css.map +1 -0
  20. package/dist/PollComponent-KLJZSW5O.js +199 -0
  21. package/dist/PollComponent-KLJZSW5O.js.map +1 -0
  22. package/dist/StickyComponent-MZSTQF47.css +774 -0
  23. package/dist/StickyComponent-MZSTQF47.css.map +1 -0
  24. package/dist/StickyComponent-ZED6LNTX.js +233 -0
  25. package/dist/StickyComponent-ZED6LNTX.js.map +1 -0
  26. package/dist/chunk-35UCX4ZT.js +168 -0
  27. package/dist/chunk-35UCX4ZT.js.map +1 -0
  28. package/dist/chunk-44LUNGL3.js +16608 -0
  29. package/dist/chunk-44LUNGL3.js.map +1 -0
  30. package/dist/chunk-BHROZTZU.js +42 -0
  31. package/dist/chunk-BHROZTZU.js.map +1 -0
  32. package/dist/chunk-FJ6COZ4H.js +275 -0
  33. package/dist/chunk-FJ6COZ4H.js.map +1 -0
  34. package/dist/chunk-GSFNU3JE.js +211 -0
  35. package/dist/chunk-GSFNU3JE.js.map +1 -0
  36. package/dist/chunk-I43VQAHW.js +918 -0
  37. package/dist/chunk-I43VQAHW.js.map +1 -0
  38. package/dist/chunk-N22RKA5D.js +402 -0
  39. package/dist/chunk-N22RKA5D.js.map +1 -0
  40. package/dist/chunk-OIMMC5C3.js +134 -0
  41. package/dist/chunk-OIMMC5C3.js.map +1 -0
  42. package/dist/chunk-PZ5AY32C.js +10 -0
  43. package/dist/chunk-PZ5AY32C.js.map +1 -0
  44. package/dist/chunk-TVF6V3BJ.js +41 -0
  45. package/dist/chunk-TVF6V3BJ.js.map +1 -0
  46. package/dist/chunk-XTKVR2JI.js +225 -0
  47. package/dist/chunk-XTKVR2JI.js.map +1 -0
  48. package/dist/emoji-list-MUV74SND.js +8 -0
  49. package/dist/emoji-list-MUV74SND.js.map +1 -0
  50. package/dist/index.css +4234 -0
  51. package/dist/index.css.map +1 -0
  52. package/dist/index.d.ts +17 -0
  53. package/dist/index.js +16050 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/landscape-RJWVK6ET.jpg +0 -0
  56. package/dist/yellow-flower-R72KOP74.jpg +0 -0
  57. package/package.json +76 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context/SettingsContext.tsx","../src/plugins/EmojisPlugin/index.ts","../src/nodes/EmojiNode.tsx","../src/plugins/KeywordsPlugin/index.ts","../src/nodes/KeywordNode.ts","../src/plugins/LinkPlugin/index.tsx","../src/utils/url.ts","../src/plugins/MentionsPlugin/index.tsx","../src/context/EditorConfigContext.tsx","../src/nodes/MentionNode.ts","../src/plugins/TreeViewPlugin/index.tsx","../src/nodes/ImageNode.tsx"],"sourcesContent":["/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {JSX} from 'react';\r\n\r\nimport * as React from 'react';\r\nimport {\r\n createContext,\r\n ReactNode,\r\n useCallback,\r\n useContext,\r\n useMemo,\r\n useState,\r\n} from 'react';\r\n\r\nexport type SettingName =\r\n | 'isCollab'\r\n | 'useCollabV2'\r\n | 'isRichText'\r\n | 'emptyEditor'\r\n | 'isCharLimit'\r\n | 'isCharLimitUtf8'\r\n | 'isAutocomplete'\r\n | 'isMaxLength'\r\n | 'showTreeView'\r\n | 'showTableOfContents'\r\n | 'shouldUseLexicalContextMenu'\r\n | 'shouldPreserveNewLinesInMarkdown'\r\n | 'tableCellMerge'\r\n | 'tableCellBackgroundColor'\r\n | 'tableScrollShadow'\r\n | 'tableFitNestedTables'\r\n | 'tableHorizontalScroll'\r\n | 'hasLinkAttributes'\r\n | 'hasNestedTables'\r\n | 'hasFitNestedTables'\r\n | 'isCodeHighlighted'\r\n | 'isCodeShiki'\r\n | 'selectionAlwaysOnDisplay'\r\n | 'listStrictIndent'\r\n | 'shouldAllowHighlightingWithBrackets'\r\n | 'shouldDisableFocusOnClickChecklist';\r\n\r\nexport const DEFAULT_SETTINGS: Record<SettingName, boolean> = {\r\n isCollab: false,\r\n useCollabV2: false,\r\n isRichText: true,\r\n emptyEditor: false,\r\n isCharLimit: false,\r\n isCharLimitUtf8: false,\r\n isAutocomplete: false,\r\n isMaxLength: false,\r\n showTreeView: false,\r\n showTableOfContents: false,\r\n shouldUseLexicalContextMenu: false,\r\n shouldPreserveNewLinesInMarkdown: false,\r\n tableCellMerge: true,\r\n tableCellBackgroundColor: true,\r\n tableScrollShadow: true,\r\n tableFitNestedTables: true,\r\n tableHorizontalScroll: true,\r\n hasLinkAttributes: false,\r\n hasNestedTables: true,\r\n hasFitNestedTables: true,\r\n isCodeHighlighted: true,\r\n isCodeShiki: false,\r\n selectionAlwaysOnDisplay: false,\r\n listStrictIndent: false,\r\n shouldAllowHighlightingWithBrackets: false,\r\n shouldDisableFocusOnClickChecklist: false,\r\n};\r\n\r\nexport const INITIAL_SETTINGS: Record<SettingName, boolean> = {\r\n ...DEFAULT_SETTINGS,\r\n};\r\n\r\ntype SettingsContextShape = {\r\n setOption: (name: SettingName, value: boolean) => void;\r\n settings: Record<SettingName, boolean>;\r\n};\r\n\r\nconst Context: React.Context<SettingsContextShape> = createContext({\r\n setOption: (_name: SettingName, _value: boolean) => {\r\n return;\r\n },\r\n settings: INITIAL_SETTINGS,\r\n});\r\n\r\nexport const SettingsContext = ({\r\n children,\r\n}: {\r\n children: ReactNode;\r\n}): JSX.Element => {\r\n const [settings, setSettings] = useState(INITIAL_SETTINGS);\r\n\r\n const setOption = useCallback((setting: SettingName, value: boolean) => {\r\n setSettings((options: Record<SettingName, boolean>) => ({\r\n ...options,\r\n [setting]: value,\r\n }));\r\n }, []);\r\n\r\n const contextValue = useMemo(() => {\r\n return {setOption, settings};\r\n }, [setOption, settings]);\r\n\r\n return <Context.Provider value={contextValue}>{children}</Context.Provider>;\r\n};\r\n\r\nexport const useSettings = (): SettingsContextShape => {\r\n return useContext(Context);\r\n};\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {LexicalEditor} from 'lexical';\r\nimport type {JSX} from 'react';\r\n\r\nimport {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';\r\nimport {TextNode} from 'lexical';\r\nimport {useEffect} from 'react';\r\n\r\nimport {$createEmojiNode, EmojiNode} from '../../nodes/EmojiNode';\r\n\r\nconst emojis: Map<string, [string, string]> = new Map([\r\n [':)', ['emoji happysmile', '🙂']],\r\n [':D', ['emoji veryhappysmile', '😀']],\r\n [':(', ['emoji unhappysmile', '🙁']],\r\n ['<3', ['emoji heart', '❤']],\r\n]);\r\n\r\nfunction $findAndTransformEmoji(node: TextNode): null | TextNode {\r\n const text = node.getTextContent();\r\n\r\n for (let i = 0; i < text.length; i++) {\r\n const emojiData = emojis.get(text[i]) || emojis.get(text.slice(i, i + 2));\r\n\r\n if (emojiData !== undefined) {\r\n const [emojiStyle, emojiText] = emojiData;\r\n let targetNode;\r\n\r\n if (i === 0) {\r\n [targetNode] = node.splitText(i + 2);\r\n } else {\r\n [, targetNode] = node.splitText(i, i + 2);\r\n }\r\n\r\n const emojiNode = $createEmojiNode(emojiStyle, emojiText);\r\n targetNode.replace(emojiNode);\r\n return emojiNode;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction $textNodeTransform(node: TextNode): void {\r\n let targetNode: TextNode | null = node;\r\n\r\n while (targetNode !== null) {\r\n if (!targetNode.isSimpleText()) {\r\n return;\r\n }\r\n\r\n targetNode = $findAndTransformEmoji(targetNode);\r\n }\r\n}\r\n\r\nfunction useEmojis(editor: LexicalEditor): void {\r\n useEffect(() => {\r\n if (!editor.hasNodes([EmojiNode])) {\r\n throw new Error('EmojisPlugin: EmojiNode not registered on editor');\r\n }\r\n\r\n return editor.registerNodeTransform(TextNode, $textNodeTransform);\r\n }, [editor]);\r\n}\r\n\r\nexport default function EmojisPlugin(): JSX.Element | null {\r\n const [editor] = useLexicalComposerContext();\r\n useEmojis(editor);\r\n return null;\r\n}\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {\r\n EditorConfig,\r\n LexicalNode,\r\n NodeKey,\r\n SerializedTextNode,\r\n Spread,\r\n} from 'lexical';\r\n\r\nimport {$applyNodeReplacement, TextNode} from 'lexical';\r\n\r\nexport type SerializedEmojiNode = Spread<\r\n {\r\n className: string;\r\n },\r\n SerializedTextNode\r\n>;\r\n\r\nexport class EmojiNode extends TextNode {\r\n __className: string;\r\n\r\n static getType(): string {\r\n return 'emoji';\r\n }\r\n\r\n static clone(node: EmojiNode): EmojiNode {\r\n return new EmojiNode(node.__className, node.__text, node.__key);\r\n }\r\n\r\n constructor(className: string, text: string, key?: NodeKey) {\r\n super(text, key);\r\n this.__className = className;\r\n }\r\n\r\n createDOM(config: EditorConfig): HTMLElement {\r\n const dom = document.createElement('span');\r\n const inner = super.createDOM(config);\r\n dom.className = this.__className;\r\n inner.className = 'emoji-inner';\r\n dom.appendChild(inner);\r\n return dom;\r\n }\r\n\r\n updateDOM(prevNode: this, dom: HTMLElement, config: EditorConfig): boolean {\r\n const inner = dom.firstChild;\r\n if (inner === null) {\r\n return true;\r\n }\r\n super.updateDOM(prevNode, inner as HTMLElement, config);\r\n return false;\r\n }\r\n\r\n static importJSON(serializedNode: SerializedEmojiNode): EmojiNode {\r\n return $createEmojiNode(\r\n serializedNode.className,\r\n serializedNode.text,\r\n ).updateFromJSON(serializedNode);\r\n }\r\n\r\n exportJSON(): SerializedEmojiNode {\r\n return {\r\n ...super.exportJSON(),\r\n className: this.getClassName(),\r\n };\r\n }\r\n\r\n getClassName(): string {\r\n const self = this.getLatest();\r\n return self.__className;\r\n }\r\n}\r\n\r\nexport function $isEmojiNode(\r\n node: LexicalNode | null | undefined,\r\n): node is EmojiNode {\r\n return node instanceof EmojiNode;\r\n}\r\n\r\nexport function $createEmojiNode(\r\n className: string,\r\n emojiText: string,\r\n): EmojiNode {\r\n const node = new EmojiNode(className, emojiText).setMode('token');\r\n return $applyNodeReplacement(node);\r\n}\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {TextNode} from 'lexical';\r\nimport type {JSX} from 'react';\r\n\r\nimport {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';\r\nimport {useLexicalTextEntity} from '@lexical/react/useLexicalTextEntity';\r\nimport {useCallback, useEffect} from 'react';\r\n\r\nimport {$createKeywordNode, KeywordNode} from '../../nodes/KeywordNode';\r\n\r\nconst KEYWORDS_REGEX =\r\n /(^|$|[^A-Za-zªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԧԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠࢢ-ࢬऄ-हऽॐक़-ॡॱ-ॷॹ-ॿঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-ళవ-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤜᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎↃↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々〆〱-〵〻〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚗꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞓꞠ-Ɦꟸ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꪀ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ])(congrats|congratulations|gratuluju|gratuluji|gratulujeme|blahopřeju|blahopřeji|blahopřejeme|Til lykke|Tillykke|Glückwunsch|Gratuliere|felicitaciones|enhorabuena|paljon onnea|onnittelut|Félicitations|gratula|gratulálok|gratulálunk|congratulazioni|complimenti|おめでとう|おめでとうございます|축하해|축하해요|gratulerer|Gefeliciteerd|gratulacje|Parabéns|parabéns|felicitações|felicitări|мои поздравления|поздравляем|поздравляю|gratulujem|blahoželám|ยินดีด้วย|ขอแสดงความยินดี|tebrikler|tebrik ederim|恭喜|祝贺你|恭喜你|恭喜|恭喜|baie geluk|veels geluk|অভিনন্দন|Čestitam|Čestitke|Čestitamo|Συγχαρητήρια|Μπράβο|અભિનંદન|badhai|बधाई|अभिनंदन|Честитам|Свака част|hongera|வாழ்த்துகள்|வாழ்த்துக்கள்|అభినందనలు|അഭിനന്ദനങ്ങൾ|Chúc mừng|מזל טוב|mazel tov|mazal tov)(^|$|[^A-Za-zªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԧԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠࢢ-ࢬऄ-हऽॐक़-ॡॱ-ॷॹ-ॿঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-ళవ-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤜᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎↃↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々〆〱-〵〻〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚗꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞓꞠ-Ɦꟸ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꪀ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ])/i;\r\n\r\nexport default function KeywordsPlugin(): JSX.Element | null {\r\n const [editor] = useLexicalComposerContext();\r\n\r\n useEffect(() => {\r\n if (!editor.hasNodes([KeywordNode])) {\r\n throw new Error('KeywordsPlugin: KeywordNode not registered on editor');\r\n }\r\n }, [editor]);\r\n\r\n const $createKeywordNode_ = useCallback((textNode: TextNode): KeywordNode => {\r\n return $createKeywordNode(textNode.getTextContent());\r\n }, []);\r\n\r\n const getKeywordMatch = useCallback((text: string) => {\r\n const matchArr = KEYWORDS_REGEX.exec(text);\r\n\r\n if (matchArr === null) {\r\n return null;\r\n }\r\n\r\n const hashtagLength = matchArr[2].length;\r\n const startOffset = matchArr.index + matchArr[1].length;\r\n const endOffset = startOffset + hashtagLength;\r\n return {\r\n end: endOffset,\r\n start: startOffset,\r\n };\r\n }, []);\r\n\r\n useLexicalTextEntity<KeywordNode>(\r\n getKeywordMatch,\r\n KeywordNode,\r\n $createKeywordNode_,\r\n );\r\n\r\n return null;\r\n}\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {EditorConfig, LexicalNode, SerializedTextNode} from 'lexical';\r\n\r\nimport {$applyNodeReplacement, TextNode} from 'lexical';\r\n\r\nexport type SerializedKeywordNode = SerializedTextNode;\r\n\r\nexport class KeywordNode extends TextNode {\r\n static getType(): string {\r\n return 'keyword';\r\n }\r\n\r\n static clone(node: KeywordNode): KeywordNode {\r\n return new KeywordNode(node.__text, node.__key);\r\n }\r\n\r\n static importJSON(serializedNode: SerializedKeywordNode): KeywordNode {\r\n return $createKeywordNode().updateFromJSON(serializedNode);\r\n }\r\n\r\n createDOM(config: EditorConfig): HTMLElement {\r\n const dom = super.createDOM(config);\r\n dom.style.cursor = 'default';\r\n dom.className = 'keyword';\r\n return dom;\r\n }\r\n\r\n canInsertTextBefore(): boolean {\r\n return false;\r\n }\r\n\r\n canInsertTextAfter(): boolean {\r\n return false;\r\n }\r\n\r\n isTextEntity(): true {\r\n return true;\r\n }\r\n}\r\n\r\nexport function $createKeywordNode(keyword: string = ''): KeywordNode {\r\n return $applyNodeReplacement(new KeywordNode(keyword));\r\n}\r\n\r\nexport function $isKeywordNode(node: LexicalNode | null | undefined): boolean {\r\n return node instanceof KeywordNode;\r\n}\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {JSX} from 'react';\r\n\r\nimport {LinkPlugin as LexicalLinkPlugin} from '@lexical/react/LexicalLinkPlugin';\r\nimport * as React from 'react';\r\n\r\nimport {validateUrl} from '../../utils/url';\r\n\r\ntype Props = {\r\n hasLinkAttributes?: boolean;\r\n};\r\n\r\nexport default function LinkPlugin({\r\n hasLinkAttributes = false,\r\n}: Props): JSX.Element {\r\n return (\r\n <LexicalLinkPlugin\r\n validateUrl={validateUrl}\r\n attributes={\r\n hasLinkAttributes\r\n ? {\r\n rel: 'noopener noreferrer',\r\n target: '_blank',\r\n }\r\n : undefined\r\n }\r\n />\r\n );\r\n}\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nconst SUPPORTED_URL_PROTOCOLS = new Set([\r\n 'http:',\r\n 'https:',\r\n 'mailto:',\r\n 'sms:',\r\n 'tel:',\r\n]);\r\n\r\nexport function sanitizeUrl(url: string): string {\r\n try {\r\n const parsedUrl = new URL(url);\r\n // eslint-disable-next-line no-script-url\r\n if (!SUPPORTED_URL_PROTOCOLS.has(parsedUrl.protocol)) {\r\n return 'about:blank';\r\n }\r\n } catch {\r\n return url;\r\n }\r\n return url;\r\n}\r\n\r\n// Source: https://stackoverflow.com/a/8234912/2013580\r\nconst urlRegExp = new RegExp(\r\n /((([A-Za-z]{3,9}:(?:\\/\\/)?)(?:[-;:&=+$,\\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\\w]+@)[A-Za-z0-9.-]+)((?:\\/[+~%/.\\w-_]*)?\\??(?:[-+=&;%@.\\w_]*)#?(?:[\\w]*))?)/,\r\n);\r\nexport function validateUrl(url: string): boolean {\r\n // TODO Fix UI for link insertion; it should never default to an invalid URL such as https://.\r\n // Maybe show a dialog where they user can type the URL before inserting it.\r\n return url === 'https://' || urlRegExp.test(url);\r\n}\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {JSX} from 'react';\r\n\r\nimport {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';\r\nimport {\r\n LexicalTypeaheadMenuPlugin,\r\n MenuOption,\r\n MenuTextMatch,\r\n useBasicTypeaheadTriggerMatch,\r\n} from '@lexical/react/LexicalTypeaheadMenuPlugin';\r\nimport {TextNode} from 'lexical';\r\nimport {useCallback, useEffect, useMemo, useState} from 'react';\r\nimport * as React from 'react';\r\nimport * as ReactDOM from 'react-dom';\r\n\r\nimport type { Baasix } from '@baasix/sdk';\r\n\r\nimport {useEditorConfig} from '../../context/EditorConfigContext';\r\nimport {$createMentionNode} from '../../nodes/MentionNode';\r\n\r\nconst PUNCTUATION =\r\n '\\\\.,\\\\+\\\\*\\\\?\\\\$\\\\@\\\\|#{}\\\\(\\\\)\\\\^\\\\-\\\\[\\\\]\\\\\\\\/!%\\'\"~=<>_:;';\r\nconst NAME = '\\\\b[A-Z][^\\\\s' + PUNCTUATION + ']';\r\n\r\nconst DocumentMentionsRegex = {\r\n NAME,\r\n PUNCTUATION,\r\n};\r\n\r\nconst PUNC = DocumentMentionsRegex.PUNCTUATION;\r\n\r\nconst TRIGGERS = ['@'].join('');\r\n\r\n// Chars we expect to see in a mention (non-space, non-punctuation).\r\nconst VALID_CHARS = '[^' + TRIGGERS + PUNC + '\\\\s]';\r\n\r\n// Non-standard series of chars. Each series must be preceded and followed by\r\n// a valid char.\r\nconst VALID_JOINS =\r\n '(?:' +\r\n '\\\\.[ |$]|' + // E.g. \"r. \" in \"Mr. Smith\"\r\n ' |' + // E.g. \" \" in \"Josh Duck\"\r\n '[' +\r\n PUNC +\r\n ']|' + // E.g. \"-' in \"Salier-Hellendag\"\r\n ')';\r\n\r\nconst LENGTH_LIMIT = 75;\r\n\r\nconst AtSignMentionsRegex = new RegExp(\r\n '(^|\\\\s|\\\\()(' +\r\n '[' +\r\n TRIGGERS +\r\n ']' +\r\n '((?:' +\r\n VALID_CHARS +\r\n VALID_JOINS +\r\n '){0,' +\r\n LENGTH_LIMIT +\r\n '})' +\r\n ')$',\r\n);\r\n\r\n// 50 is the longest alias length limit.\r\nconst ALIAS_LENGTH_LIMIT = 50;\r\n\r\n// Regex used to match alias.\r\nconst AtSignMentionsRegexAliasRegex = new RegExp(\r\n '(^|\\\\s|\\\\()(' +\r\n '[' +\r\n TRIGGERS +\r\n ']' +\r\n '((?:' +\r\n VALID_CHARS +\r\n '){0,' +\r\n ALIAS_LENGTH_LIMIT +\r\n '})' +\r\n ')$',\r\n);\r\n\r\n// At most, 5 suggestions are shown in the popup.\r\nconst SUGGESTION_LIST_LENGTH_LIMIT = 5;\r\n\r\nconst mentionsCache = new Map<string, Array<string> | null>();\r\n\r\nasync function searchBaasixUsers(\r\n client: Baasix,\r\n query: string,\r\n): Promise<Array<string>> {\r\n if (!query || query.length < 1) return [];\r\n try {\r\n const response: any = await client\r\n .items('baasix_User')\r\n .find({search: query, fields: ['id', 'fullName'], limit: 10});\r\n return (response?.data || []).map(\r\n (user: any) => user.fullName || user.id,\r\n );\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nfunction useMentionLookupService(client: Baasix, mentionString: string | null) {\r\n const [results, setResults] = useState<Array<string>>([]);\r\n\r\n useEffect(() => {\r\n if (mentionString == null) {\r\n setResults([]);\r\n return;\r\n }\r\n\r\n const cachedResults = mentionsCache.get(mentionString);\r\n\r\n // null means a request is already in-flight\r\n if (cachedResults === null) {\r\n return;\r\n }\r\n if (cachedResults !== undefined) {\r\n setResults(cachedResults);\r\n return;\r\n }\r\n\r\n mentionsCache.set(mentionString, null);\r\n\r\n let cancelled = false;\r\n searchBaasixUsers(client, mentionString).then((newResults) => {\r\n mentionsCache.set(mentionString, newResults);\r\n if (!cancelled) {\r\n setResults(newResults);\r\n }\r\n });\r\n\r\n return () => {\r\n cancelled = true;\r\n };\r\n }, [mentionString]);\r\n\r\n return results;\r\n}\r\n\r\nfunction checkForAtSignMentions(\r\n text: string,\r\n minMatchLength: number,\r\n): MenuTextMatch | null {\r\n let match = AtSignMentionsRegex.exec(text);\r\n\r\n if (match === null) {\r\n match = AtSignMentionsRegexAliasRegex.exec(text);\r\n }\r\n if (match !== null) {\r\n // The strategy ignores leading whitespace but we need to know it's\r\n // length to add it to the leadOffset\r\n const maybeLeadingWhitespace = match[1];\r\n\r\n const matchingString = match[3];\r\n if (matchingString.length >= minMatchLength) {\r\n return {\r\n leadOffset: match.index + maybeLeadingWhitespace.length,\r\n matchingString,\r\n replaceableString: match[2],\r\n };\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction getPossibleQueryMatch(text: string): MenuTextMatch | null {\r\n return checkForAtSignMentions(text, 1);\r\n}\r\n\r\nclass MentionTypeaheadOption extends MenuOption {\r\n name: string;\r\n picture: JSX.Element;\r\n\r\n constructor(name: string, picture: JSX.Element) {\r\n super(name);\r\n this.name = name;\r\n this.picture = picture;\r\n }\r\n}\r\n\r\nfunction MentionsTypeaheadMenuItem({\r\n index,\r\n isSelected,\r\n onClick,\r\n onMouseEnter,\r\n option,\r\n}: {\r\n index: number;\r\n isSelected: boolean;\r\n onClick: () => void;\r\n onMouseEnter: () => void;\r\n option: MentionTypeaheadOption;\r\n}) {\r\n let className = 'item';\r\n if (isSelected) {\r\n className += ' selected';\r\n }\r\n return (\r\n <li\r\n key={option.key}\r\n tabIndex={-1}\r\n className={className}\r\n ref={option.setRefElement}\r\n role=\"option\"\r\n aria-selected={isSelected}\r\n id={'typeahead-item-' + index}\r\n onMouseEnter={onMouseEnter}\r\n onClick={onClick}>\r\n {option.picture}\r\n <span className=\"text\">{option.name}</span>\r\n </li>\r\n );\r\n}\r\n\r\nexport default function NewMentionsPlugin(): JSX.Element | null {\r\n const [editor] = useLexicalComposerContext();\r\n const { baasixClient } = useEditorConfig();\r\n\r\n const [queryString, setQueryString] = useState<string | null>(null);\r\n\r\n const results = useMentionLookupService(baasixClient, queryString);\r\n\r\n const checkForSlashTriggerMatch = useBasicTypeaheadTriggerMatch('/', {\r\n minLength: 0,\r\n });\r\n\r\n const options = useMemo(\r\n () =>\r\n results\r\n .map(\r\n (result) =>\r\n new MentionTypeaheadOption(result, <i className=\"icon user\" />),\r\n )\r\n .slice(0, SUGGESTION_LIST_LENGTH_LIMIT),\r\n [results],\r\n );\r\n\r\n const onSelectOption = useCallback(\r\n (\r\n selectedOption: MentionTypeaheadOption,\r\n nodeToReplace: TextNode | null,\r\n closeMenu: () => void,\r\n ) => {\r\n editor.update(() => {\r\n const mentionNode = $createMentionNode(selectedOption.name);\r\n if (nodeToReplace) {\r\n nodeToReplace.replace(mentionNode);\r\n }\r\n mentionNode.select();\r\n closeMenu();\r\n });\r\n },\r\n [editor],\r\n );\r\n\r\n const checkForMentionMatch = useCallback(\r\n (text: string) => {\r\n const slashMatch = checkForSlashTriggerMatch(text, editor);\r\n if (slashMatch !== null) {\r\n return null;\r\n }\r\n return getPossibleQueryMatch(text);\r\n },\r\n [checkForSlashTriggerMatch, editor],\r\n );\r\n\r\n return (\r\n <LexicalTypeaheadMenuPlugin<MentionTypeaheadOption>\r\n onQueryChange={setQueryString}\r\n onSelectOption={onSelectOption}\r\n triggerFn={checkForMentionMatch}\r\n options={options}\r\n menuRenderFn={(\r\n anchorElementRef,\r\n {selectedIndex, selectOptionAndCleanUp, setHighlightedIndex},\r\n ) =>\r\n anchorElementRef.current && results.length\r\n ? ReactDOM.createPortal(\r\n <div className=\"typeahead-popover mentions-menu\">\r\n <ul>\r\n {options.map((option, i: number) => (\r\n <MentionsTypeaheadMenuItem\r\n index={i}\r\n isSelected={selectedIndex === i}\r\n onClick={() => {\r\n setHighlightedIndex(i);\r\n selectOptionAndCleanUp(option);\r\n }}\r\n onMouseEnter={() => {\r\n setHighlightedIndex(i);\r\n }}\r\n key={option.key}\r\n option={option}\r\n />\r\n ))}\r\n </ul>\r\n </div>,\r\n anchorElementRef.current,\r\n )\r\n : null\r\n }\r\n />\r\n );\r\n}\r\n","import React, { createContext, useContext } from 'react';\nimport type { Baasix } from '@baasix/sdk';\n\nexport interface EditorConfig {\n baasixClient: Baasix;\n folder?: string;\n}\n\nconst EditorConfigContext = createContext<EditorConfig | null>(null);\n\nexport function EditorConfigProvider({\n baasixClient,\n folder,\n children,\n}: {\n baasixClient: Baasix;\n folder?: string;\n children: React.ReactNode;\n}) {\n return (\n <EditorConfigContext.Provider value={{ baasixClient, folder }}>\n {children}\n </EditorConfigContext.Provider>\n );\n}\n\nexport function useEditorConfig(): EditorConfig {\n const ctx = useContext(EditorConfigContext);\n if (!ctx) {\n throw new Error('useEditorConfig must be used within EditorConfigProvider');\n }\n return ctx;\n}\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport {\r\n $applyNodeReplacement,\r\n type DOMConversionMap,\r\n type DOMConversionOutput,\r\n type DOMExportOutput,\r\n type EditorConfig,\r\n type LexicalNode,\r\n type NodeKey,\r\n type SerializedTextNode,\r\n type Spread,\r\n TextNode,\r\n} from 'lexical';\r\n\r\nexport type SerializedMentionNode = Spread<\r\n {\r\n mentionName: string;\r\n },\r\n SerializedTextNode\r\n>;\r\n\r\nfunction $convertMentionElement(\r\n domNode: HTMLElement,\r\n): DOMConversionOutput | null {\r\n const textContent = domNode.textContent;\r\n const mentionName = domNode.getAttribute('data-lexical-mention-name');\r\n\r\n if (textContent !== null) {\r\n const node = $createMentionNode(\r\n typeof mentionName === 'string' ? mentionName : textContent,\r\n textContent,\r\n );\r\n return {\r\n node,\r\n };\r\n }\r\n\r\n return null;\r\n}\r\n\r\nconst mentionStyle = 'background-color: rgba(24, 119, 232, 0.2)';\r\nexport class MentionNode extends TextNode {\r\n __mention: string;\r\n\r\n static getType(): string {\r\n return 'mention';\r\n }\r\n\r\n static clone(node: MentionNode): MentionNode {\r\n return new MentionNode(node.__mention, node.__text, node.__key);\r\n }\r\n static importJSON(serializedNode: SerializedMentionNode): MentionNode {\r\n return $createMentionNode(serializedNode.mentionName).updateFromJSON(\r\n serializedNode,\r\n );\r\n }\r\n\r\n constructor(mentionName: string, text?: string, key?: NodeKey) {\r\n super(text ?? mentionName, key);\r\n this.__mention = mentionName;\r\n }\r\n\r\n exportJSON(): SerializedMentionNode {\r\n return {\r\n ...super.exportJSON(),\r\n mentionName: this.__mention,\r\n };\r\n }\r\n\r\n createDOM(config: EditorConfig): HTMLElement {\r\n const dom = super.createDOM(config);\r\n dom.style.cssText = mentionStyle;\r\n dom.className = 'mention';\r\n dom.spellcheck = false;\r\n\r\n return dom;\r\n }\r\n\r\n exportDOM(): DOMExportOutput {\r\n const element = document.createElement('span');\r\n element.setAttribute('data-lexical-mention', 'true');\r\n if (this.__text !== this.__mention) {\r\n element.setAttribute('data-lexical-mention-name', this.__mention);\r\n }\r\n element.textContent = this.__text;\r\n return {element};\r\n }\r\n\r\n static importDOM(): DOMConversionMap | null {\r\n return {\r\n span: (domNode: HTMLElement) => {\r\n if (!domNode.hasAttribute('data-lexical-mention')) {\r\n return null;\r\n }\r\n return {\r\n conversion: $convertMentionElement,\r\n priority: 1,\r\n };\r\n },\r\n };\r\n }\r\n\r\n isTextEntity(): true {\r\n return true;\r\n }\r\n\r\n canInsertTextBefore(): boolean {\r\n return false;\r\n }\r\n\r\n canInsertTextAfter(): boolean {\r\n return false;\r\n }\r\n}\r\n\r\nexport function $createMentionNode(\r\n mentionName: string,\r\n textContent?: string,\r\n): MentionNode {\r\n const mentionNode = new MentionNode(mentionName, (textContent = mentionName));\r\n mentionNode.setMode('segmented').toggleDirectionless();\r\n return $applyNodeReplacement(mentionNode);\r\n}\r\n\r\nexport function $isMentionNode(\r\n node: LexicalNode | null | undefined,\r\n): node is MentionNode {\r\n return node instanceof MentionNode;\r\n}\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {JSX} from 'react';\r\n\r\nimport {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';\r\nimport {TreeView} from '@lexical/react/LexicalTreeView';\r\nimport * as React from 'react';\r\n\r\nexport default function TreeViewPlugin(): JSX.Element {\r\n const [editor] = useLexicalComposerContext();\r\n return (\r\n <TreeView\r\n viewClassName=\"tree-view-output\"\r\n treeTypeButtonClassName=\"debug-treetype-button\"\r\n timeTravelPanelClassName=\"debug-timetravel-panel\"\r\n timeTravelButtonClassName=\"debug-timetravel-button\"\r\n timeTravelPanelSliderClassName=\"debug-timetravel-panel-slider\"\r\n timeTravelPanelButtonClassName=\"debug-timetravel-panel-button\"\r\n editor={editor}\r\n />\r\n );\r\n}\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {\r\n DOMConversionMap,\r\n DOMConversionOutput,\r\n DOMExportOutput,\r\n EditorConfig,\r\n LexicalEditor,\r\n LexicalNode,\r\n LexicalUpdateJSON,\r\n NodeKey,\r\n RangeSelection,\r\n SerializedEditor,\r\n SerializedLexicalNode,\r\n Spread,\r\n} from 'lexical';\r\nimport type {JSX} from 'react';\r\n\r\nimport {$insertGeneratedNodes} from '@lexical/clipboard';\r\nimport {HashtagNode} from '@lexical/hashtag';\r\nimport {$generateHtmlFromNodes, $generateNodesFromDOM} from '@lexical/html';\r\nimport {LinkNode} from '@lexical/link';\r\nimport {\r\n $applyNodeReplacement,\r\n $createRangeSelection,\r\n $extendCaretToRange,\r\n $getChildCaret,\r\n $getEditor,\r\n $getRoot,\r\n $isElementNode,\r\n $isParagraphNode,\r\n $selectAll,\r\n $setSelection,\r\n createEditor,\r\n DecoratorNode,\r\n LineBreakNode,\r\n ParagraphNode,\r\n RootNode,\r\n SKIP_DOM_SELECTION_TAG,\r\n TextNode,\r\n} from 'lexical';\r\nimport * as React from 'react';\r\n\r\nimport {EmojiNode} from './EmojiNode';\r\nimport {KeywordNode} from './KeywordNode';\r\n\r\nconst ImageComponent = React.lazy(() => import('./ImageComponent'));\r\n\r\nexport interface ImagePayload {\r\n altText: string;\r\n caption?: LexicalEditor;\r\n height?: number;\r\n key?: NodeKey;\r\n maxWidth?: number;\r\n showCaption?: boolean;\r\n src: string;\r\n width?: number;\r\n captionsEnabled?: boolean;\r\n}\r\n\r\nfunction isGoogleDocCheckboxImg(img: HTMLImageElement): boolean {\r\n return (\r\n img.parentElement != null &&\r\n img.parentElement.tagName === 'LI' &&\r\n img.previousSibling === null &&\r\n img.getAttribute('aria-roledescription') === 'checkbox'\r\n );\r\n}\r\n\r\nfunction $convertImageElement(domNode: Node): null | DOMConversionOutput {\r\n const img = domNode as HTMLImageElement;\r\n const src = img.getAttribute('src');\r\n if (!src || src.startsWith('file:///') || isGoogleDocCheckboxImg(img)) {\r\n return null;\r\n }\r\n const {alt: altText, width, height} = img;\r\n const node = $createImageNode({altText, height, src, width});\r\n return {node};\r\n}\r\n\r\nexport function $isCaptionEditorEmpty(): boolean {\r\n // Search the document for any non-element node\r\n // to determine if it's empty or not\r\n for (const {origin} of $extendCaretToRange(\r\n $getChildCaret($getRoot(), 'next'),\r\n )) {\r\n if (!$isElementNode(origin)) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\nexport type SerializedImageNode = Spread<\r\n {\r\n altText: string;\r\n caption: SerializedEditor;\r\n height?: number;\r\n maxWidth: number;\r\n showCaption: boolean;\r\n src: string;\r\n width?: number;\r\n },\r\n SerializedLexicalNode\r\n>;\r\n\r\nexport class ImageNode extends DecoratorNode<JSX.Element> {\r\n __src: string;\r\n __altText: string;\r\n __width: 'inherit' | number;\r\n __height: 'inherit' | number;\r\n __maxWidth: number;\r\n __showCaption: boolean;\r\n __caption: LexicalEditor;\r\n // Captions cannot yet be used within editor cells\r\n __captionsEnabled: boolean;\r\n\r\n static getType(): string {\r\n return 'image';\r\n }\r\n\r\n static clone(node: ImageNode): ImageNode {\r\n return new ImageNode(\r\n node.__src,\r\n node.__altText,\r\n node.__maxWidth,\r\n node.__width,\r\n node.__height,\r\n node.__showCaption,\r\n node.__caption,\r\n node.__captionsEnabled,\r\n node.__key,\r\n );\r\n }\r\n\r\n static importJSON(serializedNode: SerializedImageNode): ImageNode {\r\n const {altText, height, width, maxWidth, src, showCaption} = serializedNode;\r\n return $createImageNode({\r\n altText,\r\n height,\r\n maxWidth,\r\n showCaption,\r\n src,\r\n width,\r\n }).updateFromJSON(serializedNode);\r\n }\r\n\r\n updateFromJSON(serializedNode: LexicalUpdateJSON<SerializedImageNode>): this {\r\n const node = super.updateFromJSON(serializedNode);\r\n const {caption} = serializedNode;\r\n\r\n const nestedEditor = node.__caption;\r\n const editorState = nestedEditor.parseEditorState(caption.editorState);\r\n if (!editorState.isEmpty()) {\r\n nestedEditor.setEditorState(editorState);\r\n }\r\n return node;\r\n }\r\n\r\n exportDOM(): DOMExportOutput {\r\n const imgElement = document.createElement('img');\r\n imgElement.setAttribute('src', this.__src);\r\n imgElement.setAttribute('alt', this.__altText);\r\n imgElement.setAttribute('width', this.__width.toString());\r\n imgElement.setAttribute('height', this.__height.toString());\r\n\r\n if (this.__showCaption && this.__caption) {\r\n const captionEditor = this.__caption;\r\n const captionHtml = captionEditor.read(() => {\r\n if ($isCaptionEditorEmpty()) {\r\n return null;\r\n }\r\n // Don't serialize the wrapping paragraph if there is only one\r\n let selection: null | RangeSelection = null;\r\n const firstChild = $getRoot().getFirstChild();\r\n if (\r\n $isParagraphNode(firstChild) &&\r\n firstChild.getNextSibling() === null\r\n ) {\r\n selection = $createRangeSelection();\r\n selection.anchor.set(firstChild.getKey(), 0, 'element');\r\n selection.focus.set(\r\n firstChild.getKey(),\r\n firstChild.getChildrenSize(),\r\n 'element',\r\n );\r\n }\r\n return $generateHtmlFromNodes(captionEditor, selection);\r\n });\r\n if (captionHtml) {\r\n const figureElement = document.createElement('figure');\r\n const figcaptionElement = document.createElement('figcaption');\r\n figcaptionElement.innerHTML = captionHtml;\r\n\r\n figureElement.appendChild(imgElement);\r\n figureElement.appendChild(figcaptionElement);\r\n\r\n return {element: figureElement};\r\n }\r\n }\r\n\r\n return {element: imgElement};\r\n }\r\n\r\n static importDOM(): DOMConversionMap | null {\r\n return {\r\n figcaption: () => ({\r\n conversion: () => ({node: null}),\r\n priority: 0,\r\n }),\r\n figure: () => ({\r\n conversion: (node) => {\r\n return {\r\n after: (childNodes) => {\r\n const imageNodes = childNodes.filter($isImageNode);\r\n const figcaption = node.querySelector('figcaption');\r\n if (figcaption) {\r\n for (const imgNode of imageNodes) {\r\n imgNode.setShowCaption(true);\r\n imgNode.__caption.update(\r\n () => {\r\n const editor = $getEditor();\r\n $insertGeneratedNodes(\r\n editor,\r\n $generateNodesFromDOM(editor, figcaption),\r\n $selectAll(),\r\n );\r\n $setSelection(null);\r\n },\r\n {tag: SKIP_DOM_SELECTION_TAG},\r\n );\r\n }\r\n }\r\n return imageNodes;\r\n },\r\n node: null,\r\n };\r\n },\r\n priority: 0,\r\n }),\r\n img: () => ({\r\n conversion: $convertImageElement,\r\n priority: 0,\r\n }),\r\n };\r\n }\r\n\r\n constructor(\r\n src: string,\r\n altText: string,\r\n maxWidth: number,\r\n width?: 'inherit' | number,\r\n height?: 'inherit' | number,\r\n showCaption?: boolean,\r\n caption?: LexicalEditor,\r\n captionsEnabled?: boolean,\r\n key?: NodeKey,\r\n ) {\r\n super(key);\r\n this.__src = src;\r\n this.__altText = altText;\r\n this.__maxWidth = maxWidth;\r\n this.__width = width || 'inherit';\r\n this.__height = height || 'inherit';\r\n this.__showCaption = showCaption || false;\r\n this.__caption =\r\n caption ||\r\n createEditor({\r\n namespace: 'Playground/ImageNodeCaption',\r\n nodes: [\r\n RootNode,\r\n TextNode,\r\n LineBreakNode,\r\n ParagraphNode,\r\n LinkNode,\r\n EmojiNode,\r\n HashtagNode,\r\n KeywordNode,\r\n ],\r\n });\r\n this.__captionsEnabled = captionsEnabled || captionsEnabled === undefined;\r\n }\r\n\r\n exportJSON(): SerializedImageNode {\r\n return {\r\n ...super.exportJSON(),\r\n altText: this.getAltText(),\r\n caption: this.__caption.toJSON(),\r\n height: this.__height === 'inherit' ? 0 : this.__height,\r\n maxWidth: this.__maxWidth,\r\n showCaption: this.__showCaption,\r\n src: this.getSrc(),\r\n width: this.__width === 'inherit' ? 0 : this.__width,\r\n };\r\n }\r\n\r\n setWidthAndHeight(\r\n width: 'inherit' | number,\r\n height: 'inherit' | number,\r\n ): void {\r\n const writable = this.getWritable();\r\n writable.__width = width;\r\n writable.__height = height;\r\n }\r\n\r\n setShowCaption(showCaption: boolean): void {\r\n const writable = this.getWritable();\r\n writable.__showCaption = showCaption;\r\n }\r\n\r\n // View\r\n\r\n createDOM(config: EditorConfig): HTMLElement {\r\n const span = document.createElement('span');\r\n const theme = config.theme;\r\n const className = theme.image;\r\n if (className !== undefined) {\r\n span.className = className;\r\n }\r\n return span;\r\n }\r\n\r\n updateDOM(): false {\r\n return false;\r\n }\r\n\r\n getSrc(): string {\r\n return this.__src;\r\n }\r\n\r\n getAltText(): string {\r\n return this.__altText;\r\n }\r\n\r\n decorate(): JSX.Element {\r\n return (\r\n <ImageComponent\r\n src={this.__src}\r\n altText={this.__altText}\r\n width={this.__width}\r\n height={this.__height}\r\n maxWidth={this.__maxWidth}\r\n nodeKey={this.getKey()}\r\n showCaption={this.__showCaption}\r\n caption={this.__caption}\r\n captionsEnabled={this.__captionsEnabled}\r\n resizable={true}\r\n />\r\n );\r\n }\r\n}\r\n\r\nexport function $createImageNode({\r\n altText,\r\n height,\r\n maxWidth = 500,\r\n captionsEnabled,\r\n src,\r\n width,\r\n showCaption,\r\n caption,\r\n key,\r\n}: ImagePayload): ImageNode {\r\n return $applyNodeReplacement(\r\n new ImageNode(\r\n src,\r\n altText,\r\n maxWidth,\r\n width,\r\n height,\r\n showCaption,\r\n caption,\r\n captionsEnabled,\r\n key,\r\n ),\r\n );\r\n}\r\n\r\nexport function $isImageNode(\r\n node: LexicalNode | null | undefined,\r\n): node is ImageNode {\r\n return node instanceof ImageNode;\r\n}\r\n"],"mappings":"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","names":["TextNode","TextNode","useLexicalComposerContext","useCallback","useEffect","$applyNodeReplacement","TextNode","useLexicalComposerContext","useEffect","useCallback","jsx","useLexicalComposerContext","useCallback","useEffect","useMemo","useState","createContext","useContext","jsx","$applyNodeReplacement","TextNode","jsx","useState","useEffect","useLexicalComposerContext","useMemo","useCallback","useLexicalComposerContext","jsx","$applyNodeReplacement","TextNode","React","jsx","TextNode","$applyNodeReplacement"]}
@@ -0,0 +1,402 @@
1
+ import {
2
+ Button
3
+ } from "./chunk-TVF6V3BJ.js";
4
+
5
+ // src/ui/ExcalidrawModal.tsx
6
+ import { isDOMNode as isDOMNode2 } from "lexical";
7
+ import { lazy, Suspense, useEffect as useEffect2, useLayoutEffect, useRef as useRef2, useState } from "react";
8
+ import { createPortal as createPortal2 } from "react-dom";
9
+
10
+ // src/ui/Modal.tsx
11
+ import { isDOMNode } from "lexical";
12
+ import { useEffect, useRef } from "react";
13
+ import { createPortal } from "react-dom";
14
+ import { jsx, jsxs } from "react/jsx-runtime";
15
+ function PortalImpl({
16
+ onClose,
17
+ children,
18
+ title,
19
+ closeOnClickOutside
20
+ }) {
21
+ const modalRef = useRef(null);
22
+ useEffect(() => {
23
+ if (modalRef.current !== null) {
24
+ modalRef.current.focus();
25
+ }
26
+ }, []);
27
+ useEffect(() => {
28
+ let modalOverlayElement = null;
29
+ const handler = (event) => {
30
+ if (event.key === "Escape") {
31
+ onClose();
32
+ }
33
+ };
34
+ const clickOutsideHandler = (event) => {
35
+ const target = event.target;
36
+ if (modalRef.current !== null && isDOMNode(target) && !modalRef.current.contains(target) && closeOnClickOutside) {
37
+ onClose();
38
+ }
39
+ };
40
+ const modelElement = modalRef.current;
41
+ if (modelElement !== null) {
42
+ modalOverlayElement = modelElement.parentElement;
43
+ if (modalOverlayElement !== null) {
44
+ modalOverlayElement.addEventListener("click", clickOutsideHandler);
45
+ }
46
+ }
47
+ window.addEventListener("keydown", handler);
48
+ return () => {
49
+ window.removeEventListener("keydown", handler);
50
+ if (modalOverlayElement !== null) {
51
+ modalOverlayElement?.removeEventListener("click", clickOutsideHandler);
52
+ }
53
+ };
54
+ }, [closeOnClickOutside, onClose]);
55
+ return /* @__PURE__ */ jsx("div", { className: "Modal__overlay", role: "dialog", children: /* @__PURE__ */ jsxs("div", { className: "Modal__modal", tabIndex: -1, ref: modalRef, children: [
56
+ /* @__PURE__ */ jsx("h2", { className: "Modal__title", children: title }),
57
+ /* @__PURE__ */ jsx(
58
+ "button",
59
+ {
60
+ className: "Modal__closeButton",
61
+ "aria-label": "Close modal",
62
+ type: "button",
63
+ onClick: onClose,
64
+ children: "X"
65
+ }
66
+ ),
67
+ /* @__PURE__ */ jsx("div", { className: "Modal__content", children })
68
+ ] }) });
69
+ }
70
+ function Modal({
71
+ onClose,
72
+ children,
73
+ title,
74
+ closeOnClickOutside = false
75
+ }) {
76
+ return createPortal(
77
+ /* @__PURE__ */ jsx(
78
+ PortalImpl,
79
+ {
80
+ onClose,
81
+ title,
82
+ closeOnClickOutside,
83
+ children
84
+ }
85
+ ),
86
+ document.body
87
+ );
88
+ }
89
+
90
+ // src/ui/ExcalidrawModal.tsx
91
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
92
+ var ExcalidrawComponent = lazy(
93
+ () => import("@excalidraw/excalidraw").then((mod) => ({ default: mod.Excalidraw }))
94
+ );
95
+ function ExcalidrawModal({
96
+ closeOnClickOutside = false,
97
+ onSave,
98
+ initialElements,
99
+ initialAppState,
100
+ initialFiles,
101
+ isShown = false,
102
+ onDelete,
103
+ onClose
104
+ }) {
105
+ const excaliDrawModelRef = useRef2(null);
106
+ const [excalidrawAPI, setExcalidrawAPI] = useState(null);
107
+ const [discardModalOpen, setDiscardModalOpen] = useState(false);
108
+ const [elements, setElements] = useState(initialElements);
109
+ const [files, setFiles] = useState(initialFiles);
110
+ useEffect2(() => {
111
+ excaliDrawModelRef.current?.focus();
112
+ }, []);
113
+ useEffect2(() => {
114
+ const onWheel = (e) => {
115
+ e.stopPropagation();
116
+ };
117
+ const observer = new MutationObserver(() => {
118
+ const container = document.querySelector(".excalidraw-modal-container");
119
+ if (container && !container.hasAttribute("data-wheel-fixed")) {
120
+ container.setAttribute("data-wheel-fixed", "true");
121
+ container.addEventListener("wheel", onWheel, { passive: false });
122
+ }
123
+ });
124
+ observer.observe(document.body, { childList: true });
125
+ return () => {
126
+ observer.disconnect();
127
+ const container = document.querySelector(".excalidraw-modal-container");
128
+ if (container) {
129
+ container.removeEventListener("wheel", onWheel);
130
+ }
131
+ };
132
+ }, []);
133
+ useEffect2(() => {
134
+ let modalOverlayElement = null;
135
+ const clickOutsideHandler = (event) => {
136
+ const target = event.target;
137
+ if (excaliDrawModelRef.current !== null && isDOMNode2(target) && !excaliDrawModelRef.current.contains(target) && closeOnClickOutside) {
138
+ onDelete();
139
+ }
140
+ };
141
+ if (excaliDrawModelRef.current !== null) {
142
+ modalOverlayElement = excaliDrawModelRef.current?.parentElement;
143
+ modalOverlayElement?.addEventListener("click", clickOutsideHandler);
144
+ }
145
+ return () => {
146
+ modalOverlayElement?.removeEventListener("click", clickOutsideHandler);
147
+ };
148
+ }, [closeOnClickOutside, onDelete]);
149
+ useLayoutEffect(() => {
150
+ const currentModalRef = excaliDrawModelRef.current;
151
+ const onKeyDown = (event) => {
152
+ if (event.key === "Escape") {
153
+ onDelete();
154
+ }
155
+ };
156
+ currentModalRef?.addEventListener("keydown", onKeyDown);
157
+ return () => {
158
+ currentModalRef?.removeEventListener("keydown", onKeyDown);
159
+ };
160
+ }, [elements, files, onDelete]);
161
+ const save = () => {
162
+ if (elements?.some((el) => !el.isDeleted)) {
163
+ const appState = excalidrawAPI?.getAppState();
164
+ const partialState = {
165
+ exportBackground: appState?.exportBackground,
166
+ exportScale: appState?.exportScale,
167
+ exportWithDarkMode: appState?.theme === "dark",
168
+ isBindingEnabled: appState?.isBindingEnabled,
169
+ isLoading: appState?.isLoading,
170
+ name: appState?.name,
171
+ theme: appState?.theme,
172
+ viewBackgroundColor: appState?.viewBackgroundColor,
173
+ viewModeEnabled: appState?.viewModeEnabled,
174
+ zenModeEnabled: appState?.zenModeEnabled,
175
+ zoom: appState?.zoom
176
+ };
177
+ onSave(elements, partialState, files);
178
+ } else {
179
+ onDelete();
180
+ }
181
+ };
182
+ const discard = () => {
183
+ setDiscardModalOpen(true);
184
+ };
185
+ function ShowDiscardDialog() {
186
+ return /* @__PURE__ */ jsxs2(
187
+ Modal,
188
+ {
189
+ title: "Discard",
190
+ onClose: () => {
191
+ setDiscardModalOpen(false);
192
+ },
193
+ closeOnClickOutside: false,
194
+ children: [
195
+ "Are you sure you want to discard the changes?",
196
+ /* @__PURE__ */ jsxs2("div", { className: "ExcalidrawModal__discardModal", children: [
197
+ /* @__PURE__ */ jsx2(
198
+ Button,
199
+ {
200
+ onClick: () => {
201
+ setDiscardModalOpen(false);
202
+ onClose();
203
+ },
204
+ children: "Discard"
205
+ }
206
+ ),
207
+ " ",
208
+ /* @__PURE__ */ jsx2(
209
+ Button,
210
+ {
211
+ onClick: () => {
212
+ setDiscardModalOpen(false);
213
+ },
214
+ children: "Cancel"
215
+ }
216
+ )
217
+ ] })
218
+ ]
219
+ }
220
+ );
221
+ }
222
+ if (isShown === false) {
223
+ return null;
224
+ }
225
+ const onChange = (els, _, fls) => {
226
+ setElements(els);
227
+ setFiles(fls);
228
+ };
229
+ return createPortal2(
230
+ /* @__PURE__ */ jsx2("div", { className: "ExcalidrawModal__overlay", role: "dialog", children: /* @__PURE__ */ jsx2(
231
+ "div",
232
+ {
233
+ className: "ExcalidrawModal__modal",
234
+ ref: excaliDrawModelRef,
235
+ tabIndex: -1,
236
+ children: /* @__PURE__ */ jsxs2("div", { className: "ExcalidrawModal__row", children: [
237
+ discardModalOpen && /* @__PURE__ */ jsx2(ShowDiscardDialog, {}),
238
+ /* @__PURE__ */ jsx2(Suspense, { fallback: /* @__PURE__ */ jsx2("div", { style: { padding: 20 }, children: "Loading Excalidraw..." }), children: /* @__PURE__ */ jsx2(
239
+ ExcalidrawComponent,
240
+ {
241
+ onChange,
242
+ excalidrawAPI: setExcalidrawAPI,
243
+ initialData: {
244
+ appState: initialAppState || { isLoading: false },
245
+ elements: initialElements,
246
+ files: initialFiles
247
+ }
248
+ }
249
+ ) }),
250
+ /* @__PURE__ */ jsxs2("div", { className: "ExcalidrawModal__actions", children: [
251
+ /* @__PURE__ */ jsx2("button", { type: "button", className: "action-button", onClick: discard, children: "Discard" }),
252
+ /* @__PURE__ */ jsx2("button", { type: "button", className: "action-button", onClick: save, children: "Save" })
253
+ ] })
254
+ ] })
255
+ }
256
+ ) }),
257
+ document.body
258
+ );
259
+ }
260
+
261
+ // src/nodes/ExcalidrawNode/index.tsx
262
+ import { DecoratorNode } from "lexical";
263
+ import * as React from "react";
264
+ import { jsx as jsx3 } from "react/jsx-runtime";
265
+ var ExcalidrawComponent2 = React.lazy(() => import("./ExcalidrawComponent-GZYLHNOY.js"));
266
+ function $convertExcalidrawElement(domNode) {
267
+ const excalidrawData = domNode.getAttribute("data-lexical-excalidraw-json");
268
+ const styleAttributes = window.getComputedStyle(domNode);
269
+ const heightStr = styleAttributes.getPropertyValue("height");
270
+ const widthStr = styleAttributes.getPropertyValue("width");
271
+ const height = !heightStr || heightStr === "inherit" ? "inherit" : parseInt(heightStr, 10);
272
+ const width = !widthStr || widthStr === "inherit" ? "inherit" : parseInt(widthStr, 10);
273
+ if (excalidrawData) {
274
+ const node = $createExcalidrawNode(excalidrawData, width, height);
275
+ return {
276
+ node
277
+ };
278
+ }
279
+ return null;
280
+ }
281
+ var ExcalidrawNode = class _ExcalidrawNode extends DecoratorNode {
282
+ __data;
283
+ __width;
284
+ __height;
285
+ static getType() {
286
+ return "excalidraw";
287
+ }
288
+ static clone(node) {
289
+ return new _ExcalidrawNode(
290
+ node.__data,
291
+ node.__width,
292
+ node.__height,
293
+ node.__key
294
+ );
295
+ }
296
+ static importJSON(serializedNode) {
297
+ return new _ExcalidrawNode(
298
+ serializedNode.data,
299
+ serializedNode.width ?? "inherit",
300
+ serializedNode.height ?? "inherit"
301
+ ).updateFromJSON(serializedNode);
302
+ }
303
+ exportJSON() {
304
+ return {
305
+ ...super.exportJSON(),
306
+ data: this.__data,
307
+ height: this.__height === "inherit" ? void 0 : this.__height,
308
+ width: this.__width === "inherit" ? void 0 : this.__width
309
+ };
310
+ }
311
+ constructor(data = "[]", width = "inherit", height = "inherit", key) {
312
+ super(key);
313
+ this.__data = data;
314
+ this.__width = width;
315
+ this.__height = height;
316
+ }
317
+ // View
318
+ createDOM(config) {
319
+ const span = document.createElement("span");
320
+ const theme = config.theme;
321
+ const className = theme.image;
322
+ if (className !== void 0) {
323
+ span.className = className;
324
+ }
325
+ return span;
326
+ }
327
+ updateDOM() {
328
+ return false;
329
+ }
330
+ static importDOM() {
331
+ return {
332
+ span: (domNode) => {
333
+ if (!domNode.hasAttribute("data-lexical-excalidraw-json")) {
334
+ return null;
335
+ }
336
+ return {
337
+ conversion: $convertExcalidrawElement,
338
+ priority: 1
339
+ };
340
+ }
341
+ };
342
+ }
343
+ exportDOM(editor) {
344
+ const element = document.createElement("span");
345
+ element.style.display = "inline-block";
346
+ const content = editor.getElementByKey(this.getKey());
347
+ if (content !== null) {
348
+ const svg = content.querySelector("svg");
349
+ if (svg !== null) {
350
+ element.innerHTML = svg.outerHTML;
351
+ }
352
+ }
353
+ element.style.width = this.__width === "inherit" ? "inherit" : `${this.__width}px`;
354
+ element.style.height = this.__height === "inherit" ? "inherit" : `${this.__height}px`;
355
+ element.setAttribute("data-lexical-excalidraw-json", this.__data);
356
+ return { element };
357
+ }
358
+ setData(data) {
359
+ const self = this.getWritable();
360
+ self.__data = data;
361
+ }
362
+ getWidth() {
363
+ return this.getLatest().__width;
364
+ }
365
+ setWidth(width) {
366
+ const self = this.getWritable();
367
+ self.__width = width;
368
+ }
369
+ getHeight() {
370
+ return this.getLatest().__height;
371
+ }
372
+ setHeight(height) {
373
+ const self = this.getWritable();
374
+ self.__height = height;
375
+ }
376
+ decorate(editor, config) {
377
+ return /* @__PURE__ */ jsx3(
378
+ ExcalidrawComponent2,
379
+ {
380
+ nodeKey: this.getKey(),
381
+ data: this.__data,
382
+ width: this.__width,
383
+ height: this.__height
384
+ }
385
+ );
386
+ }
387
+ };
388
+ function $createExcalidrawNode(data = "[]", width = "inherit", height = "inherit") {
389
+ return new ExcalidrawNode(data, width, height);
390
+ }
391
+ function $isExcalidrawNode(node) {
392
+ return node instanceof ExcalidrawNode;
393
+ }
394
+
395
+ export {
396
+ Modal,
397
+ ExcalidrawModal,
398
+ ExcalidrawNode,
399
+ $createExcalidrawNode,
400
+ $isExcalidrawNode
401
+ };
402
+ //# sourceMappingURL=chunk-N22RKA5D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui/ExcalidrawModal.tsx","../src/ui/Modal.tsx","../src/nodes/ExcalidrawNode/index.tsx"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport type {\n AppState,\n BinaryFiles,\n ExcalidrawImperativeAPI,\n ExcalidrawInitialDataState,\n} from '@excalidraw/excalidraw/types';\nimport type {JSX} from 'react';\n\nimport './ExcalidrawModal.css';\n\nimport {isDOMNode} from 'lexical';\nimport * as React from 'react';\nimport {ReactPortal, lazy, Suspense, useEffect, useLayoutEffect, useRef, useState} from 'react';\nimport {createPortal} from 'react-dom';\n\nimport Button from './Button';\nimport Modal from './Modal';\n\nconst ExcalidrawComponent = lazy(() =>\n import('@excalidraw/excalidraw').then((mod) => ({default: mod.Excalidraw})),\n);\n\nexport type ExcalidrawInitialElements = ExcalidrawInitialDataState['elements'];\n\ntype Props = {\n closeOnClickOutside?: boolean;\n /**\n * The initial set of elements to draw into the scene\n */\n initialElements: ExcalidrawInitialElements;\n /**\n * The initial set of elements to draw into the scene\n */\n initialAppState: AppState;\n /**\n * The initial set of elements to draw into the scene\n */\n initialFiles: BinaryFiles;\n /**\n * Controls the visibility of the modal\n */\n isShown?: boolean;\n /**\n * Callback when closing and discarding the new changes\n */\n onClose: () => void;\n /**\n * Completely remove Excalidraw component\n */\n onDelete: () => void;\n /**\n * Callback when the save button is clicked\n */\n onSave: (\n elements: ExcalidrawInitialElements,\n appState: Partial<AppState>,\n files: BinaryFiles,\n ) => void;\n};\n\n/**\n * @explorer-desc\n * A component which renders a modal with Excalidraw (a painting app)\n * which can be used to export an editable image\n */\nexport default function ExcalidrawModal({\n closeOnClickOutside = false,\n onSave,\n initialElements,\n initialAppState,\n initialFiles,\n isShown = false,\n onDelete,\n onClose,\n}: Props): ReactPortal | null {\n const excaliDrawModelRef = useRef<HTMLDivElement | null>(null);\n const [excalidrawAPI, setExcalidrawAPI] =\n useState<ExcalidrawImperativeAPI | null>(null);\n const [discardModalOpen, setDiscardModalOpen] = useState(false);\n const [elements, setElements] =\n useState<ExcalidrawInitialElements>(initialElements);\n const [files, setFiles] = useState<BinaryFiles>(initialFiles);\n\n useEffect(() => {\n excaliDrawModelRef.current?.focus();\n }, []);\n\n // Excalidraw registers a document-level wheel handler that calls preventDefault(),\n // which blocks scrolling inside its own modal dialogs (Help, etc.).\n // Watch for the modal container and stop wheel propagation so scroll works.\n useEffect(() => {\n const onWheel = (e: WheelEvent) => {\n e.stopPropagation();\n };\n\n const observer = new MutationObserver(() => {\n const container = document.querySelector('.excalidraw-modal-container');\n if (container && !container.hasAttribute('data-wheel-fixed')) {\n container.setAttribute('data-wheel-fixed', 'true');\n container.addEventListener('wheel', onWheel, {passive: false});\n }\n });\n\n observer.observe(document.body, {childList: true});\n\n return () => {\n observer.disconnect();\n const container = document.querySelector('.excalidraw-modal-container');\n if (container) {\n container.removeEventListener('wheel', onWheel);\n }\n };\n }, []);\n\n useEffect(() => {\n let modalOverlayElement: HTMLElement | null = null;\n\n const clickOutsideHandler = (event: MouseEvent) => {\n const target = event.target;\n if (\n excaliDrawModelRef.current !== null &&\n isDOMNode(target) &&\n !excaliDrawModelRef.current.contains(target) &&\n closeOnClickOutside\n ) {\n onDelete();\n }\n };\n\n if (excaliDrawModelRef.current !== null) {\n modalOverlayElement = excaliDrawModelRef.current?.parentElement;\n modalOverlayElement?.addEventListener('click', clickOutsideHandler);\n }\n\n return () => {\n modalOverlayElement?.removeEventListener('click', clickOutsideHandler);\n };\n }, [closeOnClickOutside, onDelete]);\n\n useLayoutEffect(() => {\n const currentModalRef = excaliDrawModelRef.current;\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onDelete();\n }\n };\n\n currentModalRef?.addEventListener('keydown', onKeyDown);\n\n return () => {\n currentModalRef?.removeEventListener('keydown', onKeyDown);\n };\n }, [elements, files, onDelete]);\n\n const save = () => {\n if (elements?.some((el: Record<string, unknown>) => !el.isDeleted)) {\n const appState = excalidrawAPI?.getAppState();\n // We only need a subset of the state\n const partialState: Partial<AppState> = {\n exportBackground: appState?.exportBackground,\n exportScale: appState?.exportScale,\n exportWithDarkMode: appState?.theme === 'dark',\n isBindingEnabled: appState?.isBindingEnabled,\n isLoading: appState?.isLoading,\n name: appState?.name,\n theme: appState?.theme,\n viewBackgroundColor: appState?.viewBackgroundColor,\n viewModeEnabled: appState?.viewModeEnabled,\n zenModeEnabled: appState?.zenModeEnabled,\n zoom: appState?.zoom,\n };\n onSave(elements, partialState, files);\n } else {\n // delete node if the scene is clear\n onDelete();\n }\n };\n\n const discard = () => {\n setDiscardModalOpen(true);\n };\n\n function ShowDiscardDialog(): JSX.Element {\n return (\n <Modal\n title=\"Discard\"\n onClose={() => {\n setDiscardModalOpen(false);\n }}\n closeOnClickOutside={false}>\n Are you sure you want to discard the changes?\n <div className=\"ExcalidrawModal__discardModal\">\n <Button\n onClick={() => {\n setDiscardModalOpen(false);\n onClose();\n }}>\n Discard\n </Button>{' '}\n <Button\n onClick={() => {\n setDiscardModalOpen(false);\n }}>\n Cancel\n </Button>\n </div>\n </Modal>\n );\n }\n\n if (isShown === false) {\n return null;\n }\n\n const onChange = (\n els: ExcalidrawInitialElements,\n _: AppState,\n fls: BinaryFiles,\n ) => {\n setElements(els);\n setFiles(fls);\n };\n\n return createPortal(\n <div className=\"ExcalidrawModal__overlay\" role=\"dialog\">\n <div\n className=\"ExcalidrawModal__modal\"\n ref={excaliDrawModelRef}\n tabIndex={-1}>\n <div className=\"ExcalidrawModal__row\">\n {discardModalOpen && <ShowDiscardDialog />}\n <Suspense fallback={<div style={{padding: 20}}>Loading Excalidraw...</div>}>\n <ExcalidrawComponent\n onChange={onChange}\n excalidrawAPI={setExcalidrawAPI}\n initialData={{\n appState: initialAppState || {isLoading: false},\n elements: initialElements,\n files: initialFiles,\n }}\n />\n </Suspense>\n <div className=\"ExcalidrawModal__actions\">\n <button type=\"button\" className=\"action-button\" onClick={discard}>\n Discard\n </button>\n <button type=\"button\" className=\"action-button\" onClick={save}>\n Save\n </button>\n </div>\n </div>\n </div>\n </div>,\n document.body,\n );\n}\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {JSX} from 'react';\r\n\r\nimport './Modal.css';\r\n\r\nimport {isDOMNode} from 'lexical';\r\nimport * as React from 'react';\r\nimport {ReactNode, useEffect, useRef} from 'react';\r\nimport {createPortal} from 'react-dom';\r\n\r\nfunction PortalImpl({\r\n onClose,\r\n children,\r\n title,\r\n closeOnClickOutside,\r\n}: {\r\n children: ReactNode;\r\n closeOnClickOutside: boolean;\r\n onClose: () => void;\r\n title: string;\r\n}) {\r\n const modalRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n if (modalRef.current !== null) {\r\n modalRef.current.focus();\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n let modalOverlayElement: HTMLElement | null = null;\r\n const handler = (event: KeyboardEvent) => {\r\n if (event.key === 'Escape') {\r\n onClose();\r\n }\r\n };\r\n const clickOutsideHandler = (event: MouseEvent) => {\r\n const target = event.target;\r\n if (\r\n modalRef.current !== null &&\r\n isDOMNode(target) &&\r\n !modalRef.current.contains(target) &&\r\n closeOnClickOutside\r\n ) {\r\n onClose();\r\n }\r\n };\r\n const modelElement = modalRef.current;\r\n if (modelElement !== null) {\r\n modalOverlayElement = modelElement.parentElement;\r\n if (modalOverlayElement !== null) {\r\n modalOverlayElement.addEventListener('click', clickOutsideHandler);\r\n }\r\n }\r\n\r\n window.addEventListener('keydown', handler);\r\n\r\n return () => {\r\n window.removeEventListener('keydown', handler);\r\n if (modalOverlayElement !== null) {\r\n modalOverlayElement?.removeEventListener('click', clickOutsideHandler);\r\n }\r\n };\r\n }, [closeOnClickOutside, onClose]);\r\n\r\n return (\r\n <div className=\"Modal__overlay\" role=\"dialog\">\r\n <div className=\"Modal__modal\" tabIndex={-1} ref={modalRef}>\r\n <h2 className=\"Modal__title\">{title}</h2>\r\n <button\r\n className=\"Modal__closeButton\"\r\n aria-label=\"Close modal\"\r\n type=\"button\"\r\n onClick={onClose}>\r\n X\r\n </button>\r\n <div className=\"Modal__content\">{children}</div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport default function Modal({\r\n onClose,\r\n children,\r\n title,\r\n closeOnClickOutside = false,\r\n}: {\r\n children: ReactNode;\r\n closeOnClickOutside?: boolean;\r\n onClose: () => void;\r\n title: string;\r\n}): JSX.Element {\r\n return createPortal(\r\n <PortalImpl\r\n onClose={onClose}\r\n title={title}\r\n closeOnClickOutside={closeOnClickOutside}>\r\n {children}\r\n </PortalImpl>,\r\n document.body,\r\n );\r\n}\r\n","/**\r\n * Copyright (c) Meta Platforms, Inc. and affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n *\r\n */\r\n\r\nimport type {\r\n DOMConversionMap,\r\n DOMConversionOutput,\r\n DOMExportOutput,\r\n EditorConfig,\r\n LexicalEditor,\r\n LexicalNode,\r\n NodeKey,\r\n SerializedLexicalNode,\r\n Spread,\r\n} from 'lexical';\r\nimport type {JSX} from 'react';\r\n\r\nimport {DecoratorNode} from 'lexical';\r\nimport * as React from 'react';\r\n\r\ntype Dimension = number | 'inherit';\r\n\r\nconst ExcalidrawComponent = React.lazy(() => import('./ExcalidrawComponent'));\r\n\r\nexport type SerializedExcalidrawNode = Spread<\r\n {\r\n data: string;\r\n width?: Dimension;\r\n height?: Dimension;\r\n },\r\n SerializedLexicalNode\r\n>;\r\n\r\nfunction $convertExcalidrawElement(\r\n domNode: HTMLElement,\r\n): DOMConversionOutput | null {\r\n const excalidrawData = domNode.getAttribute('data-lexical-excalidraw-json');\r\n const styleAttributes = window.getComputedStyle(domNode);\r\n const heightStr = styleAttributes.getPropertyValue('height');\r\n const widthStr = styleAttributes.getPropertyValue('width');\r\n const height =\r\n !heightStr || heightStr === 'inherit' ? 'inherit' : parseInt(heightStr, 10);\r\n const width =\r\n !widthStr || widthStr === 'inherit' ? 'inherit' : parseInt(widthStr, 10);\r\n\r\n if (excalidrawData) {\r\n const node = $createExcalidrawNode(excalidrawData, width, height);\r\n return {\r\n node,\r\n };\r\n }\r\n return null;\r\n}\r\n\r\nexport class ExcalidrawNode extends DecoratorNode<JSX.Element> {\r\n __data: string;\r\n __width: Dimension;\r\n __height: Dimension;\r\n\r\n static getType(): string {\r\n return 'excalidraw';\r\n }\r\n\r\n static clone(node: ExcalidrawNode): ExcalidrawNode {\r\n return new ExcalidrawNode(\r\n node.__data,\r\n node.__width,\r\n node.__height,\r\n node.__key,\r\n );\r\n }\r\n\r\n static importJSON(serializedNode: SerializedExcalidrawNode): ExcalidrawNode {\r\n return new ExcalidrawNode(\r\n serializedNode.data,\r\n serializedNode.width ?? 'inherit',\r\n serializedNode.height ?? 'inherit',\r\n ).updateFromJSON(serializedNode);\r\n }\r\n\r\n exportJSON(): SerializedExcalidrawNode {\r\n return {\r\n ...super.exportJSON(),\r\n data: this.__data,\r\n height: this.__height === 'inherit' ? undefined : this.__height,\r\n width: this.__width === 'inherit' ? undefined : this.__width,\r\n };\r\n }\r\n\r\n constructor(\r\n data = '[]',\r\n width: Dimension = 'inherit',\r\n height: Dimension = 'inherit',\r\n key?: NodeKey,\r\n ) {\r\n super(key);\r\n this.__data = data;\r\n this.__width = width;\r\n this.__height = height;\r\n }\r\n\r\n // View\r\n createDOM(config: EditorConfig): HTMLElement {\r\n const span = document.createElement('span');\r\n const theme = config.theme;\r\n const className = theme.image;\r\n if (className !== undefined) {\r\n span.className = className;\r\n }\r\n return span;\r\n }\r\n\r\n updateDOM(): false {\r\n return false;\r\n }\r\n\r\n static importDOM(): DOMConversionMap<HTMLSpanElement> | null {\r\n return {\r\n span: (domNode: HTMLSpanElement) => {\r\n if (!domNode.hasAttribute('data-lexical-excalidraw-json')) {\r\n return null;\r\n }\r\n return {\r\n conversion: $convertExcalidrawElement,\r\n priority: 1,\r\n };\r\n },\r\n };\r\n }\r\n\r\n exportDOM(editor: LexicalEditor): DOMExportOutput {\r\n const element = document.createElement('span');\r\n\r\n element.style.display = 'inline-block';\r\n\r\n const content = editor.getElementByKey(this.getKey());\r\n if (content !== null) {\r\n const svg = content.querySelector('svg');\r\n if (svg !== null) {\r\n element.innerHTML = svg.outerHTML;\r\n }\r\n }\r\n\r\n element.style.width =\r\n this.__width === 'inherit' ? 'inherit' : `${this.__width}px`;\r\n element.style.height =\r\n this.__height === 'inherit' ? 'inherit' : `${this.__height}px`;\r\n\r\n element.setAttribute('data-lexical-excalidraw-json', this.__data);\r\n return {element};\r\n }\r\n\r\n setData(data: string): void {\r\n const self = this.getWritable();\r\n self.__data = data;\r\n }\r\n\r\n getWidth(): Dimension {\r\n return this.getLatest().__width;\r\n }\r\n\r\n setWidth(width: Dimension): void {\r\n const self = this.getWritable();\r\n self.__width = width;\r\n }\r\n\r\n getHeight(): Dimension {\r\n return this.getLatest().__height;\r\n }\r\n\r\n setHeight(height: Dimension): void {\r\n const self = this.getWritable();\r\n self.__height = height;\r\n }\r\n\r\n decorate(editor: LexicalEditor, config: EditorConfig): JSX.Element {\r\n return (\r\n <ExcalidrawComponent\r\n nodeKey={this.getKey()}\r\n data={this.__data}\r\n width={this.__width}\r\n height={this.__height}\r\n />\r\n );\r\n }\r\n}\r\n\r\nexport function $createExcalidrawNode(\r\n data: string = '[]',\r\n width: Dimension = 'inherit',\r\n height: Dimension = 'inherit',\r\n): ExcalidrawNode {\r\n return new ExcalidrawNode(data, width, height);\r\n}\r\n\r\nexport function $isExcalidrawNode(\r\n node: LexicalNode | null | undefined,\r\n): node is ExcalidrawNode {\r\n return node instanceof ExcalidrawNode;\r\n}\r\n"],"mappings":"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","names":["isDOMNode","useEffect","useRef","createPortal","jsx","jsxs","useRef","useEffect","isDOMNode","createPortal","jsx","ExcalidrawComponent"]}