@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.
- package/README.md +81 -0
- package/bin/motion-kit.mjs +3 -3
- package/dist/auto/index.d.ts +56 -3
- package/dist/auto/index.js +107 -3
- package/dist/auto/index.js.map +1 -1
- package/dist/{chunk-XAKC2QY7.js → chunk-6IRJYXJU.js} +3 -28
- package/dist/chunk-6IRJYXJU.js.map +1 -0
- package/dist/chunk-A6QQCF6V.js +21333 -0
- package/dist/chunk-A6QQCF6V.js.map +1 -0
- package/dist/chunk-JXRS3OEA.js +3638 -0
- package/dist/chunk-JXRS3OEA.js.map +1 -0
- package/dist/chunk-QP4QJOEN.js +72 -0
- package/dist/chunk-QP4QJOEN.js.map +1 -0
- package/dist/css/components/activity-feed.css +240 -0
- package/dist/css/components/add-to-cart.css +72 -0
- package/dist/css/components/attachment.css +266 -0
- package/dist/css/components/bidirectional-slider.css +168 -0
- package/dist/css/components/breadcrumb.css +110 -0
- package/dist/css/components/chart-tooltip.css +168 -0
- package/dist/css/components/chart.css +296 -0
- package/dist/css/components/code-block.css +264 -0
- package/dist/css/components/color-area.css +82 -0
- package/dist/css/components/color-field.css +67 -0
- package/dist/css/components/color-picker.css +131 -0
- package/dist/css/components/color-slider.css +113 -0
- package/dist/css/components/command-search.css +252 -0
- package/dist/css/components/context-menu.css +23 -0
- package/dist/css/components/credit-card.css +288 -0
- package/dist/css/components/data-table.css +686 -0
- package/dist/css/components/date-range-picker.css +168 -0
- package/dist/css/components/date-time-picker.css +178 -0
- package/dist/css/components/drawer.css +58 -0
- package/dist/css/components/editable-table.css +201 -0
- package/dist/css/components/empty-state.css +61 -0
- package/dist/css/components/file-explorer.css +633 -0
- package/dist/css/components/filter-builder.css +227 -0
- package/dist/css/components/heatmap-chart.css +391 -0
- package/dist/css/components/hold-confirm.css +87 -0
- package/dist/css/components/hover-card.css +19 -7
- package/dist/css/components/image-preview.css +283 -0
- package/dist/css/components/json-viewer.css +304 -0
- package/dist/css/components/like-button.css +78 -0
- package/dist/css/components/link-preview.css +275 -0
- package/dist/css/components/loading-button.css +77 -0
- package/dist/css/components/multi-select.css +267 -0
- package/dist/css/components/nav.css +102 -102
- package/dist/css/components/notification-bell.css +127 -0
- package/dist/css/components/orbit-menu.css +130 -0
- package/dist/css/components/pagination.css +10 -5
- package/dist/css/components/password-strength.css +183 -0
- package/dist/css/components/pie-chart.css +390 -0
- package/dist/css/components/pill-button.css +135 -0
- package/dist/css/components/popover.css +25 -0
- package/dist/css/components/progress.css +140 -0
- package/dist/css/components/questionnaire.css +217 -0
- package/dist/css/components/radar-chart.css +370 -0
- package/dist/css/components/radial-chart.css +398 -0
- package/dist/css/components/range-calendar.css +186 -0
- package/dist/css/components/range-slider.css +192 -0
- package/dist/css/components/resizable-panel.css +243 -0
- package/dist/css/components/rich-text-editor.css +284 -0
- package/dist/css/components/sankey-chart.css +358 -0
- package/dist/css/components/scratch-card.css +75 -0
- package/dist/css/components/scroll-island.css +111 -0
- package/dist/css/components/select.css +136 -0
- package/dist/css/components/skeleton.css +108 -0
- package/dist/css/components/split-view.css +19 -0
- package/dist/css/components/star-rating.css +80 -0
- package/dist/css/components/stat-card.css +164 -0
- package/dist/css/components/swipe-actions.css +105 -0
- package/dist/css/components/tag-input.css +244 -0
- package/dist/css/components/time-field.css +88 -0
- package/dist/css/components/timeline.css +219 -0
- package/dist/css/components/toolbar.css +122 -0
- package/dist/css/components/tooltip.css +79 -0
- package/dist/css/components/tree-view.css +289 -0
- package/dist/css/components/virtual-list.css +195 -0
- package/dist/css/components/voice-dots.css +70 -0
- package/dist/css/tokens.css +185 -181
- package/dist/elements/index.d.ts +849 -7
- package/dist/elements/index.js +1642 -8
- package/dist/elements/index.js.map +1 -1
- package/dist/{engine-GDGwQnJE.d.ts → engine-5zRIssTO.d.ts} +11 -1
- package/dist/engine-QECQnGz1.d.ts +33 -0
- package/dist/index.css +10890 -311
- package/dist/index.d.ts +89 -5
- package/dist/index.js +273 -9
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +686 -24
- package/dist/react/index.js +2345 -9
- package/dist/react/index.js.map +1 -1
- package/dist/{reduced-BmBzKH94.d.ts → reduced-6X_bns60.d.ts} +9 -2
- package/dist/reveal-BfyKKsw4.d.ts +2474 -0
- package/dist/store-CA2Qcun_.d.ts +453 -0
- package/package.json +9 -16
- package/registry.json +1096 -543
- package/src/auto/auto-init.ts +104 -0
- package/src/components/activity-feed/README.md +56 -0
- package/src/components/activity-feed/activity-feed.css +239 -0
- package/src/components/activity-feed/element.ts +36 -0
- package/src/components/activity-feed/engine.ts +351 -0
- package/src/components/activity-feed/react.tsx +32 -0
- package/src/components/add-to-cart/README.md +34 -0
- package/src/components/add-to-cart/add-to-cart.css +71 -0
- package/src/components/add-to-cart/element.ts +20 -0
- package/src/components/add-to-cart/engine.ts +206 -0
- package/src/components/add-to-cart/react.tsx +29 -0
- package/src/components/attachment/README.md +27 -0
- package/src/components/attachment/attachment.css +265 -0
- package/src/components/attachment/element.ts +50 -0
- package/src/components/attachment/engine.ts +469 -0
- package/src/components/attachment/react.tsx +65 -0
- package/src/components/bidirectional-slider/README.md +46 -0
- package/src/components/bidirectional-slider/bidirectional-slider.css +167 -0
- package/src/components/bidirectional-slider/element.ts +42 -0
- package/src/components/bidirectional-slider/engine.ts +289 -0
- package/src/components/bidirectional-slider/react.tsx +45 -0
- package/src/components/breadcrumb/README.md +38 -0
- package/src/components/breadcrumb/breadcrumb.css +109 -0
- package/src/components/breadcrumb/element.ts +27 -0
- package/src/components/breadcrumb/engine.ts +249 -0
- package/src/components/breadcrumb/react.tsx +30 -0
- package/src/components/chart/README.md +34 -0
- package/src/components/chart/chart.css +295 -0
- package/src/components/chart/element.ts +43 -0
- package/src/components/chart/engine.ts +838 -0
- package/src/components/chart/parts.ts +237 -0
- package/src/components/chart/react.tsx +50 -0
- package/src/components/chart/use-chart.ts +55 -0
- package/src/components/chart-tooltip/README.md +53 -0
- package/src/components/chart-tooltip/chart-tooltip.css +167 -0
- package/src/components/chart-tooltip/element.ts +37 -0
- package/src/components/chart-tooltip/engine.ts +442 -0
- package/src/components/chart-tooltip/react.tsx +47 -0
- package/src/components/code-block/README.md +19 -0
- package/src/components/code-block/code-block.css +263 -0
- package/src/components/code-block/element.ts +34 -0
- package/src/components/code-block/engine.ts +254 -0
- package/src/components/code-block/highlight.ts +244 -0
- package/src/components/code-block/react.tsx +94 -0
- package/src/components/color-area/README.md +50 -0
- package/src/components/color-area/color-area.css +81 -0
- package/src/components/color-area/element.ts +26 -0
- package/src/components/color-area/engine.ts +246 -0
- package/src/components/color-area/react.tsx +42 -0
- package/src/components/color-field/README.md +43 -0
- package/src/components/color-field/color-field.css +66 -0
- package/src/components/color-field/element.ts +26 -0
- package/src/components/color-field/engine.ts +174 -0
- package/src/components/color-field/react.tsx +42 -0
- package/src/components/color-picker/README.md +45 -0
- package/src/components/color-picker/color-picker.css +130 -0
- package/src/components/color-picker/element.ts +45 -0
- package/src/components/color-picker/engine.ts +314 -0
- package/src/components/color-picker/react.tsx +47 -0
- package/src/components/color-slider/README.md +55 -0
- package/src/components/color-slider/color-slider.css +112 -0
- package/src/components/color-slider/element.ts +26 -0
- package/src/components/color-slider/engine.ts +234 -0
- package/src/components/color-slider/react.tsx +45 -0
- package/src/components/command-search/README.md +15 -0
- package/src/components/command-search/command-search.css +251 -0
- package/src/components/command-search/element.ts +36 -0
- package/src/components/command-search/engine.ts +356 -0
- package/src/components/command-search/match.ts +53 -0
- package/src/components/command-search/react.tsx +66 -0
- package/src/components/context-menu/README.md +31 -0
- package/src/components/context-menu/context-menu.css +22 -0
- package/src/components/context-menu/element.ts +40 -0
- package/src/components/context-menu/engine.ts +153 -0
- package/src/components/context-menu/react.tsx +57 -0
- package/src/components/credit-card/README.md +20 -0
- package/src/components/credit-card/card.ts +77 -0
- package/src/components/credit-card/credit-card.css +287 -0
- package/src/components/credit-card/element.ts +33 -0
- package/src/components/credit-card/engine.ts +410 -0
- package/src/components/credit-card/react.tsx +36 -0
- package/src/components/data-table/README.md +83 -0
- package/src/components/data-table/data-table.css +685 -0
- package/src/components/data-table/element.ts +54 -0
- package/src/components/data-table/engine.ts +1111 -0
- package/src/components/data-table/react.tsx +94 -0
- package/src/components/date-range-picker/README.md +51 -0
- package/src/components/date-range-picker/date-range-picker.css +167 -0
- package/src/components/date-range-picker/element.ts +52 -0
- package/src/components/date-range-picker/engine.ts +352 -0
- package/src/components/date-range-picker/react.tsx +57 -0
- package/src/components/date-time-picker/README.md +48 -0
- package/src/components/date-time-picker/date-time-picker.css +177 -0
- package/src/components/date-time-picker/element.ts +47 -0
- package/src/components/date-time-picker/engine.ts +350 -0
- package/src/components/date-time-picker/react.tsx +54 -0
- package/src/components/dialog/README.md +103 -102
- package/src/components/dialog/element.ts +123 -118
- package/src/components/dialog/engine.ts +449 -432
- package/src/components/drawer/README.md +28 -0
- package/src/components/drawer/drawer.css +57 -0
- package/src/components/drawer/element.ts +21 -0
- package/src/components/drawer/engine.ts +56 -0
- package/src/components/drawer/react.tsx +85 -0
- package/src/components/editable-table/README.md +67 -0
- package/src/components/editable-table/editable-table.css +200 -0
- package/src/components/editable-table/element.ts +45 -0
- package/src/components/editable-table/engine.ts +831 -0
- package/src/components/editable-table/react.tsx +79 -0
- package/src/components/empty-state/README.md +41 -0
- package/src/components/empty-state/element.ts +23 -0
- package/src/components/empty-state/empty-state.css +60 -0
- package/src/components/empty-state/engine.ts +232 -0
- package/src/components/empty-state/react.tsx +34 -0
- package/src/components/file-explorer/README.md +67 -0
- package/src/components/file-explorer/element.ts +39 -0
- package/src/components/file-explorer/engine.ts +1307 -0
- package/src/components/file-explorer/file-explorer.css +632 -0
- package/src/components/file-explorer/react.tsx +77 -0
- package/src/components/filter-builder/README.md +47 -0
- package/src/components/filter-builder/element.ts +34 -0
- package/src/components/filter-builder/engine.ts +396 -0
- package/src/components/filter-builder/filter-builder.css +226 -0
- package/src/components/filter-builder/react.tsx +36 -0
- package/src/components/heatmap-chart/README.md +48 -0
- package/src/components/heatmap-chart/element.ts +21 -0
- package/src/components/heatmap-chart/engine.ts +281 -0
- package/src/components/heatmap-chart/heatmap-chart.css +93 -0
- package/src/components/heatmap-chart/react.tsx +14 -0
- package/src/components/hold-confirm/README.md +13 -0
- package/src/components/hold-confirm/element.ts +24 -0
- package/src/components/hold-confirm/engine.ts +216 -0
- package/src/components/hold-confirm/hold-confirm.css +86 -0
- package/src/components/hold-confirm/react.tsx +28 -0
- package/src/components/hover-card/README.md +6 -2
- package/src/components/hover-card/engine.ts +98 -7
- package/src/components/hover-card/hover-card.css +19 -7
- package/src/components/image-preview/README.md +16 -0
- package/src/components/image-preview/element.ts +26 -0
- package/src/components/image-preview/engine.ts +405 -0
- package/src/components/image-preview/image-preview.css +282 -0
- package/src/components/image-preview/react.tsx +43 -0
- package/src/components/json-viewer/README.md +56 -0
- package/src/components/json-viewer/element.ts +37 -0
- package/src/components/json-viewer/engine.ts +449 -0
- package/src/components/json-viewer/json-viewer.css +303 -0
- package/src/components/json-viewer/react.tsx +56 -0
- package/src/components/like-button/README.md +13 -0
- package/src/components/like-button/element.ts +47 -0
- package/src/components/like-button/engine.ts +145 -0
- package/src/components/like-button/like-button.css +77 -0
- package/src/components/like-button/react.tsx +39 -0
- package/src/components/link-preview/README.md +19 -0
- package/src/components/link-preview/element.ts +29 -0
- package/src/components/link-preview/engine.ts +192 -0
- package/src/components/link-preview/link-preview.css +274 -0
- package/src/components/link-preview/react.tsx +101 -0
- package/src/components/loading-button/README.md +45 -0
- package/src/components/loading-button/element.ts +34 -0
- package/src/components/loading-button/engine.ts +201 -0
- package/src/components/loading-button/loading-button.css +76 -0
- package/src/components/loading-button/react.tsx +43 -0
- package/src/components/multi-select/README.md +48 -0
- package/src/components/multi-select/element.ts +28 -0
- package/src/components/multi-select/engine.ts +294 -0
- package/src/components/multi-select/multi-select.css +266 -0
- package/src/components/multi-select/react.tsx +39 -0
- package/src/components/nav/README.md +12 -10
- package/src/components/nav/element.ts +5 -5
- package/src/components/nav/engine.ts +21 -14
- package/src/components/nav/nav.css +102 -102
- package/src/components/nav/react.tsx +4 -4
- package/src/components/notification-bell/README.md +14 -0
- package/src/components/notification-bell/element.ts +48 -0
- package/src/components/notification-bell/engine.ts +202 -0
- package/src/components/notification-bell/notification-bell.css +126 -0
- package/src/components/notification-bell/react.tsx +57 -0
- package/src/components/orbit-menu/README.md +46 -0
- package/src/components/orbit-menu/element.ts +27 -0
- package/src/components/orbit-menu/engine.ts +179 -0
- package/src/components/orbit-menu/orbit-menu.css +129 -0
- package/src/components/orbit-menu/react.tsx +44 -0
- package/src/components/pagination/README.md +1 -1
- package/src/components/pagination/engine.ts +50 -4
- package/src/components/pagination/pagination.css +10 -5
- package/src/components/password-strength/README.md +17 -0
- package/src/components/password-strength/element.ts +22 -0
- package/src/components/password-strength/engine.ts +212 -0
- package/src/components/password-strength/password-strength.css +182 -0
- package/src/components/password-strength/react.tsx +36 -0
- package/src/components/password-strength/score.ts +62 -0
- package/src/components/pie-chart/README.md +48 -0
- package/src/components/pie-chart/element.ts +30 -0
- package/src/components/pie-chart/engine.ts +283 -0
- package/src/components/pie-chart/pie-chart.css +92 -0
- package/src/components/pie-chart/react.tsx +14 -0
- package/src/components/pill-button/README.md +46 -0
- package/src/components/pill-button/element.ts +16 -0
- package/src/components/pill-button/engine.ts +77 -0
- package/src/components/pill-button/pill-button.css +134 -0
- package/src/components/pill-button/react.tsx +32 -0
- package/src/components/popover/README.md +44 -0
- package/src/components/popover/element.ts +31 -0
- package/src/components/popover/engine.ts +114 -0
- package/src/components/popover/popover.css +24 -0
- package/src/components/popover/react.tsx +50 -0
- package/src/components/progress/README.md +17 -0
- package/src/components/progress/element.ts +30 -0
- package/src/components/progress/engine.ts +173 -0
- package/src/components/progress/progress.css +139 -0
- package/src/components/progress/react.tsx +35 -0
- package/src/components/questionnaire/README.md +32 -0
- package/src/components/questionnaire/element.ts +118 -0
- package/src/components/questionnaire/engine.ts +255 -0
- package/src/components/questionnaire/questionnaire.css +216 -0
- package/src/components/questionnaire/react.tsx +140 -0
- package/src/components/radar-chart/README.md +48 -0
- package/src/components/radar-chart/element.ts +30 -0
- package/src/components/radar-chart/engine.ts +327 -0
- package/src/components/radar-chart/radar-chart.css +72 -0
- package/src/components/radar-chart/react.tsx +14 -0
- package/src/components/radial-chart/README.md +48 -0
- package/src/components/radial-chart/element.ts +30 -0
- package/src/components/radial-chart/engine.ts +290 -0
- package/src/components/radial-chart/radial-chart.css +100 -0
- package/src/components/radial-chart/react.tsx +14 -0
- package/src/components/range-calendar/README.md +58 -0
- package/src/components/range-calendar/element.ts +42 -0
- package/src/components/range-calendar/engine.ts +390 -0
- package/src/components/range-calendar/range-calendar.css +185 -0
- package/src/components/range-calendar/react.tsx +56 -0
- package/src/components/range-slider/README.md +23 -0
- package/src/components/range-slider/element.ts +53 -0
- package/src/components/range-slider/engine.ts +316 -0
- package/src/components/range-slider/range-slider.css +191 -0
- package/src/components/range-slider/react.tsx +66 -0
- package/src/components/resizable-panel/README.md +61 -0
- package/src/components/resizable-panel/element.ts +36 -0
- package/src/components/resizable-panel/engine.ts +551 -0
- package/src/components/resizable-panel/react.tsx +74 -0
- package/src/components/resizable-panel/resizable-panel.css +242 -0
- package/src/components/rich-text-editor/README.md +57 -0
- package/src/components/rich-text-editor/element.ts +34 -0
- package/src/components/rich-text-editor/engine.ts +673 -0
- package/src/components/rich-text-editor/react.tsx +60 -0
- package/src/components/rich-text-editor/rich-text-editor.css +283 -0
- package/src/components/sankey-chart/README.md +48 -0
- package/src/components/sankey-chart/element.ts +31 -0
- package/src/components/sankey-chart/engine.ts +401 -0
- package/src/components/sankey-chart/react.tsx +14 -0
- package/src/components/sankey-chart/sankey-chart.css +60 -0
- package/src/components/scratch-card/README.md +15 -0
- package/src/components/scratch-card/element.ts +30 -0
- package/src/components/scratch-card/engine.ts +257 -0
- package/src/components/scratch-card/react.tsx +40 -0
- package/src/components/scratch-card/scratch-card.css +74 -0
- package/src/components/scroll-island/README.md +34 -0
- package/src/components/scroll-island/element.ts +16 -0
- package/src/components/scroll-island/engine.ts +252 -0
- package/src/components/scroll-island/react.tsx +26 -0
- package/src/components/scroll-island/scroll-island.css +110 -0
- package/src/components/select/README.md +34 -0
- package/src/components/select/element.ts +26 -0
- package/src/components/select/engine.ts +267 -0
- package/src/components/select/react.tsx +33 -0
- package/src/components/select/select.css +135 -0
- package/src/components/skeleton/README.md +15 -0
- package/src/components/skeleton/element.ts +32 -0
- package/src/components/skeleton/engine.ts +104 -0
- package/src/components/skeleton/react.tsx +41 -0
- package/src/components/skeleton/skeleton.css +107 -0
- package/src/components/split-view/README.md +50 -0
- package/src/components/split-view/element.ts +34 -0
- package/src/components/split-view/engine.ts +114 -0
- package/src/components/split-view/react.tsx +63 -0
- package/src/components/split-view/split-view.css +18 -0
- package/src/components/star-rating/README.md +14 -0
- package/src/components/star-rating/element.ts +26 -0
- package/src/components/star-rating/engine.ts +217 -0
- package/src/components/star-rating/react.tsx +33 -0
- package/src/components/star-rating/star-rating.css +79 -0
- package/src/components/stat-card/README.md +42 -0
- package/src/components/stat-card/element.ts +40 -0
- package/src/components/stat-card/engine.ts +283 -0
- package/src/components/stat-card/react.tsx +36 -0
- package/src/components/stat-card/stat-card.css +163 -0
- package/src/components/swipe-actions/README.md +19 -0
- package/src/components/swipe-actions/element.ts +26 -0
- package/src/components/swipe-actions/engine.ts +260 -0
- package/src/components/swipe-actions/react.tsx +80 -0
- package/src/components/swipe-actions/swipe-actions.css +104 -0
- package/src/components/tag-input/README.md +42 -0
- package/src/components/tag-input/element.ts +39 -0
- package/src/components/tag-input/engine.ts +313 -0
- package/src/components/tag-input/react.tsx +54 -0
- package/src/components/tag-input/tag-input.css +243 -0
- package/src/components/time-field/README.md +54 -0
- package/src/components/time-field/element.ts +38 -0
- package/src/components/time-field/engine.ts +110 -0
- package/src/components/time-field/react.tsx +45 -0
- package/src/components/time-field/time-field.css +87 -0
- package/src/components/timeline/README.md +57 -0
- package/src/components/timeline/element.ts +31 -0
- package/src/components/timeline/engine.ts +300 -0
- package/src/components/timeline/react.tsx +59 -0
- package/src/components/timeline/timeline.css +218 -0
- package/src/components/toolbar/README.md +46 -0
- package/src/components/toolbar/element.ts +30 -0
- package/src/components/toolbar/engine.ts +230 -0
- package/src/components/toolbar/react.tsx +34 -0
- package/src/components/toolbar/toolbar.css +121 -0
- package/src/components/tooltip/README.md +46 -0
- package/src/components/tooltip/element.ts +22 -0
- package/src/components/tooltip/engine.ts +288 -0
- package/src/components/tooltip/react.tsx +30 -0
- package/src/components/tooltip/tooltip.css +78 -0
- package/src/components/tree-view/README.md +61 -0
- package/src/components/tree-view/element.ts +32 -0
- package/src/components/tree-view/engine.ts +743 -0
- package/src/components/tree-view/react.tsx +82 -0
- package/src/components/tree-view/tree-view.css +288 -0
- package/src/components/virtual-list/README.md +81 -0
- package/src/components/virtual-list/element.ts +42 -0
- package/src/components/virtual-list/engine.ts +678 -0
- package/src/components/virtual-list/react.tsx +101 -0
- package/src/components/virtual-list/virtual-list.css +194 -0
- package/src/components/voice-dots/README.md +48 -0
- package/src/components/voice-dots/element.ts +45 -0
- package/src/components/voice-dots/engine.ts +243 -0
- package/src/components/voice-dots/react.tsx +52 -0
- package/src/components/voice-dots/voice-dots.css +69 -0
- package/src/core/chips.ts +196 -0
- package/src/core/color.ts +304 -0
- package/src/core/date-range.ts +67 -0
- package/src/core/dates.ts +11 -1
- package/src/core/files.ts +107 -0
- package/src/core/filter.ts +229 -0
- package/src/core/gsap.ts +80 -65
- package/src/core/listbox.ts +332 -0
- package/src/core/mark.ts +29 -0
- package/src/core/position.ts +89 -0
- package/src/core/relative-time.ts +77 -0
- package/src/core/segment-field.ts +373 -0
- package/src/core/segments.ts +153 -0
- package/src/core/tree.ts +116 -0
- package/src/core/virtual.ts +79 -0
- package/src/css/tokens.css +186 -182
- package/src/elements/index.ts +186 -0
- package/src/index.ts +88 -0
- package/src/motion/liquid.ts +14 -4
- package/src/motion/micro.ts +248 -0
- package/src/motion/sheet.ts +88 -65
- package/src/motion/surface.ts +9 -0
- package/src/react/index.ts +71 -1
- package/dist/chunk-IKQ5FODN.js +0 -1617
- package/dist/chunk-IKQ5FODN.js.map +0 -1
- package/dist/chunk-J6OCFNGU.js +0 -177
- package/dist/chunk-J6OCFNGU.js.map +0 -1
- package/dist/chunk-TFNRIZHU.js +0 -3977
- package/dist/chunk-TFNRIZHU.js.map +0 -1
- package/dist/chunk-XAKC2QY7.js.map +0 -1
- package/dist/reveal-jsX-uwUz.d.ts +0 -625
- package/dist/store-DYb3tTsZ.d.ts +0 -195
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { gsap, EASE, registerMotion } from '../../core/gsap';
|
|
2
|
+
import { reduced } from '../../core/reduced';
|
|
3
|
+
import { createScope } from '../../core/scope';
|
|
4
|
+
import { inert, warnOnce, type Instance } from '../../core/types';
|
|
5
|
+
import { press } from '../../motion/micro';
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* Orbit menu: a square button in the middle whose options come out around it
|
|
9
|
+
* (four make a cross: up, right, down, left; more share the circle). Opening,
|
|
10
|
+
* the button's lines turn into an ×, it goes glassy, and each option swirls out
|
|
11
|
+
* of it along an arc, its distance on the swatch curve (.38,.49,0,1.5) so it
|
|
12
|
+
* overshoots and settles, out of a blur, 45 ms after the one before; closing,
|
|
13
|
+
* they keep turning and are drawn back in (.3 s). Arrows pick the option on
|
|
14
|
+
* that side, Tab walks them, Escape or a click outside closes and gives focus
|
|
15
|
+
* back. Closed options are inert. Choosing one presses it and closes.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export interface OrbitMenuOptions {
|
|
19
|
+
/** Distance of the options from the middle, px (default 96). */
|
|
20
|
+
radius?: number;
|
|
21
|
+
/** Where the first option sits, degrees clockwise from the top (default 0). */
|
|
22
|
+
start?: number;
|
|
23
|
+
/** Close after an option is chosen (default true). */
|
|
24
|
+
closeOnSelect?: boolean;
|
|
25
|
+
onToggle?: (open: boolean) => void;
|
|
26
|
+
/** An option was chosen: its data-mk-value, else its position. */
|
|
27
|
+
onSelect?: (value: string) => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface OrbitMenuInstance extends Instance {
|
|
31
|
+
open(): void;
|
|
32
|
+
close(): void;
|
|
33
|
+
toggle(): void;
|
|
34
|
+
readonly isOpen: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createOrbitMenu(root: HTMLElement | null, options: OrbitMenuOptions = {}): OrbitMenuInstance {
|
|
38
|
+
const toggle = root?.querySelector<HTMLButtonElement>('[data-mk-orbit-toggle]') ?? null;
|
|
39
|
+
const items = root ? [...root.querySelectorAll<HTMLElement>('[data-mk-orbit-item]')] : [];
|
|
40
|
+
if (!root || !toggle || !items.length) {
|
|
41
|
+
if (root) warnOnce('orbit-menu: needs a [data-mk-orbit-toggle] and at least one [data-mk-orbit-item]');
|
|
42
|
+
return inert({ open() {}, close() {}, toggle() {}, isOpen: false });
|
|
43
|
+
}
|
|
44
|
+
registerMotion();
|
|
45
|
+
const scope = createScope();
|
|
46
|
+
const radius = Number.isFinite(options.radius) ? Math.max(24, options.radius!) : 96;
|
|
47
|
+
const start = ((Number.isFinite(options.start) ? options.start! : 0) * Math.PI) / 180;
|
|
48
|
+
const angles = items.map((_, i) => start + (i * Math.PI * 2) / items.length);
|
|
49
|
+
const valueOf = (item: HTMLElement) => item.dataset.mkValue ?? String(items.indexOf(item));
|
|
50
|
+
|
|
51
|
+
// The lines that turn into an ×, when the button brings no icon of its own.
|
|
52
|
+
if (!toggle.children.length && !toggle.textContent?.trim()) {
|
|
53
|
+
const burger = document.createElement('span');
|
|
54
|
+
burger.dataset.mkOrbitBurger = '';
|
|
55
|
+
burger.setAttribute('aria-hidden', 'true');
|
|
56
|
+
burger.append(document.createElement('i'), document.createElement('i'), document.createElement('i'));
|
|
57
|
+
toggle.append(burger);
|
|
58
|
+
scope.add(() => burger.remove());
|
|
59
|
+
}
|
|
60
|
+
scope.attr(toggle, 'aria-expanded', 'false');
|
|
61
|
+
scope.attr(toggle, 'aria-haspopup', 'true');
|
|
62
|
+
if (!toggle.getAttribute('aria-label') && !toggle.textContent?.trim()) scope.attr(toggle, 'aria-label', 'Menú');
|
|
63
|
+
for (const item of items) {
|
|
64
|
+
scope.attr(item, 'inert', '');
|
|
65
|
+
if (item instanceof HTMLButtonElement) scope.attr(item, 'type', item.getAttribute('type') ?? 'button');
|
|
66
|
+
}
|
|
67
|
+
scope.attr(root, 'data-mk-ready', '');
|
|
68
|
+
scope.attr(root, 'data-mk-state', 'closed');
|
|
69
|
+
|
|
70
|
+
const states = items.map((_, i) => ({ a: angles[i]!, r: 0 }));
|
|
71
|
+
const apply = (i: number) => {
|
|
72
|
+
const { a, r } = states[i]!;
|
|
73
|
+
gsap.set(items[i]!, { x: r * Math.sin(a), y: -r * Math.cos(a) });
|
|
74
|
+
};
|
|
75
|
+
let timeline: gsap.core.Timeline | null = null;
|
|
76
|
+
scope.add(() => {
|
|
77
|
+
timeline?.kill();
|
|
78
|
+
gsap.set(items, { clearProps: 'transform,opacity,filter,visibility' });
|
|
79
|
+
});
|
|
80
|
+
gsap.set(items, { opacity: 0, scale: 0.3, visibility: 'hidden' });
|
|
81
|
+
|
|
82
|
+
let open = false;
|
|
83
|
+
const set = (next: boolean, focus: 'first' | 'toggle' | false = false) => {
|
|
84
|
+
if (next === open) return;
|
|
85
|
+
open = next;
|
|
86
|
+
toggle.setAttribute('aria-expanded', String(open));
|
|
87
|
+
root.dataset.mkState = open ? 'open' : 'closed';
|
|
88
|
+
for (const item of items) item.toggleAttribute('inert', !open);
|
|
89
|
+
timeline?.kill();
|
|
90
|
+
if (reduced()) {
|
|
91
|
+
items.forEach((item, i) => {
|
|
92
|
+
states[i] = { a: angles[i]!, r: open ? radius : 0 };
|
|
93
|
+
apply(i);
|
|
94
|
+
gsap.set(item, { opacity: open ? 1 : 0, scale: open ? 1 : 0.3, filter: 'none', visibility: open ? 'visible' : 'hidden' });
|
|
95
|
+
});
|
|
96
|
+
} else if (open) {
|
|
97
|
+
timeline = gsap.timeline();
|
|
98
|
+
items.forEach((item, i) => {
|
|
99
|
+
const state = states[i]!;
|
|
100
|
+
// From a little behind its place, swirling out to it.
|
|
101
|
+
if (state.r < 1) state.a = angles[i]! - 0.7;
|
|
102
|
+
const at = i * 0.045;
|
|
103
|
+
gsap.set(item, { visibility: 'visible' });
|
|
104
|
+
timeline!.to(state, { r: radius, duration: 0.55, ease: EASE.swatch, onUpdate: () => apply(i) }, at);
|
|
105
|
+
timeline!.to(state, { a: angles[i]!, duration: 0.5, ease: 'power3.out', onUpdate: () => apply(i) }, at);
|
|
106
|
+
timeline!.fromTo(item, { filter: 'blur(8px)' }, { opacity: 1, scale: 1, filter: 'blur(0px)', duration: 0.35, ease: 'power2.out', clearProps: 'filter' }, at);
|
|
107
|
+
});
|
|
108
|
+
} else {
|
|
109
|
+
timeline = gsap.timeline();
|
|
110
|
+
[...items].reverse().forEach((item, k) => {
|
|
111
|
+
const i = items.length - 1 - k;
|
|
112
|
+
const state = states[i]!;
|
|
113
|
+
const at = k * 0.03;
|
|
114
|
+
timeline!.to(state, { r: 0, a: state.a + 0.6, duration: 0.3, ease: 'power2.in', onUpdate: () => apply(i) }, at);
|
|
115
|
+
timeline!.to(item, { opacity: 0, scale: 0.3, filter: 'blur(6px)', duration: 0.28, ease: 'power2.in', onComplete: () => {
|
|
116
|
+
gsap.set(item, { visibility: 'hidden', clearProps: 'filter' });
|
|
117
|
+
} }, at);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (focus === 'first') items[0]!.focus();
|
|
121
|
+
if (focus === 'toggle') toggle.focus();
|
|
122
|
+
options.onToggle?.(open);
|
|
123
|
+
root.dispatchEvent(new CustomEvent('mk:toggle', { bubbles: true, detail: { open } }));
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
scope.on(toggle, 'click', (event) => {
|
|
127
|
+
press(toggle);
|
|
128
|
+
// A keyboard click (detail 0) opens onto the first option.
|
|
129
|
+
set(!open, !open && (event as MouseEvent).detail === 0 ? 'first' : false);
|
|
130
|
+
});
|
|
131
|
+
scope.on(root, 'click', (event) => {
|
|
132
|
+
const item = (event.target as Element).closest<HTMLElement>('[data-mk-orbit-item]');
|
|
133
|
+
if (!item || !items.includes(item) || !open) return;
|
|
134
|
+
press(item);
|
|
135
|
+
const value = valueOf(item);
|
|
136
|
+
options.onSelect?.(value);
|
|
137
|
+
root.dispatchEvent(new CustomEvent('mk:select', { bubbles: true, detail: { value } }));
|
|
138
|
+
if (options.closeOnSelect !== false) set(false, 'toggle');
|
|
139
|
+
});
|
|
140
|
+
// Arrows: the option on that side (the nearest angle).
|
|
141
|
+
const sides: Record<string, number> = { ArrowUp: 0, ArrowRight: Math.PI / 2, ArrowDown: Math.PI, ArrowLeft: (Math.PI * 3) / 2 };
|
|
142
|
+
scope.on(root, 'keydown', (event) => {
|
|
143
|
+
const key = (event as KeyboardEvent).key;
|
|
144
|
+
if (key === 'Escape' && open) {
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
set(false, 'toggle');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (!(key in sides)) return;
|
|
150
|
+
if (!open) {
|
|
151
|
+
if (document.activeElement !== toggle) return;
|
|
152
|
+
event.preventDefault();
|
|
153
|
+
set(true);
|
|
154
|
+
} else event.preventDefault();
|
|
155
|
+
const want = sides[key]!;
|
|
156
|
+
const gap = (a: number) => {
|
|
157
|
+
const d = Math.abs((((a - want) % (Math.PI * 2)) + Math.PI * 3) % (Math.PI * 2) - Math.PI);
|
|
158
|
+
return d;
|
|
159
|
+
};
|
|
160
|
+
let best = 0;
|
|
161
|
+
angles.forEach((a, i) => {
|
|
162
|
+
if (gap(a) < gap(angles[best]!)) best = i;
|
|
163
|
+
});
|
|
164
|
+
items[best]!.focus();
|
|
165
|
+
});
|
|
166
|
+
scope.on(document, 'pointerdown', (event) => {
|
|
167
|
+
if (open && !root.contains(event.target as Node)) set(false);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
open: () => set(true),
|
|
172
|
+
close: () => set(false),
|
|
173
|
+
toggle: () => set(!open),
|
|
174
|
+
get isOpen() {
|
|
175
|
+
return open;
|
|
176
|
+
},
|
|
177
|
+
destroy: () => scope.dispose(),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* orbit-menu — soft white squares (16 px corners, a wide low shadow) around a middle button whose lines turn into an ×.
|
|
2
|
+
The options sit on the middle and the engine moves them out; give the menu room around it. */
|
|
3
|
+
.mk-orbit-menu,
|
|
4
|
+
mk-orbit-menu {
|
|
5
|
+
--mk-orbit-size: 4rem;
|
|
6
|
+
--mk-orbit-face: var(--mk-surface-3);
|
|
7
|
+
--mk-orbit-ink: var(--mk-text);
|
|
8
|
+
--mk-orbit-shadow: 0 18px 36px -14px rgb(0 0 0 / 0.22), 0 2px 6px -2px rgb(0 0 0 / 0.08);
|
|
9
|
+
position: relative;
|
|
10
|
+
display: inline-grid;
|
|
11
|
+
place-items: center;
|
|
12
|
+
width: var(--mk-orbit-size);
|
|
13
|
+
height: var(--mk-orbit-size);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:is(.mk-orbit-menu, mk-orbit-menu) :is([data-mk-orbit-toggle], [data-mk-orbit-item]) {
|
|
17
|
+
display: grid;
|
|
18
|
+
place-items: center;
|
|
19
|
+
width: var(--mk-orbit-size);
|
|
20
|
+
height: var(--mk-orbit-size);
|
|
21
|
+
padding: 0;
|
|
22
|
+
border: 1px solid var(--mk-outline-soft);
|
|
23
|
+
border-radius: var(--mk-radius-md);
|
|
24
|
+
background: var(--mk-orbit-face);
|
|
25
|
+
box-shadow: var(--mk-orbit-shadow);
|
|
26
|
+
color: var(--mk-orbit-ink);
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
-webkit-tap-highlight-color: transparent;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:is(.mk-orbit-menu, mk-orbit-menu) [data-mk-orbit-toggle] {
|
|
32
|
+
position: relative;
|
|
33
|
+
z-index: 2;
|
|
34
|
+
transition:
|
|
35
|
+
background-color 0.3s ease,
|
|
36
|
+
box-shadow 0.3s ease;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Open: the middle goes glassy, the options are the faces now. */
|
|
40
|
+
:is(.mk-orbit-menu, mk-orbit-menu)[data-mk-state='open'] [data-mk-orbit-toggle] {
|
|
41
|
+
background: color-mix(in srgb, var(--mk-orbit-face) 55%, transparent);
|
|
42
|
+
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mk-orbit-ink) 8%, transparent);
|
|
43
|
+
backdrop-filter: blur(8px);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
:is(.mk-orbit-menu, mk-orbit-menu) [data-mk-orbit-item] {
|
|
47
|
+
position: absolute;
|
|
48
|
+
top: 0;
|
|
49
|
+
left: 0;
|
|
50
|
+
z-index: 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
:is(.mk-orbit-menu, mk-orbit-menu) :is([data-mk-orbit-toggle], [data-mk-orbit-item]) svg {
|
|
54
|
+
width: 1.75rem;
|
|
55
|
+
height: 1.75rem;
|
|
56
|
+
transition: transform 0.35s var(--mk-ease-swatch);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@media (hover: hover) {
|
|
60
|
+
:is(.mk-orbit-menu, mk-orbit-menu) [data-mk-orbit-item]:hover svg {
|
|
61
|
+
transform: scale(1.12);
|
|
62
|
+
}
|
|
63
|
+
:is(.mk-orbit-menu, mk-orbit-menu) [data-mk-orbit-item]:hover {
|
|
64
|
+
box-shadow: 0 22px 40px -14px rgb(0 0 0 / 0.28), 0 2px 6px -2px rgb(0 0 0 / 0.1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
:is(.mk-orbit-menu, mk-orbit-menu) :is([data-mk-orbit-toggle], [data-mk-orbit-item]):focus-visible {
|
|
69
|
+
outline: 2px solid var(--mk-accent);
|
|
70
|
+
outline-offset: 3px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* The three lines and their × . */
|
|
74
|
+
[data-mk-orbit-burger] {
|
|
75
|
+
position: relative;
|
|
76
|
+
width: 1.5rem;
|
|
77
|
+
height: 1rem;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
[data-mk-orbit-burger] i {
|
|
81
|
+
position: absolute;
|
|
82
|
+
left: 0;
|
|
83
|
+
width: 100%;
|
|
84
|
+
height: 2px;
|
|
85
|
+
border-radius: 2px;
|
|
86
|
+
background: currentColor;
|
|
87
|
+
transition:
|
|
88
|
+
transform 0.4s var(--mk-ease-swatch),
|
|
89
|
+
opacity 0.2s ease;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
[data-mk-orbit-burger] i:nth-child(1) {
|
|
93
|
+
top: 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
[data-mk-orbit-burger] i:nth-child(2) {
|
|
97
|
+
top: calc(50% - 1px);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
[data-mk-orbit-burger] i:nth-child(3) {
|
|
101
|
+
bottom: 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
:is(.mk-orbit-menu, mk-orbit-menu)[data-mk-state='open'] [data-mk-orbit-burger] i:nth-child(1) {
|
|
105
|
+
transform: translateY(calc(0.5rem - 1px)) rotate(45deg);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
:is(.mk-orbit-menu, mk-orbit-menu)[data-mk-state='open'] [data-mk-orbit-burger] i:nth-child(2) {
|
|
109
|
+
opacity: 0;
|
|
110
|
+
transform: scaleX(0.2);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
:is(.mk-orbit-menu, mk-orbit-menu)[data-mk-state='open'] [data-mk-orbit-burger] i:nth-child(3) {
|
|
114
|
+
transform: translateY(calc(-0.5rem + 1px)) rotate(-45deg);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media (prefers-reduced-motion: reduce) {
|
|
118
|
+
[data-mk-orbit-burger] i,
|
|
119
|
+
:is(.mk-orbit-menu, mk-orbit-menu) [data-mk-orbit-toggle],
|
|
120
|
+
:is(.mk-orbit-menu, mk-orbit-menu) svg {
|
|
121
|
+
transition: none;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@media (forced-colors: active) {
|
|
126
|
+
:is(.mk-orbit-menu, mk-orbit-menu) :is([data-mk-orbit-toggle], [data-mk-orbit-item]) {
|
|
127
|
+
border: 1px solid ButtonText;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useRef, type HTMLAttributes, type MutableRefObject, type ReactNode } from 'react';
|
|
3
|
+
import { useIsomorphicLayoutEffect, useLatest } from '../../react/use-recipe';
|
|
4
|
+
import { createOrbitMenu, type OrbitMenuInstance, type OrbitMenuOptions } from './engine';
|
|
5
|
+
|
|
6
|
+
export interface OrbitMenuItem {
|
|
7
|
+
value: string;
|
|
8
|
+
label: string;
|
|
9
|
+
icon: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface OrbitMenuProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onToggle'>, OrbitMenuOptions {
|
|
13
|
+
items: OrbitMenuItem[];
|
|
14
|
+
/** The middle button's name (default 'Menú'). */
|
|
15
|
+
label?: string;
|
|
16
|
+
instanceRef?: MutableRefObject<OrbitMenuInstance | null>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** <OrbitMenu label="Acciones" items={[{ value: 'nuevo', label: 'Nuevo', icon: <Plus /> }, …]} onSelect={run} /> */
|
|
20
|
+
export function OrbitMenu({ items, label = 'Menú', radius, start, closeOnSelect, onToggle, onSelect, instanceRef, className, ...props }: OrbitMenuProps) {
|
|
21
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
22
|
+
const toggled = useLatest(onToggle);
|
|
23
|
+
const selected = useLatest(onSelect);
|
|
24
|
+
const keys = items.map((item) => item.value).join('\u0000');
|
|
25
|
+
useIsomorphicLayoutEffect(() => {
|
|
26
|
+
const created = createOrbitMenu(ref.current, { radius, start, closeOnSelect, onToggle: (open) => toggled.current?.(open), onSelect: (value) => selected.current?.(value) });
|
|
27
|
+
if (instanceRef) instanceRef.current = created;
|
|
28
|
+
return () => {
|
|
29
|
+
created.destroy();
|
|
30
|
+
if (instanceRef) instanceRef.current = null;
|
|
31
|
+
};
|
|
32
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33
|
+
}, [keys, radius, start, closeOnSelect]);
|
|
34
|
+
return (
|
|
35
|
+
<div {...props} ref={ref} className={['mk-orbit-menu', className].filter(Boolean).join(' ')}>
|
|
36
|
+
<button type="button" data-mk-orbit-toggle="" aria-label={label} />
|
|
37
|
+
{items.map((item) => (
|
|
38
|
+
<button key={item.value} type="button" data-mk-orbit-item="" data-mk-value={item.value} aria-label={item.label}>
|
|
39
|
+
{item.icon}
|
|
40
|
+
</button>
|
|
41
|
+
))}
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pagination
|
|
2
2
|
|
|
3
|
-
Paginación con ventana acotada de números, extremos
|
|
3
|
+
Paginación con ventana acotada de números, extremos y elipsis. Una píldora de acento se desliza bajo la página actual (.4 s, curva swing); cuando la ventana se mueve, los números que siguen se deslizan a su sitio nuevo y los nuevos entran con un pop desde un blur; las flechas hacen el press y se inclinan hacia su lado; al pasar, los botones se elevan.
|
|
4
4
|
|
|
5
5
|
```html
|
|
6
6
|
<mk-pagination class="mk-pagination" total-pages="30" page="4" role="navigation" aria-label="Artículos">
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { gsap, EASE, registerMotion } from '../../core/gsap';
|
|
2
|
+
import { reduced } from '../../core/reduced';
|
|
1
3
|
import { createScope } from '../../core/scope';
|
|
2
4
|
import { inert, type Instance } from '../../core/types';
|
|
5
|
+
import { press } from '../../motion/micro';
|
|
3
6
|
|
|
4
7
|
export interface PaginationOptions {
|
|
5
8
|
totalPages?: number;
|
|
@@ -17,20 +20,45 @@ export interface PaginationInstance extends Instance {
|
|
|
17
20
|
// Reserve room for the page-window arithmetic so incrementing always progresses.
|
|
18
21
|
const positive = (n: number | undefined, fallback: number) => Number.isFinite(n) ? Math.max(1, Math.min(Number.MAX_SAFE_INTEGER - 32, Math.floor(n!))) : fallback;
|
|
19
22
|
|
|
20
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Renders a bounded window of pages, even when totalPages is very large. A pill
|
|
25
|
+
* ([data-mk-pagination-indicator]) glides under the current page on Melonmind's
|
|
26
|
+
* swing; when the window moves, the numbers that stay slide to their new place
|
|
27
|
+
* and the new ones pop in out of a blur; the arrows press and nudge their way.
|
|
28
|
+
*/
|
|
21
29
|
export function createPagination(root: HTMLElement | null, options: PaginationOptions = {}): PaginationInstance {
|
|
22
30
|
const pages = root?.querySelector<HTMLElement>('[data-mk-pagination-pages]');
|
|
23
31
|
if (!root || !pages) return inert({ setPage() {}, setTotalPages() {}, page: 1, totalPages: 1 });
|
|
32
|
+
registerMotion();
|
|
24
33
|
const scope = createScope();
|
|
25
34
|
const original = [...pages.childNodes];
|
|
35
|
+
const indicator = document.createElement('span');
|
|
36
|
+
indicator.dataset.mkPaginationIndicator = '';
|
|
37
|
+
indicator.setAttribute('aria-hidden', 'true');
|
|
38
|
+
const effects = new Set<gsap.core.Animation>();
|
|
39
|
+
const keep = (animation: gsap.core.Animation | null) => {
|
|
40
|
+
if (!animation) return;
|
|
41
|
+
effects.add(animation);
|
|
42
|
+
// Finished ones leave as new ones arrive: the animation's own onComplete stays untouched.
|
|
43
|
+
for (const effect of effects) if (effect.totalProgress() === 1) effects.delete(effect);
|
|
44
|
+
};
|
|
45
|
+
scope.add(() => {
|
|
46
|
+
for (const effect of effects) effect.kill();
|
|
47
|
+
effects.clear();
|
|
48
|
+
});
|
|
49
|
+
let placed = false;
|
|
26
50
|
const previous = root.querySelector<HTMLButtonElement>('[data-mk-pagination-previous]');
|
|
27
51
|
const next = root.querySelector<HTMLButtonElement>('[data-mk-pagination-next]');
|
|
28
52
|
let total = positive(options.totalPages, 10);
|
|
29
53
|
let page = Math.min(total, positive(options.page, 1));
|
|
30
54
|
const siblings = Math.min(10, Math.max(0, Number.isFinite(options.siblings) ? Math.floor(options.siblings!) : 1));
|
|
31
55
|
scope.attr(root, 'data-mk-ready', '');
|
|
32
|
-
|
|
56
|
+
// The pill draws the current page (the buttons themselves stay clear).
|
|
57
|
+
scope.attr(root, 'data-mk-glide', '');
|
|
58
|
+
const render = (animate = false) => {
|
|
33
59
|
const hadFocus = pages.contains(document.activeElement);
|
|
60
|
+
// Where each number was, to slide the ones that stay.
|
|
61
|
+
const before = new Map([...pages.querySelectorAll<HTMLElement>('[data-mk-page]')].map((button) => [button.dataset.mkPage!, button.offsetLeft]));
|
|
34
62
|
const selected = new Set([1, total]);
|
|
35
63
|
for (let n = Math.max(1, page - siblings); n <= Math.min(total, page + siblings); n++) selected.add(n);
|
|
36
64
|
const fragment = document.createDocumentFragment();
|
|
@@ -52,8 +80,23 @@ export function createPagination(root: HTMLElement | null, options: PaginationOp
|
|
|
52
80
|
fragment.append(button);
|
|
53
81
|
last = n;
|
|
54
82
|
}
|
|
55
|
-
pages.replaceChildren(fragment);
|
|
83
|
+
pages.replaceChildren(indicator, fragment);
|
|
56
84
|
if (hadFocus) pages.querySelector<HTMLButtonElement>('[aria-current]')?.focus();
|
|
85
|
+
const motion = animate && !reduced();
|
|
86
|
+
if (motion) {
|
|
87
|
+
for (const button of pages.querySelectorAll<HTMLElement>('[data-mk-page]')) {
|
|
88
|
+
const from = before.get(button.dataset.mkPage!);
|
|
89
|
+
if (from === undefined) keep(gsap.fromTo(button, { opacity: 0, scale: 0.6, filter: 'blur(4px)' }, { opacity: 1, scale: 1, filter: 'blur(0px)', duration: 0.3, ease: EASE.pop, clearProps: 'opacity,transform,filter' }));
|
|
90
|
+
else if (from !== button.offsetLeft) keep(gsap.fromTo(button, { x: from - button.offsetLeft }, { x: 0, duration: 0.35, ease: EASE.swatch, clearProps: 'transform' }));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const current = pages.querySelector<HTMLElement>('[aria-current]');
|
|
94
|
+
if (current) {
|
|
95
|
+
const box = { x: current.offsetLeft, width: current.offsetWidth, height: current.offsetHeight };
|
|
96
|
+
if (motion && placed) keep(gsap.to(indicator, { ...box, duration: 0.4, ease: EASE.swatch }));
|
|
97
|
+
else gsap.set(indicator, box);
|
|
98
|
+
placed = true;
|
|
99
|
+
}
|
|
57
100
|
if (previous) scope.attr(previous, 'disabled', page === 1 ? '' : null);
|
|
58
101
|
if (next) scope.attr(next, 'disabled', page === total ? '' : null);
|
|
59
102
|
};
|
|
@@ -63,7 +106,7 @@ export function createPagination(root: HTMLElement | null, options: PaginationOp
|
|
|
63
106
|
if (candidate === page) return;
|
|
64
107
|
const focused = pages.contains(document.activeElement);
|
|
65
108
|
page = candidate;
|
|
66
|
-
render();
|
|
109
|
+
render(true);
|
|
67
110
|
if (focused) pages.querySelector<HTMLButtonElement>('[aria-current]')?.focus();
|
|
68
111
|
if (notify) {
|
|
69
112
|
options.onChange?.(page);
|
|
@@ -73,6 +116,9 @@ export function createPagination(root: HTMLElement | null, options: PaginationOp
|
|
|
73
116
|
scope.on(root, 'click', (event) => {
|
|
74
117
|
const target = (event.target as Element).closest<HTMLButtonElement>('button');
|
|
75
118
|
if (!target || target.disabled) return;
|
|
119
|
+
if (!reduced()) keep(press(target));
|
|
120
|
+
// The arrow leans the way it goes, then settles.
|
|
121
|
+
if ((target === previous || target === next) && !reduced()) keep(gsap.fromTo(target, { x: target === next ? 4 : -4 }, { x: 0, duration: 0.45, ease: EASE.click, clearProps: 'x' }));
|
|
76
122
|
if (target === previous) setPage(page - 1);
|
|
77
123
|
else if (target === next) setPage(page + 1);
|
|
78
124
|
else if (target.dataset.mkPage) setPage(Number(target.dataset.mkPage));
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
/* pagination — round page buttons on surface-2; a pill (accent) glides under the current page; numbers that stay slide
|
|
2
|
+
when the window moves and new ones pop in; hover lifts, press squeezes. */
|
|
1
3
|
.mk-pagination, mk-pagination { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: .35rem; }
|
|
2
|
-
.mk-pagination [data-mk-pagination-pages], mk-pagination [data-mk-pagination-pages] { display: flex; align-items: center; gap: .25rem; }
|
|
3
|
-
.mk-pagination button, mk-pagination button { min-width: 2.5rem; height: 2.5rem; border: 0; border-radius: var(--mk-radius-full); background: var(--mk-surface-2); color: var(--mk-text); font: inherit; cursor: pointer; transition:
|
|
4
|
+
.mk-pagination [data-mk-pagination-pages], mk-pagination [data-mk-pagination-pages] { position: relative; display: flex; align-items: center; gap: .25rem; isolation: isolate; }
|
|
5
|
+
.mk-pagination button, mk-pagination button { position: relative; min-width: 2.5rem; height: 2.5rem; border: 0; border-radius: var(--mk-radius-full); background: var(--mk-surface-2); color: var(--mk-text); font: inherit; font-variant-numeric: tabular-nums; cursor: pointer; transition: translate .3s cubic-bezier(.38,.49,0,1.5), background-color .25s, color .25s; }
|
|
4
6
|
.mk-pagination button[aria-current], mk-pagination button[aria-current] { background: var(--mk-accent); color: var(--mk-on-accent); }
|
|
5
|
-
|
|
6
|
-
.mk-pagination
|
|
7
|
+
/* With the engine, the pill paints the current page and its button stays clear. */
|
|
8
|
+
:is(.mk-pagination, mk-pagination)[data-mk-glide] button[aria-current] { background: transparent; }
|
|
9
|
+
:is(.mk-pagination, mk-pagination) [data-mk-pagination-indicator] { position: absolute; top: 0; left: 0; z-index: -1; border-radius: var(--mk-radius-full); background: var(--mk-accent); pointer-events: none; }
|
|
10
|
+
.mk-pagination button:hover:not(:disabled), mk-pagination button:hover:not(:disabled) { translate: 0 -3px; }
|
|
11
|
+
.mk-pagination button:hover:not(:disabled):not([aria-current]), mk-pagination button:hover:not(:disabled):not([aria-current]) { background: var(--mk-surface-3); }
|
|
7
12
|
.mk-pagination button:focus-visible, mk-pagination button:focus-visible { outline: 2px solid var(--mk-accent); outline-offset: 3px; }
|
|
8
13
|
.mk-pagination button:disabled, mk-pagination button:disabled { opacity: .35; cursor: default; }
|
|
9
14
|
.mk-pagination__gap { padding: 0 .15rem; color: var(--mk-muted); }
|
|
10
|
-
@media (prefers-reduced-motion: reduce) { .mk-pagination button, mk-pagination button { transition: none;
|
|
15
|
+
@media (prefers-reduced-motion: reduce) { .mk-pagination button, mk-pagination button { transition: none; translate: none !important; } }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# password-strength
|
|
2
|
+
|
|
3
|
+
Campo de contraseña nativo con fortaleza en vivo: botón mostrar/ocultar (el ojo cambia con blur y su barra se dibuja), medidor de cuatro segmentos que se encienden en cascada y cambian de color por nivel (débil → aceptable → fuerte → muy fuerte), etiqueta que cambia con blur y lista de requisitos cuyos ✓ se dibujan. Un estado educado anuncia el nivel cuando dejas de escribir.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<mk-password-strength class="mk-password-strength">
|
|
7
|
+
<input type="password" name="password" autocomplete="new-password" aria-label="Contraseña" />
|
|
8
|
+
</mk-password-strength>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`defineElements()`, `createPasswordStrength(root, options)` o `<PasswordStrength name="password" requireScore={3} onStrength={setResult} />` (el campo sigue sin control; `onValueChange` da el texto).
|
|
12
|
+
|
|
13
|
+
Opciones: `minLength=8`, `score(value)` (sustituye la puntuación), `requireScore` (por debajo, el campo se marca inválido con `setCustomValidity`), `labels {show, hide, invalid, checks}`, `onChange(result)`. API: `score`, `value`, `destroy()`. Evento `mk:strength` con `{score, label, met}`.
|
|
14
|
+
|
|
15
|
+
Utilidad pura `scorePassword(value, minLength)`: la longitud y la variedad suben la puntuación; contraseñas comunes, secuencias (abc, 123) y repeticiones (aaa) la bajan. Es orientativa: el servidor decide qué acepta.
|
|
16
|
+
|
|
17
|
+
Variables: `--mk-password-weak`, `--mk-password-fair`, `--mk-password-good`, `--mk-password-strong`. Movimiento reducido: los segmentos y la etiqueta cambian sin animación.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { MkElement, defineElement, type OptionType } from '../../elements/base';
|
|
2
|
+
import { createPasswordStrength, type PasswordStrengthInstance } from './engine';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* <mk-password-strength class="mk-password-strength" min-length="10">
|
|
6
|
+
* <input type="password" name="password" autocomplete="new-password" aria-label="Contraseña" />
|
|
7
|
+
* </mk-password-strength>
|
|
8
|
+
* Emits mk:strength ({score, label, met}).
|
|
9
|
+
*/
|
|
10
|
+
export class MkPasswordStrengthElement extends MkElement<PasswordStrengthInstance> {
|
|
11
|
+
static options: Record<string, OptionType> = { minLength: 'number', requireScore: 'number', labels: 'json' };
|
|
12
|
+
|
|
13
|
+
protected create(options: Record<string, unknown>) {
|
|
14
|
+
return createPasswordStrength(this, options);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get score() {
|
|
18
|
+
return this.instance?.score ?? 0;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const definePasswordStrength = () => defineElement('mk-password-strength', MkPasswordStrengthElement);
|