@procaaso/alphinity-ui-components 1.0.12 → 1.1.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.d.cts CHANGED
@@ -274,6 +274,8 @@ interface ControlMode {
274
274
  value: string;
275
275
  /** Display label */
276
276
  label: string;
277
+ /** Description or context about this mode */
278
+ description?: string;
277
279
  /** Whether this mode is currently available */
278
280
  enabled?: boolean;
279
281
  /** Icon or emoji to display (optional) */
@@ -490,10 +492,16 @@ interface DeviceControlPanelProps {
490
492
  onOpenConfig?: () => void;
491
493
  /** Show configuration button in header */
492
494
  showConfigButton?: boolean;
493
- /** Style for mode selector: 'buttons' (horizontal scroll) or 'dropdown' (select) */
494
- modeSelectionStyle?: 'buttons' | 'dropdown';
495
- }
496
- declare function DeviceControlPanel({ binding, onClose, position, align, touchOptimized, compact, fontScale, maxHeight, maxWidth, toastDuration, onModeChange, onParameterChange, onStart, onStop, onCustomAction, onOpenConfig, showConfigButton, modeSelectionStyle, }: DeviceControlPanelProps): react_jsx_runtime.JSX.Element | null;
495
+ /** Called when undock button clicked (optional, shows undock button if provided) */
496
+ onUndock?: () => void;
497
+ /** Icon to display in undock button (default: '⇱') */
498
+ undockIcon?: string;
499
+ /** Style for mode selector: 'buttons' (horizontal scroll), 'dropdown' (select), or 'modal' (click to open modal) */
500
+ modeSelectionStyle?: 'buttons' | 'dropdown' | 'modal';
501
+ /** Embedded mode - uses static positioning for rendering in containers (default: false) */
502
+ embedded?: boolean;
503
+ }
504
+ declare function DeviceControlPanel({ binding, onClose, position, align, touchOptimized, compact, fontScale, maxHeight, maxWidth, toastDuration, onModeChange, onParameterChange, onStart, onStop, onCustomAction, onOpenConfig, showConfigButton, onUndock, undockIcon, modeSelectionStyle, embedded, }: DeviceControlPanelProps): react_jsx_runtime.JSX.Element | null;
497
505
 
498
506
  type DisplayMode = 'standard' | 'dashboard';
499
507
  interface FullscreenContainerProps {
@@ -1735,6 +1743,10 @@ interface DeviceConfigPanelProps {
1735
1743
  binding: DeviceConfigBinding | null;
1736
1744
  /** Called when panel should close */
1737
1745
  onClose: () => void;
1746
+ /** Called when undock button clicked (optional, shows undock button if provided) */
1747
+ onUndock?: () => void;
1748
+ /** Icon to display in undock button (default: '⇱') */
1749
+ undockIcon?: string;
1738
1750
  /** Panel position */
1739
1751
  position?: 'bottom' | 'side';
1740
1752
  /** Horizontal alignment for bottom position (default: center) */
@@ -1755,8 +1767,10 @@ interface DeviceConfigPanelProps {
1755
1767
  onOpenControls?: () => void;
1756
1768
  /** Show controls button in header */
1757
1769
  showControlsButton?: boolean;
1770
+ /** Embedded mode - uses static positioning for rendering in containers (default: false) */
1771
+ embedded?: boolean;
1758
1772
  }
1759
- declare function DeviceConfigPanel({ binding, onClose, position, align, touchOptimized, compact, fontScale, maxHeight, maxWidth, toastDuration, onOpenControls, showControlsButton, }: DeviceConfigPanelProps): react_jsx_runtime.JSX.Element | null;
1773
+ declare function DeviceConfigPanel({ binding, onClose, onUndock, undockIcon, position, align, touchOptimized, compact, fontScale, maxHeight, maxWidth, toastDuration, onOpenControls, showControlsButton, embedded, }: DeviceConfigPanelProps): react_jsx_runtime.JSX.Element | null;
1760
1774
 
1761
1775
  /**
1762
1776
  * Options for simulation behavior
package/dist/index.d.ts CHANGED
@@ -274,6 +274,8 @@ interface ControlMode {
274
274
  value: string;
275
275
  /** Display label */
276
276
  label: string;
277
+ /** Description or context about this mode */
278
+ description?: string;
277
279
  /** Whether this mode is currently available */
278
280
  enabled?: boolean;
279
281
  /** Icon or emoji to display (optional) */
@@ -490,10 +492,16 @@ interface DeviceControlPanelProps {
490
492
  onOpenConfig?: () => void;
491
493
  /** Show configuration button in header */
492
494
  showConfigButton?: boolean;
493
- /** Style for mode selector: 'buttons' (horizontal scroll) or 'dropdown' (select) */
494
- modeSelectionStyle?: 'buttons' | 'dropdown';
495
- }
496
- declare function DeviceControlPanel({ binding, onClose, position, align, touchOptimized, compact, fontScale, maxHeight, maxWidth, toastDuration, onModeChange, onParameterChange, onStart, onStop, onCustomAction, onOpenConfig, showConfigButton, modeSelectionStyle, }: DeviceControlPanelProps): react_jsx_runtime.JSX.Element | null;
495
+ /** Called when undock button clicked (optional, shows undock button if provided) */
496
+ onUndock?: () => void;
497
+ /** Icon to display in undock button (default: '⇱') */
498
+ undockIcon?: string;
499
+ /** Style for mode selector: 'buttons' (horizontal scroll), 'dropdown' (select), or 'modal' (click to open modal) */
500
+ modeSelectionStyle?: 'buttons' | 'dropdown' | 'modal';
501
+ /** Embedded mode - uses static positioning for rendering in containers (default: false) */
502
+ embedded?: boolean;
503
+ }
504
+ declare function DeviceControlPanel({ binding, onClose, position, align, touchOptimized, compact, fontScale, maxHeight, maxWidth, toastDuration, onModeChange, onParameterChange, onStart, onStop, onCustomAction, onOpenConfig, showConfigButton, onUndock, undockIcon, modeSelectionStyle, embedded, }: DeviceControlPanelProps): react_jsx_runtime.JSX.Element | null;
497
505
 
498
506
  type DisplayMode = 'standard' | 'dashboard';
499
507
  interface FullscreenContainerProps {
@@ -1735,6 +1743,10 @@ interface DeviceConfigPanelProps {
1735
1743
  binding: DeviceConfigBinding | null;
1736
1744
  /** Called when panel should close */
1737
1745
  onClose: () => void;
1746
+ /** Called when undock button clicked (optional, shows undock button if provided) */
1747
+ onUndock?: () => void;
1748
+ /** Icon to display in undock button (default: '⇱') */
1749
+ undockIcon?: string;
1738
1750
  /** Panel position */
1739
1751
  position?: 'bottom' | 'side';
1740
1752
  /** Horizontal alignment for bottom position (default: center) */
@@ -1755,8 +1767,10 @@ interface DeviceConfigPanelProps {
1755
1767
  onOpenControls?: () => void;
1756
1768
  /** Show controls button in header */
1757
1769
  showControlsButton?: boolean;
1770
+ /** Embedded mode - uses static positioning for rendering in containers (default: false) */
1771
+ embedded?: boolean;
1758
1772
  }
1759
- declare function DeviceConfigPanel({ binding, onClose, position, align, touchOptimized, compact, fontScale, maxHeight, maxWidth, toastDuration, onOpenControls, showControlsButton, }: DeviceConfigPanelProps): react_jsx_runtime.JSX.Element | null;
1773
+ declare function DeviceConfigPanel({ binding, onClose, onUndock, undockIcon, position, align, touchOptimized, compact, fontScale, maxHeight, maxWidth, toastDuration, onOpenControls, showControlsButton, embedded, }: DeviceConfigPanelProps): react_jsx_runtime.JSX.Element | null;
1760
1774
 
1761
1775
  /**
1762
1776
  * Options for simulation behavior
package/dist/index.js CHANGED
@@ -914,9 +914,14 @@ function DeviceControlPanel({
914
914
  onCustomAction,
915
915
  onOpenConfig,
916
916
  showConfigButton = true,
917
- modeSelectionStyle = "buttons"
917
+ onUndock,
918
+ undockIcon = "\u21F1",
919
+ modeSelectionStyle = "buttons",
920
+ embedded = false
918
921
  }) {
919
922
  const [localParameterValues, setLocalParameterValues] = useState5({});
923
+ const [showModeModal, setShowModeModal] = useState5(false);
924
+ const [pendingMode, setPendingMode] = useState5(null);
920
925
  const [showToast, setShowToast] = useState5(true);
921
926
  useEffect2(() => {
922
927
  if (binding) {
@@ -953,7 +958,8 @@ function DeviceControlPanel({
953
958
  value: Math.round(13 * fontScale),
954
959
  input: Math.round(14 * fontScale),
955
960
  button: Math.round(12 * fontScale),
956
- status: Math.round(10 * fontScale)
961
+ status: Math.round(10 * fontScale),
962
+ description: Math.round(13 * fontScale)
957
963
  };
958
964
  const currentModeObj = binding.modes.find((m) => m.value === currentMode);
959
965
  const activeCapabilities = currentModeObj?.capabilities ?? binding.capabilities ?? {};
@@ -989,11 +995,31 @@ function DeviceControlPanel({
989
995
  const handleParameterInput = (parameterId, value) => {
990
996
  setLocalParameterValues((prev) => ({ ...prev, [parameterId]: value }));
991
997
  };
992
- const panelStyle = {
998
+ const panelStyle = embedded ? {
999
+ // Embedded mode: static positioning for container layouts
1000
+ position: "static",
1001
+ width: "100%",
1002
+ backgroundColor,
1003
+ color: textColor,
1004
+ borderRadius: "8px 8px 0 0",
1005
+ boxShadow: "none",
1006
+ border: `2px solid ${borderColor}`,
1007
+ padding: spacing.padding,
1008
+ maxHeight: maxHeight || "70vh",
1009
+ overflowY: "auto",
1010
+ ...binding.display?.style
1011
+ } : {
1012
+ // Fixed mode: traditional overlay positioning
993
1013
  position: "fixed",
994
1014
  ...position === "bottom" ? {
995
1015
  bottom: 0,
996
- ...align === "left" ? { left: 0, right: "auto", width: maxWidth } : align === "right" ? { right: 0, left: "auto", width: maxWidth } : { left: 0, right: 0, marginLeft: "auto", marginRight: "auto", maxWidth },
1016
+ ...align === "left" ? { left: 0, right: "auto", width: maxWidth } : align === "right" ? { right: 0, left: "auto", width: maxWidth } : {
1017
+ left: 0,
1018
+ right: 0,
1019
+ marginLeft: "auto",
1020
+ marginRight: "auto",
1021
+ maxWidth
1022
+ },
997
1023
  animation: "slideUp 0.3s ease-out"
998
1024
  } : {
999
1025
  right: 0,
@@ -1039,9 +1065,14 @@ function DeviceControlPanel({
1039
1065
  fontFamily: "Arial, sans-serif",
1040
1066
  letterSpacing: "0.5px",
1041
1067
  textTransform: "uppercase",
1042
- color: textColor
1068
+ color: textColor,
1069
+ overflow: "hidden",
1070
+ textOverflow: "ellipsis",
1071
+ whiteSpace: "nowrap",
1072
+ maxWidth: "200px"
1043
1073
  },
1044
- children: titleText
1074
+ title: titleText.length > 25 ? titleText : void 0,
1075
+ children: titleText.length > 25 ? titleText.slice(0, 25) + "..." : titleText
1045
1076
  }
1046
1077
  ),
1047
1078
  binding.deviceType && /* @__PURE__ */ jsx8(
@@ -1079,6 +1110,27 @@ function DeviceControlPanel({
1079
1110
  children: "\u2699"
1080
1111
  }
1081
1112
  ),
1113
+ onUndock && /* @__PURE__ */ jsx8(
1114
+ "button",
1115
+ {
1116
+ onClick: onUndock,
1117
+ title: "Undock panel",
1118
+ style: {
1119
+ width: touchSize * 0.7,
1120
+ height: touchSize * 0.7,
1121
+ backgroundColor: surfaceColor,
1122
+ color: textColor,
1123
+ border: `2px solid ${borderColor}`,
1124
+ borderRadius: "2px",
1125
+ fontSize: "16px",
1126
+ cursor: "pointer",
1127
+ fontWeight: 600,
1128
+ fontFamily: "Arial, sans-serif",
1129
+ padding: "0"
1130
+ },
1131
+ children: undockIcon
1132
+ }
1133
+ ),
1082
1134
  /* @__PURE__ */ jsx8(
1083
1135
  "button",
1084
1136
  {
@@ -1216,7 +1268,205 @@ function DeviceControlPanel({
1216
1268
  },
1217
1269
  children: binding.modes.map((mode) => /* @__PURE__ */ jsx8("option", { value: mode.value, disabled: mode.enabled === false, children: mode.label }, mode.value))
1218
1270
  }
1219
- ) : /* @__PURE__ */ jsx8(
1271
+ ) : modeSelectionStyle === "modal" ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
1272
+ /* @__PURE__ */ jsxs7(
1273
+ "div",
1274
+ {
1275
+ onClick: () => setShowModeModal(true),
1276
+ style: {
1277
+ padding: "12px",
1278
+ backgroundColor: surfaceColor,
1279
+ border: `2px solid ${borderColor}`,
1280
+ borderRadius: "6px",
1281
+ fontSize: `${fontSize.label}px`,
1282
+ fontWeight: 600,
1283
+ fontFamily: "Arial, sans-serif",
1284
+ letterSpacing: "0.5px",
1285
+ textTransform: "uppercase",
1286
+ cursor: "pointer",
1287
+ display: "flex",
1288
+ justifyContent: "space-between",
1289
+ alignItems: "center"
1290
+ },
1291
+ children: [
1292
+ /* @__PURE__ */ jsx8("span", { children: binding.modes.find((m) => m.value === currentMode)?.label || currentMode }),
1293
+ /* @__PURE__ */ jsx8("span", { style: { fontSize: "20px", marginLeft: "8px" }, children: "\u25BC" })
1294
+ ]
1295
+ }
1296
+ ),
1297
+ showModeModal && /* @__PURE__ */ jsx8(
1298
+ "div",
1299
+ {
1300
+ style: {
1301
+ position: "fixed",
1302
+ top: 0,
1303
+ left: 0,
1304
+ right: 0,
1305
+ bottom: 0,
1306
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
1307
+ display: "flex",
1308
+ alignItems: "center",
1309
+ justifyContent: "center",
1310
+ zIndex: 2e4
1311
+ },
1312
+ onClick: () => {
1313
+ setShowModeModal(false);
1314
+ setPendingMode(null);
1315
+ },
1316
+ children: /* @__PURE__ */ jsxs7(
1317
+ "div",
1318
+ {
1319
+ onClick: (e) => e.stopPropagation(),
1320
+ style: {
1321
+ backgroundColor,
1322
+ borderRadius: "8px",
1323
+ padding: "24px",
1324
+ minWidth: "300px",
1325
+ maxWidth: "400px",
1326
+ border: `2px solid ${borderColor}`
1327
+ },
1328
+ children: [
1329
+ /* @__PURE__ */ jsx8(
1330
+ "h3",
1331
+ {
1332
+ style: {
1333
+ margin: "0 0 4px 0",
1334
+ fontSize: `${fontSize.title}px`,
1335
+ fontWeight: 600,
1336
+ fontFamily: "Arial, sans-serif",
1337
+ color: textColor
1338
+ },
1339
+ children: "Select Mode"
1340
+ }
1341
+ ),
1342
+ /* @__PURE__ */ jsx8(
1343
+ "div",
1344
+ {
1345
+ style: {
1346
+ marginBottom: "16px",
1347
+ fontSize: `${fontSize.label}px`,
1348
+ fontWeight: 600,
1349
+ fontFamily: "Arial, sans-serif",
1350
+ color: mutedTextColor,
1351
+ textTransform: "uppercase"
1352
+ },
1353
+ children: binding.display?.title || binding.deviceName || binding.tag || binding.nodeId
1354
+ }
1355
+ ),
1356
+ /* @__PURE__ */ jsx8(
1357
+ "select",
1358
+ {
1359
+ value: pendingMode || currentMode,
1360
+ onChange: (e) => setPendingMode(e.target.value),
1361
+ style: {
1362
+ width: "100%",
1363
+ height: `${touchSize}px`,
1364
+ marginBottom: "8px",
1365
+ backgroundColor: surfaceColor,
1366
+ color: textColor,
1367
+ border: `2px solid ${borderColor}`,
1368
+ borderRadius: "6px",
1369
+ fontSize: `${fontSize.label}px`,
1370
+ fontWeight: 600,
1371
+ fontFamily: "Arial, sans-serif",
1372
+ letterSpacing: "0.5px",
1373
+ textTransform: "uppercase",
1374
+ paddingLeft: "12px",
1375
+ paddingRight: "12px",
1376
+ cursor: "pointer"
1377
+ },
1378
+ children: binding.modes.map((mode) => /* @__PURE__ */ jsx8(
1379
+ "option",
1380
+ {
1381
+ value: mode.value,
1382
+ disabled: mode.enabled === false,
1383
+ children: mode.label
1384
+ },
1385
+ mode.value
1386
+ ))
1387
+ }
1388
+ ),
1389
+ (() => {
1390
+ const selectedMode = binding.modes.find(
1391
+ (m) => m.value === (pendingMode || currentMode)
1392
+ );
1393
+ return selectedMode?.description ? /* @__PURE__ */ jsx8(
1394
+ "div",
1395
+ {
1396
+ style: {
1397
+ marginBottom: "16px",
1398
+ padding: "12px",
1399
+ backgroundColor: surfaceColor,
1400
+ border: `1px solid ${borderColor}`,
1401
+ borderRadius: "6px",
1402
+ fontSize: `${fontSize.description}px`,
1403
+ color: mutedTextColor,
1404
+ fontFamily: "Arial, sans-serif",
1405
+ lineHeight: "1.4"
1406
+ },
1407
+ children: selectedMode.description
1408
+ }
1409
+ ) : null;
1410
+ })(),
1411
+ /* @__PURE__ */ jsxs7("div", { style: { display: "flex", gap: "12px" }, children: [
1412
+ /* @__PURE__ */ jsx8(
1413
+ "button",
1414
+ {
1415
+ onClick: () => {
1416
+ if (pendingMode && pendingMode !== currentMode) {
1417
+ handleModeChange(pendingMode);
1418
+ }
1419
+ setShowModeModal(false);
1420
+ setPendingMode(null);
1421
+ },
1422
+ style: {
1423
+ flex: 1,
1424
+ height: `${touchSize}px`,
1425
+ backgroundColor: "#4ade80",
1426
+ color: "#000000",
1427
+ border: "2px solid #22c55e",
1428
+ borderRadius: "6px",
1429
+ fontSize: `${fontSize.button}px`,
1430
+ fontWeight: 600,
1431
+ fontFamily: "Arial, sans-serif",
1432
+ letterSpacing: "0.5px",
1433
+ textTransform: "uppercase",
1434
+ cursor: "pointer"
1435
+ },
1436
+ children: "Confirm"
1437
+ }
1438
+ ),
1439
+ /* @__PURE__ */ jsx8(
1440
+ "button",
1441
+ {
1442
+ onClick: () => {
1443
+ setShowModeModal(false);
1444
+ setPendingMode(null);
1445
+ },
1446
+ style: {
1447
+ flex: 1,
1448
+ height: `${touchSize}px`,
1449
+ backgroundColor: surfaceColor,
1450
+ color: textColor,
1451
+ border: `2px solid ${borderColor}`,
1452
+ borderRadius: "6px",
1453
+ fontSize: `${fontSize.button}px`,
1454
+ fontWeight: 600,
1455
+ fontFamily: "Arial, sans-serif",
1456
+ letterSpacing: "0.5px",
1457
+ textTransform: "uppercase",
1458
+ cursor: "pointer"
1459
+ },
1460
+ children: "Cancel"
1461
+ }
1462
+ )
1463
+ ] })
1464
+ ]
1465
+ }
1466
+ )
1467
+ }
1468
+ )
1469
+ ] }) : /* @__PURE__ */ jsx8(
1220
1470
  "div",
1221
1471
  {
1222
1472
  style: {
@@ -7829,6 +8079,8 @@ import { Fragment as Fragment9, jsx as jsx22, jsxs as jsxs18 } from "react/jsx-r
7829
8079
  function DeviceConfigPanel({
7830
8080
  binding,
7831
8081
  onClose,
8082
+ onUndock,
8083
+ undockIcon = "\u21F1",
7832
8084
  position = "bottom",
7833
8085
  align = "center",
7834
8086
  touchOptimized = true,
@@ -7838,7 +8090,8 @@ function DeviceConfigPanel({
7838
8090
  maxWidth,
7839
8091
  toastDuration = 3e3,
7840
8092
  onOpenControls,
7841
- showControlsButton = true
8093
+ showControlsButton = true,
8094
+ embedded = false
7842
8095
  }) {
7843
8096
  const [localValues, setLocalValues] = useState17(() => {
7844
8097
  if (binding) {
@@ -8205,11 +8458,33 @@ function DeviceConfigPanel({
8205
8458
  section.id
8206
8459
  );
8207
8460
  };
8208
- const panelStyle = {
8461
+ const panelStyle = embedded ? {
8462
+ // Embedded mode: static positioning for container layouts
8463
+ position: "static",
8464
+ width: "100%",
8465
+ backgroundColor,
8466
+ color: textColor,
8467
+ borderRadius: "8px 8px 0 0",
8468
+ boxShadow: "none",
8469
+ border: `2px solid ${borderColor}`,
8470
+ padding: spacing.padding,
8471
+ maxHeight: maxHeight || "70vh",
8472
+ overflowY: "auto",
8473
+ display: "flex",
8474
+ flexDirection: "column",
8475
+ ...binding.display?.style
8476
+ } : {
8477
+ // Fixed mode: traditional overlay positioning
8209
8478
  position: "fixed",
8210
8479
  ...position === "bottom" ? {
8211
8480
  bottom: 0,
8212
- ...align === "left" ? { left: 0, right: "auto", width: maxWidth } : align === "right" ? { right: 0, left: "auto", width: maxWidth } : { left: 0, right: 0, marginLeft: "auto", marginRight: "auto", maxWidth },
8481
+ ...align === "left" ? { left: 0, right: "auto", width: maxWidth } : align === "right" ? { right: 0, left: "auto", width: maxWidth } : {
8482
+ left: 0,
8483
+ right: 0,
8484
+ marginLeft: "auto",
8485
+ marginRight: "auto",
8486
+ maxWidth
8487
+ },
8213
8488
  animation: "slideUp 0.3s ease-out"
8214
8489
  } : {
8215
8490
  right: 0,
@@ -8261,9 +8536,14 @@ function DeviceConfigPanel({
8261
8536
  fontFamily: "Arial, sans-serif",
8262
8537
  letterSpacing: "0.5px",
8263
8538
  textTransform: "uppercase",
8264
- color: textColor
8539
+ color: textColor,
8540
+ overflow: "hidden",
8541
+ textOverflow: "ellipsis",
8542
+ whiteSpace: "nowrap",
8543
+ maxWidth: "200px"
8265
8544
  },
8266
- children: titleText
8545
+ title: titleText.length > 25 ? titleText : void 0,
8546
+ children: titleText.length > 25 ? titleText.slice(0, 25) + "..." : titleText
8267
8547
  }
8268
8548
  ),
8269
8549
  binding.display?.subtitle && /* @__PURE__ */ jsx22(
@@ -8303,6 +8583,27 @@ function DeviceConfigPanel({
8303
8583
  children: "CTRL"
8304
8584
  }
8305
8585
  ),
8586
+ onUndock && /* @__PURE__ */ jsx22(
8587
+ "button",
8588
+ {
8589
+ onClick: onUndock,
8590
+ title: "Undock panel",
8591
+ style: {
8592
+ width: touchSize * 0.7,
8593
+ height: touchSize * 0.7,
8594
+ backgroundColor: surfaceColor,
8595
+ color: textColor,
8596
+ border: `2px solid ${borderColor}`,
8597
+ borderRadius: "2px",
8598
+ fontSize: "16px",
8599
+ cursor: "pointer",
8600
+ fontWeight: 600,
8601
+ fontFamily: "Arial, sans-serif",
8602
+ padding: "0"
8603
+ },
8604
+ children: undockIcon
8605
+ }
8606
+ ),
8306
8607
  /* @__PURE__ */ jsx22(
8307
8608
  "button",
8308
8609
  {