@payloadcms/richtext-lexical 3.0.0-beta.32 → 3.0.0-beta.34

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 (52) hide show
  1. package/dist/field/features/blocks/plugin/index.js +3 -2
  2. package/dist/field/features/blocks/plugin/index.js.map +1 -1
  3. package/dist/field/features/debug/testRecorder/plugin/index.js +1 -1
  4. package/dist/field/features/debug/testRecorder/plugin/index.js.map +1 -1
  5. package/dist/field/features/heading/feature.client.js +3 -3
  6. package/dist/field/features/heading/feature.client.js.map +1 -1
  7. package/dist/field/features/horizontalRule/component/index.js +3 -3
  8. package/dist/field/features/horizontalRule/component/index.js.map +1 -1
  9. package/dist/field/features/horizontalRule/nodes/HorizontalRuleNode.js +2 -2
  10. package/dist/field/features/horizontalRule/nodes/HorizontalRuleNode.js.map +1 -1
  11. package/dist/field/features/link/nodes/LinkNode.d.ts +3 -1
  12. package/dist/field/features/link/nodes/LinkNode.d.ts.map +1 -1
  13. package/dist/field/features/link/nodes/LinkNode.js +4 -3
  14. package/dist/field/features/link/nodes/LinkNode.js.map +1 -1
  15. package/dist/field/features/link/plugins/autoLink/index.d.ts.map +1 -1
  16. package/dist/field/features/link/plugins/autoLink/index.js +6 -4
  17. package/dist/field/features/link/plugins/autoLink/index.js.map +1 -1
  18. package/dist/field/features/link/plugins/floatingLinkEditor/LinkEditor/index.js +10 -10
  19. package/dist/field/features/link/plugins/floatingLinkEditor/LinkEditor/index.js.map +1 -1
  20. package/dist/field/features/relationship/nodes/RelationshipNode.js +2 -2
  21. package/dist/field/features/relationship/nodes/RelationshipNode.js.map +1 -1
  22. package/dist/field/features/relationship/nodes/components/RelationshipComponent.js +3 -3
  23. package/dist/field/features/relationship/nodes/components/RelationshipComponent.js.map +1 -1
  24. package/dist/field/features/relationship/plugins/index.js +3 -2
  25. package/dist/field/features/relationship/plugins/index.js.map +1 -1
  26. package/dist/field/features/toolbars/fixed/Toolbar/index.scss +9 -2
  27. package/dist/field/features/toolbars/fixed/feature.client.js +1 -1
  28. package/dist/field/features/toolbars/fixed/feature.client.js.map +1 -1
  29. package/dist/field/features/toolbars/inline/Toolbar/index.js +7 -7
  30. package/dist/field/features/toolbars/inline/Toolbar/index.js.map +1 -1
  31. package/dist/field/features/types.d.ts +16 -0
  32. package/dist/field/features/types.d.ts.map +1 -1
  33. package/dist/field/features/types.js.map +1 -1
  34. package/dist/field/features/upload/component/index.d.ts.map +1 -1
  35. package/dist/field/features/upload/component/index.js +3 -3
  36. package/dist/field/features/upload/component/index.js.map +1 -1
  37. package/dist/field/features/upload/nodes/UploadNode.js +2 -2
  38. package/dist/field/features/upload/nodes/UploadNode.js.map +1 -1
  39. package/dist/field/features/upload/plugin/index.js +9 -8
  40. package/dist/field/features/upload/plugin/index.js.map +1 -1
  41. package/dist/field/features/upload/validate.js +1 -1
  42. package/dist/field/features/upload/validate.js.map +1 -1
  43. package/dist/field/index.scss +3 -7
  44. package/dist/field/lexical/LexicalEditor.d.ts.map +1 -1
  45. package/dist/field/lexical/LexicalEditor.js +18 -0
  46. package/dist/field/lexical/LexicalEditor.js.map +1 -1
  47. package/dist/field/lexical/LexicalEditor.scss +1 -1
  48. package/dist/field/lexical/LexicalProvider.d.ts.map +1 -1
  49. package/dist/field/lexical/LexicalProvider.js +1 -3
  50. package/dist/field/lexical/LexicalProvider.js.map +1 -1
  51. package/dist/field/lexical/ui/ContentEditable.scss +5 -2
  52. package/package.json +35 -23
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/field/features/link/plugins/autoLink/index.tsx"],"sourcesContent":["'use client'\nimport type { ElementNode, LexicalEditor, LexicalNode } from 'lexical'\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'\nimport { mergeRegister } from '@lexical/utils'\nimport {\n $createTextNode,\n $getSelection,\n $isElementNode,\n $isLineBreakNode,\n $isNodeSelection,\n $isRangeSelection,\n $isTextNode,\n TextNode as TextNodeValue,\n} from 'lexical'\nimport { type TextNode } from 'lexical'\nimport { useEffect } from 'react'\n\nimport type { PluginComponent } from '../../../types.js'\nimport type { ClientProps } from '../../feature.client.js'\nimport type { LinkFields } from '../../nodes/types.js'\n\nimport { invariant } from '../../../../lexical/utils/invariant.js'\nimport { $createAutoLinkNode, $isAutoLinkNode, AutoLinkNode } from '../../nodes/AutoLinkNode.js'\nimport { $isLinkNode } from '../../nodes/LinkNode.js'\n\ntype ChangeHandler = (url: null | string, prevUrl: null | string) => void\n\ninterface LinkMatcherResult {\n fields?: LinkFields\n index: number\n length: number\n text: string\n url: string\n}\n\nexport type LinkMatcher = (text: string) => LinkMatcherResult | null\n\nexport function createLinkMatcherWithRegExp(\n regExp: RegExp,\n urlTransformer: (text: string) => string = (text) => text,\n) {\n return (text: string) => {\n const match = regExp.exec(text)\n if (match === null) return null\n return {\n index: match.index,\n length: match[0].length,\n text: match[0],\n url: urlTransformer(match[0]),\n }\n }\n}\n\nfunction findFirstMatch(text: string, matchers: LinkMatcher[]): LinkMatcherResult | null {\n for (let i = 0; i < matchers.length; i++) {\n const match = matchers[i](text)\n\n if (match != null) {\n return match\n }\n }\n\n return null\n}\n\nconst PUNCTUATION_OR_SPACE = /[.,;\\s]/\n\nfunction isSeparator(char: string): boolean {\n return PUNCTUATION_OR_SPACE.test(char)\n}\n\nfunction endsWithSeparator(textContent: string): boolean {\n return isSeparator(textContent[textContent.length - 1])\n}\n\nfunction startsWithSeparator(textContent: string): boolean {\n return isSeparator(textContent[0])\n}\n\nfunction isPreviousNodeValid(node: LexicalNode): boolean {\n let previousNode = node.getPreviousSibling()\n if ($isElementNode(previousNode)) {\n previousNode = previousNode.getLastDescendant()\n }\n return (\n previousNode === null ||\n $isLineBreakNode(previousNode) ||\n ($isTextNode(previousNode) && endsWithSeparator(previousNode.getTextContent()))\n )\n}\n\nfunction isNextNodeValid(node: LexicalNode): boolean {\n let nextNode = node.getNextSibling()\n if ($isElementNode(nextNode)) {\n nextNode = nextNode.getFirstDescendant()\n }\n return (\n nextNode === null ||\n $isLineBreakNode(nextNode) ||\n ($isTextNode(nextNode) && startsWithSeparator(nextNode.getTextContent()))\n )\n}\n\nfunction isContentAroundIsValid(\n matchStart: number,\n matchEnd: number,\n text: string,\n nodes: TextNode[],\n): boolean {\n const contentBeforeIsValid =\n matchStart > 0 ? isSeparator(text[matchStart - 1]) : isPreviousNodeValid(nodes[0])\n if (!contentBeforeIsValid) {\n return false\n }\n\n const contentAfterIsValid =\n matchEnd < text.length ? isSeparator(text[matchEnd]) : isNextNodeValid(nodes[nodes.length - 1])\n return contentAfterIsValid\n}\n\nfunction extractMatchingNodes(\n nodes: TextNode[],\n startIndex: number,\n endIndex: number,\n): [\n matchingOffset: number,\n unmodifiedBeforeNodes: TextNode[],\n matchingNodes: TextNode[],\n unmodifiedAfterNodes: TextNode[],\n] {\n const unmodifiedBeforeNodes: TextNode[] = []\n const matchingNodes: TextNode[] = []\n const unmodifiedAfterNodes: TextNode[] = []\n let matchingOffset = 0\n\n let currentOffset = 0\n const currentNodes = [...nodes]\n\n while (currentNodes.length > 0) {\n const currentNode = currentNodes[0]\n const currentNodeText = currentNode.getTextContent()\n const currentNodeLength = currentNodeText.length\n const currentNodeStart = currentOffset\n const currentNodeEnd = currentOffset + currentNodeLength\n\n if (currentNodeEnd <= startIndex) {\n unmodifiedBeforeNodes.push(currentNode)\n matchingOffset += currentNodeLength\n } else if (currentNodeStart >= endIndex) {\n unmodifiedAfterNodes.push(currentNode)\n } else {\n matchingNodes.push(currentNode)\n }\n currentOffset += currentNodeLength\n currentNodes.shift()\n }\n return [matchingOffset, unmodifiedBeforeNodes, matchingNodes, unmodifiedAfterNodes]\n}\n\nfunction createAutoLinkNode(\n nodes: TextNode[],\n startIndex: number,\n endIndex: number,\n match: LinkMatcherResult,\n): TextNode | undefined {\n const fields: LinkFields = {\n linkType: 'custom',\n url: match.url,\n ...match.fields,\n }\n\n const linkNode = $createAutoLinkNode({ fields })\n if (nodes.length === 1) {\n let remainingTextNode = nodes[0]\n let linkTextNode\n if (startIndex === 0) {\n ;[linkTextNode, remainingTextNode] = remainingTextNode.splitText(endIndex)\n } else {\n ;[, linkTextNode, remainingTextNode] = remainingTextNode.splitText(startIndex, endIndex)\n }\n const textNode = $createTextNode(match.text)\n textNode.setFormat(linkTextNode.getFormat())\n textNode.setDetail(linkTextNode.getDetail())\n linkNode.append(textNode)\n linkTextNode.replace(linkNode)\n return remainingTextNode\n } else if (nodes.length > 1) {\n const firstTextNode = nodes[0]\n let offset = firstTextNode.getTextContent().length\n let firstLinkTextNode\n if (startIndex === 0) {\n firstLinkTextNode = firstTextNode\n } else {\n ;[, firstLinkTextNode] = firstTextNode.splitText(startIndex)\n }\n const linkNodes = []\n let remainingTextNode\n for (let i = 1; i < nodes.length; i++) {\n const currentNode = nodes[i]\n const currentNodeText = currentNode.getTextContent()\n const currentNodeLength = currentNodeText.length\n const currentNodeStart = offset\n const currentNodeEnd = offset + currentNodeLength\n if (currentNodeStart < endIndex) {\n if (currentNodeEnd <= endIndex) {\n linkNodes.push(currentNode)\n } else {\n const [linkTextNode, endNode] = currentNode.splitText(endIndex - currentNodeStart)\n linkNodes.push(linkTextNode)\n remainingTextNode = endNode\n }\n }\n offset += currentNodeLength\n }\n const selection = $getSelection()\n const selectedTextNode = selection ? selection.getNodes().find($isTextNode) : undefined\n const textNode = $createTextNode(firstLinkTextNode.getTextContent())\n textNode.setFormat(firstLinkTextNode.getFormat())\n textNode.setDetail(firstLinkTextNode.getDetail())\n linkNode.append(textNode, ...linkNodes)\n // it does not preserve caret position if caret was at the first text node\n // so we need to restore caret position\n if (selectedTextNode && selectedTextNode === firstLinkTextNode) {\n if ($isRangeSelection(selection)) {\n textNode.select(selection.anchor.offset, selection.focus.offset)\n } else if ($isNodeSelection(selection)) {\n textNode.select(0, textNode.getTextContent().length)\n }\n }\n firstLinkTextNode.replace(linkNode)\n return remainingTextNode\n }\n return undefined\n}\n\nfunction handleLinkCreation(\n nodes: TextNode[],\n matchers: LinkMatcher[],\n onChange: ChangeHandler,\n): void {\n let currentNodes = [...nodes]\n const initialText = currentNodes.map((node) => node.getTextContent()).join('')\n let text = initialText\n\n let match\n let invalidMatchEnd = 0\n\n while ((match = findFirstMatch(text, matchers)) != null && match !== null) {\n const matchStart: number = match.index\n const matchLength: number = match.length\n const matchEnd = matchStart + matchLength\n const isValid = isContentAroundIsValid(\n invalidMatchEnd + matchStart,\n invalidMatchEnd + matchEnd,\n initialText,\n currentNodes,\n )\n\n if (isValid) {\n const [matchingOffset, , matchingNodes, unmodifiedAfterNodes] = extractMatchingNodes(\n currentNodes,\n invalidMatchEnd + matchStart,\n invalidMatchEnd + matchEnd,\n )\n\n const actualMatchStart = invalidMatchEnd + matchStart - matchingOffset\n const actualMatchEnd = invalidMatchEnd + matchEnd - matchingOffset\n const remainingTextNode = createAutoLinkNode(\n matchingNodes,\n actualMatchStart,\n actualMatchEnd,\n match,\n )\n currentNodes = remainingTextNode\n ? [remainingTextNode, ...unmodifiedAfterNodes]\n : unmodifiedAfterNodes\n onChange(match.url, null)\n invalidMatchEnd = 0\n } else {\n invalidMatchEnd += matchEnd\n }\n\n text = text.substring(matchEnd)\n }\n}\n\nfunction handleLinkEdit(\n linkNode: AutoLinkNode,\n matchers: LinkMatcher[],\n onChange: ChangeHandler,\n): void {\n // Check children are simple text\n const children = linkNode.getChildren()\n const childrenLength = children.length\n for (let i = 0; i < childrenLength; i++) {\n const child = children[i]\n if (!$isTextNode(child) || !child.isSimpleText()) {\n replaceWithChildren(linkNode)\n onChange(null, linkNode.getFields()?.url ?? null)\n return\n }\n }\n\n // Check text content fully matches\n const text = linkNode.getTextContent()\n const match = findFirstMatch(text, matchers)\n if (match === null || match.text !== text) {\n replaceWithChildren(linkNode)\n onChange(null, linkNode.getFields()?.url ?? null)\n return\n }\n\n // Check neighbors\n if (!isPreviousNodeValid(linkNode) || !isNextNodeValid(linkNode)) {\n replaceWithChildren(linkNode)\n onChange(null, linkNode.getFields()?.url ?? null)\n return\n }\n\n const url = linkNode.getFields()?.url\n if (url !== match?.url) {\n const flds = linkNode.getFields()\n flds.url = match?.url\n linkNode.setFields(flds)\n onChange(match.url, url ?? null)\n }\n}\n\n// Bad neighbors are edits in neighbor nodes that make AutoLinks incompatible.\n// Given the creation preconditions, these can only be simple text nodes.\nfunction handleBadNeighbors(\n textNode: TextNode,\n matchers: LinkMatcher[],\n onChange: ChangeHandler,\n): void {\n const previousSibling = textNode.getPreviousSibling()\n const nextSibling = textNode.getNextSibling()\n const text = textNode.getTextContent()\n\n if ($isAutoLinkNode(previousSibling) && !startsWithSeparator(text)) {\n previousSibling.append(textNode)\n handleLinkEdit(previousSibling, matchers, onChange)\n onChange(null, previousSibling.getFields()?.url ?? null)\n }\n\n if ($isAutoLinkNode(nextSibling) && !endsWithSeparator(text)) {\n replaceWithChildren(nextSibling)\n handleLinkEdit(nextSibling, matchers, onChange)\n onChange(null, nextSibling.getFields()?.url ?? null)\n }\n}\n\nfunction replaceWithChildren(node: ElementNode): LexicalNode[] {\n const children = node.getChildren()\n const childrenLength = children.length\n\n for (let j = childrenLength - 1; j >= 0; j--) {\n node.insertAfter(children[j])\n }\n\n node.remove()\n return children.map((child) => child.getLatest())\n}\n\nfunction getTextNodesToMatch(textNode: TextNode): TextNode[] {\n // check if next siblings are simple text nodes till a node contains a space separator\n const textNodesToMatch = [textNode]\n let nextSibling = textNode.getNextSibling()\n while (nextSibling !== null && $isTextNode(nextSibling) && nextSibling.isSimpleText()) {\n textNodesToMatch.push(nextSibling)\n if (/\\s/.test(nextSibling.getTextContent())) {\n break\n }\n nextSibling = nextSibling.getNextSibling()\n }\n return textNodesToMatch\n}\n\nfunction useAutoLink(\n editor: LexicalEditor,\n matchers: LinkMatcher[],\n onChange?: ChangeHandler,\n): void {\n useEffect(() => {\n if (!editor.hasNodes([AutoLinkNode])) {\n invariant(false, 'LexicalAutoLinkPlugin: AutoLinkNode not registered on editor')\n }\n\n const onChangeWrapped = (url: null | string, prevUrl: null | string): void => {\n if (onChange != null) {\n onChange(url, prevUrl)\n }\n }\n\n return mergeRegister(\n editor.registerNodeTransform(TextNodeValue, (textNode: TextNode) => {\n const parent = textNode.getParentOrThrow()\n const previous = textNode.getPreviousSibling()\n if ($isAutoLinkNode(parent)) {\n handleLinkEdit(parent, matchers, onChangeWrapped)\n } else if (!$isLinkNode(parent)) {\n if (\n textNode.isSimpleText() &&\n (startsWithSeparator(textNode.getTextContent()) || !$isAutoLinkNode(previous))\n ) {\n const textNodesToMatch = getTextNodesToMatch(textNode)\n handleLinkCreation(textNodesToMatch, matchers, onChangeWrapped)\n }\n\n handleBadNeighbors(textNode, matchers, onChangeWrapped)\n }\n }),\n )\n }, [editor, matchers, onChange])\n}\n\nconst URL_REGEX =\n /((https?:\\/\\/(www\\.)?)|(www\\.))[-\\w@:%.+~#=]{1,256}\\.[a-zA-Z\\d()]{1,6}\\b([-\\w()@:%+.~#?&/=]*)/\n\nconst EMAIL_REGEX =\n /(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\])|(([a-z\\-\\d]+\\.)+[a-z]{2,}))/i\n\nconst MATCHERS = [\n createLinkMatcherWithRegExp(URL_REGEX, (text) => {\n return text.startsWith('http') ? text : `https://${text}`\n }),\n createLinkMatcherWithRegExp(EMAIL_REGEX, (text) => {\n return `mailto:${text}`\n }),\n]\n\nexport const AutoLinkPlugin: PluginComponent<ClientProps> = () => {\n const [editor] = useLexicalComposerContext()\n\n useAutoLink(editor, MATCHERS)\n\n return null\n}\n"],"names":["useLexicalComposerContext","mergeRegister","$createTextNode","$getSelection","$isElementNode","$isLineBreakNode","$isNodeSelection","$isRangeSelection","$isTextNode","TextNode","TextNodeValue","useEffect","invariant","$createAutoLinkNode","$isAutoLinkNode","AutoLinkNode","$isLinkNode","createLinkMatcherWithRegExp","regExp","urlTransformer","text","match","exec","index","length","url","findFirstMatch","matchers","i","PUNCTUATION_OR_SPACE","isSeparator","char","test","endsWithSeparator","textContent","startsWithSeparator","isPreviousNodeValid","node","previousNode","getPreviousSibling","getLastDescendant","getTextContent","isNextNodeValid","nextNode","getNextSibling","getFirstDescendant","isContentAroundIsValid","matchStart","matchEnd","nodes","contentBeforeIsValid","contentAfterIsValid","extractMatchingNodes","startIndex","endIndex","unmodifiedBeforeNodes","matchingNodes","unmodifiedAfterNodes","matchingOffset","currentOffset","currentNodes","currentNode","currentNodeText","currentNodeLength","currentNodeStart","currentNodeEnd","push","shift","createAutoLinkNode","fields","linkType","linkNode","remainingTextNode","linkTextNode","splitText","textNode","setFormat","getFormat","setDetail","getDetail","append","replace","firstTextNode","offset","firstLinkTextNode","linkNodes","endNode","selection","selectedTextNode","getNodes","find","undefined","select","anchor","focus","handleLinkCreation","onChange","initialText","map","join","invalidMatchEnd","matchLength","isValid","actualMatchStart","actualMatchEnd","substring","handleLinkEdit","children","getChildren","childrenLength","child","isSimpleText","replaceWithChildren","getFields","flds","setFields","handleBadNeighbors","previousSibling","nextSibling","j","insertAfter","remove","getLatest","getTextNodesToMatch","textNodesToMatch","useAutoLink","editor","hasNodes","onChangeWrapped","prevUrl","registerNodeTransform","parent","getParentOrThrow","previous","URL_REGEX","EMAIL_REGEX","MATCHERS","startsWith","AutoLinkPlugin"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../src/field/features/link/plugins/autoLink/index.tsx"],"sourcesContent":["'use client'\nimport type { ElementNode, LexicalEditor, LexicalNode } from 'lexical'\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'\nimport { mergeRegister } from '@lexical/utils'\nimport {\n $createTextNode,\n $getSelection,\n $isElementNode,\n $isLineBreakNode,\n $isNodeSelection,\n $isRangeSelection,\n $isTextNode,\n TextNode as TextNodeValue,\n} from 'lexical'\nimport { type TextNode } from 'lexical'\nimport { useEffect } from 'react'\n\nimport type { PluginComponent } from '../../../types.js'\nimport type { ClientProps } from '../../feature.client.js'\nimport type { LinkFields } from '../../nodes/types.js'\n\nimport { invariant } from '../../../../lexical/utils/invariant.js'\nimport { $createAutoLinkNode, $isAutoLinkNode, AutoLinkNode } from '../../nodes/AutoLinkNode.js'\nimport { $isLinkNode } from '../../nodes/LinkNode.js'\n\ntype ChangeHandler = (url: null | string, prevUrl: null | string) => void\n\ninterface LinkMatcherResult {\n fields?: LinkFields\n index: number\n length: number\n text: string\n url: string\n}\n\nexport type LinkMatcher = (text: string) => LinkMatcherResult | null\n\nexport function createLinkMatcherWithRegExp(\n regExp: RegExp,\n urlTransformer: (text: string) => string = (text) => text,\n) {\n return (text: string) => {\n const match = regExp.exec(text)\n if (match === null) return null\n return {\n index: match.index,\n length: match[0].length,\n text: match[0],\n url: urlTransformer(match[0]),\n }\n }\n}\n\nfunction findFirstMatch(text: string, matchers: LinkMatcher[]): LinkMatcherResult | null {\n for (let i = 0; i < matchers.length; i++) {\n const match = matchers[i](text)\n\n if (match != null) {\n return match\n }\n }\n\n return null\n}\n\nconst PUNCTUATION_OR_SPACE = /[.,;\\s]/\n\nfunction isSeparator(char: string): boolean {\n return PUNCTUATION_OR_SPACE.test(char)\n}\n\nfunction endsWithSeparator(textContent: string): boolean {\n return isSeparator(textContent[textContent.length - 1])\n}\n\nfunction startsWithSeparator(textContent: string): boolean {\n return isSeparator(textContent[0])\n}\n\nfunction isPreviousNodeValid(node: LexicalNode): boolean {\n let previousNode = node.getPreviousSibling()\n if ($isElementNode(previousNode)) {\n previousNode = previousNode.getLastDescendant()\n }\n return (\n previousNode === null ||\n $isLineBreakNode(previousNode) ||\n ($isTextNode(previousNode) && endsWithSeparator(previousNode.getTextContent()))\n )\n}\n\nfunction isNextNodeValid(node: LexicalNode): boolean {\n let nextNode = node.getNextSibling()\n if ($isElementNode(nextNode)) {\n nextNode = nextNode.getFirstDescendant()\n }\n return (\n nextNode === null ||\n $isLineBreakNode(nextNode) ||\n ($isTextNode(nextNode) && startsWithSeparator(nextNode.getTextContent()))\n )\n}\n\nfunction isContentAroundIsValid(\n matchStart: number,\n matchEnd: number,\n text: string,\n nodes: TextNode[],\n): boolean {\n const contentBeforeIsValid =\n matchStart > 0 ? isSeparator(text[matchStart - 1]) : isPreviousNodeValid(nodes[0])\n if (!contentBeforeIsValid) {\n return false\n }\n\n const contentAfterIsValid =\n matchEnd < text.length ? isSeparator(text[matchEnd]) : isNextNodeValid(nodes[nodes.length - 1])\n return contentAfterIsValid\n}\n\nfunction extractMatchingNodes(\n nodes: TextNode[],\n startIndex: number,\n endIndex: number,\n): [\n matchingOffset: number,\n unmodifiedBeforeNodes: TextNode[],\n matchingNodes: TextNode[],\n unmodifiedAfterNodes: TextNode[],\n] {\n const unmodifiedBeforeNodes: TextNode[] = []\n const matchingNodes: TextNode[] = []\n const unmodifiedAfterNodes: TextNode[] = []\n let matchingOffset = 0\n\n let currentOffset = 0\n const currentNodes = [...nodes]\n\n while (currentNodes.length > 0) {\n const currentNode = currentNodes[0]\n const currentNodeText = currentNode.getTextContent()\n const currentNodeLength = currentNodeText.length\n const currentNodeStart = currentOffset\n const currentNodeEnd = currentOffset + currentNodeLength\n\n if (currentNodeEnd <= startIndex) {\n unmodifiedBeforeNodes.push(currentNode)\n matchingOffset += currentNodeLength\n } else if (currentNodeStart >= endIndex) {\n unmodifiedAfterNodes.push(currentNode)\n } else {\n matchingNodes.push(currentNode)\n }\n currentOffset += currentNodeLength\n currentNodes.shift()\n }\n return [matchingOffset, unmodifiedBeforeNodes, matchingNodes, unmodifiedAfterNodes]\n}\n\nfunction $createAutoLinkNode_(\n nodes: TextNode[],\n startIndex: number,\n endIndex: number,\n match: LinkMatcherResult,\n): TextNode | undefined {\n const fields: LinkFields = {\n linkType: 'custom',\n url: match.url,\n ...match.fields,\n }\n\n const linkNode = $createAutoLinkNode({ fields })\n if (nodes.length === 1) {\n let remainingTextNode = nodes[0]\n let linkTextNode\n if (startIndex === 0) {\n ;[linkTextNode, remainingTextNode] = remainingTextNode.splitText(endIndex)\n } else {\n ;[, linkTextNode, remainingTextNode] = remainingTextNode.splitText(startIndex, endIndex)\n }\n const textNode = $createTextNode(match.text)\n textNode.setFormat(linkTextNode.getFormat())\n textNode.setDetail(linkTextNode.getDetail())\n textNode.setStyle(linkTextNode.getStyle())\n linkNode.append(textNode)\n linkTextNode.replace(linkNode)\n return remainingTextNode\n } else if (nodes.length > 1) {\n const firstTextNode = nodes[0]\n let offset = firstTextNode.getTextContent().length\n let firstLinkTextNode\n if (startIndex === 0) {\n firstLinkTextNode = firstTextNode\n } else {\n ;[, firstLinkTextNode] = firstTextNode.splitText(startIndex)\n }\n const linkNodes = []\n let remainingTextNode\n for (let i = 1; i < nodes.length; i++) {\n const currentNode = nodes[i]\n const currentNodeText = currentNode.getTextContent()\n const currentNodeLength = currentNodeText.length\n const currentNodeStart = offset\n const currentNodeEnd = offset + currentNodeLength\n if (currentNodeStart < endIndex) {\n if (currentNodeEnd <= endIndex) {\n linkNodes.push(currentNode)\n } else {\n const [linkTextNode, endNode] = currentNode.splitText(endIndex - currentNodeStart)\n linkNodes.push(linkTextNode)\n remainingTextNode = endNode\n }\n }\n offset += currentNodeLength\n }\n const selection = $getSelection()\n const selectedTextNode = selection ? selection.getNodes().find($isTextNode) : undefined\n const textNode = $createTextNode(firstLinkTextNode.getTextContent())\n textNode.setFormat(firstLinkTextNode.getFormat())\n textNode.setDetail(firstLinkTextNode.getDetail())\n textNode.setStyle(firstLinkTextNode.getStyle())\n linkNode.append(textNode, ...linkNodes)\n // it does not preserve caret position if caret was at the first text node\n // so we need to restore caret position\n if (selectedTextNode && selectedTextNode === firstLinkTextNode) {\n if ($isRangeSelection(selection)) {\n textNode.select(selection.anchor.offset, selection.focus.offset)\n } else if ($isNodeSelection(selection)) {\n textNode.select(0, textNode.getTextContent().length)\n }\n }\n firstLinkTextNode.replace(linkNode)\n return remainingTextNode\n }\n return undefined\n}\n\nfunction $handleLinkCreation(\n nodes: TextNode[],\n matchers: LinkMatcher[],\n onChange: ChangeHandler,\n): void {\n let currentNodes = [...nodes]\n const initialText = currentNodes.map((node) => node.getTextContent()).join('')\n let text = initialText\n\n let match\n let invalidMatchEnd = 0\n\n while ((match = findFirstMatch(text, matchers)) != null && match !== null) {\n const matchStart: number = match.index\n const matchLength: number = match.length\n const matchEnd = matchStart + matchLength\n const isValid = isContentAroundIsValid(\n invalidMatchEnd + matchStart,\n invalidMatchEnd + matchEnd,\n initialText,\n currentNodes,\n )\n\n if (isValid) {\n const [matchingOffset, , matchingNodes, unmodifiedAfterNodes] = extractMatchingNodes(\n currentNodes,\n invalidMatchEnd + matchStart,\n invalidMatchEnd + matchEnd,\n )\n\n const actualMatchStart = invalidMatchEnd + matchStart - matchingOffset\n const actualMatchEnd = invalidMatchEnd + matchEnd - matchingOffset\n const remainingTextNode = $createAutoLinkNode_(\n matchingNodes,\n actualMatchStart,\n actualMatchEnd,\n match,\n )\n currentNodes = remainingTextNode\n ? [remainingTextNode, ...unmodifiedAfterNodes]\n : unmodifiedAfterNodes\n onChange(match.url, null)\n invalidMatchEnd = 0\n } else {\n invalidMatchEnd += matchEnd\n }\n\n text = text.substring(matchEnd)\n }\n}\n\nfunction handleLinkEdit(\n linkNode: AutoLinkNode,\n matchers: LinkMatcher[],\n onChange: ChangeHandler,\n): void {\n // Check children are simple text\n const children = linkNode.getChildren()\n const childrenLength = children.length\n for (let i = 0; i < childrenLength; i++) {\n const child = children[i]\n if (!$isTextNode(child) || !child.isSimpleText()) {\n replaceWithChildren(linkNode)\n onChange(null, linkNode.getFields()?.url ?? null)\n return\n }\n }\n\n // Check text content fully matches\n const text = linkNode.getTextContent()\n const match = findFirstMatch(text, matchers)\n if (match === null || match.text !== text) {\n replaceWithChildren(linkNode)\n onChange(null, linkNode.getFields()?.url ?? null)\n return\n }\n\n // Check neighbors\n if (!isPreviousNodeValid(linkNode) || !isNextNodeValid(linkNode)) {\n replaceWithChildren(linkNode)\n onChange(null, linkNode.getFields()?.url ?? null)\n return\n }\n\n const url = linkNode.getFields()?.url\n if (url !== match?.url) {\n const flds = linkNode.getFields()\n flds.url = match?.url\n linkNode.setFields(flds)\n onChange(match.url, url ?? null)\n }\n}\n\n// Bad neighbors are edits in neighbor nodes that make AutoLinks incompatible.\n// Given the creation preconditions, these can only be simple text nodes.\nfunction handleBadNeighbors(\n textNode: TextNode,\n matchers: LinkMatcher[],\n onChange: ChangeHandler,\n): void {\n const previousSibling = textNode.getPreviousSibling()\n const nextSibling = textNode.getNextSibling()\n const text = textNode.getTextContent()\n\n if ($isAutoLinkNode(previousSibling) && !startsWithSeparator(text)) {\n previousSibling.append(textNode)\n handleLinkEdit(previousSibling, matchers, onChange)\n onChange(null, previousSibling.getFields()?.url ?? null)\n }\n\n if ($isAutoLinkNode(nextSibling) && !endsWithSeparator(text)) {\n replaceWithChildren(nextSibling)\n handleLinkEdit(nextSibling, matchers, onChange)\n onChange(null, nextSibling.getFields()?.url ?? null)\n }\n}\n\nfunction replaceWithChildren(node: ElementNode): LexicalNode[] {\n const children = node.getChildren()\n const childrenLength = children.length\n\n for (let j = childrenLength - 1; j >= 0; j--) {\n node.insertAfter(children[j])\n }\n\n node.remove()\n return children.map((child) => child.getLatest())\n}\n\nfunction getTextNodesToMatch(textNode: TextNode): TextNode[] {\n // check if next siblings are simple text nodes till a node contains a space separator\n const textNodesToMatch = [textNode]\n let nextSibling = textNode.getNextSibling()\n while (nextSibling !== null && $isTextNode(nextSibling) && nextSibling.isSimpleText()) {\n textNodesToMatch.push(nextSibling)\n if (/\\s/.test(nextSibling.getTextContent())) {\n break\n }\n nextSibling = nextSibling.getNextSibling()\n }\n return textNodesToMatch\n}\n\nfunction useAutoLink(\n editor: LexicalEditor,\n matchers: LinkMatcher[],\n onChange?: ChangeHandler,\n): void {\n useEffect(() => {\n if (!editor.hasNodes([AutoLinkNode])) {\n invariant(false, 'LexicalAutoLinkPlugin: AutoLinkNode not registered on editor')\n }\n\n const onChangeWrapped = (url: null | string, prevUrl: null | string): void => {\n if (onChange != null) {\n onChange(url, prevUrl)\n }\n }\n\n return mergeRegister(\n editor.registerNodeTransform(TextNodeValue, (textNode: TextNode) => {\n const parent = textNode.getParentOrThrow()\n const previous = textNode.getPreviousSibling()\n if ($isAutoLinkNode(parent)) {\n handleLinkEdit(parent, matchers, onChangeWrapped)\n } else if (!$isLinkNode(parent)) {\n if (\n textNode.isSimpleText() &&\n (startsWithSeparator(textNode.getTextContent()) || !$isAutoLinkNode(previous))\n ) {\n const textNodesToMatch = getTextNodesToMatch(textNode)\n $handleLinkCreation(textNodesToMatch, matchers, onChangeWrapped)\n }\n\n handleBadNeighbors(textNode, matchers, onChangeWrapped)\n }\n }),\n )\n }, [editor, matchers, onChange])\n}\n\nconst URL_REGEX =\n /((https?:\\/\\/(www\\.)?)|(www\\.))[-\\w@:%.+~#=]{1,256}\\.[a-zA-Z\\d()]{1,6}\\b([-\\w()@:%+.~#?&/=]*)/\n\nconst EMAIL_REGEX =\n /(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\])|(([a-z\\-\\d]+\\.)+[a-z]{2,}))/i\n\nconst MATCHERS = [\n createLinkMatcherWithRegExp(URL_REGEX, (text) => {\n return text.startsWith('http') ? text : `https://${text}`\n }),\n createLinkMatcherWithRegExp(EMAIL_REGEX, (text) => {\n return `mailto:${text}`\n }),\n]\n\nexport const AutoLinkPlugin: PluginComponent<ClientProps> = () => {\n const [editor] = useLexicalComposerContext()\n\n useAutoLink(editor, MATCHERS)\n\n return null\n}\n"],"names":["useLexicalComposerContext","mergeRegister","$createTextNode","$getSelection","$isElementNode","$isLineBreakNode","$isNodeSelection","$isRangeSelection","$isTextNode","TextNode","TextNodeValue","useEffect","invariant","$createAutoLinkNode","$isAutoLinkNode","AutoLinkNode","$isLinkNode","createLinkMatcherWithRegExp","regExp","urlTransformer","text","match","exec","index","length","url","findFirstMatch","matchers","i","PUNCTUATION_OR_SPACE","isSeparator","char","test","endsWithSeparator","textContent","startsWithSeparator","isPreviousNodeValid","node","previousNode","getPreviousSibling","getLastDescendant","getTextContent","isNextNodeValid","nextNode","getNextSibling","getFirstDescendant","isContentAroundIsValid","matchStart","matchEnd","nodes","contentBeforeIsValid","contentAfterIsValid","extractMatchingNodes","startIndex","endIndex","unmodifiedBeforeNodes","matchingNodes","unmodifiedAfterNodes","matchingOffset","currentOffset","currentNodes","currentNode","currentNodeText","currentNodeLength","currentNodeStart","currentNodeEnd","push","shift","$createAutoLinkNode_","fields","linkType","linkNode","remainingTextNode","linkTextNode","splitText","textNode","setFormat","getFormat","setDetail","getDetail","setStyle","getStyle","append","replace","firstTextNode","offset","firstLinkTextNode","linkNodes","endNode","selection","selectedTextNode","getNodes","find","undefined","select","anchor","focus","$handleLinkCreation","onChange","initialText","map","join","invalidMatchEnd","matchLength","isValid","actualMatchStart","actualMatchEnd","substring","handleLinkEdit","children","getChildren","childrenLength","child","isSimpleText","replaceWithChildren","getFields","flds","setFields","handleBadNeighbors","previousSibling","nextSibling","j","insertAfter","remove","getLatest","getTextNodesToMatch","textNodesToMatch","useAutoLink","editor","hasNodes","onChangeWrapped","prevUrl","registerNodeTransform","parent","getParentOrThrow","previous","URL_REGEX","EMAIL_REGEX","MATCHERS","startsWith","AutoLinkPlugin"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -54,7 +54,7 @@ export function LinkEditor({ anchorElem }) {
54
54
  setLinkLabel,
55
55
  setSelectedNodes
56
56
  ]);
57
- const updateLinkEditor = useCallback(()=>{
57
+ const $updateLinkEditor = useCallback(()=>{
58
58
  const selection = $getSelection();
59
59
  let selectedNodeDomRect = null;
60
60
  if (!$isRangeSelection(selection) || !selection) {
@@ -147,13 +147,13 @@ export function LinkEditor({ anchorElem }) {
147
147
  return mergeRegister(editor.registerCommand(TOGGLE_LINK_WITH_MODAL_COMMAND, (payload)=>{
148
148
  editor.dispatchCommand(TOGGLE_LINK_COMMAND, payload);
149
149
  // Now, open the modal
150
- updateLinkEditor();
150
+ $updateLinkEditor();
151
151
  toggleModal(drawerSlug);
152
152
  return true;
153
153
  }, COMMAND_PRIORITY_LOW));
154
154
  }, [
155
155
  editor,
156
- updateLinkEditor,
156
+ $updateLinkEditor,
157
157
  toggleModal,
158
158
  drawerSlug
159
159
  ]);
@@ -161,7 +161,7 @@ export function LinkEditor({ anchorElem }) {
161
161
  const scrollerElem = anchorElem.parentElement;
162
162
  const update = ()=>{
163
163
  editor.getEditorState().read(()=>{
164
- void updateLinkEditor();
164
+ void $updateLinkEditor();
165
165
  });
166
166
  };
167
167
  window.addEventListener('resize', update);
@@ -177,15 +177,15 @@ export function LinkEditor({ anchorElem }) {
177
177
  }, [
178
178
  anchorElem.parentElement,
179
179
  editor,
180
- updateLinkEditor
180
+ $updateLinkEditor
181
181
  ]);
182
182
  useEffect(()=>{
183
183
  return mergeRegister(editor.registerUpdateListener(({ editorState })=>{
184
184
  editorState.read(()=>{
185
- void updateLinkEditor();
185
+ void $updateLinkEditor();
186
186
  });
187
187
  }), editor.registerCommand(SELECTION_CHANGE_COMMAND, ()=>{
188
- void updateLinkEditor();
188
+ void $updateLinkEditor();
189
189
  return true;
190
190
  }, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ESCAPE_COMMAND, ()=>{
191
191
  if (isLink) {
@@ -196,17 +196,17 @@ export function LinkEditor({ anchorElem }) {
196
196
  }, COMMAND_PRIORITY_HIGH));
197
197
  }, [
198
198
  editor,
199
- updateLinkEditor,
199
+ $updateLinkEditor,
200
200
  isLink,
201
201
  setNotLink
202
202
  ]);
203
203
  useEffect(()=>{
204
204
  editor.getEditorState().read(()=>{
205
- void updateLinkEditor();
205
+ void $updateLinkEditor();
206
206
  });
207
207
  }, [
208
208
  editor,
209
- updateLinkEditor
209
+ $updateLinkEditor
210
210
  ]);
211
211
  return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("div", {
212
212
  className: "link-editor",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/field/features/link/plugins/floatingLinkEditor/LinkEditor/index.tsx"],"sourcesContent":["'use client'\nimport type { LexicalNode } from 'lexical'\nimport type { FormState } from 'payload/types'\nimport type { Data } from 'payload/types'\n\nimport * as facelessUIImport from '@faceless-ui/modal'\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'\nimport { $findMatchingParent, mergeRegister } from '@lexical/utils'\nimport { getTranslation } from '@payloadcms/translations'\nimport { formatDrawerSlug } from '@payloadcms/ui/elements/Drawer'\nimport { useConfig } from '@payloadcms/ui/providers/Config'\nimport { useEditDepth } from '@payloadcms/ui/providers/EditDepth'\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport { $isLineBreakNode } from 'lexical'\nimport {\n $getSelection,\n $isRangeSelection,\n COMMAND_PRIORITY_HIGH,\n COMMAND_PRIORITY_LOW,\n KEY_ESCAPE_COMMAND,\n SELECTION_CHANGE_COMMAND,\n} from 'lexical'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type { LinkNode } from '../../../nodes/LinkNode.js'\nimport type { LinkFields } from '../../../nodes/types.js'\nimport type { LinkPayload } from '../types.js'\n\nimport { useEditorConfigContext } from '../../../../../lexical/config/client/EditorConfigProvider.js'\nimport { getSelectedNode } from '../../../../../lexical/utils/getSelectedNode.js'\nimport { setFloatingElemPositionForLinkEditor } from '../../../../../lexical/utils/setFloatingElemPositionForLinkEditor.js'\nimport { LinkDrawer } from '../../../drawer/index.js'\nimport { $isAutoLinkNode } from '../../../nodes/AutoLinkNode.js'\nimport { $createLinkNode } from '../../../nodes/LinkNode.js'\nimport { $isLinkNode, TOGGLE_LINK_COMMAND } from '../../../nodes/LinkNode.js'\nimport { TOGGLE_LINK_WITH_MODAL_COMMAND } from './commands.js'\n\nexport function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.ReactNode {\n const { useModal } = facelessUIImport\n\n const [editor] = useLexicalComposerContext()\n\n const editorRef = useRef<HTMLDivElement | null>(null)\n const [linkUrl, setLinkUrl] = useState(null)\n const [linkLabel, setLinkLabel] = useState(null)\n\n const { uuid } = useEditorConfigContext()\n\n const config = useConfig()\n\n const { i18n, t } = useTranslation()\n\n const [stateData, setStateData] = useState<{} | (LinkFields & { text: string })>({})\n\n const { closeModal, toggleModal } = useModal()\n const editDepth = useEditDepth()\n const [isLink, setIsLink] = useState(false)\n const [selectedNodes, setSelectedNodes] = useState<LexicalNode[]>([])\n\n const [isAutoLink, setIsAutoLink] = useState(false)\n\n const drawerSlug = formatDrawerSlug({\n slug: `lexical-rich-text-link-` + uuid,\n depth: editDepth,\n })\n\n const setNotLink = useCallback(() => {\n setIsLink(false)\n if (editorRef && editorRef.current) {\n editorRef.current.style.opacity = '0'\n editorRef.current.style.transform = 'translate(-10000px, -10000px)'\n }\n setIsAutoLink(false)\n setLinkUrl(null)\n setLinkLabel(null)\n setSelectedNodes([])\n setStateData({})\n }, [setIsLink, setLinkUrl, setLinkLabel, setSelectedNodes])\n\n const updateLinkEditor = useCallback(() => {\n const selection = $getSelection()\n let selectedNodeDomRect: DOMRect | undefined = null\n\n if (!$isRangeSelection(selection) || !selection) {\n setNotLink()\n return\n }\n\n // Handle the data displayed in the floating link editor & drawer when you click on a link node\n\n const focusNode = getSelectedNode(selection)\n selectedNodeDomRect = editor.getElementByKey(focusNode.getKey())?.getBoundingClientRect()\n const focusLinkParent: LinkNode = $findMatchingParent(focusNode, $isLinkNode)\n\n // Prevent link modal from showing if selection spans further than the link: https://github.com/facebook/lexical/issues/4064\n const badNode = selection\n .getNodes()\n .filter((node) => !$isLineBreakNode(node))\n .find((node) => {\n const linkNode = $findMatchingParent(node, $isLinkNode)\n return (\n (focusLinkParent && !focusLinkParent.is(linkNode)) ||\n (linkNode && !linkNode.is(focusLinkParent))\n )\n })\n\n if (focusLinkParent == null || badNode) {\n setNotLink()\n return\n }\n\n // Initial state:\n const data: LinkFields & { text: string } = {\n doc: undefined,\n linkType: undefined,\n newTab: undefined,\n url: '',\n ...focusLinkParent.getFields(),\n text: focusLinkParent.getTextContent(),\n }\n\n if (focusLinkParent.getFields()?.linkType === 'custom') {\n setLinkUrl(focusLinkParent.getFields()?.url ?? null)\n setLinkLabel(null)\n } else {\n // internal link\n setLinkUrl(\n `/admin/collections/${focusLinkParent.getFields()?.doc?.relationTo}/${\n focusLinkParent.getFields()?.doc?.value\n }`,\n )\n\n const relatedField = config.collections.find(\n (coll) => coll.slug === focusLinkParent.getFields()?.doc?.relationTo,\n )\n if (!relatedField) {\n // Usually happens if the user removed all default fields. In this case, we let them specify the label or do not display the label at all.\n // label could be a virtual field the user added. This is useful if they want to use the link feature for things other than links.\n setLinkLabel(\n focusLinkParent.getFields()?.label ? String(focusLinkParent.getFields()?.label) : null,\n )\n setLinkUrl(\n focusLinkParent.getFields()?.url ? String(focusLinkParent.getFields()?.url) : null,\n )\n } else {\n const label = t('fields:linkedTo', {\n label: getTranslation(relatedField.labels.singular, i18n),\n }).replace(/<[^>]*>?/g, '')\n setLinkLabel(label)\n }\n }\n\n setStateData(data)\n setIsLink(true)\n setSelectedNodes(selection ? selection?.getNodes() : [])\n\n if ($isAutoLinkNode(focusLinkParent)) {\n setIsAutoLink(true)\n } else {\n setIsAutoLink(false)\n }\n\n const editorElem = editorRef.current\n const nativeSelection = window.getSelection()\n const { activeElement } = document\n\n if (editorElem === null) {\n return\n }\n\n const rootElement = editor.getRootElement()\n\n if (\n nativeSelection !== null &&\n rootElement !== null &&\n rootElement.contains(nativeSelection.anchorNode)\n ) {\n if (!selectedNodeDomRect) {\n // Get the DOM rect of the selected node using the native selection. This sometimes produces the wrong\n // result, which is why we use lexical's selection preferably.\n selectedNodeDomRect = nativeSelection.getRangeAt(0).getBoundingClientRect()\n }\n\n if (selectedNodeDomRect != null) {\n selectedNodeDomRect.y += 40\n setFloatingElemPositionForLinkEditor(selectedNodeDomRect, editorElem, anchorElem)\n }\n } else if (activeElement == null || activeElement.className !== 'link-input') {\n if (rootElement !== null) {\n setFloatingElemPositionForLinkEditor(null, editorElem, anchorElem)\n }\n setLinkUrl(null)\n setLinkLabel(null)\n }\n\n return true\n }, [editor, setNotLink, config.collections, t, i18n, anchorElem])\n\n useEffect(() => {\n return mergeRegister(\n editor.registerCommand(\n TOGGLE_LINK_WITH_MODAL_COMMAND,\n (payload: LinkPayload) => {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, payload)\n\n // Now, open the modal\n updateLinkEditor()\n toggleModal(drawerSlug)\n\n return true\n },\n COMMAND_PRIORITY_LOW,\n ),\n )\n }, [editor, updateLinkEditor, toggleModal, drawerSlug])\n\n useEffect(() => {\n const scrollerElem = anchorElem.parentElement\n\n const update = (): void => {\n editor.getEditorState().read(() => {\n void updateLinkEditor()\n })\n }\n\n window.addEventListener('resize', update)\n\n if (scrollerElem != null) {\n scrollerElem.addEventListener('scroll', update)\n }\n\n return () => {\n window.removeEventListener('resize', update)\n\n if (scrollerElem != null) {\n scrollerElem.removeEventListener('scroll', update)\n }\n }\n }, [anchorElem.parentElement, editor, updateLinkEditor])\n\n useEffect(() => {\n return mergeRegister(\n editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n void updateLinkEditor()\n })\n }),\n\n editor.registerCommand(\n SELECTION_CHANGE_COMMAND,\n () => {\n void updateLinkEditor()\n return true\n },\n COMMAND_PRIORITY_LOW,\n ),\n editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n () => {\n if (isLink) {\n setNotLink()\n\n return true\n }\n return false\n },\n COMMAND_PRIORITY_HIGH,\n ),\n )\n }, [editor, updateLinkEditor, isLink, setNotLink])\n\n useEffect(() => {\n editor.getEditorState().read(() => {\n void updateLinkEditor()\n })\n }, [editor, updateLinkEditor])\n\n return (\n <React.Fragment>\n <div className=\"link-editor\" ref={editorRef}>\n <div className=\"link-input\">\n {linkUrl && linkUrl.length > 0 ? (\n <a href={linkUrl} rel=\"noopener noreferrer\" target=\"_blank\">\n {linkLabel != null && linkLabel.length > 0 ? linkLabel : linkUrl}\n </a>\n ) : linkLabel != null && linkLabel.length > 0 ? (\n <span className=\"link-input__label-pure\">{linkLabel}</span>\n ) : null}\n\n {editor.isEditable() && (\n <React.Fragment>\n <button\n aria-label=\"Edit link\"\n className=\"link-edit\"\n onClick={() => {\n toggleModal(drawerSlug)\n }}\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n tabIndex={0}\n type=\"button\"\n />\n {!isAutoLink && (\n <button\n aria-label=\"Remove link\"\n className=\"link-trash\"\n onClick={() => {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, null)\n }}\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n tabIndex={0}\n type=\"button\"\n />\n )}\n </React.Fragment>\n )}\n </div>\n </div>\n <LinkDrawer\n drawerSlug={drawerSlug}\n handleModalSubmit={(fields: FormState, data: Data) => {\n closeModal(drawerSlug)\n\n const newLinkPayload = data as LinkFields & { text: string }\n\n const bareLinkFields: LinkFields = {\n ...newLinkPayload,\n }\n delete bareLinkFields.text\n\n // See: https://github.com/facebook/lexical/pull/5536. This updates autolink nodes to link nodes whenever a change was made (which is good!).\n editor.update(() => {\n const selection = $getSelection()\n let linkParent = null\n if ($isRangeSelection(selection)) {\n linkParent = getSelectedNode(selection).getParent()\n } else {\n if (selectedNodes.length) {\n linkParent = selectedNodes[0].getParent()\n }\n }\n\n if (linkParent && $isAutoLinkNode(linkParent)) {\n const linkNode = $createLinkNode({\n fields: bareLinkFields,\n })\n linkParent.replace(linkNode, true)\n }\n })\n\n // Needs to happen AFTER a potential auto link => link node conversion, as otherwise, the updated text to display may be lost due to\n // it being applied to the auto link node instead of the link node.\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, {\n fields: bareLinkFields,\n selectedNodes,\n text: newLinkPayload.text,\n })\n }}\n stateData={stateData}\n />\n </React.Fragment>\n )\n}\n"],"names":["facelessUIImport","useLexicalComposerContext","$findMatchingParent","mergeRegister","getTranslation","formatDrawerSlug","useConfig","useEditDepth","useTranslation","$isLineBreakNode","$getSelection","$isRangeSelection","COMMAND_PRIORITY_HIGH","COMMAND_PRIORITY_LOW","KEY_ESCAPE_COMMAND","SELECTION_CHANGE_COMMAND","React","useCallback","useEffect","useRef","useState","useEditorConfigContext","getSelectedNode","setFloatingElemPositionForLinkEditor","LinkDrawer","$isAutoLinkNode","$createLinkNode","$isLinkNode","TOGGLE_LINK_COMMAND","TOGGLE_LINK_WITH_MODAL_COMMAND","LinkEditor","anchorElem","useModal","editor","editorRef","linkUrl","setLinkUrl","linkLabel","setLinkLabel","uuid","config","i18n","t","stateData","setStateData","closeModal","toggleModal","editDepth","isLink","setIsLink","selectedNodes","setSelectedNodes","isAutoLink","setIsAutoLink","drawerSlug","slug","depth","setNotLink","current","style","opacity","transform","updateLinkEditor","selection","selectedNodeDomRect","focusNode","getElementByKey","getKey","getBoundingClientRect","focusLinkParent","badNode","getNodes","filter","node","find","linkNode","is","data","doc","undefined","linkType","newTab","url","getFields","text","getTextContent","relationTo","value","relatedField","collections","coll","label","String","labels","singular","replace","editorElem","nativeSelection","window","getSelection","activeElement","document","rootElement","getRootElement","contains","anchorNode","getRangeAt","y","className","registerCommand","payload","dispatchCommand","scrollerElem","parentElement","update","getEditorState","read","addEventListener","removeEventListener","registerUpdateListener","editorState","Fragment","div","ref","length","a","href","rel","target","span","isEditable","button","aria-label","onClick","onMouseDown","event","preventDefault","tabIndex","type","handleModalSubmit","fields","newLinkPayload","bareLinkFields","linkParent","getParent"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../src/field/features/link/plugins/floatingLinkEditor/LinkEditor/index.tsx"],"sourcesContent":["'use client'\nimport type { LexicalNode } from 'lexical'\nimport type { FormState } from 'payload/types'\nimport type { Data } from 'payload/types'\n\nimport * as facelessUIImport from '@faceless-ui/modal'\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'\nimport { $findMatchingParent, mergeRegister } from '@lexical/utils'\nimport { getTranslation } from '@payloadcms/translations'\nimport { formatDrawerSlug } from '@payloadcms/ui/elements/Drawer'\nimport { useConfig } from '@payloadcms/ui/providers/Config'\nimport { useEditDepth } from '@payloadcms/ui/providers/EditDepth'\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport { $isLineBreakNode } from 'lexical'\nimport {\n $getSelection,\n $isRangeSelection,\n COMMAND_PRIORITY_HIGH,\n COMMAND_PRIORITY_LOW,\n KEY_ESCAPE_COMMAND,\n SELECTION_CHANGE_COMMAND,\n} from 'lexical'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type { LinkNode } from '../../../nodes/LinkNode.js'\nimport type { LinkFields } from '../../../nodes/types.js'\nimport type { LinkPayload } from '../types.js'\n\nimport { useEditorConfigContext } from '../../../../../lexical/config/client/EditorConfigProvider.js'\nimport { getSelectedNode } from '../../../../../lexical/utils/getSelectedNode.js'\nimport { setFloatingElemPositionForLinkEditor } from '../../../../../lexical/utils/setFloatingElemPositionForLinkEditor.js'\nimport { LinkDrawer } from '../../../drawer/index.js'\nimport { $isAutoLinkNode } from '../../../nodes/AutoLinkNode.js'\nimport { $createLinkNode } from '../../../nodes/LinkNode.js'\nimport { $isLinkNode, TOGGLE_LINK_COMMAND } from '../../../nodes/LinkNode.js'\nimport { TOGGLE_LINK_WITH_MODAL_COMMAND } from './commands.js'\n\nexport function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.ReactNode {\n const { useModal } = facelessUIImport\n\n const [editor] = useLexicalComposerContext()\n\n const editorRef = useRef<HTMLDivElement | null>(null)\n const [linkUrl, setLinkUrl] = useState(null)\n const [linkLabel, setLinkLabel] = useState(null)\n\n const { uuid } = useEditorConfigContext()\n\n const config = useConfig()\n\n const { i18n, t } = useTranslation()\n\n const [stateData, setStateData] = useState<{} | (LinkFields & { text: string })>({})\n\n const { closeModal, toggleModal } = useModal()\n const editDepth = useEditDepth()\n const [isLink, setIsLink] = useState(false)\n const [selectedNodes, setSelectedNodes] = useState<LexicalNode[]>([])\n\n const [isAutoLink, setIsAutoLink] = useState(false)\n\n const drawerSlug = formatDrawerSlug({\n slug: `lexical-rich-text-link-` + uuid,\n depth: editDepth,\n })\n\n const setNotLink = useCallback(() => {\n setIsLink(false)\n if (editorRef && editorRef.current) {\n editorRef.current.style.opacity = '0'\n editorRef.current.style.transform = 'translate(-10000px, -10000px)'\n }\n setIsAutoLink(false)\n setLinkUrl(null)\n setLinkLabel(null)\n setSelectedNodes([])\n setStateData({})\n }, [setIsLink, setLinkUrl, setLinkLabel, setSelectedNodes])\n\n const $updateLinkEditor = useCallback(() => {\n const selection = $getSelection()\n let selectedNodeDomRect: DOMRect | undefined = null\n\n if (!$isRangeSelection(selection) || !selection) {\n setNotLink()\n return\n }\n\n // Handle the data displayed in the floating link editor & drawer when you click on a link node\n\n const focusNode = getSelectedNode(selection)\n selectedNodeDomRect = editor.getElementByKey(focusNode.getKey())?.getBoundingClientRect()\n const focusLinkParent: LinkNode = $findMatchingParent(focusNode, $isLinkNode)\n\n // Prevent link modal from showing if selection spans further than the link: https://github.com/facebook/lexical/issues/4064\n const badNode = selection\n .getNodes()\n .filter((node) => !$isLineBreakNode(node))\n .find((node) => {\n const linkNode = $findMatchingParent(node, $isLinkNode)\n return (\n (focusLinkParent && !focusLinkParent.is(linkNode)) ||\n (linkNode && !linkNode.is(focusLinkParent))\n )\n })\n\n if (focusLinkParent == null || badNode) {\n setNotLink()\n return\n }\n\n // Initial state:\n const data: LinkFields & { text: string } = {\n doc: undefined,\n linkType: undefined,\n newTab: undefined,\n url: '',\n ...focusLinkParent.getFields(),\n text: focusLinkParent.getTextContent(),\n }\n\n if (focusLinkParent.getFields()?.linkType === 'custom') {\n setLinkUrl(focusLinkParent.getFields()?.url ?? null)\n setLinkLabel(null)\n } else {\n // internal link\n setLinkUrl(\n `/admin/collections/${focusLinkParent.getFields()?.doc?.relationTo}/${\n focusLinkParent.getFields()?.doc?.value\n }`,\n )\n\n const relatedField = config.collections.find(\n (coll) => coll.slug === focusLinkParent.getFields()?.doc?.relationTo,\n )\n if (!relatedField) {\n // Usually happens if the user removed all default fields. In this case, we let them specify the label or do not display the label at all.\n // label could be a virtual field the user added. This is useful if they want to use the link feature for things other than links.\n setLinkLabel(\n focusLinkParent.getFields()?.label ? String(focusLinkParent.getFields()?.label) : null,\n )\n setLinkUrl(\n focusLinkParent.getFields()?.url ? String(focusLinkParent.getFields()?.url) : null,\n )\n } else {\n const label = t('fields:linkedTo', {\n label: getTranslation(relatedField.labels.singular, i18n),\n }).replace(/<[^>]*>?/g, '')\n setLinkLabel(label)\n }\n }\n\n setStateData(data)\n setIsLink(true)\n setSelectedNodes(selection ? selection?.getNodes() : [])\n\n if ($isAutoLinkNode(focusLinkParent)) {\n setIsAutoLink(true)\n } else {\n setIsAutoLink(false)\n }\n\n const editorElem = editorRef.current\n const nativeSelection = window.getSelection()\n const { activeElement } = document\n\n if (editorElem === null) {\n return\n }\n\n const rootElement = editor.getRootElement()\n\n if (\n nativeSelection !== null &&\n rootElement !== null &&\n rootElement.contains(nativeSelection.anchorNode)\n ) {\n if (!selectedNodeDomRect) {\n // Get the DOM rect of the selected node using the native selection. This sometimes produces the wrong\n // result, which is why we use lexical's selection preferably.\n selectedNodeDomRect = nativeSelection.getRangeAt(0).getBoundingClientRect()\n }\n\n if (selectedNodeDomRect != null) {\n selectedNodeDomRect.y += 40\n setFloatingElemPositionForLinkEditor(selectedNodeDomRect, editorElem, anchorElem)\n }\n } else if (activeElement == null || activeElement.className !== 'link-input') {\n if (rootElement !== null) {\n setFloatingElemPositionForLinkEditor(null, editorElem, anchorElem)\n }\n setLinkUrl(null)\n setLinkLabel(null)\n }\n\n return true\n }, [editor, setNotLink, config.collections, t, i18n, anchorElem])\n\n useEffect(() => {\n return mergeRegister(\n editor.registerCommand(\n TOGGLE_LINK_WITH_MODAL_COMMAND,\n (payload: LinkPayload) => {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, payload)\n\n // Now, open the modal\n $updateLinkEditor()\n toggleModal(drawerSlug)\n\n return true\n },\n COMMAND_PRIORITY_LOW,\n ),\n )\n }, [editor, $updateLinkEditor, toggleModal, drawerSlug])\n\n useEffect(() => {\n const scrollerElem = anchorElem.parentElement\n\n const update = (): void => {\n editor.getEditorState().read(() => {\n void $updateLinkEditor()\n })\n }\n\n window.addEventListener('resize', update)\n\n if (scrollerElem != null) {\n scrollerElem.addEventListener('scroll', update)\n }\n\n return () => {\n window.removeEventListener('resize', update)\n\n if (scrollerElem != null) {\n scrollerElem.removeEventListener('scroll', update)\n }\n }\n }, [anchorElem.parentElement, editor, $updateLinkEditor])\n\n useEffect(() => {\n return mergeRegister(\n editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n void $updateLinkEditor()\n })\n }),\n\n editor.registerCommand(\n SELECTION_CHANGE_COMMAND,\n () => {\n void $updateLinkEditor()\n return true\n },\n COMMAND_PRIORITY_LOW,\n ),\n editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n () => {\n if (isLink) {\n setNotLink()\n\n return true\n }\n return false\n },\n COMMAND_PRIORITY_HIGH,\n ),\n )\n }, [editor, $updateLinkEditor, isLink, setNotLink])\n\n useEffect(() => {\n editor.getEditorState().read(() => {\n void $updateLinkEditor()\n })\n }, [editor, $updateLinkEditor])\n\n return (\n <React.Fragment>\n <div className=\"link-editor\" ref={editorRef}>\n <div className=\"link-input\">\n {linkUrl && linkUrl.length > 0 ? (\n <a href={linkUrl} rel=\"noopener noreferrer\" target=\"_blank\">\n {linkLabel != null && linkLabel.length > 0 ? linkLabel : linkUrl}\n </a>\n ) : linkLabel != null && linkLabel.length > 0 ? (\n <span className=\"link-input__label-pure\">{linkLabel}</span>\n ) : null}\n\n {editor.isEditable() && (\n <React.Fragment>\n <button\n aria-label=\"Edit link\"\n className=\"link-edit\"\n onClick={() => {\n toggleModal(drawerSlug)\n }}\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n tabIndex={0}\n type=\"button\"\n />\n {!isAutoLink && (\n <button\n aria-label=\"Remove link\"\n className=\"link-trash\"\n onClick={() => {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, null)\n }}\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n tabIndex={0}\n type=\"button\"\n />\n )}\n </React.Fragment>\n )}\n </div>\n </div>\n <LinkDrawer\n drawerSlug={drawerSlug}\n handleModalSubmit={(fields: FormState, data: Data) => {\n closeModal(drawerSlug)\n\n const newLinkPayload = data as LinkFields & { text: string }\n\n const bareLinkFields: LinkFields = {\n ...newLinkPayload,\n }\n delete bareLinkFields.text\n\n // See: https://github.com/facebook/lexical/pull/5536. This updates autolink nodes to link nodes whenever a change was made (which is good!).\n editor.update(() => {\n const selection = $getSelection()\n let linkParent = null\n if ($isRangeSelection(selection)) {\n linkParent = getSelectedNode(selection).getParent()\n } else {\n if (selectedNodes.length) {\n linkParent = selectedNodes[0].getParent()\n }\n }\n\n if (linkParent && $isAutoLinkNode(linkParent)) {\n const linkNode = $createLinkNode({\n fields: bareLinkFields,\n })\n linkParent.replace(linkNode, true)\n }\n })\n\n // Needs to happen AFTER a potential auto link => link node conversion, as otherwise, the updated text to display may be lost due to\n // it being applied to the auto link node instead of the link node.\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, {\n fields: bareLinkFields,\n selectedNodes,\n text: newLinkPayload.text,\n })\n }}\n stateData={stateData}\n />\n </React.Fragment>\n )\n}\n"],"names":["facelessUIImport","useLexicalComposerContext","$findMatchingParent","mergeRegister","getTranslation","formatDrawerSlug","useConfig","useEditDepth","useTranslation","$isLineBreakNode","$getSelection","$isRangeSelection","COMMAND_PRIORITY_HIGH","COMMAND_PRIORITY_LOW","KEY_ESCAPE_COMMAND","SELECTION_CHANGE_COMMAND","React","useCallback","useEffect","useRef","useState","useEditorConfigContext","getSelectedNode","setFloatingElemPositionForLinkEditor","LinkDrawer","$isAutoLinkNode","$createLinkNode","$isLinkNode","TOGGLE_LINK_COMMAND","TOGGLE_LINK_WITH_MODAL_COMMAND","LinkEditor","anchorElem","useModal","editor","editorRef","linkUrl","setLinkUrl","linkLabel","setLinkLabel","uuid","config","i18n","t","stateData","setStateData","closeModal","toggleModal","editDepth","isLink","setIsLink","selectedNodes","setSelectedNodes","isAutoLink","setIsAutoLink","drawerSlug","slug","depth","setNotLink","current","style","opacity","transform","$updateLinkEditor","selection","selectedNodeDomRect","focusNode","getElementByKey","getKey","getBoundingClientRect","focusLinkParent","badNode","getNodes","filter","node","find","linkNode","is","data","doc","undefined","linkType","newTab","url","getFields","text","getTextContent","relationTo","value","relatedField","collections","coll","label","String","labels","singular","replace","editorElem","nativeSelection","window","getSelection","activeElement","document","rootElement","getRootElement","contains","anchorNode","getRangeAt","y","className","registerCommand","payload","dispatchCommand","scrollerElem","parentElement","update","getEditorState","read","addEventListener","removeEventListener","registerUpdateListener","editorState","Fragment","div","ref","length","a","href","rel","target","span","isEditable","button","aria-label","onClick","onMouseDown","event","preventDefault","tabIndex","type","handleModalSubmit","fields","newLinkPayload","bareLinkFields","linkParent","getParent"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  const RelationshipComponent = /*#__PURE__*/ React.lazy(()=>import('./components/RelationshipComponent.js').then((module)=>({
4
4
  default: module.RelationshipComponent
5
5
  })));
6
- function relationshipElementToNode(domNode) {
6
+ function $relationshipElementToNode(domNode) {
7
7
  const id = domNode.getAttribute('data-lexical-relationship-id');
8
8
  const relationTo = domNode.getAttribute('data-lexical-relationship-relationTo');
9
9
  if (id != null && relationTo != null) {
@@ -40,7 +40,7 @@ export class RelationshipNode extends DecoratorBlockNode {
40
40
  return null;
41
41
  }
42
42
  return {
43
- conversion: relationshipElementToNode,
43
+ conversion: $relationshipElementToNode,
44
44
  priority: 2
45
45
  };
46
46
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/field/features/relationship/nodes/RelationshipNode.tsx"],"sourcesContent":["import type { SerializedDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode.js'\nimport type {\n DOMConversionMap,\n DOMConversionOutput,\n DOMExportOutput,\n EditorConfig,\n ElementFormatType,\n LexicalEditor,\n LexicalNode,\n NodeKey,\n Spread,\n} from 'lexical'\n\nimport { DecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode.js'\nimport * as React from 'react'\n\nconst RelationshipComponent = React.lazy(() =>\n import('./components/RelationshipComponent.js').then((module) => ({\n default: module.RelationshipComponent,\n })),\n)\n\nexport type RelationshipData = {\n relationTo: string\n value: number | string\n}\n\nexport type SerializedRelationshipNode = Spread<RelationshipData, SerializedDecoratorBlockNode>\n\nfunction relationshipElementToNode(domNode: HTMLDivElement): DOMConversionOutput | null {\n const id = domNode.getAttribute('data-lexical-relationship-id')\n const relationTo = domNode.getAttribute('data-lexical-relationship-relationTo')\n\n if (id != null && relationTo != null) {\n const node = $createRelationshipNode({\n relationTo,\n value: id,\n })\n return { node }\n }\n return null\n}\n\nexport class RelationshipNode extends DecoratorBlockNode {\n __data: RelationshipData\n\n constructor({\n data,\n format,\n key,\n }: {\n data: RelationshipData\n format?: ElementFormatType\n key?: NodeKey\n }) {\n super(format, key)\n this.__data = data\n }\n\n static clone(node: RelationshipNode): RelationshipNode {\n return new RelationshipNode({\n data: node.__data,\n format: node.__format,\n key: node.__key,\n })\n }\n\n static getType(): string {\n return 'relationship'\n }\n\n static importDOM(): DOMConversionMap<HTMLDivElement> | null {\n return {\n div: (domNode: HTMLDivElement) => {\n if (\n !domNode.hasAttribute('data-lexical-relationship-relationTo') ||\n !domNode.hasAttribute('data-lexical-relationship-id')\n ) {\n return null\n }\n return {\n conversion: relationshipElementToNode,\n priority: 2,\n }\n },\n }\n }\n\n static importJSON(serializedNode: SerializedRelationshipNode): RelationshipNode {\n if (serializedNode.version === 1 && (serializedNode?.value as unknown as { id: string })?.id) {\n serializedNode.value = (serializedNode.value as unknown as { id: string }).id\n }\n\n const importedData: RelationshipData = {\n relationTo: serializedNode.relationTo,\n value: serializedNode.value,\n }\n const node = $createRelationshipNode(importedData)\n node.setFormat(serializedNode.format)\n return node\n }\n\n static isInline(): false {\n return false\n }\n\n decorate(editor: LexicalEditor, config: EditorConfig): JSX.Element {\n return (\n <RelationshipComponent\n className={config.theme.relationship ?? 'LexicalEditorTheme__relationship'}\n data={this.__data}\n format={this.__format}\n nodeKey={this.getKey()}\n />\n )\n }\n exportDOM(): DOMExportOutput {\n const element = document.createElement('div')\n element.setAttribute('data-lexical-relationship-id', String(this.__data?.value))\n element.setAttribute('data-lexical-relationship-relationTo', this.__data?.relationTo)\n\n const text = document.createTextNode(this.getTextContent())\n element.append(text)\n return { element }\n }\n\n exportJSON(): SerializedRelationshipNode {\n return {\n ...super.exportJSON(),\n ...this.getData(),\n type: this.getType(),\n version: 2,\n }\n }\n\n getData(): RelationshipData {\n return this.getLatest().__data\n }\n\n getTextContent(): string {\n return `${this.__data?.relationTo} relation to ${this.__data?.value}`\n }\n\n setData(data: RelationshipData): void {\n const writable = this.getWritable()\n writable.__data = data\n }\n}\n\nexport function $createRelationshipNode(data: RelationshipData): RelationshipNode {\n return new RelationshipNode({\n data,\n })\n}\n\nexport function $isRelationshipNode(\n node: LexicalNode | RelationshipNode | null | undefined,\n): node is RelationshipNode {\n return node instanceof RelationshipNode\n}\n"],"names":["DecoratorBlockNode","React","RelationshipComponent","lazy","then","module","default","relationshipElementToNode","domNode","id","getAttribute","relationTo","node","$createRelationshipNode","value","RelationshipNode","__data","constructor","data","format","key","clone","__format","__key","getType","importDOM","div","hasAttribute","conversion","priority","importJSON","serializedNode","version","importedData","setFormat","isInline","decorate","editor","config","className","theme","relationship","nodeKey","getKey","exportDOM","element","document","createElement","setAttribute","String","text","createTextNode","getTextContent","append","exportJSON","getData","type","getLatest","setData","writable","getWritable","$isRelationshipNode"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/field/features/relationship/nodes/RelationshipNode.tsx"],"sourcesContent":["import type { SerializedDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode.js'\nimport type {\n DOMConversionMap,\n DOMConversionOutput,\n DOMExportOutput,\n EditorConfig,\n ElementFormatType,\n LexicalEditor,\n LexicalNode,\n NodeKey,\n Spread,\n} from 'lexical'\n\nimport { DecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode.js'\nimport * as React from 'react'\n\nconst RelationshipComponent = React.lazy(() =>\n import('./components/RelationshipComponent.js').then((module) => ({\n default: module.RelationshipComponent,\n })),\n)\n\nexport type RelationshipData = {\n relationTo: string\n value: number | string\n}\n\nexport type SerializedRelationshipNode = Spread<RelationshipData, SerializedDecoratorBlockNode>\n\nfunction $relationshipElementToNode(domNode: HTMLDivElement): DOMConversionOutput | null {\n const id = domNode.getAttribute('data-lexical-relationship-id')\n const relationTo = domNode.getAttribute('data-lexical-relationship-relationTo')\n\n if (id != null && relationTo != null) {\n const node = $createRelationshipNode({\n relationTo,\n value: id,\n })\n return { node }\n }\n return null\n}\n\nexport class RelationshipNode extends DecoratorBlockNode {\n __data: RelationshipData\n\n constructor({\n data,\n format,\n key,\n }: {\n data: RelationshipData\n format?: ElementFormatType\n key?: NodeKey\n }) {\n super(format, key)\n this.__data = data\n }\n\n static clone(node: RelationshipNode): RelationshipNode {\n return new RelationshipNode({\n data: node.__data,\n format: node.__format,\n key: node.__key,\n })\n }\n\n static getType(): string {\n return 'relationship'\n }\n\n static importDOM(): DOMConversionMap<HTMLDivElement> | null {\n return {\n div: (domNode: HTMLDivElement) => {\n if (\n !domNode.hasAttribute('data-lexical-relationship-relationTo') ||\n !domNode.hasAttribute('data-lexical-relationship-id')\n ) {\n return null\n }\n return {\n conversion: $relationshipElementToNode,\n priority: 2,\n }\n },\n }\n }\n\n static importJSON(serializedNode: SerializedRelationshipNode): RelationshipNode {\n if (serializedNode.version === 1 && (serializedNode?.value as unknown as { id: string })?.id) {\n serializedNode.value = (serializedNode.value as unknown as { id: string }).id\n }\n\n const importedData: RelationshipData = {\n relationTo: serializedNode.relationTo,\n value: serializedNode.value,\n }\n const node = $createRelationshipNode(importedData)\n node.setFormat(serializedNode.format)\n return node\n }\n\n static isInline(): false {\n return false\n }\n\n decorate(editor: LexicalEditor, config: EditorConfig): JSX.Element {\n return (\n <RelationshipComponent\n className={config.theme.relationship ?? 'LexicalEditorTheme__relationship'}\n data={this.__data}\n format={this.__format}\n nodeKey={this.getKey()}\n />\n )\n }\n exportDOM(): DOMExportOutput {\n const element = document.createElement('div')\n element.setAttribute('data-lexical-relationship-id', String(this.__data?.value))\n element.setAttribute('data-lexical-relationship-relationTo', this.__data?.relationTo)\n\n const text = document.createTextNode(this.getTextContent())\n element.append(text)\n return { element }\n }\n\n exportJSON(): SerializedRelationshipNode {\n return {\n ...super.exportJSON(),\n ...this.getData(),\n type: this.getType(),\n version: 2,\n }\n }\n\n getData(): RelationshipData {\n return this.getLatest().__data\n }\n\n getTextContent(): string {\n return `${this.__data?.relationTo} relation to ${this.__data?.value}`\n }\n\n setData(data: RelationshipData): void {\n const writable = this.getWritable()\n writable.__data = data\n }\n}\n\nexport function $createRelationshipNode(data: RelationshipData): RelationshipNode {\n return new RelationshipNode({\n data,\n })\n}\n\nexport function $isRelationshipNode(\n node: LexicalNode | RelationshipNode | null | undefined,\n): node is RelationshipNode {\n return node instanceof RelationshipNode\n}\n"],"names":["DecoratorBlockNode","React","RelationshipComponent","lazy","then","module","default","$relationshipElementToNode","domNode","id","getAttribute","relationTo","node","$createRelationshipNode","value","RelationshipNode","__data","constructor","data","format","key","clone","__format","__key","getType","importDOM","div","hasAttribute","conversion","priority","importJSON","serializedNode","version","importedData","setFormat","isInline","decorate","editor","config","className","theme","relationship","nodeKey","getKey","exportDOM","element","document","createElement","setAttribute","String","text","createTextNode","getTextContent","append","exportJSON","getData","type","getLatest","setData","writable","getWritable","$isRelationshipNode"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -56,7 +56,7 @@ const Component = (props)=>{
56
56
  setParams,
57
57
  closeDrawer
58
58
  ]);
59
- const onDelete = useCallback((payload)=>{
59
+ const $onDelete = useCallback((payload)=>{
60
60
  if (isSelected && $isNodeSelection($getSelection())) {
61
61
  const event = payload;
62
62
  event.preventDefault();
@@ -92,13 +92,13 @@ const Component = (props)=>{
92
92
  clearSelection
93
93
  ]);
94
94
  useEffect(()=>{
95
- return mergeRegister(editor.registerCommand(CLICK_COMMAND, onClick, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_DELETE_COMMAND, onDelete, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_BACKSPACE_COMMAND, onDelete, COMMAND_PRIORITY_LOW));
95
+ return mergeRegister(editor.registerCommand(CLICK_COMMAND, onClick, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_DELETE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_BACKSPACE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW));
96
96
  }, [
97
97
  clearSelection,
98
98
  editor,
99
99
  isSelected,
100
100
  nodeKey,
101
- onDelete,
101
+ $onDelete,
102
102
  setSelected,
103
103
  onClick
104
104
  ]);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/field/features/relationship/nodes/components/RelationshipComponent.tsx"],"sourcesContent":["'use client'\nimport type { ElementFormatType } from 'lexical'\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'\nimport { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection.js'\nimport { mergeRegister } from '@lexical/utils'\nimport { getTranslation } from '@payloadcms/translations'\nimport { Button } from '@payloadcms/ui/elements/Button'\nimport { useDocumentDrawer } from '@payloadcms/ui/elements/DocumentDrawer'\nimport usePayloadAPI from '@payloadcms/ui/hooks/usePayloadAPI'\nimport { useConfig } from '@payloadcms/ui/providers/Config'\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport {\n $getSelection,\n $isNodeSelection,\n CLICK_COMMAND,\n COMMAND_PRIORITY_LOW,\n KEY_BACKSPACE_COMMAND,\n KEY_DELETE_COMMAND,\n} from 'lexical'\nimport { $getNodeByKey } from 'lexical'\nimport React, { useCallback, useEffect, useReducer, useRef, useState } from 'react'\n\nimport type { RelationshipData } from '../RelationshipNode.js'\n\nimport { useEditorConfigContext } from '../../../../lexical/config/client/EditorConfigProvider.js'\nimport { INSERT_RELATIONSHIP_WITH_DRAWER_COMMAND } from '../../drawer/commands.js'\nimport { $isRelationshipNode } from '../RelationshipNode.js'\nimport './index.scss'\n\nconst baseClass = 'lexical-relationship'\n\nconst initialParams = {\n depth: 0,\n}\n\ntype Props = {\n children?: React.ReactNode\n className?: string\n data: RelationshipData\n format?: ElementFormatType\n nodeKey?: string\n}\n\nconst Component: React.FC<Props> = (props) => {\n const {\n children,\n data: { relationTo, value: id },\n nodeKey,\n } = props\n\n const relationshipElemRef = useRef<HTMLDivElement | null>(null)\n\n const [editor] = useLexicalComposerContext()\n const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey)\n const { field } = useEditorConfigContext()\n const {\n collections,\n routes: { api },\n serverURL,\n } = useConfig()\n\n const [relatedCollection, setRelatedCollection] = useState(() =>\n collections.find((coll) => coll.slug === relationTo),\n )\n\n const { i18n, t } = useTranslation()\n const [cacheBust, dispatchCacheBust] = useReducer((state) => state + 1, 0)\n const [{ data }, { setParams }] = usePayloadAPI(\n `${serverURL}${api}/${relatedCollection.slug}/${id}`,\n { initialParams },\n )\n\n const [DocumentDrawer, DocumentDrawerToggler, { closeDrawer }] = useDocumentDrawer({\n id,\n collectionSlug: relatedCollection.slug,\n })\n\n const removeRelationship = useCallback(() => {\n editor.update(() => {\n $getNodeByKey(nodeKey).remove()\n })\n }, [editor, nodeKey])\n\n const updateRelationship = React.useCallback(\n ({ doc }) => {\n setParams({\n ...initialParams,\n cacheBust, // do this to get the usePayloadAPI to re-fetch the data even though the URL string hasn't changed\n })\n\n closeDrawer()\n dispatchCacheBust()\n },\n [cacheBust, setParams, closeDrawer],\n )\n\n const onDelete = useCallback(\n (payload: KeyboardEvent) => {\n if (isSelected && $isNodeSelection($getSelection())) {\n const event: KeyboardEvent = payload\n event.preventDefault()\n const node = $getNodeByKey(nodeKey)\n if ($isRelationshipNode(node)) {\n node.remove()\n return true\n }\n }\n return false\n },\n [isSelected, nodeKey],\n )\n const onClick = useCallback(\n (payload: MouseEvent) => {\n const event = payload\n // Check if relationshipElemRef.target or anything WITHIN relationshipElemRef.target was clicked\n if (\n event.target === relationshipElemRef.current ||\n relationshipElemRef.current?.contains(event.target as Node)\n ) {\n if (event.shiftKey) {\n setSelected(!isSelected)\n } else {\n if (!isSelected) {\n clearSelection()\n setSelected(true)\n }\n }\n return true\n }\n\n return false\n },\n [isSelected, setSelected, clearSelection],\n )\n\n useEffect(() => {\n return mergeRegister(\n editor.registerCommand<MouseEvent>(CLICK_COMMAND, onClick, COMMAND_PRIORITY_LOW),\n\n editor.registerCommand(KEY_DELETE_COMMAND, onDelete, COMMAND_PRIORITY_LOW),\n editor.registerCommand(KEY_BACKSPACE_COMMAND, onDelete, COMMAND_PRIORITY_LOW),\n )\n }, [clearSelection, editor, isSelected, nodeKey, onDelete, setSelected, onClick])\n\n return (\n <div\n className={[baseClass, isSelected && `${baseClass}--selected`].filter(Boolean).join(' ')}\n contentEditable={false}\n ref={relationshipElemRef}\n >\n <div className={`${baseClass}__wrap`}>\n <p className={`${baseClass}__label`}>\n {t('fields:labelRelationship', {\n label: getTranslation(relatedCollection.labels.singular, i18n),\n })}\n </p>\n <DocumentDrawerToggler className={`${baseClass}__doc-drawer-toggler`}>\n <p className={`${baseClass}__title`}>\n {data ? data[relatedCollection?.admin?.useAsTitle || 'id'] : id}\n </p>\n </DocumentDrawerToggler>\n </div>\n {editor.isEditable() && (\n <div className={`${baseClass}__actions`}>\n <Button\n buttonStyle=\"icon-label\"\n className={`${baseClass}__swapButton`}\n disabled={field?.readOnly}\n el=\"div\"\n icon=\"swap\"\n onClick={() => {\n editor.dispatchCommand(INSERT_RELATIONSHIP_WITH_DRAWER_COMMAND, {\n replace: { nodeKey },\n })\n }}\n round\n tooltip={t('fields:swapRelationship')}\n />\n <Button\n buttonStyle=\"icon-label\"\n className={`${baseClass}__removeButton`}\n disabled={field?.readOnly}\n icon=\"x\"\n onClick={(e) => {\n e.preventDefault()\n removeRelationship()\n }}\n round\n tooltip={t('fields:removeRelationship')}\n />\n </div>\n )}\n\n {id && <DocumentDrawer onSave={updateRelationship} />}\n {children}\n </div>\n )\n}\n\nexport const RelationshipComponent = (props: Props): React.ReactNode => {\n return <Component {...props} />\n}\n"],"names":["useLexicalComposerContext","useLexicalNodeSelection","mergeRegister","getTranslation","Button","useDocumentDrawer","usePayloadAPI","useConfig","useTranslation","$getSelection","$isNodeSelection","CLICK_COMMAND","COMMAND_PRIORITY_LOW","KEY_BACKSPACE_COMMAND","KEY_DELETE_COMMAND","$getNodeByKey","React","useCallback","useEffect","useReducer","useRef","useState","useEditorConfigContext","INSERT_RELATIONSHIP_WITH_DRAWER_COMMAND","$isRelationshipNode","baseClass","initialParams","depth","Component","props","children","data","relationTo","value","id","nodeKey","relationshipElemRef","editor","isSelected","setSelected","clearSelection","field","collections","routes","api","serverURL","relatedCollection","setRelatedCollection","find","coll","slug","i18n","t","cacheBust","dispatchCacheBust","state","setParams","DocumentDrawer","DocumentDrawerToggler","closeDrawer","collectionSlug","removeRelationship","update","remove","updateRelationship","doc","onDelete","payload","event","preventDefault","node","onClick","target","current","contains","shiftKey","registerCommand","div","className","filter","Boolean","join","contentEditable","ref","p","label","labels","singular","admin","useAsTitle","isEditable","buttonStyle","disabled","readOnly","el","icon","dispatchCommand","replace","round","tooltip","e","onSave","RelationshipComponent"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../src/field/features/relationship/nodes/components/RelationshipComponent.tsx"],"sourcesContent":["'use client'\nimport type { ElementFormatType } from 'lexical'\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'\nimport { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection.js'\nimport { mergeRegister } from '@lexical/utils'\nimport { getTranslation } from '@payloadcms/translations'\nimport { Button } from '@payloadcms/ui/elements/Button'\nimport { useDocumentDrawer } from '@payloadcms/ui/elements/DocumentDrawer'\nimport usePayloadAPI from '@payloadcms/ui/hooks/usePayloadAPI'\nimport { useConfig } from '@payloadcms/ui/providers/Config'\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport {\n $getSelection,\n $isNodeSelection,\n CLICK_COMMAND,\n COMMAND_PRIORITY_LOW,\n KEY_BACKSPACE_COMMAND,\n KEY_DELETE_COMMAND,\n} from 'lexical'\nimport { $getNodeByKey } from 'lexical'\nimport React, { useCallback, useEffect, useReducer, useRef, useState } from 'react'\n\nimport type { RelationshipData } from '../RelationshipNode.js'\n\nimport { useEditorConfigContext } from '../../../../lexical/config/client/EditorConfigProvider.js'\nimport { INSERT_RELATIONSHIP_WITH_DRAWER_COMMAND } from '../../drawer/commands.js'\nimport { $isRelationshipNode } from '../RelationshipNode.js'\nimport './index.scss'\n\nconst baseClass = 'lexical-relationship'\n\nconst initialParams = {\n depth: 0,\n}\n\ntype Props = {\n children?: React.ReactNode\n className?: string\n data: RelationshipData\n format?: ElementFormatType\n nodeKey?: string\n}\n\nconst Component: React.FC<Props> = (props) => {\n const {\n children,\n data: { relationTo, value: id },\n nodeKey,\n } = props\n\n const relationshipElemRef = useRef<HTMLDivElement | null>(null)\n\n const [editor] = useLexicalComposerContext()\n const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey)\n const { field } = useEditorConfigContext()\n const {\n collections,\n routes: { api },\n serverURL,\n } = useConfig()\n\n const [relatedCollection, setRelatedCollection] = useState(() =>\n collections.find((coll) => coll.slug === relationTo),\n )\n\n const { i18n, t } = useTranslation()\n const [cacheBust, dispatchCacheBust] = useReducer((state) => state + 1, 0)\n const [{ data }, { setParams }] = usePayloadAPI(\n `${serverURL}${api}/${relatedCollection.slug}/${id}`,\n { initialParams },\n )\n\n const [DocumentDrawer, DocumentDrawerToggler, { closeDrawer }] = useDocumentDrawer({\n id,\n collectionSlug: relatedCollection.slug,\n })\n\n const removeRelationship = useCallback(() => {\n editor.update(() => {\n $getNodeByKey(nodeKey).remove()\n })\n }, [editor, nodeKey])\n\n const updateRelationship = React.useCallback(\n ({ doc }) => {\n setParams({\n ...initialParams,\n cacheBust, // do this to get the usePayloadAPI to re-fetch the data even though the URL string hasn't changed\n })\n\n closeDrawer()\n dispatchCacheBust()\n },\n [cacheBust, setParams, closeDrawer],\n )\n\n const $onDelete = useCallback(\n (payload: KeyboardEvent) => {\n if (isSelected && $isNodeSelection($getSelection())) {\n const event: KeyboardEvent = payload\n event.preventDefault()\n const node = $getNodeByKey(nodeKey)\n if ($isRelationshipNode(node)) {\n node.remove()\n return true\n }\n }\n return false\n },\n [isSelected, nodeKey],\n )\n const onClick = useCallback(\n (payload: MouseEvent) => {\n const event = payload\n // Check if relationshipElemRef.target or anything WITHIN relationshipElemRef.target was clicked\n if (\n event.target === relationshipElemRef.current ||\n relationshipElemRef.current?.contains(event.target as Node)\n ) {\n if (event.shiftKey) {\n setSelected(!isSelected)\n } else {\n if (!isSelected) {\n clearSelection()\n setSelected(true)\n }\n }\n return true\n }\n\n return false\n },\n [isSelected, setSelected, clearSelection],\n )\n\n useEffect(() => {\n return mergeRegister(\n editor.registerCommand<MouseEvent>(CLICK_COMMAND, onClick, COMMAND_PRIORITY_LOW),\n\n editor.registerCommand(KEY_DELETE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW),\n editor.registerCommand(KEY_BACKSPACE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW),\n )\n }, [clearSelection, editor, isSelected, nodeKey, $onDelete, setSelected, onClick])\n\n return (\n <div\n className={[baseClass, isSelected && `${baseClass}--selected`].filter(Boolean).join(' ')}\n contentEditable={false}\n ref={relationshipElemRef}\n >\n <div className={`${baseClass}__wrap`}>\n <p className={`${baseClass}__label`}>\n {t('fields:labelRelationship', {\n label: getTranslation(relatedCollection.labels.singular, i18n),\n })}\n </p>\n <DocumentDrawerToggler className={`${baseClass}__doc-drawer-toggler`}>\n <p className={`${baseClass}__title`}>\n {data ? data[relatedCollection?.admin?.useAsTitle || 'id'] : id}\n </p>\n </DocumentDrawerToggler>\n </div>\n {editor.isEditable() && (\n <div className={`${baseClass}__actions`}>\n <Button\n buttonStyle=\"icon-label\"\n className={`${baseClass}__swapButton`}\n disabled={field?.readOnly}\n el=\"div\"\n icon=\"swap\"\n onClick={() => {\n editor.dispatchCommand(INSERT_RELATIONSHIP_WITH_DRAWER_COMMAND, {\n replace: { nodeKey },\n })\n }}\n round\n tooltip={t('fields:swapRelationship')}\n />\n <Button\n buttonStyle=\"icon-label\"\n className={`${baseClass}__removeButton`}\n disabled={field?.readOnly}\n icon=\"x\"\n onClick={(e) => {\n e.preventDefault()\n removeRelationship()\n }}\n round\n tooltip={t('fields:removeRelationship')}\n />\n </div>\n )}\n\n {id && <DocumentDrawer onSave={updateRelationship} />}\n {children}\n </div>\n )\n}\n\nexport const RelationshipComponent = (props: Props): React.ReactNode => {\n return <Component {...props} />\n}\n"],"names":["useLexicalComposerContext","useLexicalNodeSelection","mergeRegister","getTranslation","Button","useDocumentDrawer","usePayloadAPI","useConfig","useTranslation","$getSelection","$isNodeSelection","CLICK_COMMAND","COMMAND_PRIORITY_LOW","KEY_BACKSPACE_COMMAND","KEY_DELETE_COMMAND","$getNodeByKey","React","useCallback","useEffect","useReducer","useRef","useState","useEditorConfigContext","INSERT_RELATIONSHIP_WITH_DRAWER_COMMAND","$isRelationshipNode","baseClass","initialParams","depth","Component","props","children","data","relationTo","value","id","nodeKey","relationshipElemRef","editor","isSelected","setSelected","clearSelection","field","collections","routes","api","serverURL","relatedCollection","setRelatedCollection","find","coll","slug","i18n","t","cacheBust","dispatchCacheBust","state","setParams","DocumentDrawer","DocumentDrawerToggler","closeDrawer","collectionSlug","removeRelationship","update","remove","updateRelationship","doc","$onDelete","payload","event","preventDefault","node","onClick","target","current","contains","shiftKey","registerCommand","div","className","filter","Boolean","join","contentEditable","ref","p","label","labels","singular","admin","useAsTitle","isEditable","buttonStyle","disabled","readOnly","el","icon","dispatchCommand","replace","round","tooltip","e","onSave","RelationshipComponent"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;AAGA,SAASA,yBAAyB,QAAQ,2CAA0C;AACpF,SAASC,uBAAuB,QAAQ,4CAA2C;AACnF,SAASC,aAAa,QAAQ,iBAAgB;AAC9C,SAASC,cAAc,QAAQ,2BAA0B;AACzD,SAASC,MAAM,QAAQ,iCAAgC;AACvD,SAASC,iBAAiB,QAAQ,yCAAwC;AAC1E,OAAOC,mBAAmB,qCAAoC;AAC9D,SAASC,SAAS,QAAQ,kCAAiC;AAC3D,SAASC,cAAc,QAAQ,uCAAsC;AACrE,SACEC,aAAa,EACbC,gBAAgB,EAChBC,aAAa,EACbC,oBAAoB,EACpBC,qBAAqB,EACrBC,kBAAkB,QACb,UAAS;AAChB,SAASC,aAAa,QAAQ,UAAS;AACvC,OAAOC,SAASC,WAAW,EAAEC,SAAS,EAAEC,UAAU,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAInF,SAASC,sBAAsB,QAAQ,4DAA2D;AAClG,SAASC,uCAAuC,QAAQ,2BAA0B;AAClF,SAASC,mBAAmB,QAAQ,yBAAwB;AAC5D,OAAO,eAAc;AAErB,MAAMC,YAAY;AAElB,MAAMC,gBAAgB;IACpBC,OAAO;AACT;AAUA,MAAMC,YAA6B,CAACC;IAClC,MAAM,EACJC,QAAQ,EACRC,MAAM,EAAEC,UAAU,EAAEC,OAAOC,EAAE,EAAE,EAC/BC,OAAO,EACR,GAAGN;IAEJ,MAAMO,sBAAsBhB,OAA8B;IAE1D,MAAM,CAACiB,OAAO,GAAGrC;IACjB,MAAM,CAACsC,YAAYC,aAAaC,eAAe,GAAGvC,wBAAwBkC;IAC1E,MAAM,EAAEM,KAAK,EAAE,GAAGnB;IAClB,MAAM,EACJoB,WAAW,EACXC,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,GAAGtC;IAEJ,MAAM,CAACuC,mBAAmBC,qBAAqB,GAAG1B,SAAS,IACzDqB,YAAYM,IAAI,CAAC,CAACC,OAASA,KAAKC,IAAI,KAAKlB;IAG3C,MAAM,EAAEmB,IAAI,EAAEC,CAAC,EAAE,GAAG5C;IACpB,MAAM,CAAC6C,WAAWC,kBAAkB,GAAGnC,WAAW,CAACoC,QAAUA,QAAQ,GAAG;IACxE,MAAM,CAAC,EAAExB,IAAI,EAAE,EAAE,EAAEyB,SAAS,EAAE,CAAC,GAAGlD,cAChC,CAAC,EAAEuC,UAAU,EAAED,IAAI,CAAC,EAAEE,kBAAkBI,IAAI,CAAC,CAAC,EAAEhB,GAAG,CAAC,EACpD;QAAER;IAAc;IAGlB,MAAM,CAAC+B,gBAAgBC,uBAAuB,EAAEC,WAAW,EAAE,CAAC,GAAGtD,kBAAkB;QACjF6B;QACA0B,gBAAgBd,kBAAkBI,IAAI;IACxC;IAEA,MAAMW,qBAAqB5C,YAAY;QACrCoB,OAAOyB,MAAM,CAAC;YACZ/C,cAAcoB,SAAS4B,MAAM;QAC/B;IACF,GAAG;QAAC1B;QAAQF;KAAQ;IAEpB,MAAM6B,qBAAqBhD,MAAMC,WAAW,CAC1C,CAAC,EAAEgD,GAAG,EAAE;QACNT,UAAU;YACR,GAAG9B,aAAa;YAChB2B;QACF;QAEAM;QACAL;IACF,GACA;QAACD;QAAWG;QAAWG;KAAY;IAGrC,MAAMO,YAAYjD,YAChB,CAACkD;QACC,IAAI7B,cAAc5B,iBAAiBD,kBAAkB;YACnD,MAAM2D,QAAuBD;YAC7BC,MAAMC,cAAc;YACpB,MAAMC,OAAOvD,cAAcoB;YAC3B,IAAIX,oBAAoB8C,OAAO;gBAC7BA,KAAKP,MAAM;gBACX,OAAO;YACT;QACF;QACA,OAAO;IACT,GACA;QAACzB;QAAYH;KAAQ;IAEvB,MAAMoC,UAAUtD,YACd,CAACkD;QACC,MAAMC,QAAQD;QACd,gGAAgG;QAChG,IACEC,MAAMI,MAAM,KAAKpC,oBAAoBqC,OAAO,IAC5CrC,oBAAoBqC,OAAO,EAAEC,SAASN,MAAMI,MAAM,GAClD;YACA,IAAIJ,MAAMO,QAAQ,EAAE;gBAClBpC,YAAY,CAACD;YACf,OAAO;gBACL,IAAI,CAACA,YAAY;oBACfE;oBACAD,YAAY;gBACd;YACF;YACA,OAAO;QACT;QAEA,OAAO;IACT,GACA;QAACD;QAAYC;QAAaC;KAAe;IAG3CtB,UAAU;QACR,OAAOhB,cACLmC,OAAOuC,eAAe,CAAajE,eAAe4D,SAAS3D,uBAE3DyB,OAAOuC,eAAe,CAAC9D,oBAAoBoD,WAAWtD,uBACtDyB,OAAOuC,eAAe,CAAC/D,uBAAuBqD,WAAWtD;IAE7D,GAAG;QAAC4B;QAAgBH;QAAQC;QAAYH;QAAS+B;QAAW3B;QAAagC;KAAQ;IAEjF,qBACE,oBAACM;QACCC,WAAW;YAACrD;YAAWa,cAAc,CAAC,EAAEb,UAAU,UAAU,CAAC;SAAC,CAACsD,MAAM,CAACC,SAASC,IAAI,CAAC;QACpFC,iBAAiB;QACjBC,KAAK/C;qBAEL,oBAACyC;QAAIC,WAAW,CAAC,EAAErD,UAAU,MAAM,CAAC;qBAClC,oBAAC2D;QAAEN,WAAW,CAAC,EAAErD,UAAU,OAAO,CAAC;OAChC2B,EAAE,4BAA4B;QAC7BiC,OAAOlF,eAAe2C,kBAAkBwC,MAAM,CAACC,QAAQ,EAAEpC;IAC3D,mBAEF,oBAACO;QAAsBoB,WAAW,CAAC,EAAErD,UAAU,oBAAoB,CAAC;qBAClE,oBAAC2D;QAAEN,WAAW,CAAC,EAAErD,UAAU,OAAO,CAAC;OAChCM,OAAOA,IAAI,CAACe,mBAAmB0C,OAAOC,cAAc,KAAK,GAAGvD,OAIlEG,OAAOqD,UAAU,oBAChB,oBAACb;QAAIC,WAAW,CAAC,EAAErD,UAAU,SAAS,CAAC;qBACrC,oBAACrB;QACCuF,aAAY;QACZb,WAAW,CAAC,EAAErD,UAAU,YAAY,CAAC;QACrCmE,UAAUnD,OAAOoD;QACjBC,IAAG;QACHC,MAAK;QACLxB,SAAS;YACPlC,OAAO2D,eAAe,CAACzE,yCAAyC;gBAC9D0E,SAAS;oBAAE9D;gBAAQ;YACrB;QACF;QACA+D,OAAAA;QACAC,SAAS/C,EAAE;sBAEb,oBAAChD;QACCuF,aAAY;QACZb,WAAW,CAAC,EAAErD,UAAU,cAAc,CAAC;QACvCmE,UAAUnD,OAAOoD;QACjBE,MAAK;QACLxB,SAAS,CAAC6B;YACRA,EAAE/B,cAAc;YAChBR;QACF;QACAqC,OAAAA;QACAC,SAAS/C,EAAE;SAKhBlB,oBAAM,oBAACuB;QAAe4C,QAAQrC;QAC9BlC;AAGP;AAEA,OAAO,MAAMwE,wBAAwB,CAACzE;IACpC,qBAAO,oBAACD,WAAcC;AACxB,EAAC"}
@@ -24,9 +24,11 @@ export const RelationshipPlugin = ({ clientProps })=>{
24
24
  throw new Error('RelationshipPlugin: RelationshipNode not registered on editor');
25
25
  }
26
26
  return editor.registerCommand(INSERT_RELATIONSHIP_COMMAND, (payload)=>{
27
- const relationshipNode = $createRelationshipNode(payload);
28
27
  const selection = $getSelection() || $getPreviousSelection();
29
28
  if ($isRangeSelection(selection)) {
29
+ const relationshipNode = $createRelationshipNode(payload);
30
+ // Insert relationship node BEFORE potentially removing focusNode, as $insertNodeToNearestRoot errors if the focusNode doesn't exist
31
+ $insertNodeToNearestRoot(relationshipNode);
30
32
  const { focus } = selection;
31
33
  const focusNode = focus.getNode();
32
34
  // First, delete currently selected node if it's an empty paragraph and if there are sufficient
@@ -34,7 +36,6 @@ export const RelationshipPlugin = ({ clientProps })=>{
34
36
  if ($isParagraphNode(focusNode) && focusNode.getTextContentSize() === 0 && focusNode.getParent().getChildren().filter((node)=>$isParagraphNode(node)).length > 1) {
35
37
  focusNode.remove();
36
38
  }
37
- $insertNodeToNearestRoot(relationshipNode);
38
39
  }
39
40
  return true;
40
41
  }, COMMAND_PRIORITY_EDITOR);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/field/features/relationship/plugins/index.tsx"],"sourcesContent":["'use client'\nimport type { LexicalCommand } from 'lexical'\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'\nimport { $insertNodeToNearestRoot } from '@lexical/utils'\nimport { useConfig } from '@payloadcms/ui/providers/Config'\nimport {\n $getPreviousSelection,\n $getSelection,\n $isParagraphNode,\n $isRangeSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from 'lexical'\nimport { useEffect } from 'react'\nimport React from 'react'\n\nimport type { PluginComponent } from '../../types.js'\nimport type { RelationshipFeatureProps } from '../feature.server.js'\nimport type { RelationshipData } from '../nodes/RelationshipNode.js'\n\nimport { RelationshipDrawer } from '../drawer/index.js'\nimport { $createRelationshipNode, RelationshipNode } from '../nodes/RelationshipNode.js'\n\nexport const INSERT_RELATIONSHIP_COMMAND: LexicalCommand<RelationshipData> = createCommand(\n 'INSERT_RELATIONSHIP_COMMAND',\n)\n\nexport const RelationshipPlugin: PluginComponent<RelationshipFeatureProps> = ({ clientProps }) => {\n const [editor] = useLexicalComposerContext()\n const { collections } = useConfig()\n\n let enabledRelations: string[] = null\n\n if (clientProps?.enabledCollections) {\n enabledRelations = clientProps?.enabledCollections\n } else if (clientProps?.disabledCollections) {\n enabledRelations = collections\n .filter(({ slug }) => !clientProps?.disabledCollections?.includes(slug))\n .map(({ slug }) => slug)\n }\n\n useEffect(() => {\n if (!editor.hasNodes([RelationshipNode])) {\n throw new Error('RelationshipPlugin: RelationshipNode not registered on editor')\n }\n\n return editor.registerCommand<RelationshipData>(\n INSERT_RELATIONSHIP_COMMAND,\n (payload) => {\n const relationshipNode = $createRelationshipNode(payload)\n\n const selection = $getSelection() || $getPreviousSelection()\n\n if ($isRangeSelection(selection)) {\n const { focus } = selection\n const focusNode = focus.getNode()\n\n // First, delete currently selected node if it's an empty paragraph and if there are sufficient\n // paragraph nodes (more than 1) left in the parent node, so that we don't \"trap\" the user\n if (\n $isParagraphNode(focusNode) &&\n focusNode.getTextContentSize() === 0 &&\n focusNode\n .getParent()\n .getChildren()\n .filter((node) => $isParagraphNode(node)).length > 1\n ) {\n focusNode.remove()\n }\n\n $insertNodeToNearestRoot(relationshipNode)\n }\n\n return true\n },\n COMMAND_PRIORITY_EDITOR,\n )\n }, [editor])\n\n return <RelationshipDrawer enabledCollectionSlugs={enabledRelations} />\n}\n"],"names":["useLexicalComposerContext","$insertNodeToNearestRoot","useConfig","$getPreviousSelection","$getSelection","$isParagraphNode","$isRangeSelection","COMMAND_PRIORITY_EDITOR","createCommand","useEffect","React","RelationshipDrawer","$createRelationshipNode","RelationshipNode","INSERT_RELATIONSHIP_COMMAND","RelationshipPlugin","clientProps","editor","collections","enabledRelations","enabledCollections","disabledCollections","filter","slug","includes","map","hasNodes","Error","registerCommand","payload","relationshipNode","selection","focus","focusNode","getNode","getTextContentSize","getParent","getChildren","node","length","remove","enabledCollectionSlugs"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;AAGA,SAASA,yBAAyB,QAAQ,2CAA0C;AACpF,SAASC,wBAAwB,QAAQ,iBAAgB;AACzD,SAASC,SAAS,QAAQ,kCAAiC;AAC3D,SACEC,qBAAqB,EACrBC,aAAa,EACbC,gBAAgB,EAChBC,iBAAiB,EACjBC,uBAAuB,EACvBC,aAAa,QACR,UAAS;AAChB,SAASC,SAAS,QAAQ,QAAO;AACjC,OAAOC,WAAW,QAAO;AAMzB,SAASC,kBAAkB,QAAQ,qBAAoB;AACvD,SAASC,uBAAuB,EAAEC,gBAAgB,QAAQ,+BAA8B;AAExF,OAAO,MAAMC,8BAAgEN,cAC3E,+BACD;AAED,OAAO,MAAMO,qBAAgE,CAAC,EAAEC,WAAW,EAAE;IAC3F,MAAM,CAACC,OAAO,GAAGjB;IACjB,MAAM,EAAEkB,WAAW,EAAE,GAAGhB;IAExB,IAAIiB,mBAA6B;IAEjC,IAAIH,aAAaI,oBAAoB;QACnCD,mBAAmBH,aAAaI;IAClC,OAAO,IAAIJ,aAAaK,qBAAqB;QAC3CF,mBAAmBD,YAChBI,MAAM,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAK,CAACP,aAAaK,qBAAqBG,SAASD,OACjEE,GAAG,CAAC,CAAC,EAAEF,IAAI,EAAE,GAAKA;IACvB;IAEAd,UAAU;QACR,IAAI,CAACQ,OAAOS,QAAQ,CAAC;YAACb;SAAiB,GAAG;YACxC,MAAM,IAAIc,MAAM;QAClB;QAEA,OAAOV,OAAOW,eAAe,CAC3Bd,6BACA,CAACe;YACC,MAAMC,mBAAmBlB,wBAAwBiB;YAEjD,MAAME,YAAY3B,mBAAmBD;YAErC,IAAIG,kBAAkByB,YAAY;gBAChC,MAAM,EAAEC,KAAK,EAAE,GAAGD;gBAClB,MAAME,YAAYD,MAAME,OAAO;gBAE/B,+FAA+F;gBAC/F,0FAA0F;gBAC1F,IACE7B,iBAAiB4B,cACjBA,UAAUE,kBAAkB,OAAO,KACnCF,UACGG,SAAS,GACTC,WAAW,GACXf,MAAM,CAAC,CAACgB,OAASjC,iBAAiBiC,OAAOC,MAAM,GAAG,GACrD;oBACAN,UAAUO,MAAM;gBAClB;gBAEAvC,yBAAyB6B;YAC3B;YAEA,OAAO;QACT,GACAvB;IAEJ,GAAG;QAACU;KAAO;IAEX,qBAAO,oBAACN;QAAmB8B,wBAAwBtB;;AACrD,EAAC"}
1
+ {"version":3,"sources":["../../../../../src/field/features/relationship/plugins/index.tsx"],"sourcesContent":["'use client'\nimport type { LexicalCommand } from 'lexical'\n\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'\nimport { $insertNodeToNearestRoot } from '@lexical/utils'\nimport { useConfig } from '@payloadcms/ui/providers/Config'\nimport {\n $getPreviousSelection,\n $getSelection,\n $isParagraphNode,\n $isRangeSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from 'lexical'\nimport { useEffect } from 'react'\nimport React from 'react'\n\nimport type { PluginComponent } from '../../types.js'\nimport type { RelationshipFeatureProps } from '../feature.server.js'\nimport type { RelationshipData } from '../nodes/RelationshipNode.js'\n\nimport { RelationshipDrawer } from '../drawer/index.js'\nimport { $createRelationshipNode, RelationshipNode } from '../nodes/RelationshipNode.js'\n\nexport const INSERT_RELATIONSHIP_COMMAND: LexicalCommand<RelationshipData> = createCommand(\n 'INSERT_RELATIONSHIP_COMMAND',\n)\n\nexport const RelationshipPlugin: PluginComponent<RelationshipFeatureProps> = ({ clientProps }) => {\n const [editor] = useLexicalComposerContext()\n const { collections } = useConfig()\n\n let enabledRelations: string[] = null\n\n if (clientProps?.enabledCollections) {\n enabledRelations = clientProps?.enabledCollections\n } else if (clientProps?.disabledCollections) {\n enabledRelations = collections\n .filter(({ slug }) => !clientProps?.disabledCollections?.includes(slug))\n .map(({ slug }) => slug)\n }\n\n useEffect(() => {\n if (!editor.hasNodes([RelationshipNode])) {\n throw new Error('RelationshipPlugin: RelationshipNode not registered on editor')\n }\n\n return editor.registerCommand<RelationshipData>(\n INSERT_RELATIONSHIP_COMMAND,\n (payload) => {\n const selection = $getSelection() || $getPreviousSelection()\n\n if ($isRangeSelection(selection)) {\n const relationshipNode = $createRelationshipNode(payload)\n // Insert relationship node BEFORE potentially removing focusNode, as $insertNodeToNearestRoot errors if the focusNode doesn't exist\n $insertNodeToNearestRoot(relationshipNode)\n\n const { focus } = selection\n const focusNode = focus.getNode()\n\n // First, delete currently selected node if it's an empty paragraph and if there are sufficient\n // paragraph nodes (more than 1) left in the parent node, so that we don't \"trap\" the user\n if (\n $isParagraphNode(focusNode) &&\n focusNode.getTextContentSize() === 0 &&\n focusNode\n .getParent()\n .getChildren()\n .filter((node) => $isParagraphNode(node)).length > 1\n ) {\n focusNode.remove()\n }\n }\n\n return true\n },\n COMMAND_PRIORITY_EDITOR,\n )\n }, [editor])\n\n return <RelationshipDrawer enabledCollectionSlugs={enabledRelations} />\n}\n"],"names":["useLexicalComposerContext","$insertNodeToNearestRoot","useConfig","$getPreviousSelection","$getSelection","$isParagraphNode","$isRangeSelection","COMMAND_PRIORITY_EDITOR","createCommand","useEffect","React","RelationshipDrawer","$createRelationshipNode","RelationshipNode","INSERT_RELATIONSHIP_COMMAND","RelationshipPlugin","clientProps","editor","collections","enabledRelations","enabledCollections","disabledCollections","filter","slug","includes","map","hasNodes","Error","registerCommand","payload","selection","relationshipNode","focus","focusNode","getNode","getTextContentSize","getParent","getChildren","node","length","remove","enabledCollectionSlugs"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;AAGA,SAASA,yBAAyB,QAAQ,2CAA0C;AACpF,SAASC,wBAAwB,QAAQ,iBAAgB;AACzD,SAASC,SAAS,QAAQ,kCAAiC;AAC3D,SACEC,qBAAqB,EACrBC,aAAa,EACbC,gBAAgB,EAChBC,iBAAiB,EACjBC,uBAAuB,EACvBC,aAAa,QACR,UAAS;AAChB,SAASC,SAAS,QAAQ,QAAO;AACjC,OAAOC,WAAW,QAAO;AAMzB,SAASC,kBAAkB,QAAQ,qBAAoB;AACvD,SAASC,uBAAuB,EAAEC,gBAAgB,QAAQ,+BAA8B;AAExF,OAAO,MAAMC,8BAAgEN,cAC3E,+BACD;AAED,OAAO,MAAMO,qBAAgE,CAAC,EAAEC,WAAW,EAAE;IAC3F,MAAM,CAACC,OAAO,GAAGjB;IACjB,MAAM,EAAEkB,WAAW,EAAE,GAAGhB;IAExB,IAAIiB,mBAA6B;IAEjC,IAAIH,aAAaI,oBAAoB;QACnCD,mBAAmBH,aAAaI;IAClC,OAAO,IAAIJ,aAAaK,qBAAqB;QAC3CF,mBAAmBD,YAChBI,MAAM,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAK,CAACP,aAAaK,qBAAqBG,SAASD,OACjEE,GAAG,CAAC,CAAC,EAAEF,IAAI,EAAE,GAAKA;IACvB;IAEAd,UAAU;QACR,IAAI,CAACQ,OAAOS,QAAQ,CAAC;YAACb;SAAiB,GAAG;YACxC,MAAM,IAAIc,MAAM;QAClB;QAEA,OAAOV,OAAOW,eAAe,CAC3Bd,6BACA,CAACe;YACC,MAAMC,YAAY1B,mBAAmBD;YAErC,IAAIG,kBAAkBwB,YAAY;gBAChC,MAAMC,mBAAmBnB,wBAAwBiB;gBACjD,oIAAoI;gBACpI5B,yBAAyB8B;gBAEzB,MAAM,EAAEC,KAAK,EAAE,GAAGF;gBAClB,MAAMG,YAAYD,MAAME,OAAO;gBAE/B,+FAA+F;gBAC/F,0FAA0F;gBAC1F,IACE7B,iBAAiB4B,cACjBA,UAAUE,kBAAkB,OAAO,KACnCF,UACGG,SAAS,GACTC,WAAW,GACXf,MAAM,CAAC,CAACgB,OAASjC,iBAAiBiC,OAAOC,MAAM,GAAG,GACrD;oBACAN,UAAUO,MAAM;gBAClB;YACF;YAEA,OAAO;QACT,GACAjC;IAEJ,GAAG;QAACU;KAAO;IAEX,qBAAO,oBAACN;QAAmB8B,wBAAwBtB;;AACrD,EAAC"}
@@ -47,6 +47,7 @@ html[data-theme='dark'] {
47
47
  .fixed-toolbar {
48
48
  @include blur-bg(var(--theme-elevation-0));
49
49
  display: flex;
50
+ flex-wrap: wrap;
50
51
  align-items: center;
51
52
  padding: calc(var(--base) / 4);
52
53
  vertical-align: middle;
@@ -83,9 +84,15 @@ html[data-theme='dark'] {
83
84
  }
84
85
  }
85
86
 
86
- + .editor-scroller {
87
- .ContentEditable__root {
87
+ + .editor-container {
88
+ > .editor-scroller > .editor > .ContentEditable__root {
88
89
  padding-top: calc(var(--base) * 1.25);
89
90
  }
91
+
92
+ > .editor-placeholder {
93
+ top: calc(var(--base) * 1.25);
94
+ }
90
95
  }
96
+
97
+
91
98
  }
@@ -9,7 +9,7 @@ const FixedToolbarFeatureClient = (props)=>{
9
9
  plugins: [
10
10
  {
11
11
  Component: FixedToolbarPlugin,
12
- position: 'top'
12
+ position: 'aboveContainer'
13
13
  }
14
14
  ]
15
15
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/field/features/toolbars/fixed/feature.client.tsx"],"sourcesContent":["'use client'\n\nimport type { FeatureProviderProviderClient } from '../../types.js'\n\nimport { createClientComponent } from '../../createClientComponent.js'\nimport { FixedToolbarPlugin } from './Toolbar/index.js'\n\nconst FixedToolbarFeatureClient: FeatureProviderProviderClient<undefined> = (props) => {\n return {\n clientFeatureProps: props,\n feature: () => ({\n clientFeatureProps: props,\n plugins: [\n {\n Component: FixedToolbarPlugin,\n position: 'top',\n },\n ],\n }),\n }\n}\n\nexport const FixedToolbarFeatureClientComponent = createClientComponent(FixedToolbarFeatureClient)\n"],"names":["createClientComponent","FixedToolbarPlugin","FixedToolbarFeatureClient","props","clientFeatureProps","feature","plugins","Component","position","FixedToolbarFeatureClientComponent"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AAAA;AAIA,SAASA,qBAAqB,QAAQ,iCAAgC;AACtE,SAASC,kBAAkB,QAAQ,qBAAoB;AAEvD,MAAMC,4BAAsE,CAACC;IAC3E,OAAO;QACLC,oBAAoBD;QACpBE,SAAS,IAAO,CAAA;gBACdD,oBAAoBD;gBACpBG,SAAS;oBACP;wBACEC,WAAWN;wBACXO,UAAU;oBACZ;iBACD;YACH,CAAA;IACF;AACF;AAEA,OAAO,MAAMC,qCAAqCT,sBAAsBE,2BAA0B"}
1
+ {"version":3,"sources":["../../../../../src/field/features/toolbars/fixed/feature.client.tsx"],"sourcesContent":["'use client'\n\nimport type { FeatureProviderProviderClient } from '../../types.js'\n\nimport { createClientComponent } from '../../createClientComponent.js'\nimport { FixedToolbarPlugin } from './Toolbar/index.js'\n\nconst FixedToolbarFeatureClient: FeatureProviderProviderClient<undefined> = (props) => {\n return {\n clientFeatureProps: props,\n feature: () => ({\n clientFeatureProps: props,\n plugins: [\n {\n Component: FixedToolbarPlugin,\n position: 'aboveContainer',\n },\n ],\n }),\n }\n}\n\nexport const FixedToolbarFeatureClientComponent = createClientComponent(FixedToolbarFeatureClient)\n"],"names":["createClientComponent","FixedToolbarPlugin","FixedToolbarFeatureClient","props","clientFeatureProps","feature","plugins","Component","position","FixedToolbarFeatureClientComponent"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AAAA;AAIA,SAASA,qBAAqB,QAAQ,iCAAgC;AACtE,SAASC,kBAAkB,QAAQ,qBAAoB;AAEvD,MAAMC,4BAAsE,CAACC;IAC3E,OAAO;QACLC,oBAAoBD;QACpBE,SAAS,IAAO,CAAA;gBACdD,oBAAoBD;gBACpBG,SAAS;oBACP;wBACEC,WAAWN;wBACXO,UAAU;oBACZ;iBACD;YACH,CAAA;IACF;AACF;AAEA,OAAO,MAAMC,qCAAqCT,sBAAsBE,2BAA0B"}
@@ -137,7 +137,7 @@ function InlineToolbar({ anchorElem, editor }) {
137
137
  mouseMoveListener,
138
138
  mouseUpListener
139
139
  ]);
140
- const updateTextFormatFloatingToolbar = useCallback(()=>{
140
+ const $updateTextFormatFloatingToolbar = useCallback(()=>{
141
141
  const selection = $getSelection();
142
142
  const nativeSelection = window.getSelection();
143
143
  if (floatingToolbarRef.current === null) {
@@ -181,7 +181,7 @@ function InlineToolbar({ anchorElem, editor }) {
181
181
  const scrollerElem = anchorElem.parentElement;
182
182
  const update = ()=>{
183
183
  editor.getEditorState().read(()=>{
184
- updateTextFormatFloatingToolbar();
184
+ $updateTextFormatFloatingToolbar();
185
185
  });
186
186
  };
187
187
  window.addEventListener('resize', update);
@@ -196,24 +196,24 @@ function InlineToolbar({ anchorElem, editor }) {
196
196
  };
197
197
  }, [
198
198
  editor,
199
- updateTextFormatFloatingToolbar,
199
+ $updateTextFormatFloatingToolbar,
200
200
  anchorElem
201
201
  ]);
202
202
  useEffect(()=>{
203
203
  editor.getEditorState().read(()=>{
204
- updateTextFormatFloatingToolbar();
204
+ $updateTextFormatFloatingToolbar();
205
205
  });
206
206
  return mergeRegister(editor.registerUpdateListener(({ editorState })=>{
207
207
  editorState.read(()=>{
208
- updateTextFormatFloatingToolbar();
208
+ $updateTextFormatFloatingToolbar();
209
209
  });
210
210
  }), editor.registerCommand(SELECTION_CHANGE_COMMAND, ()=>{
211
- updateTextFormatFloatingToolbar();
211
+ $updateTextFormatFloatingToolbar();
212
212
  return false;
213
213
  }, COMMAND_PRIORITY_LOW));
214
214
  }, [
215
215
  editor,
216
- updateTextFormatFloatingToolbar
216
+ $updateTextFormatFloatingToolbar
217
217
  ]);
218
218
  return /*#__PURE__*/ React.createElement("div", {
219
219
  className: "inline-toolbar-popup",