@eledah/parto
Version:
Framework-agnostic argument map sunburst charts with light/dark themes
713 lines (712 loc) • 25 kB
JavaScript
import * as e from "d3";
//#region src/config.ts
var t = {
legend: "Argument types",
center: "Center",
support: "Agree",
attack: "Disagree",
claim: "Claim",
unknownSpeaker: "Unknown",
intensity: "Intensity",
confidence: "Confidence",
statusLoading: "Loading map…",
statusEmpty: "No map data yet.",
statusError: "Could not load this argument map."
}, n = {
center: "#b08a3e",
support: "#3f7652",
attack: "#9f4f4f",
border: "#ffffff"
}, r = {
colors: { ...n },
chart: {
maxCenterRadius: .4,
radiusPadding: 5,
minRadius: 10,
cornerRadius: 3,
strokeWidth: .5
},
spacing: {
verticalGap: .01,
padAngle: {
inner: .025,
outer: .012
},
radiusExponent: {
base: 1.2,
perLevel: .2
},
exponentDepthThreshold: 3
}
}, i = {
center: "--pam-center",
support: "--pam-support",
attack: "--pam-attack",
border: "--pam-border"
};
function a(e) {
return !!(e && (e.startsWith("#") || e.startsWith("rgb")));
}
function o(e) {
let t = getComputedStyle(e);
for (let [e, n] of Object.entries(i)) {
let i = t.getPropertyValue(n).trim();
a(i) && (r.colors[e] = i);
}
}
function s(e, t) {
for (let [n, r] of Object.entries({
center: "--pam-center",
support: "--pam-support",
attack: "--pam-attack",
border: "--pam-border"
})) {
let i = t[n];
i && e.style.setProperty(r, i);
}
o(e);
}
//#endregion
//#region src/core/buildTree.ts
function c(e) {
let t = [], n = /* @__PURE__ */ new Map();
for (let t of e) n.set(t.id, t);
let r = e.find((e) => e.type === "thesis");
if (!r) return {
tree: null,
warnings: ["No thesis node found"]
};
let i = /* @__PURE__ */ new Map();
for (let t of e) for (let e of t.relations) {
if (!n.has(e.target_node_id)) continue;
let r = i.get(e.target_node_id) ?? [];
r.push({
childId: t.id,
relationType: e.relation_type,
reasoning: e.reasoning
}), i.set(e.target_node_id, r);
}
let a = (e, r, o, s, c, l) => {
let u = l.join("/"), d = {
...e,
children: [],
value: 1,
relationType: o,
relationReasoning: s,
parentId: r,
pathKey: u
};
if (c.has(e.id)) return t.push(`Cycle detected at node ${e.id}; branch skipped`), d;
let f = new Set(c);
f.add(e.id);
let p = i.get(e.id) ?? [];
for (let t of p) {
let r = n.get(t.childId);
if (!r) continue;
let i = a(r, e.id, t.relationType, t.reasoning, f, [...l, t.childId]);
d.children.push(i);
}
return d;
};
return {
tree: a(r, void 0, void 0, void 0, /* @__PURE__ */ new Set(), [r.id]),
warnings: t
};
}
function l(e, t) {
if (!e) return null;
if (e.id === t) return e;
for (let n of e.children) {
let e = l(n, t);
if (e) return e;
}
return null;
}
function u(e, t) {
if (!e || t.length === 0) return null;
let n = e;
for (let e = 1; e < t.length; e++) {
let r = t[e];
if (n = n?.children.find((e) => e.id === r) ?? null, !n) return null;
}
return n;
}
function d(e, t) {
let n = [], r = (e, i) => {
let a = [...i, e];
if (e.id === t) return n.push(...a), !0;
for (let t of e.children) if (r(t, a)) return !0;
return !1;
};
return r(e, []), n;
}
function f(e, t) {
return t && e.id === t.id ? "pam-arc--center" : e.relationType === "attack" ? "pam-arc--attack" : "pam-arc--support";
}
function p(e, t, n) {
return t && e.id === t.id ? n.center : e.relationType === "attack" ? n.attack : n.support;
}
//#endregion
//#region src/errors.ts
var m = class extends Error {
constructor(e) {
super(e), this.name = "ArgumentMapError";
}
}, h = class extends m {
issues;
constructor(e) {
super(e.join("; ")), this.name = "ValidationError", this.issues = e;
}
};
//#endregion
//#region src/core/validateMapData.ts
function g(e) {
let t = [], n = [];
if (!e || typeof e != "object") throw new h(["Map data must be an object"]);
let r = e;
if (!Array.isArray(r.new_nodes)) throw new h(["Map data must include a new_nodes array"]);
let i = [], a = /* @__PURE__ */ new Set(), o = 0;
for (let e of r.new_nodes) {
if (!e || typeof e != "object") {
t.push("Each node must be an object");
continue;
}
let n = e, r = String(n.id ?? "");
if (!r) {
t.push("Node is missing id");
continue;
}
if (a.has(r)) {
t.push(`Duplicate node id: ${r}`);
continue;
}
a.add(r);
let s = String(n.type ?? "");
s === "thesis" && (o += 1);
let c = (Array.isArray(n.relations) ? n.relations : []).map((e) => {
let n = e, i = String(n.relation_type ?? "");
return i !== "support" && i !== "attack" && t.push(`Node ${r} has unsupported relation_type: ${i}`), {
target_node_id: String(n.target_node_id ?? ""),
relation_type: i,
reasoning: String(n.reasoning ?? "")
};
}), l = {
id: r,
type: s,
title: String(n.title ?? ""),
description: String(n.description ?? ""),
quote: String(n.quote ?? ""),
speaker: String(n.speaker ?? ""),
relations: c
};
if (n.score && typeof n.score == "object") {
let e = n.score;
l.score = {
intensity: Number(e.intensity ?? 0),
confidence: Number(e.confidence ?? 0)
};
}
i.push(l);
}
if (t.length > 0) throw new h(t);
if (o === 0 || o > 1) throw new h(["Map must include exactly one thesis node"]);
let s = new Set(i.map((e) => e.id));
for (let e of i) for (let t of e.relations) s.has(t.target_node_id) || n.push(`Node ${e.id} references missing target ${t.target_node_id}`);
return {
data: { new_nodes: i },
warnings: n
};
}
//#endregion
//#region src/core/ZoomController.ts
var _ = class {
fullTree = null;
zoomStack = [];
setTree(e) {
this.fullTree = e, this.zoomStack = e ? [e] : [];
}
getFocusRoot() {
return this.zoomStack.length === 0 ? null : this.zoomStack[this.zoomStack.length - 1] ?? null;
}
getFullTree() {
return this.fullTree;
}
getZoomPath() {
return this.zoomStack.map((e) => ({
id: e.id,
title: e.title,
type: e.type,
relationType: e.relationType
}));
}
resetZoom() {
this.fullTree && (this.zoomStack = [this.fullTree]);
}
zoomTo(e) {
if (!this.fullTree) return !1;
let t = d(this.fullTree, e);
return t.length === 0 || !t[t.length - 1] ? !1 : (this.zoomStack = t, !0);
}
zoomToPath(e) {
if (!this.fullTree || e.length === 0 || !u(this.fullTree, e)) return !1;
let t = [], n = this.fullTree;
t.push(n);
for (let r = 1; r < e.length; r++) {
let i = e[r], a = n.children.find((e) => e.id === i);
if (!a) return !1;
t.push(a), n = a;
}
return this.zoomStack = t, !0;
}
zoomIn(e) {
return (e.children?.length ?? 0) !== 0 && (this.zoomStack.push(e), !0);
}
zoomOut() {
return this.zoomStack.length <= 1 ? !1 : (this.zoomStack.pop(), !0);
}
handleClick(e, t, n) {
if (t === 0) {
this.zoomOut();
return;
}
if (n) {
let t = l(this.getFocusRoot(), e.id);
t && this.zoomIn(t);
}
}
}, v = class {
container;
chartRoot;
width = 0;
height = 0;
radius = 0;
svg;
g;
partition = e.partition();
arc;
legend = null;
currentRoot = null;
highlightId = null;
resizeObserver = null;
options;
tooltipId;
touchZoomPathKey = null;
touchOutsideHandler = null;
constructor(n, i) {
this.container = n, this.options = i, this.tooltipId = `pam-tooltip-${Math.random().toString(36).slice(2, 9)}`, this.chartRoot = document.createElement("div"), this.chartRoot.className = "pam-chart__canvas", n.appendChild(this.chartRoot), o(n), this.svg = e.select(this.chartRoot).append("svg").attr("width", "100%").attr("height", "100%").attr("preserveAspectRatio", "xMidYMid meet").attr("role", "img").attr("aria-label", i.ariaLabel), this.g = this.svg.append("g"), (i.legend ?? !0) && (this.legend = this.createLegend(i.labels ?? t), this.chartRoot.appendChild(this.legend)), this.partition = e.partition().size([2 * Math.PI, this.radius]), this.arc = e.arc().startAngle((e) => e.x0).endAngle((e) => e.x1).padAngle(r.spacing.padAngle.inner).innerRadius((e) => e.y0).outerRadius((e) => e.y1), this.resizeObserver = new ResizeObserver(() => this.resize()), this.resizeObserver.observe(n), this.resize();
}
destroy() {
this.unbindTouchOutsideDismiss(), this.resizeObserver &&= (this.resizeObserver.disconnect(), null), this.chartRoot.remove();
}
resize() {
let e = this.chartRoot.getBoundingClientRect();
this.width = e.width, this.height = e.height;
let t = this.legend?.getBoundingClientRect().height ?? 0, n = this.legend ? Math.max(56, t + 28) : 0, i = Math.max(0, this.height - n);
this.radius = Math.min(this.width, i) / 2 - r.chart.radiusPadding, !(this.radius < r.chart.minRadius) && (this.partition.size([2 * Math.PI, this.radius]), this.svg.attr("viewBox", `0 0 ${this.width} ${this.height}`), this.g.attr("transform", `translate(${this.width / 2}, ${i / 2})`), this.currentRoot && this.render(this.currentRoot));
}
setHighlight(e) {
this.highlightId = e, this.g.selectAll("path").classed("pam-arc--highlighted", (t) => e === t.data.id).classed("pam-arc--dimmed", (t) => e != null && e !== t.data.id);
}
render(t) {
this.touchZoomPathKey = null, this.unbindTouchOutsideDismiss(), this.currentRoot = t, o(this.container);
let n = r.colors, i = e.hierarchy(t), a = 0;
i.each((e) => {
a = Math.max(a, e.depth);
});
let s = Math.max(a, 1);
this.partition(i);
let c = i, l = (e, t, n) => {
if (e.x0 = t, e.x1 = n, e.children?.length) {
let r = (n - t) / e.children.length;
e.children.forEach((e, n) => {
l(e, t + n * r, t + (n + 1) * r);
});
}
};
l(c, 0, 2 * Math.PI);
let u = (e) => (e / this.radius) ** +(r.spacing.radiusExponent.base + (s - r.spacing.exponentDepthThreshold) * r.spacing.radiusExponent.perLevel) * this.radius, d = this.radius * r.spacing.verticalGap;
this.arc.innerRadius((e) => u(e.y0) + d).outerRadius((e) => e.depth === 0 ? Math.min(u(e.y1) - d, this.radius * r.chart.maxCenterRadius) : u(e.y1) - d).padAngle((e) => {
let t = e.depth / s;
return r.spacing.padAngle.inner - t * (r.spacing.padAngle.inner - r.spacing.padAngle.outer);
}).cornerRadius(r.chart.cornerRadius), this.g.selectAll("*").remove();
let m = this.g.selectAll("path").data(c.descendants()).enter().append("path").attr("d", this.arc).attr("data-node-id", (e) => e.data.id).attr("data-path-key", (e) => e.data.pathKey).attr("class", (e) => f(e.data, t)).attr("tabindex", "0").attr("role", "button").attr("aria-label", (e) => e.data.title).attr("aria-describedby", this.tooltipId).style("stroke", n.border).style("stroke-width", r.chart.strokeWidth).style("stroke-linejoin", "round").style("cursor", this.options.zoomEnabled ? "pointer" : "default").classed("pam-arc--highlighted", (e) => this.highlightId === e.data.id).classed("pam-arc--dimmed", (e) => this.highlightId != null && this.highlightId !== e.data.id), h = (r, i) => {
m.classed("pam-arc--dimmed", (e) => e.data.id !== i.data.id), m.classed("pam-arc--highlighted", (e) => e.data.id === i.data.id);
try {
let a = p(i.data, t, n), o = e.color(a);
o && (o.opacity = .28), e.select(r.currentTarget).style("filter", `brightness(${i.depth === 0 ? 1.02 : 1.06}) drop-shadow(0 2px 5px ${o?.formatRgb() ?? a})`);
} catch {}
this.options.onHover?.(i.data, r);
}, g = () => {
m.classed("pam-arc--dimmed", !1).classed("pam-arc--highlighted", !1).style("filter", "none"), this.highlightId && this.setHighlight(this.highlightId), this.options.onLeave?.();
}, _ = (e, t) => {
if (e.stopPropagation(), e.pointerType === "touch") {
this.touchZoomPathKey === t.data.pathKey ? (this.touchZoomPathKey = null, this.unbindTouchOutsideDismiss(), this.options.zoomEnabled && this.options.onClick?.(t.data, t.depth, (t.data.children?.length ?? 0) > 0)) : (this.touchZoomPathKey = t.data.pathKey, h(e, t), this.bindTouchOutsideDismiss(g));
return;
}
this.options.zoomEnabled && this.options.onClick?.(t.data, t.depth, (t.data.children?.length ?? 0) > 0);
};
m.on("pointerenter", (e, t) => {
e.pointerType !== "touch" && h(e, t);
}).on("pointermove", (e, t) => {
e.pointerType !== "touch" && h(e, t);
}).on("pointerleave", (e) => {
e.pointerType !== "touch" && g();
}).on("focus", (e, t) => h(e, t)).on("blur", () => g()).on("click", (e, t) => _(e, t)).on("keydown", (e, t) => {
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), this.options.zoomEnabled && this.options.onClick?.(t.data, t.depth, (t.data.children?.length ?? 0) > 0));
});
}
getTooltipElementId() {
return this.tooltipId;
}
createLegend(e) {
let t = document.createElement("div");
t.className = "pam-chart__legend", t.setAttribute("role", "list"), t.setAttribute("aria-label", e.legend ?? "Argument types");
let n = [
{
type: "center",
label: e.center
},
{
type: "support",
label: e.support
},
{
type: "attack",
label: e.attack
}
];
for (let e of n) {
let n = document.createElement("span");
n.className = "pam-chart__legend-item", n.setAttribute("role", "listitem");
let r = document.createElement("span");
r.className = `pam-chart__legend-swatch pam-chart__legend-swatch--${e.type}`, r.setAttribute("aria-hidden", "true");
let i = document.createElement("span");
i.textContent = e.label, n.append(r, i), t.appendChild(n);
}
return t;
}
bindTouchOutsideDismiss(e) {
this.unbindTouchOutsideDismiss(), this.touchOutsideHandler = (t) => {
let n = t.target;
n && this.container.contains(n) || (this.touchZoomPathKey = null, e(), this.unbindTouchOutsideDismiss());
}, window.setTimeout(() => {
this.touchOutsideHandler && document.addEventListener("pointerdown", this.touchOutsideHandler, !0);
}, 0);
}
unbindTouchOutsideDismiss() {
this.touchOutsideHandler &&= (document.removeEventListener("pointerdown", this.touchOutsideHandler, !0), null);
}
};
function y(e, t, n) {
let r = t.getBoundingClientRect(), i = r.width || 320, a = r.height || 200;
if (n === "touch") {
let t = e.x - i / 2, n = e.y - a - 56;
return t = Math.max(12, Math.min(t, window.innerWidth - i - 12)), n = Math.max(12, Math.min(n, window.innerHeight - a - 12)), {
x: t,
y: n
};
}
let o = e.x + 20, s = e.y + 20;
return o + i > window.innerWidth && (o = e.x - i - 20), s + a > window.innerHeight && (s = e.y - a - 20), {
x: o,
y: s
};
}
//#endregion
//#region src/ui/TooltipController.ts
function b(e, t) {
return e.type === "thesis" ? {
text: t.center,
className: "center"
} : e.relationType === "attack" ? {
text: t.attack,
className: "attack"
} : e.relationType === "support" ? {
text: t.support,
className: "support"
} : {
text: t.claim,
className: "claim"
};
}
function x(e, n = t) {
let r = document.createElement("div");
r.className = "pam-tooltip";
let i = document.createElement("div");
i.className = "pam-tooltip__header";
let a = b(e, n), o = document.createElement("span");
o.className = `pam-tooltip__type pam-tooltip__type--${a.className}`, o.textContent = a.text;
let s = document.createElement("span");
s.className = "pam-tooltip__speaker", s.textContent = e.speaker || n.unknownSpeaker, i.append(o, s);
let c = document.createElement("h3");
if (c.className = "pam-tooltip__title", c.textContent = e.title, r.append(i, c), e.description) {
let t = document.createElement("p");
t.className = "pam-tooltip__description", t.textContent = e.description, r.append(t);
}
if (e.relationType && e.relationReasoning) {
let t = document.createElement("p");
t.className = "pam-tooltip__reasoning", t.textContent = e.relationReasoning, r.append(t);
}
if (e.quote) {
let t = document.createElement("blockquote");
t.className = "pam-tooltip__quote", t.textContent = `"${e.quote}"`, r.append(t);
}
if (e.score) {
let t = document.createElement("div");
t.className = "pam-tooltip__scores";
let i = document.createElement("span");
i.textContent = `${n.intensity}: ${Math.round(e.score.intensity * 100)}%`;
let a = document.createElement("span");
a.textContent = `${n.confidence}: ${Math.round(e.score.confidence * 100)}%`, t.append(i, a), r.append(t);
}
return r;
}
function S(e) {
if ("clientX" in e && typeof e.clientX == "number") {
let t = "pointerType" in e ? e.pointerType : void 0;
return {
x: e.clientX,
y: e.clientY,
pointerType: t
};
}
return {
x: 0,
y: 0
};
}
var C = class {
element;
rafId = null;
position = {
x: 0,
y: 0
};
pointerType;
renderer;
labels;
visible = !1;
constructor(e, t, n, r) {
this.renderer = n, this.labels = r, this.element = document.createElement("div"), this.element.id = t, this.element.className = "pam-tooltip-host", this.element.setAttribute("role", "region"), this.element.setAttribute("aria-live", "polite"), e.appendChild(this.element);
}
show(e, t) {
let n = S(t);
this.position = {
x: n.x,
y: n.y
}, this.pointerType = n.pointerType, this.element.replaceChildren(this.renderer(e, this.labels)), this.element.classList.toggle("pam-tooltip-host--touch", n.pointerType === "touch"), this.element.classList.add("pam-tooltip-host--visible"), this.visible = !0, this.schedulePosition();
}
move(e) {
this.visible && (this.position = {
x: e.clientX,
y: e.clientY
}, this.pointerType = e.pointerType, this.element.classList.toggle("pam-tooltip-host--touch", e.pointerType === "touch"), this.schedulePosition());
}
hide() {
this.visible = !1, this.pointerType = void 0, this.element.classList.remove("pam-tooltip-host--visible", "pam-tooltip-host--touch"), this.element.replaceChildren(), this.rafId != null && (cancelAnimationFrame(this.rafId), this.rafId = null);
}
setLabels(e) {
this.labels = e;
}
destroy() {
this.hide(), this.element.remove();
}
schedulePosition() {
this.rafId != null && cancelAnimationFrame(this.rafId), this.rafId = requestAnimationFrame(() => {
let e = this.element.firstElementChild;
if (!e) return;
let { x: t, y: n } = y(this.position, e, this.pointerType);
this.element.style.left = `${t}px`, this.element.style.top = `${n}px`;
});
}
}, w = class {
element;
messages;
state = null;
constructor(e, t) {
this.messages = t, this.element = document.createElement("div"), this.element.className = "pam-chart__status", this.element.setAttribute("role", "status"), this.element.setAttribute("aria-live", "polite"), this.element.hidden = !0, e.appendChild(this.element);
}
show(e, t) {
this.state = e, this.element.hidden = !1, this.element.className = `pam-chart__status pam-chart__status--${e}`;
let n = t ?? this.messages[e];
this.element.replaceChildren();
let r = document.createElement("p");
if (r.className = "pam-chart__status-text", r.textContent = n, this.element.append(r), e === "loading") {
let e = document.createElement("span");
e.className = "pam-chart__status-spinner", e.setAttribute("aria-hidden", "true"), this.element.prepend(e);
}
}
hide() {
this.state = null, this.element.hidden = !0, this.element.replaceChildren(), this.element.className = "pam-chart__status";
}
isVisible() {
return this.state !== null;
}
getState() {
return this.state;
}
destroy() {
this.element.remove();
}
};
//#endregion
//#region src/ArgumentMapChart.ts
function T(e) {
if (typeof e == "string") {
let t = document.querySelector(e);
if (!t) throw Error(`Container not found: ${e}`);
return t;
}
return e;
}
function E(e) {
return {
...t,
...e
};
}
var D = class {
container;
zoom = new _();
renderer;
tooltip = null;
options;
themeMedia = null;
themeListener = null;
keydownHandler = null;
status;
constructor(e, t, n = {}) {
this.container = T(e), this.container.classList.add("pam-chart");
let r = n.direction ?? "inherit";
if (r !== "inherit" && this.container.setAttribute("dir", r), n.lang && this.container.setAttribute("lang", n.lang), this.options = {
theme: n.theme ?? "auto",
legend: n.legend ?? !0,
zoom: n.zoom ?? !0,
direction: r,
lang: n.lang ?? "en",
ariaLabel: n.ariaLabel ?? "Argument map chart",
tooltip: n.tooltip ?? !0,
labels: E(n.labels),
onNodeHover: n.onNodeHover,
onNodeLeave: n.onNodeLeave,
onNodeClick: n.onNodeClick,
onZoomChange: n.onZoomChange,
onWarning: n.onWarning
}, n.colors && s(this.container, n.colors), this.status = new w(this.container, {
loading: this.options.labels.statusLoading,
empty: this.options.labels.statusEmpty,
error: this.options.labels.statusError
}), this.renderer = new v(this.container, {
ariaLabel: this.options.ariaLabel,
legend: this.options.legend,
labels: this.options.labels,
zoomEnabled: this.options.zoom,
onHover: (e, t) => this.handleHover(e, t),
onLeave: () => this.handleLeave(),
onClick: (e, t, n) => this.handleClick(e, t, n)
}), this.options.tooltip !== !1) {
let e = typeof this.options.tooltip == "function" ? this.options.tooltip : x;
this.tooltip = new C(document.body, this.renderer.getTooltipElementId(), e, this.options.labels);
}
this.applyTheme(this.options.theme), this.bindKeyboard(), t ? this.setData(t) : this.status.show("empty");
}
setData(e) {
try {
let { data: t, warnings: n } = g(e);
for (let e of n) this.options.onWarning?.(e);
let { tree: r, warnings: i } = c(t.new_nodes);
for (let e of i) this.options.onWarning?.(e);
if (!r) {
this.options.onWarning?.("Could not build tree from map data"), this.status.show("error", this.options.labels.statusError);
return;
}
this.status.hide(), this.zoom.setTree(r), this.render(), this.emitZoomChange();
} catch (e) {
let t = e instanceof h ? e.issues.join("; ") : e instanceof Error ? e.message : this.options.labels.statusError;
this.options.onWarning?.(t), this.status.show("error", t);
}
}
setLoading(e) {
e ? (this.status.show("loading"), this.tooltip?.hide()) : this.status.getState() === "loading" && this.status.hide();
}
showError(e) {
this.options.onWarning?.(e ?? this.options.labels.statusError), this.status.show("error", e), this.tooltip?.hide();
}
setTheme(e) {
this.options.theme = e, this.applyTheme(e);
}
setColors(e) {
s(this.container, {
center: e.center,
support: e.support,
attack: e.attack,
border: e.border
}), o(this.container);
let t = this.zoom.getFocusRoot();
t && this.renderer.render(t);
}
highlight(e) {
this.renderer.setHighlight(e);
}
zoomTo(e) {
this.zoom.zoomTo(e) && (this.render(), this.emitZoomChange());
}
zoomToPath(e) {
this.zoom.zoomToPath(e) && (this.render(), this.emitZoomChange());
}
zoomOut() {
this.zoom.zoomOut() && (this.render(), this.emitZoomChange());
}
resetZoom() {
this.zoom.resetZoom(), this.render(), this.emitZoomChange();
}
resize() {
this.renderer.resize();
}
getZoomPath() {
return this.zoom.getZoomPath();
}
destroy() {
this.themeMedia && this.themeListener && this.themeMedia.removeEventListener("change", this.themeListener), this.keydownHandler && document.removeEventListener("keydown", this.keydownHandler), this.tooltip?.destroy(), this.status.destroy(), this.renderer.destroy(), this.container.classList.remove("pam-chart", "pam-chart--light", "pam-chart--dark"), this.options.direction !== "inherit" && this.container.removeAttribute("dir");
}
render() {
let e = this.zoom.getFocusRoot();
e && this.renderer.render(e);
}
emitZoomChange() {
this.options.onZoomChange?.(this.zoom.getZoomPath());
}
handleHover(e, t) {
this.tooltip?.show(e, t), this.options.onNodeHover?.(e, t);
}
handleLeave() {
this.tooltip?.hide(), this.options.onNodeLeave?.();
}
handleClick(e, t, n) {
this.options.zoom && (this.zoom.handleClick(e, t, n), this.render(), this.emitZoomChange()), this.options.onNodeClick?.(e, t, n);
}
applyTheme(e) {
this.container.classList.remove("pam-chart--light", "pam-chart--dark");
let t = (e) => {
this.container.classList.add(e === "light" ? "pam-chart--light" : "pam-chart--dark"), r.colors.center = n.center, r.colors.support = n.support, r.colors.attack = n.attack, r.colors.border = n.border, o(this.container);
let t = this.zoom.getFocusRoot();
t && this.renderer.render(t);
};
if (this.themeMedia && this.themeListener && (this.themeMedia.removeEventListener("change", this.themeListener), this.themeMedia = null, this.themeListener = null), e === "light" || e === "dark") {
t(e);
return;
}
this.themeMedia = window.matchMedia("(prefers-color-scheme: dark)"), t(this.themeMedia.matches ? "dark" : "light"), this.themeListener = (e) => t(e.matches ? "dark" : "light"), this.themeMedia.addEventListener("change", this.themeListener);
}
bindKeyboard() {
this.keydownHandler = (e) => {
this.options.zoom && (e.key === "Escape" || e.key === "Backspace") && this.zoom.zoomOut() && (e.preventDefault(), this.render(), this.emitZoomChange());
}, document.addEventListener("keydown", this.keydownHandler);
}
};
function O(e, t, n) {
return new D(e, t, n);
}
//#endregion
export { m as ArgumentMapError, n as DEFAULT_COLORS, t as DEFAULT_LABELS, v as SunburstRenderer, h as ValidationError, _ as ZoomController, c as buildTree, r as chartConfig, O as createArgumentMap, x as createDefaultTooltip, l as findNodeById, d as pathToNode, g as validateMapData };
//# sourceMappingURL=index.js.map