UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

393 lines (390 loc) 16.6 kB
'use client'; import { jsx, jsxs } from 'react/jsx-runtime'; import { useState, useCallback } from 'react'; import { GlassCore } from '../../primitives/GlassCore.js'; import '../../primitives/glass/GlassAdvanced.js'; import '../../primitives/OptimizedGlassCore.js'; import '../../primitives/glass/OptimizedGlassAdvanced.js'; import '../../primitives/MotionNative.js'; import '../../primitives/motion/MotionFramer.js'; import { cn } from '../../lib/utilsComprehensive.js'; import { useDragDrop } from './GlassDragDropProvider.js'; const PropertyInput = ({ label, type, value, options, min, max, step, onChange }) => { const renderInput = () => { switch (type) { case "text": return jsx("input", { "data-glass-component": true, type: "text", value: value || "", onChange: e => onChange(e.target.value), className: 'glass-w-full glass-px-3 glass-py-2 glass-text-sm glass-border glass-border-subtle glass-radius-md focus:outline-none focus:ring-2 focus:ring-blue-500' }); case "number": return jsx("input", { type: "number", value: value || 0, min: min, max: max, step: step, onChange: e => onChange(Number(e.target.value)), className: 'glass-w-full glass-px-3 glass-py-2 glass-text-sm glass-border glass-border-subtle glass-radius-md focus:outline-none focus:ring-2 focus:ring-blue-500' }); case "range": return jsxs("div", { className: 'space-y-2', children: [jsx("input", { type: "range", value: value || 0, min: min || 0, max: max || 100, step: step || 1, onChange: e => onChange(Number(e.target.value)), className: "glass-w-full" }), jsx("div", { className: 'glass-text-xs glass-text-secondary text-center', children: value })] }); case "color": return jsxs("div", { className: "glass-flex glass-items-center glass-gap-2", children: [jsx("input", { type: "color", value: value || "var(--glass-black)", onChange: e => onChange(e.target.value), className: 'w-12 h-8 glass-border glass-border-subtle glass-radius cursor-pointer' }), jsx("input", { type: "text", value: value || "var(--glass-black)", onChange: e => onChange(e.target.value), className: 'glass-flex-1 glass-px-3 glass-py-2 glass-text-sm glass-border glass-border-subtle glass-radius-md focus:outline-none focus:ring-2 focus:ring-blue-500' })] }); case "boolean": return jsxs("label", { className: 'glass-flex glass-items-center cursor-pointer', children: [jsx("input", { type: "checkbox", checked: value || false, onChange: e => onChange(e.target.checked), className: 'mr-2 w-4 h-4 text-primary glass-border-subtle glass-radius focus:ring-blue-500' }), jsx("span", { className: "glass-text-sm glass-text-secondary", children: "Enabled" })] }); case "select": return jsx("select", { value: value || "", onChange: e => onChange(e.target.value), className: 'glass-w-full glass-px-3 glass-py-2 glass-text-sm glass-border glass-border-subtle glass-radius-md focus:outline-none focus:ring-2 focus:ring-blue-500', children: options?.map(option => jsx("option", { value: option, children: option }, option)) }); case "image": return jsxs("div", { className: 'space-y-2', children: [jsx("input", { type: "url", value: value || "", onChange: e => onChange(e.target.value), placeholder: "https://example.com/image.jpg", className: 'glass-w-full glass-px-3 glass-py-2 glass-text-sm glass-border glass-border-subtle glass-radius-md focus:outline-none focus:ring-2 focus:ring-blue-500' }), jsxs("div", { className: "glass-flex glass-gap-2", children: [jsx("button", { onClick: () => { const input = document.createElement("input"); input.type = "file"; input.accept = "image/*"; input.onchange = e => { const file = e.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = e => onChange(e.target?.result); reader.readAsDataURL(file); } }; input.click(); }, className: 'glass-px-3 glass-py-1.5 glass-text-xs glass-surface-subtle glass-text-secondary glass-radius hover:glass-surface-subtle transition-colors', children: "Upload" }), jsx("button", { onClick: () => onChange("https://via.placeholder.com/400x300"), className: 'glass-px-3 glass-py-1.5 glass-text-xs glass-surface-subtle glass-text-secondary glass-radius hover:glass-surface-subtle transition-colors', children: "Placeholder" })] }), value && jsx("div", { className: 'mt-2', children: jsx("img", { src: value, alt: "Preview", className: 'glass-w-full h-24 object-cover glass-radius glass-border', onError: e => { e.target.src = "https://via.placeholder.com/400x300?text=Invalid+Image"; } }) })] }); default: return jsxs("div", { className: 'glass-text-sm glass-text-secondary italic', children: ["Unsupported input type: ", type] }); } }; return jsxs("div", { className: 'space-y-2', children: [jsx("label", { className: 'block glass-text-sm font-medium glass-text-secondary', children: label }), renderInput()] }); }; const ActionButton = ({ onClick, icon, label, variant = "default" }) => jsxs("button", { onClick: onClick, className: cn("flex items-center gap-2 px-3 py-2 text-sm rounded-md transition-colors glass-focus glass-touch-target", variant === "default" ? "bg-gray-100 text-gray-700 hover:bg-gray-200" : "bg-red-50 text-red-700 hover:bg-red-100"), children: [jsx("span", { children: icon }), label] }); const GlassPropertyPanel = ({ className, collapsed = false, onToggleCollapse }) => { const { pageState, componentLibrary, getSelectedComponent, updateComponent, duplicateComponent, deleteComponent, copyComponent, pasteComponent } = useDragDrop(); const [activeSection, setActiveSection] = useState("properties"); const selectedComponent = getSelectedComponent(); const componentDefinition = selectedComponent ? componentLibrary.find(def => def.type === selectedComponent.type) : null; const handlePropertyChange = useCallback((prop, value) => { if (selectedComponent) { updateComponent(selectedComponent.id, { [prop]: value }); } }, [selectedComponent, updateComponent]); if (collapsed) { return jsx("div", { className: cn("w-12", className), children: jsx(GlassCore, { className: "glass-h-full glass-contrast-guard", children: jsx("button", { onClick: onToggleCollapse, className: 'glass-flex glass-items-center glass-justify-center glass-w-full h-12 glass-text-secondary hover:glass-text-secondary transition-colors glass-focus glass-touch-target glass-focus glass-touch-target glass-contrast-guard', title: "Expand Property Panel", children: jsx("div", { className: "glass-text-lg", children: "\u2699\uFE0F" }) }) }) }); } return jsx("div", { className: cn("w-80 h-full flex flex-col", className), children: jsxs(GlassCore, { className: "glass-h-full glass-flex glass-flex-col glass-contrast-guard", children: [jsxs("div", { className: "glass-flex glass-items-center glass-justify-between glass-p-4 glass-border-b glass-border-subtle", children: [jsx("h2", { className: 'glass-text-lg font-semibold glass-text-secondary', children: "Properties" }), jsx("button", { onClick: onToggleCollapse, className: 'glass-p-2 glass-text-secondary hover:glass-text-secondary transition-colors glass-focus glass-touch-target glass-focus glass-touch-target glass-contrast-guard', title: "Collapse Panel", children: "\u25B6" })] }), !selectedComponent ? (/* No Selection State */ jsx("div", { className: "glass-flex-1 glass-flex glass-items-center glass-justify-center glass-p-6", children: jsxs("div", { className: 'text-center', children: [jsx("div", { className: 'glass-text-4xl mb-4', children: "\uD83C\uDFAF" }), jsx("h3", { className: 'glass-text-lg font-medium glass-text-secondary mb-2', children: "No Component Selected" }), jsx("p", { className: "glass-text-secondary glass-text-sm", children: "Click on a component in the canvas to edit its properties." })] }) })) : jsxs("div", { className: 'glass-flex-1 glass-flex glass-flex-col overflow-hidden', children: [jsx("div", { className: "glass-p-4 glass-surface-subtle glass-border-b glass-border-subtle", children: jsxs("div", { className: "glass-flex glass-items-center glass-gap-3", children: [jsx("span", { className: "glass-text-2xl", children: componentDefinition?.icon || "📦" }), jsxs("div", { className: 'glass-flex-1 min-glass-w-0', children: [jsx("div", { className: 'glass-text-sm font-medium glass-text-secondary truncate', children: componentDefinition?.name || selectedComponent.type }), jsxs("div", { className: "glass-text-xs glass-text-secondary", children: ["ID: ", selectedComponent.id.split("_").pop()] })] })] }) }), jsx("div", { className: "glass-p-4 glass-border-b glass-border-subtle", children: jsxs("div", { className: "glass-grid glass-grid-cols-2 glass-gap-2", children: [jsx(ActionButton, { onClick: () => duplicateComponent(selectedComponent.id), icon: "\uD83D\uDCCB", label: "Duplicate" }), jsx(ActionButton, { onClick: () => copyComponent(selectedComponent.id), icon: "\uD83D\uDCC4", label: "Copy" }), jsx(ActionButton, { onClick: () => pasteComponent(selectedComponent.id), icon: "\uD83D\uDCC1", label: "Paste" }), jsx(ActionButton, { onClick: () => deleteComponent(selectedComponent.id), icon: "\uD83D\uDDD1\uFE0F", label: "Delete", variant: "danger" })] }) }), jsx("div", { className: "glass-flex glass-border-b glass-border-subtle", children: [{ key: "properties", label: "Properties", icon: "⚙️" }, { key: "styles", label: "Styles", icon: "🎨" }, { key: "advanced", label: "Advanced", icon: "🔧" }].map(section => jsxs("button", { onClick: () => setActiveSection(section.key), className: cn("flex-1 flex items-center justify-center gap-1 px-3 py-2 text-sm font-medium transition-colors glass-focus glass-touch-target", activeSection === section.key ? "text-blue-600 border-b-2 border-blue-600 bg-blue-50" : "text-gray-600 hover:text-gray-900"), children: [jsx("span", { className: "glass-text-xs", children: section.icon }), section.label] }, section.key)) }), jsx("div", { className: 'glass-flex-1 overflow-y-auto glass-p-4', children: componentDefinition?.editableProps ? jsxs("div", { className: 'space-y-4', children: [Object.entries(componentDefinition.editableProps).filter(([key, config]) => { // Filter properties based on active section if (activeSection === "styles") { return ["color", "backgroundColor", "fontSize", "fontWeight", "textAlign", "padding", "margin", "borderRadius", "border", "boxShadow"].includes(key); } else if (activeSection === "advanced") { return ["onClick", "href", "className", "id"].includes(key); } else { // Properties section - show main functional properties return !["color", "backgroundColor", "fontSize", "fontWeight", "textAlign", "padding", "margin", "borderRadius", "border", "boxShadow", "onClick", "href", "className", "id"].includes(key); } }).map(([key, config]) => jsx(PropertyInput, { label: config.label, type: config.type, value: selectedComponent.props[key], options: config.options, min: config.min, max: config.max, step: config.step, onChange: value => handlePropertyChange(key, value) }, key)), Object.entries(componentDefinition.editableProps).filter(([key]) => { if (activeSection === "styles") { return ["color", "backgroundColor", "fontSize", "fontWeight", "textAlign", "padding", "margin", "borderRadius", "border", "boxShadow"].includes(key); } else if (activeSection === "advanced") { return ["onClick", "href", "className", "id"].includes(key); } else { return !["color", "backgroundColor", "fontSize", "fontWeight", "textAlign", "padding", "margin", "borderRadius", "border", "boxShadow", "onClick", "href", "className", "id"].includes(key); } }).length === 0 && jsxs("div", { className: 'text-center glass-py-8 glass-text-secondary', children: [jsx("div", { className: 'glass-text-2xl mb-2', children: activeSection === "styles" ? "🎨" : activeSection === "advanced" ? "🔧" : "⚙️" }), jsxs("p", { className: "glass-text-sm", children: ["No ", activeSection, " available for this component"] })] })] }) : jsxs("div", { className: 'text-center glass-py-8 glass-text-secondary', children: [jsx("div", { className: 'glass-text-2xl mb-2', children: "\u26A0\uFE0F" }), jsx("p", { className: "glass-text-sm", children: "No editable properties found" })] }) }), jsx("div", { className: "glass-p-4 glass-surface-subtle glass-border-t glass-border-subtle", children: jsxs("div", { className: 'glass-text-xs glass-text-secondary space-y-1', children: [jsxs("div", { className: "glass-flex glass-justify-between", children: [jsx("span", { children: "Children:" }), jsx("span", { children: selectedComponent.children.length })] }), jsxs("div", { className: "glass-flex glass-justify-between", children: [jsx("span", { children: "Parent:" }), jsx("span", { children: selectedComponent.parent ? "Yes" : "Root" })] }), selectedComponent.locked && jsxs("div", { className: 'glass-flex glass-items-center glass-gap-1 text-primary', children: [jsx("span", { children: "\uD83D\uDD12" }), jsx("span", { children: "Locked" })] })] }) })] })] }) }); }; export { GlassPropertyPanel }; //# sourceMappingURL=GlassPropertyPanel.js.map