@yewdiel21/motion-kit 0.9.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -0
- package/dist/auto/index.d.ts +72 -3
- package/dist/auto/index.js +139 -3
- package/dist/auto/index.js.map +1 -1
- package/dist/{chunk-BFC27F2G.js → chunk-6P4P7NU6.js} +2 -218
- package/dist/chunk-6P4P7NU6.js.map +1 -0
- package/dist/chunk-CU6SXW3E.js +20334 -0
- package/dist/chunk-CU6SXW3E.js.map +1 -0
- package/dist/{chunk-XDWBVFHQ.js → chunk-EY4BJKC4.js} +1203 -29
- package/dist/chunk-EY4BJKC4.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/attachment.css +266 -0
- package/dist/css/components/breadcrumb.css +110 -0
- package/dist/css/components/calendar.css +159 -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 +591 -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 +232 -0
- package/dist/css/components/hold-confirm.css +87 -0
- package/dist/css/components/hover-card.css +20 -0
- package/dist/css/components/image-preview.css +195 -0
- package/dist/css/components/input-otp.css +10 -0
- package/dist/css/components/json-viewer.css +272 -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/notification-bell.css +127 -0
- package/dist/css/components/pagination.css +11 -0
- package/dist/css/components/password-strength.css +183 -0
- package/dist/css/components/popover.css +25 -0
- package/dist/css/components/progress.css +140 -0
- package/dist/css/components/quantity.css +16 -0
- package/dist/css/components/questionnaire.css +217 -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/scratch-card.css +75 -0
- package/dist/css/components/skeleton.css +108 -0
- package/dist/css/components/slot-picker.css +126 -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/studio-dock.css +35 -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/tooltip.css +79 -0
- package/dist/css/components/trailer.css +37 -0
- package/dist/css/components/tree-view.css +210 -0
- package/dist/css/components/virtual-list.css +195 -0
- package/dist/css/controls.css +65 -0
- package/dist/css/tokens.css +185 -181
- package/dist/elements/index.d.ts +742 -5
- package/dist/elements/index.js +1527 -8
- package/dist/elements/index.js.map +1 -1
- package/dist/{engine-GDGwQnJE.d.ts → engine-Cn6IhE3z.d.ts} +1 -1
- package/dist/engine-QECQnGz1.d.ts +33 -0
- package/dist/index.css +10113 -181
- package/dist/index.d.ts +89 -5
- package/dist/index.js +285 -9
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +678 -23
- package/dist/react/index.js +2389 -7
- package/dist/react/index.js.map +1 -1
- package/dist/{reduced-B98f8LPs.d.ts → reduced-BBUusld6.d.ts} +206 -2
- package/dist/reveal-DEvp6U6T.d.ts +2381 -0
- package/dist/{store-pHiUvxP8.d.ts → store-DjkTBX7f.d.ts} +2 -2
- package/package.json +1 -1
- package/registry.json +583 -104
- package/skills/motion-kit/SKILL.md +209 -189
- package/src/auto/auto-init.ts +136 -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/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/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/calendar/README.md +82 -0
- package/src/components/calendar/calendar.css +158 -0
- package/src/components/calendar/element.ts +27 -0
- package/src/components/calendar/engine.ts +412 -0
- package/src/components/calendar/react.tsx +69 -0
- package/src/components/chart/README.md +24 -0
- package/src/components/chart/chart.css +295 -0
- package/src/components/chart/element.ts +41 -0
- package/src/components/chart/engine.ts +811 -0
- package/src/components/chart/react.tsx +50 -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 +590 -0
- package/src/components/data-table/element.ts +54 -0
- package/src/components/data-table/engine.ts +1059 -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 +775 -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 +365 -0
- package/src/components/filter-builder/filter-builder.css +231 -0
- package/src/components/filter-builder/react.tsx +36 -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 +20 -0
- package/src/components/hover-card/element.ts +8 -0
- package/src/components/hover-card/engine.ts +131 -0
- package/src/components/hover-card/hover-card.css +19 -0
- package/src/components/hover-card/react.tsx +19 -0
- 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 +325 -0
- package/src/components/image-preview/image-preview.css +194 -0
- package/src/components/image-preview/react.tsx +43 -0
- package/src/components/input-otp/README.md +18 -0
- package/src/components/input-otp/element.ts +14 -0
- package/src/components/input-otp/engine.ts +106 -0
- package/src/components/input-otp/input-otp.css +9 -0
- package/src/components/input-otp/react.tsx +21 -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 +440 -0
- package/src/components/json-viewer/json-viewer.css +271 -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/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/pagination/README.md +17 -0
- package/src/components/pagination/element.ts +14 -0
- package/src/components/pagination/engine.ts +102 -0
- package/src/components/pagination/pagination.css +10 -0
- package/src/components/pagination/react.tsx +22 -0
- 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/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/quantity/README.md +20 -0
- package/src/components/quantity/element.ts +14 -0
- package/src/components/quantity/engine.ts +85 -0
- package/src/components/quantity/quantity.css +15 -0
- package/src/components/quantity/react.tsx +21 -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/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/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/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/slot-picker/README.md +68 -0
- package/src/components/slot-picker/element.ts +27 -0
- package/src/components/slot-picker/engine.ts +412 -0
- package/src/components/slot-picker/react.tsx +76 -0
- package/src/components/slot-picker/slot-picker.css +125 -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/studio-dock/README.md +44 -0
- package/src/components/studio-dock/element.ts +11 -0
- package/src/components/studio-dock/engine.ts +212 -0
- package/src/components/studio-dock/react.tsx +23 -0
- package/src/components/studio-dock/studio-dock.css +34 -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/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/trailer/README.md +28 -0
- package/src/components/trailer/element.ts +13 -0
- package/src/components/trailer/engine.ts +189 -0
- package/src/components/trailer/react.tsx +16 -0
- package/src/components/trailer/trailer.css +36 -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 +569 -0
- package/src/components/tree-view/react.tsx +78 -0
- package/src/components/tree-view/tree-view.css +209 -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/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 +108 -0
- 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/controls/README.md +14 -0
- package/src/css/controls/status.css +63 -0
- package/src/css/tokens.css +186 -182
- package/src/elements/index.ts +171 -0
- package/src/index.ts +97 -0
- 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 +78 -0
- package/src/react/use-action-button.ts +6 -0
- package/src/react/use-editorial-reveal.ts +7 -0
- package/src/react/use-film-hero.ts +6 -0
- package/src/react/use-font-cycle.ts +7 -0
- package/src/react/use-image-zoom.ts +5 -0
- package/src/react/use-joined-cta.ts +5 -0
- package/src/react/use-local-clock.ts +5 -0
- package/src/react/use-scroll-dock.ts +5 -0
- package/src/react/use-sticker.ts +5 -0
- package/src/react/use-studio-dock.ts +8 -0
- package/src/react/use-thumbnail-nav.ts +7 -0
- package/src/react/use-trailer.ts +6 -0
- package/src/react/use-weight-hover.ts +5 -0
- package/src/recipes/action-button/README.md +31 -0
- package/src/recipes/action-button/action-button.css +113 -0
- package/src/recipes/action-button/create-action-button.ts +56 -0
- package/src/recipes/editorial-reveal/README.md +35 -0
- package/src/recipes/editorial-reveal/create-editorial-reveal.ts +91 -0
- package/src/recipes/editorial-reveal/editorial-reveal.css +17 -0
- package/src/recipes/film-hero/README.md +23 -0
- package/src/recipes/film-hero/create-film-hero.ts +65 -0
- package/src/recipes/film-hero/film-hero.css +29 -0
- package/src/recipes/font-cycle/README.md +11 -0
- package/src/recipes/font-cycle/create-font-cycle.ts +126 -0
- package/src/recipes/font-cycle/font-cycle.css +36 -0
- package/src/recipes/image-zoom/README.md +16 -0
- package/src/recipes/image-zoom/create-image-zoom.ts +27 -0
- package/src/recipes/image-zoom/image-zoom.css +7 -0
- package/src/recipes/joined-cta/README.md +13 -0
- package/src/recipes/joined-cta/create-joined-cta.ts +22 -0
- package/src/recipes/joined-cta/joined-cta.css +17 -0
- package/src/recipes/local-clock/README.md +31 -0
- package/src/recipes/local-clock/create-local-clock.ts +61 -0
- package/src/recipes/scroll-dock/README.md +46 -0
- package/src/recipes/scroll-dock/create-scroll-dock.ts +72 -0
- package/src/recipes/scroll-dock/scroll-dock.css +70 -0
- package/src/recipes/sticker/README.md +59 -0
- package/src/recipes/sticker/create-sticker.ts +490 -0
- package/src/recipes/sticker/sticker.css +112 -0
- package/src/recipes/thumbnail-nav/README.md +16 -0
- package/src/recipes/thumbnail-nav/create-thumbnail-nav.ts +165 -0
- package/src/recipes/thumbnail-nav/thumbnail-nav.css +108 -0
- package/src/recipes/weight-hover/README.md +37 -0
- package/src/recipes/weight-hover/create-weight-hover.ts +136 -0
- package/src/recipes/weight-hover/weight-hover.css +7 -0
- package/dist/chunk-BFC27F2G.js.map +0 -1
- package/dist/chunk-J6OCFNGU.js +0 -177
- package/dist/chunk-J6OCFNGU.js.map +0 -1
- package/dist/chunk-JQMJQSXD.js +0 -2374
- package/dist/chunk-JQMJQSXD.js.map +0 -1
- package/dist/chunk-XDWBVFHQ.js.map +0 -1
- package/dist/reveal-C0hCDcB_.d.ts +0 -415
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# color-picker
|
|
2
|
+
|
|
3
|
+
Selector de color completo: un botón con la muestra y el código que, al pulsarlo, crece hasta un panel (el mismo `dialog` anclado de motion-kit, que sale del botón y se pliega de vuelta en él; como las opciones de `menu`, sus secciones entran en cascada mientras la superficie crece). El panel tiene un área de saturación y brillo (`color-area`), un deslizador de tono, uno de opacidad (con `alpha`), un campo de código (`color-field`), colores guardados y un cuentagotas donde el navegador ofrece `EyeDropper`. Con `inline` el panel se muestra en su sitio, sin botón.
|
|
4
|
+
|
|
5
|
+
Hay un solo color: cambie el control que cambie, los demás se deslizan al nuevo valor (curva swing), la muestra del botón cambia en directo y su código rueda al confirmar. Los colores guardados rebotan al pulsarlos y se marcan con `aria-pressed`.
|
|
6
|
+
|
|
7
|
+
Importa también `css/components/dialog.css` (el panel es un diálogo anclado), `color-area.css`, `color-slider.css` y `color-field.css`, o el CSS completo. La CLI los copia: la entrada `requires` dialog, color-area, color-slider y color-field.
|
|
8
|
+
|
|
9
|
+
## HTML / Astro
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<mk-color-picker class="mk-color-picker" value="#3b82f6" label="Color del evento"></mk-color-picker>
|
|
13
|
+
<mk-color-picker class="mk-color-picker" inline alpha swatches="#111111,#ef4444,#22c55e"></mk-color-picker>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## React
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
const [color, setColor] = useState('#22c55e');
|
|
20
|
+
<ColorPicker value={color} onInput={setColor} label="Color de la etiqueta" />
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Opciones
|
|
24
|
+
|
|
25
|
+
| Opción | Atributo | Por defecto | Qué hace |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| `value` | `value` | `'#ff8800'` | Color de partida. |
|
|
28
|
+
| `alpha` | `alpha` | `false` | Añade el deslizador de opacidad y conserva la transparencia. |
|
|
29
|
+
| `format` | `format` | `'hex'` | Formato del campo de código: `hex`, `rgb` o `hsl`. |
|
|
30
|
+
| `swatches` | `swatches` (lista con comas) | 8 colores | Colores guardados; `[]` los quita. |
|
|
31
|
+
| `label` | `label` | `'Color'` | Nombre accesible; el botón dice «<label>: #rrggbb». |
|
|
32
|
+
| `name` | `name` | — | Un input oculto envía el hex. |
|
|
33
|
+
| `disabled` | `disabled` | `false` | Desactiva botón y controles. |
|
|
34
|
+
| `inline` | `inline` | `false` | Panel en su sitio, sin botón ni popover. |
|
|
35
|
+
| `eyedropper` | `eyedropper` | `true` | Botón de cuentagotas donde exista la API. |
|
|
36
|
+
| `onInput(hex, hsva)` | — | — | En directo, al arrastrar. |
|
|
37
|
+
| `onChange(hex, hsva)` | — | — | Color confirmado. |
|
|
38
|
+
|
|
39
|
+
## API y eventos
|
|
40
|
+
|
|
41
|
+
`open()`, `close()`, `setColor(color, notify = true)`, `value`, `color`, `isOpen`, `destroy()`. Eventos `mk:input` y `mk:change` con `{ value, color }`; los de las piezas internas se detienen en el panel, así que quien escucha al selector solo oye al selector.
|
|
42
|
+
|
|
43
|
+
## Accesibilidad
|
|
44
|
+
|
|
45
|
+
El botón tiene `aria-haspopup="dialog"` y `aria-expanded`. Escape o un clic fuera cierran el panel y el foco vuelve al botón. El cuentagotas, si se cancela, no cambia nada. Con movimiento reducido el panel aparece sin crecer y los controles saltan a su valor.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/* color-picker — a swatch button (12 px, the hex beside it) that grows into a 20 px panel: area, hue, alpha, field,
|
|
2
|
+
eyedropper and 8 px preset swatches. Inline, the panel sits in place. Needs dialog.css for the popover, and the
|
|
3
|
+
color-area, color-slider and color-field stylesheets for its parts. */
|
|
4
|
+
.mk-color-picker,
|
|
5
|
+
mk-color-picker {
|
|
6
|
+
--mk-color-checker: repeating-conic-gradient(#d4d4d4 0 25%, #fff 0 50%) 0 0 / 8px 8px;
|
|
7
|
+
display: inline-block;
|
|
8
|
+
max-width: 100%;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
:is(.mk-color-picker, mk-color-picker) [data-mk-color-trigger] {
|
|
12
|
+
display: inline-flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
gap: 0.6rem;
|
|
15
|
+
height: 2.75rem;
|
|
16
|
+
padding: 0 0.9rem 0 0.4rem;
|
|
17
|
+
border: 0;
|
|
18
|
+
border-radius: 12px;
|
|
19
|
+
background: var(--mk-surface-3);
|
|
20
|
+
color: var(--mk-text);
|
|
21
|
+
font: 500 0.9375rem/1 var(--mk-font-mono, ui-monospace, monospace);
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:is(.mk-color-picker, mk-color-picker) [data-mk-color-trigger]:focus-visible {
|
|
26
|
+
outline: 3px solid color-mix(in srgb, var(--mk-accent) 45%, transparent);
|
|
27
|
+
outline-offset: 2px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
:is(.mk-color-picker, mk-color-picker) [data-mk-color-trigger]:disabled {
|
|
31
|
+
opacity: 0.5;
|
|
32
|
+
cursor: not-allowed;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
:is(.mk-color-picker, mk-color-picker) [data-mk-color-trigger] [data-mk-color-swatch],
|
|
36
|
+
[data-mk-color-preset] {
|
|
37
|
+
border-radius: 8px;
|
|
38
|
+
background: linear-gradient(var(--mk-color-swatch), var(--mk-color-swatch)), var(--mk-color-checker, repeating-conic-gradient(#d4d4d4 0 25%, #fff 0 50%) 0 0 / 8px 8px);
|
|
39
|
+
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mk-text) 22%, transparent);
|
|
40
|
+
transition: background 0.25s ease;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
:is(.mk-color-picker, mk-color-picker) [data-mk-color-trigger] [data-mk-color-swatch] {
|
|
44
|
+
width: 2rem;
|
|
45
|
+
height: 2rem;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Classes, not data attributes: the copy that folds back into the swatch on close keeps only the classes. */
|
|
49
|
+
.mk-dialog.mk-color-panel {
|
|
50
|
+
--mk-dialog-width: 18rem;
|
|
51
|
+
--mk-dialog-radius: 20px;
|
|
52
|
+
--mk-dialog-bg: var(--mk-surface-1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
[data-mk-color-panel-body] {
|
|
56
|
+
display: grid;
|
|
57
|
+
gap: 0.9rem;
|
|
58
|
+
padding: 0.9rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* The loupes pop above the area and the sliders: the panel leaves them room. */
|
|
62
|
+
.mk-dialog.mk-color-panel [data-mk-color-panel-body] {
|
|
63
|
+
padding-top: 1.1rem;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:is(.mk-color-picker, mk-color-picker)[data-mk-inline] [data-mk-color-panel-body] {
|
|
67
|
+
width: min(18rem, 100%);
|
|
68
|
+
box-sizing: border-box;
|
|
69
|
+
border-radius: 20px;
|
|
70
|
+
background: var(--mk-surface-1);
|
|
71
|
+
box-shadow: inset 0 0 0 1px var(--mk-outline-soft, rgb(0 0 0 / 0.08));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
[data-mk-color-panel-body] .mk-color-slider {
|
|
75
|
+
grid-template-columns: minmax(0, 1fr);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
[data-mk-color-row] {
|
|
79
|
+
display: flex;
|
|
80
|
+
gap: 0.5rem;
|
|
81
|
+
min-width: 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
[data-mk-color-row] > .mk-color-field {
|
|
85
|
+
flex: 1;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
[data-mk-color-eyedropper] {
|
|
89
|
+
display: grid;
|
|
90
|
+
flex: none;
|
|
91
|
+
place-items: center;
|
|
92
|
+
width: 2.75rem;
|
|
93
|
+
height: 2.75rem;
|
|
94
|
+
border: 0;
|
|
95
|
+
border-radius: 12px;
|
|
96
|
+
background: var(--mk-surface-3);
|
|
97
|
+
color: var(--mk-text);
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
[data-mk-color-swatches] {
|
|
102
|
+
display: grid;
|
|
103
|
+
grid-template-columns: repeat(8, minmax(0, 1fr));
|
|
104
|
+
gap: 0.4rem;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
[data-mk-color-preset] {
|
|
108
|
+
aspect-ratio: 1;
|
|
109
|
+
min-width: 0;
|
|
110
|
+
padding: 0;
|
|
111
|
+
border: 0;
|
|
112
|
+
cursor: pointer;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
[data-mk-color-preset][aria-pressed='true'] {
|
|
116
|
+
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mk-text) 22%, transparent), 0 0 0 2px var(--mk-surface-1), 0 0 0 4px var(--mk-text);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
[data-mk-color-preset]:focus-visible,
|
|
120
|
+
[data-mk-color-eyedropper]:focus-visible {
|
|
121
|
+
outline: 3px solid color-mix(in srgb, var(--mk-accent) 45%, transparent);
|
|
122
|
+
outline-offset: 2px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@media (prefers-reduced-motion: reduce) {
|
|
126
|
+
:is(.mk-color-picker, mk-color-picker) [data-mk-color-swatch],
|
|
127
|
+
[data-mk-color-preset] {
|
|
128
|
+
transition: none;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { MkElement, defineElement, type OptionType } from '../../elements/base';
|
|
2
|
+
import { createColorPicker, type ColorPickerInstance } from './engine';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* <mk-color-picker class="mk-color-picker" value="#3b82f6" label="Color del evento"></mk-color-picker>
|
|
6
|
+
* `inline` shows the panel in place; `swatches="#111,#ef4444"` sets the presets.
|
|
7
|
+
* Emits mk:input (live) and mk:change (committed) with {value, color}.
|
|
8
|
+
*/
|
|
9
|
+
export class MkColorPickerElement extends MkElement<ColorPickerInstance> {
|
|
10
|
+
static options: Record<string, OptionType> = {
|
|
11
|
+
value: 'string',
|
|
12
|
+
alpha: 'boolean',
|
|
13
|
+
format: 'string',
|
|
14
|
+
swatches: 'list',
|
|
15
|
+
label: 'string',
|
|
16
|
+
name: 'string',
|
|
17
|
+
disabled: 'boolean',
|
|
18
|
+
inline: 'boolean',
|
|
19
|
+
eyedropper: 'boolean',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
protected create(options: Record<string, unknown>) {
|
|
23
|
+
return createColorPicker(this, options);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
attributeChangedCallback(name: string, previous: string | null, next: string | null) {
|
|
27
|
+
if (previous === next || !this.instance) return;
|
|
28
|
+
if (name === 'value' && next) this.instance.setColor(next, false);
|
|
29
|
+
else super.attributeChangedCallback(name, previous, next);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
open() {
|
|
33
|
+
this.instance?.open();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
close() {
|
|
37
|
+
this.instance?.close();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get value() {
|
|
41
|
+
return this.instance?.value ?? '';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const defineColorPicker = () => defineElement('mk-color-picker', MkColorPickerElement);
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { gsap, EASE, registerMotion } from '../../core/gsap';
|
|
2
|
+
import { reduced } from '../../core/reduced';
|
|
3
|
+
import { createScope } from '../../core/scope';
|
|
4
|
+
import { inert, type Instance } from '../../core/types';
|
|
5
|
+
import { formatColor, sameColor, toHex, toHsva, type ColorFormat, type Hsva } from '../../core/color';
|
|
6
|
+
import { press, ringPulse, rollDigits } from '../../motion/micro';
|
|
7
|
+
import { flowInMenu } from '../../motion/entrances';
|
|
8
|
+
import { createDialog } from '../dialog/engine';
|
|
9
|
+
import { createColorArea } from '../color-area/engine';
|
|
10
|
+
import { createColorSlider } from '../color-slider/engine';
|
|
11
|
+
import { createColorField } from '../color-field/engine';
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* Color picker: a swatch button that grows into a panel (an anchored dialog,
|
|
15
|
+
* motion/morph.ts container transform; like a menu's options, its sections
|
|
16
|
+
* flow in while the surface grows) holding a color-area, a hue slider, an
|
|
17
|
+
* alpha slider (alpha: true), a color-field, preset swatches and an eyedropper
|
|
18
|
+
* where the browser has one. `inline` puts the panel in place, without button.
|
|
19
|
+
* One source of truth: whichever control changes, the others glide to the new
|
|
20
|
+
* colour (setColor(…, false)); the trigger swatch follows live and its hex
|
|
21
|
+
* label rolls on commit. Presets press, pop and mark themselves (aria-pressed).
|
|
22
|
+
* The children's mk:input / mk:change stop at the panel: listeners on the
|
|
23
|
+
* picker hear only the picker's own.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
export const DEFAULT_SWATCHES = ['#111111', '#6b7280', '#ef4444', '#f59e0b', '#22c55e', '#14b8a6', '#3b82f6', '#a855f7'];
|
|
27
|
+
|
|
28
|
+
export interface ColorPickerOptions {
|
|
29
|
+
value?: string | Hsva;
|
|
30
|
+
alpha?: boolean;
|
|
31
|
+
format?: ColorFormat;
|
|
32
|
+
swatches?: string[];
|
|
33
|
+
/** Accessible name; the trigger reads "<label>: <hex>". */
|
|
34
|
+
label?: string;
|
|
35
|
+
name?: string;
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
/** The panel in place, without a button or popover. */
|
|
38
|
+
inline?: boolean;
|
|
39
|
+
/** Eyedropper button where the browser has the EyeDropper API (default true). */
|
|
40
|
+
eyedropper?: boolean;
|
|
41
|
+
onInput?: (value: string, color: Hsva) => void;
|
|
42
|
+
onChange?: (value: string, color: Hsva) => void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ColorPickerInstance extends Instance {
|
|
46
|
+
open(): void;
|
|
47
|
+
close(): void;
|
|
48
|
+
setColor(color: string | Hsva, notify?: boolean): void;
|
|
49
|
+
readonly value: string;
|
|
50
|
+
readonly color: Hsva;
|
|
51
|
+
readonly isOpen: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const PIPETTE =
|
|
55
|
+
'<svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 4.5l5 5"/><path d="M17 2.5a2.1 2.1 0 0 1 3 3l-3 3-3-3z"/><path d="M14 6.5l-9.3 9.3a2 2 0 0 0-.5.9L3.5 20.5l3.8-.7a2 2 0 0 0 .9-.5L17.5 10"/></svg>';
|
|
56
|
+
|
|
57
|
+
interface EyeDropperLike {
|
|
58
|
+
open(): Promise<{ sRGBHex: string }>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const div = (attribute: string, className?: string) => {
|
|
62
|
+
const element = document.createElement('div');
|
|
63
|
+
element.setAttribute(attribute, '');
|
|
64
|
+
if (className) element.className = className;
|
|
65
|
+
return element;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export function createColorPicker(root: HTMLElement | null, options: ColorPickerOptions = {}): ColorPickerInstance {
|
|
69
|
+
if (!root) return inert({ open() {}, close() {}, setColor() {}, value: '', color: { h: 0, s: 0, v: 0, a: 1 }, isOpen: false });
|
|
70
|
+
registerMotion();
|
|
71
|
+
const scope = createScope();
|
|
72
|
+
const effects = new Set<gsap.core.Animation>();
|
|
73
|
+
const keep = (animation: gsap.core.Animation | null) => {
|
|
74
|
+
if (!animation) return;
|
|
75
|
+
effects.add(animation);
|
|
76
|
+
// Finished ones leave as new ones arrive: the animation's own onComplete stays untouched.
|
|
77
|
+
for (const effect of effects) if (effect.totalProgress() === 1) effects.delete(effect);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const alpha = Boolean(options.alpha);
|
|
81
|
+
const format: ColorFormat = options.format === 'rgb' || options.format === 'hsl' ? options.format : 'hex';
|
|
82
|
+
const label = options.label ?? 'Color';
|
|
83
|
+
const inline = Boolean(options.inline);
|
|
84
|
+
const swatches = options.swatches ?? DEFAULT_SWATCHES;
|
|
85
|
+
const opaque = (color: Hsva) => (alpha ? { ...color } : { ...color, a: 1 });
|
|
86
|
+
let current = opaque(toHsva(options.value ?? '#ff8800'));
|
|
87
|
+
|
|
88
|
+
const made: Element[] = [];
|
|
89
|
+
let trigger: HTMLButtonElement | null = null;
|
|
90
|
+
let triggerSwatch: HTMLElement | null = null;
|
|
91
|
+
let triggerLabel: HTMLElement | null = null;
|
|
92
|
+
let dialogElement: HTMLDialogElement | null = null;
|
|
93
|
+
if (!inline) {
|
|
94
|
+
trigger = document.createElement('button');
|
|
95
|
+
trigger.type = 'button';
|
|
96
|
+
trigger.dataset.mkColorTrigger = '';
|
|
97
|
+
trigger.setAttribute('aria-haspopup', 'dialog');
|
|
98
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
99
|
+
trigger.disabled = Boolean(options.disabled);
|
|
100
|
+
triggerSwatch = document.createElement('span');
|
|
101
|
+
triggerSwatch.dataset.mkColorSwatch = '';
|
|
102
|
+
triggerSwatch.setAttribute('aria-hidden', 'true');
|
|
103
|
+
triggerLabel = document.createElement('span');
|
|
104
|
+
triggerLabel.dataset.mkColorTriggerLabel = '';
|
|
105
|
+
triggerLabel.setAttribute('aria-hidden', 'true');
|
|
106
|
+
trigger.append(triggerSwatch, triggerLabel);
|
|
107
|
+
dialogElement = document.createElement('dialog');
|
|
108
|
+
// A class, not only an attribute: the copy that folds back into the swatch on close keeps classes only.
|
|
109
|
+
dialogElement.className = 'mk-dialog mk-color-panel';
|
|
110
|
+
dialogElement.dataset.mkColorPanel = '';
|
|
111
|
+
dialogElement.setAttribute('aria-label', label);
|
|
112
|
+
root.append(trigger, dialogElement);
|
|
113
|
+
made.push(trigger, dialogElement);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const body = div('data-mk-color-panel-body');
|
|
117
|
+
const areaHost = div('data-mk-color-area-host', 'mk-color-area');
|
|
118
|
+
const hueHost = div('data-mk-color-hue', 'mk-color-slider');
|
|
119
|
+
const alphaHost = alpha ? div('data-mk-color-alpha', 'mk-color-slider') : null;
|
|
120
|
+
const row = div('data-mk-color-row');
|
|
121
|
+
const fieldHost = div('data-mk-color-field-host', 'mk-color-field');
|
|
122
|
+
row.append(fieldHost);
|
|
123
|
+
let eyedropper: HTMLButtonElement | null = null;
|
|
124
|
+
const EyeDropper = typeof window !== 'undefined' ? (window as unknown as { EyeDropper?: new () => EyeDropperLike }).EyeDropper : undefined;
|
|
125
|
+
if (options.eyedropper !== false && typeof EyeDropper === 'function') {
|
|
126
|
+
eyedropper = document.createElement('button');
|
|
127
|
+
eyedropper.type = 'button';
|
|
128
|
+
eyedropper.dataset.mkColorEyedropper = '';
|
|
129
|
+
eyedropper.setAttribute('aria-label', 'Tomar un color de la pantalla');
|
|
130
|
+
eyedropper.innerHTML = PIPETTE;
|
|
131
|
+
eyedropper.disabled = Boolean(options.disabled);
|
|
132
|
+
row.append(eyedropper);
|
|
133
|
+
}
|
|
134
|
+
const presetsHost = div('data-mk-color-swatches');
|
|
135
|
+
presetsHost.setAttribute('role', 'group');
|
|
136
|
+
presetsHost.setAttribute('aria-label', 'Colores guardados');
|
|
137
|
+
const presets = swatches.map((swatch, index) => {
|
|
138
|
+
const button = document.createElement('button');
|
|
139
|
+
button.type = 'button';
|
|
140
|
+
button.dataset.mkColorPreset = '';
|
|
141
|
+
button.dataset.mkIndex = String(index);
|
|
142
|
+
button.setAttribute('aria-label', swatch);
|
|
143
|
+
button.setAttribute('aria-pressed', 'false');
|
|
144
|
+
button.disabled = Boolean(options.disabled);
|
|
145
|
+
button.style.setProperty('--mk-color-swatch', formatColor(toHsva(swatch), 'rgb'));
|
|
146
|
+
presetsHost.append(button);
|
|
147
|
+
return button;
|
|
148
|
+
});
|
|
149
|
+
body.append(areaHost, hueHost, ...(alphaHost ? [alphaHost] : []), row);
|
|
150
|
+
if (presets.length) body.append(presetsHost);
|
|
151
|
+
if (dialogElement) dialogElement.append(body);
|
|
152
|
+
else {
|
|
153
|
+
root.append(body);
|
|
154
|
+
made.push(body);
|
|
155
|
+
}
|
|
156
|
+
let hidden: HTMLInputElement | null = null;
|
|
157
|
+
if (options.name) {
|
|
158
|
+
hidden = document.createElement('input');
|
|
159
|
+
hidden.type = 'hidden';
|
|
160
|
+
hidden.name = options.name;
|
|
161
|
+
root.append(hidden);
|
|
162
|
+
made.push(hidden);
|
|
163
|
+
}
|
|
164
|
+
scope.add(() => made.forEach((node) => node.remove()));
|
|
165
|
+
if (inline) scope.attr(root, 'data-mk-inline', '');
|
|
166
|
+
scope.attr(root, 'data-mk-ready', '');
|
|
167
|
+
// Listeners on the picker hear the picker, not its parts.
|
|
168
|
+
for (const type of ['mk:input', 'mk:change']) scope.on(body, type, (event) => event.stopPropagation());
|
|
169
|
+
|
|
170
|
+
const emit = (type: 'input' | 'change') => {
|
|
171
|
+
const value = toHex(current);
|
|
172
|
+
(type === 'input' ? options.onInput : options.onChange)?.(value, { ...current });
|
|
173
|
+
root.dispatchEvent(new CustomEvent(`mk:${type}`, { bubbles: true, detail: { value, color: { ...current } } }));
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const paintTrigger = (commit: boolean) => {
|
|
177
|
+
if (hidden) hidden.value = toHex(current);
|
|
178
|
+
if (!trigger || !triggerSwatch || !triggerLabel) return;
|
|
179
|
+
const hex = toHex(current);
|
|
180
|
+
triggerSwatch.style.setProperty('--mk-color-swatch', formatColor(current, 'rgb'));
|
|
181
|
+
trigger.setAttribute('aria-label', `${label}: ${hex}`);
|
|
182
|
+
if (commit && !reduced() && triggerLabel.textContent) keep(rollDigits(triggerLabel, hex, 1, 0.28));
|
|
183
|
+
else if (commit || !triggerLabel.textContent) triggerLabel.textContent = hex;
|
|
184
|
+
};
|
|
185
|
+
const markPresets = () => {
|
|
186
|
+
for (const preset of presets) {
|
|
187
|
+
const on = sameColor(opaque(toHsva(preset.getAttribute('aria-label'))), current);
|
|
188
|
+
preset.setAttribute('aria-pressed', String(on));
|
|
189
|
+
preset.toggleAttribute('data-mk-checked', on);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
type Child = { setColor(color: Hsva, notify?: boolean): void; destroy(): void };
|
|
194
|
+
const children: Child[] = [];
|
|
195
|
+
const update = (next: Hsva, source: Child | null, commit: boolean, notify = true) => {
|
|
196
|
+
if (scope.disposed) return;
|
|
197
|
+
current = opaque(next);
|
|
198
|
+
for (const child of children) if (child !== source) child.setColor(current, false);
|
|
199
|
+
paintTrigger(commit);
|
|
200
|
+
markPresets();
|
|
201
|
+
if (!notify) return;
|
|
202
|
+
emit('input');
|
|
203
|
+
if (commit) emit('change');
|
|
204
|
+
};
|
|
205
|
+
const area: Child = createColorArea(areaHost, {
|
|
206
|
+
value: current,
|
|
207
|
+
label,
|
|
208
|
+
disabled: options.disabled,
|
|
209
|
+
onInput: (_, color) => update(color, area, false),
|
|
210
|
+
onChange: (_, color) => update(color, area, true),
|
|
211
|
+
});
|
|
212
|
+
const hue: Child = createColorSlider(hueHost, {
|
|
213
|
+
channel: 'hue',
|
|
214
|
+
value: current,
|
|
215
|
+
disabled: options.disabled,
|
|
216
|
+
onInput: (_, color) => update(color, hue, false),
|
|
217
|
+
onChange: (_, color) => update(color, hue, true),
|
|
218
|
+
});
|
|
219
|
+
const opacity: Child | null = alphaHost
|
|
220
|
+
? createColorSlider(alphaHost, {
|
|
221
|
+
channel: 'alpha',
|
|
222
|
+
value: current,
|
|
223
|
+
disabled: options.disabled,
|
|
224
|
+
onInput: (_, color) => update(color, opacity, false),
|
|
225
|
+
onChange: (_, color) => update(color, opacity, true),
|
|
226
|
+
})
|
|
227
|
+
: null;
|
|
228
|
+
const field: Child = createColorField(fieldHost, {
|
|
229
|
+
value: current,
|
|
230
|
+
format,
|
|
231
|
+
alpha,
|
|
232
|
+
label: 'Código de color',
|
|
233
|
+
disabled: options.disabled,
|
|
234
|
+
onChange: (_, color) => update(color, field, true),
|
|
235
|
+
});
|
|
236
|
+
children.push(area, hue, ...(opacity ? [opacity] : []), field);
|
|
237
|
+
scope.add(() => children.forEach((child) => child.destroy()));
|
|
238
|
+
paintTrigger(true);
|
|
239
|
+
markPresets();
|
|
240
|
+
|
|
241
|
+
scope.on(presetsHost, 'click', (event) => {
|
|
242
|
+
const preset = (event.target as Element | null)?.closest<HTMLButtonElement>('[data-mk-color-preset]');
|
|
243
|
+
if (!preset || options.disabled) return;
|
|
244
|
+
keep(press(preset));
|
|
245
|
+
update(toHsva(preset.getAttribute('aria-label'), current), null, true);
|
|
246
|
+
if (!reduced()) keep(gsap.fromTo(preset, { scale: 0.85 }, { scale: 1, duration: 0.3, ease: EASE.pop, clearProps: 'scale,transform' }));
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
if (eyedropper && EyeDropper) {
|
|
250
|
+
scope.on(eyedropper, 'click', () => {
|
|
251
|
+
keep(press(eyedropper));
|
|
252
|
+
new EyeDropper()
|
|
253
|
+
.open()
|
|
254
|
+
.then(({ sRGBHex }) => {
|
|
255
|
+
if (scope.disposed) return;
|
|
256
|
+
update(toHsva(sRGBHex, current), null, true);
|
|
257
|
+
keep(ringPulse(triggerSwatch ?? areaHost));
|
|
258
|
+
})
|
|
259
|
+
// Escape or a refused permission: nothing changes.
|
|
260
|
+
.catch(() => {});
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const panel = dialogElement
|
|
265
|
+
? createDialog(dialogElement, {
|
|
266
|
+
placement: 'anchor',
|
|
267
|
+
backdrop: false,
|
|
268
|
+
drag: false,
|
|
269
|
+
autoResize: false,
|
|
270
|
+
triggers: false,
|
|
271
|
+
animateContent: false,
|
|
272
|
+
// Like a menu's options: the area, the sliders, the field and the swatches flow in while the surface grows.
|
|
273
|
+
onOpen: () => keep(flowInMenu([...body.children])),
|
|
274
|
+
onClose: () => trigger?.setAttribute('aria-expanded', 'false'),
|
|
275
|
+
})
|
|
276
|
+
: null;
|
|
277
|
+
if (panel) scope.add(() => panel.destroy());
|
|
278
|
+
const open = () => {
|
|
279
|
+
if (!panel || !trigger || options.disabled || panel.isOpen) return;
|
|
280
|
+
panel.open(trigger);
|
|
281
|
+
trigger.setAttribute('aria-expanded', 'true');
|
|
282
|
+
};
|
|
283
|
+
if (trigger && panel) {
|
|
284
|
+
scope.on(trigger, 'click', () => {
|
|
285
|
+
if (panel.isOpen) panel.close();
|
|
286
|
+
else open();
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
scope.add(() => {
|
|
290
|
+
for (const effect of effects) effect.kill();
|
|
291
|
+
effects.clear();
|
|
292
|
+
gsap.killTweensOf(presets);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
open,
|
|
297
|
+
close: () => panel?.close(),
|
|
298
|
+
setColor(next, notify = true) {
|
|
299
|
+
const target = opaque(toHsva(next, current));
|
|
300
|
+
if (sameColor(target, current) && target.h === current.h) return;
|
|
301
|
+
update(target, null, true, notify);
|
|
302
|
+
},
|
|
303
|
+
get value() {
|
|
304
|
+
return toHex(current);
|
|
305
|
+
},
|
|
306
|
+
get color() {
|
|
307
|
+
return { ...current };
|
|
308
|
+
},
|
|
309
|
+
get isOpen() {
|
|
310
|
+
return panel?.isOpen ?? false;
|
|
311
|
+
},
|
|
312
|
+
destroy: () => scope.dispose(),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useRef, type HTMLAttributes } from 'react';
|
|
3
|
+
import { useIsomorphicLayoutEffect, useLatest } from '../../react/use-recipe';
|
|
4
|
+
import { toHex, toHsva } from '../../core/color';
|
|
5
|
+
import { createColorPicker, type ColorPickerInstance, type ColorPickerOptions } from './engine';
|
|
6
|
+
|
|
7
|
+
export interface ColorPickerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onInput' | 'onChange' | 'defaultValue'>, Omit<ColorPickerOptions, 'value'> {
|
|
8
|
+
/** Controlled colour; without it the picker keeps its own (defaultValue). */
|
|
9
|
+
value?: string;
|
|
10
|
+
defaultValue?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** <ColorPicker value={color} onInput={setColor} alpha /> or <ColorPicker inline … />. */
|
|
14
|
+
export function ColorPicker({ value, defaultValue, alpha, format, swatches, label, name, disabled, inline, eyedropper, onInput, onChange, className, ...props }: ColorPickerProps) {
|
|
15
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
16
|
+
const instance = useRef<ColorPickerInstance | null>(null);
|
|
17
|
+
const input = useLatest(onInput);
|
|
18
|
+
const change = useLatest(onChange);
|
|
19
|
+
const start = useRef(value ?? defaultValue);
|
|
20
|
+
const key = JSON.stringify(swatches ?? null);
|
|
21
|
+
useIsomorphicLayoutEffect(() => {
|
|
22
|
+
const created = createColorPicker(ref.current, {
|
|
23
|
+
value: value ?? start.current,
|
|
24
|
+
alpha,
|
|
25
|
+
format,
|
|
26
|
+
swatches,
|
|
27
|
+
label,
|
|
28
|
+
name,
|
|
29
|
+
disabled,
|
|
30
|
+
inline,
|
|
31
|
+
eyedropper,
|
|
32
|
+
onInput: (hex, color) => input.current?.(hex, color),
|
|
33
|
+
onChange: (hex, color) => change.current?.(hex, color),
|
|
34
|
+
});
|
|
35
|
+
instance.current = created;
|
|
36
|
+
return () => {
|
|
37
|
+
start.current = created.value;
|
|
38
|
+
created.destroy();
|
|
39
|
+
instance.current = null;
|
|
40
|
+
};
|
|
41
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
42
|
+
}, [alpha, format, key, label, name, disabled, inline, eyedropper]);
|
|
43
|
+
useIsomorphicLayoutEffect(() => {
|
|
44
|
+
if (value !== undefined && instance.current && instance.current.value !== toHex(toHsva(value))) instance.current.setColor(value, false);
|
|
45
|
+
}, [value]);
|
|
46
|
+
return <div {...props} ref={ref} className={['mk-color-picker', className].filter(Boolean).join(' ')} />;
|
|
47
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# color-slider
|
|
2
|
+
|
|
3
|
+
Deslizador de un canal de color (tono, saturación, brillo, luminosidad, rojo, verde, azul u opacidad) sobre un `<input type="range">` nativo: teclado, táctil y formularios vienen de la plataforma. El motor pinta la pista con el degradado de ese canal para el color actual (la opacidad sobre un damero) y un pulgar redondo relleno del color.
|
|
4
|
+
|
|
5
|
+
Origen: línea Melon Mind. El pulgar se desliza 0,35 s con la curva swing (`.38,.49,0,1.5`) al usar el teclado o `setColor`, y sigue al puntero en 0,1 s al arrastrar. Al agarrarlo crece (curva click `.37,1.42,.37,1`) y aparece encima una lupa con el color (curva pop); al soltar, la lupa se desvanece con blur. El valor mostrado rueda.
|
|
6
|
+
|
|
7
|
+
## HTML / Astro
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<mk-color-slider class="mk-color-slider" channel="hue" value="#ff8800" show-value></mk-color-slider>
|
|
11
|
+
<script>
|
|
12
|
+
import { defineElements } from '@yewdiel21/motion-kit/elements';
|
|
13
|
+
defineElements(['mk-color-slider']);
|
|
14
|
+
</script>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## React
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
const [color, setColor] = useState('#ff8800');
|
|
21
|
+
<ColorSlider channel="hue" value={color} onInput={setColor} showValue />
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Con `value` es controlado; con `defaultValue` guarda su propio color.
|
|
25
|
+
|
|
26
|
+
## Opciones
|
|
27
|
+
|
|
28
|
+
| Opción | Atributo | Por defecto | Qué hace |
|
|
29
|
+
|---|---|---|---|
|
|
30
|
+
| `channel` | `channel` | `'hue'` | Canal: `hue`, `saturation`, `brightness`, `lightness`, `red`, `green`, `blue`, `alpha`. |
|
|
31
|
+
| `value` | `value` | `'hsl(0 100% 50%)'` | Color de partida: hex, `rgb()`, `hsl()` o un objeto HSVA. |
|
|
32
|
+
| `label` | `label` | nombre del canal | Nombre accesible (Tono, Saturación, Brillo, Luminosidad, Rojo, Verde, Azul, Opacidad). |
|
|
33
|
+
| `orientation` | `orientation` | `'horizontal'` | `vertical` pone la pista de pie (abajo es el mínimo). |
|
|
34
|
+
| `step` | `step` | `1` (opacidad `0.01`) | Paso del input. |
|
|
35
|
+
| `showValue` | `show-value` | `false` | Muestra el valor («210°», «64 %», «136») en un `<output>`. |
|
|
36
|
+
| `name` | `name` | — | Un input oculto envía el hex con el formulario. |
|
|
37
|
+
| `disabled` | `disabled` | `false` | Desactiva el input. |
|
|
38
|
+
| `onInput(hex, hsva)` | — | — | Cada movimiento. |
|
|
39
|
+
| `onChange(hex, hsva)` | — | — | Valor confirmado (al soltar o con una tecla). |
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
`setColor(color, notify = true)` cambia el color (otro control lo movió; con `notify=false` no llama a los callbacks), `value` (hex, `#rrggbbaa` si es translúcido), `color` (copia HSVA), `destroy()`.
|
|
44
|
+
|
|
45
|
+
## Eventos
|
|
46
|
+
|
|
47
|
+
`mk:input` y `mk:change` con `{ value, color }`.
|
|
48
|
+
|
|
49
|
+
## Variables CSS
|
|
50
|
+
|
|
51
|
+
`--mk-color-size` (1.75rem, alto de la pista y del pulgar), `--mk-color-length` (12rem, alto en vertical), `--mk-color-checker` (damero bajo los colores translúcidos). El motor escribe `--mk-color-track`, `--mk-color-thumb` y `--mk-color-pos`.
|
|
52
|
+
|
|
53
|
+
## Accesibilidad
|
|
54
|
+
|
|
55
|
+
Es un input range nativo con `aria-valuetext` legible («210°», «64 %») y `aria-orientation`. Con movimiento reducido no hay escalas ni deslizamientos: el pulgar salta a su sitio y la lupa aparece sin animar mientras se arrastra. Deja unos 3,5 rem libres encima para que la lupa no se corte.
|