@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,350 @@
1
+ import { gsap, registerMotion } from '../../core/gsap';
2
+ import { createScope } from '../../core/scope';
3
+ import { inert, type Instance } from '../../core/types';
4
+ import { dayKey, toDate, type DateInput } from '../../core/dates';
5
+ import { daysIn, formatTime, to12, to24 } from '../../core/segments';
6
+ import { createSegmentField, type SegmentValues } from '../../core/segment-field';
7
+ import { isPickable, type DayRules } from '../../core/date-range';
8
+ import { press, shake } from '../../motion/micro';
9
+ import { flowInMenu } from '../../motion/entrances';
10
+ import { createDialog } from '../dialog/engine';
11
+ import { createRangeCalendar } from '../range-calendar/engine';
12
+ import { createTimeField } from '../time-field/engine';
13
+
14
+ /*
15
+ * Date-time picker: date and time in one segmented field, in the locale's
16
+ * order and joint ("23/11/2026, 13:05" in Spanish; 12 h with AM/PM where the
17
+ * locale writes it). The calendar button grows a panel out of itself (an
18
+ * anchored dialog, like menu) whose content flows in like a menu's options: a
19
+ * one-day calendar (range-calendar, selection: 'single'), a time field and
20
+ * "Ahora" / "Listo". Picking a day keeps the time; changing the time keeps the
21
+ * day; every change rolls the field's digits. Typing a complete date and time
22
+ * checks min, max and unavailable days: out of bounds marks the field invalid,
23
+ * says why under it and shakes once when focus leaves. onChange reports valid
24
+ * values (and null when the field is emptied).
25
+ */
26
+
27
+ export interface DateTimePickerOptions {
28
+ /** A Date or 'YYYY-MM-DDTHH:MM' (local). */
29
+ value?: DateInput | null;
30
+ min?: DateInput | null;
31
+ max?: DateInput | null;
32
+ locale?: string;
33
+ hourCycle?: 12 | 24;
34
+ /** Arrow step of the minutes (default 5). */
35
+ minuteStep?: number;
36
+ firstDay?: number;
37
+ unavailable?: string[] | ((day: Date) => boolean);
38
+ /** Override "today" (demos, tests). */
39
+ today?: DateInput;
40
+ /** Accessible name of the field (default 'Fecha y hora'). */
41
+ label?: string;
42
+ /** Hidden input with 'YYYY-MM-DDTHH:MM'. */
43
+ name?: string;
44
+ disabled?: boolean;
45
+ onChange?: (value: Date | null) => void;
46
+ }
47
+
48
+ export interface DateTimePickerInstance extends Instance {
49
+ open(): void;
50
+ close(): void;
51
+ setValue(value: DateInput | null): void;
52
+ readonly value: Date | null;
53
+ readonly isOpen: boolean;
54
+ }
55
+
56
+ const CALENDAR_ICON =
57
+ '<svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="5" width="17" height="15.5" rx="3"/><path d="M3.5 10h17M8 3v4M16 3v4"/><path d="M12 13.5v2.5l1.6 1"/></svg>';
58
+ let sequence = 0;
59
+ const pad = (n: number) => String(n).padStart(2, '0');
60
+
61
+ /** A local date-time from a Date or 'YYYY-MM-DD[T ]HH:MM[:SS]'; null when unreadable. */
62
+ export function toDateTimeValue(input: DateInput | null | undefined): Date | null {
63
+ if (input === null || input === undefined || input === '') return null;
64
+ if (input instanceof Date) return Number.isNaN(input.getTime()) ? null : new Date(input.getTime());
65
+ if (typeof input === 'string') {
66
+ const match = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2}))?)?$/.exec(input.trim());
67
+ if (match) {
68
+ const date = new Date(2000, 0, 1);
69
+ date.setFullYear(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
70
+ date.setHours(Number(match[4] ?? 0), Number(match[5] ?? 0), Number(match[6] ?? 0), 0);
71
+ return date;
72
+ }
73
+ }
74
+ const parsed = new Date(input);
75
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
76
+ }
77
+
78
+ /** 'YYYY-MM-DDTHH:MM' of a local date-time (what <input type="datetime-local"> posts). */
79
+ export const dateTimeKey = (date: Date) => `${dayKey(date)}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
80
+
81
+ export function createDateTimePicker(root: HTMLElement | null, options: DateTimePickerOptions = {}): DateTimePickerInstance {
82
+ if (!root) return inert({ open() {}, close() {}, setValue() {}, value: null, isOpen: false });
83
+ registerMotion();
84
+ const scope = createScope();
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
+ scope.add(() => {
93
+ for (const effect of effects) effect.kill();
94
+ effects.clear();
95
+ });
96
+ const uid = `mk-datetime-${++sequence}`;
97
+ const locale = options.locale ?? root.closest('[lang]')?.getAttribute('lang') ?? 'es';
98
+ const step = options.minuteStep && options.minuteStep > 0 ? Math.round(options.minuteStep) : 5;
99
+ const min = toDateTimeValue(options.min);
100
+ const max = toDateTimeValue(options.max);
101
+ const unavailable = options.unavailable;
102
+ const rules: DayRules = {
103
+ isUnavailable: typeof unavailable === 'function' ? unavailable : Array.isArray(unavailable) ? (day) => unavailable.includes(dayKey(day)) : undefined,
104
+ };
105
+ let value: Date | null = toDateTimeValue(options.value);
106
+
107
+ const made: Element[] = [];
108
+ const box = document.createElement('div');
109
+ box.dataset.mkDtField = '';
110
+ root.append(box);
111
+ made.push(box);
112
+ const field = createSegmentField(box, {
113
+ kind: 'datetime',
114
+ locale,
115
+ hour12: options.hourCycle ? options.hourCycle === 12 : undefined,
116
+ steps: { minute: step },
117
+ disabled: options.disabled,
118
+ onChange: () => typed(),
119
+ });
120
+ scope.add(() => field.destroy());
121
+ field.element.setAttribute('aria-label', options.label ?? 'Fecha y hora');
122
+ field.element.setAttribute('aria-describedby', `${uid}-error`);
123
+ const twelve = field.element.querySelector('[data-mk-segment="dayPeriod"]') !== null;
124
+ const button = document.createElement('button');
125
+ button.type = 'button';
126
+ button.dataset.mkDtButton = '';
127
+ button.setAttribute('aria-label', 'Abrir calendario');
128
+ button.setAttribute('aria-haspopup', 'dialog');
129
+ button.setAttribute('aria-expanded', 'false');
130
+ button.disabled = Boolean(options.disabled);
131
+ button.innerHTML = CALENDAR_ICON;
132
+ box.append(button);
133
+ const error = document.createElement('p');
134
+ error.id = `${uid}-error`;
135
+ error.dataset.mkDtError = '';
136
+ error.setAttribute('aria-live', 'polite');
137
+ error.hidden = true;
138
+ root.append(error);
139
+ made.push(error);
140
+
141
+ const dialogElement = document.createElement('dialog');
142
+ // A class, not only an attribute: the copy that folds back into the button on close keeps classes only.
143
+ dialogElement.className = 'mk-dialog mk-dt-popover';
144
+ dialogElement.dataset.mkDtPopover = '';
145
+ dialogElement.setAttribute('aria-label', 'Elegir fecha y hora');
146
+ const calendarHost = document.createElement('div');
147
+ calendarHost.className = 'mk-range-calendar';
148
+ const timeRow = document.createElement('div');
149
+ timeRow.dataset.mkDtTimeRow = '';
150
+ const timeLabel = document.createElement('span');
151
+ timeLabel.dataset.mkDtTimeLabel = '';
152
+ timeLabel.textContent = 'Hora';
153
+ const timeHost = document.createElement('div');
154
+ timeHost.className = 'mk-time-field';
155
+ timeRow.append(timeLabel, timeHost);
156
+ const footer = document.createElement('div');
157
+ footer.dataset.mkDtFooter = '';
158
+ const now = document.createElement('button');
159
+ now.type = 'button';
160
+ now.dataset.mkDtNow = '';
161
+ now.textContent = 'Ahora';
162
+ const done = document.createElement('button');
163
+ done.type = 'button';
164
+ done.dataset.mkDtDone = '';
165
+ done.dataset.mkClose = '';
166
+ done.textContent = 'Listo';
167
+ footer.append(now, done);
168
+ dialogElement.append(calendarHost, timeRow, footer);
169
+ root.append(dialogElement);
170
+ made.push(dialogElement);
171
+ let hidden: HTMLInputElement | null = null;
172
+ if (options.name) {
173
+ hidden = document.createElement('input');
174
+ hidden.type = 'hidden';
175
+ hidden.name = options.name;
176
+ root.append(hidden);
177
+ made.push(hidden);
178
+ }
179
+ scope.add(() => made.forEach((node) => node.remove()));
180
+ // Listeners on the picker hear the picker, not the calendar and time field inside its panel.
181
+ scope.on(dialogElement, 'mk:change', (event) => event.stopPropagation());
182
+ scope.attr(root, 'data-mk-ready', '');
183
+
184
+ const segmentsOf = (date: Date | null): SegmentValues => {
185
+ if (!date) return { day: null, month: null, year: null, hour: null, minute: null, dayPeriod: null };
186
+ const hour = date.getHours();
187
+ const clock = twelve ? to12(hour) : { hour, period: null };
188
+ return { day: date.getDate(), month: date.getMonth() + 1, year: date.getFullYear(), hour: clock.hour, minute: date.getMinutes(), dayPeriod: clock.period };
189
+ };
190
+ const dateOf = (values: SegmentValues): Date | null => {
191
+ const { day, month, year, hour, minute } = values;
192
+ if (day == null || month == null || year == null || hour == null || minute == null || (twelve && values.dayPeriod == null)) return null;
193
+ if (day > daysIn(year, month)) return null;
194
+ const date = new Date(2000, 0, 1);
195
+ date.setFullYear(year, month - 1, day);
196
+ date.setHours(twelve ? to24(hour, values.dayPeriod!) : hour, minute, 0, 0);
197
+ return date;
198
+ };
199
+ const empty = (values: SegmentValues) => Object.values(values).every((part) => part == null);
200
+
201
+ const showError = (message: string | null) => {
202
+ error.textContent = message ?? '';
203
+ error.hidden = !message;
204
+ field.invalid(Boolean(message));
205
+ };
206
+ const problem = (date: Date) => {
207
+ if ((min && date < min) || (max && date > max)) return 'Fuera del rango permitido';
208
+ if (!isPickable(toDate(date), rules)) return 'Ese día no está disponible';
209
+ return null;
210
+ };
211
+
212
+ let calendarReady = false;
213
+ /** Make `next` the value: the field (rolling), the calendar, the time field, the form; report it. */
214
+ const commit = (next: Date | null, fill: boolean, notify = true) => {
215
+ const same = next && value ? next.getTime() === value.getTime() : next === value;
216
+ value = next;
217
+ if (fill) field.setValues(segmentsOf(next), true);
218
+ showError(null);
219
+ if (hidden) hidden.value = next ? dateTimeKey(next) : '';
220
+ if (calendarReady) {
221
+ calendar.setValue(next ? { start: dayKey(next), end: dayKey(next) } : null, false);
222
+ timeField.setValue(next ? formatTime({ hour: next.getHours(), minute: next.getMinutes(), second: 0 }) : null, true);
223
+ }
224
+ if (same || !notify) return;
225
+ options.onChange?.(next ? new Date(next.getTime()) : null);
226
+ root.dispatchEvent(new CustomEvent('mk:change', { bubbles: true, detail: { value: next ? dateTimeKey(next) : null } }));
227
+ };
228
+
229
+ // Typing: a complete, allowed date-time becomes the value; an emptied field reports null.
230
+ const typed = () => {
231
+ const values = field.values();
232
+ if (empty(values)) return commit(null, false);
233
+ const date = dateOf(values);
234
+ if (!date) return showError(null);
235
+ const why = problem(date);
236
+ if (why) return showError(why);
237
+ commit(date, false);
238
+ };
239
+ scope.on(box, 'focusout', (event) => {
240
+ if (!box.contains((event as FocusEvent).relatedTarget as Node | null) && field.element.hasAttribute('aria-invalid')) keep(shake(box));
241
+ });
242
+
243
+ /** The time of day to keep when only the day is picked: the value's, else the time field's, else now (on the step). */
244
+ const rounded = (date: Date) => {
245
+ const result = new Date(date.getTime());
246
+ result.setSeconds(0, 0);
247
+ result.setMinutes(Math.round(result.getMinutes() / step) * step);
248
+ return result;
249
+ };
250
+ /** Inside min and max (a day picked in the panel keeps its time unless that falls outside). */
251
+ const clamp = (date: Date) => (min && date < min ? new Date(min.getTime()) : max && date > max ? new Date(max.getTime()) : date);
252
+ const timeOfDay = () => {
253
+ if (value) return { hour: value.getHours(), minute: value.getMinutes() };
254
+ const time = timeField.value?.split(':').map(Number);
255
+ if (time && time.length >= 2) return { hour: time[0]!, minute: time[1]! };
256
+ const current = rounded(new Date());
257
+ return { hour: current.getHours(), minute: current.getMinutes() };
258
+ };
259
+
260
+ const calendar = createRangeCalendar(calendarHost, {
261
+ selection: 'single',
262
+ value: value ? { start: dayKey(value), end: dayKey(value) } : null,
263
+ firstDay: options.firstDay,
264
+ min: min ? dayKey(min) : null,
265
+ max: max ? dayKey(max) : null,
266
+ unavailable: options.unavailable,
267
+ locale,
268
+ today: options.today,
269
+ onChange: (range) => {
270
+ const { hour, minute } = timeOfDay();
271
+ const next = new Date(range.start.getTime());
272
+ next.setHours(hour, minute, 0, 0);
273
+ commit(clamp(next), true);
274
+ },
275
+ });
276
+ scope.add(() => calendar.destroy());
277
+ const timeField = createTimeField(timeHost, {
278
+ value: value ? formatTime({ hour: value.getHours(), minute: value.getMinutes(), second: 0 }) : null,
279
+ locale,
280
+ hourCycle: options.hourCycle,
281
+ minuteStep: step,
282
+ label: 'Hora',
283
+ onChange: (time) => {
284
+ if (!time) return;
285
+ const [hour, minute] = time.split(':').map(Number);
286
+ const base = value ?? toDate(options.today ?? new Date());
287
+ const next = new Date(base.getTime());
288
+ next.setHours(hour!, minute!, 0, 0);
289
+ commit(clamp(next), true);
290
+ },
291
+ });
292
+ scope.add(() => timeField.destroy());
293
+ calendarReady = true;
294
+
295
+ const startDay = () => value ?? toDate(options.today ?? new Date());
296
+ const popover = createDialog(dialogElement, {
297
+ placement: 'anchor',
298
+ backdrop: false,
299
+ drag: false,
300
+ autoResize: false,
301
+ triggers: false,
302
+ animateContent: false,
303
+ onOpen: () => {
304
+ calendar.focusDay(startDay(), false);
305
+ // Like a menu's options: the calendar, the time and the buttons flow in while the surface grows.
306
+ keep(flowInMenu([...dialogElement.querySelectorAll<HTMLElement>('[data-mk-range-header], [data-mk-range-month], [data-mk-dt-time-row], [data-mk-dt-footer]')]));
307
+ },
308
+ onClose: () => button.setAttribute('aria-expanded', 'false'),
309
+ });
310
+ scope.add(() => popover.destroy());
311
+
312
+ const open = () => {
313
+ if (options.disabled || popover.isOpen) return;
314
+ // The calendar shows the value's month before the panel is measured and placed.
315
+ calendar.setValue(value ? { start: dayKey(value), end: dayKey(value) } : null, false);
316
+ calendar.focusDay(startDay(), false);
317
+ popover.open(button);
318
+ button.setAttribute('aria-expanded', 'true');
319
+ };
320
+ scope.on(button, 'click', () => {
321
+ keep(press(button));
322
+ if (popover.isOpen) popover.close();
323
+ else open();
324
+ });
325
+ scope.on(now, 'click', () => {
326
+ keep(press(now));
327
+ const current = rounded(new Date());
328
+ commit(problem(current) ? value : current, true);
329
+ calendar.focusDay(current, false);
330
+ });
331
+
332
+ field.setValues(segmentsOf(value));
333
+ if (hidden) hidden.value = value ? dateTimeKey(value) : '';
334
+
335
+ return {
336
+ open,
337
+ close: () => popover.close(),
338
+ setValue(next) {
339
+ if (scope.disposed) return;
340
+ commit(toDateTimeValue(next), true, false);
341
+ },
342
+ get value() {
343
+ return value ? new Date(value.getTime()) : null;
344
+ },
345
+ get isOpen() {
346
+ return popover.isOpen;
347
+ },
348
+ destroy: () => scope.dispose(),
349
+ };
350
+ }
@@ -0,0 +1,54 @@
1
+ 'use client';
2
+ import { useRef, type HTMLAttributes } from 'react';
3
+ import { useIsomorphicLayoutEffect, useLatest } from '../../react/use-recipe';
4
+ import type { DateInput } from '../../core/dates';
5
+ import { createDateTimePicker, dateTimeKey, toDateTimeValue, type DateTimePickerInstance, type DateTimePickerOptions } from './engine';
6
+
7
+ export interface DateTimePickerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'>, Omit<DateTimePickerOptions, 'value'> {
8
+ /** Controlled value (Date or 'YYYY-MM-DDTHH:MM'); without it the picker keeps its own (defaultValue). */
9
+ value?: DateInput | null;
10
+ defaultValue?: DateInput | null;
11
+ }
12
+
13
+ const keyOf = (value: DateInput | null | undefined) => {
14
+ const date = toDateTimeValue(value);
15
+ return date ? dateTimeKey(date) : 'null';
16
+ };
17
+
18
+ /** <DateTimePicker value={when} onChange={setWhen} minuteStep={15} />. */
19
+ export function DateTimePicker({ value, defaultValue, min, max, locale, hourCycle, minuteStep, firstDay, unavailable, today, label, name, disabled, onChange, className, ...props }: DateTimePickerProps) {
20
+ const ref = useRef<HTMLDivElement>(null);
21
+ const instance = useRef<DateTimePickerInstance | null>(null);
22
+ const change = useLatest(onChange);
23
+ const test = useLatest(unavailable);
24
+ const start = useRef<DateInput | null>(value !== undefined ? value : (defaultValue ?? null));
25
+ const rules = typeof unavailable === 'function' ? 'function' : JSON.stringify(unavailable ?? null);
26
+ useIsomorphicLayoutEffect(() => {
27
+ const created = createDateTimePicker(ref.current, {
28
+ value: value !== undefined ? value : start.current,
29
+ min,
30
+ max,
31
+ locale,
32
+ hourCycle,
33
+ minuteStep,
34
+ firstDay,
35
+ unavailable: typeof unavailable === 'function' ? (day) => (typeof test.current === 'function' ? test.current(day) : false) : unavailable,
36
+ today,
37
+ label,
38
+ name,
39
+ disabled,
40
+ onChange: (next) => change.current?.(next),
41
+ });
42
+ instance.current = created;
43
+ return () => {
44
+ start.current = created.value;
45
+ created.destroy();
46
+ instance.current = null;
47
+ };
48
+ // eslint-disable-next-line react-hooks/exhaustive-deps
49
+ }, [String(min ?? ''), String(max ?? ''), locale, hourCycle, minuteStep, firstDay, rules, String(today ?? ''), label, name, disabled]);
50
+ useIsomorphicLayoutEffect(() => {
51
+ if (value !== undefined && instance.current && keyOf(value) !== keyOf(instance.current.value)) instance.current.setValue(value);
52
+ }, [keyOf(value)]);
53
+ return <div {...props} ref={ref} className={['mk-date-time-picker', className].filter(Boolean).join(' ')} />;
54
+ }
@@ -1,102 +1,103 @@
1
- # dialog
2
-
3
- El diálogo sobre `<dialog>` nativo (foco atrapado, Escape, capa superior). El botón que lo abre se convierte en el diálogo y al cerrar vuelve a él.
4
-
5
- - **Abrir desde el botón (morph):** la superficie viaja recortada desde el rect del botón en 0.7 s con la curva signature y toma su color en 0.3 s; el contenido crece como grupo desde la caja del botón con blur 8 → 0. El botón se oculta en 80 ms mientras está "dentro".
6
- - **Elementos compartidos:** `data-mk-shared="titulo"` en una pieza del botón y otra del diálogo: el texto vuela de una a otra (0.7 s al abrir, 0.5 s al cerrar).
7
- - **Sin botón en pantalla:** escala .92 → 1 en 0.35 s (`power2.out`).
8
- - **Cerrar:** el diálogo se cierra al instante (el foco vuelve y la página responde) mientras una copia inerte se pliega al botón: forma 0.5 s, contenido con blur → 32 px (`.37,.35,0,1`) y fundido (`.56,.27,0,1`), velo `power3.in`; el botón reaparece 0.3 s tras 0.2 s. Sin botón: escala .9 + blur 32.
9
- - **Líquido** (`variant="liquid"`): dos blobs bajo filtro goo; posición con resorte 144/14 y patada de 2400 px/s, tamaño 0.3 s `cubic(.8,.3,.5,.8)`, radio 0.7 s, contenido `scale 2 → 1` y blur 8 → 0, color 0.4 s tras 0.15 s. Cierre con resorte 130/18.
10
- - **Backdrop:** tinte 0.5 s con la curva signature (`linear()`).
11
- - **Auto-resize:** si el contenido crece o se encoge, la altura se ajusta en 0.45 s (signature).
12
- - **Arrastrar para cerrar:** sigue al puntero a la mitad y encoge (`1 − y/400`); pasados 100 px se cierra donde quedó, si no vuelve con `elastic.out(.5,.5)` 0.5 s. También con la rueda. Ignora controles, áreas con scroll y `[data-mk-no-drag]`.
13
- - **Ventana flotante** (`float="clave"`, escritorio ≥ 680 px): el asa la levanta (la página sigue usable), se mueve con resorte 1100/38 e inercia, se queda dentro de la pantalla, se redimensiona por las esquinas (mín. 320 × 240) y recuerda su sitio. Un clic en el asa la devuelve.
14
- - **Móvil (< 680 px):** pantalla completa, radio 0.
15
-
16
- - **Sheet** (`variant="sheet"`): la hoja sube desde abajo (`y 100% → 0`, 0.72 s `cubic-bezier(.16,1,.3,1)`) y lo marcado con `[data-mk-underlay]` se hunde a escala .98 y opacidad .4 con un resorte 300/30. Al cerrar, una copia inerte cae por debajo de la pantalla y el foco vuelve al instante. No sale del botón. Mientras está abierta, la página no hace scroll.
17
-
18
- ## HTML / Astro
19
-
20
- ```html
21
- <button class="mk-button" data-mk-open="crear">Crear proyecto</button>
22
-
23
- <mk-dialog id="crear" heading="Crear proyecto" description="Se guarda en tu espacio.">
24
- <label class="mk-field"><span class="mk-field__label">Nombre</span><input /></label>
25
- <div data-mk-part="footer">
26
- <button class="mk-button mk-button--text" data-mk-close>Cancelar</button>
27
- <button class="mk-button mk-button--primary">Crear</button>
28
- </div>
29
- </mk-dialog>
30
-
31
- <script>
32
- import { defineElements } from '@yewdiel21/motion-kit/elements';
33
- defineElements(['mk-dialog']);
34
- </script>
35
- ```
36
-
37
- Sin `heading`, tus hijos van dentro tal cual si ya usan partes (`data-mk-part="header|body|footer"`), o dentro de un cuerpo si no. Sobre tu propio `<dialog class="mk-dialog">`: `createDialog(dialog, opciones)`.
38
-
39
- ## React
40
-
41
- ```tsx
42
- <Dialog.Root variant="liquid" onOpenChange={setOpen}>
43
- <Dialog.Trigger className="mk-button">Crear</Dialog.Trigger>
44
- <Dialog.Content>
45
- <Dialog.Header>
46
- <div><Dialog.Title>Crear proyecto</Dialog.Title></div>
47
- <Dialog.Actions><Dialog.Close /></Dialog.Actions>
48
- </Dialog.Header>
49
- <Dialog.Body>…</Dialog.Body>
50
- <Dialog.Footer>…</Dialog.Footer>
51
- </Dialog.Content>
52
- </Dialog.Root>
53
- ```
54
-
55
- Las opciones van en `Dialog.Root` (`variant`, `placement`, `float`…). Controlado con `open` + `onOpenChange`, o libre con `defaultOpen`. `Dialog.Trigger` registra su botón como origen.
56
-
57
- ## Opciones
58
-
59
- | Opción | Atributo | Por defecto | Qué hace |
60
- |---|---|---|---|
61
- | `variant` | `variant` | `'morph'` | `'liquid'` para la versión líquida; `'sheet'` para la hoja que sube desde abajo |
62
- | `placement` | `placement` | `'center'` | `'anchor'` junto al botón, `'side'` panel lateral |
63
- | `backdrop` | `no-backdrop` | `true` | Velo tintado |
64
- | `closeOnBackdrop` | `persistent` | `true` | Clic fuera cierra |
65
- | `drag` | `no-drag` | `true` | Arrastrar para cerrar |
66
- | `float` | `float="clave"` | `false` | Ventana flotante (necesita un `[data-mk-part="handle"]`; con `heading` se crea) |
67
- | `autoResize` | — | `true` | Ajuste suave de altura |
68
- | `triggers` | (el `id`) | `true` | `[data-mk-open="<id>"]` lo abre |
69
- | `modal` | — | `true` | Modal o no |
70
- | `labels` | `close-label` | `{ close: 'Cerrar', float, dock }` | Textos accesibles |
71
- | `size` | `size` | `md` (400 px) | `sm` 360, `lg` 640, `xl` 960 |
72
-
73
- ## Sheet
74
-
75
- ```html
76
- <main data-mk-underlay>…la página…</main>
77
- <button class="mk-button" data-mk-open="proyecto">Ver proyecto</button>
78
- <mk-dialog id="proyecto" variant="sheet" heading="Private Space">…</mk-dialog>
79
- ```
80
-
81
- ```tsx
82
- <Dialog.Root variant="sheet">
83
- <Dialog.Trigger>Ver proyecto</Dialog.Trigger>
84
- <Dialog.Content>…</Dialog.Content>
85
- </Dialog.Root>
86
- ```
87
-
88
- Ancho hasta `--mk-sheet-max-width` (720px), alto hasta `100dvh − 24px`, radio solo arriba; en el móvil ocupa todo el ancho. Se cierra con Escape, con el fondo, arrastrando hacia abajo o con `[data-mk-close]`. Con movimiento reducido aparece y desaparece sin animar y la página de detrás no cambia. Funciones sueltas: `sheetOpen`, `sheetClose`, `pushUnderlay`, `releaseUnderlay`.
89
-
90
- ## Controles y eventos
91
-
92
- `open(origen?)`, `close()`, `toggle(origen?)`, `float()`, `dock()`, `isOpen`, `isFloating`, `destroy()`.
93
- Eventos que burbujean desde el `<dialog>`: `mk:open` (`detail.origin`), `mk:close` (cancelable; `detail.inPlace` tras un arrastre), `mk:closed`.
94
- Cualquier `[data-mk-part="close"]` o `[data-mk-close]` dentro lo cierra.
95
-
96
- ## Variables CSS
97
-
98
- `--mk-dialog-bg` (surface-2), `--mk-dialog-radius` (40px), `--mk-dialog-width` (400px), `--mk-dialog-padding` (24px), `--mk-dialog-shadow`.
99
-
100
- ## Accesibilidad
101
-
102
- `<dialog>` nativo: foco atrapado, Escape, fondo inerte. El título (`data-mk-part="title"`) nombra el diálogo y la descripción lo describe. El foco va al primer campo al abrir y vuelve al botón al cerrar. Con movimiento reducido abre y cierra sin viaje ni arrastre.
1
+ # dialog
2
+
3
+ El diálogo sobre `<dialog>` nativo (foco atrapado, Escape, capa superior). El botón que lo abre se convierte en el diálogo y al cerrar vuelve a él.
4
+
5
+ - **Abrir desde el botón (morph):** la superficie viaja recortada desde el rect del botón en 0.7 s con la curva signature y toma su color en 0.3 s; el contenido crece como grupo desde la caja del botón con blur 8 → 0. El botón se oculta en 80 ms mientras está "dentro".
6
+ - **Elementos compartidos:** `data-mk-shared="titulo"` en una pieza del botón y otra del diálogo: el texto vuela de una a otra (0.7 s al abrir, 0.5 s al cerrar).
7
+ - **Sin botón en pantalla:** escala .92 → 1 en 0.35 s (`power2.out`).
8
+ - **Cerrar:** el diálogo se cierra al instante (el foco vuelve y la página responde) mientras una copia inerte se pliega al botón: forma 0.5 s, contenido con blur → 32 px (`.37,.35,0,1`) y fundido (`.56,.27,0,1`), velo `power3.in`; el botón reaparece 0.3 s tras 0.2 s. Sin botón: escala .9 + blur 32.
9
+ - **Líquido** (`variant="liquid"`): dos blobs bajo filtro goo; posición con resorte 144/14 y patada de 2400 px/s, tamaño 0.3 s `cubic(.8,.3,.5,.8)`, radio 0.7 s, contenido `scale 2 → 1` y blur 8 → 0, color 0.4 s tras 0.15 s. Cierre con resorte 130/18.
10
+ - **Backdrop:** tinte 0.5 s con la curva signature (`linear()`).
11
+ - **Auto-resize:** si el contenido crece o se encoge, la altura se ajusta en 0.45 s (signature).
12
+ - **Arrastrar para cerrar:** sigue al puntero a la mitad y encoge (`1 − y/400`); pasados 100 px se cierra donde quedó, si no vuelve con `elastic.out(.5,.5)` 0.5 s. También con la rueda. Ignora controles, áreas con scroll y `[data-mk-no-drag]`.
13
+ - **Ventana flotante** (`float="clave"`, escritorio ≥ 680 px): el asa la levanta (la página sigue usable), se mueve con resorte 1100/38 e inercia, se queda dentro de la pantalla, se redimensiona por las esquinas (mín. 320 × 240) y recuerda su sitio. Un clic en el asa la devuelve.
14
+ - **Móvil (< 680 px):** pantalla completa, radio 0.
15
+
16
+ - **Sheet** (`variant="sheet"`): la hoja sube desde abajo (`y 100% → 0`, 0.72 s `cubic-bezier(.16,1,.3,1)`) y lo marcado con `[data-mk-underlay]` se hunde a escala .98 y opacidad .4 con un resorte 300/30. Al cerrar, una copia inerte cae por debajo de la pantalla y el foco vuelve al instante. No sale del botón. Mientras está abierta, la página no hace scroll.
17
+
18
+ ## HTML / Astro
19
+
20
+ ```html
21
+ <button class="mk-button" data-mk-open="crear">Crear proyecto</button>
22
+
23
+ <mk-dialog id="crear" heading="Crear proyecto" description="Se guarda en tu espacio.">
24
+ <label class="mk-field"><span class="mk-field__label">Nombre</span><input /></label>
25
+ <div data-mk-part="footer">
26
+ <button class="mk-button mk-button--text" data-mk-close>Cancelar</button>
27
+ <button class="mk-button mk-button--primary">Crear</button>
28
+ </div>
29
+ </mk-dialog>
30
+
31
+ <script>
32
+ import { defineElements } from '@yewdiel21/motion-kit/elements';
33
+ defineElements(['mk-dialog']);
34
+ </script>
35
+ ```
36
+
37
+ Sin `heading`, tus hijos van dentro tal cual si ya usan partes (`data-mk-part="header|body|footer"`), o dentro de un cuerpo si no. Sobre tu propio `<dialog class="mk-dialog">`: `createDialog(dialog, opciones)`.
38
+
39
+ ## React
40
+
41
+ ```tsx
42
+ <Dialog.Root variant="liquid" onOpenChange={setOpen}>
43
+ <Dialog.Trigger className="mk-button">Crear</Dialog.Trigger>
44
+ <Dialog.Content>
45
+ <Dialog.Header>
46
+ <div><Dialog.Title>Crear proyecto</Dialog.Title></div>
47
+ <Dialog.Actions><Dialog.Close /></Dialog.Actions>
48
+ </Dialog.Header>
49
+ <Dialog.Body>…</Dialog.Body>
50
+ <Dialog.Footer>…</Dialog.Footer>
51
+ </Dialog.Content>
52
+ </Dialog.Root>
53
+ ```
54
+
55
+ Las opciones van en `Dialog.Root` (`variant`, `placement`, `float`…). Controlado con `open` + `onOpenChange`, o libre con `defaultOpen`. `Dialog.Trigger` registra su botón como origen.
56
+
57
+ ## Opciones
58
+
59
+ | Opción | Atributo | Por defecto | Qué hace |
60
+ |---|---|---|---|
61
+ | `variant` | `variant` | `'morph'` | `'liquid'` para la versión líquida; `'sheet'` para la hoja que sube desde abajo; `'drawer'` desliza desde su lado (`data-mk-drawer`, ver [drawer](../drawer/README.md)) |
62
+ | `placement` | `placement` | `'center'` | `'anchor'` junto al botón, `'side'` panel lateral |
63
+ | `anchor` | — | caja del origen | Con `placement: 'anchor'`, función que devuelve la caja (`DOMRect`) junto a la que se coloca; se lee al abrir y al redimensionar ([context-menu](../context-menu/README.md) la usa para el puntero) |
64
+ | `backdrop` | `no-backdrop` | `true` | Velo tintado |
65
+ | `closeOnBackdrop` | `persistent` | `true` | Clic fuera cierra |
66
+ | `drag` | `no-drag` | `true` | Arrastrar para cerrar |
67
+ | `float` | `float="clave"` | `false` | Ventana flotante (necesita un `[data-mk-part="handle"]`; con `heading` se crea) |
68
+ | `autoResize` | — | `true` | Ajuste suave de altura |
69
+ | `triggers` | (el `id`) | `true` | `[data-mk-open="<id>"]` lo abre |
70
+ | `modal` | — | `true` | Modal o no |
71
+ | `labels` | `close-label` | `{ close: 'Cerrar', float, dock }` | Textos accesibles |
72
+ | `size` | `size` | `md` (400 px) | `sm` 360, `lg` 640, `xl` 960 |
73
+
74
+ ## Sheet
75
+
76
+ ```html
77
+ <main data-mk-underlay>…la página…</main>
78
+ <button class="mk-button" data-mk-open="proyecto">Ver proyecto</button>
79
+ <mk-dialog id="proyecto" variant="sheet" heading="Private Space">…</mk-dialog>
80
+ ```
81
+
82
+ ```tsx
83
+ <Dialog.Root variant="sheet">
84
+ <Dialog.Trigger>Ver proyecto</Dialog.Trigger>
85
+ <Dialog.Content>…</Dialog.Content>
86
+ </Dialog.Root>
87
+ ```
88
+
89
+ Ancho hasta `--mk-sheet-max-width` (720px), alto hasta `100dvh − 24px`, radio solo arriba; en el móvil ocupa todo el ancho. Se cierra con Escape, con el fondo, arrastrando hacia abajo o con `[data-mk-close]`. Con movimiento reducido aparece y desaparece sin animar y la página de detrás no cambia. Funciones sueltas: `sheetOpen`, `sheetClose`, `pushUnderlay`, `releaseUnderlay`.
90
+
91
+ ## Controles y eventos
92
+
93
+ `open(origen?)`, `close()`, `toggle(origen?)`, `float()`, `dock()`, `isOpen`, `isFloating`, `destroy()`.
94
+ Eventos que burbujean desde el `<dialog>`: `mk:open` (`detail.origin`), `mk:close` (cancelable; `detail.inPlace` tras un arrastre), `mk:closed`.
95
+ Cualquier `[data-mk-part="close"]` o `[data-mk-close]` dentro lo cierra.
96
+
97
+ ## Variables CSS
98
+
99
+ `--mk-dialog-bg` (surface-2), `--mk-dialog-radius` (40px), `--mk-dialog-width` (400px), `--mk-dialog-padding` (24px), `--mk-dialog-shadow`.
100
+
101
+ ## Accesibilidad
102
+
103
+ `<dialog>` nativo: foco atrapado, Escape, fondo inerte. El título (`data-mk-part="title"`) nombra el diálogo y la descripción lo describe. El foco va al primer campo al abrir y vuelve al botón al cerrar. Con movimiento reducido abre y cierra sin viaje ni arrastre.