aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
393 lines (390 loc) • 16.6 kB
JavaScript
'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