fancy-ui-svelte 0.5.0 → 0.7.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 +98 -74
- package/dist/fancy-ui/dock/index.d.ts +1 -1
- package/dist/fancy-ui/dock/index.js +0 -1
- package/dist/fancy-ui/editorial-engine/EditorialEngine.svelte +181 -0
- package/dist/fancy-ui/editorial-engine/EditorialEngine.svelte.d.ts +26 -0
- package/dist/fancy-ui/editorial-engine/README.md +56 -0
- package/dist/fancy-ui/editorial-engine/engine.d.ts +7 -0
- package/dist/fancy-ui/editorial-engine/engine.js +581 -0
- package/dist/fancy-ui/editorial-engine/index.d.ts +2 -0
- package/dist/fancy-ui/editorial-engine/index.js +1 -0
- package/dist/fancy-ui/frosted-glass/FrostedGlass.svelte +202 -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 +59 -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 +5 -0
- package/dist/fancy-ui/index.js +5 -0
- package/dist/fancy-ui/line-reveal/LineReveal.svelte +168 -0
- package/dist/fancy-ui/line-reveal/LineReveal.svelte.d.ts +33 -0
- package/dist/fancy-ui/line-reveal/README.md +42 -0
- package/dist/fancy-ui/line-reveal/index.d.ts +2 -0
- package/dist/fancy-ui/line-reveal/index.js +1 -0
- package/dist/fancy-ui/noise-reveal/NoiseReveal.svelte +323 -0
- package/dist/fancy-ui/noise-reveal/NoiseReveal.svelte.d.ts +19 -0
- package/dist/fancy-ui/noise-reveal/NoiseReveal.test.d.ts +1 -0
- package/dist/fancy-ui/noise-reveal/NoiseReveal.test.js +123 -0
- package/dist/fancy-ui/noise-reveal/index.d.ts +2 -0
- package/dist/fancy-ui/noise-reveal/index.js +1 -0
- package/dist/fancy-ui/registry.js +196 -11
- package/dist/fancy-ui/themes.d.ts +38 -0
- package/dist/fancy-ui/themes.js +356 -0
- package/dist/types.d.ts +2 -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 -3
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helpers for color manipulation, gradients, and OKLCH color space operations.
|
|
5
|
+
* Supports dynamic color effects in beam, glow, and gradient components.
|
|
6
|
+
*/
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// Color Parsing
|
|
9
|
+
// =============================================================================
|
|
10
|
+
/**
|
|
11
|
+
* Parse a hex color to RGB
|
|
12
|
+
*/
|
|
13
|
+
export function hexToRgb(hex) {
|
|
14
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
15
|
+
return result
|
|
16
|
+
? {
|
|
17
|
+
r: parseInt(result[1], 16),
|
|
18
|
+
g: parseInt(result[2], 16),
|
|
19
|
+
b: parseInt(result[3], 16),
|
|
20
|
+
}
|
|
21
|
+
: null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convert RGB to hex
|
|
25
|
+
*/
|
|
26
|
+
export function rgbToHex(rgb) {
|
|
27
|
+
const toHex = (n) => Math.round(Math.max(0, Math.min(255, n)))
|
|
28
|
+
.toString(16)
|
|
29
|
+
.padStart(2, "0");
|
|
30
|
+
return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Parse an HSL string to HSL object
|
|
34
|
+
*/
|
|
35
|
+
export function parseHsl(hsl) {
|
|
36
|
+
const match = hsl.match(/hsl\(\s*(\d+)\s+(\d+)%\s+(\d+)%\s*\)/);
|
|
37
|
+
if (!match)
|
|
38
|
+
return null;
|
|
39
|
+
return {
|
|
40
|
+
h: parseInt(match[1], 10),
|
|
41
|
+
s: parseInt(match[2], 10),
|
|
42
|
+
l: parseInt(match[3], 10),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Convert HSL to CSS string
|
|
47
|
+
*/
|
|
48
|
+
export function hslToString(hsl) {
|
|
49
|
+
return `hsl(${hsl.h} ${hsl.s}% ${hsl.l}%)`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Parse an OKLCH string to OKLCH object
|
|
53
|
+
*/
|
|
54
|
+
export function parseOklch(oklch) {
|
|
55
|
+
const match = oklch.match(/oklch\(\s*([\d.]+)\s+([\d.]+)\s+([\d.]+)\s*\)/);
|
|
56
|
+
if (!match)
|
|
57
|
+
return null;
|
|
58
|
+
return {
|
|
59
|
+
l: parseFloat(match[1]),
|
|
60
|
+
c: parseFloat(match[2]),
|
|
61
|
+
h: parseFloat(match[3]),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Convert OKLCH to CSS string
|
|
66
|
+
*/
|
|
67
|
+
export function oklchToString(oklch) {
|
|
68
|
+
return `oklch(${oklch.l} ${oklch.c} ${oklch.h})`;
|
|
69
|
+
}
|
|
70
|
+
// =============================================================================
|
|
71
|
+
// Color Conversion
|
|
72
|
+
// =============================================================================
|
|
73
|
+
/**
|
|
74
|
+
* Convert RGB to HSL
|
|
75
|
+
*/
|
|
76
|
+
export function rgbToHsl(rgb) {
|
|
77
|
+
const r = rgb.r / 255;
|
|
78
|
+
const g = rgb.g / 255;
|
|
79
|
+
const b = rgb.b / 255;
|
|
80
|
+
const max = Math.max(r, g, b);
|
|
81
|
+
const min = Math.min(r, g, b);
|
|
82
|
+
const l = (max + min) / 2;
|
|
83
|
+
let h = 0;
|
|
84
|
+
let s = 0;
|
|
85
|
+
if (max !== min) {
|
|
86
|
+
const d = max - min;
|
|
87
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
88
|
+
switch (max) {
|
|
89
|
+
case r:
|
|
90
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
91
|
+
break;
|
|
92
|
+
case g:
|
|
93
|
+
h = ((b - r) / d + 2) / 6;
|
|
94
|
+
break;
|
|
95
|
+
case b:
|
|
96
|
+
h = ((r - g) / d + 4) / 6;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
h: Math.round(h * 360),
|
|
102
|
+
s: Math.round(s * 100),
|
|
103
|
+
l: Math.round(l * 100),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Convert HSL to RGB
|
|
108
|
+
*/
|
|
109
|
+
export function hslToRgb(hsl) {
|
|
110
|
+
const h = hsl.h / 360;
|
|
111
|
+
const s = hsl.s / 100;
|
|
112
|
+
const l = hsl.l / 100;
|
|
113
|
+
let r, g, b;
|
|
114
|
+
if (s === 0) {
|
|
115
|
+
r = g = b = l;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const hue2rgb = (p, q, t) => {
|
|
119
|
+
if (t < 0)
|
|
120
|
+
t += 1;
|
|
121
|
+
if (t > 1)
|
|
122
|
+
t -= 1;
|
|
123
|
+
if (t < 1 / 6)
|
|
124
|
+
return p + (q - p) * 6 * t;
|
|
125
|
+
if (t < 1 / 2)
|
|
126
|
+
return q;
|
|
127
|
+
if (t < 2 / 3)
|
|
128
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
129
|
+
return p;
|
|
130
|
+
};
|
|
131
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
132
|
+
const p = 2 * l - q;
|
|
133
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
134
|
+
g = hue2rgb(p, q, h);
|
|
135
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
r: Math.round(r * 255),
|
|
139
|
+
g: Math.round(g * 255),
|
|
140
|
+
b: Math.round(b * 255),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// =============================================================================
|
|
144
|
+
// Color Manipulation
|
|
145
|
+
// =============================================================================
|
|
146
|
+
/**
|
|
147
|
+
* Lighten a color by a percentage
|
|
148
|
+
*/
|
|
149
|
+
export function lighten(hsl, amount) {
|
|
150
|
+
return {
|
|
151
|
+
...hsl,
|
|
152
|
+
l: Math.min(100, hsl.l + amount),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Darken a color by a percentage
|
|
157
|
+
*/
|
|
158
|
+
export function darken(hsl, amount) {
|
|
159
|
+
return {
|
|
160
|
+
...hsl,
|
|
161
|
+
l: Math.max(0, hsl.l - amount),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Saturate a color by a percentage
|
|
166
|
+
*/
|
|
167
|
+
export function saturate(hsl, amount) {
|
|
168
|
+
return {
|
|
169
|
+
...hsl,
|
|
170
|
+
s: Math.min(100, hsl.s + amount),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Desaturate a color by a percentage
|
|
175
|
+
*/
|
|
176
|
+
export function desaturate(hsl, amount) {
|
|
177
|
+
return {
|
|
178
|
+
...hsl,
|
|
179
|
+
s: Math.max(0, hsl.s - amount),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Shift hue by degrees
|
|
184
|
+
*/
|
|
185
|
+
export function shiftHue(hsl, degrees) {
|
|
186
|
+
return {
|
|
187
|
+
...hsl,
|
|
188
|
+
h: (hsl.h + degrees + 360) % 360,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get complementary color
|
|
193
|
+
*/
|
|
194
|
+
export function complementary(hsl) {
|
|
195
|
+
return shiftHue(hsl, 180);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Interpolate between two colors
|
|
199
|
+
*/
|
|
200
|
+
export function interpolateColor(from, to, t) {
|
|
201
|
+
// Handle hue interpolation (shortest path)
|
|
202
|
+
let hDiff = to.h - from.h;
|
|
203
|
+
if (Math.abs(hDiff) > 180) {
|
|
204
|
+
hDiff = hDiff > 0 ? hDiff - 360 : hDiff + 360;
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
h: (from.h + hDiff * t + 360) % 360,
|
|
208
|
+
s: from.s + (to.s - from.s) * t,
|
|
209
|
+
l: from.l + (to.l - from.l) * t,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
// =============================================================================
|
|
213
|
+
// Gradient Generation
|
|
214
|
+
// =============================================================================
|
|
215
|
+
/**
|
|
216
|
+
* Generate a linear gradient CSS string
|
|
217
|
+
*/
|
|
218
|
+
export function linearGradient(angle, ...colors) {
|
|
219
|
+
return `linear-gradient(${angle}deg, ${colors.join(", ")})`;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Generate a radial gradient CSS string
|
|
223
|
+
*/
|
|
224
|
+
export function radialGradient(shape, ...colors) {
|
|
225
|
+
return `radial-gradient(${shape}, ${colors.join(", ")})`;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Generate a conic gradient CSS string
|
|
229
|
+
*/
|
|
230
|
+
export function conicGradient(fromAngle, ...colors) {
|
|
231
|
+
return `conic-gradient(from ${fromAngle}deg, ${colors.join(", ")})`;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Generate rainbow gradient colors
|
|
235
|
+
*/
|
|
236
|
+
export function getRainbowColors(count = 5) {
|
|
237
|
+
const colors = [];
|
|
238
|
+
for (let i = 0; i < count; i++) {
|
|
239
|
+
colors.push({
|
|
240
|
+
h: (i * 360) / count,
|
|
241
|
+
s: 100,
|
|
242
|
+
l: 63,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return colors;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Generate a gradient from theme CSS variables
|
|
249
|
+
*/
|
|
250
|
+
export function getThemeGradient(startVar, endVar, angle = 135) {
|
|
251
|
+
return `linear-gradient(${angle}deg, var(${startVar}), var(${endVar}))`;
|
|
252
|
+
}
|
|
253
|
+
// =============================================================================
|
|
254
|
+
// Color Utilities
|
|
255
|
+
// =============================================================================
|
|
256
|
+
/**
|
|
257
|
+
* Get a CSS variable value
|
|
258
|
+
*/
|
|
259
|
+
export function getCssVariable(name) {
|
|
260
|
+
if (typeof window === "undefined")
|
|
261
|
+
return "";
|
|
262
|
+
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Set a CSS variable
|
|
266
|
+
*/
|
|
267
|
+
export function setCssVariable(name, value) {
|
|
268
|
+
if (typeof window === "undefined")
|
|
269
|
+
return;
|
|
270
|
+
document.documentElement.style.setProperty(name, value);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Generate a random color
|
|
274
|
+
*/
|
|
275
|
+
export function randomColor() {
|
|
276
|
+
return {
|
|
277
|
+
h: Math.floor(Math.random() * 360),
|
|
278
|
+
s: 70 + Math.floor(Math.random() * 30),
|
|
279
|
+
l: 50 + Math.floor(Math.random() * 20),
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Check if a color is light or dark
|
|
284
|
+
*/
|
|
285
|
+
export function isLightColor(hsl) {
|
|
286
|
+
return hsl.l > 50;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Get contrasting text color (black or white)
|
|
290
|
+
*/
|
|
291
|
+
export function getContrastColor(hsl) {
|
|
292
|
+
return isLightColor(hsl) ? "black" : "white";
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Add alpha to a color string
|
|
296
|
+
*/
|
|
297
|
+
export function withAlpha(color, alpha) {
|
|
298
|
+
// Handle hex
|
|
299
|
+
if (color.startsWith("#")) {
|
|
300
|
+
const rgb = hexToRgb(color);
|
|
301
|
+
if (rgb) {
|
|
302
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
// Handle hsl
|
|
306
|
+
if (color.startsWith("hsl(")) {
|
|
307
|
+
return color.replace("hsl(", "hsla(").replace(")", `, ${alpha})`);
|
|
308
|
+
}
|
|
309
|
+
// Handle oklch
|
|
310
|
+
if (color.startsWith("oklch(")) {
|
|
311
|
+
return color.replace(")", ` / ${alpha})`);
|
|
312
|
+
}
|
|
313
|
+
return color;
|
|
314
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Geometry Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helpers for calculating positions, angles, distances, and directions.
|
|
5
|
+
* Used for hover effects, spotlights, and direction-aware components.
|
|
6
|
+
*/
|
|
7
|
+
export interface Point {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
}
|
|
11
|
+
export interface Size {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
}
|
|
15
|
+
export interface Rect extends Point, Size {
|
|
16
|
+
}
|
|
17
|
+
export type Direction = "top" | "right" | "bottom" | "left";
|
|
18
|
+
export type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
19
|
+
/**
|
|
20
|
+
* Create a point object
|
|
21
|
+
*/
|
|
22
|
+
export declare function point(x: number, y: number): Point;
|
|
23
|
+
/**
|
|
24
|
+
* Add two points
|
|
25
|
+
*/
|
|
26
|
+
export declare function addPoints(a: Point, b: Point): Point;
|
|
27
|
+
/**
|
|
28
|
+
* Subtract point b from point a
|
|
29
|
+
*/
|
|
30
|
+
export declare function subtractPoints(a: Point, b: Point): Point;
|
|
31
|
+
/**
|
|
32
|
+
* Scale a point by a factor
|
|
33
|
+
*/
|
|
34
|
+
export declare function scalePoint(p: Point, factor: number): Point;
|
|
35
|
+
/**
|
|
36
|
+
* Get the midpoint between two points
|
|
37
|
+
*/
|
|
38
|
+
export declare function midpoint(a: Point, b: Point): Point;
|
|
39
|
+
/**
|
|
40
|
+
* Calculate the distance between two points
|
|
41
|
+
*/
|
|
42
|
+
export declare function distance(a: Point, b: Point): number;
|
|
43
|
+
/**
|
|
44
|
+
* Calculate the squared distance between two points (faster, no sqrt)
|
|
45
|
+
*/
|
|
46
|
+
export declare function distanceSquared(a: Point, b: Point): number;
|
|
47
|
+
/**
|
|
48
|
+
* Calculate the angle between two points in radians
|
|
49
|
+
*/
|
|
50
|
+
export declare function angle(from: Point, to: Point): number;
|
|
51
|
+
/**
|
|
52
|
+
* Calculate the angle between two points in degrees
|
|
53
|
+
*/
|
|
54
|
+
export declare function angleDegrees(from: Point, to: Point): number;
|
|
55
|
+
/**
|
|
56
|
+
* Convert radians to degrees
|
|
57
|
+
*/
|
|
58
|
+
export declare function radToDeg(radians: number): number;
|
|
59
|
+
/**
|
|
60
|
+
* Convert degrees to radians
|
|
61
|
+
*/
|
|
62
|
+
export declare function degToRad(degrees: number): number;
|
|
63
|
+
/**
|
|
64
|
+
* Normalize an angle to 0-360 degrees
|
|
65
|
+
*/
|
|
66
|
+
export declare function normalizeAngle(degrees: number): number;
|
|
67
|
+
/**
|
|
68
|
+
* Get mouse position relative to an element
|
|
69
|
+
*/
|
|
70
|
+
export declare function getRelativeMousePosition(event: MouseEvent, element: HTMLElement): Point;
|
|
71
|
+
/**
|
|
72
|
+
* Get mouse position as a percentage of element dimensions (0-1)
|
|
73
|
+
*/
|
|
74
|
+
export declare function getRelativeMousePercent(event: MouseEvent, element: HTMLElement): Point;
|
|
75
|
+
/**
|
|
76
|
+
* Get mouse position centered on element (-0.5 to 0.5)
|
|
77
|
+
*/
|
|
78
|
+
export declare function getRelativeMouseCentered(event: MouseEvent, element: HTMLElement): Point;
|
|
79
|
+
/**
|
|
80
|
+
* Get the center point of an element
|
|
81
|
+
*/
|
|
82
|
+
export declare function getElementCenter(element: HTMLElement): Point;
|
|
83
|
+
/**
|
|
84
|
+
* Get the center point of an element relative to itself
|
|
85
|
+
*/
|
|
86
|
+
export declare function getElementLocalCenter(element: HTMLElement): Point;
|
|
87
|
+
/**
|
|
88
|
+
* Determine which direction mouse entered/exited an element
|
|
89
|
+
*/
|
|
90
|
+
export declare function getEntryDirection(event: MouseEvent, element: HTMLElement): Direction;
|
|
91
|
+
/**
|
|
92
|
+
* Get the opposite direction
|
|
93
|
+
*/
|
|
94
|
+
export declare function getOppositeDirection(direction: Direction): Direction;
|
|
95
|
+
/**
|
|
96
|
+
* Get the nearest corner to a point within an element
|
|
97
|
+
*/
|
|
98
|
+
export declare function getNearestCorner(point: Point, size: Size): Corner;
|
|
99
|
+
/**
|
|
100
|
+
* Check if a point is inside a rectangle
|
|
101
|
+
*/
|
|
102
|
+
export declare function isPointInRect(p: Point, rect: Rect): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Get the bounding rect of an element
|
|
105
|
+
*/
|
|
106
|
+
export declare function getRect(element: HTMLElement): Rect;
|
|
107
|
+
/**
|
|
108
|
+
* Expand a rect by a given amount
|
|
109
|
+
*/
|
|
110
|
+
export declare function expandRect(rect: Rect, amount: number): Rect;
|
|
111
|
+
/**
|
|
112
|
+
* Calculate rotation transform based on mouse position
|
|
113
|
+
* Returns rotation values suitable for 3D transforms
|
|
114
|
+
*/
|
|
115
|
+
export declare function calculateTiltTransform(mousePos: Point, elementSize: Size, maxRotation?: number): {
|
|
116
|
+
rotateX: number;
|
|
117
|
+
rotateY: number;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Calculate spotlight position for gradient effects
|
|
121
|
+
*/
|
|
122
|
+
export declare function calculateSpotlightPosition(mousePos: Point, elementSize: Size): {
|
|
123
|
+
x: string;
|
|
124
|
+
y: string;
|
|
125
|
+
};
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Geometry Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helpers for calculating positions, angles, distances, and directions.
|
|
5
|
+
* Used for hover effects, spotlights, and direction-aware components.
|
|
6
|
+
*/
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// Point Operations
|
|
9
|
+
// =============================================================================
|
|
10
|
+
/**
|
|
11
|
+
* Create a point object
|
|
12
|
+
*/
|
|
13
|
+
export function point(x, y) {
|
|
14
|
+
return { x, y };
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Add two points
|
|
18
|
+
*/
|
|
19
|
+
export function addPoints(a, b) {
|
|
20
|
+
return { x: a.x + b.x, y: a.y + b.y };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Subtract point b from point a
|
|
24
|
+
*/
|
|
25
|
+
export function subtractPoints(a, b) {
|
|
26
|
+
return { x: a.x - b.x, y: a.y - b.y };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Scale a point by a factor
|
|
30
|
+
*/
|
|
31
|
+
export function scalePoint(p, factor) {
|
|
32
|
+
return { x: p.x * factor, y: p.y * factor };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the midpoint between two points
|
|
36
|
+
*/
|
|
37
|
+
export function midpoint(a, b) {
|
|
38
|
+
return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
|
|
39
|
+
}
|
|
40
|
+
// =============================================================================
|
|
41
|
+
// Distance & Angle Calculations
|
|
42
|
+
// =============================================================================
|
|
43
|
+
/**
|
|
44
|
+
* Calculate the distance between two points
|
|
45
|
+
*/
|
|
46
|
+
export function distance(a, b) {
|
|
47
|
+
const dx = b.x - a.x;
|
|
48
|
+
const dy = b.y - a.y;
|
|
49
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Calculate the squared distance between two points (faster, no sqrt)
|
|
53
|
+
*/
|
|
54
|
+
export function distanceSquared(a, b) {
|
|
55
|
+
const dx = b.x - a.x;
|
|
56
|
+
const dy = b.y - a.y;
|
|
57
|
+
return dx * dx + dy * dy;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Calculate the angle between two points in radians
|
|
61
|
+
*/
|
|
62
|
+
export function angle(from, to) {
|
|
63
|
+
return Math.atan2(to.y - from.y, to.x - from.x);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Calculate the angle between two points in degrees
|
|
67
|
+
*/
|
|
68
|
+
export function angleDegrees(from, to) {
|
|
69
|
+
return (angle(from, to) * 180) / Math.PI;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Convert radians to degrees
|
|
73
|
+
*/
|
|
74
|
+
export function radToDeg(radians) {
|
|
75
|
+
return (radians * 180) / Math.PI;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Convert degrees to radians
|
|
79
|
+
*/
|
|
80
|
+
export function degToRad(degrees) {
|
|
81
|
+
return (degrees * Math.PI) / 180;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Normalize an angle to 0-360 degrees
|
|
85
|
+
*/
|
|
86
|
+
export function normalizeAngle(degrees) {
|
|
87
|
+
return ((degrees % 360) + 360) % 360;
|
|
88
|
+
}
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// Mouse & Element Positions
|
|
91
|
+
// =============================================================================
|
|
92
|
+
/**
|
|
93
|
+
* Get mouse position relative to an element
|
|
94
|
+
*/
|
|
95
|
+
export function getRelativeMousePosition(event, element) {
|
|
96
|
+
const rect = element.getBoundingClientRect();
|
|
97
|
+
return {
|
|
98
|
+
x: event.clientX - rect.left,
|
|
99
|
+
y: event.clientY - rect.top,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get mouse position as a percentage of element dimensions (0-1)
|
|
104
|
+
*/
|
|
105
|
+
export function getRelativeMousePercent(event, element) {
|
|
106
|
+
const rect = element.getBoundingClientRect();
|
|
107
|
+
return {
|
|
108
|
+
x: (event.clientX - rect.left) / rect.width,
|
|
109
|
+
y: (event.clientY - rect.top) / rect.height,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get mouse position centered on element (-0.5 to 0.5)
|
|
114
|
+
*/
|
|
115
|
+
export function getRelativeMouseCentered(event, element) {
|
|
116
|
+
const percent = getRelativeMousePercent(event, element);
|
|
117
|
+
return {
|
|
118
|
+
x: percent.x - 0.5,
|
|
119
|
+
y: percent.y - 0.5,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get the center point of an element
|
|
124
|
+
*/
|
|
125
|
+
export function getElementCenter(element) {
|
|
126
|
+
const rect = element.getBoundingClientRect();
|
|
127
|
+
return {
|
|
128
|
+
x: rect.left + rect.width / 2,
|
|
129
|
+
y: rect.top + rect.height / 2,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get the center point of an element relative to itself
|
|
134
|
+
*/
|
|
135
|
+
export function getElementLocalCenter(element) {
|
|
136
|
+
const rect = element.getBoundingClientRect();
|
|
137
|
+
return {
|
|
138
|
+
x: rect.width / 2,
|
|
139
|
+
y: rect.height / 2,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// =============================================================================
|
|
143
|
+
// Direction Detection
|
|
144
|
+
// =============================================================================
|
|
145
|
+
/**
|
|
146
|
+
* Determine which direction mouse entered/exited an element
|
|
147
|
+
*/
|
|
148
|
+
export function getEntryDirection(event, element) {
|
|
149
|
+
const rect = element.getBoundingClientRect();
|
|
150
|
+
const x = event.clientX - rect.left - rect.width / 2;
|
|
151
|
+
const y = event.clientY - rect.top - rect.height / 2;
|
|
152
|
+
// Calculate direction based on angle
|
|
153
|
+
const angleRad = Math.atan2(y, x);
|
|
154
|
+
const angleDeg = normalizeAngle((angleRad * 180) / Math.PI);
|
|
155
|
+
if (angleDeg >= 315 || angleDeg < 45)
|
|
156
|
+
return "right";
|
|
157
|
+
if (angleDeg >= 45 && angleDeg < 135)
|
|
158
|
+
return "bottom";
|
|
159
|
+
if (angleDeg >= 135 && angleDeg < 225)
|
|
160
|
+
return "left";
|
|
161
|
+
return "top";
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get the opposite direction
|
|
165
|
+
*/
|
|
166
|
+
export function getOppositeDirection(direction) {
|
|
167
|
+
const opposites = {
|
|
168
|
+
top: "bottom",
|
|
169
|
+
right: "left",
|
|
170
|
+
bottom: "top",
|
|
171
|
+
left: "right",
|
|
172
|
+
};
|
|
173
|
+
return opposites[direction];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get the nearest corner to a point within an element
|
|
177
|
+
*/
|
|
178
|
+
export function getNearestCorner(point, size) {
|
|
179
|
+
const centerX = size.width / 2;
|
|
180
|
+
const centerY = size.height / 2;
|
|
181
|
+
const isTop = point.y < centerY;
|
|
182
|
+
const isLeft = point.x < centerX;
|
|
183
|
+
if (isTop && isLeft)
|
|
184
|
+
return "top-left";
|
|
185
|
+
if (isTop && !isLeft)
|
|
186
|
+
return "top-right";
|
|
187
|
+
if (!isTop && isLeft)
|
|
188
|
+
return "bottom-left";
|
|
189
|
+
return "bottom-right";
|
|
190
|
+
}
|
|
191
|
+
// =============================================================================
|
|
192
|
+
// Rect & Bounds
|
|
193
|
+
// =============================================================================
|
|
194
|
+
/**
|
|
195
|
+
* Check if a point is inside a rectangle
|
|
196
|
+
*/
|
|
197
|
+
export function isPointInRect(p, rect) {
|
|
198
|
+
return (p.x >= rect.x && p.x <= rect.x + rect.width && p.y >= rect.y && p.y <= rect.y + rect.height);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Get the bounding rect of an element
|
|
202
|
+
*/
|
|
203
|
+
export function getRect(element) {
|
|
204
|
+
const rect = element.getBoundingClientRect();
|
|
205
|
+
return {
|
|
206
|
+
x: rect.left,
|
|
207
|
+
y: rect.top,
|
|
208
|
+
width: rect.width,
|
|
209
|
+
height: rect.height,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Expand a rect by a given amount
|
|
214
|
+
*/
|
|
215
|
+
export function expandRect(rect, amount) {
|
|
216
|
+
return {
|
|
217
|
+
x: rect.x - amount,
|
|
218
|
+
y: rect.y - amount,
|
|
219
|
+
width: rect.width + amount * 2,
|
|
220
|
+
height: rect.height + amount * 2,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// =============================================================================
|
|
224
|
+
// Transforms
|
|
225
|
+
// =============================================================================
|
|
226
|
+
/**
|
|
227
|
+
* Calculate rotation transform based on mouse position
|
|
228
|
+
* Returns rotation values suitable for 3D transforms
|
|
229
|
+
*/
|
|
230
|
+
export function calculateTiltTransform(mousePos, elementSize, maxRotation = 15) {
|
|
231
|
+
const centerX = elementSize.width / 2;
|
|
232
|
+
const centerY = elementSize.height / 2;
|
|
233
|
+
const percentX = (mousePos.x - centerX) / centerX;
|
|
234
|
+
const percentY = (mousePos.y - centerY) / centerY;
|
|
235
|
+
return {
|
|
236
|
+
rotateX: -percentY * maxRotation,
|
|
237
|
+
rotateY: percentX * maxRotation,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Calculate spotlight position for gradient effects
|
|
242
|
+
*/
|
|
243
|
+
export function calculateSpotlightPosition(mousePos, elementSize) {
|
|
244
|
+
const percentX = (mousePos.x / elementSize.width) * 100;
|
|
245
|
+
const percentY = (mousePos.y / elementSize.height) * 100;
|
|
246
|
+
return {
|
|
247
|
+
x: `${percentX}%`,
|
|
248
|
+
y: `${percentY}%`,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities barrel export
|
|
3
|
+
*/
|
|
4
|
+
export { cn } from "../utils.js";
|
|
5
|
+
export type { WithoutChild, WithoutChildren, WithoutChildrenOrChild, WithElementRef, } from "../utils.js";
|
|
6
|
+
export { type SpringConfig, type AnimationOptions, springPresets, linear, easeIn, easeOut, easeInOut, easeInCubic, easeOutCubic, easeInOutCubic, easeOutBounce, easeOutElastic, easeOutBack, lerp, clamp, mapRange, springStep, isSpringAtRest, staggerDelay, getProgress, getDurationFromCSS, rafDebounce, rafThrottle, } from "./animation.js";
|
|
7
|
+
export { type Point, type Size, type Rect, type Direction, type Corner, point, addPoints, subtractPoints, scalePoint, midpoint, distance, distanceSquared, angle, angleDegrees, radToDeg, degToRad, normalizeAngle, getRelativeMousePosition, getRelativeMousePercent, getRelativeMouseCentered, getElementCenter, getElementLocalCenter, getEntryDirection, getOppositeDirection, getNearestCorner, isPointInRect, getRect, expandRect, calculateTiltTransform, calculateSpotlightPosition, } from "./geometry.js";
|
|
8
|
+
export { type RGB, type HSL, type OKLCH, type RGBA, hexToRgb, rgbToHex, parseHsl, hslToString, parseOklch, oklchToString, rgbToHsl, hslToRgb, lighten, darken, saturate, desaturate, shiftHue, complementary, interpolateColor, linearGradient, radialGradient, conicGradient, getRainbowColors, getThemeGradient, getCssVariable, setCssVariable, randomColor, isLightColor, getContrastColor, withAlpha, } from "./color.js";
|