@ichigo_san/graphing
Version:
A lightweight UML-style diagram editor built with React Flow and Tailwind CSS
975 lines (937 loc) โข 78.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _lucideReact = require("lucide-react");
var _GradientPicker = _interopRequireDefault(require("./GradientPicker"));
var _ShadowPicker = _interopRequireDefault(require("./ShadowPicker"));
var _gradientUtils = require("../utils/gradientUtils");
var _shadowUtils = require("../utils/shadowUtils");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
// src/components/editor/TailwindPropertyEditor.jsx
// Container preview component
const ContainerPreview = ({
width,
height,
padding,
borderRadius,
borderWidth,
headerHeight,
headerColor,
contentColor,
borderColor,
headerFontSize,
fontSize
}) => {
return /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Preview:"), /*#__PURE__*/_react.default.createElement("div", {
style: {
width: Math.min(width * 0.4, 120),
height: Math.min(height * 0.4, 80),
border: `${borderWidth}px solid ${borderColor}`,
borderRadius: `${borderRadius}px`,
overflow: 'hidden',
backgroundColor: contentColor,
margin: '0 auto'
}
}, /*#__PURE__*/_react.default.createElement("div", {
style: {
height: `${headerHeight * 0.4}px`,
backgroundColor: headerColor,
padding: `${padding * 0.4}px`,
fontSize: `${Math.max(headerFontSize * 0.4, 8)}px`,
fontWeight: 'bold',
display: 'flex',
alignItems: 'center',
borderBottom: headerHeight > 0 ? `1px solid ${borderColor}` : 'none'
}
}, "Sample Container"), /*#__PURE__*/_react.default.createElement("div", {
style: {
padding: `${padding * 0.4}px`,
fontSize: `${Math.max(fontSize * 0.4, 6)}px`,
color: '#666'
}
}, "Content area")));
};
// Simple preview for the different intersection styles
const IntersectionStylePreview = ({
style,
size = 40,
className = ''
}) => {
const cx = size / 2;
const cy = size / 2;
const line = size * 0.7;
const jump = 8;
switch (style) {
case 'arc':
return /*#__PURE__*/_react.default.createElement("svg", {
width: size,
height: size,
className: className,
viewBox: `0 0 ${size} ${size}`
}, /*#__PURE__*/_react.default.createElement("line", {
x1: cx - line / 2,
y1: cy,
x2: cx + line / 2,
y2: cy,
stroke: "#94a3b8",
strokeWidth: "2"
}), /*#__PURE__*/_react.default.createElement("path", {
d: `M ${cx} ${cy - line / 2} L ${cx} ${cy - jump / 2} Q ${cx + jump / 2} ${cy} ${cx} ${cy + jump / 2} L ${cx} ${cy + line / 2}`,
stroke: "#3b82f6",
strokeWidth: "2",
fill: "none"
}));
case 'sharp':
return /*#__PURE__*/_react.default.createElement("svg", {
width: size,
height: size,
className: className,
viewBox: `0 0 ${size} ${size}`
}, /*#__PURE__*/_react.default.createElement("line", {
x1: cx - line / 2,
y1: cy,
x2: cx + line / 2,
y2: cy,
stroke: "#94a3b8",
strokeWidth: "2"
}), /*#__PURE__*/_react.default.createElement("path", {
d: `M ${cx} ${cy - line / 2} L ${cx} ${cy - jump / 2} L ${cx + jump / 2} ${cy - jump / 2} L ${cx + jump / 2} ${cy + jump / 2} L ${cx} ${cy + jump / 2} L ${cx} ${cy + line / 2}`,
stroke: "#3b82f6",
strokeWidth: "2",
fill: "none"
}));
default:
return /*#__PURE__*/_react.default.createElement("svg", {
width: size,
height: size,
className: className,
viewBox: `0 0 ${size} ${size}`
}, /*#__PURE__*/_react.default.createElement("line", {
x1: cx - line / 2,
y1: cy,
x2: cx + line / 2,
y2: cy,
stroke: "#94a3b8",
strokeWidth: "2"
}), /*#__PURE__*/_react.default.createElement("line", {
x1: cx,
y1: cy - line / 2,
x2: cx,
y2: cy + line / 2,
stroke: "#3b82f6",
strokeWidth: "2"
}));
}
};
// Small selector embedded in this file to avoid extra components
const IntersectionStyleSelector = ({
value,
onChange,
disabled = false
}) => {
const options = [{
value: 'none',
label: 'None'
}, {
value: 'arc',
label: 'Arc'
}, {
value: 'sharp',
label: 'Sharp'
}];
const handleClick = val => {
if (disabled) return;
onChange({
target: {
value: val
}
});
};
return /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Intersections:"), /*#__PURE__*/_react.default.createElement("div", {
className: "flex gap-2"
}, options.map(opt => /*#__PURE__*/_react.default.createElement("button", {
type: "button",
key: opt.value,
onClick: () => handleClick(opt.value),
className: `p-1 border rounded ${value === opt.value ? 'border-indigo-500' : 'border-gray-200'} ${disabled ? 'opacity-50 cursor-not-allowed' : 'hover:border-indigo-400'}`
}, /*#__PURE__*/_react.default.createElement(IntersectionStylePreview, {
style: opt.value,
size: 32
})))));
};
const TailwindPropertyEditor = ({
selectedNode,
selectedEdge,
onElementPropertyChange,
minimized = false,
onToggleMinimized = () => {},
onClose = () => {}
}) => {
var _selectedNode$data6, _selectedNode$data7, _selectedNode$data8, _selectedNode$data9, _selectedNode$data1, _selectedNode$data10, _selectedNode$data12, _selectedNode$data13, _selectedNode$data15, _selectedNode$data16, _selectedNode$data17, _selectedNode$data18, _selectedNode$data19;
// Node properties
const [nodeLabel, setNodeLabel] = (0, _react.useState)('');
const [nodeIcon, setNodeIcon] = (0, _react.useState)('');
const [nodeTextColor, setNodeTextColor] = (0, _react.useState)('#000000');
const [nodeDescription, setNodeDescription] = (0, _react.useState)('');
const [nodeColor, setNodeColor] = (0, _react.useState)('#ffffff');
const [nodeBorderColor, setNodeBorderColor] = (0, _react.useState)('#dddddd');
const [nodeZIndex, setNodeZIndex] = (0, _react.useState)(1);
// Container-specific properties
const [containerWidth, setContainerWidth] = (0, _react.useState)(200);
const [containerHeight, setContainerHeight] = (0, _react.useState)(150);
const [containerPadding, setContainerPadding] = (0, _react.useState)(8);
const [containerBorderRadius, setContainerBorderRadius] = (0, _react.useState)(8);
const [containerBorderWidth, setContainerBorderWidth] = (0, _react.useState)(2);
const [containerHeaderHeight, setContainerHeaderHeight] = (0, _react.useState)(32);
const [containerHeaderColor, setContainerHeaderColor] = (0, _react.useState)('#f9f9f9');
const [containerContentColor, setContainerContentColor] = (0, _react.useState)('#ffffff');
const [containerFontSize, setContainerFontSize] = (0, _react.useState)(14);
const [containerHeaderFontSize, setContainerHeaderFontSize] = (0, _react.useState)(14);
// Edge properties
const [edgeLabel, setEdgeLabel] = (0, _react.useState)('');
const [edgeDescription, setEdgeDescription] = (0, _react.useState)('');
const [edgeType, setEdgeType] = (0, _react.useState)('smoothstep');
const [edgeAnimated, setEdgeAnimated] = (0, _react.useState)(false);
const [edgeStrokeWidth, setEdgeStrokeWidth] = (0, _react.useState)(2);
const [edgeStrokeColor, setEdgeStrokeColor] = (0, _react.useState)('#999999');
const [edgeStrokeDasharray, setEdgeStrokeDasharray] = (0, _react.useState)('');
const [edgeZIndex, setEdgeZIndex] = (0, _react.useState)(5);
const [edgeMarkerOption, setEdgeMarkerOption] = (0, _react.useState)('end');
const [edgeIntersection, setEdgeIntersection] = (0, _react.useState)('none');
// UI State
const [expandedSections, setExpandedSections] = (0, _react.useState)({
basic: true,
style: true,
layout: false,
container: false,
advanced: false
});
// Advanced styling state
const [useAdvancedStyling, setUseAdvancedStyling] = (0, _react.useState)(false);
// Store original colors before applying gradients
const [originalColors, setOriginalColors] = (0, _react.useState)({
background: null,
headerColor: null,
contentColor: null
});
// Shadow state
const [nodeShadow, setNodeShadow] = (0, _react.useState)('none');
const [originalShadow, setOriginalShadow] = (0, _react.useState)(null);
// Common emojis with categories
const emojiCategories = {
'Tech': ['๐ป', '๐ฅ๏ธ', '๐ฑ', 'โ', '๐ก', '๐ฐ๏ธ', '๐พ', '๐ฟ', '๐', '๐', '๐', '๐จ๏ธ', 'โจ๏ธ', '๐ฑ๏ธ', '๐ฝ'],
'Network': ['๐', '๐ถ', '๐ก', '๐', 'โ๏ธ', '๐', '๐', '๐', '๐', '๐๏ธ', '๐', '๐', '๐', '๐', '๐'],
'Data': ['๐', '๐', '๐๏ธ', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐'],
'Tools': ['๐ง', '๐จ', 'โ๏ธ', '๐ ๏ธ', '๐๏ธ', 'โ๏ธ', '๐งฐ', '๐ฉ', 'โ๏ธ', '๐งฒ', 'โ๏ธ', '๐งช', '๐งฌ', '๐ฌ', '๐ญ'],
'Shapes': ['๐ท', '๐ถ', '๐ต', '๐ข', '๐ก', '๐ ', '๐ด', '๐ฃ', 'โซ', 'โช', '๐ค', 'โญ', 'โจ', '๐ซ', '๐']
};
// Update local state when selection changes
(0, _react.useEffect)(() => {
if (selectedNode !== null && selectedNode !== void 0 && selectedNode.data) {
var _selectedNode$style, _selectedNode$style2;
setNodeLabel(selectedNode.data.label || '');
setNodeIcon(selectedNode.data.icon || '');
setNodeTextColor(selectedNode.data.textColor || '#000000');
setNodeDescription(selectedNode.data.description || '');
setNodeColor(selectedNode.data.color || '#ffffff');
setNodeBorderColor(selectedNode.data.borderColor || '#dddddd');
setNodeZIndex(selectedNode.zIndex || ((_selectedNode$style = selectedNode.style) === null || _selectedNode$style === void 0 ? void 0 : _selectedNode$style.zIndex) || 1);
// Container-specific properties
setContainerWidth(selectedNode.data.width || selectedNode.width || 200);
setContainerHeight(selectedNode.data.height || selectedNode.height || 150);
setContainerPadding(selectedNode.data.padding || 8);
setContainerBorderRadius(selectedNode.data.borderRadius || 8);
setContainerBorderWidth(selectedNode.data.borderWidth || 2);
setContainerHeaderHeight(selectedNode.data.headerHeight || 32);
setContainerHeaderColor(selectedNode.data.headerColor || '#f9f9f9');
setContainerContentColor(selectedNode.data.contentColor || '#ffffff');
setContainerFontSize(selectedNode.data.fontSize || 14);
setContainerHeaderFontSize(selectedNode.data.headerFontSize || 14);
// Initialize shadow state
setNodeShadow(selectedNode.data.boxShadow || ((_selectedNode$style2 = selectedNode.style) === null || _selectedNode$style2 === void 0 ? void 0 : _selectedNode$style2.boxShadow) || 'none');
// Auto-detect advanced styling mode
const hasAdvancedBackground = selectedNode.data.background && (selectedNode.data.background.includes('gradient') || typeof selectedNode.data.background === 'object');
const hasAdvancedHeaderBg = selectedNode.data.headerColor && selectedNode.data.headerColor.includes('gradient');
const hasAdvancedContentBg = selectedNode.data.contentColor && selectedNode.data.contentColor.includes('gradient');
const hasAdvancedShadow = selectedNode.data.boxShadow && selectedNode.data.boxShadow !== 'none';
setUseAdvancedStyling(hasAdvancedBackground || hasAdvancedHeaderBg || hasAdvancedContentBg || hasAdvancedShadow);
// Store original simple colors for reversion
setOriginalColors({
background: selectedNode.data.color || '#ffffff',
headerColor: selectedNode.data.headerColor && !selectedNode.data.headerColor.includes('gradient') ? selectedNode.data.headerColor : '#f9f9f9',
contentColor: selectedNode.data.contentColor && !selectedNode.data.contentColor.includes('gradient') ? selectedNode.data.contentColor : selectedNode.data.color || '#ffffff'
});
// Store original shadow for reversion
setOriginalShadow(!selectedNode.data.boxShadow || selectedNode.data.boxShadow === 'none' ? 'none' : null);
}
if (selectedEdge) {
var _selectedEdge$data, _selectedEdge$data2, _selectedEdge$style, _selectedEdge$style2, _selectedEdge$style3, _selectedEdge$style4, _selectedEdge$markerS, _selectedEdge$markerE, _selectedEdge$data3;
setEdgeLabel(((_selectedEdge$data = selectedEdge.data) === null || _selectedEdge$data === void 0 ? void 0 : _selectedEdge$data.label) || selectedEdge.label || '');
setEdgeDescription(((_selectedEdge$data2 = selectedEdge.data) === null || _selectedEdge$data2 === void 0 ? void 0 : _selectedEdge$data2.description) || '');
setEdgeType(selectedEdge.type || 'smoothstep');
setEdgeAnimated(selectedEdge.animated || false);
setEdgeStrokeWidth(((_selectedEdge$style = selectedEdge.style) === null || _selectedEdge$style === void 0 ? void 0 : _selectedEdge$style.strokeWidth) || 2);
setEdgeStrokeColor(((_selectedEdge$style2 = selectedEdge.style) === null || _selectedEdge$style2 === void 0 ? void 0 : _selectedEdge$style2.stroke) || '#999999');
setEdgeStrokeDasharray(((_selectedEdge$style3 = selectedEdge.style) === null || _selectedEdge$style3 === void 0 ? void 0 : _selectedEdge$style3.strokeDasharray) || '');
setEdgeZIndex(selectedEdge.zIndex || ((_selectedEdge$style4 = selectedEdge.style) === null || _selectedEdge$style4 === void 0 ? void 0 : _selectedEdge$style4.zIndex) || 5);
const start = ((_selectedEdge$markerS = selectedEdge.markerStart) === null || _selectedEdge$markerS === void 0 ? void 0 : _selectedEdge$markerS.type) !== undefined ? selectedEdge.markerStart.type : 'none';
const end = ((_selectedEdge$markerE = selectedEdge.markerEnd) === null || _selectedEdge$markerE === void 0 ? void 0 : _selectedEdge$markerE.type) !== undefined ? selectedEdge.markerEnd.type : 'none';
if (start !== 'none' && end !== 'none') setEdgeMarkerOption('both');else if (start !== 'none') setEdgeMarkerOption('start');else if (end !== 'none') setEdgeMarkerOption('end');else setEdgeMarkerOption('none');
setEdgeIntersection(((_selectedEdge$data3 = selectedEdge.data) === null || _selectedEdge$data3 === void 0 ? void 0 : _selectedEdge$data3.intersection) || 'none');
}
}, [selectedNode, selectedEdge]);
// Toggle section expansion
const toggleSection = (0, _react.useCallback)(section => {
setExpandedSections(prev => ({
...prev,
[section]: !prev[section]
}));
}, []);
// Node property handlers
const handleNodeLabelChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setNodeLabel(value);
onElementPropertyChange('node', 'label', value);
}, [onElementPropertyChange]);
const handleNodeIconChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setNodeIcon(value);
onElementPropertyChange('node', 'icon', value);
}, [onElementPropertyChange]);
const handleEmojiClick = (0, _react.useCallback)(emoji => {
setNodeIcon(emoji);
onElementPropertyChange('node', 'icon', emoji);
}, [onElementPropertyChange]);
// Quick style presets
const applyEdgePreset = (0, _react.useCallback)(preset => {
switch (preset) {
case 'solid':
setEdgeStrokeDasharray('');
setEdgeStrokeWidth(2);
onElementPropertyChange('edge', 'style.strokeDasharray', undefined);
onElementPropertyChange('edge', 'style.strokeWidth', 2);
break;
case 'dashed':
setEdgeStrokeDasharray('5,5');
onElementPropertyChange('edge', 'style.strokeDasharray', '5,5');
break;
case 'dotted':
setEdgeStrokeDasharray('2,2');
onElementPropertyChange('edge', 'style.strokeDasharray', '2,2');
break;
case 'thick':
setEdgeStrokeWidth(4);
onElementPropertyChange('edge', 'style.strokeWidth', 4);
break;
default:
break;
}
}, [onElementPropertyChange]);
// Node handlers
const handleNodeDescriptionChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setNodeDescription(value);
onElementPropertyChange('node', 'description', value);
}, [onElementPropertyChange]);
const handleNodeZIndexChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 0;
setNodeZIndex(value);
onElementPropertyChange('node', 'zIndex', value);
}, [onElementPropertyChange]);
const handleNodeColorChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setNodeColor(value);
onElementPropertyChange('node', 'color', value);
}, [onElementPropertyChange]);
const handleNodeBorderColorChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setNodeBorderColor(value);
onElementPropertyChange('node', 'borderColor', value);
}, [onElementPropertyChange]);
const handleNodeTextColorChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setNodeTextColor(value);
onElementPropertyChange('node', 'textColor', value);
}, [onElementPropertyChange]);
// Container property handlers
const handleContainerWidthChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 200;
setContainerWidth(value);
onElementPropertyChange('node', 'width', value);
}, [onElementPropertyChange]);
const handleContainerHeightChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 150;
setContainerHeight(value);
onElementPropertyChange('node', 'height', value);
}, [onElementPropertyChange]);
const handleContainerPaddingChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 0;
setContainerPadding(value);
onElementPropertyChange('node', 'padding', value);
}, [onElementPropertyChange]);
const handleContainerBorderRadiusChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 0;
setContainerBorderRadius(value);
onElementPropertyChange('node', 'borderRadius', value);
}, [onElementPropertyChange]);
const handleContainerBorderWidthChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 1;
setContainerBorderWidth(value);
onElementPropertyChange('node', 'borderWidth', value);
}, [onElementPropertyChange]);
const handleContainerHeaderHeightChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 20;
setContainerHeaderHeight(value);
onElementPropertyChange('node', 'headerHeight', value);
}, [onElementPropertyChange]);
const handleContainerHeaderColorChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setContainerHeaderColor(value);
onElementPropertyChange('node', 'headerColor', value);
}, [onElementPropertyChange]);
const handleContainerContentColorChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setContainerContentColor(value);
onElementPropertyChange('node', 'contentColor', value);
}, [onElementPropertyChange]);
const handleContainerFontSizeChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 12;
setContainerFontSize(value);
onElementPropertyChange('node', 'fontSize', value);
}, [onElementPropertyChange]);
const handleContainerHeaderFontSizeChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 12;
setContainerHeaderFontSize(value);
onElementPropertyChange('node', 'headerFontSize', value);
}, [onElementPropertyChange]);
// Advanced gradient handlers
const handleAdvancedBackgroundChange = (0, _react.useCallback)(gradientCss => {
var _selectedNode$data;
// Store original color before first gradient application
if (!(selectedNode !== null && selectedNode !== void 0 && (_selectedNode$data = selectedNode.data) !== null && _selectedNode$data !== void 0 && _selectedNode$data.background) && originalColors.background === null) {
setOriginalColors(prev => ({
...prev,
background: nodeColor
}));
}
// Store the CSS value - the components will handle rendering
onElementPropertyChange('node', 'background', gradientCss);
// Also update the simple color for backward compatibility
if (typeof gradientCss === 'string' && gradientCss.startsWith('#')) {
setNodeColor(gradientCss);
onElementPropertyChange('node', 'color', gradientCss);
}
}, [onElementPropertyChange, selectedNode, nodeColor, originalColors.background]);
const handleAdvancedHeaderBackgroundChange = (0, _react.useCallback)(gradientCss => {
var _selectedNode$data2;
// Store original header color before first gradient application
if (!(selectedNode !== null && selectedNode !== void 0 && (_selectedNode$data2 = selectedNode.data) !== null && _selectedNode$data2 !== void 0 && (_selectedNode$data2 = _selectedNode$data2.headerColor) !== null && _selectedNode$data2 !== void 0 && _selectedNode$data2.includes('gradient')) && originalColors.headerColor === null) {
setOriginalColors(prev => ({
...prev,
headerColor: containerHeaderColor
}));
}
setContainerHeaderColor(gradientCss);
onElementPropertyChange('node', 'headerColor', gradientCss);
}, [onElementPropertyChange, selectedNode, containerHeaderColor, originalColors.headerColor]);
const handleAdvancedContentBackgroundChange = (0, _react.useCallback)(gradientCss => {
var _selectedNode$data3;
// Store original content color before first gradient application
if (!(selectedNode !== null && selectedNode !== void 0 && (_selectedNode$data3 = selectedNode.data) !== null && _selectedNode$data3 !== void 0 && (_selectedNode$data3 = _selectedNode$data3.contentColor) !== null && _selectedNode$data3 !== void 0 && _selectedNode$data3.includes('gradient')) && originalColors.contentColor === null) {
setOriginalColors(prev => ({
...prev,
contentColor: containerContentColor
}));
}
setContainerContentColor(gradientCss);
onElementPropertyChange('node', 'contentColor', gradientCss);
}, [onElementPropertyChange, selectedNode, containerContentColor, originalColors.contentColor]);
// Shadow handlers
const handleShadowChange = (0, _react.useCallback)(shadowCss => {
var _selectedNode$data4, _selectedNode$data5;
// Store original shadow before first shadow application
if ((!(selectedNode !== null && selectedNode !== void 0 && (_selectedNode$data4 = selectedNode.data) !== null && _selectedNode$data4 !== void 0 && _selectedNode$data4.boxShadow) || (selectedNode === null || selectedNode === void 0 || (_selectedNode$data5 = selectedNode.data) === null || _selectedNode$data5 === void 0 ? void 0 : _selectedNode$data5.boxShadow) === 'none') && originalShadow === null) {
setOriginalShadow('none');
}
setNodeShadow(shadowCss);
onElementPropertyChange('node', 'boxShadow', shadowCss);
}, [onElementPropertyChange, selectedNode, originalShadow]);
// Extract simple color from gradient or advanced background
const extractSimpleColor = (0, _react.useCallback)((background, fallback = '#ffffff') => {
if (!background) return fallback;
// If it's already a simple hex color, return it
if (typeof background === 'string' && background.startsWith('#')) {
return background;
}
// If it's a gradient string, try to extract the first color
if (typeof background === 'string' && background.includes('gradient')) {
const colorMatch = background.match(/#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}|rgba?\([^)]+\)/);
if (colorMatch) {
return colorMatch[0];
}
}
return fallback;
}, []);
// Handle advanced styling toggle
const handleAdvancedStylingToggle = (0, _react.useCallback)(enabled => {
setUseAdvancedStyling(enabled);
if (!enabled) {
// Revert to original colors when advanced styling is disabled
// Revert main background to original color
const originalBg = originalColors.background || nodeColor;
setNodeColor(originalBg);
onElementPropertyChange('node', 'color', originalBg);
// Clear any advanced background properties
onElementPropertyChange('node', 'background', undefined);
// For containers, also revert header/content backgrounds
if ((selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.type) === 'container') {
const originalHeaderColor = originalColors.headerColor || '#f9f9f9';
const originalContentColor = originalColors.contentColor || originalColors.background || '#ffffff';
setContainerHeaderColor(originalHeaderColor);
setContainerContentColor(originalContentColor);
onElementPropertyChange('node', 'headerColor', originalHeaderColor);
onElementPropertyChange('node', 'contentColor', originalContentColor);
}
// Revert shadow to original state
const originalShadowValue = originalShadow || 'none';
setNodeShadow(originalShadowValue);
onElementPropertyChange('node', 'boxShadow', originalShadowValue);
// Reset stored values for next time
setOriginalColors({
background: null,
headerColor: null,
contentColor: null
});
setOriginalShadow(null);
}
}, [onElementPropertyChange, selectedNode, nodeColor, originalColors, originalShadow]);
// Edge handlers
const handleEdgeLabel = (0, _react.useCallback)(e => {
const value = e.target.value;
setEdgeLabel(value);
onElementPropertyChange('edge', 'label', value);
}, [onElementPropertyChange]);
const handleEdgeDescriptionChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setEdgeDescription(value);
onElementPropertyChange('edge', 'description', value);
}, [onElementPropertyChange]);
const handleEdgeZIndexChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 0;
setEdgeZIndex(value);
onElementPropertyChange('edge', 'zIndex', value);
}, [onElementPropertyChange]);
const handleEdgeTypeChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setEdgeType(value);
onElementPropertyChange('edge', 'type', value);
}, [onElementPropertyChange]);
const handleEdgeStrokeColorChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setEdgeStrokeColor(value);
onElementPropertyChange('edge', 'style.stroke', value);
}, [onElementPropertyChange]);
const handleEdgeStrokeWidthChange = (0, _react.useCallback)(e => {
const value = parseInt(e.target.value, 10) || 1;
setEdgeStrokeWidth(value);
onElementPropertyChange('edge', 'style.strokeWidth', value);
}, [onElementPropertyChange]);
const handleEdgeStrokeDasharrayChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setEdgeStrokeDasharray(value);
onElementPropertyChange('edge', 'style.strokeDasharray', value);
}, [onElementPropertyChange]);
const handleEdgeAnimatedChange = (0, _react.useCallback)(e => {
const checked = e.target.checked;
setEdgeAnimated(checked);
onElementPropertyChange('edge', 'animated', checked);
}, [onElementPropertyChange]);
const handleEdgeMarkerChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setEdgeMarkerOption(value);
switch (value) {
case 'both':
onElementPropertyChange('edge', 'markerStart', {
type: 'arrow'
});
onElementPropertyChange('edge', 'markerEnd', {
type: 'arrow'
});
break;
case 'start':
onElementPropertyChange('edge', 'markerStart', {
type: 'arrow'
});
onElementPropertyChange('edge', 'markerEnd', undefined);
break;
case 'end':
onElementPropertyChange('edge', 'markerStart', undefined);
onElementPropertyChange('edge', 'markerEnd', {
type: 'arrow'
});
break;
default:
onElementPropertyChange('edge', 'markerStart', undefined);
onElementPropertyChange('edge', 'markerEnd', undefined);
break;
}
}, [onElementPropertyChange]);
// ๐ UPDATED: This handler now works with the new component
const handleEdgeIntersectionChange = (0, _react.useCallback)(e => {
const value = e.target.value;
setEdgeIntersection(value);
onElementPropertyChange('edge', 'intersection', value);
}, [onElementPropertyChange]);
// Container preset functions
const applyContainerPreset = (0, _react.useCallback)(preset => {
switch (preset) {
case 'small':
setContainerWidth(150);
setContainerHeight(100);
onElementPropertyChange('node', 'width', 150);
onElementPropertyChange('node', 'height', 100);
break;
case 'medium':
setContainerWidth(200);
setContainerHeight(150);
onElementPropertyChange('node', 'width', 200);
onElementPropertyChange('node', 'height', 150);
break;
case 'large':
setContainerWidth(300);
setContainerHeight(200);
onElementPropertyChange('node', 'width', 300);
onElementPropertyChange('node', 'height', 200);
break;
case 'wide':
setContainerWidth(400);
setContainerHeight(150);
onElementPropertyChange('node', 'width', 400);
onElementPropertyChange('node', 'height', 150);
break;
case 'tall':
setContainerWidth(200);
setContainerHeight(300);
onElementPropertyChange('node', 'width', 200);
onElementPropertyChange('node', 'height', 300);
break;
default:
break;
}
}, [onElementPropertyChange]);
if (!selectedNode && !selectedEdge) {
return /*#__PURE__*/_react.default.createElement("div", {
className: `w-72 max-w-[90vw] bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-100 rounded-lg shadow-lg ${minimized ? 'overflow-hidden' : 'h-full overflow-y-auto'}`
}, /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center justify-between py-3 px-4 bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-100 font-semibold rounded-t-lg"
}, /*#__PURE__*/_react.default.createElement("span", null, "Properties"), /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center space-x-1"
}, /*#__PURE__*/_react.default.createElement("button", {
className: "p-1 hover:bg-white/10 rounded",
onClick: onToggleMinimized,
title: minimized ? 'Expand' : 'Minimize'
}, minimized ? /*#__PURE__*/_react.default.createElement(_lucideReact.ChevronUp, {
size: 14
}) : /*#__PURE__*/_react.default.createElement(_lucideReact.ChevronDown, {
size: 14
})), /*#__PURE__*/_react.default.createElement("button", {
className: "p-1 hover:bg-white/10 rounded",
onClick: onClose,
title: "Close"
}, /*#__PURE__*/_react.default.createElement(_lucideReact.X, {
size: 14
})))), !minimized && /*#__PURE__*/_react.default.createElement("div", {
className: "p-4"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "text-center text-gray-500 dark:text-gray-400 py-6"
}, /*#__PURE__*/_react.default.createElement("p", null, "Select an element to edit its properties"), /*#__PURE__*/_react.default.createElement("div", {
className: "mt-4 text-left text-sm bg-gray-50 dark:bg-gray-700 p-3 rounded-lg"
}, /*#__PURE__*/_react.default.createElement("strong", null, "Tips:"), /*#__PURE__*/_react.default.createElement("ul", {
className: "mt-2 pl-5 list-disc"
}, /*#__PURE__*/_react.default.createElement("li", {
className: "mb-1"
}, "Click nodes or edges to select them"), /*#__PURE__*/_react.default.createElement("li", {
className: "mb-1"
}, "Use Ctrl+C/V to copy/paste"), /*#__PURE__*/_react.default.createElement("li", {
className: "mb-1"
}, "Use Delete key to remove elements"), /*#__PURE__*/_react.default.createElement("li", {
className: "mb-1"
}, "Double-click to edit labels inline"))))));
}
return /*#__PURE__*/_react.default.createElement("div", {
className: `w-72 max-w-[90vw] bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-100 rounded-lg shadow-lg ${minimized ? 'overflow-hidden' : 'h-full overflow-y-auto'}`
}, /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center justify-between py-3 px-4 bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-100 font-semibold rounded-t-lg"
}, /*#__PURE__*/_react.default.createElement("span", null, selectedNode ? `${selectedNode.type || 'Node'} Properties` : 'Edge Properties'), /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center space-x-1"
}, /*#__PURE__*/_react.default.createElement("button", {
className: "p-1 hover:bg-white/10 rounded",
onClick: onToggleMinimized,
title: minimized ? 'Expand' : 'Minimize'
}, minimized ? /*#__PURE__*/_react.default.createElement(_lucideReact.ChevronUp, {
size: 14
}) : /*#__PURE__*/_react.default.createElement(_lucideReact.ChevronDown, {
size: 14
})), /*#__PURE__*/_react.default.createElement("button", {
className: "p-1 hover:bg-white/10 rounded",
onClick: onClose,
title: "Close"
}, /*#__PURE__*/_react.default.createElement(_lucideReact.X, {
size: 14
})))), !minimized && /*#__PURE__*/_react.default.createElement("div", {
className: "p-4"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center px-4 py-3 bg-gray-50 dark:bg-gray-800 cursor-pointer",
onClick: () => toggleSection('basic')
}, /*#__PURE__*/_react.default.createElement(_lucideReact.ChevronRight, {
className: `mr-2 text-gray-500 transition-transform ${expandedSections.basic ? 'rotate-90' : ''}`,
size: 16
}), /*#__PURE__*/_react.default.createElement("span", {
className: "font-medium text-gray-700 dark:text-gray-200"
}, "Basic Properties")), expandedSections.basic && /*#__PURE__*/_react.default.createElement("div", {
className: "p-4"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Name/Label:"), /*#__PURE__*/_react.default.createElement("input", {
type: "text",
value: selectedNode ? nodeLabel : edgeLabel,
onChange: selectedNode ? handleNodeLabelChange : handleEdgeLabel,
placeholder: selectedNode ? "Enter node name" : "Enter edge label",
className: "w-full px-3 py-2 border-2 border-gray-200 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
})), /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Description:"), /*#__PURE__*/_react.default.createElement("textarea", {
value: selectedNode ? nodeDescription : edgeDescription,
onChange: selectedNode ? handleNodeDescriptionChange : handleEdgeDescriptionChange,
placeholder: "Enter description",
rows: 3,
className: "w-full px-3 py-2 border-2 border-gray-200 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent resize-y"
})), /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Layer (Z-Index):"), /*#__PURE__*/_react.default.createElement("div", {
className: "flex flex-col"
}, /*#__PURE__*/_react.default.createElement("input", {
type: "number",
value: selectedNode ? nodeZIndex : edgeZIndex,
onChange: selectedNode ? handleNodeZIndexChange : handleEdgeZIndexChange,
min: "0",
max: "1000",
className: "w-24 px-3 py-2 border-2 border-gray-200 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
}), /*#__PURE__*/_react.default.createElement("span", {
className: "mt-1 text-xs text-gray-500 dark:text-gray-400"
}, "Higher numbers appear on top"))), selectedNode && /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Icon:"), /*#__PURE__*/_react.default.createElement("input", {
type: "text",
value: nodeIcon,
onChange: handleNodeIconChange,
placeholder: "Enter emoji or icon",
className: "w-full px-3 py-2 border-2 border-gray-200 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
})), selectedEdge && /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Connection Type:"), /*#__PURE__*/_react.default.createElement("select", {
value: edgeType,
onChange: handleEdgeTypeChange,
className: "w-full px-3 py-2 border-2 border-gray-200 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
}, /*#__PURE__*/_react.default.createElement("option", {
value: "adjustable"
}, "Adjustable"), /*#__PURE__*/_react.default.createElement("option", {
value: "default"
}, "Straight"), /*#__PURE__*/_react.default.createElement("option", {
value: "step"
}, "Step"), /*#__PURE__*/_react.default.createElement("option", {
value: "smoothstep"
}, "Smooth Step"), /*#__PURE__*/_react.default.createElement("option", {
value: "straight"
}, "Direct"))), selectedEdge && /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Arrowheads:"), /*#__PURE__*/_react.default.createElement("select", {
value: edgeMarkerOption,
onChange: handleEdgeMarkerChange,
className: "w-full px-3 py-2 border-2 border-gray-200 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
}, /*#__PURE__*/_react.default.createElement("option", {
value: "end"
}, "Pointing to Target"), /*#__PURE__*/_react.default.createElement("option", {
value: "start"
}, "Pointing from Target"), /*#__PURE__*/_react.default.createElement("option", {
value: "both"
}, "Both Ends"), /*#__PURE__*/_react.default.createElement("option", {
value: "none"
}, "None"))), selectedEdge && /*#__PURE__*/_react.default.createElement(IntersectionStyleSelector, {
value: edgeIntersection,
onChange: handleEdgeIntersectionChange
}))), /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center px-4 py-3 bg-gray-50 dark:bg-gray-800 cursor-pointer",
onClick: () => toggleSection('style')
}, /*#__PURE__*/_react.default.createElement(_lucideReact.ChevronRight, {
className: `mr-2 text-gray-500 transition-transform ${expandedSections.style ? 'rotate-90' : ''}`,
size: 16
}), /*#__PURE__*/_react.default.createElement("span", {
className: "font-medium text-gray-700 dark:text-gray-200"
}, "Style Properties")), expandedSections.style && /*#__PURE__*/_react.default.createElement("div", {
className: "p-4"
}, selectedNode && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "flex items-center gap-2 cursor-pointer"
}, /*#__PURE__*/_react.default.createElement("input", {
type: "checkbox",
checked: useAdvancedStyling,
onChange: e => handleAdvancedStylingToggle(e.target.checked),
className: "rounded"
}), /*#__PURE__*/_react.default.createElement("div", {
className: "flex flex-col"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Advanced Styling (Gradients & Effects)"), useAdvancedStyling && /*#__PURE__*/_react.default.createElement("span", {
className: "text-xs text-indigo-600 dark:text-indigo-400"
}, "Gradients active - toggle off to revert to simple colors")))), useAdvancedStyling && /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Style Presets:"), /*#__PURE__*/_react.default.createElement("div", {
className: "grid grid-cols-2 gap-2"
}, /*#__PURE__*/_react.default.createElement("button", {
onClick: () => {
handleAdvancedBackgroundChange('linear-gradient(135deg, #667eea 0%, #764ba2 100%)');
handleShadowChange('0 4px 8px rgba(0, 0, 0, 0.12)');
onElementPropertyChange('node', 'borderRadius', 12);
onElementPropertyChange('node', 'opacity', 0.95);
},
className: "p-3 bg-gradient-to-br from-indigo-400 to-purple-500 text-white text-xs font-medium rounded shadow hover:shadow-md transition-all"
}, "Elegant"), /*#__PURE__*/_react.default.createElement("button", {
onClick: () => {
handleAdvancedBackgroundChange('linear-gradient(to right, #00c6ff 0%, #0072ff 100%)');
handleShadowChange('0 8px 16px rgba(0, 114, 255, 0.2)');
onElementPropertyChange('node', 'borderWidth', 0);
onElementPropertyChange('node', 'borderRadius', 16);
},
className: "p-3 bg-gradient-to-r from-cyan-400 to-blue-500 text-white text-xs font-medium rounded shadow hover:shadow-md transition-all"
}, "Modern"), /*#__PURE__*/_react.default.createElement("button", {
onClick: () => {
handleAdvancedBackgroundChange('linear-gradient(to bottom right, #ffecd2 0%, #fcb69f 100%)');
handleShadowChange('0 2px 4px rgba(0, 0, 0, 0.08)');
onElementPropertyChange('node', 'borderWidth', 1);
onElementPropertyChange('node', 'borderColor', '#f0f0f0');
},
className: "p-3 bg-gradient-to-br from-orange-200 to-pink-200 text-gray-700 text-xs font-medium rounded shadow hover:shadow-md transition-all"
}, "Soft"), /*#__PURE__*/_react.default.createElement("button", {
onClick: () => {
handleAdvancedBackgroundChange('linear-gradient(45deg, #ff6b6b 0%, #ee5a24 100%)');
handleShadowChange('0 6px 12px rgba(238, 90, 36, 0.3)');
onElementPropertyChange('node', 'borderWidth', 3);
onElementPropertyChange('node', 'borderColor', '#c44569');
onElementPropertyChange('node', 'scale', 1.05);
},
className: "p-3 bg-gradient-to-r from-red-400 to-red-600 text-white text-xs font-medium rounded shadow hover:shadow-md transition-all"
}, "Bold"), /*#__PURE__*/_react.default.createElement("button", {
onClick: () => {
handleAdvancedBackgroundChange('rgba(255, 255, 255, 0.2)');
handleShadowChange('0 8px 32px rgba(31, 38, 135, 0.37)');
onElementPropertyChange('node', 'borderWidth', 1);
onElementPropertyChange('node', 'borderColor', 'rgba(255, 255, 255, 0.18)');
onElementPropertyChange('node', 'borderRadius', 10);
onElementPropertyChange('node', 'opacity', 0.9);
},
className: "p-3 bg-white bg-opacity-20 backdrop-blur-sm border border-white border-opacity-20 text-gray-700 text-xs font-medium rounded shadow hover:shadow-md transition-all"
}, "Glass"), /*#__PURE__*/_react.default.createElement("button", {
onClick: () => {
handleAdvancedBackgroundChange('linear-gradient(135deg, #2c3e50 0%, #34495e 100%)');
handleShadowChange('0 4px 8px rgba(0, 0, 0, 0.3)');
onElementPropertyChange('node', 'borderWidth', 1);
onElementPropertyChange('node', 'borderColor', '#4a5568');
onElementPropertyChange('node', 'textColor', '#ffffff');
},
className: "p-3 bg-gradient-to-br from-gray-700 to-gray-800 text-white text-xs font-medium rounded shadow hover:shadow-md transition-all"
}, "Dark")), /*#__PURE__*/_react.default.createElement("button", {
onClick: () => {
// Reset to defaults
handleAdvancedBackgroundChange(originalColors.background || '#ffffff');
handleShadowChange('none');
onElementPropertyChange('node', 'borderWidth', 2);
onElementPropertyChange('node', 'borderColor', '#dddddd');
onElementPropertyChange('node', 'borderRadius', 8);
onElementPropertyChange('node', 'opacity', 1);
onElementPropertyChange('node', 'scale', 1);
onElementPropertyChange('node', 'rotation', 0);
onElementPropertyChange('node', 'textColor', '#000000');
},
className: "w-full mt-2 px-3 py-2 text-sm bg-gray-200 dark:bg-gray-600 text-gray-700 dark:text-gray-300 rounded hover:bg-gray-300 dark:hover:bg-gray-500 transition-colors"
}, "Reset to Default")), useAdvancedStyling ? /*#__PURE__*/_react.default.createElement(_GradientPicker.default, {
label: "Background",
value: ((_selectedNode$data6 = selectedNode.data) === null || _selectedNode$data6 === void 0 ? void 0 : _selectedNode$data6.background) || nodeColor,
onChange: handleAdvancedBackgroundChange
}) : /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Background Color:"), /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center gap-2"
}, /*#__PURE__*/_react.default.createElement("input", {
type: "color",
value: nodeColor,
onChange: handleNodeColorChange,
className: "w-12 h-10 p-0 border-2 border-gray-200 dark:border-gray-600 rounded cursor-pointer"
}), /*#__PURE__*/_react.default.createElement("input", {
type: "text",
value: nodeColor,
onChange: handleNodeColorChange,
placeholder: "#ffffff",
className: "flex-1 px-3 py-2 border-2 border-gray-200 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent font-mono"
}))), useAdvancedStyling && /*#__PURE__*/_react.default.createElement(_ShadowPicker.default, {
label: "Shadow Effects",
value: ((_selectedNode$data7 = selectedNode.data) === null || _selectedNode$data7 === void 0 ? void 0 : _selectedNode$data7.boxShadow) || nodeShadow,
onChange: handleShadowChange
}), useAdvancedStyling && /*#__PURE__*/_react.default.createElement("div", {
className: "mb-4"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300"
}, "Opacity:"), /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center gap-3"
}, /*#__PURE__*/_react.default.createElement("input", {
type: "range",
min: "0",
max: "100",
value: Math.round((((_selectedNode$data8 = selectedNode.data) === null || _selectedNode$data8 === void 0 ? void 0 : _selectedNode$data8.opacity) ?? 1) * 100),
onChange: e => onElementPropertyChange('node', 'opacity', parseFloat(e.target.value) / 100),
className: "flex-1 h-2 bg-gray-300 rounded-full appearance-none"
}), /*#__PURE__*/_react.default.createElement("span", {
className: "px-2 py-1 bg-gray-100 dark:bg-gray-700 text-sm font-medium text-gray-700 dark:text-gray-300 rounded min-w-[50px] text-center"
}, Math.round((((_selectedNode$data9 = selectedNode.data) === null || _selectedNode$data9 === void 0 ? void 0 : _selectedNode$data9.opacity) ?? 1) * 100), "%")), /*#__PURE__*/_react.default.createElement("div", {
className: "flex gap-1 mt-2"
}, [0.25, 0.5, 0.75, 1].map(opacity => {
var _selectedNode$data0;
return /*#__PURE__*/_react.default.createElement("button", {
key: opacity,
onClick: () => onElementPropertyChange('node', 'opacity', opacity),
className: `px-2 py-1 text-xs rounded transition-colors ${Math.abs((((_selectedNode$data0 = selectedNode.data) === null || _selectedNode$data0 === void 0 ? void 0 : _selectedNode$data0.opacity) ?? 1) - opacity) < 0.01 ? 'bg-indigo-500 text-white' : 'bg-gray-200 dark:bg-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-500'}`
}, Math.round(opacity * 100), "%");
}))), useAdvancedStyling && /*#__PURE__*/_react.default.createElement("div", {