@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,93 @@
1
+ /* heatmap-chart — a week per column of 3 px rounded days, deepening from the track to the accent; needs chart.css.
2
+ The day under the pointer lifts with a ring; the "less … more" scale sits under it, to the right. */
3
+ .mk-heatmap-chart,
4
+ mk-heatmap-chart {
5
+ --mk-heatmap-color: var(--mk-accent);
6
+ --mk-heatmap-empty: var(--mk-surface-2);
7
+ display: grid;
8
+ gap: 0.6rem;
9
+ min-width: 0;
10
+ }
11
+
12
+ [data-mk-heatmap-scroll] {
13
+ overflow-x: auto;
14
+ overflow-y: hidden;
15
+ padding-block: 4px;
16
+ scrollbar-width: thin;
17
+ }
18
+
19
+ [data-mk-chart-type='heatmap'] [data-mk-chart-svg] {
20
+ width: var(--mk-heatmap-width, auto);
21
+ max-width: none;
22
+ overflow: visible;
23
+ cursor: pointer;
24
+ }
25
+
26
+ [data-mk-chart-type='heatmap'] [data-mk-part='cells'] rect {
27
+ transform-box: fill-box;
28
+ transform-origin: center;
29
+ transition:
30
+ fill 0.35s ease,
31
+ opacity 0.2s ease,
32
+ transform 0.3s var(--mk-ease-swatch);
33
+ }
34
+
35
+ [data-mk-chart-type='heatmap'] [data-mk-part='cells'] rect[data-mk-on] {
36
+ stroke: var(--mk-text);
37
+ stroke-width: 1.5;
38
+ transform: scale(1.3);
39
+ }
40
+
41
+ [data-mk-chart-type='heatmap'] [data-mk-part='cells'] rect[data-mk-dim] {
42
+ opacity: 0.25;
43
+ }
44
+
45
+ [data-mk-chart-type='heatmap'] [data-mk-part='months'] text,
46
+ [data-mk-chart-type='heatmap'] [data-mk-part='weekdays'] text {
47
+ font-size: 10px;
48
+ }
49
+
50
+ [data-mk-heatmap-scale] {
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: flex-end;
54
+ gap: 3px;
55
+ color: var(--mk-muted);
56
+ font-size: 0.75rem;
57
+ }
58
+
59
+ [data-mk-heatmap-scale][hidden] {
60
+ display: none;
61
+ }
62
+
63
+ [data-mk-heatmap-scale] span {
64
+ margin-inline: 0.35rem;
65
+ }
66
+
67
+ [data-mk-heatmap-scale] i {
68
+ width: 12px;
69
+ height: 12px;
70
+ border-radius: 3px;
71
+ cursor: pointer;
72
+ transition: transform 0.25s var(--mk-ease-swatch);
73
+ }
74
+
75
+ @media (hover: hover) {
76
+ [data-mk-heatmap-scale] i:hover {
77
+ transform: scale(1.25);
78
+ }
79
+ }
80
+
81
+ @media (prefers-reduced-motion: reduce) {
82
+ [data-mk-chart-type='heatmap'] [data-mk-part='cells'] rect,
83
+ [data-mk-heatmap-scale] i {
84
+ transition: none;
85
+ }
86
+ }
87
+
88
+ @media (forced-colors: active) {
89
+ [data-mk-chart-type='heatmap'] [data-mk-part='cells'] rect {
90
+ stroke: CanvasText;
91
+ stroke-width: 0.5;
92
+ }
93
+ }
@@ -0,0 +1,14 @@
1
+ 'use client';
2
+
3
+ import type { HTMLAttributes } from 'react';
4
+ import { useChart } from '../chart/use-chart';
5
+ import { createHeatmapChart, type HeatmapChartInstance, type HeatmapChartOptions } from './engine';
6
+
7
+ export interface HeatmapChartProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect' | 'children'>, HeatmapChartOptions {
8
+ instanceRef?: { current: HeatmapChartInstance | null };
9
+ }
10
+
11
+ export function HeatmapChart({ data, end, weeks, firstDay, locale, levels, color, unit, label, legend, formatValue, emptyLabel, onSelect, instanceRef, className, ...props }: HeatmapChartProps) {
12
+ const ref = useChart(createHeatmapChart, { data, end, weeks, firstDay, locale, levels, color, unit, label, legend, emptyLabel }, { formatValue, onSelect }, instanceRef);
13
+ return <div {...props} ref={ref} className={['mk-heatmap-chart', className].filter(Boolean).join(' ')} />;
14
+ }
@@ -0,0 +1,13 @@
1
+ # hold-confirm
2
+
3
+ Confirmación por pulsación mantenida sobre el mismo botón: mientras se mantiene (puntero, Espacio o Enter) un relleno lo cruza durante `duration`, el botón se comprime un poco y la etiqueta cambia con blur. Soltar antes devuelve el relleno con resorte. Al completar: rebote de pulsación (curva click de Melonmind), un ✓ que se dibuja, partículas, `onConfirm` / `mk:confirm` y vuelta al inicio tras `resetAfter`.
4
+
5
+ ```html
6
+ <mk-hold-confirm class="mk-hold-confirm"><button>Eliminar cuenta</button></mk-hold-confirm>
7
+ ```
8
+
9
+ `defineElements()`, `createHoldConfirm(root, options)` (root es el botón o lo contiene) o `<HoldConfirm onConfirm={remove}>Eliminar cuenta</HoldConfirm>`.
10
+
11
+ Opciones: `duration=1200` ms, `resetAfter=1800` ms (0 lo deja confirmado), `holdingLabel='Mantén pulsado…'`, `doneLabel='Confirmado'`, `hint='Mantén pulsado para confirmar'` (descripción accesible), `disabled`, `onConfirm()`. API: `reset()`, `confirmed`, `destroy()`. Un clic simple no envía formularios ni actúa. Un estado educado anuncia la confirmación.
12
+
13
+ Variables: `--mk-hold-bg`, `--mk-hold-fg`, `--mk-hold-fill`, `--mk-hold-on-fill` (tonos de error por defecto; `.mk-hold-confirm--neutral` usa superficie y texto). Movimiento reducido: el relleno salta y no hay partículas; la confirmación sigue llegando a su tiempo.
@@ -0,0 +1,24 @@
1
+ import { MkElement, defineElement, type OptionType } from '../../elements/base';
2
+ import { createHoldConfirm, type HoldConfirmInstance } from './engine';
3
+
4
+ /**
5
+ * <mk-hold-confirm class="mk-hold-confirm" duration="1200"><button>Eliminar cuenta</button></mk-hold-confirm>
6
+ * Hold the button (pointer, Space or Enter) to confirm. Emits mk:confirm.
7
+ */
8
+ export class MkHoldConfirmElement extends MkElement<HoldConfirmInstance> {
9
+ static options: Record<string, OptionType> = { duration: 'number', resetAfter: 'number', holdingLabel: 'string', doneLabel: 'string', hint: 'string', disabled: 'boolean' };
10
+
11
+ protected create(options: Record<string, unknown>) {
12
+ return createHoldConfirm(this, options);
13
+ }
14
+
15
+ reset() {
16
+ this.instance?.reset();
17
+ }
18
+
19
+ get confirmed() {
20
+ return this.instance?.confirmed ?? false;
21
+ }
22
+ }
23
+
24
+ export const defineHoldConfirm = () => defineElement('mk-hold-confirm', MkHoldConfirmElement);
@@ -0,0 +1,216 @@
1
+ import { gsap, EASE, registerMotion } from '../../core/gsap';
2
+ import { reduced } from '../../core/reduced';
3
+ import { createScope } from '../../core/scope';
4
+ import { inert, type Instance } from '../../core/types';
5
+ import { burst, press } from '../../motion/micro';
6
+
7
+ /*
8
+ * Hold to confirm: the same button is held (pointer, Space or Enter) while a
9
+ * fill runs across it for `duration`; the button presses in a little and its
10
+ * label changes with a blur. Letting go early springs the fill back. Holding
11
+ * to the end confirms: a press bounce, a check that draws itself, a ring of
12
+ * particles, onConfirm / mk:confirm, and the button returns after `resetAfter`.
13
+ * The hint ("Mantén pulsado para confirmar") is the button's description.
14
+ */
15
+
16
+ export interface HoldConfirmOptions {
17
+ /** Hold time in ms (default 1200). */
18
+ duration?: number;
19
+ /** Back to the start after confirming, in ms (default 1800; 0 keeps it confirmed). */
20
+ resetAfter?: number;
21
+ holdingLabel?: string;
22
+ doneLabel?: string;
23
+ hint?: string;
24
+ disabled?: boolean;
25
+ onConfirm?: () => void;
26
+ }
27
+
28
+ export interface HoldConfirmInstance extends Instance {
29
+ reset(): void;
30
+ readonly confirmed: boolean;
31
+ }
32
+
33
+ const CHECK = '<svg aria-hidden="true" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5" pathLength="1"/></svg>';
34
+ let sequence = 0;
35
+
36
+ export function createHoldConfirm(root: HTMLElement | null, options: HoldConfirmOptions = {}): HoldConfirmInstance {
37
+ const button = root ? ((root.matches('button') ? root : root.querySelector('button')) as HTMLButtonElement | null) : null;
38
+ if (!root || !button) return inert({ reset() {}, confirmed: false });
39
+ registerMotion();
40
+ const scope = createScope();
41
+ const duration = Number.isFinite(options.duration) && options.duration! > 0 ? options.duration! : 1200;
42
+ const resetAfter = Number.isFinite(options.resetAfter) ? Math.max(0, options.resetAfter!) : 1800;
43
+ const made: Element[] = [];
44
+ const add = <T extends Element>(parent: Element, element: T, first = false) => {
45
+ if (first) parent.prepend(element);
46
+ else parent.append(element);
47
+ made.push(element);
48
+ return element;
49
+ };
50
+ scope.add(() => made.forEach((element) => element.remove()));
51
+
52
+ // The label: the authored text, kept in a span that swaps with a blur.
53
+ const authored = [...button.childNodes];
54
+ const label = document.createElement('span');
55
+ label.dataset.mkHoldLabel = '';
56
+ label.append(...authored);
57
+ button.append(label);
58
+ scope.add(() => {
59
+ label.remove();
60
+ button.append(...authored);
61
+ });
62
+ const fill = add(button, document.createElement('span'), true);
63
+ fill.dataset.mkHoldFill = '';
64
+ fill.setAttribute('aria-hidden', 'true');
65
+ const check = add(button, document.createElement('span'));
66
+ check.dataset.mkHoldCheck = '';
67
+ check.innerHTML = CHECK;
68
+ const hint = add(root === button ? button : root, document.createElement('span'));
69
+ hint.className = 'mk-sr-only';
70
+ hint.id = `mk-hold-${++sequence}`;
71
+ hint.textContent = options.hint ?? 'Mantén pulsado para confirmar';
72
+ const live = add(root === button ? button : root, document.createElement('span'));
73
+ live.className = 'mk-sr-only';
74
+ live.setAttribute('role', 'status');
75
+
76
+ scope.attr(button, 'type', button.getAttribute('type') ?? 'button');
77
+ scope.attr(button, 'aria-describedby', [button.getAttribute('aria-describedby'), hint.id].filter(Boolean).join(' '));
78
+ scope.attr(button, 'data-mk-hold', '');
79
+ scope.attr(button, 'style', button.getAttribute('style'));
80
+ if (options.disabled) scope.attr(button, 'disabled', '');
81
+ scope.attr(root, 'data-mk-ready', '');
82
+
83
+ let holding = false;
84
+ let confirmed = false;
85
+ let timer: ReturnType<typeof setTimeout> | undefined;
86
+ let back: ReturnType<typeof setTimeout> | undefined;
87
+ const effects = new Set<gsap.core.Animation>();
88
+ const keep = (animation: gsap.core.Animation | null) => {
89
+ if (!animation) return;
90
+ effects.add(animation);
91
+ // Finished ones leave as new ones arrive: the animation's own onComplete stays untouched.
92
+ for (const effect of effects) if (effect.totalProgress() === 1) effects.delete(effect);
93
+ };
94
+ scope.add(() => {
95
+ clearTimeout(timer);
96
+ clearTimeout(back);
97
+ for (const effect of effects) effect.kill();
98
+ effects.clear();
99
+ gsap.killTweensOf([fill, button, label, check]);
100
+ });
101
+
102
+ /** Show `text`, or the authored content again with null. */
103
+ let showing: string | null = null;
104
+ const write = (text: string | null) => {
105
+ showing = text;
106
+ if (text === null) label.replaceChildren(...authored);
107
+ else label.textContent = text;
108
+ };
109
+ const swap = (text: string | null) => {
110
+ if (showing === text) return;
111
+ if (reduced()) {
112
+ write(text);
113
+ return;
114
+ }
115
+ gsap.killTweensOf(label);
116
+ keep(
117
+ gsap
118
+ .timeline()
119
+ .to(label, { opacity: 0, filter: 'blur(6px)', y: -4, duration: 0.12, ease: 'power2.in' })
120
+ .call(() => write(text))
121
+ .fromTo(label, { opacity: 0, filter: 'blur(6px)', y: 4 }, { opacity: 1, filter: 'blur(0px)', y: 0, duration: 0.25, ease: EASE.pop, clearProps: 'all' }),
122
+ );
123
+ };
124
+
125
+ const setProgress = (value: number, seconds: number, ease: string) => {
126
+ gsap.killTweensOf(fill, 'scaleX');
127
+ if (reduced() || seconds === 0) gsap.set(fill, { scaleX: value });
128
+ else keep(gsap.to(fill, { scaleX: value, duration: seconds, ease }));
129
+ };
130
+
131
+ const start = () => {
132
+ if (holding || confirmed || button.disabled || scope.disposed) return;
133
+ holding = true;
134
+ scope.attr(button, 'data-mk-holding', '');
135
+ swap(options.holdingLabel ?? 'Mantén pulsado…');
136
+ setProgress(1, duration / 1000, 'power1.in');
137
+ if (!reduced()) keep(gsap.to(button, { scale: 0.96, duration: duration / 1000, ease: 'power1.out' }));
138
+ clearTimeout(timer);
139
+ timer = setTimeout(confirm, duration);
140
+ };
141
+
142
+ const cancel = () => {
143
+ if (!holding) return;
144
+ holding = false;
145
+ clearTimeout(timer);
146
+ scope.attr(button, 'data-mk-holding', null);
147
+ swap(null);
148
+ setProgress(0, 0.5, EASE.swatch);
149
+ if (!reduced()) keep(gsap.to(button, { scale: 1, duration: 0.5, ease: EASE.click, clearProps: 'scale,transform' }));
150
+ };
151
+
152
+ const reset = () => {
153
+ if (scope.disposed) return;
154
+ clearTimeout(back);
155
+ confirmed = false;
156
+ holding = false;
157
+ scope.attr(button, 'data-mk-confirmed', null);
158
+ scope.attr(button, 'data-mk-holding', null);
159
+ swap(null);
160
+ setProgress(0, 0.4, 'power2.out');
161
+ };
162
+
163
+ function confirm() {
164
+ if (!holding || scope.disposed) return;
165
+ holding = false;
166
+ confirmed = true;
167
+ scope.attr(button!, 'data-mk-holding', null);
168
+ scope.attr(button!, 'data-mk-confirmed', '');
169
+ setProgress(1, 0, 'none');
170
+ gsap.killTweensOf(button, 'scale');
171
+ gsap.set(button, { clearProps: 'scale,transform' });
172
+ keep(press(button));
173
+ swap(options.doneLabel ?? 'Confirmado');
174
+ const path = check.querySelector('path');
175
+ if (path && !reduced()) keep(gsap.fromTo(path, { strokeDasharray: 1, strokeDashoffset: 1 }, { strokeDashoffset: 0, duration: 0.45, delay: 0.1, ease: 'power2.out' }));
176
+ keep(burst(button, { count: 8, distance: 34, colors: ['currentColor'] }));
177
+ live.textContent = options.doneLabel ?? 'Confirmado';
178
+ options.onConfirm?.();
179
+ root!.dispatchEvent(new CustomEvent('mk:confirm', { bubbles: true }));
180
+ if (resetAfter) back = setTimeout(reset, resetAfter);
181
+ }
182
+
183
+ scope.on(button, 'pointerdown', (event) => {
184
+ const pointer = event as PointerEvent;
185
+ if (pointer.button !== 0) return;
186
+ pointer.preventDefault();
187
+ button.focus({ preventScroll: true });
188
+ start();
189
+ });
190
+ for (const type of ['pointerup', 'pointerleave', 'pointercancel']) scope.on(button, type, cancel);
191
+ scope.on(button, 'keydown', (event) => {
192
+ const key = event as KeyboardEvent;
193
+ if (key.key !== ' ' && key.key !== 'Enter') return;
194
+ key.preventDefault();
195
+ if (!key.repeat) start();
196
+ });
197
+ scope.on(button, 'keyup', (event) => {
198
+ const key = (event as KeyboardEvent).key;
199
+ if (key === ' ' || key === 'Enter') cancel();
200
+ });
201
+ scope.on(button, 'blur', cancel);
202
+ // A plain click (no hold) must not submit a form or act.
203
+ scope.on(button, 'click', (event) => event.preventDefault());
204
+ scope.on(button, 'contextmenu', (event) => {
205
+ if (holding) event.preventDefault();
206
+ });
207
+ gsap.set(fill, { scaleX: 0 });
208
+
209
+ return {
210
+ reset,
211
+ get confirmed() {
212
+ return confirmed;
213
+ },
214
+ destroy: () => scope.dispose(),
215
+ };
216
+ }
@@ -0,0 +1,86 @@
1
+ /* hold-confirm — Melonmind button (64 px pill, surface tones); while held a darker fill runs from the left,
2
+ the button presses in, the label changes; confirmed, a check draws itself. */
3
+ .mk-hold-confirm,
4
+ mk-hold-confirm {
5
+ display: inline-flex;
6
+ }
7
+
8
+ [data-mk-hold] {
9
+ --mk-hold-bg: var(--mk-error-soft);
10
+ --mk-hold-fg: var(--mk-on-error-soft);
11
+ --mk-hold-fill: var(--mk-error);
12
+ --mk-hold-on-fill: var(--mk-on-error);
13
+ position: relative;
14
+ isolation: isolate;
15
+ display: inline-flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ gap: 0.5rem;
19
+ min-height: 3rem;
20
+ min-width: 12rem;
21
+ padding: 0 1.75rem;
22
+ overflow: hidden;
23
+ border: 0;
24
+ border-radius: 64px;
25
+ background: var(--mk-hold-bg);
26
+ color: var(--mk-hold-fg);
27
+ font: inherit;
28
+ font-weight: 500;
29
+ cursor: pointer;
30
+ user-select: none;
31
+ -webkit-user-select: none;
32
+ touch-action: manipulation;
33
+ -webkit-touch-callout: none;
34
+ transition: color 0.2s ease;
35
+ }
36
+
37
+ [data-mk-hold]:focus-visible {
38
+ outline: 2px solid var(--mk-accent);
39
+ outline-offset: 3px;
40
+ }
41
+
42
+ [data-mk-hold]:disabled {
43
+ opacity: 0.5;
44
+ cursor: not-allowed;
45
+ }
46
+
47
+ [data-mk-hold] [data-mk-hold-fill] {
48
+ position: absolute;
49
+ inset: 0;
50
+ z-index: -1;
51
+ border-radius: inherit;
52
+ background: var(--mk-hold-fill);
53
+ transform-origin: left center;
54
+ }
55
+
56
+ [data-mk-hold]:is([data-mk-holding], [data-mk-confirmed]) {
57
+ color: var(--mk-hold-on-fill);
58
+ }
59
+
60
+ [data-mk-hold] [data-mk-hold-label] {
61
+ display: inline-block;
62
+ }
63
+
64
+ [data-mk-hold] [data-mk-hold-check] {
65
+ display: none;
66
+ }
67
+
68
+ [data-mk-hold][data-mk-confirmed] [data-mk-hold-check] {
69
+ display: inline-grid;
70
+ order: -1;
71
+ }
72
+
73
+ /* The neutral variant (Melonmind tonal). */
74
+ .mk-hold-confirm--neutral [data-mk-hold],
75
+ [data-mk-hold].mk-hold-confirm--neutral {
76
+ --mk-hold-bg: var(--mk-surface-3);
77
+ --mk-hold-fg: var(--mk-text);
78
+ --mk-hold-fill: var(--mk-text);
79
+ --mk-hold-on-fill: var(--mk-bg);
80
+ }
81
+
82
+ @media (prefers-reduced-motion: reduce) {
83
+ [data-mk-hold] {
84
+ transition: none;
85
+ }
86
+ }
@@ -0,0 +1,28 @@
1
+ 'use client';
2
+ import { useRef, type ButtonHTMLAttributes, type ReactNode } from 'react';
3
+ import { useIsomorphicLayoutEffect, useLatest } from '../../react/use-recipe';
4
+ import { createHoldConfirm, type HoldConfirmOptions } from './engine';
5
+
6
+ export interface HoldConfirmProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'onClick'>, HoldConfirmOptions {
7
+ children?: ReactNode;
8
+ }
9
+
10
+ /**
11
+ * <HoldConfirm onConfirm={removeAccount}>Eliminar cuenta</HoldConfirm>: hold the button to confirm.
12
+ * The engine moves the label into its own span, so pass plain text or inline content.
13
+ */
14
+ export function HoldConfirm({ duration, resetAfter, holdingLabel, doneLabel, hint, disabled, onConfirm, className, children, ...props }: HoldConfirmProps) {
15
+ const ref = useRef<HTMLSpanElement>(null);
16
+ const confirm = useLatest(onConfirm);
17
+ useIsomorphicLayoutEffect(() => {
18
+ const instance = createHoldConfirm(ref.current, { duration, resetAfter, holdingLabel, doneLabel, hint, disabled, onConfirm: () => confirm.current?.() });
19
+ return () => instance.destroy();
20
+ }, [duration, resetAfter, holdingLabel, doneLabel, hint, disabled]);
21
+ return (
22
+ <span ref={ref} className={['mk-hold-confirm', className].filter(Boolean).join(' ')}>
23
+ <button type="button" {...props}>
24
+ <span data-mk-hold-text="">{children}</span>
25
+ </button>
26
+ </span>
27
+ );
28
+ }
@@ -11,6 +11,10 @@ Vista previa no modal, accesible al señalar, enfocar o tocar. Los enlaces/boton
11
11
 
12
12
  `defineElements()`, `createHoverCard(root, options)`, o `<HoverCard trigger="Ver estudio" placement="bottom">Contenido</HoverCard>`.
13
13
 
14
- Opciones: `openDelay=120` ms, `closeDelay=140` ms, `placement='top'|'bottom'`, `onOpenChange(boolean)`. API `open()`, `close()`, `isOpen`, `destroy()`. Evento `mk:open-change` con `{open}`.
14
+ Opciones: `openDelay=120` ms, `closeDelay=140` ms, `placement='top'|'bottom'` (lado preferido), `onOpenChange(boolean)`. API `open()`, `close()`, `reposition()`, `isOpen`, `destroy()`. Evento `mk:open-change` con `{open}`.
15
15
 
16
- Escape cierra y retorna al disparador; salir con foco y puntero fuera o tocar fuera cierra. El panel se posiciona respecto al root: mantener un ancestro que permita overflow; no crea portal. No atrapa el foco. Entrada .28 s, instantánea bajo movimiento reducido. Limpia timers y restaura todos los atributos.
16
+ Escape cierra y retorna al disparador; salir con foco y puntero fuera o tocar fuera cierra. El puntero puede pasar del disparador al panel sin cerrarlo y el panel admite foco en su contenido. No atrapa el foco.
17
+
18
+ El panel se posiciona respecto al root (sin portal: mantener un ancestro que permita overflow) y no se sale del viewport: si su lado no tiene sitio pasa al otro (`data-mk-side`) y se desplaza en horizontal lejos de los bordes (`--mk-hover-shift`); vuelve a colocarse con scroll y resize mientras está abierto. El panel es cristal inverso (`--mk-glass-inverse`, radio de 24px) y entra con un pop de .3 s desde el blur al señalar o tocar; abierto desde teclado (`data-mk-input="keyboard"`) aparece sin entrada, igual que con movimiento reducido. Limpia timers, listeners y frames y restaura todos los atributos.
19
+
20
+ [link-preview](../link-preview/README.md) lo compone para previsualizar enlaces.
@@ -1,61 +1,144 @@
1
+ import { requestFrame } from '../../core/frame';
2
+ import { reduced } from '../../core/reduced';
1
3
  import { createScope } from '../../core/scope';
2
4
  import { inert, type Instance } from '../../core/types';
3
5
 
4
6
  export interface HoverCardOptions {
5
7
  openDelay?: number;
6
8
  closeDelay?: number;
9
+ /** Preferred side; it flips when the viewport has no room there. */
7
10
  placement?: 'top' | 'bottom';
8
11
  onOpenChange?: (open: boolean) => void;
9
12
  }
10
13
  export interface HoverCardInstance extends Instance {
11
14
  open(): void;
12
15
  close(): void;
16
+ /** Place the open panel again (after its content changed size). */
17
+ reposition(): void;
13
18
  readonly isOpen: boolean;
14
19
  }
15
20
  let sequence = 0;
21
+ /** Distance kept from the viewport edges. */
22
+ const EDGE = 12;
23
+ const GAP = 12;
24
+ /** Longest fold back into the trigger (the CSS one is .22 s); then it hides anyway. */
25
+ const FOLD_MS = 400;
16
26
 
17
- /** Nonmodal preview: pointer, keyboard focus and tap all reveal the same panel. */
27
+ /**
28
+ * Nonmodal preview: pointer, keyboard focus and tap all reveal the same panel.
29
+ * The panel stays inside the viewport: it flips to the other side when its own
30
+ * has no room and shifts sideways (--mk-hover-shift) away from the edges, again
31
+ * on scroll and resize. Opened from the keyboard it appears without the entrance.
32
+ * It grows out of the trigger's centre (--mk-hover-origin-x) and, when the
33
+ * pointer leaves, folds back into it (data-mk-closing, .22 s) before hiding.
34
+ */
18
35
  export function createHoverCard(root: HTMLElement | null, options: HoverCardOptions = {}): HoverCardInstance {
19
36
  const trigger = root?.querySelector<HTMLElement>('[data-mk-hover-trigger]');
20
37
  const panel = root?.querySelector<HTMLElement>('[data-mk-hover-panel]');
21
- if (!root || !trigger || !panel) return inert({ open() {}, close() {}, isOpen: false });
38
+ if (!root || !trigger || !panel) return inert({ open() {}, close() {}, reposition() {}, isOpen: false });
22
39
  const scope = createScope();
23
40
  const openDelay = Number.isFinite(options.openDelay) ? Math.max(0, options.openDelay!) : 120;
24
41
  const closeDelay = Number.isFinite(options.closeDelay) ? Math.max(0, options.closeDelay!) : 140;
42
+ const preferred = options.placement ?? 'top';
25
43
  let opened = false;
26
44
  let timer: ReturnType<typeof setTimeout> | undefined;
27
45
  let pointerInside = false;
46
+ /** The last input was a pointer (focus that follows a click is not keyboard). */
47
+ let pointerInput = false;
28
48
  let id = panel.id;
29
49
  if (!id) { do { id = `mk-hover-${++sequence}`; } while (document.getElementById(id)); }
30
50
  scope.attr(panel, 'id', id);
31
51
  scope.attr(trigger, 'aria-controls', id);
32
- scope.attr(root, 'data-mk-placement', options.placement ?? 'top');
52
+ scope.attr(root, 'data-mk-placement', preferred);
53
+ scope.attr(root, 'data-mk-side', preferred);
54
+ scope.attr(root, 'style', root.getAttribute('style'));
33
55
  scope.attr(root, 'data-mk-ready', '');
56
+
57
+ const place = () => {
58
+ if (!opened || scope.disposed) return;
59
+ root.style.removeProperty('--mk-hover-shift');
60
+ const anchor = root.getBoundingClientRect();
61
+ const box = panel.getBoundingClientRect();
62
+ const view = { width: innerWidth, height: innerHeight };
63
+ const need = box.height + GAP + EDGE;
64
+ const above = anchor.top;
65
+ const below = view.height - anchor.bottom;
66
+ let side = preferred;
67
+ if (preferred === 'top' && above < need && below > above) side = 'bottom';
68
+ if (preferred === 'bottom' && below < need && above > below) side = 'top';
69
+ scope.attr(root, 'data-mk-side', side);
70
+ // The panel starts at the root's left edge; move it back inside the viewport.
71
+ const left = anchor.left;
72
+ let shift = 0;
73
+ if (left + box.width > view.width - EDGE) shift = view.width - EDGE - box.width - left;
74
+ if (left + shift < EDGE) shift = EDGE - left;
75
+ if (shift) root.style.setProperty('--mk-hover-shift', `${Math.round(shift)}px`);
76
+ // The panel grows from (and folds back into) the trigger's centre.
77
+ const target = trigger.getBoundingClientRect();
78
+ root.style.setProperty('--mk-hover-origin-x', `${Math.round(target.left + target.width / 2 - (left + shift))}px`);
79
+ };
80
+ let pending: (() => void) | null = null;
81
+ const schedulePlace = () => {
82
+ if (!opened || pending) return;
83
+ pending = requestFrame(() => {
84
+ pending = null;
85
+ place();
86
+ });
87
+ };
88
+ scope.add(() => pending?.());
89
+
34
90
  const cancel = () => { clearTimeout(timer); timer = undefined; };
91
+ // The fold back into the trigger: the panel stays until its animation ends (or FOLD_MS passes).
92
+ let folding: ReturnType<typeof setTimeout> | undefined;
93
+ const settleFold = () => {
94
+ clearTimeout(folding);
95
+ folding = undefined;
96
+ panel.removeEventListener('animationend', settleFold);
97
+ if (scope.disposed) return;
98
+ scope.attr(root, 'data-mk-closing', null);
99
+ if (!opened) scope.attr(panel, 'hidden', '');
100
+ };
101
+ scope.add(() => {
102
+ clearTimeout(folding);
103
+ panel.removeEventListener('animationend', settleFold);
104
+ });
35
105
  const set = (value: boolean) => {
36
106
  cancel();
37
107
  if (scope.disposed) return;
38
108
  const changed = value !== opened;
39
109
  opened = value;
40
110
  scope.attr(trigger, 'aria-expanded', String(value));
41
- scope.attr(panel, 'hidden', value ? null : '');
111
+ if (value) {
112
+ if (folding !== undefined) settleFold();
113
+ scope.attr(panel, 'hidden', null);
114
+ } else if (changed && !reduced() && root.dataset.mkInput !== 'keyboard' && !panel.hidden) {
115
+ scope.attr(root, 'data-mk-closing', '');
116
+ panel.addEventListener('animationend', settleFold);
117
+ folding = setTimeout(settleFold, FOLD_MS);
118
+ } else if (folding === undefined) scope.attr(panel, 'hidden', '');
42
119
  scope.attr(root, 'data-mk-open', value ? '' : null);
120
+ if (value && changed) {
121
+ scope.attr(root, 'data-mk-input', pointerInput ? 'pointer' : 'keyboard');
122
+ place();
123
+ }
43
124
  if (changed) {
44
125
  options.onOpenChange?.(value);
45
126
  root.dispatchEvent(new CustomEvent('mk:open-change', { bubbles: true, detail: { open: value } }));
46
127
  }
47
128
  };
48
129
  const schedule = (value: boolean, delay: number) => { cancel(); timer = setTimeout(() => set(value), delay); };
49
- scope.on(root, 'pointerenter', () => { pointerInside = true; schedule(true, openDelay); });
130
+ scope.on(root, 'pointerenter', () => { pointerInside = true; pointerInput = true; schedule(true, openDelay); });
50
131
  scope.on(root, 'pointerleave', () => {
51
132
  pointerInside = false;
52
133
  if (!root.contains(document.activeElement)) schedule(false, closeDelay);
53
134
  });
135
+ scope.on(root, 'pointerdown', () => { pointerInput = true; });
136
+ scope.on(document, 'keydown', () => { pointerInput = false; }, true);
54
137
  scope.on(root, 'focusin', () => set(true));
55
138
  scope.on(root, 'focusout', (event) => {
56
139
  if (!pointerInside && !root.contains((event as FocusEvent).relatedTarget as Node | null)) schedule(false, closeDelay);
57
140
  });
58
- scope.on(trigger, 'click', () => set(true));
141
+ scope.on(trigger, 'click', () => { pointerInput = true; set(true); });
59
142
  scope.on(document, 'pointerdown', (event) => { if (!root.contains(event.target as Node)) set(false); });
60
143
  scope.on(root, 'keydown', (event) => {
61
144
  if (event.key !== 'Escape' || !opened) return;
@@ -63,7 +146,15 @@ export function createHoverCard(root: HTMLElement | null, options: HoverCardOpti
63
146
  trigger.focus();
64
147
  set(false);
65
148
  });
149
+ scope.on(window, 'resize', schedulePlace);
150
+ scope.on(window, 'scroll', schedulePlace, { capture: true, passive: true });
66
151
  scope.add(cancel);
67
152
  set(false);
68
- return { open: () => set(true), close: () => set(false), get isOpen() { return opened; }, destroy: () => scope.dispose() };
153
+ return {
154
+ open: () => set(true),
155
+ close: () => set(false),
156
+ reposition: place,
157
+ get isOpen() { return opened; },
158
+ destroy: () => scope.dispose(),
159
+ };
69
160
  }