@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
JavaScript
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 };