@glinui/ui 0.1.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/components/accordion.d.ts +42 -0
- package/dist/components/accordion.d.ts.map +1 -0
- package/dist/components/accordion.js +85 -0
- package/dist/components/alert-dialog.d.ts +30 -0
- package/dist/components/alert-dialog.d.ts.map +1 -0
- package/dist/components/alert-dialog.js +53 -0
- package/dist/components/alert.d.ts +15 -0
- package/dist/components/alert.d.ts.map +1 -0
- package/dist/components/alert.js +39 -0
- package/dist/components/animated-gradient.d.ts +11 -0
- package/dist/components/animated-gradient.d.ts.map +1 -0
- package/dist/components/animated-gradient.js +23 -0
- package/dist/components/aurora-background.d.ts +15 -0
- package/dist/components/aurora-background.d.ts.map +1 -0
- package/dist/components/aurora-background.js +26 -0
- package/dist/components/avatar.d.ts +54 -0
- package/dist/components/avatar.d.ts.map +1 -0
- package/dist/components/avatar.js +92 -0
- package/dist/components/badge.d.ts +13 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.js +32 -0
- package/dist/components/blur-fade.d.ts +17 -0
- package/dist/components/blur-fade.d.ts.map +1 -0
- package/dist/components/blur-fade.js +48 -0
- package/dist/components/blur-spotlight.d.ts +13 -0
- package/dist/components/blur-spotlight.d.ts.map +1 -0
- package/dist/components/blur-spotlight.js +58 -0
- package/dist/components/border-beam.d.ts +11 -0
- package/dist/components/border-beam.d.ts.map +1 -0
- package/dist/components/border-beam.js +14 -0
- package/dist/components/button.d.ts +17 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +33 -0
- package/dist/components/card.d.ts +39 -0
- package/dist/components/card.d.ts.map +1 -0
- package/dist/components/card.js +81 -0
- package/dist/components/checkbox.d.ts +14 -0
- package/dist/components/checkbox.d.ts.map +1 -0
- package/dist/components/checkbox.js +58 -0
- package/dist/components/chip.d.ts +15 -0
- package/dist/components/chip.d.ts.map +1 -0
- package/dist/components/chip.js +35 -0
- package/dist/components/chromatic-text.d.ts +11 -0
- package/dist/components/chromatic-text.d.ts.map +1 -0
- package/dist/components/chromatic-text.js +22 -0
- package/dist/components/code.d.ts +13 -0
- package/dist/components/code.d.ts.map +1 -0
- package/dist/components/code.js +27 -0
- package/dist/components/command.d.ts +89 -0
- package/dist/components/command.d.ts.map +1 -0
- package/dist/components/command.js +123 -0
- package/dist/components/counter.d.ts +19 -0
- package/dist/components/counter.d.ts.map +1 -0
- package/dist/components/counter.js +28 -0
- package/dist/components/data-table.d.ts +38 -0
- package/dist/components/data-table.d.ts.map +1 -0
- package/dist/components/data-table.js +183 -0
- package/dist/components/depth-card.d.ts +15 -0
- package/dist/components/depth-card.d.ts.map +1 -0
- package/dist/components/depth-card.js +52 -0
- package/dist/components/dot-pattern.d.ts +10 -0
- package/dist/components/dot-pattern.d.ts.map +1 -0
- package/dist/components/dot-pattern.js +10 -0
- package/dist/components/dropdown-menu.d.ts +74 -0
- package/dist/components/dropdown-menu.d.ts.map +1 -0
- package/dist/components/dropdown-menu.js +90 -0
- package/dist/components/floating-panel.d.ts +17 -0
- package/dist/components/floating-panel.d.ts.map +1 -0
- package/dist/components/floating-panel.js +57 -0
- package/dist/components/glass-breadcrumb.d.ts +17 -0
- package/dist/components/glass-breadcrumb.d.ts.map +1 -0
- package/dist/components/glass-breadcrumb.js +14 -0
- package/dist/components/glass-card.d.ts +20 -0
- package/dist/components/glass-card.d.ts.map +1 -0
- package/dist/components/glass-card.js +36 -0
- package/dist/components/glass-dock.d.ts +21 -0
- package/dist/components/glass-dock.d.ts.map +1 -0
- package/dist/components/glass-dock.js +54 -0
- package/dist/components/glass-navbar.d.ts +21 -0
- package/dist/components/glass-navbar.d.ts.map +1 -0
- package/dist/components/glass-navbar.js +43 -0
- package/dist/components/glass-toggle.d.ts +15 -0
- package/dist/components/glass-toggle.d.ts.map +1 -0
- package/dist/components/glass-toggle.js +32 -0
- package/dist/components/glow-border.d.ts +13 -0
- package/dist/components/glow-border.d.ts.map +1 -0
- package/dist/components/glow-border.js +10 -0
- package/dist/components/gradient-mesh.d.ts +13 -0
- package/dist/components/gradient-mesh.d.ts.map +1 -0
- package/dist/components/gradient-mesh.js +25 -0
- package/dist/components/heading.d.ts +18 -0
- package/dist/components/heading.d.ts.map +1 -0
- package/dist/components/heading.js +28 -0
- package/dist/components/hover-card.d.ts +32 -0
- package/dist/components/hover-card.d.ts.map +1 -0
- package/dist/components/hover-card.js +28 -0
- package/dist/components/icon-frame.d.ts +13 -0
- package/dist/components/icon-frame.d.ts.map +1 -0
- package/dist/components/icon-frame.js +27 -0
- package/dist/components/input.d.ts +13 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +38 -0
- package/dist/components/kbd.d.ts +13 -0
- package/dist/components/kbd.d.ts.map +1 -0
- package/dist/components/kbd.js +27 -0
- package/dist/components/label.d.ts +13 -0
- package/dist/components/label.d.ts.map +1 -0
- package/dist/components/label.js +27 -0
- package/dist/components/light-leak.d.ts +15 -0
- package/dist/components/light-leak.d.ts.map +1 -0
- package/dist/components/light-leak.js +29 -0
- package/dist/components/link.d.ts +15 -0
- package/dist/components/link.d.ts.map +1 -0
- package/dist/components/link.js +32 -0
- package/dist/components/liquid-button.d.ts +17 -0
- package/dist/components/liquid-button.d.ts.map +1 -0
- package/dist/components/liquid-button.js +18 -0
- package/dist/components/magnetic-cta.d.ts +18 -0
- package/dist/components/magnetic-cta.d.ts.map +1 -0
- package/dist/components/magnetic-cta.js +46 -0
- package/dist/components/marquee.d.ts +10 -0
- package/dist/components/marquee.d.ts.map +1 -0
- package/dist/components/marquee.js +16 -0
- package/dist/components/meteor-shower.d.ts +11 -0
- package/dist/components/meteor-shower.d.ts.map +1 -0
- package/dist/components/meteor-shower.js +39 -0
- package/dist/components/modal.d.ts +30 -0
- package/dist/components/modal.d.ts.map +1 -0
- package/dist/components/modal.js +39 -0
- package/dist/components/morphing-tabs.d.ts +22 -0
- package/dist/components/morphing-tabs.d.ts.map +1 -0
- package/dist/components/morphing-tabs.js +72 -0
- package/dist/components/number-ticker.d.ts +11 -0
- package/dist/components/number-ticker.d.ts.map +1 -0
- package/dist/components/number-ticker.js +66 -0
- package/dist/components/orbiting-circles.d.ts +21 -0
- package/dist/components/orbiting-circles.d.ts.map +1 -0
- package/dist/components/orbiting-circles.js +24 -0
- package/dist/components/particle-field.d.ts +19 -0
- package/dist/components/particle-field.d.ts.map +1 -0
- package/dist/components/particle-field.js +41 -0
- package/dist/components/popover.d.ts +27 -0
- package/dist/components/popover.d.ts.map +1 -0
- package/dist/components/popover.js +52 -0
- package/dist/components/prism-border.d.ts +13 -0
- package/dist/components/prism-border.d.ts.map +1 -0
- package/dist/components/prism-border.js +16 -0
- package/dist/components/progress.d.ts +58 -0
- package/dist/components/progress.d.ts.map +1 -0
- package/dist/components/progress.js +108 -0
- package/dist/components/pulsating-button.d.ts +13 -0
- package/dist/components/pulsating-button.d.ts.map +1 -0
- package/dist/components/pulsating-button.js +40 -0
- package/dist/components/radio-group.d.ts +27 -0
- package/dist/components/radio-group.d.ts.map +1 -0
- package/dist/components/radio-group.js +58 -0
- package/dist/components/retro-grid.d.ts +13 -0
- package/dist/components/retro-grid.d.ts.map +1 -0
- package/dist/components/retro-grid.js +17 -0
- package/dist/components/reveal-text.d.ts +17 -0
- package/dist/components/reveal-text.d.ts.map +1 -0
- package/dist/components/reveal-text.js +61 -0
- package/dist/components/ripple-button.d.ts +11 -0
- package/dist/components/ripple-button.d.ts.map +1 -0
- package/dist/components/ripple-button.js +47 -0
- package/dist/components/ripple.d.ts +13 -0
- package/dist/components/ripple.d.ts.map +1 -0
- package/dist/components/ripple.js +24 -0
- package/dist/components/select.d.ts +24 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.js +30 -0
- package/dist/components/separator.d.ts +29 -0
- package/dist/components/separator.d.ts.map +1 -0
- package/dist/components/separator.js +84 -0
- package/dist/components/sheet.d.ts +41 -0
- package/dist/components/sheet.d.ts.map +1 -0
- package/dist/components/sheet.js +85 -0
- package/dist/components/shimmer-button.d.ts +13 -0
- package/dist/components/shimmer-button.d.ts.map +1 -0
- package/dist/components/shimmer-button.js +32 -0
- package/dist/components/skeleton.d.ts +17 -0
- package/dist/components/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton.js +42 -0
- package/dist/components/slider.d.ts +14 -0
- package/dist/components/slider.d.ts.map +1 -0
- package/dist/components/slider.js +89 -0
- package/dist/components/sonner.d.ts +14 -0
- package/dist/components/sonner.d.ts.map +1 -0
- package/dist/components/sonner.js +70 -0
- package/dist/components/spotlight-card.d.ts +11 -0
- package/dist/components/spotlight-card.d.ts.map +1 -0
- package/dist/components/spotlight-card.js +39 -0
- package/dist/components/spotlight.d.ts +19 -0
- package/dist/components/spotlight.d.ts.map +1 -0
- package/dist/components/spotlight.js +23 -0
- package/dist/components/status-dot.d.ts +24 -0
- package/dist/components/status-dot.d.ts.map +1 -0
- package/dist/components/status-dot.js +46 -0
- package/dist/components/switch.d.ts +42 -0
- package/dist/components/switch.d.ts.map +1 -0
- package/dist/components/switch.js +77 -0
- package/dist/components/table.d.ts +69 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/table.js +176 -0
- package/dist/components/tabs.d.ts +34 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/tabs.js +75 -0
- package/dist/components/text-reveal.d.ts +6 -0
- package/dist/components/text-reveal.d.ts.map +1 -0
- package/dist/components/text-reveal.js +56 -0
- package/dist/components/text.d.ts +13 -0
- package/dist/components/text.d.ts.map +1 -0
- package/dist/components/text.js +27 -0
- package/dist/components/textarea.d.ts +13 -0
- package/dist/components/textarea.d.ts.map +1 -0
- package/dist/components/textarea.js +37 -0
- package/dist/components/toast.d.ts +23 -0
- package/dist/components/toast.d.ts.map +1 -0
- package/dist/components/toast.js +36 -0
- package/dist/components/tooltip.d.ts +35 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip.js +34 -0
- package/dist/components/tree.d.ts +50 -0
- package/dist/components/tree.d.ts.map +1 -0
- package/dist/components/tree.js +77 -0
- package/dist/components/typewriter.d.ts +25 -0
- package/dist/components/typewriter.d.ts.map +1 -0
- package/dist/components/typewriter.js +109 -0
- package/dist/components/word-rotate.d.ts +11 -0
- package/dist/components/word-rotate.d.ts.map +1 -0
- package/dist/components/word-rotate.js +29 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/lib/cn.d.ts +3 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +5 -0
- package/dist/lib/use-liquid-glass.d.ts +46 -0
- package/dist/lib/use-liquid-glass.d.ts.map +1 -0
- package/dist/lib/use-liquid-glass.js +144 -0
- package/dist/lib/use-prefers-reduced-motion.d.ts +2 -0
- package/dist/lib/use-prefers-reduced-motion.d.ts.map +1 -0
- package/dist/lib/use-prefers-reduced-motion.js +23 -0
- package/package.json +72 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../lib/cn";
|
|
5
|
+
import { usePrefersReducedMotion } from "../lib/use-prefers-reduced-motion";
|
|
6
|
+
export const Typewriter = React.forwardRef(({ className, text, words, speed = 50, deleteSpeed = 30, delay = 0, cursor = true, cursorChar = "|", loop = false, pauseDuration = 1500, onComplete, "aria-label": ariaLabel, ...props }, ref) => {
|
|
7
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
8
|
+
const [displayedText, setDisplayedText] = React.useState("");
|
|
9
|
+
const [phase, setPhase] = React.useState("idle");
|
|
10
|
+
// Resolve the word list: words array takes priority, fallback to single text
|
|
11
|
+
const wordList = React.useMemo(() => {
|
|
12
|
+
if (words && words.length > 0)
|
|
13
|
+
return words;
|
|
14
|
+
if (text)
|
|
15
|
+
return [text];
|
|
16
|
+
return [""];
|
|
17
|
+
}, [words, text]);
|
|
18
|
+
const isMultiWord = wordList.length > 1;
|
|
19
|
+
// Stable ref so effect deps stay minimal
|
|
20
|
+
const onCompleteRef = React.useRef(onComplete);
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
onCompleteRef.current = onComplete;
|
|
23
|
+
}, [onComplete]);
|
|
24
|
+
React.useEffect(() => {
|
|
25
|
+
// Reduced-motion: show first word immediately with no animation
|
|
26
|
+
if (prefersReducedMotion) {
|
|
27
|
+
setDisplayedText(wordList[0]);
|
|
28
|
+
setPhase("pausing");
|
|
29
|
+
onCompleteRef.current?.();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let wordIndex = 0;
|
|
33
|
+
let charIndex = 0;
|
|
34
|
+
let timeoutId;
|
|
35
|
+
let cancelled = false;
|
|
36
|
+
const typeWord = () => {
|
|
37
|
+
if (cancelled)
|
|
38
|
+
return;
|
|
39
|
+
const currentWord = wordList[wordIndex];
|
|
40
|
+
setPhase("typing");
|
|
41
|
+
const typeStep = () => {
|
|
42
|
+
if (cancelled)
|
|
43
|
+
return;
|
|
44
|
+
if (charIndex <= currentWord.length) {
|
|
45
|
+
setDisplayedText(currentWord.slice(0, charIndex));
|
|
46
|
+
charIndex += 1;
|
|
47
|
+
timeoutId = setTimeout(typeStep, speed);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Finished typing current word
|
|
51
|
+
setPhase("pausing");
|
|
52
|
+
onCompleteRef.current?.();
|
|
53
|
+
if (isMultiWord || loop) {
|
|
54
|
+
timeoutId = setTimeout(() => {
|
|
55
|
+
if (cancelled)
|
|
56
|
+
return;
|
|
57
|
+
deleteWord(currentWord);
|
|
58
|
+
}, pauseDuration);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
typeStep();
|
|
63
|
+
};
|
|
64
|
+
const deleteWord = (currentWord) => {
|
|
65
|
+
if (cancelled)
|
|
66
|
+
return;
|
|
67
|
+
setPhase("deleting");
|
|
68
|
+
let delIndex = currentWord.length;
|
|
69
|
+
const deleteStep = () => {
|
|
70
|
+
if (cancelled)
|
|
71
|
+
return;
|
|
72
|
+
if (delIndex >= 0) {
|
|
73
|
+
setDisplayedText(currentWord.slice(0, delIndex));
|
|
74
|
+
delIndex -= 1;
|
|
75
|
+
timeoutId = setTimeout(deleteStep, deleteSpeed);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// Finished deleting — move to next word
|
|
79
|
+
wordIndex = (wordIndex + 1) % wordList.length;
|
|
80
|
+
// If not looping and we've cycled through all words, stop
|
|
81
|
+
if (!loop && wordIndex === 0 && !isMultiWord) {
|
|
82
|
+
setPhase("pausing");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
charIndex = 0;
|
|
86
|
+
timeoutId = setTimeout(typeWord, speed * 2);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
deleteStep();
|
|
90
|
+
};
|
|
91
|
+
setDisplayedText("");
|
|
92
|
+
setPhase("idle");
|
|
93
|
+
charIndex = 0;
|
|
94
|
+
wordIndex = 0;
|
|
95
|
+
timeoutId = setTimeout(typeWord, delay);
|
|
96
|
+
return () => {
|
|
97
|
+
cancelled = true;
|
|
98
|
+
clearTimeout(timeoutId);
|
|
99
|
+
};
|
|
100
|
+
}, [wordList, speed, deleteSpeed, delay, loop, pauseDuration, isMultiWord, prefersReducedMotion]);
|
|
101
|
+
// Cursor blinks when pausing; solid while actively typing/deleting
|
|
102
|
+
const cursorBlinking = phase === "pausing";
|
|
103
|
+
// For aria-label: join all words or use single text
|
|
104
|
+
const fullLabel = ariaLabel ?? wordList.join(", ");
|
|
105
|
+
return (_jsxs("span", { ref: ref, "aria-label": fullLabel, "aria-live": "off", className: cn("inline-flex items-baseline", className), ...props, children: [_jsx("span", { "aria-hidden": "true", children: displayedText }), cursor && (_jsx("span", { "aria-hidden": "true", className: cn("ml-[0.05em] inline-block select-none", cursorBlinking
|
|
106
|
+
? "animate-blink motion-reduce:[animation:none]"
|
|
107
|
+
: "opacity-100"), children: cursorChar }))] }));
|
|
108
|
+
});
|
|
109
|
+
Typewriter.displayName = "Typewriter";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface WordRotateProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
3
|
+
/** Array of words to cycle through */
|
|
4
|
+
words: string[];
|
|
5
|
+
/** Duration each word is shown (ms) */
|
|
6
|
+
duration?: number;
|
|
7
|
+
/** Animation speed for enter/exit (ms) */
|
|
8
|
+
animationDuration?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const WordRotate: React.ForwardRefExoticComponent<WordRotateProps & React.RefAttributes<HTMLSpanElement>>;
|
|
11
|
+
//# sourceMappingURL=word-rotate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"word-rotate.d.ts","sourceRoot":"","sources":["../../src/components/word-rotate.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,WAAW,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;IAC5E,sCAAsC;IACtC,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0CAA0C;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,eAAO,MAAM,UAAU,yFA0DtB,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../lib/cn";
|
|
5
|
+
export const WordRotate = React.forwardRef(({ className, words, duration = 2500, animationDuration = 300, style, ...props }, ref) => {
|
|
6
|
+
const [currentIndex, setCurrentIndex] = React.useState(0);
|
|
7
|
+
const [animating, setAnimating] = React.useState("idle");
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
if (words.length <= 1)
|
|
10
|
+
return;
|
|
11
|
+
const prefersReduced = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
12
|
+
if (prefersReduced)
|
|
13
|
+
return;
|
|
14
|
+
const timer = setInterval(() => {
|
|
15
|
+
setAnimating("out");
|
|
16
|
+
setTimeout(() => {
|
|
17
|
+
setCurrentIndex((prev) => (prev + 1) % words.length);
|
|
18
|
+
setAnimating("in");
|
|
19
|
+
setTimeout(() => setAnimating("idle"), animationDuration);
|
|
20
|
+
}, animationDuration);
|
|
21
|
+
}, duration);
|
|
22
|
+
return () => clearInterval(timer);
|
|
23
|
+
}, [words, duration, animationDuration]);
|
|
24
|
+
return (_jsx("span", { ref: ref, className: cn("inline-block overflow-hidden", className), style: {
|
|
25
|
+
"--word-rotate-duration": `${animationDuration}ms`,
|
|
26
|
+
...style,
|
|
27
|
+
}, ...props, children: _jsx("span", { className: cn("inline-block", animating === "in" && "animate-word-rotate-in", animating === "out" && "animate-word-rotate-out", "motion-reduce:[animation:none]"), "aria-live": "polite", children: words[currentIndex] }, currentIndex) }));
|
|
28
|
+
});
|
|
29
|
+
WordRotate.displayName = "WordRotate";
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export * from "./components/accordion";
|
|
2
|
+
export * from "./components/alert-dialog";
|
|
3
|
+
export * from "./components/animated-gradient";
|
|
4
|
+
export * from "./components/alert";
|
|
5
|
+
export * from "./components/aurora-background";
|
|
6
|
+
export * from "./components/avatar";
|
|
7
|
+
export * from "./components/badge";
|
|
8
|
+
export * from "./components/blur-fade";
|
|
9
|
+
export * from "./components/blur-spotlight";
|
|
10
|
+
export * from "./components/border-beam";
|
|
11
|
+
export * from "./components/button";
|
|
12
|
+
export * from "./components/card";
|
|
13
|
+
export * from "./components/checkbox";
|
|
14
|
+
export * from "./components/chip";
|
|
15
|
+
export * from "./components/chromatic-text";
|
|
16
|
+
export * from "./components/code";
|
|
17
|
+
export * from "./components/command";
|
|
18
|
+
export * from "./components/counter";
|
|
19
|
+
export * from "./components/data-table";
|
|
20
|
+
export * from "./components/depth-card";
|
|
21
|
+
export * from "./components/dot-pattern";
|
|
22
|
+
export * from "./components/dropdown-menu";
|
|
23
|
+
export * from "./components/floating-panel";
|
|
24
|
+
export * from "./components/glass-breadcrumb";
|
|
25
|
+
export * from "./components/glass-card";
|
|
26
|
+
export * from "./components/glass-dock";
|
|
27
|
+
export * from "./components/glow-border";
|
|
28
|
+
export * from "./components/gradient-mesh";
|
|
29
|
+
export * from "./components/glass-navbar";
|
|
30
|
+
export * from "./components/glass-toggle";
|
|
31
|
+
export * from "./components/heading";
|
|
32
|
+
export * from "./components/hover-card";
|
|
33
|
+
export * from "./components/icon-frame";
|
|
34
|
+
export * from "./components/input";
|
|
35
|
+
export * from "./components/kbd";
|
|
36
|
+
export * from "./components/label";
|
|
37
|
+
export * from "./components/light-leak";
|
|
38
|
+
export * from "./components/liquid-button";
|
|
39
|
+
export * from "./components/link";
|
|
40
|
+
export * from "./components/magnetic-cta";
|
|
41
|
+
export * from "./components/marquee";
|
|
42
|
+
export * from "./components/meteor-shower";
|
|
43
|
+
export * from "./components/modal";
|
|
44
|
+
export * from "./components/morphing-tabs";
|
|
45
|
+
export * from "./components/number-ticker";
|
|
46
|
+
export * from "./components/orbiting-circles";
|
|
47
|
+
export * from "./components/particle-field";
|
|
48
|
+
export * from "./components/popover";
|
|
49
|
+
export * from "./components/progress";
|
|
50
|
+
export * from "./components/prism-border";
|
|
51
|
+
export * from "./components/pulsating-button";
|
|
52
|
+
export * from "./components/radio-group";
|
|
53
|
+
export * from "./components/retro-grid";
|
|
54
|
+
export * from "./components/reveal-text";
|
|
55
|
+
export * from "./components/ripple";
|
|
56
|
+
export * from "./components/ripple-button";
|
|
57
|
+
export * from "./components/select";
|
|
58
|
+
export * from "./components/separator";
|
|
59
|
+
export * from "./components/sheet";
|
|
60
|
+
export * from "./components/shimmer-button";
|
|
61
|
+
export * from "./components/skeleton";
|
|
62
|
+
export * from "./components/slider";
|
|
63
|
+
export * from "./components/spotlight-card";
|
|
64
|
+
export * from "./components/spotlight";
|
|
65
|
+
export * from "./components/status-dot";
|
|
66
|
+
export * from "./components/switch";
|
|
67
|
+
export * from "./components/table";
|
|
68
|
+
export * from "./components/tabs";
|
|
69
|
+
export * from "./components/text";
|
|
70
|
+
export * from "./components/text-reveal";
|
|
71
|
+
export * from "./components/textarea";
|
|
72
|
+
export * from "./components/sonner";
|
|
73
|
+
export * from "./components/toast";
|
|
74
|
+
export * from "./components/tree";
|
|
75
|
+
export * from "./components/tooltip";
|
|
76
|
+
export * from "./components/typewriter";
|
|
77
|
+
export * from "./components/word-rotate";
|
|
78
|
+
export * from "./lib/cn";
|
|
79
|
+
export { useLiquidGlass } from "./lib/use-liquid-glass";
|
|
80
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,oBAAoB,CAAA;AAClC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,oBAAoB,CAAA;AAClC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AACnC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,UAAU,CAAA;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export * from "./components/accordion";
|
|
2
|
+
export * from "./components/alert-dialog";
|
|
3
|
+
export * from "./components/animated-gradient";
|
|
4
|
+
export * from "./components/alert";
|
|
5
|
+
export * from "./components/aurora-background";
|
|
6
|
+
export * from "./components/avatar";
|
|
7
|
+
export * from "./components/badge";
|
|
8
|
+
export * from "./components/blur-fade";
|
|
9
|
+
export * from "./components/blur-spotlight";
|
|
10
|
+
export * from "./components/border-beam";
|
|
11
|
+
export * from "./components/button";
|
|
12
|
+
export * from "./components/card";
|
|
13
|
+
export * from "./components/checkbox";
|
|
14
|
+
export * from "./components/chip";
|
|
15
|
+
export * from "./components/chromatic-text";
|
|
16
|
+
export * from "./components/code";
|
|
17
|
+
export * from "./components/command";
|
|
18
|
+
export * from "./components/counter";
|
|
19
|
+
export * from "./components/data-table";
|
|
20
|
+
export * from "./components/depth-card";
|
|
21
|
+
export * from "./components/dot-pattern";
|
|
22
|
+
export * from "./components/dropdown-menu";
|
|
23
|
+
export * from "./components/floating-panel";
|
|
24
|
+
export * from "./components/glass-breadcrumb";
|
|
25
|
+
export * from "./components/glass-card";
|
|
26
|
+
export * from "./components/glass-dock";
|
|
27
|
+
export * from "./components/glow-border";
|
|
28
|
+
export * from "./components/gradient-mesh";
|
|
29
|
+
export * from "./components/glass-navbar";
|
|
30
|
+
export * from "./components/glass-toggle";
|
|
31
|
+
export * from "./components/heading";
|
|
32
|
+
export * from "./components/hover-card";
|
|
33
|
+
export * from "./components/icon-frame";
|
|
34
|
+
export * from "./components/input";
|
|
35
|
+
export * from "./components/kbd";
|
|
36
|
+
export * from "./components/label";
|
|
37
|
+
export * from "./components/light-leak";
|
|
38
|
+
export * from "./components/liquid-button";
|
|
39
|
+
export * from "./components/link";
|
|
40
|
+
export * from "./components/magnetic-cta";
|
|
41
|
+
export * from "./components/marquee";
|
|
42
|
+
export * from "./components/meteor-shower";
|
|
43
|
+
export * from "./components/modal";
|
|
44
|
+
export * from "./components/morphing-tabs";
|
|
45
|
+
export * from "./components/number-ticker";
|
|
46
|
+
export * from "./components/orbiting-circles";
|
|
47
|
+
export * from "./components/particle-field";
|
|
48
|
+
export * from "./components/popover";
|
|
49
|
+
export * from "./components/progress";
|
|
50
|
+
export * from "./components/prism-border";
|
|
51
|
+
export * from "./components/pulsating-button";
|
|
52
|
+
export * from "./components/radio-group";
|
|
53
|
+
export * from "./components/retro-grid";
|
|
54
|
+
export * from "./components/reveal-text";
|
|
55
|
+
export * from "./components/ripple";
|
|
56
|
+
export * from "./components/ripple-button";
|
|
57
|
+
export * from "./components/select";
|
|
58
|
+
export * from "./components/separator";
|
|
59
|
+
export * from "./components/sheet";
|
|
60
|
+
export * from "./components/shimmer-button";
|
|
61
|
+
export * from "./components/skeleton";
|
|
62
|
+
export * from "./components/slider";
|
|
63
|
+
export * from "./components/spotlight-card";
|
|
64
|
+
export * from "./components/spotlight";
|
|
65
|
+
export * from "./components/status-dot";
|
|
66
|
+
export * from "./components/switch";
|
|
67
|
+
export * from "./components/table";
|
|
68
|
+
export * from "./components/tabs";
|
|
69
|
+
export * from "./components/text";
|
|
70
|
+
export * from "./components/text-reveal";
|
|
71
|
+
export * from "./components/textarea";
|
|
72
|
+
export * from "./components/sonner";
|
|
73
|
+
export * from "./components/toast";
|
|
74
|
+
export * from "./components/tree";
|
|
75
|
+
export * from "./components/tooltip";
|
|
76
|
+
export * from "./components/typewriter";
|
|
77
|
+
export * from "./components/word-rotate";
|
|
78
|
+
export * from "./lib/cn";
|
|
79
|
+
export { useLiquidGlass } from "./lib/use-liquid-glass";
|
package/dist/lib/cn.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../src/lib/cn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAA;AAG5C,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
|
package/dist/lib/cn.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Liquid Glass — SVG displacement-map refraction for `backdrop-filter`.
|
|
4
|
+
*
|
|
5
|
+
* Uses `feDisplacementMap` to create real optical refraction through a
|
|
6
|
+
* curved "squircle" surface. The SVG filter handles ONLY the displacement;
|
|
7
|
+
* blur + saturation are chained as separate CSS `backdrop-filter` functions
|
|
8
|
+
* so Chrome processes them correctly.
|
|
9
|
+
*
|
|
10
|
+
* `backdrop-filter: url(#svgFilter) blur(Xpx) saturate(Y)`
|
|
11
|
+
*
|
|
12
|
+
* Browser support (2026):
|
|
13
|
+
* - Chromium (Chrome, Edge, Brave, Arc, Opera) — full refraction
|
|
14
|
+
* - Safari / Firefox — graceful fallback to CSS blur + saturate
|
|
15
|
+
*
|
|
16
|
+
* When Safari / Firefox add `backdrop-filter: url()` support, the
|
|
17
|
+
* effect will automatically upgrade without code changes.
|
|
18
|
+
*
|
|
19
|
+
* Technique credit: https://kube.io/blog/liquid-glass-css-svg
|
|
20
|
+
*/
|
|
21
|
+
type LiquidGlassOptions = {
|
|
22
|
+
/** Max pixel displacement for refraction (default: 40) */
|
|
23
|
+
displacement?: number;
|
|
24
|
+
/** Gaussian blur standard-deviation in px (default: 12) */
|
|
25
|
+
blur?: number;
|
|
26
|
+
/** Saturation multiplier — 1.8 = Apple's 180% (default: 1.8) */
|
|
27
|
+
saturate?: number;
|
|
28
|
+
/** Surface profile shape (default: "squircle") */
|
|
29
|
+
profile?: "squircle" | "convex";
|
|
30
|
+
/** Disable the effect entirely (default: false) */
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
};
|
|
33
|
+
export declare function useLiquidGlass(opts?: LiquidGlassOptions): {
|
|
34
|
+
/** Attach to the glass element */
|
|
35
|
+
ref: import("react").RefObject<HTMLDivElement | null>;
|
|
36
|
+
/** Render this anywhere in the DOM (hidden SVG filter defs) */
|
|
37
|
+
svgFilter: ReactNode;
|
|
38
|
+
/** Apply to the glass element's `style` prop */
|
|
39
|
+
style: CSSProperties;
|
|
40
|
+
/** Filter ID (for manual usage) */
|
|
41
|
+
filterId: string;
|
|
42
|
+
/** True when SVG refraction is active (Chrome only) */
|
|
43
|
+
isSupported: boolean;
|
|
44
|
+
};
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=use-liquid-glass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-liquid-glass.d.ts","sourceRoot":"","sources":["../../src/lib/use-liquid-glass.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGrD;;;;;;;;;;;;;;;;;;GAkBG;AAEH,KAAK,kBAAkB,GAAG;IACxB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kDAAkD;IAClD,OAAO,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IAC/B,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAmGD,wBAAgB,cAAc,CAAC,IAAI,GAAE,kBAAuB;IA0GxD,kCAAkC;;IAElC,+DAA+D;eACvC,SAAS;IACjC,gDAAgD;;IAEhD,mCAAmC;;IAEnC,uDAAuD;;EAG1D"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Browser detection
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/** Only Chromium exposes SVG filters as `backdrop-filter`. */
|
|
8
|
+
function supportsBackdropSvgFilter() {
|
|
9
|
+
if (typeof navigator === "undefined")
|
|
10
|
+
return false;
|
|
11
|
+
return /Chrome|Chromium/.test(navigator.userAgent);
|
|
12
|
+
}
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Displacement map generator
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/**
|
|
17
|
+
* Builds a PNG data-URL encoding a displacement map.
|
|
18
|
+
*
|
|
19
|
+
* Red channel → horizontal displacement
|
|
20
|
+
* Green channel → vertical displacement
|
|
21
|
+
* 128 = neutral (no shift), ±127 = max shift.
|
|
22
|
+
*
|
|
23
|
+
* Generated at half resolution for performance — the SVG filter stretches
|
|
24
|
+
* it to the element size via `preserveAspectRatio="none"`.
|
|
25
|
+
*/
|
|
26
|
+
function buildDisplacementMap(w, h, profile) {
|
|
27
|
+
const canvas = document.createElement("canvas");
|
|
28
|
+
canvas.width = w;
|
|
29
|
+
canvas.height = h;
|
|
30
|
+
const ctx = canvas.getContext("2d");
|
|
31
|
+
const img = ctx.createImageData(w, h);
|
|
32
|
+
const px = img.data;
|
|
33
|
+
const mx = w / 2;
|
|
34
|
+
const my = h / 2;
|
|
35
|
+
for (let row = 0; row < h; row++) {
|
|
36
|
+
for (let col = 0; col < w; col++) {
|
|
37
|
+
const i = (row * w + col) * 4;
|
|
38
|
+
// Normalized coords [-1, 1]
|
|
39
|
+
const nx = (col - mx) / mx;
|
|
40
|
+
const ny = (row - my) / my;
|
|
41
|
+
// Distance from centre (squircle or circle)
|
|
42
|
+
const dist = profile === "squircle"
|
|
43
|
+
? (Math.abs(nx) ** 4 + Math.abs(ny) ** 4) ** 0.25
|
|
44
|
+
: Math.hypot(nx, ny);
|
|
45
|
+
// Outside shape or dead-centre → no displacement
|
|
46
|
+
if (dist >= 1 || dist < 0.002) {
|
|
47
|
+
px[i] = 128;
|
|
48
|
+
px[i + 1] = 128;
|
|
49
|
+
px[i + 2] = 128;
|
|
50
|
+
px[i + 3] = 255;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
// Surface gradient magnitude (derivative of height function)
|
|
54
|
+
let grad;
|
|
55
|
+
if (profile === "squircle") {
|
|
56
|
+
// h = (1 - d^4)^0.25 → |∇h| ∝ d^3 / (1 - d^4)^0.75
|
|
57
|
+
grad = dist ** 3 / Math.max(1 - dist ** 4, 1e-4) ** 0.75;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// h = √(1 - d²) → |∇h| = d / √(1 - d²)
|
|
61
|
+
grad = dist / Math.max(1 - dist * dist, 1e-4) ** 0.5;
|
|
62
|
+
}
|
|
63
|
+
// Smooth falloff near rim so edges don't clip hard
|
|
64
|
+
grad *= (1 - dist) ** 0.5;
|
|
65
|
+
grad = Math.min(grad, 1);
|
|
66
|
+
// Direction: radially outward from centre
|
|
67
|
+
const angle = Math.atan2(ny, nx);
|
|
68
|
+
const dx = Math.cos(angle) * grad;
|
|
69
|
+
const dy = Math.sin(angle) * grad;
|
|
70
|
+
// Encode in R/G channels — FULL range ±127 for maximum refraction
|
|
71
|
+
px[i] = Math.round(Math.max(0, Math.min(255, 128 + dx * 127)));
|
|
72
|
+
px[i + 1] = Math.round(Math.max(0, Math.min(255, 128 + dy * 127)));
|
|
73
|
+
px[i + 2] = 128;
|
|
74
|
+
px[i + 3] = 255;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
ctx.putImageData(img, 0, 0);
|
|
78
|
+
return canvas.toDataURL("image/png");
|
|
79
|
+
}
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Hook
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
export function useLiquidGlass(opts = {}) {
|
|
84
|
+
const { displacement = 40, blur = 12, saturate = 1.8, profile = "squircle", disabled = false, } = opts;
|
|
85
|
+
const uid = useId().replace(/:/g, "");
|
|
86
|
+
const filterId = `lg-${uid}`;
|
|
87
|
+
const ref = useRef(null);
|
|
88
|
+
const [supported, setSupported] = useState(false);
|
|
89
|
+
const [dim, setDim] = useState({ w: 0, h: 0 });
|
|
90
|
+
const [mapUrl, setMapUrl] = useState(null);
|
|
91
|
+
// Detect Chromium on mount
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (!disabled)
|
|
94
|
+
setSupported(supportsBackdropSvgFilter());
|
|
95
|
+
}, [disabled]);
|
|
96
|
+
// Observe element dimensions
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!supported || !ref.current)
|
|
99
|
+
return;
|
|
100
|
+
const el = ref.current;
|
|
101
|
+
const ro = new ResizeObserver(([entry]) => {
|
|
102
|
+
if (!entry)
|
|
103
|
+
return;
|
|
104
|
+
const { width, height } = entry.contentRect;
|
|
105
|
+
setDim({ w: Math.round(width), h: Math.round(height) });
|
|
106
|
+
});
|
|
107
|
+
ro.observe(el);
|
|
108
|
+
return () => ro.disconnect();
|
|
109
|
+
}, [supported]);
|
|
110
|
+
// Generate displacement map at half resolution (better quality than 1/4)
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (!supported || dim.w < 16 || dim.h < 16)
|
|
113
|
+
return;
|
|
114
|
+
const scale = 0.5;
|
|
115
|
+
const url = buildDisplacementMap(Math.round(dim.w * scale), Math.round(dim.h * scale), profile);
|
|
116
|
+
setMapUrl(url);
|
|
117
|
+
}, [supported, dim.w, dim.h, profile]);
|
|
118
|
+
const ready = supported && !!mapUrl && dim.w > 0;
|
|
119
|
+
// SVG filter — ONLY displacement, no blur or saturate.
|
|
120
|
+
// Blur + saturate are chained as CSS functions in `backdropFilter`.
|
|
121
|
+
// This is critical: Chrome processes `url()` + CSS functions correctly
|
|
122
|
+
// only when the SVG filter is simple (displacement only).
|
|
123
|
+
const svgFilter = ready ? (_jsx("svg", { width: "0", height: "0", style: { position: "fixed", top: 0, left: 0, pointerEvents: "none" }, "aria-hidden": true, children: _jsx("defs", { children: _jsxs("filter", { id: filterId, x: "0", y: "0", width: dim.w, height: dim.h, filterUnits: "userSpaceOnUse", colorInterpolationFilters: "sRGB", children: [_jsx("feImage", { href: mapUrl, x: "0", y: "0", width: dim.w, height: dim.h, result: "dispMap", preserveAspectRatio: "none" }), _jsx("feDisplacementMap", { in: "SourceGraphic", in2: "dispMap", scale: String(displacement), xChannelSelector: "R", yChannelSelector: "G" })] }) }) })) : null;
|
|
124
|
+
// Style: chain SVG displacement with CSS blur + saturate
|
|
125
|
+
// Chrome processes: url(#filter) → blur → saturate as a pipeline
|
|
126
|
+
const style = ready
|
|
127
|
+
? {
|
|
128
|
+
backdropFilter: `url(#${filterId}) blur(${blur}px) saturate(${saturate})`,
|
|
129
|
+
WebkitBackdropFilter: `url(#${filterId}) blur(${blur}px) saturate(${saturate})`,
|
|
130
|
+
}
|
|
131
|
+
: {};
|
|
132
|
+
return {
|
|
133
|
+
/** Attach to the glass element */
|
|
134
|
+
ref,
|
|
135
|
+
/** Render this anywhere in the DOM (hidden SVG filter defs) */
|
|
136
|
+
svgFilter: svgFilter,
|
|
137
|
+
/** Apply to the glass element's `style` prop */
|
|
138
|
+
style,
|
|
139
|
+
/** Filter ID (for manual usage) */
|
|
140
|
+
filterId,
|
|
141
|
+
/** True when SVG refraction is active (Chrome only) */
|
|
142
|
+
isSupported: ready,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-prefers-reduced-motion.d.ts","sourceRoot":"","sources":["../../src/lib/use-prefers-reduced-motion.ts"],"names":[],"mappings":"AAMA,wBAAgB,uBAAuB,YA0BtC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
const QUERY = "(prefers-reduced-motion: reduce)";
|
|
4
|
+
export function usePrefersReducedMotion() {
|
|
5
|
+
const [prefersReducedMotion, setPrefersReducedMotion] = React.useState(false);
|
|
6
|
+
React.useEffect(() => {
|
|
7
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const mediaQuery = window.matchMedia(QUERY);
|
|
11
|
+
const handleChange = () => {
|
|
12
|
+
setPrefersReducedMotion(mediaQuery.matches);
|
|
13
|
+
};
|
|
14
|
+
handleChange();
|
|
15
|
+
if (typeof mediaQuery.addEventListener === "function") {
|
|
16
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
17
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
18
|
+
}
|
|
19
|
+
mediaQuery.addListener(handleChange);
|
|
20
|
+
return () => mediaQuery.removeListener(handleChange);
|
|
21
|
+
}, []);
|
|
22
|
+
return prefersReducedMotion;
|
|
23
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@glinui/ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": ["dist"],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/GLINCKER/glinui",
|
|
18
|
+
"directory": "packages/ui"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://glinui.com",
|
|
21
|
+
"bugs": "https://github.com/GLINCKER/glinui/issues",
|
|
22
|
+
"keywords": ["glinui", "glassmorphism", "liquid-glass", "react", "tailwindcss", "ui", "design-system"],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc -p tsconfig.json",
|
|
28
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
29
|
+
"lint": "echo 'lint: @glinui/ui (todo)'",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:coverage": "vitest run --coverage"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
35
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@radix-ui/react-accordion": "^1.2.12",
|
|
39
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
40
|
+
"@radix-ui/react-checkbox": "^1.3.3",
|
|
41
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
42
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
43
|
+
"@radix-ui/react-hover-card": "^1.1.15",
|
|
44
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
45
|
+
"@radix-ui/react-progress": "^1.1.8",
|
|
46
|
+
"@radix-ui/react-radio-group": "^1.3.8",
|
|
47
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
48
|
+
"@radix-ui/react-slider": "^1.3.6",
|
|
49
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
50
|
+
"@radix-ui/react-switch": "^1.2.6",
|
|
51
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
52
|
+
"@radix-ui/react-toast": "^1.2.15",
|
|
53
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
54
|
+
"class-variance-authority": "^0.7.1",
|
|
55
|
+
"clsx": "^2.1.1",
|
|
56
|
+
"cmdk": "^1.1.1",
|
|
57
|
+
"lucide-react": "^0.563.0",
|
|
58
|
+
"sonner": "^2.0.7",
|
|
59
|
+
"tailwind-merge": "^3.3.1"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
63
|
+
"@testing-library/react": "^16.3.0",
|
|
64
|
+
"@testing-library/user-event": "^14.6.1",
|
|
65
|
+
"@types/react": "^19.0.6",
|
|
66
|
+
"@types/react-dom": "^19.0.2",
|
|
67
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
68
|
+
"axe-core": "^4.11.1",
|
|
69
|
+
"jsdom": "^26.1.0",
|
|
70
|
+
"vitest": "^3.2.4"
|
|
71
|
+
}
|
|
72
|
+
}
|