@pisell/materials 1.0.1060 → 1.0.1062

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 (64) 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 +7 -7
  5. package/build/lowcode/render/default/view.css +1 -1
  6. package/build/lowcode/render/default/view.js +3 -3
  7. package/build/lowcode/view.css +1 -1
  8. package/build/lowcode/view.js +23 -23
  9. package/es/components/PisellLayouts/index.js +14 -14
  10. package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.js +9 -4
  11. package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.stories.js +34 -34
  12. package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +55 -2
  13. package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +1 -0
  14. package/es/components/pisellFloorMapLayout/components/ItemLayer.js +5 -5
  15. package/es/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +3 -2
  16. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEditState.d.ts +2 -0
  17. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +4 -2
  18. package/es/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +42 -1
  19. package/es/components/pisellFloorMapLayout/types.d.ts +17 -1
  20. package/es/components/pisellHierarchicalSummaryList/hooks/useExpandedKeys.js +2 -2
  21. package/es/components/pisellHierarchicalSummaryList/index.js +2 -2
  22. package/es/components/pisellRecordBoard/PisellRecordBoard.js +30 -5
  23. package/es/components/pisellRecordBoard/PisellRecordBoard.stories.js +51 -51
  24. package/es/components/pisellRecordBoard/shellFrame/ToolBar/index.js +4 -4
  25. package/es/components/pisellRecordBoard/shellFrame/index.js +4 -2
  26. package/es/components/pisellRecordBoard/types.d.ts +8 -2
  27. package/es/components/pisellReservationScheduleBand/PisellReservationScheduleBand.less +1 -1
  28. package/es/components/pisellTimeNavigator/PisellTimeNavigator.js +148 -51
  29. package/es/components/pisellTimeNavigator/PisellTimeNavigator.less +38 -4
  30. package/es/components/pisellTimeNavigator/components/BackgroundLayer.js +2 -2
  31. package/es/components/pisellTimeNavigator/components/CursorLayer.js +4 -4
  32. package/es/components/pisellTimeNavigator/components/GestureLayer.js +2 -2
  33. package/es/components/pisellTimeNavigator/components/NowButton.js +3 -3
  34. package/es/components/pisellTimeNavigator/components/ScaleLayer.js +3 -3
  35. package/es/components/pisellTimeNavigator/hooks/useDragInertia.js +2 -2
  36. package/es/components/pisellTimeNavigator/hooks/useRealtime.js +2 -2
  37. package/es/components/pisellTimeNavigator/hooks/useTimeAxis.js +8 -8
  38. package/es/components/pisellTimeNavigator/types.d.ts +4 -0
  39. package/es/components/pisellTimeNavigator/utils/index.d.ts +4 -0
  40. package/es/components/pisellTimeNavigator/utils/index.js +28 -14
  41. package/es/index.js +16 -16
  42. package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.js +7 -4
  43. package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +231 -157
  44. package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +1 -0
  45. package/lib/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
  46. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEditState.d.ts +2 -0
  47. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +4 -2
  48. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +47 -1
  49. package/lib/components/pisellFloorMapLayout/types.d.ts +17 -1
  50. package/lib/components/pisellRecordBoard/PisellRecordBoard.js +32 -4
  51. package/lib/components/pisellRecordBoard/shellFrame/index.js +1 -0
  52. package/lib/components/pisellRecordBoard/types.d.ts +8 -2
  53. package/lib/components/pisellReservationScheduleBand/PisellReservationScheduleBand.less +1 -1
  54. package/lib/components/pisellTimeNavigator/PisellTimeNavigator.js +143 -29
  55. package/lib/components/pisellTimeNavigator/PisellTimeNavigator.less +38 -4
  56. package/lib/components/pisellTimeNavigator/types.d.ts +4 -0
  57. package/lib/components/pisellTimeNavigator/utils/index.d.ts +4 -0
  58. package/lib/components/pisellTimeNavigator/utils/index.js +9 -0
  59. package/lowcode/floor-map-layout-provider/meta.ts +1 -1
  60. package/lowcode/pisell-floor-map-layout/meta.ts +75 -1
  61. package/lowcode/pisell-hierarchical-summary-list/meta.ts +244 -244
  62. package/lowcode/render-figma-style-round-table-card/meta.ts +1 -1
  63. package/lowcode/render-figma-style-table-card/meta.ts +1 -1
  64. package/package.json +4 -4
@@ -76,6 +76,7 @@ function FloorMapEditPanel(props) {
76
76
  savingRecord,
77
77
  dataSourceLabels = {},
78
78
  layoutDraftDirty,
79
+ showDataSourceRecordFormBlock: showRecordFormProp,
79
80
  className
80
81
  } = props;
81
82
  const [form] = import_antd.Form.useForm();
@@ -220,6 +221,7 @@ function FloorMapEditPanel(props) {
220
221
  const hasCustomRecordForm = recordFormSlotRaw !== void 0 && recordFormSlotRaw !== null && recordFormSlotRaw !== false;
221
222
  const showDataBindingSection = bindingPolicy !== "none";
222
223
  const showDataSourceRecordBlock = hasBoundDataRecord && Boolean(binding) && (onSaveRecord != null || hasCustomRecordForm);
224
+ const showDataRecordEditorSection = showRecordFormProp !== false && showDataSourceRecordBlock && Boolean(binding);
223
225
  const recordFormContext = (0, import_react.useMemo)(() => {
224
226
  if (!binding) return null;
225
227
  return {
@@ -247,185 +249,257 @@ function FloorMapEditPanel(props) {
247
249
  layoutTransformLocked: !sceneElement.layoutTransformLocked
248
250
  });
249
251
  };
250
- return /* @__PURE__ */ import_react.default.createElement("div", { className: (0, import_classnames.default)(`${PREFIX}-edit-panel`, className) }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-header` }, /* @__PURE__ */ import_react.default.createElement("span", null, ep.elementProps), /* @__PURE__ */ import_react.default.createElement(
251
- import_antd.Button,
252
- {
253
- type: "text",
254
- size: "small",
255
- className: `${PREFIX}-edit-panel-close`,
256
- icon: /* @__PURE__ */ import_react.default.createElement(import_icons.CloseOutlined, null),
257
- "aria-label": ep.closeAria,
258
- onClick: onClose
259
- }
260
- )), (formHasUnappliedChanges || layoutDraftDirty) && /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-hints`, role: "status" }, formHasUnappliedChanges ? /* @__PURE__ */ import_react.default.createElement("p", { className: `${PREFIX}-edit-panel-hint warn` }, ep.hintApply) : null, layoutDraftDirty ? /* @__PURE__ */ import_react.default.createElement("p", { className: `${PREFIX}-edit-panel-hint muted` }, ep.hintSave) : null), /* @__PURE__ */ import_react.default.createElement(
261
- import_antd.Form,
262
- {
263
- form,
264
- layout: "vertical",
265
- size: "small",
266
- onFinish: handleFinish,
267
- initialValues,
268
- onValuesChange: () => {
269
- if (skipFormValuesChangeRef.current) return;
270
- setFormHasUnappliedChanges(true);
252
+ const panelScrollRef = (0, import_react.useRef)(null);
253
+ const dragScrollRef = (0, import_react.useRef)({
254
+ active: false,
255
+ pointerId: -1,
256
+ startY: 0,
257
+ startScrollTop: 0
258
+ });
259
+ const isDragScrollSurface = (0, import_react.useCallback)((target) => {
260
+ if (!(target instanceof Element)) return false;
261
+ return !target.closest(
262
+ 'input,textarea,button,select,.ant-select,.ant-input,[contenteditable="true"]'
263
+ );
264
+ }, []);
265
+ const handlePanelPointerDown = (0, import_react.useCallback)(
266
+ (e) => {
267
+ if (!isDragScrollSurface(e.target)) return;
268
+ const el = panelScrollRef.current;
269
+ if (!el || el.scrollHeight <= el.clientHeight) return;
270
+ el.setPointerCapture(e.pointerId);
271
+ dragScrollRef.current = {
272
+ active: true,
273
+ pointerId: e.pointerId,
274
+ startY: e.clientY,
275
+ startScrollTop: el.scrollTop
276
+ };
277
+ },
278
+ [isDragScrollSurface]
279
+ );
280
+ const handlePanelPointerMove = (0, import_react.useCallback)(
281
+ (e) => {
282
+ const d = dragScrollRef.current;
283
+ if (!d.active || e.pointerId !== d.pointerId) return;
284
+ const el = panelScrollRef.current;
285
+ if (!el) return;
286
+ el.scrollTop = d.startScrollTop + (d.startY - e.clientY);
287
+ },
288
+ []
289
+ );
290
+ const endPanelDragScroll = (0, import_react.useCallback)(
291
+ (e) => {
292
+ var _a2;
293
+ const d = dragScrollRef.current;
294
+ if (!d.active || e.pointerId !== d.pointerId) return;
295
+ dragScrollRef.current = {
296
+ active: false,
297
+ pointerId: -1,
298
+ startY: 0,
299
+ startScrollTop: 0
300
+ };
301
+ try {
302
+ (_a2 = panelScrollRef.current) == null ? void 0 : _a2.releasePointerCapture(e.pointerId);
303
+ } catch {
271
304
  }
272
305
  },
273
- /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-layout-lock-header` }, /* @__PURE__ */ import_react.default.createElement("span", { className: `${PREFIX}-edit-panel-layout-lock-title` }, ep.sectionLayout), /* @__PURE__ */ import_react.default.createElement(
306
+ []
307
+ );
308
+ return /* @__PURE__ */ import_react.default.createElement(
309
+ "div",
310
+ {
311
+ ref: panelScrollRef,
312
+ className: (0, import_classnames.default)(`${PREFIX}-edit-panel`, className),
313
+ onPointerDown: handlePanelPointerDown,
314
+ onPointerMove: handlePanelPointerMove,
315
+ onPointerUp: endPanelDragScroll,
316
+ onPointerCancel: endPanelDragScroll
317
+ },
318
+ /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-header` }, /* @__PURE__ */ import_react.default.createElement("span", null, ep.elementProps), /* @__PURE__ */ import_react.default.createElement(
274
319
  import_antd.Button,
275
320
  {
276
321
  type: "text",
277
322
  size: "small",
278
- className: `${PREFIX}-edit-panel-layout-lock-btn`,
279
- icon: layoutLocked ? /* @__PURE__ */ import_react.default.createElement(import_icons.LockOutlined, null) : /* @__PURE__ */ import_react.default.createElement(import_icons.UnlockOutlined, null),
280
- "aria-pressed": layoutLocked,
281
- onClick: toggleLayoutLock,
282
- title: layoutLocked ? ep.lockOn : ep.lockOff
323
+ className: `${PREFIX}-edit-panel-close`,
324
+ icon: /* @__PURE__ */ import_react.default.createElement(import_icons.CloseOutlined, null),
325
+ "aria-label": ep.closeAria,
326
+ onClick: onClose
283
327
  }
284
328
  )),
285
- /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-xy-row` }, /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "x", label: ep.labelX }, /* @__PURE__ */ import_react.default.createElement(
286
- import_antd.InputNumber,
287
- {
288
- style: { width: "100%" },
289
- min: 0,
290
- disabled: layoutLocked
291
- }
292
- )), /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "y", label: ep.labelY }, /* @__PURE__ */ import_react.default.createElement(
293
- import_antd.InputNumber,
294
- {
295
- style: { width: "100%" },
296
- min: 0,
297
- disabled: layoutLocked
298
- }
299
- )), /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "zIndex", label: ep.labelZ }, /* @__PURE__ */ import_react.default.createElement(import_antd.InputNumber, { style: { width: "100%" }, disabled: layoutLocked }))),
300
- /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-size-row` }, /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "width", label: ep.labelWidth }, /* @__PURE__ */ import_react.default.createElement(
301
- import_antd.InputNumber,
302
- {
303
- style: { width: "100%" },
304
- min: 20,
305
- disabled: layoutLocked
306
- }
307
- )), /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "height", label: ep.labelHeight }, /* @__PURE__ */ import_react.default.createElement(
308
- import_antd.InputNumber,
309
- {
310
- style: { width: "100%" },
311
- min: 20,
312
- disabled: layoutLocked
313
- }
314
- ))),
329
+ (formHasUnappliedChanges || layoutDraftDirty) && /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-hints`, role: "status" }, formHasUnappliedChanges ? /* @__PURE__ */ import_react.default.createElement("p", { className: `${PREFIX}-edit-panel-hint warn` }, ep.hintApply) : null, layoutDraftDirty ? /* @__PURE__ */ import_react.default.createElement("p", { className: `${PREFIX}-edit-panel-hint muted` }, ep.hintSave) : null),
315
330
  /* @__PURE__ */ import_react.default.createElement(
316
- import_antd.Form.Item,
331
+ import_antd.Form,
317
332
  {
318
- name: "name",
319
- label: isStageLike ? ep.labelNameStage : ep.labelName
333
+ form,
334
+ layout: "vertical",
335
+ size: "small",
336
+ onFinish: handleFinish,
337
+ initialValues,
338
+ onValuesChange: () => {
339
+ if (skipFormValuesChangeRef.current) return;
340
+ setFormHasUnappliedChanges(true);
341
+ }
320
342
  },
343
+ /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-layout-lock-header` }, /* @__PURE__ */ import_react.default.createElement("span", { className: `${PREFIX}-edit-panel-layout-lock-title` }, ep.sectionLayout), /* @__PURE__ */ import_react.default.createElement(
344
+ import_antd.Button,
345
+ {
346
+ type: "text",
347
+ size: "small",
348
+ className: `${PREFIX}-edit-panel-layout-lock-btn`,
349
+ icon: layoutLocked ? /* @__PURE__ */ import_react.default.createElement(import_icons.LockOutlined, null) : /* @__PURE__ */ import_react.default.createElement(import_icons.UnlockOutlined, null),
350
+ "aria-pressed": layoutLocked,
351
+ onClick: toggleLayoutLock,
352
+ title: layoutLocked ? ep.lockOn : ep.lockOff
353
+ }
354
+ )),
355
+ /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-xy-row` }, /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "x", label: ep.labelX }, /* @__PURE__ */ import_react.default.createElement(
356
+ import_antd.InputNumber,
357
+ {
358
+ style: { width: "100%" },
359
+ min: 0,
360
+ disabled: layoutLocked
361
+ }
362
+ )), /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "y", label: ep.labelY }, /* @__PURE__ */ import_react.default.createElement(
363
+ import_antd.InputNumber,
364
+ {
365
+ style: { width: "100%" },
366
+ min: 0,
367
+ disabled: layoutLocked
368
+ }
369
+ )), /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "zIndex", label: ep.labelZ }, /* @__PURE__ */ import_react.default.createElement(import_antd.InputNumber, { style: { width: "100%" }, disabled: layoutLocked }))),
370
+ /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-size-row` }, /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "width", label: ep.labelWidth }, /* @__PURE__ */ import_react.default.createElement(
371
+ import_antd.InputNumber,
372
+ {
373
+ style: { width: "100%" },
374
+ min: 20,
375
+ disabled: layoutLocked
376
+ }
377
+ )), /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "height", label: ep.labelHeight }, /* @__PURE__ */ import_react.default.createElement(
378
+ import_antd.InputNumber,
379
+ {
380
+ style: { width: "100%" },
381
+ min: 20,
382
+ disabled: layoutLocked
383
+ }
384
+ ))),
321
385
  /* @__PURE__ */ import_react.default.createElement(
322
- import_antd.Input,
386
+ import_antd.Form.Item,
387
+ {
388
+ name: "name",
389
+ label: isStageLike ? ep.labelNameStage : ep.labelName
390
+ },
391
+ /* @__PURE__ */ import_react.default.createElement(
392
+ import_antd.Input,
393
+ {
394
+ placeholder: isStageLike ? ep.phNameStage : ep.phName,
395
+ allowClear: true
396
+ }
397
+ )
398
+ ),
399
+ isImageKind ? /* @__PURE__ */ import_react.default.createElement(
400
+ import_antd.Form.Item,
401
+ {
402
+ name: "imageUrl",
403
+ label: ep.labelImageUrl,
404
+ extra: ep.extraImageUrl
405
+ },
406
+ /* @__PURE__ */ import_react.default.createElement(import_antd.Input, { allowClear: true, placeholder: ep.phHttps })
407
+ ) : null,
408
+ /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "canvasId", label: ep.labelCanvas }, /* @__PURE__ */ import_react.default.createElement(
409
+ import_antd.Select,
323
410
  {
324
- placeholder: isStageLike ? ep.phNameStage : ep.phName,
325
- allowClear: true
411
+ options: canvasOptions.map((c) => ({
412
+ value: c.id,
413
+ label: (0, import_floorMapCanvasDisplay.getFloorMapCanvasDisplayName)(c, engineLocale)
414
+ })),
415
+ allowClear: false
326
416
  }
327
- )
417
+ )),
418
+ /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, null, /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { type: "primary", htmlType: "submit", size: "small" }, ep.apply))
328
419
  ),
329
- isImageKind ? /* @__PURE__ */ import_react.default.createElement(
330
- import_antd.Form.Item,
331
- {
332
- name: "imageUrl",
333
- label: ep.labelImageUrl,
334
- extra: ep.extraImageUrl
335
- },
336
- /* @__PURE__ */ import_react.default.createElement(import_antd.Input, { allowClear: true, placeholder: ep.phHttps })
337
- ) : null,
338
- /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, { name: "canvasId", label: ep.labelCanvas }, /* @__PURE__ */ import_react.default.createElement(
420
+ showDataBindingSection && /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-title` }, ep.dataBinding), /* @__PURE__ */ import_react.default.createElement("p", { className: `${PREFIX}-edit-panel-record-draft-note` }, ep.dataBindingNote), allowedKeys.length >= 1 ? /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-bind` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-bind-label` }, ep.labelDataSource), /* @__PURE__ */ import_react.default.createElement(
339
421
  import_antd.Select,
340
422
  {
341
- options: canvasOptions.map((c) => ({
342
- value: c.id,
343
- label: (0, import_floorMapCanvasDisplay.getFloorMapCanvasDisplayName)(c, engineLocale)
423
+ size: "small",
424
+ style: { width: "100%" },
425
+ placeholder: ep.phDataSource,
426
+ value: binding == null ? void 0 : binding.dataSourceKey,
427
+ options: allowedKeys.map((k) => ({
428
+ value: k,
429
+ label: dataSourceLabels[k] ?? k
344
430
  })),
345
- allowClear: false
431
+ onChange: (key) => {
432
+ if (!key && bindingPolicy === "optional") {
433
+ onUpdate({ dataBinding: void 0 });
434
+ return;
435
+ }
436
+ if (!key) return;
437
+ onUpdate({
438
+ dataBinding: {
439
+ dataSourceKey: key,
440
+ recordId: (binding == null ? void 0 : binding.dataSourceKey) === key ? binding.recordId : ""
441
+ }
442
+ });
443
+ },
444
+ allowClear: bindingPolicy === "optional"
346
445
  }
347
- )),
348
- /* @__PURE__ */ import_react.default.createElement(import_antd.Form.Item, null, /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { type: "primary", htmlType: "submit", size: "small" }, ep.apply))
349
- ), showDataBindingSection && /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-title` }, ep.dataBinding), /* @__PURE__ */ import_react.default.createElement("p", { className: `${PREFIX}-edit-panel-record-draft-note` }, ep.dataBindingNote), allowedKeys.length >= 1 ? /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-bind` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-bind-label` }, ep.labelDataSource), /* @__PURE__ */ import_react.default.createElement(
350
- import_antd.Select,
351
- {
352
- size: "small",
353
- style: { width: "100%" },
354
- placeholder: ep.phDataSource,
355
- value: binding == null ? void 0 : binding.dataSourceKey,
356
- options: allowedKeys.map((k) => ({
357
- value: k,
358
- label: dataSourceLabels[k] ?? k
359
- })),
360
- onChange: (key) => {
361
- if (!key && bindingPolicy === "optional") {
362
- onUpdate({ dataBinding: void 0 });
363
- return;
364
- }
365
- if (!key) return;
366
- onUpdate({
367
- dataBinding: {
368
- dataSourceKey: key,
369
- recordId: (binding == null ? void 0 : binding.dataSourceKey) === key ? binding.recordId : ""
446
+ )) : null, allowedKeys.length >= 1 && /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-bind` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-bind-label` }, ep.labelPickRow), /* @__PURE__ */ import_react.default.createElement(
447
+ import_antd.Select,
448
+ {
449
+ size: "small",
450
+ placeholder: dataRecordBindOptions.length ? ep.phPickRow : ep.phNoRows,
451
+ style: { width: "100%" },
452
+ value: hasBoundDataRecord ? binding == null ? void 0 : binding.recordId : void 0,
453
+ allowClear: bindingPolicy === "optional",
454
+ options: dataRecordBindOptions,
455
+ onChange: (newId) => {
456
+ const key = (binding == null ? void 0 : binding.dataSourceKey) ?? allowedKeys[0];
457
+ if (!key) return;
458
+ if (!newId) {
459
+ onUpdate({ dataBinding: void 0 });
460
+ return;
370
461
  }
371
- });
372
- },
373
- allowClear: bindingPolicy === "optional"
374
- }
375
- )) : null, allowedKeys.length >= 1 && /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-bind` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-bind-label` }, ep.labelPickRow), /* @__PURE__ */ import_react.default.createElement(
376
- import_antd.Select,
377
- {
378
- size: "small",
379
- placeholder: dataRecordBindOptions.length ? ep.phPickRow : ep.phNoRows,
380
- style: { width: "100%" },
381
- value: hasBoundDataRecord ? binding == null ? void 0 : binding.recordId : void 0,
382
- allowClear: bindingPolicy === "optional",
383
- options: dataRecordBindOptions,
384
- onChange: (newId) => {
385
- const key = (binding == null ? void 0 : binding.dataSourceKey) ?? allowedKeys[0];
386
- if (!key) return;
387
- if (!newId) {
388
- onUpdate({ dataBinding: void 0 });
389
- return;
462
+ const row = (dataSources[key] ?? []).find(
463
+ (r) => r.id === newId
464
+ );
465
+ onUpdate({
466
+ dataBinding: {
467
+ dataSourceKey: key,
468
+ recordId: newId
469
+ },
470
+ name: row ? String(row.name ?? newId) : void 0
471
+ });
390
472
  }
391
- const row = (dataSources[key] ?? []).find(
392
- (r) => r.id === newId
393
- );
394
- onUpdate({
395
- dataBinding: {
396
- dataSourceKey: key,
397
- recordId: newId
398
- },
399
- name: row ? String(row.name ?? newId) : void 0
400
- });
401
473
  }
402
- }
403
- ), !hasBoundDataRecord && /* @__PURE__ */ import_react.default.createElement("p", { className: `${PREFIX}-edit-panel-record-bind-hint` }, ep.hintUnbound))), showDataSourceRecordBlock && binding && /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-title` }, ep.recordTitle), hasCustomRecordForm && recordFormContext && recordFormSlotRaw != null ? /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-custom` }, resolveDataSourceRecordForm(
404
- recordFormSlotRaw,
405
- recordFormContext
406
- )) : null, !hasCustomRecordForm && onSaveRecord ? /* @__PURE__ */ import_react.default.createElement(
407
- import_FloorMapDataForm.FloorMapDataForm,
408
- {
409
- dataSourceKey: binding.dataSourceKey,
410
- recordId: binding.recordId,
411
- record,
412
- dataSources,
413
- onSave: onSaveRecord,
414
- saving: savingRecord,
415
- columns: recordFormColumns == null ? void 0 : recordFormColumns[binding.dataSourceKey]
416
- }
417
- ) : null), config.canvasUi.canEdit && onDelete ? /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-footer` }, /* @__PURE__ */ import_react.default.createElement(
418
- import_antd.Popconfirm,
419
- {
420
- title: ep.popTitle,
421
- description: ep.popDesc,
422
- onConfirm: onDelete,
423
- okText: ep.btnOkDelete,
424
- cancelText: ep.btnCancel,
425
- okButtonProps: { danger: true }
426
- },
427
- /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { type: "default", danger: true, block: true, size: "small" }, ep.btnDelete)
428
- )) : null);
474
+ ), !hasBoundDataRecord && /* @__PURE__ */ import_react.default.createElement("p", { className: `${PREFIX}-edit-panel-record-bind-hint` }, ep.hintUnbound))),
475
+ showDataRecordEditorSection && binding && /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-title` }, ep.recordTitle), hasCustomRecordForm && recordFormContext && recordFormSlotRaw != null ? /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-record-custom` }, resolveDataSourceRecordForm(
476
+ recordFormSlotRaw,
477
+ recordFormContext
478
+ )) : null, !hasCustomRecordForm && onSaveRecord ? /* @__PURE__ */ import_react.default.createElement(
479
+ import_FloorMapDataForm.FloorMapDataForm,
480
+ {
481
+ dataSourceKey: binding.dataSourceKey,
482
+ recordId: binding.recordId,
483
+ record,
484
+ dataSources,
485
+ onSave: onSaveRecord,
486
+ saving: savingRecord,
487
+ columns: recordFormColumns == null ? void 0 : recordFormColumns[binding.dataSourceKey]
488
+ }
489
+ ) : null),
490
+ config.canvasUi.canEdit && onDelete ? /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-edit-panel-footer` }, /* @__PURE__ */ import_react.default.createElement(
491
+ import_antd.Popconfirm,
492
+ {
493
+ title: ep.popTitle,
494
+ description: ep.popDesc,
495
+ onConfirm: onDelete,
496
+ okText: ep.btnOkDelete,
497
+ cancelText: ep.btnCancel,
498
+ okButtonProps: { danger: true }
499
+ },
500
+ /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { type: "default", danger: true, block: true, size: "small" }, ep.btnDelete)
501
+ )) : null
502
+ );
429
503
  }
430
504
  var FloorMapEditPanel_default = FloorMapEditPanel;
431
505
  // Annotate the CommonJS export names for ESM import in node:
@@ -7,6 +7,7 @@
7
7
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
8
8
  max-height: 80vh;
9
9
  overflow-y: auto;
10
+ touch-action: pan-y;
10
11
 
11
12
  &-header {
12
13
  display: flex;
@@ -37,7 +37,8 @@ function mergeFloorMapLayoutPropsFromContext(props, ctx) {
37
37
  saveError: props.saveError ?? ctx.saveError,
38
38
  onElementRenderError: props.onElementRenderError ?? ctx.onElementRenderError,
39
39
  toolbarShowSave: props.toolbarShowSave ?? ctx.toolbarShowSave,
40
- floorMapFullscreenMode: props.floorMapFullscreenMode ?? ctx.floorMapFullscreenMode
40
+ floorMapFullscreenMode: props.floorMapFullscreenMode ?? ctx.floorMapFullscreenMode,
41
+ showDataSourceRecordFormBlock: props.showDataSourceRecordFormBlock ?? ctx.showDataSourceRecordFormBlock
41
42
  };
42
43
  }
43
44
  // Annotate the CommonJS export names for ESM import in node:
@@ -16,6 +16,7 @@ export interface UseFloorMapEditStateParams<T extends FloorMapItemBase> {
16
16
  x: number;
17
17
  y: number;
18
18
  }>;
19
+ showDataSourceRecordFormBlock?: boolean;
19
20
  }
20
21
  export declare function useFloorMapEditState<T extends FloorMapItemBase>(params: UseFloorMapEditStateParams<T>): {
21
22
  config: FloorMapViewConfig | null;
@@ -54,6 +55,7 @@ export declare function useFloorMapEditState<T extends FloorMapItemBase>(params:
54
55
  dataSourceRecordForm: Record<string, FloorMapDataSourceRecordFormContent> | undefined;
55
56
  dataSourceLabels: Record<string, string> | undefined;
56
57
  layoutDraftDirty: boolean;
58
+ showDataSourceRecordFormBlock: boolean | undefined;
57
59
  } | null;
58
60
  placeOverlayClass: string;
59
61
  isLayoutDirty: boolean;
@@ -70,7 +70,8 @@ function useFloorMapEditState(params) {
70
70
  dataSourceRecordForm,
71
71
  dataSourceLabels,
72
72
  layoutPrefix,
73
- contentOffsetRef
73
+ contentOffsetRef,
74
+ showDataSourceRecordFormBlock
74
75
  } = params;
75
76
  const engineCtx = (0, import_useEngineContext.default)();
76
77
  const engineLocale = ((_b = (_a = engineCtx == null ? void 0 : engineCtx.engine) == null ? void 0 : _a.props) == null ? void 0 : _b.locale) || "zh-CN";
@@ -397,7 +398,8 @@ function useFloorMapEditState(params) {
397
398
  recordFormColumns: dataSourceFormColumns,
398
399
  dataSourceRecordForm,
399
400
  dataSourceLabels,
400
- layoutDraftDirty: isLayoutDirty
401
+ layoutDraftDirty: isLayoutDirty,
402
+ showDataSourceRecordFormBlock
401
403
  } : null;
402
404
  return {
403
405
  config,
@@ -65,6 +65,7 @@ function useFloorMapTransformMetrics(params) {
65
65
  setMapAreaSize({ width: el.clientWidth, height: el.clientHeight });
66
66
  return () => ro.disconnect();
67
67
  }, []);
68
+ const autoFitOnMount = zoom.autoFitOnMount === true;
68
69
  const zoomConfig = (0, import_react.useMemo)(
69
70
  () => ({
70
71
  initialScale: zoom.defaultScale ?? 1,
@@ -149,6 +150,10 @@ function useFloorMapTransformMetrics(params) {
149
150
  if (initialAlignRef.current.frame !== frameResetKey) {
150
151
  initialAlignRef.current = { frame: frameResetKey, done: false };
151
152
  }
153
+ if (autoFitOnMount) {
154
+ initialAlignRef.current.done = true;
155
+ return;
156
+ }
152
157
  if (alignPadSingle == null) {
153
158
  initialAlignRef.current.done = false;
154
159
  return;
@@ -182,7 +187,8 @@ function useFloorMapTransformMetrics(params) {
182
187
  initialPositionX,
183
188
  initialPositionY,
184
189
  zoomConfig.initialScale,
185
- transformRef
190
+ transformRef,
191
+ autoFitOnMount
186
192
  ]);
187
193
  (0, import_react.useEffect)(() => {
188
194
  const el = containerRef.current;
@@ -218,6 +224,46 @@ function useFloorMapTransformMetrics(params) {
218
224
  const y = VIEWPORT_TOP_LEFT_MARGIN - padA * nextScale;
219
225
  ctx.setTransform(x, y, nextScale);
220
226
  }, [contentWidth, contentHeight, zoom.max, transformRef, alignPadSingle]);
227
+ const autoFitOnceRef = (0, import_react.useRef)({
228
+ frame: "",
229
+ done: false
230
+ });
231
+ (0, import_react.useEffect)(() => {
232
+ if (!isFloorMapView || !autoFitOnMount || frameResetKey === void 0)
233
+ return;
234
+ const frame = String(frameResetKey);
235
+ if (autoFitOnceRef.current.frame !== frame) {
236
+ autoFitOnceRef.current = { frame, done: false };
237
+ }
238
+ if (autoFitOnceRef.current.done) return;
239
+ if (contentWidth <= 0 || contentHeight <= 0) return;
240
+ let cancelled = false;
241
+ let raf = 0;
242
+ const tick = () => {
243
+ if (cancelled) return;
244
+ const ctx = transformRef.current;
245
+ const container = containerRef.current;
246
+ if (!ctx || !(container == null ? void 0 : container.querySelector(".react-transform-wrapper"))) {
247
+ raf = requestAnimationFrame(tick);
248
+ return;
249
+ }
250
+ fitBounds();
251
+ autoFitOnceRef.current.done = true;
252
+ };
253
+ raf = requestAnimationFrame(tick);
254
+ return () => {
255
+ cancelled = true;
256
+ cancelAnimationFrame(raf);
257
+ };
258
+ }, [
259
+ isFloorMapView,
260
+ autoFitOnMount,
261
+ frameResetKey,
262
+ contentWidth,
263
+ contentHeight,
264
+ fitBounds,
265
+ transformRef
266
+ ]);
221
267
  const lastTransformRef = (0, import_react.useRef)({ x: 0, y: 0, scale: 1 });
222
268
  const [isInteractingWithElement, setIsInteractingWithElement] = (0, import_react.useState)(false);
223
269
  const prevInteractingRef = (0, import_react.useRef)(false);
@@ -81,6 +81,11 @@ export interface FloorMapZoomConfig {
81
81
  max?: number;
82
82
  /** 缩放步进,默认 0.1 (10%) */
83
83
  step?: number;
84
+ /**
85
+ * 为 true 时:挂载后每个画布(frameResetKey)自动执行一次 fitBounds,使图元落在视口内。
86
+ * 为 true 时跳过「首帧 defaultScale 左上对齐」,避免与 fit 闪动叠加。
87
+ */
88
+ autoFitOnMount?: boolean;
84
89
  }
85
90
  /**
86
91
  * 平移配置
@@ -377,6 +382,11 @@ export interface FloorMapEditPanelParams {
377
382
  * 用于提示用户点击顶部「保存」持久化布局草稿。
378
383
  */
379
384
  layoutDraftDirty?: boolean;
385
+ /**
386
+ * 为 false 时不渲染「数据绑定」下方的数据源记录编辑表单(FloorMapDataForm / 自定义 record 表单);
387
+ * 数据绑定选数据源与选行仍可展示。
388
+ */
389
+ showDataSourceRecordFormBlock?: boolean;
380
390
  }
381
391
  /**
382
392
  * 合并当前画布的 sceneElements 为 items(用于 Layout 渲染)
@@ -400,7 +410,7 @@ export declare type FloorMapFullscreenMode = 'toggle' | 'locked' | 'disabled';
400
410
  * 平面图 Layout 注入上下文:数据、保存、侧栏表单与状态等(不包含 renderItem/mapLayer 等展示向 props)。
401
411
  * 由 `FloorMapLayoutProvider` / RecordBoard `floorMapLayoutContext` 提供,与 `PisellFloorMapLayout` props 按 `??` 合并,props 优先。
402
412
  */
403
- export declare type FloorMapLayoutContextValue = Partial<Pick<PisellFloorMapLayoutProps<FloorMapItemBase>, 'floorMapConfig' | 'dataSources' | 'onSave' | 'onDataSourceRecordSave' | 'dataSourceLabels' | 'dataSourceFormColumns' | 'dataSourceRecordForm' | 'loading' | 'saveError' | 'onElementRenderError' | 'toolbarShowSave' | 'floorMapFullscreenMode'>>;
413
+ export declare type FloorMapLayoutContextValue = Partial<Pick<PisellFloorMapLayoutProps<FloorMapItemBase>, 'floorMapConfig' | 'dataSources' | 'onSave' | 'onDataSourceRecordSave' | 'dataSourceLabels' | 'dataSourceFormColumns' | 'dataSourceRecordForm' | 'loading' | 'saveError' | 'onElementRenderError' | 'toolbarShowSave' | 'floorMapFullscreenMode' | 'showDataSourceRecordFormBlock'>>;
404
414
  /**
405
415
  * PisellFloorMapLayout 组件 Props
406
416
  * @template T - 资源项类型,需继承 FloorMapItemBase 或兼容 id/x/y
@@ -527,6 +537,10 @@ export interface PisellFloorMapLayoutProps<T extends FloorMapItemBase = FloorMap
527
537
  * 是否在左侧工具栏底部显示「保存」(默认 true;非全屏时顶栏为 Tab+全屏,保存多在侧栏;全屏时保存仅在顶栏)
528
538
  */
529
539
  toolbarShowSave?: boolean;
540
+ /**
541
+ * 为 false 时隐藏侧栏「数据源记录」表单区(保留数据绑定选源/选行)。
542
+ */
543
+ showDataSourceRecordFormBlock?: boolean;
530
544
  }
531
545
  /**
532
546
  * PisellFloorMapLayout Ref 方法
@@ -541,4 +555,6 @@ export interface PisellFloorMapLayoutRef {
541
555
  reset: () => void;
542
556
  /** 区域定位:使所有 items 落在视口内 */
543
557
  fitBounds: () => void;
558
+ /** 提交当前布局草稿(与顶栏/侧栏「保存」一致) */
559
+ saveLayout: () => void;
544
560
  }