@exegia/corpora-ui 1.0.0 → 3.0.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 (1151) hide show
  1. package/README.md +1 -1
  2. package/dist-lib/components/atoms/avatar/base.d.ts +2 -0
  3. package/dist-lib/components/atoms/avatar/index.d.ts +3 -0
  4. package/dist-lib/components/atoms/avatar/types.d.ts +20 -0
  5. package/dist-lib/components/atoms/avatar/utils.d.ts +13 -0
  6. package/dist-lib/components/atoms/background/texture.d.ts +2 -0
  7. package/dist-lib/components/atoms/background/type.d.ts +7 -0
  8. package/dist-lib/components/atoms/background/utils.d.ts +4 -0
  9. package/dist-lib/components/atoms/bubble/actions.d.ts +7 -0
  10. package/dist-lib/components/atoms/bubble/context.d.ts +4 -0
  11. package/dist-lib/components/atoms/bubble/default.d.ts +3 -0
  12. package/dist-lib/components/atoms/bubble/header.d.ts +8 -0
  13. package/dist-lib/components/atoms/bubble/index.d.ts +16 -0
  14. package/dist-lib/components/atoms/bubble/message.d.ts +3 -0
  15. package/dist-lib/components/atoms/bubble/reactions.d.ts +14 -0
  16. package/dist-lib/components/atoms/bubble/types.d.ts +62 -0
  17. package/dist-lib/components/atoms/bubble/utils.d.ts +13 -0
  18. package/dist-lib/components/atoms/field.d.ts +2 -0
  19. package/dist-lib/components/atoms/index.d.ts +10 -0
  20. package/dist-lib/components/atoms/loader.d.ts +2 -0
  21. package/dist-lib/components/atoms/reference.d.ts +7 -0
  22. package/dist-lib/components/atoms/text/default.d.ts +1144 -0
  23. package/dist-lib/components/atoms/text/heading.d.ts +2 -0
  24. package/dist-lib/components/atoms/text/index.d.ts +18 -0
  25. package/dist-lib/components/atoms/text/label.d.ts +2 -0
  26. package/dist-lib/components/atoms/text/paragraph.d.ts +2 -0
  27. package/dist-lib/components/atoms/text/span.d.ts +2 -0
  28. package/dist-lib/components/atoms/text/types.d.ts +27 -0
  29. package/dist-lib/components/atoms/text/utils.d.ts +4 -0
  30. package/dist-lib/components/atoms/text-selection/click-popover.d.ts +3 -0
  31. package/dist-lib/components/atoms/text-selection/index.d.ts +6 -0
  32. package/dist-lib/components/atoms/text-selection/popover.d.ts +3 -0
  33. package/dist-lib/components/atoms/text-selection/selection-atom.d.ts +30 -0
  34. package/dist-lib/components/atoms/text-selection/selection.d.ts +3 -0
  35. package/dist-lib/components/atoms/text-selection/types.d.ts +90 -0
  36. package/dist-lib/components/atoms/text-selection/use-selection.d.ts +7 -0
  37. package/dist-lib/components/atoms/types.d.ts +39 -0
  38. package/dist-lib/components/blocks/auth/auth-flow-atom.d.ts +76 -0
  39. package/dist-lib/components/blocks/auth/auth-flow-block.d.ts +41 -0
  40. package/dist-lib/components/blocks/auth/auth-session-atom.d.ts +28 -0
  41. package/dist-lib/components/blocks/auth/auth-shell.d.ts +55 -0
  42. package/dist-lib/components/blocks/auth/auth-state.d.ts +8 -0
  43. package/dist-lib/components/blocks/auth/code-auth-block.d.ts +3 -0
  44. package/dist-lib/components/blocks/auth/forgot-password-block.d.ts +3 -0
  45. package/dist-lib/components/blocks/auth/linked-accounts-block.d.ts +9 -0
  46. package/dist-lib/components/blocks/auth/login-block.d.ts +3 -0
  47. package/dist-lib/components/blocks/auth/onboarding/profile-step.d.ts +8 -0
  48. package/dist-lib/components/blocks/auth/onboarding-block.d.ts +15 -0
  49. package/dist-lib/components/blocks/auth/passkey-manager-block.d.ts +10 -0
  50. package/dist-lib/components/blocks/auth/passkey-sign-in-block.d.ts +8 -0
  51. package/dist-lib/components/blocks/auth/signup-block.d.ts +3 -0
  52. package/dist-lib/components/blocks/auth/type.d.ts +398 -0
  53. package/dist-lib/components/blocks/auth/update-password-block.d.ts +9 -0
  54. package/dist-lib/components/blocks/auth/use-auth-state.d.ts +52 -0
  55. package/dist-lib/components/blocks/chat/banners.d.ts +5 -0
  56. package/dist-lib/components/blocks/chat/base.d.ts +10 -0
  57. package/dist-lib/components/blocks/chat/header.d.ts +4 -0
  58. package/dist-lib/components/blocks/chat/index.d.ts +11 -0
  59. package/dist-lib/components/blocks/chat/recommendation-stack.d.ts +11 -0
  60. package/dist-lib/components/blocks/chat/suggested-prompts.d.ts +3 -0
  61. package/dist-lib/components/blocks/chat/type.d.ts +75 -0
  62. package/dist-lib/components/blocks/chat/version-history-record.d.ts +3 -0
  63. package/dist-lib/components/blocks/layout.d.ts +8 -0
  64. package/dist-lib/components/blocks/profile/index.d.ts +7 -0
  65. package/dist-lib/components/blocks/profile/profile-card-atom.d.ts +68 -0
  66. package/dist-lib/components/blocks/profile/profile-card-block.d.ts +66 -0
  67. package/dist-lib/components/blocks/profile/type.d.ts +80 -0
  68. package/dist-lib/components/blocks/profile/use-profile-card-state.d.ts +24 -0
  69. package/dist-lib/components/blocks/profile/use-profile-card.d.ts +34 -0
  70. package/dist-lib/components/blocks/scaffold/index.d.ts +29 -0
  71. package/dist-lib/components/blocks/scaffold/panel-close-button.d.ts +4 -0
  72. package/dist-lib/components/blocks/scaffold/panel-menu-button.d.ts +8 -0
  73. package/dist-lib/components/blocks/scaffold/scaffold-actions.d.ts +10 -0
  74. package/dist-lib/components/blocks/scaffold/scaffold-atom.d.ts +112 -0
  75. package/dist-lib/components/blocks/scaffold/scaffold-canvas.d.ts +9 -0
  76. package/dist-lib/components/blocks/scaffold/scaffold-context.d.ts +7 -0
  77. package/dist-lib/components/blocks/scaffold/scaffold-inspector.d.ts +9 -0
  78. package/dist-lib/components/blocks/scaffold/scaffold-main.d.ts +8 -0
  79. package/dist-lib/components/blocks/scaffold/scaffold-panel.d.ts +16 -0
  80. package/dist-lib/components/blocks/scaffold/scaffold-root.d.ts +17 -0
  81. package/dist-lib/components/blocks/scaffold/scaffold-sidebar.d.ts +7 -0
  82. package/dist-lib/components/blocks/scaffold/scaffold-sub-panel.d.ts +6 -0
  83. package/dist-lib/components/blocks/scaffold/scaffold-tab.d.ts +14 -0
  84. package/dist-lib/components/blocks/scaffold/type.d.ts +216 -0
  85. package/dist-lib/components/blocks/scaffold/use-scaffold-state.d.ts +26 -0
  86. package/dist-lib/components/blocks/scaffold/use-scaffold.d.ts +14 -0
  87. package/dist-lib/components/blocks/scaffold/utils.d.ts +38 -0
  88. package/dist-lib/components/blocks/shell/animated-panel-inset.d.ts +2 -0
  89. package/dist-lib/components/blocks/shell/animated-panel-provider.d.ts +2 -0
  90. package/dist-lib/components/blocks/shell/animated-panel-trigger.d.ts +2 -0
  91. package/dist-lib/components/blocks/shell/animated-panel.d.ts +2 -0
  92. package/dist-lib/components/blocks/shell/shell-fit-atom.d.ts +68 -0
  93. package/dist-lib/components/blocks/shell/shell-layout.d.ts +3 -0
  94. package/dist-lib/components/blocks/shell/shell-metrics.d.ts +72 -0
  95. package/dist-lib/components/blocks/shell/shell-panel-atom.d.ts +40 -0
  96. package/dist-lib/components/blocks/shell/type.d.ts +301 -0
  97. package/dist-lib/components/blocks/shell/use-shell-fit-state.d.ts +25 -0
  98. package/dist-lib/components/blocks/shell/use-shell-fit.d.ts +13 -0
  99. package/dist-lib/components/blocks/shell/use-shell-panels.d.ts +20 -0
  100. package/dist-lib/components/blocks/shell/utils.d.ts +72 -0
  101. package/dist-lib/components/blocks/sidebar/ai-sidebar-atom.d.ts +217 -0
  102. package/dist-lib/components/blocks/sidebar/ai-sidebar.d.ts +11 -0
  103. package/dist-lib/components/blocks/sidebar/index.d.ts +15 -0
  104. package/dist-lib/components/blocks/sidebar/sidebar-context.d.ts +3 -0
  105. package/dist-lib/components/blocks/sidebar/sidebar-icon.d.ts +2 -0
  106. package/dist-lib/components/blocks/sidebar/sidebar-row.d.ts +4 -0
  107. package/dist-lib/components/blocks/sidebar/type.d.ts +245 -0
  108. package/dist-lib/components/blocks/sidebar/use-ai-sidebar-state.d.ts +29 -0
  109. package/dist-lib/components/blocks/sidebar/use-ai-sidebar.d.ts +27 -0
  110. package/dist-lib/components/blocks/sidebar/utils.d.ts +21 -0
  111. package/dist-lib/components/blocks/types.d.ts +6 -0
  112. package/dist-lib/components/composed/action-bar/action.d.ts +18 -0
  113. package/dist-lib/components/composed/action-bar/emojis.d.ts +10 -0
  114. package/dist-lib/components/composed/action-bar/index.d.ts +12 -0
  115. package/dist-lib/components/composed/action-bar/toolbar.d.ts +2 -0
  116. package/dist-lib/components/composed/action-bar/types.d.ts +55 -0
  117. package/dist-lib/components/composed/action-bar/utils.d.ts +56 -0
  118. package/dist-lib/components/composed/ai/index.d.ts +17 -0
  119. package/dist-lib/components/composed/ai/message.d.ts +7 -0
  120. package/dist-lib/components/composed/ai/research-answer.d.ts +30 -0
  121. package/dist-lib/components/composed/ai/streaming-text.d.ts +26 -0
  122. package/dist-lib/components/composed/ai/suggested-prompt.d.ts +35 -0
  123. package/dist-lib/components/composed/ai/types.d.ts +68 -0
  124. package/dist-lib/components/composed/chat/attachment-file.d.ts +17 -0
  125. package/dist-lib/components/composed/chat/attachment.d.ts +60 -0
  126. package/dist-lib/components/composed/chat/chart/chart-atom.d.ts +30 -0
  127. package/dist-lib/components/composed/chat/chart/chart-context.d.ts +2 -0
  128. package/dist-lib/components/composed/chat/chart/chart-legend.d.ts +4 -0
  129. package/dist-lib/components/composed/chat/chart/chart-plot.d.ts +3 -0
  130. package/dist-lib/components/composed/chat/chart/chart-root.d.ts +3 -0
  131. package/dist-lib/components/composed/chat/chart/chart-tooltip.d.ts +4 -0
  132. package/dist-lib/components/composed/chat/chart/constants.d.ts +3 -0
  133. package/dist-lib/components/composed/chat/chart/evilcharts/echarts-area-chart.d.ts +93 -0
  134. package/dist-lib/components/composed/chat/chart/evilcharts/echarts-bar-chart.d.ts +86 -0
  135. package/dist-lib/components/composed/chat/chart/evilcharts/echarts-brush.d.ts +65 -0
  136. package/dist-lib/components/composed/chat/chart/evilcharts/echarts-chart.d.ts +44 -0
  137. package/dist-lib/components/composed/chat/chart/evilcharts/echarts-dot.d.ts +16 -0
  138. package/dist-lib/components/composed/chat/chart/evilcharts/echarts-legend.d.ts +24 -0
  139. package/dist-lib/components/composed/chat/chart/evilcharts/echarts-line-chart.d.ts +90 -0
  140. package/dist-lib/components/composed/chat/chart/evilcharts/echarts-pie-chart.d.ts +73 -0
  141. package/dist-lib/components/composed/chat/chart/evilcharts/echarts-tooltip.d.ts +29 -0
  142. package/dist-lib/components/composed/chat/chart/index.d.ts +6 -0
  143. package/dist-lib/components/composed/chat/chart/type.d.ts +80 -0
  144. package/dist-lib/components/composed/chat/chart/use-chart-state.d.ts +3 -0
  145. package/dist-lib/components/composed/chat/chart/use-chart.d.ts +6 -0
  146. package/dist-lib/components/composed/chat/chart/utils.d.ts +5 -0
  147. package/dist-lib/components/composed/chat/chart.d.ts +1 -0
  148. package/dist-lib/components/composed/chat/code-block.d.ts +26 -0
  149. package/dist-lib/components/composed/chat/composer/add-button.d.ts +5 -0
  150. package/dist-lib/components/composed/chat/composer/base.d.ts +5 -0
  151. package/dist-lib/components/composed/chat/composer/command-menu.d.ts +3 -0
  152. package/dist-lib/components/composed/chat/composer/hooks.d.ts +9 -0
  153. package/dist-lib/components/composed/chat/composer/send-button.d.ts +3 -0
  154. package/dist-lib/components/composed/chat/composer/suggestions.d.ts +7 -0
  155. package/dist-lib/components/composed/chat/composer/use-dictation.d.ts +8 -0
  156. package/dist-lib/components/composed/chat/composer/utils.d.ts +19 -0
  157. package/dist-lib/components/composed/chat/context-cards.d.ts +27 -0
  158. package/dist-lib/components/composed/chat/filter-table.d.ts +40 -0
  159. package/dist-lib/components/composed/chat/flowchart/chart-node.d.ts +2 -0
  160. package/dist-lib/components/composed/chat/flowchart/connector.d.ts +2 -0
  161. package/dist-lib/components/composed/chat/flowchart/default.d.ts +7 -0
  162. package/dist-lib/components/composed/chat/flowchart/edge-toolbar.d.ts +9 -0
  163. package/dist-lib/components/composed/chat/flowchart/hooks.d.ts +290 -0
  164. package/dist-lib/components/composed/chat/flowchart/step-body.d.ts +6 -0
  165. package/dist-lib/components/composed/chat/flowchart/types.d.ts +91 -0
  166. package/dist-lib/components/composed/chat/flowchart/utils.d.ts +64 -0
  167. package/dist-lib/components/composed/chat/index.d.ts +15 -0
  168. package/dist-lib/components/composed/chat/insight-cards.d.ts +54 -0
  169. package/dist-lib/components/composed/chat/markdown-atom.d.ts +7 -0
  170. package/dist-lib/components/composed/chat/markdown.d.ts +22 -0
  171. package/dist-lib/components/composed/chat/recommendation/checkbox.d.ts +9 -0
  172. package/dist-lib/components/composed/chat/recommendation/constant.d.ts +52 -0
  173. package/dist-lib/components/composed/chat/recommendation/default.d.ts +7 -0
  174. package/dist-lib/components/composed/chat/recommendation/group.d.ts +7 -0
  175. package/dist-lib/components/composed/chat/recommendation/index.d.ts +13 -0
  176. package/dist-lib/components/composed/chat/recommendation/item.d.ts +12 -0
  177. package/dist-lib/components/composed/chat/recommendation/types.d.ts +62 -0
  178. package/dist-lib/components/composed/chat/records-table.d.ts +40 -0
  179. package/dist-lib/components/composed/chat/type.d.ts +117 -0
  180. package/dist-lib/components/composed/logo.d.ts +34 -0
  181. package/dist-lib/components/composed/password-input.d.ts +30 -0
  182. package/dist-lib/components/composed/reader/applied-mark.d.ts +3 -0
  183. package/dist-lib/components/composed/reader/apply-toast.d.ts +3 -0
  184. package/dist-lib/components/composed/reader/selection-highlight.d.ts +3 -0
  185. package/dist-lib/components/composed/reader/selection-popover.d.ts +9 -0
  186. package/dist-lib/components/composed/reader/type.d.ts +40 -0
  187. package/dist-lib/components/composed/social-providers.d.ts +39 -0
  188. package/dist-lib/components/composed/tree/index.d.ts +6 -0
  189. package/dist-lib/components/composed/tree/tree-atom.d.ts +160 -0
  190. package/dist-lib/components/composed/tree/tree-context.d.ts +4 -0
  191. package/dist-lib/components/composed/tree/tree-node.d.ts +12 -0
  192. package/dist-lib/components/composed/tree/tree.d.ts +19 -0
  193. package/dist-lib/components/composed/tree/type.d.ts +290 -0
  194. package/dist-lib/components/composed/tree/use-tree-dnd.d.ts +18 -0
  195. package/dist-lib/components/composed/tree/use-tree-state.d.ts +25 -0
  196. package/dist-lib/components/composed/tree/use-tree.d.ts +24 -0
  197. package/dist-lib/components/composed/tree/utils.d.ts +28 -0
  198. package/dist-lib/components/composed/types.d.ts +7 -0
  199. package/dist-lib/components/composed/user/index.d.ts +11 -0
  200. package/dist-lib/components/composed/user/info.d.ts +12 -0
  201. package/dist-lib/components/composed/user/message.d.ts +2 -0
  202. package/dist-lib/components/composed/user/pill.d.ts +10 -0
  203. package/dist-lib/components/composed/user/types.d.ts +27 -0
  204. package/dist-lib/components/composed/verse/index.d.ts +2 -0
  205. package/dist-lib/components/composed/verse/types.d.ts +18 -0
  206. package/dist-lib/components/composed/verse/verse.d.ts +5 -0
  207. package/dist-lib/components/docs/atoms-gallery.d.ts +12 -0
  208. package/dist-lib/components/docs/block-demo-stage.d.ts +7 -0
  209. package/dist-lib/components/docs/blocks-gallery.d.ts +2 -0
  210. package/dist-lib/components/docs/browser.d.ts +10 -0
  211. package/dist-lib/components/docs/components-gallery.d.ts +2 -0
  212. package/dist-lib/components/docs/demo-controls.d.ts +21 -0
  213. package/dist-lib/components/icons/__tests__/icons.test.d.ts +1 -0
  214. package/dist-lib/components/icons/file-badge-cfm.d.ts +7 -0
  215. package/dist-lib/components/icons/file-badge-corpus.d.ts +7 -0
  216. package/dist-lib/components/icons/file-badge-pdf.d.ts +7 -0
  217. package/dist-lib/components/icons/file-badge-tei.d.ts +7 -0
  218. package/dist-lib/components/icons/file-badge-tf.d.ts +7 -0
  219. package/dist-lib/components/icons/file-badge-txt.d.ts +7 -0
  220. package/dist-lib/components/icons/file-badge-xml.d.ts +7 -0
  221. package/dist-lib/components/icons/file-wordmark-cfm.d.ts +7 -0
  222. package/dist-lib/components/icons/file-wordmark-corpus.d.ts +7 -0
  223. package/dist-lib/components/icons/file-wordmark-pdf.d.ts +7 -0
  224. package/dist-lib/components/icons/file-wordmark-tei.d.ts +7 -0
  225. package/dist-lib/components/icons/file-wordmark-tf.d.ts +7 -0
  226. package/dist-lib/components/icons/file-wordmark-txt.d.ts +7 -0
  227. package/dist-lib/components/icons/file-wordmark-xml.d.ts +7 -0
  228. package/dist-lib/components/icons/index.d.ts +15 -0
  229. package/dist-lib/components/icons/types.d.ts +7 -0
  230. package/dist-lib/components/motion/index.d.ts +1 -0
  231. package/dist-lib/components/motion/overflow-actions.d.ts +35 -0
  232. package/dist-lib/components/motion/popover-morph.d.ts +35 -0
  233. package/dist-lib/components/motion/popover-position.d.ts +15 -0
  234. package/dist-lib/components/motion/shared-layout-bg.d.ts +13 -0
  235. package/dist-lib/components/stories/attachment.story.d.ts +11 -0
  236. package/dist-lib/components/stories/auth-flow-block.story.d.ts +2 -0
  237. package/dist-lib/components/stories/avatar.story.d.ts +6 -0
  238. package/dist-lib/components/stories/base.story.d.ts +6 -0
  239. package/dist-lib/components/stories/bubble.story.d.ts +6 -0
  240. package/dist-lib/components/stories/button.story.d.ts +9 -0
  241. package/dist-lib/components/stories/card.story.d.ts +8 -0
  242. package/dist-lib/components/stories/chart.story.d.ts +71 -0
  243. package/dist-lib/components/stories/checkbox.story.d.ts +6 -0
  244. package/dist-lib/components/stories/code-auth-block.story.d.ts +2 -0
  245. package/dist-lib/components/stories/code-block.story.d.ts +12 -0
  246. package/dist-lib/components/stories/composed-password-input.story.d.ts +6 -0
  247. package/dist-lib/components/stories/context-cards.story.d.ts +3 -0
  248. package/dist-lib/components/stories/emoji-action-bar.story.d.ts +3 -0
  249. package/dist-lib/components/stories/field.story.d.ts +6 -0
  250. package/dist-lib/components/stories/file-icons.story.d.ts +5 -0
  251. package/dist-lib/components/stories/filter-table.story.d.ts +21 -0
  252. package/dist-lib/components/stories/flowchart.story.d.ts +3 -0
  253. package/dist-lib/components/stories/forgot-password-block.story.d.ts +2 -0
  254. package/dist-lib/components/stories/frame.story.d.ts +8 -0
  255. package/dist-lib/components/stories/index.d.ts +54 -0
  256. package/dist-lib/components/stories/input-group.story.d.ts +6 -0
  257. package/dist-lib/components/stories/input.story.d.ts +8 -0
  258. package/dist-lib/components/stories/insight-cards.story.d.ts +74 -0
  259. package/dist-lib/components/stories/label.story.d.ts +8 -0
  260. package/dist-lib/components/stories/linked-accounts-block.story.d.ts +2 -0
  261. package/dist-lib/components/stories/login-block.story.d.ts +2 -0
  262. package/dist-lib/components/stories/logo.story.d.ts +3 -0
  263. package/dist-lib/components/stories/markdown.story.d.ts +7 -0
  264. package/dist-lib/components/stories/menu-command.story.d.ts +13 -0
  265. package/dist-lib/components/stories/onboarding-block.story.d.ts +2 -0
  266. package/dist-lib/components/stories/otp-field.story.d.ts +8 -0
  267. package/dist-lib/components/stories/passkey-manager-block.story.d.ts +2 -0
  268. package/dist-lib/components/stories/passkey-sign-in-block.story.d.ts +2 -0
  269. package/dist-lib/components/stories/password-input.story.d.ts +9 -0
  270. package/dist-lib/components/stories/profile-card-block.story.d.ts +6 -0
  271. package/dist-lib/components/stories/recommendation-card.story.d.ts +3 -0
  272. package/dist-lib/components/stories/records-table.story.d.ts +23 -0
  273. package/dist-lib/components/stories/reference.story.d.ts +9 -0
  274. package/dist-lib/components/stories/research-answer.story.d.ts +10 -0
  275. package/dist-lib/components/stories/scaffold-root.story.d.ts +6 -0
  276. package/dist-lib/components/stories/separator.story.d.ts +6 -0
  277. package/dist-lib/components/stories/shell-layout.story.d.ts +2 -0
  278. package/dist-lib/components/stories/signup-block.story.d.ts +2 -0
  279. package/dist-lib/components/stories/social-providers.story.d.ts +3 -0
  280. package/dist-lib/components/stories/streaming-text.story.d.ts +3 -0
  281. package/dist-lib/components/stories/text.story.d.ts +8 -0
  282. package/dist-lib/components/stories/textarea.story.d.ts +6 -0
  283. package/dist-lib/components/stories/tree.story.d.ts +4 -0
  284. package/dist-lib/components/stories/update-password-block.story.d.ts +2 -0
  285. package/dist-lib/components/stories/user.story.d.ts +8 -0
  286. package/dist-lib/components/stories/verse.story.d.ts +6 -0
  287. package/dist-lib/components/theme-provider.d.ts +15 -0
  288. package/dist-lib/components/types.d.ts +11 -0
  289. package/dist-lib/components/ui/badge.d.ts +14 -0
  290. package/dist-lib/components/ui/button.d.ts +28 -0
  291. package/dist-lib/components/ui/chat/__tests__/segmented-toggle.test.d.ts +1 -0
  292. package/dist-lib/components/ui/chat/avatar-handle.d.ts +13 -0
  293. package/dist-lib/components/ui/chat/badges.d.ts +29 -0
  294. package/dist-lib/components/ui/chat/buttons.d.ts +29 -0
  295. package/dist-lib/components/ui/chat/chips.d.ts +48 -0
  296. package/dist-lib/components/ui/chat/dot.d.ts +30 -0
  297. package/dist-lib/components/ui/chat/icon-button.d.ts +18 -0
  298. package/dist-lib/components/ui/chat/icon-tile.d.ts +20 -0
  299. package/dist-lib/components/ui/chat/index.d.ts +12 -0
  300. package/dist-lib/components/ui/chat/inline-source.d.ts +20 -0
  301. package/dist-lib/components/ui/chat/segmented-toggle.d.ts +20 -0
  302. package/dist-lib/components/ui/chat/tag.d.ts +21 -0
  303. package/dist-lib/components/ui/chat/thumbnail.d.ts +13 -0
  304. package/dist-lib/components/ui/chat/waveform.d.ts +13 -0
  305. package/dist-lib/components/ui/glasscn/glass-button-group.d.ts +7 -0
  306. package/dist-lib/components/ui/glasscn/glass-button.d.ts +6 -0
  307. package/dist-lib/components/ui/glasscn/glass-container.d.ts +8 -0
  308. package/dist-lib/components/ui/glasscn/glass-separator.d.ts +5 -0
  309. package/dist-lib/components/ui/glasscn/liquid-glass.d.ts +29 -0
  310. package/dist-lib/components/ui/input-group.d.ts +13 -0
  311. package/dist-lib/components/ui/input.d.ts +9 -0
  312. package/dist-lib/components/ui/menu-command.d.ts +36 -0
  313. package/dist-lib/components/ui/popover-glass.d.ts +32 -0
  314. package/dist-lib/components/ui/select.d.ts +30 -0
  315. package/dist-lib/components/ui/tabs.d.ts +15 -0
  316. package/dist-lib/components/ui/textarea.d.ts +8 -0
  317. package/dist-lib/components/ui/toast.d.ts +15 -0
  318. package/dist-lib/index.d.ts +65 -0
  319. package/dist-lib/index.js +11893 -6443
  320. package/dist-lib/index.js.map +1 -1
  321. package/dist-lib/lib/attachment-content.d.ts +4 -0
  322. package/dist-lib/lib/auth-accent.d.ts +33 -0
  323. package/dist-lib/lib/glass-variants.d.ts +9 -0
  324. package/dist-lib/lib/keyed-atom.d.ts +14 -0
  325. package/dist-lib/lib/segmented-control.d.ts +8 -0
  326. package/dist-lib/lib/specular.d.ts +12 -0
  327. package/dist-lib/lib/state/__tests__/sound.test.d.ts +1 -0
  328. package/dist-lib/lib/state/exegia-provider.d.ts +51 -0
  329. package/dist-lib/lib/state/index.d.ts +4 -0
  330. package/dist-lib/lib/state/store.d.ts +17 -0
  331. package/dist-lib/lib/use-motion-panel.d.ts +9 -0
  332. package/dist-lib/lib/utils.test.d.ts +1 -0
  333. package/package.json +6 -1
  334. package/src/components/atoms/avatar/base.tsx +3 -3
  335. package/src/components/atoms/avatar/index.ts +8 -1
  336. package/src/components/atoms/avatar/types.ts +9 -9
  337. package/src/components/atoms/avatar/utils.ts +6 -6
  338. package/src/components/atoms/background/texture.tsx +2 -2
  339. package/src/components/atoms/background/type.ts +3 -3
  340. package/src/components/atoms/background/utils.ts +2 -2
  341. package/src/components/atoms/bubble/__tests__/bubble.test.tsx +59 -4
  342. package/src/components/atoms/bubble/actions.tsx +2 -2
  343. package/src/components/atoms/bubble/context.ts +3 -3
  344. package/src/components/atoms/bubble/default.tsx +2 -2
  345. package/src/components/atoms/bubble/header.tsx +6 -4
  346. package/src/components/atoms/bubble/index.ts +9 -9
  347. package/src/components/atoms/bubble/message.tsx +12 -5
  348. package/src/components/atoms/bubble/reactions.tsx +11 -14
  349. package/src/components/atoms/bubble/types.ts +21 -18
  350. package/src/components/atoms/bubble/utils.ts +10 -10
  351. package/src/components/atoms/field.tsx +43 -0
  352. package/src/components/atoms/index.ts +0 -26
  353. package/src/components/atoms/loader.tsx +2 -11
  354. package/src/components/atoms/reference.tsx +2 -2
  355. package/src/components/atoms/text/default.tsx +5 -5
  356. package/src/components/atoms/text/heading.tsx +2 -5
  357. package/src/components/atoms/text/index.ts +8 -4
  358. package/src/components/atoms/text/label.tsx +2 -2
  359. package/src/components/atoms/text/paragraph.tsx +2 -5
  360. package/src/components/atoms/text/span.tsx +2 -3
  361. package/src/components/atoms/text/types.ts +18 -8
  362. package/src/components/atoms/text/utils.ts +2 -2
  363. package/src/components/atoms/text-selection/click-popover.tsx +3 -3
  364. package/src/components/atoms/text-selection/index.ts +12 -12
  365. package/src/components/atoms/text-selection/popover.tsx +7 -4
  366. package/src/components/atoms/text-selection/selection-atom.ts +7 -7
  367. package/src/components/atoms/text-selection/selection.tsx +2 -2
  368. package/src/components/atoms/text-selection/types.ts +24 -24
  369. package/src/components/atoms/text-selection/use-selection.ts +3 -3
  370. package/src/components/atoms/types.ts +30 -2
  371. package/src/components/blocks/auth/__tests__/auth-flow-block.test.tsx +4 -4
  372. package/src/components/blocks/auth/__tests__/auth-state-atom.test.tsx +2 -2
  373. package/src/components/blocks/auth/__tests__/linked-accounts-block.test.tsx +2 -2
  374. package/src/components/blocks/auth/__tests__/onboarding-block.test.tsx +39 -12
  375. package/src/components/blocks/auth/__tests__/passkey-manager-block.test.tsx +4 -4
  376. package/src/components/blocks/auth/auth-flow-atom.ts +27 -27
  377. package/src/components/blocks/auth/auth-flow-block.tsx +8 -93
  378. package/src/components/blocks/auth/auth-session-atom.ts +9 -9
  379. package/src/components/blocks/auth/auth-shell.tsx +2 -3
  380. package/src/components/blocks/auth/auth-state.ts +0 -12
  381. package/src/components/blocks/auth/code-auth-block.tsx +16 -30
  382. package/src/components/blocks/auth/forgot-password-block.tsx +4 -15
  383. package/src/components/blocks/auth/linked-accounts-block.tsx +10 -36
  384. package/src/components/blocks/auth/login-block.tsx +7 -29
  385. package/src/components/blocks/auth/onboarding/profile-step.tsx +14 -25
  386. package/src/components/blocks/auth/onboarding-block.tsx +39 -96
  387. package/src/components/blocks/auth/passkey-manager-block.tsx +8 -33
  388. package/src/components/blocks/auth/passkey-sign-in-block.tsx +6 -20
  389. package/src/components/blocks/auth/signup-block.tsx +7 -44
  390. package/src/components/blocks/auth/type.ts +436 -0
  391. package/src/components/blocks/auth/update-password-block.tsx +4 -22
  392. package/src/components/blocks/auth/use-auth-state.ts +12 -12
  393. package/src/components/blocks/chat/__tests__/ai-panel.test.tsx +2 -2
  394. package/src/components/blocks/chat/banners.tsx +5 -13
  395. package/src/components/blocks/chat/base.tsx +2 -2
  396. package/src/components/blocks/chat/header.tsx +2 -2
  397. package/src/components/blocks/chat/index.ts +17 -19
  398. package/src/components/blocks/chat/recommendation-stack.tsx +4 -6
  399. package/src/components/blocks/chat/suggested-prompts.tsx +2 -2
  400. package/src/components/blocks/chat/type.ts +96 -0
  401. package/src/components/blocks/chat/version-history-record.tsx +2 -2
  402. package/src/components/blocks/profile/__tests__/profile-card-block.test.tsx +6 -6
  403. package/src/components/blocks/profile/index.ts +2 -2
  404. package/src/components/blocks/profile/profile-card-atom.ts +29 -29
  405. package/src/components/blocks/profile/profile-card-block.tsx +30 -30
  406. package/src/components/blocks/profile/type.ts +17 -17
  407. package/src/components/blocks/profile/use-profile-card-state.ts +7 -7
  408. package/src/components/blocks/profile/use-profile-card.ts +18 -18
  409. package/src/components/blocks/scaffold/__tests__/scaffold-atom.test.tsx +28 -2
  410. package/src/components/blocks/scaffold/__tests__/scaffold.test.tsx +90 -11
  411. package/src/components/blocks/scaffold/index.ts +4 -0
  412. package/src/components/blocks/scaffold/panel-close-button.tsx +2 -2
  413. package/src/components/blocks/scaffold/panel-menu-button.tsx +2 -2
  414. package/src/components/blocks/scaffold/scaffold-actions.tsx +2 -2
  415. package/src/components/blocks/scaffold/scaffold-atom.ts +76 -32
  416. package/src/components/blocks/scaffold/scaffold-canvas.tsx +89 -10
  417. package/src/components/blocks/scaffold/scaffold-context.ts +3 -3
  418. package/src/components/blocks/scaffold/scaffold-inspector.tsx +56 -7
  419. package/src/components/blocks/scaffold/scaffold-main.tsx +2 -2
  420. package/src/components/blocks/scaffold/scaffold-panel.tsx +119 -71
  421. package/src/components/blocks/scaffold/scaffold-root.tsx +14 -12
  422. package/src/components/blocks/scaffold/scaffold-sidebar.tsx +2 -2
  423. package/src/components/blocks/scaffold/scaffold-sub-panel.tsx +82 -13
  424. package/src/components/blocks/scaffold/scaffold-tab.tsx +2 -2
  425. package/src/components/blocks/scaffold/type.ts +46 -28
  426. package/src/components/blocks/scaffold/use-scaffold-state.ts +35 -8
  427. package/src/components/blocks/scaffold/use-scaffold.ts +3 -3
  428. package/src/components/blocks/scaffold/utils.ts +9 -6
  429. package/src/components/blocks/shell/__tests__/shell-fit-atom.test.tsx +7 -5
  430. package/src/components/blocks/shell/__tests__/shell-layout.test.tsx +154 -9
  431. package/src/components/blocks/shell/__tests__/shell-metrics.test.ts +56 -10
  432. package/src/components/blocks/shell/animated-panel-inset.tsx +9 -9
  433. package/src/components/blocks/shell/animated-panel-provider.tsx +76 -30
  434. package/src/components/blocks/shell/animated-panel-trigger.tsx +10 -5
  435. package/src/components/blocks/shell/animated-panel.tsx +76 -128
  436. package/src/components/blocks/shell/shell-fit-atom.ts +29 -26
  437. package/src/components/blocks/shell/shell-layout.tsx +29 -13
  438. package/src/components/blocks/shell/shell-metrics.ts +69 -15
  439. package/src/components/blocks/shell/shell-panel-atom.ts +74 -0
  440. package/src/components/blocks/shell/type.ts +78 -69
  441. package/src/components/blocks/shell/use-shell-fit-state.ts +4 -4
  442. package/src/components/blocks/shell/use-shell-fit.ts +52 -34
  443. package/src/components/blocks/shell/use-shell-panels.ts +32 -66
  444. package/src/components/blocks/shell/utils.ts +8 -4
  445. package/src/components/blocks/sidebar/__tests__/ai-sidebar-atom.test.tsx +325 -0
  446. package/src/components/blocks/sidebar/__tests__/ai-sidebar.test.tsx +93 -0
  447. package/src/components/blocks/sidebar/__tests__/use-ai-sidebar.test.tsx +310 -0
  448. package/src/components/blocks/sidebar/ai-sidebar-atom.ts +698 -0
  449. package/src/components/blocks/sidebar/ai-sidebar.tsx +150 -0
  450. package/src/components/blocks/sidebar/index.ts +67 -0
  451. package/src/components/blocks/sidebar/sidebar-context.ts +15 -0
  452. package/src/components/blocks/sidebar/sidebar-icon.tsx +14 -0
  453. package/src/components/blocks/sidebar/sidebar-row.tsx +378 -0
  454. package/src/components/blocks/sidebar/type.ts +294 -0
  455. package/src/components/blocks/sidebar/use-ai-sidebar-state.ts +123 -0
  456. package/src/components/blocks/sidebar/use-ai-sidebar.ts +619 -0
  457. package/src/components/blocks/sidebar/utils.ts +170 -0
  458. package/src/components/blocks/types.ts +6 -0
  459. package/src/components/composed/action-bar/__tests__/action-bar.test.tsx +43 -14
  460. package/src/components/composed/action-bar/action.tsx +9 -12
  461. package/src/components/composed/action-bar/emojis.tsx +4 -4
  462. package/src/components/composed/action-bar/index.ts +8 -8
  463. package/src/components/composed/action-bar/toolbar.tsx +36 -30
  464. package/src/components/composed/action-bar/types.ts +14 -14
  465. package/src/components/composed/action-bar/utils.ts +17 -18
  466. package/src/components/composed/ai/__tests__/ai.test.tsx +3 -4
  467. package/src/components/composed/ai/avatar.tsx +4 -5
  468. package/src/components/composed/ai/index.ts +7 -7
  469. package/src/components/composed/ai/message.tsx +7 -7
  470. package/src/components/composed/ai/research-answer.tsx +7 -7
  471. package/src/components/composed/ai/streaming-text.tsx +5 -5
  472. package/src/components/composed/ai/suggested-prompt.tsx +4 -4
  473. package/src/components/composed/ai/types.ts +30 -30
  474. package/src/components/composed/chat/__tests__/attachment.test.tsx +182 -9
  475. package/src/components/composed/chat/__tests__/chart.test.tsx +295 -8
  476. package/src/components/composed/chat/__tests__/composer-attachments.test.tsx +51 -3
  477. package/src/components/composed/chat/__tests__/composer.test.tsx +173 -6
  478. package/src/components/composed/chat/__tests__/flowchart.test.tsx +15 -2
  479. package/src/components/composed/chat/__tests__/glass-material.test.tsx +54 -0
  480. package/src/components/composed/chat/__tests__/menu-command.test.tsx +35 -0
  481. package/src/components/composed/chat/__tests__/recommendation.test.tsx +43 -0
  482. package/src/components/composed/chat/attachment-file.ts +82 -0
  483. package/src/components/composed/chat/attachment.tsx +387 -117
  484. package/src/components/composed/chat/chart/chart-atom.ts +55 -0
  485. package/src/components/composed/chat/chart/chart-context.ts +9 -0
  486. package/src/components/composed/chat/chart/chart-legend.tsx +75 -0
  487. package/src/components/composed/chat/chart/chart-plot.tsx +233 -0
  488. package/src/components/composed/chat/chart/chart-root.tsx +229 -0
  489. package/src/components/composed/chat/chart/chart-tooltip.tsx +74 -0
  490. package/src/components/composed/chat/chart/constants.ts +8 -0
  491. package/src/components/composed/chat/chart/evilcharts/LICENSE +21 -0
  492. package/src/components/composed/chat/chart/evilcharts/README.md +8 -0
  493. package/src/components/composed/chat/chart/evilcharts/echarts-area-chart.tsx +2358 -0
  494. package/src/components/composed/chat/chart/evilcharts/echarts-bar-chart.tsx +2261 -0
  495. package/src/components/composed/chat/chart/evilcharts/echarts-brush.tsx +233 -0
  496. package/src/components/composed/chat/chart/evilcharts/echarts-chart.tsx +214 -0
  497. package/src/components/composed/chat/chart/evilcharts/echarts-dot.tsx +111 -0
  498. package/src/components/composed/chat/chart/evilcharts/echarts-legend.tsx +131 -0
  499. package/src/components/composed/chat/chart/evilcharts/echarts-line-chart.tsx +2112 -0
  500. package/src/components/composed/chat/chart/evilcharts/echarts-pie-chart.tsx +1235 -0
  501. package/src/components/composed/chat/chart/evilcharts/echarts-tooltip.tsx +125 -0
  502. package/src/components/composed/chat/chart/index.ts +13 -0
  503. package/src/components/composed/chat/chart/type.ts +88 -0
  504. package/src/components/composed/chat/chart/use-chart-state.ts +22 -0
  505. package/src/components/composed/chat/chart/use-chart.ts +70 -0
  506. package/src/components/composed/chat/chart/utils.ts +47 -0
  507. package/src/components/composed/chat/chart.tsx +2 -192
  508. package/src/components/composed/chat/code-block.tsx +5 -5
  509. package/src/components/composed/chat/composer/BEAUTIFUL-UI-LICENSE.txt +23 -0
  510. package/src/components/composed/chat/composer/add-button.tsx +24 -17
  511. package/src/components/composed/chat/composer/base.tsx +503 -178
  512. package/src/components/composed/chat/composer/command-menu.tsx +31 -26
  513. package/src/components/composed/chat/composer/hooks.ts +3 -3
  514. package/src/components/composed/chat/composer/send-button.tsx +20 -28
  515. package/src/components/composed/chat/composer/suggestions.tsx +2 -2
  516. package/src/components/composed/chat/composer/use-dictation.ts +123 -0
  517. package/src/components/composed/chat/composer/utils.ts +4 -4
  518. package/src/components/composed/chat/context-cards.tsx +5 -5
  519. package/src/components/composed/chat/filter-table.tsx +8 -8
  520. package/src/components/composed/chat/flowchart/chart-node.tsx +2 -2
  521. package/src/components/composed/chat/flowchart/connector.tsx +2 -2
  522. package/src/components/composed/chat/flowchart/default.tsx +3 -3
  523. package/src/components/composed/chat/flowchart/edge-toolbar.tsx +5 -5
  524. package/src/components/composed/chat/flowchart/hooks.tsx +28 -26
  525. package/src/components/composed/chat/flowchart/step-body.tsx +2 -2
  526. package/src/components/composed/chat/flowchart/types.ts +14 -14
  527. package/src/components/composed/chat/flowchart/utils.ts +15 -15
  528. package/src/components/composed/chat/index.ts +35 -39
  529. package/src/components/composed/chat/insight-cards.tsx +17 -17
  530. package/src/components/composed/chat/markdown-atom.ts +2 -2
  531. package/src/components/composed/chat/markdown.tsx +10 -10
  532. package/src/components/composed/chat/recommendation/checkbox.tsx +3 -14
  533. package/src/components/composed/chat/recommendation/constant.ts +35 -6
  534. package/src/components/composed/chat/recommendation/default.tsx +2 -2
  535. package/src/components/composed/chat/recommendation/group.tsx +4 -11
  536. package/src/components/composed/chat/recommendation/index.ts +0 -2
  537. package/src/components/composed/chat/recommendation/item.tsx +35 -64
  538. package/src/components/composed/chat/recommendation/types.ts +26 -15
  539. package/src/components/composed/chat/records-table.tsx +20 -18
  540. package/src/components/composed/chat/type.ts +56 -25
  541. package/src/components/composed/logo.tsx +4 -4
  542. package/src/components/composed/password-input.tsx +2 -2
  543. package/src/components/composed/reader/applied-mark.tsx +2 -2
  544. package/src/components/composed/reader/apply-toast.tsx +2 -2
  545. package/src/components/composed/reader/selection-highlight.tsx +2 -2
  546. package/src/components/composed/reader/selection-popover.tsx +2 -2
  547. package/src/components/composed/reader/type.ts +8 -8
  548. package/src/components/composed/social-providers.tsx +26 -18
  549. package/src/components/composed/tree/CLAUDE.md +3 -3
  550. package/src/components/composed/tree/__tests__/tree-atom.test.tsx +8 -8
  551. package/src/components/composed/tree/__tests__/tree.test.tsx +10 -10
  552. package/src/components/composed/tree/__tests__/use-tree.test.tsx +10 -10
  553. package/src/components/composed/tree/index.ts +12 -12
  554. package/src/components/composed/tree/tree-atom.ts +46 -46
  555. package/src/components/composed/tree/tree-context.ts +3 -3
  556. package/src/components/composed/tree/tree-node.tsx +7 -7
  557. package/src/components/composed/tree/tree.tsx +13 -13
  558. package/src/components/composed/tree/type.ts +56 -56
  559. package/src/components/composed/tree/use-tree-dnd.ts +10 -10
  560. package/src/components/composed/tree/use-tree-state.ts +3 -3
  561. package/src/components/composed/tree/use-tree.ts +10 -10
  562. package/src/components/composed/tree/utils.ts +21 -21
  563. package/src/components/composed/types.ts +9 -0
  564. package/src/components/composed/user/__tests__/message.test.tsx +79 -0
  565. package/src/components/composed/user/index.ts +2 -2
  566. package/src/components/composed/user/info.tsx +15 -7
  567. package/src/components/composed/user/message.tsx +33 -7
  568. package/src/components/composed/user/pill.tsx +3 -3
  569. package/src/components/composed/user/types.ts +34 -14
  570. package/src/components/composed/verse/index.ts +1 -1
  571. package/src/components/composed/verse/types.ts +8 -8
  572. package/src/components/composed/verse/verse.tsx +6 -6
  573. package/src/components/docs/atoms-gallery.tsx +45 -45
  574. package/src/components/docs/block-demo-stage.tsx +38 -0
  575. package/src/components/docs/blocks-gallery.tsx +224 -0
  576. package/src/components/docs/browser.tsx +87 -0
  577. package/src/components/docs/components-gallery.tsx +182 -0
  578. package/src/components/docs/demo-controls.tsx +6 -7
  579. package/src/components/docs/hero.tsx +2 -3
  580. package/src/components/icons/file-badge-cfm.tsx +2 -2
  581. package/src/components/icons/file-badge-corpus.tsx +2 -2
  582. package/src/components/icons/file-badge-pdf.tsx +2 -2
  583. package/src/components/icons/file-badge-tei.tsx +2 -2
  584. package/src/components/icons/file-badge-tf.tsx +2 -2
  585. package/src/components/icons/file-badge-txt.tsx +2 -2
  586. package/src/components/icons/file-badge-xml.tsx +2 -2
  587. package/src/components/icons/file-wordmark-cfm.tsx +2 -2
  588. package/src/components/icons/file-wordmark-corpus.tsx +2 -2
  589. package/src/components/icons/file-wordmark-pdf.tsx +2 -2
  590. package/src/components/icons/file-wordmark-tei.tsx +2 -2
  591. package/src/components/icons/file-wordmark-tf.tsx +2 -2
  592. package/src/components/icons/file-wordmark-txt.tsx +2 -2
  593. package/src/components/icons/file-wordmark-xml.tsx +2 -2
  594. package/src/components/icons/index.ts +1 -1
  595. package/src/components/icons/types.ts +1 -1
  596. package/src/components/motion/overflow-actions.tsx +19 -19
  597. package/src/components/motion/popover-morph.tsx +15 -15
  598. package/src/components/motion/popover-position.ts +4 -4
  599. package/src/components/motion/shared-layout-bg.tsx +2 -2
  600. package/src/components/stories/attachment.story.tsx +40 -0
  601. package/src/components/stories/auth-flow-block.story.tsx +17 -0
  602. package/src/components/stories/avatar.story.tsx +33 -0
  603. package/src/components/stories/base.story.tsx +70 -0
  604. package/src/components/stories/bubble.story.tsx +61 -0
  605. package/src/components/stories/button.story.tsx +32 -0
  606. package/src/components/stories/card.story.tsx +36 -0
  607. package/src/components/stories/chart.story.tsx +69 -0
  608. package/src/components/stories/checkbox.story.tsx +30 -0
  609. package/src/components/stories/code-auth-block.story.tsx +20 -0
  610. package/src/components/stories/code-block.story.tsx +35 -0
  611. package/src/components/stories/composed-password-input.story.tsx +41 -0
  612. package/src/components/stories/context-cards.story.tsx +30 -0
  613. package/src/components/stories/emoji-action-bar.story.tsx +20 -0
  614. package/src/components/stories/field.story.tsx +32 -0
  615. package/src/components/stories/file-icons.story.tsx +20 -0
  616. package/src/components/stories/filter-table.story.tsx +63 -0
  617. package/src/components/stories/flowchart.story.tsx +25 -0
  618. package/src/components/stories/forgot-password-block.story.tsx +14 -0
  619. package/src/components/stories/frame.story.tsx +32 -0
  620. package/src/components/stories/index.ts +57 -0
  621. package/src/components/stories/input-group.story.tsx +27 -0
  622. package/src/components/stories/input.story.tsx +42 -0
  623. package/src/components/stories/insight-cards.story.tsx +67 -0
  624. package/src/components/stories/label.story.tsx +32 -0
  625. package/src/components/stories/linked-accounts-block.story.tsx +23 -0
  626. package/src/components/stories/login-block.story.tsx +18 -0
  627. package/src/components/stories/logo.story.tsx +21 -0
  628. package/src/components/stories/markdown.story.tsx +31 -0
  629. package/src/components/stories/menu-command.story.tsx +43 -0
  630. package/src/components/stories/onboarding-block.story.tsx +14 -0
  631. package/src/components/stories/otp-field.story.tsx +35 -0
  632. package/src/components/stories/passkey-manager-block.story.tsx +18 -0
  633. package/src/components/stories/passkey-sign-in-block.story.tsx +15 -0
  634. package/src/components/stories/password-input.story.tsx +35 -0
  635. package/src/components/stories/profile-card-block.story.tsx +29 -0
  636. package/src/components/stories/recommendation-card.story.tsx +37 -0
  637. package/src/components/stories/records-table.story.tsx +52 -0
  638. package/src/components/stories/reference.story.tsx +33 -0
  639. package/src/components/stories/research-answer.story.tsx +32 -0
  640. package/src/components/stories/scaffold-root.story.tsx +47 -0
  641. package/src/components/stories/separator.story.tsx +37 -0
  642. package/src/components/stories/shell-layout.story.tsx +19 -0
  643. package/src/components/stories/signup-block.story.tsx +18 -0
  644. package/src/components/stories/social-providers.story.tsx +26 -0
  645. package/src/components/stories/streaming-text.story.tsx +25 -0
  646. package/src/components/stories/text.story.tsx +31 -0
  647. package/src/components/stories/textarea.story.tsx +34 -0
  648. package/src/components/stories/tree.story.tsx +31 -0
  649. package/src/components/stories/update-password-block.story.tsx +14 -0
  650. package/src/components/stories/user.story.tsx +32 -0
  651. package/src/components/stories/verse.story.tsx +42 -0
  652. package/src/components/theme-provider.tsx +16 -16
  653. package/src/components/types.ts +106 -0
  654. package/src/components/ui/badge.tsx +3 -3
  655. package/src/components/ui/button.tsx +15 -22
  656. package/src/components/ui/chat/avatar-handle.tsx +2 -2
  657. package/src/components/ui/chat/badges.tsx +2 -2
  658. package/src/components/ui/chat/buttons.tsx +7 -7
  659. package/src/components/ui/chat/chips.tsx +11 -11
  660. package/src/components/ui/chat/dot.tsx +8 -8
  661. package/src/components/ui/chat/icon-button.tsx +3 -3
  662. package/src/components/ui/chat/icon-tile.tsx +2 -2
  663. package/src/components/ui/chat/index.ts +12 -12
  664. package/src/components/ui/chat/inline-source.tsx +2 -2
  665. package/src/components/ui/chat/segmented-toggle.tsx +4 -4
  666. package/src/components/ui/chat/tag.tsx +10 -10
  667. package/src/components/ui/chat/thumbnail.tsx +2 -2
  668. package/src/components/ui/chat/waveform.tsx +2 -2
  669. package/src/components/ui/field.tsx +3 -3
  670. package/src/components/ui/glasscn/glass-button-group.tsx +7 -21
  671. package/src/components/ui/glasscn/glass-button.tsx +5 -5
  672. package/src/components/ui/glasscn/glass-container.tsx +10 -47
  673. package/src/components/ui/glasscn/glass-separator.tsx +6 -6
  674. package/src/components/ui/glasscn/liquid-glass.tsx +43 -300
  675. package/src/components/ui/input-group.tsx +4 -4
  676. package/src/components/ui/input.tsx +2 -2
  677. package/src/components/ui/menu-command.tsx +103 -75
  678. package/src/components/ui/popover-glass.tsx +11 -14
  679. package/src/components/ui/select.tsx +2 -2
  680. package/src/components/ui/tabs.tsx +12 -12
  681. package/src/components/ui/textarea.tsx +2 -2
  682. package/src/components/ui/toast.tsx +13 -13
  683. package/src/index.css +3 -1
  684. package/src/index.ts +3 -1
  685. package/src/lib/attachment-content.ts +28 -0
  686. package/src/lib/auth-accent.ts +2 -2
  687. package/src/lib/glass-variants.ts +19 -54
  688. package/src/lib/keyed-atom.ts +3 -3
  689. package/src/lib/segmented-control.ts +2 -2
  690. package/src/lib/specular.ts +10 -0
  691. package/src/lib/state/__tests__/sound.test.tsx +53 -0
  692. package/src/lib/state/exegia-provider.tsx +6 -6
  693. package/src/lib/state/index.ts +2 -2
  694. package/src/lib/state/store.ts +2 -2
  695. package/src/lib/use-motion-panel.ts +78 -0
  696. package/src/lib/utils.ts +7 -5
  697. package/src/specular.js +4 -0
  698. package/dist-lib/src/components/atoms/avatar/base.d.ts +0 -2
  699. package/dist-lib/src/components/atoms/avatar/index.d.ts +0 -2
  700. package/dist-lib/src/components/atoms/avatar/types.d.ts +0 -20
  701. package/dist-lib/src/components/atoms/avatar/utils.d.ts +0 -13
  702. package/dist-lib/src/components/atoms/background/texture.d.ts +0 -2
  703. package/dist-lib/src/components/atoms/background/type.d.ts +0 -7
  704. package/dist-lib/src/components/atoms/background/utils.d.ts +0 -4
  705. package/dist-lib/src/components/atoms/bubble/actions.d.ts +0 -7
  706. package/dist-lib/src/components/atoms/bubble/context.d.ts +0 -4
  707. package/dist-lib/src/components/atoms/bubble/default.d.ts +0 -3
  708. package/dist-lib/src/components/atoms/bubble/header.d.ts +0 -8
  709. package/dist-lib/src/components/atoms/bubble/index.d.ts +0 -16
  710. package/dist-lib/src/components/atoms/bubble/message.d.ts +0 -3
  711. package/dist-lib/src/components/atoms/bubble/reactions.d.ts +0 -14
  712. package/dist-lib/src/components/atoms/bubble/types.d.ts +0 -59
  713. package/dist-lib/src/components/atoms/bubble/utils.d.ts +0 -13
  714. package/dist-lib/src/components/atoms/index.d.ts +0 -15
  715. package/dist-lib/src/components/atoms/loader.d.ts +0 -8
  716. package/dist-lib/src/components/atoms/reference.d.ts +0 -7
  717. package/dist-lib/src/components/atoms/text/default.d.ts +0 -1144
  718. package/dist-lib/src/components/atoms/text/heading.d.ts +0 -4
  719. package/dist-lib/src/components/atoms/text/index.d.ts +0 -21
  720. package/dist-lib/src/components/atoms/text/label.d.ts +0 -2
  721. package/dist-lib/src/components/atoms/text/paragraph.d.ts +0 -4
  722. package/dist-lib/src/components/atoms/text/span.d.ts +0 -3
  723. package/dist-lib/src/components/atoms/text/types.d.ts +0 -23
  724. package/dist-lib/src/components/atoms/text/utils.d.ts +0 -4
  725. package/dist-lib/src/components/atoms/text-selection/click-popover.d.ts +0 -3
  726. package/dist-lib/src/components/atoms/text-selection/index.d.ts +0 -6
  727. package/dist-lib/src/components/atoms/text-selection/popover.d.ts +0 -3
  728. package/dist-lib/src/components/atoms/text-selection/selection-atom.d.ts +0 -30
  729. package/dist-lib/src/components/atoms/text-selection/selection.d.ts +0 -3
  730. package/dist-lib/src/components/atoms/text-selection/types.d.ts +0 -90
  731. package/dist-lib/src/components/atoms/text-selection/use-selection.d.ts +0 -7
  732. package/dist-lib/src/components/atoms/types.d.ts +0 -17
  733. package/dist-lib/src/components/blocks/auth/auth-flow-atom.d.ts +0 -77
  734. package/dist-lib/src/components/blocks/auth/auth-flow-block.d.ts +0 -123
  735. package/dist-lib/src/components/blocks/auth/auth-flow-block.story.d.ts +0 -3
  736. package/dist-lib/src/components/blocks/auth/auth-session-atom.d.ts +0 -28
  737. package/dist-lib/src/components/blocks/auth/auth-shell.d.ts +0 -56
  738. package/dist-lib/src/components/blocks/auth/auth-state-type.d.ts +0 -71
  739. package/dist-lib/src/components/blocks/auth/auth-state.d.ts +0 -9
  740. package/dist-lib/src/components/blocks/auth/code-auth-block.d.ts +0 -22
  741. package/dist-lib/src/components/blocks/auth/code-auth-block.story.d.ts +0 -3
  742. package/dist-lib/src/components/blocks/auth/forgot-password-block.d.ts +0 -15
  743. package/dist-lib/src/components/blocks/auth/forgot-password-block.story.d.ts +0 -3
  744. package/dist-lib/src/components/blocks/auth/linked-accounts-block.d.ts +0 -36
  745. package/dist-lib/src/components/blocks/auth/linked-accounts-block.story.d.ts +0 -3
  746. package/dist-lib/src/components/blocks/auth/login-block.d.ts +0 -25
  747. package/dist-lib/src/components/blocks/auth/login-block.story.d.ts +0 -3
  748. package/dist-lib/src/components/blocks/auth/onboarding/profile-step.d.ts +0 -19
  749. package/dist-lib/src/components/blocks/auth/onboarding-block.d.ts +0 -69
  750. package/dist-lib/src/components/blocks/auth/onboarding-block.story.d.ts +0 -3
  751. package/dist-lib/src/components/blocks/auth/passkey-manager-block.d.ts +0 -38
  752. package/dist-lib/src/components/blocks/auth/passkey-manager-block.story.d.ts +0 -3
  753. package/dist-lib/src/components/blocks/auth/passkey-sign-in-block.d.ts +0 -27
  754. package/dist-lib/src/components/blocks/auth/passkey-sign-in-block.story.d.ts +0 -3
  755. package/dist-lib/src/components/blocks/auth/signup-block.d.ts +0 -41
  756. package/dist-lib/src/components/blocks/auth/signup-block.story.d.ts +0 -3
  757. package/dist-lib/src/components/blocks/auth/update-password-block.d.ts +0 -28
  758. package/dist-lib/src/components/blocks/auth/update-password-block.story.d.ts +0 -3
  759. package/dist-lib/src/components/blocks/auth/use-auth-state.d.ts +0 -52
  760. package/dist-lib/src/components/blocks/chat/banners.d.ts +0 -13
  761. package/dist-lib/src/components/blocks/chat/base.d.ts +0 -10
  762. package/dist-lib/src/components/blocks/chat/base.story.d.ts +0 -3
  763. package/dist-lib/src/components/blocks/chat/header.d.ts +0 -4
  764. package/dist-lib/src/components/blocks/chat/index.d.ts +0 -13
  765. package/dist-lib/src/components/blocks/chat/recommendation-stack.d.ts +0 -13
  766. package/dist-lib/src/components/blocks/chat/suggested-prompts.d.ts +0 -3
  767. package/dist-lib/src/components/blocks/chat/types.d.ts +0 -64
  768. package/dist-lib/src/components/blocks/chat/version-history-record.d.ts +0 -3
  769. package/dist-lib/src/components/blocks/layout.d.ts +0 -8
  770. package/dist-lib/src/components/blocks/nav/sidebar/ai-sidebar-atom.d.ts +0 -217
  771. package/dist-lib/src/components/blocks/nav/sidebar/ai-sidebar.d.ts +0 -11
  772. package/dist-lib/src/components/blocks/nav/sidebar/index.d.ts +0 -15
  773. package/dist-lib/src/components/blocks/nav/sidebar/sidebar-context.d.ts +0 -3
  774. package/dist-lib/src/components/blocks/nav/sidebar/sidebar-icon.d.ts +0 -2
  775. package/dist-lib/src/components/blocks/nav/sidebar/sidebar-row.d.ts +0 -4
  776. package/dist-lib/src/components/blocks/nav/sidebar/type.d.ts +0 -245
  777. package/dist-lib/src/components/blocks/nav/sidebar/use-ai-sidebar-state.d.ts +0 -29
  778. package/dist-lib/src/components/blocks/nav/sidebar/use-ai-sidebar.d.ts +0 -27
  779. package/dist-lib/src/components/blocks/nav/sidebar/utils.d.ts +0 -21
  780. package/dist-lib/src/components/blocks/profile/index.d.ts +0 -7
  781. package/dist-lib/src/components/blocks/profile/profile-card-atom.d.ts +0 -68
  782. package/dist-lib/src/components/blocks/profile/profile-card-block.d.ts +0 -66
  783. package/dist-lib/src/components/blocks/profile/profile-card-block.story.d.ts +0 -3
  784. package/dist-lib/src/components/blocks/profile/type.d.ts +0 -80
  785. package/dist-lib/src/components/blocks/profile/use-profile-card-state.d.ts +0 -24
  786. package/dist-lib/src/components/blocks/profile/use-profile-card.d.ts +0 -34
  787. package/dist-lib/src/components/blocks/scaffold/index.d.ts +0 -29
  788. package/dist-lib/src/components/blocks/scaffold/panel-close-button.d.ts +0 -4
  789. package/dist-lib/src/components/blocks/scaffold/panel-menu-button.d.ts +0 -8
  790. package/dist-lib/src/components/blocks/scaffold/scaffold-actions.d.ts +0 -10
  791. package/dist-lib/src/components/blocks/scaffold/scaffold-atom.d.ts +0 -97
  792. package/dist-lib/src/components/blocks/scaffold/scaffold-canvas.d.ts +0 -9
  793. package/dist-lib/src/components/blocks/scaffold/scaffold-context.d.ts +0 -7
  794. package/dist-lib/src/components/blocks/scaffold/scaffold-inspector.d.ts +0 -9
  795. package/dist-lib/src/components/blocks/scaffold/scaffold-main.d.ts +0 -8
  796. package/dist-lib/src/components/blocks/scaffold/scaffold-panel.d.ts +0 -10
  797. package/dist-lib/src/components/blocks/scaffold/scaffold-root.d.ts +0 -17
  798. package/dist-lib/src/components/blocks/scaffold/scaffold-root.story.d.ts +0 -3
  799. package/dist-lib/src/components/blocks/scaffold/scaffold-sidebar.d.ts +0 -7
  800. package/dist-lib/src/components/blocks/scaffold/scaffold-sub-panel.d.ts +0 -3
  801. package/dist-lib/src/components/blocks/scaffold/scaffold-tab.d.ts +0 -14
  802. package/dist-lib/src/components/blocks/scaffold/type.d.ts +0 -203
  803. package/dist-lib/src/components/blocks/scaffold/use-scaffold-state.d.ts +0 -26
  804. package/dist-lib/src/components/blocks/scaffold/use-scaffold.d.ts +0 -14
  805. package/dist-lib/src/components/blocks/scaffold/utils.d.ts +0 -37
  806. package/dist-lib/src/components/blocks/shell/animated-panel-inset.d.ts +0 -2
  807. package/dist-lib/src/components/blocks/shell/animated-panel-provider.d.ts +0 -2
  808. package/dist-lib/src/components/blocks/shell/animated-panel-trigger.d.ts +0 -2
  809. package/dist-lib/src/components/blocks/shell/animated-panel.d.ts +0 -2
  810. package/dist-lib/src/components/blocks/shell/shell-fit-atom.d.ts +0 -68
  811. package/dist-lib/src/components/blocks/shell/shell-layout.d.ts +0 -3
  812. package/dist-lib/src/components/blocks/shell/shell-layout.story.d.ts +0 -3
  813. package/dist-lib/src/components/blocks/shell/shell-metrics.d.ts +0 -54
  814. package/dist-lib/src/components/blocks/shell/type.d.ts +0 -292
  815. package/dist-lib/src/components/blocks/shell/use-shell-fit-state.d.ts +0 -25
  816. package/dist-lib/src/components/blocks/shell/use-shell-fit.d.ts +0 -14
  817. package/dist-lib/src/components/blocks/shell/use-shell-panels.d.ts +0 -20
  818. package/dist-lib/src/components/blocks/shell/utils.d.ts +0 -70
  819. package/dist-lib/src/components/composed/action-bar/action.d.ts +0 -18
  820. package/dist-lib/src/components/composed/action-bar/emojis.d.ts +0 -10
  821. package/dist-lib/src/components/composed/action-bar/index.d.ts +0 -12
  822. package/dist-lib/src/components/composed/action-bar/toolbar.d.ts +0 -2
  823. package/dist-lib/src/components/composed/action-bar/types.d.ts +0 -55
  824. package/dist-lib/src/components/composed/action-bar/utils.d.ts +0 -57
  825. package/dist-lib/src/components/composed/ai/index.d.ts +0 -17
  826. package/dist-lib/src/components/composed/ai/message.d.ts +0 -7
  827. package/dist-lib/src/components/composed/ai/research-answer.d.ts +0 -30
  828. package/dist-lib/src/components/composed/ai/streaming-text.d.ts +0 -26
  829. package/dist-lib/src/components/composed/ai/suggested-prompt.d.ts +0 -35
  830. package/dist-lib/src/components/composed/ai/types.d.ts +0 -66
  831. package/dist-lib/src/components/composed/attachment.story.d.ts +0 -3
  832. package/dist-lib/src/components/composed/chart.story.d.ts +0 -3
  833. package/dist-lib/src/components/composed/chat/attachment.d.ts +0 -62
  834. package/dist-lib/src/components/composed/chat/chart.d.ts +0 -41
  835. package/dist-lib/src/components/composed/chat/code-block.d.ts +0 -26
  836. package/dist-lib/src/components/composed/chat/composer/add-button.d.ts +0 -5
  837. package/dist-lib/src/components/composed/chat/composer/base.d.ts +0 -8
  838. package/dist-lib/src/components/composed/chat/composer/command-menu.d.ts +0 -2
  839. package/dist-lib/src/components/composed/chat/composer/hooks.d.ts +0 -9
  840. package/dist-lib/src/components/composed/chat/composer/send-button.d.ts +0 -3
  841. package/dist-lib/src/components/composed/chat/composer/suggestions.d.ts +0 -7
  842. package/dist-lib/src/components/composed/chat/composer/utils.d.ts +0 -19
  843. package/dist-lib/src/components/composed/chat/context-cards.d.ts +0 -27
  844. package/dist-lib/src/components/composed/chat/filter-table.d.ts +0 -40
  845. package/dist-lib/src/components/composed/chat/flowchart/chart-node.d.ts +0 -2
  846. package/dist-lib/src/components/composed/chat/flowchart/connector.d.ts +0 -2
  847. package/dist-lib/src/components/composed/chat/flowchart/default.d.ts +0 -7
  848. package/dist-lib/src/components/composed/chat/flowchart/edge-toolbar.d.ts +0 -9
  849. package/dist-lib/src/components/composed/chat/flowchart/hooks.d.ts +0 -290
  850. package/dist-lib/src/components/composed/chat/flowchart/step-body.d.ts +0 -6
  851. package/dist-lib/src/components/composed/chat/flowchart/types.d.ts +0 -91
  852. package/dist-lib/src/components/composed/chat/flowchart/utils.d.ts +0 -64
  853. package/dist-lib/src/components/composed/chat/index.d.ts +0 -15
  854. package/dist-lib/src/components/composed/chat/insight-cards.d.ts +0 -54
  855. package/dist-lib/src/components/composed/chat/markdown-atom.d.ts +0 -7
  856. package/dist-lib/src/components/composed/chat/markdown.d.ts +0 -22
  857. package/dist-lib/src/components/composed/chat/recommendation/checkbox.d.ts +0 -15
  858. package/dist-lib/src/components/composed/chat/recommendation/constant.d.ts +0 -6
  859. package/dist-lib/src/components/composed/chat/recommendation/default.d.ts +0 -7
  860. package/dist-lib/src/components/composed/chat/recommendation/group.d.ts +0 -8
  861. package/dist-lib/src/components/composed/chat/recommendation/index.d.ts +0 -15
  862. package/dist-lib/src/components/composed/chat/recommendation/item.d.ts +0 -12
  863. package/dist-lib/src/components/composed/chat/recommendation/types.d.ts +0 -53
  864. package/dist-lib/src/components/composed/chat/records-table.d.ts +0 -38
  865. package/dist-lib/src/components/composed/chat/type.d.ts +0 -86
  866. package/dist-lib/src/components/composed/code-block.story.d.ts +0 -3
  867. package/dist-lib/src/components/composed/context-cards.story.d.ts +0 -3
  868. package/dist-lib/src/components/composed/emoji-action-bar.story.d.ts +0 -3
  869. package/dist-lib/src/components/composed/filter-table.story.d.ts +0 -7
  870. package/dist-lib/src/components/composed/flowchart.story.d.ts +0 -3
  871. package/dist-lib/src/components/composed/insight-cards.story.d.ts +0 -3
  872. package/dist-lib/src/components/composed/logo.d.ts +0 -34
  873. package/dist-lib/src/components/composed/logo.story.d.ts +0 -3
  874. package/dist-lib/src/components/composed/markdown.story.d.ts +0 -3
  875. package/dist-lib/src/components/composed/password-input.d.ts +0 -30
  876. package/dist-lib/src/components/composed/password-input.story.d.ts +0 -7
  877. package/dist-lib/src/components/composed/reader/applied-mark.d.ts +0 -3
  878. package/dist-lib/src/components/composed/reader/apply-toast.d.ts +0 -3
  879. package/dist-lib/src/components/composed/reader/selection-highlight.d.ts +0 -3
  880. package/dist-lib/src/components/composed/reader/selection-popover.d.ts +0 -9
  881. package/dist-lib/src/components/composed/reader/type.d.ts +0 -40
  882. package/dist-lib/src/components/composed/recommendation-card.story.d.ts +0 -3
  883. package/dist-lib/src/components/composed/records-table.story.d.ts +0 -3
  884. package/dist-lib/src/components/composed/research-answer.story.d.ts +0 -3
  885. package/dist-lib/src/components/composed/social-providers.d.ts +0 -37
  886. package/dist-lib/src/components/composed/social-providers.story.d.ts +0 -3
  887. package/dist-lib/src/components/composed/streaming-text.story.d.ts +0 -3
  888. package/dist-lib/src/components/composed/tree/index.d.ts +0 -6
  889. package/dist-lib/src/components/composed/tree/tree-atom.d.ts +0 -160
  890. package/dist-lib/src/components/composed/tree/tree-context.d.ts +0 -4
  891. package/dist-lib/src/components/composed/tree/tree-node.d.ts +0 -12
  892. package/dist-lib/src/components/composed/tree/tree.d.ts +0 -19
  893. package/dist-lib/src/components/composed/tree/type.d.ts +0 -290
  894. package/dist-lib/src/components/composed/tree/use-tree-dnd.d.ts +0 -18
  895. package/dist-lib/src/components/composed/tree/use-tree-state.d.ts +0 -25
  896. package/dist-lib/src/components/composed/tree/use-tree.d.ts +0 -24
  897. package/dist-lib/src/components/composed/tree/utils.d.ts +0 -28
  898. package/dist-lib/src/components/composed/tree.story.d.ts +0 -6
  899. package/dist-lib/src/components/composed/user/index.d.ts +0 -11
  900. package/dist-lib/src/components/composed/user/info.d.ts +0 -12
  901. package/dist-lib/src/components/composed/user/message.d.ts +0 -3
  902. package/dist-lib/src/components/composed/user/pill.d.ts +0 -10
  903. package/dist-lib/src/components/composed/user/types.d.ts +0 -20
  904. package/dist-lib/src/components/composed/user.story.d.ts +0 -8
  905. package/dist-lib/src/components/composed/verse/index.d.ts +0 -2
  906. package/dist-lib/src/components/composed/verse/types.d.ts +0 -18
  907. package/dist-lib/src/components/composed/verse/verse.d.ts +0 -5
  908. package/dist-lib/src/components/composed/verse.story.d.ts +0 -3
  909. package/dist-lib/src/components/docs/atoms-gallery.d.ts +0 -3
  910. package/dist-lib/src/components/docs/demo-controls.d.ts +0 -21
  911. package/dist-lib/src/components/icons/file-badge-cfm.d.ts +0 -7
  912. package/dist-lib/src/components/icons/file-badge-corpus.d.ts +0 -7
  913. package/dist-lib/src/components/icons/file-badge-pdf.d.ts +0 -7
  914. package/dist-lib/src/components/icons/file-badge-tei.d.ts +0 -7
  915. package/dist-lib/src/components/icons/file-badge-tf.d.ts +0 -7
  916. package/dist-lib/src/components/icons/file-badge-txt.d.ts +0 -7
  917. package/dist-lib/src/components/icons/file-badge-xml.d.ts +0 -7
  918. package/dist-lib/src/components/icons/file-wordmark-cfm.d.ts +0 -7
  919. package/dist-lib/src/components/icons/file-wordmark-corpus.d.ts +0 -7
  920. package/dist-lib/src/components/icons/file-wordmark-pdf.d.ts +0 -7
  921. package/dist-lib/src/components/icons/file-wordmark-tei.d.ts +0 -7
  922. package/dist-lib/src/components/icons/file-wordmark-tf.d.ts +0 -7
  923. package/dist-lib/src/components/icons/file-wordmark-txt.d.ts +0 -7
  924. package/dist-lib/src/components/icons/file-wordmark-xml.d.ts +0 -7
  925. package/dist-lib/src/components/icons/index.d.ts +0 -15
  926. package/dist-lib/src/components/icons/types.d.ts +0 -7
  927. package/dist-lib/src/components/motion/overflow-actions.d.ts +0 -35
  928. package/dist-lib/src/components/motion/popover-morph.d.ts +0 -35
  929. package/dist-lib/src/components/motion/popover-position.d.ts +0 -15
  930. package/dist-lib/src/components/motion/shared-layout-bg.d.ts +0 -13
  931. package/dist-lib/src/components/theme-provider.d.ts +0 -15
  932. package/dist-lib/src/components/ui/avatar.story.d.ts +0 -7
  933. package/dist-lib/src/components/ui/badge.d.ts +0 -14
  934. package/dist-lib/src/components/ui/bubble.story.d.ts +0 -7
  935. package/dist-lib/src/components/ui/button.d.ts +0 -28
  936. package/dist-lib/src/components/ui/button.story.d.ts +0 -8
  937. package/dist-lib/src/components/ui/card.story.d.ts +0 -9
  938. package/dist-lib/src/components/ui/chat/avatar-handle.d.ts +0 -13
  939. package/dist-lib/src/components/ui/chat/badges.d.ts +0 -29
  940. package/dist-lib/src/components/ui/chat/buttons.d.ts +0 -29
  941. package/dist-lib/src/components/ui/chat/chips.d.ts +0 -48
  942. package/dist-lib/src/components/ui/chat/dot.d.ts +0 -30
  943. package/dist-lib/src/components/ui/chat/icon-button.d.ts +0 -18
  944. package/dist-lib/src/components/ui/chat/icon-tile.d.ts +0 -20
  945. package/dist-lib/src/components/ui/chat/index.d.ts +0 -12
  946. package/dist-lib/src/components/ui/chat/inline-source.d.ts +0 -20
  947. package/dist-lib/src/components/ui/chat/segmented-toggle.d.ts +0 -20
  948. package/dist-lib/src/components/ui/chat/tag.d.ts +0 -21
  949. package/dist-lib/src/components/ui/chat/thumbnail.d.ts +0 -13
  950. package/dist-lib/src/components/ui/chat/waveform.d.ts +0 -13
  951. package/dist-lib/src/components/ui/chat-atoms.story.d.ts +0 -22
  952. package/dist-lib/src/components/ui/checkbox.story.d.ts +0 -7
  953. package/dist-lib/src/components/ui/field.story.d.ts +0 -7
  954. package/dist-lib/src/components/ui/file-icons.story.d.ts +0 -7
  955. package/dist-lib/src/components/ui/frame.story.d.ts +0 -9
  956. package/dist-lib/src/components/ui/glasscn/glass-button-group.d.ts +0 -5
  957. package/dist-lib/src/components/ui/glasscn/glass-button.d.ts +0 -6
  958. package/dist-lib/src/components/ui/glasscn/glass-container.d.ts +0 -12
  959. package/dist-lib/src/components/ui/glasscn/glass-separator.d.ts +0 -5
  960. package/dist-lib/src/components/ui/glasscn/liquid-glass.d.ts +0 -31
  961. package/dist-lib/src/components/ui/input-group.d.ts +0 -13
  962. package/dist-lib/src/components/ui/input-group.story.d.ts +0 -7
  963. package/dist-lib/src/components/ui/input.d.ts +0 -9
  964. package/dist-lib/src/components/ui/input.story.d.ts +0 -9
  965. package/dist-lib/src/components/ui/label.story.d.ts +0 -9
  966. package/dist-lib/src/components/ui/menu-command.d.ts +0 -37
  967. package/dist-lib/src/components/ui/menu-command.story.d.ts +0 -7
  968. package/dist-lib/src/components/ui/otp-field.story.d.ts +0 -9
  969. package/dist-lib/src/components/ui/password-input.story.d.ts +0 -3
  970. package/dist-lib/src/components/ui/popover-glass.d.ts +0 -32
  971. package/dist-lib/src/components/ui/reference.story.d.ts +0 -10
  972. package/dist-lib/src/components/ui/select.d.ts +0 -30
  973. package/dist-lib/src/components/ui/separator.story.d.ts +0 -7
  974. package/dist-lib/src/components/ui/tabs.d.ts +0 -15
  975. package/dist-lib/src/components/ui/text.story.d.ts +0 -9
  976. package/dist-lib/src/components/ui/textarea.d.ts +0 -8
  977. package/dist-lib/src/components/ui/textarea.story.d.ts +0 -7
  978. package/dist-lib/src/components/ui/toast.d.ts +0 -15
  979. package/dist-lib/src/index.d.ts +0 -63
  980. package/dist-lib/src/lib/auth-accent.d.ts +0 -33
  981. package/dist-lib/src/lib/glass-variants.d.ts +0 -6
  982. package/dist-lib/src/lib/keyed-atom.d.ts +0 -14
  983. package/dist-lib/src/lib/segmented-control.d.ts +0 -8
  984. package/dist-lib/src/lib/state/exegia-provider.d.ts +0 -51
  985. package/dist-lib/src/lib/state/index.d.ts +0 -4
  986. package/dist-lib/src/lib/state/store.d.ts +0 -17
  987. package/src/components/blocks/auth/auth-flow-block.story.tsx +0 -17
  988. package/src/components/blocks/auth/auth-state-type.ts +0 -97
  989. package/src/components/blocks/auth/code-auth-block.story.tsx +0 -20
  990. package/src/components/blocks/auth/forgot-password-block.story.tsx +0 -14
  991. package/src/components/blocks/auth/linked-accounts-block.story.tsx +0 -23
  992. package/src/components/blocks/auth/login-block.story.tsx +0 -18
  993. package/src/components/blocks/auth/onboarding-block.story.tsx +0 -14
  994. package/src/components/blocks/auth/passkey-manager-block.story.tsx +0 -18
  995. package/src/components/blocks/auth/passkey-sign-in-block.story.tsx +0 -14
  996. package/src/components/blocks/auth/signup-block.story.tsx +0 -18
  997. package/src/components/blocks/auth/update-password-block.story.tsx +0 -14
  998. package/src/components/blocks/chat/base.story.tsx +0 -19
  999. package/src/components/blocks/chat/types.ts +0 -81
  1000. package/src/components/blocks/nav/sidebar/__tests__/ai-sidebar-atom.test.tsx +0 -325
  1001. package/src/components/blocks/nav/sidebar/__tests__/ai-sidebar.test.tsx +0 -93
  1002. package/src/components/blocks/nav/sidebar/__tests__/use-ai-sidebar.test.tsx +0 -310
  1003. package/src/components/blocks/nav/sidebar/ai-sidebar-atom.ts +0 -698
  1004. package/src/components/blocks/nav/sidebar/ai-sidebar.tsx +0 -150
  1005. package/src/components/blocks/nav/sidebar/index.ts +0 -67
  1006. package/src/components/blocks/nav/sidebar/sidebar-context.ts +0 -15
  1007. package/src/components/blocks/nav/sidebar/sidebar-icon.tsx +0 -14
  1008. package/src/components/blocks/nav/sidebar/sidebar-row.tsx +0 -378
  1009. package/src/components/blocks/nav/sidebar/type.ts +0 -294
  1010. package/src/components/blocks/nav/sidebar/use-ai-sidebar-state.ts +0 -123
  1011. package/src/components/blocks/nav/sidebar/use-ai-sidebar.ts +0 -619
  1012. package/src/components/blocks/nav/sidebar/utils.ts +0 -170
  1013. package/src/components/blocks/profile/profile-card-block.story.tsx +0 -18
  1014. package/src/components/blocks/scaffold/scaffold-root.story.tsx +0 -36
  1015. package/src/components/blocks/shell/shell-layout.story.tsx +0 -19
  1016. package/src/components/composed/attachment.story.tsx +0 -52
  1017. package/src/components/composed/chart.story.tsx +0 -46
  1018. package/src/components/composed/code-block.story.tsx +0 -29
  1019. package/src/components/composed/context-cards.story.tsx +0 -30
  1020. package/src/components/composed/emoji-action-bar.story.tsx +0 -20
  1021. package/src/components/composed/filter-table.story.tsx +0 -58
  1022. package/src/components/composed/flowchart.story.tsx +0 -24
  1023. package/src/components/composed/insight-cards.story.tsx +0 -51
  1024. package/src/components/composed/logo.story.tsx +0 -21
  1025. package/src/components/composed/markdown.story.tsx +0 -21
  1026. package/src/components/composed/password-input.story.tsx +0 -38
  1027. package/src/components/composed/recommendation-card.story.tsx +0 -32
  1028. package/src/components/composed/records-table.story.tsx +0 -46
  1029. package/src/components/composed/research-answer.story.tsx +0 -32
  1030. package/src/components/composed/social-providers.story.tsx +0 -24
  1031. package/src/components/composed/streaming-text.story.tsx +0 -24
  1032. package/src/components/composed/tree.story.tsx +0 -31
  1033. package/src/components/composed/user.story.tsx +0 -29
  1034. package/src/components/composed/verse.story.tsx +0 -21
  1035. package/src/components/ui/avatar.story.tsx +0 -33
  1036. package/src/components/ui/bubble.story.tsx +0 -45
  1037. package/src/components/ui/button.story.tsx +0 -62
  1038. package/src/components/ui/card.story.tsx +0 -36
  1039. package/src/components/ui/chat-atoms.story.tsx +0 -94
  1040. package/src/components/ui/checkbox.story.tsx +0 -30
  1041. package/src/components/ui/field.story.tsx +0 -32
  1042. package/src/components/ui/file-icons.story.tsx +0 -24
  1043. package/src/components/ui/frame.story.tsx +0 -32
  1044. package/src/components/ui/input-group.story.tsx +0 -27
  1045. package/src/components/ui/input.story.tsx +0 -42
  1046. package/src/components/ui/label.story.tsx +0 -32
  1047. package/src/components/ui/menu-command.story.tsx +0 -37
  1048. package/src/components/ui/otp-field.story.tsx +0 -35
  1049. package/src/components/ui/password-input.story.tsx +0 -19
  1050. package/src/components/ui/reference.story.tsx +0 -33
  1051. package/src/components/ui/separator.story.tsx +0 -34
  1052. package/src/components/ui/text.story.tsx +0 -31
  1053. package/src/components/ui/textarea.story.tsx +0 -34
  1054. /package/dist-lib/{src/components → components}/atoms/_layout.d.ts +0 -0
  1055. /package/dist-lib/{src/components → components}/atoms/avatar/verified.d.ts +0 -0
  1056. /package/dist-lib/{src/components → components}/atoms/background/index.d.ts +0 -0
  1057. /package/dist-lib/{src/components → components}/atoms/bubble/__tests__/bubble.test.d.ts +0 -0
  1058. /package/dist-lib/{src/components → components}/atoms/bubble/__tests__/reference.test.d.ts +0 -0
  1059. /package/dist-lib/{src/components → components}/atoms/chip.d.ts +0 -0
  1060. /package/dist-lib/{src/components → components}/atoms/text/__tests__/text.test.d.ts +0 -0
  1061. /package/dist-lib/{src/components → components}/atoms/text-selection/__tests__/click-popover.test.d.ts +0 -0
  1062. /package/dist-lib/{src/components → components}/atoms/text-selection/__tests__/text-selection.test.d.ts +0 -0
  1063. /package/dist-lib/{src/components → components}/blocks/auth/__tests__/auth-flow-block.test.d.ts +0 -0
  1064. /package/dist-lib/{src/components → components}/blocks/auth/__tests__/auth-state-atom.test.d.ts +0 -0
  1065. /package/dist-lib/{src/components → components}/blocks/auth/__tests__/linked-accounts-block.test.d.ts +0 -0
  1066. /package/dist-lib/{src/components → components}/blocks/auth/__tests__/onboarding-block.test.d.ts +0 -0
  1067. /package/dist-lib/{src/components → components}/blocks/auth/__tests__/passkey-manager-block.test.d.ts +0 -0
  1068. /package/dist-lib/{src/components → components}/blocks/auth/__tests__/passkey-sign-in-block.test.d.ts +0 -0
  1069. /package/dist-lib/{src/components → components}/blocks/auth/__tests__/signup-block.test.d.ts +0 -0
  1070. /package/dist-lib/{src/components → components}/blocks/auth/__tests__/update-password-block.test.d.ts +0 -0
  1071. /package/dist-lib/{src/components → components}/blocks/chat/__tests__/ai-panel.test.d.ts +0 -0
  1072. /package/dist-lib/{src/components → components}/blocks/chat/shared.d.ts +0 -0
  1073. /package/dist-lib/{src/components → components}/blocks/profile/__tests__/profile-card-block.test.d.ts +0 -0
  1074. /package/dist-lib/{src/components → components}/blocks/scaffold/__tests__/scaffold-atom.test.d.ts +0 -0
  1075. /package/dist-lib/{src/components → components}/blocks/scaffold/__tests__/scaffold.test.d.ts +0 -0
  1076. /package/dist-lib/{src/components → components}/blocks/scaffold/constants.d.ts +0 -0
  1077. /package/dist-lib/{src/components → components}/blocks/shell/__tests__/shell-fit-atom.test.d.ts +0 -0
  1078. /package/dist-lib/{src/components → components}/blocks/shell/__tests__/shell-layout.test.d.ts +0 -0
  1079. /package/dist-lib/{src/components → components}/blocks/shell/__tests__/shell-metrics.test.d.ts +0 -0
  1080. /package/dist-lib/{src/components → components}/blocks/shell/index.d.ts +0 -0
  1081. /package/dist-lib/{src/components/blocks/nav → components/blocks}/sidebar/__tests__/ai-sidebar-atom.test.d.ts +0 -0
  1082. /package/dist-lib/{src/components/blocks/nav → components/blocks}/sidebar/__tests__/ai-sidebar.test.d.ts +0 -0
  1083. /package/dist-lib/{src/components/blocks/nav → components/blocks}/sidebar/__tests__/use-ai-sidebar.test.d.ts +0 -0
  1084. /package/dist-lib/{src/components/blocks/nav → components/blocks}/sidebar/marquee-label.d.ts +0 -0
  1085. /package/dist-lib/{src/components → components}/composed/__tests__/logo.test.d.ts +0 -0
  1086. /package/dist-lib/{src/components → components}/composed/action-bar/__tests__/action-bar.test.d.ts +0 -0
  1087. /package/dist-lib/{src/components → components}/composed/ai/__tests__/ai.test.d.ts +0 -0
  1088. /package/dist-lib/{src/components → components}/composed/ai/avatar.d.ts +0 -0
  1089. /package/dist-lib/{src/components → components}/composed/ai/shared.d.ts +0 -0
  1090. /package/dist-lib/{src/components → components}/composed/chat/__tests__/attachment.test.d.ts +0 -0
  1091. /package/dist-lib/{src/components → components}/composed/chat/__tests__/beautiful-ui.test.d.ts +0 -0
  1092. /package/dist-lib/{src/components → components}/composed/chat/__tests__/chart.test.d.ts +0 -0
  1093. /package/dist-lib/{src/components → components}/composed/chat/__tests__/code-block.test.d.ts +0 -0
  1094. /package/dist-lib/{src/components → components}/composed/chat/__tests__/composer-attachments.test.d.ts +0 -0
  1095. /package/dist-lib/{src/components → components}/composed/chat/__tests__/composer.test.d.ts +0 -0
  1096. /package/dist-lib/{src/components → components}/composed/chat/__tests__/flowchart.test.d.ts +0 -0
  1097. /package/dist-lib/{src/components/composed/chat/__tests__/markdown.test.d.ts → components/composed/chat/__tests__/glass-material.test.d.ts} +0 -0
  1098. /package/dist-lib/{src/components/composed/tree/__tests__/tree-atom.test.d.ts → components/composed/chat/__tests__/markdown.test.d.ts} +0 -0
  1099. /package/dist-lib/{src/components/composed/tree/__tests__/tree.test.d.ts → components/composed/chat/__tests__/menu-command.test.d.ts} +0 -0
  1100. /package/dist-lib/{src/components/composed/tree/__tests__/use-tree.test.d.ts → components/composed/chat/__tests__/recommendation.test.d.ts} +0 -0
  1101. /package/dist-lib/{src/components → components}/composed/chat/actions.d.ts +0 -0
  1102. /package/dist-lib/{src/components → components}/composed/chat/composer/index.d.ts +0 -0
  1103. /package/dist-lib/{src/components → components}/composed/chat/flowchart/constant.d.ts +0 -0
  1104. /package/dist-lib/{src/components → components}/composed/chat/flowchart/index.d.ts +0 -0
  1105. /package/dist-lib/{src/components → components}/composed/chat/hint.d.ts +0 -0
  1106. /package/dist-lib/{src/components → components}/composed/reader/index.d.ts +0 -0
  1107. /package/dist-lib/{src/components/composed/user/utils.d.ts → components/composed/tree/__tests__/tree-atom.test.d.ts} +0 -0
  1108. /package/dist-lib/{src/components/composed/verse/__tests__/verse.test.d.ts → components/composed/tree/__tests__/tree.test.d.ts} +0 -0
  1109. /package/dist-lib/{src/components/icons/__tests__/icons.test.d.ts → components/composed/tree/__tests__/use-tree.test.d.ts} +0 -0
  1110. /package/dist-lib/{src/components → components}/composed/tree/constants.d.ts +0 -0
  1111. /package/dist-lib/{src/components/motion/index.d.ts → components/composed/user/__tests__/message.test.d.ts} +0 -0
  1112. /package/dist-lib/{src/components/ui/chat/__tests__/segmented-toggle.test.d.ts → components/composed/user/utils.d.ts} +0 -0
  1113. /package/dist-lib/{src/lib/utils.test.d.ts → components/composed/verse/__tests__/verse.test.d.ts} +0 -0
  1114. /package/dist-lib/{src/components → components}/docs/code-block.d.ts +0 -0
  1115. /package/dist-lib/{src/components → components}/docs/hero.d.ts +0 -0
  1116. /package/dist-lib/{src/components → components}/docs/mermaid.d.ts +0 -0
  1117. /package/dist-lib/{src/components → components}/ui/accordion.d.ts +0 -0
  1118. /package/dist-lib/{src/components → components}/ui/alert-dialog.d.ts +0 -0
  1119. /package/dist-lib/{src/components → components}/ui/alert.d.ts +0 -0
  1120. /package/dist-lib/{src/components → components}/ui/autocomplete.d.ts +0 -0
  1121. /package/dist-lib/{src/components → components}/ui/avatar.d.ts +0 -0
  1122. /package/dist-lib/{src/components → components}/ui/button-group.d.ts +0 -0
  1123. /package/dist-lib/{src/components → components}/ui/card.d.ts +0 -0
  1124. /package/dist-lib/{src/components → components}/ui/checkbox.d.ts +0 -0
  1125. /package/dist-lib/{src/components → components}/ui/collapsible.d.ts +0 -0
  1126. /package/dist-lib/{src/components → components}/ui/command.d.ts +0 -0
  1127. /package/dist-lib/{src/components → components}/ui/context-menu.d.ts +0 -0
  1128. /package/dist-lib/{src/components → components}/ui/emoji-picker.d.ts +0 -0
  1129. /package/dist-lib/{src/components → components}/ui/field.d.ts +0 -0
  1130. /package/dist-lib/{src/components → components}/ui/frame.d.ts +0 -0
  1131. /package/dist-lib/{src/components → components}/ui/group.d.ts +0 -0
  1132. /package/dist-lib/{src/components → components}/ui/kbd.d.ts +0 -0
  1133. /package/dist-lib/{src/components → components}/ui/label.d.ts +0 -0
  1134. /package/dist-lib/{src/components → components}/ui/menu.d.ts +0 -0
  1135. /package/dist-lib/{src/components → components}/ui/otp-field.d.ts +0 -0
  1136. /package/dist-lib/{src/components → components}/ui/popover.d.ts +0 -0
  1137. /package/dist-lib/{src/components → components}/ui/preview-card.d.ts +0 -0
  1138. /package/dist-lib/{src/components → components}/ui/scroll-area.d.ts +0 -0
  1139. /package/dist-lib/{src/components → components}/ui/separator.d.ts +0 -0
  1140. /package/dist-lib/{src/components → components}/ui/sheet.d.ts +0 -0
  1141. /package/dist-lib/{src/components → components}/ui/skeleton.d.ts +0 -0
  1142. /package/dist-lib/{src/components → components}/ui/spinner.d.ts +0 -0
  1143. /package/dist-lib/{src/components → components}/ui/switch.d.ts +0 -0
  1144. /package/dist-lib/{src/components → components}/ui/toolbar.d.ts +0 -0
  1145. /package/dist-lib/{src/components → components}/ui/tooltip.d.ts +0 -0
  1146. /package/dist-lib/{src/lib → lib}/ease.d.ts +0 -0
  1147. /package/dist-lib/{src/lib → lib}/hooks/use-hover-capable.d.ts +0 -0
  1148. /package/dist-lib/{src/lib → lib}/hooks/use-mobile.d.ts +0 -0
  1149. /package/dist-lib/{src/lib → lib}/sound.d.ts +0 -0
  1150. /package/dist-lib/{src/lib → lib}/utils.d.ts +0 -0
  1151. /package/src/components/blocks/{nav/sidebar → sidebar}/marquee-label.tsx +0 -0
@@ -0,0 +1,2358 @@
1
+ "use client";
2
+
3
+ import {
4
+ DEFAULT_ECHARTS_RENDERER,
5
+ buildChartCss,
6
+ flattenColor,
7
+ getColorsCount,
8
+ resolveColors,
9
+ seriesPaint,
10
+ withAlpha,
11
+ type ChartConfig,
12
+ type EChartsRenderer,
13
+ type ResolvedColors,
14
+ } from "./echarts-chart";
15
+ import {
16
+ tooltipBaseOption,
17
+ tooltipIndicatorHtml,
18
+ tooltipRow,
19
+ tooltipShell,
20
+ type TooltipPosition,
21
+ type TooltipRoundness,
22
+ type TooltipVariant,
23
+ } from "./echarts-tooltip";
24
+ import {
25
+ Brush,
26
+ buildBrushDataZoom,
27
+ syncBrushOverlay,
28
+ type BrushGeometry,
29
+ type BrushOverlayElements,
30
+ type BrushProps,
31
+ type BrushRange,
32
+ } from "./echarts-brush";
33
+ import {
34
+ DataZoomComponent,
35
+ GridComponent,
36
+ TooltipComponent,
37
+ type DataZoomComponentOption,
38
+ type GridComponentOption,
39
+ type TooltipComponentOption,
40
+ } from "echarts/components";
41
+ import {
42
+ Children,
43
+ isValidElement,
44
+ useCallback,
45
+ useEffect,
46
+ useId,
47
+ useMemo,
48
+ useRef,
49
+ useState,
50
+ type CSSProperties,
51
+ type FC,
52
+ type ReactNode,
53
+ } from "react";
54
+ import { dotItemStyle, dotStyle, sampleGradient, type DotVariant } from "./echarts-dot";
55
+ import { LegendOverlay, type LegendVariant } from "./echarts-legend";
56
+ import type { ComposeOption, ImagePatternObject } from "echarts/core";
57
+ import { LineChart, type LineSeriesOption } from "echarts/charts";
58
+ import { motion, useReducedMotion } from "motion/react";
59
+ import * as echarts from "echarts/core";
60
+
61
+ // Re-export the shared types that were previously declared inline here, so
62
+ // existing consumers/examples keep importing them from the chart module.
63
+ export type {
64
+ ChartConfig,
65
+ DotVariant,
66
+ EChartsRenderer,
67
+ LegendVariant,
68
+ TooltipPosition,
69
+ TooltipRoundness,
70
+ TooltipVariant,
71
+ };
72
+
73
+ // Modular registration keeps the bundle lean — only the pieces this chart needs.
74
+ // `DataZoomComponent` bundles both the slider (brush footer) and inside (wheel/drag)
75
+ // zoom. The brush's frame/handles/labels are raw zrender elements, not the
76
+ // graphic component — see syncBrushOverlay.
77
+ echarts.use([LineChart, GridComponent, TooltipComponent, DataZoomComponent]);
78
+
79
+ type EChartsInstance = ReturnType<typeof echarts.init>;
80
+
81
+ // The exact option surface this chart uses — line series, grid, tooltip, and
82
+ // dataZoom, plus the axis options they pull in as dependencies. Narrower than
83
+ // echarts' full EChartsOption, so a misspelled key fails the compile instead of
84
+ // silently reaching setOption.
85
+ type EChartsOption = ComposeOption<
86
+ LineSeriesOption | GridComponentOption | TooltipComponentOption | DataZoomComponentOption
87
+ >;
88
+
89
+ // Single-entry views of the composed option's array-or-single fields — the
90
+ // modular entry points don't export the axis option types directly.
91
+ type ArrayItem<T> = T extends readonly (infer U)[] ? U : T;
92
+ type XAxisOption = ArrayItem<NonNullable<EChartsOption["xAxis"]>>;
93
+ type YAxisOption = ArrayItem<NonNullable<EChartsOption["yAxis"]>>;
94
+
95
+ // ─────────────────────────────────────────────────────────────────────────────
96
+ // Constants
97
+ // ─────────────────────────────────────────────────────────────────────────────
98
+
99
+ const STROKE_WIDTH = 0.8; // default series stroke — <Area strokeWidth> overrides it
100
+ const LOADING_ANIMATION_DURATION = 2000; // shimmer loop, in milliseconds
101
+ const REVEAL_DURATION = 1000; // intro draw-in length, in milliseconds
102
+ // NOTE: the intro draw-in runs ECharts' RAW default entrance animation. Custom
103
+ // easing was tried and abandoned — ECharts hardcodes the line-entrance clip to
104
+ // linear and ignores animationEasing at every level (verified empirically).
105
+ const LOADING_DEFAULT_POINTS = 14;
106
+ // Buffer line: the last segment's stroke renders as this dash while the rest of
107
+ // the area stays solid, echoing the Recharts twin's 4px dash / 3px gap forecast
108
+ // tail. Ported from the line-chart twin.
109
+ const BUFFER_DASH: [number, number] = [4, 3];
110
+
111
+ // ─────────────────────────────────────────────────────────────────────────────
112
+ // Theme knobs — every neutral line in the chart draws from these. Base colors
113
+ // come from the consumer's CSS tokens (resolved from the live DOM), so only the
114
+ // opacity factors live here. Factors MULTIPLY the token's own alpha — a border
115
+ // token that is already 10%-white stays subtle. Tune here, not in the builder.
116
+ // ─────────────────────────────────────────────────────────────────────────────
117
+ // Recharts draws its grid at border/50, but SVG dashes render pixel-crisp while
118
+ // canvas at 2× DPR spreads a 1px line across device pixels — roughly halving
119
+ // perceived intensity. Using the border token's full alpha lands both engines at
120
+ // the same apparent brightness.
121
+ const GRID_LINE_OPACITY = 1; // dashed y-axis split lines, × border alpha
122
+ const AXIS_POINTER_OPACITY = 1; // tooltip cursor line, × border alpha
123
+ // The skeleton is CLIPPED to a small sweeping window — only the wave section
124
+ // inside it exists (stroke + fill), everything outside is fully transparent,
125
+ // like a clip-path sliding across the chart.
126
+ const LOADING_STROKE_OPACITY = 0.5; // outline inside the window, × foreground alpha
127
+ const LOADING_SHIMMER_MAX_OPACITY = 0.03; // fill inside the window, × foreground alpha
128
+ const LOADING_SHIMMER_BAND = 0.2; // window half-width, fraction of chart width
129
+ const LOADING_SHIMMER_FEATHER = 0.2; // eased edge softening of the clip window
130
+ const BRUSH_STROKE_OPACITY = 0.5; // mini-chart series stroke
131
+ const BRUSH_FILL_OPACITY = 0.15; // mini-chart series fade, at the top stop
132
+ const BRUSH_FILLER_OPACITY = 0; // selected-range wash — evil-brush draws none
133
+
134
+ // ─────────────────────────────────────────────────────────────────────────────
135
+ // Public types
136
+ // ─────────────────────────────────────────────────────────────────────────────
137
+
138
+ export type AreaVariant =
139
+ | "gradient"
140
+ | "gradient-reverse"
141
+ | "solid"
142
+ | "dotted"
143
+ | "lines"
144
+ | "hatched"
145
+ | "none"; // stroke only — no fill at all
146
+ export type StrokeVariant = "solid" | "dashed" | "animated-dashed";
147
+ export type StackType = "default" | "stacked" | "expanded";
148
+ export type AreaAnimationType =
149
+ | "none"
150
+ | "left-to-right"
151
+ | "right-to-left"
152
+ | "center-out"
153
+ | "edges-in";
154
+ export type CurveType =
155
+ | "linear"
156
+ | "smooth"
157
+ | "bump"
158
+ | "monotone"
159
+ | "monotoneX"
160
+ | "monotoneY"
161
+ | "natural"
162
+ | "step";
163
+ // DotVariant, TooltipVariant, TooltipRoundness, LegendVariant, and ChartConfig
164
+ // now live in the shared ./echarts/* modules and are imported +
165
+ // re-exported at the top of this file.
166
+
167
+ export interface EChartsAreaChartProps<TData extends Record<string, unknown>> {
168
+ data: TData[]; // rows rendered by the chart
169
+ config: ChartConfig; // series colors + labels
170
+ renderer?: EChartsRenderer; // rendering engine — defaults to canvas
171
+ xDataKey?: keyof TData & string; // x category key — falls back to the <XAxis> dataKey / first free column
172
+ className?: string; // extra classes for the chart container
173
+ curveType?: CurveType; // default curve interpolation each <Area> inherits
174
+ stackType?: StackType; // how multiple areas combine
175
+ animation?: boolean; // master switch for the intro draw-in — false renders instantly
176
+ animationType?: AreaAnimationType; // default intro reveal (first <Area> overrides)
177
+ enableHoverHighlight?: boolean; // hovering a series dims the others, like a temporary selection
178
+ enableHoverReveal?: boolean; // hovering colors each area up to the pointer's x and mutes the rest
179
+ defaultSelectedDataKey?: string | null; // series selected on first render
180
+ selectedDataKey?: string | null; // controlled selection — overrides internal state when set
181
+ onSelectionChange?: (key: string | null) => void; // fires when the selected series changes
182
+ isLoading?: boolean; // shows the animated loading skeleton
183
+ loadingPoints?: number; // number of points in the loading skeleton
184
+ chartOptions?: Record<string, unknown>; // escape hatch merged over the built ECharts option
185
+ children?: ReactNode; // declarative config — <Area>, <XAxis>, <Grid>, <Tooltip>, <Legend>, <Brush>, …
186
+ }
187
+
188
+ // ─────────────────────────────────────────────────────────────────────────────
189
+ // Composible parts — DECLARATIVE CONFIG. Every part renders `null`; the root
190
+ // walks `children` by reference (child.type === Area, …) to collect its props.
191
+ // Presence semantics mirror the Recharts twin: omit a child and that part does
192
+ // not render. These are never mounted into the tree — they only carry props.
193
+ // ─────────────────────────────────────────────────────────────────────────────
194
+
195
+ export interface AreaProps {
196
+ dataKey: string; // series key — must exist on the data + config
197
+ variant?: AreaVariant; // fill style for this area only
198
+ strokeVariant?: StrokeVariant; // stroke style for this area
199
+ strokeWidth?: number; // stroke thickness in pixels for this area
200
+ curveType?: CurveType; // curve interpolation — falls back to the root curveType
201
+ animationType?: AreaAnimationType; // intro reveal — first area drives the wrapper wipe
202
+ connectNulls?: boolean; // join segments across null/missing values
203
+ isClickable?: boolean; // lets this area be selected by clicking it
204
+ enableBufferLine?: boolean; // renders this area's last segment as a dashed, fill-less buffer
205
+ children?: ReactNode; // optional <Dot> and <ActiveDot> config
206
+ }
207
+
208
+ /**
209
+ * A single area series. Declares its own fill/stroke/curve/clickability and,
210
+ * optionally, resting/active point markers via composed <Dot> / <ActiveDot>.
211
+ * Renders nothing — the root reads these props to build the ECharts series.
212
+ */
213
+ const Area: FC<AreaProps> = () => null;
214
+
215
+ export interface DotProps {
216
+ variant?: DotVariant; // visual style of the point marker
217
+ }
218
+
219
+ /** Declares the resting point marker for the enclosing <Area>. Renders nothing. */
220
+ const Dot: FC<DotProps> = () => null;
221
+
222
+ /** Declares the hovered/active point marker for the enclosing <Area>. Renders nothing. */
223
+ const ActiveDot: FC<DotProps> = () => null;
224
+
225
+ export interface XAxisProps {
226
+ dataKey?: string; // x category key — overrides the root xDataKey
227
+ // Category-axis values are always stringified, so the formatter sees a string —
228
+ // letting examples share `(value) => value.substring(0, 3)` with the Recharts twin.
229
+ tickFormatter?: (value: string, index: number) => string; // formats x tick labels
230
+ label?: string; // axis title, centered below the tick labels
231
+ hideDots?: boolean; // hides the tick dots beside this axis's labels
232
+ }
233
+
234
+ /** Presence shows the x-axis category labels. Renders nothing. */
235
+ const XAxis: FC<XAxisProps> = () => null;
236
+
237
+ export interface YAxisProps {
238
+ dataKey?: string; // reserved for parity with the Recharts twin
239
+ tickFormatter?: (value: number, index: number) => string; // formats y tick labels
240
+ label?: string; // axis title, rotated alongside the tick labels
241
+ hideDots?: boolean; // hides the tick dots beside this axis's labels
242
+ }
243
+
244
+ /** Presence shows the y value axis. Renders nothing. */
245
+ const YAxis: FC<YAxisProps> = () => null;
246
+
247
+ /** Presence shows the dashed horizontal split lines. Renders nothing. */
248
+ const Grid: FC = () => null;
249
+
250
+ export interface TooltipProps {
251
+ variant?: TooltipVariant; // visual style of the tooltip surface
252
+ roundness?: TooltipRoundness; // border-radius of the tooltip
253
+ cursor?: boolean; // whether the vertical cursor line follows the pointer
254
+ position?: TooltipPosition; // "variable" follows both axes (default); "fixed" pins the tooltip near the top and tracks the pointer's X
255
+ }
256
+
257
+ /** Presence enables the hover tooltip. Renders nothing. */
258
+ const Tooltip: FC<TooltipProps> = () => null;
259
+
260
+ export interface LegendProps {
261
+ variant?: LegendVariant; // visual style of the legend indicators
262
+ align?: "left" | "center" | "right"; // horizontal placement
263
+ verticalAlign?: "top" | "middle" | "bottom"; // vertical placement
264
+ isClickable?: boolean; // lets each entry toggle selection of its series
265
+ }
266
+
267
+ /** Presence enables the HTML legend overlay. Renders nothing. */
268
+ const Legend: FC<LegendProps> = () => null;
269
+
270
+ // ─────────────────────────────────────────────────────────────────────────────
271
+ // Children collection — walk the declarative config into plain objects the
272
+ // option builder consumes. <Dot> / <ActiveDot> are read from each <Area>'s own
273
+ // children; a missing dot child means that marker does not render.
274
+ // ─────────────────────────────────────────────────────────────────────────────
275
+
276
+ type AreaSeriesConfig = {
277
+ dataKey: string;
278
+ variant: AreaVariant;
279
+ strokeVariant: StrokeVariant;
280
+ strokeWidth: number;
281
+ curveType?: CurveType;
282
+ animationType?: AreaAnimationType;
283
+ connectNulls: boolean;
284
+ isClickable: boolean;
285
+ enableBufferLine: boolean;
286
+ dotVariant: DotVariant; // "none" when no <Dot> child is present
287
+ activeDotVariant: DotVariant; // "none" when no <ActiveDot> child is present
288
+ };
289
+
290
+ type XAxisSlot = {
291
+ present: boolean;
292
+ dataKey?: string;
293
+ tickFormatter?: (value: string, index: number) => string;
294
+ label?: string;
295
+ hideDots: boolean;
296
+ };
297
+ type YAxisSlot = {
298
+ present: boolean;
299
+ dataKey?: string;
300
+ tickFormatter?: (value: number, index: number) => string;
301
+ label?: string;
302
+ hideDots: boolean;
303
+ };
304
+ type TooltipSlot = {
305
+ present: boolean;
306
+ variant: TooltipVariant;
307
+ roundness: TooltipRoundness;
308
+ cursor: boolean;
309
+ position: TooltipPosition;
310
+ };
311
+ type LegendSlot = {
312
+ present: boolean;
313
+ variant: LegendVariant;
314
+ align: "left" | "center" | "right";
315
+ verticalAlign: "top" | "middle" | "bottom";
316
+ isClickable: boolean;
317
+ };
318
+ type BrushSlot = {
319
+ present: boolean; // a <Brush> child was passed — replaces the old showBrush prop
320
+ height?: number;
321
+ formatLabel?: (value: string, index: number) => string;
322
+ onChange?: (range: { startIndex: number; endIndex: number }) => void;
323
+ };
324
+
325
+ type CollectedConfig = {
326
+ areas: AreaSeriesConfig[];
327
+ xAxis: XAxisSlot;
328
+ yAxis: YAxisSlot;
329
+ showGrid: boolean;
330
+ tooltip: TooltipSlot;
331
+ legend: LegendSlot;
332
+ brush: BrushSlot;
333
+ };
334
+
335
+ function collectConfig(children: ReactNode): CollectedConfig {
336
+ const areas: AreaSeriesConfig[] = [];
337
+ let xAxis: XAxisSlot = { present: false, hideDots: false };
338
+ let yAxis: YAxisSlot = { present: false, hideDots: false };
339
+ let showGrid = false;
340
+ let tooltip: TooltipSlot = {
341
+ present: false,
342
+ variant: "default",
343
+ roundness: "lg",
344
+ cursor: true,
345
+ position: "variable",
346
+ };
347
+ let legend: LegendSlot = {
348
+ present: false,
349
+ variant: "rounded-square",
350
+ align: "right",
351
+ verticalAlign: "top",
352
+ isClickable: false,
353
+ };
354
+ let brush: BrushSlot = { present: false };
355
+
356
+ Children.forEach(children, (child) => {
357
+ if (!isValidElement(child)) return;
358
+ const type = child.type;
359
+
360
+ if (type === Area) {
361
+ const props = child.props as AreaProps;
362
+ let dotVariant: DotVariant = "none";
363
+ let activeDotVariant: DotVariant = "none";
364
+ Children.forEach(props.children, (dotChild) => {
365
+ if (!isValidElement(dotChild)) return;
366
+ if (dotChild.type === Dot) {
367
+ dotVariant = (dotChild.props as DotProps).variant ?? "default";
368
+ } else if (dotChild.type === ActiveDot) {
369
+ activeDotVariant = (dotChild.props as DotProps).variant ?? "default";
370
+ }
371
+ });
372
+ areas.push({
373
+ dataKey: props.dataKey,
374
+ variant: props.variant ?? "gradient",
375
+ strokeVariant: props.strokeVariant ?? "dashed",
376
+ strokeWidth: props.strokeWidth ?? STROKE_WIDTH,
377
+ curveType: props.curveType,
378
+ animationType: props.animationType,
379
+ connectNulls: props.connectNulls ?? false,
380
+ isClickable: props.isClickable ?? false,
381
+ enableBufferLine: props.enableBufferLine ?? false,
382
+ dotVariant,
383
+ activeDotVariant,
384
+ });
385
+ } else if (type === XAxis) {
386
+ const props = child.props as XAxisProps;
387
+ xAxis = {
388
+ present: true,
389
+ dataKey: props.dataKey,
390
+ tickFormatter: props.tickFormatter,
391
+ label: props.label,
392
+ hideDots: props.hideDots ?? false,
393
+ };
394
+ } else if (type === YAxis) {
395
+ const props = child.props as YAxisProps;
396
+ yAxis = {
397
+ present: true,
398
+ dataKey: props.dataKey,
399
+ tickFormatter: props.tickFormatter,
400
+ label: props.label,
401
+ hideDots: props.hideDots ?? false,
402
+ };
403
+ } else if (type === Grid) {
404
+ showGrid = true;
405
+ } else if (type === Tooltip) {
406
+ const props = child.props as TooltipProps;
407
+ tooltip = {
408
+ present: true,
409
+ variant: props.variant ?? "default",
410
+ roundness: props.roundness ?? "lg",
411
+ cursor: props.cursor ?? true,
412
+ position: props.position ?? "variable",
413
+ };
414
+ } else if (type === Legend) {
415
+ const props = child.props as LegendProps;
416
+ legend = {
417
+ present: true,
418
+ variant: props.variant ?? "rounded-square",
419
+ align: props.align ?? "right",
420
+ verticalAlign: props.verticalAlign ?? "top",
421
+ isClickable: props.isClickable ?? false,
422
+ };
423
+ } else if (type === Brush) {
424
+ const props = child.props as BrushProps;
425
+ brush = {
426
+ present: true,
427
+ height: props.height,
428
+ formatLabel: props.formatLabel,
429
+ onChange: props.onChange,
430
+ };
431
+ }
432
+ });
433
+
434
+ return { areas, xAxis, yAxis, showGrid, tooltip, legend, brush };
435
+ }
436
+
437
+ // Color plumbing (ChartConfig, getColorsCount, distributeColors, buildChartCss,
438
+ // normalizeColor, withAlpha, ResolvedColors, resolveColors, seriesPaint) now
439
+ // lives in ./echarts-chart and is imported at the top of this file.
440
+
441
+ // ─────────────────────────────────────────────────────────────────────────────
442
+ // Fill paints — the ECharts analogue of the Recharts fill variants (§1.1).
443
+ // The first three are alpha fades; the last three are tiling canvas patterns.
444
+ // ─────────────────────────────────────────────────────────────────────────────
445
+
446
+ // Tiling texture fills, tinted with the series' first color. Stripes are drawn
447
+ // STRAIGHT (trivially seamless) and the pattern itself is rotated — zrender
448
+ // applies pattern transforms the same way ECharts decals do. Baking a diagonal
449
+ // into a square tile clips the stroke at the corners, which reads as periodic
450
+ // gaps once tiled. Tiles render at devicePixelRatio and scale back down so the
451
+ // texture stays crisp on retina canvases.
452
+ function patternFill(
453
+ kind: "dotted" | "lines" | "hatched" | "stripe",
454
+ color: string,
455
+ ): ImagePatternObject | null {
456
+ if (typeof document === "undefined") return null;
457
+ const dpr = Math.max(window.devicePixelRatio || 1, 1);
458
+ const canvas = document.createElement("canvas");
459
+ const ctx = canvas.getContext("2d");
460
+ if (!ctx) return null;
461
+
462
+ const size = (width: number, height: number) => {
463
+ canvas.width = width * dpr;
464
+ canvas.height = height * dpr;
465
+ ctx.scale(dpr, dpr);
466
+ };
467
+ const pattern = (rotation = 0): ImagePatternObject => ({
468
+ image: canvas,
469
+ repeat: "repeat",
470
+ rotation,
471
+ scaleX: 1 / dpr,
472
+ scaleY: 1 / dpr,
473
+ });
474
+
475
+ if (kind === "dotted") {
476
+ size(6, 6);
477
+ // Slightly larger dots at 0.7 — the vertical fade + areaStyle opacity temper
478
+ // them, so at the old 0.5/r0.6 they washed out (especially on shorter areas).
479
+ ctx.fillStyle = withAlpha(color, 0.7);
480
+ ctx.beginPath();
481
+ ctx.arc(3, 3, 0.85, 0, Math.PI * 2);
482
+ ctx.fill();
483
+ return pattern();
484
+ }
485
+
486
+ if (kind === "lines" || kind === "stripe") {
487
+ // Vertical 1px line every 5px, rotated 45° by the pattern transform.
488
+ size(5, 5);
489
+ ctx.strokeStyle = withAlpha(color, 0.3);
490
+ ctx.lineWidth = 1;
491
+ ctx.beginPath();
492
+ ctx.moveTo(2.5, -1);
493
+ ctx.lineTo(2.5, 6);
494
+ ctx.stroke();
495
+ return pattern(-Math.PI / 4);
496
+ }
497
+
498
+ // hatched: bold two-tone stripes leaning ~20°, echoing the Recharts
499
+ // gradient-edged stripe fill.
500
+ size(20, 20);
501
+ ctx.fillStyle = withAlpha(color, 0.06);
502
+ ctx.fillRect(0, 0, 10, 20);
503
+ ctx.fillStyle = withAlpha(color, 0.22);
504
+ ctx.fillRect(10, 0, 10, 20);
505
+ return pattern((20 * Math.PI) / 180);
506
+ }
507
+
508
+ // Canvas can't express "multi-stop color horizontally × alpha fade vertically"
509
+ // as one gradient, so multi-color fills composite the two on an offscreen canvas
510
+ // sized to the chart: paint the horizontal color run, then mask it with a
511
+ // vertical alpha ramp via destination-in. Regenerated on resize (patterns anchor
512
+ // to the renderer's origin at natural pixel size).
513
+ function gradientFillTexture(
514
+ slots: string[],
515
+ width: number,
516
+ height: number,
517
+ reverse: boolean,
518
+ ): HTMLCanvasElement | null {
519
+ if (typeof document === "undefined" || width < 1 || height < 1) return null;
520
+
521
+ const canvas = document.createElement("canvas");
522
+ canvas.width = Math.ceil(width);
523
+ canvas.height = Math.ceil(height);
524
+ const ctx = canvas.getContext("2d");
525
+ if (!ctx) return null;
526
+
527
+ const colors = ctx.createLinearGradient(0, 0, canvas.width, 0);
528
+ slots.forEach((color, i) => colors.addColorStop(i / (slots.length - 1), color));
529
+ ctx.fillStyle = colors;
530
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
531
+
532
+ const fade = ctx.createLinearGradient(0, 0, 0, canvas.height);
533
+ fade.addColorStop(0, `rgba(0, 0, 0, ${reverse ? 0 : 0.1})`);
534
+ fade.addColorStop(1, `rgba(0, 0, 0, ${reverse ? 0.1 : 0})`);
535
+ ctx.globalCompositeOperation = "destination-in";
536
+ ctx.fillStyle = fade;
537
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
538
+
539
+ return canvas;
540
+ }
541
+
542
+ // A pattern fill (dotted/lines/hatched) faded vertically — opaque at the top
543
+ // (near the line), transparent toward the baseline — so it reads like the
544
+ // gradient variant instead of a flat wall of pattern. The tiling pattern can't
545
+ // itself carry an alpha ramp, so bake it into a plot-sized texture: tile the
546
+ // pattern (reusing patternFill's tile + rotation), then mask it with a vertical
547
+ // alpha ramp via destination-in.
548
+ function patternFadeTexture(
549
+ kind: "dotted" | "lines" | "hatched",
550
+ color: string,
551
+ width: number,
552
+ height: number,
553
+ ): HTMLCanvasElement | null {
554
+ const patternObj = patternFill(kind, color);
555
+ if (!patternObj || typeof document === "undefined" || width < 1 || height < 1) return null;
556
+ const tile = patternObj.image;
557
+ if (!(tile instanceof HTMLCanvasElement)) return null;
558
+ const rotation = patternObj.rotation ?? 0;
559
+ const tileScale = patternObj.scaleX ?? 1; // patternFill draws the tile at dpr; 1/dpr scales it back
560
+
561
+ const w = Math.ceil(width);
562
+ const h = Math.ceil(height);
563
+ const canvas = document.createElement("canvas");
564
+ canvas.width = w;
565
+ canvas.height = h;
566
+ const ctx = canvas.getContext("2d");
567
+ if (!ctx) return null;
568
+
569
+ const pat = ctx.createPattern(tile, "repeat");
570
+ if (!pat) return null;
571
+ // Replicate the ECharts ImagePattern transform (rotate the tiling, scale the
572
+ // dpr tile back to CSS size) so the baked texture matches the plain pattern.
573
+ if (typeof pat.setTransform === "function") {
574
+ const m = new DOMMatrix();
575
+ m.rotateSelf((rotation * 180) / Math.PI);
576
+ m.scaleSelf(tileScale, tileScale);
577
+ pat.setTransform(m);
578
+ }
579
+ ctx.fillStyle = pat;
580
+ ctx.fillRect(0, 0, w, h);
581
+
582
+ const fade = ctx.createLinearGradient(0, 0, 0, h);
583
+ fade.addColorStop(0, "rgba(0, 0, 0, 1)"); // top: keep the pattern
584
+ fade.addColorStop(1, "rgba(0, 0, 0, 0)"); // baseline: fade it out
585
+ ctx.globalCompositeOperation = "destination-in";
586
+ ctx.fillStyle = fade;
587
+ ctx.fillRect(0, 0, w, h);
588
+
589
+ return canvas;
590
+ }
591
+
592
+ // Resolves the area fill for a variant into an ECharts color value. `size` is the
593
+ // full renderer size, used to bake 2D gradients for multi-color series.
594
+ function fillPaint(
595
+ variant: AreaVariant,
596
+ showUnselected: boolean,
597
+ slots: string[],
598
+ size: { width: number; height: number },
599
+ ): string | echarts.graphic.LinearGradient | ImagePatternObject {
600
+ const base = slots[0] ?? "rgba(120, 120, 120, 1)";
601
+ const multi = slots.length > 1;
602
+
603
+ // "none" — stroke only, no fill (even when unselected).
604
+ if (variant === "none") return "transparent";
605
+
606
+ // A non-selected area in a clickable chart recedes as a 45° stripe texture.
607
+ if (showUnselected) {
608
+ return patternFill("stripe", base) ?? withAlpha(base, 0.1);
609
+ }
610
+
611
+ switch (variant) {
612
+ case "gradient":
613
+ case "gradient-reverse": {
614
+ const reverse = variant === "gradient-reverse";
615
+ if (multi) {
616
+ const texture = gradientFillTexture(slots, size.width, size.height, reverse);
617
+ if (texture) return { image: texture, repeat: "no-repeat" };
618
+ }
619
+ return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
620
+ { offset: 0, color: withAlpha(base, reverse ? 0 : 0.1) },
621
+ { offset: 1, color: withAlpha(base, reverse ? 0.1 : 0) },
622
+ ]);
623
+ }
624
+ case "solid": {
625
+ // Uniform alpha, so the horizontal color run survives as one gradient.
626
+ if (multi) {
627
+ return new echarts.graphic.LinearGradient(
628
+ 0,
629
+ 0,
630
+ 1,
631
+ 0,
632
+ slots.map((color, i) => ({
633
+ offset: i / (slots.length - 1),
634
+ color: withAlpha(color, 0.1),
635
+ })),
636
+ );
637
+ }
638
+ return withAlpha(base, 0.1);
639
+ }
640
+ case "dotted":
641
+ case "lines":
642
+ case "hatched": {
643
+ // Faded by default (opaque near the line, transparent at the baseline).
644
+ const texture = patternFadeTexture(variant, base, size.width, size.height);
645
+ if (texture) return { image: texture, repeat: "no-repeat" };
646
+ return patternFill(variant, base) ?? withAlpha(base, 0.1);
647
+ }
648
+ default:
649
+ return withAlpha(base, 0.1);
650
+ }
651
+ }
652
+
653
+ // ─────────────────────────────────────────────────────────────────────────────
654
+ // Curve mapping — linear → straight, step → step:"end", everything else → smooth.
655
+ // ─────────────────────────────────────────────────────────────────────────────
656
+
657
+ function curveConfig(curveType: CurveType): { smooth: boolean; step: "middle" | false } {
658
+ // Recharts "step" is d3's curveStep: the transition happens at the MIDPOINT
659
+ // between points, so each dot sits centered on its plateau.
660
+ if (curveType === "step") return { smooth: false, step: "middle" };
661
+ if (curveType === "linear") return { smooth: false, step: false };
662
+ return { smooth: true, step: false };
663
+ }
664
+
665
+ // ─────────────────────────────────────────────────────────────────────────────
666
+ // Selection opacities (§4.3) — dims a series only when another one is selected.
667
+ // ─────────────────────────────────────────────────────────────────────────────
668
+
669
+ function getOpacity(selected: string | null, key: string) {
670
+ if (selected === null || selected === key) return { fill: 0.8, stroke: 1, dot: 1 };
671
+ return { fill: 0.1, stroke: 0.3, dot: 0.3 };
672
+ }
673
+
674
+ // ─────────────────────────────────────────────────────────────────────────────
675
+ // Loading skeleton helpers
676
+ // ─────────────────────────────────────────────────────────────────────────────
677
+
678
+ // Skeleton data as a smooth random walk in a comfortable band — reads like a
679
+ // resting chart instead of raw noise spikes.
680
+ function getLoadingData(points: number): number[] {
681
+ const rows: number[] = [];
682
+ let value = 30 + Math.random() * 20;
683
+ for (let i = 0; i < points; i++) {
684
+ value = Math.min(58, Math.max(16, value + (Math.random() - 0.5) * 16));
685
+ rows.push(Math.round(value));
686
+ }
687
+ return rows;
688
+ }
689
+
690
+ // Gradient stops forming a hard clip window around `center`: full `peak` alpha
691
+ // inside, zero outside, with a small feather so the edge isn't aliased.
692
+ // `center` may run outside [0, 1] so the window fully enters and exits the frame.
693
+ function shimmerWindowStops(center: number, color: string, peak: number) {
694
+ const half = LOADING_SHIMMER_BAND;
695
+ const feather = LOADING_SHIMMER_FEATHER;
696
+
697
+ const alphaAt = (x: number) => {
698
+ const dist = Math.abs(x - center);
699
+ if (dist <= half - feather) return peak;
700
+ if (dist >= half) return 0;
701
+ // Sine-eased falloff — a linear ramp still reads as a hard cut.
702
+ return peak * Math.sin(((1 - (dist - (half - feather)) / feather) * Math.PI) / 2);
703
+ };
704
+
705
+ const offsets = [
706
+ 0,
707
+ center - half,
708
+ center - half + feather,
709
+ center,
710
+ center + half - feather,
711
+ center + half,
712
+ 1,
713
+ ]
714
+ .filter((x) => x >= 0 && x <= 1)
715
+ .sort((a, b) => a - b);
716
+
717
+ const stops: { offset: number; color: string }[] = [];
718
+ for (const offset of offsets) {
719
+ if (stops.length === 0 || offset - stops[stops.length - 1].offset > 1e-4) {
720
+ stops.push({ offset, color: withAlpha(color, alphaAt(offset)) });
721
+ }
722
+ }
723
+ return stops;
724
+ }
725
+
726
+ // The `__buffer-` prefix marks the dashed forecast overlay of a buffer area; it
727
+ // carries the SAME key's value, so the tooltip recovers the key from it (see
728
+ // createTooltipFormatter). Every other `__`-prefixed series (mini chart, loading
729
+ // skeleton, hover-reveal base) is truly internal and never surfaces.
730
+ const BUFFER_PREFIX = "__buffer-";
731
+ // The fill-only patch under a buffer area's dashed tail (the main area's fill
732
+ // stops one point early). Internal, so the tooltip drops it.
733
+ const BUFFERFILL_PREFIX = "__bufferfill-";
734
+ // The `__reveal-` prefix marks the muted base layer of a hover-reveal area — see
735
+ // buildAreaSeries. Internal, so the tooltip drops it like the mini/loading rows.
736
+ const REVEAL_PREFIX = "__reveal-";
737
+
738
+ // ─────────────────────────────────────────────────────────────────────────────
739
+ // Option builders — pure functions from a snapshot context to ECharts option
740
+ // fragments. The component reads its refs and renderer size ONCE per build into
741
+ // this context; nothing below touches React state or the chart instance, so
742
+ // each fragment can be reasoned about (and tested) in isolation.
743
+ // ─────────────────────────────────────────────────────────────────────────────
744
+
745
+ type OptionBuildContext = {
746
+ data: Record<string, unknown>[];
747
+ config: ChartConfig;
748
+ areas: AreaSeriesConfig[];
749
+ seriesKeys: string[];
750
+ curveType: CurveType;
751
+ isStacked: boolean;
752
+ isExpanded: boolean;
753
+ selectedDataKey: string | null;
754
+ hasSelection: boolean;
755
+ showGrid: boolean;
756
+ xAxisSlot: XAxisSlot;
757
+ yAxisSlot: YAxisSlot;
758
+ tooltipSlot: TooltipSlot;
759
+ legendSlot: LegendSlot;
760
+ isLoading: boolean;
761
+ loadingData: () => number[];
762
+ showBrush: boolean;
763
+ brushHeight: number;
764
+ enableHoverHighlight: boolean;
765
+ enableHoverReveal: boolean; // hover colors each area up to the pointer, mutes the rest
766
+ revealIndex: number | null; // pointer's x-index while revealing (null = idle → chart looks normal)
767
+ revealSink: Record<string, unknown[]>; // buildAreaSeries writes each area's full per-datum points here for the hover handler
768
+ resolved: ResolvedColors;
769
+ rendererSize: { width: number; height: number }; // 2D gradient textures bake at renderer size
770
+ categories: string[];
771
+ brushRange: BrushRange; // zoom window carried through rebuilds
772
+ getHoveredKey: () => string | null; // read per tooltip render — hover never repushes the option
773
+ };
774
+
775
+ // Grid insets plus the footer band reserved for the brush. ECharts 6 contains
776
+ // axis labels automatically (the legacy `containLabel` flag now only triggers a
777
+ // deprecation warning).
778
+ function buildChartLayout({ legendSlot, xAxisSlot, showBrush, brushHeight }: OptionBuildContext): {
779
+ grid: GridComponentOption;
780
+ brushBottom: number;
781
+ } {
782
+ const legendTop = legendSlot.present && legendSlot.verticalAlign === "top";
783
+ const legendBottom = legendSlot.present && legendSlot.verticalAlign === "bottom";
784
+ // Clearance covers the x-axis labels plus the same breathing room the
785
+ // Recharts twin leaves between them and the brush. An x-axis TITLE renders
786
+ // below the labels (nameGap), so it needs its own band above the brush frame.
787
+ const brushGap = showBrush ? brushHeight + 30 + (xAxisSlot.label ? 22 : 0) : 0;
788
+
789
+ return {
790
+ grid: {
791
+ left: 8,
792
+ right: 8,
793
+ top: legendTop ? 42 : 16,
794
+ bottom: 8 + brushGap + (legendBottom ? 34 : 0),
795
+ },
796
+ brushBottom: legendBottom ? 34 : 6,
797
+ };
798
+ }
799
+
800
+ function buildMainAxes(ctx: OptionBuildContext): { xAxis: XAxisOption; yAxis: YAxisOption } {
801
+ const { xAxisSlot, yAxisSlot, showGrid, isLoading, isExpanded, categories, loadingData } = ctx;
802
+ const { tokens } = ctx.resolved;
803
+
804
+ const axisLabelColor = tokens.mutedForeground;
805
+ const splitLineColor = withAlpha(tokens.border, GRID_LINE_OPACITY);
806
+ // Gridline gray as an opaque color — see flattenColor.
807
+ const tickDotColor = flattenColor(splitLineColor, tokens.background);
808
+
809
+ const xTickFormatter = xAxisSlot.tickFormatter;
810
+ const yTickFormatter = yAxisSlot.tickFormatter;
811
+
812
+ const xAxis: XAxisOption = {
813
+ type: "category",
814
+ boundaryGap: false,
815
+ show: true,
816
+ data: isLoading ? loadingData().map((_, i) => i) : categories,
817
+ // Axis title — same size/color as the tick labels, pushed clear of them.
818
+ name: isLoading ? undefined : xAxisSlot.label,
819
+ nameLocation: "middle",
820
+ nameGap: 30,
821
+ nameTextStyle: { color: axisLabelColor, fontSize: 10 },
822
+ axisLine: { show: false },
823
+ // Tick DOTS: a near-zero-length tick whose round caps form a true circle,
824
+ // in the gridline gray (flattened opaque so the caps don't stack).
825
+ axisTick: {
826
+ show: !isLoading && xAxisSlot.present && !xAxisSlot.hideDots,
827
+ // Ticks default to the BOUNDARY between categories, which on a boundaryGap
828
+ // axis drops the dot in the gap instead of under its label. A no-op here
829
+ // (boundaryGap is false), kept for parity with the bar/composed charts.
830
+ alignWithLabel: true,
831
+ length: 0.5,
832
+ lineStyle: { color: tickDotColor, width: 3, cap: "round" },
833
+ },
834
+ splitLine: { show: false },
835
+ axisLabel: {
836
+ show: !isLoading && xAxisSlot.present,
837
+ color: axisLabelColor,
838
+ fontSize: 10,
839
+ margin: 8,
840
+ formatter: xTickFormatter
841
+ ? (value: string, index: number) => xTickFormatter(value, index)
842
+ : undefined,
843
+ },
844
+ };
845
+
846
+ // An ECharts axis with `show: false` hides its splitLines too, but Recharts'
847
+ // <CartesianGrid> draws with or without a visible <YAxis>. Keep the axis on
848
+ // whenever <Grid/> is present and gate the LABELS on <YAxis/> instead.
849
+ const yAxis: YAxisOption = {
850
+ type: "value",
851
+ show: yAxisSlot.present || showGrid,
852
+ max: isExpanded ? 1 : undefined,
853
+ // Axis title — rendered rotated alongside the tick labels, same styling.
854
+ name: isLoading ? undefined : yAxisSlot.label,
855
+ nameLocation: "middle",
856
+ nameGap: 38,
857
+ nameTextStyle: { color: axisLabelColor, fontSize: 10 },
858
+ axisLine: { show: false },
859
+ // Same tick dots as the x-axis, beside each value label. No alignWithLabel
860
+ // here: ECharts types it on the CATEGORY axis only, and a value axis already
861
+ // puts its ticks on the labels.
862
+ axisTick: {
863
+ show: yAxisSlot.present && !isLoading && !yAxisSlot.hideDots,
864
+ length: 0.5,
865
+ lineStyle: { color: tickDotColor, width: 3, cap: "round" },
866
+ },
867
+ splitLine: {
868
+ // Hidden while loading — the skeleton floats on a clean canvas.
869
+ show: showGrid && !isLoading,
870
+ lineStyle: { color: splitLineColor, type: [3, 3] as [number, number], width: 1 },
871
+ },
872
+ axisLabel: {
873
+ // Hidden while loading — skeleton values are meaningless, and the
874
+ // Recharts YAxis unmounts during loading too.
875
+ show: yAxisSlot.present && !isLoading,
876
+ color: axisLabelColor,
877
+ fontSize: 10,
878
+ margin: 8,
879
+ formatter: isExpanded
880
+ ? (value: number) => `${Math.round(value * 100)}%`
881
+ : yTickFormatter
882
+ ? (value: number, index: number) => yTickFormatter(value, index)
883
+ : undefined,
884
+ },
885
+ };
886
+
887
+ return { xAxis, yAxis };
888
+ }
889
+
890
+ // Tooltip HTML builder, closed over the build context. `getHoveredKey` is read
891
+ // per invocation — ECharts calls the formatter at hover time, and syncing hover
892
+ // through an option push instead would reset the native blur state mid-hover.
893
+ function createTooltipFormatter(ctx: OptionBuildContext) {
894
+ const { config, selectedDataKey, tooltipSlot, getHoveredKey } = ctx;
895
+
896
+ return (params: unknown): string => {
897
+ const rows = Array.isArray(params) ? params : [params];
898
+ if (!rows.length) return "";
899
+
900
+ const first = rows[0] as { axisValue?: string | number; name?: string };
901
+ // Label shows the RAW axis value — matches ChartTooltipContent (no tick formatter).
902
+ const axisValue = first.axisValue ?? first.name ?? "";
903
+ const label = String(axisValue);
904
+
905
+ // Dedupe by effective key: a buffer area contributes both its solid part
906
+ // (id=key) and its dashed overlay (id=`__buffer-{key}`) at the shared
907
+ // second-to-last point. Keep the first non-null value seen per key so the
908
+ // final point (only the overlay has data there) still shows its number.
909
+ const seen = new Set<string>();
910
+ const body = rows
911
+ .map((param) => {
912
+ const p = param as {
913
+ seriesId?: string;
914
+ seriesName?: string;
915
+ value?: number | string | null;
916
+ };
917
+ const rawId = String(p.seriesId ?? "");
918
+ // Map the dashed buffer overlay back onto its series; drop every other
919
+ // internal series (mini chart, loading skeleton, hover-reveal base).
920
+ const key = rawId.startsWith(BUFFER_PREFIX)
921
+ ? rawId.slice(BUFFER_PREFIX.length)
922
+ : rawId.startsWith("__")
923
+ ? ""
924
+ : (p.seriesId ?? p.seriesName ?? "");
925
+ if (!key) return "";
926
+ // A null value means this series does not reach the hovered x (a buffer
927
+ // area's solid part stops before the last point, a revealed series stops
928
+ // at the cursor) — skip it, letting another row for the key stand in.
929
+ if (p.value === null || p.value === undefined) return "";
930
+ if (seen.has(key)) return "";
931
+ seen.add(key);
932
+
933
+ const item = config[key];
934
+ const colorsCount = item ? getColorsCount(item) : 1;
935
+ const labelText = typeof item?.label === "string" ? item.label : (p.seriesName ?? key);
936
+ const hovered = getHoveredKey();
937
+ const dimmed =
938
+ (selectedDataKey != null && selectedDataKey !== key) ||
939
+ (hovered != null && hovered !== key)
940
+ ? " opacity-30"
941
+ : "";
942
+ const value =
943
+ typeof p.value === "number" ? p.value.toLocaleString() : String(p.value ?? "");
944
+
945
+ return tooltipRow({
946
+ indicatorHtml: tooltipIndicatorHtml(key, colorsCount),
947
+ labelText,
948
+ valueText: value,
949
+ dimmed,
950
+ });
951
+ })
952
+ .join("");
953
+
954
+ return tooltipShell({
955
+ label,
956
+ body,
957
+ roundness: tooltipSlot.roundness,
958
+ variant: tooltipSlot.variant,
959
+ });
960
+ };
961
+ }
962
+
963
+ function buildTooltipOption(ctx: OptionBuildContext): TooltipComponentOption {
964
+ const { tooltipSlot, isLoading } = ctx;
965
+ const { tokens } = ctx.resolved;
966
+
967
+ return {
968
+ ...tooltipBaseOption({
969
+ present: tooltipSlot.present && !isLoading,
970
+ cursor: tooltipSlot.cursor,
971
+ tokens,
972
+ position: tooltipSlot.position,
973
+ axisPointerColor: withAlpha(tokens.border, AXIS_POINTER_OPACITY),
974
+ strokeWidth: STROKE_WIDTH,
975
+ }),
976
+ formatter: createTooltipFormatter(ctx),
977
+ };
978
+ }
979
+
980
+ // ── Brush — the evil-brush look, canvas-style: a real mini chart of the full
981
+ // data in a second grid, with a transparent slider dataZoom laid over it. Both
982
+ // zoom entries target only the MAIN x-axis, so the mini chart never filters
983
+ // itself. Only called when `showBrush` is set.
984
+ function buildBrushOption(
985
+ ctx: OptionBuildContext,
986
+ brushBottom: number,
987
+ ): {
988
+ miniGrid: GridComponentOption;
989
+ miniXAxis: XAxisOption;
990
+ miniYAxis: YAxisOption;
991
+ miniSeries: LineSeriesOption[];
992
+ dataZoom: DataZoomComponentOption[];
993
+ } {
994
+ const { data, areas, curveType, isStacked, selectedDataKey, brushHeight, categories } = ctx;
995
+ const { tokens } = ctx.resolved;
996
+
997
+ const miniGrid: GridComponentOption = {
998
+ left: 8,
999
+ right: 8,
1000
+ bottom: brushBottom,
1001
+ height: brushHeight,
1002
+ // No visible axes here — opt out of label containment so the mini chart
1003
+ // spans the full brush frame.
1004
+ outerBoundsMode: "none",
1005
+ };
1006
+
1007
+ const miniXAxis: XAxisOption = {
1008
+ type: "category",
1009
+ gridIndex: 1,
1010
+ boundaryGap: false,
1011
+ show: false,
1012
+ data: categories,
1013
+ axisPointer: { show: false },
1014
+ };
1015
+
1016
+ const miniYAxis: YAxisOption = { type: "value", gridIndex: 1, show: false };
1017
+
1018
+ const miniSeries: LineSeriesOption[] = areas.map((area) => {
1019
+ const key = area.dataKey;
1020
+ const base = (ctx.resolved.series[key] ?? [])[0] ?? "rgba(120, 120, 120, 1)";
1021
+ const curve = curveConfig(area.curveType ?? curveType);
1022
+
1023
+ // The mini chart mirrors the click selection: unselected series recede
1024
+ // by the same ratios as the main plot.
1025
+ // Dim ratios normalize against the base opacities (stroke 1, fill 0.8).
1026
+ const opacity = getOpacity(selectedDataKey, key);
1027
+ const strokeDim = opacity.stroke;
1028
+ const fillDim = opacity.fill / 0.8;
1029
+
1030
+ return {
1031
+ id: `__mini-${key}`,
1032
+ type: "line",
1033
+ xAxisIndex: 1,
1034
+ yAxisIndex: 1,
1035
+ data: data.map((row) => Number(row[key]) || 0),
1036
+ stack: isStacked ? "__mini-total" : undefined,
1037
+ smooth: curve.smooth,
1038
+ step: curve.step,
1039
+ connectNulls: area.connectNulls,
1040
+ silent: true,
1041
+ showSymbol: false,
1042
+ emphasis: { disabled: true },
1043
+ tooltip: { show: false },
1044
+ lineStyle: { color: base, width: 1, opacity: BRUSH_STROKE_OPACITY * strokeDim },
1045
+ areaStyle: {
1046
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
1047
+ { offset: 0, color: withAlpha(base, BRUSH_FILL_OPACITY * fillDim) },
1048
+ { offset: 1, color: withAlpha(base, 0) },
1049
+ ]),
1050
+ },
1051
+ z: 0,
1052
+ };
1053
+ });
1054
+
1055
+ const dataZoom = buildBrushDataZoom({
1056
+ brushBottom,
1057
+ brushHeight,
1058
+ brushRange: ctx.brushRange,
1059
+ fillerColor: withAlpha(tokens.foreground, BRUSH_FILLER_OPACITY),
1060
+ });
1061
+
1062
+ return { miniGrid, miniXAxis, miniYAxis, miniSeries, dataZoom };
1063
+ }
1064
+
1065
+ // Loading skeleton — ONE gray wave regardless of declared areas (Recharts
1066
+ // parity: its skeleton is a single LoadingArea), swept by the shimmer rAF.
1067
+ function buildLoadingOption(
1068
+ ctx: OptionBuildContext,
1069
+ frame: { grid: GridComponentOption; xAxis: XAxisOption; yAxis: YAxisOption },
1070
+ ): EChartsOption {
1071
+ const { tokens } = ctx.resolved;
1072
+ const curve = curveConfig(ctx.curveType);
1073
+
1074
+ return {
1075
+ animation: false,
1076
+ grid: frame.grid,
1077
+ xAxis: frame.xAxis,
1078
+ yAxis: frame.yAxis,
1079
+ tooltip: { show: false },
1080
+ series: [
1081
+ {
1082
+ id: "__loading",
1083
+ type: "line",
1084
+ data: ctx.loadingData(),
1085
+ smooth: curve.smooth,
1086
+ step: curve.step,
1087
+ showSymbol: false,
1088
+ silent: true,
1089
+ // Invisible until the first shimmer tick positions the clip window.
1090
+ lineStyle: { color: withAlpha(tokens.foreground, 0), width: 1 },
1091
+ areaStyle: { color: withAlpha(tokens.foreground, 0) },
1092
+ z: 1,
1093
+ },
1094
+ ],
1095
+ };
1096
+ }
1097
+
1098
+ function buildAreaSeries(ctx: OptionBuildContext): LineSeriesOption[] {
1099
+ const {
1100
+ data,
1101
+ config,
1102
+ areas,
1103
+ seriesKeys,
1104
+ curveType,
1105
+ isStacked,
1106
+ isExpanded,
1107
+ selectedDataKey,
1108
+ hasSelection,
1109
+ enableHoverHighlight,
1110
+ enableHoverReveal,
1111
+ revealIndex,
1112
+ revealSink,
1113
+ resolved,
1114
+ rendererSize,
1115
+ } = ctx;
1116
+
1117
+ // Optional per-row normalization for the expanded (100%) stack.
1118
+ const rowTotals = isExpanded
1119
+ ? data.map((row) => seriesKeys.reduce((sum, key) => sum + (Number(row[key]) || 0), 0))
1120
+ : [];
1121
+
1122
+ return areas.flatMap((area): LineSeriesOption[] => {
1123
+ const key = area.dataKey;
1124
+ const slots = resolved.series[key] ?? ["rgba(120, 120, 120, 1)"];
1125
+ const paint = seriesPaint(slots);
1126
+ const isSelected = selectedDataKey === key;
1127
+ const showUnselected = hasSelection && !isSelected;
1128
+ const opacity = getOpacity(selectedDataKey, key);
1129
+ const curve = curveConfig(area.curveType ?? curveType);
1130
+
1131
+ const values = data.map((row, i) => {
1132
+ const value = Number(row[key]) || 0;
1133
+ if (!isExpanded) return value;
1134
+ const total = rowTotals[i];
1135
+ return total ? value / total : 0;
1136
+ });
1137
+ const n = values.length;
1138
+ // Hover-reveal is a root-level mode and owns the whole area rendering, so it
1139
+ // takes precedence over a per-area buffer tail when both are set.
1140
+ const reveal = enableHoverReveal;
1141
+ const buffer = !reveal && area.enableBufferLine && n >= 2;
1142
+ const revealActive = reveal && revealIndex !== null;
1143
+
1144
+ const restingDot = dotStyle(area.dotVariant, paint, resolved.tokens.background);
1145
+ const activeDot = dotStyle(area.activeDotVariant, paint, resolved.tokens.background);
1146
+ const restingVisible = area.dotVariant !== "none";
1147
+ const dotOpacity = opacity.dot;
1148
+ const multiColor = slots.length > 1;
1149
+
1150
+ // The reveal truncates the line to the cursor, which would COMPRESS a
1151
+ // bbox-relative stroke gradient into the shorter span — misaligning it from
1152
+ // the plot-anchored fill texture and the index-sampled dots. Anchor the
1153
+ // stroke to the plot in absolute pixels so every x keeps its own color.
1154
+ const strokePaint =
1155
+ reveal && multiColor
1156
+ ? new echarts.graphic.LinearGradient(
1157
+ 8,
1158
+ 0,
1159
+ Math.max(rendererSize.width - 8, 9),
1160
+ 0,
1161
+ slots.map((color, i) => ({ offset: i / (slots.length - 1), color })),
1162
+ true,
1163
+ )
1164
+ : paint;
1165
+
1166
+ // Turn a value list into ECharts data — attaching per-datum symbol colors
1167
+ // for multi-color areas (like the Recharts dots; the line/fill keep the full
1168
+ // gradient), and passing `null` gaps through so a buffer area's two parts
1169
+ // each draw only their own segment.
1170
+ type AreaPoint =
1171
+ | number
1172
+ | null
1173
+ | {
1174
+ value: number;
1175
+ itemStyle: Record<string, unknown>;
1176
+ emphasis: { itemStyle: Record<string, unknown> };
1177
+ };
1178
+ const toPoints = (vals: (number | null)[]): AreaPoint[] =>
1179
+ !multiColor
1180
+ ? vals
1181
+ : vals.map((value, i): AreaPoint => {
1182
+ if (value === null) return null;
1183
+ const t = vals.length > 1 ? i / (vals.length - 1) : 0;
1184
+ const pointColor = sampleGradient(slots, t);
1185
+ return {
1186
+ value,
1187
+ itemStyle: {
1188
+ ...dotItemStyle(
1189
+ restingVisible ? area.dotVariant : area.activeDotVariant,
1190
+ pointColor,
1191
+ resolved.tokens.background,
1192
+ ),
1193
+ opacity: dotOpacity,
1194
+ },
1195
+ emphasis: {
1196
+ itemStyle: {
1197
+ ...dotItemStyle(
1198
+ area.activeDotVariant === "none" ? "default" : area.activeDotVariant,
1199
+ pointColor,
1200
+ resolved.tokens.background,
1201
+ ),
1202
+ opacity: 1,
1203
+ },
1204
+ },
1205
+ };
1206
+ });
1207
+
1208
+ // Buffer area: the solid MAIN part drops the last point (its final segment —
1209
+ // both fill and stroke — becomes the dashed, fill-less overlay); the overlay
1210
+ // carries only the last two points. Reveal instead TRUNCATES the real series
1211
+ // at the cursor's x-index (points beyond it null'd), so its line + fill stop
1212
+ // there and the muted base layer shows through past it. When idle
1213
+ // (revealIndex null) the real series carries its full data — the chart looks
1214
+ // completely normal.
1215
+ // Snapshot the FULL per-datum points (with the multi-color dot itemStyle) so
1216
+ // the reveal hover handler can slice them without losing each dot's sampled
1217
+ // gradient color — plain values would fall back to the default palette.
1218
+ if (reveal) revealSink[key] = toPoints(values);
1219
+
1220
+ const mainValues: (number | null)[] = buffer
1221
+ ? values.map((v, i) => (i === n - 1 ? null : v))
1222
+ : revealActive
1223
+ ? sliceToNull(values, revealIndex as number)
1224
+ : values;
1225
+
1226
+ // A buffer area keeps its body solid and dashes only the tail overlay, so
1227
+ // the main stroke is always solid regardless of strokeVariant (matches the
1228
+ // Recharts twin, which suppresses the base dasharray while buffering).
1229
+ const mainDash: "solid" | [number, number] =
1230
+ buffer || area.strokeVariant === "solid" ? "solid" : ([3, 3] as [number, number]);
1231
+
1232
+ const z = isSelected ? 3 : hasSelection ? 1 : 2;
1233
+
1234
+ const mainSeries: LineSeriesOption = {
1235
+ id: key,
1236
+ name: typeof config[key]?.label === "string" ? config[key]?.label : key,
1237
+ type: "line",
1238
+ data: toPoints(mainValues),
1239
+ stack: isStacked ? "total" : undefined,
1240
+ smooth: curve.smooth,
1241
+ step: curve.step,
1242
+ connectNulls: area.connectNulls,
1243
+ cursor: area.isClickable ? "pointer" : "default",
1244
+ // By default ECharts only fires mouse events on the symbols — this makes
1245
+ // the line AND the filled area clickable, like the Recharts <Area>.
1246
+ // (`true` covers both; the deprecated `triggerLineEvent` did the same.)
1247
+ triggerEvent: area.isClickable,
1248
+ showSymbol: restingVisible,
1249
+ symbol: "circle",
1250
+ symbolSize: restingVisible ? restingDot.size : activeDot.size,
1251
+ z,
1252
+ lineStyle: {
1253
+ color: strokePaint,
1254
+ width: area.strokeWidth,
1255
+ opacity: opacity.stroke,
1256
+ type: mainDash,
1257
+ dashOffset: 0,
1258
+ },
1259
+ itemStyle: multiColor
1260
+ ? { opacity: dotOpacity }
1261
+ : {
1262
+ ...(restingVisible ? restingDot.itemStyle : activeDot.itemStyle),
1263
+ opacity: dotOpacity,
1264
+ },
1265
+ areaStyle: {
1266
+ color: fillPaint(area.variant, showUnselected, slots, rendererSize),
1267
+ opacity: opacity.fill,
1268
+ },
1269
+ emphasis: {
1270
+ // focus "series" blurs every other series in this grid while one is
1271
+ // hovered — the hover twin of the click selection. Suppressed entirely
1272
+ // while a series is click-selected: the selection dim owns the canvas,
1273
+ // so hover highlighting stops until the selection clears (the option
1274
+ // rebuilds on selection change, making this a build-time conditional).
1275
+ // Reveal owns the hover visual, so native focus-blur stands down when it
1276
+ // is on (they must not blend).
1277
+ focus: enableHoverHighlight && !enableHoverReveal && !hasSelection ? "series" : "none",
1278
+ scale: restingVisible ? activeDot.size / Math.max(restingDot.size, 1) : 1,
1279
+ ...(multiColor ? {} : { itemStyle: { ...activeDot.itemStyle, opacity: 1 } }),
1280
+ },
1281
+ // Blur styling mirrors the click-selection dim (fill 0.1 / stroke 0.3 / dot 0.3).
1282
+ blur: {
1283
+ lineStyle: { opacity: 0.3 },
1284
+ areaStyle: { opacity: 0.1 },
1285
+ itemStyle: { opacity: 0.3 },
1286
+ },
1287
+ };
1288
+
1289
+ // Hover-reveal: a muted gray BASE layer of the FULL series sits one z below
1290
+ // the real one. It is invisible while idle (opacity 0 → the chart looks
1291
+ // normal) and fades in only while hovering, so the region PAST the cursor —
1292
+ // where the truncated real series has stopped — shows as neutral gray.
1293
+ if (reveal) {
1294
+ const muted = resolved.tokens.mutedForeground;
1295
+ const revealBase: LineSeriesOption = {
1296
+ id: `${REVEAL_PREFIX}${key}`,
1297
+ type: "line",
1298
+ // Only the region FROM the cursor onward (null before it), so the gray
1299
+ // never sits under the colored part — the two meet exactly at the
1300
+ // pointer and their colors can't mix.
1301
+ data: revealActive ? sliceFrom(values, revealIndex as number) : values,
1302
+ // Its OWN stack, not "total" — a second series in the real stack would
1303
+ // double every key's contribution (broken geometry). This mirror stack
1304
+ // reproduces the same cumulative shape in a separate layer.
1305
+ stack: isStacked ? "__reveal-total" : undefined,
1306
+ smooth: curve.smooth,
1307
+ step: curve.step,
1308
+ connectNulls: false,
1309
+ silent: true,
1310
+ showSymbol: false,
1311
+ symbol: "circle",
1312
+ z: z - 1,
1313
+ // Neutral gray, NO fill, SAME dash pattern as the colored line.
1314
+ lineStyle: {
1315
+ color: muted,
1316
+ width: area.strokeWidth,
1317
+ type: mainDash,
1318
+ opacity: revealActive ? 0.3 : 0,
1319
+ },
1320
+ emphasis: { disabled: true },
1321
+ blur: { lineStyle: { opacity: revealActive ? 0.3 : 0 } },
1322
+ tooltip: { show: false },
1323
+ };
1324
+ return [revealBase, mainSeries];
1325
+ }
1326
+
1327
+ if (!buffer) return [mainSeries];
1328
+
1329
+ // Dashed forecast overlay — draws ONLY the last segment's stroke, with NO
1330
+ // fill (matching the line twin's fill-less buffer). Silent, so it never
1331
+ // intercepts clicks/hover; it still feeds the axis tooltip (silent series
1332
+ // are aggregated by axis), which is why the last point keeps its number.
1333
+ const bufferValues: (number | null)[] = values.map((v, i) => (i >= n - 2 ? v : null));
1334
+ const bufferSeries: LineSeriesOption = {
1335
+ id: `${BUFFER_PREFIX}${key}`,
1336
+ type: "line",
1337
+ data: toPoints(bufferValues),
1338
+ // Own mirror stack — a second series in "total" would double the last
1339
+ // points' stacked height (buffer drawn too high). Same values in the same
1340
+ // order give the identical cumulative height, so the dash lines up.
1341
+ stack: isStacked ? "__buffer-total" : undefined,
1342
+ smooth: curve.smooth,
1343
+ step: curve.step,
1344
+ connectNulls: true,
1345
+ silent: true,
1346
+ showSymbol: restingVisible,
1347
+ symbol: "circle",
1348
+ symbolSize: restingVisible ? restingDot.size : activeDot.size,
1349
+ z,
1350
+ lineStyle: {
1351
+ color: paint,
1352
+ width: area.strokeWidth,
1353
+ opacity: opacity.stroke,
1354
+ type: BUFFER_DASH,
1355
+ },
1356
+ itemStyle: multiColor
1357
+ ? { opacity: dotOpacity }
1358
+ : {
1359
+ ...(restingVisible ? restingDot.itemStyle : activeDot.itemStyle),
1360
+ opacity: dotOpacity,
1361
+ },
1362
+ // The dashed tail is a separate silent series, so focus:"series" on its
1363
+ // parent would blur it apart from the area it belongs to. The root
1364
+ // dispatch-links this id (companionIdsByKey) so it focuses WITH its parent;
1365
+ // these styles give it the parent's look while focused and the
1366
+ // click-selection dim while another series is hovered.
1367
+ emphasis: {
1368
+ focus: "none",
1369
+ scale: false,
1370
+ lineStyle: { opacity: opacity.stroke },
1371
+ itemStyle: { opacity: dotOpacity },
1372
+ },
1373
+ blur: { lineStyle: { opacity: 0.3 }, itemStyle: { opacity: 0.3 } },
1374
+ };
1375
+
1376
+ // Fill patch — the main area drops its last point (so the tail stroke can be
1377
+ // the dashed overlay), which also removes the FILL under that last segment.
1378
+ // This fill-only layer (no stroke, no dots) fills just that segment so the
1379
+ // area reads as full under the dashed tail. Its OWN mirror stack keeps the
1380
+ // stacked geometry right — a second series in "total" would double the last
1381
+ // points' cumulative height (same reason as the reveal base + mini chart).
1382
+ const bufferFillSeries: LineSeriesOption = {
1383
+ id: `${BUFFERFILL_PREFIX}${key}`,
1384
+ type: "line",
1385
+ data: toPoints(bufferValues),
1386
+ stack: isStacked ? "__bufferfill-total" : undefined,
1387
+ smooth: curve.smooth,
1388
+ step: curve.step,
1389
+ connectNulls: true,
1390
+ silent: true,
1391
+ showSymbol: false,
1392
+ z: z - 1,
1393
+ lineStyle: { opacity: 0 },
1394
+ areaStyle: {
1395
+ color: fillPaint(area.variant, showUnselected, slots, rendererSize),
1396
+ opacity: opacity.fill,
1397
+ },
1398
+ emphasis: { disabled: true },
1399
+ blur: { areaStyle: { opacity: 0.1 } },
1400
+ tooltip: { show: false },
1401
+ };
1402
+
1403
+ return [mainSeries, bufferSeries, bufferFillSeries];
1404
+ });
1405
+ }
1406
+
1407
+ // Copy a value list with everything AFTER `idx` nulled — the hover-reveal cut:
1408
+ // the colored real series keeps its data up to the cursor and drops the rest, so
1409
+ // (with connectNulls false) its line and fill stop dead at the pointer.
1410
+ function sliceToNull<T>(vals: readonly T[], idx: number): (T | null)[] {
1411
+ return vals.map((v, i) => (i > idx ? null : v));
1412
+ }
1413
+
1414
+ // Copy a value list with everything BEFORE `idx` nulled — the reveal's gray tail.
1415
+ // The muted base keeps only the region from the cursor onward, so it never sits
1416
+ // under the colored part; both include `idx` so they meet at the pointer.
1417
+ // Generic so it preserves per-datum point objects (multi-color dot itemStyle).
1418
+ function sliceFrom<T>(vals: readonly T[], idx: number): (T | null)[] {
1419
+ return vals.map((v, i) => (i < idx ? null : v));
1420
+ }
1421
+
1422
+ // Per-series PLOTTED top value per category index — expanded normalization and
1423
+ // stack accumulation applied — so pointer hit-testing can reason in data space.
1424
+ function computePlottedTops(ctx: OptionBuildContext): Record<string, number[]> {
1425
+ const { data, areas, seriesKeys, isStacked, isExpanded } = ctx;
1426
+ const rowTotals = isExpanded
1427
+ ? data.map((row) => seriesKeys.reduce((sum, key) => sum + (Number(row[key]) || 0), 0))
1428
+ : [];
1429
+ const running = new Array(data.length).fill(0);
1430
+ const tops: Record<string, number[]> = {};
1431
+ for (const area of areas) {
1432
+ const key = area.dataKey;
1433
+ tops[key] = data.map((row, i) => {
1434
+ let value = Number(row[key]) || 0;
1435
+ if (isExpanded) value = rowTotals[i] ? value / rowTotals[i] : 0;
1436
+ return isStacked ? (running[i] += value) : value;
1437
+ });
1438
+ }
1439
+ return tops;
1440
+ }
1441
+
1442
+ // Overlapping area polygons all contain the same pixel, so ECharts' native hit
1443
+ // test lands on whichever series drew topmost — not the band the user SEES.
1444
+ // Resolve the intended series geometrically: a plotted line within grab
1445
+ // distance of the pointer wins outright; otherwise the point belongs to the
1446
+ // nearest line ABOVE it (the boundary of the band the pointer is inside).
1447
+ // Returns null when the pointer is outside the grid or above every line.
1448
+ function resolveAreaAtPixel(
1449
+ chart: EChartsInstance,
1450
+ tops: Record<string, number[]>,
1451
+ keys: string[],
1452
+ x: number,
1453
+ y: number,
1454
+ ): string | null {
1455
+ if (keys.length < 2) return null;
1456
+ if (!chart.containPixel({ gridIndex: 0 }, [x, y])) return null;
1457
+ const [rawIndex] = chart.convertFromPixel({ gridIndex: 0 }, [x, y]);
1458
+ const index = Math.round(rawIndex);
1459
+
1460
+ let nearest: string | null = null;
1461
+ let nearestDist = Infinity;
1462
+ let above: string | null = null;
1463
+ let abovePixelY = -Infinity;
1464
+ for (const key of keys) {
1465
+ const value = tops[key]?.[index];
1466
+ if (value === undefined) continue;
1467
+ const pixelY = chart.convertToPixel({ gridIndex: 0 }, [index, value])[1];
1468
+ const dist = Math.abs(pixelY - y);
1469
+ if (dist < nearestDist) {
1470
+ nearestDist = dist;
1471
+ nearest = key;
1472
+ }
1473
+ // Pixel y grows downward: a line above the pointer has the larger pixelY
1474
+ // among those ≤ the pointer's.
1475
+ if (pixelY <= y && pixelY > abovePixelY) {
1476
+ abovePixelY = pixelY;
1477
+ above = key;
1478
+ }
1479
+ }
1480
+ return nearestDist <= 10 ? nearest : above;
1481
+ }
1482
+
1483
+ // ─────────────────────────────────────────────────────────────────────────────
1484
+ // Live imperative state — everything the ECharts event handlers, rAF loops, and
1485
+ // theme/resize repushes read or write OUTSIDE the React render cycle, grouped in
1486
+ // one ref-stable object so the whole imperative surface is visible at a glance.
1487
+ // None of it is render output, which is exactly why it is not React state.
1488
+ // ─────────────────────────────────────────────────────────────────────────────
1489
+
1490
+ type LiveState = {
1491
+ resolved: ResolvedColors | null; // colors read off the live DOM — feeds builds and rAF loops
1492
+ hoveredKey: string | null; // tooltip's view of hover — the legend's twin lives in React state
1493
+ hasRevealed: boolean; // the intro draw-in already played on this chart instance
1494
+ revealEndsAt: number; // performance.now() timestamp when the entrance settles
1495
+ loadingRows: number[] | null; // skeleton data, lazily rolled and re-rolled per shimmer sweep
1496
+ categories: string[]; // x labels of the last build, for the brush label pills
1497
+ dataLength: number; // row count, for the datazoom index math
1498
+ plottedTops: Record<string, number[]>; // per-series plotted line value per index, for pointer hit-testing
1499
+ seriesKeyByIndex: (string | undefined)[]; // built series order → key, so a polygon click's seriesIndex recovers its key past interleaved buffer/reveal/mini series
1500
+ companionIdsByKey: Map<string, string[]>; // per-key silent companion series ids (buffer tail, reveal base) — highlighted/downplayed with their parent
1501
+ revealIndex: number | null; // hover-reveal pointer x-index (null = idle); read by builds and the reveal hover handler
1502
+ revealValues: Record<string, unknown[]>; // per-area FULL per-datum points (with dot itemStyle), sliced to the cursor on hover without a rebuild
1503
+ brushRange: BrushRange; // live zoom window — carried through every rebuild
1504
+ brushGeom: BrushGeometry | null; // brush footer layout of the last build
1505
+ brushOverlay: BrushOverlayElements | null; // zrender elements, owned by syncBrushOverlay
1506
+ brushHover: { inside: boolean; left: boolean; right: boolean };
1507
+ // Latest callbacks/flags for the imperative ECharts event handlers.
1508
+ handlers: {
1509
+ onBrushChange?: (range: { startIndex: number; endIndex: number }) => void;
1510
+ onSelectionChange?: (key: string | null) => void;
1511
+ clickableKeys: Set<string>;
1512
+ selectedDataKey: string | null;
1513
+ brushFormatLabel?: (value: string, index: number) => string;
1514
+ seriesKeys: string[];
1515
+ enableHoverHighlight: boolean;
1516
+ enableHoverReveal: boolean;
1517
+ };
1518
+ // Update-style re-push for paths that bypass React entirely (theme flips,
1519
+ // resizes) — set by the sync effect.
1520
+ repush: () => void;
1521
+ };
1522
+
1523
+ // ─────────────────────────────────────────────────────────────────────────────
1524
+ // Component
1525
+ // ─────────────────────────────────────────────────────────────────────────────
1526
+
1527
+ /**
1528
+ * Apache ECharts port of the EvilCharts area chart, exposing a compound-as-config
1529
+ * API so its JSX reads identically to the Recharts twin. The root owns the data,
1530
+ * config, selection state, loading skeleton, intro reveal, and optional zoom
1531
+ * brush; every visual part — `<Area>`, `<XAxis>`, `<YAxis>`, `<Grid>`,
1532
+ * `<Tooltip>`, `<Legend>` — is composed as a declarative child that renders
1533
+ * nothing. The root walks those children by reference and drives a single
1534
+ * imperative ECharts instance. Fully self-contained: its only dependencies are
1535
+ * `react` and `echarts`.
1536
+ */
1537
+ export function EChartsAreaChart<TData extends Record<string, unknown>>({
1538
+ data,
1539
+ config,
1540
+ renderer = DEFAULT_ECHARTS_RENDERER,
1541
+ xDataKey,
1542
+ className,
1543
+ curveType = "linear",
1544
+ stackType = "default",
1545
+ animation = true,
1546
+ animationType = "left-to-right",
1547
+ enableHoverHighlight = false,
1548
+ enableHoverReveal = false,
1549
+ defaultSelectedDataKey = null,
1550
+ selectedDataKey: selectedDataKeyProp,
1551
+ onSelectionChange,
1552
+ isLoading = false,
1553
+ loadingPoints = LOADING_DEFAULT_POINTS,
1554
+ chartOptions,
1555
+ children,
1556
+ }: EChartsAreaChartProps<TData>) {
1557
+ const rawId = useId();
1558
+ const chartId = `chart-${rawId.replace(/:/g, "")}`;
1559
+
1560
+ const containerRef = useRef<HTMLDivElement>(null);
1561
+ const mountRef = useRef<HTMLDivElement>(null);
1562
+ const echartsRef = useRef<EChartsInstance | null>(null);
1563
+
1564
+ // The single imperative surface (see LiveState). `resolved` lives here rather
1565
+ // than in state: as state it forced an extra render pass and an effect whose
1566
+ // only job was to trigger the option push — the "chain of computations"
1567
+ // react.dev/learn/you-might-not-need-an-effect warns about. The object
1568
+ // identity is stable for the component's lifetime.
1569
+ const live = useRef<LiveState>({
1570
+ resolved: null,
1571
+ hoveredKey: null,
1572
+ hasRevealed: false,
1573
+ revealEndsAt: 0,
1574
+ loadingRows: null,
1575
+ categories: [],
1576
+ dataLength: 0,
1577
+ plottedTops: {},
1578
+ seriesKeyByIndex: [],
1579
+ companionIdsByKey: new Map<string, string[]>(),
1580
+ revealIndex: null,
1581
+ revealValues: {},
1582
+ brushRange: { start: 0, end: 100 },
1583
+ brushGeom: null,
1584
+ brushOverlay: null,
1585
+ brushHover: { inside: false, left: false, right: false },
1586
+ handlers: {
1587
+ onBrushChange: undefined, // set per-render from the <Brush> child's onChange
1588
+ onSelectionChange,
1589
+ clickableKeys: new Set<string>(),
1590
+ selectedDataKey: defaultSelectedDataKey,
1591
+ brushFormatLabel: undefined, // set per-render from the <Brush> child's formatLabel
1592
+ seriesKeys: [],
1593
+ enableHoverHighlight,
1594
+ enableHoverReveal,
1595
+ },
1596
+ repush: () => {},
1597
+ }).current;
1598
+
1599
+ // Skeleton rows roll lazily on first use — an impure useRef initializer would
1600
+ // re-roll Math.random() on every render.
1601
+ const loadingData = useCallback(
1602
+ () => (live.loadingRows ??= getLoadingData(loadingPoints)),
1603
+ [live, loadingPoints],
1604
+ );
1605
+ const shouldReduceMotion = useReducedMotion();
1606
+
1607
+ // Selection is controlled when the `selectedDataKey` prop is provided;
1608
+ // otherwise the internal state (seeded by defaultSelectedDataKey) drives it.
1609
+ const [internalSelectedKey, setSelectedDataKey] = useState<string | null>(defaultSelectedDataKey);
1610
+ const selectedDataKey =
1611
+ selectedDataKeyProp !== undefined ? selectedDataKeyProp : internalSelectedKey;
1612
+
1613
+ // Hover-highlight mirrors into the legend (React state) and tooltip
1614
+ // (live.hoveredKey — its formatter runs on every hover, and pushing an option
1615
+ // to sync it would reset ECharts' blur state mid-hover).
1616
+ const [hoveredDataKey, setHoveredDataKey] = useState<string | null>(null);
1617
+
1618
+ // ── Declarative config, collected from children by reference ─────────────────
1619
+ const collected = useMemo(() => collectConfig(children), [children]);
1620
+ const {
1621
+ areas,
1622
+ xAxis: xAxisSlot,
1623
+ yAxis: yAxisSlot,
1624
+ showGrid,
1625
+ tooltip: tooltipSlot,
1626
+ legend: legendSlot,
1627
+ brush: brushSlot,
1628
+ } = collected;
1629
+ // Brush is a <Brush> child now (not props): presence turns it on, its props
1630
+ // carry height/formatLabel/onChange.
1631
+ const showBrush = brushSlot.present;
1632
+ const brushHeight = brushSlot.height ?? 56;
1633
+
1634
+ const seriesKeys = useMemo(() => areas.map((area) => area.dataKey), [areas]);
1635
+
1636
+ // x category key: <XAxis dataKey> → root xDataKey → first data column no <Area> claims.
1637
+ const xCategoryKey = useMemo(() => {
1638
+ if (xAxisSlot.dataKey) return xAxisSlot.dataKey;
1639
+ if (xDataKey) return xDataKey as string;
1640
+ const firstRow = data[0];
1641
+ if (firstRow) {
1642
+ const claimed = new Set(seriesKeys);
1643
+ const found = Object.keys(firstRow).find((key) => !claimed.has(key));
1644
+ if (found) return found;
1645
+ }
1646
+ return "";
1647
+ }, [xAxisSlot.dataKey, xDataKey, data, seriesKeys]);
1648
+
1649
+ // The intro draw-in follows the first area's setting, falling back to the root default.
1650
+ const effectiveAnimation = areas[0]?.animationType ?? animationType;
1651
+
1652
+ const css = useMemo(() => buildChartCss(chartId, config), [chartId, config]);
1653
+
1654
+ const hasSelection = selectedDataKey !== null;
1655
+ const isExpanded = stackType === "expanded";
1656
+ const isStacked = stackType === "stacked" || isExpanded;
1657
+
1658
+ // Which series may be clicked to toggle selection (consulted by the click handler).
1659
+ const clickableKeys = useMemo(
1660
+ () => new Set(areas.filter((area) => area.isClickable).map((area) => area.dataKey)),
1661
+ [areas],
1662
+ );
1663
+
1664
+ // Refresh the handlers' snapshot of the latest callbacks/flags every render.
1665
+ live.handlers = {
1666
+ onBrushChange: brushSlot.onChange,
1667
+ onSelectionChange,
1668
+ clickableKeys,
1669
+ selectedDataKey,
1670
+ brushFormatLabel: brushSlot.formatLabel,
1671
+ seriesKeys,
1672
+ enableHoverHighlight,
1673
+ enableHoverReveal,
1674
+ };
1675
+ live.dataLength = data.length;
1676
+
1677
+ // Reads the CURRENT selection through live.handlers so the identity stays
1678
+ // stable for the init effect's click closure, and stays correct when the
1679
+ // selection is controlled from outside.
1680
+ const toggleSelection = useCallback(
1681
+ (key: string) => {
1682
+ const next = live.handlers.selectedDataKey === key ? null : key;
1683
+ // Making a selection hands the canvas to the selection dim — clear any
1684
+ // active hover highlight at that moment so it doesn't linger in the
1685
+ // legend/tooltip or fight the notMerge rebuild that follows.
1686
+ if (next !== null && live.hoveredKey !== null) {
1687
+ const previous = live.hoveredKey;
1688
+ live.hoveredKey = null;
1689
+ setHoveredDataKey(null);
1690
+ echartsRef.current?.dispatchAction({
1691
+ type: "downplay",
1692
+ seriesIndex: live.handlers.seriesKeys.indexOf(previous),
1693
+ });
1694
+ }
1695
+ setSelectedDataKey(next);
1696
+ live.handlers.onSelectionChange?.(next);
1697
+ },
1698
+ [live],
1699
+ );
1700
+
1701
+ // Reposition the brush overlays from the live refs — safe to call from drag
1702
+ // events, hover tracking, and pushes alike, since it never touches setOption.
1703
+ const syncBrushOverlayNow = useCallback(() => {
1704
+ const chart = echartsRef.current;
1705
+ if (!chart) return;
1706
+
1707
+ const geom = live.brushGeom;
1708
+ const tokens = live.resolved?.tokens;
1709
+ if (!geom || !tokens) {
1710
+ syncBrushOverlay(chart, live, null);
1711
+ return;
1712
+ }
1713
+
1714
+ const range = live.brushRange;
1715
+ const categories = live.categories;
1716
+ const format = live.handlers.brushFormatLabel;
1717
+ const lastIndex = Math.max(categories.length - 1, 0);
1718
+ const startIndex = Math.round((range.start / 100) * lastIndex);
1719
+ const endIndex = Math.round((range.end / 100) * lastIndex);
1720
+ const labels =
1721
+ format && categories.length
1722
+ ? {
1723
+ start: format(categories[startIndex] ?? "", startIndex),
1724
+ end: format(categories[endIndex] ?? "", endIndex),
1725
+ }
1726
+ : null;
1727
+
1728
+ syncBrushOverlay(chart, live, {
1729
+ range,
1730
+ geom,
1731
+ size: { width: chart.getWidth(), height: chart.getHeight() },
1732
+ tokens,
1733
+ labels,
1734
+ showLabels: live.brushHover.inside,
1735
+ hover: live.brushHover,
1736
+ });
1737
+ }, [live]);
1738
+
1739
+ // ── Option builder ─────────────────────────────────────────────────────────
1740
+ // Thin orchestrator over the pure builders above: snapshot the imperative
1741
+ // surface (refs, renderer size) into an OptionBuildContext, then assemble.
1742
+ const buildOption = useCallback((): EChartsOption => {
1743
+ const resolved = live.resolved;
1744
+ if (!resolved) return {};
1745
+
1746
+ const categories = data.map((row) => String(row[xCategoryKey]));
1747
+ live.categories = categories;
1748
+
1749
+ // buildAreaSeries fills this with each area's full per-datum points (with the
1750
+ // multi-color dot itemStyle) so the reveal hover handler slices real data.
1751
+ const revealSink: Record<string, unknown[]> = {};
1752
+
1753
+ const ctx: OptionBuildContext = {
1754
+ data,
1755
+ config,
1756
+ areas,
1757
+ seriesKeys,
1758
+ curveType,
1759
+ isStacked,
1760
+ isExpanded,
1761
+ selectedDataKey,
1762
+ hasSelection,
1763
+ showGrid,
1764
+ xAxisSlot,
1765
+ yAxisSlot,
1766
+ tooltipSlot,
1767
+ legendSlot,
1768
+ isLoading,
1769
+ loadingData,
1770
+ showBrush,
1771
+ brushHeight,
1772
+ enableHoverHighlight,
1773
+ enableHoverReveal,
1774
+ revealIndex: live.revealIndex,
1775
+ resolved,
1776
+ rendererSize: {
1777
+ width: echartsRef.current?.getWidth() ?? mountRef.current?.clientWidth ?? 0,
1778
+ height: echartsRef.current?.getHeight() ?? mountRef.current?.clientHeight ?? 0,
1779
+ },
1780
+ categories,
1781
+ brushRange: live.brushRange,
1782
+ getHoveredKey: () => live.hoveredKey,
1783
+ revealSink,
1784
+ };
1785
+
1786
+ live.plottedTops = computePlottedTops(ctx);
1787
+
1788
+ const { grid, brushBottom } = buildChartLayout(ctx);
1789
+ live.brushGeom = showBrush ? { bottom: brushBottom, height: brushHeight } : null;
1790
+
1791
+ const { xAxis, yAxis } = buildMainAxes(ctx);
1792
+
1793
+ if (isLoading) return buildLoadingOption(ctx, { grid, xAxis, yAxis });
1794
+
1795
+ const brush = showBrush ? buildBrushOption(ctx, brushBottom) : null;
1796
+
1797
+ const series = [...buildAreaSeries(ctx), ...(brush?.miniSeries ?? [])];
1798
+ // buildAreaSeries has now filled revealSink with each area's full per-datum
1799
+ // points — hand them to the hover handler for slicing.
1800
+ if (enableHoverReveal) live.revealValues = revealSink;
1801
+ // Record the exact series order so an area-polygon click (which reports only
1802
+ // a seriesIndex) can recover its key — buffer/reveal/mini/loading series
1803
+ // break the "index === key position" shortcut, so map each index to its id.
1804
+ live.seriesKeyByIndex = series.map((s) => {
1805
+ const id = String(s.id ?? "");
1806
+ return id && !id.startsWith("__") ? id : undefined;
1807
+ });
1808
+ // Map each key to its silent companion series ids (buffer tail, hover-reveal
1809
+ // base), mirroring exactly what buildAreaSeries emits — the hover handlers
1810
+ // highlight/downplay these with the parent so focus:"series" never strands
1811
+ // an area's own forecast tail or muted reveal base apart from it.
1812
+ const companionIdsByKey = new Map<string, string[]>();
1813
+ for (const area of areas) {
1814
+ const ids: string[] = [];
1815
+ if (area.enableBufferLine && data.length >= 2) {
1816
+ ids.push(`${BUFFER_PREFIX}${area.dataKey}`, `${BUFFERFILL_PREFIX}${area.dataKey}`);
1817
+ }
1818
+ if (enableHoverReveal) ids.push(`${REVEAL_PREFIX}${area.dataKey}`);
1819
+ if (ids.length) companionIdsByKey.set(area.dataKey, ids);
1820
+ }
1821
+ live.companionIdsByKey = companionIdsByKey;
1822
+
1823
+ return {
1824
+ animation: false,
1825
+ grid: brush ? [grid, brush.miniGrid] : grid,
1826
+ xAxis: brush ? [xAxis, brush.miniXAxis] : xAxis,
1827
+ yAxis: brush ? [yAxis, brush.miniYAxis] : yAxis,
1828
+ tooltip: buildTooltipOption(ctx),
1829
+ dataZoom: brush?.dataZoom,
1830
+ series,
1831
+ };
1832
+ }, [
1833
+ live,
1834
+ data,
1835
+ config,
1836
+ areas,
1837
+ seriesKeys,
1838
+ xCategoryKey,
1839
+ curveType,
1840
+ isStacked,
1841
+ isExpanded,
1842
+ selectedDataKey,
1843
+ hasSelection,
1844
+ showGrid,
1845
+ xAxisSlot,
1846
+ yAxisSlot,
1847
+ tooltipSlot,
1848
+ legendSlot,
1849
+ isLoading,
1850
+ loadingData,
1851
+ showBrush,
1852
+ brushHeight,
1853
+ enableHoverHighlight,
1854
+ enableHoverReveal,
1855
+ ]);
1856
+
1857
+ // ── Init + resize + theme observer (per renderer instance) ──────────────────
1858
+ useEffect(() => {
1859
+ const mount = mountRef.current;
1860
+ const container = containerRef.current;
1861
+ if (!mount || !container) return;
1862
+
1863
+ // Pointer state belongs to the renderer instance. A renderer switch disposes
1864
+ // that surface without emitting mouseout/globalout, so do not carry a hover,
1865
+ // reveal slice, or brush-hover treatment into the replacement instance.
1866
+ // Keep brushRange: the selected zoom window should survive the switch.
1867
+ live.hoveredKey = null;
1868
+ live.revealIndex = null;
1869
+ live.brushHover = { inside: false, left: false, right: false };
1870
+ setHoveredDataKey(null);
1871
+
1872
+ const chart = echarts.init(mount, null, { renderer });
1873
+ echartsRef.current = chart;
1874
+
1875
+ const resizeObserver = new ResizeObserver(() => {
1876
+ // Observers always fire once right after observe(). Repushing on that
1877
+ // no-op fire would land one frame into the intro and stomp the line's
1878
+ // reveal clip — only react when the renderer size actually changed.
1879
+ if (mount.clientWidth === chart.getWidth() && mount.clientHeight === chart.getHeight()) {
1880
+ return;
1881
+ }
1882
+ chart.resize();
1883
+ // 2D gradient textures are baked at renderer size — rebuild them to fit.
1884
+ live.repush();
1885
+ });
1886
+ resizeObserver.observe(mount);
1887
+
1888
+ // Light/dark flips change no React state — re-resolve and push directly.
1889
+ const themeObserver = new MutationObserver(() => {
1890
+ live.repush();
1891
+ });
1892
+ themeObserver.observe(document.documentElement, {
1893
+ attributes: true,
1894
+ attributeFilter: ["class"],
1895
+ });
1896
+
1897
+ chart.on("click", (params) => {
1898
+ const { clickableKeys: clickable, seriesKeys: keys } = live.handlers;
1899
+ const p = params as {
1900
+ seriesId?: string;
1901
+ seriesIndex?: number;
1902
+ event?: { offsetX?: number; offsetY?: number };
1903
+ };
1904
+ // Symbol clicks carry seriesId; area-polygon clicks (triggerEvent)
1905
+ // only carry seriesIndex — recover the key from the last build's index map,
1906
+ // which accounts for the extra `__buffer-`/`__reveal-`/`__mini-` series
1907
+ // interleaved between the main ones (a raw seriesKeys lookup would miss).
1908
+ let id =
1909
+ p.seriesId ??
1910
+ (typeof p.seriesIndex === "number" ? live.seriesKeyByIndex[p.seriesIndex] : undefined);
1911
+ // Overlapping polygons: the native hit is the topmost series, not the
1912
+ // band the pointer is visually inside — resolve geometrically.
1913
+ if (typeof p.event?.offsetX === "number" && typeof p.event?.offsetY === "number") {
1914
+ const resolved = resolveAreaAtPixel(
1915
+ chart,
1916
+ live.plottedTops,
1917
+ keys,
1918
+ p.event.offsetX,
1919
+ p.event.offsetY,
1920
+ );
1921
+ if (resolved) id = resolved;
1922
+ }
1923
+ if (typeof id === "string" && clickable.has(id)) toggleSelection(id);
1924
+ });
1925
+
1926
+ // Hover-highlight is POINTER-driven, not series-mouseover-driven:
1927
+ // overlapping polygons would pin the native hover on the topmost series and
1928
+ // never re-fire while the pointer moves within it. A zrender mousemove
1929
+ // tracker resolves the visually-hovered band, drives the canvas emphasis
1930
+ // via dispatchAction, and mirrors into the HTML legend (React state) and
1931
+ // tooltip (live.hoveredKey — its formatter runs per pointer move).
1932
+ const applyHoverKey = (key: string | null) => {
1933
+ if (live.hoveredKey === key) return;
1934
+ const previous = live.hoveredKey;
1935
+ live.hoveredKey = key;
1936
+ setHoveredDataKey(key);
1937
+ // Dispatch by seriesId (buffer/reveal series shift the numeric indices), and
1938
+ // link each key's silent companions (buffer tail, reveal base) so
1939
+ // focus:"series" never strands them apart from their parent.
1940
+ if (previous) {
1941
+ chart.dispatchAction({ type: "downplay", seriesId: previous });
1942
+ for (const id of live.companionIdsByKey.get(previous) ?? [])
1943
+ chart.dispatchAction({ type: "downplay", seriesId: id });
1944
+ }
1945
+ if (key) {
1946
+ chart.dispatchAction({ type: "highlight", seriesId: key });
1947
+ for (const id of live.companionIdsByKey.get(key) ?? [])
1948
+ chart.dispatchAction({ type: "highlight", seriesId: id });
1949
+ }
1950
+ };
1951
+
1952
+ // Hover-reveal: color each area up to the pointer's x-index, mute the rest.
1953
+ // Purely TARGETED series updates (real series data + muted base opacity) — we
1954
+ // NEVER rebuild the whole option on mousemove, which would replay transitions
1955
+ // and fight the tooltip's axis pointer.
1956
+ const pushReveal = (idx: number | null) => {
1957
+ const keys = live.handlers.seriesKeys;
1958
+ const on = idx !== null;
1959
+ chart.setOption(
1960
+ {
1961
+ series: keys.flatMap((key) => [
1962
+ {
1963
+ id: key,
1964
+ data: on
1965
+ ? sliceToNull(live.revealValues[key] ?? [], idx)
1966
+ : (live.revealValues[key] ?? []),
1967
+ },
1968
+ {
1969
+ id: `${REVEAL_PREFIX}${key}`,
1970
+ // Gray tail keeps only the region from the cursor onward.
1971
+ data: on
1972
+ ? sliceFrom(live.revealValues[key] ?? [], idx)
1973
+ : (live.revealValues[key] ?? []),
1974
+ lineStyle: { opacity: on ? 0.3 : 0 },
1975
+ },
1976
+ ]),
1977
+ },
1978
+ // NOT lazy: the highlight dispatched just below re-draws the active dot
1979
+ // the setOption wipes, so the option must be committed first — a queued
1980
+ // (lazy) update would land after the dispatch and erase the dot again.
1981
+ { silent: true },
1982
+ );
1983
+ // The per-frame setOption above cancels the axis tooltip's transient hover
1984
+ // symbol, so the <ActiveDot> never lands at the cursor. Re-assert it:
1985
+ // highlighting a real series at the cursor index draws its emphasis symbol
1986
+ // (the active dot) even with showSymbol:false; downplay clears it on exit.
1987
+ for (const key of keys) {
1988
+ chart.dispatchAction(
1989
+ on
1990
+ ? { type: "highlight", seriesId: key, dataIndex: idx as number }
1991
+ : { type: "downplay", seriesId: key },
1992
+ );
1993
+ }
1994
+ };
1995
+ const applyReveal = (event: { offsetX?: number; offsetY?: number }) => {
1996
+ const len = live.dataLength;
1997
+ if (len < 1) return;
1998
+ const x = event.offsetX ?? -1;
1999
+ const y = event.offsetY ?? -1;
2000
+ if (!chart.containPixel({ gridIndex: 0 }, [x, y])) {
2001
+ clearReveal();
2002
+ return;
2003
+ }
2004
+ const raw = chart.convertFromPixel({ gridIndex: 0 }, [x, y])[0];
2005
+ const idx = Math.max(0, Math.min(len - 1, Math.round(raw)));
2006
+ if (idx === live.revealIndex) return;
2007
+ live.revealIndex = idx;
2008
+ pushReveal(idx);
2009
+ };
2010
+ const clearReveal = () => {
2011
+ if (live.revealIndex === null) return;
2012
+ live.revealIndex = null;
2013
+ pushReveal(null);
2014
+ };
2015
+
2016
+ const zrHover = chart.getZr();
2017
+ const onZrHoverMove = (event: { offsetX?: number; offsetY?: number }) => {
2018
+ // Reveal is a standalone hover mode and takes precedence over highlight.
2019
+ if (live.handlers.enableHoverReveal) {
2020
+ applyReveal(event);
2021
+ return;
2022
+ }
2023
+ if (!live.handlers.enableHoverHighlight) return;
2024
+ // A click selection owns the canvas dim — hover highlighting stops
2025
+ // entirely while one exists and resumes once it clears.
2026
+ if (live.handlers.selectedDataKey !== null) return;
2027
+ applyHoverKey(
2028
+ resolveAreaAtPixel(
2029
+ chart,
2030
+ live.plottedTops,
2031
+ live.handlers.seriesKeys,
2032
+ event.offsetX ?? -1,
2033
+ event.offsetY ?? -1,
2034
+ ),
2035
+ );
2036
+ };
2037
+ const onZrHoverOut = () => {
2038
+ if (live.handlers.enableHoverReveal) clearReveal();
2039
+ else if (live.handlers.enableHoverHighlight) applyHoverKey(null);
2040
+ };
2041
+ zrHover.on("mousemove", onZrHoverMove);
2042
+ zrHover.on("globalout", onZrHoverOut);
2043
+
2044
+ // The native hover still emphasizes whichever element the pointer entered —
2045
+ // cancel it whenever it disagrees with the tracker's resolved key.
2046
+ chart.on("mouseover", (params) => {
2047
+ const { enableHoverHighlight: hoverOn, enableHoverReveal: revealOn } = live.handlers;
2048
+ if (!hoverOn || revealOn) return;
2049
+ // While a selection is active, hover highlighting is disabled — never
2050
+ // dispatch emphasis/downplay so the selection dim is the only dimming.
2051
+ if (live.handlers.selectedDataKey !== null) return;
2052
+ const p = params as { seriesIndex?: number; componentType?: string };
2053
+ if (p.componentType !== "series" || typeof p.seriesIndex !== "number") return;
2054
+ const key = live.seriesKeyByIndex[p.seriesIndex];
2055
+ if (!key || key.startsWith("__")) return;
2056
+ if (key !== live.hoveredKey) {
2057
+ chart.dispatchAction({ type: "downplay", seriesIndex: p.seriesIndex });
2058
+ if (live.hoveredKey) {
2059
+ chart.dispatchAction({ type: "highlight", seriesId: live.hoveredKey });
2060
+ }
2061
+ }
2062
+ });
2063
+
2064
+ chart.on("datazoom", () => {
2065
+ const option = chart.getOption() as { dataZoom?: { start?: number; end?: number }[] };
2066
+ const zoom = option.dataZoom?.[0];
2067
+ if (!zoom) return;
2068
+
2069
+ // Ride the selection — pure zrender updates, so the drag stays 1:1.
2070
+ live.brushRange = { start: zoom.start ?? 0, end: zoom.end ?? 100 };
2071
+ syncBrushOverlayNow();
2072
+
2073
+ const { onBrushChange: onChange } = live.handlers;
2074
+ if (!onChange) return;
2075
+ const len = live.dataLength;
2076
+ const startIndex = Math.round(((zoom.start ?? 0) / 100) * (len - 1));
2077
+ const endIndex = Math.round(((zoom.end ?? 100) / 100) * (len - 1));
2078
+ onChange({ startIndex, endIndex });
2079
+ });
2080
+
2081
+ // Hover tracking for the overlay: labels show while the pointer is over the
2082
+ // brush, and each pill brightens when the pointer is near its edge.
2083
+ const zr = chart.getZr();
2084
+ const applyHover = (next: { inside: boolean; left: boolean; right: boolean }) => {
2085
+ const prev = live.brushHover;
2086
+ if (prev.inside === next.inside && prev.left === next.left && prev.right === next.right) {
2087
+ return;
2088
+ }
2089
+ live.brushHover = next;
2090
+ syncBrushOverlayNow();
2091
+ };
2092
+ const onZrMove = (event: { offsetX?: number; offsetY?: number }) => {
2093
+ const geom = live.brushGeom;
2094
+ if (!geom) return;
2095
+ const x = event.offsetX ?? -1;
2096
+ const y = event.offsetY ?? -1;
2097
+ const top = chart.getHeight() - geom.bottom - geom.height;
2098
+ const inside = y >= top - 4 && y <= top + geom.height + 4;
2099
+ const trackLeft = 8;
2100
+ const trackWidth = Math.max(chart.getWidth() - 16, 1);
2101
+ const { start, end } = live.brushRange;
2102
+ const selectionLeft = trackLeft + (trackWidth * start) / 100;
2103
+ const selectionRight = trackLeft + (trackWidth * end) / 100;
2104
+ applyHover({
2105
+ inside,
2106
+ left: inside && Math.abs(x - selectionLeft) <= 8,
2107
+ right: inside && Math.abs(x - selectionRight) <= 8,
2108
+ });
2109
+ };
2110
+ const onZrOut = () => applyHover({ inside: false, left: false, right: false });
2111
+ zr.on("mousemove", onZrMove);
2112
+ zr.on("globalout", onZrOut);
2113
+
2114
+ return () => {
2115
+ zrHover.off("mousemove", onZrHoverMove);
2116
+ zrHover.off("globalout", onZrHoverOut);
2117
+ zr.off("mousemove", onZrMove);
2118
+ zr.off("globalout", onZrOut);
2119
+ resizeObserver.disconnect();
2120
+ themeObserver.disconnect();
2121
+ chart.dispose();
2122
+ echartsRef.current = null;
2123
+ // The overlay elements died with the zrender instance.
2124
+ live.brushOverlay = null;
2125
+ // The reveal guard belongs to the chart instance it guarded. Without this
2126
+ // reset, StrictMode's dev-only mount→unmount→remount plays the entrance on
2127
+ // the throwaway instance and the surviving one renders without it.
2128
+ live.hasRevealed = false;
2129
+ };
2130
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2131
+ }, [renderer]);
2132
+
2133
+ // ── Sync ECharts with props/theme/selection — resolve, build, push ────────────
2134
+ useEffect(() => {
2135
+ const chart = echartsRef.current;
2136
+ const container = containerRef.current;
2137
+ if (!chart || !container) return;
2138
+
2139
+ // Colors come from the <style> committed just before this effect ran — read
2140
+ // them here, right before the push, rather than round-tripping through state.
2141
+ live.resolved = resolveColors(container, config, seriesKeys);
2142
+
2143
+ const push = (withEntrance: boolean) => {
2144
+ const option = buildOption();
2145
+ const merged = chartOptions ? { ...option, ...chartOptions } : option;
2146
+ Object.assign(merged, {
2147
+ animation: withEntrance,
2148
+ animationDuration: REVEAL_DURATION,
2149
+ animationDurationUpdate: 0,
2150
+ });
2151
+ // chartOptions is an untyped escape hatch — the spread erases the option's
2152
+ // shape, so re-assert it. The only cast in the file.
2153
+ chart.setOption(merged as EChartsOption, { notMerge: true });
2154
+ // Overlays live outside the option — reposition them after every push.
2155
+ syncBrushOverlayNow();
2156
+ };
2157
+
2158
+ // Intro reveal — ECharts' native progressive draw, enabled only for the first
2159
+ // real render: the line traces in, dots pop up as its front passes. Every
2160
+ // later push (selection, theme, zoom) applies instantly, since notMerge would
2161
+ // otherwise replay the entrance on each of them. A loading cycle re-arms it:
2162
+ // the Recharts twin unmounts its <Area>s while loading and replays the intro
2163
+ // on remount, so data → loading → data draws in again here too.
2164
+ if (isLoading) live.hasRevealed = false;
2165
+ const shouldReveal = !live.hasRevealed && !isLoading;
2166
+ if (shouldReveal) live.hasRevealed = true;
2167
+ const revealEnabled =
2168
+ animation && shouldReveal && effectiveAnimation !== "none" && !shouldReduceMotion;
2169
+ if (revealEnabled) live.revealEndsAt = performance.now() + REVEAL_DURATION;
2170
+ push(revealEnabled);
2171
+
2172
+ // Theme flips and resizes re-enter here without touching React: re-read the
2173
+ // tokens (the .dark class changed, or textures need renderer-sized rebakes)
2174
+ // and push an update-style option.
2175
+ live.repush = () => {
2176
+ live.resolved = resolveColors(container, config, seriesKeys);
2177
+ push(false);
2178
+ };
2179
+ }, [
2180
+ renderer,
2181
+ live,
2182
+ buildOption,
2183
+ chartOptions,
2184
+ isLoading,
2185
+ animation,
2186
+ effectiveAnimation,
2187
+ shouldReduceMotion,
2188
+ config,
2189
+ seriesKeys,
2190
+ syncBrushOverlayNow,
2191
+ ]);
2192
+
2193
+ // ── Animated dashed stroke — rAF sweeps the dash offset while unselected ─────
2194
+ useEffect(() => {
2195
+ const chart = echartsRef.current;
2196
+ if (!chart || isLoading) return;
2197
+ const animatedKeys = areas
2198
+ .filter((area) => area.strokeVariant === "animated-dashed" && !area.enableBufferLine)
2199
+ .map((area) => area.dataKey);
2200
+ if (animatedKeys.length === 0 || hasSelection) return;
2201
+
2202
+ let raf = 0;
2203
+ let delayTimer: ReturnType<typeof setTimeout> | undefined;
2204
+ const begin = () => {
2205
+ const loopStart = performance.now();
2206
+ const tick = (now: number) => {
2207
+ const offset = -(((now - loopStart) / 1000) % 1) * 6; // 0 → -6 per second
2208
+ chart.setOption(
2209
+ { series: animatedKeys.map((id) => ({ id, lineStyle: { dashOffset: offset } })) },
2210
+ { silent: true, lazyUpdate: true },
2211
+ );
2212
+ raf = requestAnimationFrame(tick);
2213
+ };
2214
+ raf = requestAnimationFrame(tick);
2215
+ };
2216
+
2217
+ // Per-frame setOption churn fights the intro draw-in (each update pass
2218
+ // recomputes the reveal clip, crawling it to a standstill) — hold the dash
2219
+ // sweep until the entrance has finished.
2220
+ const delay = Math.max(0, live.revealEndsAt - performance.now());
2221
+ if (delay > 0) delayTimer = setTimeout(begin, delay + 50);
2222
+ else begin();
2223
+
2224
+ return () => {
2225
+ if (delayTimer !== undefined) clearTimeout(delayTimer);
2226
+ cancelAnimationFrame(raf);
2227
+ };
2228
+ }, [renderer, live, areas, hasSelection, isLoading]);
2229
+
2230
+ // ── Loading shimmer — rAF sweeps a bright band, regenerating data off-screen ─
2231
+ useEffect(() => {
2232
+ const chart = echartsRef.current;
2233
+ if (!chart || !isLoading) return;
2234
+
2235
+ let raf = 0;
2236
+ let lastPhase = 0;
2237
+ const start = performance.now();
2238
+ const tick = (now: number) => {
2239
+ const phase = ((((now - start) / LOADING_ANIMATION_DURATION) % 1) + 1) % 1;
2240
+ // Wrapped past 1 → the band is off-screen; swap in fresh random data.
2241
+ if (phase < lastPhase) live.loadingRows = getLoadingData(loadingPoints);
2242
+ lastPhase = phase;
2243
+
2244
+ // Read tokens per frame, so a theme flip mid-loading retints the shimmer.
2245
+ const foreground = live.resolved?.tokens.foreground ?? "rgba(120, 120, 120, 1)";
2246
+ // Sweep the clip window from fully off-screen left to fully off-screen
2247
+ // right, leaned 45°. The gradient uses ABSOLUTE pixel coordinates shared
2248
+ // by stroke and fill — bbox-relative coords put the window at different
2249
+ // positions for the line vs the area polygon (their bounding boxes
2250
+ // differ), which made the line trail the fill near the sweep's end.
2251
+ const w = chart.getWidth();
2252
+ const h = chart.getHeight();
2253
+ if (!w || !h) {
2254
+ raf = requestAnimationFrame(tick);
2255
+ return;
2256
+ }
2257
+ // Farthest plot corner projected onto the 45° axis — keeps the sweep
2258
+ // tight instead of dawdling off-plot at the end of each loop.
2259
+ const maxT = (w + h) / (2 * w);
2260
+ const center = phase * (maxT + 2 * LOADING_SHIMMER_BAND) - LOADING_SHIMMER_BAND;
2261
+ const clip = (peak: number) =>
2262
+ new echarts.graphic.LinearGradient(
2263
+ 0,
2264
+ 0,
2265
+ w,
2266
+ w,
2267
+ shimmerWindowStops(center, foreground, peak),
2268
+ true,
2269
+ );
2270
+ chart.setOption(
2271
+ {
2272
+ series: [
2273
+ {
2274
+ id: "__loading",
2275
+ data: loadingData(),
2276
+ lineStyle: { color: clip(LOADING_STROKE_OPACITY), width: 1 },
2277
+ areaStyle: { color: clip(LOADING_SHIMMER_MAX_OPACITY) },
2278
+ },
2279
+ ],
2280
+ },
2281
+ { silent: true, lazyUpdate: true },
2282
+ );
2283
+ raf = requestAnimationFrame(tick);
2284
+ };
2285
+ raf = requestAnimationFrame(tick);
2286
+ return () => cancelAnimationFrame(raf);
2287
+ }, [renderer, live, isLoading, loadingPoints, loadingData]);
2288
+
2289
+ // ── Legend overlay position ──────────────────────────────────────────────────
2290
+ // Insets match the Recharts legend's breathing room inside the plot frame.
2291
+ const legendStyle: CSSProperties = {
2292
+ position: "absolute",
2293
+ left: 16,
2294
+ right: 16,
2295
+ pointerEvents: "auto",
2296
+ ...(legendSlot.verticalAlign === "top"
2297
+ ? { top: 12 }
2298
+ : legendSlot.verticalAlign === "bottom"
2299
+ ? { bottom: showBrush ? brushHeight + 16 : 12 }
2300
+ : { top: "50%", transform: "translateY(-50%)" }),
2301
+ };
2302
+
2303
+ return (
2304
+ <div
2305
+ ref={containerRef}
2306
+ data-chart={chartId}
2307
+ className={`relative flex flex-col text-xs ${className ?? ""}`}
2308
+ >
2309
+ <style dangerouslySetInnerHTML={{ __html: css }} />
2310
+
2311
+ <div className="relative min-h-0 w-full flex-1">
2312
+ <div ref={mountRef} className="h-full min-h-0 w-full" />
2313
+ </div>
2314
+
2315
+ {legendSlot.present && !isLoading && (
2316
+ <LegendOverlay
2317
+ seriesKeys={seriesKeys}
2318
+ config={config}
2319
+ variant={legendSlot.variant}
2320
+ align={legendSlot.align}
2321
+ verticalAlign={legendSlot.verticalAlign}
2322
+ selectedKey={selectedDataKey}
2323
+ hoveredKey={hoveredDataKey}
2324
+ isClickable={legendSlot.isClickable}
2325
+ onToggle={toggleSelection}
2326
+ style={legendStyle}
2327
+ />
2328
+ )}
2329
+
2330
+ {isLoading && (
2331
+ <div className="pointer-events-none absolute inset-0 z-20 flex items-center justify-center">
2332
+ <motion.div
2333
+ initial={shouldReduceMotion ? false : { opacity: 0, scale: 0.92 }}
2334
+ animate={{ opacity: 1, scale: 1 }}
2335
+ transition={{ duration: 0.25, ease: "easeOut" }}
2336
+ className="text-primary bg-background flex items-center justify-center gap-2 rounded-md border px-2 py-0.5 text-sm"
2337
+ >
2338
+ <div className="border-border border-t-primary h-3 w-3 animate-spin rounded-full border" />
2339
+ <span>Loading</span>
2340
+ </motion.div>
2341
+ </div>
2342
+ )}
2343
+ </div>
2344
+ );
2345
+ }
2346
+
2347
+ // Compound API: every part hangs off the root as a static member, so a consumer
2348
+ // writes <EChartsAreaChart.Area/>, <EChartsAreaChart.Tooltip/>, … from a single
2349
+ // import — no colliding named marker exports when several charts share one file.
2350
+ EChartsAreaChart.Area = Area;
2351
+ EChartsAreaChart.Dot = Dot;
2352
+ EChartsAreaChart.ActiveDot = ActiveDot;
2353
+ EChartsAreaChart.XAxis = XAxis;
2354
+ EChartsAreaChart.YAxis = YAxis;
2355
+ EChartsAreaChart.Grid = Grid;
2356
+ EChartsAreaChart.Tooltip = Tooltip;
2357
+ EChartsAreaChart.Legend = Legend;
2358
+ EChartsAreaChart.Brush = Brush;