@stn-uiux/pub-ui-react 0.1.87 → 0.1.88

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 CHANGED
@@ -900,6 +900,7 @@ var StnPopover = forwardRef5(function StnPopover2({
900
900
  onClose,
901
901
  container,
902
902
  disablePortal = false,
903
+ hideBackdrop = false,
903
904
  children,
904
905
  ...rest
905
906
  }, ref) {
@@ -1010,11 +1011,16 @@ var StnPopover = forwardRef5(function StnPopover2({
1010
1011
  {
1011
1012
  ref: rootRef,
1012
1013
  id,
1013
- className: cn("stn-popover", open && "is-open", className),
1014
+ className: cn(
1015
+ "stn-popover",
1016
+ open && "is-open",
1017
+ hideBackdrop && "stn-popover--no-backdrop",
1018
+ className
1019
+ ),
1014
1020
  style,
1015
1021
  ...rest,
1016
1022
  children: [
1017
- /* @__PURE__ */ jsx8(
1023
+ !hideBackdrop && /* @__PURE__ */ jsx8(
1018
1024
  "div",
1019
1025
  {
1020
1026
  className: "stn-popover__backdrop",
@@ -3262,6 +3268,7 @@ var StnMenuBase = forwardRef18(function StnMenuBase2({
3262
3268
  paperClassName,
3263
3269
  paperStyle,
3264
3270
  disablePortal = false,
3271
+ hideBackdrop = false,
3265
3272
  className,
3266
3273
  children,
3267
3274
  ...rest
@@ -3301,6 +3308,7 @@ var StnMenuBase = forwardRef18(function StnMenuBase2({
3301
3308
  transformOrigin,
3302
3309
  onClose,
3303
3310
  disablePortal,
3311
+ hideBackdrop,
3304
3312
  className: cn("stn-menu-popover", className),
3305
3313
  paperClassName: cn(
3306
3314
  "stn-menu-paper",
@@ -4270,8 +4278,8 @@ function StnCardHeader({
4270
4278
  function StnCardBody({ children, className, flush = false, ...rest }) {
4271
4279
  return /* @__PURE__ */ jsx26("div", { className: cn("stn-card__body", flush && "is-flush", className), ...rest, children });
4272
4280
  }
4273
- function StnCardFooter({ children, className, ...rest }) {
4274
- return /* @__PURE__ */ jsx26("div", { className: cn("stn-card__footer", className), ...rest, children });
4281
+ function StnCardFooter({ children, className, align = "right", ...rest }) {
4282
+ return /* @__PURE__ */ jsx26("div", { className: cn("stn-card__footer", `align-${align}`, className), ...rest, children });
4275
4283
  }
4276
4284
  var StnCard = forwardRef21(function StnCard2({
4277
4285
  children,
@@ -8015,7 +8023,7 @@ import {
8015
8023
  // src/components/StnWidget.tsx
8016
8024
  import {
8017
8025
  Children as Children7,
8018
- Fragment as Fragment9,
8026
+ Fragment as Fragment10,
8019
8027
  cloneElement as cloneElement5,
8020
8028
  isValidElement as isValidElement10
8021
8029
  } from "react";
@@ -8517,9 +8525,9 @@ var STN_TOPOLOGY_STATUS_COLORS = {
8517
8525
  label: "\uD3EC\uC778\uD2B8/\uAC70\uC810"
8518
8526
  },
8519
8527
  normal: {
8520
- main: "var(--stn-grade-normal)",
8521
- glow: "color-mix(in srgb, var(--stn-grade-normal) 35%, transparent)",
8522
- text: "var(--stn-grade-normal)",
8528
+ main: "var(--stn-topology-node-normal)",
8529
+ glow: "color-mix(in srgb, var(--stn-topology-node-normal) 35%, transparent)",
8530
+ text: "var(--stn-topology-node-normal)",
8523
8531
  label: "\uC815\uC0C1"
8524
8532
  },
8525
8533
  warning: {
@@ -8547,9 +8555,9 @@ var STN_TOPOLOGY_STATUS_COLORS = {
8547
8555
  label: "\uC2EC\uAC01"
8548
8556
  },
8549
8557
  neutral: {
8550
- main: "var(--stn-grade-neutral)",
8551
- glow: "color-mix(in srgb, var(--stn-grade-neutral) 30%, transparent)",
8552
- text: "var(--stn-grade-neutral)",
8558
+ main: "var(--stn-topology-node-normal)",
8559
+ glow: "color-mix(in srgb, var(--stn-topology-node-normal) 30%, transparent)",
8560
+ text: "var(--stn-topology-node-normal)",
8553
8561
  label: "\uC911\uB9BD/\uB300\uAE30"
8554
8562
  }
8555
8563
  };
@@ -8597,6 +8605,29 @@ function topologyShapePoints(shape, cx, cy, r) {
8597
8605
  if (shape === "square") return polygonPoints(cx, cy, r, 4, 45);
8598
8606
  return polygonPoints(cx, cy, r, 32, 0);
8599
8607
  }
8608
+ var TOPOLOGY_LINK_LABEL_SPEC = {
8609
+ baseFontSize: 4.6,
8610
+ minFontSize: 4,
8611
+ maxFontSize: 5.2,
8612
+ offsetY: 3.2,
8613
+ haloStrokeWidth: 1.2
8614
+ };
8615
+ var TOPOLOGY_NODE_CURRENT_RING_SPEC = {
8616
+ circleOffset: 5.5,
8617
+ // 기존 8.5px -> 5.5px (약 35% 슬림화)
8618
+ squareOffset: 5,
8619
+ // 기존 7.5px -> 5.0px (총 너비/높이 증가분 기존 15 -> 10)
8620
+ squareRxOffset: 2.3,
8621
+ // 기존 3.5px -> 2.3px
8622
+ triangleOffset: 5.5,
8623
+ // 기존 8.5px -> 5.5px
8624
+ starOuterOffset: 5,
8625
+ // 기존 7.5px -> 5.0px
8626
+ starInnerOffset: 2.3,
8627
+ // 기존 3.5px -> 2.3px
8628
+ diamondOffset: 5.3
8629
+ // 기존 8.0px -> 5.3px
8630
+ };
8600
8631
 
8601
8632
  // src/components/topology/StnTopologyNodeMark.tsx
8602
8633
  import { jsx as jsx59, jsxs as jsxs47 } from "react/jsx-runtime";
@@ -8750,8 +8781,7 @@ function StnTopologyNodeMark({
8750
8781
  y: foY,
8751
8782
  width: boxWidth,
8752
8783
  height: boxHeight,
8753
- style: { overflow: "visible" },
8754
- children: /* @__PURE__ */ jsx59("div", { style: { width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx59(
8784
+ children: /* @__PURE__ */ jsx59("div", { children: /* @__PURE__ */ jsx59(
8755
8785
  StnTopologyNodeItem,
8756
8786
  {
8757
8787
  size,
@@ -9316,7 +9346,7 @@ var GLYPH_SIZE_MAP = {
9316
9346
  function StnTopologyNodeGlyph({
9317
9347
  shape = "circle",
9318
9348
  variant = "outline",
9319
- color = "currentColor",
9349
+ color = "var(--stn-topology-node-normal)",
9320
9350
  surfaceBg = "none",
9321
9351
  size = 14,
9322
9352
  strokeWidth = 1.4,
@@ -9353,7 +9383,7 @@ function StnTopologyNodeGlyph({
9353
9383
  }
9354
9384
  StnTopologyNodeGlyph.displayName = "StnTopologyGraph.NodeGlyph";
9355
9385
  function StnTopologyLinkGlyph({
9356
- color = "var(--stn-border-subtle)",
9386
+ color = "var(--stn-topology-link-line)",
9357
9387
  variant = "line",
9358
9388
  size = 14,
9359
9389
  width,
@@ -9662,7 +9692,7 @@ function StnTopologyGraphMinimap({ className, style }) {
9662
9692
  const n2 = nodeMap.get(link.target);
9663
9693
  if (!n1 || !n2) return null;
9664
9694
  const statusColor = link.status === "critical" ? "var(--stn-grade-critical)" : link.status === "major" ? "var(--stn-grade-major)" : link.status === "minor" ? "var(--stn-grade-minor)" : link.status === "warning" ? "var(--stn-grade-warning)" : link.status === "primary" || link.status === "point" ? "var(--stn-primary)" : null;
9665
- const strokeColor = link.color ?? statusColor ?? "var(--stn-border-strong)";
9695
+ const strokeColor = link.color ?? statusColor ?? "var(--stn-topology-link-line)";
9666
9696
  const miniStrokeWidth = typeof link.strokeWidth === "number" ? Math.max(0.6, link.strokeWidth * 0.4) : link.strokeWidth === "xs" ? 0.7 : link.strokeWidth === "sm" ? 1 : link.strokeWidth === "lg" ? 1.8 : link.strokeWidth === "xl" ? 2.5 : 1.2;
9667
9697
  const miniOpacity = resolveTopologyOpacity(link.opacity, 0.7);
9668
9698
  return /* @__PURE__ */ jsx63(
@@ -9760,6 +9790,7 @@ function renderCurrentNodeRing({
9760
9790
  r
9761
9791
  }) {
9762
9792
  const bg = "var(--stn-topology-node-current-bg)";
9793
+ const spec = TOPOLOGY_NODE_CURRENT_RING_SPEC;
9763
9794
  if (shape === "square") {
9764
9795
  const s = r * 1.8;
9765
9796
  const half = s / 2;
@@ -9767,11 +9798,11 @@ function renderCurrentNodeRing({
9767
9798
  return /* @__PURE__ */ jsx63("g", { className: "stn-topology-node__current-ring", children: /* @__PURE__ */ jsx63(
9768
9799
  "rect",
9769
9800
  {
9770
- x: -half - 7.5,
9771
- y: -half - 7.5,
9772
- width: s + 15,
9773
- height: s + 15,
9774
- rx: rx + 3.5,
9801
+ x: -half - spec.squareOffset,
9802
+ y: -half - spec.squareOffset,
9803
+ width: s + spec.squareOffset * 2,
9804
+ height: s + spec.squareOffset * 2,
9805
+ rx: rx + spec.squareRxOffset,
9775
9806
  fill: bg,
9776
9807
  stroke: "none"
9777
9808
  }
@@ -9782,7 +9813,7 @@ function renderCurrentNodeRing({
9782
9813
  return /* @__PURE__ */ jsx63("g", { className: "stn-topology-node__current-ring", children: /* @__PURE__ */ jsx63(
9783
9814
  "polygon",
9784
9815
  {
9785
- points: trianglePoints(0, 0, R2 + 8.5),
9816
+ points: trianglePoints(0, 0, R2 + spec.triangleOffset),
9786
9817
  fill: bg,
9787
9818
  stroke: "none",
9788
9819
  strokeLinejoin: "round"
@@ -9795,7 +9826,7 @@ function renderCurrentNodeRing({
9795
9826
  return /* @__PURE__ */ jsx63("g", { className: "stn-topology-node__current-ring", children: /* @__PURE__ */ jsx63(
9796
9827
  "polygon",
9797
9828
  {
9798
- points: starPoints(0, 0, R2 + 7.5, rIn + 3.5),
9829
+ points: starPoints(0, 0, R2 + spec.starOuterOffset, rIn + spec.starInnerOffset),
9799
9830
  fill: bg,
9800
9831
  stroke: "none",
9801
9832
  strokeLinejoin: "round"
@@ -9807,7 +9838,7 @@ function renderCurrentNodeRing({
9807
9838
  return /* @__PURE__ */ jsx63("g", { className: "stn-topology-node__current-ring", children: /* @__PURE__ */ jsx63(
9808
9839
  "polygon",
9809
9840
  {
9810
- points: diamondPoints(0, 0, R2 + 8),
9841
+ points: diamondPoints(0, 0, R2 + spec.diamondOffset),
9811
9842
  fill: bg,
9812
9843
  stroke: "none"
9813
9844
  }
@@ -9818,7 +9849,7 @@ function renderCurrentNodeRing({
9818
9849
  {
9819
9850
  cx: "0",
9820
9851
  cy: "0",
9821
- r: r + 8.5,
9852
+ r: r + spec.circleOffset,
9822
9853
  fill: bg,
9823
9854
  stroke: "none"
9824
9855
  }
@@ -9835,6 +9866,8 @@ function StnTopologyGraphViewport({ className, style }) {
9835
9866
  onNodeClick,
9836
9867
  onNodeContextMenu,
9837
9868
  onLinkClick,
9869
+ onLinkHover,
9870
+ linkLabelMode,
9838
9871
  onCanvasClick,
9839
9872
  onBackgroundClick,
9840
9873
  handleNodeMouseDown,
@@ -9844,8 +9877,11 @@ function StnTopologyGraphViewport({ className, style }) {
9844
9877
  renderBadge,
9845
9878
  renderNodeLabel,
9846
9879
  hoveredNodeId,
9847
- setHoveredNodeId
9880
+ setHoveredNodeId,
9881
+ hasDraggedRef
9848
9882
  } = useStnTopologyGraph();
9883
+ const [hoveredLinkKey, setHoveredLinkKey] = useState17(null);
9884
+ const isAnyLinkHovered = hoveredLinkKey !== null;
9849
9885
  return /* @__PURE__ */ jsxs50(
9850
9886
  "svg",
9851
9887
  {
@@ -9864,119 +9900,148 @@ function StnTopologyGraphViewport({ className, style }) {
9864
9900
  /* @__PURE__ */ jsx63("stop", { offset: "100%", stopColor: "var(--stn-primary)" })
9865
9901
  ] }) }),
9866
9902
  renderGridLines(),
9867
- /* @__PURE__ */ jsx63("g", { className: "stn-topology-links-group", children: projectedLinks.map((link, idx) => {
9868
- if (!link.n1 || !link.n2) return null;
9869
- const { n1, n2 } = link;
9870
- const depthScale = 550 / (550 + link.avgDepth);
9871
- const baseOpacity = Math.max(0.65, Math.min(1, depthScale));
9872
- const opacity = resolveTopologyOpacity(link.opacity, baseOpacity);
9873
- const isDot = link.variant === "dot";
9874
- const effectiveStatus = link.status ?? (isDot ? n1.status === "critical" || n2.status === "critical" ? "critical" : n1.status === "major" || n2.status === "major" ? "major" : n1.status === "minor" || n2.status === "minor" ? "minor" : n1.status === "warning" || n2.status === "warning" ? "warning" : void 0 : void 0);
9875
- const statusColor = effectiveStatus === "critical" ? "var(--stn-grade-critical)" : effectiveStatus === "major" ? "var(--stn-grade-major)" : effectiveStatus === "minor" ? "var(--stn-grade-minor)" : effectiveStatus === "warning" ? "var(--stn-grade-warning)" : effectiveStatus === "primary" || effectiveStatus === "point" ? "var(--stn-primary)" : null;
9876
- let dotElement = null;
9877
- if (isDot) {
9878
- const midSX = (n1.sx + n2.sx) / 2;
9879
- const midSY = (n1.sy + n2.sy) / 2;
9880
- const dotRadius = Math.max(2, 3 * depthScale * Math.min(1.2, Math.max(0.6, zoom)));
9881
- const dotFill = link.color ?? statusColor ?? "var(--stn-grade-neutral)";
9882
- dotElement = /* @__PURE__ */ jsx63("circle", { cx: midSX, cy: midSY, r: dotRadius, fill: dotFill });
9883
- }
9884
- const lineColor = link.color ?? (!isDot && statusColor ? statusColor : "var(--stn-border-strong)");
9885
- const effectiveStrokeWidth = resolveTopologyStrokeWidth(
9886
- link.strokeWidth,
9887
- depthScale,
9888
- zoom,
9889
- viewMode === "2D"
9890
- );
9891
- let labelElement = null;
9892
- if (link.label) {
9893
- const midX = (n1.sx + n2.sx) / 2;
9894
- const midY = (n1.sy + n2.sy) / 2;
9895
- const dx = n2.sx - n1.sx;
9896
- const dy = n2.sy - n1.sy;
9897
- const angleDeg = Math.atan2(dy, dx) * 180 / Math.PI;
9898
- let rotation = angleDeg;
9899
- if (rotation > 90) {
9900
- rotation -= 180;
9901
- } else if (rotation < -90) {
9902
- rotation += 180;
9903
- }
9904
- const offsetY = -(3.2 + effectiveStrokeWidth / 2);
9905
- const fontSize = Math.max(4.2, Math.min(6.2, 5 * depthScale));
9906
- const labelColor = link.labelColor ?? "var(--stn-topology-link-label-fg, var(--stn-text-secondary))";
9907
- labelElement = /* @__PURE__ */ jsx63(
9908
- "g",
9909
- {
9910
- className: "stn-topology-link__label",
9911
- transform: `translate(${midX}, ${midY}) rotate(${rotation})`,
9912
- style: { pointerEvents: "none", userSelect: "none" },
9913
- children: /* @__PURE__ */ jsx63(
9914
- "text",
9915
- {
9916
- x: 0,
9917
- y: offsetY,
9918
- textAnchor: "middle",
9919
- dominantBaseline: "alphabetic",
9920
- fill: labelColor,
9921
- stroke: "var(--stn-topology-link-label-halo, var(--stn-elevation-surface-0))",
9922
- strokeWidth: 2.4,
9923
- paintOrder: "stroke",
9924
- strokeLinejoin: "round",
9925
- fontSize,
9926
- fontWeight: 600,
9927
- letterSpacing: "-0.2px",
9928
- children: link.label
9929
- }
9930
- )
9903
+ /* @__PURE__ */ jsx63(
9904
+ "g",
9905
+ {
9906
+ className: cn(
9907
+ "stn-topology-links-group",
9908
+ isAnyLinkHovered && "is-link-hovered",
9909
+ `stn-topology-links-group--label-${linkLabelMode}`
9910
+ ),
9911
+ children: projectedLinks.map((link, idx) => {
9912
+ if (!link.n1 || !link.n2) return null;
9913
+ const { n1, n2 } = link;
9914
+ const depthScale = 550 / (550 + link.avgDepth);
9915
+ const baseOpacity = Math.max(0.65, Math.min(1, depthScale));
9916
+ const opacity = resolveTopologyOpacity(link.opacity, baseOpacity);
9917
+ const linkKey = String(link.id ?? `${link.source}-${link.target}-${idx}`);
9918
+ const isThisLinkHovered = hoveredLinkKey === linkKey;
9919
+ const effectiveLineOpacity = isThisLinkHovered ? 1 : opacity;
9920
+ const isLabelVisible = linkLabelMode === "always" || linkLabelMode === "hover" && isAnyLinkHovered;
9921
+ const isDot = link.variant === "dot";
9922
+ const effectiveStatus = link.status ?? (isDot ? n1.status === "critical" || n2.status === "critical" ? "critical" : n1.status === "major" || n2.status === "major" ? "major" : n1.status === "minor" || n2.status === "minor" ? "minor" : n1.status === "warning" || n2.status === "warning" ? "warning" : void 0 : void 0);
9923
+ const statusColor = effectiveStatus === "critical" ? "var(--stn-grade-critical)" : effectiveStatus === "major" ? "var(--stn-grade-major)" : effectiveStatus === "minor" ? "var(--stn-grade-minor)" : effectiveStatus === "warning" ? "var(--stn-grade-warning)" : effectiveStatus === "primary" || effectiveStatus === "point" ? "var(--stn-primary)" : null;
9924
+ let dotElement = null;
9925
+ if (isDot) {
9926
+ const midSX = (n1.sx + n2.sx) / 2;
9927
+ const midSY = (n1.sy + n2.sy) / 2;
9928
+ const dotRadius = Math.max(2, 3 * depthScale * Math.min(1.2, Math.max(0.6, zoom)));
9929
+ const dotFill = link.color ?? statusColor ?? "var(--stn-topology-node-normal)";
9930
+ dotElement = /* @__PURE__ */ jsx63("circle", { cx: midSX, cy: midSY, r: dotRadius, fill: dotFill, opacity: effectiveLineOpacity });
9931
9931
  }
9932
- );
9933
- }
9934
- const isClickable = Boolean(onLinkClick);
9935
- return /* @__PURE__ */ jsxs50(
9936
- "g",
9937
- {
9938
- opacity,
9939
- className: cn("stn-topology-link", isClickable && "stn-topology-link--clickable"),
9940
- style: { cursor: isClickable ? "pointer" : void 0 },
9941
- onClick: (e) => {
9942
- if (onLinkClick) {
9943
- e.stopPropagation();
9944
- onLinkClick(link, e);
9932
+ const lineColor = link.color ?? (!isDot && statusColor ? statusColor : "var(--stn-topology-link-line)");
9933
+ const effectiveStrokeWidth = resolveTopologyStrokeWidth(
9934
+ link.strokeWidth,
9935
+ depthScale,
9936
+ zoom,
9937
+ viewMode === "2D"
9938
+ );
9939
+ let labelElement = null;
9940
+ if (link.label) {
9941
+ const midX = (n1.sx + n2.sx) / 2;
9942
+ const midY = (n1.sy + n2.sy) / 2;
9943
+ const dx = n2.sx - n1.sx;
9944
+ const dy = n2.sy - n1.sy;
9945
+ const angleDeg = Math.atan2(dy, dx) * 180 / Math.PI;
9946
+ let rotation = angleDeg;
9947
+ if (rotation > 90) {
9948
+ rotation -= 180;
9949
+ } else if (rotation < -90) {
9950
+ rotation += 180;
9945
9951
  }
9946
- },
9947
- children: [
9948
- isClickable && /* @__PURE__ */ jsx63(
9949
- "line",
9950
- {
9951
- x1: n1.sx,
9952
- y1: n1.sy,
9953
- x2: n2.sx,
9954
- y2: n2.sy,
9955
- stroke: "transparent",
9956
- strokeWidth: Math.max(16, effectiveStrokeWidth + 12),
9957
- pointerEvents: "stroke"
9958
- }
9959
- ),
9960
- /* @__PURE__ */ jsx63(
9961
- "line",
9952
+ const offsetY = -(TOPOLOGY_LINK_LABEL_SPEC.offsetY + effectiveStrokeWidth / 2);
9953
+ const fontSize = Math.max(
9954
+ TOPOLOGY_LINK_LABEL_SPEC.minFontSize,
9955
+ Math.min(TOPOLOGY_LINK_LABEL_SPEC.maxFontSize, TOPOLOGY_LINK_LABEL_SPEC.baseFontSize * depthScale)
9956
+ );
9957
+ const labelColor = link.labelColor ?? "var(--stn-topology-link-label-fg, var(--stn-text-secondary))";
9958
+ labelElement = /* @__PURE__ */ jsx63(
9959
+ "g",
9962
9960
  {
9963
- x1: n1.sx,
9964
- y1: n1.sy,
9965
- x2: n2.sx,
9966
- y2: n2.sy,
9967
- stroke: lineColor,
9968
- strokeWidth: effectiveStrokeWidth,
9969
- strokeDasharray: link.dashed ? "4 4" : void 0,
9970
- pointerEvents: isClickable ? "stroke" : "none"
9961
+ className: "stn-topology-link__label",
9962
+ transform: `translate(${midX}, ${midY}) rotate(${rotation})`,
9963
+ opacity: isLabelVisible ? 1 : 0,
9964
+ children: /* @__PURE__ */ jsx63(
9965
+ "text",
9966
+ {
9967
+ x: 0,
9968
+ y: offsetY,
9969
+ textAnchor: "middle",
9970
+ dominantBaseline: "alphabetic",
9971
+ fill: labelColor,
9972
+ stroke: "var(--stn-topology-link-label-halo, var(--stn-elevation-surface-0))",
9973
+ strokeWidth: TOPOLOGY_LINK_LABEL_SPEC.haloStrokeWidth,
9974
+ paintOrder: "stroke",
9975
+ strokeLinejoin: "round",
9976
+ fontSize,
9977
+ fontWeight: 600,
9978
+ letterSpacing: "-0.2px",
9979
+ children: link.label
9980
+ }
9981
+ )
9971
9982
  }
9972
- ),
9973
- dotElement,
9974
- labelElement
9975
- ]
9976
- },
9977
- `link-${idx}`
9978
- );
9979
- }) }),
9983
+ );
9984
+ }
9985
+ const isClickable = Boolean(onLinkClick);
9986
+ return /* @__PURE__ */ jsxs50(
9987
+ "g",
9988
+ {
9989
+ className: cn(
9990
+ "stn-topology-link",
9991
+ isClickable && "stn-topology-link--clickable",
9992
+ isThisLinkHovered && "is-hovered"
9993
+ ),
9994
+ style: { cursor: isClickable ? "pointer" : void 0 },
9995
+ onMouseEnter: (e) => {
9996
+ setHoveredLinkKey(linkKey);
9997
+ onLinkHover?.(link, e);
9998
+ },
9999
+ onMouseLeave: (e) => {
10000
+ setHoveredLinkKey((prev) => prev === linkKey ? null : prev);
10001
+ onLinkHover?.(null, e);
10002
+ },
10003
+ onClick: (e) => {
10004
+ if (onLinkClick) {
10005
+ e.stopPropagation();
10006
+ onLinkClick(link, e);
10007
+ }
10008
+ },
10009
+ children: [
10010
+ /* @__PURE__ */ jsx63(
10011
+ "line",
10012
+ {
10013
+ x1: n1.sx,
10014
+ y1: n1.sy,
10015
+ x2: n2.sx,
10016
+ y2: n2.sy,
10017
+ stroke: "transparent",
10018
+ strokeWidth: Math.max(20, effectiveStrokeWidth + 16),
10019
+ pointerEvents: "stroke"
10020
+ }
10021
+ ),
10022
+ /* @__PURE__ */ jsx63(
10023
+ "line",
10024
+ {
10025
+ x1: n1.sx,
10026
+ y1: n1.sy,
10027
+ x2: n2.sx,
10028
+ y2: n2.sy,
10029
+ stroke: lineColor,
10030
+ strokeWidth: effectiveStrokeWidth,
10031
+ strokeDasharray: link.dashed ? "4 4" : void 0,
10032
+ opacity: effectiveLineOpacity,
10033
+ pointerEvents: "none"
10034
+ }
10035
+ ),
10036
+ dotElement,
10037
+ labelElement
10038
+ ]
10039
+ },
10040
+ `link-${idx}`
10041
+ );
10042
+ })
10043
+ }
10044
+ ),
9980
10045
  /* @__PURE__ */ jsx63("g", { className: "stn-topology-nodes-group", children: sortedNodes.map((n) => {
9981
10046
  const depthScale = 550 / (550 + n.depth);
9982
10047
  const scale = Math.max(0.4, n.scale);
@@ -9994,7 +10059,7 @@ function StnTopologyGraphViewport({ className, style }) {
9994
10059
  const hasPulse = isCritical || Boolean(n.pulse);
9995
10060
  const shape = n.shape ?? (isCore ? "diamond" : "circle");
9996
10061
  const variant = n.variant ?? (isCore ? "combined" : "outline");
9997
- const statusColor = n.color ? n.color : isCritical ? "var(--stn-grade-critical)" : isMajor ? "var(--stn-grade-major)" : isMinor ? "var(--stn-grade-minor)" : isWarning ? "var(--stn-grade-warning)" : isPrimary || isCore ? "var(--stn-primary)" : isNeutral ? "var(--stn-grade-neutral)" : isNormal ? "var(--stn-grade-normal)" : "var(--stn-grade-neutral)";
10062
+ const statusColor = n.color ? n.color : isCritical ? "var(--stn-grade-critical)" : isMajor ? "var(--stn-grade-major)" : isMinor ? "var(--stn-grade-minor)" : isWarning ? "var(--stn-grade-warning)" : isPrimary || isCore ? "var(--stn-primary)" : isNormal || isNeutral ? "var(--stn-topology-node-normal)" : "var(--stn-topology-node-normal)";
9998
10063
  const baseRadius = typeof n.size === "number" ? n.size : n.size && TOPOLOGY_NODE_SIZE_MAP[n.size] ? TOPOLOGY_NODE_SIZE_MAP[n.size] : isCore ? TOPOLOGY_NODE_SIZE_MAP.lg : TOPOLOGY_NODE_SIZE_MAP.md;
9999
10064
  const r = baseRadius * scale;
10000
10065
  const strokeWidth = "var(--stn-topology-node-stroke, 1.2px)";
@@ -10050,40 +10115,23 @@ function StnTopologyGraphViewport({ className, style }) {
10050
10115
  y: posY,
10051
10116
  width: bW,
10052
10117
  height: bH,
10053
- style: { overflow: "visible", pointerEvents: "none" },
10054
- children: /* @__PURE__ */ jsx63(
10118
+ className: "stn-topology-node__badge-fo",
10119
+ children: /* @__PURE__ */ jsx63("div", { className: "stn-topology-node__badge-fo-inner", children: /* @__PURE__ */ jsx63(
10055
10120
  "div",
10056
10121
  {
10057
- style: {
10058
- display: "flex",
10059
- justifyContent: "center",
10060
- alignItems: "center",
10061
- width: "100%",
10062
- height: "100%",
10063
- pointerEvents: "none"
10064
- },
10122
+ className: "stn-topology-node__badge-fo-scale",
10123
+ style: { transform: `scale(${badgeScale})` },
10065
10124
  children: /* @__PURE__ */ jsx63(
10066
- "div",
10125
+ StnBadge,
10067
10126
  {
10068
- style: {
10069
- display: "inline-flex",
10070
- transform: `scale(${badgeScale})`,
10071
- transformOrigin: "center center",
10072
- userSelect: "none"
10073
- },
10074
- children: /* @__PURE__ */ jsx63(
10075
- StnBadge,
10076
- {
10077
- color: n.badgeColor ?? "primary",
10078
- appearance: n.badgeAppearance ?? "solid",
10079
- badgeContent: badgeText,
10080
- ...n.badgeProps
10081
- }
10082
- )
10127
+ color: n.badgeColor ?? "primary",
10128
+ appearance: n.badgeAppearance ?? "solid",
10129
+ badgeContent: badgeText,
10130
+ ...n.badgeProps
10083
10131
  }
10084
10132
  )
10085
10133
  }
10086
- )
10134
+ ) })
10087
10135
  }
10088
10136
  );
10089
10137
  }
@@ -10111,41 +10159,24 @@ function StnTopologyGraphViewport({ className, style }) {
10111
10159
  y: posY,
10112
10160
  width: bW,
10113
10161
  height: bH,
10114
- style: { overflow: "visible", pointerEvents: "none" },
10115
- children: /* @__PURE__ */ jsx63(
10162
+ className: "stn-topology-node__badge-fo",
10163
+ children: /* @__PURE__ */ jsx63("div", { className: "stn-topology-node__badge-fo-inner", children: /* @__PURE__ */ jsx63(
10116
10164
  "div",
10117
10165
  {
10118
- style: {
10119
- display: "flex",
10120
- justifyContent: "center",
10121
- alignItems: "center",
10122
- width: "100%",
10123
- height: "100%",
10124
- pointerEvents: "none"
10125
- },
10166
+ className: "stn-topology-node__badge-fo-scale",
10167
+ style: { transform: `scale(${badgeScale})` },
10126
10168
  children: /* @__PURE__ */ jsx63(
10127
- "div",
10169
+ StnBadge,
10128
10170
  {
10129
- style: {
10130
- display: "inline-flex",
10131
- transform: `scale(${badgeScale})`,
10132
- transformOrigin: "center center",
10133
- userSelect: "none"
10134
- },
10135
- children: /* @__PURE__ */ jsx63(
10136
- StnBadge,
10137
- {
10138
- color: n.labelBadgeColor ?? "neutral",
10139
- appearance: n.labelBadgeAppearance ?? "subtle",
10140
- badgeContent: labelText,
10141
- className: cn("stn-topology-node__label-badge", n.labelBadgeProps?.className),
10142
- ...n.labelBadgeProps
10143
- }
10144
- )
10171
+ color: n.labelBadgeColor ?? "neutral",
10172
+ appearance: n.labelBadgeAppearance ?? "subtle",
10173
+ badgeContent: labelText,
10174
+ className: cn("stn-topology-node__label-badge", n.labelBadgeProps?.className),
10175
+ ...n.labelBadgeProps
10145
10176
  }
10146
10177
  )
10147
10178
  }
10148
- )
10179
+ ) })
10149
10180
  }
10150
10181
  );
10151
10182
  } else {
@@ -10164,7 +10195,6 @@ function StnTopologyGraphViewport({ className, style }) {
10164
10195
  fontSize: 5.8,
10165
10196
  fontWeight: 700,
10166
10197
  letterSpacing: "-0.2px",
10167
- style: { userSelect: "none", pointerEvents: "none" },
10168
10198
  children: labelText
10169
10199
  }
10170
10200
  ) });
@@ -10187,6 +10217,9 @@ function StnTopologyGraphViewport({ className, style }) {
10187
10217
  onMouseDown: (e) => handleNodeMouseDown(e, n.id),
10188
10218
  onClick: (e) => {
10189
10219
  e.stopPropagation();
10220
+ if (hasDraggedRef.current) {
10221
+ return;
10222
+ }
10190
10223
  onNodeClick?.(n);
10191
10224
  },
10192
10225
  onContextMenu: (e) => {
@@ -10241,8 +10274,8 @@ function StnTopologyGraphViewport({ className, style }) {
10241
10274
  children: /* @__PURE__ */ jsxs50(
10242
10275
  "g",
10243
10276
  {
10277
+ className: "stn-topology-node-tooltip__box",
10244
10278
  transform: `translate(0, ${tooltipBoxY})`,
10245
- style: { filter: "drop-shadow(0px 1px 2px var(--stn-opacity-black-25))" },
10246
10279
  children: [
10247
10280
  /* @__PURE__ */ jsx63(
10248
10281
  "rect",
@@ -10273,7 +10306,6 @@ function StnTopologyGraphViewport({ className, style }) {
10273
10306
  fontSize: 6.8,
10274
10307
  fontWeight: 600,
10275
10308
  letterSpacing: "-0.1px",
10276
- style: { userSelect: "none", pointerEvents: "none", fontFamily: "inherit" },
10277
10309
  children: n.label
10278
10310
  }
10279
10311
  )
@@ -10303,10 +10335,12 @@ var StnTopologyGraphInternal = forwardRef39(
10303
10335
  onModeChange,
10304
10336
  showModeToggle = true,
10305
10337
  showToolbar = true,
10306
- showMinimap = true,
10338
+ showMinimap = false,
10307
10339
  showTooltips = false,
10308
10340
  showNodeLabels = true,
10309
10341
  nodeLabelMode = "badge",
10342
+ linkLabelMode = "hover",
10343
+ onLinkHover,
10310
10344
  useHtmlBadge = true,
10311
10345
  renderBadge,
10312
10346
  renderNodeLabel,
@@ -10377,15 +10411,32 @@ var StnTopologyGraphInternal = forwardRef39(
10377
10411
  const lastMousePosRef = useRef11({ x: 0, y: 0 });
10378
10412
  const viewModeRef = useRef11(viewMode);
10379
10413
  viewModeRef.current = viewMode;
10414
+ const pitchRef = useRef11(pitch);
10415
+ pitchRef.current = pitch;
10416
+ const yawRef = useRef11(yaw);
10417
+ yawRef.current = yaw;
10418
+ const zoomRef = useRef11(zoom);
10419
+ zoomRef.current = zoom;
10380
10420
  useEffect14(() => {
10381
10421
  setNodeList((prev) => {
10382
10422
  if (prev === effectiveNodes) return prev;
10383
- if (prev.length === effectiveNodes.length && prev.every(
10384
- (n, i) => n.id === effectiveNodes[i].id && n.x === effectiveNodes[i].x && n.y === effectiveNodes[i].y && n.z === effectiveNodes[i].z && n.status === effectiveNodes[i].status && n.pulse === effectiveNodes[i].pulse && n.isCurrent === effectiveNodes[i].isCurrent && n.isSelected === effectiveNodes[i].isSelected && n.opacity === effectiveNodes[i].opacity && n.variant === effectiveNodes[i].variant && n.label === effectiveNodes[i].label && n.color === effectiveNodes[i].color && n.badge === effectiveNodes[i].badge && n.badgeColor === effectiveNodes[i].badgeColor && n.badgeAppearance === effectiveNodes[i].badgeAppearance && n.labelBadgeColor === effectiveNodes[i].labelBadgeColor && n.labelBadgeAppearance === effectiveNodes[i].labelBadgeAppearance
10423
+ const prevPosMap = /* @__PURE__ */ new Map();
10424
+ for (const n of prev) {
10425
+ prevPosMap.set(n.id, { x: n.x, y: n.y, z: n.z });
10426
+ }
10427
+ const merged = effectiveNodes.map((n) => {
10428
+ const savedPos = prevPosMap.get(n.id);
10429
+ if (savedPos) {
10430
+ return { ...n, x: savedPos.x, y: savedPos.y, z: savedPos.z ?? n.z };
10431
+ }
10432
+ return n;
10433
+ });
10434
+ if (prev.length === merged.length && prev.every(
10435
+ (n, i) => n.id === merged[i].id && n.x === merged[i].x && n.y === merged[i].y && n.z === merged[i].z && n.status === merged[i].status && n.pulse === merged[i].pulse && n.isCurrent === merged[i].isCurrent && n.isSelected === merged[i].isSelected && n.opacity === merged[i].opacity && n.variant === merged[i].variant && n.label === merged[i].label && n.color === merged[i].color && n.badge === merged[i].badge && n.badgeColor === merged[i].badgeColor && n.badgeAppearance === merged[i].badgeAppearance && n.labelBadgeColor === merged[i].labelBadgeColor && n.labelBadgeAppearance === merged[i].labelBadgeAppearance
10385
10436
  )) {
10386
10437
  return prev;
10387
10438
  }
10388
- return effectiveNodes;
10439
+ return merged;
10389
10440
  });
10390
10441
  }, [effectiveNodes]);
10391
10442
  const handleSwitchMode = useCallback10(
@@ -10476,11 +10527,54 @@ var StnTopologyGraphInternal = forwardRef39(
10476
10527
  const dx = e.clientX - lastMousePosRef.current.x;
10477
10528
  const dy = e.clientY - lastMousePosRef.current.y;
10478
10529
  lastMousePosRef.current = { x: e.clientX, y: e.clientY };
10479
- setNodeList(
10480
- (prev) => prev.map(
10481
- (n) => n.id === draggedNodeIdRef.current ? { ...n, x: n.x + dx * 0.8, y: n.y + dy * 0.8 } : n
10482
- )
10483
- );
10530
+ const currentZoom = Math.max(0.1, zoomRef.current);
10531
+ const svg = containerRef.current?.querySelector("svg.stn-topology-graph__svg");
10532
+ const ctm = svg?.getScreenCTM();
10533
+ const rect = containerRef.current?.getBoundingClientRect();
10534
+ const screenPixelsPerSvgUnit = ctm && ctm.a > 0 ? ctm.a : rect && rect.height > 0 && rect.width > 0 ? Math.min(rect.width, rect.height) / 500 : 1;
10535
+ if (viewModeRef.current === "2D") {
10536
+ const moveFactor = 1 / (currentZoom * screenPixelsPerSvgUnit);
10537
+ setNodeList(
10538
+ (prev) => prev.map(
10539
+ (n) => n.id === draggedNodeIdRef.current ? { ...n, x: n.x + dx * moveFactor, y: n.y + dy * moveFactor } : n
10540
+ )
10541
+ );
10542
+ } else {
10543
+ const currentPitch = pitchRef.current;
10544
+ const currentYaw = yawRef.current;
10545
+ const radY = currentYaw * (Math.PI / 180);
10546
+ const radP = currentPitch * (Math.PI / 180);
10547
+ const cosY = Math.cos(radY);
10548
+ const sinY = Math.sin(radY);
10549
+ const cosP = Math.cos(radP);
10550
+ const sinP = Math.sin(radP);
10551
+ setNodeList((prev) => {
10552
+ const target = prev.find((n) => n.id === draggedNodeIdRef.current);
10553
+ if (!target) return prev;
10554
+ const proj = project3DCoordinate(
10555
+ target.x,
10556
+ target.y,
10557
+ target.z ?? 0,
10558
+ currentYaw,
10559
+ currentPitch,
10560
+ currentZoom
10561
+ );
10562
+ const effectiveScale = Math.max(0.05, proj.scale * screenPixelsPerSvgUnit);
10563
+ const dx_cam = dx / effectiveScale;
10564
+ const dy_cam = dy / effectiveScale;
10565
+ const dx_world = dx_cam * cosY + dy_cam * sinP * sinY;
10566
+ const dy_world = dy_cam * cosP;
10567
+ const dz_world = dx_cam * sinY - dy_cam * sinP * cosY;
10568
+ return prev.map(
10569
+ (n) => n.id === draggedNodeIdRef.current ? {
10570
+ ...n,
10571
+ x: n.x + dx_world,
10572
+ y: n.y + dy_world,
10573
+ z: (n.z ?? 0) + dz_world
10574
+ } : n
10575
+ );
10576
+ });
10577
+ }
10484
10578
  } else if (isOrbitingRef.current) {
10485
10579
  if (viewModeRef.current === "2D") return;
10486
10580
  const dx = e.clientX - lastMousePosRef.current.x;
@@ -10502,6 +10596,9 @@ var StnTopologyGraphInternal = forwardRef39(
10502
10596
  isOrbitingRef.current = false;
10503
10597
  isDraggingNodeRef.current = false;
10504
10598
  draggedNodeIdRef.current = null;
10599
+ setTimeout(() => {
10600
+ hasDraggedRef.current = false;
10601
+ }, 120);
10505
10602
  }, []);
10506
10603
  useEffect14(() => {
10507
10604
  window.addEventListener("mousemove", handleMouseMove);
@@ -10620,6 +10717,8 @@ var StnTopologyGraphInternal = forwardRef39(
10620
10717
  onNodeClick,
10621
10718
  onNodeContextMenu,
10622
10719
  onLinkClick,
10720
+ onLinkHover,
10721
+ linkLabelMode,
10623
10722
  onCanvasClick,
10624
10723
  onBackgroundClick,
10625
10724
  handleNodeMouseDown,
@@ -10632,7 +10731,8 @@ var StnTopologyGraphInternal = forwardRef39(
10632
10731
  renderBadge,
10633
10732
  renderNodeLabel,
10634
10733
  hoveredNodeId,
10635
- setHoveredNodeId
10734
+ setHoveredNodeId,
10735
+ hasDraggedRef
10636
10736
  };
10637
10737
  return /* @__PURE__ */ jsx63(StnTopologyGraphContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs50(
10638
10738
  "div",
@@ -10694,8 +10794,8 @@ StnTopologyGraph2.Viewport = StnTopologyGraphViewport;
10694
10794
  StnTopologyGraph2.displayName = "StnTopologyGraph";
10695
10795
 
10696
10796
  // src/components/topology/StnTopologyNodeContextMenu.tsx
10697
- import { forwardRef as forwardRef40 } from "react";
10698
- import { jsx as jsx64, jsxs as jsxs51 } from "react/jsx-runtime";
10797
+ import { forwardRef as forwardRef40, useState as useState18, useRef as useRef12, useEffect as useEffect15 } from "react";
10798
+ import { Fragment as Fragment9, jsx as jsx64, jsxs as jsxs51 } from "react/jsx-runtime";
10699
10799
  var CIRCLED_TO_PLAIN = {
10700
10800
  "\u2460": "1",
10701
10801
  "\u2461": "2",
@@ -10716,93 +10816,195 @@ var StepBadge = ({ num }) => {
10716
10816
  };
10717
10817
  var StnTopologyNodeContextMenu = forwardRef40(
10718
10818
  function StnTopologyNodeContextMenu2({ target, onClose, onAction }, ref) {
10819
+ const [submenuAnchorEl, setSubmenuAnchorEl] = useState18(null);
10820
+ const closeTimerRef = useRef12(null);
10821
+ useEffect15(() => {
10822
+ if (!target) {
10823
+ if (closeTimerRef.current) {
10824
+ clearTimeout(closeTimerRef.current);
10825
+ closeTimerRef.current = null;
10826
+ }
10827
+ setSubmenuAnchorEl(null);
10828
+ }
10829
+ }, [target]);
10830
+ useEffect15(() => {
10831
+ return () => {
10832
+ if (closeTimerRef.current) {
10833
+ clearTimeout(closeTimerRef.current);
10834
+ }
10835
+ };
10836
+ }, []);
10719
10837
  if (!target) return null;
10838
+ const handleClose = () => {
10839
+ if (closeTimerRef.current) {
10840
+ clearTimeout(closeTimerRef.current);
10841
+ closeTimerRef.current = null;
10842
+ }
10843
+ setSubmenuAnchorEl(null);
10844
+ onClose();
10845
+ };
10720
10846
  const handleItemClick = (key) => {
10721
- onAction?.(key, target.node);
10847
+ if (closeTimerRef.current) {
10848
+ clearTimeout(closeTimerRef.current);
10849
+ closeTimerRef.current = null;
10850
+ }
10851
+ setSubmenuAnchorEl(null);
10852
+ if (target) {
10853
+ onAction?.(key, target.node);
10854
+ }
10722
10855
  onClose();
10723
10856
  };
10724
- return /* @__PURE__ */ jsxs51(
10725
- StnMenu,
10726
- {
10727
- ref,
10728
- open: Boolean(target),
10729
- onClose,
10730
- anchorReference: "anchorPosition",
10731
- anchorPosition: target ? { top: target.mouseY, left: target.mouseX } : void 0,
10732
- width: "w200",
10733
- elevation: 3,
10734
- children: [
10735
- /* @__PURE__ */ jsx64(StnMenu.Subheader, { children: target.node.label || `NODE-${target.node.id}` }),
10736
- /* @__PURE__ */ jsx64(
10737
- StnMenu.Item,
10738
- {
10739
- icon: /* @__PURE__ */ jsx64(StepBadge, { num: "1" }),
10740
- onClick: () => handleItemClick("create-node"),
10741
- children: "\uC2E0\uADDC\uB178\uB4DC \uC0DD\uC131"
10742
- }
10743
- ),
10744
- /* @__PURE__ */ jsx64(
10745
- StnMenu.Item,
10746
- {
10747
- icon: /* @__PURE__ */ jsx64(StepBadge, { num: "2" }),
10748
- onClick: () => handleItemClick("create-link"),
10749
- children: "\uB9C1\uD06C \uC0DD\uC131"
10750
- }
10751
- ),
10752
- /* @__PURE__ */ jsx64(
10753
- StnMenu.Item,
10754
- {
10755
- icon: /* @__PURE__ */ jsx64(StepBadge, { num: "3" }),
10756
- onClick: () => handleItemClick("edit-links"),
10757
- children: "\uB9C1\uD06C \uD3B8\uC9D1 (\uBAA9\uB85D)"
10758
- }
10759
- ),
10760
- /* @__PURE__ */ jsx64(
10761
- StnMenu.Item,
10762
- {
10763
- icon: /* @__PURE__ */ jsx64(StepBadge, { num: "4" }),
10764
- onClick: () => handleItemClick("create-service"),
10765
- children: "\uC11C\uBE44\uC2A4 \uC0DD\uC131"
10766
- }
10767
- ),
10768
- /* @__PURE__ */ jsx64(StnMenu.Divider, {}),
10769
- /* @__PURE__ */ jsx64(
10770
- StnMenu.Item,
10771
- {
10772
- icon: "line/activity",
10773
- onClick: () => handleItemClick("create-tunnel"),
10774
- children: "\uD130\uB110 \uC0DD\uC131"
10775
- }
10776
- ),
10777
- /* @__PURE__ */ jsx64(
10778
- StnMenu.Item,
10779
- {
10780
- icon: "line/settings",
10781
- shortcut: /* @__PURE__ */ jsx64(StnIcon, { name: "line/chevron-right", size: 14 }),
10782
- onClick: () => handleItemClick("individual-design"),
10783
- children: "\uAC1C\uBCC4 \uC124\uACC4"
10784
- }
10785
- ),
10786
- /* @__PURE__ */ jsx64(StnMenu.Divider, {}),
10787
- /* @__PURE__ */ jsx64(
10788
- StnMenu.Item,
10789
- {
10790
- icon: "line/refresh",
10791
- onClick: () => handleItemClick("sync-request"),
10792
- children: "\uB3D9\uAE30\uD654 \uC694\uCCAD"
10793
- }
10794
- ),
10795
- /* @__PURE__ */ jsx64(
10796
- StnMenu.Item,
10797
- {
10798
- icon: "line/terminal",
10799
- onClick: () => handleItemClick("device-connect"),
10800
- children: "\uC7A5\uBE44 \uC811\uC18D"
10801
- }
10802
- )
10803
- ]
10857
+ const handleEnterIndividualDesign = (e) => {
10858
+ if (closeTimerRef.current) {
10859
+ clearTimeout(closeTimerRef.current);
10860
+ closeTimerRef.current = null;
10804
10861
  }
10805
- );
10862
+ setSubmenuAnchorEl(e.currentTarget);
10863
+ };
10864
+ const handleLeaveIndividualDesign = () => {
10865
+ closeTimerRef.current = window.setTimeout(() => {
10866
+ setSubmenuAnchorEl(null);
10867
+ }, 180);
10868
+ };
10869
+ const handleHoverOtherItem = () => {
10870
+ if (closeTimerRef.current) {
10871
+ clearTimeout(closeTimerRef.current);
10872
+ closeTimerRef.current = null;
10873
+ }
10874
+ setSubmenuAnchorEl(null);
10875
+ };
10876
+ const handleEnterSubmenu = () => {
10877
+ if (closeTimerRef.current) {
10878
+ clearTimeout(closeTimerRef.current);
10879
+ closeTimerRef.current = null;
10880
+ }
10881
+ };
10882
+ const handleLeaveSubmenu = () => {
10883
+ closeTimerRef.current = window.setTimeout(() => {
10884
+ setSubmenuAnchorEl(null);
10885
+ }, 180);
10886
+ };
10887
+ return /* @__PURE__ */ jsxs51(Fragment9, { children: [
10888
+ /* @__PURE__ */ jsxs51(
10889
+ StnMenu,
10890
+ {
10891
+ ref,
10892
+ open: Boolean(target),
10893
+ onClose: handleClose,
10894
+ anchorReference: "anchorPosition",
10895
+ anchorPosition: target ? { top: target.mouseY, left: target.mouseX } : void 0,
10896
+ width: "w200",
10897
+ elevation: 3,
10898
+ children: [
10899
+ /* @__PURE__ */ jsx64(StnMenu.Subheader, { children: target.node.label || `NODE-${target.node.id}` }),
10900
+ /* @__PURE__ */ jsx64(
10901
+ StnMenu.Item,
10902
+ {
10903
+ icon: /* @__PURE__ */ jsx64(StepBadge, { num: "1" }),
10904
+ onMouseEnter: handleHoverOtherItem,
10905
+ onClick: () => handleItemClick("create-node"),
10906
+ children: "\uC2E0\uADDC\uB178\uB4DC \uC0DD\uC131"
10907
+ }
10908
+ ),
10909
+ /* @__PURE__ */ jsx64(
10910
+ StnMenu.Item,
10911
+ {
10912
+ icon: /* @__PURE__ */ jsx64(StepBadge, { num: "2" }),
10913
+ onMouseEnter: handleHoverOtherItem,
10914
+ onClick: () => handleItemClick("create-link"),
10915
+ children: "\uB9C1\uD06C \uC0DD\uC131"
10916
+ }
10917
+ ),
10918
+ /* @__PURE__ */ jsx64(
10919
+ StnMenu.Item,
10920
+ {
10921
+ icon: /* @__PURE__ */ jsx64(StepBadge, { num: "3" }),
10922
+ onMouseEnter: handleHoverOtherItem,
10923
+ onClick: () => handleItemClick("edit-links"),
10924
+ children: "\uB9C1\uD06C \uD3B8\uC9D1 (\uBAA9\uB85D)"
10925
+ }
10926
+ ),
10927
+ /* @__PURE__ */ jsx64(
10928
+ StnMenu.Item,
10929
+ {
10930
+ icon: /* @__PURE__ */ jsx64(StepBadge, { num: "4" }),
10931
+ onMouseEnter: handleHoverOtherItem,
10932
+ onClick: () => handleItemClick("create-service"),
10933
+ children: "\uC11C\uBE44\uC2A4 \uC0DD\uC131"
10934
+ }
10935
+ ),
10936
+ /* @__PURE__ */ jsx64(StnMenu.Divider, {}),
10937
+ /* @__PURE__ */ jsx64(
10938
+ StnMenu.Item,
10939
+ {
10940
+ icon: "line/activity",
10941
+ onMouseEnter: handleHoverOtherItem,
10942
+ onClick: () => handleItemClick("create-tunnel"),
10943
+ children: "\uD130\uB110 \uC0DD\uC131"
10944
+ }
10945
+ ),
10946
+ /* @__PURE__ */ jsx64(
10947
+ StnMenu.Item,
10948
+ {
10949
+ icon: "line/tool",
10950
+ shortcut: /* @__PURE__ */ jsx64(StnIcon, { name: "line/chevron-right", size: 14 }),
10951
+ selected: Boolean(submenuAnchorEl),
10952
+ onMouseEnter: handleEnterIndividualDesign,
10953
+ onMouseLeave: handleLeaveIndividualDesign,
10954
+ onClick: handleEnterIndividualDesign,
10955
+ children: "\uAC1C\uBCC4 \uC124\uACC4"
10956
+ }
10957
+ ),
10958
+ /* @__PURE__ */ jsx64(StnMenu.Divider, {}),
10959
+ /* @__PURE__ */ jsx64(
10960
+ StnMenu.Item,
10961
+ {
10962
+ icon: "line/refresh",
10963
+ onMouseEnter: handleHoverOtherItem,
10964
+ onClick: () => handleItemClick("sync-request"),
10965
+ children: "\uB3D9\uAE30\uD654 \uC694\uCCAD"
10966
+ }
10967
+ ),
10968
+ /* @__PURE__ */ jsx64(
10969
+ StnMenu.Item,
10970
+ {
10971
+ icon: "line/terminal",
10972
+ onMouseEnter: handleHoverOtherItem,
10973
+ onClick: () => handleItemClick("device-connect"),
10974
+ children: "\uC7A5\uBE44 \uC811\uC18D"
10975
+ }
10976
+ )
10977
+ ]
10978
+ }
10979
+ ),
10980
+ /* @__PURE__ */ jsxs51(
10981
+ StnMenu,
10982
+ {
10983
+ open: Boolean(target && submenuAnchorEl),
10984
+ anchorEl: submenuAnchorEl,
10985
+ anchorOrigin: { vertical: "top", horizontal: "right" },
10986
+ transformOrigin: { vertical: "top", horizontal: "left" },
10987
+ hideBackdrop: true,
10988
+ width: "w160",
10989
+ elevation: 3,
10990
+ onMouseEnter: handleEnterSubmenu,
10991
+ onMouseLeave: handleLeaveSubmenu,
10992
+ children: [
10993
+ /* @__PURE__ */ jsx64(StnMenu.Subheader, { children: "\uB9C1\uD06C \uC694\uC18C" }),
10994
+ /* @__PURE__ */ jsx64(StnMenu.Item, { onClick: () => handleItemClick("design-port"), children: "\uD3EC\uD2B8" }),
10995
+ /* @__PURE__ */ jsx64(StnMenu.Item, { onClick: () => handleItemClick("design-interface"), children: "\uC778\uD130\uD398\uC774\uC2A4" }),
10996
+ /* @__PURE__ */ jsx64(StnMenu.Item, { onClick: () => handleItemClick("design-ospf"), children: "OSPF" }),
10997
+ /* @__PURE__ */ jsx64(StnMenu.Item, { onClick: () => handleItemClick("design-mpls-rsvp"), children: "MPLS/RSVP" }),
10998
+ /* @__PURE__ */ jsx64(StnMenu.Subheader, { children: "\uD130\uB110 \uC694\uC18C" }),
10999
+ /* @__PURE__ */ jsx64(StnMenu.Item, { onClick: () => handleItemClick("design-path"), children: "PATH" }),
11000
+ /* @__PURE__ */ jsx64(StnMenu.Item, { onClick: () => handleItemClick("design-lsp"), children: "LSP" }),
11001
+ /* @__PURE__ */ jsx64(StnMenu.Item, { onClick: () => handleItemClick("design-sdp"), children: "SDP" }),
11002
+ /* @__PURE__ */ jsx64(StnMenu.Subheader, { children: "\uD68C\uC120 \uC694\uC18C" }),
11003
+ /* @__PURE__ */ jsx64(StnMenu.Item, { onClick: () => handleItemClick("design-epipe"), children: "EPIPE" })
11004
+ ]
11005
+ }
11006
+ )
11007
+ ] });
10806
11008
  }
10807
11009
  );
10808
11010
  StnTopologyNodeContextMenu.displayName = "StnTopologyNodeContextMenu";
@@ -10909,7 +11111,7 @@ function StnStatusList({ className, children, ...rest }) {
10909
11111
  }
10910
11112
 
10911
11113
  // src/components/StnWidget.tsx
10912
- import { Fragment as Fragment10, jsx as jsx68, jsxs as jsxs55 } from "react/jsx-runtime";
11114
+ import { Fragment as Fragment11, jsx as jsx68, jsxs as jsxs55 } from "react/jsx-runtime";
10913
11115
  var SHELL_PUB_CLASS = {
10914
11116
  card: "",
10915
11117
  "fault-panel": "",
@@ -10944,7 +11146,7 @@ function readWidgetSlot(type) {
10944
11146
  function flattenWidgetChildren(children) {
10945
11147
  const out = [];
10946
11148
  Children7.forEach(children, (child) => {
10947
- if (isValidElement10(child) && child.type === Fragment9) {
11149
+ if (isValidElement10(child) && child.type === Fragment10) {
10948
11150
  const fragmentProps = child.props;
10949
11151
  out.push(...flattenWidgetChildren(fragmentProps.children));
10950
11152
  return;
@@ -11074,7 +11276,7 @@ function StnWidgetHeaderInner({
11074
11276
  title != null || badge != null ? typeof title === "string" || title == null ? /* @__PURE__ */ jsxs55("div", { className: "stn-widget__title-wrap", children: [
11075
11277
  typeof title === "string" ? /* @__PURE__ */ jsx68("p", { className: cn("stn-widget__title", titleSize, titleWeight), title, children: title }) : null,
11076
11278
  badge
11077
- ] }) : /* @__PURE__ */ jsxs55(Fragment10, { children: [
11279
+ ] }) : /* @__PURE__ */ jsxs55(Fragment11, { children: [
11078
11280
  title,
11079
11281
  badge
11080
11282
  ] }) : null
@@ -11433,7 +11635,7 @@ function PubChartSample({
11433
11635
  }
11434
11636
 
11435
11637
  // src/patterns/alertCenter/StnAlertCenterPanel.tsx
11436
- import { useState as useState18 } from "react";
11638
+ import { useState as useState19 } from "react";
11437
11639
  import {
11438
11640
  STN_ALERT_CENTER_TABS
11439
11641
  } from "@stn-uiux/pub-ui/data/stnAlertCenter";
@@ -11565,7 +11767,7 @@ function StnAlertCenterPanel({
11565
11767
  closeLabel = "\uB2EB\uAE30",
11566
11768
  className
11567
11769
  }) {
11568
- const [activeTab, setActiveTab] = useState18(defaultTab);
11770
+ const [activeTab, setActiveTab] = useState19(defaultTab);
11569
11771
  const alertCount = alerts.length;
11570
11772
  const resolvedTitleOverflow = titleOverflow ?? textOverflow;
11571
11773
  const resolvedDescOverflow = descOverflow ?? textOverflow;
@@ -11873,7 +12075,7 @@ var StnSideNavLogo = forwardRef42(
11873
12075
  );
11874
12076
 
11875
12077
  // src/components/sideNav/StnSideNavHeader.tsx
11876
- import { Fragment as Fragment11, jsx as jsx75, jsxs as jsxs60 } from "react/jsx-runtime";
12078
+ import { Fragment as Fragment12, jsx as jsx75, jsxs as jsxs60 } from "react/jsx-runtime";
11877
12079
  var StnSideNavHeader = forwardRef43(function StnSideNavHeader2({
11878
12080
  children,
11879
12081
  border = false,
@@ -11897,7 +12099,7 @@ var StnSideNavHeader = forwardRef43(function StnSideNavHeader2({
11897
12099
  className
11898
12100
  ),
11899
12101
  ...rest,
11900
- children: children ?? /* @__PURE__ */ jsxs60(Fragment11, { children: [
12102
+ children: children ?? /* @__PURE__ */ jsxs60(Fragment12, { children: [
11901
12103
  /* @__PURE__ */ jsx75(StnSideNavLogo, {}),
11902
12104
  shouldShowClose ? /* @__PURE__ */ jsx75(
11903
12105
  StnButton,
@@ -11961,9 +12163,9 @@ var StnSideNavMenu = forwardRef44(function StnSideNavMenu2({
11961
12163
  // src/components/sideNav/StnSideNavGroup.tsx
11962
12164
  import {
11963
12165
  forwardRef as forwardRef45,
11964
- useEffect as useEffect15,
11965
- useRef as useRef12,
11966
- useState as useState19
12166
+ useEffect as useEffect16,
12167
+ useRef as useRef13,
12168
+ useState as useState20
11967
12169
  } from "react";
11968
12170
  import { jsx as jsx77, jsxs as jsxs61 } from "react/jsx-runtime";
11969
12171
  var StnSideNavGroup = forwardRef45(function StnSideNavGroup2({
@@ -11982,13 +12184,13 @@ var StnSideNavGroup = forwardRef45(function StnSideNavGroup2({
11982
12184
  ...rest
11983
12185
  }, ref) {
11984
12186
  const { collapsed } = useSideNav();
11985
- const [internalOpen, setInternalOpen] = useState19(defaultOpen);
12187
+ const [internalOpen, setInternalOpen] = useState20(defaultOpen);
11986
12188
  const isOpen = openProp ?? internalOpen;
11987
12189
  const isDropdown = Boolean(dropdown || variant === "dropdown");
11988
12190
  const isTransparent = dropdownVariant === "transparent" || dropdownBackground === false;
11989
12191
  const isUp = direction === "up";
11990
- const groupRef = useRef12(null);
11991
- useEffect15(() => {
12192
+ const groupRef = useRef13(null);
12193
+ useEffect16(() => {
11992
12194
  if (!isDropdown || !isOpen) return;
11993
12195
  const handlePointerDown = (e) => {
11994
12196
  if (groupRef.current && !groupRef.current.contains(e.target)) {
@@ -12144,13 +12346,13 @@ var StnSideNavWatermark = forwardRef49(
12144
12346
  );
12145
12347
 
12146
12348
  // src/components/sideNav/StnSideNavMobileTrigger.tsx
12147
- import { forwardRef as forwardRef50, useEffect as useEffect16, useState as useState20 } from "react";
12349
+ import { forwardRef as forwardRef50, useEffect as useEffect17, useState as useState21 } from "react";
12148
12350
  import { jsx as jsx82, jsxs as jsxs62 } from "react/jsx-runtime";
12149
12351
  var StnSideNavMobileTrigger = forwardRef50(
12150
12352
  function StnSideNavMobileTrigger2({ floating = false, className, children, onClick, ...rest }, ref) {
12151
12353
  const { onToggleMobileOpen, mobileOpen: contextMobileOpen } = useSideNav();
12152
- const [fallbackMobileOpen, setFallbackMobileOpen] = useState20(false);
12153
- useEffect16(() => {
12354
+ const [fallbackMobileOpen, setFallbackMobileOpen] = useState21(false);
12355
+ useEffect17(() => {
12154
12356
  if (onToggleMobileOpen) return;
12155
12357
  const handleStateChange = (e) => {
12156
12358
  const customEvent = e;
@@ -12297,13 +12499,13 @@ var StnSideNavSubNav = forwardRef52(
12297
12499
  import {
12298
12500
  forwardRef as forwardRef53,
12299
12501
  useCallback as useCallback11,
12300
- useEffect as useEffect17,
12502
+ useEffect as useEffect18,
12301
12503
  useMemo as useMemo5,
12302
- useState as useState21
12504
+ useState as useState22
12303
12505
  } from "react";
12304
12506
  import { jsx as jsx85, jsxs as jsxs63 } from "react/jsx-runtime";
12305
12507
  function useControllableState(controlledValue, defaultValue, onChange) {
12306
- const [internalState, setInternalState] = useState21(defaultValue);
12508
+ const [internalState, setInternalState] = useState22(defaultValue);
12307
12509
  const isControlled = controlledValue !== void 0;
12308
12510
  const value = isControlled ? controlledValue : internalState;
12309
12511
  const setValue = useCallback11(
@@ -12361,7 +12563,7 @@ var StnSideNavigationRoot = forwardRef53(function StnSideNavigationRoot2({
12361
12563
  const handleToggleMobileOpen = useCallback11(() => {
12362
12564
  setMobileOpen(!mobileOpen);
12363
12565
  }, [mobileOpen, setMobileOpen]);
12364
- useEffect17(() => {
12566
+ useEffect18(() => {
12365
12567
  const handleGlobalToggle = () => {
12366
12568
  setMobileOpen(!mobileOpen);
12367
12569
  };
@@ -12370,7 +12572,7 @@ var StnSideNavigationRoot = forwardRef53(function StnSideNavigationRoot2({
12370
12572
  window.removeEventListener("stn-side-nav-toggle-mobile", handleGlobalToggle);
12371
12573
  };
12372
12574
  }, [mobileOpen, setMobileOpen]);
12373
- useEffect17(() => {
12575
+ useEffect18(() => {
12374
12576
  window.dispatchEvent(
12375
12577
  new CustomEvent("stn-side-nav-mobile-change", {
12376
12578
  detail: { mobileOpen }
@@ -12444,16 +12646,16 @@ var StnSideNavigation = Object.assign(StnSideNavigationRoot, {
12444
12646
 
12445
12647
  // src/components/StnBreadcrumb.tsx
12446
12648
  import {
12447
- Fragment as Fragment12,
12448
- useEffect as useEffect18,
12649
+ Fragment as Fragment13,
12650
+ useEffect as useEffect19,
12449
12651
  useId as useId17,
12450
- useRef as useRef13,
12451
- useState as useState22
12652
+ useRef as useRef14,
12653
+ useState as useState23
12452
12654
  } from "react";
12453
12655
  import {
12454
12656
  STN_BREADCRUMB_ICON_SRC
12455
12657
  } from "@stn-uiux/pub-ui/data/stnBreadcrumb";
12456
- import { Fragment as Fragment13, jsx as jsx86, jsxs as jsxs64 } from "react/jsx-runtime";
12658
+ import { Fragment as Fragment14, jsx as jsx86, jsxs as jsxs64 } from "react/jsx-runtime";
12457
12659
  function maskStyle3(src) {
12458
12660
  return { maskImage: `url('${src}')`, WebkitMaskImage: `url('${src}')` };
12459
12661
  }
@@ -12486,7 +12688,7 @@ function SegmentContent({
12486
12688
  label,
12487
12689
  menu
12488
12690
  }) {
12489
- return /* @__PURE__ */ jsxs64(Fragment13, { children: [
12691
+ return /* @__PURE__ */ jsxs64(Fragment14, { children: [
12490
12692
  iconSrc ? /* @__PURE__ */ jsx86(BreadcrumbIcon, { src: iconSrc }) : null,
12491
12693
  /* @__PURE__ */ jsx86("span", { className: "stn-breadcrumb__label", children: label }),
12492
12694
  menu ? /* @__PURE__ */ jsx86(BreadcrumbCaret, {}) : null
@@ -12524,8 +12726,8 @@ function BreadcrumbMenuList({
12524
12726
  ) }, option.id)) });
12525
12727
  }
12526
12728
  function useDismissibleMenu(open, onClose) {
12527
- const rootRef = useRef13(null);
12528
- useEffect18(() => {
12729
+ const rootRef = useRef14(null);
12730
+ useEffect19(() => {
12529
12731
  if (!open) return;
12530
12732
  const onPointerDown = (event) => {
12531
12733
  if (!rootRef.current?.contains(event.target)) onClose();
@@ -12547,7 +12749,7 @@ function BreadcrumbSegment({
12547
12749
  isCurrent
12548
12750
  }) {
12549
12751
  const menuId = useId17();
12550
- const [open, setOpen] = useState22(false);
12752
+ const [open, setOpen] = useState23(false);
12551
12753
  const menuItems = item.menuItems ?? [];
12552
12754
  const showMenu = hasSegmentMenu(item) && !isCurrent;
12553
12755
  const canOpenMenu = showMenu && menuItems.length > 0;
@@ -12605,7 +12807,7 @@ function BreadcrumbBack({
12605
12807
  href,
12606
12808
  onClick
12607
12809
  }) {
12608
- const content = /* @__PURE__ */ jsxs64(Fragment13, { children: [
12810
+ const content = /* @__PURE__ */ jsxs64(Fragment14, { children: [
12609
12811
  /* @__PURE__ */ jsx86(
12610
12812
  "span",
12611
12813
  {
@@ -12641,7 +12843,7 @@ function BreadcrumbCollapsed({
12641
12843
  items,
12642
12844
  menuId
12643
12845
  }) {
12644
- const [open, setOpen] = useState22(false);
12846
+ const [open, setOpen] = useState23(false);
12645
12847
  const rootRef = useDismissibleMenu(open, () => setOpen(false));
12646
12848
  const menuItems = items.map((item) => ({
12647
12849
  id: item.id,
@@ -12729,19 +12931,19 @@ function StnBreadcrumb({
12729
12931
  /* @__PURE__ */ jsx86(BreadcrumbIcon, { src: STN_BREADCRUMB_ICON_SRC.home }),
12730
12932
  /* @__PURE__ */ jsx86("span", { className: "blind", children: homeLabel })
12731
12933
  ] }) }) : null,
12732
- head.map((item, index) => /* @__PURE__ */ jsxs64(Fragment12, { children: [
12934
+ head.map((item, index) => /* @__PURE__ */ jsxs64(Fragment13, { children: [
12733
12935
  !reverse && (showHome || index > 0 || leadSeparator) || reverse && (index > 0 || leadSeparator) ? /* @__PURE__ */ jsx86(BreadcrumbSeparator, {}) : null,
12734
12936
  renderTrailItem(item)
12735
12937
  ] }, item.id)),
12736
- hidden.length > 0 ? /* @__PURE__ */ jsxs64(Fragment13, { children: [
12938
+ hidden.length > 0 ? /* @__PURE__ */ jsxs64(Fragment14, { children: [
12737
12939
  /* @__PURE__ */ jsx86(BreadcrumbSeparator, {}),
12738
12940
  /* @__PURE__ */ jsx86(BreadcrumbCollapsed, { items: hidden, menuId })
12739
12941
  ] }) : null,
12740
- tail.map((item) => /* @__PURE__ */ jsxs64(Fragment12, { children: [
12942
+ tail.map((item) => /* @__PURE__ */ jsxs64(Fragment13, { children: [
12741
12943
  /* @__PURE__ */ jsx86(BreadcrumbSeparator, {}),
12742
12944
  renderTrailItem(item)
12743
12945
  ] }, item.id)),
12744
- reverse && showHome ? /* @__PURE__ */ jsxs64(Fragment13, { children: [
12946
+ reverse && showHome ? /* @__PURE__ */ jsxs64(Fragment14, { children: [
12745
12947
  /* @__PURE__ */ jsx86(BreadcrumbSeparator, {}),
12746
12948
  /* @__PURE__ */ jsx86("li", { className: "stn-breadcrumb__item stn-breadcrumb__item--home", children: /* @__PURE__ */ jsxs64("a", { className: "stn-breadcrumb__home", href: homeHref, onClick: onHomeClick, children: [
12747
12949
  /* @__PURE__ */ jsx86(BreadcrumbIcon, { src: STN_BREADCRUMB_ICON_SRC.home }),
@@ -12754,7 +12956,7 @@ function StnBreadcrumb({
12754
12956
  }
12755
12957
 
12756
12958
  // src/components/StnHeaderTitle.tsx
12757
- import { useEffect as useEffect19, useState as useState23 } from "react";
12959
+ import { useEffect as useEffect20, useState as useState24 } from "react";
12758
12960
  import { STN_HEADER_TITLE_FRAME } from "@stn-uiux/pub-ui/data/stnHeaderTitle";
12759
12961
  import { jsx as jsx87, jsxs as jsxs65 } from "react/jsx-runtime";
12760
12962
  var KO_WEEKDAY_SHORT = ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"];
@@ -12831,8 +13033,8 @@ function StnHeaderTitleFramePreview({ className }) {
12831
13033
  return /* @__PURE__ */ jsx87("div", { className: cn("stn-header-title__frame-only", className), children: /* @__PURE__ */ jsx87(HeaderTitleFrame, { preview: true }) });
12832
13034
  }
12833
13035
  function useLiveClock(enabled) {
12834
- const [now, setNow] = useState23(() => /* @__PURE__ */ new Date());
12835
- useEffect19(() => {
13036
+ const [now, setNow] = useState24(() => /* @__PURE__ */ new Date());
13037
+ useEffect20(() => {
12836
13038
  if (!enabled) return;
12837
13039
  const id = window.setInterval(() => setNow(/* @__PURE__ */ new Date()), 1e3);
12838
13040
  return () => window.clearInterval(id);
@@ -13717,14 +13919,14 @@ function DashboardPageScaffold({
13717
13919
  }
13718
13920
 
13719
13921
  // src/patterns/scaffold/AlertCenterPageScaffold.tsx
13720
- import { useMemo as useMemo6, useState as useState24 } from "react";
13922
+ import { useMemo as useMemo6, useState as useState25 } from "react";
13721
13923
  import {
13722
13924
  STN_ALERT_CENTER_DEMO_ALERTS,
13723
13925
  STN_ALERT_CENTER_DEMO_DEPLOY,
13724
13926
  STN_ALERT_CENTER_DEMO_WORK
13725
13927
  } from "@stn-uiux/pub-ui/data/stnAlertCenter";
13726
13928
  import { systemIconSrc } from "@stn-uiux/pub-ui/data/stnSystemIcons";
13727
- import { Fragment as Fragment14, jsx as jsx95, jsxs as jsxs69 } from "react/jsx-runtime";
13929
+ import { Fragment as Fragment15, jsx as jsx95, jsxs as jsxs69 } from "react/jsx-runtime";
13728
13930
  function defaultTopologyHeader(_clock) {
13729
13931
  return /* @__PURE__ */ jsx95(StnHeader, { variant: "widget" });
13730
13932
  }
@@ -13743,7 +13945,7 @@ function AlertCenterPageScaffold({
13743
13945
  defaultGnbOpen = true,
13744
13946
  ...shellProps
13745
13947
  }) {
13746
- const [gnbOpen, setGnbOpen] = useState24(defaultGnbOpen);
13948
+ const [gnbOpen, setGnbOpen] = useState25(defaultGnbOpen);
13747
13949
  const panel = useMemo6(
13748
13950
  () => gnbAlertPanel ?? /* @__PURE__ */ jsx95(
13749
13951
  StnAlertCenterPanel,
@@ -13756,7 +13958,7 @@ function AlertCenterPageScaffold({
13756
13958
  [gnbAlertPanel]
13757
13959
  );
13758
13960
  const sideNav = useMemo6(
13759
- () => gnbProp ?? /* @__PURE__ */ jsxs69(Fragment14, { children: [
13961
+ () => gnbProp ?? /* @__PURE__ */ jsxs69(Fragment15, { children: [
13760
13962
  /* @__PURE__ */ jsxs69(
13761
13963
  StnSideNavigation,
13762
13964
  {
@@ -13811,7 +14013,7 @@ function AlertCenterPageScaffold({
13811
14013
  }
13812
14014
 
13813
14015
  // src/patterns/scaffold/LoginPageScaffold.tsx
13814
- import { useState as useState25 } from "react";
14016
+ import { useState as useState26 } from "react";
13815
14017
  import { jsx as jsx96, jsxs as jsxs70 } from "react/jsx-runtime";
13816
14018
  var LOGIN_TABS = [
13817
14019
  { value: "normal", label: "\uC77C\uBC18 \uB85C\uADF8\uC778" },
@@ -13823,9 +14025,9 @@ function DefaultLoginForm({
13823
14025
  signUpHref = "#",
13824
14026
  recoverHref = "#"
13825
14027
  }) {
13826
- const [mode, setMode] = useState25("normal");
13827
- const [userId, setUserId] = useState25("");
13828
- const [password, setPassword] = useState25("");
14028
+ const [mode, setMode] = useState26("normal");
14029
+ const [userId, setUserId] = useState26("");
14030
+ const [password, setPassword] = useState26("");
13829
14031
  function handleSubmit(e) {
13830
14032
  e.preventDefault();
13831
14033
  onLogin?.(userId, password);
@@ -13972,7 +14174,7 @@ import React4 from "react";
13972
14174
  import {
13973
14175
  STN_EMPTY_STATE_PRESETS
13974
14176
  } from "@stn-uiux/pub-ui/data/stnEmptyState";
13975
- import { Fragment as Fragment15, jsx as jsx97, jsxs as jsxs71 } from "react/jsx-runtime";
14177
+ import { Fragment as Fragment16, jsx as jsx97, jsxs as jsxs71 } from "react/jsx-runtime";
13976
14178
  var ICON_PX2 = {
13977
14179
  sm: 40,
13978
14180
  md: 56,
@@ -14019,7 +14221,7 @@ var StnEmptyState = React4.forwardRef(
14019
14221
  const showGraphic = !hideIcon && visual !== "icon" && Boolean(resolvedGraphic);
14020
14222
  const iconNode = hideIcon || showGraphic ? null : resolveIconNode3(icon, preset?.icon, size);
14021
14223
  const resolvedCode = hideCode ? void 0 : code ?? (showGraphic ? void 0 : preset?.code);
14022
- const actionNodes = actions ?? ((primaryAction || secondaryAction) && /* @__PURE__ */ jsxs71(Fragment15, { children: [
14224
+ const actionNodes = actions ?? ((primaryAction || secondaryAction) && /* @__PURE__ */ jsxs71(Fragment16, { children: [
14023
14225
  primaryAction && /* @__PURE__ */ jsx97(
14024
14226
  StnButton,
14025
14227
  {
@@ -14228,9 +14430,9 @@ function renderChartState(loading, hasData, emptyText = "\uC870\uD68C\uB41C \uB3
14228
14430
 
14229
14431
  // src/components/StnBarChart.tsx
14230
14432
  import {
14231
- useState as useState26
14433
+ useState as useState27
14232
14434
  } from "react";
14233
- import { Fragment as Fragment16, jsx as jsx99, jsxs as jsxs73 } from "react/jsx-runtime";
14435
+ import { Fragment as Fragment17, jsx as jsx99, jsxs as jsxs73 } from "react/jsx-runtime";
14234
14436
  var DEFAULT_BAR_COLORS = STN_CHART_COLORS;
14235
14437
  var SIZE_WIDTH_MAP = {
14236
14438
  sm: "var(--stn-chart-bar-width-sm)",
@@ -14261,8 +14463,8 @@ function StnBarChart({
14261
14463
  style,
14262
14464
  ...rest
14263
14465
  }) {
14264
- const [internalHighlight, setInternalHighlight] = useState26(null);
14265
- const [hoveredIndex, setHoveredIndex] = useState26(null);
14466
+ const [internalHighlight, setInternalHighlight] = useState27(null);
14467
+ const [hoveredIndex, setHoveredIndex] = useState27(null);
14266
14468
  const isHorizontal = direction === "horizontal" || orientation === "horizontal";
14267
14469
  if (loading || !data || data.length === 0) {
14268
14470
  const emptyContainerStyle = {
@@ -14343,7 +14545,7 @@ function StnBarChart({
14343
14545
  children: [
14344
14546
  /* @__PURE__ */ jsx99("div", { className: "stn-chart-bar__body", children: isHorizontal ? (
14345
14547
  /* ==================== 가로 막대 (Horizontal) ==================== */
14346
- /* @__PURE__ */ jsxs73(Fragment16, { children: [
14548
+ /* @__PURE__ */ jsxs73(Fragment17, { children: [
14347
14549
  showXAxis && /* @__PURE__ */ jsx99("div", { className: "stn-chart-bar__grid-v", "aria-hidden": "true", children: gridCols.map((col, cIdx) => /* @__PURE__ */ jsxs73("div", { className: "stn-chart-bar__grid-v-col", children: [
14348
14550
  /* @__PURE__ */ jsx99(
14349
14551
  "div",
@@ -14446,7 +14648,7 @@ function StnBarChart({
14446
14648
  ] })
14447
14649
  ) : (
14448
14650
  /* ==================== 세로 막대 (Vertical) ==================== */
14449
- /* @__PURE__ */ jsxs73(Fragment16, { children: [
14651
+ /* @__PURE__ */ jsxs73(Fragment17, { children: [
14450
14652
  showYAxis && /* @__PURE__ */ jsx99("div", { className: "stn-chart-bar__grid", "aria-hidden": "true", children: gridRows.map((row, rIdx) => /* @__PURE__ */ jsxs73("div", { className: "stn-chart-bar__grid-row", children: [
14451
14653
  /* @__PURE__ */ jsx99("span", { className: "stn-chart-bar__axis-label", children: row.label }),
14452
14654
  /* @__PURE__ */ jsx99(
@@ -14567,9 +14769,9 @@ function StnBarChart({
14567
14769
  // src/components/StnPieChart.tsx
14568
14770
  import {
14569
14771
  useId as useId18,
14570
- useState as useState27
14772
+ useState as useState28
14571
14773
  } from "react";
14572
- import { Fragment as Fragment17, jsx as jsx100, jsxs as jsxs74 } from "react/jsx-runtime";
14774
+ import { Fragment as Fragment18, jsx as jsx100, jsxs as jsxs74 } from "react/jsx-runtime";
14573
14775
  var DEFAULT_PIE_COLORS = STN_CHART_COLORS;
14574
14776
  var R = 38;
14575
14777
  var CIRCUMFERENCE = 2 * Math.PI * R;
@@ -14597,7 +14799,7 @@ function StnPieChart({
14597
14799
  ...rest
14598
14800
  }) {
14599
14801
  const filterId = useId18().replace(/:/g, "");
14600
- const [hoveredIndex, setHoveredIndex] = useState27(null);
14802
+ const [hoveredIndex, setHoveredIndex] = useState28(null);
14601
14803
  const hasData = Boolean(data && data.length > 0);
14602
14804
  if (loading || !hasData) {
14603
14805
  return /* @__PURE__ */ jsx100(
@@ -14696,7 +14898,7 @@ function StnPieChart({
14696
14898
  seg.id ?? sIdx
14697
14899
  );
14698
14900
  }),
14699
- variant === "gauge" ? /* @__PURE__ */ jsxs74(Fragment17, { children: [
14901
+ variant === "gauge" ? /* @__PURE__ */ jsxs74(Fragment18, { children: [
14700
14902
  /* @__PURE__ */ jsx100("circle", { className: "stn-chart-gauge__center-outer", cx: "45", cy: "45", r: "31" }),
14701
14903
  /* @__PURE__ */ jsx100(
14702
14904
  "circle",
@@ -14709,7 +14911,7 @@ function StnPieChart({
14709
14911
  }
14710
14912
  ),
14711
14913
  centerLabel && /* @__PURE__ */ jsx100("text", { className: "stn-chart-gauge__center-text", x: "45", y: "49", children: centerLabel })
14712
- ] }) : /* @__PURE__ */ jsxs74(Fragment17, { children: [
14914
+ ] }) : /* @__PURE__ */ jsxs74(Fragment18, { children: [
14713
14915
  /* @__PURE__ */ jsx100("circle", { className: "stn-chart-gauge__center-outer", cx: "45", cy: "45", r: "30" }),
14714
14916
  centerLabel && /* @__PURE__ */ jsx100("text", { className: "stn-chart-gauge__center-text", x: "45", y: centerSubLabel ? "46" : "49", children: centerLabel }),
14715
14917
  centerSubLabel && /* @__PURE__ */ jsx100(
@@ -14782,8 +14984,8 @@ var StnGaugeChart = StnPieChart;
14782
14984
  // src/components/StnLineChart.tsx
14783
14985
  import {
14784
14986
  useId as useId19,
14785
- useRef as useRef14,
14786
- useState as useState28
14987
+ useRef as useRef15,
14988
+ useState as useState29
14787
14989
  } from "react";
14788
14990
  import { jsx as jsx101, jsxs as jsxs75 } from "react/jsx-runtime";
14789
14991
  var DEFAULT_LINE_COLORS = STN_CHART_COLORS;
@@ -14824,8 +15026,8 @@ function StnLineChart({
14824
15026
  ...rest
14825
15027
  }) {
14826
15028
  const chartId = useId19().replace(/:/g, "");
14827
- const svgRef = useRef14(null);
14828
- const [hoverIndex, setHoverIndex] = useState28(null);
15029
+ const svgRef = useRef15(null);
15030
+ const [hoverIndex, setHoverIndex] = useState29(null);
14829
15031
  const valueFormatter = format ?? ((v) => formatChartValue(v, decimals));
14830
15032
  const hasDots = Boolean(showDots ?? showPoints ?? dots ?? false);
14831
15033
  const dotRadius = DOT_RADIUS_MAP[size] || 3;
@@ -15143,7 +15345,7 @@ function StnLineChart({
15143
15345
  // src/components/StnComboChart.tsx
15144
15346
  import {
15145
15347
  useId as useId20,
15146
- useState as useState29
15348
+ useState as useState30
15147
15349
  } from "react";
15148
15350
  import { jsx as jsx102, jsxs as jsxs76 } from "react/jsx-runtime";
15149
15351
  var BAR_WIDTH_MAP = {
@@ -15184,8 +15386,8 @@ function StnComboChart({
15184
15386
  ...rest
15185
15387
  }) {
15186
15388
  const chartId = useId20().replace(/:/g, "");
15187
- const [internalHighlight, setInternalHighlight] = useState29(null);
15188
- const [hoverIndex, setHoverIndex] = useState29(null);
15389
+ const [internalHighlight, setInternalHighlight] = useState30(null);
15390
+ const [hoverIndex, setHoverIndex] = useState30(null);
15189
15391
  const hasData = Boolean(data && data.length > 0);
15190
15392
  if (loading || !hasData) {
15191
15393
  return /* @__PURE__ */ jsx102(