@yewdiel21/motion-kit 0.10.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (459) hide show
  1. package/README.md +81 -0
  2. package/bin/motion-kit.mjs +3 -3
  3. package/dist/auto/index.d.ts +56 -3
  4. package/dist/auto/index.js +107 -3
  5. package/dist/auto/index.js.map +1 -1
  6. package/dist/{chunk-XAKC2QY7.js → chunk-6IRJYXJU.js} +3 -28
  7. package/dist/chunk-6IRJYXJU.js.map +1 -0
  8. package/dist/chunk-A6QQCF6V.js +21333 -0
  9. package/dist/chunk-A6QQCF6V.js.map +1 -0
  10. package/dist/chunk-JXRS3OEA.js +3638 -0
  11. package/dist/chunk-JXRS3OEA.js.map +1 -0
  12. package/dist/chunk-QP4QJOEN.js +72 -0
  13. package/dist/chunk-QP4QJOEN.js.map +1 -0
  14. package/dist/css/components/activity-feed.css +240 -0
  15. package/dist/css/components/add-to-cart.css +72 -0
  16. package/dist/css/components/attachment.css +266 -0
  17. package/dist/css/components/bidirectional-slider.css +168 -0
  18. package/dist/css/components/breadcrumb.css +110 -0
  19. package/dist/css/components/chart-tooltip.css +168 -0
  20. package/dist/css/components/chart.css +296 -0
  21. package/dist/css/components/code-block.css +264 -0
  22. package/dist/css/components/color-area.css +82 -0
  23. package/dist/css/components/color-field.css +67 -0
  24. package/dist/css/components/color-picker.css +131 -0
  25. package/dist/css/components/color-slider.css +113 -0
  26. package/dist/css/components/command-search.css +252 -0
  27. package/dist/css/components/context-menu.css +23 -0
  28. package/dist/css/components/credit-card.css +288 -0
  29. package/dist/css/components/data-table.css +686 -0
  30. package/dist/css/components/date-range-picker.css +168 -0
  31. package/dist/css/components/date-time-picker.css +178 -0
  32. package/dist/css/components/drawer.css +58 -0
  33. package/dist/css/components/editable-table.css +201 -0
  34. package/dist/css/components/empty-state.css +61 -0
  35. package/dist/css/components/file-explorer.css +633 -0
  36. package/dist/css/components/filter-builder.css +227 -0
  37. package/dist/css/components/heatmap-chart.css +391 -0
  38. package/dist/css/components/hold-confirm.css +87 -0
  39. package/dist/css/components/hover-card.css +19 -7
  40. package/dist/css/components/image-preview.css +283 -0
  41. package/dist/css/components/json-viewer.css +304 -0
  42. package/dist/css/components/like-button.css +78 -0
  43. package/dist/css/components/link-preview.css +275 -0
  44. package/dist/css/components/loading-button.css +77 -0
  45. package/dist/css/components/multi-select.css +267 -0
  46. package/dist/css/components/nav.css +102 -102
  47. package/dist/css/components/notification-bell.css +127 -0
  48. package/dist/css/components/orbit-menu.css +130 -0
  49. package/dist/css/components/pagination.css +10 -5
  50. package/dist/css/components/password-strength.css +183 -0
  51. package/dist/css/components/pie-chart.css +390 -0
  52. package/dist/css/components/pill-button.css +135 -0
  53. package/dist/css/components/popover.css +25 -0
  54. package/dist/css/components/progress.css +140 -0
  55. package/dist/css/components/questionnaire.css +217 -0
  56. package/dist/css/components/radar-chart.css +370 -0
  57. package/dist/css/components/radial-chart.css +398 -0
  58. package/dist/css/components/range-calendar.css +186 -0
  59. package/dist/css/components/range-slider.css +192 -0
  60. package/dist/css/components/resizable-panel.css +243 -0
  61. package/dist/css/components/rich-text-editor.css +284 -0
  62. package/dist/css/components/sankey-chart.css +358 -0
  63. package/dist/css/components/scratch-card.css +75 -0
  64. package/dist/css/components/scroll-island.css +111 -0
  65. package/dist/css/components/select.css +136 -0
  66. package/dist/css/components/skeleton.css +108 -0
  67. package/dist/css/components/split-view.css +19 -0
  68. package/dist/css/components/star-rating.css +80 -0
  69. package/dist/css/components/stat-card.css +164 -0
  70. package/dist/css/components/swipe-actions.css +105 -0
  71. package/dist/css/components/tag-input.css +244 -0
  72. package/dist/css/components/time-field.css +88 -0
  73. package/dist/css/components/timeline.css +219 -0
  74. package/dist/css/components/toolbar.css +122 -0
  75. package/dist/css/components/tooltip.css +79 -0
  76. package/dist/css/components/tree-view.css +289 -0
  77. package/dist/css/components/virtual-list.css +195 -0
  78. package/dist/css/components/voice-dots.css +70 -0
  79. package/dist/css/tokens.css +185 -181
  80. package/dist/elements/index.d.ts +849 -7
  81. package/dist/elements/index.js +1642 -8
  82. package/dist/elements/index.js.map +1 -1
  83. package/dist/{engine-GDGwQnJE.d.ts → engine-5zRIssTO.d.ts} +11 -1
  84. package/dist/engine-QECQnGz1.d.ts +33 -0
  85. package/dist/index.css +10890 -311
  86. package/dist/index.d.ts +89 -5
  87. package/dist/index.js +273 -9
  88. package/dist/index.js.map +1 -1
  89. package/dist/react/index.d.ts +686 -24
  90. package/dist/react/index.js +2345 -9
  91. package/dist/react/index.js.map +1 -1
  92. package/dist/{reduced-BmBzKH94.d.ts → reduced-6X_bns60.d.ts} +9 -2
  93. package/dist/reveal-BfyKKsw4.d.ts +2474 -0
  94. package/dist/store-CA2Qcun_.d.ts +453 -0
  95. package/package.json +9 -16
  96. package/registry.json +1096 -543
  97. package/src/auto/auto-init.ts +104 -0
  98. package/src/components/activity-feed/README.md +56 -0
  99. package/src/components/activity-feed/activity-feed.css +239 -0
  100. package/src/components/activity-feed/element.ts +36 -0
  101. package/src/components/activity-feed/engine.ts +351 -0
  102. package/src/components/activity-feed/react.tsx +32 -0
  103. package/src/components/add-to-cart/README.md +34 -0
  104. package/src/components/add-to-cart/add-to-cart.css +71 -0
  105. package/src/components/add-to-cart/element.ts +20 -0
  106. package/src/components/add-to-cart/engine.ts +206 -0
  107. package/src/components/add-to-cart/react.tsx +29 -0
  108. package/src/components/attachment/README.md +27 -0
  109. package/src/components/attachment/attachment.css +265 -0
  110. package/src/components/attachment/element.ts +50 -0
  111. package/src/components/attachment/engine.ts +469 -0
  112. package/src/components/attachment/react.tsx +65 -0
  113. package/src/components/bidirectional-slider/README.md +46 -0
  114. package/src/components/bidirectional-slider/bidirectional-slider.css +167 -0
  115. package/src/components/bidirectional-slider/element.ts +42 -0
  116. package/src/components/bidirectional-slider/engine.ts +289 -0
  117. package/src/components/bidirectional-slider/react.tsx +45 -0
  118. package/src/components/breadcrumb/README.md +38 -0
  119. package/src/components/breadcrumb/breadcrumb.css +109 -0
  120. package/src/components/breadcrumb/element.ts +27 -0
  121. package/src/components/breadcrumb/engine.ts +249 -0
  122. package/src/components/breadcrumb/react.tsx +30 -0
  123. package/src/components/chart/README.md +34 -0
  124. package/src/components/chart/chart.css +295 -0
  125. package/src/components/chart/element.ts +43 -0
  126. package/src/components/chart/engine.ts +838 -0
  127. package/src/components/chart/parts.ts +237 -0
  128. package/src/components/chart/react.tsx +50 -0
  129. package/src/components/chart/use-chart.ts +55 -0
  130. package/src/components/chart-tooltip/README.md +53 -0
  131. package/src/components/chart-tooltip/chart-tooltip.css +167 -0
  132. package/src/components/chart-tooltip/element.ts +37 -0
  133. package/src/components/chart-tooltip/engine.ts +442 -0
  134. package/src/components/chart-tooltip/react.tsx +47 -0
  135. package/src/components/code-block/README.md +19 -0
  136. package/src/components/code-block/code-block.css +263 -0
  137. package/src/components/code-block/element.ts +34 -0
  138. package/src/components/code-block/engine.ts +254 -0
  139. package/src/components/code-block/highlight.ts +244 -0
  140. package/src/components/code-block/react.tsx +94 -0
  141. package/src/components/color-area/README.md +50 -0
  142. package/src/components/color-area/color-area.css +81 -0
  143. package/src/components/color-area/element.ts +26 -0
  144. package/src/components/color-area/engine.ts +246 -0
  145. package/src/components/color-area/react.tsx +42 -0
  146. package/src/components/color-field/README.md +43 -0
  147. package/src/components/color-field/color-field.css +66 -0
  148. package/src/components/color-field/element.ts +26 -0
  149. package/src/components/color-field/engine.ts +174 -0
  150. package/src/components/color-field/react.tsx +42 -0
  151. package/src/components/color-picker/README.md +45 -0
  152. package/src/components/color-picker/color-picker.css +130 -0
  153. package/src/components/color-picker/element.ts +45 -0
  154. package/src/components/color-picker/engine.ts +314 -0
  155. package/src/components/color-picker/react.tsx +47 -0
  156. package/src/components/color-slider/README.md +55 -0
  157. package/src/components/color-slider/color-slider.css +112 -0
  158. package/src/components/color-slider/element.ts +26 -0
  159. package/src/components/color-slider/engine.ts +234 -0
  160. package/src/components/color-slider/react.tsx +45 -0
  161. package/src/components/command-search/README.md +15 -0
  162. package/src/components/command-search/command-search.css +251 -0
  163. package/src/components/command-search/element.ts +36 -0
  164. package/src/components/command-search/engine.ts +356 -0
  165. package/src/components/command-search/match.ts +53 -0
  166. package/src/components/command-search/react.tsx +66 -0
  167. package/src/components/context-menu/README.md +31 -0
  168. package/src/components/context-menu/context-menu.css +22 -0
  169. package/src/components/context-menu/element.ts +40 -0
  170. package/src/components/context-menu/engine.ts +153 -0
  171. package/src/components/context-menu/react.tsx +57 -0
  172. package/src/components/credit-card/README.md +20 -0
  173. package/src/components/credit-card/card.ts +77 -0
  174. package/src/components/credit-card/credit-card.css +287 -0
  175. package/src/components/credit-card/element.ts +33 -0
  176. package/src/components/credit-card/engine.ts +410 -0
  177. package/src/components/credit-card/react.tsx +36 -0
  178. package/src/components/data-table/README.md +83 -0
  179. package/src/components/data-table/data-table.css +685 -0
  180. package/src/components/data-table/element.ts +54 -0
  181. package/src/components/data-table/engine.ts +1111 -0
  182. package/src/components/data-table/react.tsx +94 -0
  183. package/src/components/date-range-picker/README.md +51 -0
  184. package/src/components/date-range-picker/date-range-picker.css +167 -0
  185. package/src/components/date-range-picker/element.ts +52 -0
  186. package/src/components/date-range-picker/engine.ts +352 -0
  187. package/src/components/date-range-picker/react.tsx +57 -0
  188. package/src/components/date-time-picker/README.md +48 -0
  189. package/src/components/date-time-picker/date-time-picker.css +177 -0
  190. package/src/components/date-time-picker/element.ts +47 -0
  191. package/src/components/date-time-picker/engine.ts +350 -0
  192. package/src/components/date-time-picker/react.tsx +54 -0
  193. package/src/components/dialog/README.md +103 -102
  194. package/src/components/dialog/element.ts +123 -118
  195. package/src/components/dialog/engine.ts +449 -432
  196. package/src/components/drawer/README.md +28 -0
  197. package/src/components/drawer/drawer.css +57 -0
  198. package/src/components/drawer/element.ts +21 -0
  199. package/src/components/drawer/engine.ts +56 -0
  200. package/src/components/drawer/react.tsx +85 -0
  201. package/src/components/editable-table/README.md +67 -0
  202. package/src/components/editable-table/editable-table.css +200 -0
  203. package/src/components/editable-table/element.ts +45 -0
  204. package/src/components/editable-table/engine.ts +831 -0
  205. package/src/components/editable-table/react.tsx +79 -0
  206. package/src/components/empty-state/README.md +41 -0
  207. package/src/components/empty-state/element.ts +23 -0
  208. package/src/components/empty-state/empty-state.css +60 -0
  209. package/src/components/empty-state/engine.ts +232 -0
  210. package/src/components/empty-state/react.tsx +34 -0
  211. package/src/components/file-explorer/README.md +67 -0
  212. package/src/components/file-explorer/element.ts +39 -0
  213. package/src/components/file-explorer/engine.ts +1307 -0
  214. package/src/components/file-explorer/file-explorer.css +632 -0
  215. package/src/components/file-explorer/react.tsx +77 -0
  216. package/src/components/filter-builder/README.md +47 -0
  217. package/src/components/filter-builder/element.ts +34 -0
  218. package/src/components/filter-builder/engine.ts +396 -0
  219. package/src/components/filter-builder/filter-builder.css +226 -0
  220. package/src/components/filter-builder/react.tsx +36 -0
  221. package/src/components/heatmap-chart/README.md +48 -0
  222. package/src/components/heatmap-chart/element.ts +21 -0
  223. package/src/components/heatmap-chart/engine.ts +281 -0
  224. package/src/components/heatmap-chart/heatmap-chart.css +93 -0
  225. package/src/components/heatmap-chart/react.tsx +14 -0
  226. package/src/components/hold-confirm/README.md +13 -0
  227. package/src/components/hold-confirm/element.ts +24 -0
  228. package/src/components/hold-confirm/engine.ts +216 -0
  229. package/src/components/hold-confirm/hold-confirm.css +86 -0
  230. package/src/components/hold-confirm/react.tsx +28 -0
  231. package/src/components/hover-card/README.md +6 -2
  232. package/src/components/hover-card/engine.ts +98 -7
  233. package/src/components/hover-card/hover-card.css +19 -7
  234. package/src/components/image-preview/README.md +16 -0
  235. package/src/components/image-preview/element.ts +26 -0
  236. package/src/components/image-preview/engine.ts +405 -0
  237. package/src/components/image-preview/image-preview.css +282 -0
  238. package/src/components/image-preview/react.tsx +43 -0
  239. package/src/components/json-viewer/README.md +56 -0
  240. package/src/components/json-viewer/element.ts +37 -0
  241. package/src/components/json-viewer/engine.ts +449 -0
  242. package/src/components/json-viewer/json-viewer.css +303 -0
  243. package/src/components/json-viewer/react.tsx +56 -0
  244. package/src/components/like-button/README.md +13 -0
  245. package/src/components/like-button/element.ts +47 -0
  246. package/src/components/like-button/engine.ts +145 -0
  247. package/src/components/like-button/like-button.css +77 -0
  248. package/src/components/like-button/react.tsx +39 -0
  249. package/src/components/link-preview/README.md +19 -0
  250. package/src/components/link-preview/element.ts +29 -0
  251. package/src/components/link-preview/engine.ts +192 -0
  252. package/src/components/link-preview/link-preview.css +274 -0
  253. package/src/components/link-preview/react.tsx +101 -0
  254. package/src/components/loading-button/README.md +45 -0
  255. package/src/components/loading-button/element.ts +34 -0
  256. package/src/components/loading-button/engine.ts +201 -0
  257. package/src/components/loading-button/loading-button.css +76 -0
  258. package/src/components/loading-button/react.tsx +43 -0
  259. package/src/components/multi-select/README.md +48 -0
  260. package/src/components/multi-select/element.ts +28 -0
  261. package/src/components/multi-select/engine.ts +294 -0
  262. package/src/components/multi-select/multi-select.css +266 -0
  263. package/src/components/multi-select/react.tsx +39 -0
  264. package/src/components/nav/README.md +12 -10
  265. package/src/components/nav/element.ts +5 -5
  266. package/src/components/nav/engine.ts +21 -14
  267. package/src/components/nav/nav.css +102 -102
  268. package/src/components/nav/react.tsx +4 -4
  269. package/src/components/notification-bell/README.md +14 -0
  270. package/src/components/notification-bell/element.ts +48 -0
  271. package/src/components/notification-bell/engine.ts +202 -0
  272. package/src/components/notification-bell/notification-bell.css +126 -0
  273. package/src/components/notification-bell/react.tsx +57 -0
  274. package/src/components/orbit-menu/README.md +46 -0
  275. package/src/components/orbit-menu/element.ts +27 -0
  276. package/src/components/orbit-menu/engine.ts +179 -0
  277. package/src/components/orbit-menu/orbit-menu.css +129 -0
  278. package/src/components/orbit-menu/react.tsx +44 -0
  279. package/src/components/pagination/README.md +1 -1
  280. package/src/components/pagination/engine.ts +50 -4
  281. package/src/components/pagination/pagination.css +10 -5
  282. package/src/components/password-strength/README.md +17 -0
  283. package/src/components/password-strength/element.ts +22 -0
  284. package/src/components/password-strength/engine.ts +212 -0
  285. package/src/components/password-strength/password-strength.css +182 -0
  286. package/src/components/password-strength/react.tsx +36 -0
  287. package/src/components/password-strength/score.ts +62 -0
  288. package/src/components/pie-chart/README.md +48 -0
  289. package/src/components/pie-chart/element.ts +30 -0
  290. package/src/components/pie-chart/engine.ts +283 -0
  291. package/src/components/pie-chart/pie-chart.css +92 -0
  292. package/src/components/pie-chart/react.tsx +14 -0
  293. package/src/components/pill-button/README.md +46 -0
  294. package/src/components/pill-button/element.ts +16 -0
  295. package/src/components/pill-button/engine.ts +77 -0
  296. package/src/components/pill-button/pill-button.css +134 -0
  297. package/src/components/pill-button/react.tsx +32 -0
  298. package/src/components/popover/README.md +44 -0
  299. package/src/components/popover/element.ts +31 -0
  300. package/src/components/popover/engine.ts +114 -0
  301. package/src/components/popover/popover.css +24 -0
  302. package/src/components/popover/react.tsx +50 -0
  303. package/src/components/progress/README.md +17 -0
  304. package/src/components/progress/element.ts +30 -0
  305. package/src/components/progress/engine.ts +173 -0
  306. package/src/components/progress/progress.css +139 -0
  307. package/src/components/progress/react.tsx +35 -0
  308. package/src/components/questionnaire/README.md +32 -0
  309. package/src/components/questionnaire/element.ts +118 -0
  310. package/src/components/questionnaire/engine.ts +255 -0
  311. package/src/components/questionnaire/questionnaire.css +216 -0
  312. package/src/components/questionnaire/react.tsx +140 -0
  313. package/src/components/radar-chart/README.md +48 -0
  314. package/src/components/radar-chart/element.ts +30 -0
  315. package/src/components/radar-chart/engine.ts +327 -0
  316. package/src/components/radar-chart/radar-chart.css +72 -0
  317. package/src/components/radar-chart/react.tsx +14 -0
  318. package/src/components/radial-chart/README.md +48 -0
  319. package/src/components/radial-chart/element.ts +30 -0
  320. package/src/components/radial-chart/engine.ts +290 -0
  321. package/src/components/radial-chart/radial-chart.css +100 -0
  322. package/src/components/radial-chart/react.tsx +14 -0
  323. package/src/components/range-calendar/README.md +58 -0
  324. package/src/components/range-calendar/element.ts +42 -0
  325. package/src/components/range-calendar/engine.ts +390 -0
  326. package/src/components/range-calendar/range-calendar.css +185 -0
  327. package/src/components/range-calendar/react.tsx +56 -0
  328. package/src/components/range-slider/README.md +23 -0
  329. package/src/components/range-slider/element.ts +53 -0
  330. package/src/components/range-slider/engine.ts +316 -0
  331. package/src/components/range-slider/range-slider.css +191 -0
  332. package/src/components/range-slider/react.tsx +66 -0
  333. package/src/components/resizable-panel/README.md +61 -0
  334. package/src/components/resizable-panel/element.ts +36 -0
  335. package/src/components/resizable-panel/engine.ts +551 -0
  336. package/src/components/resizable-panel/react.tsx +74 -0
  337. package/src/components/resizable-panel/resizable-panel.css +242 -0
  338. package/src/components/rich-text-editor/README.md +57 -0
  339. package/src/components/rich-text-editor/element.ts +34 -0
  340. package/src/components/rich-text-editor/engine.ts +673 -0
  341. package/src/components/rich-text-editor/react.tsx +60 -0
  342. package/src/components/rich-text-editor/rich-text-editor.css +283 -0
  343. package/src/components/sankey-chart/README.md +48 -0
  344. package/src/components/sankey-chart/element.ts +31 -0
  345. package/src/components/sankey-chart/engine.ts +401 -0
  346. package/src/components/sankey-chart/react.tsx +14 -0
  347. package/src/components/sankey-chart/sankey-chart.css +60 -0
  348. package/src/components/scratch-card/README.md +15 -0
  349. package/src/components/scratch-card/element.ts +30 -0
  350. package/src/components/scratch-card/engine.ts +257 -0
  351. package/src/components/scratch-card/react.tsx +40 -0
  352. package/src/components/scratch-card/scratch-card.css +74 -0
  353. package/src/components/scroll-island/README.md +34 -0
  354. package/src/components/scroll-island/element.ts +16 -0
  355. package/src/components/scroll-island/engine.ts +252 -0
  356. package/src/components/scroll-island/react.tsx +26 -0
  357. package/src/components/scroll-island/scroll-island.css +110 -0
  358. package/src/components/select/README.md +34 -0
  359. package/src/components/select/element.ts +26 -0
  360. package/src/components/select/engine.ts +267 -0
  361. package/src/components/select/react.tsx +33 -0
  362. package/src/components/select/select.css +135 -0
  363. package/src/components/skeleton/README.md +15 -0
  364. package/src/components/skeleton/element.ts +32 -0
  365. package/src/components/skeleton/engine.ts +104 -0
  366. package/src/components/skeleton/react.tsx +41 -0
  367. package/src/components/skeleton/skeleton.css +107 -0
  368. package/src/components/split-view/README.md +50 -0
  369. package/src/components/split-view/element.ts +34 -0
  370. package/src/components/split-view/engine.ts +114 -0
  371. package/src/components/split-view/react.tsx +63 -0
  372. package/src/components/split-view/split-view.css +18 -0
  373. package/src/components/star-rating/README.md +14 -0
  374. package/src/components/star-rating/element.ts +26 -0
  375. package/src/components/star-rating/engine.ts +217 -0
  376. package/src/components/star-rating/react.tsx +33 -0
  377. package/src/components/star-rating/star-rating.css +79 -0
  378. package/src/components/stat-card/README.md +42 -0
  379. package/src/components/stat-card/element.ts +40 -0
  380. package/src/components/stat-card/engine.ts +283 -0
  381. package/src/components/stat-card/react.tsx +36 -0
  382. package/src/components/stat-card/stat-card.css +163 -0
  383. package/src/components/swipe-actions/README.md +19 -0
  384. package/src/components/swipe-actions/element.ts +26 -0
  385. package/src/components/swipe-actions/engine.ts +260 -0
  386. package/src/components/swipe-actions/react.tsx +80 -0
  387. package/src/components/swipe-actions/swipe-actions.css +104 -0
  388. package/src/components/tag-input/README.md +42 -0
  389. package/src/components/tag-input/element.ts +39 -0
  390. package/src/components/tag-input/engine.ts +313 -0
  391. package/src/components/tag-input/react.tsx +54 -0
  392. package/src/components/tag-input/tag-input.css +243 -0
  393. package/src/components/time-field/README.md +54 -0
  394. package/src/components/time-field/element.ts +38 -0
  395. package/src/components/time-field/engine.ts +110 -0
  396. package/src/components/time-field/react.tsx +45 -0
  397. package/src/components/time-field/time-field.css +87 -0
  398. package/src/components/timeline/README.md +57 -0
  399. package/src/components/timeline/element.ts +31 -0
  400. package/src/components/timeline/engine.ts +300 -0
  401. package/src/components/timeline/react.tsx +59 -0
  402. package/src/components/timeline/timeline.css +218 -0
  403. package/src/components/toolbar/README.md +46 -0
  404. package/src/components/toolbar/element.ts +30 -0
  405. package/src/components/toolbar/engine.ts +230 -0
  406. package/src/components/toolbar/react.tsx +34 -0
  407. package/src/components/toolbar/toolbar.css +121 -0
  408. package/src/components/tooltip/README.md +46 -0
  409. package/src/components/tooltip/element.ts +22 -0
  410. package/src/components/tooltip/engine.ts +288 -0
  411. package/src/components/tooltip/react.tsx +30 -0
  412. package/src/components/tooltip/tooltip.css +78 -0
  413. package/src/components/tree-view/README.md +61 -0
  414. package/src/components/tree-view/element.ts +32 -0
  415. package/src/components/tree-view/engine.ts +743 -0
  416. package/src/components/tree-view/react.tsx +82 -0
  417. package/src/components/tree-view/tree-view.css +288 -0
  418. package/src/components/virtual-list/README.md +81 -0
  419. package/src/components/virtual-list/element.ts +42 -0
  420. package/src/components/virtual-list/engine.ts +678 -0
  421. package/src/components/virtual-list/react.tsx +101 -0
  422. package/src/components/virtual-list/virtual-list.css +194 -0
  423. package/src/components/voice-dots/README.md +48 -0
  424. package/src/components/voice-dots/element.ts +45 -0
  425. package/src/components/voice-dots/engine.ts +243 -0
  426. package/src/components/voice-dots/react.tsx +52 -0
  427. package/src/components/voice-dots/voice-dots.css +69 -0
  428. package/src/core/chips.ts +196 -0
  429. package/src/core/color.ts +304 -0
  430. package/src/core/date-range.ts +67 -0
  431. package/src/core/dates.ts +11 -1
  432. package/src/core/files.ts +107 -0
  433. package/src/core/filter.ts +229 -0
  434. package/src/core/gsap.ts +80 -65
  435. package/src/core/listbox.ts +332 -0
  436. package/src/core/mark.ts +29 -0
  437. package/src/core/position.ts +89 -0
  438. package/src/core/relative-time.ts +77 -0
  439. package/src/core/segment-field.ts +373 -0
  440. package/src/core/segments.ts +153 -0
  441. package/src/core/tree.ts +116 -0
  442. package/src/core/virtual.ts +79 -0
  443. package/src/css/tokens.css +186 -182
  444. package/src/elements/index.ts +186 -0
  445. package/src/index.ts +88 -0
  446. package/src/motion/liquid.ts +14 -4
  447. package/src/motion/micro.ts +248 -0
  448. package/src/motion/sheet.ts +88 -65
  449. package/src/motion/surface.ts +9 -0
  450. package/src/react/index.ts +71 -1
  451. package/dist/chunk-IKQ5FODN.js +0 -1617
  452. package/dist/chunk-IKQ5FODN.js.map +0 -1
  453. package/dist/chunk-J6OCFNGU.js +0 -177
  454. package/dist/chunk-J6OCFNGU.js.map +0 -1
  455. package/dist/chunk-TFNRIZHU.js +0 -3977
  456. package/dist/chunk-TFNRIZHU.js.map +0 -1
  457. package/dist/chunk-XAKC2QY7.js.map +0 -1
  458. package/dist/reveal-jsX-uwUz.d.ts +0 -625
  459. package/dist/store-DYb3tTsZ.d.ts +0 -195
@@ -0,0 +1,19 @@
1
+ # link-preview
2
+
3
+ Tarjeta de enlace con miniatura (o la inicial del dominio), sitio, título y descripción alrededor de un enlace real; o un enlace que previsualiza esa tarjeta en un [hover-card](../hover-card/README.md) al señalar, enfocar o tocar. La app suministra los metadatos: no se descarga nada ni depende de un backend.
4
+
5
+ ```html
6
+ <mk-link-preview class="mk-link-preview"
7
+ url="https://example.com/guia" title="Guía de movimiento" description="Curvas, duraciones y cuándo no animar."
8
+ image="/thumbs/guia.jpg" site-name="Motion Kit"></mk-link-preview>
9
+
10
+ <p>Lee la <mk-link-preview class="mk-link-preview" variant="hover" label="guía de movimiento" url="https://example.com/guia" title="Guía de movimiento"></mk-link-preview>.</p>
11
+ ```
12
+
13
+ `defineElements()`, `createLinkPreview(root, options)` o `<LinkPreview url="…" title="…" description="…" image="…" siteName="…" variant="hover" label="guía" />`.
14
+
15
+ Opciones: `url`, `title`, `description`, `image`, `imageAlt` (por defecto decorativa), `siteName`, `variant='card'|'row'|'hover'` (`row`: miniatura al lado del texto), `label` (texto del enlace en hover), `target` (`_blank` añade `rel="noopener noreferrer"`) y, en hover, `openDelay`, `closeDelay`, `placement`, `onOpenChange`. API: `href` (el enlace usado o `null`), `hoverCard`, `destroy()`. Utilidades: `safeHref(url)`, `safeImage(url)`, `linkDomain(href)`.
16
+
17
+ Los enlaces aceptan sólo http(s) y rutas relativas: `javascript:`, `data:` u otros esquemas (también con espacios o saltos intercalados) dejan una tarjeta sin enlace. Las imágenes aceptan http(s), relativas, `blob:` y `data:image/…`. Todos los textos se insertan como texto. Si la miniatura falla, se oculta y queda la inicial (`data-mk-image="error"`); después de `destroy()` no hay listeners que cambien nada.
18
+
19
+ Con root vacío el motor crea el marcado y lo quita al destruir; con marcado propio (`[data-mk-link-card]`, `img[data-mk-link-image]`, `[data-mk-hover-trigger]` + `[data-mk-hover-panel]`) sólo añade el comportamiento. La tarjeta sigue a Melon Mind: imagen 16:9 con 8px de margen, inicial del sitio, título a dos líneas, descripción y un botón redondo que gira al señalar; en hover, la tarjeta va dentro del cristal inverso. Variables: `--mk-link-radius` (24px), `--mk-link-thumb` (5.5rem). Movimiento reducido quita la escala al pulsar y el giro.
@@ -0,0 +1,29 @@
1
+ import { MkElement, defineElement, type OptionType } from '../../elements/base';
2
+ import { createLinkPreview, type LinkPreviewInstance } from './engine';
3
+
4
+ /**
5
+ * <mk-link-preview class="mk-link-preview" url="https://…" title="…" description="…" image="/thumb.jpg" site-name="Blog"></mk-link-preview>
6
+ * variant="hover" turns it into a link that previews the card (label = link text).
7
+ */
8
+ export class MkLinkPreviewElement extends MkElement<LinkPreviewInstance> {
9
+ static options: Record<string, OptionType> = {
10
+ url: 'string',
11
+ title: 'string',
12
+ description: 'string',
13
+ image: 'string',
14
+ imageAlt: 'string',
15
+ siteName: 'string',
16
+ variant: 'string',
17
+ label: 'string',
18
+ target: 'string',
19
+ openDelay: 'number',
20
+ closeDelay: 'number',
21
+ placement: 'string',
22
+ };
23
+
24
+ protected create(options: Record<string, unknown>) {
25
+ return createLinkPreview(this, options);
26
+ }
27
+ }
28
+
29
+ export const defineLinkPreview = () => defineElement('mk-link-preview', MkLinkPreviewElement);
@@ -0,0 +1,192 @@
1
+ import { createScope } from '../../core/scope';
2
+ import { inert, type Instance } from '../../core/types';
3
+ import { createHoverCard, type HoverCardInstance, type HoverCardOptions } from '../hover-card/engine';
4
+
5
+ /*
6
+ * Link preview: a resource card (thumbnail or domain initial, site, title,
7
+ * description) around a real link, or a link that previews that card in a
8
+ * hover card (pointer, focus, tap). The app supplies the metadata; nothing is
9
+ * fetched. Links accept http(s) and relative URLs only; strings are text; a
10
+ * thumbnail that fails to load gives way to the domain initial.
11
+ * Made into an empty root; with authored markup ([data-mk-link-card],
12
+ * img[data-mk-link-image], [data-mk-hover-trigger]) only the behaviour is added.
13
+ */
14
+
15
+ /** card: image on top (default); row: thumbnail beside the text; hover: a link that previews the card. */
16
+ export type LinkPreviewVariant = 'card' | 'row' | 'hover';
17
+
18
+ /** The arrow of the card's go button (decorative). */
19
+ const GO_ICON =
20
+ '<svg aria-hidden="true" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17L17 7M9 7h8v8"/></svg>';
21
+
22
+ export interface LinkPreviewOptions extends Pick<HoverCardOptions, 'openDelay' | 'closeDelay' | 'placement' | 'onOpenChange'> {
23
+ url?: string;
24
+ title?: string;
25
+ description?: string;
26
+ /** Thumbnail URL (http(s), relative, data:image or blob). */
27
+ image?: string;
28
+ imageAlt?: string;
29
+ siteName?: string;
30
+ variant?: LinkPreviewVariant;
31
+ /** Text of the hover variant's link (default: the title). */
32
+ label?: string;
33
+ /** '_blank' opens a new tab (with rel="noopener noreferrer"). */
34
+ target?: string;
35
+ }
36
+
37
+ export interface LinkPreviewInstance extends Instance {
38
+ /** The link actually used (null when the URL was refused). */
39
+ readonly href: string | null;
40
+ readonly hoverCard: HoverCardInstance | null;
41
+ }
42
+
43
+ // Browsers drop tabs/newlines inside URLs ("java\nscript:"): check what they will see.
44
+ const squash = (url: string) => url.replace(/[\u0000- \u007f]+/g, '');
45
+ const schemeOf = (url: string) => /^([a-z][a-z\d+.-]*):/i.exec(squash(url))?.[1]?.toLowerCase() ?? null;
46
+
47
+ /** http(s) or relative links; anything else (javascript:, data:, vbscript:…) is null. */
48
+ export function safeHref(url: string | null | undefined): string | null {
49
+ if (typeof url !== 'string' || !url.trim()) return null;
50
+ const scheme = schemeOf(url.trim());
51
+ return scheme === null || scheme === 'http' || scheme === 'https' ? url.trim() : null;
52
+ }
53
+
54
+ /** Image sources: http(s), relative, blob: and data:image/… */
55
+ export function safeImage(url: string | null | undefined): string | null {
56
+ if (typeof url !== 'string' || !url.trim()) return null;
57
+ const value = url.trim();
58
+ const scheme = schemeOf(value);
59
+ if (scheme === null || scheme === 'http' || scheme === 'https' || scheme === 'blob') return value;
60
+ return scheme === 'data' && /^data:image\//i.test(squash(value)) ? value : null;
61
+ }
62
+
63
+ /** Host without www. of an absolute link; relative links have none (same on server and client). */
64
+ export function linkDomain(href: string | null) {
65
+ if (!href) return '';
66
+ try {
67
+ return new URL(href.startsWith('//') ? `https:${href}` : href).hostname.replace(/^www\./, '');
68
+ } catch {
69
+ return '';
70
+ }
71
+ }
72
+
73
+ let sequence = 0;
74
+
75
+ const part = (tag: string, name: string, text?: string) => {
76
+ const element = document.createElement(tag);
77
+ element.dataset.mkPart = name;
78
+ if (text !== undefined) element.textContent = text;
79
+ return element;
80
+ };
81
+
82
+ /** The card markup (also used by the hover panel). Text only; the href is already safe. */
83
+ function buildCard(options: LinkPreviewOptions, href: string | null) {
84
+ const domain = linkDomain(href);
85
+ // Spans (not divs): the hover variant lives inside running text.
86
+ const card = document.createElement(href ? 'a' : 'span');
87
+ card.dataset.mkLinkCard = '';
88
+ if (href) {
89
+ card.setAttribute('href', href);
90
+ if (options.target) {
91
+ card.setAttribute('target', options.target);
92
+ if (options.target === '_blank') card.setAttribute('rel', 'noopener noreferrer');
93
+ }
94
+ }
95
+ const id = `mk-link-${++sequence}`;
96
+ const media = part('span', 'media');
97
+ const fallback = part('span', 'fallback', (options.siteName || domain || options.title || '?').trim().charAt(0).toUpperCase());
98
+ fallback.setAttribute('aria-hidden', 'true');
99
+ media.append(fallback);
100
+ const image = safeImage(options.image);
101
+ if (image) {
102
+ const img = document.createElement('img');
103
+ img.dataset.mkLinkImage = '';
104
+ img.alt = options.imageAlt ?? '';
105
+ img.loading = 'lazy';
106
+ img.decoding = 'async';
107
+ img.src = image;
108
+ media.append(img);
109
+ }
110
+ const text = part('span', 'text');
111
+ const site = [options.siteName, domain].filter(Boolean).filter((value, i, all) => all.indexOf(value) === i).join(' · ');
112
+ if (site) {
113
+ const meta = part('span', 'meta');
114
+ const favicon = part('span', 'favicon', (options.siteName || domain).trim().charAt(0).toUpperCase());
115
+ favicon.setAttribute('aria-hidden', 'true');
116
+ meta.append(favicon, part('span', 'site', site));
117
+ text.append(meta);
118
+ }
119
+ const title = part('span', 'title', options.title || domain || href || '');
120
+ title.id = `${id}-title`;
121
+ text.append(title);
122
+ if (options.description) {
123
+ const description = part('span', 'description', options.description);
124
+ description.id = `${id}-description`;
125
+ text.append(description);
126
+ card.setAttribute('aria-describedby', description.id);
127
+ }
128
+ card.setAttribute('aria-labelledby', title.id);
129
+ const go = part('span', 'go');
130
+ go.setAttribute('aria-hidden', 'true');
131
+ go.innerHTML = GO_ICON;
132
+ card.append(media, text, go);
133
+ return card;
134
+ }
135
+
136
+ export function createLinkPreview(root: HTMLElement | null, options: LinkPreviewOptions = {}): LinkPreviewInstance {
137
+ if (!root) return inert({ href: null, hoverCard: null });
138
+ const scope = createScope();
139
+ const variant: LinkPreviewVariant = options.variant === 'hover' || options.variant === 'row' ? options.variant : 'card';
140
+ const href = safeHref(options.url);
141
+ const authored = root.querySelector('[data-mk-link-card], [data-mk-hover-trigger]');
142
+ const made: Node[] = [];
143
+ if (!authored) {
144
+ const card = buildCard(options, href);
145
+ if (variant === 'hover') {
146
+ const trigger = document.createElement(href ? 'a' : 'span');
147
+ trigger.dataset.mkHoverTrigger = '';
148
+ if (href) trigger.setAttribute('href', href);
149
+ else trigger.tabIndex = 0;
150
+ if (href && options.target) {
151
+ trigger.setAttribute('target', options.target);
152
+ if (options.target === '_blank') trigger.setAttribute('rel', 'noopener noreferrer');
153
+ }
154
+ trigger.textContent = options.label || options.title || linkDomain(href) || href || '';
155
+ const panel = document.createElement('span');
156
+ panel.dataset.mkHoverPanel = '';
157
+ panel.setAttribute('role', 'region');
158
+ panel.setAttribute('aria-label', `Vista previa: ${options.title || linkDomain(href)}`);
159
+ panel.hidden = true;
160
+ panel.append(card);
161
+ made.push(trigger, panel);
162
+ } else made.push(card);
163
+ root.append(...made);
164
+ scope.add(() => made.forEach((node) => node.parentNode?.removeChild(node)));
165
+ }
166
+ scope.attr(root, 'data-mk-link-variant', variant);
167
+ if (variant === 'hover' && !root.classList.contains('mk-hover-card')) {
168
+ scope.attr(root, 'class', root.getAttribute('class'));
169
+ root.classList.add('mk-hover-card');
170
+ }
171
+ scope.attr(root, 'data-mk-ready', '');
172
+
173
+ // A thumbnail that fails gives way to the initial (listeners go with destroy).
174
+ for (const img of root.querySelectorAll<HTMLImageElement>('img[data-mk-link-image]')) {
175
+ const failed = () => {
176
+ scope.attr(img, 'hidden', '');
177
+ scope.attr(root, 'data-mk-image', 'error');
178
+ };
179
+ scope.on(img, 'error', failed);
180
+ }
181
+
182
+ const hoverCard = root.querySelector('[data-mk-hover-trigger]') ? createHoverCard(root, options) : null;
183
+ if (hoverCard) scope.add(() => hoverCard.destroy());
184
+
185
+ return {
186
+ get href() {
187
+ return href ?? root.querySelector<HTMLAnchorElement>('a[data-mk-link-card], a[data-mk-hover-trigger]')?.getAttribute('href') ?? null;
188
+ },
189
+ hoverCard,
190
+ destroy: () => scope.dispose(),
191
+ };
192
+ }
@@ -0,0 +1,274 @@
1
+ /* link-preview — Melonmind content box: a 24 px card with the image on top (16 px inner radius, 8 px inset), favicon and
2
+ site, a two-line title, the description and a round go button that springs on hover. Row: thumbnail beside the text.
3
+ Hover: the card in Melonmind's inverse glass popover. */
4
+ .mk-link-preview,
5
+ mk-link-preview {
6
+ --mk-link-radius: var(--mk-radius-lg, 24px);
7
+ --mk-link-inset: 8px;
8
+ --mk-link-thumb: 5.5rem;
9
+ display: block;
10
+ color: var(--mk-text);
11
+ font-family: var(--mk-font);
12
+ }
13
+
14
+ :is(.mk-link-preview, mk-link-preview)[data-mk-link-variant='hover'] {
15
+ display: inline-flex;
16
+ }
17
+
18
+ :is(.mk-link-preview, mk-link-preview) [data-mk-link-card] {
19
+ position: relative;
20
+ display: grid;
21
+ gap: 0;
22
+ padding: var(--mk-link-inset);
23
+ border-radius: var(--mk-link-radius);
24
+ background: var(--mk-surface-1);
25
+ box-shadow: inset 0 0 0 1px var(--mk-outline-soft);
26
+ color: inherit;
27
+ text-decoration: none;
28
+ transition:
29
+ translate 0.5s var(--mk-ease-signature, cubic-bezier(0.2, 0.8, 0.2, 1)),
30
+ box-shadow 0.3s ease;
31
+ }
32
+
33
+ :is(.mk-link-preview, mk-link-preview) a[data-mk-link-card]:hover {
34
+ translate: 0 -3px;
35
+ box-shadow:
36
+ inset 0 0 0 1px var(--mk-outline-soft),
37
+ 0 18px 40px -22px color-mix(in srgb, var(--mk-shadow-color) 45%, transparent);
38
+ }
39
+
40
+ :is(.mk-link-preview, mk-link-preview) a[data-mk-link-card]:active {
41
+ animation: mk-link-press 500ms cubic-bezier(0.37, 1.42, 0.37, 1);
42
+ }
43
+
44
+ :is(.mk-link-preview, mk-link-preview) a[data-mk-link-card]:focus-visible,
45
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-trigger]:focus-visible {
46
+ outline: 2px solid var(--mk-accent);
47
+ outline-offset: 3px;
48
+ }
49
+
50
+ :is(.mk-link-preview, mk-link-preview) [data-mk-part='media'] {
51
+ position: relative;
52
+ display: grid;
53
+ place-items: center;
54
+ overflow: hidden;
55
+ aspect-ratio: 16 / 9;
56
+ border-radius: calc(var(--mk-link-radius) - var(--mk-link-inset));
57
+ background: var(--mk-surface-3);
58
+ color: var(--mk-muted);
59
+ }
60
+
61
+ :is(.mk-link-preview, mk-link-preview) [data-mk-part='fallback'] {
62
+ font-size: clamp(2rem, 8vw, 3.5rem);
63
+ font-weight: 500;
64
+ letter-spacing: -0.04em;
65
+ }
66
+
67
+ :is(.mk-link-preview, mk-link-preview) [data-mk-link-image] {
68
+ position: absolute;
69
+ inset: 0;
70
+ width: 100%;
71
+ height: 100%;
72
+ object-fit: cover;
73
+ transition: scale 0.7s var(--mk-ease-signature, cubic-bezier(0.2, 0.8, 0.2, 1));
74
+ }
75
+
76
+ :is(.mk-link-preview, mk-link-preview) a[data-mk-link-card]:hover [data-mk-link-image] {
77
+ scale: 1.04;
78
+ }
79
+
80
+ :is(.mk-link-preview, mk-link-preview) [data-mk-link-image][hidden] {
81
+ display: none;
82
+ }
83
+
84
+ :is(.mk-link-preview, mk-link-preview) [data-mk-part='text'] {
85
+ display: grid;
86
+ gap: 0.35rem;
87
+ min-width: 0;
88
+ padding: 0.85rem 3.25rem 0.6rem 0.6rem;
89
+ }
90
+
91
+ :is(.mk-link-preview, mk-link-preview) [data-mk-part='meta'] {
92
+ display: flex;
93
+ align-items: center;
94
+ gap: 0.45rem;
95
+ min-width: 0;
96
+ }
97
+
98
+ :is(.mk-link-preview, mk-link-preview) [data-mk-part='favicon'] {
99
+ display: grid;
100
+ flex: none;
101
+ place-items: center;
102
+ width: 1.25rem;
103
+ height: 1.25rem;
104
+ border-radius: 50%;
105
+ background: var(--mk-text);
106
+ color: var(--mk-bg);
107
+ font-size: 0.6875rem;
108
+ font-weight: 600;
109
+ }
110
+
111
+ :is(.mk-link-preview, mk-link-preview) [data-mk-part='site'] {
112
+ overflow: hidden;
113
+ color: var(--mk-muted);
114
+ font-size: 0.8125rem;
115
+ text-overflow: ellipsis;
116
+ white-space: nowrap;
117
+ }
118
+
119
+ :is(.mk-link-preview, mk-link-preview) [data-mk-part='title'] {
120
+ font-size: 1.0625rem;
121
+ font-weight: 500;
122
+ line-height: 1.25;
123
+ letter-spacing: -0.01em;
124
+ display: -webkit-box;
125
+ overflow: hidden;
126
+ -webkit-box-orient: vertical;
127
+ -webkit-line-clamp: 2;
128
+ }
129
+
130
+ :is(.mk-link-preview, mk-link-preview) [data-mk-part='description'] {
131
+ color: var(--mk-muted);
132
+ font-size: 0.875rem;
133
+ line-height: 1.4;
134
+ display: -webkit-box;
135
+ overflow: hidden;
136
+ -webkit-box-orient: vertical;
137
+ -webkit-line-clamp: 2;
138
+ }
139
+
140
+ /* The go button: bottom right, it turns and fills on hover (Melonmind playful curve). */
141
+ :is(.mk-link-preview, mk-link-preview) [data-mk-part='go'] {
142
+ position: absolute;
143
+ right: calc(var(--mk-link-inset) + 0.5rem);
144
+ bottom: calc(var(--mk-link-inset) + 0.5rem);
145
+ display: grid;
146
+ place-items: center;
147
+ width: 2.5rem;
148
+ height: 2.5rem;
149
+ border-radius: 50%;
150
+ background: var(--mk-surface-3);
151
+ color: var(--mk-text);
152
+ rotate: 45deg;
153
+ transition:
154
+ rotate 0.4s cubic-bezier(0.38, 0.49, 0, 2),
155
+ background-color 0.2s ease,
156
+ color 0.2s ease,
157
+ scale 0.4s cubic-bezier(0.38, 0.49, 0, 1.5);
158
+ }
159
+
160
+ :is(.mk-link-preview, mk-link-preview) a[data-mk-link-card]:is(:hover, :focus-visible) [data-mk-part='go'] {
161
+ rotate: 0deg;
162
+ scale: 1.08;
163
+ background: var(--mk-text);
164
+ color: var(--mk-bg);
165
+ }
166
+
167
+ :is(.mk-link-preview, mk-link-preview) span[data-mk-link-card] [data-mk-part='go'] {
168
+ display: none;
169
+ }
170
+
171
+ /* Row: the thumbnail beside the text. */
172
+ :is(.mk-link-preview, mk-link-preview)[data-mk-link-variant='row'] [data-mk-link-card] {
173
+ grid-template-columns: var(--mk-link-thumb) minmax(0, 1fr);
174
+ align-items: center;
175
+ gap: 0.25rem;
176
+ border-radius: var(--mk-radius-md, 16px);
177
+ }
178
+
179
+ :is(.mk-link-preview, mk-link-preview)[data-mk-link-variant='row'] [data-mk-part='media'] {
180
+ aspect-ratio: 1;
181
+ border-radius: 10px;
182
+ }
183
+
184
+ :is(.mk-link-preview, mk-link-preview)[data-mk-link-variant='row'] [data-mk-part='fallback'] {
185
+ font-size: 2rem;
186
+ }
187
+
188
+ :is(.mk-link-preview, mk-link-preview)[data-mk-link-variant='row'] [data-mk-part='text'] {
189
+ padding: 0.25rem 3.25rem 0.25rem 0.75rem;
190
+ }
191
+
192
+ :is(.mk-link-preview, mk-link-preview)[data-mk-link-variant='row'] [data-mk-part='go'] {
193
+ top: 50%;
194
+ bottom: auto;
195
+ margin-top: -1.25rem;
196
+ }
197
+
198
+ /* Hover: an underlined link; the card sits in the inverse glass. */
199
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-trigger] {
200
+ color: inherit;
201
+ font-weight: 500;
202
+ text-decoration: underline;
203
+ text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
204
+ text-decoration-thickness: 1.5px;
205
+ text-underline-offset: 0.22em;
206
+ cursor: pointer;
207
+ transition: text-decoration-color 0.2s ease;
208
+ }
209
+
210
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-trigger]:hover {
211
+ text-decoration-color: currentColor;
212
+ }
213
+
214
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-panel] {
215
+ width: min(20rem, calc(100vw - 1.5rem));
216
+ padding: 0;
217
+ border: 0;
218
+ border-radius: var(--mk-link-radius);
219
+ background: var(--mk-glass-inverse);
220
+ box-shadow: var(--mk-glass-bevel);
221
+ backdrop-filter: blur(16px);
222
+ color: var(--mk-on-glass-inverse);
223
+ }
224
+
225
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-panel] [data-mk-link-card] {
226
+ background: transparent;
227
+ box-shadow: none;
228
+ translate: none;
229
+ }
230
+
231
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-panel] [data-mk-part='media'] {
232
+ background: color-mix(in srgb, var(--mk-on-glass-inverse) 12%, transparent);
233
+ color: var(--mk-on-glass-inverse);
234
+ }
235
+
236
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-panel] :is([data-mk-part='site'], [data-mk-part='description']) {
237
+ color: color-mix(in srgb, var(--mk-on-glass-inverse) 70%, transparent);
238
+ }
239
+
240
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-panel] [data-mk-part='favicon'] {
241
+ background: var(--mk-on-glass-inverse);
242
+ color: var(--mk-text);
243
+ }
244
+
245
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-panel] [data-mk-part='go'] {
246
+ background: color-mix(in srgb, var(--mk-on-glass-inverse) 14%, transparent);
247
+ color: var(--mk-on-glass-inverse);
248
+ }
249
+
250
+ :is(.mk-link-preview, mk-link-preview) [data-mk-hover-panel] a[data-mk-link-card]:is(:hover, :focus-visible) [data-mk-part='go'] {
251
+ background: var(--mk-on-glass-inverse);
252
+ color: var(--mk-text);
253
+ }
254
+
255
+ @keyframes mk-link-press {
256
+ 50% {
257
+ transform: scale(0.97, 0.95);
258
+ }
259
+ }
260
+
261
+ @media (max-width: 420px) {
262
+ :is(.mk-link-preview, mk-link-preview) {
263
+ --mk-link-thumb: 4.25rem;
264
+ }
265
+ }
266
+
267
+ @media (prefers-reduced-motion: reduce) {
268
+ :is(.mk-link-preview, mk-link-preview) :is([data-mk-link-card], [data-mk-link-image], [data-mk-part='go']) {
269
+ transition: none;
270
+ animation: none !important;
271
+ translate: none !important;
272
+ scale: none !important;
273
+ }
274
+ }
@@ -0,0 +1,101 @@
1
+ 'use client';
2
+ import { useEffect, useId, useRef, useState, type HTMLAttributes } from 'react';
3
+ import { useIsomorphicLayoutEffect, useLatest } from '../../react/use-recipe';
4
+ import { createHoverCard } from '../hover-card/engine';
5
+ import { linkDomain, safeHref, safeImage, type LinkPreviewOptions } from './engine';
6
+
7
+ export interface LinkPreviewProps extends Omit<HTMLAttributes<HTMLElement>, 'title'>, LinkPreviewOptions {}
8
+
9
+ function Card({ url, title, description, image, imageAlt, siteName, target }: LinkPreviewOptions) {
10
+ const id = useId();
11
+ const href = safeHref(url);
12
+ const domain = linkDomain(href);
13
+ const source = safeImage(image);
14
+ const [failed, setFailed] = useState(false);
15
+ useEffect(() => setFailed(false), [source]);
16
+ const site = [siteName, domain].filter(Boolean).filter((value, i, all) => all.indexOf(value) === i).join(' · ');
17
+ const content = (
18
+ <>
19
+ <span data-mk-part="media">
20
+ <span data-mk-part="fallback" aria-hidden="true">
21
+ {(siteName || domain || title || '?').trim().charAt(0).toUpperCase()}
22
+ </span>
23
+ {source && !failed ? <img data-mk-link-image="" src={source} alt={imageAlt ?? ''} loading="lazy" decoding="async" onError={() => setFailed(true)} /> : null}
24
+ </span>
25
+ <span data-mk-part="text">
26
+ {site && (
27
+ <span data-mk-part="meta">
28
+ <span data-mk-part="favicon" aria-hidden="true">
29
+ {(siteName || domain).trim().charAt(0).toUpperCase()}
30
+ </span>
31
+ <span data-mk-part="site">{site}</span>
32
+ </span>
33
+ )}
34
+ <span data-mk-part="title" id={`${id}-title`}>
35
+ {title || domain || href}
36
+ </span>
37
+ {description && (
38
+ <span data-mk-part="description" id={`${id}-description`}>
39
+ {description}
40
+ </span>
41
+ )}
42
+ </span>
43
+ <span data-mk-part="go" aria-hidden="true">
44
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round">
45
+ <path d="M7 17L17 7M9 7h8v8" />
46
+ </svg>
47
+ </span>
48
+ </>
49
+ );
50
+ const labelled = { 'aria-labelledby': `${id}-title`, 'aria-describedby': description ? `${id}-description` : undefined };
51
+ return href ? (
52
+ <a data-mk-link-card="" href={href} target={target} rel={target === '_blank' ? 'noopener noreferrer' : undefined} {...labelled}>
53
+ {content}
54
+ </a>
55
+ ) : (
56
+ <span data-mk-link-card="" {...labelled}>
57
+ {content}
58
+ </span>
59
+ );
60
+ }
61
+
62
+ /**
63
+ * <LinkPreview url="https://…" title="…" description="…" image="/thumb.jpg" siteName="Blog" />, or
64
+ * variant="hover" for a link that previews the card on pointer, focus or tap. Metadata comes from the app.
65
+ */
66
+ export function LinkPreview({ url, title, description, image, imageAlt, siteName, variant = 'card', label, target, openDelay, closeDelay, placement, onOpenChange, className, ...props }: LinkPreviewProps) {
67
+ const ref = useRef<HTMLSpanElement>(null);
68
+ const change = useLatest(onOpenChange);
69
+ const href = safeHref(url);
70
+ const hover = variant === 'hover';
71
+ useIsomorphicLayoutEffect(() => {
72
+ if (!hover) return;
73
+ const instance = createHoverCard(ref.current, { openDelay, closeDelay, placement, onOpenChange: (open) => change.current?.(open) });
74
+ return () => instance.destroy();
75
+ }, [hover, openDelay, closeDelay, placement]);
76
+ const card = <Card url={url} title={title} description={description} image={image} imageAlt={imageAlt} siteName={siteName} target={target} />;
77
+ if (!hover) {
78
+ return (
79
+ <div {...props} className={['mk-link-preview', className].filter(Boolean).join(' ')} data-mk-link-variant={variant === 'row' ? 'row' : 'card'}>
80
+ {card}
81
+ </div>
82
+ );
83
+ }
84
+ const text = label || title || linkDomain(href) || href;
85
+ return (
86
+ <span {...props} ref={ref} className={['mk-link-preview mk-hover-card', className].filter(Boolean).join(' ')} data-mk-link-variant="hover">
87
+ {href ? (
88
+ <a data-mk-hover-trigger="" href={href} target={target} rel={target === '_blank' ? 'noopener noreferrer' : undefined}>
89
+ {text}
90
+ </a>
91
+ ) : (
92
+ <span data-mk-hover-trigger="" tabIndex={0}>
93
+ {text}
94
+ </span>
95
+ )}
96
+ <span data-mk-hover-panel="" role="region" aria-label={`Vista previa: ${title || linkDomain(href)}`} hidden>
97
+ {card}
98
+ </span>
99
+ </span>
100
+ );
101
+ }
@@ -0,0 +1,45 @@
1
+ # loading-button
2
+
3
+ Botón que muestra su trabajo. Al pulsarlo (o con `run()`) hace el press de Melon Mind, su texto se desvanece con blur y entra un indicador de carga mientras el botón se desliza a su nuevo ancho (.4 s, curva swing). En éxito pasa al color de éxito con una marca que se dibuja sola (.35 s) y rebota; en error pasa al color de error, se sacude y dibuja una cruz. Tras `resetAfter` vuelve a su texto.
4
+
5
+ ## HTML / Astro
6
+
7
+ ```html
8
+ <mk-loading-button>
9
+ <button class="mk-button mk-button--primary">Guardar cambios</button>
10
+ </mk-loading-button>
11
+ <script>
12
+ const save = document.querySelector('mk-loading-button');
13
+ save.addEventListener('click', () => save.run(() => fetch('/api/guardar', { method: 'POST' })));
14
+ </script>
15
+ ```
16
+
17
+ El atributo `state` (`idle`, `loading`, `success`, `error`) lo controla desde fuera.
18
+
19
+ ## React
20
+
21
+ ```tsx
22
+ <LoadingButton className="mk-button mk-button--primary" action={() => api.save(form)} labels={{ success: 'Guardado' }}>
23
+ Guardar cambios
24
+ </LoadingButton>
25
+ ```
26
+
27
+ Con `action`, la promesa decide el resultado (se resuelve → éxito; se rechaza → error). Sin ella, `state` lo controla.
28
+
29
+ ## Opciones
30
+
31
+ | Opción | Atributo | Por defecto | Qué hace |
32
+ |---|---|---|---|
33
+ | `action` | — | — | Se ejecuta al pulsar; su promesa recorre los estados. |
34
+ | `labels` | `labels` (JSON) | Cargando… / Listo / Error | Textos que se anuncian (y se muestran si no es compacto). |
35
+ | `compact` | `compact` | `true` | Solo el icono mientras trabaja; con `false`, icono y texto. |
36
+ | `resetAfter` | `reset-after` | `1800` | ms en éxito o error antes de volver; `0` se queda. |
37
+ | `onStateChange(state)` | — | — | Cada cambio de estado. |
38
+
39
+ ## API y eventos
40
+
41
+ `setState(state)`, `run(action?)` (resuelve `true` si salió bien), `state`, `destroy()`. Evento `mk:state-change` con `{ state }`.
42
+
43
+ ## Accesibilidad y estilo
44
+
45
+ Mientras carga sigue siendo enfocable pero no responde (`aria-disabled`, `aria-busy`), y un estado discreto junto a él dice qué pasó. El botón conserva su propio estilo (`.mk-button` o el tuyo); el componente añade los colores de estado (`--mk-loading-success`, `--mk-error`) en `data-mk-state`. Con movimiento reducido el indicador queda quieto y no hay deslizamientos ni sacudida.