react-glass-ui
Version:
A customizable React component library for building liquid-glass interfaces with dynamic, realistic fluid distortion. Powered by advanced SVG filters, the library simulates true refraction, blur, and chromatic distortion to create authentic glass-like sur
950 lines (941 loc) • 38.3 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
GlassButton: () => GlassButton,
GlassCard: () => GlassCard,
GlassInput: () => GlassInput
});
module.exports = __toCommonJS(index_exports);
// src/ui-elements/glass-card/index.tsx
var import_react = require("react");
// src/models/index.ts
var glassDefaultProps = {
blur: 2,
distortion: 40,
chromaticAberration: 0,
borderRadius: 10,
borderSize: 1,
borderOpacity: 0.2,
color: "white",
backgroundColor: "white",
backgroundOpacity: 0,
flexibility: 0,
onHoverScale: 1,
saturation: 120,
brightness: 100,
innerLightBlur: 10,
innerLightSpread: 1,
innerLightColor: "white",
innerLightOpacity: 0,
outerLightBlur: 10,
outerLightSpread: 1,
outerLightColor: "white",
outerLightOpacity: 0,
padding: "10px"
};
// src/assets/normal-maps/index.ts
var distortionMap = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAIAAADTED8xAAAAK3RFWHRDcmVhdGlvbiBUaW1lAE1vbiAxIEp1biAyMDA5IDAwOjUwOjA4ICswMTAwlMZeaQAAAAd0SU1FB9kGAQsgET14njMAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAEZ0FNQQAAsY8L/GEFAAACvUlEQVR42u3TgQkAMAzDsBb2/81ld1gi5APvzKxZde8fVAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkCIE0ApAmANAGQJgDSBECaAEgTAGkHGmUF/FFYhBoAAAAASUVORK5CYII=";
// src/utils/index.tsx
var import_utils = require("./utils-5Z2TKYUT.css");
var import_jsx_runtime = require("react/jsx-runtime");
var renderLayers = (id, blur, borderRadius, saturation, brightness, distortion, backgroundColor, backgroundOpacity, style, innerLightOpacity, outerLightOpacity, borderColor, borderSize, borderOpacity, chromaticAberration, avoidSvgCreation, type) => {
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
distortion && !avoidSvgCreation ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { style: { borderRadius }, className: "glass-ui-svg", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("clipPath", { id: `${id}-clip`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"rect",
{
x: "0",
y: "0",
width: "100%",
height: "100%",
rx: 0,
ry: borderRadius
}
) }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
"filter",
{
id: `${id}-filter`,
x: "0",
y: "0",
width: "100%",
height: "100%",
colorInterpolationFilters: "sRGB",
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"feImage",
{
id: "feimage",
x: "0%",
y: "0",
width: "100%",
height: "100%",
href: distortionMap,
result: "originalMap",
preserveAspectRatio: "xMidYMid slice"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"feDisplacementMap",
{
in: "SourceGraphic",
in2: "originalMap",
scale: distortion,
xChannelSelector: "R",
yChannelSelector: "G",
result: "distortedOutput"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"feColorMatrix",
{
in: "distortedOutput",
type: "matrix",
values: "1 0 0 0 0\r\n 0 0 0 0 0\r\n 0 0 0 0 0\r\n 0 0 0 1 0",
result: "r"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"feOffset",
{
in: "r",
dx: -chromaticAberration,
dy: "0",
result: "rOffset"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"feColorMatrix",
{
in: "distortedOutput",
type: "matrix",
values: "0 0 0 0 0\r\n 0 1 0 0 0\r\n 0 0 0 0 0\r\n 0 0 0 1 0",
result: "g"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feOffset", { in: "g", dx: "0", dy: "0", result: "gOffset" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"feColorMatrix",
{
in: "distortedOutput",
type: "matrix",
values: "0 0 0 0 0\r\n 0 0 0 0 0\r\n 0 0 1 0 0\r\n 0 0 0 1 0",
result: "b"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"feOffset",
{
in: "b",
dx: chromaticAberration,
dy: "0",
result: "bOffset"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feBlend", { in: "rOffset", in2: "gOffset", mode: "screen", result: "rgb1" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"feBlend",
{
in: "rgb1",
in2: "bOffset",
mode: "screen",
result: "finalRender"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feComposite", { in: "finalRender", in2: "SourceAlpha", operator: "in" })
]
}
) })
] }) : "",
type === "range" ? "" : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
borderSize ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"span",
{
className: "glass-ui-border-layer",
style: {
borderRadius,
border: `${borderSize}px solid ${borderColor}`,
opacity: borderOpacity
}
}
) : "",
innerLightOpacity ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"span",
{
className: "glass-ui-inner-light",
style: {
borderRadius,
boxShadow: style.innerBoxShadow,
opacity: innerLightOpacity
}
}
) : "",
backgroundOpacity ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"div",
{
className: "glass-ui-background-layer",
style: {
borderRadius,
opacity: `${backgroundOpacity}`,
backgroundColor: `${backgroundColor}`
}
}
) : "",
distortion || blur || saturation || brightness ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"div",
{
className: "glass-ui-distortion-layer",
style: {
borderRadius,
clipPath: `url(#${id}-clip)`,
WebkitClipPath: `url(#${id}-clip)`,
filter: `url(#${id}-filter)`,
backdropFilter: `blur(${blur}px) saturate(${saturation}%) brightness(${brightness}%)`,
WebkitBackdropFilter: `blur(${blur}px) saturate(${saturation}%) brightness(${brightness}%)`
}
}
) : "",
outerLightOpacity ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"span",
{
className: "glass-ui-outer-light",
style: {
borderRadius,
boxShadow: style.outerBoxShadow,
opacity: outerLightOpacity
}
}
) : ""
] })
] });
};
function calculateHoverEffect(e, card, props) {
const {
flexibility = 0,
onHoverScale = 1,
innerLightBlur = 0,
innerLightSpread = 0,
innerLightColor = "white",
outerLightBlur = 0,
outerLightSpread = 0,
outerLightColor = "white"
} = props;
let transform = "none";
if (flexibility > 0) {
const rect = card.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const dx = e.clientX - centerX;
const dy = e.clientY - centerY;
const angle = Math.atan2(dy, dx);
const distance = Math.sqrt(dx * dx + dy * dy);
const scaleFactor = flexibility / 100;
const translateX = Math.cos(angle) * distance * scaleFactor;
const translateY = Math.sin(angle) * distance * scaleFactor;
let stretchX = 1;
let stretchY = 1;
if (onHoverScale) {
stretchX = onHoverScale + Math.abs(translateX) / rect.width;
stretchY = onHoverScale + Math.abs(translateY) / rect.height;
}
transform = `translate(${translateX}px, ${translateY}px) scale(${stretchX}, ${stretchY})`;
}
return {
transform,
innerBoxShadow: `inset 0px 0px ${innerLightBlur}px ${innerLightSpread}px ${innerLightColor}`,
outerBoxShadow: `0 0 ${outerLightBlur}px ${outerLightSpread}px ${outerLightColor}`
};
}
// src/ui-elements/glass-card/index.tsx
var import_glass_card = require("./glass-card-NPANW5ET.css");
var import_jsx_runtime2 = require("react/jsx-runtime");
var GlassCard = (props) => {
var _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
const _a = __spreadValues(__spreadValues({}, glassDefaultProps), props), {
padding = "10px 20px",
children
} = _a, cardProps = __objRest(_a, [
"padding",
"children"
]);
const id = (0, import_react.useMemo)(() => {
var _a2;
return (_a2 = cardProps.id) != null ? _a2 : crypto.randomUUID();
}, [cardProps.id]);
const glassCardContainerRef = (0, import_react.useRef)(null);
const glassCardContentRef = (0, import_react.useRef)(null);
const [isHovered, setIsHovered] = (0, import_react.useState)(false);
const [style, setStyle] = (0, import_react.useState)({
transform: "none",
innerBoxShadow: `inset 0 0 ${cardProps.innerLightBlur}px ${cardProps.innerLightSpread}px ${cardProps.innerLightColor}`,
outerBoxShadow: `0 0 ${cardProps.outerLightBlur}px ${cardProps.outerLightSpread}px ${cardProps.outerLightColor}`
});
(0, import_react.useEffect)(() => {
const card = glassCardContainerRef.current;
if (!card) return;
const getTouchPoint = (e) => {
if ("touches" in e && e.touches.length > 0) {
return {
clientX: e.touches[0].clientX,
clientY: e.touches[0].clientY
};
}
return {
clientX: e.clientX,
clientY: e.clientY
};
};
const handleMove = (e) => {
const point = getTouchPoint(e);
const result = calculateHoverEffect(point, card, cardProps);
setStyle((prev) => __spreadValues(__spreadValues({}, prev), result));
setIsHovered(true);
};
const reset = () => {
setIsHovered(false);
setStyle({
transform: "none",
innerBoxShadow: `inset 0 0 ${cardProps.innerLightBlur}px ${cardProps.innerLightSpread}px ${cardProps.innerLightColor}`,
outerBoxShadow: `0 0 ${cardProps.outerLightBlur}px ${cardProps.outerLightSpread}px ${cardProps.outerLightColor}`
});
};
card.addEventListener("mousemove", handleMove);
card.addEventListener("mouseleave", reset);
card.addEventListener("touchstart", handleMove, { passive: true });
card.addEventListener("touchmove", handleMove, { passive: true });
card.addEventListener("touchend", reset);
card.addEventListener("touchcancel", reset);
return () => {
card.removeEventListener("mousemove", handleMove);
card.removeEventListener("mouseleave", reset);
card.removeEventListener("touchstart", handleMove);
card.removeEventListener("touchmove", handleMove);
card.removeEventListener("touchend", reset);
card.removeEventListener("touchcancel", reset);
};
}, [style]);
(0, import_react.useEffect)(() => {
setStyle((prev) => __spreadProps(__spreadValues({}, prev), {
innerBoxShadow: `inset 0 0 ${cardProps.innerLightBlur}px ${cardProps.innerLightSpread}px ${cardProps.innerLightColor}`,
outerBoxShadow: `0 0 ${cardProps.outerLightBlur}px ${cardProps.outerLightSpread}px ${cardProps.outerLightColor}`
}));
}, [
cardProps.innerLightBlur,
cardProps.innerLightSpread,
cardProps.innerLightColor,
cardProps.outerLightBlur,
cardProps.outerLightSpread,
cardProps.outerLightColor
]);
const handleOnMouseEnter = () => {
setIsHovered(true);
};
const handleOnMouseLeave = () => {
setIsHovered(false);
};
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
"div",
{
id: cardProps.id,
ref: glassCardContainerRef,
className: `glass-ui-container ${cardProps.className ? cardProps.className : ""}`,
onMouseEnter: handleOnMouseEnter,
onMouseLeave: handleOnMouseLeave,
onClick: cardProps.onClick,
style: {
color: cardProps.color,
width: (_b = cardProps.width) != null ? _b : "fit-content",
height: (_c = cardProps.height) != null ? _c : "fit-content",
borderRadius: cardProps.borderRadius,
transform: style.transform,
transition: isHovered ? "transform 80ms ease-out" : "transform 250ms cubic-bezier(0.3, 0.7, 0.4, 1.5)",
willChange: "transform",
zIndex: cardProps.zIndex
},
children: [
renderLayers(
id,
(_d = cardProps.blur) != null ? _d : 1,
(_e = cardProps.borderRadius) != null ? _e : 8,
(_f = cardProps.saturation) != null ? _f : 100,
(_g = cardProps.brightness) != null ? _g : 100,
(_h = cardProps.distortion) != null ? _h : 50,
(_i = cardProps.backgroundColor) != null ? _i : "white",
(_j = cardProps.backgroundOpacity) != null ? _j : 0,
style,
(_k = cardProps.innerLightOpacity) != null ? _k : 0.2,
(_l = cardProps.outerLightOpacity) != null ? _l : 0.2,
(_n = (_m = cardProps.borderColor) != null ? _m : cardProps.innerLightColor) != null ? _n : "white",
(_o = cardProps.borderSize) != null ? _o : 1,
(_p = cardProps.borderOpacity) != null ? _p : 1,
(_q = cardProps.chromaticAberration) != null ? _q : 0,
(_r = cardProps.avoidSvgCreation) != null ? _r : false
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"div",
{
ref: glassCardContentRef,
className: `glass-ui-card-content ${cardProps.contentCenter ? "content-center" : ""} ${cardProps.itemsCenter ? "items-center" : ""} ${cardProps.contentCenter || cardProps.itemsCenter ? "d-flex" : ""} ${cardProps.contentClassName ? cardProps.contentClassName : ""}`,
style: {
padding: padding != null ? padding : "",
borderRadius: cardProps.borderRadius
},
children
}
)
]
},
cardProps.key
) });
};
// src/ui-elements/glass-input/index.tsx
var import_react2 = require("react");
var import_glass_input = require("./glass-input-TRVHLVO4.css");
var import_jsx_runtime3 = require("react/jsx-runtime");
var GlassInput = (props) => {
var _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
const _a = __spreadValues(__spreadValues({}, glassDefaultProps), props), {
height = 40,
type = "text",
maxLength,
minLength,
placeholder = "Placeholder",
label,
labelColor = "white",
multiple = false,
required = false,
autofocus = false,
onChange,
inputRangeBlur = 1,
inputRangeDistortion = 10
} = _a, inputProps = __objRest(_a, [
"height",
"type",
"maxLength",
"minLength",
"placeholder",
"label",
"labelColor",
"multiple",
"required",
"autofocus",
"onChange",
"inputRangeBlur",
"inputRangeDistortion"
]);
const id = (0, import_react2.useMemo)(
() => {
var _a2;
return (_a2 = inputProps.id) != null ? _a2 : crypto.randomUUID();
},
[inputProps.id]
);
const glassInputContainerRef = (0, import_react2.useRef)(null);
const glassInputContentRef = (0, import_react2.useRef)(null);
const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
const [rangeValue, setRangeValue] = (0, import_react2.useState)(0);
const [style, setStyle] = (0, import_react2.useState)({
transform: "none",
innerBoxShadow: `inset 0 0 ${inputProps.innerLightBlur}px ${inputProps.innerLightSpread}px ${inputProps.innerLightColor}`,
outerBoxShadow: `0 0 ${inputProps.outerLightBlur}px ${inputProps.outerLightSpread}px ${inputProps.outerLightColor}`
});
(0, import_react2.useEffect)(() => {
setRangeValue(inputProps.value);
}, [inputProps.value]);
(0, import_react2.useEffect)(() => {
const card = glassInputContainerRef.current;
if (!card) return;
const getTouchPoint = (e) => {
if ("touches" in e && e.touches.length > 0) {
return {
clientX: e.touches[0].clientX,
clientY: e.touches[0].clientY
};
}
return {
clientX: e.clientX,
clientY: e.clientY
};
};
const handleMove = (e) => {
const point = getTouchPoint(e);
const result = calculateHoverEffect(point, card, inputProps);
setStyle((prev) => __spreadValues(__spreadValues({}, prev), result));
setIsHovered(true);
};
const reset = () => {
setIsHovered(false);
setStyle({
transform: "none",
innerBoxShadow: `inset 0 0 ${inputProps.innerLightBlur}px ${inputProps.innerLightSpread}px ${inputProps.innerLightColor}`,
outerBoxShadow: `0 0 ${inputProps.outerLightBlur}px ${inputProps.outerLightSpread}px ${inputProps.outerLightColor}`
});
};
card.addEventListener("mousemove", handleMove);
card.addEventListener("mouseleave", reset);
card.addEventListener("touchstart", handleMove, { passive: true });
card.addEventListener("touchmove", handleMove, { passive: true });
card.addEventListener("touchend", reset);
card.addEventListener("touchcancel", reset);
return () => {
card.removeEventListener("mousemove", handleMove);
card.removeEventListener("mouseleave", reset);
card.removeEventListener("touchstart", handleMove);
card.removeEventListener("touchmove", handleMove);
card.removeEventListener("touchend", reset);
card.removeEventListener("touchcancel", reset);
};
}, [style]);
(0, import_react2.useEffect)(() => {
setStyle((prev) => __spreadProps(__spreadValues({}, prev), {
innerBoxShadow: `inset 0 0 ${inputProps.innerLightBlur}px ${inputProps.innerLightSpread}px ${inputProps.innerLightColor}`,
outerBoxShadow: `0 0 ${inputProps.outerLightBlur}px ${inputProps.outerLightSpread}px ${inputProps.outerLightColor}`
}));
}, [
inputProps.innerLightBlur,
inputProps.innerLightSpread,
inputProps.innerLightColor,
inputProps.outerLightBlur,
inputProps.outerLightSpread,
inputProps.outerLightColor
]);
const handleOnMouseEnter = () => {
setIsHovered(true);
};
const handleOnMouseLeave = () => {
setIsHovered(false);
};
const renderInput = () => {
var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2;
if (type === "range") {
const trackRef = (0, import_react2.useRef)(null);
const [dragging, setDragging] = (0, import_react2.useState)(false);
const min = (_a2 = inputProps.min) != null ? _a2 : 0;
const max = (_b2 = inputProps.max) != null ? _b2 : 100;
const step = (_c2 = inputProps.step) != null ? _c2 : 1;
const percent = Math.ceil((rangeValue - min) / (max - min) * 100);
(0, import_react2.useEffect)(() => {
if (dragging) {
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
window.addEventListener("touchmove", handleTouchMove, {
passive: false
});
window.addEventListener("touchend", handleMouseUp);
} else {
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
window.removeEventListener("touchmove", handleTouchMove);
window.removeEventListener("touchend", handleMouseUp);
}
return () => {
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
window.removeEventListener("touchmove", handleTouchMove);
window.removeEventListener("touchend", handleMouseUp);
};
}, [dragging]);
const handleTouchStart = (e) => {
setDragging(true);
updatePosition(e.touches[0].clientX);
};
const handleTouchMove = (e) => {
e.preventDefault();
if (dragging) updatePosition(e.touches[0].clientX);
};
const handleMouseDown = (e) => {
setDragging(true);
updatePosition(e.clientX);
};
const handleMouseMove = (e) => {
if (dragging) updatePosition(e.clientX);
};
const handleMouseUp = () => setDragging(false);
const updatePosition = (clientX) => {
const track = trackRef.current;
if (!track) return;
const rect = track.getBoundingClientRect();
const x = Math.min(Math.max(clientX - rect.left - 10, 0), rect.width);
const percent2 = x / rect.width;
const clampedValue = min + percent2 * (max - min);
const steppedValue = Math.round(clampedValue / step) * step;
const newValue = Math.min(Math.max(steppedValue, min), max);
setRangeValue(newValue);
onChange == null ? void 0 : onChange({
target: { value: newValue, name: inputProps.name }
});
};
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
"div",
{
className: "glass-range-track",
ref: trackRef,
onMouseDown: handleMouseDown,
onTouchStart: handleTouchStart,
children: [
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"div",
{
className: "glass-range-fill",
style: {
width: `${percent}%`,
backgroundColor: (_e2 = (_d2 = inputProps.backgroundColor) != null ? _d2 : inputProps.borderColor) != null ? _e2 : "white",
opacity: dragging ? 0.7 : 1
}
}
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"div",
{
className: "glass-range-after-fill",
style: {
left: `calc(${percent > 96 ? 96 : percent}% + 30px)`,
width: `calc(${100 - percent}% - 30px)`
}
}
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"div",
{
className: "glass-range-thumb",
style: {
left: `calc(${percent > 96 ? 96 : percent}% + 17px)`,
transform: `translate(-50%, -50%) scale(${dragging ? 1.4 : 1})`,
borderRadius: dragging ? inputProps.borderRadius ? inputProps.borderRadius + 1 : 2 : inputProps.borderRadius,
filter: `url(#${id}-filter)`,
backdropFilter: `blur(${inputProps.blur}px) saturate(${inputProps.saturation}%)`,
WebkitBackdropFilter: `blur(${inputProps.blur}px) saturate(${inputProps.saturation}%)`
},
onMouseDown: handleMouseDown,
onTouchStart: handleTouchStart
}
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"div",
{
className: "glass-range-thumb glass-range-border",
style: {
left: `calc(${percent > 96 ? 96 : percent}% + 17px)`,
border: `${(_f2 = inputProps.borderSize) != null ? _f2 : 1}px solid ${(_g2 = inputProps.borderColor) != null ? _g2 : "white"}`,
transform: `translate(-50%, -50%) scale(${dragging ? 1.4 : 1})`,
borderRadius: dragging ? inputProps.borderRadius ? inputProps.borderRadius + 1 : 2 : inputProps.borderRadius
}
}
),
percent > 96 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"div",
{
className: "glass-range-thumb",
style: {
left: `calc(96% + 17px)`,
transform: `translate(-50%, -50%) scale(${dragging ? 1.4 : 1})`,
backgroundColor: (_j2 = (_i2 = (_h2 = inputProps.color) != null ? _h2 : inputProps.backgroundColor) != null ? _i2 : inputProps.borderColor) != null ? _j2 : "white",
borderRadius: dragging ? inputProps.borderRadius ? inputProps.borderRadius + 1 : 2 : inputProps.borderRadius
}
}
) : ""
]
}
);
} else {
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"input",
{
value: inputProps.value,
type,
name: inputProps.name,
placeholder,
required,
autoFocus: autofocus,
multiple,
maxLength,
minLength,
className: `glass-input ${inputProps.contentCenter ? "content-center" : ""}`,
onChange: (e) => onChange ? onChange(e) : {},
style: {
color: inputProps.color,
padding: inputProps.padding
}
}
),
type === "file" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"span",
{
style: {
color: inputProps.color
},
className: `file-type-placeholder ${inputProps.contentCenter ? "content-center" : ""} ${inputProps.itemsCenter ? "items-center" : ""} ${inputProps.contentCenter || inputProps.itemsCenter ? "d-flex" : ""} ${inputProps.contentClassName ? inputProps.contentClassName : ""}`,
children: placeholder
}
) : ""
] });
}
};
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
"div",
{
id: inputProps.id,
className: `glass-ui-input-container${inputProps.className ? ` ${inputProps.className}` : ""}`,
children: [
label && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "glass-ui-input-label", style: { color: labelColor }, children: label }),
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
"div",
{
ref: glassInputContainerRef,
className: "glass-ui-container",
onMouseEnter: handleOnMouseEnter,
onMouseLeave: handleOnMouseLeave,
style: {
color: inputProps.color,
width: inputProps.width,
height: type === "range" ? 30 : height,
borderRadius: inputProps.borderRadius,
transform: style.transform,
transition: isHovered ? "transform 80ms ease-out" : "transform 250ms cubic-bezier(0.3, 0.7, 0.4, 1.5)",
willChange: "transform",
zIndex: inputProps.zIndex
},
children: [
renderLayers(
id,
type === "range" ? inputRangeBlur != null ? inputRangeBlur : 1 : (_b = inputProps.blur) != null ? _b : 2,
(_c = inputProps.borderRadius) != null ? _c : 8,
(_d = inputProps.saturation) != null ? _d : 100,
(_e = inputProps.brightness) != null ? _e : 100,
type === "range" ? inputRangeDistortion != null ? inputRangeDistortion : 10 : (_f = inputProps.distortion) != null ? _f : 50,
(_g = inputProps.backgroundColor) != null ? _g : "white",
(_h = inputProps.backgroundOpacity) != null ? _h : 0,
style,
(_i = inputProps.innerLightOpacity) != null ? _i : 0.2,
(_j = inputProps.outerLightOpacity) != null ? _j : 0.2,
(_l = (_k = inputProps.borderColor) != null ? _k : inputProps.innerLightColor) != null ? _l : "white",
(_m = inputProps.borderSize) != null ? _m : 1,
(_n = inputProps.borderOpacity) != null ? _n : 1,
(_o = inputProps.chromaticAberration) != null ? _o : 0,
(_p = inputProps.avoidSvgCreation) != null ? _p : false,
type
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"div",
{
ref: glassInputContentRef,
className: "glass-ui-input-content",
style: {
display: type === "range" ? "flex" : "block",
alignItems: "center",
justifyContent: "center",
borderRadius: inputProps.borderRadius
},
children: renderInput()
}
)
]
}
)
]
},
inputProps.key
);
};
// src/ui-elements/glass-button/index.tsx
var import_react3 = require("react");
var import_glass_button = require("./glass-button-Z4JXODNC.css");
var import_jsx_runtime4 = require("react/jsx-runtime");
var GlassButton = (props) => {
var _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
const _a = __spreadValues(__spreadValues({}, glassDefaultProps), props), {
contentCenter = true,
itemsCenter = true,
children
} = _a, buttonProps = __objRest(_a, [
"contentCenter",
"itemsCenter",
"children"
]);
const id = (0, import_react3.useMemo)(
() => {
var _a2;
return (_a2 = buttonProps.id) != null ? _a2 : crypto.randomUUID();
},
[buttonProps.id]
);
const glassButtonContainerRef = (0, import_react3.useRef)(null);
const glassButtonContentRef = (0, import_react3.useRef)(null);
const [isHovered, setIsHovered] = (0, import_react3.useState)(false);
const [style, setStyle] = (0, import_react3.useState)({
transform: "none",
innerBoxShadow: `inset 0 0 ${buttonProps.innerLightBlur}px ${buttonProps.innerLightSpread}px ${buttonProps.innerLightColor}`,
outerBoxShadow: `0 0 ${buttonProps.outerLightBlur}px ${buttonProps.outerLightSpread}px ${buttonProps.outerLightColor}`
});
(0, import_react3.useEffect)(() => {
const card = glassButtonContainerRef.current;
if (!card) return;
const getTouchPoint = (e) => {
if ("touches" in e && e.touches.length > 0) {
return {
clientX: e.touches[0].clientX,
clientY: e.touches[0].clientY
};
}
return {
clientX: e.clientX,
clientY: e.clientY
};
};
const handleMove = (e) => {
const point = getTouchPoint(e);
const result = calculateHoverEffect(point, card, buttonProps);
setStyle((prev) => __spreadValues(__spreadValues({}, prev), result));
setIsHovered(true);
};
const reset = () => {
setIsHovered(false);
setStyle({
transform: "none",
innerBoxShadow: `inset 0 0 ${buttonProps.innerLightBlur}px ${buttonProps.innerLightSpread}px ${buttonProps.innerLightColor}`,
outerBoxShadow: `0 0 ${buttonProps.outerLightBlur}px ${buttonProps.outerLightSpread}px ${buttonProps.outerLightColor}`
});
};
card.addEventListener("mousemove", handleMove);
card.addEventListener("mouseleave", reset);
card.addEventListener("touchstart", handleMove, { passive: true });
card.addEventListener("touchmove", handleMove, { passive: true });
card.addEventListener("touchend", reset);
card.addEventListener("touchcancel", reset);
return () => {
card.removeEventListener("mousemove", handleMove);
card.removeEventListener("mouseleave", reset);
card.removeEventListener("touchstart", handleMove);
card.removeEventListener("touchmove", handleMove);
card.removeEventListener("touchend", reset);
card.removeEventListener("touchcancel", reset);
};
}, [style]);
(0, import_react3.useEffect)(() => {
setStyle((prev) => __spreadProps(__spreadValues({}, prev), {
innerBoxShadow: `inset 0 0 ${buttonProps.innerLightBlur}px ${buttonProps.innerLightSpread}px ${buttonProps.innerLightColor}`,
outerBoxShadow: `0 0 ${buttonProps.outerLightBlur}px ${buttonProps.outerLightSpread}px ${buttonProps.outerLightColor}`
}));
}, [
buttonProps.innerLightBlur,
buttonProps.innerLightSpread,
buttonProps.innerLightColor,
buttonProps.outerLightBlur,
buttonProps.outerLightSpread,
buttonProps.outerLightColor
]);
const handleOnMouseEnter = () => {
setIsHovered(true);
};
const handleOnMouseLeave = () => {
setIsHovered(false);
};
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
"div",
{
id: buttonProps.id,
ref: glassButtonContainerRef,
className: `glass-ui-container ${buttonProps.className ? buttonProps.className : ""}`,
onClick: buttonProps.onClick,
onMouseEnter: handleOnMouseEnter,
onMouseLeave: handleOnMouseLeave,
style: {
color: buttonProps.color,
width: (_b = buttonProps.width) != null ? _b : "100%",
height: buttonProps.height,
borderRadius: buttonProps.borderRadius,
transform: style.transform,
transition: isHovered ? "transform 80ms ease-out" : "transform 250ms cubic-bezier(0.3, 0.7, 0.4, 1.5)",
willChange: "transform",
zIndex: buttonProps.zIndex
},
children: [
renderLayers(
id,
(_c = buttonProps.blur) != null ? _c : 1,
(_d = buttonProps.borderRadius) != null ? _d : 8,
(_e = buttonProps.saturation) != null ? _e : 100,
(_f = buttonProps.brightness) != null ? _f : 100,
(_g = buttonProps.distortion) != null ? _g : 50,
(_h = buttonProps.backgroundColor) != null ? _h : "white",
(_i = buttonProps.backgroundOpacity) != null ? _i : 0,
style,
(_j = buttonProps.innerLightOpacity) != null ? _j : 0.2,
(_k = buttonProps.outerLightOpacity) != null ? _k : 0.2,
(_m = (_l = buttonProps.borderColor) != null ? _l : buttonProps.innerLightColor) != null ? _m : "white",
(_n = buttonProps.borderSize) != null ? _n : 1,
(_o = buttonProps.borderOpacity) != null ? _o : 1,
(_p = buttonProps.chromaticAberration) != null ? _p : 0,
(_q = buttonProps.avoidSvgCreation) != null ? _q : false
),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
"div",
{
ref: glassButtonContentRef,
className: `glass-ui-button-content ${contentCenter ? "content-center" : ""} ${itemsCenter ? "items-center" : ""} ${contentCenter || itemsCenter ? "d-flex" : ""} ${buttonProps.contentClassName ? buttonProps.contentClassName : ""}`,
style: {
padding: buttonProps.padding,
borderRadius: buttonProps.borderSize
},
children
}
)
]
},
buttonProps.key
) });
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
GlassButton,
GlassCard,
GlassInput
});