@ds-mo/ui 13.6.0 → 13.7.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 (259) hide show
  1. package/dist/.package-ready.json +1 -1
  2. package/dist/agent-patterns.json +2 -2
  3. package/dist/agent.json +109 -371
  4. package/dist/angular/ds-card-chart.d.ts +18 -0
  5. package/dist/angular/{ds-card-data-viz.js → ds-card-chart.js} +10 -10
  6. package/dist/angular/ds-chart.d.ts +19 -0
  7. package/dist/angular/{ds-chart-donut.js → ds-chart.js} +15 -15
  8. package/dist/angular/ds-tooltip-chart.d.ts +12 -0
  9. package/dist/angular/{ds-chart-line.js → ds-tooltip-chart.js} +12 -12
  10. package/dist/angular/index.d.ts +1 -1
  11. package/dist/angular/index.js +3 -5
  12. package/dist/angular/proxies.d.ts +3 -5
  13. package/dist/angular/proxies.js +3 -5
  14. package/dist/components/ds-agent-activity.js +1 -1
  15. package/dist/components/ds-agent-response.js +1 -1
  16. package/dist/components/ds-agent-source-list.js +1 -1
  17. package/dist/components/ds-agent-tool-call.js +1 -1
  18. package/dist/components/ds-attachment-list.js +1 -1
  19. package/dist/components/ds-badge.js +1 -1
  20. package/dist/components/ds-banner.js +1 -1
  21. package/dist/components/ds-banner.js.map +1 -1
  22. package/dist/components/ds-bar-nav.js +1 -1
  23. package/dist/components/ds-bar-title.js +1 -1
  24. package/dist/components/ds-bar-workflow.js +1 -1
  25. package/dist/components/ds-breadcrumb.js +1 -1
  26. package/dist/components/ds-button-filled.js +1 -1
  27. package/dist/components/ds-button-unfilled.js +1 -1
  28. package/dist/components/{ds-chart-line.d.ts → ds-card-chart.d.ts} +4 -4
  29. package/dist/components/ds-card-chart.js +2 -0
  30. package/dist/components/ds-card-chart.js.map +1 -0
  31. package/dist/components/ds-card-overview.js +1 -1
  32. package/dist/components/ds-card-setting.js +1 -1
  33. package/dist/components/ds-card-setting.js.map +1 -1
  34. package/dist/components/ds-chart-legend.js +1 -1
  35. package/dist/components/ds-chart-legend.js.map +1 -1
  36. package/dist/components/{ds-chart-bar.d.ts → ds-chart.d.ts} +4 -4
  37. package/dist/components/ds-chart.js +2 -0
  38. package/dist/components/ds-chart.js.map +1 -0
  39. package/dist/components/ds-checkbox.js +1 -1
  40. package/dist/components/ds-chip.js +1 -1
  41. package/dist/components/ds-code-block.js +1 -1
  42. package/dist/components/ds-conversation-list-item.js +1 -1
  43. package/dist/components/ds-conversation-list-section.js +1 -1
  44. package/dist/components/ds-conversation-list.js +1 -1
  45. package/dist/components/ds-divider.js +1 -1
  46. package/dist/components/ds-empty-state.js +1 -1
  47. package/dist/components/ds-field.js +1 -1
  48. package/dist/components/ds-input.js +1 -1
  49. package/dist/components/ds-markdown.js +1 -1
  50. package/dist/components/ds-menu.js +1 -1
  51. package/dist/components/ds-message-actions.js +1 -1
  52. package/dist/components/ds-message-bubble.js +1 -1
  53. package/dist/components/ds-message-composer.js +1 -1
  54. package/dist/components/ds-message-composer.js.map +1 -1
  55. package/dist/components/ds-message-scroller.js +1 -1
  56. package/dist/components/ds-message.js +1 -1
  57. package/dist/components/ds-mobile-bar-nav.js +1 -1
  58. package/dist/components/ds-mobile-header.js +1 -1
  59. package/dist/components/ds-mobile-section-switcher.js +1 -1
  60. package/dist/components/ds-mobile-sheet-nav.js +1 -1
  61. package/dist/components/ds-modal.js +1 -1
  62. package/dist/components/ds-modal.js.map +1 -1
  63. package/dist/components/ds-panel-nav.js +1 -1
  64. package/dist/components/ds-panel-sub-nav.js +1 -1
  65. package/dist/components/ds-panel-tool-header.js +1 -1
  66. package/dist/components/ds-panel-tool-search.js +1 -1
  67. package/dist/components/ds-panel-tools.js +1 -1
  68. package/dist/components/ds-radio.js +1 -1
  69. package/dist/components/ds-scroll-overlay.js +1 -1
  70. package/dist/components/ds-scroll-overlay.js.map +1 -1
  71. package/dist/components/ds-select.js +1 -1
  72. package/dist/components/ds-select.js.map +1 -1
  73. package/dist/components/ds-shell-app.js +1 -1
  74. package/dist/components/ds-shell-page.js +1 -1
  75. package/dist/components/ds-shell-tools.js +1 -1
  76. package/dist/components/ds-skeleton.js +1 -1
  77. package/dist/components/ds-slider.js +1 -1
  78. package/dist/components/ds-swatch-picker.js +1 -1
  79. package/dist/components/ds-switch.js +1 -1
  80. package/dist/components/ds-tab-group.js +1 -1
  81. package/dist/components/ds-tag.js +1 -1
  82. package/dist/components/ds-text.js +1 -1
  83. package/dist/components/ds-toast.js +1 -1
  84. package/dist/components/ds-toast.js.map +1 -1
  85. package/dist/components/{ds-card-data-viz.d.ts → ds-tooltip-chart.d.ts} +4 -4
  86. package/dist/components/ds-tooltip-chart.js +2 -0
  87. package/dist/components/ds-tooltip.js +1 -1
  88. package/dist/components/ds-typing-indicator.js +1 -1
  89. package/dist/components/{p-IYy-jODg.js → p-1Zbh1MRy.js} +2 -2
  90. package/dist/components/{p-wOOAzVMC.js → p-BVsLc3t5.js} +2 -2
  91. package/dist/components/p-BZCUFHYa.js +2 -0
  92. package/dist/components/{p-D0bM3cKj.js.map → p-BZCUFHYa.js.map} +1 -1
  93. package/dist/components/{p-BBtjABBS.js → p-BjiRqLtB.js} +2 -2
  94. package/dist/components/p-Bk1A9jLm.js +2 -0
  95. package/dist/components/p-Bk1A9jLm.js.map +1 -0
  96. package/dist/components/{p-Bsfpxto1.js → p-BsBw-w1q.js} +2 -2
  97. package/dist/components/p-ByfXC1wu.js +2 -0
  98. package/dist/components/{p-1S9AW2MA.js.map → p-ByfXC1wu.js.map} +1 -1
  99. package/dist/components/{p-B6RrZQqw.js → p-C-ENnZzq.js} +2 -2
  100. package/dist/components/{p-BPyymeuR.js → p-C2U48kDH.js} +2 -2
  101. package/dist/components/{p-CKRJX0Y0.js → p-C7mCjS2t.js} +2 -2
  102. package/dist/components/{p-6B411hQA.js → p-CL8XL1eh.js} +2 -2
  103. package/dist/components/{p-DfvDNcoq.js → p-CMZVPEZ_.js} +2 -2
  104. package/dist/components/{p-BtuYufL3.js → p-CWL61nKt.js} +2 -2
  105. package/dist/components/p-CWL61nKt.js.map +1 -0
  106. package/dist/components/p-CWLrXsDQ.js +2 -0
  107. package/dist/components/{p-D2cjoj2r.js.map → p-CWLrXsDQ.js.map} +1 -1
  108. package/dist/components/{p-Di81y9Q2.js → p-CX7QIytv.js} +2 -2
  109. package/dist/components/p-CXduurfd.js +2 -0
  110. package/dist/components/p-CXduurfd.js.map +1 -0
  111. package/dist/components/p-CbAfTqlb.js +2 -0
  112. package/dist/components/{p-CuJ3J6OJ.js.map → p-CbAfTqlb.js.map} +1 -1
  113. package/dist/components/{p-DVuxzrCC.js → p-CfTThRNX.js} +2 -2
  114. package/dist/components/{p-BmNpPyzf.js → p-CkLffZGn.js} +2 -2
  115. package/dist/components/{p-B4_0Ys4w.js → p-CkyXU1YX.js} +2 -2
  116. package/dist/components/{p-iCjUWcp7.js → p-CywKWfgD.js} +2 -2
  117. package/dist/components/{p-BR_oMaas.js → p-D3UKwTEo.js} +2 -2
  118. package/dist/components/{p-Bl6A5AJq.js → p-D7z9bJ6n.js} +2 -2
  119. package/dist/components/{p-DaqFuVKZ.js → p-DAftUxvL.js} +2 -2
  120. package/dist/components/{p-BFfHIu6y.js → p-DQ94PkZA.js} +2 -2
  121. package/dist/components/{p-B-kRByho.js → p-DSpq7xQF.js} +2 -2
  122. package/dist/components/{p-og48Kh2i.js → p-DzM3TcyQ.js} +2 -2
  123. package/dist/components/p-GbTasczF.js +2 -0
  124. package/dist/components/{p-Ca6s5fLR.js → p-Mmr9b1bB.js} +2 -2
  125. package/dist/components/p-UH2AGfR0.js +2 -0
  126. package/dist/components/{p-DX4c3kZ1.js.map → p-UH2AGfR0.js.map} +1 -1
  127. package/dist/components/{p-CxgMUvqg.js → p-Z2zfShlF.js} +2 -2
  128. package/dist/components/{p-Bmo4T96l.js → p-_mClULFL.js} +2 -2
  129. package/dist/components/{p-Bb4f5SuF.js → p-jf1zCsuw.js} +2 -2
  130. package/dist/components/{p-Eep5mxtv.js → p-oiR4IoH1.js} +2 -2
  131. package/dist/components/{p-DHF5cLzr.js → p-u2OZHaLY.js} +2 -2
  132. package/dist/docs/components.json +180 -662
  133. package/dist/lib/utils/chart-grammar.d.ts +359 -0
  134. package/dist/lib/utils/index.d.ts +2 -0
  135. package/dist/lib/utils/index.js +504 -0
  136. package/dist/lib/utils/index.js.map +4 -4
  137. package/dist/lib/utils/token-defaults.d.ts +3 -0
  138. package/dist/mcp-data/registry/banner.json +2 -2
  139. package/dist/mcp-data/registry/card-chart.json +238 -0
  140. package/dist/mcp-data/registry/card-overview.json +2 -2
  141. package/dist/mcp-data/registry/card-setting.json +2 -2
  142. package/dist/mcp-data/registry/chart-legend.json +11 -18
  143. package/dist/mcp-data/registry/chart.json +258 -0
  144. package/dist/mcp-data/registry/mobile-bar-nav.json +3 -3
  145. package/dist/mcp-data/registry/registry.json +108 -376
  146. package/dist/mcp-data/registry/tooltip-chart.json +253 -0
  147. package/dist/mcp-data/registry/tooltip.json +2 -2
  148. package/dist/react/components.d.ts +3 -5
  149. package/dist/react/components.js +3 -5
  150. package/dist/react/ds-card-chart.d.ts +12 -0
  151. package/dist/react/ds-card-chart.js +12 -0
  152. package/dist/react/ds-chart.d.ts +12 -0
  153. package/dist/react/ds-chart.js +12 -0
  154. package/dist/react/{ds-chart-bar.d.ts → ds-tooltip-chart.d.ts} +3 -3
  155. package/dist/react/ds-tooltip-chart.js +12 -0
  156. package/dist/types/components/{CardDataViz/CardDataViz.d.ts → CardChart/CardChart.d.ts} +9 -13
  157. package/dist/types/components/CardChart/index.d.ts +2 -0
  158. package/dist/types/components/Chart/Chart.d.ts +66 -0
  159. package/dist/types/components/Chart/index.d.ts +2 -0
  160. package/dist/types/components/ChartLegend/ChartLegend.d.ts +1 -1
  161. package/dist/types/components/{TooltipDataViz/TooltipDataViz.d.ts → TooltipChart/TooltipChart.d.ts} +15 -6
  162. package/dist/types/components/TooltipChart/index.d.ts +2 -0
  163. package/dist/types/components.d.ts +129 -294
  164. package/dist/types/utils/chart-grammar.d.ts +360 -0
  165. package/dist/types/utils/chart-scene.d.ts +128 -0
  166. package/dist/types/utils/chart-theme.d.ts +27 -0
  167. package/dist/types/utils/chart-types.d.ts +0 -13
  168. package/dist/types/utils/index.d.ts +2 -0
  169. package/dist/types/utils/token-defaults.d.ts +3 -0
  170. package/package.json +1 -1
  171. package/dist/angular/ds-card-data-viz.d.ts +0 -18
  172. package/dist/angular/ds-chart-bar.d.ts +0 -12
  173. package/dist/angular/ds-chart-bar.js +0 -38
  174. package/dist/angular/ds-chart-donut.d.ts +0 -19
  175. package/dist/angular/ds-chart-line.d.ts +0 -12
  176. package/dist/angular/ds-tooltip-data-viz.d.ts +0 -12
  177. package/dist/angular/ds-tooltip-data-viz.js +0 -38
  178. package/dist/components/ds-card-data-viz.js +0 -2
  179. package/dist/components/ds-card-data-viz.js.map +0 -1
  180. package/dist/components/ds-chart-bar.js +0 -2
  181. package/dist/components/ds-chart-bar.js.map +0 -1
  182. package/dist/components/ds-chart-donut.d.ts +0 -11
  183. package/dist/components/ds-chart-donut.js +0 -2
  184. package/dist/components/ds-chart-donut.js.map +0 -1
  185. package/dist/components/ds-chart-line.js +0 -2
  186. package/dist/components/ds-chart-line.js.map +0 -1
  187. package/dist/components/ds-tooltip-data-viz.d.ts +0 -11
  188. package/dist/components/ds-tooltip-data-viz.js +0 -2
  189. package/dist/components/p-1S9AW2MA.js +0 -2
  190. package/dist/components/p-B6Vuayt6.js +0 -2
  191. package/dist/components/p-B6Vuayt6.js.map +0 -1
  192. package/dist/components/p-BBpASejH.js +0 -2
  193. package/dist/components/p-BBpASejH.js.map +0 -1
  194. package/dist/components/p-BtuYufL3.js.map +0 -1
  195. package/dist/components/p-BybqPD8K.js +0 -2
  196. package/dist/components/p-BybqPD8K.js.map +0 -1
  197. package/dist/components/p-C4uYvyq6.js +0 -2
  198. package/dist/components/p-C4uYvyq6.js.map +0 -1
  199. package/dist/components/p-CbjFUpOj.js +0 -2
  200. package/dist/components/p-CbjFUpOj.js.map +0 -1
  201. package/dist/components/p-CrCGIx8s.js +0 -2
  202. package/dist/components/p-CrCGIx8s.js.map +0 -1
  203. package/dist/components/p-CuJ3J6OJ.js +0 -2
  204. package/dist/components/p-D0bM3cKj.js +0 -2
  205. package/dist/components/p-D2cjoj2r.js +0 -2
  206. package/dist/components/p-DX4c3kZ1.js +0 -2
  207. package/dist/components/p-DXewjzkM.js +0 -2
  208. package/dist/components/p-DXewjzkM.js.map +0 -1
  209. package/dist/components/p-yhj1lIPx.js +0 -2
  210. package/dist/mcp-data/registry/card-data-viz.json +0 -241
  211. package/dist/mcp-data/registry/chart-bar.json +0 -245
  212. package/dist/mcp-data/registry/chart-donut.json +0 -344
  213. package/dist/mcp-data/registry/chart-line.json +0 -223
  214. package/dist/mcp-data/registry/tooltip-data-viz.json +0 -224
  215. package/dist/react/ds-card-data-viz.d.ts +0 -12
  216. package/dist/react/ds-card-data-viz.js +0 -12
  217. package/dist/react/ds-chart-bar.js +0 -12
  218. package/dist/react/ds-chart-donut.d.ts +0 -12
  219. package/dist/react/ds-chart-donut.js +0 -12
  220. package/dist/react/ds-chart-line.d.ts +0 -9
  221. package/dist/react/ds-chart-line.js +0 -12
  222. package/dist/react/ds-tooltip-data-viz.d.ts +0 -9
  223. package/dist/react/ds-tooltip-data-viz.js +0 -12
  224. package/dist/types/components/CardDataViz/index.d.ts +0 -2
  225. package/dist/types/components/ChartBar/ChartBar.d.ts +0 -31
  226. package/dist/types/components/ChartBar/index.d.ts +0 -3
  227. package/dist/types/components/ChartDonut/ChartDonut.d.ts +0 -72
  228. package/dist/types/components/ChartDonut/index.d.ts +0 -2
  229. package/dist/types/components/ChartLine/ChartLine.d.ts +0 -23
  230. package/dist/types/components/ChartLine/index.d.ts +0 -2
  231. package/dist/types/components/TooltipDataViz/index.d.ts +0 -2
  232. /package/dist/components/{ds-tooltip-data-viz.js.map → ds-tooltip-chart.js.map} +0 -0
  233. /package/dist/components/{p-IYy-jODg.js.map → p-1Zbh1MRy.js.map} +0 -0
  234. /package/dist/components/{p-wOOAzVMC.js.map → p-BVsLc3t5.js.map} +0 -0
  235. /package/dist/components/{p-BBtjABBS.js.map → p-BjiRqLtB.js.map} +0 -0
  236. /package/dist/components/{p-Bsfpxto1.js.map → p-BsBw-w1q.js.map} +0 -0
  237. /package/dist/components/{p-B6RrZQqw.js.map → p-C-ENnZzq.js.map} +0 -0
  238. /package/dist/components/{p-BPyymeuR.js.map → p-C2U48kDH.js.map} +0 -0
  239. /package/dist/components/{p-CKRJX0Y0.js.map → p-C7mCjS2t.js.map} +0 -0
  240. /package/dist/components/{p-6B411hQA.js.map → p-CL8XL1eh.js.map} +0 -0
  241. /package/dist/components/{p-DfvDNcoq.js.map → p-CMZVPEZ_.js.map} +0 -0
  242. /package/dist/components/{p-Di81y9Q2.js.map → p-CX7QIytv.js.map} +0 -0
  243. /package/dist/components/{p-DVuxzrCC.js.map → p-CfTThRNX.js.map} +0 -0
  244. /package/dist/components/{p-BmNpPyzf.js.map → p-CkLffZGn.js.map} +0 -0
  245. /package/dist/components/{p-B4_0Ys4w.js.map → p-CkyXU1YX.js.map} +0 -0
  246. /package/dist/components/{p-iCjUWcp7.js.map → p-CywKWfgD.js.map} +0 -0
  247. /package/dist/components/{p-BR_oMaas.js.map → p-D3UKwTEo.js.map} +0 -0
  248. /package/dist/components/{p-Bl6A5AJq.js.map → p-D7z9bJ6n.js.map} +0 -0
  249. /package/dist/components/{p-DaqFuVKZ.js.map → p-DAftUxvL.js.map} +0 -0
  250. /package/dist/components/{p-BFfHIu6y.js.map → p-DQ94PkZA.js.map} +0 -0
  251. /package/dist/components/{p-B-kRByho.js.map → p-DSpq7xQF.js.map} +0 -0
  252. /package/dist/components/{p-og48Kh2i.js.map → p-DzM3TcyQ.js.map} +0 -0
  253. /package/dist/components/{p-yhj1lIPx.js.map → p-GbTasczF.js.map} +0 -0
  254. /package/dist/components/{p-Ca6s5fLR.js.map → p-Mmr9b1bB.js.map} +0 -0
  255. /package/dist/components/{p-CxgMUvqg.js.map → p-Z2zfShlF.js.map} +0 -0
  256. /package/dist/components/{p-Bmo4T96l.js.map → p-_mClULFL.js.map} +0 -0
  257. /package/dist/components/{p-Bb4f5SuF.js.map → p-jf1zCsuw.js.map} +0 -0
  258. /package/dist/components/{p-Eep5mxtv.js.map → p-oiR4IoH1.js.map} +0 -0
  259. /package/dist/components/{p-DHF5cLzr.js.map → p-u2OZHaLY.js.map} +0 -0
@@ -0,0 +1,258 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "chart",
4
+ "title": "Chart",
5
+ "description": "Responsive chart grammar for Cartesian, polar, heatmap, and distribution compositions with one keyed scene and centralized focus.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@ds-mo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/compomo/?path=/story/chart",
11
+ "source": "src/wc/components/Chart/Chart.tsx",
12
+ "intentStatus": "complete",
13
+ "intent": {
14
+ "audience": "specialized",
15
+ "status": "stable",
16
+ "summary": "Responsive chart grammar for Cartesian, polar, heatmap, and distribution compositions with one keyed scene and centralized focus.",
17
+ "useWhen": [
18
+ "A product needs a responsive line, area, bar, scatter, pie, donut, gauge, radar, heatmap, histogram, density, or boxplot visualization.",
19
+ "Several mark layers must share scales and semantic interaction points."
20
+ ],
21
+ "avoidWhen": [
22
+ "The visualization needs maps, networks, brushing, zooming, selection, or Canvas."
23
+ ],
24
+ "alternatives": [],
25
+ "commonlyComposedWith": [
26
+ "component:ds-chart-legend",
27
+ "component:ds-card-chart",
28
+ "component:ds-tooltip-chart"
29
+ ],
30
+ "accessibility": [
31
+ "Provide the required label and an adjacent exact-value summary when exact values are essential.",
32
+ "The SVG is one tab stop; arrow keys, Home, End, and Escape control semantic focus.",
33
+ "Pointer and keyboard input resolve through the same interaction points and polite status output."
34
+ ],
35
+ "states": [
36
+ "Definition compilation is renderer-independent and regenerates when data, locale, width, or height changes.",
37
+ "Stable mark and datum keys preserve focus across responsive recompilation and reordered data.",
38
+ "Tooltip rows are chart-owned while legends remain external and static.",
39
+ "Pie and donut pointer tooltips require direct slice containment and follow the pointer; keyboard tooltips remain anchored to the semantic slice.",
40
+ "Polar center content defaults to its authored total and may opt into focused content."
41
+ ],
42
+ "responsiveBehavior": [
43
+ "The chart observes its container unless width is fixed and recompiles geometry at CSS pixel dimensions.",
44
+ "Height uses an authored height or aspectRatio, fills the chart region supplied by CardChart, and otherwise defaults to 320px.",
45
+ "Measured guide labels reserve margins and thin colliding ticks while retaining boundary ticks."
46
+ ],
47
+ "frameworkCaveats": {
48
+ "customElements": [
49
+ "Assign definition as a JavaScript property and import D3 scale factories from granular D3 packages."
50
+ ],
51
+ "react": [
52
+ "Pass the typed definition object as a property; do not serialize it to an attribute."
53
+ ],
54
+ "angular": [
55
+ "Bind definition as a property so accessors and D3 factories remain intact."
56
+ ]
57
+ },
58
+ "references": [
59
+ {
60
+ "label": "Storybook examples",
61
+ "path": "src/wc/components/Chart/Chart.stories.ts"
62
+ },
63
+ {
64
+ "label": "Chart guide",
65
+ "path": "src/docs/Charts.mdx"
66
+ }
67
+ ]
68
+ },
69
+ "api": {
70
+ "props": {
71
+ "aspectRatio": {
72
+ "type": "number",
73
+ "resolvedType": "number | undefined",
74
+ "attribute": "aspect-ratio",
75
+ "required": false,
76
+ "mutable": false,
77
+ "description": "Derives height from the current width when height is not supplied."
78
+ },
79
+ "definition": {
80
+ "type": "ChartDefinition",
81
+ "resolvedType": "ChartDefinition<unknown>",
82
+ "required": true,
83
+ "mutable": false,
84
+ "description": "Typed chart definition. Set as a JavaScript property, not an HTML attribute."
85
+ },
86
+ "description": {
87
+ "type": "string",
88
+ "resolvedType": "string | undefined",
89
+ "attribute": "description",
90
+ "required": false,
91
+ "mutable": false,
92
+ "description": "Optional longer accessible description."
93
+ },
94
+ "height": {
95
+ "type": "number",
96
+ "resolvedType": "number | undefined",
97
+ "attribute": "height",
98
+ "required": false,
99
+ "mutable": false,
100
+ "description": "Product-owned surface height. Wins over aspectRatio."
101
+ },
102
+ "label": {
103
+ "type": "string",
104
+ "resolvedType": "string",
105
+ "attribute": "label",
106
+ "required": true,
107
+ "mutable": false,
108
+ "description": "Required accessible name for the visualization."
109
+ },
110
+ "locale": {
111
+ "type": "string",
112
+ "resolvedType": "string | undefined",
113
+ "attribute": "locale",
114
+ "required": false,
115
+ "mutable": false,
116
+ "description": "Locale used by axes and default tooltip formatters."
117
+ },
118
+ "width": {
119
+ "type": "number",
120
+ "resolvedType": "number | undefined",
121
+ "attribute": "width",
122
+ "required": false,
123
+ "mutable": false,
124
+ "description": "Fixed surface width. Otherwise the chart observes its container."
125
+ }
126
+ },
127
+ "events": [
128
+ {
129
+ "name": "dsChartFocusChange",
130
+ "detail": "ChartFocusChangeDetail",
131
+ "bubbles": true,
132
+ "cancelable": true,
133
+ "composed": true,
134
+ "description": "Fires whenever pointer or keyboard focus resolves to semantic chart points."
135
+ }
136
+ ],
137
+ "methods": [],
138
+ "slots": []
139
+ },
140
+ "props": {
141
+ "aspectRatio": {
142
+ "type": "number",
143
+ "resolvedType": "number | undefined",
144
+ "attribute": "aspect-ratio",
145
+ "required": false,
146
+ "mutable": false,
147
+ "description": "Derives height from the current width when height is not supplied."
148
+ },
149
+ "definition": {
150
+ "type": "ChartDefinition",
151
+ "resolvedType": "ChartDefinition<unknown>",
152
+ "required": true,
153
+ "mutable": false,
154
+ "description": "Typed chart definition. Set as a JavaScript property, not an HTML attribute."
155
+ },
156
+ "description": {
157
+ "type": "string",
158
+ "resolvedType": "string | undefined",
159
+ "attribute": "description",
160
+ "required": false,
161
+ "mutable": false,
162
+ "description": "Optional longer accessible description."
163
+ },
164
+ "height": {
165
+ "type": "number",
166
+ "resolvedType": "number | undefined",
167
+ "attribute": "height",
168
+ "required": false,
169
+ "mutable": false,
170
+ "description": "Product-owned surface height. Wins over aspectRatio."
171
+ },
172
+ "label": {
173
+ "type": "string",
174
+ "resolvedType": "string",
175
+ "attribute": "label",
176
+ "required": true,
177
+ "mutable": false,
178
+ "description": "Required accessible name for the visualization."
179
+ },
180
+ "locale": {
181
+ "type": "string",
182
+ "resolvedType": "string | undefined",
183
+ "attribute": "locale",
184
+ "required": false,
185
+ "mutable": false,
186
+ "description": "Locale used by axes and default tooltip formatters."
187
+ },
188
+ "width": {
189
+ "type": "number",
190
+ "resolvedType": "number | undefined",
191
+ "attribute": "width",
192
+ "required": false,
193
+ "mutable": false,
194
+ "description": "Fixed surface width. Otherwise the chart observes its container."
195
+ }
196
+ },
197
+ "events": [
198
+ {
199
+ "name": "dsChartFocusChange",
200
+ "detail": "ChartFocusChangeDetail",
201
+ "bubbles": true,
202
+ "cancelable": true,
203
+ "composed": true,
204
+ "description": "Fires whenever pointer or keyboard focus resolves to semantic chart points."
205
+ }
206
+ ],
207
+ "methods": [],
208
+ "slots": [],
209
+ "exports": {
210
+ "customElement": "ds-chart",
211
+ "react": "DsChart",
212
+ "angular": "DsChart"
213
+ },
214
+ "consumption": {
215
+ "install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
216
+ "cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
217
+ "customElements": {
218
+ "import": "import '@ds-mo/ui/dist/components/ds-chart.js';",
219
+ "example": "<ds-chart></ds-chart>"
220
+ },
221
+ "react": {
222
+ "import": "import { DsChart } from '@ds-mo/ui/react';",
223
+ "example": "<DsChart />"
224
+ },
225
+ "angular": {
226
+ "import": "import { DsChart } from '@ds-mo/ui/angular/ds-chart';",
227
+ "example": "<ds-chart></ds-chart>"
228
+ },
229
+ "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: definition.",
230
+ "peerDependencies": {
231
+ "required": [
232
+ "@ds-mo/tokens ^5.1.1",
233
+ "@ds-mo/icons ^6.4.0"
234
+ ],
235
+ "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
236
+ }
237
+ }
238
+ },
239
+ "dependencies": [
240
+ "@ds-mo/ui",
241
+ "@ds-mo/tokens"
242
+ ],
243
+ "registryDependencies": [
244
+ "tooltip-chart"
245
+ ],
246
+ "files": [
247
+ {
248
+ "path": "src/wc/components/Chart/Chart.css",
249
+ "content": "@import '../../utils/forced-colors.css';\n\n:host {\n position: relative;\n display: block;\n width: var(--ds-chart-width, 100%);\n max-width: 100%;\n height: var(--ds-chart-height, 320px);\n font-family: var(--typography-font-family);\n}\n\n.chart__surface {\n display: block;\n width: 100%;\n height: 100%;\n overflow: hidden;\n outline: none;\n touch-action: none;\n}\n\n.chart__surface:focus-visible {\n outline: var(--dimension-stroke-width-025) solid var(--color-border-focus);\n outline-offset: var(--dimension-space-025);\n}\n\n.chart__interaction-surface {\n fill: transparent;\n pointer-events: all;\n}\n\n.chart__grid,\n.chart__axis-line,\n.chart__plot-boundary,\n.chart__mark {\n vector-effect: non-scaling-stroke;\n}\n\n.chart__grid {\n stroke: var(--color-foreground-quaternary);\n stroke-width: var(--dimension-stroke-width-012);\n}\n\n.chart__plot-boundary {\n stroke: var(--color-foreground-quaternary);\n stroke-width: var(--dimension-stroke-width-012);\n}\n\n.chart__axis-line {\n stroke: var(--color-foreground-tertiary);\n stroke-width: var(--dimension-stroke-width-012);\n}\n\n.chart__tick,\n.chart__text-mark {\n fill: var(--color-foreground-secondary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-xs);\n font-weight: var(--typography-weight-medium);\n letter-spacing: var(--typography-letterspacing-positive);\n text-transform: uppercase;\n}\n\n.chart__axis-title {\n fill: var(--color-foreground-primary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-xs);\n font-weight: var(--typography-weight-semibold);\n letter-spacing: var(--typography-letterspacing-positive);\n text-transform: uppercase;\n}\n\n.chart__center-value {\n fill: var(--color-foreground-primary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-xl);\n font-weight: var(--typography-weight-semibold);\n letter-spacing: var(--typography-letterspacing-negative-double);\n}\n\n.chart__center-caption {\n fill: var(--color-foreground-secondary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-md);\n font-weight: var(--typography-weight-regular);\n letter-spacing: var(--typography-letterspacing-negative-half);\n}\n\n.chart__focus {\n fill: none;\n stroke: var(--color-border-focus);\n stroke-width: var(--dimension-stroke-width-025);\n vector-effect: non-scaling-stroke;\n pointer-events: none;\n}\n\n.chart__focus-guide {\n stroke: var(--color-foreground-quaternary);\n stroke-width: var(--dimension-stroke-width-012);\n vector-effect: non-scaling-stroke;\n pointer-events: none;\n}\n\n.chart__focus-point {\n vector-effect: non-scaling-stroke;\n pointer-events: none;\n}\n\n.chart__description,\n.chart__status {\n position: absolute;\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-stroke-width-012);\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n@media (forced-colors: active) {\n .chart__mark,\n .chart__focus,\n .chart__focus-point {\n forced-color-adjust: none;\n }\n\n .chart__focus {\n stroke: var(--ds-forced-color-focus);\n }\n}\n",
250
+ "type": "registry:ui"
251
+ },
252
+ {
253
+ "path": "src/wc/components/Chart/Chart.tsx",
254
+ "content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n Prop,\n State,\n Watch,\n h,\n Host,\n} from '@stencil/core';\nimport type {\n ChartDefinition,\n ChartPoint,\n ChartTooltipItem,\n ChartTooltipOptions,\n} from '../../utils/chart-grammar';\nimport {\n compileChartScene,\n findChartFocus,\n type ChartScene,\n type ChartSceneNode,\n} from '../../utils/chart-scene';\nimport { resolveChartTheme } from '../../utils/chart-theme';\n\nconst DEFAULT_WIDTH = 480;\nconst DEFAULT_HEIGHT = 320;\n\nexport type ChartFocusSource = 'pointer' | 'keyboard';\n\nexport interface ChartFocusChangeDetail {\n primary: ChartPoint | null;\n points: readonly ChartPoint[];\n source: ChartFocusSource;\n}\n\ninterface FocusState {\n primary: ChartPoint;\n points: ChartPoint[];\n source: ChartFocusSource;\n}\n\ninterface PointerAnchor {\n x: number;\n y: number;\n}\n\n@Component({\n tag: 'ds-chart',\n styleUrl: 'Chart.css',\n scoped: true,\n})\nexport class Chart {\n @Element() el!: HTMLElement;\n\n /** Typed chart definition. Set as a JavaScript property, not an HTML attribute. */\n @Prop() definition!: ChartDefinition;\n /** Required accessible name for the visualization. */\n @Prop() label!: string;\n /** Optional longer accessible description. */\n @Prop() description?: string;\n /** Locale used by axes and default tooltip formatters. */\n @Prop() locale?: string;\n /** Fixed surface width. Otherwise the chart observes its container. */\n @Prop() width?: number;\n /** Product-owned surface height. Wins over aspectRatio. */\n @Prop() height?: number;\n /** Derives height from the current width when height is not supplied. */\n @Prop() aspectRatio?: number;\n\n /** Fires whenever pointer or keyboard focus resolves to semantic chart points. */\n @Event() dsChartFocusChange!: EventEmitter<ChartFocusChangeDetail>;\n\n @State() private surfaceWidth = DEFAULT_WIDTH;\n @State() private containerHeight?: number;\n @State() private scene?: ChartScene;\n @State() private focusState?: FocusState;\n @State() private pointerAnchor?: PointerAnchor;\n\n private resizeObserver?: ResizeObserver;\n private resizeFrame?: number;\n private compileFrame?: number;\n private warnedConflictingHeight = false;\n private measuredLabels = new Map<string, { width: number; height: number }>();\n private descriptionId = `ds-chart-description-${Math.random().toString(36).slice(2)}`;\n private clipId = `ds-chart-clip-${Math.random().toString(36).slice(2)}`;\n\n componentWillLoad() {\n if (this.width && this.width > 0) this.surfaceWidth = this.width;\n this.compile();\n }\n\n componentDidLoad() {\n this.connectResizeObserver();\n this.waitForFonts();\n }\n\n componentDidRender() {\n this.measureRenderedLabels();\n }\n\n disconnectedCallback() {\n this.resizeObserver?.disconnect();\n if (this.resizeFrame) cancelAnimationFrame(this.resizeFrame);\n if (this.compileFrame) cancelAnimationFrame(this.compileFrame);\n }\n\n @Watch('definition')\n @Watch('locale')\n @Watch('height')\n @Watch('aspectRatio')\n onDefinitionInputChange() {\n this.scheduleCompile();\n }\n\n @Watch('width')\n onWidthChange() {\n if (this.width && this.width > 0) this.surfaceWidth = this.width;\n else this.measureHost();\n this.scheduleCompile();\n }\n\n private get surfaceHeight(): number {\n if (this.height && this.height > 0) {\n if (this.aspectRatio && !this.warnedConflictingHeight) {\n this.warnedConflictingHeight = true;\n console.warn('[ds-chart] height wins when both height and aspectRatio are supplied.');\n }\n return this.height;\n }\n if (this.aspectRatio && this.aspectRatio > 0) {\n return Math.max(1, this.surfaceWidth / this.aspectRatio);\n }\n return this.containerHeight ?? DEFAULT_HEIGHT;\n }\n\n private connectResizeObserver() {\n this.resizeObserver?.disconnect();\n if (typeof ResizeObserver === 'undefined') return;\n this.resizeObserver = new ResizeObserver(entries => {\n const entry = entries[0];\n if (!entry) return;\n if (this.resizeFrame) cancelAnimationFrame(this.resizeFrame);\n this.resizeFrame = requestAnimationFrame(() => {\n this.resizeFrame = undefined;\n this.applyMeasuredSize(entry.contentRect.width, entry.contentRect.height);\n });\n });\n this.resizeObserver.observe(this.el);\n this.measureHost();\n }\n\n private measureHost() {\n const bounds = this.el.getBoundingClientRect();\n this.applyMeasuredSize(bounds.width, bounds.height);\n }\n\n private applyMeasuredSize(width: number, height: number) {\n let changed = false;\n if (!this.width && width > 0) {\n const nextWidth = Math.round(width * 100) / 100;\n if (nextWidth !== this.surfaceWidth) {\n this.surfaceWidth = nextWidth;\n changed = true;\n }\n }\n if (!this.height && !this.aspectRatio && height > 0) {\n const nextHeight = Math.round(height * 100) / 100;\n if (nextHeight !== this.containerHeight) {\n this.containerHeight = nextHeight;\n changed = true;\n }\n }\n if (changed) {\n this.scheduleCompile();\n }\n }\n\n private scheduleCompile() {\n if (this.compileFrame) cancelAnimationFrame(this.compileFrame);\n this.compileFrame = requestAnimationFrame(() => {\n this.compileFrame = undefined;\n this.compile();\n });\n }\n\n private compile() {\n if (!this.definition || !(this.surfaceWidth > 0) || !(this.surfaceHeight > 0)) return;\n const previousKey = this.focusState?.primary.sceneKey;\n const scene = compileChartScene(\n this.definition,\n this.surfaceWidth,\n this.surfaceHeight,\n this.locale ?? document.documentElement.lang ?? 'en',\n text => this.measuredLabels.get(text) ?? { width: text.length * 7, height: 14 },\n resolveChartTheme(this.el),\n );\n this.scene = scene;\n if (previousKey) {\n const restored = scene.points.find(point => point.sceneKey === previousKey);\n if (restored && this.focusState) {\n const grouped = findChartFocus(\n scene.points,\n scene.focus,\n restored.x,\n restored.y,\n scene.maxFocusDistance,\n scene.arcHitRegions,\n );\n this.focusState = grouped\n ? { ...grouped, source: this.focusState.source }\n : undefined;\n } else {\n this.focusState = undefined;\n }\n }\n }\n\n private waitForFonts() {\n if (!document.fonts) return;\n void document.fonts.ready.then(() => {\n this.measuredLabels.clear();\n this.scheduleCompile();\n });\n }\n\n private measureRenderedLabels() {\n const labels = this.el.querySelectorAll<SVGTextElement>('[data-chart-measure]');\n let changed = false;\n labels.forEach(label => {\n const text = label.textContent ?? '';\n let box: DOMRect;\n try {\n box = label.getBBox();\n } catch {\n return;\n }\n const previous = this.measuredLabels.get(text);\n if (!previous || Math.abs(previous.width - box.width) > 0.5 || Math.abs(previous.height - box.height) > 0.5) {\n this.measuredLabels.set(text, { width: box.width, height: box.height });\n changed = true;\n }\n });\n if (changed) this.scheduleCompile();\n }\n\n private resolveFocus(x: number, y: number, source: ChartFocusSource) {\n if (!this.scene) return;\n const result = findChartFocus(\n this.scene.points,\n this.scene.focus,\n x,\n y,\n this.scene.maxFocusDistance,\n this.scene.arcHitRegions,\n );\n if (!result) {\n this.clearFocus(source);\n return;\n }\n if (\n this.focusState?.primary.sceneKey === result.primary.sceneKey &&\n this.focusState.source === source\n ) return;\n this.focusState = { ...result, source };\n this.dsChartFocusChange.emit({ ...result, source });\n }\n\n private clearFocus(source: ChartFocusSource) {\n if (!this.focusState) return;\n this.focusState = undefined;\n this.dsChartFocusChange.emit({ primary: null, points: [], source });\n }\n\n private onPointerMove = (event: PointerEvent) => {\n const svg = event.currentTarget as SVGSVGElement;\n const rect = svg.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n this.pointerAnchor = this.scene?.arcHitRegions.length ? { x, y } : undefined;\n this.resolveFocus(x, y, 'pointer');\n };\n\n private onPointerLeave = () => {\n this.pointerAnchor = undefined;\n this.clearFocus('pointer');\n };\n\n private keyboardPoints(): ChartPoint[] {\n if (!this.scene) return [];\n return [...this.scene.points].sort((a, b) => a.x - b.x || a.y - b.y);\n }\n\n private onKeyDown = (event: KeyboardEvent) => {\n const points = this.keyboardPoints();\n if (points.length === 0) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.clearFocus('keyboard');\n return;\n }\n const current = this.focusState\n ? points.findIndex(point => point.sceneKey === this.focusState?.primary.sceneKey)\n : -1;\n let next: number | undefined;\n if (event.key === 'Home') next = 0;\n else if (event.key === 'End') next = points.length - 1;\n else if (event.key === 'ArrowRight' || event.key === 'ArrowDown') next = Math.min(points.length - 1, current + 1);\n else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') next = Math.max(0, current < 0 ? 0 : current - 1);\n else return;\n event.preventDefault();\n const point = points[next ?? 0] ?? points[0];\n this.resolveFocus(point.x, point.y, 'keyboard');\n };\n\n private renderNode(node: ChartSceneNode, className = 'chart__mark') {\n const resolvedClassName = node.className ?? className;\n const presentation = {\n fill: node.style.fill,\n stroke: node.style.stroke,\n opacity: node.style.opacity,\n 'fill-opacity': node.style.fillOpacity,\n 'stroke-opacity': node.style.strokeOpacity,\n 'stroke-width': node.style.strokeWidth,\n 'stroke-dasharray': node.style.strokeDasharray || undefined,\n };\n if (node.type === 'path') return <path key={node.key} class={resolvedClassName} d={node.d} transform={node.transform} {...presentation} />;\n if (node.type === 'rect') {\n return <rect key={node.key} class={resolvedClassName} x={node.x} y={node.y} width={node.width} height={node.height} rx={node.style.radius} {...presentation} />;\n }\n if (node.type === 'circle') return <circle key={node.key} class={resolvedClassName} cx={node.x} cy={node.y} r={node.radius} {...presentation} />;\n if (node.type === 'line') return <line key={node.key} class={resolvedClassName} x1={node.x1} x2={node.x2} y1={node.y1} y2={node.y2} {...presentation} />;\n return <text key={node.key} class={node.className ?? `${className} chart__text-mark`} data-chart-measure={node.measure ? '' : undefined} x={node.x} y={node.y} dx={node.dx} dy={node.dy} text-anchor={node.style.textAnchor} font-family={node.style.fontFamily} font-size={node.style.fontSize} font-weight={node.style.fontWeight} dominant-baseline={node.dominantBaseline ?? 'middle'} transform={node.rotate ? `rotate(${node.rotate} ${node.x} ${node.y})` : undefined} {...presentation}>{node.text}</text>;\n }\n\n private renderMarkLayers(scene: ChartScene) {\n const layers: Array<{ clipped: boolean; nodes: ChartSceneNode[] }> = [];\n scene.nodes.forEach(node => {\n const clipped = scene.clip && node.clipToPlot !== false;\n const current = layers[layers.length - 1];\n if (current?.clipped === clipped) current.nodes.push(node);\n else layers.push({ clipped, nodes: [node] });\n });\n return layers.map((layer, index) => (\n <g\n key={`marks-${index}`}\n class=\"chart__marks\"\n aria-hidden=\"true\"\n clip-path={layer.clipped ? `url(#${this.clipId})` : undefined}\n >\n {layer.nodes.map(node => this.renderNode(node))}\n </g>\n ));\n }\n\n private focusedDotPoints(scene: ChartScene): ChartPoint[] {\n if (!this.focusState) return [];\n const focusDotPointKeys = new Set(scene.focusDotPointKeys);\n return this.focusState.points.filter(point => focusDotPointKeys.has(point.sceneKey));\n }\n\n private tooltipContent(): { heading?: string; items: ChartTooltipItem[] } | undefined {\n if (!this.scene || !this.focusState || this.scene.tooltip === false) return undefined;\n const options: ChartTooltipOptions =\n typeof this.scene.tooltip === 'object' ? this.scene.tooltip : {};\n const locale = this.locale ?? document.documentElement.lang ?? 'en';\n const points = this.focusState.points;\n const formatValue = (point: ChartPoint) => {\n const value = point.value ?? point.yValue;\n return options.format?.(point, locale) ??\n (typeof value === 'number'\n ? new Intl.NumberFormat(locale, { maximumFractionDigits: 2 }).format(value)\n : String(value));\n };\n return {\n heading:\n points.length > 1\n ? options.formatGroupHeading?.(points, locale) ?? String(this.focusState.primary.xValue)\n : undefined,\n items: points.map(point =>\n options.formatGroupItem?.(point, locale) ?? {\n label: point.groupLabel ?? point.markId,\n value: formatValue(point),\n color: point.color,\n },\n ),\n };\n }\n\n private statusText(): string {\n const content = this.tooltipContent();\n if (!content) return '';\n return [content.heading, ...content.items.map(item => `${item.label}: ${item.value}`)]\n .filter(Boolean)\n .join('. ');\n }\n\n render() {\n const scene = this.scene;\n const tooltip = this.tooltipContent();\n const focus = this.focusState?.primary;\n const tooltipAnchor = focus &&\n this.focusState?.source === 'pointer' &&\n scene?.arcHitRegions.length &&\n this.pointerAnchor\n ? this.pointerAnchor\n : focus;\n const focusedDotPoints = scene ? this.focusedDotPoints(scene) : [];\n const groupedPointFocus = scene?.coordinate === 'cartesian' &&\n scene.focus === 'group-x' &&\n focusedDotPoints.length > 1;\n const center = focus && scene?.center?.focused\n ? scene.center.focused(focus, this.locale ?? document.documentElement.lang ?? 'en')\n : scene?.center;\n return (\n <Host\n class=\"chart\"\n style={{\n '--ds-chart-width': this.width ? `${this.width}px` : '100%',\n '--ds-chart-height': this.height || this.aspectRatio\n ? `${this.surfaceHeight}px`\n : 'var(--ds-chart-container-height, 320px)',\n }}\n >\n {this.description && <span id={this.descriptionId} class=\"chart__description\">{this.description}</span>}\n {scene && (\n /* eslint-disable-next-line local/prefer-ds-icon -- SVG is the chart renderer. */\n <svg\n class=\"chart__surface\"\n width={scene.width}\n height={scene.height}\n viewBox={`0 0 ${scene.width} ${scene.height}`}\n role=\"img\"\n aria-label={this.label || 'Chart'}\n aria-describedby={this.description ? this.descriptionId : undefined}\n tabindex={0}\n onPointerMove={this.onPointerMove}\n onPointerLeave={this.onPointerLeave}\n onKeyDown={this.onKeyDown}\n >\n <defs aria-hidden=\"true\">\n <clipPath id={this.clipId}>\n <rect x={scene.plot.left} y={scene.plot.top} width={scene.plot.width} height={scene.plot.height} />\n </clipPath>\n </defs>\n <rect\n class=\"chart__interaction-surface\"\n x=\"0\"\n y=\"0\"\n width={scene.width}\n height={scene.height}\n aria-hidden=\"true\"\n />\n <g class=\"chart__guides\" aria-hidden=\"true\">\n {scene.guides.map(node => this.renderNode(node, 'chart__grid chart__polar-guide'))}\n {scene.yAxis.line && <line class=\"chart__axis-line\" x1={scene.plot.left} x2={scene.plot.left} y1={scene.plot.top} y2={scene.plot.bottom} />}\n {scene.yAxis.ticks.map(tick => (\n <g key={`y-${tick.key}`}>\n {scene.yAxis.grid && <line class=\"chart__grid\" x1={scene.plot.left} x2={scene.plot.right} y1={tick.position} y2={tick.position} />}\n <line class=\"chart__axis-line chart__tick-stub\" x1={scene.plot.left - scene.yAxis.tickSize} x2={scene.plot.left} y1={tick.position} y2={tick.position} />\n {tick.labelVisible && <text data-chart-measure class=\"chart__tick chart__tick--y\" x={scene.plot.left - scene.yAxis.tickSize - scene.yAxis.tickPadding} y={tick.position} text-anchor=\"end\" dominant-baseline=\"middle\">{tick.label}</text>}\n </g>\n ))}\n {scene.xAxis.line && <line class=\"chart__axis-line\" x1={scene.plot.left} x2={scene.plot.right} y1={scene.plot.bottom} y2={scene.plot.bottom} />}\n {scene.xAxis.ticks.map(tick => (\n <g key={`x-${tick.key}`}>\n {scene.xAxis.grid && <line class=\"chart__grid\" x1={tick.position} x2={tick.position} y1={scene.plot.top} y2={scene.plot.bottom} />}\n <line class=\"chart__axis-line chart__tick-stub\" x1={tick.position} x2={tick.position} y1={scene.plot.bottom} y2={scene.plot.bottom + scene.xAxis.tickSize} />\n {tick.labelVisible && <text data-chart-measure class=\"chart__tick chart__tick--x\" x={tick.position} y={scene.plot.bottom + scene.xAxis.tickSize + scene.xAxis.tickPadding} text-anchor=\"middle\" dominant-baseline=\"hanging\" transform={scene.xAxis.rotate ? `rotate(${scene.xAxis.rotate} ${tick.position} ${scene.plot.bottom + scene.xAxis.tickSize + scene.xAxis.tickPadding})` : undefined}>{tick.label}</text>}\n </g>\n ))}\n {scene.xAxis.label && <text class=\"chart__axis-title\" x={(scene.plot.left + scene.plot.right) / 2} y={scene.height - 4} text-anchor=\"middle\">{scene.xAxis.label}</text>}\n {scene.yAxis.label && <text class=\"chart__axis-title\" x=\"8\" y={(scene.plot.top + scene.plot.bottom) / 2} text-anchor=\"middle\" dominant-baseline=\"middle\" transform={`rotate(-90 8 ${(scene.plot.top + scene.plot.bottom) / 2})`}>{scene.yAxis.label}</text>}\n {scene.coordinate === 'cartesian' && (\n <g class=\"chart__plot-frame\">\n <line class=\"chart__plot-boundary chart__plot-boundary--top\" x1={scene.plot.left} x2={scene.plot.right} y1={scene.plot.top} y2={scene.plot.top} />\n <line class=\"chart__plot-boundary chart__plot-boundary--right\" x1={scene.plot.right} x2={scene.plot.right} y1={scene.plot.top} y2={scene.plot.bottom} />\n </g>\n )}\n </g>\n {this.renderMarkLayers(scene)}\n {groupedPointFocus && focus && (\n <line\n class=\"chart__focus-guide\"\n x1={focus.x}\n x2={focus.x}\n y1={scene.plot.top}\n y2={scene.plot.bottom}\n aria-hidden=\"true\"\n />\n )}\n {focusedDotPoints.map(point => (\n <circle\n key={`focus-${point.sceneKey}`}\n class=\"chart__focus-point\"\n cx={point.x}\n cy={point.y}\n r={scene.focusDotCircleRadius}\n fill={point.color}\n stroke=\"var(--color-background-primary)\"\n stroke-width={scene.focusDotHaloWidth}\n aria-hidden=\"true\"\n />\n ))}\n {focus && focusedDotPoints.length === 0 && <circle class=\"chart__focus\" cx={focus.x} cy={focus.y} r=\"6\" aria-hidden=\"true\" />}\n {center?.value && (\n <text\n class=\"chart__center-value\"\n x={(scene.plot.left + scene.plot.right) / 2}\n y={(scene.plot.top + scene.plot.bottom) / 2 - (center.caption ? 10 : 0)}\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n aria-hidden=\"true\"\n >\n {center.value}\n </text>\n )}\n {center?.caption && (\n <text\n class=\"chart__center-caption\"\n x={(scene.plot.left + scene.plot.right) / 2}\n y={(scene.plot.top + scene.plot.bottom) / 2 + 14}\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n aria-hidden=\"true\"\n >\n {center.caption}\n </text>\n )}\n </svg>\n )}\n {tooltip && tooltipAnchor && (\n <ds-tooltip-chart\n heading={tooltip.heading}\n items={tooltip.items}\n x={tooltipAnchor.x}\n y={tooltipAnchor.y}\n />\n )}\n <span class=\"chart__status\" aria-live=\"polite\" aria-atomic=\"true\">{this.statusText()}</span>\n </Host>\n );\n }\n}\n",
255
+ "type": "registry:ui"
256
+ }
257
+ ]
258
+ }
@@ -39,8 +39,8 @@
39
39
  "Direct touch paints the pressed overlay immediately, keeps a quick tap visible for one short frame, and clears it after release or cancellation without relying on Safari's latch-prone active state."
40
40
  ],
41
41
  "responsiveBehavior": [
42
- "Render only below the mobile breakpoint; its secondary surface extends through the bottom safe-area inset when the application enables viewport-fit=cover.",
43
- "The secondary-background bar keeps an 8px outer inset; its two icon-only groups anchor to opposite edges while retaining fixed 40px targets and a divider between Menu and current area.",
42
+ "Render only below the mobile breakpoint; its primary surface extends through the bottom safe-area inset when the application enables viewport-fit=cover.",
43
+ "The primary-background bar keeps an 8px outer inset; its two icon-only groups anchor to opposite edges while retaining fixed 40px targets and a divider between Menu and current area.",
44
44
  "Bar chrome and its divider are not text-selectable and suppress the iOS touch callout."
45
45
  ],
46
46
  "references": [
@@ -318,7 +318,7 @@
318
318
  "files": [
319
319
  {
320
320
  "path": "src/wc/components/MobileBarNav/MobileBarNav.css",
321
- "content": "@import '../../utils/chrome-layout.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n\n:host {\n display: block;\n min-width: 0;\n background: var(--color-background-secondary);\n color: var(--color-foreground-tertiary);\n -webkit-user-select: none;\n user-select: none;\n -webkit-touch-callout: none;\n}\n\n.mobile-bar-nav {\n justify-content: space-between;\n min-width: 0;\n padding-block-end: max(var(--ds-chrome-padding), env(safe-area-inset-bottom));\n border-top: var(--dimension-stroke-width-012) solid var(--color-border-tertiary);\n background: var(--color-background-secondary);\n -webkit-user-select: none;\n user-select: none;\n -webkit-touch-callout: none;\n}\n\n.mobile-bar-nav__group {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n}\n\n.mobile-bar-nav__item {\n appearance: none;\n flex: 0 0 var(--dimension-size-500);\n width: var(--dimension-size-500);\n height: var(--dimension-size-500);\n padding: var(--dimension-space-100);\n border: 0;\n border-radius: var(--dimension-radius-025);\n background: transparent;\n color: inherit;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: default;\n}\n\n.mobile-bar-nav__item--selected {\n color: var(--color-foreground-primary);\n}\n\n/*\n * Safari can retain its native :active state after a direct touch. On coarse\n * touch-only pointers, the component-owned class provides one deterministic\n * press frame and clears it after release/cancel.\n */\n@media (hover: none) and (pointer: coarse) {\n .mobile-bar-nav__item.ds-interaction-fill:active:not(:disabled)::after {\n background: transparent;\n }\n\n .mobile-bar-nav__item--pressed.ds-interaction-fill::after,\n .mobile-bar-nav__item--pressed.ds-interaction-fill:active:not(:disabled)::after {\n background: var(--ds-interaction-pressed);\n }\n}\n\n.mobile-bar-nav__divider {\n flex: 0 0 var(--dimension-stroke-width-012);\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-iconography-lg);\n background: var(--color-border-tertiary);\n pointer-events: none;\n -webkit-user-select: none;\n user-select: none;\n}\n\n.mobile-bar-nav__icon {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--dimension-iconography-lg);\n height: var(--dimension-iconography-lg);\n}\n\n.mobile-bar-nav__dot {\n position: absolute;\n inset-block-start: calc(var(--dimension-space-025) * -1);\n inset-inline-end: calc(var(--dimension-space-025) * -1);\n}\n",
321
+ "content": "@import '../../utils/chrome-layout.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n\n:host {\n display: block;\n min-width: 0;\n background: var(--color-background-primary);\n color: var(--color-foreground-tertiary);\n -webkit-user-select: none;\n user-select: none;\n -webkit-touch-callout: none;\n}\n\n.mobile-bar-nav {\n justify-content: space-between;\n min-width: 0;\n padding-block-end: max(var(--ds-chrome-padding), env(safe-area-inset-bottom));\n border-top: var(--dimension-stroke-width-012) solid var(--color-border-tertiary);\n background: var(--color-background-primary);\n -webkit-user-select: none;\n user-select: none;\n -webkit-touch-callout: none;\n}\n\n.mobile-bar-nav__group {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n}\n\n.mobile-bar-nav__item {\n appearance: none;\n flex: 0 0 var(--dimension-size-500);\n width: var(--dimension-size-500);\n height: var(--dimension-size-500);\n padding: var(--dimension-space-100);\n border: 0;\n border-radius: var(--dimension-radius-025);\n background: transparent;\n color: inherit;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: default;\n}\n\n.mobile-bar-nav__item--selected {\n color: var(--color-foreground-primary);\n}\n\n/*\n * Safari can retain its native :active state after a direct touch. On coarse\n * touch-only pointers, the component-owned class provides one deterministic\n * press frame and clears it after release/cancel.\n */\n@media (hover: none) and (pointer: coarse) {\n .mobile-bar-nav__item.ds-interaction-fill:active:not(:disabled)::after {\n background: transparent;\n }\n\n .mobile-bar-nav__item--pressed.ds-interaction-fill::after,\n .mobile-bar-nav__item--pressed.ds-interaction-fill:active:not(:disabled)::after {\n background: var(--ds-interaction-pressed);\n }\n}\n\n.mobile-bar-nav__divider {\n flex: 0 0 var(--dimension-stroke-width-012);\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-iconography-lg);\n background: var(--color-border-tertiary);\n pointer-events: none;\n -webkit-user-select: none;\n user-select: none;\n}\n\n.mobile-bar-nav__icon {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--dimension-iconography-lg);\n height: var(--dimension-iconography-lg);\n}\n\n.mobile-bar-nav__dot {\n position: absolute;\n inset-block-start: calc(var(--dimension-space-025) * -1);\n inset-inline-end: calc(var(--dimension-space-025) * -1);\n}\n",
322
322
  "type": "registry:ui"
323
323
  },
324
324
  {