@vielzeug/prism 2.2.4 → 2.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/charts/area/area-chart.cjs +1 -1
  2. package/dist/charts/area/area-chart.cjs.map +1 -1
  3. package/dist/charts/area/area-chart.d.ts.map +1 -1
  4. package/dist/charts/area/area-chart.js +47 -43
  5. package/dist/charts/area/area-chart.js.map +1 -1
  6. package/dist/charts/bar/bar-chart.cjs +1 -1
  7. package/dist/charts/bar/bar-chart.cjs.map +1 -1
  8. package/dist/charts/bar/bar-chart.d.ts.map +1 -1
  9. package/dist/charts/bar/bar-chart.js +145 -140
  10. package/dist/charts/bar/bar-chart.js.map +1 -1
  11. package/dist/charts/line/line-chart.cjs +1 -1
  12. package/dist/charts/line/line-chart.cjs.map +1 -1
  13. package/dist/charts/line/line-chart.d.ts.map +1 -1
  14. package/dist/charts/line/line-chart.js +48 -44
  15. package/dist/charts/line/line-chart.js.map +1 -1
  16. package/dist/charts/pie/pie-chart.cjs +1 -1
  17. package/dist/charts/pie/pie-chart.cjs.map +1 -1
  18. package/dist/charts/pie/pie-chart.d.ts.map +1 -1
  19. package/dist/charts/pie/pie-chart.js +101 -97
  20. package/dist/charts/pie/pie-chart.js.map +1 -1
  21. package/dist/charts/sparkline/sparkline.cjs +1 -1
  22. package/dist/charts/sparkline/sparkline.cjs.map +1 -1
  23. package/dist/charts/sparkline/sparkline.d.ts.map +1 -1
  24. package/dist/charts/sparkline/sparkline.js +65 -62
  25. package/dist/charts/sparkline/sparkline.js.map +1 -1
  26. package/dist/core/index.d.ts +1 -0
  27. package/dist/core/index.d.ts.map +1 -1
  28. package/dist/core/resolve.cjs +2 -0
  29. package/dist/core/resolve.cjs.map +1 -0
  30. package/dist/core/resolve.d.ts +9 -0
  31. package/dist/core/resolve.d.ts.map +1 -0
  32. package/dist/core/resolve.js +15 -0
  33. package/dist/core/resolve.js.map +1 -0
  34. package/dist/interaction/series-interaction.cjs +1 -1
  35. package/dist/interaction/series-interaction.cjs.map +1 -1
  36. package/dist/interaction/series-interaction.d.ts.map +1 -1
  37. package/dist/interaction/series-interaction.js +4 -3
  38. package/dist/interaction/series-interaction.js.map +1 -1
  39. package/dist/interaction/tooltip.cjs +1 -1
  40. package/dist/interaction/tooltip.cjs.map +1 -1
  41. package/dist/interaction/tooltip.js +1 -1
  42. package/dist/interaction/tooltip.js.map +1 -1
  43. package/dist/prism.cjs +1 -1
  44. package/dist/prism.cjs.map +1 -1
  45. package/dist/prism.iife.js +1 -1
  46. package/dist/prism.iife.js.map +1 -1
  47. package/dist/prism.js +1 -1
  48. package/dist/prism.js.map +1 -1
  49. package/package.json +3 -3
@@ -3,8 +3,9 @@ import { resolveMotion as t } from "../../animation/motion.js";
3
3
  import { tweenNumber as n } from "../../animation/tween.js";
4
4
  import { createSvgElement as r, setAttributes as i } from "../../svg/element.js";
5
5
  import { createChartBase as a } from "../../core/chart-base.js";
6
- import { areaPath as o, linePath as s, monotonePath as c, stepPath as l } from "../../svg/path.js";
7
- import { createScope as u, effect as d, isReactive as f } from "@vielzeug/ripple";
6
+ import { resolveMaybeSignal as o } from "../../core/resolve.js";
7
+ import { areaPath as s, linePath as c, monotonePath as l, stepPath as u } from "../../svg/path.js";
8
+ import { createScope as d, effect as f } from "@vielzeug/ripple";
8
9
  //#region src/charts/sparkline/sparkline.ts
9
10
  function p(e, t, n) {
10
11
  if (e.length === 0) return [];
@@ -20,12 +21,12 @@ function m(e, t, n, r = "linear") {
20
21
  x: e.x,
21
22
  y: n
22
23
  }));
23
- return o(i, a, r ?? "linear");
24
+ return s(i, a, r ?? "linear");
24
25
  }
25
26
  function h(e, t, n, r) {
26
27
  if (e.length === 0) return "";
27
28
  let i = p(e, t, n);
28
- return r === "monotone" ? c(i) : r === "step" ? l(i) : s(i);
29
+ return r === "monotone" ? l(i) : r === "step" ? u(i) : c(i);
29
30
  }
30
31
  function g(a, o, s, c, l, u, d) {
31
32
  let f = o.length, p = Math.max(1, s / f - 1), m = s / f, h = Math.min(0, ...o), g = Math.max(...o) - h || 1, _ = t(u, 0), v = _.duration, y = e(_.easing);
@@ -88,7 +89,7 @@ function y(e) {
88
89
  return `var(--prism-color-${e % 8 + 1})`;
89
90
  }
90
91
  function b(e, t) {
91
- let n = t.variant ?? "line", o = t.color ?? "var(--prism-color-1)", s = t.curve ?? "linear", c = t.strokeWidth ?? 1.5, l = t.fillOpacity ?? .2, p = a(e, {
92
+ let n = t.variant ?? "line", s = t.color ?? "var(--prism-color-1)", c = t.curve ?? "linear", l = t.strokeWidth ?? 1.5, u = t.fillOpacity ?? .2, p = o(t.data), b = a(e, {
92
93
  ...t.a11y ? { a11y: t.a11y } : { ariaHidden: !0 },
93
94
  margin: {
94
95
  bottom: 0,
@@ -96,25 +97,25 @@ function b(e, t) {
96
97
  right: 0,
97
98
  top: 0
98
99
  }
99
- }), { svg: b } = p;
100
- b.classList.add("prism-sparkline");
101
- let x = r("g", { class: "prism-spark-inner" });
102
- b.appendChild(x);
103
- let S;
104
- function C() {
105
- let { height: e, width: a } = p.dimensions.value, u = f(t.data) ? t.data.value : t.data;
106
- for (; x.firstChild;) x.removeChild(x.firstChild);
107
- if (u.length !== 0) {
108
- if (n === "stack" && _(u)) {
100
+ }), { svg: x } = b;
101
+ x.classList.add("prism-sparkline");
102
+ let S = r("g", { class: "prism-spark-inner" });
103
+ x.appendChild(S);
104
+ let C;
105
+ function w() {
106
+ let { height: e, width: a } = b.dimensions.value, o = p.value;
107
+ for (; S.firstChild;) S.removeChild(S.firstChild);
108
+ if (o.length !== 0) {
109
+ if (n === "stack" && _(o)) {
109
110
  let n = r("g", { class: "prism-spark-stack" });
110
- x.appendChild(n);
111
- let o = t.cornerRadius ?? 4, s = u, c = s.reduce((e, t) => e + Math.max(0, t.value), 0);
112
- if (c > 0) {
113
- let l = (t.padPixels ?? 0) / 2, u = 0;
114
- s.forEach((t, d) => {
111
+ S.appendChild(n);
112
+ let s = t.cornerRadius ?? 4, c = o, l = c.reduce((e, t) => e + Math.max(0, t.value), 0);
113
+ if (l > 0) {
114
+ let o = (t.padPixels ?? 0) / 2, u = 0;
115
+ c.forEach((t, d) => {
115
116
  let f = Math.round(u);
116
- u += Math.max(0, t.value) / c * a;
117
- let p = d === s.length - 1 ? a : Math.round(u), m = d === 0, h = d === s.length - 1, g = v(f + (m ? 0 : l), 0, Math.max(0, p - f - (m ? 0 : l) - (h ? 0 : l)), e, o, m, h), _ = r("path", { class: "prism-spark-stack-segment" });
117
+ u += Math.max(0, t.value) / l * a;
118
+ let p = d === c.length - 1 ? a : Math.round(u), m = d === 0, h = d === c.length - 1, g = v(f + (m ? 0 : o), 0, Math.max(0, p - f - (m ? 0 : o) - (h ? 0 : o)), e, s, m, h), _ = r("path", { class: "prism-spark-stack-segment" });
118
119
  i(_, {
119
120
  d: g,
120
121
  fill: t.color ?? y(d)
@@ -123,66 +124,68 @@ function b(e, t) {
123
124
  }
124
125
  } else if (n === "bar") {
125
126
  let n = r("g", { class: "prism-spark-bars" });
126
- x.appendChild(n), g(n, u, a, e, o, t.transition, T.signal);
127
+ S.appendChild(n), g(n, o, a, e, s, t.transition, E.signal);
127
128
  } else {
128
129
  if (n === "area") {
129
- let t = r("path", { class: "prism-spark-fill" }), n = m(u, a, e, s);
130
+ let t = r("path", { class: "prism-spark-fill" }), n = m(o, a, e, c);
130
131
  i(t, {
131
132
  d: n,
132
- fill: o,
133
- "fill-opacity": l,
133
+ fill: s,
134
+ "fill-opacity": u,
134
135
  stroke: "none"
135
- }), x.appendChild(t);
136
+ }), S.appendChild(t);
136
137
  }
137
- let t = r("path", { class: "prism-spark-line" }), d = h(u, a, e, s);
138
+ let t = r("path", { class: "prism-spark-line" }), d = h(o, a, e, c);
138
139
  i(t, {
139
140
  d,
140
141
  fill: "none",
141
- stroke: o,
142
- "stroke-width": c
143
- }), x.appendChild(t);
142
+ stroke: s,
143
+ "stroke-width": l
144
+ }), S.appendChild(t);
144
145
  }
145
- _(u) || w(u);
146
+ _(o) || T(o);
146
147
  }
147
148
  }
148
- function w(e) {
149
- if (S?.(), S = void 0, !t.onHover && !t.onClick || e.length <= 1) return;
150
- let { width: n } = p.dimensions.value;
151
- b.style.cursor = "crosshair";
149
+ function T(e) {
150
+ if (C?.(), C = void 0, !t.onHover && !t.onClick || e.length <= 1) return;
151
+ let { width: n } = b.dimensions.value;
152
+ x.style.cursor = "crosshair";
152
153
  let r = n / (e.length - 1), i = (n) => {
153
- let i = b.getBoundingClientRect(), a = n.clientX - i.left, o = Math.max(0, Math.min(e.length - 1, Math.round(a / r)));
154
+ let i = x.getBoundingClientRect(), a = n.clientX - i.left, o = Math.max(0, Math.min(e.length - 1, Math.round(a / r)));
154
155
  t.onHover?.(o, e[o]);
155
156
  }, a = () => t.onHover?.(null, null), o = (n) => {
156
157
  if (!t.onClick) return;
157
- let i = b.getBoundingClientRect(), a = n.clientX - i.left, o = Math.max(0, Math.min(e.length - 1, Math.round(a / r)));
158
+ let i = x.getBoundingClientRect(), a = n.clientX - i.left, o = Math.max(0, Math.min(e.length - 1, Math.round(a / r)));
158
159
  t.onClick(o, e[o]);
159
160
  };
160
- b.addEventListener("mousemove", i), b.addEventListener("mouseleave", a), b.addEventListener("click", o), S = () => {
161
- b.removeEventListener("mousemove", i), b.removeEventListener("mouseleave", a), b.removeEventListener("click", o);
161
+ x.addEventListener("mousemove", i), x.addEventListener("mouseleave", a), x.addEventListener("click", o), C = () => {
162
+ x.removeEventListener("mousemove", i), x.removeEventListener("mouseleave", a), x.removeEventListener("click", o);
162
163
  };
163
164
  }
164
- let T = new AbortController(), E = u();
165
- E.run(() => {
166
- d(() => {
167
- C();
168
- }, { scheduler: "microtask" });
169
- });
170
- let D = !1;
171
- return {
172
- get disposalSignal() {
173
- return T.signal;
174
- },
175
- dispose() {
176
- D || (D = !0, T.abort(), S?.(), E.dispose(), p.dispose());
177
- },
178
- get disposed() {
179
- return D;
180
- },
181
- el: b,
182
- [Symbol.dispose]() {
183
- this.dispose();
184
- }
185
- };
165
+ let E = new AbortController(), D = d(), O = !1;
166
+ try {
167
+ return D.run(() => {
168
+ f(() => {
169
+ w();
170
+ }, { scheduler: "microtask" });
171
+ }), {
172
+ get disposalSignal() {
173
+ return E.signal;
174
+ },
175
+ dispose() {
176
+ O || (O = !0, E.abort(), C?.(), D.dispose(), b.dispose());
177
+ },
178
+ get disposed() {
179
+ return O;
180
+ },
181
+ el: x,
182
+ [Symbol.dispose]() {
183
+ this.dispose();
184
+ }
185
+ };
186
+ } catch (e) {
187
+ throw E.abort(), D.dispose(), b.dispose(), e;
188
+ }
186
189
  }
187
190
  //#endregion
188
191
  export { b as createSparkline };
@@ -1 +1 @@
1
- {"version":3,"file":"sparkline.js","names":[],"sources":["../../../src/charts/sparkline/sparkline.ts"],"sourcesContent":["import { createScope, effect, isReactive } from '@vielzeug/ripple';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport { createChartBase } from '../../core/chart-base';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { areaPath, linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ChartHandle, SparklineConfig, StackSegment } from '../../types';\n\nfunction buildTopPoints(data: number[], width: number, height: number): Point[] {\n if (data.length === 0) return [];\n\n const xStep = width / Math.max(1, data.length - 1);\n const min = Math.min(...data);\n const max = Math.max(...data);\n const yRange = max - min || 1;\n\n return data.map((v, i) => ({\n x: i * xStep,\n y: height - ((v - min) / yRange) * height,\n }));\n}\n\nfunction buildAreaPath(\n data: number[],\n width: number,\n height: number,\n curve: SparklineConfig['curve'] = 'linear',\n): string {\n if (data.length === 0) return '';\n\n const top = buildTopPoints(data, width, height);\n const bottom = top.map((p) => ({ x: p.x, y: height }));\n\n return areaPath(top, bottom, curve ?? 'linear');\n}\n\nfunction buildPath(data: number[], width: number, height: number, curve: SparklineConfig['curve']): string {\n if (data.length === 0) return '';\n\n const points = buildTopPoints(data, width, height);\n\n return curve === 'monotone' ? monotonePath(points) : curve === 'step' ? stepPath(points) : linePath(points);\n}\n\nfunction renderSparkBars(\n parent: SVGGElement,\n data: number[],\n width: number,\n height: number,\n color: string,\n transition?: SparklineConfig['transition'],\n disposalSignal?: AbortSignal,\n): void {\n const count = data.length;\n const barW = Math.max(1, width / count - 1);\n const gap = width / count;\n const min = Math.min(0, ...data);\n const max = Math.max(...data);\n const yRange = max - min || 1;\n const motion = resolveMotion(transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n while (parent.children.length > count) {\n const last = parent.lastElementChild;\n\n if (last) parent.removeChild(last);\n }\n\n for (let i = 0; i < count; i++) {\n const finalH = Math.max(1, ((data[i] - min) / yRange) * height);\n const finalY = height - finalH;\n\n let rect = parent.children[i] as SVGRectElement | undefined;\n\n if (!rect) {\n rect = createSvgElement('rect', { class: 'prism-spark-bar' });\n parent.appendChild(rect);\n }\n\n setAttributes(rect, { fill: color, width: barW, x: i * gap });\n\n if (dur > 0 && !rect.hasAttribute('data-init')) {\n rect.setAttribute('data-init', '1');\n setAttributes(rect, { height: 0, y: height });\n\n let start: number | null = null;\n const from = { h: 0, y: height };\n const to = { h: finalH, y: finalY };\n\n const frame = (ts: number) => {\n if (disposalSignal?.aborted) return;\n\n if (start === null) start = ts;\n\n const t = easing(Math.min(1, (ts - start) / dur));\n\n setAttributes(rect!, {\n height: tweenNumber(from.h, to.h, t),\n y: tweenNumber(from.y, to.y, t),\n });\n\n if (t < 1) requestAnimationFrame(frame);\n };\n\n requestAnimationFrame(frame);\n } else {\n rect.setAttribute('data-init', '1');\n setAttributes(rect, { height: finalH, y: finalY });\n }\n }\n}\n\nfunction isStackData(data: number[] | StackSegment[]): data is StackSegment[] {\n return data.length > 0 && data[0] !== null && typeof data[0] === 'object';\n}\n\nfunction buildRoundedStackRect(\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n roundLeft: boolean,\n roundRight: boolean,\n): string {\n const maxR = Math.min(r, w / 2, h / 2);\n const tl = roundLeft ? maxR : 0;\n const bl = roundLeft ? maxR : 0;\n const tr = roundRight ? maxR : 0;\n const br = roundRight ? maxR : 0;\n\n return [\n `M${x + tl},${y}`,\n `H${x + w - tr}`,\n tr ? `Q${x + w},${y} ${x + w},${y + tr}` : '',\n `V${y + h - br}`,\n br ? `Q${x + w},${y + h} ${x + w - br},${y + h}` : '',\n `H${x + bl}`,\n bl ? `Q${x},${y + h} ${x},${y + h - bl}` : '',\n `V${y + tl}`,\n tl ? `Q${x},${y} ${x + tl},${y}` : '',\n 'Z',\n ]\n .filter(Boolean)\n .join('');\n}\n\nfunction defaultStackColor(i: number): string {\n return `var(--prism-color-${(i % 8) + 1})`;\n}\n\nexport function createSparkline(container: HTMLElement, config: SparklineConfig): ChartHandle {\n const variant = config.variant ?? 'line';\n const color = config.color ?? 'var(--prism-color-1)';\n const curve = config.curve ?? 'linear';\n const strokeWidth = config.strokeWidth ?? 1.5;\n const fillOpacity = config.fillOpacity ?? 0.2;\n\n const base = createChartBase(container, {\n ...(config.a11y ? { a11y: config.a11y } : { ariaHidden: true }),\n margin: { bottom: 0, left: 0, right: 0, top: 0 },\n });\n\n const { svg } = base;\n\n svg.classList.add('prism-sparkline');\n\n const innerGroup = createSvgElement('g', { class: 'prism-spark-inner' });\n\n svg.appendChild(innerGroup);\n\n let cleanupInteraction: (() => void) | undefined;\n\n function renderAll(): void {\n const { height: h, width: w } = base.dimensions.value;\n const data = isReactive(config.data) ? config.data.value : config.data;\n\n while (innerGroup.firstChild) innerGroup.removeChild(innerGroup.firstChild);\n\n if (data.length === 0) return;\n\n if (variant === 'stack' && isStackData(data)) {\n const stackGroup = createSvgElement('g', { class: 'prism-spark-stack' });\n\n innerGroup.appendChild(stackGroup);\n\n const cornerRadius = config.cornerRadius ?? 4;\n const segs = data as StackSegment[];\n const total = segs.reduce((s, d) => s + Math.max(0, d.value), 0);\n\n if (total > 0) {\n const half = (config.padPixels ?? 0) / 2;\n let xAcc = 0;\n\n segs.forEach((seg, i) => {\n const xStart = Math.round(xAcc);\n\n xAcc += (Math.max(0, seg.value) / total) * w;\n\n const xEnd = i === segs.length - 1 ? w : Math.round(xAcc);\n const isFirst = i === 0;\n const isLast = i === segs.length - 1;\n const drawX = xStart + (isFirst ? 0 : half);\n const drawW = Math.max(0, xEnd - xStart - (isFirst ? 0 : half) - (isLast ? 0 : half));\n const d = buildRoundedStackRect(drawX, 0, drawW, h, cornerRadius, isFirst, isLast);\n const path = createSvgElement('path', { class: 'prism-spark-stack-segment' });\n\n setAttributes(path, { d, fill: seg.color ?? defaultStackColor(i) });\n stackGroup.appendChild(path);\n });\n }\n } else if (variant === 'bar') {\n const barsGroup = createSvgElement('g', { class: 'prism-spark-bars' });\n\n innerGroup.appendChild(barsGroup);\n renderSparkBars(barsGroup, data as number[], w, h, color, config.transition, ac.signal);\n } else {\n if (variant === 'area') {\n const fill = createSvgElement('path', { class: 'prism-spark-fill' });\n const fillD = buildAreaPath(data as number[], w, h, curve);\n\n setAttributes(fill, { d: fillD, fill: color, 'fill-opacity': fillOpacity, stroke: 'none' });\n innerGroup.appendChild(fill);\n }\n\n const path = createSvgElement('path', { class: 'prism-spark-line' });\n const pathD = buildPath(data as number[], w, h, curve);\n\n setAttributes(path, { d: pathD, fill: 'none', stroke: color, 'stroke-width': strokeWidth });\n innerGroup.appendChild(path);\n }\n\n if (!isStackData(data)) attachInteraction(data as number[]);\n }\n\n function attachInteraction(data: number[]): void {\n cleanupInteraction?.();\n cleanupInteraction = undefined;\n\n if (!config.onHover && !config.onClick) return;\n\n if (data.length <= 1) return;\n\n const { width: w } = base.dimensions.value;\n\n svg.style.cursor = 'crosshair';\n\n const xStep = w / (data.length - 1);\n\n const handleMove = (e: MouseEvent) => {\n const rect = svg.getBoundingClientRect();\n const relX = e.clientX - rect.left;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(relX / xStep)));\n\n config.onHover?.(idx, data[idx]);\n };\n\n const handleLeave = () => config.onHover?.(null, null);\n\n const handleClick = (e: MouseEvent) => {\n if (!config.onClick) return;\n\n const rect = svg.getBoundingClientRect();\n const relX = e.clientX - rect.left;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(relX / xStep)));\n\n config.onClick(idx, data[idx]);\n };\n\n svg.addEventListener('mousemove', handleMove);\n svg.addEventListener('mouseleave', handleLeave);\n svg.addEventListener('click', handleClick);\n\n cleanupInteraction = () => {\n svg.removeEventListener('mousemove', handleMove);\n svg.removeEventListener('mouseleave', handleLeave);\n svg.removeEventListener('click', handleClick);\n };\n }\n\n const ac = new AbortController();\n\n const scope = createScope();\n\n scope.run(() => {\n effect(\n () => {\n renderAll();\n },\n { scheduler: 'microtask' },\n );\n });\n\n let isDisposed = false;\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n ac.abort();\n cleanupInteraction?.();\n scope.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n el: svg,\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sparkline.js","names":[],"sources":["../../../src/charts/sparkline/sparkline.ts"],"sourcesContent":["import { createScope, effect } from '@vielzeug/ripple';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport { createChartBase } from '../../core/chart-base';\nimport { resolveMaybeSignal } from '../../core/resolve';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { areaPath, linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ChartHandle, SparklineConfig, StackSegment } from '../../types';\n\nfunction buildTopPoints(data: number[], width: number, height: number): Point[] {\n if (data.length === 0) return [];\n\n const xStep = width / Math.max(1, data.length - 1);\n const min = Math.min(...data);\n const max = Math.max(...data);\n const yRange = max - min || 1;\n\n return data.map((v, i) => ({\n x: i * xStep,\n y: height - ((v - min) / yRange) * height,\n }));\n}\n\nfunction buildAreaPath(\n data: number[],\n width: number,\n height: number,\n curve: SparklineConfig['curve'] = 'linear',\n): string {\n if (data.length === 0) return '';\n\n const top = buildTopPoints(data, width, height);\n const bottom = top.map((p) => ({ x: p.x, y: height }));\n\n return areaPath(top, bottom, curve ?? 'linear');\n}\n\nfunction buildPath(data: number[], width: number, height: number, curve: SparklineConfig['curve']): string {\n if (data.length === 0) return '';\n\n const points = buildTopPoints(data, width, height);\n\n return curve === 'monotone' ? monotonePath(points) : curve === 'step' ? stepPath(points) : linePath(points);\n}\n\nfunction renderSparkBars(\n parent: SVGGElement,\n data: number[],\n width: number,\n height: number,\n color: string,\n transition?: SparklineConfig['transition'],\n disposalSignal?: AbortSignal,\n): void {\n const count = data.length;\n const barW = Math.max(1, width / count - 1);\n const gap = width / count;\n const min = Math.min(0, ...data);\n const max = Math.max(...data);\n const yRange = max - min || 1;\n const motion = resolveMotion(transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n while (parent.children.length > count) {\n const last = parent.lastElementChild;\n\n if (last) parent.removeChild(last);\n }\n\n for (let i = 0; i < count; i++) {\n const finalH = Math.max(1, ((data[i] - min) / yRange) * height);\n const finalY = height - finalH;\n\n let rect = parent.children[i] as SVGRectElement | undefined;\n\n if (!rect) {\n rect = createSvgElement('rect', { class: 'prism-spark-bar' });\n parent.appendChild(rect);\n }\n\n setAttributes(rect, { fill: color, width: barW, x: i * gap });\n\n if (dur > 0 && !rect.hasAttribute('data-init')) {\n rect.setAttribute('data-init', '1');\n setAttributes(rect, { height: 0, y: height });\n\n let start: number | null = null;\n const from = { h: 0, y: height };\n const to = { h: finalH, y: finalY };\n\n const frame = (ts: number) => {\n if (disposalSignal?.aborted) return;\n\n if (start === null) start = ts;\n\n const t = easing(Math.min(1, (ts - start) / dur));\n\n setAttributes(rect!, {\n height: tweenNumber(from.h, to.h, t),\n y: tweenNumber(from.y, to.y, t),\n });\n\n if (t < 1) requestAnimationFrame(frame);\n };\n\n requestAnimationFrame(frame);\n } else {\n rect.setAttribute('data-init', '1');\n setAttributes(rect, { height: finalH, y: finalY });\n }\n }\n}\n\nfunction isStackData(data: number[] | StackSegment[]): data is StackSegment[] {\n return data.length > 0 && data[0] !== null && typeof data[0] === 'object';\n}\n\nfunction buildRoundedStackRect(\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n roundLeft: boolean,\n roundRight: boolean,\n): string {\n const maxR = Math.min(r, w / 2, h / 2);\n const tl = roundLeft ? maxR : 0;\n const bl = roundLeft ? maxR : 0;\n const tr = roundRight ? maxR : 0;\n const br = roundRight ? maxR : 0;\n\n return [\n `M${x + tl},${y}`,\n `H${x + w - tr}`,\n tr ? `Q${x + w},${y} ${x + w},${y + tr}` : '',\n `V${y + h - br}`,\n br ? `Q${x + w},${y + h} ${x + w - br},${y + h}` : '',\n `H${x + bl}`,\n bl ? `Q${x},${y + h} ${x},${y + h - bl}` : '',\n `V${y + tl}`,\n tl ? `Q${x},${y} ${x + tl},${y}` : '',\n 'Z',\n ]\n .filter(Boolean)\n .join('');\n}\n\nfunction defaultStackColor(i: number): string {\n return `var(--prism-color-${(i % 8) + 1})`;\n}\n\nexport function createSparkline(container: HTMLElement, config: SparklineConfig): ChartHandle {\n const variant = config.variant ?? 'line';\n const color = config.color ?? 'var(--prism-color-1)';\n const curve = config.curve ?? 'linear';\n const strokeWidth = config.strokeWidth ?? 1.5;\n const fillOpacity = config.fillOpacity ?? 0.2;\n const dataSignal = resolveMaybeSignal(config.data);\n\n const base = createChartBase(container, {\n ...(config.a11y ? { a11y: config.a11y } : { ariaHidden: true }),\n margin: { bottom: 0, left: 0, right: 0, top: 0 },\n });\n\n const { svg } = base;\n\n svg.classList.add('prism-sparkline');\n\n const innerGroup = createSvgElement('g', { class: 'prism-spark-inner' });\n\n svg.appendChild(innerGroup);\n\n let cleanupInteraction: (() => void) | undefined;\n\n function renderAll(): void {\n const { height: h, width: w } = base.dimensions.value;\n const data = dataSignal.value;\n\n while (innerGroup.firstChild) innerGroup.removeChild(innerGroup.firstChild);\n\n if (data.length === 0) return;\n\n if (variant === 'stack' && isStackData(data)) {\n const stackGroup = createSvgElement('g', { class: 'prism-spark-stack' });\n\n innerGroup.appendChild(stackGroup);\n\n const cornerRadius = config.cornerRadius ?? 4;\n const segs = data as StackSegment[];\n const total = segs.reduce((s, d) => s + Math.max(0, d.value), 0);\n\n if (total > 0) {\n const half = (config.padPixels ?? 0) / 2;\n let xAcc = 0;\n\n segs.forEach((seg, i) => {\n const xStart = Math.round(xAcc);\n\n xAcc += (Math.max(0, seg.value) / total) * w;\n\n const xEnd = i === segs.length - 1 ? w : Math.round(xAcc);\n const isFirst = i === 0;\n const isLast = i === segs.length - 1;\n const drawX = xStart + (isFirst ? 0 : half);\n const drawW = Math.max(0, xEnd - xStart - (isFirst ? 0 : half) - (isLast ? 0 : half));\n const d = buildRoundedStackRect(drawX, 0, drawW, h, cornerRadius, isFirst, isLast);\n const path = createSvgElement('path', { class: 'prism-spark-stack-segment' });\n\n setAttributes(path, { d, fill: seg.color ?? defaultStackColor(i) });\n stackGroup.appendChild(path);\n });\n }\n } else if (variant === 'bar') {\n const barsGroup = createSvgElement('g', { class: 'prism-spark-bars' });\n\n innerGroup.appendChild(barsGroup);\n renderSparkBars(barsGroup, data as number[], w, h, color, config.transition, ac.signal);\n } else {\n if (variant === 'area') {\n const fill = createSvgElement('path', { class: 'prism-spark-fill' });\n const fillD = buildAreaPath(data as number[], w, h, curve);\n\n setAttributes(fill, { d: fillD, fill: color, 'fill-opacity': fillOpacity, stroke: 'none' });\n innerGroup.appendChild(fill);\n }\n\n const path = createSvgElement('path', { class: 'prism-spark-line' });\n const pathD = buildPath(data as number[], w, h, curve);\n\n setAttributes(path, { d: pathD, fill: 'none', stroke: color, 'stroke-width': strokeWidth });\n innerGroup.appendChild(path);\n }\n\n if (!isStackData(data)) attachInteraction(data as number[]);\n }\n\n function attachInteraction(data: number[]): void {\n cleanupInteraction?.();\n cleanupInteraction = undefined;\n\n if (!config.onHover && !config.onClick) return;\n\n if (data.length <= 1) return;\n\n const { width: w } = base.dimensions.value;\n\n svg.style.cursor = 'crosshair';\n\n const xStep = w / (data.length - 1);\n\n const handleMove = (e: MouseEvent) => {\n const rect = svg.getBoundingClientRect();\n const relX = e.clientX - rect.left;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(relX / xStep)));\n\n config.onHover?.(idx, data[idx]);\n };\n\n const handleLeave = () => config.onHover?.(null, null);\n\n const handleClick = (e: MouseEvent) => {\n if (!config.onClick) return;\n\n const rect = svg.getBoundingClientRect();\n const relX = e.clientX - rect.left;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(relX / xStep)));\n\n config.onClick(idx, data[idx]);\n };\n\n svg.addEventListener('mousemove', handleMove);\n svg.addEventListener('mouseleave', handleLeave);\n svg.addEventListener('click', handleClick);\n\n cleanupInteraction = () => {\n svg.removeEventListener('mousemove', handleMove);\n svg.removeEventListener('mouseleave', handleLeave);\n svg.removeEventListener('click', handleClick);\n };\n }\n\n const ac = new AbortController();\n\n const scope = createScope();\n\n let isDisposed = false;\n\n try {\n scope.run(() => {\n effect(\n () => {\n renderAll();\n },\n { scheduler: 'microtask' },\n );\n });\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n ac.abort();\n cleanupInteraction?.();\n scope.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n el: svg,\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n } catch (error) {\n ac.abort();\n scope.dispose();\n base.dispose();\n throw error;\n }\n}\n"],"mappings":"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"}
@@ -3,5 +3,6 @@ export { createChartBase } from './chart-base';
3
3
  export type { ChartEventHandlers, RadialScaffoldContext, ScaffoldContext, ScaffoldGroups } from './chart-scaffold';
4
4
  export { createChartScaffold, createRadialScaffold } from './chart-scaffold';
5
5
  export { chartArea, resolveMargin } from './layout';
6
+ export { resolveMaybeSignal } from './resolve';
6
7
  export { observeResize } from './responsive';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACnH,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACnH,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ let e=require("@vielzeug/ripple");function t(t){return(0,e.isReactive)(t)?t:{peek:()=>t,subscribe:()=>()=>{},get value(){return t}}}exports.resolveMaybeSignal=t;
2
+ //# sourceMappingURL=resolve.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.cjs","names":[],"sources":["../../src/core/resolve.ts"],"sourcesContent":["import { isReactive, type Readable } from '@vielzeug/ripple';\nimport type { MaybeSignal } from '../types';\n\n/**\n * Normalizes a `MaybeSignal<T>` into a `Readable<T>`. Plain values are wrapped\n * in a constant readable so chart factories can `.value`/`.peek` uniformly and\n * drop repeated `isReactive()` checks per render.\n */\nexport function resolveMaybeSignal<T>(value: MaybeSignal<T>): Readable<T> {\n return isReactive(value)\n ? value\n : {\n peek: () => value,\n subscribe: () => () => {},\n get value() {\n return value;\n },\n };\n}\n"],"mappings":"kCAQA,SAAgB,EAAsB,EAAoC,CACxE,OAAA,EAAO,EAAA,WAAA,CAAW,CAAK,EACnB,EACA,CACE,SAAY,EACZ,kBAAuB,CAAC,EACxB,IAAI,OAAQ,CACV,OAAO,CACT,CACF,CACN"}
@@ -0,0 +1,9 @@
1
+ import { type Readable } from '@vielzeug/ripple';
2
+ import type { MaybeSignal } from '../types';
3
+ /**
4
+ * Normalizes a `MaybeSignal<T>` into a `Readable<T>`. Plain values are wrapped
5
+ * in a constant readable so chart factories can `.value`/`.peek` uniformly and
6
+ * drop repeated `isReactive()` checks per render.
7
+ */
8
+ export declare function resolveMaybeSignal<T>(value: MaybeSignal<T>): Readable<T>;
9
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/core/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAUxE"}
@@ -0,0 +1,15 @@
1
+ import { isReactive as e } from "@vielzeug/ripple";
2
+ //#region src/core/resolve.ts
3
+ function t(t) {
4
+ return e(t) ? t : {
5
+ peek: () => t,
6
+ subscribe: () => () => {},
7
+ get value() {
8
+ return t;
9
+ }
10
+ };
11
+ }
12
+ //#endregion
13
+ export { t as resolveMaybeSignal };
14
+
15
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","names":[],"sources":["../../src/core/resolve.ts"],"sourcesContent":["import { isReactive, type Readable } from '@vielzeug/ripple';\nimport type { MaybeSignal } from '../types';\n\n/**\n * Normalizes a `MaybeSignal<T>` into a `Readable<T>`. Plain values are wrapped\n * in a constant readable so chart factories can `.value`/`.peek` uniformly and\n * drop repeated `isReactive()` checks per render.\n */\nexport function resolveMaybeSignal<T>(value: MaybeSignal<T>): Readable<T> {\n return isReactive(value)\n ? value\n : {\n peek: () => value,\n subscribe: () => () => {},\n get value() {\n return value;\n },\n };\n}\n"],"mappings":";;AAQA,SAAgB,EAAsB,GAAoC;CACxE,OAAO,EAAW,CAAK,IACnB,IACA;EACE,YAAY;EACZ,uBAAuB,CAAC;EACxB,IAAI,QAAQ;GACV,OAAO;EACT;CACF;AACN"}
@@ -1,2 +1,2 @@
1
- const e=require("../core/layout.cjs"),t=require("../core/cartesian-model.cjs"),n=require("./events.cjs");function r(e,t,n){let r=null,i=1/0;for(let a=0;a<t.length;a++)for(let o=0;o<(t[a]?.length??0);o++){let s=e[a]?.[o],c=t[a]?.[o];if(!s||!c)continue;let l=Math.abs(c.x-n);l<i&&(i=l,r=s.key)}return r}function i(e,n,r,i){let a=t.keyId(r),o=null,s=1/0;for(let r=0;r<n.length;r++){let c=e[r]?.findIndex(e=>t.keyId(e.key)===a)??-1,l=c===-1?void 0:e[r]?.[c],u=c===-1?void 0:n[r]?.[c];if(!l||!u)continue;let d=Number.isFinite(i)?Math.abs(u.y-i):0;d<s&&(s=d,o={datum:l,point:u,seriesIndex:r})}return o}function a(a){let o=0;return{onClick:t=>{if(!a.onClick)return;let o=a.getPoints();if(o.length===0||o[0].length===0)return;let s=a.dims(),c=n.getMousePosition(a.svg,t,s.margin.left,s.margin.top),l=e.chartArea(s.width,s.height,s.margin);if(c.x<0||c.x>l.width||c.y<0||c.y>l.height)return;let u=r(a.getData(),o,c.x);if(u===null)return;let d=i(a.getData(),o,u,c.y),f=d?a.getSeriesList()[d.seriesIndex]:void 0;d&&f&&a.onClick({datum:d.datum,originalEvent:t,series:f})},onKeyDown:e=>{let n=a.getData(),r=a.getPoints(),s=[...new Map(n.flat().map(e=>[t.keyId(e.key),e.key])).values()];if(s.length!==0){if(e.key===`ArrowLeft`||e.key===`ArrowRight`){e.preventDefault(),o=Math.max(0,Math.min(s.length-1,o+(e.key===`ArrowLeft`?-1:1)));let t=s[o],c=i(n,r,t,1/0),l=c?a.getSeriesList()[c.seriesIndex]:void 0;if(!c||!l)return;a.crosshair?.show(c.point.x,c.point.y,a.dims().width,a.dims().height,`${l.name}: ${c.datum.value}`),a.tooltip?.show(c.point.x+a.dims().margin.left,c.point.y+a.dims().margin.top,c.datum,l),a.onHover?.({datum:c.datum,originalEvent:e,series:l})}if((e.key===`Enter`||e.key===` `)&&a.onClick){e.preventDefault();let t=s[o],c=i(n,r,t,1/0),l=c?a.getSeriesList()[c.seriesIndex]:void 0;c&&l&&a.onClick({datum:c.datum,originalEvent:e,series:l})}e.key===`Escape`&&(a.crosshair?.hide(),a.tooltip?.hide(),a.onHover?.(null))}},onMouseLeave:()=>{a.crosshair?.hide(),a.tooltip?.hide(),a.onHover?.(null)},onMouseMove:t=>{let o=a.getPoints();if(o.length===0||o[0].length===0)return;let s=a.dims(),c=n.getMousePosition(a.svg,t,s.margin.left,s.margin.top),l=e.chartArea(s.width,s.height,s.margin);if(c.x<0||c.x>l.width||c.y<0||c.y>l.height){a.crosshair?.hide(),a.tooltip?.hide();return}let u=r(a.getData(),o,c.x);if(u===null)return;let d=i(a.getData(),o,u,c.y),f=d?a.getSeriesList()[d.seriesIndex]:void 0,p=a.crosshair?.snap===!1?c.x:d?.point.x??c.x,m=a.crosshair?.snap===!1?c.y:d?.point.y??c.y;a.crosshair?.show(p,m,l.width,l.height,f&&d?`${f.name}: ${d.datum.value}`:void 0),d&&f&&(a.tooltip?.show(d.point.x+s.margin.left,d.point.y+s.margin.top,d.datum,f),a.onHover?.({datum:d.datum,originalEvent:t,series:f}))}}}exports.createSeriesInteraction=a;
1
+ const e=require("../core/layout.cjs"),t=require("../core/cartesian-model.cjs"),n=require("./events.cjs");function r(e,t,n){let r=null,i=1/0;for(let a=0;a<t.length;a++)for(let o=0;o<(t[a]?.length??0);o++){let s=e[a]?.[o],c=t[a]?.[o];if(!s||!c)continue;let l=Math.abs(c.x-n);l<i&&(i=l,r=s.key)}return r}function i(e,n,r,i){let a=t.keyId(r),o=null,s=1/0;for(let r=0;r<n.length;r++){let c=e[r]?.findIndex(e=>t.keyId(e.key)===a)??-1,l=c===-1?void 0:e[r]?.[c],u=c===-1?void 0:n[r]?.[c];if(!l||!u)continue;let d=Number.isFinite(i)?Math.abs(u.y-i):0;d<s&&(s=d,o={datum:l,point:u,seriesIndex:r})}return o}function a(a){let o=0;return{onClick:t=>{if(!a.onClick)return;let o=a.getPoints();if(o.length===0||o[0].length===0)return;let s=a.dims(),c=n.getMousePosition(a.svg,t,s.margin.left,s.margin.top),l=e.chartArea(s.width,s.height,s.margin);if(c.x<0||c.x>l.width||c.y<0||c.y>l.height)return;let u=r(a.getData(),o,c.x);if(u===null)return;let d=i(a.getData(),o,u,c.y),f=d?a.getSeriesList()[d.seriesIndex]:void 0;d&&f&&a.onClick({datum:d.datum,originalEvent:t,series:f})},onKeyDown:e=>{let n=a.getData(),r=a.getPoints(),s=[...new Map(n.flat().map(e=>[t.keyId(e.key),e.key])).values()];if(s.length!==0){if(e.key===`ArrowLeft`||e.key===`ArrowRight`){e.preventDefault(),o=Math.max(0,Math.min(s.length-1,o+(e.key===`ArrowLeft`?-1:1)));let t=s[o],c=i(n,r,t,1/0),l=c?a.getSeriesList()[c.seriesIndex]:void 0;if(!c||!l)return;let u=a.tooltip?void 0:`${l.name}: ${c.datum.value}`;a.crosshair?.show(c.point.x,c.point.y,a.dims().width,a.dims().height,u),a.tooltip?.show(c.point.x+a.dims().margin.left,c.point.y+a.dims().margin.top,c.datum,l),a.onHover?.({datum:c.datum,originalEvent:e,series:l})}if((e.key===`Enter`||e.key===` `)&&a.onClick){e.preventDefault();let t=s[o],c=i(n,r,t,1/0),l=c?a.getSeriesList()[c.seriesIndex]:void 0;c&&l&&a.onClick({datum:c.datum,originalEvent:e,series:l})}e.key===`Escape`&&(a.crosshair?.hide(),a.tooltip?.hide(),a.onHover?.(null))}},onMouseLeave:()=>{a.crosshair?.hide(),a.tooltip?.hide(),a.onHover?.(null)},onMouseMove:t=>{let o=a.getPoints();if(o.length===0||o[0].length===0)return;let s=a.dims(),c=n.getMousePosition(a.svg,t,s.margin.left,s.margin.top),l=e.chartArea(s.width,s.height,s.margin);if(c.x<0||c.x>l.width||c.y<0||c.y>l.height){a.crosshair?.hide(),a.tooltip?.hide();return}let u=r(a.getData(),o,c.x);if(u===null)return;let d=i(a.getData(),o,u,c.y),f=d?a.getSeriesList()[d.seriesIndex]:void 0,p=a.crosshair?.snap===!1?c.x:d?.point.x??c.x,m=a.crosshair?.snap===!1?c.y:d?.point.y??c.y,h=!a.tooltip&&f&&d?`${f.name}: ${d.datum.value}`:void 0;a.crosshair?.show(p,m,l.width,l.height,h),d&&f&&(a.tooltip?.show(d.point.x+s.margin.left,d.point.y+s.margin.top,d.datum,f),a.onHover?.({datum:d.datum,originalEvent:t,series:f}))}}}exports.createSeriesInteraction=a;
2
2
  //# sourceMappingURL=series-interaction.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"series-interaction.cjs","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import { keyId } from '../core/cartesian-model';\nimport type { ChartEventHandlers } from '../core/chart-scaffold';\nimport { chartArea } from '../core/layout';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series } from '../types';\nimport type { CrosshairState } from './crosshair';\nimport { getMousePosition } from './events';\nimport type { TooltipState } from './tooltip';\n\nexport interface SeriesInteractionOptions {\n crosshair?: CrosshairState | null;\n dims: () => ChartDimensions;\n getData: () => Datum[][];\n getPoints: () => Point[][];\n getSeriesList: () => Series[];\n onClick?: ((event: ChartEvent) => void) | undefined;\n onHover?: ((event: ChartEvent | null) => void) | undefined;\n svg: SVGSVGElement;\n tooltip?: TooltipState | null;\n}\n\ntype SeriesPoint = { datum: Datum; point: Point; seriesIndex: number };\n\nfunction findNearestKey(allData: Datum[][], allPoints: Point[][], posX: number): Datum['key'] | null {\n let nearest: Datum['key'] | null = null;\n let minXDistance = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n for (let datumIndex = 0; datumIndex < (allPoints[seriesIndex]?.length ?? 0); datumIndex++) {\n const datum = allData[seriesIndex]?.[datumIndex];\n const point = allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Math.abs(point.x - posX);\n\n if (distance < minXDistance) {\n minXDistance = distance;\n nearest = datum.key;\n }\n }\n }\n\n return nearest;\n}\n\nfunction findNearestSeries(\n allData: Datum[][],\n allPoints: Point[][],\n key: Datum['key'],\n posY: number,\n): SeriesPoint | null {\n const id = keyId(key);\n let nearest: { datum: Datum; point: Point; seriesIndex: number } | null = null;\n let minYDist = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n const datumIndex = allData[seriesIndex]?.findIndex((datum) => keyId(datum.key) === id) ?? -1;\n const datum = datumIndex === -1 ? undefined : allData[seriesIndex]?.[datumIndex];\n const point = datumIndex === -1 ? undefined : allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Number.isFinite(posY) ? Math.abs(point.y - posY) : 0;\n\n if (distance < minYDist) {\n minYDist = distance;\n nearest = { datum, point, seriesIndex };\n }\n }\n\n return nearest;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\n let keyboardIndex = 0;\n\n const onMouseMove = (event: MouseEvent) => {\n const allPoints = opts.getPoints();\n\n if (allPoints.length === 0 || allPoints[0].length === 0) return;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n\n return;\n }\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n if (key === null) return;\n\n const nearest = findNearestSeries(opts.getData(), allPoints, key, pos.y);\n const series = nearest ? opts.getSeriesList()[nearest.seriesIndex] : undefined;\n const crosshairX = opts.crosshair?.snap === false ? pos.x : (nearest?.point.x ?? pos.x);\n const crosshairY = opts.crosshair?.snap === false ? pos.y : (nearest?.point.y ?? pos.y);\n\n opts.crosshair?.show(\n crosshairX,\n crosshairY,\n area.width,\n area.height,\n series && nearest ? `${series.name}: ${nearest.datum.value}` : undefined,\n );\n\n if (nearest && series) {\n opts.tooltip?.show(nearest.point.x + dims.margin.left, nearest.point.y + dims.margin.top, nearest.datum, series);\n opts.onHover?.({ datum: nearest.datum, originalEvent: event, series });\n }\n };\n\n const onMouseLeave = () => {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.onHover?.(null);\n };\n\n const onClick = (event: MouseEvent) => {\n if (!opts.onClick) return;\n\n const allPoints = opts.getPoints();\n\n if (allPoints.length === 0 || allPoints[0].length === 0) return;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) return;\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n if (key === null) return;\n\n const nearest = findNearestSeries(opts.getData(), allPoints, key, pos.y);\n const series = nearest ? opts.getSeriesList()[nearest.seriesIndex] : undefined;\n\n if (nearest && series) {\n opts.onClick({ datum: nearest.datum, originalEvent: event, series });\n }\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n const allData = opts.getData();\n const allPoints = opts.getPoints();\n const domain = [...new Map(allData.flat().map((datum) => [keyId(datum.key), datum.key])).values()];\n\n if (domain.length === 0) return;\n\n if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {\n event.preventDefault();\n keyboardIndex = Math.max(0, Math.min(domain.length - 1, keyboardIndex + (event.key === 'ArrowLeft' ? -1 : 1)));\n\n const key = domain[keyboardIndex]!;\n const candidate = findNearestSeries(allData, allPoints, key, Number.POSITIVE_INFINITY);\n const series = candidate ? opts.getSeriesList()[candidate.seriesIndex] : undefined;\n\n if (!candidate || !series) return;\n\n opts.crosshair?.show(\n candidate.point.x,\n candidate.point.y,\n opts.dims().width,\n opts.dims().height,\n `${series.name}: ${candidate.datum.value}`,\n );\n opts.tooltip?.show(\n candidate.point.x + opts.dims().margin.left,\n candidate.point.y + opts.dims().margin.top,\n candidate.datum,\n series,\n );\n opts.onHover?.({ datum: candidate.datum, originalEvent: event, series });\n }\n\n if ((event.key === 'Enter' || event.key === ' ') && opts.onClick) {\n event.preventDefault();\n\n const key = domain[keyboardIndex]!;\n const candidate = findNearestSeries(allData, allPoints, key, Number.POSITIVE_INFINITY);\n const series = candidate ? opts.getSeriesList()[candidate.seriesIndex] : undefined;\n\n if (candidate && series) opts.onClick({ datum: candidate.datum, originalEvent: event, series });\n }\n\n if (event.key === 'Escape') {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.onHover?.(null);\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave, onMouseMove };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"series-interaction.cjs","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import { keyId } from '../core/cartesian-model';\nimport type { ChartEventHandlers } from '../core/chart-scaffold';\nimport { chartArea } from '../core/layout';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series } from '../types';\nimport type { CrosshairState } from './crosshair';\nimport { getMousePosition } from './events';\nimport type { TooltipState } from './tooltip';\n\nexport interface SeriesInteractionOptions {\n crosshair?: CrosshairState | null;\n dims: () => ChartDimensions;\n getData: () => Datum[][];\n getPoints: () => Point[][];\n getSeriesList: () => Series[];\n onClick?: ((event: ChartEvent) => void) | undefined;\n onHover?: ((event: ChartEvent | null) => void) | undefined;\n svg: SVGSVGElement;\n tooltip?: TooltipState | null;\n}\n\ntype SeriesPoint = { datum: Datum; point: Point; seriesIndex: number };\n\nfunction findNearestKey(allData: Datum[][], allPoints: Point[][], posX: number): Datum['key'] | null {\n let nearest: Datum['key'] | null = null;\n let minXDistance = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n for (let datumIndex = 0; datumIndex < (allPoints[seriesIndex]?.length ?? 0); datumIndex++) {\n const datum = allData[seriesIndex]?.[datumIndex];\n const point = allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Math.abs(point.x - posX);\n\n if (distance < minXDistance) {\n minXDistance = distance;\n nearest = datum.key;\n }\n }\n }\n\n return nearest;\n}\n\nfunction findNearestSeries(\n allData: Datum[][],\n allPoints: Point[][],\n key: Datum['key'],\n posY: number,\n): SeriesPoint | null {\n const id = keyId(key);\n let nearest: { datum: Datum; point: Point; seriesIndex: number } | null = null;\n let minYDist = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n const datumIndex = allData[seriesIndex]?.findIndex((datum) => keyId(datum.key) === id) ?? -1;\n const datum = datumIndex === -1 ? undefined : allData[seriesIndex]?.[datumIndex];\n const point = datumIndex === -1 ? undefined : allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Number.isFinite(posY) ? Math.abs(point.y - posY) : 0;\n\n if (distance < minYDist) {\n minYDist = distance;\n nearest = { datum, point, seriesIndex };\n }\n }\n\n return nearest;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\n let keyboardIndex = 0;\n\n const onMouseMove = (event: MouseEvent) => {\n const allPoints = opts.getPoints();\n\n if (allPoints.length === 0 || allPoints[0].length === 0) return;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n\n return;\n }\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n if (key === null) return;\n\n const nearest = findNearestSeries(opts.getData(), allPoints, key, pos.y);\n const series = nearest ? opts.getSeriesList()[nearest.seriesIndex] : undefined;\n const crosshairX = opts.crosshair?.snap === false ? pos.x : (nearest?.point.x ?? pos.x);\n const crosshairY = opts.crosshair?.snap === false ? pos.y : (nearest?.point.y ?? pos.y);\n\n // When a tooltip is present it already carries role=\"status\" + aria-live=\"polite\",\n // so the crosshair's own live region must stay silent to avoid double-announcing.\n const announceText = !opts.tooltip && series && nearest ? `${series.name}: ${nearest.datum.value}` : undefined;\n\n opts.crosshair?.show(crosshairX, crosshairY, area.width, area.height, announceText);\n\n if (nearest && series) {\n opts.tooltip?.show(nearest.point.x + dims.margin.left, nearest.point.y + dims.margin.top, nearest.datum, series);\n opts.onHover?.({ datum: nearest.datum, originalEvent: event, series });\n }\n };\n\n const onMouseLeave = () => {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.onHover?.(null);\n };\n\n const onClick = (event: MouseEvent) => {\n if (!opts.onClick) return;\n\n const allPoints = opts.getPoints();\n\n if (allPoints.length === 0 || allPoints[0].length === 0) return;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) return;\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n if (key === null) return;\n\n const nearest = findNearestSeries(opts.getData(), allPoints, key, pos.y);\n const series = nearest ? opts.getSeriesList()[nearest.seriesIndex] : undefined;\n\n if (nearest && series) {\n opts.onClick({ datum: nearest.datum, originalEvent: event, series });\n }\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n const allData = opts.getData();\n const allPoints = opts.getPoints();\n const domain = [...new Map(allData.flat().map((datum) => [keyId(datum.key), datum.key])).values()];\n\n if (domain.length === 0) return;\n\n if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {\n event.preventDefault();\n keyboardIndex = Math.max(0, Math.min(domain.length - 1, keyboardIndex + (event.key === 'ArrowLeft' ? -1 : 1)));\n\n const key = domain[keyboardIndex]!;\n const candidate = findNearestSeries(allData, allPoints, key, Number.POSITIVE_INFINITY);\n const series = candidate ? opts.getSeriesList()[candidate.seriesIndex] : undefined;\n\n if (!candidate || !series) return;\n\n // Same dedup as onMouseMove — tooltip announces when present.\n const announceText = !opts.tooltip ? `${series.name}: ${candidate.datum.value}` : undefined;\n\n opts.crosshair?.show(candidate.point.x, candidate.point.y, opts.dims().width, opts.dims().height, announceText);\n opts.tooltip?.show(\n candidate.point.x + opts.dims().margin.left,\n candidate.point.y + opts.dims().margin.top,\n candidate.datum,\n series,\n );\n opts.onHover?.({ datum: candidate.datum, originalEvent: event, series });\n }\n\n if ((event.key === 'Enter' || event.key === ' ') && opts.onClick) {\n event.preventDefault();\n\n const key = domain[keyboardIndex]!;\n const candidate = findNearestSeries(allData, allPoints, key, Number.POSITIVE_INFINITY);\n const series = candidate ? opts.getSeriesList()[candidate.seriesIndex] : undefined;\n\n if (candidate && series) opts.onClick({ datum: candidate.datum, originalEvent: event, series });\n }\n\n if (event.key === 'Escape') {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.onHover?.(null);\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave, onMouseMove };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"series-interaction.d.ts","sourceRoot":"","sources":["../../src/interaction/series-interaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC,IAAI,EAAE,MAAM,eAAe,CAAC;IAC5B,OAAO,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;IAC3B,aAAa,EAAE,MAAM,MAAM,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC/B;AAuDD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG,kBAAkB,CA4H1F"}
1
+ {"version":3,"file":"series-interaction.d.ts","sourceRoot":"","sources":["../../src/interaction/series-interaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC,IAAI,EAAE,MAAM,eAAe,CAAC;IAC5B,OAAO,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;IAC3B,aAAa,EAAE,MAAM,MAAM,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC/B;AAuDD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG,kBAAkB,CAuH1F"}
@@ -51,7 +51,8 @@ function a(a) {
51
51
  e.preventDefault(), o = Math.max(0, Math.min(s.length - 1, o + (e.key === "ArrowLeft" ? -1 : 1)));
52
52
  let t = s[o], c = i(n, r, t, Infinity), l = c ? a.getSeriesList()[c.seriesIndex] : void 0;
53
53
  if (!c || !l) return;
54
- a.crosshair?.show(c.point.x, c.point.y, a.dims().width, a.dims().height, `${l.name}: ${c.datum.value}`), a.tooltip?.show(c.point.x + a.dims().margin.left, c.point.y + a.dims().margin.top, c.datum, l), a.onHover?.({
54
+ let u = a.tooltip ? void 0 : `${l.name}: ${c.datum.value}`;
55
+ a.crosshair?.show(c.point.x, c.point.y, a.dims().width, a.dims().height, u), a.tooltip?.show(c.point.x + a.dims().margin.left, c.point.y + a.dims().margin.top, c.datum, l), a.onHover?.({
55
56
  datum: c.datum,
56
57
  originalEvent: e,
57
58
  series: l
@@ -82,8 +83,8 @@ function a(a) {
82
83
  }
83
84
  let u = r(a.getData(), o, c.x);
84
85
  if (u === null) return;
85
- let d = i(a.getData(), o, u, c.y), f = d ? a.getSeriesList()[d.seriesIndex] : void 0, p = a.crosshair?.snap === !1 ? c.x : d?.point.x ?? c.x, m = a.crosshair?.snap === !1 ? c.y : d?.point.y ?? c.y;
86
- a.crosshair?.show(p, m, l.width, l.height, f && d ? `${f.name}: ${d.datum.value}` : void 0), d && f && (a.tooltip?.show(d.point.x + s.margin.left, d.point.y + s.margin.top, d.datum, f), a.onHover?.({
86
+ let d = i(a.getData(), o, u, c.y), f = d ? a.getSeriesList()[d.seriesIndex] : void 0, p = a.crosshair?.snap === !1 ? c.x : d?.point.x ?? c.x, m = a.crosshair?.snap === !1 ? c.y : d?.point.y ?? c.y, h = !a.tooltip && f && d ? `${f.name}: ${d.datum.value}` : void 0;
87
+ a.crosshair?.show(p, m, l.width, l.height, h), d && f && (a.tooltip?.show(d.point.x + s.margin.left, d.point.y + s.margin.top, d.datum, f), a.onHover?.({
87
88
  datum: d.datum,
88
89
  originalEvent: t,
89
90
  series: f
@@ -1 +1 @@
1
- {"version":3,"file":"series-interaction.js","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import { keyId } from '../core/cartesian-model';\nimport type { ChartEventHandlers } from '../core/chart-scaffold';\nimport { chartArea } from '../core/layout';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series } from '../types';\nimport type { CrosshairState } from './crosshair';\nimport { getMousePosition } from './events';\nimport type { TooltipState } from './tooltip';\n\nexport interface SeriesInteractionOptions {\n crosshair?: CrosshairState | null;\n dims: () => ChartDimensions;\n getData: () => Datum[][];\n getPoints: () => Point[][];\n getSeriesList: () => Series[];\n onClick?: ((event: ChartEvent) => void) | undefined;\n onHover?: ((event: ChartEvent | null) => void) | undefined;\n svg: SVGSVGElement;\n tooltip?: TooltipState | null;\n}\n\ntype SeriesPoint = { datum: Datum; point: Point; seriesIndex: number };\n\nfunction findNearestKey(allData: Datum[][], allPoints: Point[][], posX: number): Datum['key'] | null {\n let nearest: Datum['key'] | null = null;\n let minXDistance = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n for (let datumIndex = 0; datumIndex < (allPoints[seriesIndex]?.length ?? 0); datumIndex++) {\n const datum = allData[seriesIndex]?.[datumIndex];\n const point = allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Math.abs(point.x - posX);\n\n if (distance < minXDistance) {\n minXDistance = distance;\n nearest = datum.key;\n }\n }\n }\n\n return nearest;\n}\n\nfunction findNearestSeries(\n allData: Datum[][],\n allPoints: Point[][],\n key: Datum['key'],\n posY: number,\n): SeriesPoint | null {\n const id = keyId(key);\n let nearest: { datum: Datum; point: Point; seriesIndex: number } | null = null;\n let minYDist = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n const datumIndex = allData[seriesIndex]?.findIndex((datum) => keyId(datum.key) === id) ?? -1;\n const datum = datumIndex === -1 ? undefined : allData[seriesIndex]?.[datumIndex];\n const point = datumIndex === -1 ? undefined : allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Number.isFinite(posY) ? Math.abs(point.y - posY) : 0;\n\n if (distance < minYDist) {\n minYDist = distance;\n nearest = { datum, point, seriesIndex };\n }\n }\n\n return nearest;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\n let keyboardIndex = 0;\n\n const onMouseMove = (event: MouseEvent) => {\n const allPoints = opts.getPoints();\n\n if (allPoints.length === 0 || allPoints[0].length === 0) return;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n\n return;\n }\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n if (key === null) return;\n\n const nearest = findNearestSeries(opts.getData(), allPoints, key, pos.y);\n const series = nearest ? opts.getSeriesList()[nearest.seriesIndex] : undefined;\n const crosshairX = opts.crosshair?.snap === false ? pos.x : (nearest?.point.x ?? pos.x);\n const crosshairY = opts.crosshair?.snap === false ? pos.y : (nearest?.point.y ?? pos.y);\n\n opts.crosshair?.show(\n crosshairX,\n crosshairY,\n area.width,\n area.height,\n series && nearest ? `${series.name}: ${nearest.datum.value}` : undefined,\n );\n\n if (nearest && series) {\n opts.tooltip?.show(nearest.point.x + dims.margin.left, nearest.point.y + dims.margin.top, nearest.datum, series);\n opts.onHover?.({ datum: nearest.datum, originalEvent: event, series });\n }\n };\n\n const onMouseLeave = () => {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.onHover?.(null);\n };\n\n const onClick = (event: MouseEvent) => {\n if (!opts.onClick) return;\n\n const allPoints = opts.getPoints();\n\n if (allPoints.length === 0 || allPoints[0].length === 0) return;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) return;\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n if (key === null) return;\n\n const nearest = findNearestSeries(opts.getData(), allPoints, key, pos.y);\n const series = nearest ? opts.getSeriesList()[nearest.seriesIndex] : undefined;\n\n if (nearest && series) {\n opts.onClick({ datum: nearest.datum, originalEvent: event, series });\n }\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n const allData = opts.getData();\n const allPoints = opts.getPoints();\n const domain = [...new Map(allData.flat().map((datum) => [keyId(datum.key), datum.key])).values()];\n\n if (domain.length === 0) return;\n\n if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {\n event.preventDefault();\n keyboardIndex = Math.max(0, Math.min(domain.length - 1, keyboardIndex + (event.key === 'ArrowLeft' ? -1 : 1)));\n\n const key = domain[keyboardIndex]!;\n const candidate = findNearestSeries(allData, allPoints, key, Number.POSITIVE_INFINITY);\n const series = candidate ? opts.getSeriesList()[candidate.seriesIndex] : undefined;\n\n if (!candidate || !series) return;\n\n opts.crosshair?.show(\n candidate.point.x,\n candidate.point.y,\n opts.dims().width,\n opts.dims().height,\n `${series.name}: ${candidate.datum.value}`,\n );\n opts.tooltip?.show(\n candidate.point.x + opts.dims().margin.left,\n candidate.point.y + opts.dims().margin.top,\n candidate.datum,\n series,\n );\n opts.onHover?.({ datum: candidate.datum, originalEvent: event, series });\n }\n\n if ((event.key === 'Enter' || event.key === ' ') && opts.onClick) {\n event.preventDefault();\n\n const key = domain[keyboardIndex]!;\n const candidate = findNearestSeries(allData, allPoints, key, Number.POSITIVE_INFINITY);\n const series = candidate ? opts.getSeriesList()[candidate.seriesIndex] : undefined;\n\n if (candidate && series) opts.onClick({ datum: candidate.datum, originalEvent: event, series });\n }\n\n if (event.key === 'Escape') {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.onHover?.(null);\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave, onMouseMove };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"series-interaction.js","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import { keyId } from '../core/cartesian-model';\nimport type { ChartEventHandlers } from '../core/chart-scaffold';\nimport { chartArea } from '../core/layout';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series } from '../types';\nimport type { CrosshairState } from './crosshair';\nimport { getMousePosition } from './events';\nimport type { TooltipState } from './tooltip';\n\nexport interface SeriesInteractionOptions {\n crosshair?: CrosshairState | null;\n dims: () => ChartDimensions;\n getData: () => Datum[][];\n getPoints: () => Point[][];\n getSeriesList: () => Series[];\n onClick?: ((event: ChartEvent) => void) | undefined;\n onHover?: ((event: ChartEvent | null) => void) | undefined;\n svg: SVGSVGElement;\n tooltip?: TooltipState | null;\n}\n\ntype SeriesPoint = { datum: Datum; point: Point; seriesIndex: number };\n\nfunction findNearestKey(allData: Datum[][], allPoints: Point[][], posX: number): Datum['key'] | null {\n let nearest: Datum['key'] | null = null;\n let minXDistance = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n for (let datumIndex = 0; datumIndex < (allPoints[seriesIndex]?.length ?? 0); datumIndex++) {\n const datum = allData[seriesIndex]?.[datumIndex];\n const point = allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Math.abs(point.x - posX);\n\n if (distance < minXDistance) {\n minXDistance = distance;\n nearest = datum.key;\n }\n }\n }\n\n return nearest;\n}\n\nfunction findNearestSeries(\n allData: Datum[][],\n allPoints: Point[][],\n key: Datum['key'],\n posY: number,\n): SeriesPoint | null {\n const id = keyId(key);\n let nearest: { datum: Datum; point: Point; seriesIndex: number } | null = null;\n let minYDist = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n const datumIndex = allData[seriesIndex]?.findIndex((datum) => keyId(datum.key) === id) ?? -1;\n const datum = datumIndex === -1 ? undefined : allData[seriesIndex]?.[datumIndex];\n const point = datumIndex === -1 ? undefined : allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Number.isFinite(posY) ? Math.abs(point.y - posY) : 0;\n\n if (distance < minYDist) {\n minYDist = distance;\n nearest = { datum, point, seriesIndex };\n }\n }\n\n return nearest;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\n let keyboardIndex = 0;\n\n const onMouseMove = (event: MouseEvent) => {\n const allPoints = opts.getPoints();\n\n if (allPoints.length === 0 || allPoints[0].length === 0) return;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n\n return;\n }\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n if (key === null) return;\n\n const nearest = findNearestSeries(opts.getData(), allPoints, key, pos.y);\n const series = nearest ? opts.getSeriesList()[nearest.seriesIndex] : undefined;\n const crosshairX = opts.crosshair?.snap === false ? pos.x : (nearest?.point.x ?? pos.x);\n const crosshairY = opts.crosshair?.snap === false ? pos.y : (nearest?.point.y ?? pos.y);\n\n // When a tooltip is present it already carries role=\"status\" + aria-live=\"polite\",\n // so the crosshair's own live region must stay silent to avoid double-announcing.\n const announceText = !opts.tooltip && series && nearest ? `${series.name}: ${nearest.datum.value}` : undefined;\n\n opts.crosshair?.show(crosshairX, crosshairY, area.width, area.height, announceText);\n\n if (nearest && series) {\n opts.tooltip?.show(nearest.point.x + dims.margin.left, nearest.point.y + dims.margin.top, nearest.datum, series);\n opts.onHover?.({ datum: nearest.datum, originalEvent: event, series });\n }\n };\n\n const onMouseLeave = () => {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.onHover?.(null);\n };\n\n const onClick = (event: MouseEvent) => {\n if (!opts.onClick) return;\n\n const allPoints = opts.getPoints();\n\n if (allPoints.length === 0 || allPoints[0].length === 0) return;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) return;\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n if (key === null) return;\n\n const nearest = findNearestSeries(opts.getData(), allPoints, key, pos.y);\n const series = nearest ? opts.getSeriesList()[nearest.seriesIndex] : undefined;\n\n if (nearest && series) {\n opts.onClick({ datum: nearest.datum, originalEvent: event, series });\n }\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n const allData = opts.getData();\n const allPoints = opts.getPoints();\n const domain = [...new Map(allData.flat().map((datum) => [keyId(datum.key), datum.key])).values()];\n\n if (domain.length === 0) return;\n\n if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {\n event.preventDefault();\n keyboardIndex = Math.max(0, Math.min(domain.length - 1, keyboardIndex + (event.key === 'ArrowLeft' ? -1 : 1)));\n\n const key = domain[keyboardIndex]!;\n const candidate = findNearestSeries(allData, allPoints, key, Number.POSITIVE_INFINITY);\n const series = candidate ? opts.getSeriesList()[candidate.seriesIndex] : undefined;\n\n if (!candidate || !series) return;\n\n // Same dedup as onMouseMove — tooltip announces when present.\n const announceText = !opts.tooltip ? `${series.name}: ${candidate.datum.value}` : undefined;\n\n opts.crosshair?.show(candidate.point.x, candidate.point.y, opts.dims().width, opts.dims().height, announceText);\n opts.tooltip?.show(\n candidate.point.x + opts.dims().margin.left,\n candidate.point.y + opts.dims().margin.top,\n candidate.datum,\n series,\n );\n opts.onHover?.({ datum: candidate.datum, originalEvent: event, series });\n }\n\n if ((event.key === 'Enter' || event.key === ' ') && opts.onClick) {\n event.preventDefault();\n\n const key = domain[keyboardIndex]!;\n const candidate = findNearestSeries(allData, allPoints, key, Number.POSITIVE_INFINITY);\n const series = candidate ? opts.getSeriesList()[candidate.seriesIndex] : undefined;\n\n if (candidate && series) opts.onClick({ datum: candidate.datum, originalEvent: event, series });\n }\n\n if (event.key === 'Escape') {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.onHover?.(null);\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave, onMouseMove };\n}\n"],"mappings":";;;;AAuBA,SAAS,EAAe,GAAoB,GAAsB,GAAmC;CACnG,IAAI,IAA+B,MAC/B,IAAe;CAEnB,KAAK,IAAI,IAAc,GAAG,IAAc,EAAU,QAAQ,KACxD,KAAK,IAAI,IAAa,GAAG,KAAc,EAAU,EAAY,EAAE,UAAU,IAAI,KAAc;EACzF,IAAM,IAAQ,EAAQ,EAAY,GAAG,IAC/B,IAAQ,EAAU,EAAY,GAAG;EAEvC,IAAI,CAAC,KAAS,CAAC,GAAO;EAEtB,IAAM,IAAW,KAAK,IAAI,EAAM,IAAI,CAAI;EAExC,AAAI,IAAW,MACb,IAAe,GACf,IAAU,EAAM;CAEpB;CAGF,OAAO;AACT;AAEA,SAAS,EACP,GACA,GACA,GACA,GACoB;CACpB,IAAM,IAAK,EAAM,CAAG,GAChB,IAAsE,MACtE,IAAW;CAEf,KAAK,IAAI,IAAc,GAAG,IAAc,EAAU,QAAQ,KAAe;EACvE,IAAM,IAAa,EAAQ,EAAY,EAAE,WAAW,MAAU,EAAM,EAAM,GAAG,MAAM,CAAE,KAAK,IACpF,IAAQ,MAAe,KAAK,KAAA,IAAY,EAAQ,EAAY,GAAG,IAC/D,IAAQ,MAAe,KAAK,KAAA,IAAY,EAAU,EAAY,GAAG;EAEvE,IAAI,CAAC,KAAS,CAAC,GAAO;EAEtB,IAAM,IAAW,OAAO,SAAS,CAAI,IAAI,KAAK,IAAI,EAAM,IAAI,CAAI,IAAI;EAEpE,AAAI,IAAW,MACb,IAAW,GACX,IAAU;GAAE;GAAO;GAAO;EAAY;CAE1C;CAEA,OAAO;AACT;AAEA,SAAgB,EAAwB,GAAoD;CAC1F,IAAI,IAAgB;CAqHpB,OAAO;EAAE,UAxEQ,MAAsB;GACrC,IAAI,CAAC,EAAK,SAAS;GAEnB,IAAM,IAAY,EAAK,UAAU;GAEjC,IAAI,EAAU,WAAW,KAAK,EAAU,EAAE,CAAC,WAAW,GAAG;GAEzD,IAAM,IAAO,EAAK,KAAK,GACjB,IAAM,EAAiB,EAAK,KAAK,GAAO,EAAK,OAAO,MAAM,EAAK,OAAO,GAAG,GACzE,IAAO,EAAU,EAAK,OAAO,EAAK,QAAQ,EAAK,MAAM;GAE3D,IAAI,EAAI,IAAI,KAAK,EAAI,IAAI,EAAK,SAAS,EAAI,IAAI,KAAK,EAAI,IAAI,EAAK,QAAQ;GAEzE,IAAM,IAAM,EAAe,EAAK,QAAQ,GAAG,GAAW,EAAI,CAAC;GAE3D,IAAI,MAAQ,MAAM;GAElB,IAAM,IAAU,EAAkB,EAAK,QAAQ,GAAG,GAAW,GAAK,EAAI,CAAC,GACjE,IAAS,IAAU,EAAK,cAAc,CAAC,CAAC,EAAQ,eAAe,KAAA;GAErE,AAAI,KAAW,KACb,EAAK,QAAQ;IAAE,OAAO,EAAQ;IAAO,eAAe;IAAO;GAAO,CAAC;EAEvE;EAiDkB,YA/CC,MAAyB;GAC1C,IAAM,IAAU,EAAK,QAAQ,GACvB,IAAY,EAAK,UAAU,GAC3B,IAAS,CAAC,GAAG,IAAI,IAAI,EAAQ,KAAK,CAAC,CAAC,KAAK,MAAU,CAAC,EAAM,EAAM,GAAG,GAAG,EAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;GAE7F,MAAO,WAAW,GAEtB;QAAI,EAAM,QAAQ,eAAe,EAAM,QAAQ,cAAc;KAE3D,AADA,EAAM,eAAe,GACrB,IAAgB,KAAK,IAAI,GAAG,KAAK,IAAI,EAAO,SAAS,GAAG,KAAiB,EAAM,QAAQ,cAAc,KAAK,EAAE,CAAC;KAE7G,IAAM,IAAM,EAAO,IACb,IAAY,EAAkB,GAAS,GAAW,GAAK,QAAwB,GAC/E,IAAS,IAAY,EAAK,cAAc,CAAC,CAAC,EAAU,eAAe,KAAA;KAEzE,IAAI,CAAC,KAAa,CAAC,GAAQ;KAG3B,IAAM,IAAgB,EAAK,UAAuD,KAAA,IAA7C,GAAG,EAAO,KAAK,IAAI,EAAU,MAAM;KASxE,AAPA,EAAK,WAAW,KAAK,EAAU,MAAM,GAAG,EAAU,MAAM,GAAG,EAAK,KAAK,CAAC,CAAC,OAAO,EAAK,KAAK,CAAC,CAAC,QAAQ,CAAY,GAC9G,EAAK,SAAS,KACZ,EAAU,MAAM,IAAI,EAAK,KAAK,CAAC,CAAC,OAAO,MACvC,EAAU,MAAM,IAAI,EAAK,KAAK,CAAC,CAAC,OAAO,KACvC,EAAU,OACV,CACF,GACA,EAAK,UAAU;MAAE,OAAO,EAAU;MAAO,eAAe;MAAO;KAAO,CAAC;IACzE;IAEA,KAAK,EAAM,QAAQ,WAAW,EAAM,QAAQ,QAAQ,EAAK,SAAS;KAChE,EAAM,eAAe;KAErB,IAAM,IAAM,EAAO,IACb,IAAY,EAAkB,GAAS,GAAW,GAAK,QAAwB,GAC/E,IAAS,IAAY,EAAK,cAAc,CAAC,CAAC,EAAU,eAAe,KAAA;KAEzE,AAAI,KAAa,KAAQ,EAAK,QAAQ;MAAE,OAAO,EAAU;MAAO,eAAe;MAAO;KAAO,CAAC;IAChG;IAEA,AAAI,EAAM,QAAQ,aAChB,EAAK,WAAW,KAAK,GACrB,EAAK,SAAS,KAAK,GACnB,EAAK,UAAU,IAAI;GAfrB;EAiBF;EAE6B,oBA9EF;GAGzB,AAFA,EAAK,WAAW,KAAK,GACrB,EAAK,SAAS,KAAK,GACnB,EAAK,UAAU,IAAI;EACrB;EA0E2C,cAnHtB,MAAsB;GACzC,IAAM,IAAY,EAAK,UAAU;GAEjC,IAAI,EAAU,WAAW,KAAK,EAAU,EAAE,CAAC,WAAW,GAAG;GAEzD,IAAM,IAAO,EAAK,KAAK,GACjB,IAAM,EAAiB,EAAK,KAAK,GAAO,EAAK,OAAO,MAAM,EAAK,OAAO,GAAG,GACzE,IAAO,EAAU,EAAK,OAAO,EAAK,QAAQ,EAAK,MAAM;GAE3D,IAAI,EAAI,IAAI,KAAK,EAAI,IAAI,EAAK,SAAS,EAAI,IAAI,KAAK,EAAI,IAAI,EAAK,QAAQ;IAEvE,AADA,EAAK,WAAW,KAAK,GACrB,EAAK,SAAS,KAAK;IAEnB;GACF;GAEA,IAAM,IAAM,EAAe,EAAK,QAAQ,GAAG,GAAW,EAAI,CAAC;GAE3D,IAAI,MAAQ,MAAM;GAElB,IAAM,IAAU,EAAkB,EAAK,QAAQ,GAAG,GAAW,GAAK,EAAI,CAAC,GACjE,IAAS,IAAU,EAAK,cAAc,CAAC,CAAC,EAAQ,eAAe,KAAA,GAC/D,IAAa,EAAK,WAAW,SAAS,KAAQ,EAAI,IAAK,GAAS,MAAM,KAAK,EAAI,GAC/E,IAAa,EAAK,WAAW,SAAS,KAAQ,EAAI,IAAK,GAAS,MAAM,KAAK,EAAI,GAI/E,IAAe,CAAC,EAAK,WAAW,KAAU,IAAU,GAAG,EAAO,KAAK,IAAI,EAAQ,MAAM,UAAU,KAAA;GAIrG,AAFA,EAAK,WAAW,KAAK,GAAY,GAAY,EAAK,OAAO,EAAK,QAAQ,CAAY,GAE9E,KAAW,MACb,EAAK,SAAS,KAAK,EAAQ,MAAM,IAAI,EAAK,OAAO,MAAM,EAAQ,MAAM,IAAI,EAAK,OAAO,KAAK,EAAQ,OAAO,CAAM,GAC/G,EAAK,UAAU;IAAE,OAAO,EAAQ;IAAO,eAAe;IAAO;GAAO,CAAC;EAEzE;CAgFuD;AACzD"}
@@ -1,2 +1,2 @@
1
- require("../_dev.cjs");let e=require("@vielzeug/orbit");function t(t,n){getComputedStyle(t).position===`static`&&(t.style.position=`relative`);let r=document.createElement(`div`);r.className=`prism-tooltip`,r.style.position=`absolute`,r.style.pointerEvents=`none`,r.style.top=`0`,r.style.left=`0`,r.setAttribute(`role`,`status`),r.setAttribute(`aria-live`,`polite`),t.appendChild(r);let i=n!==!0&&n?.offset||8,a=n===!0?void 0:n?.render,o=n===!0?void 0:n?.sanitize,s=null,c=null,l=!1,u=()=>{c!==null&&(clearTimeout(c),c=null)},d=()=>{s!==null&&(cancelAnimationFrame(s),s=null)},f=()=>{d(),u(),r.remove()};return{dispose:f,el:r,hide(){d(),u(),l=!1,r.style.opacity=`0`,c=setTimeout(()=>{c=null,l||(r.textContent=``)},150)},show(n,c,d,f){if(!t.isConnected)return;if(u(),a){let e=a(d,f);o?r.innerHTML=o(e):r.textContent=e}else r.textContent=`${f.name}: ${d.value}`;let{x:p,y:m}=(0,e.computePosition)({getBoundingClientRect:()=>{let e=t.getBoundingClientRect();return{bottom:e.top+c,height:0,left:e.left+n,right:e.left+n,top:e.top+c,width:0,x:e.left+n,y:e.top+c}}},r,{containingBlock:t,middleware:[(0,e.offset)(i),(0,e.flip)(),(0,e.shift)({padding:8})],placement:`top`});if(r.style.left=`${p}px`,r.style.top=`${m}px`,l){s===null&&(r.style.opacity=`1`);return}l=!0,r.style.opacity=`0`,s=requestAnimationFrame(()=>{s=null,l&&(r.style.opacity=`1`)})},[Symbol.dispose]:f}}exports.createTooltip=t;
1
+ require("../_dev.cjs");let e=require("@vielzeug/orbit");function t(t,n){getComputedStyle(t).position===`static`&&(t.style.position=`relative`);let r=t.ownerDocument.createElement(`div`);r.className=`prism-tooltip`,r.style.position=`absolute`,r.style.pointerEvents=`none`,r.style.top=`0`,r.style.left=`0`,r.setAttribute(`role`,`status`),r.setAttribute(`aria-live`,`polite`),t.appendChild(r);let i=n!==!0&&n?.offset||8,a=n===!0?void 0:n?.render,o=n===!0?void 0:n?.sanitize,s=null,c=null,l=!1,u=()=>{c!==null&&(clearTimeout(c),c=null)},d=()=>{s!==null&&(cancelAnimationFrame(s),s=null)},f=()=>{d(),u(),r.remove()};return{dispose:f,el:r,hide(){d(),u(),l=!1,r.style.opacity=`0`,c=setTimeout(()=>{c=null,l||(r.textContent=``)},150)},show(n,c,d,f){if(!t.isConnected)return;if(u(),a){let e=a(d,f);o?r.innerHTML=o(e):r.textContent=e}else r.textContent=`${f.name}: ${d.value}`;let{x:p,y:m}=(0,e.computePosition)({getBoundingClientRect:()=>{let e=t.getBoundingClientRect();return{bottom:e.top+c,height:0,left:e.left+n,right:e.left+n,top:e.top+c,width:0,x:e.left+n,y:e.top+c}}},r,{containingBlock:t,middleware:[(0,e.offset)(i),(0,e.flip)(),(0,e.shift)({padding:8})],placement:`top`});if(r.style.left=`${p}px`,r.style.top=`${m}px`,l){s===null&&(r.style.opacity=`1`);return}l=!0,r.style.opacity=`0`,s=requestAnimationFrame(()=>{s=null,l&&(r.style.opacity=`1`)})},[Symbol.dispose]:f}}exports.createTooltip=t;
2
2
  //# sourceMappingURL=tooltip.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.cjs","names":[],"sources":["../../src/interaction/tooltip.ts"],"sourcesContent":["import { computePosition, flip, offset, shift } from '@vielzeug/orbit';\nimport { warn } from '../_dev';\nimport type { Datum, Series, TooltipConfig } from '../types';\n\nexport interface TooltipState {\n dispose(): void;\n el: HTMLDivElement | null;\n hide(): void;\n show(x: number, y: number, datum: Datum, series: Series): void;\n [Symbol.dispose](): void;\n}\n\nexport function createTooltip(container: HTMLElement, config?: TooltipConfig | true): TooltipState {\n if (getComputedStyle(container).position === 'static') {\n container.style.position = 'relative';\n }\n\n const el = document.createElement('div');\n\n el.className = 'prism-tooltip';\n el.style.position = 'absolute';\n el.style.pointerEvents = 'none';\n el.style.top = '0';\n el.style.left = '0';\n // Non-modal status text — announced by assistive tech whenever content/hide state changes.\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n container.appendChild(el);\n\n const tooltipOffset: number = (config !== true && config?.offset) || 8;\n const render = config !== true ? config?.render : undefined;\n const sanitize = config !== true ? config?.sanitize : undefined;\n\n if (render && !sanitize) {\n warn(\n 'createTooltip: `render` is set without `sanitize` — falling back to plain-text rendering of the returned string to avoid an XSS risk. Pass `sanitize` to render HTML.',\n );\n }\n\n let revealFrame: number | null = null;\n let clearTimer: ReturnType<typeof setTimeout> | null = null;\n let visible = false;\n\n const cancelClear = (): void => {\n if (clearTimer === null) return;\n\n clearTimeout(clearTimer);\n clearTimer = null;\n };\n\n const cancelReveal = (): void => {\n if (revealFrame === null) return;\n\n cancelAnimationFrame(revealFrame);\n revealFrame = null;\n };\n\n const disposeHandle = (): void => {\n cancelReveal();\n cancelClear();\n el.remove();\n };\n\n return {\n dispose: disposeHandle,\n el,\n hide() {\n cancelReveal();\n cancelClear();\n visible = false;\n el.style.opacity = '0';\n clearTimer = setTimeout(() => {\n clearTimer = null;\n\n if (!visible) el.textContent = '';\n }, 150);\n },\n show(x: number, y: number, datum: Datum, series: Series) {\n if (!container.isConnected) return;\n\n cancelClear();\n\n if (render) {\n const html = render(datum, series);\n\n if (sanitize) {\n el.innerHTML = sanitize(html);\n } else {\n // No sanitizer provided — never inject the raw string as HTML. Render it as text instead.\n el.textContent = html;\n }\n } else {\n el.textContent = `${series.name}: ${datum.value}`;\n }\n\n const virtualRef = {\n getBoundingClientRect: () => {\n const rect = container.getBoundingClientRect();\n\n return {\n bottom: rect.top + y,\n height: 0,\n left: rect.left + x,\n right: rect.left + x,\n top: rect.top + y,\n width: 0,\n x: rect.left + x,\n y: rect.top + y,\n };\n },\n };\n\n const { x: positionX, y: positionY } = computePosition(virtualRef, el, {\n containingBlock: container,\n middleware: [offset(tooltipOffset), flip(), shift({ padding: 8 })],\n placement: 'top',\n });\n\n el.style.left = `${positionX}px`;\n el.style.top = `${positionY}px`;\n\n if (visible) {\n if (revealFrame === null) el.style.opacity = '1';\n\n return;\n }\n\n visible = true;\n el.style.opacity = '0';\n revealFrame = requestAnimationFrame(() => {\n revealFrame = null;\n\n if (visible) el.style.opacity = '1';\n });\n },\n [Symbol.dispose]: disposeHandle,\n };\n}\n"],"mappings":"wDAYA,SAAgB,EAAc,EAAwB,EAA6C,CAC7F,iBAAiB,CAAS,CAAC,CAAC,WAAa,WAC3C,EAAU,MAAM,SAAW,YAG7B,IAAM,EAAK,SAAS,cAAc,KAAK,EAEvC,EAAG,UAAY,gBACf,EAAG,MAAM,SAAW,WACpB,EAAG,MAAM,cAAgB,OACzB,EAAG,MAAM,IAAM,IACf,EAAG,MAAM,KAAO,IAEhB,EAAG,aAAa,OAAQ,QAAQ,EAChC,EAAG,aAAa,YAAa,QAAQ,EACrC,EAAU,YAAY,CAAE,EAExB,IAAM,EAAyB,IAAW,IAAQ,GAAQ,QAAW,EAC/D,EAAS,IAAW,GAAwB,IAAA,GAAjB,GAAQ,OACnC,EAAW,IAAW,GAA0B,IAAA,GAAnB,GAAQ,SAQvC,EAA6B,KAC7B,EAAmD,KACnD,EAAU,GAER,MAA0B,CAC1B,IAAe,OAEnB,aAAa,CAAU,EACvB,EAAa,KACf,EAEM,MAA2B,CAC3B,IAAgB,OAEpB,qBAAqB,CAAW,EAChC,EAAc,KAChB,EAEM,MAA4B,CAChC,EAAa,EACb,EAAY,EACZ,EAAG,OAAO,CACZ,EAEA,MAAO,CACL,QAAS,EACT,KACA,MAAO,CACL,EAAa,EACb,EAAY,EACZ,EAAU,GACV,EAAG,MAAM,QAAU,IACnB,EAAa,eAAiB,CAC5B,EAAa,KAER,IAAS,EAAG,YAAc,GACjC,EAAG,GAAG,CACR,EACA,KAAK,EAAW,EAAW,EAAc,EAAgB,CACvD,GAAI,CAAC,EAAU,YAAa,OAI5B,GAFA,EAAY,EAER,EAAQ,CACV,IAAM,EAAO,EAAO,EAAO,CAAM,EAE7B,EACF,EAAG,UAAY,EAAS,CAAI,EAG5B,EAAG,YAAc,CAErB,KACE,GAAG,YAAc,GAAG,EAAO,KAAK,IAAI,EAAM,QAoB5C,GAAM,CAAE,EAAG,EAAW,EAAG,IAAA,EAAc,EAAA,gBAAA,CAAgB,CAhBrD,0BAA6B,CAC3B,IAAM,EAAO,EAAU,sBAAsB,EAE7C,MAAO,CACL,OAAQ,EAAK,IAAM,EACnB,OAAQ,EACR,KAAM,EAAK,KAAO,EAClB,MAAO,EAAK,KAAO,EACnB,IAAK,EAAK,IAAM,EAChB,MAAO,EACP,EAAG,EAAK,KAAO,EACf,EAAG,EAAK,IAAM,CAChB,CACF,CAGqD,EAAY,EAAI,CACrE,gBAAiB,EACjB,WAAY,EAAC,EAAA,EAAA,OAAA,CAAO,CAAa,GAAG,EAAA,EAAA,KAAA,CAAK,GAAG,EAAA,EAAA,MAAA,CAAM,CAAE,QAAS,CAAE,CAAC,CAAC,EACjE,UAAW,KACb,CAAC,EAKD,GAHA,EAAG,MAAM,KAAO,GAAG,EAAU,IAC7B,EAAG,MAAM,IAAM,GAAG,EAAU,IAExB,EAAS,CACP,IAAgB,OAAM,EAAG,MAAM,QAAU,KAE7C,MACF,CAEA,EAAU,GACV,EAAG,MAAM,QAAU,IACnB,EAAc,0BAA4B,CACxC,EAAc,KAEV,IAAS,EAAG,MAAM,QAAU,IAClC,CAAC,CACH,GACC,OAAO,SAAU,CACpB,CACF"}
1
+ {"version":3,"file":"tooltip.cjs","names":[],"sources":["../../src/interaction/tooltip.ts"],"sourcesContent":["import { computePosition, flip, offset, shift } from '@vielzeug/orbit';\nimport { warn } from '../_dev';\nimport type { Datum, Series, TooltipConfig } from '../types';\n\nexport interface TooltipState {\n dispose(): void;\n el: HTMLDivElement | null;\n hide(): void;\n show(x: number, y: number, datum: Datum, series: Series): void;\n [Symbol.dispose](): void;\n}\n\nexport function createTooltip(container: HTMLElement, config?: TooltipConfig | true): TooltipState {\n if (getComputedStyle(container).position === 'static') {\n container.style.position = 'relative';\n }\n\n const el = container.ownerDocument.createElement('div');\n\n el.className = 'prism-tooltip';\n el.style.position = 'absolute';\n el.style.pointerEvents = 'none';\n el.style.top = '0';\n el.style.left = '0';\n // Non-modal status text — announced by assistive tech whenever content/hide state changes.\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n container.appendChild(el);\n\n const tooltipOffset: number = (config !== true && config?.offset) || 8;\n const render = config !== true ? config?.render : undefined;\n const sanitize = config !== true ? config?.sanitize : undefined;\n\n if (render && !sanitize) {\n warn(\n 'createTooltip: `render` is set without `sanitize` — falling back to plain-text rendering of the returned string to avoid an XSS risk. Pass `sanitize` to render HTML.',\n );\n }\n\n let revealFrame: number | null = null;\n let clearTimer: ReturnType<typeof setTimeout> | null = null;\n let visible = false;\n\n const cancelClear = (): void => {\n if (clearTimer === null) return;\n\n clearTimeout(clearTimer);\n clearTimer = null;\n };\n\n const cancelReveal = (): void => {\n if (revealFrame === null) return;\n\n cancelAnimationFrame(revealFrame);\n revealFrame = null;\n };\n\n const disposeHandle = (): void => {\n cancelReveal();\n cancelClear();\n el.remove();\n };\n\n return {\n dispose: disposeHandle,\n el,\n hide() {\n cancelReveal();\n cancelClear();\n visible = false;\n el.style.opacity = '0';\n clearTimer = setTimeout(() => {\n clearTimer = null;\n\n if (!visible) el.textContent = '';\n }, 150);\n },\n show(x: number, y: number, datum: Datum, series: Series) {\n if (!container.isConnected) return;\n\n cancelClear();\n\n if (render) {\n const html = render(datum, series);\n\n if (sanitize) {\n el.innerHTML = sanitize(html);\n } else {\n // No sanitizer provided — never inject the raw string as HTML. Render it as text instead.\n el.textContent = html;\n }\n } else {\n el.textContent = `${series.name}: ${datum.value}`;\n }\n\n const virtualRef = {\n getBoundingClientRect: () => {\n const rect = container.getBoundingClientRect();\n\n return {\n bottom: rect.top + y,\n height: 0,\n left: rect.left + x,\n right: rect.left + x,\n top: rect.top + y,\n width: 0,\n x: rect.left + x,\n y: rect.top + y,\n };\n },\n };\n\n const { x: positionX, y: positionY } = computePosition(virtualRef, el, {\n containingBlock: container,\n middleware: [offset(tooltipOffset), flip(), shift({ padding: 8 })],\n placement: 'top',\n });\n\n el.style.left = `${positionX}px`;\n el.style.top = `${positionY}px`;\n\n if (visible) {\n if (revealFrame === null) el.style.opacity = '1';\n\n return;\n }\n\n visible = true;\n el.style.opacity = '0';\n revealFrame = requestAnimationFrame(() => {\n revealFrame = null;\n\n if (visible) el.style.opacity = '1';\n });\n },\n [Symbol.dispose]: disposeHandle,\n };\n}\n"],"mappings":"wDAYA,SAAgB,EAAc,EAAwB,EAA6C,CAC7F,iBAAiB,CAAS,CAAC,CAAC,WAAa,WAC3C,EAAU,MAAM,SAAW,YAG7B,IAAM,EAAK,EAAU,cAAc,cAAc,KAAK,EAEtD,EAAG,UAAY,gBACf,EAAG,MAAM,SAAW,WACpB,EAAG,MAAM,cAAgB,OACzB,EAAG,MAAM,IAAM,IACf,EAAG,MAAM,KAAO,IAEhB,EAAG,aAAa,OAAQ,QAAQ,EAChC,EAAG,aAAa,YAAa,QAAQ,EACrC,EAAU,YAAY,CAAE,EAExB,IAAM,EAAyB,IAAW,IAAQ,GAAQ,QAAW,EAC/D,EAAS,IAAW,GAAwB,IAAA,GAAjB,GAAQ,OACnC,EAAW,IAAW,GAA0B,IAAA,GAAnB,GAAQ,SAQvC,EAA6B,KAC7B,EAAmD,KACnD,EAAU,GAER,MAA0B,CAC1B,IAAe,OAEnB,aAAa,CAAU,EACvB,EAAa,KACf,EAEM,MAA2B,CAC3B,IAAgB,OAEpB,qBAAqB,CAAW,EAChC,EAAc,KAChB,EAEM,MAA4B,CAChC,EAAa,EACb,EAAY,EACZ,EAAG,OAAO,CACZ,EAEA,MAAO,CACL,QAAS,EACT,KACA,MAAO,CACL,EAAa,EACb,EAAY,EACZ,EAAU,GACV,EAAG,MAAM,QAAU,IACnB,EAAa,eAAiB,CAC5B,EAAa,KAER,IAAS,EAAG,YAAc,GACjC,EAAG,GAAG,CACR,EACA,KAAK,EAAW,EAAW,EAAc,EAAgB,CACvD,GAAI,CAAC,EAAU,YAAa,OAI5B,GAFA,EAAY,EAER,EAAQ,CACV,IAAM,EAAO,EAAO,EAAO,CAAM,EAE7B,EACF,EAAG,UAAY,EAAS,CAAI,EAG5B,EAAG,YAAc,CAErB,KACE,GAAG,YAAc,GAAG,EAAO,KAAK,IAAI,EAAM,QAoB5C,GAAM,CAAE,EAAG,EAAW,EAAG,IAAA,EAAc,EAAA,gBAAA,CAAgB,CAhBrD,0BAA6B,CAC3B,IAAM,EAAO,EAAU,sBAAsB,EAE7C,MAAO,CACL,OAAQ,EAAK,IAAM,EACnB,OAAQ,EACR,KAAM,EAAK,KAAO,EAClB,MAAO,EAAK,KAAO,EACnB,IAAK,EAAK,IAAM,EAChB,MAAO,EACP,EAAG,EAAK,KAAO,EACf,EAAG,EAAK,IAAM,CAChB,CACF,CAGqD,EAAY,EAAI,CACrE,gBAAiB,EACjB,WAAY,EAAC,EAAA,EAAA,OAAA,CAAO,CAAa,GAAG,EAAA,EAAA,KAAA,CAAK,GAAG,EAAA,EAAA,MAAA,CAAM,CAAE,QAAS,CAAE,CAAC,CAAC,EACjE,UAAW,KACb,CAAC,EAKD,GAHA,EAAG,MAAM,KAAO,GAAG,EAAU,IAC7B,EAAG,MAAM,IAAM,GAAG,EAAU,IAExB,EAAS,CACP,IAAgB,OAAM,EAAG,MAAM,QAAU,KAE7C,MACF,CAEA,EAAU,GACV,EAAG,MAAM,QAAU,IACnB,EAAc,0BAA4B,CACxC,EAAc,KAEV,IAAS,EAAG,MAAM,QAAU,IAClC,CAAC,CACH,GACC,OAAO,SAAU,CACpB,CACF"}
@@ -3,7 +3,7 @@ import { computePosition as e, flip as t, offset as n, shift as r } from "@vielz
3
3
  //#region src/interaction/tooltip.ts
4
4
  function i(i, a) {
5
5
  getComputedStyle(i).position === "static" && (i.style.position = "relative");
6
- let o = document.createElement("div");
6
+ let o = i.ownerDocument.createElement("div");
7
7
  o.className = "prism-tooltip", o.style.position = "absolute", o.style.pointerEvents = "none", o.style.top = "0", o.style.left = "0", o.setAttribute("role", "status"), o.setAttribute("aria-live", "polite"), i.appendChild(o);
8
8
  let s = a !== !0 && a?.offset || 8, c = a === !0 ? void 0 : a?.render, l = a === !0 ? void 0 : a?.sanitize, u = null, d = null, f = !1, p = () => {
9
9
  d !== null && (clearTimeout(d), d = null);
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.js","names":[],"sources":["../../src/interaction/tooltip.ts"],"sourcesContent":["import { computePosition, flip, offset, shift } from '@vielzeug/orbit';\nimport { warn } from '../_dev';\nimport type { Datum, Series, TooltipConfig } from '../types';\n\nexport interface TooltipState {\n dispose(): void;\n el: HTMLDivElement | null;\n hide(): void;\n show(x: number, y: number, datum: Datum, series: Series): void;\n [Symbol.dispose](): void;\n}\n\nexport function createTooltip(container: HTMLElement, config?: TooltipConfig | true): TooltipState {\n if (getComputedStyle(container).position === 'static') {\n container.style.position = 'relative';\n }\n\n const el = document.createElement('div');\n\n el.className = 'prism-tooltip';\n el.style.position = 'absolute';\n el.style.pointerEvents = 'none';\n el.style.top = '0';\n el.style.left = '0';\n // Non-modal status text — announced by assistive tech whenever content/hide state changes.\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n container.appendChild(el);\n\n const tooltipOffset: number = (config !== true && config?.offset) || 8;\n const render = config !== true ? config?.render : undefined;\n const sanitize = config !== true ? config?.sanitize : undefined;\n\n if (render && !sanitize) {\n warn(\n 'createTooltip: `render` is set without `sanitize` — falling back to plain-text rendering of the returned string to avoid an XSS risk. Pass `sanitize` to render HTML.',\n );\n }\n\n let revealFrame: number | null = null;\n let clearTimer: ReturnType<typeof setTimeout> | null = null;\n let visible = false;\n\n const cancelClear = (): void => {\n if (clearTimer === null) return;\n\n clearTimeout(clearTimer);\n clearTimer = null;\n };\n\n const cancelReveal = (): void => {\n if (revealFrame === null) return;\n\n cancelAnimationFrame(revealFrame);\n revealFrame = null;\n };\n\n const disposeHandle = (): void => {\n cancelReveal();\n cancelClear();\n el.remove();\n };\n\n return {\n dispose: disposeHandle,\n el,\n hide() {\n cancelReveal();\n cancelClear();\n visible = false;\n el.style.opacity = '0';\n clearTimer = setTimeout(() => {\n clearTimer = null;\n\n if (!visible) el.textContent = '';\n }, 150);\n },\n show(x: number, y: number, datum: Datum, series: Series) {\n if (!container.isConnected) return;\n\n cancelClear();\n\n if (render) {\n const html = render(datum, series);\n\n if (sanitize) {\n el.innerHTML = sanitize(html);\n } else {\n // No sanitizer provided — never inject the raw string as HTML. Render it as text instead.\n el.textContent = html;\n }\n } else {\n el.textContent = `${series.name}: ${datum.value}`;\n }\n\n const virtualRef = {\n getBoundingClientRect: () => {\n const rect = container.getBoundingClientRect();\n\n return {\n bottom: rect.top + y,\n height: 0,\n left: rect.left + x,\n right: rect.left + x,\n top: rect.top + y,\n width: 0,\n x: rect.left + x,\n y: rect.top + y,\n };\n },\n };\n\n const { x: positionX, y: positionY } = computePosition(virtualRef, el, {\n containingBlock: container,\n middleware: [offset(tooltipOffset), flip(), shift({ padding: 8 })],\n placement: 'top',\n });\n\n el.style.left = `${positionX}px`;\n el.style.top = `${positionY}px`;\n\n if (visible) {\n if (revealFrame === null) el.style.opacity = '1';\n\n return;\n }\n\n visible = true;\n el.style.opacity = '0';\n revealFrame = requestAnimationFrame(() => {\n revealFrame = null;\n\n if (visible) el.style.opacity = '1';\n });\n },\n [Symbol.dispose]: disposeHandle,\n };\n}\n"],"mappings":";;;AAYA,SAAgB,EAAc,GAAwB,GAA6C;CACjG,AAAI,iBAAiB,CAAS,CAAC,CAAC,aAAa,aAC3C,EAAU,MAAM,WAAW;CAG7B,IAAM,IAAK,SAAS,cAAc,KAAK;CAUvC,AARA,EAAG,YAAY,iBACf,EAAG,MAAM,WAAW,YACpB,EAAG,MAAM,gBAAgB,QACzB,EAAG,MAAM,MAAM,KACf,EAAG,MAAM,OAAO,KAEhB,EAAG,aAAa,QAAQ,QAAQ,GAChC,EAAG,aAAa,aAAa,QAAQ,GACrC,EAAU,YAAY,CAAE;CAExB,IAAM,IAAyB,MAAW,MAAQ,GAAQ,UAAW,GAC/D,IAAS,MAAW,KAAwB,KAAA,IAAjB,GAAQ,QACnC,IAAW,MAAW,KAA0B,KAAA,IAAnB,GAAQ,UAQvC,IAA6B,MAC7B,IAAmD,MACnD,IAAU,IAER,UAA0B;EAC1B,MAAe,SAEnB,aAAa,CAAU,GACvB,IAAa;CACf,GAEM,UAA2B;EAC3B,MAAgB,SAEpB,qBAAqB,CAAW,GAChC,IAAc;CAChB,GAEM,UAA4B;EAGhC,AAFA,EAAa,GACb,EAAY,GACZ,EAAG,OAAO;CACZ;CAEA,OAAO;EACL,SAAS;EACT;EACA,OAAO;GAKL,AAJA,EAAa,GACb,EAAY,GACZ,IAAU,IACV,EAAG,MAAM,UAAU,KACnB,IAAa,iBAAiB;IAG5B,AAFA,IAAa,MAER,MAAS,EAAG,cAAc;GACjC,GAAG,GAAG;EACR;EACA,KAAK,GAAW,GAAW,GAAc,GAAgB;GACvD,IAAI,CAAC,EAAU,aAAa;GAI5B,IAFA,EAAY,GAER,GAAQ;IACV,IAAM,IAAO,EAAO,GAAO,CAAM;IAEjC,AAAI,IACF,EAAG,YAAY,EAAS,CAAI,IAG5B,EAAG,cAAc;GAErB,OACE,EAAG,cAAc,GAAG,EAAO,KAAK,IAAI,EAAM;GAoB5C,IAAM,EAAE,GAAG,GAAW,GAAG,MAAc,EAAgB,EAhBrD,6BAA6B;IAC3B,IAAM,IAAO,EAAU,sBAAsB;IAE7C,OAAO;KACL,QAAQ,EAAK,MAAM;KACnB,QAAQ;KACR,MAAM,EAAK,OAAO;KAClB,OAAO,EAAK,OAAO;KACnB,KAAK,EAAK,MAAM;KAChB,OAAO;KACP,GAAG,EAAK,OAAO;KACf,GAAG,EAAK,MAAM;IAChB;GACF,EAGqD,GAAY,GAAI;IACrE,iBAAiB;IACjB,YAAY;KAAC,EAAO,CAAa;KAAG,EAAK;KAAG,EAAM,EAAE,SAAS,EAAE,CAAC;IAAC;IACjE,WAAW;GACb,CAAC;GAKD,IAHA,EAAG,MAAM,OAAO,GAAG,EAAU,KAC7B,EAAG,MAAM,MAAM,GAAG,EAAU,KAExB,GAAS;IACX,AAAI,MAAgB,SAAM,EAAG,MAAM,UAAU;IAE7C;GACF;GAIA,AAFA,IAAU,IACV,EAAG,MAAM,UAAU,KACnB,IAAc,4BAA4B;IAGxC,AAFA,IAAc,MAEV,MAAS,EAAG,MAAM,UAAU;GAClC,CAAC;EACH;GACC,OAAO,UAAU;CACpB;AACF"}
1
+ {"version":3,"file":"tooltip.js","names":[],"sources":["../../src/interaction/tooltip.ts"],"sourcesContent":["import { computePosition, flip, offset, shift } from '@vielzeug/orbit';\nimport { warn } from '../_dev';\nimport type { Datum, Series, TooltipConfig } from '../types';\n\nexport interface TooltipState {\n dispose(): void;\n el: HTMLDivElement | null;\n hide(): void;\n show(x: number, y: number, datum: Datum, series: Series): void;\n [Symbol.dispose](): void;\n}\n\nexport function createTooltip(container: HTMLElement, config?: TooltipConfig | true): TooltipState {\n if (getComputedStyle(container).position === 'static') {\n container.style.position = 'relative';\n }\n\n const el = container.ownerDocument.createElement('div');\n\n el.className = 'prism-tooltip';\n el.style.position = 'absolute';\n el.style.pointerEvents = 'none';\n el.style.top = '0';\n el.style.left = '0';\n // Non-modal status text — announced by assistive tech whenever content/hide state changes.\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n container.appendChild(el);\n\n const tooltipOffset: number = (config !== true && config?.offset) || 8;\n const render = config !== true ? config?.render : undefined;\n const sanitize = config !== true ? config?.sanitize : undefined;\n\n if (render && !sanitize) {\n warn(\n 'createTooltip: `render` is set without `sanitize` — falling back to plain-text rendering of the returned string to avoid an XSS risk. Pass `sanitize` to render HTML.',\n );\n }\n\n let revealFrame: number | null = null;\n let clearTimer: ReturnType<typeof setTimeout> | null = null;\n let visible = false;\n\n const cancelClear = (): void => {\n if (clearTimer === null) return;\n\n clearTimeout(clearTimer);\n clearTimer = null;\n };\n\n const cancelReveal = (): void => {\n if (revealFrame === null) return;\n\n cancelAnimationFrame(revealFrame);\n revealFrame = null;\n };\n\n const disposeHandle = (): void => {\n cancelReveal();\n cancelClear();\n el.remove();\n };\n\n return {\n dispose: disposeHandle,\n el,\n hide() {\n cancelReveal();\n cancelClear();\n visible = false;\n el.style.opacity = '0';\n clearTimer = setTimeout(() => {\n clearTimer = null;\n\n if (!visible) el.textContent = '';\n }, 150);\n },\n show(x: number, y: number, datum: Datum, series: Series) {\n if (!container.isConnected) return;\n\n cancelClear();\n\n if (render) {\n const html = render(datum, series);\n\n if (sanitize) {\n el.innerHTML = sanitize(html);\n } else {\n // No sanitizer provided — never inject the raw string as HTML. Render it as text instead.\n el.textContent = html;\n }\n } else {\n el.textContent = `${series.name}: ${datum.value}`;\n }\n\n const virtualRef = {\n getBoundingClientRect: () => {\n const rect = container.getBoundingClientRect();\n\n return {\n bottom: rect.top + y,\n height: 0,\n left: rect.left + x,\n right: rect.left + x,\n top: rect.top + y,\n width: 0,\n x: rect.left + x,\n y: rect.top + y,\n };\n },\n };\n\n const { x: positionX, y: positionY } = computePosition(virtualRef, el, {\n containingBlock: container,\n middleware: [offset(tooltipOffset), flip(), shift({ padding: 8 })],\n placement: 'top',\n });\n\n el.style.left = `${positionX}px`;\n el.style.top = `${positionY}px`;\n\n if (visible) {\n if (revealFrame === null) el.style.opacity = '1';\n\n return;\n }\n\n visible = true;\n el.style.opacity = '0';\n revealFrame = requestAnimationFrame(() => {\n revealFrame = null;\n\n if (visible) el.style.opacity = '1';\n });\n },\n [Symbol.dispose]: disposeHandle,\n };\n}\n"],"mappings":";;;AAYA,SAAgB,EAAc,GAAwB,GAA6C;CACjG,AAAI,iBAAiB,CAAS,CAAC,CAAC,aAAa,aAC3C,EAAU,MAAM,WAAW;CAG7B,IAAM,IAAK,EAAU,cAAc,cAAc,KAAK;CAUtD,AARA,EAAG,YAAY,iBACf,EAAG,MAAM,WAAW,YACpB,EAAG,MAAM,gBAAgB,QACzB,EAAG,MAAM,MAAM,KACf,EAAG,MAAM,OAAO,KAEhB,EAAG,aAAa,QAAQ,QAAQ,GAChC,EAAG,aAAa,aAAa,QAAQ,GACrC,EAAU,YAAY,CAAE;CAExB,IAAM,IAAyB,MAAW,MAAQ,GAAQ,UAAW,GAC/D,IAAS,MAAW,KAAwB,KAAA,IAAjB,GAAQ,QACnC,IAAW,MAAW,KAA0B,KAAA,IAAnB,GAAQ,UAQvC,IAA6B,MAC7B,IAAmD,MACnD,IAAU,IAER,UAA0B;EAC1B,MAAe,SAEnB,aAAa,CAAU,GACvB,IAAa;CACf,GAEM,UAA2B;EAC3B,MAAgB,SAEpB,qBAAqB,CAAW,GAChC,IAAc;CAChB,GAEM,UAA4B;EAGhC,AAFA,EAAa,GACb,EAAY,GACZ,EAAG,OAAO;CACZ;CAEA,OAAO;EACL,SAAS;EACT;EACA,OAAO;GAKL,AAJA,EAAa,GACb,EAAY,GACZ,IAAU,IACV,EAAG,MAAM,UAAU,KACnB,IAAa,iBAAiB;IAG5B,AAFA,IAAa,MAER,MAAS,EAAG,cAAc;GACjC,GAAG,GAAG;EACR;EACA,KAAK,GAAW,GAAW,GAAc,GAAgB;GACvD,IAAI,CAAC,EAAU,aAAa;GAI5B,IAFA,EAAY,GAER,GAAQ;IACV,IAAM,IAAO,EAAO,GAAO,CAAM;IAEjC,AAAI,IACF,EAAG,YAAY,EAAS,CAAI,IAG5B,EAAG,cAAc;GAErB,OACE,EAAG,cAAc,GAAG,EAAO,KAAK,IAAI,EAAM;GAoB5C,IAAM,EAAE,GAAG,GAAW,GAAG,MAAc,EAAgB,EAhBrD,6BAA6B;IAC3B,IAAM,IAAO,EAAU,sBAAsB;IAE7C,OAAO;KACL,QAAQ,EAAK,MAAM;KACnB,QAAQ;KACR,MAAM,EAAK,OAAO;KAClB,OAAO,EAAK,OAAO;KACnB,KAAK,EAAK,MAAM;KAChB,OAAO;KACP,GAAG,EAAK,OAAO;KACf,GAAG,EAAK,MAAM;IAChB;GACF,EAGqD,GAAY,GAAI;IACrE,iBAAiB;IACjB,YAAY;KAAC,EAAO,CAAa;KAAG,EAAK;KAAG,EAAM,EAAE,SAAS,EAAE,CAAC;IAAC;IACjE,WAAW;GACb,CAAC;GAKD,IAHA,EAAG,MAAM,OAAO,GAAG,EAAU,KAC7B,EAAG,MAAM,MAAM,GAAG,EAAU,KAExB,GAAS;IACX,AAAI,MAAgB,SAAM,EAAG,MAAM,UAAU;IAE7C;GACF;GAIA,AAFA,IAAU,IACV,EAAG,MAAM,UAAU,KACnB,IAAc,4BAA4B;IAGxC,AAFA,IAAc,MAEV,MAAS,EAAG,MAAM,UAAU;GAClC,CAAC;EACH;GACC,OAAO,UAAU;CACpB;AACF"}