@krizaka/charts 0.0.0-stage → 0.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 (273) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +47 -2
  3. package/dist/bar.d.ts +17 -0
  4. package/dist/bar.js +16 -0
  5. package/dist/bar.js.map +1 -0
  6. package/dist/candlestick-IG626XL4.js +13 -0
  7. package/dist/candlestick-IG626XL4.js.map +1 -0
  8. package/dist/candlestick.d.ts +42 -0
  9. package/dist/candlestick.js +13 -0
  10. package/dist/candlestick.js.map +1 -0
  11. package/dist/canvas-4MSYDVFO.js +14 -0
  12. package/dist/canvas-4MSYDVFO.js.map +1 -0
  13. package/dist/cartesian-BRhNQ3ib.d.ts +34 -0
  14. package/dist/chart.d.ts +58 -0
  15. package/dist/chart.js +11 -0
  16. package/dist/chart.js.map +1 -0
  17. package/dist/chunk-3CJHBJXA.js +186 -0
  18. package/dist/chunk-3CJHBJXA.js.map +1 -0
  19. package/dist/chunk-6FINSUOS.js +49 -0
  20. package/dist/chunk-6FINSUOS.js.map +1 -0
  21. package/dist/chunk-7CSAGFBW.js +166 -0
  22. package/dist/chunk-7CSAGFBW.js.map +1 -0
  23. package/dist/chunk-7TIFCK5E.js +103 -0
  24. package/dist/chunk-7TIFCK5E.js.map +1 -0
  25. package/dist/chunk-AHQXJSAQ.js +38 -0
  26. package/dist/chunk-AHQXJSAQ.js.map +1 -0
  27. package/dist/chunk-ANUCSRUN.js +43 -0
  28. package/dist/chunk-ANUCSRUN.js.map +1 -0
  29. package/dist/chunk-BISL7DYW.js +66 -0
  30. package/dist/chunk-BISL7DYW.js.map +1 -0
  31. package/dist/chunk-BZ5CQFPH.js +19 -0
  32. package/dist/chunk-BZ5CQFPH.js.map +1 -0
  33. package/dist/chunk-DWJPPEMC.js +455 -0
  34. package/dist/chunk-DWJPPEMC.js.map +1 -0
  35. package/dist/chunk-DZB6HEVO.js +73 -0
  36. package/dist/chunk-DZB6HEVO.js.map +1 -0
  37. package/dist/chunk-EK3Z647J.js +133 -0
  38. package/dist/chunk-EK3Z647J.js.map +1 -0
  39. package/dist/chunk-I5QUZVU2.js +234 -0
  40. package/dist/chunk-I5QUZVU2.js.map +1 -0
  41. package/dist/chunk-OB5EFDDH.js +118 -0
  42. package/dist/chunk-OB5EFDDH.js.map +1 -0
  43. package/dist/chunk-OER6ETT4.js +155 -0
  44. package/dist/chunk-OER6ETT4.js.map +1 -0
  45. package/dist/chunk-PTSB3H5Q.js +205 -0
  46. package/dist/chunk-PTSB3H5Q.js.map +1 -0
  47. package/dist/chunk-TPJDOB7R.js +15 -0
  48. package/dist/chunk-TPJDOB7R.js.map +1 -0
  49. package/dist/chunk-UNK4MJVG.js +378 -0
  50. package/dist/chunk-UNK4MJVG.js.map +1 -0
  51. package/dist/chunk-VKO2OYYM.js +88 -0
  52. package/dist/chunk-VKO2OYYM.js.map +1 -0
  53. package/dist/chunk-VKTZD7UT.js +107 -0
  54. package/dist/chunk-VKTZD7UT.js.map +1 -0
  55. package/dist/chunk-W5FX4TU3.js +102 -0
  56. package/dist/chunk-W5FX4TU3.js.map +1 -0
  57. package/dist/chunk-WBH2QU77.js +178 -0
  58. package/dist/chunk-WBH2QU77.js.map +1 -0
  59. package/dist/chunk-WIRCIOLH.js +145 -0
  60. package/dist/chunk-WIRCIOLH.js.map +1 -0
  61. package/dist/chunk-XAJ3KCC4.js +116 -0
  62. package/dist/chunk-XAJ3KCC4.js.map +1 -0
  63. package/dist/chunk-XC6BQ3RN.js +92 -0
  64. package/dist/chunk-XC6BQ3RN.js.map +1 -0
  65. package/dist/chunk-XLLYNNC6.js +89 -0
  66. package/dist/chunk-XLLYNNC6.js.map +1 -0
  67. package/dist/chunk-XR4ZJDOV.js +15 -0
  68. package/dist/chunk-XR4ZJDOV.js.map +1 -0
  69. package/dist/context-BgYUymEO.d.ts +163 -0
  70. package/dist/frame-I7_xYGy5.d.ts +45 -0
  71. package/dist/full-S2MBPEEP.js +11 -0
  72. package/dist/full-S2MBPEEP.js.map +1 -0
  73. package/dist/funnel-QU5ZPC52.js +13 -0
  74. package/dist/funnel-QU5ZPC52.js.map +1 -0
  75. package/dist/funnel.d.ts +26 -0
  76. package/dist/funnel.js +13 -0
  77. package/dist/funnel.js.map +1 -0
  78. package/dist/gauge.d.ts +38 -0
  79. package/dist/gauge.js +12 -0
  80. package/dist/gauge.js.map +1 -0
  81. package/dist/geo.d.ts +37 -0
  82. package/dist/geo.js +13 -0
  83. package/dist/geo.js.map +1 -0
  84. package/dist/globe.d.ts +36 -0
  85. package/dist/globe.js +12 -0
  86. package/dist/globe.js.map +1 -0
  87. package/dist/heatmap-JWQOKUGM.js +13 -0
  88. package/dist/heatmap-JWQOKUGM.js.map +1 -0
  89. package/dist/heatmap.d.ts +47 -0
  90. package/dist/heatmap.js +15 -0
  91. package/dist/heatmap.js.map +1 -0
  92. package/dist/host-_F8RgiIz.d.ts +15 -0
  93. package/dist/index.d.ts +22 -0
  94. package/dist/index.js +101 -0
  95. package/dist/index.js.map +1 -0
  96. package/dist/line.d.ts +25 -0
  97. package/dist/line.js +18 -0
  98. package/dist/line.js.map +1 -0
  99. package/dist/native.d.ts +300 -0
  100. package/dist/native.js +875 -0
  101. package/dist/native.js.map +1 -0
  102. package/dist/pie.d.ts +37 -0
  103. package/dist/pie.js +16 -0
  104. package/dist/pie.js.map +1 -0
  105. package/dist/provider.d.ts +73 -0
  106. package/dist/provider.js +24 -0
  107. package/dist/provider.js.map +1 -0
  108. package/dist/radar-75GRJ2IK.js +13 -0
  109. package/dist/radar-75GRJ2IK.js.map +1 -0
  110. package/dist/radar.d.ts +22 -0
  111. package/dist/radar.js +13 -0
  112. package/dist/radar.js.map +1 -0
  113. package/dist/sankey-XQTX2EG6.js +13 -0
  114. package/dist/sankey-XQTX2EG6.js.map +1 -0
  115. package/dist/sankey.d.ts +28 -0
  116. package/dist/sankey.js +13 -0
  117. package/dist/sankey.js.map +1 -0
  118. package/dist/scatter-XSNG4OKD.js +13 -0
  119. package/dist/scatter-XSNG4OKD.js.map +1 -0
  120. package/dist/scatter.d.ts +41 -0
  121. package/dist/scatter.js +15 -0
  122. package/dist/scatter.js.map +1 -0
  123. package/dist/sparkline.d.ts +26 -0
  124. package/dist/sparkline.js +15 -0
  125. package/dist/sparkline.js.map +1 -0
  126. package/dist/svg-BJUHYX3B.js +14 -0
  127. package/dist/svg-BJUHYX3B.js.map +1 -0
  128. package/dist/treemap-OMGGGB5U.js +13 -0
  129. package/dist/treemap-OMGGGB5U.js.map +1 -0
  130. package/dist/treemap.d.ts +24 -0
  131. package/dist/treemap.js +14 -0
  132. package/dist/treemap.js.map +1 -0
  133. package/dist/world-110m-DVFWXS42.js +18 -0
  134. package/dist/world-110m-DVFWXS42.js.map +1 -0
  135. package/package.json +518 -3
  136. package/registry/area-chart.json +784 -0
  137. package/registry/bar-chart.json +783 -0
  138. package/registry/calendar-heatmap.json +459 -0
  139. package/registry/candlestick.json +552 -0
  140. package/registry/chart.json +440 -0
  141. package/registry/charts-provider.json +190 -0
  142. package/registry/examples/area-chart/credits-usage.d.ts +4 -0
  143. package/registry/examples/area-chart/credits-usage.js +38 -0
  144. package/registry/examples/area-chart/credits-usage.tsx +32 -0
  145. package/registry/examples/area-chart/native/credits-usage.d.ts +4 -0
  146. package/registry/examples/area-chart/native/credits-usage.dark.png +0 -0
  147. package/registry/examples/area-chart/native/credits-usage.js +33 -0
  148. package/registry/examples/area-chart/native/credits-usage.light.png +0 -0
  149. package/registry/examples/area-chart/native/credits-usage.tsx +27 -0
  150. package/registry/examples/area-chart/storage.d.ts +4 -0
  151. package/registry/examples/area-chart/storage.js +27 -0
  152. package/registry/examples/area-chart/storage.tsx +21 -0
  153. package/registry/examples/bar-chart/jobs-by-status.d.ts +4 -0
  154. package/registry/examples/bar-chart/jobs-by-status.js +37 -0
  155. package/registry/examples/bar-chart/jobs-by-status.tsx +31 -0
  156. package/registry/examples/bar-chart/native/jobs-by-status.d.ts +4 -0
  157. package/registry/examples/bar-chart/native/jobs-by-status.dark.png +0 -0
  158. package/registry/examples/bar-chart/native/jobs-by-status.js +32 -0
  159. package/registry/examples/bar-chart/native/jobs-by-status.light.png +0 -0
  160. package/registry/examples/bar-chart/native/jobs-by-status.tsx +26 -0
  161. package/registry/examples/bar-chart/plans-by-quarter.d.ts +4 -0
  162. package/registry/examples/bar-chart/plans-by-quarter.js +31 -0
  163. package/registry/examples/bar-chart/plans-by-quarter.tsx +26 -0
  164. package/registry/examples/bar-chart/top-supporters.d.ts +4 -0
  165. package/registry/examples/bar-chart/top-supporters.js +32 -0
  166. package/registry/examples/bar-chart/top-supporters.tsx +27 -0
  167. package/registry/examples/calendar-heatmap/publishing.d.ts +4 -0
  168. package/registry/examples/calendar-heatmap/publishing.js +28 -0
  169. package/registry/examples/calendar-heatmap/publishing.tsx +23 -0
  170. package/registry/examples/candlestick/auction-bids.d.ts +4 -0
  171. package/registry/examples/candlestick/auction-bids.js +37 -0
  172. package/registry/examples/candlestick/auction-bids.tsx +32 -0
  173. package/registry/examples/chart/polar-uploads.d.ts +4 -0
  174. package/registry/examples/chart/polar-uploads.js +34 -0
  175. package/registry/examples/chart/polar-uploads.tsx +30 -0
  176. package/registry/examples/charts-provider/french-orazaka.d.ts +4 -0
  177. package/registry/examples/charts-provider/french-orazaka.js +26 -0
  178. package/registry/examples/charts-provider/french-orazaka.tsx +22 -0
  179. package/registry/examples/charts-provider/native/french-orazaka.d.ts +4 -0
  180. package/registry/examples/charts-provider/native/french-orazaka.dark.png +0 -0
  181. package/registry/examples/charts-provider/native/french-orazaka.js +17 -0
  182. package/registry/examples/charts-provider/native/french-orazaka.light.png +0 -0
  183. package/registry/examples/charts-provider/native/french-orazaka.tsx +17 -0
  184. package/registry/examples/funnel/signup.d.ts +4 -0
  185. package/registry/examples/funnel/signup.js +30 -0
  186. package/registry/examples/funnel/signup.tsx +24 -0
  187. package/registry/examples/gauge/challenge-goal.d.ts +4 -0
  188. package/registry/examples/gauge/challenge-goal.js +24 -0
  189. package/registry/examples/gauge/challenge-goal.tsx +18 -0
  190. package/registry/examples/gauge/credits-quota.d.ts +4 -0
  191. package/registry/examples/gauge/credits-quota.js +26 -0
  192. package/registry/examples/gauge/credits-quota.tsx +19 -0
  193. package/registry/examples/gauge/native/credits-quota.d.ts +4 -0
  194. package/registry/examples/gauge/native/credits-quota.dark.png +0 -0
  195. package/registry/examples/gauge/native/credits-quota.js +25 -0
  196. package/registry/examples/gauge/native/credits-quota.light.png +0 -0
  197. package/registry/examples/gauge/native/credits-quota.tsx +18 -0
  198. package/registry/examples/geo-map/viewers.d.ts +4 -0
  199. package/registry/examples/geo-map/viewers.js +43 -0
  200. package/registry/examples/geo-map/viewers.tsx +29 -0
  201. package/registry/examples/globe/deployment-regions.d.ts +4 -0
  202. package/registry/examples/globe/deployment-regions.js +36 -0
  203. package/registry/examples/globe/deployment-regions.tsx +30 -0
  204. package/registry/examples/heatmap/upload-activity.d.ts +4 -0
  205. package/registry/examples/heatmap/upload-activity.js +30 -0
  206. package/registry/examples/heatmap/upload-activity.tsx +25 -0
  207. package/registry/examples/line-chart/creator-earnings.d.ts +4 -0
  208. package/registry/examples/line-chart/creator-earnings.js +35 -0
  209. package/registry/examples/line-chart/creator-earnings.tsx +30 -0
  210. package/registry/examples/line-chart/forecast.d.ts +4 -0
  211. package/registry/examples/line-chart/forecast.js +36 -0
  212. package/registry/examples/line-chart/forecast.tsx +30 -0
  213. package/registry/examples/line-chart/live-jobs.d.ts +4 -0
  214. package/registry/examples/line-chart/live-jobs.js +21 -0
  215. package/registry/examples/line-chart/live-jobs.tsx +23 -0
  216. package/registry/examples/line-chart/native/creator-earnings.d.ts +4 -0
  217. package/registry/examples/line-chart/native/creator-earnings.dark.png +0 -0
  218. package/registry/examples/line-chart/native/creator-earnings.js +32 -0
  219. package/registry/examples/line-chart/native/creator-earnings.light.png +0 -0
  220. package/registry/examples/line-chart/native/creator-earnings.tsx +26 -0
  221. package/registry/examples/line-chart/states.d.ts +4 -0
  222. package/registry/examples/line-chart/states.js +16 -0
  223. package/registry/examples/line-chart/states.tsx +13 -0
  224. package/registry/examples/pie-chart/credit-spend.d.ts +4 -0
  225. package/registry/examples/pie-chart/credit-spend.js +30 -0
  226. package/registry/examples/pie-chart/credit-spend.tsx +24 -0
  227. package/registry/examples/pie-chart/native/credit-spend.d.ts +4 -0
  228. package/registry/examples/pie-chart/native/credit-spend.dark.png +0 -0
  229. package/registry/examples/pie-chart/native/credit-spend.js +17 -0
  230. package/registry/examples/pie-chart/native/credit-spend.light.png +0 -0
  231. package/registry/examples/pie-chart/native/credit-spend.tsx +12 -0
  232. package/registry/examples/pie-chart/storage-by-kind.d.ts +4 -0
  233. package/registry/examples/pie-chart/storage-by-kind.js +31 -0
  234. package/registry/examples/pie-chart/storage-by-kind.tsx +26 -0
  235. package/registry/examples/radar-chart/model-comparison.d.ts +4 -0
  236. package/registry/examples/radar-chart/model-comparison.js +33 -0
  237. package/registry/examples/radar-chart/model-comparison.tsx +28 -0
  238. package/registry/examples/sankey/credit-flow.d.ts +4 -0
  239. package/registry/examples/sankey/credit-flow.js +37 -0
  240. package/registry/examples/sankey/credit-flow.tsx +32 -0
  241. package/registry/examples/scatter-chart/watch-time.d.ts +4 -0
  242. package/registry/examples/scatter-chart/watch-time.js +36 -0
  243. package/registry/examples/scatter-chart/watch-time.tsx +31 -0
  244. package/registry/examples/sparkline/bars.d.ts +4 -0
  245. package/registry/examples/sparkline/bars.js +12 -0
  246. package/registry/examples/sparkline/bars.tsx +7 -0
  247. package/registry/examples/sparkline/native/stat-trend.d.ts +4 -0
  248. package/registry/examples/sparkline/native/stat-trend.dark.png +0 -0
  249. package/registry/examples/sparkline/native/stat-trend.js +12 -0
  250. package/registry/examples/sparkline/native/stat-trend.light.png +0 -0
  251. package/registry/examples/sparkline/native/stat-trend.tsx +7 -0
  252. package/registry/examples/sparkline/stat-trend.d.ts +4 -0
  253. package/registry/examples/sparkline/stat-trend.js +18 -0
  254. package/registry/examples/sparkline/stat-trend.tsx +15 -0
  255. package/registry/examples/sparkline/table-rows.d.ts +4 -0
  256. package/registry/examples/sparkline/table-rows.js +23 -0
  257. package/registry/examples/sparkline/table-rows.tsx +26 -0
  258. package/registry/examples/treemap/storage.d.ts +4 -0
  259. package/registry/examples/treemap/storage.js +17 -0
  260. package/registry/examples/treemap/storage.tsx +13 -0
  261. package/registry/funnel.json +486 -0
  262. package/registry/gauge.json +599 -0
  263. package/registry/geo-map.json +483 -0
  264. package/registry/globe.json +468 -0
  265. package/registry/heatmap.json +530 -0
  266. package/registry/index.json +420 -0
  267. package/registry/line-chart.json +792 -0
  268. package/registry/pie-chart.json +1287 -0
  269. package/registry/radar-chart.json +458 -0
  270. package/registry/sankey.json +502 -0
  271. package/registry/scatter-chart.json +558 -0
  272. package/registry/sparkline.json +562 -0
  273. package/registry/treemap.json +431 -0
@@ -0,0 +1,116 @@
1
+ "use client";
2
+ import {
3
+ EChartHost,
4
+ baseOption,
5
+ tooltipHtml
6
+ } from "./chunk-I5QUZVU2.js";
7
+ import {
8
+ read
9
+ } from "./chunk-W5FX4TU3.js";
10
+ import {
11
+ shareFormatter,
12
+ valueFormatter
13
+ } from "./chunk-XLLYNNC6.js";
14
+ import {
15
+ useSettings
16
+ } from "./chunk-DWJPPEMC.js";
17
+ import {
18
+ capitalize,
19
+ fill
20
+ } from "./chunk-3CJHBJXA.js";
21
+
22
+ // src/funnel/funnel.tsx
23
+ import { useCallback, useMemo } from "react";
24
+ import { jsx } from "react/jsx-runtime";
25
+ var engine = () => import("./funnel-QU5ZPC52.js");
26
+ function Funnel(props) {
27
+ const { data, label, value, format = "integer", stageLabel, valueLabel, fromFirstLabel = "% first", fromPreviousLabel = "% previous" } = props;
28
+ const { locale, labels } = useSettings(props);
29
+ const fmt = useMemo(() => ({ value: valueFormatter(format, locale, labels.noValue), share: shareFormatter(locale) }), [format, locale, labels.noValue]);
30
+ const stages = useMemo(() => data.map((d, i) => ({ label: String(read(label, d, i)), value: Math.max(0, Number(read(value, d, i)) || 0) })), [data, label, value]);
31
+ const isEmpty = stages.length === 0 || stages.every((s) => s.value === 0);
32
+ const first = stages[0]?.value ?? 0;
33
+ const rate = useCallback((i) => i === 0 || !stages[i - 1].value ? 1 : stages[i].value / stages[i - 1].value, [stages]);
34
+ const overall = first && stages.length ? stages[stages.length - 1].value / first : 0;
35
+ const summary = isEmpty ? labels.empty : [
36
+ fill(labels.summaryIntro, { kind: labels.kinds.funnel, count: stages.length }),
37
+ `${stages.slice(1).map((s, k) => fill(labels.summaryConversion, { from: stages[k].label, to: s.label, rate: fmt.share(rate(k + 1)) })).join(", ")}.`,
38
+ `${capitalize(fill(labels.summaryOverall, { rate: fmt.share(overall) }))}.`
39
+ ].join(" ");
40
+ const items = stages.map((s, i) => ({ seriesIndex: 0, dataIndex: i, text: `${s.label}: ${fmt.value(s.value)}${i ? ` (${fmt.share(rate(i))})` : ""}` }));
41
+ const build = useCallback(
42
+ (theme, size) => {
43
+ const base = baseOption(theme, true);
44
+ const steps = [...theme.ramp].reverse();
45
+ const labelRoom = Math.min(220, Math.max(120, size.width * 0.38));
46
+ return {
47
+ ...base,
48
+ tooltip: {
49
+ ...base.tooltip,
50
+ trigger: "item",
51
+ formatter: (p) => {
52
+ const i = p.dataIndex;
53
+ const s = stages[i];
54
+ return tooltipHtml(
55
+ s.label,
56
+ [
57
+ { label: valueLabel ?? labels.value, value: fmt.value(s.value) },
58
+ ...i ? [{ label: fromPreviousLabel, value: fmt.share(rate(i)) }] : [],
59
+ { label: fromFirstLabel, value: fmt.share(first ? s.value / first : 0) }
60
+ ]
61
+ );
62
+ }
63
+ },
64
+ series: [
65
+ {
66
+ type: "funnel",
67
+ sort: "none",
68
+ left: 8,
69
+ right: labelRoom,
70
+ top: 8,
71
+ bottom: 8,
72
+ minSize: "8%",
73
+ gap: 2,
74
+ data: stages.map((s, i) => ({ name: s.label, value: s.value, itemStyle: { color: steps[Math.round(i / Math.max(1, stages.length - 1) * (steps.length - 2))], borderWidth: 0 } })),
75
+ label: {
76
+ position: "right",
77
+ color: theme.text,
78
+ fontFamily: theme.font,
79
+ fontSize: 12,
80
+ formatter: (p) => {
81
+ const i = p.dataIndex;
82
+ return `{name|${stages[i].label}} {value|${fmt.value(stages[i].value)}}${i ? ` {rate|${fmt.share(rate(i))}}` : ""}`;
83
+ },
84
+ rich: { name: { color: theme.text2, fontSize: 12 }, value: { color: theme.text, fontWeight: 600, fontSize: 12 }, rate: { color: theme.text3, fontSize: 11 } }
85
+ },
86
+ labelLine: { lineStyle: { color: theme.axis } },
87
+ emphasis: { itemStyle: { borderColor: theme.text, borderWidth: 2 } }
88
+ }
89
+ ]
90
+ };
91
+ },
92
+ [stages, fmt, first, valueLabel, fromFirstLabel, fromPreviousLabel, labels.value, rate]
93
+ );
94
+ return /* @__PURE__ */ jsx(
95
+ EChartHost,
96
+ {
97
+ kind: "funnel",
98
+ frame: props,
99
+ defaultHeight: 280,
100
+ table: {
101
+ columns: [stageLabel ?? labels.category, valueLabel ?? labels.value, fromFirstLabel, fromPreviousLabel],
102
+ rows: stages.map((s, i) => [s.label, fmt.value(s.value), fmt.share(first ? s.value / first : 0), i ? fmt.share(rate(i)) : labels.noValue])
103
+ },
104
+ summary,
105
+ isEmpty,
106
+ engine,
107
+ build,
108
+ items
109
+ }
110
+ );
111
+ }
112
+
113
+ export {
114
+ Funnel
115
+ };
116
+ //# sourceMappingURL=chunk-XAJ3KCC4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/funnel/funnel.tsx"],"sourcesContent":["\"use client\";\n// Stages that lose people on the way — sign-up, verification, first video, first sale — with what the industry's\n// funnels leave out: the conversion from each stage to the next and from the first, written beside each stage, in the\n// summary and in the table. Ordinal steps of the brand hue (full → light), labels outside the shapes in the text\n// colours. ECharts, loaded when the chart nears the screen.\nimport { useCallback, useMemo } from \"react\";\n\nimport { read } from \"../core/data\";\nimport { shareFormatter, valueFormatter } from \"../core/format\";\nimport { capitalize, fill } from \"../core/labels\";\nimport type { Accessor, Datum, ValueFormat } from \"../core/types\";\nimport { EChartHost, type EngineProps, type WalkItem } from \"../echarts/host\";\nimport { baseOption, type ResolvedTheme, tooltipHtml } from \"../echarts/theme\";\nimport type { ChartFrameProps } from \"../web/frame\";\nimport { useSettings } from \"../web/frame\";\n\nconst engine = () => import(\"../echarts/engines/funnel\");\n\nexport interface FunnelProps<T extends Datum> extends ChartFrameProps, EngineProps {\n /** One row per stage, first stage first. */\n data: readonly T[];\n /** The field (or function) naming the stage. */\n label: Accessor<T, string>;\n /** The field of how many reached it. */\n value: Accessor<T, number>;\n /** How the counts are written. Default `\"integer\"`. */\n format?: ValueFormat;\n /** The headers of the data table: the stage, the count, the share of the first, of the previous. */\n stageLabel?: string;\n/** The header of the counts. */\n valueLabel?: string;\n/** The header of the share of the first stage. Default “% first”. */\n fromFirstLabel?: string;\n/** The header of the share of the previous stage. Default “% previous”. */\n fromPreviousLabel?: string;\n}\n\nexport function Funnel<T extends Datum>(props: FunnelProps<T>) {\n const { data, label, value, format = \"integer\", stageLabel, valueLabel, fromFirstLabel = \"% first\", fromPreviousLabel = \"% previous\" } = props;\n const { locale, labels } = useSettings(props);\n const fmt = useMemo(() => ({ value: valueFormatter(format, locale, labels.noValue), share: shareFormatter(locale) }), [format, locale, labels.noValue]);\n const stages = useMemo(() => data.map((d, i) => ({ label: String(read(label, d, i)), value: Math.max(0, Number(read(value, d, i)) || 0) })), [data, label, value]);\n const isEmpty = stages.length === 0 || stages.every((s) => s.value === 0);\n const first = stages[0]?.value ?? 0;\n const rate = useCallback((i: number) => (i === 0 || !stages[i - 1]!.value ? 1 : stages[i]!.value / stages[i - 1]!.value), [stages]);\n const overall = first && stages.length ? stages[stages.length - 1]!.value / first : 0;\n const summary = isEmpty\n ? labels.empty\n : [\n fill(labels.summaryIntro, { kind: labels.kinds.funnel, count: stages.length }),\n `${stages\n .slice(1)\n .map((s, k) => fill(labels.summaryConversion, { from: stages[k]!.label, to: s.label, rate: fmt.share(rate(k + 1)) }))\n .join(\", \")}.`,\n `${capitalize(fill(labels.summaryOverall, { rate: fmt.share(overall) }))}.`,\n ].join(\" \");\n const items: WalkItem[] = stages.map((s, i) => ({ seriesIndex: 0, dataIndex: i, text: `${s.label}: ${fmt.value(s.value)}${i ? ` (${fmt.share(rate(i))})` : \"\"}` }));\n\n const build = useCallback(\n (theme: ResolvedTheme, size: { width: number }) => {\n const base = baseOption(theme, true);\n const steps = [...theme.ramp].reverse();\n const labelRoom = Math.min(220, Math.max(120, size.width * 0.38));\n return {\n ...base,\n tooltip: {\n ...(base.tooltip as object),\n trigger: \"item\",\n formatter: (p: { dataIndex: number }) => {\n const i = p.dataIndex;\n const s = stages[i]!;\n return tooltipHtml(\n s.label,\n [\n { label: valueLabel ?? labels.value, value: fmt.value(s.value) },\n ...(i ? [{ label: fromPreviousLabel, value: fmt.share(rate(i)) }] : []),\n { label: fromFirstLabel, value: fmt.share(first ? s.value / first : 0) },\n ],\n );\n },\n },\n series: [\n {\n type: \"funnel\",\n sort: \"none\",\n left: 8,\n right: labelRoom,\n top: 8,\n bottom: 8,\n minSize: \"8%\",\n gap: 2,\n data: stages.map((s, i) => ({ name: s.label, value: s.value, itemStyle: { color: steps[Math.round((i / Math.max(1, stages.length - 1)) * (steps.length - 2))], borderWidth: 0 } })),\n label: {\n position: \"right\",\n color: theme.text,\n fontFamily: theme.font,\n fontSize: 12,\n formatter: (p: { dataIndex: number }) => {\n const i = p.dataIndex;\n return `{name|${stages[i]!.label}} {value|${fmt.value(stages[i]!.value)}}${i ? ` {rate|${fmt.share(rate(i))}}` : \"\"}`;\n },\n rich: { name: { color: theme.text2, fontSize: 12 }, value: { color: theme.text, fontWeight: 600, fontSize: 12 }, rate: { color: theme.text3, fontSize: 11 } },\n },\n labelLine: { lineStyle: { color: theme.axis } },\n emphasis: { itemStyle: { borderColor: theme.text, borderWidth: 2 } },\n },\n ],\n };\n },\n [stages, fmt, first, valueLabel, fromFirstLabel, fromPreviousLabel, labels.value, rate],\n );\n\n return (\n <EChartHost\n kind=\"funnel\"\n frame={props}\n defaultHeight={280}\n table={{\n columns: [stageLabel ?? labels.category, valueLabel ?? labels.value, fromFirstLabel, fromPreviousLabel],\n rows: stages.map((s, i) => [s.label, fmt.value(s.value), fmt.share(first ? s.value / first : 0), i ? fmt.share(rate(i)) : labels.noValue]),\n }}\n summary={summary}\n isEmpty={isEmpty}\n engine={engine}\n build={build}\n items={items}\n />\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,92 @@
1
+ "use client";
2
+ import {
3
+ EChartHost,
4
+ baseOption,
5
+ tooltipHtml
6
+ } from "./chunk-I5QUZVU2.js";
7
+ import {
8
+ read
9
+ } from "./chunk-W5FX4TU3.js";
10
+ import {
11
+ shareFormatter,
12
+ valueFormatter
13
+ } from "./chunk-XLLYNNC6.js";
14
+ import {
15
+ useSettings
16
+ } from "./chunk-DWJPPEMC.js";
17
+ import {
18
+ capitalize,
19
+ fill
20
+ } from "./chunk-3CJHBJXA.js";
21
+
22
+ // src/sankey/sankey.tsx
23
+ import { useCallback, useMemo } from "react";
24
+ import { jsx } from "react/jsx-runtime";
25
+ var engine = () => import("./sankey-XQTX2EG6.js");
26
+ function Sankey(props) {
27
+ const { data, source, target, value, format, vertical, sourceLabel, targetLabel, valueLabel } = props;
28
+ const { locale, labels } = useSettings(props);
29
+ const fmt = useMemo(() => ({ value: valueFormatter(format, locale, labels.noValue), share: shareFormatter(locale) }), [format, locale, labels.noValue]);
30
+ const model = useMemo(() => {
31
+ const links = data.map((d, i) => ({ source: String(read(source, d, i)), target: String(read(target, d, i)), value: Number(read(value, d, i)) })).filter((l) => Number.isFinite(l.value) && l.value > 0);
32
+ const nodes = [...new Set(links.flatMap((l) => [l.source, l.target]))];
33
+ return { links, nodes };
34
+ }, [data, source, target, value]);
35
+ const isEmpty = model.links.length === 0;
36
+ const total = model.links.filter((l) => !model.links.some((o) => o.target === l.source)).reduce((sum, l) => sum + l.value, 0);
37
+ const top = [...model.links].sort((a, b) => b.value - a.value).slice(0, 3);
38
+ const summary = isEmpty ? labels.empty : `${fill(labels.summaryIntro, { kind: labels.kinds.sankey, count: `${model.nodes.length} \xB7 ${model.links.length}` })} ${top.map((l) => fill(labels.summaryShare, { label: `${l.source} \u2192 ${l.target}`, value: fmt.value(l.value), share: fmt.share(total ? l.value / total : 0) })).join(", ")}. ${capitalize(fill(labels.summaryTotal, { total: fmt.value(total) }))}.`;
39
+ const items = model.links.map((l, i) => ({ seriesIndex: 0, dataIndex: i, dataType: "edge", text: `${l.source} \u2192 ${l.target}: ${fmt.value(l.value)}` }));
40
+ const build = useCallback(
41
+ (theme) => {
42
+ const base = baseOption(theme, true);
43
+ const colorOf = (name) => theme.palette[model.nodes.indexOf(name) % 8];
44
+ return {
45
+ ...base,
46
+ tooltip: {
47
+ ...base.tooltip,
48
+ trigger: "item",
49
+ formatter: (p) => p.dataType === "edge" ? tooltipHtml(`${p.data.source} \u2192 ${p.data.target}`, [{ label: valueLabel ?? labels.value, value: fmt.value(p.data.value), color: colorOf(p.data.source) }]) : tooltipHtml(p.name, [{ label: valueLabel ?? labels.value, value: fmt.value(p.value), color: colorOf(p.name) }])
50
+ },
51
+ series: [
52
+ {
53
+ type: "sankey",
54
+ orient: vertical ? "vertical" : "horizontal",
55
+ left: 8,
56
+ right: vertical ? 8 : 120,
57
+ top: 8,
58
+ bottom: vertical ? 40 : 8,
59
+ nodeWidth: 12,
60
+ nodeGap: 10,
61
+ draggable: false,
62
+ emphasis: { focus: "adjacency" },
63
+ data: model.nodes.map((name) => ({ name, itemStyle: { color: colorOf(name), borderColor: theme.surface, borderWidth: 1 } })),
64
+ links: model.links.map((l) => ({ ...l, lineStyle: { color: colorOf(l.source), opacity: 0.28 } })),
65
+ label: { color: theme.text, fontSize: 11, fontFamily: theme.font },
66
+ lineStyle: { curveness: 0.5 }
67
+ }
68
+ ]
69
+ };
70
+ },
71
+ [model, fmt, vertical, valueLabel, labels.value]
72
+ );
73
+ return /* @__PURE__ */ jsx(
74
+ EChartHost,
75
+ {
76
+ kind: "sankey",
77
+ frame: props,
78
+ defaultHeight: 320,
79
+ table: { columns: [sourceLabel ?? labels.category, targetLabel ?? labels.value, valueLabel ?? labels.value], rows: model.links.map((l) => [l.source, l.target, fmt.value(l.value)]) },
80
+ summary,
81
+ isEmpty,
82
+ engine,
83
+ build,
84
+ items
85
+ }
86
+ );
87
+ }
88
+
89
+ export {
90
+ Sankey
91
+ };
92
+ //# sourceMappingURL=chunk-XC6BQ3RN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sankey/sankey.tsx"],"sourcesContent":["\"use client\";\n// Flows between stages — credits from plans to models to outcomes, viewers from sources to purchases — on ECharts\n// (loaded when the chart nears the screen). Each node keeps its palette slot in order of appearance; links take\n// their source's colour, softened.\nimport { useCallback, useMemo } from \"react\";\n\nimport { read } from \"../core/data\";\nimport { shareFormatter, valueFormatter } from \"../core/format\";\nimport { capitalize, fill } from \"../core/labels\";\nimport type { Accessor, Datum, ValueFormat } from \"../core/types\";\nimport { EChartHost, type EngineProps, type WalkItem } from \"../echarts/host\";\nimport { baseOption, type ResolvedTheme, tooltipHtml } from \"../echarts/theme\";\nimport type { ChartFrameProps } from \"../web/frame\";\nimport { useSettings } from \"../web/frame\";\n\nconst engine = () => import(\"../echarts/engines/sankey\");\n\nexport interface SankeyProps<T extends Datum> extends ChartFrameProps, EngineProps {\n /** One row per flow. */\n data: readonly T[];\n /** The fields (or functions) naming where the flow comes from and where it goes. */\n source: Accessor<T, string>;\n/** The field (or function) naming where the flow goes. */\n target: Accessor<T, string>;\n /** The field of its amount. */\n value: Accessor<T, number>;\n /** How the amounts are written. */\n format?: ValueFormat;\n /** Lay the stages out top to bottom (narrow screens). Default: left to right. */\n vertical?: boolean;\n /** The headers of the data table. */\n sourceLabel?: string;\n/** The header of the targets. */\n targetLabel?: string;\n/** The header of the amounts. */\n valueLabel?: string;\n}\n\nexport function Sankey<T extends Datum>(props: SankeyProps<T>) {\n const { data, source, target, value, format, vertical, sourceLabel, targetLabel, valueLabel } = props;\n const { locale, labels } = useSettings(props);\n const fmt = useMemo(() => ({ value: valueFormatter(format, locale, labels.noValue), share: shareFormatter(locale) }), [format, locale, labels.noValue]);\n const model = useMemo(() => {\n const links = data.map((d, i) => ({ source: String(read(source, d, i)), target: String(read(target, d, i)), value: Number(read(value, d, i)) })).filter((l) => Number.isFinite(l.value) && l.value > 0);\n const nodes = [...new Set(links.flatMap((l) => [l.source, l.target]))];\n return { links, nodes };\n }, [data, source, target, value]);\n const isEmpty = model.links.length === 0;\n const total = model.links.filter((l) => !model.links.some((o) => o.target === l.source)).reduce((sum, l) => sum + l.value, 0);\n const top = [...model.links].sort((a, b) => b.value - a.value).slice(0, 3);\n const summary = isEmpty\n ? labels.empty\n : `${fill(labels.summaryIntro, { kind: labels.kinds.sankey, count: `${model.nodes.length} · ${model.links.length}` })} ${top.map((l) => fill(labels.summaryShare, { label: `${l.source} → ${l.target}`, value: fmt.value(l.value), share: fmt.share(total ? l.value / total : 0) })).join(\", \")}. ${capitalize(fill(labels.summaryTotal, { total: fmt.value(total) }))}.`;\n const items: WalkItem[] = model.links.map((l, i) => ({ seriesIndex: 0, dataIndex: i, dataType: \"edge\", text: `${l.source} → ${l.target}: ${fmt.value(l.value)}` }));\n\n const build = useCallback(\n (theme: ResolvedTheme) => {\n const base = baseOption(theme, true);\n const colorOf = (name: string) => theme.palette[model.nodes.indexOf(name) % 8]!;\n return {\n ...base,\n tooltip: {\n ...(base.tooltip as object),\n trigger: \"item\",\n formatter: (p: { dataType: string; data: { source?: string; target?: string; value?: number; name?: string }; value: number; name: string }) =>\n p.dataType === \"edge\"\n ? tooltipHtml(`${p.data.source} → ${p.data.target}`, [{ label: valueLabel ?? labels.value, value: fmt.value(p.data.value), color: colorOf(p.data.source!) }])\n : tooltipHtml(p.name, [{ label: valueLabel ?? labels.value, value: fmt.value(p.value), color: colorOf(p.name) }]),\n },\n series: [\n {\n type: \"sankey\",\n orient: vertical ? \"vertical\" : \"horizontal\",\n left: 8,\n right: vertical ? 8 : 120,\n top: 8,\n bottom: vertical ? 40 : 8,\n nodeWidth: 12,\n nodeGap: 10,\n draggable: false,\n emphasis: { focus: \"adjacency\" },\n data: model.nodes.map((name) => ({ name, itemStyle: { color: colorOf(name), borderColor: theme.surface, borderWidth: 1 } })),\n links: model.links.map((l) => ({ ...l, lineStyle: { color: colorOf(l.source), opacity: 0.28 } })),\n label: { color: theme.text, fontSize: 11, fontFamily: theme.font },\n lineStyle: { curveness: 0.5 },\n },\n ],\n };\n },\n [model, fmt, vertical, valueLabel, labels.value],\n );\n\n return (\n <EChartHost\n kind=\"sankey\"\n frame={props}\n defaultHeight={320}\n table={{ columns: [sourceLabel ?? labels.category, targetLabel ?? labels.value, valueLabel ?? labels.value], rows: model.links.map((l) => [l.source, l.target, fmt.value(l.value)]) }}\n summary={summary}\n isEmpty={isEmpty}\n engine={engine}\n build={build}\n items={items}\n />\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,89 @@
1
+ "use client";
2
+
3
+ // src/core/format.ts
4
+ import { currencyDigits, formatCompact, formatDate, formatMoney, formatNumber, formatPercent, getDateTimeFormat, getNumberFormat } from "@krizaka/intl";
5
+ function valueFormatter(format = "number", locale, noValue = "\u2014", axis = false) {
6
+ const write = writerOf(format, locale, axis);
7
+ return (value) => value == null || Number.isNaN(value) ? noValue : write(value);
8
+ }
9
+ function writerOf(format, locale, axis) {
10
+ if (typeof format === "function") return (value) => format(value, locale);
11
+ if (format === "integer") return (value) => formatNumber(Math.round(value), { locale, maximumFractionDigits: 0 });
12
+ if (format === "compact") return (value) => formatCompact(value, { locale });
13
+ if (format === "percent") return (value) => formatPercent(value, { locale, maximumFractionDigits: axis ? 0 : 1 });
14
+ if (format === "number") {
15
+ return (value) => axis && Math.abs(value) >= 1e4 ? formatCompact(value, { locale }) : formatNumber(value, { locale, maximumFractionDigits: 2 });
16
+ }
17
+ if (format.style === "money") {
18
+ const { currency } = format;
19
+ const digits = currencyDigits(currency);
20
+ return (value) => {
21
+ const minor = Math.round(value);
22
+ if ((axis || format.compact) && Math.abs(minor) >= 1e6) {
23
+ const options2 = { style: "currency", currency, currencyDisplay: "narrowSymbol", notation: "compact", minimumFractionDigits: 0, maximumFractionDigits: 1 };
24
+ return getNumberFormat(locale, options2).format(minor / 10 ** digits);
25
+ }
26
+ if (axis && minor % 10 ** digits === 0) {
27
+ return getNumberFormat(locale, { style: "currency", currency, minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(minor / 10 ** digits);
28
+ }
29
+ return formatMoney(minor, { currency, locale });
30
+ };
31
+ }
32
+ if (format.style === "unit") {
33
+ const { unit } = format;
34
+ const compact = axis || format.compact;
35
+ const options2 = { style: "unit", unit, unitDisplay: "short", ...compact ? { notation: "compact" } : {}, maximumFractionDigits: compact ? 1 : 2 };
36
+ return (value) => getNumberFormat(locale, options2).format(value);
37
+ }
38
+ const { options } = format;
39
+ return (value) => formatNumber(value, { locale, ...options });
40
+ }
41
+ function asDate(value) {
42
+ if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
43
+ if (typeof value === "number" && value > 1e10) return new Date(value);
44
+ if (typeof value === "string" && /^\d{4}-\d{2}(-\d{2})?([T ][\d:.]+(Z|[+-]\d{2}:?\d{2})?)?$/.test(value)) {
45
+ const iso = value.length === 7 ? `${value}-01T00:00:00Z` : value.length === 10 ? `${value}T00:00:00Z` : value;
46
+ const date = new Date(iso);
47
+ return Number.isNaN(date.getTime()) ? null : date;
48
+ }
49
+ return null;
50
+ }
51
+ var DATE_OPTIONS = {
52
+ year: { year: "numeric", timeZone: "UTC" },
53
+ month: { month: "short", year: "numeric", timeZone: "UTC" },
54
+ day: { month: "short", day: "numeric", timeZone: "UTC" },
55
+ date: { dateStyle: "medium", timeZone: "UTC" },
56
+ time: { timeStyle: "short", timeZone: "UTC" },
57
+ datetime: { dateStyle: "medium", timeStyle: "short", timeZone: "UTC" }
58
+ };
59
+ function categoryFormatter(format, locale) {
60
+ if (typeof format === "function") return (category) => format(category, locale);
61
+ if (format === "text") return (category) => String(category ?? "");
62
+ return (category) => {
63
+ const date = asDate(category);
64
+ if (!date) return String(category ?? "");
65
+ const kind = format ?? guessPrecision(category);
66
+ if (kind === "date") return formatDate(date, { locale, style: "medium", timeZone: "UTC" });
67
+ return getDateTimeFormat(locale, DATE_OPTIONS[kind]).format(date);
68
+ };
69
+ }
70
+ function guessPrecision(category) {
71
+ if (typeof category === "string") {
72
+ if (category.length === 7) return "month";
73
+ if (category.length === 10) return "date";
74
+ return "datetime";
75
+ }
76
+ const date = asDate(category);
77
+ return date && date.getUTCHours() === 0 && date.getUTCMinutes() === 0 ? "date" : "datetime";
78
+ }
79
+ function shareFormatter(locale) {
80
+ return (ratio) => formatPercent(ratio, { locale, maximumFractionDigits: Math.abs(ratio) < 0.1 ? 1 : 0 });
81
+ }
82
+
83
+ export {
84
+ valueFormatter,
85
+ asDate,
86
+ categoryFormatter,
87
+ shareFormatter
88
+ };
89
+ //# sourceMappingURL=chunk-XLLYNNC6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/format.ts"],"sourcesContent":["// Values and categories written the same way in the axes, the tooltips, the data table and the summary, through\n// @krizaka/intl (one cached Intl formatter per locale and options).\nimport { currencyDigits, formatCompact, formatDate, formatMoney, formatNumber, formatPercent, getDateTimeFormat, getNumberFormat } from \"@krizaka/intl\";\n\nimport type { CategoryFormat, Locale, ValueFormat } from \"./types\";\n\nexport type ValueFormatter = (value: number | null | undefined) => string;\n\n/**\n * A formatter for `format`. `axis` asks for the short form of the axis ticks (money and units go compact past 10 000).\n * A missing value is written `noValue`.\n */\nexport function valueFormatter(format: ValueFormat = \"number\", locale: Locale, noValue = \"—\", axis = false): ValueFormatter {\n const write = writerOf(format, locale, axis);\n return (value) => (value == null || Number.isNaN(value) ? noValue : write(value));\n}\n\nfunction writerOf(format: ValueFormat, locale: Locale, axis: boolean): (value: number) => string {\n if (typeof format === \"function\") return (value) => format(value, locale);\n if (format === \"integer\") return (value) => formatNumber(Math.round(value), { locale, maximumFractionDigits: 0 });\n if (format === \"compact\") return (value) => formatCompact(value, { locale });\n if (format === \"percent\") return (value) => formatPercent(value, { locale, maximumFractionDigits: axis ? 0 : 1 });\n if (format === \"number\") {\n return (value) => (axis && Math.abs(value) >= 10_000 ? formatCompact(value, { locale }) : formatNumber(value, { locale, maximumFractionDigits: 2 }));\n }\n if (format.style === \"money\") {\n const { currency } = format;\n const digits = currencyDigits(currency);\n return (value) => {\n const minor = Math.round(value);\n // Compact money on the axes (`€12K`): the amount in major units, Intl's compact currency notation.\n if ((axis || format.compact) && Math.abs(minor) >= 1_000_000) {\n const options = { style: \"currency\", currency, currencyDisplay: \"narrowSymbol\", notation: \"compact\", minimumFractionDigits: 0, maximumFractionDigits: 1 } as const;\n return getNumberFormat(locale, options).format(minor / 10 ** digits);\n }\n // An axis tick is a round amount: no cents to write (`€2,500`, not `€2,500.00`).\n if (axis && minor % 10 ** digits === 0) {\n return getNumberFormat(locale, { style: \"currency\", currency, minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(minor / 10 ** digits);\n }\n return formatMoney(minor, { currency, locale });\n };\n }\n if (format.style === \"unit\") {\n const { unit } = format;\n const compact = axis || format.compact;\n const options: Intl.NumberFormatOptions = { style: \"unit\", unit, unitDisplay: \"short\", ...(compact ? { notation: \"compact\" } : {}), maximumFractionDigits: compact ? 1 : 2 };\n return (value) => getNumberFormat(locale, options).format(value);\n }\n const { options } = format;\n return (value) => formatNumber(value, { locale, ...options });\n}\n\n/** An ISO date (`2026-04`, `2026-04-12`, `2026-04-12T14:30Z`), a `Date` or an epoch → a `Date`; anything else → null. */\nexport function asDate(value: unknown): Date | null {\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;\n if (typeof value === \"number\" && value > 10_000_000_000) return new Date(value);\n if (typeof value === \"string\" && /^\\d{4}-\\d{2}(-\\d{2})?([T ][\\d:.]+(Z|[+-]\\d{2}:?\\d{2})?)?$/.test(value)) {\n // `2026-04` is the first of April, at midnight UTC: a month never slips to March in a negative time zone.\n const iso = value.length === 7 ? `${value}-01T00:00:00Z` : value.length === 10 ? `${value}T00:00:00Z` : value;\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? null : date;\n }\n return null;\n}\n\nconst DATE_OPTIONS: Record<Exclude<CategoryFormat, \"text\" | ((category: unknown, locale: Locale) => string)>, Intl.DateTimeFormatOptions> = {\n year: { year: \"numeric\", timeZone: \"UTC\" },\n month: { month: \"short\", year: \"numeric\", timeZone: \"UTC\" },\n day: { month: \"short\", day: \"numeric\", timeZone: \"UTC\" },\n date: { dateStyle: \"medium\", timeZone: \"UTC\" },\n time: { timeStyle: \"short\", timeZone: \"UTC\" },\n datetime: { dateStyle: \"medium\", timeStyle: \"short\", timeZone: \"UTC\" },\n};\n\nexport type CategoryFormatter = (category: unknown) => string;\n\n/**\n * A formatter for the categories. Without a format, a date category is written by its precision (`2026-04` → a month,\n * `2026-04-12` → a day) and anything else as text. Dates are written in UTC, the zone of an ISO date without one:\n * pass a function for a local time.\n */\nexport function categoryFormatter(format: CategoryFormat | undefined, locale: Locale): CategoryFormatter {\n if (typeof format === \"function\") return (category) => format(category, locale);\n if (format === \"text\") return (category) => String(category ?? \"\");\n return (category) => {\n const date = asDate(category);\n if (!date) return String(category ?? \"\");\n const kind = format ?? guessPrecision(category);\n if (kind === \"date\") return formatDate(date, { locale, style: \"medium\", timeZone: \"UTC\" });\n return getDateTimeFormat(locale, DATE_OPTIONS[kind]).format(date);\n };\n}\n\nfunction guessPrecision(category: unknown): \"month\" | \"date\" | \"datetime\" {\n if (typeof category === \"string\") {\n if (category.length === 7) return \"month\";\n if (category.length === 10) return \"date\";\n return \"datetime\";\n }\n const date = asDate(category);\n return date && date.getUTCHours() === 0 && date.getUTCMinutes() === 0 ? \"date\" : \"datetime\";\n}\n\n/** A ratio for the summary and the shares: `0.236` → `24%` (one decimal under 10 %). */\nexport function shareFormatter(locale: Locale): (ratio: number) => string {\n return (ratio) => formatPercent(ratio, { locale, maximumFractionDigits: Math.abs(ratio) < 0.1 ? 1 : 0 });\n}\n"],"mappings":"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","names":["options"]}
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import {
3
+ Cartesian
4
+ } from "./chunk-UNK4MJVG.js";
5
+
6
+ // src/bar/bar-chart.tsx
7
+ import { jsx } from "react/jsx-runtime";
8
+ function BarChart({ stacked, horizontal, valueLabels = true, ...props }) {
9
+ return /* @__PURE__ */ jsx(Cartesian, { props, options: { kind: "bar", mode: "bar", stacked, horizontal, valueLabels } });
10
+ }
11
+
12
+ export {
13
+ BarChart
14
+ };
15
+ //# sourceMappingURL=chunk-XR4ZJDOV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bar/bar-chart.tsx"],"sourcesContent":["\"use client\";\nimport { Cartesian, type CartesianProps } from \"../cartesian/cartesian\";\nimport type { Datum } from \"../core/types\";\n\nexport interface BarChartProps<T extends Datum> extends CartesianProps<T> {\n /** Stack the series in one bar per category (a total and its parts); default: grouped side by side. */\n stacked?: boolean;\n /** Bars grow to the right, the categories down the side: long labels, rankings. */\n horizontal?: boolean;\n /** Write each value at the tip of its bar (one series, up to 16 bars). Default true. */\n valueLabels?: boolean;\n}\n\n/** Compare amounts across categories: grouped, stacked or horizontal bars, each value at its tip. */\nexport function BarChart<T extends Datum>({ stacked, horizontal, valueLabels = true, ...props }: BarChartProps<T>) {\n return <Cartesian props={props} options={{ kind: \"bar\", mode: \"bar\", stacked, horizontal, valueLabels }} />;\n}\n"],"mappings":";;;;;;AAeS;AADF,SAAS,SAA0B,EAAE,SAAS,YAAY,cAAc,MAAM,GAAG,MAAM,GAAqB;AACjH,SAAO,oBAAC,aAAU,OAAc,SAAS,EAAE,MAAM,OAAO,MAAM,OAAO,SAAS,YAAY,YAAY,GAAG;AAC3G;","names":[]}
@@ -0,0 +1,163 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface ChartLabels {
5
+ /** The button that shows the data table. */
6
+ showData: string;
7
+ /** The button that hides it. */
8
+ hideData: string;
9
+ /** The caption of the data table: `{title}`. */
10
+ tableCaption: string;
11
+ /** The export buttons. */
12
+ exportPng: string;
13
+ exportSvg: string;
14
+ exportCsv: string;
15
+ /** Announced while the data loads. */
16
+ loading: string;
17
+ /** Shown when there is nothing to draw. */
18
+ empty: string;
19
+ /** Shown when the data could not be loaded. */
20
+ error: string;
21
+ /** The keyboard hint, read once when the plot takes the focus. */
22
+ keyboardHint: string;
23
+ /** The role description of the plot (`chart`). */
24
+ roleDescription: string;
25
+ /** Summary pieces. `{kind}` is the chart's name (`Line chart`), `{count}` a number of points or series. */
26
+ summaryIntro: string;
27
+ summarySeries: string;
28
+ summaryRange: string;
29
+ summaryTrendUp: string;
30
+ summaryTrendDown: string;
31
+ summaryTrendFlat: string;
32
+ summaryTotal: string;
33
+ summaryThreshold: string;
34
+ summaryShare: string;
35
+ /** Scatter: the correlation of x and y (Pearson's r). */
36
+ summaryCorrelation: string;
37
+ /** Funnel: from one stage to the next, and from the first to the last. */
38
+ summaryConversion: string;
39
+ summaryOverall: string;
40
+ /** Heatmap, calendar: the largest cell and the number of cells with a value. */
41
+ summaryPeak: string;
42
+ summaryActive: string;
43
+ /** Candlestick: the period's range. */
44
+ summaryOhlc: string;
45
+ /** The names of the charts, read first in the summary. */
46
+ kinds: Record<ChartKind, string>;
47
+ /** The column of the values, when the chart has no value label. */
48
+ value: string;
49
+ /** The column of the categories in the data table, when the chart has no x label. */
50
+ category: string;
51
+ /** The total row of a stacked chart, a pie, a funnel. */
52
+ total: string;
53
+ /** What a missing value reads as. */
54
+ noValue: string;
55
+ }
56
+ type ChartKind = "line" | "area" | "bar" | "pie" | "donut" | "gauge" | "sparkline" | "radar" | "heatmap" | "calendar" | "sankey" | "funnel" | "candlestick" | "treemap" | "scatter" | "map" | "globe" | "chart";
57
+ declare const DEFAULT_LABELS: ChartLabels;
58
+ /** The words an app or a chart passes: any of them, and any of the chart names. */
59
+ type ChartLabelsInput = Partial<Omit<ChartLabels, "kinds">> & {
60
+ kinds?: Partial<Record<ChartKind, string>>;
61
+ };
62
+
63
+ /** A row of data: any object; the chart reads the fields its `x`, `y` and `series` name. */
64
+ type Datum = object;
65
+ /** A field of a row (`"month"`) or a function that reads it. */
66
+ type Accessor<T, V> = (keyof T & string) | ((datum: T, index: number) => V);
67
+ /** A Krizaka brand: its palette leads with the brand's own hue (Krizaka blue, Orazaka orange, Orochia violet). */
68
+ type BrandId = "krizaka" | "orazaka" | "orochia";
69
+ /** A BCP 47 locale (`"en-US"`, `"fr-FR"`), always explicit: server and client write the same figures. */
70
+ type Locale = string | readonly string[];
71
+ /**
72
+ * How a value is written, through `@krizaka/intl`:
73
+ * - `"number"` (default) `12,345.6`, `"integer"` `12,346`, `"compact"` `12.3K`, `"percent"` (a ratio: `0.42` → `42%`);
74
+ * - `{ style: "money", currency }`: the values are **integer minor units** (cents), as the ledger stores them;
75
+ * - `{ style: "unit", unit }`: an `Intl` unit (`"second"`, `"megabyte"`);
76
+ * - a function, for anything else.
77
+ */
78
+ type ValueFormat = "number" | "integer" | "compact" | "percent" | {
79
+ readonly style: "money";
80
+ readonly currency: string;
81
+ readonly compact?: boolean;
82
+ } | {
83
+ readonly style: "unit";
84
+ readonly unit: string;
85
+ readonly compact?: boolean;
86
+ } | {
87
+ readonly style: "number";
88
+ readonly options: Intl.NumberFormatOptions;
89
+ } | ((value: number, locale: Locale) => string);
90
+ /**
91
+ * How a category of the x axis is written. A category that is a `Date`, an epoch or an ISO date (`"2026-04"`,
92
+ * `"2026-04-12"`) is a date: `"month"` (`Apr 2026`), `"day"` (`Apr 12`), `"date"` (`Apr 12, 2026`), `"time"`
93
+ * (`14:30`), `"datetime"`, `"year"`. `"text"` writes it as is (the default for anything that is not a date).
94
+ */
95
+ type CategoryFormat = "text" | "year" | "month" | "day" | "date" | "time" | "datetime" | ((category: unknown, locale: Locale) => string);
96
+ /** A series to draw: the field holding its values and the words that name it. */
97
+ interface SeriesSpec<T extends Datum = Datum> {
98
+ /** The field (or a function) holding the series' value in each row. */
99
+ readonly key: Accessor<T, number | null | undefined>;
100
+ /** Its name: in the legend, the tooltip, the data table and the summary. */
101
+ readonly label: string;
102
+ /** A colour role instead of the next palette slot: `"accent"`, a status (`"success"`…) or a `var(--…)`. */
103
+ readonly color?: SeriesColor;
104
+ /** Draw it dashed (a forecast, a previous period). Lines and areas only. */
105
+ readonly dashed?: boolean;
106
+ }
107
+ /** A status or brand role a series, a threshold or a marker may wear instead of a palette slot. */
108
+ type Tone = "neutral" | "accent" | "success" | "warning" | "danger" | "info";
109
+ /** A palette slot (1–8), a tone, or any CSS colour (`var(--kz-…)` preferred). */
110
+ type SeriesColor = Tone | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | (string & {});
111
+ /** A horizontal line at a value: a goal, a payout threshold, a quota. */
112
+ interface Threshold {
113
+ readonly value: number;
114
+ /** What it means, written beside the line and in the summary: “Payout threshold”. */
115
+ readonly label: string;
116
+ /** Default `"neutral"`; a goal reads well in `"success"`, a limit in `"danger"`. */
117
+ readonly tone?: Tone;
118
+ }
119
+ /** A vertical marker at a category: an event worth pointing at (“Campaign launch”). */
120
+ interface Marker {
121
+ /** The category it marks, as in the data (`"2026-04"`). */
122
+ readonly x: unknown;
123
+ readonly label: string;
124
+ readonly tone?: Tone;
125
+ }
126
+ /** What a series says about itself, for the written summary. */
127
+ interface SeriesSummary {
128
+ readonly label: string;
129
+ readonly count: number;
130
+ readonly min: {
131
+ readonly value: number;
132
+ readonly category: string;
133
+ } | null;
134
+ readonly max: {
135
+ readonly value: number;
136
+ readonly category: string;
137
+ } | null;
138
+ readonly first: number | null;
139
+ readonly last: number | null;
140
+ readonly total: number;
141
+ /** `last / first − 1`, or null when it cannot be said (no first value, a first value of 0). */
142
+ readonly change: number | null;
143
+ readonly trend: "up" | "down" | "flat" | "none";
144
+ }
145
+
146
+ interface ChartsSettings {
147
+ /** The locale of every figure and date (`"fr-FR"`). Default `"en-US"`. */
148
+ locale?: Locale;
149
+ /**
150
+ * The brand whose palette the charts use. Without it, a chart follows a `.brand-<id>` ancestor, else Krizaka. Set it
151
+ * when the app loads a brand stylesheet on `:root` (`@krizaka/tokens/brands/orazaka.css`).
152
+ */
153
+ brand?: BrandId;
154
+ /** The words, translated: the buttons, the states, the written summary. */
155
+ labels?: ChartLabelsInput;
156
+ }
157
+ interface ChartsProviderProps extends ChartsSettings {
158
+ children: ReactNode;
159
+ }
160
+ /** Sets the locale, the brand and the words of every chart below it. */
161
+ declare function ChartsProvider({ locale, brand, labels, children }: ChartsProviderProps): react.JSX.Element;
162
+
163
+ export { type Accessor as A, type BrandId as B, type CategoryFormat as C, DEFAULT_LABELS as D, type Locale as L, type Marker as M, type SeriesColor as S, type Threshold as T, type ValueFormat as V, type ChartKind as a, type ChartLabels as b, type ChartLabelsInput as c, ChartsProvider as d, type ChartsProviderProps as e, type ChartsSettings as f, type Datum as g, type SeriesSpec as h, type SeriesSummary as i, type Tone as j };
@@ -0,0 +1,45 @@
1
+ import { ReactNode, CSSProperties } from 'react';
2
+ import { f as ChartsSettings } from './context-BgYUymEO.js';
3
+
4
+ type ExportFormat = "png" | "svg" | "csv";
5
+ /** The props every web chart takes, on top of its data. */
6
+ interface ChartFrameProps extends ChartsSettings {
7
+ /** What the chart shows, in a few words: its accessible name, and its heading unless `hideTitle`. */
8
+ title: string;
9
+ /** A sentence under the title: the period, the unit, the source. */
10
+ description?: ReactNode;
11
+ /** Visually hide the title (it stays the chart's accessible name): a card that already has its heading. */
12
+ hideTitle?: boolean;
13
+ /** The height of the plot in pixels. Default 280 (a sparkline: 32). */
14
+ height?: number;
15
+ /** The data is on its way: a skeleton of the chart, announced once. */
16
+ loading?: boolean;
17
+ /** The data could not be loaded: `true` says the default words, a node says yours (a retry button…). */
18
+ error?: boolean | ReactNode;
19
+ /** What to show when there is nothing to draw (default: the `empty` label). An `EmptyState` of @krizaka/ui fits. */
20
+ empty?: ReactNode;
21
+ /** The written summary: read by screen readers only (`"hidden"`, default), or shown under the chart (`"visible"`). */
22
+ summary?: "hidden" | "visible";
23
+ /** Your own summary instead of the generated one (still read first by screen readers). */
24
+ summaryText?: string;
25
+ /** The "Show data" button (the table is in the page for screen readers either way). Default true. */
26
+ dataTable?: boolean;
27
+ /** Export buttons: `true` for PNG, SVG and CSV, or the formats you want. */
28
+ exportable?: boolean | readonly ExportFormat[];
29
+ /** Streaming data (a job queue, an auction): no entrance on updates, no announcement of every new point. */
30
+ live?: boolean;
31
+ /** The id of the figure. */
32
+ id?: string;
33
+ /** A class on the figure (layout: margins, grid placement). */
34
+ className?: string;
35
+ /** Inline style on the figure (layout only: colours come from the tokens). */
36
+ style?: CSSProperties;
37
+ }
38
+ interface TableModel {
39
+ /** The header of each column; the first one names the categories. */
40
+ readonly columns: readonly string[];
41
+ /** The rows, already written (formatted values). The first cell is the row's header. */
42
+ readonly rows: readonly (readonly string[])[];
43
+ }
44
+
45
+ export type { ChartFrameProps as C, TableModel as T };
@@ -0,0 +1,11 @@
1
+ "use client";
2
+
3
+ // src/echarts/engines/full.ts
4
+ import * as echarts from "echarts";
5
+ function install() {
6
+ return echarts;
7
+ }
8
+ export {
9
+ install
10
+ };
11
+ //# sourceMappingURL=full-S2MBPEEP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/echarts/engines/full.ts"],"sourcesContent":["// Every chart and component of ECharts: what `<Chart>` loads when it is not told which modules an option needs.\nimport * as echarts from \"echarts\";\n\n/** Nothing to register: the full build registers everything. Exported so the module is used, not only imported. */\nexport function install(): typeof echarts {\n return echarts;\n}\n"],"mappings":";;;AACA,YAAY,aAAa;AAGlB,SAAS,UAA0B;AACxC,SAAO;AACT;","names":[]}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+
3
+ // src/echarts/engines/funnel.ts
4
+ import { FunnelChart } from "echarts/charts";
5
+ import { TooltipComponent } from "echarts/components";
6
+ import { use as register } from "echarts/core";
7
+ function install() {
8
+ register([FunnelChart, TooltipComponent]);
9
+ }
10
+ export {
11
+ install
12
+ };
13
+ //# sourceMappingURL=funnel-QU5ZPC52.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/echarts/engines/funnel.ts"],"sourcesContent":["import { FunnelChart } from \"echarts/charts\";\nimport { TooltipComponent } from \"echarts/components\";\nimport { use as register } from \"echarts/core\";\n\n/**\n * Registers what this chart needs. A function, not a side effect of the import: the package is `sideEffects: false`,\n * and a bundler drops a module imported only for its side effects.\n */\nexport function install(): void {\n register([FunnelChart, TooltipComponent]);\n}\n"],"mappings":";;;AAAA,SAAS,mBAAmB;AAC5B,SAAS,wBAAwB;AACjC,SAAS,OAAO,gBAAgB;AAMzB,SAAS,UAAgB;AAC9B,WAAS,CAAC,aAAa,gBAAgB,CAAC;AAC1C;","names":[]}