UNPKG

splitpanes-ts

Version:

TypeScript version of A Vue.js reliable, simple and touch-ready panes splitter / resizer

258 lines (257 loc) 13.6 kB
import { defineComponent as G, ref as w, computed as h, watch as B, onMounted as X, onBeforeUnmount as Y, provide as g, createElementBlock as I, openBlock as V, normalizeClass as de, renderSlot as W, nextTick as T, inject as M, getCurrentInstance as me, normalizeStyle as fe, unref as H } from "vue"; const ze = /* @__PURE__ */ G({ __name: "splitpanes", props: { horizontal: { type: Boolean, default: !1 }, pushOtherPanes: { type: Boolean, default: !0 }, maximizePanes: { type: Boolean, default: !0 }, rtl: { type: Boolean, default: !1 }, firstSplitter: { type: Boolean, default: !1 } }, emits: ["ready", "resize", "resized", "pane-click", "pane-maximize", "pane-add", "pane-remove", "splitter-click", "splitter-dblclick"], setup(A, { emit: x }) { const E = x, u = A, l = w([]), k = h( () => l.value.reduce((e, n) => (e[n.id] = n, e), {}) ), z = h(() => l.value.length), v = w(null), S = w(!1), c = w({ mouseDown: !1, dragging: !1, activeSplitter: null, cursorOffset: 0 }), p = w({ splitter: null, timeoutId: null }), _ = h(() => ({ [`splitpanes splitpanes--${u.horizontal ? "horizontal" : "vertical"}`]: !0, "splitpanes--dragging": c.value.dragging })), R = () => { document.addEventListener("mousemove", P, { passive: !1 }), document.addEventListener("mouseup", o), "ontouchstart" in window && (document.addEventListener("touchmove", P, { passive: !1 }), document.addEventListener("touchend", o)); }, y = () => { document.removeEventListener("mousemove", P), document.removeEventListener("mouseup", o), "ontouchstart" in window && (document.removeEventListener("touchmove", P), document.removeEventListener("touchend", o)); }, C = (e, n) => { var i; const t = (i = e.target) == null ? void 0 : i.closest(".splitpanes__splitter"); if (t) { const { left: a, top: s } = t.getBoundingClientRect(), { clientX: r, clientY: d } = "ontouchstart" in window && "touches" in e ? e.touches[0] : e; c.value.cursorOffset = u.horizontal ? d - s : r - a; } R(), c.value.mouseDown = !0, c.value.activeSplitter = n; }, P = (e) => { c.value.mouseDown && (e.preventDefault(), c.value.dragging = !0, requestAnimationFrame(() => { Z(K(e)), m("resize", { event: e }, !0); })); }, o = (e) => { var n; c.value.dragging && ((n = window.getSelection()) == null || n.removeAllRanges(), m("resized", { event: e }, !0)), c.value.mouseDown = !1, c.value.activeSplitter = null, setTimeout(() => { c.value.dragging = !1, y(); }, 100); }, N = (e, n) => { "ontouchstart" in window && (e.preventDefault(), p.value.splitter === n ? (clearTimeout(p.value.timeoutId), p.value.timeoutId = null, D(e, n), p.value.splitter = null) : (p.value.splitter = n, p.value.timeoutId = setTimeout(() => p.value.splitter = null, 500))), c.value.dragging || m("splitter-click", { event: e, index: n }, !0); }, D = (e, n) => { if (m("splitter-dblclick", { event: e, index: n }, !0), u.maximizePanes) { let t = 0; l.value = l.value.map((i, a) => (i.size = a === n ? i.max : i.min, a !== n && (t += i.min), i)), l.value[n].size -= t, m("pane-maximize", { event: e, index: n, pane: l.value[n] }), m("resized", { event: e, index: n }, !0); } }, J = (e, n) => { const t = k.value[n]; t && m("pane-click", { event: e, index: t.index, pane: t }); }, K = (e) => { const n = v.value.getBoundingClientRect(), { clientX: t, clientY: i } = "ontouchstart" in window && "touches" in e ? e.touches[0] : e; return { x: t - (u.horizontal ? 0 : c.value.cursorOffset) - n.left, y: i - (u.horizontal ? c.value.cursorOffset : 0) - n.top }; }, Q = (e) => { const n = e[u.horizontal ? "y" : "x"], t = v.value[u.horizontal ? "clientHeight" : "clientWidth"]; return (u.rtl && !u.horizontal ? t - n : n) * 100 / t; }, Z = (e) => { const n = c.value.activeSplitter; if (n === null) return; let t = { prevPanesSize: U(n), nextPanesSize: b(n), prevReachedMinPanes: 0, nextReachedMinPanes: 0 }; const i = 0 + (u.pushOtherPanes ? 0 : t.prevPanesSize), a = 100 - (u.pushOtherPanes ? 0 : t.nextPanesSize), s = Math.max(Math.min(Q(e), a), i); let r = [n, n + 1], d = l.value[r[0]] || null, f = l.value[r[1]] || null; const j = d.max < 100 && s >= d.max + t.prevPanesSize, ve = f.max < 100 && s <= 100 - (f.max + b(n + 1)); if (j || ve) { j ? (d.size = d.max, f.size = Math.max(100 - d.max - t.prevPanesSize - t.nextPanesSize, 0)) : (d.size = Math.max(100 - f.max - t.prevPanesSize - b(n + 1), 0), f.size = f.max); return; } if (u.pushOtherPanes) { const F = ee(t, s); if (!F) return; ({ sums: t, panesToResize: r } = F), d = l.value[r[0]] || null, f = l.value[r[1]] || null; } d !== null && (d.size = Math.min(Math.max(s - t.prevPanesSize - t.prevReachedMinPanes, d.min), d.max)), f !== null && (f.size = Math.min(Math.max(100 - s - t.nextPanesSize - t.nextReachedMinPanes, f.min), f.max)); }, ee = (e, n) => { const t = c.value.activeSplitter; if (t === null) return null; const i = [t, t + 1]; return n < e.prevPanesSize + l.value[i[0]].min && (i[0] = ne(t).index || 0, e.prevReachedMinPanes = 0, i[0] < t && l.value.forEach((a, s) => { s > i[0] && s <= t && (a.size = a.min, e.prevReachedMinPanes += a.min); }), e.prevPanesSize = U(i[0]), i[0] === void 0) ? (e.prevReachedMinPanes = 0, l.value[0].size = l.value[0].min, l.value.forEach((a, s) => { s > 0 && s <= t && (a.size = a.min, e.prevReachedMinPanes += a.min); }), l.value[i[1]].size = 100 - e.prevReachedMinPanes - l.value[0].min - e.prevPanesSize - e.nextPanesSize, null) : n > 100 - e.nextPanesSize - l.value[i[1]].min && (i[1] = te(t).index || l.value.length - 1, e.nextReachedMinPanes = 0, i[1] > t + 1 && l.value.forEach((a, s) => { s > t && s < i[1] && (a.size = a.min, e.nextReachedMinPanes += a.min); }), e.nextPanesSize = b(i[1] - 1), i[1] === void 0) ? (e.nextReachedMinPanes = 0, l.value.forEach((a, s) => { s < z.value - 1 && s >= t + 1 && (a.size = a.min, e.nextReachedMinPanes += a.min); }), l.value[i[0]].size = 100 - e.prevPanesSize - b(i[0] - 1), null) : { sums: e, panesToResize: i }; }, U = (e) => l.value.reduce((n, t, i) => n + (i < e ? t.size : 0), 0), b = (e) => l.value.reduce((n, t, i) => n + (i > e + 1 ? t.size : 0), 0), ne = (e) => [...l.value].reverse().find((t) => t.index < e && t.size > t.min) || {}, te = (e) => l.value.find((t) => t.index > e + 1 && t.size > t.min) || {}, ie = () => { var n; const e = Array.from(((n = v.value) == null ? void 0 : n.children) || []); for (const t of e) { const i = t.classList.contains("splitpanes__pane"), a = t.classList.contains("splitpanes__splitter"); !i && !a && (t.remove(), console.warn("Splitpanes: Only <pane> elements are allowed at the root of <splitpanes>. One of your DOM nodes was removed.")); } }, $ = (e, n, t = !1) => { var s; const i = e - 1, a = document.createElement("div"); a.classList.add("splitpanes__splitter"), t || (a.onmousedown = (r) => C(r, i), typeof window < "u" && "ontouchstart" in window && (a.ontouchstart = (r) => C(r, i)), a.onclick = (r) => N(r, i + 1)), a.ondblclick = (r) => D(r, i + 1), (s = n.parentNode) == null || s.insertBefore(a, n); }, ae = (e) => { e.onmousedown = null, e.onclick = null, e.ondblclick = null, e.remove(); }, O = () => { var t; const e = Array.from(((t = v.value) == null ? void 0 : t.children) || []); for (const i of e) i.className.includes("splitpanes__splitter") && ae(i); let n = 0; for (const i of e) i.className.includes("splitpanes__pane") && (!n && u.firstSplitter ? $(n, i, !0) : n && $(n, i), n++); }, se = ({ uid: e, ...n }) => { const t = k.value[e]; for (const [i, a] of Object.entries(n)) t[i] = a; }, le = (e) => { var t; let n = -1; Array.from(((t = v.value) == null ? void 0 : t.children) || []).some((i) => (i.className.includes("splitpanes__pane") && n++, i.isSameNode(e.el))), l.value.splice(n, 0, { ...e, index: n }), l.value.forEach((i, a) => i.index = a), S.value && T(() => { O(), L({ addedPane: l.value[n] }), m("pane-add", { pane: l.value[n] }); }); }, oe = (e) => { const n = l.value.findIndex((i) => i.id === e); l.value[n].el = null; const t = l.value.splice(n, 1)[0]; l.value.forEach((i, a) => i.index = a), T(() => { O(), m("pane-remove", { pane: t }), L({ removedPane: { ...t } }); }); }, L = (e = {}) => { !e.addedPane && !e.removedPane ? ue() : l.value.some((n) => n.givenSize !== null || n.min || n.max < 100) ? ce(e) : re(), S.value && m("resized"); }, re = () => { const e = 100 / z.value; let n = 0; const t = [], i = []; for (const a of l.value) a.size = Math.max(Math.min(e, a.max), a.min), n -= a.size, a.size >= a.max && t.push(a.id), a.size <= a.min && i.push(a.id); n > 0.1 && q(n, t, i); }, ue = () => { let e = 100; const n = [], t = []; let i = 0; for (const s of l.value) e -= s.size, s.givenSize !== null && i++, s.size >= s.max && n.push(s.id), s.size <= s.min && t.push(s.id); let a = 100; if (e > 0.1) { for (const s of l.value) s.givenSize === null && (s.size = Math.max(Math.min(e / (z.value - i), s.max), s.min)), a -= s.size; a > 0.1 && q(a, n, t); } }, ce = ({ addedPane: e } = {}) => { let n = 100 / z.value, t = 0; const i = [], a = []; e && e.givenSize !== null && (n = (100 - e.givenSize) / (z.value - 1)); for (const s of l.value) t -= s.size, s.size >= s.max && i.push(s.id), s.size <= s.min && a.push(s.id); if (!(Math.abs(t) < 0.1)) { for (const s of l.value) (e == null ? void 0 : e.givenSize) !== null && (e == null ? void 0 : e.id) === s.id || (s.size = Math.max(Math.min(n, s.max), s.min)), t -= s.size, s.size >= s.max && i.push(s.id), s.size <= s.min && a.push(s.id); t > 0.1 && q(t, i, a); } }, q = (e, n, t) => { let i; e > 0 ? i = e / (z.value - n.length) : i = e / (z.value - t.length), l.value.forEach((a) => { if (e > 0 && !n.includes(a.id)) { const s = Math.max(Math.min(a.size + i, a.max), a.min), r = s - a.size; e -= r, a.size = s; } else if (!t.includes(a.id)) { const s = Math.max(Math.min(a.size + i, a.max), a.min), r = s - a.size; e -= r, a.size = s; } }), Math.abs(e) > 0.1 && T(() => { S.value && console.warn("Splitpanes: Could not resize panes correctly due to their constraints."); }); }, m = (e, n = void 0, t = !1) => { const i = (n == null ? void 0 : n.index) ?? c.value.activeSplitter ?? null; E(e, { ...n, ...i !== null && { index: i }, ...t && i !== null && { prevPane: l.value[i - (u.firstSplitter ? 1 : 0)], nextPane: l.value[i + (u.firstSplitter ? 0 : 1)] }, panes: l.value.map((a) => ({ min: a.min, max: a.max, size: a.size })) }); }; return B(() => u.firstSplitter, () => O()), X(() => { ie(), O(), L(), m("ready"), S.value = !0; }), Y(() => S.value = !1), g("panes", l), g("indexedPanes", k), g("horizontal", h(() => u.horizontal)), g("requestUpdate", se), g("onPaneAdd", le), g("onPaneRemove", oe), g("onPaneClick", J), (e, n) => (V(), I("div", { ref_key: "containerEl", ref: v, class: de(_.value) }, [ W(e.$slots, "default") ], 2)); } }), he = /* @__PURE__ */ G({ __name: "pane", props: { size: {}, minSize: { default: 0 }, maxSize: { default: 100 } }, setup(A) { var P; const x = A, E = M("requestUpdate"), u = M("onPaneAdd"), l = M("horizontal"), k = M("onPaneRemove"), z = M("onPaneClick"), v = (P = me()) == null ? void 0 : P.uid, S = M("indexedPanes"), c = h(() => S.value[v]), p = w(null), _ = h(() => { const o = isNaN(Number(x.size)) || x.size === void 0 ? 0 : parseFloat(String(x.size)); return Math.max(Math.min(o, y.value), R.value); }), R = h(() => { const o = parseFloat(String(x.minSize)); return isNaN(o) ? 0 : o; }), y = h(() => { const o = parseFloat(String(x.maxSize)); return isNaN(o) ? 100 : o; }), C = h(() => { var o; return `${l.value ? "height" : "width"}: ${(o = c.value) == null ? void 0 : o.size}%`; }); return B(() => _.value, (o) => E({ uid: v, size: o })), B(() => R.value, (o) => E({ uid: v, min: o })), B(() => y.value, (o) => E({ uid: v, max: o })), X(() => { u({ id: v, el: p.value, min: R.value, max: y.value, // The given size (useful to know the user intention). givenSize: x.size === void 0 ? null : _.value, size: _.value // The computed current size at any time. }); }), Y(() => k(v)), (o, N) => (V(), I("div", { ref_key: "paneEl", ref: p, class: "splitpanes__pane", onClick: N[0] || (N[0] = (D) => H(z)(D, H(v))), style: fe(C.value) }, [ W(o.$slots, "default") ], 4)); } }); export { he as Pane, ze as Splitpanes };