@procaaso/alphinity-ui-components 1.0.2 → 1.0.4

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/README.md CHANGED
@@ -18,33 +18,20 @@ function HMIPanel() {
18
18
  const [temperature, setTemperature] = useState(72.5);
19
19
  const [pressure, setPressure] = useState(14.7);
20
20
  const [systemStatus, setSystemStatus] = useState('normal');
21
-
21
+
22
22
  return (
23
23
  <div className="p-4 space-y-4">
24
24
  {/* System status indicators */}
25
25
  <div className="flex gap-4 items-center">
26
- <StatusIndicator
27
- status="normal"
28
- label="Power"
29
- size="medium"
30
- led={true}
31
- />
32
- <StatusIndicator
33
- status="alarm"
34
- label="Temperature Alert"
26
+ <StatusIndicator status="normal" label="Power" size="medium" led={true} />
27
+ <StatusIndicator
28
+ status="alarm"
29
+ label="Temperature Alert"
35
30
  animation="pulse"
36
31
  shape="circle"
37
32
  />
38
- <StatusIndicator
39
- status="warning"
40
- label="Maintenance Due"
41
- animation="blink"
42
- />
43
- <StatusIndicator
44
- status="active"
45
- label="Process Running"
46
- size="large"
47
- />
33
+ <StatusIndicator status="warning" label="Maintenance Due" animation="blink" />
34
+ <StatusIndicator status="active" label="Process Running" size="large" />
48
35
  </div>
49
36
 
50
37
  {/* Process control values */}
@@ -58,7 +45,7 @@ function HMIPanel() {
58
45
  precision={1}
59
46
  status="normal"
60
47
  />
61
-
48
+
62
49
  <ValueEntry
63
50
  value={pressure}
64
51
  onChange={setPressure}
@@ -67,7 +54,7 @@ function HMIPanel() {
67
54
  status="warning"
68
55
  readOnly
69
56
  />
70
-
57
+
71
58
  {/* Control buttons */}
72
59
  <Button variant="primary" onClick={() => console.log('Start process')}>
73
60
  Start
package/dist/index.cjs CHANGED
@@ -2055,9 +2055,10 @@ function NodeRenderer({
2055
2055
  x: symbol.viewBox.width / 2 + (node.labelOffset?.x ?? 0),
2056
2056
  y: symbol.viewBox.height + 12 + (node.labelOffset?.y ?? 0),
2057
2057
  textAnchor: "middle",
2058
- fontSize: "10",
2058
+ fontSize: node.labelFontSize ?? 10,
2059
2059
  fontWeight: "600",
2060
2060
  fill: isSelected ? "#3b82f6" : "#1f2937",
2061
+ transform: node.transform.rotation ? `rotate(${-node.transform.rotation}, ${symbol.viewBox.width / 2 + (node.labelOffset?.x ?? 0)}, ${symbol.viewBox.height + 12 + (node.labelOffset?.y ?? 0)})` : void 0,
2061
2062
  children: node.label || node.id
2062
2063
  }
2063
2064
  )
@@ -2437,6 +2438,34 @@ function useViewBox(options) {
2437
2438
  };
2438
2439
  });
2439
2440
  }, [initialViewBox, maxZoom]);
2441
+ const fitToContent = (0, import_react8.useCallback)((bounds, padding = 50) => {
2442
+ const contentWidth = bounds.maxX - bounds.minX;
2443
+ const contentHeight = bounds.maxY - bounds.minY;
2444
+ if (contentWidth === 0 || contentHeight === 0) {
2445
+ return;
2446
+ }
2447
+ const paddedWidth = contentWidth + padding * 2;
2448
+ const paddedHeight = contentHeight + padding * 2;
2449
+ const aspectRatio = initialViewBox.width / initialViewBox.height;
2450
+ const contentAspectRatio = paddedWidth / paddedHeight;
2451
+ let newWidth;
2452
+ let newHeight;
2453
+ if (contentAspectRatio > aspectRatio) {
2454
+ newWidth = paddedWidth;
2455
+ newHeight = paddedWidth / aspectRatio;
2456
+ } else {
2457
+ newHeight = paddedHeight;
2458
+ newWidth = paddedHeight * aspectRatio;
2459
+ }
2460
+ const centerX = bounds.minX + contentWidth / 2;
2461
+ const centerY = bounds.minY + contentHeight / 2;
2462
+ setViewBox({
2463
+ x: centerX - newWidth / 2,
2464
+ y: centerY - newHeight / 2,
2465
+ width: newWidth,
2466
+ height: newHeight
2467
+ });
2468
+ }, [initialViewBox]);
2440
2469
  (0, import_react8.useEffect)(() => {
2441
2470
  if (!enableZoom || !svgRef.current) return;
2442
2471
  const svg = svgRef.current;
@@ -2668,6 +2697,8 @@ function useViewBox(options) {
2668
2697
  resetViewBox,
2669
2698
  zoomIn,
2670
2699
  zoomOut,
2700
+ fitToContent,
2701
+ setViewBox,
2671
2702
  screenToWorld,
2672
2703
  svgRef
2673
2704
  };
@@ -3322,6 +3353,7 @@ function PIDCanvas({
3322
3353
  onPaste,
3323
3354
  onSymbolDrop,
3324
3355
  onPipeCreated,
3356
+ onMounted,
3325
3357
  telemetry,
3326
3358
  ...props
3327
3359
  }) {
@@ -3339,12 +3371,72 @@ function PIDCanvas({
3339
3371
  const {
3340
3372
  viewBox: controlledViewBox,
3341
3373
  svgRef,
3342
- screenToWorld
3374
+ screenToWorld,
3375
+ fitToContent: fitToContentViewBox,
3376
+ setViewBox
3343
3377
  } = useViewBox({
3344
3378
  initialViewBox: diagram.viewBox,
3345
3379
  enablePan: features.pan ?? true,
3346
3380
  enableZoom: features.zoom ?? true
3347
3381
  });
3382
+ const calculateContentBounds = (0, import_react13.useCallback)(() => {
3383
+ const nodes2 = localDiagram.nodes.filter((n) => n.visible !== false);
3384
+ if (nodes2.length === 0) {
3385
+ return null;
3386
+ }
3387
+ let minX = Infinity;
3388
+ let minY = Infinity;
3389
+ let maxX = -Infinity;
3390
+ let maxY = -Infinity;
3391
+ nodes2.forEach((node) => {
3392
+ const symbol = getSymbolDefinition(node.symbolId);
3393
+ if (!symbol) return;
3394
+ const nodeMinX = node.transform.x;
3395
+ const nodeMinY = node.transform.y;
3396
+ const nodeMaxX = node.transform.x + symbol.viewBox.width;
3397
+ const nodeMaxY = node.transform.y + symbol.viewBox.height;
3398
+ minX = Math.min(minX, nodeMinX);
3399
+ minY = Math.min(minY, nodeMinY);
3400
+ maxX = Math.max(maxX, nodeMaxX);
3401
+ maxY = Math.max(maxY, nodeMaxY);
3402
+ });
3403
+ return { minX, minY, maxX, maxY };
3404
+ }, [localDiagram.nodes]);
3405
+ (0, import_react13.useEffect)(() => {
3406
+ if (onMounted) {
3407
+ const controls = {
3408
+ fitToContent: (padding = 50) => {
3409
+ const bounds = calculateContentBounds();
3410
+ if (bounds) {
3411
+ fitToContentViewBox(bounds, padding);
3412
+ }
3413
+ },
3414
+ setZoom: (zoomLevel) => {
3415
+ const centerX = controlledViewBox.x + controlledViewBox.width / 2;
3416
+ const centerY = controlledViewBox.y + controlledViewBox.height / 2;
3417
+ const newWidth = diagram.viewBox.width / zoomLevel;
3418
+ const newHeight = diagram.viewBox.height / zoomLevel;
3419
+ setViewBox({
3420
+ x: centerX - newWidth / 2,
3421
+ y: centerY - newHeight / 2,
3422
+ width: newWidth,
3423
+ height: newHeight
3424
+ });
3425
+ },
3426
+ getZoom: () => {
3427
+ return diagram.viewBox.width / controlledViewBox.width;
3428
+ }
3429
+ };
3430
+ onMounted(controls);
3431
+ }
3432
+ }, [
3433
+ onMounted,
3434
+ calculateContentBounds,
3435
+ fitToContentViewBox,
3436
+ setViewBox,
3437
+ controlledViewBox,
3438
+ diagram.viewBox
3439
+ ]);
3348
3440
  const { selection, selectNode, selectPipe, clearSelection } = useSelection({
3349
3441
  multiSelect: features.multiSelect ?? true,
3350
3442
  onSelectionChange
@@ -3635,21 +3727,32 @@ function PIDCanvas({
3635
3727
  onDrop: handleDrop,
3636
3728
  onDragLeave: handleDragLeave,
3637
3729
  children: [
3638
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("defs", { children: [
3639
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
3640
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
3641
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
3642
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
3643
- ] })
3644
- ] }),
3645
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3730
+ features.showGrid !== false ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
3731
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("defs", { children: [
3732
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
3733
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
3734
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
3735
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
3736
+ ] })
3737
+ ] }),
3738
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3739
+ "rect",
3740
+ {
3741
+ x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
3742
+ y: Math.floor(viewBox.y / 25) * 25 - viewBox.height,
3743
+ width: Math.ceil(viewBox.width * 3 / 25) * 25,
3744
+ height: Math.ceil(viewBox.height * 3 / 25) * 25,
3745
+ fill: "url(#grid-major)"
3746
+ }
3747
+ )
3748
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3646
3749
  "rect",
3647
3750
  {
3648
3751
  x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
3649
3752
  y: Math.floor(viewBox.y / 25) * 25 - viewBox.height,
3650
3753
  width: Math.ceil(viewBox.width * 3 / 25) * 25,
3651
3754
  height: Math.ceil(viewBox.height * 3 / 25) * 25,
3652
- fill: "url(#grid-major)"
3755
+ fill: features.backgroundColor ?? "#ffffff"
3653
3756
  }
3654
3757
  ),
3655
3758
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -4082,6 +4185,54 @@ function NodeConfigPanel({
4082
4185
  }
4083
4186
  )
4084
4187
  ] })
4188
+ ] }),
4189
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4190
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
4191
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4192
+ "input",
4193
+ {
4194
+ type: "number",
4195
+ min: "6",
4196
+ max: "24",
4197
+ value: node.labelFontSize ?? 10,
4198
+ onChange: (e) => onUpdateNode({
4199
+ labelFontSize: parseFloat(e.target.value) || 10
4200
+ }),
4201
+ style: {
4202
+ width: "100%",
4203
+ padding: "6px 8px",
4204
+ borderRadius: "4px",
4205
+ border: "1px solid #cbd5e1",
4206
+ fontSize: "0.875rem"
4207
+ }
4208
+ }
4209
+ )
4210
+ ] }),
4211
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4212
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
4213
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4214
+ "input",
4215
+ {
4216
+ type: "number",
4217
+ min: "0",
4218
+ max: "360",
4219
+ step: "15",
4220
+ value: node.transform.rotation ?? 0,
4221
+ onChange: (e) => onUpdateNode({
4222
+ transform: {
4223
+ ...node.transform,
4224
+ rotation: parseFloat(e.target.value) || 0
4225
+ }
4226
+ }),
4227
+ style: {
4228
+ width: "100%",
4229
+ padding: "6px 8px",
4230
+ borderRadius: "4px",
4231
+ border: "1px solid #cbd5e1",
4232
+ fontSize: "0.875rem"
4233
+ }
4234
+ }
4235
+ )
4085
4236
  ] })
4086
4237
  ] }),
4087
4238
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { marginBottom: "20px" }, children: [