@liveblocks/react-ui 2.8.2 → 2.9.0-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Comment.js +1 -1
- package/dist/components/Comment.js.map +1 -1
- package/dist/components/Comment.mjs +1 -1
- package/dist/components/Comment.mjs.map +1 -1
- package/dist/components/InboxNotification.js +23 -16
- package/dist/components/InboxNotification.js.map +1 -1
- package/dist/components/InboxNotification.mjs +23 -16
- package/dist/components/InboxNotification.mjs.map +1 -1
- package/dist/components/InboxNotificationList.js +19 -2
- package/dist/components/InboxNotificationList.js.map +1 -1
- package/dist/components/InboxNotificationList.mjs +20 -3
- package/dist/components/InboxNotificationList.mjs.map +1 -1
- package/dist/components/internal/InboxNotificationThread.js +3 -0
- package/dist/components/internal/InboxNotificationThread.js.map +1 -1
- package/dist/components/internal/InboxNotificationThread.mjs +3 -0
- package/dist/components/internal/InboxNotificationThread.mjs.map +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/primitives/EmojiPicker/index.js +14 -3
- package/dist/primitives/EmojiPicker/index.js.map +1 -1
- package/dist/primitives/EmojiPicker/index.mjs +14 -3
- package/dist/primitives/EmojiPicker/index.mjs.map +1 -1
- package/dist/primitives/EmojiPicker/utils.js +3 -2
- package/dist/primitives/EmojiPicker/utils.js.map +1 -1
- package/dist/primitives/EmojiPicker/utils.mjs +3 -2
- package/dist/primitives/EmojiPicker/utils.mjs.map +1 -1
- package/dist/slate/plugins/auto-links.js +16 -9
- package/dist/slate/plugins/auto-links.js.map +1 -1
- package/dist/slate/plugins/auto-links.mjs +16 -9
- package/dist/slate/plugins/auto-links.mjs.map +1 -1
- package/dist/slate/plugins/paste.js.map +1 -1
- package/dist/slate/plugins/paste.mjs.map +1 -1
- package/dist/slate/utils/is-empty.js +1 -1
- package/dist/slate/utils/is-empty.js.map +1 -1
- package/dist/slate/utils/is-empty.mjs +1 -1
- package/dist/slate/utils/is-empty.mjs.map +1 -1
- package/dist/utils/find-last-index.js +2 -1
- package/dist/utils/find-last-index.js.map +1 -1
- package/dist/utils/find-last-index.mjs +2 -1
- package/dist/utils/find-last-index.mjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/package.json +4 -4
|
@@ -63,10 +63,12 @@ function isSeparator(char) {
|
|
|
63
63
|
return PUNCTUATION_OR_SPACE.test(char);
|
|
64
64
|
}
|
|
65
65
|
function endsWithSeparator(textContent) {
|
|
66
|
-
|
|
66
|
+
const lastCharacter = textContent[textContent.length - 1];
|
|
67
|
+
return lastCharacter !== void 0 ? isSeparator(lastCharacter) : false;
|
|
67
68
|
}
|
|
68
69
|
function startsWithSeparator(textContent) {
|
|
69
|
-
|
|
70
|
+
const firstCharacter = textContent[0];
|
|
71
|
+
return firstCharacter !== void 0 ? isSeparator(firstCharacter) : false;
|
|
70
72
|
}
|
|
71
73
|
function endsWithPeriodOrQuestionMark(textContent) {
|
|
72
74
|
return textContent[textContent.length - 1] === "." || textContent[textContent.length - 1] === "?";
|
|
@@ -106,8 +108,10 @@ function isNextNodeValid(editor, path) {
|
|
|
106
108
|
function isContentAroundValid(editor, entry, start, end) {
|
|
107
109
|
const [node, path] = entry;
|
|
108
110
|
const text = node.text;
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
+
const contentBefore = text[start - 1];
|
|
112
|
+
const contentBeforeIsValid = start > 0 && contentBefore ? isSeparator(contentBefore) : isPreviousNodeValid(editor, path);
|
|
113
|
+
const contentAfter = text[end];
|
|
114
|
+
const contentAfterIsValid = end < text.length && contentAfter ? isSeparator(contentAfter) : isNextNodeValid(editor, path);
|
|
111
115
|
return contentBeforeIsValid && contentAfterIsValid;
|
|
112
116
|
}
|
|
113
117
|
const handleLinkEdit = (editor, entry) => {
|
|
@@ -121,7 +125,8 @@ const handleLinkEdit = (editor, entry) => {
|
|
|
121
125
|
}
|
|
122
126
|
const text = slate.Node.string(node);
|
|
123
127
|
const match = URL_REGEX.exec(text);
|
|
124
|
-
|
|
128
|
+
const matchContent = match?.[0];
|
|
129
|
+
if (!match || matchContent !== text) {
|
|
125
130
|
slate.Transforms.unwrapNodes(editor, { at: path });
|
|
126
131
|
return;
|
|
127
132
|
}
|
|
@@ -171,24 +176,26 @@ const handleLinkEdit = (editor, entry) => {
|
|
|
171
176
|
return;
|
|
172
177
|
}
|
|
173
178
|
if (node.url !== text) {
|
|
174
|
-
slate.Transforms.setNodes(editor, { url:
|
|
179
|
+
slate.Transforms.setNodes(editor, { url: matchContent }, { at: path });
|
|
175
180
|
return;
|
|
176
181
|
}
|
|
177
182
|
};
|
|
178
183
|
const handleLinkCreate = (editor, entry) => {
|
|
179
184
|
const [node, path] = entry;
|
|
180
185
|
const match = URL_REGEX.exec(node.text);
|
|
181
|
-
|
|
186
|
+
const matchContent = match?.[0];
|
|
187
|
+
if (!match || matchContent === void 0) {
|
|
182
188
|
return;
|
|
189
|
+
}
|
|
183
190
|
const start = match.index;
|
|
184
|
-
const end = start +
|
|
191
|
+
const end = start + matchContent.length;
|
|
185
192
|
if (!isContentAroundValid(editor, entry, start, end))
|
|
186
193
|
return;
|
|
187
194
|
slate.Transforms.wrapNodes(
|
|
188
195
|
editor,
|
|
189
196
|
{
|
|
190
197
|
type: "auto-link",
|
|
191
|
-
url:
|
|
198
|
+
url: matchContent,
|
|
192
199
|
children: []
|
|
193
200
|
},
|
|
194
201
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-links.js","sources":["../../../src/slate/plugins/auto-links.ts"],"sourcesContent":["import type { NodeEntry, Text } from \"slate\";\nimport { Editor, Element, Node, Path, Range, Transforms } from \"slate\";\n\nimport type { ComposerBodyAutoLink } from \"../../types\";\nimport { isPlainText, isText } from \"../utils/is-text\";\nimport { isComposerBodyCustomLink } from \"./custom-links\";\n\n/**\n * This implementation is inspired by Lexical's AutoLink plugin.\n * Additional modifications and features were added to adapt it to our specific needs.\n *\n * Original Lexical AutoLink plugin can be found at [Lexical's Github Repository](https://github.com/facebook/lexical/blob/main/packages/lexical-react/src/LexicalAutoLinkPlugin.ts)\n */\nexport function withAutoLinks(editor: Editor): Editor {\n const { isInline, normalizeNode, deleteBackward } = editor;\n\n editor.isInline = (element) => {\n return element.type === \"auto-link\" ? true : isInline(element);\n };\n\n editor.normalizeNode = (entry) => {\n const [node, path] = entry;\n\n // Prevent auto links from being created inside custom links\n if (isComposerBodyCustomLink(node)) {\n return;\n }\n\n if (isText(node)) {\n const parentNode = Node.parent(editor, path);\n\n // Prevent auto links from being created inside custom links\n if (isComposerBodyCustomLink(parentNode)) {\n return;\n } else if (isComposerBodyAutoLink(parentNode)) {\n const parentPath = Path.parent(path);\n handleLinkEdit(editor, [parentNode, parentPath]);\n\n // Prevent rich text within auto links by removing all marks of inner text nodes\n if (!isPlainText(node)) {\n const marks = Object.keys(node).filter((key) => key !== \"text\");\n\n Transforms.unsetNodes(editor, marks, { at: path });\n }\n } else {\n handleLinkCreate(editor, [node, path]);\n handleNeighbours(editor, [node, path]);\n }\n }\n\n normalizeNode(entry);\n };\n\n editor.deleteBackward = (unit) => {\n deleteBackward(unit);\n const { selection } = editor;\n if (!selection) return;\n\n if (!Range.isCollapsed(selection)) return;\n\n const [match] = Editor.nodes(editor, {\n at: selection,\n match: isComposerBodyAutoLink,\n mode: \"lowest\",\n });\n\n if (!match) return;\n\n Transforms.unwrapNodes(editor, {\n match: isComposerBodyAutoLink,\n });\n };\n\n return editor;\n}\n\nexport function isComposerBodyAutoLink(\n node: Node\n): node is ComposerBodyAutoLink {\n return Element.isElement(node) && node.type === \"auto-link\";\n}\n\n/**\n * 1. ((https?:\\/\\/(www\\.)?)|(www\\.))\n * - Matches 'http://' or 'https://' optionally followed by 'www.', or just 'www.'\n *\n * 2. [-a-zA-Z0-9@:%._+~#=]{1,256}\n * - Matches any character in the set [-a-zA-Z0-9@:%._+~#=] between 1 and 256 times, often found in the domain and subdomain part of the URL\n *\n * 3. \\.[a-zA-Z0-9()]{1,6}\n * - Matches a period followed by any character in the set [a-zA-Z0-9()] between 1 and 6 times, usually indicating the domain extension like .com, .org, etc.\n *\n * 4. \\b\n * - Represents a word boundary, ensuring that the characters following cannot be part of a different word\n *\n * 5. ([-a-zA-Z0-9().@:%_+~#?&//=]*)\n * - Matches any character in the set [-a-zA-Z0-9().@:%_+~#?&//=] between 0 and unlimited times, often found in the path, query parameters, or anchor part of the URL\n *\n * Matching URLs:\n * - http://www.example.com\n * - https://www.example.com\n * - www.example.com\n * - https://example.com/path?query=param#anchor\n *\n * Non-Matching URLs:\n * - http:/example.com (malformed scheme)\n * - example (missing scheme and domain extension)\n * - ftp://example.com (ftp scheme is not supported)\n * - example.com (missing scheme)\n */\nconst URL_REGEX =\n /((https?:\\/\\/(www\\.)?)|(www\\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9().@:%_+~#?&//=]*)/;\n\nconst PUNCTUATION_OR_SPACE = /[.,;!?\\s()]/;\n\nconst PERIOD_OR_QUESTION_MARK_FOLLOWED_BY_ALPHANUMERIC = /^[.?][a-zA-Z0-9]+/;\n\nconst PARENTHESES = /[()]/;\n\n/**\n * Helper function to check if a character is a separator (punctuation or space)\n * @param char The character to check\n * @returns Whether the character is a separator or not\n */\nfunction isSeparator(char: string): boolean {\n return PUNCTUATION_OR_SPACE.test(char);\n}\n\n/**\n * Helper function to check if a text content ends with a separator (punctuation or space)\n * @param textContent The text content to check\n * @returns Whether the text content ends with a separator or not\n */\nfunction endsWithSeparator(textContent: string): boolean {\n return isSeparator(textContent[textContent.length - 1]);\n}\n\n/**\n * Helper function to check if a text content starts with a separator (punctuation or space)\n * @param textContent The text content to check\n * @returns Whether the text content starts with a separator or not\n */\nfunction startsWithSeparator(textContent: string): boolean {\n return isSeparator(textContent[0]);\n}\n\n/**\n * Helper function to check if a text content ends with a period or question mark\n * @param textContent The text content to check\n * @returns Whether the text content ends with a period or not\n */\nfunction endsWithPeriodOrQuestionMark(textContent: string): boolean {\n return (\n textContent[textContent.length - 1] === \".\" ||\n textContent[textContent.length - 1] === \"?\"\n );\n}\n\n/**\n * Helper function to get the \"logical length\" of a URL, taking into account things like opening/closing parentheses\n * @param url The URL to check\n * @returns The \"logical length\" of the URL\n */\nfunction getUrlLogicalLength(url: string): number {\n if (!PARENTHESES.test(url)) {\n return url.length;\n }\n\n let logicalLength = 0;\n let parenthesesCount = 0;\n\n for (const character of url) {\n if (character === \"(\") {\n parenthesesCount++;\n }\n\n if (character === \")\") {\n parenthesesCount--;\n\n if (parenthesesCount < 0) {\n break;\n }\n }\n\n logicalLength++;\n }\n\n return logicalLength;\n}\n\n/**\n * Helper function to check if the previous node is valid (text node that ends with a separator or is empty)\n */\nfunction isPreviousNodeValid(editor: Editor, path: Path): boolean {\n const entry = Editor.previous(editor, { at: path });\n if (!entry) return true;\n\n return (\n isText(entry[0]) &&\n (endsWithSeparator(entry[0].text) || entry[0].text === \"\")\n );\n}\n\n/**\n * Helper function to check if the next node is valid (text node that starts with a separator or is empty)\n */\nfunction isNextNodeValid(editor: Editor, path: Path): boolean {\n const entry = Editor.next(editor, { at: path });\n if (!entry) return true;\n\n return (\n isText(entry[0]) &&\n (startsWithSeparator(entry[0].text) || entry[0].text === \"\")\n );\n}\n\n/**\n * Helper function to check if the content around a text node is valid.\n * @param editor\n * @param entry\n * @param start\n * @param end\n * @returns\n */\nfunction isContentAroundValid(\n editor: Editor,\n entry: NodeEntry<Text>,\n start: number,\n end: number\n): boolean {\n const [node, path] = entry;\n const text = node.text;\n\n const contentBeforeIsValid =\n start > 0\n ? isSeparator(text[start - 1])\n : isPreviousNodeValid(editor, path);\n\n const contentAfterIsValid =\n end < text.length ? isSeparator(text[end]) : isNextNodeValid(editor, path);\n\n return contentBeforeIsValid && contentAfterIsValid;\n}\n\nconst handleLinkEdit = (\n editor: Editor,\n entry: NodeEntry<ComposerBodyAutoLink>\n) => {\n const [node, path] = entry;\n\n // Step 1: Ensure that the Link node only contains text nodes as children\n const children = Node.children(editor, path);\n for (const [child] of children) {\n if (isText(child)) continue;\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n // Attempt to match the text content (of the Link node) against the URL regex\n const text = Node.string(node);\n const match = URL_REGEX.exec(text);\n\n // Step 2: Ensure that the text content of the Link node matches the URL regex and is identical to the match\n if (!match || match[0] !== text) {\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n\n // Step 3: Ensure that if the text content of the Link node ends with a period, we unwrap the Link node and wrap the text before the period in a new Link node\n if (endsWithPeriodOrQuestionMark(text)) {\n Transforms.unwrapNodes(editor, { at: path });\n\n const textBeforePeriod = text.slice(0, text.length - 1);\n\n // Remove the last character from the link text and wrap the remaining text in a new link node\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: textBeforePeriod,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: 0 },\n focus: { path, offset: textBeforePeriod.length },\n },\n split: true,\n }\n );\n return;\n }\n\n // Step 4: Allow some conditions to shorten the URL (e.g. supporting parentheses but only if they are balanced)\n const logicalLength = getUrlLogicalLength(text);\n\n if (logicalLength < text.length) {\n Transforms.unwrapNodes(editor, { at: path });\n\n const logicalText = text.slice(0, logicalLength);\n\n // Keep the \"logical\" text and wrap it in a new link node\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: logicalText,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: 0 },\n focus: { path, offset: logicalText.length },\n },\n split: true,\n }\n );\n return;\n }\n\n // Step 5: Ensure that the text content of the Link node is surrounded by separators or the start/end of the text content\n if (!isPreviousNodeValid(editor, path) || !isNextNodeValid(editor, path)) {\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n\n // Step 6: Ensure that the url attribute of the Link node is identical to its text content\n if (node.url !== text) {\n Transforms.setNodes(editor, { url: match[0] }, { at: path });\n return;\n }\n};\n\nconst handleLinkCreate = (editor: Editor, entry: NodeEntry<Text>) => {\n const [node, path] = entry;\n\n // Step 1: Ensure that the text content of the node matches the URL regex\n const match = URL_REGEX.exec(node.text);\n if (!match) return;\n\n const start = match.index;\n const end = start + match[0].length;\n\n // Step 2: Ensure that the content around the node is valid\n if (!isContentAroundValid(editor, entry, start, end)) return;\n\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: match[0],\n children: [],\n },\n {\n at: {\n anchor: { path, offset: start },\n focus: { path, offset: end },\n },\n split: true,\n }\n );\n return;\n};\n\nconst handleNeighbours = (editor: Editor, entry: NodeEntry<Text>) => {\n const [node, path] = entry;\n const text = node.text;\n\n const previousSibling = Editor.previous(editor, { at: path });\n\n if (previousSibling && isComposerBodyAutoLink(previousSibling[0])) {\n if (PERIOD_OR_QUESTION_MARK_FOLLOWED_BY_ALPHANUMERIC.test(text)) {\n Transforms.unwrapNodes(editor, { at: previousSibling[1] });\n Transforms.mergeNodes(editor, { at: path });\n return;\n }\n\n if (!startsWithSeparator(text)) {\n Transforms.unwrapNodes(editor, { at: previousSibling[1] });\n return;\n }\n }\n\n const nextSibling = Editor.next(editor, { at: path });\n if (\n nextSibling &&\n isComposerBodyAutoLink(nextSibling[0]) &&\n !endsWithSeparator(text)\n ) {\n Transforms.unwrapNodes(editor, { at: nextSibling[1] });\n return;\n }\n};\n"],"names":["isComposerBodyCustomLink","isText","Node","Path","isPlainText","Transforms","Range","Editor","Element"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auto-links.js","sources":["../../../src/slate/plugins/auto-links.ts"],"sourcesContent":["import type { NodeEntry, Text } from \"slate\";\nimport { Editor, Element, Node, Path, Range, Transforms } from \"slate\";\n\nimport type { ComposerBodyAutoLink } from \"../../types\";\nimport { isPlainText, isText } from \"../utils/is-text\";\nimport { isComposerBodyCustomLink } from \"./custom-links\";\n\n/**\n * This implementation is inspired by Lexical's AutoLink plugin.\n * Additional modifications and features were added to adapt it to our specific needs.\n *\n * Original Lexical AutoLink plugin can be found at [Lexical's Github Repository](https://github.com/facebook/lexical/blob/main/packages/lexical-react/src/LexicalAutoLinkPlugin.ts)\n */\nexport function withAutoLinks(editor: Editor): Editor {\n const { isInline, normalizeNode, deleteBackward } = editor;\n\n editor.isInline = (element) => {\n return element.type === \"auto-link\" ? true : isInline(element);\n };\n\n editor.normalizeNode = (entry) => {\n const [node, path] = entry;\n\n // Prevent auto links from being created inside custom links\n if (isComposerBodyCustomLink(node)) {\n return;\n }\n\n if (isText(node)) {\n const parentNode = Node.parent(editor, path);\n\n // Prevent auto links from being created inside custom links\n if (isComposerBodyCustomLink(parentNode)) {\n return;\n } else if (isComposerBodyAutoLink(parentNode)) {\n const parentPath = Path.parent(path);\n handleLinkEdit(editor, [parentNode, parentPath]);\n\n // Prevent rich text within auto links by removing all marks of inner text nodes\n if (!isPlainText(node)) {\n const marks = Object.keys(node).filter((key) => key !== \"text\");\n\n Transforms.unsetNodes(editor, marks, { at: path });\n }\n } else {\n handleLinkCreate(editor, [node, path]);\n handleNeighbours(editor, [node, path]);\n }\n }\n\n normalizeNode(entry);\n };\n\n editor.deleteBackward = (unit) => {\n deleteBackward(unit);\n const { selection } = editor;\n if (!selection) return;\n\n if (!Range.isCollapsed(selection)) return;\n\n const [match] = Editor.nodes(editor, {\n at: selection,\n match: isComposerBodyAutoLink,\n mode: \"lowest\",\n });\n\n if (!match) return;\n\n Transforms.unwrapNodes(editor, {\n match: isComposerBodyAutoLink,\n });\n };\n\n return editor;\n}\n\nexport function isComposerBodyAutoLink(\n node: Node\n): node is ComposerBodyAutoLink {\n return Element.isElement(node) && node.type === \"auto-link\";\n}\n\n/**\n * 1. ((https?:\\/\\/(www\\.)?)|(www\\.))\n * - Matches 'http://' or 'https://' optionally followed by 'www.', or just 'www.'\n *\n * 2. [-a-zA-Z0-9@:%._+~#=]{1,256}\n * - Matches any character in the set [-a-zA-Z0-9@:%._+~#=] between 1 and 256 times, often found in the domain and subdomain part of the URL\n *\n * 3. \\.[a-zA-Z0-9()]{1,6}\n * - Matches a period followed by any character in the set [a-zA-Z0-9()] between 1 and 6 times, usually indicating the domain extension like .com, .org, etc.\n *\n * 4. \\b\n * - Represents a word boundary, ensuring that the characters following cannot be part of a different word\n *\n * 5. ([-a-zA-Z0-9().@:%_+~#?&//=]*)\n * - Matches any character in the set [-a-zA-Z0-9().@:%_+~#?&//=] between 0 and unlimited times, often found in the path, query parameters, or anchor part of the URL\n *\n * Matching URLs:\n * - http://www.example.com\n * - https://www.example.com\n * - www.example.com\n * - https://example.com/path?query=param#anchor\n *\n * Non-Matching URLs:\n * - http:/example.com (malformed scheme)\n * - example (missing scheme and domain extension)\n * - ftp://example.com (ftp scheme is not supported)\n * - example.com (missing scheme)\n */\nconst URL_REGEX =\n /((https?:\\/\\/(www\\.)?)|(www\\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9().@:%_+~#?&//=]*)/;\n\nconst PUNCTUATION_OR_SPACE = /[.,;!?\\s()]/;\n\nconst PERIOD_OR_QUESTION_MARK_FOLLOWED_BY_ALPHANUMERIC = /^[.?][a-zA-Z0-9]+/;\n\nconst PARENTHESES = /[()]/;\n\n/**\n * Helper function to check if a character is a separator (punctuation or space)\n * @param char The character to check\n * @returns Whether the character is a separator or not\n */\nfunction isSeparator(char: string): boolean {\n return PUNCTUATION_OR_SPACE.test(char);\n}\n\n/**\n * Helper function to check if a text content ends with a separator (punctuation or space)\n * @param textContent The text content to check\n * @returns Whether the text content ends with a separator or not\n */\nfunction endsWithSeparator(textContent: string): boolean {\n const lastCharacter = textContent[textContent.length - 1];\n\n return lastCharacter !== undefined ? isSeparator(lastCharacter) : false;\n}\n\n/**\n * Helper function to check if a text content starts with a separator (punctuation or space)\n * @param textContent The text content to check\n * @returns Whether the text content starts with a separator or not\n */\nfunction startsWithSeparator(textContent: string): boolean {\n const firstCharacter = textContent[0];\n\n return firstCharacter !== undefined ? isSeparator(firstCharacter) : false;\n}\n\n/**\n * Helper function to check if a text content ends with a period or question mark\n * @param textContent The text content to check\n * @returns Whether the text content ends with a period or not\n */\nfunction endsWithPeriodOrQuestionMark(textContent: string): boolean {\n return (\n textContent[textContent.length - 1] === \".\" ||\n textContent[textContent.length - 1] === \"?\"\n );\n}\n\n/**\n * Helper function to get the \"logical length\" of a URL, taking into account things like opening/closing parentheses\n * @param url The URL to check\n * @returns The \"logical length\" of the URL\n */\nfunction getUrlLogicalLength(url: string): number {\n if (!PARENTHESES.test(url)) {\n return url.length;\n }\n\n let logicalLength = 0;\n let parenthesesCount = 0;\n\n for (const character of url) {\n if (character === \"(\") {\n parenthesesCount++;\n }\n\n if (character === \")\") {\n parenthesesCount--;\n\n if (parenthesesCount < 0) {\n break;\n }\n }\n\n logicalLength++;\n }\n\n return logicalLength;\n}\n\n/**\n * Helper function to check if the previous node is valid (text node that ends with a separator or is empty)\n */\nfunction isPreviousNodeValid(editor: Editor, path: Path): boolean {\n const entry = Editor.previous(editor, { at: path });\n if (!entry) return true;\n\n return (\n isText(entry[0]) &&\n (endsWithSeparator(entry[0].text) || entry[0].text === \"\")\n );\n}\n\n/**\n * Helper function to check if the next node is valid (text node that starts with a separator or is empty)\n */\nfunction isNextNodeValid(editor: Editor, path: Path): boolean {\n const entry = Editor.next(editor, { at: path });\n if (!entry) return true;\n\n return (\n isText(entry[0]) &&\n (startsWithSeparator(entry[0].text) || entry[0].text === \"\")\n );\n}\n\n/**\n * Helper function to check if the content around a text node is valid.\n * @param editor\n * @param entry\n * @param start\n * @param end\n * @returns\n */\nfunction isContentAroundValid(\n editor: Editor,\n entry: NodeEntry<Text>,\n start: number,\n end: number\n): boolean {\n const [node, path] = entry;\n const text = node.text;\n\n const contentBefore = text[start - 1];\n const contentBeforeIsValid =\n start > 0 && contentBefore\n ? isSeparator(contentBefore)\n : isPreviousNodeValid(editor, path);\n\n const contentAfter = text[end];\n const contentAfterIsValid =\n end < text.length && contentAfter\n ? isSeparator(contentAfter)\n : isNextNodeValid(editor, path);\n\n return contentBeforeIsValid && contentAfterIsValid;\n}\n\nconst handleLinkEdit = (\n editor: Editor,\n entry: NodeEntry<ComposerBodyAutoLink>\n) => {\n const [node, path] = entry;\n\n // Step 1: Ensure that the Link node only contains text nodes as children\n const children = Node.children(editor, path);\n for (const [child] of children) {\n if (isText(child)) continue;\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n // Attempt to match the text content (of the Link node) against the URL regex\n const text = Node.string(node);\n const match = URL_REGEX.exec(text);\n const matchContent = match?.[0];\n\n // Step 2: Ensure that the text content of the Link node matches the URL regex and is identical to the match\n if (!match || matchContent !== text) {\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n\n // Step 3: Ensure that if the text content of the Link node ends with a period, we unwrap the Link node and wrap the text before the period in a new Link node\n if (endsWithPeriodOrQuestionMark(text)) {\n Transforms.unwrapNodes(editor, { at: path });\n\n const textBeforePeriod = text.slice(0, text.length - 1);\n\n // Remove the last character from the link text and wrap the remaining text in a new link node\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: textBeforePeriod,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: 0 },\n focus: { path, offset: textBeforePeriod.length },\n },\n split: true,\n }\n );\n return;\n }\n\n // Step 4: Allow some conditions to shorten the URL (e.g. supporting parentheses but only if they are balanced)\n const logicalLength = getUrlLogicalLength(text);\n\n if (logicalLength < text.length) {\n Transforms.unwrapNodes(editor, { at: path });\n\n const logicalText = text.slice(0, logicalLength);\n\n // Keep the \"logical\" text and wrap it in a new link node\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: logicalText,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: 0 },\n focus: { path, offset: logicalText.length },\n },\n split: true,\n }\n );\n return;\n }\n\n // Step 5: Ensure that the text content of the Link node is surrounded by separators or the start/end of the text content\n if (!isPreviousNodeValid(editor, path) || !isNextNodeValid(editor, path)) {\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n\n // Step 6: Ensure that the url attribute of the Link node is identical to its text content\n if (node.url !== text) {\n Transforms.setNodes(editor, { url: matchContent }, { at: path });\n return;\n }\n};\n\nconst handleLinkCreate = (editor: Editor, entry: NodeEntry<Text>) => {\n const [node, path] = entry;\n\n // Step 1: Ensure that the text content of the node matches the URL regex\n const match = URL_REGEX.exec(node.text);\n const matchContent = match?.[0];\n\n if (!match || matchContent === undefined) {\n return;\n }\n\n const start = match.index;\n const end = start + matchContent.length;\n\n // Step 2: Ensure that the content around the node is valid\n if (!isContentAroundValid(editor, entry, start, end)) return;\n\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: matchContent,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: start },\n focus: { path, offset: end },\n },\n split: true,\n }\n );\n return;\n};\n\nconst handleNeighbours = (editor: Editor, entry: NodeEntry<Text>) => {\n const [node, path] = entry;\n const text = node.text;\n\n const previousSibling = Editor.previous(editor, { at: path });\n\n if (previousSibling && isComposerBodyAutoLink(previousSibling[0])) {\n if (PERIOD_OR_QUESTION_MARK_FOLLOWED_BY_ALPHANUMERIC.test(text)) {\n Transforms.unwrapNodes(editor, { at: previousSibling[1] });\n Transforms.mergeNodes(editor, { at: path });\n return;\n }\n\n if (!startsWithSeparator(text)) {\n Transforms.unwrapNodes(editor, { at: previousSibling[1] });\n return;\n }\n }\n\n const nextSibling = Editor.next(editor, { at: path });\n if (\n nextSibling &&\n isComposerBodyAutoLink(nextSibling[0]) &&\n !endsWithSeparator(text)\n ) {\n Transforms.unwrapNodes(editor, { at: nextSibling[1] });\n return;\n }\n};\n"],"names":["isComposerBodyCustomLink","isText","Node","Path","isPlainText","Transforms","Range","Editor","Element"],"mappings":"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"}
|
|
@@ -61,10 +61,12 @@ function isSeparator(char) {
|
|
|
61
61
|
return PUNCTUATION_OR_SPACE.test(char);
|
|
62
62
|
}
|
|
63
63
|
function endsWithSeparator(textContent) {
|
|
64
|
-
|
|
64
|
+
const lastCharacter = textContent[textContent.length - 1];
|
|
65
|
+
return lastCharacter !== void 0 ? isSeparator(lastCharacter) : false;
|
|
65
66
|
}
|
|
66
67
|
function startsWithSeparator(textContent) {
|
|
67
|
-
|
|
68
|
+
const firstCharacter = textContent[0];
|
|
69
|
+
return firstCharacter !== void 0 ? isSeparator(firstCharacter) : false;
|
|
68
70
|
}
|
|
69
71
|
function endsWithPeriodOrQuestionMark(textContent) {
|
|
70
72
|
return textContent[textContent.length - 1] === "." || textContent[textContent.length - 1] === "?";
|
|
@@ -104,8 +106,10 @@ function isNextNodeValid(editor, path) {
|
|
|
104
106
|
function isContentAroundValid(editor, entry, start, end) {
|
|
105
107
|
const [node, path] = entry;
|
|
106
108
|
const text = node.text;
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
+
const contentBefore = text[start - 1];
|
|
110
|
+
const contentBeforeIsValid = start > 0 && contentBefore ? isSeparator(contentBefore) : isPreviousNodeValid(editor, path);
|
|
111
|
+
const contentAfter = text[end];
|
|
112
|
+
const contentAfterIsValid = end < text.length && contentAfter ? isSeparator(contentAfter) : isNextNodeValid(editor, path);
|
|
109
113
|
return contentBeforeIsValid && contentAfterIsValid;
|
|
110
114
|
}
|
|
111
115
|
const handleLinkEdit = (editor, entry) => {
|
|
@@ -119,7 +123,8 @@ const handleLinkEdit = (editor, entry) => {
|
|
|
119
123
|
}
|
|
120
124
|
const text = Node.string(node);
|
|
121
125
|
const match = URL_REGEX.exec(text);
|
|
122
|
-
|
|
126
|
+
const matchContent = match?.[0];
|
|
127
|
+
if (!match || matchContent !== text) {
|
|
123
128
|
Transforms.unwrapNodes(editor, { at: path });
|
|
124
129
|
return;
|
|
125
130
|
}
|
|
@@ -169,24 +174,26 @@ const handleLinkEdit = (editor, entry) => {
|
|
|
169
174
|
return;
|
|
170
175
|
}
|
|
171
176
|
if (node.url !== text) {
|
|
172
|
-
Transforms.setNodes(editor, { url:
|
|
177
|
+
Transforms.setNodes(editor, { url: matchContent }, { at: path });
|
|
173
178
|
return;
|
|
174
179
|
}
|
|
175
180
|
};
|
|
176
181
|
const handleLinkCreate = (editor, entry) => {
|
|
177
182
|
const [node, path] = entry;
|
|
178
183
|
const match = URL_REGEX.exec(node.text);
|
|
179
|
-
|
|
184
|
+
const matchContent = match?.[0];
|
|
185
|
+
if (!match || matchContent === void 0) {
|
|
180
186
|
return;
|
|
187
|
+
}
|
|
181
188
|
const start = match.index;
|
|
182
|
-
const end = start +
|
|
189
|
+
const end = start + matchContent.length;
|
|
183
190
|
if (!isContentAroundValid(editor, entry, start, end))
|
|
184
191
|
return;
|
|
185
192
|
Transforms.wrapNodes(
|
|
186
193
|
editor,
|
|
187
194
|
{
|
|
188
195
|
type: "auto-link",
|
|
189
|
-
url:
|
|
196
|
+
url: matchContent,
|
|
190
197
|
children: []
|
|
191
198
|
},
|
|
192
199
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-links.mjs","sources":["../../../src/slate/plugins/auto-links.ts"],"sourcesContent":["import type { NodeEntry, Text } from \"slate\";\nimport { Editor, Element, Node, Path, Range, Transforms } from \"slate\";\n\nimport type { ComposerBodyAutoLink } from \"../../types\";\nimport { isPlainText, isText } from \"../utils/is-text\";\nimport { isComposerBodyCustomLink } from \"./custom-links\";\n\n/**\n * This implementation is inspired by Lexical's AutoLink plugin.\n * Additional modifications and features were added to adapt it to our specific needs.\n *\n * Original Lexical AutoLink plugin can be found at [Lexical's Github Repository](https://github.com/facebook/lexical/blob/main/packages/lexical-react/src/LexicalAutoLinkPlugin.ts)\n */\nexport function withAutoLinks(editor: Editor): Editor {\n const { isInline, normalizeNode, deleteBackward } = editor;\n\n editor.isInline = (element) => {\n return element.type === \"auto-link\" ? true : isInline(element);\n };\n\n editor.normalizeNode = (entry) => {\n const [node, path] = entry;\n\n // Prevent auto links from being created inside custom links\n if (isComposerBodyCustomLink(node)) {\n return;\n }\n\n if (isText(node)) {\n const parentNode = Node.parent(editor, path);\n\n // Prevent auto links from being created inside custom links\n if (isComposerBodyCustomLink(parentNode)) {\n return;\n } else if (isComposerBodyAutoLink(parentNode)) {\n const parentPath = Path.parent(path);\n handleLinkEdit(editor, [parentNode, parentPath]);\n\n // Prevent rich text within auto links by removing all marks of inner text nodes\n if (!isPlainText(node)) {\n const marks = Object.keys(node).filter((key) => key !== \"text\");\n\n Transforms.unsetNodes(editor, marks, { at: path });\n }\n } else {\n handleLinkCreate(editor, [node, path]);\n handleNeighbours(editor, [node, path]);\n }\n }\n\n normalizeNode(entry);\n };\n\n editor.deleteBackward = (unit) => {\n deleteBackward(unit);\n const { selection } = editor;\n if (!selection) return;\n\n if (!Range.isCollapsed(selection)) return;\n\n const [match] = Editor.nodes(editor, {\n at: selection,\n match: isComposerBodyAutoLink,\n mode: \"lowest\",\n });\n\n if (!match) return;\n\n Transforms.unwrapNodes(editor, {\n match: isComposerBodyAutoLink,\n });\n };\n\n return editor;\n}\n\nexport function isComposerBodyAutoLink(\n node: Node\n): node is ComposerBodyAutoLink {\n return Element.isElement(node) && node.type === \"auto-link\";\n}\n\n/**\n * 1. ((https?:\\/\\/(www\\.)?)|(www\\.))\n * - Matches 'http://' or 'https://' optionally followed by 'www.', or just 'www.'\n *\n * 2. [-a-zA-Z0-9@:%._+~#=]{1,256}\n * - Matches any character in the set [-a-zA-Z0-9@:%._+~#=] between 1 and 256 times, often found in the domain and subdomain part of the URL\n *\n * 3. \\.[a-zA-Z0-9()]{1,6}\n * - Matches a period followed by any character in the set [a-zA-Z0-9()] between 1 and 6 times, usually indicating the domain extension like .com, .org, etc.\n *\n * 4. \\b\n * - Represents a word boundary, ensuring that the characters following cannot be part of a different word\n *\n * 5. ([-a-zA-Z0-9().@:%_+~#?&//=]*)\n * - Matches any character in the set [-a-zA-Z0-9().@:%_+~#?&//=] between 0 and unlimited times, often found in the path, query parameters, or anchor part of the URL\n *\n * Matching URLs:\n * - http://www.example.com\n * - https://www.example.com\n * - www.example.com\n * - https://example.com/path?query=param#anchor\n *\n * Non-Matching URLs:\n * - http:/example.com (malformed scheme)\n * - example (missing scheme and domain extension)\n * - ftp://example.com (ftp scheme is not supported)\n * - example.com (missing scheme)\n */\nconst URL_REGEX =\n /((https?:\\/\\/(www\\.)?)|(www\\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9().@:%_+~#?&//=]*)/;\n\nconst PUNCTUATION_OR_SPACE = /[.,;!?\\s()]/;\n\nconst PERIOD_OR_QUESTION_MARK_FOLLOWED_BY_ALPHANUMERIC = /^[.?][a-zA-Z0-9]+/;\n\nconst PARENTHESES = /[()]/;\n\n/**\n * Helper function to check if a character is a separator (punctuation or space)\n * @param char The character to check\n * @returns Whether the character is a separator or not\n */\nfunction isSeparator(char: string): boolean {\n return PUNCTUATION_OR_SPACE.test(char);\n}\n\n/**\n * Helper function to check if a text content ends with a separator (punctuation or space)\n * @param textContent The text content to check\n * @returns Whether the text content ends with a separator or not\n */\nfunction endsWithSeparator(textContent: string): boolean {\n return isSeparator(textContent[textContent.length - 1]);\n}\n\n/**\n * Helper function to check if a text content starts with a separator (punctuation or space)\n * @param textContent The text content to check\n * @returns Whether the text content starts with a separator or not\n */\nfunction startsWithSeparator(textContent: string): boolean {\n return isSeparator(textContent[0]);\n}\n\n/**\n * Helper function to check if a text content ends with a period or question mark\n * @param textContent The text content to check\n * @returns Whether the text content ends with a period or not\n */\nfunction endsWithPeriodOrQuestionMark(textContent: string): boolean {\n return (\n textContent[textContent.length - 1] === \".\" ||\n textContent[textContent.length - 1] === \"?\"\n );\n}\n\n/**\n * Helper function to get the \"logical length\" of a URL, taking into account things like opening/closing parentheses\n * @param url The URL to check\n * @returns The \"logical length\" of the URL\n */\nfunction getUrlLogicalLength(url: string): number {\n if (!PARENTHESES.test(url)) {\n return url.length;\n }\n\n let logicalLength = 0;\n let parenthesesCount = 0;\n\n for (const character of url) {\n if (character === \"(\") {\n parenthesesCount++;\n }\n\n if (character === \")\") {\n parenthesesCount--;\n\n if (parenthesesCount < 0) {\n break;\n }\n }\n\n logicalLength++;\n }\n\n return logicalLength;\n}\n\n/**\n * Helper function to check if the previous node is valid (text node that ends with a separator or is empty)\n */\nfunction isPreviousNodeValid(editor: Editor, path: Path): boolean {\n const entry = Editor.previous(editor, { at: path });\n if (!entry) return true;\n\n return (\n isText(entry[0]) &&\n (endsWithSeparator(entry[0].text) || entry[0].text === \"\")\n );\n}\n\n/**\n * Helper function to check if the next node is valid (text node that starts with a separator or is empty)\n */\nfunction isNextNodeValid(editor: Editor, path: Path): boolean {\n const entry = Editor.next(editor, { at: path });\n if (!entry) return true;\n\n return (\n isText(entry[0]) &&\n (startsWithSeparator(entry[0].text) || entry[0].text === \"\")\n );\n}\n\n/**\n * Helper function to check if the content around a text node is valid.\n * @param editor\n * @param entry\n * @param start\n * @param end\n * @returns\n */\nfunction isContentAroundValid(\n editor: Editor,\n entry: NodeEntry<Text>,\n start: number,\n end: number\n): boolean {\n const [node, path] = entry;\n const text = node.text;\n\n const contentBeforeIsValid =\n start > 0\n ? isSeparator(text[start - 1])\n : isPreviousNodeValid(editor, path);\n\n const contentAfterIsValid =\n end < text.length ? isSeparator(text[end]) : isNextNodeValid(editor, path);\n\n return contentBeforeIsValid && contentAfterIsValid;\n}\n\nconst handleLinkEdit = (\n editor: Editor,\n entry: NodeEntry<ComposerBodyAutoLink>\n) => {\n const [node, path] = entry;\n\n // Step 1: Ensure that the Link node only contains text nodes as children\n const children = Node.children(editor, path);\n for (const [child] of children) {\n if (isText(child)) continue;\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n // Attempt to match the text content (of the Link node) against the URL regex\n const text = Node.string(node);\n const match = URL_REGEX.exec(text);\n\n // Step 2: Ensure that the text content of the Link node matches the URL regex and is identical to the match\n if (!match || match[0] !== text) {\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n\n // Step 3: Ensure that if the text content of the Link node ends with a period, we unwrap the Link node and wrap the text before the period in a new Link node\n if (endsWithPeriodOrQuestionMark(text)) {\n Transforms.unwrapNodes(editor, { at: path });\n\n const textBeforePeriod = text.slice(0, text.length - 1);\n\n // Remove the last character from the link text and wrap the remaining text in a new link node\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: textBeforePeriod,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: 0 },\n focus: { path, offset: textBeforePeriod.length },\n },\n split: true,\n }\n );\n return;\n }\n\n // Step 4: Allow some conditions to shorten the URL (e.g. supporting parentheses but only if they are balanced)\n const logicalLength = getUrlLogicalLength(text);\n\n if (logicalLength < text.length) {\n Transforms.unwrapNodes(editor, { at: path });\n\n const logicalText = text.slice(0, logicalLength);\n\n // Keep the \"logical\" text and wrap it in a new link node\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: logicalText,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: 0 },\n focus: { path, offset: logicalText.length },\n },\n split: true,\n }\n );\n return;\n }\n\n // Step 5: Ensure that the text content of the Link node is surrounded by separators or the start/end of the text content\n if (!isPreviousNodeValid(editor, path) || !isNextNodeValid(editor, path)) {\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n\n // Step 6: Ensure that the url attribute of the Link node is identical to its text content\n if (node.url !== text) {\n Transforms.setNodes(editor, { url: match[0] }, { at: path });\n return;\n }\n};\n\nconst handleLinkCreate = (editor: Editor, entry: NodeEntry<Text>) => {\n const [node, path] = entry;\n\n // Step 1: Ensure that the text content of the node matches the URL regex\n const match = URL_REGEX.exec(node.text);\n if (!match) return;\n\n const start = match.index;\n const end = start + match[0].length;\n\n // Step 2: Ensure that the content around the node is valid\n if (!isContentAroundValid(editor, entry, start, end)) return;\n\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: match[0],\n children: [],\n },\n {\n at: {\n anchor: { path, offset: start },\n focus: { path, offset: end },\n },\n split: true,\n }\n );\n return;\n};\n\nconst handleNeighbours = (editor: Editor, entry: NodeEntry<Text>) => {\n const [node, path] = entry;\n const text = node.text;\n\n const previousSibling = Editor.previous(editor, { at: path });\n\n if (previousSibling && isComposerBodyAutoLink(previousSibling[0])) {\n if (PERIOD_OR_QUESTION_MARK_FOLLOWED_BY_ALPHANUMERIC.test(text)) {\n Transforms.unwrapNodes(editor, { at: previousSibling[1] });\n Transforms.mergeNodes(editor, { at: path });\n return;\n }\n\n if (!startsWithSeparator(text)) {\n Transforms.unwrapNodes(editor, { at: previousSibling[1] });\n return;\n }\n }\n\n const nextSibling = Editor.next(editor, { at: path });\n if (\n nextSibling &&\n isComposerBodyAutoLink(nextSibling[0]) &&\n !endsWithSeparator(text)\n ) {\n Transforms.unwrapNodes(editor, { at: nextSibling[1] });\n return;\n }\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auto-links.mjs","sources":["../../../src/slate/plugins/auto-links.ts"],"sourcesContent":["import type { NodeEntry, Text } from \"slate\";\nimport { Editor, Element, Node, Path, Range, Transforms } from \"slate\";\n\nimport type { ComposerBodyAutoLink } from \"../../types\";\nimport { isPlainText, isText } from \"../utils/is-text\";\nimport { isComposerBodyCustomLink } from \"./custom-links\";\n\n/**\n * This implementation is inspired by Lexical's AutoLink plugin.\n * Additional modifications and features were added to adapt it to our specific needs.\n *\n * Original Lexical AutoLink plugin can be found at [Lexical's Github Repository](https://github.com/facebook/lexical/blob/main/packages/lexical-react/src/LexicalAutoLinkPlugin.ts)\n */\nexport function withAutoLinks(editor: Editor): Editor {\n const { isInline, normalizeNode, deleteBackward } = editor;\n\n editor.isInline = (element) => {\n return element.type === \"auto-link\" ? true : isInline(element);\n };\n\n editor.normalizeNode = (entry) => {\n const [node, path] = entry;\n\n // Prevent auto links from being created inside custom links\n if (isComposerBodyCustomLink(node)) {\n return;\n }\n\n if (isText(node)) {\n const parentNode = Node.parent(editor, path);\n\n // Prevent auto links from being created inside custom links\n if (isComposerBodyCustomLink(parentNode)) {\n return;\n } else if (isComposerBodyAutoLink(parentNode)) {\n const parentPath = Path.parent(path);\n handleLinkEdit(editor, [parentNode, parentPath]);\n\n // Prevent rich text within auto links by removing all marks of inner text nodes\n if (!isPlainText(node)) {\n const marks = Object.keys(node).filter((key) => key !== \"text\");\n\n Transforms.unsetNodes(editor, marks, { at: path });\n }\n } else {\n handleLinkCreate(editor, [node, path]);\n handleNeighbours(editor, [node, path]);\n }\n }\n\n normalizeNode(entry);\n };\n\n editor.deleteBackward = (unit) => {\n deleteBackward(unit);\n const { selection } = editor;\n if (!selection) return;\n\n if (!Range.isCollapsed(selection)) return;\n\n const [match] = Editor.nodes(editor, {\n at: selection,\n match: isComposerBodyAutoLink,\n mode: \"lowest\",\n });\n\n if (!match) return;\n\n Transforms.unwrapNodes(editor, {\n match: isComposerBodyAutoLink,\n });\n };\n\n return editor;\n}\n\nexport function isComposerBodyAutoLink(\n node: Node\n): node is ComposerBodyAutoLink {\n return Element.isElement(node) && node.type === \"auto-link\";\n}\n\n/**\n * 1. ((https?:\\/\\/(www\\.)?)|(www\\.))\n * - Matches 'http://' or 'https://' optionally followed by 'www.', or just 'www.'\n *\n * 2. [-a-zA-Z0-9@:%._+~#=]{1,256}\n * - Matches any character in the set [-a-zA-Z0-9@:%._+~#=] between 1 and 256 times, often found in the domain and subdomain part of the URL\n *\n * 3. \\.[a-zA-Z0-9()]{1,6}\n * - Matches a period followed by any character in the set [a-zA-Z0-9()] between 1 and 6 times, usually indicating the domain extension like .com, .org, etc.\n *\n * 4. \\b\n * - Represents a word boundary, ensuring that the characters following cannot be part of a different word\n *\n * 5. ([-a-zA-Z0-9().@:%_+~#?&//=]*)\n * - Matches any character in the set [-a-zA-Z0-9().@:%_+~#?&//=] between 0 and unlimited times, often found in the path, query parameters, or anchor part of the URL\n *\n * Matching URLs:\n * - http://www.example.com\n * - https://www.example.com\n * - www.example.com\n * - https://example.com/path?query=param#anchor\n *\n * Non-Matching URLs:\n * - http:/example.com (malformed scheme)\n * - example (missing scheme and domain extension)\n * - ftp://example.com (ftp scheme is not supported)\n * - example.com (missing scheme)\n */\nconst URL_REGEX =\n /((https?:\\/\\/(www\\.)?)|(www\\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9().@:%_+~#?&//=]*)/;\n\nconst PUNCTUATION_OR_SPACE = /[.,;!?\\s()]/;\n\nconst PERIOD_OR_QUESTION_MARK_FOLLOWED_BY_ALPHANUMERIC = /^[.?][a-zA-Z0-9]+/;\n\nconst PARENTHESES = /[()]/;\n\n/**\n * Helper function to check if a character is a separator (punctuation or space)\n * @param char The character to check\n * @returns Whether the character is a separator or not\n */\nfunction isSeparator(char: string): boolean {\n return PUNCTUATION_OR_SPACE.test(char);\n}\n\n/**\n * Helper function to check if a text content ends with a separator (punctuation or space)\n * @param textContent The text content to check\n * @returns Whether the text content ends with a separator or not\n */\nfunction endsWithSeparator(textContent: string): boolean {\n const lastCharacter = textContent[textContent.length - 1];\n\n return lastCharacter !== undefined ? isSeparator(lastCharacter) : false;\n}\n\n/**\n * Helper function to check if a text content starts with a separator (punctuation or space)\n * @param textContent The text content to check\n * @returns Whether the text content starts with a separator or not\n */\nfunction startsWithSeparator(textContent: string): boolean {\n const firstCharacter = textContent[0];\n\n return firstCharacter !== undefined ? isSeparator(firstCharacter) : false;\n}\n\n/**\n * Helper function to check if a text content ends with a period or question mark\n * @param textContent The text content to check\n * @returns Whether the text content ends with a period or not\n */\nfunction endsWithPeriodOrQuestionMark(textContent: string): boolean {\n return (\n textContent[textContent.length - 1] === \".\" ||\n textContent[textContent.length - 1] === \"?\"\n );\n}\n\n/**\n * Helper function to get the \"logical length\" of a URL, taking into account things like opening/closing parentheses\n * @param url The URL to check\n * @returns The \"logical length\" of the URL\n */\nfunction getUrlLogicalLength(url: string): number {\n if (!PARENTHESES.test(url)) {\n return url.length;\n }\n\n let logicalLength = 0;\n let parenthesesCount = 0;\n\n for (const character of url) {\n if (character === \"(\") {\n parenthesesCount++;\n }\n\n if (character === \")\") {\n parenthesesCount--;\n\n if (parenthesesCount < 0) {\n break;\n }\n }\n\n logicalLength++;\n }\n\n return logicalLength;\n}\n\n/**\n * Helper function to check if the previous node is valid (text node that ends with a separator or is empty)\n */\nfunction isPreviousNodeValid(editor: Editor, path: Path): boolean {\n const entry = Editor.previous(editor, { at: path });\n if (!entry) return true;\n\n return (\n isText(entry[0]) &&\n (endsWithSeparator(entry[0].text) || entry[0].text === \"\")\n );\n}\n\n/**\n * Helper function to check if the next node is valid (text node that starts with a separator or is empty)\n */\nfunction isNextNodeValid(editor: Editor, path: Path): boolean {\n const entry = Editor.next(editor, { at: path });\n if (!entry) return true;\n\n return (\n isText(entry[0]) &&\n (startsWithSeparator(entry[0].text) || entry[0].text === \"\")\n );\n}\n\n/**\n * Helper function to check if the content around a text node is valid.\n * @param editor\n * @param entry\n * @param start\n * @param end\n * @returns\n */\nfunction isContentAroundValid(\n editor: Editor,\n entry: NodeEntry<Text>,\n start: number,\n end: number\n): boolean {\n const [node, path] = entry;\n const text = node.text;\n\n const contentBefore = text[start - 1];\n const contentBeforeIsValid =\n start > 0 && contentBefore\n ? isSeparator(contentBefore)\n : isPreviousNodeValid(editor, path);\n\n const contentAfter = text[end];\n const contentAfterIsValid =\n end < text.length && contentAfter\n ? isSeparator(contentAfter)\n : isNextNodeValid(editor, path);\n\n return contentBeforeIsValid && contentAfterIsValid;\n}\n\nconst handleLinkEdit = (\n editor: Editor,\n entry: NodeEntry<ComposerBodyAutoLink>\n) => {\n const [node, path] = entry;\n\n // Step 1: Ensure that the Link node only contains text nodes as children\n const children = Node.children(editor, path);\n for (const [child] of children) {\n if (isText(child)) continue;\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n // Attempt to match the text content (of the Link node) against the URL regex\n const text = Node.string(node);\n const match = URL_REGEX.exec(text);\n const matchContent = match?.[0];\n\n // Step 2: Ensure that the text content of the Link node matches the URL regex and is identical to the match\n if (!match || matchContent !== text) {\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n\n // Step 3: Ensure that if the text content of the Link node ends with a period, we unwrap the Link node and wrap the text before the period in a new Link node\n if (endsWithPeriodOrQuestionMark(text)) {\n Transforms.unwrapNodes(editor, { at: path });\n\n const textBeforePeriod = text.slice(0, text.length - 1);\n\n // Remove the last character from the link text and wrap the remaining text in a new link node\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: textBeforePeriod,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: 0 },\n focus: { path, offset: textBeforePeriod.length },\n },\n split: true,\n }\n );\n return;\n }\n\n // Step 4: Allow some conditions to shorten the URL (e.g. supporting parentheses but only if they are balanced)\n const logicalLength = getUrlLogicalLength(text);\n\n if (logicalLength < text.length) {\n Transforms.unwrapNodes(editor, { at: path });\n\n const logicalText = text.slice(0, logicalLength);\n\n // Keep the \"logical\" text and wrap it in a new link node\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: logicalText,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: 0 },\n focus: { path, offset: logicalText.length },\n },\n split: true,\n }\n );\n return;\n }\n\n // Step 5: Ensure that the text content of the Link node is surrounded by separators or the start/end of the text content\n if (!isPreviousNodeValid(editor, path) || !isNextNodeValid(editor, path)) {\n Transforms.unwrapNodes(editor, { at: path });\n return;\n }\n\n // Step 6: Ensure that the url attribute of the Link node is identical to its text content\n if (node.url !== text) {\n Transforms.setNodes(editor, { url: matchContent }, { at: path });\n return;\n }\n};\n\nconst handleLinkCreate = (editor: Editor, entry: NodeEntry<Text>) => {\n const [node, path] = entry;\n\n // Step 1: Ensure that the text content of the node matches the URL regex\n const match = URL_REGEX.exec(node.text);\n const matchContent = match?.[0];\n\n if (!match || matchContent === undefined) {\n return;\n }\n\n const start = match.index;\n const end = start + matchContent.length;\n\n // Step 2: Ensure that the content around the node is valid\n if (!isContentAroundValid(editor, entry, start, end)) return;\n\n Transforms.wrapNodes<ComposerBodyAutoLink>(\n editor,\n {\n type: \"auto-link\",\n url: matchContent,\n children: [],\n },\n {\n at: {\n anchor: { path, offset: start },\n focus: { path, offset: end },\n },\n split: true,\n }\n );\n return;\n};\n\nconst handleNeighbours = (editor: Editor, entry: NodeEntry<Text>) => {\n const [node, path] = entry;\n const text = node.text;\n\n const previousSibling = Editor.previous(editor, { at: path });\n\n if (previousSibling && isComposerBodyAutoLink(previousSibling[0])) {\n if (PERIOD_OR_QUESTION_MARK_FOLLOWED_BY_ALPHANUMERIC.test(text)) {\n Transforms.unwrapNodes(editor, { at: previousSibling[1] });\n Transforms.mergeNodes(editor, { at: path });\n return;\n }\n\n if (!startsWithSeparator(text)) {\n Transforms.unwrapNodes(editor, { at: previousSibling[1] });\n return;\n }\n }\n\n const nextSibling = Editor.next(editor, { at: path });\n if (\n nextSibling &&\n isComposerBodyAutoLink(nextSibling[0]) &&\n !endsWithSeparator(text)\n ) {\n Transforms.unwrapNodes(editor, { at: nextSibling[1] });\n return;\n }\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paste.js","sources":["../../../src/slate/plugins/paste.ts"],"sourcesContent":["import type { Descendant, Editor, Element, Node as SlateNode } from \"slate\";\nimport { Transforms } from \"slate\";\nimport { jsx } from \"slate-hyperscript\";\n\nimport type {\n ComposerBodyAutoLink,\n ComposerBodyBlockElement,\n ComposerBodyCustomLink,\n ComposerBodyInlineElement,\n ComposerBodyParagraph,\n ComposerBodyText,\n} from \"../../types\";\nimport { getFiles } from \"../../utils/data-transfer\";\n\n// Based on: https://github.com/ianstormtaylor/slate/blob/main/site/examples/paste-html.tsx\n\ntype OmitTextChildren<T> = Omit<T, \"text\" | \"children\">;\n\ntype ComposerBodyElementTag = OmitTextChildren<\n ComposerBodyBlockElement | ComposerBodyInlineElement\n>;\ntype ComposerBodyTextTag = OmitTextChildren<ComposerBodyText>;\n\ntype DeserializedNode =\n | string\n | null\n | Element\n | Descendant[]\n | ComposerBodyText[]\n | DeserializedNode[];\n\nfunction areUrlsEqual(a: string, b: string) {\n try {\n const urlA = new URL(a);\n const urlB = new URL(b);\n\n return urlA.origin === urlB.origin && urlA.pathname === urlB.pathname;\n } catch {\n return false;\n }\n}\n\nconst createParagraphElement = (): OmitTextChildren<ComposerBodyParagraph> => ({\n type: \"paragraph\",\n});\n\nconst ELEMENT_TAGS = {\n A: (\n element\n ): OmitTextChildren<ComposerBodyCustomLink | ComposerBodyAutoLink> => {\n const href = element.getAttribute(\"href\");\n const innerText = element.innerText;\n\n return {\n type: href && areUrlsEqual(href, innerText) ? \"auto-link\" : \"custom-link\",\n url: href ?? \"\",\n };\n },\n P: createParagraphElement,\n // Falling back to paragraphs for unsupported elements\n BLOCKQUOTE: createParagraphElement,\n H1: createParagraphElement,\n H2: createParagraphElement,\n H3: createParagraphElement,\n H4: createParagraphElement,\n H5: createParagraphElement,\n H6: createParagraphElement,\n LI: createParagraphElement,\n} as Record<string, (node: HTMLElement) => ComposerBodyElementTag>;\n\nconst TEXT_TAGS = {\n CODE: (): ComposerBodyTextTag => ({ code: true }),\n DEL: (): ComposerBodyTextTag => ({ strikethrough: true }),\n EM: (): ComposerBodyTextTag => ({ italic: true }),\n I: (): ComposerBodyTextTag => ({ italic: true }),\n S: (): ComposerBodyTextTag => ({ strikethrough: true }),\n STRONG: (): ComposerBodyTextTag => ({ bold: true }),\n // `B` is omitted because Google Docs uses `<b>` in weird ways\n // B: (): ComposerBodyTextTag => ({ bold: true }),\n} as Record<string, (node: HTMLElement) => ComposerBodyTextTag>;\n\nfunction flattenListItems(node: HTMLElement): HTMLElement[] {\n const listItems: HTMLElement[] = [];\n\n if (node.nodeName === \"LI\") {\n listItems.push(node);\n }\n\n node.childNodes.forEach((child) => {\n if (child.nodeType === 1) {\n listItems.push(...flattenListItems(child as HTMLElement));\n }\n });\n\n return listItems;\n}\n\nfunction deserialize(node: Node): DeserializedNode {\n if (node.nodeType === 3) {\n return node.textContent;\n } else if (node.nodeType !== 1) {\n return null;\n } else if (node.nodeName === \"BR\") {\n return \"\\n\";\n }\n\n const childNodes = Array.from(node.childNodes);\n let children = childNodes.map(deserialize).flat();\n\n // Lists aren't supported (yet), so we flatten them into paragraphs\n if (node.nodeName === \"UL\" || node.nodeName === \"OL\") {\n const listItems = flattenListItems(node as HTMLElement);\n\n children = listItems.map((li) => deserialize(li)).flat();\n }\n\n if (children.length === 0) {\n children = [{ text: \"\" }];\n }\n\n if (node.nodeName === \"BODY\") {\n return jsx(\"fragment\", {}, children);\n }\n\n if (ELEMENT_TAGS[node.nodeName]) {\n const attrs = ELEMENT_TAGS[node.nodeName](node as HTMLElement);\n\n return jsx(\"element\", attrs, children);\n }\n\n if (TEXT_TAGS[node.nodeName]) {\n const attrs = TEXT_TAGS[node.nodeName](node as HTMLElement);\n\n return children.map((child) => jsx(\"text\", attrs, child));\n }\n\n return children as DeserializedNode;\n}\n\nexport function withPaste(\n editor: Editor,\n {\n createAttachments,\n pasteFilesAsAttachments,\n }: {\n createAttachments: (files: File[]) => void;\n pasteFilesAsAttachments?: boolean;\n }\n) {\n const { insertData } = editor;\n\n editor.insertData = (data) => {\n // Create attachments from files when pasting\n if (data.types.includes(\"Files\") && pasteFilesAsAttachments) {\n const files = getFiles(data);\n\n if (files.length > 0) {\n createAttachments(files);\n\n return;\n }\n }\n\n // Deserialize rich text from HTML when pasting\n if (data.types.includes(\"text/html\")) {\n const html = data.getData(\"text/html\");\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n const fragment = deserialize(parsed.body);\n\n if (fragment !== null && Array.isArray(fragment)) {\n Transforms.insertFragment(editor, fragment as SlateNode[]);\n\n return;\n }\n }\n\n insertData(data);\n };\n\n return editor;\n}\n"],"names":["jsx","getFiles","Transforms"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"paste.js","sources":["../../../src/slate/plugins/paste.ts"],"sourcesContent":["import type { Descendant, Editor, Element, Node as SlateNode } from \"slate\";\nimport { Transforms } from \"slate\";\nimport { jsx } from \"slate-hyperscript\";\n\nimport type {\n ComposerBodyAutoLink,\n ComposerBodyBlockElement,\n ComposerBodyCustomLink,\n ComposerBodyInlineElement,\n ComposerBodyParagraph,\n ComposerBodyText,\n} from \"../../types\";\nimport { getFiles } from \"../../utils/data-transfer\";\n\n// Based on: https://github.com/ianstormtaylor/slate/blob/main/site/examples/paste-html.tsx\n\ntype OmitTextChildren<T> = Omit<T, \"text\" | \"children\">;\n\ntype ComposerBodyElementTag = OmitTextChildren<\n ComposerBodyBlockElement | ComposerBodyInlineElement\n>;\ntype ComposerBodyTextTag = OmitTextChildren<ComposerBodyText>;\n\ntype DeserializedNode =\n | string\n | null\n | Element\n | Descendant[]\n | ComposerBodyText[]\n | DeserializedNode[];\n\nfunction areUrlsEqual(a: string, b: string) {\n try {\n const urlA = new URL(a);\n const urlB = new URL(b);\n\n return urlA.origin === urlB.origin && urlA.pathname === urlB.pathname;\n } catch {\n return false;\n }\n}\n\nconst createParagraphElement = (): OmitTextChildren<ComposerBodyParagraph> => ({\n type: \"paragraph\",\n});\n\nconst ELEMENT_TAGS = {\n A: (\n element\n ): OmitTextChildren<ComposerBodyCustomLink | ComposerBodyAutoLink> => {\n const href = element.getAttribute(\"href\");\n const innerText = element.innerText;\n\n return {\n type: href && areUrlsEqual(href, innerText) ? \"auto-link\" : \"custom-link\",\n url: href ?? \"\",\n };\n },\n P: createParagraphElement,\n // Falling back to paragraphs for unsupported elements\n BLOCKQUOTE: createParagraphElement,\n H1: createParagraphElement,\n H2: createParagraphElement,\n H3: createParagraphElement,\n H4: createParagraphElement,\n H5: createParagraphElement,\n H6: createParagraphElement,\n LI: createParagraphElement,\n} as Record<string, (node: HTMLElement) => ComposerBodyElementTag>;\n\nconst TEXT_TAGS = {\n CODE: (): ComposerBodyTextTag => ({ code: true }),\n DEL: (): ComposerBodyTextTag => ({ strikethrough: true }),\n EM: (): ComposerBodyTextTag => ({ italic: true }),\n I: (): ComposerBodyTextTag => ({ italic: true }),\n S: (): ComposerBodyTextTag => ({ strikethrough: true }),\n STRONG: (): ComposerBodyTextTag => ({ bold: true }),\n // `B` is omitted because Google Docs uses `<b>` in weird ways\n // B: (): ComposerBodyTextTag => ({ bold: true }),\n} as Record<string, (node: HTMLElement) => ComposerBodyTextTag>;\n\nfunction flattenListItems(node: HTMLElement): HTMLElement[] {\n const listItems: HTMLElement[] = [];\n\n if (node.nodeName === \"LI\") {\n listItems.push(node);\n }\n\n node.childNodes.forEach((child) => {\n if (child.nodeType === 1) {\n listItems.push(...flattenListItems(child as HTMLElement));\n }\n });\n\n return listItems;\n}\n\nfunction deserialize(node: Node): DeserializedNode {\n if (node.nodeType === 3) {\n return node.textContent;\n } else if (node.nodeType !== 1) {\n return null;\n } else if (node.nodeName === \"BR\") {\n return \"\\n\";\n }\n\n const childNodes = Array.from(node.childNodes);\n let children = childNodes.map(deserialize).flat();\n\n // Lists aren't supported (yet), so we flatten them into paragraphs\n if (node.nodeName === \"UL\" || node.nodeName === \"OL\") {\n const listItems = flattenListItems(node as HTMLElement);\n\n children = listItems.map((li) => deserialize(li)).flat();\n }\n\n if (children.length === 0) {\n children = [{ text: \"\" }];\n }\n\n if (node.nodeName === \"BODY\") {\n return jsx(\"fragment\", {}, children);\n }\n\n if (ELEMENT_TAGS[node.nodeName]) {\n const attrs = ELEMENT_TAGS[node.nodeName]!(node as HTMLElement);\n\n return jsx(\"element\", attrs, children);\n }\n\n if (TEXT_TAGS[node.nodeName]) {\n const attrs = TEXT_TAGS[node.nodeName]!(node as HTMLElement);\n\n return children.map((child) => jsx(\"text\", attrs, child));\n }\n\n return children as DeserializedNode;\n}\n\nexport function withPaste(\n editor: Editor,\n {\n createAttachments,\n pasteFilesAsAttachments,\n }: {\n createAttachments: (files: File[]) => void;\n pasteFilesAsAttachments?: boolean;\n }\n) {\n const { insertData } = editor;\n\n editor.insertData = (data) => {\n // Create attachments from files when pasting\n if (data.types.includes(\"Files\") && pasteFilesAsAttachments) {\n const files = getFiles(data);\n\n if (files.length > 0) {\n createAttachments(files);\n\n return;\n }\n }\n\n // Deserialize rich text from HTML when pasting\n if (data.types.includes(\"text/html\")) {\n const html = data.getData(\"text/html\");\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n const fragment = deserialize(parsed.body);\n\n if (fragment !== null && Array.isArray(fragment)) {\n Transforms.insertFragment(editor, fragment as SlateNode[]);\n\n return;\n }\n }\n\n insertData(data);\n };\n\n return editor;\n}\n"],"names":["jsx","getFiles","Transforms"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paste.mjs","sources":["../../../src/slate/plugins/paste.ts"],"sourcesContent":["import type { Descendant, Editor, Element, Node as SlateNode } from \"slate\";\nimport { Transforms } from \"slate\";\nimport { jsx } from \"slate-hyperscript\";\n\nimport type {\n ComposerBodyAutoLink,\n ComposerBodyBlockElement,\n ComposerBodyCustomLink,\n ComposerBodyInlineElement,\n ComposerBodyParagraph,\n ComposerBodyText,\n} from \"../../types\";\nimport { getFiles } from \"../../utils/data-transfer\";\n\n// Based on: https://github.com/ianstormtaylor/slate/blob/main/site/examples/paste-html.tsx\n\ntype OmitTextChildren<T> = Omit<T, \"text\" | \"children\">;\n\ntype ComposerBodyElementTag = OmitTextChildren<\n ComposerBodyBlockElement | ComposerBodyInlineElement\n>;\ntype ComposerBodyTextTag = OmitTextChildren<ComposerBodyText>;\n\ntype DeserializedNode =\n | string\n | null\n | Element\n | Descendant[]\n | ComposerBodyText[]\n | DeserializedNode[];\n\nfunction areUrlsEqual(a: string, b: string) {\n try {\n const urlA = new URL(a);\n const urlB = new URL(b);\n\n return urlA.origin === urlB.origin && urlA.pathname === urlB.pathname;\n } catch {\n return false;\n }\n}\n\nconst createParagraphElement = (): OmitTextChildren<ComposerBodyParagraph> => ({\n type: \"paragraph\",\n});\n\nconst ELEMENT_TAGS = {\n A: (\n element\n ): OmitTextChildren<ComposerBodyCustomLink | ComposerBodyAutoLink> => {\n const href = element.getAttribute(\"href\");\n const innerText = element.innerText;\n\n return {\n type: href && areUrlsEqual(href, innerText) ? \"auto-link\" : \"custom-link\",\n url: href ?? \"\",\n };\n },\n P: createParagraphElement,\n // Falling back to paragraphs for unsupported elements\n BLOCKQUOTE: createParagraphElement,\n H1: createParagraphElement,\n H2: createParagraphElement,\n H3: createParagraphElement,\n H4: createParagraphElement,\n H5: createParagraphElement,\n H6: createParagraphElement,\n LI: createParagraphElement,\n} as Record<string, (node: HTMLElement) => ComposerBodyElementTag>;\n\nconst TEXT_TAGS = {\n CODE: (): ComposerBodyTextTag => ({ code: true }),\n DEL: (): ComposerBodyTextTag => ({ strikethrough: true }),\n EM: (): ComposerBodyTextTag => ({ italic: true }),\n I: (): ComposerBodyTextTag => ({ italic: true }),\n S: (): ComposerBodyTextTag => ({ strikethrough: true }),\n STRONG: (): ComposerBodyTextTag => ({ bold: true }),\n // `B` is omitted because Google Docs uses `<b>` in weird ways\n // B: (): ComposerBodyTextTag => ({ bold: true }),\n} as Record<string, (node: HTMLElement) => ComposerBodyTextTag>;\n\nfunction flattenListItems(node: HTMLElement): HTMLElement[] {\n const listItems: HTMLElement[] = [];\n\n if (node.nodeName === \"LI\") {\n listItems.push(node);\n }\n\n node.childNodes.forEach((child) => {\n if (child.nodeType === 1) {\n listItems.push(...flattenListItems(child as HTMLElement));\n }\n });\n\n return listItems;\n}\n\nfunction deserialize(node: Node): DeserializedNode {\n if (node.nodeType === 3) {\n return node.textContent;\n } else if (node.nodeType !== 1) {\n return null;\n } else if (node.nodeName === \"BR\") {\n return \"\\n\";\n }\n\n const childNodes = Array.from(node.childNodes);\n let children = childNodes.map(deserialize).flat();\n\n // Lists aren't supported (yet), so we flatten them into paragraphs\n if (node.nodeName === \"UL\" || node.nodeName === \"OL\") {\n const listItems = flattenListItems(node as HTMLElement);\n\n children = listItems.map((li) => deserialize(li)).flat();\n }\n\n if (children.length === 0) {\n children = [{ text: \"\" }];\n }\n\n if (node.nodeName === \"BODY\") {\n return jsx(\"fragment\", {}, children);\n }\n\n if (ELEMENT_TAGS[node.nodeName]) {\n const attrs = ELEMENT_TAGS[node.nodeName](node as HTMLElement);\n\n return jsx(\"element\", attrs, children);\n }\n\n if (TEXT_TAGS[node.nodeName]) {\n const attrs = TEXT_TAGS[node.nodeName](node as HTMLElement);\n\n return children.map((child) => jsx(\"text\", attrs, child));\n }\n\n return children as DeserializedNode;\n}\n\nexport function withPaste(\n editor: Editor,\n {\n createAttachments,\n pasteFilesAsAttachments,\n }: {\n createAttachments: (files: File[]) => void;\n pasteFilesAsAttachments?: boolean;\n }\n) {\n const { insertData } = editor;\n\n editor.insertData = (data) => {\n // Create attachments from files when pasting\n if (data.types.includes(\"Files\") && pasteFilesAsAttachments) {\n const files = getFiles(data);\n\n if (files.length > 0) {\n createAttachments(files);\n\n return;\n }\n }\n\n // Deserialize rich text from HTML when pasting\n if (data.types.includes(\"text/html\")) {\n const html = data.getData(\"text/html\");\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n const fragment = deserialize(parsed.body);\n\n if (fragment !== null && Array.isArray(fragment)) {\n Transforms.insertFragment(editor, fragment as SlateNode[]);\n\n return;\n }\n }\n\n insertData(data);\n };\n\n return editor;\n}\n"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"paste.mjs","sources":["../../../src/slate/plugins/paste.ts"],"sourcesContent":["import type { Descendant, Editor, Element, Node as SlateNode } from \"slate\";\nimport { Transforms } from \"slate\";\nimport { jsx } from \"slate-hyperscript\";\n\nimport type {\n ComposerBodyAutoLink,\n ComposerBodyBlockElement,\n ComposerBodyCustomLink,\n ComposerBodyInlineElement,\n ComposerBodyParagraph,\n ComposerBodyText,\n} from \"../../types\";\nimport { getFiles } from \"../../utils/data-transfer\";\n\n// Based on: https://github.com/ianstormtaylor/slate/blob/main/site/examples/paste-html.tsx\n\ntype OmitTextChildren<T> = Omit<T, \"text\" | \"children\">;\n\ntype ComposerBodyElementTag = OmitTextChildren<\n ComposerBodyBlockElement | ComposerBodyInlineElement\n>;\ntype ComposerBodyTextTag = OmitTextChildren<ComposerBodyText>;\n\ntype DeserializedNode =\n | string\n | null\n | Element\n | Descendant[]\n | ComposerBodyText[]\n | DeserializedNode[];\n\nfunction areUrlsEqual(a: string, b: string) {\n try {\n const urlA = new URL(a);\n const urlB = new URL(b);\n\n return urlA.origin === urlB.origin && urlA.pathname === urlB.pathname;\n } catch {\n return false;\n }\n}\n\nconst createParagraphElement = (): OmitTextChildren<ComposerBodyParagraph> => ({\n type: \"paragraph\",\n});\n\nconst ELEMENT_TAGS = {\n A: (\n element\n ): OmitTextChildren<ComposerBodyCustomLink | ComposerBodyAutoLink> => {\n const href = element.getAttribute(\"href\");\n const innerText = element.innerText;\n\n return {\n type: href && areUrlsEqual(href, innerText) ? \"auto-link\" : \"custom-link\",\n url: href ?? \"\",\n };\n },\n P: createParagraphElement,\n // Falling back to paragraphs for unsupported elements\n BLOCKQUOTE: createParagraphElement,\n H1: createParagraphElement,\n H2: createParagraphElement,\n H3: createParagraphElement,\n H4: createParagraphElement,\n H5: createParagraphElement,\n H6: createParagraphElement,\n LI: createParagraphElement,\n} as Record<string, (node: HTMLElement) => ComposerBodyElementTag>;\n\nconst TEXT_TAGS = {\n CODE: (): ComposerBodyTextTag => ({ code: true }),\n DEL: (): ComposerBodyTextTag => ({ strikethrough: true }),\n EM: (): ComposerBodyTextTag => ({ italic: true }),\n I: (): ComposerBodyTextTag => ({ italic: true }),\n S: (): ComposerBodyTextTag => ({ strikethrough: true }),\n STRONG: (): ComposerBodyTextTag => ({ bold: true }),\n // `B` is omitted because Google Docs uses `<b>` in weird ways\n // B: (): ComposerBodyTextTag => ({ bold: true }),\n} as Record<string, (node: HTMLElement) => ComposerBodyTextTag>;\n\nfunction flattenListItems(node: HTMLElement): HTMLElement[] {\n const listItems: HTMLElement[] = [];\n\n if (node.nodeName === \"LI\") {\n listItems.push(node);\n }\n\n node.childNodes.forEach((child) => {\n if (child.nodeType === 1) {\n listItems.push(...flattenListItems(child as HTMLElement));\n }\n });\n\n return listItems;\n}\n\nfunction deserialize(node: Node): DeserializedNode {\n if (node.nodeType === 3) {\n return node.textContent;\n } else if (node.nodeType !== 1) {\n return null;\n } else if (node.nodeName === \"BR\") {\n return \"\\n\";\n }\n\n const childNodes = Array.from(node.childNodes);\n let children = childNodes.map(deserialize).flat();\n\n // Lists aren't supported (yet), so we flatten them into paragraphs\n if (node.nodeName === \"UL\" || node.nodeName === \"OL\") {\n const listItems = flattenListItems(node as HTMLElement);\n\n children = listItems.map((li) => deserialize(li)).flat();\n }\n\n if (children.length === 0) {\n children = [{ text: \"\" }];\n }\n\n if (node.nodeName === \"BODY\") {\n return jsx(\"fragment\", {}, children);\n }\n\n if (ELEMENT_TAGS[node.nodeName]) {\n const attrs = ELEMENT_TAGS[node.nodeName]!(node as HTMLElement);\n\n return jsx(\"element\", attrs, children);\n }\n\n if (TEXT_TAGS[node.nodeName]) {\n const attrs = TEXT_TAGS[node.nodeName]!(node as HTMLElement);\n\n return children.map((child) => jsx(\"text\", attrs, child));\n }\n\n return children as DeserializedNode;\n}\n\nexport function withPaste(\n editor: Editor,\n {\n createAttachments,\n pasteFilesAsAttachments,\n }: {\n createAttachments: (files: File[]) => void;\n pasteFilesAsAttachments?: boolean;\n }\n) {\n const { insertData } = editor;\n\n editor.insertData = (data) => {\n // Create attachments from files when pasting\n if (data.types.includes(\"Files\") && pasteFilesAsAttachments) {\n const files = getFiles(data);\n\n if (files.length > 0) {\n createAttachments(files);\n\n return;\n }\n }\n\n // Deserialize rich text from HTML when pasting\n if (data.types.includes(\"text/html\")) {\n const html = data.getData(\"text/html\");\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n const fragment = deserialize(parsed.body);\n\n if (fragment !== null && Array.isArray(fragment)) {\n Transforms.insertFragment(editor, fragment as SlateNode[]);\n\n return;\n }\n }\n\n insertData(data);\n };\n\n return editor;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ function isEmpty(editor, children) {
|
|
|
11
11
|
return false;
|
|
12
12
|
}
|
|
13
13
|
} else if (child.type === "paragraph") {
|
|
14
|
-
if (child.children.length > 1 || !(isText.isText(child.children[0]) && isEmptyString.isEmptyString(child.children[0].text))) {
|
|
14
|
+
if (child.children.length > 1 || child.children[0] && !(isText.isText(child.children[0]) && isEmptyString.isEmptyString(child.children[0].text))) {
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
17
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-empty.js","sources":["../../../src/slate/utils/is-empty.ts"],"sourcesContent":["import type { Descendant } from \"slate\";\nimport { Editor as SlateEditor } from \"slate\";\n\nimport { isEmptyString } from \"./is-empty-string\";\nimport { isText } from \"./is-text\";\n\nexport function isEmpty(editor: SlateEditor, children: Descendant[]) {\n // Check if all blocks are empty, stopping at the first non-empty block\n for (const child of children) {\n if (isText(child)) {\n // Non-empty text\n if (!isEmptyString(child.text)) {\n return false;\n }\n } else if (child.type === \"paragraph\") {\n // Non-empty paragraph\n if (\n child.children.length > 1 ||\n !(isText(child.children[0]) && isEmptyString(child.children[0].text))\n ) {\n return false;\n }\n } else {\n // Non-empty other block\n if (!SlateEditor.isEmpty(editor, child)) {\n return false;\n }\n }\n }\n\n return true;\n}\n"],"names":["isText","isEmptyString","SlateEditor"],"mappings":";;;;;;AAMgB,SAAA,OAAA,CAAQ,QAAqB,QAAwB,EAAA;AAEnE,EAAA,KAAA,MAAW,SAAS,QAAU,EAAA;AAC5B,IAAI,IAAAA,aAAA,CAAO,KAAK,CAAG,EAAA;AAEjB,MAAA,IAAI,CAACC,2BAAA,CAAc,KAAM,CAAA,IAAI,CAAG,EAAA;AAC9B,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AAAA,KACF,MAAA,IAAW,KAAM,CAAA,IAAA,KAAS,WAAa,EAAA;AAErC,MAAA,IACE,
|
|
1
|
+
{"version":3,"file":"is-empty.js","sources":["../../../src/slate/utils/is-empty.ts"],"sourcesContent":["import type { Descendant } from \"slate\";\nimport { Editor as SlateEditor } from \"slate\";\n\nimport { isEmptyString } from \"./is-empty-string\";\nimport { isText } from \"./is-text\";\n\nexport function isEmpty(editor: SlateEditor, children: Descendant[]) {\n // Check if all blocks are empty, stopping at the first non-empty block\n for (const child of children) {\n if (isText(child)) {\n // Non-empty text\n if (!isEmptyString(child.text)) {\n return false;\n }\n } else if (child.type === \"paragraph\") {\n // Non-empty paragraph\n if (\n child.children.length > 1 ||\n (child.children[0] &&\n !(isText(child.children[0]) && isEmptyString(child.children[0].text)))\n ) {\n return false;\n }\n } else {\n // Non-empty other block\n if (!SlateEditor.isEmpty(editor, child)) {\n return false;\n }\n }\n }\n\n return true;\n}\n"],"names":["isText","isEmptyString","SlateEditor"],"mappings":";;;;;;AAMgB,SAAA,OAAA,CAAQ,QAAqB,QAAwB,EAAA;AAEnE,EAAA,KAAA,MAAW,SAAS,QAAU,EAAA;AAC5B,IAAI,IAAAA,aAAA,CAAO,KAAK,CAAG,EAAA;AAEjB,MAAA,IAAI,CAACC,2BAAA,CAAc,KAAM,CAAA,IAAI,CAAG,EAAA;AAC9B,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AAAA,KACF,MAAA,IAAW,KAAM,CAAA,IAAA,KAAS,WAAa,EAAA;AAErC,MAAA,IACE,MAAM,QAAS,CAAA,MAAA,GAAS,KACvB,KAAM,CAAA,QAAA,CAAS,MACd,EAAED,aAAA,CAAO,KAAM,CAAA,QAAA,CAAS,EAAE,CAAK,IAAAC,2BAAA,CAAc,MAAM,QAAS,CAAA,CAAA,CAAA,CAAG,IAAI,CACrE,CAAA,EAAA;AACA,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AAAA,KACK,MAAA;AAEL,MAAA,IAAI,CAACC,YAAA,CAAY,OAAQ,CAAA,MAAA,EAAQ,KAAK,CAAG,EAAA;AACvC,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AAAA,KACF;AAAA,GACF;AAEA,EAAO,OAAA,IAAA,CAAA;AACT;;;;"}
|
|
@@ -9,7 +9,7 @@ function isEmpty(editor, children) {
|
|
|
9
9
|
return false;
|
|
10
10
|
}
|
|
11
11
|
} else if (child.type === "paragraph") {
|
|
12
|
-
if (child.children.length > 1 || !(isText(child.children[0]) && isEmptyString(child.children[0].text))) {
|
|
12
|
+
if (child.children.length > 1 || child.children[0] && !(isText(child.children[0]) && isEmptyString(child.children[0].text))) {
|
|
13
13
|
return false;
|
|
14
14
|
}
|
|
15
15
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-empty.mjs","sources":["../../../src/slate/utils/is-empty.ts"],"sourcesContent":["import type { Descendant } from \"slate\";\nimport { Editor as SlateEditor } from \"slate\";\n\nimport { isEmptyString } from \"./is-empty-string\";\nimport { isText } from \"./is-text\";\n\nexport function isEmpty(editor: SlateEditor, children: Descendant[]) {\n // Check if all blocks are empty, stopping at the first non-empty block\n for (const child of children) {\n if (isText(child)) {\n // Non-empty text\n if (!isEmptyString(child.text)) {\n return false;\n }\n } else if (child.type === \"paragraph\") {\n // Non-empty paragraph\n if (\n child.children.length > 1 ||\n !(isText(child.children[0]) && isEmptyString(child.children[0].text))\n ) {\n return false;\n }\n } else {\n // Non-empty other block\n if (!SlateEditor.isEmpty(editor, child)) {\n return false;\n }\n }\n }\n\n return true;\n}\n"],"names":["SlateEditor"],"mappings":";;;;AAMgB,SAAA,OAAA,CAAQ,QAAqB,QAAwB,EAAA;AAEnE,EAAA,KAAA,MAAW,SAAS,QAAU,EAAA;AAC5B,IAAI,IAAA,MAAA,CAAO,KAAK,CAAG,EAAA;AAEjB,MAAA,IAAI,CAAC,aAAA,CAAc,KAAM,CAAA,IAAI,CAAG,EAAA;AAC9B,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AAAA,KACF,MAAA,IAAW,KAAM,CAAA,IAAA,KAAS,WAAa,EAAA;AAErC,MAAA,IACE,
|
|
1
|
+
{"version":3,"file":"is-empty.mjs","sources":["../../../src/slate/utils/is-empty.ts"],"sourcesContent":["import type { Descendant } from \"slate\";\nimport { Editor as SlateEditor } from \"slate\";\n\nimport { isEmptyString } from \"./is-empty-string\";\nimport { isText } from \"./is-text\";\n\nexport function isEmpty(editor: SlateEditor, children: Descendant[]) {\n // Check if all blocks are empty, stopping at the first non-empty block\n for (const child of children) {\n if (isText(child)) {\n // Non-empty text\n if (!isEmptyString(child.text)) {\n return false;\n }\n } else if (child.type === \"paragraph\") {\n // Non-empty paragraph\n if (\n child.children.length > 1 ||\n (child.children[0] &&\n !(isText(child.children[0]) && isEmptyString(child.children[0].text)))\n ) {\n return false;\n }\n } else {\n // Non-empty other block\n if (!SlateEditor.isEmpty(editor, child)) {\n return false;\n }\n }\n }\n\n return true;\n}\n"],"names":["SlateEditor"],"mappings":";;;;AAMgB,SAAA,OAAA,CAAQ,QAAqB,QAAwB,EAAA;AAEnE,EAAA,KAAA,MAAW,SAAS,QAAU,EAAA;AAC5B,IAAI,IAAA,MAAA,CAAO,KAAK,CAAG,EAAA;AAEjB,MAAA,IAAI,CAAC,aAAA,CAAc,KAAM,CAAA,IAAI,CAAG,EAAA;AAC9B,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AAAA,KACF,MAAA,IAAW,KAAM,CAAA,IAAA,KAAS,WAAa,EAAA;AAErC,MAAA,IACE,MAAM,QAAS,CAAA,MAAA,GAAS,KACvB,KAAM,CAAA,QAAA,CAAS,MACd,EAAE,MAAA,CAAO,KAAM,CAAA,QAAA,CAAS,EAAE,CAAK,IAAA,aAAA,CAAc,MAAM,QAAS,CAAA,CAAA,CAAA,CAAG,IAAI,CACrE,CAAA,EAAA;AACA,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AAAA,KACK,MAAA;AAEL,MAAA,IAAI,CAACA,MAAA,CAAY,OAAQ,CAAA,MAAA,EAAQ,KAAK,CAAG,EAAA;AACvC,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AAAA,KACF;AAAA,GACF;AAEA,EAAO,OAAA,IAAA,CAAA;AACT;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-last-index.js","sources":["../../src/utils/find-last-index.ts"],"sourcesContent":["export function findLastIndex<T>(\n array: T[],\n predicate: (member: T) => unknown\n) {\n let index = array.length - 1;\n\n while (index >= 0) {\n if (predicate(
|
|
1
|
+
{"version":3,"file":"find-last-index.js","sources":["../../src/utils/find-last-index.ts"],"sourcesContent":["export function findLastIndex<T>(\n array: T[],\n predicate: (member: T) => unknown\n) {\n let index = array.length - 1;\n\n while (index >= 0) {\n const element = array[index];\n\n if (element && predicate(element)) {\n return index;\n }\n\n index--;\n }\n\n return -1;\n}\n"],"names":[],"mappings":";;AAAgB,SAAA,aAAA,CACd,OACA,SACA,EAAA;AACA,EAAI,IAAA,KAAA,GAAQ,MAAM,MAAS,GAAA,CAAA,CAAA;AAE3B,EAAA,OAAO,SAAS,CAAG,EAAA;AACjB,IAAA,MAAM,UAAU,KAAM,CAAA,KAAA,CAAA,CAAA;AAEtB,IAAI,IAAA,OAAA,IAAW,SAAU,CAAA,OAAO,CAAG,EAAA;AACjC,MAAO,OAAA,KAAA,CAAA;AAAA,KACT;AAEA,IAAA,KAAA,EAAA,CAAA;AAAA,GACF;AAEA,EAAO,OAAA,CAAA,CAAA,CAAA;AACT;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-last-index.mjs","sources":["../../src/utils/find-last-index.ts"],"sourcesContent":["export function findLastIndex<T>(\n array: T[],\n predicate: (member: T) => unknown\n) {\n let index = array.length - 1;\n\n while (index >= 0) {\n if (predicate(
|
|
1
|
+
{"version":3,"file":"find-last-index.mjs","sources":["../../src/utils/find-last-index.ts"],"sourcesContent":["export function findLastIndex<T>(\n array: T[],\n predicate: (member: T) => unknown\n) {\n let index = array.length - 1;\n\n while (index >= 0) {\n const element = array[index];\n\n if (element && predicate(element)) {\n return index;\n }\n\n index--;\n }\n\n return -1;\n}\n"],"names":[],"mappings":"AAAgB,SAAA,aAAA,CACd,OACA,SACA,EAAA;AACA,EAAI,IAAA,KAAA,GAAQ,MAAM,MAAS,GAAA,CAAA,CAAA;AAE3B,EAAA,OAAO,SAAS,CAAG,EAAA;AACjB,IAAA,MAAM,UAAU,KAAM,CAAA,KAAA,CAAA,CAAA;AAEtB,IAAI,IAAA,OAAA,IAAW,SAAU,CAAA,OAAO,CAAG,EAAA;AACjC,MAAO,OAAA,KAAA,CAAA;AAAA,KACT;AAEA,IAAA,KAAA,EAAA,CAAA;AAAA,GACF;AAEA,EAAO,OAAA,CAAA,CAAA,CAAA;AACT;;;;"}
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-ui\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":";;AAGO,MAAM,QAAW,GAAA,uBAAA;AACX,MAAA,WAAA,GAAiD,
|
|
1
|
+
{"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-ui\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":";;AAGO,MAAM,QAAW,GAAA,uBAAA;AACX,MAAA,WAAA,GAAiD,YAAA;AACjD,MAAA,UAAA,GAAkD;;;;;;"}
|
package/dist/version.mjs
CHANGED
package/dist/version.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.mjs","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-ui\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":"AAGO,MAAM,QAAW,GAAA,uBAAA;AACX,MAAA,WAAA,GAAiD,
|
|
1
|
+
{"version":3,"file":"version.mjs","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-ui\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":"AAGO,MAAM,QAAW,GAAA,uBAAA;AACX,MAAA,WAAA,GAAiD,YAAA;AACjD,MAAA,UAAA,GAAkD;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/react-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0-rc1",
|
|
4
4
|
"description": "A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -75,9 +75,9 @@
|
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
77
|
"@floating-ui/react-dom": "^2.1.1",
|
|
78
|
-
"@liveblocks/client": "2.
|
|
79
|
-
"@liveblocks/core": "2.
|
|
80
|
-
"@liveblocks/react": "2.
|
|
78
|
+
"@liveblocks/client": "2.9.0-rc1",
|
|
79
|
+
"@liveblocks/core": "2.9.0-rc1",
|
|
80
|
+
"@liveblocks/react": "2.9.0-rc1",
|
|
81
81
|
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
|
82
82
|
"@radix-ui/react-popover": "^1.0.7",
|
|
83
83
|
"@radix-ui/react-slot": "^1.0.2",
|