@pisell/materials 1.8.54 → 1.8.55

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 (139) 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/meta.js +3 -3
  5. package/build/lowcode/render/default/view.css +1 -1
  6. package/build/lowcode/render/default/view.js +35 -35
  7. package/build/lowcode/view.css +1 -1
  8. package/build/lowcode/view.js +35 -35
  9. package/es/components/buttonGroupPreview/index.js +8 -4
  10. package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.js +207 -49
  11. package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
  12. package/es/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
  13. package/es/components/pisellFloorMapLayout/components/EdgeLayer.js +252 -0
  14. package/es/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
  15. package/es/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
  16. package/es/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
  17. package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +131 -0
  18. package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
  19. package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +5 -4
  20. package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
  21. package/es/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
  22. package/es/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
  23. package/es/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
  24. package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.js +290 -147
  25. package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
  26. package/es/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +81 -0
  27. package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
  28. package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +21 -0
  29. package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
  30. package/es/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
  31. package/es/components/pisellFloorMapLayout/components/NodePortMarkers.js +70 -0
  32. package/es/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
  33. package/es/components/pisellFloorMapLayout/components/ViewControls.js +13 -5
  34. package/es/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
  35. package/es/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
  36. package/es/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
  37. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +340 -0
  38. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +102 -0
  39. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +244 -84
  40. package/es/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
  41. package/es/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
  42. package/es/components/pisellFloorMapLayout/index.d.ts +5 -1
  43. package/es/components/pisellFloorMapLayout/locales-ja.js +14 -2
  44. package/es/components/pisellFloorMapLayout/locales-pt.js +14 -2
  45. package/es/components/pisellFloorMapLayout/locales.js +161 -8
  46. package/es/components/pisellFloorMapLayout/types.d.ts +86 -4
  47. package/es/components/pisellFloorMapLayout/types.js +5 -1
  48. package/es/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
  49. package/es/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +86 -0
  50. package/es/components/pisellFloorMapLayout/utils/edgeRouting.js +942 -0
  51. package/es/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
  52. package/es/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -1
  53. package/es/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
  54. package/es/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +20 -3
  55. package/es/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
  56. package/es/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
  57. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
  58. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +62 -0
  59. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
  60. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
  61. package/es/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +51 -0
  62. package/es/components/productCard/cartSkuCard/components/BookingItem/index.js +14 -0
  63. package/es/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
  64. package/es/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
  65. package/es/components/productCard/cartSkuCard/index.js +17 -11
  66. package/es/components/productCard/lineItem/BookingLineItem.js +6 -4
  67. package/es/components/productCard/lineItem/components/Resources/index.js +45 -0
  68. package/es/components/productCard/lineItem/components/TimeRange/index.js +64 -0
  69. package/es/components/productCard/lineItem/index.js +2 -1
  70. package/es/components/productCard/lineItem/index.less +21 -10
  71. package/es/index.d.ts +6 -2
  72. package/es/index.js +6 -2
  73. package/es/pisell-materials.tw.css +3 -0
  74. package/lib/components/buttonGroupPreview/index.js +8 -4
  75. package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.js +206 -48
  76. package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
  77. package/lib/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
  78. package/lib/components/pisellFloorMapLayout/components/EdgeLayer.js +255 -0
  79. package/lib/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
  80. package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
  81. package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
  82. package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +134 -0
  83. package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
  84. package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +4 -3
  85. package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
  86. package/lib/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
  87. package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
  88. package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
  89. package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.js +287 -144
  90. package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
  91. package/lib/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +84 -0
  92. package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
  93. package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +23 -0
  94. package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
  95. package/lib/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
  96. package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.js +73 -0
  97. package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
  98. package/lib/components/pisellFloorMapLayout/components/ViewControls.js +12 -4
  99. package/lib/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
  100. package/lib/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
  101. package/lib/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
  102. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +341 -0
  103. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +103 -0
  104. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +242 -82
  105. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
  106. package/lib/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
  107. package/lib/components/pisellFloorMapLayout/index.d.ts +5 -1
  108. package/lib/components/pisellFloorMapLayout/locales-ja.js +14 -2
  109. package/lib/components/pisellFloorMapLayout/locales-pt.js +14 -2
  110. package/lib/components/pisellFloorMapLayout/locales.js +161 -8
  111. package/lib/components/pisellFloorMapLayout/types.d.ts +86 -4
  112. package/lib/components/pisellFloorMapLayout/types.js +5 -0
  113. package/lib/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
  114. package/lib/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +87 -0
  115. package/lib/components/pisellFloorMapLayout/utils/edgeRouting.js +956 -0
  116. package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
  117. package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -0
  118. package/lib/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
  119. package/lib/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +21 -2
  120. package/lib/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
  121. package/lib/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
  122. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
  123. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +64 -0
  124. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
  125. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
  126. package/lib/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +54 -0
  127. package/lib/components/productCard/cartSkuCard/components/BookingItem/index.js +17 -0
  128. package/lib/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
  129. package/lib/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
  130. package/lib/components/productCard/cartSkuCard/index.js +17 -11
  131. package/lib/components/productCard/lineItem/BookingLineItem.js +6 -4
  132. package/lib/components/productCard/lineItem/components/Resources/index.js +47 -0
  133. package/lib/components/productCard/lineItem/components/TimeRange/index.js +67 -0
  134. package/lib/components/productCard/lineItem/index.js +2 -1
  135. package/lib/components/productCard/lineItem/index.less +21 -10
  136. package/lib/index.d.ts +6 -2
  137. package/lib/index.js +11 -0
  138. package/lib/pisell-materials.tw.css +3 -0
  139. package/package.json +4 -1
@@ -4,8 +4,8 @@
4
4
  position: relative;
5
5
  /**
6
6
  * 中等宽度抽屉:248px → 124px。
7
- * 配合 cellW/cellH(见 FloorMapToolbar.tsx)按 0.5 倍渲染,preview-cell(最大 92px)
8
- * + 标准 padding(12 8)正好落在 124px 内,兼顾画布展示空间与图元预览可视性。
7
+ * 配合 cellW/cellH(见 FloorMapToolbar.tsx)侧栏预览为历史一半(最大约 46px),
8
+ * + 标准 padding(12 8)落在 124px 内,兼顾画布展示空间与图元预览可视性。
9
9
  */
10
10
  width: 124px;
11
11
  flex-shrink: 0;
@@ -96,7 +96,7 @@
96
96
  flex: 1;
97
97
  min-height: 0;
98
98
  overflow-y: auto;
99
- /** 124px 抽屉下,左右各留 8px 给 preview-card 的标准 padding 兜住 92px cell */
99
+ /** 124px 抽屉下,左右各留 8px 给 preview-card 的标准 padding 兜住约 46px cell */
100
100
  padding: 12px 8px;
101
101
  /**
102
102
  * 写死 124px 防止展开动画过程中跟随父容器 0→124px 同步缩放,避免文案被挤成竖排。
@@ -115,13 +115,22 @@
115
115
  }
116
116
  }
117
117
 
118
+ /**
119
+ * 编辑侧栏分类标题:在 toolbar-body 纵向滚动时吸顶,便于长列表切换「资源 / 装饰」等分组。
120
+ * 后一个分类标题滚到顶部时会顶开前一个(同一滚动容器内的标准 sticky 叠放)。
121
+ */
118
122
  &-section-title {
123
+ position: sticky;
124
+ top: 0;
125
+ z-index: 2;
119
126
  margin: 0 0 8px 0;
120
- padding: 0 4px;
127
+ padding: 4px 4px 6px;
121
128
  font-size: 13px;
122
129
  font-weight: 600;
123
130
  color: #262626;
124
131
  line-height: 20px;
132
+ background: #fff;
133
+ box-shadow: 0 1px 0 #f0f0f0;
125
134
  }
126
135
 
127
136
  &-preview-list {
@@ -136,6 +145,145 @@
136
145
  gap: 6px;
137
146
  }
138
147
 
148
+ &-view-all {
149
+ display: block;
150
+ width: 100%;
151
+ margin-top: 2px;
152
+ padding: 6px 8px;
153
+ font-size: 12px;
154
+ line-height: 18px;
155
+ color: var(--fmap-primary, #1677ff);
156
+ text-align: center;
157
+ background: transparent;
158
+ border: 1px dashed #d9d9d9;
159
+ border-radius: 6px;
160
+ cursor: pointer;
161
+ transition: border-color 0.2s, background 0.2s;
162
+
163
+ &:hover {
164
+ background: #f0f7ff;
165
+ border-color: #91caff;
166
+ }
167
+ }
168
+
169
+ &-view-all-modal-hint {
170
+ margin: 0 0 4px;
171
+ font-size: 12px;
172
+ line-height: 18px;
173
+ color: #8c8c8c;
174
+ }
175
+
176
+ &-view-all-modal-grid {
177
+ display: grid;
178
+ grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
179
+ gap: 4px;
180
+ max-height: min(60vh, 420px);
181
+ overflow-y: auto;
182
+ padding: 0;
183
+ }
184
+
185
+ &-view-all-modal-card {
186
+ display: flex;
187
+ flex-direction: column;
188
+ align-items: center;
189
+ gap: 4px;
190
+ padding: 6px;
191
+ text-align: center;
192
+ background: #fafafa;
193
+ border: 1px solid #e8e8e8;
194
+ border-radius: 6px;
195
+ transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;
196
+
197
+ &:hover {
198
+ border-color: #91caff;
199
+ background: #f0f7ff;
200
+ }
201
+
202
+ &--selected {
203
+ border-color: var(--fmap-primary, #1677ff);
204
+ background: color-mix(in srgb, var(--fmap-primary, #1677ff) 10%, #fff);
205
+ box-shadow: 0 0 0 1px var(--fmap-primary, #1677ff);
206
+ }
207
+ }
208
+
209
+ /** 名称下方居中:数量步进器(触控友好尺寸) */
210
+ &-view-all-modal-card-stepper {
211
+ display: inline-flex;
212
+ align-items: center;
213
+ justify-content: center;
214
+ gap: 4px;
215
+ padding: 3px 4px;
216
+ background: #fff;
217
+ border: 1px solid #e8e8e8;
218
+ border-radius: 6px;
219
+ }
220
+
221
+ &-view-all-modal-card-stepper-btn {
222
+ display: inline-flex;
223
+ align-items: center;
224
+ justify-content: center;
225
+ width: 26px;
226
+ height: 26px;
227
+ padding: 0;
228
+ font-size: 12px;
229
+ line-height: 1;
230
+ color: #595959;
231
+ background: #fafafa;
232
+ border: 1px solid #d9d9d9;
233
+ border-radius: 4px;
234
+ cursor: pointer;
235
+ transition: border-color 0.15s, color 0.15s, background 0.15s;
236
+
237
+ .anticon {
238
+ font-size: 12px;
239
+ }
240
+
241
+ &:hover:not(:disabled) {
242
+ color: var(--fmap-primary, #1677ff);
243
+ border-color: #91caff;
244
+ background: #f0f7ff;
245
+ }
246
+
247
+ &:disabled {
248
+ color: #bfbfbf;
249
+ background: #f5f5f5;
250
+ border-color: #f0f0f0;
251
+ cursor: not-allowed;
252
+ }
253
+ }
254
+
255
+ &-view-all-modal-card-stepper-qty {
256
+ min-width: 18px;
257
+ padding: 0 4px;
258
+ font-size: 13px;
259
+ font-weight: 600;
260
+ line-height: 26px;
261
+ color: #262626;
262
+ text-align: center;
263
+ user-select: none;
264
+ }
265
+
266
+ &-view-all-modal-card-preview {
267
+ display: flex;
268
+ justify-content: center;
269
+ align-items: center;
270
+ min-height: 28px;
271
+ pointer-events: none;
272
+
273
+ .pisell-floor-map-layout-toolbar-preview-cell {
274
+ flex-shrink: 0;
275
+ }
276
+ }
277
+
278
+ &-view-all-modal-card-label {
279
+ width: 100%;
280
+ margin: 0;
281
+ font-size: 11px;
282
+ line-height: 16px;
283
+ color: #262626;
284
+ text-align: center;
285
+ }
286
+
139
287
  &-preview-group-label {
140
288
  padding: 0 4px;
141
289
  font-size: 12px;
@@ -153,7 +301,7 @@
153
301
  &-preview-card {
154
302
  display: block;
155
303
  width: 100%;
156
- /** 标准 padding 适配 124px 抽屉 + 92px cell 的尺寸预算 */
304
+ /** 标准 padding 适配 124px 抽屉 + 46px cell 的尺寸预算 */
157
305
  padding: 8px;
158
306
  text-align: center;
159
307
  background: #fafafa;
@@ -199,13 +347,12 @@
199
347
  }
200
348
 
201
349
  &-preview-content {
350
+ position: absolute;
351
+ left: 50%;
352
+ top: 50%;
353
+ flex-shrink: 0;
202
354
  pointer-events: none;
203
- }
204
-
205
- &-preview-cell {
206
- .pisell-floor-map-layout-toolbar-preview-content {
207
- overflow: hidden;
208
- }
355
+ overflow: hidden;
209
356
  }
210
357
 
211
358
  &-preview-fallback {
@@ -329,6 +476,27 @@
329
476
  line-height: 1.45;
330
477
  }
331
478
 
479
+ &-resource-picker-btn {
480
+ display: block;
481
+ width: 100%;
482
+ margin-top: 4px;
483
+ padding: 8px 10px;
484
+ font-size: 13px;
485
+ line-height: 18px;
486
+ text-align: center;
487
+ color: var(--fmap-primary, #1677ff);
488
+ background: #fff;
489
+ border: 1px solid #91caff;
490
+ border-radius: 6px;
491
+ cursor: pointer;
492
+ transition: background 0.15s, border-color 0.15s;
493
+
494
+ &:hover {
495
+ background: #f0f7ff;
496
+ border-color: var(--fmap-primary, #1677ff);
497
+ }
498
+ }
499
+
332
500
  &-record-hint {
333
501
  font-size: 11px;
334
502
  color: #8c8c8c;
@@ -419,3 +587,34 @@
419
587
  line-height: 1;
420
588
  }
421
589
  }
590
+
591
+ /**
592
+ * 「查看全部」弹窗:padding 统一 6px,块间距 / grid gap 统一 4px(覆盖 antd 默认 24px 内边距)。
593
+ */
594
+ .pisell-floor-map-layout-toolbar-view-all-modal {
595
+ .pisell-lowcode-modal-content {
596
+ padding: 0;
597
+ }
598
+
599
+ .pisell-lowcode-modal-header {
600
+ padding: 6px 6px 0;
601
+ margin-bottom: 0;
602
+ }
603
+
604
+ .pisell-lowcode-modal-body {
605
+ padding: 4px 6px 6px;
606
+ }
607
+
608
+ .pisell-lowcode-modal-footer {
609
+ display: flex;
610
+ flex-wrap: wrap;
611
+ justify-content: flex-end;
612
+ gap: 4px;
613
+ padding: 4px 6px 6px;
614
+ margin-top: 0;
615
+
616
+ > .pisell-lowcode-btn + .pisell-lowcode-btn {
617
+ margin-inline-start: 0;
618
+ }
619
+ }
620
+ }
@@ -0,0 +1,84 @@
1
+ const require_runtime = require("../../../_virtual/_rolldown/runtime.js");
2
+ const require_toPropertyKey = require("../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/toPropertyKey.js");
3
+ const require_objectSpread2 = require("../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js");
4
+ const require_objectWithoutProperties = require("../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectWithoutProperties.js");
5
+ const require_floorMapLayoutConstants = require("../floorMapLayoutConstants.js");
6
+ const require_floorMapToolbarPalette = require("../utils/floorMapToolbarPalette.js");
7
+ let react = require("react");
8
+ react = require_runtime.__toESM(react);
9
+ let _pisell_utils = require("@pisell/utils");
10
+ let antd = require("antd");
11
+ let _ant_design_icons = require("@ant-design/icons");
12
+ let classnames = require("classnames");
13
+ classnames = require_runtime.__toESM(classnames);
14
+ //#region src/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.tsx
15
+ /**
16
+ * 侧栏 palette「查看全部」:任意分类下图元超过展示上限时,弹窗内按数量多选并一键落点。
17
+ */
18
+ const I18N_TB = "pisell-floor-map-layout.toolbar";
19
+ /** 单种图元在弹窗内可添加的最大数量 */
20
+ const PALETTE_VIEW_ALL_MODAL_MAX_QTY = 99;
21
+ function FloorMapToolbarViewAllModal(props) {
22
+ const { open, categoryLabel, entries, onClose, onConfirm, renderEntryPreview } = props;
23
+ const [quantities, setQuantities] = (0, react.useState)({});
24
+ (0, react.useEffect)(() => {
25
+ if (!open) setQuantities({});
26
+ }, [open]);
27
+ const totalQty = (0, react.useMemo)(() => Object.values(quantities).reduce((sum, n) => sum + (Number.isFinite(n) && n > 0 ? n : 0), 0), [quantities]);
28
+ const setQty = (0, react.useCallback)((key, next) => {
29
+ const clamped = Math.max(0, Math.min(PALETTE_VIEW_ALL_MODAL_MAX_QTY, next));
30
+ setQuantities((prev) => {
31
+ if (clamped === 0) {
32
+ const { [key]: _removed } = prev;
33
+ return require_objectWithoutProperties._objectWithoutProperties(prev, [key].map(require_toPropertyKey.toPropertyKey));
34
+ }
35
+ return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, prev), {}, { [key]: clamped });
36
+ });
37
+ }, []);
38
+ const title = (0, react.useMemo)(() => _pisell_utils.locales.getText(`${I18N_TB}.view-all-modal-title`).replace(/\{category\}/g, categoryLabel), [categoryLabel]);
39
+ return /* @__PURE__ */ react.default.createElement(antd.Modal, {
40
+ open,
41
+ title,
42
+ onCancel: onClose,
43
+ destroyOnClose: true,
44
+ width: 520,
45
+ zIndex: 1100,
46
+ className: `${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal`,
47
+ okText: _pisell_utils.locales.getText(`${I18N_TB}.view-all-modal-add`),
48
+ cancelText: _pisell_utils.locales.getText(`${I18N_TB}.view-all-modal-cancel`),
49
+ okButtonProps: { disabled: totalQty === 0 },
50
+ onOk: () => {
51
+ if (totalQty === 0) return;
52
+ onConfirm(require_floorMapToolbarPalette.expandPaletteEntriesByQuantity(entries, quantities));
53
+ onClose();
54
+ }
55
+ }, /* @__PURE__ */ react.default.createElement("p", { className: `${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-hint` }, _pisell_utils.locales.getText(`${I18N_TB}.view-all-modal-hint`)), /* @__PURE__ */ react.default.createElement("div", { className: `${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-grid` }, entries.map((entry) => {
56
+ var _quantities$entry$key;
57
+ const qty = (_quantities$entry$key = quantities[entry.key]) !== null && _quantities$entry$key !== void 0 ? _quantities$entry$key : 0;
58
+ const selected = qty > 0;
59
+ return /* @__PURE__ */ react.default.createElement("div", {
60
+ key: entry.key,
61
+ className: (0, classnames.default)(`${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-card`, { [`${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-card--selected`]: selected })
62
+ }, /* @__PURE__ */ react.default.createElement("div", { className: `${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-card-preview` }, renderEntryPreview(entry)), /* @__PURE__ */ react.default.createElement("span", { className: `${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-card-label` }, entry.label), /* @__PURE__ */ react.default.createElement("div", {
63
+ className: `${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-card-stepper`,
64
+ onClick: (e) => e.stopPropagation()
65
+ }, /* @__PURE__ */ react.default.createElement("button", {
66
+ type: "button",
67
+ className: `${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-card-stepper-btn`,
68
+ disabled: qty <= 0,
69
+ "aria-label": _pisell_utils.locales.getText(`${I18N_TB}.view-all-modal-qty-decrease`),
70
+ onClick: () => setQty(entry.key, qty - 1)
71
+ }, /* @__PURE__ */ react.default.createElement(_ant_design_icons.MinusOutlined, null)), /* @__PURE__ */ react.default.createElement("span", {
72
+ className: `${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-card-stepper-qty`,
73
+ "aria-live": "polite"
74
+ }, qty), /* @__PURE__ */ react.default.createElement("button", {
75
+ type: "button",
76
+ className: `${require_floorMapLayoutConstants.FLOOR_MAP_LAYOUT_CLASS_PREFIX}-toolbar-view-all-modal-card-stepper-btn`,
77
+ disabled: qty >= PALETTE_VIEW_ALL_MODAL_MAX_QTY,
78
+ "aria-label": _pisell_utils.locales.getText(`${I18N_TB}.view-all-modal-qty-increase`),
79
+ onClick: () => setQty(entry.key, qty + 1)
80
+ }, /* @__PURE__ */ react.default.createElement(_ant_design_icons.PlusOutlined, null))));
81
+ })));
82
+ }
83
+ //#endregion
84
+ exports.default = FloorMapToolbarViewAllModal;
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ //#region src/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts
3
+ interface FloorMapZoneElementProps {
4
+ name?: string;
5
+ }
6
+ declare function FloorMapZoneElement(props: FloorMapZoneElementProps): React.JSX.Element;
7
+ //#endregion
8
+ export { FloorMapZoneElement };
@@ -0,0 +1,23 @@
1
+ const require_runtime = require("../../../_virtual/_rolldown/runtime.js");
2
+ let react = require("react");
3
+ react = require_runtime.__toESM(react);
4
+ let _pisell_utils = require("@pisell/utils");
5
+ require("./FloorMapZoneElement.less");
6
+ //#region src/components/pisellFloorMapLayout/components/FloorMapZoneElement.tsx
7
+ /**
8
+ * 分区(zone)图元展示:虚线容器 + 左上角标题标签,避免与空白占位资源混淆。
9
+ */
10
+ const PREFIX = "pisell-floor-map-zone";
11
+ const I18N_BADGE = "pisell-floor-map-layout.zone.title-badge";
12
+ const I18N_UNNAMED = "pisell-floor-map-layout.zone.unnamed";
13
+ function FloorMapZoneElement(props) {
14
+ const raw = props.name != null ? String(props.name).trim() : "";
15
+ const hasName = raw.length > 0;
16
+ const displayName = hasName ? raw : _pisell_utils.locales.getText(I18N_UNNAMED);
17
+ return /* @__PURE__ */ react.default.createElement("div", { className: PREFIX }, /* @__PURE__ */ react.default.createElement("div", {
18
+ className: `${PREFIX}__body`,
19
+ "aria-hidden": true
20
+ }), /* @__PURE__ */ react.default.createElement("div", { className: `${PREFIX}__title` }, /* @__PURE__ */ react.default.createElement("span", { className: `${PREFIX}__title-badge` }, _pisell_utils.locales.getText(I18N_BADGE)), /* @__PURE__ */ react.default.createElement("span", { className: `${PREFIX}__title-text${hasName ? "" : ` ${PREFIX}__title-text--placeholder`}` }, displayName)));
21
+ }
22
+ //#endregion
23
+ exports.FloorMapZoneElement = FloorMapZoneElement;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * 分区容器图元:标题为左上角标签条,与居中灰底「空白占位」资源区分。
3
+ */
4
+ .pisell-floor-map-zone {
5
+ position: relative;
6
+ width: 100%;
7
+ height: 100%;
8
+ box-sizing: border-box;
9
+ overflow: visible;
10
+ pointer-events: none;
11
+ }
12
+
13
+ .pisell-floor-map-zone__body {
14
+ width: 100%;
15
+ height: 100%;
16
+ box-sizing: border-box;
17
+ border: 2px dashed #91caff;
18
+ border-radius: 8px;
19
+ background: color-mix(
20
+ in srgb,
21
+ var(--fmap-primary, #1677ff) 8%,
22
+ #fff
23
+ );
24
+ }
25
+
26
+ .pisell-floor-map-zone__title {
27
+ position: absolute;
28
+ top: 0;
29
+ left: 10px;
30
+ z-index: 1;
31
+ display: inline-flex;
32
+ align-items: center;
33
+ gap: 6px;
34
+ max-width: calc(100% - 20px);
35
+ padding: 3px 10px 3px 8px;
36
+ transform: translateY(-50%);
37
+ background: #fff;
38
+ border: 1px solid #91caff;
39
+ border-radius: 6px;
40
+ box-shadow: 0 2px 6px rgba(16, 24, 40, 0.12);
41
+ line-height: 1.3;
42
+ pointer-events: none;
43
+ }
44
+
45
+ .pisell-floor-map-zone__title-badge {
46
+ flex-shrink: 0;
47
+ padding: 1px 5px;
48
+ border-radius: 4px;
49
+ font-size: 10px;
50
+ font-weight: 700;
51
+ letter-spacing: 0.04em;
52
+ text-transform: uppercase;
53
+ color: var(--fmap-primary, #1677ff);
54
+ background: color-mix(
55
+ in srgb,
56
+ var(--fmap-primary, #1677ff) 14%,
57
+ #fff
58
+ );
59
+ }
60
+
61
+ .pisell-floor-map-zone__title-text {
62
+ min-width: 0;
63
+ font-size: 13px;
64
+ font-weight: 600;
65
+ color: #101828;
66
+ white-space: nowrap;
67
+ overflow: hidden;
68
+ text-overflow: ellipsis;
69
+ }
70
+
71
+ .pisell-floor-map-zone__title-text--placeholder {
72
+ font-weight: 500;
73
+ color: #667085;
74
+ }
@@ -33,7 +33,9 @@
33
33
  * 仅在 item 内包含该类卡片时放开 overflow,避免影响其它图元定位/裁剪。
34
34
  */
35
35
  .pisell-floor-map-layout-item:has(.pisell-res-floor-room-card[data-tooltip-time='on']),
36
- .pisell-floor-map-layout-item:has(.pisell-res-floor-room-card[data-reserved-halo='on']) {
36
+ .pisell-floor-map-layout-item:has(.pisell-res-floor-room-card[data-reserved-halo='on']),
37
+ .pisell-floor-map-layout-item:has(.pisell-topology-device-card),
38
+ .pisell-floor-map-layout-item:has(.pisell-floor-map-zone) {
37
39
  overflow: visible;
38
40
  z-index: 1;
39
41
  }
@@ -0,0 +1,73 @@
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("./NodePortMarkers.less");
8
+ //#region src/components/pisellFloorMapLayout/components/NodePortMarkers.tsx
9
+ /**
10
+ * NodePortMarkers - 选中图元时显示四向锚点,用于拉线
11
+ */
12
+ /** 端口圆点的视觉直径(px),与 NodePortMarkers.less 中 base width/height 保持一致 */
13
+ const MARKER_VISUAL_SIZE = 10;
14
+ const PREFIX = "pisell-floor-map-layout";
15
+ const MARKER_ANCHORS = [
16
+ "top",
17
+ "right",
18
+ "bottom",
19
+ "left"
20
+ ];
21
+ function NodePortMarkers(props) {
22
+ const { rect, contentOffsetX = 0, contentOffsetY = 0, previewOnly = false, onAnchorPointerDown, highlightAnchors = [], className, viewportScale = 1 } = props;
23
+ const safeScale = Math.max(viewportScale, .01);
24
+ const markerSize = MARKER_VISUAL_SIZE / safeScale;
25
+ const markerHalf = markerSize / 2;
26
+ const markerOutset = 16 / safeScale;
27
+ return /* @__PURE__ */ react.default.createElement("div", {
28
+ className: (0, classnames.default)(`${PREFIX}-port-markers`, className),
29
+ style: {
30
+ position: "absolute",
31
+ left: contentOffsetX + rect.left,
32
+ top: contentOffsetY + rect.top,
33
+ width: rect.width,
34
+ height: rect.height,
35
+ pointerEvents: "none",
36
+ zIndex: 5
37
+ }
38
+ }, MARKER_ANCHORS.map((anchor) => {
39
+ const pt = require_edgeRouting.getPortMarkerDisplayPoint({
40
+ left: 0,
41
+ top: 0,
42
+ width: rect.width,
43
+ height: rect.height
44
+ }, anchor, markerOutset);
45
+ const highlighted = highlightAnchors.includes(anchor);
46
+ const Tag = previewOnly ? "span" : "button";
47
+ return /* @__PURE__ */ react.default.createElement(Tag, {
48
+ key: anchor,
49
+ type: previewOnly ? void 0 : "button",
50
+ className: (0, classnames.default)(`${PREFIX}-port-marker`, {
51
+ [`${PREFIX}-port-marker--highlight`]: highlighted,
52
+ [`${PREFIX}-port-marker--preview`]: previewOnly
53
+ }),
54
+ style: {
55
+ left: pt.x,
56
+ top: pt.y,
57
+ width: markerSize,
58
+ height: markerSize,
59
+ marginLeft: -markerHalf,
60
+ marginTop: -markerHalf,
61
+ pointerEvents: previewOnly ? "none" : "auto"
62
+ },
63
+ "aria-label": anchor,
64
+ onPointerDown: previewOnly || !onAnchorPointerDown ? void 0 : (ev) => {
65
+ ev.stopPropagation();
66
+ ev.preventDefault();
67
+ onAnchorPointerDown(anchor, ev);
68
+ }
69
+ });
70
+ }));
71
+ }
72
+ //#endregion
73
+ exports.NodePortMarkers = NodePortMarkers;
@@ -0,0 +1,33 @@
1
+ .pisell-floor-map-layout-port-markers {
2
+ overflow: visible;
3
+ /** 高于边中点缩放手柄 (z-index: 3),避免拖拽连线时误触缩放 */
4
+ z-index: 5;
5
+ }
6
+
7
+ .pisell-floor-map-layout-port-markers--draw-target {
8
+ z-index: 6;
9
+ }
10
+
11
+ .pisell-floor-map-layout-port-marker {
12
+ position: absolute;
13
+ width: 10px;
14
+ height: 10px;
15
+ margin: -5px 0 0 -5px;
16
+ padding: 0;
17
+ border: 2px solid #1570ef;
18
+ border-radius: 50%;
19
+ background: #fff;
20
+ cursor: crosshair;
21
+ box-shadow: 0 1px 2px rgba(16, 24, 40, 0.12);
22
+ z-index: 1;
23
+ }
24
+
25
+ .pisell-floor-map-layout-port-marker--highlight {
26
+ background: #1570ef;
27
+ transform: scale(1.15);
28
+ }
29
+
30
+ .pisell-floor-map-layout-port-marker--preview {
31
+ cursor: default;
32
+ box-shadow: 0 0 0 2px rgba(21, 112, 239, 0.25);
33
+ }
@@ -16,12 +16,13 @@ const PREFIX = "pisell-floor-map-layout";
16
16
  const I18N_VC = "pisell-floor-map-layout.view-controls";
17
17
  function ViewControls(props) {
18
18
  var _config$horizontalAli;
19
- const { api, config = {}, scale = 1, isFullscreen = false, fitBoundsActive = false, className, mapGridVisible = false, onToggleMapGrid, viewportLocked = false, onToggleViewportLock, dockChrome = false, dockExpandedToolButtons, dockExpandedTrailing, autoCollapseDockMs = 1e4 } = props;
19
+ const { api, config = {}, scale = 1, isFullscreen = false, fitBoundsActive = false, className, mapGridVisible = false, onToggleMapGrid, edgesLayerVisible = true, onToggleEdgesLayer, viewportLocked = false, onToggleViewportLock, dockChrome = false, dockExpandedToolButtons, dockExpandedTrailing, autoCollapseDockMs = 1e4 } = props;
20
20
  const showZoom = config.showZoom !== false;
21
21
  const showReset = config.showReset === true;
22
22
  const showFitBounds = config.showFitBounds === true;
23
23
  const showFullscreen = config.showFullscreen === true;
24
24
  const showGridToggle = config.showGridToggle === true && typeof onToggleMapGrid === "function";
25
+ const showEdgesToggle = config.showEdgesToggle === true && typeof onToggleEdgesLayer === "function";
25
26
  const showViewportLock = config.showViewportLock === true && typeof onToggleViewportLock === "function";
26
27
  /**
27
28
  * `horizontalAlign` 仅作用于非 dockChrome 的普通横条(决定贴左下还是右下)。
@@ -29,7 +30,7 @@ function ViewControls(props) {
29
30
  */
30
31
  const horizontalAlign = (_config$horizontalAli = config.horizontalAlign) !== null && _config$horizontalAli !== void 0 ? _config$horizontalAli : "start";
31
32
  const scalePercent = Math.round(scale * 100);
32
- const showTools = showReset || showFitBounds || showFullscreen || showGridToggle || showViewportLock;
33
+ const showTools = showReset || showFitBounds || showFullscreen || showGridToggle || showEdgesToggle || showViewportLock;
33
34
  const hasDockToolButtons = dockExpandedToolButtons != null && dockExpandedToolButtons !== false;
34
35
  const hasTrailingSlot = dockExpandedTrailing != null && dockExpandedTrailing !== false;
35
36
  const dockHasExpandable = dockChrome && (showTools || hasDockToolButtons || hasTrailingSlot);
@@ -113,7 +114,14 @@ function ViewControls(props) {
113
114
  onClick: () => onToggleMapGrid(),
114
115
  "aria-pressed": mapGridVisible,
115
116
  "aria-label": _pisell_utils.locales.getText(mapGridVisible ? `${I18N_VC}.grid-hide-aria` : `${I18N_VC}.grid-show-aria`)
116
- }, /* @__PURE__ */ react.default.createElement(_ant_design_icons.BorderInnerOutlined, null)) : null, showViewportLock && !omitLock ? /* @__PURE__ */ react.default.createElement("button", {
117
+ }, /* @__PURE__ */ react.default.createElement(_ant_design_icons.BorderInnerOutlined, null)) : null, showEdgesToggle ? /* @__PURE__ */ react.default.createElement("button", {
118
+ type: "button",
119
+ className: (0, classnames.default)(`${PREFIX}-view-controls-tool-btn`, { [`${PREFIX}-view-controls-tool-btn--active`]: edgesLayerVisible }),
120
+ onClick: () => onToggleEdgesLayer(),
121
+ "aria-pressed": edgesLayerVisible,
122
+ "aria-label": _pisell_utils.locales.getText(edgesLayerVisible ? `${I18N_VC}.edges-hide-aria` : `${I18N_VC}.edges-show-aria`),
123
+ title: _pisell_utils.locales.getText(edgesLayerVisible ? `${I18N_VC}.edges-hide-aria` : `${I18N_VC}.edges-show-aria`)
124
+ }, /* @__PURE__ */ react.default.createElement(_ant_design_icons.NodeIndexOutlined, null)) : null, showViewportLock && !omitLock ? /* @__PURE__ */ react.default.createElement("button", {
117
125
  type: "button",
118
126
  className: (0, classnames.default)(`${PREFIX}-view-controls-tool-btn`, { [`${PREFIX}-view-controls-tool-btn--active`]: viewportLocked }),
119
127
  onClick: () => onToggleViewportLock(),
@@ -132,7 +140,7 @@ function ViewControls(props) {
132
140
  * dockChrome 展开条内的「工具区」按钮:锁 / 全览 已常驻在 `dock-collapsed-extras` 屏右缘,
133
141
  * 展开条内不再重复渲染,避免冗余。
134
142
  */
135
- const dockExpandedBarHasToolButtons = showReset || showGridToggle || showFullscreen && Boolean(api.toggleFullscreen);
143
+ const dockExpandedBarHasToolButtons = showReset || showGridToggle || showEdgesToggle || showFullscreen && Boolean(api.toggleFullscreen);
136
144
  /**
137
145
  * dockChrome 合并入口:同一个 toggle 按钮承担展开/收起,常驻在 slide 内最左端。
138
146
  * - 折叠态:箭头朝左,点一下展开(slide 由 toggle 宽撑成 max-width);
@@ -30,6 +30,8 @@ function ViewControlsWithZoom(props) {
30
30
  fitBoundsActive: props.fitBoundsActive,
31
31
  mapGridVisible: props.mapGridVisible,
32
32
  onToggleMapGrid: props.onToggleMapGrid,
33
+ edgesLayerVisible: props.edgesLayerVisible,
34
+ onToggleEdgesLayer: props.onToggleEdgesLayer,
33
35
  viewportLocked: props.viewportLocked,
34
36
  onToggleViewportLock: props.onToggleViewportLock,
35
37
  dockChrome: props.dockChrome,
@@ -4,7 +4,7 @@ const require_objectSpread2 = require("../../../_virtual/_@oxc-project_runtime@0
4
4
  * 将 `FloorMapLayoutContext` 与 Layout props 合并:各字段 props ?? ctx,props 显式值优先。
5
5
  */
6
6
  function mergeFloorMapLayoutPropsFromContext(props, ctx) {
7
- var _props$floorMapConfig, _props$dataSources, _props$onSave, _props$onDataSourceRe, _props$dataSourceLabe, _props$dataSourceForm, _props$dataSourceReco, _props$loading, _props$saveError, _props$onElementRende, _props$toolbarShowSav, _props$floorMapFullsc, _props$appearanceMode, _props$showDataSource, _props$viewportDockTo, _props$viewportDockTr;
7
+ var _props$floorMapConfig, _props$dataSources, _props$onSave, _props$onDataSourceRe, _props$dataSourceLabe, _props$dataSourceForm, _props$dataSourceReco, _props$loading, _props$saveError, _props$onElementRende, _props$toolbarShowSav, _props$paletteSidebar, _props$floorMapFullsc, _props$appearanceMode, _props$showDataSource, _props$viewportDockTo, _props$viewportDockTr;
8
8
  if (ctx == null) return props;
9
9
  return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, props), {}, {
10
10
  floorMapConfig: (_props$floorMapConfig = props.floorMapConfig) !== null && _props$floorMapConfig !== void 0 ? _props$floorMapConfig : ctx.floorMapConfig,
@@ -18,6 +18,7 @@ function mergeFloorMapLayoutPropsFromContext(props, ctx) {
18
18
  saveError: (_props$saveError = props.saveError) !== null && _props$saveError !== void 0 ? _props$saveError : ctx.saveError,
19
19
  onElementRenderError: (_props$onElementRende = props.onElementRenderError) !== null && _props$onElementRende !== void 0 ? _props$onElementRende : ctx.onElementRenderError,
20
20
  toolbarShowSave: (_props$toolbarShowSav = props.toolbarShowSave) !== null && _props$toolbarShowSav !== void 0 ? _props$toolbarShowSav : ctx.toolbarShowSave,
21
+ paletteSidebarVisibleLimit: (_props$paletteSidebar = props.paletteSidebarVisibleLimit) !== null && _props$paletteSidebar !== void 0 ? _props$paletteSidebar : ctx.paletteSidebarVisibleLimit,
21
22
  floorMapFullscreenMode: (_props$floorMapFullsc = props.floorMapFullscreenMode) !== null && _props$floorMapFullsc !== void 0 ? _props$floorMapFullsc : ctx.floorMapFullscreenMode,
22
23
  appearanceMode: (_props$appearanceMode = props.appearanceMode) !== null && _props$appearanceMode !== void 0 ? _props$appearanceMode : ctx.appearanceMode,
23
24
  showDataSourceRecordFormBlock: (_props$showDataSource = props.showDataSourceRecordFormBlock) !== null && _props$showDataSource !== void 0 ? _props$showDataSource : ctx.showDataSourceRecordFormBlock,
@@ -13,7 +13,7 @@ const FLOOR_MAP_PHONE_EDIT_DRAWER_Z_INDEX = 2002;
13
13
  const FLOOR_MAP_CONFIRM_OVERLAY_Z_INDEX = 2100;
14
14
  /**
15
15
  * 「全览」伪画布 Tab id。
16
- * 仅在阅读态、启用画布 > 1 时插入到画布 Tab 列表最前,用来承载「同时查看所有画布」的入口。
16
+ * 仅在阅读态、启用画布 > 1 时插入到画布 Tab 列表末尾,用来承载「同时查看所有画布」的入口。
17
17
  * 不会写入 `config.canvases`,也不参与视口持久化、items 计算等真实画布逻辑。
18
18
  */
19
19
  const FLOOR_MAP_OVERVIEW_TAB_ID = "__pisell_floor_map_overview__";