@yewdiel21/motion-kit 0.10.0 → 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 (365) hide show
  1. package/README.md +155 -93
  2. package/dist/auto/index.d.ts +53 -3
  3. package/dist/auto/index.js +101 -3
  4. package/dist/auto/index.js.map +1 -1
  5. package/dist/{chunk-IKQ5FODN.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-XAKC2QY7.js → chunk-EY4BJKC4.js} +3 -28
  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/chart-tooltip.css +168 -0
  17. package/dist/css/components/chart.css +296 -0
  18. package/dist/css/components/code-block.css +264 -0
  19. package/dist/css/components/color-area.css +82 -0
  20. package/dist/css/components/color-field.css +67 -0
  21. package/dist/css/components/color-picker.css +131 -0
  22. package/dist/css/components/color-slider.css +113 -0
  23. package/dist/css/components/command-search.css +252 -0
  24. package/dist/css/components/context-menu.css +23 -0
  25. package/dist/css/components/credit-card.css +288 -0
  26. package/dist/css/components/data-table.css +591 -0
  27. package/dist/css/components/date-range-picker.css +168 -0
  28. package/dist/css/components/date-time-picker.css +178 -0
  29. package/dist/css/components/drawer.css +58 -0
  30. package/dist/css/components/editable-table.css +201 -0
  31. package/dist/css/components/empty-state.css +61 -0
  32. package/dist/css/components/file-explorer.css +633 -0
  33. package/dist/css/components/filter-builder.css +232 -0
  34. package/dist/css/components/hold-confirm.css +87 -0
  35. package/dist/css/components/hover-card.css +13 -7
  36. package/dist/css/components/image-preview.css +195 -0
  37. package/dist/css/components/json-viewer.css +272 -0
  38. package/dist/css/components/like-button.css +78 -0
  39. package/dist/css/components/link-preview.css +275 -0
  40. package/dist/css/components/loading-button.css +77 -0
  41. package/dist/css/components/multi-select.css +267 -0
  42. package/dist/css/components/notification-bell.css +127 -0
  43. package/dist/css/components/password-strength.css +183 -0
  44. package/dist/css/components/popover.css +25 -0
  45. package/dist/css/components/progress.css +140 -0
  46. package/dist/css/components/questionnaire.css +217 -0
  47. package/dist/css/components/range-calendar.css +186 -0
  48. package/dist/css/components/range-slider.css +192 -0
  49. package/dist/css/components/resizable-panel.css +243 -0
  50. package/dist/css/components/rich-text-editor.css +284 -0
  51. package/dist/css/components/scratch-card.css +75 -0
  52. package/dist/css/components/skeleton.css +108 -0
  53. package/dist/css/components/split-view.css +19 -0
  54. package/dist/css/components/star-rating.css +80 -0
  55. package/dist/css/components/stat-card.css +164 -0
  56. package/dist/css/components/swipe-actions.css +105 -0
  57. package/dist/css/components/tag-input.css +244 -0
  58. package/dist/css/components/time-field.css +88 -0
  59. package/dist/css/components/timeline.css +219 -0
  60. package/dist/css/components/tooltip.css +79 -0
  61. package/dist/css/components/tree-view.css +210 -0
  62. package/dist/css/components/virtual-list.css +195 -0
  63. package/dist/css/tokens.css +185 -181
  64. package/dist/elements/index.d.ts +674 -5
  65. package/dist/elements/index.js +1361 -8
  66. package/dist/elements/index.js.map +1 -1
  67. package/dist/{engine-GDGwQnJE.d.ts → engine-Cn6IhE3z.d.ts} +1 -1
  68. package/dist/engine-QECQnGz1.d.ts +33 -0
  69. package/dist/index.css +9104 -189
  70. package/dist/index.d.ts +89 -5
  71. package/dist/index.js +243 -9
  72. package/dist/index.js.map +1 -1
  73. package/dist/react/index.d.ts +579 -23
  74. package/dist/react/index.js +2042 -7
  75. package/dist/react/index.js.map +1 -1
  76. package/dist/{reduced-BmBzKH94.d.ts → reduced-BBUusld6.d.ts} +9 -2
  77. package/dist/reveal-DEvp6U6T.d.ts +2381 -0
  78. package/dist/{store-DYb3tTsZ.d.ts → store-DjkTBX7f.d.ts} +2 -2
  79. package/package.json +1 -1
  80. package/registry.json +406 -1
  81. package/src/auto/auto-init.ts +98 -0
  82. package/src/components/activity-feed/README.md +56 -0
  83. package/src/components/activity-feed/activity-feed.css +239 -0
  84. package/src/components/activity-feed/element.ts +36 -0
  85. package/src/components/activity-feed/engine.ts +351 -0
  86. package/src/components/activity-feed/react.tsx +32 -0
  87. package/src/components/attachment/README.md +27 -0
  88. package/src/components/attachment/attachment.css +265 -0
  89. package/src/components/attachment/element.ts +50 -0
  90. package/src/components/attachment/engine.ts +469 -0
  91. package/src/components/attachment/react.tsx +65 -0
  92. package/src/components/breadcrumb/README.md +38 -0
  93. package/src/components/breadcrumb/breadcrumb.css +109 -0
  94. package/src/components/breadcrumb/element.ts +27 -0
  95. package/src/components/breadcrumb/engine.ts +249 -0
  96. package/src/components/breadcrumb/react.tsx +30 -0
  97. package/src/components/chart/README.md +24 -0
  98. package/src/components/chart/chart.css +295 -0
  99. package/src/components/chart/element.ts +41 -0
  100. package/src/components/chart/engine.ts +811 -0
  101. package/src/components/chart/react.tsx +50 -0
  102. package/src/components/chart-tooltip/README.md +53 -0
  103. package/src/components/chart-tooltip/chart-tooltip.css +167 -0
  104. package/src/components/chart-tooltip/element.ts +37 -0
  105. package/src/components/chart-tooltip/engine.ts +442 -0
  106. package/src/components/chart-tooltip/react.tsx +47 -0
  107. package/src/components/code-block/README.md +19 -0
  108. package/src/components/code-block/code-block.css +263 -0
  109. package/src/components/code-block/element.ts +34 -0
  110. package/src/components/code-block/engine.ts +254 -0
  111. package/src/components/code-block/highlight.ts +244 -0
  112. package/src/components/code-block/react.tsx +94 -0
  113. package/src/components/color-area/README.md +50 -0
  114. package/src/components/color-area/color-area.css +81 -0
  115. package/src/components/color-area/element.ts +26 -0
  116. package/src/components/color-area/engine.ts +246 -0
  117. package/src/components/color-area/react.tsx +42 -0
  118. package/src/components/color-field/README.md +43 -0
  119. package/src/components/color-field/color-field.css +66 -0
  120. package/src/components/color-field/element.ts +26 -0
  121. package/src/components/color-field/engine.ts +174 -0
  122. package/src/components/color-field/react.tsx +42 -0
  123. package/src/components/color-picker/README.md +45 -0
  124. package/src/components/color-picker/color-picker.css +130 -0
  125. package/src/components/color-picker/element.ts +45 -0
  126. package/src/components/color-picker/engine.ts +314 -0
  127. package/src/components/color-picker/react.tsx +47 -0
  128. package/src/components/color-slider/README.md +55 -0
  129. package/src/components/color-slider/color-slider.css +112 -0
  130. package/src/components/color-slider/element.ts +26 -0
  131. package/src/components/color-slider/engine.ts +234 -0
  132. package/src/components/color-slider/react.tsx +45 -0
  133. package/src/components/command-search/README.md +15 -0
  134. package/src/components/command-search/command-search.css +251 -0
  135. package/src/components/command-search/element.ts +36 -0
  136. package/src/components/command-search/engine.ts +356 -0
  137. package/src/components/command-search/match.ts +53 -0
  138. package/src/components/command-search/react.tsx +66 -0
  139. package/src/components/context-menu/README.md +31 -0
  140. package/src/components/context-menu/context-menu.css +22 -0
  141. package/src/components/context-menu/element.ts +40 -0
  142. package/src/components/context-menu/engine.ts +153 -0
  143. package/src/components/context-menu/react.tsx +57 -0
  144. package/src/components/credit-card/README.md +20 -0
  145. package/src/components/credit-card/card.ts +77 -0
  146. package/src/components/credit-card/credit-card.css +287 -0
  147. package/src/components/credit-card/element.ts +33 -0
  148. package/src/components/credit-card/engine.ts +410 -0
  149. package/src/components/credit-card/react.tsx +36 -0
  150. package/src/components/data-table/README.md +83 -0
  151. package/src/components/data-table/data-table.css +590 -0
  152. package/src/components/data-table/element.ts +54 -0
  153. package/src/components/data-table/engine.ts +1059 -0
  154. package/src/components/data-table/react.tsx +94 -0
  155. package/src/components/date-range-picker/README.md +51 -0
  156. package/src/components/date-range-picker/date-range-picker.css +167 -0
  157. package/src/components/date-range-picker/element.ts +52 -0
  158. package/src/components/date-range-picker/engine.ts +352 -0
  159. package/src/components/date-range-picker/react.tsx +57 -0
  160. package/src/components/date-time-picker/README.md +48 -0
  161. package/src/components/date-time-picker/date-time-picker.css +177 -0
  162. package/src/components/date-time-picker/element.ts +47 -0
  163. package/src/components/date-time-picker/engine.ts +350 -0
  164. package/src/components/date-time-picker/react.tsx +54 -0
  165. package/src/components/dialog/README.md +103 -102
  166. package/src/components/dialog/element.ts +123 -118
  167. package/src/components/dialog/engine.ts +449 -432
  168. package/src/components/drawer/README.md +28 -0
  169. package/src/components/drawer/drawer.css +57 -0
  170. package/src/components/drawer/element.ts +21 -0
  171. package/src/components/drawer/engine.ts +56 -0
  172. package/src/components/drawer/react.tsx +85 -0
  173. package/src/components/editable-table/README.md +67 -0
  174. package/src/components/editable-table/editable-table.css +200 -0
  175. package/src/components/editable-table/element.ts +45 -0
  176. package/src/components/editable-table/engine.ts +775 -0
  177. package/src/components/editable-table/react.tsx +79 -0
  178. package/src/components/empty-state/README.md +41 -0
  179. package/src/components/empty-state/element.ts +23 -0
  180. package/src/components/empty-state/empty-state.css +60 -0
  181. package/src/components/empty-state/engine.ts +232 -0
  182. package/src/components/empty-state/react.tsx +34 -0
  183. package/src/components/file-explorer/README.md +67 -0
  184. package/src/components/file-explorer/element.ts +39 -0
  185. package/src/components/file-explorer/engine.ts +1307 -0
  186. package/src/components/file-explorer/file-explorer.css +632 -0
  187. package/src/components/file-explorer/react.tsx +77 -0
  188. package/src/components/filter-builder/README.md +47 -0
  189. package/src/components/filter-builder/element.ts +34 -0
  190. package/src/components/filter-builder/engine.ts +365 -0
  191. package/src/components/filter-builder/filter-builder.css +231 -0
  192. package/src/components/filter-builder/react.tsx +36 -0
  193. package/src/components/hold-confirm/README.md +13 -0
  194. package/src/components/hold-confirm/element.ts +24 -0
  195. package/src/components/hold-confirm/engine.ts +216 -0
  196. package/src/components/hold-confirm/hold-confirm.css +86 -0
  197. package/src/components/hold-confirm/react.tsx +28 -0
  198. package/src/components/hover-card/README.md +6 -2
  199. package/src/components/hover-card/engine.ts +68 -6
  200. package/src/components/hover-card/hover-card.css +13 -7
  201. package/src/components/image-preview/README.md +16 -0
  202. package/src/components/image-preview/element.ts +26 -0
  203. package/src/components/image-preview/engine.ts +325 -0
  204. package/src/components/image-preview/image-preview.css +194 -0
  205. package/src/components/image-preview/react.tsx +43 -0
  206. package/src/components/json-viewer/README.md +56 -0
  207. package/src/components/json-viewer/element.ts +37 -0
  208. package/src/components/json-viewer/engine.ts +440 -0
  209. package/src/components/json-viewer/json-viewer.css +271 -0
  210. package/src/components/json-viewer/react.tsx +56 -0
  211. package/src/components/like-button/README.md +13 -0
  212. package/src/components/like-button/element.ts +47 -0
  213. package/src/components/like-button/engine.ts +145 -0
  214. package/src/components/like-button/like-button.css +77 -0
  215. package/src/components/like-button/react.tsx +39 -0
  216. package/src/components/link-preview/README.md +19 -0
  217. package/src/components/link-preview/element.ts +29 -0
  218. package/src/components/link-preview/engine.ts +192 -0
  219. package/src/components/link-preview/link-preview.css +274 -0
  220. package/src/components/link-preview/react.tsx +101 -0
  221. package/src/components/loading-button/README.md +45 -0
  222. package/src/components/loading-button/element.ts +34 -0
  223. package/src/components/loading-button/engine.ts +201 -0
  224. package/src/components/loading-button/loading-button.css +76 -0
  225. package/src/components/loading-button/react.tsx +43 -0
  226. package/src/components/multi-select/README.md +48 -0
  227. package/src/components/multi-select/element.ts +28 -0
  228. package/src/components/multi-select/engine.ts +294 -0
  229. package/src/components/multi-select/multi-select.css +266 -0
  230. package/src/components/multi-select/react.tsx +39 -0
  231. package/src/components/notification-bell/README.md +14 -0
  232. package/src/components/notification-bell/element.ts +48 -0
  233. package/src/components/notification-bell/engine.ts +202 -0
  234. package/src/components/notification-bell/notification-bell.css +126 -0
  235. package/src/components/notification-bell/react.tsx +57 -0
  236. package/src/components/password-strength/README.md +17 -0
  237. package/src/components/password-strength/element.ts +22 -0
  238. package/src/components/password-strength/engine.ts +212 -0
  239. package/src/components/password-strength/password-strength.css +182 -0
  240. package/src/components/password-strength/react.tsx +36 -0
  241. package/src/components/password-strength/score.ts +62 -0
  242. package/src/components/popover/README.md +44 -0
  243. package/src/components/popover/element.ts +31 -0
  244. package/src/components/popover/engine.ts +114 -0
  245. package/src/components/popover/popover.css +24 -0
  246. package/src/components/popover/react.tsx +50 -0
  247. package/src/components/progress/README.md +17 -0
  248. package/src/components/progress/element.ts +30 -0
  249. package/src/components/progress/engine.ts +173 -0
  250. package/src/components/progress/progress.css +139 -0
  251. package/src/components/progress/react.tsx +35 -0
  252. package/src/components/questionnaire/README.md +32 -0
  253. package/src/components/questionnaire/element.ts +118 -0
  254. package/src/components/questionnaire/engine.ts +255 -0
  255. package/src/components/questionnaire/questionnaire.css +216 -0
  256. package/src/components/questionnaire/react.tsx +140 -0
  257. package/src/components/range-calendar/README.md +58 -0
  258. package/src/components/range-calendar/element.ts +42 -0
  259. package/src/components/range-calendar/engine.ts +390 -0
  260. package/src/components/range-calendar/range-calendar.css +185 -0
  261. package/src/components/range-calendar/react.tsx +56 -0
  262. package/src/components/range-slider/README.md +23 -0
  263. package/src/components/range-slider/element.ts +53 -0
  264. package/src/components/range-slider/engine.ts +316 -0
  265. package/src/components/range-slider/range-slider.css +191 -0
  266. package/src/components/range-slider/react.tsx +66 -0
  267. package/src/components/resizable-panel/README.md +61 -0
  268. package/src/components/resizable-panel/element.ts +36 -0
  269. package/src/components/resizable-panel/engine.ts +551 -0
  270. package/src/components/resizable-panel/react.tsx +74 -0
  271. package/src/components/resizable-panel/resizable-panel.css +242 -0
  272. package/src/components/rich-text-editor/README.md +57 -0
  273. package/src/components/rich-text-editor/element.ts +34 -0
  274. package/src/components/rich-text-editor/engine.ts +673 -0
  275. package/src/components/rich-text-editor/react.tsx +60 -0
  276. package/src/components/rich-text-editor/rich-text-editor.css +283 -0
  277. package/src/components/scratch-card/README.md +15 -0
  278. package/src/components/scratch-card/element.ts +30 -0
  279. package/src/components/scratch-card/engine.ts +257 -0
  280. package/src/components/scratch-card/react.tsx +40 -0
  281. package/src/components/scratch-card/scratch-card.css +74 -0
  282. package/src/components/skeleton/README.md +15 -0
  283. package/src/components/skeleton/element.ts +32 -0
  284. package/src/components/skeleton/engine.ts +104 -0
  285. package/src/components/skeleton/react.tsx +41 -0
  286. package/src/components/skeleton/skeleton.css +107 -0
  287. package/src/components/split-view/README.md +50 -0
  288. package/src/components/split-view/element.ts +34 -0
  289. package/src/components/split-view/engine.ts +114 -0
  290. package/src/components/split-view/react.tsx +63 -0
  291. package/src/components/split-view/split-view.css +18 -0
  292. package/src/components/star-rating/README.md +14 -0
  293. package/src/components/star-rating/element.ts +26 -0
  294. package/src/components/star-rating/engine.ts +217 -0
  295. package/src/components/star-rating/react.tsx +33 -0
  296. package/src/components/star-rating/star-rating.css +79 -0
  297. package/src/components/stat-card/README.md +42 -0
  298. package/src/components/stat-card/element.ts +40 -0
  299. package/src/components/stat-card/engine.ts +283 -0
  300. package/src/components/stat-card/react.tsx +36 -0
  301. package/src/components/stat-card/stat-card.css +163 -0
  302. package/src/components/swipe-actions/README.md +19 -0
  303. package/src/components/swipe-actions/element.ts +26 -0
  304. package/src/components/swipe-actions/engine.ts +260 -0
  305. package/src/components/swipe-actions/react.tsx +80 -0
  306. package/src/components/swipe-actions/swipe-actions.css +104 -0
  307. package/src/components/tag-input/README.md +42 -0
  308. package/src/components/tag-input/element.ts +39 -0
  309. package/src/components/tag-input/engine.ts +313 -0
  310. package/src/components/tag-input/react.tsx +54 -0
  311. package/src/components/tag-input/tag-input.css +243 -0
  312. package/src/components/time-field/README.md +54 -0
  313. package/src/components/time-field/element.ts +38 -0
  314. package/src/components/time-field/engine.ts +110 -0
  315. package/src/components/time-field/react.tsx +45 -0
  316. package/src/components/time-field/time-field.css +87 -0
  317. package/src/components/timeline/README.md +57 -0
  318. package/src/components/timeline/element.ts +31 -0
  319. package/src/components/timeline/engine.ts +300 -0
  320. package/src/components/timeline/react.tsx +59 -0
  321. package/src/components/timeline/timeline.css +218 -0
  322. package/src/components/tooltip/README.md +46 -0
  323. package/src/components/tooltip/element.ts +22 -0
  324. package/src/components/tooltip/engine.ts +288 -0
  325. package/src/components/tooltip/react.tsx +30 -0
  326. package/src/components/tooltip/tooltip.css +78 -0
  327. package/src/components/tree-view/README.md +61 -0
  328. package/src/components/tree-view/element.ts +32 -0
  329. package/src/components/tree-view/engine.ts +569 -0
  330. package/src/components/tree-view/react.tsx +78 -0
  331. package/src/components/tree-view/tree-view.css +209 -0
  332. package/src/components/virtual-list/README.md +81 -0
  333. package/src/components/virtual-list/element.ts +42 -0
  334. package/src/components/virtual-list/engine.ts +678 -0
  335. package/src/components/virtual-list/react.tsx +101 -0
  336. package/src/components/virtual-list/virtual-list.css +194 -0
  337. package/src/core/chips.ts +196 -0
  338. package/src/core/color.ts +304 -0
  339. package/src/core/date-range.ts +67 -0
  340. package/src/core/dates.ts +11 -1
  341. package/src/core/files.ts +107 -0
  342. package/src/core/filter.ts +229 -0
  343. package/src/core/gsap.ts +80 -65
  344. package/src/core/listbox.ts +332 -0
  345. package/src/core/mark.ts +29 -0
  346. package/src/core/position.ts +89 -0
  347. package/src/core/relative-time.ts +77 -0
  348. package/src/core/segment-field.ts +373 -0
  349. package/src/core/segments.ts +153 -0
  350. package/src/core/tree.ts +116 -0
  351. package/src/core/virtual.ts +79 -0
  352. package/src/css/tokens.css +186 -182
  353. package/src/elements/index.ts +147 -0
  354. package/src/index.ts +72 -0
  355. package/src/motion/micro.ts +248 -0
  356. package/src/motion/sheet.ts +88 -65
  357. package/src/motion/surface.ts +9 -0
  358. package/src/react/index.ts +57 -0
  359. package/dist/chunk-IKQ5FODN.js.map +0 -1
  360. package/dist/chunk-J6OCFNGU.js +0 -177
  361. package/dist/chunk-J6OCFNGU.js.map +0 -1
  362. package/dist/chunk-TFNRIZHU.js +0 -3977
  363. package/dist/chunk-TFNRIZHU.js.map +0 -1
  364. package/dist/chunk-XAKC2QY7.js.map +0 -1
  365. package/dist/reveal-jsX-uwUz.d.ts +0 -625
@@ -1,3977 +0,0 @@
1
- import {
2
- TIMING,
3
- createScope,
4
- reduced
5
- } from "./chunk-DOOMULVV.js";
6
- import {
7
- inert,
8
- warnOnce
9
- } from "./chunk-TGV27ZWM.js";
10
-
11
- // src/core/curves.ts
12
- var PATHS = {
13
- /** The signature: a strong deceleration that is not a plain ease-out. */
14
- signature: "M0,0 C0.308,0.19 0.107,0.633 0.288,0.866 0.382,0.987 0.656,1 1,1",
15
- /** Lists and steps entering (`flowSoft`, also `numberSoft`). */
16
- flow: "M0,0 C0.25,0.1 0.25,1 1,1",
17
- /** A conversation scrolling to its newest message. */
18
- chatScroll: "M0,0 C0.308,0.19 0.318,0.567 0.5,0.8 0.593,0.921 0.656,1 1,1"
19
- };
20
- function springPath(ratio, velocity = 0, steps = 72) {
21
- const damping = Math.min(Math.max(ratio, 0.05), 0.999);
22
- const stiffness = 5.6;
23
- const frequency = stiffness / damping * Math.sqrt(1 - damping * damping);
24
- const phase = (velocity - stiffness) / frequency;
25
- const at = (time2) => 1 + Math.exp(-stiffness * time2) * (-Math.cos(frequency * time2) + phase * Math.sin(frequency * time2));
26
- let path = "M0,0";
27
- for (let step = 1; step <= steps; step += 1) {
28
- const time2 = step / steps;
29
- path += ` L${time2.toFixed(4)},${(step === steps ? 1 : at(time2)).toFixed(4)}`;
30
- }
31
- return path;
32
- }
33
- var SIGNATURE_LINEAR = "linear(0 0%, .017 2.5%, .037 5%, .061 7.5%, .091 10%, .13 12.5%, .184 15%, .275 17.5%, .562 20%, .733 22.5%, .803 25%, .848 27.5%, .88 30%, .902 32.5%, .942 40%, .97 50%, .985 60%, .993 70%, .998 80%, 1 90%, 1 100%)";
34
-
35
- // src/core/gsap.ts
36
- import { gsap } from "gsap";
37
- import { ScrollTrigger } from "gsap/ScrollTrigger";
38
- import { SplitText } from "gsap/SplitText";
39
- import { CustomEase } from "gsap/CustomEase";
40
- import { Flip } from "gsap/Flip";
41
- var ELASTIC = "elastic.out(1, 0.45)";
42
- var EASE = {
43
- signature: "mk-signature",
44
- flow: "mk-flow",
45
- /** A closing surface's fade (`.56,.27,0,1`). Kept from v0.1; same curve as `fadeAway`. */
46
- close: "mk-close",
47
- fadeAway: "mk-fade-away",
48
- /** A closing surface's blur (`.37,.35,0,1`). */
49
- blurAway: "mk-blur-away",
50
- chatScroll: "mk-chat-scroll",
51
- /** Items travelling to a new place in a list (spring ratio .52). */
52
- layoutReflow: "mk-layout-reflow",
53
- /** A dragged item landing in its slot (spring ratio .62). */
54
- sortableLand: "mk-sortable-land",
55
- slot: "mk-slot",
56
- slotResize: "mk-slot-resize",
57
- liquidSize: "mk-liquid-size",
58
- swatch: "mk-swatch",
59
- swatchLight: "mk-swatch-light",
60
- sheet: "mk-sheet",
61
- inOut: "mk-in-out"
62
- };
63
- var CURVES = {
64
- signature: PATHS.signature,
65
- flow: PATHS.flow,
66
- close: ".56,.27,0,1",
67
- fadeAway: ".56,.27,0,1",
68
- blurAway: ".37,.35,0,1",
69
- chatScroll: PATHS.chatScroll,
70
- layoutReflow: springPath(0.52),
71
- sortableLand: springPath(0.62),
72
- slot: ".34,1.56,.64,1",
73
- slotResize: ".2,0,0,1",
74
- liquidSize: ".8,.3,.5,.8",
75
- swatch: ".38,.49,0,1.5",
76
- swatchLight: ".11,1,0,1",
77
- sheet: ".16,1,.3,1",
78
- inOut: ".42,0,.58,1"
79
- };
80
- var registered = false;
81
- function registerMotion() {
82
- if (typeof window === "undefined") return;
83
- document.documentElement.classList.add("mk-ready");
84
- if (registered) return;
85
- registered = true;
86
- gsap.registerPlugin(ScrollTrigger, SplitText, CustomEase, Flip);
87
- for (const key of Object.keys(EASE)) CustomEase.create(EASE[key], CURVES[key]);
88
- }
89
-
90
- // src/core/channels.ts
91
- import { gsap as gsap2 } from "gsap";
92
- var easeOut = (t) => 1 - (1 - t) * (1 - t);
93
- var easeOutCubic = (t) => 1 - (1 - t) ** 3;
94
- var easeInCubic = (t) => t * t * t;
95
- function bezier(x1, y1, x2, y2) {
96
- const at = (t, a, b) => {
97
- const u = 1 - t;
98
- return 3 * u * u * t * a + 3 * u * t * t * b + t * t * t;
99
- };
100
- return (progress) => {
101
- if (progress <= 0 || progress >= 1) return Math.min(1, Math.max(0, progress));
102
- let low = 0;
103
- let high = 1;
104
- let t = progress;
105
- for (let step = 0; step < 24; step += 1) {
106
- const x = at(t, x1, x2);
107
- if (Math.abs(x - progress) < 1e-5) break;
108
- if (x < progress) low = t;
109
- else high = t;
110
- t = (low + high) / 2;
111
- }
112
- return at(t, y1, y2);
113
- };
114
- }
115
- var spring = (stiffness, damping, extra = {}) => ({
116
- type: "spring",
117
- stiffness,
118
- damping,
119
- ...extra
120
- });
121
- var eased = (duration, ease) => ({ type: "ease", duration, ease });
122
- var createChannelState = (value) => ({
123
- current: value,
124
- origin: value,
125
- target: value,
126
- velocity: 0,
127
- elapsed: 0,
128
- active: false,
129
- config: null
130
- });
131
- function stepChannel(channel, seconds) {
132
- const config = channel.config;
133
- if (!channel.active || !config) return;
134
- if (config.type === "spring") {
135
- const time2 = Math.min(0.064, Math.max(0, seconds));
136
- const steps = Math.max(1, Math.ceil(time2 / (1 / 60) - 1e-9));
137
- const step = time2 / steps;
138
- for (let index = 0; index < steps; index += 1) {
139
- const force = -config.stiffness * (channel.current - channel.target) - config.damping * channel.velocity;
140
- channel.velocity += force / (config.mass ?? 1) * step;
141
- channel.current += channel.velocity * step;
142
- }
143
- if (Math.abs(channel.velocity) <= 0.01 && Math.abs(channel.target - channel.current) <= 0.01) {
144
- channel.current = channel.target;
145
- channel.velocity = 0;
146
- channel.active = false;
147
- }
148
- } else {
149
- channel.elapsed += Math.max(0, seconds);
150
- const progress = Math.min(1, channel.elapsed / config.duration);
151
- channel.current = progress >= 1 ? channel.target : channel.origin + (channel.target - channel.origin) * config.ease(progress);
152
- if (progress >= 1) channel.active = false;
153
- }
154
- }
155
- function channels(start, onChange) {
156
- const names = Object.keys(start);
157
- const state = Object.fromEntries(names.map((name) => [name, createChannelState(start[name])]));
158
- let last = 0;
159
- let resolveDone = null;
160
- const tick = () => {
161
- const now = performance.now();
162
- const elapsed = Math.max(0, (now - last) / 1e3);
163
- last = now;
164
- let running2 = false;
165
- for (const name of names) {
166
- const channel = state[name];
167
- if (!channel.active) continue;
168
- stepChannel(channel, elapsed);
169
- onChange(name, channel.current);
170
- running2 ||= channel.active;
171
- }
172
- if (!running2) {
173
- gsap2.ticker.remove(tick);
174
- resolveDone?.();
175
- resolveDone = null;
176
- }
177
- };
178
- return {
179
- state,
180
- /** Start moving; resolves when every channel has settled (or `stop()` is called). */
181
- animate(targets, configs) {
182
- for (const name of Object.keys(targets)) {
183
- const channel = state[name];
184
- const config = configs[name];
185
- if (!channel || !config) continue;
186
- channel.config = config;
187
- channel.origin = channel.current;
188
- channel.target = targets[name];
189
- channel.elapsed = 0;
190
- if (config.type === "spring" && config.velocity) {
191
- const sign = config.direction !== void 0 ? Math.sign(config.direction) : Math.sign(channel.target - channel.current);
192
- channel.velocity = Math.abs(config.velocity) * sign;
193
- }
194
- channel.active = channel.target !== channel.current || channel.velocity !== 0;
195
- }
196
- last = performance.now();
197
- gsap2.ticker.remove(tick);
198
- gsap2.ticker.add(tick);
199
- resolveDone?.();
200
- return new Promise((resolve) => {
201
- resolveDone = resolve;
202
- });
203
- },
204
- stop() {
205
- gsap2.ticker.remove(tick);
206
- for (const name of names) state[name].active = false;
207
- resolveDone?.();
208
- resolveDone = null;
209
- }
210
- };
211
- }
212
- function springEase(ratio, velocity = 0) {
213
- const damping = Math.min(Math.max(ratio, 0.05), 0.999);
214
- const stiffness = 5.6;
215
- const frequency = stiffness / damping * Math.sqrt(1 - damping * damping);
216
- const phase = (velocity - stiffness) / frequency;
217
- return (progress) => progress >= 1 ? 1 : 1 + Math.exp(-stiffness * progress) * (-Math.cos(frequency * progress) + phase * Math.sin(frequency * progress));
218
- }
219
-
220
- // src/core/split.ts
221
- function splitWords(el, { exclude = ["table", "pre"], className = "mk-split-word" } = {}) {
222
- const parts = [];
223
- const replaced = [];
224
- const skip = exclude.join(",");
225
- const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
226
- const texts = [];
227
- for (let node = walker.nextNode(); node; node = walker.nextNode()) {
228
- const parent = node.parentElement;
229
- if (skip && parent?.closest(skip) && el.contains(parent.closest(skip))) continue;
230
- if (node.data.trim()) texts.push(node);
231
- }
232
- for (const text of texts) {
233
- const pieces = text.data.split(/(\s+)/);
234
- const nodes = [];
235
- for (const piece of pieces) {
236
- if (!piece) continue;
237
- if (/^\s+$/.test(piece)) {
238
- nodes.push(document.createTextNode(piece));
239
- continue;
240
- }
241
- const span = document.createElement("span");
242
- span.className = className;
243
- span.style.display = "inline-block";
244
- span.textContent = piece;
245
- parts.push(span);
246
- nodes.push(span);
247
- }
248
- text.replaceWith(...nodes);
249
- replaced.push([text, nodes]);
250
- }
251
- let reverted = false;
252
- return {
253
- parts,
254
- revert() {
255
- if (reverted) return;
256
- reverted = true;
257
- for (const [text, nodes] of replaced.reverse()) {
258
- nodes[0]?.parentNode?.insertBefore(text, nodes[0]);
259
- for (const node of nodes) node.parentNode?.removeChild(node);
260
- }
261
- el.normalize();
262
- }
263
- };
264
- }
265
- function splitGraphemes(text, limit = 64) {
266
- const Ctor = Intl.Segmenter;
267
- const all = Ctor ? Array.from(new Ctor(void 0, { granularity: "grapheme" }).segment(text), (part2) => part2.segment) : Array.from(text);
268
- return all.slice(0, limit);
269
- }
270
-
271
- // src/core/frame.ts
272
- function requestFrame(fn) {
273
- if (typeof requestAnimationFrame === "function") {
274
- const id2 = requestAnimationFrame(fn);
275
- return () => cancelAnimationFrame(id2);
276
- }
277
- const id = setTimeout(() => fn(Date.now()), 16);
278
- return () => clearTimeout(id);
279
- }
280
- var nextFrame = () => new Promise((resolve) => requestFrame(() => resolve()));
281
-
282
- // src/core/styles.ts
283
- function clearStyles(targets, properties) {
284
- for (const element of targets) {
285
- const style = element.style;
286
- if (!style) continue;
287
- for (const property of properties) style.removeProperty(property);
288
- if (element.getAttribute("style") === "") element.removeAttribute("style");
289
- delete element._gsap;
290
- }
291
- }
292
- var MORPH_STYLES = [
293
- "transform",
294
- "translate",
295
- "rotate",
296
- "scale",
297
- "transform-origin",
298
- "clip-path",
299
- "opacity",
300
- "visibility",
301
- "filter",
302
- "will-change"
303
- ];
304
-
305
- // src/core/physics-spring.ts
306
- var REST = 1e-3;
307
- var STEP = 1 / 240;
308
- var LIMIT = 10;
309
- function position(stiffness, damping, mass) {
310
- const w0 = Math.sqrt(stiffness / mass);
311
- const zeta = damping / (2 * Math.sqrt(stiffness * mass));
312
- if (zeta < 1) {
313
- const wd = w0 * Math.sqrt(1 - zeta * zeta);
314
- return (t) => 1 - Math.exp(-zeta * w0 * t) * (Math.cos(wd * t) + zeta * w0 / wd * Math.sin(wd * t));
315
- }
316
- if (zeta === 1) return (t) => 1 - Math.exp(-w0 * t) * (1 + w0 * t);
317
- const root = Math.sqrt(zeta * zeta - 1);
318
- const r1 = -w0 * (zeta - root);
319
- const r2 = -w0 * (zeta + root);
320
- return (t) => 1 - (r2 * Math.exp(r1 * t) - r1 * Math.exp(r2 * t)) / (r2 - r1);
321
- }
322
- var springs = /* @__PURE__ */ new Map();
323
- function motionSpring(stiffness, damping, mass = 1) {
324
- const key = `${stiffness}/${damping}/${mass}`;
325
- const known = springs.get(key);
326
- if (known) return known;
327
- const x = position(Math.max(stiffness, 1e-6), Math.max(damping, 0), Math.max(mass, 1e-6));
328
- let settled = 0;
329
- for (let i = 0; i * STEP <= LIMIT; i++) if (Math.abs(x(i * STEP) - 1) > REST) settled = (i + 1) * STEP;
330
- const duration = Math.round(Math.min(settled, LIMIT) * 1e3) / 1e3;
331
- const spring2 = {
332
- ease: (progress) => progress <= 0 ? 0 : progress >= 1 ? 1 : x(progress * duration),
333
- duration
334
- };
335
- springs.set(key, spring2);
336
- return spring2;
337
- }
338
- var springDuration = (stiffness, damping, mass = 1) => motionSpring(stiffness, damping, mass).duration;
339
- function springLinear(stiffness, damping, mass = 1, points = 40) {
340
- const { ease } = motionSpring(stiffness, damping, mass);
341
- return `linear(${Array.from({ length: points + 1 }, (_, i) => Number(ease(i / points).toFixed(4))).join(", ")})`;
342
- }
343
-
344
- // src/motion/flow.ts
345
- var CLEAR = "transform,filter,opacity,visibility";
346
- function list(targets, target, reverse) {
347
- let items;
348
- if (target && targets instanceof Element) items = [...targets.querySelectorAll(target)];
349
- else items = gsap.utils.toArray(targets);
350
- return reverse ? items.reverse() : items;
351
- }
352
- function flowIn(targets, options = {}) {
353
- registerMotion();
354
- const {
355
- y = 20,
356
- blur = 16,
357
- duration = TIMING.flow,
358
- stagger = TIMING.flowStagger,
359
- delay = 0,
360
- style = 1,
361
- startScale = 0.9,
362
- reverse = false,
363
- target,
364
- ease = EASE.flow,
365
- autoAlpha = true
366
- } = options;
367
- const items = list(targets, target, reverse);
368
- if (!items.length) return null;
369
- if (reduced()) {
370
- clearStyles(items, ["transform", "translate", "rotate", "scale", "filter", "opacity", "visibility"]);
371
- return null;
372
- }
373
- const from = style === 2 ? { scale: startScale } : { y: -y };
374
- const to = style === 2 ? { scale: 1 } : { y: 0 };
375
- const alpha = autoAlpha ? "autoAlpha" : "opacity";
376
- return gsap.fromTo(
377
- items,
378
- { ...from, [alpha]: 0, filter: `blur(${blur}px)` },
379
- { ...to, [alpha]: 1, filter: "blur(0px)", duration, stagger, delay, ease, clearProps: CLEAR }
380
- );
381
- }
382
- function flowOut(targets, options = {}) {
383
- registerMotion();
384
- const { y = 20, blur = 16, duration = TIMING.flow, stagger = TIMING.flowStagger, delay = 0, reverse = false, target } = options;
385
- const items = list(targets, target, reverse);
386
- if (!items.length) return null;
387
- if (reduced()) {
388
- gsap.set(items, { autoAlpha: 0 });
389
- return null;
390
- }
391
- return gsap.to(items, { y, autoAlpha: 0, filter: `blur(${blur}px)`, duration, stagger, delay, ease: EASE.flow });
392
- }
393
- async function stepChange(container, mutate, { duration = TIMING.stepChange } = {}) {
394
- const before = [...container.children];
395
- const out = flowOut(before, { duration });
396
- if (out) await out;
397
- await mutate();
398
- await nextFrame();
399
- flowIn([...container.children], { duration });
400
- }
401
-
402
- // src/motion/entrances.ts
403
- var flowInMenu = (targets) => flowIn(targets, { style: 2, startScale: 0.9, blur: 4, reverse: true, autoAlpha: false, ...TIMING.menu });
404
- var flowInPalette = (targets) => flowIn(targets, { style: 2, startScale: 0.5, blur: 4, autoAlpha: false, ...TIMING.palette });
405
- var flowInForm = (targets) => flowIn(targets, { style: 2, startScale: 0.9, blur: 8, ...TIMING.form });
406
- var flowInLanding = (targets) => flowIn(targets, { style: 2, startScale: 0.85, blur: 24, ...TIMING.landing });
407
- var flowInContent = (root) => flowIn(root, { style: 2, target: "[data-flow], .markdown-content > *", ...TIMING.content });
408
-
409
- // src/core/pointer.ts
410
- import { gsap as gsap3 } from "gsap";
411
- var pointer = { x: 0, y: 0, active: false };
412
- var mx = 0;
413
- var my = 0;
414
- var lastX = null;
415
- var lastY = null;
416
- var users = 0;
417
- function onMove(e) {
418
- if (lastX !== null && lastY !== null) {
419
- mx += e.clientX - lastX;
420
- my += e.clientY - lastY;
421
- }
422
- lastX = pointer.x = e.clientX;
423
- lastY = pointer.y = e.clientY;
424
- pointer.active = true;
425
- }
426
- function onOut(e) {
427
- if (e.relatedTarget) return;
428
- pointer.active = false;
429
- lastX = lastY = null;
430
- }
431
- function bindPointer() {
432
- if (users++ === 0) {
433
- addEventListener("pointermove", onMove, { passive: true });
434
- document.addEventListener("pointerout", onOut);
435
- }
436
- let released = false;
437
- return () => {
438
- if (released) return;
439
- released = true;
440
- if (--users > 0) return;
441
- removeEventListener("pointermove", onMove);
442
- document.removeEventListener("pointerout", onOut);
443
- pointer.active = false;
444
- lastX = lastY = null;
445
- mx = my = 0;
446
- };
447
- }
448
- var frameMovement = { mx: 0, my: 0 };
449
- var movementFrame = -1;
450
- function takeMovement() {
451
- const frame = gsap3.ticker.frame;
452
- if (frame !== movementFrame) {
453
- movementFrame = frame;
454
- frameMovement = { mx, my };
455
- mx = my = 0;
456
- }
457
- return frameMovement;
458
- }
459
-
460
- // src/motion/reveal.ts
461
- var TRANSPARENT = /^(transparent|rgba\(0, 0, 0, 0\))$/;
462
- function backgroundOf(el) {
463
- for (let node = el; node; node = node.parentElement) {
464
- const color = getComputedStyle(node).backgroundColor;
465
- if (color && !TRANSPARENT.test(color)) return color;
466
- }
467
- return "var(--mk-bg, #fff)";
468
- }
469
- function revealFrom(target, options = {}) {
470
- if (reduced() || !target.isConnected) return null;
471
- registerMotion();
472
- const { speed = "normal", delay = 0, overshoot = 2 } = options;
473
- const style = getComputedStyle(target);
474
- const fill = options.fill ?? backgroundOf(target);
475
- const position2 = target.style.position;
476
- if (style.position === "static") target.style.position = "relative";
477
- const box = target.getBoundingClientRect();
478
- const width = target.clientWidth;
479
- const height = target.clientHeight;
480
- let point = null;
481
- const origin = options.origin;
482
- if (origin instanceof Element) {
483
- if (origin.isConnected) {
484
- const rect = origin.getBoundingClientRect();
485
- point = { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
486
- }
487
- } else if (origin) point = origin;
488
- else if (origin === void 0 && pointer.active) point = { x: pointer.x, y: pointer.y };
489
- const x = point ? point.x - box.left - target.clientLeft : width / 2;
490
- const y = point ? point.y - box.top - target.clientTop : height / 2;
491
- const radius = Math.max(Math.hypot(x, y), Math.hypot(width - x, y), Math.hypot(x, height - y), Math.hypot(width - x, height - y)) * overshoot;
492
- const veil = document.createElement("div");
493
- veil.setAttribute("aria-hidden", "true");
494
- veil.dataset.mkVeil = "";
495
- Object.assign(veil.style, {
496
- position: "absolute",
497
- top: `${target.scrollTop}px`,
498
- left: `${target.scrollLeft}px`,
499
- width: `${width}px`,
500
- height: `${height}px`,
501
- borderRadius: style.borderRadius,
502
- pointerEvents: "none",
503
- zIndex: "1000"
504
- });
505
- const progress = { value: 0 };
506
- const paint = () => {
507
- veil.style.background = `radial-gradient(${radius}px at ${x}px ${y}px, transparent 0%, ${fill} ${progress.value}%)`;
508
- };
509
- paint();
510
- target.append(veil);
511
- let done = false;
512
- let resolve;
513
- const finished = new Promise((r) => resolve = r);
514
- const cleanup = () => {
515
- if (done) return;
516
- done = true;
517
- veil.remove();
518
- target.style.position = position2;
519
- resolve();
520
- };
521
- const [duration, fade] = TIMING.reveal[speed];
522
- const timeline = gsap.timeline({ delay, onComplete: cleanup, onInterrupt: cleanup }).to(progress, { value: 100, duration, ease: "power2.out", onUpdate: paint }, 0).to(veil, { opacity: 0, duration: fade, ease: "power1.out" }, Math.max(0, duration * Math.min(1, 1 / overshoot) - 0.1));
523
- return {
524
- timeline,
525
- finished,
526
- cancel() {
527
- timeline.kill();
528
- cleanup();
529
- }
530
- };
531
- }
532
-
533
- // src/motion/count.ts
534
- var shown = /* @__PURE__ */ new WeakMap();
535
- var tweens = /* @__PURE__ */ new WeakMap();
536
- var frames = /* @__PURE__ */ new WeakMap();
537
- var defaultFormat = (value) => String(Math.round(value));
538
- function current(el) {
539
- const known = shown.get(el);
540
- if (known !== void 0) return known;
541
- const parsed = Number((el.textContent ?? "").replace(/[^\d.-]/g, ""));
542
- return Number.isFinite(parsed) ? parsed : 0;
543
- }
544
- function tweenNumber(from, to, onUpdate, { duration = TIMING.number } = {}) {
545
- registerMotion();
546
- if (from === to || reduced()) {
547
- onUpdate(to);
548
- return null;
549
- }
550
- const state = { value: from };
551
- return gsap.to(state, { value: to, duration, ease: EASE.flow, onUpdate: () => onUpdate(state.value), onComplete: () => onUpdate(to) });
552
- }
553
- function countTo(el, to, { from, duration = TIMING.number, format = defaultFormat } = {}) {
554
- registerMotion();
555
- tweens.get(el)?.kill();
556
- const start = from ?? current(el);
557
- const write = (value) => {
558
- shown.set(el, value);
559
- el.textContent = format(value);
560
- };
561
- if (start === to || reduced()) {
562
- write(to);
563
- return null;
564
- }
565
- const state = { value: start };
566
- const tween = gsap.to(state, {
567
- value: to,
568
- duration,
569
- ease: EASE.flow,
570
- onUpdate: () => write(state.value),
571
- onComplete: () => {
572
- write(to);
573
- tweens.delete(el);
574
- }
575
- });
576
- tweens.set(el, tween);
577
- return tween;
578
- }
579
- function revealCounter(el, to, { from, duration = TIMING.revealCounter, format = defaultFormat } = {}) {
580
- frames.get(el)?.();
581
- const start = from ?? current(el);
582
- const write = (value) => {
583
- shown.set(el, value);
584
- el.textContent = format(value);
585
- };
586
- if (start === to || reduced()) {
587
- write(to);
588
- return () => {
589
- };
590
- }
591
- let began = null;
592
- let cancel = () => {
593
- };
594
- const step = (time2) => {
595
- began ??= time2;
596
- const progress = Math.min(1, (time2 - began) / (duration * 1e3));
597
- write(start + (to - start) * (1 - (1 - progress) ** 3));
598
- if (progress < 1) cancel = requestFrame(step);
599
- else frames.delete(el);
600
- };
601
- cancel = requestFrame(step);
602
- const stop2 = () => cancel();
603
- frames.set(el, stop2);
604
- return stop2;
605
- }
606
-
607
- // src/motion/anchor.ts
608
- var EDGE = 16;
609
- var GAP = 8;
610
- var PHONE = 680;
611
- var PLACED = ["top", "left", "right", "bottom", "margin", "margin-top", "margin-right", "margin-bottom", "margin-left"];
612
- function anchorSurface(surface, origin, viewport) {
613
- const view = viewport ?? { width: innerWidth, height: innerHeight };
614
- if (!origin || view.width < PHONE) {
615
- for (const side of PLACED) surface.style.removeProperty(side);
616
- return;
617
- }
618
- const box = surface.getBoundingClientRect();
619
- const clampLeft = (value) => Math.max(EDGE, Math.min(value, view.width - box.width - EDGE));
620
- const below = origin.bottom + GAP;
621
- const above = origin.top - GAP - box.height;
622
- const lowest = Math.max(EDGE, view.height - box.height - EDGE);
623
- const besideRight = origin.right + GAP;
624
- const besideLeft = origin.left - GAP - box.width;
625
- let top;
626
- let left;
627
- if (below <= lowest) [top, left] = [below, clampLeft(origin.left)];
628
- else if (above >= EDGE) [top, left] = [above, clampLeft(origin.left)];
629
- else if (besideRight + box.width <= view.width - EDGE) [top, left] = [Math.min(Math.max(EDGE, origin.top), lowest), besideRight];
630
- else if (besideLeft >= EDGE) [top, left] = [Math.min(Math.max(EDGE, origin.top), lowest), besideLeft];
631
- else [top, left] = [lowest, clampLeft(origin.left)];
632
- Object.assign(surface.style, { margin: "0", top: `${Math.round(top)}px`, left: `${Math.round(left)}px`, right: "auto", bottom: "auto" });
633
- }
634
- function clearAnchor(surface) {
635
- for (const side of PLACED) surface.style.removeProperty(side);
636
- }
637
-
638
- // src/motion/drag-dismiss.ts
639
- var START = 6;
640
- var FOLLOW = 0.5;
641
- var DISMISS = 100;
642
- var SHRINK = 400;
643
- var WHEEL_SPEED = 1.5;
644
- var WHEEL_MIN = 16;
645
- var WHEEL_IDLE = 90;
646
- var WHEEL_COOLDOWN = 250;
647
- var CONTROLS = [
648
- "a[href]",
649
- "button",
650
- "input",
651
- "select",
652
- "textarea",
653
- "label",
654
- "summary",
655
- '[contenteditable="true"]',
656
- '[role="button"]',
657
- '[role="slider"]',
658
- '[role="combobox"]',
659
- '[role="option"]',
660
- '[role="checkbox"]',
661
- '[role="menuitem"]'
662
- ].join(",");
663
- function scrollerOf(target, surface) {
664
- let element = target instanceof Element ? target : null;
665
- while (element) {
666
- if (element.scrollHeight > element.clientHeight + 1) {
667
- const overflow = getComputedStyle(element).overflowY;
668
- if (overflow === "auto" || overflow === "scroll") return element;
669
- }
670
- if (element === surface) break;
671
- element = element.parentElement;
672
- }
673
- return null;
674
- }
675
- var draggableFrom = (target, surface) => target instanceof Element && !target.closest("[data-mk-no-drag], [popover]") && !target.closest(CONTROLS) && !(surface.querySelector("[data-mk-drag-handle]") && !target.closest("[data-mk-drag-handle]"));
676
- function attachDragDismiss(surface, { canDrag = () => true, onDismiss }) {
677
- registerMotion();
678
- let pointer2 = null;
679
- let startX = 0;
680
- let startY = 0;
681
- let mode = null;
682
- let pulled = 0;
683
- let base = { x: 0, y: 0, scale: 1 };
684
- let target = null;
685
- const noSelect = (event) => event.preventDefault();
686
- const begin = () => {
687
- mode = "drag";
688
- gsap.killTweensOf(surface, "x,y,scale");
689
- base = {
690
- x: Number(gsap.getProperty(surface, "x")) || 0,
691
- y: Number(gsap.getProperty(surface, "y")) || 0,
692
- scale: Number(gsap.getProperty(surface, "scaleX")) || 1
693
- };
694
- window.getSelection?.()?.removeAllRanges();
695
- document.body.style.userSelect = "none";
696
- document.addEventListener("selectstart", noSelect);
697
- };
698
- const follow = (dx, dy) => {
699
- pulled = dy * FOLLOW;
700
- gsap.set(surface, { x: base.x + dx * FOLLOW, y: base.y + pulled, scale: Math.max(0.1, base.scale * (1 - pulled / SHRINK)) });
701
- };
702
- const restore = () => gsap.to(surface, { x: 0, y: 0, scale: 1, duration: TIMING.drag.restore, ease: "elastic.out(0.5,0.5)" });
703
- const release = () => {
704
- document.removeEventListener("selectstart", noSelect);
705
- document.body.style.userSelect = "";
706
- const dismiss = pulled > DISMISS;
707
- mode = null;
708
- pulled = 0;
709
- if (dismiss) onDismiss();
710
- else restore();
711
- };
712
- const onPointerDown = (event) => {
713
- if (event.button !== 0 || pointer2 !== null || reduced() || !canDrag()) return;
714
- if (!draggableFrom(event.target, surface)) return;
715
- pointer2 = event.pointerId;
716
- target = event.target;
717
- startX = event.clientX;
718
- startY = event.clientY;
719
- mode = null;
720
- pulled = 0;
721
- };
722
- const onPointerMove = (event) => {
723
- if (event.pointerId !== pointer2 || mode === "scroll") return;
724
- const dx = event.clientX - startX;
725
- const dy = event.clientY - startY;
726
- if (mode === null) {
727
- if (Math.abs(dx) < START && Math.abs(dy) < START) return;
728
- if (event.pointerType !== "mouse") {
729
- const scroller = scrollerOf(target, surface);
730
- if (scroller && Math.abs(dx) < Math.abs(dy) && !(dy > 0 && scroller.scrollTop <= 0)) {
731
- mode = "scroll";
732
- return;
733
- }
734
- }
735
- begin();
736
- }
737
- if (event.cancelable) event.preventDefault();
738
- follow(dx, dy);
739
- };
740
- const onPointerUp = (event) => {
741
- if (event.pointerId !== pointer2) return;
742
- pointer2 = null;
743
- target = null;
744
- if (mode !== "drag") {
745
- mode = null;
746
- return;
747
- }
748
- const swallow = (click) => {
749
- click.stopPropagation();
750
- click.preventDefault();
751
- };
752
- window.addEventListener("click", swallow, { capture: true, once: true });
753
- setTimeout(() => window.removeEventListener("click", swallow, { capture: true }), 50);
754
- release();
755
- };
756
- let wheeling = false;
757
- let wheelPull = 0;
758
- let wheelSpeed = 0;
759
- let lastWheel = 0;
760
- let idle;
761
- let quietUntil = 0;
762
- const deltaOf = (event) => event.deltaMode === 1 ? event.deltaY * 16 : event.deltaMode === 2 ? event.deltaY * innerHeight : event.deltaY;
763
- function endWheel(dismiss, at) {
764
- window.removeEventListener("wheel", onWheelCapture, { capture: true });
765
- clearTimeout(idle);
766
- wheeling = false;
767
- quietUntil = at + WHEEL_COOLDOWN;
768
- pulled = 0;
769
- wheelPull = 0;
770
- wheelSpeed = 0;
771
- lastWheel = 0;
772
- document.body.style.userSelect = "";
773
- if (dismiss) onDismiss();
774
- else restore();
775
- }
776
- function stepWheel(event) {
777
- const amount = -deltaOf(event);
778
- const elapsed = lastWheel ? Math.max(1, event.timeStamp - lastWheel) : 16;
779
- lastWheel = event.timeStamp;
780
- wheelSpeed = wheelSpeed * 0.4 + amount / elapsed * 0.6;
781
- wheelPull = Math.max(0, wheelPull + amount);
782
- follow(0, wheelPull);
783
- if (wheelSpeed > WHEEL_SPEED && pulled > WHEEL_MIN || pulled > DISMISS) {
784
- endWheel(true, event.timeStamp);
785
- return;
786
- }
787
- clearTimeout(idle);
788
- idle = setTimeout(() => wheeling && endWheel(false, performance.now()), WHEEL_IDLE);
789
- }
790
- function onWheelCapture(event) {
791
- if (!wheeling) return;
792
- event.preventDefault();
793
- event.stopPropagation();
794
- stepWheel(event);
795
- }
796
- const onWheel = (event) => {
797
- if (wheeling || reduced() || !canDrag()) return;
798
- const up = deltaOf(event) < 0;
799
- const scroller = scrollerOf(event.target, surface);
800
- const canScroll = scroller ? up ? scroller.scrollTop > 0 : scroller.scrollTop + scroller.clientHeight < scroller.scrollHeight - 1 : false;
801
- if (canScroll || !up || event.timeStamp < quietUntil) return;
802
- if (event.target instanceof Element && event.target.closest("[data-mk-no-drag], [popover]")) return;
803
- event.preventDefault();
804
- wheeling = true;
805
- wheelPull = 0;
806
- wheelSpeed = 0;
807
- lastWheel = 0;
808
- begin();
809
- mode = null;
810
- window.addEventListener("wheel", onWheelCapture, { passive: false, capture: true });
811
- stepWheel(event);
812
- };
813
- surface.addEventListener("pointerdown", onPointerDown);
814
- window.addEventListener("pointermove", onPointerMove, { passive: false });
815
- window.addEventListener("pointerup", onPointerUp);
816
- window.addEventListener("pointercancel", onPointerUp);
817
- surface.addEventListener("wheel", onWheel, { passive: false });
818
- return () => {
819
- surface.removeEventListener("pointerdown", onPointerDown);
820
- window.removeEventListener("pointermove", onPointerMove);
821
- window.removeEventListener("pointerup", onPointerUp);
822
- window.removeEventListener("pointercancel", onPointerUp);
823
- surface.removeEventListener("wheel", onWheel);
824
- window.removeEventListener("wheel", onWheelCapture, { capture: true });
825
- clearTimeout(idle);
826
- document.removeEventListener("selectstart", noSelect);
827
- document.body.style.userSelect = "";
828
- };
829
- }
830
-
831
- // src/motion/floating.ts
832
- var MIN_WIDTH = 320;
833
- var MIN_HEIGHT = 240;
834
- var MARGIN = 8;
835
- var DESKTOP = 680;
836
- var LIFT = 4;
837
- var SPRING = { stiffness: 1100, damping: 38 };
838
- var MASS_AREA = 24e3;
839
- var MAX_MASS = 1.5;
840
- var REST_SPEED = 24;
841
- var FLING_SPEED = 350;
842
- var POINTER_SMOOTHING = 0.05;
843
- var SHRINK_FULL = 0.85;
844
- var FLOAT_SHADOW = "rgba(0, 0, 0, 0.24) 0px 0px 24px -6px";
845
- var floatingAvailable = () => typeof innerWidth === "number" && innerWidth >= DESKTOP;
846
- function clampRect(rect, viewport = { width: innerWidth, height: innerHeight }) {
847
- const maxWidth = Math.max(MIN_WIDTH, viewport.width - MARGIN * 2);
848
- const maxHeight = Math.max(MIN_HEIGHT, viewport.height - MARGIN * 2);
849
- const width = Math.min(maxWidth, Math.max(MIN_WIDTH, rect.width));
850
- const height = Math.min(maxHeight, Math.max(MIN_HEIGHT, rect.height));
851
- return {
852
- top: Math.min(Math.max(MARGIN, viewport.height - height - MARGIN), Math.max(MARGIN, rect.top)),
853
- left: Math.min(Math.max(MARGIN, viewport.width - width - MARGIN), Math.max(MARGIN, rect.left)),
854
- width,
855
- height
856
- };
857
- }
858
- var rectOf = (element) => {
859
- const box = element.getBoundingClientRect();
860
- return { top: box.top, left: box.left, width: box.width, height: box.height };
861
- };
862
- var place = (element, rect) => Object.assign(element.style, {
863
- position: "fixed",
864
- inset: "auto",
865
- margin: "0",
866
- top: `${rect.top}px`,
867
- left: `${rect.left}px`,
868
- width: `${rect.width}px`,
869
- height: `${rect.height}px`,
870
- maxWidth: "none",
871
- maxHeight: "none"
872
- });
873
- var storageKey = (key) => `mk-float.${key}`;
874
- function savedFloat(key) {
875
- try {
876
- const value = JSON.parse(localStorage.getItem(storageKey(key)) ?? "null");
877
- return value && ["top", "left", "width", "height"].every((name) => Number.isFinite(value[name])) ? clampRect(value) : null;
878
- } catch {
879
- return null;
880
- }
881
- }
882
- function saveFloat(key, rect) {
883
- try {
884
- localStorage.setItem(
885
- storageKey(key),
886
- JSON.stringify({ top: Math.round(rect.top), left: Math.round(rect.left), width: Math.round(rect.width), height: Math.round(rect.height) })
887
- );
888
- } catch {
889
- }
890
- }
891
- function forgetFloat(key) {
892
- try {
893
- localStorage.removeItem(storageKey(key));
894
- } catch {
895
- }
896
- }
897
- function liftWindow(surface, rect) {
898
- registerMotion();
899
- place(surface, clampRect(rect));
900
- surface.classList.add("is-floating");
901
- if (!reduced()) {
902
- gsap.fromTo(
903
- surface,
904
- { boxShadow: "rgba(0, 0, 0, 0) 0px 0px 0px 0px" },
905
- { boxShadow: FLOAT_SHADOW, duration: TIMING.float.shadow, ease: EASE.signature, clearProps: "boxShadow" }
906
- );
907
- }
908
- }
909
- var PLACED2 = [
910
- "position",
911
- "inset",
912
- "right",
913
- "bottom",
914
- "margin",
915
- "margin-top",
916
- "margin-right",
917
- "margin-bottom",
918
- "margin-left",
919
- "top",
920
- "left",
921
- "width",
922
- "height",
923
- "max-width",
924
- "max-height"
925
- ];
926
- function unplaceWindow(surface) {
927
- surface.classList.remove("is-floating");
928
- for (const name of PLACED2) surface.style.removeProperty(name);
929
- }
930
- function dockWindow(surface, from) {
931
- registerMotion();
932
- unplaceWindow(surface);
933
- if (reduced()) return;
934
- const to = rectOf(surface);
935
- gsap.from(surface, { x: from.left - to.left, y: from.top - to.top, duration: TIMING.float.shadow, ease: EASE.signature, clearProps: "transform" });
936
- }
937
- function attachFloating(surface, { key, handle, corners = [], isFloating, float, dock }) {
938
- const cleanups = [];
939
- const listen = (element, listener) => {
940
- element.addEventListener("pointerdown", listener);
941
- cleanups.push(() => element.removeEventListener("pointerdown", listener));
942
- };
943
- let active = null;
944
- let release = null;
945
- const capture = (element, down, { onMove: onMove2, onUp }) => {
946
- release?.();
947
- active = down.pointerId;
948
- try {
949
- element.setPointerCapture?.(down.pointerId);
950
- } catch {
951
- }
952
- const move = (event) => {
953
- if (event.pointerId === active) onMove2(event);
954
- };
955
- const up = (event) => {
956
- if (event.pointerId !== active) return;
957
- stop2();
958
- onUp();
959
- };
960
- const stop2 = () => {
961
- active = null;
962
- release = null;
963
- window.removeEventListener("pointermove", move);
964
- window.removeEventListener("pointerup", up);
965
- window.removeEventListener("pointercancel", up);
966
- };
967
- release = stop2;
968
- window.addEventListener("pointermove", move);
969
- window.addEventListener("pointerup", up);
970
- window.addEventListener("pointercancel", up);
971
- };
972
- cleanups.push(() => release?.());
973
- let body = null;
974
- const settle = () => {
975
- if (!body) return;
976
- gsap.ticker.remove(tick);
977
- body = null;
978
- };
979
- function tick() {
980
- if (!body) return;
981
- const now = performance.now();
982
- const elapsed = Math.min((now - body.time) / 1e3, 1 / 30);
983
- if (elapsed <= 0) return;
984
- body.time = now;
985
- if (body.gliding) {
986
- const decay = Math.exp(-elapsed / TIMING.float.glideDecay);
987
- body.vx *= decay;
988
- body.vy *= decay;
989
- } else {
990
- body.vx += ((body.targetX - body.x) * SPRING.stiffness - body.vx * SPRING.damping) * elapsed / body.mass;
991
- body.vy += ((body.targetY - body.y) * SPRING.stiffness - body.vy * SPRING.damping) * elapsed / body.mass;
992
- }
993
- body.x += body.vx * elapsed;
994
- body.y += body.vy * elapsed;
995
- const smoothing = 1 - Math.exp(-elapsed / TIMING.float.sizeSmoothing);
996
- body.w += (body.targetW - body.w) * smoothing;
997
- body.h += (body.targetH - body.h) * smoothing;
998
- if (Math.abs(body.targetW - body.w) < 0.5) body.w = body.targetW;
999
- if (Math.abs(body.targetH - body.h) < 0.5) body.h = body.targetH;
1000
- const rect = clampRect({ top: body.y, left: body.x, width: body.w, height: body.h });
1001
- if (rect.left !== body.x) {
1002
- body.x = rect.left;
1003
- body.vx = 0;
1004
- }
1005
- if (rect.top !== body.y) {
1006
- body.y = rect.top;
1007
- body.vy = 0;
1008
- }
1009
- place(surface, rect);
1010
- const resting = Math.hypot(body.vx, body.vy) < REST_SPEED && body.w === body.targetW && body.h === body.targetH;
1011
- if (body.gliding && resting) {
1012
- saveFloat(key, rect);
1013
- settle();
1014
- }
1015
- }
1016
- listen(handle, (down) => {
1017
- if (down.button !== 0 || active !== null || !floatingAvailable()) return;
1018
- down.preventDefault();
1019
- settle();
1020
- let moved = false;
1021
- capture(handle, down, {
1022
- onMove(event) {
1023
- const dx = event.clientX - down.clientX;
1024
- const dy = event.clientY - down.clientY;
1025
- if (!moved) {
1026
- if (Math.abs(dx) < LIFT && Math.abs(dy) < LIFT) return;
1027
- moved = true;
1028
- if (!isFloating()) float();
1029
- const rect = rectOf(surface);
1030
- const fullWidth = innerWidth - MARGIN * 2;
1031
- const fullHeight = innerHeight - MARGIN * 2;
1032
- const width = rect.width >= fullWidth - 2 ? Math.max(MIN_WIDTH, Math.round(fullWidth * SHRINK_FULL)) : rect.width;
1033
- const height = rect.height >= fullHeight - 2 ? Math.max(MIN_HEIGHT, Math.round(fullHeight * SHRINK_FULL)) : rect.height;
1034
- const grip = rect.width > 0 ? (down.clientX - rect.left) / rect.width : 0;
1035
- const left = rect.left + (rect.width - width) * grip;
1036
- const now2 = performance.now();
1037
- body = {
1038
- x: left,
1039
- y: rect.top,
1040
- vx: 0,
1041
- vy: 0,
1042
- w: rect.width,
1043
- h: rect.height,
1044
- targetX: left,
1045
- targetY: rect.top,
1046
- targetW: width,
1047
- targetH: height,
1048
- mass: Math.min(MAX_MASS, Math.max(1, Math.sqrt(rect.width * rect.height / MASS_AREA))),
1049
- time: now2,
1050
- gliding: false,
1051
- fromX: left,
1052
- fromY: rect.top,
1053
- pointerVx: 0,
1054
- pointerVy: 0,
1055
- pointerX: event.clientX,
1056
- pointerY: event.clientY,
1057
- pointerTime: now2
1058
- };
1059
- gsap.ticker.add(tick);
1060
- }
1061
- if (!body) return;
1062
- body.targetX = body.fromX + dx;
1063
- body.targetY = body.fromY + dy;
1064
- const now = performance.now();
1065
- const seconds = Math.max(1, now - body.pointerTime) / 1e3;
1066
- const smoothing = 1 - Math.exp(-seconds / POINTER_SMOOTHING);
1067
- body.pointerVx += ((event.clientX - body.pointerX) / seconds - body.pointerVx) * smoothing;
1068
- body.pointerVy += ((event.clientY - body.pointerY) / seconds - body.pointerVy) * smoothing;
1069
- body.pointerX = event.clientX;
1070
- body.pointerY = event.clientY;
1071
- body.pointerTime = now;
1072
- },
1073
- onUp() {
1074
- if (!moved) {
1075
- if (isFloating()) dock();
1076
- else float();
1077
- return;
1078
- }
1079
- if (!body) return;
1080
- const speed = performance.now() - body.pointerTime > 80 ? 0 : Math.hypot(body.pointerVx, body.pointerVy);
1081
- if (speed >= FLING_SPEED) {
1082
- body.vx = body.pointerVx;
1083
- body.vy = body.pointerVy;
1084
- } else {
1085
- body.vx = 0;
1086
- body.vy = 0;
1087
- body.targetX = body.x;
1088
- body.targetY = body.y;
1089
- }
1090
- body.gliding = true;
1091
- }
1092
- });
1093
- });
1094
- for (const corner of corners) {
1095
- listen(corner, (down) => {
1096
- if (down.button !== 0 || active !== null || !floatingAvailable()) return;
1097
- down.preventDefault();
1098
- settle();
1099
- const side = corner.dataset.mkFloatCorner ?? "br";
1100
- const fromLeft = side.endsWith("l");
1101
- const fromTop = side.startsWith("t");
1102
- let start = null;
1103
- capture(corner, down, {
1104
- onMove(event) {
1105
- const dx = event.clientX - down.clientX;
1106
- const dy = event.clientY - down.clientY;
1107
- if (!start) {
1108
- if (Math.abs(dx) < LIFT && Math.abs(dy) < LIFT) return;
1109
- if (!isFloating()) float();
1110
- start = rectOf(surface);
1111
- }
1112
- const width = Math.min(innerWidth - MARGIN * 2, Math.max(MIN_WIDTH, fromLeft ? start.width - dx : start.width + dx));
1113
- const height = Math.min(innerHeight - MARGIN * 2, Math.max(MIN_HEIGHT, fromTop ? start.height - dy : start.height + dy));
1114
- place(
1115
- surface,
1116
- clampRect({
1117
- top: fromTop ? start.top + start.height - height : start.top,
1118
- left: fromLeft ? start.left + start.width - width : start.left,
1119
- width,
1120
- height
1121
- })
1122
- );
1123
- },
1124
- onUp() {
1125
- if (start) saveFloat(key, rectOf(surface));
1126
- }
1127
- });
1128
- });
1129
- }
1130
- return () => {
1131
- if (body?.gliding) saveFloat(key, rectOf(surface));
1132
- settle();
1133
- for (const cleanup of cleanups) cleanup();
1134
- };
1135
- }
1136
-
1137
- // src/motion/surface.ts
1138
- var transparentColor = (color) => !color || color === "transparent" || /,\s*0\)$/.test(color) || /\/\s*0\)$/.test(color);
1139
- function openModal(dialog, modal = true) {
1140
- if (dialog.hasAttribute("open")) return;
1141
- if (modal && typeof dialog.showModal === "function") dialog.showModal();
1142
- else if (typeof dialog.show === "function") dialog.show();
1143
- else dialog.setAttribute("open", "");
1144
- }
1145
- function closeModal(dialog) {
1146
- if (typeof dialog.close === "function") dialog.close();
1147
- else dialog.removeAttribute("open");
1148
- }
1149
- function fadeBackdrop(dialog, direction) {
1150
- if (typeof dialog.animate !== "function" || reduced()) return Promise.resolve();
1151
- try {
1152
- const animation = dialog.animate(direction === "in" ? [{ opacity: 0 }, { opacity: 1 }] : [{ opacity: 1 }, { opacity: 0 }], {
1153
- duration: (direction === "in" ? TIMING.dialog.backdrop : TIMING.dialog.close) * 1e3,
1154
- easing: direction === "in" ? SIGNATURE_LINEAR : "linear",
1155
- fill: direction === "out" ? "forwards" : "none",
1156
- pseudoElement: "::backdrop"
1157
- });
1158
- return animation.finished.then(
1159
- () => void 0,
1160
- () => void 0
1161
- );
1162
- } catch {
1163
- return Promise.resolve();
1164
- }
1165
- }
1166
- function backdropVeil(surface) {
1167
- const backdrop = getComputedStyle(surface, "::backdrop");
1168
- const veil = document.createElement("div");
1169
- veil.setAttribute("aria-hidden", "true");
1170
- veil.dataset.mkVeil = "";
1171
- Object.assign(veil.style, {
1172
- position: "fixed",
1173
- inset: "0",
1174
- zIndex: "2147483645",
1175
- background: backdrop.background || backdrop.backgroundColor,
1176
- backdropFilter: backdrop.backdropFilter,
1177
- pointerEvents: "none"
1178
- });
1179
- return veil;
1180
- }
1181
- function ghostOf(surface) {
1182
- const rect = surface.getBoundingClientRect();
1183
- if (rect.width === 0 || rect.height === 0) return null;
1184
- const style = getComputedStyle(surface);
1185
- const ghost = document.createElement("div");
1186
- ghost.className = surface.className;
1187
- ghost.innerHTML = surface.innerHTML;
1188
- ghost.setAttribute("aria-hidden", "true");
1189
- ghost.inert = true;
1190
- ghost.dataset.mkGhost = "";
1191
- const strip = ["id", "for", "name", "aria-labelledby", "aria-describedby", "aria-label", "role"];
1192
- for (const element of ghost.querySelectorAll(strip.map((name) => `[${name}]`).join(","))) {
1193
- for (const name of strip) element.removeAttribute(name);
1194
- }
1195
- for (const label of ghost.querySelectorAll("label")) {
1196
- const span = document.createElement("span");
1197
- span.className = label.className;
1198
- span.append(...label.childNodes);
1199
- label.replaceWith(span);
1200
- }
1201
- Object.assign(ghost.style, {
1202
- position: "fixed",
1203
- inset: "auto",
1204
- left: `${rect.left}px`,
1205
- top: `${rect.top}px`,
1206
- width: `${rect.width}px`,
1207
- height: `${rect.height}px`,
1208
- margin: "0",
1209
- display: style.display === "none" ? "flex" : style.display,
1210
- flexDirection: style.flexDirection,
1211
- zIndex: "2147483646",
1212
- pointerEvents: "none"
1213
- });
1214
- return ghost;
1215
- }
1216
-
1217
- // src/motion/liquid.ts
1218
- var GOO = "mk-liquid-goo";
1219
- function ensureGoo() {
1220
- if (document.getElementById(GOO)) return;
1221
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
1222
- svg.setAttribute("aria-hidden", "true");
1223
- svg.setAttribute("width", "0");
1224
- svg.setAttribute("height", "0");
1225
- svg.style.position = "absolute";
1226
- svg.innerHTML = `<defs><filter id="${GOO}" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur in="SourceGraphic" stdDeviation="20"/><feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9"/></filter></defs>`;
1227
- document.body.append(svg);
1228
- }
1229
- function gooLayer(surface) {
1230
- ensureGoo();
1231
- const box = surface.getBoundingClientRect();
1232
- const layer = document.createElement("div");
1233
- layer.className = "mk-morph-face mk-liquid";
1234
- layer.setAttribute("aria-hidden", "true");
1235
- Object.assign(layer.style, {
1236
- position: "absolute",
1237
- left: `${-box.left - surface.clientLeft}px`,
1238
- top: `${-box.top - surface.clientTop}px`,
1239
- width: `${innerWidth}px`,
1240
- height: `${innerHeight}px`,
1241
- zIndex: "-1",
1242
- pointerEvents: "none",
1243
- filter: `url(#${GOO})`,
1244
- borderRadius: "0",
1245
- background: "none"
1246
- });
1247
- const blob = (from, radius, color) => {
1248
- const element = document.createElement("div");
1249
- Object.assign(element.style, {
1250
- position: "absolute",
1251
- top: `${from.top}px`,
1252
- left: `${from.left}px`,
1253
- width: `${from.width}px`,
1254
- height: `${from.height}px`,
1255
- borderRadius: `${radius}px`,
1256
- background: color
1257
- });
1258
- layer.append(element);
1259
- return element;
1260
- };
1261
- surface.append(layer);
1262
- return { layer, blob };
1263
- }
1264
- function hideFrame(surface) {
1265
- const saved = surface.getAttribute("style");
1266
- Object.assign(surface.style, {
1267
- transition: "none",
1268
- background: "transparent",
1269
- boxShadow: "none",
1270
- borderColor: "transparent",
1271
- overflow: "visible"
1272
- });
1273
- return () => {
1274
- if (saved === null) surface.removeAttribute("style");
1275
- else surface.setAttribute("style", saved);
1276
- };
1277
- }
1278
- var radiusOf = (element, box) => Math.min(parseFloat(getComputedStyle(element).borderTopLeftRadius) || 0, box.width / 2, box.height / 2);
1279
- function centerParts(surface, parts) {
1280
- const box = surface.getBoundingClientRect();
1281
- const centerX = box.left + box.width / 2;
1282
- const centerY = box.top + box.height / 2;
1283
- for (const part2 of parts) {
1284
- const own = part2.getBoundingClientRect();
1285
- gsap.set(part2, { transformOrigin: `${centerX - own.left}px ${centerY - own.top}px` });
1286
- }
1287
- return { centerX, centerY };
1288
- }
1289
- function liquidOpen(surface, origin, parts) {
1290
- const box = surface.getBoundingClientRect();
1291
- const start = origin.getBoundingClientRect();
1292
- const surfaceColor = getComputedStyle(surface).backgroundColor;
1293
- const originLook = getComputedStyle(origin).backgroundColor;
1294
- const originColor = transparentColor(originLook) ? surfaceColor : originLook;
1295
- const endRadius = radiusOf(surface, box);
1296
- const startRadius = radiusOf(origin, start);
1297
- const { centerX, centerY } = centerParts(surface, parts);
1298
- const restore = hideFrame(surface);
1299
- const { layer, blob } = gooLayer(surface);
1300
- const originBlob = blob(start, startRadius, originColor);
1301
- const shape = blob(start, startRadius, originColor);
1302
- const towardX = start.left + start.width / 2 < innerWidth / 2 ? 1 : -1;
1303
- const towardY = start.top + start.height / 2 < innerHeight / 2 ? 1 : -1;
1304
- if (parts.length) gsap.set(parts, { opacity: 0 });
1305
- const current2 = { top: start.top, left: start.left, width: start.width, height: start.height, scale: 2, blur: 8 };
1306
- const paint = () => {
1307
- if (!parts.length) return;
1308
- gsap.set(parts, {
1309
- x: current2.left + current2.width / 2 - centerX,
1310
- y: current2.top + current2.height / 2 - centerY,
1311
- scale: current2.scale,
1312
- filter: `blur(${current2.blur}px)`
1313
- });
1314
- };
1315
- const motion = channels({ ...current2, radius: startRadius }, (name, value) => {
1316
- if (name === "radius") shape.style.borderRadius = `${value}px`;
1317
- else {
1318
- current2[name] = value;
1319
- if (name === "top" || name === "left" || name === "width" || name === "height") shape.style[name] = `${value}px`;
1320
- paint();
1321
- }
1322
- });
1323
- const L = TIMING.liquid;
1324
- void motion.animate(
1325
- { top: box.top, left: box.left, width: box.width, height: box.height, radius: endRadius, scale: 1, blur: 0 },
1326
- {
1327
- top: spring(144, 14, { velocity: 2400, direction: towardY }),
1328
- left: spring(144, 14, { velocity: 2400, direction: towardX }),
1329
- width: eased(L.size, bezier(0.8, 0.3, 0.5, 0.8)),
1330
- height: eased(L.size, bezier(0.8, 0.3, 0.5, 0.8)),
1331
- radius: eased(L.radius, easeOut),
1332
- scale: eased(L.content, easeOut),
1333
- blur: eased(L.content, easeOut)
1334
- }
1335
- );
1336
- gsap.to(shape, { background: surfaceColor, duration: L.color, delay: L.colorDelay, ease: "power2.out" });
1337
- if (parts.length) gsap.to(parts, { opacity: 1, duration: L.color, delay: L.colorDelay, ease: "power2.out" });
1338
- gsap.to(originBlob, { opacity: 0, duration: L.ghost, delay: L.ghostDelay, ease: "power2.out" });
1339
- let done = false;
1340
- const finish = () => {
1341
- if (done) return;
1342
- done = true;
1343
- motion.stop();
1344
- clearTimeout(timer);
1345
- layer.remove();
1346
- restore();
1347
- if (parts.length) gsap.set(parts, { clearProps: "opacity,transform,transformOrigin,filter" });
1348
- };
1349
- const timer = setTimeout(finish, L.safetyMs);
1350
- return finish;
1351
- }
1352
- function liquidClose(surface, origin, parts, onComplete) {
1353
- const box = surface.getBoundingClientRect();
1354
- const end = origin.getBoundingClientRect();
1355
- const surfaceColor = getComputedStyle(surface).backgroundColor;
1356
- const originLook = getComputedStyle(origin).backgroundColor;
1357
- const originColor = transparentColor(originLook) ? surfaceColor : originLook;
1358
- const startRadius = radiusOf(surface, box);
1359
- const endRadius = radiusOf(origin, end);
1360
- const { centerX, centerY } = centerParts(surface, parts);
1361
- hideFrame(surface);
1362
- const { blob } = gooLayer(surface);
1363
- const originBlob = blob(end, endRadius, originColor);
1364
- originBlob.style.opacity = "0";
1365
- const shape = blob(box, startRadius, surfaceColor);
1366
- const current2 = { top: box.top, left: box.left, width: box.width, height: box.height, scale: 1, blur: 0 };
1367
- const motion = channels({ ...current2, radius: startRadius, opacity: 1 }, (name, value) => {
1368
- if (name === "radius") shape.style.borderRadius = `${value}px`;
1369
- else if (name === "opacity") {
1370
- if (parts.length) gsap.set(parts, { opacity: value });
1371
- } else {
1372
- current2[name] = value;
1373
- if (name === "top" || name === "left" || name === "width" || name === "height") shape.style[name] = `${value}px`;
1374
- if (parts.length) {
1375
- gsap.set(parts, {
1376
- x: current2.left + current2.width / 2 - centerX,
1377
- y: current2.top + current2.height / 2 - centerY,
1378
- scale: current2.scale,
1379
- filter: `blur(${current2.blur}px)`
1380
- });
1381
- }
1382
- }
1383
- });
1384
- const L = TIMING.liquid;
1385
- void motion.animate(
1386
- { top: end.top, left: end.left, width: end.width, height: end.height, radius: endRadius, scale: 2, blur: 8, opacity: 0 },
1387
- {
1388
- top: spring(130, 18),
1389
- left: spring(130, 18),
1390
- width: eased(L.closeSize, easeOut),
1391
- height: eased(L.closeSize, easeOut),
1392
- // It rounds into the opener's shape early, long before it arrives.
1393
- radius: eased(L.closeSize, easeOut),
1394
- scale: eased(L.closeContent, easeOut),
1395
- blur: eased(L.closeContent, easeOut),
1396
- opacity: spring(137, 20)
1397
- }
1398
- );
1399
- gsap.to(originBlob, { opacity: 1, duration: L.originRestore, delay: 0.15, ease: "power2.in" });
1400
- gsap.to(shape, { background: originColor, duration: L.originRestore, ease: "power2.out" });
1401
- gsap.to(surface, { opacity: 0, duration: TIMING.dialog.close, ease: "power3.in" });
1402
- setTimeout(() => {
1403
- motion.stop();
1404
- onComplete();
1405
- }, L.safetyMs);
1406
- }
1407
-
1408
- // src/motion/morph.ts
1409
- var FACE = "mk-morph-face";
1410
- var HIDDEN_ORIGIN = "data-mk-morph-origin";
1411
- var SHARED = "data-mk-shared";
1412
- var SHARED_HIDDEN = "data-mk-shared-hidden";
1413
- var clamp = (value, min, max) => Math.min(Math.max(value, min), Math.max(min, max));
1414
- var radiusOf2 = (value, size) => {
1415
- const parsed = Number.parseFloat(value) || 0;
1416
- return value.trim().endsWith("%") ? parsed / 100 * size : parsed;
1417
- };
1418
- function shapeOf(surface, origin) {
1419
- if (!origin?.isConnected) return null;
1420
- const start = origin.getBoundingClientRect();
1421
- const box = surface.getBoundingClientRect();
1422
- if (start.width < 4 || start.height < 4 || !box.width || !box.height) return null;
1423
- if (start.bottom < 0 || start.top > innerHeight || start.right < 0 || start.left > innerWidth) return null;
1424
- const width = Math.min(start.width, box.width);
1425
- const height = Math.min(start.height, box.height);
1426
- const left = clamp(start.left - box.left, 0, box.width - width);
1427
- const top = clamp(start.top - box.top, 0, box.height - height);
1428
- const corner = Math.min(radiusOf2(getComputedStyle(origin).borderTopLeftRadius, start.height), width / 2, height / 2);
1429
- const radius = radiusOf2(getComputedStyle(surface).borderTopLeftRadius, box.height);
1430
- return {
1431
- x: start.left + (start.width - width) / 2 - (box.left + left),
1432
- y: start.top + (start.height - height) / 2 - (box.top + top),
1433
- from: `inset(${top}px ${box.width - left - width}px ${box.height - top - height}px ${left}px round ${corner}px)`,
1434
- to: `inset(0px 0px 0px 0px round ${radius}px)`,
1435
- left,
1436
- top,
1437
- width,
1438
- height
1439
- };
1440
- }
1441
- var LOOK = [
1442
- "display",
1443
- "alignItems",
1444
- "justifyContent",
1445
- "gap",
1446
- "padding",
1447
- "borderRadius",
1448
- "borderWidth",
1449
- "borderStyle",
1450
- "borderColor",
1451
- "backgroundColor",
1452
- "color",
1453
- "fontFamily",
1454
- "fontSize",
1455
- "fontWeight",
1456
- "lineHeight",
1457
- "letterSpacing",
1458
- "whiteSpace"
1459
- ];
1460
- function faceOf(surface, origin, shape, withCopy) {
1461
- const look = getComputedStyle(origin);
1462
- const face = document.createElement("div");
1463
- face.className = FACE;
1464
- face.setAttribute("aria-hidden", "true");
1465
- face.inert = true;
1466
- if (!transparentColor(look.backgroundColor)) face.style.background = look.backgroundColor;
1467
- surface.append(face);
1468
- if (!withCopy) return { face, copy: null };
1469
- const copy = document.createElement("span");
1470
- copy.innerHTML = origin.innerHTML;
1471
- for (const element of copy.querySelectorAll("[id], [name], [for]")) for (const name of ["id", "name", "for"]) element.removeAttribute(name);
1472
- for (const property of LOOK) copy.style[property] = look[property];
1473
- Object.assign(copy.style, {
1474
- position: "absolute",
1475
- left: `${shape.left}px`,
1476
- top: `${shape.top}px`,
1477
- width: `${shape.width}px`,
1478
- height: `${shape.height}px`,
1479
- boxSizing: "border-box",
1480
- margin: "0",
1481
- overflow: "hidden"
1482
- });
1483
- face.append(copy);
1484
- return { face, copy };
1485
- }
1486
- var running = /* @__PURE__ */ new WeakMap();
1487
- var isMorphing = (surface) => running.has(surface);
1488
- function stop(surface) {
1489
- running.get(surface)?.kill();
1490
- running.delete(surface);
1491
- gsap.killTweensOf(surface);
1492
- for (const face of surface.querySelectorAll(`:scope > .${FACE}`)) face.remove();
1493
- clearStyles([surface], MORPH_STYLES);
1494
- }
1495
- function stopMorph(surface) {
1496
- stop(surface);
1497
- const parts = [...surface.querySelectorAll(":scope > *")].filter((element) => !element.classList.contains("mk-liquid"));
1498
- gsap.killTweensOf(parts);
1499
- clearStyles(parts, MORPH_STYLES);
1500
- }
1501
- var compact = (element) => {
1502
- const box = element.getBoundingClientRect();
1503
- return box.width <= 360 && box.height <= 72;
1504
- };
1505
- function showOrigin(origin, { fade = false } = {}) {
1506
- if (!origin?.hasAttribute(HIDDEN_ORIGIN)) return;
1507
- if (!fade || reduced()) {
1508
- origin.removeAttribute(HIDDEN_ORIGIN);
1509
- return;
1510
- }
1511
- const previous = origin.style.transition;
1512
- const { originShow, originShowDelay } = TIMING.dialog;
1513
- origin.style.transition = `opacity ${originShow}s cubic-bezier(0.215, 0.61, 0.355, 1) ${originShowDelay}s`;
1514
- origin.removeAttribute(HIDDEN_ORIGIN);
1515
- setTimeout(() => {
1516
- origin.style.transition = previous;
1517
- }, (originShow + originShowDelay) * 1e3 + 50);
1518
- }
1519
- function groupOf(surface, parts, shape) {
1520
- const box = surface.getBoundingClientRect();
1521
- for (const part2 of parts) {
1522
- const own = part2.getBoundingClientRect();
1523
- gsap.set(part2, { transformOrigin: `${box.left - own.left}px ${box.top - own.top}px` });
1524
- }
1525
- return {
1526
- x: shape.left,
1527
- y: shape.top,
1528
- scaleX: box.width ? shape.width / box.width : 1,
1529
- scaleY: box.height ? shape.height / box.height : 1
1530
- };
1531
- }
1532
- var escape = (value) => typeof CSS !== "undefined" && CSS.escape ? CSS.escape(value) : value.replace(/"/g, '\\"');
1533
- function sharedPairs(origin, surface) {
1534
- return [origin, ...origin.querySelectorAll(`[${SHARED}]`)].filter((source) => source.hasAttribute(SHARED)).map((source) => ({
1535
- source,
1536
- target: surface.querySelector(`[${SHARED}="${escape(source.getAttribute(SHARED) ?? "")}"]`)
1537
- })).filter((pair) => pair.target !== null);
1538
- }
1539
- function textBox(element) {
1540
- const box = element.getBoundingClientRect();
1541
- const style = getComputedStyle(element);
1542
- const px = (value) => parseFloat(value) || 0;
1543
- const left = box.left + px(style.borderLeftWidth) + px(style.paddingLeft);
1544
- const top = box.top + px(style.borderTopWidth) + px(style.paddingTop);
1545
- const bottom = box.bottom - px(style.borderBottomWidth) - px(style.paddingBottom);
1546
- return { left, top, height: Math.max(0, bottom - top), style };
1547
- }
1548
- var textOf = (element) => element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement ? element.value || element.placeholder : element.firstChild?.textContent ?? element.textContent ?? "";
1549
- function flyText(from, to, text, duration) {
1550
- return new Promise((resolve) => {
1551
- const start = textBox(from);
1552
- const end = textBox(to);
1553
- const fromSize = parseFloat(start.style.fontSize) || 16;
1554
- const toSize = parseFloat(end.style.fontSize) || fromSize;
1555
- const scale = toSize / fromSize;
1556
- const ghost = document.createElement("div");
1557
- ghost.setAttribute("aria-hidden", "true");
1558
- ghost.setAttribute("popover", "manual");
1559
- ghost.textContent = text;
1560
- Object.assign(ghost.style, {
1561
- position: "fixed",
1562
- inset: "auto",
1563
- left: `${start.left}px`,
1564
- top: `${start.top}px`,
1565
- margin: "0",
1566
- padding: "0",
1567
- border: "0",
1568
- background: "transparent",
1569
- overflow: "visible",
1570
- whiteSpace: "nowrap",
1571
- pointerEvents: "none",
1572
- fontFamily: start.style.fontFamily,
1573
- fontSize: start.style.fontSize,
1574
- fontWeight: start.style.fontWeight,
1575
- lineHeight: `${start.height || fromSize * 1.2}px`,
1576
- letterSpacing: start.style.letterSpacing,
1577
- color: start.style.color,
1578
- transformOrigin: "0 0"
1579
- });
1580
- document.body.append(ghost);
1581
- if (typeof ghost.showPopover === "function") ghost.showPopover();
1582
- const height = (start.height || fromSize * 1.2) * scale;
1583
- gsap.to(ghost, {
1584
- x: end.left - start.left,
1585
- y: end.top + end.height / 2 - height / 2 - start.top,
1586
- scale,
1587
- color: end.style.color,
1588
- duration,
1589
- ease: EASE.signature,
1590
- onComplete: () => {
1591
- ghost.remove();
1592
- resolve();
1593
- }
1594
- });
1595
- });
1596
- }
1597
- function releaseShared(origin) {
1598
- if (!origin) return;
1599
- for (const element of [origin, ...origin.querySelectorAll(`[${SHARED_HIDDEN}]`)]) element.removeAttribute(SHARED_HIDDEN);
1600
- }
1601
- function shareInto(origin, surface, duration = TIMING.dialog.open) {
1602
- for (const { source, target } of sharedPairs(origin, surface)) {
1603
- const text = textOf(source);
1604
- source.setAttribute(SHARED_HIDDEN, "");
1605
- gsap.set(target, { opacity: 0 });
1606
- void flyText(source, target, text, duration).then(() => gsap.set(target, { clearProps: "opacity" }));
1607
- }
1608
- }
1609
- function shareBack(surface, origin, duration = TIMING.dialog.close) {
1610
- for (const { source, target } of sharedPairs(origin, surface)) {
1611
- gsap.set(target, { opacity: 0 });
1612
- void flyText(target, source, textOf(source), duration).then(() => source.removeAttribute(SHARED_HIDDEN));
1613
- }
1614
- }
1615
- var partsOf = (surface, content) => [...surface.querySelectorAll(content ?? ":scope > *")].filter(
1616
- (element) => !element.classList.contains(FACE) && !element.classList.contains("mk-liquid")
1617
- );
1618
- function morphOpen(surface, origin, options = {}) {
1619
- registerMotion();
1620
- const { duration = TIMING.dialog.open, hideOrigin = false, content, stagger = 0, liquid = false } = options;
1621
- stop(surface);
1622
- if (reduced()) return null;
1623
- const parts = partsOf(surface, content);
1624
- if (liquid && !stagger && origin && shapeOf(surface, origin)) {
1625
- if (hideOrigin && compact(origin)) origin.setAttribute(HIDDEN_ORIGIN, "");
1626
- const settle = liquidOpen(surface, origin, parts);
1627
- const window2 = gsap.timeline({
1628
- onComplete: () => {
1629
- settle();
1630
- running.delete(surface);
1631
- },
1632
- onInterrupt: settle
1633
- });
1634
- window2.to({}, { duration: TIMING.liquid.safetyMs / 1e3 });
1635
- running.set(surface, window2);
1636
- return window2;
1637
- }
1638
- const enter = stagger ? { opacity: 1, y: 0, duration: TIMING.dialog.list, ease: "power2.out", stagger, clearProps: "opacity,transform" } : { opacity: 1, filter: "blur(0px)", duration, ease: EASE.signature, clearProps: "opacity,filter" };
1639
- const enterFrom = stagger ? { opacity: 0, y: -6 } : { opacity: 0, filter: "blur(8px)" };
1640
- const shape = shapeOf(surface, origin);
1641
- if (!shape || !origin) {
1642
- const rise = gsap.timeline({
1643
- onComplete: () => {
1644
- running.delete(surface);
1645
- }
1646
- }).fromTo(
1647
- surface,
1648
- { opacity: 0, scale: 0.92 },
1649
- { opacity: 1, scale: 1, duration: TIMING.dialog.fallback, ease: "power2.out", clearProps: "opacity,transform" }
1650
- );
1651
- if (parts.length) rise.fromTo(parts, enterFrom, { ...enter, duration: Math.min(enter.duration, TIMING.dialog.fallback) }, 0);
1652
- running.set(surface, rise);
1653
- return rise;
1654
- }
1655
- const list2 = Boolean(stagger);
1656
- if (!list2) shareInto(origin, surface, duration);
1657
- const { face, copy } = faceOf(surface, origin, shape, list2);
1658
- const group = list2 ? null : groupOf(surface, parts, shape);
1659
- if (hideOrigin && compact(origin)) origin.setAttribute(HIDDEN_ORIGIN, "");
1660
- const finish = () => {
1661
- face.remove();
1662
- running.delete(surface);
1663
- gsap.set(surface, { clearProps: "transform,clipPath,willChange" });
1664
- if (parts.length) gsap.set(parts, { clearProps: "opacity,transform,transformOrigin,filter" });
1665
- };
1666
- const timeline = gsap.timeline({ onComplete: finish, onInterrupt: finish }).fromTo(
1667
- surface,
1668
- { x: shape.x, y: shape.y, clipPath: shape.from, willChange: "transform,clip-path" },
1669
- { x: 0, y: 0, clipPath: shape.to, duration, ease: EASE.signature },
1670
- 0
1671
- ).to(face, { opacity: 0, duration: TIMING.dialog.surfaceColor, ease: EASE.signature }, 0);
1672
- if (copy) timeline.to(copy, { opacity: 0, duration: 0.25, ease: "power2.out" }, 0.05);
1673
- if (parts.length) {
1674
- if (group) {
1675
- timeline.fromTo(
1676
- parts,
1677
- { ...group, opacity: 0, filter: "blur(8px)" },
1678
- { x: 0, y: 0, scaleX: 1, scaleY: 1, opacity: 1, filter: "blur(0px)", duration, ease: EASE.signature },
1679
- 0
1680
- );
1681
- } else timeline.fromTo(parts, enterFrom, enter, duration * 0.2);
1682
- }
1683
- running.set(surface, timeline);
1684
- return timeline;
1685
- }
1686
- function morphClose(surface, origin, onComplete, options = {}) {
1687
- registerMotion();
1688
- const { duration = TIMING.dialog.close, content, liquid = false } = options;
1689
- stop(surface);
1690
- if (reduced()) {
1691
- onComplete();
1692
- return null;
1693
- }
1694
- const parts = partsOf(surface, content);
1695
- const shape = shapeOf(surface, origin);
1696
- if (!shape || !origin) {
1697
- const fade = gsap.timeline({
1698
- onComplete: () => {
1699
- running.delete(surface);
1700
- onComplete();
1701
- gsap.set(surface, { clearProps: "opacity,transform" });
1702
- if (parts.length) gsap.set(parts, { clearProps: "filter" });
1703
- }
1704
- }).to(surface, { scale: 0.9, duration, ease: EASE.signature }, 0).to(surface, { opacity: 0, duration, ease: EASE.fadeAway }, 0);
1705
- if (parts.length) fade.to(parts, { filter: "blur(32px)", duration, ease: EASE.blurAway }, 0);
1706
- running.set(surface, fade);
1707
- return fade;
1708
- }
1709
- const list2 = content !== void 0;
1710
- if (liquid && !list2) {
1711
- liquidClose(surface, origin, parts, onComplete);
1712
- return null;
1713
- }
1714
- const { face, copy } = faceOf(surface, origin, shape, list2);
1715
- gsap.set(copy ? [face, copy] : face, { opacity: 0 });
1716
- if (!list2) {
1717
- shareBack(surface, origin, duration);
1718
- const group = groupOf(surface, parts, shape);
1719
- const signature = gsap.parseEase(EASE.signature);
1720
- const toward = (progress) => signature(progress * (duration / TIMING.dialog.contentReturn));
1721
- const timeline2 = gsap.timeline({
1722
- onComplete: () => {
1723
- running.delete(surface);
1724
- onComplete();
1725
- face.remove();
1726
- gsap.set(surface, { clearProps: "transform,clipPath,opacity,willChange" });
1727
- if (parts.length) gsap.set(parts, { clearProps: "opacity,transform,transformOrigin,filter,borderRadius" });
1728
- },
1729
- onInterrupt: () => {
1730
- face.remove();
1731
- if (parts.length) gsap.set(parts, { clearProps: "opacity,transform,transformOrigin,filter,borderRadius" });
1732
- }
1733
- }).fromTo(
1734
- surface,
1735
- { clipPath: shape.to, willChange: "transform,clip-path" },
1736
- { x: shape.x, y: shape.y, clipPath: shape.from, duration, ease: EASE.signature },
1737
- 0
1738
- ).to(face, { opacity: 1, duration, ease: EASE.signature }, 0).to(surface, { opacity: 0, duration, ease: "power3.in" }, 0);
1739
- if (parts.length) {
1740
- timeline2.to(parts, { ...group, duration, ease: toward }, 0).to(parts, { opacity: 0, borderRadius: "400px", duration, ease: EASE.fadeAway }, 0).to(parts, { filter: "blur(32px)", duration, ease: EASE.blurAway }, 0);
1741
- }
1742
- running.set(surface, timeline2);
1743
- return timeline2;
1744
- }
1745
- const timeline = gsap.timeline({
1746
- onComplete: () => {
1747
- running.delete(surface);
1748
- onComplete();
1749
- face.remove();
1750
- gsap.set(surface, { clearProps: "transform,clipPath,willChange" });
1751
- if (parts.length) gsap.set(parts, { clearProps: "opacity,transform,filter" });
1752
- },
1753
- onInterrupt: () => {
1754
- face.remove();
1755
- if (parts.length) gsap.set(parts, { clearProps: "opacity,transform,filter" });
1756
- }
1757
- }).fromTo(
1758
- surface,
1759
- { clipPath: shape.to, willChange: "transform,clip-path" },
1760
- { x: shape.x, y: shape.y, clipPath: shape.from, duration, ease: EASE.signature },
1761
- 0
1762
- ).to(face, { opacity: 1, duration: duration * 0.5, ease: "power1.in" }, duration * 0.3);
1763
- if (parts.length) timeline.to(parts, { opacity: 0, filter: "blur(32px)", duration: duration * 0.7, ease: "power2.in" }, 0);
1764
- if (copy) timeline.to(copy, { opacity: 1, duration: duration * 0.3, ease: "power1.in" }, duration * 0.65);
1765
- running.set(surface, timeline);
1766
- return timeline;
1767
- }
1768
- function morphCloseWithGhost(surface, origin, { inPlace = false, liquid = false } = {}) {
1769
- registerMotion();
1770
- const dragged = inPlace ? {
1771
- x: Number(gsap.getProperty(surface, "x")) || 0,
1772
- y: Number(gsap.getProperty(surface, "y")) || 0,
1773
- scale: Number(gsap.getProperty(surface, "scaleX")) || 1
1774
- } : null;
1775
- if (dragged) gsap.set(surface, { clearProps: "transform" });
1776
- const ghost = reduced() ? null : ghostOf(surface);
1777
- if (!ghost) {
1778
- showOrigin(origin);
1779
- releaseShared(origin);
1780
- return;
1781
- }
1782
- const veil = backdropVeil(surface);
1783
- document.body.append(veil, ghost);
1784
- showOrigin(origin, { fade: true });
1785
- gsap.to(veil, { opacity: 0, duration: TIMING.dialog.close, ease: "power3.in" });
1786
- if (dragged) gsap.set(ghost, { ...dragged, transformOrigin: getComputedStyle(surface).transformOrigin });
1787
- morphClose(
1788
- ghost,
1789
- dragged ? null : origin,
1790
- () => {
1791
- showOrigin(origin);
1792
- releaseShared(origin);
1793
- ghost.remove();
1794
- veil.remove();
1795
- },
1796
- { liquid }
1797
- );
1798
- }
1799
-
1800
- // src/motion/sheet.ts
1801
- var UNDERLAY_STYLES = ["transform", "translate", "rotate", "scale", "transform-origin", "opacity"];
1802
- function sheetOpen(surface) {
1803
- if (reduced()) return null;
1804
- registerMotion();
1805
- return gsap.fromTo(surface, { yPercent: 100 }, { yPercent: 0, duration: TIMING.sheet.open, ease: EASE.sheet, clearProps: "transform" });
1806
- }
1807
- function sheetClose(surface, { inPlace = false } = {}) {
1808
- registerMotion();
1809
- const dragged = inPlace ? Number(gsap.getProperty(surface, "y")) || 0 : 0;
1810
- gsap.killTweensOf(surface);
1811
- clearStyles([surface], ["transform", "translate", "rotate", "scale"]);
1812
- const ghost = reduced() ? null : ghostOf(surface);
1813
- if (!ghost) return null;
1814
- const veil = backdropVeil(surface);
1815
- document.body.append(veil, ghost);
1816
- gsap.to(veil, { opacity: 0, duration: TIMING.sheet.close, ease: "power3.in", onComplete: () => veil.remove() });
1817
- return gsap.fromTo(
1818
- ghost,
1819
- { y: dragged, yPercent: 0 },
1820
- { yPercent: 100, duration: TIMING.sheet.close, ease: EASE.sheet, onComplete: () => ghost.remove() }
1821
- );
1822
- }
1823
- function pushUnderlay(elements) {
1824
- if (!elements.length || reduced()) return;
1825
- registerMotion();
1826
- const { ease, duration } = motionSpring(...TIMING.springs.underlay);
1827
- gsap.to(elements, {
1828
- scale: TIMING.sheet.underlayScale,
1829
- opacity: TIMING.sheet.underlayOpacity,
1830
- transformOrigin: "50% 0",
1831
- duration,
1832
- ease,
1833
- overwrite: "auto"
1834
- });
1835
- }
1836
- function releaseUnderlay(elements, animated = true) {
1837
- if (!elements.length) return;
1838
- const restore = () => clearStyles(elements, UNDERLAY_STYLES);
1839
- if (!animated || reduced()) {
1840
- gsap.killTweensOf(elements);
1841
- restore();
1842
- return;
1843
- }
1844
- const { ease, duration } = motionSpring(...TIMING.springs.underlay);
1845
- gsap.to(elements, { scale: 1, opacity: 1, duration, ease, overwrite: "auto", onComplete: restore });
1846
- }
1847
-
1848
- // src/components/dialog/engine.ts
1849
- var DEFAULT_LABELS = { close: "Cerrar", float: "Ventana flotante", dock: "Volver a su sitio" };
1850
- var FIELDS = '[autofocus], input:not([type="hidden"]):not(:disabled), textarea:not(:disabled), select:not(:disabled)';
1851
- var CORNERS = ["tl", "tr", "bl", "br"];
1852
- var uid = 0;
1853
- var part = (dialog, name) => dialog.querySelector(`[data-mk-part="${name}"]`);
1854
- function createDialog(dialog, options = {}) {
1855
- if (!dialog) {
1856
- warnOnce("dialog: missing <dialog> element");
1857
- return inert({ open() {
1858
- }, close() {
1859
- }, toggle() {
1860
- }, float() {
1861
- }, dock() {
1862
- }, isOpen: false, isFloating: false, element: null });
1863
- }
1864
- registerMotion();
1865
- const {
1866
- variant = "morph",
1867
- placement = "center",
1868
- backdrop = true,
1869
- closeOnBackdrop = true,
1870
- drag = true,
1871
- float: floatKey = false,
1872
- autoResize = true,
1873
- triggers = true,
1874
- modal = true
1875
- } = options;
1876
- const labels = { ...DEFAULT_LABELS, ...options.labels };
1877
- const liquid = variant === "liquid";
1878
- const sheet = variant === "sheet";
1879
- const scope = createScope();
1880
- let session = [];
1881
- let opener = null;
1882
- let isOpen = false;
1883
- let closing = false;
1884
- let floating = false;
1885
- let ownCloses = 0;
1886
- const closeNatively = () => {
1887
- if (!dialog.hasAttribute("open")) return;
1888
- ownCloses += 1;
1889
- closeModal(dialog);
1890
- };
1891
- let destroyed = false;
1892
- let tearingDown = false;
1893
- if (placement !== "center") scope.attr(dialog, "data-mk-placement", placement);
1894
- if (!backdrop) scope.attr(dialog, "data-mk-backdrop", "none");
1895
- scope.attr(dialog, "data-mk-variant", variant);
1896
- const title = part(dialog, "title");
1897
- if (title && !dialog.hasAttribute("aria-label") && !dialog.hasAttribute("aria-labelledby")) {
1898
- if (!title.id) scope.attr(title, "id", `mk-dialog-title-${++uid}`);
1899
- scope.attr(dialog, "aria-labelledby", title.id);
1900
- }
1901
- const description = part(dialog, "description");
1902
- if (description && !dialog.hasAttribute("aria-describedby")) {
1903
- if (!description.id) scope.attr(description, "id", `mk-dialog-description-${++uid}`);
1904
- scope.attr(dialog, "aria-describedby", description.id);
1905
- }
1906
- const closeButton = part(dialog, "close");
1907
- if (closeButton && !closeButton.hasAttribute("aria-label") && !closeButton.textContent?.trim()) {
1908
- scope.attr(closeButton, "aria-label", labels.close);
1909
- }
1910
- const handle = floatKey ? part(dialog, "handle") : null;
1911
- if (handle) {
1912
- scope.attr(handle, "data-mk-no-drag", "");
1913
- scope.attr(handle, "aria-pressed", "false");
1914
- scope.attr(handle, "aria-label", labels.float);
1915
- }
1916
- const corners = [];
1917
- if (floatKey) {
1918
- for (const corner of CORNERS) {
1919
- const element = document.createElement("span");
1920
- element.className = "mk-float-corner";
1921
- element.dataset.mkFloatCorner = corner;
1922
- element.dataset.mkNoDrag = "";
1923
- element.setAttribute("aria-hidden", "true");
1924
- dialog.append(element);
1925
- corners.push(element);
1926
- }
1927
- scope.add(() => corners.forEach((corner) => corner.remove()));
1928
- }
1929
- const emit = (type, cancelable = false, detail = {}) => dialog.dispatchEvent(new CustomEvent(type, { bubbles: true, cancelable, detail: { dialog, ...detail } }));
1930
- const endSession = () => {
1931
- for (const cleanup of session.splice(0).reverse()) cleanup();
1932
- };
1933
- const settleFloating = () => {
1934
- if (!floating) return;
1935
- floating = false;
1936
- if (typeof dialog.hidePopover === "function" && dialog.hasAttribute("popover")) {
1937
- try {
1938
- dialog.hidePopover();
1939
- } catch {
1940
- }
1941
- }
1942
- dialog.removeAttribute("popover");
1943
- unplaceWindow(dialog);
1944
- if (handle) {
1945
- handle.setAttribute("aria-pressed", "false");
1946
- handle.setAttribute("aria-label", labels.float);
1947
- }
1948
- };
1949
- const closedQuietly = () => {
1950
- stopMorph(dialog);
1951
- endSession();
1952
- isOpen = false;
1953
- closing = false;
1954
- showOrigin(opener);
1955
- releaseShared(opener);
1956
- emit("mk:closed");
1957
- options.onClose?.();
1958
- };
1959
- const lift = () => {
1960
- if (!floatKey || floating || !isOpen || !floatingAvailable()) return;
1961
- const box = dialog.getBoundingClientRect();
1962
- const rect = savedFloat(floatKey) ?? { top: box.top, left: box.left, width: box.width, height: box.height };
1963
- const focused = document.activeElement;
1964
- const backdropStyle = getComputedStyle(dialog, "::backdrop");
1965
- const veil = document.createElement("div");
1966
- veil.setAttribute("aria-hidden", "true");
1967
- Object.assign(veil.style, {
1968
- position: "fixed",
1969
- inset: "0",
1970
- background: backdropStyle.background || backdropStyle.backgroundColor,
1971
- backdropFilter: backdropStyle.backdropFilter,
1972
- pointerEvents: "none"
1973
- });
1974
- closeNatively();
1975
- document.body.append(veil);
1976
- dialog.setAttribute("popover", "manual");
1977
- if (typeof dialog.showPopover === "function") dialog.showPopover();
1978
- else openModal(dialog, false);
1979
- liftWindow(dialog, rect);
1980
- gsap.to(veil, { opacity: 0, duration: reduced() ? 0 : TIMING.float.shadow, ease: EASE.signature, onComplete: () => veil.remove() });
1981
- floating = true;
1982
- if (handle) {
1983
- handle.setAttribute("aria-pressed", "true");
1984
- handle.setAttribute("aria-label", labels.dock);
1985
- }
1986
- showOrigin(opener, { fade: true });
1987
- if (focused instanceof HTMLElement && dialog.contains(focused)) focused.focus();
1988
- };
1989
- const dock = () => {
1990
- if (!floatKey || !floating) return;
1991
- const box = dialog.getBoundingClientRect();
1992
- const focused = document.activeElement;
1993
- floating = false;
1994
- if (typeof dialog.hidePopover === "function") dialog.hidePopover();
1995
- dialog.removeAttribute("popover");
1996
- closeNatively();
1997
- openModal(dialog, modal);
1998
- dockWindow(dialog, { top: box.top, left: box.left, width: box.width, height: box.height });
1999
- if (backdrop) void fadeBackdrop(dialog, "in");
2000
- forgetFloat(floatKey);
2001
- if (handle) {
2002
- handle.setAttribute("aria-pressed", "false");
2003
- handle.setAttribute("aria-label", labels.float);
2004
- }
2005
- if (focused instanceof HTMLElement && dialog.contains(focused)) focused.focus();
2006
- };
2007
- const startSession = () => {
2008
- if (sheet) {
2009
- const behind = [...document.querySelectorAll("[data-mk-underlay]")];
2010
- pushUnderlay(behind);
2011
- const root = document.documentElement;
2012
- const overflow = root.style.overflow;
2013
- root.style.overflow = "hidden";
2014
- session.push(() => {
2015
- root.style.overflow = overflow;
2016
- if (root.getAttribute("style") === "") root.removeAttribute("style");
2017
- releaseUnderlay(behind, !tearingDown);
2018
- });
2019
- }
2020
- if (autoResize && typeof ResizeObserver === "function") {
2021
- let last = dialog.offsetHeight;
2022
- let resizing = null;
2023
- const observer = new ResizeObserver(() => {
2024
- if (resizing?.isActive()) return;
2025
- const next = dialog.offsetHeight;
2026
- const previous = last;
2027
- last = next;
2028
- if (floating || Math.abs(next - previous) < 2 || !previous || isMorphing(dialog) || reduced()) return;
2029
- resizing = gsap.fromTo(
2030
- dialog,
2031
- { height: previous },
2032
- {
2033
- height: next,
2034
- duration: TIMING.dialog.autoResize,
2035
- ease: EASE.signature,
2036
- clearProps: "height",
2037
- onComplete: () => {
2038
- last = dialog.offsetHeight;
2039
- }
2040
- }
2041
- );
2042
- });
2043
- observer.observe(dialog);
2044
- session.push(() => {
2045
- observer.disconnect();
2046
- resizing?.kill();
2047
- clearStyles([dialog], ["height"]);
2048
- });
2049
- }
2050
- if (drag) {
2051
- session.push(
2052
- attachDragDismiss(dialog, {
2053
- canDrag: () => !isMorphing(dialog) && !floating && !closing && isOpen,
2054
- onDismiss: () => close(true)
2055
- })
2056
- );
2057
- }
2058
- if (placement === "anchor") {
2059
- const onResize = () => {
2060
- if (isOpen && !floating) anchorSurface(dialog, opener?.isConnected ? opener.getBoundingClientRect() : null);
2061
- };
2062
- addEventListener("resize", onResize);
2063
- session.push(() => {
2064
- removeEventListener("resize", onResize);
2065
- clearAnchor(dialog);
2066
- });
2067
- }
2068
- if (floatKey && handle) {
2069
- session.push(attachFloating(dialog, { key: floatKey, handle, corners, isFloating: () => floating, float: lift, dock }));
2070
- const onResize = () => {
2071
- if (floating && !floatingAvailable()) dock();
2072
- };
2073
- addEventListener("resize", onResize);
2074
- session.push(() => removeEventListener("resize", onResize));
2075
- }
2076
- };
2077
- const open = (origin) => {
2078
- if (destroyed || isOpen) return;
2079
- const active = document.activeElement;
2080
- opener = origin !== void 0 ? origin : active instanceof HTMLElement && active !== document.body && !dialog.contains(active) ? active : null;
2081
- closing = false;
2082
- isOpen = true;
2083
- openModal(dialog, modal);
2084
- if (placement === "anchor") anchorSurface(dialog, opener?.getBoundingClientRect());
2085
- if (backdrop && modal) void fadeBackdrop(dialog, "in");
2086
- if (sheet) sheetOpen(dialog);
2087
- else morphOpen(dialog, opener, { hideOrigin: true, liquid, content: options.animateContent === false ? ":scope > :not(*)" : void 0 });
2088
- startSession();
2089
- dialog.querySelector(FIELDS)?.focus({ preventScroll: true });
2090
- emit("mk:open", false, { origin: opener });
2091
- options.onOpen?.();
2092
- };
2093
- const close = (inPlace = false) => {
2094
- if (destroyed || !isOpen || closing) return;
2095
- if (!emit("mk:close", true, { inPlace })) return;
2096
- closing = true;
2097
- if (sheet) sheetClose(dialog, { inPlace });
2098
- else morphCloseWithGhost(dialog, opener, { inPlace, liquid });
2099
- endSession();
2100
- if (floating) settleFloating();
2101
- if (dialog.hasAttribute("open")) closeModal(dialog);
2102
- isOpen = false;
2103
- closing = false;
2104
- if (opener?.isConnected) opener.focus();
2105
- emit("mk:closed");
2106
- options.onClose?.();
2107
- };
2108
- scope.on(dialog, "cancel", (event) => {
2109
- event.preventDefault();
2110
- close();
2111
- });
2112
- scope.on(dialog, "close", () => {
2113
- if (ownCloses > 0) {
2114
- ownCloses -= 1;
2115
- return;
2116
- }
2117
- if (!isOpen || closing) return;
2118
- closedQuietly();
2119
- });
2120
- scope.on(dialog, "keydown", (event) => {
2121
- if (event.key === "Escape" && floating) {
2122
- event.preventDefault();
2123
- close();
2124
- }
2125
- });
2126
- scope.on(dialog, "click", (event) => {
2127
- const target = event.target;
2128
- if (target?.closest('[data-mk-part="close"], [data-mk-close]') && dialog.contains(target)) {
2129
- close();
2130
- return;
2131
- }
2132
- if (target !== dialog || !closeOnBackdrop || floating) return;
2133
- const mouse = event;
2134
- const box = dialog.getBoundingClientRect();
2135
- if (mouse.clientX < box.left || mouse.clientX > box.right || mouse.clientY < box.top || mouse.clientY > box.bottom) close();
2136
- });
2137
- const triggerId = triggers === true ? dialog.id : triggers || "";
2138
- if (triggerId) {
2139
- const selector = `[data-mk-open="${typeof CSS !== "undefined" && CSS.escape ? CSS.escape(triggerId) : triggerId}"]`;
2140
- scope.on(document, "click", (event) => {
2141
- const trigger = event.target?.closest(selector);
2142
- if (!trigger || dialog.contains(trigger)) return;
2143
- event.preventDefault();
2144
- if (isOpen) close();
2145
- else open(trigger);
2146
- });
2147
- }
2148
- dialog.dataset.mkReady = "";
2149
- return {
2150
- open,
2151
- close: () => close(),
2152
- toggle: (origin) => isOpen ? close() : open(origin),
2153
- float: lift,
2154
- dock,
2155
- get isOpen() {
2156
- return isOpen;
2157
- },
2158
- get isFloating() {
2159
- return floating;
2160
- },
2161
- element: dialog,
2162
- destroy() {
2163
- if (destroyed) return;
2164
- tearingDown = true;
2165
- if (isOpen) {
2166
- settleFloating();
2167
- closing = true;
2168
- if (dialog.hasAttribute("open")) closeModal(dialog);
2169
- closedQuietly();
2170
- }
2171
- destroyed = true;
2172
- endSession();
2173
- gsap.killTweensOf(dialog);
2174
- clearStyles([dialog], [...MORPH_STYLES, "height"]);
2175
- scope.dispose();
2176
- delete dialog.dataset.mkReady;
2177
- }
2178
- };
2179
- }
2180
-
2181
- // src/components/menu/engine.ts
2182
- var ITEM = "[data-mk-item]";
2183
- function createMenu(dialog, options = {}) {
2184
- if (!dialog) {
2185
- warnOnce("menu: missing <dialog> element");
2186
- return inert({
2187
- open() {
2188
- },
2189
- close() {
2190
- },
2191
- toggle() {
2192
- },
2193
- float() {
2194
- },
2195
- dock() {
2196
- },
2197
- isOpen: false,
2198
- isFloating: false,
2199
- element: null,
2200
- items: []
2201
- });
2202
- }
2203
- const { closeOnSelect = true } = options;
2204
- const scope = createScope();
2205
- let ticketAnimation;
2206
- if (options.ticket) {
2207
- scope.attr(dialog, "data-mk-ticket", "");
2208
- scope.attr(dialog, "style", dialog.getAttribute("style"));
2209
- for (const item of dialog.querySelectorAll(ITEM)) scope.attr(item, "style", item.getAttribute("style"));
2210
- scope.add(() => ticketAnimation?.kill());
2211
- }
2212
- const items = () => [...dialog.querySelectorAll(ITEM)].filter((item) => !item.hasAttribute("disabled") && item.getAttribute("aria-disabled") !== "true");
2213
- scope.attr(dialog, "role", "menu");
2214
- const markItems = () => {
2215
- for (const item of dialog.querySelectorAll(ITEM)) {
2216
- scope.attr(item, "role", "menuitem");
2217
- scope.attr(item, "tabindex", "-1");
2218
- }
2219
- };
2220
- markItems();
2221
- const surface = createDialog(dialog, {
2222
- ...options,
2223
- placement: "anchor",
2224
- backdrop: false,
2225
- drag: false,
2226
- autoResize: false,
2227
- animateContent: false,
2228
- onOpen: () => {
2229
- markItems();
2230
- const list2 = items();
2231
- if (options.ticket && !reduced()) {
2232
- ticketAnimation?.kill();
2233
- ticketAnimation = gsap.timeline().fromTo(dialog, { clipPath: "inset(0 0 100% 0)" }, { clipPath: "inset(0 0 0% 0)", duration: TIMING.ticketMenu.open, ease: "expo.out" }).fromTo(list2, { yPercent: TIMING.ticketMenu.from }, { yPercent: 0, duration: TIMING.ticketMenu.content, stagger: TIMING.ticketMenu.stagger, ease: "expo.out" }, 0);
2234
- } else flowInMenu(list2);
2235
- list2[0]?.focus({ preventScroll: true });
2236
- options.onOpen?.();
2237
- }
2238
- });
2239
- const select = (item) => {
2240
- const value = item.dataset.mkValue ?? item.textContent?.trim() ?? "";
2241
- dialog.dispatchEvent(new CustomEvent("mk:select", { bubbles: true, detail: { value, item } }));
2242
- options.onSelect?.(value, item);
2243
- if (closeOnSelect) surface.close();
2244
- };
2245
- scope.on(dialog, "click", (event) => {
2246
- const item = event.target?.closest(ITEM);
2247
- if (item && dialog.contains(item) && items().includes(item)) select(item);
2248
- });
2249
- scope.on(dialog, "keydown", (event) => {
2250
- const key = event.key;
2251
- const list2 = items();
2252
- if (!list2.length) return;
2253
- const at = list2.indexOf(document.activeElement);
2254
- const moves = {
2255
- ArrowDown: at < 0 ? 0 : (at + 1) % list2.length,
2256
- ArrowUp: at < 0 ? list2.length - 1 : (at - 1 + list2.length) % list2.length,
2257
- Home: 0,
2258
- End: list2.length - 1
2259
- };
2260
- if (key in moves) {
2261
- event.preventDefault();
2262
- list2[moves[key]]?.focus();
2263
- return;
2264
- }
2265
- const target = event.target;
2266
- if ((key === "Enter" || key === " ") && list2.includes(target) && !target.matches("button, a[href]")) {
2267
- event.preventDefault();
2268
- select(target);
2269
- }
2270
- });
2271
- return {
2272
- open: surface.open,
2273
- close: surface.close,
2274
- toggle: surface.toggle,
2275
- float: surface.float,
2276
- dock: surface.dock,
2277
- get isOpen() {
2278
- return surface.isOpen;
2279
- },
2280
- get isFloating() {
2281
- return surface.isFloating;
2282
- },
2283
- get items() {
2284
- return items();
2285
- },
2286
- element: dialog,
2287
- destroy() {
2288
- surface.destroy();
2289
- scope.dispose();
2290
- }
2291
- };
2292
- }
2293
-
2294
- // src/components/quantity/engine.ts
2295
- function createQuantity(root, options = {}) {
2296
- const input = root?.querySelector("[data-mk-quantity-input]");
2297
- if (!root || !input) return inert({ setValue() {
2298
- }, value: 0 });
2299
- const scope = createScope();
2300
- const min = Number.isFinite(options.min) ? options.min : 1;
2301
- const max = Number.isFinite(options.max) ? Math.max(min, options.max) : Math.max(min, 999);
2302
- const step = Number.isFinite(options.step) && options.step > 0 ? options.step : 1;
2303
- const steps = Math.floor((max - min) / step + 1e-9);
2304
- const upper = Math.min(max, Number((min + steps * step).toFixed(10)));
2305
- const normalize = (n) => Math.max(min, Math.min(upper, Number((min + Math.round((n - min) / step) * step).toFixed(10))));
2306
- const original = input.value;
2307
- const disabled = options.disabled ?? input.disabled;
2308
- const decrease = root.querySelector("[data-mk-quantity-decrease]");
2309
- const increase = root.querySelector("[data-mk-quantity-increase]");
2310
- scope.attr(input, "min", String(min));
2311
- scope.attr(input, "max", String(max));
2312
- scope.attr(input, "step", String(step));
2313
- scope.attr(input, "disabled", disabled ? "" : null);
2314
- scope.attr(root, "data-mk-ready", "");
2315
- const initial = input.value.trim() ? Number(input.value) : NaN;
2316
- let value = normalize(Number.isFinite(options.value) ? options.value : Number.isFinite(initial) ? initial : min);
2317
- let pendingReset = null;
2318
- const typed = () => input.value.trim() && Number.isFinite(input.valueAsNumber) ? input.valueAsNumber : NaN;
2319
- const render = (syncInput = true) => {
2320
- if (pendingReset) {
2321
- if (pendingReset.eventPhase !== 0) return;
2322
- if (!pendingReset.defaultPrevented) value = normalize(Number.isFinite(typed()) ? typed() : min);
2323
- pendingReset = null;
2324
- }
2325
- if (syncInput) input.value = String(value);
2326
- if (decrease) scope.attr(decrease, "disabled", disabled || value <= min ? "" : null);
2327
- if (increase) scope.attr(increase, "disabled", disabled || value >= upper ? "" : null);
2328
- };
2329
- const commit = (next, notify, syncInput) => {
2330
- if (scope.disposed || !Number.isFinite(next)) return;
2331
- if (pendingReset?.eventPhase === 0) pendingReset = null;
2332
- const previous = value;
2333
- value = normalize(next);
2334
- render(syncInput);
2335
- if (notify && value !== previous) {
2336
- options.onChange?.(value);
2337
- root.dispatchEvent(new CustomEvent("mk:change", { bubbles: true, detail: { value, previous } }));
2338
- }
2339
- };
2340
- const setValue = (next, notify = true) => commit(next, notify, true);
2341
- if (decrease) scope.on(decrease, "click", () => {
2342
- if (!decrease.disabled) setValue(value - step);
2343
- });
2344
- if (increase) scope.on(increase, "click", () => {
2345
- if (!increase.disabled) setValue(value + step);
2346
- });
2347
- scope.on(input, "input", () => {
2348
- const n = typed();
2349
- if (Number.isFinite(n) && normalize(n) === n) commit(n, true, false);
2350
- });
2351
- scope.on(input, "change", () => {
2352
- if (Number.isFinite(typed())) setValue(typed());
2353
- else render();
2354
- });
2355
- scope.on(input, "blur", () => render());
2356
- if (input.form) scope.on(input.form, "reset", (event) => {
2357
- render();
2358
- pendingReset = event;
2359
- scope.timeout(() => {
2360
- if (pendingReset === event) render();
2361
- }, 0);
2362
- });
2363
- scope.add(() => {
2364
- input.value = original;
2365
- });
2366
- render();
2367
- return { setValue, get value() {
2368
- return value;
2369
- }, destroy: () => scope.dispose() };
2370
- }
2371
-
2372
- // src/components/pagination/engine.ts
2373
- var positive = (n, fallback) => Number.isFinite(n) ? Math.max(1, Math.min(Number.MAX_SAFE_INTEGER - 32, Math.floor(n))) : fallback;
2374
- function createPagination(root, options = {}) {
2375
- const pages = root?.querySelector("[data-mk-pagination-pages]");
2376
- if (!root || !pages) return inert({ setPage() {
2377
- }, setTotalPages() {
2378
- }, page: 1, totalPages: 1 });
2379
- const scope = createScope();
2380
- const original = [...pages.childNodes];
2381
- const previous = root.querySelector("[data-mk-pagination-previous]");
2382
- const next = root.querySelector("[data-mk-pagination-next]");
2383
- let total = positive(options.totalPages, 10);
2384
- let page = Math.min(total, positive(options.page, 1));
2385
- const siblings = Math.min(10, Math.max(0, Number.isFinite(options.siblings) ? Math.floor(options.siblings) : 1));
2386
- scope.attr(root, "data-mk-ready", "");
2387
- const render = () => {
2388
- const hadFocus = pages.contains(document.activeElement);
2389
- const selected = /* @__PURE__ */ new Set([1, total]);
2390
- for (let n = Math.max(1, page - siblings); n <= Math.min(total, page + siblings); n++) selected.add(n);
2391
- const fragment = document.createDocumentFragment();
2392
- let last = 0;
2393
- for (const n of [...selected].sort((a, b) => a - b)) {
2394
- if (last && n - last > 1) {
2395
- const gap = document.createElement("span");
2396
- gap.className = "mk-pagination__gap";
2397
- gap.textContent = "\u2026";
2398
- gap.setAttribute("aria-hidden", "true");
2399
- fragment.append(gap);
2400
- }
2401
- const button = document.createElement("button");
2402
- button.type = "button";
2403
- button.dataset.mkPage = String(n);
2404
- button.textContent = String(n);
2405
- button.setAttribute("aria-label", options.pageLabel?.(n) ?? `P\xE1gina ${n}`);
2406
- if (n === page) button.setAttribute("aria-current", "page");
2407
- fragment.append(button);
2408
- last = n;
2409
- }
2410
- pages.replaceChildren(fragment);
2411
- if (hadFocus) pages.querySelector("[aria-current]")?.focus();
2412
- if (previous) scope.attr(previous, "disabled", page === 1 ? "" : null);
2413
- if (next) scope.attr(next, "disabled", page === total ? "" : null);
2414
- };
2415
- const setPage = (value, notify = true) => {
2416
- if (scope.disposed || !Number.isFinite(value)) return;
2417
- const candidate = Math.max(1, Math.min(total, Math.round(value)));
2418
- if (candidate === page) return;
2419
- const focused = pages.contains(document.activeElement);
2420
- page = candidate;
2421
- render();
2422
- if (focused) pages.querySelector("[aria-current]")?.focus();
2423
- if (notify) {
2424
- options.onChange?.(page);
2425
- root.dispatchEvent(new CustomEvent("mk:change", { bubbles: true, detail: { page, totalPages: total } }));
2426
- }
2427
- };
2428
- scope.on(root, "click", (event) => {
2429
- const target = event.target.closest("button");
2430
- if (!target || target.disabled) return;
2431
- if (target === previous) setPage(page - 1);
2432
- else if (target === next) setPage(page + 1);
2433
- else if (target.dataset.mkPage) setPage(Number(target.dataset.mkPage));
2434
- });
2435
- scope.on(root, "keydown", (event) => {
2436
- if (!(event.target instanceof HTMLButtonElement)) return;
2437
- const to = event.key === "ArrowRight" ? page + 1 : event.key === "ArrowLeft" ? page - 1 : event.key === "Home" ? 1 : event.key === "End" ? total : null;
2438
- if (to === null) return;
2439
- event.preventDefault();
2440
- setPage(to);
2441
- pages.querySelector("[aria-current]")?.focus();
2442
- });
2443
- scope.add(() => pages.replaceChildren(...original));
2444
- render();
2445
- return {
2446
- setPage,
2447
- setTotalPages(value) {
2448
- if (scope.disposed || !Number.isFinite(value)) return;
2449
- total = positive(value, 1);
2450
- if (page > total) setPage(total);
2451
- else render();
2452
- },
2453
- get page() {
2454
- return page;
2455
- },
2456
- get totalPages() {
2457
- return total;
2458
- },
2459
- destroy: () => scope.dispose()
2460
- };
2461
- }
2462
-
2463
- // src/components/hover-card/engine.ts
2464
- var sequence = 0;
2465
- function createHoverCard(root, options = {}) {
2466
- const trigger = root?.querySelector("[data-mk-hover-trigger]");
2467
- const panel = root?.querySelector("[data-mk-hover-panel]");
2468
- if (!root || !trigger || !panel) return inert({ open() {
2469
- }, close() {
2470
- }, isOpen: false });
2471
- const scope = createScope();
2472
- const openDelay = Number.isFinite(options.openDelay) ? Math.max(0, options.openDelay) : 120;
2473
- const closeDelay = Number.isFinite(options.closeDelay) ? Math.max(0, options.closeDelay) : 140;
2474
- let opened = false;
2475
- let timer;
2476
- let pointerInside = false;
2477
- let id = panel.id;
2478
- if (!id) {
2479
- do {
2480
- id = `mk-hover-${++sequence}`;
2481
- } while (document.getElementById(id));
2482
- }
2483
- scope.attr(panel, "id", id);
2484
- scope.attr(trigger, "aria-controls", id);
2485
- scope.attr(root, "data-mk-placement", options.placement ?? "top");
2486
- scope.attr(root, "data-mk-ready", "");
2487
- const cancel = () => {
2488
- clearTimeout(timer);
2489
- timer = void 0;
2490
- };
2491
- const set = (value) => {
2492
- cancel();
2493
- if (scope.disposed) return;
2494
- const changed = value !== opened;
2495
- opened = value;
2496
- scope.attr(trigger, "aria-expanded", String(value));
2497
- scope.attr(panel, "hidden", value ? null : "");
2498
- scope.attr(root, "data-mk-open", value ? "" : null);
2499
- if (changed) {
2500
- options.onOpenChange?.(value);
2501
- root.dispatchEvent(new CustomEvent("mk:open-change", { bubbles: true, detail: { open: value } }));
2502
- }
2503
- };
2504
- const schedule = (value, delay) => {
2505
- cancel();
2506
- timer = setTimeout(() => set(value), delay);
2507
- };
2508
- scope.on(root, "pointerenter", () => {
2509
- pointerInside = true;
2510
- schedule(true, openDelay);
2511
- });
2512
- scope.on(root, "pointerleave", () => {
2513
- pointerInside = false;
2514
- if (!root.contains(document.activeElement)) schedule(false, closeDelay);
2515
- });
2516
- scope.on(root, "focusin", () => set(true));
2517
- scope.on(root, "focusout", (event) => {
2518
- if (!pointerInside && !root.contains(event.relatedTarget)) schedule(false, closeDelay);
2519
- });
2520
- scope.on(trigger, "click", () => set(true));
2521
- scope.on(document, "pointerdown", (event) => {
2522
- if (!root.contains(event.target)) set(false);
2523
- });
2524
- scope.on(root, "keydown", (event) => {
2525
- if (event.key !== "Escape" || !opened) return;
2526
- event.preventDefault();
2527
- trigger.focus();
2528
- set(false);
2529
- });
2530
- scope.add(cancel);
2531
- set(false);
2532
- return { open: () => set(true), close: () => set(false), get isOpen() {
2533
- return opened;
2534
- }, destroy: () => scope.dispose() };
2535
- }
2536
-
2537
- // src/components/input-otp/engine.ts
2538
- function createInputOtp(root, options = {}) {
2539
- const input = root?.querySelector("[data-mk-otp-input]");
2540
- const slots = root?.querySelector("[data-mk-otp-slots]");
2541
- if (!root || !input || !slots) return inert({ setValue() {
2542
- }, focus() {
2543
- }, value: "" });
2544
- const scope = createScope();
2545
- const length = Number.isFinite(options.length) ? Math.min(16, Math.max(1, Math.round(options.length))) : 6;
2546
- const clean = (text) => text.replace(/[^0-9]/g, "").slice(0, length);
2547
- const original = input.value;
2548
- const originalNodes = [...slots.childNodes];
2549
- let value = clean(options.value ?? input.value);
2550
- let pendingReset = null;
2551
- const cells = Array.from({ length }, () => {
2552
- const cell = document.createElement("span");
2553
- cell.className = "mk-input-otp__slot";
2554
- return cell;
2555
- });
2556
- slots.replaceChildren(...cells);
2557
- scope.attr(slots, "aria-hidden", "true");
2558
- scope.attr(input, "type", "text");
2559
- scope.attr(input, "inputmode", "numeric");
2560
- scope.attr(input, "autocomplete", "one-time-code");
2561
- scope.attr(input, "maxlength", String(length));
2562
- scope.attr(input, "pattern", `[0-9]{${length}}`);
2563
- scope.attr(root, "data-mk-ready", "");
2564
- const render = () => {
2565
- if (pendingReset) {
2566
- if (pendingReset.eventPhase !== 0) return;
2567
- if (!pendingReset.defaultPrevented) value = clean(input.value);
2568
- pendingReset = null;
2569
- }
2570
- input.value = value;
2571
- const active = document.activeElement === input ? Math.min(length - 1, input.selectionStart ?? value.length) : -1;
2572
- cells.forEach((cell, i) => {
2573
- const text = value[i] ? options.mask ? "\u2022" : value[i] : "";
2574
- if (cell.textContent !== text) cell.textContent = text;
2575
- cell.toggleAttribute("data-mk-active", i === active);
2576
- cell.toggleAttribute("data-mk-filled", i < value.length);
2577
- });
2578
- scope.attr(root, "data-mk-complete", value.length === length ? "" : null);
2579
- };
2580
- const setValue = (next, notify = true) => {
2581
- if (scope.disposed) return;
2582
- if (pendingReset?.eventPhase === 0) pendingReset = null;
2583
- const previous = value;
2584
- value = clean(String(next));
2585
- render();
2586
- if (notify && value !== previous) {
2587
- options.onChange?.(value);
2588
- root.dispatchEvent(new CustomEvent("mk:change", { bubbles: true, detail: { value, complete: value.length === length } }));
2589
- if (value.length === length) {
2590
- options.onComplete?.(value);
2591
- root.dispatchEvent(new CustomEvent("mk:complete", { bubbles: true, detail: { value } }));
2592
- }
2593
- }
2594
- };
2595
- scope.on(input, "input", (event) => {
2596
- if (event.isComposing) return;
2597
- const caret = clean(input.value.slice(0, input.selectionStart ?? input.value.length)).length;
2598
- setValue(input.value);
2599
- input.setSelectionRange(caret, caret);
2600
- render();
2601
- });
2602
- scope.on(input, "compositionend", () => setValue(input.value));
2603
- scope.on(input, "paste", (event) => {
2604
- const text = event.clipboardData?.getData("text");
2605
- if (text === void 0) return;
2606
- event.preventDefault();
2607
- const start = input.selectionStart ?? value.length;
2608
- const end = input.selectionEnd ?? start;
2609
- const inserted = clean(text);
2610
- setValue(value.slice(0, start) + inserted + value.slice(end));
2611
- const caret = Math.min(length, start + inserted.length);
2612
- input.setSelectionRange(caret, caret);
2613
- render();
2614
- });
2615
- scope.on(input, "focus", render);
2616
- scope.on(input, "blur", render);
2617
- scope.on(input, "keyup", render);
2618
- scope.on(input, "click", render);
2619
- scope.on(document, "selectionchange", () => {
2620
- if (document.activeElement === input) render();
2621
- });
2622
- if (input.form) scope.on(input.form, "reset", (event) => {
2623
- render();
2624
- pendingReset = event;
2625
- scope.timeout(() => {
2626
- if (pendingReset === event) render();
2627
- }, 0);
2628
- });
2629
- scope.add(() => {
2630
- slots.replaceChildren(...originalNodes);
2631
- input.value = original;
2632
- });
2633
- render();
2634
- return { setValue, focus: () => {
2635
- if (!scope.disposed) input.focus();
2636
- }, get value() {
2637
- return value;
2638
- }, destroy: () => scope.dispose() };
2639
- }
2640
-
2641
- // src/components/studio-dock/engine.ts
2642
- var nextId = 0;
2643
- var PANEL_OFFSET = 76;
2644
- var VIEWPORT_GAP = 12;
2645
- var MIN_SPACE = 320;
2646
- var FOCUSABLE = 'a[href],button:not(:disabled),input:not(:disabled),select:not(:disabled),textarea:not(:disabled),video[controls],[tabindex]:not([tabindex="-1"])';
2647
- function createStudioDock(root, options = {}) {
2648
- const toggleButton = root?.querySelector("[data-mk-studio-toggle]");
2649
- const panel = root?.querySelector("[data-mk-studio-panel]");
2650
- if (!root || !toggleButton || !panel) return inert({ open() {
2651
- }, close() {
2652
- }, toggle() {
2653
- }, selectPage() {
2654
- }, state: { open: false, view: "menu", page: 0 } });
2655
- registerMotion();
2656
- const scope = createScope();
2657
- const context = gsap.context(() => {
2658
- }, root);
2659
- scope.add(() => context.revert());
2660
- const views = [...panel.querySelectorAll("[data-mk-studio-view]")];
2661
- const pages = [...panel.querySelectorAll("[data-mk-studio-page]")];
2662
- const pageButtons = [...root.querySelectorAll("[data-mk-studio-page-to]")];
2663
- const slide = root.querySelector("[data-mk-studio-slide]");
2664
- const tracked = [root, panel, ...slide ? [slide] : []];
2665
- tracked.forEach((el) => {
2666
- const style = el.getAttribute("style");
2667
- scope.add(() => style === null ? el.removeAttribute("style") : el.setAttribute("style", style));
2668
- });
2669
- scope.attr(panel, "id", panel.id || `mk-studio-panel-${++nextId}`);
2670
- scope.attr(panel, "role", panel.getAttribute("role") || "dialog");
2671
- scope.attr(panel, "aria-label", panel.getAttribute("aria-label") || "Studio navigation");
2672
- scope.attr(panel, "tabindex", "-1");
2673
- scope.attr(toggleButton, "aria-controls", panel.id);
2674
- scope.attr(toggleButton, "aria-expanded", "false");
2675
- scope.attr(panel, "hidden", "");
2676
- scope.attr(panel, "aria-hidden", "true");
2677
- scope.attr(root, "data-mk-ready", "");
2678
- let state = { open: false, view: "menu", page: 0 };
2679
- let previousFocus = null;
2680
- let animation;
2681
- let slideStart = null;
2682
- let slideDistance = 0;
2683
- let slideMoved = false;
2684
- let suppressSlideClick = false;
2685
- const place2 = (decide = false) => {
2686
- const view = root.ownerDocument.defaultView;
2687
- if (!state.open || !view) return;
2688
- const rect = root.getBoundingClientRect();
2689
- const offset = parseFloat(view.getComputedStyle(root).getPropertyValue("--mk-studio-dock-offset")) || PANEL_OFFSET;
2690
- const above = rect.bottom - offset - VIEWPORT_GAP;
2691
- const below = view.innerHeight - rect.top - offset - VIEWPORT_GAP;
2692
- if (decide) scope.attr(root, "data-mk-studio-below", above < Math.min(panel.scrollHeight || MIN_SPACE, MIN_SPACE) && below > above ? "" : null);
2693
- const flip = root.hasAttribute("data-mk-studio-below");
2694
- root.style.setProperty("--mk-studio-dock-space", `${Math.max(MIN_SPACE / 2, Math.floor(flip ? below : above))}px`);
2695
- };
2696
- const hidden = () => root.hasAttribute("data-mk-studio-below") ? { clipPath: "inset(0% 0% 100% 0% round 18px)", y: -16, opacity: 0 } : { clipPath: "inset(100% 0% 0% 0% round 18px)", y: 16, opacity: 0 };
2697
- const notify = () => {
2698
- const value = { ...state };
2699
- options.onChange?.(value);
2700
- root.dispatchEvent(new CustomEvent("mk:studio-dock", { bubbles: true, detail: value }));
2701
- };
2702
- const isTabbable = (el) => el.tabIndex >= 0 && !el.closest("[hidden], [inert]") && el.getAttribute("aria-disabled") !== "true";
2703
- const visibleFocus = () => [...panel.querySelectorAll(FOCUSABLE)].filter(isTabbable);
2704
- const focusView = () => {
2705
- if (options.focusOnOpen !== false) (visibleFocus()[0] ?? panel).focus({ preventScroll: true });
2706
- };
2707
- const setView = (view) => {
2708
- state.view = views.length && !views.some((el) => el.dataset.mkStudioView === view) ? "menu" : view;
2709
- views.forEach((el) => scope.attr(el, "hidden", el.dataset.mkStudioView === state.view ? null : ""));
2710
- scope.attr(root, "data-mk-studio-active", state.view);
2711
- panel.querySelectorAll("video").forEach((video) => {
2712
- if (state.view !== "reel") video.pause();
2713
- });
2714
- };
2715
- const selectPage = (index, announce = true) => {
2716
- if (scope.disposed || !pages.length || !Number.isFinite(index)) return;
2717
- state.page = (Math.round(index) % pages.length + pages.length) % pages.length;
2718
- pages.forEach((el, i) => scope.attr(el, "hidden", i === state.page ? null : ""));
2719
- pageButtons.forEach((el) => scope.attr(el, "aria-current", Number(el.dataset.mkStudioPageTo) === state.page ? "true" : null));
2720
- if (announce) notify();
2721
- };
2722
- const open = (view = "menu") => {
2723
- if (scope.disposed) return;
2724
- const wasOpen = state.open;
2725
- if (wasOpen && state.view === view) return;
2726
- if (!wasOpen) {
2727
- const active = root.ownerDocument.activeElement;
2728
- previousFocus = active instanceof HTMLElement && active !== root.ownerDocument.body && !panel.contains(active) ? active : toggleButton;
2729
- }
2730
- animation?.kill();
2731
- state.open = true;
2732
- scope.attr(panel, "hidden", null);
2733
- scope.attr(panel, "inert", null);
2734
- scope.attr(panel, "aria-hidden", "false");
2735
- scope.attr(root, "data-mk-studio-open", "");
2736
- scope.attr(toggleButton, "aria-expanded", "true");
2737
- setView(view);
2738
- place2(!wasOpen);
2739
- if (!reduced()) context.add(() => {
2740
- animation = gsap.fromTo(panel, hidden(), { clipPath: "inset(0% 0% 0% 0% round 18px)", y: 0, opacity: 1, duration: Math.max(0, options.duration ?? 1.3), ease: options.ease ?? "back.out(0.52)", overwrite: true });
2741
- });
2742
- else context.add(() => {
2743
- gsap.set(panel, { clipPath: "inset(0% round 18px)", y: 0, opacity: 1 });
2744
- });
2745
- focusView();
2746
- notify();
2747
- };
2748
- const close = (restoreFocus = true) => {
2749
- if (scope.disposed || !state.open) return;
2750
- animation?.kill();
2751
- state.open = false;
2752
- scope.attr(toggleButton, "aria-expanded", "false");
2753
- scope.attr(root, "data-mk-studio-open", null);
2754
- scope.attr(panel, "inert", "");
2755
- scope.attr(panel, "aria-hidden", "true");
2756
- if (reduced()) scope.attr(panel, "hidden", "");
2757
- else context.add(() => {
2758
- animation = gsap.to(panel, { ...hidden(), duration: Math.max(0, options.duration ?? 1.3), ease: options.ease ?? "back.out(0.52)", overwrite: true, onComplete: () => {
2759
- if (!scope.disposed && !state.open) scope.attr(panel, "hidden", "");
2760
- } });
2761
- });
2762
- panel.querySelectorAll("video").forEach((video) => video.pause());
2763
- if (restoreFocus) (previousFocus?.isConnected ? previousFocus : toggleButton).focus({ preventScroll: true });
2764
- notify();
2765
- };
2766
- scope.on(root, "click", (event) => {
2767
- const target = event.target instanceof Element ? event.target : null;
2768
- if (!target) return;
2769
- if (target.closest("[data-mk-studio-toggle]") === toggleButton) state.open ? close() : open();
2770
- else if (target.closest("[data-mk-studio-close]")) close();
2771
- else if (target.closest("[data-mk-studio-slide]")) {
2772
- if (suppressSlideClick) {
2773
- event.preventDefault();
2774
- suppressSlideClick = false;
2775
- } else open("contact");
2776
- } else {
2777
- const view = target.closest("[data-mk-studio-to]")?.dataset.mkStudioTo;
2778
- if (view === "menu" || view === "contact" || view === "reel") open(view);
2779
- const page = target.closest("[data-mk-studio-page-to]");
2780
- if (page) selectPage(Number(page.dataset.mkStudioPageTo));
2781
- }
2782
- });
2783
- if (root.ownerDocument.defaultView) scope.on(root.ownerDocument.defaultView, "resize", () => place2());
2784
- scope.on(root.ownerDocument, "scroll", () => place2(), { passive: true, capture: true });
2785
- scope.on(root.ownerDocument, "pointerdown", (event) => {
2786
- if (state.open && event.target instanceof Node && !root.contains(event.target)) close(false);
2787
- });
2788
- scope.on(root.ownerDocument, "keydown", (event) => {
2789
- if (!state.open || event.defaultPrevented) return;
2790
- if (event.key === "Escape") {
2791
- event.preventDefault();
2792
- close();
2793
- return;
2794
- }
2795
- if (!(event.target instanceof Node) || !root.contains(event.target)) return;
2796
- if ((event.key === "ArrowLeft" || event.key === "ArrowRight") && event.target.closest("[data-mk-studio-pages]")) {
2797
- event.preventDefault();
2798
- selectPage(state.page + (event.key === "ArrowRight" ? 1 : -1));
2799
- pageButtons.find((el) => Number(el.dataset.mkStudioPageTo) === state.page)?.focus();
2800
- }
2801
- if (event.key === "Tab" && options.trapFocus !== false) {
2802
- const elements = [...root.querySelectorAll(FOCUSABLE)].filter((el) => (el === toggleButton || panel.contains(el)) && isTabbable(el));
2803
- if (!elements.length) {
2804
- event.preventDefault();
2805
- panel.focus();
2806
- return;
2807
- }
2808
- const first = elements[0], last = elements.at(-1);
2809
- if (event.shiftKey && (root.ownerDocument.activeElement === first || root.ownerDocument.activeElement === panel)) {
2810
- event.preventDefault();
2811
- last.focus();
2812
- } else if (!event.shiftKey && root.ownerDocument.activeElement === last) {
2813
- event.preventDefault();
2814
- first.focus();
2815
- }
2816
- }
2817
- });
2818
- if (slide) {
2819
- scope.on(slide, "pointerdown", (event) => {
2820
- if (event.button !== 0) return;
2821
- slideStart = event.clientX;
2822
- slideDistance = 0;
2823
- slideMoved = false;
2824
- });
2825
- scope.on(root.ownerDocument, "pointermove", (event) => {
2826
- if (slideStart === null) return;
2827
- const width = Math.max(0, (slide.parentElement?.clientWidth ?? 0) - slide.offsetWidth);
2828
- slideMoved ||= Math.abs(event.clientX - slideStart) > 5;
2829
- slideDistance = Math.max(0, Math.min(width, event.clientX - slideStart));
2830
- if (!reduced()) slide.style.setProperty("--mk-studio-drag", `${slideDistance}px`);
2831
- });
2832
- const release = (cancel = false) => {
2833
- if (slideStart === null) return;
2834
- const width = Math.max(0, (slide.parentElement?.clientWidth ?? 0) - slide.offsetWidth);
2835
- suppressSlideClick = slideMoved;
2836
- slideStart = null;
2837
- slide.style.removeProperty("--mk-studio-drag");
2838
- if (!cancel && width > 0 && slideDistance / width >= 0.7) open("contact");
2839
- scope.timeout(() => {
2840
- suppressSlideClick = false;
2841
- }, 150);
2842
- };
2843
- scope.on(root.ownerDocument, "pointerup", () => release());
2844
- scope.on(root.ownerDocument, "pointercancel", () => release(true));
2845
- }
2846
- const clocks = [...root.querySelectorAll("[data-mk-studio-timezone]")];
2847
- const clockOriginals = clocks.map((el) => ({ el, text: el.textContent, style: el.getAttribute("style") }));
2848
- const tick = () => clocks.forEach((el) => {
2849
- try {
2850
- el.textContent = new Intl.DateTimeFormat(void 0, { hour: "2-digit", minute: "2-digit", timeZone: el.dataset.mkStudioTimezone }).format(/* @__PURE__ */ new Date());
2851
- } catch {
2852
- }
2853
- });
2854
- if (clocks.length) {
2855
- tick();
2856
- const timer = setInterval(tick, 6e4);
2857
- scope.add(() => clearInterval(timer));
2858
- }
2859
- scope.add(() => clockOriginals.forEach(({ el, text, style }) => {
2860
- el.textContent = text;
2861
- if (style === null) el.removeAttribute("style");
2862
- else el.setAttribute("style", style);
2863
- }));
2864
- setView("menu");
2865
- selectPage(0, false);
2866
- return { open, close, toggle: () => state.open ? close() : open(), selectPage, get state() {
2867
- return { ...state };
2868
- }, destroy() {
2869
- if (scope.disposed) return;
2870
- const focused = root.contains(root.ownerDocument.activeElement);
2871
- animation?.kill();
2872
- panel.querySelectorAll("video").forEach((video) => video.pause());
2873
- scope.dispose();
2874
- if (focused) toggleButton.focus({ preventScroll: true });
2875
- } };
2876
- }
2877
-
2878
- // src/components/trailer/engine.ts
2879
- var time = (value) => {
2880
- const seconds = Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
2881
- return `${Math.floor(seconds / 60).toString().padStart(2, "0")}:${(seconds % 60).toString().padStart(2, "0")}`;
2882
- };
2883
- function createTrailer(root, options = {}) {
2884
- const video = root?.querySelector("video");
2885
- if (!root || !video || root.tagName !== "DIALOG") return inert({ open() {
2886
- }, close() {
2887
- }, toggle() {
2888
- }, play: async () => false, pause() {
2889
- }, seek() {
2890
- }, setVolume() {
2891
- }, isOpen: false });
2892
- const scope = createScope();
2893
- const get = (name) => root.querySelector(`[data-mk-trailer-${name}]`);
2894
- const playButton = get("play");
2895
- const muteButton = get("mute");
2896
- const fullButton = get("fullscreen");
2897
- const fullTarget = get("stage") ?? video;
2898
- const captionsButton = get("captions");
2899
- const seekInput = get("seek");
2900
- const volumeInput = get("volume");
2901
- const output = get("time");
2902
- const status = get("status");
2903
- const originalText = [output, status].filter((el) => !!el).map((el) => [el, el.textContent]);
2904
- scope.add(() => originalText.forEach(([el, text]) => {
2905
- el.textContent = text;
2906
- }));
2907
- scope.attr(root, "data-mk-trailer-ready", "");
2908
- scope.attr(root, "data-mk-trailer-state", "paused");
2909
- const controls = video.controls;
2910
- if (playButton && muteButton && seekInput && (!video.querySelector("track") || captionsButton)) video.controls = false;
2911
- scope.add(() => {
2912
- video.controls = controls;
2913
- });
2914
- for (const input of [seekInput, volumeInput]) {
2915
- if (!input) continue;
2916
- const initialValue = input.value;
2917
- scope.add(() => {
2918
- input.value = initialValue;
2919
- });
2920
- scope.attr(input, "min", "0");
2921
- scope.attr(input, "max", "1");
2922
- scope.attr(input, "step", input === volumeInput ? ".01" : ".1");
2923
- scope.attr(input, "aria-label", input.getAttribute("aria-label") ?? (input === volumeInput ? "Volumen" : "Posici\xF3n del video"));
2924
- }
2925
- if (status) scope.attr(status, "role", "status");
2926
- const tell = (message) => {
2927
- if (!scope.disposed && status) status.textContent = message;
2928
- };
2929
- const sync = () => {
2930
- if (scope.disposed) return;
2931
- const duration = Number.isFinite(video.duration) ? Math.max(0, video.duration) : 0;
2932
- scope.attr(root, "data-mk-trailer-state", video.ended ? "ended" : video.paused ? "paused" : "playing");
2933
- if (playButton) {
2934
- scope.attr(playButton, "aria-label", video.paused || video.ended ? "Reproducir" : "Pausar");
2935
- scope.attr(playButton, "aria-pressed", String(!video.paused && !video.ended));
2936
- }
2937
- if (muteButton) {
2938
- scope.attr(muteButton, "aria-label", video.muted ? "Activar sonido" : "Silenciar");
2939
- scope.attr(muteButton, "aria-pressed", String(video.muted));
2940
- }
2941
- if (seekInput) {
2942
- scope.attr(seekInput, "max", String(duration || 1));
2943
- scope.attr(seekInput, "disabled", duration ? null : "");
2944
- scope.attr(seekInput, "aria-valuetext", `${time(video.currentTime)} de ${time(duration)}`);
2945
- seekInput.value = String(Number.isFinite(video.currentTime) ? video.currentTime : 0);
2946
- }
2947
- if (volumeInput) volumeInput.value = String(video.muted ? 0 : video.volume);
2948
- if (captionsButton) {
2949
- scope.attr(captionsButton, "disabled", video.textTracks.length ? null : "");
2950
- scope.attr(captionsButton, "aria-pressed", String(video.textTracks[0]?.mode === "showing"));
2951
- }
2952
- if (output) output.textContent = `${time(video.currentTime)} / ${time(duration)}`;
2953
- };
2954
- let playRequest = 0;
2955
- let wantsPlayback = false;
2956
- const pause = () => {
2957
- if (!scope.disposed) {
2958
- wantsPlayback = false;
2959
- ++playRequest;
2960
- video.pause();
2961
- sync();
2962
- }
2963
- };
2964
- const play = async () => {
2965
- if (scope.disposed) return false;
2966
- wantsPlayback = true;
2967
- const request = ++playRequest;
2968
- try {
2969
- await video.play();
2970
- if (scope.disposed || request !== playRequest) {
2971
- if (scope.disposed || !wantsPlayback) video.pause();
2972
- return false;
2973
- }
2974
- tell("");
2975
- sync();
2976
- return true;
2977
- } catch {
2978
- if (scope.disposed || request !== playRequest) return false;
2979
- wantsPlayback = false;
2980
- tell("No se pudo reproducir el video. Revisa la fuente y vuelve a intentarlo.");
2981
- sync();
2982
- return false;
2983
- }
2984
- };
2985
- const seek = (seconds) => {
2986
- if (scope.disposed || !Number.isFinite(seconds) || !Number.isFinite(video.duration) || video.duration <= 0) return;
2987
- video.currentTime = Math.max(0, Math.min(video.duration, seconds));
2988
- sync();
2989
- };
2990
- const setVolume = (volume) => {
2991
- if (scope.disposed || !Number.isFinite(volume)) return;
2992
- video.volume = Math.max(0, Math.min(1, volume));
2993
- video.muted = volume <= 0;
2994
- sync();
2995
- };
2996
- const exitFullscreen = () => {
2997
- if (document.fullscreenElement !== fullTarget) return;
2998
- void document.exitFullscreen?.().catch(() => {
2999
- });
3000
- };
3001
- const dialog = createDialog(root, {
3002
- triggers: options.triggers,
3003
- closeOnBackdrop: options.closeOnBackdrop ?? true,
3004
- drag: false,
3005
- autoResize: false,
3006
- animateContent: false,
3007
- onOpen: () => {
3008
- sync();
3009
- if (options.autoplay) void play();
3010
- options.onOpen?.();
3011
- },
3012
- onClose: () => {
3013
- ++playRequest;
3014
- pause();
3015
- exitFullscreen();
3016
- options.onClose?.();
3017
- }
3018
- });
3019
- if (playButton) scope.on(playButton, "click", () => video.paused || video.ended ? void play() : pause());
3020
- if (muteButton) scope.on(muteButton, "click", () => {
3021
- video.muted = !video.muted;
3022
- sync();
3023
- });
3024
- if (seekInput) scope.on(seekInput, "input", () => seek(Number(seekInput.value)));
3025
- if (volumeInput) scope.on(volumeInput, "input", () => setVolume(Number(volumeInput.value)));
3026
- if (captionsButton) scope.on(captionsButton, "click", () => {
3027
- const track = video.textTracks[0];
3028
- if (track) track.mode = track.mode === "showing" ? "hidden" : "showing";
3029
- sync();
3030
- });
3031
- const fullscreen = async () => {
3032
- if (scope.disposed) return;
3033
- try {
3034
- if (document.fullscreenElement === fullTarget) await document.exitFullscreen?.();
3035
- else if (fullTarget.requestFullscreen) {
3036
- await fullTarget.requestFullscreen();
3037
- if (scope.disposed || !dialog.isOpen) exitFullscreen();
3038
- } else tell("La pantalla completa no est\xE1 disponible en este navegador.");
3039
- } catch {
3040
- tell("No se pudo abrir la pantalla completa.");
3041
- }
3042
- };
3043
- if (fullButton) {
3044
- scope.attr(fullButton, "aria-label", "Pantalla completa");
3045
- scope.on(fullButton, "click", () => {
3046
- void fullscreen();
3047
- });
3048
- scope.on(document, "fullscreenchange", () => {
3049
- scope.attr(fullButton, "aria-label", document.fullscreenElement === fullTarget ? "Salir de pantalla completa" : "Pantalla completa");
3050
- });
3051
- }
3052
- for (const event of ["loadedmetadata", "durationchange", "timeupdate", "play", "pause", "ended", "volumechange"]) scope.on(video, event, sync);
3053
- scope.on(video, "error", () => {
3054
- tell("El video no est\xE1 disponible.");
3055
- scope.attr(root, "data-mk-trailer-state", "error");
3056
- });
3057
- scope.on(root, "keydown", (event) => {
3058
- if (!dialog.isOpen || event.target instanceof Element && event.target.closest("button, input, select, textarea, a, [contenteditable]")) return;
3059
- if (event.key === " " || event.key.toLowerCase() === "k") {
3060
- event.preventDefault();
3061
- video.paused ? void play() : pause();
3062
- } else if (event.key === "ArrowRight" || event.key === "ArrowLeft") {
3063
- event.preventDefault();
3064
- seek(video.currentTime + (event.key === "ArrowRight" ? 5 : -5));
3065
- } else if (event.key.toLowerCase() === "m") {
3066
- video.muted = !video.muted;
3067
- sync();
3068
- }
3069
- });
3070
- sync();
3071
- return {
3072
- open: (origin) => {
3073
- if (!scope.disposed) dialog.open(origin);
3074
- },
3075
- close: () => {
3076
- if (!scope.disposed) dialog.close();
3077
- },
3078
- toggle: (origin) => {
3079
- if (!scope.disposed) dialog.toggle(origin);
3080
- },
3081
- play,
3082
- pause,
3083
- seek,
3084
- setVolume,
3085
- get isOpen() {
3086
- return dialog.isOpen;
3087
- },
3088
- destroy() {
3089
- if (scope.disposed) return;
3090
- wantsPlayback = false;
3091
- ++playRequest;
3092
- video.pause();
3093
- exitFullscreen();
3094
- dialog.destroy();
3095
- scope.dispose();
3096
- }
3097
- };
3098
- }
3099
-
3100
- // src/core/dates.ts
3101
- function toDate(input, fallback = /* @__PURE__ */ new Date()) {
3102
- if (input instanceof Date) return Number.isNaN(input.getTime()) ? startOfDay(fallback) : startOfDay(input);
3103
- if (typeof input === "string") {
3104
- const day = /^(\d{4})-(\d{2})-(\d{2})$/.exec(input.trim());
3105
- if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3]));
3106
- }
3107
- if (typeof input === "string" || typeof input === "number") {
3108
- const parsed = new Date(input);
3109
- if (!Number.isNaN(parsed.getTime())) return startOfDay(parsed);
3110
- }
3111
- return startOfDay(fallback);
3112
- }
3113
- function toDateTime(input) {
3114
- if (input instanceof Date) return Number.isNaN(input.getTime()) ? null : input;
3115
- if (typeof input === "string" && /^\d{4}-\d{2}-\d{2}$/.test(input.trim())) return toDate(input);
3116
- const parsed = new Date(input);
3117
- return Number.isNaN(parsed.getTime()) ? null : parsed;
3118
- }
3119
- var startOfDay = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate());
3120
- var addDays = (date, days) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);
3121
- function addMonths(date, months) {
3122
- const target = new Date(date.getFullYear(), date.getMonth() + months, 1);
3123
- const last = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
3124
- return new Date(target.getFullYear(), target.getMonth(), Math.min(date.getDate(), last));
3125
- }
3126
- var startOfMonth = (date) => new Date(date.getFullYear(), date.getMonth(), 1);
3127
- function startOfWeek(date, firstDay = 0) {
3128
- const shift = (date.getDay() - firstDay + 7) % 7;
3129
- return addDays(startOfDay(date), -shift);
3130
- }
3131
- var sameDay = (a, b) => !!a && !!b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
3132
- var sameMonth = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
3133
- var pad = (n) => String(n).padStart(2, "0");
3134
- var dayKey = (date) => `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
3135
- function monthWeeks(date, firstDay = 0) {
3136
- const first = startOfMonth(date);
3137
- const last = new Date(date.getFullYear(), date.getMonth() + 1, 0);
3138
- const weeks = [];
3139
- for (let start = startOfWeek(first, firstDay); start <= last; start = addDays(start, 7)) {
3140
- weeks.push(Array.from({ length: 7 }, (_, i) => addDays(start, i)));
3141
- }
3142
- return weeks;
3143
- }
3144
- var weekDays = (date, firstDay = 0) => Array.from({ length: 7 }, (_, i) => addDays(startOfWeek(date, firstDay), i));
3145
- function weekdayNames(locale, firstDay = 0, width = "short") {
3146
- const format = safeFormat(locale, { weekday: width });
3147
- return Array.from({ length: 7 }, (_, i) => format.format(new Date(2024, 8, 1 + (firstDay + i) % 7)));
3148
- }
3149
- function safeFormat(locale, options) {
3150
- try {
3151
- return new Intl.DateTimeFormat(locale, options);
3152
- } catch {
3153
- return new Intl.DateTimeFormat(void 0, options);
3154
- }
3155
- }
3156
- var capitalize = (text) => text.charAt(0).toLocaleUpperCase() + text.slice(1);
3157
- function fromJson(value) {
3158
- if (typeof value !== "string") return value;
3159
- try {
3160
- return JSON.parse(value);
3161
- } catch {
3162
- return void 0;
3163
- }
3164
- }
3165
- var clampFirstDay = (n) => Number.isInteger(n) && n >= 0 && n <= 6 ? n : 0;
3166
-
3167
- // src/components/calendar/engine.ts
3168
- var SLIDE = 30;
3169
- var SLIDE_OUT = 0.12;
3170
- var SLIDE_GAP = 0.1;
3171
- var SLIDE_DURATION = 0.25;
3172
- var CELL_STAGGER = 5e-3;
3173
- var EVENT_STAGGER = 0.02;
3174
- function createCalendar(root, options = {}) {
3175
- const grid = root?.querySelector("[data-mk-calendar-grid]");
3176
- if (!root || !grid) {
3177
- const now = toDate(null);
3178
- return inert({
3179
- next() {
3180
- },
3181
- prev() {
3182
- },
3183
- goToday() {
3184
- },
3185
- setDate() {
3186
- },
3187
- setView() {
3188
- },
3189
- setEvents() {
3190
- },
3191
- select() {
3192
- },
3193
- date: now,
3194
- view: "month",
3195
- selected: null,
3196
- range: { start: now, end: now, view: "month" }
3197
- });
3198
- }
3199
- registerMotion();
3200
- const scope = createScope();
3201
- const ctx = gsap.context(() => {
3202
- });
3203
- scope.add(() => ctx.revert());
3204
- const locale = options.locale ?? "es";
3205
- const firstDay = clampFirstDay(options.firstDay);
3206
- const maxEvents = Number.isFinite(options.maxEvents) ? Math.max(0, Math.floor(options.maxEvents)) : 3;
3207
- const labels = {
3208
- more: options.labels?.more ?? ((n) => `+${n} m\xE1s`),
3209
- events: options.labels?.events ?? ((n) => n === 1 ? "1 evento" : `${n} eventos`),
3210
- status: { pending: "pendiente", done: "completado", cancelled: "cancelado", ...options.labels?.status }
3211
- };
3212
- let date = toDate(options.date);
3213
- let view = options.view === "week" ? "week" : "month";
3214
- let selected = options.selected ? toDate(options.selected) : null;
3215
- let focusDay = selected ?? date;
3216
- let events = [];
3217
- let byDay = /* @__PURE__ */ new Map();
3218
- let first = true;
3219
- const today = () => toDate(options.today ?? null);
3220
- const title = root.querySelector("[data-mk-calendar-title]");
3221
- const prevButton = root.querySelector("[data-mk-calendar-prev]");
3222
- const nextButton = root.querySelector("[data-mk-calendar-next]");
3223
- const todayButton = root.querySelector("[data-mk-calendar-today]");
3224
- const viewButtons = [...root.querySelectorAll("[data-mk-calendar-view]")];
3225
- const originalGrid = [...grid.childNodes];
3226
- const originalTitle = title ? [...title.childNodes] : [];
3227
- scope.add(() => {
3228
- grid.replaceChildren(...originalGrid);
3229
- title?.replaceChildren(...originalTitle);
3230
- });
3231
- scope.attr(root, "data-mk-ready", "");
3232
- scope.attr(grid, "role", "grid");
3233
- if (title) {
3234
- if (!title.id) scope.attr(title, "id", `mk-calendar-${Math.random().toString(36).slice(2, 8)}`);
3235
- scope.attr(grid, "aria-labelledby", title.id);
3236
- }
3237
- const monthTitle = safeFormat(locale, { month: "long", year: "numeric" });
3238
- const rangeTitle = safeFormat(locale, { day: "numeric", month: "short", year: "numeric" });
3239
- const fullDay = safeFormat(locale, { weekday: "long", day: "numeric", month: "long", year: "numeric" });
3240
- const timeFormat = safeFormat(locale, { hour: "numeric", minute: "2-digit" });
3241
- const index = (list2) => {
3242
- events = Array.isArray(list2) ? list2.filter((e) => e && toDateTime(e.start)) : [];
3243
- byDay = /* @__PURE__ */ new Map();
3244
- const sorted = [...events].sort((a, b) => toDateTime(a.start).getTime() - toDateTime(b.start).getTime());
3245
- for (const event of sorted) {
3246
- const start = toDate(toDateTime(event.start));
3247
- const endTime = event.end ? toDateTime(event.end) : null;
3248
- const end = endTime && endTime > start ? toDate(endTime) : start;
3249
- for (let day = start, n = 0; day <= end && n < 62; day = addDays(day, 1), n++) {
3250
- const key = dayKey(day);
3251
- byDay.set(key, [...byDay.get(key) ?? [], event]);
3252
- }
3253
- }
3254
- };
3255
- index(fromJson(options.events) ?? []);
3256
- const days = () => view === "week" ? [weekDays(date, firstDay)] : monthWeeks(date, firstDay);
3257
- const range = () => {
3258
- const weeks = days();
3259
- return { start: weeks[0][0], end: weeks[weeks.length - 1][6], view };
3260
- };
3261
- const inRange = (day) => {
3262
- const r = range();
3263
- return day >= r.start && day <= r.end;
3264
- };
3265
- const header = () => {
3266
- const row = document.createElement("div");
3267
- row.className = "mk-calendar__head";
3268
- row.setAttribute("role", "row");
3269
- const long = weekdayNames(locale, firstDay, "short");
3270
- const narrow = weekdayNames(locale, firstDay, "narrow");
3271
- long.forEach((name, i) => {
3272
- const cell = document.createElement("div");
3273
- cell.className = "mk-calendar__weekday";
3274
- cell.setAttribute("role", "columnheader");
3275
- cell.innerHTML = '<span class="mk-calendar__weekday-long"></span><span class="mk-calendar__weekday-narrow" aria-hidden="true"></span>';
3276
- cell.firstElementChild.textContent = name;
3277
- cell.lastElementChild.textContent = narrow[i];
3278
- row.append(cell);
3279
- });
3280
- return row;
3281
- };
3282
- const chip = (event) => {
3283
- const button = document.createElement("button");
3284
- button.type = "button";
3285
- button.className = "mk-calendar__event";
3286
- button.dataset.mkEvent = String(event.id);
3287
- const status = event.status ?? "pending";
3288
- button.dataset.state = status;
3289
- if (event.color) button.style.setProperty("--mk-calendar-event-color", event.color);
3290
- const start = toDateTime(event.start);
3291
- const time2 = event.allDay ? "" : timeFormat.format(start);
3292
- button.innerHTML = '<span class="mk-calendar__status" aria-hidden="true"></span><span class="mk-calendar__event-title"></span><span class="mk-calendar__event-time"></span>';
3293
- button.children[1].textContent = event.title;
3294
- button.children[2].textContent = time2;
3295
- button.setAttribute("aria-label", [event.title, time2, labels.status[status]].filter(Boolean).join(", "));
3296
- return button;
3297
- };
3298
- const body = () => {
3299
- const wrap = document.createElement("div");
3300
- wrap.className = "mk-calendar__body";
3301
- wrap.dataset.view = view;
3302
- wrap.setAttribute("role", "rowgroup");
3303
- const now = today();
3304
- const focusKey = dayKey(focusDay);
3305
- for (const week of days()) {
3306
- const row = document.createElement("div");
3307
- row.className = "mk-calendar__week";
3308
- row.setAttribute("role", "row");
3309
- for (const day of week) {
3310
- const key = dayKey(day);
3311
- const cell = document.createElement("div");
3312
- cell.className = "mk-calendar__day";
3313
- cell.setAttribute("role", "gridcell");
3314
- cell.dataset.mkDate = key;
3315
- if (view === "month" && !sameMonth(day, date)) cell.dataset.outside = "";
3316
- if (sameDay(day, now)) cell.dataset.today = "";
3317
- const isSelected = sameDay(day, selected);
3318
- cell.setAttribute("aria-selected", String(isSelected));
3319
- const list2 = byDay.get(key) ?? [];
3320
- const number = document.createElement("button");
3321
- number.type = "button";
3322
- number.className = "mk-calendar__number";
3323
- number.dataset.mkDay = key;
3324
- number.textContent = view === "week" ? `${day.getDate()}` : String(day.getDate());
3325
- number.tabIndex = key === focusKey ? 0 : -1;
3326
- number.setAttribute("aria-label", `${capitalize(fullDay.format(day))}${list2.length ? `, ${labels.events(list2.length)}` : ""}`);
3327
- if (sameDay(day, now)) number.setAttribute("aria-current", "date");
3328
- cell.append(number);
3329
- if (list2.length) {
3330
- const box = document.createElement("div");
3331
- box.className = "mk-calendar__events";
3332
- const shown2 = view === "week" ? list2 : list2.slice(0, maxEvents);
3333
- for (const event of shown2) box.append(chip(event));
3334
- if (shown2.length < list2.length) {
3335
- const more = document.createElement("button");
3336
- more.type = "button";
3337
- more.className = "mk-calendar__more";
3338
- more.dataset.mkMore = key;
3339
- more.textContent = labels.more(list2.length - shown2.length);
3340
- box.append(more);
3341
- }
3342
- cell.append(box);
3343
- }
3344
- row.append(cell);
3345
- }
3346
- wrap.append(row);
3347
- }
3348
- return wrap;
3349
- };
3350
- let current2 = null;
3351
- const leaving = /* @__PURE__ */ new Set();
3352
- scope.add(() => leaving.forEach((el) => el.remove()));
3353
- const syncChrome = () => {
3354
- if (title) {
3355
- const r = range();
3356
- let text = capitalize(monthTitle.format(date));
3357
- if (view === "week") {
3358
- const format = rangeTitle;
3359
- text = format.formatRange ? format.formatRange(r.start, r.end) : `${rangeTitle.format(r.start)} \u2013 ${rangeTitle.format(r.end)}`;
3360
- }
3361
- title.textContent = text;
3362
- }
3363
- for (const button of viewButtons) {
3364
- scope.attr(button, "aria-pressed", String(button.dataset.mkCalendarView === view));
3365
- }
3366
- };
3367
- const render = (direction) => {
3368
- const next = body();
3369
- const motion = !reduced();
3370
- if (!current2) {
3371
- grid.replaceChildren(header(), next);
3372
- } else if (motion && direction !== 0) {
3373
- const old = current2;
3374
- old.style.top = `${old.offsetTop}px`;
3375
- old.classList.add("mk-calendar__body--leaving");
3376
- old.setAttribute("aria-hidden", "true");
3377
- old.querySelectorAll("button").forEach((b) => b.tabIndex = -1);
3378
- leaving.add(old);
3379
- grid.append(next);
3380
- ctx.add(() => {
3381
- gsap.to(old, { x: -SLIDE * direction, opacity: 0, duration: SLIDE_OUT, ease: "power1.in", onComplete: () => {
3382
- old.remove();
3383
- leaving.delete(old);
3384
- } });
3385
- gsap.fromTo(next, { x: SLIDE * direction, opacity: 0 }, { x: 0, opacity: 1, duration: SLIDE_DURATION, delay: SLIDE_GAP, ease: "power2.out", clearProps: "transform,opacity" });
3386
- });
3387
- } else {
3388
- current2.replaceWith(next);
3389
- }
3390
- current2 = next;
3391
- syncChrome();
3392
- if (motion) {
3393
- ctx.add(() => {
3394
- if (first) flowIn(next, { target: ".mk-calendar__day", stagger: CELL_STAGGER });
3395
- flowIn(next, { target: ".mk-calendar__event, .mk-calendar__more", stagger: EVENT_STAGGER, delay: first ? 0.1 : direction ? SLIDE_GAP + SLIDE_DURATION * 0.5 : 0 });
3396
- });
3397
- }
3398
- first = false;
3399
- };
3400
- const focusButton = () => grid.querySelector(`.mk-calendar__body:not(.mk-calendar__body--leaving) [data-mk-day="${dayKey(focusDay)}"]`);
3401
- const navigate = (to, focus = false) => {
3402
- if (scope.disposed) return;
3403
- const from = date;
3404
- const moved = view === "week" ? !sameDay(startOfWeek(to, firstDay), startOfWeek(from, firstDay)) : !sameMonth(to, from);
3405
- date = to;
3406
- focusDay = to;
3407
- if (moved) {
3408
- render(to > from ? 1 : -1);
3409
- const r = range();
3410
- options.onNavigate?.(r);
3411
- root.dispatchEvent(new CustomEvent("mk:navigate", { bubbles: true, detail: r }));
3412
- } else {
3413
- grid.querySelectorAll("[data-mk-day]").forEach((b) => b.tabIndex = b.dataset.mkDay === dayKey(to) ? 0 : -1);
3414
- }
3415
- if (focus) focusButton()?.focus();
3416
- };
3417
- const select = (value, notify = true) => {
3418
- if (scope.disposed) return;
3419
- selected = value === null ? null : toDate(value);
3420
- grid.querySelectorAll(".mk-calendar__day").forEach((cell) => cell.setAttribute("aria-selected", String(!!selected && cell.dataset.mkDate === dayKey(selected))));
3421
- if (selected && notify) {
3422
- options.onSelect?.(selected);
3423
- root.dispatchEvent(new CustomEvent("mk:select", { bubbles: true, detail: { date: selected, key: dayKey(selected) } }));
3424
- }
3425
- };
3426
- scope.on(root, "click", (e) => {
3427
- const target = e.target.closest("button");
3428
- if (!target || !root.contains(target) || target.disabled) return;
3429
- if (target === prevButton) navigate(view === "week" ? addDays(date, -7) : addMonths(date, -1));
3430
- else if (target === nextButton) navigate(view === "week" ? addDays(date, 7) : addMonths(date, 1));
3431
- else if (target === todayButton) navigate(today(), true);
3432
- else if (target.dataset.mkCalendarView) setView(target.dataset.mkCalendarView);
3433
- else if (target.dataset.mkEvent !== void 0) {
3434
- const event = events.find((ev) => String(ev.id) === target.dataset.mkEvent);
3435
- if (event) {
3436
- options.onEventClick?.(event);
3437
- root.dispatchEvent(new CustomEvent("mk:event", { bubbles: true, detail: { event } }));
3438
- }
3439
- } else if (target.dataset.mkDay || target.dataset.mkMore) {
3440
- const day = toDate(target.dataset.mkDay ?? target.dataset.mkMore);
3441
- focusDay = day;
3442
- grid.querySelectorAll("[data-mk-day]").forEach((b) => b.tabIndex = b.dataset.mkDay === dayKey(day) ? 0 : -1);
3443
- select(day);
3444
- }
3445
- });
3446
- scope.on(grid, "keydown", (e) => {
3447
- const event = e;
3448
- const target = event.target;
3449
- if (!target.dataset?.mkDay) return;
3450
- const day = toDate(target.dataset.mkDay);
3451
- const map = {
3452
- ArrowLeft: () => addDays(day, -1),
3453
- ArrowRight: () => addDays(day, 1),
3454
- ArrowUp: () => addDays(day, -7),
3455
- ArrowDown: () => addDays(day, 7),
3456
- Home: () => startOfWeek(day, firstDay),
3457
- End: () => addDays(startOfWeek(day, firstDay), 6),
3458
- PageUp: () => addMonths(day, event.shiftKey ? -12 : -1),
3459
- PageDown: () => addMonths(day, event.shiftKey ? 12 : 1)
3460
- };
3461
- const to = map[event.key]?.();
3462
- if (!to) return;
3463
- event.preventDefault();
3464
- if (!event.key.startsWith("Page") && inRange(to)) {
3465
- focusDay = to;
3466
- grid.querySelectorAll("[data-mk-day]").forEach((b) => b.tabIndex = b.dataset.mkDay === dayKey(to) ? 0 : -1);
3467
- focusButton()?.focus();
3468
- } else navigate(to, true);
3469
- });
3470
- const setView = (next) => {
3471
- if (scope.disposed || next !== "month" && next !== "week" || next === view) return;
3472
- view = next;
3473
- date = focusDay;
3474
- render(0);
3475
- const r = range();
3476
- options.onNavigate?.(r);
3477
- root.dispatchEvent(new CustomEvent("mk:navigate", { bubbles: true, detail: r }));
3478
- };
3479
- render(0);
3480
- return {
3481
- next: () => navigate(view === "week" ? addDays(date, 7) : addMonths(date, 1)),
3482
- prev: () => navigate(view === "week" ? addDays(date, -7) : addMonths(date, -1)),
3483
- goToday: () => navigate(today()),
3484
- setDate: (value) => navigate(toDate(value, date)),
3485
- setView,
3486
- setEvents(list2) {
3487
- if (scope.disposed) return;
3488
- const hadFocus = grid.contains(document.activeElement);
3489
- index(fromJson(list2) ?? []);
3490
- const fresh = body();
3491
- current2?.replaceWith(fresh);
3492
- current2 = fresh;
3493
- if (hadFocus) focusButton()?.focus();
3494
- },
3495
- select,
3496
- get date() {
3497
- return date;
3498
- },
3499
- get view() {
3500
- return view;
3501
- },
3502
- get selected() {
3503
- return selected;
3504
- },
3505
- get range() {
3506
- return range();
3507
- },
3508
- destroy: () => scope.dispose()
3509
- };
3510
- }
3511
-
3512
- // src/components/slot-picker/engine.ts
3513
- var SLIDE2 = 30;
3514
- var SLIDE_DURATION2 = 0.25;
3515
- var slotEaseReady = false;
3516
- function createSlotPicker(root, options = {}) {
3517
- const daysHost = root?.querySelector("[data-mk-slot-days]");
3518
- const timesHost = root?.querySelector("[data-mk-slot-times]");
3519
- if (!root || !daysHost || !timesHost) {
3520
- return inert({ selectDate() {
3521
- }, selectTime() {
3522
- }, setSlots() {
3523
- }, date: null, time: null, value: null });
3524
- }
3525
- registerMotion();
3526
- if (!slotEaseReady && typeof window !== "undefined") {
3527
- CustomEase.create("mk-slot-in", ".38,.49,0,1.1");
3528
- slotEaseReady = true;
3529
- }
3530
- const scope = createScope();
3531
- const ctx = gsap.context(() => {
3532
- });
3533
- scope.add(() => ctx.revert());
3534
- const locale = options.locale ?? "es";
3535
- const firstDay = clampFirstDay(options.firstDay);
3536
- const labels = {
3537
- placeholder: options.labels?.placeholder ?? "Elige un d\xEDa para ver los horarios.",
3538
- empty: options.labels?.empty ?? "No hay horarios este d\xEDa.",
3539
- loading: options.labels?.loading ?? "Cargando horarios\u2026",
3540
- heading: options.labels?.heading ?? ((d) => capitalize(safeFormat(locale, { weekday: "long", day: "numeric", month: "long" }).format(d)))
3541
- };
3542
- const min = options.min !== void 0 ? toDate(options.min) : null;
3543
- const max = options.max !== void 0 ? toDate(options.max) : null;
3544
- const closedList = fromJson(options.closedDays);
3545
- const closed = new Set((Array.isArray(closedList) ? closedList : []).filter((n) => Number.isInteger(n)));
3546
- let slots = fromJson(options.slots) ?? [];
3547
- const initial = (() => {
3548
- const v = options.value;
3549
- if (typeof v === "string") {
3550
- const match = /^(\d{4}-\d{2}-\d{2})(?:T(\d{1,2}:\d{2}))?/.exec(v);
3551
- return match ? { date: toDate(match[1]), time: match[2] ?? null } : null;
3552
- }
3553
- return v ? { date: toDate(v.date), time: v.time ?? null } : null;
3554
- })();
3555
- let month = initial?.date ?? toDate(options.date);
3556
- let date = initial?.date ?? (options.date !== void 0 ? toDate(options.date) : null);
3557
- let time2 = initial?.time ?? null;
3558
- let focusDay = date ?? month;
3559
- let times = [];
3560
- let request = 0;
3561
- const title = root.querySelector("[data-mk-slot-title]");
3562
- const heading = root.querySelector("[data-mk-slot-heading]");
3563
- const prev = root.querySelector("[data-mk-slot-prev]");
3564
- const next = root.querySelector("[data-mk-slot-next]");
3565
- const output = root.querySelector("[data-mk-slot-value]");
3566
- const originals = [daysHost, timesHost, title, heading].filter(Boolean).map((el) => [el, [...el.childNodes]]);
3567
- scope.add(() => originals.forEach(([el, nodes]) => el.replaceChildren(...nodes)));
3568
- if (output) {
3569
- const before = output.value;
3570
- scope.add(() => {
3571
- output.value = before;
3572
- });
3573
- }
3574
- scope.attr(root, "data-mk-ready", "");
3575
- scope.attr(daysHost, "role", "grid");
3576
- scope.attr(timesHost, "role", "radiogroup");
3577
- if (heading) {
3578
- if (!heading.id) scope.attr(heading, "id", `mk-slot-${Math.random().toString(36).slice(2, 8)}`);
3579
- scope.attr(timesHost, "aria-labelledby", heading.id);
3580
- }
3581
- if (title) {
3582
- if (!title.id) scope.attr(title, "id", `mk-slot-month-${Math.random().toString(36).slice(2, 8)}`);
3583
- scope.attr(daysHost, "aria-labelledby", title.id);
3584
- }
3585
- const monthTitle = safeFormat(locale, { month: "long", year: "numeric" });
3586
- const fullDay = safeFormat(locale, { weekday: "long", day: "numeric", month: "long", year: "numeric" });
3587
- const disabled = (d) => min && d < min || max && d > max || closed.has(d.getDay()) || !!options.isDisabled?.(d);
3588
- let daysBody = null;
3589
- const leaving = /* @__PURE__ */ new Set();
3590
- scope.add(() => leaving.forEach((el) => el.remove()));
3591
- const buildDays = () => {
3592
- const wrap = document.createElement("div");
3593
- wrap.className = "mk-slot-picker__days";
3594
- wrap.setAttribute("role", "rowgroup");
3595
- const head = document.createElement("div");
3596
- head.className = "mk-slot-picker__weekdays";
3597
- head.setAttribute("role", "row");
3598
- for (const name of weekdayNames(locale, firstDay, "short")) {
3599
- const cell = document.createElement("span");
3600
- cell.setAttribute("role", "columnheader");
3601
- cell.textContent = name.slice(0, 2);
3602
- head.append(cell);
3603
- }
3604
- wrap.append(head);
3605
- const focusKey = dayKey(focusDay);
3606
- for (const week of monthWeeks(month, firstDay)) {
3607
- const row = document.createElement("div");
3608
- row.className = "mk-slot-picker__week";
3609
- row.setAttribute("role", "row");
3610
- for (const d of week) {
3611
- const cell = document.createElement("span");
3612
- cell.setAttribute("role", "gridcell");
3613
- if (!sameMonth(d, month)) {
3614
- row.append(cell);
3615
- continue;
3616
- }
3617
- const button = document.createElement("button");
3618
- button.type = "button";
3619
- button.className = "mk-slot-picker__day";
3620
- button.dataset.mkSlotDay = dayKey(d);
3621
- button.textContent = String(d.getDate());
3622
- button.tabIndex = dayKey(d) === focusKey ? 0 : -1;
3623
- button.setAttribute("aria-label", capitalize(fullDay.format(d)));
3624
- if (disabled(d)) button.disabled = true;
3625
- if (sameDay(d, /* @__PURE__ */ new Date())) button.setAttribute("aria-current", "date");
3626
- cell.setAttribute("aria-selected", String(sameDay(d, date)));
3627
- cell.append(button);
3628
- row.append(cell);
3629
- }
3630
- wrap.append(row);
3631
- }
3632
- return wrap;
3633
- };
3634
- const renderDays = (direction) => {
3635
- const fresh = buildDays();
3636
- if (title) title.textContent = capitalize(monthTitle.format(month));
3637
- if (prev) scope.attr(prev, "disabled", min && new Date(month.getFullYear(), month.getMonth(), 0) < min ? "" : null);
3638
- if (next) scope.attr(next, "disabled", max && new Date(month.getFullYear(), month.getMonth() + 1, 1) > max ? "" : null);
3639
- if (daysBody && direction && !reduced()) {
3640
- const old = daysBody;
3641
- old.style.top = `${old.offsetTop}px`;
3642
- old.classList.add("mk-slot-picker__leaving");
3643
- old.setAttribute("aria-hidden", "true");
3644
- leaving.add(old);
3645
- daysHost.append(fresh);
3646
- ctx.add(() => {
3647
- gsap.to(old, { x: -SLIDE2 * direction, opacity: 0, duration: SLIDE_DURATION2, ease: "power1.out", onComplete: () => {
3648
- old.remove();
3649
- leaving.delete(old);
3650
- } });
3651
- gsap.fromTo(fresh, { x: SLIDE2 * direction, opacity: 0 }, { x: 0, opacity: 1, duration: SLIDE_DURATION2, ease: "power1.out", clearProps: "transform,opacity" });
3652
- });
3653
- } else if (daysBody) daysBody.replaceWith(fresh);
3654
- else daysHost.replaceChildren(fresh);
3655
- daysBody = fresh;
3656
- };
3657
- const dayButton = (d) => daysHost.querySelector(`.mk-slot-picker__days:not(.mk-slot-picker__leaving) [data-mk-slot-day="${dayKey(d)}"]`);
3658
- const moveFocus = (to, focus) => {
3659
- focusDay = to;
3660
- if (!sameMonth(to, month)) {
3661
- const direction = to > month ? 1 : -1;
3662
- month = to;
3663
- renderDays(direction);
3664
- } else daysHost.querySelectorAll("[data-mk-slot-day]").forEach((b) => b.tabIndex = b.dataset.mkSlotDay === dayKey(to) ? 0 : -1);
3665
- if (focus) dayButton(to)?.focus();
3666
- };
3667
- let timesBody = null;
3668
- let firstList = true;
3669
- const buildTimes = (state) => {
3670
- const wrap = document.createElement("div");
3671
- wrap.className = "mk-slot-picker__list";
3672
- if (state !== "ready" || !times.length) {
3673
- const note = document.createElement("p");
3674
- note.className = "mk-slot-picker__note";
3675
- note.textContent = state === "placeholder" ? labels.placeholder : state === "loading" ? labels.loading : labels.empty;
3676
- wrap.append(note);
3677
- return wrap;
3678
- }
3679
- const focusTime = time2 && times.includes(time2) ? time2 : times[0];
3680
- for (const t of times) {
3681
- const button = document.createElement("button");
3682
- button.type = "button";
3683
- button.className = "mk-slot-picker__time";
3684
- button.setAttribute("role", "radio");
3685
- button.dataset.mkSlotTime = t;
3686
- button.textContent = t;
3687
- button.setAttribute("aria-checked", String(t === time2));
3688
- button.tabIndex = t === focusTime ? 0 : -1;
3689
- wrap.append(button);
3690
- }
3691
- return wrap;
3692
- };
3693
- const renderTimes = (state, direction) => {
3694
- const fresh = buildTimes(state);
3695
- scope.attr(timesHost, "aria-busy", state === "loading" ? "true" : null);
3696
- const motion = !reduced();
3697
- if (timesBody && direction && motion) {
3698
- const old = timesBody;
3699
- old.style.top = `${old.offsetTop}px`;
3700
- old.classList.add("mk-slot-picker__leaving");
3701
- old.setAttribute("aria-hidden", "true");
3702
- old.querySelectorAll("button").forEach((b) => b.tabIndex = -1);
3703
- leaving.add(old);
3704
- timesHost.append(fresh);
3705
- ctx.add(() => {
3706
- gsap.to(old, { x: -SLIDE2 * direction, opacity: 0, duration: SLIDE_DURATION2, ease: "power1.out", onComplete: () => {
3707
- old.remove();
3708
- leaving.delete(old);
3709
- } });
3710
- gsap.fromTo(fresh, { x: SLIDE2 * direction, opacity: 0 }, { x: 0, opacity: 1, duration: SLIDE_DURATION2, ease: "power1.out", clearProps: "transform,opacity" });
3711
- });
3712
- } else if (timesBody) timesBody.replaceWith(fresh);
3713
- else timesHost.replaceChildren(fresh);
3714
- timesBody = fresh;
3715
- if (state === "ready" && times.length && motion && firstList) {
3716
- firstList = false;
3717
- ctx.add(() => flowIn(fresh, { target: ".mk-slot-picker__time", style: 2, startScale: 0.7, blur: 32, duration: 0.3, stagger: 0.02, ease: "mk-slot-in" }));
3718
- }
3719
- };
3720
- const resolve = (d) => {
3721
- const source = slots;
3722
- if (Array.isArray(source)) return source;
3723
- if (typeof source === "function") return source(d);
3724
- return source?.[dayKey(d)] ?? [];
3725
- };
3726
- const clean = (list2) => Array.isArray(list2) ? [...new Set(list2.filter((t) => typeof t === "string" && /^\d{1,2}:\d{2}$/.test(t)))] : [];
3727
- const load = (direction) => {
3728
- if (!date) {
3729
- times = [];
3730
- renderTimes("placeholder", 0);
3731
- return;
3732
- }
3733
- const mine = ++request;
3734
- let result;
3735
- try {
3736
- result = resolve(date);
3737
- } catch {
3738
- result = [];
3739
- }
3740
- if (result && typeof result.then === "function") {
3741
- renderTimes("loading", direction);
3742
- result.then(
3743
- (list2) => {
3744
- if (mine === request && !scope.disposed) {
3745
- times = clean(list2);
3746
- renderTimes("ready", 0);
3747
- }
3748
- },
3749
- () => {
3750
- if (mine === request && !scope.disposed) {
3751
- times = [];
3752
- renderTimes("ready", 0);
3753
- }
3754
- }
3755
- );
3756
- } else {
3757
- times = clean(result);
3758
- if (time2 && !times.includes(time2)) time2 = null;
3759
- renderTimes("ready", direction);
3760
- }
3761
- };
3762
- const syncHeading = () => {
3763
- if (!heading) return;
3764
- if (date) {
3765
- heading.textContent = labels.heading(date);
3766
- if (!heading.hasAttribute("data-mk-shown")) scope.attr(heading, "data-mk-shown", "");
3767
- }
3768
- };
3769
- const emit = () => {
3770
- const key = date ? dayKey(date) : "";
3771
- const value = date && time2 ? `${key}T${time2}` : null;
3772
- if (output) {
3773
- output.value = value ?? "";
3774
- output.dispatchEvent(new Event("input", { bubbles: true }));
3775
- output.dispatchEvent(new Event("change", { bubbles: true }));
3776
- }
3777
- if (date && time2 && value) {
3778
- const detail = { date, time: time2, key, value };
3779
- options.onChange?.(detail);
3780
- root.dispatchEvent(new CustomEvent("mk:change", { bubbles: true, detail }));
3781
- }
3782
- };
3783
- const selectDate = (input, notify = true) => {
3784
- if (scope.disposed) return;
3785
- const d = toDate(input);
3786
- if (disabled(d)) return;
3787
- const direction = date ? Math.sign(d.getTime() - date.getTime()) : 0;
3788
- if (sameDay(d, date)) return;
3789
- date = d;
3790
- time2 = null;
3791
- focusDay = d;
3792
- if (!sameMonth(d, month)) {
3793
- const dir = d > month ? 1 : -1;
3794
- month = d;
3795
- renderDays(dir);
3796
- }
3797
- daysHost.querySelectorAll('[role="gridcell"]').forEach((cell) => {
3798
- const b = cell.querySelector("[data-mk-slot-day]");
3799
- if (b) {
3800
- cell.setAttribute("aria-selected", String(b.dataset.mkSlotDay === dayKey(d)));
3801
- b.tabIndex = b.dataset.mkSlotDay === dayKey(d) ? 0 : -1;
3802
- }
3803
- });
3804
- syncHeading();
3805
- load(direction);
3806
- if (notify) {
3807
- options.onDateChange?.(d);
3808
- emit();
3809
- }
3810
- };
3811
- const selectTime = (t, notify = true) => {
3812
- if (scope.disposed || !date) return;
3813
- if (t !== null && !times.includes(t)) return;
3814
- time2 = t;
3815
- timesHost.querySelectorAll("[data-mk-slot-time]").forEach((b) => {
3816
- b.setAttribute("aria-checked", String(b.dataset.mkSlotTime === t));
3817
- b.tabIndex = (t ? b.dataset.mkSlotTime === t : b === timesHost.querySelector("[data-mk-slot-time]")) ? 0 : -1;
3818
- });
3819
- if (notify) emit();
3820
- };
3821
- scope.on(root, "click", (e) => {
3822
- const target = e.target.closest("button");
3823
- if (!target || target.disabled || !root.contains(target)) return;
3824
- if (target === prev) moveFocus(addMonths(month, -1), false);
3825
- else if (target === next) moveFocus(addMonths(month, 1), false);
3826
- else if (target.dataset.mkSlotDay) selectDate(target.dataset.mkSlotDay);
3827
- else if (target.dataset.mkSlotTime) selectTime(target.dataset.mkSlotTime);
3828
- });
3829
- scope.on(daysHost, "keydown", (e) => {
3830
- const event = e;
3831
- const key = event.target.dataset?.mkSlotDay;
3832
- if (!key) return;
3833
- const d = toDate(key);
3834
- const to = {
3835
- ArrowLeft: () => addDays(d, -1),
3836
- ArrowRight: () => addDays(d, 1),
3837
- ArrowUp: () => addDays(d, -7),
3838
- ArrowDown: () => addDays(d, 7),
3839
- Home: () => startOfWeek(d, firstDay),
3840
- End: () => addDays(startOfWeek(d, firstDay), 6),
3841
- PageUp: () => addMonths(d, -1),
3842
- PageDown: () => addMonths(d, 1)
3843
- }[event.key]?.();
3844
- if (!to) return;
3845
- event.preventDefault();
3846
- moveFocus(to, true);
3847
- });
3848
- scope.on(timesHost, "keydown", (e) => {
3849
- const event = e;
3850
- const current2 = event.target.dataset?.mkSlotTime;
3851
- if (!current2) return;
3852
- const i = times.indexOf(current2);
3853
- const to = { ArrowRight: i + 1, ArrowDown: i + 1, ArrowLeft: i - 1, ArrowUp: i - 1, Home: 0, End: times.length - 1 }[event.key];
3854
- if (to === void 0) return;
3855
- event.preventDefault();
3856
- const t = times[(to + times.length) % times.length];
3857
- selectTime(t);
3858
- timesHost.querySelector(`[data-mk-slot-time="${t}"]`)?.focus();
3859
- });
3860
- renderDays(0);
3861
- if (date) {
3862
- syncHeading();
3863
- load(0);
3864
- if (time2 && !times.includes(time2)) time2 = null;
3865
- } else renderTimes("placeholder", 0);
3866
- return {
3867
- selectDate: (d) => selectDate(d),
3868
- selectTime: (t) => selectTime(t),
3869
- setSlots(source) {
3870
- if (scope.disposed) return;
3871
- slots = fromJson(source) ?? [];
3872
- load(0);
3873
- },
3874
- get date() {
3875
- return date;
3876
- },
3877
- get time() {
3878
- return time2;
3879
- },
3880
- get value() {
3881
- return date && time2 ? `${dayKey(date)}T${time2}` : null;
3882
- },
3883
- destroy: () => scope.dispose()
3884
- };
3885
- }
3886
-
3887
- export {
3888
- PATHS,
3889
- springPath,
3890
- SIGNATURE_LINEAR,
3891
- gsap,
3892
- ScrollTrigger,
3893
- SplitText,
3894
- CustomEase,
3895
- Flip,
3896
- ELASTIC,
3897
- EASE,
3898
- registerMotion,
3899
- easeOut,
3900
- easeOutCubic,
3901
- easeInCubic,
3902
- bezier,
3903
- spring,
3904
- eased,
3905
- createChannelState,
3906
- stepChannel,
3907
- channels,
3908
- springEase,
3909
- splitWords,
3910
- splitGraphemes,
3911
- requestFrame,
3912
- nextFrame,
3913
- clearStyles,
3914
- MORPH_STYLES,
3915
- motionSpring,
3916
- springDuration,
3917
- springLinear,
3918
- flowIn,
3919
- flowOut,
3920
- stepChange,
3921
- flowInMenu,
3922
- flowInPalette,
3923
- flowInForm,
3924
- flowInLanding,
3925
- flowInContent,
3926
- pointer,
3927
- bindPointer,
3928
- takeMovement,
3929
- revealFrom,
3930
- tweenNumber,
3931
- countTo,
3932
- revealCounter,
3933
- anchorSurface,
3934
- clearAnchor,
3935
- attachDragDismiss,
3936
- floatingAvailable,
3937
- clampRect,
3938
- savedFloat,
3939
- forgetFloat,
3940
- liftWindow,
3941
- dockWindow,
3942
- attachFloating,
3943
- transparentColor,
3944
- openModal,
3945
- closeModal,
3946
- fadeBackdrop,
3947
- backdropVeil,
3948
- ghostOf,
3949
- liquidOpen,
3950
- liquidClose,
3951
- isMorphing,
3952
- stopMorph,
3953
- showOrigin,
3954
- releaseShared,
3955
- shareInto,
3956
- shareBack,
3957
- morphOpen,
3958
- morphClose,
3959
- morphCloseWithGhost,
3960
- sheetOpen,
3961
- sheetClose,
3962
- pushUnderlay,
3963
- releaseUnderlay,
3964
- createDialog,
3965
- createMenu,
3966
- createQuantity,
3967
- createPagination,
3968
- createHoverCard,
3969
- createInputOtp,
3970
- createStudioDock,
3971
- createTrailer,
3972
- toDate,
3973
- dayKey,
3974
- createCalendar,
3975
- createSlotPicker
3976
- };
3977
- //# sourceMappingURL=chunk-TFNRIZHU.js.map