@procaaso/alphinity-ui-components 1.0.0

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.js ADDED
@@ -0,0 +1,1050 @@
1
+ // src/Button.tsx
2
+ import { jsx } from "react/jsx-runtime";
3
+ var Button = ({
4
+ variant = "primary",
5
+ children,
6
+ className = "",
7
+ ...props
8
+ }) => {
9
+ 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";
10
+ 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";
11
+ return /* @__PURE__ */ jsx("button", { className: `${baseStyles} ${variantStyles} ${className}`.trim(), ...props, children });
12
+ };
13
+
14
+ // src/TestValueEntry.tsx
15
+ import { useState, useCallback } from "react";
16
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
17
+ var ValueEntry = ({
18
+ value,
19
+ onChange,
20
+ unit,
21
+ status = "normal",
22
+ min,
23
+ max,
24
+ precision = 2,
25
+ inputType = "numeric",
26
+ label,
27
+ readOnly = false,
28
+ className = "",
29
+ disabled,
30
+ ...props
31
+ }) => {
32
+ const [displayValue, setDisplayValue] = useState(String(value));
33
+ const [isEditing, setIsEditing] = useState(false);
34
+ const handleFocus = useCallback(() => {
35
+ setIsEditing(true);
36
+ setDisplayValue(String(value));
37
+ }, [value]);
38
+ const handleBlur = useCallback(() => {
39
+ setIsEditing(false);
40
+ let newValue = displayValue;
41
+ if (inputType === "numeric") {
42
+ const numValue = parseFloat(displayValue);
43
+ if (!isNaN(numValue)) {
44
+ let constrainedValue = numValue;
45
+ if (min !== void 0) constrainedValue = Math.max(min, constrainedValue);
46
+ if (max !== void 0) constrainedValue = Math.min(max, constrainedValue);
47
+ constrainedValue = parseFloat(constrainedValue.toFixed(precision));
48
+ newValue = constrainedValue;
49
+ setDisplayValue(String(constrainedValue));
50
+ } else {
51
+ setDisplayValue(String(value));
52
+ return;
53
+ }
54
+ }
55
+ if (newValue !== value) {
56
+ onChange(newValue);
57
+ }
58
+ }, [displayValue, inputType, min, max, precision, value, onChange]);
59
+ const handleChange = useCallback((e) => {
60
+ setDisplayValue(e.target.value);
61
+ }, []);
62
+ const handleKeyDown = useCallback(
63
+ (e) => {
64
+ if (e.key === "Enter") {
65
+ e.currentTarget.blur();
66
+ }
67
+ if (e.key === "Escape") {
68
+ setDisplayValue(String(value));
69
+ e.currentTarget.blur();
70
+ }
71
+ },
72
+ [value]
73
+ );
74
+ const displayText = isEditing ? displayValue : inputType === "numeric" ? Number(value).toFixed(precision) : String(value);
75
+ const getStatusStyles = () => {
76
+ switch (status) {
77
+ case "alarm":
78
+ return {
79
+ borderColor: "#ef4444",
80
+ backgroundColor: "rgba(239, 68, 68, 0.15)",
81
+ color: "#fecaca",
82
+ boxShadow: "0 0 20px rgba(239, 68, 68, 0.3)"
83
+ };
84
+ case "warning":
85
+ return {
86
+ borderColor: "#f59e0b",
87
+ backgroundColor: "rgba(245, 158, 11, 0.15)",
88
+ color: "#fed7aa",
89
+ boxShadow: "0 0 20px rgba(245, 158, 11, 0.3)"
90
+ };
91
+ case "disabled":
92
+ return {
93
+ borderColor: "#6b7280",
94
+ backgroundColor: "rgba(107, 114, 128, 0.1)",
95
+ color: "#9ca3af",
96
+ cursor: "not-allowed"
97
+ };
98
+ default:
99
+ return {
100
+ borderColor: "#64748b",
101
+ backgroundColor: "rgba(30, 41, 59, 0.9)",
102
+ color: "#f1f5f9",
103
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.3)"
104
+ };
105
+ }
106
+ };
107
+ const statusStyles = getStatusStyles();
108
+ const inputStyle = {
109
+ width: "12rem",
110
+ height: "4rem",
111
+ padding: unit ? "1rem 4rem 1rem 1.5rem" : "1rem 1.5rem",
112
+ border: "2px solid",
113
+ borderRadius: "1.5rem",
114
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
115
+ fontSize: "1.25rem",
116
+ fontWeight: "bold",
117
+ textAlign: "center",
118
+ outline: "none",
119
+ transition: "all 300ms ease",
120
+ backdropFilter: "blur(8px)",
121
+ ...statusStyles
122
+ };
123
+ const inputStyleFocus = {
124
+ ...inputStyle,
125
+ borderColor: "#60a5fa",
126
+ boxShadow: "0 0 0 4px rgba(96, 165, 250, 0.3), " + (statusStyles.boxShadow || "0 8px 32px rgba(0, 0, 0, 0.3)"),
127
+ transform: "scale(1.02)"
128
+ };
129
+ const unitStyle = {
130
+ position: "absolute",
131
+ right: "0.75rem",
132
+ top: "50%",
133
+ transform: "translateY(-50%)",
134
+ padding: "0.5rem 0.75rem",
135
+ fontSize: "1rem",
136
+ fontWeight: "bold",
137
+ color: "#ffffff",
138
+ backgroundColor: "#3b82f6",
139
+ borderRadius: "0.5rem",
140
+ border: "2px solid #60a5fa",
141
+ backdropFilter: "blur(4px)",
142
+ pointerEvents: "none",
143
+ zIndex: 10,
144
+ boxShadow: "0 2px 8px rgba(59, 130, 246, 0.4)"
145
+ };
146
+ return /* @__PURE__ */ jsxs(
147
+ "div",
148
+ {
149
+ style: {
150
+ display: "inline-flex",
151
+ flexDirection: "column",
152
+ alignItems: "center",
153
+ gap: "0.75rem"
154
+ },
155
+ children: [
156
+ label && /* @__PURE__ */ jsx2(
157
+ "label",
158
+ {
159
+ style: {
160
+ fontSize: "0.875rem",
161
+ fontWeight: "600",
162
+ color: "#cbd5e1",
163
+ textTransform: "uppercase",
164
+ letterSpacing: "0.05em"
165
+ },
166
+ children: label
167
+ }
168
+ ),
169
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", display: "inline-flex", alignItems: "center" }, children: [
170
+ /* @__PURE__ */ jsx2(
171
+ "input",
172
+ {
173
+ type: "text",
174
+ value: displayText,
175
+ onChange: handleChange,
176
+ onFocus: (e) => {
177
+ Object.assign(e.target.style, inputStyleFocus);
178
+ handleFocus();
179
+ },
180
+ onBlur: (e) => {
181
+ Object.assign(e.target.style, inputStyle);
182
+ handleBlur();
183
+ },
184
+ onKeyDown: handleKeyDown,
185
+ disabled,
186
+ readOnly,
187
+ style: inputStyle,
188
+ ...props
189
+ }
190
+ ),
191
+ unit && /* @__PURE__ */ jsx2("span", { style: unitStyle, children: unit }),
192
+ status === "alarm" && /* @__PURE__ */ jsx2(
193
+ "div",
194
+ {
195
+ style: {
196
+ position: "absolute",
197
+ top: "-8px",
198
+ right: "-8px",
199
+ width: "1rem",
200
+ height: "1rem",
201
+ backgroundColor: "#ef4444",
202
+ borderRadius: "50%",
203
+ boxShadow: "0 0 10px rgba(239, 68, 68, 0.8)",
204
+ animation: "pulse 2s infinite"
205
+ }
206
+ }
207
+ ),
208
+ status === "warning" && /* @__PURE__ */ jsx2(
209
+ "div",
210
+ {
211
+ style: {
212
+ position: "absolute",
213
+ top: "-8px",
214
+ right: "-8px",
215
+ width: "1rem",
216
+ height: "1rem",
217
+ backgroundColor: "#f59e0b",
218
+ borderRadius: "50%",
219
+ boxShadow: "0 0 10px rgba(245, 158, 11, 0.8)"
220
+ }
221
+ }
222
+ )
223
+ ] })
224
+ ]
225
+ }
226
+ );
227
+ };
228
+
229
+ // src/StatusIndicator.tsx
230
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
231
+ var StatusIndicator = ({
232
+ status,
233
+ size = "medium",
234
+ animation = "none",
235
+ label,
236
+ labelPosition = "right",
237
+ shape = "circle",
238
+ led = true,
239
+ className = "",
240
+ ...props
241
+ }) => {
242
+ const sizeStyles = {
243
+ small: "w-5 h-5",
244
+ medium: "w-7 h-7",
245
+ large: "w-10 h-10"
246
+ };
247
+ const shapeStyles = {
248
+ circle: "rounded-full",
249
+ square: "rounded-lg",
250
+ diamond: "rotate-45 rounded-lg"
251
+ };
252
+ const statusStyles = {
253
+ off: "bg-gradient-to-br from-slate-500 to-slate-600 border-slate-400 shadow-slate-500/30",
254
+ normal: "bg-gradient-to-br from-emerald-400 via-green-500 to-green-600 border-emerald-300 shadow-green-500/70",
255
+ alarm: "bg-gradient-to-br from-red-400 via-red-500 to-red-600 border-red-300 shadow-red-500/70",
256
+ warning: "bg-gradient-to-br from-amber-400 via-yellow-500 to-orange-500 border-amber-300 shadow-yellow-500/70",
257
+ active: "bg-gradient-to-br from-blue-400 via-blue-500 to-indigo-600 border-blue-300 shadow-blue-500/70",
258
+ fault: "bg-gradient-to-br from-purple-400 via-purple-500 to-violet-600 border-purple-300 shadow-purple-500/70"
259
+ };
260
+ const animationStyles = {
261
+ none: "",
262
+ pulse: "animate-pulse",
263
+ blink: "animate-bounce",
264
+ flash: "animate-ping"
265
+ };
266
+ const ledEffect = led ? "shadow-lg border-2" : "border";
267
+ const glowEffect = status !== "off" && led ? "shadow-lg" : "";
268
+ const indicatorClasses = `
269
+ ${sizeStyles[size]}
270
+ ${shapeStyles[shape]}
271
+ ${statusStyles[status]}
272
+ ${animationStyles[animation]}
273
+ ${ledEffect}
274
+ ${glowEffect}
275
+ inline-block
276
+ transition-all
277
+ duration-300
278
+ `.trim().replace(/\s+/g, " ");
279
+ const labelClasses = "text-sm font-medium text-gray-700 uppercase tracking-wide select-none";
280
+ const getContainerLayout = () => {
281
+ switch (labelPosition) {
282
+ case "left":
283
+ return "inline-flex items-center gap-2 flex-row-reverse";
284
+ case "right":
285
+ return "inline-flex items-center gap-2";
286
+ case "top":
287
+ return "inline-flex flex-col-reverse items-center gap-1";
288
+ case "bottom":
289
+ return "inline-flex flex-col items-center gap-1";
290
+ default:
291
+ return "inline-flex items-center gap-2";
292
+ }
293
+ };
294
+ const getAriaLabel = () => {
295
+ if (label) {
296
+ return `${label}: ${status}`;
297
+ }
298
+ return `Status indicator: ${status}`;
299
+ };
300
+ const getAriaDescription = () => {
301
+ const descriptions = {
302
+ off: "Inactive or disabled state",
303
+ normal: "Normal operating condition",
304
+ alarm: "Critical alarm condition requiring attention",
305
+ warning: "Warning condition that should be monitored",
306
+ active: "Currently active or running",
307
+ fault: "System fault or error condition"
308
+ };
309
+ return descriptions[status];
310
+ };
311
+ return /* @__PURE__ */ jsxs2("div", { className: `${getContainerLayout()} ${className}`.trim(), ...props, children: [
312
+ /* @__PURE__ */ jsx3(
313
+ "div",
314
+ {
315
+ className: indicatorClasses,
316
+ role: "status",
317
+ "aria-label": getAriaLabel(),
318
+ "aria-description": getAriaDescription(),
319
+ "data-status": status,
320
+ "data-testid": `status-indicator-${status}`
321
+ }
322
+ ),
323
+ label && /* @__PURE__ */ jsx3("span", { className: labelClasses, children: label })
324
+ ] });
325
+ };
326
+
327
+ // src/Selector.tsx
328
+ import { useState as useState2, useRef, useEffect } from "react";
329
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
330
+ var Selector = ({
331
+ value,
332
+ onChange,
333
+ options,
334
+ placeholder = "Select option...",
335
+ disabled = false,
336
+ status = "normal",
337
+ size = "medium",
338
+ label,
339
+ dropdownUp = false,
340
+ className = "",
341
+ ...props
342
+ }) => {
343
+ const [isOpen, setIsOpen] = useState2(false);
344
+ const [focusedIndex, setFocusedIndex] = useState2(-1);
345
+ const selectorRef = useRef(null);
346
+ const dropdownRef = useRef(null);
347
+ useEffect(() => {
348
+ const handleClickOutside = (event) => {
349
+ if (selectorRef.current && !selectorRef.current.contains(event.target)) {
350
+ setIsOpen(false);
351
+ setFocusedIndex(-1);
352
+ }
353
+ };
354
+ document.addEventListener("mousedown", handleClickOutside);
355
+ return () => document.removeEventListener("mousedown", handleClickOutside);
356
+ }, []);
357
+ const handleKeyDown = (e) => {
358
+ if (disabled) return;
359
+ switch (e.key) {
360
+ case "Enter":
361
+ case " ":
362
+ e.preventDefault();
363
+ if (!isOpen) {
364
+ setIsOpen(true);
365
+ setFocusedIndex(
366
+ Math.max(
367
+ 0,
368
+ options.findIndex((opt) => opt.value === value)
369
+ )
370
+ );
371
+ } else if (focusedIndex >= 0) {
372
+ const selectedOption2 = options[focusedIndex];
373
+ if (!selectedOption2.disabled) {
374
+ onChange(selectedOption2.value);
375
+ setIsOpen(false);
376
+ setFocusedIndex(-1);
377
+ }
378
+ }
379
+ break;
380
+ case "Escape":
381
+ setIsOpen(false);
382
+ setFocusedIndex(-1);
383
+ break;
384
+ case "ArrowDown":
385
+ e.preventDefault();
386
+ if (!isOpen) {
387
+ setIsOpen(true);
388
+ setFocusedIndex(
389
+ Math.max(
390
+ 0,
391
+ options.findIndex((opt) => opt.value === value)
392
+ )
393
+ );
394
+ } else {
395
+ setFocusedIndex((prev) => {
396
+ const nextIndex = Math.min(prev + 1, options.length - 1);
397
+ return options[nextIndex]?.disabled ? prev : nextIndex;
398
+ });
399
+ }
400
+ break;
401
+ case "ArrowUp":
402
+ e.preventDefault();
403
+ if (isOpen) {
404
+ setFocusedIndex((prev) => {
405
+ const nextIndex = Math.max(prev - 1, 0);
406
+ return options[nextIndex]?.disabled ? prev : nextIndex;
407
+ });
408
+ }
409
+ break;
410
+ }
411
+ };
412
+ const selectedOption = options.find((opt) => opt.value === value);
413
+ const getSizeStyles = () => {
414
+ switch (size) {
415
+ case "small":
416
+ return {
417
+ height: "2.5rem",
418
+ padding: "0.5rem 0.75rem",
419
+ fontSize: "0.875rem",
420
+ iconSize: "1rem"
421
+ };
422
+ case "large":
423
+ return {
424
+ height: "4rem",
425
+ padding: "1rem 1.5rem",
426
+ fontSize: "1.25rem",
427
+ iconSize: "1.5rem"
428
+ };
429
+ default:
430
+ return {
431
+ height: "3rem",
432
+ padding: "0.75rem 1rem",
433
+ fontSize: "1rem",
434
+ iconSize: "1.25rem"
435
+ };
436
+ }
437
+ };
438
+ const getStatusStyles = () => {
439
+ switch (status) {
440
+ case "alarm":
441
+ return {
442
+ borderColor: "var(--selector-alarm-border, #ef4444)",
443
+ backgroundColor: "var(--selector-alarm-bg, rgba(239, 68, 68, 0.15))",
444
+ color: "var(--selector-alarm-text, #fecaca)",
445
+ boxShadow: "var(--selector-alarm-shadow, 0 0 20px rgba(239, 68, 68, 0.3))"
446
+ };
447
+ case "warning":
448
+ return {
449
+ borderColor: "var(--selector-warning-border, #f59e0b)",
450
+ backgroundColor: "var(--selector-warning-bg, rgba(245, 158, 11, 0.15))",
451
+ color: "var(--selector-warning-text, #fed7aa)",
452
+ boxShadow: "var(--selector-warning-shadow, 0 0 20px rgba(245, 158, 11, 0.3))"
453
+ };
454
+ case "disabled":
455
+ return {
456
+ borderColor: "var(--selector-disabled-border, #6b7280)",
457
+ backgroundColor: "var(--selector-disabled-bg, rgba(107, 114, 128, 0.1))",
458
+ color: "var(--selector-disabled-text, #9ca3af)",
459
+ cursor: "not-allowed"
460
+ };
461
+ default:
462
+ return {
463
+ borderColor: "var(--selector-normal-border, #64748b)",
464
+ backgroundColor: "var(--selector-normal-bg, rgba(30, 41, 59, 0.9))",
465
+ color: "var(--selector-normal-text, #f1f5f9)",
466
+ boxShadow: "var(--selector-normal-shadow, 0 8px 32px rgba(0, 0, 0, 0.3))"
467
+ };
468
+ }
469
+ };
470
+ const sizeStyles = getSizeStyles();
471
+ const statusStyles = getStatusStyles();
472
+ const selectorStyle = {
473
+ position: "relative",
474
+ width: "100%",
475
+ height: sizeStyles.height,
476
+ padding: sizeStyles.padding,
477
+ paddingRight: "3rem",
478
+ border: "2px solid",
479
+ borderRadius: "1rem",
480
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
481
+ fontSize: sizeStyles.fontSize,
482
+ fontWeight: "bold",
483
+ outline: "none",
484
+ transition: "all 300ms ease",
485
+ backdropFilter: "blur(8px)",
486
+ cursor: disabled ? "not-allowed" : "pointer",
487
+ display: "flex",
488
+ alignItems: "center",
489
+ justifyContent: "space-between",
490
+ userSelect: "none",
491
+ ...statusStyles
492
+ };
493
+ const dropdownStyle = {
494
+ position: "absolute",
495
+ top: dropdownUp ? "auto" : "100%",
496
+ bottom: dropdownUp ? "100%" : "auto",
497
+ left: 0,
498
+ right: 0,
499
+ marginTop: dropdownUp ? 0 : "0.25rem",
500
+ marginBottom: dropdownUp ? "0.25rem" : 0,
501
+ backgroundColor: "var(--selector-dropdown-bg, rgba(30, 41, 59, 0.95))",
502
+ border: "2px solid var(--selector-dropdown-border, #64748b)",
503
+ borderRadius: "1rem",
504
+ backdropFilter: "blur(12px)",
505
+ boxShadow: "var(--selector-dropdown-shadow, 0 12px 48px rgba(0, 0, 0, 0.4))",
506
+ zIndex: 50,
507
+ maxHeight: "12rem",
508
+ overflowY: "auto"
509
+ };
510
+ const optionStyle = (option, index) => ({
511
+ padding: sizeStyles.padding,
512
+ fontSize: sizeStyles.fontSize,
513
+ fontWeight: "600",
514
+ color: option.disabled ? "var(--selector-option-disabled-text, #6b7280)" : "var(--selector-option-text, #f1f5f9)",
515
+ backgroundColor: index === focusedIndex ? "var(--selector-option-focused-bg, rgba(59, 130, 246, 0.3))" : "transparent",
516
+ cursor: option.disabled ? "not-allowed" : "pointer",
517
+ transition: "all 150ms ease",
518
+ borderRadius: index === focusedIndex ? "0.5rem" : "0",
519
+ margin: index === focusedIndex ? "0.125rem" : "0"
520
+ });
521
+ const arrowStyle = {
522
+ position: "absolute",
523
+ right: "1rem",
524
+ top: "50%",
525
+ transform: `translateY(-50%) rotate(${isOpen ? "180deg" : "0deg"})`,
526
+ transition: "transform 200ms ease",
527
+ width: sizeStyles.iconSize,
528
+ height: sizeStyles.iconSize,
529
+ color: disabled ? "#6b7280" : "#94a3b8"
530
+ };
531
+ return /* @__PURE__ */ jsxs3(
532
+ "div",
533
+ {
534
+ className: "selector-container",
535
+ style: { display: "flex", flexDirection: "column", gap: "0.5rem" },
536
+ children: [
537
+ label && /* @__PURE__ */ jsx4(
538
+ "label",
539
+ {
540
+ className: "selector-label",
541
+ style: {
542
+ fontSize: "0.875rem",
543
+ fontWeight: "600",
544
+ color: "var(--selector-label-color, #cbd5e1)",
545
+ textTransform: "uppercase",
546
+ letterSpacing: "0.05em"
547
+ },
548
+ children: label
549
+ }
550
+ ),
551
+ /* @__PURE__ */ jsxs3("div", { ref: selectorRef, style: { position: "relative" }, children: [
552
+ /* @__PURE__ */ jsxs3(
553
+ "div",
554
+ {
555
+ className: `selector ${className}`,
556
+ style: selectorStyle,
557
+ onClick: () => !disabled && setIsOpen(!isOpen),
558
+ onKeyDown: handleKeyDown,
559
+ tabIndex: disabled ? -1 : 0,
560
+ role: "combobox",
561
+ "aria-expanded": isOpen,
562
+ "aria-haspopup": "listbox",
563
+ ...props,
564
+ children: [
565
+ /* @__PURE__ */ jsx4(
566
+ "span",
567
+ {
568
+ style: {
569
+ color: selectedOption ? statusStyles.color : "var(--selector-placeholder-text, #9ca3af)",
570
+ overflow: "hidden",
571
+ textOverflow: "ellipsis",
572
+ whiteSpace: "nowrap"
573
+ },
574
+ children: selectedOption ? selectedOption.label : placeholder
575
+ }
576
+ ),
577
+ /* @__PURE__ */ jsx4("svg", { style: arrowStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
578
+ ]
579
+ }
580
+ ),
581
+ isOpen && /* @__PURE__ */ jsx4("div", { ref: dropdownRef, style: dropdownStyle, role: "listbox", children: options.map((option, index) => /* @__PURE__ */ jsxs3(
582
+ "div",
583
+ {
584
+ style: optionStyle(option, index),
585
+ onClick: () => {
586
+ if (!option.disabled) {
587
+ onChange(option.value);
588
+ setIsOpen(false);
589
+ setFocusedIndex(-1);
590
+ }
591
+ },
592
+ onMouseEnter: () => !option.disabled && setFocusedIndex(index),
593
+ role: "option",
594
+ "aria-selected": option.value === value,
595
+ "aria-disabled": option.disabled,
596
+ title: option.description,
597
+ children: [
598
+ /* @__PURE__ */ jsxs3(
599
+ "div",
600
+ {
601
+ style: { display: "flex", justifyContent: "space-between", alignItems: "center" },
602
+ children: [
603
+ /* @__PURE__ */ jsx4("span", { children: option.label }),
604
+ option.value === value && /* @__PURE__ */ jsx4(
605
+ "svg",
606
+ {
607
+ style: { width: "1rem", height: "1rem", color: "#3b82f6" },
608
+ fill: "currentColor",
609
+ viewBox: "0 0 20 20",
610
+ children: /* @__PURE__ */ jsx4(
611
+ "path",
612
+ {
613
+ fillRule: "evenodd",
614
+ 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",
615
+ clipRule: "evenodd"
616
+ }
617
+ )
618
+ }
619
+ )
620
+ ]
621
+ }
622
+ ),
623
+ option.description && /* @__PURE__ */ jsx4(
624
+ "div",
625
+ {
626
+ style: {
627
+ fontSize: "0.75rem",
628
+ color: "#9ca3af",
629
+ marginTop: "0.25rem",
630
+ fontWeight: "normal"
631
+ },
632
+ children: option.description
633
+ }
634
+ )
635
+ ]
636
+ },
637
+ option.value
638
+ )) })
639
+ ] })
640
+ ]
641
+ }
642
+ );
643
+ };
644
+
645
+ // src/ControlPanel.tsx
646
+ import { useState as useState3 } from "react";
647
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
648
+ var ControlPanel = ({
649
+ title,
650
+ selectedMode,
651
+ modeOptions,
652
+ onModeChange,
653
+ setpointValue,
654
+ onSetpointChange,
655
+ secondSetpointValue,
656
+ onSecondSetpointChange,
657
+ modeConfigs = {},
658
+ defaultUnit = "Units",
659
+ defaultLabel = "Setpoint",
660
+ defaultMin = 0,
661
+ defaultMax = 100,
662
+ defaultPrecision = 2,
663
+ status = "normal",
664
+ collapsed = false,
665
+ onCollapseChange,
666
+ size = "medium",
667
+ setpointReadOnly = false,
668
+ showStartStopButtons = false,
669
+ isRunning = false,
670
+ onStart,
671
+ onStop,
672
+ startButtonText = "Start",
673
+ stopButtonText = "Stop",
674
+ className = "",
675
+ ...props
676
+ }) => {
677
+ const [isExpanded, setIsExpanded] = useState3(!collapsed);
678
+ const toggleExpanded = () => {
679
+ const newExpanded = !isExpanded;
680
+ setIsExpanded(newExpanded);
681
+ onCollapseChange?.(!newExpanded);
682
+ };
683
+ const currentModeConfig = modeConfigs[selectedMode] || {};
684
+ const currentUnit = currentModeConfig.unit || defaultUnit;
685
+ const currentLabel = currentModeConfig.label || defaultLabel;
686
+ const currentMin = currentModeConfig.min ?? defaultMin;
687
+ const currentMax = currentModeConfig.max ?? defaultMax;
688
+ const currentPrecision = currentModeConfig.precision ?? defaultPrecision;
689
+ const hasSecondSetpoint = currentModeConfig.hasSecondSetpoint || false;
690
+ const getSizeStyles = () => {
691
+ switch (size) {
692
+ case "small":
693
+ return {
694
+ padding: "1rem",
695
+ titleSize: "1rem",
696
+ gap: "0.75rem"
697
+ };
698
+ case "large":
699
+ return {
700
+ padding: "1.5rem",
701
+ titleSize: "1.5rem",
702
+ gap: "1.25rem"
703
+ };
704
+ default:
705
+ return {
706
+ padding: "1.25rem",
707
+ titleSize: "1.125rem",
708
+ gap: "1rem"
709
+ };
710
+ }
711
+ };
712
+ const getStatusStyles = () => {
713
+ switch (status) {
714
+ case "alarm":
715
+ return {
716
+ borderColor: "var(--control-panel-alarm-border, #ef4444)",
717
+ backgroundColor: "var(--control-panel-alarm-bg, rgba(239, 68, 68, 0.1))",
718
+ titleColor: "var(--control-panel-alarm-text, #fecaca)",
719
+ boxShadow: "var(--control-panel-alarm-shadow, 0 0 20px rgba(239, 68, 68, 0.3))",
720
+ glowEffect: "var(--control-panel-alarm-glow, 0 0 30px rgba(239, 68, 68, 0.2))"
721
+ };
722
+ case "warning":
723
+ return {
724
+ borderColor: "var(--control-panel-warning-border, #f59e0b)",
725
+ backgroundColor: "var(--control-panel-warning-bg, rgba(245, 158, 11, 0.1))",
726
+ titleColor: "var(--control-panel-warning-text, #fed7aa)",
727
+ boxShadow: "var(--control-panel-warning-shadow, 0 0 20px rgba(245, 158, 11, 0.3))",
728
+ glowEffect: "var(--control-panel-warning-glow, 0 0 30px rgba(245, 158, 11, 0.2))"
729
+ };
730
+ case "disabled":
731
+ return {
732
+ borderColor: "var(--control-panel-disabled-border, #6b7280)",
733
+ backgroundColor: "var(--control-panel-disabled-bg, rgba(107, 114, 128, 0.1))",
734
+ titleColor: "var(--control-panel-disabled-text, #9ca3af)",
735
+ boxShadow: "var(--control-panel-disabled-shadow, 0 8px 32px rgba(0, 0, 0, 0.2))",
736
+ glowEffect: "var(--control-panel-disabled-glow, none)"
737
+ };
738
+ default:
739
+ return {
740
+ borderColor: "var(--control-panel-normal-border, #64748b)",
741
+ backgroundColor: "var(--control-panel-normal-bg, rgba(30, 41, 59, 0.9))",
742
+ titleColor: "var(--control-panel-normal-text, #f1f5f9)",
743
+ boxShadow: "var(--control-panel-normal-shadow, 0 8px 32px rgba(0, 0, 0, 0.3))",
744
+ glowEffect: "var(--control-panel-normal-glow, 0 0 20px rgba(59, 130, 246, 0.1))"
745
+ };
746
+ }
747
+ };
748
+ const sizeStyles = getSizeStyles();
749
+ const statusStyles = getStatusStyles();
750
+ const panelStyle = {
751
+ border: "2px solid",
752
+ borderRadius: "1.5rem",
753
+ backdropFilter: "blur(12px)",
754
+ transition: "all 400ms cubic-bezier(0.4, 0, 0.2, 1)",
755
+ position: "relative",
756
+ overflow: "hidden",
757
+ minWidth: "300px",
758
+ maxWidth: "400px",
759
+ minHeight: "400px",
760
+ width: "100%",
761
+ ...statusStyles,
762
+ boxShadow: isExpanded ? statusStyles.glowEffect : statusStyles.boxShadow
763
+ };
764
+ const headerStyle = {
765
+ display: "flex",
766
+ alignItems: "center",
767
+ justifyContent: "space-between",
768
+ padding: sizeStyles.padding,
769
+ cursor: onCollapseChange ? "pointer" : "default",
770
+ borderBottom: isExpanded ? `1px solid ${statusStyles.borderColor}40` : "none",
771
+ transition: "all 300ms ease"
772
+ };
773
+ const titleStyle = {
774
+ fontSize: sizeStyles.titleSize,
775
+ fontWeight: "bold",
776
+ color: statusStyles.titleColor,
777
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
778
+ letterSpacing: "0.05em",
779
+ margin: 0
780
+ };
781
+ const contentStyle = {
782
+ padding: isExpanded ? sizeStyles.padding : "0",
783
+ paddingTop: isExpanded ? sizeStyles.padding : "0",
784
+ maxHeight: isExpanded ? "500px" : "0",
785
+ opacity: isExpanded ? 1 : 0,
786
+ overflow: "hidden",
787
+ transition: "all 400ms cubic-bezier(0.4, 0, 0.2, 1)",
788
+ display: "flex",
789
+ flexDirection: "column",
790
+ gap: sizeStyles.gap,
791
+ justifyContent: "space-between",
792
+ flex: 1
793
+ };
794
+ const chevronStyle = {
795
+ width: "1.5rem",
796
+ height: "1.5rem",
797
+ color: statusStyles.titleColor,
798
+ transform: `rotate(${isExpanded ? "180deg" : "0deg"})`,
799
+ transition: "transform 300ms ease",
800
+ opacity: onCollapseChange ? 1 : 0.3
801
+ };
802
+ const statusBadgeStyle = {
803
+ position: "absolute",
804
+ top: "0.5rem",
805
+ right: "0.5rem",
806
+ width: "0.75rem",
807
+ height: "0.75rem",
808
+ borderRadius: "50%",
809
+ backgroundColor: status === "alarm" ? "#ef4444" : status === "warning" ? "#f59e0b" : status === "disabled" ? "#6b7280" : "#22c55e",
810
+ boxShadow: `0 0 10px ${status === "alarm" ? "#ef4444" : status === "warning" ? "#f59e0b" : status === "disabled" ? "#6b7280" : "#22c55e"}80`,
811
+ animation: status === "alarm" ? "pulse 2s infinite" : "none"
812
+ };
813
+ return /* @__PURE__ */ jsxs4("div", { style: panelStyle, className: `control-panel glass-card ${className}`, ...props, children: [
814
+ /* @__PURE__ */ jsx5("div", { style: statusBadgeStyle }),
815
+ /* @__PURE__ */ jsxs4("div", { style: headerStyle, onClick: onCollapseChange ? toggleExpanded : void 0, children: [
816
+ /* @__PURE__ */ jsx5("h3", { style: titleStyle, children: title }),
817
+ onCollapseChange && /* @__PURE__ */ jsx5("svg", { style: chevronStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
818
+ ] }),
819
+ /* @__PURE__ */ jsxs4("div", { style: contentStyle, children: [
820
+ /* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5(
821
+ Selector,
822
+ {
823
+ value: selectedMode,
824
+ onChange: onModeChange,
825
+ options: modeOptions,
826
+ label: "Control Mode",
827
+ status,
828
+ size: size === "small" ? "small" : size === "large" ? "large" : "medium",
829
+ disabled: status === "disabled"
830
+ }
831
+ ) }),
832
+ /* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5(
833
+ ValueEntry,
834
+ {
835
+ value: setpointValue,
836
+ onChange: onSetpointChange,
837
+ label: currentLabel,
838
+ unit: currentUnit,
839
+ min: currentMin,
840
+ max: currentMax,
841
+ precision: currentPrecision,
842
+ status,
843
+ readOnly: setpointReadOnly || status === "disabled",
844
+ disabled: status === "disabled"
845
+ }
846
+ ) }),
847
+ hasSecondSetpoint && onSecondSetpointChange && /* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5(
848
+ ValueEntry,
849
+ {
850
+ value: secondSetpointValue || 0,
851
+ onChange: onSecondSetpointChange,
852
+ label: currentModeConfig.secondLabel || "Time",
853
+ unit: currentModeConfig.secondUnit || "sec",
854
+ min: currentModeConfig.secondMin ?? 0,
855
+ max: currentModeConfig.secondMax ?? 999,
856
+ precision: currentModeConfig.secondPrecision ?? 0,
857
+ status,
858
+ readOnly: setpointReadOnly || status === "disabled",
859
+ disabled: status === "disabled"
860
+ }
861
+ ) }),
862
+ showStartStopButtons && (onStart || onStop) && /* @__PURE__ */ jsxs4("div", { style: { display: "flex", gap: "0.75rem" }, children: [
863
+ onStart && /* @__PURE__ */ jsx5(
864
+ Button,
865
+ {
866
+ variant: "primary",
867
+ onClick: onStart,
868
+ disabled: isRunning || status === "disabled",
869
+ style: {
870
+ flex: 1,
871
+ fontSize: "0.875rem",
872
+ padding: "0.75rem 1rem",
873
+ backgroundColor: isRunning ? "#6b7280" : void 0
874
+ },
875
+ children: startButtonText
876
+ }
877
+ ),
878
+ onStop && /* @__PURE__ */ jsx5(
879
+ Button,
880
+ {
881
+ variant: "secondary",
882
+ onClick: onStop,
883
+ disabled: !isRunning || status === "disabled",
884
+ style: {
885
+ flex: 1,
886
+ fontSize: "0.875rem",
887
+ padding: "0.75rem 1rem",
888
+ backgroundColor: !isRunning ? "#6b7280" : "#dc2626",
889
+ borderColor: !isRunning ? "#6b7280" : "#dc2626"
890
+ },
891
+ children: stopButtonText
892
+ }
893
+ )
894
+ ] }),
895
+ /* @__PURE__ */ jsxs4(
896
+ "div",
897
+ {
898
+ className: "control-panel-info",
899
+ style: {
900
+ display: "flex",
901
+ justifyContent: "space-between",
902
+ alignItems: "center",
903
+ padding: "0.5rem 0",
904
+ fontSize: "0.75rem",
905
+ color: "var(--control-panel-info-text, #9ca3af)",
906
+ borderTop: `1px solid ${statusStyles.borderColor}20`,
907
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
908
+ },
909
+ children: [
910
+ /* @__PURE__ */ jsxs4("span", { children: [
911
+ "Mode: ",
912
+ selectedMode.toUpperCase()
913
+ ] }),
914
+ /* @__PURE__ */ jsxs4("div", { style: { display: "flex", gap: "1rem" }, children: [
915
+ /* @__PURE__ */ jsxs4("span", { children: [
916
+ "SP: ",
917
+ String(setpointValue),
918
+ currentUnit
919
+ ] }),
920
+ hasSecondSetpoint && secondSetpointValue && /* @__PURE__ */ jsxs4("span", { children: [
921
+ currentModeConfig.secondLabel,
922
+ ": ",
923
+ String(secondSetpointValue),
924
+ currentModeConfig.secondUnit
925
+ ] })
926
+ ] })
927
+ ]
928
+ }
929
+ )
930
+ ] })
931
+ ] });
932
+ };
933
+
934
+ // src/ThemeContext.tsx
935
+ import { createContext, useContext, useState as useState4, useEffect as useEffect2 } from "react";
936
+ import { jsx as jsx6 } from "react/jsx-runtime";
937
+ var ThemeContext = createContext(void 0);
938
+ var useTheme = () => {
939
+ const context = useContext(ThemeContext);
940
+ if (!context) {
941
+ throw new Error("useTheme must be used within a ThemeProvider");
942
+ }
943
+ return context;
944
+ };
945
+ var ThemeProvider = ({ children }) => {
946
+ const [theme, setThemeState] = useState4("modern");
947
+ useEffect2(() => {
948
+ document.body.className = "";
949
+ document.body.classList.add(`theme-${theme}`);
950
+ document.documentElement.className = "";
951
+ document.documentElement.classList.add(`theme-${theme}`);
952
+ }, [theme]);
953
+ const toggleTheme = () => {
954
+ setTheme(theme === "modern" ? "hmi" : "modern");
955
+ };
956
+ const setTheme = (newTheme) => {
957
+ setThemeState(newTheme);
958
+ };
959
+ return /* @__PURE__ */ jsx6(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
960
+ };
961
+
962
+ // src/ThemeToggle.tsx
963
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
964
+ var ThemeToggle = ({
965
+ size = "medium",
966
+ position = "top-right",
967
+ className = "",
968
+ ...props
969
+ }) => {
970
+ const { theme, toggleTheme } = useTheme();
971
+ const sizeStyles = {
972
+ small: { padding: "0.5rem 1rem", fontSize: "0.75rem" },
973
+ medium: { padding: "0.75rem 1.5rem", fontSize: "0.875rem" },
974
+ large: { padding: "1rem 2rem", fontSize: "1rem" }
975
+ };
976
+ const positionStyles = {
977
+ "top-left": { position: "fixed", top: "1rem", left: "1rem", zIndex: 1e3 },
978
+ "top-right": { position: "fixed", top: "1rem", right: "1rem", zIndex: 1e3 },
979
+ "bottom-left": { position: "fixed", bottom: "1rem", left: "1rem", zIndex: 1e3 },
980
+ "bottom-right": { position: "fixed", bottom: "1rem", right: "1rem", zIndex: 1e3 },
981
+ inline: { position: "relative" }
982
+ };
983
+ const baseStyle = {
984
+ display: "flex",
985
+ alignItems: "center",
986
+ gap: "0.75rem",
987
+ cursor: "pointer",
988
+ borderRadius: "0.5rem",
989
+ border: "2px solid",
990
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
991
+ fontWeight: 600,
992
+ textTransform: "uppercase",
993
+ letterSpacing: "0.05em",
994
+ transition: "all 0.2s ease",
995
+ userSelect: "none",
996
+ ...sizeStyles[size],
997
+ ...positionStyles[position]
998
+ };
999
+ const modernStyle = {
1000
+ ...baseStyle,
1001
+ background: "linear-gradient(135deg, #3b82f6 0%, #2563eb 50%, #1d4ed8 100%)",
1002
+ borderColor: "rgba(59, 130, 246, 0.4)",
1003
+ color: "#ffffff",
1004
+ boxShadow: "0 8px 32px rgba(59, 130, 246, 0.3)"
1005
+ };
1006
+ const hmiStyle = {
1007
+ ...baseStyle,
1008
+ backgroundColor: "#666666",
1009
+ borderColor: "#999999",
1010
+ color: "#ffffff",
1011
+ boxShadow: "none"
1012
+ };
1013
+ const currentStyle = theme === "modern" ? modernStyle : hmiStyle;
1014
+ const toggleStyle = {
1015
+ position: "relative",
1016
+ width: "3rem",
1017
+ height: "1.5rem",
1018
+ borderRadius: "0.75rem",
1019
+ transition: "all 0.2s ease",
1020
+ backgroundColor: theme === "modern" ? "#3b82f6" : "#808080",
1021
+ border: `2px solid ${theme === "modern" ? "#2563eb" : "#666666"}`
1022
+ };
1023
+ const thumbStyle = {
1024
+ position: "absolute",
1025
+ top: "0.125rem",
1026
+ left: theme === "modern" ? "0.125rem" : "1.375rem",
1027
+ width: "1rem",
1028
+ height: "1rem",
1029
+ borderRadius: "50%",
1030
+ backgroundColor: "#ffffff",
1031
+ transition: "all 0.2s ease",
1032
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
1033
+ };
1034
+ return /* @__PURE__ */ jsxs5("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
1035
+ /* @__PURE__ */ jsx7("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
1036
+ /* @__PURE__ */ jsx7("div", { style: toggleStyle, children: /* @__PURE__ */ jsx7("div", { style: thumbStyle }) }),
1037
+ /* @__PURE__ */ jsx7("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
1038
+ ] });
1039
+ };
1040
+ export {
1041
+ Button,
1042
+ ControlPanel,
1043
+ Selector,
1044
+ StatusIndicator,
1045
+ ThemeProvider,
1046
+ ThemeToggle,
1047
+ ValueEntry,
1048
+ useTheme
1049
+ };
1050
+ //# sourceMappingURL=index.js.map