@yewdiel21/motion-kit 0.9.1 → 0.14.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 (458) hide show
  1. package/README.md +72 -0
  2. package/dist/auto/index.d.ts +72 -3
  3. package/dist/auto/index.js +139 -3
  4. package/dist/auto/index.js.map +1 -1
  5. package/dist/{chunk-BFC27F2G.js → chunk-6P4P7NU6.js} +2 -218
  6. package/dist/chunk-6P4P7NU6.js.map +1 -0
  7. package/dist/chunk-CU6SXW3E.js +20334 -0
  8. package/dist/chunk-CU6SXW3E.js.map +1 -0
  9. package/dist/{chunk-XDWBVFHQ.js → chunk-EY4BJKC4.js} +1203 -29
  10. package/dist/chunk-EY4BJKC4.js.map +1 -0
  11. package/dist/chunk-QP4QJOEN.js +72 -0
  12. package/dist/chunk-QP4QJOEN.js.map +1 -0
  13. package/dist/css/components/activity-feed.css +240 -0
  14. package/dist/css/components/attachment.css +266 -0
  15. package/dist/css/components/breadcrumb.css +110 -0
  16. package/dist/css/components/calendar.css +159 -0
  17. package/dist/css/components/chart-tooltip.css +168 -0
  18. package/dist/css/components/chart.css +296 -0
  19. package/dist/css/components/code-block.css +264 -0
  20. package/dist/css/components/color-area.css +82 -0
  21. package/dist/css/components/color-field.css +67 -0
  22. package/dist/css/components/color-picker.css +131 -0
  23. package/dist/css/components/color-slider.css +113 -0
  24. package/dist/css/components/command-search.css +252 -0
  25. package/dist/css/components/context-menu.css +23 -0
  26. package/dist/css/components/credit-card.css +288 -0
  27. package/dist/css/components/data-table.css +591 -0
  28. package/dist/css/components/date-range-picker.css +168 -0
  29. package/dist/css/components/date-time-picker.css +178 -0
  30. package/dist/css/components/drawer.css +58 -0
  31. package/dist/css/components/editable-table.css +201 -0
  32. package/dist/css/components/empty-state.css +61 -0
  33. package/dist/css/components/file-explorer.css +633 -0
  34. package/dist/css/components/filter-builder.css +232 -0
  35. package/dist/css/components/hold-confirm.css +87 -0
  36. package/dist/css/components/hover-card.css +20 -0
  37. package/dist/css/components/image-preview.css +195 -0
  38. package/dist/css/components/input-otp.css +10 -0
  39. package/dist/css/components/json-viewer.css +272 -0
  40. package/dist/css/components/like-button.css +78 -0
  41. package/dist/css/components/link-preview.css +275 -0
  42. package/dist/css/components/loading-button.css +77 -0
  43. package/dist/css/components/multi-select.css +267 -0
  44. package/dist/css/components/notification-bell.css +127 -0
  45. package/dist/css/components/pagination.css +11 -0
  46. package/dist/css/components/password-strength.css +183 -0
  47. package/dist/css/components/popover.css +25 -0
  48. package/dist/css/components/progress.css +140 -0
  49. package/dist/css/components/quantity.css +16 -0
  50. package/dist/css/components/questionnaire.css +217 -0
  51. package/dist/css/components/range-calendar.css +186 -0
  52. package/dist/css/components/range-slider.css +192 -0
  53. package/dist/css/components/resizable-panel.css +243 -0
  54. package/dist/css/components/rich-text-editor.css +284 -0
  55. package/dist/css/components/scratch-card.css +75 -0
  56. package/dist/css/components/skeleton.css +108 -0
  57. package/dist/css/components/slot-picker.css +126 -0
  58. package/dist/css/components/split-view.css +19 -0
  59. package/dist/css/components/star-rating.css +80 -0
  60. package/dist/css/components/stat-card.css +164 -0
  61. package/dist/css/components/studio-dock.css +35 -0
  62. package/dist/css/components/swipe-actions.css +105 -0
  63. package/dist/css/components/tag-input.css +244 -0
  64. package/dist/css/components/time-field.css +88 -0
  65. package/dist/css/components/timeline.css +219 -0
  66. package/dist/css/components/tooltip.css +79 -0
  67. package/dist/css/components/trailer.css +37 -0
  68. package/dist/css/components/tree-view.css +210 -0
  69. package/dist/css/components/virtual-list.css +195 -0
  70. package/dist/css/controls.css +65 -0
  71. package/dist/css/tokens.css +185 -181
  72. package/dist/elements/index.d.ts +742 -5
  73. package/dist/elements/index.js +1527 -8
  74. package/dist/elements/index.js.map +1 -1
  75. package/dist/{engine-GDGwQnJE.d.ts → engine-Cn6IhE3z.d.ts} +1 -1
  76. package/dist/engine-QECQnGz1.d.ts +33 -0
  77. package/dist/index.css +10113 -181
  78. package/dist/index.d.ts +89 -5
  79. package/dist/index.js +285 -9
  80. package/dist/index.js.map +1 -1
  81. package/dist/react/index.d.ts +678 -23
  82. package/dist/react/index.js +2389 -7
  83. package/dist/react/index.js.map +1 -1
  84. package/dist/{reduced-B98f8LPs.d.ts → reduced-BBUusld6.d.ts} +206 -2
  85. package/dist/reveal-DEvp6U6T.d.ts +2381 -0
  86. package/dist/{store-pHiUvxP8.d.ts → store-DjkTBX7f.d.ts} +2 -2
  87. package/package.json +1 -1
  88. package/registry.json +583 -104
  89. package/skills/motion-kit/SKILL.md +209 -189
  90. package/src/auto/auto-init.ts +136 -0
  91. package/src/components/activity-feed/README.md +56 -0
  92. package/src/components/activity-feed/activity-feed.css +239 -0
  93. package/src/components/activity-feed/element.ts +36 -0
  94. package/src/components/activity-feed/engine.ts +351 -0
  95. package/src/components/activity-feed/react.tsx +32 -0
  96. package/src/components/attachment/README.md +27 -0
  97. package/src/components/attachment/attachment.css +265 -0
  98. package/src/components/attachment/element.ts +50 -0
  99. package/src/components/attachment/engine.ts +469 -0
  100. package/src/components/attachment/react.tsx +65 -0
  101. package/src/components/breadcrumb/README.md +38 -0
  102. package/src/components/breadcrumb/breadcrumb.css +109 -0
  103. package/src/components/breadcrumb/element.ts +27 -0
  104. package/src/components/breadcrumb/engine.ts +249 -0
  105. package/src/components/breadcrumb/react.tsx +30 -0
  106. package/src/components/calendar/README.md +82 -0
  107. package/src/components/calendar/calendar.css +158 -0
  108. package/src/components/calendar/element.ts +27 -0
  109. package/src/components/calendar/engine.ts +412 -0
  110. package/src/components/calendar/react.tsx +69 -0
  111. package/src/components/chart/README.md +24 -0
  112. package/src/components/chart/chart.css +295 -0
  113. package/src/components/chart/element.ts +41 -0
  114. package/src/components/chart/engine.ts +811 -0
  115. package/src/components/chart/react.tsx +50 -0
  116. package/src/components/chart-tooltip/README.md +53 -0
  117. package/src/components/chart-tooltip/chart-tooltip.css +167 -0
  118. package/src/components/chart-tooltip/element.ts +37 -0
  119. package/src/components/chart-tooltip/engine.ts +442 -0
  120. package/src/components/chart-tooltip/react.tsx +47 -0
  121. package/src/components/code-block/README.md +19 -0
  122. package/src/components/code-block/code-block.css +263 -0
  123. package/src/components/code-block/element.ts +34 -0
  124. package/src/components/code-block/engine.ts +254 -0
  125. package/src/components/code-block/highlight.ts +244 -0
  126. package/src/components/code-block/react.tsx +94 -0
  127. package/src/components/color-area/README.md +50 -0
  128. package/src/components/color-area/color-area.css +81 -0
  129. package/src/components/color-area/element.ts +26 -0
  130. package/src/components/color-area/engine.ts +246 -0
  131. package/src/components/color-area/react.tsx +42 -0
  132. package/src/components/color-field/README.md +43 -0
  133. package/src/components/color-field/color-field.css +66 -0
  134. package/src/components/color-field/element.ts +26 -0
  135. package/src/components/color-field/engine.ts +174 -0
  136. package/src/components/color-field/react.tsx +42 -0
  137. package/src/components/color-picker/README.md +45 -0
  138. package/src/components/color-picker/color-picker.css +130 -0
  139. package/src/components/color-picker/element.ts +45 -0
  140. package/src/components/color-picker/engine.ts +314 -0
  141. package/src/components/color-picker/react.tsx +47 -0
  142. package/src/components/color-slider/README.md +55 -0
  143. package/src/components/color-slider/color-slider.css +112 -0
  144. package/src/components/color-slider/element.ts +26 -0
  145. package/src/components/color-slider/engine.ts +234 -0
  146. package/src/components/color-slider/react.tsx +45 -0
  147. package/src/components/command-search/README.md +15 -0
  148. package/src/components/command-search/command-search.css +251 -0
  149. package/src/components/command-search/element.ts +36 -0
  150. package/src/components/command-search/engine.ts +356 -0
  151. package/src/components/command-search/match.ts +53 -0
  152. package/src/components/command-search/react.tsx +66 -0
  153. package/src/components/context-menu/README.md +31 -0
  154. package/src/components/context-menu/context-menu.css +22 -0
  155. package/src/components/context-menu/element.ts +40 -0
  156. package/src/components/context-menu/engine.ts +153 -0
  157. package/src/components/context-menu/react.tsx +57 -0
  158. package/src/components/credit-card/README.md +20 -0
  159. package/src/components/credit-card/card.ts +77 -0
  160. package/src/components/credit-card/credit-card.css +287 -0
  161. package/src/components/credit-card/element.ts +33 -0
  162. package/src/components/credit-card/engine.ts +410 -0
  163. package/src/components/credit-card/react.tsx +36 -0
  164. package/src/components/data-table/README.md +83 -0
  165. package/src/components/data-table/data-table.css +590 -0
  166. package/src/components/data-table/element.ts +54 -0
  167. package/src/components/data-table/engine.ts +1059 -0
  168. package/src/components/data-table/react.tsx +94 -0
  169. package/src/components/date-range-picker/README.md +51 -0
  170. package/src/components/date-range-picker/date-range-picker.css +167 -0
  171. package/src/components/date-range-picker/element.ts +52 -0
  172. package/src/components/date-range-picker/engine.ts +352 -0
  173. package/src/components/date-range-picker/react.tsx +57 -0
  174. package/src/components/date-time-picker/README.md +48 -0
  175. package/src/components/date-time-picker/date-time-picker.css +177 -0
  176. package/src/components/date-time-picker/element.ts +47 -0
  177. package/src/components/date-time-picker/engine.ts +350 -0
  178. package/src/components/date-time-picker/react.tsx +54 -0
  179. package/src/components/dialog/README.md +103 -102
  180. package/src/components/dialog/element.ts +123 -118
  181. package/src/components/dialog/engine.ts +449 -432
  182. package/src/components/drawer/README.md +28 -0
  183. package/src/components/drawer/drawer.css +57 -0
  184. package/src/components/drawer/element.ts +21 -0
  185. package/src/components/drawer/engine.ts +56 -0
  186. package/src/components/drawer/react.tsx +85 -0
  187. package/src/components/editable-table/README.md +67 -0
  188. package/src/components/editable-table/editable-table.css +200 -0
  189. package/src/components/editable-table/element.ts +45 -0
  190. package/src/components/editable-table/engine.ts +775 -0
  191. package/src/components/editable-table/react.tsx +79 -0
  192. package/src/components/empty-state/README.md +41 -0
  193. package/src/components/empty-state/element.ts +23 -0
  194. package/src/components/empty-state/empty-state.css +60 -0
  195. package/src/components/empty-state/engine.ts +232 -0
  196. package/src/components/empty-state/react.tsx +34 -0
  197. package/src/components/file-explorer/README.md +67 -0
  198. package/src/components/file-explorer/element.ts +39 -0
  199. package/src/components/file-explorer/engine.ts +1307 -0
  200. package/src/components/file-explorer/file-explorer.css +632 -0
  201. package/src/components/file-explorer/react.tsx +77 -0
  202. package/src/components/filter-builder/README.md +47 -0
  203. package/src/components/filter-builder/element.ts +34 -0
  204. package/src/components/filter-builder/engine.ts +365 -0
  205. package/src/components/filter-builder/filter-builder.css +231 -0
  206. package/src/components/filter-builder/react.tsx +36 -0
  207. package/src/components/hold-confirm/README.md +13 -0
  208. package/src/components/hold-confirm/element.ts +24 -0
  209. package/src/components/hold-confirm/engine.ts +216 -0
  210. package/src/components/hold-confirm/hold-confirm.css +86 -0
  211. package/src/components/hold-confirm/react.tsx +28 -0
  212. package/src/components/hover-card/README.md +20 -0
  213. package/src/components/hover-card/element.ts +8 -0
  214. package/src/components/hover-card/engine.ts +131 -0
  215. package/src/components/hover-card/hover-card.css +19 -0
  216. package/src/components/hover-card/react.tsx +19 -0
  217. package/src/components/image-preview/README.md +16 -0
  218. package/src/components/image-preview/element.ts +26 -0
  219. package/src/components/image-preview/engine.ts +325 -0
  220. package/src/components/image-preview/image-preview.css +194 -0
  221. package/src/components/image-preview/react.tsx +43 -0
  222. package/src/components/input-otp/README.md +18 -0
  223. package/src/components/input-otp/element.ts +14 -0
  224. package/src/components/input-otp/engine.ts +106 -0
  225. package/src/components/input-otp/input-otp.css +9 -0
  226. package/src/components/input-otp/react.tsx +21 -0
  227. package/src/components/json-viewer/README.md +56 -0
  228. package/src/components/json-viewer/element.ts +37 -0
  229. package/src/components/json-viewer/engine.ts +440 -0
  230. package/src/components/json-viewer/json-viewer.css +271 -0
  231. package/src/components/json-viewer/react.tsx +56 -0
  232. package/src/components/like-button/README.md +13 -0
  233. package/src/components/like-button/element.ts +47 -0
  234. package/src/components/like-button/engine.ts +145 -0
  235. package/src/components/like-button/like-button.css +77 -0
  236. package/src/components/like-button/react.tsx +39 -0
  237. package/src/components/link-preview/README.md +19 -0
  238. package/src/components/link-preview/element.ts +29 -0
  239. package/src/components/link-preview/engine.ts +192 -0
  240. package/src/components/link-preview/link-preview.css +274 -0
  241. package/src/components/link-preview/react.tsx +101 -0
  242. package/src/components/loading-button/README.md +45 -0
  243. package/src/components/loading-button/element.ts +34 -0
  244. package/src/components/loading-button/engine.ts +201 -0
  245. package/src/components/loading-button/loading-button.css +76 -0
  246. package/src/components/loading-button/react.tsx +43 -0
  247. package/src/components/multi-select/README.md +48 -0
  248. package/src/components/multi-select/element.ts +28 -0
  249. package/src/components/multi-select/engine.ts +294 -0
  250. package/src/components/multi-select/multi-select.css +266 -0
  251. package/src/components/multi-select/react.tsx +39 -0
  252. package/src/components/notification-bell/README.md +14 -0
  253. package/src/components/notification-bell/element.ts +48 -0
  254. package/src/components/notification-bell/engine.ts +202 -0
  255. package/src/components/notification-bell/notification-bell.css +126 -0
  256. package/src/components/notification-bell/react.tsx +57 -0
  257. package/src/components/pagination/README.md +17 -0
  258. package/src/components/pagination/element.ts +14 -0
  259. package/src/components/pagination/engine.ts +102 -0
  260. package/src/components/pagination/pagination.css +10 -0
  261. package/src/components/pagination/react.tsx +22 -0
  262. package/src/components/password-strength/README.md +17 -0
  263. package/src/components/password-strength/element.ts +22 -0
  264. package/src/components/password-strength/engine.ts +212 -0
  265. package/src/components/password-strength/password-strength.css +182 -0
  266. package/src/components/password-strength/react.tsx +36 -0
  267. package/src/components/password-strength/score.ts +62 -0
  268. package/src/components/popover/README.md +44 -0
  269. package/src/components/popover/element.ts +31 -0
  270. package/src/components/popover/engine.ts +114 -0
  271. package/src/components/popover/popover.css +24 -0
  272. package/src/components/popover/react.tsx +50 -0
  273. package/src/components/progress/README.md +17 -0
  274. package/src/components/progress/element.ts +30 -0
  275. package/src/components/progress/engine.ts +173 -0
  276. package/src/components/progress/progress.css +139 -0
  277. package/src/components/progress/react.tsx +35 -0
  278. package/src/components/quantity/README.md +20 -0
  279. package/src/components/quantity/element.ts +14 -0
  280. package/src/components/quantity/engine.ts +85 -0
  281. package/src/components/quantity/quantity.css +15 -0
  282. package/src/components/quantity/react.tsx +21 -0
  283. package/src/components/questionnaire/README.md +32 -0
  284. package/src/components/questionnaire/element.ts +118 -0
  285. package/src/components/questionnaire/engine.ts +255 -0
  286. package/src/components/questionnaire/questionnaire.css +216 -0
  287. package/src/components/questionnaire/react.tsx +140 -0
  288. package/src/components/range-calendar/README.md +58 -0
  289. package/src/components/range-calendar/element.ts +42 -0
  290. package/src/components/range-calendar/engine.ts +390 -0
  291. package/src/components/range-calendar/range-calendar.css +185 -0
  292. package/src/components/range-calendar/react.tsx +56 -0
  293. package/src/components/range-slider/README.md +23 -0
  294. package/src/components/range-slider/element.ts +53 -0
  295. package/src/components/range-slider/engine.ts +316 -0
  296. package/src/components/range-slider/range-slider.css +191 -0
  297. package/src/components/range-slider/react.tsx +66 -0
  298. package/src/components/resizable-panel/README.md +61 -0
  299. package/src/components/resizable-panel/element.ts +36 -0
  300. package/src/components/resizable-panel/engine.ts +551 -0
  301. package/src/components/resizable-panel/react.tsx +74 -0
  302. package/src/components/resizable-panel/resizable-panel.css +242 -0
  303. package/src/components/rich-text-editor/README.md +57 -0
  304. package/src/components/rich-text-editor/element.ts +34 -0
  305. package/src/components/rich-text-editor/engine.ts +673 -0
  306. package/src/components/rich-text-editor/react.tsx +60 -0
  307. package/src/components/rich-text-editor/rich-text-editor.css +283 -0
  308. package/src/components/scratch-card/README.md +15 -0
  309. package/src/components/scratch-card/element.ts +30 -0
  310. package/src/components/scratch-card/engine.ts +257 -0
  311. package/src/components/scratch-card/react.tsx +40 -0
  312. package/src/components/scratch-card/scratch-card.css +74 -0
  313. package/src/components/skeleton/README.md +15 -0
  314. package/src/components/skeleton/element.ts +32 -0
  315. package/src/components/skeleton/engine.ts +104 -0
  316. package/src/components/skeleton/react.tsx +41 -0
  317. package/src/components/skeleton/skeleton.css +107 -0
  318. package/src/components/slot-picker/README.md +68 -0
  319. package/src/components/slot-picker/element.ts +27 -0
  320. package/src/components/slot-picker/engine.ts +412 -0
  321. package/src/components/slot-picker/react.tsx +76 -0
  322. package/src/components/slot-picker/slot-picker.css +125 -0
  323. package/src/components/split-view/README.md +50 -0
  324. package/src/components/split-view/element.ts +34 -0
  325. package/src/components/split-view/engine.ts +114 -0
  326. package/src/components/split-view/react.tsx +63 -0
  327. package/src/components/split-view/split-view.css +18 -0
  328. package/src/components/star-rating/README.md +14 -0
  329. package/src/components/star-rating/element.ts +26 -0
  330. package/src/components/star-rating/engine.ts +217 -0
  331. package/src/components/star-rating/react.tsx +33 -0
  332. package/src/components/star-rating/star-rating.css +79 -0
  333. package/src/components/stat-card/README.md +42 -0
  334. package/src/components/stat-card/element.ts +40 -0
  335. package/src/components/stat-card/engine.ts +283 -0
  336. package/src/components/stat-card/react.tsx +36 -0
  337. package/src/components/stat-card/stat-card.css +163 -0
  338. package/src/components/studio-dock/README.md +44 -0
  339. package/src/components/studio-dock/element.ts +11 -0
  340. package/src/components/studio-dock/engine.ts +212 -0
  341. package/src/components/studio-dock/react.tsx +23 -0
  342. package/src/components/studio-dock/studio-dock.css +34 -0
  343. package/src/components/swipe-actions/README.md +19 -0
  344. package/src/components/swipe-actions/element.ts +26 -0
  345. package/src/components/swipe-actions/engine.ts +260 -0
  346. package/src/components/swipe-actions/react.tsx +80 -0
  347. package/src/components/swipe-actions/swipe-actions.css +104 -0
  348. package/src/components/tag-input/README.md +42 -0
  349. package/src/components/tag-input/element.ts +39 -0
  350. package/src/components/tag-input/engine.ts +313 -0
  351. package/src/components/tag-input/react.tsx +54 -0
  352. package/src/components/tag-input/tag-input.css +243 -0
  353. package/src/components/time-field/README.md +54 -0
  354. package/src/components/time-field/element.ts +38 -0
  355. package/src/components/time-field/engine.ts +110 -0
  356. package/src/components/time-field/react.tsx +45 -0
  357. package/src/components/time-field/time-field.css +87 -0
  358. package/src/components/timeline/README.md +57 -0
  359. package/src/components/timeline/element.ts +31 -0
  360. package/src/components/timeline/engine.ts +300 -0
  361. package/src/components/timeline/react.tsx +59 -0
  362. package/src/components/timeline/timeline.css +218 -0
  363. package/src/components/tooltip/README.md +46 -0
  364. package/src/components/tooltip/element.ts +22 -0
  365. package/src/components/tooltip/engine.ts +288 -0
  366. package/src/components/tooltip/react.tsx +30 -0
  367. package/src/components/tooltip/tooltip.css +78 -0
  368. package/src/components/trailer/README.md +28 -0
  369. package/src/components/trailer/element.ts +13 -0
  370. package/src/components/trailer/engine.ts +189 -0
  371. package/src/components/trailer/react.tsx +16 -0
  372. package/src/components/trailer/trailer.css +36 -0
  373. package/src/components/tree-view/README.md +61 -0
  374. package/src/components/tree-view/element.ts +32 -0
  375. package/src/components/tree-view/engine.ts +569 -0
  376. package/src/components/tree-view/react.tsx +78 -0
  377. package/src/components/tree-view/tree-view.css +209 -0
  378. package/src/components/virtual-list/README.md +81 -0
  379. package/src/components/virtual-list/element.ts +42 -0
  380. package/src/components/virtual-list/engine.ts +678 -0
  381. package/src/components/virtual-list/react.tsx +101 -0
  382. package/src/components/virtual-list/virtual-list.css +194 -0
  383. package/src/core/chips.ts +196 -0
  384. package/src/core/color.ts +304 -0
  385. package/src/core/date-range.ts +67 -0
  386. package/src/core/dates.ts +108 -0
  387. package/src/core/files.ts +107 -0
  388. package/src/core/filter.ts +229 -0
  389. package/src/core/gsap.ts +80 -65
  390. package/src/core/listbox.ts +332 -0
  391. package/src/core/mark.ts +29 -0
  392. package/src/core/position.ts +89 -0
  393. package/src/core/relative-time.ts +77 -0
  394. package/src/core/segment-field.ts +373 -0
  395. package/src/core/segments.ts +153 -0
  396. package/src/core/tree.ts +116 -0
  397. package/src/core/virtual.ts +79 -0
  398. package/src/css/controls/README.md +14 -0
  399. package/src/css/controls/status.css +63 -0
  400. package/src/css/tokens.css +186 -182
  401. package/src/elements/index.ts +171 -0
  402. package/src/index.ts +97 -0
  403. package/src/motion/micro.ts +248 -0
  404. package/src/motion/sheet.ts +88 -65
  405. package/src/motion/surface.ts +9 -0
  406. package/src/react/index.ts +78 -0
  407. package/src/react/use-action-button.ts +6 -0
  408. package/src/react/use-editorial-reveal.ts +7 -0
  409. package/src/react/use-film-hero.ts +6 -0
  410. package/src/react/use-font-cycle.ts +7 -0
  411. package/src/react/use-image-zoom.ts +5 -0
  412. package/src/react/use-joined-cta.ts +5 -0
  413. package/src/react/use-local-clock.ts +5 -0
  414. package/src/react/use-scroll-dock.ts +5 -0
  415. package/src/react/use-sticker.ts +5 -0
  416. package/src/react/use-studio-dock.ts +8 -0
  417. package/src/react/use-thumbnail-nav.ts +7 -0
  418. package/src/react/use-trailer.ts +6 -0
  419. package/src/react/use-weight-hover.ts +5 -0
  420. package/src/recipes/action-button/README.md +31 -0
  421. package/src/recipes/action-button/action-button.css +113 -0
  422. package/src/recipes/action-button/create-action-button.ts +56 -0
  423. package/src/recipes/editorial-reveal/README.md +35 -0
  424. package/src/recipes/editorial-reveal/create-editorial-reveal.ts +91 -0
  425. package/src/recipes/editorial-reveal/editorial-reveal.css +17 -0
  426. package/src/recipes/film-hero/README.md +23 -0
  427. package/src/recipes/film-hero/create-film-hero.ts +65 -0
  428. package/src/recipes/film-hero/film-hero.css +29 -0
  429. package/src/recipes/font-cycle/README.md +11 -0
  430. package/src/recipes/font-cycle/create-font-cycle.ts +126 -0
  431. package/src/recipes/font-cycle/font-cycle.css +36 -0
  432. package/src/recipes/image-zoom/README.md +16 -0
  433. package/src/recipes/image-zoom/create-image-zoom.ts +27 -0
  434. package/src/recipes/image-zoom/image-zoom.css +7 -0
  435. package/src/recipes/joined-cta/README.md +13 -0
  436. package/src/recipes/joined-cta/create-joined-cta.ts +22 -0
  437. package/src/recipes/joined-cta/joined-cta.css +17 -0
  438. package/src/recipes/local-clock/README.md +31 -0
  439. package/src/recipes/local-clock/create-local-clock.ts +61 -0
  440. package/src/recipes/scroll-dock/README.md +46 -0
  441. package/src/recipes/scroll-dock/create-scroll-dock.ts +72 -0
  442. package/src/recipes/scroll-dock/scroll-dock.css +70 -0
  443. package/src/recipes/sticker/README.md +59 -0
  444. package/src/recipes/sticker/create-sticker.ts +490 -0
  445. package/src/recipes/sticker/sticker.css +112 -0
  446. package/src/recipes/thumbnail-nav/README.md +16 -0
  447. package/src/recipes/thumbnail-nav/create-thumbnail-nav.ts +165 -0
  448. package/src/recipes/thumbnail-nav/thumbnail-nav.css +108 -0
  449. package/src/recipes/weight-hover/README.md +37 -0
  450. package/src/recipes/weight-hover/create-weight-hover.ts +136 -0
  451. package/src/recipes/weight-hover/weight-hover.css +7 -0
  452. package/dist/chunk-BFC27F2G.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-JQMJQSXD.js +0 -2374
  456. package/dist/chunk-JQMJQSXD.js.map +0 -1
  457. package/dist/chunk-XDWBVFHQ.js.map +0 -1
  458. package/dist/reveal-C0hCDcB_.d.ts +0 -415
@@ -0,0 +1,300 @@
1
+ import { gsap, EASE, Flip, registerMotion } from '../../core/gsap';
2
+ import { reduced } from '../../core/reduced';
3
+ import { TIMING } from '../../core/timing';
4
+ import { createScope } from '../../core/scope';
5
+ import { inert, type Instance } from '../../core/types';
6
+ import { dayKey, fromJson } from '../../core/dates';
7
+ import { dayLabel, everyMinute, fullTime, relativeTime, toTime, type TimeInput } from '../../core/relative-time';
8
+ import { blurIn, collapse } from '../../motion/micro';
9
+
10
+ /*
11
+ * Timeline: events in order along a rail — dots with an icon or a state, a
12
+ * time ("hace 2 h", the full date in its title; refreshed every minute), a
13
+ * title, a description and small meta. When it comes into view the rail draws
14
+ * itself from the first dot (.8 s, wipe) and the events cascade in out of a
15
+ * blur (60 ms apart); the done stretch of the rail is filled in the accent up
16
+ * to the current event, whose dot breathes. add() drops an event in at the
17
+ * start or the end: the others glide to make room (layout reflow, the rail
18
+ * following), it comes in out of a blur, its dot pops and a soft highlight
19
+ * fades behind it; update() changes one in place (a new state pops its dot);
20
+ * remove() folds one away. 'alternate' puts the events on both sides of the
21
+ * rail when there is room; `group` heads each day with a chip on the rail.
22
+ */
23
+
24
+ export type TimelineStatus = 'done' | 'current' | 'upcoming' | 'error';
25
+
26
+ export interface TimelineEvent {
27
+ id: string;
28
+ title: string;
29
+ description?: string;
30
+ time?: TimeInput;
31
+ status?: TimelineStatus;
32
+ /** A short glyph in the dot (an emoji or one or two letters). */
33
+ icon?: string;
34
+ /** Small text under it (an author, a place). */
35
+ meta?: string;
36
+ }
37
+
38
+ export interface TimelineOptions {
39
+ events?: TimelineEvent[];
40
+ /** 'start' (default): the rail on the left; 'alternate': both sides on wide screens. */
41
+ layout?: 'start' | 'alternate';
42
+ /** A heading for each day (default false). */
43
+ group?: boolean;
44
+ /** Times as "hace 2 h", refreshed every minute (default true); false shows the date and time. */
45
+ relative?: boolean;
46
+ locale?: string;
47
+ /** Accessible name of the list (default 'Historial'). */
48
+ label?: string;
49
+ }
50
+
51
+ export interface TimelineInstance extends Instance {
52
+ add(event: TimelineEvent, at?: 'start' | 'end'): void;
53
+ update(id: string, patch: Partial<Omit<TimelineEvent, 'id'>>): void;
54
+ remove(id: string): void;
55
+ setEvents(events: TimelineEvent[]): void;
56
+ readonly events: TimelineEvent[];
57
+ }
58
+
59
+ const STATUS_LABEL: Record<TimelineStatus, string> = { done: 'Hecho', current: 'En curso', upcoming: 'Pendiente', error: 'Con error' };
60
+
61
+ /** Events written as <li data-status data-time data-icon>Title<p>description</p></li>. */
62
+ const readAuthored = (root: HTMLElement): TimelineEvent[] =>
63
+ [...root.querySelectorAll<HTMLElement>(':scope > ol > li, :scope > ul > li')].map((item, i) => {
64
+ const description = item.querySelector('p')?.textContent?.trim();
65
+ const title = [...item.childNodes].filter((node) => node.nodeType === Node.TEXT_NODE || (node instanceof HTMLElement && node.tagName !== 'P')).map((node) => node.textContent).join('').trim();
66
+ return {
67
+ id: item.id || `e${i}`,
68
+ title,
69
+ description,
70
+ time: item.dataset.time,
71
+ status: item.dataset.status as TimelineStatus | undefined,
72
+ icon: item.dataset.icon,
73
+ meta: item.dataset.meta,
74
+ };
75
+ });
76
+
77
+ export function createTimeline(root: HTMLElement | null, options: TimelineOptions = {}): TimelineInstance {
78
+ if (!root) return inert({ add() {}, update() {}, remove() {}, setEvents() {}, events: [] });
79
+ registerMotion();
80
+ const scope = createScope();
81
+ const locale = options.locale ?? root.closest('[lang]')?.getAttribute('lang') ?? 'es';
82
+ const relative = options.relative !== false;
83
+ // JSON text too (data-mk-events through autoInit).
84
+ let events = (fromJson(options.events) ?? readAuthored(root)).map((event) => ({ ...event }));
85
+ const effects = new Set<gsap.core.Animation>();
86
+ const keep = (animation: gsap.core.Animation | null) => {
87
+ if (!animation) return;
88
+ effects.add(animation);
89
+ // Finished ones leave as new ones arrive: the animation's own onComplete stays untouched.
90
+ for (const effect of effects) if (effect.totalProgress() === 1) effects.delete(effect);
91
+ };
92
+
93
+ // Authored markup stays, out of sight; the engine draws its own list.
94
+ const holder = document.createElement('div');
95
+ holder.hidden = true;
96
+ holder.append(...root.childNodes);
97
+ const list = document.createElement('ol');
98
+ list.dataset.mkTimelineList = '';
99
+ list.setAttribute('aria-label', options.label ?? 'Historial');
100
+ const rail = document.createElement('span');
101
+ rail.dataset.mkTlRail = '';
102
+ rail.setAttribute('aria-hidden', 'true');
103
+ const progress = document.createElement('span');
104
+ progress.dataset.mkTlProgress = '';
105
+ rail.append(progress);
106
+ const wrap = document.createElement('div');
107
+ wrap.dataset.mkTlWrap = '';
108
+ wrap.append(rail, list);
109
+ root.append(wrap);
110
+ scope.add(() => {
111
+ for (const effect of effects) effect.kill();
112
+ effects.clear();
113
+ wrap.remove();
114
+ root.append(...holder.childNodes);
115
+ });
116
+ scope.attr(root, 'data-mk-layout', options.layout === 'alternate' ? 'alternate' : 'start');
117
+ scope.attr(root, 'data-mk-ready', '');
118
+
119
+ const timeText = (date: Date) => (relative ? relativeTime(date, new Date(), locale) : fullTime(date, locale));
120
+
121
+ const item = (event: TimelineEvent) => {
122
+ const li = document.createElement('li');
123
+ li.dataset.mkTlItem = '';
124
+ li.dataset.id = event.id;
125
+ li.dataset.status = event.status ?? 'done';
126
+ const dot = document.createElement('span');
127
+ dot.dataset.mkTlDot = '';
128
+ dot.setAttribute('aria-hidden', 'true');
129
+ dot.textContent = event.icon ?? '';
130
+ const body = document.createElement('div');
131
+ body.dataset.mkTlBody = '';
132
+ const date = toTime(event.time);
133
+ if (date) {
134
+ const time = document.createElement('time');
135
+ time.dataset.mkTlTime = '';
136
+ time.dateTime = date.toISOString();
137
+ time.title = fullTime(date, locale);
138
+ time.textContent = timeText(date);
139
+ body.append(time);
140
+ }
141
+ const title = document.createElement('strong');
142
+ title.dataset.mkTlTitle = '';
143
+ title.textContent = event.title;
144
+ body.append(title);
145
+ if (event.status && event.status !== 'done') {
146
+ const state = document.createElement('span');
147
+ state.className = 'mk-sr-only';
148
+ state.textContent = ` (${STATUS_LABEL[event.status]})`;
149
+ title.append(state);
150
+ }
151
+ if (event.description) {
152
+ const description = document.createElement('p');
153
+ description.dataset.mkTlDescription = '';
154
+ description.textContent = event.description;
155
+ body.append(description);
156
+ }
157
+ if (event.meta) {
158
+ const meta = document.createElement('span');
159
+ meta.dataset.mkTlMeta = '';
160
+ meta.textContent = event.meta;
161
+ body.append(meta);
162
+ }
163
+ li.append(dot, body);
164
+ return li;
165
+ };
166
+
167
+ const heading = (date: Date) => {
168
+ const li = document.createElement('li');
169
+ li.dataset.mkTlDay = '';
170
+ li.dataset.day = dayKey(date);
171
+ li.setAttribute('role', 'presentation');
172
+ li.dataset.flipId = `day-${li.dataset.day}`;
173
+ li.textContent = dayLabel(date, new Date(), locale);
174
+ return li;
175
+ };
176
+
177
+ /** The rail runs from the first dot to the last; its filled part reaches the current (or last done) event. */
178
+ const measureRail = () => {
179
+ const dots = [...list.querySelectorAll<HTMLElement>('[data-mk-tl-dot]')];
180
+ if (!dots.length) {
181
+ rail.hidden = true;
182
+ return;
183
+ }
184
+ rail.hidden = false;
185
+ // Centres measured against the wrapper, whatever positions the items.
186
+ const base = wrap.getBoundingClientRect().top;
187
+ const centre = (dot: HTMLElement) => {
188
+ const box = dot.getBoundingClientRect();
189
+ return box.top - base + box.height / 2;
190
+ };
191
+ const top = centre(dots[0]!);
192
+ const bottom = centre(dots[dots.length - 1]!);
193
+ rail.style.top = `${top}px`;
194
+ rail.style.height = `${Math.max(0, bottom - top)}px`;
195
+ const reached = [...list.querySelectorAll<HTMLElement>('[data-mk-tl-item]')].filter((li) => li.dataset.status === 'done' || li.dataset.status === 'current');
196
+ const last = reached[reached.length - 1]?.querySelector<HTMLElement>('[data-mk-tl-dot]');
197
+ progress.style.height = `${last ? Math.max(0, centre(last) - top) : 0}px`;
198
+ };
199
+ const itemOf = (id: string) => [...list.querySelectorAll<HTMLElement>('[data-mk-tl-item]')].find((li) => li.dataset.id === id) ?? null;
200
+
201
+ const render = () => {
202
+ const nodes: HTMLElement[] = [];
203
+ let day = '';
204
+ events.forEach((event, i) => {
205
+ const date = toTime(event.time);
206
+ if (options.group && date && dayKey(date) !== day) {
207
+ day = dayKey(date);
208
+ nodes.push(heading(date));
209
+ }
210
+ const element = item(event);
211
+ // 'alternate': the events take turns on each side of the rail.
212
+ element.dataset.side = i % 2 ? 'end' : 'start';
213
+ element.dataset.flipId = event.id;
214
+ nodes.push(element);
215
+ });
216
+ list.replaceChildren(...nodes);
217
+ measureRail();
218
+ };
219
+
220
+ const refreshTimes = () => {
221
+ for (const time of list.querySelectorAll<HTMLTimeElement>('[data-mk-tl-time]')) time.textContent = timeText(new Date(time.dateTime));
222
+ if (options.group) for (const day of list.querySelectorAll<HTMLElement>('[data-mk-tl-day]')) day.textContent = dayLabel(toTime(day.dataset.day!)!, new Date(), locale);
223
+ };
224
+ if (relative) scope.add(everyMinute(refreshTimes));
225
+ if (typeof ResizeObserver === 'function') scope.observe(new ResizeObserver(() => measureRail())).observe(list);
226
+
227
+ /** The entrance: the rail draws, the events cascade in. */
228
+ const enter = () => {
229
+ if (reduced()) return;
230
+ keep(gsap.fromTo(rail, { scaleY: 0 }, { scaleY: 1, transformOrigin: '50% 0%', duration: 0.8, ease: EASE.wipe, clearProps: 'transform' }));
231
+ keep(blurIn([...list.children], { from: 'rise', stagger: 0.06 }));
232
+ };
233
+
234
+ render();
235
+ if (typeof IntersectionObserver === 'function' && !reduced()) {
236
+ gsap.set([rail, ...list.children], { opacity: 0 });
237
+ const observer = scope.observe(
238
+ new IntersectionObserver((entries) => {
239
+ if (!entries.some((entry) => entry.isIntersecting)) return;
240
+ observer.disconnect();
241
+ gsap.set([rail, ...list.children], { clearProps: 'opacity' });
242
+ enter();
243
+ }, { threshold: 0.15 }),
244
+ );
245
+ observer.observe(root);
246
+ }
247
+
248
+ return {
249
+ add(event, at = 'end') {
250
+ if (scope.disposed) return;
251
+ // What is there glides to make room (the rail follows); the new event and a new day come in.
252
+ const state = reduced() ? null : Flip.getState([...list.children]);
253
+ events = at === 'start' ? [{ ...event }, ...events] : [...events, { ...event }];
254
+ render();
255
+ const added = itemOf(event.id);
256
+ if (!added || !state) return;
257
+ added.setAttribute('data-mk-tl-fresh', '');
258
+ scope.timeout(() => added.removeAttribute('data-mk-tl-fresh'), 1800);
259
+ keep(
260
+ Flip.from(state, {
261
+ targets: [...list.children],
262
+ duration: TIMING.layoutTravel,
263
+ ease: EASE.layoutReflow,
264
+ onUpdate: measureRail,
265
+ onComplete: measureRail,
266
+ onEnter: (entering) =>
267
+ gsap.fromTo(entering, { opacity: 0, y: at === 'start' ? -16 : 16, filter: 'blur(10px)' }, { opacity: 1, y: 0, filter: 'blur(0px)', duration: 0.45, ease: 'power2.out', clearProps: 'opacity,transform,filter' }),
268
+ }),
269
+ );
270
+ const dot = added.querySelector<HTMLElement>('[data-mk-tl-dot]')!;
271
+ keep(gsap.fromTo(dot, { scale: 0 }, { scale: 1, duration: 0.4, delay: 0.12, ease: EASE.pop, clearProps: 'transform' }));
272
+ },
273
+ update(id, patch) {
274
+ const event = events.find((entry) => entry.id === id);
275
+ if (!event || scope.disposed) return;
276
+ const statusChanged = patch.status && patch.status !== event.status;
277
+ Object.assign(event, patch);
278
+ render();
279
+ const dot = itemOf(id)?.querySelector<HTMLElement>('[data-mk-tl-dot]');
280
+ if (statusChanged && dot && !reduced()) keep(gsap.fromTo(dot, { scale: 0.6 }, { scale: 1, duration: 0.4, ease: EASE.pop, clearProps: 'transform' }));
281
+ },
282
+ remove(id) {
283
+ const element = itemOf(id);
284
+ events = events.filter((event) => event.id !== id);
285
+ if (!element) return render();
286
+ if (reduced()) return render();
287
+ keep(collapse(element, { onComplete: render }));
288
+ },
289
+ setEvents(next) {
290
+ if (scope.disposed) return;
291
+ events = next.map((event) => ({ ...event }));
292
+ render();
293
+ if (!reduced()) keep(blurIn([...list.children], { from: 'rise', stagger: 0.04 }));
294
+ },
295
+ get events() {
296
+ return events.map((event) => ({ ...event }));
297
+ },
298
+ destroy: () => scope.dispose(),
299
+ };
300
+ }
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+ import { useRef, type HTMLAttributes } from 'react';
3
+ import { useIsomorphicLayoutEffect } from '../../react/use-recipe';
4
+ import { createTimeline, type TimelineEvent, type TimelineInstance, type TimelineOptions } from './engine';
5
+
6
+ export interface TimelineProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'>, Omit<TimelineOptions, 'events'> {
7
+ events: TimelineEvent[];
8
+ }
9
+
10
+ /**
11
+ * <Timeline events={history} group />. Changing `events` updates in place: an event added at either end grows in,
12
+ * one that changes state recolours its dot, one that goes folds away.
13
+ */
14
+ export function Timeline({ events, layout, group, relative, locale, label, className, ...props }: TimelineProps) {
15
+ const ref = useRef<HTMLDivElement>(null);
16
+ const instance = useRef<TimelineInstance | null>(null);
17
+ const shown = useRef<TimelineEvent[]>(events);
18
+ useIsomorphicLayoutEffect(() => {
19
+ const created = createTimeline(ref.current, { events: shown.current, layout, group, relative, locale, label });
20
+ instance.current = created;
21
+ return () => {
22
+ created.destroy();
23
+ instance.current = null;
24
+ };
25
+ // eslint-disable-next-line react-hooks/exhaustive-deps
26
+ }, [layout, group, relative, locale, label]);
27
+ const key = JSON.stringify(events);
28
+ useIsomorphicLayoutEffect(() => {
29
+ const timeline = instance.current;
30
+ const before = shown.current;
31
+ shown.current = events;
32
+ if (!timeline || JSON.stringify(timeline.events) === key) return;
33
+ const ids = new Set(before.map((event) => event.id));
34
+ const fresh = events.filter((event) => !ids.has(event.id));
35
+ const kept = events.filter((event) => ids.has(event.id));
36
+ const gone = before.filter((old) => !events.some((event) => event.id === old.id));
37
+ const stayed = before.filter((old) => !gone.includes(old));
38
+ const sameOrder = kept.every((event, i) => stayed[i]?.id === event.id);
39
+ /** The events that stayed take their changes (a new state recolours a dot). */
40
+ const patch = () => {
41
+ for (const event of kept) {
42
+ const old = before.find((entry) => entry.id === event.id);
43
+ // Keys the new version dropped are cleared too.
44
+ if (old && JSON.stringify(old) !== JSON.stringify(event)) timeline.update(event.id, { ...Object.fromEntries(Object.keys(old).map((name) => [name, undefined])), ...event });
45
+ }
46
+ };
47
+ const first = events[0]?.id;
48
+ const last = events[events.length - 1]?.id;
49
+ // One event added at an end grows in; one taken out folds away; anything else is redrawn.
50
+ if (sameOrder && !gone.length && fresh.length === 1 && (fresh[0]!.id === first || fresh[0]!.id === last)) {
51
+ patch();
52
+ timeline.add(fresh[0]!, fresh[0]!.id === first ? 'start' : 'end');
53
+ } else if (sameOrder && !fresh.length && gone.length <= 1) {
54
+ patch();
55
+ if (gone[0]) timeline.remove(gone[0].id);
56
+ } else timeline.setEvents(events);
57
+ }, [key]);
58
+ return <div {...props} ref={ref} className={['mk-timeline', className].filter(Boolean).join(' ')} />;
59
+ }
@@ -0,0 +1,218 @@
1
+ /* timeline — a 2 px rail (outline-soft) behind 2rem dots, its done stretch in the accent; dots by state (done: accent,
2
+ current: accent-soft with a ring that breathes, upcoming: dashed, error: error); a muted time, a 600 title, a muted
3
+ description; days are chips on the rail. 'alternate' puts the events on both sides of a centred rail when the timeline
4
+ is 520 px wide or more. */
5
+ .mk-timeline,
6
+ mk-timeline {
7
+ container-type: inline-size;
8
+ display: block;
9
+ min-width: 0;
10
+ color: var(--mk-text);
11
+ }
12
+
13
+ [data-mk-tl-wrap] {
14
+ position: relative;
15
+ }
16
+
17
+ [data-mk-timeline-list] {
18
+ display: grid;
19
+ gap: 1.1rem;
20
+ margin: 0;
21
+ padding: 0;
22
+ list-style: none;
23
+ }
24
+
25
+ [data-mk-tl-rail] {
26
+ position: absolute;
27
+ left: calc(1rem - 1px);
28
+ width: 2px;
29
+ overflow: hidden;
30
+ border-radius: 2px;
31
+ background: var(--mk-outline-soft);
32
+ }
33
+
34
+ [data-mk-tl-rail][hidden] {
35
+ display: none;
36
+ }
37
+
38
+ [data-mk-tl-progress] {
39
+ display: block;
40
+ width: 100%;
41
+ border-radius: inherit;
42
+ background: var(--mk-accent);
43
+ transition: height 0.5s cubic-bezier(0.38, 0.49, 0, 1);
44
+ }
45
+
46
+ [data-mk-tl-item] {
47
+ display: grid;
48
+ grid-template-columns: 2rem minmax(0, 1fr);
49
+ align-items: start;
50
+ column-gap: 0.85rem;
51
+ }
52
+
53
+ [data-mk-tl-dot] {
54
+ position: relative;
55
+ z-index: 1;
56
+ display: grid;
57
+ place-items: center;
58
+ width: 2rem;
59
+ height: 2rem;
60
+ border-radius: 50%;
61
+ background: var(--mk-accent);
62
+ color: var(--mk-on-accent);
63
+ box-shadow: 0 0 0 4px var(--mk-surface-1, var(--mk-bg));
64
+ font-size: 0.8125rem;
65
+ font-weight: 700;
66
+ line-height: 1;
67
+ }
68
+
69
+ [data-mk-tl-dot]:empty::after {
70
+ content: '';
71
+ width: 0.5rem;
72
+ height: 0.5rem;
73
+ border-radius: 50%;
74
+ background: currentColor;
75
+ }
76
+
77
+ [data-mk-tl-item][data-status='current'] [data-mk-tl-dot] {
78
+ background: var(--mk-accent-soft);
79
+ color: var(--mk-on-accent-soft, var(--mk-text));
80
+ animation: mk-tl-breathe 2.2s ease-in-out infinite;
81
+ }
82
+
83
+ [data-mk-tl-item][data-status='upcoming'] [data-mk-tl-dot] {
84
+ background: var(--mk-surface-1, var(--mk-bg));
85
+ color: var(--mk-muted);
86
+ outline: 2px dashed var(--mk-outline);
87
+ outline-offset: -2px;
88
+ }
89
+
90
+ [data-mk-tl-item][data-status='error'] [data-mk-tl-dot] {
91
+ background: var(--mk-error, #c62828);
92
+ color: var(--mk-on-error, #fff);
93
+ }
94
+
95
+ @keyframes mk-tl-breathe {
96
+ 0%,
97
+ 100% {
98
+ box-shadow: 0 0 0 4px var(--mk-surface-1, var(--mk-bg)), 0 0 0 4px color-mix(in srgb, var(--mk-accent) 45%, transparent);
99
+ }
100
+
101
+ 50% {
102
+ box-shadow: 0 0 0 4px var(--mk-surface-1, var(--mk-bg)), 0 0 0 9px color-mix(in srgb, var(--mk-accent) 0%, transparent);
103
+ }
104
+ }
105
+
106
+ [data-mk-tl-body] {
107
+ position: relative;
108
+ isolation: isolate;
109
+ display: grid;
110
+ justify-self: start;
111
+ gap: 0.2rem;
112
+ min-width: 0;
113
+ padding-top: 0.25rem;
114
+ }
115
+
116
+ /* A new event: a soft accent highlight behind it that fades. */
117
+ [data-mk-tl-fresh] [data-mk-tl-body]::before {
118
+ content: '';
119
+ position: absolute;
120
+ inset: -0.125rem -0.625rem -0.375rem;
121
+ z-index: -1;
122
+ border-radius: 12px;
123
+ background: var(--mk-accent-soft);
124
+ animation: mk-tl-fresh 1.8s ease-out both;
125
+ pointer-events: none;
126
+ }
127
+
128
+ @keyframes mk-tl-fresh {
129
+ from {
130
+ opacity: 0.75;
131
+ }
132
+
133
+ to {
134
+ opacity: 0;
135
+ }
136
+ }
137
+
138
+ [data-mk-tl-time],
139
+ [data-mk-tl-meta] {
140
+ color: var(--mk-muted);
141
+ font-size: 0.75rem;
142
+ }
143
+
144
+ [data-mk-tl-title] {
145
+ font-weight: 600;
146
+ line-height: 1.35;
147
+ overflow-wrap: anywhere;
148
+ }
149
+
150
+ [data-mk-tl-item][data-status='upcoming'] [data-mk-tl-title] {
151
+ color: var(--mk-muted);
152
+ }
153
+
154
+ [data-mk-tl-description] {
155
+ margin: 0;
156
+ color: var(--mk-muted);
157
+ font-size: 0.875rem;
158
+ line-height: 1.5;
159
+ overflow-wrap: anywhere;
160
+ }
161
+
162
+ /* A day is a small chip on the rail (it hides the line behind it). */
163
+ [data-mk-tl-day] {
164
+ position: relative;
165
+ z-index: 1;
166
+ justify-self: start;
167
+ margin-top: 0.35rem;
168
+ padding: 0.25rem 0.625rem;
169
+ border-radius: 8px;
170
+ background: var(--mk-surface-3);
171
+ color: var(--mk-muted);
172
+ font-size: 0.6875rem;
173
+ font-weight: 700;
174
+ letter-spacing: 0.04em;
175
+ text-transform: uppercase;
176
+ }
177
+
178
+ @container (min-width: 520px) {
179
+ :is(.mk-timeline, mk-timeline)[data-mk-layout='alternate'] [data-mk-tl-rail] {
180
+ left: calc(50% - 1px);
181
+ }
182
+
183
+ :is(.mk-timeline, mk-timeline)[data-mk-layout='alternate'] [data-mk-tl-item] {
184
+ grid-template-columns: minmax(0, 1fr) 2rem minmax(0, 1fr);
185
+ }
186
+
187
+ :is(.mk-timeline, mk-timeline)[data-mk-layout='alternate'] [data-mk-tl-dot] {
188
+ grid-row: 1;
189
+ grid-column: 2;
190
+ }
191
+
192
+ :is(.mk-timeline, mk-timeline)[data-mk-layout='alternate'] [data-mk-tl-item][data-side='start'] [data-mk-tl-body] {
193
+ grid-row: 1;
194
+ grid-column: 1;
195
+ justify-self: end;
196
+ text-align: end;
197
+ }
198
+
199
+ :is(.mk-timeline, mk-timeline)[data-mk-layout='alternate'] [data-mk-tl-item][data-side='end'] [data-mk-tl-body] {
200
+ grid-row: 1;
201
+ grid-column: 3;
202
+ }
203
+
204
+ :is(.mk-timeline, mk-timeline)[data-mk-layout='alternate'] [data-mk-tl-day] {
205
+ justify-self: center;
206
+ }
207
+ }
208
+
209
+ @media (prefers-reduced-motion: reduce) {
210
+ [data-mk-tl-item][data-status='current'] [data-mk-tl-dot] {
211
+ animation: none;
212
+ box-shadow: 0 0 0 4px var(--mk-surface-1, var(--mk-bg)), 0 0 0 6px color-mix(in srgb, var(--mk-accent) 45%, transparent);
213
+ }
214
+
215
+ [data-mk-tl-progress] {
216
+ transition: none;
217
+ }
218
+ }
@@ -0,0 +1,46 @@
1
+ # tooltip
2
+
3
+ Descripción breve junto a su disparador. Aparece cuando el puntero se detiene sobre él (400 ms), en cuanto el foco del teclado llega (al momento) o con una pulsación larga en pantallas táctiles (500 ms). Toma el lado preferido, cambia al opuesto si no cabe, se mantiene dentro de la ventana y apunta con una flecha al centro del disparador. Vive en la capa superior (API `popover`), así que ningún `overflow` lo recorta.
4
+
5
+ Movimiento (línea Melon Mind): sale de la flecha con un pop (escala .85, 4 px hacia el disparador, blur 4 → 0, .22 s) y se va en .12 s. Si pasas a otro tooltip en menos de .4 s, aparece al instante con un fundido simple («caliente»). El texto nuevo cambia con un fundido.
6
+
7
+ ## HTML / Astro
8
+
9
+ ```html
10
+ <mk-tooltip class="mk-tooltip" content="Copiar enlace">
11
+ <button class="mk-button mk-button--icon" aria-label="Copiar">⧉</button>
12
+ </mk-tooltip>
13
+
14
+ <!-- Sin content usa el title del disparador (y lo quita, para que no salga el del navegador). -->
15
+ <mk-tooltip placement="right"><button title="Ajustes">⚙</button></mk-tooltip>
16
+ ```
17
+
18
+ ## React
19
+
20
+ ```tsx
21
+ <Tooltip content={copied ? 'Copiado' : 'Copiar enlace'}>
22
+ <button onClick={copy}>⧉</button>
23
+ </Tooltip>
24
+ ```
25
+
26
+ El primer elemento enfocable dentro es el disparador (o `[data-mk-tooltip-trigger]`). Si no hay ninguno, el propio contenedor recibe `tabindex="0"`.
27
+
28
+ ## Opciones
29
+
30
+ | Opción | Atributo | Por defecto | Qué hace |
31
+ |---|---|---|---|
32
+ | `content` | `content` | el `title` del disparador | Texto del tooltip. |
33
+ | `placement` | `placement` | `'top'` | `top`, `bottom`, `left`, `right` o `auto` (el lado con más espacio). |
34
+ | `openDelay` | `open-delay` | `400` | Espera al señalar, en ms. |
35
+ | `closeDelay` | `close-delay` | `100` | Espera al salir, en ms. |
36
+ | `interactive` | `interactive` | `false` | El puntero puede entrar en el tooltip (enlaces, texto seleccionable). |
37
+ | `arrow` | `arrow` | `true` | Flecha hacia el disparador. |
38
+ | `onOpenChange(open)` | — | — | Al abrirse o cerrarse. |
39
+
40
+ ## API y eventos
41
+
42
+ `open()`, `close()`, `setContent(texto)` (un texto vacío lo oculta), `isOpen`, `destroy()`. Evento `mk:open-change` con `{ open }`.
43
+
44
+ ## Accesibilidad
45
+
46
+ `role="tooltip"` y `aria-describedby` en el disparador. Escape lo oculta sin mover el foco (WCAG 1.4.13). Con movimiento reducido aparece y desaparece sin animación. Variable CSS: `--mk-tooltip-bg` (cristal invertido).
@@ -0,0 +1,22 @@
1
+ import { MkElement, defineElement, type OptionType } from '../../elements/base';
2
+ import { createTooltip, type TooltipInstance } from './engine';
3
+
4
+ /**
5
+ * <mk-tooltip class="mk-tooltip" content="Copiar enlace"><button>…</button></mk-tooltip>
6
+ * Without `content`, the trigger's title. Emits mk:open-change ({open}).
7
+ */
8
+ export class MkTooltipElement extends MkElement<TooltipInstance> {
9
+ static options: Record<string, OptionType> = { content: 'string', placement: 'string', openDelay: 'number', closeDelay: 'number', interactive: 'boolean', arrow: 'boolean' };
10
+
11
+ protected create(options: Record<string, unknown>) {
12
+ return createTooltip(this, options);
13
+ }
14
+
15
+ attributeChangedCallback(name: string, previous: string | null, next: string | null) {
16
+ if (previous === next || !this.instance) return;
17
+ if (name === 'content') this.instance.setContent(next ?? '');
18
+ else super.attributeChangedCallback(name, previous, next);
19
+ }
20
+ }
21
+
22
+ export const defineTooltip = () => defineElement('mk-tooltip', MkTooltipElement);