@lofcz/platejs-core 52.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,387 @@
1
+ import { $ as DebugPlugin, A as pluginDeserializeHtml, At as withNormalizeRules, B as collapseWhiteSpaceText, Bt as getPluginKey, C as deserializeHtmlElement, Ct as isSlatePluginNode, D as pipeDeserializeHtmlLeaf, Dt as applyDeepToNodes, E as htmlElementToLeaf, Et as isSlateVoid, F as collapseWhiteSpace, Ft as HistoryPlugin, G as isHtmlBlockElement, Gt as getEditorPlugin, H as upsertInlineFormattingContext, Ht as getPluginType, I as collapseWhiteSpaceElement, It as withPlateHistory, J as isHtmlText, K as isHtmlInlineElement, Kt as createSlatePlugin, L as inferWhiteSpaceRule, Lt as AstPlugin, M as htmlBrToNewLine, Mt as withDeleteRules, N as htmlBodyToFragment, Nt as withBreakRules, O as htmlElementToElement, Ot as OverridePlugin, P as deserializeHtmlNodeChildren, Pt as BaseParagraphPlugin, Q as withScrolling, R as collapseWhiteSpaceChildren, Rt as getContainerTypes, S as htmlStringToDOMNode, St as isSlatePluginElement, T as htmlTextNodeToString, Tt as isSlateText, U as isLastNonEmptyTextOfInlineFormattingContext, Ut as getPluginTypes, V as endInlineFormattingContext, Vt as getPluginKeys, W as collapseString, Wt as getSlatePlugin, X as AUTO_SCROLL, Y as isHtmlElement, Z as DOMPlugin, _ as withNodeId, _t as getSlateElements, a as pipeInsertDataQuery, at as isNodeAffinity, b as parseHtmlDocument, bt as isSlateLeaf, c as setValue, ct as getEdgeNodes, d as init, dt as getPluginNodeProps, et as PlateError, ft as getNodeDataAttributeKeys, g as normalizeNodeId, gt as defaultsDeepToNodes, h as NodeIdPlugin, ht as getInjectMatch, i as ParserPlugin, it as setAffinitySelection, j as getDataNodeProps, jt as withMergeRules, k as pipeDeserializeHtmlElement, kt as withOverrides, l as resetBlock, lt as mergeDeepToNodes, m as pipeOnNodeChange, mt as getInjectedPlugins, n as withSlate, nt as withChunking, o as normalizeDescendantsToDocumentFragment, ot as isNodesAffinity, p as pipeOnTextChange, pt as keyToDataAttribute, q as inlineTagNames, qt as createTSlatePlugin, r as getCorePlugins, rt as AffinityPlugin, s as SlateExtensionPlugin, st as getMarkBoundaryAffinity, t as createSlateEditor, tt as ChunkingPlugin, u as insertExitBreak, ut as getSlateClass, v as LengthPlugin, vt as isSlateEditor, w as deserializeHtmlNode, wt as isSlateString, x as deserializeHtml, xt as isSlateNode, y as HtmlPlugin, yt as isSlateElement, z as collapseWhiteSpaceNode, zt as getPluginByType } from "./withSlate-1B0SfAWG.js";
2
+ import { n as createHotkey, r as isHotkey, t as Hotkeys } from "./hotkeys-DI1HPO2Q.js";
3
+ import { nanoid } from "nanoid";
4
+ import { createVanillaStore as createZustandStore } from "zustand-x/vanilla";
5
+ import castArray from "lodash/castArray.js";
6
+ import defaultsDeep from "lodash/defaultsDeep.js";
7
+
8
+ //#region src/lib/utils/isType.ts
9
+ /** Does the node match the type provided. */
10
+ const isType = (editor, node, key) => {
11
+ const keys = castArray(key);
12
+ const types = [];
13
+ for (const _key of keys) types.push(editor.getType(_key));
14
+ return types.includes(node?.type);
15
+ };
16
+
17
+ //#endregion
18
+ //#region src/lib/plugins/html/constants.ts
19
+ const CARRIAGE_RETURN = "\r";
20
+ const LINE_FEED = "\n";
21
+ const NO_BREAK_SPACE = "\xA0";
22
+ const SPACE = " ";
23
+ const TAB = " ";
24
+ const ZERO_WIDTH_SPACE = "​";
25
+
26
+ //#endregion
27
+ //#region src/lib/plugins/html/utils/traverseHtmlNode.ts
28
+ /**
29
+ * Depth-first pre-order tree traverse the given HTML node and calls the given
30
+ * callback for each node. see:
31
+ * https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_(NLR)
32
+ *
33
+ * @param callback Returns a boolean indicating whether traversal should be
34
+ * continued
35
+ */
36
+ const traverseHtmlNode = (node, callback) => {
37
+ if (!callback(node)) return;
38
+ let child = node.firstChild;
39
+ while (child) {
40
+ const currentChild = child;
41
+ const previousChild = child.previousSibling;
42
+ child = child.nextSibling;
43
+ traverseHtmlNode(currentChild, callback);
44
+ if (!currentChild.previousSibling && !currentChild.nextSibling && !currentChild.parentNode && child && previousChild !== child.previousSibling && child.parentNode) child = previousChild ? previousChild.nextSibling : node.firstChild;
45
+ else if (!currentChild.previousSibling && !currentChild.nextSibling && !currentChild.parentNode && child && !child.previousSibling && !child.nextSibling && !child.parentNode) {
46
+ if (previousChild) child = previousChild.nextSibling ? previousChild.nextSibling.nextSibling : null;
47
+ else if (node.firstChild) child = node.firstChild.nextSibling;
48
+ }
49
+ }
50
+ };
51
+
52
+ //#endregion
53
+ //#region src/lib/plugins/html/utils/traverseHtmlElements.ts
54
+ /**
55
+ * Traverse the HTML elements of the given HTML node.
56
+ *
57
+ * @param rootNode The root HTML node to traverse.
58
+ * @param callback The callback to call for each HTML element.
59
+ */
60
+ const traverseHtmlElements = (rootNode, callback) => {
61
+ traverseHtmlNode(rootNode, (node) => {
62
+ if (!isHtmlElement(node)) return true;
63
+ return callback(node);
64
+ });
65
+ };
66
+
67
+ //#endregion
68
+ //#region src/lib/plugins/html/utils/cleanHtmlBrElements.ts
69
+ /** Replace BR elements with line feeds. */
70
+ const cleanHtmlBrElements = (rootNode) => {
71
+ traverseHtmlElements(rootNode, (element) => {
72
+ if (element.tagName !== "BR") return true;
73
+ const replacementTextNode = document.createTextNode(LINE_FEED);
74
+ if (element.parentElement) element.parentElement.replaceChild(replacementTextNode, element);
75
+ return false;
76
+ });
77
+ };
78
+
79
+ //#endregion
80
+ //#region src/lib/plugins/html/utils/cleanHtmlCrLf.ts
81
+ /** Replace \r\n and \r with \n */
82
+ const cleanHtmlCrLf = (html) => html.replaceAll(/\r\n|\r/g, "\n");
83
+
84
+ //#endregion
85
+ //#region src/lib/plugins/html/utils/cleanHtmlEmptyElements.ts
86
+ const ALLOWED_EMPTY_ELEMENTS = new Set([
87
+ "BR",
88
+ "IMG",
89
+ "TD",
90
+ "TH"
91
+ ]);
92
+ const isEmpty = (element) => !ALLOWED_EMPTY_ELEMENTS.has(element.nodeName) && !element.innerHTML.trim();
93
+ const removeIfEmpty = (element) => {
94
+ if (isEmpty(element)) {
95
+ const { parentElement } = element;
96
+ element.remove();
97
+ if (parentElement) removeIfEmpty(parentElement);
98
+ }
99
+ };
100
+ /** Remove empty elements from rootNode. Allowed empty elements: BR, IMG. */
101
+ const cleanHtmlEmptyElements = (rootNode) => {
102
+ traverseHtmlElements(rootNode, (element) => {
103
+ removeIfEmpty(element);
104
+ return true;
105
+ });
106
+ };
107
+
108
+ //#endregion
109
+ //#region src/lib/plugins/html/utils/replaceTagName.ts
110
+ /**
111
+ * Replace `element` tag name by `tagName`. Attributes, innerHTML and parent
112
+ * relationship is kept.
113
+ */
114
+ const replaceTagName = (element, tagName) => {
115
+ const newElement = document.createElement(tagName);
116
+ newElement.innerHTML = element.innerHTML;
117
+ for (const { name } of element.attributes) {
118
+ const value = element.getAttribute(name);
119
+ if (value) newElement.setAttribute(name, value);
120
+ }
121
+ if (element.parentNode) element.parentNode.replaceChild(newElement, element);
122
+ return newElement;
123
+ };
124
+
125
+ //#endregion
126
+ //#region src/lib/plugins/html/utils/cleanHtmlFontElements.ts
127
+ /**
128
+ * Replace FONT elements with SPAN elements if there is textContent (remove
129
+ * otherwise).
130
+ */
131
+ const cleanHtmlFontElements = (rootNode) => {
132
+ traverseHtmlElements(rootNode, (element) => {
133
+ if (element.tagName === "FONT") if (element.textContent) replaceTagName(element, "span");
134
+ else element.remove();
135
+ return true;
136
+ });
137
+ };
138
+
139
+ //#endregion
140
+ //#region src/lib/plugins/html/utils/isHtmlFragmentHref.ts
141
+ /** If href starts with '#'. */
142
+ const isHtmlFragmentHref = (href) => href.startsWith("#");
143
+
144
+ //#endregion
145
+ //#region src/lib/plugins/html/utils/unwrapHtmlElement.ts
146
+ /** Unwrap the given HTML element. */
147
+ const unwrapHtmlElement = (element) => {
148
+ element.outerHTML = element.innerHTML;
149
+ };
150
+
151
+ //#endregion
152
+ //#region src/lib/plugins/html/utils/cleanHtmlLinkElements.ts
153
+ /** Remove fragment hrefs and spans without inner text. */
154
+ const cleanHtmlLinkElements = (rootNode) => {
155
+ traverseHtmlElements(rootNode, (element) => {
156
+ if (element.tagName !== "A") return true;
157
+ const href = element.getAttribute("href");
158
+ if (!href || isHtmlFragmentHref(href)) unwrapHtmlElement(element);
159
+ if (href && element.querySelector("img")) {
160
+ for (const span of element.querySelectorAll("span")) if (!span.textContent) unwrapHtmlElement(span);
161
+ }
162
+ return true;
163
+ });
164
+ };
165
+
166
+ //#endregion
167
+ //#region src/lib/plugins/html/utils/traverseHtmlTexts.ts
168
+ const traverseHtmlTexts = (rootNode, callback) => {
169
+ traverseHtmlNode(rootNode, (node) => {
170
+ if (!isHtmlText(node)) return true;
171
+ return callback(node);
172
+ });
173
+ };
174
+
175
+ //#endregion
176
+ //#region src/lib/plugins/html/utils/cleanHtmlTextNodes.ts
177
+ const NEWLINE_WHITESPACE_REGEX = /^\n\s*$/;
178
+ const NON_WHITESPACE_REGEX = /\S/;
179
+ const LEADING_NEWLINES_REGEX = /^[\n\r]+/;
180
+ const cleanHtmlTextNodes = (rootNode) => {
181
+ traverseHtmlTexts(rootNode, (textNode) => {
182
+ if (NEWLINE_WHITESPACE_REGEX.test(textNode.data) && (textNode.previousElementSibling || textNode.nextElementSibling)) {
183
+ textNode.remove();
184
+ return true;
185
+ }
186
+ textNode.data = textNode.data.replaceAll(/\n\s*/g, "\n");
187
+ if (textNode.data.includes(CARRIAGE_RETURN) || textNode.data.includes(LINE_FEED) || textNode.data.includes(NO_BREAK_SPACE)) {
188
+ const hasSpace = textNode.data.includes(SPACE);
189
+ const hasNonWhitespace = NON_WHITESPACE_REGEX.test(textNode.data);
190
+ const hasLineFeed = textNode.data.includes(LINE_FEED);
191
+ if (!(hasSpace || hasNonWhitespace) && !hasLineFeed) {
192
+ if (textNode.data === NO_BREAK_SPACE) {
193
+ textNode.data = SPACE;
194
+ return true;
195
+ }
196
+ textNode.remove();
197
+ return true;
198
+ }
199
+ if (textNode.previousSibling && textNode.previousSibling.nodeName === "BR" && textNode.parentElement) {
200
+ textNode.previousSibling.remove();
201
+ const matches = LEADING_NEWLINES_REGEX.exec(textNode.data);
202
+ const offset = matches ? matches[0].length : 0;
203
+ textNode.data = textNode.data.slice(Math.max(0, offset)).replaceAll(new RegExp(LINE_FEED, "g"), SPACE).replaceAll(new RegExp(CARRIAGE_RETURN, "g"), SPACE);
204
+ textNode.data = `\n${textNode.data}`;
205
+ } else textNode.data = textNode.data.replaceAll(new RegExp(LINE_FEED, "g"), SPACE).replaceAll(new RegExp(CARRIAGE_RETURN, "g"), SPACE);
206
+ }
207
+ return true;
208
+ });
209
+ };
210
+
211
+ //#endregion
212
+ //#region src/lib/plugins/html/utils/isHtmlTable.ts
213
+ const isHtmlTable = (element) => element.nodeName === "TABLE";
214
+
215
+ //#endregion
216
+ //#region src/lib/plugins/html/utils/copyBlockMarksToSpanChild.ts
217
+ /**
218
+ * Set HTML blocks mark styles to a new child span element if any. This allows
219
+ * Plate to use block marks.
220
+ */
221
+ const copyBlockMarksToSpanChild = (rootNode) => {
222
+ traverseHtmlElements(rootNode, (element) => {
223
+ const el = element;
224
+ if (!element.getAttribute("style")) return true;
225
+ if (isHtmlBlockElement(el) && !isHtmlTable(el)) {
226
+ const { style: { backgroundColor, color, fontFamily, fontSize, fontStyle, fontWeight, textDecoration } } = el;
227
+ if (backgroundColor || color || fontFamily || fontSize || fontStyle || fontWeight || textDecoration) {
228
+ const span = document.createElement("span");
229
+ if (!["inherit", "initial"].includes(color)) span.style.color = color;
230
+ span.style.fontFamily = fontFamily;
231
+ span.style.fontSize = fontSize;
232
+ if (![
233
+ "inherit",
234
+ "initial",
235
+ "normal"
236
+ ].includes(color)) span.style.fontStyle = fontStyle;
237
+ if (![400, "normal"].includes(fontWeight)) span.style.fontWeight = fontWeight;
238
+ span.style.textDecoration = textDecoration;
239
+ span.innerHTML = el.innerHTML;
240
+ element.innerHTML = span.outerHTML;
241
+ }
242
+ }
243
+ return true;
244
+ });
245
+ };
246
+
247
+ //#endregion
248
+ //#region src/lib/plugins/html/utils/findHtmlElement.ts
249
+ /**
250
+ * Find the first HTML element that matches the given selector.
251
+ *
252
+ * @param rootNode
253
+ * @param predicate
254
+ */
255
+ const findHtmlElement = (rootNode, predicate) => {
256
+ let res = null;
257
+ traverseHtmlElements(rootNode, (node) => {
258
+ if (predicate(node)) {
259
+ res = node;
260
+ return false;
261
+ }
262
+ return true;
263
+ });
264
+ return res;
265
+ };
266
+ const someHtmlElement = (rootNode, predicate) => !!findHtmlElement(rootNode, predicate);
267
+
268
+ //#endregion
269
+ //#region src/lib/plugins/html/utils/getHtmlComments.ts
270
+ const acceptNode = () => NodeFilter.FILTER_ACCEPT;
271
+ const getHtmlComments = (node) => {
272
+ const comments = [];
273
+ const iterator = document.createNodeIterator(node, NodeFilter.SHOW_COMMENT, { acceptNode });
274
+ let currentNode = iterator.nextNode();
275
+ while (currentNode) {
276
+ if (currentNode.nodeValue) comments.push(currentNode.nodeValue);
277
+ currentNode = iterator.nextNode();
278
+ }
279
+ return comments;
280
+ };
281
+
282
+ //#endregion
283
+ //#region src/lib/plugins/html/utils/isHtmlComment.ts
284
+ const isHtmlComment = (node) => node.nodeType === Node.COMMENT_NODE;
285
+
286
+ //#endregion
287
+ //#region src/lib/plugins/html/utils/isOlSymbol.ts
288
+ const OL_SYMBOL_REGEX = /[\da-np-z]\S/;
289
+ const isOlSymbol = (symbol) => OL_SYMBOL_REGEX.test(symbol.toLowerCase());
290
+
291
+ //#endregion
292
+ //#region src/lib/plugins/html/utils/parseHtmlElement.ts
293
+ const parseHtmlElement = (html) => {
294
+ const { body } = parseHtmlDocument(html);
295
+ return body.firstElementChild;
296
+ };
297
+
298
+ //#endregion
299
+ //#region src/lib/plugins/html/utils/postCleanHtml.ts
300
+ /** Trim the html and remove zero width spaces, then wrap it with a body element. */
301
+ const postCleanHtml = (html) => {
302
+ return `<body>${html.trim().replaceAll(new RegExp(ZERO_WIDTH_SPACE, "g"), "")}</body>`;
303
+ };
304
+
305
+ //#endregion
306
+ //#region src/lib/plugins/html/utils/removeHtmlSurroundings.ts
307
+ /** Remove string before <html */
308
+ const removeBeforeHtml = (html) => {
309
+ const index = html.indexOf("<html");
310
+ if (index === -1) return html;
311
+ return html.slice(Math.max(0, index));
312
+ };
313
+ /** Remove string after </html> */
314
+ const removeAfterHtml = (html) => {
315
+ const index = html.lastIndexOf("</html>");
316
+ if (index === -1) return html;
317
+ return html.slice(0, Math.max(0, index + 7));
318
+ };
319
+ /** Remove string before <html and after </html> */
320
+ const removeHtmlSurroundings = (html) => removeBeforeHtml(removeAfterHtml(html));
321
+
322
+ //#endregion
323
+ //#region src/lib/plugins/html/utils/preCleanHtml.ts
324
+ const cleaners = [removeHtmlSurroundings, cleanHtmlCrLf];
325
+ /** Remove HTML surroundings and clean HTML from CR/LF */
326
+ const preCleanHtml = (html) => cleaners.reduce((result, clean) => clean(result), html);
327
+
328
+ //#endregion
329
+ //#region src/lib/plugins/html/utils/traverseHtmlComments.ts
330
+ /** Traverse HTML comments. */
331
+ const traverseHtmlComments = (rootNode, callback) => {
332
+ traverseHtmlNode(rootNode, (node) => {
333
+ if (!isHtmlComment(node)) return true;
334
+ return callback(node);
335
+ });
336
+ };
337
+
338
+ //#endregion
339
+ //#region src/lib/plugins/html/utils/removeHtmlNodesBetweenComments.ts
340
+ /** Removes HTML nodes between HTML comments. */
341
+ const removeHtmlNodesBetweenComments = (rootNode, start, end) => {
342
+ const isClosingComment = (node) => isHtmlComment(node) && node.data === end;
343
+ traverseHtmlComments(rootNode, (comment) => {
344
+ if (comment.data === start) {
345
+ let node = comment.nextSibling;
346
+ comment.remove();
347
+ while (node && !isClosingComment(node)) {
348
+ const { nextSibling } = node;
349
+ node.remove();
350
+ node = nextSibling;
351
+ }
352
+ if (node && isClosingComment(node)) node.remove();
353
+ }
354
+ return true;
355
+ });
356
+ };
357
+
358
+ //#endregion
359
+ //#region src/lib/utils/omitPluginContext.ts
360
+ const omitPluginContext = (ctx) => {
361
+ const { api, editor, getOption, getOptions, plugin, setOption, setOptions, tf, type, ...rest } = ctx;
362
+ return rest;
363
+ };
364
+
365
+ //#endregion
366
+ //#region src/lib/utils/overridePluginsByKey.ts
367
+ /**
368
+ * Recursive deep merge of each plugin from `override.plugins` into plugin with
369
+ * same key (plugin > plugin.plugins).
370
+ */
371
+ const overridePluginsByKey = (plugin, overrideByKey = {}, nested = false) => {
372
+ if (overrideByKey[plugin.key]) {
373
+ const { __extensions: pluginOverridesExtensions, plugins: pluginOverridesPlugins, ...pluginOverrides } = overrideByKey[plugin.key];
374
+ plugin = defaultsDeep({}, pluginOverrides, plugin);
375
+ if (pluginOverridesExtensions) plugin.__extensions = [...plugin.__extensions || [], ...pluginOverridesExtensions];
376
+ if (!nested) pluginOverridesPlugins?.forEach((pOverrides) => {
377
+ if (!plugin.plugins) plugin.plugins = [];
378
+ if (!plugin.plugins.find((p) => p.key === pOverrides.key)) plugin.plugins.push(pOverrides);
379
+ });
380
+ }
381
+ if (plugin.plugins) plugin.plugins = plugin.plugins.map((p) => overridePluginsByKey(p, overrideByKey, true));
382
+ return plugin;
383
+ };
384
+
385
+ //#endregion
386
+ export { AUTO_SCROLL, AffinityPlugin, AstPlugin, BaseParagraphPlugin, CARRIAGE_RETURN, ChunkingPlugin, DOMPlugin, DebugPlugin, HistoryPlugin, Hotkeys, HtmlPlugin, LINE_FEED, LengthPlugin, NO_BREAK_SPACE, NodeIdPlugin, OverridePlugin, ParserPlugin, PlateError, SPACE, SlateExtensionPlugin, TAB, ZERO_WIDTH_SPACE, applyDeepToNodes, cleanHtmlBrElements, cleanHtmlCrLf, cleanHtmlEmptyElements, cleanHtmlFontElements, cleanHtmlLinkElements, cleanHtmlTextNodes, collapseString, collapseWhiteSpace, collapseWhiteSpaceChildren, collapseWhiteSpaceElement, collapseWhiteSpaceNode, collapseWhiteSpaceText, copyBlockMarksToSpanChild, createHotkey, createSlateEditor, createSlatePlugin, createTSlatePlugin, createZustandStore, defaultsDeepToNodes, deserializeHtml, deserializeHtmlElement, deserializeHtmlNode, deserializeHtmlNodeChildren, endInlineFormattingContext, findHtmlElement, getContainerTypes, getCorePlugins, getDataNodeProps, getEdgeNodes, getEditorPlugin, getHtmlComments, getInjectMatch, getInjectedPlugins, getMarkBoundaryAffinity, getNodeDataAttributeKeys, getPluginByType, getPluginKey, getPluginKeys, getPluginNodeProps, getPluginType, getPluginTypes, getSlateClass, getSlateElements, getSlatePlugin, htmlBodyToFragment, htmlBrToNewLine, htmlElementToElement, htmlElementToLeaf, htmlStringToDOMNode, htmlTextNodeToString, inferWhiteSpaceRule, init, inlineTagNames, insertExitBreak, isHotkey, isHtmlBlockElement, isHtmlComment, isHtmlElement, isHtmlFragmentHref, isHtmlInlineElement, isHtmlTable, isHtmlText, isLastNonEmptyTextOfInlineFormattingContext, isNodeAffinity, isNodesAffinity, isOlSymbol, isSlateEditor, isSlateElement, isSlateLeaf, isSlateNode, isSlatePluginElement, isSlatePluginNode, isSlateString, isSlateText, isSlateVoid, isType, keyToDataAttribute, mergeDeepToNodes, nanoid, normalizeDescendantsToDocumentFragment, normalizeNodeId, omitPluginContext, overridePluginsByKey, parseHtmlDocument, parseHtmlElement, pipeDeserializeHtmlElement, pipeDeserializeHtmlLeaf, pipeInsertDataQuery, pipeOnNodeChange, pipeOnTextChange, pluginDeserializeHtml, postCleanHtml, preCleanHtml, removeHtmlNodesBetweenComments, removeHtmlSurroundings, replaceTagName, resetBlock, setAffinitySelection, setValue, someHtmlElement, traverseHtmlComments, traverseHtmlElements, traverseHtmlNode, traverseHtmlTexts, unwrapHtmlElement, upsertInlineFormattingContext, withBreakRules, withChunking, withDeleteRules, withMergeRules, withNodeId, withNormalizeRules, withOverrides, withPlateHistory, withScrolling, withSlate };
387
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["castArray","SlateEditor","isType","editor","node","key","keys","types","_key","push","getType","includes","type","CARRIAGE_RETURN","LINE_FEED","NO_BREAK_SPACE","SPACE","TAB","ZERO_WIDTH_SPACE","Callback","node","Node","traverseHtmlNode","callback","keepTraversing","child","firstChild","currentChild","previousChild","previousSibling","nextSibling","parentNode","isHtmlElement","traverseHtmlNode","Callback","node","Element","traverseHtmlElements","rootNode","Node","callback","LINE_FEED","traverseHtmlElements","cleanHtmlBrElements","rootNode","Node","element","tagName","replacementTextNode","document","createTextNode","parentElement","replaceChild","cleanHtmlCrLf","html","replaceAll","traverseHtmlElements","ALLOWED_EMPTY_ELEMENTS","Set","isEmpty","element","Element","has","nodeName","innerHTML","trim","removeIfEmpty","parentElement","remove","cleanHtmlEmptyElements","rootNode","Node","replaceTagName","element","Element","tagName","newElement","document","createElement","innerHTML","name","attributes","value","getAttribute","setAttribute","parentNode","replaceChild","replaceTagName","traverseHtmlElements","cleanHtmlFontElements","rootNode","Node","element","tagName","textContent","remove","isHtmlFragmentHref","href","startsWith","unwrapHtmlElement","element","Element","outerHTML","innerHTML","isHtmlFragmentHref","traverseHtmlElements","unwrapHtmlElement","cleanHtmlLinkElements","rootNode","Node","element","tagName","href","getAttribute","querySelector","span","querySelectorAll","textContent","isHtmlText","traverseHtmlNode","Callback","node","Text","traverseHtmlTexts","rootNode","Node","callback","CARRIAGE_RETURN","LINE_FEED","NO_BREAK_SPACE","SPACE","traverseHtmlTexts","NEWLINE_WHITESPACE_REGEX","NON_WHITESPACE_REGEX","LEADING_NEWLINES_REGEX","cleanHtmlTextNodes","rootNode","Node","textNode","test","data","previousElementSibling","nextElementSibling","remove","replaceAll","includes","hasSpace","hasNonWhitespace","hasLineFeed","previousSibling","nodeName","parentElement","matches","exec","offset","length","slice","Math","max","RegExp","isHtmlTable","element","Element","nodeName","isHtmlBlockElement","isHtmlTable","traverseHtmlElements","copyBlockMarksToSpanChild","rootNode","Node","element","el","HTMLElement","styleAttribute","getAttribute","style","backgroundColor","color","fontFamily","fontSize","fontStyle","fontWeight","textDecoration","span","document","createElement","includes","innerHTML","outerHTML","traverseHtmlElements","findHtmlElement","rootNode","Node","predicate","node","HTMLElement","res","someHtmlElement","acceptNode","NodeFilter","FILTER_ACCEPT","getHtmlComments","node","Node","comments","iterator","document","createNodeIterator","SHOW_COMMENT","currentNode","nextNode","nodeValue","push","isHtmlComment","node","Node","Comment","nodeType","COMMENT_NODE","OL_SYMBOL_REGEX","isOlSymbol","symbol","test","toLowerCase","parseHtmlDocument","parseHtmlElement","html","body","firstElementChild","HTMLElement","ZERO_WIDTH_SPACE","postCleanHtml","html","cleanHtml","trim","replaceAll","RegExp","removeBeforeHtml","html","index","indexOf","slice","Math","max","removeAfterHtml","lastIndexOf","length","removeHtmlSurroundings","cleanHtmlCrLf","removeHtmlSurroundings","cleaners","preCleanHtml","html","reduce","result","clean","isHtmlComment","traverseHtmlNode","Callback","node","Comment","traverseHtmlComments","rootNode","Node","callback","isHtmlComment","traverseHtmlComments","removeHtmlNodesBetweenComments","rootNode","Node","start","end","isClosingComment","node","data","comment","nextSibling","remove","AnySlatePlugin","SlatePluginContext","omitPluginContext","ctx","T","api","editor","getOption","getOptions","plugin","setOption","setOptions","tf","type","rest","defaultsDeep","AnySlatePlugin","overridePluginsByKey","plugin","overrideByKey","Record","Partial","nested","key","__extensions","pluginOverridesExtensions","plugins","pluginOverridesPlugins","pluginOverrides","forEach","pOverrides","found","find","p","push","map"],"sources":["../src/lib/utils/isType.ts","../src/lib/plugins/html/constants.ts","../src/lib/plugins/html/utils/traverseHtmlNode.ts","../src/lib/plugins/html/utils/traverseHtmlElements.ts","../src/lib/plugins/html/utils/cleanHtmlBrElements.ts","../src/lib/plugins/html/utils/cleanHtmlCrLf.ts","../src/lib/plugins/html/utils/cleanHtmlEmptyElements.ts","../src/lib/plugins/html/utils/replaceTagName.ts","../src/lib/plugins/html/utils/cleanHtmlFontElements.ts","../src/lib/plugins/html/utils/isHtmlFragmentHref.ts","../src/lib/plugins/html/utils/unwrapHtmlElement.ts","../src/lib/plugins/html/utils/cleanHtmlLinkElements.ts","../src/lib/plugins/html/utils/traverseHtmlTexts.ts","../src/lib/plugins/html/utils/cleanHtmlTextNodes.ts","../src/lib/plugins/html/utils/isHtmlTable.ts","../src/lib/plugins/html/utils/copyBlockMarksToSpanChild.ts","../src/lib/plugins/html/utils/findHtmlElement.ts","../src/lib/plugins/html/utils/getHtmlComments.ts","../src/lib/plugins/html/utils/isHtmlComment.ts","../src/lib/plugins/html/utils/isOlSymbol.ts","../src/lib/plugins/html/utils/parseHtmlElement.ts","../src/lib/plugins/html/utils/postCleanHtml.ts","../src/lib/plugins/html/utils/removeHtmlSurroundings.ts","../src/lib/plugins/html/utils/preCleanHtml.ts","../src/lib/plugins/html/utils/traverseHtmlComments.ts","../src/lib/plugins/html/utils/removeHtmlNodesBetweenComments.ts","../src/lib/utils/omitPluginContext.ts","../src/lib/utils/overridePluginsByKey.ts"],"sourcesContent":["import castArray from 'lodash/castArray.js';\n\nimport type { SlateEditor } from '../editor';\n\n/** Does the node match the type provided. */\nexport const isType = (\n editor: SlateEditor,\n node: any,\n key?: string[] | string\n) => {\n const keys = castArray(key);\n const types: string[] = [];\n\n for (const _key of keys) {\n types.push(editor.getType(_key));\n }\n\n return types.includes(node?.type);\n};\n","export const CARRIAGE_RETURN = '\\u000D';\n\nexport const LINE_FEED = '\\u000A';\n\nexport const NO_BREAK_SPACE = '\\u00A0';\n\nexport const SPACE = '\\u0020';\n\nexport const TAB = '\\u0009';\n\nexport const ZERO_WIDTH_SPACE = '\\u200B';\n","type Callback = (node: Node) => boolean;\n\n/**\n * Depth-first pre-order tree traverse the given HTML node and calls the given\n * callback for each node. see:\n * https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_(NLR)\n *\n * @param callback Returns a boolean indicating whether traversal should be\n * continued\n */\nexport const traverseHtmlNode = (node: Node, callback: Callback): void => {\n const keepTraversing = callback(node);\n\n if (!keepTraversing) {\n return;\n }\n\n let child = node.firstChild;\n\n while (child) {\n const currentChild = child;\n const previousChild = child.previousSibling;\n child = child.nextSibling;\n\n traverseHtmlNode(currentChild, callback);\n\n if (\n // An unwrap was made. Need to compute the next child again.\n !currentChild.previousSibling &&\n !currentChild.nextSibling &&\n !currentChild.parentNode &&\n child &&\n previousChild !== child.previousSibling &&\n child.parentNode\n ) {\n child = previousChild ? previousChild.nextSibling : node.firstChild;\n } else if (\n // A list was created. Need to compute the next child again.\n !currentChild.previousSibling &&\n !currentChild.nextSibling &&\n !currentChild.parentNode &&\n child &&\n !child.previousSibling &&\n !child.nextSibling &&\n !child.parentNode\n ) {\n if (previousChild) {\n child = previousChild.nextSibling\n ? previousChild.nextSibling.nextSibling\n : null;\n } else if (node.firstChild) {\n child = node.firstChild.nextSibling;\n }\n }\n }\n};\n","import { isHtmlElement } from './isHtmlElement';\nimport { traverseHtmlNode } from './traverseHtmlNode';\n\ntype Callback = (node: Element) => boolean;\n\n/**\n * Traverse the HTML elements of the given HTML node.\n *\n * @param rootNode The root HTML node to traverse.\n * @param callback The callback to call for each HTML element.\n */\nexport const traverseHtmlElements = (\n rootNode: Node,\n callback: Callback\n): void => {\n traverseHtmlNode(rootNode, (node) => {\n if (!isHtmlElement(node)) {\n return true;\n }\n\n return callback(node);\n });\n};\n","import { LINE_FEED } from '../constants';\nimport { traverseHtmlElements } from './traverseHtmlElements';\n\n/** Replace BR elements with line feeds. */\nexport const cleanHtmlBrElements = (rootNode: Node): void => {\n traverseHtmlElements(rootNode, (element) => {\n if (element.tagName !== 'BR') {\n return true;\n }\n\n const replacementTextNode = document.createTextNode(LINE_FEED);\n\n if (element.parentElement) {\n element.parentElement.replaceChild(replacementTextNode, element);\n }\n\n return false;\n });\n};\n","/** Replace \\r\\n and \\r with \\n */\nexport const cleanHtmlCrLf = (html: string): string =>\n html.replaceAll(/\\r\\n|\\r/g, '\\n');\n","import { traverseHtmlElements } from './traverseHtmlElements';\n\nconst ALLOWED_EMPTY_ELEMENTS = new Set(['BR', 'IMG', 'TD', 'TH']);\n\nconst isEmpty = (element: Element): boolean =>\n !ALLOWED_EMPTY_ELEMENTS.has(element.nodeName) && !element.innerHTML.trim();\n\nconst removeIfEmpty = (element: Element): void => {\n if (isEmpty(element)) {\n const { parentElement } = element;\n\n element.remove();\n\n if (parentElement) {\n removeIfEmpty(parentElement);\n }\n }\n};\n\n/** Remove empty elements from rootNode. Allowed empty elements: BR, IMG. */\nexport const cleanHtmlEmptyElements = (rootNode: Node): void => {\n traverseHtmlElements(rootNode, (element) => {\n removeIfEmpty(element);\n\n return true;\n });\n};\n","/**\n * Replace `element` tag name by `tagName`. Attributes, innerHTML and parent\n * relationship is kept.\n */\nexport const replaceTagName = (element: Element, tagName: string): Element => {\n const newElement = document.createElement(tagName);\n\n newElement.innerHTML = element.innerHTML;\n\n for (const { name } of element.attributes) {\n const value = element.getAttribute(name);\n\n if (value) {\n newElement.setAttribute(name, value);\n }\n }\n\n if (element.parentNode) {\n element.parentNode.replaceChild(newElement, element);\n }\n\n return newElement;\n};\n","import { replaceTagName } from './replaceTagName';\nimport { traverseHtmlElements } from './traverseHtmlElements';\n\n/**\n * Replace FONT elements with SPAN elements if there is textContent (remove\n * otherwise).\n */\nexport const cleanHtmlFontElements = (rootNode: Node): void => {\n traverseHtmlElements(rootNode, (element) => {\n if (element.tagName === 'FONT') {\n if (element.textContent) {\n replaceTagName(element, 'span');\n } else {\n element.remove();\n }\n }\n\n return true;\n });\n};\n","/** If href starts with '#'. */\nexport const isHtmlFragmentHref = (href: string): boolean =>\n href.startsWith('#');\n","/** Unwrap the given HTML element. */\nexport const unwrapHtmlElement = (element: Element): void => {\n element.outerHTML = element.innerHTML;\n};\n","import { isHtmlFragmentHref } from './isHtmlFragmentHref';\nimport { traverseHtmlElements } from './traverseHtmlElements';\nimport { unwrapHtmlElement } from './unwrapHtmlElement';\n\n/** Remove fragment hrefs and spans without inner text. */\nexport const cleanHtmlLinkElements = (rootNode: Node): void => {\n traverseHtmlElements(rootNode, (element) => {\n if (element.tagName !== 'A') {\n return true;\n }\n\n const href = element.getAttribute('href');\n\n if (!href || isHtmlFragmentHref(href)) {\n unwrapHtmlElement(element);\n }\n if (href && element.querySelector('img')) {\n for (const span of element.querySelectorAll('span')) {\n if (!span.textContent) {\n unwrapHtmlElement(span);\n }\n }\n }\n\n return true;\n });\n};\n","import { isHtmlText } from './isHtmlText';\nimport { traverseHtmlNode } from './traverseHtmlNode';\n\ntype Callback = (node: Text) => boolean;\n\nexport const traverseHtmlTexts = (rootNode: Node, callback: Callback): void => {\n traverseHtmlNode(rootNode, (node) => {\n if (!isHtmlText(node)) {\n return true;\n }\n\n return callback(node);\n });\n};\n","import {\n CARRIAGE_RETURN,\n LINE_FEED,\n NO_BREAK_SPACE,\n SPACE,\n} from '../constants';\nimport { traverseHtmlTexts } from './traverseHtmlTexts';\n\nconst NEWLINE_WHITESPACE_REGEX = /^\\n\\s*$/;\nconst NON_WHITESPACE_REGEX = /\\S/;\nconst LEADING_NEWLINES_REGEX = /^[\\n\\r]+/;\n\nexport const cleanHtmlTextNodes = (rootNode: Node): void => {\n traverseHtmlTexts(rootNode, (textNode) => {\n if (\n NEWLINE_WHITESPACE_REGEX.test(textNode.data) &&\n (textNode.previousElementSibling || textNode.nextElementSibling)\n ) {\n textNode.remove();\n\n return true;\n }\n\n textNode.data = textNode.data.replaceAll(/\\n\\s*/g, '\\n');\n\n if (\n textNode.data.includes(CARRIAGE_RETURN) ||\n textNode.data.includes(LINE_FEED) ||\n textNode.data.includes(NO_BREAK_SPACE)\n ) {\n const hasSpace = textNode.data.includes(SPACE);\n const hasNonWhitespace = NON_WHITESPACE_REGEX.test(textNode.data);\n const hasLineFeed = textNode.data.includes(LINE_FEED);\n\n if (!(hasSpace || hasNonWhitespace) && !hasLineFeed) {\n if (textNode.data === NO_BREAK_SPACE) {\n textNode.data = SPACE;\n\n return true;\n }\n\n textNode.remove();\n\n return true;\n }\n if (\n textNode.previousSibling &&\n textNode.previousSibling.nodeName === 'BR' &&\n textNode.parentElement\n ) {\n textNode.previousSibling.remove();\n\n const matches = LEADING_NEWLINES_REGEX.exec(textNode.data);\n const offset = matches ? matches[0].length : 0;\n\n textNode.data = textNode.data\n .slice(Math.max(0, offset))\n .replaceAll(new RegExp(LINE_FEED, 'g'), SPACE)\n .replaceAll(new RegExp(CARRIAGE_RETURN, 'g'), SPACE);\n textNode.data = `\\n${textNode.data}`;\n } else {\n textNode.data = textNode.data\n .replaceAll(new RegExp(LINE_FEED, 'g'), SPACE)\n .replaceAll(new RegExp(CARRIAGE_RETURN, 'g'), SPACE);\n }\n }\n\n return true;\n });\n};\n","export const isHtmlTable = (element: Element) => element.nodeName === 'TABLE';\n","import { isHtmlBlockElement } from './isHtmlBlockElement';\nimport { isHtmlTable } from './isHtmlTable';\nimport { traverseHtmlElements } from './traverseHtmlElements';\n\n/**\n * Set HTML blocks mark styles to a new child span element if any. This allows\n * Plate to use block marks.\n */\nexport const copyBlockMarksToSpanChild = (rootNode: Node) => {\n traverseHtmlElements(rootNode, (element) => {\n const el = element as HTMLElement;\n\n const styleAttribute = element.getAttribute('style');\n\n if (!styleAttribute) return true;\n if (isHtmlBlockElement(el) && !isHtmlTable(el)) {\n const {\n style: {\n backgroundColor,\n color,\n fontFamily,\n fontSize,\n fontStyle,\n fontWeight,\n textDecoration,\n },\n } = el;\n\n if (\n backgroundColor ||\n color ||\n fontFamily ||\n fontSize ||\n fontStyle ||\n fontWeight ||\n textDecoration\n ) {\n const span = document.createElement('span');\n\n if (!['inherit', 'initial'].includes(color)) {\n span.style.color = color;\n }\n\n span.style.fontFamily = fontFamily;\n span.style.fontSize = fontSize;\n\n if (!['inherit', 'initial', 'normal'].includes(color)) {\n span.style.fontStyle = fontStyle;\n }\n if (![400, 'normal'].includes(fontWeight)) {\n span.style.fontWeight = fontWeight;\n }\n\n span.style.textDecoration = textDecoration;\n\n span.innerHTML = el.innerHTML;\n element.innerHTML = span.outerHTML;\n }\n }\n\n return true;\n });\n};\n","import { traverseHtmlElements } from './traverseHtmlElements';\n\n/**\n * Find the first HTML element that matches the given selector.\n *\n * @param rootNode\n * @param predicate\n */\nexport const findHtmlElement = (\n rootNode: Node,\n predicate: (node: HTMLElement) => boolean\n) => {\n let res: Node | null = null;\n\n traverseHtmlElements(rootNode, (node) => {\n if (predicate(node as HTMLElement)) {\n res = node;\n\n return false;\n }\n\n return true;\n });\n\n return res;\n};\n\nexport const someHtmlElement = (\n rootNode: Node,\n predicate: (node: HTMLElement) => boolean\n) => !!findHtmlElement(rootNode, predicate);\n","const acceptNode = () => NodeFilter.FILTER_ACCEPT;\n\nexport const getHtmlComments = (node: Node): string[] => {\n const comments: string[] = [];\n const iterator = document.createNodeIterator(node, NodeFilter.SHOW_COMMENT, {\n acceptNode,\n });\n let currentNode = iterator.nextNode();\n\n while (currentNode) {\n if (currentNode.nodeValue) {\n comments.push(currentNode.nodeValue);\n }\n\n currentNode = iterator.nextNode();\n }\n\n return comments;\n};\n","export const isHtmlComment = (node: Node): node is Comment =>\n node.nodeType === Node.COMMENT_NODE;\n","const OL_SYMBOL_REGEX = /[\\da-np-z]\\S/;\n\nexport const isOlSymbol = (symbol: string): boolean =>\n OL_SYMBOL_REGEX.test(symbol.toLowerCase());\n","import { parseHtmlDocument } from './parseHtmlDocument';\n\nexport const parseHtmlElement = (html: string) => {\n const { body } = parseHtmlDocument(html);\n\n return body.firstElementChild as HTMLElement;\n};\n","import { ZERO_WIDTH_SPACE } from '../constants';\n\n/** Trim the html and remove zero width spaces, then wrap it with a body element. */\nexport const postCleanHtml = (html: string): string => {\n const cleanHtml = html\n .trim()\n .replaceAll(new RegExp(ZERO_WIDTH_SPACE, 'g'), '');\n\n return `<body>${cleanHtml}</body>`;\n};\n","/** Remove string before <html */\nconst removeBeforeHtml = (html: string): string => {\n const index = html.indexOf('<html');\n\n if (index === -1) {\n return html;\n }\n\n return html.slice(Math.max(0, index));\n};\n\n/** Remove string after </html> */\nconst removeAfterHtml = (html: string): string => {\n const index = html.lastIndexOf('</html>');\n\n if (index === -1) {\n return html;\n }\n\n return html.slice(0, Math.max(0, index + '</html>'.length));\n};\n\n/** Remove string before <html and after </html> */\nexport const removeHtmlSurroundings = (html: string): string =>\n removeBeforeHtml(removeAfterHtml(html));\n","import { cleanHtmlCrLf } from './cleanHtmlCrLf';\nimport { removeHtmlSurroundings } from './removeHtmlSurroundings';\n\nconst cleaners = [removeHtmlSurroundings, cleanHtmlCrLf];\n\n/** Remove HTML surroundings and clean HTML from CR/LF */\nexport const preCleanHtml = (html: string): string =>\n cleaners.reduce((result, clean) => clean(result), html);\n","import { isHtmlComment } from './isHtmlComment';\nimport { traverseHtmlNode } from './traverseHtmlNode';\n\ntype Callback = (node: Comment) => boolean;\n\n/** Traverse HTML comments. */\nexport const traverseHtmlComments = (\n rootNode: Node,\n callback: Callback\n): void => {\n traverseHtmlNode(rootNode, (node) => {\n if (!isHtmlComment(node)) {\n return true;\n }\n\n return callback(node);\n });\n};\n","import { isHtmlComment } from './isHtmlComment';\nimport { traverseHtmlComments } from './traverseHtmlComments';\n\n/** Removes HTML nodes between HTML comments. */\nexport const removeHtmlNodesBetweenComments = (\n rootNode: Node,\n start: string,\n end: string\n): void => {\n const isClosingComment = (node: Node) =>\n isHtmlComment(node) && node.data === end;\n\n traverseHtmlComments(rootNode, (comment) => {\n if (comment.data === start) {\n let node = comment.nextSibling;\n\n comment.remove();\n\n while (node && !isClosingComment(node)) {\n const { nextSibling } = node;\n node.remove();\n node = nextSibling;\n }\n\n if (node && isClosingComment(node)) {\n node.remove();\n }\n }\n\n return true;\n });\n};\n","import type { AnySlatePlugin, SlatePluginContext } from '../plugin';\n\nexport const omitPluginContext = <T extends SlatePluginContext<AnySlatePlugin>>(\n ctx: T\n) => {\n const {\n api,\n editor,\n getOption,\n getOptions,\n plugin,\n setOption,\n setOptions,\n tf,\n type,\n ...rest\n } = ctx;\n\n return rest;\n};\n","import defaultsDeep from 'lodash/defaultsDeep.js';\n\nimport type { AnySlatePlugin } from '../plugin/SlatePlugin';\n\n/**\n * Recursive deep merge of each plugin from `override.plugins` into plugin with\n * same key (plugin > plugin.plugins).\n */\nexport const overridePluginsByKey = (\n plugin: AnySlatePlugin,\n overrideByKey: Record<string, Partial<AnySlatePlugin>> = {},\n nested = false\n): AnySlatePlugin => {\n if (overrideByKey[plugin.key]) {\n const {\n __extensions: pluginOverridesExtensions,\n plugins: pluginOverridesPlugins,\n ...pluginOverrides\n } = overrideByKey[plugin.key];\n\n // Override plugin\n // biome-ignore lint/style/noParameterAssign: Intentional plugin override pattern\n plugin = defaultsDeep({}, pluginOverrides, plugin);\n\n // Merge __extensions\n if (pluginOverridesExtensions) {\n plugin.__extensions = [\n ...(plugin.__extensions || []),\n ...pluginOverridesExtensions,\n ];\n }\n if (!nested) {\n // Concat new pluginOverrides.plugins to plugin.plugins\n pluginOverridesPlugins?.forEach((pOverrides) => {\n if (!plugin.plugins) plugin.plugins = [];\n\n const found = plugin.plugins.find((p) => p.key === pOverrides.key);\n\n if (!found) plugin.plugins.push(pOverrides);\n });\n }\n }\n if (plugin.plugins) {\n // Override plugin.plugins\n plugin.plugins = plugin.plugins.map((p) =>\n overridePluginsByKey(p, overrideByKey, true)\n );\n }\n\n return plugin;\n};\n"],"mappings":"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"}