@liveblocks/react-ui
Version: 
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.
167 lines (163 loc) • 5.06 kB
JavaScript
;
var slate = require('slate');
var slateHyperscript = require('slate-hyperscript');
var dataTransfer = require('../../utils/data-transfer.cjs');
const NEWLINE_REGEX = /[\r\n]/g;
const WHITESPACE_REGEX = /\s+/g;
function areUrlsEqual(a, b) {
  try {
    const urlA = new URL(a);
    const urlB = new URL(b);
    return urlA.origin === urlB.origin && urlA.pathname === urlB.pathname;
  } catch {
    return false;
  }
}
const createParagraphElement = () => ({
  type: "paragraph"
});
const ELEMENT_TAGS = {
  A: (element) => {
    const href = element.getAttribute("href");
    const innerText = element.innerText;
    return {
      type: href && areUrlsEqual(href, innerText) ? "auto-link" : "custom-link",
      url: href ?? ""
    };
  },
  P: createParagraphElement,
  BLOCKQUOTE: createParagraphElement,
  H1: createParagraphElement,
  H2: createParagraphElement,
  H3: createParagraphElement,
  H4: createParagraphElement,
  H5: createParagraphElement,
  H6: createParagraphElement,
  LI: createParagraphElement
};
const TEXT_TAGS = {
  CODE: () => ({ code: true }),
  DEL: () => ({ strikethrough: true }),
  EM: () => ({ italic: true }),
  I: () => ({ italic: true }),
  S: () => ({ strikethrough: true }),
  STRONG: () => ({ bold: true }),
  B: () => ({ bold: true })
};
function flattenListItems(node) {
  const listItems = [];
  if (node.nodeName === "LI") {
    listItems.push(node);
  }
  node.childNodes.forEach((child) => {
    if (child.nodeType === 1) {
      listItems.push(...flattenListItems(child));
    }
  });
  return listItems;
}
function jsxTextChildren(children, attrs) {
  return children.map((child) => slateHyperscript.jsx("text", attrs, child));
}
function deserialize(node) {
  if (node.nodeType === 3) {
    let text = node.textContent;
    const isMultiLine = text && NEWLINE_REGEX.test(text);
    if (text && isMultiLine) {
      text = text.replace(WHITESPACE_REGEX, " ").trim();
    }
    return text ? { text } : null;
  } else if (node.nodeType !== 1) {
    return null;
  } else if (node.nodeName === "BR") {
    return slateHyperscript.jsx("element", createParagraphElement(), []);
  }
  const childNodes = Array.from(node.childNodes);
  let children = childNodes.map(deserialize).flat();
  if (node.nodeName === "UL" || node.nodeName === "OL") {
    const listItems = flattenListItems(node);
    children = listItems.map((li) => deserialize(li)).flat();
  }
  if (children.length === 0) {
    children = [{ text: "" }];
  }
  if (node.nodeName === "BODY") {
    if (children.length > 0 && children.every((child) => typeof child === "string")) {
      children = [
        { type: "paragraph", children: [{ text: children.join("") }] }
      ];
    }
    return slateHyperscript.jsx(
      "fragment",
      {},
      children.filter((child) => typeof child !== "string")
    );
  }
  if (ELEMENT_TAGS[node.nodeName]) {
    const attrs = ELEMENT_TAGS[node.nodeName](node);
    return slateHyperscript.jsx("element", attrs, children);
  }
  if (TEXT_TAGS[node.nodeName]) {
    const attrs = TEXT_TAGS[node.nodeName](node);
    if (children.some(
      (child) => child && typeof child !== "string" && "type" in child
    )) {
      return slateHyperscript.jsx("fragment", {}, children);
    }
    return jsxTextChildren(children, attrs);
  }
  if (node.nodeName === "SPAN") {
    const style = node.style;
    const attrs = {};
    if (style.fontWeight === "bold" || style.fontWeight === "700" || style.fontWeight === "800" || style.fontWeight === "900") {
      attrs.bold = true;
    }
    if (style.fontStyle === "italic") {
      attrs.italic = true;
    }
    if (style.textDecoration === "line-through") {
      attrs.strikethrough = true;
    }
    return jsxTextChildren(children, attrs);
  }
  return children;
}
function withPaste(editor, {
  createAttachments,
  pasteFilesAsAttachments
}) {
  const { insertData } = editor;
  editor.insertData = (data) => {
    if (data.types.includes("Files") && pasteFilesAsAttachments) {
      const files = dataTransfer.getFiles(data);
      if (files.length > 0) {
        createAttachments(files);
        return;
      }
    }
    if (data.types.includes("text/html") && !data.types.includes("application/x-slate-fragment")) {
      const html = data.getData("text/html");
      try {
        const { body } = new DOMParser().parseFromString(html, "text/html");
        body.querySelector("br.Apple-interchange-newline")?.remove();
        if (body.children.length === 1 && body.children[0]?.nodeName === "B") {
          const wrapper = body.children[0];
          while (wrapper.firstChild) {
            body.insertBefore(wrapper.firstChild, wrapper);
          }
          body.removeChild(wrapper);
        }
        const fragment = deserialize(body);
        if (fragment !== null && Array.isArray(fragment)) {
          slate.Transforms.insertFragment(editor, fragment);
          return;
        }
      } catch {
      }
    }
    insertData(data);
  };
  return editor;
}
exports.withPaste = withPaste;
//# sourceMappingURL=paste.cjs.map