@logicflow/extension 2.0.10 → 2.0.12

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 (51) hide show
  1. package/.turbo/turbo-build.log +9 -17
  2. package/CHANGELOG.md +37 -0
  3. package/dist/index.css +278 -1
  4. package/es/bpmn-elements/presets/Pool/Pool.d.ts +2 -2
  5. package/es/dynamic-group/index.d.ts +2 -1
  6. package/es/dynamic-group/index.js +21 -19
  7. package/es/dynamic-group/model.js +1 -5
  8. package/es/dynamic-group/node.d.ts +8 -1
  9. package/es/dynamic-group/node.js +87 -22
  10. package/es/index.css +278 -1
  11. package/es/index.less +1 -0
  12. package/es/materials/group/GroupNode.d.ts +5 -5
  13. package/es/materials/group/GroupNode.js +3 -3
  14. package/es/materials/group/index.js +5 -5
  15. package/es/materials/node-selection/index.d.ts +6 -6
  16. package/es/materials/node-selection/index.js +90 -10
  17. package/es/style/index.css +278 -1
  18. package/es/style/index.less +327 -0
  19. package/lib/bpmn-elements/presets/Pool/Pool.d.ts +2 -2
  20. package/lib/dynamic-group/index.d.ts +2 -1
  21. package/lib/dynamic-group/index.js +21 -19
  22. package/lib/dynamic-group/model.js +1 -5
  23. package/lib/dynamic-group/node.d.ts +8 -1
  24. package/lib/dynamic-group/node.js +87 -22
  25. package/lib/index.css +278 -1
  26. package/lib/index.less +1 -0
  27. package/lib/materials/group/GroupNode.d.ts +5 -5
  28. package/lib/materials/group/GroupNode.js +3 -3
  29. package/lib/materials/group/index.js +5 -5
  30. package/lib/materials/node-selection/index.d.ts +6 -6
  31. package/lib/materials/node-selection/index.js +89 -9
  32. package/lib/style/index.css +278 -1
  33. package/lib/style/index.less +327 -0
  34. package/package.json +3 -3
  35. package/src/components/mini-map/index.ts +11 -0
  36. package/src/dynamic-group/index.ts +29 -8
  37. package/src/dynamic-group/model.ts +1 -6
  38. package/src/dynamic-group/node.ts +136 -85
  39. package/src/index.ts +1 -0
  40. package/src/materials/group/GroupNode.ts +3 -3
  41. package/src/materials/group/index.ts +5 -5
  42. package/src/materials/node-selection/index.ts +115 -14
  43. package/src/style/index.less +3 -5
  44. package/src/style/raw.ts +3 -7
  45. package/src/tools/label/Label.tsx +106 -55
  46. package/src/tools/label/LabelModel.ts +1 -0
  47. package/src/tools/label/index.ts +64 -3
  48. package/src/tools/proximity-connect/index.ts +399 -0
  49. package/stats.html +1 -1
  50. package/dist/index.min.js +0 -2
  51. package/dist/index.min.js.map +0 -1
@@ -25,6 +25,7 @@ export interface ILabelState {
25
25
  isEditing: boolean
26
26
  isHovered: boolean
27
27
  isDragging: boolean
28
+ isSelected: boolean
28
29
  }
29
30
 
30
31
  @observer
@@ -52,6 +53,7 @@ export class Label extends Component<ILabelProps, ILabelState> {
52
53
  isEditing: false,
53
54
  isHovered: false,
54
55
  isDragging: false,
56
+ isSelected: false,
55
57
  }
56
58
  }
57
59
 
@@ -75,35 +77,34 @@ export class Label extends Component<ILabelProps, ILabelState> {
75
77
  const {
76
78
  editConfigModel: { nodeTextDraggable },
77
79
  } = graphModel
78
-
79
- // 当 label 允许拖拽 且不处于拖拽状态时, StepDrag 开启拖拽
80
- if ((label.draggable ?? nodeTextDraggable) && !this.state.isDragging) {
81
- this.setState({ isDragging: true })
80
+ // 当 label 允许拖拽 且不处于拖拽状态、不处于编辑状态时, StepDrag 开启拖拽
81
+ if (
82
+ (label.draggable ?? nodeTextDraggable) &&
83
+ !this.state.isDragging &&
84
+ !this.state.isEditing
85
+ ) {
82
86
  this.stepDrag.handleMouseDown(e)
83
87
  }
84
88
  }
89
+ handleMouseUp = (e: MouseEvent) => {
90
+ if (this.state.isDragging) {
91
+ this.stepDrag.handleMouseUp(e)
92
+ }
93
+ }
85
94
  handleDragging = ({ deltaX, deltaY }: IDragParams) => {
86
- const { label, element, graphModel } = this.props
95
+ if (!this.state.isDragging) {
96
+ this.setState({ isDragging: true })
97
+ }
98
+ const { label, graphModel } = this.props
87
99
 
88
100
  // DONE: 添加缩放时拖拽的逻辑,对 deltaX 和 deltaY 进行按比例缩放
89
101
  const { transformModel } = graphModel
90
102
  const [curDeltaX, curDeltaY] = transformModel.fixDeltaXY(deltaX, deltaY)
91
103
 
92
- // DONE:更新 label 位置,触发 LABEL:DRAG 事件,并抛出相关的数据
93
- const {
94
- properties: { _label },
95
- } = element
96
- const elementLabel = _label as LabelConfig[]
97
- const idx = findIndex(elementLabel, (cur) => cur.id === label.id)
98
-
99
- const target = elementLabel[idx]
100
- elementLabel[idx] = {
101
- ...target,
102
- x: target.x + curDeltaX,
103
- y: target.y + curDeltaY,
104
- }
105
- const targetElem = graphModel.getElement(element.id)
106
- targetElem?.setProperty('_label', elementLabel)
104
+ this.setElementModelLabelInfo({
105
+ x: label.x + curDeltaX,
106
+ y: label.y + curDeltaY,
107
+ })
107
108
 
108
109
  graphModel.eventCenter.emit('label:drag', {
109
110
  data: label.getData(),
@@ -114,6 +115,21 @@ export class Label extends Component<ILabelProps, ILabelState> {
114
115
  this.setState({ isDragging: false })
115
116
  }
116
117
 
118
+ handleClick = (e: MouseEvent) => {
119
+ const { label, element, graphModel } = this.props
120
+ // 更新当前Label选中状态
121
+ element.setSelected(!this.state.isSelected)
122
+ this.setState({ isSelected: !this.state.isSelected })
123
+ this.setElementModelLabelInfo({
124
+ isSelected: true,
125
+ })
126
+ graphModel.eventCenter.emit('label:click', {
127
+ data: label.getData(),
128
+ e,
129
+ model: element,
130
+ })
131
+ }
132
+
117
133
  handleDbClick = (e: MouseEvent) => {
118
134
  const { label, element, graphModel } = this.props
119
135
  graphModel.eventCenter.emit('label:dblclick', {
@@ -162,9 +178,28 @@ export class Label extends Component<ILabelProps, ILabelState> {
162
178
  this.setState({
163
179
  isDragging: false,
164
180
  isHovered: false,
181
+ isSelected: false,
165
182
  })
166
183
  }
167
184
 
185
+ setElementModelLabelInfo(data) {
186
+ const { label, element, graphModel } = this.props
187
+ const {
188
+ properties: { _label },
189
+ } = element
190
+ const elementLabel = _label as LabelConfig[]
191
+ const idx = findIndex(elementLabel, (cur) => cur.id === label.id)
192
+
193
+ const target = elementLabel[idx]
194
+ elementLabel[idx] = {
195
+ ...target,
196
+ ...data,
197
+ }
198
+
199
+ const targetElem = graphModel.getElement(element.id)
200
+ targetElem?.setProperty('_label', elementLabel)
201
+ }
202
+
168
203
  // 重新计算 Label 大小
169
204
  reCalcLabelSize = () => {}
170
205
 
@@ -175,37 +210,49 @@ export class Label extends Component<ILabelProps, ILabelState> {
175
210
  const { label, element, graphModel } = this.props
176
211
 
177
212
  // 在点击元素、边或者画布 时,结束 Label 的编辑态
178
- graphModel.eventCenter.on('blank:click,node:click,edge:click', () => {
179
- // 如果当前 label 处于编辑态,则结束编辑态
180
- if (this.state.isEditing) {
181
- this.setState({ isEditing: false })
182
-
183
- const value = this.textRef.current?.innerText ?? ''
184
- const content = this.textRef.current?.innerHTML ?? ''
185
-
186
- const {
187
- properties: { _label },
188
- } = element
189
- const elementLabel = _label as LabelConfig[]
190
- const idx = findIndex(elementLabel, (cur) => cur.id === label.id)
191
-
192
- const target = elementLabel[idx]
193
- elementLabel[idx] = {
194
- ...target,
195
- value,
196
- content,
213
+ graphModel.eventCenter.on(
214
+ 'blank:click,node:click,edge:click,label:click',
215
+ ({ data }) => {
216
+ // 点击的不是label 、点击的不是当前label、点击的是当前label,且当前 label 处于选中态
217
+ // 则取消选中态
218
+ if (
219
+ data?.type !== 'label' ||
220
+ (data.type === 'label' && data.id !== label.id) ||
221
+ this.state.isSelected
222
+ ) {
223
+ this.setState({ isSelected: false })
197
224
  }
198
-
199
- const targetElem = graphModel.getElement(element.id)
200
- targetElem?.setProperty('_label', elementLabel)
201
-
202
- element.setElementState(ElementState.DEFAULT)
203
- }
204
- if (this.textRef.current) {
205
- this.textRef.current.contentEditable = 'false'
206
- }
207
- })
208
-
225
+ // 点击的不是label 、点击的不是当前label、点击的是当前label,且当前 label 处于编辑态
226
+ // 则结束编辑态
227
+ if (
228
+ (data?.type !== 'label' ||
229
+ (data.type == 'label' && data.id !== label.id)) &&
230
+ this.state.isEditing
231
+ ) {
232
+ this.setState({ isEditing: false })
233
+
234
+ const value = this.textRef.current?.innerText ?? ''
235
+ const content = this.textRef.current?.innerHTML ?? ''
236
+
237
+ this.setElementModelLabelInfo({
238
+ value,
239
+ content,
240
+ isSelected: false,
241
+ })
242
+
243
+ element.setElementState(ElementState.DEFAULT)
244
+ }
245
+ // 点击的不是label 、点击的不是当前label、点击的是当前label,且当前 label 的文本DOM存在
246
+ // 则结束文本DOM的编辑态
247
+ if (
248
+ (data?.type !== 'label' ||
249
+ (data.type == 'label' && data.id !== label.id)) &&
250
+ this.textRef.current
251
+ ) {
252
+ this.textRef.current.contentEditable = 'false'
253
+ }
254
+ },
255
+ )
209
256
  // TODO: 节点拖拽结束后,更新 Label 的位置
210
257
  // eventCenter.on('node:drag', () => {})
211
258
  // eventCenter.on('node:drop', () => {})
@@ -216,7 +263,7 @@ export class Label extends Component<ILabelProps, ILabelState> {
216
263
 
217
264
  componentDidUpdate() {
218
265
  // snapshot: any, // previousState: Readonly<ILabelState>, // previousProps: Readonly<ILabelProps>,
219
- console.log('Label componentDidUpdate')
266
+ // console.log('Label componentDidUpdate')
220
267
  // console.log('previousProps', previousProps)
221
268
  // console.log('previousState', previousState)
222
269
  // console.log('snapshot', snapshot)
@@ -232,7 +279,7 @@ export class Label extends Component<ILabelProps, ILabelState> {
232
279
 
233
280
  render() {
234
281
  const { label, element, graphModel } = this.props
235
- const { isDragging, isHovered, isEditing } = this.state
282
+ const { isDragging, isHovered, isSelected, isEditing } = this.state
236
283
  const { transformModel } = graphModel
237
284
  const { transform } = transformModel.getTransformStyle()
238
285
  const {
@@ -260,13 +307,14 @@ export class Label extends Component<ILabelProps, ILabelState> {
260
307
  ? `${transform} rotate(${rotate}deg)`
261
308
  : `${transform} rotate(${vertical ? -0.25 : 0}turn)`,
262
309
  }
263
-
264
310
  return (
265
311
  <div
266
312
  id={`element-container-${id}`}
267
313
  className={classNames('lf-label-editor-container')}
268
314
  style={containerStyle}
269
315
  onMouseDown={this.handleMouseDown}
316
+ onMouseUp={this.handleMouseUp}
317
+ onClick={this.handleClick}
270
318
  onDblClick={this.handleDbClick}
271
319
  onBlur={this.handleBlur}
272
320
  onMouseEnter={this.setHoverOn}
@@ -279,12 +327,15 @@ export class Label extends Component<ILabelProps, ILabelState> {
279
327
  className={classNames('lf-label-editor', {
280
328
  'lf-label-editor-dragging': isDragging,
281
329
  'lf-label-editor-editing': isEditing,
282
- 'lf-label-editor-hover': !isEditing && isHovered,
330
+ 'lf-label-editor-hover': !isEditing && (isHovered || isSelected),
283
331
  [`lf-label-editor-${textOverflowMode}`]: !isEditing,
284
332
  })}
285
333
  style={{
286
334
  maxWidth: `${maxLabelWidth}px`,
287
- width: `${maxLabelWidth}px`,
335
+ boxSizing: 'border-box',
336
+ display: 'inline-block',
337
+ background:
338
+ isEditing || element.BaseType === 'edge' ? '#fff' : 'transparent',
288
339
  ...style,
289
340
  }}
290
341
  dangerouslySetInnerHTML={{ __html: content }}
@@ -64,6 +64,7 @@ export class LabelModel {
64
64
  id: this.id,
65
65
  x: this.x,
66
66
  y: this.y,
67
+ type: 'label',
67
68
  content: this.content,
68
69
  value: this.value,
69
70
  rotate: this.rotate,
@@ -1,5 +1,13 @@
1
1
  import LogicFlow, { createUuid, GraphModel, TextMode } from '@logicflow/core'
2
- import { cloneDeep, forEach, isArray, isObject, map } from 'lodash-es'
2
+ import {
3
+ cloneDeep,
4
+ forEach,
5
+ isArray,
6
+ isEmpty,
7
+ isEqual,
8
+ isObject,
9
+ map,
10
+ } from 'lodash-es'
3
11
  import LabelOverlay, { LabelConfigType } from './LabelOverlay'
4
12
  import {
5
13
  BBoxInfo,
@@ -53,7 +61,7 @@ export class Label implements Extension {
53
61
  this.addEventListeners()
54
62
 
55
63
  // TODO: 3. 自定义快捷键,比如 delete,选中 label 时,移除 label
56
- // this.rewriteShortcut()
64
+ this.rewriteShortcut()
57
65
 
58
66
  // 插件中注册 LabelOverlay 工具,用于 label 的编辑
59
67
  lf.tool.registerTool(LabelOverlay.toolName, LabelOverlay)
@@ -377,7 +385,60 @@ export class Label implements Extension {
377
385
  // TODO: others methods ???
378
386
  }
379
387
 
380
- // private rewriteShortcut() {}
388
+ private rewriteShortcut() {
389
+ const { keyboard, graphModel } = this.lf
390
+ const {
391
+ options: { keyboard: keyboardOptions },
392
+ } = keyboard
393
+ keyboard.off(['backspace'])
394
+ keyboard.on(['backspace'], () => {
395
+ if (!keyboardOptions?.enabled) return true
396
+ if (graphModel.textEditElement) return true
397
+ const elements = graphModel.getSelectElements(true)
398
+ this.lf.clearSelectElements()
399
+ const {
400
+ graphModel: { editConfigModel },
401
+ } = this.lf
402
+ elements.edges.forEach((edge) => {
403
+ const { properties } = edge
404
+ if (
405
+ properties &&
406
+ !isEmpty(properties._label) &&
407
+ editConfigModel.textMode === TextMode.LABEL
408
+ ) {
409
+ const newLabelList = properties._label.filter(
410
+ (label) => !label.isSelected,
411
+ )
412
+ // 如果两个labelList长度不一致,说明有选中的元素,此时backspace做的动作是删除label
413
+ if (!isEqual(newLabelList.length, properties._label.length)) {
414
+ const edgeModel = graphModel.getEdgeModelById(edge.id)
415
+ edgeModel?.setProperty('_label', newLabelList)
416
+ return
417
+ }
418
+ }
419
+ edge.id && this.lf.deleteEdge(edge.id)
420
+ })
421
+ elements.nodes.forEach((node) => {
422
+ const { properties } = node
423
+ if (
424
+ properties &&
425
+ !isEmpty(properties._label) &&
426
+ editConfigModel.textMode === TextMode.LABEL
427
+ ) {
428
+ const newLabelList = properties._label.filter(
429
+ (label) => !label.isSelected,
430
+ )
431
+ if (!isEqual(newLabelList.length, properties._label.length)) {
432
+ const nodeModel = graphModel.getNodeModelById(node.id)
433
+ nodeModel?.setProperty('_label', newLabelList)
434
+ return
435
+ }
436
+ }
437
+ node.id && this.lf.deleteNode(node.id)
438
+ })
439
+ return false
440
+ })
441
+ }
381
442
 
382
443
  /**
383
444
  * 更新当前渲染使用的 Text or Label 模式