@pisell/materials 1.8.54 → 1.8.56

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.
Files changed (151) hide show
  1. package/build/lowcode/assets-daily.json +11 -11
  2. package/build/lowcode/assets-dev.json +2 -2
  3. package/build/lowcode/assets-prod.json +11 -11
  4. package/build/lowcode/async/view.js +1 -1
  5. package/build/lowcode/index.js +1 -1
  6. package/build/lowcode/meta.js +3 -3
  7. package/build/lowcode/preview.js +1 -1
  8. package/build/lowcode/render/default/async/view.js +1 -1
  9. package/build/lowcode/render/default/view.css +1 -1
  10. package/build/lowcode/render/default/view.js +37 -37
  11. package/build/lowcode/view.css +1 -1
  12. package/build/lowcode/view.js +37 -37
  13. package/es/components/buttonGroupPreview/index.js +8 -4
  14. package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.js +207 -49
  15. package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
  16. package/es/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
  17. package/es/components/pisellFloorMapLayout/components/EdgeLayer.js +252 -0
  18. package/es/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
  19. package/es/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
  20. package/es/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
  21. package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +131 -0
  22. package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
  23. package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +5 -4
  24. package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
  25. package/es/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
  26. package/es/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
  27. package/es/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
  28. package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.js +290 -147
  29. package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
  30. package/es/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +81 -0
  31. package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
  32. package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +21 -0
  33. package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
  34. package/es/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
  35. package/es/components/pisellFloorMapLayout/components/NodePortMarkers.js +70 -0
  36. package/es/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
  37. package/es/components/pisellFloorMapLayout/components/ViewControls.js +13 -5
  38. package/es/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
  39. package/es/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
  40. package/es/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
  41. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +340 -0
  42. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +102 -0
  43. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +244 -84
  44. package/es/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
  45. package/es/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
  46. package/es/components/pisellFloorMapLayout/index.d.ts +5 -1
  47. package/es/components/pisellFloorMapLayout/locales-ja.js +14 -2
  48. package/es/components/pisellFloorMapLayout/locales-pt.js +14 -2
  49. package/es/components/pisellFloorMapLayout/locales.js +161 -8
  50. package/es/components/pisellFloorMapLayout/types.d.ts +86 -4
  51. package/es/components/pisellFloorMapLayout/types.js +5 -1
  52. package/es/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
  53. package/es/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +86 -0
  54. package/es/components/pisellFloorMapLayout/utils/edgeRouting.js +942 -0
  55. package/es/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
  56. package/es/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -1
  57. package/es/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
  58. package/es/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +20 -3
  59. package/es/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
  60. package/es/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
  61. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
  62. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +62 -0
  63. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
  64. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
  65. package/es/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +51 -0
  66. package/es/components/productCard/cartSkuCard/components/BookingItem/index.js +14 -0
  67. package/es/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
  68. package/es/components/productCard/cartSkuCard/components/resources/index.less +4 -0
  69. package/es/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
  70. package/es/components/productCard/cartSkuCard/index.js +17 -11
  71. package/es/components/productCard/lineItem/BookingLineItem.js +17 -6
  72. package/es/components/productCard/lineItem/components/Holders/index.js +51 -0
  73. package/es/components/productCard/lineItem/components/Holders/index.less +39 -0
  74. package/es/components/productCard/lineItem/components/Resources/index.js +45 -0
  75. package/es/components/productCard/lineItem/components/TimeRange/index.js +64 -0
  76. package/es/components/productCard/lineItem/index.js +5 -2
  77. package/es/components/productCard/lineItem/index.less +21 -10
  78. package/es/components/productCard/types.d.ts +1 -0
  79. package/es/index.d.ts +6 -2
  80. package/es/index.js +6 -2
  81. package/es/pisell-materials.tw.css +3 -0
  82. package/lib/components/buttonGroupPreview/index.js +8 -4
  83. package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.js +206 -48
  84. package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
  85. package/lib/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
  86. package/lib/components/pisellFloorMapLayout/components/EdgeLayer.js +255 -0
  87. package/lib/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
  88. package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
  89. package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
  90. package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +134 -0
  91. package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
  92. package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +4 -3
  93. package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
  94. package/lib/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
  95. package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
  96. package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
  97. package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.js +287 -144
  98. package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
  99. package/lib/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +84 -0
  100. package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
  101. package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +23 -0
  102. package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
  103. package/lib/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
  104. package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.js +73 -0
  105. package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
  106. package/lib/components/pisellFloorMapLayout/components/ViewControls.js +12 -4
  107. package/lib/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
  108. package/lib/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
  109. package/lib/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
  110. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +341 -0
  111. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +103 -0
  112. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +242 -82
  113. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
  114. package/lib/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
  115. package/lib/components/pisellFloorMapLayout/index.d.ts +5 -1
  116. package/lib/components/pisellFloorMapLayout/locales-ja.js +14 -2
  117. package/lib/components/pisellFloorMapLayout/locales-pt.js +14 -2
  118. package/lib/components/pisellFloorMapLayout/locales.js +161 -8
  119. package/lib/components/pisellFloorMapLayout/types.d.ts +86 -4
  120. package/lib/components/pisellFloorMapLayout/types.js +5 -0
  121. package/lib/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
  122. package/lib/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +87 -0
  123. package/lib/components/pisellFloorMapLayout/utils/edgeRouting.js +956 -0
  124. package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
  125. package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -0
  126. package/lib/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
  127. package/lib/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +21 -2
  128. package/lib/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
  129. package/lib/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
  130. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
  131. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +64 -0
  132. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
  133. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
  134. package/lib/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +54 -0
  135. package/lib/components/productCard/cartSkuCard/components/BookingItem/index.js +17 -0
  136. package/lib/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
  137. package/lib/components/productCard/cartSkuCard/components/resources/index.less +4 -0
  138. package/lib/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
  139. package/lib/components/productCard/cartSkuCard/index.js +17 -11
  140. package/lib/components/productCard/lineItem/BookingLineItem.js +17 -6
  141. package/lib/components/productCard/lineItem/components/Holders/index.js +53 -0
  142. package/lib/components/productCard/lineItem/components/Holders/index.less +39 -0
  143. package/lib/components/productCard/lineItem/components/Resources/index.js +47 -0
  144. package/lib/components/productCard/lineItem/components/TimeRange/index.js +67 -0
  145. package/lib/components/productCard/lineItem/index.js +5 -2
  146. package/lib/components/productCard/lineItem/index.less +21 -10
  147. package/lib/components/productCard/types.d.ts +1 -0
  148. package/lib/index.d.ts +6 -2
  149. package/lib/index.js +11 -0
  150. package/lib/pisell-materials.tw.css +3 -0
  151. package/package.json +6 -3
@@ -3,11 +3,59 @@ const require_objectSpread2 = require("../../../_virtual/_@oxc-project_runtime@0
3
3
  const FLOOR_MAP_APPEARANCE_TOKENS = {
4
4
  light: {
5
5
  mode: "light",
6
- fallbackCanvasBackgroundColor: "#F2F4F7"
6
+ fallbackCanvasBackgroundColor: "#F2F4F7",
7
+ edgeStatusStyles: {
8
+ online: {
9
+ stroke: "#12B76A",
10
+ dashed: false
11
+ },
12
+ offline: {
13
+ stroke: "#98A2B3",
14
+ dashed: true
15
+ },
16
+ warning: {
17
+ stroke: "#F79009",
18
+ dashed: false
19
+ },
20
+ unknown: {
21
+ stroke: "#667085",
22
+ dashed: false
23
+ }
24
+ },
25
+ edgeSelectedStroke: "#1570EF",
26
+ edgeGhostStroke: "#84CAFF",
27
+ edgePortLabelBackground: "#FFFFFF",
28
+ edgePortLabelText: "#344054",
29
+ edgePortLabelBorder: "#D0D5DD",
30
+ alignGuideStroke: "#1570EF"
7
31
  },
8
32
  dark: {
9
33
  mode: "dark",
10
- fallbackCanvasBackgroundColor: "#31353d"
34
+ fallbackCanvasBackgroundColor: "#31353d",
35
+ edgeStatusStyles: {
36
+ online: {
37
+ stroke: "#32D583",
38
+ dashed: false
39
+ },
40
+ offline: {
41
+ stroke: "#667085",
42
+ dashed: true
43
+ },
44
+ warning: {
45
+ stroke: "#FDB022",
46
+ dashed: false
47
+ },
48
+ unknown: {
49
+ stroke: "#98A2B3",
50
+ dashed: false
51
+ }
52
+ },
53
+ edgeSelectedStroke: "#53B1FD",
54
+ edgeGhostStroke: "#2E90FA",
55
+ edgePortLabelBackground: "#1D2939",
56
+ edgePortLabelText: "#F2F4F7",
57
+ edgePortLabelBorder: "#475467",
58
+ alignGuideStroke: "#53B1FD"
11
59
  }
12
60
  };
13
61
  /**
@@ -0,0 +1,255 @@
1
+ const require_runtime = require("../../../_virtual/_rolldown/runtime.js");
2
+ const require_edgeRouting = require("../utils/edgeRouting.js");
3
+ let react = require("react");
4
+ react = require_runtime.__toESM(react);
5
+ let classnames = require("classnames");
6
+ classnames = require_runtime.__toESM(classnames);
7
+ require("./EdgeLayer.less");
8
+ //#region src/components/pisellFloorMapLayout/components/EdgeLayer.tsx
9
+ /**
10
+ * EdgeLayer - 拓扑连线 SVG 层(正交折线 + 端口标签)
11
+ */
12
+ const PREFIX = "pisell-floor-map-layout";
13
+ /** 中段手柄基础视觉尺寸(px),实际渲染会按 viewportScale 反向缩放 */
14
+ const SEGMENT_HANDLE_BASE_SIZE = 12;
15
+ /** 段长 < 该值(px)时不渲染手柄,避免极短段误触 */
16
+ const SEGMENT_HANDLE_MIN_LENGTH = 16;
17
+ function resolveEdgeStroke(edge, appearance, selected) {
18
+ var _edge$status, _edge$strokeWidth3;
19
+ if (selected) {
20
+ var _edge$strokeWidth;
21
+ return {
22
+ stroke: appearance.edgeSelectedStroke,
23
+ strokeWidth: ((_edge$strokeWidth = edge.strokeWidth) !== null && _edge$strokeWidth !== void 0 ? _edge$strokeWidth : 1.5) + 1
24
+ };
25
+ }
26
+ if (edge.color) {
27
+ var _edge$strokeWidth2;
28
+ return {
29
+ stroke: edge.color,
30
+ strokeWidth: (_edge$strokeWidth2 = edge.strokeWidth) !== null && _edge$strokeWidth2 !== void 0 ? _edge$strokeWidth2 : 1.5,
31
+ strokeDasharray: edge.dashed ? "6 4" : void 0
32
+ };
33
+ }
34
+ const status = (_edge$status = edge.status) !== null && _edge$status !== void 0 ? _edge$status : "unknown";
35
+ const style = appearance.edgeStatusStyles[status];
36
+ return {
37
+ stroke: style.stroke,
38
+ strokeWidth: (_edge$strokeWidth3 = edge.strokeWidth) !== null && _edge$strokeWidth3 !== void 0 ? _edge$strokeWidth3 : 1.5,
39
+ strokeDasharray: edge.dashed || style.dashed ? "6 4" : void 0
40
+ };
41
+ }
42
+ function PortLabel(props) {
43
+ const { x, y, text, appearance } = props;
44
+ const estW = Math.max(32, text.length * 6.5 + 12);
45
+ const h = 18;
46
+ return /* @__PURE__ */ react.default.createElement("g", { className: `${PREFIX}-edge-port-label` }, /* @__PURE__ */ react.default.createElement("rect", {
47
+ x: x - estW / 2,
48
+ y: y - h / 2,
49
+ width: estW,
50
+ height: h,
51
+ rx: 4,
52
+ fill: appearance.edgePortLabelBackground,
53
+ stroke: appearance.edgePortLabelBorder,
54
+ strokeWidth: 1
55
+ }), /* @__PURE__ */ react.default.createElement("text", {
56
+ x,
57
+ y: y + 4,
58
+ textAnchor: "middle",
59
+ fontSize: 11,
60
+ fill: appearance.edgePortLabelText
61
+ }, text));
62
+ }
63
+ function EdgeLayer(props) {
64
+ const { width, height, contentOffsetX = 0, contentOffsetY = 0, edges, routes, rectsById, appearance, mode, selectedEdgeId, ghostPathD, onEdgeClick, viewportScale = 1, onSegmentDragStart, className } = props;
65
+ const safeScale = Math.max(viewportScale, .01);
66
+ const handleSize = SEGMENT_HANDLE_BASE_SIZE / safeScale;
67
+ const handleHalf = handleSize / 2;
68
+ const edgeById = (0, react.useMemo)(() => {
69
+ const m = /* @__PURE__ */ new Map();
70
+ for (const e of edges) m.set(e.id, e);
71
+ return m;
72
+ }, [edges]);
73
+ const routeById = (0, react.useMemo)(() => {
74
+ const m = /* @__PURE__ */ new Map();
75
+ for (const r of routes) m.set(r.edgeId, r);
76
+ return m;
77
+ }, [routes]);
78
+ /** 同目标多边时错开 connection_type 标签,避免叠在一起 */
79
+ const centerLabelByEdgeId = (0, react.useMemo)(() => require_edgeRouting.resolveEdgeCenterLabelPositions(routes.map((route) => {
80
+ const edge = edgeById.get(route.edgeId);
81
+ if (!edge) return null;
82
+ return {
83
+ edgeId: route.edgeId,
84
+ sourceId: edge.sourceId,
85
+ targetId: edge.targetId,
86
+ points: route.points,
87
+ label: edge.label
88
+ };
89
+ }).filter((row) => row != null), {
90
+ placement: "target-tail",
91
+ rectsById
92
+ }), [
93
+ routes,
94
+ edgeById,
95
+ rectsById
96
+ ]);
97
+ return /* @__PURE__ */ react.default.createElement("svg", {
98
+ className: (0, classnames.default)(`${PREFIX}-edge-layer`, className),
99
+ width,
100
+ height,
101
+ style: {
102
+ position: "absolute",
103
+ left: contentOffsetX,
104
+ top: contentOffsetY,
105
+ pointerEvents: "none",
106
+ overflow: "visible"
107
+ },
108
+ "aria-hidden": mode === "read"
109
+ }, /* @__PURE__ */ react.default.createElement("g", { className: `${PREFIX}-edge-layer-inner` }, routes.map((route) => {
110
+ const edge = edgeById.get(route.edgeId);
111
+ if (!edge) return null;
112
+ const selected = selectedEdgeId === edge.id;
113
+ const stroke = resolveEdgeStroke(edge, appearance, selected);
114
+ return /* @__PURE__ */ react.default.createElement("g", {
115
+ key: edge.id,
116
+ className: `${PREFIX}-edge-group`
117
+ }, /* @__PURE__ */ react.default.createElement("path", {
118
+ d: route.pathD,
119
+ fill: "none",
120
+ stroke: stroke.stroke,
121
+ strokeWidth: stroke.strokeWidth,
122
+ strokeDasharray: stroke.strokeDasharray,
123
+ strokeLinecap: "round",
124
+ strokeLinejoin: "round",
125
+ className: (0, classnames.default)(`${PREFIX}-edge-path`, {
126
+ [`${PREFIX}-edge-path--selected`]: selected,
127
+ [`${PREFIX}-edge-path--interactive`]: mode === "edit"
128
+ }),
129
+ style: {
130
+ pointerEvents: mode === "edit" ? "stroke" : "none",
131
+ cursor: mode === "edit" ? "pointer" : void 0
132
+ },
133
+ onClick: mode === "edit" && onEdgeClick ? (ev) => {
134
+ ev.stopPropagation();
135
+ onEdgeClick(edge.id, ev);
136
+ } : void 0
137
+ }), edge.label && route.points.length >= 2 ? (() => {
138
+ const labelPos = centerLabelByEdgeId.get(edge.id);
139
+ if (!labelPos) return null;
140
+ return /* @__PURE__ */ react.default.createElement(PortLabel, {
141
+ x: labelPos.x,
142
+ y: labelPos.y,
143
+ text: edge.label,
144
+ appearance
145
+ });
146
+ })() : null);
147
+ }), edges.map((edge) => {
148
+ var _edge$sourceAnchor, _edge$targetAnchor;
149
+ const route = routeById.get(edge.id);
150
+ const srcRect = rectsById.get(edge.sourceId);
151
+ const tgtRect = rectsById.get(edge.targetId);
152
+ if (!route || !srcRect || !tgtRect) return null;
153
+ const sourceAnchor = (_edge$sourceAnchor = edge.sourceAnchor) !== null && _edge$sourceAnchor !== void 0 ? _edge$sourceAnchor : "right";
154
+ const targetAnchor = (_edge$targetAnchor = edge.targetAnchor) !== null && _edge$targetAnchor !== void 0 ? _edge$targetAnchor : "left";
155
+ const spLabel = require_edgeRouting.getPortLabelPosition(srcRect, sourceAnchor);
156
+ const tpLabel = require_edgeRouting.getPortLabelPosition(tgtRect, targetAnchor);
157
+ return /* @__PURE__ */ react.default.createElement("g", { key: `${edge.id}-labels` }, edge.sourceLabel ? /* @__PURE__ */ react.default.createElement(PortLabel, {
158
+ x: spLabel.x,
159
+ y: spLabel.y,
160
+ text: edge.sourceLabel,
161
+ appearance
162
+ }) : null, edge.targetLabel ? /* @__PURE__ */ react.default.createElement(PortLabel, {
163
+ x: tpLabel.x,
164
+ y: tpLabel.y,
165
+ text: edge.targetLabel,
166
+ appearance
167
+ }) : null);
168
+ }), mode === "edit" && selectedEdgeId && onSegmentDragStart ? (() => {
169
+ const route = routeById.get(selectedEdgeId);
170
+ if (!route) return null;
171
+ const pts = route.points;
172
+ if (pts.length < 2) return null;
173
+ const lastSegIdx = pts.length - 2;
174
+ const handles = [];
175
+ for (let i = 0; i <= lastSegIdx; i++) {
176
+ const role = i === 0 ? "first" : i === lastSegIdx ? "last" : "inner";
177
+ const [x1, y1] = pts[i];
178
+ const [x2, y2] = pts[i + 1];
179
+ let axis;
180
+ let position;
181
+ let length;
182
+ let midX;
183
+ let midY;
184
+ if (y1 === y2 && x1 !== x2) {
185
+ axis = "h";
186
+ position = y1;
187
+ length = Math.abs(x2 - x1);
188
+ midX = (x1 + x2) / 2;
189
+ midY = y1;
190
+ } else if (x1 === x2 && y1 !== y2) {
191
+ axis = "v";
192
+ position = x1;
193
+ length = Math.abs(y2 - y1);
194
+ midX = x1;
195
+ midY = (y1 + y2) / 2;
196
+ } else continue;
197
+ if (length < SEGMENT_HANDLE_MIN_LENGTH) continue;
198
+ handles.push({
199
+ key: `${role}-${i}`,
200
+ role,
201
+ segmentIndex: i,
202
+ axis,
203
+ position,
204
+ length,
205
+ midX,
206
+ midY
207
+ });
208
+ }
209
+ if (handles.length === 0) return null;
210
+ return /* @__PURE__ */ react.default.createElement("g", {
211
+ className: `${PREFIX}-edge-segment-handles`,
212
+ pointerEvents: "auto"
213
+ }, handles.map((h) => /* @__PURE__ */ react.default.createElement("rect", {
214
+ key: h.key,
215
+ x: h.midX - handleHalf,
216
+ y: h.midY - handleHalf,
217
+ width: handleSize,
218
+ height: handleSize,
219
+ rx: handleHalf,
220
+ ry: handleHalf,
221
+ className: (0, classnames.default)(`${PREFIX}-edge-segment-handle`, `${PREFIX}-edge-segment-handle--${h.axis}`, `${PREFIX}-edge-segment-handle--${h.role}`),
222
+ fill: appearance.edgeSelectedStroke,
223
+ stroke: "#fff",
224
+ strokeWidth: 1.5 / safeScale,
225
+ style: {
226
+ cursor: h.axis === "h" ? "ns-resize" : "ew-resize",
227
+ touchAction: "none"
228
+ },
229
+ onPointerDown: (ev) => {
230
+ ev.stopPropagation();
231
+ ev.preventDefault();
232
+ onSegmentDragStart({
233
+ edgeId: selectedEdgeId,
234
+ role: h.role,
235
+ segmentIndex: h.segmentIndex,
236
+ axis: h.axis,
237
+ startPosition: h.position,
238
+ clientX: ev.clientX,
239
+ clientY: ev.clientY,
240
+ segmentLength: h.length
241
+ });
242
+ }
243
+ })));
244
+ })() : null, ghostPathD ? /* @__PURE__ */ react.default.createElement("path", {
245
+ d: ghostPathD,
246
+ fill: "none",
247
+ stroke: appearance.edgeGhostStroke,
248
+ strokeWidth: 1.5,
249
+ strokeDasharray: "4 4",
250
+ strokeLinecap: "round",
251
+ pointerEvents: "none"
252
+ }) : null));
253
+ }
254
+ //#endregion
255
+ exports.EdgeLayer = EdgeLayer;
@@ -0,0 +1,11 @@
1
+ .pisell-floor-map-layout-edge-layer {
2
+ z-index: 2;
3
+ }
4
+
5
+ .pisell-floor-map-layout-edge-path--interactive:hover {
6
+ filter: brightness(1.05);
7
+ }
8
+
9
+ .pisell-floor-map-layout-edge-path--selected {
10
+ filter: drop-shadow(0 0 2px rgba(21, 112, 239, 0.35));
11
+ }
@@ -1,6 +1,7 @@
1
1
  const require_runtime = require("../../../_virtual/_rolldown/runtime.js");
2
2
  const require_objectSpread2 = require("../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js");
3
3
  const require_snap = require("../utils/snap.js");
4
+ const require_alignSnap = require("../utils/alignSnap.js");
4
5
  const require_FloorMapEditQuickActions = require("./FloorMapEditQuickActions.js");
5
6
  let react = require("react");
6
7
  react = require_runtime.__toESM(react);
@@ -19,6 +20,12 @@ const PREFIX = "pisell-floor-map-layout";
19
20
  const DRAG_THRESHOLD = 4;
20
21
  /** 选中图元抬升到该层级,保证快捷栏与缩放点不被其它图元(任意 item.zIndex)遮住 */
21
22
  const SELECTED_ITEM_STACK_Z = 1e6;
23
+ const RESIZE_CORNER_HANDLES = [
24
+ "nw",
25
+ "ne",
26
+ "se",
27
+ "sw"
28
+ ];
22
29
  function getItemKey(item, index, rowKey) {
23
30
  var _rowKey;
24
31
  if (!rowKey) return item.id;
@@ -33,11 +40,40 @@ function getShapeStyle(shape = "rect") {
33
40
  }
34
41
  }
35
42
  function EditableItemLayer(props) {
36
- const { items, renderItem, rowKey, cellSize, itemUnit = "pixel", itemGap = 0, contentWidth, contentHeight, contentOffsetX = 0, contentOffsetY = 0, selectedId, onSelect, onUpdateItem, snapStep = 0, scale = 1, onInteractionChange, getMergedItemWrapperStyle, className, editQuickBar } = props;
43
+ const { items, renderItem, rowKey, cellSize, itemUnit = "pixel", itemGap = 0, contentWidth, contentHeight, contentOffsetX = 0, contentOffsetY = 0, selectedId, onSelect, onUpdateItem, snapStep = 0, scale = 1, onInteractionChange, onLiveRectChange, alignSnapThresholdPx = 6, onAlignGuidesChange, alignGuideStroke = "#1570EF", getMergedItemWrapperStyle, className, editQuickBar } = props;
37
44
  const contentRef = (0, react.useRef)(null);
38
45
  const liveRectRef = (0, react.useRef)(null);
39
46
  const [interaction, setInteraction] = (0, react.useState)(null);
40
47
  const [liveRect, setLiveRect] = (0, react.useState)(null);
48
+ /** 拖动/缩放过程中的对齐辅助线(红色虚线) */
49
+ const [alignGuides, setAlignGuides] = (0, react.useState)([]);
50
+ /** 基础像素矩形(与 liveRect 无关),供对齐吸附排除自身后参考 */
51
+ const getBaseRect = (0, react.useCallback)((item) => {
52
+ var _item$width2, _item$height2;
53
+ const isPixel = itemUnit === "pixel";
54
+ const g = itemGap !== null && itemGap !== void 0 ? itemGap : 0;
55
+ if (isPixel) {
56
+ var _item$width, _item$height;
57
+ return {
58
+ left: item.x,
59
+ top: item.y,
60
+ width: (_item$width = item.width) !== null && _item$width !== void 0 ? _item$width : cellSize,
61
+ height: (_item$height = item.height) !== null && _item$height !== void 0 ? _item$height : cellSize
62
+ };
63
+ }
64
+ const w = (_item$width2 = item.width) !== null && _item$width2 !== void 0 ? _item$width2 : 1;
65
+ const h = (_item$height2 = item.height) !== null && _item$height2 !== void 0 ? _item$height2 : 1;
66
+ return {
67
+ left: g > 0 ? item.x * (cellSize + g) + g : item.x * cellSize,
68
+ top: g > 0 ? item.y * (cellSize + g) + g : item.y * cellSize,
69
+ width: g > 0 ? w * cellSize + (w - 1) * g : w * cellSize,
70
+ height: g > 0 ? h * cellSize + (h - 1) * g : h * cellSize
71
+ };
72
+ }, [
73
+ cellSize,
74
+ itemGap,
75
+ itemUnit
76
+ ]);
41
77
  const getItemStyle = (0, react.useCallback)((item, index) => {
42
78
  const isPixel = itemUnit === "pixel";
43
79
  const g = itemGap !== null && itemGap !== void 0 ? itemGap : 0;
@@ -46,15 +82,15 @@ function EditableItemLayer(props) {
46
82
  let width;
47
83
  let height;
48
84
  if (isPixel) {
49
- var _item$width, _item$height;
50
- width = (_item$width = item.width) !== null && _item$width !== void 0 ? _item$width : cellSize;
51
- height = (_item$height = item.height) !== null && _item$height !== void 0 ? _item$height : cellSize;
85
+ var _item$width3, _item$height3;
86
+ width = (_item$width3 = item.width) !== null && _item$width3 !== void 0 ? _item$width3 : cellSize;
87
+ height = (_item$height3 = item.height) !== null && _item$height3 !== void 0 ? _item$height3 : cellSize;
52
88
  left = item.x;
53
89
  top = item.y;
54
90
  } else {
55
- var _item$width2, _item$height2;
56
- const w = (_item$width2 = item.width) !== null && _item$width2 !== void 0 ? _item$width2 : 1;
57
- const h = (_item$height2 = item.height) !== null && _item$height2 !== void 0 ? _item$height2 : 1;
91
+ var _item$width4, _item$height4;
92
+ const w = (_item$width4 = item.width) !== null && _item$width4 !== void 0 ? _item$width4 : 1;
93
+ const h = (_item$height4 = item.height) !== null && _item$height4 !== void 0 ? _item$height4 : 1;
58
94
  left = g > 0 ? item.x * (cellSize + g) + g : item.x * cellSize;
59
95
  top = g > 0 ? item.y * (cellSize + g) + g : item.y * cellSize;
60
96
  width = g > 0 ? w * cellSize + (w - 1) * g : w * cellSize;
@@ -125,18 +161,46 @@ function EditableItemLayer(props) {
125
161
  ]);
126
162
  react.default.useEffect(() => {
127
163
  if (!interaction) return;
164
+ /** 阈值按 scale 折算到内容坐标,让它在屏幕上恒定 */
165
+ const threshold = Math.max(0, alignSnapThresholdPx) / Math.max(scale, .01);
166
+ /** 内部计算 snap 目标:排除自身,使用基础 rect(避开 liveRect 自吸) */
167
+ const otherRects = items.filter((it) => it.id !== interaction.itemId).map((it) => require_objectSpread2._objectSpread2({ id: it.id }, getBaseRect(it)));
128
168
  const onMove = (e) => {
129
169
  if (interaction.type === "drag") {
130
170
  const dx = (e.clientX - interaction.startX) / scale;
131
171
  const dy = (e.clientY - interaction.startY) / scale;
132
- const next = {
172
+ const rawNext = {
133
173
  x: interaction.itemX + dx,
134
174
  y: interaction.itemY + dy,
135
175
  width: interaction.itemW,
136
176
  height: interaction.itemH
137
177
  };
178
+ const snap = require_alignSnap.snapRectToOthers({
179
+ id: interaction.itemId,
180
+ left: rawNext.x,
181
+ top: rawNext.y,
182
+ width: rawNext.width,
183
+ height: rawNext.height
184
+ }, otherRects, {
185
+ mode: "drag",
186
+ threshold
187
+ });
188
+ const next = {
189
+ x: snap.rect.left,
190
+ y: snap.rect.top,
191
+ width: snap.rect.width,
192
+ height: snap.rect.height
193
+ };
138
194
  liveRectRef.current = next;
139
195
  setLiveRect(require_objectSpread2._objectSpread2({ id: interaction.itemId }, next));
196
+ onLiveRectChange === null || onLiveRectChange === void 0 || onLiveRectChange(interaction.itemId, {
197
+ left: next.x,
198
+ top: next.y,
199
+ width: next.width,
200
+ height: next.height
201
+ });
202
+ setAlignGuides(snap.guides);
203
+ onAlignGuidesChange === null || onAlignGuidesChange === void 0 || onAlignGuidesChange(snap.guides);
140
204
  } else {
141
205
  const dx = (e.clientX - interaction.startX) / scale;
142
206
  const dy = (e.clientY - interaction.startY) / scale;
@@ -155,14 +219,36 @@ function EditableItemLayer(props) {
155
219
  h = Math.max(20, startH - dy);
156
220
  y = startItemY + dy;
157
221
  }
158
- const next = {
159
- x,
160
- y,
222
+ const movableEdgesX = handle.includes("w") ? ["left"] : handle.includes("e") ? ["right"] : [];
223
+ const movableEdgesY = handle.includes("n") ? ["top"] : handle.includes("s") ? ["bottom"] : [];
224
+ const snap = require_alignSnap.snapRectToOthers({
225
+ id: interaction.itemId,
226
+ left: x,
227
+ top: y,
161
228
  width: w,
162
229
  height: h
230
+ }, otherRects, {
231
+ mode: "resize",
232
+ threshold,
233
+ movableEdgesX,
234
+ movableEdgesY
235
+ });
236
+ const next = {
237
+ x: snap.rect.left,
238
+ y: snap.rect.top,
239
+ width: Math.max(20, snap.rect.width),
240
+ height: Math.max(20, snap.rect.height)
163
241
  };
164
242
  liveRectRef.current = next;
165
243
  setLiveRect(require_objectSpread2._objectSpread2({ id: interaction.itemId }, next));
244
+ onLiveRectChange === null || onLiveRectChange === void 0 || onLiveRectChange(interaction.itemId, {
245
+ left: next.x,
246
+ top: next.y,
247
+ width: next.width,
248
+ height: next.height
249
+ });
250
+ setAlignGuides(snap.guides);
251
+ onAlignGuidesChange === null || onAlignGuidesChange === void 0 || onAlignGuidesChange(snap.guides);
166
252
  }
167
253
  };
168
254
  const onUp = () => {
@@ -170,6 +256,9 @@ function EditableItemLayer(props) {
170
256
  if (!current) return;
171
257
  const last = liveRectRef.current;
172
258
  onInteractionChange === null || onInteractionChange === void 0 || onInteractionChange(false);
259
+ onLiveRectChange === null || onLiveRectChange === void 0 || onLiveRectChange(null, null);
260
+ setAlignGuides([]);
261
+ onAlignGuidesChange === null || onAlignGuidesChange === void 0 || onAlignGuidesChange([]);
173
262
  setLiveRect(null);
174
263
  liveRectRef.current = null;
175
264
  setInteraction(null);
@@ -205,7 +294,12 @@ function EditableItemLayer(props) {
205
294
  scale,
206
295
  snapStep,
207
296
  onUpdateItem,
208
- onInteractionChange
297
+ onInteractionChange,
298
+ onLiveRectChange,
299
+ items,
300
+ getBaseRect,
301
+ alignSnapThresholdPx,
302
+ onAlignGuidesChange
209
303
  ]);
210
304
  const handleItemClick = (0, react.useCallback)((e, item) => {
211
305
  if (interaction) return;
@@ -241,26 +335,31 @@ function EditableItemLayer(props) {
241
335
  }, shapeStyle), wrapperStyle), {}, { zIndex: isSelected ? SELECTED_ITEM_STACK_Z + ((_item$zIndex2 = item.zIndex) !== null && _item$zIndex2 !== void 0 ? _item$zIndex2 : 0) : baseZ }),
242
336
  onPointerDown: (e) => handlePointerDown(e, item, index),
243
337
  onClick: (e) => handleItemClick(e, item)
244
- }, /* @__PURE__ */ react.default.createElement("div", { className: `${PREFIX}-editable-item-inner` }, renderItem(item, index, { viewportScale: scale })), isSelected && !isSceneLayoutTransformLocked(merged) && /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, [
245
- "nw",
246
- "n",
247
- "ne",
248
- "e",
249
- "se",
250
- "s",
251
- "sw",
252
- "w"
253
- ].map((h) => /* @__PURE__ */ react.default.createElement("div", {
254
- key: h,
255
- className: (0, classnames.default)(`${PREFIX}-editable-resize-handle`, `${PREFIX}-editable-resize-handle-${h}`),
256
- onPointerDown: (e) => handleResizePointerDown(e, item.id, h),
257
- style: { position: "absolute" }
258
- }))), isSelected && editQuickBar ? /* @__PURE__ */ react.default.createElement(require_FloorMapEditQuickActions.FloorMapEditQuickActions, {
338
+ }, /* @__PURE__ */ react.default.createElement("div", { className: `${PREFIX}-editable-item-inner` }, renderItem(item, index, { viewportScale: scale })), isSelected && !isSceneLayoutTransformLocked(merged) && /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, RESIZE_CORNER_HANDLES.map((h) => {
339
+ /** viewport scale 补偿:保持视觉 20px 不随画布放大变大 */
340
+ const size = 20 / Math.max(scale, .01);
341
+ const half = size / 2;
342
+ return /* @__PURE__ */ react.default.createElement("div", {
343
+ key: h,
344
+ className: (0, classnames.default)(`${PREFIX}-editable-resize-handle`, `${PREFIX}-editable-resize-handle-${h}`),
345
+ onPointerDown: (e) => handleResizePointerDown(e, item.id, h),
346
+ style: {
347
+ position: "absolute",
348
+ width: size,
349
+ height: size,
350
+ marginTop: -half,
351
+ marginRight: -half,
352
+ marginBottom: -half,
353
+ marginLeft: -half
354
+ }
355
+ });
356
+ })), isSelected && editQuickBar ? /* @__PURE__ */ react.default.createElement(require_FloorMapEditQuickActions.FloorMapEditQuickActions, {
259
357
  labels: editQuickBar.labels,
260
358
  isLocked: editQuickBar.isLocked,
261
359
  onToggleLock: editQuickBar.onToggleLock,
262
360
  onDuplicate: editQuickBar.onDuplicate,
263
- onDelete: editQuickBar.onDelete
361
+ onDelete: editQuickBar.onDelete,
362
+ viewportScale: scale
264
363
  }) : null);
265
364
  });
266
365
  }, [
@@ -295,7 +394,58 @@ function EditableItemLayer(props) {
295
394
  width: contentWidth,
296
395
  height: contentHeight,
297
396
  transform: `translate(${contentOffsetX}px, ${contentOffsetY}px)`
298
- } }, itemNodes) : itemNodes);
397
+ } }, itemNodes, alignGuides.length > 0 ? /* @__PURE__ */ react.default.createElement(AlignGuideOverlay, {
398
+ guides: alignGuides,
399
+ width: contentWidth,
400
+ height: contentHeight,
401
+ scale,
402
+ stroke: alignGuideStroke
403
+ }) : null) : /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, itemNodes, alignGuides.length > 0 ? /* @__PURE__ */ react.default.createElement(AlignGuideOverlay, {
404
+ guides: alignGuides,
405
+ width: contentWidth,
406
+ height: contentHeight,
407
+ scale,
408
+ stroke: alignGuideStroke
409
+ }) : null));
410
+ }
411
+ /** 拖动/缩放时的对齐辅助线层;线宽按 scale 反向缩放,保持屏幕恒定 1px */
412
+ function AlignGuideOverlay(props) {
413
+ const { guides, width, height, scale, stroke } = props;
414
+ const safeScale = Math.max(scale, .01);
415
+ const sw = 1 / safeScale;
416
+ return /* @__PURE__ */ react.default.createElement("svg", {
417
+ width,
418
+ height,
419
+ style: {
420
+ position: "absolute",
421
+ left: 0,
422
+ top: 0,
423
+ pointerEvents: "none",
424
+ overflow: "visible"
425
+ },
426
+ "aria-hidden": true
427
+ }, guides.map((g, i) => {
428
+ if (g.orientation === "v") return /* @__PURE__ */ react.default.createElement("line", {
429
+ key: `v-${i}-${g.position}`,
430
+ x1: g.position,
431
+ y1: g.start,
432
+ x2: g.position,
433
+ y2: g.end,
434
+ stroke,
435
+ strokeWidth: sw,
436
+ strokeDasharray: `${4 / safeScale} ${3 / safeScale}`
437
+ });
438
+ return /* @__PURE__ */ react.default.createElement("line", {
439
+ key: `h-${i}-${g.position}`,
440
+ x1: g.start,
441
+ y1: g.position,
442
+ x2: g.end,
443
+ y2: g.position,
444
+ stroke,
445
+ strokeWidth: sw,
446
+ strokeDasharray: `${4 / safeScale} ${3 / safeScale}`
447
+ });
448
+ }));
299
449
  }
300
450
  //#endregion
301
451
  exports.default = EditableItemLayer;
@@ -52,51 +52,23 @@
52
52
  cursor: nwse-resize;
53
53
  }
54
54
 
55
- &-n {
56
- left: 50%;
57
- top: 0;
58
- margin-left: -10px;
59
- cursor: ns-resize;
60
- }
61
-
62
55
  &-ne {
63
56
  right: 0;
64
57
  top: 0;
65
58
  cursor: nesw-resize;
66
59
  }
67
60
 
68
- &-e {
69
- right: 0;
70
- top: 50%;
71
- margin-top: -10px;
72
- cursor: ew-resize;
73
- }
74
-
75
61
  &-se {
76
62
  right: 0;
77
63
  bottom: 0;
78
64
  cursor: nwse-resize;
79
65
  }
80
66
 
81
- &-s {
82
- left: 50%;
83
- bottom: 0;
84
- margin-left: -10px;
85
- cursor: ns-resize;
86
- }
87
-
88
67
  &-sw {
89
68
  left: 0;
90
69
  bottom: 0;
91
70
  cursor: nesw-resize;
92
71
  }
93
-
94
- &-w {
95
- left: 0;
96
- top: 50%;
97
- margin-top: -10px;
98
- cursor: ew-resize;
99
- }
100
72
  }
101
73
 
102
74
  .pisell-floor-map-layout-edit-quick-actions {