@procaaso/alphinity-ui-components 1.0.0 → 1.0.1

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 CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,23 +17,58 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
23
33
  Button: () => Button,
34
+ CardHeader: () => CardHeader,
35
+ CardUnit: () => CardUnit,
36
+ CardValue: () => CardValue,
37
+ CircularGauge: () => CircularGauge,
24
38
  ControlPanel: () => ControlPanel,
39
+ DashboardCard: () => DashboardCard,
40
+ DisplayModeToggle: () => DisplayModeToggle,
41
+ EquipmentIndicator: () => EquipmentIndicator,
42
+ EquipmentIndicatorWithSparkline: () => EquipmentIndicatorWithSparkline,
43
+ FixedSVGContainer: () => FixedSVGContainer,
44
+ FooterPanel: () => FooterPanel,
45
+ FullscreenContainer: () => FullscreenContainer,
46
+ FullscreenWorkspace: () => FullscreenWorkspace,
47
+ LeftPanel: () => LeftPanel,
48
+ LeftToggleButton: () => LeftToggleButton,
49
+ LegacyValueEntry: () => LegacyValueEntry,
50
+ PanelContent: () => PanelContent,
51
+ PanelTabs: () => PanelTabs,
52
+ RightPanel: () => RightPanel,
53
+ RightToggleButton: () => RightToggleButton,
54
+ SVGArea: () => SVGArea,
55
+ SVGLockedOverlay: () => SVGLockedOverlay,
56
+ ScrollableSVGWrapper: () => ScrollableSVGWrapper,
25
57
  Selector: () => Selector,
58
+ Sparkline: () => Sparkline,
26
59
  StatusIndicator: () => StatusIndicator,
27
60
  ThemeProvider: () => ThemeProvider,
28
61
  ThemeToggle: () => ThemeToggle,
62
+ TrendLine: () => TrendLine,
29
63
  ValueEntry: () => ValueEntry,
64
+ ZoomButton: () => ZoomButton,
65
+ ZoomControls: () => ZoomControls,
66
+ overlayStyles: () => overlayStyles,
30
67
  useTheme: () => useTheme
31
68
  });
32
69
  module.exports = __toCommonJS(index_exports);
33
70
 
34
- // src/Button.tsx
71
+ // src/components/Button/Button.tsx
35
72
  var import_jsx_runtime = require("react/jsx-runtime");
36
73
  var Button = ({
37
74
  variant = "primary",
@@ -39,14 +76,163 @@ var Button = ({
39
76
  className = "",
40
77
  ...props
41
78
  }) => {
42
- const baseStyles = "h-20 min-w-[160px] px-12 py-5 rounded-3xl font-bold text-2xl transition-all duration-300 transform hover:scale-[1.03] active:scale-[0.97] focus:outline-none focus:ring-4 focus:ring-offset-3 focus:ring-offset-slate-900 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none shadow-2xl backdrop-blur-sm";
43
- const variantStyles = variant === "primary" ? "bg-gradient-to-br from-blue-400 via-blue-600 to-purple-700 hover:from-blue-500 hover:via-blue-700 hover:to-purple-800 text-white shadow-blue-600/40 focus:ring-blue-400/70 border border-blue-300/40 hover:shadow-2xl hover:shadow-blue-600/60 hover:border-blue-200/50" : "bg-gradient-to-br from-slate-500 via-slate-700 to-slate-900 hover:from-slate-400 hover:via-slate-600 hover:to-slate-800 text-slate-100 shadow-slate-600/40 focus:ring-slate-400/70 border border-slate-400/40 hover:shadow-2xl hover:shadow-slate-600/60 hover:border-slate-300/50";
44
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: `${baseStyles} ${variantStyles} ${className}`.trim(), ...props, children });
79
+ const baseClass = "ui-btn";
80
+ const variantClass = variant ? `ui-btn--${variant}` : "";
81
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: `${baseClass} ${variantClass} ${className}`.trim(), ...props, children });
45
82
  };
46
83
 
47
- // src/TestValueEntry.tsx
84
+ // src/components/ControlPanel/ControlPanel.tsx
85
+ var import_react4 = require("react");
86
+
87
+ // src/components/Selector/Selector.tsx
48
88
  var import_react = require("react");
49
89
  var import_jsx_runtime2 = require("react/jsx-runtime");
90
+ var Selector = ({
91
+ value,
92
+ onChange,
93
+ options,
94
+ placeholder = "Select option...",
95
+ disabled = false,
96
+ status = "normal",
97
+ size = "medium",
98
+ label,
99
+ dropdownUp: _dropdownUp = false,
100
+ className = "",
101
+ ...props
102
+ }) => {
103
+ const [isOpen, setIsOpen] = (0, import_react.useState)(false);
104
+ const [focusedIndex, setFocusedIndex] = (0, import_react.useState)(-1);
105
+ const selectorRef = (0, import_react.useRef)(null);
106
+ const dropdownRef = (0, import_react.useRef)(null);
107
+ (0, import_react.useEffect)(() => {
108
+ const handleClickOutside = (event) => {
109
+ if (selectorRef.current && !selectorRef.current.contains(event.target)) {
110
+ setIsOpen(false);
111
+ setFocusedIndex(-1);
112
+ }
113
+ };
114
+ document.addEventListener("mousedown", handleClickOutside);
115
+ return () => document.removeEventListener("mousedown", handleClickOutside);
116
+ }, []);
117
+ const handleKeyDown = (e) => {
118
+ if (disabled) return;
119
+ switch (e.key) {
120
+ case "Enter":
121
+ case " ":
122
+ e.preventDefault();
123
+ if (!isOpen) {
124
+ setIsOpen(true);
125
+ setFocusedIndex(
126
+ Math.max(
127
+ 0,
128
+ options.findIndex((opt) => opt.value === value)
129
+ )
130
+ );
131
+ } else if (focusedIndex >= 0) {
132
+ const selectedOption2 = options[focusedIndex];
133
+ if (!selectedOption2.disabled) {
134
+ onChange(selectedOption2.value);
135
+ setIsOpen(false);
136
+ setFocusedIndex(-1);
137
+ }
138
+ }
139
+ break;
140
+ case "Escape":
141
+ setIsOpen(false);
142
+ setFocusedIndex(-1);
143
+ break;
144
+ case "ArrowDown":
145
+ e.preventDefault();
146
+ if (!isOpen) {
147
+ setIsOpen(true);
148
+ setFocusedIndex(
149
+ Math.max(
150
+ 0,
151
+ options.findIndex((opt) => opt.value === value)
152
+ )
153
+ );
154
+ } else {
155
+ setFocusedIndex((prev) => {
156
+ const nextIndex = Math.min(prev + 1, options.length - 1);
157
+ return options[nextIndex]?.disabled ? prev : nextIndex;
158
+ });
159
+ }
160
+ break;
161
+ case "ArrowUp":
162
+ e.preventDefault();
163
+ if (isOpen) {
164
+ setFocusedIndex((prev) => {
165
+ const nextIndex = Math.max(prev - 1, 0);
166
+ return options[nextIndex]?.disabled ? prev : nextIndex;
167
+ });
168
+ }
169
+ break;
170
+ }
171
+ };
172
+ const baseClass = "ui-selector";
173
+ const statusClass = status ? `ui-selector--${status}` : "";
174
+ const sizeClass = size ? `ui-selector--${size}` : "";
175
+ const selectedOption = options.find((opt) => opt.value === value);
176
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `ui-selector-container ${className}`.trim(), children: [
177
+ label && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "ui-selector-label", children: label }),
178
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref: selectorRef, style: { position: "relative" }, children: [
179
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
180
+ "div",
181
+ {
182
+ className: `${baseClass} ${statusClass} ${sizeClass}`.trim(),
183
+ onClick: () => !disabled && setIsOpen(!isOpen),
184
+ onKeyDown: handleKeyDown,
185
+ tabIndex: disabled ? -1 : 0,
186
+ role: "combobox",
187
+ "aria-expanded": isOpen,
188
+ "aria-haspopup": "listbox",
189
+ ...props,
190
+ children: [
191
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ui-selector-value", children: selectedOption ? selectedOption.label : placeholder }),
192
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "ui-selector-arrow", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
193
+ ]
194
+ }
195
+ ),
196
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: dropdownRef, className: "ui-selector-dropdown", role: "listbox", children: options.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
197
+ "div",
198
+ {
199
+ className: `ui-selector-option${option.disabled ? " is-disabled" : ""}${option.value === value ? " is-selected" : ""}`,
200
+ onClick: () => {
201
+ if (!option.disabled) {
202
+ onChange(option.value);
203
+ setIsOpen(false);
204
+ setFocusedIndex(-1);
205
+ }
206
+ },
207
+ onMouseEnter: () => !option.disabled && setFocusedIndex(index),
208
+ role: "option",
209
+ "aria-selected": option.value === value,
210
+ "aria-disabled": option.disabled,
211
+ title: option.description,
212
+ children: [
213
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ui-selector-option-label", children: [
214
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: option.label }),
215
+ option.value === value && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "ui-selector-check", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
216
+ "path",
217
+ {
218
+ fillRule: "evenodd",
219
+ 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",
220
+ clipRule: "evenodd"
221
+ }
222
+ ) })
223
+ ] }),
224
+ option.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ui-selector-option-desc", children: option.description })
225
+ ]
226
+ },
227
+ option.value
228
+ )) })
229
+ ] })
230
+ ] });
231
+ };
232
+
233
+ // src/components/ValueEntry/ValueEntry.tsx
234
+ var import_react2 = require("react");
235
+ var import_jsx_runtime3 = require("react/jsx-runtime");
50
236
  var ValueEntry = ({
51
237
  value,
52
238
  onChange,
@@ -62,13 +248,103 @@ var ValueEntry = ({
62
248
  disabled,
63
249
  ...props
64
250
  }) => {
65
- const [displayValue, setDisplayValue] = (0, import_react.useState)(String(value));
66
- const [isEditing, setIsEditing] = (0, import_react.useState)(false);
67
- const handleFocus = (0, import_react.useCallback)(() => {
251
+ const [displayValue, setDisplayValue] = (0, import_react2.useState)(String(value));
252
+ const [isEditing, setIsEditing] = (0, import_react2.useState)(false);
253
+ const handleFocus = (0, import_react2.useCallback)(() => {
254
+ setIsEditing(true);
255
+ setDisplayValue(String(value));
256
+ }, [value]);
257
+ const handleBlur = (0, import_react2.useCallback)(() => {
258
+ setIsEditing(false);
259
+ let newValue = displayValue;
260
+ if (inputType === "numeric") {
261
+ const numValue = parseFloat(displayValue);
262
+ if (!isNaN(numValue)) {
263
+ let constrainedValue = numValue;
264
+ if (min !== void 0) constrainedValue = Math.max(min, constrainedValue);
265
+ if (max !== void 0) constrainedValue = Math.min(max, constrainedValue);
266
+ constrainedValue = parseFloat(constrainedValue.toFixed(precision));
267
+ newValue = constrainedValue;
268
+ setDisplayValue(String(constrainedValue));
269
+ } else {
270
+ setDisplayValue(String(value));
271
+ return;
272
+ }
273
+ }
274
+ if (newValue !== value) {
275
+ onChange(newValue);
276
+ }
277
+ }, [displayValue, inputType, min, max, precision, value, onChange]);
278
+ const handleChange = (0, import_react2.useCallback)((e) => {
279
+ setDisplayValue(e.target.value);
280
+ }, []);
281
+ const handleKeyDown = (0, import_react2.useCallback)(
282
+ (e) => {
283
+ if (e.key === "Enter") {
284
+ e.currentTarget.blur();
285
+ }
286
+ if (e.key === "Escape") {
287
+ setDisplayValue(String(value));
288
+ e.currentTarget.blur();
289
+ }
290
+ },
291
+ [value]
292
+ );
293
+ const baseClass = "ui-value-entry";
294
+ const unitClass = unit ? "ui-value-entry--with-unit" : "";
295
+ const currentStatus = disabled || readOnly ? "disabled" : status;
296
+ const statusVariantClass = currentStatus ? `ui-value-entry--${currentStatus}` : "";
297
+ const displayText = isEditing ? displayValue : inputType === "numeric" ? Number(value).toFixed(precision) : String(value);
298
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ui-value-entry-container", children: [
299
+ label && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "ui-value-entry-label", children: label }),
300
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ui-value-entry-wrapper", children: [
301
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
302
+ "input",
303
+ {
304
+ type: inputType === "numeric" ? "text" : "text",
305
+ value: displayText,
306
+ onChange: handleChange,
307
+ onFocus: handleFocus,
308
+ onBlur: handleBlur,
309
+ onKeyDown: handleKeyDown,
310
+ disabled,
311
+ readOnly,
312
+ className: `${baseClass} ${statusVariantClass} ${unitClass} ${className}`.trim(),
313
+ ...props
314
+ }
315
+ ),
316
+ unit && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ui-value-entry-unit", children: unit }),
317
+ status === "alarm" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ui-value-entry-badge ui-value-entry-badge--alarm" }),
318
+ status === "warning" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ui-value-entry-badge ui-value-entry-badge--warning" })
319
+ ] })
320
+ ] });
321
+ };
322
+
323
+ // src/components/ValueEntry/LegacyValueEntry.tsx
324
+ var import_react3 = require("react");
325
+ var import_jsx_runtime4 = require("react/jsx-runtime");
326
+ var LegacyValueEntry = ({
327
+ value,
328
+ onChange,
329
+ unit,
330
+ status = "normal",
331
+ min,
332
+ max,
333
+ precision = 2,
334
+ inputType = "numeric",
335
+ label,
336
+ readOnly = false,
337
+ className = "",
338
+ disabled,
339
+ ...props
340
+ }) => {
341
+ const [displayValue, setDisplayValue] = (0, import_react3.useState)(String(value));
342
+ const [isEditing, setIsEditing] = (0, import_react3.useState)(false);
343
+ const handleFocus = (0, import_react3.useCallback)(() => {
68
344
  setIsEditing(true);
69
345
  setDisplayValue(String(value));
70
346
  }, [value]);
71
- const handleBlur = (0, import_react.useCallback)(() => {
347
+ const handleBlur = (0, import_react3.useCallback)(() => {
72
348
  setIsEditing(false);
73
349
  let newValue = displayValue;
74
350
  if (inputType === "numeric") {
@@ -89,10 +365,10 @@ var ValueEntry = ({
89
365
  onChange(newValue);
90
366
  }
91
367
  }, [displayValue, inputType, min, max, precision, value, onChange]);
92
- const handleChange = (0, import_react.useCallback)((e) => {
368
+ const handleChange = (0, import_react3.useCallback)((e) => {
93
369
  setDisplayValue(e.target.value);
94
370
  }, []);
95
- const handleKeyDown = (0, import_react.useCallback)(
371
+ const handleKeyDown = (0, import_react3.useCallback)(
96
372
  (e) => {
97
373
  if (e.key === "Enter") {
98
374
  e.currentTarget.blur();
@@ -176,7 +452,7 @@ var ValueEntry = ({
176
452
  zIndex: 10,
177
453
  boxShadow: "0 2px 8px rgba(59, 130, 246, 0.4)"
178
454
  };
179
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
455
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
180
456
  "div",
181
457
  {
182
458
  style: {
@@ -186,7 +462,7 @@ var ValueEntry = ({
186
462
  gap: "0.75rem"
187
463
  },
188
464
  children: [
189
- label && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
465
+ label && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
190
466
  "label",
191
467
  {
192
468
  style: {
@@ -199,8 +475,8 @@ var ValueEntry = ({
199
475
  children: label
200
476
  }
201
477
  ),
202
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { position: "relative", display: "inline-flex", alignItems: "center" }, children: [
203
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
478
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { position: "relative", display: "inline-flex", alignItems: "center" }, children: [
479
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
204
480
  "input",
205
481
  {
206
482
  type: "text",
@@ -221,8 +497,8 @@ var ValueEntry = ({
221
497
  ...props
222
498
  }
223
499
  ),
224
- unit && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: unitStyle, children: unit }),
225
- status === "alarm" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
500
+ unit && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: unitStyle, children: unit }),
501
+ status === "alarm" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
226
502
  "div",
227
503
  {
228
504
  style: {
@@ -238,7 +514,7 @@ var ValueEntry = ({
238
514
  }
239
515
  }
240
516
  ),
241
- status === "warning" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
517
+ status === "warning" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
242
518
  "div",
243
519
  {
244
520
  style: {
@@ -259,8 +535,174 @@ var ValueEntry = ({
259
535
  );
260
536
  };
261
537
 
262
- // src/StatusIndicator.tsx
263
- var import_jsx_runtime3 = require("react/jsx-runtime");
538
+ // src/components/ControlPanel/ControlPanel.tsx
539
+ var import_jsx_runtime5 = require("react/jsx-runtime");
540
+ var ControlPanel = ({
541
+ title,
542
+ selectedMode,
543
+ modeOptions,
544
+ onModeChange,
545
+ setpointValue,
546
+ onSetpointChange,
547
+ secondSetpointValue,
548
+ onSecondSetpointChange,
549
+ modeConfigs = {},
550
+ defaultUnit = "Units",
551
+ defaultLabel = "Setpoint",
552
+ defaultMin = 0,
553
+ defaultMax = 100,
554
+ defaultPrecision = 2,
555
+ status = "normal",
556
+ collapsed = false,
557
+ onCollapseChange,
558
+ size = "medium",
559
+ setpointReadOnly = false,
560
+ showStartStopButtons = false,
561
+ isRunning = false,
562
+ onStart,
563
+ onStop,
564
+ startButtonText = "Start",
565
+ stopButtonText = "Stop",
566
+ className = "",
567
+ ...props
568
+ }) => {
569
+ const [isExpanded, setIsExpanded] = (0, import_react4.useState)(!collapsed);
570
+ const toggleExpanded = () => {
571
+ const newExpanded = !isExpanded;
572
+ setIsExpanded(newExpanded);
573
+ onCollapseChange?.(!newExpanded);
574
+ };
575
+ const currentModeConfig = modeConfigs[selectedMode] || {};
576
+ const currentUnit = currentModeConfig.unit || defaultUnit;
577
+ const currentLabel = currentModeConfig.label || defaultLabel;
578
+ const currentMin = currentModeConfig.min ?? defaultMin;
579
+ const currentMax = currentModeConfig.max ?? defaultMax;
580
+ const currentPrecision = currentModeConfig.precision ?? defaultPrecision;
581
+ const hasSecondSetpoint = currentModeConfig.hasSecondSetpoint || false;
582
+ const baseClass = "ui-control-panel";
583
+ const statusClass = status ? `ui-control-panel--${status}` : "";
584
+ const sizeClass = size ? `ui-control-panel--${size}` : "";
585
+ const expandedClass = isExpanded ? "is-expanded" : "is-collapsed";
586
+ const collapsibleClass = onCollapseChange ? "is-collapsible" : "";
587
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
588
+ "div",
589
+ {
590
+ className: `${baseClass} ${statusClass} ${sizeClass} ${expandedClass} ${collapsibleClass} ${className}`.trim(),
591
+ ...props,
592
+ children: [
593
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: `ui-control-panel-badge ui-control-panel-badge--${status}` }),
594
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
595
+ "div",
596
+ {
597
+ className: "ui-control-panel-header",
598
+ onClick: onCollapseChange ? toggleExpanded : void 0,
599
+ children: [
600
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "ui-control-panel-title", children: title }),
601
+ onCollapseChange && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
602
+ "svg",
603
+ {
604
+ className: "ui-control-panel-chevron",
605
+ fill: "none",
606
+ viewBox: "0 0 24 24",
607
+ stroke: "currentColor",
608
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
609
+ }
610
+ )
611
+ ]
612
+ }
613
+ ),
614
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ui-control-panel-content", children: [
615
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
616
+ Selector,
617
+ {
618
+ value: selectedMode,
619
+ onChange: onModeChange,
620
+ options: modeOptions,
621
+ label: "Control Mode",
622
+ status,
623
+ size: size === "small" ? "small" : size === "large" ? "large" : "medium",
624
+ disabled: status === "disabled"
625
+ }
626
+ ) }),
627
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
628
+ LegacyValueEntry,
629
+ {
630
+ value: setpointValue,
631
+ onChange: onSetpointChange,
632
+ label: currentLabel,
633
+ unit: currentUnit,
634
+ min: currentMin,
635
+ max: currentMax,
636
+ precision: currentPrecision,
637
+ status,
638
+ readOnly: setpointReadOnly || status === "disabled",
639
+ disabled: status === "disabled"
640
+ }
641
+ ) }),
642
+ hasSecondSetpoint && onSecondSetpointChange && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
643
+ LegacyValueEntry,
644
+ {
645
+ value: secondSetpointValue || 0,
646
+ onChange: onSecondSetpointChange,
647
+ label: currentModeConfig.secondLabel || "Time",
648
+ unit: currentModeConfig.secondUnit || "sec",
649
+ min: currentModeConfig.secondMin ?? 0,
650
+ max: currentModeConfig.secondMax ?? 999,
651
+ precision: currentModeConfig.secondPrecision ?? 0,
652
+ status,
653
+ readOnly: setpointReadOnly || status === "disabled",
654
+ disabled: status === "disabled"
655
+ }
656
+ ) }),
657
+ showStartStopButtons && (onStart || onStop) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ui-control-panel-buttons", children: [
658
+ onStart && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
659
+ Button,
660
+ {
661
+ variant: "primary",
662
+ onClick: onStart,
663
+ disabled: isRunning || status === "disabled",
664
+ className: isRunning ? "is-running" : "",
665
+ children: startButtonText
666
+ }
667
+ ),
668
+ onStop && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
669
+ Button,
670
+ {
671
+ variant: "secondary",
672
+ onClick: onStop,
673
+ disabled: !isRunning || status === "disabled",
674
+ className: `ui-control-panel-stop-btn${!isRunning ? " is-disabled" : ""}`,
675
+ children: stopButtonText
676
+ }
677
+ )
678
+ ] }),
679
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ui-control-panel-info", children: [
680
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
681
+ "Mode: ",
682
+ selectedMode.toUpperCase()
683
+ ] }),
684
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ui-control-panel-info-values", children: [
685
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
686
+ "SP: ",
687
+ String(setpointValue),
688
+ currentUnit
689
+ ] }),
690
+ hasSecondSetpoint && secondSetpointValue && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
691
+ currentModeConfig.secondLabel,
692
+ ": ",
693
+ String(secondSetpointValue),
694
+ currentModeConfig.secondUnit
695
+ ] })
696
+ ] })
697
+ ] })
698
+ ] })
699
+ ]
700
+ }
701
+ );
702
+ };
703
+
704
+ // src/components/StatusIndicator/StatusIndicator.tsx
705
+ var import_jsx_runtime6 = require("react/jsx-runtime");
264
706
  var StatusIndicator = ({
265
707
  status,
266
708
  size = "medium",
@@ -272,712 +714,940 @@ var StatusIndicator = ({
272
714
  className = "",
273
715
  ...props
274
716
  }) => {
275
- const sizeStyles = {
276
- small: "w-5 h-5",
277
- medium: "w-7 h-7",
278
- large: "w-10 h-10"
279
- };
280
- const shapeStyles = {
281
- circle: "rounded-full",
282
- square: "rounded-lg",
283
- diamond: "rotate-45 rounded-lg"
284
- };
285
- const statusStyles = {
286
- off: "bg-gradient-to-br from-slate-500 to-slate-600 border-slate-400 shadow-slate-500/30",
287
- normal: "bg-gradient-to-br from-emerald-400 via-green-500 to-green-600 border-emerald-300 shadow-green-500/70",
288
- alarm: "bg-gradient-to-br from-red-400 via-red-500 to-red-600 border-red-300 shadow-red-500/70",
289
- warning: "bg-gradient-to-br from-amber-400 via-yellow-500 to-orange-500 border-amber-300 shadow-yellow-500/70",
290
- active: "bg-gradient-to-br from-blue-400 via-blue-500 to-indigo-600 border-blue-300 shadow-blue-500/70",
291
- fault: "bg-gradient-to-br from-purple-400 via-purple-500 to-violet-600 border-purple-300 shadow-purple-500/70"
292
- };
293
- const animationStyles = {
294
- none: "",
295
- pulse: "animate-pulse",
296
- blink: "animate-bounce",
297
- flash: "animate-ping"
298
- };
299
- const ledEffect = led ? "shadow-lg border-2" : "border";
300
- const glowEffect = status !== "off" && led ? "shadow-lg" : "";
301
- const indicatorClasses = `
302
- ${sizeStyles[size]}
303
- ${shapeStyles[shape]}
304
- ${statusStyles[status]}
305
- ${animationStyles[animation]}
306
- ${ledEffect}
307
- ${glowEffect}
308
- inline-block
309
- transition-all
310
- duration-300
311
- `.trim().replace(/\s+/g, " ");
312
- const labelClasses = "text-sm font-medium text-gray-700 uppercase tracking-wide select-none";
717
+ const baseClass = "ui-status-indicator";
718
+ const statusClass = status ? `ui-status-indicator--${status}` : "";
719
+ const sizeClass = size ? `ui-status-indicator--${size}` : "";
720
+ const shapeClass = shape ? `ui-status-indicator--${shape}` : "";
721
+ const animationClass = animation ? `ui-status-indicator--${animation}` : "";
722
+ const ledClass = led ? "ui-status-indicator--led" : "";
313
723
  const getContainerLayout = () => {
314
724
  switch (labelPosition) {
315
725
  case "left":
316
- return "inline-flex items-center gap-2 flex-row-reverse";
726
+ return "ui-status-indicator-container ui-status-indicator-label-left";
317
727
  case "right":
318
- return "inline-flex items-center gap-2";
728
+ return "ui-status-indicator-container ui-status-indicator-label-right";
319
729
  case "top":
320
- return "inline-flex flex-col-reverse items-center gap-1";
730
+ return "ui-status-indicator-container ui-status-indicator-label-top";
321
731
  case "bottom":
322
- return "inline-flex flex-col items-center gap-1";
732
+ return "ui-status-indicator-container ui-status-indicator-label-bottom";
323
733
  default:
324
- return "inline-flex items-center gap-2";
325
- }
326
- };
327
- const getAriaLabel = () => {
328
- if (label) {
329
- return `${label}: ${status}`;
734
+ return "ui-status-indicator-container ui-status-indicator-label-right";
330
735
  }
331
- return `Status indicator: ${status}`;
332
736
  };
333
- const getAriaDescription = () => {
334
- const descriptions = {
335
- off: "Inactive or disabled state",
336
- normal: "Normal operating condition",
337
- alarm: "Critical alarm condition requiring attention",
338
- warning: "Warning condition that should be monitored",
339
- active: "Currently active or running",
340
- fault: "System fault or error condition"
341
- };
342
- return descriptions[status];
343
- };
344
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `${getContainerLayout()} ${className}`.trim(), ...props, children: [
345
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
346
- "div",
737
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: getContainerLayout(), children: [
738
+ label && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ui-status-indicator-label", children: label }),
739
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
740
+ "span",
347
741
  {
348
- className: indicatorClasses,
349
- role: "status",
350
- "aria-label": getAriaLabel(),
351
- "aria-description": getAriaDescription(),
352
- "data-status": status,
353
- "data-testid": `status-indicator-${status}`
742
+ className: `
743
+ ${baseClass}
744
+ ${statusClass}
745
+ ${sizeClass}
746
+ ${shapeClass}
747
+ ${animationClass}
748
+ ${ledClass}
749
+ ${className}
750
+ `.replace(/\s+/g, " ").trim(),
751
+ ...props
354
752
  }
355
753
  ),
356
- label && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: labelClasses, children: label })
754
+ label && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ui-status-indicator-label", children: label })
357
755
  ] });
358
756
  };
359
757
 
360
- // src/Selector.tsx
361
- var import_react2 = require("react");
362
- var import_jsx_runtime4 = require("react/jsx-runtime");
363
- var Selector = ({
364
- value,
365
- onChange,
366
- options,
367
- placeholder = "Select option...",
368
- disabled = false,
369
- status = "normal",
370
- size = "medium",
371
- label,
372
- dropdownUp = false,
373
- className = "",
374
- ...props
375
- }) => {
376
- const [isOpen, setIsOpen] = (0, import_react2.useState)(false);
377
- const [focusedIndex, setFocusedIndex] = (0, import_react2.useState)(-1);
378
- const selectorRef = (0, import_react2.useRef)(null);
379
- const dropdownRef = (0, import_react2.useRef)(null);
380
- (0, import_react2.useEffect)(() => {
381
- const handleClickOutside = (event) => {
382
- if (selectorRef.current && !selectorRef.current.contains(event.target)) {
383
- setIsOpen(false);
384
- setFocusedIndex(-1);
758
+ // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
759
+ var import_react6 = __toESM(require("react"), 1);
760
+ var import_material3 = require("@mui/material");
761
+
762
+ // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.styles.tsx
763
+ var import_material = require("@mui/material");
764
+ var import_styled = __toESM(require("@emotion/styled"), 1);
765
+ var import_jsx_runtime7 = require("react/jsx-runtime");
766
+ var FullscreenContainer = (0, import_styled.default)(import_material.Box)(
767
+ ({ leftCollapsed, rightCollapsed }) => {
768
+ const getGridTemplateAreas = () => {
769
+ if (leftCollapsed && rightCollapsed) {
770
+ return `"svg-area" "footer"`;
771
+ }
772
+ if (leftCollapsed) {
773
+ return `"svg-area right-panel" "footer footer"`;
385
774
  }
775
+ if (rightCollapsed) {
776
+ return `"left-panel svg-area" "footer footer"`;
777
+ }
778
+ return `"left-panel svg-area right-panel" "footer footer footer"`;
386
779
  };
387
- document.addEventListener("mousedown", handleClickOutside);
388
- return () => document.removeEventListener("mousedown", handleClickOutside);
389
- }, []);
390
- const handleKeyDown = (e) => {
391
- if (disabled) return;
392
- switch (e.key) {
393
- case "Enter":
394
- case " ":
395
- e.preventDefault();
396
- if (!isOpen) {
397
- setIsOpen(true);
398
- setFocusedIndex(
399
- Math.max(
400
- 0,
401
- options.findIndex((opt) => opt.value === value)
402
- )
403
- );
404
- } else if (focusedIndex >= 0) {
405
- const selectedOption2 = options[focusedIndex];
406
- if (!selectedOption2.disabled) {
407
- onChange(selectedOption2.value);
408
- setIsOpen(false);
409
- setFocusedIndex(-1);
410
- }
411
- }
412
- break;
413
- case "Escape":
414
- setIsOpen(false);
415
- setFocusedIndex(-1);
416
- break;
417
- case "ArrowDown":
418
- e.preventDefault();
419
- if (!isOpen) {
420
- setIsOpen(true);
421
- setFocusedIndex(
422
- Math.max(
423
- 0,
424
- options.findIndex((opt) => opt.value === value)
425
- )
426
- );
427
- } else {
428
- setFocusedIndex((prev) => {
429
- const nextIndex = Math.min(prev + 1, options.length - 1);
430
- return options[nextIndex]?.disabled ? prev : nextIndex;
431
- });
432
- }
433
- break;
434
- case "ArrowUp":
435
- e.preventDefault();
436
- if (isOpen) {
437
- setFocusedIndex((prev) => {
438
- const nextIndex = Math.max(prev - 1, 0);
439
- return options[nextIndex]?.disabled ? prev : nextIndex;
440
- });
441
- }
442
- break;
780
+ const getGridTemplateColumns = () => {
781
+ if (leftCollapsed && rightCollapsed) {
782
+ return "1fr";
783
+ }
784
+ if (leftCollapsed) {
785
+ return "1fr 380px";
786
+ }
787
+ if (rightCollapsed) {
788
+ return "420px 1fr";
789
+ }
790
+ return "420px 1fr 380px";
791
+ };
792
+ return {
793
+ width: "100vw",
794
+ height: "100vh",
795
+ background: "#f5f5f5",
796
+ display: "grid",
797
+ gridTemplateAreas: getGridTemplateAreas(),
798
+ gridTemplateRows: "1fr 100px",
799
+ gridTemplateColumns: getGridTemplateColumns(),
800
+ gap: "10px",
801
+ padding: "10px",
802
+ boxSizing: "border-box",
803
+ transition: "grid-template-columns 0.3s ease-in-out"
804
+ };
805
+ }
806
+ );
807
+ var LeftPanel = (0, import_styled.default)(import_material.Box)(({ collapsed }) => ({
808
+ gridArea: "left-panel",
809
+ background: "rgba(255, 255, 255, 0.0)",
810
+ border: "1px solid #ddd",
811
+ borderRadius: "8px",
812
+ padding: collapsed ? "0" : "15px",
813
+ overflowY: "auto",
814
+ display: collapsed ? "none" : "block",
815
+ transition: "all 0.3s ease-in-out"
816
+ }));
817
+ var RightPanel = (0, import_styled.default)(import_material.Box)(({ collapsed }) => ({
818
+ gridArea: "right-panel",
819
+ background: "rgba(255, 255, 255, 0.0)",
820
+ border: "1px solid #ddd",
821
+ borderRadius: "8px",
822
+ padding: collapsed ? "0" : "15px",
823
+ overflowY: "auto",
824
+ display: collapsed ? "none" : "block",
825
+ transition: "all 0.3s ease-in-out"
826
+ }));
827
+ var SVGArea = (0, import_styled.default)(import_material.Box)({
828
+ gridArea: "svg-area",
829
+ display: "flex",
830
+ alignItems: "center",
831
+ justifyContent: "flex-start",
832
+ position: "relative",
833
+ background: "rgba(255, 255, 255, 0.0)",
834
+ border: "1px solid #ddd",
835
+ borderRadius: "8px",
836
+ overflow: "auto",
837
+ width: "100%",
838
+ height: "100%"
839
+ });
840
+ var LeftToggleButton = (0, import_styled.default)(import_material.IconButton)(
841
+ ({ collapsed }) => ({
842
+ position: "absolute",
843
+ left: collapsed ? "10px" : "410px",
844
+ top: "50%",
845
+ transform: "translateY(-50%)",
846
+ zIndex: 1e3,
847
+ backgroundColor: "rgba(255, 255, 255, 0.9)",
848
+ border: "1px solid #ddd",
849
+ transition: "left 0.3s ease-in-out",
850
+ "&:hover": {
851
+ backgroundColor: "rgba(255, 255, 255, 1)"
443
852
  }
444
- };
445
- const selectedOption = options.find((opt) => opt.value === value);
446
- const getSizeStyles = () => {
447
- switch (size) {
448
- case "small":
449
- return {
450
- height: "2.5rem",
451
- padding: "0.5rem 0.75rem",
452
- fontSize: "0.875rem",
453
- iconSize: "1rem"
454
- };
455
- case "large":
456
- return {
457
- height: "4rem",
458
- padding: "1rem 1.5rem",
459
- fontSize: "1.25rem",
460
- iconSize: "1.5rem"
461
- };
462
- default:
463
- return {
464
- height: "3rem",
465
- padding: "0.75rem 1rem",
466
- fontSize: "1rem",
467
- iconSize: "1.25rem"
468
- };
853
+ })
854
+ );
855
+ var RightToggleButton = (0, import_styled.default)(import_material.IconButton)(
856
+ ({ collapsed }) => ({
857
+ position: "absolute",
858
+ right: collapsed ? "10px" : "370px",
859
+ top: "50%",
860
+ transform: "translateY(-50%)",
861
+ zIndex: 1e3,
862
+ backgroundColor: "rgba(255, 255, 255, 0.9)",
863
+ border: "1px solid #ddd",
864
+ transition: "right 0.3s ease-in-out",
865
+ "&:hover": {
866
+ backgroundColor: "rgba(255, 255, 255, 1)"
469
867
  }
470
- };
471
- const getStatusStyles = () => {
472
- switch (status) {
473
- case "alarm":
474
- return {
475
- borderColor: "var(--selector-alarm-border, #ef4444)",
476
- backgroundColor: "var(--selector-alarm-bg, rgba(239, 68, 68, 0.15))",
477
- color: "var(--selector-alarm-text, #fecaca)",
478
- boxShadow: "var(--selector-alarm-shadow, 0 0 20px rgba(239, 68, 68, 0.3))"
479
- };
480
- case "warning":
481
- return {
482
- borderColor: "var(--selector-warning-border, #f59e0b)",
483
- backgroundColor: "var(--selector-warning-bg, rgba(245, 158, 11, 0.15))",
484
- color: "var(--selector-warning-text, #fed7aa)",
485
- boxShadow: "var(--selector-warning-shadow, 0 0 20px rgba(245, 158, 11, 0.3))"
486
- };
487
- case "disabled":
488
- return {
489
- borderColor: "var(--selector-disabled-border, #6b7280)",
490
- backgroundColor: "var(--selector-disabled-bg, rgba(107, 114, 128, 0.1))",
491
- color: "var(--selector-disabled-text, #9ca3af)",
492
- cursor: "not-allowed"
493
- };
494
- default:
495
- return {
496
- borderColor: "var(--selector-normal-border, #64748b)",
497
- backgroundColor: "var(--selector-normal-bg, rgba(30, 41, 59, 0.9))",
498
- color: "var(--selector-normal-text, #f1f5f9)",
499
- boxShadow: "var(--selector-normal-shadow, 0 8px 32px rgba(0, 0, 0, 0.3))"
500
- };
868
+ })
869
+ );
870
+ var DisplayModeToggle = (0, import_styled.default)(import_material.IconButton)(({ mode }) => ({
871
+ position: "absolute",
872
+ top: "50px",
873
+ left: "75%",
874
+ transform: "translateX(-50%)",
875
+ zIndex: 1e3,
876
+ backgroundColor: mode === "dashboard" ? "rgba(52, 152, 219, 0.9)" : "rgba(255, 255, 255, 0.9)",
877
+ color: mode === "dashboard" ? "white" : "#333",
878
+ border: "1px solid #ddd",
879
+ borderRadius: "20px",
880
+ padding: "8px 16px",
881
+ fontSize: "12px",
882
+ fontWeight: "600",
883
+ minWidth: "120px",
884
+ transition: "all 0.3s ease-in-out",
885
+ "&:hover": {
886
+ backgroundColor: mode === "dashboard" ? "rgba(52, 152, 219, 1)" : "rgba(255, 255, 255, 1)",
887
+ transform: "translateX(-50%) scale(1.05)"
888
+ }
889
+ }));
890
+ var ChevronLeft = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
891
+ "div",
892
+ {
893
+ style: {
894
+ width: 0,
895
+ height: 0,
896
+ borderTop: "6px solid transparent",
897
+ borderBottom: "6px solid transparent",
898
+ borderRight: "8px solid #666"
501
899
  }
502
- };
503
- const sizeStyles = getSizeStyles();
504
- const statusStyles = getStatusStyles();
505
- const selectorStyle = {
506
- position: "relative",
507
- width: "100%",
508
- height: sizeStyles.height,
509
- padding: sizeStyles.padding,
510
- paddingRight: "3rem",
511
- border: "2px solid",
512
- borderRadius: "1rem",
513
- fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
514
- fontSize: sizeStyles.fontSize,
515
- fontWeight: "bold",
516
- outline: "none",
517
- transition: "all 300ms ease",
518
- backdropFilter: "blur(8px)",
519
- cursor: disabled ? "not-allowed" : "pointer",
520
- display: "flex",
521
- alignItems: "center",
522
- justifyContent: "space-between",
523
- userSelect: "none",
524
- ...statusStyles
525
- };
526
- const dropdownStyle = {
900
+ }
901
+ );
902
+ var ChevronRight = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
903
+ "div",
904
+ {
905
+ style: {
906
+ width: 0,
907
+ height: 0,
908
+ borderTop: "6px solid transparent",
909
+ borderBottom: "6px solid transparent",
910
+ borderLeft: "8px solid #666"
911
+ }
912
+ }
913
+ );
914
+ var ZoomControls = (0, import_styled.default)(import_material.Box)({
915
+ position: "absolute",
916
+ top: "10px",
917
+ right: "10px",
918
+ display: "flex",
919
+ flexDirection: "column",
920
+ gap: "5px",
921
+ zIndex: 1e3
922
+ });
923
+ var ZoomButton = (0, import_styled.default)(import_material.IconButton)({
924
+ backgroundColor: "rgba(255, 255, 255, 0.9)",
925
+ border: "1px solid #ddd",
926
+ width: "32px",
927
+ height: "32px",
928
+ fontSize: "14px",
929
+ fontWeight: "bold",
930
+ "&:hover": {
931
+ backgroundColor: "rgba(255, 255, 255, 1)"
932
+ }
933
+ });
934
+ var FooterPanel = (0, import_styled.default)(import_material.Box)({
935
+ gridArea: "footer",
936
+ background: "rgba(255, 255, 255, 0.95)",
937
+ border: "1px solid #ddd",
938
+ borderRadius: "8px",
939
+ padding: "10px",
940
+ display: "flex",
941
+ justifyContent: "space-around",
942
+ alignItems: "center"
943
+ });
944
+ var PanelTabs = (0, import_styled.default)(import_material.Tabs)({
945
+ minHeight: "36px",
946
+ "& .MuiTabs-indicator": {
947
+ backgroundColor: "#546e7a"
948
+ },
949
+ "& .MuiTab-root": {
950
+ minHeight: "36px",
951
+ padding: "6px 12px",
952
+ fontSize: "12px",
953
+ fontWeight: "600",
954
+ textTransform: "none",
955
+ color: "#666",
956
+ "&.Mui-selected": {
957
+ color: "#546e7a"
958
+ }
959
+ }
960
+ });
961
+ var PanelContent = (0, import_styled.default)(import_material.Box)({
962
+ flex: 1,
963
+ overflow: "auto",
964
+ padding: "10px"
965
+ });
966
+ var FixedSVGContainer = (0, import_styled.default)("div")({
967
+ position: "relative",
968
+ width: "1300px",
969
+ height: "400px",
970
+ minWidth: "1300px",
971
+ minHeight: "400px",
972
+ maxWidth: "1300px",
973
+ maxHeight: "400px",
974
+ border: "none",
975
+ backgroundColor: "transparent",
976
+ overflow: "visible",
977
+ "& .svg-locked-overlay": {
978
+ position: "absolute",
979
+ pointerEvents: "auto",
980
+ zIndex: 10
981
+ },
982
+ "& svg": {
527
983
  position: "absolute",
528
- top: dropdownUp ? "auto" : "100%",
529
- bottom: dropdownUp ? "100%" : "auto",
530
984
  left: 0,
531
- right: 0,
532
- marginTop: dropdownUp ? 0 : "0.25rem",
533
- marginBottom: dropdownUp ? "0.25rem" : 0,
534
- backgroundColor: "var(--selector-dropdown-bg, rgba(30, 41, 59, 0.95))",
535
- border: "2px solid var(--selector-dropdown-border, #64748b)",
536
- borderRadius: "1rem",
537
- backdropFilter: "blur(12px)",
538
- boxShadow: "var(--selector-dropdown-shadow, 0 12px 48px rgba(0, 0, 0, 0.4))",
539
- zIndex: 50,
540
- maxHeight: "12rem",
541
- overflowY: "auto"
542
- };
543
- const optionStyle = (option, index) => ({
544
- padding: sizeStyles.padding,
545
- fontSize: sizeStyles.fontSize,
546
- fontWeight: "600",
547
- color: option.disabled ? "var(--selector-option-disabled-text, #6b7280)" : "var(--selector-option-text, #f1f5f9)",
548
- backgroundColor: index === focusedIndex ? "var(--selector-option-focused-bg, rgba(59, 130, 246, 0.3))" : "transparent",
549
- cursor: option.disabled ? "not-allowed" : "pointer",
550
- transition: "all 150ms ease",
551
- borderRadius: index === focusedIndex ? "0.5rem" : "0",
552
- margin: index === focusedIndex ? "0.125rem" : "0"
553
- });
554
- const arrowStyle = {
985
+ top: 0,
986
+ width: "1300px",
987
+ height: "280px",
988
+ minWidth: "1300px",
989
+ minHeight: "280px",
990
+ maxWidth: "none",
991
+ maxHeight: "none",
992
+ objectFit: "none",
993
+ transform: "none",
994
+ border: "none"
995
+ }
996
+ });
997
+ var ScrollableSVGWrapper = (0, import_styled.default)("div")({
998
+ position: "relative",
999
+ width: "100%",
1000
+ height: "100%",
1001
+ overflow: "auto",
1002
+ transform: "rotateX(180deg)",
1003
+ padding: "250px",
1004
+ paddingTop: "200px",
1005
+ boxSizing: "border-box",
1006
+ "& > *": {
1007
+ display: "block",
1008
+ transform: "rotateX(180deg)"
1009
+ }
1010
+ });
1011
+
1012
+ // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.overlays.tsx
1013
+ var import_react5 = require("react");
1014
+ var import_material2 = require("@mui/material");
1015
+ var import_styled2 = __toESM(require("@emotion/styled"), 1);
1016
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1017
+ var baseOverlayStyles = {
1018
+ tank: {
1019
+ background: "linear-gradient(135deg, rgba(69, 90, 120, 0.95) 0%, rgba(52, 73, 94, 0.95) 100%)",
1020
+ border: "1px solid #455a64",
1021
+ color: "white",
1022
+ borderRadius: "4px",
1023
+ fontSize: "12px",
1024
+ fontWeight: "500",
1025
+ textAlign: "center",
1026
+ padding: "8px",
1027
+ minWidth: "60px",
1028
+ boxShadow: "0 1px 4px rgba(69, 90, 120, 0.2)"
1029
+ },
1030
+ pressure: {
1031
+ background: "linear-gradient(135deg, rgba(30, 50, 90, 0.75) 0%, rgba(20, 35, 70, 0.75) 100%)",
1032
+ border: "1px solid #1e3a8a",
1033
+ color: "white",
1034
+ borderRadius: "4px",
1035
+ fontSize: "11px",
1036
+ fontWeight: "500",
1037
+ textAlign: "center",
1038
+ padding: "6px",
1039
+ minWidth: "50px",
1040
+ boxShadow: "0 1px 4px rgba(30, 50, 90, 0.15)"
1041
+ },
1042
+ vessel: {
1043
+ background: "linear-gradient(135deg, rgba(84, 110, 122, 0.95) 0%, rgba(69, 90, 100, 0.95) 100%)",
1044
+ border: "1px solid #546e7a",
1045
+ color: "white",
1046
+ borderRadius: "4px",
1047
+ fontSize: "13px",
1048
+ fontWeight: "500",
1049
+ textAlign: "center",
1050
+ padding: "8px",
1051
+ minWidth: "70px",
1052
+ boxShadow: "0 1px 4px rgba(84, 110, 122, 0.2)"
1053
+ },
1054
+ flow: {
1055
+ background: "linear-gradient(135deg, rgba(102, 125, 102, 0.95) 0%, rgba(85, 107, 85, 0.95) 100%)",
1056
+ border: "1px solid #689f38",
1057
+ color: "white",
1058
+ borderRadius: "4px",
1059
+ fontSize: "11px",
1060
+ fontWeight: "500",
1061
+ textAlign: "center",
1062
+ padding: "5px",
1063
+ minWidth: "60px",
1064
+ boxShadow: "0 1px 4px rgba(102, 125, 102, 0.2)"
1065
+ }
1066
+ };
1067
+ var overlayStyles = baseOverlayStyles;
1068
+ var SVGLockedOverlay = ({
1069
+ svgX,
1070
+ svgY,
1071
+ children,
1072
+ theme,
1073
+ style = {},
1074
+ className = "",
1075
+ onClick,
1076
+ containerSelector = ".tff-svg-container"
1077
+ }) => {
1078
+ const [svgOffset, setSvgOffset] = (0, import_react5.useState)({ x: 0, y: 0 });
1079
+ (0, import_react5.useEffect)(() => {
1080
+ const updateSvgOffset = () => {
1081
+ const containerElement = document.querySelector(containerSelector);
1082
+ const svgElement = containerElement?.querySelector("svg");
1083
+ if (svgElement && containerElement) {
1084
+ const svgRect = svgElement.getBoundingClientRect();
1085
+ const containerRect = containerElement.getBoundingClientRect();
1086
+ setSvgOffset({
1087
+ x: svgRect.left - containerRect.left,
1088
+ y: svgRect.top - containerRect.top
1089
+ });
1090
+ }
1091
+ };
1092
+ updateSvgOffset();
1093
+ window.addEventListener("resize", updateSvgOffset);
1094
+ return () => window.removeEventListener("resize", updateSvgOffset);
1095
+ }, [containerSelector]);
1096
+ const pixelX = svgX + svgOffset.x;
1097
+ const pixelY = svgY + svgOffset.y;
1098
+ const appliedStyle = theme ? { ...overlayStyles[theme], ...style } : style;
1099
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1100
+ import_material2.Box,
1101
+ {
1102
+ className: `svg-locked-overlay ${className}`.trim(),
1103
+ onClick,
1104
+ sx: {
1105
+ position: "absolute",
1106
+ left: `${pixelX}px`,
1107
+ top: `${pixelY}px`,
1108
+ cursor: onClick ? "pointer" : "default",
1109
+ zIndex: 10,
1110
+ pointerEvents: "auto",
1111
+ ...appliedStyle
1112
+ },
1113
+ children
1114
+ }
1115
+ );
1116
+ };
1117
+ var DashboardCard = (0, import_styled2.default)(import_material2.Box)(
1118
+ ({ svgX, svgY, cardType }) => ({
555
1119
  position: "absolute",
556
- right: "1rem",
557
- top: "50%",
558
- transform: `translateY(-50%) rotate(${isOpen ? "180deg" : "0deg"})`,
559
- transition: "transform 200ms ease",
560
- width: sizeStyles.iconSize,
561
- height: sizeStyles.iconSize,
562
- color: disabled ? "#6b7280" : "#94a3b8"
563
- };
564
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1120
+ left: svgX,
1121
+ top: svgY,
1122
+ background: cardType === "critical" ? "linear-gradient(135deg, rgba(220, 53, 69, 0.95) 0%, rgba(173, 20, 87, 0.95) 100%)" : cardType === "warning" ? "linear-gradient(135deg, rgba(255, 193, 7, 0.95) 0%, rgba(255, 143, 0, 0.95) 100%)" : cardType === "vessel" ? "linear-gradient(135deg, rgba(46, 204, 113, 0.95) 0%, rgba(39, 174, 96, 0.95) 100%)" : cardType === "process" ? "linear-gradient(135deg, rgba(155, 89, 182, 0.95) 0%, rgba(142, 68, 173, 0.95) 100%)" : cardType === "control" ? "linear-gradient(135deg, rgba(26, 188, 156, 0.95) 0%, rgba(22, 160, 133, 0.95) 100%)" : "linear-gradient(135deg, rgba(52, 152, 219, 0.95) 0%, rgba(41, 128, 185, 0.95) 100%)",
1123
+ border: "1px solid rgba(255, 255, 255, 0.2)",
1124
+ borderRadius: "12px",
1125
+ padding: "12px",
1126
+ minWidth: "140px",
1127
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.3)",
1128
+ backdropFilter: "blur(10px)",
1129
+ color: "white",
1130
+ fontSize: "12px",
1131
+ fontWeight: "600",
1132
+ textAlign: "center",
1133
+ transform: "translate(-50%, -50%)",
1134
+ transition: "all 0.3s ease-in-out",
1135
+ cursor: "pointer",
1136
+ "&:hover": {
1137
+ transform: "translate(-50%, -50%) scale(1.05)",
1138
+ boxShadow: "0 12px 40px rgba(0, 0, 0, 0.4)"
1139
+ }
1140
+ })
1141
+ );
1142
+ var CardHeader = (0, import_styled2.default)("div")(({ color }) => ({
1143
+ fontSize: "10px",
1144
+ opacity: 0.9,
1145
+ marginBottom: "4px",
1146
+ textTransform: "uppercase",
1147
+ letterSpacing: "0.5px",
1148
+ color: color || "inherit",
1149
+ borderBottom: color ? `1px solid ${color}40` : "none",
1150
+ paddingBottom: color ? "2px" : "0"
1151
+ }));
1152
+ var CardValue = (0, import_styled2.default)("div")({
1153
+ fontSize: "16px",
1154
+ fontWeight: "700",
1155
+ marginBottom: "2px"
1156
+ });
1157
+ var CardUnit = (0, import_styled2.default)("div")({
1158
+ fontSize: "9px",
1159
+ opacity: 0.8
1160
+ });
1161
+
1162
+ // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx
1163
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1164
+ var TrendLine = ({
1165
+ values,
1166
+ width = 60,
1167
+ height = 20,
1168
+ color = "#4fc3f7",
1169
+ strokeWidth = 1.5,
1170
+ backgroundColor = "rgba(255, 255, 255, 0.1)"
1171
+ }) => {
1172
+ if (!values || values.length < 2) {
1173
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1174
+ "div",
1175
+ {
1176
+ style: {
1177
+ width,
1178
+ height,
1179
+ backgroundColor,
1180
+ borderRadius: "2px",
1181
+ display: "flex",
1182
+ alignItems: "center",
1183
+ justifyContent: "center"
1184
+ },
1185
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" })
1186
+ }
1187
+ );
1188
+ }
1189
+ const minValue = Math.min(...values);
1190
+ const maxValue = Math.max(...values);
1191
+ const range = maxValue - minValue;
1192
+ const normalizedValues = range === 0 ? values.map(() => height / 2) : values.map((v) => height - 4 - (v - minValue) / range * (height - 8));
1193
+ const pathData = normalizedValues.map((y, i) => {
1194
+ const x = 4 + i / (values.length - 1) * (width - 8);
1195
+ return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
1196
+ }).join(" ");
1197
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1198
+ "div",
1199
+ {
1200
+ style: {
1201
+ width,
1202
+ height,
1203
+ backgroundColor,
1204
+ borderRadius: "2px",
1205
+ position: "relative",
1206
+ overflow: "hidden"
1207
+ },
1208
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width, height, style: { position: "absolute", top: 0, left: 0 }, children: [
1209
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1210
+ "path",
1211
+ {
1212
+ d: pathData,
1213
+ fill: "none",
1214
+ stroke: color,
1215
+ strokeWidth,
1216
+ strokeLinecap: "round",
1217
+ strokeLinejoin: "round"
1218
+ }
1219
+ ),
1220
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1221
+ "circle",
1222
+ {
1223
+ cx: 4 + (width - 8),
1224
+ cy: normalizedValues[normalizedValues.length - 1],
1225
+ r: 1.5,
1226
+ fill: color
1227
+ }
1228
+ )
1229
+ ] })
1230
+ }
1231
+ );
1232
+ };
1233
+ var hexToRgba = (hex, alpha) => {
1234
+ const r = parseInt(hex.slice(1, 3), 16);
1235
+ const g = parseInt(hex.slice(3, 5), 16);
1236
+ const b = parseInt(hex.slice(5, 7), 16);
1237
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
1238
+ };
1239
+ var CircularGauge = ({
1240
+ value,
1241
+ max,
1242
+ unit,
1243
+ label,
1244
+ size = 60,
1245
+ color = "rgba(255, 255, 255, 0.9)"
1246
+ }) => {
1247
+ const percentage = Math.min(value / max * 100, 100);
1248
+ const strokeWidth = 4;
1249
+ const radius = (size - strokeWidth) / 2;
1250
+ const circumference = radius * 2 * Math.PI;
1251
+ const strokeDasharray = circumference;
1252
+ const strokeDashoffset = circumference - percentage / 100 * circumference;
1253
+ const isHex = color.startsWith("#");
1254
+ const innerCircleColor = isHex ? hexToRgba(color, 0.8) : color;
1255
+ const borderColor = isHex ? hexToRgba(color, 0.9) : color;
1256
+ const backgroundColor = isHex ? hexToRgba(color, 0.15) : color;
1257
+ const borderStrokeColor = isHex ? hexToRgba(color, 0.4) : color;
1258
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
565
1259
  "div",
566
1260
  {
567
- className: "selector-container",
568
- style: { display: "flex", flexDirection: "column", gap: "0.5rem" },
1261
+ style: {
1262
+ display: "flex",
1263
+ flexDirection: "column",
1264
+ alignItems: "center"
1265
+ },
569
1266
  children: [
570
- label && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
571
- "label",
1267
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1268
+ "div",
572
1269
  {
573
- className: "selector-label",
574
1270
  style: {
575
- fontSize: "0.875rem",
576
- fontWeight: "600",
577
- color: "var(--selector-label-color, #cbd5e1)",
578
- textTransform: "uppercase",
579
- letterSpacing: "0.05em"
1271
+ position: "relative",
1272
+ width: size,
1273
+ height: size,
1274
+ borderRadius: "50%",
1275
+ backgroundColor,
1276
+ border: `1px solid ${borderStrokeColor}`
580
1277
  },
581
- children: label
582
- }
583
- ),
584
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { ref: selectorRef, style: { position: "relative" }, children: [
585
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
586
- "div",
587
- {
588
- className: `selector ${className}`,
589
- style: selectorStyle,
590
- onClick: () => !disabled && setIsOpen(!isOpen),
591
- onKeyDown: handleKeyDown,
592
- tabIndex: disabled ? -1 : 0,
593
- role: "combobox",
594
- "aria-expanded": isOpen,
595
- "aria-haspopup": "listbox",
596
- ...props,
597
- children: [
598
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
599
- "span",
1278
+ children: [
1279
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
1280
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1281
+ "circle",
600
1282
  {
601
- style: {
602
- color: selectedOption ? statusStyles.color : "var(--selector-placeholder-text, #9ca3af)",
603
- overflow: "hidden",
604
- textOverflow: "ellipsis",
605
- whiteSpace: "nowrap"
606
- },
607
- children: selectedOption ? selectedOption.label : placeholder
1283
+ cx: size / 2,
1284
+ cy: size / 2,
1285
+ r: radius - strokeWidth - 2,
1286
+ fill: innerCircleColor,
1287
+ stroke: borderColor,
1288
+ strokeWidth: 1
608
1289
  }
609
1290
  ),
610
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { style: arrowStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
611
- ]
612
- }
613
- ),
614
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref: dropdownRef, style: dropdownStyle, role: "listbox", children: options.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
615
- "div",
616
- {
617
- style: optionStyle(option, index),
618
- onClick: () => {
619
- if (!option.disabled) {
620
- onChange(option.value);
621
- setIsOpen(false);
622
- setFocusedIndex(-1);
623
- }
624
- },
625
- onMouseEnter: () => !option.disabled && setFocusedIndex(index),
626
- role: "option",
627
- "aria-selected": option.value === value,
628
- "aria-disabled": option.disabled,
629
- title: option.description,
630
- children: [
631
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
632
- "div",
1291
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1292
+ "circle",
633
1293
  {
634
- style: { display: "flex", justifyContent: "space-between", alignItems: "center" },
635
- children: [
636
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: option.label }),
637
- option.value === value && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
638
- "svg",
639
- {
640
- style: { width: "1rem", height: "1rem", color: "#3b82f6" },
641
- fill: "currentColor",
642
- viewBox: "0 0 20 20",
643
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
644
- "path",
645
- {
646
- fillRule: "evenodd",
647
- 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",
648
- clipRule: "evenodd"
649
- }
650
- )
651
- }
652
- )
653
- ]
1294
+ cx: size / 2,
1295
+ cy: size / 2,
1296
+ r: radius,
1297
+ stroke: "rgba(255, 255, 255, 0.2)",
1298
+ strokeWidth,
1299
+ fill: "transparent"
654
1300
  }
655
1301
  ),
656
- option.description && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
657
- "div",
1302
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1303
+ "circle",
658
1304
  {
659
- style: {
660
- fontSize: "0.75rem",
661
- color: "#9ca3af",
662
- marginTop: "0.25rem",
663
- fontWeight: "normal"
664
- },
665
- children: option.description
1305
+ cx: size / 2,
1306
+ cy: size / 2,
1307
+ r: radius,
1308
+ stroke: color,
1309
+ strokeWidth,
1310
+ fill: "transparent",
1311
+ strokeDasharray,
1312
+ strokeDashoffset,
1313
+ strokeLinecap: "round",
1314
+ style: { transition: "stroke-dashoffset 0.5s ease-in-out" }
666
1315
  }
667
1316
  )
668
- ]
1317
+ ] }),
1318
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1319
+ "div",
1320
+ {
1321
+ style: {
1322
+ position: "absolute",
1323
+ top: "50%",
1324
+ left: "50%",
1325
+ transform: "translate(-50%, -50%)",
1326
+ fontSize: "11px",
1327
+ fontWeight: "700",
1328
+ color: "white",
1329
+ textAlign: "center",
1330
+ textShadow: "0 1px 2px rgba(0, 0, 0, 0.5)"
1331
+ },
1332
+ children: [
1333
+ value.toFixed(1),
1334
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
1335
+ ]
1336
+ }
1337
+ )
1338
+ ]
1339
+ }
1340
+ ),
1341
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1342
+ "div",
1343
+ {
1344
+ style: {
1345
+ fontSize: "9px",
1346
+ marginTop: "4px",
1347
+ opacity: 0.9,
1348
+ color: "white"
669
1349
  },
670
- option.value
671
- )) })
672
- ] })
1350
+ children: label
1351
+ }
1352
+ )
673
1353
  ]
674
1354
  }
675
1355
  );
676
1356
  };
1357
+ var Sparkline = ({ data, width, height, color }) => {
1358
+ if (!data || data.length < 2) {
1359
+ return null;
1360
+ }
1361
+ const max = Math.max(...data);
1362
+ const min = Math.min(...data);
1363
+ const range = max - min;
1364
+ if (range === 0) {
1365
+ return null;
1366
+ }
1367
+ const points = data.map((value, index) => {
1368
+ const x = index / (data.length - 1) * (width - 8);
1369
+ const y = height - 8 - (value - min) / range * (height - 8);
1370
+ return `${x + 4},${y + 4}`;
1371
+ }).join(" ");
1372
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1373
+ "div",
1374
+ {
1375
+ style: {
1376
+ width,
1377
+ height,
1378
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
1379
+ border: "1px solid rgba(255, 255, 255, 0.3)",
1380
+ borderRadius: "4px",
1381
+ display: "flex",
1382
+ alignItems: "center",
1383
+ justifyContent: "center",
1384
+ boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)"
1385
+ },
1386
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { width, height, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) })
1387
+ }
1388
+ );
1389
+ };
1390
+ var EquipmentIndicatorWithSparkline = ({
1391
+ svgX,
1392
+ svgY,
1393
+ color,
1394
+ label,
1395
+ size = 30,
1396
+ sparklineData,
1397
+ sparklineOffset = { x: 40, y: 0 }
1398
+ }) => {
1399
+ const hasSparkline = sparklineData && sparklineData.length > 1 && Math.max(...sparklineData) !== Math.min(...sparklineData);
1400
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1401
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1402
+ "div",
1403
+ {
1404
+ style: {
1405
+ width: size,
1406
+ height: size,
1407
+ borderRadius: "50%",
1408
+ backgroundColor: color,
1409
+ display: "flex",
1410
+ alignItems: "center",
1411
+ justifyContent: "center",
1412
+ color: "white",
1413
+ fontSize: "7px",
1414
+ fontWeight: "700",
1415
+ textAlign: "center",
1416
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
1417
+ border: "2px solid rgba(255, 255, 255, 0.3)"
1418
+ },
1419
+ children: label
1420
+ }
1421
+ ) }),
1422
+ hasSparkline && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Sparkline, { data: sparklineData, width: 60, height: 20, color }) })
1423
+ ] });
1424
+ };
1425
+ var EquipmentIndicator = ({
1426
+ svgX,
1427
+ svgY,
1428
+ color,
1429
+ label,
1430
+ size = 30,
1431
+ style,
1432
+ className
1433
+ }) => {
1434
+ const overlayStyle = style !== void 0 ? { transform: "translate(-50%, -50%)", ...style } : { transform: "translate(-50%, -50%)" };
1435
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1436
+ "div",
1437
+ {
1438
+ style: {
1439
+ width: size,
1440
+ height: size,
1441
+ borderRadius: "50%",
1442
+ backgroundColor: color,
1443
+ display: "flex",
1444
+ alignItems: "center",
1445
+ justifyContent: "center",
1446
+ color: "white",
1447
+ fontSize: "7px",
1448
+ fontWeight: "700",
1449
+ textAlign: "center",
1450
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
1451
+ border: "2px solid rgba(255, 255, 255, 0.3)"
1452
+ },
1453
+ children: label
1454
+ }
1455
+ ) });
1456
+ };
677
1457
 
678
- // src/ControlPanel.tsx
679
- var import_react3 = require("react");
680
- var import_jsx_runtime5 = require("react/jsx-runtime");
681
- var ControlPanel = ({
682
- title,
683
- selectedMode,
684
- modeOptions,
685
- onModeChange,
686
- setpointValue,
687
- onSetpointChange,
688
- secondSetpointValue,
689
- onSecondSetpointChange,
690
- modeConfigs = {},
691
- defaultUnit = "Units",
692
- defaultLabel = "Setpoint",
693
- defaultMin = 0,
694
- defaultMax = 100,
695
- defaultPrecision = 2,
696
- status = "normal",
697
- collapsed = false,
698
- onCollapseChange,
699
- size = "medium",
700
- setpointReadOnly = false,
701
- showStartStopButtons = false,
702
- isRunning = false,
703
- onStart,
704
- onStop,
705
- startButtonText = "Start",
706
- stopButtonText = "Stop",
1458
+ // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
1459
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1460
+ function FullscreenWorkspace({
1461
+ svgContent,
1462
+ overlays,
1463
+ leftPanel,
1464
+ rightPanel,
1465
+ footer,
1466
+ tabs,
1467
+ activeTab,
1468
+ onTabChange,
1469
+ defaultLeftCollapsed = false,
1470
+ defaultRightCollapsed = false,
1471
+ leftCollapsed: leftCollapsedProp,
1472
+ rightCollapsed: rightCollapsedProp,
1473
+ onLeftCollapseChange,
1474
+ onRightCollapseChange,
1475
+ displayMode,
1476
+ defaultDisplayMode = "standard",
1477
+ onDisplayModeChange,
1478
+ showDisplayModeToggle = true,
1479
+ showZoomControls = false,
1480
+ onZoomIn,
1481
+ onZoomOut,
1482
+ onResetZoom,
1483
+ zoomDisabled = false,
707
1484
  className = "",
708
- ...props
709
- }) => {
710
- const [isExpanded, setIsExpanded] = (0, import_react3.useState)(!collapsed);
711
- const toggleExpanded = () => {
712
- const newExpanded = !isExpanded;
713
- setIsExpanded(newExpanded);
714
- onCollapseChange?.(!newExpanded);
715
- };
716
- const currentModeConfig = modeConfigs[selectedMode] || {};
717
- const currentUnit = currentModeConfig.unit || defaultUnit;
718
- const currentLabel = currentModeConfig.label || defaultLabel;
719
- const currentMin = currentModeConfig.min ?? defaultMin;
720
- const currentMax = currentModeConfig.max ?? defaultMax;
721
- const currentPrecision = currentModeConfig.precision ?? defaultPrecision;
722
- const hasSecondSetpoint = currentModeConfig.hasSecondSetpoint || false;
723
- const getSizeStyles = () => {
724
- switch (size) {
725
- case "small":
726
- return {
727
- padding: "1rem",
728
- titleSize: "1rem",
729
- gap: "0.75rem"
730
- };
731
- case "large":
732
- return {
733
- padding: "1.5rem",
734
- titleSize: "1.5rem",
735
- gap: "1.25rem"
736
- };
737
- default:
738
- return {
739
- padding: "1.25rem",
740
- titleSize: "1.125rem",
741
- gap: "1rem"
742
- };
1485
+ ...rest
1486
+ }) {
1487
+ const [leftCollapsedState, setLeftCollapsedState] = import_react6.default.useState(defaultLeftCollapsed);
1488
+ const [rightCollapsedState, setRightCollapsedState] = import_react6.default.useState(defaultRightCollapsed);
1489
+ const [internalDisplayMode, setInternalDisplayMode] = import_react6.default.useState(displayMode ?? defaultDisplayMode);
1490
+ const [internalTab, setInternalTab] = import_react6.default.useState(
1491
+ tabs && tabs.length > 0 ? tabs[0].value : ""
1492
+ );
1493
+ const leftCollapsed = leftCollapsedProp ?? leftCollapsedState;
1494
+ const rightCollapsed = rightCollapsedProp ?? rightCollapsedState;
1495
+ const isDisplayModeControlled = displayMode !== void 0;
1496
+ const currentDisplayMode = isDisplayModeControlled ? displayMode : internalDisplayMode;
1497
+ const isTabControlled = activeTab !== void 0 && activeTab !== null;
1498
+ const resolvedTabs = import_react6.default.useMemo(() => tabs ?? [], [tabs]);
1499
+ const defaultTabValue = resolvedTabs.length > 0 ? resolvedTabs[0].value : "";
1500
+ const currentTab = isTabControlled ? activeTab : internalTab || defaultTabValue;
1501
+ import_react6.default.useEffect(() => {
1502
+ if (resolvedTabs.length > 0) {
1503
+ const values = resolvedTabs.map((tab) => tab.value);
1504
+ if (!values.includes(currentTab)) {
1505
+ const fallback = activeTab ?? defaultTabValue;
1506
+ setInternalTab(fallback);
1507
+ }
743
1508
  }
744
- };
745
- const getStatusStyles = () => {
746
- switch (status) {
747
- case "alarm":
748
- return {
749
- borderColor: "var(--control-panel-alarm-border, #ef4444)",
750
- backgroundColor: "var(--control-panel-alarm-bg, rgba(239, 68, 68, 0.1))",
751
- titleColor: "var(--control-panel-alarm-text, #fecaca)",
752
- boxShadow: "var(--control-panel-alarm-shadow, 0 0 20px rgba(239, 68, 68, 0.3))",
753
- glowEffect: "var(--control-panel-alarm-glow, 0 0 30px rgba(239, 68, 68, 0.2))"
754
- };
755
- case "warning":
756
- return {
757
- borderColor: "var(--control-panel-warning-border, #f59e0b)",
758
- backgroundColor: "var(--control-panel-warning-bg, rgba(245, 158, 11, 0.1))",
759
- titleColor: "var(--control-panel-warning-text, #fed7aa)",
760
- boxShadow: "var(--control-panel-warning-shadow, 0 0 20px rgba(245, 158, 11, 0.3))",
761
- glowEffect: "var(--control-panel-warning-glow, 0 0 30px rgba(245, 158, 11, 0.2))"
762
- };
763
- case "disabled":
764
- return {
765
- borderColor: "var(--control-panel-disabled-border, #6b7280)",
766
- backgroundColor: "var(--control-panel-disabled-bg, rgba(107, 114, 128, 0.1))",
767
- titleColor: "var(--control-panel-disabled-text, #9ca3af)",
768
- boxShadow: "var(--control-panel-disabled-shadow, 0 8px 32px rgba(0, 0, 0, 0.2))",
769
- glowEffect: "var(--control-panel-disabled-glow, none)"
770
- };
771
- default:
772
- return {
773
- borderColor: "var(--control-panel-normal-border, #64748b)",
774
- backgroundColor: "var(--control-panel-normal-bg, rgba(30, 41, 59, 0.9))",
775
- titleColor: "var(--control-panel-normal-text, #f1f5f9)",
776
- boxShadow: "var(--control-panel-normal-shadow, 0 8px 32px rgba(0, 0, 0, 0.3))",
777
- glowEffect: "var(--control-panel-normal-glow, 0 0 20px rgba(59, 130, 246, 0.1))"
778
- };
1509
+ }, [resolvedTabs, activeTab, currentTab, defaultTabValue]);
1510
+ import_react6.default.useEffect(() => {
1511
+ if (displayMode !== void 0) {
1512
+ setInternalDisplayMode(displayMode);
779
1513
  }
1514
+ }, [displayMode]);
1515
+ const handleLeftToggle = () => {
1516
+ const next = !leftCollapsed;
1517
+ if (leftCollapsedProp === void 0) {
1518
+ setLeftCollapsedState(next);
1519
+ }
1520
+ onLeftCollapseChange?.(next);
780
1521
  };
781
- const sizeStyles = getSizeStyles();
782
- const statusStyles = getStatusStyles();
783
- const panelStyle = {
784
- border: "2px solid",
785
- borderRadius: "1.5rem",
786
- backdropFilter: "blur(12px)",
787
- transition: "all 400ms cubic-bezier(0.4, 0, 0.2, 1)",
788
- position: "relative",
789
- overflow: "hidden",
790
- minWidth: "300px",
791
- maxWidth: "400px",
792
- minHeight: "400px",
793
- width: "100%",
794
- ...statusStyles,
795
- boxShadow: isExpanded ? statusStyles.glowEffect : statusStyles.boxShadow
796
- };
797
- const headerStyle = {
798
- display: "flex",
799
- alignItems: "center",
800
- justifyContent: "space-between",
801
- padding: sizeStyles.padding,
802
- cursor: onCollapseChange ? "pointer" : "default",
803
- borderBottom: isExpanded ? `1px solid ${statusStyles.borderColor}40` : "none",
804
- transition: "all 300ms ease"
805
- };
806
- const titleStyle = {
807
- fontSize: sizeStyles.titleSize,
808
- fontWeight: "bold",
809
- color: statusStyles.titleColor,
810
- fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
811
- letterSpacing: "0.05em",
812
- margin: 0
813
- };
814
- const contentStyle = {
815
- padding: isExpanded ? sizeStyles.padding : "0",
816
- paddingTop: isExpanded ? sizeStyles.padding : "0",
817
- maxHeight: isExpanded ? "500px" : "0",
818
- opacity: isExpanded ? 1 : 0,
819
- overflow: "hidden",
820
- transition: "all 400ms cubic-bezier(0.4, 0, 0.2, 1)",
821
- display: "flex",
822
- flexDirection: "column",
823
- gap: sizeStyles.gap,
824
- justifyContent: "space-between",
825
- flex: 1
1522
+ const handleRightToggle = () => {
1523
+ const next = !rightCollapsed;
1524
+ if (rightCollapsedProp === void 0) {
1525
+ setRightCollapsedState(next);
1526
+ }
1527
+ onRightCollapseChange?.(next);
826
1528
  };
827
- const chevronStyle = {
828
- width: "1.5rem",
829
- height: "1.5rem",
830
- color: statusStyles.titleColor,
831
- transform: `rotate(${isExpanded ? "180deg" : "0deg"})`,
832
- transition: "transform 300ms ease",
833
- opacity: onCollapseChange ? 1 : 0.3
1529
+ const handleModeToggle = () => {
1530
+ const nextMode = currentDisplayMode === "standard" ? "dashboard" : "standard";
1531
+ if (!isDisplayModeControlled) {
1532
+ setInternalDisplayMode(nextMode);
1533
+ }
1534
+ onDisplayModeChange?.(nextMode);
834
1535
  };
835
- const statusBadgeStyle = {
836
- position: "absolute",
837
- top: "0.5rem",
838
- right: "0.5rem",
839
- width: "0.75rem",
840
- height: "0.75rem",
841
- borderRadius: "50%",
842
- backgroundColor: status === "alarm" ? "#ef4444" : status === "warning" ? "#f59e0b" : status === "disabled" ? "#6b7280" : "#22c55e",
843
- boxShadow: `0 0 10px ${status === "alarm" ? "#ef4444" : status === "warning" ? "#f59e0b" : status === "disabled" ? "#6b7280" : "#22c55e"}80`,
844
- animation: status === "alarm" ? "pulse 2s infinite" : "none"
1536
+ const handleTabChangeInternal = (_, value) => {
1537
+ if (!isTabControlled) {
1538
+ setInternalTab(value);
1539
+ }
1540
+ onTabChange?.(value);
845
1541
  };
846
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: panelStyle, className: `control-panel glass-card ${className}`, ...props, children: [
847
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: statusBadgeStyle }),
848
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: headerStyle, onClick: onCollapseChange ? toggleExpanded : void 0, children: [
849
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { style: titleStyle, children: title }),
850
- onCollapseChange && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { style: chevronStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
851
- ] }),
852
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: contentStyle, children: [
853
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
854
- Selector,
855
- {
856
- value: selectedMode,
857
- onChange: onModeChange,
858
- options: modeOptions,
859
- label: "Control Mode",
860
- status,
861
- size: size === "small" ? "small" : size === "large" ? "large" : "medium",
862
- disabled: status === "disabled"
863
- }
864
- ) }),
865
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
866
- ValueEntry,
867
- {
868
- value: setpointValue,
869
- onChange: onSetpointChange,
870
- label: currentLabel,
871
- unit: currentUnit,
872
- min: currentMin,
873
- max: currentMax,
874
- precision: currentPrecision,
875
- status,
876
- readOnly: setpointReadOnly || status === "disabled",
877
- disabled: status === "disabled"
878
- }
879
- ) }),
880
- hasSecondSetpoint && onSecondSetpointChange && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
881
- ValueEntry,
882
- {
883
- value: secondSetpointValue || 0,
884
- onChange: onSecondSetpointChange,
885
- label: currentModeConfig.secondLabel || "Time",
886
- unit: currentModeConfig.secondUnit || "sec",
887
- min: currentModeConfig.secondMin ?? 0,
888
- max: currentModeConfig.secondMax ?? 999,
889
- precision: currentModeConfig.secondPrecision ?? 0,
890
- status,
891
- readOnly: setpointReadOnly || status === "disabled",
892
- disabled: status === "disabled"
893
- }
894
- ) }),
895
- showStartStopButtons && (onStart || onStop) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: "0.75rem" }, children: [
896
- onStart && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
897
- Button,
1542
+ const currentTabContent = resolvedTabs.find((tab) => tab.value === currentTab)?.content ?? null;
1543
+ const showLeftToggle = Boolean(leftPanel);
1544
+ const showRightToggle = Boolean(rightPanel);
1545
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1546
+ FullscreenContainer,
1547
+ {
1548
+ leftCollapsed,
1549
+ rightCollapsed,
1550
+ className: `tff-svg-container ${className}`.trim(),
1551
+ ...rest,
1552
+ children: [
1553
+ showLeftToggle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1554
+ LeftToggleButton,
898
1555
  {
899
- variant: "primary",
900
- onClick: onStart,
901
- disabled: isRunning || status === "disabled",
902
- style: {
903
- flex: 1,
904
- fontSize: "0.875rem",
905
- padding: "0.75rem 1rem",
906
- backgroundColor: isRunning ? "#6b7280" : void 0
907
- },
908
- children: startButtonText
1556
+ collapsed: leftCollapsed,
1557
+ onClick: handleLeftToggle,
1558
+ "aria-label": leftCollapsed ? "Expand left panel" : "Collapse left panel",
1559
+ children: leftCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChevronRight, {}) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChevronLeft, {})
909
1560
  }
910
1561
  ),
911
- onStop && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
912
- Button,
1562
+ showRightToggle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1563
+ RightToggleButton,
913
1564
  {
914
- variant: "secondary",
915
- onClick: onStop,
916
- disabled: !isRunning || status === "disabled",
917
- style: {
918
- flex: 1,
919
- fontSize: "0.875rem",
920
- padding: "0.75rem 1rem",
921
- backgroundColor: !isRunning ? "#6b7280" : "#dc2626",
922
- borderColor: !isRunning ? "#6b7280" : "#dc2626"
923
- },
924
- children: stopButtonText
1565
+ collapsed: rightCollapsed,
1566
+ onClick: handleRightToggle,
1567
+ "aria-label": rightCollapsed ? "Expand right panel" : "Collapse right panel",
1568
+ children: rightCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChevronLeft, {}) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChevronRight, {})
925
1569
  }
926
- )
927
- ] }),
928
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
929
- "div",
930
- {
931
- className: "control-panel-info",
932
- style: {
933
- display: "flex",
934
- justifyContent: "space-between",
935
- alignItems: "center",
936
- padding: "0.5rem 0",
937
- fontSize: "0.75rem",
938
- color: "var(--control-panel-info-text, #9ca3af)",
939
- borderTop: `1px solid ${statusStyles.borderColor}20`,
940
- fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
941
- },
942
- children: [
943
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
944
- "Mode: ",
945
- selectedMode.toUpperCase()
946
- ] }),
947
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: "1rem" }, children: [
948
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
949
- "SP: ",
950
- String(setpointValue),
951
- currentUnit
952
- ] }),
953
- hasSecondSetpoint && secondSetpointValue && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
954
- currentModeConfig.secondLabel,
955
- ": ",
956
- String(secondSetpointValue),
957
- currentModeConfig.secondUnit
958
- ] })
959
- ] })
960
- ]
961
- }
962
- )
963
- ] })
964
- ] });
965
- };
1570
+ ),
1571
+ showDisplayModeToggle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1572
+ DisplayModeToggle,
1573
+ {
1574
+ mode: currentDisplayMode,
1575
+ onClick: handleModeToggle,
1576
+ "aria-label": "Toggle display mode",
1577
+ children: currentDisplayMode === "dashboard" ? "Dashboard Mode" : "Standard Mode"
1578
+ }
1579
+ ),
1580
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(SVGArea, { children: [
1581
+ showZoomControls && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ZoomControls, { children: [
1582
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1583
+ ZoomButton,
1584
+ {
1585
+ onClick: onZoomIn,
1586
+ disabled: zoomDisabled || !onZoomIn,
1587
+ size: "small",
1588
+ "aria-label": "Zoom in",
1589
+ children: "+"
1590
+ }
1591
+ ),
1592
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1593
+ ZoomButton,
1594
+ {
1595
+ onClick: onZoomOut,
1596
+ disabled: zoomDisabled || !onZoomOut,
1597
+ size: "small",
1598
+ "aria-label": "Zoom out",
1599
+ children: "-"
1600
+ }
1601
+ ),
1602
+ onResetZoom && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1603
+ ZoomButton,
1604
+ {
1605
+ onClick: onResetZoom,
1606
+ disabled: zoomDisabled,
1607
+ size: "small",
1608
+ "aria-label": "Reset zoom",
1609
+ children: "Reset"
1610
+ }
1611
+ )
1612
+ ] }),
1613
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(FixedSVGContainer, { className: "svg-container", children: [
1614
+ svgContent,
1615
+ overlays
1616
+ ] }) })
1617
+ ] }),
1618
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LeftPanel, { collapsed: leftCollapsed, children: resolvedTabs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1619
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1620
+ PanelTabs,
1621
+ {
1622
+ value: currentTab,
1623
+ onChange: handleTabChangeInternal,
1624
+ "aria-label": "Left panel tabs",
1625
+ children: resolvedTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material3.Tab, { label: tab.label, value: tab.value }, tab.value))
1626
+ }
1627
+ ),
1628
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PanelContent, { children: currentTabContent })
1629
+ ] }) : leftPanel }),
1630
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
1631
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FooterPanel, { children: footer })
1632
+ ]
1633
+ }
1634
+ );
1635
+ }
966
1636
 
967
- // src/ThemeContext.tsx
968
- var import_react4 = require("react");
969
- var import_jsx_runtime6 = require("react/jsx-runtime");
970
- var ThemeContext = (0, import_react4.createContext)(void 0);
1637
+ // src/theme/ThemeContext.tsx
1638
+ var import_react7 = require("react");
1639
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1640
+ var ThemeContext = (0, import_react7.createContext)(void 0);
971
1641
  var useTheme = () => {
972
- const context = (0, import_react4.useContext)(ThemeContext);
1642
+ const context = (0, import_react7.useContext)(ThemeContext);
973
1643
  if (!context) {
974
1644
  throw new Error("useTheme must be used within a ThemeProvider");
975
1645
  }
976
1646
  return context;
977
1647
  };
978
1648
  var ThemeProvider = ({ children }) => {
979
- const [theme, setThemeState] = (0, import_react4.useState)("modern");
980
- (0, import_react4.useEffect)(() => {
1649
+ const [theme, setThemeState] = (0, import_react7.useState)("modern");
1650
+ (0, import_react7.useEffect)(() => {
981
1651
  document.body.className = "";
982
1652
  document.body.classList.add(`theme-${theme}`);
983
1653
  document.documentElement.className = "";
@@ -989,11 +1659,11 @@ var ThemeProvider = ({ children }) => {
989
1659
  const setTheme = (newTheme) => {
990
1660
  setThemeState(newTheme);
991
1661
  };
992
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
1662
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
993
1663
  };
994
1664
 
995
- // src/ThemeToggle.tsx
996
- var import_jsx_runtime7 = require("react/jsx-runtime");
1665
+ // src/theme/ThemeToggle.tsx
1666
+ var import_jsx_runtime12 = require("react/jsx-runtime");
997
1667
  var ThemeToggle = ({
998
1668
  size = "medium",
999
1669
  position = "top-right",
@@ -1064,21 +1734,48 @@ var ThemeToggle = ({
1064
1734
  transition: "all 0.2s ease",
1065
1735
  boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
1066
1736
  };
1067
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
1068
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
1069
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: toggleStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: thumbStyle }) }),
1070
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
1737
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
1738
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
1739
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: toggleStyle, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: thumbStyle }) }),
1740
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
1071
1741
  ] });
1072
1742
  };
1073
1743
  // Annotate the CommonJS export names for ESM import in node:
1074
1744
  0 && (module.exports = {
1075
1745
  Button,
1746
+ CardHeader,
1747
+ CardUnit,
1748
+ CardValue,
1749
+ CircularGauge,
1076
1750
  ControlPanel,
1751
+ DashboardCard,
1752
+ DisplayModeToggle,
1753
+ EquipmentIndicator,
1754
+ EquipmentIndicatorWithSparkline,
1755
+ FixedSVGContainer,
1756
+ FooterPanel,
1757
+ FullscreenContainer,
1758
+ FullscreenWorkspace,
1759
+ LeftPanel,
1760
+ LeftToggleButton,
1761
+ LegacyValueEntry,
1762
+ PanelContent,
1763
+ PanelTabs,
1764
+ RightPanel,
1765
+ RightToggleButton,
1766
+ SVGArea,
1767
+ SVGLockedOverlay,
1768
+ ScrollableSVGWrapper,
1077
1769
  Selector,
1770
+ Sparkline,
1078
1771
  StatusIndicator,
1079
1772
  ThemeProvider,
1080
1773
  ThemeToggle,
1774
+ TrendLine,
1081
1775
  ValueEntry,
1776
+ ZoomButton,
1777
+ ZoomControls,
1778
+ overlayStyles,
1082
1779
  useTheme
1083
1780
  });
1084
1781
  //# sourceMappingURL=index.cjs.map