@cssints/reveal 0.11.0 → 0.12.1
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 +137 -39
- package/dist/index.d.mts +62 -1
- package/dist/index.mjs +65 -3
- package/dist/runtime.mjs +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
# @cssints/reveal
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
Entrance animations for [cssints](../../README.md), on [@cssints/motion](../motion/README.md)'s presets, as two chain
|
|
4
|
+
members of `cssints/plugin` `scope()`:
|
|
5
|
+
|
|
6
|
+
- **`reveal()`** is scroll-_driven_: an element runs the entrance as it scrolls into view, on `animation-timeline: view()`
|
|
7
|
+
and `animation-range`, so the scroll scrubs it. In the spirit of
|
|
8
|
+
[the supersonic plugin](https://github.com/the-illarionov/the-supersonic-plugin-for-scroll-based-animation) and
|
|
9
|
+
[lax.js](https://github.com/alexfoxy/lax.js), with the browser doing the work.
|
|
10
|
+
- **`appear()`** is scroll-_triggered_: the scroll only decides _when_ a normal, time-based animation plays, on
|
|
11
|
+
`timeline-trigger` + `animation-trigger`. It keeps its own duration and easing, so a slow scroll cannot stretch the
|
|
12
|
+
entrance. The case is [utilitybend's article on CSS animation triggers](https://utilitybend.com/blog/scroll-triggered-animation-as-the-missing-piece-for-scrollytelling-on-the-web).
|
|
13
|
+
|
|
14
|
+
Where a target lacks the feature a member runs on, a 0.4 kB script plays the same animation once when the element enters.
|
|
9
15
|
|
|
10
16
|
```ts
|
|
11
17
|
import { cn, hover } from "cssints" with { type: "cssints" };
|
|
12
|
-
import { reveal } from "@cssints/reveal" with { type: "cssints" };
|
|
18
|
+
import { appear, reveal } from "@cssints/reveal" with { type: "cssints" };
|
|
13
19
|
|
|
20
|
+
// scroll-driven: the scroll scrubs it
|
|
14
21
|
export const fade = reveal();
|
|
15
22
|
export const card = reveal()
|
|
16
23
|
.preset("slide-in-up")
|
|
@@ -18,8 +25,14 @@ export const card = reveal()
|
|
|
18
25
|
.duration("500ms")
|
|
19
26
|
.easing("linear");
|
|
20
27
|
export const tile = cn(reveal().preset("blur-in"), hover(reveal().duration("1s")));
|
|
28
|
+
|
|
29
|
+
// scroll-triggered: it plays once on entry, with its own time
|
|
30
|
+
export const lede = appear().preset("slide-in-up").duration("600ms").easing("linear");
|
|
31
|
+
export const band = appear().preset("fade-in").inOut();
|
|
21
32
|
```
|
|
22
33
|
|
|
34
|
+
The CSS of `reveal()` (`fade` and `card` above):
|
|
35
|
+
|
|
23
36
|
```css
|
|
24
37
|
@layer _.k {
|
|
25
38
|
@keyframes kf-7f473efd {
|
|
@@ -76,61 +89,146 @@ export const tile = cn(reveal().preset("blur-in"), hover(reveal().duration("1s")
|
|
|
76
89
|
}
|
|
77
90
|
```
|
|
78
91
|
|
|
92
|
+
The CSS of `appear()` (`lede` and `band` above):
|
|
93
|
+
|
|
94
|
+
```css
|
|
95
|
+
@layer _.k {
|
|
96
|
+
/* motion's keyframes, the two rules reveal() names too (one pair for the page) */
|
|
97
|
+
._reveal-enter {
|
|
98
|
+
animation: var(--reveal-enter-k) var(--reveal-enter-d) var(--reveal-enter-e) both;
|
|
99
|
+
timeline-trigger: --reveal-t view() var(--reveal-enter-g);
|
|
100
|
+
--reveal-enter-k: kf-7f473efd;
|
|
101
|
+
--reveal-enter-rk: kf-4f766ef7;
|
|
102
|
+
--reveal-enter-d: 300ms;
|
|
103
|
+
--reveal-enter-e: ease-out;
|
|
104
|
+
--reveal-enter-g: entry 100% exit 0%;
|
|
105
|
+
--reveal-enter: play-once;
|
|
106
|
+
--reveal-leave: none;
|
|
107
|
+
--motion-o: 0;
|
|
108
|
+
--motion-x: 0;
|
|
109
|
+
--motion-y: 0;
|
|
110
|
+
--motion-s: 1;
|
|
111
|
+
--motion-b: 0;
|
|
112
|
+
animation-trigger: --reveal-t var(--reveal-enter) var(--reveal-leave);
|
|
113
|
+
trigger-scope: --reveal-t;
|
|
114
|
+
}
|
|
115
|
+
@media (prefers-reduced-motion: reduce) {
|
|
116
|
+
._reveal-enter {
|
|
117
|
+
animation-name: var(--reveal-enter-rk);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/* only when a target lacks animation triggers */
|
|
121
|
+
@supports not (animation-trigger: none) {
|
|
122
|
+
[data-reveal] ._reveal-enter:not([data-reveal-in]) {
|
|
123
|
+
animation-play-state: paused;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
@layer _.a {
|
|
128
|
+
._5mnsmm {
|
|
129
|
+
--reveal-enter: play-forwards;
|
|
130
|
+
}
|
|
131
|
+
._67iv7r {
|
|
132
|
+
--reveal-leave: play-backwards;
|
|
133
|
+
}
|
|
134
|
+
._1a9p5a9 {
|
|
135
|
+
--motion-y: 25%;
|
|
136
|
+
}
|
|
137
|
+
._knj5bv {
|
|
138
|
+
--motion-o: 0;
|
|
139
|
+
}
|
|
140
|
+
._oflqj4 {
|
|
141
|
+
--reveal-enter-e: linear;
|
|
142
|
+
}
|
|
143
|
+
._rsl9nu {
|
|
144
|
+
--reveal-enter-d: 600ms;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
79
149
|
## Rules
|
|
80
150
|
|
|
81
151
|
- **Methods**, each once, in any order, all optional: `preset(name)` (`fade-in`), `range(<'animation-range'>)`
|
|
82
|
-
(`entry 0% cover 40%`), `duration(<time [0s,∞]>)` (300ms) and
|
|
83
|
-
class that sets a custom property, so a method works under a
|
|
84
|
-
|
|
85
|
-
|
|
152
|
+
(`entry 0% cover 40%` for `reveal()`, `entry 100% exit 0%` for `appear()`), `duration(<time [0s,∞]>)` (300ms) and
|
|
153
|
+
`easing(<easing-function>)` (`ease-out`). Each is one class that sets a custom property, so a method works under a
|
|
154
|
+
condition.
|
|
155
|
+
- **`reveal()`.** Where the timeline is native, the range decides when the animation runs and the scroll drives it (back
|
|
156
|
+
and forth); the duration and the easing shape the fallback's one play (the easing applies to the scrubbed progress too).
|
|
157
|
+
- **`appear()`.** The range is the _activation_ range of the trigger: the element is fully in at `entry 100%`, so the
|
|
158
|
+
animation plays there and not while it is entering. The animation then runs over `duration()` with `easing()`, whatever
|
|
159
|
+
the scroll does. The default actions are `play-once none`: it plays once and stays, which is what an entrance wants —
|
|
160
|
+
and exactly what the fallback does. `inOut()` sets `play-forwards play-backwards`, so it plays back out when the
|
|
161
|
+
element leaves (where the triggers are native).
|
|
86
162
|
- **Presets** are motion's entrance presets: `fade-in`, `slide-in-up`, `slide-in-down`, `slide-in-left`,
|
|
87
163
|
`slide-in-right`, `scale-in`, `blur-in`. The `-out` ones are not: the fallback can only play when an element enters.
|
|
88
|
-
- **Reuse of motion.**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
164
|
+
- **Reuse of motion.** Both members name motion's `motionKeyframes.in` and `motionKeyframes.reducedIn`, so that rule is
|
|
165
|
+
motion's kernel, printed once however many styles use it, and a preset sets the values those keyframes read from
|
|
166
|
+
motion's `presets` table under motion's names (`motionVars`). Only each member's own properties are its own names:
|
|
167
|
+
`appear()`'s are `--reveal-enter-*`, because `reveal()`'s kernel declares the scope's short names (`--reveal-k` and
|
|
168
|
+
the rest) and two kernels of one scope may not share one of them. A scope may reuse a name another scope owns — that
|
|
169
|
+
is how both of them set `--motion-*` — so `motion()`, `reveal()` and `appear()` can sit on one page.
|
|
170
|
+
- **`trigger-scope` is required.** The trigger name is the kernel's (`--reveal-t`) and every element of the class shares
|
|
171
|
+
it; without `trigger-scope: --reveal-t`, the last element in the document would drive every card. With it, two boxes
|
|
172
|
+
of the same class trigger independently (checked in Chrome 156). Two different styles on one page do not collide
|
|
173
|
+
either: each kernel has its own name.
|
|
174
|
+
- **Reduced motion.** Under `prefers-reduced-motion: reduce` each kernel runs the opacity-only keyframes (motion's rule):
|
|
175
|
+
a slide, scale or blur becomes a fade over the same range or trigger.
|
|
176
|
+
- **One kernel, written as styles.** The `animation` shorthand resets `animation-timeline` and `animation-trigger`; a
|
|
177
|
+
kernel prints a shorthand before its longhands, so the declarations beside it win.
|
|
178
|
+
- **Conflicts.** `reveal()` and `appear()` set the animation: a `cn()` that holds one and an `animation*` property is a
|
|
179
|
+
build error, derived from the kernel:
|
|
180
|
+
`cssints: reveal: kernel enter sets animation, timeline-trigger, animation-trigger, trigger-scope, animation-name (this style also sets animation-duration)`.
|
|
97
181
|
- **Errors** are the grammar's, in the types and at build time: `reveal.preset: unexpected "fade-out" in "fade-out",
|
|
98
|
-
expected fade-in | ...`, `
|
|
182
|
+
expected fade-in | ...`, `appear.range: unexpected "sideways" in "entry 0% sideways"`.
|
|
99
183
|
|
|
100
184
|
## Browsers
|
|
101
185
|
|
|
102
|
-
- **Native
|
|
103
|
-
`animation-range`)
|
|
104
|
-
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
`
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
186
|
+
- **Native.** `reveal()`: Chrome 115, Safari 26 (scroll-driven animations, `css.properties.animation-timeline` and
|
|
187
|
+
`animation-range`); Firefox has them behind a flag only. `appear()`: Chrome 146, Edge 146, Opera 130
|
|
188
|
+
(`css.properties.animation-trigger`, `timeline-trigger` and `trigger-scope`); Firefox and Safari have no animation
|
|
189
|
+
triggers today. CSS animation triggers are a candidate for Interop 2027.
|
|
190
|
+
- **The fallback.** When a browserslist target lacks the feature a member runs on, the build adds that member's
|
|
191
|
+
`@supports not` rule above to the sheet (it stays out of the sheet for targets that all have it), and the kernel's
|
|
192
|
+
declarations give no support warning: the runtime polyfills them. The script, `@cssints/reveal/runtime`, comes with
|
|
193
|
+
it: each runtime entry names it (`script`), so a module that uses `reveal()` imports it through
|
|
194
|
+
`virtual:cssints/runtime/reveal.io` and one that uses `appear()` through `virtual:cssints/runtime/reveal.io-appear`;
|
|
195
|
+
each is empty when every target has its feature. Nothing to import by hand.
|
|
196
|
+
- **One script, two gates.** In the browser the script does nothing where both features work. It gates on
|
|
197
|
+
`CSS.supports("animation-timeline:view()")` for `reveal()` and `CSS.supports("animation-trigger:none")` for
|
|
198
|
+
`appear()`: it marks `<html data-reveal>` (the rule then holds each fallback animation at its first frame) and an
|
|
199
|
+
`IntersectionObserver` gives an element `data-reveal-in` when it enters the viewport, which plays the keyframes once,
|
|
200
|
+
over `duration()`. A `MutationObserver` picks up elements added later. 605 bytes minified, 369 gzip; no imports.
|
|
201
|
+
- **The fallback equals `appear()`'s default.** Playing once on entry is exactly `play-once none`, so on Firefox and
|
|
202
|
+
Safari `appear()` needs no extra behaviour; it cannot play back out (`inOut()`), follow the range, or react to the
|
|
203
|
+
scroll.
|
|
112
204
|
- **Why not a polyfill.** [flackr's scroll-timeline polyfill](https://github.com/flackr/scroll-timeline) scrubs the
|
|
113
205
|
animation as the native timeline does, but it is about 61 kB minified (17 kB gzip), rewrites stylesheets and runs on
|
|
114
|
-
every scroll.
|
|
206
|
+
every scroll. An entrance is a one-shot: playing it once on entry is what most sites want, costs 1/50 of the bytes and
|
|
115
207
|
nothing per scroll. The price is that the fallback is not scrubbed and ignores `range()`.
|
|
116
|
-
- Without the script, a target that lacks the
|
|
208
|
+
- Without the script, a target that lacks the feature plays the animation on load, as `motion()` would: nothing stays
|
|
117
209
|
hidden.
|
|
118
|
-
- Tested in Chrome
|
|
119
|
-
`bun run test:browsers`.
|
|
210
|
+
- Tested in Chrome 156 (native triggers and the fallback forced), Firefox 157 (the fallback) and WebKit 27.2 (the
|
|
211
|
+
reveal timeline native, the fallback for `appear()`): `bun run test:browsers`.
|
|
120
212
|
|
|
121
213
|
## Limits
|
|
122
214
|
|
|
123
215
|
- With targets that mix both (the default browserslist), the script ships to every browser and only probes where the
|
|
124
|
-
|
|
216
|
+
feature is native.
|
|
125
217
|
- The fallback does not follow the range, the scroll direction or an element that leaves the viewport: it plays once. An
|
|
126
218
|
element that gets the class after it is in the document (not added with it) is not seen.
|
|
127
|
-
- Until the script runs,
|
|
128
|
-
script runs with the first module that uses `reveal()`.
|
|
219
|
+
- Until the script runs, an animation below the fold may start playing; it is paused where it is and resumes on entry.
|
|
220
|
+
The script runs with the first module that uses `reveal()` or `appear()`.
|
|
221
|
+
- None of `motion()`, `reveal()` and `appear()` may be put on one element: each sets the `animation`, which two
|
|
222
|
+
kernels of one style refuse (`kernels ... both set animation`). On a page they share motion's keyframes and custom
|
|
223
|
+
properties.
|
|
224
|
+
- The trigger is on the animated element itself. A tall section that triggers its children is written by hand:
|
|
225
|
+
`css.timelineTrigger()` and `css.animationTrigger()` on the section, and `css.animationTrigger()` on the child. A
|
|
226
|
+
separate trigger element and a `.from("--name")` method are deferred.
|
|
129
227
|
- Entrance presets only, one per element; for an exit on scroll write the animation with `animationTimeline("view()")`
|
|
130
228
|
and `animationRange("exit ...")` yourself.
|
|
131
229
|
|
|
132
230
|
```bash
|
|
133
|
-
cd packages/reveal && bun run test # fixtures through the engine (output by targets, runtime
|
|
231
|
+
cd packages/reveal && bun run test # fixtures through the engine (output by targets, runtime modules, conflicts, errors)
|
|
134
232
|
cd packages/reveal && bun run test:browsers # Chrome, Firefox and WebKit through playwright-core
|
|
135
233
|
```
|
|
136
234
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
/** The scope of `reveal()`, for a scope that embeds it (
|
|
1
|
+
/** The scope of `reveal()` and `appear()`, for a scope that embeds it (their kernels `core` and `enter`). */
|
|
2
2
|
export declare const revealScope: import("cssints/plugin").Scope<"reveal", {
|
|
3
3
|
readonly "#core": {
|
|
4
4
|
readonly css: (css: import("cssints/plugin").Css) => import("cssints").Style[];
|
|
5
5
|
};
|
|
6
|
+
readonly "#enter": {
|
|
7
|
+
readonly css: (css: import("cssints/plugin").Css) => import("cssints").Style[];
|
|
8
|
+
};
|
|
6
9
|
readonly "#io": {
|
|
7
10
|
readonly polyfills: ["css.properties.animation-timeline", "css.properties.animation-range"];
|
|
8
11
|
readonly script: "@cssints/reveal/runtime";
|
|
9
12
|
readonly css: "@supports not (animation-timeline:view()){[data-reveal] &:not([data-reveal-in]){animation-play-state:paused}}";
|
|
10
13
|
};
|
|
14
|
+
readonly "#io-appear": {
|
|
15
|
+
readonly polyfills: ["css.properties.animation-trigger", "css.properties.timeline-trigger", "css.properties.trigger-scope"];
|
|
16
|
+
readonly script: "@cssints/reveal/runtime";
|
|
17
|
+
readonly css: "@supports not (animation-trigger:none){[data-reveal] &:not([data-reveal-in]){animation-play-state:paused}}";
|
|
18
|
+
};
|
|
11
19
|
readonly reveal: {
|
|
12
20
|
readonly uses: readonly ["core", "io"];
|
|
13
21
|
readonly chain: {
|
|
@@ -29,12 +37,44 @@ export declare const revealScope: import("cssints/plugin").Scope<"reveal", {
|
|
|
29
37
|
};
|
|
30
38
|
};
|
|
31
39
|
};
|
|
40
|
+
readonly appear: {
|
|
41
|
+
readonly uses: readonly ["enter", "io-appear"];
|
|
42
|
+
readonly chain: {
|
|
43
|
+
readonly preset: {
|
|
44
|
+
readonly args: "fade-in | slide-in-up | slide-in-down | slide-in-left | slide-in-right | scale-in | blur-in";
|
|
45
|
+
readonly emit: (name: string) => (readonly ["--motion-o" | "--motion-x" | "--motion-y" | "--motion-s" | "--motion-b", string])[];
|
|
46
|
+
};
|
|
47
|
+
readonly range: {
|
|
48
|
+
readonly args: "<'animation-range'>";
|
|
49
|
+
readonly emit: (v: string) => [string, string][];
|
|
50
|
+
};
|
|
51
|
+
readonly duration: {
|
|
52
|
+
readonly args: "<time [0s,∞]>";
|
|
53
|
+
readonly emit: (v: string) => [string, string][];
|
|
54
|
+
};
|
|
55
|
+
readonly easing: {
|
|
56
|
+
readonly args: "<easing-function>";
|
|
57
|
+
readonly emit: (v: string) => [string, string][];
|
|
58
|
+
};
|
|
59
|
+
readonly inOut: {
|
|
60
|
+
readonly args: "";
|
|
61
|
+
readonly emit: () => [string, string][];
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
};
|
|
32
65
|
}>;
|
|
33
66
|
/**
|
|
34
67
|
* `reveal().preset("slide-in-up").range("entry 0% entry 100%").duration("500ms").easing("linear")`: motion's entrance
|
|
35
68
|
* preset driven by the element's scroll into view, each method once and optional (`fade-in`, `entry 0% cover 40%`,
|
|
36
69
|
* 300ms and `ease-out` for the fallback, which plays once on entry). Under `prefers-reduced-motion: reduce` only the
|
|
37
70
|
* opacity moves. It sets the animation, so an `animation*` property in the same `cn()` is a build error.
|
|
71
|
+
*
|
|
72
|
+
* `appear().preset("slide-in-up").duration("600ms").easing("linear")`: motion's entrance preset triggered by the
|
|
73
|
+
* element's scroll into view, each method once and optional (`fade-in`, `entry 100% exit 0%`, 300ms and `ease-out`).
|
|
74
|
+
* The scroll only starts the animation: it keeps its own duration and easing. `inOut()` plays it forwards on entry and
|
|
75
|
+
* backwards on exit, where the triggers are native; the default plays it once and stays. Under
|
|
76
|
+
* `prefers-reduced-motion: reduce` only the opacity moves. It sets the animation, so an `animation*` property in the
|
|
77
|
+
* same `cn()` is a build error.
|
|
38
78
|
*/
|
|
39
79
|
export declare const reveal: () => import("cssints/plugin").Chain<"reveal", {
|
|
40
80
|
readonly preset: {
|
|
@@ -53,4 +93,25 @@ export declare const reveal: () => import("cssints/plugin").Chain<"reveal", {
|
|
|
53
93
|
readonly args: "<easing-function>";
|
|
54
94
|
readonly emit: (v: string) => [string, string][];
|
|
55
95
|
};
|
|
96
|
+
}, {}>, appear: () => import("cssints/plugin").Chain<"appear", {
|
|
97
|
+
readonly preset: {
|
|
98
|
+
readonly args: "fade-in | slide-in-up | slide-in-down | slide-in-left | slide-in-right | scale-in | blur-in";
|
|
99
|
+
readonly emit: (name: string) => (readonly ["--motion-o" | "--motion-x" | "--motion-y" | "--motion-s" | "--motion-b", string])[];
|
|
100
|
+
};
|
|
101
|
+
readonly range: {
|
|
102
|
+
readonly args: "<'animation-range'>";
|
|
103
|
+
readonly emit: (v: string) => [string, string][];
|
|
104
|
+
};
|
|
105
|
+
readonly duration: {
|
|
106
|
+
readonly args: "<time [0s,∞]>";
|
|
107
|
+
readonly emit: (v: string) => [string, string][];
|
|
108
|
+
};
|
|
109
|
+
readonly easing: {
|
|
110
|
+
readonly args: "<easing-function>";
|
|
111
|
+
readonly emit: (v: string) => [string, string][];
|
|
112
|
+
};
|
|
113
|
+
readonly inOut: {
|
|
114
|
+
readonly args: "";
|
|
115
|
+
readonly emit: () => [string, string][];
|
|
116
|
+
};
|
|
56
117
|
}, {}>;
|
package/dist/index.mjs
CHANGED
|
@@ -10,7 +10,7 @@ const emitPreset = (name) => {
|
|
|
10
10
|
return v === void 0 ? [] : [[motionVars[f], v]];
|
|
11
11
|
});
|
|
12
12
|
};
|
|
13
|
-
/** The scope of `reveal()`, for a scope that embeds it (
|
|
13
|
+
/** The scope of `reveal()` and `appear()`, for a scope that embeds it (their kernels `core` and `enter`). */
|
|
14
14
|
const revealScope = scope("reveal", {
|
|
15
15
|
"#core": { css: (css) => [
|
|
16
16
|
css.vars({
|
|
@@ -30,11 +30,41 @@ const revealScope = scope("reveal", {
|
|
|
30
30
|
css.animationRange("var(--_g)"),
|
|
31
31
|
css.media("(prefers-reduced-motion: reduce)")(css.animationName("var(--_rk)"))
|
|
32
32
|
] },
|
|
33
|
+
"#enter": { css: (css) => [
|
|
34
|
+
css.vars({
|
|
35
|
+
"--_enter-k": motionKeyframes.in,
|
|
36
|
+
"--_enter-rk": motionKeyframes.reducedIn,
|
|
37
|
+
"--_enter-d": "300ms",
|
|
38
|
+
"--_enter-e": "ease-out",
|
|
39
|
+
"--_enter-g": "entry 100% exit 0%",
|
|
40
|
+
"--_enter": "play-once",
|
|
41
|
+
"--_leave": "none",
|
|
42
|
+
[motionVars.opacity]: 0,
|
|
43
|
+
[motionVars.x]: 0,
|
|
44
|
+
[motionVars.y]: 0,
|
|
45
|
+
[motionVars.scale]: 1,
|
|
46
|
+
[motionVars.blur]: 0
|
|
47
|
+
}),
|
|
48
|
+
css.animation("var(--_enter-k) var(--_enter-d) var(--_enter-e) both"),
|
|
49
|
+
css.timelineTrigger("--_t view() var(--_enter-g)"),
|
|
50
|
+
css.animationTrigger("--_t var(--_enter) var(--_leave)"),
|
|
51
|
+
css.triggerScope("--_t"),
|
|
52
|
+
css.media("(prefers-reduced-motion: reduce)")(css.animationName("var(--_enter-rk)"))
|
|
53
|
+
] },
|
|
33
54
|
"#io": {
|
|
34
55
|
polyfills: ["css.properties.animation-timeline", "css.properties.animation-range"],
|
|
35
56
|
script: "@cssints/reveal/runtime",
|
|
36
57
|
css: `@supports not (animation-timeline:view()){[data-reveal] &:not([data-reveal-in]){animation-play-state:paused}}`
|
|
37
58
|
},
|
|
59
|
+
"#io-appear": {
|
|
60
|
+
polyfills: [
|
|
61
|
+
"css.properties.animation-trigger",
|
|
62
|
+
"css.properties.timeline-trigger",
|
|
63
|
+
"css.properties.trigger-scope"
|
|
64
|
+
],
|
|
65
|
+
script: "@cssints/reveal/runtime",
|
|
66
|
+
css: `@supports not (animation-trigger:none){[data-reveal] &:not([data-reveal-in]){animation-play-state:paused}}`
|
|
67
|
+
},
|
|
38
68
|
reveal: {
|
|
39
69
|
uses: ["core", "io"],
|
|
40
70
|
chain: {
|
|
@@ -55,6 +85,31 @@ const revealScope = scope("reveal", {
|
|
|
55
85
|
emit: (v) => [["--_e", v]]
|
|
56
86
|
}
|
|
57
87
|
}
|
|
88
|
+
},
|
|
89
|
+
appear: {
|
|
90
|
+
uses: ["enter", "io-appear"],
|
|
91
|
+
chain: {
|
|
92
|
+
preset: {
|
|
93
|
+
args: names,
|
|
94
|
+
emit: emitPreset
|
|
95
|
+
},
|
|
96
|
+
range: {
|
|
97
|
+
args: "<'animation-range'>",
|
|
98
|
+
emit: (v) => [["--_enter-g", v]]
|
|
99
|
+
},
|
|
100
|
+
duration: {
|
|
101
|
+
args: "<time [0s,∞]>",
|
|
102
|
+
emit: (v) => [["--_enter-d", v]]
|
|
103
|
+
},
|
|
104
|
+
easing: {
|
|
105
|
+
args: "<easing-function>",
|
|
106
|
+
emit: (v) => [["--_enter-e", v]]
|
|
107
|
+
},
|
|
108
|
+
inOut: {
|
|
109
|
+
args: "",
|
|
110
|
+
emit: () => [["--_enter", "play-forwards"], ["--_leave", "play-backwards"]]
|
|
111
|
+
}
|
|
112
|
+
}
|
|
58
113
|
}
|
|
59
114
|
});
|
|
60
115
|
/**
|
|
@@ -62,6 +117,13 @@ const revealScope = scope("reveal", {
|
|
|
62
117
|
* preset driven by the element's scroll into view, each method once and optional (`fade-in`, `entry 0% cover 40%`,
|
|
63
118
|
* 300ms and `ease-out` for the fallback, which plays once on entry). Under `prefers-reduced-motion: reduce` only the
|
|
64
119
|
* opacity moves. It sets the animation, so an `animation*` property in the same `cn()` is a build error.
|
|
120
|
+
*
|
|
121
|
+
* `appear().preset("slide-in-up").duration("600ms").easing("linear")`: motion's entrance preset triggered by the
|
|
122
|
+
* element's scroll into view, each method once and optional (`fade-in`, `entry 100% exit 0%`, 300ms and `ease-out`).
|
|
123
|
+
* The scroll only starts the animation: it keeps its own duration and easing. `inOut()` plays it forwards on entry and
|
|
124
|
+
* backwards on exit, where the triggers are native; the default plays it once and stays. Under
|
|
125
|
+
* `prefers-reduced-motion: reduce` only the opacity moves. It sets the animation, so an `animation*` property in the
|
|
126
|
+
* same `cn()` is a build error.
|
|
65
127
|
*/
|
|
66
|
-
const { reveal } = revealScope.export();
|
|
67
|
-
export { reveal, revealScope };
|
|
128
|
+
const { reveal, appear } = revealScope.export();
|
|
129
|
+
export { appear, reveal, revealScope };
|
package/dist/runtime.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
if(typeof CSS<`u
|
|
1
|
+
if(typeof CSS<`u`){let e=!CSS.supports(`animation-timeline:view()`),t=!CSS.supports(`animation-trigger:none`);if(e||t){let n=document.documentElement,r=[e&&`._reveal-core`,t&&`._reveal-enter`].filter(Boolean).join(`,`),i=new IntersectionObserver(e=>{for(let t of e)t.isIntersecting&&(t.target.setAttribute(`data-reveal-in`,``),i.unobserve(t.target))}),a=e=>{e.matches(r)&&i.observe(e);for(let t of e.querySelectorAll(r))i.observe(t)};n.setAttribute(`data-reveal`,``),a(n),new MutationObserver(e=>{for(let t of e)for(let e of t.addedNodes)e instanceof Element&&a(e)}).observe(n,{childList:!0,subtree:!0})}}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cssints/reveal",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Scroll-driven
|
|
3
|
+
"version": "0.12.1",
|
|
4
|
+
"description": "Scroll-driven and scroll-triggered entrance animations for cssints: motion's presets on animation-timeline: view() (reveal) or on CSS animation triggers (appear), with a tiny IntersectionObserver fallback",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@cssints/motion": "^0.
|
|
31
|
+
"@cssints/motion": "^0.12.1"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"cssints": "^0.
|
|
34
|
+
"cssints": "^0.12.0"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=22"
|