@blukavantui/charts-community 0.0.0-stage → 1.2.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 (262) hide show
  1. package/LICENSE.txt +103 -0
  2. package/README.md +98 -2
  3. package/THIRD_PARTY_NOTICES.txt +288 -0
  4. package/dist/accessibility.d.ts +53 -0
  5. package/dist/async.d.ts +2 -0
  6. package/dist/bar.css +1 -0
  7. package/dist/bar.d.ts +5 -0
  8. package/dist/bar.js +1 -0
  9. package/dist/browser/charts-community.css +1 -0
  10. package/dist/browser/charts-community.js +52 -0
  11. package/dist/build-audit.json +209 -0
  12. package/dist/builders/bar.d.ts +6 -0
  13. package/dist/builders/doughnut.d.ts +6 -0
  14. package/dist/builders/heatmap.d.ts +16 -0
  15. package/dist/builders/line.d.ts +6 -0
  16. package/dist/builders/pie.d.ts +6 -0
  17. package/dist/builders/radar.d.ts +6 -0
  18. package/dist/builders/scatter.d.ts +6 -0
  19. package/dist/catalogue-model.d.ts +11 -0
  20. package/dist/catalogue-runtime.d.ts +23 -0
  21. package/dist/catalogue-types.d.ts +167 -0
  22. package/dist/chart-state.d.ts +18 -0
  23. package/dist/chunk-2GUWWKHW.js +1 -0
  24. package/dist/chunk-3PITHTEO.js +1 -0
  25. package/dist/chunk-4B5MQ6GZ.js +1 -0
  26. package/dist/chunk-4EQMOBBN.js +1 -0
  27. package/dist/chunk-4WDZUJDS.js +1 -0
  28. package/dist/chunk-5NUOOMHV.js +1 -0
  29. package/dist/chunk-7OCMRHIH.js +1 -0
  30. package/dist/chunk-CF5Q2DDP.js +1 -0
  31. package/dist/chunk-EITBQBN2.js +1 -0
  32. package/dist/chunk-FXNKAHRG.js +1 -0
  33. package/dist/chunk-IDMAFTWV.js +1 -0
  34. package/dist/chunk-ILTENI35.js +1 -0
  35. package/dist/chunk-KRMM7EWI.js +1 -0
  36. package/dist/chunk-LUUPBBD4.js +1 -0
  37. package/dist/chunk-MR5VITXX.js +1 -0
  38. package/dist/chunk-NASBRHIW.js +1 -0
  39. package/dist/chunk-NXDBBMF5.js +1 -0
  40. package/dist/chunk-OQ6MP7PY.js +1 -0
  41. package/dist/chunk-RC2TCMJF.js +1 -0
  42. package/dist/chunk-RXOGAN23.js +1 -0
  43. package/dist/chunk-UGXWOWAG.js +2 -0
  44. package/dist/chunk-UO2KNHTU.js +2 -0
  45. package/dist/chunk-UQMMBG26.js +3 -0
  46. package/dist/chunk-VTJ4XPRV.js +1 -0
  47. package/dist/chunk-WJ3UHH6J.js +1 -0
  48. package/dist/chunk-XLJUSNGV.js +1 -0
  49. package/dist/colors.d.ts +15 -0
  50. package/dist/community.d.ts +11 -0
  51. package/dist/doughnut.css +1 -0
  52. package/dist/doughnut.d.ts +5 -0
  53. package/dist/doughnut.js +1 -0
  54. package/dist/export.d.ts +5 -0
  55. package/dist/fonts/dm-sans-LICENSE.txt +93 -0
  56. package/dist/fonts/dm-sans-latin-ext-wght-italic.woff2 +0 -0
  57. package/dist/fonts/dm-sans-latin-ext-wght-normal.woff2 +0 -0
  58. package/dist/fonts/dm-sans-latin-wght-italic.woff2 +0 -0
  59. package/dist/fonts/dm-sans-latin-wght-normal.woff2 +0 -0
  60. package/dist/fonts/ibm-plex-mono-LICENSE.txt +93 -0
  61. package/dist/fonts/ibm-plex-mono-latin-100-italic.woff2 +0 -0
  62. package/dist/fonts/ibm-plex-mono-latin-100-normal.woff2 +0 -0
  63. package/dist/fonts/ibm-plex-mono-latin-200-italic.woff2 +0 -0
  64. package/dist/fonts/ibm-plex-mono-latin-200-normal.woff2 +0 -0
  65. package/dist/fonts/ibm-plex-mono-latin-300-italic.woff2 +0 -0
  66. package/dist/fonts/ibm-plex-mono-latin-300-normal.woff2 +0 -0
  67. package/dist/fonts/ibm-plex-mono-latin-400-italic.woff2 +0 -0
  68. package/dist/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  69. package/dist/fonts/ibm-plex-mono-latin-500-italic.woff2 +0 -0
  70. package/dist/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  71. package/dist/fonts/ibm-plex-mono-latin-600-italic.woff2 +0 -0
  72. package/dist/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  73. package/dist/fonts/ibm-plex-mono-latin-700-italic.woff2 +0 -0
  74. package/dist/fonts/ibm-plex-mono-latin-700-normal.woff2 +0 -0
  75. package/dist/fonts/ibm-plex-mono-latin-ext-100-italic.woff2 +0 -0
  76. package/dist/fonts/ibm-plex-mono-latin-ext-100-normal.woff2 +0 -0
  77. package/dist/fonts/ibm-plex-mono-latin-ext-200-italic.woff2 +0 -0
  78. package/dist/fonts/ibm-plex-mono-latin-ext-200-normal.woff2 +0 -0
  79. package/dist/fonts/ibm-plex-mono-latin-ext-300-italic.woff2 +0 -0
  80. package/dist/fonts/ibm-plex-mono-latin-ext-300-normal.woff2 +0 -0
  81. package/dist/fonts/ibm-plex-mono-latin-ext-400-italic.woff2 +0 -0
  82. package/dist/fonts/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
  83. package/dist/fonts/ibm-plex-mono-latin-ext-500-italic.woff2 +0 -0
  84. package/dist/fonts/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
  85. package/dist/fonts/ibm-plex-mono-latin-ext-600-italic.woff2 +0 -0
  86. package/dist/fonts/ibm-plex-mono-latin-ext-600-normal.woff2 +0 -0
  87. package/dist/fonts/ibm-plex-mono-latin-ext-700-italic.woff2 +0 -0
  88. package/dist/fonts/ibm-plex-mono-latin-ext-700-normal.woff2 +0 -0
  89. package/dist/fonts/inter-LICENSE.txt +93 -0
  90. package/dist/fonts/inter-latin-ext-wght-italic.woff2 +0 -0
  91. package/dist/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  92. package/dist/fonts/inter-latin-wght-italic.woff2 +0 -0
  93. package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
  94. package/dist/fonts/jetbrains-mono-LICENSE.txt +93 -0
  95. package/dist/fonts/jetbrains-mono-latin-ext-wght-italic.woff2 +0 -0
  96. package/dist/fonts/jetbrains-mono-latin-ext-wght-normal.woff2 +0 -0
  97. package/dist/fonts/jetbrains-mono-latin-wght-italic.woff2 +0 -0
  98. package/dist/fonts/jetbrains-mono-latin-wght-normal.woff2 +0 -0
  99. package/dist/fonts/lora-LICENSE.txt +93 -0
  100. package/dist/fonts/lora-latin-ext-wght-italic.woff2 +0 -0
  101. package/dist/fonts/lora-latin-ext-wght-normal.woff2 +0 -0
  102. package/dist/fonts/lora-latin-wght-italic.woff2 +0 -0
  103. package/dist/fonts/lora-latin-wght-normal.woff2 +0 -0
  104. package/dist/fonts/manifest.json +618 -0
  105. package/dist/fonts/manrope-LICENSE.txt +93 -0
  106. package/dist/fonts/manrope-latin-ext-wght-normal.woff2 +0 -0
  107. package/dist/fonts/manrope-latin-wght-normal.woff2 +0 -0
  108. package/dist/fonts/merriweather-LICENSE.txt +93 -0
  109. package/dist/fonts/merriweather-latin-ext-wght-italic.woff2 +0 -0
  110. package/dist/fonts/merriweather-latin-ext-wght-normal.woff2 +0 -0
  111. package/dist/fonts/merriweather-latin-wght-italic.woff2 +0 -0
  112. package/dist/fonts/merriweather-latin-wght-normal.woff2 +0 -0
  113. package/dist/fonts/montserrat-LICENSE.txt +93 -0
  114. package/dist/fonts/montserrat-latin-ext-wght-italic.woff2 +0 -0
  115. package/dist/fonts/montserrat-latin-ext-wght-normal.woff2 +0 -0
  116. package/dist/fonts/montserrat-latin-wght-italic.woff2 +0 -0
  117. package/dist/fonts/montserrat-latin-wght-normal.woff2 +0 -0
  118. package/dist/fonts/playfair-display-LICENSE.txt +93 -0
  119. package/dist/fonts/playfair-display-latin-ext-wght-italic.woff2 +0 -0
  120. package/dist/fonts/playfair-display-latin-ext-wght-normal.woff2 +0 -0
  121. package/dist/fonts/playfair-display-latin-wght-italic.woff2 +0 -0
  122. package/dist/fonts/playfair-display-latin-wght-normal.woff2 +0 -0
  123. package/dist/fonts/roboto-LICENSE.txt +93 -0
  124. package/dist/fonts/roboto-latin-ext-wght-italic.woff2 +0 -0
  125. package/dist/fonts/roboto-latin-ext-wght-normal.woff2 +0 -0
  126. package/dist/fonts/roboto-latin-wght-italic.woff2 +0 -0
  127. package/dist/fonts/roboto-latin-wght-normal.woff2 +0 -0
  128. package/dist/fonts/source-sans-3-LICENSE.txt +93 -0
  129. package/dist/fonts/source-sans-3-latin-ext-wght-italic.woff2 +0 -0
  130. package/dist/fonts/source-sans-3-latin-ext-wght-normal.woff2 +0 -0
  131. package/dist/fonts/source-sans-3-latin-wght-italic.woff2 +0 -0
  132. package/dist/fonts/source-sans-3-latin-wght-normal.woff2 +0 -0
  133. package/dist/heatmap.css +1 -0
  134. package/dist/heatmap.d.ts +3 -0
  135. package/dist/heatmap.js +1 -0
  136. package/dist/index.css +1 -0
  137. package/dist/index.d.ts +11 -0
  138. package/dist/index.js +1 -0
  139. package/dist/legend-export.d.ts +9 -0
  140. package/dist/legend-model.d.ts +39 -0
  141. package/dist/legend.d.ts +19 -0
  142. package/dist/limits.d.ts +16 -0
  143. package/dist/line.css +1 -0
  144. package/dist/line.d.ts +5 -0
  145. package/dist/line.js +1 -0
  146. package/dist/loading-state.d.ts +6 -0
  147. package/dist/map-assets.d.ts +4 -0
  148. package/dist/map-resources.d.ts +24 -0
  149. package/dist/messages.d.ts +3 -0
  150. package/dist/model.d.ts +41 -0
  151. package/dist/motion/bar.css +1 -0
  152. package/dist/motion/bar.d.ts +8 -0
  153. package/dist/motion/bar.js +1 -0
  154. package/dist/motion/doughnut.css +1 -0
  155. package/dist/motion/doughnut.d.ts +8 -0
  156. package/dist/motion/doughnut.js +1 -0
  157. package/dist/motion/heatmap.css +1 -0
  158. package/dist/motion/heatmap.d.ts +7 -0
  159. package/dist/motion/heatmap.js +1 -0
  160. package/dist/motion/line.css +1 -0
  161. package/dist/motion/line.d.ts +8 -0
  162. package/dist/motion/line.js +1 -0
  163. package/dist/motion/pie.css +1 -0
  164. package/dist/motion/pie.d.ts +8 -0
  165. package/dist/motion/pie.js +1 -0
  166. package/dist/motion/radar.css +1 -0
  167. package/dist/motion/radar.d.ts +8 -0
  168. package/dist/motion/radar.js +1 -0
  169. package/dist/motion/scatter.css +1 -0
  170. package/dist/motion/scatter.d.ts +8 -0
  171. package/dist/motion/scatter.js +1 -0
  172. package/dist/motion/sparkline.d.ts +7 -0
  173. package/dist/motion/sparkline.js +1 -0
  174. package/dist/motion-collection.d.ts +7 -0
  175. package/dist/motion-community.d.ts +40 -0
  176. package/dist/motion-policy.d.ts +14 -0
  177. package/dist/motion.css +1 -0
  178. package/dist/motion.d.ts +40 -0
  179. package/dist/motion.js +1 -0
  180. package/dist/options.d.ts +11 -0
  181. package/dist/pie.css +1 -0
  182. package/dist/pie.d.ts +5 -0
  183. package/dist/pie.js +1 -0
  184. package/dist/radar.css +1 -0
  185. package/dist/radar.d.ts +4 -0
  186. package/dist/radar.js +1 -0
  187. package/dist/runtime.d.ts +4 -0
  188. package/dist/scatter.css +1 -0
  189. package/dist/scatter.d.ts +5 -0
  190. package/dist/scatter.js +1 -0
  191. package/dist/sparkline-runtime/runtime.d.ts +10 -0
  192. package/dist/sparkline-validation.d.ts +3 -0
  193. package/dist/sparkline.css +25 -0
  194. package/dist/sparkline.d.ts +44 -0
  195. package/dist/sparkline.js +1 -0
  196. package/dist/state-announcement.d.ts +6 -0
  197. package/dist/styles.css +496 -0
  198. package/dist/theme.css +1391 -0
  199. package/dist/types.d.ts +137 -0
  200. package/dist/validation.d.ts +8 -0
  201. package/dist/web-api.json +4305 -0
  202. package/dist/web-motion-sparkline.d.ts +4 -0
  203. package/edition.json +48 -0
  204. package/package.json +103 -4
  205. package/src/accessibility.ts +81 -0
  206. package/src/assets.d.ts +1 -0
  207. package/src/async.ts +12 -0
  208. package/src/bar.ts +13 -0
  209. package/src/builders/bar.ts +39 -0
  210. package/src/builders/doughnut.ts +66 -0
  211. package/src/builders/heatmap.ts +60 -0
  212. package/src/builders/line.ts +39 -0
  213. package/src/builders/pie.ts +66 -0
  214. package/src/builders/radar.ts +65 -0
  215. package/src/builders/scatter.ts +34 -0
  216. package/src/catalogue-model.ts +235 -0
  217. package/src/catalogue-runtime.ts +244 -0
  218. package/src/catalogue-types.ts +163 -0
  219. package/src/chart-state.ts +35 -0
  220. package/src/charts.css +135 -0
  221. package/src/colors.ts +277 -0
  222. package/src/community.ts +11 -0
  223. package/src/doughnut.ts +12 -0
  224. package/src/export.ts +50 -0
  225. package/src/heatmap.ts +11 -0
  226. package/src/index.ts +11 -0
  227. package/src/legend-export.ts +36 -0
  228. package/src/legend-model.ts +76 -0
  229. package/src/legend.css +64 -0
  230. package/src/legend.ts +90 -0
  231. package/src/limits.ts +7 -0
  232. package/src/line.ts +13 -0
  233. package/src/loading-state.ts +39 -0
  234. package/src/map-assets.ts +1 -0
  235. package/src/map-resources.ts +46 -0
  236. package/src/messages.ts +5 -0
  237. package/src/model.ts +32 -0
  238. package/src/motion/bar.ts +15 -0
  239. package/src/motion/doughnut.ts +14 -0
  240. package/src/motion/heatmap.ts +14 -0
  241. package/src/motion/line.ts +15 -0
  242. package/src/motion/pie.ts +14 -0
  243. package/src/motion/radar.ts +15 -0
  244. package/src/motion/scatter.ts +15 -0
  245. package/src/motion/sparkline.ts +10 -0
  246. package/src/motion-collection.ts +20 -0
  247. package/src/motion-community.ts +22 -0
  248. package/src/motion-policy.ts +36 -0
  249. package/src/options.ts +24 -0
  250. package/src/pie.ts +12 -0
  251. package/src/radar.ts +12 -0
  252. package/src/runtime.ts +7 -0
  253. package/src/scatter.ts +13 -0
  254. package/src/sparkline-runtime/runtime.d.ts +10 -0
  255. package/src/sparkline-runtime/runtime.js +263 -0
  256. package/src/sparkline-validation.ts +19 -0
  257. package/src/sparkline.css +25 -0
  258. package/src/sparkline.ts +68 -0
  259. package/src/state-announcement.ts +17 -0
  260. package/src/types.ts +104 -0
  261. package/src/validation.ts +75 -0
  262. package/src/web-motion-sparkline.ts +37 -0
@@ -0,0 +1,15 @@
1
+ /** Optional motion factory; preserves the original chart contract. */
2
+ import type {ComponentMotionSettings} from '@blukavantui/community/motion/settings';
3
+ import {configuredChart,type MotionState} from '../motion-policy.ts';
4
+ import {use} from 'echarts/core';
5
+ import {createChartRuntime} from '../catalogue-runtime.ts';
6
+ import {ScatterChart} from 'echarts/charts';
7
+ import {GridComponent} from 'echarts/components';
8
+ import {buildOption as scatter} from '../builders/scatter.ts';
9
+ import type {ChartPoint,ScatterOptions} from '../catalogue-types.ts';
10
+ import type {ChartEvents} from '../types.ts';
11
+ export function createMotionScatterChart(host: HTMLElement, options: ScatterOptions, motion: MotionState, events: ChartEvents<ChartPoint> = {}, settings:ComponentMotionSettings = {}) {
12
+ return configuredChart(host,motion,settings,(policy,host)=>{
13
+ use([ScatterChart, GridComponent]); return createChartRuntime<ScatterOptions, ChartPoint>(host, 'scatter', options, events, scatter, policy);
14
+ });
15
+ }
@@ -0,0 +1,10 @@
1
+ /** Optional motion factory; preserves the original chart contract. */
2
+ import type {ComponentMotionSettings} from '@blukavantui/community/motion/settings';
3
+ import {configuredChart,type MotionState} from '../motion-policy.ts';
4
+ import {createMotionSparkline as sparklineWithPolicy} from '../web-motion-sparkline.ts';
5
+ import type {SparklineOptions,SparklineEvents} from '../sparkline.ts';
6
+ export function createMotionSparkline(host: HTMLElement, options: SparklineOptions, motion: MotionState, events: SparklineEvents = {}, settings:ComponentMotionSettings = {}) {
7
+ return configuredChart(host,motion,settings,(policy,host)=>{
8
+ return sparklineWithPolicy(host, options, events, policy);
9
+ });
10
+ }
@@ -0,0 +1,20 @@
1
+ import {createMotionSettingsGroup} from '@blukavantui/community/motion/settings';
2
+ import type {ComponentMotionSettings} from '@blukavantui/community/motion/settings';
3
+ import type {MotionState} from './motion-policy.ts';
4
+ export function bindMotionCharts<F extends Record<string, (host:any,options:any,motion:MotionState,events?:any,settings?:ComponentMotionSettings)=>any>>(factories:F, motion:MotionState,defaults:ComponentMotionSettings={}) {
5
+ const settings=createMotionSettingsGroup(defaults);
6
+ const owned=new Set<{destroy():void}>(); let dead=false;
7
+ function bind<F extends (host:any,options:any,motion:MotionState,events?:any,settings?:ComponentMotionSettings)=>any>(factory:F) {
8
+ return (host:Parameters<F>[0],options:Parameters<F>[1],events:Parameters<F>[3]={}):ReturnType<F> => {
9
+ if(dead)throw Error('Motion charts are destroyed.');
10
+ const instance=factory(host,options,motion,events,settings.settings),destroy=instance.destroy.bind(instance);let disposed=false;
11
+ const binding=settings.bind(instance.setMotion);instance.setMotion=binding.setMotion;
12
+ instance.destroy=()=>{if(disposed)return;disposed=true;owned.delete(instance);binding.destroy();destroy();};owned.add(instance);return instance;
13
+ };
14
+ }
15
+ return {
16
+ configure(next:ComponentMotionSettings={}){if(dead)throw Error('Motion charts are destroyed.');settings.configure(next);},
17
+ ...Object.fromEntries(Object.entries(factories).map(([name,factory])=>[name,bind(factory)])) as {[K in keyof F]:(host:Parameters<F[K]>[0],options:Parameters<F[K]>[1],events?:Parameters<F[K]>[3])=>ReturnType<F[K]>},
18
+ destroy(){if(dead)return;dead=true;for(const instance of [...owned])instance.destroy();}
19
+ };
20
+ }
@@ -0,0 +1,22 @@
1
+ import {bindMotionCharts} from './motion-collection.ts';
2
+ import type {MotionState} from './motion-policy.ts';
3
+ import type {ComponentMotionSettings} from '@blukavantui/community/motion/settings';
4
+ import {createMotionSparkline} from './motion/sparkline.ts';
5
+ export {createMotionSparkline} from './motion/sparkline.ts';
6
+ import {createMotionLineChart} from './motion/line.ts';
7
+ export {createMotionLineChart} from './motion/line.ts';
8
+ import {createMotionBarChart} from './motion/bar.ts';
9
+ export {createMotionBarChart} from './motion/bar.ts';
10
+ import {createMotionPieChart} from './motion/pie.ts';
11
+ export {createMotionPieChart} from './motion/pie.ts';
12
+ import {createMotionDoughnutChart} from './motion/doughnut.ts';
13
+ export {createMotionDoughnutChart} from './motion/doughnut.ts';
14
+ import {createMotionScatterChart} from './motion/scatter.ts';
15
+ export {createMotionScatterChart} from './motion/scatter.ts';
16
+ import {createMotionRadarChart} from './motion/radar.ts';
17
+ export {createMotionRadarChart} from './motion/radar.ts';
18
+ import {createMotionHeatmap} from './motion/heatmap.ts';
19
+ export {createMotionHeatmap} from './motion/heatmap.ts';
20
+ export function createMotionCharts(motion:MotionState,defaults:ComponentMotionSettings={}) {
21
+ return bindMotionCharts({createSparkline:createMotionSparkline,createLineChart:createMotionLineChart,createBarChart:createMotionBarChart,createPieChart:createMotionPieChart,createDoughnutChart:createMotionDoughnutChart,createScatterChart:createMotionScatterChart,createRadarChart:createMotionRadarChart,createHeatmap:createMotionHeatmap},motion,defaults);
22
+ }
@@ -0,0 +1,36 @@
1
+ import type {ChartPresentation} from './catalogue-runtime.ts';
2
+ import {createComponentMotionState,validateComponentMotion,type ComponentMotionSettings} from '@blukavantui/community/motion/settings';
3
+ import {motionEasings} from '@blukavantui/community/motion';
4
+ export interface MotionState { readonly mode:'full'|'reduced'|'off'; }
5
+ const engineEasing={standard:'cubicOut','ease-in':'cubicIn','ease-out':'cubicOut','ease-in-out':'cubicInOut',linear:'linear',spring:'backOut'};
6
+ export function chartMotionPolicy(motion:MotionState,state?:ReturnType<typeof createComponentMotionState>) {
7
+ const listeners=new Set<()=>void>();
8
+ const policy:ChartPresentation & {notify():void} = {
9
+ mode(host) {
10
+ if(motion.mode==='off'||host.closest('[data-blu-motion="off"], .blu-motion-off'))return 'off';
11
+ return motion.mode==='reduced'||host.closest('[data-blu-motion="reduced"]')?'reduced':'full';
12
+ },
13
+ timing() {const s=state?.settings;return {duration:s?.duration,easing:s?.easing?engineEasing[s.easing]:undefined,curve:s?.easing?motionEasings[s.easing]:undefined};},
14
+ subscribe(host,refresh) {
15
+ let previous=policy.mode(host);
16
+ const changed=()=>{previous=policy.mode(host);refresh();};listeners.add(changed);
17
+ const observer=new MutationObserver(()=>{if(policy.mode(host)!==previous)changed();});
18
+ for(let ancestor:HTMLElement|null=host;ancestor;ancestor=ancestor.parentElement)observer.observe(ancestor,{attributes:true,attributeFilter:['data-blu-motion','class']});
19
+ return ()=>{listeners.delete(changed);observer.disconnect();};
20
+ },
21
+ notify(){for(const listener of listeners)listener();},
22
+ };
23
+ return policy;
24
+ }
25
+ /** Preserves the original chart instance, selection, events, licence and disposal. */
26
+ export function configuredChart<C extends {destroy():void}>(host:HTMLElement,motion:MotionState,settings:ComponentMotionSettings,create:(policy:ChartPresentation,root:HTMLElement)=>C) {
27
+ validateComponentMotion(settings);
28
+ // A collection may append several charts to one host. Each owns its own scope.
29
+ const root=document.createElement('div');root.className='blu-chart-motion-scope';host.append(root);
30
+ const state=createComponentMotionState(root,motion,settings),policy=chartMotionPolicy(motion,state);
31
+ let instance:C;
32
+ try{instance=create(policy,root);}catch(error){state.destroy();root.remove();throw error;}
33
+ const destroy=instance.destroy.bind(instance);let dead=false;
34
+ instance.destroy=()=>{if(dead)return;dead=true;destroy();state.destroy();root.remove();};
35
+ return Object.assign(instance,{setMotion(next:ComponentMotionSettings={}){if(dead)throw Error('Chart motion is destroyed.');state.update(next);policy.notify();}});
36
+ }
package/src/options.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { EChartsCoreOption } from 'echarts/core';
2
+ import type { MixedChartOptions, HeatmapOptions, ChartOptions } from './types.ts';
3
+ import { formatValue, heatmapRange, heatmapPoint } from './model.ts';
4
+ import { automaticPalette, componentPalette, isComponentColor, resolveChartColor, contrastText, interpolateColor } from './colors.ts';
5
+ import { markColor, markStyle, highlightStyle, sequentialScale, seriesSymbol, seriesDash, seriesDecal } from './accessibility.ts';
6
+ import { escapeText } from './validation.ts';
7
+
8
+ export interface ChartTheme { surface: string; text: string; muted: string; border: string; dark: boolean; forcedColors?: boolean; read: (name: string) => string; palette: string[]; }
9
+ export function themeTokens(host: HTMLElement): ChartTheme {
10
+ const style = getComputedStyle(host);
11
+ const read = (name: string, fallback: string) => style.getPropertyValue(name).trim() || fallback;
12
+ const dark = document.documentElement.dataset.bluuiTheme === 'dark';
13
+ const forcedColors = matchMedia('(forced-colors: active)').matches;
14
+ if (forcedColors) {
15
+ const probe = document.createElement('span');
16
+ probe.style.cssText = 'position:absolute;visibility:hidden;color:Canvas;background-color:CanvasText;forced-color-adjust:none';
17
+ host.append(probe);
18
+ const computed = getComputedStyle(probe), surface = computed.color, text = computed.backgroundColor;
19
+ probe.remove();
20
+ return { surface, text, muted: text, border: text, dark, forcedColors, read: () => '', palette: Array(8).fill(text) };
21
+ }
22
+ return { forcedColors, surface: read('--bluui-surface', '#fff'), text: read('--bluui-text', '#182230'), muted: read('--bluui-text-muted', '#667085'), border: read('--bluui-border', '#e3e5ed'), dark, read: (name: string) => style.getPropertyValue(name),
23
+ palette: automaticPalette(dark) };
24
+ }
package/src/pie.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { buildOption } from './builders/pie.ts';
2
+ import { use } from 'echarts/core';
3
+ import { PieChart } from 'echarts/charts';
4
+ import { createCatalogueChart } from './catalogue-runtime.ts';
5
+ import type { OptionsByKind, ChartPoint } from './catalogue-types.ts';
6
+ import type { ChartEvents } from './types.ts';
7
+ export type { OptionsByKind, ChartPoint } from './catalogue-types.ts';
8
+ export type PieChartOptions = OptionsByKind['pie'];
9
+ export function createPieChart(host: HTMLElement, options: PieChartOptions, events: ChartEvents<ChartPoint> = {}) {
10
+ use([PieChart]);
11
+ return createCatalogueChart(host, 'pie', options, events, buildOption);
12
+ }
package/src/radar.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { buildOption } from './builders/radar.ts';
2
+ import { use } from 'echarts/core';
3
+ import { RadarChart } from 'echarts/charts';
4
+ import { RadarComponent } from 'echarts/components';
5
+ import { createCatalogueChart } from './catalogue-runtime.ts';
6
+ import type { RadarOptions, ChartPoint } from './catalogue-types.ts';
7
+ import type { ChartEvents } from './types.ts';
8
+ export type { RadarOptions, RadarCategory } from './catalogue-types.ts';
9
+ export function createRadarChart(host: HTMLElement, options: RadarOptions, events: ChartEvents<ChartPoint> = {}) {
10
+ use([RadarChart, RadarComponent]);
11
+ return createCatalogueChart(host, 'radar', options, events, buildOption);
12
+ }
package/src/runtime.ts ADDED
@@ -0,0 +1,7 @@
1
+ import {createChartRuntime} from './catalogue-runtime.ts';
2
+ import type {MixedChartOptions,HeatmapOptions,MixedPoint,HeatmapPoint,ChartEvents,ChartInstance} from './types.ts';
3
+ import type {EChartsCoreOption} from 'echarts/core';
4
+ import type {themeTokens} from './options.ts';
5
+ export function createChart<O extends MixedChartOptions|HeatmapOptions,P extends MixedPoint|HeatmapPoint>(host:HTMLElement,kind:'mixed'|'heatmap',initial:O,events:ChartEvents<P>,build:(o:any,t:ReturnType<typeof themeTokens>)=>EChartsCoreOption):ChartInstance<O> {
6
+ return createChartRuntime(host,kind,initial,events,build);
7
+ }
package/src/scatter.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { buildOption } from './builders/scatter.ts';
2
+ import { use } from 'echarts/core';
3
+ import { ScatterChart } from 'echarts/charts';
4
+ import { GridComponent } from 'echarts/components';
5
+ import { createCatalogueChart } from './catalogue-runtime.ts';
6
+ import type { OptionsByKind, ChartPoint } from './catalogue-types.ts';
7
+ import type { ChartEvents } from './types.ts';
8
+ export type { OptionsByKind, ChartPoint } from './catalogue-types.ts';
9
+ export type ScatterChartOptions = OptionsByKind['scatter'];
10
+ export function createScatterChart(host: HTMLElement, options: ScatterChartOptions, events: ChartEvents<ChartPoint> = {}) {
11
+ use([ScatterChart, GridComponent]);
12
+ return createCatalogueChart(host, 'scatter', options, events, buildOption);
13
+ }
@@ -0,0 +1,10 @@
1
+ export function installSparkline(): {
2
+ sync(id: string, options: object, events: { Error?(message: string): unknown }, key: string): string;
3
+ destroy(key: string): void;
4
+ geometry(raw: string | Array<{ Value: number; Label?: string }>, height: number, width?: number, lineStyle?: 'Straight' | 'Smooth'): {
5
+ rows: Array<{ Value: number; Label?: string }>;
6
+ coordinates: number[][];
7
+ line: string;
8
+ area: string;
9
+ };
10
+ };
@@ -0,0 +1,263 @@
1
+ // Lightweight SVG renderer, migrated from the Community Sparkline.
2
+ // Module-local ownership keeps Charts independent of the native UI runtime.
3
+ var shared = { instances: new Map(), serial: 0 };
4
+ var installed;
5
+ function el(tag, cls, text) {
6
+ var n = document.createElement(tag);
7
+ if (cls) n.className = cls;
8
+ if (text !== void 0) n.textContent = text;
9
+ return n;
10
+ }
11
+ function attr(n, key, value) {
12
+ n.setAttribute(key, String(value));
13
+ return n;
14
+ }
15
+ function report(s, message) {
16
+ if (!s.error) {
17
+ s.error = attr(el("p", "blu-common-error"), "role", "alert");
18
+ s.host.append(s.error);
19
+ }
20
+ s.error.textContent = message;
21
+ s.error.hidden = !message;
22
+ if (message && s.lastError !== message && s.events.Error) {
23
+ s.lastError = message;
24
+ try {
25
+ s.events.Error(message);
26
+ } catch (_) {
27
+ }
28
+ }
29
+ if (!message) s.lastError = "";
30
+ }
31
+ function integer(value, fallback, min, max) {
32
+ value = value === void 0 ? fallback : Number(value);
33
+ if (!Number.isInteger(value) || value < min || value > max) throw Error("Expected an integer between " + min + " and " + max + ".");
34
+ return value;
35
+ }
36
+ function destroy(key) {
37
+ var s = shared.instances.get(key);
38
+ if (!s) return;
39
+ s.dead = true;
40
+ s.cleanup.forEach(function(f) {
41
+ f();
42
+ });
43
+ s.owned.forEach(function(n) {
44
+ n.remove();
45
+ });
46
+ if (s.host._bluChartsSparklineOwner === key) {
47
+ delete s.host._bluChartsSparklineOwner;
48
+ s.host.removeAttribute("data-blu-ready");
49
+ }
50
+ shared.instances.delete(key);
51
+ }
52
+ function own(s, node) {
53
+ s.owned.push(node);
54
+ return node;
55
+ }
56
+ function geometry(raw, height, width = 300, lineStyle = 'Smooth') {
57
+ var rows = typeof raw === "string" ? JSON.parse(raw || "[]") : raw || [];
58
+ if (!Array.isArray(rows) || rows.length > 1e4) throw Error("Points must be a list with at most 10,000 items.");
59
+ var values = rows.map(function(p) {
60
+ if (!p || typeof p.Value !== "number" || !Number.isFinite(p.Value)) throw Error("Every Sparkline point needs a finite numeric Value.");
61
+ return p.Value;
62
+ });
63
+ if (!values.length) return { rows, coordinates: [], line: "", area: "" };
64
+ var min = Math.min.apply(null, values), max = Math.max.apply(null, values), range = max - min;
65
+ var scale = Math.max(Math.abs(min), Math.abs(max), 1), low = min / scale, spread = max / scale - low;
66
+ var coordinates = values.map(function(value, index) {
67
+ return [values.length === 1 ? width / 2 : 6 + index * (width - 12) / (values.length - 1), spread ? height - 6 - (value / scale - low) / spread * (height - 12) : height / 2];
68
+ });
69
+ var line = coordinates.map(function(p, i) {
70
+ return (i ? "L" : "M") + p[0].toFixed(3) + " " + p[1].toFixed(3);
71
+ }).join(" ");
72
+ if (lineStyle === 'Smooth' && coordinates.length > 2) {
73
+ // Monotone cubic interpolation keeps each segment within its observed values.
74
+ var step = (width - 12) / (coordinates.length - 1);
75
+ var slopes = coordinates.slice(1).map(function(p, i) { return (p[1] - coordinates[i][1]) / step; });
76
+ var tangents = coordinates.map(function(_, i) {
77
+ if (i === 0) return slopes[0];
78
+ if (i === coordinates.length - 1) return slopes[i - 1];
79
+ var before = slopes[i - 1], after = slopes[i];
80
+ return before * after > 0 ? 2 * before * after / (before + after) : 0;
81
+ });
82
+ line = 'M' + coordinates[0][0].toFixed(3) + ' ' + coordinates[0][1].toFixed(3);
83
+ for (var i = 1; i < coordinates.length; i++) {
84
+ var start = coordinates[i - 1], end = coordinates[i];
85
+ line += ' C' + (start[0] + step / 3).toFixed(3) + ' ' + (start[1] + tangents[i - 1] * step / 3).toFixed(3)
86
+ + ' ' + (end[0] - step / 3).toFixed(3) + ' ' + (end[1] - tangents[i] * step / 3).toFixed(3)
87
+ + ' ' + end[0].toFixed(3) + ' ' + end[1].toFixed(3);
88
+ }
89
+ }
90
+ return { rows, coordinates, line, area: line + " L" + coordinates[coordinates.length - 1][0] + " " + (height - 4) + " L" + coordinates[0][0] + " " + (height - 4) + " Z", min, max, first: values[0], last: values[values.length - 1] };
91
+ }
92
+ function sparkline(s) {
93
+ var o = s.options, width = Math.max(24, Math.round(s.host.clientWidth || 300)), signature = JSON.stringify([o, width, s.reducedMotion.matches]);
94
+ const msg=(key,fallback,values={})=>(o.Messages?.[key]??fallback).replace(/\{(\w+)\}/g,(token,name)=>values[name]??token);
95
+ if (s.renderSignature === signature) return;
96
+ var lineStyle = o.LineStyle || 'Smooth';
97
+ if (!['Straight', 'Smooth'].includes(lineStyle)) throw Error('LineStyle must be Straight or Smooth.');
98
+ var height = integer(o.Height, 64, 24, 240), geometryKey = JSON.stringify([o.PointsJson, height, width, lineStyle]);
99
+ var g = s.geometryKey === geometryKey ? s.geometry : geometry(o.PointsJson, height, width, lineStyle);
100
+ var animation = o.Animation || (o.AnimateGlow === false ? 'Off' : 'Once');
101
+ if (!['Off', 'Once', 'Continuous'].includes(animation)) throw Error('Animation must be Off, Once or Continuous.');
102
+ var duration = o.AnimationDuration === undefined ? 5 : Number(o.AnimationDuration);
103
+ if (!Number.isFinite(duration) || duration < 1 || duration > 60) throw Error('AnimationDuration must be between 1 and 60 seconds.');
104
+ var opacity = o.AreaOpacity === undefined ? 18 : Number(o.AreaOpacity);
105
+ if (!Number.isFinite(opacity) || opacity < 0 || opacity > 100) throw Error('AreaOpacity must be between 0 and 100 percent.');
106
+ if (s.animation !== animation) s.animationPaused = false;
107
+ s.animation = animation;
108
+ s.geometryKey = geometryKey;
109
+ s.geometry = g;
110
+ var color = String(o.Color || "Primary").toLowerCase();
111
+ if ("default primary secondary success processing warning error danger magenta red volcano orange gold lime green cyan blue geekblue purple".split(" ").indexOf(color) < 0) throw Error("Unknown ComponentColor.");
112
+ if (!s.body) {
113
+ s.body = own(s, el("div", "blu-sparkline"));
114
+ s.host.append(s.body);
115
+ }
116
+ var body = s.body, wasOpen = !!(body.querySelector("details") && body.querySelector("details").open), hadFocus = body.contains(document.activeElement);
117
+ while (body.firstChild) body.removeChild(body.firstChild);
118
+ body.style.setProperty("--blu-sparkline-color", "var(--bluui-color-" + color + "-text)");
119
+ body.style.setProperty("--blu-sparkline-height", height + "px");
120
+ if (!g.rows.length) {
121
+ body.append(el("p", "blu-sparkline__empty", o.EmptyText || "No trend data."));
122
+ s.renderSignature = signature;
123
+ return;
124
+ }
125
+ var ns = "http://www.w3.org/2000/svg", svg = document.createElementNS(ns, "svg");
126
+ attr(svg, "viewBox", "0 0 " + width + " " + height);
127
+ attr(svg, "preserveAspectRatio", "none");
128
+ attr(svg, "role", "img");
129
+ const direction=g.last>g.first?'Rising':g.last<g.first?'Falling':'Unchanged';
130
+ var summary = o.SummaryText || msg('TrendSummary','{count} points. {direction} from {first} to {last}. Minimum {min}, maximum {max}.',{count:g.rows.length,direction:msg(direction,direction),first:g.first,last:g.last,min:g.min,max:g.max});
131
+ attr(svg, "aria-label", (o.AccessibleLabel || "Trend") + ". " + summary);
132
+ var title = document.createElementNS(ns, "title");
133
+ title.textContent = (o.AccessibleLabel || "Trend") + ". " + summary;
134
+ svg.append(title);
135
+ if (o.ShowArea !== false && g.rows.length > 1) {
136
+ var defs = document.createElementNS(ns, 'defs'), gradient = document.createElementNS(ns, 'linearGradient');
137
+ attr(gradient, 'id', s.uid + '-area');
138
+ attr(gradient, 'x1', '0%'); attr(gradient, 'y1', '0%'); attr(gradient, 'x2', '0%'); attr(gradient, 'y2', '100%');
139
+ [opacity / 100, o.AreaFade === false ? opacity / 100 : 0].forEach(function(value, index) {
140
+ var stop = document.createElementNS(ns, 'stop');
141
+ attr(stop, 'offset', index ? '100%' : '0%');
142
+ stop.style.stopColor = 'var(--blu-sparkline-color)';
143
+ attr(stop, 'stop-opacity', value); gradient.append(stop);
144
+ });
145
+ defs.append(gradient); svg.append(defs);
146
+ var area = document.createElementNS(ns, "path");
147
+ attr(area, "d", g.area);
148
+ attr(area, "class", "blu-sparkline__area");
149
+ area.style.fill = 'url(#' + s.uid + '-area)';
150
+ svg.append(area);
151
+ }
152
+ var path = document.createElementNS(ns, "path");
153
+ attr(path, "d", g.line);
154
+ attr(path, "class", "blu-sparkline__line");
155
+ attr(path, "vector-effect", "non-scaling-stroke");
156
+ svg.append(path);
157
+ var moving = animation !== 'Off' && g.rows.length > 1 && !s.reducedMotion.matches;
158
+ if ((!moving && o.ShowEndMarker !== false) || g.rows.length === 1) {
159
+ var p = g.coordinates[g.coordinates.length - 1], circle = document.createElementNS(ns, "circle");
160
+ attr(circle, "cx", p[0]);
161
+ attr(circle, "cy", p[1]);
162
+ attr(circle, "r", 3);
163
+ attr(circle, "class", "blu-sparkline__point");
164
+ svg.append(circle);
165
+ }
166
+ if (moving) {
167
+ var traveler = document.createElementNS(ns, 'g');
168
+ attr(traveler, 'class', 'blu-sparkline__traveler'); attr(traveler, 'aria-hidden', 'true');
169
+ [['halo', 6], ['ring', 4.5], ['cursor', 3]].forEach(function(part) {
170
+ var marker = document.createElementNS(ns, 'circle');
171
+ attr(marker, 'r', part[1]);
172
+ attr(marker, 'class', 'blu-sparkline__' + part[0]); traveler.append(marker);
173
+ });
174
+ var motion = document.createElementNS(ns, 'animateMotion'), fade = document.createElementNS(ns, 'animate');
175
+ attr(motion, 'path', g.line); attr(motion, 'calcMode', 'spline');
176
+ attr(motion, 'keyPoints', '0;1'); attr(motion, 'keyTimes', '0;1');
177
+ attr(motion, 'keySplines', '0.22 0.61 0.36 1');
178
+ attr(fade, 'attributeName', 'opacity'); attr(fade, 'values', '0;1;1;0'); attr(fade, 'keyTimes', '0;0.03;0.96;1');
179
+ [motion, fade].forEach(function(effect) {
180
+ attr(effect, 'dur', duration + 's'); attr(effect, 'repeatCount', animation === 'Continuous' ? 'indefinite' : '1'); attr(effect, 'fill', 'freeze'); traveler.append(effect);
181
+ });
182
+ svg.append(traveler);
183
+ }
184
+ body.append(svg);
185
+ if (moving && (animation === 'Continuous' || duration > 5)) {
186
+ var pause = el('button', 'blu-sparkline__pause'); pause.type = 'button';
187
+ var updatePause = function() {
188
+ pause.textContent = s.animationPaused ? msg('ResumeAnimation','Resume animation') : msg('PauseAnimation','Pause animation');
189
+ if (s.animationPaused) svg.pauseAnimations(); else svg.unpauseAnimations();
190
+ };
191
+ pause.addEventListener('click', function() { s.animationPaused = !s.animationPaused; updatePause(); });
192
+ body.append(pause); updatePause();
193
+ }
194
+ if (o.ShowDataTable) {
195
+ let buildTable = function() {
196
+ if (!details.open || tableBuilt) return;
197
+ var table = el("table"), caption = el("caption", "", o.AccessibleLabel || "Trend"), thead = el("thead"), headings = el("tr");
198
+ headings.append(attr(el("th", "", msg('Point','Point')), "scope", "col"), attr(el("th", "", msg('Value','Value')), "scope", "col"));
199
+ thead.append(headings);
200
+ table.append(caption, thead);
201
+ var tbody = el("tbody");
202
+ g.rows.forEach(function(row, index) {
203
+ var tr = el("tr");
204
+ tr.append(attr(el("th", "", row.Label || String(index + 1)), "scope", "row"), el("td", "", String(row.Value)));
205
+ tbody.append(tr);
206
+ });
207
+ table.append(tbody);
208
+ details.append(table);
209
+ tableBuilt = true;
210
+ };
211
+ var details = el("details", "blu-sparkline__data");
212
+ details.open = wasOpen;
213
+ details.append(el("summary", "", msg('ViewData','View trend data')));
214
+ var tableBuilt = false;
215
+ details.addEventListener("toggle", buildTable);
216
+ body.append(details);
217
+ buildTable();
218
+ if (hadFocus) details.querySelector("summary").focus();
219
+ }
220
+ s.renderSignature = signature;
221
+ }
222
+ function api(kind, render) {
223
+ return { sync: function(id, options, events, key) {
224
+ var host = document.getElementById(id);
225
+ if (!host) return "Component host was not found.";
226
+ key = key || id;
227
+ var s = shared.instances.get(key);
228
+ if (s && s.host !== host) {
229
+ destroy(key);
230
+ s = null;
231
+ }
232
+ if (host._bluChartsSparklineOwner && host._bluChartsSparklineOwner !== key) destroy(host._bluChartsSparklineOwner);
233
+ if (!s) {
234
+ s = { host, key, uid: "blu-charts-trend-" + ++shared.serial, owned: [], cleanup: [], reducedMotion: matchMedia('(prefers-reduced-motion: reduce)') };
235
+ shared.instances.set(key, s);
236
+ var refresh = function() { if (!s.dead && s.options) { try { render(s); } catch (_) {} } };
237
+ var observer = new ResizeObserver(refresh); observer.observe(host);
238
+ s.reducedMotion.addEventListener('change', refresh);
239
+ s.cleanup.push(function() { observer.disconnect(); s.reducedMotion.removeEventListener('change', refresh); });
240
+ }
241
+ var preview = host.nextElementSibling;
242
+ if (preview && preview.classList.contains("blu-component-preview")) preview.hidden = true;
243
+ host._bluChartsSparklineOwner = key;
244
+ s.options = options || {};
245
+ s.events = events || {};
246
+ attr(host, "data-blu-ready", "true");
247
+ try {
248
+ render(s);
249
+ report(s, "");
250
+ return "";
251
+ } catch (e) {
252
+ s.renderSignature = void 0;
253
+ report(s, e.message || String(e));
254
+ return e.message || String(e);
255
+ }
256
+ }, destroy };
257
+ }
258
+ function installSparkline() {
259
+ return installed || (installed = Object.assign(api("Sparkline", sparkline), { geometry }));
260
+ }
261
+ export {
262
+ installSparkline
263
+ };
@@ -0,0 +1,19 @@
1
+ import type {SparklineOptions} from './sparkline.ts';
2
+ import {boundedList,boundedText,safeNumber} from './limits.ts';
3
+ import {isComponentColor} from './colors.ts';
4
+ /** Validate before touching the SVG or committing an update. */
5
+ export function validateSparkline(o:SparklineOptions) {
6
+ boundedList(o.Points,'Points');
7
+ if(o.Messages!==undefined&&(!o.Messages||typeof o.Messages!=='object'||Array.isArray(o.Messages)||Object.keys(o.Messages).length>100||!Object.values(o.Messages).every(boundedText)))throw new Error('Messages must contain plain text translations.');
8
+ if(o.Points.some(p=>!p||!safeNumber(p.Value)||p.Label!==undefined&&!boundedText(p.Label)))throw new Error('Points require supported finite values and plain text labels.');
9
+ for(const key of ['AnimateGlow','ShowArea','AreaFade','ShowEndMarker','ShowDataTable'] as const)
10
+ if(o[key]!==undefined&&typeof o[key]!=='boolean')throw new Error(`${key} must be Boolean.`);
11
+ for(const key of ['AccessibleLabel','SummaryText','EmptyText','ExtendedClass'] as const)
12
+ if(o[key]!==undefined&&!boundedText(o[key]))throw new Error(`${key} must be plain text within the text limit.`);
13
+ if(o.Color!==undefined&&!isComponentColor(o.Color))throw new Error('Unknown ComponentColor.');
14
+ if(o.LineStyle!==undefined&&!['Straight','Smooth'].includes(o.LineStyle))throw new Error('LineStyle must be Straight or Smooth.');
15
+ if(o.Animation!==undefined&&!['Off','Once','Continuous'].includes(o.Animation))throw new Error('Animation must be Off, Once or Continuous.');
16
+ if(o.Height!==undefined&&(!Number.isInteger(o.Height)||o.Height<24||o.Height>240))throw new Error('Height must be an integer from 24 to 240.');
17
+ if(o.AnimationDuration!==undefined&&(!safeNumber(o.AnimationDuration)||o.AnimationDuration<1||o.AnimationDuration>60))throw new Error('AnimationDuration must be between 1 and 60.');
18
+ if(o.AreaOpacity!==undefined&&(!safeNumber(o.AreaOpacity)||o.AreaOpacity<0||o.AreaOpacity>100))throw new Error('AreaOpacity must be between 0 and 100.');
19
+ }
@@ -0,0 +1,25 @@
1
+ /* BluKavantUI Charts Community / Sparkline. SVG scales with the container; colors inherit the
2
+ shared palette. Values are always exposed through an accessible summary. */
3
+ .blu-sparkline { min-width: 0; width: 100%; color: var(--bluui-text); }
4
+ .blu-sparkline svg { display: block; width: 100%; height: var(--blu-sparkline-height, 64px); overflow: visible; }
5
+ .blu-sparkline__line { fill: none; stroke: var(--blu-sparkline-color); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
6
+ .blu-sparkline__area { fill: var(--blu-sparkline-color); opacity: 1; }
7
+ .blu-sparkline__point { fill: var(--blu-sparkline-color); }
8
+ .blu-sparkline__empty { margin: 0; min-height: var(--blu-sparkline-height, 64px); display: flex; align-items: center; color: var(--bluui-text-muted); }
9
+ .blu-sparkline__data { margin-top: 8px; font-size: 13px; }
10
+ .blu-sparkline__data summary { width: fit-content; padding: 6px 0; cursor: pointer; color: var(--bluui-color-primary-text); }
11
+ .blu-sparkline__data table { border-collapse: collapse; width: 100%; margin-top: 8px; }
12
+ .blu-sparkline__data :is(th,td) { padding: 6px 12px; border-bottom: 1px solid var(--bluui-border); text-align: start; }
13
+ .blu-sparkline__data summary:focus-visible { outline: 2px solid var(--bluui-primary); outline-offset: 3px; }
14
+
15
+
16
+ /* A small point and its soft halo travel along the line, easing into the end. */
17
+ .blu-sparkline__traveler { pointer-events: none; fill: var(--blu-sparkline-color); }
18
+ .blu-sparkline__halo { opacity: .18; filter: blur(1.5px); }
19
+ .blu-sparkline__ring { opacity: .12; }
20
+ .blu-sparkline__cursor { stroke: none; }
21
+ .blu-sparkline__pause { margin-top: 8px; padding: 5px 8px; min-height: 28px; border: 1px solid var(--bluui-border); border-radius: 5px; background: var(--bluui-surface); color: var(--bluui-text-muted); font: inherit; font-size: 11px; cursor: pointer; }
22
+ .blu-sparkline__pause:focus-visible { outline: 2px solid var(--bluui-primary); outline-offset: 3px; }
23
+ @media (prefers-reduced-motion: reduce), (forced-colors: active) {
24
+ .blu-sparkline__traveler { display: none; }
25
+ }
@@ -0,0 +1,68 @@
1
+ import { installSparkline } from './sparkline-runtime/runtime.js'
2
+ import type { ComponentColor } from './types.ts'
3
+ import { validateSparkline } from './sparkline-validation.ts'
4
+
5
+ /** One ordered numeric observation. */
6
+ export interface BluSparklinePoint { Label?: string; Value: number }
7
+ export interface SparklineOptions {
8
+ Points: BluSparklinePoint[]
9
+ /** Height in pixels, from 24 to 240. Defaults to 64. */
10
+ Height?: number
11
+ Color?: ComponentColor
12
+ /** A smooth curve that stays within the data range, or straight segments. Defaults to Smooth. */
13
+ LineStyle?: 'Straight' | 'Smooth'
14
+ /** @deprecated Use Animation. False disables motion; true uses Once. */
15
+ AnimateGlow?: boolean
16
+ /** A glow and point follow the line. Defaults to Once; reduced motion disables it. */
17
+ Animation?: 'Off' | 'Once' | 'Continuous'
18
+ /** Seconds per pass, from 1 to 60. Defaults to 5. */
19
+ AnimationDuration?: number
20
+ ShowArea?: boolean
21
+ /** Area opacity from 0 to 100 percent. Defaults to 18. */
22
+ AreaOpacity?: number
23
+ /** Fade the area to transparent at the bottom. Defaults to true. */
24
+ AreaFade?: boolean
25
+ /** Final point for a static trend. Hidden during animation; a single value always remains visible. */
26
+ ShowEndMarker?: boolean
27
+ ShowDataTable?: boolean
28
+ AccessibleLabel?: string
29
+ SummaryText?: string
30
+ EmptyText?: string
31
+ ExtendedClass?: string
32
+ /** Plain-text translations for the summary, animation controls and data disclosure. */
33
+ Messages?: Record<string,string>
34
+ }
35
+ export interface SparklineEvents { Error?(message: string): unknown }
36
+ export interface SparklineInstance {
37
+ element: HTMLElement
38
+ update(options: Partial<SparklineOptions>): void
39
+ destroy(): void
40
+ }
41
+
42
+ /** Compact SVG trend. Importing this entry does not load ECharts. */
43
+ export function createSparkline(host: HTMLElement, options: SparklineOptions, events: SparklineEvents = {}): SparklineInstance {
44
+ const runtime = installSparkline()
45
+ const element = document.createElement('div')
46
+ element.id = 'blu-charts-sparkline-' + crypto.randomUUID()
47
+ host.append(element)
48
+ let current = { ...options }
49
+ let disposed = false
50
+ const update = (patch: Partial<SparklineOptions>) => {
51
+ if (disposed) throw new Error('Component is destroyed.')
52
+ const next = { ...current, ...structuredClone(patch) }
53
+ try { validateSparkline(next) } catch(error) { try { events.Error?.((error as Error).message) } catch {} throw error }
54
+ const { Points, ExtendedClass, ...rest } = next
55
+ const error = runtime.sync(element.id, { ...rest, PointsJson: JSON.stringify(Points || []) }, events, element.id)
56
+ if (error) throw new Error(error)
57
+ current = next
58
+ element.className = ExtendedClass || ''
59
+ }
60
+ const destroy = () => {
61
+ if (disposed) return
62
+ disposed = true
63
+ runtime.destroy(element.id)
64
+ element.remove()
65
+ }
66
+ try { update({}) } catch (error) { destroy(); throw error }
67
+ return { element, update, destroy }
68
+ }
@@ -0,0 +1,17 @@
1
+ /** Give a control's focus/value announcement time to settle before a chart state
2
+ * change. Keep the live region outside aria-busy so loading is not deferred. */
3
+ export function stateAnnouncement(element: HTMLElement) {
4
+ let previous = '', timer = 0;
5
+ return {
6
+ update(message: string) {
7
+ if (message === previous) return;
8
+ const initial = !previous;
9
+ previous = message;
10
+ window.clearTimeout(timer);
11
+ if (initial) { element.textContent = message; return; }
12
+ element.textContent = '';
13
+ timer = window.setTimeout(() => { if (element.isConnected) element.textContent = message; }, 150);
14
+ },
15
+ destroy() { window.clearTimeout(timer); },
16
+ };
17
+ }