solid-drift 0.2.0 → 0.7.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.
Files changed (48) hide show
  1. package/README.md +735 -10
  2. package/dist/animate.d.ts +2 -2
  3. package/dist/animate.js +2 -2
  4. package/dist/cartoon.d.ts +190 -0
  5. package/dist/cartoon.js +334 -0
  6. package/dist/color.d.ts +53 -0
  7. package/dist/color.js +391 -0
  8. package/dist/directive.d.ts +5 -5
  9. package/dist/directive.js +15 -7
  10. package/dist/easing.d.ts +22 -1
  11. package/dist/easing.js +49 -1
  12. package/dist/flip.d.ts +44 -0
  13. package/dist/flip.js +108 -0
  14. package/dist/horizontal.d.ts +107 -0
  15. package/dist/horizontal.js +208 -0
  16. package/dist/index.d.ts +16 -3
  17. package/dist/index.js +15 -3
  18. package/dist/inview.d.ts +4 -4
  19. package/dist/inview.js +5 -5
  20. package/dist/motion.d.ts +327 -0
  21. package/dist/motion.js +729 -0
  22. package/dist/physics.d.ts +146 -0
  23. package/dist/physics.js +352 -0
  24. package/dist/pointer.d.ts +76 -0
  25. package/dist/pointer.js +123 -0
  26. package/dist/reduced-motion.d.ts +3 -3
  27. package/dist/reduced-motion.js +5 -4
  28. package/dist/scroll.d.ts +3 -3
  29. package/dist/scroll.js +5 -5
  30. package/dist/scrollfx.d.ts +156 -0
  31. package/dist/scrollfx.js +148 -0
  32. package/dist/scrub.d.ts +51 -0
  33. package/dist/scrub.js +67 -0
  34. package/dist/spring.d.ts +39 -4
  35. package/dist/spring.js +26 -7
  36. package/dist/stagger.d.ts +4 -4
  37. package/dist/stagger.js +4 -4
  38. package/dist/timeline.d.ts +45 -0
  39. package/dist/timeline.js +93 -0
  40. package/dist/trail.d.ts +27 -0
  41. package/dist/trail.js +75 -0
  42. package/dist/tween.d.ts +3 -3
  43. package/dist/tween.js +3 -3
  44. package/dist/typography.d.ts +241 -0
  45. package/dist/typography.js +812 -0
  46. package/dist/velocity.d.ts +44 -0
  47. package/dist/velocity.js +88 -0
  48. package/package.json +1 -1
package/dist/color.js ADDED
@@ -0,0 +1,391 @@
1
+ import { resolveEasing } from "./easing.js";
2
+ function clamp01(v) {
3
+ return v < 0 ? 0 : v > 1 ? 1 : v;
4
+ }
5
+ /** sRGB channel (0 to 1) to linear light. */
6
+ function srgbToLinear(c) {
7
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
8
+ }
9
+ /** Linear light channel (0 to 1) back to sRGB. */
10
+ function linearToSrgb(c) {
11
+ return c <= 0.0031308
12
+ ? 12.92 * c
13
+ : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
14
+ }
15
+ /** Round to at most 4 decimals so values like 0.30000000000000004 never leak. */
16
+ function fmtNum(v) {
17
+ return String(Math.round(v * 10000) / 10000);
18
+ }
19
+ function failColor(input) {
20
+ throw new Error(`[solid-drift] could not parse color "${input}". ` +
21
+ "Use hex (#rgb, #rrggbb), rgb()/rgba(), hsl()/hsla(), or a CSS color name.");
22
+ }
23
+ function parseHexColor(raw) {
24
+ const hex = raw.slice(1);
25
+ if (!/^[0-9a-f]+$/.test(hex))
26
+ failColor(raw);
27
+ const pair = (s) => parseInt(s, 16);
28
+ let r = 0;
29
+ let g = 0;
30
+ let b = 0;
31
+ let a = 1;
32
+ if (hex.length === 3 || hex.length === 4) {
33
+ const d = (c) => pair(c + c);
34
+ r = d(hex[0]);
35
+ g = d(hex[1]);
36
+ b = d(hex[2]);
37
+ if (hex.length === 4)
38
+ a = d(hex[3]) / 255;
39
+ }
40
+ else if (hex.length === 6 || hex.length === 8) {
41
+ r = pair(hex.slice(0, 2));
42
+ g = pair(hex.slice(2, 4));
43
+ b = pair(hex.slice(4, 6));
44
+ if (hex.length === 8)
45
+ a = pair(hex.slice(6, 8)) / 255;
46
+ }
47
+ else {
48
+ failColor(raw);
49
+ }
50
+ return {
51
+ r: srgbToLinear(r / 255),
52
+ g: srgbToLinear(g / 255),
53
+ b: srgbToLinear(b / 255),
54
+ a,
55
+ };
56
+ }
57
+ /** Split the inside of a rgb()/hsl() call into its 3 or 4 components. */
58
+ function splitColorArgs(inner) {
59
+ return inner
60
+ .replace(/\//g, " ")
61
+ .split(/[\s,]+/)
62
+ .filter((part) => part.length > 0);
63
+ }
64
+ function parseAlpha(part) {
65
+ if (part.endsWith("%"))
66
+ return clamp01(parseFloat(part) / 100);
67
+ return clamp01(parseFloat(part));
68
+ }
69
+ function parseRgbChannel(part) {
70
+ if (part.endsWith("%"))
71
+ return clamp01(parseFloat(part) / 100);
72
+ return clamp01(parseFloat(part) / 255);
73
+ }
74
+ function parseRgbColor(raw) {
75
+ const inner = raw.slice(raw.indexOf("(") + 1, raw.lastIndexOf(")"));
76
+ const parts = splitColorArgs(inner);
77
+ if (parts.length < 3 || parts.length > 4)
78
+ failColor(raw);
79
+ const [r, g, b] = parts.map(parseRgbChannel);
80
+ const a = parts.length === 4 ? parseAlpha(parts[3]) : 1;
81
+ return {
82
+ r: srgbToLinear(r),
83
+ g: srgbToLinear(g),
84
+ b: srgbToLinear(b),
85
+ a,
86
+ };
87
+ }
88
+ function parseHue(part) {
89
+ let h = parseFloat(part);
90
+ if (part.endsWith("turn"))
91
+ h *= 360;
92
+ // Bare numbers and "deg" are degrees; wrap negative values around.
93
+ return ((h % 360) + 360) % 360;
94
+ }
95
+ function parsePercent(part) {
96
+ return clamp01(parseFloat(part) / 100);
97
+ }
98
+ function hslToRgb(h, s, l) {
99
+ const c = (1 - Math.abs(2 * l - 1)) * s;
100
+ const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
101
+ const m = l - c / 2;
102
+ let r = 0;
103
+ let g = 0;
104
+ let b = 0;
105
+ if (h < 60) {
106
+ r = c;
107
+ g = x;
108
+ }
109
+ else if (h < 120) {
110
+ r = x;
111
+ g = c;
112
+ }
113
+ else if (h < 180) {
114
+ g = c;
115
+ b = x;
116
+ }
117
+ else if (h < 240) {
118
+ g = x;
119
+ b = c;
120
+ }
121
+ else if (h < 300) {
122
+ r = x;
123
+ b = c;
124
+ }
125
+ else {
126
+ r = c;
127
+ b = x;
128
+ }
129
+ return [r + m, g + m, b + m];
130
+ }
131
+ function parseHslColor(raw) {
132
+ const inner = raw.slice(raw.indexOf("(") + 1, raw.lastIndexOf(")"));
133
+ const parts = splitColorArgs(inner);
134
+ if (parts.length < 3 || parts.length > 4)
135
+ failColor(raw);
136
+ const h = parseHue(parts[0]);
137
+ const s = parsePercent(parts[1]);
138
+ const l = parsePercent(parts[2]);
139
+ const a = parts.length === 4 ? parseAlpha(parts[3]) : 1;
140
+ const [r, g, b] = hslToRgb(h, s, l);
141
+ return {
142
+ r: srgbToLinear(r),
143
+ g: srgbToLinear(g),
144
+ b: srgbToLinear(b),
145
+ a,
146
+ };
147
+ }
148
+ /** The 148 CSS named colors, stored as hex. */
149
+ const NAMED_COLORS = {
150
+ aliceblue: "#f0f8ff",
151
+ antiquewhite: "#faebd7",
152
+ aqua: "#00ffff",
153
+ aquamarine: "#7fffd4",
154
+ azure: "#f0ffff",
155
+ beige: "#f5f5dc",
156
+ bisque: "#ffe4c4",
157
+ black: "#000000",
158
+ blanchedalmond: "#ffebcd",
159
+ blue: "#0000ff",
160
+ blueviolet: "#8a2be2",
161
+ brown: "#a52a2a",
162
+ burlywood: "#deb887",
163
+ cadetblue: "#5f9ea0",
164
+ chartreuse: "#7fff00",
165
+ chocolate: "#d2691e",
166
+ coral: "#ff7f50",
167
+ cornflowerblue: "#6495ed",
168
+ cornsilk: "#fff8dc",
169
+ crimson: "#dc143c",
170
+ cyan: "#00ffff",
171
+ darkblue: "#00008b",
172
+ darkcyan: "#008b8b",
173
+ darkgoldenrod: "#b8860b",
174
+ darkgray: "#a9a9a9",
175
+ darkgrey: "#a9a9a9",
176
+ darkgreen: "#006400",
177
+ darkkhaki: "#bdb76b",
178
+ darkmagenta: "#8b008b",
179
+ darkolivegreen: "#556b2f",
180
+ darkorange: "#ff8c00",
181
+ darkorchid: "#9932cc",
182
+ darkred: "#8b0000",
183
+ darksalmon: "#e9967a",
184
+ darkseagreen: "#8fbc8f",
185
+ darkslateblue: "#483d8b",
186
+ darkslategray: "#2f4f4f",
187
+ darkslategrey: "#2f4f4f",
188
+ darkturquoise: "#00ced1",
189
+ darkviolet: "#9400d3",
190
+ deeppink: "#ff1493",
191
+ deepskyblue: "#00bfff",
192
+ dimgray: "#696969",
193
+ dimgrey: "#696969",
194
+ dodgerblue: "#1e90ff",
195
+ firebrick: "#b22222",
196
+ floralwhite: "#fffaf0",
197
+ forestgreen: "#228b22",
198
+ fuchsia: "#ff00ff",
199
+ gainsboro: "#dcdcdc",
200
+ ghostwhite: "#f8f8ff",
201
+ gold: "#ffd700",
202
+ goldenrod: "#daa520",
203
+ gray: "#808080",
204
+ grey: "#808080",
205
+ green: "#008000",
206
+ greenyellow: "#adff2f",
207
+ honeydew: "#f0fff0",
208
+ hotpink: "#ff69b4",
209
+ indianred: "#cd5c5c",
210
+ indigo: "#4b0082",
211
+ ivory: "#fffff0",
212
+ khaki: "#f0e68c",
213
+ lavender: "#e6e6fa",
214
+ lavenderblush: "#fff0f5",
215
+ lawngreen: "#7cfc00",
216
+ lemonchiffon: "#fffacd",
217
+ lightblue: "#add8e6",
218
+ lightcoral: "#f08080",
219
+ lightcyan: "#e0ffff",
220
+ lightgoldenrodyellow: "#fafad2",
221
+ lightgray: "#d3d3d3",
222
+ lightgrey: "#d3d3d3",
223
+ lightgreen: "#90ee90",
224
+ lightpink: "#ffb6c1",
225
+ lightsalmon: "#ffa07a",
226
+ lightseagreen: "#20b2aa",
227
+ lightskyblue: "#87cefa",
228
+ lightslategray: "#778899",
229
+ lightslategrey: "#778899",
230
+ lightsteelblue: "#b0c4de",
231
+ lightyellow: "#ffffe0",
232
+ lime: "#00ff00",
233
+ limegreen: "#32cd32",
234
+ linen: "#faf0e6",
235
+ magenta: "#ff00ff",
236
+ maroon: "#800000",
237
+ mediumaquamarine: "#66cdaa",
238
+ mediumblue: "#0000cd",
239
+ mediumorchid: "#ba55d3",
240
+ mediumpurple: "#9370db",
241
+ mediumseagreen: "#3cb371",
242
+ mediumslateblue: "#7b68ee",
243
+ mediumspringgreen: "#00fa9a",
244
+ mediumturquoise: "#48d1cc",
245
+ mediumvioletred: "#c71585",
246
+ midnightblue: "#191970",
247
+ mintcream: "#f5fffa",
248
+ mistyrose: "#ffe4e1",
249
+ moccasin: "#ffe4b5",
250
+ navajowhite: "#ffdead",
251
+ navy: "#000080",
252
+ oldlace: "#fdf5e6",
253
+ olive: "#808000",
254
+ olivedrab: "#6b8e23",
255
+ orange: "#ffa500",
256
+ orangered: "#ff4500",
257
+ orchid: "#da70d6",
258
+ palegoldenrod: "#eee8aa",
259
+ palegreen: "#98fb98",
260
+ paleturquoise: "#afeeee",
261
+ palevioletred: "#db7093",
262
+ papayawhip: "#ffefd5",
263
+ peachpuff: "#ffdab9",
264
+ peru: "#cd853f",
265
+ pink: "#ffc0cb",
266
+ plum: "#dda0dd",
267
+ powderblue: "#b0e0e6",
268
+ purple: "#800080",
269
+ rebeccapurple: "#663399",
270
+ red: "#ff0000",
271
+ rosybrown: "#bc8f8f",
272
+ royalblue: "#4169e1",
273
+ saddlebrown: "#8b4513",
274
+ salmon: "#fa8072",
275
+ sandybrown: "#f4a460",
276
+ seagreen: "#2e8b57",
277
+ seashell: "#fff5ee",
278
+ sienna: "#a0522d",
279
+ silver: "#c0c0c0",
280
+ skyblue: "#87ceeb",
281
+ slateblue: "#6a5acd",
282
+ slategray: "#708090",
283
+ slategrey: "#708090",
284
+ snow: "#fffafa",
285
+ springgreen: "#00ff7f",
286
+ steelblue: "#4682b4",
287
+ tan: "#d2b48c",
288
+ teal: "#008080",
289
+ thistle: "#d8bfd8",
290
+ tomato: "#ff6347",
291
+ turquoise: "#40e0d0",
292
+ violet: "#ee82ee",
293
+ wheat: "#f5deb3",
294
+ white: "#ffffff",
295
+ whitesmoke: "#f5f5f5",
296
+ yellow: "#ffff00",
297
+ yellowgreen: "#9acd32",
298
+ };
299
+ /** Parse any supported CSS color into linear RGB plus alpha. */
300
+ export function parseColor(input) {
301
+ const raw = input.trim().toLowerCase();
302
+ if (raw.startsWith("#"))
303
+ return parseHexColor(raw);
304
+ if (raw.startsWith("rgb"))
305
+ return parseRgbColor(raw);
306
+ if (raw.startsWith("hsl"))
307
+ return parseHslColor(raw);
308
+ const named = NAMED_COLORS[raw];
309
+ if (named)
310
+ return parseHexColor(named);
311
+ return failColor(input);
312
+ }
313
+ export function lerpColor(a, b, t) {
314
+ return {
315
+ r: a.r + (b.r - a.r) * t,
316
+ g: a.g + (b.g - a.g) * t,
317
+ b: a.b + (b.b - a.b) * t,
318
+ a: a.a + (b.a - a.a) * t,
319
+ };
320
+ }
321
+ function rgbToHsl(r, g, b) {
322
+ const max = Math.max(r, g, b);
323
+ const min = Math.min(r, g, b);
324
+ const l = (max + min) / 2;
325
+ let h = 0;
326
+ let s = 0;
327
+ if (max !== min) {
328
+ const d = max - min;
329
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
330
+ if (max === r)
331
+ h = ((g - b) / d + (g < b ? 6 : 0)) * 60;
332
+ else if (max === g)
333
+ h = ((b - r) / d + 2) * 60;
334
+ else
335
+ h = ((r - g) / d + 4) * 60;
336
+ }
337
+ return { h, s, l };
338
+ }
339
+ export function formatColor(color, format) {
340
+ const r = Math.round(clamp01(linearToSrgb(color.r)) * 255);
341
+ const g = Math.round(clamp01(linearToSrgb(color.g)) * 255);
342
+ const b = Math.round(clamp01(linearToSrgb(color.b)) * 255);
343
+ const a = clamp01(color.a);
344
+ const hex2 = (n) => n.toString(16).padStart(2, "0");
345
+ if (format === "hex") {
346
+ const base = `#${hex2(r)}${hex2(g)}${hex2(b)}`;
347
+ return a >= 0.999 ? base : `${base}${hex2(Math.round(a * 255))}`;
348
+ }
349
+ if (format === "rgb") {
350
+ return a >= 0.999
351
+ ? `rgb(${r}, ${g}, ${b})`
352
+ : `rgba(${r}, ${g}, ${b}, ${fmtNum(a)})`;
353
+ }
354
+ const { h, s, l } = rgbToHsl(r / 255, g / 255, b / 255);
355
+ const hsl = `hsl(${Math.round(h)}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%)`;
356
+ return a >= 0.999
357
+ ? hsl
358
+ : `hsla(${Math.round(h)}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%, ${fmtNum(a)})`;
359
+ }
360
+ /**
361
+ * Sort stops by `at`, parse every color, and resolve each segment's
362
+ * easing. Shared by the scroll-driven and time-driven color primitives.
363
+ */
364
+ export function parseColorStops(stops, fallbackEasing) {
365
+ const sorted = [...stops].sort((a, b) => a.at - b.at);
366
+ return sorted.map((stop) => ({
367
+ at: stop.at,
368
+ color: parseColor(stop.color),
369
+ easing: resolveEasing(stop.easing ?? fallbackEasing ?? "linear"),
370
+ }));
371
+ }
372
+ /**
373
+ * Sample a parsed stop list at progress `p` (clamped 0 to 1) and return
374
+ * the interpolated color string in the requested format.
375
+ */
376
+ export function sampleColorStops(stops, p, format) {
377
+ const t = p < 0 ? 0 : p > 1 ? 1 : p;
378
+ if (t <= stops[0].at)
379
+ return formatColor(stops[0].color, format);
380
+ const last = stops[stops.length - 1];
381
+ if (t >= last.at)
382
+ return formatColor(last.color, format);
383
+ let i = 0;
384
+ while (i < stops.length - 2 && stops[i + 1].at <= t)
385
+ i++;
386
+ const a = stops[i];
387
+ const b = stops[i + 1];
388
+ const span = b.at - a.at;
389
+ const local = span <= 0 ? 0 : (t - a.at) / span;
390
+ return formatColor(lerpColor(a.color, b.color, b.easing(local)), format);
391
+ }
@@ -25,15 +25,15 @@ declare module "solid-js" {
25
25
  }
26
26
  /**
27
27
  * Directive that binds animated values straight to an element's style.
28
- * Each prop can be a plain number or any signal — combine with
28
+ * Each prop can be a plain number or any signal. Combine with
29
29
  * `createSpring` / `createTween` for buttery motion:
30
30
  *
31
31
  * ```tsx
32
- * import { drift } from "solid-drift";
32
+ * import { drift } from "solid-drift"
33
33
  *
34
- * const [open, setOpen] = createSignal(false);
35
- * const y = createSpring(() => (open() ? 0 : 24));
36
- * const opacity = createTween(() => (open() ? 1 : 0), { duration: 250 });
34
+ * const [open, setOpen] = createSignal(false)
35
+ * const y = createSpring(() => (open() ? 0 : 24))
36
+ * const opacity = createTween(() => (open() ? 1 : 0), { duration: 250 })
37
37
  *
38
38
  * <div use:drift={{ y, opacity }}>slides and fades</div>
39
39
  * ```
package/dist/directive.js CHANGED
@@ -4,15 +4,15 @@ function resolve(value) {
4
4
  }
5
5
  /**
6
6
  * Directive that binds animated values straight to an element's style.
7
- * Each prop can be a plain number or any signal — combine with
7
+ * Each prop can be a plain number or any signal. Combine with
8
8
  * `createSpring` / `createTween` for buttery motion:
9
9
  *
10
10
  * ```tsx
11
- * import { drift } from "solid-drift";
11
+ * import { drift } from "solid-drift"
12
12
  *
13
- * const [open, setOpen] = createSignal(false);
14
- * const y = createSpring(() => (open() ? 0 : 24));
15
- * const opacity = createTween(() => (open() ? 1 : 0), { duration: 250 });
13
+ * const [open, setOpen] = createSignal(false)
14
+ * const y = createSpring(() => (open() ? 0 : 24))
15
+ * const opacity = createTween(() => (open() ? 1 : 0), { duration: 250 })
16
16
  *
17
17
  * <div use:drift={{ y, opacity }}>slides and fades</div>
18
18
  * ```
@@ -30,8 +30,16 @@ export function drift(el, props) {
30
30
  const rotate = p.rotate !== undefined ? resolve(p.rotate) : 0;
31
31
  if (rotate !== 0)
32
32
  parts.push(`rotate(${rotate}deg)`);
33
- const sx = p.scaleX !== undefined ? resolve(p.scaleX) : p.scale !== undefined ? resolve(p.scale) : 1;
34
- const sy = p.scaleY !== undefined ? resolve(p.scaleY) : p.scale !== undefined ? resolve(p.scale) : 1;
33
+ const sx = p.scaleX !== undefined
34
+ ? resolve(p.scaleX)
35
+ : p.scale !== undefined
36
+ ? resolve(p.scale)
37
+ : 1;
38
+ const sy = p.scaleY !== undefined
39
+ ? resolve(p.scaleY)
40
+ : p.scale !== undefined
41
+ ? resolve(p.scale)
42
+ : 1;
35
43
  if (sx !== 1 || sy !== 1)
36
44
  parts.push(`scale(${sx}, ${sy})`);
37
45
  el.style.transform = parts.join(" ");
package/dist/easing.d.ts CHANGED
@@ -12,6 +12,23 @@ export declare const easeOutQuart: Easing;
12
12
  export declare const easeInOutQuart: Easing;
13
13
  export declare const easeOutExpo: Easing;
14
14
  export declare const easeOutBack: Easing;
15
+ /**
16
+ * Anticipation easing: dips below the start value before climbing to 1.
17
+ * The classic cartoon wind-up, a character crouching before the jump.
18
+ */
19
+ export declare const easeInBack: Easing;
20
+ /** Overshoot at both ends: winds up, fires past the target, settles back. */
21
+ export declare const easeInOutBack: Easing;
22
+ /**
23
+ * Elastic wobble: overshoots and oscillates with decaying amplitude,
24
+ * like a plucked rubber band or a jelly landing.
25
+ */
26
+ export declare const easeOutElastic: Easing;
27
+ /**
28
+ * Cartoon bounce: hits the end value with a series of shrinking hops,
29
+ * like a dropped rubber ball.
30
+ */
31
+ export declare const easeOutBounce: Easing;
15
32
  /**
16
33
  * Cubic bezier easing, same parameters as CSS `cubic-bezier(x1, y1, x2, y2)`.
17
34
  */
@@ -29,7 +46,11 @@ export declare const easings: {
29
46
  readonly easeInOutQuart: Easing;
30
47
  readonly easeOutExpo: Easing;
31
48
  readonly easeOutBack: Easing;
49
+ readonly easeInBack: Easing;
50
+ readonly easeInOutBack: Easing;
51
+ readonly easeOutElastic: Easing;
52
+ readonly easeOutBounce: Easing;
32
53
  };
33
54
  export type EasingName = keyof typeof easings;
34
- /** Accept an easing function or its name; throws on unknown names. */
55
+ /** Accept an easing function or its name. Throws on unknown names. */
35
56
  export declare function resolveEasing(easing: Easing | EasingName | undefined): Easing;
package/dist/easing.js CHANGED
@@ -14,6 +14,50 @@ export const easeOutBack = (t) => {
14
14
  const c3 = c1 + 1;
15
15
  return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
16
16
  };
17
+ /**
18
+ * Anticipation easing: dips below the start value before climbing to 1.
19
+ * The classic cartoon wind-up, a character crouching before the jump.
20
+ */
21
+ export const easeInBack = (t) => {
22
+ const c1 = 1.70158;
23
+ const c3 = c1 + 1;
24
+ return c3 * t * t * t - c1 * t * t;
25
+ };
26
+ /** Overshoot at both ends: winds up, fires past the target, settles back. */
27
+ export const easeInOutBack = (t) => {
28
+ const c1 = 1.70158;
29
+ const c2 = c1 * 1.525;
30
+ return t < 0.5
31
+ ? (Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
32
+ : (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
33
+ };
34
+ /**
35
+ * Elastic wobble: overshoots and oscillates with decaying amplitude,
36
+ * like a plucked rubber band or a jelly landing.
37
+ */
38
+ export const easeOutElastic = (t) => {
39
+ if (t <= 0)
40
+ return 0;
41
+ if (t >= 1)
42
+ return 1;
43
+ const c4 = (2 * Math.PI) / 3;
44
+ return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
45
+ };
46
+ /**
47
+ * Cartoon bounce: hits the end value with a series of shrinking hops,
48
+ * like a dropped rubber ball.
49
+ */
50
+ export const easeOutBounce = (t) => {
51
+ const n1 = 7.5625;
52
+ const d1 = 2.75;
53
+ if (t < 1 / d1)
54
+ return n1 * t * t;
55
+ if (t < 2 / d1)
56
+ return n1 * (t -= 1.5 / d1) * t + 0.75;
57
+ if (t < 2.5 / d1)
58
+ return n1 * (t -= 2.25 / d1) * t + 0.9375;
59
+ return n1 * (t -= 2.625 / d1) * t + 0.984375;
60
+ };
17
61
  /**
18
62
  * Cubic bezier easing, same parameters as CSS `cubic-bezier(x1, y1, x2, y2)`.
19
63
  */
@@ -67,8 +111,12 @@ export const easings = {
67
111
  easeInOutQuart,
68
112
  easeOutExpo,
69
113
  easeOutBack,
114
+ easeInBack,
115
+ easeInOutBack,
116
+ easeOutElastic,
117
+ easeOutBounce,
70
118
  };
71
- /** Accept an easing function or its name; throws on unknown names. */
119
+ /** Accept an easing function or its name. Throws on unknown names. */
72
120
  export function resolveEasing(easing) {
73
121
  if (!easing)
74
122
  return easeOutCubic;
package/dist/flip.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { type AnimateOptions, type AnimationControls } from "./animate.js";
2
+ export interface FlipOptions {
3
+ /** Duration in milliseconds. Default 400. */
4
+ duration?: number;
5
+ /** Delay before starting, in milliseconds. Default 0. */
6
+ delay?: number;
7
+ /** Easing function or name. Default "easeOutCubic". */
8
+ easing?: AnimateOptions["easing"];
9
+ /**
10
+ * Also animate the size delta as scale, so growing or shrinking
11
+ * elements morph instead of just sliding. Default true.
12
+ */
13
+ scale?: boolean;
14
+ }
15
+ /**
16
+ * FLIP layout animation around a DOM mutation.
17
+ *
18
+ * Records the element's position and size (First), runs your `mutate()`
19
+ * which changes the layout (Last), then Inverts the delta as a transform
20
+ * and Plays it back to identity. List reorders, expanding panels, and
21
+ * grid reshuffles glide to their new spots instead of jumping.
22
+ *
23
+ * The element's pre-existing `transform` is captured and restored after
24
+ * the animation, so FLIP composes with other transform animations.
25
+ * `stop()` halts mid-flight and restores the original transform.
26
+ *
27
+ * SSR-safe and reduced-motion safe: the mutation runs with no animation.
28
+ * If the element does not move, no animation runs either.
29
+ *
30
+ * ```tsx
31
+ * import { animateFlip } from "solid-drift"
32
+ *
33
+ * const [items, setItems] = createSignal(["a", "b", "c"])
34
+ * let list!: HTMLUListElement
35
+ *
36
+ * const shuffle = () =>
37
+ * animateFlip(
38
+ * () => list,
39
+ * () => setItems((prev) => [...prev].reverse()),
40
+ * { duration: 450 },
41
+ * )
42
+ * ```
43
+ */
44
+ export declare function animateFlip(ref: () => Element | null | undefined, mutate: () => void, options?: FlipOptions): AnimationControls;