@nyaruka/temba-components 0.156.8 → 0.156.10

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 (59) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/temba-components.js +678 -631
  3. package/dist/temba-components.js.map +1 -1
  4. package/package.json +1 -1
  5. package/src/display/Chat.ts +8 -8
  6. package/src/display/FloatingTab.ts +2 -2
  7. package/src/display/Options.ts +8 -2
  8. package/src/flow/CanvasMenu.ts +20 -25
  9. package/src/flow/CanvasNode.ts +16 -12
  10. package/src/flow/DragManager.ts +93 -33
  11. package/src/flow/Editor.ts +64 -59
  12. package/src/flow/EditorToolbar.ts +19 -20
  13. package/src/flow/FlowSearch.ts +9 -7
  14. package/src/flow/MessageTable.ts +181 -74
  15. package/src/flow/NodeEditor.ts +55 -72
  16. package/src/flow/RevisionsWindow.ts +2 -4
  17. package/src/flow/ZoomManager.ts +1 -2
  18. package/src/flow/actions/play_audio.ts +1 -28
  19. package/src/flow/actions/say_msg.ts +1 -40
  20. package/src/flow/actions/send_broadcast.ts +1 -2
  21. package/src/flow/actions/send_email.ts +5 -56
  22. package/src/flow/actions/send_msg.ts +10 -2
  23. package/src/flow/actions/start_session.ts +1 -2
  24. package/src/flow/categoryLocalization.ts +1 -5
  25. package/src/flow/categoryUtils.ts +139 -0
  26. package/src/flow/nodes/shared-rules.ts +6 -16
  27. package/src/flow/nodes/shared.ts +113 -6
  28. package/src/flow/nodes/split_by_airtime.ts +41 -63
  29. package/src/flow/nodes/split_by_contact_field.ts +8 -17
  30. package/src/flow/nodes/split_by_expression.ts +8 -17
  31. package/src/flow/nodes/split_by_groups.ts +34 -112
  32. package/src/flow/nodes/split_by_llm.ts +1 -7
  33. package/src/flow/nodes/split_by_llm_categorize.ts +27 -43
  34. package/src/flow/nodes/split_by_random.ts +39 -99
  35. package/src/flow/nodes/split_by_resthook.ts +5 -19
  36. package/src/flow/nodes/split_by_run_result.ts +8 -17
  37. package/src/flow/nodes/split_by_scheme.ts +39 -124
  38. package/src/flow/nodes/split_by_subflow.ts +1 -7
  39. package/src/flow/nodes/split_by_ticket.ts +1 -7
  40. package/src/flow/nodes/split_by_webhook.ts +2 -8
  41. package/src/flow/nodes/wait_for_audio.ts +1 -7
  42. package/src/flow/nodes/wait_for_dial.ts +2 -8
  43. package/src/flow/nodes/wait_for_digits.ts +5 -7
  44. package/src/flow/nodes/wait_for_menu.ts +5 -7
  45. package/src/flow/nodes/wait_for_response.ts +10 -18
  46. package/src/flow/types.ts +27 -0
  47. package/src/flow/utils.ts +111 -3
  48. package/src/form/Compose.ts +11 -4
  49. package/src/form/MessageEditor.ts +5 -3
  50. package/src/form/RichEditor.ts +3 -1
  51. package/src/form/TemplateEditor.ts +5 -1
  52. package/src/form/select/Select.ts +11 -9
  53. package/src/layout/AccordionSection.ts +9 -3
  54. package/src/layout/Modax.ts +1 -3
  55. package/src/live/ContactChat.ts +54 -46
  56. package/src/simulator/Simulator.ts +9 -3
  57. package/src/store/AppState.ts +1 -1
  58. package/src/store/Store.ts +6 -1
  59. package/src/utils.ts +21 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nyaruka/temba-components",
3
- "version": "0.156.8",
3
+ "version": "0.156.10",
4
4
  "description": "Web components to support rapidpro and related projects",
5
5
  "author": "Nyaruka <code@nyaruka.coim>",
6
6
  "main": "dist/index.js",
@@ -862,7 +862,12 @@ export class Chat extends RapidElement {
862
862
 
863
863
  // show notification if new messages are appended and user is scrolled away from bottom
864
864
  // but not during search (searchHighlight is set)
865
- if (append && isScrolledAway && newMessages.length > 0 && !this.searchHighlight) {
865
+ if (
866
+ append &&
867
+ isScrolledAway &&
868
+ newMessages.length > 0 &&
869
+ !this.searchHighlight
870
+ ) {
866
871
  this.showNewMessageNotification = true;
867
872
  }
868
873
 
@@ -1123,10 +1128,7 @@ export class Chat extends RapidElement {
1123
1128
  }, 150);
1124
1129
  }
1125
1130
 
1126
- private highlightText(
1127
- text: string,
1128
- search: string
1129
- ): TemplateResult | string {
1131
+ private highlightText(text: string, search: string): TemplateResult | string {
1130
1132
  if (!search || !text) {
1131
1133
  return text;
1132
1134
  }
@@ -1245,9 +1247,7 @@ export class Chat extends RapidElement {
1245
1247
  const latestClass = index === msgIds.length - 1 ? 'latest' : '';
1246
1248
  const eventClass = msg._rendered ? 'is-event' : '';
1247
1249
  const matchClass =
1248
- this.highlightMessageUuid === msg.uuid
1249
- ? 'search-match'
1250
- : '';
1250
+ this.highlightMessageUuid === msg.uuid ? 'search-match' : '';
1251
1251
  return html`<div
1252
1252
  class="row message ${statusClass} ${unsendableClass} ${deletedClass} ${latestClass} ${eventClass} ${matchClass}"
1253
1253
  data-uuid=${msg.uuid || nothing}
@@ -28,8 +28,8 @@ export class FloatingTab extends RapidElement {
28
28
  border-bottom-left-radius: 8px;
29
29
  cursor: pointer;
30
30
  box-shadow: -2px 2px 8px rgba(0, 0, 0, 0.2);
31
- transition:
32
- transform calc(var(--transition-duration, 300ms) * 0.7) ease-in-out;
31
+ transition: transform calc(var(--transition-duration, 300ms) * 0.7)
32
+ ease-in-out;
33
33
  user-select: none;
34
34
  }
35
35
 
@@ -170,12 +170,18 @@ export class Options extends RapidElement {
170
170
  }
171
171
 
172
172
  .option:hover {
173
- background: var(--temba-options-option-hover-bg, var(--option-hover-bg));
173
+ background: var(
174
+ --temba-options-option-hover-bg,
175
+ var(--option-hover-bg)
176
+ );
174
177
  color: var(--temba-options-option-hover-text, var(--option-hover-text));
175
178
  }
176
179
 
177
180
  .option.focused {
178
- background: var(--temba-options-option-focus-bg, var(--color-selection));
181
+ background: var(
182
+ --temba-options-option-focus-bg,
183
+ var(--color-selection)
184
+ );
179
185
  color: var(--temba-options-option-focus-text, var(--color-text-dark));
180
186
  }
181
187
 
@@ -2,12 +2,15 @@ import { css, html, PropertyValueMap, TemplateResult } from 'lit';
2
2
  import { property, state } from 'lit/decorators.js';
3
3
  import { RapidElement } from '../RapidElement';
4
4
  import { CustomEventType } from '../interfaces';
5
+ import { ContextMenuShortcut } from './types';
5
6
 
6
7
  /**
7
- * Event detail for canvas menu selection
8
+ * Event detail for canvas menu selection. `action` is either one of the
9
+ * built-in menu actions ('sticky', 'other', 'reflow') or the `type` of a
10
+ * configured shortcut (e.g. 'send_msg', 'say_msg', 'set_contact_field').
8
11
  */
9
12
  export interface CanvasMenuSelection {
10
- action: 'sticky' | 'other' | 'send_msg' | 'wait_for_response' | 'reflow';
13
+ action: string;
11
14
  position: { x: number; y: number };
12
15
  }
13
16
 
@@ -78,8 +81,8 @@ export class CanvasMenu extends RapidElement {
78
81
  @property({ type: Boolean })
79
82
  public showStickyNote = true;
80
83
 
81
- @property({ type: Boolean })
82
- public showWaitForResponse = true;
84
+ @property({ type: Array })
85
+ public shortcuts: ContextMenuShortcut[] = [];
83
86
 
84
87
  @property({ type: Boolean })
85
88
  public showReflow = false;
@@ -131,14 +134,14 @@ export class CanvasMenu extends RapidElement {
131
134
  clickPosition: { x: number; y: number },
132
135
  showStickyNote: boolean = true,
133
136
  showReflow: boolean = false,
134
- showWaitForResponse: boolean = true
137
+ shortcuts: ContextMenuShortcut[] = []
135
138
  ) {
136
139
  this.x = x;
137
140
  this.y = y;
138
141
  this.clickPosition = clickPosition;
139
142
  this.showStickyNote = showStickyNote;
140
143
  this.showReflow = showReflow;
141
- this.showWaitForResponse = showWaitForResponse;
144
+ this.shortcuts = shortcuts;
142
145
  this.open = true;
143
146
 
144
147
  // Adjust position after menu renders to ensure it fits on screen
@@ -202,25 +205,17 @@ export class CanvasMenu extends RapidElement {
202
205
 
203
206
  return html`
204
207
  <div class="menu" style="left: ${this.x}px; top: ${this.y}px;">
205
- <div
206
- class="menu-item"
207
- @click=${() => this.handleMenuItemClick('send_msg')}
208
- >
209
- <temba-icon name="send" size="1.25"></temba-icon>
210
- <div class="menu-item-title">Send Message</div>
211
- </div>
212
-
213
- ${this.showWaitForResponse
214
- ? html`
215
- <div
216
- class="menu-item"
217
- @click=${() => this.handleMenuItemClick('wait_for_response')}
218
- >
219
- <temba-icon name="message" size="1.25"></temba-icon>
220
- <div class="menu-item-title">Wait for Response</div>
221
- </div>
222
- `
223
- : ''}
208
+ ${this.shortcuts.map(
209
+ (shortcut) => html`
210
+ <div
211
+ class="menu-item"
212
+ @click=${() => this.handleMenuItemClick(shortcut.type)}
213
+ >
214
+ <temba-icon name="${shortcut.icon}" size="1.25"></temba-icon>
215
+ <div class="menu-item-title">${shortcut.name}</div>
216
+ </div>
217
+ `
218
+ )}
224
219
 
225
220
  <div
226
221
  class="menu-item"
@@ -1622,9 +1622,7 @@ export class CanvasNode extends RapidElement {
1622
1622
 
1623
1623
  // IMPORTANT: Add the action to this node FIRST, before removing from source
1624
1624
  // This ensures we don't lose the action if the source node gets deleted
1625
- const droppedAction = isCopy
1626
- ? { ...action, uuid: generateUUID() }
1627
- : action;
1625
+ const droppedAction = isCopy ? { ...action, uuid: generateUUID() } : action;
1628
1626
  const newActions = [...this.node.actions];
1629
1627
  newActions.splice(dropIndex, 0, droppedAction);
1630
1628
 
@@ -1638,11 +1636,13 @@ export class CanvasNode extends RapidElement {
1638
1636
  for (const langCode of Object.keys(localization)) {
1639
1637
  const entry = localization[langCode]?.[action.uuid];
1640
1638
  if (entry) {
1641
- store.getState().updateLocalization(
1642
- langCode,
1643
- droppedAction.uuid,
1644
- JSON.parse(JSON.stringify(entry))
1645
- );
1639
+ store
1640
+ .getState()
1641
+ .updateLocalization(
1642
+ langCode,
1643
+ droppedAction.uuid,
1644
+ JSON.parse(JSON.stringify(entry))
1645
+ );
1646
1646
  }
1647
1647
  }
1648
1648
  }
@@ -1915,9 +1915,10 @@ export class CanvasNode extends RapidElement {
1915
1915
  const nodeConfig = NODE_CONFIG[this.ui?.type];
1916
1916
  const supportsLocalization = nodeConfig?.localizable === 'categories';
1917
1917
  const translatableCategoryUuids = new Set(
1918
- getTranslatableCategoriesForNode(this.ui?.type, node.router.categories).map(
1919
- (category) => category.uuid
1920
- )
1918
+ getTranslatableCategoriesForNode(
1919
+ this.ui?.type,
1920
+ node.router.categories
1921
+ ).map((category) => category.uuid)
1921
1922
  );
1922
1923
 
1923
1924
  return html`<div class="categories">
@@ -2010,7 +2011,10 @@ export class CanvasNode extends RapidElement {
2010
2011
  // currently hidden by the categories toggle.
2011
2012
  const hasTranslatableCategories =
2012
2013
  nodeConfig?.localizable === 'categories' &&
2013
- hasTranslatableCategoriesForNode(this.ui.type, this.node.router?.categories);
2014
+ hasTranslatableCategoriesForNode(
2015
+ this.ui.type,
2016
+ this.node.router?.categories
2017
+ );
2014
2018
  const hasTranslatableActions = (this.node.actions || []).some((action) => {
2015
2019
  const actionConfig = ACTION_CONFIG[action.type];
2016
2020
  return !!actionConfig?.localizable?.length;
@@ -138,7 +138,11 @@ export class DragManager {
138
138
  const position = this.getPosition(uuid, type);
139
139
  if (!position) return;
140
140
 
141
- if (!this.editor.selectedItems.has(uuid) && !event.ctrlKey && !event.metaKey) {
141
+ if (
142
+ !this.editor.selectedItems.has(uuid) &&
143
+ !event.ctrlKey &&
144
+ !event.metaKey
145
+ ) {
142
146
  this.editor.selectedItems.clear();
143
147
  } else if (!this.editor.selectedItems.has(uuid)) {
144
148
  this.editor.selectedItems.add(uuid);
@@ -215,7 +219,9 @@ export class DragManager {
215
219
  private handleGlobalMouseDown(event: MouseEvent): void {
216
220
  if (isRightClick(event)) return;
217
221
 
218
- const canvasRect = this.editor.querySelector('#grid')?.getBoundingClientRect();
222
+ const canvasRect = this.editor
223
+ .querySelector('#grid')
224
+ ?.getBoundingClientRect();
219
225
  if (!canvasRect) return;
220
226
 
221
227
  const isWithinCanvas =
@@ -258,7 +264,9 @@ export class DragManager {
258
264
  this.canvasMouseDown = true;
259
265
  this.dragStartPos = { x: event.clientX, y: event.clientY };
260
266
 
261
- const canvasRect = this.editor.querySelector('#canvas')?.getBoundingClientRect();
267
+ const canvasRect = this.editor
268
+ .querySelector('#canvas')
269
+ ?.getBoundingClientRect();
262
270
  if (canvasRect) {
263
271
  this.editor.selectedItems.clear();
264
272
 
@@ -348,7 +356,9 @@ export class DragManager {
348
356
  private updateSelectionBox(event: MouseEvent): void {
349
357
  if (!this.editor.selectionBox || !this.canvasMouseDown) return;
350
358
 
351
- const canvasRect = this.editor.querySelector('#canvas')?.getBoundingClientRect();
359
+ const canvasRect = this.editor
360
+ .querySelector('#canvas')
361
+ ?.getBoundingClientRect();
352
362
  if (!canvasRect) return;
353
363
 
354
364
  const relativeX = (event.clientX - canvasRect.left) / this.editor.zoom;
@@ -368,9 +378,18 @@ export class DragManager {
368
378
 
369
379
  const newSelection = new Set<string>();
370
380
 
371
- const boxLeft = Math.min(this.editor.selectionBox.startX, this.editor.selectionBox.endX);
372
- const boxTop = Math.min(this.editor.selectionBox.startY, this.editor.selectionBox.endY);
373
- const boxRight = Math.max(this.editor.selectionBox.startX, this.editor.selectionBox.endX);
381
+ const boxLeft = Math.min(
382
+ this.editor.selectionBox.startX,
383
+ this.editor.selectionBox.endX
384
+ );
385
+ const boxTop = Math.min(
386
+ this.editor.selectionBox.startY,
387
+ this.editor.selectionBox.endY
388
+ );
389
+ const boxRight = Math.max(
390
+ this.editor.selectionBox.startX,
391
+ this.editor.selectionBox.endX
392
+ );
374
393
  const boxBottom = Math.max(
375
394
  this.editor.selectionBox.startY,
376
395
  this.editor.selectionBox.endY
@@ -384,8 +403,9 @@ export class DragManager {
384
403
  if (nodeElement) {
385
404
  const position = this.editor.definition._ui?.nodes[node.uuid]?.position;
386
405
  if (position) {
387
- const canvasRect =
388
- this.editor.querySelector('#canvas')?.getBoundingClientRect();
406
+ const canvasRect = this.editor
407
+ .querySelector('#canvas')
408
+ ?.getBoundingClientRect();
389
409
 
390
410
  if (canvasRect) {
391
411
  const nodeLeft = position.left;
@@ -441,10 +461,20 @@ export class DragManager {
441
461
  public renderSelectionBox(): TemplateResult | string {
442
462
  if (!this.editor.selectionBox || !this.editor.isSelecting) return '';
443
463
 
444
- const left = Math.min(this.editor.selectionBox.startX, this.editor.selectionBox.endX);
445
- const top = Math.min(this.editor.selectionBox.startY, this.editor.selectionBox.endY);
446
- const width = Math.abs(this.editor.selectionBox.endX - this.editor.selectionBox.startX);
447
- const height = Math.abs(this.editor.selectionBox.endY - this.editor.selectionBox.startY);
464
+ const left = Math.min(
465
+ this.editor.selectionBox.startX,
466
+ this.editor.selectionBox.endX
467
+ );
468
+ const top = Math.min(
469
+ this.editor.selectionBox.startY,
470
+ this.editor.selectionBox.endY
471
+ );
472
+ const width = Math.abs(
473
+ this.editor.selectionBox.endX - this.editor.selectionBox.startX
474
+ );
475
+ const height = Math.abs(
476
+ this.editor.selectionBox.endY - this.editor.selectionBox.startY
477
+ );
448
478
 
449
479
  return html`<div
450
480
  class="selection-box"
@@ -484,7 +514,9 @@ export class DragManager {
484
514
  this.canvasMouseDown = true;
485
515
  this.dragStartPos = { x: touch.clientX, y: touch.clientY };
486
516
 
487
- const canvasRect = this.editor.querySelector('#canvas')?.getBoundingClientRect();
517
+ const canvasRect = this.editor
518
+ .querySelector('#canvas')
519
+ ?.getBoundingClientRect();
488
520
  if (canvasRect) {
489
521
  this.editor.selectedItems.clear();
490
522
 
@@ -529,7 +561,8 @@ export class DragManager {
529
561
 
530
562
  if (targetNode) {
531
563
  this.editor.targetId = targetNode.getAttribute('uuid');
532
- this.editor.isValidTarget = this.editor.targetId !== this.editor.dragFromNodeId;
564
+ this.editor.isValidTarget =
565
+ this.editor.targetId !== this.editor.dragFromNodeId;
533
566
 
534
567
  if (this.editor.isValidTarget) {
535
568
  targetNode.classList.add('connection-target-valid');
@@ -545,7 +578,8 @@ export class DragManager {
545
578
  const canvas = this.editor.querySelector('#canvas');
546
579
  if (canvas) {
547
580
  const canvasRect = canvas.getBoundingClientRect();
548
- const relativeX = (event.clientX - canvasRect.left) / this.editor.zoom;
581
+ const relativeX =
582
+ (event.clientX - canvasRect.left) / this.editor.zoom;
549
583
  const relativeY = (event.clientY - canvasRect.top) / this.editor.zoom;
550
584
 
551
585
  const placeholderWidth = 200;
@@ -630,9 +664,10 @@ export class DragManager {
630
664
  this.currentDragIsCopy = true;
631
665
 
632
666
  for (const uuid of itemsToCopy) {
633
- const element = this.editor.querySelector(`[uuid="${uuid}"]`) as HTMLElement;
634
- const type =
635
- element?.tagName === 'TEMBA-FLOW-NODE' ? 'node' : 'sticky';
667
+ const element = this.editor.querySelector(
668
+ `[uuid="${uuid}"]`
669
+ ) as HTMLElement;
670
+ const type = element?.tagName === 'TEMBA-FLOW-NODE' ? 'node' : 'sticky';
636
671
  const position = this.getPosition(uuid, type);
637
672
  if (element && position) {
638
673
  element.style.left = `${position.left}px`;
@@ -641,7 +676,9 @@ export class DragManager {
641
676
  }
642
677
  this.editor.plumber.revalidate(itemsToCopy);
643
678
  for (const uuid of itemsToCopy) {
644
- const element = this.editor.querySelector(`[uuid="${uuid}"]`) as HTMLElement;
679
+ const element = this.editor.querySelector(
680
+ `[uuid="${uuid}"]`
681
+ ) as HTMLElement;
645
682
  if (element) {
646
683
  void element.offsetHeight;
647
684
  element.classList.remove('dragging');
@@ -724,7 +761,9 @@ export class DragManager {
724
761
  : [this.editor.currentDragItem.uuid];
725
762
 
726
763
  itemsToMove.forEach((uuid) => {
727
- const element = this.editor.querySelector(`[uuid="${uuid}"]`) as HTMLElement;
764
+ const element = this.editor.querySelector(
765
+ `[uuid="${uuid}"]`
766
+ ) as HTMLElement;
728
767
  if (element) {
729
768
  const type = element.tagName === 'TEMBA-FLOW-NODE' ? 'node' : 'sticky';
730
769
  const position = this.getPosition(uuid, type);
@@ -814,9 +853,11 @@ export class DragManager {
814
853
 
815
854
  if (scrollDx > 0 || scrollDy > 0) {
816
855
  const neededWidth =
817
- (editorEl.scrollLeft + editorEl.clientWidth + scrollDx) / this.editor.zoom;
856
+ (editorEl.scrollLeft + editorEl.clientWidth + scrollDx) /
857
+ this.editor.zoom;
818
858
  const neededHeight =
819
- (editorEl.scrollTop + editorEl.clientHeight + scrollDy) / this.editor.zoom;
859
+ (editorEl.scrollTop + editorEl.clientHeight + scrollDy) /
860
+ this.editor.zoom;
820
861
  getStore()?.getState()?.expandCanvas(neededWidth, neededHeight);
821
862
  }
822
863
 
@@ -884,7 +925,9 @@ export class DragManager {
884
925
  const newPositions: { [uuid: string]: FlowPosition } = {};
885
926
 
886
927
  itemsToMove.forEach((uuid) => {
887
- const type = this.editor.definition.nodes.find((node) => node.uuid === uuid)
928
+ const type = this.editor.definition.nodes.find(
929
+ (node) => node.uuid === uuid
930
+ )
888
931
  ? 'node'
889
932
  : 'sticky';
890
933
  const position = this.getPosition(uuid, type);
@@ -899,7 +942,9 @@ export class DragManager {
899
942
  const newPosition = { left: snappedLeft, top: snappedTop };
900
943
  newPositions[uuid] = newPosition;
901
944
 
902
- const element = this.editor.querySelector(`[uuid="${uuid}"]`) as HTMLElement;
945
+ const element = this.editor.querySelector(
946
+ `[uuid="${uuid}"]`
947
+ ) as HTMLElement;
903
948
  if (element) {
904
949
  element.classList.remove('dragging', 'drag-copy');
905
950
  element.style.left = `${snappedLeft}px`;
@@ -983,7 +1028,9 @@ export class DragManager {
983
1028
  event.preventDefault();
984
1029
  this.editor.isSelecting = true;
985
1030
 
986
- const canvasRect = this.editor.querySelector('#canvas')?.getBoundingClientRect();
1031
+ const canvasRect = this.editor
1032
+ .querySelector('#canvas')
1033
+ ?.getBoundingClientRect();
987
1034
  if (canvasRect && this.editor.selectionBox) {
988
1035
  this.editor.selectionBox = {
989
1036
  ...this.editor.selectionBox,
@@ -1001,7 +1048,10 @@ export class DragManager {
1001
1048
  if (this.editor.plumber.connectionDragging) {
1002
1049
  event.preventDefault();
1003
1050
 
1004
- const targetNode = this.editor.findTargetNodeAt(touch.clientX, touch.clientY);
1051
+ const targetNode = this.editor.findTargetNodeAt(
1052
+ touch.clientX,
1053
+ touch.clientY
1054
+ );
1005
1055
 
1006
1056
  document.querySelectorAll('temba-flow-node').forEach((node) => {
1007
1057
  node.classList.remove(
@@ -1012,7 +1062,8 @@ export class DragManager {
1012
1062
 
1013
1063
  if (targetNode) {
1014
1064
  this.editor.targetId = targetNode.getAttribute('uuid');
1015
- this.editor.isValidTarget = this.editor.targetId !== this.editor.dragFromNodeId;
1065
+ this.editor.isValidTarget =
1066
+ this.editor.targetId !== this.editor.dragFromNodeId;
1016
1067
 
1017
1068
  if (this.editor.isValidTarget) {
1018
1069
  targetNode.classList.add('connection-target-valid');
@@ -1028,7 +1079,8 @@ export class DragManager {
1028
1079
  const canvas = this.editor.querySelector('#canvas');
1029
1080
  if (canvas) {
1030
1081
  const canvasRect = canvas.getBoundingClientRect();
1031
- const relativeX = (touch.clientX - canvasRect.left) / this.editor.zoom;
1082
+ const relativeX =
1083
+ (touch.clientX - canvasRect.left) / this.editor.zoom;
1032
1084
  const relativeY = (touch.clientY - canvasRect.top) / this.editor.zoom;
1033
1085
 
1034
1086
  const placeholderWidth = 200;
@@ -1123,10 +1175,14 @@ export class DragManager {
1123
1175
  // --- Connection dragging ---
1124
1176
  if (this.editor.plumber.connectionDragging) {
1125
1177
  if (touch) {
1126
- const targetNode = this.editor.findTargetNodeAt(touch.clientX, touch.clientY);
1178
+ const targetNode = this.editor.findTargetNodeAt(
1179
+ touch.clientX,
1180
+ touch.clientY
1181
+ );
1127
1182
  if (targetNode) {
1128
1183
  this.editor.targetId = targetNode.getAttribute('uuid');
1129
- this.editor.isValidTarget = this.editor.targetId !== this.editor.dragFromNodeId;
1184
+ this.editor.isValidTarget =
1185
+ this.editor.targetId !== this.editor.dragFromNodeId;
1130
1186
  }
1131
1187
  }
1132
1188
  return;
@@ -1154,7 +1210,9 @@ export class DragManager {
1154
1210
  const newPositions: { [uuid: string]: FlowPosition } = {};
1155
1211
 
1156
1212
  itemsToMove.forEach((uuid) => {
1157
- const type = this.editor.definition.nodes.find((node) => node.uuid === uuid)
1213
+ const type = this.editor.definition.nodes.find(
1214
+ (node) => node.uuid === uuid
1215
+ )
1158
1216
  ? 'node'
1159
1217
  : 'sticky';
1160
1218
  const position = this.getPosition(uuid, type);
@@ -1167,7 +1225,9 @@ export class DragManager {
1167
1225
 
1168
1226
  newPositions[uuid] = { left: snappedLeft, top: snappedTop };
1169
1227
 
1170
- const element = this.editor.querySelector(`[uuid="${uuid}"]`) as HTMLElement;
1228
+ const element = this.editor.querySelector(
1229
+ `[uuid="${uuid}"]`
1230
+ ) as HTMLElement;
1171
1231
  if (element) {
1172
1232
  element.classList.remove('dragging');
1173
1233
  element.style.left = `${snappedLeft}px`;