@procaaso/alphinity-ui-components 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2110 -465
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -2
- package/dist/index.d.ts +63 -2
- package/dist/index.js +2064 -420
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Button/Button.tsx","../src/components/ControlPanel/ControlPanel.tsx","../src/components/Selector/Selector.tsx","../src/components/ValueEntry/ValueEntry.tsx","../src/components/ValueEntry/LegacyValueEntry.tsx","../src/components/StatusIndicator/StatusIndicator.tsx","../src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx","../src/components/layout/FullscreenWorkspace/FullscreenWorkspace.styles.tsx","../src/components/layout/FullscreenWorkspace/FullscreenWorkspace.overlays.tsx","../src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx","../src/theme/ThemeContext.tsx","../src/theme/ThemeToggle.tsx","../src/components/PIDCanvas/PIDCanvas.tsx","../src/diagram/symbols/mockSymbolLibrary.ts","../src/components/PIDCanvas/NodeRenderer.tsx","../src/components/PIDCanvas/PipeRenderer.tsx","../src/components/PIDCanvas/DataOverlay.tsx","../src/diagram/hooks/useViewBox.ts","../src/diagram/hooks/useSelection.ts","../src/diagram/hooks/useTelemetry.ts","../src/diagram/hooks/useDrag.ts","../src/diagram/hooks/useKeyboardShortcuts.ts","../src/diagram/utils/portCalculations.ts","../src/components/SymbolLibrary/SymbolLibrary.tsx","../src/components/NodeConfigPanel/NodeConfigPanel.tsx","../src/diagram/utils/serialization.ts","../src/diagram/examples/exampleDiagram.ts","../src/utils/thresholds.ts","../src/diagram/hooks/useSimulation.ts"],"sourcesContent":["import React from 'react';\r\n\r\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\r\n variant?: 'primary' | 'secondary';\r\n children: React.ReactNode;\r\n}\r\n\r\nexport const Button: React.FC<ButtonProps> = ({\r\n variant = 'primary',\r\n children,\r\n className = '',\r\n ...props\r\n}) => {\r\n // Use CSS classes for base and variant styles\r\n const baseClass = 'ui-btn';\r\n const variantClass = variant ? `ui-btn--${variant}` : '';\r\n return (\r\n <button className={`${baseClass} ${variantClass} ${className}`.trim()} {...props}>\r\n {children}\r\n </button>\r\n );\r\n};\r\n","import React, { useState } from 'react';\r\nimport { Selector, SelectorOption } from '../Selector';\r\nimport { LegacyValueEntry as ValueEntry } from '../ValueEntry';\r\nimport { Button } from '../Button';\r\n\r\nexport interface ModeConfig {\r\n /** Units for this mode */\r\n unit?: string;\r\n /** Label for the primary setpoint */\r\n label?: string;\r\n /** Minimum value for primary setpoint */\r\n min?: number;\r\n /** Maximum value for primary setpoint */\r\n max?: number;\r\n /** Precision for primary setpoint */\r\n precision?: number;\r\n /** Whether this mode has a second setpoint (like ramp time) */\r\n hasSecondSetpoint?: boolean;\r\n /** Label for the second setpoint */\r\n secondLabel?: string;\r\n /** Units for the second setpoint */\r\n secondUnit?: string;\r\n /** Min value for second setpoint */\r\n secondMin?: number;\r\n /** Max value for second setpoint */\r\n secondMax?: number;\r\n /** Precision for second setpoint */\r\n secondPrecision?: number;\r\n}\r\n\r\nexport interface ControlPanelProps extends React.HTMLAttributes<HTMLDivElement> {\r\n /** Panel title/identifier */\r\n title: string;\r\n /** Currently selected mode */\r\n selectedMode: string;\r\n /** Available mode options */\r\n modeOptions: SelectorOption[];\r\n /** Callback when mode changes */\r\n onModeChange: (mode: string) => void;\r\n /** Current setpoint value */\r\n setpointValue: number | string;\r\n /** Callback when setpoint changes */\r\n onSetpointChange: (value: number | string) => void;\r\n /** Current second setpoint value (for ramp mode, etc.) */\r\n secondSetpointValue?: number | string;\r\n /** Callback when second setpoint changes */\r\n onSecondSetpointChange?: (value: number | string) => void;\r\n /** Configuration for each mode */\r\n modeConfigs?: Record<string, ModeConfig>;\r\n /** Default unit when no mode config is found */\r\n defaultUnit?: string;\r\n /** Default label when no mode config is found */\r\n defaultLabel?: string;\r\n /** Default min when no mode config is found */\r\n defaultMin?: number;\r\n /** Default max when no mode config is found */\r\n defaultMax?: number;\r\n /** Default precision when no mode config is found */\r\n defaultPrecision?: number;\r\n /** Status state for the entire panel */\r\n status?: 'normal' | 'alarm' | 'warning' | 'disabled';\r\n /** Whether the panel is collapsed */\r\n collapsed?: boolean;\r\n /** Callback when collapse state changes */\r\n onCollapseChange?: (collapsed: boolean) => void;\r\n /** Panel size variant */\r\n size?: 'small' | 'medium' | 'large';\r\n /** Whether setpoint is read-only */\r\n setpointReadOnly?: boolean;\r\n /** Whether to show start/stop buttons */\r\n showStartStopButtons?: boolean;\r\n /** Whether the process is currently running */\r\n isRunning?: boolean;\r\n /** Callback when start button is clicked */\r\n onStart?: () => void;\r\n /** Callback when stop button is clicked */\r\n onStop?: () => void;\r\n /** Custom start button text */\r\n startButtonText?: string;\r\n /** Custom stop button text */\r\n stopButtonText?: string;\r\n}\r\n\r\nexport const ControlPanel: React.FC<ControlPanelProps> = ({\r\n title,\r\n selectedMode,\r\n modeOptions,\r\n onModeChange,\r\n setpointValue,\r\n onSetpointChange,\r\n secondSetpointValue,\r\n onSecondSetpointChange,\r\n modeConfigs = {},\r\n defaultUnit = 'Units',\r\n defaultLabel = 'Setpoint',\r\n defaultMin = 0,\r\n defaultMax = 100,\r\n defaultPrecision = 2,\r\n status = 'normal',\r\n collapsed = false,\r\n onCollapseChange,\r\n size = 'medium',\r\n setpointReadOnly = false,\r\n showStartStopButtons = false,\r\n isRunning = false,\r\n onStart,\r\n onStop,\r\n startButtonText = 'Start',\r\n stopButtonText = 'Stop',\r\n className = '',\r\n ...props\r\n}) => {\r\n const [isExpanded, setIsExpanded] = useState(!collapsed);\r\n\r\n const toggleExpanded = () => {\r\n const newExpanded = !isExpanded;\r\n setIsExpanded(newExpanded);\r\n onCollapseChange?.(!newExpanded);\r\n };\r\n\r\n // Get current mode configuration\r\n const currentModeConfig = modeConfigs[selectedMode] || {};\r\n const currentUnit = currentModeConfig.unit || defaultUnit;\r\n const currentLabel = currentModeConfig.label || defaultLabel;\r\n const currentMin = currentModeConfig.min ?? defaultMin;\r\n const currentMax = currentModeConfig.max ?? defaultMax;\r\n const currentPrecision = currentModeConfig.precision ?? defaultPrecision;\r\n const hasSecondSetpoint = currentModeConfig.hasSecondSetpoint || false;\r\n\r\n // Use CSS classes for base, status, size, and expanded state\r\n const baseClass = 'ui-control-panel';\r\n const statusClass = status ? `ui-control-panel--${status}` : '';\r\n const sizeClass = size ? `ui-control-panel--${size}` : '';\r\n const expandedClass = isExpanded ? 'is-expanded' : 'is-collapsed';\r\n const collapsibleClass = onCollapseChange ? 'is-collapsible' : '';\r\n\r\n return (\r\n <div\r\n className={`${baseClass} ${statusClass} ${sizeClass} ${expandedClass} ${collapsibleClass} ${className}`.trim()}\r\n {...props}\r\n >\r\n {/* Status Badge */}\r\n <div className={`ui-control-panel-badge ui-control-panel-badge--${status}`} />\r\n\r\n {/* Header */}\r\n <div\r\n className=\"ui-control-panel-header\"\r\n onClick={onCollapseChange ? toggleExpanded : undefined}\r\n >\r\n <h3 className=\"ui-control-panel-title\">{title}</h3>\r\n {onCollapseChange && (\r\n <svg\r\n className=\"ui-control-panel-chevron\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n >\r\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\r\n </svg>\r\n )}\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"ui-control-panel-content\">\r\n {/* Mode Selector */}\r\n <div>\r\n <Selector\r\n value={selectedMode}\r\n onChange={onModeChange}\r\n options={modeOptions}\r\n label=\"Control Mode\"\r\n status={status}\r\n size={size === 'small' ? 'small' : size === 'large' ? 'large' : 'medium'}\r\n disabled={status === 'disabled'}\r\n />\r\n </div>\r\n\r\n {/* Primary Setpoint Value Entry */}\r\n <div>\r\n <ValueEntry\r\n value={setpointValue}\r\n onChange={onSetpointChange}\r\n label={currentLabel}\r\n unit={currentUnit}\r\n min={currentMin}\r\n max={currentMax}\r\n precision={currentPrecision}\r\n status={status}\r\n readOnly={setpointReadOnly || status === 'disabled'}\r\n disabled={status === 'disabled'}\r\n />\r\n </div>\r\n\r\n {/* Second Setpoint (for ramp mode, etc.) */}\r\n {hasSecondSetpoint && onSecondSetpointChange && (\r\n <div>\r\n <ValueEntry\r\n value={secondSetpointValue || 0}\r\n onChange={onSecondSetpointChange}\r\n label={currentModeConfig.secondLabel || 'Time'}\r\n unit={currentModeConfig.secondUnit || 'sec'}\r\n min={currentModeConfig.secondMin ?? 0}\r\n max={currentModeConfig.secondMax ?? 999}\r\n precision={currentModeConfig.secondPrecision ?? 0}\r\n status={status}\r\n readOnly={setpointReadOnly || status === 'disabled'}\r\n disabled={status === 'disabled'}\r\n />\r\n </div>\r\n )}\r\n\r\n {/* Start/Stop Buttons */}\r\n {showStartStopButtons && (onStart || onStop) && (\r\n <div className=\"ui-control-panel-buttons\">\r\n {onStart && (\r\n <Button\r\n variant=\"primary\"\r\n onClick={onStart}\r\n disabled={isRunning || status === 'disabled'}\r\n className={isRunning ? 'is-running' : ''}\r\n >\r\n {startButtonText}\r\n </Button>\r\n )}\r\n {onStop && (\r\n <Button\r\n variant=\"secondary\"\r\n onClick={onStop}\r\n disabled={!isRunning || status === 'disabled'}\r\n className={`ui-control-panel-stop-btn${!isRunning ? ' is-disabled' : ''}`}\r\n >\r\n {stopButtonText}\r\n </Button>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Additional Info Row */}\r\n <div className=\"ui-control-panel-info\">\r\n <span>Mode: {selectedMode.toUpperCase()}</span>\r\n <div className=\"ui-control-panel-info-values\">\r\n <span>\r\n SP: {String(setpointValue)}\r\n {currentUnit}\r\n </span>\r\n {hasSecondSetpoint && secondSetpointValue && (\r\n <span>\r\n {currentModeConfig.secondLabel}: {String(secondSetpointValue)}\r\n {currentModeConfig.secondUnit}\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useRef, useEffect } from 'react';\r\n\r\nexport interface SelectorOption {\r\n /** Unique value for the option */\r\n value: string;\r\n /** Display label for the option */\r\n label: string;\r\n /** Whether this option is disabled */\r\n disabled?: boolean;\r\n /** Optional description for tooltip or additional context */\r\n description?: string;\r\n}\r\n\r\nexport interface SelectorProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\r\n /** Currently selected value */\r\n value: string;\r\n /** Callback when selection changes */\r\n onChange: (value: string) => void;\r\n /** List of available options */\r\n options: SelectorOption[];\r\n /** Placeholder text when no option is selected */\r\n placeholder?: string;\r\n /** Whether the selector is disabled */\r\n disabled?: boolean;\r\n /** Status state for visual feedback */\r\n status?: 'normal' | 'alarm' | 'warning' | 'disabled';\r\n /** Size variant */\r\n size?: 'small' | 'medium' | 'large';\r\n /** Label for the selector */\r\n label?: string;\r\n /** Whether the dropdown should open upward */\r\n dropdownUp?: boolean;\r\n}\r\n\r\nexport const Selector: React.FC<SelectorProps> = ({\r\n value,\r\n onChange,\r\n options,\r\n placeholder = 'Select option...',\r\n disabled = false,\r\n status = 'normal',\r\n size = 'medium',\r\n label,\r\n dropdownUp: _dropdownUp = false,\r\n className = '',\r\n ...props\r\n}) => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [focusedIndex, setFocusedIndex] = useState(-1);\r\n const selectorRef = useRef<HTMLDivElement>(null);\r\n const dropdownRef = useRef<HTMLDivElement>(null);\r\n\r\n // Close dropdown when clicking outside\r\n useEffect(() => {\r\n const handleClickOutside = (event: MouseEvent) => {\r\n if (selectorRef.current && !selectorRef.current.contains(event.target as Node)) {\r\n setIsOpen(false);\r\n setFocusedIndex(-1);\r\n }\r\n };\r\n document.addEventListener('mousedown', handleClickOutside);\r\n return () => document.removeEventListener('mousedown', handleClickOutside);\r\n }, []);\r\n\r\n // Handle keyboard navigation\r\n const handleKeyDown = (e: React.KeyboardEvent) => {\r\n if (disabled) return;\r\n switch (e.key) {\r\n case 'Enter':\r\n case ' ':\r\n e.preventDefault();\r\n if (!isOpen) {\r\n setIsOpen(true);\r\n setFocusedIndex(\r\n Math.max(\r\n 0,\r\n options.findIndex((opt) => opt.value === value)\r\n )\r\n );\r\n } else if (focusedIndex >= 0) {\r\n const selectedOption = options[focusedIndex];\r\n if (!selectedOption.disabled) {\r\n onChange(selectedOption.value);\r\n setIsOpen(false);\r\n setFocusedIndex(-1);\r\n }\r\n }\r\n break;\r\n case 'Escape':\r\n setIsOpen(false);\r\n setFocusedIndex(-1);\r\n break;\r\n case 'ArrowDown':\r\n e.preventDefault();\r\n if (!isOpen) {\r\n setIsOpen(true);\r\n setFocusedIndex(\r\n Math.max(\r\n 0,\r\n options.findIndex((opt) => opt.value === value)\r\n )\r\n );\r\n } else {\r\n setFocusedIndex((prev) => {\r\n const nextIndex = Math.min(prev + 1, options.length - 1);\r\n return options[nextIndex]?.disabled ? prev : nextIndex;\r\n });\r\n }\r\n break;\r\n case 'ArrowUp':\r\n e.preventDefault();\r\n if (isOpen) {\r\n setFocusedIndex((prev) => {\r\n const nextIndex = Math.max(prev - 1, 0);\r\n return options[nextIndex]?.disabled ? prev : nextIndex;\r\n });\r\n }\r\n break;\r\n }\r\n };\r\n\r\n // CSS class names for base, status, and size\r\n const baseClass = 'ui-selector';\r\n const statusClass = status ? `ui-selector--${status}` : '';\r\n const sizeClass = size ? `ui-selector--${size}` : '';\r\n\r\n // Get current selected option\r\n const selectedOption = options.find((opt) => opt.value === value);\r\n\r\n return (\r\n <div className={`ui-selector-container ${className}`.trim()}>\r\n {label && <label className=\"ui-selector-label\">{label}</label>}\r\n <div ref={selectorRef} style={{ position: 'relative' }}>\r\n <div\r\n className={`${baseClass} ${statusClass} ${sizeClass}`.trim()}\r\n onClick={() => !disabled && setIsOpen(!isOpen)}\r\n onKeyDown={handleKeyDown}\r\n tabIndex={disabled ? -1 : 0}\r\n role=\"combobox\"\r\n aria-expanded={isOpen}\r\n aria-haspopup=\"listbox\"\r\n {...props}\r\n >\r\n <span className=\"ui-selector-value\">\r\n {selectedOption ? selectedOption.label : placeholder}\r\n </span>\r\n {/* Arrow Icon */}\r\n <svg className=\"ui-selector-arrow\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\r\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\r\n </svg>\r\n </div>\r\n\r\n {/* Dropdown */}\r\n {isOpen && (\r\n <div ref={dropdownRef} className=\"ui-selector-dropdown\" role=\"listbox\">\r\n {options.map((option, index) => (\r\n <div\r\n key={option.value}\r\n className={`ui-selector-option${option.disabled ? ' is-disabled' : ''}${option.value === value ? ' is-selected' : ''}`}\r\n onClick={() => {\r\n if (!option.disabled) {\r\n onChange(option.value);\r\n setIsOpen(false);\r\n setFocusedIndex(-1);\r\n }\r\n }}\r\n onMouseEnter={() => !option.disabled && setFocusedIndex(index)}\r\n role=\"option\"\r\n aria-selected={option.value === value}\r\n aria-disabled={option.disabled}\r\n title={option.description}\r\n >\r\n <div className=\"ui-selector-option-label\">\r\n <span>{option.label}</span>\r\n {option.value === value && (\r\n <svg className=\"ui-selector-check\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path\r\n fillRule=\"evenodd\"\r\n d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\r\n clipRule=\"evenodd\"\r\n />\r\n </svg>\r\n )}\r\n </div>\r\n {option.description && (\r\n <div className=\"ui-selector-option-desc\">{option.description}</div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useCallback } from 'react';\r\n\r\nexport interface ValueEntryProps\r\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {\r\n /** Current value */\r\n value: number | string;\r\n /** Callback when value changes */\r\n onChange: (value: number | string) => void;\r\n /** Unit of measurement to display */\r\n unit?: string;\r\n /** Status state for visual feedback */\r\n status?: 'normal' | 'alarm' | 'warning' | 'disabled';\r\n /** Minimum allowed value (for numeric inputs) */\r\n min?: number;\r\n /** Maximum allowed value (for numeric inputs) */\r\n max?: number;\r\n /** Number of decimal places (for numeric inputs) */\r\n precision?: number;\r\n /** Input type - numeric or text */\r\n inputType?: 'numeric' | 'text';\r\n /** Label for the input */\r\n label?: string;\r\n /** Whether the input is read-only */\r\n readOnly?: boolean;\r\n}\r\n\r\nexport const ValueEntry: React.FC<ValueEntryProps> = ({\r\n value,\r\n onChange,\r\n unit,\r\n status = 'normal',\r\n min,\r\n max,\r\n precision = 2,\r\n inputType = 'numeric',\r\n label,\r\n readOnly = false,\r\n className = '',\r\n disabled,\r\n ...props\r\n}) => {\r\n const [displayValue, setDisplayValue] = useState(String(value));\r\n const [isEditing, setIsEditing] = useState(false);\r\n\r\n const handleFocus = useCallback(() => {\r\n setIsEditing(true);\r\n setDisplayValue(String(value));\r\n }, [value]);\r\n\r\n const handleBlur = useCallback(() => {\r\n setIsEditing(false);\r\n let newValue: number | string = displayValue;\r\n\r\n if (inputType === 'numeric') {\r\n const numValue = parseFloat(displayValue);\r\n if (!isNaN(numValue)) {\r\n // Apply min/max constraints\r\n let constrainedValue = numValue;\r\n if (min !== undefined) constrainedValue = Math.max(min, constrainedValue);\r\n if (max !== undefined) constrainedValue = Math.min(max, constrainedValue);\r\n\r\n // Apply precision\r\n constrainedValue = parseFloat(constrainedValue.toFixed(precision));\r\n newValue = constrainedValue;\r\n setDisplayValue(String(constrainedValue));\r\n } else {\r\n // Invalid number, revert to original value\r\n setDisplayValue(String(value));\r\n return;\r\n }\r\n }\r\n\r\n if (newValue !== value) {\r\n onChange(newValue);\r\n }\r\n }, [displayValue, inputType, min, max, precision, value, onChange]);\r\n\r\n const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\r\n setDisplayValue(e.target.value);\r\n }, []);\r\n\r\n const handleKeyDown = useCallback(\r\n (e: React.KeyboardEvent<HTMLInputElement>) => {\r\n if (e.key === 'Enter') {\r\n e.currentTarget.blur();\r\n }\r\n if (e.key === 'Escape') {\r\n setDisplayValue(String(value));\r\n e.currentTarget.blur();\r\n }\r\n },\r\n [value]\r\n );\r\n\r\n // Use CSS classes for base, status, and unit styles\r\n const baseClass = 'ui-value-entry';\r\n const unitClass = unit ? 'ui-value-entry--with-unit' : '';\r\n const currentStatus = disabled || readOnly ? 'disabled' : status;\r\n const statusVariantClass = currentStatus ? `ui-value-entry--${currentStatus}` : '';\r\n\r\n const displayText = isEditing\r\n ? displayValue\r\n : inputType === 'numeric'\r\n ? Number(value).toFixed(precision)\r\n : String(value);\r\n\r\n return (\r\n <div className=\"ui-value-entry-container\">\r\n {label && <label className=\"ui-value-entry-label\">{label}</label>}\r\n <div className=\"ui-value-entry-wrapper\">\r\n <input\r\n type={inputType === 'numeric' ? 'text' : 'text'}\r\n value={displayText}\r\n onChange={handleChange}\r\n onFocus={handleFocus}\r\n onBlur={handleBlur}\r\n onKeyDown={handleKeyDown}\r\n disabled={disabled}\r\n readOnly={readOnly}\r\n className={`${baseClass} ${statusVariantClass} ${unitClass} ${className}`.trim()}\r\n {...props}\r\n />\r\n {unit && <span className=\"ui-value-entry-unit\">{unit}</span>}\r\n {status === 'alarm' && <div className=\"ui-value-entry-badge ui-value-entry-badge--alarm\" />}\r\n {status === 'warning' && (\r\n <div className=\"ui-value-entry-badge ui-value-entry-badge--warning\" />\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useCallback } from 'react';\n\nexport interface LegacyValueEntryProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {\n /** Current value */\n value: number | string;\n /** Callback when value changes */\r\n onChange: (value: number | string) => void;\r\n /** Unit of measurement to display */\r\n unit?: string;\r\n /** Status state for visual feedback */\r\n status?: 'normal' | 'alarm' | 'warning' | 'disabled';\r\n /** Minimum allowed value (for numeric inputs) */\r\n min?: number;\r\n /** Maximum allowed value (for numeric inputs) */\r\n max?: number;\r\n /** Number of decimal places (for numeric inputs) */\r\n precision?: number;\r\n /** Input type - numeric or text */\r\n inputType?: 'numeric' | 'text';\r\n /** Label for the input */\n label?: string;\n /** Whether the input is read-only */\n readOnly?: boolean;\n}\n\nexport const LegacyValueEntry: React.FC<LegacyValueEntryProps> = ({\n value,\n onChange,\n unit,\n status = 'normal',\n min,\r\n max,\r\n precision = 2,\r\n inputType = 'numeric',\r\n label,\r\n readOnly = false,\r\n className = '',\r\n disabled,\r\n ...props\r\n}) => {\r\n const [displayValue, setDisplayValue] = useState(String(value));\r\n const [isEditing, setIsEditing] = useState(false);\r\n\r\n const handleFocus = useCallback(() => {\r\n setIsEditing(true);\r\n setDisplayValue(String(value));\r\n }, [value]);\r\n\r\n const handleBlur = useCallback(() => {\r\n setIsEditing(false);\r\n let newValue: number | string = displayValue;\r\n\r\n if (inputType === 'numeric') {\r\n const numValue = parseFloat(displayValue);\r\n if (!isNaN(numValue)) {\r\n // Apply min/max constraints\r\n let constrainedValue = numValue;\r\n if (min !== undefined) constrainedValue = Math.max(min, constrainedValue);\r\n if (max !== undefined) constrainedValue = Math.min(max, constrainedValue);\r\n\r\n // Apply precision\r\n constrainedValue = parseFloat(constrainedValue.toFixed(precision));\r\n newValue = constrainedValue;\r\n setDisplayValue(String(constrainedValue));\r\n } else {\r\n // Invalid number, revert to original value\r\n setDisplayValue(String(value));\r\n return;\r\n }\r\n }\r\n\r\n if (newValue !== value) {\r\n onChange(newValue);\r\n }\r\n }, [displayValue, inputType, min, max, precision, value, onChange]);\r\n\r\n const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\r\n setDisplayValue(e.target.value);\r\n }, []);\r\n\r\n const handleKeyDown = useCallback(\r\n (e: React.KeyboardEvent<HTMLInputElement>) => {\r\n if (e.key === 'Enter') {\r\n e.currentTarget.blur();\r\n }\r\n if (e.key === 'Escape') {\r\n setDisplayValue(String(value));\r\n e.currentTarget.blur();\r\n }\r\n },\r\n [value]\r\n );\r\n\r\n // Create the display text\r\n const displayText = isEditing\r\n ? displayValue\r\n : inputType === 'numeric'\r\n ? Number(value).toFixed(precision)\r\n : String(value);\r\n\r\n // Status-based styling with modern industrial colors\r\n const getStatusStyles = () => {\r\n switch (status) {\r\n case 'alarm':\r\n return {\r\n borderColor: '#ef4444',\r\n backgroundColor: 'rgba(239, 68, 68, 0.15)',\r\n color: '#fecaca',\r\n boxShadow: '0 0 20px rgba(239, 68, 68, 0.3)',\r\n };\r\n case 'warning':\r\n return {\r\n borderColor: '#f59e0b',\r\n backgroundColor: 'rgba(245, 158, 11, 0.15)',\r\n color: '#fed7aa',\r\n boxShadow: '0 0 20px rgba(245, 158, 11, 0.3)',\r\n };\r\n case 'disabled':\r\n return {\r\n borderColor: '#6b7280',\r\n backgroundColor: 'rgba(107, 114, 128, 0.1)',\r\n color: '#9ca3af',\r\n cursor: 'not-allowed',\r\n };\r\n default:\r\n return {\r\n borderColor: '#64748b',\r\n backgroundColor: 'rgba(30, 41, 59, 0.9)',\r\n color: '#f1f5f9',\r\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3)',\r\n };\r\n }\r\n };\r\n\r\n const statusStyles = getStatusStyles();\r\n\r\n const inputStyle: React.CSSProperties = {\r\n width: '12rem',\r\n height: '4rem',\r\n padding: unit ? '1rem 4rem 1rem 1.5rem' : '1rem 1.5rem',\r\n border: '2px solid',\r\n borderRadius: '1.5rem',\r\n fontFamily:\r\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace',\r\n fontSize: '1.25rem',\r\n fontWeight: 'bold',\r\n textAlign: 'center',\r\n outline: 'none',\r\n transition: 'all 300ms ease',\r\n backdropFilter: 'blur(8px)',\r\n ...statusStyles,\r\n };\r\n\r\n const inputStyleFocus: React.CSSProperties = {\r\n ...inputStyle,\r\n borderColor: '#60a5fa',\r\n boxShadow:\r\n '0 0 0 4px rgba(96, 165, 250, 0.3), ' +\r\n (statusStyles.boxShadow || '0 8px 32px rgba(0, 0, 0, 0.3)'),\r\n transform: 'scale(1.02)',\r\n };\r\n\r\n const unitStyle: React.CSSProperties = {\r\n position: 'absolute',\r\n right: '0.75rem',\r\n top: '50%',\r\n transform: 'translateY(-50%)',\r\n padding: '0.5rem 0.75rem',\r\n fontSize: '1rem',\r\n fontWeight: 'bold',\r\n color: '#ffffff',\r\n backgroundColor: '#3b82f6',\r\n borderRadius: '0.5rem',\r\n border: '2px solid #60a5fa',\r\n backdropFilter: 'blur(4px)',\r\n pointerEvents: 'none' as const,\r\n zIndex: 10,\r\n boxShadow: '0 2px 8px rgba(59, 130, 246, 0.4)',\r\n };\r\n\r\n return (\r\n <div\r\n style={{\r\n display: 'inline-flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n gap: '0.75rem',\r\n }}\r\n >\r\n {label && (\r\n <label\r\n style={{\r\n fontSize: '0.875rem',\r\n fontWeight: '600',\r\n color: '#cbd5e1',\r\n textTransform: 'uppercase',\r\n letterSpacing: '0.05em',\r\n }}\r\n >\r\n {label}\r\n </label>\r\n )}\r\n <div style={{ position: 'relative', display: 'inline-flex', alignItems: 'center' }}>\r\n <input\r\n type=\"text\"\r\n value={displayText}\r\n onChange={handleChange}\r\n onFocus={(e) => {\r\n Object.assign(e.target.style, inputStyleFocus);\r\n handleFocus();\r\n }}\r\n onBlur={(e) => {\r\n Object.assign(e.target.style, inputStyle);\r\n handleBlur();\r\n }}\r\n onKeyDown={handleKeyDown}\r\n disabled={disabled}\r\n readOnly={readOnly}\r\n style={inputStyle}\r\n {...props}\r\n />\r\n {unit && <span style={unitStyle}>{unit}</span>}\r\n {status === 'alarm' && (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: '-8px',\r\n right: '-8px',\r\n width: '1rem',\r\n height: '1rem',\r\n backgroundColor: '#ef4444',\r\n borderRadius: '50%',\r\n boxShadow: '0 0 10px rgba(239, 68, 68, 0.8)',\r\n animation: 'pulse 2s infinite',\r\n }}\r\n />\r\n )}\r\n {status === 'warning' && (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: '-8px',\r\n right: '-8px',\r\n width: '1rem',\r\n height: '1rem',\r\n backgroundColor: '#f59e0b',\r\n borderRadius: '50%',\r\n boxShadow: '0 0 10px rgba(245, 158, 11, 0.8)',\r\n }}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\n\r\nconst getStatusDescription = (status: string): string => {\r\n switch (status) {\r\n case 'alarm':\r\n return 'Critical alarm condition requiring attention';\r\n case 'warning':\r\n return 'Warning condition that should be monitored';\r\n case 'fault':\r\n return 'Equipment fault detected';\r\n case 'active':\r\n return 'Equipment is actively running';\r\n case 'normal':\r\n return 'Operating normally';\r\n case 'off':\r\n return 'Equipment is off';\r\n default:\r\n return '';\r\n }\r\n};\r\n\r\nexport interface StatusIndicatorProps extends React.HTMLAttributes<HTMLDivElement> {\r\n /** Status state determining color and behavior */\r\n status: 'off' | 'normal' | 'alarm' | 'warning' | 'active' | 'fault';\r\n /** Size of the indicator */\r\n size?: 'small' | 'medium' | 'large';\r\n /** Animation behavior */\r\n animation?: 'none' | 'pulse' | 'blink' | 'flash';\r\n /** Label text to display next to indicator */\r\n label?: string;\r\n /** Position of label relative to indicator */\r\n labelPosition?: 'left' | 'right' | 'top' | 'bottom';\r\n /** Shape of the indicator */\r\n shape?: 'circle' | 'square' | 'diamond';\r\n /** Whether the indicator should have a 3D LED effect */\r\n led?: boolean;\r\n}\r\n\r\nexport const StatusIndicator: React.FC<StatusIndicatorProps> = ({\r\n status,\r\n size = 'medium',\r\n animation = 'none',\r\n label,\r\n labelPosition = 'right',\r\n shape = 'circle',\r\n led = true,\r\n className = '',\r\n ...props\r\n}) => {\r\n // Use CSS classes for base, status, size, shape, animation, led\r\n const baseClass = 'ui-status-indicator';\r\n const statusClass = status ? `ui-status-indicator--${status}` : '';\r\n const sizeClass = size ? `ui-status-indicator--${size}` : '';\r\n const shapeClass = shape ? `ui-status-indicator--${shape}` : '';\r\n const animationClass = animation ? `ui-status-indicator--${animation}` : '';\r\n const ledClass = led ? 'ui-status-indicator--led' : '';\r\n\r\n // Container layout based on label position\r\n const getContainerLayout = () => {\r\n switch (labelPosition) {\r\n case 'left':\r\n return 'ui-status-indicator-container ui-status-indicator-label-left';\r\n case 'right':\r\n return 'ui-status-indicator-container ui-status-indicator-label-right';\r\n case 'top':\r\n return 'ui-status-indicator-container ui-status-indicator-label-top';\r\n case 'bottom':\r\n return 'ui-status-indicator-container ui-status-indicator-label-bottom';\r\n default:\r\n return 'ui-status-indicator-container ui-status-indicator-label-right';\r\n }\r\n };\r\n\r\n return (\r\n <span className={getContainerLayout()}>\r\n {label && (labelPosition === 'left' || labelPosition === 'top') && (\r\n <span className=\"ui-status-indicator-label\">{label}</span>\r\n )}\r\n <span\r\n role=\"status\"\r\n aria-label={label || `Status: ${status}`}\r\n aria-description={getStatusDescription(status)}\r\n data-status={status}\r\n className={`\r\n ${baseClass}\r\n ${statusClass}\r\n ${sizeClass}\r\n ${shapeClass}\r\n ${animationClass}\r\n ${ledClass}\r\n ${className}\r\n `\r\n .replace(/\\s+/g, ' ')\r\n .trim()}\r\n {...props}\r\n />\r\n {label && (labelPosition === 'right' || labelPosition === 'bottom') && (\r\n <span className=\"ui-status-indicator-label\">{label}</span>\r\n )}\r\n </span>\r\n );\r\n};\r\n","import React from 'react';\nimport { Tab } from '@mui/material';\nimport {\n ChevronLeft,\n ChevronRight,\n DisplayModeToggle,\n FixedSVGContainer,\n FooterPanel,\n FullscreenContainer,\n LeftPanel,\n LeftToggleButton,\n PanelContent,\n PanelTabs,\n RightPanel,\n RightToggleButton,\n SVGArea,\n ScrollableSVGWrapper,\n ZoomButton,\n ZoomControls,\n} from './FullscreenWorkspace.styles';\nimport type { DisplayMode, FullscreenWorkspaceProps } from './types';\n\nexport function FullscreenWorkspace({\n svgContent,\n overlays,\n leftPanel,\n rightPanel,\n footer,\n tabs,\n activeTab,\n onTabChange,\n defaultLeftCollapsed = false,\n defaultRightCollapsed = false,\n leftCollapsed: leftCollapsedProp,\n rightCollapsed: rightCollapsedProp,\n onLeftCollapseChange,\n onRightCollapseChange,\n displayMode,\n defaultDisplayMode = 'standard',\n onDisplayModeChange,\n showDisplayModeToggle = true,\n showZoomControls = false,\n onZoomIn,\n onZoomOut,\n onResetZoom,\n zoomDisabled = false,\n className = '',\n ...rest\n}: FullscreenWorkspaceProps): React.ReactElement {\n const [leftCollapsedState, setLeftCollapsedState] = React.useState(defaultLeftCollapsed);\n const [rightCollapsedState, setRightCollapsedState] = React.useState(defaultRightCollapsed);\n const [internalDisplayMode, setInternalDisplayMode] =\n React.useState<DisplayMode>(displayMode ?? defaultDisplayMode);\n const [internalTab, setInternalTab] = React.useState<string>(\n tabs && tabs.length > 0 ? tabs[0].value : ''\n );\n\n const leftCollapsed = leftCollapsedProp ?? leftCollapsedState;\n const rightCollapsed = rightCollapsedProp ?? rightCollapsedState;\n const isDisplayModeControlled = displayMode !== undefined;\n const currentDisplayMode = isDisplayModeControlled ? displayMode : internalDisplayMode;\n const isTabControlled = activeTab !== undefined && activeTab !== null;\n\n const resolvedTabs = React.useMemo(() => tabs ?? [], [tabs]);\n const defaultTabValue = resolvedTabs.length > 0 ? resolvedTabs[0].value : '';\n const currentTab = isTabControlled ? (activeTab as string) : internalTab || defaultTabValue;\n\n React.useEffect(() => {\n if (resolvedTabs.length > 0) {\n const values = resolvedTabs.map((tab) => tab.value);\n if (!values.includes(currentTab)) {\n const fallback = activeTab ?? defaultTabValue;\n setInternalTab(fallback);\n }\n }\n }, [resolvedTabs, activeTab, currentTab, defaultTabValue]);\n\n React.useEffect(() => {\n if (displayMode !== undefined) {\n setInternalDisplayMode(displayMode);\n }\n }, [displayMode]);\n\n const handleLeftToggle = () => {\n const next = !leftCollapsed;\n if (leftCollapsedProp === undefined) {\n setLeftCollapsedState(next);\n }\n onLeftCollapseChange?.(next);\n };\n\n const handleRightToggle = () => {\n const next = !rightCollapsed;\n if (rightCollapsedProp === undefined) {\n setRightCollapsedState(next);\n }\n onRightCollapseChange?.(next);\n };\n\n const handleModeToggle = () => {\n const nextMode = currentDisplayMode === 'standard' ? 'dashboard' : 'standard';\n if (!isDisplayModeControlled) {\n setInternalDisplayMode(nextMode);\n }\n onDisplayModeChange?.(nextMode);\n };\n\n const handleTabChangeInternal = (_: React.SyntheticEvent, value: string) => {\n if (!isTabControlled) {\n setInternalTab(value);\n }\n onTabChange?.(value);\n };\n\n const currentTabContent =\n resolvedTabs.find((tab) => tab.value === currentTab)?.content ?? null;\n\n const showLeftToggle = Boolean(leftPanel);\n const showRightToggle = Boolean(rightPanel);\n\n return (\n <FullscreenContainer\n leftCollapsed={leftCollapsed}\n rightCollapsed={rightCollapsed}\n className={`tff-svg-container ${className}`.trim()}\n {...rest}\n >\n {showLeftToggle && (\n <LeftToggleButton\n collapsed={leftCollapsed}\n onClick={handleLeftToggle}\n aria-label={leftCollapsed ? 'Expand left panel' : 'Collapse left panel'}\n >\n {leftCollapsed ? <ChevronRight /> : <ChevronLeft />}\n </LeftToggleButton>\n )}\n\n {showRightToggle && (\n <RightToggleButton\n collapsed={rightCollapsed}\n onClick={handleRightToggle}\n aria-label={rightCollapsed ? 'Expand right panel' : 'Collapse right panel'}\n >\n {rightCollapsed ? <ChevronLeft /> : <ChevronRight />}\n </RightToggleButton>\n )}\n\n {showDisplayModeToggle && (\n <DisplayModeToggle\n mode={currentDisplayMode}\n onClick={handleModeToggle}\n aria-label=\"Toggle display mode\"\n >\n {currentDisplayMode === 'dashboard' ? 'Dashboard Mode' : 'Standard Mode'}\n </DisplayModeToggle>\n )}\n\n <SVGArea>\n {showZoomControls && (\n <ZoomControls>\n <ZoomButton\n onClick={onZoomIn}\n disabled={zoomDisabled || !onZoomIn}\n size=\"small\"\n aria-label=\"Zoom in\"\n >\n +\n </ZoomButton>\n <ZoomButton\n onClick={onZoomOut}\n disabled={zoomDisabled || !onZoomOut}\n size=\"small\"\n aria-label=\"Zoom out\"\n >\n -\n </ZoomButton>\n {onResetZoom && (\n <ZoomButton\n onClick={onResetZoom}\n disabled={zoomDisabled}\n size=\"small\"\n aria-label=\"Reset zoom\"\n >\n Reset\n </ZoomButton>\n )}\n </ZoomControls>\n )}\n\n <ScrollableSVGWrapper className=\"svg-scroll-wrapper\">\n <FixedSVGContainer className=\"svg-container\">\n {svgContent}\n {overlays}\n </FixedSVGContainer>\n </ScrollableSVGWrapper>\n </SVGArea>\n\n <LeftPanel collapsed={leftCollapsed}>\n {resolvedTabs.length > 0 ? (\n <>\n <PanelTabs\n value={currentTab}\n onChange={handleTabChangeInternal}\n aria-label=\"Left panel tabs\"\n >\n {resolvedTabs.map((tab) => (\n <Tab key={tab.value} label={tab.label} value={tab.value} />\n ))}\n </PanelTabs>\n <PanelContent>{currentTabContent}</PanelContent>\n </>\n ) : (\n leftPanel\n )}\n </LeftPanel>\n\n <RightPanel collapsed={rightCollapsed}>{rightPanel}</RightPanel>\n\n <FooterPanel>{footer}</FooterPanel>\n </FullscreenContainer>\n );\n}\n\nexport type {\n DisplayMode,\n FullscreenContainerProps,\n FullscreenWorkspaceProps,\n FullscreenWorkspaceTab,\n OverlayTheme,\n SVGLockedOverlayProps,\n TrendLineProps,\n CircularGaugeProps,\n SparklineProps,\n EquipmentIndicatorProps,\n EquipmentIndicatorWithSparklineProps,\n} from './types';\n\nexport {\n FullscreenContainer,\n LeftPanel,\n RightPanel,\n SVGArea,\n LeftToggleButton,\n RightToggleButton,\n DisplayModeToggle,\n ZoomControls,\n ZoomButton,\n FooterPanel,\n PanelTabs,\n PanelContent,\n FixedSVGContainer,\n ScrollableSVGWrapper,\n ChevronLeft,\n ChevronRight,\n} from './FullscreenWorkspace.styles';\n\nexport {\n overlayStyles,\n SVGLockedOverlay,\n DashboardCard,\n CardHeader,\n CardValue,\n CardUnit,\n} from './FullscreenWorkspace.overlays';\n\nexport {\n TrendLine,\n Sparkline,\n CircularGauge,\n EquipmentIndicator,\n EquipmentIndicatorWithSparkline,\n} from './FullscreenWorkspace.visuals';\n","import { Box, IconButton, Tabs } from '@mui/material';\nimport styled from '@emotion/styled';\nimport type { DisplayMode, FullscreenContainerProps } from './types';\n\nexport const FullscreenContainer = styled(Box)<FullscreenContainerProps>(\n ({ leftCollapsed, rightCollapsed }) => {\n const getGridTemplateAreas = () => {\n if (leftCollapsed && rightCollapsed) {\n return `\"svg-area\" \"footer\"`;\n }\n if (leftCollapsed) {\n return `\"svg-area right-panel\" \"footer footer\"`;\n }\n if (rightCollapsed) {\n return `\"left-panel svg-area\" \"footer footer\"`;\n }\n return `\"left-panel svg-area right-panel\" \"footer footer footer\"`;\n };\n\n const getGridTemplateColumns = () => {\n if (leftCollapsed && rightCollapsed) {\n return '1fr';\n }\n if (leftCollapsed) {\n return '1fr 380px';\n }\n if (rightCollapsed) {\n return '420px 1fr';\n }\n return '420px 1fr 380px';\n };\n\n return {\n width: '100vw',\n height: '100vh',\n background: '#f5f5f5',\n display: 'grid',\n gridTemplateAreas: getGridTemplateAreas(),\n gridTemplateRows: '1fr 100px',\n gridTemplateColumns: getGridTemplateColumns(),\n gap: '10px',\n padding: '10px',\n boxSizing: 'border-box',\n transition: 'grid-template-columns 0.3s ease-in-out',\n };\n }\n);\n\nexport const LeftPanel = styled(Box)<{ collapsed: boolean }>(({ collapsed }) => ({\n gridArea: 'left-panel',\n background: 'rgba(255, 255, 255, 0.0)',\n border: '1px solid #ddd',\n borderRadius: '8px',\n padding: collapsed ? '0' : '15px',\n overflowY: 'auto',\n display: collapsed ? 'none' : 'block',\n transition: 'all 0.3s ease-in-out',\n}));\n\nexport const RightPanel = styled(Box)<{ collapsed: boolean }>(({ collapsed }) => ({\n gridArea: 'right-panel',\n background: 'rgba(255, 255, 255, 0.0)',\n border: '1px solid #ddd',\n borderRadius: '8px',\n padding: collapsed ? '0' : '15px',\n overflowY: 'auto',\n display: collapsed ? 'none' : 'block',\n transition: 'all 0.3s ease-in-out',\n}));\n\nexport const SVGArea = styled(Box)({\n gridArea: 'svg-area',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-start',\n position: 'relative',\n background: 'rgba(255, 255, 255, 0.0)',\n border: '1px solid #ddd',\n borderRadius: '8px',\n overflow: 'auto',\n width: '100%',\n height: '100%',\n});\n\nexport const LeftToggleButton = styled(IconButton)<{ collapsed: boolean }>(\n ({ collapsed }) => ({\n position: 'absolute',\n left: collapsed ? '10px' : '410px',\n top: '50%',\n transform: 'translateY(-50%)',\n zIndex: 1000,\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n border: '1px solid #ddd',\n transition: 'left 0.3s ease-in-out',\n '&:hover': {\n backgroundColor: 'rgba(255, 255, 255, 1)',\n },\n })\n);\n\nexport const RightToggleButton = styled(IconButton)<{ collapsed: boolean }>(\n ({ collapsed }) => ({\n position: 'absolute',\n right: collapsed ? '10px' : '370px',\n top: '50%',\n transform: 'translateY(-50%)',\n zIndex: 1000,\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n border: '1px solid #ddd',\n transition: 'right 0.3s ease-in-out',\n '&:hover': {\n backgroundColor: 'rgba(255, 255, 255, 1)',\n },\n })\n);\n\nexport const DisplayModeToggle = styled(IconButton)<{ mode: DisplayMode }>(({ mode }) => ({\n position: 'absolute',\n top: '50px',\n left: '75%',\n transform: 'translateX(-50%)',\n zIndex: 1000,\n backgroundColor:\n mode === 'dashboard' ? 'rgba(52, 152, 219, 0.9)' : 'rgba(255, 255, 255, 0.9)',\n color: mode === 'dashboard' ? 'white' : '#333',\n border: '1px solid #ddd',\n borderRadius: '20px',\n padding: '8px 16px',\n fontSize: '12px',\n fontWeight: '600',\n minWidth: '120px',\n transition: 'all 0.3s ease-in-out',\n '&:hover': {\n backgroundColor:\n mode === 'dashboard' ? 'rgba(52, 152, 219, 1)' : 'rgba(255, 255, 255, 1)',\n transform: 'translateX(-50%) scale(1.05)',\n },\n}));\n\nexport const ChevronLeft = () => (\n <div\n style={{\n width: 0,\n height: 0,\n borderTop: '6px solid transparent',\n borderBottom: '6px solid transparent',\n borderRight: '8px solid #666',\n }}\n />\n);\n\nexport const ChevronRight = () => (\n <div\n style={{\n width: 0,\n height: 0,\n borderTop: '6px solid transparent',\n borderBottom: '6px solid transparent',\n borderLeft: '8px solid #666',\n }}\n />\n);\n\nexport const ZoomControls = styled(Box)({\n position: 'absolute',\n top: '10px',\n right: '10px',\n display: 'flex',\n flexDirection: 'column',\n gap: '5px',\n zIndex: 1000,\n});\n\nexport const ZoomButton = styled(IconButton)({\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n border: '1px solid #ddd',\n width: '32px',\n height: '32px',\n fontSize: '14px',\n fontWeight: 'bold',\n '&:hover': {\n backgroundColor: 'rgba(255, 255, 255, 1)',\n },\n});\n\nexport const FooterPanel = styled(Box)({\n gridArea: 'footer',\n background: 'rgba(255, 255, 255, 0.95)',\n border: '1px solid #ddd',\n borderRadius: '8px',\n padding: '10px',\n display: 'flex',\n justifyContent: 'space-around',\n alignItems: 'center',\n});\n\nexport const PanelTabs = styled(Tabs)({\n minHeight: '36px',\n '& .MuiTabs-indicator': {\n backgroundColor: '#546e7a',\n },\n '& .MuiTab-root': {\n minHeight: '36px',\n padding: '6px 12px',\n fontSize: '12px',\n fontWeight: '600',\n textTransform: 'none',\n color: '#666',\n '&.Mui-selected': {\n color: '#546e7a',\n },\n },\n});\n\nexport const PanelContent = styled(Box)({\n flex: 1,\n overflow: 'auto',\n padding: '10px',\n});\n\nexport const FixedSVGContainer = styled('div')({\n position: 'relative',\n width: '1300px',\n height: '400px',\n minWidth: '1300px',\n minHeight: '400px',\n maxWidth: '1300px',\n maxHeight: '400px',\n border: 'none',\n backgroundColor: 'transparent',\n overflow: 'visible',\n '& .svg-locked-overlay': {\n position: 'absolute',\n pointerEvents: 'auto',\n zIndex: 10,\n },\n '& svg': {\n position: 'absolute',\n left: 0,\n top: 0,\n width: '1300px',\n height: '280px',\n minWidth: '1300px',\n minHeight: '280px',\n maxWidth: 'none',\n maxHeight: 'none',\n objectFit: 'none',\n transform: 'none',\n border: 'none',\n },\n});\n\nexport const ScrollableSVGWrapper = styled('div')({\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'auto',\n transform: 'rotateX(180deg)',\n padding: '250px',\n paddingTop: '200px',\n boxSizing: 'border-box',\n '& > *': {\n display: 'block',\n transform: 'rotateX(180deg)',\n },\n});\n","import { useEffect, useState } from 'react';\nimport { Box } from '@mui/material';\nimport styled from '@emotion/styled';\nimport type { OverlayTheme, SVGLockedOverlayProps } from './types';\n\nconst baseOverlayStyles = {\n tank: {\n background:\n 'linear-gradient(135deg, rgba(69, 90, 120, 0.95) 0%, rgba(52, 73, 94, 0.95) 100%)',\n border: '1px solid #455a64',\n color: 'white',\n borderRadius: '4px',\n fontSize: '12px',\n fontWeight: '500',\n textAlign: 'center' as const,\n padding: '8px',\n minWidth: '60px',\n boxShadow: '0 1px 4px rgba(69, 90, 120, 0.2)',\n },\n pressure: {\n background:\n 'linear-gradient(135deg, rgba(30, 50, 90, 0.75) 0%, rgba(20, 35, 70, 0.75) 100%)',\n border: '1px solid #1e3a8a',\n color: 'white',\n borderRadius: '4px',\n fontSize: '11px',\n fontWeight: '500',\n textAlign: 'center' as const,\n padding: '6px',\n minWidth: '50px',\n boxShadow: '0 1px 4px rgba(30, 50, 90, 0.15)',\n },\n vessel: {\n background:\n 'linear-gradient(135deg, rgba(84, 110, 122, 0.95) 0%, rgba(69, 90, 100, 0.95) 100%)',\n border: '1px solid #546e7a',\n color: 'white',\n borderRadius: '4px',\n fontSize: '13px',\n fontWeight: '500',\n textAlign: 'center' as const,\n padding: '8px',\n minWidth: '70px',\n boxShadow: '0 1px 4px rgba(84, 110, 122, 0.2)',\n },\n flow: {\n background:\n 'linear-gradient(135deg, rgba(102, 125, 102, 0.95) 0%, rgba(85, 107, 85, 0.95) 100%)',\n border: '1px solid #689f38',\n color: 'white',\n borderRadius: '4px',\n fontSize: '11px',\n fontWeight: '500',\n textAlign: 'center' as const,\n padding: '5px',\n minWidth: '60px',\n boxShadow: '0 1px 4px rgba(102, 125, 102, 0.2)',\n },\n} as const;\n\nexport const overlayStyles: Record<OverlayTheme, typeof baseOverlayStyles[OverlayTheme]> =\n baseOverlayStyles;\n\nexport const SVGLockedOverlay = ({\n svgX,\n svgY,\n children,\n theme,\n style = {},\n className = '',\n onClick,\n containerSelector = '.tff-svg-container',\n}: SVGLockedOverlayProps) => {\n const [svgOffset, setSvgOffset] = useState({ x: 0, y: 0 });\n\n useEffect(() => {\n const updateSvgOffset = () => {\n const containerElement = document.querySelector(containerSelector);\n const svgElement = containerElement?.querySelector('svg');\n\n if (svgElement && containerElement) {\n const svgRect = svgElement.getBoundingClientRect();\n const containerRect = containerElement.getBoundingClientRect();\n\n setSvgOffset({\n x: svgRect.left - containerRect.left,\n y: svgRect.top - containerRect.top,\n });\n }\n };\n\n updateSvgOffset();\n window.addEventListener('resize', updateSvgOffset);\n return () => window.removeEventListener('resize', updateSvgOffset);\n }, [containerSelector]);\n\n const pixelX = svgX + svgOffset.x;\n const pixelY = svgY + svgOffset.y;\n\n const appliedStyle = theme ? { ...overlayStyles[theme], ...style } : style;\n\n return (\n <Box\n className={`svg-locked-overlay ${className}`.trim()}\n onClick={onClick}\n sx={{\n position: 'absolute',\n left: `${pixelX}px`,\n top: `${pixelY}px`,\n cursor: onClick ? 'pointer' : 'default',\n zIndex: 10,\n pointerEvents: 'auto',\n ...appliedStyle,\n }}\n >\n {children}\n </Box>\n );\n};\n\nexport const DashboardCard = styled(Box)<{ svgX: number; svgY: number; cardType?: string }>(\n ({ svgX, svgY, cardType }) => ({\n position: 'absolute',\n left: svgX,\n top: svgY,\n background:\n cardType === 'critical'\n ? 'linear-gradient(135deg, rgba(220, 53, 69, 0.95) 0%, rgba(173, 20, 87, 0.95) 100%)'\n : cardType === 'warning'\n ? 'linear-gradient(135deg, rgba(255, 193, 7, 0.95) 0%, rgba(255, 143, 0, 0.95) 100%)'\n : cardType === 'vessel'\n ? 'linear-gradient(135deg, rgba(46, 204, 113, 0.95) 0%, rgba(39, 174, 96, 0.95) 100%)'\n : cardType === 'process'\n ? 'linear-gradient(135deg, rgba(155, 89, 182, 0.95) 0%, rgba(142, 68, 173, 0.95) 100%)'\n : cardType === 'control'\n ? 'linear-gradient(135deg, rgba(26, 188, 156, 0.95) 0%, rgba(22, 160, 133, 0.95) 100%)'\n : 'linear-gradient(135deg, rgba(52, 152, 219, 0.95) 0%, rgba(41, 128, 185, 0.95) 100%)',\n border: '1px solid rgba(255, 255, 255, 0.2)',\n borderRadius: '12px',\n padding: '12px',\n minWidth: '140px',\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3)',\n backdropFilter: 'blur(10px)',\n color: 'white',\n fontSize: '12px',\n fontWeight: '600',\n textAlign: 'center',\n transform: 'translate(-50%, -50%)',\n transition: 'all 0.3s ease-in-out',\n cursor: 'pointer',\n '&:hover': {\n transform: 'translate(-50%, -50%) scale(1.05)',\n boxShadow: '0 12px 40px rgba(0, 0, 0, 0.4)',\n },\n })\n);\n\nexport const CardHeader = styled('div')<{ color?: string }>(({ color }) => ({\n fontSize: '10px',\n opacity: 0.9,\n marginBottom: '4px',\n textTransform: 'uppercase',\n letterSpacing: '0.5px',\n color: color || 'inherit',\n borderBottom: color ? `1px solid ${color}40` : 'none',\n paddingBottom: color ? '2px' : '0',\n}));\n\nexport const CardValue = styled('div')({\n fontSize: '16px',\n fontWeight: '700',\n marginBottom: '2px',\n});\n\nexport const CardUnit = styled('div')({\n fontSize: '9px',\n opacity: 0.8,\n});\n\n","import type {\n CircularGaugeProps,\n EquipmentIndicatorProps,\n EquipmentIndicatorWithSparklineProps,\n SparklineProps,\n TrendLineProps,\n} from './types';\nimport { SVGLockedOverlay } from './FullscreenWorkspace.overlays';\n\nexport const TrendLine = ({\n values,\n width = 60,\n height = 20,\n color = '#4fc3f7',\n strokeWidth = 1.5,\n backgroundColor = 'rgba(255, 255, 255, 0.1)',\n}: TrendLineProps) => {\n if (!values || values.length < 2) {\n return (\n <div\n style={{\n width,\n height,\n backgroundColor,\n borderRadius: '2px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <span style={{ fontSize: '8px', color: '#ccc' }}>No data</span>\n </div>\n );\n }\n\n const minValue = Math.min(...values);\n const maxValue = Math.max(...values);\n const range = maxValue - minValue;\n\n const normalizedValues =\n range === 0\n ? values.map(() => height / 2)\n : values.map((v) => height - 4 - ((v - minValue) / range) * (height - 8));\n\n const pathData = normalizedValues\n .map((y, i) => {\n const x = 4 + (i / (values.length - 1)) * (width - 8);\n return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;\n })\n .join(' ');\n\n return (\n <div\n style={{\n width,\n height,\n backgroundColor,\n borderRadius: '2px',\n position: 'relative',\n overflow: 'hidden',\n }}\n >\n <svg width={width} height={height} style={{ position: 'absolute', top: 0, left: 0 }}>\n <path\n d={pathData}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <circle\n cx={4 + (width - 8)}\n cy={normalizedValues[normalizedValues.length - 1]}\n r={1.5}\n fill={color}\n />\n </svg>\n </div>\n );\n};\n\nconst hexToRgba = (hex: string, alpha: number) => {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n};\n\nexport const CircularGauge = ({\n value,\n max,\n unit,\n label,\n size = 60,\n color = 'rgba(255, 255, 255, 0.9)',\n}: CircularGaugeProps) => {\n const percentage = Math.min((value / max) * 100, 100);\n const strokeWidth = 4;\n const radius = (size - strokeWidth) / 2;\n const circumference = radius * 2 * Math.PI;\n const strokeDasharray = circumference;\n const strokeDashoffset = circumference - (percentage / 100) * circumference;\n\n const isHex = color.startsWith('#');\n const innerCircleColor = isHex ? hexToRgba(color, 0.8) : color;\n const borderColor = isHex ? hexToRgba(color, 0.9) : color;\n const backgroundColor = isHex ? hexToRgba(color, 0.15) : color;\n const borderStrokeColor = isHex ? hexToRgba(color, 0.4) : color;\n\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n }}\n >\n <div\n style={{\n position: 'relative',\n width: size,\n height: size,\n borderRadius: '50%',\n backgroundColor,\n border: `1px solid ${borderStrokeColor}`,\n }}\n >\n <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius - strokeWidth - 2}\n fill={innerCircleColor}\n stroke={borderColor}\n strokeWidth={1}\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n stroke=\"rgba(255, 255, 255, 0.2)\"\n strokeWidth={strokeWidth}\n fill=\"transparent\"\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n stroke={color}\n strokeWidth={strokeWidth}\n fill=\"transparent\"\n strokeDasharray={strokeDasharray}\n strokeDashoffset={strokeDashoffset}\n strokeLinecap=\"round\"\n style={{ transition: 'stroke-dashoffset 0.5s ease-in-out' }}\n />\n </svg>\n <div\n style={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n fontSize: '11px',\n fontWeight: '700',\n color: 'white',\n textAlign: 'center',\n textShadow: '0 1px 2px rgba(0, 0, 0, 0.5)',\n }}\n >\n {value.toFixed(1)}\n <div style={{ fontSize: '8px', opacity: 0.9, color: 'white' }}>{unit}</div>\n </div>\n </div>\n <div\n style={{\n fontSize: '9px',\n marginTop: '4px',\n opacity: 0.9,\n color: 'white',\n }}\n >\n {label}\n </div>\n </div>\n );\n};\n\nexport const Sparkline = ({ data, width, height, color }: SparklineProps) => {\n if (!data || data.length < 2) {\n return null;\n }\n\n const max = Math.max(...data);\n const min = Math.min(...data);\n const range = max - min;\n\n if (range === 0) {\n return null;\n }\n\n const points = data\n .map((value, index) => {\n const x = (index / (data.length - 1)) * (width - 8);\n const y = height - 8 - ((value - min) / range) * (height - 8);\n return `${x + 4},${y + 4}`;\n })\n .join(' ');\n\n return (\n <div\n style={{\n width,\n height,\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n border: '1px solid rgba(255, 255, 255, 0.3)',\n borderRadius: '4px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 1px 3px rgba(0, 0, 0, 0.2)',\n }}\n >\n <svg width={width} height={height}>\n <polyline points={points} fill=\"none\" stroke={color} strokeWidth=\"1.5\" opacity=\"0.9\" />\n </svg>\n </div>\n );\n};\n\nexport const EquipmentIndicatorWithSparkline = ({\n svgX,\n svgY,\n color,\n label,\n size = 30,\n sparklineData,\n sparklineOffset = { x: 40, y: 0 },\n}: EquipmentIndicatorWithSparklineProps) => {\n const hasSparkline =\n sparklineData &&\n sparklineData.length > 1 &&\n Math.max(...sparklineData) !== Math.min(...sparklineData);\n\n return (\n <>\n <SVGLockedOverlay svgX={svgX} svgY={svgY} style={{ transform: 'translate(-50%, -50%)' }}>\n <div\n style={{\n width: size,\n height: size,\n borderRadius: '50%',\n backgroundColor: color,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'white',\n fontSize: '7px',\n fontWeight: '700',\n textAlign: 'center',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n border: '2px solid rgba(255, 255, 255, 0.3)',\n }}\n >\n {label}\n </div>\n </SVGLockedOverlay>\n\n {hasSparkline && (\n <SVGLockedOverlay svgX={svgX + sparklineOffset.x} svgY={svgY + sparklineOffset.y}>\n <Sparkline data={sparklineData!} width={60} height={20} color={color} />\n </SVGLockedOverlay>\n )}\n </>\n );\n};\n\nexport const EquipmentIndicator = ({\n svgX,\n svgY,\n color,\n label,\n size = 30,\n style,\n className,\n}: EquipmentIndicatorProps) => {\n const overlayStyle =\n style !== undefined\n ? { transform: 'translate(-50%, -50%)', ...style }\n : { transform: 'translate(-50%, -50%)' };\n\n return (\n <SVGLockedOverlay svgX={svgX} svgY={svgY} style={overlayStyle} className={className}>\n <div\n style={{\n width: size,\n height: size,\n borderRadius: '50%',\n backgroundColor: color,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'white',\n fontSize: '7px',\n fontWeight: '700',\n textAlign: 'center',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n border: '2px solid rgba(255, 255, 255, 0.3)',\n }}\n >\n {label}\n </div>\n </SVGLockedOverlay>\n );\n};\n","import React, { createContext, useContext, useState, useEffect } from 'react';\r\n\r\ntype Theme = 'modern' | 'hmi';\r\n\r\ninterface ThemeContextType {\r\n theme: Theme;\r\n toggleTheme: () => void;\r\n setTheme: (theme: Theme) => void;\r\n}\r\n\r\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined);\r\n\r\nexport const useTheme = () => {\r\n const context = useContext(ThemeContext);\r\n if (!context) {\r\n throw new Error('useTheme must be used within a ThemeProvider');\r\n }\r\n return context;\r\n};\r\n\r\ninterface ThemeProviderProps {\r\n children: React.ReactNode;\r\n}\r\n\r\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {\r\n const [theme, setThemeState] = useState<Theme>('modern');\r\n\r\n useEffect(() => {\r\n // Apply theme classes to document body\r\n document.body.className = '';\r\n document.body.classList.add(`theme-${theme}`);\r\n\r\n // Also apply to html element for global styling\r\n document.documentElement.className = '';\r\n document.documentElement.classList.add(`theme-${theme}`);\r\n }, [theme]);\r\n\r\n const toggleTheme = () => {\r\n setTheme(theme === 'modern' ? 'hmi' : 'modern');\r\n };\r\n\r\n const setTheme = (newTheme: Theme) => {\r\n setThemeState(newTheme);\r\n };\r\n\r\n return (\r\n <ThemeContext.Provider value={{ theme, toggleTheme, setTheme }}>\r\n {children}\r\n </ThemeContext.Provider>\r\n );\r\n};\r\n","import React from 'react';\r\nimport { useTheme } from './ThemeContext';\r\n\r\nexport interface ThemeToggleProps extends React.HTMLAttributes<HTMLDivElement> {\r\n /** Size of the toggle */\r\n size?: 'small' | 'medium' | 'large';\r\n /** Position of the toggle */\r\n position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'inline';\r\n}\r\n\r\nexport const ThemeToggle: React.FC<ThemeToggleProps> = ({\r\n size = 'medium',\r\n position = 'top-right',\r\n className = '',\r\n ...props\r\n}) => {\r\n const { theme, toggleTheme } = useTheme();\r\n\r\n const sizeStyles = {\r\n small: { padding: '0.5rem 1rem', fontSize: '0.75rem' },\r\n medium: { padding: '0.75rem 1.5rem', fontSize: '0.875rem' },\r\n large: { padding: '1rem 2rem', fontSize: '1rem' },\r\n };\r\n\r\n const positionStyles = {\r\n 'top-left': { position: 'fixed' as const, top: '1rem', left: '1rem', zIndex: 1000 },\r\n 'top-right': { position: 'fixed' as const, top: '1rem', right: '1rem', zIndex: 1000 },\r\n 'bottom-left': { position: 'fixed' as const, bottom: '1rem', left: '1rem', zIndex: 1000 },\r\n 'bottom-right': { position: 'fixed' as const, bottom: '1rem', right: '1rem', zIndex: 1000 },\r\n inline: { position: 'relative' as const },\r\n };\r\n\r\n const baseStyle: React.CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '0.75rem',\r\n cursor: 'pointer',\r\n borderRadius: '0.5rem',\r\n border: '2px solid',\r\n fontFamily:\r\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace',\r\n fontWeight: 600,\r\n textTransform: 'uppercase',\r\n letterSpacing: '0.05em',\r\n transition: 'all 0.2s ease',\r\n userSelect: 'none',\r\n ...sizeStyles[size],\r\n ...positionStyles[position],\r\n };\r\n\r\n const modernStyle: React.CSSProperties = {\r\n ...baseStyle,\r\n background: 'linear-gradient(135deg, #3b82f6 0%, #2563eb 50%, #1d4ed8 100%)',\r\n borderColor: 'rgba(59, 130, 246, 0.4)',\r\n color: '#ffffff',\r\n boxShadow: '0 8px 32px rgba(59, 130, 246, 0.3)',\r\n };\r\n\r\n const hmiStyle: React.CSSProperties = {\r\n ...baseStyle,\r\n backgroundColor: '#666666',\r\n borderColor: '#999999',\r\n color: '#ffffff',\r\n boxShadow: 'none',\r\n };\r\n\r\n const currentStyle = theme === 'modern' ? modernStyle : hmiStyle;\r\n\r\n const toggleStyle: React.CSSProperties = {\r\n position: 'relative',\r\n width: '3rem',\r\n height: '1.5rem',\r\n borderRadius: '0.75rem',\r\n transition: 'all 0.2s ease',\r\n backgroundColor: theme === 'modern' ? '#3b82f6' : '#808080',\r\n border: `2px solid ${theme === 'modern' ? '#2563eb' : '#666666'}`,\r\n };\r\n\r\n const thumbStyle: React.CSSProperties = {\r\n position: 'absolute',\r\n top: '0.125rem',\r\n left: theme === 'modern' ? '0.125rem' : '1.375rem',\r\n width: '1rem',\r\n height: '1rem',\r\n borderRadius: '50%',\r\n backgroundColor: '#ffffff',\r\n transition: 'all 0.2s ease',\r\n boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',\r\n };\r\n\r\n return (\r\n <div style={currentStyle} onClick={toggleTheme} className={className} {...props}>\r\n <span>{theme === 'modern' ? '🎨 Modern' : '🏭 HMI'}</span>\r\n <div style={toggleStyle}>\r\n <div style={thumbStyle} />\r\n </div>\r\n <span style={{ fontSize: '0.75rem', opacity: 0.8 }}>\r\n {theme === 'modern' ? 'Industrial Design' : 'High Performance'}\r\n </span>\r\n </div>\r\n );\r\n};\r\n","import React, { useCallback, useState, useEffect } from 'react';\r\nimport type { Diagram } from '../../diagram/schema';\r\nimport type { TelemetryMap } from '../../diagram/schema';\r\nimport { NodeRenderer } from './NodeRenderer';\r\nimport { PipeRenderer } from './PipeRenderer';\r\nimport { DataOverlay } from './DataOverlay';\r\nimport { useViewBox, useSelection, useDrag, useKeyboardShortcuts } from '../../diagram/hooks';\r\nimport type { SelectionState } from '../../diagram/hooks';\r\nimport { getSymbolDefinition } from '../../diagram/symbols';\r\nimport { generateRoutePoints, getPortWorldPosition } from '../../diagram/utils/portCalculations';\r\n\r\nexport interface PIDCanvasFeatures {\r\n /** Enable pan interaction (default: true) */\r\n pan?: boolean;\r\n /** Enable zoom interaction (default: true) */\r\n zoom?: boolean;\r\n /** Enable selection interaction (default: false) */\r\n selection?: boolean;\r\n /** Allow multi-selection with Ctrl/Cmd key (default: true) */\r\n multiSelect?: boolean;\r\n /** Enable telemetry data overlays (default: false) */\r\n telemetry?: boolean;\r\n /** Enable drag-and-drop for nodes (default: false) */\r\n dragNodes?: boolean;\r\n /** Snap dragged nodes to grid (0 = no snap) */\r\n snapToGrid?: number;\r\n /** Enable keyboard shortcuts for delete/copy/paste (default: false) */\r\n keyboardShortcuts?: boolean;\r\n /** Enable pipe waypoint editing (drag waypoints, add/remove) (default: false) */\r\n editPipeRoutes?: boolean;\r\n /** Enable dropping symbols from library to add nodes (default: false) */\r\n allowSymbolDrop?: boolean;\r\n /** Enable connection drawing mode to create pipes between nodes (default: false) */\r\n connectionMode?: boolean;\r\n /** Show background grid (default: true) */\r\n showGrid?: boolean;\r\n /** Background color for canvas (default: '#ffffff') */\r\n backgroundColor?: string;\r\n}\r\n\r\nexport interface PIDCanvasProps extends React.HTMLAttributes<HTMLDivElement> {\r\n /** The diagram to render */\r\n diagram: Diagram;\r\n /** Optional className for the container */\r\n className?: string;\r\n /** Optional inline styles for the container */\r\n style?: React.CSSProperties;\r\n /** Enable interactive features (pan, zoom, selection, telemetry, dragNodes) */\r\n features?: PIDCanvasFeatures;\r\n /** Callback when selection changes */\r\n onSelectionChange?: (selection: SelectionState) => void;\r\n /** Callback when a node is clicked */\r\n onNodeClick?: (nodeId: string) => void;\r\n /** Callback when a pipe is clicked */\r\n onPipeClick?: (pipeId: string) => void;\r\n /** Callback when a node is moved (drag-and-drop) */\r\n onNodeMove?: (nodeId: string, newX: number, newY: number) => void;\r\n /** Callback when diagram changes (for internal state updates) */\r\n onDiagramChange?: (diagram: Diagram) => void;\r\n /** Callback when items are deleted */\r\n onDelete?: (nodeIds: string[], pipeIds: string[]) => void;\r\n /** Callback when items are copied (returns copied data for external storage) */\r\n onItemsCopied?: (nodeIds: string[], pipeIds: string[]) => void;\r\n /** Callback when paste is requested (external code should handle the paste logic) */\r\n onPaste?: () => void;\r\n /** Callback when a symbol is dropped onto canvas (returns symbol ID and position) */\r\n onSymbolDrop?: (symbolId: string, position: { x: number; y: number }) => void;\r\n /** Callback when a pipe is created via connection mode */\r\n onPipeCreated?: (\r\n sourceNodeId: string,\r\n targetNodeId: string,\r\n sourcePortId?: string,\r\n targetPortId?: string\r\n ) => void;\r\n /** Telemetry data bindings for live values */\r\n telemetry?: TelemetryMap;\r\n}\r\n\r\n/**\r\n * PIDCanvas - Interactive canvas for rendering P&ID diagrams\r\n *\r\n * Features:\r\n * - Renders nodes (PR #3) and pipes (PR #4) with static layout\r\n * - Drag-and-drop: Drag nodes to reposition (PR #8)\r\n *\r\n * Future: Editing tools, symbol library UI\r\n */\r\nexport function PIDCanvas({\r\n diagram,\r\n className = '',\r\n style,\r\n features = {\r\n pan: true,\r\n zoom: true,\r\n selection: false,\r\n multiSelect: true,\r\n telemetry: false,\r\n dragNodes: false,\r\n },\r\n onSelectionChange,\r\n onNodeClick,\r\n onPipeClick,\r\n onNodeMove,\r\n onDiagramChange,\r\n onDelete,\r\n onItemsCopied,\r\n onPaste,\r\n onSymbolDrop,\r\n onPipeCreated,\r\n telemetry,\r\n ...props\r\n}: PIDCanvasProps): React.ReactElement {\r\n const [localDiagram, setLocalDiagram] = useState(diagram);\r\n const [dragOverPosition, setDragOverPosition] = useState<{ x: number; y: number } | null>(null);\r\n\r\n // Connection mode state\r\n const [isConnecting, setIsConnecting] = useState(false);\r\n const [connectionSource, setConnectionSource] = useState<string | null>(null);\r\n const [connectionSourcePort, setConnectionSourcePort] = useState<string | null>(null);\r\n const [connectionCursor, setConnectionCursor] = useState<{ x: number; y: number } | null>(null);\r\n const [hoveredNode, setHoveredNode] = useState<string | null>(null);\r\n const [hoveredPort, setHoveredPort] = useState<string | null>(null);\r\n\r\n // Sync external diagram changes to local state\r\n useEffect(() => {\r\n setLocalDiagram(diagram);\r\n }, [diagram]);\r\n\r\n const {\r\n viewBox: controlledViewBox,\r\n svgRef,\r\n screenToWorld,\r\n } = useViewBox({\r\n initialViewBox: diagram.viewBox,\r\n enablePan: features.pan ?? true,\r\n enableZoom: features.zoom ?? true,\r\n });\r\n\r\n const { selection, selectNode, selectPipe, clearSelection } = useSelection({\r\n multiSelect: features.multiSelect ?? true,\r\n onSelectionChange,\r\n });\r\n\r\n const dragEnabled = features.dragNodes ?? false;\r\n const selectionEnabled = features.selection ?? false;\r\n\r\n const handleDragEnd = useCallback(\r\n (nodeId: string, offset: { x: number; y: number }, finalPosition: { x: number; y: number }) => {\r\n // If drag offset is zero or very small, treat as a click for selection\r\n const dragDistance = Math.sqrt(offset.x ** 2 + offset.y ** 2);\r\n if (dragDistance < 2) {\r\n // This was a click, not a drag - handle selection\r\n if (selectionEnabled) {\r\n // We need to check if this was a Ctrl/Cmd click, but we don't have the event here\r\n // For now, just select without modifier\r\n selectNode(nodeId, false);\r\n }\r\n return;\r\n }\r\n\r\n // Update node position in diagram\r\n const updatedNodes = localDiagram.nodes.map((node) =>\r\n node.id === nodeId\r\n ? {\r\n ...node,\r\n transform: {\r\n ...node.transform,\r\n x: finalPosition.x,\r\n y: finalPosition.y,\r\n },\r\n }\r\n : node\r\n );\r\n\r\n // Find affected pipes (pipes connected to this node)\r\n const affectedPipes = localDiagram.pipes.filter(\r\n (pipe) => pipe.fromNodeId === nodeId || pipe.toNodeId === nodeId\r\n );\r\n\r\n // Recalculate routes for affected pipes\r\n const updatedPipes = localDiagram.pipes.map((pipe) => {\r\n if (!affectedPipes.find((p) => p.id === pipe.id)) return pipe;\r\n\r\n const sourceNode = updatedNodes.find((n) => n.id === pipe.fromNodeId);\r\n const targetNode = updatedNodes.find((n) => n.id === pipe.toNodeId);\r\n\r\n if (!sourceNode || !targetNode) return pipe;\r\n\r\n // If pipe has custom waypoints (more than 2 points), preserve ALL waypoints\r\n // including endpoints - user has manually positioned them\r\n if (pipe.routePoints.length > 2) {\r\n return pipe; // Keep all waypoints as-is, including endpoints\r\n }\r\n\r\n // For simple pipes (2 points), recalculate to follow node ports\r\n const newRoutePoints = generateRoutePoints(\r\n sourceNode,\r\n pipe.fromPortId ?? 'output',\r\n targetNode,\r\n pipe.toPortId ?? 'input'\r\n );\r\n\r\n return {\r\n ...pipe,\r\n routePoints: newRoutePoints,\r\n };\r\n });\r\n\r\n const updatedDiagram: Diagram = {\r\n ...localDiagram,\r\n nodes: updatedNodes,\r\n pipes: updatedPipes,\r\n };\r\n\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n onNodeMove?.(nodeId, finalPosition.x, finalPosition.y);\r\n },\r\n [localDiagram, onDiagramChange, onNodeMove, selectionEnabled, selectNode]\r\n );\r\n\r\n const { dragState, startDrag } = useDrag({\r\n snapToGrid: features.snapToGrid ?? 0,\r\n screenToWorld,\r\n onDragEnd: handleDragEnd,\r\n });\r\n\r\n // Separate drag state for waypoints\r\n const { dragState: waypointDragState, startDrag: startWaypointDrag } = useDrag({\r\n snapToGrid: features.snapToGrid ?? 0,\r\n screenToWorld,\r\n onDragEnd: (\r\n pipeId: string,\r\n _offset: { x: number; y: number },\r\n finalPosition: { x: number; y: number }\r\n ) => {\r\n // Update waypoint position\r\n const [actualPipeId, pointIndex] = pipeId.split(':');\r\n const idx = parseInt(pointIndex, 10);\r\n\r\n const updatedPipes = localDiagram.pipes.map((pipe) => {\r\n if (pipe.id !== actualPipeId) return pipe;\r\n\r\n const updatedRoutePoints = pipe.routePoints.map((point, i) =>\r\n i === idx ? { x: finalPosition.x, y: finalPosition.y } : point\r\n );\r\n\r\n return { ...pipe, routePoints: updatedRoutePoints };\r\n });\r\n\r\n const updatedDiagram = { ...localDiagram, pipes: updatedPipes };\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n },\r\n });\r\n\r\n const handleNodeDragStart = useCallback(\r\n (nodeId: string, event: React.MouseEvent | React.TouchEvent) => {\r\n const node = localDiagram.nodes.find((n) => n.id === nodeId);\r\n if (!node) return;\r\n startDrag(nodeId, event, { x: node.transform.x, y: node.transform.y });\r\n },\r\n [localDiagram.nodes, startDrag]\r\n );\r\n\r\n const handleWaypointDragStart = useCallback(\r\n (pipeId: string, pointIndex: number, event: React.MouseEvent | React.TouchEvent) => {\r\n const pipe = localDiagram.pipes.find((p) => p.id === pipeId);\r\n if (!pipe || pointIndex >= pipe.routePoints.length) return;\r\n\r\n const point = pipe.routePoints[pointIndex];\r\n // Use compound ID to track both pipe and point\r\n startWaypointDrag(`${pipeId}:${pointIndex}`, event, { x: point.x, y: point.y });\r\n },\r\n [localDiagram.pipes, startWaypointDrag]\r\n );\r\n\r\n const handlePipeSegmentClick = useCallback(\r\n (pipeId: string, position: { x: number; y: number }, segmentIndex: number) => {\r\n const updatedPipes = localDiagram.pipes.map((pipe) => {\r\n if (pipe.id !== pipeId) return pipe;\r\n\r\n // Insert new waypoint after segmentIndex\r\n const updatedRoutePoints = [\r\n ...pipe.routePoints.slice(0, segmentIndex + 1),\r\n position,\r\n ...pipe.routePoints.slice(segmentIndex + 1),\r\n ];\r\n\r\n return { ...pipe, routePoints: updatedRoutePoints };\r\n });\r\n\r\n const updatedDiagram = { ...localDiagram, pipes: updatedPipes };\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n },\r\n [localDiagram, onDiagramChange]\r\n );\r\n\r\n const telemetryEnabled = features.telemetry ?? false;\r\n\r\n const handleDelete = useCallback(() => {\r\n if (!selectionEnabled) return;\r\n const { selectedNodeIds, selectedPipeIds } = selection;\r\n\r\n if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;\r\n\r\n // Remove selected nodes\r\n const updatedNodes = localDiagram.nodes.filter((node) => !selectedNodeIds.has(node.id));\r\n\r\n // Remove selected pipes and pipes connected to deleted nodes\r\n const updatedPipes = localDiagram.pipes.filter(\r\n (pipe) =>\r\n !selectedPipeIds.has(pipe.id) &&\r\n !selectedNodeIds.has(pipe.fromNodeId) &&\r\n !selectedNodeIds.has(pipe.toNodeId)\r\n );\r\n\r\n const updatedDiagram = {\r\n ...localDiagram,\r\n nodes: updatedNodes,\r\n pipes: updatedPipes,\r\n };\r\n\r\n setLocalDiagram(updatedDiagram);\r\n clearSelection();\r\n onDiagramChange?.(updatedDiagram);\r\n onDelete?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));\r\n }, [selection, localDiagram, selectionEnabled, clearSelection, onDiagramChange, onDelete]);\r\n\r\n const handleCopy = useCallback(() => {\r\n if (!selectionEnabled) return;\r\n const { selectedNodeIds, selectedPipeIds } = selection;\r\n\r\n if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;\r\n\r\n onItemsCopied?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));\r\n }, [selection, selectionEnabled, onItemsCopied]);\r\n\r\n const handlePaste = useCallback(() => {\r\n if (!selectionEnabled) return;\r\n onPaste?.();\r\n }, [selectionEnabled, onPaste]);\r\n\r\n const handleNodeDoubleClick = (nodeId: string, event: React.MouseEvent) => {\r\n if (!selectionEnabled) return;\r\n console.log('Node double-clicked:', nodeId);\r\n selectNode(nodeId, event.ctrlKey || event.metaKey);\r\n };\r\n\r\n useKeyboardShortcuts({\r\n enabled: features.keyboardShortcuts ?? false,\r\n onDelete: handleDelete,\r\n onCopy: handleCopy,\r\n onPaste: handlePaste,\r\n });\r\n\r\n const handleNodeClick = (nodeId: string, event: React.MouseEvent) => {\r\n // Connection mode takes priority\r\n const connectionModeEnabled = features.connectionMode ?? false;\r\n\r\n if (connectionModeEnabled && isConnecting) {\r\n // Second click - complete connection\r\n if (connectionSource && connectionSource !== nodeId) {\r\n // Use hovered port if available, otherwise let handler choose\r\n onPipeCreated?.(\r\n connectionSource,\r\n nodeId,\r\n connectionSourcePort || undefined,\r\n hoveredPort || undefined\r\n );\r\n setIsConnecting(false);\r\n setConnectionSource(null);\r\n setConnectionSourcePort(null);\r\n setConnectionCursor(null);\r\n setHoveredPort(null);\r\n }\r\n return;\r\n }\r\n\r\n if (connectionModeEnabled && !isConnecting) {\r\n // First click - start connection\r\n setIsConnecting(true);\r\n setConnectionSource(nodeId);\r\n setConnectionSourcePort(hoveredPort);\r\n return;\r\n }\r\n\r\n // Normal selection mode\r\n if (selectionEnabled) {\r\n selectNode(nodeId, event.ctrlKey || event.metaKey);\r\n }\r\n onNodeClick?.(nodeId);\r\n };\r\n\r\n const handlePipeClick = (pipeId: string, event: React.MouseEvent) => {\r\n if (selectionEnabled) {\r\n selectPipe(pipeId, event.ctrlKey || event.metaKey);\r\n }\r\n onPipeClick?.(pipeId);\r\n };\r\n\r\n const handleCanvasClick = () => {\r\n if (selectionEnabled) {\r\n clearSelection();\r\n }\r\n };\r\n\r\n const handleDragOver = useCallback(\r\n (event: React.DragEvent) => {\r\n if (!features.allowSymbolDrop) return;\r\n\r\n event.preventDefault();\r\n event.dataTransfer.dropEffect = 'copy';\r\n\r\n // Convert screen coordinates to world coordinates\r\n if (!svgRef.current) return;\r\n\r\n const worldPos = screenToWorld(event.clientX, event.clientY);\r\n\r\n setDragOverPosition(worldPos);\r\n },\r\n [features.allowSymbolDrop, screenToWorld]\r\n );\r\n\r\n const handleDrop = useCallback(\r\n (event: React.DragEvent) => {\r\n if (!features.allowSymbolDrop) return;\r\n\r\n event.preventDefault();\r\n setDragOverPosition(null);\r\n\r\n // Get symbol ID from drag data\r\n const symbolId = event.dataTransfer.getData('application/symbol-id');\r\n if (!symbolId) return;\r\n\r\n // Convert drop position to world coordinates\r\n if (!svgRef.current) return;\r\n const worldPos = screenToWorld(event.clientX, event.clientY);\r\n\r\n onSymbolDrop?.(symbolId, worldPos);\r\n },\r\n [features.allowSymbolDrop, screenToWorld, onSymbolDrop]\r\n );\r\n\r\n const handleDragLeave = useCallback(() => {\r\n setDragOverPosition(null);\r\n }, []);\r\n\r\n const handleMouseMove = useCallback(\r\n (event: React.MouseEvent<SVGSVGElement>) => {\r\n const connectionModeEnabled = features.connectionMode ?? false;\r\n\r\n if (connectionModeEnabled) {\r\n const worldPos = screenToWorld(event.clientX, event.clientY);\r\n\r\n // Update cursor position if connecting\r\n if (isConnecting && connectionSource) {\r\n setConnectionCursor(worldPos);\r\n }\r\n\r\n // Always track hovered port in connection mode (for both source and target selection)\r\n let foundPort: string | null = null;\r\n let foundNode: string | null = null;\r\n\r\n for (const node of localDiagram.nodes) {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol || !symbol.ports) continue;\r\n\r\n for (const port of symbol.ports) {\r\n const portPos = getPortWorldPosition(node, port.id);\r\n if (!portPos) continue;\r\n\r\n const distance = Math.sqrt(\r\n (worldPos.x - portPos.x) ** 2 + (worldPos.y - portPos.y) ** 2\r\n );\r\n\r\n if (distance < 10) {\r\n foundPort = port.id;\r\n foundNode = node.id;\r\n break;\r\n }\r\n }\r\n if (foundPort) break;\r\n }\r\n\r\n setHoveredPort(foundPort);\r\n setHoveredNode(foundNode);\r\n }\r\n },\r\n [isConnecting, connectionSource, screenToWorld, localDiagram.nodes, features.connectionMode]\r\n );\r\n\r\n const { name } = diagram;\r\n const viewBox = controlledViewBox;\r\n const displayDiagram = localDiagram;\r\n\r\n return (\r\n <div\r\n className={`pid-canvas ${className}`.trim()}\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n position: 'relative',\r\n overflow: 'hidden',\r\n backgroundColor: '#f5f5f5',\r\n ...style,\r\n }}\r\n {...props}\r\n >\r\n <svg\r\n ref={svgRef}\r\n width=\"100%\"\r\n height=\"100%\"\r\n viewBox={`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`}\r\n preserveAspectRatio=\"xMidYMid meet\"\r\n style={{\r\n display: 'block',\r\n }}\r\n aria-label={`P&ID diagram: ${name}`}\r\n role=\"img\"\r\n onClick={handleCanvasClick}\r\n onMouseMove={handleMouseMove}\r\n onDragOver={handleDragOver}\r\n onDrop={handleDrop}\r\n onDragLeave={handleDragLeave}\r\n >\r\n {/* Background - solid color or grid */}\r\n {features.showGrid !== false ? (\r\n <>\r\n <defs>\r\n {/* Minor grid - 5 unit increments */}\r\n <pattern id=\"grid-minor\" width=\"5\" height=\"5\" patternUnits=\"userSpaceOnUse\">\r\n <path d=\"M 5 0 L 0 0 0 5\" fill=\"none\" stroke=\"#e5e7eb\" strokeWidth=\"0.5\" />\r\n </pattern>\r\n {/* Major grid - 25 unit increments */}\r\n <pattern id=\"grid-major\" width=\"25\" height=\"25\" patternUnits=\"userSpaceOnUse\">\r\n <rect width=\"25\" height=\"25\" fill=\"url(#grid-minor)\" />\r\n <path d=\"M 25 0 L 0 0 0 25\" fill=\"none\" stroke=\"#d1d5db\" strokeWidth=\"1\" />\r\n </pattern>\r\n </defs>\r\n <rect\r\n x={Math.floor(viewBox.x / 25) * 25 - viewBox.width}\r\n y={Math.floor(viewBox.y / 25) * 25 - viewBox.height}\r\n width={Math.ceil((viewBox.width * 3) / 25) * 25}\r\n height={Math.ceil((viewBox.height * 3) / 25) * 25}\r\n fill=\"url(#grid-major)\"\r\n />\r\n </>\r\n ) : (\r\n <rect\r\n x={Math.floor(viewBox.x / 25) * 25 - viewBox.width}\r\n y={Math.floor(viewBox.y / 25) * 25 - viewBox.height}\r\n width={Math.ceil((viewBox.width * 3) / 25) * 25}\r\n height={Math.ceil((viewBox.height * 3) / 25) * 25}\r\n fill={features.backgroundColor ?? '#ffffff'}\r\n />\r\n )}\r\n\r\n {/* Render pipes (behind nodes for proper layering) */}\r\n <PipeRenderer\r\n pipes={displayDiagram.pipes}\r\n selectedPipeIds={selectionEnabled ? selection.selectedPipeIds : undefined}\r\n onPipeClick={selectionEnabled ? handlePipeClick : undefined}\r\n enableWaypointEditing={false}\r\n onWaypointDragStart={undefined}\r\n editingPipeId={null}\r\n draggingWaypointIndex={null}\r\n waypointDragOffset={undefined}\r\n onPipeSegmentClick={undefined}\r\n />\r\n\r\n {/* Render nodes */}\r\n <NodeRenderer\r\n nodes={displayDiagram.nodes}\r\n selectedNodeIds={selectionEnabled ? selection.selectedNodeIds : undefined}\r\n onNodeClick={selectionEnabled || features.connectionMode ? handleNodeClick : undefined}\r\n onNodeDoubleClick={selectionEnabled ? handleNodeDoubleClick : undefined}\r\n enableDrag={dragEnabled && !isConnecting}\r\n onNodeDragStart={dragEnabled && !isConnecting ? handleNodeDragStart : undefined}\r\n draggingNodeId={dragState.draggedId}\r\n dragOffset={dragState.offset}\r\n />\r\n\r\n {/* Render waypoint editing controls on top of nodes */}\r\n {(features.editPipeRoutes ?? false) && (\r\n <PipeRenderer\r\n pipes={displayDiagram.pipes}\r\n selectedPipeIds={selectionEnabled ? selection.selectedPipeIds : undefined}\r\n onPipeClick={undefined}\r\n enableWaypointEditing={true}\r\n onWaypointDragStart={handleWaypointDragStart}\r\n editingPipeId={waypointDragState.draggedId?.split(':')[0] || null}\r\n draggingWaypointIndex={\r\n waypointDragState.draggedId\r\n ? parseInt(waypointDragState.draggedId.split(':')[1], 10)\r\n : null\r\n }\r\n waypointDragOffset={waypointDragState.offset}\r\n onPipeSegmentClick={handlePipeSegmentClick}\r\n />\r\n )}\r\n\r\n {/* Render telemetry data overlays */}\r\n {telemetryEnabled && telemetry && (\r\n <g id=\"layer-telemetry\">\r\n {displayDiagram.nodes.map((node) => {\r\n const binding = telemetry.get(node.id);\r\n if (!binding) return null;\r\n\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol) return null;\r\n\r\n // Position overlay above the node\r\n const overlayY = node.transform.y - symbol.viewBox.height / 2 - 10;\r\n\r\n return (\r\n <DataOverlay\r\n key={`telemetry-${node.id}`}\r\n nodeId={node.id}\r\n x={node.transform.x}\r\n y={overlayY}\r\n telemetry={binding}\r\n />\r\n );\r\n })}\r\n </g>\r\n )}\r\n\r\n {/* Drop indicator */}\r\n {dragOverPosition && (\r\n <circle\r\n cx={dragOverPosition.x}\r\n cy={dragOverPosition.y}\r\n r={20}\r\n fill=\"#3b82f6\"\r\n opacity={0.3}\r\n stroke=\"#3b82f6\"\r\n strokeWidth={2}\r\n pointerEvents=\"none\"\r\n />\r\n )}\r\n\r\n {/* Connection mode rubber-band line */}\r\n {isConnecting && connectionSource && connectionCursor && (\r\n <g id=\"connection-preview\" pointerEvents=\"none\">\r\n {(() => {\r\n const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);\r\n if (!sourceNode) return null;\r\n\r\n // If a source port was selected, draw line from that port\r\n const symbol = getSymbolDefinition(sourceNode.symbolId);\r\n let lineStartX = sourceNode.transform.x;\r\n let lineStartY = sourceNode.transform.y;\r\n\r\n if (connectionSourcePort && symbol?.ports) {\r\n const port = symbol.ports.find((p) => p.id === connectionSourcePort);\r\n if (port) {\r\n const portPos = getPortWorldPosition(sourceNode, connectionSourcePort);\r\n if (portPos) {\r\n lineStartX = portPos.x;\r\n lineStartY = portPos.y;\r\n }\r\n }\r\n }\r\n\r\n return (\r\n <>\r\n {/* Highlight source node */}\r\n <circle\r\n cx={sourceNode.transform.x}\r\n cy={sourceNode.transform.y}\r\n r={30}\r\n fill=\"none\"\r\n stroke=\"#10b981\"\r\n strokeWidth={3}\r\n opacity={0.6}\r\n />\r\n {/* Rubber-band line */}\r\n <line\r\n x1={lineStartX}\r\n y1={lineStartY}\r\n x2={connectionCursor.x}\r\n y2={connectionCursor.y}\r\n stroke=\"#10b981\"\r\n strokeWidth={2}\r\n strokeDasharray=\"5,5\"\r\n opacity={0.8}\r\n />\r\n {/* Cursor indicator */}\r\n <circle\r\n cx={connectionCursor.x}\r\n cy={connectionCursor.y}\r\n r={8}\r\n fill=\"#10b981\"\r\n opacity={0.6}\r\n />\r\n </>\r\n );\r\n })()}\r\n </g>\r\n )}\r\n\r\n {/* Port indicators in connection mode */}\r\n {features.connectionMode && (\r\n <g id=\"port-indicators\" pointerEvents=\"none\">\r\n {displayDiagram.nodes.map((node) => {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol?.ports) return null;\r\n\r\n return symbol.ports.map((port) => {\r\n const portPos = getPortWorldPosition(node, port.id);\r\n if (!portPos) return null;\r\n\r\n const isHovered = hoveredPort === port.id && hoveredNode === node.id;\r\n const isSourcePort =\r\n node.id === connectionSource && port.id === connectionSourcePort;\r\n\r\n return (\r\n <circle\r\n key={`${node.id}-${port.id}`}\r\n cx={portPos.x}\r\n cy={portPos.y}\r\n r={isHovered ? 8 : 5}\r\n fill={isSourcePort ? '#10b981' : isHovered ? '#3b82f6' : '#94a3b8'}\r\n stroke={isSourcePort ? '#059669' : isHovered ? '#2563eb' : '#64748b'}\r\n strokeWidth={isHovered || isSourcePort ? 2 : 1}\r\n opacity={isHovered || isSourcePort ? 1 : 0.6}\r\n />\r\n );\r\n });\r\n })}\r\n </g>\r\n )}\r\n </svg>\r\n </div>\r\n );\r\n}\r\n","import type { SymbolDefinition } from '../schema';\r\n\r\n/**\r\n * Mock symbol library with basic P&ID shapes\r\n * Phase 4 will add proper symbol library management\r\n */\r\nexport const mockSymbolLibrary: Record<string, SymbolDefinition> = {\r\n 'valve-ball': {\r\n id: 'valve-ball',\r\n name: 'Ball Valve',\r\n category: 'valve',\r\n viewBox: { x: 0, y: 0, width: 50, height: 50 },\r\n ports: [\r\n { id: 'inlet', x: 0, y: 25, type: 'inlet', direction: 'in' },\r\n { id: 'outlet', x: 50, y: 25, type: 'outlet', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Valve body -->\r\n <rect x=\"15\" y=\"10\" width=\"20\" height=\"30\" fill=\"#546e7a\" stroke=\"#263238\" stroke-width=\"2\" rx=\"2\"/>\r\n <!-- Ball indicator -->\r\n <circle cx=\"25\" cy=\"25\" r=\"6\" fill=\"#ffa726\" stroke=\"#e65100\" stroke-width=\"1.5\"/>\r\n <!-- Inlet/outlet lines -->\r\n <line x1=\"0\" y1=\"25\" x2=\"15\" y2=\"25\" stroke=\"#263238\" stroke-width=\"3\" stroke-linecap=\"round\"/>\r\n <line x1=\"35\" y1=\"25\" x2=\"50\" y2=\"25\" stroke=\"#263238\" stroke-width=\"3\" stroke-linecap=\"round\"/>\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Ball valve for flow control',\r\n tags: ['valve', 'control', 'shutoff'],\r\n },\r\n },\r\n\r\n 'valve-gate': {\r\n id: 'valve-gate',\r\n name: 'Gate Valve (Powered)',\r\n category: 'valve',\r\n viewBox: { x: 0, y: 0, width: 52, height: 52 },\r\n ports: [\r\n { id: 'inlet', x: 0, y: 36, type: 'inlet', direction: 'in' },\r\n { id: 'outlet', x: 52, y: 36, type: 'outlet', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Actuator box -->\r\n <rect x=\"16.74\" y=\"0\" width=\"18.02\" height=\"18.02\" fill=\"#edeeef\" stroke=\"#666666\" pointer-events=\"all\"/>\r\n <!-- Actuator stem -->\r\n <path d=\"M 25.75 18.02 L 25.75 36.05\" fill=\"none\" stroke=\"#666666\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" pointer-events=\"all\"/>\r\n <!-- Valve body (two triangles forming diamond) -->\r\n <path d=\"M 0 20.6 L 25.75 36.05 L 0 51.5 Z M 51.5 20.6 L 25.75 36.05 L 51.5 51.5 Z\" fill=\"#edeeef\" stroke=\"#666666\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" pointer-events=\"all\"/>\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Gate valve with powered actuator',\r\n tags: ['valve', 'gate', 'powered', 'actuator'],\r\n },\r\n },\r\n\r\n 'pump-centrifugal': {\r\n id: 'pump-centrifugal',\r\n name: 'Centrifugal Pump',\r\n category: 'pump',\r\n viewBox: { x: 0, y: 0, width: 80, height: 60 },\r\n ports: [\r\n { id: 'inlet', x: 10, y: 30, type: 'inlet', direction: 'in' },\r\n { id: 'outlet', x: 70, y: 30, type: 'outlet', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Pump casing -->\r\n <circle cx=\"40\" cy=\"30\" r=\"22\" fill=\"#4fc3f7\" stroke=\"#0277bd\" stroke-width=\"2.5\"/>\r\n <!-- Impeller -->\r\n <path d=\"M 40 30 L 50 20 M 40 30 L 50 40 M 40 30 L 30 40 M 40 30 L 30 20\" \r\n stroke=\"#01579b\" stroke-width=\"2.5\" stroke-linecap=\"round\"/>\r\n <!-- Center hub -->\r\n <circle cx=\"40\" cy=\"30\" r=\"5\" fill=\"#0277bd\" stroke=\"#01579b\" stroke-width=\"1.5\"/>\r\n <!-- Inlet pipe -->\r\n <line x1=\"0\" y1=\"30\" x2=\"18\" y2=\"30\" stroke=\"#0277bd\" stroke-width=\"4\" stroke-linecap=\"round\"/>\r\n <!-- Outlet pipe -->\r\n <line x1=\"62\" y1=\"30\" x2=\"80\" y2=\"30\" stroke=\"#0277bd\" stroke-width=\"4\" stroke-linecap=\"round\"/>\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Centrifugal pump for fluid transfer',\r\n tags: ['pump', 'centrifugal', 'transfer'],\r\n },\r\n },\r\n\r\n 'vessel-tank': {\r\n id: 'vessel-tank',\r\n name: 'Storage Tank',\r\n category: 'vessel',\r\n viewBox: { x: 0, y: 0, width: 60, height: 80 },\r\n ports: [\r\n { id: 'inlet', x: 30, y: 10, type: 'inlet', direction: 'in' },\r\n { id: 'outlet', x: 30, y: 70, type: 'outlet', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Tank body -->\r\n <rect x=\"10\" y=\"15\" width=\"40\" height=\"50\" fill=\"#66bb6a\" stroke=\"#2e7d32\" stroke-width=\"2.5\" rx=\"3\"/>\r\n <!-- Tank bottom (rounded) -->\r\n <ellipse cx=\"30\" cy=\"65\" rx=\"20\" ry=\"8\" fill=\"#66bb6a\" stroke=\"#2e7d32\" stroke-width=\"2.5\"/>\r\n <!-- Liquid level indicator -->\r\n <rect x=\"12\" y=\"35\" width=\"36\" height=\"28\" fill=\"#4dd0e1\" opacity=\"0.6\"/>\r\n <!-- Inlet pipe -->\r\n <line x1=\"30\" y1=\"0\" x2=\"30\" y2=\"15\" stroke=\"#2e7d32\" stroke-width=\"3\" stroke-linecap=\"round\"/>\r\n <!-- Outlet pipe -->\r\n <line x1=\"30\" y1=\"65\" x2=\"30\" y2=\"80\" stroke=\"#2e7d32\" stroke-width=\"3\" stroke-linecap=\"round\"/>\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Storage vessel for liquids',\r\n tags: ['vessel', 'tank', 'storage'],\r\n },\r\n },\r\n\r\n 'instrument-indicator': {\r\n id: 'instrument-indicator',\r\n name: 'Instrument Indicator',\r\n category: 'instrument',\r\n viewBox: { x: 0, y: 0, width: 40, height: 40 },\r\n ports: [\r\n { id: 'signal', x: 20, y: 40, type: 'signal', direction: 'bi' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Instrument circle -->\r\n <circle cx=\"20\" cy=\"20\" r=\"15\" fill=\"#fff\" stroke=\"#616161\" stroke-width=\"2\"/>\r\n <!-- Inner circle -->\r\n <circle cx=\"20\" cy=\"20\" r=\"12\" fill=\"none\" stroke=\"#616161\" stroke-width=\"1\"/>\r\n <!-- Signal line -->\r\n <line x1=\"20\" y1=\"35\" x2=\"20\" y2=\"40\" stroke=\"#616161\" stroke-width=\"2\" stroke-linecap=\"round\"/>\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Generic instrument indicator',\r\n tags: ['instrument', 'indicator', 'measurement'],\r\n },\r\n },\r\n};\r\n\r\n/**\r\n * Get symbol definition by ID\r\n */\r\nexport function getSymbolDefinition(symbolId: string): SymbolDefinition | undefined {\r\n return mockSymbolLibrary[symbolId];\r\n}\r\n\r\n/**\r\n * Get all available symbol IDs\r\n */\r\nexport function getAvailableSymbols(): string[] {\r\n return Object.keys(mockSymbolLibrary);\r\n}\r\n","import React from 'react';\r\nimport type { NodeInstance } from '../../diagram/schema';\r\nimport { getSymbolDefinition } from '../../diagram/symbols';\r\n\r\nexport interface NodeRendererProps {\r\n /** Array of node instances to render */\r\n nodes: NodeInstance[];\r\n /** IDs of selected nodes */\r\n selectedNodeIds?: Set<string>;\r\n /** Callback when a node is clicked */\r\n onNodeClick?: (nodeId: string, event: React.MouseEvent) => void;\r\n /** Callback when a node is double-clicked */\r\n onNodeDoubleClick?: (nodeId: string, event: React.MouseEvent) => void;\r\n /** Callback when a node drag starts */\r\n onNodeDragStart?: (nodeId: string, event: React.MouseEvent | React.TouchEvent) => void;\r\n /** ID of node being dragged */\r\n draggingNodeId?: string | null;\r\n /** Drag offset for the dragging node */\r\n dragOffset?: { x: number; y: number };\r\n /** Whether dragging is enabled (default: false) */\r\n enableDrag?: boolean;\r\n}\r\n\r\n/**\r\n * NodeRenderer - Renders symbol instances with transforms and selection support\r\n *\r\n * Applies translate, rotate, and scale transforms to each node\r\n * Supports click selection with visual feedback\r\n */\r\nexport function NodeRenderer({\r\n nodes,\r\n selectedNodeIds,\r\n onNodeClick,\r\n onNodeDoubleClick,\r\n onNodeDragStart,\r\n draggingNodeId,\r\n dragOffset = { x: 0, y: 0 },\r\n enableDrag = false,\r\n}: NodeRendererProps): React.ReactElement {\r\n return (\r\n <g id=\"layer-nodes\">\r\n {nodes\r\n .filter((node) => node.visible !== false) // Filter hidden nodes\r\n .map((node) => {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n const isSelected = selectedNodeIds?.has(node.id) ?? false;\r\n const isDragging = draggingNodeId === node.id;\r\n\r\n if (!symbol) {\r\n // Symbol not found - render placeholder\r\n return (\r\n <g key={node.id}>\r\n <circle\r\n cx={node.transform.x}\r\n cy={node.transform.y}\r\n r=\"15\"\r\n fill=\"#ff0000\"\r\n opacity=\"0.3\"\r\n stroke=\"#ff0000\"\r\n strokeWidth=\"2\"\r\n />\r\n <text\r\n x={node.transform.x}\r\n y={node.transform.y}\r\n textAnchor=\"middle\"\r\n dominantBaseline=\"middle\"\r\n fontSize=\"10\"\r\n fill=\"#ff0000\"\r\n >\r\n ?\r\n </text>\r\n </g>\r\n );\r\n }\r\n\r\n // Build transform string\r\n const transforms: string[] = [];\r\n\r\n // Apply drag offset if this node is being dragged\r\n const effectiveX = isDragging ? node.transform.x + dragOffset.x : node.transform.x;\r\n const effectiveY = isDragging ? node.transform.y + dragOffset.y : node.transform.y;\r\n\r\n // Translate\r\n transforms.push(`translate(${effectiveX}, ${effectiveY})`);\r\n\r\n // Rotate (around center of symbol)\r\n if (node.transform.rotation) {\r\n const centerX = symbol.viewBox.width / 2;\r\n const centerY = symbol.viewBox.height / 2;\r\n transforms.push(`rotate(${node.transform.rotation}, ${centerX}, ${centerY})`);\r\n }\r\n\r\n // Scale\r\n if (node.transform.scale && node.transform.scale !== 1) {\r\n const centerX = symbol.viewBox.width / 2;\r\n const centerY = symbol.viewBox.height / 2;\r\n transforms.push(\r\n `translate(${centerX}, ${centerY}) scale(${node.transform.scale}) translate(${-centerX}, ${-centerY})`\r\n );\r\n }\r\n\r\n // Flip\r\n if (node.transform.flipX || node.transform.flipY) {\r\n const scaleX = node.transform.flipX ? -1 : 1;\r\n const scaleY = node.transform.flipY ? -1 : 1;\r\n const centerX = symbol.viewBox.width / 2;\r\n const centerY = symbol.viewBox.height / 2;\r\n transforms.push(\r\n `translate(${centerX}, ${centerY}) scale(${scaleX}, ${scaleY}) translate(${-centerX}, ${-centerY})`\r\n );\r\n }\r\n\r\n return (\r\n <g\r\n key={node.id}\r\n data-node-id={node.id}\r\n data-symbol-id={node.symbolId}\r\n data-selected={isSelected}\r\n data-dragging={isDragging}\r\n transform={transforms.join(' ')}\r\n onClick={(e) => {\r\n // Always fire onClick - drag system will handle whether to drag\r\n e.stopPropagation();\r\n onNodeClick?.(node.id, e);\r\n }}\r\n onDoubleClick={(e) => {\r\n e.stopPropagation();\r\n onNodeDoubleClick?.(node.id, e);\r\n }}\r\n onMouseDown={(e) => {\r\n if (enableDrag) {\r\n // Don't stop propagation - let click still fire\r\n onNodeDragStart?.(node.id, e);\r\n }\r\n }}\r\n onTouchStart={(e) => {\r\n if (enableDrag) {\r\n e.stopPropagation();\r\n onNodeDragStart?.(node.id, e);\r\n }\r\n }}\r\n style={{\r\n cursor: enableDrag\r\n ? isDragging\r\n ? 'grabbing'\r\n : 'grab'\r\n : onNodeClick\r\n ? 'pointer'\r\n : 'default',\r\n }}\r\n >\r\n {/* Selection indicator - bounding box */}\r\n {isSelected && (\r\n <rect\r\n x=\"-5\"\r\n y=\"-5\"\r\n width={symbol.viewBox.width + 10}\r\n height={symbol.viewBox.height + 10}\r\n fill=\"none\"\r\n stroke={isDragging ? '#10b981' : '#3b82f6'}\r\n strokeWidth={isDragging ? '3' : '2'}\r\n strokeDasharray=\"4 2\"\r\n rx=\"2\"\r\n pointerEvents=\"none\"\r\n />\r\n )}\r\n\r\n {/* Render symbol inline (future: use <use> with <defs>) */}\r\n <g\r\n dangerouslySetInnerHTML={{ __html: symbol.svgContent }}\r\n data-symbol-content={symbol.id}\r\n style={{ pointerEvents: 'auto' }}\r\n />\r\n\r\n {/* Node label */}\r\n <text\r\n x={symbol.viewBox.width / 2 + (node.labelOffset?.x ?? 0)}\r\n y={symbol.viewBox.height + 12 + (node.labelOffset?.y ?? 0)}\r\n textAnchor=\"middle\"\r\n fontSize={node.labelFontSize ?? 10}\r\n fontWeight=\"600\"\r\n fill={isSelected ? '#3b82f6' : '#1f2937'}\r\n transform={\r\n node.transform.rotation\r\n ? `rotate(${-node.transform.rotation}, ${symbol.viewBox.width / 2 + (node.labelOffset?.x ?? 0)}, ${symbol.viewBox.height + 12 + (node.labelOffset?.y ?? 0)})`\r\n : undefined\r\n }\r\n >\r\n {node.label || node.id}\r\n </text>\r\n </g>\r\n );\r\n })}\r\n </g>\r\n );\r\n}\r\n","import React from 'react';\r\nimport type { PipeEdge, PipeStyle } from '../../diagram/schema';\r\n\r\nexport interface PipeRendererProps {\r\n /** Array of pipe edges to render */\r\n pipes: PipeEdge[];\r\n /** IDs of selected pipes */\r\n selectedPipeIds?: Set<string>;\r\n /** Callback when a pipe is clicked */\r\n onPipeClick?: (pipeId: string, event: React.MouseEvent) => void;\r\n /** Enable waypoint editing mode */\r\n enableWaypointEditing?: boolean;\r\n /** Callback when waypoint drag starts */\r\n onWaypointDragStart?: (\r\n pipeId: string,\r\n pointIndex: number,\r\n event: React.MouseEvent | React.TouchEvent\r\n ) => void;\r\n /** ID of pipe being edited */\r\n editingPipeId?: string | null;\r\n /** Index of waypoint being dragged */\r\n draggingWaypointIndex?: number | null;\r\n /** Offset for dragged waypoint */\r\n waypointDragOffset?: { x: number; y: number };\r\n /** Callback when pipe segment is clicked (to add waypoint) */\r\n onPipeSegmentClick?: (\r\n pipeId: string,\r\n position: { x: number; y: number },\r\n segmentIndex: number\r\n ) => void;\r\n}\r\n\r\n/**\r\n * PipeRenderer - Renders pipe connections between nodes with selection support\r\n *\r\n * Uses SVG polyline elements to render pipes with route points\r\n * Supports click selection with visual feedback\r\n */\r\nexport function PipeRenderer({\r\n pipes,\r\n selectedPipeIds,\r\n onPipeClick,\r\n enableWaypointEditing = false,\r\n onWaypointDragStart,\r\n editingPipeId,\r\n draggingWaypointIndex,\r\n waypointDragOffset,\r\n onPipeSegmentClick,\r\n}: PipeRendererProps): React.ReactElement {\r\n return (\r\n <g id=\"layer-pipes\">\r\n {pipes\r\n .filter((pipe) => pipe.visible !== false) // Filter hidden pipes\r\n .map((pipe) => {\r\n const isSelected = selectedPipeIds?.has(pipe.id) ?? false;\r\n const isEditing = enableWaypointEditing && editingPipeId === pipe.id;\r\n const showEditingControls = enableWaypointEditing && isSelected;\r\n\r\n // Apply waypoint drag offset if dragging\r\n const displayPoints = pipe.routePoints.map((point, idx) => {\r\n if (isEditing && draggingWaypointIndex === idx && waypointDragOffset) {\r\n return {\r\n x: point.x + waypointDragOffset.x,\r\n y: point.y + waypointDragOffset.y,\r\n };\r\n }\r\n return point;\r\n });\r\n\r\n // Convert route points to polyline points string\r\n const pointsString = displayPoints.map((point) => `${point.x},${point.y}`).join(' ');\r\n\r\n // Apply pipe style with defaults\r\n const pipeStyle: Partial<PipeStyle> = pipe.style || {};\r\n const stroke = isSelected ? '#3b82f6' : pipeStyle.stroke || '#263238';\r\n const strokeWidth = isSelected\r\n ? (pipeStyle.strokeWidth || 3) + 2\r\n : pipeStyle.strokeWidth || 3;\r\n const strokeDasharray = pipeStyle.strokeDasharray;\r\n const opacity = pipeStyle.opacity !== undefined ? pipeStyle.opacity : 1;\r\n\r\n return (\r\n <g\r\n key={pipe.id}\r\n data-pipe-id={pipe.id}\r\n data-selected={isSelected}\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onPipeClick?.(pipe.id, e);\r\n }}\r\n style={{\r\n cursor: onPipeClick ? 'pointer' : 'default',\r\n }}\r\n >\r\n {/* Only render pipe lines when NOT in waypoint-only mode */}\r\n {!enableWaypointEditing && (\r\n <>\r\n {/* Selection indicator - wider transparent clickable area */}\r\n {onPipeClick && (\r\n <polyline\r\n points={pointsString}\r\n fill=\"none\"\r\n stroke=\"transparent\"\r\n strokeWidth={strokeWidth + 8}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n pointerEvents=\"stroke\"\r\n />\r\n )}\r\n\r\n {/* Main pipe line */}\r\n <polyline\r\n points={pointsString}\r\n fill=\"none\"\r\n stroke={stroke}\r\n strokeWidth={strokeWidth}\r\n strokeDasharray={strokeDasharray}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n opacity={opacity}\r\n data-from={pipe.fromNodeId}\r\n data-to={pipe.toNodeId}\r\n pointerEvents={onPipeClick ? 'none' : 'auto'}\r\n />\r\n </>\r\n )}\r\n\r\n {/* Connection points indicators */}\r\n {displayPoints.map((point, idx) => {\r\n // Show all waypoints including endpoints\r\n const isEndpoint = idx === 0 || idx === displayPoints.length - 1;\r\n\r\n const isDragging = isEditing && draggingWaypointIndex === idx;\r\n const waypointSize = isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;\r\n const waypointOpacity = isDragging\r\n ? 1\r\n : showEditingControls\r\n ? 0.9\r\n : isSelected\r\n ? 0.8\r\n : 0.5;\r\n\r\n // Endpoints get a different color when editable\r\n const waypointColor =\r\n isEndpoint && showEditingControls ? '#f59e0b' : isDragging ? '#10b981' : stroke;\r\n\r\n return (\r\n <circle\r\n key={`${pipe.id}-point-${idx}`}\r\n cx={point.x}\r\n cy={point.y}\r\n r={waypointSize}\r\n fill={waypointColor}\r\n stroke={showEditingControls ? '#ffffff' : 'none'}\r\n strokeWidth={showEditingControls ? 2 : 0}\r\n opacity={waypointOpacity}\r\n className=\"pipe-route-point\"\r\n style={{\r\n cursor: showEditingControls ? (isDragging ? 'grabbing' : 'grab') : 'default',\r\n }}\r\n pointerEvents={showEditingControls ? 'all' : 'none'}\r\n onMouseDown={(e) => {\r\n if (showEditingControls) {\r\n e.stopPropagation();\r\n onWaypointDragStart?.(pipe.id, idx, e);\r\n }\r\n }}\r\n onTouchStart={(e) => {\r\n if (showEditingControls) {\r\n e.stopPropagation();\r\n onWaypointDragStart?.(pipe.id, idx, e);\r\n }\r\n }}\r\n />\r\n );\r\n })}\r\n\r\n {/* Pipe segment click areas (for adding waypoints) */}\r\n {showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && (\r\n <>\r\n {displayPoints.slice(0, -1).map((point, idx) => {\r\n const nextPoint = displayPoints[idx + 1];\r\n const midX = (point.x + nextPoint.x) / 2;\r\n const midY = (point.y + nextPoint.y) / 2;\r\n\r\n return (\r\n <g key={`${pipe.id}-segment-${idx}`}>\r\n {/* Larger clickable area */}\r\n <circle\r\n cx={midX}\r\n cy={midY}\r\n r={8}\r\n fill=\"transparent\"\r\n className=\"pipe-segment-add-area\"\r\n style={{ cursor: 'crosshair' }}\r\n pointerEvents=\"all\"\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onPipeSegmentClick?.(pipe.id, { x: midX, y: midY }, idx);\r\n }}\r\n />\r\n {/* Visible indicator */}\r\n <circle\r\n cx={midX}\r\n cy={midY}\r\n r={4}\r\n fill=\"#3b82f6\"\r\n stroke=\"#ffffff\"\r\n strokeWidth={2}\r\n opacity={0.6}\r\n className=\"pipe-segment-add\"\r\n pointerEvents=\"none\"\r\n />\r\n </g>\r\n );\r\n })}\r\n </>\r\n )}\r\n\r\n {/* Pipe label (optional) */}\r\n {pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && (\r\n <text\r\n x={\r\n pipe.routePoints[Math.floor(pipe.routePoints.length / 2)].x +\r\n (pipe.labelOffset?.x ?? 0)\r\n }\r\n y={\r\n pipe.routePoints[Math.floor(pipe.routePoints.length / 2)].y -\r\n 8 +\r\n (pipe.labelOffset?.y ?? 0)\r\n }\r\n textAnchor=\"middle\"\r\n fontSize=\"10\"\r\n fontWeight={isSelected ? '600' : '500'}\r\n fill={stroke}\r\n opacity={opacity * 0.8}\r\n pointerEvents=\"none\"\r\n >\r\n {pipe.label}\r\n </text>\r\n )}\r\n </g>\r\n );\r\n })}\r\n </g>\r\n );\r\n}\r\n","import React from 'react';\r\nimport type { TelemetryBinding } from '../../diagram/schema/TelemetryBinding';\r\n\r\nexport interface DataOverlayProps {\r\n /** Node ID this overlay is for */\r\n nodeId: string;\r\n /** X position in SVG coordinates */\r\n x: number;\r\n /** Y position in SVG coordinates */\r\n y: number;\r\n /** Telemetry binding data */\r\n telemetry: TelemetryBinding;\r\n}\r\n\r\n/**\r\n * DataOverlay - Renders live telemetry values above P&ID nodes\r\n *\r\n * Shows:\r\n * - Current value with unit\r\n * - Status-based color coding\r\n * - Optional label\r\n */\r\nexport function DataOverlay({ nodeId, x, y, telemetry }: DataOverlayProps): React.ReactElement {\r\n const { value, display, history } = telemetry;\r\n const showValue = display?.showValue ?? true;\r\n const showStatus = display?.showStatus ?? true;\r\n const showSparkline = display?.showSparkline ?? false;\r\n const label = display?.label;\r\n const precision = display?.precision;\r\n const sparklineColor = display?.sparklineColor;\r\n const textColor = display?.textColor;\r\n const backgroundColor = display?.backgroundColor;\r\n const offsetX = display?.offsetX ?? 0;\r\n const offsetY = display?.offsetY ?? 0;\r\n\r\n if (!showValue) {\r\n return <></>;\r\n }\r\n\r\n // Format value based on type and precision\r\n const formatValue = (val: number | string | boolean): string => {\r\n if (typeof val === 'number') {\r\n return precision !== undefined ? val.toFixed(precision) : val.toString();\r\n }\r\n if (typeof val === 'boolean') {\r\n return val ? 'ON' : 'OFF';\r\n }\r\n return val.toString();\r\n };\r\n\r\n // Status color mapping - use custom colors if provided, otherwise defaults\r\n const defaultStatusColors: Record<string, { bg: string; text: string; border: string }> = {\r\n normal: { bg: '#10b981', text: '#ffffff', border: '#059669' },\r\n warning: { bg: '#f59e0b', text: '#ffffff', border: '#d97706' },\r\n alarm: { bg: '#ef4444', text: '#ffffff', border: '#dc2626' },\r\n fault: { bg: '#dc2626', text: '#ffffff', border: '#b91c1c' },\r\n off: { bg: '#6b7280', text: '#ffffff', border: '#4b5563' },\r\n };\r\n\r\n // Apply custom colors if provided\r\n const customColor = telemetry.statusColors?.[value.status];\r\n const defaultColorSet = defaultStatusColors[value.status] || defaultStatusColors.normal;\r\n\r\n const statusColors = customColor\r\n ? { bg: customColor, text: '#ffffff', border: customColor }\r\n : defaultColorSet;\r\n\r\n const colors =\r\n backgroundColor && backgroundColor !== 'status'\r\n ? { bg: backgroundColor, text: textColor || '#ffffff', border: backgroundColor }\r\n : statusColors;\r\n\r\n // Override text color if explicitly set\r\n const finalTextColor = textColor || colors.text;\r\n\r\n const formattedValue = formatValue(value.value);\r\n const displayText = value.unit ? `${formattedValue} ${value.unit}` : formattedValue;\r\n\r\n // Calculate sparkline path if history is provided\r\n const sparklinePath = (() => {\r\n if (!showSparkline || !history || history.length < 2) return '';\r\n\r\n const width = 70;\r\n const height = 20;\r\n const padding = 5;\r\n const effectiveWidth = width - padding * 2;\r\n const effectiveHeight = height - padding * 2;\r\n\r\n const min = Math.min(...history);\r\n const max = Math.max(...history);\r\n const range = max - min || 1; // Avoid division by zero\r\n\r\n const points = history.map((val, i) => {\r\n const xPos = (i / (history.length - 1)) * effectiveWidth + padding;\r\n const yPos = height - padding - ((val - min) / range) * effectiveHeight;\r\n return `${xPos.toFixed(2)},${yPos.toFixed(2)}`;\r\n });\r\n\r\n return `M ${points.join(' L ')}`;\r\n })();\r\n\r\n const hasSparkline = showSparkline && sparklinePath;\r\n const overlayHeight = label ? (hasSparkline ? 55 : 30) : hasSparkline ? 47 : 22;\r\n\r\n // Apply position offsets\r\n const displayX = x + offsetX;\r\n const displayY = y + offsetY;\r\n\r\n return (\r\n <g data-overlay-node={nodeId} data-status={value.status}>\r\n {/* Background rect */}\r\n <rect\r\n x={displayX - 40}\r\n y={displayY - 25}\r\n width=\"80\"\r\n height={overlayHeight}\r\n rx=\"4\"\r\n fill={colors.bg}\r\n stroke={colors.border}\r\n strokeWidth=\"1\"\r\n opacity=\"0.95\"\r\n filter=\"drop-shadow(0 2px 4px rgba(0,0,0,0.2))\"\r\n />\r\n\r\n {/* Label (optional) */}\r\n {label && (\r\n <text\r\n x={displayX}\r\n y={displayY - 15}\r\n textAnchor=\"middle\"\r\n fontSize=\"8\"\r\n fontWeight=\"600\"\r\n fill={finalTextColor}\r\n opacity=\"0.9\"\r\n >\r\n {label}\r\n </text>\r\n )}\r\n\r\n {/* Value text */}\r\n <text\r\n x={displayX}\r\n y={label ? displayY - 3 : displayY - 9}\r\n textAnchor=\"middle\"\r\n fontSize=\"11\"\r\n fontWeight=\"700\"\r\n fill={finalTextColor}\r\n letterSpacing=\"0.02em\"\r\n >\r\n {displayText}\r\n </text>\r\n\r\n {/* Status indicator dot (optional) */}\r\n {showStatus && value.status !== 'normal' && (\r\n <circle cx={displayX + 35} cy={displayY - 18} r=\"3\" fill={finalTextColor} opacity=\"0.9\">\r\n <animate\r\n attributeName=\"opacity\"\r\n values=\"0.9;0.3;0.9\"\r\n dur=\"1.5s\"\r\n repeatCount=\"indefinite\"\r\n />\r\n </circle>\r\n )}\r\n\r\n {/* Quality indicator (if provided and < 100) */}\r\n {value.quality !== undefined && value.quality < 100 && (\r\n <text\r\n x={displayX}\r\n y={displayY + 5}\r\n textAnchor=\"middle\"\r\n fontSize=\"7\"\r\n fontWeight=\"500\"\r\n fill={finalTextColor}\r\n opacity=\"0.7\"\r\n >\r\n Q: {value.quality}%\r\n </text>\r\n )}\r\n\r\n {/* Sparkline trend (if history provided) */}\r\n {hasSparkline && (\r\n <g transform={`translate(${displayX - 35}, ${displayY + (label ? 5 : 0)})`}>\r\n <path\r\n d={sparklinePath}\r\n fill=\"none\"\r\n stroke={sparklineColor || finalTextColor}\r\n strokeWidth=\"1.5\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n opacity=\"0.9\"\r\n />\r\n </g>\r\n )}\r\n </g>\r\n );\r\n}\r\n","import { useState, useCallback, useRef, useEffect } from 'react';\r\nimport type { ViewBox } from '../schema';\r\n\r\nexport interface UseViewBoxOptions {\r\n /** Initial viewBox configuration */\r\n initialViewBox: ViewBox;\r\n /** Enable pan interaction (default: true) */\r\n enablePan?: boolean;\r\n /** Enable zoom interaction (default: true) */\r\n enableZoom?: boolean;\r\n /** Minimum zoom level (smaller = more zoomed in, default: 0.1) */\r\n minZoom?: number;\r\n /** Maximum zoom level (larger = more zoomed out, default: 10) */\r\n maxZoom?: number;\r\n /** Zoom sensitivity (default: 0.001) */\r\n zoomSensitivity?: number;\r\n /** Allow left-click drag for panning (default: true for touch-friendly) */\r\n allowLeftClickPan?: boolean;\r\n}\r\n\r\nexport interface UseViewBoxResult {\r\n /** Current viewBox state */\r\n viewBox: ViewBox;\r\n /** Reset viewBox to initial state */\r\n resetViewBox: () => void;\r\n /** Zoom in (decrease viewBox size) */\r\n zoomIn: () => void;\r\n /** Zoom out (increase viewBox size) */\r\n zoomOut: () => void;\r\n /** Convert screen coordinates to world (SVG) coordinates */\r\n screenToWorld: (screenX: number, screenY: number) => { x: number; y: number };\r\n /** SVG element ref to attach event listeners */\r\n svgRef: React.RefObject<SVGSVGElement | null>;\r\n}\r\n\r\n/**\r\n * Custom hook for managing ViewBox state with pan and zoom interactions\r\n * \r\n * Pan controls:\r\n * - Left mouse button + drag (if allowLeftClickPan=true, default)\r\n * - Middle mouse button + drag (always)\r\n * - Space + left mouse button + drag (always)\r\n * - Touch drag (single finger)\r\n * \r\n * Zoom controls:\r\n * - Mouse wheel (zoom to cursor position)\r\n * - Pinch gesture (touch devices)\r\n * - Programmatic zoomIn/zoomOut functions\r\n */\r\nexport function useViewBox(options: UseViewBoxOptions): UseViewBoxResult {\r\n const {\r\n initialViewBox,\r\n enablePan = true,\r\n enableZoom = true,\r\n minZoom = 0.1,\r\n maxZoom = 10,\r\n zoomSensitivity = 0.001,\r\n allowLeftClickPan = true,\r\n } = options;\r\n\r\n const [viewBox, setViewBox] = useState<ViewBox>(initialViewBox);\r\n const svgRef = useRef<SVGSVGElement | null>(null);\r\n const isPanningRef = useRef(false);\r\n const lastMousePosRef = useRef({ x: 0, y: 0 });\r\n const spaceKeyDownRef = useRef(false);\r\n const lastTouchDistanceRef = useRef<number | null>(null);\r\n\r\n // Reset to initial viewBox\r\n const resetViewBox = useCallback(() => {\r\n setViewBox(initialViewBox);\r\n }, [initialViewBox]);\r\n\r\n // Zoom in (25% closer)\r\n const zoomIn = useCallback(() => {\r\n setViewBox((prev) => {\r\n const currentZoom = initialViewBox.width / prev.width;\r\n const newZoom = Math.min(1 / minZoom, currentZoom * 1.25);\r\n const scale = initialViewBox.width / newZoom;\r\n \r\n const centerX = prev.x + prev.width / 2;\r\n const centerY = prev.y + prev.height / 2;\r\n const newWidth = scale;\r\n const newHeight = (prev.height / prev.width) * scale;\r\n\r\n return {\r\n x: centerX - newWidth / 2,\r\n y: centerY - newHeight / 2,\r\n width: newWidth,\r\n height: newHeight,\r\n };\r\n });\r\n }, [initialViewBox, minZoom]);\r\n\r\n // Zoom out (25% farther)\r\n const zoomOut = useCallback(() => {\r\n setViewBox((prev) => {\r\n const currentZoom = initialViewBox.width / prev.width;\r\n const newZoom = Math.max(1 / maxZoom, currentZoom * 0.8);\r\n const scale = initialViewBox.width / newZoom;\r\n \r\n const centerX = prev.x + prev.width / 2;\r\n const centerY = prev.y + prev.height / 2;\r\n const newWidth = scale;\r\n const newHeight = (prev.height / prev.width) * scale;\r\n\r\n return {\r\n x: centerX - newWidth / 2,\r\n y: centerY - newHeight / 2,\r\n width: newWidth,\r\n height: newHeight,\r\n };\r\n });\r\n }, [initialViewBox, maxZoom]);\r\n\r\n // Handle mouse wheel zoom\r\n useEffect(() => {\r\n if (!enableZoom || !svgRef.current) return;\r\n\r\n const svg = svgRef.current;\r\n\r\n const handleWheel = (e: WheelEvent) => {\r\n e.preventDefault();\r\n\r\n // Get mouse position in SVG coordinate space\r\n const rect = svg.getBoundingClientRect();\r\n const mouseX = e.clientX - rect.left;\r\n const mouseY = e.clientY - rect.top;\r\n\r\n setViewBox((prev) => {\r\n // Convert mouse position to viewBox coordinates\r\n const svgX = prev.x + (mouseX / rect.width) * prev.width;\r\n const svgY = prev.y + (mouseY / rect.height) * prev.height;\r\n\r\n // Calculate zoom factor\r\n const delta = -e.deltaY * zoomSensitivity;\r\n const zoom = Math.exp(delta);\r\n\r\n // Calculate new viewBox dimensions\r\n let newWidth = prev.width / zoom;\r\n let newHeight = prev.height / zoom;\r\n\r\n // Clamp zoom level\r\n const currentZoom = initialViewBox.width / prev.width;\r\n const newZoom = currentZoom * zoom;\r\n if (newZoom < minZoom || newZoom > 1 / minZoom) {\r\n return prev; // Don't zoom beyond limits\r\n }\r\n\r\n // Adjust viewBox position to zoom towards mouse cursor\r\n const newX = svgX - (mouseX / rect.width) * newWidth;\r\n const newY = svgY - (mouseY / rect.height) * newHeight;\r\n\r\n return {\r\n x: newX,\r\n y: newY,\r\n width: newWidth,\r\n height: newHeight,\r\n };\r\n });\r\n };\r\n\r\n svg.addEventListener('wheel', handleWheel, { passive: false });\r\n return () => svg.removeEventListener('wheel', handleWheel);\r\n }, [enableZoom, zoomSensitivity, minZoom, initialViewBox]);\r\n\r\n // Handle panning\r\n useEffect(() => {\r\n if (!enablePan || !svgRef.current) return;\r\n\r\n const svg = svgRef.current;\r\n\r\n const handleMouseDown = (e: MouseEvent) => {\r\n // Check if clicking on a draggable element (node, waypoint, pipe segment)\r\n const target = e.target as Element;\r\n const isDraggableNode = target.closest('[data-node-id]');\r\n const isWaypoint = target.classList.contains('pipe-route-point');\r\n const isPipeSegment = target.classList.contains('pipe-segment-add') || target.classList.contains('pipe-segment-add-area');\r\n \r\n if (isDraggableNode || isWaypoint || isPipeSegment) {\r\n return; // Let drag handler take over\r\n }\r\n\r\n // Left button (if allowed), middle button, or space + left button\r\n const isLeftClick = e.button === 0 && allowLeftClickPan;\r\n const isMiddleClick = e.button === 1;\r\n const isSpaceLeftClick = e.button === 0 && spaceKeyDownRef.current;\r\n \r\n if (isLeftClick || isMiddleClick || isSpaceLeftClick) {\r\n e.preventDefault();\r\n isPanningRef.current = true;\r\n lastMousePosRef.current = { x: e.clientX, y: e.clientY };\r\n svg.style.cursor = 'grabbing';\r\n }\r\n };\r\n\r\n const handleMouseMove = (e: MouseEvent) => {\r\n if (!isPanningRef.current) return;\r\n\r\n const dx = e.clientX - lastMousePosRef.current.x;\r\n const dy = e.clientY - lastMousePosRef.current.y;\r\n lastMousePosRef.current = { x: e.clientX, y: e.clientY };\r\n\r\n setViewBox((prev) => {\r\n const rect = svg.getBoundingClientRect();\r\n const scaleX = prev.width / rect.width;\r\n const scaleY = prev.height / rect.height;\r\n\r\n return {\r\n ...prev,\r\n x: prev.x - dx * scaleX,\r\n y: prev.y - dy * scaleY,\r\n };\r\n });\r\n };\r\n\r\n const handleMouseUp = () => {\r\n if (isPanningRef.current) {\r\n isPanningRef.current = false;\r\n svg.style.cursor = (allowLeftClickPan || spaceKeyDownRef.current) ? 'grab' : '';\r\n }\r\n };\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.code === 'Space' && !spaceKeyDownRef.current) {\r\n e.preventDefault();\r\n spaceKeyDownRef.current = true;\r\n if (!isPanningRef.current && !allowLeftClickPan) {\r\n svg.style.cursor = 'grab';\r\n }\r\n }\r\n };\r\n\r\n const handleKeyUp = (e: KeyboardEvent) => {\r\n if (e.code === 'Space') {\r\n spaceKeyDownRef.current = false;\r\n if (!isPanningRef.current && !allowLeftClickPan) {\r\n svg.style.cursor = '';\r\n }\r\n }\r\n };\r\n\r\n // Set initial cursor if left-click pan is enabled\r\n if (allowLeftClickPan && !isPanningRef.current) {\r\n svg.style.cursor = 'grab';\r\n }\r\n\r\n svg.addEventListener('mousedown', handleMouseDown);\r\n window.addEventListener('mousemove', handleMouseMove);\r\n window.addEventListener('mouseup', handleMouseUp);\r\n window.addEventListener('keydown', handleKeyDown);\r\n window.addEventListener('keyup', handleKeyUp);\r\n\r\n return () => {\r\n svg.removeEventListener('mousedown', handleMouseDown);\r\n window.removeEventListener('mousemove', handleMouseMove);\r\n window.removeEventListener('mouseup', handleMouseUp);\r\n window.removeEventListener('keydown', handleKeyDown);\r\n window.removeEventListener('keyup', handleKeyUp);\r\n };\r\n }, [enablePan, allowLeftClickPan]);\r\n\r\n // Handle touch gestures (pan and pinch-to-zoom)\r\n useEffect(() => {\r\n if (!svgRef.current) return;\r\n if (!enablePan && !enableZoom) return;\r\n\r\n const svg = svgRef.current;\r\n\r\n const handleTouchStart = (e: TouchEvent) => {\r\n // Check if touching a draggable element (node, waypoint, pipe segment)\r\n const target = e.target as Element;\r\n const isDraggableNode = target.closest('[data-node-id]');\r\n const isWaypoint = target.classList.contains('pipe-route-point');\r\n const isPipeSegment = target.classList.contains('pipe-segment-add') || target.classList.contains('pipe-segment-add-area');\r\n \r\n if ((isDraggableNode || isWaypoint || isPipeSegment) && e.touches.length === 1) {\r\n return; // Let drag handler take over for single touch\r\n }\r\n\r\n if (e.touches.length === 1 && enablePan) {\r\n // Single touch - pan\r\n isPanningRef.current = true;\r\n lastMousePosRef.current = {\r\n x: e.touches[0].clientX,\r\n y: e.touches[0].clientY,\r\n };\r\n } else if (e.touches.length === 2 && enableZoom) {\r\n // Two touches - prepare for pinch zoom\r\n const touch1 = e.touches[0];\r\n const touch2 = e.touches[1];\r\n const distance = Math.hypot(\r\n touch2.clientX - touch1.clientX,\r\n touch2.clientY - touch1.clientY\r\n );\r\n lastTouchDistanceRef.current = distance;\r\n }\r\n };\r\n\r\n const handleTouchMove = (e: TouchEvent) => {\r\n e.preventDefault();\r\n\r\n if (e.touches.length === 1 && isPanningRef.current && enablePan) {\r\n // Single touch pan\r\n const touch = e.touches[0];\r\n const dx = touch.clientX - lastMousePosRef.current.x;\r\n const dy = touch.clientY - lastMousePosRef.current.y;\r\n lastMousePosRef.current = { x: touch.clientX, y: touch.clientY };\r\n\r\n setViewBox((prev) => {\r\n const rect = svg.getBoundingClientRect();\r\n const scaleX = prev.width / rect.width;\r\n const scaleY = prev.height / rect.height;\r\n\r\n return {\r\n ...prev,\r\n x: prev.x - dx * scaleX,\r\n y: prev.y - dy * scaleY,\r\n };\r\n });\r\n } else if (e.touches.length === 2 && enableZoom && lastTouchDistanceRef.current) {\r\n // Pinch zoom\r\n const touch1 = e.touches[0];\r\n const touch2 = e.touches[1];\r\n const distance = Math.hypot(\r\n touch2.clientX - touch1.clientX,\r\n touch2.clientY - touch1.clientY\r\n );\r\n\r\n const scale = distance / lastTouchDistanceRef.current;\r\n lastTouchDistanceRef.current = distance;\r\n\r\n // Get center point between two touches\r\n const centerX = (touch1.clientX + touch2.clientX) / 2;\r\n const centerY = (touch1.clientY + touch2.clientY) / 2;\r\n const rect = svg.getBoundingClientRect();\r\n\r\n setViewBox((prev) => {\r\n // Convert touch center to viewBox coordinates\r\n const svgX = prev.x + ((centerX - rect.left) / rect.width) * prev.width;\r\n const svgY = prev.y + ((centerY - rect.top) / rect.height) * prev.height;\r\n\r\n // Calculate new dimensions\r\n let newWidth = prev.width / scale;\r\n let newHeight = prev.height / scale;\r\n\r\n // Clamp zoom level\r\n const currentZoom = initialViewBox.width / prev.width;\r\n const newZoom = currentZoom * scale;\r\n if (newZoom < minZoom || newZoom > 1 / minZoom) {\r\n return prev;\r\n }\r\n\r\n // Adjust position to zoom toward touch center\r\n const newX = svgX - ((centerX - rect.left) / rect.width) * newWidth;\r\n const newY = svgY - ((centerY - rect.top) / rect.height) * newHeight;\r\n\r\n return {\r\n x: newX,\r\n y: newY,\r\n width: newWidth,\r\n height: newHeight,\r\n };\r\n });\r\n }\r\n };\r\n\r\n const handleTouchEnd = () => {\r\n isPanningRef.current = false;\r\n lastTouchDistanceRef.current = null;\r\n };\r\n\r\n svg.addEventListener('touchstart', handleTouchStart);\r\n svg.addEventListener('touchmove', handleTouchMove, { passive: false });\r\n svg.addEventListener('touchend', handleTouchEnd);\r\n\r\n return () => {\r\n svg.removeEventListener('touchstart', handleTouchStart);\r\n svg.removeEventListener('touchmove', handleTouchMove);\r\n svg.removeEventListener('touchend', handleTouchEnd);\r\n };\r\n }, [enablePan, enableZoom, minZoom, initialViewBox]);\r\n\r\n const screenToWorld = useCallback(\r\n (screenX: number, screenY: number): { x: number; y: number } => {\r\n const svg = svgRef.current;\r\n if (!svg) return { x: screenX, y: screenY };\r\n\r\n const rect = svg.getBoundingClientRect();\r\n \r\n // Account for preserveAspectRatio=\"xMidYMid meet\"\r\n const svgAspect = rect.width / rect.height;\r\n const viewBoxAspect = viewBox.width / viewBox.height;\r\n \r\n let actualWidth = rect.width;\r\n let actualHeight = rect.height;\r\n let offsetX = 0;\r\n let offsetY = 0;\r\n \r\n if (svgAspect > viewBoxAspect) {\r\n // SVG is wider - pillarboxing on sides\r\n actualWidth = rect.height * viewBoxAspect;\r\n offsetX = (rect.width - actualWidth) / 2;\r\n } else {\r\n // SVG is taller - letterboxing on top/bottom\r\n actualHeight = rect.width / viewBoxAspect;\r\n offsetY = (rect.height - actualHeight) / 2;\r\n }\r\n \r\n const relativeX = (screenX - rect.left - offsetX) / actualWidth;\r\n const relativeY = (screenY - rect.top - offsetY) / actualHeight;\r\n\r\n const worldX = viewBox.x + relativeX * viewBox.width;\r\n const worldY = viewBox.y + relativeY * viewBox.height;\r\n\r\n return { x: worldX, y: worldY };\r\n },\r\n [viewBox]\r\n );\r\n\r\n return {\r\n viewBox,\r\n resetViewBox,\r\n zoomIn,\r\n zoomOut,\r\n screenToWorld,\r\n svgRef,\r\n };\r\n}\r\n","import { useState, useCallback } from 'react';\r\n\r\nexport interface SelectionState {\r\n /** IDs of selected nodes */\r\n selectedNodeIds: Set<string>;\r\n /** IDs of selected pipes */\r\n selectedPipeIds: Set<string>;\r\n}\r\n\r\nexport interface UseSelectionOptions {\r\n /** Allow multiple selection with Ctrl/Cmd key (default: true) */\r\n multiSelect?: boolean;\r\n /** Initial selection state */\r\n initialSelection?: SelectionState;\r\n /** Callback when selection changes */\r\n onSelectionChange?: (selection: SelectionState) => void;\r\n}\r\n\r\nexport interface UseSelectionResult {\r\n /** Current selection state */\r\n selection: SelectionState;\r\n /** Check if a node is selected */\r\n isNodeSelected: (nodeId: string) => boolean;\r\n /** Check if a pipe is selected */\r\n isPipeSelected: (pipeId: string) => boolean;\r\n /** Select a node */\r\n selectNode: (nodeId: string, multiSelect?: boolean) => void;\r\n /** Select a pipe */\r\n selectPipe: (pipeId: string, multiSelect?: boolean) => void;\r\n /** Clear all selections */\r\n clearSelection: () => void;\r\n /** Select multiple nodes */\r\n selectNodes: (nodeIds: string[]) => void;\r\n /** Select multiple pipes */\r\n selectPipes: (pipeIds: string[]) => void;\r\n}\r\n\r\n/**\r\n * Custom hook for managing selection state in P&ID diagrams\r\n * \r\n * Supports:\r\n * - Single selection (click)\r\n * - Multi-selection (Ctrl+click)\r\n * - Programmatic selection\r\n * - Selection callbacks\r\n */\r\nexport function useSelection(options: UseSelectionOptions = {}): UseSelectionResult {\r\n const {\r\n multiSelect = true,\r\n initialSelection = { selectedNodeIds: new Set(), selectedPipeIds: new Set() },\r\n onSelectionChange,\r\n } = options;\r\n\r\n const [selection, setSelection] = useState<SelectionState>(initialSelection);\r\n\r\n const notifyChange = useCallback(\r\n (newSelection: SelectionState) => {\r\n if (onSelectionChange) {\r\n onSelectionChange(newSelection);\r\n }\r\n },\r\n [onSelectionChange]\r\n );\r\n\r\n const isNodeSelected = useCallback(\r\n (nodeId: string) => selection.selectedNodeIds.has(nodeId),\r\n [selection.selectedNodeIds]\r\n );\r\n\r\n const isPipeSelected = useCallback(\r\n (pipeId: string) => selection.selectedPipeIds.has(pipeId),\r\n [selection.selectedPipeIds]\r\n );\r\n\r\n const selectNode = useCallback(\r\n (nodeId: string, isMultiSelect = false) => {\r\n setSelection((prev) => {\r\n const newNodeIds = new Set<string>(isMultiSelect && multiSelect ? prev.selectedNodeIds : []);\r\n \r\n if (newNodeIds.has(nodeId)) {\r\n // Deselect if already selected in multi-select mode\r\n newNodeIds.delete(nodeId);\r\n } else {\r\n newNodeIds.add(nodeId);\r\n }\r\n\r\n const newSelection: SelectionState = {\r\n selectedNodeIds: newNodeIds,\r\n selectedPipeIds: isMultiSelect && multiSelect ? prev.selectedPipeIds : new Set<string>(),\r\n };\r\n\r\n notifyChange(newSelection);\r\n return newSelection;\r\n });\r\n },\r\n [multiSelect, notifyChange]\r\n );\r\n\r\n const selectPipe = useCallback(\r\n (pipeId: string, isMultiSelect = false) => {\r\n setSelection((prev) => {\r\n const newPipeIds = new Set<string>(isMultiSelect && multiSelect ? prev.selectedPipeIds : []);\r\n \r\n if (newPipeIds.has(pipeId)) {\r\n // Deselect if already selected in multi-select mode\r\n newPipeIds.delete(pipeId);\r\n } else {\r\n newPipeIds.add(pipeId);\r\n }\r\n\r\n const newSelection: SelectionState = {\r\n selectedNodeIds: isMultiSelect && multiSelect ? prev.selectedNodeIds : new Set<string>(),\r\n selectedPipeIds: newPipeIds,\r\n };\r\n\r\n notifyChange(newSelection);\r\n return newSelection;\r\n });\r\n },\r\n [multiSelect, notifyChange]\r\n );\r\n\r\n const clearSelection = useCallback(() => {\r\n const newSelection = {\r\n selectedNodeIds: new Set<string>(),\r\n selectedPipeIds: new Set<string>(),\r\n };\r\n setSelection(newSelection);\r\n notifyChange(newSelection);\r\n }, [notifyChange]);\r\n\r\n const selectNodes = useCallback(\r\n (nodeIds: string[]) => {\r\n const newSelection = {\r\n selectedNodeIds: new Set(nodeIds),\r\n selectedPipeIds: new Set<string>(),\r\n };\r\n setSelection(newSelection);\r\n notifyChange(newSelection);\r\n },\r\n [notifyChange]\r\n );\r\n\r\n const selectPipes = useCallback(\r\n (pipeIds: string[]) => {\r\n const newSelection = {\r\n selectedNodeIds: new Set<string>(),\r\n selectedPipeIds: new Set(pipeIds),\r\n };\r\n setSelection(newSelection);\r\n notifyChange(newSelection);\r\n },\r\n [notifyChange]\r\n );\r\n\r\n return {\r\n selection,\r\n isNodeSelected,\r\n isPipeSelected,\r\n selectNode,\r\n selectPipe,\r\n clearSelection,\r\n selectNodes,\r\n selectPipes,\r\n };\r\n}\r\n","import { useState, useCallback, useEffect, useRef } from 'react';\r\nimport type { TelemetryBinding, TelemetryMap, TelemetryValue } from '../schema/TelemetryBinding';\r\n\r\n// Re-export types for consumer convenience\r\nexport type { TelemetryBinding, TelemetryMap, TelemetryValue };\r\n\r\nexport interface UseTelemetryOptions {\r\n /** Initial telemetry bindings */\r\n initialBindings?: TelemetryBinding[];\r\n /** Callback when telemetry values change */\r\n onTelemetryChange?: (bindings: TelemetryMap) => void;\r\n /** Auto-refresh interval in milliseconds (0 = disabled) */\r\n refreshInterval?: number;\r\n}\r\n\r\nexport interface UseTelemetryResult {\r\n /** Current telemetry bindings map */\r\n telemetry: TelemetryMap;\r\n /** Update a single telemetry value */\r\n updateTelemetry: (nodeId: string, value: TelemetryValue) => void;\r\n /** Update multiple telemetry values at once */\r\n updateTelemetryBatch: (updates: Array<{ nodeId: string; value: TelemetryValue; history?: number[] }>) => void;\r\n /** Get telemetry for a specific node */\r\n getTelemetry: (nodeId: string) => TelemetryBinding | undefined;\r\n /** Clear all telemetry data */\r\n clearTelemetry: () => void;\r\n /** Set telemetry bindings */\r\n setBindings: (bindings: TelemetryBinding[]) => void;\r\n}\r\n\r\n/**\r\n * Custom hook for managing telemetry data bindings\r\n * \r\n * Supports:\r\n * - Real-time value updates\r\n * - Status monitoring (normal, warning, alarm, fault, off)\r\n * - Batch updates for performance\r\n * - Auto-refresh capability\r\n * - Quality indicators\r\n */\r\nexport function useTelemetry(options: UseTelemetryOptions = {}): UseTelemetryResult {\r\n const {\r\n initialBindings = [],\r\n onTelemetryChange,\r\n refreshInterval = 0,\r\n } = options;\r\n\r\n // Initialize telemetry map from bindings\r\n const [telemetry, setTelemetry] = useState<TelemetryMap>(() => {\r\n const map = new Map<string, TelemetryBinding>();\r\n initialBindings.forEach((binding) => {\r\n map.set(binding.nodeId, binding);\r\n });\r\n return map;\r\n });\r\n\r\n const telemetryRef = useRef(telemetry);\r\n telemetryRef.current = telemetry;\r\n\r\n const notifyChange = useCallback(\r\n (newTelemetry: TelemetryMap) => {\r\n if (onTelemetryChange) {\r\n onTelemetryChange(newTelemetry);\r\n }\r\n },\r\n [onTelemetryChange]\r\n );\r\n\r\n const updateTelemetry = useCallback(\r\n (nodeId: string, value: TelemetryValue) => {\r\n setTelemetry((prev) => {\r\n const newMap = new Map(prev);\r\n const existing = newMap.get(nodeId);\r\n \r\n if (existing) {\r\n // Update existing binding\r\n newMap.set(nodeId, {\r\n ...existing,\r\n value: {\r\n ...value,\r\n timestamp: value.timestamp ?? Date.now(),\r\n },\r\n });\r\n } else {\r\n // Create new binding\r\n newMap.set(nodeId, {\r\n nodeId,\r\n tag: nodeId, // Default tag to nodeId\r\n value: {\r\n ...value,\r\n timestamp: value.timestamp ?? Date.now(),\r\n },\r\n });\r\n }\r\n\r\n notifyChange(newMap);\r\n return newMap;\r\n });\r\n },\r\n [notifyChange]\r\n );\r\n\r\n const updateTelemetryBatch = useCallback(\r\n (updates: Array<{ \r\n nodeId: string; \r\n tag?: string; \r\n value?: TelemetryValue; \r\n history?: number[]; \r\n display?: any; \r\n thresholds?: any; \r\n statusColors?: any;\r\n remove?: boolean \r\n }>) => {\r\n setTelemetry((prev) => {\r\n const newMap = new Map(prev);\r\n let hasChanges = false;\r\n\r\n updates.forEach(({ nodeId, tag, value, history, display, thresholds, statusColors, remove }) => {\r\n if (remove) {\r\n // Remove telemetry binding\r\n if (newMap.has(nodeId)) {\r\n newMap.delete(nodeId);\r\n hasChanges = true;\r\n }\r\n return;\r\n }\r\n\r\n const existing = newMap.get(nodeId);\r\n\r\n if (existing) {\r\n newMap.set(nodeId, {\r\n ...existing,\r\n ...(tag !== undefined && { tag }),\r\n ...(value !== undefined && {\r\n value: {\r\n ...value,\r\n timestamp: value.timestamp ?? Date.now(),\r\n },\r\n }),\r\n ...(history !== undefined && { history }),\r\n ...(display !== undefined && { display }),\r\n ...(thresholds !== undefined && { thresholds }),\r\n ...(statusColors !== undefined && { statusColors }),\r\n });\r\n hasChanges = true;\r\n } else if (value) {\r\n newMap.set(nodeId, {\r\n nodeId,\r\n tag: tag ?? nodeId,\r\n value: {\r\n ...value,\r\n timestamp: value.timestamp ?? Date.now(),\r\n },\r\n ...(history !== undefined && { history }),\r\n ...(display !== undefined && { display }),\r\n ...(thresholds !== undefined && { thresholds }),\r\n ...(statusColors !== undefined && { statusColors }),\r\n });\r\n hasChanges = true;\r\n }\r\n });\r\n\r\n if (hasChanges) {\r\n notifyChange(newMap);\r\n }\r\n return newMap;\r\n });\r\n },\r\n [notifyChange]\r\n );\r\n\r\n const getTelemetry = useCallback(\r\n (nodeId: string) => telemetryRef.current.get(nodeId),\r\n []\r\n );\r\n\r\n const clearTelemetry = useCallback(() => {\r\n const newMap = new Map<string, TelemetryBinding>();\r\n setTelemetry(newMap);\r\n notifyChange(newMap);\r\n }, [notifyChange]);\r\n\r\n const setBindings = useCallback(\r\n (bindings: TelemetryBinding[]) => {\r\n const newMap = new Map<string, TelemetryBinding>();\r\n bindings.forEach((binding) => {\r\n newMap.set(binding.nodeId, binding);\r\n });\r\n setTelemetry(newMap);\r\n notifyChange(newMap);\r\n },\r\n [notifyChange]\r\n );\r\n\r\n // Auto-refresh functionality\r\n useEffect(() => {\r\n if (refreshInterval <= 0) return;\r\n\r\n const intervalId = setInterval(() => {\r\n // Trigger change notification to allow external refresh logic\r\n notifyChange(telemetryRef.current);\r\n }, refreshInterval);\r\n\r\n return () => clearInterval(intervalId);\r\n }, [refreshInterval, notifyChange]);\r\n\r\n return {\r\n telemetry,\r\n updateTelemetry,\r\n updateTelemetryBatch,\r\n getTelemetry,\r\n clearTelemetry,\r\n setBindings,\r\n };\r\n}\r\n","import { useState, useCallback, useRef, useEffect } from 'react';\r\n\r\nexport interface DragPoint {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport interface DragState {\r\n /** Whether drag is currently active */\r\n isDragging: boolean;\r\n /** Initial position when drag started */\r\n startPosition: DragPoint | null;\r\n /** Current drag offset from start */\r\n offset: DragPoint;\r\n /** ID of the item being dragged */\r\n draggedId: string | null;\r\n}\r\n\r\nexport interface UseDragOptions {\r\n /** Callback when drag starts */\r\n onDragStart?: (id: string, position: DragPoint) => void;\r\n /** Callback during drag movement */\r\n onDragMove?: (id: string, offset: DragPoint, position: DragPoint) => void;\r\n /** Callback when drag ends */\r\n onDragEnd?: (id: string, offset: DragPoint, finalPosition: DragPoint) => void;\r\n /** Snap to grid size (0 = no snap) */\r\n snapToGrid?: number;\r\n /** Minimum drag distance before triggering (prevents accidental drags) */\r\n dragThreshold?: number;\r\n /** Convert screen coordinates to world coordinates */\r\n screenToWorld?: (screenX: number, screenY: number) => DragPoint;\r\n}\r\n\r\nexport interface UseDragResult {\r\n /** Current drag state */\r\n dragState: DragState;\r\n /** Start dragging an item */\r\n startDrag: (id: string, event: React.MouseEvent | React.TouchEvent, itemPosition: DragPoint) => void;\r\n /** Cancel current drag */\r\n cancelDrag: () => void;\r\n /** Check if a specific item is being dragged */\r\n isDraggingItem: (id: string) => boolean;\r\n}\r\n\r\n/**\r\n * Custom hook for drag-and-drop functionality in P&ID diagrams\r\n * \r\n * Supports:\r\n * - Mouse drag\r\n * - Touch drag\r\n * - Snap-to-grid\r\n * - World coordinate conversion (for SVG viewBox)\r\n * - Drag threshold to prevent accidental drags\r\n */\r\nexport function useDrag(options: UseDragOptions = {}): UseDragResult {\r\n const {\r\n onDragStart,\r\n onDragMove,\r\n onDragEnd,\r\n snapToGrid = 0,\r\n dragThreshold = 3,\r\n screenToWorld = (x, y) => ({ x, y }),\r\n } = options;\r\n\r\n const [dragState, setDragState] = useState<DragState>({\r\n isDragging: false,\r\n startPosition: null,\r\n offset: { x: 0, y: 0 },\r\n draggedId: null,\r\n });\r\n\r\n const [isListening, setIsListening] = useState(false);\r\n const dragStartRef = useRef<{ id: string; screenStart: DragPoint; worldStart: DragPoint; itemPosition: DragPoint; clickOffset: DragPoint } | null>(null);\r\n const hasMovedRef = useRef(false);\r\n\r\n const applySnap = useCallback(\r\n (value: number): number => {\r\n if (snapToGrid <= 0) return value;\r\n return Math.round(value / snapToGrid) * snapToGrid;\r\n },\r\n [snapToGrid]\r\n );\r\n\r\n const handleMouseMove = useCallback(\r\n (event: MouseEvent) => {\r\n if (!dragStartRef.current) return;\r\n\r\n const { id, screenStart: _screenStart, itemPosition, clickOffset } = dragStartRef.current;\r\n const currentWorld = screenToWorld(event.clientX, event.clientY);\r\n\r\n // New position = current cursor - click offset\r\n const newX = currentWorld.x - clickOffset.x;\r\n const newY = currentWorld.y - clickOffset.y;\r\n\r\n const rawOffset = {\r\n x: newX - itemPosition.x,\r\n y: newY - itemPosition.y,\r\n };\r\n\r\n // Check if we've exceeded the drag threshold\r\n const distance = Math.sqrt(rawOffset.x ** 2 + rawOffset.y ** 2);\r\n if (!hasMovedRef.current && distance < dragThreshold) {\r\n return;\r\n }\r\n\r\n if (!hasMovedRef.current) {\r\n hasMovedRef.current = true;\r\n setDragState({\r\n isDragging: true,\r\n startPosition: itemPosition,\r\n offset: { x: 0, y: 0 },\r\n draggedId: id,\r\n });\r\n onDragStart?.(id, itemPosition);\r\n }\r\n\r\n const snappedOffset = {\r\n x: applySnap(rawOffset.x),\r\n y: applySnap(rawOffset.y),\r\n };\r\n\r\n const newPosition = {\r\n x: applySnap(itemPosition.x + rawOffset.x),\r\n y: applySnap(itemPosition.y + rawOffset.y),\r\n };\r\n\r\n setDragState((prev) => ({\r\n ...prev,\r\n offset: snappedOffset,\r\n }));\r\n\r\n onDragMove?.(id, snappedOffset, newPosition);\r\n },\r\n [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]\r\n );\r\n\r\n const handleMouseUp = useCallback(\r\n (event: MouseEvent) => {\r\n if (!dragStartRef.current || !hasMovedRef.current) {\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n return;\r\n }\r\n\r\n const { id, itemPosition, clickOffset } = dragStartRef.current;\r\n const currentWorld = screenToWorld(event.clientX, event.clientY);\r\n\r\n const newX = currentWorld.x - clickOffset.x;\r\n const newY = currentWorld.y - clickOffset.y;\r\n\r\n const rawOffset = {\r\n x: newX - itemPosition.x,\r\n y: newY - itemPosition.y,\r\n };\r\n\r\n const snappedOffset = {\r\n x: applySnap(rawOffset.x),\r\n y: applySnap(rawOffset.y),\r\n };\r\n\r\n const finalPosition = {\r\n x: applySnap(itemPosition.x + rawOffset.x),\r\n y: applySnap(itemPosition.y + rawOffset.y),\r\n };\r\n\r\n onDragEnd?.(id, snappedOffset, finalPosition);\r\n\r\n setDragState({\r\n isDragging: false,\r\n startPosition: null,\r\n offset: { x: 0, y: 0 },\r\n draggedId: null,\r\n });\r\n\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n },\r\n [screenToWorld, applySnap, onDragEnd]\r\n );\r\n\r\n const handleTouchMove = useCallback(\r\n (event: TouchEvent) => {\r\n if (!dragStartRef.current || event.touches.length !== 1) return;\r\n\r\n const touch = event.touches[0];\r\n const { id, screenStart: _screenStart2, itemPosition, clickOffset } = dragStartRef.current;\r\n const currentWorld = screenToWorld(touch.clientX, touch.clientY);\r\n\r\n const newX = currentWorld.x - clickOffset.x;\r\n const newY = currentWorld.y - clickOffset.y;\r\n\r\n const rawOffset = {\r\n x: newX - itemPosition.x,\r\n y: newY - itemPosition.y,\r\n };\r\n\r\n const distance = Math.sqrt(rawOffset.x ** 2 + rawOffset.y ** 2);\r\n if (!hasMovedRef.current && distance < dragThreshold) {\r\n return;\r\n }\r\n\r\n event.preventDefault(); // Prevent scrolling\r\n\r\n if (!hasMovedRef.current) {\r\n hasMovedRef.current = true;\r\n setDragState({\r\n isDragging: true,\r\n startPosition: itemPosition,\r\n offset: { x: 0, y: 0 },\r\n draggedId: id,\r\n });\r\n onDragStart?.(id, itemPosition);\r\n }\r\n\r\n const snappedOffset = {\r\n x: applySnap(rawOffset.x),\r\n y: applySnap(rawOffset.y),\r\n };\r\n\r\n const newPosition = {\r\n x: applySnap(itemPosition.x + rawOffset.x),\r\n y: applySnap(itemPosition.y + rawOffset.y),\r\n };\r\n\r\n setDragState((prev) => ({\r\n ...prev,\r\n offset: snappedOffset,\r\n }));\r\n\r\n onDragMove?.(id, snappedOffset, newPosition);\r\n },\r\n [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]\r\n );\r\n\r\n const handleTouchEnd = useCallback(\r\n (event: TouchEvent) => {\r\n if (!dragStartRef.current || !hasMovedRef.current) {\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n return;\r\n }\r\n\r\n const { id, itemPosition, clickOffset } = dragStartRef.current;\r\n const touch = event.changedTouches[0];\r\n const currentWorld = screenToWorld(touch.clientX, touch.clientY);\r\n\r\n const newX = currentWorld.x - clickOffset.x;\r\n const newY = currentWorld.y - clickOffset.y;\r\n\r\n const rawOffset = {\r\n x: newX - itemPosition.x,\r\n y: newY - itemPosition.y,\r\n };\r\n\r\n const snappedOffset = {\r\n x: applySnap(rawOffset.x),\r\n y: applySnap(rawOffset.y),\r\n };\r\n\r\n const finalPosition = {\r\n x: applySnap(itemPosition.x + rawOffset.x),\r\n y: applySnap(itemPosition.y + rawOffset.y),\r\n };\r\n\r\n onDragEnd?.(id, snappedOffset, finalPosition);\r\n\r\n setDragState({\r\n isDragging: false,\r\n startPosition: null,\r\n offset: { x: 0, y: 0 },\r\n draggedId: null,\r\n });\r\n\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n },\r\n [screenToWorld, applySnap, onDragEnd]\r\n );\r\n\r\n useEffect(() => {\r\n // Only attach listeners when actively listening for drag events\r\n if (!isListening) return;\r\n\r\n document.addEventListener('mousemove', handleMouseMove);\r\n document.addEventListener('mouseup', handleMouseUp);\r\n document.addEventListener('touchmove', handleTouchMove, { passive: false });\r\n document.addEventListener('touchend', handleTouchEnd);\r\n document.addEventListener('touchcancel', handleTouchEnd);\r\n\r\n return () => {\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n document.removeEventListener('mouseup', handleMouseUp);\r\n document.removeEventListener('touchmove', handleTouchMove);\r\n document.removeEventListener('touchend', handleTouchEnd);\r\n document.removeEventListener('touchcancel', handleTouchEnd);\r\n };\r\n }, [isListening, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);\r\n\r\n const startDrag = useCallback(\r\n (id: string, event: React.MouseEvent | React.TouchEvent, itemPosition: DragPoint) => {\r\n event.stopPropagation();\r\n\r\n let clientX: number;\r\n let clientY: number;\r\n\r\n if ('touches' in event) {\r\n if (event.touches.length !== 1) return;\r\n clientX = event.touches[0].clientX;\r\n clientY = event.touches[0].clientY;\r\n } else {\r\n clientX = event.clientX;\r\n clientY = event.clientY;\r\n }\r\n\r\n const worldStart = screenToWorld(clientX, clientY);\r\n \r\n // Calculate offset from click position to item position\r\n const clickOffset = {\r\n x: worldStart.x - itemPosition.x,\r\n y: worldStart.y - itemPosition.y,\r\n };\r\n\r\n dragStartRef.current = {\r\n id,\r\n screenStart: { x: clientX, y: clientY },\r\n worldStart,\r\n itemPosition,\r\n clickOffset,\r\n };\r\n hasMovedRef.current = false;\r\n setIsListening(true); // Start listening for move/up events\r\n },\r\n [screenToWorld]\r\n );\r\n\r\n const cancelDrag = useCallback(() => {\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n setDragState({\r\n isDragging: false,\r\n startPosition: null,\r\n offset: { x: 0, y: 0 },\r\n draggedId: null,\r\n });\r\n }, []);\r\n\r\n const isDraggingItem = useCallback(\r\n (id: string) => dragState.isDragging && dragState.draggedId === id,\r\n [dragState.isDragging, dragState.draggedId]\r\n );\r\n\r\n return {\r\n dragState,\r\n startDrag,\r\n cancelDrag,\r\n isDraggingItem,\r\n };\r\n}\r\n","import { useEffect } from 'react';\r\n\r\nexport interface KeyboardShortcutsOptions {\r\n /** Callback when Delete or Backspace is pressed */\r\n onDelete?: () => void;\r\n /** Callback when Ctrl+C is pressed */\r\n onCopy?: () => void;\r\n /** Callback when Ctrl+V is pressed */\r\n onPaste?: () => void;\r\n /** Callback when Ctrl+Z is pressed (undo) */\r\n onUndo?: () => void;\r\n /** Callback when Ctrl+Y or Ctrl+Shift+Z is pressed (redo) */\r\n onRedo?: () => void;\r\n /** Callback when Ctrl+A is pressed (select all) */\r\n onSelectAll?: () => void;\r\n /** Enable keyboard shortcuts (default: true) */\r\n enabled?: boolean;\r\n}\r\n\r\n/**\r\n * Custom hook for handling keyboard shortcuts in P&ID diagrams\r\n * \r\n * Supported shortcuts:\r\n * - Delete/Backspace: Delete selected items\r\n * - Ctrl+C: Copy selected items\r\n * - Ctrl+V: Paste copied items\r\n * - Ctrl+Z: Undo last action\r\n * - Ctrl+Y / Ctrl+Shift+Z: Redo\r\n * - Ctrl+A: Select all\r\n */\r\nexport function useKeyboardShortcuts(options: KeyboardShortcutsOptions): void {\r\n const {\r\n onDelete,\r\n onCopy,\r\n onPaste,\r\n onUndo,\r\n onRedo,\r\n onSelectAll,\r\n enabled = true,\r\n } = options;\r\n\r\n useEffect(() => {\r\n if (!enabled) return;\r\n\r\n const handleKeyDown = (event: KeyboardEvent) => {\r\n // Ignore if user is typing in an input field\r\n const target = event.target as HTMLElement;\r\n if (\r\n target.tagName === 'INPUT' ||\r\n target.tagName === 'TEXTAREA' ||\r\n target.isContentEditable\r\n ) {\r\n return;\r\n }\r\n\r\n const isCtrl = event.ctrlKey || event.metaKey;\r\n const isShift = event.shiftKey;\r\n\r\n // Delete or Backspace\r\n if ((event.key === 'Delete' || event.key === 'Backspace') && !isCtrl) {\r\n event.preventDefault();\r\n onDelete?.();\r\n return;\r\n }\r\n\r\n // Ctrl+C - Copy\r\n if (isCtrl && event.key === 'c') {\r\n event.preventDefault();\r\n onCopy?.();\r\n return;\r\n }\r\n\r\n // Ctrl+V - Paste\r\n if (isCtrl && event.key === 'v') {\r\n event.preventDefault();\r\n onPaste?.();\r\n return;\r\n }\r\n\r\n // Ctrl+Z - Undo\r\n if (isCtrl && event.key === 'z' && !isShift) {\r\n event.preventDefault();\r\n onUndo?.();\r\n return;\r\n }\r\n\r\n // Ctrl+Y or Ctrl+Shift+Z - Redo\r\n if (isCtrl && (event.key === 'y' || (event.key === 'z' && isShift))) {\r\n event.preventDefault();\r\n onRedo?.();\r\n return;\r\n }\r\n\r\n // Ctrl+A - Select all\r\n if (isCtrl && event.key === 'a') {\r\n event.preventDefault();\r\n onSelectAll?.();\r\n return;\r\n }\r\n };\r\n\r\n window.addEventListener('keydown', handleKeyDown);\r\n return () => window.removeEventListener('keydown', handleKeyDown);\r\n }, [enabled, onDelete, onCopy, onPaste, onUndo, onRedo, onSelectAll]);\r\n}\r\n","import type { NodeInstance, Point } from '../schema';\r\nimport { getSymbolDefinition } from '../symbols';\r\n\r\n/**\r\n * Calculate the world position of a port on a node instance\r\n * \r\n * Takes into account the node's transform (position, rotation, scale, flip)\r\n * and the port's position within the symbol's viewBox\r\n */\r\nexport function getPortWorldPosition(\r\n node: NodeInstance,\r\n portId: string\r\n): Point | null {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol) return null;\r\n\r\n const port = symbol.ports.find((p) => p.id === portId);\r\n if (!port) return null;\r\n\r\n const { x: nodeX, y: nodeY, rotation = 0, scale = 1, flipX = false, flipY = false } = node.transform;\r\n\r\n // Start with port position relative to symbol\r\n let portX = port.x;\r\n let portY = port.y;\r\n\r\n // Apply flip transforms (relative to symbol center)\r\n const centerX = symbol.viewBox.width / 2;\r\n const centerY = symbol.viewBox.height / 2;\r\n \r\n if (flipX) {\r\n portX = symbol.viewBox.width - portX;\r\n }\r\n if (flipY) {\r\n portY = symbol.viewBox.height - portY;\r\n }\r\n\r\n // Apply scale (relative to symbol center)\r\n portX = centerX + (portX - centerX) * scale;\r\n portY = centerY + (portY - centerY) * scale;\r\n\r\n // Apply rotation (relative to symbol center)\r\n if (rotation !== 0) {\r\n const rad = (rotation * Math.PI) / 180;\r\n const cos = Math.cos(rad);\r\n const sin = Math.sin(rad);\r\n \r\n const dx = portX - centerX;\r\n const dy = portY - centerY;\r\n \r\n portX = centerX + dx * cos - dy * sin;\r\n portY = centerY + dx * sin + dy * cos;\r\n }\r\n\r\n // Translate to world position\r\n return {\r\n x: nodeX + portX,\r\n y: nodeY + portY,\r\n };\r\n}\r\n\r\n/**\r\n * Generate route points for a pipe from source port to destination port\r\n * \r\n * Options:\r\n * - direct: Straight line from source to destination\r\n * - orthogonal: Right-angle routing (future enhancement)\r\n * - custom: Provide your own waypoints\r\n */\r\nexport function generateRoutePoints(\r\n fromNode: NodeInstance,\r\n fromPortId: string,\r\n toNode: NodeInstance,\r\n toPortId: string,\r\n options?: {\r\n style?: 'direct' | 'orthogonal';\r\n waypoints?: Point[];\r\n }\r\n): Point[] {\r\n const startPoint = getPortWorldPosition(fromNode, fromPortId);\r\n const endPoint = getPortWorldPosition(toNode, toPortId);\r\n\r\n if (!startPoint || !endPoint) {\r\n return [];\r\n }\r\n\r\n const style = options?.style || 'direct';\r\n\r\n if (style === 'direct') {\r\n // Straight line from start to end\r\n return [startPoint, endPoint];\r\n }\r\n\r\n if (style === 'orthogonal' && options?.waypoints) {\r\n // Start → waypoints → end\r\n return [startPoint, ...options.waypoints, endPoint];\r\n }\r\n\r\n if (style === 'orthogonal') {\r\n // Simple orthogonal routing: horizontal then vertical\r\n const midX = (startPoint.x + endPoint.x) / 2;\r\n return [\r\n startPoint,\r\n { x: midX, y: startPoint.y },\r\n { x: midX, y: endPoint.y },\r\n endPoint,\r\n ];\r\n }\r\n\r\n return [startPoint, endPoint];\r\n}\r\n\r\n/**\r\n * Validate that a node has a specific port\r\n */\r\nexport function nodeHasPort(node: NodeInstance, portId: string): boolean {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol) return false;\r\n return symbol.ports.some((p) => p.id === portId);\r\n}\r\n","import React, { useState } from 'react';\r\nimport { getAvailableSymbols, getSymbolDefinition } from '../../diagram/symbols';\r\nimport type { SymbolDefinition } from '../../diagram/schema';\r\n\r\nexport interface SymbolLibraryProps {\r\n /** Optional className for styling */\r\n className?: string;\r\n /** Callback when a symbol drag starts */\r\n onSymbolDragStart?: (symbolId: string, event: React.DragEvent) => void;\r\n /** Show category filter */\r\n showCategories?: boolean;\r\n /** Custom symbol categories */\r\n categories?: string[];\r\n}\r\n\r\n/**\r\n * SymbolLibrary - Browse and drag symbols onto the canvas\r\n *\r\n * Displays available symbols organized by category\r\n * Supports drag-and-drop to add new nodes to diagrams\r\n */\r\nexport function SymbolLibrary({\r\n className = '',\r\n onSymbolDragStart,\r\n showCategories = true,\r\n categories = ['Valves', 'Pumps', 'Tanks', 'Instruments', 'Displays'],\r\n}: SymbolLibraryProps): React.ReactElement {\r\n const [selectedCategory, setSelectedCategory] = useState<string>('all');\r\n const [searchQuery, setSearchQuery] = useState('');\r\n\r\n const symbolIds = getAvailableSymbols();\r\n const allSymbols: SymbolDefinition[] = symbolIds\r\n .map((id) => getSymbolDefinition(id))\r\n .filter((symbol): symbol is SymbolDefinition => symbol !== undefined);\r\n\r\n // Filter symbols by category and search\r\n const filteredSymbols = allSymbols.filter((symbol) => {\r\n const matchesCategory = selectedCategory === 'all' || symbol.category === selectedCategory;\r\n\r\n const matchesSearch =\r\n searchQuery === '' ||\r\n symbol.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\r\n symbol.id.toLowerCase().includes(searchQuery.toLowerCase());\r\n\r\n return matchesCategory && matchesSearch;\r\n });\r\n\r\n const handleDragStart = (symbol: SymbolDefinition, event: React.DragEvent) => {\r\n // Store symbol ID in drag data\r\n event.dataTransfer.setData('application/symbol-id', symbol.id);\r\n event.dataTransfer.effectAllowed = 'copy';\r\n onSymbolDragStart?.(symbol.id, event);\r\n };\r\n\r\n return (\r\n <div className={`symbol-library ${className}`.trim()} style={styles.container}>\r\n {/* Header */}\r\n <div style={styles.header}>\r\n <h3 style={styles.title}>Symbol Library</h3>\r\n </div>\r\n\r\n {/* Search */}\r\n <div style={styles.searchContainer}>\r\n <input\r\n type=\"text\"\r\n placeholder=\"Search symbols...\"\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n style={styles.searchInput}\r\n />\r\n </div>\r\n\r\n {/* Category Filter */}\r\n {showCategories && (\r\n <div style={styles.categories}>\r\n <button\r\n onClick={() => setSelectedCategory('all')}\r\n style={{\r\n ...styles.categoryButton,\r\n ...(selectedCategory === 'all' ? styles.categoryButtonActive : {}),\r\n }}\r\n >\r\n All\r\n </button>\r\n {categories.map((category) => (\r\n <button\r\n key={category}\r\n onClick={() => setSelectedCategory(category)}\r\n style={{\r\n ...styles.categoryButton,\r\n ...(selectedCategory === category ? styles.categoryButtonActive : {}),\r\n }}\r\n >\r\n {category}\r\n </button>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Symbol Grid */}\r\n <div style={styles.symbolGrid}>\r\n {filteredSymbols.length === 0 ? (\r\n <div style={styles.emptyState}>No symbols found</div>\r\n ) : (\r\n filteredSymbols.map((symbol) => (\r\n <div\r\n key={symbol.id}\r\n draggable\r\n onDragStart={(e) => handleDragStart(symbol, e)}\r\n style={styles.symbolCard}\r\n title={symbol.metadata?.description || symbol.name}\r\n >\r\n {/* Symbol Preview */}\r\n <div style={styles.symbolPreview}>\r\n <svg\r\n viewBox={`${symbol.viewBox.x} ${symbol.viewBox.y} ${symbol.viewBox.width} ${symbol.viewBox.height}`}\r\n style={styles.symbolSvg}\r\n >\r\n <g dangerouslySetInnerHTML={{ __html: symbol.svgContent }} />\r\n </svg>\r\n </div>\r\n\r\n {/* Symbol Name */}\r\n <div style={styles.symbolName}>{symbol.name}</div>\r\n </div>\r\n ))\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nconst styles: Record<string, React.CSSProperties> = {\r\n container: {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n height: '100%',\r\n backgroundColor: '#ffffff',\r\n border: '1px solid #e0e0e0',\r\n borderRadius: '8px',\r\n overflow: 'hidden',\r\n },\r\n header: {\r\n padding: '16px',\r\n borderBottom: '1px solid #e0e0e0',\r\n backgroundColor: '#f5f5f5',\r\n },\r\n title: {\r\n margin: 0,\r\n fontSize: '16px',\r\n fontWeight: 600,\r\n color: '#263238',\r\n },\r\n searchContainer: {\r\n padding: '12px 16px',\r\n borderBottom: '1px solid #e0e0e0',\r\n },\r\n searchInput: {\r\n width: '100%',\r\n padding: '8px 12px',\r\n border: '1px solid #e0e0e0',\r\n borderRadius: '4px',\r\n fontSize: '14px',\r\n outline: 'none',\r\n },\r\n categories: {\r\n display: 'flex',\r\n gap: '8px',\r\n padding: '12px 16px',\r\n borderBottom: '1px solid #e0e0e0',\r\n flexWrap: 'wrap',\r\n },\r\n categoryButton: {\r\n padding: '6px 12px',\r\n border: '1px solid #e0e0e0',\r\n borderRadius: '4px',\r\n backgroundColor: '#ffffff',\r\n fontSize: '13px',\r\n cursor: 'pointer',\r\n transition: 'all 0.2s',\r\n },\r\n categoryButtonActive: {\r\n backgroundColor: '#3b82f6',\r\n color: '#ffffff',\r\n borderColor: '#3b82f6',\r\n },\r\n symbolGrid: {\r\n flex: 1,\r\n padding: '16px',\r\n display: 'grid',\r\n gridTemplateColumns: 'repeat(auto-fill, minmax(100px, 1fr))',\r\n gap: '12px',\r\n overflowY: 'auto',\r\n alignContent: 'start',\r\n },\r\n emptyState: {\r\n gridColumn: '1 / -1',\r\n textAlign: 'center',\r\n padding: '32px',\r\n color: '#999',\r\n },\r\n symbolCard: {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n padding: '12px',\r\n border: '1px solid #e0e0e0',\r\n borderRadius: '6px',\r\n backgroundColor: '#ffffff',\r\n cursor: 'grab',\r\n transition: 'all 0.2s',\r\n },\r\n symbolPreview: {\r\n width: '60px',\r\n height: '60px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n marginBottom: '8px',\r\n },\r\n symbolSvg: {\r\n maxWidth: '100%',\r\n maxHeight: '100%',\r\n },\r\n symbolName: {\r\n fontSize: '12px',\r\n color: '#263238',\r\n textAlign: 'center',\r\n wordBreak: 'break-word',\r\n lineHeight: '1.3',\r\n },\r\n};\r\n","import React from 'react';\r\nimport type { NodeInstance } from '../../diagram/schema';\r\nimport type { TelemetryBinding } from '../../diagram/hooks/useTelemetry';\r\n\r\nexport interface NodeConfigPanelProps {\r\n /** Selected node to configure */\r\n node: NodeInstance;\r\n /** Telemetry binding for the node (if any) */\r\n binding: TelemetryBinding | null;\r\n /** Callback when node properties are updated */\r\n onUpdateNode: (updates: Partial<NodeInstance>) => void;\r\n /** Callback when telemetry is added/updated */\r\n onUpdateTelemetry: (updates: any) => void;\r\n /** Callback when telemetry binding is added for the first time */\r\n onAddTelemetry?: () => void;\r\n /** Callback when node is removed */\r\n onRemove: () => void;\r\n /** Additional CSS class name */\r\n className?: string;\r\n /** Custom styles */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * NodeConfigPanel - Reusable configuration panel for editing node properties and telemetry\r\n *\r\n * @example\r\n * ```tsx\r\n * <NodeConfigPanel\r\n * node={selectedNode}\r\n * binding={telemetry.get(selectedNode.id)}\r\n * onUpdateNode={(updates) => updateNode(selectedNode.id, updates)}\r\n * onUpdateTelemetry={(updates) => updateTelemetryBatch([updates])}\r\n * onRemove={() => removeNode(selectedNode.id)}\r\n * />\r\n * ```\r\n */\r\nexport function NodeConfigPanel({\r\n node,\r\n binding,\r\n onUpdateNode,\r\n onUpdateTelemetry,\r\n onAddTelemetry,\r\n onRemove,\r\n className = '',\r\n style = {},\r\n}: NodeConfigPanelProps) {\r\n const defaultStyle: React.CSSProperties = {\r\n width: '320px',\r\n backgroundColor: '#f8fafc',\r\n borderLeft: '1px solid #e2e8f0',\r\n overflow: 'auto',\r\n padding: '20px',\r\n ...style,\r\n };\r\n\r\n return (\r\n <div className={className} style={defaultStyle}>\r\n <h2 style={{ margin: '0 0 16px 0', fontSize: '1rem', fontWeight: 600 }}>\r\n Configure: {node.id}\r\n </h2>\r\n\r\n {/* Node Settings */}\r\n <div style={{ marginBottom: '20px' }}>\r\n <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '8px' }}>\r\n Node Settings\r\n </h3>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>Label:</label>\r\n <input\r\n type=\"text\"\r\n value={node.label || node.id}\r\n onChange={(e) => onUpdateNode({ label: e.target.value })}\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n marginBottom: '8px',\r\n }}\r\n />\r\n\r\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px' }}>\r\n <div>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Label Offset X:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={node.labelOffset?.x ?? 0}\r\n onChange={(e) =>\r\n onUpdateNode({\r\n labelOffset: {\r\n x: parseFloat(e.target.value) || 0,\r\n y: node.labelOffset?.y ?? 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n <div>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Label Offset Y:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={node.labelOffset?.y ?? 0}\r\n onChange={(e) =>\r\n onUpdateNode({\r\n labelOffset: {\r\n x: node.labelOffset?.x ?? 0,\r\n y: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n\r\n <div>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Label Font Size:\r\n </label>\r\n <input\r\n type=\"number\"\r\n min=\"6\"\r\n max=\"24\"\r\n value={node.labelFontSize ?? 10}\r\n onChange={(e) =>\r\n onUpdateNode({\r\n labelFontSize: parseFloat(e.target.value) || 10,\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n\r\n <div>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Rotation (degrees):\r\n </label>\r\n <input\r\n type=\"number\"\r\n min=\"0\"\r\n max=\"360\"\r\n step=\"15\"\r\n value={node.transform.rotation ?? 0}\r\n onChange={(e) =>\r\n onUpdateNode({\r\n transform: {\r\n ...node.transform,\r\n rotation: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n\r\n {/* Telemetry Configuration */}\r\n <div style={{ marginBottom: '20px' }}>\r\n <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '8px' }}>\r\n Telemetry Data\r\n </h3>\r\n\r\n {!binding ? (\r\n <button\r\n onClick={() => {\r\n if (onAddTelemetry) {\r\n onAddTelemetry();\r\n } else {\r\n // Default telemetry initialization\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: node.id,\r\n value: {\r\n value: 50,\r\n status: 'normal',\r\n unit: 'PSI',\r\n timestamp: Date.now(),\r\n },\r\n history: [45, 47, 48, 50, 52, 51, 49, 50],\r\n display: {\r\n showValue: true,\r\n showSparkline: false,\r\n precision: 1,\r\n backgroundColor: 'status',\r\n },\r\n thresholds: {\r\n highHigh: 85,\r\n high: 70,\r\n low: 30,\r\n lowLow: 15,\r\n },\r\n });\r\n }\r\n }}\r\n style={{\r\n padding: '8px 16px',\r\n backgroundColor: '#3b82f6',\r\n color: '#fff',\r\n border: 'none',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n width: '100%',\r\n }}\r\n >\r\n + Add Telemetry\r\n </button>\r\n ) : (\r\n <>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Initial Value:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={binding.value.value as number}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n value: {\r\n ...binding.value,\r\n value: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n marginBottom: '8px',\r\n }}\r\n />\r\n\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Unit:\r\n </label>\r\n <input\r\n type=\"text\"\r\n value={binding.value.unit || ''}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n value: {\r\n ...binding.value,\r\n unit: e.target.value,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n marginBottom: '8px',\r\n }}\r\n />\r\n\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n <input\r\n type=\"checkbox\"\r\n checked={binding.display?.showSparkline ?? false}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n showSparkline: e.target.checked,\r\n },\r\n })\r\n }\r\n style={{ marginRight: '6px' }}\r\n />\r\n Show Sparkline\r\n </label>\r\n\r\n <div style={{ marginTop: '12px' }}>\r\n <label\r\n style={{\r\n fontSize: '0.75rem',\r\n fontWeight: 600,\r\n display: 'block',\r\n marginBottom: '8px',\r\n }}\r\n >\r\n Telemetry Position Offset:\r\n </label>\r\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px' }}>\r\n <div>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n X Offset:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={binding.display?.offsetX ?? 0}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n offsetX: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.75rem',\r\n }}\r\n />\r\n </div>\r\n <div>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n Y Offset:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={binding.display?.offsetY ?? 0}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n offsetY: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.75rem',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n {/* Text & Sparkline Colors */}\r\n <div style={{ marginTop: '16px' }}>\r\n <label\r\n style={{\r\n fontSize: '0.75rem',\r\n fontWeight: 600,\r\n display: 'block',\r\n marginBottom: '8px',\r\n }}\r\n >\r\n Display Colors:\r\n </label>\r\n\r\n {/* Text Color */}\r\n <div style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n Text Color:\r\n </label>\r\n <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>\r\n <input\r\n type=\"color\"\r\n value={binding.display?.textColor ?? '#000000'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n textColor: e.target.value,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '40px',\r\n height: '28px',\r\n border: '1px solid #cbd5e1',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n }}\r\n />\r\n <input\r\n type=\"text\"\r\n value={binding.display?.textColor ?? '#000000'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n textColor: e.target.value,\r\n },\r\n })\r\n }\r\n placeholder=\"#000000\"\r\n style={{\r\n flex: 1,\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.7rem',\r\n fontFamily: 'monospace',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n\r\n {/* Sparkline Color */}\r\n {binding.display?.showSparkline && (\r\n <div style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n Sparkline Color:\r\n </label>\r\n <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>\r\n <input\r\n type=\"color\"\r\n value={binding.display?.sparklineColor ?? '#3b82f6'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n sparklineColor: e.target.value,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '40px',\r\n height: '28px',\r\n border: '1px solid #cbd5e1',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n }}\r\n />\r\n <input\r\n type=\"text\"\r\n value={binding.display?.sparklineColor ?? '#3b82f6'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n sparklineColor: e.target.value,\r\n },\r\n })\r\n }\r\n placeholder=\"#3b82f6\"\r\n style={{\r\n flex: 1,\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.7rem',\r\n fontFamily: 'monospace',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Background Color */}\r\n <div style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n Background:\r\n </label>\r\n <input\r\n type=\"text\"\r\n value={binding.display?.backgroundColor ?? 'status'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n backgroundColor: e.target.value,\r\n },\r\n })\r\n }\r\n placeholder=\"status or #ffffff\"\r\n style={{\r\n width: '100%',\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.7rem',\r\n fontFamily: 'monospace',\r\n }}\r\n />\r\n <div style={{ fontSize: '0.65rem', color: '#6b7280', marginTop: '2px' }}>\r\n Use 'status' for status-based color or hex code\r\n </div>\r\n </div>\r\n </div>{' '}\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n\r\n {/* Thresholds (if telemetry exists) */}\r\n {binding && (\r\n <div style={{ marginBottom: '20px' }}>\r\n <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '8px' }}>Thresholds</h3>\r\n\r\n {(['highHigh', 'high', 'low', 'lowLow'] as const).map((key) => {\r\n const label =\r\n key === 'highHigh'\r\n ? 'High-High (≥)'\r\n : key === 'high'\r\n ? 'High (≥)'\r\n : key === 'low'\r\n ? 'Low (≤)'\r\n : 'Low-Low (≤)';\r\n return (\r\n <div key={key} style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n {label}\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={\r\n binding.thresholds?.[key] ??\r\n (key === 'highHigh' ? 85 : key === 'high' ? 70 : key === 'low' ? 30 : 15)\r\n }\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n thresholds: {\r\n ...binding.thresholds,\r\n [key]: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {/* Status Colors (if telemetry exists) */}\r\n {binding && (\r\n <div style={{ marginBottom: '20px' }}>\r\n <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '8px' }}>\r\n Status Colors\r\n </h3>\r\n\r\n {(['normal', 'warning', 'alarm', 'fault', 'off'] as const).map((status) => {\r\n const defaultColors = {\r\n normal: '#10b981',\r\n warning: '#f59e0b',\r\n alarm: '#ef4444',\r\n fault: '#8b5cf6',\r\n off: '#6b7280',\r\n };\r\n const label =\r\n status === 'normal'\r\n ? 'Normal'\r\n : status === 'warning'\r\n ? 'Warning'\r\n : status === 'alarm'\r\n ? 'Alarm'\r\n : status === 'fault'\r\n ? 'Fault'\r\n : 'Off';\r\n return (\r\n <div key={status} style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n {label}:\r\n </label>\r\n <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>\r\n <input\r\n type=\"color\"\r\n value={binding.statusColors?.[status] ?? defaultColors[status]}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n statusColors: {\r\n ...binding.statusColors,\r\n [status]: e.target.value,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '50px',\r\n height: '32px',\r\n border: '1px solid #cbd5e1',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n }}\r\n />\r\n <input\r\n type=\"text\"\r\n value={binding.statusColors?.[status] ?? defaultColors[status]}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n statusColors: {\r\n ...binding.statusColors,\r\n [status]: e.target.value,\r\n },\r\n })\r\n }\r\n placeholder={defaultColors[status]}\r\n style={{\r\n flex: 1,\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.75rem',\r\n fontFamily: 'monospace',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {/* Remove Node */}\r\n <div style={{ marginTop: '20px', paddingTop: '20px', borderTop: '1px solid #cbd5e1' }}>\r\n <button\r\n onClick={onRemove}\r\n style={{\r\n padding: '8px 16px',\r\n backgroundColor: '#ef4444',\r\n color: '#fff',\r\n border: 'none',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n width: '100%',\r\n }}\r\n >\r\n Remove Node\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { Diagram } from '../schema';\r\n\r\n/**\r\n * Validates a diagram object structure\r\n */\r\nexport function validateDiagram(diagram: unknown): { valid: boolean; errors: string[] } {\r\n const errors: string[] = [];\r\n\r\n if (!diagram || typeof diagram !== 'object') {\r\n errors.push('Diagram must be an object');\r\n return { valid: false, errors };\r\n }\r\n\r\n const d = diagram as Partial<Diagram>;\r\n\r\n // Required fields\r\n if (!d.id || typeof d.id !== 'string') {\r\n errors.push('Diagram must have a valid id (string)');\r\n }\r\n if (!d.name || typeof d.name !== 'string') {\r\n errors.push('Diagram must have a valid name (string)');\r\n }\r\n if (!d.version || typeof d.version !== 'string') {\r\n errors.push('Diagram must have a valid version (string)');\r\n }\r\n\r\n // ViewBox validation\r\n if (!d.viewBox) {\r\n errors.push('Diagram must have a viewBox');\r\n } else if (\r\n typeof d.viewBox.x !== 'number' ||\r\n typeof d.viewBox.y !== 'number' ||\r\n typeof d.viewBox.width !== 'number' ||\r\n typeof d.viewBox.height !== 'number'\r\n ) {\r\n errors.push('ViewBox must have numeric x, y, width, height properties');\r\n }\r\n\r\n // Array validations\r\n if (!Array.isArray(d.nodes)) {\r\n errors.push('Diagram.nodes must be an array');\r\n }\r\n if (!Array.isArray(d.pipes)) {\r\n errors.push('Diagram.pipes must be an array');\r\n }\r\n if (!Array.isArray(d.overlays)) {\r\n errors.push('Diagram.overlays must be an array');\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Serializes a diagram to JSON string\r\n */\r\nexport function exportDiagram(diagram: Diagram): string {\r\n return JSON.stringify(diagram, null, 2);\r\n}\r\n\r\n/**\r\n * Parses a diagram from JSON string\r\n */\r\nexport function importDiagram(json: string): Diagram {\r\n try {\r\n const parsed = JSON.parse(json);\r\n const validation = validateDiagram(parsed);\r\n\r\n if (!validation.valid) {\r\n throw new Error(`Invalid diagram: ${validation.errors.join(', ')}`);\r\n }\r\n\r\n return parsed as Diagram;\r\n } catch (error) {\r\n if (error instanceof SyntaxError) {\r\n throw new Error(`Invalid JSON: ${error.message}`);\r\n }\r\n throw error;\r\n }\r\n}\r\n","import type { Diagram } from '../schema';\r\nimport { generateRoutePoints } from '../utils/portCalculations';\r\n\r\n// Define nodes first so we can calculate pipe routes\r\nconst nodes = [\r\n {\r\n id: 'V-101',\r\n symbolId: 'valve-ball',\r\n transform: {\r\n x: 100,\r\n y: 150,\r\n rotation: 0,\r\n },\r\n ports: [\r\n { id: 'inlet', x: -25, y: 0, type: 'inlet' as const },\r\n { id: 'outlet', x: 25, y: 0, type: 'outlet' as const },\r\n ],\r\n },\r\n {\r\n id: 'P-101',\r\n symbolId: 'pump-centrifugal',\r\n transform: {\r\n x: 250,\r\n y: 150,\r\n rotation: 0,\r\n },\r\n ports: [\r\n { id: 'inlet', x: -40, y: 0, type: 'inlet' as const },\r\n { id: 'outlet', x: 40, y: 0, type: 'outlet' as const },\r\n ],\r\n },\r\n {\r\n id: 'T-101',\r\n symbolId: 'vessel-tank',\r\n transform: {\r\n x: 450,\r\n y: 120,\r\n rotation: 0,\r\n },\r\n ports: [\r\n { id: 'inlet', x: 0, y: -40, type: 'inlet' as const },\r\n { id: 'outlet', x: 0, y: 40, type: 'outlet' as const },\r\n ],\r\n },\r\n];\r\n\r\n/**\r\n * Example P&ID diagram with a simple valve-pump-tank flow\r\n * Uses automatic port-to-port connection routing\r\n */\r\nexport const exampleDiagram: Diagram = {\r\n id: 'example-001',\r\n name: 'Simple Process Flow',\r\n version: '1.0.0',\r\n viewBox: {\r\n x: -100,\r\n y: -50,\r\n width: 1200,\r\n height: 600,\r\n },\r\n nodes,\r\n pipes: [\r\n {\r\n id: 'pipe-001',\r\n fromNodeId: 'V-101',\r\n fromPortId: 'outlet',\r\n toNodeId: 'P-101',\r\n toPortId: 'inlet',\r\n routePoints: generateRoutePoints(nodes[0], 'outlet', nodes[1], 'inlet'),\r\n style: {\r\n stroke: '#0277bd',\r\n strokeWidth: 4,\r\n },\r\n },\r\n {\r\n id: 'pipe-002',\r\n fromNodeId: 'P-101',\r\n fromPortId: 'outlet',\r\n toNodeId: 'T-101',\r\n toPortId: 'inlet',\r\n routePoints: generateRoutePoints(nodes[1], 'outlet', nodes[2], 'inlet', {\r\n style: 'orthogonal',\r\n }),\r\n style: {\r\n stroke: '#2e7d32',\r\n strokeWidth: 4,\r\n },\r\n },\r\n ],\r\n overlays: [\r\n {\r\n id: 'overlay-v101',\r\n type: 'value',\r\n anchorType: 'node',\r\n anchorId: 'V-101',\r\n offset: { x: 0, y: -40 },\r\n binding: {\r\n sourceType: 'tag',\r\n source: 'V101.position',\r\n format: '0.0%',\r\n },\r\n content: {\r\n text: 'Valve Position',\r\n },\r\n },\r\n {\r\n id: 'overlay-p101',\r\n type: 'value',\r\n anchorType: 'node',\r\n anchorId: 'P-101',\r\n offset: { x: 0, y: -50 },\r\n binding: {\r\n sourceType: 'tag',\r\n source: 'P101.flow',\r\n format: '0.0 LPM',\r\n },\r\n content: {\r\n text: 'Flow Rate',\r\n },\r\n },\r\n {\r\n id: 'overlay-t101',\r\n type: 'gauge',\r\n anchorType: 'node',\r\n anchorId: 'T-101',\r\n offset: { x: 60, y: 0 },\r\n binding: {\r\n sourceType: 'tag',\r\n source: 'T101.level',\r\n },\r\n content: {\r\n component: 'CircularGauge',\r\n props: {\r\n max: 100,\r\n unit: '%',\r\n label: 'Level',\r\n },\r\n },\r\n },\r\n ],\r\n metadata: {\r\n author: 'System',\r\n created: '2025-12-31T00:00:00Z',\r\n description: 'Example P&ID diagram demonstrating schema structure',\r\n tags: ['example', 'tutorial'],\r\n },\r\n};\r\n","/**\r\n * Telemetry status type\r\n */\r\nexport type TelemetryStatus = 'normal' | 'warning' | 'alarm' | 'fault' | 'off';\r\n\r\n/**\r\n * Threshold configuration\r\n */\r\nexport interface Thresholds {\r\n highHigh?: number;\r\n high?: number;\r\n low?: number;\r\n lowLow?: number;\r\n}\r\n\r\n/**\r\n * Calculate status based on value and thresholds\r\n * @param value - Current numeric value\r\n * @param thresholds - Threshold configuration\r\n * @returns Status string\r\n */\r\nexport function calculateThresholdStatus(\r\n value: number,\r\n thresholds?: Thresholds\r\n): TelemetryStatus {\r\n if (!thresholds) return 'normal';\r\n\r\n const { highHigh, high, low, lowLow } = thresholds;\r\n\r\n // Check high-high alarm (highest priority)\r\n if (highHigh !== undefined && value >= highHigh) {\r\n return 'alarm';\r\n }\r\n\r\n // Check low-low fault\r\n if (lowLow !== undefined && value <= lowLow) {\r\n return 'fault';\r\n }\r\n\r\n // Check high warning\r\n if (high !== undefined && value >= high) {\r\n return 'warning';\r\n }\r\n\r\n // Check low warning\r\n if (low !== undefined && value <= low) {\r\n return 'warning';\r\n }\r\n\r\n return 'normal';\r\n}\r\n\r\n/**\r\n * Default thresholds for typical industrial processes (percentage-based)\r\n */\r\nexport const DEFAULT_THRESHOLDS: Thresholds = {\r\n highHigh: 85,\r\n high: 70,\r\n low: 30,\r\n lowLow: 15,\r\n};\r\n","import { useEffect } from 'react';\r\nimport { calculateThresholdStatus } from '../../utils/thresholds';\r\nimport type { TelemetryMap, TelemetryBinding } from './useTelemetry';\r\n\r\n/**\r\n * Options for simulation behavior\r\n */\r\nexport interface SimulationOptions {\r\n /** Update interval in milliseconds (default: 2000) */\r\n interval?: number;\r\n /** Whether simulation is enabled (default: true) */\r\n enabled?: boolean;\r\n /** Maximum change per update (default: 10) */\r\n maxChange?: number;\r\n /** Minimum value clamp (default: 0) */\r\n minValue?: number;\r\n /** Maximum value clamp (default: 100) */\r\n maxValue?: number;\r\n /** Maximum history length (default: 10) */\r\n historyLength?: number;\r\n /** Custom value generator function */\r\n generateValue?: (currentValue: number, nodeId: string) => number;\r\n}\r\n\r\n/**\r\n * Hook to automatically simulate telemetry data updates\r\n * Randomly updates numeric telemetry values and calculates status based on thresholds\r\n * \r\n * @param telemetry - Telemetry map from useTelemetry\r\n * @param updateTelemetryBatch - Batch update function from useTelemetry\r\n * @param options - Simulation configuration options\r\n * \r\n * @example\r\n * ```tsx\r\n * const { telemetry, updateTelemetryBatch } = useTelemetry();\r\n * useSimulation(telemetry, updateTelemetryBatch, {\r\n * interval: 2000,\r\n * enabled: mode === 'runtime'\r\n * });\r\n * ```\r\n */\r\nexport function useSimulation(\r\n telemetry: TelemetryMap,\r\n updateTelemetryBatch: (updates: Array<any>) => void,\r\n options: SimulationOptions = {}\r\n) {\r\n const {\r\n interval = 2000,\r\n enabled = true,\r\n maxChange = 10,\r\n minValue = 0,\r\n maxValue = 100,\r\n historyLength = 10,\r\n generateValue,\r\n } = options;\r\n\r\n useEffect(() => {\r\n if (!enabled) return;\r\n\r\n const intervalId = setInterval(() => {\r\n const updates: Array<{\r\n nodeId: string;\r\n tag?: string;\r\n value?: any;\r\n history?: number[];\r\n display?: any;\r\n thresholds?: any;\r\n statusColors?: any;\r\n }> = [];\r\n\r\n telemetry.forEach((binding: TelemetryBinding, nodeId: string) => {\r\n // Only simulate numeric values\r\n if (typeof binding.value.value !== 'number') return;\r\n\r\n const currentValue = binding.value.value as number;\r\n\r\n // Generate new value\r\n let newValue: number;\r\n if (generateValue) {\r\n newValue = generateValue(currentValue, nodeId);\r\n } else {\r\n // Default random walk simulation\r\n const change = (Math.random() - 0.5) * maxChange;\r\n newValue = Math.max(minValue, Math.min(maxValue, currentValue + change));\r\n }\r\n\r\n // Calculate status based on thresholds\r\n const status = calculateThresholdStatus(newValue, binding.thresholds);\r\n\r\n // Update history\r\n const newHistory = [...(binding.history || []), newValue].slice(-historyLength);\r\n\r\n updates.push({\r\n nodeId,\r\n tag: binding.tag,\r\n value: {\r\n ...binding.value,\r\n value: newValue,\r\n status,\r\n timestamp: Date.now(),\r\n },\r\n history: newHistory,\r\n display: binding.display,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n });\r\n });\r\n\r\n if (updates.length > 0) {\r\n updateTelemetryBatch(updates);\r\n }\r\n }, interval);\r\n\r\n return () => clearInterval(intervalId);\r\n }, [\r\n enabled,\r\n interval,\r\n maxChange,\r\n minValue,\r\n maxValue,\r\n historyLength,\r\n generateValue,\r\n telemetry,\r\n updateTelemetryBatch,\r\n ]);\r\n}\r\n"],"mappings":"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","names":["useState","jsx","selectedOption","useState","jsx","jsxs","useState","useCallback","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","React","jsx","useEffect","useState","Box","styled","jsx","jsx","jsxs","Fragment","jsx","jsxs","React","useState","useEffect","jsx","jsx","jsxs","useCallback","useState","useEffect","jsx","jsxs","nodes","Fragment","jsx","jsxs","Fragment","jsx","jsxs","useState","useCallback","useRef","useEffect","useState","useCallback","useState","useCallback","useEffect","useRef","useState","useCallback","useRef","useEffect","useEffect","Fragment","jsx","jsxs","useState","useEffect","useCallback","useState","jsx","jsxs","useState","Fragment","jsx","jsxs","useEffect","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/Button/Button.tsx","../src/components/ControlPanel/ControlPanel.tsx","../src/components/Selector/Selector.tsx","../src/components/ValueEntry/ValueEntry.tsx","../src/components/ValueEntry/LegacyValueEntry.tsx","../src/components/StatusIndicator/StatusIndicator.tsx","../src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx","../src/components/layout/FullscreenWorkspace/FullscreenWorkspace.styles.tsx","../src/components/layout/FullscreenWorkspace/FullscreenWorkspace.overlays.tsx","../src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx","../src/theme/ThemeContext.tsx","../src/theme/ThemeToggle.tsx","../src/components/PIDCanvas/PIDCanvas.tsx","../src/diagram/symbols/mockSymbolLibrary.ts","../src/components/PIDCanvas/NodeRenderer.tsx","../src/components/PIDCanvas/PipeRenderer.tsx","../src/components/PIDCanvas/DataOverlay.tsx","../src/components/PIDCanvas/PositionPanel.tsx","../src/diagram/hooks/useViewBox.ts","../src/diagram/hooks/useSelection.ts","../src/diagram/hooks/useTelemetry.ts","../src/diagram/hooks/useTelemetryStatus.ts","../src/diagram/hooks/useDrag.ts","../src/diagram/hooks/useKeyboardShortcuts.ts","../src/diagram/utils/portCalculations.ts","../src/components/SymbolLibrary/SymbolLibrary.tsx","../src/components/NodeConfigPanel/NodeConfigPanel.tsx","../src/diagram/utils/serialization.ts","../src/diagram/examples/exampleDiagram.ts","../src/utils/thresholds.ts","../src/diagram/hooks/useSimulation.ts"],"sourcesContent":["import React from 'react';\r\n\r\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\r\n variant?: 'primary' | 'secondary';\r\n children: React.ReactNode;\r\n}\r\n\r\nexport const Button: React.FC<ButtonProps> = ({\r\n variant = 'primary',\r\n children,\r\n className = '',\r\n ...props\r\n}) => {\r\n // Use CSS classes for base and variant styles\r\n const baseClass = 'ui-btn';\r\n const variantClass = variant ? `ui-btn--${variant}` : '';\r\n return (\r\n <button className={`${baseClass} ${variantClass} ${className}`.trim()} {...props}>\r\n {children}\r\n </button>\r\n );\r\n};\r\n","import React, { useState } from 'react';\r\nimport { Selector, SelectorOption } from '../Selector';\r\nimport { LegacyValueEntry as ValueEntry } from '../ValueEntry';\r\nimport { Button } from '../Button';\r\n\r\nexport interface ModeConfig {\r\n /** Units for this mode */\r\n unit?: string;\r\n /** Label for the primary setpoint */\r\n label?: string;\r\n /** Minimum value for primary setpoint */\r\n min?: number;\r\n /** Maximum value for primary setpoint */\r\n max?: number;\r\n /** Precision for primary setpoint */\r\n precision?: number;\r\n /** Whether this mode has a second setpoint (like ramp time) */\r\n hasSecondSetpoint?: boolean;\r\n /** Label for the second setpoint */\r\n secondLabel?: string;\r\n /** Units for the second setpoint */\r\n secondUnit?: string;\r\n /** Min value for second setpoint */\r\n secondMin?: number;\r\n /** Max value for second setpoint */\r\n secondMax?: number;\r\n /** Precision for second setpoint */\r\n secondPrecision?: number;\r\n}\r\n\r\nexport interface ControlPanelProps extends React.HTMLAttributes<HTMLDivElement> {\r\n /** Panel title/identifier */\r\n title: string;\r\n /** Currently selected mode */\r\n selectedMode: string;\r\n /** Available mode options */\r\n modeOptions: SelectorOption[];\r\n /** Callback when mode changes */\r\n onModeChange: (mode: string) => void;\r\n /** Current setpoint value */\r\n setpointValue: number | string;\r\n /** Callback when setpoint changes */\r\n onSetpointChange: (value: number | string) => void;\r\n /** Current second setpoint value (for ramp mode, etc.) */\r\n secondSetpointValue?: number | string;\r\n /** Callback when second setpoint changes */\r\n onSecondSetpointChange?: (value: number | string) => void;\r\n /** Configuration for each mode */\r\n modeConfigs?: Record<string, ModeConfig>;\r\n /** Default unit when no mode config is found */\r\n defaultUnit?: string;\r\n /** Default label when no mode config is found */\r\n defaultLabel?: string;\r\n /** Default min when no mode config is found */\r\n defaultMin?: number;\r\n /** Default max when no mode config is found */\r\n defaultMax?: number;\r\n /** Default precision when no mode config is found */\r\n defaultPrecision?: number;\r\n /** Status state for the entire panel */\r\n status?: 'normal' | 'alarm' | 'warning' | 'disabled';\r\n /** Whether the panel is collapsed */\r\n collapsed?: boolean;\r\n /** Callback when collapse state changes */\r\n onCollapseChange?: (collapsed: boolean) => void;\r\n /** Panel size variant */\r\n size?: 'small' | 'medium' | 'large';\r\n /** Whether setpoint is read-only */\r\n setpointReadOnly?: boolean;\r\n /** Whether to show start/stop buttons */\r\n showStartStopButtons?: boolean;\r\n /** Whether the process is currently running */\r\n isRunning?: boolean;\r\n /** Callback when start button is clicked */\r\n onStart?: () => void;\r\n /** Callback when stop button is clicked */\r\n onStop?: () => void;\r\n /** Custom start button text */\r\n startButtonText?: string;\r\n /** Custom stop button text */\r\n stopButtonText?: string;\r\n}\r\n\r\nexport const ControlPanel: React.FC<ControlPanelProps> = ({\r\n title,\r\n selectedMode,\r\n modeOptions,\r\n onModeChange,\r\n setpointValue,\r\n onSetpointChange,\r\n secondSetpointValue,\r\n onSecondSetpointChange,\r\n modeConfigs = {},\r\n defaultUnit = 'Units',\r\n defaultLabel = 'Setpoint',\r\n defaultMin = 0,\r\n defaultMax = 100,\r\n defaultPrecision = 2,\r\n status = 'normal',\r\n collapsed = false,\r\n onCollapseChange,\r\n size = 'medium',\r\n setpointReadOnly = false,\r\n showStartStopButtons = false,\r\n isRunning = false,\r\n onStart,\r\n onStop,\r\n startButtonText = 'Start',\r\n stopButtonText = 'Stop',\r\n className = '',\r\n ...props\r\n}) => {\r\n const [isExpanded, setIsExpanded] = useState(!collapsed);\r\n\r\n const toggleExpanded = () => {\r\n const newExpanded = !isExpanded;\r\n setIsExpanded(newExpanded);\r\n onCollapseChange?.(!newExpanded);\r\n };\r\n\r\n // Get current mode configuration\r\n const currentModeConfig = modeConfigs[selectedMode] || {};\r\n const currentUnit = currentModeConfig.unit || defaultUnit;\r\n const currentLabel = currentModeConfig.label || defaultLabel;\r\n const currentMin = currentModeConfig.min ?? defaultMin;\r\n const currentMax = currentModeConfig.max ?? defaultMax;\r\n const currentPrecision = currentModeConfig.precision ?? defaultPrecision;\r\n const hasSecondSetpoint = currentModeConfig.hasSecondSetpoint || false;\r\n\r\n // Use CSS classes for base, status, size, and expanded state\r\n const baseClass = 'ui-control-panel';\r\n const statusClass = status ? `ui-control-panel--${status}` : '';\r\n const sizeClass = size ? `ui-control-panel--${size}` : '';\r\n const expandedClass = isExpanded ? 'is-expanded' : 'is-collapsed';\r\n const collapsibleClass = onCollapseChange ? 'is-collapsible' : '';\r\n\r\n return (\r\n <div\r\n className={`${baseClass} ${statusClass} ${sizeClass} ${expandedClass} ${collapsibleClass} ${className}`.trim()}\r\n {...props}\r\n >\r\n {/* Status Badge */}\r\n <div className={`ui-control-panel-badge ui-control-panel-badge--${status}`} />\r\n\r\n {/* Header */}\r\n <div\r\n className=\"ui-control-panel-header\"\r\n onClick={onCollapseChange ? toggleExpanded : undefined}\r\n >\r\n <h3 className=\"ui-control-panel-title\">{title}</h3>\r\n {onCollapseChange && (\r\n <svg\r\n className=\"ui-control-panel-chevron\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n >\r\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\r\n </svg>\r\n )}\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"ui-control-panel-content\">\r\n {/* Mode Selector */}\r\n <div>\r\n <Selector\r\n value={selectedMode}\r\n onChange={onModeChange}\r\n options={modeOptions}\r\n label=\"Control Mode\"\r\n status={status}\r\n size={size === 'small' ? 'small' : size === 'large' ? 'large' : 'medium'}\r\n disabled={status === 'disabled'}\r\n />\r\n </div>\r\n\r\n {/* Primary Setpoint Value Entry */}\r\n <div>\r\n <ValueEntry\r\n value={setpointValue}\r\n onChange={onSetpointChange}\r\n label={currentLabel}\r\n unit={currentUnit}\r\n min={currentMin}\r\n max={currentMax}\r\n precision={currentPrecision}\r\n status={status}\r\n readOnly={setpointReadOnly || status === 'disabled'}\r\n disabled={status === 'disabled'}\r\n />\r\n </div>\r\n\r\n {/* Second Setpoint (for ramp mode, etc.) */}\r\n {hasSecondSetpoint && onSecondSetpointChange && (\r\n <div>\r\n <ValueEntry\r\n value={secondSetpointValue || 0}\r\n onChange={onSecondSetpointChange}\r\n label={currentModeConfig.secondLabel || 'Time'}\r\n unit={currentModeConfig.secondUnit || 'sec'}\r\n min={currentModeConfig.secondMin ?? 0}\r\n max={currentModeConfig.secondMax ?? 999}\r\n precision={currentModeConfig.secondPrecision ?? 0}\r\n status={status}\r\n readOnly={setpointReadOnly || status === 'disabled'}\r\n disabled={status === 'disabled'}\r\n />\r\n </div>\r\n )}\r\n\r\n {/* Start/Stop Buttons */}\r\n {showStartStopButtons && (onStart || onStop) && (\r\n <div className=\"ui-control-panel-buttons\">\r\n {onStart && (\r\n <Button\r\n variant=\"primary\"\r\n onClick={onStart}\r\n disabled={isRunning || status === 'disabled'}\r\n className={isRunning ? 'is-running' : ''}\r\n >\r\n {startButtonText}\r\n </Button>\r\n )}\r\n {onStop && (\r\n <Button\r\n variant=\"secondary\"\r\n onClick={onStop}\r\n disabled={!isRunning || status === 'disabled'}\r\n className={`ui-control-panel-stop-btn${!isRunning ? ' is-disabled' : ''}`}\r\n >\r\n {stopButtonText}\r\n </Button>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Additional Info Row */}\r\n <div className=\"ui-control-panel-info\">\r\n <span>Mode: {selectedMode.toUpperCase()}</span>\r\n <div className=\"ui-control-panel-info-values\">\r\n <span>\r\n SP: {String(setpointValue)}\r\n {currentUnit}\r\n </span>\r\n {hasSecondSetpoint && secondSetpointValue && (\r\n <span>\r\n {currentModeConfig.secondLabel}: {String(secondSetpointValue)}\r\n {currentModeConfig.secondUnit}\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useRef, useEffect } from 'react';\r\n\r\nexport interface SelectorOption {\r\n /** Unique value for the option */\r\n value: string;\r\n /** Display label for the option */\r\n label: string;\r\n /** Whether this option is disabled */\r\n disabled?: boolean;\r\n /** Optional description for tooltip or additional context */\r\n description?: string;\r\n}\r\n\r\nexport interface SelectorProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\r\n /** Currently selected value */\r\n value: string;\r\n /** Callback when selection changes */\r\n onChange: (value: string) => void;\r\n /** List of available options */\r\n options: SelectorOption[];\r\n /** Placeholder text when no option is selected */\r\n placeholder?: string;\r\n /** Whether the selector is disabled */\r\n disabled?: boolean;\r\n /** Status state for visual feedback */\r\n status?: 'normal' | 'alarm' | 'warning' | 'disabled';\r\n /** Size variant */\r\n size?: 'small' | 'medium' | 'large';\r\n /** Label for the selector */\r\n label?: string;\r\n /** Whether the dropdown should open upward */\r\n dropdownUp?: boolean;\r\n}\r\n\r\nexport const Selector: React.FC<SelectorProps> = ({\r\n value,\r\n onChange,\r\n options,\r\n placeholder = 'Select option...',\r\n disabled = false,\r\n status = 'normal',\r\n size = 'medium',\r\n label,\r\n dropdownUp: _dropdownUp = false,\r\n className = '',\r\n ...props\r\n}) => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [focusedIndex, setFocusedIndex] = useState(-1);\r\n const selectorRef = useRef<HTMLDivElement>(null);\r\n const dropdownRef = useRef<HTMLDivElement>(null);\r\n\r\n // Close dropdown when clicking outside\r\n useEffect(() => {\r\n const handleClickOutside = (event: MouseEvent) => {\r\n if (selectorRef.current && !selectorRef.current.contains(event.target as Node)) {\r\n setIsOpen(false);\r\n setFocusedIndex(-1);\r\n }\r\n };\r\n document.addEventListener('mousedown', handleClickOutside);\r\n return () => document.removeEventListener('mousedown', handleClickOutside);\r\n }, []);\r\n\r\n // Handle keyboard navigation\r\n const handleKeyDown = (e: React.KeyboardEvent) => {\r\n if (disabled) return;\r\n switch (e.key) {\r\n case 'Enter':\r\n case ' ':\r\n e.preventDefault();\r\n if (!isOpen) {\r\n setIsOpen(true);\r\n setFocusedIndex(\r\n Math.max(\r\n 0,\r\n options.findIndex((opt) => opt.value === value)\r\n )\r\n );\r\n } else if (focusedIndex >= 0) {\r\n const selectedOption = options[focusedIndex];\r\n if (!selectedOption.disabled) {\r\n onChange(selectedOption.value);\r\n setIsOpen(false);\r\n setFocusedIndex(-1);\r\n }\r\n }\r\n break;\r\n case 'Escape':\r\n setIsOpen(false);\r\n setFocusedIndex(-1);\r\n break;\r\n case 'ArrowDown':\r\n e.preventDefault();\r\n if (!isOpen) {\r\n setIsOpen(true);\r\n setFocusedIndex(\r\n Math.max(\r\n 0,\r\n options.findIndex((opt) => opt.value === value)\r\n )\r\n );\r\n } else {\r\n setFocusedIndex((prev) => {\r\n const nextIndex = Math.min(prev + 1, options.length - 1);\r\n return options[nextIndex]?.disabled ? prev : nextIndex;\r\n });\r\n }\r\n break;\r\n case 'ArrowUp':\r\n e.preventDefault();\r\n if (isOpen) {\r\n setFocusedIndex((prev) => {\r\n const nextIndex = Math.max(prev - 1, 0);\r\n return options[nextIndex]?.disabled ? prev : nextIndex;\r\n });\r\n }\r\n break;\r\n }\r\n };\r\n\r\n // CSS class names for base, status, and size\r\n const baseClass = 'ui-selector';\r\n const statusClass = status ? `ui-selector--${status}` : '';\r\n const sizeClass = size ? `ui-selector--${size}` : '';\r\n\r\n // Get current selected option\r\n const selectedOption = options.find((opt) => opt.value === value);\r\n\r\n return (\r\n <div className={`ui-selector-container ${className}`.trim()}>\r\n {label && <label className=\"ui-selector-label\">{label}</label>}\r\n <div ref={selectorRef} style={{ position: 'relative' }}>\r\n <div\r\n className={`${baseClass} ${statusClass} ${sizeClass}`.trim()}\r\n onClick={() => !disabled && setIsOpen(!isOpen)}\r\n onKeyDown={handleKeyDown}\r\n tabIndex={disabled ? -1 : 0}\r\n role=\"combobox\"\r\n aria-expanded={isOpen}\r\n aria-haspopup=\"listbox\"\r\n {...props}\r\n >\r\n <span className=\"ui-selector-value\">\r\n {selectedOption ? selectedOption.label : placeholder}\r\n </span>\r\n {/* Arrow Icon */}\r\n <svg className=\"ui-selector-arrow\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\r\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\r\n </svg>\r\n </div>\r\n\r\n {/* Dropdown */}\r\n {isOpen && (\r\n <div ref={dropdownRef} className=\"ui-selector-dropdown\" role=\"listbox\">\r\n {options.map((option, index) => (\r\n <div\r\n key={option.value}\r\n className={`ui-selector-option${option.disabled ? ' is-disabled' : ''}${option.value === value ? ' is-selected' : ''}`}\r\n onClick={() => {\r\n if (!option.disabled) {\r\n onChange(option.value);\r\n setIsOpen(false);\r\n setFocusedIndex(-1);\r\n }\r\n }}\r\n onMouseEnter={() => !option.disabled && setFocusedIndex(index)}\r\n role=\"option\"\r\n aria-selected={option.value === value}\r\n aria-disabled={option.disabled}\r\n title={option.description}\r\n >\r\n <div className=\"ui-selector-option-label\">\r\n <span>{option.label}</span>\r\n {option.value === value && (\r\n <svg className=\"ui-selector-check\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path\r\n fillRule=\"evenodd\"\r\n d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\r\n clipRule=\"evenodd\"\r\n />\r\n </svg>\r\n )}\r\n </div>\r\n {option.description && (\r\n <div className=\"ui-selector-option-desc\">{option.description}</div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useCallback } from 'react';\r\n\r\nexport interface ValueEntryProps\r\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {\r\n /** Current value */\r\n value: number | string;\r\n /** Callback when value changes */\r\n onChange: (value: number | string) => void;\r\n /** Unit of measurement to display */\r\n unit?: string;\r\n /** Status state for visual feedback */\r\n status?: 'normal' | 'alarm' | 'warning' | 'disabled';\r\n /** Minimum allowed value (for numeric inputs) */\r\n min?: number;\r\n /** Maximum allowed value (for numeric inputs) */\r\n max?: number;\r\n /** Number of decimal places (for numeric inputs) */\r\n precision?: number;\r\n /** Input type - numeric or text */\r\n inputType?: 'numeric' | 'text';\r\n /** Label for the input */\r\n label?: string;\r\n /** Whether the input is read-only */\r\n readOnly?: boolean;\r\n}\r\n\r\nexport const ValueEntry: React.FC<ValueEntryProps> = ({\r\n value,\r\n onChange,\r\n unit,\r\n status = 'normal',\r\n min,\r\n max,\r\n precision = 2,\r\n inputType = 'numeric',\r\n label,\r\n readOnly = false,\r\n className = '',\r\n disabled,\r\n ...props\r\n}) => {\r\n const [displayValue, setDisplayValue] = useState(String(value));\r\n const [isEditing, setIsEditing] = useState(false);\r\n\r\n const handleFocus = useCallback(() => {\r\n setIsEditing(true);\r\n setDisplayValue(String(value));\r\n }, [value]);\r\n\r\n const handleBlur = useCallback(() => {\r\n setIsEditing(false);\r\n let newValue: number | string = displayValue;\r\n\r\n if (inputType === 'numeric') {\r\n const numValue = parseFloat(displayValue);\r\n if (!isNaN(numValue)) {\r\n // Apply min/max constraints\r\n let constrainedValue = numValue;\r\n if (min !== undefined) constrainedValue = Math.max(min, constrainedValue);\r\n if (max !== undefined) constrainedValue = Math.min(max, constrainedValue);\r\n\r\n // Apply precision\r\n constrainedValue = parseFloat(constrainedValue.toFixed(precision));\r\n newValue = constrainedValue;\r\n setDisplayValue(String(constrainedValue));\r\n } else {\r\n // Invalid number, revert to original value\r\n setDisplayValue(String(value));\r\n return;\r\n }\r\n }\r\n\r\n if (newValue !== value) {\r\n onChange(newValue);\r\n }\r\n }, [displayValue, inputType, min, max, precision, value, onChange]);\r\n\r\n const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\r\n setDisplayValue(e.target.value);\r\n }, []);\r\n\r\n const handleKeyDown = useCallback(\r\n (e: React.KeyboardEvent<HTMLInputElement>) => {\r\n if (e.key === 'Enter') {\r\n e.currentTarget.blur();\r\n }\r\n if (e.key === 'Escape') {\r\n setDisplayValue(String(value));\r\n e.currentTarget.blur();\r\n }\r\n },\r\n [value]\r\n );\r\n\r\n // Use CSS classes for base, status, and unit styles\r\n const baseClass = 'ui-value-entry';\r\n const unitClass = unit ? 'ui-value-entry--with-unit' : '';\r\n const currentStatus = disabled || readOnly ? 'disabled' : status;\r\n const statusVariantClass = currentStatus ? `ui-value-entry--${currentStatus}` : '';\r\n\r\n const displayText = isEditing\r\n ? displayValue\r\n : inputType === 'numeric'\r\n ? Number(value).toFixed(precision)\r\n : String(value);\r\n\r\n return (\r\n <div className=\"ui-value-entry-container\">\r\n {label && <label className=\"ui-value-entry-label\">{label}</label>}\r\n <div className=\"ui-value-entry-wrapper\">\r\n <input\r\n type={inputType === 'numeric' ? 'text' : 'text'}\r\n value={displayText}\r\n onChange={handleChange}\r\n onFocus={handleFocus}\r\n onBlur={handleBlur}\r\n onKeyDown={handleKeyDown}\r\n disabled={disabled}\r\n readOnly={readOnly}\r\n className={`${baseClass} ${statusVariantClass} ${unitClass} ${className}`.trim()}\r\n {...props}\r\n />\r\n {unit && <span className=\"ui-value-entry-unit\">{unit}</span>}\r\n {status === 'alarm' && <div className=\"ui-value-entry-badge ui-value-entry-badge--alarm\" />}\r\n {status === 'warning' && (\r\n <div className=\"ui-value-entry-badge ui-value-entry-badge--warning\" />\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useCallback } from 'react';\n\nexport interface LegacyValueEntryProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {\n /** Current value */\n value: number | string;\n /** Callback when value changes */\r\n onChange: (value: number | string) => void;\r\n /** Unit of measurement to display */\r\n unit?: string;\r\n /** Status state for visual feedback */\r\n status?: 'normal' | 'alarm' | 'warning' | 'disabled';\r\n /** Minimum allowed value (for numeric inputs) */\r\n min?: number;\r\n /** Maximum allowed value (for numeric inputs) */\r\n max?: number;\r\n /** Number of decimal places (for numeric inputs) */\r\n precision?: number;\r\n /** Input type - numeric or text */\r\n inputType?: 'numeric' | 'text';\r\n /** Label for the input */\n label?: string;\n /** Whether the input is read-only */\n readOnly?: boolean;\n}\n\nexport const LegacyValueEntry: React.FC<LegacyValueEntryProps> = ({\n value,\n onChange,\n unit,\n status = 'normal',\n min,\r\n max,\r\n precision = 2,\r\n inputType = 'numeric',\r\n label,\r\n readOnly = false,\r\n className = '',\r\n disabled,\r\n ...props\r\n}) => {\r\n const [displayValue, setDisplayValue] = useState(String(value));\r\n const [isEditing, setIsEditing] = useState(false);\r\n\r\n const handleFocus = useCallback(() => {\r\n setIsEditing(true);\r\n setDisplayValue(String(value));\r\n }, [value]);\r\n\r\n const handleBlur = useCallback(() => {\r\n setIsEditing(false);\r\n let newValue: number | string = displayValue;\r\n\r\n if (inputType === 'numeric') {\r\n const numValue = parseFloat(displayValue);\r\n if (!isNaN(numValue)) {\r\n // Apply min/max constraints\r\n let constrainedValue = numValue;\r\n if (min !== undefined) constrainedValue = Math.max(min, constrainedValue);\r\n if (max !== undefined) constrainedValue = Math.min(max, constrainedValue);\r\n\r\n // Apply precision\r\n constrainedValue = parseFloat(constrainedValue.toFixed(precision));\r\n newValue = constrainedValue;\r\n setDisplayValue(String(constrainedValue));\r\n } else {\r\n // Invalid number, revert to original value\r\n setDisplayValue(String(value));\r\n return;\r\n }\r\n }\r\n\r\n if (newValue !== value) {\r\n onChange(newValue);\r\n }\r\n }, [displayValue, inputType, min, max, precision, value, onChange]);\r\n\r\n const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\r\n setDisplayValue(e.target.value);\r\n }, []);\r\n\r\n const handleKeyDown = useCallback(\r\n (e: React.KeyboardEvent<HTMLInputElement>) => {\r\n if (e.key === 'Enter') {\r\n e.currentTarget.blur();\r\n }\r\n if (e.key === 'Escape') {\r\n setDisplayValue(String(value));\r\n e.currentTarget.blur();\r\n }\r\n },\r\n [value]\r\n );\r\n\r\n // Create the display text\r\n const displayText = isEditing\r\n ? displayValue\r\n : inputType === 'numeric'\r\n ? Number(value).toFixed(precision)\r\n : String(value);\r\n\r\n // Status-based styling with modern industrial colors\r\n const getStatusStyles = () => {\r\n switch (status) {\r\n case 'alarm':\r\n return {\r\n borderColor: '#ef4444',\r\n backgroundColor: 'rgba(239, 68, 68, 0.15)',\r\n color: '#fecaca',\r\n boxShadow: '0 0 20px rgba(239, 68, 68, 0.3)',\r\n };\r\n case 'warning':\r\n return {\r\n borderColor: '#f59e0b',\r\n backgroundColor: 'rgba(245, 158, 11, 0.15)',\r\n color: '#fed7aa',\r\n boxShadow: '0 0 20px rgba(245, 158, 11, 0.3)',\r\n };\r\n case 'disabled':\r\n return {\r\n borderColor: '#6b7280',\r\n backgroundColor: 'rgba(107, 114, 128, 0.1)',\r\n color: '#9ca3af',\r\n cursor: 'not-allowed',\r\n };\r\n default:\r\n return {\r\n borderColor: '#64748b',\r\n backgroundColor: 'rgba(30, 41, 59, 0.9)',\r\n color: '#f1f5f9',\r\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3)',\r\n };\r\n }\r\n };\r\n\r\n const statusStyles = getStatusStyles();\r\n\r\n const inputStyle: React.CSSProperties = {\r\n width: '12rem',\r\n height: '4rem',\r\n padding: unit ? '1rem 4rem 1rem 1.5rem' : '1rem 1.5rem',\r\n border: '2px solid',\r\n borderRadius: '1.5rem',\r\n fontFamily:\r\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace',\r\n fontSize: '1.25rem',\r\n fontWeight: 'bold',\r\n textAlign: 'center',\r\n outline: 'none',\r\n transition: 'all 300ms ease',\r\n backdropFilter: 'blur(8px)',\r\n ...statusStyles,\r\n };\r\n\r\n const inputStyleFocus: React.CSSProperties = {\r\n ...inputStyle,\r\n borderColor: '#60a5fa',\r\n boxShadow:\r\n '0 0 0 4px rgba(96, 165, 250, 0.3), ' +\r\n (statusStyles.boxShadow || '0 8px 32px rgba(0, 0, 0, 0.3)'),\r\n transform: 'scale(1.02)',\r\n };\r\n\r\n const unitStyle: React.CSSProperties = {\r\n position: 'absolute',\r\n right: '0.75rem',\r\n top: '50%',\r\n transform: 'translateY(-50%)',\r\n padding: '0.5rem 0.75rem',\r\n fontSize: '1rem',\r\n fontWeight: 'bold',\r\n color: '#ffffff',\r\n backgroundColor: '#3b82f6',\r\n borderRadius: '0.5rem',\r\n border: '2px solid #60a5fa',\r\n backdropFilter: 'blur(4px)',\r\n pointerEvents: 'none' as const,\r\n zIndex: 10,\r\n boxShadow: '0 2px 8px rgba(59, 130, 246, 0.4)',\r\n };\r\n\r\n return (\r\n <div\r\n style={{\r\n display: 'inline-flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n gap: '0.75rem',\r\n }}\r\n >\r\n {label && (\r\n <label\r\n style={{\r\n fontSize: '0.875rem',\r\n fontWeight: '600',\r\n color: '#cbd5e1',\r\n textTransform: 'uppercase',\r\n letterSpacing: '0.05em',\r\n }}\r\n >\r\n {label}\r\n </label>\r\n )}\r\n <div style={{ position: 'relative', display: 'inline-flex', alignItems: 'center' }}>\r\n <input\r\n type=\"text\"\r\n value={displayText}\r\n onChange={handleChange}\r\n onFocus={(e) => {\r\n Object.assign(e.target.style, inputStyleFocus);\r\n handleFocus();\r\n }}\r\n onBlur={(e) => {\r\n Object.assign(e.target.style, inputStyle);\r\n handleBlur();\r\n }}\r\n onKeyDown={handleKeyDown}\r\n disabled={disabled}\r\n readOnly={readOnly}\r\n style={inputStyle}\r\n {...props}\r\n />\r\n {unit && <span style={unitStyle}>{unit}</span>}\r\n {status === 'alarm' && (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: '-8px',\r\n right: '-8px',\r\n width: '1rem',\r\n height: '1rem',\r\n backgroundColor: '#ef4444',\r\n borderRadius: '50%',\r\n boxShadow: '0 0 10px rgba(239, 68, 68, 0.8)',\r\n animation: 'pulse 2s infinite',\r\n }}\r\n />\r\n )}\r\n {status === 'warning' && (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: '-8px',\r\n right: '-8px',\r\n width: '1rem',\r\n height: '1rem',\r\n backgroundColor: '#f59e0b',\r\n borderRadius: '50%',\r\n boxShadow: '0 0 10px rgba(245, 158, 11, 0.8)',\r\n }}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\n\r\nconst getStatusDescription = (status: string): string => {\r\n switch (status) {\r\n case 'alarm':\r\n return 'Critical alarm condition requiring attention';\r\n case 'warning':\r\n return 'Warning condition that should be monitored';\r\n case 'fault':\r\n return 'Equipment fault detected';\r\n case 'active':\r\n return 'Equipment is actively running';\r\n case 'normal':\r\n return 'Operating normally';\r\n case 'off':\r\n return 'Equipment is off';\r\n default:\r\n return '';\r\n }\r\n};\r\n\r\nexport interface StatusIndicatorProps extends React.HTMLAttributes<HTMLDivElement> {\r\n /** Status state determining color and behavior */\r\n status: 'off' | 'normal' | 'alarm' | 'warning' | 'active' | 'fault';\r\n /** Size of the indicator */\r\n size?: 'small' | 'medium' | 'large';\r\n /** Animation behavior */\r\n animation?: 'none' | 'pulse' | 'blink' | 'flash';\r\n /** Label text to display next to indicator */\r\n label?: string;\r\n /** Position of label relative to indicator */\r\n labelPosition?: 'left' | 'right' | 'top' | 'bottom';\r\n /** Shape of the indicator */\r\n shape?: 'circle' | 'square' | 'diamond';\r\n /** Whether the indicator should have a 3D LED effect */\r\n led?: boolean;\r\n}\r\n\r\nexport const StatusIndicator: React.FC<StatusIndicatorProps> = ({\r\n status,\r\n size = 'medium',\r\n animation = 'none',\r\n label,\r\n labelPosition = 'right',\r\n shape = 'circle',\r\n led = true,\r\n className = '',\r\n ...props\r\n}) => {\r\n // Use CSS classes for base, status, size, shape, animation, led\r\n const baseClass = 'ui-status-indicator';\r\n const statusClass = status ? `ui-status-indicator--${status}` : '';\r\n const sizeClass = size ? `ui-status-indicator--${size}` : '';\r\n const shapeClass = shape ? `ui-status-indicator--${shape}` : '';\r\n const animationClass = animation ? `ui-status-indicator--${animation}` : '';\r\n const ledClass = led ? 'ui-status-indicator--led' : '';\r\n\r\n // Container layout based on label position\r\n const getContainerLayout = () => {\r\n switch (labelPosition) {\r\n case 'left':\r\n return 'ui-status-indicator-container ui-status-indicator-label-left';\r\n case 'right':\r\n return 'ui-status-indicator-container ui-status-indicator-label-right';\r\n case 'top':\r\n return 'ui-status-indicator-container ui-status-indicator-label-top';\r\n case 'bottom':\r\n return 'ui-status-indicator-container ui-status-indicator-label-bottom';\r\n default:\r\n return 'ui-status-indicator-container ui-status-indicator-label-right';\r\n }\r\n };\r\n\r\n return (\r\n <span className={getContainerLayout()}>\r\n {label && (labelPosition === 'left' || labelPosition === 'top') && (\r\n <span className=\"ui-status-indicator-label\">{label}</span>\r\n )}\r\n <span\r\n role=\"status\"\r\n aria-label={label || `Status: ${status}`}\r\n aria-description={getStatusDescription(status)}\r\n data-status={status}\r\n className={`\r\n ${baseClass}\r\n ${statusClass}\r\n ${sizeClass}\r\n ${shapeClass}\r\n ${animationClass}\r\n ${ledClass}\r\n ${className}\r\n `\r\n .replace(/\\s+/g, ' ')\r\n .trim()}\r\n {...props}\r\n />\r\n {label && (labelPosition === 'right' || labelPosition === 'bottom') && (\r\n <span className=\"ui-status-indicator-label\">{label}</span>\r\n )}\r\n </span>\r\n );\r\n};\r\n","import React from 'react';\nimport { Tab } from '@mui/material';\nimport {\n ChevronLeft,\n ChevronRight,\n DisplayModeToggle,\n FixedSVGContainer,\n FooterPanel,\n FullscreenContainer,\n LeftPanel,\n LeftToggleButton,\n PanelContent,\n PanelTabs,\n RightPanel,\n RightToggleButton,\n SVGArea,\n ScrollableSVGWrapper,\n ZoomButton,\n ZoomControls,\n} from './FullscreenWorkspace.styles';\nimport type { DisplayMode, FullscreenWorkspaceProps } from './types';\n\nexport function FullscreenWorkspace({\n svgContent,\n overlays,\n leftPanel,\n rightPanel,\n footer,\n tabs,\n activeTab,\n onTabChange,\n defaultLeftCollapsed = false,\n defaultRightCollapsed = false,\n leftCollapsed: leftCollapsedProp,\n rightCollapsed: rightCollapsedProp,\n onLeftCollapseChange,\n onRightCollapseChange,\n displayMode,\n defaultDisplayMode = 'standard',\n onDisplayModeChange,\n showDisplayModeToggle = true,\n showZoomControls = false,\n onZoomIn,\n onZoomOut,\n onResetZoom,\n zoomDisabled = false,\n className = '',\n ...rest\n}: FullscreenWorkspaceProps): React.ReactElement {\n const [leftCollapsedState, setLeftCollapsedState] = React.useState(defaultLeftCollapsed);\n const [rightCollapsedState, setRightCollapsedState] = React.useState(defaultRightCollapsed);\n const [internalDisplayMode, setInternalDisplayMode] =\n React.useState<DisplayMode>(displayMode ?? defaultDisplayMode);\n const [internalTab, setInternalTab] = React.useState<string>(\n tabs && tabs.length > 0 ? tabs[0].value : ''\n );\n\n const leftCollapsed = leftCollapsedProp ?? leftCollapsedState;\n const rightCollapsed = rightCollapsedProp ?? rightCollapsedState;\n const isDisplayModeControlled = displayMode !== undefined;\n const currentDisplayMode = isDisplayModeControlled ? displayMode : internalDisplayMode;\n const isTabControlled = activeTab !== undefined && activeTab !== null;\n\n const resolvedTabs = React.useMemo(() => tabs ?? [], [tabs]);\n const defaultTabValue = resolvedTabs.length > 0 ? resolvedTabs[0].value : '';\n const currentTab = isTabControlled ? (activeTab as string) : internalTab || defaultTabValue;\n\n React.useEffect(() => {\n if (resolvedTabs.length > 0) {\n const values = resolvedTabs.map((tab) => tab.value);\n if (!values.includes(currentTab)) {\n const fallback = activeTab ?? defaultTabValue;\n setInternalTab(fallback);\n }\n }\n }, [resolvedTabs, activeTab, currentTab, defaultTabValue]);\n\n React.useEffect(() => {\n if (displayMode !== undefined) {\n setInternalDisplayMode(displayMode);\n }\n }, [displayMode]);\n\n const handleLeftToggle = () => {\n const next = !leftCollapsed;\n if (leftCollapsedProp === undefined) {\n setLeftCollapsedState(next);\n }\n onLeftCollapseChange?.(next);\n };\n\n const handleRightToggle = () => {\n const next = !rightCollapsed;\n if (rightCollapsedProp === undefined) {\n setRightCollapsedState(next);\n }\n onRightCollapseChange?.(next);\n };\n\n const handleModeToggle = () => {\n const nextMode = currentDisplayMode === 'standard' ? 'dashboard' : 'standard';\n if (!isDisplayModeControlled) {\n setInternalDisplayMode(nextMode);\n }\n onDisplayModeChange?.(nextMode);\n };\n\n const handleTabChangeInternal = (_: React.SyntheticEvent, value: string) => {\n if (!isTabControlled) {\n setInternalTab(value);\n }\n onTabChange?.(value);\n };\n\n const currentTabContent =\n resolvedTabs.find((tab) => tab.value === currentTab)?.content ?? null;\n\n const showLeftToggle = Boolean(leftPanel);\n const showRightToggle = Boolean(rightPanel);\n\n return (\n <FullscreenContainer\n leftCollapsed={leftCollapsed}\n rightCollapsed={rightCollapsed}\n className={`tff-svg-container ${className}`.trim()}\n {...rest}\n >\n {showLeftToggle && (\n <LeftToggleButton\n collapsed={leftCollapsed}\n onClick={handleLeftToggle}\n aria-label={leftCollapsed ? 'Expand left panel' : 'Collapse left panel'}\n >\n {leftCollapsed ? <ChevronRight /> : <ChevronLeft />}\n </LeftToggleButton>\n )}\n\n {showRightToggle && (\n <RightToggleButton\n collapsed={rightCollapsed}\n onClick={handleRightToggle}\n aria-label={rightCollapsed ? 'Expand right panel' : 'Collapse right panel'}\n >\n {rightCollapsed ? <ChevronLeft /> : <ChevronRight />}\n </RightToggleButton>\n )}\n\n {showDisplayModeToggle && (\n <DisplayModeToggle\n mode={currentDisplayMode}\n onClick={handleModeToggle}\n aria-label=\"Toggle display mode\"\n >\n {currentDisplayMode === 'dashboard' ? 'Dashboard Mode' : 'Standard Mode'}\n </DisplayModeToggle>\n )}\n\n <SVGArea>\n {showZoomControls && (\n <ZoomControls>\n <ZoomButton\n onClick={onZoomIn}\n disabled={zoomDisabled || !onZoomIn}\n size=\"small\"\n aria-label=\"Zoom in\"\n >\n +\n </ZoomButton>\n <ZoomButton\n onClick={onZoomOut}\n disabled={zoomDisabled || !onZoomOut}\n size=\"small\"\n aria-label=\"Zoom out\"\n >\n -\n </ZoomButton>\n {onResetZoom && (\n <ZoomButton\n onClick={onResetZoom}\n disabled={zoomDisabled}\n size=\"small\"\n aria-label=\"Reset zoom\"\n >\n Reset\n </ZoomButton>\n )}\n </ZoomControls>\n )}\n\n <ScrollableSVGWrapper className=\"svg-scroll-wrapper\">\n <FixedSVGContainer className=\"svg-container\">\n {svgContent}\n {overlays}\n </FixedSVGContainer>\n </ScrollableSVGWrapper>\n </SVGArea>\n\n <LeftPanel collapsed={leftCollapsed}>\n {resolvedTabs.length > 0 ? (\n <>\n <PanelTabs\n value={currentTab}\n onChange={handleTabChangeInternal}\n aria-label=\"Left panel tabs\"\n >\n {resolvedTabs.map((tab) => (\n <Tab key={tab.value} label={tab.label} value={tab.value} />\n ))}\n </PanelTabs>\n <PanelContent>{currentTabContent}</PanelContent>\n </>\n ) : (\n leftPanel\n )}\n </LeftPanel>\n\n <RightPanel collapsed={rightCollapsed}>{rightPanel}</RightPanel>\n\n <FooterPanel>{footer}</FooterPanel>\n </FullscreenContainer>\n );\n}\n\nexport type {\n DisplayMode,\n FullscreenContainerProps,\n FullscreenWorkspaceProps,\n FullscreenWorkspaceTab,\n OverlayTheme,\n SVGLockedOverlayProps,\n TrendLineProps,\n CircularGaugeProps,\n SparklineProps,\n EquipmentIndicatorProps,\n EquipmentIndicatorWithSparklineProps,\n} from './types';\n\nexport {\n FullscreenContainer,\n LeftPanel,\n RightPanel,\n SVGArea,\n LeftToggleButton,\n RightToggleButton,\n DisplayModeToggle,\n ZoomControls,\n ZoomButton,\n FooterPanel,\n PanelTabs,\n PanelContent,\n FixedSVGContainer,\n ScrollableSVGWrapper,\n ChevronLeft,\n ChevronRight,\n} from './FullscreenWorkspace.styles';\n\nexport {\n overlayStyles,\n SVGLockedOverlay,\n DashboardCard,\n CardHeader,\n CardValue,\n CardUnit,\n} from './FullscreenWorkspace.overlays';\n\nexport {\n TrendLine,\n Sparkline,\n CircularGauge,\n EquipmentIndicator,\n EquipmentIndicatorWithSparkline,\n} from './FullscreenWorkspace.visuals';\n","import { Box, IconButton, Tabs } from '@mui/material';\nimport styled from '@emotion/styled';\nimport type { DisplayMode, FullscreenContainerProps } from './types';\n\nexport const FullscreenContainer = styled(Box)<FullscreenContainerProps>(\n ({ leftCollapsed, rightCollapsed }) => {\n const getGridTemplateAreas = () => {\n if (leftCollapsed && rightCollapsed) {\n return `\"svg-area\" \"footer\"`;\n }\n if (leftCollapsed) {\n return `\"svg-area right-panel\" \"footer footer\"`;\n }\n if (rightCollapsed) {\n return `\"left-panel svg-area\" \"footer footer\"`;\n }\n return `\"left-panel svg-area right-panel\" \"footer footer footer\"`;\n };\n\n const getGridTemplateColumns = () => {\n if (leftCollapsed && rightCollapsed) {\n return '1fr';\n }\n if (leftCollapsed) {\n return '1fr 380px';\n }\n if (rightCollapsed) {\n return '420px 1fr';\n }\n return '420px 1fr 380px';\n };\n\n return {\n width: '100vw',\n height: '100vh',\n background: '#f5f5f5',\n display: 'grid',\n gridTemplateAreas: getGridTemplateAreas(),\n gridTemplateRows: '1fr 100px',\n gridTemplateColumns: getGridTemplateColumns(),\n gap: '10px',\n padding: '10px',\n boxSizing: 'border-box',\n transition: 'grid-template-columns 0.3s ease-in-out',\n };\n }\n);\n\nexport const LeftPanel = styled(Box)<{ collapsed: boolean }>(({ collapsed }) => ({\n gridArea: 'left-panel',\n background: 'rgba(255, 255, 255, 0.0)',\n border: '1px solid #ddd',\n borderRadius: '8px',\n padding: collapsed ? '0' : '15px',\n overflowY: 'auto',\n display: collapsed ? 'none' : 'block',\n transition: 'all 0.3s ease-in-out',\n}));\n\nexport const RightPanel = styled(Box)<{ collapsed: boolean }>(({ collapsed }) => ({\n gridArea: 'right-panel',\n background: 'rgba(255, 255, 255, 0.0)',\n border: '1px solid #ddd',\n borderRadius: '8px',\n padding: collapsed ? '0' : '15px',\n overflowY: 'auto',\n display: collapsed ? 'none' : 'block',\n transition: 'all 0.3s ease-in-out',\n}));\n\nexport const SVGArea = styled(Box)({\n gridArea: 'svg-area',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-start',\n position: 'relative',\n background: 'rgba(255, 255, 255, 0.0)',\n border: '1px solid #ddd',\n borderRadius: '8px',\n overflow: 'auto',\n width: '100%',\n height: '100%',\n});\n\nexport const LeftToggleButton = styled(IconButton)<{ collapsed: boolean }>(\n ({ collapsed }) => ({\n position: 'absolute',\n left: collapsed ? '10px' : '410px',\n top: '50%',\n transform: 'translateY(-50%)',\n zIndex: 1000,\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n border: '1px solid #ddd',\n transition: 'left 0.3s ease-in-out',\n '&:hover': {\n backgroundColor: 'rgba(255, 255, 255, 1)',\n },\n })\n);\n\nexport const RightToggleButton = styled(IconButton)<{ collapsed: boolean }>(\n ({ collapsed }) => ({\n position: 'absolute',\n right: collapsed ? '10px' : '370px',\n top: '50%',\n transform: 'translateY(-50%)',\n zIndex: 1000,\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n border: '1px solid #ddd',\n transition: 'right 0.3s ease-in-out',\n '&:hover': {\n backgroundColor: 'rgba(255, 255, 255, 1)',\n },\n })\n);\n\nexport const DisplayModeToggle = styled(IconButton)<{ mode: DisplayMode }>(({ mode }) => ({\n position: 'absolute',\n top: '50px',\n left: '75%',\n transform: 'translateX(-50%)',\n zIndex: 1000,\n backgroundColor:\n mode === 'dashboard' ? 'rgba(52, 152, 219, 0.9)' : 'rgba(255, 255, 255, 0.9)',\n color: mode === 'dashboard' ? 'white' : '#333',\n border: '1px solid #ddd',\n borderRadius: '20px',\n padding: '8px 16px',\n fontSize: '12px',\n fontWeight: '600',\n minWidth: '120px',\n transition: 'all 0.3s ease-in-out',\n '&:hover': {\n backgroundColor:\n mode === 'dashboard' ? 'rgba(52, 152, 219, 1)' : 'rgba(255, 255, 255, 1)',\n transform: 'translateX(-50%) scale(1.05)',\n },\n}));\n\nexport const ChevronLeft = () => (\n <div\n style={{\n width: 0,\n height: 0,\n borderTop: '6px solid transparent',\n borderBottom: '6px solid transparent',\n borderRight: '8px solid #666',\n }}\n />\n);\n\nexport const ChevronRight = () => (\n <div\n style={{\n width: 0,\n height: 0,\n borderTop: '6px solid transparent',\n borderBottom: '6px solid transparent',\n borderLeft: '8px solid #666',\n }}\n />\n);\n\nexport const ZoomControls = styled(Box)({\n position: 'absolute',\n top: '10px',\n right: '10px',\n display: 'flex',\n flexDirection: 'column',\n gap: '5px',\n zIndex: 1000,\n});\n\nexport const ZoomButton = styled(IconButton)({\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n border: '1px solid #ddd',\n width: '32px',\n height: '32px',\n fontSize: '14px',\n fontWeight: 'bold',\n '&:hover': {\n backgroundColor: 'rgba(255, 255, 255, 1)',\n },\n});\n\nexport const FooterPanel = styled(Box)({\n gridArea: 'footer',\n background: 'rgba(255, 255, 255, 0.95)',\n border: '1px solid #ddd',\n borderRadius: '8px',\n padding: '10px',\n display: 'flex',\n justifyContent: 'space-around',\n alignItems: 'center',\n});\n\nexport const PanelTabs = styled(Tabs)({\n minHeight: '36px',\n '& .MuiTabs-indicator': {\n backgroundColor: '#546e7a',\n },\n '& .MuiTab-root': {\n minHeight: '36px',\n padding: '6px 12px',\n fontSize: '12px',\n fontWeight: '600',\n textTransform: 'none',\n color: '#666',\n '&.Mui-selected': {\n color: '#546e7a',\n },\n },\n});\n\nexport const PanelContent = styled(Box)({\n flex: 1,\n overflow: 'auto',\n padding: '10px',\n});\n\nexport const FixedSVGContainer = styled('div')({\n position: 'relative',\n width: '1300px',\n height: '400px',\n minWidth: '1300px',\n minHeight: '400px',\n maxWidth: '1300px',\n maxHeight: '400px',\n border: 'none',\n backgroundColor: 'transparent',\n overflow: 'visible',\n '& .svg-locked-overlay': {\n position: 'absolute',\n pointerEvents: 'auto',\n zIndex: 10,\n },\n '& svg': {\n position: 'absolute',\n left: 0,\n top: 0,\n width: '1300px',\n height: '280px',\n minWidth: '1300px',\n minHeight: '280px',\n maxWidth: 'none',\n maxHeight: 'none',\n objectFit: 'none',\n transform: 'none',\n border: 'none',\n },\n});\n\nexport const ScrollableSVGWrapper = styled('div')({\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'auto',\n transform: 'rotateX(180deg)',\n padding: '250px',\n paddingTop: '200px',\n boxSizing: 'border-box',\n '& > *': {\n display: 'block',\n transform: 'rotateX(180deg)',\n },\n});\n","import { useEffect, useState } from 'react';\nimport { Box } from '@mui/material';\nimport styled from '@emotion/styled';\nimport type { OverlayTheme, SVGLockedOverlayProps } from './types';\n\nconst baseOverlayStyles = {\n tank: {\n background:\n 'linear-gradient(135deg, rgba(69, 90, 120, 0.95) 0%, rgba(52, 73, 94, 0.95) 100%)',\n border: '1px solid #455a64',\n color: 'white',\n borderRadius: '4px',\n fontSize: '12px',\n fontWeight: '500',\n textAlign: 'center' as const,\n padding: '8px',\n minWidth: '60px',\n boxShadow: '0 1px 4px rgba(69, 90, 120, 0.2)',\n },\n pressure: {\n background:\n 'linear-gradient(135deg, rgba(30, 50, 90, 0.75) 0%, rgba(20, 35, 70, 0.75) 100%)',\n border: '1px solid #1e3a8a',\n color: 'white',\n borderRadius: '4px',\n fontSize: '11px',\n fontWeight: '500',\n textAlign: 'center' as const,\n padding: '6px',\n minWidth: '50px',\n boxShadow: '0 1px 4px rgba(30, 50, 90, 0.15)',\n },\n vessel: {\n background:\n 'linear-gradient(135deg, rgba(84, 110, 122, 0.95) 0%, rgba(69, 90, 100, 0.95) 100%)',\n border: '1px solid #546e7a',\n color: 'white',\n borderRadius: '4px',\n fontSize: '13px',\n fontWeight: '500',\n textAlign: 'center' as const,\n padding: '8px',\n minWidth: '70px',\n boxShadow: '0 1px 4px rgba(84, 110, 122, 0.2)',\n },\n flow: {\n background:\n 'linear-gradient(135deg, rgba(102, 125, 102, 0.95) 0%, rgba(85, 107, 85, 0.95) 100%)',\n border: '1px solid #689f38',\n color: 'white',\n borderRadius: '4px',\n fontSize: '11px',\n fontWeight: '500',\n textAlign: 'center' as const,\n padding: '5px',\n minWidth: '60px',\n boxShadow: '0 1px 4px rgba(102, 125, 102, 0.2)',\n },\n} as const;\n\nexport const overlayStyles: Record<OverlayTheme, typeof baseOverlayStyles[OverlayTheme]> =\n baseOverlayStyles;\n\nexport const SVGLockedOverlay = ({\n svgX,\n svgY,\n children,\n theme,\n style = {},\n className = '',\n onClick,\n containerSelector = '.tff-svg-container',\n}: SVGLockedOverlayProps) => {\n const [svgOffset, setSvgOffset] = useState({ x: 0, y: 0 });\n\n useEffect(() => {\n const updateSvgOffset = () => {\n const containerElement = document.querySelector(containerSelector);\n const svgElement = containerElement?.querySelector('svg');\n\n if (svgElement && containerElement) {\n const svgRect = svgElement.getBoundingClientRect();\n const containerRect = containerElement.getBoundingClientRect();\n\n setSvgOffset({\n x: svgRect.left - containerRect.left,\n y: svgRect.top - containerRect.top,\n });\n }\n };\n\n updateSvgOffset();\n window.addEventListener('resize', updateSvgOffset);\n return () => window.removeEventListener('resize', updateSvgOffset);\n }, [containerSelector]);\n\n const pixelX = svgX + svgOffset.x;\n const pixelY = svgY + svgOffset.y;\n\n const appliedStyle = theme ? { ...overlayStyles[theme], ...style } : style;\n\n return (\n <Box\n className={`svg-locked-overlay ${className}`.trim()}\n onClick={onClick}\n sx={{\n position: 'absolute',\n left: `${pixelX}px`,\n top: `${pixelY}px`,\n cursor: onClick ? 'pointer' : 'default',\n zIndex: 10,\n pointerEvents: 'auto',\n ...appliedStyle,\n }}\n >\n {children}\n </Box>\n );\n};\n\nexport const DashboardCard = styled(Box)<{ svgX: number; svgY: number; cardType?: string }>(\n ({ svgX, svgY, cardType }) => ({\n position: 'absolute',\n left: svgX,\n top: svgY,\n background:\n cardType === 'critical'\n ? 'linear-gradient(135deg, rgba(220, 53, 69, 0.95) 0%, rgba(173, 20, 87, 0.95) 100%)'\n : cardType === 'warning'\n ? 'linear-gradient(135deg, rgba(255, 193, 7, 0.95) 0%, rgba(255, 143, 0, 0.95) 100%)'\n : cardType === 'vessel'\n ? 'linear-gradient(135deg, rgba(46, 204, 113, 0.95) 0%, rgba(39, 174, 96, 0.95) 100%)'\n : cardType === 'process'\n ? 'linear-gradient(135deg, rgba(155, 89, 182, 0.95) 0%, rgba(142, 68, 173, 0.95) 100%)'\n : cardType === 'control'\n ? 'linear-gradient(135deg, rgba(26, 188, 156, 0.95) 0%, rgba(22, 160, 133, 0.95) 100%)'\n : 'linear-gradient(135deg, rgba(52, 152, 219, 0.95) 0%, rgba(41, 128, 185, 0.95) 100%)',\n border: '1px solid rgba(255, 255, 255, 0.2)',\n borderRadius: '12px',\n padding: '12px',\n minWidth: '140px',\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3)',\n backdropFilter: 'blur(10px)',\n color: 'white',\n fontSize: '12px',\n fontWeight: '600',\n textAlign: 'center',\n transform: 'translate(-50%, -50%)',\n transition: 'all 0.3s ease-in-out',\n cursor: 'pointer',\n '&:hover': {\n transform: 'translate(-50%, -50%) scale(1.05)',\n boxShadow: '0 12px 40px rgba(0, 0, 0, 0.4)',\n },\n })\n);\n\nexport const CardHeader = styled('div')<{ color?: string }>(({ color }) => ({\n fontSize: '10px',\n opacity: 0.9,\n marginBottom: '4px',\n textTransform: 'uppercase',\n letterSpacing: '0.5px',\n color: color || 'inherit',\n borderBottom: color ? `1px solid ${color}40` : 'none',\n paddingBottom: color ? '2px' : '0',\n}));\n\nexport const CardValue = styled('div')({\n fontSize: '16px',\n fontWeight: '700',\n marginBottom: '2px',\n});\n\nexport const CardUnit = styled('div')({\n fontSize: '9px',\n opacity: 0.8,\n});\n\n","import type {\n CircularGaugeProps,\n EquipmentIndicatorProps,\n EquipmentIndicatorWithSparklineProps,\n SparklineProps,\n TrendLineProps,\n} from './types';\nimport { SVGLockedOverlay } from './FullscreenWorkspace.overlays';\n\nexport const TrendLine = ({\n values,\n width = 60,\n height = 20,\n color = '#4fc3f7',\n strokeWidth = 1.5,\n backgroundColor = 'rgba(255, 255, 255, 0.1)',\n}: TrendLineProps) => {\n if (!values || values.length < 2) {\n return (\n <div\n style={{\n width,\n height,\n backgroundColor,\n borderRadius: '2px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <span style={{ fontSize: '8px', color: '#ccc' }}>No data</span>\n </div>\n );\n }\n\n const minValue = Math.min(...values);\n const maxValue = Math.max(...values);\n const range = maxValue - minValue;\n\n const normalizedValues =\n range === 0\n ? values.map(() => height / 2)\n : values.map((v) => height - 4 - ((v - minValue) / range) * (height - 8));\n\n const pathData = normalizedValues\n .map((y, i) => {\n const x = 4 + (i / (values.length - 1)) * (width - 8);\n return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;\n })\n .join(' ');\n\n return (\n <div\n style={{\n width,\n height,\n backgroundColor,\n borderRadius: '2px',\n position: 'relative',\n overflow: 'hidden',\n }}\n >\n <svg width={width} height={height} style={{ position: 'absolute', top: 0, left: 0 }}>\n <path\n d={pathData}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <circle\n cx={4 + (width - 8)}\n cy={normalizedValues[normalizedValues.length - 1]}\n r={1.5}\n fill={color}\n />\n </svg>\n </div>\n );\n};\n\nconst hexToRgba = (hex: string, alpha: number) => {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n};\n\nexport const CircularGauge = ({\n value,\n max,\n unit,\n label,\n size = 60,\n color = 'rgba(255, 255, 255, 0.9)',\n}: CircularGaugeProps) => {\n const percentage = Math.min((value / max) * 100, 100);\n const strokeWidth = 4;\n const radius = (size - strokeWidth) / 2;\n const circumference = radius * 2 * Math.PI;\n const strokeDasharray = circumference;\n const strokeDashoffset = circumference - (percentage / 100) * circumference;\n\n const isHex = color.startsWith('#');\n const innerCircleColor = isHex ? hexToRgba(color, 0.8) : color;\n const borderColor = isHex ? hexToRgba(color, 0.9) : color;\n const backgroundColor = isHex ? hexToRgba(color, 0.15) : color;\n const borderStrokeColor = isHex ? hexToRgba(color, 0.4) : color;\n\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n }}\n >\n <div\n style={{\n position: 'relative',\n width: size,\n height: size,\n borderRadius: '50%',\n backgroundColor,\n border: `1px solid ${borderStrokeColor}`,\n }}\n >\n <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius - strokeWidth - 2}\n fill={innerCircleColor}\n stroke={borderColor}\n strokeWidth={1}\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n stroke=\"rgba(255, 255, 255, 0.2)\"\n strokeWidth={strokeWidth}\n fill=\"transparent\"\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n stroke={color}\n strokeWidth={strokeWidth}\n fill=\"transparent\"\n strokeDasharray={strokeDasharray}\n strokeDashoffset={strokeDashoffset}\n strokeLinecap=\"round\"\n style={{ transition: 'stroke-dashoffset 0.5s ease-in-out' }}\n />\n </svg>\n <div\n style={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n fontSize: '11px',\n fontWeight: '700',\n color: 'white',\n textAlign: 'center',\n textShadow: '0 1px 2px rgba(0, 0, 0, 0.5)',\n }}\n >\n {value.toFixed(1)}\n <div style={{ fontSize: '8px', opacity: 0.9, color: 'white' }}>{unit}</div>\n </div>\n </div>\n <div\n style={{\n fontSize: '9px',\n marginTop: '4px',\n opacity: 0.9,\n color: 'white',\n }}\n >\n {label}\n </div>\n </div>\n );\n};\n\nexport const Sparkline = ({ data, width, height, color }: SparklineProps) => {\n if (!data || data.length < 2) {\n return null;\n }\n\n const max = Math.max(...data);\n const min = Math.min(...data);\n const range = max - min;\n\n if (range === 0) {\n return null;\n }\n\n const points = data\n .map((value, index) => {\n const x = (index / (data.length - 1)) * (width - 8);\n const y = height - 8 - ((value - min) / range) * (height - 8);\n return `${x + 4},${y + 4}`;\n })\n .join(' ');\n\n return (\n <div\n style={{\n width,\n height,\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n border: '1px solid rgba(255, 255, 255, 0.3)',\n borderRadius: '4px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 1px 3px rgba(0, 0, 0, 0.2)',\n }}\n >\n <svg width={width} height={height}>\n <polyline points={points} fill=\"none\" stroke={color} strokeWidth=\"1.5\" opacity=\"0.9\" />\n </svg>\n </div>\n );\n};\n\nexport const EquipmentIndicatorWithSparkline = ({\n svgX,\n svgY,\n color,\n label,\n size = 30,\n sparklineData,\n sparklineOffset = { x: 40, y: 0 },\n}: EquipmentIndicatorWithSparklineProps) => {\n const hasSparkline =\n sparklineData &&\n sparklineData.length > 1 &&\n Math.max(...sparklineData) !== Math.min(...sparklineData);\n\n return (\n <>\n <SVGLockedOverlay svgX={svgX} svgY={svgY} style={{ transform: 'translate(-50%, -50%)' }}>\n <div\n style={{\n width: size,\n height: size,\n borderRadius: '50%',\n backgroundColor: color,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'white',\n fontSize: '7px',\n fontWeight: '700',\n textAlign: 'center',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n border: '2px solid rgba(255, 255, 255, 0.3)',\n }}\n >\n {label}\n </div>\n </SVGLockedOverlay>\n\n {hasSparkline && (\n <SVGLockedOverlay svgX={svgX + sparklineOffset.x} svgY={svgY + sparklineOffset.y}>\n <Sparkline data={sparklineData!} width={60} height={20} color={color} />\n </SVGLockedOverlay>\n )}\n </>\n );\n};\n\nexport const EquipmentIndicator = ({\n svgX,\n svgY,\n color,\n label,\n size = 30,\n style,\n className,\n}: EquipmentIndicatorProps) => {\n const overlayStyle =\n style !== undefined\n ? { transform: 'translate(-50%, -50%)', ...style }\n : { transform: 'translate(-50%, -50%)' };\n\n return (\n <SVGLockedOverlay svgX={svgX} svgY={svgY} style={overlayStyle} className={className}>\n <div\n style={{\n width: size,\n height: size,\n borderRadius: '50%',\n backgroundColor: color,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'white',\n fontSize: '7px',\n fontWeight: '700',\n textAlign: 'center',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n border: '2px solid rgba(255, 255, 255, 0.3)',\n }}\n >\n {label}\n </div>\n </SVGLockedOverlay>\n );\n};\n","import React, { createContext, useContext, useState, useEffect } from 'react';\r\n\r\ntype Theme = 'modern' | 'hmi';\r\n\r\ninterface ThemeContextType {\r\n theme: Theme;\r\n toggleTheme: () => void;\r\n setTheme: (theme: Theme) => void;\r\n}\r\n\r\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined);\r\n\r\nexport const useTheme = () => {\r\n const context = useContext(ThemeContext);\r\n if (!context) {\r\n throw new Error('useTheme must be used within a ThemeProvider');\r\n }\r\n return context;\r\n};\r\n\r\ninterface ThemeProviderProps {\r\n children: React.ReactNode;\r\n}\r\n\r\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {\r\n const [theme, setThemeState] = useState<Theme>('modern');\r\n\r\n useEffect(() => {\r\n // Apply theme classes to document body\r\n document.body.className = '';\r\n document.body.classList.add(`theme-${theme}`);\r\n\r\n // Also apply to html element for global styling\r\n document.documentElement.className = '';\r\n document.documentElement.classList.add(`theme-${theme}`);\r\n }, [theme]);\r\n\r\n const toggleTheme = () => {\r\n setTheme(theme === 'modern' ? 'hmi' : 'modern');\r\n };\r\n\r\n const setTheme = (newTheme: Theme) => {\r\n setThemeState(newTheme);\r\n };\r\n\r\n return (\r\n <ThemeContext.Provider value={{ theme, toggleTheme, setTheme }}>\r\n {children}\r\n </ThemeContext.Provider>\r\n );\r\n};\r\n","import React from 'react';\r\nimport { useTheme } from './ThemeContext';\r\n\r\nexport interface ThemeToggleProps extends React.HTMLAttributes<HTMLDivElement> {\r\n /** Size of the toggle */\r\n size?: 'small' | 'medium' | 'large';\r\n /** Position of the toggle */\r\n position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'inline';\r\n}\r\n\r\nexport const ThemeToggle: React.FC<ThemeToggleProps> = ({\r\n size = 'medium',\r\n position = 'top-right',\r\n className = '',\r\n ...props\r\n}) => {\r\n const { theme, toggleTheme } = useTheme();\r\n\r\n const sizeStyles = {\r\n small: { padding: '0.5rem 1rem', fontSize: '0.75rem' },\r\n medium: { padding: '0.75rem 1.5rem', fontSize: '0.875rem' },\r\n large: { padding: '1rem 2rem', fontSize: '1rem' },\r\n };\r\n\r\n const positionStyles = {\r\n 'top-left': { position: 'fixed' as const, top: '1rem', left: '1rem', zIndex: 1000 },\r\n 'top-right': { position: 'fixed' as const, top: '1rem', right: '1rem', zIndex: 1000 },\r\n 'bottom-left': { position: 'fixed' as const, bottom: '1rem', left: '1rem', zIndex: 1000 },\r\n 'bottom-right': { position: 'fixed' as const, bottom: '1rem', right: '1rem', zIndex: 1000 },\r\n inline: { position: 'relative' as const },\r\n };\r\n\r\n const baseStyle: React.CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '0.75rem',\r\n cursor: 'pointer',\r\n borderRadius: '0.5rem',\r\n border: '2px solid',\r\n fontFamily:\r\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace',\r\n fontWeight: 600,\r\n textTransform: 'uppercase',\r\n letterSpacing: '0.05em',\r\n transition: 'all 0.2s ease',\r\n userSelect: 'none',\r\n ...sizeStyles[size],\r\n ...positionStyles[position],\r\n };\r\n\r\n const modernStyle: React.CSSProperties = {\r\n ...baseStyle,\r\n background: 'linear-gradient(135deg, #3b82f6 0%, #2563eb 50%, #1d4ed8 100%)',\r\n borderColor: 'rgba(59, 130, 246, 0.4)',\r\n color: '#ffffff',\r\n boxShadow: '0 8px 32px rgba(59, 130, 246, 0.3)',\r\n };\r\n\r\n const hmiStyle: React.CSSProperties = {\r\n ...baseStyle,\r\n backgroundColor: '#666666',\r\n borderColor: '#999999',\r\n color: '#ffffff',\r\n boxShadow: 'none',\r\n };\r\n\r\n const currentStyle = theme === 'modern' ? modernStyle : hmiStyle;\r\n\r\n const toggleStyle: React.CSSProperties = {\r\n position: 'relative',\r\n width: '3rem',\r\n height: '1.5rem',\r\n borderRadius: '0.75rem',\r\n transition: 'all 0.2s ease',\r\n backgroundColor: theme === 'modern' ? '#3b82f6' : '#808080',\r\n border: `2px solid ${theme === 'modern' ? '#2563eb' : '#666666'}`,\r\n };\r\n\r\n const thumbStyle: React.CSSProperties = {\r\n position: 'absolute',\r\n top: '0.125rem',\r\n left: theme === 'modern' ? '0.125rem' : '1.375rem',\r\n width: '1rem',\r\n height: '1rem',\r\n borderRadius: '50%',\r\n backgroundColor: '#ffffff',\r\n transition: 'all 0.2s ease',\r\n boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',\r\n };\r\n\r\n return (\r\n <div style={currentStyle} onClick={toggleTheme} className={className} {...props}>\r\n <span>{theme === 'modern' ? '🎨 Modern' : '🏭 HMI'}</span>\r\n <div style={toggleStyle}>\r\n <div style={thumbStyle} />\r\n </div>\r\n <span style={{ fontSize: '0.75rem', opacity: 0.8 }}>\r\n {theme === 'modern' ? 'Industrial Design' : 'High Performance'}\r\n </span>\r\n </div>\r\n );\r\n};\r\n","import React, { useCallback, useState, useEffect, useRef } from 'react';\r\nimport type { Diagram } from '../../diagram/schema';\r\nimport type { TelemetryMap } from '../../diagram/schema';\r\nimport { NodeRenderer } from './NodeRenderer';\r\nimport { PipeRenderer } from './PipeRenderer';\r\nimport { DataOverlay } from './DataOverlay';\r\nimport { PositionPanel } from './PositionPanel';\r\nimport { useViewBox, useSelection, useDrag, useKeyboardShortcuts } from '../../diagram/hooks';\r\nimport type { SelectionState } from '../../diagram/hooks';\r\nimport { getSymbolDefinition } from '../../diagram/symbols';\r\nimport { generateRoutePoints, getPortWorldPosition } from '../../diagram/utils/portCalculations';\r\n\r\nexport interface PIDCanvasFeatures {\r\n /** Enable pan interaction (default: true) */\r\n pan?: boolean;\r\n /** Enable zoom interaction (default: true) */\r\n zoom?: boolean;\r\n /** Enable selection interaction (default: false) */\r\n selection?: boolean;\r\n /** Allow multi-selection with Ctrl/Cmd key (default: true) */\r\n multiSelect?: boolean;\r\n /** Enable telemetry data overlays (default: false) */\r\n telemetry?: boolean;\r\n /** Scale factor for telemetry displays (default: 1.0, range: 0.5-2.0) */\r\n telemetryScale?: number;\r\n /** Enable drag-and-drop for nodes (default: false) */\r\n dragNodes?: boolean;\r\n /** Snap dragged nodes to grid (0 = no snap) */\r\n snapToGrid?: number;\r\n /** Enable keyboard shortcuts for delete/copy/paste (default: false) */\r\n keyboardShortcuts?: boolean;\r\n /** Enable pipe waypoint editing (drag waypoints, add/remove) (default: false) */\r\n editPipeRoutes?: boolean;\r\n /** Enable dropping symbols from library to add nodes (default: false) */\r\n allowSymbolDrop?: boolean;\r\n /** Enable connection drawing mode to create pipes between nodes (default: false) */\r\n connectionMode?: boolean;\r\n /** Show background grid (default: true) */\r\n showGrid?: boolean;\r\n /** Background color for canvas (default: '#ffffff') */\r\n backgroundColor?: string;\r\n}\r\n\r\nexport interface PIDCanvasProps extends React.HTMLAttributes<HTMLDivElement> {\r\n /** The diagram to render */\r\n diagram: Diagram;\r\n /** Optional className for the container */\r\n className?: string;\r\n /** Optional inline styles for the container */\r\n style?: React.CSSProperties;\r\n /** Enable interactive features (pan, zoom, selection, telemetry, dragNodes) */\r\n features?: PIDCanvasFeatures;\r\n /** Callback when selection changes */\r\n onSelectionChange?: (selection: SelectionState) => void;\r\n /** Callback when a node is clicked */\r\n onNodeClick?: (nodeId: string) => void;\r\n /** Callback when a pipe is clicked */\r\n onPipeClick?: (pipeId: string) => void;\r\n /** Callback when a node is moved (drag-and-drop) */\r\n onNodeMove?: (nodeId: string, newX: number, newY: number) => void;\r\n /** Callback when diagram changes (for internal state updates) */\r\n onDiagramChange?: (diagram: Diagram) => void;\r\n /** Callback when items are deleted */\r\n onDelete?: (nodeIds: string[], pipeIds: string[]) => void;\r\n /** Callback when items are copied (returns copied data for external storage) */\r\n onItemsCopied?: (nodeIds: string[], pipeIds: string[]) => void;\r\n /** Callback when paste is requested (external code should handle the paste logic) */\r\n onPaste?: () => void;\r\n /** Callback when a symbol is dropped onto canvas (returns symbol ID and position) */\r\n onSymbolDrop?: (symbolId: string, position: { x: number; y: number }) => void;\r\n /** Callback when a pipe is created via connection mode */\r\n onPipeCreated?: (\r\n sourceNodeId: string,\r\n targetNodeId: string,\r\n sourcePortId?: string,\r\n targetPortId?: string\r\n ) => void;\r\n /** Callback when canvas is mounted, provides control functions */\r\n onMounted?: (controls: PIDCanvasControls) => void;\r\n /** Telemetry data bindings for live values */\r\n telemetry?: TelemetryMap;\r\n}\r\n\r\nexport interface PIDCanvasControls {\r\n /** Fit view to show all diagram content */\r\n fitToContent: (padding?: number) => void;\r\n /** Set zoom level (1 = 100%, 2 = 200%, etc.) */\r\n setZoom: (zoomLevel: number) => void;\r\n /** Get current zoom level */\r\n getZoom: () => number;\r\n}\r\n\r\n/**\r\n * PIDCanvas - Interactive canvas for rendering P&ID diagrams\r\n *\r\n * Features:\r\n * - Renders nodes (PR #3) and pipes (PR #4) with static layout\r\n * - Drag-and-drop: Drag nodes to reposition (PR #8)\r\n *\r\n * Future: Editing tools, symbol library UI\r\n */\r\nexport function PIDCanvas({\r\n diagram,\r\n className = '',\r\n style,\r\n features = {\r\n pan: true,\r\n zoom: true,\r\n selection: false,\r\n multiSelect: true,\r\n telemetry: false,\r\n dragNodes: false,\r\n },\r\n onSelectionChange,\r\n onNodeClick,\r\n onPipeClick,\r\n onNodeMove,\r\n onDiagramChange,\r\n onDelete,\r\n onItemsCopied,\r\n onPaste,\r\n onSymbolDrop,\r\n onPipeCreated,\r\n onMounted,\r\n telemetry,\r\n ...props\r\n}: PIDCanvasProps): React.ReactElement {\r\n const [localDiagram, setLocalDiagram] = useState(diagram);\r\n const [dragOverPosition, setDragOverPosition] = useState<{ x: number; y: number } | null>(null);\r\n\r\n // Connection mode state\r\n const [isConnecting, setIsConnecting] = useState(false);\r\n const [connectionSource, setConnectionSource] = useState<string | null>(null);\r\n const [connectionSourcePort, setConnectionSourcePort] = useState<string | null>(null);\r\n const [connectionCursor, setConnectionCursor] = useState<{ x: number; y: number } | null>(null);\r\n const [hoveredNode, setHoveredNode] = useState<string | null>(null);\r\n const [hoveredPort, setHoveredPort] = useState<string | null>(null);\r\n\r\n // Waypoint selection state (separate from node/pipe selection)\r\n const [selectedWaypoint, setSelectedWaypoint] = useState<{\r\n pipeId: string;\r\n pointIndex: number;\r\n } | null>(null);\r\n\r\n // Undo/Redo state - using refs to avoid re-renders\r\n const historyStack = useRef<Diagram[]>([]);\r\n const redoStack = useRef<Diagram[]>([]);\r\n const isUndoRedoAction = useRef(false);\r\n const isInternalChange = useRef(false);\r\n const lastInternalDiagram = useRef<Diagram | null>(null);\r\n\r\n // Sync external diagram changes to local state\r\n useEffect(() => {\r\n // Only reset history if this is a truly external change (not from our callbacks)\r\n const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;\r\n\r\n // Only update state if this is an external change\r\n // This is a legitimate use of setState in effect - syncing external prop to local state\r\n if (isExternal) {\r\n setLocalDiagram(diagram);\r\n\r\n // Reset history for external changes\r\n if (!isUndoRedoAction.current) {\r\n historyStack.current = [];\r\n redoStack.current = [];\r\n }\r\n }\r\n\r\n // Reset the internal change flag\r\n isInternalChange.current = false;\r\n }, [diagram]);\r\n\r\n const {\r\n viewBox: controlledViewBox,\r\n svgRef,\r\n screenToWorld,\r\n fitToContent: fitToContentViewBox,\r\n setViewBox,\r\n } = useViewBox({\r\n initialViewBox: diagram.viewBox,\r\n enablePan: features.pan ?? true,\r\n enableZoom: features.zoom ?? true,\r\n });\r\n\r\n // Calculate content bounds\r\n const calculateContentBounds = useCallback(() => {\r\n const nodes = localDiagram.nodes.filter((n) => n.visible !== false);\r\n if (nodes.length === 0) {\r\n return null;\r\n }\r\n\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n\r\n nodes.forEach((node) => {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol) return;\r\n\r\n const nodeMinX = node.transform.x;\r\n const nodeMinY = node.transform.y;\r\n const nodeMaxX = node.transform.x + symbol.viewBox.width;\r\n const nodeMaxY = node.transform.y + symbol.viewBox.height;\r\n\r\n minX = Math.min(minX, nodeMinX);\r\n minY = Math.min(minY, nodeMinY);\r\n maxX = Math.max(maxX, nodeMaxX);\r\n maxY = Math.max(maxY, nodeMaxY);\r\n });\r\n\r\n return { minX, minY, maxX, maxY };\r\n }, [localDiagram.nodes]);\r\n\r\n // Expose controls via onMounted callback\r\n useEffect(() => {\r\n if (onMounted) {\r\n const controls: PIDCanvasControls = {\r\n fitToContent: (padding = 50) => {\r\n const bounds = calculateContentBounds();\r\n if (bounds) {\r\n fitToContentViewBox(bounds, padding);\r\n }\r\n },\r\n setZoom: (zoomLevel: number) => {\r\n const centerX = controlledViewBox.x + controlledViewBox.width / 2;\r\n const centerY = controlledViewBox.y + controlledViewBox.height / 2;\r\n const newWidth = diagram.viewBox.width / zoomLevel;\r\n const newHeight = diagram.viewBox.height / zoomLevel;\r\n setViewBox({\r\n x: centerX - newWidth / 2,\r\n y: centerY - newHeight / 2,\r\n width: newWidth,\r\n height: newHeight,\r\n });\r\n },\r\n getZoom: () => {\r\n return diagram.viewBox.width / controlledViewBox.width;\r\n },\r\n };\r\n onMounted(controls);\r\n }\r\n }, [\r\n onMounted,\r\n calculateContentBounds,\r\n fitToContentViewBox,\r\n setViewBox,\r\n controlledViewBox,\r\n diagram.viewBox,\r\n ]);\r\n\r\n const { selection, selectNode, selectPipe, clearSelection } = useSelection({\r\n multiSelect: features.multiSelect ?? true,\r\n onSelectionChange,\r\n });\r\n\r\n const dragEnabled = features.dragNodes ?? false;\r\n const selectionEnabled = features.selection ?? false;\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n\r\n // Push current state to history (for undo)\r\n const pushToHistory = useCallback((currentDiagram: Diagram) => {\r\n if (isUndoRedoAction.current) return; // Don't add to history during undo/redo\r\n\r\n // Deep clone to avoid reference issues\r\n const snapshot = JSON.parse(JSON.stringify(currentDiagram));\r\n historyStack.current.push(snapshot);\r\n\r\n // Limit history size to 15 states\r\n if (historyStack.current.length > 15) {\r\n historyStack.current.shift();\r\n }\r\n\r\n // Clear redo stack on new action\r\n redoStack.current = [];\r\n }, []);\r\n\r\n // Undo function\r\n const undo = useCallback(() => {\r\n if (historyStack.current.length === 0) return;\r\n\r\n isUndoRedoAction.current = true;\r\n\r\n // Save current state to redo stack\r\n const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));\r\n redoStack.current.push(currentSnapshot);\r\n\r\n // Pop from history and restore\r\n const previousState = historyStack.current.pop()!;\r\n isInternalChange.current = true;\r\n lastInternalDiagram.current = previousState;\r\n setLocalDiagram(previousState);\r\n onDiagramChange?.(previousState);\r\n\r\n // Reset flag after state updates\r\n setTimeout(() => {\r\n isUndoRedoAction.current = false;\r\n }, 0);\r\n }, [localDiagram, onDiagramChange]);\r\n\r\n // Redo function\r\n const redo = useCallback(() => {\r\n if (redoStack.current.length === 0) return;\r\n\r\n isUndoRedoAction.current = true;\r\n\r\n // Save current state to history\r\n const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));\r\n historyStack.current.push(currentSnapshot);\r\n\r\n // Pop from redo stack and restore\r\n const nextState = redoStack.current.pop()!;\r\n isInternalChange.current = true;\r\n lastInternalDiagram.current = nextState;\r\n setLocalDiagram(nextState);\r\n onDiagramChange?.(nextState);\r\n\r\n // Reset flag after state updates\r\n setTimeout(() => {\r\n isUndoRedoAction.current = false;\r\n }, 0);\r\n }, [localDiagram, onDiagramChange]);\r\n\r\n // Keyboard shortcuts for undo/redo\r\n useEffect(() => {\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n // Check for Ctrl+Z (Windows/Linux) or Cmd+Z (Mac)\r\n const isCtrlOrCmd = e.ctrlKey || e.metaKey;\r\n\r\n if (isCtrlOrCmd && e.key === 'z' && !e.shiftKey) {\r\n e.preventDefault();\r\n undo();\r\n } else if (isCtrlOrCmd && e.key === 'z' && e.shiftKey) {\r\n e.preventDefault();\r\n redo();\r\n } else if (isCtrlOrCmd && e.key === 'y') {\r\n // Ctrl+Y is also a common redo shortcut\r\n e.preventDefault();\r\n redo();\r\n }\r\n };\r\n\r\n window.addEventListener('keydown', handleKeyDown);\r\n return () => window.removeEventListener('keydown', handleKeyDown);\r\n }, [undo, redo]);\r\n\r\n // Keyboard nudging for selected nodes and waypoints\r\n useEffect(() => {\r\n if (!features.dragNodes) return;\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n // Only handle arrow keys when something is selected\r\n if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;\r\n\r\n // Ignore if user is typing in an input\r\n if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {\r\n return;\r\n }\r\n\r\n const nudgeAmount = e.shiftKey ? 10 : 1; // Shift for larger nudge\r\n let dx = 0;\r\n let dy = 0;\r\n\r\n switch (e.key) {\r\n case 'ArrowLeft':\r\n dx = -nudgeAmount;\r\n e.preventDefault();\r\n break;\r\n case 'ArrowRight':\r\n dx = nudgeAmount;\r\n e.preventDefault();\r\n break;\r\n case 'ArrowUp':\r\n dy = -nudgeAmount;\r\n e.preventDefault();\r\n break;\r\n case 'ArrowDown':\r\n dy = nudgeAmount;\r\n e.preventDefault();\r\n break;\r\n default:\r\n return;\r\n }\r\n\r\n // Update selected waypoint if one is selected\r\n if (selectedWaypoint) {\r\n pushToHistory(localDiagram);\r\n\r\n const updatedPipes = localDiagram.pipes.map((pipe) => {\r\n if (pipe.id === selectedWaypoint.pipeId) {\r\n const updatedRoutePoints = pipe.routePoints.map((point, idx) =>\r\n idx === selectedWaypoint.pointIndex ? { x: point.x + dx, y: point.y + dy } : point\r\n );\r\n return { ...pipe, routePoints: updatedRoutePoints };\r\n }\r\n return pipe;\r\n });\r\n\r\n const updatedDiagram = { ...localDiagram, pipes: updatedPipes };\r\n isInternalChange.current = true;\r\n lastInternalDiagram.current = updatedDiagram;\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n return;\r\n }\r\n\r\n // Update all selected nodes\r\n if (selectionEnabled && selection.selectedNodeIds.size > 0) {\r\n pushToHistory(localDiagram);\r\n\r\n const updatedNodes = localDiagram.nodes.map((node) =>\r\n selection.selectedNodeIds.has(node.id)\r\n ? {\r\n ...node,\r\n transform: {\r\n ...node.transform,\r\n x: node.transform.x + dx,\r\n y: node.transform.y + dy,\r\n },\r\n }\r\n : node\r\n );\r\n\r\n const updatedDiagram = { ...localDiagram, nodes: updatedNodes };\r\n isInternalChange.current = true;\r\n lastInternalDiagram.current = updatedDiagram;\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n\r\n // Call onNodeMove for each moved node\r\n selection.selectedNodeIds.forEach((nodeId) => {\r\n const node = updatedNodes.find((n) => n.id === nodeId);\r\n if (node) {\r\n onNodeMove?.(nodeId, node.transform.x, node.transform.y);\r\n }\r\n });\r\n }\r\n };\r\n\r\n window.addEventListener('keydown', handleKeyDown);\r\n return () => window.removeEventListener('keydown', handleKeyDown);\r\n }, [\r\n selectionEnabled,\r\n features.dragNodes,\r\n selection.selectedNodeIds,\r\n selectedWaypoint,\r\n localDiagram,\r\n onDiagramChange,\r\n onNodeMove,\r\n pushToHistory,\r\n ]);\r\n\r\n // Handler for node position panel changes\r\n const handlePositionChange = useCallback(\r\n (nodeId: string, x: number, y: number) => {\r\n pushToHistory(localDiagram);\r\n\r\n const updatedNodes = localDiagram.nodes.map((node) =>\r\n node.id === nodeId\r\n ? {\r\n ...node,\r\n transform: {\r\n ...node.transform,\r\n x,\r\n y,\r\n },\r\n }\r\n : node\r\n );\r\n\r\n const updatedDiagram = { ...localDiagram, nodes: updatedNodes };\r\n isInternalChange.current = true;\r\n lastInternalDiagram.current = updatedDiagram;\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n onNodeMove?.(nodeId, x, y);\r\n },\r\n [localDiagram, onDiagramChange, onNodeMove, pushToHistory]\r\n );\r\n\r\n // Handler for waypoint position panel changes\r\n const handleWaypointPositionChange = useCallback(\r\n (pipeId: string, pointIndex: number, x: number, y: number) => {\r\n pushToHistory(localDiagram);\r\n\r\n const updatedPipes = localDiagram.pipes.map((pipe) => {\r\n if (pipe.id === pipeId) {\r\n const updatedRoutePoints = pipe.routePoints.map((point, idx) =>\r\n idx === pointIndex ? { x, y } : point\r\n );\r\n return { ...pipe, routePoints: updatedRoutePoints };\r\n }\r\n return pipe;\r\n });\r\n\r\n const updatedDiagram = { ...localDiagram, pipes: updatedPipes };\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n },\r\n [localDiagram, onDiagramChange, pushToHistory]\r\n );\r\n\r\n const handleDragEnd = useCallback(\r\n (nodeId: string, offset: { x: number; y: number }, finalPosition: { x: number; y: number }) => {\r\n // If drag offset is zero or very small, treat as a click for selection\r\n const dragDistance = Math.sqrt(offset.x ** 2 + offset.y ** 2);\r\n if (dragDistance < 2) {\r\n // This was a click, not a drag - handle selection\r\n if (selectionEnabled) {\r\n // We need to check if this was a Ctrl/Cmd click, but we don't have the event here\r\n // For now, just select without modifier\r\n selectNode(nodeId, false);\r\n }\r\n return;\r\n }\r\n\r\n pushToHistory(localDiagram);\r\n\r\n // Update node position in diagram\r\n const updatedNodes = localDiagram.nodes.map((node) =>\r\n node.id === nodeId\r\n ? {\r\n ...node,\r\n transform: {\r\n ...node.transform,\r\n x: finalPosition.x,\r\n y: finalPosition.y,\r\n },\r\n }\r\n : node\r\n );\r\n\r\n // Find affected pipes (pipes connected to this node)\r\n const affectedPipes = localDiagram.pipes.filter(\r\n (pipe) => pipe.fromNodeId === nodeId || pipe.toNodeId === nodeId\r\n );\r\n\r\n // Recalculate routes for affected pipes\r\n const updatedPipes = localDiagram.pipes.map((pipe) => {\r\n if (!affectedPipes.find((p) => p.id === pipe.id)) return pipe;\r\n\r\n const sourceNode = updatedNodes.find((n) => n.id === pipe.fromNodeId);\r\n const targetNode = updatedNodes.find((n) => n.id === pipe.toNodeId);\r\n\r\n if (!sourceNode || !targetNode) return pipe;\r\n\r\n // If pipe has custom waypoints (more than 2 points), preserve ALL waypoints\r\n // including endpoints - user has manually positioned them\r\n if (pipe.routePoints.length > 2) {\r\n return pipe; // Keep all waypoints as-is, including endpoints\r\n }\r\n\r\n // For simple pipes (2 points), recalculate to follow node ports\r\n const newRoutePoints = generateRoutePoints(\r\n sourceNode,\r\n pipe.fromPortId ?? 'output',\r\n targetNode,\r\n pipe.toPortId ?? 'input'\r\n );\r\n\r\n return {\r\n ...pipe,\r\n routePoints: newRoutePoints,\r\n };\r\n });\r\n\r\n const updatedDiagram: Diagram = {\r\n ...localDiagram,\r\n nodes: updatedNodes,\r\n pipes: updatedPipes,\r\n };\r\n\r\n isInternalChange.current = true;\r\n lastInternalDiagram.current = updatedDiagram;\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n onNodeMove?.(nodeId, finalPosition.x, finalPosition.y);\r\n },\r\n [localDiagram, onDiagramChange, onNodeMove, selectionEnabled, selectNode, pushToHistory]\r\n );\r\n\r\n const { dragState, startDrag } = useDrag({\r\n snapToGrid: features.snapToGrid ?? 0,\r\n screenToWorld,\r\n onDragEnd: handleDragEnd,\r\n });\r\n\r\n // Separate drag state for waypoints\r\n const { dragState: waypointDragState, startDrag: startWaypointDrag } = useDrag({\r\n snapToGrid: features.snapToGrid ?? 0,\r\n screenToWorld,\r\n onDragEnd: (\r\n pipeId: string,\r\n _offset: { x: number; y: number },\r\n finalPosition: { x: number; y: number }\r\n ) => {\r\n pushToHistory(localDiagram);\r\n\r\n // Update waypoint position\r\n const [actualPipeId, pointIndex] = pipeId.split(':');\r\n const idx = parseInt(pointIndex, 10);\r\n\r\n const updatedPipes = localDiagram.pipes.map((pipe) => {\r\n if (pipe.id !== actualPipeId) return pipe;\r\n\r\n const updatedRoutePoints = pipe.routePoints.map((point, i) =>\r\n i === idx ? { x: finalPosition.x, y: finalPosition.y } : point\r\n );\r\n\r\n return { ...pipe, routePoints: updatedRoutePoints };\r\n });\r\n\r\n const updatedDiagram = { ...localDiagram, pipes: updatedPipes };\r\n isInternalChange.current = true;\r\n lastInternalDiagram.current = updatedDiagram;\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n },\r\n });\r\n\r\n const handleNodeDragStart = useCallback(\r\n (nodeId: string, event: React.MouseEvent | React.TouchEvent) => {\r\n const node = localDiagram.nodes.find((n) => n.id === nodeId);\r\n if (!node) return;\r\n startDrag(nodeId, event, { x: node.transform.x, y: node.transform.y });\r\n },\r\n [localDiagram.nodes, startDrag]\r\n );\r\n\r\n const handleWaypointClick = useCallback(\r\n (pipeId: string, pointIndex: number) => {\r\n // Select this waypoint\r\n setSelectedWaypoint({ pipeId, pointIndex });\r\n\r\n // Clear node/pipe selection\r\n if (selectionEnabled) {\r\n clearSelection();\r\n }\r\n },\r\n [selectionEnabled, clearSelection]\r\n );\r\n\r\n const handleWaypointDragStart = useCallback(\r\n (pipeId: string, pointIndex: number, event: React.MouseEvent | React.TouchEvent) => {\r\n const pipe = localDiagram.pipes.find((p) => p.id === pipeId);\r\n if (!pipe || pointIndex >= pipe.routePoints.length) return;\r\n\r\n const point = pipe.routePoints[pointIndex];\r\n\r\n // Use compound ID to track both pipe and point\r\n startWaypointDrag(`${pipeId}:${pointIndex}`, event, { x: point.x, y: point.y });\r\n },\r\n [localDiagram.pipes, startWaypointDrag]\r\n );\r\n\r\n const handlePipeSegmentClick = useCallback(\r\n (pipeId: string, position: { x: number; y: number }, segmentIndex: number) => {\r\n pushToHistory(localDiagram);\r\n\r\n const updatedPipes = localDiagram.pipes.map((pipe) => {\r\n if (pipe.id !== pipeId) return pipe;\r\n\r\n // Insert new waypoint after segmentIndex\r\n const updatedRoutePoints = [\r\n ...pipe.routePoints.slice(0, segmentIndex + 1),\r\n position,\r\n ...pipe.routePoints.slice(segmentIndex + 1),\r\n ];\r\n\r\n return { ...pipe, routePoints: updatedRoutePoints };\r\n });\r\n\r\n const updatedDiagram = { ...localDiagram, pipes: updatedPipes };\r\n setLocalDiagram(updatedDiagram);\r\n onDiagramChange?.(updatedDiagram);\r\n },\r\n [localDiagram, onDiagramChange, pushToHistory]\r\n );\r\n\r\n const telemetryEnabled = features.telemetry ?? false;\r\n\r\n const handleDelete = useCallback(() => {\r\n if (!selectionEnabled) return;\r\n const { selectedNodeIds, selectedPipeIds } = selection;\r\n\r\n if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;\r\n\r\n pushToHistory(localDiagram);\r\n\r\n // Remove selected nodes\r\n const updatedNodes = localDiagram.nodes.filter((node) => !selectedNodeIds.has(node.id));\r\n\r\n // Remove selected pipes and pipes connected to deleted nodes\r\n const updatedPipes = localDiagram.pipes.filter(\r\n (pipe) =>\r\n !selectedPipeIds.has(pipe.id) &&\r\n !selectedNodeIds.has(pipe.fromNodeId) &&\r\n !selectedNodeIds.has(pipe.toNodeId)\r\n );\r\n\r\n const updatedDiagram = {\r\n ...localDiagram,\r\n nodes: updatedNodes,\r\n pipes: updatedPipes,\r\n };\r\n\r\n isInternalChange.current = true;\r\n lastInternalDiagram.current = updatedDiagram;\r\n setLocalDiagram(updatedDiagram);\r\n clearSelection();\r\n onDiagramChange?.(updatedDiagram);\r\n onDelete?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));\r\n }, [\r\n selection,\r\n localDiagram,\r\n selectionEnabled,\r\n clearSelection,\r\n onDiagramChange,\r\n onDelete,\r\n pushToHistory,\r\n ]);\r\n\r\n const handleCopy = useCallback(() => {\r\n if (!selectionEnabled) return;\r\n const { selectedNodeIds, selectedPipeIds } = selection;\r\n\r\n if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;\r\n\r\n onItemsCopied?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));\r\n }, [selection, selectionEnabled, onItemsCopied]);\r\n\r\n const handlePaste = useCallback(() => {\r\n if (!selectionEnabled) return;\r\n onPaste?.();\r\n }, [selectionEnabled, onPaste]);\r\n\r\n const handleNodeDoubleClick = (nodeId: string, event: React.MouseEvent) => {\r\n if (!selectionEnabled) return;\r\n console.log('Node double-clicked:', nodeId);\r\n selectNode(nodeId, event.ctrlKey || event.metaKey);\r\n };\r\n\r\n useKeyboardShortcuts({\r\n enabled: features.keyboardShortcuts ?? false,\r\n onDelete: handleDelete,\r\n onCopy: handleCopy,\r\n onPaste: handlePaste,\r\n });\r\n\r\n const handleNodeClick = (nodeId: string, event: React.MouseEvent) => {\r\n // Connection mode takes priority\r\n const connectionModeEnabled = features.connectionMode ?? false;\r\n\r\n if (connectionModeEnabled && isConnecting) {\r\n // Second click - complete connection\r\n if (connectionSource && connectionSource !== nodeId) {\r\n // Use hovered port if available, otherwise let handler choose\r\n onPipeCreated?.(\r\n connectionSource,\r\n nodeId,\r\n connectionSourcePort || undefined,\r\n hoveredPort || undefined\r\n );\r\n setIsConnecting(false);\r\n setConnectionSource(null);\r\n setConnectionSourcePort(null);\r\n setConnectionCursor(null);\r\n setHoveredPort(null);\r\n }\r\n return;\r\n }\r\n\r\n if (connectionModeEnabled && !isConnecting) {\r\n // First click - start connection\r\n setIsConnecting(true);\r\n setConnectionSource(nodeId);\r\n setConnectionSourcePort(hoveredPort);\r\n return;\r\n }\r\n\r\n // Normal selection mode\r\n if (selectionEnabled) {\r\n selectNode(nodeId, event.ctrlKey || event.metaKey);\r\n }\r\n onNodeClick?.(nodeId);\r\n };\r\n\r\n const handlePipeClick = (pipeId: string, event: React.MouseEvent) => {\r\n if (selectionEnabled) {\r\n selectPipe(pipeId, event.ctrlKey || event.metaKey);\r\n }\r\n onPipeClick?.(pipeId);\r\n };\r\n\r\n const handleCanvasClick = (e: React.MouseEvent<SVGSVGElement>) => {\r\n // Don't clear selection if clicking on a waypoint or its parent elements\r\n const target = e.target as Element;\r\n\r\n // Check if target or any parent has the pipe-route-point class\r\n if (target.closest('.pipe-route-point')) {\r\n return;\r\n }\r\n\r\n if (selectionEnabled) {\r\n clearSelection();\r\n }\r\n setSelectedWaypoint(null);\r\n };\r\n\r\n const handleDragOver = useCallback(\r\n (event: React.DragEvent) => {\r\n if (!features.allowSymbolDrop) return;\r\n\r\n event.preventDefault();\r\n event.dataTransfer.dropEffect = 'copy';\r\n\r\n // Convert screen coordinates to world coordinates\r\n if (!svgRef.current) return;\r\n\r\n const worldPos = screenToWorld(event.clientX, event.clientY);\r\n\r\n setDragOverPosition(worldPos);\r\n },\r\n [features.allowSymbolDrop, screenToWorld, svgRef]\r\n );\r\n\r\n const handleDrop = useCallback(\r\n (event: React.DragEvent) => {\r\n if (!features.allowSymbolDrop) return;\r\n\r\n event.preventDefault();\r\n setDragOverPosition(null);\r\n\r\n // Get symbol ID from drag data\r\n const symbolId = event.dataTransfer.getData('application/symbol-id');\r\n if (!symbolId) return;\r\n\r\n // Convert drop position to world coordinates\r\n if (!svgRef.current) return;\r\n const worldPos = screenToWorld(event.clientX, event.clientY);\r\n\r\n onSymbolDrop?.(symbolId, worldPos);\r\n },\r\n [features.allowSymbolDrop, screenToWorld, onSymbolDrop, svgRef]\r\n );\r\n\r\n const handleDragLeave = useCallback(() => {\r\n setDragOverPosition(null);\r\n }, []);\r\n\r\n const handleMouseMove = useCallback(\r\n (event: React.MouseEvent<SVGSVGElement>) => {\r\n const connectionModeEnabled = features.connectionMode ?? false;\r\n\r\n if (connectionModeEnabled) {\r\n const worldPos = screenToWorld(event.clientX, event.clientY);\r\n\r\n // Update cursor position if connecting\r\n if (isConnecting && connectionSource) {\r\n setConnectionCursor(worldPos);\r\n }\r\n\r\n // Always track hovered port in connection mode (for both source and target selection)\r\n let foundPort: string | null = null;\r\n let foundNode: string | null = null;\r\n\r\n for (const node of localDiagram.nodes) {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol || !symbol.ports) continue;\r\n\r\n for (const port of symbol.ports) {\r\n const portPos = getPortWorldPosition(node, port.id);\r\n if (!portPos) continue;\r\n\r\n const distance = Math.sqrt(\r\n (worldPos.x - portPos.x) ** 2 + (worldPos.y - portPos.y) ** 2\r\n );\r\n\r\n // Increased detection radius to 15 for better clickability (visual port is radius 5-8)\r\n if (distance < 15) {\r\n foundPort = port.id;\r\n foundNode = node.id;\r\n break;\r\n }\r\n }\r\n if (foundPort) break;\r\n }\r\n\r\n setHoveredPort(foundPort);\r\n setHoveredNode(foundNode);\r\n }\r\n },\r\n [isConnecting, connectionSource, screenToWorld, localDiagram.nodes, features.connectionMode]\r\n );\r\n\r\n const { name } = diagram;\r\n const viewBox = controlledViewBox;\r\n const displayDiagram = localDiagram;\r\n\r\n // Get first selected node for position panel\r\n const selectedNode =\r\n selectionEnabled && selection.selectedNodeIds.size === 1\r\n ? localDiagram.nodes.find((n) => selection.selectedNodeIds.has(n.id)) || null\r\n : null;\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n className={`pid-canvas ${className}`.trim()}\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n position: 'relative',\r\n overflow: 'hidden',\r\n backgroundColor: '#f5f5f5',\r\n ...style,\r\n }}\r\n {...props}\r\n >\r\n <svg\r\n ref={svgRef}\r\n width=\"100%\"\r\n height=\"100%\"\r\n viewBox={`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`}\r\n preserveAspectRatio=\"xMidYMid meet\"\r\n style={{\r\n display: 'block',\r\n }}\r\n aria-label={`P&ID diagram: ${name}`}\r\n role=\"img\"\r\n onClick={handleCanvasClick}\r\n onMouseMove={handleMouseMove}\r\n onDragOver={handleDragOver}\r\n onDrop={handleDrop}\r\n onDragLeave={handleDragLeave}\r\n >\r\n {/* Background - solid color or grid */}\r\n {features.showGrid !== false ? (\r\n <>\r\n <defs>\r\n {/* Minor grid - 5 unit increments */}\r\n <pattern id=\"grid-minor\" width=\"5\" height=\"5\" patternUnits=\"userSpaceOnUse\">\r\n <path d=\"M 5 0 L 0 0 0 5\" fill=\"none\" stroke=\"#e5e7eb\" strokeWidth=\"0.5\" />\r\n </pattern>\r\n {/* Major grid - 25 unit increments */}\r\n <pattern id=\"grid-major\" width=\"25\" height=\"25\" patternUnits=\"userSpaceOnUse\">\r\n <rect width=\"25\" height=\"25\" fill=\"url(#grid-minor)\" />\r\n <path d=\"M 25 0 L 0 0 0 25\" fill=\"none\" stroke=\"#d1d5db\" strokeWidth=\"1\" />\r\n </pattern>\r\n </defs>\r\n <rect\r\n x={Math.floor(viewBox.x / 25) * 25 - viewBox.width}\r\n y={Math.floor(viewBox.y / 25) * 25 - viewBox.height}\r\n width={Math.ceil((viewBox.width * 3) / 25) * 25}\r\n height={Math.ceil((viewBox.height * 3) / 25) * 25}\r\n fill=\"url(#grid-major)\"\r\n />\r\n </>\r\n ) : (\r\n <rect\r\n x={Math.floor(viewBox.x / 25) * 25 - viewBox.width}\r\n y={Math.floor(viewBox.y / 25) * 25 - viewBox.height}\r\n width={Math.ceil((viewBox.width * 3) / 25) * 25}\r\n height={Math.ceil((viewBox.height * 3) / 25) * 25}\r\n fill={features.backgroundColor ?? '#ffffff'}\r\n />\r\n )}\r\n\r\n {/* Render pipes (behind nodes for proper layering) */}\r\n <PipeRenderer\r\n pipes={displayDiagram.pipes}\r\n selectedPipeIds={selectionEnabled ? selection.selectedPipeIds : undefined}\r\n onPipeClick={selectionEnabled ? handlePipeClick : undefined}\r\n enableWaypointEditing={false}\r\n onWaypointDragStart={undefined}\r\n editingPipeId={null}\r\n draggingWaypointIndex={null}\r\n waypointDragOffset={undefined}\r\n onPipeSegmentClick={undefined}\r\n />\r\n\r\n {/* Render nodes */}\r\n <NodeRenderer\r\n nodes={displayDiagram.nodes}\r\n selectedNodeIds={selectionEnabled ? selection.selectedNodeIds : undefined}\r\n onNodeClick={selectionEnabled || features.connectionMode ? handleNodeClick : undefined}\r\n onNodeDoubleClick={selectionEnabled ? handleNodeDoubleClick : undefined}\r\n enableDrag={dragEnabled && !isConnecting}\r\n onNodeDragStart={dragEnabled && !isConnecting ? handleNodeDragStart : undefined}\r\n draggingNodeId={dragState.draggedId}\r\n dragOffset={dragState.offset}\r\n />\r\n\r\n {/* Render waypoint editing controls on top of nodes */}\r\n {(features.editPipeRoutes ?? false) && (\r\n <PipeRenderer\r\n pipes={displayDiagram.pipes}\r\n selectedPipeIds={selectionEnabled ? selection.selectedPipeIds : undefined}\r\n onPipeClick={undefined}\r\n enableWaypointEditing={true}\r\n onWaypointClick={handleWaypointClick}\r\n onWaypointDragStart={handleWaypointDragStart}\r\n selectedWaypointPipeId={selectedWaypoint?.pipeId || null}\r\n selectedWaypointIndex={selectedWaypoint?.pointIndex ?? null}\r\n editingPipeId={waypointDragState.draggedId?.split(':')[0] || null}\r\n draggingWaypointIndex={\r\n waypointDragState.draggedId\r\n ? parseInt(waypointDragState.draggedId.split(':')[1], 10)\r\n : null\r\n }\r\n waypointDragOffset={waypointDragState.offset}\r\n onPipeSegmentClick={handlePipeSegmentClick}\r\n />\r\n )}\r\n\r\n {/* Render telemetry data overlays */}\r\n {telemetryEnabled && telemetry && (\r\n <g id=\"layer-telemetry\">\r\n {displayDiagram.nodes.map((node) => {\r\n const binding = telemetry.get(node.id);\r\n if (!binding) return null;\r\n\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol) return null;\r\n\r\n // Position overlay centered horizontally and below the node by default\r\n const overlayX = node.transform.x + symbol.viewBox.width / 2;\r\n const overlayY = node.transform.y + symbol.viewBox.height + 50;\r\n\r\n return (\r\n <DataOverlay\r\n key={`telemetry-${node.id}`}\r\n nodeId={node.id}\r\n x={overlayX}\r\n y={overlayY}\r\n telemetry={binding}\r\n scale={features.telemetryScale ?? 1.0}\r\n />\r\n );\r\n })}\r\n </g>\r\n )}\r\n\r\n {/* Drop indicator */}\r\n {dragOverPosition && (\r\n <circle\r\n cx={dragOverPosition.x}\r\n cy={dragOverPosition.y}\r\n r={20}\r\n fill=\"#3b82f6\"\r\n opacity={0.3}\r\n stroke=\"#3b82f6\"\r\n strokeWidth={2}\r\n pointerEvents=\"none\"\r\n />\r\n )}\r\n\r\n {/* Connection mode rubber-band line */}\r\n {isConnecting && connectionSource && connectionCursor && (\r\n <g id=\"connection-preview\" pointerEvents=\"none\">\r\n {(() => {\r\n const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);\r\n if (!sourceNode) return null;\r\n\r\n // If a source port was selected, draw line from that port\r\n const symbol = getSymbolDefinition(sourceNode.symbolId);\r\n let lineStartX = sourceNode.transform.x;\r\n let lineStartY = sourceNode.transform.y;\r\n\r\n if (connectionSourcePort && symbol?.ports) {\r\n const port = symbol.ports.find((p) => p.id === connectionSourcePort);\r\n if (port) {\r\n const portPos = getPortWorldPosition(sourceNode, connectionSourcePort);\r\n if (portPos) {\r\n lineStartX = portPos.x;\r\n lineStartY = portPos.y;\r\n }\r\n }\r\n }\r\n\r\n return (\r\n <>\r\n {/* Highlight source port */}\r\n <circle\r\n cx={lineStartX}\r\n cy={lineStartY}\r\n r={30}\r\n fill=\"none\"\r\n stroke=\"#10b981\"\r\n strokeWidth={3}\r\n opacity={0.6}\r\n />\r\n {/* Rubber-band line */}\r\n <line\r\n x1={lineStartX}\r\n y1={lineStartY}\r\n x2={connectionCursor.x}\r\n y2={connectionCursor.y}\r\n stroke=\"#10b981\"\r\n strokeWidth={2}\r\n strokeDasharray=\"5,5\"\r\n opacity={0.8}\r\n />\r\n {/* Cursor indicator */}\r\n <circle\r\n cx={connectionCursor.x}\r\n cy={connectionCursor.y}\r\n r={8}\r\n fill=\"#10b981\"\r\n opacity={0.6}\r\n />\r\n </>\r\n );\r\n })()}\r\n </g>\r\n )}\r\n\r\n {/* Port indicators in connection mode */}\r\n {features.connectionMode && (\r\n <g id=\"port-indicators\">\r\n {displayDiagram.nodes.map((node) => {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol?.ports) return null;\r\n\r\n return symbol.ports.map((port) => {\r\n const portPos = getPortWorldPosition(node, port.id);\r\n if (!portPos) return null;\r\n\r\n const isHovered = hoveredPort === port.id && hoveredNode === node.id;\r\n const isSourcePort =\r\n node.id === connectionSource && port.id === connectionSourcePort;\r\n\r\n return (\r\n <g key={`${node.id}-${port.id}`}>\r\n {/* Invisible larger hit area for easier clicking */}\r\n <circle\r\n cx={portPos.x}\r\n cy={portPos.y}\r\n r={15}\r\n fill=\"transparent\"\r\n style={{ cursor: 'pointer' }}\r\n pointerEvents=\"auto\"\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n // Trigger the same logic as clicking on the node\r\n if (isConnecting && connectionSource) {\r\n // Second click - complete connection\r\n if (connectionSource !== node.id) {\r\n onPipeCreated?.(\r\n connectionSource,\r\n node.id,\r\n connectionSourcePort || undefined,\r\n port.id\r\n );\r\n setIsConnecting(false);\r\n setConnectionSource(null);\r\n setConnectionSourcePort(null);\r\n setConnectionCursor(null);\r\n setHoveredPort(null);\r\n }\r\n } else {\r\n // First click - start connection\r\n setIsConnecting(true);\r\n setConnectionSource(node.id);\r\n setConnectionSourcePort(port.id);\r\n }\r\n }}\r\n />\r\n {/* Visible port indicator */}\r\n <circle\r\n cx={portPos.x}\r\n cy={portPos.y}\r\n r={isHovered ? 8 : 5}\r\n fill={isSourcePort ? '#10b981' : isHovered ? '#3b82f6' : '#94a3b8'}\r\n stroke={isSourcePort ? '#059669' : isHovered ? '#2563eb' : '#64748b'}\r\n strokeWidth={isHovered || isSourcePort ? 2 : 1}\r\n opacity={isHovered || isSourcePort ? 1 : 0.6}\r\n pointerEvents=\"none\"\r\n />\r\n </g>\r\n );\r\n });\r\n })}\r\n </g>\r\n )}\r\n </svg>\r\n\r\n {/* Position Panel - shows when single node is selected */}\r\n {features.dragNodes && (\r\n <PositionPanel\r\n selectedNode={selectedNode}\r\n selectedWaypoint={\r\n selectedWaypoint\r\n ? {\r\n pipeId: selectedWaypoint.pipeId,\r\n pointIndex: selectedWaypoint.pointIndex,\r\n position: localDiagram.pipes.find((p) => p.id === selectedWaypoint.pipeId)\r\n ?.routePoints[selectedWaypoint.pointIndex] || { x: 0, y: 0 },\r\n }\r\n : null\r\n }\r\n onPositionChange={handlePositionChange}\r\n onWaypointPositionChange={handleWaypointPositionChange}\r\n position=\"top-right\"\r\n />\r\n )}\r\n </div>\r\n );\r\n}\r\n","import type { SymbolDefinition } from '../schema';\r\n\r\n/**\r\n * Mock symbol library with basic P&ID shapes\r\n * Phase 4 will add proper symbol library management\r\n */\r\nexport const mockSymbolLibrary: Record<string, SymbolDefinition> = {\r\n 'valve-gate': {\r\n id: 'valve-gate',\r\n name: 'Gate Valve (Powered)',\r\n category: 'valve',\r\n viewBox: { x: 0, y: 0, width: 52, height: 52 },\r\n ports: [\r\n { id: 'inlet', x: 0, y: 36, type: 'inlet', direction: 'in' },\r\n { id: 'outlet', x: 52, y: 36, type: 'outlet', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Actuator box -->\r\n <rect x=\"16.74\" y=\"0\" width=\"18.02\" height=\"18.02\" fill=\"var(--symbol-fill, #edeeef)\" stroke=\"var(--symbol-stroke, #666666)\" pointer-events=\"all\"/>\r\n <!-- Actuator stem -->\r\n <path d=\"M 25.75 18.02 L 25.75 36.05\" fill=\"none\" stroke=\"var(--symbol-stroke, #666666)\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" pointer-events=\"all\"/>\r\n <!-- Valve body (two triangles forming diamond) -->\r\n <path d=\"M 0 20.6 L 25.75 36.05 L 0 51.5 Z M 51.5 20.6 L 25.75 36.05 L 51.5 51.5 Z\" fill=\"var(--symbol-fill, #edeeef)\" stroke=\"var(--symbol-stroke, #666666)\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" pointer-events=\"all\"/>\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Gate valve with powered actuator',\r\n tags: ['valve', 'gate', 'powered', 'actuator'],\r\n },\r\n },\r\n\r\n 'pump-positive-displacement': {\r\n id: 'pump-positive-displacement',\r\n name: 'Positive Displacement Pump',\r\n category: 'pump',\r\n viewBox: { x: 0, y: 0, width: 56.25, height: 56.25 },\r\n ports: [\r\n { id: 'inlet', x: 0, y: 28.125, type: 'inlet', direction: 'in' },\r\n { id: 'outlet', x: 56.25, y: 28.125, type: 'outlet', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g transform=\"scale(0.5625)\">\r\n <!-- Outer circle -->\r\n <ellipse \r\n cx=\"50\" \r\n cy=\"50\" \r\n rx=\"50\" \r\n ry=\"50\" \r\n fill=\"var(--symbol-fill, #edeeef)\"\r\n stroke=\"var(--symbol-stroke, rgb(0, 0, 0))\"\r\n stroke-width=\"1\"\r\n />\r\n \r\n <!-- Diagonal line from top to bottom-right -->\r\n <path \r\n d=\"M 50 0 L 100 50 L 50 100\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, rgb(0, 0, 0))\"\r\n stroke-width=\"1\"\r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Center square -->\r\n <rect \r\n x=\"35\" \r\n y=\"35\" \r\n width=\"30\" \r\n height=\"30\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, rgb(0, 0, 0))\"\r\n stroke-width=\"1\"\r\n />\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Positive displacement pump (ISO standard)',\r\n tags: ['pump', 'positive-displacement', 'iso'],\r\n },\r\n },\r\n\r\n 'vannefold-bottom': {\r\n id: 'vannefold-bottom',\r\n name: 'Vannefold Block (Bottom)',\r\n category: 'valve',\r\n viewBox: { x: -0.5, y: -0.5, width: 88, height: 67.785156 },\r\n ports: [\r\n { id: 'bottom-inlet', x: 0, y: 25, type: 'control', direction: 'in' },\r\n { id: 'top-outlet', x: 48, y: 65, type: 'control', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Bottom inlet pipe -->\r\n <path \r\n d=\"M 3,29.785156 H 0 v -10 h 3 m 14,10 h 3 v -10 h -3 m -15,8 h 16 m -16,-6 h 16\"\r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Top outlet pipe -->\r\n <path \r\n d=\"m 43,49.785156 v -3 h 10 v 3 m -10,14 v 3 h 10 v -3 m -8,-15 v 16 m 6,-16 v 16\"\r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Main block outer -->\r\n <rect \r\n x=\"7\" \r\n y=\"0\" \r\n width=\"80\" \r\n height=\"59.785156\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Main block inner -->\r\n <rect \r\n x=\"9\" \r\n y=\"2\" \r\n width=\"76\" \r\n height=\"55.785156\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Bolt holes -->\r\n <ellipse cx=\"15\" cy=\"7\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"7\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"7\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"7\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"51.785156\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"51.785156\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"51.785156\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"51.785156\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n \r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Vannefold heat exchanger block with bottom inlet configuration',\r\n tags: ['heat-exchanger', 'vannefold', 'fold', 'bottom'],\r\n },\r\n },\r\n\r\n 'vannefold-middle': {\r\n id: 'vannefold-middle',\r\n name: 'Vannefold Block (Middle)',\r\n category: 'valve',\r\n viewBox: { x: -0.5, y: -0.5, width: 95, height: 53.097656 },\r\n ports: [\r\n { id: 'left-inlet', x: 0, y: 27.3125, type: 'control', direction: 'in' },\r\n { id: 'right-outlet', x: 95, y: 27.3125, type: 'control', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Left inlet pipe -->\r\n <path \r\n d=\"M 3,22.3125 H 0 v 10 H 3 m 14,-10 h 3 v 10 h -3 m -15,-8 h 16 m -16,6 h 16\"\r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Main block outer -->\r\n <rect \r\n x=\"7\" \r\n y=\"0\" \r\n width=\"80\" \r\n height=\"52.097656\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Main block inner -->\r\n <rect \r\n x=\"9\" \r\n y=\"0\" \r\n width=\"76\" \r\n height=\"52.097656\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Bolt holes -->\r\n <ellipse cx=\"15\" cy=\"5.3125\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"5.3125\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"5.3125\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"5.3125\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"47.3125\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"47.3125\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"47.3125\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"47.3125\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Vannefold heat exchanger block with side inlet configuration',\r\n tags: ['heat-exchanger', 'vannefold', 'fold', 'middle'],\r\n },\r\n },\r\n\r\n 'vannefold-top': {\r\n id: 'vannefold-top',\r\n name: 'Vannefold Block (Top)',\r\n category: 'valve',\r\n viewBox: { x: -0.5, y: -0.5, width: 95, height: 60.785156 },\r\n ports: [\r\n { id: 'bottom-inlet', x: 0, y: 35, type: 'control', direction: 'in' },\r\n { id: 'top-outlet', x: 48, y: 0, type: 'control', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Bottom inlet pipe -->\r\n <path \r\n d=\"M 3,30 H 0 V 40 H 3 M 17,30 h 3 V 40 H 17 M 2,32 H 18 M 2,38 H 18\"\r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Main block outer -->\r\n <rect \r\n x=\"7\" \r\n y=\"0\" \r\n width=\"80\" \r\n height=\"59.785156\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Main block inner -->\r\n <rect \r\n x=\"9\" \r\n y=\"2\" \r\n width=\"76\" \r\n height=\"57.785156\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Bolt holes -->\r\n <ellipse cx=\"15\" cy=\"8\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"8\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"8\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"8\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"55\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"55\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"55\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"55\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n \r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Vannefold heat exchanger block with bottom inlet and top outlet configuration',\r\n tags: ['heat-exchanger', 'vannefold', 'fold', 'top'],\r\n },\r\n },\r\n\r\n 'vannefold-top-top-inlet': {\r\n id: 'vannefold-top-top-inlet',\r\n name: 'Vannefold Block (Top, Top Inlet)',\r\n category: 'valve',\r\n viewBox: { x: 0, y: 0, width: 88, height: 67.576004 },\r\n ports: [\r\n { id: 'top-inlet', x: 47, y: 0, type: 'control', direction: 'in' },\r\n { id: 'bottom-outlet', x: 0, y: 42, type: 'control', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Top inlet pipe flange -->\r\n <path \r\n d=\"M 52,3 V 1.3598666e-8 H 42 V 3 m 10,14 v 3 H 42 V 17 M 50,2 V 18 M 44,2 v 16\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Bottom outlet pipe flange -->\r\n <path \r\n d=\"M 3,36.79085 H 0 v 10 h 3 m 14,-10 h 3 v 10 h -3 m -15,-8 h 16 m -16,6 h 16\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Main block outer -->\r\n <rect \r\n x=\"7\" \r\n y=\"6.7908498\" \r\n width=\"80\" \r\n height=\"59.785156\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Main block inner -->\r\n <rect \r\n x=\"9\" \r\n y=\"8.7908498\" \r\n width=\"76\" \r\n height=\"57.785156\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Bolt holes -->\r\n <ellipse cx=\"15\" cy=\"14.79085\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"14.79085\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"61.79085\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"61.79085\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"14.79085\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"14.79085\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"61.79085\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"79\" cy=\"61.79085\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n \r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Vannefold heat exchanger block with top inlet and bottom outlet configuration',\r\n tags: ['heat-exchanger', 'vannefold', 'fold', 'top', 'top-inlet'],\r\n },\r\n },\r\n\r\n 'vannefold-left': {\r\n id: 'vannefold-left',\r\n name: 'Vannefold Block (Left)',\r\n category: 'valve',\r\n viewBox: { x: 0, y: 0, width: 67.785156, height: 88.5 },\r\n ports: [\r\n { id: 'left-inlet', x: 0, y: 41.5, type: 'control', direction: 'in' },\r\n { id: 'right-outlet', x: 42, y: 87, type: 'control', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Left inlet pipe flange -->\r\n <path \r\n d=\"M 3,46.5 H 2.8789924e-8 v -10 H 3 m 14,10 h 3 v -10 h -3 m -15,8 h 16 m -16,-6 h 16\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Right outlet pipe flange -->\r\n <path \r\n d=\"m 37,70.5 v -3 h 10 v 3 m -10,14 v 3 h 10 v -3 m -8,-15 v 16 m 6,-16 v 16\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Main block outer -->\r\n <rect \r\n x=\"7\" \r\n y=\"0.5\" \r\n width=\"59.785156\" \r\n height=\"80\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Main block inner -->\r\n <rect \r\n x=\"9\" \r\n y=\"2.5\" \r\n width=\"57.785156\" \r\n height=\"76\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Bolt holes -->\r\n <ellipse cx=\"15\" cy=\"8.5\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"8.5\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"62\" cy=\"8.5\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"62\" cy=\"8.5\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"72.5\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"15\" cy=\"72.5\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"62\" cy=\"72.5\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"62\" cy=\"72.5\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n \r\n `,\r\n metadata: {\r\n description: 'Vannefold heat exchanger block with left inlet and right outlet, vertical orientation',\r\n tags: ['heat-exchanger', 'vannefold', 'fold', 'left', 'vertical'],\r\n },\r\n },\r\n \r\n 'vannefold-right': {\r\n id: 'vannefold-right',\r\n name: 'Vannefold Block (Right)',\r\n category: 'valve',\r\n viewBox: { x: 0, y: 0, width: 67.785156, height: 88.5 },\r\n ports: [\r\n { id: 'right-inlet', x: 67.785156, y: 41.5, type: 'control', direction: 'in' },\r\n { id: 'left-outlet', x: 24.785156, y: 87.5, type: 'control', direction: 'out' },\r\n ],\r\n svgContent: `\r\n <g>\r\n <!-- Right inlet pipe flange -->\r\n <path \r\n d=\"m 63.785156,46.5 h 3 v -10 h -3 m -14,10 h -3 v -10 h 3 m 15,8 h -16 m 16,-6 h -16\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Left outlet pipe flange -->\r\n <path \r\n d=\"m 29.785156,70.5 v -3 h -10 v 3 m 10,14 v 3 h -10 v -3 m 8,-15 v 16 m -6,-16 v 16\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n />\r\n \r\n <!-- Main block outer -->\r\n <rect \r\n x=\"0\" \r\n y=\"0.5\" \r\n width=\"59.785156\" \r\n height=\"80\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Main block inner -->\r\n <rect \r\n x=\"0\" \r\n y=\"2.5\" \r\n width=\"57.785156\" \r\n height=\"76\" \r\n fill=\"var(--symbol-fill, #eaeaea)\" \r\n stroke=\"var(--symbol-stroke, #000000)\"\r\n />\r\n \r\n <!-- Bolt holes -->\r\n <ellipse cx=\"51.785156\" cy=\"8.5\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"51.785156\" cy=\"8.5\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"4.785156\" cy=\"8.5\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"4.785156\" cy=\"8.5\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"51.785156\" cy=\"72.5\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"51.785156\" cy=\"72.5\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"4.785156\" cy=\"72.5\" rx=\"5\" ry=\"5\" fill=\"#ffffff\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n <ellipse cx=\"4.785156\" cy=\"72.5\" rx=\"3\" ry=\"3\" fill=\"none\" stroke=\"var(--symbol-stroke, #000000)\" />\r\n \r\n `,\r\n metadata: {\r\n description: 'Vannefold heat exchanger block with right inlet and left outlet, vertical orientation',\r\n tags: ['heat-exchanger', 'vannefold', 'fold', 'right', 'vertical'],\r\n },\r\n },\r\n\r\n 'pixer': {\r\n id: 'pixer',\r\n name: 'Pixer',\r\n category: 'pump',\r\n viewBox: { x: 0, y: 0, width: 50.625, height: 46.6875 },\r\n ports: [\r\n { id: 'right-outlet', x: 50.625, y: 30.9375, type: 'control', direction: 'out' },\r\n { id: 'left-outlet', x: 0, y: 30.9375, type: 'control', direction: 'out' },\r\n { id: 'left-inlet', x: 50.625, y: 19.6875, type: 'control', direction: 'in' },\r\n { id: 'right-inlet', x: 0, y: 19.6875, type: 'control', direction: 'in' },\r\n { id: 'top-inlet', x: 25.3125, y: 0, type: 'control', direction: 'in' },\r\n ],\r\n svgContent: `\r\n <g transform=\"scale(0.196875) translate(-195, -186)\">\r\n <!-- Top mounting flange -->\r\n <rect \r\n width=\"141.313\" \r\n height=\"9.872\" \r\n transform=\"translate(252.392 185.89)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n \r\n <!-- Motor housing top -->\r\n <rect \r\n width=\"106.614\" \r\n height=\"2.468\" \r\n transform=\"translate(269.742 199.918)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <rect \r\n width=\"106.614\" \r\n height=\"5.835\" \r\n transform=\"translate(269.742 202.384)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <rect \r\n width=\"106.614\" \r\n height=\"2.468\" \r\n transform=\"translate(269.742 208.222)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Bottom mounting flange -->\r\n <rect \r\n width=\"221.702\" \r\n height=\"2.401\" \r\n transform=\"translate(212.199 395.587)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <rect \r\n width=\"221.702\" \r\n height=\"6.269\" \r\n transform=\"translate(212.199 397.988)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <rect \r\n width=\"221.702\" \r\n height=\"2.65\" \r\n transform=\"translate(212.199 404.257)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Motor housing transition -->\r\n <path \r\n d=\"M444.7,228.776l17.117,4.1H568.429l17.089-4.085a.032.032,0,0,0,0-.062H444.705a.028.028,0,0,0-.007.046Z\" \r\n transform=\"translate(-192.059 -32.959)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Bottom flange -->\r\n <rect \r\n width=\"256\" \r\n height=\"9.872\" \r\n transform=\"translate(195.05 411.066)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n <path \r\n d=\"M195.05,1148.286l17.149-4.156H433.9l17.149,4.156Z\" \r\n transform=\"translate(0 -737.221)\" \r\n fill=\"var(--symbol-fill, #e2e2e2)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n \r\n <!-- Vessel top cone -->\r\n <path \r\n d=\"M451.05,328.356h-256l74.692-34.946H376.358Z\" \r\n transform=\"translate(0 -82.72)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n \r\n <!-- Main vessel body -->\r\n <rect \r\n width=\"256\" \r\n height=\"59.803\" \r\n transform=\"translate(195.05 245.636)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n <rect \r\n width=\"256\" \r\n height=\"76.892\" \r\n transform=\"translate(195.05 308.417)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n \r\n <!-- Vessel bottom transitions -->\r\n <path \r\n d=\"M449.265,705.7H196.773l-1.654-1.465a.014.014,0,0,1,0-.023H451.078Z\" \r\n transform=\"translate(-0.049 -398.769)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <path \r\n d=\"M449.278,710.66H196.793l-1.663,1.462v.016H451.086s.012,0,0-.016Z\" \r\n transform=\"translate(-0.062 -403.731)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <path \r\n d=\"M433.9,1060.758H212.2L195.05,1050.48h256Z\" \r\n transform=\"translate(0 -665.171)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Agitator blades/impellers (simplified without gradients) -->\r\n <ellipse \r\n cx=\"15.454\" \r\n cy=\"6.096\" \r\n rx=\"15.454\" \r\n ry=\"6.096\" \r\n transform=\"translate(307.486 228.161)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #c0c0c0)\"\r\n />\r\n <ellipse \r\n cx=\"15.454\" \r\n cy=\"5.3\" \r\n rx=\"15.454\" \r\n ry=\"5.3\" \r\n transform=\"translate(307.486 229.753)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <ellipse \r\n cx=\"5.174\" \r\n cy=\"15.117\" \r\n rx=\"5.174\" \r\n ry=\"15.117\" \r\n transform=\"translate(367.144 236.079) rotate(-77.61)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <path \r\n d=\"M947,380.271s1.631-2.83,8.084-2.235c5.427.5,16.927,2.855,20.574,8.26\" \r\n transform=\"translate(-578.512 -147.764)\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n <ellipse \r\n cx=\"15.117\" \r\n cy=\"5.174\" \r\n rx=\"15.117\" \r\n ry=\"5.174\" \r\n transform=\"translate(247 232.438) rotate(-12.39)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <path \r\n d=\"M456.439,380.271s-1.631-2.83-8.073-2.235c-5.43.5-16.93,2.855-20.576,8.26\" \r\n transform=\"translate(-179.058 -147.764)\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n <ellipse \r\n cx=\"1.651\" \r\n cy=\"15.082\" \r\n rx=\"1.651\" \r\n ry=\"15.082\" \r\n transform=\"translate(406.71 230.174) rotate(-68.13)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <path \r\n d=\"M1119,375.62a119.876,119.876,0,0,1,26.193,10.419\" \r\n transform=\"translate(-710.84 -145.969)\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n <ellipse \r\n cx=\"15.082\" \r\n cy=\"1.651\" \r\n rx=\"15.082\" \r\n ry=\"1.651\" \r\n transform=\"translate(210.225 238.342) rotate(-21.87)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <path \r\n d=\"M293.943,375.62a119.829,119.829,0,0,0-26.193,10.419\" \r\n transform=\"translate(-55.932 -145.969)\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Pixer mixer/agitator vessel with top-mounted drive',\r\n tags: ['vessel', 'mixer', 'agitator', 'pixer', 'tank'],\r\n },\r\n },\r\n\r\n 'pixer-barb': {\r\n id: 'pixer-barb',\r\n name: 'Pixer (Hose Barb)',\r\n category: 'pump',\r\n viewBox: { x: 0, y: 0, width: 50.625, height: 46.6875 },\r\n ports: [\r\n { id: 'right-outlet', x: 50.625, y: 30.9375, type: 'control', direction: 'out' },\r\n { id: 'left-outlet', x: 0, y: 30.9375, type: 'control', direction: 'out' },\r\n { id: 'left-inlet', x: 50.625, y: 19.6875, type: 'control', direction: 'in' },\r\n { id: 'right-inlet', x: 0, y: 19.6875, type: 'control', direction: 'in' },\r\n { id: 'top-inlet', x: 25.3125, y: 0, type: 'control', direction: 'in' },\r\n ],\r\n svgContent: `\r\n <g transform=\"scale(0.196875) translate(-195, -186)\">\r\n <!-- Hose barb ridges at top -->\r\n <rect \r\n width=\"20\" \r\n height=\"2\" \r\n transform=\"translate(313 173)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"0.5\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <rect \r\n width=\"20\" \r\n height=\"2\" \r\n transform=\"translate(313 177)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"0.5\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <rect \r\n width=\"20\" \r\n height=\"2\" \r\n transform=\"translate(313 181)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"0.5\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n \r\n <!-- Taper from barb to motor housing -->\r\n <path \r\n d=\"M 313,183 L 269.742,199.918 L 376.356,199.918 L 333,183 Z\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n \r\n <!-- Motor housing top -->\r\n <rect \r\n width=\"106.614\" \r\n height=\"2.468\" \r\n transform=\"translate(269.742 199.918)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <rect \r\n width=\"106.614\" \r\n height=\"5.835\" \r\n transform=\"translate(269.742 202.384)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <rect \r\n width=\"106.614\" \r\n height=\"2.468\" \r\n transform=\"translate(269.742 208.222)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Bottom mounting flange -->\r\n <rect \r\n width=\"221.702\" \r\n height=\"2.401\" \r\n transform=\"translate(212.199 395.587)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <rect \r\n width=\"221.702\" \r\n height=\"6.269\" \r\n transform=\"translate(212.199 397.988)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <rect \r\n width=\"221.702\" \r\n height=\"2.65\" \r\n transform=\"translate(212.199 404.257)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Bottom flange -->\r\n <rect \r\n width=\"256\" \r\n height=\"9.872\" \r\n transform=\"translate(195.05 411.066)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n <path \r\n d=\"M195.05,1148.286l17.149-4.156H433.9l17.149,4.156Z\" \r\n transform=\"translate(0 -737.221)\" \r\n fill=\"var(--symbol-fill, #e2e2e2)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n \r\n <!-- Vessel top cone -->\r\n <path \r\n d=\"M451.05,328.356h-256l74.692-34.946H376.358Z\" \r\n transform=\"translate(0 -82.72)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n \r\n <!-- Main vessel body -->\r\n <rect \r\n width=\"256\" \r\n height=\"59.803\" \r\n transform=\"translate(195.05 245.636)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n <rect \r\n width=\"256\" \r\n height=\"76.892\" \r\n transform=\"translate(195.05 308.417)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n \r\n <!-- Vessel bottom transitions -->\r\n <path \r\n d=\"M449.265,705.7H196.773l-1.654-1.465a.014.014,0,0,1,0-.023H451.078Z\" \r\n transform=\"translate(-0.049 -398.769)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <path \r\n d=\"M449.278,710.66H196.793l-1.663,1.462v.016H451.086s.012,0,0-.016Z\" \r\n transform=\"translate(-0.062 -403.731)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n <path \r\n d=\"M433.9,1060.758H212.2L195.05,1050.48h256Z\" \r\n transform=\"translate(0 -665.171)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Agitator blades/impellers (simplified without gradients) -->\r\n <ellipse \r\n cx=\"15.454\" \r\n cy=\"6.096\" \r\n rx=\"15.454\" \r\n ry=\"6.096\" \r\n transform=\"translate(307.486 228.161)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #c0c0c0)\"\r\n />\r\n <ellipse \r\n cx=\"15.454\" \r\n cy=\"5.3\" \r\n rx=\"15.454\" \r\n ry=\"5.3\" \r\n transform=\"translate(307.486 229.753)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <ellipse \r\n cx=\"5.174\" \r\n cy=\"15.117\" \r\n rx=\"5.174\" \r\n ry=\"15.117\" \r\n transform=\"translate(367.144 236.079) rotate(-77.61)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <path \r\n d=\"M947,380.271s1.631-2.83,8.084-2.235c5.427.5,16.927,2.855,20.574,8.26\" \r\n transform=\"translate(-578.512 -147.764)\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n <ellipse \r\n cx=\"15.117\" \r\n cy=\"5.174\" \r\n rx=\"15.117\" \r\n ry=\"5.174\" \r\n transform=\"translate(247 232.438) rotate(-12.39)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <path \r\n d=\"M456.439,380.271s-1.631-2.83-8.073-2.235c-5.43.5-16.93,2.855-20.576,8.26\" \r\n transform=\"translate(-179.058 -147.764)\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n <ellipse \r\n cx=\"1.651\" \r\n cy=\"15.082\" \r\n rx=\"1.651\" \r\n ry=\"15.082\" \r\n transform=\"translate(406.71 230.174) rotate(-68.13)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <path \r\n d=\"M1119,375.62a119.876,119.876,0,0,1,26.193,10.419\" \r\n transform=\"translate(-710.84 -145.969)\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n <ellipse \r\n cx=\"15.082\" \r\n cy=\"1.651\" \r\n rx=\"15.082\" \r\n ry=\"1.651\" \r\n transform=\"translate(210.225 238.342) rotate(-21.87)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #d0d0d0)\"\r\n />\r\n <path \r\n d=\"M293.943,375.62a119.829,119.829,0,0,0-26.193,10.419\" \r\n transform=\"translate(-55.932 -145.969)\" \r\n fill=\"none\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\"\r\n />\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Pixer mixer/agitator vessel with tapered hose barb connection at top',\r\n tags: ['vessel', 'mixer', 'agitator', 'pixer', 'tank', 'hose-barb'],\r\n },\r\n },\r\n \r\n 'vessel-balloon': {\r\n id: 'vessel-balloon',\r\n name: 'Vessel',\r\n category: 'vessel',\r\n viewBox: { x: 0, y: 0, width: 50.625, height: 91 },\r\n ports: [\r\n { id: 'top', type: 'inlet', x: 25.3125, y: 0 },\r\n { id: 'left', type: 'inlet', x: 5, y: 39 },\r\n { id: 'right', type: 'outlet', x: 45.625, y: 39 },\r\n { id: 'bottom', type: 'outlet', x: 25.3125, y: 91 },\r\n ],\r\n svgContent: `\r\n <g transform=\"scale(0.196875) translate(-195, -100)\">\r\n <!-- Top opening nozzle -->\r\n <rect \r\n width=\"65\" \r\n height=\"19.5\" \r\n transform=\"translate(290.5, 100)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Transition from nozzle to dome -->\r\n <path \r\n d=\"M 290.5,119.5 L 238,152 L 408,152 L 355.5,119.5 Z\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Upper balloon dome - rounded bulge -->\r\n <path \r\n d=\"M 238,152 C 185,210 150,320 180,395 L 466,395 C 496,320 461,210 408,152 Z\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n \r\n <!-- Tapered vessel body -->\r\n <path \r\n d=\"M 180,395 L 269.742,530 L 376.356,530 L 466,395 Z\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n \r\n <!-- Bottom cone -->\r\n <path \r\n d=\"M 269.742,530 L 280,555 L 366,555 L 376.356,530 Z\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\"\r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #e0e0e0)\"\r\n />\r\n \r\n <!-- Bottom flange matching pixer top dimensions -->\r\n <rect \r\n width=\"141.313\" \r\n height=\"9.872\" \r\n transform=\"translate(252.392, 555)\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-miterlimit=\"10\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #eaeaea)\"\r\n />\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'Balloon-shaped vessel with rounded top and tapered bottom, designed to fit on standard pixer',\r\n tags: ['vessel', 'storage', 'tank', 'balloon'],\r\n },\r\n },\r\n \r\n 'psr-f': {\r\n id: 'psr-f',\r\n name: 'PSR F',\r\n category: 'instrument',\r\n viewBox: { x: 0, y: 0, width: 57, height: 57 },\r\n ports: [\r\n { id: 'top', type: 'signal', x: 28.5, y: 14.25 },\r\n { id: 'right', type: 'signal', x: 42.75, y: 28.5 },\r\n { id: 'bottom', type: 'signal', x: 28.5, y: 42.75 },\r\n { id: 'left', type: 'signal', x: 14.25, y: 28.5 },\r\n ],\r\n svgContent: `\r\n <g transform=\"scale(0.5) translate(28.5, 28.5)\">\r\n <!-- Circle background -->\r\n <ellipse \r\n cx=\"28.5\" \r\n cy=\"28.5\" \r\n rx=\"28.5\" \r\n ry=\"28.5\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #ffffff)\"\r\n />\r\n \r\n <!-- Letter F -->\r\n <text \r\n x=\"28.5\" \r\n y=\"38\" \r\n text-anchor=\"middle\" \r\n font-family=\"'Times New Roman', Georgia, serif\" \r\n font-size=\"34\" \r\n font-weight=\"normal\" \r\n font-style=\"italic\" \r\n fill=\"var(--symbol-stroke, #000000)\"\r\n >F</text>\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'PSR F instrument symbol - Flow indicator',\r\n tags: ['instrument', 'psr', 'flow', 'indicator'],\r\n },\r\n },\r\n \r\n 'psr-p': {\r\n id: 'psr-p',\r\n name: 'PSR P',\r\n category: 'instrument',\r\n viewBox: { x: 0, y: 0, width: 57, height: 57 },\r\n ports: [\r\n { id: 'top', type: 'signal', x: 28.5, y: 14.25 },\r\n { id: 'right', type: 'signal', x: 42.75, y: 28.5 },\r\n { id: 'bottom', type: 'signal', x: 28.5, y: 42.75 },\r\n { id: 'left', type: 'signal', x: 14.25, y: 28.5 },\r\n ],\r\n svgContent: `\r\n <g transform=\"scale(0.5) translate(28.5, 28.5)\">\r\n <!-- Circle background -->\r\n <ellipse \r\n cx=\"28.5\" \r\n cy=\"28.5\" \r\n rx=\"28.5\" \r\n ry=\"28.5\" \r\n stroke=\"var(--symbol-stroke, #000000)\" \r\n stroke-width=\"1\" \r\n fill=\"var(--symbol-fill, #ffffff)\"\r\n />\r\n \r\n <!-- Letter P -->\r\n <text \r\n x=\"28.5\" \r\n y=\"38\" \r\n text-anchor=\"middle\" \r\n font-family=\"'Times New Roman', Georgia, serif\" \r\n font-size=\"34\" \r\n font-weight=\"normal\" \r\n font-style=\"italic\" \r\n fill=\"var(--symbol-stroke, #000000)\"\r\n >P</text>\r\n </g>\r\n `,\r\n metadata: {\r\n description: 'PSR P instrument symbol - Pressure indicator',\r\n tags: ['instrument', 'psr', 'pressure', 'indicator'],\r\n },\r\n },\r\n};\r\n\r\n/**\r\n * Get symbol definition by ID\r\n */\r\nexport function getSymbolDefinition(symbolId: string): SymbolDefinition | undefined {\r\n return mockSymbolLibrary[symbolId];\r\n}\r\n\r\n/**\r\n * Get all available symbol IDs\r\n */\r\nexport function getAvailableSymbols(): string[] {\r\n return Object.keys(mockSymbolLibrary);\r\n}\r\n","import React from 'react';\r\nimport type { NodeInstance } from '../../diagram/schema';\r\nimport { getSymbolDefinition } from '../../diagram/symbols';\r\n\r\nexport interface NodeRendererProps {\r\n /** Array of node instances to render */\r\n nodes: NodeInstance[];\r\n /** IDs of selected nodes */\r\n selectedNodeIds?: Set<string>;\r\n /** Callback when a node is clicked */\r\n onNodeClick?: (nodeId: string, event: React.MouseEvent) => void;\r\n /** Callback when a node is double-clicked */\r\n onNodeDoubleClick?: (nodeId: string, event: React.MouseEvent) => void;\r\n /** Callback when a node drag starts */\r\n onNodeDragStart?: (nodeId: string, event: React.MouseEvent | React.TouchEvent) => void;\r\n /** ID of node being dragged */\r\n draggingNodeId?: string | null;\r\n /** Drag offset for the dragging node */\r\n dragOffset?: { x: number; y: number };\r\n /** Whether dragging is enabled (default: false) */\r\n enableDrag?: boolean;\r\n}\r\n\r\n/**\r\n * NodeRenderer - Renders symbol instances with transforms and selection support\r\n *\r\n * Applies translate, rotate, and scale transforms to each node\r\n * Supports click selection with visual feedback\r\n */\r\nexport function NodeRenderer({\r\n nodes,\r\n selectedNodeIds,\r\n onNodeClick,\r\n onNodeDoubleClick,\r\n onNodeDragStart,\r\n draggingNodeId,\r\n dragOffset = { x: 0, y: 0 },\r\n enableDrag = false,\r\n}: NodeRendererProps): React.ReactElement {\r\n return (\r\n <g id=\"layer-nodes\">\r\n {nodes\r\n .filter((node) => node.visible !== false) // Filter hidden nodes\r\n .map((node) => {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n const isSelected = selectedNodeIds?.has(node.id) ?? false;\r\n const isDragging = draggingNodeId === node.id;\r\n\r\n if (!symbol) {\r\n // Symbol not found - render placeholder\r\n return (\r\n <g key={node.id}>\r\n <circle\r\n cx={node.transform.x}\r\n cy={node.transform.y}\r\n r=\"15\"\r\n fill=\"#ff0000\"\r\n opacity=\"0.3\"\r\n stroke=\"#ff0000\"\r\n strokeWidth=\"2\"\r\n />\r\n <text\r\n x={node.transform.x}\r\n y={node.transform.y}\r\n textAnchor=\"middle\"\r\n dominantBaseline=\"middle\"\r\n fontSize=\"10\"\r\n fill=\"#ff0000\"\r\n >\r\n ?\r\n </text>\r\n </g>\r\n );\r\n }\r\n\r\n // Build transform string\r\n const transforms: string[] = [];\r\n\r\n // Apply drag offset if this node is being dragged\r\n const effectiveX = isDragging ? node.transform.x + dragOffset.x : node.transform.x;\r\n const effectiveY = isDragging ? node.transform.y + dragOffset.y : node.transform.y;\r\n\r\n // Translate\r\n transforms.push(`translate(${effectiveX}, ${effectiveY})`);\r\n\r\n // Rotate (around center of symbol)\r\n if (node.transform.rotation) {\r\n const centerX = symbol.viewBox.width / 2;\r\n const centerY = symbol.viewBox.height / 2;\r\n transforms.push(`rotate(${node.transform.rotation}, ${centerX}, ${centerY})`);\r\n }\r\n\r\n // Scale\r\n if (node.transform.scale && node.transform.scale !== 1) {\r\n const centerX = symbol.viewBox.width / 2;\r\n const centerY = symbol.viewBox.height / 2;\r\n transforms.push(\r\n `translate(${centerX}, ${centerY}) scale(${node.transform.scale}) translate(${-centerX}, ${-centerY})`\r\n );\r\n }\r\n\r\n // Flip\r\n if (node.transform.flipX || node.transform.flipY) {\r\n const scaleX = node.transform.flipX ? -1 : 1;\r\n const scaleY = node.transform.flipY ? -1 : 1;\r\n const centerX = symbol.viewBox.width / 2;\r\n const centerY = symbol.viewBox.height / 2;\r\n transforms.push(\r\n `translate(${centerX}, ${centerY}) scale(${scaleX}, ${scaleY}) translate(${-centerX}, ${-centerY})`\r\n );\r\n }\r\n\r\n // Determine colors based on status or custom colors\r\n const getStatusColor = (status?: string): string => {\r\n switch (status) {\r\n case 'running':\r\n return '#22c55e'; // Green\r\n case 'alarm':\r\n return '#ef4444'; // Red\r\n case 'warning':\r\n return '#f59e0b'; // Orange\r\n case 'stopped':\r\n default:\r\n return '#edeeef'; // Gray\r\n }\r\n };\r\n\r\n const fillColor = node.customColors?.fill ?? getStatusColor(node.status);\r\n const strokeColor = node.customColors?.stroke ?? 'rgb(0, 0, 0)';\r\n\r\n return (\r\n <g\r\n key={node.id}\r\n data-node-id={node.id}\r\n data-symbol-id={node.symbolId}\r\n data-selected={isSelected}\r\n data-dragging={isDragging}\r\n transform={transforms.join(' ')}\r\n style={\r\n {\r\n '--symbol-fill': fillColor,\r\n '--symbol-stroke': strokeColor,\r\n cursor: enableDrag\r\n ? isDragging\r\n ? 'grabbing'\r\n : 'grab'\r\n : onNodeClick\r\n ? 'pointer'\r\n : 'default',\r\n } as React.CSSProperties\r\n }\r\n onClick={(e) => {\r\n // Always fire onClick - drag system will handle whether to drag\r\n e.stopPropagation();\r\n onNodeClick?.(node.id, e);\r\n }}\r\n onDoubleClick={(e) => {\r\n e.stopPropagation();\r\n onNodeDoubleClick?.(node.id, e);\r\n }}\r\n onMouseDown={(e) => {\r\n if (enableDrag) {\r\n // Don't stop propagation - let click still fire\r\n onNodeDragStart?.(node.id, e);\r\n }\r\n }}\r\n onTouchStart={(e) => {\r\n if (enableDrag) {\r\n e.stopPropagation();\r\n onNodeDragStart?.(node.id, e);\r\n }\r\n }}\r\n >\r\n {/* Selection indicator - bounding box */}\r\n {isSelected && (\r\n <rect\r\n x=\"-5\"\r\n y=\"-5\"\r\n width={symbol.viewBox.width + 10}\r\n height={symbol.viewBox.height + 10}\r\n fill=\"none\"\r\n stroke={isDragging ? '#10b981' : '#3b82f6'}\r\n strokeWidth={isDragging ? '3' : '2'}\r\n strokeDasharray=\"4 2\"\r\n rx=\"2\"\r\n pointerEvents=\"none\"\r\n />\r\n )}\r\n\r\n {/* Render symbol inline (future: use <use> with <defs>) */}\r\n <g\r\n dangerouslySetInnerHTML={{ __html: symbol.svgContent }}\r\n data-symbol-content={symbol.id}\r\n style={{ pointerEvents: 'auto' }}\r\n />\r\n\r\n {/* Node label */}\r\n <text\r\n x={symbol.viewBox.width / 2 + (node.labelOffset?.x ?? 0)}\r\n y={symbol.viewBox.height + 12 + (node.labelOffset?.y ?? 0)}\r\n textAnchor=\"middle\"\r\n fontSize={node.labelFontSize ?? 10}\r\n fontWeight=\"600\"\r\n fill={isSelected ? '#3b82f6' : '#1f2937'}\r\n transform={\r\n node.transform.rotation\r\n ? `rotate(${-node.transform.rotation}, ${symbol.viewBox.width / 2 + (node.labelOffset?.x ?? 0)}, ${symbol.viewBox.height + 12 + (node.labelOffset?.y ?? 0)})`\r\n : undefined\r\n }\r\n >\r\n {node.label || node.id}\r\n </text>\r\n </g>\r\n );\r\n })}\r\n </g>\r\n );\r\n}\r\n","import React from 'react';\r\nimport type { PipeEdge, PipeStyle } from '../../diagram/schema';\r\n\r\nexport interface PipeRendererProps {\r\n /** Array of pipe edges to render */\r\n pipes: PipeEdge[];\r\n /** IDs of selected pipes */\r\n selectedPipeIds?: Set<string>;\r\n /** Callback when a pipe is clicked */\r\n onPipeClick?: (pipeId: string, event: React.MouseEvent) => void;\r\n /** Enable waypoint editing mode */\r\n enableWaypointEditing?: boolean;\r\n /** Callback when waypoint drag starts */\r\n onWaypointDragStart?: (\r\n pipeId: string,\r\n pointIndex: number,\r\n event: React.MouseEvent | React.TouchEvent\r\n ) => void;\r\n /** Callback when waypoint is clicked (for selection) */\r\n onWaypointClick?: (pipeId: string, pointIndex: number) => void;\r\n /** Selected waypoint pipe ID */\r\n selectedWaypointPipeId?: string | null;\r\n /** Selected waypoint point index */\r\n selectedWaypointIndex?: number | null;\r\n /** ID of pipe being edited */\r\n editingPipeId?: string | null;\r\n /** Index of waypoint being dragged */\r\n draggingWaypointIndex?: number | null;\r\n /** Offset for dragged waypoint */\r\n waypointDragOffset?: { x: number; y: number };\r\n /** Callback when pipe segment is clicked (to add waypoint) */\r\n onPipeSegmentClick?: (\r\n pipeId: string,\r\n position: { x: number; y: number },\r\n segmentIndex: number\r\n ) => void;\r\n}\r\n\r\n/**\r\n * PipeRenderer - Renders pipe connections between nodes with selection support\r\n *\r\n * Uses SVG polyline elements to render pipes with route points\r\n * Supports click selection with visual feedback\r\n */\r\nexport function PipeRenderer({\r\n pipes,\r\n selectedPipeIds,\r\n onPipeClick,\r\n enableWaypointEditing = false,\r\n onWaypointDragStart,\r\n onWaypointClick,\r\n selectedWaypointPipeId,\r\n selectedWaypointIndex,\r\n editingPipeId,\r\n draggingWaypointIndex,\r\n waypointDragOffset,\r\n onPipeSegmentClick,\r\n}: PipeRendererProps): React.ReactElement {\r\n return (\r\n <g id=\"layer-pipes\">\r\n {pipes\r\n .filter((pipe) => pipe.visible !== false) // Filter hidden pipes\r\n .map((pipe) => {\r\n const isSelected = selectedPipeIds?.has(pipe.id) ?? false;\r\n const isEditing = enableWaypointEditing && editingPipeId === pipe.id;\r\n const showEditingControls = enableWaypointEditing && isSelected;\r\n\r\n // Apply waypoint drag offset if dragging\r\n const displayPoints = pipe.routePoints.map((point, idx) => {\r\n if (isEditing && draggingWaypointIndex === idx && waypointDragOffset) {\r\n return {\r\n x: point.x + waypointDragOffset.x,\r\n y: point.y + waypointDragOffset.y,\r\n };\r\n }\r\n return point;\r\n });\r\n\r\n // Convert route points to polyline points string\r\n const pointsString = displayPoints.map((point) => `${point.x},${point.y}`).join(' ');\r\n\r\n // Apply pipe style with defaults\r\n const pipeStyle: Partial<PipeStyle> = pipe.style || {};\r\n const stroke = isSelected ? '#3b82f6' : pipeStyle.stroke || '#94a1b8';\r\n const strokeWidth = isSelected\r\n ? (pipeStyle.strokeWidth || 3) + 2\r\n : pipeStyle.strokeWidth || 3;\r\n const strokeDasharray = pipeStyle.strokeDasharray;\r\n const opacity = pipeStyle.opacity !== undefined ? pipeStyle.opacity : 1;\r\n\r\n return (\r\n <g\r\n key={pipe.id}\r\n data-pipe-id={pipe.id}\r\n data-selected={isSelected}\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onPipeClick?.(pipe.id, e);\r\n }}\r\n style={{\r\n cursor: onPipeClick ? 'pointer' : 'default',\r\n }}\r\n >\r\n {/* Only render pipe lines when NOT in waypoint-only mode */}\r\n {!enableWaypointEditing && (\r\n <>\r\n {/* Selection indicator - wider transparent clickable area */}\r\n {onPipeClick && (\r\n <polyline\r\n points={pointsString}\r\n fill=\"none\"\r\n stroke=\"transparent\"\r\n strokeWidth={strokeWidth + 8}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n pointerEvents=\"stroke\"\r\n />\r\n )}\r\n\r\n {/* Main pipe line */}\r\n <polyline\r\n points={pointsString}\r\n fill=\"none\"\r\n stroke={stroke}\r\n strokeWidth={strokeWidth}\r\n strokeDasharray={strokeDasharray}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n opacity={opacity}\r\n data-from={pipe.fromNodeId}\r\n data-to={pipe.toNodeId}\r\n pointerEvents={onPipeClick ? 'none' : 'auto'}\r\n />\r\n </>\r\n )}\r\n\r\n {/* Connection points indicators */}\r\n {displayPoints.map((point, idx) => {\r\n // Show all waypoints including endpoints\r\n const isEndpoint = idx === 0 || idx === displayPoints.length - 1;\r\n const isSelectedWaypoint =\r\n selectedWaypointPipeId === pipe.id && selectedWaypointIndex === idx;\r\n\r\n const isDragging = isEditing && draggingWaypointIndex === idx;\r\n const waypointSize = isSelectedWaypoint\r\n ? 8\r\n : isDragging\r\n ? 8\r\n : showEditingControls\r\n ? 6\r\n : isSelected\r\n ? 3\r\n : 2;\r\n const waypointOpacity = isSelectedWaypoint\r\n ? 1\r\n : isDragging\r\n ? 1\r\n : showEditingControls\r\n ? 0.9\r\n : isSelected\r\n ? 0.8\r\n : 0.5;\r\n\r\n // Color priority: selected > dragging > endpoint > default\r\n const waypointColor = isSelectedWaypoint\r\n ? '#3b82f6' // Blue for selected\r\n : isEndpoint && showEditingControls\r\n ? '#f59e0b' // Amber for endpoints\r\n : isDragging\r\n ? '#10b981' // Green for dragging\r\n : stroke; // Default pipe color\r\n\r\n return (\r\n <circle\r\n key={`${pipe.id}-point-${idx}`}\r\n cx={point.x}\r\n cy={point.y}\r\n r={waypointSize}\r\n fill={waypointColor}\r\n stroke={showEditingControls ? '#ffffff' : 'none'}\r\n strokeWidth={showEditingControls ? 2 : 0}\r\n opacity={waypointOpacity}\r\n className=\"pipe-route-point\"\r\n style={{\r\n cursor: showEditingControls ? (isDragging ? 'grabbing' : 'grab') : 'default',\r\n }}\r\n pointerEvents={showEditingControls ? 'all' : 'none'}\r\n onClick={(e) => {\r\n if (showEditingControls) {\r\n e.stopPropagation();\r\n onWaypointClick?.(pipe.id, idx);\r\n }\r\n }}\r\n onMouseDown={(e) => {\r\n if (showEditingControls) {\r\n e.stopPropagation();\r\n onWaypointDragStart?.(pipe.id, idx, e);\r\n }\r\n }}\r\n onTouchStart={(e) => {\r\n if (showEditingControls) {\r\n e.stopPropagation();\r\n onWaypointDragStart?.(pipe.id, idx, e);\r\n }\r\n }}\r\n />\r\n );\r\n })}\r\n\r\n {/* Pipe segment click areas (for adding waypoints) */}\r\n {showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && (\r\n <>\r\n {displayPoints.slice(0, -1).map((point, idx) => {\r\n const nextPoint = displayPoints[idx + 1];\r\n const midX = (point.x + nextPoint.x) / 2;\r\n const midY = (point.y + nextPoint.y) / 2;\r\n\r\n return (\r\n <g key={`${pipe.id}-segment-${idx}`}>\r\n {/* Larger clickable area */}\r\n <circle\r\n cx={midX}\r\n cy={midY}\r\n r={8}\r\n fill=\"transparent\"\r\n className=\"pipe-segment-add-area\"\r\n style={{ cursor: 'crosshair' }}\r\n pointerEvents=\"all\"\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onPipeSegmentClick?.(pipe.id, { x: midX, y: midY }, idx);\r\n }}\r\n />\r\n {/* Visible indicator */}\r\n <circle\r\n cx={midX}\r\n cy={midY}\r\n r={4}\r\n fill=\"#3b82f6\"\r\n stroke=\"#ffffff\"\r\n strokeWidth={2}\r\n opacity={0.6}\r\n className=\"pipe-segment-add\"\r\n pointerEvents=\"none\"\r\n />\r\n </g>\r\n );\r\n })}\r\n </>\r\n )}\r\n\r\n {/* Pipe label (optional) */}\r\n {pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && (\r\n <text\r\n x={\r\n pipe.routePoints[Math.floor(pipe.routePoints.length / 2)].x +\r\n (pipe.labelOffset?.x ?? 0)\r\n }\r\n y={\r\n pipe.routePoints[Math.floor(pipe.routePoints.length / 2)].y -\r\n 8 +\r\n (pipe.labelOffset?.y ?? 0)\r\n }\r\n textAnchor=\"middle\"\r\n fontSize=\"10\"\r\n fontWeight={isSelected ? '600' : '500'}\r\n fill={stroke}\r\n opacity={opacity * 0.8}\r\n pointerEvents=\"none\"\r\n >\r\n {pipe.label}\r\n </text>\r\n )}\r\n </g>\r\n );\r\n })}\r\n </g>\r\n );\r\n}\r\n","import React from 'react';\r\nimport type { TelemetryBinding } from '../../diagram/schema/TelemetryBinding';\r\n\r\nexport interface DataOverlayProps {\r\n /** Node ID this overlay is for */\r\n nodeId: string;\r\n /** X position in SVG coordinates */\r\n x: number;\r\n /** Y position in SVG coordinates */\r\n y: number;\r\n /** Telemetry binding data */\r\n telemetry: TelemetryBinding;\r\n /** Scale factor for display size (default: 1.0) */\r\n scale?: number;\r\n}\r\n\r\n/**\r\n * DataOverlay - Renders live telemetry values above P&ID nodes\r\n *\r\n * Shows:\r\n * - Current value with unit\r\n * - Status-based color coding\r\n * - Optional label\r\n */\r\nexport function DataOverlay({\r\n nodeId,\r\n x,\r\n y,\r\n telemetry,\r\n scale = 1.0,\r\n}: DataOverlayProps): React.ReactElement {\r\n const { value, display, history } = telemetry;\r\n const showValue = display?.showValue ?? true;\r\n const showStatus = display?.showStatus ?? true;\r\n const showSparkline = display?.showSparkline ?? false;\r\n const label = display?.label;\r\n const precision = display?.precision;\r\n const sparklineColor = display?.sparklineColor;\r\n const textColor = display?.textColor;\r\n const backgroundColor = display?.backgroundColor;\r\n const offsetX = display?.offsetX ?? 0;\r\n const offsetY = display?.offsetY ?? 0;\r\n\r\n if (!showValue) {\r\n return <></>;\r\n }\r\n\r\n // Format value based on type and precision\r\n const formatValue = (val: number | string | boolean): string => {\r\n if (typeof val === 'number') {\r\n return precision !== undefined ? val.toFixed(precision) : val.toString();\r\n }\r\n if (typeof val === 'boolean') {\r\n return val ? 'ON' : 'OFF';\r\n }\r\n return val.toString();\r\n };\r\n\r\n // Status color mapping - use custom colors if provided, otherwise defaults\r\n const defaultStatusColors: Record<string, { bg: string; text: string; border: string }> = {\r\n normal: { bg: '#10b981', text: '#ffffff', border: '#059669' },\r\n warning: { bg: '#f59e0b', text: '#ffffff', border: '#d97706' },\r\n alarm: { bg: '#ef4444', text: '#ffffff', border: '#dc2626' },\r\n fault: { bg: '#dc2626', text: '#ffffff', border: '#b91c1c' },\r\n off: { bg: '#6b7280', text: '#ffffff', border: '#4b5563' },\r\n };\r\n\r\n // Apply custom colors if provided\r\n const customColor = telemetry.statusColors?.[value.status];\r\n const defaultColorSet = defaultStatusColors[value.status] || defaultStatusColors.normal;\r\n\r\n const statusColors = customColor\r\n ? { bg: customColor, text: '#ffffff', border: customColor }\r\n : defaultColorSet;\r\n\r\n const colors =\r\n backgroundColor && backgroundColor !== 'status'\r\n ? { bg: backgroundColor, text: textColor || '#ffffff', border: backgroundColor }\r\n : statusColors;\r\n\r\n // Override text color if explicitly set\r\n const finalTextColor = textColor || colors.text;\r\n\r\n const formattedValue = formatValue(value.value);\r\n const displayText = value.unit ? `${formattedValue} ${value.unit}` : formattedValue;\r\n\r\n // Calculate sparkline path if history is provided\r\n const sparklinePath = (() => {\r\n if (!showSparkline || !history || history.length < 2) return '';\r\n\r\n const width = 70 * scale;\r\n const height = 20 * scale;\r\n const padding = 5 * scale;\r\n const effectiveWidth = width - padding * 2;\r\n const effectiveHeight = height - padding * 2;\r\n\r\n const min = Math.min(...history);\r\n const max = Math.max(...history);\r\n const range = max - min || 1; // Avoid division by zero\r\n\r\n const points = history.map((val, i) => {\r\n const xPos = (i / (history.length - 1)) * effectiveWidth + padding;\r\n const yPos = height - padding - ((val - min) / range) * effectiveHeight;\r\n return `${xPos.toFixed(2)},${yPos.toFixed(2)}`;\r\n });\r\n\r\n return `M ${points.join(' L ')}`;\r\n })();\r\n\r\n const hasSparkline = showSparkline && sparklinePath;\r\n const overlayHeight = (label ? (hasSparkline ? 55 : 30) : hasSparkline ? 47 : 22) * scale;\r\n const overlayWidth = 80 * scale;\r\n\r\n // Apply position offsets\r\n const displayX = x + offsetX;\r\n const displayY = y + offsetY;\r\n\r\n return (\r\n <g data-overlay-node={nodeId} data-status={value.status}>\r\n {/* Background rect */}\r\n <rect\r\n x={displayX - overlayWidth / 2}\r\n y={displayY - 25 * scale}\r\n width={overlayWidth}\r\n height={overlayHeight}\r\n rx={4 * scale}\r\n fill={colors.bg}\r\n stroke={colors.border}\r\n strokeWidth={1 * scale}\r\n opacity=\"0.95\"\r\n filter=\"drop-shadow(0 2px 4px rgba(0,0,0,0.2))\"\r\n />\r\n\r\n {/* Label (optional) */}\r\n {label && (\r\n <text\r\n x={displayX}\r\n y={displayY - 15 * scale}\r\n textAnchor=\"middle\"\r\n fontSize={8 * scale}\r\n fontWeight=\"600\"\r\n fill={finalTextColor}\r\n opacity=\"0.9\"\r\n >\r\n {label}\r\n </text>\r\n )}\r\n\r\n {/* Value text */}\r\n <text\r\n x={displayX}\r\n y={label ? displayY - 3 * scale : displayY - 9 * scale}\r\n textAnchor=\"middle\"\r\n fontSize={11 * scale}\r\n fontWeight=\"700\"\r\n fill={finalTextColor}\r\n letterSpacing=\"0.02em\"\r\n >\r\n {displayText}\r\n </text>\r\n\r\n {/* Status indicator dot (optional) */}\r\n {showStatus && value.status !== 'normal' && (\r\n <circle\r\n cx={displayX + 35 * scale}\r\n cy={displayY - 18 * scale}\r\n r={3 * scale}\r\n fill={finalTextColor}\r\n opacity=\"0.9\"\r\n >\r\n <animate\r\n attributeName=\"opacity\"\r\n values=\"0.9;0.3;0.9\"\r\n dur=\"1.5s\"\r\n repeatCount=\"indefinite\"\r\n />\r\n </circle>\r\n )}\r\n\r\n {/* Quality indicator (if provided and < 100) */}\r\n {value.quality !== undefined && value.quality < 100 && (\r\n <text\r\n x={displayX}\r\n y={displayY + 5 * scale}\r\n textAnchor=\"middle\"\r\n fontSize={7 * scale}\r\n fontWeight=\"500\"\r\n fill={finalTextColor}\r\n opacity=\"0.7\"\r\n >\r\n Q: {value.quality}%\r\n </text>\r\n )}\r\n\r\n {/* Sparkline trend (if history provided) */}\r\n {hasSparkline && (\r\n <g transform={`translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`}>\r\n <path\r\n d={sparklinePath}\r\n fill=\"none\"\r\n stroke={sparklineColor || finalTextColor}\r\n strokeWidth={1.5 * scale}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n opacity=\"0.9\"\r\n />\r\n </g>\r\n )}\r\n </g>\r\n );\r\n}\r\n","import React, { useState, useEffect } from 'react';\r\nimport type { NodeInstance, Point } from '../../diagram/schema';\r\n\r\nexport interface PositionPanelProps {\r\n /** The selected node to display/edit position for */\r\n selectedNode?: NodeInstance | null;\r\n /** The selected waypoint to display/edit position for */\r\n selectedWaypoint?: { pipeId: string; pointIndex: number; position: Point } | null;\r\n /** Callback when node position is changed */\r\n onPositionChange?: (nodeId: string, x: number, y: number) => void;\r\n /** Callback when waypoint position is changed */\r\n onWaypointPositionChange?: (pipeId: string, pointIndex: number, x: number, y: number) => void;\r\n /** Position of the panel (default: top-right) */\r\n position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\r\n}\r\n\r\n/**\r\n * PositionPanel - Displays and allows editing of selected node or waypoint position\r\n */\r\nexport function PositionPanel({\r\n selectedNode,\r\n selectedWaypoint,\r\n onPositionChange,\r\n onWaypointPositionChange,\r\n position = 'top-right',\r\n}: PositionPanelProps): React.ReactElement | null {\r\n const [x, setX] = useState<string>('');\r\n const [y, setY] = useState<string>('');\r\n\r\n // Update inputs when selected node or waypoint changes\r\n useEffect(() => {\r\n if (selectedNode) {\r\n setX(selectedNode.transform.x.toFixed(2));\r\n setY(selectedNode.transform.y.toFixed(2));\r\n } else if (selectedWaypoint) {\r\n setX(selectedWaypoint.position.x.toFixed(2));\r\n setY(selectedWaypoint.position.y.toFixed(2));\r\n }\r\n }, [selectedNode, selectedWaypoint]);\r\n\r\n if (!selectedNode && !selectedWaypoint) {\r\n return null;\r\n }\r\n\r\n const handleXChange = (value: string) => {\r\n setX(value);\r\n const numValue = parseFloat(value);\r\n if (!isNaN(numValue)) {\r\n if (selectedNode && onPositionChange) {\r\n onPositionChange(selectedNode.id, numValue, selectedNode.transform.y);\r\n } else if (selectedWaypoint && onWaypointPositionChange) {\r\n onWaypointPositionChange(\r\n selectedWaypoint.pipeId,\r\n selectedWaypoint.pointIndex,\r\n numValue,\r\n selectedWaypoint.position.y\r\n );\r\n }\r\n }\r\n };\r\n\r\n const handleYChange = (value: string) => {\r\n setY(value);\r\n const numValue = parseFloat(value);\r\n if (!isNaN(numValue)) {\r\n if (selectedNode && onPositionChange) {\r\n onPositionChange(selectedNode.id, selectedNode.transform.x, numValue);\r\n } else if (selectedWaypoint && onWaypointPositionChange) {\r\n onWaypointPositionChange(\r\n selectedWaypoint.pipeId,\r\n selectedWaypoint.pointIndex,\r\n selectedWaypoint.position.x,\r\n numValue\r\n );\r\n }\r\n }\r\n };\r\n\r\n const handleBlur = () => {\r\n // Reset to actual position on blur (handles invalid input)\r\n if (selectedNode) {\r\n setX(selectedNode.transform.x.toFixed(2));\r\n setY(selectedNode.transform.y.toFixed(2));\r\n } else if (selectedWaypoint) {\r\n setX(selectedWaypoint.position.x.toFixed(2));\r\n setY(selectedWaypoint.position.y.toFixed(2));\r\n }\r\n };\r\n\r\n const positionStyles: Record<string, React.CSSProperties> = {\r\n 'top-left': { top: 10, left: 10 },\r\n 'top-right': { top: 10, right: 10 },\r\n 'bottom-left': { bottom: 10, left: 10 },\r\n 'bottom-right': { bottom: 10, right: 10 },\r\n };\r\n\r\n return (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n ...positionStyles[position],\r\n backgroundColor: 'white',\r\n border: '1px solid #ccc',\r\n borderRadius: '4px',\r\n padding: '12px',\r\n boxShadow: '0 2px 8px rgba(0,0,0,0.1)',\r\n zIndex: 1000,\r\n minWidth: '180px',\r\n fontFamily: 'system-ui, -apple-system, sans-serif',\r\n fontSize: '13px',\r\n }}\r\n >\r\n <div style={{ marginBottom: '8px', fontWeight: 600, color: '#333' }}>Position</div>\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\r\n <label style={{ width: '16px', color: '#666' }}>X:</label>\r\n <input\r\n type=\"number\"\r\n value={x}\r\n onChange={(e) => handleXChange(e.target.value)}\r\n onBlur={handleBlur}\r\n style={{\r\n flex: 1,\r\n padding: '4px 8px',\r\n border: '1px solid #ddd',\r\n borderRadius: '3px',\r\n fontSize: '13px',\r\n }}\r\n step=\"1\"\r\n />\r\n </div>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\r\n <label style={{ width: '16px', color: '#666' }}>Y:</label>\r\n <input\r\n type=\"number\"\r\n value={y}\r\n onChange={(e) => handleYChange(e.target.value)}\r\n onBlur={handleBlur}\r\n style={{\r\n flex: 1,\r\n padding: '4px 8px',\r\n border: '1px solid #ddd',\r\n borderRadius: '3px',\r\n fontSize: '13px',\r\n }}\r\n step=\"1\"\r\n />\r\n </div>\r\n </div>\r\n <div style={{ marginTop: '8px', fontSize: '11px', color: '#888' }}>\r\n Use arrow keys to nudge (±1px)\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { useState, useCallback, useRef, useEffect } from 'react';\r\nimport type { ViewBox } from '../schema';\r\n\r\nexport interface UseViewBoxOptions {\r\n /** Initial viewBox configuration */\r\n initialViewBox: ViewBox;\r\n /** Enable pan interaction (default: true) */\r\n enablePan?: boolean;\r\n /** Enable zoom interaction (default: true) */\r\n enableZoom?: boolean;\r\n /** Minimum zoom level (smaller = more zoomed in, default: 0.1) */\r\n minZoom?: number;\r\n /** Maximum zoom level (larger = more zoomed out, default: 10) */\r\n maxZoom?: number;\r\n /** Zoom sensitivity (default: 0.001) */\r\n zoomSensitivity?: number;\r\n /** Allow left-click drag for panning (default: true for touch-friendly) */\r\n allowLeftClickPan?: boolean;\r\n}\r\n\r\nexport interface UseViewBoxResult {\r\n /** Current viewBox state */\r\n viewBox: ViewBox;\r\n /** Reset viewBox to initial state */\r\n resetViewBox: () => void;\r\n /** Zoom in (decrease viewBox size) */\r\n zoomIn: () => void;\r\n /** Zoom out (increase viewBox size) */\r\n zoomOut: () => void;\r\n /** Fit viewBox to content bounds with optional padding */\r\n fitToContent: (bounds: { minX: number; minY: number; maxX: number; maxY: number }, padding?: number) => void;\r\n /** Set viewBox directly */\r\n setViewBox: (viewBox: ViewBox) => void;\r\n /** Convert screen coordinates to world (SVG) coordinates */\r\n screenToWorld: (screenX: number, screenY: number) => { x: number; y: number };\r\n /** SVG element ref to attach event listeners */\r\n svgRef: React.RefObject<SVGSVGElement | null>;\r\n}\r\n\r\n/**\r\n * Custom hook for managing ViewBox state with pan and zoom interactions\r\n * \r\n * Pan controls:\r\n * - Left mouse button + drag (if allowLeftClickPan=true, default)\r\n * - Middle mouse button + drag (always)\r\n * - Space + left mouse button + drag (always)\r\n * - Touch drag (single finger)\r\n * \r\n * Zoom controls:\r\n * - Mouse wheel (zoom to cursor position)\r\n * - Pinch gesture (touch devices)\r\n * - Programmatic zoomIn/zoomOut functions\r\n */\r\nexport function useViewBox(options: UseViewBoxOptions): UseViewBoxResult {\r\n const {\r\n initialViewBox,\r\n enablePan = true,\r\n enableZoom = true,\r\n minZoom = 0.1,\r\n maxZoom = 10,\r\n zoomSensitivity = 0.001,\r\n allowLeftClickPan = true,\r\n } = options;\r\n\r\n const [viewBox, setViewBox] = useState<ViewBox>(initialViewBox);\r\n const svgRef = useRef<SVGSVGElement | null>(null);\r\n const isPanningRef = useRef(false);\r\n const lastMousePosRef = useRef({ x: 0, y: 0 });\r\n const spaceKeyDownRef = useRef(false);\r\n const lastTouchDistanceRef = useRef<number | null>(null);\r\n\r\n // Reset to initial viewBox\r\n const resetViewBox = useCallback(() => {\r\n setViewBox(initialViewBox);\r\n }, [initialViewBox]);\r\n\r\n // Zoom in (25% closer)\r\n const zoomIn = useCallback(() => {\r\n setViewBox((prev) => {\r\n const currentZoom = initialViewBox.width / prev.width;\r\n const newZoom = Math.min(1 / minZoom, currentZoom * 1.25);\r\n const scale = initialViewBox.width / newZoom;\r\n \r\n const centerX = prev.x + prev.width / 2;\r\n const centerY = prev.y + prev.height / 2;\r\n const newWidth = scale;\r\n const newHeight = (prev.height / prev.width) * scale;\r\n\r\n return {\r\n x: centerX - newWidth / 2,\r\n y: centerY - newHeight / 2,\r\n width: newWidth,\r\n height: newHeight,\r\n };\r\n });\r\n }, [initialViewBox, minZoom]);\r\n\r\n // Zoom out (25% farther)\r\n const zoomOut = useCallback(() => {\r\n setViewBox((prev) => {\r\n const currentZoom = initialViewBox.width / prev.width;\r\n const newZoom = Math.max(1 / maxZoom, currentZoom * 0.8);\r\n const scale = initialViewBox.width / newZoom;\r\n \r\n const centerX = prev.x + prev.width / 2;\r\n const centerY = prev.y + prev.height / 2;\r\n const newWidth = scale;\r\n const newHeight = (prev.height / prev.width) * scale;\r\n\r\n return {\r\n x: centerX - newWidth / 2,\r\n y: centerY - newHeight / 2,\r\n width: newWidth,\r\n height: newHeight,\r\n };\r\n });\r\n }, [initialViewBox, maxZoom]);\r\n\r\n // Fit to content bounds\r\n const fitToContent = useCallback((bounds: { minX: number; minY: number; maxX: number; maxY: number }, padding: number = 50) => {\r\n const contentWidth = bounds.maxX - bounds.minX;\r\n const contentHeight = bounds.maxY - bounds.minY;\r\n \r\n if (contentWidth === 0 || contentHeight === 0) {\r\n // No content or invalid bounds\r\n return;\r\n }\r\n\r\n // Add padding\r\n const paddedWidth = contentWidth + padding * 2;\r\n const paddedHeight = contentHeight + padding * 2;\r\n \r\n // Maintain aspect ratio of initial viewBox\r\n const aspectRatio = initialViewBox.width / initialViewBox.height;\r\n const contentAspectRatio = paddedWidth / paddedHeight;\r\n \r\n let newWidth: number;\r\n let newHeight: number;\r\n \r\n if (contentAspectRatio > aspectRatio) {\r\n // Content is wider - fit to width\r\n newWidth = paddedWidth;\r\n newHeight = paddedWidth / aspectRatio;\r\n } else {\r\n // Content is taller - fit to height\r\n newHeight = paddedHeight;\r\n newWidth = paddedHeight * aspectRatio;\r\n }\r\n \r\n const centerX = bounds.minX + contentWidth / 2;\r\n const centerY = bounds.minY + contentHeight / 2;\r\n \r\n setViewBox({\r\n x: centerX - newWidth / 2,\r\n y: centerY - newHeight / 2,\r\n width: newWidth,\r\n height: newHeight,\r\n });\r\n }, [initialViewBox]);\r\n\r\n // Handle mouse wheel zoom\r\n useEffect(() => {\r\n if (!enableZoom || !svgRef.current) return;\r\n\r\n const svg = svgRef.current;\r\n\r\n const handleWheel = (e: WheelEvent) => {\r\n e.preventDefault();\r\n\r\n // Get mouse position in SVG coordinate space\r\n const rect = svg.getBoundingClientRect();\r\n const mouseX = e.clientX - rect.left;\r\n const mouseY = e.clientY - rect.top;\r\n\r\n setViewBox((prev) => {\r\n // Convert mouse position to viewBox coordinates\r\n const svgX = prev.x + (mouseX / rect.width) * prev.width;\r\n const svgY = prev.y + (mouseY / rect.height) * prev.height;\r\n\r\n // Calculate zoom factor\r\n const delta = -e.deltaY * zoomSensitivity;\r\n const zoom = Math.exp(delta);\r\n\r\n // Calculate new viewBox dimensions\r\n let newWidth = prev.width / zoom;\r\n let newHeight = prev.height / zoom;\r\n\r\n // Clamp zoom level\r\n const currentZoom = initialViewBox.width / prev.width;\r\n const newZoom = currentZoom * zoom;\r\n if (newZoom < minZoom || newZoom > 1 / minZoom) {\r\n return prev; // Don't zoom beyond limits\r\n }\r\n\r\n // Adjust viewBox position to zoom towards mouse cursor\r\n const newX = svgX - (mouseX / rect.width) * newWidth;\r\n const newY = svgY - (mouseY / rect.height) * newHeight;\r\n\r\n return {\r\n x: newX,\r\n y: newY,\r\n width: newWidth,\r\n height: newHeight,\r\n };\r\n });\r\n };\r\n\r\n svg.addEventListener('wheel', handleWheel, { passive: false });\r\n return () => svg.removeEventListener('wheel', handleWheel);\r\n }, [enableZoom, zoomSensitivity, minZoom, initialViewBox]);\r\n\r\n // Handle panning\r\n useEffect(() => {\r\n if (!enablePan || !svgRef.current) return;\r\n\r\n const svg = svgRef.current;\r\n\r\n const handleMouseDown = (e: MouseEvent) => {\r\n // Check if clicking on a draggable element (node, waypoint, pipe segment)\r\n const target = e.target as Element;\r\n const isDraggableNode = target.closest('[data-node-id]');\r\n const isWaypoint = target.classList.contains('pipe-route-point');\r\n const isPipeSegment = target.classList.contains('pipe-segment-add') || target.classList.contains('pipe-segment-add-area');\r\n \r\n if (isDraggableNode || isWaypoint || isPipeSegment) {\r\n return; // Let drag handler take over\r\n }\r\n\r\n // Left button (if allowed), middle button, or space + left button\r\n const isLeftClick = e.button === 0 && allowLeftClickPan;\r\n const isMiddleClick = e.button === 1;\r\n const isSpaceLeftClick = e.button === 0 && spaceKeyDownRef.current;\r\n \r\n if (isLeftClick || isMiddleClick || isSpaceLeftClick) {\r\n e.preventDefault();\r\n isPanningRef.current = true;\r\n lastMousePosRef.current = { x: e.clientX, y: e.clientY };\r\n svg.style.cursor = 'grabbing';\r\n }\r\n };\r\n\r\n const handleMouseMove = (e: MouseEvent) => {\r\n if (!isPanningRef.current) return;\r\n\r\n const dx = e.clientX - lastMousePosRef.current.x;\r\n const dy = e.clientY - lastMousePosRef.current.y;\r\n lastMousePosRef.current = { x: e.clientX, y: e.clientY };\r\n\r\n setViewBox((prev) => {\r\n const rect = svg.getBoundingClientRect();\r\n const scaleX = prev.width / rect.width;\r\n const scaleY = prev.height / rect.height;\r\n\r\n return {\r\n ...prev,\r\n x: prev.x - dx * scaleX,\r\n y: prev.y - dy * scaleY,\r\n };\r\n });\r\n };\r\n\r\n const handleMouseUp = () => {\r\n if (isPanningRef.current) {\r\n isPanningRef.current = false;\r\n svg.style.cursor = (allowLeftClickPan || spaceKeyDownRef.current) ? 'grab' : '';\r\n }\r\n };\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.code === 'Space' && !spaceKeyDownRef.current) {\r\n e.preventDefault();\r\n spaceKeyDownRef.current = true;\r\n if (!isPanningRef.current && !allowLeftClickPan) {\r\n svg.style.cursor = 'grab';\r\n }\r\n }\r\n };\r\n\r\n const handleKeyUp = (e: KeyboardEvent) => {\r\n if (e.code === 'Space') {\r\n spaceKeyDownRef.current = false;\r\n if (!isPanningRef.current && !allowLeftClickPan) {\r\n svg.style.cursor = '';\r\n }\r\n }\r\n };\r\n\r\n // Set initial cursor if left-click pan is enabled\r\n if (allowLeftClickPan && !isPanningRef.current) {\r\n svg.style.cursor = 'grab';\r\n }\r\n\r\n svg.addEventListener('mousedown', handleMouseDown);\r\n window.addEventListener('mousemove', handleMouseMove);\r\n window.addEventListener('mouseup', handleMouseUp);\r\n window.addEventListener('keydown', handleKeyDown);\r\n window.addEventListener('keyup', handleKeyUp);\r\n\r\n return () => {\r\n svg.removeEventListener('mousedown', handleMouseDown);\r\n window.removeEventListener('mousemove', handleMouseMove);\r\n window.removeEventListener('mouseup', handleMouseUp);\r\n window.removeEventListener('keydown', handleKeyDown);\r\n window.removeEventListener('keyup', handleKeyUp);\r\n };\r\n }, [enablePan, allowLeftClickPan]);\r\n\r\n // Handle touch gestures (pan and pinch-to-zoom)\r\n useEffect(() => {\r\n if (!svgRef.current) return;\r\n if (!enablePan && !enableZoom) return;\r\n\r\n const svg = svgRef.current;\r\n\r\n const handleTouchStart = (e: TouchEvent) => {\r\n // Check if touching a draggable element (node, waypoint, pipe segment)\r\n const target = e.target as Element;\r\n const isDraggableNode = target.closest('[data-node-id]');\r\n const isWaypoint = target.classList.contains('pipe-route-point');\r\n const isPipeSegment = target.classList.contains('pipe-segment-add') || target.classList.contains('pipe-segment-add-area');\r\n \r\n if ((isDraggableNode || isWaypoint || isPipeSegment) && e.touches.length === 1) {\r\n return; // Let drag handler take over for single touch\r\n }\r\n\r\n if (e.touches.length === 1 && enablePan) {\r\n // Single touch - pan\r\n isPanningRef.current = true;\r\n lastMousePosRef.current = {\r\n x: e.touches[0].clientX,\r\n y: e.touches[0].clientY,\r\n };\r\n } else if (e.touches.length === 2 && enableZoom) {\r\n // Two touches - prepare for pinch zoom\r\n const touch1 = e.touches[0];\r\n const touch2 = e.touches[1];\r\n const distance = Math.hypot(\r\n touch2.clientX - touch1.clientX,\r\n touch2.clientY - touch1.clientY\r\n );\r\n lastTouchDistanceRef.current = distance;\r\n }\r\n };\r\n\r\n const handleTouchMove = (e: TouchEvent) => {\r\n e.preventDefault();\r\n\r\n if (e.touches.length === 1 && isPanningRef.current && enablePan) {\r\n // Single touch pan\r\n const touch = e.touches[0];\r\n const dx = touch.clientX - lastMousePosRef.current.x;\r\n const dy = touch.clientY - lastMousePosRef.current.y;\r\n lastMousePosRef.current = { x: touch.clientX, y: touch.clientY };\r\n\r\n setViewBox((prev) => {\r\n const rect = svg.getBoundingClientRect();\r\n const scaleX = prev.width / rect.width;\r\n const scaleY = prev.height / rect.height;\r\n\r\n return {\r\n ...prev,\r\n x: prev.x - dx * scaleX,\r\n y: prev.y - dy * scaleY,\r\n };\r\n });\r\n } else if (e.touches.length === 2 && enableZoom && lastTouchDistanceRef.current) {\r\n // Pinch zoom\r\n const touch1 = e.touches[0];\r\n const touch2 = e.touches[1];\r\n const distance = Math.hypot(\r\n touch2.clientX - touch1.clientX,\r\n touch2.clientY - touch1.clientY\r\n );\r\n\r\n const scale = distance / lastTouchDistanceRef.current;\r\n lastTouchDistanceRef.current = distance;\r\n\r\n // Get center point between two touches\r\n const centerX = (touch1.clientX + touch2.clientX) / 2;\r\n const centerY = (touch1.clientY + touch2.clientY) / 2;\r\n const rect = svg.getBoundingClientRect();\r\n\r\n setViewBox((prev) => {\r\n // Convert touch center to viewBox coordinates\r\n const svgX = prev.x + ((centerX - rect.left) / rect.width) * prev.width;\r\n const svgY = prev.y + ((centerY - rect.top) / rect.height) * prev.height;\r\n\r\n // Calculate new dimensions\r\n let newWidth = prev.width / scale;\r\n let newHeight = prev.height / scale;\r\n\r\n // Clamp zoom level\r\n const currentZoom = initialViewBox.width / prev.width;\r\n const newZoom = currentZoom * scale;\r\n if (newZoom < minZoom || newZoom > 1 / minZoom) {\r\n return prev;\r\n }\r\n\r\n // Adjust position to zoom toward touch center\r\n const newX = svgX - ((centerX - rect.left) / rect.width) * newWidth;\r\n const newY = svgY - ((centerY - rect.top) / rect.height) * newHeight;\r\n\r\n return {\r\n x: newX,\r\n y: newY,\r\n width: newWidth,\r\n height: newHeight,\r\n };\r\n });\r\n }\r\n };\r\n\r\n const handleTouchEnd = () => {\r\n isPanningRef.current = false;\r\n lastTouchDistanceRef.current = null;\r\n };\r\n\r\n svg.addEventListener('touchstart', handleTouchStart);\r\n svg.addEventListener('touchmove', handleTouchMove, { passive: false });\r\n svg.addEventListener('touchend', handleTouchEnd);\r\n\r\n return () => {\r\n svg.removeEventListener('touchstart', handleTouchStart);\r\n svg.removeEventListener('touchmove', handleTouchMove);\r\n svg.removeEventListener('touchend', handleTouchEnd);\r\n };\r\n }, [enablePan, enableZoom, minZoom, initialViewBox]);\r\n\r\n const screenToWorld = useCallback(\r\n (screenX: number, screenY: number): { x: number; y: number } => {\r\n const svg = svgRef.current;\r\n if (!svg) return { x: screenX, y: screenY };\r\n\r\n const rect = svg.getBoundingClientRect();\r\n \r\n // Account for preserveAspectRatio=\"xMidYMid meet\"\r\n const svgAspect = rect.width / rect.height;\r\n const viewBoxAspect = viewBox.width / viewBox.height;\r\n \r\n let actualWidth = rect.width;\r\n let actualHeight = rect.height;\r\n let offsetX = 0;\r\n let offsetY = 0;\r\n \r\n if (svgAspect > viewBoxAspect) {\r\n // SVG is wider - pillarboxing on sides\r\n actualWidth = rect.height * viewBoxAspect;\r\n offsetX = (rect.width - actualWidth) / 2;\r\n } else {\r\n // SVG is taller - letterboxing on top/bottom\r\n actualHeight = rect.width / viewBoxAspect;\r\n offsetY = (rect.height - actualHeight) / 2;\r\n }\r\n \r\n const relativeX = (screenX - rect.left - offsetX) / actualWidth;\r\n const relativeY = (screenY - rect.top - offsetY) / actualHeight;\r\n\r\n const worldX = viewBox.x + relativeX * viewBox.width;\r\n const worldY = viewBox.y + relativeY * viewBox.height;\r\n\r\n return { x: worldX, y: worldY };\r\n },\r\n [viewBox]\r\n );\r\n\r\n return {\r\n viewBox,\r\n resetViewBox,\r\n zoomIn,\r\n zoomOut,\r\n fitToContent,\r\n setViewBox,\r\n screenToWorld,\r\n svgRef,\r\n };\r\n}\r\n","import { useState, useCallback } from 'react';\r\n\r\nexport interface SelectionState {\r\n /** IDs of selected nodes */\r\n selectedNodeIds: Set<string>;\r\n /** IDs of selected pipes */\r\n selectedPipeIds: Set<string>;\r\n}\r\n\r\nexport interface UseSelectionOptions {\r\n /** Allow multiple selection with Ctrl/Cmd key (default: true) */\r\n multiSelect?: boolean;\r\n /** Initial selection state */\r\n initialSelection?: SelectionState;\r\n /** Callback when selection changes */\r\n onSelectionChange?: (selection: SelectionState) => void;\r\n}\r\n\r\nexport interface UseSelectionResult {\r\n /** Current selection state */\r\n selection: SelectionState;\r\n /** Check if a node is selected */\r\n isNodeSelected: (nodeId: string) => boolean;\r\n /** Check if a pipe is selected */\r\n isPipeSelected: (pipeId: string) => boolean;\r\n /** Select a node */\r\n selectNode: (nodeId: string, multiSelect?: boolean) => void;\r\n /** Select a pipe */\r\n selectPipe: (pipeId: string, multiSelect?: boolean) => void;\r\n /** Clear all selections */\r\n clearSelection: () => void;\r\n /** Select multiple nodes */\r\n selectNodes: (nodeIds: string[]) => void;\r\n /** Select multiple pipes */\r\n selectPipes: (pipeIds: string[]) => void;\r\n}\r\n\r\n/**\r\n * Custom hook for managing selection state in P&ID diagrams\r\n * \r\n * Supports:\r\n * - Single selection (click)\r\n * - Multi-selection (Ctrl+click)\r\n * - Programmatic selection\r\n * - Selection callbacks\r\n */\r\nexport function useSelection(options: UseSelectionOptions = {}): UseSelectionResult {\r\n const {\r\n multiSelect = true,\r\n initialSelection = { selectedNodeIds: new Set(), selectedPipeIds: new Set() },\r\n onSelectionChange,\r\n } = options;\r\n\r\n const [selection, setSelection] = useState<SelectionState>(initialSelection);\r\n\r\n const notifyChange = useCallback(\r\n (newSelection: SelectionState) => {\r\n if (onSelectionChange) {\r\n onSelectionChange(newSelection);\r\n }\r\n },\r\n [onSelectionChange]\r\n );\r\n\r\n const isNodeSelected = useCallback(\r\n (nodeId: string) => selection.selectedNodeIds.has(nodeId),\r\n [selection.selectedNodeIds]\r\n );\r\n\r\n const isPipeSelected = useCallback(\r\n (pipeId: string) => selection.selectedPipeIds.has(pipeId),\r\n [selection.selectedPipeIds]\r\n );\r\n\r\n const selectNode = useCallback(\r\n (nodeId: string, isMultiSelect = false) => {\r\n setSelection((prev) => {\r\n const newNodeIds = new Set<string>(isMultiSelect && multiSelect ? prev.selectedNodeIds : []);\r\n \r\n if (newNodeIds.has(nodeId)) {\r\n // Deselect if already selected in multi-select mode\r\n newNodeIds.delete(nodeId);\r\n } else {\r\n newNodeIds.add(nodeId);\r\n }\r\n\r\n const newSelection: SelectionState = {\r\n selectedNodeIds: newNodeIds,\r\n selectedPipeIds: isMultiSelect && multiSelect ? prev.selectedPipeIds : new Set<string>(),\r\n };\r\n\r\n notifyChange(newSelection);\r\n return newSelection;\r\n });\r\n },\r\n [multiSelect, notifyChange]\r\n );\r\n\r\n const selectPipe = useCallback(\r\n (pipeId: string, isMultiSelect = false) => {\r\n setSelection((prev) => {\r\n const newPipeIds = new Set<string>(isMultiSelect && multiSelect ? prev.selectedPipeIds : []);\r\n \r\n if (newPipeIds.has(pipeId)) {\r\n // Deselect if already selected in multi-select mode\r\n newPipeIds.delete(pipeId);\r\n } else {\r\n newPipeIds.add(pipeId);\r\n }\r\n\r\n const newSelection: SelectionState = {\r\n selectedNodeIds: isMultiSelect && multiSelect ? prev.selectedNodeIds : new Set<string>(),\r\n selectedPipeIds: newPipeIds,\r\n };\r\n\r\n notifyChange(newSelection);\r\n return newSelection;\r\n });\r\n },\r\n [multiSelect, notifyChange]\r\n );\r\n\r\n const clearSelection = useCallback(() => {\r\n const newSelection = {\r\n selectedNodeIds: new Set<string>(),\r\n selectedPipeIds: new Set<string>(),\r\n };\r\n setSelection(newSelection);\r\n notifyChange(newSelection);\r\n }, [notifyChange]);\r\n\r\n const selectNodes = useCallback(\r\n (nodeIds: string[]) => {\r\n const newSelection = {\r\n selectedNodeIds: new Set(nodeIds),\r\n selectedPipeIds: new Set<string>(),\r\n };\r\n setSelection(newSelection);\r\n notifyChange(newSelection);\r\n },\r\n [notifyChange]\r\n );\r\n\r\n const selectPipes = useCallback(\r\n (pipeIds: string[]) => {\r\n const newSelection = {\r\n selectedNodeIds: new Set<string>(),\r\n selectedPipeIds: new Set(pipeIds),\r\n };\r\n setSelection(newSelection);\r\n notifyChange(newSelection);\r\n },\r\n [notifyChange]\r\n );\r\n\r\n return {\r\n selection,\r\n isNodeSelected,\r\n isPipeSelected,\r\n selectNode,\r\n selectPipe,\r\n clearSelection,\r\n selectNodes,\r\n selectPipes,\r\n };\r\n}\r\n","import { useState, useCallback, useEffect, useRef } from 'react';\r\nimport type { TelemetryBinding, TelemetryMap, TelemetryValue } from '../schema/TelemetryBinding';\r\n\r\n// Re-export types for consumer convenience\r\nexport type { TelemetryBinding, TelemetryMap, TelemetryValue };\r\n\r\nexport interface UseTelemetryOptions {\r\n /** Initial telemetry bindings */\r\n initialBindings?: TelemetryBinding[];\r\n /** Callback when telemetry values change */\r\n onTelemetryChange?: (bindings: TelemetryMap) => void;\r\n /** Auto-refresh interval in milliseconds (0 = disabled) */\r\n refreshInterval?: number;\r\n}\r\n\r\nexport interface UseTelemetryResult {\r\n /** Current telemetry bindings map */\r\n telemetry: TelemetryMap;\r\n /** Update a single telemetry value */\r\n updateTelemetry: (nodeId: string, value: TelemetryValue) => void;\r\n /** Update multiple telemetry values at once */\r\n updateTelemetryBatch: (updates: Array<{ nodeId: string; value: TelemetryValue; history?: number[] }>) => void;\r\n /** Get telemetry for a specific node */\r\n getTelemetry: (nodeId: string) => TelemetryBinding | undefined;\r\n /** Clear all telemetry data */\r\n clearTelemetry: () => void;\r\n /** Set telemetry bindings */\r\n setBindings: (bindings: TelemetryBinding[]) => void;\r\n}\r\n\r\n/**\r\n * Custom hook for managing telemetry data bindings\r\n * \r\n * Supports:\r\n * - Real-time value updates\r\n * - Status monitoring (normal, warning, alarm, fault, off)\r\n * - Batch updates for performance\r\n * - Auto-refresh capability\r\n * - Quality indicators\r\n */\r\nexport function useTelemetry(options: UseTelemetryOptions = {}): UseTelemetryResult {\r\n const {\r\n initialBindings = [],\r\n onTelemetryChange,\r\n refreshInterval = 0,\r\n } = options;\r\n\r\n // Initialize telemetry map from bindings\r\n const [telemetry, setTelemetry] = useState<TelemetryMap>(() => {\r\n const map = new Map<string, TelemetryBinding>();\r\n initialBindings.forEach((binding) => {\r\n map.set(binding.nodeId, binding);\r\n });\r\n return map;\r\n });\r\n\r\n const telemetryRef = useRef(telemetry);\r\n telemetryRef.current = telemetry;\r\n\r\n const notifyChange = useCallback(\r\n (newTelemetry: TelemetryMap) => {\r\n if (onTelemetryChange) {\r\n onTelemetryChange(newTelemetry);\r\n }\r\n },\r\n [onTelemetryChange]\r\n );\r\n\r\n const updateTelemetry = useCallback(\r\n (nodeId: string, value: TelemetryValue) => {\r\n setTelemetry((prev) => {\r\n const newMap = new Map(prev);\r\n const existing = newMap.get(nodeId);\r\n \r\n if (existing) {\r\n // Update existing binding\r\n newMap.set(nodeId, {\r\n ...existing,\r\n value: {\r\n ...value,\r\n timestamp: value.timestamp ?? Date.now(),\r\n },\r\n });\r\n } else {\r\n // Create new binding\r\n newMap.set(nodeId, {\r\n nodeId,\r\n tag: nodeId, // Default tag to nodeId\r\n value: {\r\n ...value,\r\n timestamp: value.timestamp ?? Date.now(),\r\n },\r\n });\r\n }\r\n\r\n notifyChange(newMap);\r\n return newMap;\r\n });\r\n },\r\n [notifyChange]\r\n );\r\n\r\n const updateTelemetryBatch = useCallback(\r\n (updates: Array<{ \r\n nodeId: string; \r\n tag?: string; \r\n value?: TelemetryValue; \r\n history?: number[]; \r\n display?: any; \r\n thresholds?: any; \r\n statusColors?: any;\r\n remove?: boolean \r\n }>) => {\r\n setTelemetry((prev) => {\r\n const newMap = new Map(prev);\r\n let hasChanges = false;\r\n\r\n updates.forEach(({ nodeId, tag, value, history, display, thresholds, statusColors, remove }) => {\r\n if (remove) {\r\n // Remove telemetry binding\r\n if (newMap.has(nodeId)) {\r\n newMap.delete(nodeId);\r\n hasChanges = true;\r\n }\r\n return;\r\n }\r\n\r\n const existing = newMap.get(nodeId);\r\n\r\n if (existing) {\r\n newMap.set(nodeId, {\r\n ...existing,\r\n ...(tag !== undefined && { tag }),\r\n ...(value !== undefined && {\r\n value: {\r\n ...value,\r\n timestamp: value.timestamp ?? Date.now(),\r\n },\r\n }),\r\n ...(history !== undefined && { history }),\r\n ...(display !== undefined && { display }),\r\n ...(thresholds !== undefined && { thresholds }),\r\n ...(statusColors !== undefined && { statusColors }),\r\n });\r\n hasChanges = true;\r\n } else if (value) {\r\n newMap.set(nodeId, {\r\n nodeId,\r\n tag: tag ?? nodeId,\r\n value: {\r\n ...value,\r\n timestamp: value.timestamp ?? Date.now(),\r\n },\r\n ...(history !== undefined && { history }),\r\n ...(display !== undefined && { display }),\r\n ...(thresholds !== undefined && { thresholds }),\r\n ...(statusColors !== undefined && { statusColors }),\r\n });\r\n hasChanges = true;\r\n }\r\n });\r\n\r\n if (hasChanges) {\r\n notifyChange(newMap);\r\n }\r\n return newMap;\r\n });\r\n },\r\n [notifyChange]\r\n );\r\n\r\n const getTelemetry = useCallback(\r\n (nodeId: string) => telemetryRef.current.get(nodeId),\r\n []\r\n );\r\n\r\n const clearTelemetry = useCallback(() => {\r\n const newMap = new Map<string, TelemetryBinding>();\r\n setTelemetry(newMap);\r\n notifyChange(newMap);\r\n }, [notifyChange]);\r\n\r\n const setBindings = useCallback(\r\n (bindings: TelemetryBinding[]) => {\r\n const newMap = new Map<string, TelemetryBinding>();\r\n bindings.forEach((binding) => {\r\n newMap.set(binding.nodeId, binding);\r\n });\r\n setTelemetry(newMap);\r\n notifyChange(newMap);\r\n },\r\n [notifyChange]\r\n );\r\n\r\n // Auto-refresh functionality\r\n useEffect(() => {\r\n if (refreshInterval <= 0) return;\r\n\r\n const intervalId = setInterval(() => {\r\n // Trigger change notification to allow external refresh logic\r\n notifyChange(telemetryRef.current);\r\n }, refreshInterval);\r\n\r\n return () => clearInterval(intervalId);\r\n }, [refreshInterval, notifyChange]);\r\n\r\n return {\r\n telemetry,\r\n updateTelemetry,\r\n updateTelemetryBatch,\r\n getTelemetry,\r\n clearTelemetry,\r\n setBindings,\r\n };\r\n}\r\n","import { useEffect } from 'react';\r\nimport type { TelemetryMap } from './useTelemetry';\r\nimport type { Diagram } from '../schema';\r\n\r\n/**\r\n * Options for syncing telemetry status to node status\r\n */\r\nexport interface UseTelemetryStatusOptions {\r\n /** Whether status sync is enabled (default: true) */\r\n enabled?: boolean;\r\n /** Custom status mapping function */\r\n mapStatus?: (telemetryStatus: string) => string;\r\n}\r\n\r\n/**\r\n * Hook to sync telemetry status to node instance status for dynamic coloring\r\n * \r\n * Updates node.status based on telemetry status values:\r\n * - 'normal' → 'running'\r\n * - 'warning' → 'warning'\r\n * - 'alarm' / 'fault' → 'alarm'\r\n * - 'off' → 'stopped'\r\n * \r\n * @param telemetry - Telemetry map from useTelemetry\r\n * @param diagram - Current diagram state\r\n * @param setDiagram - Diagram state setter\r\n * @param options - Configuration options\r\n * \r\n * @example\r\n * ```tsx\r\n * const { telemetry } = useTelemetry();\r\n * const [diagram, setDiagram] = useState<Diagram>({...});\r\n * \r\n * useTelemetryStatus(telemetry, diagram, setDiagram, {\r\n * enabled: mode === 'runtime'\r\n * });\r\n * ```\r\n */\r\nexport function useTelemetryStatus(\r\n telemetry: TelemetryMap,\r\n diagram: Diagram,\r\n setDiagram: (diagram: Diagram) => void,\r\n options: UseTelemetryStatusOptions = {}\r\n) {\r\n const { enabled = true, mapStatus } = options;\r\n\r\n useEffect(() => {\r\n if (!enabled) return;\r\n\r\n // Map telemetry status to node status\r\n const defaultMapStatus = (telemetryStatus: string): string => {\r\n switch (telemetryStatus) {\r\n case 'normal':\r\n return 'running';\r\n case 'warning':\r\n return 'warning';\r\n case 'alarm':\r\n case 'fault':\r\n return 'alarm';\r\n case 'off':\r\n return 'stopped';\r\n default:\r\n return 'stopped';\r\n }\r\n };\r\n\r\n const statusMapper = mapStatus || defaultMapStatus;\r\n\r\n // Check if any node status needs updating\r\n let needsUpdate = false;\r\n const updatedNodes = diagram.nodes.map((node) => {\r\n const binding = telemetry.get(node.id);\r\n if (!binding) return node;\r\n\r\n const newStatus = statusMapper(binding.value.status);\r\n if (node.status !== newStatus) {\r\n needsUpdate = true;\r\n return { ...node, status: newStatus };\r\n }\r\n return node;\r\n });\r\n\r\n if (needsUpdate) {\r\n setDiagram({\r\n ...diagram,\r\n nodes: updatedNodes,\r\n });\r\n }\r\n }, [telemetry, diagram, setDiagram, enabled, mapStatus]);\r\n}\r\n","import { useState, useCallback, useRef, useEffect } from 'react';\r\n\r\nexport interface DragPoint {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport interface DragState {\r\n /** Whether drag is currently active */\r\n isDragging: boolean;\r\n /** Initial position when drag started */\r\n startPosition: DragPoint | null;\r\n /** Current drag offset from start */\r\n offset: DragPoint;\r\n /** ID of the item being dragged */\r\n draggedId: string | null;\r\n}\r\n\r\nexport interface UseDragOptions {\r\n /** Callback when drag starts */\r\n onDragStart?: (id: string, position: DragPoint) => void;\r\n /** Callback during drag movement */\r\n onDragMove?: (id: string, offset: DragPoint, position: DragPoint) => void;\r\n /** Callback when drag ends */\r\n onDragEnd?: (id: string, offset: DragPoint, finalPosition: DragPoint) => void;\r\n /** Snap to grid size (0 = no snap) */\r\n snapToGrid?: number;\r\n /** Minimum drag distance before triggering (prevents accidental drags) */\r\n dragThreshold?: number;\r\n /** Convert screen coordinates to world coordinates */\r\n screenToWorld?: (screenX: number, screenY: number) => DragPoint;\r\n}\r\n\r\nexport interface UseDragResult {\r\n /** Current drag state */\r\n dragState: DragState;\r\n /** Start dragging an item */\r\n startDrag: (id: string, event: React.MouseEvent | React.TouchEvent, itemPosition: DragPoint) => void;\r\n /** Cancel current drag */\r\n cancelDrag: () => void;\r\n /** Check if a specific item is being dragged */\r\n isDraggingItem: (id: string) => boolean;\r\n}\r\n\r\n/**\r\n * Custom hook for drag-and-drop functionality in P&ID diagrams\r\n * \r\n * Supports:\r\n * - Mouse drag\r\n * - Touch drag\r\n * - Snap-to-grid\r\n * - World coordinate conversion (for SVG viewBox)\r\n * - Drag threshold to prevent accidental drags\r\n */\r\nexport function useDrag(options: UseDragOptions = {}): UseDragResult {\r\n const {\r\n onDragStart,\r\n onDragMove,\r\n onDragEnd,\r\n snapToGrid = 0,\r\n dragThreshold = 3,\r\n screenToWorld = (x, y) => ({ x, y }),\r\n } = options;\r\n\r\n const [dragState, setDragState] = useState<DragState>({\r\n isDragging: false,\r\n startPosition: null,\r\n offset: { x: 0, y: 0 },\r\n draggedId: null,\r\n });\r\n\r\n const [isListening, setIsListening] = useState(false);\r\n const dragStartRef = useRef<{ id: string; screenStart: DragPoint; worldStart: DragPoint; itemPosition: DragPoint; clickOffset: DragPoint } | null>(null);\r\n const hasMovedRef = useRef(false);\r\n\r\n const applySnap = useCallback(\r\n (value: number): number => {\r\n if (snapToGrid <= 0) return value;\r\n return Math.round(value / snapToGrid) * snapToGrid;\r\n },\r\n [snapToGrid]\r\n );\r\n\r\n const handleMouseMove = useCallback(\r\n (event: MouseEvent) => {\r\n if (!dragStartRef.current) return;\r\n\r\n const { id, screenStart: _screenStart, itemPosition, clickOffset } = dragStartRef.current;\r\n const currentWorld = screenToWorld(event.clientX, event.clientY);\r\n\r\n // New position = current cursor - click offset\r\n const newX = currentWorld.x - clickOffset.x;\r\n const newY = currentWorld.y - clickOffset.y;\r\n\r\n const rawOffset = {\r\n x: newX - itemPosition.x,\r\n y: newY - itemPosition.y,\r\n };\r\n\r\n // Check if we've exceeded the drag threshold\r\n const distance = Math.sqrt(rawOffset.x ** 2 + rawOffset.y ** 2);\r\n if (!hasMovedRef.current && distance < dragThreshold) {\r\n return;\r\n }\r\n\r\n if (!hasMovedRef.current) {\r\n hasMovedRef.current = true;\r\n setDragState({\r\n isDragging: true,\r\n startPosition: itemPosition,\r\n offset: { x: 0, y: 0 },\r\n draggedId: id,\r\n });\r\n onDragStart?.(id, itemPosition);\r\n }\r\n\r\n const snappedOffset = {\r\n x: applySnap(rawOffset.x),\r\n y: applySnap(rawOffset.y),\r\n };\r\n\r\n const newPosition = {\r\n x: applySnap(itemPosition.x + rawOffset.x),\r\n y: applySnap(itemPosition.y + rawOffset.y),\r\n };\r\n\r\n setDragState((prev) => ({\r\n ...prev,\r\n offset: snappedOffset,\r\n }));\r\n\r\n onDragMove?.(id, snappedOffset, newPosition);\r\n },\r\n [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]\r\n );\r\n\r\n const handleMouseUp = useCallback(\r\n (event: MouseEvent) => {\r\n if (!dragStartRef.current || !hasMovedRef.current) {\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n return;\r\n }\r\n\r\n const { id, itemPosition, clickOffset } = dragStartRef.current;\r\n const currentWorld = screenToWorld(event.clientX, event.clientY);\r\n\r\n const newX = currentWorld.x - clickOffset.x;\r\n const newY = currentWorld.y - clickOffset.y;\r\n\r\n const rawOffset = {\r\n x: newX - itemPosition.x,\r\n y: newY - itemPosition.y,\r\n };\r\n\r\n const snappedOffset = {\r\n x: applySnap(rawOffset.x),\r\n y: applySnap(rawOffset.y),\r\n };\r\n\r\n const finalPosition = {\r\n x: applySnap(itemPosition.x + rawOffset.x),\r\n y: applySnap(itemPosition.y + rawOffset.y),\r\n };\r\n\r\n onDragEnd?.(id, snappedOffset, finalPosition);\r\n\r\n setDragState({\r\n isDragging: false,\r\n startPosition: null,\r\n offset: { x: 0, y: 0 },\r\n draggedId: null,\r\n });\r\n\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n },\r\n [screenToWorld, applySnap, onDragEnd]\r\n );\r\n\r\n const handleTouchMove = useCallback(\r\n (event: TouchEvent) => {\r\n if (!dragStartRef.current || event.touches.length !== 1) return;\r\n\r\n const touch = event.touches[0];\r\n const { id, screenStart: _screenStart2, itemPosition, clickOffset } = dragStartRef.current;\r\n const currentWorld = screenToWorld(touch.clientX, touch.clientY);\r\n\r\n const newX = currentWorld.x - clickOffset.x;\r\n const newY = currentWorld.y - clickOffset.y;\r\n\r\n const rawOffset = {\r\n x: newX - itemPosition.x,\r\n y: newY - itemPosition.y,\r\n };\r\n\r\n const distance = Math.sqrt(rawOffset.x ** 2 + rawOffset.y ** 2);\r\n if (!hasMovedRef.current && distance < dragThreshold) {\r\n return;\r\n }\r\n\r\n event.preventDefault(); // Prevent scrolling\r\n\r\n if (!hasMovedRef.current) {\r\n hasMovedRef.current = true;\r\n setDragState({\r\n isDragging: true,\r\n startPosition: itemPosition,\r\n offset: { x: 0, y: 0 },\r\n draggedId: id,\r\n });\r\n onDragStart?.(id, itemPosition);\r\n }\r\n\r\n const snappedOffset = {\r\n x: applySnap(rawOffset.x),\r\n y: applySnap(rawOffset.y),\r\n };\r\n\r\n const newPosition = {\r\n x: applySnap(itemPosition.x + rawOffset.x),\r\n y: applySnap(itemPosition.y + rawOffset.y),\r\n };\r\n\r\n setDragState((prev) => ({\r\n ...prev,\r\n offset: snappedOffset,\r\n }));\r\n\r\n onDragMove?.(id, snappedOffset, newPosition);\r\n },\r\n [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]\r\n );\r\n\r\n const handleTouchEnd = useCallback(\r\n (event: TouchEvent) => {\r\n if (!dragStartRef.current || !hasMovedRef.current) {\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n return;\r\n }\r\n\r\n const { id, itemPosition, clickOffset } = dragStartRef.current;\r\n const touch = event.changedTouches[0];\r\n const currentWorld = screenToWorld(touch.clientX, touch.clientY);\r\n\r\n const newX = currentWorld.x - clickOffset.x;\r\n const newY = currentWorld.y - clickOffset.y;\r\n\r\n const rawOffset = {\r\n x: newX - itemPosition.x,\r\n y: newY - itemPosition.y,\r\n };\r\n\r\n const snappedOffset = {\r\n x: applySnap(rawOffset.x),\r\n y: applySnap(rawOffset.y),\r\n };\r\n\r\n const finalPosition = {\r\n x: applySnap(itemPosition.x + rawOffset.x),\r\n y: applySnap(itemPosition.y + rawOffset.y),\r\n };\r\n\r\n onDragEnd?.(id, snappedOffset, finalPosition);\r\n\r\n setDragState({\r\n isDragging: false,\r\n startPosition: null,\r\n offset: { x: 0, y: 0 },\r\n draggedId: null,\r\n });\r\n\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n },\r\n [screenToWorld, applySnap, onDragEnd]\r\n );\r\n\r\n useEffect(() => {\r\n // Only attach listeners when actively listening for drag events\r\n if (!isListening) return;\r\n\r\n document.addEventListener('mousemove', handleMouseMove);\r\n document.addEventListener('mouseup', handleMouseUp);\r\n document.addEventListener('touchmove', handleTouchMove, { passive: false });\r\n document.addEventListener('touchend', handleTouchEnd);\r\n document.addEventListener('touchcancel', handleTouchEnd);\r\n\r\n return () => {\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n document.removeEventListener('mouseup', handleMouseUp);\r\n document.removeEventListener('touchmove', handleTouchMove);\r\n document.removeEventListener('touchend', handleTouchEnd);\r\n document.removeEventListener('touchcancel', handleTouchEnd);\r\n };\r\n }, [isListening, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);\r\n\r\n const startDrag = useCallback(\r\n (id: string, event: React.MouseEvent | React.TouchEvent, itemPosition: DragPoint) => {\r\n event.stopPropagation();\r\n\r\n let clientX: number;\r\n let clientY: number;\r\n\r\n if ('touches' in event) {\r\n if (event.touches.length !== 1) return;\r\n clientX = event.touches[0].clientX;\r\n clientY = event.touches[0].clientY;\r\n } else {\r\n clientX = event.clientX;\r\n clientY = event.clientY;\r\n }\r\n\r\n const worldStart = screenToWorld(clientX, clientY);\r\n \r\n // Calculate offset from click position to item position\r\n const clickOffset = {\r\n x: worldStart.x - itemPosition.x,\r\n y: worldStart.y - itemPosition.y,\r\n };\r\n\r\n dragStartRef.current = {\r\n id,\r\n screenStart: { x: clientX, y: clientY },\r\n worldStart,\r\n itemPosition,\r\n clickOffset,\r\n };\r\n hasMovedRef.current = false;\r\n setIsListening(true); // Start listening for move/up events\r\n },\r\n [screenToWorld]\r\n );\r\n\r\n const cancelDrag = useCallback(() => {\r\n dragStartRef.current = null;\r\n hasMovedRef.current = false;\r\n setIsListening(false);\r\n setDragState({\r\n isDragging: false,\r\n startPosition: null,\r\n offset: { x: 0, y: 0 },\r\n draggedId: null,\r\n });\r\n }, []);\r\n\r\n const isDraggingItem = useCallback(\r\n (id: string) => dragState.isDragging && dragState.draggedId === id,\r\n [dragState.isDragging, dragState.draggedId]\r\n );\r\n\r\n return {\r\n dragState,\r\n startDrag,\r\n cancelDrag,\r\n isDraggingItem,\r\n };\r\n}\r\n","import { useEffect } from 'react';\r\n\r\nexport interface KeyboardShortcutsOptions {\r\n /** Callback when Delete or Backspace is pressed */\r\n onDelete?: () => void;\r\n /** Callback when Ctrl+C is pressed */\r\n onCopy?: () => void;\r\n /** Callback when Ctrl+V is pressed */\r\n onPaste?: () => void;\r\n /** Callback when Ctrl+Z is pressed (undo) */\r\n onUndo?: () => void;\r\n /** Callback when Ctrl+Y or Ctrl+Shift+Z is pressed (redo) */\r\n onRedo?: () => void;\r\n /** Callback when Ctrl+A is pressed (select all) */\r\n onSelectAll?: () => void;\r\n /** Enable keyboard shortcuts (default: true) */\r\n enabled?: boolean;\r\n}\r\n\r\n/**\r\n * Custom hook for handling keyboard shortcuts in P&ID diagrams\r\n * \r\n * Supported shortcuts:\r\n * - Delete/Backspace: Delete selected items\r\n * - Ctrl+C: Copy selected items\r\n * - Ctrl+V: Paste copied items\r\n * - Ctrl+Z: Undo last action\r\n * - Ctrl+Y / Ctrl+Shift+Z: Redo\r\n * - Ctrl+A: Select all\r\n */\r\nexport function useKeyboardShortcuts(options: KeyboardShortcutsOptions): void {\r\n const {\r\n onDelete,\r\n onCopy,\r\n onPaste,\r\n onUndo,\r\n onRedo,\r\n onSelectAll,\r\n enabled = true,\r\n } = options;\r\n\r\n useEffect(() => {\r\n if (!enabled) return;\r\n\r\n const handleKeyDown = (event: KeyboardEvent) => {\r\n // Ignore if user is typing in an input field\r\n const target = event.target as HTMLElement;\r\n if (\r\n target.tagName === 'INPUT' ||\r\n target.tagName === 'TEXTAREA' ||\r\n target.isContentEditable\r\n ) {\r\n return;\r\n }\r\n\r\n const isCtrl = event.ctrlKey || event.metaKey;\r\n const isShift = event.shiftKey;\r\n\r\n // Delete or Backspace\r\n if ((event.key === 'Delete' || event.key === 'Backspace') && !isCtrl) {\r\n event.preventDefault();\r\n onDelete?.();\r\n return;\r\n }\r\n\r\n // Ctrl+C - Copy\r\n if (isCtrl && event.key === 'c') {\r\n event.preventDefault();\r\n onCopy?.();\r\n return;\r\n }\r\n\r\n // Ctrl+V - Paste\r\n if (isCtrl && event.key === 'v') {\r\n event.preventDefault();\r\n onPaste?.();\r\n return;\r\n }\r\n\r\n // Ctrl+Z - Undo\r\n if (isCtrl && event.key === 'z' && !isShift) {\r\n event.preventDefault();\r\n onUndo?.();\r\n return;\r\n }\r\n\r\n // Ctrl+Y or Ctrl+Shift+Z - Redo\r\n if (isCtrl && (event.key === 'y' || (event.key === 'z' && isShift))) {\r\n event.preventDefault();\r\n onRedo?.();\r\n return;\r\n }\r\n\r\n // Ctrl+A - Select all\r\n if (isCtrl && event.key === 'a') {\r\n event.preventDefault();\r\n onSelectAll?.();\r\n return;\r\n }\r\n };\r\n\r\n window.addEventListener('keydown', handleKeyDown);\r\n return () => window.removeEventListener('keydown', handleKeyDown);\r\n }, [enabled, onDelete, onCopy, onPaste, onUndo, onRedo, onSelectAll]);\r\n}\r\n","import type { NodeInstance, Point } from '../schema';\r\nimport { getSymbolDefinition } from '../symbols';\r\n\r\n/**\r\n * Calculate the world position of a port on a node instance\r\n * \r\n * Takes into account the node's transform (position, rotation, scale, flip)\r\n * and the port's position within the symbol's viewBox\r\n */\r\nexport function getPortWorldPosition(\r\n node: NodeInstance,\r\n portId: string\r\n): Point | null {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol) return null;\r\n\r\n const port = symbol.ports.find((p) => p.id === portId);\r\n if (!port) return null;\r\n\r\n const { x: nodeX, y: nodeY, rotation = 0, scale = 1, flipX = false, flipY = false } = node.transform;\r\n\r\n // Start with port position relative to symbol\r\n let portX = port.x;\r\n let portY = port.y;\r\n\r\n // Apply flip transforms (relative to symbol center)\r\n const centerX = symbol.viewBox.width / 2;\r\n const centerY = symbol.viewBox.height / 2;\r\n \r\n if (flipX) {\r\n portX = symbol.viewBox.width - portX;\r\n }\r\n if (flipY) {\r\n portY = symbol.viewBox.height - portY;\r\n }\r\n\r\n // Apply scale (relative to symbol center)\r\n portX = centerX + (portX - centerX) * scale;\r\n portY = centerY + (portY - centerY) * scale;\r\n\r\n // Apply rotation (relative to symbol center)\r\n if (rotation !== 0) {\r\n const rad = (rotation * Math.PI) / 180;\r\n const cos = Math.cos(rad);\r\n const sin = Math.sin(rad);\r\n \r\n const dx = portX - centerX;\r\n const dy = portY - centerY;\r\n \r\n portX = centerX + dx * cos - dy * sin;\r\n portY = centerY + dx * sin + dy * cos;\r\n }\r\n\r\n // Translate to world position\r\n return {\r\n x: nodeX + portX,\r\n y: nodeY + portY,\r\n };\r\n}\r\n\r\n/**\r\n * Generate route points for a pipe from source port to destination port\r\n * \r\n * Options:\r\n * - direct: Straight line from source to destination\r\n * - orthogonal: Right-angle routing (future enhancement)\r\n * - custom: Provide your own waypoints\r\n */\r\nexport function generateRoutePoints(\r\n fromNode: NodeInstance,\r\n fromPortId: string,\r\n toNode: NodeInstance,\r\n toPortId: string,\r\n options?: {\r\n style?: 'direct' | 'orthogonal';\r\n waypoints?: Point[];\r\n }\r\n): Point[] {\r\n const startPoint = getPortWorldPosition(fromNode, fromPortId);\r\n const endPoint = getPortWorldPosition(toNode, toPortId);\r\n\r\n if (!startPoint || !endPoint) {\r\n return [];\r\n }\r\n\r\n const style = options?.style || 'direct';\r\n\r\n if (style === 'direct') {\r\n // Straight line from start to end\r\n return [startPoint, endPoint];\r\n }\r\n\r\n if (style === 'orthogonal' && options?.waypoints) {\r\n // Start → waypoints → end\r\n return [startPoint, ...options.waypoints, endPoint];\r\n }\r\n\r\n if (style === 'orthogonal') {\r\n // Simple orthogonal routing: horizontal then vertical\r\n const midX = (startPoint.x + endPoint.x) / 2;\r\n return [\r\n startPoint,\r\n { x: midX, y: startPoint.y },\r\n { x: midX, y: endPoint.y },\r\n endPoint,\r\n ];\r\n }\r\n\r\n return [startPoint, endPoint];\r\n}\r\n\r\n/**\r\n * Validate that a node has a specific port\r\n */\r\nexport function nodeHasPort(node: NodeInstance, portId: string): boolean {\r\n const symbol = getSymbolDefinition(node.symbolId);\r\n if (!symbol) return false;\r\n return symbol.ports.some((p) => p.id === portId);\r\n}\r\n","import React, { useState } from 'react';\r\nimport { getAvailableSymbols, getSymbolDefinition } from '../../diagram/symbols';\r\nimport type { SymbolDefinition } from '../../diagram/schema';\r\n\r\nexport interface SymbolLibraryProps {\r\n /** Optional className for styling */\r\n className?: string;\r\n /** Callback when a symbol drag starts */\r\n onSymbolDragStart?: (symbolId: string, event: React.DragEvent) => void;\r\n /** Show category filter */\r\n showCategories?: boolean;\r\n /** Custom symbol categories */\r\n categories?: string[];\r\n}\r\n\r\n/**\r\n * SymbolLibrary - Browse and drag symbols onto the canvas\r\n *\r\n * Displays available symbols organized by category\r\n * Supports drag-and-drop to add new nodes to diagrams\r\n */\r\nexport function SymbolLibrary({\r\n className = '',\r\n onSymbolDragStart,\r\n showCategories = true,\r\n categories = ['Valves', 'Pumps', 'Tanks', 'Instruments', 'Displays'],\r\n}: SymbolLibraryProps): React.ReactElement {\r\n const [selectedCategory, setSelectedCategory] = useState<string>('all');\r\n const [searchQuery, setSearchQuery] = useState('');\r\n\r\n const symbolIds = getAvailableSymbols();\r\n const allSymbols: SymbolDefinition[] = symbolIds\r\n .map((id) => getSymbolDefinition(id))\r\n .filter((symbol): symbol is SymbolDefinition => symbol !== undefined);\r\n\r\n // Map display category names to actual category values\r\n const categoryMap: Record<string, string> = {\r\n Valves: 'valve',\r\n Pumps: 'pump',\r\n Tanks: 'vessel',\r\n Instruments: 'instrument',\r\n Displays: 'display',\r\n };\r\n\r\n // Filter symbols by category and search\r\n const filteredSymbols = allSymbols.filter((symbol) => {\r\n const actualCategory = categoryMap[selectedCategory] || selectedCategory;\r\n const matchesCategory = selectedCategory === 'all' || symbol.category === actualCategory;\r\n\r\n const matchesSearch =\r\n searchQuery === '' ||\r\n symbol.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\r\n symbol.id.toLowerCase().includes(searchQuery.toLowerCase());\r\n\r\n return matchesCategory && matchesSearch;\r\n });\r\n\r\n const handleDragStart = (symbol: SymbolDefinition, event: React.DragEvent) => {\r\n // Store symbol ID in drag data\r\n event.dataTransfer.setData('application/symbol-id', symbol.id);\r\n event.dataTransfer.effectAllowed = 'copy';\r\n onSymbolDragStart?.(symbol.id, event);\r\n };\r\n\r\n return (\r\n <div className={`symbol-library ${className}`.trim()} style={styles.container}>\r\n {/* Header */}\r\n <div style={styles.header}>\r\n <h3 style={styles.title}>Symbol Library</h3>\r\n </div>\r\n\r\n {/* Search */}\r\n <div style={styles.searchContainer}>\r\n <input\r\n type=\"text\"\r\n placeholder=\"Search symbols...\"\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n style={styles.searchInput}\r\n />\r\n </div>\r\n\r\n {/* Category Filter */}\r\n {showCategories && (\r\n <div style={styles.categories}>\r\n <button\r\n onClick={() => setSelectedCategory('all')}\r\n style={{\r\n ...styles.categoryButton,\r\n ...(selectedCategory === 'all' ? styles.categoryButtonActive : {}),\r\n }}\r\n >\r\n All\r\n </button>\r\n {categories.map((category) => (\r\n <button\r\n key={category}\r\n onClick={() => setSelectedCategory(category)}\r\n style={{\r\n ...styles.categoryButton,\r\n ...(selectedCategory === category ? styles.categoryButtonActive : {}),\r\n }}\r\n >\r\n {category}\r\n </button>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Symbol Grid */}\r\n <div style={styles.symbolGrid}>\r\n {filteredSymbols.length === 0 ? (\r\n <div style={styles.emptyState}>No symbols found</div>\r\n ) : (\r\n filteredSymbols.map((symbol) => (\r\n <div\r\n key={symbol.id}\r\n draggable\r\n onDragStart={(e) => handleDragStart(symbol, e)}\r\n style={styles.symbolCard}\r\n title={symbol.metadata?.description || symbol.name}\r\n >\r\n {/* Symbol Preview */}\r\n <div style={styles.symbolPreview}>\r\n <svg\r\n viewBox={`${symbol.viewBox.x} ${symbol.viewBox.y} ${symbol.viewBox.width} ${symbol.viewBox.height}`}\r\n style={styles.symbolSvg}\r\n >\r\n <g dangerouslySetInnerHTML={{ __html: symbol.svgContent }} />\r\n </svg>\r\n </div>\r\n\r\n {/* Symbol Name */}\r\n <div style={styles.symbolName}>{symbol.name}</div>\r\n </div>\r\n ))\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nconst styles: Record<string, React.CSSProperties> = {\r\n container: {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n height: '100%',\r\n backgroundColor: '#ffffff',\r\n border: '1px solid #e0e0e0',\r\n borderRadius: '8px',\r\n overflow: 'hidden',\r\n },\r\n header: {\r\n padding: '16px',\r\n borderBottom: '1px solid #e0e0e0',\r\n backgroundColor: '#f5f5f5',\r\n },\r\n title: {\r\n margin: 0,\r\n fontSize: '16px',\r\n fontWeight: 600,\r\n color: '#263238',\r\n },\r\n searchContainer: {\r\n padding: '12px 16px',\r\n borderBottom: '1px solid #e0e0e0',\r\n },\r\n searchInput: {\r\n width: '100%',\r\n padding: '8px 12px',\r\n border: '1px solid #e0e0e0',\r\n borderRadius: '4px',\r\n fontSize: '14px',\r\n outline: 'none',\r\n },\r\n categories: {\r\n display: 'flex',\r\n gap: '8px',\r\n padding: '12px 16px',\r\n borderBottom: '1px solid #e0e0e0',\r\n flexWrap: 'wrap',\r\n },\r\n categoryButton: {\r\n padding: '6px 12px',\r\n border: '1px solid #e0e0e0',\r\n borderRadius: '4px',\r\n backgroundColor: '#ffffff',\r\n fontSize: '13px',\r\n cursor: 'pointer',\r\n transition: 'all 0.2s',\r\n },\r\n categoryButtonActive: {\r\n backgroundColor: '#3b82f6',\r\n color: '#ffffff',\r\n borderColor: '#3b82f6',\r\n },\r\n symbolGrid: {\r\n flex: 1,\r\n padding: '16px',\r\n display: 'grid',\r\n gridTemplateColumns: 'repeat(auto-fill, minmax(100px, 1fr))',\r\n gap: '12px',\r\n overflowY: 'auto',\r\n alignContent: 'start',\r\n },\r\n emptyState: {\r\n gridColumn: '1 / -1',\r\n textAlign: 'center',\r\n padding: '32px',\r\n color: '#999',\r\n },\r\n symbolCard: {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n padding: '12px',\r\n border: '1px solid #e0e0e0',\r\n borderRadius: '6px',\r\n backgroundColor: '#ffffff',\r\n cursor: 'grab',\r\n transition: 'all 0.2s',\r\n },\r\n symbolPreview: {\r\n width: '60px',\r\n height: '60px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n marginBottom: '8px',\r\n },\r\n symbolSvg: {\r\n maxWidth: '100%',\r\n maxHeight: '100%',\r\n },\r\n symbolName: {\r\n fontSize: '12px',\r\n color: '#263238',\r\n textAlign: 'center',\r\n wordBreak: 'break-word',\r\n lineHeight: '1.3',\r\n },\r\n};\r\n","import React from 'react';\r\nimport type { NodeInstance } from '../../diagram/schema';\r\nimport type { TelemetryBinding } from '../../diagram/hooks/useTelemetry';\r\n\r\nexport interface NodeConfigPanelProps {\r\n /** Selected node to configure */\r\n node: NodeInstance;\r\n /** Telemetry binding for the node (if any) */\r\n binding: TelemetryBinding | null;\r\n /** Callback when node properties are updated */\r\n onUpdateNode: (updates: Partial<NodeInstance>) => void;\r\n /** Callback when telemetry is added/updated */\r\n onUpdateTelemetry: (updates: any) => void;\r\n /** Callback when telemetry binding is added for the first time */\r\n onAddTelemetry?: () => void;\r\n /** Callback when node is removed */\r\n onRemove: () => void;\r\n /** Additional CSS class name */\r\n className?: string;\r\n /** Custom styles */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * NodeConfigPanel - Reusable configuration panel for editing node properties and telemetry\r\n *\r\n * @example\r\n * ```tsx\r\n * <NodeConfigPanel\r\n * node={selectedNode}\r\n * binding={telemetry.get(selectedNode.id)}\r\n * onUpdateNode={(updates) => updateNode(selectedNode.id, updates)}\r\n * onUpdateTelemetry={(updates) => updateTelemetryBatch([updates])}\r\n * onRemove={() => removeNode(selectedNode.id)}\r\n * />\r\n * ```\r\n */\r\nexport function NodeConfigPanel({\r\n node,\r\n binding,\r\n onUpdateNode,\r\n onUpdateTelemetry,\r\n onAddTelemetry,\r\n onRemove,\r\n className = '',\r\n style = {},\r\n}: NodeConfigPanelProps) {\r\n const defaultStyle: React.CSSProperties = {\r\n width: '320px',\r\n backgroundColor: '#f8fafc',\r\n borderLeft: '1px solid #e2e8f0',\r\n overflow: 'auto',\r\n padding: '20px',\r\n ...style,\r\n };\r\n\r\n return (\r\n <div className={className} style={defaultStyle}>\r\n <h2 style={{ margin: '0 0 16px 0', fontSize: '1rem', fontWeight: 600 }}>\r\n Configure: {node.id}\r\n </h2>\r\n\r\n {/* Node Settings */}\r\n <div style={{ marginBottom: '20px' }}>\r\n <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '8px' }}>\r\n Node Settings\r\n </h3>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>Label:</label>\r\n <input\r\n type=\"text\"\r\n value={node.label || node.id}\r\n onChange={(e) => onUpdateNode({ label: e.target.value })}\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n marginBottom: '8px',\r\n }}\r\n />\r\n\r\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px' }}>\r\n <div>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Label Offset X:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={node.labelOffset?.x ?? 0}\r\n onChange={(e) =>\r\n onUpdateNode({\r\n labelOffset: {\r\n x: parseFloat(e.target.value) || 0,\r\n y: node.labelOffset?.y ?? 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n <div>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Label Offset Y:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={node.labelOffset?.y ?? 0}\r\n onChange={(e) =>\r\n onUpdateNode({\r\n labelOffset: {\r\n x: node.labelOffset?.x ?? 0,\r\n y: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n\r\n <div>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Label Font Size:\r\n </label>\r\n <input\r\n type=\"number\"\r\n min=\"6\"\r\n max=\"24\"\r\n value={node.labelFontSize ?? 10}\r\n onChange={(e) =>\r\n onUpdateNode({\r\n labelFontSize: parseFloat(e.target.value) || 10,\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n\r\n <div>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Rotation (degrees):\r\n </label>\r\n <input\r\n type=\"number\"\r\n min=\"0\"\r\n max=\"360\"\r\n step=\"15\"\r\n value={node.transform.rotation ?? 0}\r\n onChange={(e) =>\r\n onUpdateNode({\r\n transform: {\r\n ...node.transform,\r\n rotation: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n\r\n {/* Telemetry Configuration */}\r\n <div style={{ marginBottom: '20px' }}>\r\n <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '8px' }}>\r\n Telemetry Data\r\n </h3>\r\n\r\n {!binding ? (\r\n <button\r\n onClick={() => {\r\n if (onAddTelemetry) {\r\n onAddTelemetry();\r\n } else {\r\n // Default telemetry initialization\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: node.id,\r\n value: {\r\n value: 50,\r\n status: 'normal',\r\n unit: 'PSI',\r\n timestamp: Date.now(),\r\n },\r\n history: [45, 47, 48, 50, 52, 51, 49, 50],\r\n display: {\r\n showValue: true,\r\n showSparkline: false,\r\n precision: 1,\r\n backgroundColor: 'status',\r\n },\r\n thresholds: {\r\n highHigh: 85,\r\n high: 70,\r\n low: 30,\r\n lowLow: 15,\r\n },\r\n });\r\n }\r\n }}\r\n style={{\r\n padding: '8px 16px',\r\n backgroundColor: '#3b82f6',\r\n color: '#fff',\r\n border: 'none',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n width: '100%',\r\n }}\r\n >\r\n + Add Telemetry\r\n </button>\r\n ) : (\r\n <>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Initial Value:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={binding.value.value as number}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n value: {\r\n ...binding.value,\r\n value: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n marginBottom: '8px',\r\n }}\r\n />\r\n\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n Unit:\r\n </label>\r\n <input\r\n type=\"text\"\r\n value={binding.value.unit || ''}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n value: {\r\n ...binding.value,\r\n unit: e.target.value,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n marginBottom: '8px',\r\n }}\r\n />\r\n\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n <input\r\n type=\"checkbox\"\r\n checked={binding.display?.showSparkline ?? false}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n showSparkline: e.target.checked,\r\n },\r\n })\r\n }\r\n style={{ marginRight: '6px' }}\r\n />\r\n Show Sparkline\r\n </label>\r\n\r\n <div style={{ marginTop: '12px' }}>\r\n <label\r\n style={{\r\n fontSize: '0.75rem',\r\n fontWeight: 600,\r\n display: 'block',\r\n marginBottom: '8px',\r\n }}\r\n >\r\n Telemetry Position Offset:\r\n </label>\r\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px' }}>\r\n <div>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n X Offset:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={binding.display?.offsetX ?? 0}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n offsetX: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.75rem',\r\n }}\r\n />\r\n </div>\r\n <div>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n Y Offset:\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={binding.display?.offsetY ?? 0}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n offsetY: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.75rem',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n {/* Text & Sparkline Colors */}\r\n <div style={{ marginTop: '16px' }}>\r\n <label\r\n style={{\r\n fontSize: '0.75rem',\r\n fontWeight: 600,\r\n display: 'block',\r\n marginBottom: '8px',\r\n }}\r\n >\r\n Display Colors:\r\n </label>\r\n\r\n {/* Text Color */}\r\n <div style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n Text Color:\r\n </label>\r\n <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>\r\n <input\r\n type=\"color\"\r\n value={binding.display?.textColor ?? '#000000'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n textColor: e.target.value,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '40px',\r\n height: '28px',\r\n border: '1px solid #cbd5e1',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n }}\r\n />\r\n <input\r\n type=\"text\"\r\n value={binding.display?.textColor ?? '#000000'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n textColor: e.target.value,\r\n },\r\n })\r\n }\r\n placeholder=\"#000000\"\r\n style={{\r\n flex: 1,\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.7rem',\r\n fontFamily: 'monospace',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n\r\n {/* Sparkline Color */}\r\n {binding.display?.showSparkline && (\r\n <div style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n Sparkline Color:\r\n </label>\r\n <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>\r\n <input\r\n type=\"color\"\r\n value={binding.display?.sparklineColor ?? '#3b82f6'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n sparklineColor: e.target.value,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '40px',\r\n height: '28px',\r\n border: '1px solid #cbd5e1',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n }}\r\n />\r\n <input\r\n type=\"text\"\r\n value={binding.display?.sparklineColor ?? '#3b82f6'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n sparklineColor: e.target.value,\r\n },\r\n })\r\n }\r\n placeholder=\"#3b82f6\"\r\n style={{\r\n flex: 1,\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.7rem',\r\n fontFamily: 'monospace',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Background Color */}\r\n <div style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.7rem', display: 'block', marginBottom: '4px' }}>\r\n Background:\r\n </label>\r\n <input\r\n type=\"text\"\r\n value={binding.display?.backgroundColor ?? 'status'}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n tag: binding.tag,\r\n value: binding.value,\r\n history: binding.history,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n display: {\r\n ...binding.display,\r\n backgroundColor: e.target.value,\r\n },\r\n })\r\n }\r\n placeholder=\"status or #ffffff\"\r\n style={{\r\n width: '100%',\r\n padding: '4px 6px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.7rem',\r\n fontFamily: 'monospace',\r\n }}\r\n />\r\n <div style={{ fontSize: '0.65rem', color: '#6b7280', marginTop: '2px' }}>\r\n Use 'status' for status-based color or hex code\r\n </div>\r\n </div>\r\n </div>{' '}\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n\r\n {/* Thresholds (if telemetry exists) */}\r\n {binding && (\r\n <div style={{ marginBottom: '20px' }}>\r\n <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '8px' }}>Thresholds</h3>\r\n\r\n {(['highHigh', 'high', 'low', 'lowLow'] as const).map((key) => {\r\n const label =\r\n key === 'highHigh'\r\n ? 'High-High (≥)'\r\n : key === 'high'\r\n ? 'High (≥)'\r\n : key === 'low'\r\n ? 'Low (≤)'\r\n : 'Low-Low (≤)';\r\n return (\r\n <div key={key} style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n {label}\r\n </label>\r\n <input\r\n type=\"number\"\r\n value={\r\n binding.thresholds?.[key] ??\r\n (key === 'highHigh' ? 85 : key === 'high' ? 70 : key === 'low' ? 30 : 15)\r\n }\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n thresholds: {\r\n ...binding.thresholds,\r\n [key]: parseFloat(e.target.value) || 0,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '100%',\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.875rem',\r\n }}\r\n />\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {/* Status Colors (if telemetry exists) */}\r\n {binding && (\r\n <div style={{ marginBottom: '20px' }}>\r\n <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '8px' }}>\r\n Status Colors\r\n </h3>\r\n\r\n {(['normal', 'warning', 'alarm', 'fault', 'off'] as const).map((status) => {\r\n const defaultColors = {\r\n normal: '#10b981',\r\n warning: '#f59e0b',\r\n alarm: '#ef4444',\r\n fault: '#8b5cf6',\r\n off: '#6b7280',\r\n };\r\n const label =\r\n status === 'normal'\r\n ? 'Normal'\r\n : status === 'warning'\r\n ? 'Warning'\r\n : status === 'alarm'\r\n ? 'Alarm'\r\n : status === 'fault'\r\n ? 'Fault'\r\n : 'Off';\r\n return (\r\n <div key={status} style={{ marginBottom: '8px' }}>\r\n <label style={{ fontSize: '0.75rem', display: 'block', marginBottom: '4px' }}>\r\n {label}:\r\n </label>\r\n <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>\r\n <input\r\n type=\"color\"\r\n value={binding.statusColors?.[status] ?? defaultColors[status]}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n statusColors: {\r\n ...binding.statusColors,\r\n [status]: e.target.value,\r\n },\r\n })\r\n }\r\n style={{\r\n width: '50px',\r\n height: '32px',\r\n border: '1px solid #cbd5e1',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n }}\r\n />\r\n <input\r\n type=\"text\"\r\n value={binding.statusColors?.[status] ?? defaultColors[status]}\r\n onChange={(e) =>\r\n onUpdateTelemetry({\r\n nodeId: node.id,\r\n statusColors: {\r\n ...binding.statusColors,\r\n [status]: e.target.value,\r\n },\r\n })\r\n }\r\n placeholder={defaultColors[status]}\r\n style={{\r\n flex: 1,\r\n padding: '6px 8px',\r\n borderRadius: '4px',\r\n border: '1px solid #cbd5e1',\r\n fontSize: '0.75rem',\r\n fontFamily: 'monospace',\r\n }}\r\n />\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {/* Remove Node */}\r\n <div style={{ marginTop: '20px', paddingTop: '20px', borderTop: '1px solid #cbd5e1' }}>\r\n <button\r\n onClick={onRemove}\r\n style={{\r\n padding: '8px 16px',\r\n backgroundColor: '#ef4444',\r\n color: '#fff',\r\n border: 'none',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n width: '100%',\r\n }}\r\n >\r\n Remove Node\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { Diagram } from '../schema';\r\n\r\n/**\r\n * Validates a diagram object structure\r\n */\r\nexport function validateDiagram(diagram: unknown): { valid: boolean; errors: string[] } {\r\n const errors: string[] = [];\r\n\r\n if (!diagram || typeof diagram !== 'object') {\r\n errors.push('Diagram must be an object');\r\n return { valid: false, errors };\r\n }\r\n\r\n const d = diagram as Partial<Diagram>;\r\n\r\n // Required fields\r\n if (!d.id || typeof d.id !== 'string') {\r\n errors.push('Diagram must have a valid id (string)');\r\n }\r\n if (!d.name || typeof d.name !== 'string') {\r\n errors.push('Diagram must have a valid name (string)');\r\n }\r\n if (!d.version || typeof d.version !== 'string') {\r\n errors.push('Diagram must have a valid version (string)');\r\n }\r\n\r\n // ViewBox validation\r\n if (!d.viewBox) {\r\n errors.push('Diagram must have a viewBox');\r\n } else if (\r\n typeof d.viewBox.x !== 'number' ||\r\n typeof d.viewBox.y !== 'number' ||\r\n typeof d.viewBox.width !== 'number' ||\r\n typeof d.viewBox.height !== 'number'\r\n ) {\r\n errors.push('ViewBox must have numeric x, y, width, height properties');\r\n }\r\n\r\n // Array validations\r\n if (!Array.isArray(d.nodes)) {\r\n errors.push('Diagram.nodes must be an array');\r\n }\r\n if (!Array.isArray(d.pipes)) {\r\n errors.push('Diagram.pipes must be an array');\r\n }\r\n if (!Array.isArray(d.overlays)) {\r\n errors.push('Diagram.overlays must be an array');\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Serializes a diagram to JSON string\r\n */\r\nexport function exportDiagram(diagram: Diagram): string {\r\n return JSON.stringify(diagram, null, 2);\r\n}\r\n\r\n/**\r\n * Parses a diagram from JSON string\r\n */\r\nexport function importDiagram(json: string): Diagram {\r\n try {\r\n const parsed = JSON.parse(json);\r\n const validation = validateDiagram(parsed);\r\n\r\n if (!validation.valid) {\r\n throw new Error(`Invalid diagram: ${validation.errors.join(', ')}`);\r\n }\r\n\r\n return parsed as Diagram;\r\n } catch (error) {\r\n if (error instanceof SyntaxError) {\r\n throw new Error(`Invalid JSON: ${error.message}`);\r\n }\r\n throw error;\r\n }\r\n}\r\n","import type { Diagram } from '../schema';\r\nimport { generateRoutePoints } from '../utils/portCalculations';\r\n\r\n// Define nodes first so we can calculate pipe routes\r\nconst nodes = [\r\n {\r\n id: 'V-101',\r\n symbolId: 'valve-ball',\r\n transform: {\r\n x: 100,\r\n y: 150,\r\n rotation: 0,\r\n },\r\n ports: [\r\n { id: 'inlet', x: -25, y: 0, type: 'inlet' as const },\r\n { id: 'outlet', x: 25, y: 0, type: 'outlet' as const },\r\n ],\r\n },\r\n {\r\n id: 'P-101',\r\n symbolId: 'pump-centrifugal',\r\n transform: {\r\n x: 250,\r\n y: 150,\r\n rotation: 0,\r\n },\r\n ports: [\r\n { id: 'inlet', x: -40, y: 0, type: 'inlet' as const },\r\n { id: 'outlet', x: 40, y: 0, type: 'outlet' as const },\r\n ],\r\n },\r\n {\r\n id: 'T-101',\r\n symbolId: 'vessel-tank',\r\n transform: {\r\n x: 450,\r\n y: 120,\r\n rotation: 0,\r\n },\r\n ports: [\r\n { id: 'inlet', x: 0, y: -40, type: 'inlet' as const },\r\n { id: 'outlet', x: 0, y: 40, type: 'outlet' as const },\r\n ],\r\n },\r\n];\r\n\r\n/**\r\n * Example P&ID diagram with a simple valve-pump-tank flow\r\n * Uses automatic port-to-port connection routing\r\n */\r\nexport const exampleDiagram: Diagram = {\r\n id: 'example-001',\r\n name: 'Simple Process Flow',\r\n version: '1.0.0',\r\n viewBox: {\r\n x: -100,\r\n y: -50,\r\n width: 1200,\r\n height: 600,\r\n },\r\n nodes,\r\n pipes: [\r\n {\r\n id: 'pipe-001',\r\n fromNodeId: 'V-101',\r\n fromPortId: 'outlet',\r\n toNodeId: 'P-101',\r\n toPortId: 'inlet',\r\n routePoints: generateRoutePoints(nodes[0], 'outlet', nodes[1], 'inlet'),\r\n style: {\r\n stroke: '#0277bd',\r\n strokeWidth: 4,\r\n },\r\n },\r\n {\r\n id: 'pipe-002',\r\n fromNodeId: 'P-101',\r\n fromPortId: 'outlet',\r\n toNodeId: 'T-101',\r\n toPortId: 'inlet',\r\n routePoints: generateRoutePoints(nodes[1], 'outlet', nodes[2], 'inlet', {\r\n style: 'orthogonal',\r\n }),\r\n style: {\r\n stroke: '#2e7d32',\r\n strokeWidth: 4,\r\n },\r\n },\r\n ],\r\n overlays: [\r\n {\r\n id: 'overlay-v101',\r\n type: 'value',\r\n anchorType: 'node',\r\n anchorId: 'V-101',\r\n offset: { x: 0, y: -40 },\r\n binding: {\r\n sourceType: 'tag',\r\n source: 'V101.position',\r\n format: '0.0%',\r\n },\r\n content: {\r\n text: 'Valve Position',\r\n },\r\n },\r\n {\r\n id: 'overlay-p101',\r\n type: 'value',\r\n anchorType: 'node',\r\n anchorId: 'P-101',\r\n offset: { x: 0, y: -50 },\r\n binding: {\r\n sourceType: 'tag',\r\n source: 'P101.flow',\r\n format: '0.0 LPM',\r\n },\r\n content: {\r\n text: 'Flow Rate',\r\n },\r\n },\r\n {\r\n id: 'overlay-t101',\r\n type: 'gauge',\r\n anchorType: 'node',\r\n anchorId: 'T-101',\r\n offset: { x: 60, y: 0 },\r\n binding: {\r\n sourceType: 'tag',\r\n source: 'T101.level',\r\n },\r\n content: {\r\n component: 'CircularGauge',\r\n props: {\r\n max: 100,\r\n unit: '%',\r\n label: 'Level',\r\n },\r\n },\r\n },\r\n ],\r\n metadata: {\r\n author: 'System',\r\n created: '2025-12-31T00:00:00Z',\r\n description: 'Example P&ID diagram demonstrating schema structure',\r\n tags: ['example', 'tutorial'],\r\n },\r\n};\r\n","/**\r\n * Telemetry status type\r\n */\r\nexport type TelemetryStatus = 'normal' | 'warning' | 'alarm' | 'fault' | 'off';\r\n\r\n/**\r\n * Threshold configuration\r\n */\r\nexport interface Thresholds {\r\n highHigh?: number;\r\n high?: number;\r\n low?: number;\r\n lowLow?: number;\r\n}\r\n\r\n/**\r\n * Calculate status based on value and thresholds\r\n * @param value - Current numeric value\r\n * @param thresholds - Threshold configuration\r\n * @returns Status string\r\n */\r\nexport function calculateThresholdStatus(\r\n value: number,\r\n thresholds?: Thresholds\r\n): TelemetryStatus {\r\n if (!thresholds) return 'normal';\r\n\r\n const { highHigh, high, low, lowLow } = thresholds;\r\n\r\n // Check high-high alarm (highest priority)\r\n if (highHigh !== undefined && value >= highHigh) {\r\n return 'alarm';\r\n }\r\n\r\n // Check low-low fault\r\n if (lowLow !== undefined && value <= lowLow) {\r\n return 'fault';\r\n }\r\n\r\n // Check high warning\r\n if (high !== undefined && value >= high) {\r\n return 'warning';\r\n }\r\n\r\n // Check low warning\r\n if (low !== undefined && value <= low) {\r\n return 'warning';\r\n }\r\n\r\n return 'normal';\r\n}\r\n\r\n/**\r\n * Default thresholds for typical industrial processes (percentage-based)\r\n */\r\nexport const DEFAULT_THRESHOLDS: Thresholds = {\r\n highHigh: 85,\r\n high: 70,\r\n low: 30,\r\n lowLow: 15,\r\n};\r\n","import { useEffect } from 'react';\r\nimport { calculateThresholdStatus } from '../../utils/thresholds';\r\nimport type { TelemetryMap, TelemetryBinding } from './useTelemetry';\r\n\r\n/**\r\n * Options for simulation behavior\r\n */\r\nexport interface SimulationOptions {\r\n /** Update interval in milliseconds (default: 2000) */\r\n interval?: number;\r\n /** Whether simulation is enabled (default: true) */\r\n enabled?: boolean;\r\n /** Maximum change per update (default: 10) */\r\n maxChange?: number;\r\n /** Minimum value clamp (default: 0) */\r\n minValue?: number;\r\n /** Maximum value clamp (default: 100) */\r\n maxValue?: number;\r\n /** Maximum history length (default: 10) */\r\n historyLength?: number;\r\n /** Custom value generator function */\r\n generateValue?: (currentValue: number, nodeId: string) => number;\r\n}\r\n\r\n/**\r\n * Hook to automatically simulate telemetry data updates\r\n * Randomly updates numeric telemetry values and calculates status based on thresholds\r\n * \r\n * @param telemetry - Telemetry map from useTelemetry\r\n * @param updateTelemetryBatch - Batch update function from useTelemetry\r\n * @param options - Simulation configuration options\r\n * \r\n * @example\r\n * ```tsx\r\n * const { telemetry, updateTelemetryBatch } = useTelemetry();\r\n * useSimulation(telemetry, updateTelemetryBatch, {\r\n * interval: 2000,\r\n * enabled: mode === 'runtime'\r\n * });\r\n * ```\r\n */\r\nexport function useSimulation(\r\n telemetry: TelemetryMap,\r\n updateTelemetryBatch: (updates: Array<any>) => void,\r\n options: SimulationOptions = {}\r\n) {\r\n const {\r\n interval = 2000,\r\n enabled = true,\r\n maxChange = 10,\r\n minValue = 0,\r\n maxValue = 100,\r\n historyLength = 10,\r\n generateValue,\r\n } = options;\r\n\r\n useEffect(() => {\r\n if (!enabled) return;\r\n\r\n const intervalId = setInterval(() => {\r\n const updates: Array<{\r\n nodeId: string;\r\n tag?: string;\r\n value?: any;\r\n history?: number[];\r\n display?: any;\r\n thresholds?: any;\r\n statusColors?: any;\r\n }> = [];\r\n\r\n telemetry.forEach((binding: TelemetryBinding, nodeId: string) => {\r\n // Only simulate numeric values\r\n if (typeof binding.value.value !== 'number') return;\r\n\r\n const currentValue = binding.value.value as number;\r\n\r\n // Generate new value\r\n let newValue: number;\r\n if (generateValue) {\r\n newValue = generateValue(currentValue, nodeId);\r\n } else {\r\n // Default random walk simulation\r\n const change = (Math.random() - 0.5) * maxChange;\r\n newValue = Math.max(minValue, Math.min(maxValue, currentValue + change));\r\n }\r\n\r\n // Calculate status based on thresholds\r\n const status = calculateThresholdStatus(newValue, binding.thresholds);\r\n\r\n // Update history\r\n const newHistory = [...(binding.history || []), newValue].slice(-historyLength);\r\n\r\n updates.push({\r\n nodeId,\r\n tag: binding.tag,\r\n value: {\r\n ...binding.value,\r\n value: newValue,\r\n status,\r\n timestamp: Date.now(),\r\n },\r\n history: newHistory,\r\n display: binding.display,\r\n thresholds: binding.thresholds,\r\n statusColors: binding.statusColors,\r\n });\r\n });\r\n\r\n if (updates.length > 0) {\r\n updateTelemetryBatch(updates);\r\n }\r\n }, interval);\r\n\r\n return () => clearInterval(intervalId);\r\n }, [\r\n enabled,\r\n interval,\r\n maxChange,\r\n minValue,\r\n maxValue,\r\n historyLength,\r\n generateValue,\r\n telemetry,\r\n updateTelemetryBatch,\r\n ]);\r\n}\r\n"],"mappings":"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","names":["useState","jsx","selectedOption","useState","jsx","jsxs","useState","useCallback","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","React","jsx","useEffect","useState","Box","styled","jsx","jsx","jsxs","Fragment","jsx","jsxs","React","useState","useEffect","jsx","jsx","jsxs","useCallback","useState","useEffect","useRef","jsx","jsxs","nodes","Fragment","jsx","jsxs","Fragment","jsx","jsxs","useState","useEffect","jsx","jsxs","useState","useCallback","useRef","useEffect","useState","useCallback","useState","useCallback","useEffect","useRef","useEffect","useState","useCallback","useRef","useEffect","useEffect","Fragment","jsx","jsxs","useState","useRef","useEffect","useCallback","nodes","useState","jsx","jsxs","useState","Fragment","jsx","jsxs","useEffect","useEffect"]}
|