@mx-sose-front/mx-sose-graph 1.1.0 → 1.1.2

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.
@@ -172,8 +172,8 @@ const shapeStyle = computed<CSSProperties>(() => {
172
172
  width = Math.max(estimatedTextWidth.value, width);
173
173
  }
174
174
 
175
- // 最小高度限制为70px
176
- const minHeight = 70;
175
+ // 最小高度限制为60px
176
+ const minHeight = 60;
177
177
  const height = Math.max(bounds.height || 40, minHeight);
178
178
 
179
179
  return {
@@ -189,8 +189,8 @@ const updateShapeBounds = async () => {
189
189
 
190
190
  const requiredWidth = estimatedTextWidth.value;
191
191
  const currentWidth = props.shape.bounds.width || 100;
192
- // 最小高度限制为70px
193
- const minHeight = 70;
192
+ // 最小高度限制为60px
193
+ const minHeight = 60;
194
194
  const currentHeight = props.shape.bounds.height || 40;
195
195
  const requiredHeight = Math.max(currentHeight, minHeight);
196
196
 
@@ -249,9 +249,9 @@ const vbW = computed(() => props.shape.bounds.width || 100)
249
249
  const vbH = computed(() => props.shape.bounds.height || 40)
250
250
  // ================== 监听 bounds 宽高变化 ==================
251
251
 
252
- // 原始宽高(150 x 70
252
+ // 原始宽高(150 x 60
253
253
  const DEFAULT_WIDTH = 150
254
- const DEFAULT_HEIGHT = 70
254
+ const DEFAULT_HEIGHT = 60
255
255
 
256
256
  // 记录上一次的宽高,用来做去重判断
257
257
  const lastBounds = ref({
@@ -268,7 +268,7 @@ watch(
268
268
  () => [props.shape.bounds.width, props.shape.bounds.height],
269
269
  ([newW, newH]) => {
270
270
  if (isGhost.value) return
271
- // 宽高兜底到默认值(150 x 70
271
+ // 宽高兜底到默认值(150 x 60
272
272
  const width = newW ?? DEFAULT_WIDTH
273
273
  const height = newH ?? DEFAULT_HEIGHT
274
274
 
@@ -281,7 +281,7 @@ watch(
281
281
  }
282
282
  // 更新“上一次”的记录
283
283
  lastBounds.value = { width, height }
284
- // 只有当宽高不再是原始 150 x 70 时才认为“真的变化”,再去调用其他方法
284
+ // 只有当宽高不再是原始 150 x 60 时才认为“真的变化”,再去调用其他方法
285
285
  if (
286
286
  width !== DEFAULT_WIDTH || height !== DEFAULT_HEIGHT
287
287
 
@@ -0,0 +1,229 @@
1
+ <template>
2
+ <div class="zoom-bar">
3
+ <button @click="handleZoomOut" class="zoom-button zoom-out">-</button>
4
+ <div class="zoom-slider">
5
+ <div class="slider-wrapper" :style="{ '--progress': `${((modelValue - min) / (max - min)) * 100}%` }">
6
+ <input
7
+ type="range"
8
+ :min="min"
9
+ :max="max"
10
+ :step="step"
11
+ v-model="internalValue"
12
+ @input="handleZoomChange"
13
+ />
14
+ </div>
15
+ </div>
16
+ <button @click="handleZoomIn" class="zoom-button zoom-in">+</button>
17
+ <div class="zoom-level">{{ Math.round(internalValue * 100) }}%</div>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { ref, watch } from 'vue'
23
+
24
+ interface Props {
25
+ modelValue: number
26
+ min?: number
27
+ max?: number
28
+ step?: number
29
+ onZoomIn?: () => void
30
+ onZoomOut?: () => void
31
+ onScaleChange?: (scale: number) => void
32
+ }
33
+
34
+ const props = withDefaults(defineProps<Props>(), {
35
+ min: 0.1,
36
+ max: 3,
37
+ step: 0.1
38
+ })
39
+
40
+ const emit = defineEmits<{
41
+ 'update:modelValue': [value: number]
42
+ 'zoom-in': []
43
+ 'zoom-out': []
44
+ 'scale-change': [scale: number]
45
+ }>()
46
+
47
+ // 内部值,用于双向绑定滑块
48
+ const internalValue = ref(props.modelValue)
49
+
50
+ // 监听props变化,更新内部值
51
+ watch(() => props.modelValue, (newValue) => {
52
+ internalValue.value = newValue
53
+ })
54
+
55
+ // 监听内部值变化,emit事件
56
+ watch(internalValue, (newValue) => {
57
+ emit('update:modelValue', newValue)
58
+ })
59
+
60
+ // 处理缩放滑块变化
61
+ const handleZoomChange = () => {
62
+ emit('scale-change', internalValue.value)
63
+ emit('update:modelValue', internalValue.value)
64
+ }
65
+
66
+ // 处理放大按钮点击
67
+ const handleZoomIn = () => {
68
+ const newValue = Math.min(internalValue.value + props.step, props.max)
69
+ internalValue.value = newValue
70
+ emit('zoom-in')
71
+ emit('update:modelValue', newValue)
72
+ }
73
+
74
+ // 处理缩小按钮点击
75
+ const handleZoomOut = () => {
76
+ const newValue = Math.max(internalValue.value - props.step, props.min)
77
+ internalValue.value = newValue
78
+ emit('zoom-out')
79
+ emit('update:modelValue', newValue)
80
+ }
81
+ </script>
82
+
83
+ <style scoped>
84
+ .zoom-bar {
85
+ position: absolute;
86
+ bottom: 0;
87
+ left: 0;
88
+ width: 100%;
89
+ height: 24px;
90
+ display: flex;
91
+ align-items: center;
92
+ justify-content: flex-end;
93
+ background: white;
94
+ border-top: 1px solid #e0e0e0;
95
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
96
+ z-index: 100;
97
+ gap: 6px;
98
+ padding: 0 10px;
99
+ }
100
+
101
+ .zoom-level {
102
+ font-size: 10px;
103
+ font-weight: 500;
104
+ min-width: 35px;
105
+ text-align: center;
106
+ color: #333;
107
+ }
108
+
109
+ .zoom-button {
110
+ width: 18px;
111
+ height: 18px;
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ border: 1px solid #e0e0e0;
116
+ border-radius: 2px;
117
+ background: white;
118
+ cursor: pointer;
119
+ font-size: 10px;
120
+ font-weight: 600;
121
+ color: #333;
122
+ transition: all 0.2s;
123
+ user-select: none;
124
+ }
125
+
126
+ .zoom-button:hover {
127
+ background: #f5f5f5;
128
+ border-color: #2a7fd9;
129
+ color: #2a7fd9;
130
+ }
131
+
132
+ .zoom-button:active {
133
+ transform: scale(0.95);
134
+ }
135
+
136
+ .zoom-slider {
137
+ width: 150px;
138
+ height: 100%;
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: center;
142
+ position: relative;
143
+ }
144
+
145
+ .slider-wrapper {
146
+ width: 100%;
147
+ height: 2px;
148
+ background: #e0e0e0;
149
+ border-radius: 1px;
150
+ position: relative;
151
+ }
152
+
153
+ .slider-wrapper::before {
154
+ content: '';
155
+ position: absolute;
156
+ top: 50%;
157
+ left: 0;
158
+ width: var(--progress, 0%);
159
+ height: 2px;
160
+ background: #2a7fd9;
161
+ border-radius: 1px;
162
+ z-index: 1;
163
+ pointer-events: none;
164
+ transform: translateY(-50%);
165
+ }
166
+
167
+ .slider-wrapper input[type="range"] {
168
+ width: 100%;
169
+ height: 12px;
170
+ background: transparent;
171
+ outline: none;
172
+ -webkit-appearance: none;
173
+ margin: 0;
174
+ position: relative;
175
+ z-index: 2;
176
+ cursor: pointer;
177
+ }
178
+
179
+ /* WebKit浏览器滑块样式 */
180
+ .slider-wrapper input[type="range"]::-webkit-slider-thumb {
181
+ -webkit-appearance: none;
182
+ appearance: none;
183
+ width: 12px;
184
+ height: 12px;
185
+ border-radius: 50%;
186
+ background: white;
187
+ border: 2px solid #2a7fd9;
188
+ cursor: pointer;
189
+ transition: all 0.2s;
190
+ transform: translateY(-6px);
191
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
192
+ }
193
+
194
+ .slider-wrapper input[type="range"]::-webkit-slider-thumb:hover {
195
+ background: white;
196
+ border-color: #2a7fd9;
197
+ transform: translateY(-6px) scale(1.1);
198
+ }
199
+
200
+ /* Mozilla浏览器滑块样式 */
201
+ .slider-wrapper input[type="range"]::-moz-range-thumb {
202
+ width: 12px;
203
+ height: 12px;
204
+ border-radius: 50%;
205
+ background: white;
206
+ border: 2px solid #2a7fd9;
207
+ cursor: pointer;
208
+ transition: all 0.2s;
209
+ transform: translateY(-6px);
210
+ }
211
+
212
+ .slider-wrapper input[type="range"]::-moz-range-thumb:hover {
213
+ background: white;
214
+ border-color: #2a7fd9;
215
+ transform: translateY(-6px) scale(1.1);
216
+ }
217
+
218
+ /* Firefox滑块轨道样式 */
219
+ .slider-wrapper input[type="range"]::-moz-range-track {
220
+ background: transparent;
221
+ height: 2px;
222
+ border: none;
223
+ }
224
+
225
+ /* 移除聚焦时的默认样式 */
226
+ .slider-wrapper input[type="range"]:focus {
227
+ outline: none;
228
+ }
229
+ </style>
@@ -201,6 +201,9 @@ export const BlockKeyMap = {
201
201
  'ActualResponsibility': 'Block',//实际责任
202
202
  'System': 'Block',//系统
203
203
  'Competence': 'Block',//权限
204
+ 'Person': 'Block',//人员
205
+ 'SecurityProcess': 'Block',//安全流程
206
+ 'ResourceMitigation': 'Block', // 资源缓解措施
204
207
 
205
208
  // 线
206
209
  'Association': 'Edge', //双向关联
@@ -228,6 +231,7 @@ export const BlockKeyMap = {
228
231
  'FunctionControlFlow':'Edge',//功能控制流
229
232
  'ServiceConnector':'Edge',//服务连接器
230
233
  'ServiceControlFlow':'Edge',//服务控制流
234
+ "ServiceObjectFlow": 'Edge', // 服务对象流
231
235
  'Connector':'Edge',//连接器
232
236
  'OperationalConnector':'Edge',//业务连接器
233
237
  'IsCapableToPerform':'Edge',//能够胜任
@@ -321,6 +325,14 @@ export const BlockKeyMap = {
321
325
  // 导出类型
322
326
  export type ShapeKeyValue = typeof BlockKeyMap[keyof typeof BlockKeyMap]
323
327
 
328
+ // 四个角手柄常量
329
+ export const resizeHandles: { position: "nw" | "ne" | "sw" | "se" }[] = [
330
+ { position: "nw" },
331
+ { position: "ne" },
332
+ { position: "sw" },
333
+ { position: "se" },
334
+ ]
335
+
324
336
  // 只包含图类型的映射
325
337
  export const DiagramKeyMap = {
326
338
  'StrategicTaxonomyDiagram': 'StrategicTaxonomyDiagram', //战略概念图
@@ -20,6 +20,7 @@ import {
20
20
  } from '../utils/compartment'
21
21
  import { EdgeUtils } from '../utils/edgeUtils'
22
22
  import { expandParentByChild } from '../utils/autoExpandParent'
23
+ import { adjustCanvasToFitAllShapes } from '../utils/diagram'
23
24
  import { applyReparentAndClone, autoExpandMovedCompartmentsAfterDrag, buildDragEndPayloads, buildPrevParentMap, collectAffectedShapeIds, createOnNestDoneCallback } from '../utils/graphDragService'
24
25
  type Rect = { x: number; y: number; width: number; height: number };
25
26
  export const useGraphStore = defineStore('graph', () => {
@@ -52,6 +53,8 @@ export const useGraphStore = defineStore('graph', () => {
52
53
  const groupBaseBox = ref<Rect | null>(null)
53
54
  // 指针相对图元左上角的偏移,用于保持拖动时鼠标与元素的相对位置
54
55
  const dragOffset = ref<{ x: number; y: number } | null>(null)
56
+ // 拖拽开始时的画布尺寸快照
57
+ const dragBaseCanvasSize = ref<{ width: number; height: number } | null>(null)
55
58
  //当前打开画布的列表
56
59
  const diagrams = ref<Shape[]>([])
57
60
  //当前打开的画布id
@@ -71,8 +74,11 @@ export const useGraphStore = defineStore('graph', () => {
71
74
  const packagesTypes = ref<string[]>([]) // 需要展示线的隔间组件的图元类型
72
75
  const classMetaTypes = ref<string[]>([]) //可以生成的class类型
73
76
  const ownerRequiredShapeKeys = ref<string[]>([])//哪些图元需要自动补 ownerId
74
- const pinsTypes=ref<string[]>([])//栓类型
77
+ const pinsTypes = ref<string[]>([])//栓类型
75
78
  const portsTypes = ref<string[]>([])//端口类型
79
+ const museInGraphView = ref<boolean>(false) //是否鼠标在图元区域
80
+ const canOperate = ref<boolean>(false)//license是否允许操作
81
+ const connectMode = ref<string>('connect')
76
82
  // 方法
77
83
  /**
78
84
  * 添加图元
@@ -259,6 +265,14 @@ export const useGraphStore = defineStore('graph', () => {
259
265
  }
260
266
  // 清空选择
261
267
  const clearSelection = () => selectShape(null)
268
+ // 全选图元
269
+ const selectAll = () => {
270
+ // 获取所有非diagram类型的图元
271
+ const allShapeIds = shapes.value
272
+ .filter(shape => shape.shapeType?.toLowerCase() !== 'diagram')
273
+ .map(shape => shape.id)
274
+ selectMany(allShapeIds)
275
+ }
262
276
  // 设置图表标题
263
277
  const setTitle = (title: string) => {
264
278
  diagramTitle.value = title
@@ -340,6 +354,16 @@ export const useGraphStore = defineStore('graph', () => {
340
354
  for (const k in snap.dragBase) dragGhost[k] = snap.dragBase[k] // 写入新 key
341
355
  draggingIds.value = validIds
342
356
  dragAnchor.value = { x: pointer.x, y: pointer.y }
357
+
358
+ const currentDiagram = shapes.value.find(s => s.shapeType === 'diagram')
359
+ if (currentDiagram) {
360
+ dragBaseCanvasSize.value = {
361
+ width: currentDiagram.bounds.width ?? 0,
362
+ height: currentDiagram.bounds.height ?? 0
363
+ }
364
+ } else {
365
+ dragBaseCanvasSize.value = null
366
+ }
343
367
  if (validIds.length === 1) {
344
368
  const b = dragBase.value[validIds[0]]
345
369
  dragOffset.value = { x: pointer.x - b.x, y: pointer.y - b.y }
@@ -444,7 +468,7 @@ export const useGraphStore = defineStore('graph', () => {
444
468
  }
445
469
  }
446
470
  //拖动过程中
447
- const moveDraggedShape = (pointer: { x: number; y: number }) => {
471
+ const moveDraggedShape = async (pointer: { x: number; y: number }) => {
448
472
  if (!isDragging.value || draggingIds.value.length === 0) return
449
473
 
450
474
  if (draggingIds.value.length === 1) {
@@ -576,6 +600,23 @@ export const useGraphStore = defineStore('graph', () => {
576
600
  updateShape,
577
601
  })
578
602
 
603
+ // 先同步调整画布大小,确保获取到最新的画布数据
604
+ adjustCanvasToFitAllShapes()
605
+
606
+ // 检查画布宽高是否有变化
607
+ if (dragBaseCanvasSize.value) {
608
+ const currentDiagram = shapes.value.find(s => s.shapeType === 'diagram')
609
+ if (currentDiagram) {
610
+ const currentWidth = currentDiagram.bounds.width
611
+ const currentHeight = currentDiagram.bounds.height
612
+ const { width: baseWidth, height: baseHeight } = dragBaseCanvasSize.value
613
+ if (currentWidth !== baseWidth || currentHeight !== baseHeight) {
614
+ const diagramPayload = _.cloneDeep(currentDiagram)
615
+ payloads.push(diagramPayload)
616
+ }
617
+ }
618
+ }
619
+
579
620
  //对外只暴露一个事件:shape-drag-end
580
621
  eventBus.emit('shape-drag-end', payloads, ownerPayload, onNestDone)
581
622
 
@@ -638,6 +679,7 @@ export const useGraphStore = defineStore('graph', () => {
638
679
  groupBaseBox.value = null
639
680
  dragSelectionSnapshot.value = []
640
681
  primaryDragId.value = null
682
+ dragBaseCanvasSize.value = null
641
683
  for (const k in dragGhost) delete dragGhost[k]
642
684
  }
643
685
  //设置当前打开的画布id
@@ -647,6 +689,14 @@ export const useGraphStore = defineStore('graph', () => {
647
689
  const setActiveDiagramId = (id: string | null) => {
648
690
  activeDiagramId.value = id;
649
691
  };
692
+ // 设置当前连线的模式
693
+ const setConnectMode = (mode: string) => {
694
+ connectMode.value = mode
695
+ }
696
+ // 获取当前连线的模式
697
+ const getConnectMode = () => {
698
+ return connectMode.value
699
+ }
650
700
  // 获取当前缩放比例
651
701
  const getScale = (diagramId?: string | null) => {
652
702
  const targetId = diagramId || activeDiagramId.value;
@@ -682,37 +732,56 @@ export const useGraphStore = defineStore('graph', () => {
682
732
  * - 内部调用 expandParentByChild → 得到 expanded / affectedIds
683
733
  * - 若有扩父,再组装 sizePayload 并发 shape-size-update 事件
684
734
  */
685
- const expandParentAndEmitSizeUpdateByChild = (child: Shape) => {
686
- if (!child.parenShapeId) {
687
- return
735
+ const collectAncestors = (shapes: Shape[], id: string) => {
736
+ const out: string[] = []
737
+ let cur = shapes.find(s => s.id === id)
738
+ while (cur) {
739
+ out.push(cur.id)
740
+ const pid = cur.parenShapeId
741
+ if (!pid) break
742
+ cur = shapes.find(s => s.id === pid)
688
743
  }
689
- if (pinsTypes.value.includes(child.shapeKey)) return
690
- const { expanded, affectedIds } = expandParentByChild({
744
+ return out
745
+ }
746
+
747
+ const expandParentAndEmitSizeUpdateByChild = (child: Shape) => {
748
+ if (!child.parenShapeId) return
749
+ if (pinsTypes.value.includes(child.shapeKey)) return
750
+
751
+ const parentId = child.parenShapeId
752
+ const chainIds = collectAncestors(shapes.value, parentId)
753
+
754
+ // before 快照(只对父链)
755
+ const before = new Map(
756
+ chainIds.map(id => [
757
+ id,
758
+ JSON.stringify(shapes.value.find(s => s.id === id)?.bounds ?? {}),
759
+ ]),
760
+ )
761
+
762
+ const { expanded } = expandParentByChild({
691
763
  shapes: shapes.value,
692
764
  child,
693
765
  updateShape,
694
766
  })
695
-
696
767
  if (!expanded) return
697
768
 
698
- const childId = child.id
699
-
700
- // 组装“只更新大小”的 payload:id + JSON.stringify(bounds)
701
- const sizePayload: ShapeSizeUpdatePayload[] = affectedIds
769
+ const payload: ShapeSizeUpdatePayload[] = chainIds
770
+ .filter(id => id !== child.id)
702
771
  .map(id => shapes.value.find(s => s.id === id))
703
772
  .filter((s): s is Shape => !!s)
704
- // 过滤掉子元素本身,只把真正扩父的父/祖先发给接口
705
- .filter(s => s.id !== childId)
706
- .map(s => ({
707
- id: s.id,
708
- bounds: JSON.stringify(s.bounds ?? {}),
709
- }))
773
+ .filter(s => before.get(s.id) !== JSON.stringify(s.bounds ?? {})) // diff
774
+ .map(s => ({ id: s.id, bounds: JSON.stringify(s.bounds ?? {}) }))
710
775
 
711
- if (!sizePayload.length) return
776
+ if (!payload.length) return
777
+ // eventBus.emit('shape-size-update', payload)
778
+ }
712
779
 
713
- // 发事件给统一监听,监听里再去调用 updateShapeSize(单条接口就 for 循环)
714
- eventBus.emit('shape-size-update', sizePayload)
780
+ // 设置鼠标是否在图元区域
781
+ const setIsMouseInGraphView = (isIn: boolean) => {
782
+ museInGraphView.value = isIn
715
783
  }
784
+
716
785
  return {
717
786
  // 状态
718
787
  shapes,
@@ -726,6 +795,7 @@ export const useGraphStore = defineStore('graph', () => {
726
795
  hoverNestable,
727
796
  currentDiagramId,
728
797
  canDropOnCanvas,
798
+ canOperate,
729
799
  //图元shapeKey
730
800
  taggedValueLabels,
731
801
  packagesTypes,
@@ -742,6 +812,9 @@ export const useGraphStore = defineStore('graph', () => {
742
812
  activeDiagramId,
743
813
  // 当前活动画布的缩放比例
744
814
  currentScale: computed(() => getScale()),
815
+ museInGraphView,
816
+ connectMode,
817
+
745
818
  // 方法
746
819
  addShape,
747
820
  removeShape,
@@ -759,6 +832,7 @@ export const useGraphStore = defineStore('graph', () => {
759
832
  setCurrentDiagramId,
760
833
  selectMany,
761
834
  clearSelection,
835
+ selectAll,
762
836
  removeSelected,
763
837
  finalCheckCanNest,
764
838
  setHoverState,
@@ -767,9 +841,12 @@ export const useGraphStore = defineStore('graph', () => {
767
841
  getScale,
768
842
  setScale,
769
843
  setActiveDiagramId,
844
+ setConnectMode,
845
+ getConnectMode,
770
846
  visibleShapes,
771
847
  externalCreatingId,
772
848
  expandParentAndEmitSizeUpdateByChild,
849
+ setIsMouseInGraphView,
773
850
  }
774
851
  },
775
852
  //配置持久化
@@ -5,6 +5,8 @@ export interface Bounds {
5
5
  width?: number | undefined
6
6
  height?: number | undefined
7
7
  }
8
+
9
+ export type Rect = { x: number; y: number; width: number; height: number };
8
10
  export type Padding = number | { top: number; right: number; bottom: number; left: number };
9
11
  // 样式接口
10
12
  export interface Style {
@@ -197,4 +199,15 @@ export interface CheckNested {
197
199
  export interface ShapeSizeUpdatePayload {
198
200
  id: string
199
201
  bounds: string // JSON string
200
- }
202
+ }
203
+
204
+ // 所在图表列表
205
+ export interface locationChart {
206
+ modelCode: string //图表图标名称
207
+ treeId: string
208
+ modelName: string //图表名称
209
+ }
210
+
211
+ // InteractionLayer types
212
+ export type { InteractionLayerProps, ExternalCreateDragState } from './interactionLayer';
213
+ export { InteractionLayerEmits } from './interactionLayer';
@@ -0,0 +1,35 @@
1
+ import type { Shape } from ".";
2
+
3
+ export interface InteractionLayerProps {
4
+ connectShapeData?: Shape;
5
+ diagramBounds?: any;
6
+ resShape: Shape;
7
+ lines?: string[];
8
+ packages?: string[];
9
+ diagram?: string[];
10
+ taggedValueLabels?: string[];
11
+ actionButtonShapeDataId?: string;
12
+ edgeCheck?: boolean;
13
+ }
14
+
15
+ export const InteractionLayerEmits = [
16
+ "propertyPanel",
17
+ "editName",
18
+ "update-shape",
19
+ "connectEnd",
20
+ "actionButtonClick",
21
+ "diagramDoubleClick",
22
+ "modelTypePropertyIdButtonClick",
23
+ "edge-click",
24
+ "property-panel",
25
+ "actionButtonAdd"
26
+ ] as string[];
27
+
28
+ export type InteractionLayerEmitsType = typeof InteractionLayerEmits;
29
+
30
+ export interface ExternalCreateDragState {
31
+ creatingId: string | null;
32
+ pendingShape: Shape | null;
33
+ isDragging: boolean;
34
+ isCheckInFlight: boolean;
35
+ }