@nyaruka/temba-components 0.156.9 → 0.156.11
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.
- package/CHANGELOG.md +18 -0
- package/dist/temba-components.js +587 -523
- package/dist/temba-components.js.map +1 -1
- package/package.json +1 -1
- package/src/display/Chat.ts +8 -8
- package/src/display/FloatingTab.ts +2 -2
- package/src/display/Options.ts +8 -2
- package/src/flow/CanvasMenu.ts +20 -25
- package/src/flow/CanvasNode.ts +16 -12
- package/src/flow/DragManager.ts +93 -33
- package/src/flow/Editor.ts +59 -54
- package/src/flow/EditorToolbar.ts +19 -20
- package/src/flow/FlowSearch.ts +9 -7
- package/src/flow/MessageTable.ts +181 -74
- package/src/flow/NodeEditor.ts +55 -72
- package/src/flow/RevisionsWindow.ts +2 -4
- package/src/flow/ZoomManager.ts +1 -2
- package/src/flow/actions/play_audio.ts +1 -28
- package/src/flow/actions/say_msg.ts +1 -40
- package/src/flow/actions/send_broadcast.ts +1 -2
- package/src/flow/actions/send_email.ts +5 -56
- package/src/flow/actions/send_msg.ts +10 -2
- package/src/flow/actions/start_session.ts +1 -2
- package/src/flow/categoryLocalization.ts +1 -5
- package/src/flow/categoryUtils.ts +139 -0
- package/src/flow/nodes/shared-rules.ts +6 -16
- package/src/flow/nodes/shared.ts +113 -6
- package/src/flow/nodes/split_by_airtime.ts +41 -63
- package/src/flow/nodes/split_by_contact_field.ts +8 -17
- package/src/flow/nodes/split_by_expression.ts +8 -17
- package/src/flow/nodes/split_by_groups.ts +34 -112
- package/src/flow/nodes/split_by_llm.ts +1 -7
- package/src/flow/nodes/split_by_llm_categorize.ts +27 -43
- package/src/flow/nodes/split_by_random.ts +39 -99
- package/src/flow/nodes/split_by_resthook.ts +5 -19
- package/src/flow/nodes/split_by_run_result.ts +8 -17
- package/src/flow/nodes/split_by_scheme.ts +39 -124
- package/src/flow/nodes/split_by_subflow.ts +1 -7
- package/src/flow/nodes/split_by_ticket.ts +1 -7
- package/src/flow/nodes/split_by_webhook.ts +2 -8
- package/src/flow/nodes/wait_for_audio.ts +1 -7
- package/src/flow/nodes/wait_for_dial.ts +2 -8
- package/src/flow/nodes/wait_for_digits.ts +5 -7
- package/src/flow/nodes/wait_for_menu.ts +5 -7
- package/src/flow/nodes/wait_for_response.ts +10 -18
- package/src/flow/types.ts +27 -0
- package/src/flow/utils.ts +111 -3
- package/src/form/Compose.ts +84 -7
- package/src/form/MessageEditor.ts +5 -3
- package/src/form/RichEditor.ts +3 -1
- package/src/form/TemplateEditor.ts +5 -1
- package/src/form/select/Select.ts +12 -10
- package/src/layout/AccordionSection.ts +9 -3
- package/src/layout/Modax.ts +1 -3
- package/src/live/ContactChat.ts +54 -46
- package/src/simulator/Simulator.ts +9 -3
- package/src/store/AppState.ts +1 -1
- package/src/utils.ts +21 -16
package/package.json
CHANGED
package/src/display/Chat.ts
CHANGED
|
@@ -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 (
|
|
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
|
-
|
|
31
|
+
transition: transform calc(var(--transition-duration, 300ms) * 0.7)
|
|
32
|
+
ease-in-out;
|
|
33
33
|
user-select: none;
|
|
34
34
|
}
|
|
35
35
|
|
package/src/display/Options.ts
CHANGED
|
@@ -170,12 +170,18 @@ export class Options extends RapidElement {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
.option:hover {
|
|
173
|
-
background: var(
|
|
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(
|
|
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
|
|
package/src/flow/CanvasMenu.ts
CHANGED
|
@@ -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:
|
|
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:
|
|
82
|
-
public
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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"
|
package/src/flow/CanvasNode.ts
CHANGED
|
@@ -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
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
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(
|
|
1919
|
-
|
|
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(
|
|
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;
|
package/src/flow/DragManager.ts
CHANGED
|
@@ -138,7 +138,11 @@ export class DragManager {
|
|
|
138
138
|
const position = this.getPosition(uuid, type);
|
|
139
139
|
if (!position) return;
|
|
140
140
|
|
|
141
|
-
if (
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
372
|
-
|
|
373
|
-
|
|
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
|
-
|
|
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(
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
634
|
-
|
|
635
|
-
|
|
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(
|
|
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(
|
|
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) /
|
|
856
|
+
(editorEl.scrollLeft + editorEl.clientWidth + scrollDx) /
|
|
857
|
+
this.editor.zoom;
|
|
818
858
|
const neededHeight =
|
|
819
|
-
(editorEl.scrollTop + editorEl.clientHeight + scrollDy) /
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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`;
|