UNPKG

react-resizable-panels

Version:

<img src="https://react-resizable-panels.vercel.app/og.png" alt="react-resizable-panels logo" width="400" height="210" />

1,972 lines 52.2 kB
"use client"; import { jsx as te } from "react/jsx-runtime"; import { useState as ne, useCallback as Q, useId as rt, useLayoutEffect as Ae, useEffect as ue, useRef as O, createContext as st, useImperativeHandle as Ne, useMemo as _e, useSyncExternalStore as Fe, useContext as at } from "react"; function lt(e, t) { const n = getComputedStyle(e), o = parseFloat(n.fontSize); return t * o; } function ut(e, t) { const n = getComputedStyle(e.ownerDocument.body), o = parseFloat(n.fontSize); return t * o; } function ct(e) { return e / 100 * window.innerHeight; } function ft(e) { return e / 100 * window.innerWidth; } function dt(e) { switch (typeof e) { case "number": return [e, "px"]; case "string": { const t = parseFloat(e); return e.endsWith("%") ? [t, "%"] : e.endsWith("px") ? [t, "px"] : e.endsWith("rem") ? [t, "rem"] : e.endsWith("em") ? [t, "em"] : e.endsWith("vh") ? [t, "vh"] : e.endsWith("vw") ? [t, "vw"] : [t, "%"]; } } } function re({ groupSize: e, panelElement: t, styleProp: n }) { let o; const [i, s] = dt(n); switch (s) { case "%": { o = i / 100 * e; break; } case "px": { o = i; break; } case "rem": { o = ut(t, i); break; } case "em": { o = lt(t, i); break; } case "vh": { o = ct(i); break; } case "vw": { o = ft(i); break; } } return o; } function _(e) { return parseFloat(e.toFixed(3)); } function J({ group: e }) { const { orientation: t, panels: n } = e; return n.reduce((o, i) => (o += t === "horizontal" ? i.element.offsetWidth : i.element.offsetHeight, o), 0); } function pe(e) { const { panels: t } = e, n = J({ group: e }); return n === 0 ? t.map((o) => ({ collapsedSize: 0, collapsible: o.panelConstraints.collapsible === !0, defaultSize: void 0, disabled: o.panelConstraints.disabled, minSize: 0, maxSize: 100, panelId: o.id })) : t.map((o) => { const { element: i, panelConstraints: s } = o; let l = 0; if (s.collapsedSize !== void 0) { const c = re({ groupSize: n, panelElement: i, styleProp: s.collapsedSize }); l = _(c / n * 100); } let r; if (s.defaultSize !== void 0) { const c = re({ groupSize: n, panelElement: i, styleProp: s.defaultSize }); r = _(c / n * 100); } let a = 0; if (s.minSize !== void 0) { const c = re({ groupSize: n, panelElement: i, styleProp: s.minSize }); a = _(c / n * 100); } let u = 100; if (s.maxSize !== void 0) { const c = re({ groupSize: n, panelElement: i, styleProp: s.maxSize }); u = _(c / n * 100); } return { collapsedSize: l, collapsible: s.collapsible === !0, defaultSize: r, disabled: s.disabled, minSize: a, maxSize: u, panelId: o.id }; }); } function P(e, t = "Assertion error") { if (!e) throw Error(t); } function he(e, t) { return Array.from(t).sort( e === "horizontal" ? pt : ht ); } function pt(e, t) { const n = e.element.offsetLeft - t.element.offsetLeft; return n !== 0 ? n : e.element.offsetWidth - t.element.offsetWidth; } function ht(e, t) { const n = e.element.offsetTop - t.element.offsetTop; return n !== 0 ? n : e.element.offsetHeight - t.element.offsetHeight; } function $e(e) { return e !== null && typeof e == "object" && "nodeType" in e && e.nodeType === Node.ELEMENT_NODE; } function He(e, t) { return { x: e.x >= t.left && e.x <= t.right ? 0 : Math.min( Math.abs(e.x - t.left), Math.abs(e.x - t.right) ), y: e.y >= t.top && e.y <= t.bottom ? 0 : Math.min( Math.abs(e.y - t.top), Math.abs(e.y - t.bottom) ) }; } function mt({ orientation: e, rects: t, targetRect: n }) { const o = { x: n.x + n.width / 2, y: n.y + n.height / 2 }; let i, s = Number.MAX_VALUE; for (const l of t) { const { x: r, y: a } = He(o, l), u = e === "horizontal" ? r : a; u < s && (s = u, i = l); } return P(i, "No rect found"), i; } let se; function gt() { return se === void 0 && (typeof matchMedia == "function" ? se = !!matchMedia("(pointer:coarse)").matches : se = !1), se; } function Ve(e) { const { element: t, orientation: n, panels: o, separators: i } = e, s = he( n, Array.from(t.children).filter($e).map((m) => ({ element: m })) ).map(({ element: m }) => m), l = []; let r = !1, a = !1, u = -1, c = -1, g = 0, b, S = []; { let m = -1; for (const d of s) d.hasAttribute("data-panel") && (m++, d.ariaDisabled === null && (g++, u === -1 && (u = m), c = m)); } if (g > 1) { let m = -1; for (const d of s) if (d.hasAttribute("data-panel")) { m++; const f = o.find( (h) => h.element === d ); if (f) { if (b) { const h = b.element.getBoundingClientRect(), v = d.getBoundingClientRect(); let x; if (a) { const y = n === "horizontal" ? new DOMRect( h.right, h.top, 0, h.height ) : new DOMRect( h.left, h.bottom, h.width, 0 ), p = n === "horizontal" ? new DOMRect(v.left, v.top, 0, v.height) : new DOMRect(v.left, v.top, v.width, 0); switch (S.length) { case 0: { x = [ y, p ]; break; } case 1: { const w = S[0], C = mt({ orientation: n, rects: [h, v], targetRect: w.element.getBoundingClientRect() }); x = [ w, C === h ? p : y ]; break; } default: { x = S; break; } } } else S.length ? x = S : x = [ n === "horizontal" ? new DOMRect( h.right, v.top, v.left - h.right, v.height ) : new DOMRect( v.left, h.bottom, v.width, v.top - h.bottom ) ]; for (const y of x) { let p = "width" in y ? y : y.element.getBoundingClientRect(); const w = gt() ? e.resizeTargetMinimumSize.coarse : e.resizeTargetMinimumSize.fine; if (p.width < w) { const R = w - p.width; p = new DOMRect( p.x - R / 2, p.y, p.width + R, p.height ); } if (p.height < w) { const R = w - p.height; p = new DOMRect( p.x, p.y - R / 2, p.width, p.height + R ); } const C = m <= u || m > c; !r && !C && l.push({ group: e, groupSize: J({ group: e }), panels: [b, f], separator: "width" in y ? void 0 : y, rect: p }), r = !1; } } a = !1, b = f, S = []; } } else if (d.hasAttribute("data-separator")) { d.ariaDisabled !== null && (r = !0); const f = i.find( (h) => h.element === d ); f ? S.push(f) : (b = void 0, S = []); } else a = !0; } return l; } class yt { #e = {}; addListener(t, n) { const o = this.#e[t]; return o === void 0 ? this.#e[t] = [n] : o.includes(n) || o.push(n), () => { this.removeListener(t, n); }; } emit(t, n) { const o = this.#e[t]; if (o !== void 0) if (o.length === 1) o[0].call(null, n); else { let i = !1, s = null; const l = Array.from(o); for (let r = 0; r < l.length; r++) { const a = l[r]; try { a.call(null, n); } catch (u) { s === null && (i = !0, s = u); } } if (i) throw s; } } removeAllListeners() { this.#e = {}; } removeListener(t, n) { const o = this.#e[t]; if (o !== void 0) { const i = o.indexOf(n); i >= 0 && o.splice(i, 1); } } } function k(e, t, n = 0) { return Math.abs(_(e) - _(t)) <= n; } let A = { cursorFlags: 0, interactionState: { state: "inactive" }, mountedGroups: /* @__PURE__ */ new Map() }; const $ = new yt(); function G() { return A; } function I(e) { const t = typeof e == "function" ? e(A) : e; if (A === t) return A; const n = A; return A = { ...A, ...t }, t.cursorFlags !== void 0 && $.emit("cursorFlagsChange", A.cursorFlags), t.interactionState !== void 0 && $.emit("interactionStateChange", A.interactionState), t.mountedGroups !== void 0 && (A.mountedGroups.forEach((o, i) => { o.derivedPanelConstraints.forEach((s) => { if (s.collapsible) { const { layout: l } = n.mountedGroups.get(i) ?? {}; if (l) { const r = k( s.collapsedSize, o.layout[s.panelId] ), a = k( s.collapsedSize, l[s.panelId] ); r && !a && (i.inMemoryLastExpandedPanelSizes[s.panelId] = l[s.panelId]); } } }); }), $.emit("mountedGroupsChange", A.mountedGroups)), A; } function St(e, t, n) { let o, i = { x: 1 / 0, y: 1 / 0 }; for (const s of t) { const l = He(n, s.rect); switch (e) { case "horizontal": { l.x <= i.x && (o = s, i = l); break; } case "vertical": { l.y <= i.y && (o = s, i = l); break; } } } return o ? { distance: i, hitRegion: o } : void 0; } function vt(e) { return e !== null && typeof e == "object" && "nodeType" in e && e.nodeType === Node.DOCUMENT_FRAGMENT_NODE; } function xt(e, t) { if (e === t) throw new Error("Cannot compare node with itself"); const n = { a: we(e), b: we(t) }; let o; for (; n.a.at(-1) === n.b.at(-1); ) o = n.a.pop(), n.b.pop(); P( o, "Stacking order can only be calculated for elements with a common ancestor" ); const i = { a: be(ze(n.a)), b: be(ze(n.b)) }; if (i.a === i.b) { const s = o.childNodes, l = { a: n.a.at(-1), b: n.b.at(-1) }; let r = s.length; for (; r--; ) { const a = s[r]; if (a === l.a) return 1; if (a === l.b) return -1; } } return Math.sign(i.a - i.b); } const zt = /\b(?:position|zIndex|opacity|transform|webkitTransform|mixBlendMode|filter|webkitFilter|isolation)\b/; function bt(e) { const t = getComputedStyle(je(e) ?? e).display; return t === "flex" || t === "inline-flex"; } function wt(e) { const t = getComputedStyle(e); return !!(t.position === "fixed" || t.zIndex !== "auto" && (t.position !== "static" || bt(e)) || +t.opacity < 1 || "transform" in t && t.transform !== "none" || "webkitTransform" in t && t.webkitTransform !== "none" || "mixBlendMode" in t && t.mixBlendMode !== "normal" || "filter" in t && t.filter !== "none" || "webkitFilter" in t && t.webkitFilter !== "none" || "isolation" in t && t.isolation === "isolate" || zt.test(t.willChange) || t.webkitOverflowScrolling === "touch"); } function ze(e) { let t = e.length; for (; t--; ) { const n = e[t]; if (P(n, "Missing node"), wt(n)) return n; } return null; } function be(e) { return e && Number(getComputedStyle(e).zIndex) || 0; } function we(e) { const t = []; for (; e; ) t.push(e), e = je(e); return t; } function je(e) { const { parentNode: t } = e; return vt(t) ? t.host : t; } function Lt(e, t) { return e.x < t.x + t.width && e.x + e.width > t.x && e.y < t.y + t.height && e.y + e.height > t.y; } function Pt({ groupElement: e, hitRegion: t, pointerEventTarget: n }) { if (!$e(n) || n.contains(e) || e.contains(n)) return !0; if (xt(n, e) > 0) { let o = n; for (; o; ) { if (o.contains(e)) return !0; if (Lt(o.getBoundingClientRect(), t)) return !1; o = o.parentElement; } } return !0; } function me(e, t) { const n = []; return t.forEach((o, i) => { if (i.disabled) return; const s = Ve(i), l = St(i.orientation, s, { x: e.clientX, y: e.clientY }); l && l.distance.x <= 0 && l.distance.y <= 0 && Pt({ groupElement: i.element, hitRegion: l.hitRegion.rect, pointerEventTarget: e.target }) && n.push(l.hitRegion); }), n; } function Ct(e, t) { if (e.length !== t.length) return !1; for (let n = 0; n < e.length; n++) if (e[n] != t[n]) return !1; return !0; } function F(e, t) { return k(e, t) ? 0 : e > t ? 1 : -1; } function Y({ overrideDisabledPanels: e, panelConstraints: t, prevSize: n, size: o }) { const { collapsedSize: i = 0, collapsible: s, disabled: l, maxSize: r = 100, minSize: a = 0 } = t; if (l && !e) return n; if (F(o, a) < 0) if (s) { const u = (i + a) / 2; F(o, u) < 0 ? o = i : o = a; } else o = a; return o = Math.min(r, o), o = _(o), o; } function oe({ delta: e, initialLayout: t, panelConstraints: n, pivotIndices: o, prevLayout: i, trigger: s }) { if (k(e, 0)) return t; const l = s === "imperative-api", r = Object.values(t), a = Object.values(i), u = [...r], [c, g] = o; P(c != null, "Invalid first pivot index"), P(g != null, "Invalid second pivot index"); let b = 0; switch (s) { case "keyboard": { { const d = e < 0 ? g : c, f = n[d]; P( f, `Panel constraints not found for index ${d}` ); const { collapsedSize: h = 0, collapsible: v, minSize: x = 0 } = f; if (v) { const y = r[d]; if (P( y != null, `Previous layout not found for panel index ${d}` ), k(y, h)) { const p = x - y; F(p, Math.abs(e)) > 0 && (e = e < 0 ? 0 - p : p); } } } { const d = e < 0 ? c : g, f = n[d]; P( f, `No panel constraints found for index ${d}` ); const { collapsedSize: h = 0, collapsible: v, minSize: x = 0 } = f; if (v) { const y = r[d]; if (P( y != null, `Previous layout not found for panel index ${d}` ), k(y, x)) { const p = y - h; F(p, Math.abs(e)) > 0 && (e = e < 0 ? 0 - p : p); } } } break; } default: { const d = e < 0 ? g : c, f = n[d]; P( f, `Panel constraints not found for index ${d}` ); const h = r[d], { collapsible: v, collapsedSize: x, minSize: y } = f; if (v && F(h, y) < 0) if (e > 0) { const p = y - x, w = p / 2, C = h + e; F(C, y) < 0 && (e = F(e, w) <= 0 ? 0 : p); } else { const p = y - x, w = 100 - p / 2, C = h - e; F(C, y) < 0 && (e = F(100 + e, w) > 0 ? 0 : -p); } break; } } { const d = e < 0 ? 1 : -1; let f = e < 0 ? g : c, h = 0; for (; ; ) { const x = r[f]; P( x != null, `Previous layout not found for panel index ${f}` ); const p = Y({ overrideDisabledPanels: l, panelConstraints: n[f], prevSize: x, size: 100 }) - x; if (h += p, f += d, f < 0 || f >= n.length) break; } const v = Math.min(Math.abs(e), Math.abs(h)); e = e < 0 ? 0 - v : v; } { let f = e < 0 ? c : g; for (; f >= 0 && f < n.length; ) { const h = Math.abs(e) - Math.abs(b), v = r[f]; P( v != null, `Previous layout not found for panel index ${f}` ); const x = v - h, y = Y({ overrideDisabledPanels: l, panelConstraints: n[f], prevSize: v, size: x }); if (!k(v, y) && (b += v - y, u[f] = y, b.toFixed(3).localeCompare(Math.abs(e).toFixed(3), void 0, { numeric: !0 }) >= 0)) break; e < 0 ? f-- : f++; } } if (Ct(a, u)) return i; { const d = e < 0 ? g : c, f = r[d]; P( f != null, `Previous layout not found for panel index ${d}` ); const h = f + b, v = Y({ overrideDisabledPanels: l, panelConstraints: n[d], prevSize: f, size: h }); if (u[d] = v, !k(v, h)) { let x = h - v, p = e < 0 ? g : c; for (; p >= 0 && p < n.length; ) { const w = u[p]; P( w != null, `Previous layout not found for panel index ${p}` ); const C = w + x, R = Y({ overrideDisabledPanels: l, panelConstraints: n[p], prevSize: w, size: C }); if (k(w, R) || (x -= R - w, u[p] = R), k(x, 0)) break; e > 0 ? p-- : p++; } } } const S = Object.values(u).reduce( (d, f) => f + d, 0 ); if (!k(S, 100, 0.1)) return i; const m = Object.keys(i); return u.reduce((d, f, h) => (d[m[h]] = f, d), {}); } function U(e, t) { if (Object.keys(e).length !== Object.keys(t).length) return !1; for (const n in e) if (t[n] === void 0 || F(e[n], t[n]) !== 0) return !1; return !0; } function B({ layout: e, panelConstraints: t }) { const n = Object.values(e), o = [...n], i = o.reduce( (r, a) => r + a, 0 ); if (o.length !== t.length) throw Error( `Invalid ${t.length} panel layout: ${o.map((r) => `${r}%`).join(", ")}` ); if (!k(i, 100) && o.length > 0) for (let r = 0; r < t.length; r++) { const a = o[r]; P(a != null, `No layout data found for index ${r}`); const u = 100 / i * a; o[r] = u; } let s = 0; for (let r = 0; r < t.length; r++) { const a = n[r]; P(a != null, `No layout data found for index ${r}`); const u = o[r]; P(u != null, `No layout data found for index ${r}`); const c = Y({ overrideDisabledPanels: !0, panelConstraints: t[r], prevSize: a, size: u }); u != c && (s += u - c, o[r] = c); } if (!k(s, 0)) for (let r = 0; r < t.length; r++) { const a = o[r]; P(a != null, `No layout data found for index ${r}`); const u = a + s, c = Y({ overrideDisabledPanels: !0, panelConstraints: t[r], prevSize: a, size: u }); if (a !== c && (s -= c - a, o[r] = c, k(s, 0))) break; } const l = Object.keys(e); return o.reduce((r, a, u) => (r[l[u]] = a, r), {}); } function We({ groupId: e, panelId: t }) { const n = () => { const { mountedGroups: r } = G(); for (const [ a, { defaultLayoutDeferred: u, derivedPanelConstraints: c, layout: g, separatorToPanels: b } ] of r) if (a.id === e) return { defaultLayoutDeferred: u, derivedPanelConstraints: c, group: a, layout: g, separatorToPanels: b }; throw Error(`Group ${e} not found`); }, o = () => { const r = n().derivedPanelConstraints.find( (a) => a.panelId === t ); if (r !== void 0) return r; throw Error(`Panel constraints not found for Panel ${t}`); }, i = () => { const r = n().group.panels.find((a) => a.id === t); if (r !== void 0) return r; throw Error(`Layout not found for Panel ${t}`); }, s = () => { const r = n().layout[t]; if (r !== void 0) return r; throw Error(`Layout not found for Panel ${t}`); }, l = (r) => { const a = s(); if (r === a) return; const { defaultLayoutDeferred: u, derivedPanelConstraints: c, group: g, layout: b, separatorToPanels: S } = n(), m = g.panels.findIndex((v) => v.id === t), d = m === g.panels.length - 1, f = oe({ delta: d ? a - r : r - a, initialLayout: b, panelConstraints: c, pivotIndices: d ? [m - 1, m] : [m, m + 1], prevLayout: b, trigger: "imperative-api" }), h = B({ layout: f, panelConstraints: c }); U(b, h) || I((v) => ({ mountedGroups: new Map(v.mountedGroups).set(g, { defaultLayoutDeferred: u, derivedPanelConstraints: c, layout: h, separatorToPanels: S }) })); }; return { collapse: () => { const { collapsible: r, collapsedSize: a } = o(), { mutableValues: u } = i(), c = s(); r && c !== a && (u.expandToSize = c, l(a)); }, expand: () => { const { collapsible: r, collapsedSize: a, minSize: u } = o(), { mutableValues: c } = i(), g = s(); if (r && g === a) { let b = c.expandToSize ?? u; b === 0 && (b = 1), l(b); } }, getSize: () => { const { group: r } = n(), a = s(), { element: u } = i(), c = r.orientation === "horizontal" ? u.offsetWidth : u.offsetHeight; return { asPercentage: a, inPixels: c }; }, isCollapsed: () => { const { collapsible: r, collapsedSize: a } = o(), u = s(); return r && k(a, u); }, resize: (r) => { if (s() !== r) { let u; switch (typeof r) { case "number": { const { group: c } = n(), g = J({ group: c }); u = _(r / g * 100); break; } case "string": { u = parseFloat(r); break; } } l(u); } } }; } function Le(e) { if (e.defaultPrevented) return; const { mountedGroups: t } = G(); me(e, t).forEach((o) => { if (o.separator) { const i = o.panels.find( (s) => s.panelConstraints.defaultSize !== void 0 ); if (i) { const s = i.panelConstraints.defaultSize, l = We({ groupId: o.group.id, panelId: i.id }); l && s !== void 0 && (l.resize(s), e.preventDefault()); } } }); } function le(e) { const { mountedGroups: t } = G(); for (const [n] of t) if (n.separators.some( (o) => o.element === e )) return n; throw Error("Could not find parent Group for separator element"); } function Ue({ groupId: e }) { const t = () => { const { mountedGroups: n } = G(); for (const [o, i] of n) if (o.id === e) return { group: o, ...i }; throw Error(`Could not find Group with id "${e}"`); }; return { getLayout() { const { defaultLayoutDeferred: n, layout: o } = t(); return n ? {} : o; }, setLayout(n) { const { defaultLayoutDeferred: o, derivedPanelConstraints: i, group: s, layout: l, separatorToPanels: r } = t(), a = B({ layout: n, panelConstraints: i }); return o ? l : (U(l, a) || I((u) => ({ mountedGroups: new Map(u.mountedGroups).set(s, { defaultLayoutDeferred: o, derivedPanelConstraints: i, layout: a, separatorToPanels: r }) })), a); } }; } function Be(e) { const { mountedGroups: t } = G(), n = t.get(e); return P(n, `Mounted Group ${e.id} not found`), n; } function W(e, t) { const n = le(e), o = Be(n), i = n.separators.find( (g) => g.element === e ); P(i, "Matching separator not found"); const s = o.separatorToPanels.get(i); P(s, "Matching panels not found"); const l = s.map((g) => n.panels.indexOf(g)), a = Ue({ groupId: n.id }).getLayout(), u = oe({ delta: t, initialLayout: a, panelConstraints: o.derivedPanelConstraints, pivotIndices: l, prevLayout: a, trigger: "keyboard" }), c = B({ layout: u, panelConstraints: o.derivedPanelConstraints }); U(a, c) || I((g) => ({ mountedGroups: new Map(g.mountedGroups).set(n, { defaultLayoutDeferred: o.defaultLayoutDeferred, derivedPanelConstraints: o.derivedPanelConstraints, layout: c, separatorToPanels: o.separatorToPanels }) })); } function Pe(e) { if (e.defaultPrevented) return; const t = e.currentTarget, n = le(t); if (!n.disabled) switch (e.key) { case "ArrowDown": { e.preventDefault(), n.orientation === "vertical" && W(t, 5); break; } case "ArrowLeft": { e.preventDefault(), n.orientation === "horizontal" && W(t, -5); break; } case "ArrowRight": { e.preventDefault(), n.orientation === "horizontal" && W(t, 5); break; } case "ArrowUp": { e.preventDefault(), n.orientation === "vertical" && W(t, -5); break; } case "End": { e.preventDefault(), W(t, 100); break; } case "Enter": { e.preventDefault(); const o = le(t), { derivedPanelConstraints: i, layout: s, separatorToPanels: l } = Be(o), r = o.separators.find( (g) => g.element === t ); P(r, "Matching separator not found"); const a = l.get(r); P(a, "Matching panels not found"); const u = a[0], c = i.find( (g) => g.panelId === u.id ); if (P(c, "Panel metadata not found"), c.collapsible) { const g = s[u.id], b = c.collapsedSize === g ? o.inMemoryLastExpandedPanelSizes[u.id] ?? c.minSize : c.collapsedSize; W(t, b - g); } break; } case "F6": { e.preventDefault(); const i = le(t).separators.map( (a) => a.element ), s = Array.from(i).findIndex( (a) => a === e.currentTarget ); P(s !== null, "Index not found"); const l = e.shiftKey ? s > 0 ? s - 1 : i.length - 1 : s + 1 < i.length ? s + 1 : 0; i[l].focus(); break; } case "Home": { e.preventDefault(), W(t, -100); break; } } } function Ce(e) { if (e.defaultPrevented) return; if (e.pointerType === "mouse" && e.button > 0) return; const { mountedGroups: t } = G(), n = me(e, t), o = /* @__PURE__ */ new Map(); let i = !1; n.forEach((s) => { s.separator && (i || (i = !0, s.separator.element.focus())); const l = t.get(s.group); l && o.set(s.group, l.layout); }), I({ interactionState: { hitRegions: n, initialLayoutMap: o, pointerDownAtPoint: { x: e.clientX, y: e.clientY }, state: "active" } }), n.length && e.preventDefault(); } const Rt = (e) => e, fe = () => { }, Ke = 1, Xe = 2, qe = 4, Ye = 8, Re = 3, Me = 12; let ae; function Ee() { return ae === void 0 && (ae = !1, typeof window < "u" && (window.navigator.userAgent.includes("Chrome") || window.navigator.userAgent.includes("Firefox")) && (ae = !0)), ae; } function Mt({ cursorFlags: e, groups: t, state: n }) { let o = 0, i = 0; switch (n) { case "active": case "hover": t.forEach((s) => { if (!s.disableCursor) switch (s.orientation) { case "horizontal": { o++; break; } case "vertical": { i++; break; } } }); } if (!(o === 0 && i === 0)) { switch (n) { case "active": { if (e && Ee()) { const s = (e & Ke) !== 0, l = (e & Xe) !== 0, r = (e & qe) !== 0, a = (e & Ye) !== 0; if (s) return r ? "se-resize" : a ? "ne-resize" : "e-resize"; if (l) return r ? "sw-resize" : a ? "nw-resize" : "w-resize"; if (r) return "s-resize"; if (a) return "n-resize"; } break; } } return Ee() ? o > 0 && i > 0 ? "move" : o > 0 ? "ew-resize" : "ns-resize" : o > 0 && i > 0 ? "grab" : o > 0 ? "col-resize" : "row-resize"; } } const ke = /* @__PURE__ */ new WeakMap(); function ge(e) { if (e.defaultView === null || e.defaultView === void 0) return; let { prevStyle: t, styleSheet: n } = ke.get(e) ?? {}; n === void 0 && (n = new e.defaultView.CSSStyleSheet(), e.adoptedStyleSheets && e.adoptedStyleSheets.push(n)); const { cursorFlags: o, interactionState: i } = G(); switch (i.state) { case "active": case "hover": { const s = Mt({ cursorFlags: o, groups: i.hitRegions.map((r) => r.group), state: i.state }), l = `*, *:hover {cursor: ${s} !important; }`; if (t === l) return; t = l, s ? n.cssRules.length === 0 ? n.insertRule(l) : n.replaceSync(l) : n.cssRules.length === 1 && n.deleteRule(0); break; } case "inactive": { t = void 0, n.cssRules.length === 1 && n.deleteRule(0); break; } } ke.set(e, { prevStyle: t, styleSheet: n }); } function Je({ document: e, event: t, hitRegions: n, initialLayoutMap: o, mountedGroups: i, pointerDownAtPoint: s, prevCursorFlags: l }) { let r = 0; const a = new Map(i); n.forEach((c) => { const { group: g, groupSize: b } = c, { disableCursor: S, orientation: m, panels: d } = g; let f = 0; s ? m === "horizontal" ? f = (t.clientX - s.x) / b * 100 : f = (t.clientY - s.y) / b * 100 : m === "horizontal" ? f = t.clientX < 0 ? -100 : 100 : f = t.clientY < 0 ? -100 : 100; const h = o.get(g), { defaultLayoutDeferred: v, derivedPanelConstraints: x, layout: y, separatorToPanels: p } = i.get(g) ?? { defaultLayoutDeferred: !1 }; if (x && h && y && p) { const w = oe({ delta: f, initialLayout: h, panelConstraints: x, pivotIndices: c.panels.map((C) => d.indexOf(C)), prevLayout: y, trigger: "mouse-or-touch" }); if (U(w, y)) { if (f !== 0 && !S) switch (m) { case "horizontal": { r |= f < 0 ? Ke : Xe; break; } case "vertical": { r |= f < 0 ? qe : Ye; break; } } } else a.set(c.group, { defaultLayoutDeferred: v, derivedPanelConstraints: x, layout: w, separatorToPanels: p }); } }); let u = 0; t.movementX === 0 ? u |= l & Re : u |= r & Re, t.movementY === 0 ? u |= l & Me : u |= r & Me, I({ cursorFlags: u, mountedGroups: a }), ge(e); } function Ge(e) { const { cursorFlags: t, interactionState: n, mountedGroups: o } = G(); switch (n.state) { case "active": Je({ document: e.currentTarget, event: e, hitRegions: n.hitRegions, initialLayoutMap: n.initialLayoutMap, mountedGroups: o, prevCursorFlags: t }); } } function Ie(e) { if (e.defaultPrevented) return; const { cursorFlags: t, interactionState: n, mountedGroups: o } = G(); switch (n.state) { case "active": { if ( // Skip this check for "pointerleave" events, else Firefox triggers a false positive (see #514) e.buttons === 0 ) { I( (i) => i.interactionState.state === "inactive" ? i : { cursorFlags: 0, interactionState: { state: "inactive" } } ), I((i) => ({ mountedGroups: new Map(i.mountedGroups) })); return; } Je({ document: e.currentTarget, event: e, hitRegions: n.hitRegions, initialLayoutMap: n.initialLayoutMap, mountedGroups: o, pointerDownAtPoint: n.pointerDownAtPoint, prevCursorFlags: t }); break; } default: { const i = me(e, o); i.length === 0 ? n.state !== "inactive" && I({ interactionState: { state: "inactive" } }) : I({ interactionState: { hitRegions: i, state: "hover" } }), ge(e.currentTarget); break; } } } function De(e) { if (e.relatedTarget instanceof HTMLIFrameElement) { const { interactionState: t } = G(); switch (t.state) { case "hover": I({ interactionState: { state: "inactive" } }); } } } function Oe(e) { if (e.defaultPrevented) return; if (e.pointerType === "mouse" && e.button > 0) return; const { interactionState: t } = G(); switch (t.state) { case "active": I({ cursorFlags: 0, interactionState: { state: "inactive" } }), t.hitRegions.length > 0 && (ge(e.currentTarget), I((n) => ({ mountedGroups: new Map(n.mountedGroups) })), e.preventDefault()); } } function Te(e) { let t = 0, n = 0; const o = {}; for (const s of e) if (s.defaultSize !== void 0) { t++; const l = _(s.defaultSize); n += l, o[s.panelId] = l; } else o[s.panelId] = void 0; const i = e.length - t; if (i !== 0) { const s = _((100 - n) / i); for (const l of e) l.defaultSize === void 0 && (o[l.panelId] = s); } return o; } function Et(e, t, n) { if (!n[0]) return; const i = e.panels.find((u) => u.element === t); if (!i || !i.onResize) return; const s = J({ group: e }), l = e.orientation === "horizontal" ? i.element.offsetWidth : i.element.offsetHeight, r = i.mutableValues.prevSize, a = { asPercentage: _(l / s * 100), inPixels: l }; i.mutableValues.prevSize = a, i.onResize(a, i.id, r); } function kt(e, t) { if (Object.keys(e).length !== Object.keys(t).length) return !1; for (const o in e) if (e[o] !== t[o]) return !1; return !0; } function Gt(e, t) { const n = e.map((i) => i.id), o = Object.keys(t); if (n.length !== o.length) return !1; for (const i of n) if (!o.includes(i)) return !1; return !0; } const q = /* @__PURE__ */ new Map(); function It(e) { let t = !0; P( e.element.ownerDocument.defaultView, "Cannot register an unmounted Group" ); const n = e.element.ownerDocument.defaultView.ResizeObserver, o = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), s = new n((m) => { for (const d of m) { const { borderBoxSize: f, target: h } = d; if (h === e.element) { if (t) { if (J({ group: e }) === 0) return; I((x) => { const y = x.mountedGroups.get(e); if (y) { const p = pe(e), w = y.defaultLayoutDeferred ? Te(p) : y.layout, C = B({ layout: w, panelConstraints: p }); return !y.defaultLayoutDeferred && U(w, C) && kt( y.derivedPanelConstraints, p ) ? x : { mountedGroups: new Map(x.mountedGroups).set(e, { defaultLayoutDeferred: !1, derivedPanelConstraints: p, layout: C, separatorToPanels: y.separatorToPanels }) }; } return x; }); } } else Et(e, h, f); } }); s.observe(e.element), e.panels.forEach((m) => { P( !o.has(m.id), `Panel ids must be unique; id "${m.id}" was used more than once` ), o.add(m.id), m.onResize && s.observe(m.element); }); const l = J({ group: e }), r = pe(e), a = e.panels.map(({ id: m }) => m).join(","); let u = e.defaultLayout; u && (Gt(e.panels, u) || (u = void 0)); const c = e.inMemoryLayouts[a] ?? u ?? Te(r), g = B({ layout: c, panelConstraints: r }), b = Ve(e), S = e.element.ownerDocument; return I((m) => { const d = /* @__PURE__ */ new Map(); return q.set( S, (q.get(S) ?? 0) + 1 ), b.forEach((f) => { f.separator && d.set(f.separator, f.panels); }), { mountedGroups: new Map(m.mountedGroups).set(e, { defaultLayoutDeferred: l === 0, derivedPanelConstraints: r, layout: g, separatorToPanels: d }) }; }), e.separators.forEach((m) => { P( !i.has(m.id), `Separator ids must be unique; id "${m.id}" was used more than once` ), i.add(m.id), m.element.addEventListener("keydown", Pe); }), q.get(S) === 1 && (S.addEventListener("dblclick", Le, !0), S.addEventListener("pointerdown", Ce, !0), S.addEventListener("pointerleave", Ge), S.addEventListener("pointermove", Ie), S.addEventListener("pointerout", De), S.addEventListener("pointerup", Oe, !0)), function() { t = !1, q.set( S, Math.max(0, (q.get(S) ?? 0) - 1) ), I((d) => { const f = new Map(d.mountedGroups); return f.delete(e), { mountedGroups: f }; }), e.separators.forEach((d) => { d.element.removeEventListener("keydown", Pe); }), q.get(S) || (S.removeEventListener( "dblclick", Le, !0 ), S.removeEventListener( "pointerdown", Ce, !0 ), S.removeEventListener("pointerleave", Ge), S.removeEventListener("pointermove", Ie), S.removeEventListener("pointerout", De), S.removeEventListener("pointerup", Oe, !0)), s.disconnect(); }; } function Dt() { const [e, t] = ne({}), n = Q(() => t({}), []); return [e, n]; } function ye(e) { const t = rt(); return `${e ?? t}`; } const K = typeof window < "u" ? Ae : ue; function ee(e) { const t = O(e); return K(() => { t.current = e; }, [e]), Q( (...n) => t.current?.(...n), [t] ); } function Se(...e) { return ee((t) => { e.forEach((n) => { if (n) switch (typeof n) { case "function": { n(t); break; } case "object": { n.current = t; break; } } }); }); } function ve(e) { const t = O({ ...e }); return K(() => { for (const n in e) t.current[n] = e[n]; }, [e]), t.current; } const Ze = st(null); function Ot(e, t) { const n = O({ getLayout: () => ({}), setLayout: Rt }); Ne(t, () => n.current, []), K(() => { Object.assign( n.current, Ue({ groupId: e }) ); }); } function Tt({ children: e, className: t, defaultLayout: n, disableCursor: o, disabled: i, elementRef: s, groupRef: l, id: r, onLayoutChange: a, onLayoutChanged: u, orientation: c = "horizontal", resizeTargetMinimumSize: g = { coarse: 20, fine: 10 }, style: b, ...S }) { const m = O({ onLayoutChange: {}, onLayoutChanged: {} }), d = ee((z) => { U(m.current.onLayoutChange, z) || (m.current.onLayoutChange = z, a?.(z)); }), f = ee((z) => { U(m.current.onLayoutChanged, z) || (m.current.onLayoutChanged = z, u?.(z)); }), h = ye(r), v = O(null), [x, y] = Dt(), p = O({ lastExpandedPanelSizes: {}, layouts: {}, panels: [], resizeTargetMinimumSize: g, separators: [] }), w = Se(v, s); Ot(h, l); const C = ee( (z, L) => { const { interactionState: E, mountedGroups: M } = G(); for (const D of M.keys()) if (D.id === z) { const T = M.get(D); if (T) { let N = !1; switch (E.state) { case "active": { N = E.hitRegions.some( (Z) => Z.group === D ); break; } } return { flexGrow: T.layout[L] ?? 1, pointerEvents: N ? "none" : void 0 }; } } return { flexGrow: n?.[L] ?? 1 }; } ), R = ve({ defaultLayout: n, disableCursor: o }), X = _e( () => ({ get disableCursor() { return !!R.disableCursor; }, getPanelStyles: C, id: h, orientation: c, registerPanel: (z) => { const L = p.current; return L.panels = he(c, [ ...L.panels, z ]), y(), () => { L.panels = L.panels.filter( (E) => E !== z ), y(); }; }, registerSeparator: (z) => { const L = p.current; return L.separators = he(c, [ ...L.separators, z ]), y(), () => { L.separators = L.separators.filter( (E) => E !== z ), y(); }; }, togglePanelDisabled: (z, L) => { const M = p.current.panels.find( (T) => T.id === z ); M && (M.panelConstraints.disabled = L); const { mountedGroups: D } = G(); for (const T of D.keys()) if (T.id === h) { const N = D.get(T); N && (N.derivedPanelConstraints = pe(T)); } }, toggleSeparatorDisabled: (z, L) => { const M = p.current.separators.find( (D) => D.id === z ); M && (M.disabled = L); } }), [C, h, y, c, R] ), V = O(null); return K(() => { const z = v.current; if (z === null) return; const L = p.current; let E; if (R.defaultLayout !== void 0 && Object.keys(R.defaultLayout).length === L.panels.length) { E = {}; for (const H of L.panels) { const j = R.defaultLayout[H.id]; j !== void 0 && (E[H.id] = j); } } const M = { defaultLayout: E, disableCursor: !!R.disableCursor, disabled: !!i, element: z, id: h, inMemoryLastExpandedPanelSizes: p.current.lastExpandedPanelSizes, inMemoryLayouts: p.current.layouts, orientation: c, panels: L.panels, resizeTargetMinimumSize: L.resizeTargetMinimumSize, separators: L.separators }; V.current = M; const D = It(M), N = G().mountedGroups.get(M); if (N) { const { defaultLayoutDeferred: H, derivedPanelConstraints: j, layout: ie } = N; !H && j.length > 0 && (d(ie), f(ie)); } const Z = $.addListener( "interactionStateChange", (H) => { H.state; } ), Qe = $.addListener( "mountedGroupsChange", (H) => { const j = H.get(M); if (j) { const { defaultLayoutDeferred: ie, derivedPanelConstraints: et, layout: ce } = j; if (ie || et.length === 0) return; const tt = M.panels.map(({ id: it }) => it).join(","); M.inMemoryLayouts[tt] = ce; const { interactionState: nt } = G(), ot = nt.state !== "active"; d(ce), ot && f(ce); } } ); return () => { V.current = null, D(), Z(), Qe(); }; }, [ i, h, f, d, c, x, R ]), ue(() => { const z = V.current; z && (z.defaultLayout = n, z.disableCursor = !!o); }), /* @__PURE__ */ te(Ze.Provider, { value: X, children: /* @__PURE__ */ te( "div", { ...S, className: t, "data-group": !0, "data-testid": h, id: h, ref: w, style: { height: "100%", width: "100%", overflow: "hidden", ...b, display: "flex", flexDirection: c === "horizontal" ? "row" : "column", flexWrap: "nowrap", // Inform the browser that the library is handling touch events for this element // but still allow users to scroll content within panels in the non-resizing direction // NOTE This is not an inherited style // See github.com/bvaughn/react-resizable-panels/issues/662 touchAction: c === "horizontal" ? "pan-y" : "pan-x" }, children: e } ) }); } Tt.displayName = "Group"; function de(e, t) { return `react-resizable-panels:${[e, ...t].join(":")}`; } function Wt({ debounceSaveMs: e = 100, panelIds: t, storage: n = localStorage, ...o }) { const i = t !== void 0, s = "id" in o ? o.id : o.groupId, l = de(s, t ?? []), r = Fe( At, () => n.getItem(l), () => n.getItem(l) ), a = _e( () => r ? JSON.parse(r) : void 0, [r] ), u = O(null), c = Q(() => { const S = u.current; S && (u.current = null, clearTimeout(S)); }, []); Ae(() => () => { c(); }, [c]); const g = Q( (S) => { c(); let m; i ? m = de(s, Object.keys(S)) : m = de(s, []); try { n.setItem(m, JSON.stringify(S)); } catch (d) { console.error(d); } }, [c, i, s, n] ), b = Q( (S) => { c(), e === 0 ? g(S) : u.current = setTimeout(() => { g(S); }, e); }, [c, e, g] ); return { /** * Pass this value to `Group` as the `defaultLayout` prop. */ defaultLayout: a, /** * Attach this callback on the `Group` as the `onLayoutChange` prop. * * @deprecated Use the {@link onLayoutChanged} prop instead. */ onLayoutChange: b, /** * Attach this callback on the `Group` as the `onLayoutChanged` prop. */ onLayoutChanged: g }; } function At() { return function() { }; } function Ut() { return ne(null); } function Bt() { return O(null); } function xe() { const e = at(Ze); return P( e, "Group Context not found; did you render a Panel or Separator outside of a Group?" ), e; } function Nt(e, t) { const { id: n } = xe(), o = O({ collapse: fe, expand: fe, getSize: () => ({ asPercentage: 0, inPixels: 0 }), isCollapsed: () => !1, resize: fe }); Ne(t, () => o.current, []), K(() => { Object.assign( o.current, We({ groupId: n, panelId: e }) ); }); } function _t({ children: e, className: t, collapsedSize: n = "0%", collapsible: o = !1, defaultSize: i, disabled: s, elementRef: l, id: r, maxSize: a = "100%", minSize: u = "0%", onResize: c, panelRef: g, style: b, ...S }) { const m = !!r, d = ye(r), f = ve({ disabled: s }), h = O(null), v = Se(h, l), { getPanelStyles: x, id: y, orientation: p, registerPanel: w, togglePanelDisabled: C } = xe(), R = c !== null, X = ee( (z, L, E) => { c?.(z, r, E); } ); K(() => { const z = h.current; if (z !== null) { const L = { element: z, id: d, idIsStable: m, mutableValues: { expandToSize: void 0, prevSize: void 0 }, onResize: R ? X : void 0, panelConstraints: { collapsedSize: n, collapsible: o, defaultSize: i, disabled: f.disabled, maxSize: a, minSize: u } }; return w(L); } }, [ n, o, i, R, d, m, a, u, X, w, f ]), ue(() => { C(d, !!s); }, [s, d, C]), Nt(d, g); const V = Fe( (z) => ($.addListener("mountedGroupsChange", z), () => { $.removeListener("mountedGroupsChange", z); }), // useSyncExternalStore does not support a custom equality check // stringify avoids re-rendering when the style value hasn't changed () => JSON.stringify(x(y, d)), () => JSON.stringify(x(y, d)) ); return /* @__PURE__ */ te( "div", { ...S, "aria-disabled": s || void 0, "data-panel": !0, "data-testid": d, id: d, ref: v, style: { ...Ft, display: "flex", flexBasis: 0, flexShrink: 1, // Prevent Panel content from interfering with panel size overflow: "hidden", ...JSON.parse(V) }, children: /* @__PURE__ */ te( "div", { className: t, style: { maxHeight: "100%", maxWidth: "100%", flexGrow: 1, ...b, // Inform the browser that the library is handling touch events for this element // but still allow users to scroll content within panels in the non-resizing direction // NOTE This is not an inherited style // See github.com/bvaughn/react-resizable-panels/issues/662 touchAction: p === "horizontal" ? "pan-y" : "pan-x" }, children: e } ) } ); } _t.displayName = "Panel"; const Ft = { minHeight: 0, maxHeight: "100%", height: "auto", minWidth: 0, maxWidth: "100%", width: "auto", border: "none", borderWidth: 0, padding: 0, margin: 0 }; function Kt() { return ne(null); } function Xt() { return O(null); } function $t({ layout: e, panelConstraints: t, panelId: n, panelIndex: o }) { let i, s; const l = e[n], r = t.find( (a) => a.panelId === n ); if (r) { const a = r.maxSize, u = r.collapsible ? r.collapsedSize : r.minSize, c = [o, o + 1]; s = B({ layout: oe({ delta: u - l, initialLayout: e, panelConstraints: t, pivotIndices: c, prevLayout: e }), panelConstraints: t })[n], i = B({ layout: oe({ delta: a - l, initialLayout: e, panelConstraints: t, pivotIndices: c, prevLayout: e }), panelConstraints: t })[n]; } return { valueControls: n, valueMax: i, valueMin: s, valueNow: l }; } function Ht({ children: e, className: t, disabled: n, elementRef: o, id: i, style: s, ...l }) { const r = ye(i), a = ve({ disabled: n }), [u, c] = ne({}), [g, b] = ne("inactive"), S = O(null), m = Se(S, o), { disableCursor: d, id: f, orientation: h, registerSeparator: v, toggleSeparatorDisabled: x } = xe(), y = h === "horizontal" ? "vertical" : "horizontal"; K(() => { const w = S.current; if (w !== null) { const C = { disabled: a.disabled, element