aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
305 lines (302 loc) • 9.21 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { cn } from '../../lib/utilsComprehensive.js';
import { forwardRef, useRef, useState, useEffect, useCallback } from 'react';
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 defaultTools = ["bold", "italic", "underline", "heading", "quote", "list", "orderedList", "link", "code", "clear"];
const toolConfigs = {
bold: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M6 12h8a4 4 0 1 0 0-8H6v8Zm0 0h9a4 4 0 1 1 0 8H6v-8Z",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Bold",
command: "bold"
},
italic: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M19 4h-9M14 20H5M15 4 9 20",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Italic",
command: "italic"
},
underline: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M6 4v7a6 6 0 0 0 12 0V4M4 21h16",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Underline",
command: "underline"
},
strike: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M16 4H9a3 3 0 0 0-2.83 4M14 12a4 4 0 0 1 0 8H6m-2-8h16",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Strikethrough",
command: "strikeThrough"
},
heading: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M6 12h12M6 4v16M18 4v16",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Heading",
command: "formatBlock",
value: "h2"
},
quote: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1zM15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Quote",
command: "formatBlock",
value: "blockquote"
},
list: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Bullet List",
command: "insertUnorderedList"
},
orderedList: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M10 6h11M10 12h11M10 18h11M4 6h1v4M4 10h2M6 18H4c0-1 2-2 2-3s-1-1.5-2-1",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Numbered List",
command: "insertOrderedList"
},
link: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Link",
command: "createLink"
},
code: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "m16 18 6-6-6-6M8 6l-6 6 6 6",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Code",
command: "formatBlock",
value: "pre"
},
clear: {
icon: jsx("svg", {
viewBox: "0 0 24 24",
fill: "none",
className: 'w-4 h-4',
children: jsx("path", {
d: "M3 6h18M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
})
}),
label: "Clear Formatting",
command: "removeFormat"
}
};
const GlassRichTextEditor = /*#__PURE__*/forwardRef(({
value = "",
onChange,
placeholder = "Start typing...",
readOnly = false,
disabled = false,
showToolbar = true,
tools = defaultTools,
minHeight = "200px",
maxHeight = "400px",
elevation = "level2",
className,
...props
}, ref) => {
const editorRef = useRef(null);
const [isFocused, setIsFocused] = useState(false);
useEffect(() => {
if (editorRef.current && value !== editorRef.current.innerHTML) {
editorRef.current.innerHTML = value;
}
}, [value]);
const handleInput = useCallback(() => {
if (editorRef.current) {
onChange?.(editorRef.current.innerHTML);
}
}, [onChange]);
const executeCommand = useCallback((command, value) => {
if (readOnly || disabled) return;
if (command === "createLink") {
const url = prompt("Enter URL:");
if (url) {
document.execCommand(command, false, url);
}
} else if (value) {
document.execCommand(command, false, value);
} else {
document.execCommand(command, false);
}
editorRef.current?.focus();
handleInput();
}, [readOnly, disabled, handleInput]);
const handleKeyDown = useCallback(e => {
if ((e.metaKey || e.ctrlKey) && !e.shiftKey) {
switch (e.key) {
case "b":
e.preventDefault();
executeCommand("bold");
break;
case "i":
e.preventDefault();
executeCommand("italic");
break;
case "u":
e.preventDefault();
executeCommand("underline");
break;
}
}
}, [executeCommand]);
return jsxs(OptimizedGlassCore, {
"data-glass-component": true,
ref: ref,
elevation: elevation,
className: cn("overflow-hidden glass-radius-lg", className),
...props,
children: [showToolbar && !readOnly && jsx("div", {
className: "glass-flex glass-flex-wrap glass-items-center glass-gap-1 glass-p-2 glass-border-b glass-border-subtle",
children: tools.map(tool => {
const config = toolConfigs[tool];
if (!config) return null;
return jsx("button", {
type: "button",
onClick: () => executeCommand(config.command, config.value),
disabled: disabled,
className: cn("glass-p-2 glass-radius-md", "transition-all duration-200", "hover:bg-white/10 active:bg-white/20", "disabled:opacity-50 disabled:cursor-not-allowed", "glass-text-primary", "glass-focus glass-touch-target glass-contrast-guard"),
title: config.label,
"aria-label": config.label,
children: config.icon
}, tool);
})
}), jsxs("div", {
className: 'relative',
children: [jsx("div", {
ref: editorRef,
contentEditable: !readOnly && !disabled,
onInput: handleInput,
onFocus: () => setIsFocused(true),
onBlur: () => setIsFocused(false),
onKeyDown: handleKeyDown,
className: cn("glass-p-4 outline-none overflow-y-auto", "glass-text-primary prose prose-sm max-w-none", "focus:ring-2 focus:ring-blue-500/50", disabled && "opacity-50 cursor-not-allowed bg-white/5", readOnly && "cursor-default"),
style: {
minHeight,
maxHeight
},
role: "textbox",
"aria-multiline": "true",
"aria-label": "Rich text editor",
"aria-readonly": readOnly,
"aria-disabled": disabled
}), !value && !isFocused && jsx("div", {
className: 'absolute top-0 left-0 glass-p-4 glass-text-secondary pointer-events-none select-none',
"aria-hidden": "true",
children: placeholder
})]
})]
});
});
GlassRichTextEditor.displayName = "GlassRichTextEditor";
export { GlassRichTextEditor, GlassRichTextEditor as default };
//# sourceMappingURL=GlassRichTextEditor.js.map