fancy-ui-svelte 0.6.0 → 0.8.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 +84 -71
- package/dist/fancy-ui/fluid-cursor/FluidCursor.svelte +1132 -1111
- package/dist/fancy-ui/fluid-cursor/FluidCursor.svelte.d.ts +3 -5
- package/dist/fancy-ui/fluid-cursor/FluidCursor.test.js +29 -0
- package/dist/fancy-ui/fluid-cursor/README.md +57 -6
- package/dist/fancy-ui/fluid-cursor/fluid-shared.d.ts +40 -0
- package/dist/fancy-ui/fluid-cursor/fluid-shared.js +125 -0
- package/dist/fancy-ui/fluid-cursor/fluid-shared.test.d.ts +1 -0
- package/dist/fancy-ui/fluid-cursor/fluid-shared.test.js +39 -0
- package/dist/fancy-ui/fluid-cursor/webgpu-engine.d.ts +29 -0
- package/dist/fancy-ui/fluid-cursor/webgpu-engine.js +847 -0
- package/dist/fancy-ui/frosted-glass/FrostedGlass.svelte +204 -0
- package/dist/fancy-ui/frosted-glass/FrostedGlass.svelte.d.ts +20 -0
- package/dist/fancy-ui/frosted-glass/FrostedGlass.test.d.ts +1 -0
- package/dist/fancy-ui/frosted-glass/FrostedGlass.test.js +48 -0
- package/dist/fancy-ui/frosted-glass/README.md +61 -0
- package/dist/fancy-ui/frosted-glass/index.d.ts +1 -0
- package/dist/fancy-ui/frosted-glass/index.js +1 -0
- package/dist/fancy-ui/index.d.ts +2 -0
- package/dist/fancy-ui/index.js +2 -0
- package/dist/fancy-ui/liquid-glass/LiquidGlass.svelte +19 -2
- package/dist/fancy-ui/liquid-glass/LiquidGlass.svelte.d.ts +4 -0
- package/dist/fancy-ui/liquid-glass/LiquidGlass.test.js +14 -0
- package/dist/fancy-ui/liquid-glass/README.md +7 -1
- package/dist/fancy-ui/liquid-text/LiquidText.svelte +1151 -0
- package/dist/fancy-ui/liquid-text/LiquidText.svelte.d.ts +37 -0
- package/dist/fancy-ui/liquid-text/LiquidText.test.d.ts +1 -0
- package/dist/fancy-ui/liquid-text/LiquidText.test.js +219 -0
- package/dist/fancy-ui/liquid-text/README.md +139 -0
- package/dist/fancy-ui/liquid-text/index.d.ts +2 -0
- package/dist/fancy-ui/liquid-text/index.js +1 -0
- package/dist/fancy-ui/registry.js +192 -0
- package/dist/fancy-ui/themes.d.ts +38 -0
- package/dist/fancy-ui/themes.js +356 -0
- package/dist/utils/animation.d.ts +109 -0
- package/dist/utils/animation.js +198 -0
- package/dist/utils/color.d.ts +128 -0
- package/dist/utils/color.js +314 -0
- package/dist/utils/geometry.d.ts +125 -0
- package/dist/utils/geometry.js +250 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.js +39 -0
- package/package.json +13 -4
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme registry (docs-site theming data).
|
|
3
|
+
*
|
|
4
|
+
* A named theme is a set of CSS-variable overrides applied on top of the base
|
|
5
|
+
* light/dark token sets defined in `src/routes/layout.css`. The theme store
|
|
6
|
+
* (`src/lib/stores/theme.svelte.ts`) applies a theme by setting these variables
|
|
7
|
+
* inline on `<html>`, toggling the `.dark` class per `colorScheme`, and setting
|
|
8
|
+
* a `data-theme` attribute.
|
|
9
|
+
*
|
|
10
|
+
* NOTE: this module is docs/theming data only. It is NOT imported by any shipped
|
|
11
|
+
* component in `src/lib/fancy-ui/*`, so it does not affect the published package.
|
|
12
|
+
*/
|
|
13
|
+
/** Every CSS variable a theme may set. The store clears these before applying a theme. */
|
|
14
|
+
export const MANAGED_VARS = [
|
|
15
|
+
"--background",
|
|
16
|
+
"--foreground",
|
|
17
|
+
"--card",
|
|
18
|
+
"--card-foreground",
|
|
19
|
+
"--popover",
|
|
20
|
+
"--popover-foreground",
|
|
21
|
+
"--primary",
|
|
22
|
+
"--primary-foreground",
|
|
23
|
+
"--secondary",
|
|
24
|
+
"--secondary-foreground",
|
|
25
|
+
"--muted",
|
|
26
|
+
"--muted-foreground",
|
|
27
|
+
"--accent",
|
|
28
|
+
"--accent-foreground",
|
|
29
|
+
"--border",
|
|
30
|
+
"--input",
|
|
31
|
+
"--ring",
|
|
32
|
+
"--radius",
|
|
33
|
+
"--rainbow-1",
|
|
34
|
+
"--rainbow-2",
|
|
35
|
+
"--rainbow-3",
|
|
36
|
+
"--rainbow-4",
|
|
37
|
+
"--rainbow-5",
|
|
38
|
+
"--sidebar",
|
|
39
|
+
"--sidebar-foreground",
|
|
40
|
+
"--sidebar-primary",
|
|
41
|
+
"--sidebar-primary-foreground",
|
|
42
|
+
"--sidebar-accent",
|
|
43
|
+
"--sidebar-accent-foreground",
|
|
44
|
+
"--sidebar-border",
|
|
45
|
+
];
|
|
46
|
+
const DEFAULT_RAINBOW = [
|
|
47
|
+
"hsl(0 100% 63%)",
|
|
48
|
+
"hsl(270 100% 63%)",
|
|
49
|
+
"hsl(210 100% 63%)",
|
|
50
|
+
"hsl(195 100% 63%)",
|
|
51
|
+
"hsl(90 100% 63%)",
|
|
52
|
+
];
|
|
53
|
+
/** Expand a compact spec into a full ThemeDef with a complete token map. */
|
|
54
|
+
function defineTheme(s) {
|
|
55
|
+
const card = s.card ?? s.bg;
|
|
56
|
+
const secondary = s.secondary ?? s.accent;
|
|
57
|
+
const secondaryFg = s.secondaryFg ?? s.accentFg;
|
|
58
|
+
const muted = s.muted ?? s.border ?? card;
|
|
59
|
+
const mutedFg = s.mutedFg ?? s.fg;
|
|
60
|
+
const border = s.border ?? s.muted ?? s.fg;
|
|
61
|
+
const ring = s.ring ?? s.primary;
|
|
62
|
+
const radius = s.radius ?? "0.625rem";
|
|
63
|
+
const rainbow = s.rainbow ?? DEFAULT_RAINBOW;
|
|
64
|
+
return {
|
|
65
|
+
name: s.name,
|
|
66
|
+
label: s.label,
|
|
67
|
+
colorScheme: s.colorScheme,
|
|
68
|
+
swatch: [s.primary, s.accent, secondary, s.bg],
|
|
69
|
+
tokens: {
|
|
70
|
+
"--background": s.bg,
|
|
71
|
+
"--foreground": s.fg,
|
|
72
|
+
"--card": card,
|
|
73
|
+
"--card-foreground": s.fg,
|
|
74
|
+
"--popover": card,
|
|
75
|
+
"--popover-foreground": s.fg,
|
|
76
|
+
"--primary": s.primary,
|
|
77
|
+
"--primary-foreground": s.primaryFg,
|
|
78
|
+
"--secondary": secondary,
|
|
79
|
+
"--secondary-foreground": secondaryFg,
|
|
80
|
+
"--muted": muted,
|
|
81
|
+
"--muted-foreground": mutedFg,
|
|
82
|
+
"--accent": s.accent,
|
|
83
|
+
"--accent-foreground": s.accentFg,
|
|
84
|
+
"--border": border,
|
|
85
|
+
"--input": border,
|
|
86
|
+
"--ring": ring,
|
|
87
|
+
"--radius": radius,
|
|
88
|
+
"--rainbow-1": rainbow[0],
|
|
89
|
+
"--rainbow-2": rainbow[1],
|
|
90
|
+
"--rainbow-3": rainbow[2],
|
|
91
|
+
"--rainbow-4": rainbow[3],
|
|
92
|
+
"--rainbow-5": rainbow[4],
|
|
93
|
+
"--sidebar": card,
|
|
94
|
+
"--sidebar-foreground": s.fg,
|
|
95
|
+
"--sidebar-primary": s.primary,
|
|
96
|
+
"--sidebar-primary-foreground": s.primaryFg,
|
|
97
|
+
"--sidebar-accent": muted,
|
|
98
|
+
"--sidebar-accent-foreground": s.fg,
|
|
99
|
+
"--sidebar-border": border,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The theme list.
|
|
105
|
+
*
|
|
106
|
+
* `light` and `dark` carry no token overrides — they are the base look defined
|
|
107
|
+
* by `:root` / `.dark` in `layout.css`. The remaining themes are self-contained.
|
|
108
|
+
* `sunset` / `ocean` / `mono` mirror the theme-generator presets.
|
|
109
|
+
*/
|
|
110
|
+
export const themes = [
|
|
111
|
+
{
|
|
112
|
+
name: "light",
|
|
113
|
+
label: "Light",
|
|
114
|
+
colorScheme: "light",
|
|
115
|
+
tokens: {},
|
|
116
|
+
swatch: [
|
|
117
|
+
"oklch(0.208 0.042 265.755)",
|
|
118
|
+
"oklch(0.65 0.15 265)",
|
|
119
|
+
"oklch(0.929 0.013 255.508)",
|
|
120
|
+
"#ffffff",
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: "dark",
|
|
125
|
+
label: "Dark",
|
|
126
|
+
colorScheme: "dark",
|
|
127
|
+
tokens: {},
|
|
128
|
+
swatch: [
|
|
129
|
+
"oklch(0.929 0.013 255.508)",
|
|
130
|
+
"oklch(0.7 0.15 265)",
|
|
131
|
+
"oklch(0.15 0.005 260)",
|
|
132
|
+
"#0a0a0a",
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
defineTheme({
|
|
136
|
+
name: "cupcake",
|
|
137
|
+
label: "Cupcake",
|
|
138
|
+
colorScheme: "light",
|
|
139
|
+
bg: "#faf7f5",
|
|
140
|
+
fg: "#291334",
|
|
141
|
+
card: "#ffffff",
|
|
142
|
+
primary: "#65c3c8",
|
|
143
|
+
primaryFg: "#004b50",
|
|
144
|
+
secondary: "#ef9fbc",
|
|
145
|
+
secondaryFg: "#5c2437",
|
|
146
|
+
accent: "#eeaf3a",
|
|
147
|
+
accentFg: "#4a3000",
|
|
148
|
+
border: "#e7e2df",
|
|
149
|
+
radius: "1rem",
|
|
150
|
+
}),
|
|
151
|
+
defineTheme({
|
|
152
|
+
name: "emerald",
|
|
153
|
+
label: "Emerald",
|
|
154
|
+
colorScheme: "light",
|
|
155
|
+
bg: "#ffffff",
|
|
156
|
+
fg: "#333c4d",
|
|
157
|
+
primary: "#66cc8a",
|
|
158
|
+
primaryFg: "#0c3d24",
|
|
159
|
+
secondary: "#377cfb",
|
|
160
|
+
secondaryFg: "#ffffff",
|
|
161
|
+
accent: "#ea5234",
|
|
162
|
+
accentFg: "#ffffff",
|
|
163
|
+
border: "#e5e7eb",
|
|
164
|
+
radius: "0.5rem",
|
|
165
|
+
}),
|
|
166
|
+
defineTheme({
|
|
167
|
+
name: "corporate",
|
|
168
|
+
label: "Corporate",
|
|
169
|
+
colorScheme: "light",
|
|
170
|
+
bg: "#ffffff",
|
|
171
|
+
fg: "#181a2a",
|
|
172
|
+
primary: "#4b6bfb",
|
|
173
|
+
primaryFg: "#ffffff",
|
|
174
|
+
secondary: "#7b92b2",
|
|
175
|
+
secondaryFg: "#ffffff",
|
|
176
|
+
accent: "#67cba0",
|
|
177
|
+
accentFg: "#00382a",
|
|
178
|
+
border: "#e5e7eb",
|
|
179
|
+
radius: "0.25rem",
|
|
180
|
+
}),
|
|
181
|
+
defineTheme({
|
|
182
|
+
name: "retro",
|
|
183
|
+
label: "Retro",
|
|
184
|
+
colorScheme: "light",
|
|
185
|
+
bg: "#ece3ca",
|
|
186
|
+
fg: "#282425",
|
|
187
|
+
card: "#e4d8b4",
|
|
188
|
+
primary: "#ef9995",
|
|
189
|
+
primaryFg: "#282425",
|
|
190
|
+
secondary: "#a4cbb4",
|
|
191
|
+
secondaryFg: "#282425",
|
|
192
|
+
accent: "#dc8850",
|
|
193
|
+
accentFg: "#282425",
|
|
194
|
+
border: "#d1c7a3",
|
|
195
|
+
radius: "0.5rem",
|
|
196
|
+
}),
|
|
197
|
+
defineTheme({
|
|
198
|
+
name: "cyberpunk",
|
|
199
|
+
label: "Cyberpunk",
|
|
200
|
+
colorScheme: "light",
|
|
201
|
+
bg: "#fff248",
|
|
202
|
+
fg: "#0f0f00",
|
|
203
|
+
card: "#fdf700",
|
|
204
|
+
primary: "#ff7598",
|
|
205
|
+
primaryFg: "#330014",
|
|
206
|
+
secondary: "#75d1f0",
|
|
207
|
+
secondaryFg: "#00222e",
|
|
208
|
+
accent: "#c07eec",
|
|
209
|
+
accentFg: "#1e0033",
|
|
210
|
+
border: "#e6dc00",
|
|
211
|
+
radius: "0rem",
|
|
212
|
+
rainbow: [
|
|
213
|
+
"hsl(330 100% 63%)",
|
|
214
|
+
"hsl(280 100% 63%)",
|
|
215
|
+
"hsl(190 100% 60%)",
|
|
216
|
+
"hsl(55 100% 55%)",
|
|
217
|
+
"hsl(150 100% 55%)",
|
|
218
|
+
],
|
|
219
|
+
}),
|
|
220
|
+
defineTheme({
|
|
221
|
+
name: "synthwave",
|
|
222
|
+
label: "Synthwave",
|
|
223
|
+
colorScheme: "dark",
|
|
224
|
+
bg: "#1a103d",
|
|
225
|
+
fg: "#f9f7fd",
|
|
226
|
+
card: "#241650",
|
|
227
|
+
primary: "#e779c1",
|
|
228
|
+
primaryFg: "#2a0e2b",
|
|
229
|
+
secondary: "#58c7f3",
|
|
230
|
+
secondaryFg: "#003044",
|
|
231
|
+
accent: "#f3cc30",
|
|
232
|
+
accentFg: "#3a2e00",
|
|
233
|
+
muted: "#2b1c5e",
|
|
234
|
+
mutedFg: "#b9a9e6",
|
|
235
|
+
border: "#3a2a6b",
|
|
236
|
+
radius: "0.75rem",
|
|
237
|
+
rainbow: [
|
|
238
|
+
"hsl(320 90% 65%)",
|
|
239
|
+
"hsl(280 90% 68%)",
|
|
240
|
+
"hsl(195 95% 60%)",
|
|
241
|
+
"hsl(48 95% 58%)",
|
|
242
|
+
"hsl(160 80% 55%)",
|
|
243
|
+
],
|
|
244
|
+
}),
|
|
245
|
+
defineTheme({
|
|
246
|
+
name: "dracula",
|
|
247
|
+
label: "Dracula",
|
|
248
|
+
colorScheme: "dark",
|
|
249
|
+
bg: "#282a36",
|
|
250
|
+
fg: "#f8f8f2",
|
|
251
|
+
card: "#343746",
|
|
252
|
+
primary: "#ff79c6",
|
|
253
|
+
primaryFg: "#28202b",
|
|
254
|
+
secondary: "#bd93f9",
|
|
255
|
+
secondaryFg: "#241a33",
|
|
256
|
+
accent: "#ffb86c",
|
|
257
|
+
accentFg: "#3a2600",
|
|
258
|
+
muted: "#3a3d4d",
|
|
259
|
+
mutedFg: "#c7c9d6",
|
|
260
|
+
border: "#44475a",
|
|
261
|
+
radius: "0.5rem",
|
|
262
|
+
}),
|
|
263
|
+
defineTheme({
|
|
264
|
+
name: "forest",
|
|
265
|
+
label: "Forest",
|
|
266
|
+
colorScheme: "dark",
|
|
267
|
+
bg: "#171212",
|
|
268
|
+
fg: "#e0ded9",
|
|
269
|
+
card: "#1f1a1a",
|
|
270
|
+
primary: "#1eb854",
|
|
271
|
+
primaryFg: "#04220f",
|
|
272
|
+
secondary: "#1fd65f",
|
|
273
|
+
secondaryFg: "#04220f",
|
|
274
|
+
accent: "#d99330",
|
|
275
|
+
accentFg: "#2b1c00",
|
|
276
|
+
muted: "#26201f",
|
|
277
|
+
mutedFg: "#b3b0aa",
|
|
278
|
+
border: "#2e2726",
|
|
279
|
+
radius: "0.75rem",
|
|
280
|
+
}),
|
|
281
|
+
defineTheme({
|
|
282
|
+
name: "sunset",
|
|
283
|
+
label: "Sunset",
|
|
284
|
+
colorScheme: "dark",
|
|
285
|
+
bg: "#1c1410",
|
|
286
|
+
fg: "#f5e9e0",
|
|
287
|
+
card: "#261a13",
|
|
288
|
+
primary: "oklch(0.62 0.19 30)",
|
|
289
|
+
primaryFg: "#22100a",
|
|
290
|
+
secondary: "oklch(0.7 0.17 8)",
|
|
291
|
+
secondaryFg: "#2a0d0a",
|
|
292
|
+
accent: "oklch(0.7 0.17 8)",
|
|
293
|
+
accentFg: "#2a0d0a",
|
|
294
|
+
muted: "#33241b",
|
|
295
|
+
mutedFg: "#d8c3b4",
|
|
296
|
+
border: "#3a2a20",
|
|
297
|
+
radius: "1rem",
|
|
298
|
+
rainbow: [
|
|
299
|
+
"hsl(12 100% 63%)",
|
|
300
|
+
"hsl(30 100% 63%)",
|
|
301
|
+
"hsl(350 100% 63%)",
|
|
302
|
+
"hsl(320 100% 63%)",
|
|
303
|
+
"hsl(50 100% 63%)",
|
|
304
|
+
],
|
|
305
|
+
}),
|
|
306
|
+
defineTheme({
|
|
307
|
+
name: "ocean",
|
|
308
|
+
label: "Ocean",
|
|
309
|
+
colorScheme: "light",
|
|
310
|
+
bg: "#f4fbff",
|
|
311
|
+
fg: "#0b2a3a",
|
|
312
|
+
card: "#ffffff",
|
|
313
|
+
primary: "oklch(0.55 0.13 230)",
|
|
314
|
+
primaryFg: "#ffffff",
|
|
315
|
+
secondary: "oklch(0.72 0.13 190)",
|
|
316
|
+
secondaryFg: "#00303a",
|
|
317
|
+
accent: "oklch(0.72 0.13 190)",
|
|
318
|
+
accentFg: "#00303a",
|
|
319
|
+
muted: "#e3f1f9",
|
|
320
|
+
mutedFg: "#3a5c6b",
|
|
321
|
+
border: "#d3e7f0",
|
|
322
|
+
radius: "0.5rem",
|
|
323
|
+
rainbow: [
|
|
324
|
+
"hsl(200 100% 63%)",
|
|
325
|
+
"hsl(220 100% 63%)",
|
|
326
|
+
"hsl(180 100% 63%)",
|
|
327
|
+
"hsl(240 100% 63%)",
|
|
328
|
+
"hsl(160 100% 63%)",
|
|
329
|
+
],
|
|
330
|
+
}),
|
|
331
|
+
defineTheme({
|
|
332
|
+
name: "mono",
|
|
333
|
+
label: "Mono",
|
|
334
|
+
colorScheme: "dark",
|
|
335
|
+
bg: "#0a0a0a",
|
|
336
|
+
fg: "#fafafa",
|
|
337
|
+
card: "#161616",
|
|
338
|
+
primary: "oklch(0.32 0 0)",
|
|
339
|
+
primaryFg: "#fafafa",
|
|
340
|
+
secondary: "oklch(0.6 0 0)",
|
|
341
|
+
secondaryFg: "#0a0a0a",
|
|
342
|
+
accent: "oklch(0.6 0 0)",
|
|
343
|
+
accentFg: "#0a0a0a",
|
|
344
|
+
muted: "#1e1e1e",
|
|
345
|
+
mutedFg: "#a3a3a3",
|
|
346
|
+
border: "#2a2a2a",
|
|
347
|
+
radius: "0.25rem",
|
|
348
|
+
rainbow: ["hsl(0 0% 80%)", "hsl(0 0% 65%)", "hsl(0 0% 90%)", "hsl(0 0% 55%)", "hsl(0 0% 75%)"],
|
|
349
|
+
}),
|
|
350
|
+
];
|
|
351
|
+
const themeByName = new Map(themes.map((t) => [t.name, t]));
|
|
352
|
+
export function getTheme(name) {
|
|
353
|
+
return themeByName.get(name);
|
|
354
|
+
}
|
|
355
|
+
export const themeNames = themes.map((t) => t.name);
|
|
356
|
+
export const DEFAULT_THEME = "light";
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helpers for creating smooth animations, spring physics, and easing functions.
|
|
5
|
+
* Used across many FancyUI components for consistent animation behavior.
|
|
6
|
+
*/
|
|
7
|
+
export interface SpringConfig {
|
|
8
|
+
/** Stiffness of the spring (default: 100) */
|
|
9
|
+
stiffness: number;
|
|
10
|
+
/** Damping ratio (default: 10) */
|
|
11
|
+
damping: number;
|
|
12
|
+
/** Mass of the object (default: 1) */
|
|
13
|
+
mass: number;
|
|
14
|
+
}
|
|
15
|
+
export interface AnimationOptions {
|
|
16
|
+
/** Duration in milliseconds */
|
|
17
|
+
duration: number;
|
|
18
|
+
/** Easing function */
|
|
19
|
+
easing?: (t: number) => number;
|
|
20
|
+
/** Delay before starting in milliseconds */
|
|
21
|
+
delay?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Pre-configured spring settings for common use cases
|
|
25
|
+
*/
|
|
26
|
+
export declare const springPresets: Record<string, SpringConfig>;
|
|
27
|
+
/**
|
|
28
|
+
* Linear easing (no easing)
|
|
29
|
+
*/
|
|
30
|
+
export declare function linear(t: number): number;
|
|
31
|
+
/**
|
|
32
|
+
* Ease in (accelerating)
|
|
33
|
+
*/
|
|
34
|
+
export declare function easeIn(t: number): number;
|
|
35
|
+
/**
|
|
36
|
+
* Ease out (decelerating)
|
|
37
|
+
*/
|
|
38
|
+
export declare function easeOut(t: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Ease in-out (accelerate then decelerate)
|
|
41
|
+
*/
|
|
42
|
+
export declare function easeInOut(t: number): number;
|
|
43
|
+
/**
|
|
44
|
+
* Cubic ease in
|
|
45
|
+
*/
|
|
46
|
+
export declare function easeInCubic(t: number): number;
|
|
47
|
+
/**
|
|
48
|
+
* Cubic ease out
|
|
49
|
+
*/
|
|
50
|
+
export declare function easeOutCubic(t: number): number;
|
|
51
|
+
/**
|
|
52
|
+
* Cubic ease in-out
|
|
53
|
+
*/
|
|
54
|
+
export declare function easeInOutCubic(t: number): number;
|
|
55
|
+
/**
|
|
56
|
+
* Bounce ease out
|
|
57
|
+
*/
|
|
58
|
+
export declare function easeOutBounce(t: number): number;
|
|
59
|
+
/**
|
|
60
|
+
* Elastic ease out
|
|
61
|
+
*/
|
|
62
|
+
export declare function easeOutElastic(t: number): number;
|
|
63
|
+
/**
|
|
64
|
+
* Back ease out (overshoots then settles)
|
|
65
|
+
*/
|
|
66
|
+
export declare function easeOutBack(t: number): number;
|
|
67
|
+
/**
|
|
68
|
+
* Interpolate between two values
|
|
69
|
+
*/
|
|
70
|
+
export declare function lerp(start: number, end: number, t: number): number;
|
|
71
|
+
/**
|
|
72
|
+
* Clamp a value between min and max
|
|
73
|
+
*/
|
|
74
|
+
export declare function clamp(value: number, min: number, max: number): number;
|
|
75
|
+
/**
|
|
76
|
+
* Map a value from one range to another
|
|
77
|
+
*/
|
|
78
|
+
export declare function mapRange(value: number, inMin: number, inMax: number, outMin: number, outMax: number): number;
|
|
79
|
+
/**
|
|
80
|
+
* Calculate spring physics for a single step
|
|
81
|
+
*/
|
|
82
|
+
export declare function springStep(current: number, target: number, velocity: number, config: SpringConfig, deltaTime: number): {
|
|
83
|
+
position: number;
|
|
84
|
+
velocity: number;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Check if a spring animation is at rest
|
|
88
|
+
*/
|
|
89
|
+
export declare function isSpringAtRest(current: number, target: number, velocity: number, threshold?: number): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Create a staggered delay for list animations
|
|
92
|
+
*/
|
|
93
|
+
export declare function staggerDelay(index: number, baseDelay?: number): number;
|
|
94
|
+
/**
|
|
95
|
+
* Calculate animation progress based on elapsed time
|
|
96
|
+
*/
|
|
97
|
+
export declare function getProgress(elapsed: number, duration: number): number;
|
|
98
|
+
/**
|
|
99
|
+
* Get duration value from CSS custom property or fallback
|
|
100
|
+
*/
|
|
101
|
+
export declare function getDurationFromCSS(property: "--animation-fast" | "--animation-normal" | "--animation-slow" | "--animation-slower", fallback?: number): number;
|
|
102
|
+
/**
|
|
103
|
+
* Debounce an animation frame callback
|
|
104
|
+
*/
|
|
105
|
+
export declare function rafDebounce<T extends (...args: unknown[]) => void>(fn: T): T;
|
|
106
|
+
/**
|
|
107
|
+
* Throttle function calls to animation frames
|
|
108
|
+
*/
|
|
109
|
+
export declare function rafThrottle<T extends (...args: unknown[]) => void>(fn: T): T;
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helpers for creating smooth animations, spring physics, and easing functions.
|
|
5
|
+
* Used across many FancyUI components for consistent animation behavior.
|
|
6
|
+
*/
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// Spring Presets
|
|
9
|
+
// =============================================================================
|
|
10
|
+
/**
|
|
11
|
+
* Pre-configured spring settings for common use cases
|
|
12
|
+
*/
|
|
13
|
+
export const springPresets = {
|
|
14
|
+
/** Default balanced spring */
|
|
15
|
+
default: { stiffness: 100, damping: 10, mass: 1 },
|
|
16
|
+
/** Gentle, slow spring */
|
|
17
|
+
gentle: { stiffness: 50, damping: 14, mass: 1 },
|
|
18
|
+
/** Wobbly, bouncy spring */
|
|
19
|
+
wobbly: { stiffness: 180, damping: 12, mass: 1 },
|
|
20
|
+
/** Stiff, snappy spring */
|
|
21
|
+
stiff: { stiffness: 210, damping: 20, mass: 1 },
|
|
22
|
+
/** Very slow, heavy spring */
|
|
23
|
+
slow: { stiffness: 50, damping: 20, mass: 1 },
|
|
24
|
+
/** Quick, responsive spring */
|
|
25
|
+
quick: { stiffness: 300, damping: 25, mass: 1 },
|
|
26
|
+
};
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// Easing Functions
|
|
29
|
+
// =============================================================================
|
|
30
|
+
/**
|
|
31
|
+
* Linear easing (no easing)
|
|
32
|
+
*/
|
|
33
|
+
export function linear(t) {
|
|
34
|
+
return t;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Ease in (accelerating)
|
|
38
|
+
*/
|
|
39
|
+
export function easeIn(t) {
|
|
40
|
+
return t * t;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Ease out (decelerating)
|
|
44
|
+
*/
|
|
45
|
+
export function easeOut(t) {
|
|
46
|
+
return t * (2 - t);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Ease in-out (accelerate then decelerate)
|
|
50
|
+
*/
|
|
51
|
+
export function easeInOut(t) {
|
|
52
|
+
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Cubic ease in
|
|
56
|
+
*/
|
|
57
|
+
export function easeInCubic(t) {
|
|
58
|
+
return t * t * t;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Cubic ease out
|
|
62
|
+
*/
|
|
63
|
+
export function easeOutCubic(t) {
|
|
64
|
+
return 1 - Math.pow(1 - t, 3);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Cubic ease in-out
|
|
68
|
+
*/
|
|
69
|
+
export function easeInOutCubic(t) {
|
|
70
|
+
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Bounce ease out
|
|
74
|
+
*/
|
|
75
|
+
export function easeOutBounce(t) {
|
|
76
|
+
const n1 = 7.5625;
|
|
77
|
+
const d1 = 2.75;
|
|
78
|
+
if (t < 1 / d1) {
|
|
79
|
+
return n1 * t * t;
|
|
80
|
+
}
|
|
81
|
+
else if (t < 2 / d1) {
|
|
82
|
+
return n1 * (t -= 1.5 / d1) * t + 0.75;
|
|
83
|
+
}
|
|
84
|
+
else if (t < 2.5 / d1) {
|
|
85
|
+
return n1 * (t -= 2.25 / d1) * t + 0.9375;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
return n1 * (t -= 2.625 / d1) * t + 0.984375;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Elastic ease out
|
|
93
|
+
*/
|
|
94
|
+
export function easeOutElastic(t) {
|
|
95
|
+
const c4 = (2 * Math.PI) / 3;
|
|
96
|
+
return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Back ease out (overshoots then settles)
|
|
100
|
+
*/
|
|
101
|
+
export function easeOutBack(t) {
|
|
102
|
+
const c1 = 1.70158;
|
|
103
|
+
const c3 = c1 + 1;
|
|
104
|
+
return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
|
|
105
|
+
}
|
|
106
|
+
// =============================================================================
|
|
107
|
+
// Animation Helpers
|
|
108
|
+
// =============================================================================
|
|
109
|
+
/**
|
|
110
|
+
* Interpolate between two values
|
|
111
|
+
*/
|
|
112
|
+
export function lerp(start, end, t) {
|
|
113
|
+
return start + (end - start) * t;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Clamp a value between min and max
|
|
117
|
+
*/
|
|
118
|
+
export function clamp(value, min, max) {
|
|
119
|
+
return Math.min(Math.max(value, min), max);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Map a value from one range to another
|
|
123
|
+
*/
|
|
124
|
+
export function mapRange(value, inMin, inMax, outMin, outMax) {
|
|
125
|
+
return ((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Calculate spring physics for a single step
|
|
129
|
+
*/
|
|
130
|
+
export function springStep(current, target, velocity, config, deltaTime) {
|
|
131
|
+
const { stiffness, damping, mass } = config;
|
|
132
|
+
// Spring force: F = -kx - cv
|
|
133
|
+
const springForce = -stiffness * (current - target);
|
|
134
|
+
const dampingForce = -damping * velocity;
|
|
135
|
+
const acceleration = (springForce + dampingForce) / mass;
|
|
136
|
+
const newVelocity = velocity + acceleration * deltaTime;
|
|
137
|
+
const newPosition = current + newVelocity * deltaTime;
|
|
138
|
+
return { position: newPosition, velocity: newVelocity };
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if a spring animation is at rest
|
|
142
|
+
*/
|
|
143
|
+
export function isSpringAtRest(current, target, velocity, threshold = 0.001) {
|
|
144
|
+
return Math.abs(current - target) < threshold && Math.abs(velocity) < threshold;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Create a staggered delay for list animations
|
|
148
|
+
*/
|
|
149
|
+
export function staggerDelay(index, baseDelay = 50) {
|
|
150
|
+
return index * baseDelay;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Calculate animation progress based on elapsed time
|
|
154
|
+
*/
|
|
155
|
+
export function getProgress(elapsed, duration) {
|
|
156
|
+
return clamp(elapsed / duration, 0, 1);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get duration value from CSS custom property or fallback
|
|
160
|
+
*/
|
|
161
|
+
export function getDurationFromCSS(property, fallback = 300) {
|
|
162
|
+
if (typeof window === "undefined")
|
|
163
|
+
return fallback;
|
|
164
|
+
const value = getComputedStyle(document.documentElement).getPropertyValue(property).trim();
|
|
165
|
+
const parsed = parseInt(value, 10);
|
|
166
|
+
return isNaN(parsed) ? fallback : parsed;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Debounce an animation frame callback
|
|
170
|
+
*/
|
|
171
|
+
export function rafDebounce(fn) {
|
|
172
|
+
let frameId = null;
|
|
173
|
+
return ((...args) => {
|
|
174
|
+
if (frameId !== null) {
|
|
175
|
+
cancelAnimationFrame(frameId);
|
|
176
|
+
}
|
|
177
|
+
frameId = requestAnimationFrame(() => {
|
|
178
|
+
fn(...args);
|
|
179
|
+
frameId = null;
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Throttle function calls to animation frames
|
|
185
|
+
*/
|
|
186
|
+
export function rafThrottle(fn) {
|
|
187
|
+
let frameId = null;
|
|
188
|
+
let lastArgs = null;
|
|
189
|
+
return ((...args) => {
|
|
190
|
+
lastArgs = args;
|
|
191
|
+
if (frameId === null) {
|
|
192
|
+
frameId = requestAnimationFrame(() => {
|
|
193
|
+
fn(...lastArgs);
|
|
194
|
+
frameId = null;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|