aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
141 lines (138 loc) • 5.18 kB
JavaScript
'use client';
import { jsxs, jsx } from 'react/jsx-runtime';
import { useState, useEffect, useMemo } from 'react';
import { cn } from '../../lib/utilsComprehensive.js';
import '../../primitives/GlassCore.js';
import '../../primitives/glass/GlassAdvanced.js';
import { OptimizedGlassCore } from '../../primitives/OptimizedGlassCore.js';
import '../../primitives/glass/OptimizedGlassAdvanced.js';
import '../../primitives/MotionNative.js';
import '../../primitives/motion/MotionFramer.js';
const statusAccent = {
active: "bg-emerald-400/90",
idle: "bg-amber-300/90",
offline: "bg-slate-500/80"
};
const DEFAULT_USERS = [{
id: "1",
name: "Nova",
presence: "active",
color: "#38bdf8"
}, {
id: "2",
name: "Orion",
presence: "idle",
color: "#f472b6"
}, {
id: "3",
name: "Lyra",
presence: "offline",
color: "#a855f7"
}];
function MultiUserGlassEditor({
users,
className,
header = "Collaborative Glass Editor",
lastUpdatedAt,
onContentChange,
value,
defaultValue,
readOnly,
textareaClassName,
...textareaProps
}) {
const normalizeValue = input => {
if (typeof input === "string") return input;
if (typeof input === "number") return String(input);
if (Array.isArray(input)) return input.join("\n");
return "";
};
const fallbackValue = normalizeValue(defaultValue);
const initialValue = normalizeValue(value) || fallbackValue;
const [internalValue, setInternalValue] = useState(initialValue);
useEffect(() => {
const updated = normalizeValue(value);
if (value !== undefined) {
setInternalValue(updated);
}
}, [value]);
const participants = useMemo(() => {
const activeUsers = users ?? DEFAULT_USERS;
return activeUsers.map((user, index) => ({
...user,
presence: user.presence ?? (index === 0 ? "active" : "idle"),
color: user.color ?? ["#38bdf8", "#f472b6", "#facc15"][index % 3]
}));
}, [users]);
const displayValue = value !== undefined ? normalizeValue(value) : internalValue;
const handleChange = event => {
if (!readOnly && typeof value !== "string") {
setInternalValue(event.target.value);
}
onContentChange?.(event.target.value);
textareaProps.onChange?.(event);
};
const formattedTimestamp = useMemo(() => {
if (!lastUpdatedAt) return "live";
const date = typeof lastUpdatedAt === "string" ? new Date(lastUpdatedAt) : lastUpdatedAt;
if (Number.isNaN(date.getTime())) return "live";
return date.toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit"
});
}, [lastUpdatedAt]);
return jsxs(OptimizedGlassCore, {
role: "region",
"aria-label": header,
className: cn("glass-radius-3xl glass-border glass-border-soft glass-p-6 space-y-6", "bg-gradient-to-br from-slate-950/80 via-slate-900/60 to-slate-900/40", className),
children: [jsxs("header", {
className: "glass-flex glass-flex-wrap glass-items-center glass-justify-between glass-gap-4",
children: [jsxs("div", {
children: [jsx("h2", {
className: 'glass-text-xl font-semibold text-primary',
children: header
}), jsx("p", {
className: 'glass-text-sm text-primary/70',
children: "Synced presence across team members with glass awareness."
})]
}), jsxs("span", {
className: 'glass-radius-full glass-border glass-border-white/10 glass-surface-subtle/10 glass-px-3 glass-py-1 glass-text-xs text-primary/70',
children: ["Updated ", formattedTimestamp]
})]
}), jsx("div", {
className: "glass-flex glass-flex-wrap glass-items-center glass-gap-3",
children: participants.map(user => jsxs("span", {
className: 'glass-flex glass-items-center glass-gap-2 glass-radius-full glass-border glass-border-white/10 glass-surface-subtle/5 glass-px-3 glass-py-1 glass-text-xs text-primary',
style: {
boxShadow: `0 0 25px -12px ${user.color}`
},
children: [jsx("span", {
className: 'glass-flex h-2.5 w-2.5 glass-radius-full',
style: {
backgroundColor: user.presence ? undefined : "#94a3b8"
},
children: user.presence && jsx("span", {
className: cn("h-2.5 w-2.5 rounded-full", statusAccent[user.presence])
})
}), jsx("span", {
className: 'font-medium',
style: {
color: user.color
},
children: user.name
}), jsx("span", {
className: 'text-primary/50',
children: user.presence ?? "active"
})]
}, user.id))
}), jsx("textarea", {
...textareaProps,
readOnly: readOnly,
value: displayValue,
onChange: handleChange,
className: cn("min-h-[200px] w-full resize-y rounded-3xl border border-white/10 bg-white/5 p-5 text-sm text-primary shadow-inner backdrop-blur transition", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-400", readOnly ? "opacity-70 cursor-not-allowed" : "hover:border-white/30", textareaClassName)
})]
});
}
export { MultiUserGlassEditor, MultiUserGlassEditor as default };
//# sourceMappingURL=MultiUserGlassEditor.js.map