@duboseweb/motus 1.0.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.
@@ -0,0 +1,2 @@
1
+ /*! dwg-motus | MIT License | https://github.com/dubose-web/dwg-motus */
2
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Motus=t()}(this,function(){"use strict";const e="data-motus",t="data-motus-inactive",n="motus-ready",o="--motus-duration",s="--motus-delay",a="--motus-easing",r="[dwg-motus]",i=Object.freeze({sm:576,md:768,lg:992,xl:1200,xxl:1400}),c=["sm","md","lg","xl","xxl"],u=Object.freeze({offset:120,delay:0,easing:"ease",duration:400,disable:"lg",breakpoints:i,once:!1,mirror:!1,anchorPlacement:"top-bottom",startEvent:"DOMContentLoaded",animatedClassName:"motus-animate",initClassName:"motus-init",useClassNames:!1,disableMutationObserver:!1,debounceDelay:50}),d=["top-bottom","top-center","top-top","center-bottom","center-center","center-top","bottom-bottom","bottom-center","bottom-top"];const l=()=>matchMedia("(pointer: coarse) and (hover: none) and (max-width: 767px)").matches,m=()=>matchMedia("(pointer: coarse) and (hover: none)").matches,b={"ease-in-back":"cubic-bezier(.6, -.28, .735, .045)","ease-out-back":"cubic-bezier(.175, .885, .32, 1.275)","ease-in-out-back":"cubic-bezier(.68, -.55, .265, 1.55)","ease-in-sine":"cubic-bezier(.47, 0, .745, .715)","ease-out-sine":"cubic-bezier(.39, .575, .565, 1)","ease-in-out-sine":"cubic-bezier(.445, .05, .55, .95)","ease-in-quad":"cubic-bezier(.55, .085, .68, .53)","ease-out-quad":"cubic-bezier(.25, .46, .45, .94)","ease-in-out-quad":"cubic-bezier(.455, .03, .515, .955)","ease-in-cubic":"cubic-bezier(.55, .055, .675, .19)","ease-out-cubic":"cubic-bezier(.215, .61, .355, 1)","ease-in-out-cubic":"cubic-bezier(.645, .045, .355, 1)","ease-in-quart":"cubic-bezier(.895, .03, .685, .22)","ease-out-quart":"cubic-bezier(.165, .84, .44, 1)","ease-in-out-quart":"cubic-bezier(.77, 0, .175, 1)"},f=e=>{var t;return null!==(t=b[e])&&void 0!==t?t:e},p=(e,t)=>{for(const n of t)e.classList.add(n)},v=(e,t)=>{for(const n of t)e.classList.remove(n)},h=(e,t,n)=>{const o={node:t};document.dispatchEvent(new CustomEvent(e,{detail:o})),n&&document.dispatchEvent(new CustomEvent(`${e}:${n}`,{detail:o}))},y=[o,s,a],g=e=>{if(e)for(const t of y)e.style.removeProperty(t)},w=e=>g(e);let $=new WeakMap;const E=(e,t)=>{$.set(e,t)},x=(e,t)=>t?e.classList.contains(t):!0===$.get(e);function N(t,n,o){const s=t.getAttribute((t=>`${e}-${t}`)(n));return"true"===s||"false"!==s&&(null!=s?s:o)}const M=(e,t)=>{const n=N(e,t);return"string"==typeof n?n:void 0},C=(e,t)=>{var n;const o=M(e,"anchor");if(!o)return e;if(t.has(o))return null!==(n=t.get(o))&&void 0!==n?n:e;let s=null;try{s=document.querySelector(o)}catch(e){console.warn(`${r} Invalid data-motus-anchor selector: ${o}`)}return t.set(o,s),null!=s?s:e},k=(t,n)=>{const r=new Map,i=n.animatedClassName?[n.animatedClassName]:[];return t.map(t=>{var c,u;const d=Boolean(N(t,"mirror",n.mirror)),l=Boolean(N(t,"once",n.once)),m=null!==(c=M(t,"id"))&&void 0!==c?c:null,b=null!==(u=M(t,"anchor-placement"))&&void 0!==u?u:n.anchorPlacement,p=Number(N(t,"offset",n.offset)),v=Number.isFinite(p)?p:n.offset;var h,y;h=t,(y={duration:M(t,"duration"),delay:M(t,"delay"),easing:M(t,"easing")}).duration&&h.style.setProperty(o,`${y.duration}ms`),y.delay&&h.style.setProperty(s,`${y.delay}ms`),y.easing&&h.style.setProperty(a,f(y.easing)),n.initClassName&&t.classList.add(n.initClassName);const g=n.useClassNames?t.getAttribute(e):null,w=g?i.concat(g.split(" ").filter(e=>""!==e)):i;return{node:t,observeTarget:C(t,r),mirror:d,once:l,id:m,animatedClassNames:w,animated:x(t,n.animatedClassName),anchorPlacement:b,offset:v}})},z=(e,t,n=window.innerHeight)=>{switch(e){case"top-center":case"center-center":case"bottom-center":{const e=Math.max(Math.round(n/2)-t,1);return`${-e}px 0px ${-e}px 0px`}case"top-top":case"center-top":case"bottom-top":return`${Math.max(t,1)}px 0px ${-(n-t)}px 0px`;default:return`0px 0px ${-t}px 0px`}},O=e=>{switch(e){case"center-bottom":case"center-center":case"center-top":return.5;default:return 0}},P=t=>{let n=!1;const o=new MutationObserver(o=>{if(n)return;o.some(t=>(t=>{for(const n of t){if(n.nodeType!==Node.ELEMENT_NODE)continue;const t=n;if(t.hasAttribute(e)||t.querySelector(`[${e}]`))return!0}return!1})(t.addedNodes))&&(n=!0,requestAnimationFrame(()=>{n=!1,t()}))});return o.observe(document.documentElement,{childList:!0,subtree:!0}),o},L=[...c,"phone","tablet","mobile"],q=e=>"number"==typeof e&&Number.isFinite(e)&&e>=0;let A=[],j=null,D=null,T=[],S=!1,I=null,F=Object.assign({},u);const U=(e,t,n)=>{e.addEventListener(t,n),T.push({target:e,event:t,fn:n})},H=()=>[...document.querySelectorAll(`[${e}]`)],B=e=>{const{disable:t}=e;return document.documentElement.hasAttribute("data-motus-disabled")||!0===t||"string"==typeof t&&t in e.breakpoints&&(n=e.breakpoints[t],matchMedia(`(max-width: ${n-.02}px)`).matches)||"mobile"===t&&m()||"phone"===t&&l()||"tablet"===t&&m()&&!l()||"function"==typeof t&&!0===t();var n},R=()=>{S&&(I=window.innerHeight,A=H(),null==j||j.disconnect(),j=((e,t=window.innerHeight)=>{let n=!1;const o=new Map,s=(e,t)=>{const n=t.targets.get(e.target);if(n){for(const t of n)e.isIntersecting?t.animated||(p(t.node,t.animatedClassNames),h("motus:in",t.node,t.id),t.animated=!0,E(t.node,!0)):t.animated&&t.mirror&&!t.once&&(v(t.node,t.animatedClassNames),h("motus:out",t.node,t.id),t.animated=!1,E(t.node,!1));n.every(e=>e.once&&e.animated)&&t.observer.unobserve(e.target)}};for(const a of e){if(a.once&&a.animated)continue;const e=`${a.anchorPlacement}-${a.offset}`;let r=o.get(e);if(!r){const i=new Map,c=new IntersectionObserver(e=>{if(n)for(const t of e)s(t,r);else r.buffered.push(...e)},{rootMargin:z(a.anchorPlacement,a.offset,t),threshold:O(a.anchorPlacement)});r={observer:c,targets:i,buffered:[]},o.set(e,r)}const i=r.targets.get(a.observeTarget);i?i.push(a):(r.targets.set(a.observeTarget,[a]),r.observer.observe(a.observeTarget))}return{disconnect:()=>{for(const e of o.values())e.observer.disconnect();o.clear()},activate:()=>{n=!0;for(const e of o.values()){const t=e.buffered.concat(e.observer.takeRecords());e.buffered.length=0;for(const n of t)s(n,e)}}}})(k(A,F),I),document.body.classList.contains(n)?null==j||j.activate():requestAnimationFrame(()=>{requestAnimationFrame(()=>{document.body.classList.add(n),null==j||j.activate()})}))},W=()=>{S=!0,R()},_=()=>{S&&I!==window.innerHeight&&R()},G=()=>{B(F)?J():S?(document.documentElement.removeAttribute(t),R()):Q(F)},J=()=>{var e;document.documentElement.setAttribute(t,""),null==D||D.disconnect(),D=null,null==j||j.disconnect(),j=null,null===(e=document.body)||void 0===e||e.classList.remove(n);for(const e of A)w(e),F.initClassName&&e.classList.remove(F.initClassName),F.animatedClassName&&e.classList.remove(F.animatedClassName);$=new WeakMap},K=()=>{J();for(const{target:e,event:t,fn:n}of T)e.removeEventListener(t,n);T=[],g(document.body),A=[],S=!1,I=null},Q=e=>(S&&K(),F=((e={})=>{const t=[];for(const n of Object.keys(e))n in u||t.push(`Unknown option "${n}".`);const n=Object.assign({},u,e);for(const e of["duration","delay","offset"])q(n[e])||(t.push(`"${e}" must be a non-negative number, received ${String(n[e])}. Using ${u[e]}.`),n[e]=u[e]);d.includes(n.anchorPlacement)||(t.push(`"anchorPlacement" must be one of ${d.join(", ")}. Using ${u.anchorPlacement}.`),n.anchorPlacement=u.anchorPlacement),"string"!=typeof n.disable||L.includes(n.disable)||(t.push(`"disable" must be a boolean, a function, or one of ${L.join(", ")}. Using ${String(u.disable)}.`),n.disable=u.disable),n.breakpoints=Object.assign({},u.breakpoints,e.breakpoints);for(const e of c){const o=n.breakpoints[e];("number"!=typeof o||!Number.isFinite(o)||o<=0)&&(t.push(`"breakpoints.${e}" must be a positive number, received ${String(o)}. Using ${u.breakpoints[e]}.`),n.breakpoints[e]=u.breakpoints[e])}"string"==typeof n.startEvent&&""!==n.startEvent||(t.push(`"startEvent" must be a non-empty string. Using ${u.startEvent}.`),n.startEvent=u.startEvent);const o=n.debounceDelay,s=Number.isFinite(o)?Math.min(500,Math.max(16,o)):u.debounceDelay;return s!==o&&t.push(`"debounceDelay" clamped from ${String(o)} to ${s} (allowed range 16–500ms).`),n.debounceDelay=s,t.length>0&&console.warn(`${r} Invalid options:\n - ${t.join("\n - ")}`),n})(e),document.documentElement.removeAttribute(t),"undefined"!=typeof window&&"function"==typeof window.IntersectionObserver&&"function"==typeof window.IntersectionObserverEntry&&"intersectionRatio"in window.IntersectionObserverEntry.prototype?(A=H(),B(F)?void J():(F.disableMutationObserver||(D=P(G)),(e=>{const{body:t}=document;t&&(t.style.setProperty(o,`${e.duration}ms`),t.style.setProperty(s,`${e.delay}ms`),t.style.setProperty(a,f(e.easing)))})(F),"DOMContentLoaded"===F.startEvent||"load"===F.startEvent?U(window,"load",()=>{S||W()}):U(document,F.startEvent,()=>W()),"DOMContentLoaded"!==F.startEvent||"complete"!==document.readyState&&"interactive"!==document.readyState||W(),U(window,"resize",function(e,t){let n;return(...o)=>{clearTimeout(n),n=setTimeout(()=>e(...o),t)}}(_,F.debounceDelay)),A)):(console.warn(`${r} IntersectionObserver is not supported in this browser; animations are disabled.`),void document.documentElement.setAttribute(t,"")));return Object.freeze({init:Q,refresh:()=>R(),refreshHard:G,destroy:K})});
package/package.json ADDED
@@ -0,0 +1,115 @@
1
+ {
2
+ "name": "@duboseweb/motus",
3
+ "version": "1.0.0",
4
+ "description": "Animate on scroll via IntersectionObserver — modular, typed, zero dependencies",
5
+ "author": "DuBose Web",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/dubose-web/dwg-motus.git"
10
+ },
11
+ "homepage": "https://github.com/dubose-web/dwg-motus#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/dubose-web/dwg-motus/issues"
14
+ },
15
+ "keywords": [
16
+ "animate on scroll",
17
+ "scroll animation",
18
+ "intersectionobserver",
19
+ "motus",
20
+ "css animation",
21
+ "reveal"
22
+ ],
23
+ "type": "module",
24
+ "sideEffects": [
25
+ "**/*.css",
26
+ "**/*.scss"
27
+ ],
28
+ "engines": {
29
+ "node": ">=20.19"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "scss",
37
+ "README.md",
38
+ "CUSTOMIZATION.md",
39
+ "LICENSE"
40
+ ],
41
+ "main": "./dist/motus.cjs",
42
+ "module": "./dist/motus.js",
43
+ "types": "./dist/motus.d.ts",
44
+ "unpkg": "./dist/motus.umd.js",
45
+ "jsdelivr": "./dist/motus.umd.js",
46
+ "exports": {
47
+ ".": {
48
+ "types": {
49
+ "import": "./dist/motus.d.ts",
50
+ "require": "./dist/motus.d.cts"
51
+ },
52
+ "import": "./dist/motus.js",
53
+ "require": "./dist/motus.cjs"
54
+ },
55
+ "./motus.css": "./dist/css/motus.css",
56
+ "./css/*.css": "./dist/css/*.css",
57
+ "./scss/*.scss": "./scss/*.scss",
58
+ "./scss/*": "./scss/*",
59
+ "./dist/*": "./dist/*",
60
+ "./package.json": "./package.json",
61
+ "./scss": "./scss/motus.scss"
62
+ },
63
+ "scripts": {
64
+ "dev": "NODE_ENV=development npm-run-all2 build:css --parallel dev:css dev:js",
65
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
66
+ "build": "npm-run-all2 clean build:js build:css",
67
+ "build:js": "rollup -c",
68
+ "build:css": "node scripts/build-css.mjs",
69
+ "test": "vitest run",
70
+ "test:watch": "vitest",
71
+ "test:coverage": "vitest run --coverage",
72
+ "lint": "eslint src test && prettier --check .",
73
+ "format": "prettier --write .",
74
+ "typecheck": "tsc --noEmit",
75
+ "prepublishOnly": "npm run lint && npm run typecheck && npm test && npm run build && npm run check:pkg && npm run test:pack -- --no-build",
76
+ "check:pkg": "publint && attw --pack . --profile node16 --entrypoints .",
77
+ "dev:js": "NODE_ENV=development rollup -c --watch",
78
+ "dev:css": "NODE_ENV=development node scripts/build-css.mjs --watch",
79
+ "test:pack": "node scripts/smoke-package.mjs"
80
+ },
81
+ "devDependencies": {
82
+ "@arethetypeswrong/cli": "^0.18.5",
83
+ "@eslint/js": "^10.0.1",
84
+ "@rollup/plugin-terser": "^1.0.0",
85
+ "@rollup/plugin-typescript": "^12.3.0",
86
+ "@vitest/coverage-v8": "^4.1.11",
87
+ "autoprefixer": "^10.6.1",
88
+ "cssnano": "^7.1.9",
89
+ "eslint": "^10.11.0",
90
+ "eslint-config-prettier": "^10.1.8",
91
+ "happy-dom": "^20.14.5",
92
+ "npm-run-all2": "^8.0.4",
93
+ "postcss": "^8.5.28",
94
+ "prettier": "^3.9.8",
95
+ "publint": "^0.3.24",
96
+ "rollup": "^4.63.4",
97
+ "rollup-plugin-dts": "^6.5.1",
98
+ "rollup-plugin-livereload": "^2.0.5",
99
+ "rollup-plugin-serve": "^3.0.0",
100
+ "sass": "^1.104.1",
101
+ "tslib": "^2.8.1",
102
+ "typescript": "^5.9.3",
103
+ "typescript-eslint": "^8.70.0",
104
+ "vitest": "^4.1.11"
105
+ },
106
+ "style": "./dist/css/motus.css",
107
+ "sass": "./scss/motus.scss",
108
+ "browserslist": [
109
+ "chrome >= 51",
110
+ "firefox >= 55",
111
+ "safari >= 12.1",
112
+ "edge >= 79",
113
+ "not dead"
114
+ ]
115
+ }
@@ -0,0 +1,60 @@
1
+ @use '../config' as *;
2
+
3
+ /// fade, fade-in
4
+ /// fade-up, fade-down, fade-left, fade-right
5
+ /// fade-up-right, fade-up-left, fade-down-right, fade-down-left
6
+
7
+ @media screen and (prefers-reduced-motion: no-preference) {
8
+ html:not(.no-js):not([data-motus-disabled]):not([data-motus-inactive]) {
9
+ // The selector is doubled on purpose: it raises specificity so the family
10
+ // base rule outranks a single-attribute override from consuming CSS.
11
+ [data-motus^='fade'][data-motus^='fade'] {
12
+ opacity: 0;
13
+ transition-property: opacity, transform;
14
+
15
+ &.motus-animate {
16
+ opacity: 1;
17
+ transform: none;
18
+ }
19
+ }
20
+
21
+ // Declared explicitly rather than relying on the prefix rule above, so a
22
+ // plain opacity fade is a real, greppable animation.
23
+ [data-motus='fade'],
24
+ [data-motus='fade-in'] {
25
+ transform: none;
26
+ }
27
+
28
+ [data-motus='fade-up'] {
29
+ transform: translate3d(0, $motus-distance, 0);
30
+ }
31
+
32
+ [data-motus='fade-down'] {
33
+ transform: translate3d(0, -$motus-distance, 0);
34
+ }
35
+
36
+ [data-motus='fade-right'] {
37
+ transform: translate3d(-$motus-distance, 0, 0);
38
+ }
39
+
40
+ [data-motus='fade-left'] {
41
+ transform: translate3d($motus-distance, 0, 0);
42
+ }
43
+
44
+ [data-motus='fade-up-right'] {
45
+ transform: translate3d(-$motus-distance, $motus-distance, 0);
46
+ }
47
+
48
+ [data-motus='fade-up-left'] {
49
+ transform: translate3d($motus-distance, $motus-distance, 0);
50
+ }
51
+
52
+ [data-motus='fade-down-right'] {
53
+ transform: translate3d(-$motus-distance, -$motus-distance, 0);
54
+ }
55
+
56
+ [data-motus='fade-down-left'] {
57
+ transform: translate3d($motus-distance, -$motus-distance, 0);
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,42 @@
1
+ /// flip-left, flip-right, flip-up, flip-down
2
+
3
+ @media screen and (prefers-reduced-motion: no-preference) {
4
+ html:not(.no-js):not([data-motus-disabled]):not([data-motus-inactive]) {
5
+ [data-motus^='flip'][data-motus^='flip'] {
6
+ backface-visibility: hidden;
7
+ transition-property: transform;
8
+ }
9
+
10
+ [data-motus='flip-left'] {
11
+ transform: perspective(2500px) rotateY(-100deg);
12
+
13
+ &.motus-animate {
14
+ transform: perspective(2500px) rotateY(0);
15
+ }
16
+ }
17
+
18
+ [data-motus='flip-right'] {
19
+ transform: perspective(2500px) rotateY(100deg);
20
+
21
+ &.motus-animate {
22
+ transform: perspective(2500px) rotateY(0);
23
+ }
24
+ }
25
+
26
+ [data-motus='flip-up'] {
27
+ transform: perspective(2500px) rotateX(-100deg);
28
+
29
+ &.motus-animate {
30
+ transform: perspective(2500px) rotateX(0);
31
+ }
32
+ }
33
+
34
+ [data-motus='flip-down'] {
35
+ transform: perspective(2500px) rotateX(100deg);
36
+
37
+ &.motus-animate {
38
+ transform: perspective(2500px) rotateX(0);
39
+ }
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,34 @@
1
+ /// slide-up, slide-down, slide-left, slide-right
2
+ ///
3
+ /// Slides move by 100% of their own size rather than $motus-distance, and use
4
+ /// visibility instead of opacity so they stay fully opaque while moving.
5
+
6
+ @media screen and (prefers-reduced-motion: no-preference) {
7
+ html:not(.no-js):not([data-motus-disabled]):not([data-motus-inactive]) {
8
+ [data-motus^='slide'][data-motus^='slide'] {
9
+ transition-property: transform;
10
+ visibility: hidden;
11
+
12
+ &.motus-animate {
13
+ visibility: visible;
14
+ transform: translate3d(0, 0, 0);
15
+ }
16
+ }
17
+
18
+ [data-motus='slide-up'] {
19
+ transform: translate3d(0, 100%, 0);
20
+ }
21
+
22
+ [data-motus='slide-down'] {
23
+ transform: translate3d(0, -100%, 0);
24
+ }
25
+
26
+ [data-motus='slide-right'] {
27
+ transform: translate3d(-100%, 0, 0);
28
+ }
29
+
30
+ [data-motus='slide-left'] {
31
+ transform: translate3d(100%, 0, 0);
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,58 @@
1
+ @use '../config' as *;
2
+
3
+ /// zoom-in, zoom-in-up, zoom-in-down, zoom-in-left, zoom-in-right
4
+ /// zoom-out, zoom-out-up, zoom-out-down, zoom-out-left, zoom-out-right
5
+
6
+ @media screen and (prefers-reduced-motion: no-preference) {
7
+ html:not(.no-js):not([data-motus-disabled]):not([data-motus-inactive]) {
8
+ [data-motus^='zoom'][data-motus^='zoom'] {
9
+ opacity: 0;
10
+ transition-property: opacity, transform;
11
+
12
+ &.motus-animate {
13
+ opacity: 1;
14
+ transform: translate3d(0, 0, 0) scale(1);
15
+ }
16
+ }
17
+
18
+ [data-motus='zoom-in'] {
19
+ transform: scale(0.6);
20
+ }
21
+
22
+ [data-motus='zoom-in-up'] {
23
+ transform: translate3d(0, $motus-distance, 0) scale(0.6);
24
+ }
25
+
26
+ [data-motus='zoom-in-down'] {
27
+ transform: translate3d(0, -$motus-distance, 0) scale(0.6);
28
+ }
29
+
30
+ [data-motus='zoom-in-right'] {
31
+ transform: translate3d(-$motus-distance, 0, 0) scale(0.6);
32
+ }
33
+
34
+ [data-motus='zoom-in-left'] {
35
+ transform: translate3d($motus-distance, 0, 0) scale(0.6);
36
+ }
37
+
38
+ [data-motus='zoom-out'] {
39
+ transform: scale(1.2);
40
+ }
41
+
42
+ [data-motus='zoom-out-up'] {
43
+ transform: translate3d(0, $motus-distance, 0) scale(1.2);
44
+ }
45
+
46
+ [data-motus='zoom-out-down'] {
47
+ transform: translate3d(0, -$motus-distance, 0) scale(1.2);
48
+ }
49
+
50
+ [data-motus='zoom-out-right'] {
51
+ transform: translate3d(-$motus-distance, 0, 0) scale(1.2);
52
+ }
53
+
54
+ [data-motus='zoom-out-left'] {
55
+ transform: translate3d($motus-distance, 0, 0) scale(1.2);
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,3 @@
1
+ /// Translate distance used by the fade and zoom families.
2
+ /// Configure with `@use '@duboseweb/motus/scss/config' with ($motus-distance: 200px);`
3
+ $motus-distance: 100px !default;
package/scss/core.scss ADDED
@@ -0,0 +1,18 @@
1
+ /// Core transition wiring. Required by every animation family.
2
+ ///
3
+ /// Duration, delay and easing come from custom properties that the JS sets on
4
+ /// <body> (globals) and on individual elements (per-element overrides), so
5
+ /// there are no generated per-value classes.
6
+
7
+ @media (prefers-reduced-motion: no-preference) {
8
+ body.motus-ready [data-motus] {
9
+ transition-duration: var(--motus-duration);
10
+ transition-delay: 0s;
11
+ transition-timing-function: var(--motus-easing);
12
+
13
+ // Delay applies on the way in only, never on a mirror reset.
14
+ &.motus-animate {
15
+ transition-delay: var(--motus-delay);
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,8 @@
1
+ /// Full bundle: core plus every animation family.
2
+ /// Import individual families instead if you only need some of them.
3
+ @forward 'config';
4
+ @use 'core';
5
+ @use 'animations/fade';
6
+ @use 'animations/zoom';
7
+ @use 'animations/slide';
8
+ @use 'animations/flip';