UNPKG

react-basic-contenteditable

Version:
216 lines (215 loc) 7.3 kB
import { jsxs as Q, jsx as k } from "react/jsx-runtime"; import { useState as X, useRef as E, useEffect as p, useCallback as A } from "react"; const I = (w, T) => T ? w.length <= T : !0, F = ({ containerClassName: w, contentEditableClassName: T, placeholderClassName: V, charsCounterClassName: z, placeholder: N, disabled: m, updatedContent: d, maxLength: u, autoFocus: b, onChange: C, onKeyUp: D, onKeyDown: B, onFocus: P, onBlur: K, onContentExternalUpdate: x }) => { const [s, f] = X(""), n = E(null), g = E([]), R = E([]); p(() => { d != null && (f(d), n.current && (n.current.innerText = d), x && x(d)); }, [d, x]), p(() => { n.current && (n.current.style.height = "auto", C && I(s, u) && C(s)); }, [s, C, u]), p(() => { n.current && b && n.current.focus(); }, [b]), p(() => { g.current.push(s); }, [s]); const S = A( (e) => { if (e.ctrlKey && e.key === "z") { if (e.preventDefault(), g.current.length > 1) { R.current.push(g.current.pop()); const t = g.current[g.current.length - 1]; f(t), n.current && (n.current.innerText = t, v(n.current)); } } else if ((e.ctrlKey && e.key === "y" || e.ctrlKey && e.shiftKey && e.key === "Z") && (e.preventDefault(), R.current.length > 0)) { const t = R.current.pop(); g.current.push(t), f(t), n.current && (n.current.innerText = t, v(n.current)); } }, [f] ); p(() => (document.addEventListener("keydown", S), () => document.removeEventListener("keydown", S)), [S]); const O = A((e) => { if (e.ownerDocument.activeElement !== e) return !1; const t = e.ownerDocument.defaultView; if (!t) return !1; const r = t.getSelection(); if (!r || r.rangeCount === 0) return !1; const c = r.getRangeAt(0); if (c.toString().length > 0) return !1; const l = c.getBoundingClientRect(), i = document.createRange(); i.selectNodeContents(e); let o = i.endContainer, a = 0; for (; o.hasChildNodes() && !(o instanceof Text); ) o.lastChild && (o = o.lastChild, a = o instanceof Text ? o.length : 0); i.setEnd(o, a), i.setStart(o, a); const h = i.getBoundingClientRect(); return l.bottom === h.bottom; }, []), y = A( (e) => { if (!n.current) return; const t = n.current; switch (e.keyCode) { case 38: t.selectionStart === 0 && (t.scrollTop = 0); break; case 13: case 40: O(t) && (t.scrollTop = t.scrollHeight); break; } }, [O] ); function M(e) { var i, o; e.preventDefault(); const r = (e.clipboardData || window.clipboardData).getData("text/plain"), c = window.getSelection(), l = ((i = n.current) == null ? void 0 : i.innerText) || ""; if (c && c.rangeCount) { const a = c.getRangeAt(0), h = a.toString(), J = u ? u - (l.length - h.length) : r.length, j = r.slice(0, J); if (j.length > 0) { a.deleteContents(); const H = document.createTextNode(j); a.insertNode(H), a.setStartAfter(H), c.removeAllRanges(), c.addRange(a), f(((o = n.current) == null ? void 0 : o.innerText) ?? ""); } } else { const a = u ? u - l.length : r.length, h = r.slice(0, a); h.length > 0 && W(h); } } function W(e) { if (!n.current) return; const t = $(n.current); n.current.innerText = n.current.innerText.slice(0, t) + e + n.current.innerText.slice(t), f(n.current.innerText), n.current.scrollTop = n.current.scrollHeight, Z(n.current, t + e.length); } function Z(e, t) { const r = document.createRange(), c = e.childNodes[0]; if (c != null) { r.setStart(c, t), r.setEnd(c, t); const l = window.getSelection(); if (!l) return; l.removeAllRanges(), l.addRange(r); } else e.focus(); } function v(e) { const t = document.createRange(), r = window.getSelection(); e.lastChild && r && (t.setStartAfter(e.lastChild), t.collapse(!0), r.removeAllRanges(), r.addRange(t)); } function $(e) { var c, l; let t = 0, r; if (window.getSelection) { const i = window.getSelection(); i && i.rangeCount && (r = i.getRangeAt(0), r.commonAncestorContainer.parentNode === e && (t = r.endOffset)); } else if (document.getSelection() && ((c = document.getSelection()) != null && c.getRangeAt) && (r = (l = document.getSelection()) == null ? void 0 : l.getRangeAt(0), r && r.commonAncestorContainer.parentNode === e)) { const i = document.createElement("span"); e.insertBefore(i, e.firstChild); const o = r.cloneRange(); o.moveToElementText(i), o.setEndPoint("EndToEnd", r), t = o.text.length; } return t; } function q(e) { B && B(e), n.current && (["Delete", "Backspace"].includes(e.key) && G() || e.key === "Backspace" && s.length === 1 || e.key === "Delete" && $(n.current) === 0 && s.length === 1) && (e.preventDefault(), n.current.innerText = "", f("")); } const G = () => { var r, c; const e = window.getSelection(), t = (((r = n.current) == null ? void 0 : r.innerText.match(/\n(\n|$)/g)) || []).length; return e ? e.toString().length + t === ((c = n.current) == null ? void 0 : c.innerText.length) : !1; }; return p(() => (document.addEventListener("keyup", y), () => document.removeEventListener("keyup", y)), [y]), /* @__PURE__ */ Q( "div", { className: w, style: { display: "flex", alignItems: "center", position: "relative" }, children: [ /* @__PURE__ */ k( "div", { ref: n, contentEditable: !0, defaultValue: s, "aria-disabled": m, dir: "auto", role: "textbox", "aria-label": N ?? "", className: T, style: { padding: "0.85rem", overflow: "auto", height: "auto", textAlign: "initial", wordBreak: "break-word", unicodeBidi: "plaintext" }, onInput: (e) => { const t = e.currentTarget.innerText; if (m || !I(t, u)) { n.current && (n.current.innerText = s, v(n.current)); return; } f(t); }, onPaste: (e) => { m || M(e); }, onFocus: (e) => { P && P(e); }, onBlur: (e) => { K && K(e); }, onKeyUp: (e) => { m || D && D(e); }, onKeyDown: (e) => { m || q(e); } } ), !s && /* @__PURE__ */ k( "span", { dir: "auto", className: V, style: { position: "absolute", pointerEvents: "none", textAlign: "initial" }, children: N ?? "" } ), !!u && /* @__PURE__ */ k( "span", { dir: "auto", className: z, style: { marginLeft: "1rem" }, children: `${s.length ?? 0}/${u}` } ) ] } ); }; export { F as default };