@enact-ui/backgrounds 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,309 @@
1
+ // src/components/background-paths.tsx
2
+ import { useMotionPreset } from "@enact-ui/animate";
3
+ import { motion } from "motion/react";
4
+ import { useMemo } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ function FloatingPaths({ position, baseDuration, opacity, ease, durationVariation, prefersReducedMotion }) {
7
+ const paths = useMemo(
8
+ () => Array.from({ length: 36 }, (_, i) => {
9
+ const durationRandom = Math.random();
10
+ return {
11
+ id: i,
12
+ d: `M-${380 - i * 5 * position} -${189 + i * 6}C-${380 - i * 5 * position} -${189 + i * 6} -${312 - i * 5 * position} ${216 - i * 6} ${152 - i * 5 * position} ${343 - i * 6}C${616 - i * 5 * position} ${470 - i * 6} ${684 - i * 5 * position} ${875 - i * 6} ${684 - i * 5 * position} ${875 - i * 6}`,
13
+ color: `rgba(15,23,42,${0.1 + i * 0.03})`,
14
+ width: 0.5 + i * 0.03,
15
+ durationRandom
16
+ };
17
+ }),
18
+ [position]
19
+ );
20
+ if (prefersReducedMotion) {
21
+ return /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0", children: /* @__PURE__ */ jsxs("svg", { className: "text-muted h-full w-full", viewBox: "0 0 696 316", fill: "none", "aria-hidden": "true", children: [
22
+ /* @__PURE__ */ jsx("title", { children: "Background Paths" }),
23
+ paths.map((path) => /* @__PURE__ */ jsx("path", { d: path.d, stroke: "currentColor", strokeWidth: path.width, strokeOpacity: opacity[1] }, path.id))
24
+ ] }) });
25
+ }
26
+ return /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0", children: /* @__PURE__ */ jsxs("svg", { className: "text-muted h-full w-full", viewBox: "0 0 696 316", fill: "none", "aria-hidden": "true", children: [
27
+ /* @__PURE__ */ jsx("title", { children: "Background Paths" }),
28
+ paths.map((path) => {
29
+ const duration = baseDuration + baseDuration * durationVariation * path.durationRandom;
30
+ return /* @__PURE__ */ jsx(
31
+ motion.path,
32
+ {
33
+ d: path.d,
34
+ stroke: "currentColor",
35
+ strokeWidth: path.width,
36
+ strokeOpacity: 0.1 + path.id * 0.03,
37
+ initial: { pathLength: 0.3, opacity: opacity[0] },
38
+ animate: {
39
+ pathLength: 1,
40
+ opacity,
41
+ pathOffset: [0, 1, 0]
42
+ },
43
+ transition: {
44
+ duration,
45
+ repeat: Number.POSITIVE_INFINITY,
46
+ ease
47
+ }
48
+ },
49
+ path.id
50
+ );
51
+ })
52
+ ] }) });
53
+ }
54
+ var BackgroundPaths = ({ preset }) => {
55
+ const motionConfig = useMotionPreset("paths", preset);
56
+ return /* @__PURE__ */ jsx("div", { className: "pointer-events-none relative flex h-full w-full items-center justify-center overflow-hidden", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("div", { className: "absolute inset-0", children: [
57
+ /* @__PURE__ */ jsx(
58
+ FloatingPaths,
59
+ {
60
+ position: 1,
61
+ baseDuration: motionConfig.baseDuration,
62
+ opacity: motionConfig.opacity,
63
+ ease: motionConfig.ease,
64
+ durationVariation: motionConfig.durationVariation,
65
+ prefersReducedMotion: motionConfig.prefersReducedMotion
66
+ }
67
+ ),
68
+ /* @__PURE__ */ jsx(
69
+ FloatingPaths,
70
+ {
71
+ position: -1,
72
+ baseDuration: motionConfig.baseDuration,
73
+ opacity: motionConfig.opacity,
74
+ ease: motionConfig.ease,
75
+ durationVariation: motionConfig.durationVariation,
76
+ prefersReducedMotion: motionConfig.prefersReducedMotion
77
+ }
78
+ )
79
+ ] }) });
80
+ };
81
+
82
+ // src/components/light-rays.tsx
83
+ import { useMotionPreset as useMotionPreset2 } from "@enact-ui/animate";
84
+ import { cx } from "@enact-ui/react";
85
+ import { motion as motion2 } from "motion/react";
86
+ import { useMemo as useMemo2 } from "react";
87
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
88
+ var createRays = (count, swingVariation) => {
89
+ if (count <= 0) return [];
90
+ return Array.from({ length: count }, (_, index) => {
91
+ const left = 8 + Math.random() * 84;
92
+ const rotate = -28 + Math.random() * 56;
93
+ const width = 160 + Math.random() * 160;
94
+ const swing = 0.8 + Math.random() * swingVariation;
95
+ const delay = Math.random();
96
+ const durationMultiplier = 0.75 + Math.random() * 0.5;
97
+ const intensityMultiplier = 0.6 + Math.random() * 0.5;
98
+ return {
99
+ id: `${index}-${Math.round(left * 10)}`,
100
+ left,
101
+ rotate,
102
+ width,
103
+ swing,
104
+ delay,
105
+ durationMultiplier,
106
+ intensityMultiplier
107
+ };
108
+ });
109
+ };
110
+ var Ray = ({ left, rotate, width, swing, delay, durationMultiplier, intensityMultiplier, cycleDuration, intensity, prefersReducedMotion }) => {
111
+ const computedIntensity = intensity * intensityMultiplier;
112
+ const computedDuration = cycleDuration * durationMultiplier;
113
+ const computedDelay = delay * cycleDuration;
114
+ if (prefersReducedMotion) {
115
+ return /* @__PURE__ */ jsx2(
116
+ "div",
117
+ {
118
+ className: "pointer-events-none absolute -top-[12%] left-[var(--ray-left)] h-[var(--light-rays-length)] w-[var(--ray-width)] origin-top -translate-x-1/2 rounded-full bg-gradient-to-b from-[color-mix(in_srgb,var(--light-rays-color)_70%,transparent)] to-transparent opacity-[var(--ray-opacity)] mix-blend-screen blur-[var(--light-rays-blur)]",
119
+ style: {
120
+ "--ray-left": `${left}%`,
121
+ "--ray-width": `${width}px`,
122
+ "--ray-opacity": computedIntensity * 0.5,
123
+ transform: `rotate(${rotate}deg)`
124
+ },
125
+ "aria-hidden": "true"
126
+ }
127
+ );
128
+ }
129
+ return /* @__PURE__ */ jsx2(
130
+ motion2.div,
131
+ {
132
+ className: "pointer-events-none absolute -top-[12%] left-[var(--ray-left)] h-[var(--light-rays-length)] w-[var(--ray-width)] origin-top -translate-x-1/2 rounded-full bg-gradient-to-b from-[color-mix(in_srgb,var(--light-rays-color)_70%,transparent)] to-transparent opacity-0 mix-blend-screen blur-[var(--light-rays-blur)]",
133
+ style: {
134
+ "--ray-left": `${left}%`,
135
+ "--ray-width": `${width}px`
136
+ },
137
+ initial: { rotate },
138
+ animate: {
139
+ opacity: [0, computedIntensity, 0],
140
+ rotate: [rotate - swing, rotate + swing, rotate - swing]
141
+ },
142
+ transition: {
143
+ duration: computedDuration,
144
+ repeat: Number.POSITIVE_INFINITY,
145
+ ease: "easeInOut",
146
+ delay: computedDelay,
147
+ repeatDelay: computedDuration * 0.1
148
+ },
149
+ "aria-hidden": "true"
150
+ }
151
+ );
152
+ };
153
+ var LightRays = ({
154
+ className,
155
+ style,
156
+ preset,
157
+ count = 7,
158
+ color = "rgba(160, 210, 255, 0.2)",
159
+ blur = 36,
160
+ length = "70vh",
161
+ ref,
162
+ ...props
163
+ }) => {
164
+ const motionConfig = useMotionPreset2("rays", preset);
165
+ const rays = useMemo2(() => createRays(count, motionConfig.swingVariation), [count, motionConfig.swingVariation]);
166
+ return /* @__PURE__ */ jsx2(
167
+ "div",
168
+ {
169
+ ref,
170
+ className: cx("pointer-events-none absolute inset-0 isolate overflow-hidden rounded-[inherit]", className),
171
+ style: {
172
+ "--light-rays-color": color,
173
+ "--light-rays-blur": `${blur}px`,
174
+ "--light-rays-length": length,
175
+ ...style
176
+ },
177
+ "aria-hidden": "true",
178
+ ...props,
179
+ children: /* @__PURE__ */ jsxs2("div", { className: "absolute inset-0 overflow-hidden", children: [
180
+ /* @__PURE__ */ jsx2(
181
+ "div",
182
+ {
183
+ "aria-hidden": "true",
184
+ className: "absolute inset-0 opacity-60",
185
+ style: {
186
+ background: "radial-gradient(circle at 20% 15%, color-mix(in srgb, var(--light-rays-color) 45%, transparent), transparent 70%)"
187
+ }
188
+ }
189
+ ),
190
+ /* @__PURE__ */ jsx2(
191
+ "div",
192
+ {
193
+ "aria-hidden": "true",
194
+ className: "absolute inset-0 opacity-60",
195
+ style: {
196
+ background: "radial-gradient(circle at 80% 10%, color-mix(in srgb, var(--light-rays-color) 35%, transparent), transparent 75%)"
197
+ }
198
+ }
199
+ ),
200
+ rays.map((ray) => /* @__PURE__ */ jsx2(
201
+ Ray,
202
+ {
203
+ ...ray,
204
+ cycleDuration: motionConfig.cycleDuration,
205
+ intensity: motionConfig.intensity,
206
+ prefersReducedMotion: motionConfig.prefersReducedMotion
207
+ },
208
+ ray.id
209
+ ))
210
+ ] })
211
+ }
212
+ );
213
+ };
214
+
215
+ // src/components/liquid-glass-background.tsx
216
+ import { motion as motion3 } from "motion/react";
217
+ import { useEffect, useState } from "react";
218
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
219
+ var LiquidGlassBackground = () => {
220
+ const [isDarkMode, setIsDarkMode] = useState(false);
221
+ useEffect(() => {
222
+ const checkDarkMode = () => {
223
+ setIsDarkMode(document.documentElement.classList.contains("dark-mode"));
224
+ };
225
+ checkDarkMode();
226
+ const observer = new MutationObserver(checkDarkMode);
227
+ observer.observe(document.documentElement, {
228
+ attributes: true,
229
+ attributeFilter: ["class"]
230
+ });
231
+ return () => observer.disconnect();
232
+ }, []);
233
+ const lightModeColors = [
234
+ "rgba(0, 212, 255, 0.15)",
235
+ // Bright cyan
236
+ "rgba(173, 230, 255, 0.12)",
237
+ // Light cyan
238
+ "rgba(102, 178, 255, 0.1)",
239
+ // Soft blue
240
+ "rgba(0, 153, 204, 0.08)"
241
+ // Deeper cyan
242
+ ];
243
+ const darkModeColors = [
244
+ "rgba(0, 102, 255, 0.2)",
245
+ // Deep blue
246
+ "rgba(51, 153, 255, 0.15)",
247
+ // Bright blue
248
+ "rgba(102, 178, 255, 0.12)",
249
+ // Light blue
250
+ "rgba(0, 51, 204, 0.1)"
251
+ // Dark blue
252
+ ];
253
+ const colors = isDarkMode ? darkModeColors : lightModeColors;
254
+ const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
255
+ const orbVariants = {
256
+ animate: {
257
+ x: prefersReducedMotion ? 0 : [0, 100, -80, 60, -40, 0],
258
+ y: prefersReducedMotion ? 0 : [0, -80, 60, -50, 40, 0],
259
+ scale: prefersReducedMotion ? 1 : [1, 1.3, 0.8, 1.2, 0.9, 1]
260
+ }
261
+ };
262
+ const transition = {
263
+ duration: prefersReducedMotion ? 0 : 12,
264
+ repeat: Infinity,
265
+ ease: "easeInOut"
266
+ };
267
+ return /* @__PURE__ */ jsxs3("div", { className: "pointer-events-none fixed inset-0 -z-10 overflow-hidden", "aria-hidden": "true", children: [
268
+ colors.map((color, index) => {
269
+ const size = 400 + index * 120;
270
+ const initialX = 10 + index * 30;
271
+ const initialY = 20 + index * 25;
272
+ return /* @__PURE__ */ jsx3(
273
+ motion3.div,
274
+ {
275
+ className: "absolute rounded-full blur-3xl",
276
+ style: {
277
+ width: `${size}px`,
278
+ height: `${size}px`,
279
+ background: `radial-gradient(circle, ${color} 0%, transparent 70%)`,
280
+ left: `${initialX}%`,
281
+ top: `${initialY}%`
282
+ },
283
+ variants: orbVariants,
284
+ animate: "animate",
285
+ transition: {
286
+ ...transition,
287
+ delay: index * 1.5
288
+ }
289
+ },
290
+ color
291
+ );
292
+ }),
293
+ /* @__PURE__ */ jsx3(
294
+ "div",
295
+ {
296
+ className: "absolute inset-0 opacity-30",
297
+ style: {
298
+ background: isDarkMode ? "radial-gradient(circle at 50% 50%, rgba(0, 102, 255, 0.1) 0%, transparent 70%)" : "radial-gradient(circle at 50% 50%, rgba(0, 212, 255, 0.08) 0%, transparent 70%)"
299
+ }
300
+ }
301
+ )
302
+ ] });
303
+ };
304
+ export {
305
+ BackgroundPaths,
306
+ LightRays,
307
+ LiquidGlassBackground
308
+ };
309
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/background-paths.tsx","../src/components/light-rays.tsx","../src/components/liquid-glass-background.tsx"],"sourcesContent":["// Copyright (c) 2025 Amsterdam Data Labs\n\"use client\";\n\nimport { type MotionPreset, useMotionPreset } from \"@enact-ui/animate\";\nimport { motion } from \"motion/react\";\nimport { type FC, useMemo } from \"react\";\n\ninterface FloatingPathsProps {\n position: number;\n baseDuration: number;\n opacity: [number, number, number];\n ease: \"linear\" | \"easeInOut\";\n durationVariation: number;\n prefersReducedMotion: boolean;\n}\n\nfunction FloatingPaths({ position, baseDuration, opacity, ease, durationVariation, prefersReducedMotion }: FloatingPathsProps) {\n // Memoize path calculations and random values to prevent regeneration on re-render\n const paths = useMemo(\n () =>\n Array.from({ length: 36 }, (_, i) => {\n // Generate stable random variations per path\n const durationRandom = Math.random();\n return {\n id: i,\n d: `M-${380 - i * 5 * position} -${189 + i * 6}C-${380 - i * 5 * position} -${189 + i * 6} -${312 - i * 5 * position} ${216 - i * 6} ${\n 152 - i * 5 * position\n } ${343 - i * 6}C${616 - i * 5 * position} ${470 - i * 6} ${\n 684 - i * 5 * position\n } ${875 - i * 6} ${684 - i * 5 * position} ${875 - i * 6}`,\n color: `rgba(15,23,42,${0.1 + i * 0.03})`,\n width: 0.5 + i * 0.03,\n durationRandom,\n };\n }),\n [position],\n );\n\n // If reduced motion is preferred, render static paths\n if (prefersReducedMotion) {\n return (\n <div className=\"pointer-events-none absolute inset-0\">\n <svg className=\"text-muted h-full w-full\" viewBox=\"0 0 696 316\" fill=\"none\" aria-hidden=\"true\">\n <title>Background Paths</title>\n {paths.map((path) => (\n <path key={path.id} d={path.d} stroke=\"currentColor\" strokeWidth={path.width} strokeOpacity={opacity[1]} />\n ))}\n </svg>\n </div>\n );\n }\n\n return (\n <div className=\"pointer-events-none absolute inset-0\">\n <svg className=\"text-muted h-full w-full\" viewBox=\"0 0 696 316\" fill=\"none\" aria-hidden=\"true\">\n <title>Background Paths</title>\n {paths.map((path) => {\n // Calculate duration with preset-based variation\n const duration = baseDuration + baseDuration * durationVariation * path.durationRandom;\n\n return (\n <motion.path\n key={path.id}\n d={path.d}\n stroke=\"currentColor\"\n strokeWidth={path.width}\n strokeOpacity={0.1 + path.id * 0.03}\n initial={{ pathLength: 0.3, opacity: opacity[0] }}\n animate={{\n pathLength: 1,\n opacity: opacity,\n pathOffset: [0, 1, 0],\n }}\n transition={{\n duration,\n repeat: Number.POSITIVE_INFINITY,\n ease,\n }}\n />\n );\n })}\n </svg>\n </div>\n );\n}\n\nexport interface BackgroundPathsProps {\n /** Motion preset - controls animation speed and intensity (required) */\n preset: MotionPreset;\n}\n\n/**\n * BackgroundPaths Component\n *\n * Renders animated SVG paths for ambient background effects.\n * Uses the motion preset system for theme-aware, configurable animations.\n *\n * @example\n * ```tsx\n * <BackgroundPaths preset=\"medium\" />\n * <BackgroundPaths preset=\"slow\" />\n * <BackgroundPaths preset=\"fast\" />\n * ```\n */\nexport const BackgroundPaths: FC<BackgroundPathsProps> = ({ preset }) => {\n const motionConfig = useMotionPreset(\"paths\", preset);\n\n return (\n <div className=\"pointer-events-none relative flex h-full w-full items-center justify-center overflow-hidden\" aria-hidden=\"true\">\n <div className=\"absolute inset-0\">\n <FloatingPaths\n position={1}\n baseDuration={motionConfig.baseDuration}\n opacity={motionConfig.opacity}\n ease={motionConfig.ease}\n durationVariation={motionConfig.durationVariation}\n prefersReducedMotion={motionConfig.prefersReducedMotion}\n />\n <FloatingPaths\n position={-1}\n baseDuration={motionConfig.baseDuration}\n opacity={motionConfig.opacity}\n ease={motionConfig.ease}\n durationVariation={motionConfig.durationVariation}\n prefersReducedMotion={motionConfig.prefersReducedMotion}\n />\n </div>\n </div>\n );\n};\n","// Copyright (c) 2025 Amsterdam Data Labs\n\"use client\";\n\nimport { type MotionPreset, useMotionPreset } from \"@enact-ui/animate\";\nimport { cx } from \"@enact-ui/react\";\nimport { type MotionStyle, motion } from \"motion/react\";\nimport { type CSSProperties, type FC, useMemo } from \"react\";\n\n/**\n * LightRays Component\n *\n * Adapted from MagicUI (MIT Licensed)\n * Original source: https://github.com/magicuidesign/magicui/blob/main/apps/www/registry/magicui/light-rays.tsx\n * Reference files: references/magicui-lightrays/\n *\n * Creates animated light rays that shine from above, perfect for ambient background effects.\n * Uses CSS gradients and motion animations - no Three.js dependencies required.\n *\n * Uses the motion preset system for theme-aware, configurable animations.\n */\nexport interface LightRaysProps extends React.HTMLAttributes<HTMLDivElement> {\n ref?: React.Ref<HTMLDivElement>;\n /** Motion preset - controls animation speed and intensity (required) */\n preset: MotionPreset;\n /** Number of light rays to render */\n count?: number;\n /** Color of the light rays (CSS color value) */\n color?: string;\n /** Blur amount in pixels */\n blur?: number;\n /** Length of the rays (CSS length value) */\n length?: string;\n}\n\ntype LightRay = {\n id: string;\n left: number;\n rotate: number;\n width: number;\n swing: number;\n delay: number;\n durationMultiplier: number;\n intensityMultiplier: number;\n};\n\nconst createRays = (count: number, swingVariation: number): LightRay[] => {\n if (count <= 0) return [];\n\n return Array.from({ length: count }, (_, index) => {\n const left = 8 + Math.random() * 84;\n const rotate = -28 + Math.random() * 56;\n const width = 160 + Math.random() * 160;\n const swing = 0.8 + Math.random() * swingVariation;\n const delay = Math.random();\n const durationMultiplier = 0.75 + Math.random() * 0.5;\n const intensityMultiplier = 0.6 + Math.random() * 0.5;\n\n return {\n id: `${index}-${Math.round(left * 10)}`,\n left,\n rotate,\n width,\n swing,\n delay,\n durationMultiplier,\n intensityMultiplier,\n };\n });\n};\n\ninterface RayProps extends LightRay {\n cycleDuration: number;\n intensity: number;\n prefersReducedMotion: boolean;\n}\n\nconst Ray: FC<RayProps> = ({ left, rotate, width, swing, delay, durationMultiplier, intensityMultiplier, cycleDuration, intensity, prefersReducedMotion }) => {\n const computedIntensity = intensity * intensityMultiplier;\n const computedDuration = cycleDuration * durationMultiplier;\n const computedDelay = delay * cycleDuration;\n\n // If reduced motion is preferred, render static ray\n if (prefersReducedMotion) {\n return (\n <div\n className=\"pointer-events-none absolute -top-[12%] left-[var(--ray-left)] h-[var(--light-rays-length)] w-[var(--ray-width)] origin-top -translate-x-1/2 rounded-full bg-gradient-to-b from-[color-mix(in_srgb,var(--light-rays-color)_70%,transparent)] to-transparent opacity-[var(--ray-opacity)] mix-blend-screen blur-[var(--light-rays-blur)]\"\n style={\n {\n \"--ray-left\": `${left}%`,\n \"--ray-width\": `${width}px`,\n \"--ray-opacity\": computedIntensity * 0.5,\n transform: `rotate(${rotate}deg)`,\n } as CSSProperties\n }\n aria-hidden=\"true\"\n />\n );\n }\n\n return (\n <motion.div\n className=\"pointer-events-none absolute -top-[12%] left-[var(--ray-left)] h-[var(--light-rays-length)] w-[var(--ray-width)] origin-top -translate-x-1/2 rounded-full bg-gradient-to-b from-[color-mix(in_srgb,var(--light-rays-color)_70%,transparent)] to-transparent opacity-0 mix-blend-screen blur-[var(--light-rays-blur)]\"\n style={\n {\n \"--ray-left\": `${left}%`,\n \"--ray-width\": `${width}px`,\n } as MotionStyle\n }\n initial={{ rotate: rotate }}\n animate={{\n opacity: [0, computedIntensity, 0],\n rotate: [rotate - swing, rotate + swing, rotate - swing],\n }}\n transition={{\n duration: computedDuration,\n repeat: Number.POSITIVE_INFINITY,\n ease: \"easeInOut\",\n delay: computedDelay,\n repeatDelay: computedDuration * 0.1,\n }}\n aria-hidden=\"true\"\n />\n );\n};\n\n/**\n * LightRays Component\n *\n * Creates animated light rays that shine from above, perfect for ambient background effects.\n * Uses the motion preset system for theme-aware, configurable animations.\n *\n * @example\n * ```tsx\n * <LightRays preset=\"medium\" />\n * <LightRays preset=\"slow\" count={5} color=\"rgba(160, 210, 255, 0.3)\" />\n * <LightRays preset=\"fast\" blur={48} length=\"80vh\" />\n * ```\n */\nexport const LightRays: FC<LightRaysProps> = ({\n className,\n style,\n preset,\n count = 7,\n color = \"rgba(160, 210, 255, 0.2)\",\n blur = 36,\n length = \"70vh\",\n ref,\n ...props\n}) => {\n const motionConfig = useMotionPreset(\"rays\", preset);\n\n // Memoize rays creation based on count and swingVariation\n const rays = useMemo(() => createRays(count, motionConfig.swingVariation), [count, motionConfig.swingVariation]);\n\n return (\n <div\n ref={ref}\n className={cx(\"pointer-events-none absolute inset-0 isolate overflow-hidden rounded-[inherit]\", className)}\n style={\n {\n \"--light-rays-color\": color,\n \"--light-rays-blur\": `${blur}px`,\n \"--light-rays-length\": length,\n ...style,\n } as CSSProperties\n }\n aria-hidden=\"true\"\n {...props}\n >\n <div className=\"absolute inset-0 overflow-hidden\">\n <div\n aria-hidden=\"true\"\n className=\"absolute inset-0 opacity-60\"\n style={\n {\n background: \"radial-gradient(circle at 20% 15%, color-mix(in srgb, var(--light-rays-color) 45%, transparent), transparent 70%)\",\n } as CSSProperties\n }\n />\n <div\n aria-hidden=\"true\"\n className=\"absolute inset-0 opacity-60\"\n style={\n {\n background: \"radial-gradient(circle at 80% 10%, color-mix(in srgb, var(--light-rays-color) 35%, transparent), transparent 75%)\",\n } as CSSProperties\n }\n />\n {rays.map((ray) => (\n <Ray\n key={ray.id}\n {...ray}\n cycleDuration={motionConfig.cycleDuration}\n intensity={motionConfig.intensity}\n prefersReducedMotion={motionConfig.prefersReducedMotion}\n />\n ))}\n </div>\n </div>\n );\n};\n","// Copyright (c) 2025 Amsterdam Data Labs\n\"use client\";\n\nimport { motion } from \"motion/react\";\nimport type React from \"react\";\nimport { useEffect, useState } from \"react\";\n\n/**\n * LiquidGlassBackground Component\n *\n * Provides a subtle animated background for the liquid glass theme.\n * Features floating gradient orbs with gentle movements that showcase\n * glassmorphism effects without being distracting.\n */\nexport const LiquidGlassBackground: React.FC = () => {\n const [isDarkMode, setIsDarkMode] = useState(false);\n\n useEffect(() => {\n // Check for dark mode class on document element\n const checkDarkMode = () => {\n setIsDarkMode(document.documentElement.classList.contains(\"dark-mode\"));\n };\n\n checkDarkMode();\n\n // Watch for dark mode changes\n const observer = new MutationObserver(checkDarkMode);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n\n return () => observer.disconnect();\n }, []);\n\n // Color gradients for light and dark modes\n const lightModeColors = [\n \"rgba(0, 212, 255, 0.15)\", // Bright cyan\n \"rgba(173, 230, 255, 0.12)\", // Light cyan\n \"rgba(102, 178, 255, 0.1)\", // Soft blue\n \"rgba(0, 153, 204, 0.08)\", // Deeper cyan\n ];\n\n const darkModeColors = [\n \"rgba(0, 102, 255, 0.2)\", // Deep blue\n \"rgba(51, 153, 255, 0.15)\", // Bright blue\n \"rgba(102, 178, 255, 0.12)\", // Light blue\n \"rgba(0, 51, 204, 0.1)\", // Dark blue\n ];\n\n const colors = isDarkMode ? darkModeColors : lightModeColors;\n\n // Check for reduced motion preference\n const prefersReducedMotion = typeof window !== \"undefined\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\n // Animation variants - more pronounced movement for visible distortion\n const orbVariants = {\n animate: {\n x: prefersReducedMotion ? 0 : [0, 100, -80, 60, -40, 0],\n y: prefersReducedMotion ? 0 : [0, -80, 60, -50, 40, 0],\n scale: prefersReducedMotion ? 1 : [1, 1.3, 0.8, 1.2, 0.9, 1],\n },\n };\n\n const transition = {\n duration: prefersReducedMotion ? 0 : 12,\n repeat: Infinity,\n ease: \"easeInOut\" as const,\n };\n\n return (\n <div className=\"pointer-events-none fixed inset-0 -z-10 overflow-hidden\" aria-hidden=\"true\">\n {/* Floating Orbs */}\n {colors.map((color, index) => {\n const size = 400 + index * 120;\n const initialX = 10 + index * 30;\n const initialY = 20 + index * 25;\n\n return (\n <motion.div\n key={color}\n className=\"absolute rounded-full blur-3xl\"\n style={{\n width: `${size}px`,\n height: `${size}px`,\n background: `radial-gradient(circle, ${color} 0%, transparent 70%)`,\n left: `${initialX}%`,\n top: `${initialY}%`,\n }}\n variants={orbVariants}\n animate=\"animate\"\n transition={{\n ...transition,\n delay: index * 1.5,\n }}\n />\n );\n })}\n\n {/* Subtle gradient overlay for depth */}\n <div\n className=\"absolute inset-0 opacity-30\"\n style={{\n background: isDarkMode\n ? \"radial-gradient(circle at 50% 50%, rgba(0, 102, 255, 0.1) 0%, transparent 70%)\"\n : \"radial-gradient(circle at 50% 50%, rgba(0, 212, 255, 0.08) 0%, transparent 70%)\",\n }}\n />\n </div>\n );\n};\n\nexport default LiquidGlassBackground;\n"],"mappings":"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","names":["useMotionPreset","motion","useMemo","jsx","jsxs","motion","jsx","jsxs"]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@enact-ui/backgrounds",
3
+ "version": "1.0.0",
4
+ "description": "Decorative background effects for ENACT UI. Purely cosmetic - can be removed without functional impact.",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "sideEffects": false,
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc --build && tsup",
22
+ "dev": "tsup --watch",
23
+ "type-check": "tsc --noEmit",
24
+ "lint": "biome check --write .",
25
+ "lint:check": "biome check .",
26
+ "clean": "rm -rf dist tsconfig.tsbuildinfo"
27
+ },
28
+ "peerDependencies": {
29
+ "@enact-ui/animate": "^1.0.0",
30
+ "@enact-ui/react": "^0.0.0",
31
+ "motion": "^12.0.0",
32
+ "react": "^18.0.0 || ^19.0.0",
33
+ "react-dom": "^18.0.0 || ^19.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/react": "^19.1.9",
37
+ "@types/react-dom": "^19.1.7",
38
+ "typescript": "^5.9.2"
39
+ },
40
+ "keywords": [
41
+ "react",
42
+ "backgrounds",
43
+ "decorative",
44
+ "animation",
45
+ "enact-ui"
46
+ ],
47
+ "engines": {
48
+ "node": ">=24.0.0",
49
+ "npm": ">=10.0.0"
50
+ },
51
+ "author": "Enact UI",
52
+ "license": "MIT",
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "https://github.com/enact-ui/enact-ui.git",
56
+ "directory": "packages/backgrounds"
57
+ },
58
+ "bugs": {
59
+ "url": "https://github.com/enact-ui/enact-ui/issues"
60
+ },
61
+ "homepage": "https://enact-ui.com"
62
+ }