xiod-ui 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/LICENSE +73 -0
- package/README.md +167 -0
- package/dist/components/accordion.d.ts +9 -0
- package/dist/components/accordion.js +46 -0
- package/dist/components/agent-steps.d.ts +47 -0
- package/dist/components/agent-steps.js +223 -0
- package/dist/components/alert-dialog.d.ts +21 -0
- package/dist/components/alert-dialog.js +74 -0
- package/dist/components/alert.d.ts +12 -0
- package/dist/components/alert.js +45 -0
- package/dist/components/aspect-ratio.d.ts +9 -0
- package/dist/components/aspect-ratio.js +22 -0
- package/dist/components/autocomplete.d.ts +35 -0
- package/dist/components/autocomplete.js +160 -0
- package/dist/components/avatar.d.ts +17 -0
- package/dist/components/avatar.js +65 -0
- package/dist/components/badge.d.ts +15 -0
- package/dist/components/badge.js +46 -0
- package/dist/components/breadcrumb.d.ts +12 -0
- package/dist/components/breadcrumb.js +75 -0
- package/dist/components/button-group.d.ts +14 -0
- package/dist/components/button-group.js +45 -0
- package/dist/components/button-split.d.ts +19 -0
- package/dist/components/button-split.js +73 -0
- package/dist/components/button.d.ts +15 -0
- package/dist/components/button.js +54 -0
- package/dist/components/calendar.d.ts +63 -0
- package/dist/components/calendar.js +425 -0
- package/dist/components/card.d.ts +17 -0
- package/dist/components/card.js +139 -0
- package/dist/components/carousel.d.ts +59 -0
- package/dist/components/carousel.js +503 -0
- package/dist/components/checkbox.d.ts +16 -0
- package/dist/components/checkbox.js +86 -0
- package/dist/components/circular-progress.d.ts +28 -0
- package/dist/components/circular-progress.js +127 -0
- package/dist/components/collapsible.d.ts +8 -0
- package/dist/components/collapsible.js +27 -0
- package/dist/components/color-picker.d.ts +159 -0
- package/dist/components/color-picker.js +1589 -0
- package/dist/components/combobox.d.ts +46 -0
- package/dist/components/combobox.js +237 -0
- package/dist/components/command.d.ts +22 -0
- package/dist/components/command.js +129 -0
- package/dist/components/context-menu.d.ts +38 -0
- package/dist/components/context-menu.js +164 -0
- package/dist/components/copy-to-clipboard.d.ts +32 -0
- package/dist/components/copy-to-clipboard.js +83 -0
- package/dist/components/corner-badge.d.ts +22 -0
- package/dist/components/corner-badge.js +84 -0
- package/dist/components/dashboard-grid.d.ts +83 -0
- package/dist/components/dashboard-grid.js +486 -0
- package/dist/components/date-picker.d.ts +29 -0
- package/dist/components/date-picker.js +261 -0
- package/dist/components/dialog.d.ts +26 -0
- package/dist/components/dialog.js +97 -0
- package/dist/components/dot-matrix.d.ts +32 -0
- package/dist/components/dot-matrix.js +707 -0
- package/dist/components/draggable.d.ts +42 -0
- package/dist/components/draggable.js +346 -0
- package/dist/components/drawer.d.ts +66 -0
- package/dist/components/drawer.js +304 -0
- package/dist/components/empty.d.ts +14 -0
- package/dist/components/empty.js +75 -0
- package/dist/components/field.d.ts +12 -0
- package/dist/components/field.js +44 -0
- package/dist/components/fieldset.d.ts +7 -0
- package/dist/components/fieldset.js +21 -0
- package/dist/components/file-upload.d.ts +61 -0
- package/dist/components/file-upload.js +482 -0
- package/dist/components/form.d.ts +6 -0
- package/dist/components/form.js +14 -0
- package/dist/components/frame.d.ts +10 -0
- package/dist/components/frame.js +47 -0
- package/dist/components/gauge.d.ts +27 -0
- package/dist/components/gauge.js +74 -0
- package/dist/components/grid.d.ts +26 -0
- package/dist/components/grid.js +204 -0
- package/dist/components/group.d.ts +19 -0
- package/dist/components/group.js +45 -0
- package/dist/components/input-group.d.ts +15 -0
- package/dist/components/input-group.js +61 -0
- package/dist/components/input-otp.d.ts +24 -0
- package/dist/components/input-otp.js +50 -0
- package/dist/components/input-payment.d.ts +131 -0
- package/dist/components/input-payment.js +1140 -0
- package/dist/components/input-phone.d.ts +70 -0
- package/dist/components/input-phone.js +657 -0
- package/dist/components/input-sensitive.d.ts +12 -0
- package/dist/components/input-sensitive.js +169 -0
- package/dist/components/input.d.ts +13 -0
- package/dist/components/input.js +26 -0
- package/dist/components/kbd.d.ts +6 -0
- package/dist/components/kbd.js +19 -0
- package/dist/components/kinetic-click.d.ts +48 -0
- package/dist/components/kinetic-click.js +1184 -0
- package/dist/components/label.d.ts +6 -0
- package/dist/components/label.js +18 -0
- package/dist/components/list-box.d.ts +20 -0
- package/dist/components/list-box.js +148 -0
- package/dist/components/loader.d.ts +13 -0
- package/dist/components/loader.js +430 -0
- package/dist/components/marker.d.ts +15 -0
- package/dist/components/marker.js +59 -0
- package/dist/components/menu.d.ts +42 -0
- package/dist/components/menu.js +186 -0
- package/dist/components/menubar.d.ts +40 -0
- package/dist/components/menubar.js +107 -0
- package/dist/components/message.d.ts +33 -0
- package/dist/components/message.js +112 -0
- package/dist/components/meter.d.ts +10 -0
- package/dist/components/meter.js +42 -0
- package/dist/components/morphic-toast.d.ts +61 -0
- package/dist/components/morphic-toast.js +916 -0
- package/dist/components/navigation-menu.d.ts +26 -0
- package/dist/components/navigation-menu.js +116 -0
- package/dist/components/number-field.d.ts +15 -0
- package/dist/components/number-field.js +86 -0
- package/dist/components/option-picker.d.ts +18 -0
- package/dist/components/option-picker.js +89 -0
- package/dist/components/orb.d.ts +38 -0
- package/dist/components/orb.js +1413 -0
- package/dist/components/pagination.d.ts +25 -0
- package/dist/components/pagination.js +147 -0
- package/dist/components/popover.d.ts +22 -0
- package/dist/components/popover.js +79 -0
- package/dist/components/preview-card.d.ts +16 -0
- package/dist/components/preview-card.js +60 -0
- package/dist/components/progress.d.ts +21 -0
- package/dist/components/progress.js +139 -0
- package/dist/components/radio.d.ts +16 -0
- package/dist/components/radio.js +68 -0
- package/dist/components/resizable.d.ts +58 -0
- package/dist/components/resizable.js +964 -0
- package/dist/components/ruler-picker.d.ts +27 -0
- package/dist/components/ruler-picker.js +253 -0
- package/dist/components/scroll-area.d.ts +13 -0
- package/dist/components/scroll-area.js +34 -0
- package/dist/components/scroll-bar.d.ts +13 -0
- package/dist/components/scroll-bar.js +47 -0
- package/dist/components/select.d.ts +29 -0
- package/dist/components/select.js +140 -0
- package/dist/components/separator.d.ts +6 -0
- package/dist/components/separator.js +15 -0
- package/dist/components/sidebar.d.ts +65 -0
- package/dist/components/sidebar.js +408 -0
- package/dist/components/skeleton.d.ts +5 -0
- package/dist/components/skeleton.js +12 -0
- package/dist/components/slider.d.ts +12 -0
- package/dist/components/slider.js +96 -0
- package/dist/components/sortable.d.ts +44 -0
- package/dist/components/sortable.js +327 -0
- package/dist/components/switch.d.ts +15 -0
- package/dist/components/switch.js +63 -0
- package/dist/components/table.d.ts +12 -0
- package/dist/components/table.js +65 -0
- package/dist/components/tabs.d.ts +12 -0
- package/dist/components/tabs.js +39 -0
- package/dist/components/text.d.ts +14 -0
- package/dist/components/text.js +69 -0
- package/dist/components/textarea.d.ts +9 -0
- package/dist/components/textarea.js +20 -0
- package/dist/components/theme-provider.d.ts +52 -0
- package/dist/components/theme-provider.js +148 -0
- package/dist/components/timeline.d.ts +34 -0
- package/dist/components/timeline.js +147 -0
- package/dist/components/toast.d.ts +17 -0
- package/dist/components/toast.js +161 -0
- package/dist/components/toggle-group.d.ts +14 -0
- package/dist/components/toggle-group.js +53 -0
- package/dist/components/toggle.d.ts +11 -0
- package/dist/components/toggle.js +36 -0
- package/dist/components/toolbar.d.ts +11 -0
- package/dist/components/toolbar.js +49 -0
- package/dist/components/tooltip.d.ts +17 -0
- package/dist/components/tooltip.js +56 -0
- package/dist/components/waveform.d.ts +61 -0
- package/dist/components/waveform.js +500 -0
- package/dist/components/wheel-picker.d.ts +44 -0
- package/dist/components/wheel-picker.js +771 -0
- package/dist/hooks/use-copy-to-clipboard.d.ts +9 -0
- package/dist/hooks/use-copy-to-clipboard.js +36 -0
- package/dist/hooks/use-media-query.d.ts +21 -0
- package/dist/hooks/use-media-query.js +58 -0
- package/dist/styles.css +202 -0
- package/dist/themes/afterglow.css +89 -0
- package/dist/themes/afterglow.scoped.css +90 -0
- package/dist/themes/blacklight.css +89 -0
- package/dist/themes/blacklight.scoped.css +90 -0
- package/dist/themes/cathode.css +89 -0
- package/dist/themes/cathode.scoped.css +90 -0
- package/dist/themes/cel.css +89 -0
- package/dist/themes/cel.scoped.css +90 -0
- package/dist/themes/cinder.css +89 -0
- package/dist/themes/cinder.scoped.css +90 -0
- package/dist/themes/clay.css +89 -0
- package/dist/themes/clay.scoped.css +90 -0
- package/dist/themes/cobalt.css +89 -0
- package/dist/themes/cobalt.scoped.css +90 -0
- package/dist/themes/crimson.css +89 -0
- package/dist/themes/crimson.scoped.css +90 -0
- package/dist/themes/ion.css +89 -0
- package/dist/themes/ion.scoped.css +90 -0
- package/dist/themes/iris.css +89 -0
- package/dist/themes/iris.scoped.css +90 -0
- package/dist/themes/lagoon.css +89 -0
- package/dist/themes/lagoon.scoped.css +90 -0
- package/dist/themes/mochi.css +89 -0
- package/dist/themes/mochi.scoped.css +90 -0
- package/dist/themes/riso.css +89 -0
- package/dist/themes/riso.scoped.css +90 -0
- package/dist/themes/roast.css +89 -0
- package/dist/themes/roast.scoped.css +90 -0
- package/dist/themes/sage.css +89 -0
- package/dist/themes/sage.scoped.css +90 -0
- package/dist/themes/sepia.css +89 -0
- package/dist/themes/sepia.scoped.css +90 -0
- package/dist/themes/sorbet.css +89 -0
- package/dist/themes/sorbet.scoped.css +90 -0
- package/dist/themes/taffy.css +89 -0
- package/dist/themes/taffy.scoped.css +90 -0
- package/dist/themes/toxin.css +89 -0
- package/dist/themes/toxin.scoped.css +90 -0
- package/package.json +140 -0
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "cn";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
//#region src/components/dot-matrix.tsx
|
|
6
|
+
const DIRECT_ANIMS = /* @__PURE__ */ new Set([
|
|
7
|
+
"helix",
|
|
8
|
+
"infinity",
|
|
9
|
+
"heart-pulse",
|
|
10
|
+
"orbit",
|
|
11
|
+
"matrix-rain",
|
|
12
|
+
"sine-wave",
|
|
13
|
+
"crt-glide",
|
|
14
|
+
"twin-orbit",
|
|
15
|
+
"rung-shift",
|
|
16
|
+
"lunar-breath",
|
|
17
|
+
"nova-wheel",
|
|
18
|
+
"prism-bloom",
|
|
19
|
+
"half-helix",
|
|
20
|
+
"honey-gate",
|
|
21
|
+
"spiral-lattice",
|
|
22
|
+
"altitude-wave",
|
|
23
|
+
"glyph-cluster",
|
|
24
|
+
"rail-scan",
|
|
25
|
+
"halo-drift"
|
|
26
|
+
]);
|
|
27
|
+
function usePrefersReducedMotion() {
|
|
28
|
+
const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (typeof window === "undefined") return;
|
|
31
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
32
|
+
setPrefersReducedMotion(mediaQuery.matches);
|
|
33
|
+
const listener = (event) => {
|
|
34
|
+
setPrefersReducedMotion(event.matches);
|
|
35
|
+
};
|
|
36
|
+
mediaQuery.addEventListener("change", listener);
|
|
37
|
+
return () => mediaQuery.removeEventListener("change", listener);
|
|
38
|
+
}, []);
|
|
39
|
+
return prefersReducedMotion;
|
|
40
|
+
}
|
|
41
|
+
function getSpiralOrder(rows, cols) {
|
|
42
|
+
const order = Array.from({ length: rows * cols }).fill(0);
|
|
43
|
+
let top = 0;
|
|
44
|
+
let bottom = rows - 1;
|
|
45
|
+
let left = 0;
|
|
46
|
+
let right = cols - 1;
|
|
47
|
+
let step = 0;
|
|
48
|
+
while (top <= bottom && left <= right) {
|
|
49
|
+
for (let col = left; col <= right; col++) order[top * cols + col] = step++;
|
|
50
|
+
top++;
|
|
51
|
+
for (let row = top; row <= bottom; row++) order[row * cols + right] = step++;
|
|
52
|
+
right--;
|
|
53
|
+
if (top <= bottom) {
|
|
54
|
+
for (let col = right; col >= left; col--) order[bottom * cols + col] = step++;
|
|
55
|
+
bottom--;
|
|
56
|
+
}
|
|
57
|
+
if (left <= right) {
|
|
58
|
+
for (let row = bottom; row >= top; row--) order[row * cols + left] = step++;
|
|
59
|
+
left++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return order;
|
|
63
|
+
}
|
|
64
|
+
function getSnakeOrder(rows, cols) {
|
|
65
|
+
const order = Array.from({ length: rows * cols }).fill(0);
|
|
66
|
+
let step = 0;
|
|
67
|
+
for (let row = 0; row < rows; row++) if (row % 2 === 0) for (let col = 0; col < cols; col++) order[row * cols + col] = step++;
|
|
68
|
+
else for (let col = cols - 1; col >= 0; col--) order[row * cols + col] = step++;
|
|
69
|
+
return order;
|
|
70
|
+
}
|
|
71
|
+
function ensureFrameSize(frame, rows, cols) {
|
|
72
|
+
const result = [];
|
|
73
|
+
for (let r = 0; r < rows; r++) {
|
|
74
|
+
result.push([]);
|
|
75
|
+
const row = frame[r] || [];
|
|
76
|
+
for (let c = 0; c < cols; c++) {
|
|
77
|
+
const val = row[c];
|
|
78
|
+
result[r][c] = typeof val === "boolean" ? val ? 1 : 0 : val ?? 0;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
function distanceSquared(ax, ay, bx, by) {
|
|
84
|
+
const dx = ax - bx;
|
|
85
|
+
const dy = ay - by;
|
|
86
|
+
return dx * dx + dy * dy;
|
|
87
|
+
}
|
|
88
|
+
function triangleWave(value) {
|
|
89
|
+
const wrapped = (value % 1 + 1) % 1;
|
|
90
|
+
return 1 - Math.abs(wrapped * 2 - 1);
|
|
91
|
+
}
|
|
92
|
+
function wavePeak(value) {
|
|
93
|
+
const wrapped = (value % 1 + 1) % 1;
|
|
94
|
+
return Math.max(0, 1 - Math.abs(wrapped * 2 - 1) / .55);
|
|
95
|
+
}
|
|
96
|
+
function DotMatrix({ rows = 5, cols = 5, mode = "animation", pattern, preset = "ripple", frames, isPlaying = true, loop = true, autoplay = true, fps = 12, speed = 1, levels, dotSize = 8, gap = 3, shape = "circle", colorPreset = "solid", color = "currentColor", colorOff = "var(--muted-foreground)", bloom = true, bloomIntensity = 1.8, halo = false, ariaLabel = "Dot matrix loader", className, onFrame, ...props }) {
|
|
97
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
98
|
+
const [currentFrameIndex, setCurrentFrameIndex] = useState(0);
|
|
99
|
+
const frameIdRef = useRef(void 0);
|
|
100
|
+
const lastTimeRef = useRef(0);
|
|
101
|
+
const accumulatorRef = useRef(0);
|
|
102
|
+
const svgRef = useRef(null);
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (!autoplay || !isPlaying || prefersReducedMotion) return;
|
|
105
|
+
if (!DIRECT_ANIMS.has(preset)) return;
|
|
106
|
+
const svg = svgRef.current;
|
|
107
|
+
if (!svg) return;
|
|
108
|
+
const dots = svg.querySelectorAll(".dmx-dot-cell");
|
|
109
|
+
if (dots.length === 0) return;
|
|
110
|
+
let animationFrameId;
|
|
111
|
+
const startTime = performance.now();
|
|
112
|
+
const tick = (now) => {
|
|
113
|
+
const elapsed = now - startTime;
|
|
114
|
+
const cycleDuration = 1600 / speed;
|
|
115
|
+
const u = elapsed % cycleDuration / cycleDuration;
|
|
116
|
+
for (let i = 0; i < dots.length; i++) {
|
|
117
|
+
const dot = dots[i];
|
|
118
|
+
const row = parseInt(dot.getAttribute("data-row") || "0", 10);
|
|
119
|
+
const col = parseInt(dot.getAttribute("data-col") || "0", 10);
|
|
120
|
+
let opacity = .12;
|
|
121
|
+
if (preset === "helix") {
|
|
122
|
+
const colCenter = (cols - 1) / 2;
|
|
123
|
+
const rowPhase = u * 2 * 2 * Math.PI + row * 1.24;
|
|
124
|
+
const left = Math.round(colCenter / 2 + Math.sin(rowPhase) * colCenter / 2);
|
|
125
|
+
const right = cols - 1 - left;
|
|
126
|
+
const bridgeOn = Math.cos(rowPhase * 2) > .82;
|
|
127
|
+
if (col === left || col === right) opacity = 1;
|
|
128
|
+
else if (bridgeOn && col > Math.min(left, right) && col < Math.max(left, right)) opacity = .58;
|
|
129
|
+
else if (Math.abs(col - left) === 1 || Math.abs(col - right) === 1) opacity = .35;
|
|
130
|
+
else opacity = .15;
|
|
131
|
+
} else if (preset === "infinity") {
|
|
132
|
+
const t = u * Math.PI * 2;
|
|
133
|
+
const hAx = Math.sin(t);
|
|
134
|
+
const hAy = .58 * Math.sin(2 * t);
|
|
135
|
+
const hBx = Math.sin(t + Math.PI);
|
|
136
|
+
const hBy = .58 * Math.sin(2 * (t + Math.PI));
|
|
137
|
+
const tAx = Math.sin(t - .25);
|
|
138
|
+
const tAy = .58 * Math.sin(2 * (t - .25));
|
|
139
|
+
const tBx = Math.sin(t + Math.PI - .25);
|
|
140
|
+
const tBy = .58 * Math.sin(2 * (t + Math.PI - .25));
|
|
141
|
+
const colCenter = (cols - 1) / 2;
|
|
142
|
+
const rowCenter = (rows - 1) / 2;
|
|
143
|
+
const dotX = (col - colCenter) / Math.max(1, colCenter);
|
|
144
|
+
const dotY = (rowCenter - row) / Math.max(1, rowCenter);
|
|
145
|
+
const headInfluence = (hx, hy) => Math.exp(-distanceSquared(dotX, dotY, hx, hy) / .19);
|
|
146
|
+
const leadVal = Math.max(headInfluence(hAx, hAy), headInfluence(hBx, hBy));
|
|
147
|
+
const trailVal = Math.max(headInfluence(tAx, tAy), headInfluence(tBx, tBy));
|
|
148
|
+
const centerPulse = Math.exp(-(dotX * dotX + dotY * dotY) / .05) * (.45 + .55 * leadVal);
|
|
149
|
+
opacity = .08 + .78 * leadVal + .42 * trailVal + .16 * centerPulse;
|
|
150
|
+
opacity = Math.min(1, opacity);
|
|
151
|
+
} else if (preset === "heart-pulse") {
|
|
152
|
+
const colCenter = (cols - 1) / 2;
|
|
153
|
+
const rowCenter = (rows - 1) / 2;
|
|
154
|
+
const xVal = col - colCenter;
|
|
155
|
+
const yVal = row - rowCenter;
|
|
156
|
+
const radius = Math.hypot(xVal, yVal);
|
|
157
|
+
const beat = Math.sin(u * Math.PI * 2);
|
|
158
|
+
const spike = Math.sin(u * Math.PI * 4);
|
|
159
|
+
const pulse = Math.max(0, beat) + Math.max(0, spike) * .55;
|
|
160
|
+
if (radius < 1.2) opacity = .25 + pulse * .75;
|
|
161
|
+
else if (radius < 2.2) opacity = .15 + pulse * .55;
|
|
162
|
+
else opacity = .12 + pulse * .18;
|
|
163
|
+
} else if (preset === "orbit") {
|
|
164
|
+
const totalOuter = Math.max(1, cols * 2 + (rows - 2) * 2);
|
|
165
|
+
if (row === 0 || row === rows - 1 || col === 0 || col === cols - 1) {
|
|
166
|
+
let ringIndex = 0;
|
|
167
|
+
if (row === 0) ringIndex = col;
|
|
168
|
+
else if (col === cols - 1) ringIndex = cols - 1 + row;
|
|
169
|
+
else if (row === rows - 1) ringIndex = cols - 1 + rows - 1 + (cols - 1 - col);
|
|
170
|
+
else if (col === 0) ringIndex = cols - 1 + rows - 1 + cols - 1 + (rows - 1 - row);
|
|
171
|
+
const distToHead = (u * totalOuter - ringIndex + totalOuter) % totalOuter;
|
|
172
|
+
opacity = .15 + Math.max(0, 1 - distToHead / (totalOuter * .35)) * .85;
|
|
173
|
+
} else opacity = .12;
|
|
174
|
+
} else if (preset === "matrix-rain") {
|
|
175
|
+
const offset = col * 7.3 % 1;
|
|
176
|
+
const dist = row - ((u * (.6 + col * 11.3 % .6) + offset) % 1 * (rows + 4) - 2);
|
|
177
|
+
if (dist <= 0 && dist > -4) opacity = .15 + (4 + dist) / 4 * .85;
|
|
178
|
+
else opacity = .15;
|
|
179
|
+
} else if (preset === "sine-wave") {
|
|
180
|
+
const phase = u * 2 * Math.PI;
|
|
181
|
+
const colPhase = col / cols * 2 * Math.PI;
|
|
182
|
+
const waveHeight = (Math.sin(phase + colPhase) + 1) / 2 * rows;
|
|
183
|
+
const distToTop = rows - 1 - row;
|
|
184
|
+
if (distToTop < waveHeight) {
|
|
185
|
+
const diff = waveHeight - distToTop;
|
|
186
|
+
opacity = .15 + Math.min(1, diff) * .85;
|
|
187
|
+
} else opacity = .15;
|
|
188
|
+
} else if (preset === "crt-glide") {
|
|
189
|
+
const dist = row - (u * (rows + 3) - 1.5);
|
|
190
|
+
if (dist >= 0 && dist < 3) opacity = .15 + (1 - dist / 3) * .85;
|
|
191
|
+
else opacity = .15;
|
|
192
|
+
} else if (preset === "twin-orbit") {
|
|
193
|
+
const totalOuter = Math.max(1, cols * 2 + (rows - 2) * 2);
|
|
194
|
+
if (row === 0 || row === rows - 1 || col === 0 || col === cols - 1) {
|
|
195
|
+
let ringIndex = 0;
|
|
196
|
+
if (row === 0) ringIndex = col;
|
|
197
|
+
else if (col === cols - 1) ringIndex = cols - 1 + row;
|
|
198
|
+
else if (row === rows - 1) ringIndex = cols - 1 + rows - 1 + (cols - 1 - col);
|
|
199
|
+
else if (col === 0) ringIndex = cols - 1 + rows - 1 + cols - 1 + (rows - 1 - row);
|
|
200
|
+
const distToHead = (u * totalOuter - ringIndex + totalOuter) % totalOuter;
|
|
201
|
+
opacity = .15 + Math.max(0, 1 - distToHead / (totalOuter * .35)) * .85;
|
|
202
|
+
} else if (rows > 2 && cols > 2) {
|
|
203
|
+
const innerRow = row - 1;
|
|
204
|
+
const innerCol = col - 1;
|
|
205
|
+
const innerR = rows - 2;
|
|
206
|
+
const innerC = cols - 2;
|
|
207
|
+
const totalInner = Math.max(1, innerC * 2 + (innerR - 2) * 2);
|
|
208
|
+
if (innerRow === 0 || innerRow === innerR - 1 || innerCol === 0 || innerCol === innerC - 1) {
|
|
209
|
+
let innerIndex = 0;
|
|
210
|
+
if (innerRow === 0) innerIndex = innerCol;
|
|
211
|
+
else if (innerCol === innerC - 1) innerIndex = innerC - 1 + innerRow;
|
|
212
|
+
else if (innerRow === innerR - 1) innerIndex = innerC - 1 + innerR - 1 + (innerC - 1 - innerCol);
|
|
213
|
+
else if (innerCol === 0) innerIndex = innerC - 1 + innerR - 1 + innerC - 1 + (innerR - 1 - innerRow);
|
|
214
|
+
const headPos = u * totalInner;
|
|
215
|
+
const distToHead = (innerIndex - headPos + totalInner) % totalInner;
|
|
216
|
+
opacity = .15 + Math.max(0, 1 - distToHead / (totalInner * .45)) * .85;
|
|
217
|
+
} else opacity = .15;
|
|
218
|
+
} else opacity = .15;
|
|
219
|
+
} else if (preset === "rung-shift") {
|
|
220
|
+
const colCenter = (cols - 1) / 2;
|
|
221
|
+
const yVal = row - (rows - 1) / 2;
|
|
222
|
+
const phaseStep = Math.floor(u * 10);
|
|
223
|
+
const activeRow = (phaseStep + rows) % rows;
|
|
224
|
+
const rowDistance = Math.abs(row - activeRow);
|
|
225
|
+
const swing = Math.sin(phaseStep / 10 * Math.PI * 2 + yVal * .9);
|
|
226
|
+
const leftAnchor = Math.round(colCenter / 2 + swing * colCenter / 2);
|
|
227
|
+
const rightAnchor = cols - 1 - leftAnchor;
|
|
228
|
+
if (row === activeRow && col >= leftAnchor && col <= rightAnchor) opacity = .95;
|
|
229
|
+
else if ((col === leftAnchor || col === rightAnchor) && rowDistance <= 1) opacity = .56;
|
|
230
|
+
else if ((col === leftAnchor || col === rightAnchor) && rowDistance === 2) opacity = .28;
|
|
231
|
+
else opacity = .15;
|
|
232
|
+
} else if (preset === "lunar-breath") {
|
|
233
|
+
const colCenter = (cols - 1) / 2;
|
|
234
|
+
const rowCenter = (rows - 1) / 2;
|
|
235
|
+
const x = col - colCenter;
|
|
236
|
+
const y = row - rowCenter;
|
|
237
|
+
const ring = Math.hypot(x, y);
|
|
238
|
+
const t = u * Math.PI * 2;
|
|
239
|
+
const angle = Math.atan2(y, x);
|
|
240
|
+
const moonCenterX = Math.cos(t) * (colCenter * .35);
|
|
241
|
+
const moonCenterY = Math.sin(t) * (rowCenter * .35);
|
|
242
|
+
const body = Math.hypot(x - moonCenterX, y - moonCenterY);
|
|
243
|
+
const cutCenterX = moonCenterX + Math.cos(t) * (colCenter * .41);
|
|
244
|
+
const cutCenterY = moonCenterY + Math.sin(t) * (rowCenter * .41);
|
|
245
|
+
const cut = Math.hypot(x - cutCenterX, y - cutCenterY);
|
|
246
|
+
const rim = Math.max(0, 1 - Math.abs(body - colCenter * .77) / .35);
|
|
247
|
+
const haloStrength = Math.max(0, 1 - Math.acos(Math.cos(angle - t)) / .9);
|
|
248
|
+
if (body < colCenter * .77 && cut > colCenter * .52) opacity = .95;
|
|
249
|
+
else if (rim > .5) opacity = .3 + rim * .22;
|
|
250
|
+
else if (haloStrength > .68 && ring > colCenter * .6) opacity = .3;
|
|
251
|
+
else opacity = .15;
|
|
252
|
+
} else if (preset === "nova-wheel") {
|
|
253
|
+
const colCenter = (cols - 1) / 2;
|
|
254
|
+
const rowCenter = (rows - 1) / 2;
|
|
255
|
+
const x = col - colCenter;
|
|
256
|
+
const y = row - rowCenter;
|
|
257
|
+
const radius = Math.hypot(x, y);
|
|
258
|
+
const angle = Math.atan2(y, x);
|
|
259
|
+
const theta = u * Math.PI * 2;
|
|
260
|
+
const pinwheel = Math.cos(angle * 4 - theta * 2.2);
|
|
261
|
+
const radialGate = Math.sin(radius * 2.1 - theta * 1.25);
|
|
262
|
+
if (radius < .6) opacity = .66;
|
|
263
|
+
else if (pinwheel > .48 && radialGate > -.25) opacity = .94;
|
|
264
|
+
else if (pinwheel > .1) opacity = .34;
|
|
265
|
+
else opacity = .15;
|
|
266
|
+
} else if (preset === "prism-bloom") {
|
|
267
|
+
const masks = [
|
|
268
|
+
"x...x.x.x...o...x.x.x...x",
|
|
269
|
+
"..x...oxo.xooox.oxo...x..",
|
|
270
|
+
".x.x.x.o.x..o..x.o.x.x.x.",
|
|
271
|
+
"x.x.x.o.o.x.o.x.o.o.x.x.x"
|
|
272
|
+
];
|
|
273
|
+
const cell = (masks[[
|
|
274
|
+
0,
|
|
275
|
+
1,
|
|
276
|
+
2,
|
|
277
|
+
3,
|
|
278
|
+
2,
|
|
279
|
+
1
|
|
280
|
+
][Math.floor(u * 6) % 6] ?? 0] ?? masks[0] ?? "")[row % 5 * 5 + col % 5] || ".";
|
|
281
|
+
if (cell === "x") opacity = 1;
|
|
282
|
+
else if (cell === "o") opacity = .52;
|
|
283
|
+
else opacity = .15;
|
|
284
|
+
} else if (preset === "half-helix") {
|
|
285
|
+
const colCenter = (cols - 1) / 2;
|
|
286
|
+
const STEP_COUNT = 20;
|
|
287
|
+
const HELIX_LOOP_RADIANS = Math.PI * 2 / 19;
|
|
288
|
+
const rowPhase = u * STEP_COUNT * HELIX_LOOP_RADIANS + row * 1.24;
|
|
289
|
+
const strandCol = Math.round(colCenter + colCenter * Math.sin(rowPhase));
|
|
290
|
+
if (col === strandCol) opacity = 1;
|
|
291
|
+
else if (Math.abs(col - strandCol) === 1) opacity = .35;
|
|
292
|
+
else opacity = .15;
|
|
293
|
+
} else if (preset === "honey-gate") {
|
|
294
|
+
const colCenter = (cols - 1) / 2;
|
|
295
|
+
const rowCenter = (rows - 1) / 2;
|
|
296
|
+
const x = col - colCenter;
|
|
297
|
+
const y = row - rowCenter;
|
|
298
|
+
const sweep = triangleWave(u) * 4 - 2;
|
|
299
|
+
const diagA = x * .86 + y * .5;
|
|
300
|
+
const diagB = x * -.86 + y * .5;
|
|
301
|
+
const gateA = Math.max(0, 1 - Math.abs(diagA - sweep) / .55);
|
|
302
|
+
const gateB = Math.max(0, 1 - Math.abs(diagB + sweep) / .55);
|
|
303
|
+
const centerDistance = Math.hypot(x, y);
|
|
304
|
+
const centerFlash = Math.max(0, 1 - Math.abs(sweep) / .68) * Math.max(0, 1 - centerDistance / 1.9);
|
|
305
|
+
opacity = .15 + gateA * .7 + gateB * .7 + centerFlash * .42;
|
|
306
|
+
opacity = Math.min(1, opacity);
|
|
307
|
+
} else if (preset === "spiral-lattice") {
|
|
308
|
+
const colCenter = (cols - 1) / 2;
|
|
309
|
+
const rowCenter = (rows - 1) / 2;
|
|
310
|
+
const x = col - colCenter;
|
|
311
|
+
const y = row - rowCenter;
|
|
312
|
+
const radius = Math.hypot(x, y);
|
|
313
|
+
const angle = Math.atan2(y, x);
|
|
314
|
+
const spiral = u + radius * .18 + angle / (Math.PI * 2);
|
|
315
|
+
const counterSpiral = u * .72 - radius * .16 - angle / (Math.PI * 2);
|
|
316
|
+
const a = wavePeak(spiral);
|
|
317
|
+
const b = wavePeak(counterSpiral) * .55;
|
|
318
|
+
const core = radius < .8 ? .54 + Math.sin(u * Math.PI * 4) * .26 : 0;
|
|
319
|
+
opacity = .15 + a * .7 + b * .42 + core;
|
|
320
|
+
opacity = Math.min(1, opacity);
|
|
321
|
+
} else if (preset === "altitude-wave") {
|
|
322
|
+
const colCenter = (cols - 1) / 2;
|
|
323
|
+
const rowPhase = (rows - 1 - row) * .13;
|
|
324
|
+
const pulse = .5 - .5 * Math.cos((u + rowPhase) * Math.PI * 2);
|
|
325
|
+
const crest = pulse * pulse;
|
|
326
|
+
const altitudeWeight = .58 + (rows - 1 - row) * .16;
|
|
327
|
+
const centerWeight = col === Math.floor(colCenter) ? .16 : 0;
|
|
328
|
+
opacity = .15 + pulse * .26 + crest * (altitudeWeight + centerWeight) * (.94 - .34);
|
|
329
|
+
opacity = Math.min(.95, opacity);
|
|
330
|
+
} else if (preset === "glyph-cluster") {
|
|
331
|
+
const patterns = [
|
|
332
|
+
[
|
|
333
|
+
"1,1",
|
|
334
|
+
"2,1",
|
|
335
|
+
"3,1",
|
|
336
|
+
"1,3",
|
|
337
|
+
"2,3",
|
|
338
|
+
"3,3"
|
|
339
|
+
],
|
|
340
|
+
[
|
|
341
|
+
"1,1",
|
|
342
|
+
"2,1",
|
|
343
|
+
"3,1",
|
|
344
|
+
"2,2",
|
|
345
|
+
"1,3",
|
|
346
|
+
"2,3",
|
|
347
|
+
"3,3"
|
|
348
|
+
],
|
|
349
|
+
[
|
|
350
|
+
"1,1",
|
|
351
|
+
"1,2",
|
|
352
|
+
"1,3",
|
|
353
|
+
"2,1",
|
|
354
|
+
"2,3",
|
|
355
|
+
"3,1",
|
|
356
|
+
"3,2",
|
|
357
|
+
"3,3"
|
|
358
|
+
],
|
|
359
|
+
[
|
|
360
|
+
"1,1",
|
|
361
|
+
"3,1",
|
|
362
|
+
"2,2",
|
|
363
|
+
"1,3",
|
|
364
|
+
"3,3"
|
|
365
|
+
],
|
|
366
|
+
[
|
|
367
|
+
"2,1",
|
|
368
|
+
"1,2",
|
|
369
|
+
"3,2",
|
|
370
|
+
"2,3"
|
|
371
|
+
],
|
|
372
|
+
[
|
|
373
|
+
"1,1",
|
|
374
|
+
"2,1",
|
|
375
|
+
"2,2",
|
|
376
|
+
"2,3",
|
|
377
|
+
"3,3"
|
|
378
|
+
]
|
|
379
|
+
];
|
|
380
|
+
const count = patterns.length;
|
|
381
|
+
const phaseIndex = Math.floor(u * count) % count;
|
|
382
|
+
const previousIndex = (phaseIndex + count - 1) % count;
|
|
383
|
+
const activeSet = new Set(patterns[phaseIndex]);
|
|
384
|
+
const prevSet = new Set(patterns[previousIndex]);
|
|
385
|
+
const key = `${row % 5},${col % 5}`;
|
|
386
|
+
const colCenter = (cols - 1) / 2;
|
|
387
|
+
const rowCenter = (rows - 1) / 2;
|
|
388
|
+
const ring = Math.hypot(col - colCenter, row - rowCenter);
|
|
389
|
+
if (activeSet.has(key)) opacity = .95;
|
|
390
|
+
else if (prevSet.has(key)) opacity = .34;
|
|
391
|
+
else if (ring < 1.1) opacity = .2;
|
|
392
|
+
else opacity = .15;
|
|
393
|
+
} else if (preset === "rail-scan") {
|
|
394
|
+
const STEP_COUNT = 25;
|
|
395
|
+
const t = Math.floor(u * STEP_COUNT) % STEP_COUNT;
|
|
396
|
+
const activeRow = t % rows;
|
|
397
|
+
const activeBrailleCol = Math.floor(t / rows * 2) % 2;
|
|
398
|
+
const railColLeft = Math.max(0, Math.floor(cols * .25));
|
|
399
|
+
const railColRight = Math.min(cols - 1, Math.ceil(cols * .75));
|
|
400
|
+
const railCol = activeBrailleCol === 0 ? railColLeft : railColRight;
|
|
401
|
+
const nearCol = Math.floor((cols - 1) / 2);
|
|
402
|
+
const rowDistance = Math.abs(row - activeRow);
|
|
403
|
+
if (col === railCol && rowDistance === 0) opacity = .95;
|
|
404
|
+
else if (col === railCol && rowDistance === 1) opacity = .34;
|
|
405
|
+
else if (col === nearCol && rowDistance === 0) opacity = .52;
|
|
406
|
+
else if ((col === railColLeft || col === railColRight) && rowDistance === 2) opacity = .24;
|
|
407
|
+
else opacity = .15;
|
|
408
|
+
} else if (preset === "halo-drift") {
|
|
409
|
+
const colCenter = (cols - 1) / 2;
|
|
410
|
+
const t = u * 20;
|
|
411
|
+
const HELIX_LOOP_RADIANS = Math.PI * 2 / 19;
|
|
412
|
+
const diagonalAxis = row + col;
|
|
413
|
+
const phaseOffset = t * HELIX_LOOP_RADIANS + diagonalAxis * .82;
|
|
414
|
+
const strandPerpendicular = Math.round(colCenter * .8 * Math.sin(phaseOffset));
|
|
415
|
+
const cellPerpendicular = col - row;
|
|
416
|
+
const distanceFromStrand = Math.abs(cellPerpendicular - strandPerpendicular);
|
|
417
|
+
if (distanceFromStrand === 0) opacity = 1;
|
|
418
|
+
else if (distanceFromStrand === 1) opacity = .35;
|
|
419
|
+
else opacity = .15;
|
|
420
|
+
}
|
|
421
|
+
dot.style.opacity = opacity.toFixed(4);
|
|
422
|
+
dot.style.filter = "none";
|
|
423
|
+
}
|
|
424
|
+
animationFrameId = requestAnimationFrame(tick);
|
|
425
|
+
};
|
|
426
|
+
animationFrameId = requestAnimationFrame(tick);
|
|
427
|
+
return () => cancelAnimationFrame(animationFrameId);
|
|
428
|
+
}, [
|
|
429
|
+
autoplay,
|
|
430
|
+
isPlaying,
|
|
431
|
+
speed,
|
|
432
|
+
preset,
|
|
433
|
+
prefersReducedMotion,
|
|
434
|
+
rows,
|
|
435
|
+
cols
|
|
436
|
+
]);
|
|
437
|
+
const spiralOrder = useMemo(() => getSpiralOrder(rows, cols), [rows, cols]);
|
|
438
|
+
const snakeOrder = useMemo(() => getSnakeOrder(rows, cols), [rows, cols]);
|
|
439
|
+
const hasCustomFrames = mode === "animation" && frames && frames.length > 0;
|
|
440
|
+
const isCurrentlyAnimating = autoplay && isPlaying && !prefersReducedMotion && hasCustomFrames;
|
|
441
|
+
useEffect(() => {
|
|
442
|
+
if (!isCurrentlyAnimating || !frames || frames.length === 0) return;
|
|
443
|
+
const interval = 1e3 / fps;
|
|
444
|
+
const animate = (currentTime) => {
|
|
445
|
+
if (lastTimeRef.current === 0) lastTimeRef.current = currentTime;
|
|
446
|
+
const delta = currentTime - lastTimeRef.current;
|
|
447
|
+
lastTimeRef.current = currentTime;
|
|
448
|
+
accumulatorRef.current += delta;
|
|
449
|
+
if (accumulatorRef.current >= interval) {
|
|
450
|
+
accumulatorRef.current -= interval;
|
|
451
|
+
setCurrentFrameIndex((prev) => {
|
|
452
|
+
const next = prev + 1;
|
|
453
|
+
if (next >= frames.length) {
|
|
454
|
+
if (loop) {
|
|
455
|
+
onFrame?.(0);
|
|
456
|
+
return 0;
|
|
457
|
+
}
|
|
458
|
+
return prev;
|
|
459
|
+
}
|
|
460
|
+
onFrame?.(next);
|
|
461
|
+
return next;
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
frameIdRef.current = requestAnimationFrame(animate);
|
|
465
|
+
};
|
|
466
|
+
frameIdRef.current = requestAnimationFrame(animate);
|
|
467
|
+
return () => {
|
|
468
|
+
if (frameIdRef.current) cancelAnimationFrame(frameIdRef.current);
|
|
469
|
+
};
|
|
470
|
+
}, [
|
|
471
|
+
isCurrentlyAnimating,
|
|
472
|
+
frames,
|
|
473
|
+
fps,
|
|
474
|
+
loop,
|
|
475
|
+
onFrame
|
|
476
|
+
]);
|
|
477
|
+
useEffect(() => {
|
|
478
|
+
setCurrentFrameIndex(0);
|
|
479
|
+
lastTimeRef.current = 0;
|
|
480
|
+
accumulatorRef.current = 0;
|
|
481
|
+
}, []);
|
|
482
|
+
const gridWidth = cols * (dotSize + gap) - gap;
|
|
483
|
+
const gridHeight = rows * (dotSize + gap) - gap;
|
|
484
|
+
const viewBoxWidth = gridWidth + 8;
|
|
485
|
+
const viewBoxHeight = gridHeight + 8;
|
|
486
|
+
const currentFrame = useMemo(() => {
|
|
487
|
+
if (mode === "vu" && levels) {
|
|
488
|
+
const frame = Array.from({ length: rows }, () => Array.from({ length: cols }).fill(0));
|
|
489
|
+
for (let col = 0; col < Math.min(cols, levels.length); col++) {
|
|
490
|
+
const level = Math.max(0, Math.min(1, levels[col] ?? 0));
|
|
491
|
+
const height = Math.round(level * rows);
|
|
492
|
+
for (let row = 0; row < rows; row++) if (rows - 1 - row < height) frame[row][col] = 1;
|
|
493
|
+
}
|
|
494
|
+
return frame;
|
|
495
|
+
}
|
|
496
|
+
if (mode === "static" && pattern) return ensureFrameSize(pattern, rows, cols);
|
|
497
|
+
if (hasCustomFrames && frames) return ensureFrameSize(frames[currentFrameIndex] || frames[0] || [], rows, cols);
|
|
498
|
+
return Array.from({ length: rows }, () => Array.from({ length: cols }).fill(1));
|
|
499
|
+
}, [
|
|
500
|
+
mode,
|
|
501
|
+
pattern,
|
|
502
|
+
frames,
|
|
503
|
+
currentFrameIndex,
|
|
504
|
+
levels,
|
|
505
|
+
rows,
|
|
506
|
+
cols,
|
|
507
|
+
hasCustomFrames
|
|
508
|
+
]);
|
|
509
|
+
const gradientColors = colorPreset !== "solid" ? {
|
|
510
|
+
sunset: ["#ff5f6d", "#ffc371"],
|
|
511
|
+
ocean: ["#00c6ff", "#0072ff"],
|
|
512
|
+
neon: ["#b4ff39", "#39ffb6"],
|
|
513
|
+
aurora: [
|
|
514
|
+
"#ff3cac",
|
|
515
|
+
"#784ba0",
|
|
516
|
+
"#2b86c5"
|
|
517
|
+
],
|
|
518
|
+
fire: ["#ff512f", "#dd2476"],
|
|
519
|
+
prism: [
|
|
520
|
+
"#12c2e9",
|
|
521
|
+
"#c471ed",
|
|
522
|
+
"#f64f59"
|
|
523
|
+
]
|
|
524
|
+
}[colorPreset] : null;
|
|
525
|
+
return /* @__PURE__ */ jsx("div", {
|
|
526
|
+
className: cn("relative inline-block select-none", className),
|
|
527
|
+
"data-slot": "dot-matrix",
|
|
528
|
+
style: {
|
|
529
|
+
"--dmx-color": color,
|
|
530
|
+
"--dmx-color-off": colorOff
|
|
531
|
+
},
|
|
532
|
+
...props,
|
|
533
|
+
children: /* @__PURE__ */ jsxs("svg", {
|
|
534
|
+
ref: svgRef,
|
|
535
|
+
width: viewBoxWidth,
|
|
536
|
+
height: viewBoxHeight,
|
|
537
|
+
viewBox: `-4 -4 ${viewBoxWidth} ${viewBoxHeight}`,
|
|
538
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
539
|
+
className: "block overflow-visible",
|
|
540
|
+
"aria-label": ariaLabel,
|
|
541
|
+
role: "img",
|
|
542
|
+
children: [
|
|
543
|
+
/* @__PURE__ */ jsxs("defs", { children: [
|
|
544
|
+
gradientColors && /* @__PURE__ */ jsx("linearGradient", {
|
|
545
|
+
id: "dmx-gradient-preset",
|
|
546
|
+
x1: "0%",
|
|
547
|
+
y1: "0%",
|
|
548
|
+
x2: "100%",
|
|
549
|
+
y2: "100%",
|
|
550
|
+
gradientUnits: "userSpaceOnUse",
|
|
551
|
+
children: gradientColors.map((col, idx) => /* @__PURE__ */ jsx("stop", {
|
|
552
|
+
offset: `${idx / (gradientColors.length - 1) * 100}%`,
|
|
553
|
+
stopColor: col
|
|
554
|
+
}, col))
|
|
555
|
+
}),
|
|
556
|
+
(bloom || halo) && /* @__PURE__ */ jsxs("filter", {
|
|
557
|
+
id: "dmx-bloom-filter",
|
|
558
|
+
x: "-50%",
|
|
559
|
+
y: "-50%",
|
|
560
|
+
width: "200%",
|
|
561
|
+
height: "200%",
|
|
562
|
+
children: [/* @__PURE__ */ jsx("feGaussianBlur", {
|
|
563
|
+
in: "SourceGraphic",
|
|
564
|
+
stdDeviation: bloomIntensity,
|
|
565
|
+
result: "blur"
|
|
566
|
+
}), /* @__PURE__ */ jsxs("feMerge", { children: [/* @__PURE__ */ jsx("feMergeNode", { in: "blur" }), /* @__PURE__ */ jsx("feMergeNode", { in: "SourceGraphic" })] })]
|
|
567
|
+
}),
|
|
568
|
+
/* @__PURE__ */ jsxs("filter", {
|
|
569
|
+
id: "dmx-hover-filter",
|
|
570
|
+
x: "-50%",
|
|
571
|
+
y: "-50%",
|
|
572
|
+
width: "200%",
|
|
573
|
+
height: "200%",
|
|
574
|
+
children: [/* @__PURE__ */ jsx("feGaussianBlur", {
|
|
575
|
+
in: "SourceGraphic",
|
|
576
|
+
stdDeviation: bloomIntensity * 1.5,
|
|
577
|
+
result: "blur"
|
|
578
|
+
}), /* @__PURE__ */ jsxs("feMerge", { children: [/* @__PURE__ */ jsx("feMergeNode", { in: "blur" }), /* @__PURE__ */ jsx("feMergeNode", { in: "SourceGraphic" })] })]
|
|
579
|
+
})
|
|
580
|
+
] }),
|
|
581
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
582
|
+
.dmx-dot {
|
|
583
|
+
transform-origin: center;
|
|
584
|
+
transform-box: fill-box;
|
|
585
|
+
transition: transform 300ms cubic-bezier(0.2, 0.8, 0.2, 1), opacity 300ms ease;
|
|
586
|
+
}
|
|
587
|
+
.dmx-dot-on {
|
|
588
|
+
fill: ${gradientColors ? "url(#dmx-gradient-preset)" : "var(--dmx-color, currentColor)"};
|
|
589
|
+
}
|
|
590
|
+
.dmx-dot-off {
|
|
591
|
+
fill: var(--dmx-color-off, currentColor);
|
|
592
|
+
opacity: 0.12;
|
|
593
|
+
}
|
|
594
|
+
.dmx-dot-animate-pulse {
|
|
595
|
+
animation: dmx-pulse-anim ${1.5 / speed}s infinite ease-in-out;
|
|
596
|
+
}
|
|
597
|
+
.dmx-dot-animate-trail {
|
|
598
|
+
animation: dmx-trail-anim ${1.5 / speed}s infinite linear;
|
|
599
|
+
}
|
|
600
|
+
.dmx-dot:hover {
|
|
601
|
+
transform: scale(1.3);
|
|
602
|
+
opacity: 1 !important;
|
|
603
|
+
${bloom ? "filter: url(#dmx-hover-filter);" : ""}
|
|
604
|
+
}
|
|
605
|
+
@keyframes dmx-pulse-anim {
|
|
606
|
+
0%, 100% { opacity: 0.12; }
|
|
607
|
+
50% { opacity: 1; }
|
|
608
|
+
}
|
|
609
|
+
@keyframes dmx-trail-anim {
|
|
610
|
+
0% { opacity: 1; }
|
|
611
|
+
35%, 100% { opacity: 0.12; }
|
|
612
|
+
}
|
|
613
|
+
` }),
|
|
614
|
+
currentFrame.map((rowArr, rowIdx) => rowArr.map((cellVal, colIdx) => {
|
|
615
|
+
const cx = colIdx * (dotSize + gap) + dotSize / 2;
|
|
616
|
+
const cy = rowIdx * (dotSize + gap) + dotSize / 2;
|
|
617
|
+
const x = colIdx * (dotSize + gap);
|
|
618
|
+
const y = rowIdx * (dotSize + gap);
|
|
619
|
+
const isCellOn = cellVal > .01;
|
|
620
|
+
const cellOpacity = isCellOn ? cellVal : .12;
|
|
621
|
+
const isDirectAnim = DIRECT_ANIMS.has(preset);
|
|
622
|
+
const useCSSAnimation = mode === "animation" && isPlaying && !prefersReducedMotion && !hasCustomFrames && preset !== "none" && !isDirectAnim;
|
|
623
|
+
const animationClass = useCSSAnimation ? [
|
|
624
|
+
"spiral",
|
|
625
|
+
"snake",
|
|
626
|
+
"diagonal",
|
|
627
|
+
"diagonal-reverse",
|
|
628
|
+
"rotor",
|
|
629
|
+
"columns-flux"
|
|
630
|
+
].includes(preset) ? "dmx-dot-animate-trail" : "dmx-dot-animate-pulse" : "";
|
|
631
|
+
const elementStyle = {
|
|
632
|
+
animationDelay: useCSSAnimation ? (() => {
|
|
633
|
+
const scaledCycle = 1.5 / speed;
|
|
634
|
+
if (preset === "ripple") {
|
|
635
|
+
const rowCenter = (rows - 1) / 2;
|
|
636
|
+
const colCenter = (cols - 1) / 2;
|
|
637
|
+
return `${(Math.hypot(rowIdx - rowCenter, colIdx - colCenter) / (Math.hypot(rowCenter, colCenter) || 1) * scaledCycle).toFixed(4)}s`;
|
|
638
|
+
}
|
|
639
|
+
if (preset === "spiral") return `${((spiralOrder[rowIdx * cols + colIdx] || 0) / (rows * cols - 1 || 1) * scaledCycle).toFixed(4)}s`;
|
|
640
|
+
if (preset === "snake") return `${((snakeOrder[rowIdx * cols + colIdx] || 0) / (rows * cols - 1 || 1) * scaledCycle).toFixed(4)}s`;
|
|
641
|
+
if (preset === "wave") return `${(colIdx / (cols - 1 || 1) * scaledCycle).toFixed(4)}s`;
|
|
642
|
+
if (preset === "wave-vertical") return `${(rowIdx / (rows - 1 || 1) * scaledCycle).toFixed(4)}s`;
|
|
643
|
+
if (preset === "diagonal") return `${((rowIdx + colIdx) / (rows + cols - 2 || 1) * scaledCycle).toFixed(4)}s`;
|
|
644
|
+
if (preset === "diagonal-reverse") return `${((rowIdx + (cols - 1 - colIdx)) / (rows + cols - 2 || 1) * scaledCycle).toFixed(4)}s`;
|
|
645
|
+
if (preset === "rotor") {
|
|
646
|
+
const rowCenter = (rows - 1) / 2;
|
|
647
|
+
const colCenter = (cols - 1) / 2;
|
|
648
|
+
return `${((Math.atan2(rowIdx - rowCenter, colIdx - colCenter) + Math.PI) / (Math.PI * 2) * scaledCycle).toFixed(4)}s`;
|
|
649
|
+
}
|
|
650
|
+
if (preset === "columns-flux") {
|
|
651
|
+
const yNorm = colIdx % 2 === 0 ? rowIdx / (rows - 1 || 1) : (rows - 1 - rowIdx) / (rows - 1 || 1);
|
|
652
|
+
const colStagger = colIdx / (cols - 1 || 1) * .3;
|
|
653
|
+
return `${((yNorm * .7 + colStagger) * scaledCycle).toFixed(4)}s`;
|
|
654
|
+
}
|
|
655
|
+
return "0s";
|
|
656
|
+
})() : void 0,
|
|
657
|
+
...(bloom || halo) && isCellOn && !useCSSAnimation && !isDirectAnim ? { filter: "url(#dmx-bloom-filter)" } : {},
|
|
658
|
+
...!useCSSAnimation ? { opacity: cellOpacity } : {}
|
|
659
|
+
};
|
|
660
|
+
const baseProps = {
|
|
661
|
+
className: cn("dmx-dot dmx-dot-cell", isCellOn ? "dmx-dot-on" : "dmx-dot-off", isCellOn && animationClass),
|
|
662
|
+
style: elementStyle,
|
|
663
|
+
"data-row": rowIdx,
|
|
664
|
+
"data-col": colIdx
|
|
665
|
+
};
|
|
666
|
+
const key = `${rowIdx}-${colIdx}`;
|
|
667
|
+
if (shape === "square") return /* @__PURE__ */ jsx("rect", {
|
|
668
|
+
...baseProps,
|
|
669
|
+
x,
|
|
670
|
+
y,
|
|
671
|
+
width: dotSize,
|
|
672
|
+
height: dotSize,
|
|
673
|
+
rx: Math.max(1, dotSize * .15)
|
|
674
|
+
}, key);
|
|
675
|
+
if (shape === "diamond") {
|
|
676
|
+
const radius = dotSize / 2;
|
|
677
|
+
const points = `${cx},${cy - radius} ${cx + radius},${cy} ${cx},${cy + radius} ${cx - radius},${cy}`;
|
|
678
|
+
return /* @__PURE__ */ jsx("polygon", {
|
|
679
|
+
...baseProps,
|
|
680
|
+
points
|
|
681
|
+
}, key);
|
|
682
|
+
}
|
|
683
|
+
if (shape === "heart") {
|
|
684
|
+
const s = dotSize / 12;
|
|
685
|
+
const pathD = `M ${cx} ${cy + 4 * s}
|
|
686
|
+
C ${cx - 5 * s} ${cy - 1.5 * s} ${cx - 6 * s} ${cy - 5 * s} ${cx - 3 * s} ${cy - 5.5 * s}
|
|
687
|
+
C ${cx - 1 * s} ${cy - 5.8 * s} ${cx} ${cy - 3 * s} ${cx} ${cy - 3 * s}
|
|
688
|
+
C ${cx} ${cy - 3 * s} ${cx + 1 * s} ${cy - 5.8 * s} ${cx + 3 * s} ${cy - 5.5 * s}
|
|
689
|
+
C ${cx + 6 * s} ${cy - 5 * s} ${cx + 5 * s} ${cy - 1.5 * s} ${cx} ${cy + 4 * s} Z`;
|
|
690
|
+
return /* @__PURE__ */ jsx("path", {
|
|
691
|
+
...baseProps,
|
|
692
|
+
d: pathD
|
|
693
|
+
}, key);
|
|
694
|
+
}
|
|
695
|
+
return /* @__PURE__ */ jsx("circle", {
|
|
696
|
+
...baseProps,
|
|
697
|
+
cx,
|
|
698
|
+
cy,
|
|
699
|
+
r: dotSize / 2
|
|
700
|
+
}, key);
|
|
701
|
+
}))
|
|
702
|
+
]
|
|
703
|
+
})
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
//#endregion
|
|
707
|
+
export { DotMatrix };
|