@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,743 @@
1
+ import { gsap, EASE, registerMotion } from '../../core/gsap';
2
+ import { requestFrame } from '../../core/frame';
3
+ import { reduced } from '../../core/reduced';
4
+ import { createScope } from '../../core/scope';
5
+ import { inert, type Instance } from '../../core/types';
6
+ import { fromJson } from '../../core/dates';
7
+ import { checkStates, findNode, isBranch, searchTree, toggleCheck, walk, type CheckState, type TreeNode } from '../../core/tree';
8
+ import { foldText, markText } from '../../core/mark';
9
+
10
+ /*
11
+ * Tree view (WAI-ARIA tree): nodes that open and close, three-state
12
+ * checkboxes and a search. A branch opens by its height (.32 s, signature)
13
+ * while its children slide in out of a blur (25 ms apart) and its chevron
14
+ * turns (.3 s, swing); it closes the same way back. The selected row sits on a
15
+ * pill that glides to each new choice (.3 s, swing). A check draws itself and
16
+ * its box pops; a branch with some children checked shows a dash. The search
17
+ * marks the letters that match, opens the branches that hold them and hides
18
+ * the rest; clearing it puts back what was open. loadChildren() fills a branch
19
+ * the first time it opens (a spinner row meanwhile). Keyboard: ↑ ↓ move, → opens
20
+ * or enters, ← closes or goes up, Home, End, * opens the siblings, Enter
21
+ * selects, Space checks (or selects), and typing jumps to a label.
22
+ * Like the file explorer: with `icons`, branches are folders whose lid opens
23
+ * with them and leaves are pages; nodes that arrive (setNodes, a move) come in
24
+ * out of a blur; with `draggable`, a dragged row lifts a card that follows the
25
+ * pointer and tilts with its speed, the folder under it opens its lid (and the
26
+ * branch after a moment), and dropping flies the card into it.
27
+ */
28
+
29
+ export type { TreeNode } from '../../core/tree';
30
+
31
+ export interface TreeViewOptions {
32
+ nodes?: TreeNode[];
33
+ /** Three-state checkboxes (default false). */
34
+ checkable?: boolean;
35
+ checked?: string[];
36
+ /** Open at the start: ids, or true for every branch. */
37
+ expanded?: string[] | boolean;
38
+ selected?: string | null;
39
+ /** A search field above the tree: true, or its placeholder. */
40
+ search?: boolean | string;
41
+ /** Accessible name (default 'Árbol'). */
42
+ label?: string;
43
+ /** Children of a branch with hasChildren, the first time it opens. */
44
+ loadChildren?: (node: TreeNode) => Promise<TreeNode[]> | TreeNode[];
45
+ /** Draw a label yourself (json-viewer, file-explorer); `query` is the search, for marking. */
46
+ renderLabel?: (node: TreeNode, element: HTMLElement, query: string) => void;
47
+ /** The text the search looks in (default: the label). */
48
+ searchText?: (node: TreeNode) => string;
49
+ onSelect?: (node: TreeNode) => void;
50
+ onCheck?: (checked: string[]) => void;
51
+ onExpand?: (node: TreeNode, expanded: boolean) => void;
52
+ /** Folder and page icons (default false); a node's own `icon` still wins. */
53
+ icons?: boolean;
54
+ /** Rows can be dragged into another branch (default false). */
55
+ draggable?: boolean;
56
+ /** A node was dropped into a branch (the tree has moved it). */
57
+ onMove?: (node: TreeNode, into: TreeNode) => void;
58
+ }
59
+
60
+ export interface TreeViewInstance extends Instance {
61
+ expand(id: string, animate?: boolean): void;
62
+ collapse(id: string, animate?: boolean): void;
63
+ toggle(id: string): void;
64
+ expandAll(): void;
65
+ collapseAll(): void;
66
+ /** Open the branches above it and bring it into view. */
67
+ reveal(id: string): void;
68
+ select(id: string | null, notify?: boolean): void;
69
+ setChecked(ids: string[]): void;
70
+ filter(query: string): void;
71
+ setNodes(nodes: TreeNode[]): void;
72
+ focusItem(id: string): void;
73
+ readonly selected: string | null;
74
+ readonly checked: string[];
75
+ readonly expanded: string[];
76
+ /** The tree element (role="tree"). */
77
+ readonly element: HTMLElement;
78
+ }
79
+
80
+ const FOLDER =
81
+ '<svg aria-hidden="true" viewBox="0 0 48 40"><path data-mk-tree-folder-back d="M2 6a4 4 0 0 1 4-4h11.6a4 4 0 0 1 2.9 1.2L23.4 6H42a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4z"/><path data-mk-tree-folder-front d="M2 14a4 4 0 0 1 4-4h36a4 4 0 0 1 4 4v20a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4z"/></svg>';
82
+ const PAGE =
83
+ '<svg aria-hidden="true" viewBox="0 0 40 48"><path data-mk-tree-sheet d="M7 2h18.5L37 13.5V42a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V6a4 4 0 0 1 4-4z"/><path data-mk-tree-fold d="M25.5 2v8.5a3 3 0 0 0 3 3H37z"/></svg>';
84
+
85
+ /** `nodes` with the node `id` moved to the end of `into`'s children (a new tree: the given one is not changed). */
86
+ export function moveTreeNode(nodes: TreeNode[], id: string, into: string): TreeNode[] {
87
+ let taken: TreeNode | null = null;
88
+ const without = (list: TreeNode[]): TreeNode[] =>
89
+ list
90
+ .filter((node) => {
91
+ if (node.id !== id) return true;
92
+ taken = node;
93
+ return false;
94
+ })
95
+ .map((node) => (node.children ? { ...node, children: without(node.children) } : node));
96
+ const rest = without(nodes);
97
+ const moved = taken as TreeNode | null;
98
+ if (!moved) return nodes;
99
+ const put = (list: TreeNode[]): TreeNode[] =>
100
+ list.map((node) => (node.id === into ? { ...node, children: [...(node.children ?? []), moved] } : node.children ? { ...node, children: put(node.children) } : node));
101
+ return put(rest);
102
+ }
103
+
104
+ const CHEVRON = '<svg aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 6l6 6-6 6"/></svg>';
105
+ const CHECK = '<svg aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path data-mk-tree-tick d="M5 12.5l4.5 4.5L19 7.5" pathLength="1"/><path data-mk-tree-dash d="M6 12h12"/></svg>';
106
+ let sequence = 0;
107
+
108
+ const fold = foldText;
109
+
110
+ // Kept here too for code that imported it from the tree.
111
+ export { markText };
112
+
113
+ export function createTreeView(root: HTMLElement | null, options: TreeViewOptions = {}): TreeViewInstance {
114
+ if (!root) return inert({ expand() {}, collapse() {}, toggle() {}, expandAll() {}, collapseAll() {}, reveal() {}, select() {}, setChecked() {}, filter() {}, setNodes() {}, focusItem() {}, selected: null, checked: [], expanded: [], element: null as unknown as HTMLElement });
115
+ registerMotion();
116
+ const scope = createScope();
117
+ const uid = `mk-tree-${++sequence}`;
118
+ // JSON text too (data-mk-nodes through autoInit).
119
+ let nodes: TreeNode[] = fromJson(options.nodes) ?? [];
120
+ const expanded = new Set<string>();
121
+ if (options.expanded === true) walk(nodes, (node) => isBranch(node) && expanded.add(node.id));
122
+ else for (const id of options.expanded || []) expanded.add(id);
123
+ /** Every given id checked with what lies under it; branches follow their children. */
124
+ const normalised = (ids: string[]) => ids.reduce((set, id) => toggleCheck(nodes, set, id, true), new Set<string>());
125
+ let checked = normalised(fromJson(options.checked) ?? []);
126
+ let selected: string | null = options.selected ?? null;
127
+ let focused: string | null = selected;
128
+ let query = '';
129
+ let beforeSearch: Set<string> | null = null;
130
+ const loading = new Set<string>();
131
+ const effects = new Set<gsap.core.Animation>();
132
+ const keep = (animation: gsap.core.Animation | null) => {
133
+ if (!animation) return;
134
+ effects.add(animation);
135
+ // Finished ones leave as new ones arrive: the animation's own onComplete stays untouched.
136
+ for (const effect of effects) if (effect.totalProgress() === 1) effects.delete(effect);
137
+ };
138
+
139
+ let searchInput: HTMLInputElement | null = null;
140
+ const status = document.createElement('span');
141
+ status.className = 'mk-sr-only';
142
+ status.setAttribute('role', 'status');
143
+ if (options.search) {
144
+ searchInput = document.createElement('input');
145
+ searchInput.type = 'search';
146
+ searchInput.dataset.mkTreeSearch = '';
147
+ searchInput.placeholder = typeof options.search === 'string' ? options.search : 'Buscar…';
148
+ searchInput.setAttribute('aria-label', 'Buscar en el árbol');
149
+ searchInput.setAttribute('aria-controls', uid);
150
+ }
151
+ const box = document.createElement('div');
152
+ box.dataset.mkTreeBox = '';
153
+ const pill = document.createElement('span');
154
+ pill.dataset.mkTreePill = '';
155
+ pill.setAttribute('aria-hidden', 'true');
156
+ const tree = document.createElement('ul');
157
+ tree.id = uid;
158
+ tree.dataset.mkTree = '';
159
+ tree.setAttribute('role', 'tree');
160
+ tree.setAttribute('aria-label', options.label ?? 'Árbol');
161
+ if (options.checkable) tree.setAttribute('aria-multiselectable', 'true');
162
+ box.append(pill, tree);
163
+ const empty = document.createElement('p');
164
+ empty.dataset.mkTreeEmpty = '';
165
+ empty.textContent = 'Sin coincidencias';
166
+ empty.hidden = true;
167
+ if (searchInput) root.append(searchInput);
168
+ root.append(box, empty, status);
169
+ scope.add(() => {
170
+ for (const effect of effects) effect.kill();
171
+ effects.clear();
172
+ gsap.killTweensOf(pill);
173
+ searchInput?.remove();
174
+ box.remove();
175
+ empty.remove();
176
+ status.remove();
177
+ });
178
+ scope.attr(root, 'data-mk-ready', '');
179
+
180
+ const itemOf = (id: string) => [...tree.querySelectorAll<HTMLElement>('[role="treeitem"]')].find((item) => item.dataset.id === id) ?? null;
181
+ const nodeOf = (id: string) => findNode(nodes, id)?.node ?? null;
182
+ /** Items a reader can reach now: not inside a closed branch, not hidden by the search. */
183
+ const visibleItems = () =>
184
+ [...tree.querySelectorAll<HTMLElement>('[role="treeitem"]')].filter((item) => !item.hidden && !item.closest('[role="group"][hidden], [role="treeitem"][hidden]'));
185
+
186
+ const paintChecks = (animate: boolean) => {
187
+ if (!options.checkable) return;
188
+ const states = checkStates(nodes, checked);
189
+ for (const item of tree.querySelectorAll<HTMLElement>('[role="treeitem"]')) {
190
+ const state = states.get(item.dataset.id!) ?? 'false';
191
+ const before = item.getAttribute('aria-checked') as CheckState | null;
192
+ item.setAttribute('aria-checked', state);
193
+ if (!animate || before === state || reduced()) continue;
194
+ const box = item.querySelector<HTMLElement>(':scope > [data-mk-tree-row] [data-mk-tree-check]');
195
+ if (!box) continue;
196
+ keep(gsap.fromTo(box, { scale: 0.8 }, { scale: 1, duration: 0.35, ease: EASE.click, clearProps: 'transform' }));
197
+ const path = box.querySelector<SVGPathElement>(state === 'true' ? '[data-mk-tree-tick]' : '[data-mk-tree-dash]');
198
+ if (path && state !== 'false') keep(gsap.fromTo(path, { strokeDasharray: state === 'true' ? 1 : 12, strokeDashoffset: state === 'true' ? 1 : 12 }, { strokeDashoffset: 0, duration: 0.3, ease: EASE.wipe, clearProps: 'strokeDasharray,strokeDashoffset' }));
199
+ }
200
+ };
201
+
202
+ const fillLabel = (node: TreeNode, label: HTMLElement) => {
203
+ label.replaceChildren();
204
+ if (options.renderLabel) options.renderLabel(node, label, query);
205
+ else label.append(markText(node.label, query));
206
+ };
207
+
208
+ const row = (node: TreeNode, depth: number, index: number, count: number): HTMLElement => {
209
+ const item = document.createElement('li');
210
+ item.dataset.id = node.id;
211
+ item.setAttribute('role', 'treeitem');
212
+ item.setAttribute('aria-level', String(depth + 1));
213
+ item.setAttribute('aria-setsize', String(count));
214
+ item.setAttribute('aria-posinset', String(index + 1));
215
+ item.tabIndex = -1;
216
+ if (node.disabled) item.setAttribute('aria-disabled', 'true');
217
+ const branch = isBranch(node);
218
+ if (branch) item.setAttribute('aria-expanded', String(expanded.has(node.id)));
219
+ if (!options.checkable && selected === node.id) item.setAttribute('aria-selected', 'true');
220
+ const line = document.createElement('div');
221
+ line.dataset.mkTreeRow = '';
222
+ line.style.setProperty('--mk-tree-depth', String(depth));
223
+ const chevron = document.createElement('span');
224
+ chevron.dataset.mkTreeChevron = '';
225
+ if (branch) chevron.innerHTML = CHEVRON;
226
+ line.append(chevron);
227
+ if (options.checkable) {
228
+ const check = document.createElement('span');
229
+ check.dataset.mkTreeCheck = '';
230
+ check.innerHTML = CHECK;
231
+ line.append(check);
232
+ }
233
+ if (node.icon) {
234
+ const icon = document.createElement('span');
235
+ icon.dataset.mkTreeIcon = '';
236
+ icon.setAttribute('aria-hidden', 'true');
237
+ icon.textContent = node.icon;
238
+ line.append(icon);
239
+ } else if (options.icons) {
240
+ const icon = document.createElement('span');
241
+ if (branch) icon.dataset.mkTreeFolder = '';
242
+ else icon.dataset.mkTreePage = '';
243
+ icon.innerHTML = branch ? FOLDER : PAGE;
244
+ line.append(icon);
245
+ }
246
+ const label = document.createElement('span');
247
+ label.dataset.mkTreeLabel = '';
248
+ fillLabel(node, label);
249
+ line.append(label);
250
+ item.append(line);
251
+ if (branch) {
252
+ const group = document.createElement('ul');
253
+ group.setAttribute('role', 'group');
254
+ group.hidden = !expanded.has(node.id);
255
+ (node.children ?? []).forEach((child, i, all) => group.append(row(child, depth + 1, i, all.length)));
256
+ item.append(group);
257
+ }
258
+ return item;
259
+ };
260
+
261
+ /** The pill under the selected row (or under nothing). */
262
+ const placePill = (animate: boolean) => {
263
+ const item = selected ? itemOf(selected) : null;
264
+ const line = item && visibleItems().includes(item) ? item.querySelector<HTMLElement>(':scope > [data-mk-tree-row]') : null;
265
+ if (!line) {
266
+ gsap.killTweensOf(pill);
267
+ pill.style.opacity = '0';
268
+ return;
269
+ }
270
+ const base = box.getBoundingClientRect();
271
+ const rect = line.getBoundingClientRect();
272
+ const target = { y: rect.top - base.top + box.scrollTop, height: rect.height };
273
+ if (!animate || reduced() || pill.style.opacity !== '1') {
274
+ gsap.killTweensOf(pill);
275
+ gsap.set(pill, target);
276
+ pill.style.opacity = '1';
277
+ return;
278
+ }
279
+ keep(gsap.to(pill, { ...target, duration: 0.3, ease: EASE.swatch, overwrite: 'auto' }));
280
+ };
281
+
282
+ const roving = () => {
283
+ const items = visibleItems();
284
+ const target = (focused && items.find((item) => item.dataset.id === focused)) || (selected && items.find((item) => item.dataset.id === selected)) || items[0];
285
+ for (const item of tree.querySelectorAll<HTMLElement>('[role="treeitem"]')) item.tabIndex = item === target ? 0 : -1;
286
+ };
287
+
288
+ let known: Set<string> | null = null;
289
+ const allIds = (list: TreeNode[], into = new Set<string>()) => {
290
+ for (const node of list) {
291
+ into.add(node.id);
292
+ if (node.children) allIds(node.children, into);
293
+ }
294
+ return into;
295
+ };
296
+ /** Rows of nodes that just arrived come in out of a blur (not on the first drawing). */
297
+ const welcome = () => {
298
+ const now = allIds(nodes);
299
+ const fresh = known ? [...now].filter((id) => !known!.has(id)) : [];
300
+ known = now;
301
+ if (reduced() || !fresh.length) return;
302
+ const rows = fresh.map((id) => itemOf(id)?.querySelector<HTMLElement>(':scope > [data-mk-tree-row]')).filter((line): line is HTMLElement => !!line && visibleItems().includes(line.parentElement!));
303
+ if (rows.length) keep(gsap.fromTo(rows, { opacity: 0, x: -8, filter: 'blur(6px)' }, { opacity: 1, x: 0, filter: 'blur(0px)', duration: 0.35, stagger: 0.03, ease: 'power2.out', clearProps: 'opacity,transform,filter' }));
304
+ };
305
+ const render = () => {
306
+ tree.replaceChildren(...nodes.map((node, i) => row(node, 0, i, nodes.length)));
307
+ paintChecks(false);
308
+ applySearch(false);
309
+ roving();
310
+ placePill(false);
311
+ welcome();
312
+ };
313
+
314
+ // ── Opening and closing ──────────────────────────────────────────────────
315
+ const animateGroup = (group: HTMLElement, open: boolean) => {
316
+ if (reduced()) {
317
+ group.hidden = !open;
318
+ return placePill(false);
319
+ }
320
+ gsap.killTweensOf(group);
321
+ if (open) {
322
+ group.hidden = false;
323
+ const height = group.scrollHeight;
324
+ keep(gsap.fromTo(group, { height: 0, opacity: 0.5, overflow: 'hidden' }, { height, opacity: 1, duration: 0.32, ease: EASE.signature, clearProps: 'height,opacity,overflow', onUpdate: () => placePill(false) }));
325
+ const rows = [...group.children].slice(0, 14);
326
+ keep(gsap.fromTo(rows, { opacity: 0, x: -6, filter: 'blur(4px)' }, { opacity: 1, x: 0, filter: 'blur(0px)', duration: 0.3, stagger: 0.025, ease: 'power2.out', clearProps: 'opacity,transform,filter' }));
327
+ } else {
328
+ keep(
329
+ gsap.to(group, {
330
+ height: 0,
331
+ opacity: 0,
332
+ overflow: 'hidden',
333
+ duration: 0.24,
334
+ ease: 'power2.in',
335
+ onUpdate: () => placePill(false),
336
+ onComplete: () => {
337
+ group.hidden = true;
338
+ gsap.set(group, { clearProps: 'height,opacity,overflow' });
339
+ placePill(false);
340
+ },
341
+ }),
342
+ );
343
+ }
344
+ };
345
+
346
+ const setOpen = async (id: string, open: boolean, animate = true) => {
347
+ const node = nodeOf(id);
348
+ const item = itemOf(id);
349
+ if (!node || !item || !isBranch(node) || expanded.has(id) === open) return;
350
+ if (open) expanded.add(id);
351
+ else expanded.delete(id);
352
+ item.setAttribute('aria-expanded', String(open));
353
+ const group = item.querySelector<HTMLElement>(':scope > [role="group"]')!;
354
+ // A branch whose children come later: a spinner row, then them.
355
+ if (open && node.hasChildren && !node.children?.length && options.loadChildren && !loading.has(id)) {
356
+ loading.add(id);
357
+ const spinner = document.createElement('li');
358
+ spinner.dataset.mkTreeLoading = '';
359
+ spinner.setAttribute('role', 'none');
360
+ spinner.textContent = 'Cargando…';
361
+ spinner.style.setProperty('--mk-tree-depth', String(Number(item.getAttribute('aria-level'))));
362
+ group.replaceChildren(spinner);
363
+ group.hidden = false;
364
+ item.setAttribute('aria-busy', 'true');
365
+ try {
366
+ node.children = await options.loadChildren(node);
367
+ } catch {
368
+ node.children = [];
369
+ }
370
+ loading.delete(id);
371
+ if (scope.disposed) return;
372
+ item.removeAttribute('aria-busy');
373
+ const depth = Number(item.getAttribute('aria-level'));
374
+ group.replaceChildren(...(node.children ?? []).map((child, i, all) => row(child, depth, i, all.length)));
375
+ paintChecks(false);
376
+ if (!node.children?.length) {
377
+ item.removeAttribute('aria-expanded');
378
+ group.remove();
379
+ return;
380
+ }
381
+ if (animate) animateGroup(group, true);
382
+ } else if (animate) animateGroup(group, open);
383
+ else {
384
+ group.hidden = !open;
385
+ placePill(false);
386
+ }
387
+ roving();
388
+ options.onExpand?.(node, open);
389
+ root.dispatchEvent(new CustomEvent('mk:expand', { bubbles: true, detail: { id, expanded: open } }));
390
+ };
391
+
392
+ // ── Selecting and checking ───────────────────────────────────────────────
393
+ const select = (id: string | null, notify: boolean) => {
394
+ if (id && (nodeOf(id)?.disabled || !itemOf(id))) return;
395
+ const changed = id !== selected;
396
+ selected = id;
397
+ if (!options.checkable) for (const item of tree.querySelectorAll<HTMLElement>('[role="treeitem"]')) {
398
+ if (item.dataset.id === id) item.setAttribute('aria-selected', 'true');
399
+ else item.removeAttribute('aria-selected');
400
+ }
401
+ if (id) focused = id;
402
+ roving();
403
+ placePill(true);
404
+ if (!changed || !notify || !id) return;
405
+ const node = nodeOf(id)!;
406
+ options.onSelect?.(node);
407
+ root.dispatchEvent(new CustomEvent('mk:select', { bubbles: true, detail: { id, node } }));
408
+ };
409
+
410
+ const check = (id: string) => {
411
+ if (!options.checkable || nodeOf(id)?.disabled) return;
412
+ checked = toggleCheck(nodes, checked, id);
413
+ paintChecks(true);
414
+ const list = [...checked];
415
+ const state = checkStates(nodes, checked).get(id);
416
+ status.textContent = `${nodeOf(id)?.label ?? ''} ${state === 'true' ? 'marcado' : 'desmarcado'}`;
417
+ options.onCheck?.(list);
418
+ root.dispatchEvent(new CustomEvent('mk:check', { bubbles: true, detail: { checked: list } }));
419
+ };
420
+
421
+ // ── Search ───────────────────────────────────────────────────────────────
422
+ const applySearch = (announce: boolean) => {
423
+ const result = searchTree(nodes, query, options.searchText);
424
+ if (result.active) {
425
+ beforeSearch ??= new Set(expanded);
426
+ for (const id of result.open) expanded.add(id);
427
+ } else if (beforeSearch) {
428
+ expanded.clear();
429
+ for (const id of beforeSearch) expanded.add(id);
430
+ beforeSearch = null;
431
+ }
432
+ for (const item of tree.querySelectorAll<HTMLElement>('[role="treeitem"]')) {
433
+ const id = item.dataset.id!;
434
+ item.hidden = result.active && !result.visible.has(id);
435
+ if (item.hasAttribute('aria-expanded')) {
436
+ const open = expanded.has(id);
437
+ item.setAttribute('aria-expanded', String(open));
438
+ const group = item.querySelector<HTMLElement>(':scope > [role="group"]');
439
+ if (group) group.hidden = !open;
440
+ }
441
+ const node = nodeOf(id);
442
+ const label = item.querySelector<HTMLElement>(':scope > [data-mk-tree-row] [data-mk-tree-label]');
443
+ if (node && label) fillLabel(node, label);
444
+ }
445
+ empty.hidden = !result.active || result.matches.size > 0;
446
+ if (announce) status.textContent = !result.active ? '' : result.matches.size ? `${result.matches.size} ${result.matches.size === 1 ? 'coincidencia' : 'coincidencias'}` : 'Sin coincidencias';
447
+ roving();
448
+ placePill(false);
449
+ };
450
+ if (searchInput) {
451
+ scope.on(searchInput, 'input', () => {
452
+ query = searchInput!.value;
453
+ applySearch(true);
454
+ });
455
+ scope.on(searchInput, 'keydown', (event) => {
456
+ if ((event as KeyboardEvent).key === 'ArrowDown') {
457
+ event.preventDefault();
458
+ visibleItems()[0]?.focus();
459
+ }
460
+ });
461
+ }
462
+
463
+ // ── Dragging into another branch ─────────────────────────────────────────
464
+ if (options.draggable) {
465
+ let drag: { id: string; x: number; y: number; pointer: number; card: HTMLElement | null; over: HTMLElement | null; lastX: number; lastT: number } | null = null;
466
+ let opening: ReturnType<typeof setTimeout> | undefined;
467
+ const clearOver = () => {
468
+ clearTimeout(opening);
469
+ drag?.over?.removeAttribute('data-mk-tree-over');
470
+ if (drag) drag.over = null;
471
+ };
472
+ /** The branch a node may go into under the pointer (a leaf counts as its branch), or null. */
473
+ const branchAt = (x: number, y: number) => {
474
+ const under = document.elementFromPoint(x, y)?.closest<HTMLElement>('[role="treeitem"]');
475
+ if (!under || !tree.contains(under) || !drag) return null;
476
+ const node = nodeOf(under.dataset.id!);
477
+ const candidate = node && isBranch(node) ? under : under.parentElement?.closest<HTMLElement>('[role="treeitem"]') ?? null;
478
+ if (!candidate) return null;
479
+ const path = findNode(nodes, candidate.dataset.id!)?.path.map((each) => each.id) ?? [];
480
+ // Not into itself, one of its own branches, or where it already is.
481
+ const parent = findNode(nodes, drag.id)?.path.at(-2)?.id;
482
+ if (path.includes(drag.id) || candidate.dataset.id === parent) return null;
483
+ return candidate;
484
+ };
485
+ const lift = (id: string, x: number, y: number) => {
486
+ const node = nodeOf(id)!;
487
+ const card = document.createElement('div');
488
+ card.dataset.mkTreeDrag = '';
489
+ card.setAttribute('aria-hidden', 'true');
490
+ if (options.icons) {
491
+ const icon = document.createElement('span');
492
+ if (isBranch(node)) icon.dataset.mkTreeFolder = '';
493
+ else icon.dataset.mkTreePage = '';
494
+ icon.innerHTML = isBranch(node) ? FOLDER : PAGE;
495
+ card.append(icon);
496
+ }
497
+ const text = document.createElement('span');
498
+ text.textContent = node.label;
499
+ card.append(text);
500
+ Object.assign(card.style, { left: '0px', top: '0px' });
501
+ root.append(card);
502
+ gsap.set(card, { x: x + 14, y: y + 10 });
503
+ if (!reduced()) keep(gsap.fromTo(card, { scale: 0.85, opacity: 0 }, { scale: 1.04, opacity: 1, duration: 0.3, ease: EASE.pop }));
504
+ itemOf(id)?.setAttribute('data-mk-tree-dragging', '');
505
+ return card;
506
+ };
507
+ const end = (drop: boolean) => {
508
+ if (!drag) return;
509
+ const { id, card, over } = drag;
510
+ clearOver();
511
+ drag = null;
512
+ itemOf(id)?.removeAttribute('data-mk-tree-dragging');
513
+ if (!card) return;
514
+ const into = drop && over ? over.dataset.id! : null;
515
+ const fly = (to: HTMLElement | null) => {
516
+ const box = to?.querySelector<HTMLElement>(':scope > [data-mk-tree-row]')?.getBoundingClientRect();
517
+ if (reduced() || !box || !box.width) return card.remove();
518
+ keep(gsap.to(card, { x: box.left + 24, y: box.top + box.height / 2 - 14, scale: 0.4, opacity: 0, duration: 0.32, ease: 'power2.in', onComplete: () => card.remove() }));
519
+ };
520
+ if (!into) return fly(itemOf(id));
521
+ fly(over);
522
+ const node = nodeOf(id)!;
523
+ nodes = moveTreeNode(nodes, id, into);
524
+ expanded.add(into);
525
+ render();
526
+ const target = nodeOf(into)!;
527
+ options.onMove?.(nodeOf(id)!, target);
528
+ root.dispatchEvent(new CustomEvent('mk:move', { bubbles: true, detail: { node, into: target } }));
529
+ };
530
+ scope.on(tree, 'pointerdown', (event) => {
531
+ const down = event as PointerEvent;
532
+ const target = down.target as Element;
533
+ const line = target.closest<HTMLElement>('[data-mk-tree-row]');
534
+ const item = line?.parentElement;
535
+ if (!line || !item || down.button !== 0 || target.closest('[data-mk-tree-chevron], [data-mk-tree-check]') || item.getAttribute('aria-disabled') === 'true') return;
536
+ drag = { id: item.dataset.id!, x: down.clientX, y: down.clientY, pointer: down.pointerId, card: null, over: null, lastX: down.clientX, lastT: performance.now() };
537
+ });
538
+ scope.on(window, 'pointermove', (event) => {
539
+ const move = event as PointerEvent;
540
+ if (!drag || move.pointerId !== drag.pointer) return;
541
+ if (!drag.card) {
542
+ if (Math.hypot(move.clientX - drag.x, move.clientY - drag.y) < 6) return;
543
+ drag.card = lift(drag.id, move.clientX, move.clientY);
544
+ }
545
+ // The card follows and leans with the pointer's speed.
546
+ const now = performance.now();
547
+ const speed = (move.clientX - drag.lastX) / Math.max(1, now - drag.lastT);
548
+ drag.lastX = move.clientX;
549
+ drag.lastT = now;
550
+ gsap.set(drag.card, { x: move.clientX + 14, y: move.clientY + 10 });
551
+ if (!reduced()) keep(gsap.to(drag.card, { rotation: Math.max(-10, Math.min(10, speed * 12)), duration: 0.25, ease: 'power2.out' }));
552
+ const over = branchAt(move.clientX, move.clientY);
553
+ if (over === drag.over) return;
554
+ clearOver();
555
+ if (!over) return;
556
+ drag.over = over;
557
+ over.setAttribute('data-mk-tree-over', '');
558
+ // A closed branch opens after a moment under the card.
559
+ if (over.getAttribute('aria-expanded') === 'false') opening = setTimeout(() => void setOpen(over.dataset.id!, true), 600);
560
+ });
561
+ scope.on(window, 'pointerup', (event) => {
562
+ if (drag && (event as PointerEvent).pointerId === drag.pointer) end(true);
563
+ });
564
+ scope.on(window, 'pointercancel', () => end(false));
565
+ scope.on(document, 'keydown', (event) => {
566
+ if ((event as KeyboardEvent).key === 'Escape' && drag?.card) end(false);
567
+ });
568
+ // A drag is not a click: the row under the pointer keeps its selection.
569
+ scope.on(tree, 'click', (event) => {
570
+ if (drag?.card) event.stopImmediatePropagation();
571
+ }, true);
572
+ scope.add(() => {
573
+ clearTimeout(opening);
574
+ drag?.card?.remove();
575
+ });
576
+ }
577
+
578
+ // ── Pointer and keyboard ─────────────────────────────────────────────────
579
+ scope.on(tree, 'click', (event) => {
580
+ const target = event.target as Element | null;
581
+ const item = target?.closest<HTMLElement>('[role="treeitem"]');
582
+ if (!item || !tree.contains(item) || item.getAttribute('aria-disabled') === 'true') return;
583
+ const id = item.dataset.id!;
584
+ focused = id;
585
+ if (target?.closest('[data-mk-tree-chevron]') && item.hasAttribute('aria-expanded')) {
586
+ void setOpen(id, item.getAttribute('aria-expanded') !== 'true');
587
+ item.focus();
588
+ return;
589
+ }
590
+ if (options.checkable && target?.closest('[data-mk-tree-check]')) check(id);
591
+ else if (options.checkable) check(id);
592
+ else select(id, true);
593
+ item.focus();
594
+ });
595
+ scope.on(tree, 'dblclick', (event) => {
596
+ const item = (event.target as Element | null)?.closest<HTMLElement>('[role="treeitem"]');
597
+ if (item?.hasAttribute('aria-expanded') && !(event.target as Element).closest('[data-mk-tree-chevron]')) void setOpen(item.dataset.id!, item.getAttribute('aria-expanded') !== 'true');
598
+ });
599
+ scope.on(tree, 'focusin', (event) => {
600
+ const item = (event.target as Element | null)?.closest<HTMLElement>('[role="treeitem"]');
601
+ if (!item) return;
602
+ focused = item.dataset.id!;
603
+ roving();
604
+ });
605
+ let typed = '';
606
+ let typedAt = 0;
607
+ scope.on(tree, 'keydown', (event) => {
608
+ const key = event as KeyboardEvent;
609
+ const item = (key.target as Element | null)?.closest<HTMLElement>('[role="treeitem"]');
610
+ if (!item || key.ctrlKey || key.metaKey || key.altKey) return;
611
+ const items = visibleItems();
612
+ const index = items.indexOf(item);
613
+ const id = item.dataset.id!;
614
+ const go = (target: HTMLElement | undefined) => {
615
+ if (!target) return;
616
+ key.preventDefault();
617
+ target.focus();
618
+ target.scrollIntoView?.({ block: 'nearest' });
619
+ };
620
+ switch (key.key) {
621
+ case 'ArrowDown':
622
+ return go(items[index + 1]);
623
+ case 'ArrowUp':
624
+ return go(items[index - 1]);
625
+ case 'Home':
626
+ return go(items[0]);
627
+ case 'End':
628
+ return go(items[items.length - 1]);
629
+ case 'ArrowRight':
630
+ key.preventDefault();
631
+ if (item.getAttribute('aria-expanded') === 'false') void setOpen(id, true);
632
+ else if (item.getAttribute('aria-expanded') === 'true') go(item.querySelector<HTMLElement>(':scope > [role="group"] > [role="treeitem"]:not([hidden])') ?? undefined);
633
+ return;
634
+ case 'ArrowLeft':
635
+ key.preventDefault();
636
+ if (item.getAttribute('aria-expanded') === 'true') void setOpen(id, false);
637
+ else go(item.parentElement?.closest<HTMLElement>('[role="treeitem"]') ?? undefined);
638
+ return;
639
+ case 'Enter':
640
+ key.preventDefault();
641
+ if (options.checkable) check(id);
642
+ else select(id, true);
643
+ return;
644
+ case ' ':
645
+ key.preventDefault();
646
+ if (options.checkable) check(id);
647
+ else select(id, true);
648
+ return;
649
+ case '*': {
650
+ key.preventDefault();
651
+ const siblings = [...(item.parentElement?.children ?? [])].filter((sibling) => sibling.getAttribute('aria-expanded') === 'false') as HTMLElement[];
652
+ for (const sibling of siblings) void setOpen(sibling.dataset.id!, true);
653
+ return;
654
+ }
655
+ }
656
+ // Typing jumps to the next label that starts with what was typed.
657
+ if (key.key.length === 1 && /\S/.test(key.key)) {
658
+ const now = Date.now();
659
+ typed = now - typedAt > 600 ? key.key : typed + key.key;
660
+ typedAt = now;
661
+ const needle = fold(typed);
662
+ const order = [...items.slice(index + (typed.length === 1 ? 1 : 0)), ...items.slice(0, index + (typed.length === 1 ? 1 : 0))];
663
+ const match = order.find((candidate) => fold(nodeOf(candidate.dataset.id!)?.label ?? '').startsWith(needle));
664
+ if (match) go(match);
665
+ }
666
+ });
667
+
668
+ if (typeof ResizeObserver === 'function') {
669
+ let pending: (() => void) | null = null;
670
+ scope.observe(
671
+ new ResizeObserver(() => {
672
+ if (pending) return;
673
+ pending = requestFrame(() => {
674
+ pending = null;
675
+ placePill(false);
676
+ });
677
+ }),
678
+ ).observe(box);
679
+ scope.add(() => pending?.());
680
+ }
681
+
682
+ render();
683
+
684
+ return {
685
+ expand: (id, animate = true) => void setOpen(id, true, animate),
686
+ collapse: (id, animate = true) => void setOpen(id, false, animate),
687
+ toggle: (id) => void setOpen(id, !expanded.has(id)),
688
+ expandAll() {
689
+ walk(nodes, (node) => {
690
+ if (node.children?.length) expanded.add(node.id);
691
+ });
692
+ render();
693
+ },
694
+ collapseAll() {
695
+ expanded.clear();
696
+ render();
697
+ },
698
+ reveal(id) {
699
+ const found = findNode(nodes, id);
700
+ if (!found) return;
701
+ for (const ancestor of found.path.slice(0, -1)) expanded.add(ancestor.id);
702
+ for (const ancestor of found.path.slice(0, -1)) {
703
+ const item = itemOf(ancestor.id);
704
+ if (!item) continue;
705
+ item.setAttribute('aria-expanded', 'true');
706
+ const group = item.querySelector<HTMLElement>(':scope > [role="group"]');
707
+ if (group) group.hidden = false;
708
+ }
709
+ roving();
710
+ placePill(false);
711
+ itemOf(id)?.scrollIntoView?.({ block: 'nearest' });
712
+ },
713
+ select: (id, notify = false) => select(id, notify),
714
+ setChecked(ids) {
715
+ checked = normalised(ids);
716
+ paintChecks(false);
717
+ },
718
+ filter(next) {
719
+ query = next;
720
+ if (searchInput) searchInput.value = next;
721
+ applySearch(true);
722
+ },
723
+ setNodes(next) {
724
+ if (scope.disposed) return;
725
+ nodes = next;
726
+ render();
727
+ },
728
+ focusItem(id) {
729
+ itemOf(id)?.focus();
730
+ },
731
+ get selected() {
732
+ return selected;
733
+ },
734
+ get checked() {
735
+ return [...checked];
736
+ },
737
+ get expanded() {
738
+ return [...expanded];
739
+ },
740
+ element: tree,
741
+ destroy: () => scope.dispose(),
742
+ };
743
+ }