@yewdiel21/motion-kit 0.10.0 → 0.15.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 (459) hide show
  1. package/README.md +81 -0
  2. package/bin/motion-kit.mjs +3 -3
  3. package/dist/auto/index.d.ts +56 -3
  4. package/dist/auto/index.js +107 -3
  5. package/dist/auto/index.js.map +1 -1
  6. package/dist/{chunk-XAKC2QY7.js → chunk-6IRJYXJU.js} +3 -28
  7. package/dist/chunk-6IRJYXJU.js.map +1 -0
  8. package/dist/chunk-A6QQCF6V.js +21333 -0
  9. package/dist/chunk-A6QQCF6V.js.map +1 -0
  10. package/dist/chunk-JXRS3OEA.js +3638 -0
  11. package/dist/chunk-JXRS3OEA.js.map +1 -0
  12. package/dist/chunk-QP4QJOEN.js +72 -0
  13. package/dist/chunk-QP4QJOEN.js.map +1 -0
  14. package/dist/css/components/activity-feed.css +240 -0
  15. package/dist/css/components/add-to-cart.css +72 -0
  16. package/dist/css/components/attachment.css +266 -0
  17. package/dist/css/components/bidirectional-slider.css +168 -0
  18. package/dist/css/components/breadcrumb.css +110 -0
  19. package/dist/css/components/chart-tooltip.css +168 -0
  20. package/dist/css/components/chart.css +296 -0
  21. package/dist/css/components/code-block.css +264 -0
  22. package/dist/css/components/color-area.css +82 -0
  23. package/dist/css/components/color-field.css +67 -0
  24. package/dist/css/components/color-picker.css +131 -0
  25. package/dist/css/components/color-slider.css +113 -0
  26. package/dist/css/components/command-search.css +252 -0
  27. package/dist/css/components/context-menu.css +23 -0
  28. package/dist/css/components/credit-card.css +288 -0
  29. package/dist/css/components/data-table.css +686 -0
  30. package/dist/css/components/date-range-picker.css +168 -0
  31. package/dist/css/components/date-time-picker.css +178 -0
  32. package/dist/css/components/drawer.css +58 -0
  33. package/dist/css/components/editable-table.css +201 -0
  34. package/dist/css/components/empty-state.css +61 -0
  35. package/dist/css/components/file-explorer.css +633 -0
  36. package/dist/css/components/filter-builder.css +227 -0
  37. package/dist/css/components/heatmap-chart.css +391 -0
  38. package/dist/css/components/hold-confirm.css +87 -0
  39. package/dist/css/components/hover-card.css +19 -7
  40. package/dist/css/components/image-preview.css +283 -0
  41. package/dist/css/components/json-viewer.css +304 -0
  42. package/dist/css/components/like-button.css +78 -0
  43. package/dist/css/components/link-preview.css +275 -0
  44. package/dist/css/components/loading-button.css +77 -0
  45. package/dist/css/components/multi-select.css +267 -0
  46. package/dist/css/components/nav.css +102 -102
  47. package/dist/css/components/notification-bell.css +127 -0
  48. package/dist/css/components/orbit-menu.css +130 -0
  49. package/dist/css/components/pagination.css +10 -5
  50. package/dist/css/components/password-strength.css +183 -0
  51. package/dist/css/components/pie-chart.css +390 -0
  52. package/dist/css/components/pill-button.css +135 -0
  53. package/dist/css/components/popover.css +25 -0
  54. package/dist/css/components/progress.css +140 -0
  55. package/dist/css/components/questionnaire.css +217 -0
  56. package/dist/css/components/radar-chart.css +370 -0
  57. package/dist/css/components/radial-chart.css +398 -0
  58. package/dist/css/components/range-calendar.css +186 -0
  59. package/dist/css/components/range-slider.css +192 -0
  60. package/dist/css/components/resizable-panel.css +243 -0
  61. package/dist/css/components/rich-text-editor.css +284 -0
  62. package/dist/css/components/sankey-chart.css +358 -0
  63. package/dist/css/components/scratch-card.css +75 -0
  64. package/dist/css/components/scroll-island.css +111 -0
  65. package/dist/css/components/select.css +136 -0
  66. package/dist/css/components/skeleton.css +108 -0
  67. package/dist/css/components/split-view.css +19 -0
  68. package/dist/css/components/star-rating.css +80 -0
  69. package/dist/css/components/stat-card.css +164 -0
  70. package/dist/css/components/swipe-actions.css +105 -0
  71. package/dist/css/components/tag-input.css +244 -0
  72. package/dist/css/components/time-field.css +88 -0
  73. package/dist/css/components/timeline.css +219 -0
  74. package/dist/css/components/toolbar.css +122 -0
  75. package/dist/css/components/tooltip.css +79 -0
  76. package/dist/css/components/tree-view.css +289 -0
  77. package/dist/css/components/virtual-list.css +195 -0
  78. package/dist/css/components/voice-dots.css +70 -0
  79. package/dist/css/tokens.css +185 -181
  80. package/dist/elements/index.d.ts +849 -7
  81. package/dist/elements/index.js +1642 -8
  82. package/dist/elements/index.js.map +1 -1
  83. package/dist/{engine-GDGwQnJE.d.ts → engine-5zRIssTO.d.ts} +11 -1
  84. package/dist/engine-QECQnGz1.d.ts +33 -0
  85. package/dist/index.css +10890 -311
  86. package/dist/index.d.ts +89 -5
  87. package/dist/index.js +273 -9
  88. package/dist/index.js.map +1 -1
  89. package/dist/react/index.d.ts +686 -24
  90. package/dist/react/index.js +2345 -9
  91. package/dist/react/index.js.map +1 -1
  92. package/dist/{reduced-BmBzKH94.d.ts → reduced-6X_bns60.d.ts} +9 -2
  93. package/dist/reveal-BfyKKsw4.d.ts +2474 -0
  94. package/dist/store-CA2Qcun_.d.ts +453 -0
  95. package/package.json +9 -16
  96. package/registry.json +1096 -543
  97. package/src/auto/auto-init.ts +104 -0
  98. package/src/components/activity-feed/README.md +56 -0
  99. package/src/components/activity-feed/activity-feed.css +239 -0
  100. package/src/components/activity-feed/element.ts +36 -0
  101. package/src/components/activity-feed/engine.ts +351 -0
  102. package/src/components/activity-feed/react.tsx +32 -0
  103. package/src/components/add-to-cart/README.md +34 -0
  104. package/src/components/add-to-cart/add-to-cart.css +71 -0
  105. package/src/components/add-to-cart/element.ts +20 -0
  106. package/src/components/add-to-cart/engine.ts +206 -0
  107. package/src/components/add-to-cart/react.tsx +29 -0
  108. package/src/components/attachment/README.md +27 -0
  109. package/src/components/attachment/attachment.css +265 -0
  110. package/src/components/attachment/element.ts +50 -0
  111. package/src/components/attachment/engine.ts +469 -0
  112. package/src/components/attachment/react.tsx +65 -0
  113. package/src/components/bidirectional-slider/README.md +46 -0
  114. package/src/components/bidirectional-slider/bidirectional-slider.css +167 -0
  115. package/src/components/bidirectional-slider/element.ts +42 -0
  116. package/src/components/bidirectional-slider/engine.ts +289 -0
  117. package/src/components/bidirectional-slider/react.tsx +45 -0
  118. package/src/components/breadcrumb/README.md +38 -0
  119. package/src/components/breadcrumb/breadcrumb.css +109 -0
  120. package/src/components/breadcrumb/element.ts +27 -0
  121. package/src/components/breadcrumb/engine.ts +249 -0
  122. package/src/components/breadcrumb/react.tsx +30 -0
  123. package/src/components/chart/README.md +34 -0
  124. package/src/components/chart/chart.css +295 -0
  125. package/src/components/chart/element.ts +43 -0
  126. package/src/components/chart/engine.ts +838 -0
  127. package/src/components/chart/parts.ts +237 -0
  128. package/src/components/chart/react.tsx +50 -0
  129. package/src/components/chart/use-chart.ts +55 -0
  130. package/src/components/chart-tooltip/README.md +53 -0
  131. package/src/components/chart-tooltip/chart-tooltip.css +167 -0
  132. package/src/components/chart-tooltip/element.ts +37 -0
  133. package/src/components/chart-tooltip/engine.ts +442 -0
  134. package/src/components/chart-tooltip/react.tsx +47 -0
  135. package/src/components/code-block/README.md +19 -0
  136. package/src/components/code-block/code-block.css +263 -0
  137. package/src/components/code-block/element.ts +34 -0
  138. package/src/components/code-block/engine.ts +254 -0
  139. package/src/components/code-block/highlight.ts +244 -0
  140. package/src/components/code-block/react.tsx +94 -0
  141. package/src/components/color-area/README.md +50 -0
  142. package/src/components/color-area/color-area.css +81 -0
  143. package/src/components/color-area/element.ts +26 -0
  144. package/src/components/color-area/engine.ts +246 -0
  145. package/src/components/color-area/react.tsx +42 -0
  146. package/src/components/color-field/README.md +43 -0
  147. package/src/components/color-field/color-field.css +66 -0
  148. package/src/components/color-field/element.ts +26 -0
  149. package/src/components/color-field/engine.ts +174 -0
  150. package/src/components/color-field/react.tsx +42 -0
  151. package/src/components/color-picker/README.md +45 -0
  152. package/src/components/color-picker/color-picker.css +130 -0
  153. package/src/components/color-picker/element.ts +45 -0
  154. package/src/components/color-picker/engine.ts +314 -0
  155. package/src/components/color-picker/react.tsx +47 -0
  156. package/src/components/color-slider/README.md +55 -0
  157. package/src/components/color-slider/color-slider.css +112 -0
  158. package/src/components/color-slider/element.ts +26 -0
  159. package/src/components/color-slider/engine.ts +234 -0
  160. package/src/components/color-slider/react.tsx +45 -0
  161. package/src/components/command-search/README.md +15 -0
  162. package/src/components/command-search/command-search.css +251 -0
  163. package/src/components/command-search/element.ts +36 -0
  164. package/src/components/command-search/engine.ts +356 -0
  165. package/src/components/command-search/match.ts +53 -0
  166. package/src/components/command-search/react.tsx +66 -0
  167. package/src/components/context-menu/README.md +31 -0
  168. package/src/components/context-menu/context-menu.css +22 -0
  169. package/src/components/context-menu/element.ts +40 -0
  170. package/src/components/context-menu/engine.ts +153 -0
  171. package/src/components/context-menu/react.tsx +57 -0
  172. package/src/components/credit-card/README.md +20 -0
  173. package/src/components/credit-card/card.ts +77 -0
  174. package/src/components/credit-card/credit-card.css +287 -0
  175. package/src/components/credit-card/element.ts +33 -0
  176. package/src/components/credit-card/engine.ts +410 -0
  177. package/src/components/credit-card/react.tsx +36 -0
  178. package/src/components/data-table/README.md +83 -0
  179. package/src/components/data-table/data-table.css +685 -0
  180. package/src/components/data-table/element.ts +54 -0
  181. package/src/components/data-table/engine.ts +1111 -0
  182. package/src/components/data-table/react.tsx +94 -0
  183. package/src/components/date-range-picker/README.md +51 -0
  184. package/src/components/date-range-picker/date-range-picker.css +167 -0
  185. package/src/components/date-range-picker/element.ts +52 -0
  186. package/src/components/date-range-picker/engine.ts +352 -0
  187. package/src/components/date-range-picker/react.tsx +57 -0
  188. package/src/components/date-time-picker/README.md +48 -0
  189. package/src/components/date-time-picker/date-time-picker.css +177 -0
  190. package/src/components/date-time-picker/element.ts +47 -0
  191. package/src/components/date-time-picker/engine.ts +350 -0
  192. package/src/components/date-time-picker/react.tsx +54 -0
  193. package/src/components/dialog/README.md +103 -102
  194. package/src/components/dialog/element.ts +123 -118
  195. package/src/components/dialog/engine.ts +449 -432
  196. package/src/components/drawer/README.md +28 -0
  197. package/src/components/drawer/drawer.css +57 -0
  198. package/src/components/drawer/element.ts +21 -0
  199. package/src/components/drawer/engine.ts +56 -0
  200. package/src/components/drawer/react.tsx +85 -0
  201. package/src/components/editable-table/README.md +67 -0
  202. package/src/components/editable-table/editable-table.css +200 -0
  203. package/src/components/editable-table/element.ts +45 -0
  204. package/src/components/editable-table/engine.ts +831 -0
  205. package/src/components/editable-table/react.tsx +79 -0
  206. package/src/components/empty-state/README.md +41 -0
  207. package/src/components/empty-state/element.ts +23 -0
  208. package/src/components/empty-state/empty-state.css +60 -0
  209. package/src/components/empty-state/engine.ts +232 -0
  210. package/src/components/empty-state/react.tsx +34 -0
  211. package/src/components/file-explorer/README.md +67 -0
  212. package/src/components/file-explorer/element.ts +39 -0
  213. package/src/components/file-explorer/engine.ts +1307 -0
  214. package/src/components/file-explorer/file-explorer.css +632 -0
  215. package/src/components/file-explorer/react.tsx +77 -0
  216. package/src/components/filter-builder/README.md +47 -0
  217. package/src/components/filter-builder/element.ts +34 -0
  218. package/src/components/filter-builder/engine.ts +396 -0
  219. package/src/components/filter-builder/filter-builder.css +226 -0
  220. package/src/components/filter-builder/react.tsx +36 -0
  221. package/src/components/heatmap-chart/README.md +48 -0
  222. package/src/components/heatmap-chart/element.ts +21 -0
  223. package/src/components/heatmap-chart/engine.ts +281 -0
  224. package/src/components/heatmap-chart/heatmap-chart.css +93 -0
  225. package/src/components/heatmap-chart/react.tsx +14 -0
  226. package/src/components/hold-confirm/README.md +13 -0
  227. package/src/components/hold-confirm/element.ts +24 -0
  228. package/src/components/hold-confirm/engine.ts +216 -0
  229. package/src/components/hold-confirm/hold-confirm.css +86 -0
  230. package/src/components/hold-confirm/react.tsx +28 -0
  231. package/src/components/hover-card/README.md +6 -2
  232. package/src/components/hover-card/engine.ts +98 -7
  233. package/src/components/hover-card/hover-card.css +19 -7
  234. package/src/components/image-preview/README.md +16 -0
  235. package/src/components/image-preview/element.ts +26 -0
  236. package/src/components/image-preview/engine.ts +405 -0
  237. package/src/components/image-preview/image-preview.css +282 -0
  238. package/src/components/image-preview/react.tsx +43 -0
  239. package/src/components/json-viewer/README.md +56 -0
  240. package/src/components/json-viewer/element.ts +37 -0
  241. package/src/components/json-viewer/engine.ts +449 -0
  242. package/src/components/json-viewer/json-viewer.css +303 -0
  243. package/src/components/json-viewer/react.tsx +56 -0
  244. package/src/components/like-button/README.md +13 -0
  245. package/src/components/like-button/element.ts +47 -0
  246. package/src/components/like-button/engine.ts +145 -0
  247. package/src/components/like-button/like-button.css +77 -0
  248. package/src/components/like-button/react.tsx +39 -0
  249. package/src/components/link-preview/README.md +19 -0
  250. package/src/components/link-preview/element.ts +29 -0
  251. package/src/components/link-preview/engine.ts +192 -0
  252. package/src/components/link-preview/link-preview.css +274 -0
  253. package/src/components/link-preview/react.tsx +101 -0
  254. package/src/components/loading-button/README.md +45 -0
  255. package/src/components/loading-button/element.ts +34 -0
  256. package/src/components/loading-button/engine.ts +201 -0
  257. package/src/components/loading-button/loading-button.css +76 -0
  258. package/src/components/loading-button/react.tsx +43 -0
  259. package/src/components/multi-select/README.md +48 -0
  260. package/src/components/multi-select/element.ts +28 -0
  261. package/src/components/multi-select/engine.ts +294 -0
  262. package/src/components/multi-select/multi-select.css +266 -0
  263. package/src/components/multi-select/react.tsx +39 -0
  264. package/src/components/nav/README.md +12 -10
  265. package/src/components/nav/element.ts +5 -5
  266. package/src/components/nav/engine.ts +21 -14
  267. package/src/components/nav/nav.css +102 -102
  268. package/src/components/nav/react.tsx +4 -4
  269. package/src/components/notification-bell/README.md +14 -0
  270. package/src/components/notification-bell/element.ts +48 -0
  271. package/src/components/notification-bell/engine.ts +202 -0
  272. package/src/components/notification-bell/notification-bell.css +126 -0
  273. package/src/components/notification-bell/react.tsx +57 -0
  274. package/src/components/orbit-menu/README.md +46 -0
  275. package/src/components/orbit-menu/element.ts +27 -0
  276. package/src/components/orbit-menu/engine.ts +179 -0
  277. package/src/components/orbit-menu/orbit-menu.css +129 -0
  278. package/src/components/orbit-menu/react.tsx +44 -0
  279. package/src/components/pagination/README.md +1 -1
  280. package/src/components/pagination/engine.ts +50 -4
  281. package/src/components/pagination/pagination.css +10 -5
  282. package/src/components/password-strength/README.md +17 -0
  283. package/src/components/password-strength/element.ts +22 -0
  284. package/src/components/password-strength/engine.ts +212 -0
  285. package/src/components/password-strength/password-strength.css +182 -0
  286. package/src/components/password-strength/react.tsx +36 -0
  287. package/src/components/password-strength/score.ts +62 -0
  288. package/src/components/pie-chart/README.md +48 -0
  289. package/src/components/pie-chart/element.ts +30 -0
  290. package/src/components/pie-chart/engine.ts +283 -0
  291. package/src/components/pie-chart/pie-chart.css +92 -0
  292. package/src/components/pie-chart/react.tsx +14 -0
  293. package/src/components/pill-button/README.md +46 -0
  294. package/src/components/pill-button/element.ts +16 -0
  295. package/src/components/pill-button/engine.ts +77 -0
  296. package/src/components/pill-button/pill-button.css +134 -0
  297. package/src/components/pill-button/react.tsx +32 -0
  298. package/src/components/popover/README.md +44 -0
  299. package/src/components/popover/element.ts +31 -0
  300. package/src/components/popover/engine.ts +114 -0
  301. package/src/components/popover/popover.css +24 -0
  302. package/src/components/popover/react.tsx +50 -0
  303. package/src/components/progress/README.md +17 -0
  304. package/src/components/progress/element.ts +30 -0
  305. package/src/components/progress/engine.ts +173 -0
  306. package/src/components/progress/progress.css +139 -0
  307. package/src/components/progress/react.tsx +35 -0
  308. package/src/components/questionnaire/README.md +32 -0
  309. package/src/components/questionnaire/element.ts +118 -0
  310. package/src/components/questionnaire/engine.ts +255 -0
  311. package/src/components/questionnaire/questionnaire.css +216 -0
  312. package/src/components/questionnaire/react.tsx +140 -0
  313. package/src/components/radar-chart/README.md +48 -0
  314. package/src/components/radar-chart/element.ts +30 -0
  315. package/src/components/radar-chart/engine.ts +327 -0
  316. package/src/components/radar-chart/radar-chart.css +72 -0
  317. package/src/components/radar-chart/react.tsx +14 -0
  318. package/src/components/radial-chart/README.md +48 -0
  319. package/src/components/radial-chart/element.ts +30 -0
  320. package/src/components/radial-chart/engine.ts +290 -0
  321. package/src/components/radial-chart/radial-chart.css +100 -0
  322. package/src/components/radial-chart/react.tsx +14 -0
  323. package/src/components/range-calendar/README.md +58 -0
  324. package/src/components/range-calendar/element.ts +42 -0
  325. package/src/components/range-calendar/engine.ts +390 -0
  326. package/src/components/range-calendar/range-calendar.css +185 -0
  327. package/src/components/range-calendar/react.tsx +56 -0
  328. package/src/components/range-slider/README.md +23 -0
  329. package/src/components/range-slider/element.ts +53 -0
  330. package/src/components/range-slider/engine.ts +316 -0
  331. package/src/components/range-slider/range-slider.css +191 -0
  332. package/src/components/range-slider/react.tsx +66 -0
  333. package/src/components/resizable-panel/README.md +61 -0
  334. package/src/components/resizable-panel/element.ts +36 -0
  335. package/src/components/resizable-panel/engine.ts +551 -0
  336. package/src/components/resizable-panel/react.tsx +74 -0
  337. package/src/components/resizable-panel/resizable-panel.css +242 -0
  338. package/src/components/rich-text-editor/README.md +57 -0
  339. package/src/components/rich-text-editor/element.ts +34 -0
  340. package/src/components/rich-text-editor/engine.ts +673 -0
  341. package/src/components/rich-text-editor/react.tsx +60 -0
  342. package/src/components/rich-text-editor/rich-text-editor.css +283 -0
  343. package/src/components/sankey-chart/README.md +48 -0
  344. package/src/components/sankey-chart/element.ts +31 -0
  345. package/src/components/sankey-chart/engine.ts +401 -0
  346. package/src/components/sankey-chart/react.tsx +14 -0
  347. package/src/components/sankey-chart/sankey-chart.css +60 -0
  348. package/src/components/scratch-card/README.md +15 -0
  349. package/src/components/scratch-card/element.ts +30 -0
  350. package/src/components/scratch-card/engine.ts +257 -0
  351. package/src/components/scratch-card/react.tsx +40 -0
  352. package/src/components/scratch-card/scratch-card.css +74 -0
  353. package/src/components/scroll-island/README.md +34 -0
  354. package/src/components/scroll-island/element.ts +16 -0
  355. package/src/components/scroll-island/engine.ts +252 -0
  356. package/src/components/scroll-island/react.tsx +26 -0
  357. package/src/components/scroll-island/scroll-island.css +110 -0
  358. package/src/components/select/README.md +34 -0
  359. package/src/components/select/element.ts +26 -0
  360. package/src/components/select/engine.ts +267 -0
  361. package/src/components/select/react.tsx +33 -0
  362. package/src/components/select/select.css +135 -0
  363. package/src/components/skeleton/README.md +15 -0
  364. package/src/components/skeleton/element.ts +32 -0
  365. package/src/components/skeleton/engine.ts +104 -0
  366. package/src/components/skeleton/react.tsx +41 -0
  367. package/src/components/skeleton/skeleton.css +107 -0
  368. package/src/components/split-view/README.md +50 -0
  369. package/src/components/split-view/element.ts +34 -0
  370. package/src/components/split-view/engine.ts +114 -0
  371. package/src/components/split-view/react.tsx +63 -0
  372. package/src/components/split-view/split-view.css +18 -0
  373. package/src/components/star-rating/README.md +14 -0
  374. package/src/components/star-rating/element.ts +26 -0
  375. package/src/components/star-rating/engine.ts +217 -0
  376. package/src/components/star-rating/react.tsx +33 -0
  377. package/src/components/star-rating/star-rating.css +79 -0
  378. package/src/components/stat-card/README.md +42 -0
  379. package/src/components/stat-card/element.ts +40 -0
  380. package/src/components/stat-card/engine.ts +283 -0
  381. package/src/components/stat-card/react.tsx +36 -0
  382. package/src/components/stat-card/stat-card.css +163 -0
  383. package/src/components/swipe-actions/README.md +19 -0
  384. package/src/components/swipe-actions/element.ts +26 -0
  385. package/src/components/swipe-actions/engine.ts +260 -0
  386. package/src/components/swipe-actions/react.tsx +80 -0
  387. package/src/components/swipe-actions/swipe-actions.css +104 -0
  388. package/src/components/tag-input/README.md +42 -0
  389. package/src/components/tag-input/element.ts +39 -0
  390. package/src/components/tag-input/engine.ts +313 -0
  391. package/src/components/tag-input/react.tsx +54 -0
  392. package/src/components/tag-input/tag-input.css +243 -0
  393. package/src/components/time-field/README.md +54 -0
  394. package/src/components/time-field/element.ts +38 -0
  395. package/src/components/time-field/engine.ts +110 -0
  396. package/src/components/time-field/react.tsx +45 -0
  397. package/src/components/time-field/time-field.css +87 -0
  398. package/src/components/timeline/README.md +57 -0
  399. package/src/components/timeline/element.ts +31 -0
  400. package/src/components/timeline/engine.ts +300 -0
  401. package/src/components/timeline/react.tsx +59 -0
  402. package/src/components/timeline/timeline.css +218 -0
  403. package/src/components/toolbar/README.md +46 -0
  404. package/src/components/toolbar/element.ts +30 -0
  405. package/src/components/toolbar/engine.ts +230 -0
  406. package/src/components/toolbar/react.tsx +34 -0
  407. package/src/components/toolbar/toolbar.css +121 -0
  408. package/src/components/tooltip/README.md +46 -0
  409. package/src/components/tooltip/element.ts +22 -0
  410. package/src/components/tooltip/engine.ts +288 -0
  411. package/src/components/tooltip/react.tsx +30 -0
  412. package/src/components/tooltip/tooltip.css +78 -0
  413. package/src/components/tree-view/README.md +61 -0
  414. package/src/components/tree-view/element.ts +32 -0
  415. package/src/components/tree-view/engine.ts +743 -0
  416. package/src/components/tree-view/react.tsx +82 -0
  417. package/src/components/tree-view/tree-view.css +288 -0
  418. package/src/components/virtual-list/README.md +81 -0
  419. package/src/components/virtual-list/element.ts +42 -0
  420. package/src/components/virtual-list/engine.ts +678 -0
  421. package/src/components/virtual-list/react.tsx +101 -0
  422. package/src/components/virtual-list/virtual-list.css +194 -0
  423. package/src/components/voice-dots/README.md +48 -0
  424. package/src/components/voice-dots/element.ts +45 -0
  425. package/src/components/voice-dots/engine.ts +243 -0
  426. package/src/components/voice-dots/react.tsx +52 -0
  427. package/src/components/voice-dots/voice-dots.css +69 -0
  428. package/src/core/chips.ts +196 -0
  429. package/src/core/color.ts +304 -0
  430. package/src/core/date-range.ts +67 -0
  431. package/src/core/dates.ts +11 -1
  432. package/src/core/files.ts +107 -0
  433. package/src/core/filter.ts +229 -0
  434. package/src/core/gsap.ts +80 -65
  435. package/src/core/listbox.ts +332 -0
  436. package/src/core/mark.ts +29 -0
  437. package/src/core/position.ts +89 -0
  438. package/src/core/relative-time.ts +77 -0
  439. package/src/core/segment-field.ts +373 -0
  440. package/src/core/segments.ts +153 -0
  441. package/src/core/tree.ts +116 -0
  442. package/src/core/virtual.ts +79 -0
  443. package/src/css/tokens.css +186 -182
  444. package/src/elements/index.ts +186 -0
  445. package/src/index.ts +88 -0
  446. package/src/motion/liquid.ts +14 -4
  447. package/src/motion/micro.ts +248 -0
  448. package/src/motion/sheet.ts +88 -65
  449. package/src/motion/surface.ts +9 -0
  450. package/src/react/index.ts +71 -1
  451. package/dist/chunk-IKQ5FODN.js +0 -1617
  452. package/dist/chunk-IKQ5FODN.js.map +0 -1
  453. package/dist/chunk-J6OCFNGU.js +0 -177
  454. package/dist/chunk-J6OCFNGU.js.map +0 -1
  455. package/dist/chunk-TFNRIZHU.js +0 -3977
  456. package/dist/chunk-TFNRIZHU.js.map +0 -1
  457. package/dist/chunk-XAKC2QY7.js.map +0 -1
  458. package/dist/reveal-jsX-uwUz.d.ts +0 -625
  459. package/dist/store-DYb3tTsZ.d.ts +0 -195
@@ -0,0 +1,3638 @@
1
+ import {
2
+ EASE,
3
+ Flip,
4
+ addDays,
5
+ bezier,
6
+ blurIn,
7
+ capitalize,
8
+ channels,
9
+ dayKey,
10
+ easeInCubic,
11
+ easeOut,
12
+ easeOutCubic,
13
+ eased,
14
+ flowIn,
15
+ flowInPalette,
16
+ gsap,
17
+ motionSpring,
18
+ press,
19
+ registerMotion,
20
+ revealFrom,
21
+ rollDigits,
22
+ safeFormat,
23
+ splitGraphemes,
24
+ splitWords,
25
+ spring,
26
+ springEase,
27
+ startOfWeek,
28
+ toDate,
29
+ weekdayNames
30
+ } from "./chunk-A6QQCF6V.js";
31
+ import {
32
+ THEMES,
33
+ THEME_EVENT,
34
+ getTheme,
35
+ setTheme
36
+ } from "./chunk-RVSKEBIC.js";
37
+ import {
38
+ TIMING,
39
+ createScope,
40
+ entrances,
41
+ reduced,
42
+ subscribe,
43
+ whileVisible
44
+ } from "./chunk-DOOMULVV.js";
45
+ import {
46
+ inert,
47
+ warnOnce
48
+ } from "./chunk-TGV27ZWM.js";
49
+
50
+ // src/motion/chat.ts
51
+ var isUser = (bubble) => bubble.dataset.mkRole === "user" || bubble.classList.contains("user");
52
+ function enterMessages(bubbles, { textSelector = "[data-mk-text], .message-text" } = {}) {
53
+ if (!bubbles.length || reduced()) return null;
54
+ registerMotion();
55
+ const reverts = [];
56
+ const cleanup = () => {
57
+ for (const revert of reverts.splice(0)) revert();
58
+ };
59
+ const timeline = gsap.timeline({ onComplete: cleanup, onInterrupt: cleanup });
60
+ bubbles.forEach((bubble, index) => {
61
+ gsap.set(bubble, { transformOrigin: isUser(bubble) ? "100% 50%" : "0% 50%" });
62
+ timeline.fromTo(
63
+ bubble,
64
+ { scale: 0.5, autoAlpha: 0, filter: "blur(24px)" },
65
+ { scale: 1, autoAlpha: 1, filter: "blur(0px)", duration: TIMING.bubble, ease: EASE.signature, clearProps: "transform,opacity,visibility,filter" },
66
+ index * TIMING.bubbleStagger
67
+ );
68
+ const text = bubble.querySelector(textSelector);
69
+ if (!text) return;
70
+ const before = text.offsetHeight;
71
+ const split = splitWords(text);
72
+ const lineHeight = parseFloat(getComputedStyle(text).lineHeight) || 0;
73
+ let targets = split.parts;
74
+ if (!split.parts.length || text.offsetHeight - before > lineHeight / 2) {
75
+ split.revert();
76
+ targets = [text];
77
+ } else reverts.push(() => split.revert());
78
+ timeline.fromTo(
79
+ targets,
80
+ { y: 16, autoAlpha: 0, filter: "blur(6px)" },
81
+ {
82
+ y: 0,
83
+ autoAlpha: 1,
84
+ filter: "blur(0px)",
85
+ duration: TIMING.word,
86
+ ease: "back.out(1)",
87
+ stagger: TIMING.wordStagger,
88
+ clearProps: "transform,opacity,visibility,filter"
89
+ },
90
+ index * TIMING.bubbleStagger
91
+ );
92
+ });
93
+ return timeline;
94
+ }
95
+ function fitComposer(field, min = 64) {
96
+ const from = field.offsetHeight;
97
+ field.style.height = "auto";
98
+ const to = Math.max(min, field.scrollHeight);
99
+ field.style.height = `${from}px`;
100
+ if (from === to || reduced()) {
101
+ field.style.height = `${to}px`;
102
+ return null;
103
+ }
104
+ registerMotion();
105
+ return gsap.to(field, { height: to, duration: TIMING.composer, ease: "power2.out", overwrite: "auto" });
106
+ }
107
+ function scrollToLatest(scroller) {
108
+ const top = scroller.scrollHeight - scroller.clientHeight;
109
+ if (reduced()) {
110
+ scroller.scrollTop = top;
111
+ return null;
112
+ }
113
+ registerMotion();
114
+ const state = { top: scroller.scrollTop };
115
+ return gsap.to(state, {
116
+ top,
117
+ duration: TIMING.chatScroll,
118
+ ease: EASE.chatScroll,
119
+ overwrite: "auto",
120
+ onUpdate: () => {
121
+ scroller.scrollTop = state.top;
122
+ }
123
+ });
124
+ }
125
+
126
+ // src/components/theme-picker/engine.ts
127
+ function createThemePicker(root, options = {}) {
128
+ if (!root) {
129
+ warnOnce("theme-picker: missing root");
130
+ return inert({ select() {
131
+ } });
132
+ }
133
+ registerMotion();
134
+ const scope = createScope();
135
+ const ctx = gsap.context(() => {
136
+ });
137
+ const generated = [];
138
+ let swatches = [...root.querySelectorAll("[data-mk-swatch]")];
139
+ if (!swatches.length) {
140
+ const byId = new Map(THEMES.map((theme) => [theme.id, theme]));
141
+ const ids = options.themes ?? THEMES.filter((theme) => options.showHidden || !theme.hidden).map((theme) => theme.id);
142
+ for (const id of ids) {
143
+ const theme = byId.get(id);
144
+ if (!theme) {
145
+ warnOnce(`theme-picker: unknown theme "${id}"`);
146
+ continue;
147
+ }
148
+ const button = document.createElement("button");
149
+ button.type = "button";
150
+ button.className = "mk-swatch";
151
+ button.dataset.mkSwatch = theme.id;
152
+ button.title = theme.name;
153
+ button.setAttribute("aria-label", theme.name);
154
+ button.style.setProperty("--mk-swatch", theme.seed);
155
+ root.append(button);
156
+ generated.push(button);
157
+ }
158
+ swatches = generated;
159
+ }
160
+ scope.attr(root, "role", "group");
161
+ if (!root.hasAttribute("aria-label")) scope.attr(root, "aria-label", options.labels?.group ?? "Tema");
162
+ const sync = () => {
163
+ const current = getTheme().id;
164
+ for (const swatch of swatches) scope.attr(swatch, "aria-pressed", String(swatch.dataset.mkSwatch === current));
165
+ };
166
+ const select = (id) => {
167
+ setTheme(id);
168
+ options.onChange?.(id);
169
+ };
170
+ scope.on(root, "click", (event) => {
171
+ const swatch = event.target?.closest("[data-mk-swatch]");
172
+ if (swatch && root.contains(swatch) && swatch.dataset.mkSwatch) select(swatch.dataset.mkSwatch);
173
+ });
174
+ scope.on(document, THEME_EVENT, sync);
175
+ sync();
176
+ if (entrances()) ctx.add(() => flowInPalette(swatches));
177
+ root.dataset.mkReady = "";
178
+ return {
179
+ select,
180
+ destroy() {
181
+ scope.dispose();
182
+ ctx.revert();
183
+ for (const button of generated.splice(0)) button.remove();
184
+ delete root.dataset.mkReady;
185
+ }
186
+ };
187
+ }
188
+
189
+ // src/components/toast/store.ts
190
+ var TOAST_LIMIT = 5;
191
+ var items = [];
192
+ var nextId = 1;
193
+ var listeners = /* @__PURE__ */ new Set();
194
+ var emit = () => {
195
+ for (const listener of listeners) listener();
196
+ };
197
+ var getToasts = () => items;
198
+ function subscribeToasts(listener) {
199
+ listeners.add(listener);
200
+ return () => {
201
+ listeners.delete(listener);
202
+ };
203
+ }
204
+ function show(message, { origin = null, duration = 4e3, tone = "success", action, icon = true } = {}) {
205
+ const id = nextId++;
206
+ const live = items.filter((item) => !item.closing);
207
+ const extra = new Set(live.slice(0, Math.max(0, live.length - TOAST_LIMIT + 1)).map((item) => item.id));
208
+ items = [
209
+ ...items.map((item) => extra.has(item.id) ? { ...item, closing: true } : item),
210
+ { id, message, origin, duration, tone, action: action ?? null, icon, closing: false }
211
+ ];
212
+ emit();
213
+ return id;
214
+ }
215
+ function dismissToast(id) {
216
+ const item = items.find((entry) => entry.id === id);
217
+ if (!item || item.closing) return;
218
+ items = items.map((entry) => entry.id === id ? { ...entry, closing: true } : entry);
219
+ emit();
220
+ }
221
+ function removeToast(id) {
222
+ toastTimers.clear(id);
223
+ items = items.filter((entry) => entry.id !== id);
224
+ emit();
225
+ }
226
+ function clearToasts() {
227
+ for (const item of items) toastTimers.clear(item.id);
228
+ items = [];
229
+ emit();
230
+ }
231
+ var toast = Object.assign(show, { dismiss: dismissToast, clear: clearToasts });
232
+ var running = /* @__PURE__ */ new Map();
233
+ var toastTimers = {
234
+ start(id, duration) {
235
+ if (duration <= 0 || running.has(id)) return;
236
+ running.set(id, { handle: setTimeout(() => dismissToast(id), duration), remaining: duration, started: Date.now() });
237
+ },
238
+ pause(id) {
239
+ const timer = running.get(id);
240
+ if (!timer?.handle) return;
241
+ clearTimeout(timer.handle);
242
+ timer.remaining = Math.max(0, timer.remaining - (Date.now() - timer.started));
243
+ timer.handle = null;
244
+ },
245
+ resume(id) {
246
+ const timer = running.get(id);
247
+ if (!timer || timer.handle) return;
248
+ if (timer.remaining <= 0) {
249
+ dismissToast(id);
250
+ return;
251
+ }
252
+ timer.started = Date.now();
253
+ timer.handle = setTimeout(() => dismissToast(id), timer.remaining);
254
+ },
255
+ clear(id) {
256
+ const timer = running.get(id);
257
+ if (timer?.handle) clearTimeout(timer.handle);
258
+ running.delete(id);
259
+ }
260
+ };
261
+
262
+ // src/components/icons.ts
263
+ var ICON_PATHS = {
264
+ close: "M6 6l12 12M18 6L6 18",
265
+ expand: "M14 4h6v6M10 20H4v-6M20 4l-7 7M4 20l7-7",
266
+ shrink: "M4 14h6v6M20 10h-6V4M10 14l-7 7M14 10l7-7",
267
+ check: "M5 12.5l4.5 4.5L19 7.5",
268
+ alert: "M12 8v5M12 16.5v.01M10.3 3.9L2.6 17.3a2 2 0 001.7 3h15.4a2 2 0 001.7-3L13.7 3.9a2 2 0 00-3.4 0z",
269
+ info: "M12 11v6M12 7.5v.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z",
270
+ send: "M12 19V5M5.5 11.5L12 5l6.5 6.5",
271
+ mic: "M12 3a3 3 0 00-3 3v6a3 3 0 006 0V6a3 3 0 00-3-3zM5.5 11a6.5 6.5 0 0013 0M12 17.5V21",
272
+ sparkle: "M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9z",
273
+ grip: "M9 6h.01M15 6h.01M9 12h.01M15 12h.01M9 18h.01M15 18h.01"
274
+ };
275
+ function iconSvg(name, size = 20) {
276
+ return `<svg aria-hidden="true" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="${ICON_PATHS[name]}"/></svg>`;
277
+ }
278
+
279
+ // src/components/toast/engine.ts
280
+ var STACK = { peek: 16, scaleStep: 0.05, minScale: 0.7, maxVisible: 3, gap: 8, baseZ: 1e3 };
281
+ var DISTANCE = { enter: 12, enterBlur: 6, exit: 24, exitBlur: 4, fade: 120 };
282
+ var GESTURE = { swipe: 48, wheel: 80, expandDrag: 24, resistance: 0.15, wheelEndMs: 140 };
283
+ var TONE_ICONS = { success: "check", error: "alert", info: "info", neutral: null };
284
+ function layout(count, expanded, heights) {
285
+ let offset = 0;
286
+ return Array.from({ length: count }, (_, index) => {
287
+ if (expanded) {
288
+ const slot = { y: offset, scale: 1, opacity: 1, visible: true, zIndex: STACK.baseZ - index };
289
+ offset += (heights[index] ?? 0) + STACK.gap;
290
+ return slot;
291
+ }
292
+ const visible = index < STACK.maxVisible;
293
+ return {
294
+ y: index * STACK.peek,
295
+ scale: Math.max(STACK.minScale, 1 - index * STACK.scaleStep),
296
+ opacity: visible ? 1 : 0,
297
+ visible,
298
+ zIndex: STACK.baseZ - index
299
+ };
300
+ });
301
+ }
302
+ function revealLetters(element) {
303
+ const text = element.textContent ?? "";
304
+ const T = TIMING.toast;
305
+ if (!text || text.length > 64 || reduced()) return;
306
+ const letters = splitGraphemes(text, 64);
307
+ const original = element.innerHTML;
308
+ const width = element.getBoundingClientRect().width;
309
+ const fragment = document.createDocumentFragment();
310
+ const chars = [];
311
+ let word = null;
312
+ for (const letter of letters) {
313
+ if (!letter.trim()) {
314
+ word = null;
315
+ fragment.append(document.createTextNode(letter));
316
+ continue;
317
+ }
318
+ if (!word) {
319
+ word = document.createElement("span");
320
+ word.style.display = "inline-block";
321
+ word.style.whiteSpace = "nowrap";
322
+ fragment.append(word);
323
+ }
324
+ const char = document.createElement("span");
325
+ char.textContent = letter;
326
+ char.style.display = "inline-block";
327
+ word.append(char);
328
+ chars.push(char);
329
+ }
330
+ if (width) element.style.width = `${width}px`;
331
+ element.textContent = "";
332
+ element.append(fragment);
333
+ gsap.fromTo(
334
+ chars,
335
+ { opacity: 0, yPercent: 40, filter: "blur(4px)" },
336
+ {
337
+ opacity: 1,
338
+ yPercent: 0,
339
+ filter: "blur(0px)",
340
+ duration: T.chars,
341
+ ease: easeOutCubic,
342
+ delay: (index) => T.charsDelay + index * T.charsStagger,
343
+ onComplete: () => {
344
+ element.innerHTML = original;
345
+ element.style.width = "";
346
+ }
347
+ }
348
+ );
349
+ }
350
+ function morphFrom(card, shell, body, origin) {
351
+ const T = TIMING.toast;
352
+ const box = shell.getBoundingClientRect();
353
+ const start = origin.getBoundingClientRect();
354
+ const look = getComputedStyle(origin);
355
+ const own = getComputedStyle(shell);
356
+ const endRadius = parseFloat(own.borderTopLeftRadius) || 20;
357
+ const startRadius = Math.min(parseFloat(look.borderTopLeftRadius) || 0, start.height / 2);
358
+ card.style.width = `${box.width}px`;
359
+ card.style.height = `${box.height}px`;
360
+ body.style.width = `${body.getBoundingClientRect().width}px`;
361
+ const towardX = start.left + start.width / 2 < innerWidth / 2 ? 1 : -1;
362
+ const towardY = start.top + start.height / 2 < innerHeight / 2 ? 1 : -1;
363
+ const offset = { x: start.left - box.left, y: start.top - box.top };
364
+ Object.assign(shell.style, {
365
+ position: "absolute",
366
+ top: "0px",
367
+ left: "0px",
368
+ width: `${start.width}px`,
369
+ height: `${start.height}px`,
370
+ borderRadius: `${startRadius}px`,
371
+ background: look.backgroundColor,
372
+ transform: `translate(${offset.x}px, ${offset.y}px)`,
373
+ transition: "none"
374
+ });
375
+ Object.assign(body.style, { transform: "scale(2)", transformOrigin: "center center", filter: "blur(8px)", opacity: "0" });
376
+ origin.style.transition = "opacity 160ms ease";
377
+ origin.style.opacity = "0";
378
+ void shell.offsetWidth;
379
+ shell.style.transition = `background ${T.morphColor}s ease-out ${T.morphColorDelay}s, box-shadow ${T.morphShadow}s ease-out ${T.morphShadowDelay}s`;
380
+ shell.style.background = "";
381
+ body.style.transition = `opacity ${T.morphColor}s ease-out ${T.morphColorDelay}s`;
382
+ body.style.opacity = "1";
383
+ const motion = channels(
384
+ { x: offset.x, y: offset.y, width: start.width, height: start.height, radius: startRadius, scale: 2, blur: 8 },
385
+ (name, value) => {
386
+ if (name === "x") offset.x = value;
387
+ else if (name === "y") offset.y = value;
388
+ else if (name === "width") shell.style.width = `${value}px`;
389
+ else if (name === "height") shell.style.height = `${value}px`;
390
+ else if (name === "radius") shell.style.borderRadius = `${value}px`;
391
+ else if (name === "scale") body.style.transform = `scale(${value})`;
392
+ else if (name === "blur") body.style.filter = `blur(${value}px)`;
393
+ if (name === "x" || name === "y") shell.style.transform = `translate(${offset.x}px, ${offset.y}px)`;
394
+ }
395
+ );
396
+ void motion.animate(
397
+ { x: 0, y: 0, width: box.width, height: box.height, radius: endRadius, scale: 1, blur: 0 },
398
+ {
399
+ x: spring(144, 14, { velocity: 2400, direction: towardX }),
400
+ y: spring(144, 14, { velocity: 2400, direction: towardY }),
401
+ width: eased(T.morphSize, bezier(0.8, 0.3, 0.5, 0.8)),
402
+ height: eased(T.morphSize, bezier(0.8, 0.3, 0.5, 0.8)),
403
+ radius: eased(T.morphRadius, easeOut),
404
+ scale: eased(T.morphContent, easeOut),
405
+ blur: eased(T.morphContent, easeOut)
406
+ }
407
+ );
408
+ let settled = false;
409
+ const settle = () => {
410
+ if (settled) return;
411
+ settled = true;
412
+ clearTimeout(timer);
413
+ motion.stop();
414
+ for (const name of ["position", "top", "left", "width", "height", "border-radius", "background", "transform", "transition"]) shell.style.removeProperty(name);
415
+ card.style.removeProperty("width");
416
+ card.style.removeProperty("height");
417
+ for (const name of ["transform", "transform-origin", "filter", "opacity", "width", "transition"]) body.style.removeProperty(name);
418
+ origin.style.transition = "opacity 300ms ease";
419
+ origin.style.opacity = "";
420
+ setTimeout(() => {
421
+ origin.style.transition = "";
422
+ }, 320);
423
+ };
424
+ const timer = setTimeout(settle, T.safetyMs);
425
+ return settle;
426
+ }
427
+ function buildCard(item, dismissLabel) {
428
+ const card = document.createElement("div");
429
+ card.className = "mk-toast";
430
+ card.dataset.mkToast = String(item.id);
431
+ card.dataset.mkTone = item.tone;
432
+ const shell = document.createElement("div");
433
+ shell.className = "mk-toast__shell";
434
+ const body = document.createElement("div");
435
+ body.className = "mk-toast__body";
436
+ const icon = item.icon ? TONE_ICONS[item.tone] : null;
437
+ if (icon) {
438
+ const holder = document.createElement("span");
439
+ holder.className = "mk-toast__icon";
440
+ holder.innerHTML = iconSvg(icon, 18);
441
+ body.append(holder);
442
+ }
443
+ const message = document.createElement("span");
444
+ message.className = "mk-toast__message";
445
+ message.textContent = item.message;
446
+ body.append(message);
447
+ if (item.action) {
448
+ const action = document.createElement("button");
449
+ action.type = "button";
450
+ action.className = "mk-toast__action";
451
+ action.dataset.mkToastAction = "";
452
+ action.textContent = item.action.label;
453
+ body.append(action);
454
+ }
455
+ const dismiss = document.createElement("button");
456
+ dismiss.type = "button";
457
+ dismiss.className = "mk-toast__dismiss";
458
+ dismiss.dataset.mkToastDismiss = "";
459
+ dismiss.setAttribute("aria-label", dismissLabel);
460
+ dismiss.innerHTML = iconSvg("close", 14);
461
+ body.append(dismiss);
462
+ shell.append(body);
463
+ card.append(shell);
464
+ return { card, shell, body, message };
465
+ }
466
+ function createToaster(host, options = {}) {
467
+ if (!host) {
468
+ warnOnce("toaster: missing host");
469
+ return inert();
470
+ }
471
+ registerMotion();
472
+ const dismissLabel = options.labels?.dismiss ?? "Cerrar";
473
+ const scope = createScope();
474
+ const cards = /* @__PURE__ */ new Map();
475
+ const entered = /* @__PURE__ */ new Set();
476
+ const leaving = /* @__PURE__ */ new Set();
477
+ const dragging = /* @__PURE__ */ new Set();
478
+ const settles = /* @__PURE__ */ new Map();
479
+ let expanded = false;
480
+ let collapse;
481
+ const popover = typeof host.showPopover === "function";
482
+ scope.attr(host, "role", "status");
483
+ scope.attr(host, "aria-live", "polite");
484
+ if (popover) scope.attr(host, "popover", "manual");
485
+ const live = () => getToasts().filter((item) => !item.closing).reverse().map((item) => ({ item, entry: cards.get(item.id) })).filter((pair) => pair.entry !== void 0);
486
+ const slotsFor = () => {
487
+ const entries = live();
488
+ return { entries, slots: layout(entries.length, expanded, entries.map(({ entry }) => entry.card.offsetHeight)) };
489
+ };
490
+ const relayout = (duration = TIMING.toast.relayout, ease = easeOutCubic, stagger = 0) => {
491
+ const { entries, slots } = slotsFor();
492
+ entries.forEach(({ item, entry }, index) => {
493
+ const slot = slots[index];
494
+ if (!slot) return;
495
+ entry.card.style.zIndex = String(slot.zIndex);
496
+ entry.card.style.pointerEvents = slot.visible ? "auto" : "none";
497
+ entry.card.setAttribute("aria-hidden", slot.visible ? "false" : "true");
498
+ if (dragging.has(item.id) || !entered.has(item.id)) return;
499
+ gsap.to(entry.card, {
500
+ xPercent: -50,
501
+ y: slot.y,
502
+ scale: slot.scale,
503
+ opacity: slot.opacity,
504
+ duration: reduced() ? 0 : duration,
505
+ ease,
506
+ delay: stagger * index,
507
+ overwrite: "auto"
508
+ });
509
+ });
510
+ };
511
+ const restingY = (id) => {
512
+ const { entries, slots } = slotsFor();
513
+ return slots[entries.findIndex(({ item }) => item.id === id)]?.y ?? 0;
514
+ };
515
+ const openDeck = () => {
516
+ clearTimeout(collapse);
517
+ if (expanded) return;
518
+ expanded = true;
519
+ for (const { item } of live()) toastTimers.pause(item.id);
520
+ relayout(TIMING.toast.expand, springEase(0.55), TIMING.toast.expandStagger);
521
+ };
522
+ const closeDeck = () => {
523
+ clearTimeout(collapse);
524
+ collapse = setTimeout(() => {
525
+ if (!expanded) return;
526
+ expanded = false;
527
+ for (const { item } of live()) toastTimers.resume(item.id);
528
+ relayout(TIMING.toast.expand, springEase(0.55), TIMING.toast.expandStagger);
529
+ }, TIMING.toast.collapseDelayMs);
530
+ };
531
+ const showLayer = (visible) => {
532
+ if (!popover) return;
533
+ try {
534
+ if (host.matches(":popover-open")) host.hidePopover();
535
+ if (visible) host.showPopover();
536
+ } catch {
537
+ }
538
+ };
539
+ const attachGestures = (item, card) => {
540
+ let start = null;
541
+ let wheel = null;
542
+ const move = (offset) => gsap.set(card, { y: restingY(item.id) + offset, opacity: Math.max(0, 1 + Math.min(0, offset) / DISTANCE.fade) });
543
+ const cancel = () => {
544
+ dragging.delete(item.id);
545
+ gsap.to(card, { y: restingY(item.id), opacity: 1, duration: 0.25, ease: easeOutCubic });
546
+ if (!expanded) toastTimers.resume(item.id);
547
+ };
548
+ card.addEventListener("mouseenter", openDeck);
549
+ card.addEventListener("mouseleave", closeDeck);
550
+ card.addEventListener("pointerdown", (event) => {
551
+ if (event.button !== 0 || event.target.closest('button, a, input, textarea, select, [role="button"]')) return;
552
+ start = { y: event.clientY, type: event.pointerType };
553
+ card.setPointerCapture?.(event.pointerId);
554
+ dragging.add(item.id);
555
+ gsap.killTweensOf(card);
556
+ toastTimers.pause(item.id);
557
+ });
558
+ card.addEventListener("pointermove", (event) => {
559
+ if (!start) return;
560
+ const dy = event.clientY - start.y;
561
+ move(dy < 0 ? dy : start.type === "touch" ? dy * GESTURE.resistance : 0);
562
+ });
563
+ const up = (event) => {
564
+ if (!start) return;
565
+ const dy = event.clientY - start.y;
566
+ const type = start.type;
567
+ start = null;
568
+ if (dy < -GESTURE.swipe) {
569
+ dragging.delete(item.id);
570
+ dismissToast(item.id);
571
+ } else if (type === "touch" && dy > GESTURE.expandDrag) {
572
+ cancel();
573
+ if (expanded) closeDeck();
574
+ else openDeck();
575
+ } else cancel();
576
+ };
577
+ card.addEventListener("pointerup", up);
578
+ card.addEventListener("pointercancel", up);
579
+ card.addEventListener(
580
+ "wheel",
581
+ (event) => {
582
+ const delta = event.deltaMode === 1 ? event.deltaY * 16 : event.deltaMode === 2 ? event.deltaY * innerHeight : event.deltaY;
583
+ if (!wheel) {
584
+ wheel = { offset: 0, end: void 0 };
585
+ dragging.add(item.id);
586
+ toastTimers.pause(item.id);
587
+ }
588
+ wheel.offset = Math.min(0, wheel.offset - delta);
589
+ move(wheel.offset);
590
+ clearTimeout(wheel.end);
591
+ wheel.end = setTimeout(() => {
592
+ const offset = wheel?.offset ?? 0;
593
+ wheel = null;
594
+ if (offset < -GESTURE.wheel) {
595
+ dragging.delete(item.id);
596
+ dismissToast(item.id);
597
+ } else cancel();
598
+ }, GESTURE.wheelEndMs);
599
+ },
600
+ { passive: true }
601
+ );
602
+ card.addEventListener("click", (event) => {
603
+ const target = event.target;
604
+ if (target.closest("[data-mk-toast-dismiss]")) dismissToast(item.id);
605
+ else if (target.closest("[data-mk-toast-action]")) {
606
+ item.action?.onClick();
607
+ dismissToast(item.id);
608
+ }
609
+ });
610
+ };
611
+ const finishCard = (id) => {
612
+ settles.get(id)?.();
613
+ settles.delete(id);
614
+ const entry = cards.get(id);
615
+ if (entry) {
616
+ gsap.killTweensOf(entry.card);
617
+ entry.card.remove();
618
+ }
619
+ cards.delete(id);
620
+ entered.delete(id);
621
+ leaving.delete(id);
622
+ dragging.delete(id);
623
+ };
624
+ const render = () => {
625
+ const list = getToasts();
626
+ const ids = new Set(list.map((item) => item.id));
627
+ for (const id of [...cards.keys()]) if (!ids.has(id)) finishCard(id);
628
+ for (const item of list) {
629
+ if (!cards.has(item.id) && !item.closing) {
630
+ const entry = buildCard(item, dismissLabel);
631
+ cards.set(item.id, entry);
632
+ host.append(entry.card);
633
+ gsap.set(entry.card, { xPercent: -50 });
634
+ attachGestures(item, entry.card);
635
+ }
636
+ }
637
+ showLayer(list.some((item) => !item.closing) || leaving.size > 0);
638
+ for (const item of list) {
639
+ const entry = cards.get(item.id);
640
+ if (!entry) continue;
641
+ if (!entered.has(item.id) && !item.closing) {
642
+ entered.add(item.id);
643
+ toastTimers.start(item.id, item.duration);
644
+ relayout();
645
+ gsap.killTweensOf(entry.card);
646
+ gsap.set(entry.card, { xPercent: -50, y: restingY(item.id), scale: 1, opacity: 1 });
647
+ if (expanded) toastTimers.pause(item.id);
648
+ revealLetters(entry.message);
649
+ if (reduced()) continue;
650
+ if (item.origin?.isConnected) settles.set(item.id, morphFrom(entry.card, entry.shell, entry.body, item.origin));
651
+ else {
652
+ const y = restingY(item.id);
653
+ gsap.fromTo(
654
+ entry.card,
655
+ { y: y - DISTANCE.enter, opacity: 0, filter: `blur(${DISTANCE.enterBlur}px)` },
656
+ { y, opacity: 1, filter: "blur(0px)", duration: TIMING.toast.enter, ease: springEase(0.58, -3.5), clearProps: "filter" }
657
+ );
658
+ }
659
+ }
660
+ if (item.closing && !leaving.has(item.id)) {
661
+ leaving.add(item.id);
662
+ toastTimers.clear(item.id);
663
+ entry.card.style.zIndex = String(STACK.baseZ + 1);
664
+ const done = () => {
665
+ finishCard(item.id);
666
+ removeToast(item.id);
667
+ };
668
+ if (reduced()) done();
669
+ else {
670
+ gsap.to(entry.card, {
671
+ y: Number(gsap.getProperty(entry.card, "y")) - DISTANCE.exit,
672
+ opacity: 0,
673
+ filter: `blur(${DISTANCE.exitBlur}px)`,
674
+ duration: TIMING.toast.exit,
675
+ ease: easeInCubic,
676
+ overwrite: "auto",
677
+ onComplete: done
678
+ });
679
+ }
680
+ relayout();
681
+ }
682
+ }
683
+ };
684
+ scope.add(subscribeToasts(render));
685
+ render();
686
+ host.dataset.mkReady = "";
687
+ return {
688
+ destroy() {
689
+ clearTimeout(collapse);
690
+ for (const id of [...cards.keys()]) finishCard(id);
691
+ showLayer(false);
692
+ scope.dispose();
693
+ delete host.dataset.mkReady;
694
+ }
695
+ };
696
+ }
697
+
698
+ // src/components/chat/engine.ts
699
+ var MESSAGE = "[data-mk-message]";
700
+ var PENDING_ID = "mk-chat-pending";
701
+ var part = (root, name) => root.querySelector(`[data-mk-part="${name}"]`);
702
+ var capturePending = (placeholder) => {
703
+ registerMotion();
704
+ return placeholder ? Flip.getState(placeholder) : null;
705
+ };
706
+ function morphPendingToReply(state, reply, scroller) {
707
+ registerMotion();
708
+ if (!state || reduced()) {
709
+ if (!reduced()) enterMessages([reply]);
710
+ return null;
711
+ }
712
+ const text = reply.querySelector("[data-mk-text], .message-text");
713
+ if (text) text.style.width = `${text.getBoundingClientRect().width}px`;
714
+ reply.setAttribute("data-flip-id", PENDING_ID);
715
+ const words = text && !text.querySelector("table, pre") ? splitWords(text) : null;
716
+ if (words?.parts.length) {
717
+ gsap.fromTo(
718
+ words.parts,
719
+ { y: 16, autoAlpha: 0, filter: "blur(6px)" },
720
+ {
721
+ y: 0,
722
+ autoAlpha: 1,
723
+ filter: "blur(0px)",
724
+ duration: TIMING.word,
725
+ ease: "back.out(1)",
726
+ stagger: TIMING.wordStagger,
727
+ clearProps: "transform,opacity,visibility,filter",
728
+ onComplete: () => words.revert()
729
+ }
730
+ );
731
+ }
732
+ return Flip.from(state, {
733
+ targets: reply,
734
+ duration: TIMING.bubble,
735
+ scale: false,
736
+ ease: EASE.signature,
737
+ onUpdate: () => {
738
+ if (scroller) scroller.scrollTop = scroller.scrollHeight;
739
+ },
740
+ onComplete: () => {
741
+ reply.removeAttribute("data-flip-id");
742
+ if (text) text.style.width = "";
743
+ }
744
+ });
745
+ }
746
+ function chatMessage(role, text) {
747
+ const message = document.createElement("div");
748
+ message.dataset.mkMessage = "";
749
+ message.dataset.mkRole = role;
750
+ const body = document.createElement("span");
751
+ body.dataset.mkText = "";
752
+ body.textContent = text;
753
+ message.append(body);
754
+ return message;
755
+ }
756
+ function createChat(root, options = {}) {
757
+ const messages = root ? part(root, "messages") : null;
758
+ if (!root || !messages) {
759
+ warnOnce('chat: needs a [data-mk-part="messages"] container');
760
+ return inert({
761
+ add: () => document.createElement("div"),
762
+ pending() {
763
+ },
764
+ reply: () => document.createElement("div"),
765
+ confirm() {
766
+ },
767
+ setRecording() {
768
+ },
769
+ scrollToLatest() {
770
+ },
771
+ adopt() {
772
+ },
773
+ messages: null
774
+ });
775
+ }
776
+ registerMotion();
777
+ const { clearOnSend = true } = options;
778
+ const thinking = options.labels?.thinking ?? "Pensando...";
779
+ const scope = createScope();
780
+ const composer = part(root, "composer");
781
+ const input = composer?.querySelector('[data-mk-part="input"], textarea') ?? null;
782
+ const mic = part(root, "mic");
783
+ const seen = /* @__PURE__ */ new WeakSet();
784
+ let placeholder = null;
785
+ let pendingTimer;
786
+ let waiting = false;
787
+ scope.attr(messages, "role", "log");
788
+ scope.attr(messages, "aria-live", "polite");
789
+ const existing = [...messages.querySelectorAll(MESSAGE)];
790
+ if (options.animateExisting) enterMessages(existing);
791
+ for (const message of existing) seen.add(message);
792
+ const observer = scope.observe(
793
+ new MutationObserver((records) => {
794
+ const fresh = [];
795
+ for (const record of records) {
796
+ for (const node of record.addedNodes) {
797
+ if (!(node instanceof HTMLElement) || !node.matches(MESSAGE) || seen.has(node)) continue;
798
+ seen.add(node);
799
+ fresh.push(node);
800
+ }
801
+ }
802
+ if (!fresh.length) return;
803
+ enterMessages(fresh);
804
+ scrollToLatest(messages);
805
+ })
806
+ );
807
+ observer.observe(messages, { childList: true });
808
+ const clearPending = () => {
809
+ clearTimeout(pendingTimer);
810
+ pendingTimer = void 0;
811
+ waiting = false;
812
+ };
813
+ const add = (role, text) => {
814
+ const message = chatMessage(role, text);
815
+ messages.append(message);
816
+ return message;
817
+ };
818
+ const pending = () => {
819
+ clearPending();
820
+ waiting = true;
821
+ pendingTimer = setTimeout(() => {
822
+ pendingTimer = void 0;
823
+ if (!waiting || placeholder) return;
824
+ placeholder = document.createElement("div");
825
+ placeholder.dataset.mkMessage = "";
826
+ placeholder.dataset.mkRole = "assistant";
827
+ placeholder.dataset.mkPending = "";
828
+ placeholder.setAttribute("data-flip-id", PENDING_ID);
829
+ placeholder.innerHTML = `<span class="mk-chat__thinking">${iconSvg("sparkle", 18)}<span></span></span>`;
830
+ placeholder.querySelector("span span").textContent = thinking;
831
+ seen.add(placeholder);
832
+ messages.append(placeholder);
833
+ enterMessages([placeholder]);
834
+ scrollToLatest(messages);
835
+ }, TIMING.chat.pendingDelayMs);
836
+ };
837
+ const reply = (content) => {
838
+ const message = typeof content === "string" ? chatMessage("assistant", content) : content;
839
+ clearPending();
840
+ seen.add(message);
841
+ const was = placeholder;
842
+ placeholder = null;
843
+ if (was?.isConnected) {
844
+ const state = capturePending(was);
845
+ was.replaceWith(message);
846
+ morphPendingToReply(state, message, messages);
847
+ } else {
848
+ if (!message.isConnected) messages.append(message);
849
+ enterMessages([message]);
850
+ scrollToLatest(messages);
851
+ }
852
+ return message;
853
+ };
854
+ const confirm = (bar) => {
855
+ if (reduced()) return;
856
+ flowIn(bar);
857
+ const words = splitWords(bar);
858
+ if (!words.parts.length) return;
859
+ gsap.fromTo(
860
+ words.parts,
861
+ { y: 16, autoAlpha: 0, filter: "blur(6px)" },
862
+ {
863
+ y: 0,
864
+ autoAlpha: 1,
865
+ filter: "blur(0px)",
866
+ duration: TIMING.word,
867
+ ease: "back.out(1)",
868
+ stagger: TIMING.chat.confirmWordStagger,
869
+ clearProps: "transform,opacity,visibility,filter",
870
+ onComplete: () => words.revert()
871
+ }
872
+ );
873
+ };
874
+ const send = () => {
875
+ if (!input) return;
876
+ const text = input.value.trim();
877
+ if (!text) return;
878
+ const allowed = root.dispatchEvent(new CustomEvent("mk:send", { bubbles: true, cancelable: true, detail: { text } }));
879
+ if (!allowed) return;
880
+ options.onSend?.(text);
881
+ if (clearOnSend) {
882
+ input.value = "";
883
+ fitComposer(input);
884
+ }
885
+ };
886
+ if (input) {
887
+ scope.on(input, "input", () => fitComposer(input));
888
+ scope.on(input, "keydown", (event) => {
889
+ const key = event;
890
+ if (key.key !== "Enter" || key.shiftKey || key.isComposing) return;
891
+ event.preventDefault();
892
+ send();
893
+ });
894
+ }
895
+ if (composer) {
896
+ scope.on(composer, "submit", (event) => {
897
+ event.preventDefault();
898
+ send();
899
+ });
900
+ const sendButton = part(root, "send");
901
+ if (sendButton && !composer.matches("form")) scope.on(sendButton, "click", send);
902
+ }
903
+ scope.add(() => {
904
+ clearPending();
905
+ placeholder?.remove();
906
+ placeholder = null;
907
+ });
908
+ if (input) fitComposer(input);
909
+ root.dataset.mkReady = "";
910
+ return {
911
+ add,
912
+ pending,
913
+ reply,
914
+ confirm,
915
+ setRecording(on) {
916
+ if (mic) scope.attr(mic, "data-mk-recording", on ? "" : null);
917
+ },
918
+ scrollToLatest: () => scrollToLatest(messages),
919
+ adopt: (message) => seen.add(message),
920
+ messages,
921
+ destroy() {
922
+ scope.dispose();
923
+ if (input) input.style.removeProperty("height");
924
+ delete root.dataset.mkReady;
925
+ }
926
+ };
927
+ }
928
+
929
+ // src/components/nav/engine.ts
930
+ var NAV_STYLES = ["sidebar", "pills", "dock", "card", "rail", "wash", "magnify"];
931
+ var NAV_STYLE_ALIASES = { clasica: "sidebar", bonita: "pills", guapa: "card", tasks: "rail", melon: "wash", tunnel: "magnify" };
932
+ var toNavStyle = (value) => NAV_STYLES.includes(value) ? value : NAV_STYLE_ALIASES[value];
933
+ var ITEM = ".mk-nav__buttons .mk-nav__button";
934
+ var valueOf = (item) => item.dataset.mkValue ?? item.getAttribute("href") ?? void 0;
935
+ var read = (key) => {
936
+ try {
937
+ return localStorage.getItem(key);
938
+ } catch {
939
+ return null;
940
+ }
941
+ };
942
+ var write = (key, value) => {
943
+ try {
944
+ localStorage.setItem(key, value);
945
+ } catch {
946
+ }
947
+ };
948
+ function revealShell(nav) {
949
+ if (!entrances()) return null;
950
+ const shell = nav.closest(".mk-shell") ?? nav.parentElement;
951
+ if (!shell) return null;
952
+ const origin = nav.querySelector(".mk-nav__button--first") ?? nav.querySelector(ITEM) ?? nav;
953
+ return revealFrom(shell, { origin });
954
+ }
955
+ function createNav(root, options = {}) {
956
+ if (!root) {
957
+ warnOnce("nav: missing root");
958
+ return inert({ select() {
959
+ }, setStyle() {
960
+ }, setAccent() {
961
+ }, index: -1, style: "pills", items: [] });
962
+ }
963
+ const scope = createScope();
964
+ const items2 = () => [...root.querySelectorAll(ITEM)];
965
+ const known = [...NAV_STYLES, ...Object.keys(NAV_STYLE_ALIASES)];
966
+ const fromClass = toNavStyle(known.find((name) => root.classList.contains(`mk-nav--${name}`)));
967
+ const saved = options.storageKey ? read(options.storageKey) : null;
968
+ let style = toNavStyle(options.style) ?? toNavStyle(saved) ?? fromClass ?? "pills";
969
+ const paint = (accent2) => {
970
+ const classes = new Set(root.classList);
971
+ for (const name of known) classes.delete(`mk-nav--${name}`);
972
+ classes.add("mk-nav");
973
+ classes.add(`mk-nav--${style}`);
974
+ if (accent2) classes.add("mk-nav--accent");
975
+ else classes.delete("mk-nav--accent");
976
+ scope.attr(root, "class", [...classes].join(" "));
977
+ };
978
+ let accent = options.accent ?? root.classList.contains("mk-nav--accent");
979
+ paint(accent);
980
+ if (root.localName !== "nav") scope.attr(root, "role", "navigation");
981
+ if (!root.hasAttribute("aria-label") && !root.hasAttribute("aria-labelledby")) scope.attr(root, "aria-label", options.labels?.nav ?? "Principal");
982
+ const mark = (current) => {
983
+ for (const item of items2()) scope.attr(item, "aria-current", item === current ? "page" : null);
984
+ };
985
+ const find = (target) => {
986
+ const list = items2();
987
+ return typeof target === "number" ? list[target] : list.find((item) => valueOf(item) === target);
988
+ };
989
+ scope.on(root, "click", (event) => {
990
+ const item = event.target?.closest(ITEM);
991
+ if (!item || !root.contains(item)) return;
992
+ const index = items2().indexOf(item);
993
+ const value = valueOf(item);
994
+ const detail = { index, value, item, originalEvent: event };
995
+ if (!root.dispatchEvent(new CustomEvent("mk:navigate", { bubbles: true, cancelable: true, detail }))) {
996
+ event.preventDefault();
997
+ return;
998
+ }
999
+ mark(item);
1000
+ options.onSelect?.(index, value, item);
1001
+ });
1002
+ let reveal = null;
1003
+ if (options.reveal) reveal = revealShell(root);
1004
+ root.dataset.mkReady = "";
1005
+ return {
1006
+ select(target) {
1007
+ const item = find(target);
1008
+ if (!item) warnOnce(`nav: no item ${JSON.stringify(target)}`);
1009
+ else mark(item);
1010
+ },
1011
+ setStyle(next) {
1012
+ const resolved = toNavStyle(next);
1013
+ if (!resolved) {
1014
+ warnOnce(`nav: unknown style "${String(next)}" (use ${NAV_STYLES.join(", ")})`);
1015
+ return;
1016
+ }
1017
+ style = resolved;
1018
+ paint(accent);
1019
+ if (options.storageKey) write(options.storageKey, resolved);
1020
+ },
1021
+ setAccent(on) {
1022
+ accent = on;
1023
+ paint(accent);
1024
+ },
1025
+ get index() {
1026
+ return items2().findIndex((item) => item.getAttribute("aria-current") === "page");
1027
+ },
1028
+ get style() {
1029
+ return style;
1030
+ },
1031
+ get items() {
1032
+ return items2();
1033
+ },
1034
+ destroy() {
1035
+ reveal?.cancel();
1036
+ reveal = null;
1037
+ scope.dispose();
1038
+ delete root.dataset.mkReady;
1039
+ }
1040
+ };
1041
+ }
1042
+
1043
+ // src/components/cursor/engine.ts
1044
+ var svg = (extra = "") => `<svg aria-hidden="true" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"${extra}><path d="${ICON_PATHS.send}"/></svg>`;
1045
+ function backgroundTone(el) {
1046
+ if (!el) return "light";
1047
+ if (el.closest("img, video, picture, canvas")) return "dark";
1048
+ for (let node = el; node; node = node.parentElement) {
1049
+ const match = getComputedStyle(node).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
1050
+ if (!match) continue;
1051
+ const alpha = match[4] === void 0 ? 1 : parseFloat(match[4]);
1052
+ if (alpha <= 0.1) continue;
1053
+ const luminance = (Number(match[1]) * 299 + Number(match[2]) * 587 + Number(match[3]) * 114) / 1e3;
1054
+ return luminance > TIMING.cursor.light ? "light" : "dark";
1055
+ }
1056
+ return "light";
1057
+ }
1058
+ function createCursor(host, options = {}) {
1059
+ const variant = options.variant ?? "chip";
1060
+ const idle = inert({ visible: false, label: "", position: { x: 0, y: 0 }, tone: "light", update() {
1061
+ } });
1062
+ if (!host) {
1063
+ warnOnce("cursor: missing element");
1064
+ return idle;
1065
+ }
1066
+ const coarse = typeof matchMedia === "function" && matchMedia("(pointer: coarse)").matches;
1067
+ if (coarse || reduced()) return idle;
1068
+ registerMotion();
1069
+ const scope = createScope();
1070
+ const t = TIMING.cursor;
1071
+ const zone = options.zone ?? (variant === "dot" ? host.parentElement ?? document.body : document.documentElement);
1072
+ scope.attr(host, "class", [host.getAttribute("class"), "mk-cursor", `mk-cursor--${variant}`].filter(Boolean).join(" "));
1073
+ scope.attr(host, "aria-hidden", "true");
1074
+ const pointer = { x: -100, y: -100, placed: false };
1075
+ const position = { x: -100, y: -100 };
1076
+ const velocity = { x: 0, y: 0 };
1077
+ let visible = false;
1078
+ let label = "";
1079
+ let tone = "light";
1080
+ const made = [];
1081
+ let chip = null;
1082
+ let chipLabel = null;
1083
+ let chipIcon = null;
1084
+ let word = null;
1085
+ const size = { width: 0, height: 0 };
1086
+ if (variant === "chip") {
1087
+ chip = document.createElement("span");
1088
+ chip.className = "mk-cursor__chip mk-glass";
1089
+ chip.innerHTML = '<span class="mk-glass__shadow" aria-hidden="true"></span><span class="mk-cursor__icon mk-icon"></span><span class="mk-cursor__label"></span>';
1090
+ chipIcon = chip.querySelector(".mk-cursor__icon");
1091
+ chipLabel = chip.querySelector(".mk-cursor__label");
1092
+ host.append(chip);
1093
+ made.push(chip);
1094
+ gsap.set(chip, { autoAlpha: 0, scale: 0.8 });
1095
+ } else {
1096
+ const arrows = options.arrows ?? "y";
1097
+ scope.attr(host, "data-mk-arrows", arrows);
1098
+ scope.attr(zone, "data-mk-cursor-zone", "");
1099
+ const dot = document.createElement("span");
1100
+ dot.className = "mk-cursor__dot";
1101
+ dot.innerHTML = arrows === "none" ? '<span class="mk-cursor__circle"></span><span class="mk-cursor__text"><span class="mk-cursor__word"></span></span>' : `<span class="mk-cursor__circle"></span><span class="mk-cursor__arrow mk-cursor__arrow--start">${svg()}</span><span class="mk-cursor__text"><span class="mk-cursor__word"></span></span><span class="mk-cursor__arrow mk-cursor__arrow--end">${svg()}</span>`;
1102
+ word = dot.querySelector(".mk-cursor__word");
1103
+ if (word) word.textContent = options.text ?? "";
1104
+ host.append(dot);
1105
+ made.push(dot);
1106
+ scope.attr(host, "data-mk-hidden", "");
1107
+ }
1108
+ const appear = motionSpring(...TIMING.springs.cursorAppear);
1109
+ const showChip = (next) => {
1110
+ if (!chip || !chipLabel || !chipIcon) return;
1111
+ const text = next?.dataset.mkCursor ?? "";
1112
+ if (text) {
1113
+ label = text;
1114
+ chipLabel.textContent = text;
1115
+ chipIcon.textContent = next?.dataset.mkCursorIcon ?? "";
1116
+ chip.classList.toggle("mk-cursor__chip--circle", next?.dataset.mkCursorShape === "circle");
1117
+ const box = chip.getBoundingClientRect();
1118
+ size.width = box.width;
1119
+ size.height = box.height;
1120
+ }
1121
+ if (Boolean(text) === visible) return;
1122
+ visible = Boolean(text);
1123
+ if (!visible) label = "";
1124
+ gsap.to(chip, {
1125
+ autoAlpha: visible ? 1 : 0,
1126
+ scale: visible ? 1 : 0.8,
1127
+ duration: appear.duration,
1128
+ ease: appear.ease,
1129
+ overwrite: "auto"
1130
+ });
1131
+ };
1132
+ let inZone = false;
1133
+ let overHide = false;
1134
+ const syncDot = () => scope.attr(host, "data-mk-hidden", inZone && !overHide ? null : "");
1135
+ const wordFor = (target) => {
1136
+ if (!word) return;
1137
+ const source = target?.closest("[data-mk-cursor]");
1138
+ word.textContent = source && zone.contains(source) ? source.dataset.mkCursor ?? "" : options.text ?? "";
1139
+ };
1140
+ const place = (event) => {
1141
+ if (event.pointerType === "touch") return;
1142
+ pointer.x = event.clientX;
1143
+ pointer.y = event.clientY;
1144
+ if (!pointer.placed) {
1145
+ pointer.placed = true;
1146
+ if (variant === "dot") {
1147
+ position.x = pointer.x;
1148
+ position.y = pointer.y;
1149
+ }
1150
+ }
1151
+ };
1152
+ scope.on(window, "pointermove", (event) => place(event), { passive: true });
1153
+ const overTarget = variant === "chip" ? document : zone;
1154
+ scope.on(overTarget, "pointerover", (event) => {
1155
+ const target = event.target;
1156
+ if (variant === "chip") {
1157
+ const source = target?.closest("[data-mk-cursor]") ?? null;
1158
+ showChip(source && zone.contains(source) ? source : null);
1159
+ return;
1160
+ }
1161
+ overHide = Boolean(target?.closest("[data-mk-cursor-hide]"));
1162
+ wordFor(target);
1163
+ syncDot();
1164
+ });
1165
+ if (variant === "dot") {
1166
+ scope.on(zone, "pointerenter", (event) => {
1167
+ place(event);
1168
+ inZone = true;
1169
+ visible = true;
1170
+ syncDot();
1171
+ });
1172
+ scope.on(zone, "pointerleave", () => {
1173
+ inZone = false;
1174
+ visible = false;
1175
+ scope.attr(host, "data-mk-pressed", null);
1176
+ syncDot();
1177
+ });
1178
+ scope.on(zone, "pointerdown", () => scope.attr(host, "data-mk-pressed", ""));
1179
+ scope.on(window, "pointerup", () => scope.attr(host, "data-mk-pressed", null));
1180
+ }
1181
+ const [stiffness, damping] = TIMING.springs.cursorFollow;
1182
+ const update = (dt = 1) => {
1183
+ if (variant === "chip") {
1184
+ const halfW = size.width / 2 + t.gutter;
1185
+ const halfH = size.height / 2 + t.gutter;
1186
+ const tx = size.width ? Math.min(Math.max(pointer.x, halfW), innerWidth - halfW) : pointer.x;
1187
+ const ty = size.height ? Math.min(Math.max(pointer.y, halfH), innerHeight - halfH) : pointer.y;
1188
+ const steps = Math.max(1, Math.ceil(dt * 4));
1189
+ const h = dt / 60 / steps;
1190
+ for (let i = 0; i < steps; i++) {
1191
+ velocity.x += (stiffness * (tx - position.x) - damping * velocity.x) * h;
1192
+ velocity.y += (stiffness * (ty - position.y) - damping * velocity.y) * h;
1193
+ position.x += velocity.x * h;
1194
+ position.y += velocity.y * h;
1195
+ }
1196
+ if (visible && typeof document.elementFromPoint === "function") {
1197
+ tone = backgroundTone(document.elementFromPoint(pointer.x, pointer.y));
1198
+ if (chip && chip.dataset.mkTone !== tone) chip.dataset.mkTone = tone;
1199
+ }
1200
+ } else {
1201
+ const step = 1 - Math.pow(1 - t.dotLerp, dt);
1202
+ position.x += (pointer.x - position.x) * step;
1203
+ position.y += (pointer.y - position.y) * step;
1204
+ }
1205
+ host.style.transform = `translate3d(${position.x.toFixed(2)}px, ${position.y.toFixed(2)}px, 0) translate(-50%, -50%)`;
1206
+ };
1207
+ scope.add(subscribe(update));
1208
+ update(0);
1209
+ host.dataset.mkReady = "";
1210
+ return {
1211
+ get visible() {
1212
+ return visible;
1213
+ },
1214
+ get label() {
1215
+ return label;
1216
+ },
1217
+ get position() {
1218
+ return { ...position };
1219
+ },
1220
+ get tone() {
1221
+ return tone;
1222
+ },
1223
+ update,
1224
+ destroy() {
1225
+ if (chip) gsap.killTweensOf(chip);
1226
+ scope.dispose();
1227
+ for (const node of made.splice(0)) node.remove();
1228
+ host.style.removeProperty("transform");
1229
+ if (host.getAttribute("style") === "") host.removeAttribute("style");
1230
+ delete host.dataset.mkReady;
1231
+ }
1232
+ };
1233
+ }
1234
+
1235
+ // src/components/island/engine.ts
1236
+ var sequence = 0;
1237
+ var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
1238
+ function createIsland(root, options = {}) {
1239
+ const shell = root?.querySelector(".mk-island__shell") ?? null;
1240
+ const panels = root ? [...root.querySelectorAll("[data-mk-island-panel]")] : [];
1241
+ if (!root || !shell || !panels.length) {
1242
+ warnOnce("island: needs .mk-island__shell and at least one [data-mk-island-panel]");
1243
+ return inert({ open() {
1244
+ }, close() {
1245
+ }, toggle() {
1246
+ }, ready() {
1247
+ }, active: null });
1248
+ }
1249
+ const t = TIMING.island;
1250
+ const { entrance = true, closeOnScroll = true, closeOnNavigate = true, focusOnOpen = true, onChange } = options;
1251
+ registerMotion();
1252
+ const scope = createScope();
1253
+ const toggles = [...root.querySelectorAll("[data-mk-island-toggle]")];
1254
+ const cta = root.querySelector(".mk-island__cta");
1255
+ const backdrops = [...root.querySelectorAll("[data-mk-island-close]")];
1256
+ let active = null;
1257
+ let trigger = null;
1258
+ let scrollStart = 0;
1259
+ let armed = false;
1260
+ let focusTimer;
1261
+ let entered = false;
1262
+ let entry = null;
1263
+ const flag = (el, name, on) => {
1264
+ if (el) scope.attr(el, name, on ? "" : null);
1265
+ };
1266
+ const sync = () => {
1267
+ for (const panel of panels) {
1268
+ const on = panel.dataset.mkIslandPanel === active;
1269
+ if (active) flag(panel, "hidden", !on);
1270
+ scope.attr(panel, "aria-hidden", String(!on));
1271
+ flag(panel, "inert", !on);
1272
+ }
1273
+ for (const button of toggles) scope.attr(button, "aria-expanded", String(button.dataset.mkIslandToggle === active));
1274
+ flag(cta, "inert", Boolean(active));
1275
+ for (const backdrop of backdrops) {
1276
+ flag(backdrop, "inert", !active);
1277
+ scope.attr(backdrop, "aria-hidden", String(!active));
1278
+ }
1279
+ flag(root, "data-mk-open", Boolean(active));
1280
+ scope.attr(root, "data-mk-active", active);
1281
+ };
1282
+ const stagger = (opening) => {
1283
+ root.querySelectorAll("[data-mk-island-item]").forEach((item, index) => {
1284
+ scope.attr(item, "style", item.getAttribute("style"));
1285
+ item.style.setProperty("--mk-island-delay", opening ? `${Number((t.delay + index * t.step).toFixed(3))}s` : "0s");
1286
+ });
1287
+ };
1288
+ const close = (returnFocus = true) => {
1289
+ if (scope.disposed || !active) return;
1290
+ clearTimeout(focusTimer);
1291
+ active = null;
1292
+ stagger(false);
1293
+ sync();
1294
+ onChange?.(null);
1295
+ if (returnFocus && trigger?.isConnected) trigger.focus({ preventScroll: true });
1296
+ };
1297
+ const open = (name = panels[0].dataset.mkIslandPanel, source) => {
1298
+ if (scope.disposed) return;
1299
+ const panel = panels.find((el) => el.dataset.mkIslandPanel === name);
1300
+ if (!panel) return;
1301
+ const wasClosed = !active;
1302
+ clearTimeout(focusTimer);
1303
+ active = name;
1304
+ trigger = source ?? toggles.find((el) => el.dataset.mkIslandToggle === name) ?? trigger;
1305
+ if (wasClosed) {
1306
+ scrollStart = window.scrollY;
1307
+ armed = false;
1308
+ stagger(true);
1309
+ }
1310
+ sync();
1311
+ onChange?.(name);
1312
+ if (focusOnOpen)
1313
+ focusTimer = setTimeout(
1314
+ () => {
1315
+ if (active !== name) return;
1316
+ const first = [...panel.querySelectorAll(FOCUSABLE)].find((el) => !el.closest("[hidden], [inert]"));
1317
+ (first ?? panel).focus({ preventScroll: true });
1318
+ },
1319
+ reduced() ? 0 : t.focus
1320
+ );
1321
+ };
1322
+ const toggle = (name = panels[0].dataset.mkIslandPanel, source) => active === name ? close(false) : open(name, source);
1323
+ for (const panel of panels) {
1324
+ if (!panel.id) scope.attr(panel, "id", `mk-island-panel-${++sequence}`);
1325
+ if (!panel.hasAttribute("tabindex")) scope.attr(panel, "tabindex", "-1");
1326
+ if (!panel.hasAttribute("role")) scope.attr(panel, "role", "region");
1327
+ }
1328
+ for (const button of toggles) {
1329
+ const panel = panels.find((el) => el.dataset.mkIslandPanel === button.dataset.mkIslandToggle);
1330
+ if (panel) scope.attr(button, "aria-controls", panel.id);
1331
+ scope.on(button, "click", () => toggle(button.dataset.mkIslandToggle, button));
1332
+ }
1333
+ for (const backdrop of backdrops) scope.on(backdrop, "click", () => close(true));
1334
+ scope.on(document, "keydown", (event) => {
1335
+ if (active && event.key === "Escape") {
1336
+ event.preventDefault();
1337
+ close(true);
1338
+ }
1339
+ });
1340
+ if (closeOnNavigate)
1341
+ scope.on(root, "click", (event) => {
1342
+ const link = event.target?.closest?.("a[href]");
1343
+ if (active && link?.closest("[data-mk-island-panel]")) close(false);
1344
+ });
1345
+ if (closeOnScroll) {
1346
+ const arm = () => {
1347
+ if (active) armed = true;
1348
+ };
1349
+ scope.on(window, "wheel", arm, { passive: true });
1350
+ scope.on(window, "touchmove", arm, { passive: true });
1351
+ scope.on(
1352
+ window,
1353
+ "scroll",
1354
+ () => {
1355
+ if (active && armed && Math.abs(window.scrollY - scrollStart) > 1) close(false);
1356
+ },
1357
+ { passive: true }
1358
+ );
1359
+ }
1360
+ scope.add(() => clearTimeout(focusTimer));
1361
+ const moving = entrance !== false && entrances();
1362
+ if (moving) gsap.set(shell, { yPercent: t.offset });
1363
+ const ready = () => {
1364
+ if (scope.disposed || entered || !moving) return;
1365
+ entered = true;
1366
+ entry = gsap.to(shell, { yPercent: 0, duration: t.entrance });
1367
+ };
1368
+ scope.add(() => {
1369
+ entry?.kill();
1370
+ if (moving) gsap.set(shell, { clearProps: "transform,translate" });
1371
+ if (shell.getAttribute("style") === "") shell.removeAttribute("style");
1372
+ });
1373
+ sync();
1374
+ if (entrance === true) ready();
1375
+ scope.attr(root, "data-mk-ready", "");
1376
+ return {
1377
+ open: (name) => open(name),
1378
+ close,
1379
+ toggle: (name) => toggle(name),
1380
+ ready,
1381
+ get active() {
1382
+ return active;
1383
+ },
1384
+ destroy: () => scope.dispose()
1385
+ };
1386
+ }
1387
+
1388
+ // src/components/pill-button/engine.ts
1389
+ var PILL_ARROW = '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg>';
1390
+ function createPillButton(root, options = {}) {
1391
+ const control = root ? root.matches('button, a, [role="button"]') ? root : root.querySelector('button, a, [role="button"]') : null;
1392
+ if (!root || !control) return inert();
1393
+ registerMotion();
1394
+ const scope = createScope();
1395
+ const icon = control.querySelector("[data-mk-pill-icon]");
1396
+ if (!control.querySelector("[data-mk-pill-label]")) {
1397
+ const label = document.createElement("span");
1398
+ label.dataset.mkPillLabel = "";
1399
+ for (const node of [...control.childNodes]) if (node !== icon) label.append(node);
1400
+ control.prepend(label);
1401
+ scope.add(() => label.replaceWith(...label.childNodes));
1402
+ }
1403
+ if (!icon) {
1404
+ const made = document.createElement("span");
1405
+ made.dataset.mkPillIcon = "";
1406
+ made.setAttribute("aria-hidden", "true");
1407
+ made.innerHTML = options.icon ?? PILL_ARROW;
1408
+ control.append(made);
1409
+ scope.add(() => made.remove());
1410
+ }
1411
+ const fill = document.createElement("span");
1412
+ fill.dataset.mkPillFill = "";
1413
+ fill.setAttribute("aria-hidden", "true");
1414
+ control.prepend(fill);
1415
+ scope.add(() => fill.remove());
1416
+ scope.attr(control, "data-mk-pill", options.expand ? "expand" : "");
1417
+ scope.attr(root, "data-mk-ready", "");
1418
+ let tapped;
1419
+ scope.on(control, "pointerdown", (event) => {
1420
+ press(control);
1421
+ if (event.pointerType !== "touch") return;
1422
+ control.setAttribute("data-mk-active", "");
1423
+ clearTimeout(tapped);
1424
+ tapped = setTimeout(() => control.removeAttribute("data-mk-active"), 650);
1425
+ });
1426
+ scope.add(() => {
1427
+ clearTimeout(tapped);
1428
+ control.removeAttribute("data-mk-active");
1429
+ });
1430
+ return { destroy: () => scope.dispose() };
1431
+ }
1432
+
1433
+ // src/components/toolbar/engine.ts
1434
+ function createToolbar(root, options = {}) {
1435
+ const tools = root ? [...root.querySelectorAll("button")] : [];
1436
+ if (!root || !tools.length) {
1437
+ if (root) warnOnce("toolbar: needs at least one <button>");
1438
+ return inert({ setValue() {
1439
+ }, value: "" });
1440
+ }
1441
+ registerMotion();
1442
+ const scope = createScope();
1443
+ const vertical = options.orientation !== "horizontal";
1444
+ const valueOf2 = (tool) => tool.dataset.mkTool ?? String(tools.indexOf(tool));
1445
+ const labelOf = (tool) => tool.getAttribute("aria-label") ?? tool.title ?? tool.textContent?.trim() ?? "";
1446
+ scope.attr(root, "role", "toolbar");
1447
+ scope.attr(root, "aria-orientation", vertical ? "vertical" : "horizontal");
1448
+ scope.attr(root, "data-mk-orientation", vertical ? "vertical" : "horizontal");
1449
+ for (const tool of tools) {
1450
+ scope.attr(tool, "type", tool.getAttribute("type") ?? "button");
1451
+ scope.attr(tool, "aria-pressed", "false");
1452
+ scope.attr(tool, "tabindex", "-1");
1453
+ if (options.tips !== false && tool.title) {
1454
+ scope.attr(tool, "aria-label", tool.getAttribute("aria-label") ?? tool.title);
1455
+ scope.attr(tool, "title", null);
1456
+ }
1457
+ }
1458
+ const blob = document.createElement("span");
1459
+ blob.dataset.mkToolbarBlob = "";
1460
+ blob.setAttribute("aria-hidden", "true");
1461
+ root.prepend(blob);
1462
+ const tip = document.createElement("span");
1463
+ tip.dataset.mkToolbarTip = "";
1464
+ tip.setAttribute("aria-hidden", "true");
1465
+ tip.hidden = true;
1466
+ if (options.tips !== false) root.append(tip);
1467
+ scope.add(() => {
1468
+ gsap.killTweensOf([blob, tip]);
1469
+ blob.remove();
1470
+ tip.remove();
1471
+ });
1472
+ scope.attr(root, "data-mk-ready", "");
1473
+ const find = (value) => tools.find((tool) => valueOf2(tool) === value);
1474
+ let current = find(options.value) ?? tools.find((tool) => !tool.disabled) ?? tools[0];
1475
+ const box = (tool) => ({ start: vertical ? tool.offsetTop : tool.offsetLeft, size: vertical ? tool.offsetHeight : tool.offsetWidth, cross: vertical ? tool.offsetLeft : tool.offsetTop, crossSize: vertical ? tool.offsetWidth : tool.offsetHeight });
1476
+ const along = vertical ? "y" : "x";
1477
+ const across = vertical ? "x" : "y";
1478
+ const length = vertical ? "height" : "width";
1479
+ const thickness = vertical ? "width" : "height";
1480
+ let timeline = null;
1481
+ const place = () => {
1482
+ const at = box(current);
1483
+ timeline?.kill();
1484
+ gsap.set(blob, { [along]: at.start, [across]: at.cross, [length]: at.size, [thickness]: at.crossSize, scaleX: 1, scaleY: 1 });
1485
+ };
1486
+ const slide = (from, to) => {
1487
+ if (reduced() || from === to) return place();
1488
+ const a = box(from);
1489
+ const b = box(to);
1490
+ const forward = b.start > a.start;
1491
+ const reach = forward ? b.start + b.size - a.start : a.start + a.size - b.start;
1492
+ const squeeze = vertical ? { scaleX: 0.84 } : { scaleY: 0.84 };
1493
+ const relax = vertical ? { scaleX: 1 } : { scaleY: 1 };
1494
+ timeline?.kill();
1495
+ timeline = gsap.timeline();
1496
+ timeline.to(blob, { [along]: forward ? a.start : b.start, [length]: reach, ...squeeze, duration: 0.2, ease: "power2.in" }, 0);
1497
+ timeline.to(blob, { [along]: b.start, [length]: b.size, duration: 0.42, ease: EASE.swatch }, 0.16);
1498
+ timeline.to(blob, { ...relax, duration: 0.5, ease: "elastic.out(1, 0.45)" }, 0.18);
1499
+ };
1500
+ const squish = () => {
1501
+ if (reduced()) return;
1502
+ timeline?.kill();
1503
+ place();
1504
+ timeline = gsap.timeline();
1505
+ timeline.to(blob, { scaleX: 0.88, scaleY: 0.88, duration: 0.1, ease: "power2.out" }).to(blob, { scaleX: 1, scaleY: 1, duration: 0.45, ease: "elastic.out(1, 0.4)" });
1506
+ };
1507
+ const paint = () => {
1508
+ for (const tool of tools) {
1509
+ tool.setAttribute("aria-pressed", String(tool === current));
1510
+ tool.setAttribute("tabindex", tool === current ? "0" : "-1");
1511
+ }
1512
+ };
1513
+ let tipFor = null;
1514
+ let tipTimer;
1515
+ scope.add(() => clearTimeout(tipTimer));
1516
+ const showTip = (tool, linger = 0) => {
1517
+ if (options.tips === false) return;
1518
+ clearTimeout(tipTimer);
1519
+ const text = labelOf(tool);
1520
+ if (!text) return hideTip();
1521
+ const at = box(tool);
1522
+ const appearing = tip.hidden;
1523
+ const changed = tipFor !== tool;
1524
+ tipFor = tool;
1525
+ tip.textContent = text;
1526
+ tip.hidden = false;
1527
+ const tipSize = vertical ? tip.offsetHeight : tip.offsetWidth;
1528
+ const spot = at.start + at.size / 2 - tipSize / 2;
1529
+ if (appearing || reduced()) {
1530
+ gsap.killTweensOf(tip);
1531
+ gsap.set(tip, { [along]: spot });
1532
+ if (!reduced()) gsap.fromTo(tip, { opacity: 0, [across]: -8, filter: "blur(4px)", scale: 0.9 }, { opacity: 1, [across]: 0, filter: "blur(0px)", scale: 1, duration: 0.28, ease: EASE.pop });
1533
+ else gsap.set(tip, { opacity: 1, [across]: 0, scale: 1, filter: "none" });
1534
+ } else if (changed) {
1535
+ gsap.to(tip, { [along]: spot, opacity: 1, [across]: 0, scale: 1, filter: "blur(0px)", duration: 0.32, ease: EASE.swatch, overwrite: "auto" });
1536
+ }
1537
+ if (linger) tipTimer = setTimeout(hideTip, linger);
1538
+ };
1539
+ const hideTip = () => {
1540
+ clearTimeout(tipTimer);
1541
+ tipFor = null;
1542
+ if (tip.hidden) return;
1543
+ if (reduced()) {
1544
+ tip.hidden = true;
1545
+ return;
1546
+ }
1547
+ gsap.to(tip, { opacity: 0, [across]: -6, filter: "blur(4px)", scale: 0.92, duration: 0.18, ease: "power2.in", overwrite: "auto", onComplete: () => {
1548
+ tip.hidden = true;
1549
+ } });
1550
+ };
1551
+ const choose = (tool, notify) => {
1552
+ if (tool.disabled) return;
1553
+ const previous = current;
1554
+ current = tool;
1555
+ paint();
1556
+ if (previous === current) squish();
1557
+ else slide(previous, current);
1558
+ if (previous === current || !notify) return;
1559
+ const value = valueOf2(current);
1560
+ options.onChange?.(value);
1561
+ root.dispatchEvent(new CustomEvent("mk:change", { bubbles: true, detail: { value } }));
1562
+ };
1563
+ scope.on(root, "click", (event) => {
1564
+ const tool = event.target.closest("button");
1565
+ if (!tool || !tools.includes(tool)) return;
1566
+ press(tool);
1567
+ choose(tool, true);
1568
+ showTip(tool, 1200);
1569
+ });
1570
+ scope.on(root, "pointerover", (event) => {
1571
+ const tool = event.target.closest("button");
1572
+ if (tool && tools.includes(tool) && event.pointerType !== "touch") showTip(tool);
1573
+ });
1574
+ scope.on(root, "pointerleave", () => {
1575
+ tipTimer = setTimeout(hideTip, 120);
1576
+ });
1577
+ scope.on(root, "focusin", (event) => {
1578
+ const tool = event.target;
1579
+ if (tools.includes(tool) && tool.matches(":focus-visible")) showTip(tool);
1580
+ });
1581
+ scope.on(root, "focusout", (event) => {
1582
+ if (!root.contains(event.relatedTarget)) hideTip();
1583
+ });
1584
+ scope.on(root, "keydown", (event) => {
1585
+ const key = event.key;
1586
+ const enabled = tools.filter((tool) => !tool.disabled);
1587
+ const at = enabled.indexOf(document.activeElement);
1588
+ if (at < 0) return;
1589
+ const next = key === "ArrowDown" || key === "ArrowRight" ? enabled[(at + 1) % enabled.length] : key === "ArrowUp" || key === "ArrowLeft" ? enabled[(at - 1 + enabled.length) % enabled.length] : key === "Home" ? enabled[0] : key === "End" ? enabled[enabled.length - 1] : null;
1590
+ if (!next) return;
1591
+ event.preventDefault();
1592
+ choose(next, true);
1593
+ next.focus();
1594
+ showTip(next, 1200);
1595
+ });
1596
+ if (typeof ResizeObserver === "function") scope.observe(new ResizeObserver(() => place())).observe(root);
1597
+ paint();
1598
+ place();
1599
+ return {
1600
+ setValue(value, notify = false) {
1601
+ const tool = find(value);
1602
+ if (tool) choose(tool, notify);
1603
+ },
1604
+ get value() {
1605
+ return valueOf2(current);
1606
+ },
1607
+ destroy: () => scope.dispose()
1608
+ };
1609
+ }
1610
+
1611
+ // src/components/bidirectional-slider/engine.ts
1612
+ var finite = (value) => typeof value === "number" && Number.isFinite(value);
1613
+ var ICONS = {
1614
+ signs: ['<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 12h12"/></svg>', '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 12h12M12 6v12"/></svg>'],
1615
+ volume: [
1616
+ '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 9.5v5h3.5L12 18.5v-13L7.5 9.5z"/><path d="M15.5 9.5a3.5 3.5 0 0 1 0 5"/></svg>',
1617
+ '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 9.5v5h3.5L12 18.5v-13L7.5 9.5z"/><path d="M15.5 9.5a3.5 3.5 0 0 1 0 5"/><path d="M18 7a7 7 0 0 1 0 10"/></svg>'
1618
+ ]
1619
+ };
1620
+ function createBidirectionalSlider(root, options = {}) {
1621
+ if (!root) return inert({ setValue() {
1622
+ }, reset() {
1623
+ }, value: 0 });
1624
+ registerMotion();
1625
+ const scope = createScope();
1626
+ const min = finite(options.min) ? options.min : -100;
1627
+ const max = finite(options.max) && options.max > min ? options.max : Math.max(min + 1, 100);
1628
+ const origin = Math.min(max, Math.max(min, finite(options.origin) ? options.origin : 0));
1629
+ const step = finite(options.step) && options.step > 0 ? options.step : 1;
1630
+ const decimals = (String(step).split(".")[1] ?? "").length;
1631
+ const snap = (n) => Number(Math.min(max, Math.max(min, Math.round((n - min) / step) * step + min)).toFixed(decimals));
1632
+ const format = options.formatValue ?? ((n) => {
1633
+ const delta = Number((n - origin).toFixed(decimals));
1634
+ const text = new Intl.NumberFormat(void 0, { maximumFractionDigits: decimals }).format(Math.abs(delta));
1635
+ return delta > 0 ? `+${text}` : delta < 0 ? `\u2212${text}` : text;
1636
+ });
1637
+ const made = (tag, parent, data) => {
1638
+ const element = document.createElement(tag);
1639
+ element.setAttribute(`data-mk-bislider-${data}`, "");
1640
+ parent.append(element);
1641
+ scope.add(() => element.remove());
1642
+ return element;
1643
+ };
1644
+ const icons = options.icons === false ? null : ICONS[options.icons ?? "signs"];
1645
+ const less = icons ? made("button", root, "less") : null;
1646
+ const track = made("span", root, "track");
1647
+ const more = icons ? made("button", root, "more") : null;
1648
+ if (less && more && icons) {
1649
+ less.type = more.type = "button";
1650
+ less.tabIndex = more.tabIndex = -1;
1651
+ less.innerHTML = icons[0];
1652
+ more.innerHTML = icons[1];
1653
+ less.setAttribute("aria-label", "Menos");
1654
+ more.setAttribute("aria-label", "M\xE1s");
1655
+ root.prepend(less);
1656
+ }
1657
+ const clip = made("span", track, "clip");
1658
+ clip.setAttribute("aria-hidden", "true");
1659
+ const fill = made("span", clip, "fill");
1660
+ const notch = made("span", clip, "notch");
1661
+ const thumb = made("span", track, "thumb");
1662
+ const bubble = made("span", track, "bubble");
1663
+ for (const part2 of [fill, notch, thumb, bubble]) part2.setAttribute("aria-hidden", "true");
1664
+ let input = root.querySelector('input[type="range"]');
1665
+ if (input) {
1666
+ const kept = input;
1667
+ const place = { parent: kept.parentNode, next: kept.nextSibling };
1668
+ const saved = ["min", "max", "step", "value", "data-mk-bislider-input"].map((name) => [name, kept.getAttribute(name)]);
1669
+ const value2 = kept.value;
1670
+ scope.add(() => {
1671
+ for (const [name, was] of saved) {
1672
+ if (was === null) kept.removeAttribute(name);
1673
+ else kept.setAttribute(name, was);
1674
+ }
1675
+ kept.value = value2;
1676
+ place.parent?.insertBefore(kept, place.next);
1677
+ });
1678
+ } else {
1679
+ input = document.createElement("input");
1680
+ input.type = "range";
1681
+ scope.add(() => input.remove());
1682
+ }
1683
+ const range = input;
1684
+ track.append(range);
1685
+ range.dataset.mkBisliderInput = "";
1686
+ range.min = String(min);
1687
+ range.max = String(max);
1688
+ range.step = String(step);
1689
+ if (options.name) scope.attr(range, "name", options.name);
1690
+ if (options.label && !range.getAttribute("aria-label")) scope.attr(range, "aria-label", options.label);
1691
+ if (options.disabled) scope.attr(range, "disabled", "");
1692
+ const start = snap(finite(options.value) ? options.value : range.getAttribute("value") !== null ? Number(range.getAttribute("value")) : origin);
1693
+ range.value = String(start);
1694
+ range.defaultValue = String(start);
1695
+ scope.attr(root, "data-mk-ready", "");
1696
+ let value = start;
1697
+ let committed = start;
1698
+ const shown = { v: start };
1699
+ const pct = (n) => (n - min) / (max - min) * 100;
1700
+ notch.style.left = `${pct(origin)}%`;
1701
+ const paint = () => {
1702
+ const at = pct(shown.v);
1703
+ const from = pct(origin);
1704
+ fill.style.left = `${Math.min(at, from)}%`;
1705
+ fill.style.width = `${Math.abs(at - from)}%`;
1706
+ thumb.style.left = `${at}%`;
1707
+ bubble.style.left = `${at}%`;
1708
+ root.setAttribute("data-mk-side", shown.v > origin ? "more" : shown.v < origin ? "less" : "origin");
1709
+ };
1710
+ scope.add(() => root.removeAttribute("data-mk-side"));
1711
+ const describe = () => {
1712
+ const text = format(value);
1713
+ bubble.textContent = text;
1714
+ range.setAttribute("aria-valuetext", text);
1715
+ };
1716
+ scope.add(() => range.removeAttribute("aria-valuetext"));
1717
+ const effects = /* @__PURE__ */ new Set();
1718
+ const keep = (animation) => {
1719
+ if (!animation) return;
1720
+ effects.add(animation);
1721
+ for (const effect of effects) if (effect.totalProgress() === 1) effects.delete(effect);
1722
+ };
1723
+ scope.add(() => {
1724
+ gsap.killTweensOf(shown);
1725
+ for (const effect of effects) effect.kill();
1726
+ effects.clear();
1727
+ });
1728
+ const bump = (element, scale = 1.25) => {
1729
+ if (!element || reduced()) return;
1730
+ keep(gsap.fromTo(element, { scale }, { scale: 1, duration: 0.5, ease: "elastic.out(1, 0.4)", overwrite: "auto" }));
1731
+ };
1732
+ let held = false;
1733
+ const set = (next, glide, notify) => {
1734
+ const before = value;
1735
+ value = snap(next);
1736
+ range.value = String(value);
1737
+ describe();
1738
+ gsap.killTweensOf(shown);
1739
+ if (glide && !reduced()) keep(gsap.to(shown, { v: value, duration: 0.45, ease: EASE.swatch, onUpdate: paint }));
1740
+ else {
1741
+ shown.v = value;
1742
+ paint();
1743
+ }
1744
+ if ((before - origin) * (value - origin) < 0 || before !== origin && value === origin) bump(notch, 1.8);
1745
+ if (value !== before && value === max) bump(more);
1746
+ if (value !== before && value === min) bump(less);
1747
+ if (notify && value !== before) {
1748
+ options.onInput?.(value);
1749
+ root.dispatchEvent(new CustomEvent("mk:input", { bubbles: true, detail: { value } }));
1750
+ }
1751
+ if (notify === "change") commit();
1752
+ };
1753
+ const commit = () => {
1754
+ if (value === committed) return;
1755
+ committed = value;
1756
+ options.onChange?.(value);
1757
+ root.dispatchEvent(new CustomEvent("mk:change", { bubbles: true, detail: { value } }));
1758
+ };
1759
+ scope.on(range, "input", () => {
1760
+ const next = Number(range.value);
1761
+ const before = value;
1762
+ set(next, !held, false);
1763
+ if (value !== before) {
1764
+ options.onInput?.(value);
1765
+ root.dispatchEvent(new CustomEvent("mk:input", { bubbles: true, detail: { value } }));
1766
+ }
1767
+ });
1768
+ scope.on(range, "change", commit);
1769
+ scope.on(range, "dblclick", () => set(origin, true, "change"));
1770
+ let pointer = null;
1771
+ scope.on(range, "pointerdown", (event) => {
1772
+ const down = event;
1773
+ if (range.disabled || down.button !== 0) return;
1774
+ held = true;
1775
+ pointer = down.pointerId;
1776
+ root.setAttribute("data-mk-held", "");
1777
+ });
1778
+ scope.on(window, "pointermove", (event) => {
1779
+ const move = event;
1780
+ if (!held || move.pointerId !== pointer || reduced()) return;
1781
+ const box = track.getBoundingClientRect();
1782
+ const over = move.clientX > box.right ? move.clientX - box.right : move.clientX < box.left ? move.clientX - box.left : 0;
1783
+ const stretch = Math.min(1, Math.abs(over) / 80) * 0.04;
1784
+ gsap.set(track, { scaleX: 1 + stretch, transformOrigin: over > 0 ? "0% 50%" : "100% 50%" });
1785
+ });
1786
+ const release = (event) => {
1787
+ if (!held || event.pointerId !== pointer) return;
1788
+ held = false;
1789
+ pointer = null;
1790
+ root.removeAttribute("data-mk-held");
1791
+ if (!reduced()) keep(gsap.to(track, { scaleX: 1, duration: 0.6, ease: "elastic.out(1, 0.35)", clearProps: "transform,transformOrigin" }));
1792
+ };
1793
+ scope.on(window, "pointerup", release);
1794
+ scope.on(window, "pointercancel", release);
1795
+ scope.add(() => {
1796
+ root.removeAttribute("data-mk-held");
1797
+ gsap.set(track, { clearProps: "transform,transformOrigin" });
1798
+ });
1799
+ let repeat;
1800
+ const stop = () => {
1801
+ clearTimeout(repeat);
1802
+ if (repeat !== void 0) commit();
1803
+ repeat = void 0;
1804
+ };
1805
+ scope.add(() => clearTimeout(repeat));
1806
+ for (const [button, direction] of [[less, -1], [more, 1]]) {
1807
+ if (!button) continue;
1808
+ scope.on(button, "pointerdown", (event) => {
1809
+ if (range.disabled || event.button !== 0) return;
1810
+ event.preventDefault();
1811
+ press(button);
1812
+ const tick = (delay) => {
1813
+ set(value + step * direction, true, "input");
1814
+ repeat = setTimeout(() => tick(Math.max(50, delay * 0.8)), delay);
1815
+ };
1816
+ tick(400);
1817
+ });
1818
+ scope.on(button, "pointerup", stop);
1819
+ scope.on(button, "pointerleave", stop);
1820
+ scope.on(button, "pointercancel", stop);
1821
+ }
1822
+ const form = range.form;
1823
+ if (form) scope.on(form, "reset", () => setTimeout(() => set(Number(range.defaultValue), true, false)));
1824
+ describe();
1825
+ paint();
1826
+ return {
1827
+ setValue: (next, notify = false) => set(next, true, notify ? "change" : false),
1828
+ reset: (notify = false) => set(origin, true, notify ? "change" : false),
1829
+ get value() {
1830
+ return value;
1831
+ },
1832
+ destroy: () => scope.dispose()
1833
+ };
1834
+ }
1835
+
1836
+ // src/components/voice-dots/engine.ts
1837
+ var LABELS = { idle: "Asistente en espera", listening: "Escuchando\u2026", thinking: "Pensando\u2026", speaking: "Hablando\u2026" };
1838
+ var STATES = ["idle", "listening", "thinking", "speaking"];
1839
+ var mediaSources = /* @__PURE__ */ new WeakMap();
1840
+ var audio = null;
1841
+ function createVoiceDots(root, options = {}) {
1842
+ if (!root) return inert({ setState() {
1843
+ }, state: "idle", setLevel() {
1844
+ }, listen: async () => () => {
1845
+ }, stop() {
1846
+ } });
1847
+ registerMotion();
1848
+ const scope = createScope();
1849
+ const count = Math.max(3, Math.min(6, Math.round(options.count ?? 4)));
1850
+ const size = Math.max(4, options.size ?? 12);
1851
+ const labels = { ...LABELS, ...options.labels };
1852
+ let state = STATES.includes(options.state) ? options.state : "idle";
1853
+ const row = document.createElement("span");
1854
+ row.dataset.mkVoiceRow = "";
1855
+ row.setAttribute("aria-hidden", "true");
1856
+ const dots = Array.from({ length: count }, (_, i) => {
1857
+ const dot = document.createElement("span");
1858
+ dot.dataset.mkVoiceDot = String(i + 1);
1859
+ row.append(dot);
1860
+ return dot;
1861
+ });
1862
+ const status = document.createElement("span");
1863
+ status.className = "mk-sr-only";
1864
+ status.setAttribute("role", "status");
1865
+ root.append(row, status);
1866
+ scope.add(() => {
1867
+ row.remove();
1868
+ status.remove();
1869
+ });
1870
+ scope.attr(root, "data-mk-ready", "");
1871
+ scope.attr(root, "data-mk-state", state);
1872
+ if (options.colorful) scope.attr(root, "data-mk-colorful", "");
1873
+ root.style.setProperty("--mk-voice-size", `${size}px`);
1874
+ scope.add(() => {
1875
+ root.style.removeProperty("--mk-voice-size");
1876
+ if (!root.getAttribute("style")) root.removeAttribute("style");
1877
+ });
1878
+ const drawn = dots.map(() => ({ h: size, x: 0, y: 0, vh: 0 }));
1879
+ const levels = dots.map(() => 0);
1880
+ let time = 0;
1881
+ const gap = size * 0.9;
1882
+ const home = (i) => (i - (count - 1) / 2) * (size + gap);
1883
+ const draw = () => {
1884
+ dots.forEach((dot, i) => {
1885
+ const d = drawn[i];
1886
+ dot.style.height = `${d.h.toFixed(2)}px`;
1887
+ dot.style.transform = `translate(${d.x.toFixed(2)}px, ${d.y.toFixed(2)}px)`;
1888
+ });
1889
+ };
1890
+ const still = () => {
1891
+ dots.forEach((_, i) => Object.assign(drawn[i], { h: size, x: 0, y: 0, vh: 0 }));
1892
+ draw();
1893
+ };
1894
+ let analyser = null;
1895
+ let bins = null;
1896
+ let release = null;
1897
+ let listening = 0;
1898
+ const sample = () => {
1899
+ if (!analyser || !bins) return;
1900
+ analyser.getByteFrequencyData(bins);
1901
+ const hz = (audio?.sampleRate ?? 48e3) / 2 / bins.length;
1902
+ const low = Math.max(1, Math.floor(120 / hz));
1903
+ const high = Math.min(bins.length - 1, Math.ceil(3e3 / hz));
1904
+ const span = (high - low) / count;
1905
+ for (let i = 0; i < count; i++) {
1906
+ let sum = 0;
1907
+ const from = Math.floor(low + span * i);
1908
+ const to = Math.max(from + 1, Math.floor(low + span * (i + 1)));
1909
+ for (let k = from; k < to; k++) sum += bins[k];
1910
+ levels[i] = Math.min(1, sum / (to - from) / 255 * (1.4 + i * 0.35));
1911
+ }
1912
+ };
1913
+ const tick = (dt) => {
1914
+ if (reduced()) return;
1915
+ time += dt / 60;
1916
+ sample();
1917
+ const k = 1 - Math.exp(-dt * 0.35);
1918
+ dots.forEach((_, i) => {
1919
+ const d = drawn[i];
1920
+ let h = size;
1921
+ let x = 0;
1922
+ let y = 0;
1923
+ if (state === "idle") {
1924
+ h = size * (1 + 0.18 * Math.max(0, Math.sin(time * 3.2 - i * 0.7)));
1925
+ y = -2 * Math.max(0, Math.sin(time * 3.2 - i * 0.7));
1926
+ } else if (state === "listening") {
1927
+ h = size + levels[i] * size * 3.2;
1928
+ } else if (state === "thinking") {
1929
+ const angle = time * 4 + i / count * Math.PI * 2;
1930
+ const ring = size * 1.2;
1931
+ x = Math.cos(angle) * ring - home(i);
1932
+ y = Math.sin(angle) * ring;
1933
+ } else {
1934
+ const wave = 0.5 + 0.5 * Math.sin(time * 9 - i * 0.9);
1935
+ const voice = analyser ? levels[i] : 0.55;
1936
+ h = size + wave * voice * size * 2.4;
1937
+ }
1938
+ const stiffness = h > d.h ? 0.5 : 0.18;
1939
+ d.vh = (d.vh + (h - d.h) * stiffness) * 0.6;
1940
+ d.h = Math.max(size * 0.8, d.h + d.vh * dt);
1941
+ d.x += (x - d.x) * k;
1942
+ d.y += (y - d.y) * k;
1943
+ });
1944
+ draw();
1945
+ };
1946
+ const stopLoop = whileVisible(root, tick);
1947
+ scope.add(stopLoop);
1948
+ const stop = () => {
1949
+ listening++;
1950
+ release?.();
1951
+ release = null;
1952
+ analyser = null;
1953
+ bins = null;
1954
+ levels.fill(0);
1955
+ };
1956
+ scope.add(stop);
1957
+ const setState = (next) => {
1958
+ if (!STATES.includes(next)) return;
1959
+ state = next;
1960
+ root.setAttribute("data-mk-state", next);
1961
+ status.textContent = next === "idle" ? "" : labels[next];
1962
+ if (reduced()) still();
1963
+ root.dispatchEvent(new CustomEvent("mk:state", { bubbles: true, detail: { state: next } }));
1964
+ };
1965
+ draw();
1966
+ if (state !== "idle") status.textContent = labels[state];
1967
+ return {
1968
+ setState,
1969
+ get state() {
1970
+ return state;
1971
+ },
1972
+ setLevel(level) {
1973
+ const list = Array.isArray(level) ? level : dots.map(() => level);
1974
+ dots.forEach((_, i) => {
1975
+ const value = Number(list[i % Math.max(1, list.length)]);
1976
+ levels[i] = Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : 0;
1977
+ });
1978
+ },
1979
+ async listen(source) {
1980
+ stop();
1981
+ const request = listening;
1982
+ const Context = globalThis.AudioContext ?? globalThis.webkitAudioContext;
1983
+ if (!Context || scope.disposed) return () => {
1984
+ };
1985
+ audio ??= new Context();
1986
+ if (audio.state === "suspended") await audio.resume().catch(() => {
1987
+ });
1988
+ if (scope.disposed || request !== listening) return () => {
1989
+ };
1990
+ const node = audio.createAnalyser();
1991
+ node.fftSize = 256;
1992
+ node.smoothingTimeConstant = 0.55;
1993
+ let input;
1994
+ if (source instanceof HTMLMediaElement) {
1995
+ const existing = mediaSources.get(source) ?? audio.createMediaElementSource(source);
1996
+ mediaSources.set(source, existing);
1997
+ existing.disconnect();
1998
+ input = existing;
1999
+ node.connect(audio.destination);
2000
+ } else input = audio.createMediaStreamSource(source);
2001
+ input.connect(node);
2002
+ analyser = node;
2003
+ bins = new Uint8Array(new ArrayBuffer(node.frequencyBinCount));
2004
+ const mine = () => {
2005
+ try {
2006
+ input.disconnect(node);
2007
+ node.disconnect();
2008
+ } catch {
2009
+ }
2010
+ if (source instanceof HTMLMediaElement && audio) input.connect(audio.destination);
2011
+ };
2012
+ release = mine;
2013
+ return () => {
2014
+ if (release === mine) stop();
2015
+ };
2016
+ },
2017
+ stop,
2018
+ destroy: () => scope.dispose()
2019
+ };
2020
+ }
2021
+
2022
+ // src/components/chart/parts.ts
2023
+ var SVG_NS = "http://www.w3.org/2000/svg";
2024
+ var SLOTS = 8;
2025
+ var svg2 = (tag, attrs = {}) => {
2026
+ const element = document.createElementNS(SVG_NS, tag);
2027
+ for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, String(value));
2028
+ return element;
2029
+ };
2030
+ var finite2 = (value) => typeof value === "number" && Number.isFinite(value);
2031
+ var round = (n) => Math.round(n * 100) / 100;
2032
+ var slotColor = (i, total = SLOTS) => total === 1 ? "var(--mk-chart-mono)" : i < SLOTS ? `var(--mk-chart-${i + 1})` : "var(--mk-chart-other)";
2033
+ var formatNumber = (value) => new Intl.NumberFormat(void 0, { maximumFractionDigits: 2 }).format(value);
2034
+ var polar = (cx, cy, r, angle) => [cx + r * Math.sin(angle), cy - r * Math.cos(angle)];
2035
+ function arcPath(cx, cy, outer, inner, a0, a1) {
2036
+ const sweep = Math.min(a1 - a0, Math.PI * 2 - 1e-4);
2037
+ const end = a0 + sweep;
2038
+ const large = sweep > Math.PI ? 1 : 0;
2039
+ const [x0, y0] = polar(cx, cy, outer, a0);
2040
+ const [x1, y1] = polar(cx, cy, outer, end);
2041
+ if (inner <= 0) return `M${round(cx)},${round(cy)}L${round(x0)},${round(y0)}A${round(outer)},${round(outer)} 0 ${large} 1 ${round(x1)},${round(y1)}Z`;
2042
+ const [x2, y2] = polar(cx, cy, inner, end);
2043
+ const [x3, y3] = polar(cx, cy, inner, a0);
2044
+ return `M${round(x0)},${round(y0)}A${round(outer)},${round(outer)} 0 ${large} 1 ${round(x1)},${round(y1)}L${round(x2)},${round(y2)}A${round(inner)},${round(inner)} 0 ${large} 0 ${round(x3)},${round(y3)}Z`;
2045
+ }
2046
+ function chartFrame(root, scope, kind) {
2047
+ if (!root.classList.contains("mk-chart")) {
2048
+ root.classList.add("mk-chart");
2049
+ scope.add(() => {
2050
+ root.classList.remove("mk-chart");
2051
+ if (!root.classList.length) root.removeAttribute("class");
2052
+ });
2053
+ }
2054
+ scope.attr(root, "data-mk-chart-type", kind);
2055
+ const made = (tag, parent = root) => {
2056
+ const element = document.createElement(tag);
2057
+ parent.append(element);
2058
+ scope.add(() => element.remove());
2059
+ return element;
2060
+ };
2061
+ const plot = made("div");
2062
+ plot.dataset.mkChartPlot = "";
2063
+ const canvas = svg2("svg");
2064
+ canvas.dataset.mkChartSvg = "";
2065
+ canvas.setAttribute("role", "img");
2066
+ canvas.setAttribute("tabindex", "0");
2067
+ canvas.setAttribute("focusable", "true");
2068
+ plot.append(canvas);
2069
+ const tooltip = made("div", plot);
2070
+ tooltip.dataset.mkChartTooltip = "";
2071
+ tooltip.setAttribute("aria-hidden", "true");
2072
+ tooltip.hidden = true;
2073
+ const empty = made("p");
2074
+ empty.dataset.mkChartEmpty = "";
2075
+ empty.hidden = true;
2076
+ const legend = made("ul");
2077
+ legend.dataset.mkChartLegend = "";
2078
+ const table = made("table");
2079
+ table.dataset.mkChartTable = "";
2080
+ table.className = "mk-sr-only";
2081
+ const live = made("span");
2082
+ live.className = "mk-sr-only";
2083
+ live.setAttribute("role", "status");
2084
+ scope.attr(root, "data-mk-ready", "");
2085
+ const effects = /* @__PURE__ */ new Set();
2086
+ const keep = (animation) => {
2087
+ if (!animation) return;
2088
+ effects.add(animation);
2089
+ for (const effect of effects) if (effect.totalProgress() === 1) effects.delete(effect);
2090
+ };
2091
+ scope.add(() => {
2092
+ for (const effect of effects) effect.kill();
2093
+ effects.clear();
2094
+ gsap.killTweensOf(tooltip);
2095
+ });
2096
+ const tip = (at) => {
2097
+ if (!at) {
2098
+ if (!tooltip.hidden && !reduced()) {
2099
+ gsap.killTweensOf(tooltip, "opacity,scale");
2100
+ keep(gsap.to(tooltip, { opacity: 0, scale: 0.94, duration: 0.15, ease: "power2.in", onComplete: () => {
2101
+ tooltip.hidden = true;
2102
+ } }));
2103
+ } else tooltip.hidden = true;
2104
+ return;
2105
+ }
2106
+ tooltip.replaceChildren();
2107
+ const title = document.createElement("strong");
2108
+ title.textContent = at.title;
2109
+ tooltip.append(title);
2110
+ for (const each of at.rows) {
2111
+ const row = document.createElement("span");
2112
+ row.dataset.mkChartRow = "";
2113
+ const swatch = document.createElement("i");
2114
+ if (!each.color || /--mk-(text|chart-mono|muted)/.test(each.color)) swatch.dataset.mkMono = "";
2115
+ else swatch.style.background = each.color;
2116
+ const name = document.createElement("span");
2117
+ name.textContent = each.name;
2118
+ const amount = document.createElement("b");
2119
+ amount.textContent = each.value;
2120
+ row.append(swatch, name, amount);
2121
+ tooltip.append(row);
2122
+ }
2123
+ const appearing = tooltip.hidden;
2124
+ tooltip.hidden = false;
2125
+ const width = plot.clientWidth || 300;
2126
+ const height = plot.clientHeight || 240;
2127
+ const tipW = tooltip.offsetWidth || 160;
2128
+ const tipH = tooltip.offsetHeight || 60;
2129
+ const left = round(Math.max(0, Math.min(width - tipW, at.x > width / 2 ? at.x - 16 - tipW : at.x + 16)));
2130
+ const top = round(Math.max(0, Math.min(height - tipH, at.y - tipH - 12)));
2131
+ if (appearing || reduced()) {
2132
+ gsap.killTweensOf(tooltip);
2133
+ gsap.set(tooltip, { x: left, y: top });
2134
+ if (!reduced()) keep(gsap.fromTo(tooltip, { opacity: 0, scale: 0.9 }, { opacity: 1, scale: 1, duration: 0.25, ease: EASE.pop }));
2135
+ else gsap.set(tooltip, { opacity: 1, scale: 1 });
2136
+ } else {
2137
+ gsap.killTweensOf(tooltip, "opacity,scale");
2138
+ gsap.set(tooltip, { opacity: 1, scale: 1 });
2139
+ keep(gsap.to(tooltip, { x: left, y: top, duration: 0.25, ease: "power3.out", overwrite: "auto" }));
2140
+ }
2141
+ };
2142
+ const fillLegend = (items2, show2, type = "bar") => {
2143
+ legend.replaceChildren();
2144
+ legend.hidden = !show2 || !items2.length;
2145
+ if (legend.hidden) return [];
2146
+ return items2.map((item) => {
2147
+ const li = document.createElement("li");
2148
+ const swatch = document.createElement("span");
2149
+ swatch.dataset.mkChartSwatch = "";
2150
+ swatch.dataset.mkType = type;
2151
+ swatch.style.background = item.color;
2152
+ swatch.style.color = item.color;
2153
+ swatch.setAttribute("aria-hidden", "true");
2154
+ const name = document.createElement("span");
2155
+ name.textContent = item.name;
2156
+ li.append(swatch, name);
2157
+ legend.append(li);
2158
+ return li;
2159
+ });
2160
+ };
2161
+ const fillTable = (caption, head, rows) => {
2162
+ table.replaceChildren();
2163
+ const cap = document.createElement("caption");
2164
+ cap.textContent = caption;
2165
+ const thead = document.createElement("thead");
2166
+ const headRow = document.createElement("tr");
2167
+ for (const text of head) {
2168
+ const th = document.createElement("th");
2169
+ th.scope = "col";
2170
+ th.textContent = text;
2171
+ headRow.append(th);
2172
+ }
2173
+ thead.append(headRow);
2174
+ const body = document.createElement("tbody");
2175
+ for (const cells of rows) {
2176
+ const row = document.createElement("tr");
2177
+ cells.forEach((text, i) => {
2178
+ const cell = document.createElement(i ? "td" : "th");
2179
+ if (!i) cell.scope = "row";
2180
+ cell.textContent = text;
2181
+ row.append(cell);
2182
+ });
2183
+ body.append(row);
2184
+ }
2185
+ table.append(cap, thead, body);
2186
+ };
2187
+ return { plot, canvas, tooltip, empty, legend, table, live, tip, fillLegend, fillTable, keep };
2188
+ }
2189
+ function onWidth(root, scope, draw) {
2190
+ if (typeof ResizeObserver !== "function") return;
2191
+ let width = 0;
2192
+ let frame = 0;
2193
+ const observer = scope.observe(
2194
+ new ResizeObserver(() => {
2195
+ const next = Math.round(root.clientWidth);
2196
+ if (!next || next === width) return;
2197
+ const first = !width;
2198
+ width = next;
2199
+ if (first) return;
2200
+ cancelAnimationFrame(frame);
2201
+ frame = requestAnimationFrame(draw);
2202
+ })
2203
+ );
2204
+ observer.observe(root);
2205
+ scope.add(() => cancelAnimationFrame(frame));
2206
+ }
2207
+
2208
+ // src/components/pie-chart/engine.ts
2209
+ var PULL = 7;
2210
+ function createPieChart(root, initial = {}) {
2211
+ if (!root) return inert({ update() {
2212
+ }, select() {
2213
+ }, selected: null });
2214
+ registerMotion();
2215
+ const scope = createScope();
2216
+ const frame = chartFrame(root, scope, "pie");
2217
+ const { plot, canvas, keep } = frame;
2218
+ let options = { ...initial };
2219
+ let selected = null;
2220
+ const center = document.createElement("div");
2221
+ center.dataset.mkPieCenter = "";
2222
+ center.setAttribute("aria-hidden", "true");
2223
+ const centerValue = document.createElement("strong");
2224
+ const centerLabel = document.createElement("span");
2225
+ center.append(centerValue, centerLabel);
2226
+ plot.append(center);
2227
+ scope.add(() => center.remove());
2228
+ const format = (value) => options.formatValue ? options.formatValue(value) : formatNumber(value);
2229
+ const slices = () => (options.data ?? []).filter((slice) => finite2(slice.value) && slice.value > 0).map((slice, i, all) => ({ label: String(slice.label), value: slice.value, color: slice.color ?? slotColor(i, Math.max(2, all.length)) }));
2230
+ let model = slices();
2231
+ const total = () => model.reduce((sum, slice) => sum + slice.value, 0);
2232
+ const share = (value) => new Intl.NumberFormat(void 0, { style: "percent", maximumFractionDigits: 1 }).format(value / (total() || 1));
2233
+ const donut = () => Math.min(0.9, Math.max(0, finite2(options.donut) ? options.donut : 0.62));
2234
+ const anglesOf = (values) => {
2235
+ const sum = values.reduce((a, b) => a + b, 0) || 1;
2236
+ const pad = values.filter((v) => v > 0).length > 1 ? (finite2(options.gap) ? options.gap : 1.5) * Math.PI / 180 : 0;
2237
+ let at = 0;
2238
+ return values.map((value) => {
2239
+ const sweep = value / sum * Math.PI * 2;
2240
+ const a0 = at + Math.min(pad / 2, sweep / 4);
2241
+ const a1 = at + sweep - Math.min(pad / 2, sweep / 4);
2242
+ at += sweep;
2243
+ return [a0, Math.max(a0, a1)];
2244
+ });
2245
+ };
2246
+ let paths = [];
2247
+ let shown = [];
2248
+ let geometry = { size: 240, cx: 120, cy: 120, outer: 112, inner: 70 };
2249
+ let glide = null;
2250
+ scope.add(() => glide?.kill());
2251
+ const measure = () => {
2252
+ const width = Math.round(plot.clientWidth || root.clientWidth || 0);
2253
+ const wanted = finite2(options.size) ? options.size : 240;
2254
+ const size = Math.max(120, width ? Math.min(wanted, width) : wanted);
2255
+ const outer = size / 2 - PULL - 2;
2256
+ geometry = { size, cx: size / 2, cy: size / 2, outer, inner: outer * donut() };
2257
+ canvas.setAttribute("viewBox", `0 0 ${size} ${size}`);
2258
+ canvas.setAttribute("width", String(size));
2259
+ canvas.setAttribute("height", String(size));
2260
+ plot.style.setProperty("--mk-pie-size", `${size}px`);
2261
+ };
2262
+ scope.add(() => plot.style.removeProperty("--mk-pie-size"));
2263
+ const paint = (angles) => {
2264
+ shown = angles;
2265
+ const { cx, cy, outer, inner } = geometry;
2266
+ paths.forEach((path, i) => {
2267
+ const [a0, a1] = angles[i] ?? [0, 0];
2268
+ path.setAttribute("d", a1 - a0 > 1e-4 ? arcPath(cx, cy, outer, inner, a0, a1) : "");
2269
+ });
2270
+ };
2271
+ const build = () => {
2272
+ canvas.replaceChildren();
2273
+ const group = svg2("g", { "data-mk-part": "series" });
2274
+ paths = model.map((slice, i) => {
2275
+ const path = svg2("path", { "data-mk-index": i });
2276
+ path.style.fill = slice.color;
2277
+ group.append(path);
2278
+ return path;
2279
+ });
2280
+ canvas.append(group);
2281
+ };
2282
+ const paintCenter = (animate) => {
2283
+ center.hidden = donut() < 0.35 || !model.length;
2284
+ if (center.hidden) return;
2285
+ const slice = selected === null ? null : model[selected];
2286
+ const text = slice ? format(slice.value) : format(total());
2287
+ const caption = slice ? `${slice.label} \xB7 ${share(slice.value)}` : options.totalLabel ?? "Total";
2288
+ const changed = centerLabel.textContent !== caption;
2289
+ if (centerValue.textContent !== text) {
2290
+ if (animate && !reduced() && centerValue.textContent) keep(rollDigits(centerValue, text, 1, 0.35));
2291
+ else centerValue.textContent = text;
2292
+ }
2293
+ centerLabel.textContent = caption;
2294
+ if (changed && animate && !reduced()) keep(blurIn(centerLabel, { from: "soft", duration: 0.3 }));
2295
+ };
2296
+ const paintSelection = (announce) => {
2297
+ const { outer } = geometry;
2298
+ paths.forEach((path, i) => {
2299
+ const chosen = i === selected;
2300
+ path.toggleAttribute("data-mk-dim", selected !== null && !chosen);
2301
+ if (!chosen) {
2302
+ path.style.transform = "";
2303
+ return;
2304
+ }
2305
+ const [a0, a1] = shown[i] ?? [0, 0];
2306
+ const [dx, dy] = polar(0, 0, Math.min(PULL, outer * 0.06), (a0 + a1) / 2);
2307
+ path.style.transform = `translate(${round(dx)}px, ${round(dy)}px)`;
2308
+ });
2309
+ legendItems.forEach((item, i) => item.toggleAttribute("data-mk-dim", selected !== null && i !== selected));
2310
+ paintCenter(true);
2311
+ const slice = selected === null ? null : model[selected];
2312
+ if (slice && center.hidden) {
2313
+ const [a0, a1] = shown[selected] ?? [0, 0];
2314
+ const [x, y] = polar(geometry.cx, geometry.cy, geometry.outer * 0.7, (a0 + a1) / 2);
2315
+ frame.tip({ x, y, title: slice.label, rows: [{ name: share(slice.value), color: slice.color, value: format(slice.value) }] });
2316
+ } else frame.tip(null);
2317
+ if (announce && slice) frame.live.textContent = `${slice.label}: ${format(slice.value)}, ${share(slice.value)}`;
2318
+ };
2319
+ let legendItems = [];
2320
+ const draw = (animate) => {
2321
+ glide?.kill();
2322
+ const before = shown;
2323
+ const sameCount = paths.length === model.length;
2324
+ const name = options.label ?? "Gr\xE1fica circular";
2325
+ canvas.setAttribute("aria-label", model.length ? `${name}. ${model.length} partes, total ${format(total())}. Usa las flechas para recorrerlas.` : `${name}: ${options.emptyLabel ?? "sin datos"}`);
2326
+ frame.fillTable(name, ["Parte", "Valor", "Porcentaje"], model.map((slice) => [slice.label, format(slice.value), share(slice.value)]));
2327
+ legendItems = frame.fillLegend(model.map((slice) => ({ name: slice.label, color: slice.color })), options.legend ?? true);
2328
+ legendItems.forEach((item, i) => {
2329
+ item.addEventListener("pointerenter", () => select(i));
2330
+ item.addEventListener("pointerleave", () => select(null));
2331
+ });
2332
+ frame.empty.hidden = model.length > 0;
2333
+ frame.empty.textContent = options.emptyLabel ?? "Sin datos para mostrar";
2334
+ plot.hidden = !model.length;
2335
+ if (!model.length) {
2336
+ canvas.replaceChildren();
2337
+ paths = [];
2338
+ shown = [];
2339
+ selected = null;
2340
+ return;
2341
+ }
2342
+ if (selected !== null && selected >= model.length) selected = null;
2343
+ measure();
2344
+ if (!sameCount || !before.length) build();
2345
+ paths.forEach((path, i) => {
2346
+ path.style.fill = model[i].color;
2347
+ });
2348
+ const target = anglesOf(model.map((slice) => slice.value));
2349
+ const done = () => {
2350
+ paint(target);
2351
+ paintSelection(false);
2352
+ };
2353
+ if (!animate || reduced()) return done();
2354
+ const state = { t: 0 };
2355
+ if (sameCount && before.length) {
2356
+ glide = gsap.to(state, {
2357
+ t: 1,
2358
+ duration: 0.6,
2359
+ ease: EASE.swatch,
2360
+ onUpdate: () => paint(target.map(([a0, a1], i) => [before[i][0] + (a0 - before[i][0]) * state.t, before[i][1] + (a1 - before[i][1]) * state.t])),
2361
+ onComplete: done
2362
+ });
2363
+ paintCenter(true);
2364
+ return;
2365
+ }
2366
+ paint(target.map(() => [0, 0]));
2367
+ centerValue.textContent = format(0);
2368
+ glide = gsap.to(state, {
2369
+ t: 1,
2370
+ duration: 0.9,
2371
+ ease: EASE.signature,
2372
+ onUpdate: () => paint(target.map(([a0, a1]) => [a0 * state.t, a1 * state.t])),
2373
+ onComplete: done
2374
+ });
2375
+ paintCenter(true);
2376
+ };
2377
+ const select = (index, announce = false) => {
2378
+ if (scope.disposed) return;
2379
+ const next = index === null || !model.length ? null : (Math.round(index) % model.length + model.length) % model.length;
2380
+ if (next === selected) return;
2381
+ selected = next;
2382
+ paintSelection(announce);
2383
+ options.onSelect?.(selected);
2384
+ const slice = selected === null ? null : model[selected];
2385
+ root.dispatchEvent(new CustomEvent("mk:select", { bubbles: true, detail: { index: selected, label: slice?.label ?? null, value: slice?.value ?? null } }));
2386
+ };
2387
+ const indexAt = (event) => {
2388
+ const target = event.target.closest("[data-mk-index]");
2389
+ return target ? Number(target.getAttribute("data-mk-index")) : null;
2390
+ };
2391
+ scope.on(canvas, "pointermove", (event) => select(indexAt(event)));
2392
+ scope.on(canvas, "pointerdown", (event) => select(indexAt(event)));
2393
+ scope.on(canvas, "pointerleave", (event) => {
2394
+ if (event.pointerType === "mouse") select(null);
2395
+ });
2396
+ scope.on(canvas, "focus", () => {
2397
+ if (selected === null && model.length) select(0, true);
2398
+ });
2399
+ scope.on(canvas, "blur", () => select(null));
2400
+ scope.on(canvas, "keydown", (event) => {
2401
+ const key = event.key;
2402
+ const moves = { ArrowRight: (selected ?? -1) + 1, ArrowDown: (selected ?? -1) + 1, ArrowLeft: (selected ?? 1) - 1, ArrowUp: (selected ?? 1) - 1, Home: 0, End: model.length - 1, Escape: null };
2403
+ if (!(key in moves) || !model.length) return;
2404
+ event.preventDefault();
2405
+ select(moves[key], true);
2406
+ });
2407
+ onWidth(root, scope, () => {
2408
+ measure();
2409
+ paint(shown);
2410
+ paintSelection(false);
2411
+ });
2412
+ draw(true);
2413
+ return {
2414
+ update(next) {
2415
+ if (scope.disposed) return;
2416
+ options = { ...options, ...next };
2417
+ model = slices();
2418
+ draw(true);
2419
+ },
2420
+ select: (index) => select(index),
2421
+ get selected() {
2422
+ return selected;
2423
+ },
2424
+ destroy: () => scope.dispose()
2425
+ };
2426
+ }
2427
+
2428
+ // src/components/radar-chart/engine.ts
2429
+ function niceMax(value) {
2430
+ if (value <= 0) return 1;
2431
+ const power = 10 ** Math.floor(Math.log10(value));
2432
+ const fraction = value / power;
2433
+ return (fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 2.5 ? 2.5 : fraction <= 5 ? 5 : 10) * power;
2434
+ }
2435
+ function createRadarChart(root, initial = {}) {
2436
+ if (!root) return inert({ update() {
2437
+ }, select() {
2438
+ }, selected: null });
2439
+ registerMotion();
2440
+ const scope = createScope();
2441
+ const frame = chartFrame(root, scope, "radar");
2442
+ const { plot, canvas, keep } = frame;
2443
+ let options = { ...initial };
2444
+ let selected = null;
2445
+ let focusSeries = null;
2446
+ const format = (value) => options.formatValue ? options.formatValue(value) : formatNumber(value);
2447
+ const modelOf = () => {
2448
+ const axes = (options.axes ?? []).map(String);
2449
+ const raw = options.series ?? [];
2450
+ return {
2451
+ axes,
2452
+ series: raw.map((series, i) => ({
2453
+ name: String(series.name ?? ""),
2454
+ values: axes.map((_, k) => finite2(series.values[k]) ? Math.max(0, series.values[k]) : null),
2455
+ color: series.color ?? slotColor(i, raw.length)
2456
+ }))
2457
+ };
2458
+ };
2459
+ let model = modelOf();
2460
+ const hasData = () => model.axes.length >= 3 && model.series.some((series) => series.values.some(finite2));
2461
+ const maxOf = () => finite2(options.max) && options.max > 0 ? options.max : niceMax(Math.max(0, ...model.series.flatMap((series) => series.values.filter(finite2))));
2462
+ let geometry = { size: 300, cx: 150, cy: 150, r: 110 };
2463
+ const angle = (k) => k / model.axes.length * Math.PI * 2;
2464
+ let shapes = [];
2465
+ let guide = null;
2466
+ let labels = [];
2467
+ let shown = [];
2468
+ let glide = null;
2469
+ scope.add(() => glide?.kill());
2470
+ const measure = () => {
2471
+ const width = Math.round(plot.clientWidth || root.clientWidth || 0);
2472
+ const wanted = finite2(options.size) ? options.size : 300;
2473
+ const size = Math.max(180, width ? Math.min(wanted, width) : wanted);
2474
+ const r = size / 2 - Math.min(64, Math.max(36, Math.max(...model.axes.map((axis) => axis.length)) * 3.6 + 14));
2475
+ geometry = { size, cx: size / 2, cy: size / 2, r: Math.max(40, r) };
2476
+ canvas.setAttribute("viewBox", `0 0 ${size} ${size}`);
2477
+ canvas.setAttribute("width", String(size));
2478
+ canvas.setAttribute("height", String(size));
2479
+ plot.style.setProperty("--mk-radar-size", `${size}px`);
2480
+ };
2481
+ scope.add(() => plot.style.removeProperty("--mk-radar-size"));
2482
+ const pointOf = (value, k, max) => polar(geometry.cx, geometry.cy, Math.min(value, max) / max * geometry.r, angle(k));
2483
+ const build = () => {
2484
+ canvas.replaceChildren();
2485
+ const { cx, cy, r } = geometry;
2486
+ const n = model.axes.length;
2487
+ const levels = Math.max(1, Math.round(options.levels ?? 4));
2488
+ const grid = svg2("g", { "data-mk-part": "grid" });
2489
+ for (let level = 1; level <= levels; level++) {
2490
+ const radius = r * level / levels;
2491
+ if (options.grid === "circle") grid.append(svg2("circle", { cx, cy, r: round(radius) }));
2492
+ else {
2493
+ const points = Array.from({ length: n }, (_, k) => polar(cx, cy, radius, angle(k)).map(round).join(",")).join(" ");
2494
+ grid.append(svg2("polygon", { points }));
2495
+ }
2496
+ }
2497
+ for (let k = 0; k < n; k++) {
2498
+ const [x, y] = polar(cx, cy, r, angle(k));
2499
+ grid.append(svg2("line", { x1: cx, y1: cy, x2: round(x), y2: round(y), "data-mk-spoke": k }));
2500
+ }
2501
+ canvas.append(grid);
2502
+ const names = svg2("g", { "data-mk-part": "axes" });
2503
+ labels = model.axes.map((axis, k) => {
2504
+ const a = angle(k);
2505
+ const [x, y] = polar(cx, cy, r + 14, a);
2506
+ const sin = Math.sin(a);
2507
+ const text = svg2("text", { x: round(x), y: round(y), "text-anchor": Math.abs(sin) < 0.2 ? "middle" : sin > 0 ? "start" : "end", "dominant-baseline": "middle" });
2508
+ text.textContent = axis;
2509
+ names.append(text);
2510
+ return text;
2511
+ });
2512
+ canvas.append(names);
2513
+ guide = svg2("line", { "data-mk-part": "guide" });
2514
+ guide.style.display = "none";
2515
+ canvas.append(guide);
2516
+ const series = svg2("g", { "data-mk-part": "series" });
2517
+ shapes = model.series.map((each, s) => {
2518
+ const group = svg2("g", { "data-mk-series": s });
2519
+ const area = svg2("path", { "data-mk-part": "area" });
2520
+ area.style.fill = each.color;
2521
+ const edge = svg2("path", { "data-mk-part": "edge" });
2522
+ edge.style.stroke = each.color;
2523
+ group.append(area, edge);
2524
+ const dots = model.axes.map(() => {
2525
+ const dot = svg2("circle", { r: 3, "data-mk-part": "dot" });
2526
+ dot.style.fill = each.color;
2527
+ group.append(dot);
2528
+ return dot;
2529
+ });
2530
+ series.append(group);
2531
+ return { area, edge, dots };
2532
+ });
2533
+ canvas.append(series);
2534
+ };
2535
+ const paint = (values) => {
2536
+ shown = values;
2537
+ const max = maxOf();
2538
+ shapes.forEach((shape, s) => {
2539
+ const list = values[s] ?? [];
2540
+ const points = model.axes.map((_, k) => pointOf(list[k] ?? 0, k, max));
2541
+ const d = `M${points.map(([x, y]) => `${round(x)},${round(y)}`).join("L")}Z`;
2542
+ shape.area.setAttribute("d", d);
2543
+ shape.edge.setAttribute("d", d);
2544
+ shape.dots.forEach((dot, k) => {
2545
+ dot.setAttribute("cx", String(round(points[k][0])));
2546
+ dot.setAttribute("cy", String(round(points[k][1])));
2547
+ dot.style.display = finite2(model.series[s].values[k]) ? "" : "none";
2548
+ });
2549
+ });
2550
+ };
2551
+ const paintSelection = (announce) => {
2552
+ shapes.forEach((shape, s) => {
2553
+ shape.area.parentElement.toggleAttribute("data-mk-dim", focusSeries !== null && s !== focusSeries);
2554
+ shape.dots.forEach((dot, k2) => {
2555
+ const on = k2 === selected;
2556
+ if (on === dot.hasAttribute("data-mk-on")) return;
2557
+ dot.toggleAttribute("data-mk-on", on);
2558
+ const r = on ? 5 : 3;
2559
+ if (reduced()) dot.setAttribute("r", String(r));
2560
+ else keep(gsap.to(dot, { attr: { r }, duration: on ? 0.3 : 0.2, ease: on ? EASE.pop : "power2.out" }));
2561
+ });
2562
+ });
2563
+ labels.forEach((label, k2) => label.toggleAttribute("data-mk-on", k2 === selected));
2564
+ if (selected === null || !guide) {
2565
+ if (guide) guide.style.display = "none";
2566
+ frame.tip(null);
2567
+ return;
2568
+ }
2569
+ const k = selected;
2570
+ const [x, y] = polar(geometry.cx, geometry.cy, geometry.r, angle(k));
2571
+ Object.entries({ x1: geometry.cx, y1: geometry.cy, x2: round(x), y2: round(y) }).forEach(([name, value]) => guide.setAttribute(name, String(value)));
2572
+ guide.style.display = "";
2573
+ const rows = model.series.map((series) => ({ name: series.name, color: series.color, value: finite2(series.values[k]) ? format(series.values[k]) : "\u2014" }));
2574
+ const max = maxOf();
2575
+ const top = Math.min(...model.series.map((series) => pointOf(series.values[k] ?? 0, k, max)[1]));
2576
+ frame.tip({ x: round(x), y: Math.min(round(y), top), title: model.axes[k], rows });
2577
+ if (announce) frame.live.textContent = `${model.axes[k]}. ${rows.map((row) => `${row.name ? `${row.name}: ` : ""}${row.value}`).join(". ")}`;
2578
+ };
2579
+ let legendItems = [];
2580
+ const draw = (animate) => {
2581
+ glide?.kill();
2582
+ const name = options.label ?? "Gr\xE1fica de radar";
2583
+ canvas.setAttribute("aria-label", hasData() ? `${name}. ${model.axes.length} medidas: ${model.axes.join(", ")}. Series: ${model.series.map((series) => series.name).join(", ")}. Usa las flechas para recorrer las medidas.` : `${name}: ${options.emptyLabel ?? "sin datos"}`);
2584
+ frame.fillTable(name, ["Medida", ...model.series.map((series) => series.name || "Valor")], model.axes.map((axis, k) => [axis, ...model.series.map((series) => finite2(series.values[k]) ? format(series.values[k]) : "\u2014")]));
2585
+ legendItems = frame.fillLegend(model.series, options.legend ?? model.series.length > 1, "area");
2586
+ legendItems.forEach((item, s) => {
2587
+ item.addEventListener("pointerenter", () => {
2588
+ focusSeries = s;
2589
+ paintSelection(false);
2590
+ });
2591
+ item.addEventListener("pointerleave", () => {
2592
+ focusSeries = null;
2593
+ paintSelection(false);
2594
+ });
2595
+ });
2596
+ const ok = hasData();
2597
+ frame.empty.hidden = ok;
2598
+ frame.empty.textContent = options.emptyLabel ?? "Sin datos para mostrar";
2599
+ plot.hidden = !ok;
2600
+ if (!ok) {
2601
+ canvas.replaceChildren();
2602
+ shapes = [];
2603
+ shown = [];
2604
+ selected = null;
2605
+ return;
2606
+ }
2607
+ if (selected !== null && selected >= model.axes.length) selected = null;
2608
+ const before = shown;
2609
+ const comparable = before.length === model.series.length && before.every((list) => list.length === model.axes.length) && shapes.length === model.series.length;
2610
+ measure();
2611
+ build();
2612
+ const target = model.series.map((series) => series.values.map((value) => value ?? 0));
2613
+ const done = () => {
2614
+ paint(target);
2615
+ paintSelection(false);
2616
+ };
2617
+ if (!animate || reduced()) return done();
2618
+ const state = { t: 0 };
2619
+ if (comparable) {
2620
+ glide = gsap.to(state, { t: 1, duration: 0.6, ease: EASE.swatch, onUpdate: () => paint(target.map((list, s) => list.map((value, k) => before[s][k] + (value - before[s][k]) * state.t))), onComplete: done });
2621
+ return;
2622
+ }
2623
+ const stagger = 0.09;
2624
+ const total = 0.7 + stagger * (target.length - 1);
2625
+ paint(target.map((list) => list.map(() => 0)));
2626
+ glide = gsap.to(state, {
2627
+ t: total,
2628
+ duration: total,
2629
+ ease: "none",
2630
+ onUpdate: () => paint(target.map((list, s) => {
2631
+ const local = Math.min(1, Math.max(0, (state.t - s * stagger) / 0.7));
2632
+ const eased2 = gsap.parseEase(EASE.swatch)(local);
2633
+ return list.map((value) => value * eased2);
2634
+ })),
2635
+ onComplete: done
2636
+ });
2637
+ };
2638
+ const select = (axis, announce = false) => {
2639
+ if (scope.disposed) return;
2640
+ const n = model.axes.length;
2641
+ const next = axis === null || !hasData() ? null : (Math.round(axis) % n + n) % n;
2642
+ if (next === selected) return;
2643
+ selected = next;
2644
+ paintSelection(announce);
2645
+ options.onSelect?.(selected);
2646
+ root.dispatchEvent(new CustomEvent("mk:select", { bubbles: true, detail: { index: selected, label: selected === null ? null : model.axes[selected], values: selected === null ? [] : model.series.map((series) => series.values[selected]) } }));
2647
+ };
2648
+ const axisAt = (event) => {
2649
+ const box = canvas.getBoundingClientRect();
2650
+ const scale = box.width ? geometry.size / box.width : 1;
2651
+ const x = (event.clientX - box.left) * scale - geometry.cx;
2652
+ const y = (event.clientY - box.top) * scale - geometry.cy;
2653
+ if (Math.hypot(x, y) < geometry.r * 0.12) return selected;
2654
+ const a = (Math.atan2(x, -y) + Math.PI * 2) % (Math.PI * 2);
2655
+ return Math.round(a / (Math.PI * 2 / model.axes.length)) % model.axes.length;
2656
+ };
2657
+ scope.on(canvas, "pointermove", (event) => select(axisAt(event)));
2658
+ scope.on(canvas, "pointerdown", (event) => select(axisAt(event)));
2659
+ scope.on(canvas, "pointerleave", (event) => {
2660
+ if (event.pointerType === "mouse") select(null);
2661
+ });
2662
+ scope.on(canvas, "focus", () => {
2663
+ if (selected === null && hasData()) select(0, true);
2664
+ });
2665
+ scope.on(canvas, "blur", () => select(null));
2666
+ scope.on(canvas, "keydown", (event) => {
2667
+ const key = event.key;
2668
+ const moves = { ArrowRight: (selected ?? -1) + 1, ArrowDown: (selected ?? -1) + 1, ArrowLeft: (selected ?? 1) - 1, ArrowUp: (selected ?? 1) - 1, Home: 0, End: model.axes.length - 1, Escape: null };
2669
+ if (!(key in moves) || !hasData()) return;
2670
+ event.preventDefault();
2671
+ select(moves[key], true);
2672
+ });
2673
+ onWidth(root, scope, () => {
2674
+ if (!hasData()) return;
2675
+ measure();
2676
+ build();
2677
+ paint(shown);
2678
+ paintSelection(false);
2679
+ });
2680
+ draw(true);
2681
+ return {
2682
+ update(next) {
2683
+ if (scope.disposed) return;
2684
+ options = { ...options, ...next };
2685
+ model = modelOf();
2686
+ draw(true);
2687
+ },
2688
+ select: (axis) => select(axis),
2689
+ get selected() {
2690
+ return selected;
2691
+ },
2692
+ destroy: () => scope.dispose()
2693
+ };
2694
+ }
2695
+
2696
+ // src/components/radial-chart/engine.ts
2697
+ function strokeArc(cx, cy, r, a0, a1) {
2698
+ const end = a0 + Math.min(a1 - a0, Math.PI * 2 - 1e-3);
2699
+ const [x0, y0] = polar(cx, cy, r, a0);
2700
+ const [x1, y1] = polar(cx, cy, r, end);
2701
+ return `M${round(x0)},${round(y0)}A${round(r)},${round(r)} 0 ${end - a0 > Math.PI ? 1 : 0} 1 ${round(x1)},${round(y1)}`;
2702
+ }
2703
+ function createRadialChart(root, initial = {}) {
2704
+ if (!root) return inert({ update() {
2705
+ }, select() {
2706
+ }, selected: null });
2707
+ registerMotion();
2708
+ const scope = createScope();
2709
+ const frame = chartFrame(root, scope, "radial");
2710
+ const { plot, canvas, keep } = frame;
2711
+ let options = { ...initial };
2712
+ let selected = null;
2713
+ const center = document.createElement("div");
2714
+ center.dataset.mkRadialCenter = "";
2715
+ center.setAttribute("aria-hidden", "true");
2716
+ const centerValue = document.createElement("strong");
2717
+ const centerLabel = document.createElement("span");
2718
+ center.append(centerValue, centerLabel);
2719
+ plot.append(center);
2720
+ scope.add(() => center.remove());
2721
+ const format = (value) => options.formatValue ? options.formatValue(value) : formatNumber(value);
2722
+ const modelOf = () => {
2723
+ const data = (options.data ?? []).filter((datum) => finite2(datum.value));
2724
+ const top = Math.max(0, ...data.map((datum) => datum.value));
2725
+ return data.map((datum, i) => ({
2726
+ label: String(datum.label),
2727
+ value: Math.max(0, datum.value),
2728
+ max: finite2(datum.max) && datum.max > 0 ? datum.max : finite2(options.max) && options.max > 0 ? options.max : top || 1,
2729
+ color: datum.color ?? slotColor(i, Math.max(2, data.length))
2730
+ }));
2731
+ };
2732
+ let model = modelOf();
2733
+ const total = () => model.reduce((sum, ring) => sum + ring.value, 0);
2734
+ const percent = (ring) => new Intl.NumberFormat(void 0, { style: "percent", maximumFractionDigits: 0 }).format(ring.value / ring.max);
2735
+ const sweep = () => Math.min(360, Math.max(90, finite2(options.sweep) ? options.sweep : 360)) * Math.PI / 180;
2736
+ const startAngle = () => -sweep() / 2 + (sweep() >= Math.PI * 2 - 1e-6 ? Math.PI : 0);
2737
+ let geometry = { size: 240, cx: 120, cy: 120, radii: [], thickness: 12 };
2738
+ let arcs = [];
2739
+ let tracks = [];
2740
+ let shown = [];
2741
+ let glide = null;
2742
+ scope.add(() => glide?.kill());
2743
+ const measure = () => {
2744
+ const width = Math.round(plot.clientWidth || root.clientWidth || 0);
2745
+ const wanted = finite2(options.size) ? options.size : 240;
2746
+ const size = Math.max(120, width ? Math.min(wanted, width) : wanted);
2747
+ const n = Math.max(1, model.length);
2748
+ const outer = size / 2 - 4;
2749
+ const fit = outer * 0.6 / (n + (n - 1) * 0.35);
2750
+ const thickness = finite2(options.thickness) ? options.thickness : Math.max(4, Math.min(16, fit));
2751
+ const spacing = thickness * 1.35;
2752
+ geometry = { size, cx: size / 2, cy: size / 2, thickness, radii: model.map((_, i) => outer - thickness / 2 - i * spacing) };
2753
+ canvas.setAttribute("viewBox", `0 0 ${size} ${size}`);
2754
+ canvas.setAttribute("width", String(size));
2755
+ canvas.setAttribute("height", String(size));
2756
+ plot.style.setProperty("--mk-radial-size", `${size}px`);
2757
+ plot.style.setProperty("--mk-radial-thickness", `${thickness}px`);
2758
+ };
2759
+ scope.add(() => {
2760
+ plot.style.removeProperty("--mk-radial-size");
2761
+ plot.style.removeProperty("--mk-radial-thickness");
2762
+ });
2763
+ const build = () => {
2764
+ canvas.replaceChildren();
2765
+ const { cx, cy, radii } = geometry;
2766
+ const a0 = startAngle();
2767
+ const back = svg2("g", { "data-mk-part": "tracks" });
2768
+ const front = svg2("g", { "data-mk-part": "series" });
2769
+ tracks = model.map((_, i) => {
2770
+ const track = svg2("path", { d: strokeArc(cx, cy, radii[i], a0, a0 + sweep()), "data-mk-index": i });
2771
+ back.append(track);
2772
+ return track;
2773
+ });
2774
+ arcs = model.map((ring, i) => {
2775
+ const arc = svg2("path", { "data-mk-index": i, "data-mk-part": "ring" });
2776
+ arc.style.stroke = ring.color;
2777
+ front.append(arc);
2778
+ return arc;
2779
+ });
2780
+ canvas.append(back, front);
2781
+ };
2782
+ const paint = (values) => {
2783
+ shown = values;
2784
+ const { cx, cy, radii } = geometry;
2785
+ const a0 = startAngle();
2786
+ arcs.forEach((arc, i) => {
2787
+ const share = Math.min(1, Math.max(0, (values[i] ?? 0) / model[i].max));
2788
+ arc.setAttribute("d", share > 1e-3 ? strokeArc(cx, cy, radii[i], a0, a0 + sweep() * share) : "");
2789
+ });
2790
+ };
2791
+ const paintCenter = (animate) => {
2792
+ center.hidden = !model.length;
2793
+ const ring = selected === null ? null : model[selected];
2794
+ const text = ring ? format(ring.value) : format(total());
2795
+ const caption = ring ? `${ring.label} \xB7 ${percent(ring)}` : options.totalLabel ?? "Total";
2796
+ const changed = centerLabel.textContent !== caption;
2797
+ if (centerValue.textContent !== text) {
2798
+ if (animate && !reduced() && centerValue.textContent) keep(rollDigits(centerValue, text, 1, 0.35));
2799
+ else centerValue.textContent = text;
2800
+ }
2801
+ centerLabel.textContent = caption;
2802
+ if (changed && animate && !reduced()) keep(blurIn(centerLabel, { from: "soft", duration: 0.3 }));
2803
+ };
2804
+ let legendItems = [];
2805
+ const paintSelection = (announce) => {
2806
+ for (const list of [arcs, tracks]) list.forEach((each, i) => {
2807
+ each.toggleAttribute("data-mk-on", i === selected);
2808
+ each.toggleAttribute("data-mk-dim", selected !== null && i !== selected);
2809
+ });
2810
+ legendItems.forEach((item, i) => item.toggleAttribute("data-mk-dim", selected !== null && i !== selected));
2811
+ paintCenter(true);
2812
+ const ring = selected === null ? null : model[selected];
2813
+ if (announce && ring) frame.live.textContent = `${ring.label}: ${format(ring.value)} de ${format(ring.max)}, ${percent(ring)}`;
2814
+ };
2815
+ const draw = (animate) => {
2816
+ glide?.kill();
2817
+ const name = options.label ?? "Gr\xE1fica radial";
2818
+ canvas.setAttribute("aria-label", model.length ? `${name}. ${model.length} anillos, total ${format(total())}. Usa las flechas para recorrerlos.` : `${name}: ${options.emptyLabel ?? "sin datos"}`);
2819
+ frame.fillTable(name, ["Anillo", "Valor", "Meta", "Avance"], model.map((ring) => [ring.label, format(ring.value), format(ring.max), percent(ring)]));
2820
+ legendItems = frame.fillLegend(model.map((datum) => ({ name: datum.label, color: datum.color })), options.legend ?? true);
2821
+ legendItems.forEach((item, i) => {
2822
+ item.addEventListener("pointerenter", () => select(i));
2823
+ item.addEventListener("pointerleave", () => select(null));
2824
+ });
2825
+ frame.empty.hidden = model.length > 0;
2826
+ frame.empty.textContent = options.emptyLabel ?? "Sin datos para mostrar";
2827
+ plot.hidden = !model.length;
2828
+ if (!model.length) {
2829
+ canvas.replaceChildren();
2830
+ arcs = [];
2831
+ shown = [];
2832
+ selected = null;
2833
+ return;
2834
+ }
2835
+ if (selected !== null && selected >= model.length) selected = null;
2836
+ const before = shown;
2837
+ const comparable = before.length === model.length && arcs.length === model.length;
2838
+ measure();
2839
+ build();
2840
+ const target = model.map((ring) => ring.value);
2841
+ const done = () => {
2842
+ paint(target);
2843
+ paintSelection(false);
2844
+ };
2845
+ if (!animate || reduced()) return done();
2846
+ const state = { t: 0 };
2847
+ if (comparable) {
2848
+ glide = gsap.to(state, { t: 1, duration: 0.6, ease: EASE.swatch, onUpdate: () => paint(target.map((value, i) => before[i] + (value - before[i]) * state.t)), onComplete: done });
2849
+ paintCenter(true);
2850
+ return;
2851
+ }
2852
+ const stagger = 0.08;
2853
+ const length = 0.8 + stagger * (target.length - 1);
2854
+ const ease = gsap.parseEase(EASE.swatch);
2855
+ paint(target.map(() => 0));
2856
+ centerValue.textContent = format(0);
2857
+ glide = gsap.to(state, {
2858
+ t: length,
2859
+ duration: length,
2860
+ ease: "none",
2861
+ onUpdate: () => paint(target.map((value, i) => value * ease(Math.min(1, Math.max(0, (state.t - i * stagger) / 0.8))))),
2862
+ onComplete: done
2863
+ });
2864
+ paintCenter(true);
2865
+ };
2866
+ const select = (index, announce = false) => {
2867
+ if (scope.disposed) return;
2868
+ const next = index === null || !model.length ? null : (Math.round(index) % model.length + model.length) % model.length;
2869
+ if (next === selected) return;
2870
+ selected = next;
2871
+ paintSelection(announce);
2872
+ options.onSelect?.(selected);
2873
+ const ring = selected === null ? null : model[selected];
2874
+ root.dispatchEvent(new CustomEvent("mk:select", { bubbles: true, detail: { index: selected, label: ring?.label ?? null, value: ring?.value ?? null } }));
2875
+ };
2876
+ const ringAt = (event) => {
2877
+ const box = canvas.getBoundingClientRect();
2878
+ const scale = box.width ? geometry.size / box.width : 1;
2879
+ const distance = Math.hypot((event.clientX - box.left) * scale - geometry.cx, (event.clientY - box.top) * scale - geometry.cy);
2880
+ const near = geometry.radii.findIndex((r) => Math.abs(distance - r) <= geometry.thickness * 0.7);
2881
+ return near < 0 ? null : near;
2882
+ };
2883
+ scope.on(canvas, "pointermove", (event) => select(ringAt(event)));
2884
+ scope.on(canvas, "pointerdown", (event) => select(ringAt(event)));
2885
+ scope.on(canvas, "pointerleave", (event) => {
2886
+ if (event.pointerType === "mouse") select(null);
2887
+ });
2888
+ scope.on(canvas, "focus", () => {
2889
+ if (selected === null && model.length) select(0, true);
2890
+ });
2891
+ scope.on(canvas, "blur", () => select(null));
2892
+ scope.on(canvas, "keydown", (event) => {
2893
+ const key = event.key;
2894
+ const moves = { ArrowDown: (selected ?? -1) + 1, ArrowRight: (selected ?? -1) + 1, ArrowUp: (selected ?? 1) - 1, ArrowLeft: (selected ?? 1) - 1, Home: 0, End: model.length - 1, Escape: null };
2895
+ if (!(key in moves) || !model.length) return;
2896
+ event.preventDefault();
2897
+ select(moves[key], true);
2898
+ });
2899
+ onWidth(root, scope, () => {
2900
+ if (!model.length) return;
2901
+ measure();
2902
+ build();
2903
+ paint(shown);
2904
+ paintSelection(false);
2905
+ });
2906
+ draw(true);
2907
+ return {
2908
+ update(next) {
2909
+ if (scope.disposed) return;
2910
+ options = { ...options, ...next };
2911
+ model = modelOf();
2912
+ draw(true);
2913
+ },
2914
+ select: (index) => select(index),
2915
+ get selected() {
2916
+ return selected;
2917
+ },
2918
+ destroy: () => scope.dispose()
2919
+ };
2920
+ }
2921
+
2922
+ // src/components/sankey-chart/engine.ts
2923
+ function createSankeyChart(root, initial = {}) {
2924
+ if (!root) return inert({ update() {
2925
+ }, select() {
2926
+ }, selected: null });
2927
+ registerMotion();
2928
+ const scope = createScope();
2929
+ const frame = chartFrame(root, scope, "sankey");
2930
+ const { plot, canvas } = frame;
2931
+ let options = { ...initial };
2932
+ let selected = null;
2933
+ let hoverNode = null;
2934
+ const uid = `mk-sankey-${Math.random().toString(36).slice(2, 8)}`;
2935
+ const format = (value) => options.formatValue ? options.formatValue(value) : formatNumber(value);
2936
+ const modelOf = () => {
2937
+ const nodes = (options.nodes ?? []).map((node, i, all) => ({ id: String(node.id), label: String(node.label ?? node.id), color: node.color ?? slotColor(i, Math.max(2, all.length)) }));
2938
+ const index = new Map(nodes.map((node, i) => [node.id, i]));
2939
+ const links = (options.links ?? []).map((link, i) => ({ source: index.get(String(link.source)) ?? -1, target: index.get(String(link.target)) ?? -1, value: link.value, given: i })).filter((link) => link.source >= 0 && link.target >= 0 && link.source !== link.target && finite2(link.value) && link.value > 0);
2940
+ const depth = nodes.map(() => 0);
2941
+ for (let pass = 0; pass < nodes.length; pass++) {
2942
+ let moved = false;
2943
+ for (const link of links) {
2944
+ if (depth[link.target] < depth[link.source] + 1 && depth[link.source] + 1 < nodes.length) {
2945
+ depth[link.target] = depth[link.source] + 1;
2946
+ moved = true;
2947
+ }
2948
+ }
2949
+ if (!moved) break;
2950
+ }
2951
+ const columns = Math.max(0, ...depth) + 1;
2952
+ nodes.forEach((_, i) => {
2953
+ if (links.some((link) => link.source === i) || !links.some((link) => link.target === i)) return;
2954
+ depth[i] = columns - 1;
2955
+ });
2956
+ const used = nodes.map((_, i) => links.some((link) => link.source === i || link.target === i));
2957
+ const value = nodes.map((_, i) => Math.max(links.filter((link) => link.target === i).reduce((s, l) => s + l.value, 0), links.filter((link) => link.source === i).reduce((s, l) => s + l.value, 0)));
2958
+ return { nodes, links, depth, columns, used, value };
2959
+ };
2960
+ let model = modelOf();
2961
+ const hasData = () => model.links.length > 0;
2962
+ let width = 600;
2963
+ let height = 320;
2964
+ const layoutOf = () => {
2965
+ width = Math.max(240, Math.round(plot.clientWidth || root.clientWidth || 600));
2966
+ height = Math.max(160, finite2(options.height) ? options.height : 320);
2967
+ const nodeWidth2 = Math.max(4, finite2(options.nodeWidth) ? options.nodeWidth : 12);
2968
+ const pad = Math.max(2, finite2(options.nodePadding) ? options.nodePadding : 14);
2969
+ const top = 6;
2970
+ const usable = height - top * 2;
2971
+ const columns = Array.from({ length: model.columns }, (_, c) => model.nodes.map((_2, i) => i).filter((i) => model.used[i] && model.depth[i] === c));
2972
+ const ky = Math.min(...columns.filter((list) => list.length).map((list) => (usable - pad * (list.length - 1)) / list.reduce((sum, i) => sum + model.value[i], 0)));
2973
+ const step = model.columns > 1 ? (width - nodeWidth2) / (model.columns - 1) : 0;
2974
+ const nodes = model.nodes.map(() => ({ x: 0, y0: 0, y1: 0 }));
2975
+ for (const list of columns) {
2976
+ const total = list.reduce((sum, i) => sum + model.value[i] * ky, 0) + pad * Math.max(0, list.length - 1);
2977
+ let y = top + (usable - total) / 2;
2978
+ for (const i of list) {
2979
+ const h = Math.max(1, model.value[i] * ky);
2980
+ nodes[i] = { x: model.depth[i] * step, y0: y, y1: y + h };
2981
+ y += h + pad;
2982
+ }
2983
+ }
2984
+ const out = /* @__PURE__ */ new Map();
2985
+ const into = /* @__PURE__ */ new Map();
2986
+ const centre = (i) => (nodes[i].y0 + nodes[i].y1) / 2;
2987
+ const links = model.links.map(() => ({ sy: 0, ty: 0, width: 0 }));
2988
+ const order = model.links.map((_, k) => k);
2989
+ for (const k of [...order].sort((a, b) => centre(model.links[a].target) - centre(model.links[b].target))) {
2990
+ const link = model.links[k];
2991
+ const w = link.value * ky;
2992
+ const at = out.get(link.source) ?? nodes[link.source].y0;
2993
+ links[k].sy = at + w / 2;
2994
+ links[k].width = w;
2995
+ out.set(link.source, at + w);
2996
+ }
2997
+ for (const k of [...order].sort((a, b) => centre(model.links[a].source) - centre(model.links[b].source))) {
2998
+ const link = model.links[k];
2999
+ const at = into.get(link.target) ?? nodes[link.target].y0;
3000
+ links[k].ty = at + links[k].width / 2;
3001
+ into.set(link.target, at + links[k].width);
3002
+ }
3003
+ return { nodes, links };
3004
+ };
3005
+ let shown = null;
3006
+ let rects = [];
3007
+ let bands = [];
3008
+ let names = [];
3009
+ let glide = null;
3010
+ scope.add(() => glide?.kill());
3011
+ const nodeWidth = () => Math.max(4, finite2(options.nodeWidth) ? options.nodeWidth : 12);
3012
+ const build = () => {
3013
+ canvas.replaceChildren();
3014
+ canvas.setAttribute("viewBox", `0 0 ${width} ${height}`);
3015
+ canvas.setAttribute("width", String(width));
3016
+ canvas.setAttribute("height", String(height));
3017
+ const defs = svg2("defs");
3018
+ const flows = svg2("g", { "data-mk-part": "links" });
3019
+ bands = model.links.map((link, k) => {
3020
+ const gradient = svg2("linearGradient", { id: `${uid}-${k}`, gradientUnits: "userSpaceOnUse" });
3021
+ const from = svg2("stop", { offset: "0" });
3022
+ from.style.stopColor = model.nodes[link.source].color;
3023
+ const to = svg2("stop", { offset: "1" });
3024
+ to.style.stopColor = model.nodes[link.target].color;
3025
+ gradient.append(from, to);
3026
+ defs.append(gradient);
3027
+ const band = svg2("path", { "data-mk-index": k });
3028
+ band.style.fill = `url(#${uid}-${k})`;
3029
+ flows.append(band);
3030
+ return band;
3031
+ });
3032
+ const nodesLayer = svg2("g", { "data-mk-part": "nodes" });
3033
+ rects = model.nodes.map((node, i) => {
3034
+ const rect = svg2("rect", { width: nodeWidth(), rx: 3, "data-mk-node": i });
3035
+ rect.style.fill = node.color;
3036
+ if (!model.used[i]) rect.style.display = "none";
3037
+ nodesLayer.append(rect);
3038
+ return rect;
3039
+ });
3040
+ const labels = svg2("g", { "data-mk-part": "labels" });
3041
+ names = model.nodes.map((node, i) => {
3042
+ const text = svg2("text", { "dominant-baseline": "middle" });
3043
+ text.textContent = node.label;
3044
+ const amount = document.createElementNS(SVG_NS, "tspan");
3045
+ amount.setAttribute("data-mk-part", "amount");
3046
+ amount.textContent = ` ${format(model.value[i])}`;
3047
+ text.append(amount);
3048
+ if (!model.used[i]) text.style.display = "none";
3049
+ labels.append(text);
3050
+ return text;
3051
+ });
3052
+ canvas.append(defs, flows, nodesLayer, labels);
3053
+ };
3054
+ const paint = (layout2) => {
3055
+ shown = layout2;
3056
+ const w = nodeWidth();
3057
+ layout2.nodes.forEach((node, i) => {
3058
+ const rect = rects[i];
3059
+ rect.setAttribute("x", String(round(node.x)));
3060
+ rect.setAttribute("y", String(round(node.y0)));
3061
+ rect.setAttribute("height", String(round(Math.max(1, node.y1 - node.y0))));
3062
+ const last = model.depth[i] === model.columns - 1 && model.columns > 1;
3063
+ const name = names[i];
3064
+ const first = model.depth[i] === 0;
3065
+ const x = round(last ? node.x - 8 : first ? node.x + w + 8 : node.x + w / 2);
3066
+ const available = model.columns > 1 ? (width - w) / (model.columns - 1) - 20 : width - w - 16;
3067
+ const characters = Math.max(3, Math.floor(available / 7));
3068
+ const label = model.nodes[i].label;
3069
+ if (name.firstChild) name.firstChild.textContent = label.length > characters ? `${label.slice(0, characters - 1)}\u2026` : label;
3070
+ name.setAttribute("x", String(x));
3071
+ name.setAttribute("y", String(round((node.y0 + node.y1) / 2 - 7)));
3072
+ name.setAttribute("text-anchor", last ? "end" : first ? "start" : "middle");
3073
+ const amount = name.querySelector("tspan");
3074
+ amount?.setAttribute("x", String(x));
3075
+ amount?.setAttribute("dy", "14");
3076
+ });
3077
+ layout2.links.forEach((link, k) => {
3078
+ const { source, target } = model.links[k];
3079
+ const x0 = layout2.nodes[source].x + w;
3080
+ const x1 = layout2.nodes[target].x;
3081
+ const xm = (x0 + x1) / 2;
3082
+ const h = link.width / 2;
3083
+ const [s0, s1, t0, t1] = [link.sy - h, link.sy + h, link.ty - h, link.ty + h].map(round);
3084
+ bands[k].setAttribute("d", `M${round(x0)},${s0}C${round(xm)},${s0} ${round(xm)},${t0} ${round(x1)},${t0}L${round(x1)},${t1}C${round(xm)},${t1} ${round(xm)},${s1} ${round(x0)},${s1}Z`);
3085
+ const gradient = canvas.querySelector(`#${uid}-${k}`);
3086
+ gradient?.setAttribute("x1", String(round(x0)));
3087
+ gradient?.setAttribute("x2", String(round(x1)));
3088
+ });
3089
+ };
3090
+ const share = (part2, whole) => new Intl.NumberFormat(void 0, { style: "percent", maximumFractionDigits: 1 }).format(part2 / (whole || 1));
3091
+ const paintSelection = (announce) => {
3092
+ const lit = (k) => selected !== null ? k === selected : hoverNode !== null ? model.links[k].source === hoverNode || model.links[k].target === hoverNode : false;
3093
+ const any = selected !== null || hoverNode !== null;
3094
+ bands.forEach((band, k) => {
3095
+ band.toggleAttribute("data-mk-on", lit(k));
3096
+ band.toggleAttribute("data-mk-dim", any && !lit(k));
3097
+ });
3098
+ rects.forEach((rect, i) => rect.toggleAttribute("data-mk-dim", any && !model.links.some((link, k) => lit(k) && (link.source === i || link.target === i))));
3099
+ if (!shown || selected === null && hoverNode === null) {
3100
+ frame.tip(null);
3101
+ return;
3102
+ }
3103
+ if (selected !== null) {
3104
+ const link = model.links[selected];
3105
+ const geometry = shown.links[selected];
3106
+ const x = (shown.nodes[link.source].x + shown.nodes[link.target].x + nodeWidth()) / 2;
3107
+ const y = (geometry.sy + geometry.ty) / 2 - geometry.width / 2;
3108
+ const from = model.nodes[link.source];
3109
+ const to = model.nodes[link.target];
3110
+ const rows = [{ name: `${share(link.value, model.value[link.source])} de ${from.label}`, color: from.color, value: format(link.value) }];
3111
+ frame.tip({ x: round(x), y: round(y), title: `${from.label} \u2192 ${to.label}`, rows });
3112
+ if (announce) frame.live.textContent = `${from.label} a ${to.label}: ${format(link.value)}`;
3113
+ } else {
3114
+ const i = hoverNode;
3115
+ const node = shown.nodes[i];
3116
+ frame.tip({ x: round(node.x + nodeWidth() / 2), y: round(node.y0), title: model.nodes[i].label, rows: [{ name: "Total", color: model.nodes[i].color, value: format(model.value[i]) }] });
3117
+ }
3118
+ };
3119
+ const draw = (animate) => {
3120
+ glide?.kill();
3121
+ const name = options.label ?? "Diagrama de flujo";
3122
+ canvas.setAttribute("aria-label", hasData() ? `${name}. ${model.links.length} flujos entre ${model.used.filter(Boolean).length} etapas. Usa las flechas para recorrer los flujos.` : `${name}: ${options.emptyLabel ?? "sin datos"}`);
3123
+ frame.fillTable(name, ["Flujo", "Valor"], model.links.map((link) => [`${model.nodes[link.source].label} \u2192 ${model.nodes[link.target].label}`, format(link.value)]));
3124
+ frame.fillLegend([], false);
3125
+ const ok = hasData();
3126
+ frame.empty.hidden = ok;
3127
+ frame.empty.textContent = options.emptyLabel ?? "Sin datos para mostrar";
3128
+ plot.hidden = !ok;
3129
+ if (!ok) {
3130
+ canvas.replaceChildren();
3131
+ shown = null;
3132
+ selected = null;
3133
+ return;
3134
+ }
3135
+ if (selected !== null && selected >= model.links.length) selected = null;
3136
+ const before = shown;
3137
+ const target = layoutOf();
3138
+ const comparable = before && before.nodes.length === target.nodes.length && before.links.length === target.links.length;
3139
+ build();
3140
+ const done = () => {
3141
+ paint(target);
3142
+ paintSelection(false);
3143
+ };
3144
+ if (!animate || reduced()) return done();
3145
+ if (comparable) {
3146
+ const state = { t: 0 };
3147
+ const mix = (a, b) => a + (b - a) * state.t;
3148
+ glide = gsap.to(state, {
3149
+ t: 1,
3150
+ duration: 0.6,
3151
+ ease: EASE.swatch,
3152
+ onUpdate: () => paint({
3153
+ nodes: target.nodes.map((node, i) => ({ x: mix(before.nodes[i].x, node.x), y0: mix(before.nodes[i].y0, node.y0), y1: mix(before.nodes[i].y1, node.y1) })),
3154
+ links: target.links.map((link, k) => ({ sy: mix(before.links[k].sy, link.sy), ty: mix(before.links[k].ty, link.ty), width: mix(before.links[k].width, link.width) }))
3155
+ }),
3156
+ onComplete: done
3157
+ });
3158
+ return;
3159
+ }
3160
+ done();
3161
+ const timeline = gsap.timeline();
3162
+ rects.forEach((rect2, i) => {
3163
+ timeline.fromTo(rect2, { scaleY: 0, transformOrigin: "50% 50%" }, { scaleY: 1, duration: 0.5, ease: EASE.swatch, clearProps: "transform" }, (model.depth[i] ?? 0) * 0.12);
3164
+ });
3165
+ timeline.fromTo(names, { opacity: 0 }, { opacity: 1, duration: 0.4, stagger: 0.02, clearProps: "opacity" }, 0.2);
3166
+ const clip = svg2("clipPath", { id: `${uid}-wipe` });
3167
+ const rect = svg2("rect", { x: 0, y: 0, width: 0, height });
3168
+ clip.append(rect);
3169
+ canvas.prepend(clip);
3170
+ const flows = canvas.querySelector('[data-mk-part="links"]');
3171
+ flows.setAttribute("clip-path", `url(#${uid}-wipe)`);
3172
+ timeline.to(rect, { attr: { width }, duration: 0.9, ease: EASE.wipe, onComplete: () => {
3173
+ flows.removeAttribute("clip-path");
3174
+ clip.remove();
3175
+ } }, 0.1);
3176
+ glide = timeline;
3177
+ };
3178
+ const select = (index, announce = false) => {
3179
+ if (scope.disposed) return;
3180
+ const n = model.links.length;
3181
+ const next = index === null || !n ? null : (Math.round(index) % n + n) % n;
3182
+ if (next === selected) return;
3183
+ selected = next;
3184
+ paintSelection(announce);
3185
+ options.onSelect?.(selected === null ? null : model.links[selected].given);
3186
+ const link = selected === null ? null : model.links[selected];
3187
+ root.dispatchEvent(new CustomEvent("mk:select", { bubbles: true, detail: { index: link?.given ?? null, source: link ? model.nodes[link.source].id : null, target: link ? model.nodes[link.target].id : null, value: link?.value ?? null } }));
3188
+ };
3189
+ scope.on(canvas, "pointermove", (event) => {
3190
+ const target = event.target;
3191
+ const band = target.closest("[data-mk-index]");
3192
+ const node = target.closest("[data-mk-node]");
3193
+ if (node) {
3194
+ const i = Number(node.getAttribute("data-mk-node"));
3195
+ if (selected !== null) select(null);
3196
+ if (hoverNode !== i) {
3197
+ hoverNode = i;
3198
+ paintSelection(false);
3199
+ }
3200
+ return;
3201
+ }
3202
+ if (hoverNode !== null) {
3203
+ hoverNode = null;
3204
+ paintSelection(false);
3205
+ }
3206
+ select(band ? Number(band.getAttribute("data-mk-index")) : null);
3207
+ });
3208
+ scope.on(canvas, "pointerleave", (event) => {
3209
+ if (event.pointerType !== "mouse") return;
3210
+ hoverNode = null;
3211
+ select(null);
3212
+ paintSelection(false);
3213
+ });
3214
+ scope.on(canvas, "focus", () => {
3215
+ if (selected === null && hasData()) select(0, true);
3216
+ });
3217
+ scope.on(canvas, "blur", () => select(null));
3218
+ scope.on(canvas, "keydown", (event) => {
3219
+ const key = event.key;
3220
+ const moves = { ArrowDown: (selected ?? -1) + 1, ArrowRight: (selected ?? -1) + 1, ArrowUp: (selected ?? 1) - 1, ArrowLeft: (selected ?? 1) - 1, Home: 0, End: model.links.length - 1, Escape: null };
3221
+ if (!(key in moves) || !hasData()) return;
3222
+ event.preventDefault();
3223
+ select(moves[key], true);
3224
+ });
3225
+ onWidth(root, scope, () => {
3226
+ if (!hasData()) return;
3227
+ const layout2 = layoutOf();
3228
+ build();
3229
+ paint(layout2);
3230
+ paintSelection(false);
3231
+ });
3232
+ draw(true);
3233
+ return {
3234
+ update(next) {
3235
+ if (scope.disposed) return;
3236
+ options = { ...options, ...next };
3237
+ model = modelOf();
3238
+ draw(true);
3239
+ },
3240
+ select: (index) => {
3241
+ const at = index === null ? null : model.links.findIndex((link) => link.given === index);
3242
+ select(at === null || at < 0 ? null : at);
3243
+ },
3244
+ get selected() {
3245
+ return selected === null ? null : model.links[selected].given;
3246
+ },
3247
+ destroy: () => scope.dispose()
3248
+ };
3249
+ }
3250
+
3251
+ // src/components/heatmap-chart/engine.ts
3252
+ var LEFT = 28;
3253
+ var TOP = 18;
3254
+ function createHeatmapChart(root, initial = {}) {
3255
+ if (!root) return inert({ update() {
3256
+ }, select() {
3257
+ }, selected: null });
3258
+ registerMotion();
3259
+ const scope = createScope();
3260
+ const frame = chartFrame(root, scope, "heatmap");
3261
+ const { plot, canvas, keep } = frame;
3262
+ let options = { ...initial };
3263
+ let selected = null;
3264
+ const scroller = document.createElement("div");
3265
+ scroller.dataset.mkHeatmapScroll = "";
3266
+ plot.prepend(scroller);
3267
+ scroller.append(canvas);
3268
+ scope.add(() => scroller.remove());
3269
+ const scale = document.createElement("div");
3270
+ scale.dataset.mkHeatmapScale = "";
3271
+ scale.setAttribute("aria-hidden", "true");
3272
+ root.insertBefore(scale, frame.legend);
3273
+ scope.add(() => scale.remove());
3274
+ const locale = () => options.locale ?? (document.documentElement.lang || "es");
3275
+ const format = (value) => options.formatValue ? options.formatValue(value) : formatNumber(value);
3276
+ const levels = () => Math.max(1, Math.min(8, Math.round(options.levels ?? 4)));
3277
+ const modelOf = () => {
3278
+ const values = /* @__PURE__ */ new Map();
3279
+ const add = (key, value) => finite2(value) && values.set(key, (values.get(key) ?? 0) + value);
3280
+ if (Array.isArray(options.data)) for (const datum of options.data) add(dayKey(toDate(datum.date)), datum.value);
3281
+ else if (options.data) for (const [key, value] of Object.entries(options.data)) add(dayKey(toDate(key)), value);
3282
+ const weeks = Math.max(1, Math.min(106, Math.round(options.weeks ?? 53)));
3283
+ const firstDay = Number.isInteger(options.firstDay) && options.firstDay >= 0 && options.firstDay <= 6 ? options.firstDay : 1;
3284
+ const end = toDate(options.end ?? /* @__PURE__ */ new Date());
3285
+ const start = startOfWeek(addDays(end, -(weeks - 1) * 7), firstDay);
3286
+ const days = [];
3287
+ for (let date = start, i = 0; date <= end; date = addDays(date, 1), i++) {
3288
+ const key = dayKey(date);
3289
+ days.push({ key, date, value: values.get(key) ?? 0, week: Math.floor(i / 7), day: i % 7 });
3290
+ }
3291
+ const max = Math.max(0, ...days.map((each) => each.value));
3292
+ return { days, weeks: (days[days.length - 1]?.week ?? 0) + 1, firstDay, max, total: days.reduce((sum, each) => sum + each.value, 0) };
3293
+ };
3294
+ let model = modelOf();
3295
+ const levelOf = (value) => value <= 0 || !model.max ? 0 : Math.max(1, Math.ceil(value / model.max * levels()));
3296
+ const fillOf = (level) => level === 0 ? "var(--mk-heatmap-empty)" : `color-mix(in srgb, ${options.color ?? "var(--mk-heatmap-color)"} ${Math.round(22 + 78 * level / levels())}%, var(--mk-heatmap-empty))`;
3297
+ let cells = [];
3298
+ let builtFrom = "";
3299
+ let geometry = { cell: 12, gap: 3, width: 0, height: 0 };
3300
+ const longDate = () => safeFormat(locale(), { weekday: "short", day: "numeric", month: "long", year: "numeric" });
3301
+ const build = (animate) => {
3302
+ canvas.replaceChildren();
3303
+ const available = Math.max(0, (plot.clientWidth || root.clientWidth || 0) - LEFT);
3304
+ const gap = 3;
3305
+ const fit = available ? Math.floor(available / model.weeks - gap) : 12;
3306
+ const cell = Math.max(10, Math.min(14, fit));
3307
+ const width = LEFT + model.weeks * (cell + gap);
3308
+ const height = TOP + 7 * (cell + gap);
3309
+ geometry = { cell, gap, width, height };
3310
+ canvas.setAttribute("viewBox", `0 0 ${width} ${height}`);
3311
+ canvas.setAttribute("width", String(width));
3312
+ canvas.setAttribute("height", String(height));
3313
+ plot.style.setProperty("--mk-heatmap-width", `${width}px`);
3314
+ const months = svg2("g", { "data-mk-part": "months" });
3315
+ const monthName = safeFormat(locale(), { month: "short" });
3316
+ let last = -1;
3317
+ for (const each of model.days) {
3318
+ if (each.day !== 0) continue;
3319
+ const month = addDays(each.date, 6).getMonth();
3320
+ if (month === last) continue;
3321
+ last = month;
3322
+ if (each.week > model.weeks - 2 && model.weeks > 4) continue;
3323
+ const text = svg2("text", { x: LEFT + each.week * (cell + gap), y: 10 });
3324
+ text.textContent = capitalize(monthName.format(addDays(each.date, 6)).replace(".", ""));
3325
+ months.append(text);
3326
+ }
3327
+ const names = weekdayNames(locale(), model.firstDay, "short");
3328
+ const weekdays = svg2("g", { "data-mk-part": "weekdays" });
3329
+ [1, 3, 5].forEach((row) => {
3330
+ const text = svg2("text", { x: 0, y: round(TOP + row * (cell + gap) + cell / 2), "dominant-baseline": "middle" });
3331
+ text.textContent = capitalize(names[row].replace(".", "")).slice(0, 3);
3332
+ weekdays.append(text);
3333
+ });
3334
+ const grid = svg2("g", { "data-mk-part": "cells" });
3335
+ cells = model.days.map((each, i) => {
3336
+ const rect = svg2("rect", { x: LEFT + each.week * (cell + gap), y: TOP + each.day * (cell + gap), width: cell, height: cell, rx: 3, "data-mk-index": i, "data-mk-level": levelOf(each.value) });
3337
+ rect.style.fill = fillOf(levelOf(each.value));
3338
+ grid.append(rect);
3339
+ return rect;
3340
+ });
3341
+ canvas.append(months, weekdays, grid);
3342
+ builtFrom = model.days[0]?.key ?? "";
3343
+ scroller.scrollLeft = scroller.scrollWidth;
3344
+ if (animate && !reduced()) keep(gsap.fromTo(cells, { opacity: 0, scale: 0.3 }, { opacity: 1, scale: 1, duration: 0.35, ease: EASE.pop, clearProps: "opacity,transform", stagger: (i) => Math.min(0.7, (model.days[i].week + model.days[i].day) * 8e-3) }));
3345
+ };
3346
+ scope.add(() => plot.style.removeProperty("--mk-heatmap-width"));
3347
+ const paintScale = () => {
3348
+ scale.replaceChildren();
3349
+ scale.hidden = options.legend === false || !model.days.length;
3350
+ if (scale.hidden) return;
3351
+ const less = document.createElement("span");
3352
+ less.textContent = "Menos";
3353
+ scale.append(less);
3354
+ for (let level = 0; level <= levels(); level++) {
3355
+ const swatch = document.createElement("i");
3356
+ swatch.style.background = fillOf(level);
3357
+ swatch.addEventListener("pointerenter", () => {
3358
+ for (const cell of cells) cell.toggleAttribute("data-mk-dim", cell.getAttribute("data-mk-level") !== String(level));
3359
+ });
3360
+ swatch.addEventListener("pointerleave", () => {
3361
+ for (const cell of cells) cell.removeAttribute("data-mk-dim");
3362
+ });
3363
+ scale.append(swatch);
3364
+ }
3365
+ const more = document.createElement("span");
3366
+ more.textContent = "M\xE1s";
3367
+ scale.append(more);
3368
+ };
3369
+ const unit = () => options.unit ?? "actividades";
3370
+ const paintSelection = (announce) => {
3371
+ cells.forEach((cell2, i) => cell2.toggleAttribute("data-mk-on", i === selected));
3372
+ const each = selected === null ? null : model.days[selected];
3373
+ if (!each) {
3374
+ frame.tip(null);
3375
+ return;
3376
+ }
3377
+ const { cell, gap } = geometry;
3378
+ const x = LEFT + each.week * (cell + gap) + cell / 2 - scroller.scrollLeft;
3379
+ const y = TOP + each.day * (cell + gap);
3380
+ const title = capitalize(longDate().format(each.date));
3381
+ frame.tip({ x, y, title, rows: [{ name: unit(), color: fillOf(Math.max(1, levelOf(each.value))), value: format(each.value) }] });
3382
+ if (announce) frame.live.textContent = `${title}: ${format(each.value)} ${unit()}`;
3383
+ };
3384
+ const draw = (animate) => {
3385
+ const name = options.label ?? "Actividad diaria";
3386
+ canvas.setAttribute("aria-label", model.days.length ? `${name}. ${model.weeks} semanas, ${format(model.total)} ${unit()} en total. Usa las flechas para recorrer los d\xEDas.` : `${name}: ${options.emptyLabel ?? "sin datos"}`);
3387
+ const active = model.days.filter((each) => each.value > 0);
3388
+ frame.fillTable(`${name}: ${format(model.total)} ${unit()}`, ["D\xEDa", capitalize(unit())], active.map((each) => [capitalize(longDate().format(each.date)), format(each.value)]));
3389
+ frame.fillLegend([], false);
3390
+ paintScale();
3391
+ if (selected !== null && selected >= model.days.length) selected = null;
3392
+ const same = cells.length === model.days.length && cells.length > 0 && builtFrom === model.days[0].key;
3393
+ if (same && animate) {
3394
+ cells.forEach((cell, i) => {
3395
+ const level = levelOf(model.days[i].value);
3396
+ cell.setAttribute("data-mk-level", String(level));
3397
+ cell.style.fill = fillOf(level);
3398
+ });
3399
+ } else build(animate);
3400
+ paintSelection(false);
3401
+ };
3402
+ const select = (index, announce = false) => {
3403
+ if (scope.disposed) return;
3404
+ const next = index === null || !model.days.length ? null : Math.max(0, Math.min(model.days.length - 1, Math.round(index)));
3405
+ if (next === selected) return;
3406
+ selected = next;
3407
+ paintSelection(announce);
3408
+ const each = selected === null ? null : model.days[selected];
3409
+ options.onSelect?.(each?.key ?? null, each?.value ?? null);
3410
+ root.dispatchEvent(new CustomEvent("mk:select", { bubbles: true, detail: { date: each?.key ?? null, value: each?.value ?? null } }));
3411
+ };
3412
+ scope.on(canvas, "pointermove", (event) => {
3413
+ const cell = event.target.closest("[data-mk-index]");
3414
+ select(cell ? Number(cell.getAttribute("data-mk-index")) : null);
3415
+ });
3416
+ scope.on(canvas, "pointerleave", (event) => {
3417
+ if (event.pointerType === "mouse") select(null);
3418
+ });
3419
+ scope.on(canvas, "focus", () => {
3420
+ if (selected === null && model.days.length) select(model.days.length - 1, true);
3421
+ });
3422
+ scope.on(canvas, "blur", () => select(null));
3423
+ scope.on(canvas, "keydown", (event) => {
3424
+ const key = event.key;
3425
+ const at = selected ?? model.days.length - 1;
3426
+ const moves = { ArrowUp: at - 1, ArrowDown: at + 1, ArrowLeft: at - 7, ArrowRight: at + 7, PageUp: at - 28, PageDown: at + 28, Home: 0, End: model.days.length - 1, Escape: null };
3427
+ if (!(key in moves) || !model.days.length) return;
3428
+ event.preventDefault();
3429
+ select(moves[key], true);
3430
+ const cell = selected === null ? null : cells[selected];
3431
+ if (cell) {
3432
+ const x = Number(cell.getAttribute("x"));
3433
+ if (x - scroller.scrollLeft < LEFT || x - scroller.scrollLeft > scroller.clientWidth - geometry.cell * 2) scroller.scrollLeft = x - scroller.clientWidth / 2;
3434
+ }
3435
+ });
3436
+ onWidth(root, scope, () => {
3437
+ build(false);
3438
+ paintSelection(false);
3439
+ });
3440
+ draw(true);
3441
+ return {
3442
+ update(next) {
3443
+ if (scope.disposed) return;
3444
+ options = { ...options, ...next };
3445
+ model = modelOf();
3446
+ draw(true);
3447
+ },
3448
+ select(date) {
3449
+ const index = date === null ? -1 : model.days.findIndex((each) => each.key === date);
3450
+ select(index < 0 ? null : index);
3451
+ },
3452
+ get selected() {
3453
+ return selected === null ? null : model.days[selected]?.key ?? null;
3454
+ },
3455
+ destroy: () => scope.dispose()
3456
+ };
3457
+ }
3458
+
3459
+ // src/components/orbit-menu/engine.ts
3460
+ function createOrbitMenu(root, options = {}) {
3461
+ const toggle = root?.querySelector("[data-mk-orbit-toggle]") ?? null;
3462
+ const items2 = root ? [...root.querySelectorAll("[data-mk-orbit-item]")] : [];
3463
+ if (!root || !toggle || !items2.length) {
3464
+ if (root) warnOnce("orbit-menu: needs a [data-mk-orbit-toggle] and at least one [data-mk-orbit-item]");
3465
+ return inert({ open() {
3466
+ }, close() {
3467
+ }, toggle() {
3468
+ }, isOpen: false });
3469
+ }
3470
+ registerMotion();
3471
+ const scope = createScope();
3472
+ const radius = Number.isFinite(options.radius) ? Math.max(24, options.radius) : 96;
3473
+ const start = (Number.isFinite(options.start) ? options.start : 0) * Math.PI / 180;
3474
+ const angles = items2.map((_, i) => start + i * Math.PI * 2 / items2.length);
3475
+ const valueOf2 = (item) => item.dataset.mkValue ?? String(items2.indexOf(item));
3476
+ if (!toggle.children.length && !toggle.textContent?.trim()) {
3477
+ const burger = document.createElement("span");
3478
+ burger.dataset.mkOrbitBurger = "";
3479
+ burger.setAttribute("aria-hidden", "true");
3480
+ burger.append(document.createElement("i"), document.createElement("i"), document.createElement("i"));
3481
+ toggle.append(burger);
3482
+ scope.add(() => burger.remove());
3483
+ }
3484
+ scope.attr(toggle, "aria-expanded", "false");
3485
+ scope.attr(toggle, "aria-haspopup", "true");
3486
+ if (!toggle.getAttribute("aria-label") && !toggle.textContent?.trim()) scope.attr(toggle, "aria-label", "Men\xFA");
3487
+ for (const item of items2) {
3488
+ scope.attr(item, "inert", "");
3489
+ if (item instanceof HTMLButtonElement) scope.attr(item, "type", item.getAttribute("type") ?? "button");
3490
+ }
3491
+ scope.attr(root, "data-mk-ready", "");
3492
+ scope.attr(root, "data-mk-state", "closed");
3493
+ const states = items2.map((_, i) => ({ a: angles[i], r: 0 }));
3494
+ const apply = (i) => {
3495
+ const { a, r } = states[i];
3496
+ gsap.set(items2[i], { x: r * Math.sin(a), y: -r * Math.cos(a) });
3497
+ };
3498
+ let timeline = null;
3499
+ scope.add(() => {
3500
+ timeline?.kill();
3501
+ gsap.set(items2, { clearProps: "transform,opacity,filter,visibility" });
3502
+ });
3503
+ gsap.set(items2, { opacity: 0, scale: 0.3, visibility: "hidden" });
3504
+ let open = false;
3505
+ const set = (next, focus = false) => {
3506
+ if (next === open) return;
3507
+ open = next;
3508
+ toggle.setAttribute("aria-expanded", String(open));
3509
+ root.dataset.mkState = open ? "open" : "closed";
3510
+ for (const item of items2) item.toggleAttribute("inert", !open);
3511
+ timeline?.kill();
3512
+ if (reduced()) {
3513
+ items2.forEach((item, i) => {
3514
+ states[i] = { a: angles[i], r: open ? radius : 0 };
3515
+ apply(i);
3516
+ gsap.set(item, { opacity: open ? 1 : 0, scale: open ? 1 : 0.3, filter: "none", visibility: open ? "visible" : "hidden" });
3517
+ });
3518
+ } else if (open) {
3519
+ timeline = gsap.timeline();
3520
+ items2.forEach((item, i) => {
3521
+ const state = states[i];
3522
+ if (state.r < 1) state.a = angles[i] - 0.7;
3523
+ const at = i * 0.045;
3524
+ gsap.set(item, { visibility: "visible" });
3525
+ timeline.to(state, { r: radius, duration: 0.55, ease: EASE.swatch, onUpdate: () => apply(i) }, at);
3526
+ timeline.to(state, { a: angles[i], duration: 0.5, ease: "power3.out", onUpdate: () => apply(i) }, at);
3527
+ timeline.fromTo(item, { filter: "blur(8px)" }, { opacity: 1, scale: 1, filter: "blur(0px)", duration: 0.35, ease: "power2.out", clearProps: "filter" }, at);
3528
+ });
3529
+ } else {
3530
+ timeline = gsap.timeline();
3531
+ [...items2].reverse().forEach((item, k) => {
3532
+ const i = items2.length - 1 - k;
3533
+ const state = states[i];
3534
+ const at = k * 0.03;
3535
+ timeline.to(state, { r: 0, a: state.a + 0.6, duration: 0.3, ease: "power2.in", onUpdate: () => apply(i) }, at);
3536
+ timeline.to(item, { opacity: 0, scale: 0.3, filter: "blur(6px)", duration: 0.28, ease: "power2.in", onComplete: () => {
3537
+ gsap.set(item, { visibility: "hidden", clearProps: "filter" });
3538
+ } }, at);
3539
+ });
3540
+ }
3541
+ if (focus === "first") items2[0].focus();
3542
+ if (focus === "toggle") toggle.focus();
3543
+ options.onToggle?.(open);
3544
+ root.dispatchEvent(new CustomEvent("mk:toggle", { bubbles: true, detail: { open } }));
3545
+ };
3546
+ scope.on(toggle, "click", (event) => {
3547
+ press(toggle);
3548
+ set(!open, !open && event.detail === 0 ? "first" : false);
3549
+ });
3550
+ scope.on(root, "click", (event) => {
3551
+ const item = event.target.closest("[data-mk-orbit-item]");
3552
+ if (!item || !items2.includes(item) || !open) return;
3553
+ press(item);
3554
+ const value = valueOf2(item);
3555
+ options.onSelect?.(value);
3556
+ root.dispatchEvent(new CustomEvent("mk:select", { bubbles: true, detail: { value } }));
3557
+ if (options.closeOnSelect !== false) set(false, "toggle");
3558
+ });
3559
+ const sides = { ArrowUp: 0, ArrowRight: Math.PI / 2, ArrowDown: Math.PI, ArrowLeft: Math.PI * 3 / 2 };
3560
+ scope.on(root, "keydown", (event) => {
3561
+ const key = event.key;
3562
+ if (key === "Escape" && open) {
3563
+ event.preventDefault();
3564
+ set(false, "toggle");
3565
+ return;
3566
+ }
3567
+ if (!(key in sides)) return;
3568
+ if (!open) {
3569
+ if (document.activeElement !== toggle) return;
3570
+ event.preventDefault();
3571
+ set(true);
3572
+ } else event.preventDefault();
3573
+ const want = sides[key];
3574
+ const gap = (a) => {
3575
+ const d = Math.abs(((a - want) % (Math.PI * 2) + Math.PI * 3) % (Math.PI * 2) - Math.PI);
3576
+ return d;
3577
+ };
3578
+ let best = 0;
3579
+ angles.forEach((a, i) => {
3580
+ if (gap(a) < gap(angles[best])) best = i;
3581
+ });
3582
+ items2[best].focus();
3583
+ });
3584
+ scope.on(document, "pointerdown", (event) => {
3585
+ if (open && !root.contains(event.target)) set(false);
3586
+ });
3587
+ return {
3588
+ open: () => set(true),
3589
+ close: () => set(false),
3590
+ toggle: () => set(!open),
3591
+ get isOpen() {
3592
+ return open;
3593
+ },
3594
+ destroy: () => scope.dispose()
3595
+ };
3596
+ }
3597
+
3598
+ export {
3599
+ enterMessages,
3600
+ fitComposer,
3601
+ scrollToLatest,
3602
+ createThemePicker,
3603
+ ICON_PATHS,
3604
+ iconSvg,
3605
+ TOAST_LIMIT,
3606
+ getToasts,
3607
+ subscribeToasts,
3608
+ dismissToast,
3609
+ removeToast,
3610
+ clearToasts,
3611
+ toast,
3612
+ toastTimers,
3613
+ createToaster,
3614
+ PENDING_ID,
3615
+ capturePending,
3616
+ morphPendingToReply,
3617
+ chatMessage,
3618
+ createChat,
3619
+ NAV_STYLES,
3620
+ NAV_STYLE_ALIASES,
3621
+ toNavStyle,
3622
+ revealShell,
3623
+ createNav,
3624
+ createCursor,
3625
+ createIsland,
3626
+ PILL_ARROW,
3627
+ createPillButton,
3628
+ createToolbar,
3629
+ createBidirectionalSlider,
3630
+ createVoiceDots,
3631
+ createPieChart,
3632
+ createRadarChart,
3633
+ createRadialChart,
3634
+ createSankeyChart,
3635
+ createHeatmapChart,
3636
+ createOrbitMenu
3637
+ };
3638
+ //# sourceMappingURL=chunk-JXRS3OEA.js.map