UNPKG

@premieroctet/next-admin

Version:

Next-Admin provides a customizable and turnkey admin dashboard for applications built with Next.js and powered by the Prisma ORM. It aims to simplify the development process by providing a turnkey admin system that can be easily integrated into your proje

368 lines (367 loc) 11.5 kB
import { Fragment, jsx } from "react/jsx-runtime"; import { Editor, Element, Text, Transforms } from "slate"; const LIST_TYPES = [ "numbered-list", "bulleted-list" ]; const TEXT_ALIGN_TYPES = [ "left", "center", "right", "justify" ]; const isMark = (format)=>[ "bold", "italic", "underline", "code", "strikethrough" ].includes(format); const toggleMark = (editor, format)=>{ const isActive = isMarkActive(editor, format); if (isActive) Editor.removeMark(editor, format); else Editor.addMark(editor, format, true); }; const toggleBlock = (editor, format)=>{ const isActive = isBlockActive(editor, format); const isList = LIST_TYPES.includes(format); Transforms.unwrapNodes(editor, { match: (n)=>!Editor.isEditor(n) && Element.isElement(n) && LIST_TYPES.includes(n.type) && !TEXT_ALIGN_TYPES.includes(format), split: true }); let newProperties; newProperties = TEXT_ALIGN_TYPES.includes(format) ? { textAlign: isActive ? void 0 : format } : { type: isActive ? "paragraph" : isList ? "list-item" : format }; Transforms.setNodes(editor, newProperties); if (!isActive && isList) { const block = { type: format, children: [] }; Transforms.wrapNodes(editor, block); } }; const isMarkActive = (editor, format)=>{ const marks = Editor.marks(editor); return marks ? true === marks[format] : false; }; const isBlockActive = (editor, format)=>{ const { selection } = editor; if (!selection) return false; const blockType = TEXT_ALIGN_TYPES.includes(String(format)) ? "textAlign" : "type"; const [match] = Editor.nodes(editor, { at: Editor.unhangRange(editor, selection), match: (n)=>!Editor.isEditor(n) && Element.isElement(n) && n[blockType] === format }); return !!match; }; const renderLeaf = ({ children, leaf, attributes })=>{ if (leaf.bold) children = /*#__PURE__*/ jsx("strong", { children: children }); if (leaf.code) children = /*#__PURE__*/ jsx("code", { style: { backgroundColor: "#eee", padding: "3px", borderRadius: "3px" }, children: children }); if (leaf.italic) children = /*#__PURE__*/ jsx("em", { children: children }); if (leaf.underline) children = /*#__PURE__*/ jsx("u", { children: children }); if (leaf.strikethrough) children = /*#__PURE__*/ jsx("s", { children: children }); return /*#__PURE__*/ jsx("span", { ...attributes, children: children }); }; const renderElement = ({ attributes, children, element })=>{ const style = { textAlign: element.textAlign }; switch(element.type){ case "bulleted-list": return /*#__PURE__*/ jsx("ul", { style: { listStyleType: "disc", marginLeft: "1rem", ...style }, ...attributes, children: children }); case "numbered-list": return /*#__PURE__*/ jsx("ol", { style: { listStyleType: "decimal", marginLeft: "1rem", ...style }, ...attributes, children: children }); case "list-item": return /*#__PURE__*/ jsx("li", { style: style, ...attributes, children: children }); case "heading-one": return /*#__PURE__*/ jsx("h1", { style: { fontSize: "2rem", fontWeight: 600, ...style }, ...attributes, children: children }); case "heading-two": return /*#__PURE__*/ jsx("h2", { style: { fontSize: "1.5rem", fontWeight: 600, ...style }, ...attributes, children: children }); case "heading-three": return /*#__PURE__*/ jsx("h3", { style: { fontSize: "1.25rem", fontWeight: 600, ...style }, ...attributes, children: children }); case "blockquote": return /*#__PURE__*/ jsx("blockquote", { style: { borderLeft: "2px solid #ddd", paddingLeft: "1rem", marginLeft: "1rem", ...style }, children: children }); case "br": return /*#__PURE__*/ jsx(Fragment, { children: children }); case "paragraph": return /*#__PURE__*/ jsx("p", { style: style, ...attributes, children: children }); case "div": return /*#__PURE__*/ jsx("div", { style: style, ...attributes, children: children }); default: return /*#__PURE__*/ jsx(Fragment, { children: children }); } }; const serialize = (nodes, format)=>{ if ("html" === format) return nodes.map((n)=>serializeHtml(n)).join(""); return JSON.stringify(nodes); }; const serializeHtml = (node)=>{ const textAlign = node.textAlign; const style = textAlign ? ` style="text-align: ${textAlign};"` : ""; if (Text.isText(node)) { let string = node.text; if (!string) return "<br />"; if (node.bold) string = `<strong${style}>${string}</strong>`; if (node.code) string = `<code${style}>${string}</code>`; if (node.italic) string = `<em${style}>${string}</em>`; if (node.underline) string = `<u${style}>${string}</u>`; if (node.strikethrough) string = `<s${style}>${string}</s>`; return string; } const children = node.children.map((n)=>serializeHtml(n)).join(""); if ("<br />" === children) return children; switch(node.type){ case "bulleted-list": return `<ul${style}>${children}</ul>`; case "numbered-list": return `<ol${style}>${children}</ol>`; case "list-item": return `<li${style}>${children}</li>`; case "heading-one": return `<h1${style}>${children}</h1>`; case "heading-two": return `<h2${style}>${children}</h2>`; case "heading-three": return `<h3${style}>${children}</h3>`; case "blockquote": return `<blockquote${style}>${children}</blockquote>`; case "paragraph": return `<p${style}>${children}</p>`; default: return `<div${style}>${children}</div>`; } }; const ensureRootNodeIsNotTextContent = (el)=>{ const firstRootElement = el.firstChild; if (firstRootElement?.nodeType === 3) { const content = firstRootElement.textContent; const lineReturnRegex = new RegExp("\\n", "gi"); const lineReturnCount = content?.match(lineReturnRegex)?.length ?? 0; const newRootNode = document.createElement("p"); newRootNode.textContent = content?.replace(/\\n/gi, "") ?? ""; el.firstChild?.remove(); for(let i = 0; i < lineReturnCount; i++){ const lineBreakNode = document.createElement("br"); el.prepend(lineBreakNode); } el.prepend(newRootNode); } return el; }; const DEFAULT_HTML_VALUE = "<br />"; const DEFAULT_JSON_VALUE = [ { type: "paragraph", children: [ { text: "" } ] } ]; const setDefaultValue = (s)=>[ { type: "paragraph", children: [ { text: s } ] } ]; const deserialize = (string, format)=>{ if (!string) return DEFAULT_JSON_VALUE; if ("html" === format) { if ("undefined" == typeof window) return DEFAULT_HTML_VALUE; const html = string.replace(/>\s+</g, "><"); const dom = new DOMParser().parseFromString(html, "text/html"); return deserializeHtml(ensureRootNodeIsNotTextContent(dom.body)); } try { return JSON.parse(string); } catch { return setDefaultValue(string); } }; const deserializeHtml = (el, markAttributes = {})=>{ if (el.nodeType === el.TEXT_NODE) return { text: el.textContent ?? "", ...markAttributes }; const nodeAttributes = { ...markAttributes }; switch(el.nodeName){ case "STRONG": nodeAttributes["bold"] = true; break; case "EM": nodeAttributes["italic"] = true; break; case "U": nodeAttributes["underline"] = true; break; case "S": nodeAttributes["strikethrough"] = true; break; case "CODE": nodeAttributes["code"] = true; break; } let children = Array.from(el.childNodes).map((node)=>deserializeHtml(node, nodeAttributes)).flat(); if (0 === children.length) children = [ { text: "" } ]; switch(el.nodeName){ case "P": return { type: "paragraph", textAlign: el.style.textAlign, children }; case "BR": return { type: "br", children }; case "H1": return { type: "heading-one", textAlign: el.style.textAlign, children }; case "H2": return { type: "heading-two", textAlign: el.style.textAlign, children }; case "H3": return { type: "heading-three", textAlign: el.style.textAlign, children }; case "BLOCKQUOTE": return { type: "blockquote", textAlign: el.style.textAlign, children }; case "UL": return { type: "bulleted-list", textAlign: el.style.textAlign, children }; case "OL": return { type: "numbered-list", textAlign: el.style.textAlign, children }; case "LI": return { type: "list-item", textAlign: el.style.textAlign, children }; case "DIV": return { type: "div", textAlign: el.style.textAlign, children }; default: return children; } }; export { DEFAULT_HTML_VALUE, DEFAULT_JSON_VALUE, deserialize, deserializeHtml, isBlockActive, isMark, isMarkActive, renderElement, renderLeaf, serialize, serializeHtml, setDefaultValue, toggleBlock, toggleMark };