@vielzeug/prism 2.0.0 → 2.1.0

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 (91) hide show
  1. package/README.md +3 -2
  2. package/dist/animation/motion.cjs +2 -0
  3. package/dist/animation/motion.cjs.map +1 -0
  4. package/dist/animation/motion.d.ts +3 -0
  5. package/dist/animation/motion.d.ts.map +1 -0
  6. package/dist/animation/motion.js +13 -0
  7. package/dist/animation/motion.js.map +1 -0
  8. package/dist/animation/transition.cjs +1 -1
  9. package/dist/animation/transition.cjs.map +1 -1
  10. package/dist/animation/transition.d.ts.map +1 -1
  11. package/dist/animation/transition.js +19 -18
  12. package/dist/animation/transition.js.map +1 -1
  13. package/dist/charts/area/area-renderer.cjs +1 -1
  14. package/dist/charts/area/area-renderer.cjs.map +1 -1
  15. package/dist/charts/area/area-renderer.d.ts.map +1 -1
  16. package/dist/charts/area/area-renderer.js +42 -41
  17. package/dist/charts/area/area-renderer.js.map +1 -1
  18. package/dist/charts/bar/bar-chart.cjs +1 -1
  19. package/dist/charts/bar/bar-chart.cjs.map +1 -1
  20. package/dist/charts/bar/bar-chart.d.ts.map +1 -1
  21. package/dist/charts/bar/bar-chart.js +104 -87
  22. package/dist/charts/bar/bar-chart.js.map +1 -1
  23. package/dist/charts/bar/bar-hit-test.cjs.map +1 -1
  24. package/dist/charts/bar/bar-hit-test.d.ts +1 -1
  25. package/dist/charts/bar/bar-hit-test.d.ts.map +1 -1
  26. package/dist/charts/bar/bar-hit-test.js.map +1 -1
  27. package/dist/charts/bar/bar-renderer.cjs +1 -1
  28. package/dist/charts/bar/bar-renderer.cjs.map +1 -1
  29. package/dist/charts/bar/bar-renderer.d.ts +1 -0
  30. package/dist/charts/bar/bar-renderer.d.ts.map +1 -1
  31. package/dist/charts/bar/bar-renderer.js +1 -1
  32. package/dist/charts/bar/bar-renderer.js.map +1 -1
  33. package/dist/charts/line/line-renderer.cjs +1 -1
  34. package/dist/charts/line/line-renderer.cjs.map +1 -1
  35. package/dist/charts/line/line-renderer.d.ts.map +1 -1
  36. package/dist/charts/line/line-renderer.js +58 -57
  37. package/dist/charts/line/line-renderer.js.map +1 -1
  38. package/dist/charts/pie/pie-chart.cjs +1 -1
  39. package/dist/charts/pie/pie-chart.cjs.map +1 -1
  40. package/dist/charts/pie/pie-chart.d.ts.map +1 -1
  41. package/dist/charts/pie/pie-chart.js +72 -70
  42. package/dist/charts/pie/pie-chart.js.map +1 -1
  43. package/dist/charts/sparkline/sparkline.cjs +1 -1
  44. package/dist/charts/sparkline/sparkline.cjs.map +1 -1
  45. package/dist/charts/sparkline/sparkline.d.ts.map +1 -1
  46. package/dist/charts/sparkline/sparkline.js +63 -62
  47. package/dist/charts/sparkline/sparkline.js.map +1 -1
  48. package/dist/core/cartesian-model.cjs +2 -0
  49. package/dist/core/cartesian-model.cjs.map +1 -0
  50. package/dist/core/cartesian-model.d.ts +14 -0
  51. package/dist/core/cartesian-model.d.ts.map +1 -0
  52. package/dist/core/cartesian-model.js +31 -0
  53. package/dist/core/cartesian-model.js.map +1 -0
  54. package/dist/core/chart-base.cjs +1 -1
  55. package/dist/core/chart-base.cjs.map +1 -1
  56. package/dist/core/chart-base.d.ts +2 -1
  57. package/dist/core/chart-base.d.ts.map +1 -1
  58. package/dist/core/chart-base.js +28 -25
  59. package/dist/core/chart-base.js.map +1 -1
  60. package/dist/core/chart-scaffold.cjs +1 -1
  61. package/dist/core/chart-scaffold.cjs.map +1 -1
  62. package/dist/core/chart-scaffold.d.ts +1 -0
  63. package/dist/core/chart-scaffold.d.ts.map +1 -1
  64. package/dist/core/chart-scaffold.js +2 -1
  65. package/dist/core/chart-scaffold.js.map +1 -1
  66. package/dist/index.d.ts +1 -2
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/interaction/series-interaction.cjs +1 -1
  69. package/dist/interaction/series-interaction.cjs.map +1 -1
  70. package/dist/interaction/series-interaction.d.ts.map +1 -1
  71. package/dist/interaction/series-interaction.js +73 -34
  72. package/dist/interaction/series-interaction.js.map +1 -1
  73. package/dist/interaction/tooltip.cjs +1 -1
  74. package/dist/interaction/tooltip.cjs.map +1 -1
  75. package/dist/interaction/tooltip.d.ts.map +1 -1
  76. package/dist/interaction/tooltip.js +28 -15
  77. package/dist/interaction/tooltip.js.map +1 -1
  78. package/dist/prism.cjs +1 -1
  79. package/dist/prism.cjs.map +1 -1
  80. package/dist/prism.iife.js +1 -1
  81. package/dist/prism.iife.js.map +1 -1
  82. package/dist/prism.js +1 -1
  83. package/dist/prism.js.map +1 -1
  84. package/dist/theme/prism.css +1 -0
  85. package/dist/types.d.ts +13 -2
  86. package/dist/types.d.ts.map +1 -1
  87. package/package.json +10 -6
  88. package/dist/interaction/hit-test.cjs +0 -2
  89. package/dist/interaction/hit-test.cjs.map +0 -1
  90. package/dist/interaction/hit-test.js +0 -14
  91. package/dist/interaction/hit-test.js.map +0 -1
@@ -10,48 +10,51 @@ function o(o, s) {
10
10
  let t = o, n = t === null ? "null" : typeof t == "object" ? t.constructor?.name ?? "object" : typeof t;
11
11
  throw new e(`Invalid chart configuration: \`container\` must be a DOM Element, received ${n}.`);
12
12
  }
13
- let c = r(s.margin), l = t("svg", {
14
- ...s.ariaHidden ? { "aria-hidden": "true" } : {
15
- ...s.ariaLabel ? { "aria-label": s.ariaLabel } : {},
13
+ let c = r(s.margin), l = s.a11y ?? (s.ariaLabel ? { ariaLabel: s.ariaLabel } : void 0), u = t("svg", {
14
+ ...s.ariaHidden || l?.decorative ? { "aria-hidden": "true" } : {
15
+ ...l ? {
16
+ "aria-label": l.ariaLabel,
17
+ tabindex: "0"
18
+ } : {},
16
19
  role: "img"
17
20
  },
18
21
  class: "prism-chart",
19
22
  style: "display:block;width:100%;height:100%"
20
- }), u = t("g", {
23
+ }), d = t("g", {
21
24
  class: "prism-chart-area",
22
25
  transform: `translate(${c.left},${c.top})`
23
26
  });
24
- l.appendChild(u);
25
- let d = o.getBoundingClientRect();
26
- d.width === 0 || d.height;
27
- let f = typeof getComputedStyle < "u" ? getComputedStyle(o) : null;
28
- f && f.position;
29
- let p = a({
30
- height: d.height || 300,
27
+ u.appendChild(d);
28
+ let f = o.getBoundingClientRect();
29
+ f.width === 0 || f.height;
30
+ let p = typeof getComputedStyle < "u" ? getComputedStyle(o) : null;
31
+ p && p.position;
32
+ let m = a({
33
+ height: f.height || 300,
31
34
  margin: c,
32
- width: d.width || 600
33
- }), m = i(o, (e, t) => {
34
- p.value = {
35
+ width: f.width || 600
36
+ }), h = i(o, (e, t) => {
37
+ m.value = {
35
38
  height: t,
36
39
  margin: c,
37
40
  width: e
38
- }, n(l, {
41
+ }, n(u, {
39
42
  height: t,
40
43
  viewBox: `0 0 ${e} ${t}`,
41
44
  width: e
42
45
  });
43
- }), h = d.width || 600, g = d.height || 300;
44
- return n(l, {
45
- height: g,
46
- viewBox: `0 0 ${h} ${g}`,
47
- width: h
48
- }), o.appendChild(l), {
49
- chartArea: u,
50
- dimensions: p,
46
+ }), g = f.width || 600, _ = f.height || 300;
47
+ return n(u, {
48
+ height: _,
49
+ viewBox: `0 0 ${g} ${_}`,
50
+ width: g
51
+ }), o.appendChild(u), {
52
+ chartArea: d,
53
+ dimensions: m,
51
54
  dispose() {
52
- m(), l.remove();
55
+ h(), u.remove();
53
56
  },
54
- svg: l
57
+ svg: u
55
58
  };
56
59
  }
57
60
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"chart-base.js","names":[],"sources":["../../src/core/chart-base.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { signal } from '@vielzeug/ripple';\n\nimport type { ChartDimensions, ChartMargin } from '../types';\n\nimport { warn } from '../_dev';\nimport { PrismRenderError } from '../errors';\nimport { createSvgElement, setAttributes } from '../svg/element';\nimport { resolveMargin } from './layout';\nimport { observeResize } from './responsive';\n\nexport interface ChartBase {\n chartArea: SVGGElement;\n dimensions: Readable<ChartDimensions>;\n svg: SVGSVGElement;\n dispose(): void;\n}\n\nexport function createChartBase(\n container: HTMLElement,\n options: { ariaHidden?: boolean; ariaLabel?: string; margin?: Partial<ChartMargin> },\n): ChartBase {\n // Duck-typed rather than `instanceof Element` — an `instanceof` check would reject a\n // structurally valid Element from a different realm (e.g. an Element created via\n // `iframe.contentDocument.createElement(...)`, whose prototype chain terminates in that\n // iframe's own `Element` constructor), which is a legitimate usage pattern this package\n // doesn't otherwise restrict.\n const isElementLike =\n typeof container === 'object' &&\n container !== null &&\n container.nodeType === 1 &&\n typeof container.appendChild === 'function' &&\n typeof container.getBoundingClientRect === 'function';\n\n if (!isElementLike) {\n const received: unknown = container;\n const kind =\n received === null\n ? 'null'\n : typeof received === 'object'\n ? (received.constructor?.name ?? 'object')\n : typeof received;\n\n throw new PrismRenderError(`Invalid chart configuration: \\`container\\` must be a DOM Element, received ${kind}.`);\n }\n\n const margin = resolveMargin(options.margin);\n const svg = createSvgElement('svg', {\n ...(options.ariaHidden\n ? { 'aria-hidden': 'true' }\n : { ...(options.ariaLabel ? { 'aria-label': options.ariaLabel } : {}), role: 'img' }),\n class: 'prism-chart',\n style: 'display:block;width:100%;height:100%',\n });\n\n const chartAreaGroup = createSvgElement('g', {\n class: 'prism-chart-area',\n transform: `translate(${margin.left},${margin.top})`,\n });\n\n svg.appendChild(chartAreaGroup);\n\n const rect = container.getBoundingClientRect();\n\n if (rect.width === 0 || rect.height === 0) {\n warn(\n 'Chart container has zero dimensions. Ensure the container has a defined width and height before mounting a chart.',\n );\n }\n\n const computedStyle = typeof getComputedStyle !== 'undefined' ? getComputedStyle(container) : null;\n\n if (computedStyle && computedStyle.position === 'static') {\n warn(\n 'Chart container has position:static. Set position:relative (or absolute/fixed) on the container so tooltip and overlay elements are positioned correctly.',\n );\n }\n\n const dimensions = signal<ChartDimensions>({\n height: rect.height || 300,\n margin,\n width: rect.width || 600,\n });\n\n const stopObserving = observeResize(container, (width, height) => {\n dimensions.value = { height, margin, width };\n setAttributes(svg, { height, viewBox: `0 0 ${width} ${height}`, width });\n });\n\n const initialWidth = rect.width || 600;\n const initialHeight = rect.height || 300;\n\n setAttributes(svg, {\n height: initialHeight,\n viewBox: `0 0 ${initialWidth} ${initialHeight}`,\n width: initialWidth,\n });\n\n container.appendChild(svg);\n\n return {\n chartArea: chartAreaGroup,\n dimensions,\n dispose() {\n stopObserving();\n svg.remove();\n },\n svg,\n };\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,EACd,GACA,GACW;CAaX,IAAI,EANF,OAAO,KAAc,YACrB,KACA,EAAU,aAAa,KACvB,OAAO,EAAU,eAAgB,cACjC,OAAO,EAAU,yBAA0B,aAEzB;EAClB,IAAM,IAAoB,GACpB,IACJ,MAAa,OACT,SACA,OAAO,KAAa,WACjB,EAAS,aAAa,QAAQ,WAC/B,OAAO;EAEf,MAAM,IAAI,EAAiB,8EAA8E,EAAK,EAAE;CAClH;CAEA,IAAM,IAAS,EAAc,EAAQ,MAAM,GACrC,IAAM,EAAiB,OAAO;EAClC,GAAI,EAAQ,aACR,EAAE,eAAe,OAAO,IACxB;GAAE,GAAI,EAAQ,YAAY,EAAE,cAAc,EAAQ,UAAU,IAAI,CAAC;GAAI,MAAM;EAAM;EACrF,OAAO;EACP,OAAO;CACT,CAAC,GAEK,IAAiB,EAAiB,KAAK;EAC3C,OAAO;EACP,WAAW,aAAa,EAAO,KAAK,GAAG,EAAO,IAAI;CACpD,CAAC;CAED,EAAI,YAAY,CAAc;CAE9B,IAAM,IAAO,EAAU,sBAAsB;CAE7C,AAAI,EAAK,UAAU,KAAK,EAAK;CAM7B,IAAM,IAAgB,OAAO,mBAAqB,MAAc,iBAAiB,CAAS,IAAI;CAE9F,AAAI,KAAiB,EAAc;CAMnC,IAAM,IAAa,EAAwB;EACzC,QAAQ,EAAK,UAAU;EACvB;EACA,OAAO,EAAK,SAAS;CACvB,CAAC,GAEK,IAAgB,EAAc,IAAY,GAAO,MAAW;EAEhE,AADA,EAAW,QAAQ;GAAE;GAAQ;GAAQ;EAAM,GAC3C,EAAc,GAAK;GAAE;GAAQ,SAAS,OAAO,EAAM,GAAG;GAAU;EAAM,CAAC;CACzE,CAAC,GAEK,IAAe,EAAK,SAAS,KAC7B,IAAgB,EAAK,UAAU;CAUrC,OARA,EAAc,GAAK;EACjB,QAAQ;EACR,SAAS,OAAO,EAAa,GAAG;EAChC,OAAO;CACT,CAAC,GAED,EAAU,YAAY,CAAG,GAElB;EACL,WAAW;EACX;EACA,UAAU;GAER,AADA,EAAc,GACd,EAAI,OAAO;EACb;EACA;CACF;AACF"}
1
+ {"version":3,"file":"chart-base.js","names":[],"sources":["../../src/core/chart-base.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { signal } from '@vielzeug/ripple';\n\nimport type { ChartA11y, ChartDimensions, ChartMargin } from '../types';\n\nimport { warn } from '../_dev';\nimport { PrismRenderError } from '../errors';\nimport { createSvgElement, setAttributes } from '../svg/element';\nimport { resolveMargin } from './layout';\nimport { observeResize } from './responsive';\n\nexport interface ChartBase {\n chartArea: SVGGElement;\n dimensions: Readable<ChartDimensions>;\n svg: SVGSVGElement;\n dispose(): void;\n}\n\nexport function createChartBase(\n container: HTMLElement,\n options: { a11y?: ChartA11y; ariaHidden?: boolean; ariaLabel?: string; margin?: Partial<ChartMargin> },\n): ChartBase {\n // Duck-typed rather than `instanceof Element` — an `instanceof` check would reject a\n // structurally valid Element from a different realm (e.g. an Element created via\n // `iframe.contentDocument.createElement(...)`, whose prototype chain terminates in that\n // iframe's own `Element` constructor), which is a legitimate usage pattern this package\n // doesn't otherwise restrict.\n const isElementLike =\n typeof container === 'object' &&\n container !== null &&\n container.nodeType === 1 &&\n typeof container.appendChild === 'function' &&\n typeof container.getBoundingClientRect === 'function';\n\n if (!isElementLike) {\n const received: unknown = container;\n const kind =\n received === null\n ? 'null'\n : typeof received === 'object'\n ? (received.constructor?.name ?? 'object')\n : typeof received;\n\n throw new PrismRenderError(`Invalid chart configuration: \\`container\\` must be a DOM Element, received ${kind}.`);\n }\n\n const margin = resolveMargin(options.margin);\n const a11y = options.a11y ?? (options.ariaLabel ? { ariaLabel: options.ariaLabel } : undefined);\n const svg = createSvgElement('svg', {\n ...(options.ariaHidden || a11y?.decorative\n ? { 'aria-hidden': 'true' }\n : {\n ...(a11y ? { 'aria-label': a11y.ariaLabel, tabindex: '0' } : {}),\n role: 'img',\n }),\n class: 'prism-chart',\n style: 'display:block;width:100%;height:100%',\n });\n\n const chartAreaGroup = createSvgElement('g', {\n class: 'prism-chart-area',\n transform: `translate(${margin.left},${margin.top})`,\n });\n\n svg.appendChild(chartAreaGroup);\n\n const rect = container.getBoundingClientRect();\n\n if (rect.width === 0 || rect.height === 0) {\n warn(\n 'Chart container has zero dimensions. Ensure the container has a defined width and height before mounting a chart.',\n );\n }\n\n const computedStyle = typeof getComputedStyle !== 'undefined' ? getComputedStyle(container) : null;\n\n if (computedStyle && computedStyle.position === 'static') {\n warn(\n 'Chart container has position:static. Set position:relative (or absolute/fixed) on the container so tooltip and overlay elements are positioned correctly.',\n );\n }\n\n const dimensions = signal<ChartDimensions>({\n height: rect.height || 300,\n margin,\n width: rect.width || 600,\n });\n\n const stopObserving = observeResize(container, (width, height) => {\n dimensions.value = { height, margin, width };\n setAttributes(svg, { height, viewBox: `0 0 ${width} ${height}`, width });\n });\n\n const initialWidth = rect.width || 600;\n const initialHeight = rect.height || 300;\n\n setAttributes(svg, {\n height: initialHeight,\n viewBox: `0 0 ${initialWidth} ${initialHeight}`,\n width: initialWidth,\n });\n\n container.appendChild(svg);\n\n return {\n chartArea: chartAreaGroup,\n dimensions,\n dispose() {\n stopObserving();\n svg.remove();\n },\n svg,\n };\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,EACd,GACA,GACW;CAaX,IAAI,EANF,OAAO,KAAc,YACrB,KACA,EAAU,aAAa,KACvB,OAAO,EAAU,eAAgB,cACjC,OAAO,EAAU,yBAA0B,aAEzB;EAClB,IAAM,IAAoB,GACpB,IACJ,MAAa,OACT,SACA,OAAO,KAAa,WACjB,EAAS,aAAa,QAAQ,WAC/B,OAAO;EAEf,MAAM,IAAI,EAAiB,8EAA8E,EAAK,EAAE;CAClH;CAEA,IAAM,IAAS,EAAc,EAAQ,MAAM,GACrC,IAAO,EAAQ,SAAS,EAAQ,YAAY,EAAE,WAAW,EAAQ,UAAU,IAAI,KAAA,IAC/E,IAAM,EAAiB,OAAO;EAClC,GAAI,EAAQ,cAAc,GAAM,aAC5B,EAAE,eAAe,OAAO,IACxB;GACE,GAAI,IAAO;IAAE,cAAc,EAAK;IAAW,UAAU;GAAI,IAAI,CAAC;GAC9D,MAAM;EACR;EACJ,OAAO;EACP,OAAO;CACT,CAAC,GAEK,IAAiB,EAAiB,KAAK;EAC3C,OAAO;EACP,WAAW,aAAa,EAAO,KAAK,GAAG,EAAO,IAAI;CACpD,CAAC;CAED,EAAI,YAAY,CAAc;CAE9B,IAAM,IAAO,EAAU,sBAAsB;CAE7C,AAAI,EAAK,UAAU,KAAK,EAAK;CAM7B,IAAM,IAAgB,OAAO,mBAAqB,MAAc,iBAAiB,CAAS,IAAI;CAE9F,AAAI,KAAiB,EAAc;CAMnC,IAAM,IAAa,EAAwB;EACzC,QAAQ,EAAK,UAAU;EACvB;EACA,OAAO,EAAK,SAAS;CACvB,CAAC,GAEK,IAAgB,EAAc,IAAY,GAAO,MAAW;EAEhE,AADA,EAAW,QAAQ;GAAE;GAAQ;GAAQ;EAAM,GAC3C,EAAc,GAAK;GAAE;GAAQ,SAAS,OAAO,EAAM,GAAG;GAAU;EAAM,CAAC;CACzE,CAAC,GAEK,IAAe,EAAK,SAAS,KAC7B,IAAgB,EAAK,UAAU;CAUrC,OARA,EAAc,GAAK;EACjB,QAAQ;EACR,SAAS,OAAO,EAAa,GAAG;EAChC,OAAO;CACT,CAAC,GAED,EAAU,YAAY,CAAG,GAElB;EACL,WAAW;EACX;EACA,UAAU;GAER,AADA,EAAc,GACd,EAAI,OAAO;EACb;EACA;CACF;AACF"}
@@ -1,2 +1,2 @@
1
- require("../_dev.cjs");const e=require("../svg/element.cjs"),t=require("../interaction/legend.cjs"),n=require("../interaction/tooltip.cjs"),r=require("./chart-base.cjs");let i=require("@vielzeug/ripple");function a(t,n,r,i){e.removeChildren(t.series),e.removeChildren(t.grid),e.removeChildren(t.xAxis),e.removeChildren(t.yAxis),n?.update([]),r?.hide(),i?.hide()}function o(e,a,o,c){let l=r.createChartBase(e,{ariaLabel:a.ariaLabel,margin:a.margin}),u=a.tooltip?n.createTooltip(e,a.tooltip):null,d=a.legend?t.createLegend(e,a.legend):null,f=new AbortController,p=o(l,u,d,f.signal),m=!1,h=s(l.svg),g=(0,i.createScope)();g.run(()=>{(0,i.effect)(()=>{m||h.attach(c(p))},{scheduler:`microtask`})});let _=[];if(a.plugins){let t={container:e,dimensions:l.dimensions,disposalSignal:f.signal,svg:l.svg};for(let e of a.plugins)try{e.install(t),_.push(e)}catch{}}return{get disposalSignal(){return f.signal},dispose(){if(!m){m=!0,f.abort(),h.detach();for(let e of _)try{e.dispose()}catch{}u?.dispose(),d?.dispose(),g.dispose(),l.dispose()}},get disposed(){return m},el:l.svg,[Symbol.dispose](){this.dispose()}}}function s(e){let t=null;return{attach(n){t&&=(t.onMouseMove&&e.removeEventListener(`mousemove`,t.onMouseMove),t.onMouseLeave&&e.removeEventListener(`mouseleave`,t.onMouseLeave),t.onClick&&e.removeEventListener(`click`,t.onClick),null),n&&(t=n,n.onMouseMove&&e.addEventListener(`mousemove`,n.onMouseMove),n.onMouseLeave&&e.addEventListener(`mouseleave`,n.onMouseLeave),n.onClick&&e.addEventListener(`click`,n.onClick))},detach(){this.attach(void 0)}}}function c(t,n,r){return o(t,n,(n,r,i,a)=>{let o={grid:e.createSvgElement(`g`,{"aria-hidden":`true`,class:`prism-grid`}),series:e.createSvgElement(`g`,{class:`prism-series`}),xAxis:e.createSvgElement(`g`,{class:`prism-x-axis`}),yAxis:e.createSvgElement(`g`,{class:`prism-y-axis`})};return n.chartArea.appendChild(o.grid),n.chartArea.appendChild(o.xAxis),n.chartArea.appendChild(o.yAxis),n.chartArea.appendChild(o.series),{chartArea:n.chartArea,container:t,dimensions:n.dimensions,disposalSignal:a,groups:o,legend:i,svg:n.svg,tooltip:r}},r)}function l(e,t,n){return o(e,t,(t,n,r,i)=>({container:e,dimensions:t.dimensions,disposalSignal:i,legend:r,svg:t.svg,tooltip:n}),n)}exports.clearCartesianDom=a,exports.createChartScaffold=c,exports.createRadialScaffold=l;
1
+ require("../_dev.cjs");const e=require("../svg/element.cjs"),t=require("../interaction/legend.cjs"),n=require("../interaction/tooltip.cjs"),r=require("./chart-base.cjs");let i=require("@vielzeug/ripple");function a(t,n,r,i){e.removeChildren(t.series),e.removeChildren(t.grid),e.removeChildren(t.xAxis),e.removeChildren(t.yAxis),n?.update([]),r?.hide(),i?.hide()}function o(e,a,o,c){let l=r.createChartBase(e,{a11y:a.a11y,ariaLabel:a.ariaLabel,margin:a.margin}),u=a.tooltip?n.createTooltip(e,a.tooltip):null,d=a.legend?t.createLegend(e,a.legend):null,f=new AbortController,p=o(l,u,d,f.signal),m=!1,h=s(l.svg),g=(0,i.createScope)();g.run(()=>{(0,i.effect)(()=>{m||h.attach(c(p))},{scheduler:`microtask`})});let _=[];if(a.plugins){let t={container:e,dimensions:l.dimensions,disposalSignal:f.signal,svg:l.svg};for(let e of a.plugins)try{e.install(t),_.push(e)}catch{}}return{get disposalSignal(){return f.signal},dispose(){if(!m){m=!0,f.abort(),h.detach();for(let e of _)try{e.dispose()}catch{}u?.dispose(),d?.dispose(),g.dispose(),l.dispose()}},get disposed(){return m},el:l.svg,[Symbol.dispose](){this.dispose()}}}function s(e){let t=null;return{attach(n){t&&=(t.onMouseMove&&e.removeEventListener(`mousemove`,t.onMouseMove),t.onMouseLeave&&e.removeEventListener(`mouseleave`,t.onMouseLeave),t.onClick&&e.removeEventListener(`click`,t.onClick),t.onKeyDown&&e.removeEventListener(`keydown`,t.onKeyDown),null),n&&(t=n,n.onMouseMove&&e.addEventListener(`mousemove`,n.onMouseMove),n.onMouseLeave&&e.addEventListener(`mouseleave`,n.onMouseLeave),n.onClick&&e.addEventListener(`click`,n.onClick),n.onKeyDown&&e.addEventListener(`keydown`,n.onKeyDown))},detach(){this.attach(void 0)}}}function c(t,n,r){return o(t,n,(n,r,i,a)=>{let o={grid:e.createSvgElement(`g`,{"aria-hidden":`true`,class:`prism-grid`}),series:e.createSvgElement(`g`,{class:`prism-series`}),xAxis:e.createSvgElement(`g`,{class:`prism-x-axis`}),yAxis:e.createSvgElement(`g`,{class:`prism-y-axis`})};return n.chartArea.appendChild(o.grid),n.chartArea.appendChild(o.xAxis),n.chartArea.appendChild(o.yAxis),n.chartArea.appendChild(o.series),{chartArea:n.chartArea,container:t,dimensions:n.dimensions,disposalSignal:a,groups:o,legend:i,svg:n.svg,tooltip:r}},r)}function l(e,t,n){return o(e,t,(t,n,r,i)=>({container:e,dimensions:t.dimensions,disposalSignal:i,legend:r,svg:t.svg,tooltip:n}),n)}exports.clearCartesianDom=a,exports.createChartScaffold=c,exports.createRadialScaffold=l;
2
2
  //# sourceMappingURL=chart-scaffold.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-scaffold.cjs","names":[],"sources":["../../src/core/chart-scaffold.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { createScope, effect } from '@vielzeug/ripple';\n\nimport type { CrosshairState } from '../interaction/crosshair';\nimport type { LegendState } from '../interaction/legend';\nimport type { TooltipState } from '../interaction/tooltip';\nimport type { BaseChartConfig, ChartDimensions, ChartHandle, ChartPlugin, ChartPluginContext } from '../types';\n\nimport { error } from '../_dev';\nimport { createLegend } from '../interaction/legend';\nimport { createTooltip } from '../interaction/tooltip';\nimport { createSvgElement, removeChildren } from '../svg/element';\nimport { createChartBase } from './chart-base';\n\nexport interface ScaffoldGroups {\n grid: SVGGElement;\n series: SVGGElement;\n xAxis: SVGGElement;\n yAxis: SVGGElement;\n}\n\n/**\n * Clears a cartesian chart's series/grid/axis groups and hides its legend/tooltip/crosshair —\n * shared by every cartesian chart factory's \"no data\" early-return so a reactive series\n * transitioning to empty leaves a fully blank chart, not a half-cleared one.\n */\nexport function clearCartesianDom(\n groups: ScaffoldGroups,\n legend: LegendState | null,\n tooltip: TooltipState | null,\n crosshair?: CrosshairState | null,\n): void {\n removeChildren(groups.series);\n removeChildren(groups.grid);\n removeChildren(groups.xAxis);\n removeChildren(groups.yAxis);\n legend?.update([]);\n tooltip?.hide();\n crosshair?.hide();\n}\n\nexport interface ScaffoldContext {\n chartArea: SVGGElement;\n container: HTMLElement;\n dimensions: Readable<ChartDimensions>;\n /** Aborted when the chart is disposed — renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n groups: ScaffoldGroups;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface RadialScaffoldContext {\n container: HTMLElement;\n dimensions: Readable<ChartDimensions>;\n /** Aborted when the chart is disposed — renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface ChartEventHandlers {\n onClick?: (event: MouseEvent) => void;\n onMouseLeave?: (event: MouseEvent) => void;\n onMouseMove?: (event: MouseEvent) => void;\n}\n\nfunction runScaffold<TCtx>(\n container: HTMLElement,\n config: BaseChartConfig,\n buildCtx: (\n base: {\n chartArea: SVGGElement;\n dimensions: Readable<ChartDimensions>;\n svg: SVGSVGElement;\n },\n tooltip: TooltipState | null,\n legend: LegendState | null,\n disposalSignal: AbortSignal,\n ) => TCtx,\n renderFn: (ctx: TCtx) => ChartEventHandlers | void,\n): ChartHandle {\n const base = createChartBase(container, { ariaLabel: config.ariaLabel, margin: config.margin });\n const tooltip = config.tooltip ? createTooltip(container, config.tooltip) : null;\n const legend = config.legend ? createLegend(container, config.legend) : null;\n const ac = new AbortController();\n const ctx = buildCtx(base, tooltip, legend, ac.signal);\n\n let disposed = false;\n const events = makeEventManager(base.svg);\n\n const scope = createScope();\n\n scope.run(() => {\n effect(\n () => {\n if (disposed) return;\n\n events.attach(renderFn(ctx));\n },\n { scheduler: 'microtask' },\n );\n });\n\n const installedPlugins: ChartPlugin[] = [];\n\n if (config.plugins) {\n const pluginCtx: ChartPluginContext = {\n container,\n dimensions: base.dimensions,\n disposalSignal: ac.signal,\n svg: base.svg,\n };\n\n for (const plugin of config.plugins) {\n try {\n plugin.install(pluginCtx);\n installedPlugins.push(plugin);\n } catch (err) {\n error('A chart plugin threw during install() — skipping it; the rest of the chart still renders.', err);\n }\n }\n }\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ac.abort();\n events.detach();\n\n for (const p of installedPlugins) {\n try {\n p.dispose();\n } catch (err) {\n error('A chart plugin threw during dispose() — continuing to tear down the rest of the chart.', err);\n }\n }\n\n tooltip?.dispose();\n legend?.dispose();\n scope.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n el: base.svg,\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction makeEventManager(svg: SVGSVGElement): {\n attach(handlers: ChartEventHandlers | void): void;\n detach(): void;\n} {\n let active: ChartEventHandlers | null = null;\n\n return {\n attach(handlers) {\n if (active) {\n if (active.onMouseMove) svg.removeEventListener('mousemove', active.onMouseMove);\n\n if (active.onMouseLeave) svg.removeEventListener('mouseleave', active.onMouseLeave);\n\n if (active.onClick) svg.removeEventListener('click', active.onClick);\n\n active = null;\n }\n\n if (!handlers) return;\n\n active = handlers;\n\n if (handlers.onMouseMove) svg.addEventListener('mousemove', handlers.onMouseMove);\n\n if (handlers.onMouseLeave) svg.addEventListener('mouseleave', handlers.onMouseLeave);\n\n if (handlers.onClick) svg.addEventListener('click', handlers.onClick);\n },\n detach() {\n this.attach(undefined);\n },\n };\n}\n\n/**\n * Cartesian scaffold: provides grid/axis/series SVG groups and a reactive\n * render loop. `renderFn` is called inside a reactive effect; it returns\n * optional `ChartEventHandlers` that are attached/replaced on every render.\n */\nexport function createChartScaffold(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: ScaffoldContext) => ChartEventHandlers | void,\n): ChartHandle {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal) => {\n const groups: ScaffoldGroups = {\n // Grid lines are purely decorative relative to the root svg's own role=\"img\"/aria-label.\n // Axis groups are NOT hidden wholesale — they can contain a meaningful `.prism-axis-title`;\n // `renderAxis` marks its own decorative tick lines/labels individually instead.\n grid: createSvgElement('g', { 'aria-hidden': 'true', class: 'prism-grid' }),\n series: createSvgElement('g', { class: 'prism-series' }),\n xAxis: createSvgElement('g', { class: 'prism-x-axis' }),\n yAxis: createSvgElement('g', { class: 'prism-y-axis' }),\n };\n\n base.chartArea.appendChild(groups.grid);\n base.chartArea.appendChild(groups.xAxis);\n base.chartArea.appendChild(groups.yAxis);\n base.chartArea.appendChild(groups.series);\n\n return {\n chartArea: base.chartArea,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n groups,\n legend,\n svg: base.svg,\n tooltip,\n } satisfies ScaffoldContext;\n },\n renderFn,\n );\n}\n\n/**\n * Radial scaffold: for charts that do not use cartesian axis groups\n * (pie, donut, semi). Provides only tooltip, legend, and the SVG root.\n */\nexport function createRadialScaffold(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: RadialScaffoldContext) => ChartEventHandlers | void,\n): ChartHandle {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal) =>\n ({\n container,\n dimensions: base.dimensions,\n disposalSignal,\n legend,\n svg: base.svg,\n tooltip,\n }) satisfies RadialScaffoldContext,\n renderFn,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chart-scaffold.cjs","names":[],"sources":["../../src/core/chart-scaffold.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { createScope, effect } from '@vielzeug/ripple';\n\nimport type { CrosshairState } from '../interaction/crosshair';\nimport type { LegendState } from '../interaction/legend';\nimport type { TooltipState } from '../interaction/tooltip';\nimport type { BaseChartConfig, ChartDimensions, ChartHandle, ChartPlugin, ChartPluginContext } from '../types';\n\nimport { error } from '../_dev';\nimport { createLegend } from '../interaction/legend';\nimport { createTooltip } from '../interaction/tooltip';\nimport { createSvgElement, removeChildren } from '../svg/element';\nimport { createChartBase } from './chart-base';\n\nexport interface ScaffoldGroups {\n grid: SVGGElement;\n series: SVGGElement;\n xAxis: SVGGElement;\n yAxis: SVGGElement;\n}\n\n/**\n * Clears a cartesian chart's series/grid/axis groups and hides its legend/tooltip/crosshair —\n * shared by every cartesian chart factory's \"no data\" early-return so a reactive series\n * transitioning to empty leaves a fully blank chart, not a half-cleared one.\n */\nexport function clearCartesianDom(\n groups: ScaffoldGroups,\n legend: LegendState | null,\n tooltip: TooltipState | null,\n crosshair?: CrosshairState | null,\n): void {\n removeChildren(groups.series);\n removeChildren(groups.grid);\n removeChildren(groups.xAxis);\n removeChildren(groups.yAxis);\n legend?.update([]);\n tooltip?.hide();\n crosshair?.hide();\n}\n\nexport interface ScaffoldContext {\n chartArea: SVGGElement;\n container: HTMLElement;\n dimensions: Readable<ChartDimensions>;\n /** Aborted when the chart is disposed — renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n groups: ScaffoldGroups;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface RadialScaffoldContext {\n container: HTMLElement;\n dimensions: Readable<ChartDimensions>;\n /** Aborted when the chart is disposed — renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface ChartEventHandlers {\n onClick?: (event: MouseEvent) => void;\n onKeyDown?: (event: KeyboardEvent) => void;\n onMouseLeave?: (event: MouseEvent) => void;\n onMouseMove?: (event: MouseEvent) => void;\n}\n\nfunction runScaffold<TCtx>(\n container: HTMLElement,\n config: BaseChartConfig,\n buildCtx: (\n base: {\n chartArea: SVGGElement;\n dimensions: Readable<ChartDimensions>;\n svg: SVGSVGElement;\n },\n tooltip: TooltipState | null,\n legend: LegendState | null,\n disposalSignal: AbortSignal,\n ) => TCtx,\n renderFn: (ctx: TCtx) => ChartEventHandlers | void,\n): ChartHandle {\n const base = createChartBase(container, { a11y: config.a11y, ariaLabel: config.ariaLabel, margin: config.margin });\n const tooltip = config.tooltip ? createTooltip(container, config.tooltip) : null;\n const legend = config.legend ? createLegend(container, config.legend) : null;\n const ac = new AbortController();\n const ctx = buildCtx(base, tooltip, legend, ac.signal);\n\n let disposed = false;\n const events = makeEventManager(base.svg);\n\n const scope = createScope();\n\n scope.run(() => {\n effect(\n () => {\n if (disposed) return;\n\n events.attach(renderFn(ctx));\n },\n { scheduler: 'microtask' },\n );\n });\n\n const installedPlugins: ChartPlugin[] = [];\n\n if (config.plugins) {\n const pluginCtx: ChartPluginContext = {\n container,\n dimensions: base.dimensions,\n disposalSignal: ac.signal,\n svg: base.svg,\n };\n\n for (const plugin of config.plugins) {\n try {\n plugin.install(pluginCtx);\n installedPlugins.push(plugin);\n } catch (err) {\n error('A chart plugin threw during install() — skipping it; the rest of the chart still renders.', err);\n }\n }\n }\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ac.abort();\n events.detach();\n\n for (const p of installedPlugins) {\n try {\n p.dispose();\n } catch (err) {\n error('A chart plugin threw during dispose() — continuing to tear down the rest of the chart.', err);\n }\n }\n\n tooltip?.dispose();\n legend?.dispose();\n scope.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n el: base.svg,\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction makeEventManager(svg: SVGSVGElement): {\n attach(handlers: ChartEventHandlers | void): void;\n detach(): void;\n} {\n let active: ChartEventHandlers | null = null;\n\n return {\n attach(handlers) {\n if (active) {\n if (active.onMouseMove) svg.removeEventListener('mousemove', active.onMouseMove);\n\n if (active.onMouseLeave) svg.removeEventListener('mouseleave', active.onMouseLeave);\n\n if (active.onClick) svg.removeEventListener('click', active.onClick);\n\n if (active.onKeyDown) svg.removeEventListener('keydown', active.onKeyDown);\n\n active = null;\n }\n\n if (!handlers) return;\n\n active = handlers;\n\n if (handlers.onMouseMove) svg.addEventListener('mousemove', handlers.onMouseMove);\n\n if (handlers.onMouseLeave) svg.addEventListener('mouseleave', handlers.onMouseLeave);\n\n if (handlers.onClick) svg.addEventListener('click', handlers.onClick);\n\n if (handlers.onKeyDown) svg.addEventListener('keydown', handlers.onKeyDown);\n },\n detach() {\n this.attach(undefined);\n },\n };\n}\n\n/**\n * Cartesian scaffold: provides grid/axis/series SVG groups and a reactive\n * render loop. `renderFn` is called inside a reactive effect; it returns\n * optional `ChartEventHandlers` that are attached/replaced on every render.\n */\nexport function createChartScaffold(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: ScaffoldContext) => ChartEventHandlers | void,\n): ChartHandle {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal) => {\n const groups: ScaffoldGroups = {\n // Grid lines are purely decorative relative to the root svg's own role=\"img\"/aria-label.\n // Axis groups are NOT hidden wholesale — they can contain a meaningful `.prism-axis-title`;\n // `renderAxis` marks its own decorative tick lines/labels individually instead.\n grid: createSvgElement('g', { 'aria-hidden': 'true', class: 'prism-grid' }),\n series: createSvgElement('g', { class: 'prism-series' }),\n xAxis: createSvgElement('g', { class: 'prism-x-axis' }),\n yAxis: createSvgElement('g', { class: 'prism-y-axis' }),\n };\n\n base.chartArea.appendChild(groups.grid);\n base.chartArea.appendChild(groups.xAxis);\n base.chartArea.appendChild(groups.yAxis);\n base.chartArea.appendChild(groups.series);\n\n return {\n chartArea: base.chartArea,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n groups,\n legend,\n svg: base.svg,\n tooltip,\n } satisfies ScaffoldContext;\n },\n renderFn,\n );\n}\n\n/**\n * Radial scaffold: for charts that do not use cartesian axis groups\n * (pie, donut, semi). Provides only tooltip, legend, and the SVG root.\n */\nexport function createRadialScaffold(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: RadialScaffoldContext) => ChartEventHandlers | void,\n): ChartHandle {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal) =>\n ({\n container,\n dimensions: base.dimensions,\n disposalSignal,\n legend,\n svg: base.svg,\n tooltip,\n }) satisfies RadialScaffoldContext,\n renderFn,\n );\n}\n"],"mappings":"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"}
@@ -37,6 +37,7 @@ export interface RadialScaffoldContext {
37
37
  }
38
38
  export interface ChartEventHandlers {
39
39
  onClick?: (event: MouseEvent) => void;
40
+ onKeyDown?: (event: KeyboardEvent) => void;
40
41
  onMouseLeave?: (event: MouseEvent) => void;
41
42
  onMouseMove?: (event: MouseEvent) => void;
42
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"chart-scaffold.d.ts","sourceRoot":"","sources":["../../src/core/chart-scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAmC,MAAM,UAAU,CAAC;AAQ/G,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,OAAO,EAAE,YAAY,GAAG,IAAI,EAC5B,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,GAChC,IAAI,CAQN;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACtC,kIAAkI;IAClI,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACtC,kIAAkI;IAClI,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC3C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAC3C;AAmID;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,kBAAkB,GAAG,IAAI,GAC5D,WAAW,CAiCb;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,kBAAkB,GAAG,IAAI,GAClE,WAAW,CAeb"}
1
+ {"version":3,"file":"chart-scaffold.d.ts","sourceRoot":"","sources":["../../src/core/chart-scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAmC,MAAM,UAAU,CAAC;AAQ/G,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,OAAO,EAAE,YAAY,GAAG,IAAI,EAC5B,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,GAChC,IAAI,CAQN;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACtC,kIAAkI;IAClI,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACtC,kIAAkI;IAClI,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC3C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAC3C;AAuID;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,kBAAkB,GAAG,IAAI,GAC5D,WAAW,CAiCb;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,kBAAkB,GAAG,IAAI,GAClE,WAAW,CAeb"}
@@ -10,6 +10,7 @@ function s(e, n, r, i) {
10
10
  }
11
11
  function c(e, t, s, c) {
12
12
  let u = i(e, {
13
+ a11y: t.a11y,
13
14
  ariaLabel: t.ariaLabel,
14
15
  margin: t.margin
15
16
  }), d = t.tooltip ? r(e, t.tooltip) : null, f = t.legend ? n(e, t.legend) : null, p = new AbortController(), m = s(u, d, f, p.signal), h = !1, g = l(u.svg), _ = a();
@@ -56,7 +57,7 @@ function l(e) {
56
57
  let t = null;
57
58
  return {
58
59
  attach(n) {
59
- t &&= (t.onMouseMove && e.removeEventListener("mousemove", t.onMouseMove), t.onMouseLeave && e.removeEventListener("mouseleave", t.onMouseLeave), t.onClick && e.removeEventListener("click", t.onClick), null), n && (t = n, n.onMouseMove && e.addEventListener("mousemove", n.onMouseMove), n.onMouseLeave && e.addEventListener("mouseleave", n.onMouseLeave), n.onClick && e.addEventListener("click", n.onClick));
60
+ t &&= (t.onMouseMove && e.removeEventListener("mousemove", t.onMouseMove), t.onMouseLeave && e.removeEventListener("mouseleave", t.onMouseLeave), t.onClick && e.removeEventListener("click", t.onClick), t.onKeyDown && e.removeEventListener("keydown", t.onKeyDown), null), n && (t = n, n.onMouseMove && e.addEventListener("mousemove", n.onMouseMove), n.onMouseLeave && e.addEventListener("mouseleave", n.onMouseLeave), n.onClick && e.addEventListener("click", n.onClick), n.onKeyDown && e.addEventListener("keydown", n.onKeyDown));
60
61
  },
61
62
  detach() {
62
63
  this.attach(void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"chart-scaffold.js","names":[],"sources":["../../src/core/chart-scaffold.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { createScope, effect } from '@vielzeug/ripple';\n\nimport type { CrosshairState } from '../interaction/crosshair';\nimport type { LegendState } from '../interaction/legend';\nimport type { TooltipState } from '../interaction/tooltip';\nimport type { BaseChartConfig, ChartDimensions, ChartHandle, ChartPlugin, ChartPluginContext } from '../types';\n\nimport { error } from '../_dev';\nimport { createLegend } from '../interaction/legend';\nimport { createTooltip } from '../interaction/tooltip';\nimport { createSvgElement, removeChildren } from '../svg/element';\nimport { createChartBase } from './chart-base';\n\nexport interface ScaffoldGroups {\n grid: SVGGElement;\n series: SVGGElement;\n xAxis: SVGGElement;\n yAxis: SVGGElement;\n}\n\n/**\n * Clears a cartesian chart's series/grid/axis groups and hides its legend/tooltip/crosshair —\n * shared by every cartesian chart factory's \"no data\" early-return so a reactive series\n * transitioning to empty leaves a fully blank chart, not a half-cleared one.\n */\nexport function clearCartesianDom(\n groups: ScaffoldGroups,\n legend: LegendState | null,\n tooltip: TooltipState | null,\n crosshair?: CrosshairState | null,\n): void {\n removeChildren(groups.series);\n removeChildren(groups.grid);\n removeChildren(groups.xAxis);\n removeChildren(groups.yAxis);\n legend?.update([]);\n tooltip?.hide();\n crosshair?.hide();\n}\n\nexport interface ScaffoldContext {\n chartArea: SVGGElement;\n container: HTMLElement;\n dimensions: Readable<ChartDimensions>;\n /** Aborted when the chart is disposed — renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n groups: ScaffoldGroups;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface RadialScaffoldContext {\n container: HTMLElement;\n dimensions: Readable<ChartDimensions>;\n /** Aborted when the chart is disposed — renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface ChartEventHandlers {\n onClick?: (event: MouseEvent) => void;\n onMouseLeave?: (event: MouseEvent) => void;\n onMouseMove?: (event: MouseEvent) => void;\n}\n\nfunction runScaffold<TCtx>(\n container: HTMLElement,\n config: BaseChartConfig,\n buildCtx: (\n base: {\n chartArea: SVGGElement;\n dimensions: Readable<ChartDimensions>;\n svg: SVGSVGElement;\n },\n tooltip: TooltipState | null,\n legend: LegendState | null,\n disposalSignal: AbortSignal,\n ) => TCtx,\n renderFn: (ctx: TCtx) => ChartEventHandlers | void,\n): ChartHandle {\n const base = createChartBase(container, { ariaLabel: config.ariaLabel, margin: config.margin });\n const tooltip = config.tooltip ? createTooltip(container, config.tooltip) : null;\n const legend = config.legend ? createLegend(container, config.legend) : null;\n const ac = new AbortController();\n const ctx = buildCtx(base, tooltip, legend, ac.signal);\n\n let disposed = false;\n const events = makeEventManager(base.svg);\n\n const scope = createScope();\n\n scope.run(() => {\n effect(\n () => {\n if (disposed) return;\n\n events.attach(renderFn(ctx));\n },\n { scheduler: 'microtask' },\n );\n });\n\n const installedPlugins: ChartPlugin[] = [];\n\n if (config.plugins) {\n const pluginCtx: ChartPluginContext = {\n container,\n dimensions: base.dimensions,\n disposalSignal: ac.signal,\n svg: base.svg,\n };\n\n for (const plugin of config.plugins) {\n try {\n plugin.install(pluginCtx);\n installedPlugins.push(plugin);\n } catch (err) {\n error('A chart plugin threw during install() — skipping it; the rest of the chart still renders.', err);\n }\n }\n }\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ac.abort();\n events.detach();\n\n for (const p of installedPlugins) {\n try {\n p.dispose();\n } catch (err) {\n error('A chart plugin threw during dispose() — continuing to tear down the rest of the chart.', err);\n }\n }\n\n tooltip?.dispose();\n legend?.dispose();\n scope.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n el: base.svg,\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction makeEventManager(svg: SVGSVGElement): {\n attach(handlers: ChartEventHandlers | void): void;\n detach(): void;\n} {\n let active: ChartEventHandlers | null = null;\n\n return {\n attach(handlers) {\n if (active) {\n if (active.onMouseMove) svg.removeEventListener('mousemove', active.onMouseMove);\n\n if (active.onMouseLeave) svg.removeEventListener('mouseleave', active.onMouseLeave);\n\n if (active.onClick) svg.removeEventListener('click', active.onClick);\n\n active = null;\n }\n\n if (!handlers) return;\n\n active = handlers;\n\n if (handlers.onMouseMove) svg.addEventListener('mousemove', handlers.onMouseMove);\n\n if (handlers.onMouseLeave) svg.addEventListener('mouseleave', handlers.onMouseLeave);\n\n if (handlers.onClick) svg.addEventListener('click', handlers.onClick);\n },\n detach() {\n this.attach(undefined);\n },\n };\n}\n\n/**\n * Cartesian scaffold: provides grid/axis/series SVG groups and a reactive\n * render loop. `renderFn` is called inside a reactive effect; it returns\n * optional `ChartEventHandlers` that are attached/replaced on every render.\n */\nexport function createChartScaffold(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: ScaffoldContext) => ChartEventHandlers | void,\n): ChartHandle {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal) => {\n const groups: ScaffoldGroups = {\n // Grid lines are purely decorative relative to the root svg's own role=\"img\"/aria-label.\n // Axis groups are NOT hidden wholesale — they can contain a meaningful `.prism-axis-title`;\n // `renderAxis` marks its own decorative tick lines/labels individually instead.\n grid: createSvgElement('g', { 'aria-hidden': 'true', class: 'prism-grid' }),\n series: createSvgElement('g', { class: 'prism-series' }),\n xAxis: createSvgElement('g', { class: 'prism-x-axis' }),\n yAxis: createSvgElement('g', { class: 'prism-y-axis' }),\n };\n\n base.chartArea.appendChild(groups.grid);\n base.chartArea.appendChild(groups.xAxis);\n base.chartArea.appendChild(groups.yAxis);\n base.chartArea.appendChild(groups.series);\n\n return {\n chartArea: base.chartArea,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n groups,\n legend,\n svg: base.svg,\n tooltip,\n } satisfies ScaffoldContext;\n },\n renderFn,\n );\n}\n\n/**\n * Radial scaffold: for charts that do not use cartesian axis groups\n * (pie, donut, semi). Provides only tooltip, legend, and the SVG root.\n */\nexport function createRadialScaffold(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: RadialScaffoldContext) => ChartEventHandlers | void,\n): ChartHandle {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal) =>\n ({\n container,\n dimensions: base.dimensions,\n disposalSignal,\n legend,\n svg: base.svg,\n tooltip,\n }) satisfies RadialScaffoldContext,\n renderFn,\n );\n}\n"],"mappings":";;;;;;;AA2BA,SAAgB,EACd,GACA,GACA,GACA,GACM;CAON,AANA,EAAe,EAAO,MAAM,GAC5B,EAAe,EAAO,IAAI,GAC1B,EAAe,EAAO,KAAK,GAC3B,EAAe,EAAO,KAAK,GAC3B,GAAQ,OAAO,CAAC,CAAC,GACjB,GAAS,KAAK,GACd,GAAW,KAAK;AAClB;AA8BA,SAAS,EACP,GACA,GACA,GAUA,GACa;CACb,IAAM,IAAO,EAAgB,GAAW;EAAE,WAAW,EAAO;EAAW,QAAQ,EAAO;CAAO,CAAC,GACxF,IAAU,EAAO,UAAU,EAAc,GAAW,EAAO,OAAO,IAAI,MACtE,IAAS,EAAO,SAAS,EAAa,GAAW,EAAO,MAAM,IAAI,MAClE,IAAK,IAAI,gBAAgB,GACzB,IAAM,EAAS,GAAM,GAAS,GAAQ,EAAG,MAAM,GAEjD,IAAW,IACT,IAAS,EAAiB,EAAK,GAAG,GAElC,IAAQ,EAAY;CAE1B,EAAM,UAAU;EACd,QACQ;GACA,KAEJ,EAAO,OAAO,EAAS,CAAG,CAAC;EAC7B,GACA,EAAE,WAAW,YAAY,CAC3B;CACF,CAAC;CAED,IAAM,IAAkC,CAAC;CAEzC,IAAI,EAAO,SAAS;EAClB,IAAM,IAAgC;GACpC;GACA,YAAY,EAAK;GACjB,gBAAgB,EAAG;GACnB,KAAK,EAAK;EACZ;EAEA,KAAK,IAAM,KAAU,EAAO,SAC1B,IAAI;GAEF,AADA,EAAO,QAAQ,CAAS,GACxB,EAAiB,KAAK,CAAM;EAC9B,QAAc,CAEd;CAEJ;CAEA,OAAO;EACL,IAAI,iBAA8B;GAChC,OAAO,EAAG;EACZ;EAEA,UAAU;GACJ,QAIJ;IAFA,IAAW,IACX,EAAG,MAAM,GACT,EAAO,OAAO;IAEd,KAAK,IAAM,KAAK,GACd,IAAI;KACF,EAAE,QAAQ;IACZ,QAAc,CAEd;IAMF,AAHA,GAAS,QAAQ,GACjB,GAAQ,QAAQ,GAChB,EAAM,QAAQ,GACd,EAAK,QAAQ;GAbC;EAchB;EAEA,IAAI,WAAoB;GACtB,OAAO;EACT;EAEA,IAAI,EAAK;EAET,CAAC,OAAO,WAAW;GACjB,KAAK,QAAQ;EACf;CACF;AACF;AAEA,SAAS,EAAiB,GAGxB;CACA,IAAI,IAAoC;CAExC,OAAO;EACL,OAAO,GAAU;GACf,AAOE,OANI,EAAO,eAAa,EAAI,oBAAoB,aAAa,EAAO,WAAW,GAE3E,EAAO,gBAAc,EAAI,oBAAoB,cAAc,EAAO,YAAY,GAE9E,EAAO,WAAS,EAAI,oBAAoB,SAAS,EAAO,OAAO,GAE1D,OAGN,MAEL,IAAS,GAEL,EAAS,eAAa,EAAI,iBAAiB,aAAa,EAAS,WAAW,GAE5E,EAAS,gBAAc,EAAI,iBAAiB,cAAc,EAAS,YAAY,GAE/E,EAAS,WAAS,EAAI,iBAAiB,SAAS,EAAS,OAAO;EACtE;EACA,SAAS;GACP,KAAK,OAAO,KAAA,CAAS;EACvB;CACF;AACF;AAOA,SAAgB,EACd,GACA,GACA,GACa;CACb,OAAO,EACL,GACA,IACC,GAAM,GAAS,GAAQ,MAAmB;EACzC,IAAM,IAAyB;GAI7B,MAAM,EAAiB,KAAK;IAAE,eAAe;IAAQ,OAAO;GAAa,CAAC;GAC1E,QAAQ,EAAiB,KAAK,EAAE,OAAO,eAAe,CAAC;GACvD,OAAO,EAAiB,KAAK,EAAE,OAAO,eAAe,CAAC;GACtD,OAAO,EAAiB,KAAK,EAAE,OAAO,eAAe,CAAC;EACxD;EAOA,OALA,EAAK,UAAU,YAAY,EAAO,IAAI,GACtC,EAAK,UAAU,YAAY,EAAO,KAAK,GACvC,EAAK,UAAU,YAAY,EAAO,KAAK,GACvC,EAAK,UAAU,YAAY,EAAO,MAAM,GAEjC;GACL,WAAW,EAAK;GAChB;GACA,YAAY,EAAK;GACjB;GACA;GACA;GACA,KAAK,EAAK;GACV;EACF;CACF,GACA,CACF;AACF;AAMA,SAAgB,EACd,GACA,GACA,GACa;CACb,OAAO,EACL,GACA,IACC,GAAM,GAAS,GAAQ,OACrB;EACC;EACA,YAAY,EAAK;EACjB;EACA;EACA,KAAK,EAAK;EACV;CACF,IACF,CACF;AACF"}
1
+ {"version":3,"file":"chart-scaffold.js","names":[],"sources":["../../src/core/chart-scaffold.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { createScope, effect } from '@vielzeug/ripple';\n\nimport type { CrosshairState } from '../interaction/crosshair';\nimport type { LegendState } from '../interaction/legend';\nimport type { TooltipState } from '../interaction/tooltip';\nimport type { BaseChartConfig, ChartDimensions, ChartHandle, ChartPlugin, ChartPluginContext } from '../types';\n\nimport { error } from '../_dev';\nimport { createLegend } from '../interaction/legend';\nimport { createTooltip } from '../interaction/tooltip';\nimport { createSvgElement, removeChildren } from '../svg/element';\nimport { createChartBase } from './chart-base';\n\nexport interface ScaffoldGroups {\n grid: SVGGElement;\n series: SVGGElement;\n xAxis: SVGGElement;\n yAxis: SVGGElement;\n}\n\n/**\n * Clears a cartesian chart's series/grid/axis groups and hides its legend/tooltip/crosshair —\n * shared by every cartesian chart factory's \"no data\" early-return so a reactive series\n * transitioning to empty leaves a fully blank chart, not a half-cleared one.\n */\nexport function clearCartesianDom(\n groups: ScaffoldGroups,\n legend: LegendState | null,\n tooltip: TooltipState | null,\n crosshair?: CrosshairState | null,\n): void {\n removeChildren(groups.series);\n removeChildren(groups.grid);\n removeChildren(groups.xAxis);\n removeChildren(groups.yAxis);\n legend?.update([]);\n tooltip?.hide();\n crosshair?.hide();\n}\n\nexport interface ScaffoldContext {\n chartArea: SVGGElement;\n container: HTMLElement;\n dimensions: Readable<ChartDimensions>;\n /** Aborted when the chart is disposed — renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n groups: ScaffoldGroups;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface RadialScaffoldContext {\n container: HTMLElement;\n dimensions: Readable<ChartDimensions>;\n /** Aborted when the chart is disposed — renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface ChartEventHandlers {\n onClick?: (event: MouseEvent) => void;\n onKeyDown?: (event: KeyboardEvent) => void;\n onMouseLeave?: (event: MouseEvent) => void;\n onMouseMove?: (event: MouseEvent) => void;\n}\n\nfunction runScaffold<TCtx>(\n container: HTMLElement,\n config: BaseChartConfig,\n buildCtx: (\n base: {\n chartArea: SVGGElement;\n dimensions: Readable<ChartDimensions>;\n svg: SVGSVGElement;\n },\n tooltip: TooltipState | null,\n legend: LegendState | null,\n disposalSignal: AbortSignal,\n ) => TCtx,\n renderFn: (ctx: TCtx) => ChartEventHandlers | void,\n): ChartHandle {\n const base = createChartBase(container, { a11y: config.a11y, ariaLabel: config.ariaLabel, margin: config.margin });\n const tooltip = config.tooltip ? createTooltip(container, config.tooltip) : null;\n const legend = config.legend ? createLegend(container, config.legend) : null;\n const ac = new AbortController();\n const ctx = buildCtx(base, tooltip, legend, ac.signal);\n\n let disposed = false;\n const events = makeEventManager(base.svg);\n\n const scope = createScope();\n\n scope.run(() => {\n effect(\n () => {\n if (disposed) return;\n\n events.attach(renderFn(ctx));\n },\n { scheduler: 'microtask' },\n );\n });\n\n const installedPlugins: ChartPlugin[] = [];\n\n if (config.plugins) {\n const pluginCtx: ChartPluginContext = {\n container,\n dimensions: base.dimensions,\n disposalSignal: ac.signal,\n svg: base.svg,\n };\n\n for (const plugin of config.plugins) {\n try {\n plugin.install(pluginCtx);\n installedPlugins.push(plugin);\n } catch (err) {\n error('A chart plugin threw during install() — skipping it; the rest of the chart still renders.', err);\n }\n }\n }\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ac.abort();\n events.detach();\n\n for (const p of installedPlugins) {\n try {\n p.dispose();\n } catch (err) {\n error('A chart plugin threw during dispose() — continuing to tear down the rest of the chart.', err);\n }\n }\n\n tooltip?.dispose();\n legend?.dispose();\n scope.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n el: base.svg,\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction makeEventManager(svg: SVGSVGElement): {\n attach(handlers: ChartEventHandlers | void): void;\n detach(): void;\n} {\n let active: ChartEventHandlers | null = null;\n\n return {\n attach(handlers) {\n if (active) {\n if (active.onMouseMove) svg.removeEventListener('mousemove', active.onMouseMove);\n\n if (active.onMouseLeave) svg.removeEventListener('mouseleave', active.onMouseLeave);\n\n if (active.onClick) svg.removeEventListener('click', active.onClick);\n\n if (active.onKeyDown) svg.removeEventListener('keydown', active.onKeyDown);\n\n active = null;\n }\n\n if (!handlers) return;\n\n active = handlers;\n\n if (handlers.onMouseMove) svg.addEventListener('mousemove', handlers.onMouseMove);\n\n if (handlers.onMouseLeave) svg.addEventListener('mouseleave', handlers.onMouseLeave);\n\n if (handlers.onClick) svg.addEventListener('click', handlers.onClick);\n\n if (handlers.onKeyDown) svg.addEventListener('keydown', handlers.onKeyDown);\n },\n detach() {\n this.attach(undefined);\n },\n };\n}\n\n/**\n * Cartesian scaffold: provides grid/axis/series SVG groups and a reactive\n * render loop. `renderFn` is called inside a reactive effect; it returns\n * optional `ChartEventHandlers` that are attached/replaced on every render.\n */\nexport function createChartScaffold(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: ScaffoldContext) => ChartEventHandlers | void,\n): ChartHandle {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal) => {\n const groups: ScaffoldGroups = {\n // Grid lines are purely decorative relative to the root svg's own role=\"img\"/aria-label.\n // Axis groups are NOT hidden wholesale — they can contain a meaningful `.prism-axis-title`;\n // `renderAxis` marks its own decorative tick lines/labels individually instead.\n grid: createSvgElement('g', { 'aria-hidden': 'true', class: 'prism-grid' }),\n series: createSvgElement('g', { class: 'prism-series' }),\n xAxis: createSvgElement('g', { class: 'prism-x-axis' }),\n yAxis: createSvgElement('g', { class: 'prism-y-axis' }),\n };\n\n base.chartArea.appendChild(groups.grid);\n base.chartArea.appendChild(groups.xAxis);\n base.chartArea.appendChild(groups.yAxis);\n base.chartArea.appendChild(groups.series);\n\n return {\n chartArea: base.chartArea,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n groups,\n legend,\n svg: base.svg,\n tooltip,\n } satisfies ScaffoldContext;\n },\n renderFn,\n );\n}\n\n/**\n * Radial scaffold: for charts that do not use cartesian axis groups\n * (pie, donut, semi). Provides only tooltip, legend, and the SVG root.\n */\nexport function createRadialScaffold(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: RadialScaffoldContext) => ChartEventHandlers | void,\n): ChartHandle {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal) =>\n ({\n container,\n dimensions: base.dimensions,\n disposalSignal,\n legend,\n svg: base.svg,\n tooltip,\n }) satisfies RadialScaffoldContext,\n renderFn,\n );\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { AreaChartConfig, AreaSeriesConfig, AxisConfig, AxisPosition, BandScale, BarChartConfig, BarSeriesConfig, BarVariant, BaseChartConfig, ChartDimensions, ChartEvent, ChartHandle, ChartMargin, ChartPlugin, ChartPluginContext, CrosshairConfig, Datum, GridConfig, LegendConfig, LegendPosition, LineChartConfig, LineSeriesConfig, MaybeSignal, PieChartConfig, PieSliceConfig, PieVariant, PrismTheme, Scale, Series, SparklineConfig, SparklineVariant, StackSegment, TooltipConfig, TransitionConfig, } from './types';
1
+ export type { AreaChartConfig, AreaSeriesConfig, AxisConfig, AxisPosition, BandScale, BarChartConfig, BarSeriesConfig, BarVariant, BaseChartConfig, ChartA11y, ChartDimensions, ChartEvent, ChartHandle, ChartMargin, ChartPlugin, ChartPluginContext, CrosshairConfig, Datum, GridConfig, LegendConfig, LegendPosition, LineChartConfig, LineSeriesConfig, MaybeSignal, PieChartConfig, PieSliceConfig, PieVariant, PrismTheme, Scale, Series, SparklineConfig, SparklineVariant, StackSegment, TooltipConfig, TransitionConfig, } from './types';
2
2
  export { PrismDisposedError, PrismError, PrismRenderError } from './errors';
3
3
  export { createAreaChart } from './charts/area';
4
4
  export { createBarChart } from './charts/bar';
@@ -14,6 +14,5 @@ export type { EasingFn } from './animation/easing';
14
14
  export type { LegendState } from './interaction/legend';
15
15
  export type { TooltipState } from './interaction/tooltip';
16
16
  export type { Point } from './svg/path';
17
- export type { ChartEventHandlers, RadialScaffoldContext, ScaffoldContext, ScaffoldGroups } from './core/chart-scaffold';
18
17
  export { resetTheme, seriesColor, setTheme } from './theme';
19
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,SAAS,EACT,cAAc,EACd,eAAe,EACf,UAAU,EACV,eAAe,EACf,eAAe,EACf,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,KAAK,EACL,UAAU,EACV,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,cAAc,EACd,UAAU,EACV,UAAU,EACV,KAAK,EACL,MAAM,EACN,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAG5E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAG1D,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGxH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,SAAS,EACT,cAAc,EACd,eAAe,EACf,UAAU,EACV,eAAe,EACf,SAAS,EACT,eAAe,EACf,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,KAAK,EACL,UAAU,EACV,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,cAAc,EACd,UAAU,EACV,UAAU,EACV,KAAK,EACL,MAAM,EACN,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAG5E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAG1D,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC"}
@@ -1,2 +1,2 @@
1
- const e=require("../core/layout.cjs"),t=require("./events.cjs"),n=require("./hit-test.cjs");function r(e,t,n){let r=0,i=1/0;for(let a=0;a<e.length;a++){let o=e[a]?.[t];if(o){let e=Math.abs(o.y-n);e<i&&(i=e,r=a)}}return r}function i(i){return{onClick:a=>{if(!i.onClick)return;let o=i.getPoints();if(o.length===0||o[0].length===0)return;let s=i.dims(),c=t.getMousePosition(i.svg,a,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=n.nearestPointX(o[0],c.x);if(u<0)return;let d=r(o,u,c.y),f=i.getData()[d]?.[u],p=i.getSeriesList()[d];f&&p&&i.onClick({datum:f,originalEvent:a,series:p})},onMouseLeave:()=>{i.crosshair?.hide(),i.tooltip?.hide(),i.onHover?.(null)},onMouseMove:a=>{let o=i.getPoints();if(o.length===0||o[0].length===0)return;let s=i.dims(),c=t.getMousePosition(i.svg,a,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){i.crosshair?.hide(),i.tooltip?.hide();return}let u=o[0]??[],d=n.nearestPointX(u,c.x);if(d<0)return;let f=u[d],p=i.crosshair?.snap===!1?c.x:f.x,m=i.crosshair?.snap===!1?c.y:f.y,h=r(o,d,c.y),g=o[h]?.[d],_=i.getData()[h]?.[d],v=i.getSeriesList()[h];i.crosshair?.show(p,m,l.width,l.height,v&&_?`${v.name}: ${_.value}`:void 0),g&&_&&v&&(i.tooltip?.show(g.x+s.margin.left,g.y+s.margin.top,_,v),i.onHover?.({datum:_,originalEvent:a,series:v}))}}}exports.createSeriesInteraction=i;
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;
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 type { ChartEventHandlers } from '../core/chart-scaffold';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series } from '../types';\nimport type { CrosshairState } from './crosshair';\nimport type { TooltipState } from './tooltip';\n\nimport { chartArea } from '../core/layout';\nimport { getMousePosition } from './events';\nimport { nearestPointX } from './hit-test';\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\nfunction findNearestSeries(allPoints: Point[][], idx: number, posY: number): number {\n let nearestSi = 0;\n let minYDist = Infinity;\n\n for (let si = 0; si < allPoints.length; si++) {\n const pt = allPoints[si]?.[idx];\n\n if (pt) {\n const d = Math.abs(pt.y - posY);\n\n if (d < minYDist) {\n minYDist = d;\n nearestSi = si;\n }\n }\n }\n\n return nearestSi;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\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 baseSeries = allPoints[0] ?? [];\n const idx = nearestPointX(baseSeries, pos.x);\n\n if (idx < 0) return;\n\n const pt = baseSeries[idx];\n const crosshairX = opts.crosshair?.snap === false ? pos.x : pt.x;\n const crosshairY = opts.crosshair?.snap === false ? pos.y : pt.y;\n\n const nearestSi = findNearestSeries(allPoints, idx, pos.y);\n const siPt = allPoints[nearestSi]?.[idx];\n const dataPoint = opts.getData()[nearestSi]?.[idx];\n const series = opts.getSeriesList()[nearestSi];\n\n opts.crosshair?.show(\n crosshairX,\n crosshairY,\n area.width,\n area.height,\n series && dataPoint ? `${series.name}: ${dataPoint.value}` : undefined,\n );\n\n if (siPt && dataPoint && series) {\n opts.tooltip?.show(siPt.x + dims.margin.left, siPt.y + dims.margin.top, dataPoint, series);\n opts.onHover?.({ datum: dataPoint, 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 idx = nearestPointX(allPoints[0], pos.x);\n\n if (idx < 0) return;\n\n const nearestSi = findNearestSeries(allPoints, idx, pos.y);\n const dataPoint = opts.getData()[nearestSi]?.[idx];\n const series = opts.getSeriesList()[nearestSi];\n\n if (dataPoint && series) {\n opts.onClick({ datum: dataPoint, originalEvent: event, series });\n }\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n}\n"],"mappings":"4FAsBA,SAAS,EAAkB,EAAsB,EAAa,EAAsB,CAClF,IAAI,EAAY,EACZ,EAAW,IAEf,IAAK,IAAI,EAAK,EAAG,EAAK,EAAU,OAAQ,IAAM,CAC5C,IAAM,EAAK,EAAU,EAAG,GAAG,GAE3B,GAAI,EAAI,CACN,IAAM,EAAI,KAAK,IAAI,EAAG,EAAI,CAAI,EAE1B,EAAI,IACN,EAAW,EACX,EAAY,EAEhB,CACF,CAEA,OAAO,CACT,CAEA,SAAgB,EAAwB,EAAoD,CA6E1F,MAAO,CAAE,QA1BQ,GAAsB,CACrC,GAAI,CAAC,EAAK,QAAS,OAEnB,IAAM,EAAY,EAAK,UAAU,EAEjC,GAAI,EAAU,SAAW,GAAK,EAAU,EAAE,CAAC,SAAW,EAAG,OAEzD,IAAM,EAAO,EAAK,KAAK,EACjB,EAAM,EAAA,iBAAiB,EAAK,IAAK,EAAO,EAAK,OAAO,KAAM,EAAK,OAAO,GAAG,EACzE,EAAO,EAAA,UAAU,EAAK,MAAO,EAAK,OAAQ,EAAK,MAAM,EAE3D,GAAI,EAAI,EAAI,GAAK,EAAI,EAAI,EAAK,OAAS,EAAI,EAAI,GAAK,EAAI,EAAI,EAAK,OAAQ,OAEzE,IAAM,EAAM,EAAA,cAAc,EAAU,GAAI,EAAI,CAAC,EAE7C,GAAI,EAAM,EAAG,OAEb,IAAM,EAAY,EAAkB,EAAW,EAAK,EAAI,CAAC,EACnD,EAAY,EAAK,QAAQ,CAAC,CAAC,EAAU,GAAG,GACxC,EAAS,EAAK,cAAc,CAAC,CAAC,GAEhC,GAAa,GACf,EAAK,QAAQ,CAAE,MAAO,EAAW,cAAe,EAAO,QAAO,CAAC,CAEnE,EAEkB,iBAhCS,CACzB,EAAK,WAAW,KAAK,EACrB,EAAK,SAAS,KAAK,EACnB,EAAK,UAAU,IAAI,CACrB,EA4BgC,YA5EX,GAAsB,CACzC,IAAM,EAAY,EAAK,UAAU,EAEjC,GAAI,EAAU,SAAW,GAAK,EAAU,EAAE,CAAC,SAAW,EAAG,OAEzD,IAAM,EAAO,EAAK,KAAK,EACjB,EAAM,EAAA,iBAAiB,EAAK,IAAK,EAAO,EAAK,OAAO,KAAM,EAAK,OAAO,GAAG,EACzE,EAAO,EAAA,UAAU,EAAK,MAAO,EAAK,OAAQ,EAAK,MAAM,EAE3D,GAAI,EAAI,EAAI,GAAK,EAAI,EAAI,EAAK,OAAS,EAAI,EAAI,GAAK,EAAI,EAAI,EAAK,OAAQ,CACvE,EAAK,WAAW,KAAK,EACrB,EAAK,SAAS,KAAK,EAEnB,MACF,CAEA,IAAM,EAAa,EAAU,IAAM,CAAC,EAC9B,EAAM,EAAA,cAAc,EAAY,EAAI,CAAC,EAE3C,GAAI,EAAM,EAAG,OAEb,IAAM,EAAK,EAAW,GAChB,EAAa,EAAK,WAAW,OAAS,GAAQ,EAAI,EAAI,EAAG,EACzD,EAAa,EAAK,WAAW,OAAS,GAAQ,EAAI,EAAI,EAAG,EAEzD,EAAY,EAAkB,EAAW,EAAK,EAAI,CAAC,EACnD,EAAO,EAAU,EAAU,GAAG,GAC9B,EAAY,EAAK,QAAQ,CAAC,CAAC,EAAU,GAAG,GACxC,EAAS,EAAK,cAAc,CAAC,CAAC,GAEpC,EAAK,WAAW,KACd,EACA,EACA,EAAK,MACL,EAAK,OACL,GAAU,EAAY,GAAG,EAAO,KAAK,IAAI,EAAU,QAAU,IAAA,EAC/D,EAEI,GAAQ,GAAa,IACvB,EAAK,SAAS,KAAK,EAAK,EAAI,EAAK,OAAO,KAAM,EAAK,EAAI,EAAK,OAAO,IAAK,EAAW,CAAM,EACzF,EAAK,UAAU,CAAE,MAAO,EAAW,cAAe,EAAO,QAAO,CAAC,EAErE,CAkC4C,CAC9C"}
1
+ {"version":3,"file":"series-interaction.cjs","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import type { ChartEventHandlers } from '../core/chart-scaffold';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series } from '../types';\nimport type { CrosshairState } from './crosshair';\nimport type { TooltipState } from './tooltip';\n\nimport { keyId } from '../core/cartesian-model';\nimport { chartArea } from '../core/layout';\nimport { getMousePosition } from './events';\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 +1 @@
1
- {"version":3,"file":"series-interaction.d.ts","sourceRoot":"","sources":["../../src/interaction/series-interaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,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;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAM9C,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;AAsBD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG,kBAAkB,CA8E1F"}
1
+ {"version":3,"file":"series-interaction.d.ts","sourceRoot":"","sources":["../../src/interaction/series-interaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,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;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAM9C,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,58 +1,97 @@
1
1
  import { chartArea as e } from "../core/layout.js";
2
- import { getMousePosition as t } from "./events.js";
3
- import { nearestPointX as n } from "./hit-test.js";
2
+ import { keyId as t } from "../core/cartesian-model.js";
3
+ import { getMousePosition as n } from "./events.js";
4
4
  //#region src/interaction/series-interaction.ts
5
5
  function r(e, t, n) {
6
- let r = 0, i = Infinity;
7
- for (let a = 0; a < e.length; a++) {
8
- let o = e[a]?.[t];
9
- if (o) {
10
- let e = Math.abs(o.y - n);
11
- e < i && (i = e, r = a);
12
- }
6
+ let r = null, i = Infinity;
7
+ for (let a = 0; a < t.length; a++) for (let o = 0; o < (t[a]?.length ?? 0); o++) {
8
+ let s = e[a]?.[o], c = t[a]?.[o];
9
+ if (!s || !c) continue;
10
+ let l = Math.abs(c.x - n);
11
+ l < i && (i = l, r = s.key);
13
12
  }
14
13
  return r;
15
14
  }
16
- function i(i) {
15
+ function i(e, n, r, i) {
16
+ let a = t(r), o = null, s = Infinity;
17
+ for (let r = 0; r < n.length; r++) {
18
+ let c = e[r]?.findIndex((e) => t(e.key) === a) ?? -1, l = c === -1 ? void 0 : e[r]?.[c], u = c === -1 ? void 0 : n[r]?.[c];
19
+ if (!l || !u) continue;
20
+ let d = Number.isFinite(i) ? Math.abs(u.y - i) : 0;
21
+ d < s && (s = d, o = {
22
+ datum: l,
23
+ point: u,
24
+ seriesIndex: r
25
+ });
26
+ }
27
+ return o;
28
+ }
29
+ function a(a) {
30
+ let o = 0;
17
31
  return {
18
- onClick: (a) => {
19
- if (!i.onClick) return;
20
- let o = i.getPoints();
32
+ onClick: (t) => {
33
+ if (!a.onClick) return;
34
+ let o = a.getPoints();
21
35
  if (o.length === 0 || o[0].length === 0) return;
22
- let s = i.dims(), c = t(i.svg, a, s.margin.left, s.margin.top), l = e(s.width, s.height, s.margin);
36
+ let s = a.dims(), c = n(a.svg, t, s.margin.left, s.margin.top), l = e(s.width, s.height, s.margin);
23
37
  if (c.x < 0 || c.x > l.width || c.y < 0 || c.y > l.height) return;
24
- let u = n(o[0], c.x);
25
- if (u < 0) return;
26
- let d = r(o, u, c.y), f = i.getData()[d]?.[u], p = i.getSeriesList()[d];
27
- f && p && i.onClick({
28
- datum: f,
29
- originalEvent: a,
30
- series: p
38
+ let u = r(a.getData(), o, c.x);
39
+ if (u === null) return;
40
+ let d = i(a.getData(), o, u, c.y), f = d ? a.getSeriesList()[d.seriesIndex] : void 0;
41
+ d && f && a.onClick({
42
+ datum: d.datum,
43
+ originalEvent: t,
44
+ series: f
31
45
  });
32
46
  },
47
+ onKeyDown: (e) => {
48
+ let n = a.getData(), r = a.getPoints(), s = [...new Map(n.flat().map((e) => [t(e.key), e.key])).values()];
49
+ if (s.length !== 0) {
50
+ if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
51
+ e.preventDefault(), o = Math.max(0, Math.min(s.length - 1, o + (e.key === "ArrowLeft" ? -1 : 1)));
52
+ let t = s[o], c = i(n, r, t, Infinity), l = c ? a.getSeriesList()[c.seriesIndex] : void 0;
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?.({
55
+ datum: c.datum,
56
+ originalEvent: e,
57
+ series: l
58
+ });
59
+ }
60
+ if ((e.key === "Enter" || e.key === " ") && a.onClick) {
61
+ e.preventDefault();
62
+ let t = s[o], c = i(n, r, t, Infinity), l = c ? a.getSeriesList()[c.seriesIndex] : void 0;
63
+ c && l && a.onClick({
64
+ datum: c.datum,
65
+ originalEvent: e,
66
+ series: l
67
+ });
68
+ }
69
+ e.key === "Escape" && (a.crosshair?.hide(), a.tooltip?.hide(), a.onHover?.(null));
70
+ }
71
+ },
33
72
  onMouseLeave: () => {
34
- i.crosshair?.hide(), i.tooltip?.hide(), i.onHover?.(null);
73
+ a.crosshair?.hide(), a.tooltip?.hide(), a.onHover?.(null);
35
74
  },
36
- onMouseMove: (a) => {
37
- let o = i.getPoints();
75
+ onMouseMove: (t) => {
76
+ let o = a.getPoints();
38
77
  if (o.length === 0 || o[0].length === 0) return;
39
- let s = i.dims(), c = t(i.svg, a, s.margin.left, s.margin.top), l = e(s.width, s.height, s.margin);
78
+ let s = a.dims(), c = n(a.svg, t, s.margin.left, s.margin.top), l = e(s.width, s.height, s.margin);
40
79
  if (c.x < 0 || c.x > l.width || c.y < 0 || c.y > l.height) {
41
- i.crosshair?.hide(), i.tooltip?.hide();
80
+ a.crosshair?.hide(), a.tooltip?.hide();
42
81
  return;
43
82
  }
44
- let u = o[0] ?? [], d = n(u, c.x);
45
- if (d < 0) return;
46
- let f = u[d], p = i.crosshair?.snap === !1 ? c.x : f.x, m = i.crosshair?.snap === !1 ? c.y : f.y, h = r(o, d, c.y), g = o[h]?.[d], _ = i.getData()[h]?.[d], v = i.getSeriesList()[h];
47
- i.crosshair?.show(p, m, l.width, l.height, v && _ ? `${v.name}: ${_.value}` : void 0), g && _ && v && (i.tooltip?.show(g.x + s.margin.left, g.y + s.margin.top, _, v), i.onHover?.({
48
- datum: _,
49
- originalEvent: a,
50
- series: v
83
+ let u = r(a.getData(), o, c.x);
84
+ 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?.({
87
+ datum: d.datum,
88
+ originalEvent: t,
89
+ series: f
51
90
  }));
52
91
  }
53
92
  };
54
93
  }
55
94
  //#endregion
56
- export { i as createSeriesInteraction };
95
+ export { a as createSeriesInteraction };
57
96
 
58
97
  //# sourceMappingURL=series-interaction.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"series-interaction.js","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import type { ChartEventHandlers } from '../core/chart-scaffold';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series } from '../types';\nimport type { CrosshairState } from './crosshair';\nimport type { TooltipState } from './tooltip';\n\nimport { chartArea } from '../core/layout';\nimport { getMousePosition } from './events';\nimport { nearestPointX } from './hit-test';\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\nfunction findNearestSeries(allPoints: Point[][], idx: number, posY: number): number {\n let nearestSi = 0;\n let minYDist = Infinity;\n\n for (let si = 0; si < allPoints.length; si++) {\n const pt = allPoints[si]?.[idx];\n\n if (pt) {\n const d = Math.abs(pt.y - posY);\n\n if (d < minYDist) {\n minYDist = d;\n nearestSi = si;\n }\n }\n }\n\n return nearestSi;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\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 baseSeries = allPoints[0] ?? [];\n const idx = nearestPointX(baseSeries, pos.x);\n\n if (idx < 0) return;\n\n const pt = baseSeries[idx];\n const crosshairX = opts.crosshair?.snap === false ? pos.x : pt.x;\n const crosshairY = opts.crosshair?.snap === false ? pos.y : pt.y;\n\n const nearestSi = findNearestSeries(allPoints, idx, pos.y);\n const siPt = allPoints[nearestSi]?.[idx];\n const dataPoint = opts.getData()[nearestSi]?.[idx];\n const series = opts.getSeriesList()[nearestSi];\n\n opts.crosshair?.show(\n crosshairX,\n crosshairY,\n area.width,\n area.height,\n series && dataPoint ? `${series.name}: ${dataPoint.value}` : undefined,\n );\n\n if (siPt && dataPoint && series) {\n opts.tooltip?.show(siPt.x + dims.margin.left, siPt.y + dims.margin.top, dataPoint, series);\n opts.onHover?.({ datum: dataPoint, 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 idx = nearestPointX(allPoints[0], pos.x);\n\n if (idx < 0) return;\n\n const nearestSi = findNearestSeries(allPoints, idx, pos.y);\n const dataPoint = opts.getData()[nearestSi]?.[idx];\n const series = opts.getSeriesList()[nearestSi];\n\n if (dataPoint && series) {\n opts.onClick({ datum: dataPoint, originalEvent: event, series });\n }\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n}\n"],"mappings":";;;;AAsBA,SAAS,EAAkB,GAAsB,GAAa,GAAsB;CAClF,IAAI,IAAY,GACZ,IAAW;CAEf,KAAK,IAAI,IAAK,GAAG,IAAK,EAAU,QAAQ,KAAM;EAC5C,IAAM,IAAK,EAAU,EAAG,GAAG;EAE3B,IAAI,GAAI;GACN,IAAM,IAAI,KAAK,IAAI,EAAG,IAAI,CAAI;GAE9B,AAAI,IAAI,MACN,IAAW,GACX,IAAY;EAEhB;CACF;CAEA,OAAO;AACT;AAEA,SAAgB,EAAwB,GAAoD;CA6E1F,OAAO;EAAE,UA1BQ,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,EAAc,EAAU,IAAI,EAAI,CAAC;GAE7C,IAAI,IAAM,GAAG;GAEb,IAAM,IAAY,EAAkB,GAAW,GAAK,EAAI,CAAC,GACnD,IAAY,EAAK,QAAQ,CAAC,CAAC,EAAU,GAAG,IACxC,IAAS,EAAK,cAAc,CAAC,CAAC;GAEpC,AAAI,KAAa,KACf,EAAK,QAAQ;IAAE,OAAO;IAAW,eAAe;IAAO;GAAO,CAAC;EAEnE;EAEkB,oBAhCS;GAGzB,AAFA,EAAK,WAAW,KAAK,GACrB,EAAK,SAAS,KAAK,GACnB,EAAK,UAAU,IAAI;EACrB;EA4BgC,cA5EX,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,IAAa,EAAU,MAAM,CAAC,GAC9B,IAAM,EAAc,GAAY,EAAI,CAAC;GAE3C,IAAI,IAAM,GAAG;GAEb,IAAM,IAAK,EAAW,IAChB,IAAa,EAAK,WAAW,SAAS,KAAQ,EAAI,IAAI,EAAG,GACzD,IAAa,EAAK,WAAW,SAAS,KAAQ,EAAI,IAAI,EAAG,GAEzD,IAAY,EAAkB,GAAW,GAAK,EAAI,CAAC,GACnD,IAAO,EAAU,EAAU,GAAG,IAC9B,IAAY,EAAK,QAAQ,CAAC,CAAC,EAAU,GAAG,IACxC,IAAS,EAAK,cAAc,CAAC,CAAC;GAUpC,AARA,EAAK,WAAW,KACd,GACA,GACA,EAAK,OACL,EAAK,QACL,KAAU,IAAY,GAAG,EAAO,KAAK,IAAI,EAAU,UAAU,KAAA,CAC/D,GAEI,KAAQ,KAAa,MACvB,EAAK,SAAS,KAAK,EAAK,IAAI,EAAK,OAAO,MAAM,EAAK,IAAI,EAAK,OAAO,KAAK,GAAW,CAAM,GACzF,EAAK,UAAU;IAAE,OAAO;IAAW,eAAe;IAAO;GAAO,CAAC;EAErE;CAkC4C;AAC9C"}
1
+ {"version":3,"file":"series-interaction.js","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import type { ChartEventHandlers } from '../core/chart-scaffold';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series } from '../types';\nimport type { CrosshairState } from './crosshair';\nimport type { TooltipState } from './tooltip';\n\nimport { keyId } from '../core/cartesian-model';\nimport { chartArea } from '../core/layout';\nimport { getMousePosition } from './events';\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,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=()=>{r.remove()};return{dispose:s,el:r,hide(){r.style.opacity=`0`,r.textContent=``},show(n,s,c,l){if(!t.isConnected)return;if(a){let e=a(c,l);o?r.innerHTML=o(e):r.textContent=e}else r.textContent=`${l.name}: ${c.value}`;let{x:u,y:d}=(0,e.computePosition)({getBoundingClientRect:()=>{let e=t.getBoundingClientRect();return{bottom:e.top+s,height:0,left:e.left+n,right:e.left+n,top:e.top+s,width:0,x:e.left+n,y:e.top+s}}},r,{middleware:[(0,e.offset)(i),(0,e.flip)(),(0,e.shift)({padding:8})],placement:`top`}),f=t.getBoundingClientRect();r.style.left=`${u-f.left}px`,r.style.top=`${d-f.top}px`,r.style.opacity=`1`},[Symbol.dispose]:s}}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=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;
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';\n\nimport type { Datum, Series, TooltipConfig } from '../types';\n\nimport { warn } from '../_dev';\n\nexport interface TooltipState {\n dispose(): void;\n [Symbol.dispose](): void;\n el: HTMLDivElement | null;\n hide(): void;\n show(x: number, y: number, datum: Datum, series: Series): 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 const disposeHandle = (): void => {\n el.remove();\n };\n\n return {\n dispose: disposeHandle,\n el,\n hide() {\n el.style.opacity = '0';\n // Clear the live region's text too — otherwise assistive tech keeps announcing the\n // last-hovered value as \"current\" even after the pointer leaves the chart.\n el.textContent = '';\n },\n show(x: number, y: number, datum: Datum, series: Series) {\n if (!container.isConnected) return;\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: posX, y: posY } = computePosition(virtualRef, el, {\n middleware: [offset(tooltipOffset), flip(), shift({ padding: 8 })],\n placement: 'top',\n });\n\n const rect = container.getBoundingClientRect();\n\n el.style.left = `${posX - rect.left}px`;\n el.style.top = `${posY - rect.top}px`;\n el.style.opacity = '1';\n },\n [Symbol.dispose]: disposeHandle,\n };\n}\n"],"mappings":"wDAcA,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,SAQrC,MAA4B,CAChC,EAAG,OAAO,CACZ,EAEA,MAAO,CACL,QAAS,EACT,KACA,MAAO,CACL,EAAG,MAAM,QAAU,IAGnB,EAAG,YAAc,EACnB,EACA,KAAK,EAAW,EAAW,EAAc,EAAgB,CACvD,GAAI,CAAC,EAAU,YAAa,OAE5B,GAAI,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,EAAM,EAAG,IAAA,EAAS,EAAA,gBAAA,CAAgB,CAhB3C,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,CAG2C,EAAY,EAAI,CAC3D,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,EAEK,EAAO,EAAU,sBAAsB,EAE7C,EAAG,MAAM,KAAO,GAAG,EAAO,EAAK,KAAK,IACpC,EAAG,MAAM,IAAM,GAAG,EAAO,EAAK,IAAI,IAClC,EAAG,MAAM,QAAU,GACrB,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';\n\nimport type { Datum, Series, TooltipConfig } from '../types';\n\nimport { warn } from '../_dev';\n\nexport interface TooltipState {\n dispose(): void;\n [Symbol.dispose](): void;\n el: HTMLDivElement | null;\n hide(): void;\n show(x: number, y: number, datum: Datum, series: Series): 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":"wDAcA,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 +1 @@
1
- {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../src/interaction/tooltip.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAI7D,MAAM,WAAW,YAAY;IAC3B,OAAO,IAAI,IAAI,CAAC;IAChB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IACzB,EAAE,EAAE,cAAc,GAAG,IAAI,CAAC;IAC1B,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,YAAY,CAsFjG"}
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../src/interaction/tooltip.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAI7D,MAAM,WAAW,YAAY;IAC3B,OAAO,IAAI,IAAI,CAAC;IAChB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IACzB,EAAE,EAAE,cAAc,GAAG,IAAI,CAAC;IAC1B,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,YAAY,CA6HjG"}