real-time-gradient 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/README.md +235 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +231 -0
- package/dist/index.umd.js +1 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# 🌅 dynamic-gradient
|
|
2
|
+
|
|
3
|
+
A lightweight JavaScript library for creating smooth, customizable, real-time gradients with flexible control over animation speed, direction, and hues.
|
|
4
|
+
|
|
5
|
+
## UMD (Browser) Usage
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<script src="dynamic-gradient.min.js"></script>
|
|
9
|
+
<script>
|
|
10
|
+
const gradient = DynamicGradient.init("#hero", {
|
|
11
|
+
type: "linear",
|
|
12
|
+
direction: "to right",
|
|
13
|
+
colors: ["#ff7e5f", "#feb47b"],
|
|
14
|
+
});
|
|
15
|
+
</script>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## ✨ Features
|
|
19
|
+
|
|
20
|
+
- 🎨 Smooth color transitions (linear, radial, conic)
|
|
21
|
+
|
|
22
|
+
- ⚡ Dynamic scheduling (interval-based animation)
|
|
23
|
+
|
|
24
|
+
- 🔄 Runtime updates (colors, speed, direction)
|
|
25
|
+
|
|
26
|
+
- 📦 Framework-agnostic — works with plain JS, React, Vue, etc.
|
|
27
|
+
|
|
28
|
+
- 🖼 Gradient-to-text clipping (textClip)
|
|
29
|
+
|
|
30
|
+
- 🛠 TypeScript typings
|
|
31
|
+
|
|
32
|
+
## 🖼️ Basic Usage
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<div id="hero" style="height: 300px;"></div>
|
|
36
|
+
|
|
37
|
+
<script type="module">
|
|
38
|
+
import DynamicGradient from "dynamic-gradient";
|
|
39
|
+
|
|
40
|
+
const gradient = DynamicGradient.init("#hero", {
|
|
41
|
+
type: "linear",
|
|
42
|
+
direction: "to right",
|
|
43
|
+
colors: ["#ff7e5f", "#feb47b"],
|
|
44
|
+
transitionDuration: 1000,
|
|
45
|
+
schedule: [
|
|
46
|
+
{ time: "6:00", colors: ["#7fff00ff", "#ffb347ff", "#ff69b4ff"] },
|
|
47
|
+
{ time: "18:00", colors: ["#ff4500ff", "#9370dbff", "#4682b4ff"] },
|
|
48
|
+
{ time: "00:00", colors: ["#ffff54ff", "#ff7f50ff", "#daa520ff"] },
|
|
49
|
+
],
|
|
50
|
+
});
|
|
51
|
+
</script>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## ⚙️ API Reference
|
|
55
|
+
|
|
56
|
+
`DynamicGradient.init(target, options)`
|
|
57
|
+
Initialize a gradient on a DOM element.
|
|
58
|
+
|
|
59
|
+
#### Parameters
|
|
60
|
+
|
|
61
|
+
- `target`: CSS selector or DOM element
|
|
62
|
+
- `options` : configuration object
|
|
63
|
+
|
|
64
|
+
#### Options:
|
|
65
|
+
|
|
66
|
+
- `type`: `"linear" | "radial"` (default: `"linear"` )
|
|
67
|
+
- `direction`: CSS gradient direction (e.g., `"to right"`, `"45deg"` )
|
|
68
|
+
- `colors`: array of color hex values
|
|
69
|
+
- `transitionDuration`: time in ms for transitions (default: `1000`)
|
|
70
|
+
- `schedule`: optional array of {`time: "HH:MM", colors: []`} objects
|
|
71
|
+
- `textClip`: boolean (default: `false`) → applies gradient as background-clip for text
|
|
72
|
+
|
|
73
|
+
### `stopEffects()`
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
gradient.stopEffects();
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### `triggerEffect({ applyColors, duration, hue })`
|
|
80
|
+
|
|
81
|
+
Overlay temporary effect
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
gradient.triggerEffect({
|
|
85
|
+
hue: "gold",
|
|
86
|
+
duration: 2000,
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
gradient.triggerEffect({
|
|
92
|
+
applyColors: ["#9370dbff", "#4682b4ff"],
|
|
93
|
+
duration: 2000,
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### `persistEffect(colors[], duration)`
|
|
98
|
+
|
|
99
|
+
Mutate a new gradient smoothly
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
gradient.persistEffect(["#9370db", "#4682b4"], 2000);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `schedule([{ time: "HH:MM", colors: [] }, ...])`
|
|
106
|
+
|
|
107
|
+
Allows scheduling of time-based gradients that change automatically throughout the day.
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
const gradient = DynamicGradient.init("#hero", {
|
|
111
|
+
type: "linear",
|
|
112
|
+
direction: "to right",
|
|
113
|
+
colors: ["#ff7f50ff", "#6a5acdff", "#20b2aaff"], // default
|
|
114
|
+
schedule: [
|
|
115
|
+
{ time: "06:00", colors: ["#7fff00ff", "#ffb347ff", "#ff69b4ff"] }, // morning
|
|
116
|
+
{ time: "18:00", colors: ["#ff4500ff", "#9370dbff", "#4682b4ff"] }, // evening
|
|
117
|
+
{ time: "00:00", colors: ["#ffff54ff", "#ff7f50ff", "#daa520ff"] }, // midnight
|
|
118
|
+
],
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- `time`: "HH:MM" in `24h format`(e.g. `"06:00"`,`"18:30"` )
|
|
123
|
+
- `colors`: array of CSS colors for the gradient
|
|
124
|
+
|
|
125
|
+
#### Optional per-entry:
|
|
126
|
+
|
|
127
|
+
- `type`: `"linear"` or `"radial"`
|
|
128
|
+
- `direction`: CSS gradient direction(`"to right"`, `"45deg"`, etc.)
|
|
129
|
+
|
|
130
|
+
#### Behavior
|
|
131
|
+
|
|
132
|
+
- The most recent matching entry before or equal to the current time will be applied.
|
|
133
|
+
- If the time is earlier than the first scheduled entry, it wraps around and uses the last entry.
|
|
134
|
+
- The schedule is checked every minute, so changes align with the clock naturally.
|
|
135
|
+
|
|
136
|
+
### `destroy()`
|
|
137
|
+
|
|
138
|
+
Stop the gradient animation and clean up.
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
gradient.destroy();
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 🎨 Hue Presets
|
|
145
|
+
|
|
146
|
+
Some ready-to-use gradient palettes:
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
hues = {
|
|
150
|
+
sunset: ["#ff7e5f", "#feb47b"],
|
|
151
|
+
ocean: ["#00c6ff", "#0072ff"],
|
|
152
|
+
forest: ["#11998e", "#38ef7d"],
|
|
153
|
+
fire: ["#ff512f", "#dd2476"],
|
|
154
|
+
mono: ["#ffffff", "#000000"],
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Additionally, `triggerEffect` accepts special hue keywords:
|
|
159
|
+
|
|
160
|
+
- `"white"`, `"black"`, `"gold"`, `"silver"`
|
|
161
|
+
- Or any custom hex string (`"#RRGGBB"`)
|
|
162
|
+
|
|
163
|
+
Usage:
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
gradient.setGradient({ colors: hues.forest });
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Or:
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
gradient.triggerEffect({ hue: "gold", duration: 2000 });
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## 📦 TypeScript Typings
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// index.d.ts
|
|
179
|
+
declare module "real-time-gradient" {
|
|
180
|
+
type GradientType = "linear" | "radial";
|
|
181
|
+
|
|
182
|
+
type HuePreset = "white" | "black" | "gold" | "silver" | string;
|
|
183
|
+
// string allows custom hex codes "#RRGGBB"
|
|
184
|
+
|
|
185
|
+
interface ScheduleEntry {
|
|
186
|
+
time: string; // "HH:MM" in 24h format
|
|
187
|
+
colors: string[]; // array of CSS color values
|
|
188
|
+
type?: GradientType;
|
|
189
|
+
direction?: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
interface GradientOptions {
|
|
193
|
+
type?: GradientType;
|
|
194
|
+
direction?: string;
|
|
195
|
+
colors?: string[];
|
|
196
|
+
transitionDuration?: number;
|
|
197
|
+
schedule?: ScheduleEntry[];
|
|
198
|
+
textClip?: boolean;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
interface EffectOptions {
|
|
202
|
+
applyColors?: string[];
|
|
203
|
+
duration?: number;
|
|
204
|
+
hue?: HuePreset;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export class DynamicGradient {
|
|
208
|
+
constructor(container: string | HTMLElement, options?: GradientOptions);
|
|
209
|
+
|
|
210
|
+
static init(
|
|
211
|
+
container: string | HTMLElement,
|
|
212
|
+
options?: GradientOptions
|
|
213
|
+
): DynamicGradient;
|
|
214
|
+
|
|
215
|
+
setGradient(options: {
|
|
216
|
+
colors: string[];
|
|
217
|
+
type?: GradientType;
|
|
218
|
+
direction?: string;
|
|
219
|
+
}): void;
|
|
220
|
+
|
|
221
|
+
schedule(entries: ScheduleEntry[]): void;
|
|
222
|
+
|
|
223
|
+
triggerEffect(options?: EffectOptions): void;
|
|
224
|
+
|
|
225
|
+
persistEffect(colors: string[], duration?: number): void;
|
|
226
|
+
|
|
227
|
+
stopEffects(): void;
|
|
228
|
+
destroy(): void;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## 📄 License
|
|
234
|
+
|
|
235
|
+
MIT © 2025 — @wakenedo
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
function c(n, e = "linear", t = "to right") {
|
|
2
|
+
return e === "linear" ? `linear-gradient(${t}, ${n.join(",")})` : `radial-gradient(circle, ${n.join(",")})`;
|
|
3
|
+
}
|
|
4
|
+
function f(n, e, t) {
|
|
5
|
+
const i = document.createElement("div");
|
|
6
|
+
return Object.assign(i.style, {
|
|
7
|
+
position: "absolute",
|
|
8
|
+
top: 0,
|
|
9
|
+
left: 0,
|
|
10
|
+
width: "100%",
|
|
11
|
+
height: "100%",
|
|
12
|
+
pointerEvents: "none",
|
|
13
|
+
zIndex: 0,
|
|
14
|
+
background: e,
|
|
15
|
+
opacity: "0",
|
|
16
|
+
transition: `opacity ${t}ms ease-in-out`
|
|
17
|
+
}), n.appendChild(i), i;
|
|
18
|
+
}
|
|
19
|
+
function m(n, e, t) {
|
|
20
|
+
const i = document.createElement("span");
|
|
21
|
+
i.textContent = n.textContent, Object.assign(i.style, {
|
|
22
|
+
position: "absolute",
|
|
23
|
+
top: 0,
|
|
24
|
+
left: 0,
|
|
25
|
+
width: "100%",
|
|
26
|
+
height: "100%",
|
|
27
|
+
display: "inline-block",
|
|
28
|
+
background: e,
|
|
29
|
+
WebkitBackgroundClip: "text",
|
|
30
|
+
backgroundClip: "text",
|
|
31
|
+
WebkitTextFillColor: "transparent",
|
|
32
|
+
color: "transparent",
|
|
33
|
+
pointerEvents: "none",
|
|
34
|
+
opacity: "0",
|
|
35
|
+
transition: `opacity ${t}ms ease-in-out`,
|
|
36
|
+
zIndex: 20
|
|
37
|
+
});
|
|
38
|
+
const s = n.parentNode;
|
|
39
|
+
getComputedStyle(s).position === "static" && (s.style.position = "relative"), s.appendChild(i), requestAnimationFrame(() => {
|
|
40
|
+
i.style.opacity = "1";
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function b(n, e) {
|
|
44
|
+
if (n.__dgTextFx && n.__dgTextFx.duration !== e) {
|
|
45
|
+
const { a, b: o } = n.__dgTextFx;
|
|
46
|
+
return a.style.transition = o.style.transition = `opacity ${e}ms ease-in-out`, n.__dgTextFx.duration = e, n.__dgTextFx;
|
|
47
|
+
}
|
|
48
|
+
if (n.__dgTextFx) return n.__dgTextFx;
|
|
49
|
+
const t = n.parentNode;
|
|
50
|
+
getComputedStyle(t).position === "static" && (t.style.position = "relative");
|
|
51
|
+
const i = (a) => {
|
|
52
|
+
const o = document.createElement("span");
|
|
53
|
+
return o.textContent = n.textContent, Object.assign(o.style, {
|
|
54
|
+
position: "absolute",
|
|
55
|
+
top: 0,
|
|
56
|
+
left: 0,
|
|
57
|
+
width: "100%",
|
|
58
|
+
height: "100%",
|
|
59
|
+
display: "inline-block",
|
|
60
|
+
WebkitBackgroundClip: "text",
|
|
61
|
+
backgroundClip: "text",
|
|
62
|
+
WebkitTextFillColor: "transparent",
|
|
63
|
+
color: "transparent",
|
|
64
|
+
pointerEvents: "none",
|
|
65
|
+
opacity: "0",
|
|
66
|
+
willChange: "opacity",
|
|
67
|
+
zIndex: a,
|
|
68
|
+
transition: `opacity ${e}ms ease-in-out`
|
|
69
|
+
}), t.appendChild(o), o;
|
|
70
|
+
}, s = i(20), r = i(21);
|
|
71
|
+
return n.__dgTextFx = { a: s, b: r, visible: null, duration: e }, n.__dgTextFx;
|
|
72
|
+
}
|
|
73
|
+
function k() {
|
|
74
|
+
const n = /* @__PURE__ */ new Date();
|
|
75
|
+
return `${String(n.getHours()).padStart(2, "0")}:${String(
|
|
76
|
+
n.getMinutes()
|
|
77
|
+
).padStart(2, "0")}`;
|
|
78
|
+
}
|
|
79
|
+
function C(n, e) {
|
|
80
|
+
if (!n.length) return null;
|
|
81
|
+
let t = n[0];
|
|
82
|
+
for (let i = 0; i < n.length; i++)
|
|
83
|
+
e >= n[i].time && (t = n[i]);
|
|
84
|
+
return e < n[0].time && (t = n[n.length - 1]), t;
|
|
85
|
+
}
|
|
86
|
+
const p = {
|
|
87
|
+
white: "#ffffff",
|
|
88
|
+
black: "#000000",
|
|
89
|
+
gold: "#ffe864ff",
|
|
90
|
+
silver: "#d4d4d4ff"
|
|
91
|
+
};
|
|
92
|
+
class g {
|
|
93
|
+
constructor(e, t = {}) {
|
|
94
|
+
if (this.container = typeof e == "string" ? document.querySelector(e) : e, !this.container)
|
|
95
|
+
throw new Error("DynamicGradient: container not found.");
|
|
96
|
+
this.type = t.type || "linear", this.direction = t.direction || "to right", this.colors = t.colors || ["#1e3c72", "#2a5298"], this.transitionDuration = t.transitionDuration ?? 1500, this.textClip = t.textClip || !1, this.scheduleData = t.schedule || [], this.currentInterval = null, this.lastAppliedKey = null, this.container.style.position = this.container.style.position || "relative", this.applyGradient(this.colors, this.type, this.direction, !1), this.scheduleData.length > 0 && this.schedule(this.scheduleData);
|
|
97
|
+
}
|
|
98
|
+
/** Apply gradient with optional transition */
|
|
99
|
+
applyGradient(e = this.colors, t = this.type, i = this.direction, s = !0) {
|
|
100
|
+
const r = c(e, t, i), a = this.container.style.background;
|
|
101
|
+
if (r !== a) {
|
|
102
|
+
if (this.textClip) {
|
|
103
|
+
const o = m(
|
|
104
|
+
this.container,
|
|
105
|
+
r,
|
|
106
|
+
this.duration
|
|
107
|
+
);
|
|
108
|
+
this.container.style.background = o, this.container.style.fontWeight = "inherit";
|
|
109
|
+
} else
|
|
110
|
+
s ? (this.transitionOverlay && this.transitionOverlay.remove(), this.transitionOverlay = f(
|
|
111
|
+
this.container,
|
|
112
|
+
r,
|
|
113
|
+
this.transitionDuration
|
|
114
|
+
), requestAnimationFrame(() => {
|
|
115
|
+
this.transitionOverlay.style.opacity = "1";
|
|
116
|
+
}), setTimeout(() => {
|
|
117
|
+
this.container.style.background = r, this.transitionOverlay.remove(), this.transitionOverlay = null;
|
|
118
|
+
}, this.transitionDuration)) : this.container.style.background = r;
|
|
119
|
+
this.colors = e, this.type = t, this.direction = i;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Allow toggling text-clip dynamically */
|
|
123
|
+
setTextClip(e = !0) {
|
|
124
|
+
this.textClip = e, this.applyGradient(this.colors, this.type, this.direction, !1);
|
|
125
|
+
}
|
|
126
|
+
/** Trigger a temporary animated effect */
|
|
127
|
+
triggerEffect({
|
|
128
|
+
applyColors: e = null,
|
|
129
|
+
duration: t = this.transitionDuration,
|
|
130
|
+
loop: i = !0,
|
|
131
|
+
hue: s = "white"
|
|
132
|
+
} = {}) {
|
|
133
|
+
let r;
|
|
134
|
+
p[s] ? r = p[s] : /^#([0-9A-F]{3}){1,2}$/i.test(s) ? r = s : r = "#ffffff";
|
|
135
|
+
const a = e ? c(e, this.type, this.direction) : c([...this.colors, r], this.type, this.direction);
|
|
136
|
+
if (this.textClip) {
|
|
137
|
+
const y = b(this.container, t), d = () => {
|
|
138
|
+
const { a: h, b: v, visible: x } = y, l = x === "a" ? v : h, T = e ? c(e, this.type, this.direction) : c(
|
|
139
|
+
[...this.colors, p[s] || r],
|
|
140
|
+
this.type,
|
|
141
|
+
this.direction
|
|
142
|
+
);
|
|
143
|
+
l.style.background = T, l.style.backgroundClip = "text", l.style.transition = `opacity ${t}ms ease-in-out`, l.style.opacity = "0", requestAnimationFrame(() => {
|
|
144
|
+
requestAnimationFrame(() => {
|
|
145
|
+
l.style.opacity = "1";
|
|
146
|
+
});
|
|
147
|
+
}), setTimeout(() => {
|
|
148
|
+
l.style.opacity = "0";
|
|
149
|
+
}, t), y.visible = l === h ? "a" : "b", i ? (this.effectLoopTimeout && clearTimeout(this.effectLoopTimeout), this.effectLoopTimeout = setTimeout(d, t * 2)) : setTimeout(() => {
|
|
150
|
+
this.applyGradient(
|
|
151
|
+
e || this.colors,
|
|
152
|
+
this.type,
|
|
153
|
+
this.direction,
|
|
154
|
+
!1
|
|
155
|
+
), h.style.opacity = "0", v.style.opacity = "0";
|
|
156
|
+
}, t * 2);
|
|
157
|
+
};
|
|
158
|
+
d();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
this.effectOverlay || (this.effectOverlay = f(
|
|
162
|
+
this.container,
|
|
163
|
+
a,
|
|
164
|
+
t
|
|
165
|
+
));
|
|
166
|
+
const o = this.effectOverlay, u = () => {
|
|
167
|
+
o.style.background = a, o.style.opacity = "1", setTimeout(() => {
|
|
168
|
+
o.style.opacity = "0";
|
|
169
|
+
}, t);
|
|
170
|
+
};
|
|
171
|
+
this.effectRunning || (this.effectRunning = !0, u(), i ? (this.effectLoopInterval && clearInterval(this.effectLoopInterval), this.effectLoopInterval = setInterval(u, t * 2)) : setTimeout(() => {
|
|
172
|
+
o.remove(), this.effectOverlay = null;
|
|
173
|
+
}, t * 2));
|
|
174
|
+
}
|
|
175
|
+
persistEffect(e = this.colors, t = this.transitionDuration) {
|
|
176
|
+
const i = c(
|
|
177
|
+
e,
|
|
178
|
+
this.type,
|
|
179
|
+
this.direction
|
|
180
|
+
);
|
|
181
|
+
if (this.textClip) {
|
|
182
|
+
const s = m(
|
|
183
|
+
this.container,
|
|
184
|
+
i,
|
|
185
|
+
t
|
|
186
|
+
);
|
|
187
|
+
requestAnimationFrame(() => {
|
|
188
|
+
s.style.opacity = "1";
|
|
189
|
+
}), setTimeout(() => {
|
|
190
|
+
this.applyGradient(e, this.type, this.direction, !1);
|
|
191
|
+
}, t);
|
|
192
|
+
} else {
|
|
193
|
+
const s = f(this.container, i, t);
|
|
194
|
+
requestAnimationFrame(() => {
|
|
195
|
+
s.style.opacity = "1";
|
|
196
|
+
}), setTimeout(() => {
|
|
197
|
+
this.applyGradient(e, this.type, this.direction, !1), s.remove();
|
|
198
|
+
}, t);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
stopEffects() {
|
|
202
|
+
this.effectLoopInterval && (clearInterval(this.effectLoopInterval), this.effectLoopInterval = null), this.effectLoopTimeout && (clearTimeout(this.effectLoopTimeout), this.effectLoopTimeout = null), this.effectRunning = !1;
|
|
203
|
+
}
|
|
204
|
+
// ✅ added: cleanup method to prevent leaks
|
|
205
|
+
destroy() {
|
|
206
|
+
this.stopEffects(), this.currentInterval && (clearInterval(this.currentInterval), this.currentInterval = null), this.transitionOverlay && (this.transitionOverlay.remove(), this.transitionOverlay = null), this.effectOverlay && (this.effectOverlay.remove(), this.effectOverlay = null);
|
|
207
|
+
}
|
|
208
|
+
setGradient({ colors: e, type: t, direction: i }) {
|
|
209
|
+
const s = e || this.colors, r = t || this.type, a = i || this.direction;
|
|
210
|
+
s.join(",") === this.colors.join(",") && r === this.type && a === this.direction || this.applyGradient(s, r, a, !0);
|
|
211
|
+
}
|
|
212
|
+
schedule(e = []) {
|
|
213
|
+
this.scheduleData = e.map((t) => ({
|
|
214
|
+
...t,
|
|
215
|
+
time: t.time.padStart(5, "0")
|
|
216
|
+
})).sort((t, i) => t.time.localeCompare(i.time)), this.currentInterval && clearInterval(this.currentInterval), this.checkSchedule(), this.currentInterval = setInterval(() => this.checkSchedule(), 60 * 1e3);
|
|
217
|
+
}
|
|
218
|
+
checkSchedule() {
|
|
219
|
+
const e = k(), t = C(this.scheduleData, e);
|
|
220
|
+
if (t) {
|
|
221
|
+
const i = `${t.time}-${t.colors.join(",")}`;
|
|
222
|
+
i !== this.lastAppliedKey && (this.setGradient(t), this.lastAppliedKey = i);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
static init(e, t) {
|
|
226
|
+
return new g(e, t);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
export {
|
|
230
|
+
g as DynamicGradient
|
|
231
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(h,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(h=typeof globalThis<"u"?globalThis:h||self,l(h.RealTimeGradient={}))})(this,function(h){"use strict";function l(n,e="linear",t="to right"){return e==="linear"?`linear-gradient(${t}, ${n.join(",")})`:`radial-gradient(circle, ${n.join(",")})`}function f(n,e,t){const i=document.createElement("div");return Object.assign(i.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%",pointerEvents:"none",zIndex:0,background:e,opacity:"0",transition:`opacity ${t}ms ease-in-out`}),n.appendChild(i),i}function d(n,e,t){const i=document.createElement("span");i.textContent=n.textContent,Object.assign(i.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%",display:"inline-block",background:e,WebkitBackgroundClip:"text",backgroundClip:"text",WebkitTextFillColor:"transparent",color:"transparent",pointerEvents:"none",opacity:"0",transition:`opacity ${t}ms ease-in-out`,zIndex:20});const s=n.parentNode;getComputedStyle(s).position==="static"&&(s.style.position="relative"),s.appendChild(i),requestAnimationFrame(()=>{i.style.opacity="1"})}function T(n,e){if(n.__dgTextFx&&n.__dgTextFx.duration!==e){const{a,b:o}=n.__dgTextFx;return a.style.transition=o.style.transition=`opacity ${e}ms ease-in-out`,n.__dgTextFx.duration=e,n.__dgTextFx}if(n.__dgTextFx)return n.__dgTextFx;const t=n.parentNode;getComputedStyle(t).position==="static"&&(t.style.position="relative");const i=a=>{const o=document.createElement("span");return o.textContent=n.textContent,Object.assign(o.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%",display:"inline-block",WebkitBackgroundClip:"text",backgroundClip:"text",WebkitTextFillColor:"transparent",color:"transparent",pointerEvents:"none",opacity:"0",willChange:"opacity",zIndex:a,transition:`opacity ${e}ms ease-in-out`}),t.appendChild(o),o},s=i(20),r=i(21);return n.__dgTextFx={a:s,b:r,visible:null,duration:e},n.__dgTextFx}function b(){const n=new Date;return`${String(n.getHours()).padStart(2,"0")}:${String(n.getMinutes()).padStart(2,"0")}`}function k(n,e){if(!n.length)return null;let t=n[0];for(let i=0;i<n.length;i++)e>=n[i].time&&(t=n[i]);return e<n[0].time&&(t=n[n.length-1]),t}const u={white:"#ffffff",black:"#000000",gold:"#ffe864ff",silver:"#d4d4d4ff"};class p{constructor(e,t={}){if(this.container=typeof e=="string"?document.querySelector(e):e,!this.container)throw new Error("DynamicGradient: container not found.");this.type=t.type||"linear",this.direction=t.direction||"to right",this.colors=t.colors||["#1e3c72","#2a5298"],this.transitionDuration=t.transitionDuration??1500,this.textClip=t.textClip||!1,this.scheduleData=t.schedule||[],this.currentInterval=null,this.lastAppliedKey=null,this.container.style.position=this.container.style.position||"relative",this.applyGradient(this.colors,this.type,this.direction,!1),this.scheduleData.length>0&&this.schedule(this.scheduleData)}applyGradient(e=this.colors,t=this.type,i=this.direction,s=!0){const r=l(e,t,i),a=this.container.style.background;if(r!==a){if(this.textClip){const o=d(this.container,r,this.duration);this.container.style.background=o,this.container.style.fontWeight="inherit"}else s?(this.transitionOverlay&&this.transitionOverlay.remove(),this.transitionOverlay=f(this.container,r,this.transitionDuration),requestAnimationFrame(()=>{this.transitionOverlay.style.opacity="1"}),setTimeout(()=>{this.container.style.background=r,this.transitionOverlay.remove(),this.transitionOverlay=null},this.transitionDuration)):this.container.style.background=r;this.colors=e,this.type=t,this.direction=i}}setTextClip(e=!0){this.textClip=e,this.applyGradient(this.colors,this.type,this.direction,!1)}triggerEffect({applyColors:e=null,duration:t=this.transitionDuration,loop:i=!0,hue:s="white"}={}){let r;u[s]?r=u[s]:/^#([0-9A-F]{3}){1,2}$/i.test(s)?r=s:r="#ffffff";const a=e?l(e,this.type,this.direction):l([...this.colors,r],this.type,this.direction);if(this.textClip){const v=T(this.container,t),g=()=>{const{a:y,b:x,visible:C}=v,c=C==="a"?x:y,O=e?l(e,this.type,this.direction):l([...this.colors,u[s]||r],this.type,this.direction);c.style.background=O,c.style.backgroundClip="text",c.style.transition=`opacity ${t}ms ease-in-out`,c.style.opacity="0",requestAnimationFrame(()=>{requestAnimationFrame(()=>{c.style.opacity="1"})}),setTimeout(()=>{c.style.opacity="0"},t),v.visible=c===y?"a":"b",i?(this.effectLoopTimeout&&clearTimeout(this.effectLoopTimeout),this.effectLoopTimeout=setTimeout(g,t*2)):setTimeout(()=>{this.applyGradient(e||this.colors,this.type,this.direction,!1),y.style.opacity="0",x.style.opacity="0"},t*2)};g();return}this.effectOverlay||(this.effectOverlay=f(this.container,a,t));const o=this.effectOverlay,m=()=>{o.style.background=a,o.style.opacity="1",setTimeout(()=>{o.style.opacity="0"},t)};this.effectRunning||(this.effectRunning=!0,m(),i?(this.effectLoopInterval&&clearInterval(this.effectLoopInterval),this.effectLoopInterval=setInterval(m,t*2)):setTimeout(()=>{o.remove(),this.effectOverlay=null},t*2))}persistEffect(e=this.colors,t=this.transitionDuration){const i=l(e,this.type,this.direction);if(this.textClip){const s=d(this.container,i,t);requestAnimationFrame(()=>{s.style.opacity="1"}),setTimeout(()=>{this.applyGradient(e,this.type,this.direction,!1)},t)}else{const s=f(this.container,i,t);requestAnimationFrame(()=>{s.style.opacity="1"}),setTimeout(()=>{this.applyGradient(e,this.type,this.direction,!1),s.remove()},t)}}stopEffects(){this.effectLoopInterval&&(clearInterval(this.effectLoopInterval),this.effectLoopInterval=null),this.effectLoopTimeout&&(clearTimeout(this.effectLoopTimeout),this.effectLoopTimeout=null),this.effectRunning=!1}destroy(){this.stopEffects(),this.currentInterval&&(clearInterval(this.currentInterval),this.currentInterval=null),this.transitionOverlay&&(this.transitionOverlay.remove(),this.transitionOverlay=null),this.effectOverlay&&(this.effectOverlay.remove(),this.effectOverlay=null)}setGradient({colors:e,type:t,direction:i}){const s=e||this.colors,r=t||this.type,a=i||this.direction;s.join(",")===this.colors.join(",")&&r===this.type&&a===this.direction||this.applyGradient(s,r,a,!0)}schedule(e=[]){this.scheduleData=e.map(t=>({...t,time:t.time.padStart(5,"0")})).sort((t,i)=>t.time.localeCompare(i.time)),this.currentInterval&&clearInterval(this.currentInterval),this.checkSchedule(),this.currentInterval=setInterval(()=>this.checkSchedule(),60*1e3)}checkSchedule(){const e=b(),t=k(this.scheduleData,e);if(t){const i=`${t.time}-${t.colors.join(",")}`;i!==this.lastAppliedKey&&(this.setGradient(t),this.lastAppliedKey=i)}}static init(e,t){return new p(e,t)}}h.DynamicGradient=p,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "real-time-gradient",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A Dynamic Gradient background library.",
|
|
5
|
+
"main": "dist/index.umd.js",
|
|
6
|
+
"module": "dist/index.es.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "vite build"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"background",
|
|
16
|
+
"gradient",
|
|
17
|
+
"dynamic",
|
|
18
|
+
"canvas"
|
|
19
|
+
],
|
|
20
|
+
"author": "wakenedo",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"vite": "^5.4.19",
|
|
24
|
+
"vite-plugin-dts": "^4.5.4"
|
|
25
|
+
}
|
|
26
|
+
}
|