@nyaruka/temba-components 0.142.2 → 0.142.3
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 +8 -0
- package/dist/temba-components.js +266 -192
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/flow/CanvasMenu.js +8 -3
- package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +158 -9
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +473 -17
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +8 -8
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +89 -27
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/StickyNote.js +63 -3
- package/out-tsc/src/flow/StickyNote.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +11 -8
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js +3 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
- package/out-tsc/src/flow/utils.js +1 -3
- package/out-tsc/src/flow/utils.js.map +1 -1
- package/out-tsc/src/list/SortableList.js +104 -43
- package/out-tsc/src/list/SortableList.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +5 -1
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
- package/src/flow/CanvasMenu.ts +12 -4
- package/src/flow/CanvasNode.ts +185 -9
- package/src/flow/Editor.ts +552 -19
- package/src/flow/NodeEditor.ts +12 -12
- package/src/flow/Plumber.ts +101 -36
- package/src/flow/StickyNote.ts +76 -4
- package/src/flow/actions/send_msg.ts +11 -8
- package/src/flow/nodes/split_by_subflow.ts +3 -1
- package/src/flow/utils.ts +1 -3
- package/src/list/SortableList.ts +117 -47
- package/src/simulator/Simulator.ts +5 -1
package/src/flow/CanvasNode.ts
CHANGED
|
@@ -251,24 +251,20 @@ export class CanvasNode extends RapidElement {
|
|
|
251
251
|
}
|
|
252
252
|
.title-spacer {
|
|
253
253
|
width: 1.8em;
|
|
254
|
-
|
|
255
254
|
}
|
|
256
255
|
|
|
257
256
|
.action:hover .drag-handle {
|
|
258
257
|
visibility: visible;
|
|
259
258
|
opacity: 0.7;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
strong {
|
|
265
|
-
font-weight: 500;
|
|
266
259
|
}
|
|
267
260
|
|
|
268
261
|
.action .drag-handle:hover {
|
|
269
262
|
visibility: visible;
|
|
270
263
|
opacity: 1;
|
|
271
|
-
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
strong {
|
|
267
|
+
font-weight: 500;
|
|
272
268
|
}
|
|
273
269
|
|
|
274
270
|
.action .cn-title,
|
|
@@ -295,6 +291,8 @@ export class CanvasNode extends RapidElement {
|
|
|
295
291
|
|
|
296
292
|
.quick-replies {
|
|
297
293
|
margin-top: 0.5em;
|
|
294
|
+
display: flex;
|
|
295
|
+
flex-wrap: wrap;
|
|
298
296
|
}
|
|
299
297
|
|
|
300
298
|
.quick-reply {
|
|
@@ -302,9 +300,14 @@ export class CanvasNode extends RapidElement {
|
|
|
302
300
|
border: 1px solid #e0e0e0;
|
|
303
301
|
border-radius: calc(var(--curvature) * 1.5);
|
|
304
302
|
padding: 0.2em 1em;
|
|
305
|
-
display: inline-block;
|
|
306
303
|
font-size: 0.8em;
|
|
307
304
|
margin: 0.2em;
|
|
305
|
+
flex: 0 1 auto;
|
|
306
|
+
min-width: 0;
|
|
307
|
+
max-width: 100%;
|
|
308
|
+
overflow: hidden;
|
|
309
|
+
text-overflow: ellipsis;
|
|
310
|
+
white-space: nowrap;
|
|
308
311
|
}
|
|
309
312
|
|
|
310
313
|
.router-section {
|
|
@@ -489,6 +492,22 @@ export class CanvasNode extends RapidElement {
|
|
|
489
492
|
color: #9ca3af;
|
|
490
493
|
font-size: 0.9em;
|
|
491
494
|
}
|
|
495
|
+
|
|
496
|
+
/* On touch devices, always show interactive controls.
|
|
497
|
+
The .touch-device class is added to the editor on first touch. */
|
|
498
|
+
.touch-device .remove-button {
|
|
499
|
+
visibility: visible !important;
|
|
500
|
+
opacity: 0.7;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.touch-device .action .drag-handle {
|
|
504
|
+
visibility: visible !important;
|
|
505
|
+
opacity: 0.7;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.touch-device .add-action-button {
|
|
509
|
+
opacity: 0.8 !important;
|
|
510
|
+
}
|
|
492
511
|
}`;
|
|
493
512
|
}
|
|
494
513
|
|
|
@@ -1049,6 +1068,75 @@ export class CanvasNode extends RapidElement {
|
|
|
1049
1068
|
this.pendingActionClick = null;
|
|
1050
1069
|
}
|
|
1051
1070
|
|
|
1071
|
+
/* c8 ignore start -- touch-only handlers untestable in headless Chromium */
|
|
1072
|
+
private handleActionTouchStart(event: TouchEvent, action: Action): void {
|
|
1073
|
+
const target = event.target as HTMLElement;
|
|
1074
|
+
if (
|
|
1075
|
+
target.closest('.remove-button') ||
|
|
1076
|
+
target.closest('.drag-handle') ||
|
|
1077
|
+
target.closest('.linked-name') ||
|
|
1078
|
+
this.actionRemovingState.has(action.uuid)
|
|
1079
|
+
) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
const touch = event.touches[0];
|
|
1084
|
+
if (!touch) return;
|
|
1085
|
+
this.actionClickStartPos = { x: touch.clientX, y: touch.clientY };
|
|
1086
|
+
this.pendingActionClick = { action, event: event as any };
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
private handleActionTouchEnd(event: TouchEvent, action: Action): void {
|
|
1090
|
+
if (
|
|
1091
|
+
!this.pendingActionClick ||
|
|
1092
|
+
this.pendingActionClick.action.uuid !== action.uuid
|
|
1093
|
+
) {
|
|
1094
|
+
this.actionClickStartPos = null;
|
|
1095
|
+
this.pendingActionClick = null;
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
const target = event.target as HTMLElement;
|
|
1100
|
+
if (
|
|
1101
|
+
target.closest('.remove-button') ||
|
|
1102
|
+
target.closest('.drag-handle') ||
|
|
1103
|
+
target.closest('.linked-name') ||
|
|
1104
|
+
this.actionRemovingState.has(action.uuid)
|
|
1105
|
+
) {
|
|
1106
|
+
this.actionClickStartPos = null;
|
|
1107
|
+
this.pendingActionClick = null;
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
const touch = event.changedTouches[0];
|
|
1112
|
+
if (this.actionClickStartPos && touch) {
|
|
1113
|
+
const deltaX = touch.clientX - this.actionClickStartPos.x;
|
|
1114
|
+
const deltaY = touch.clientY - this.actionClickStartPos.y;
|
|
1115
|
+
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
1116
|
+
|
|
1117
|
+
const editor = this.closest('temba-flow-editor') as any;
|
|
1118
|
+
const editorWasDragging = editor?.dragging;
|
|
1119
|
+
|
|
1120
|
+
if (distance <= DRAG_THRESHOLD && (!editor || !editorWasDragging)) {
|
|
1121
|
+
const actionEl = event.currentTarget as Element;
|
|
1122
|
+
const origin = actionEl
|
|
1123
|
+
? this.getTopCenter(actionEl)
|
|
1124
|
+
: { x: touch.clientX, y: touch.clientY };
|
|
1125
|
+
|
|
1126
|
+
this.fireCustomEvent(CustomEventType.ActionEditRequested, {
|
|
1127
|
+
action,
|
|
1128
|
+
nodeUuid: this.node.uuid,
|
|
1129
|
+
originX: origin.x,
|
|
1130
|
+
originY: origin.y
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
this.actionClickStartPos = null;
|
|
1136
|
+
this.pendingActionClick = null;
|
|
1137
|
+
}
|
|
1138
|
+
/* c8 ignore stop */
|
|
1139
|
+
|
|
1052
1140
|
private handleActionClick(event: MouseEvent, action: Action): void {
|
|
1053
1141
|
// This method is kept for backward compatibility but should not be used
|
|
1054
1142
|
// The new mousedown/mouseup approach handles click vs drag properly
|
|
@@ -1192,6 +1280,84 @@ export class CanvasNode extends RapidElement {
|
|
|
1192
1280
|
this.pendingNodeClick = null;
|
|
1193
1281
|
}
|
|
1194
1282
|
|
|
1283
|
+
/* c8 ignore start -- touch-only handlers */
|
|
1284
|
+
private handleNodeTouchStart(event: TouchEvent): void {
|
|
1285
|
+
const target = event.target as HTMLElement;
|
|
1286
|
+
if (
|
|
1287
|
+
target.closest('.remove-button') ||
|
|
1288
|
+
target.closest('.exit') ||
|
|
1289
|
+
target.closest('.exit-wrapper') ||
|
|
1290
|
+
target.closest('.drag-handle') ||
|
|
1291
|
+
target.closest('.linked-name') ||
|
|
1292
|
+
this.actionRemovingState.has(this.node.uuid)
|
|
1293
|
+
) {
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
const touch = event.touches[0];
|
|
1298
|
+
if (!touch) return;
|
|
1299
|
+
this.nodeClickStartPos = { x: touch.clientX, y: touch.clientY };
|
|
1300
|
+
this.pendingNodeClick = { event: event as any };
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
private handleNodeTouchEnd(event: TouchEvent): void {
|
|
1304
|
+
if (!this.pendingNodeClick) {
|
|
1305
|
+
this.nodeClickStartPos = null;
|
|
1306
|
+
this.pendingNodeClick = null;
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
const target = event.target as HTMLElement;
|
|
1311
|
+
if (
|
|
1312
|
+
target.closest('.remove-button') ||
|
|
1313
|
+
target.closest('.exit') ||
|
|
1314
|
+
target.closest('.exit-wrapper') ||
|
|
1315
|
+
target.closest('.drag-handle') ||
|
|
1316
|
+
target.closest('.linked-name') ||
|
|
1317
|
+
this.actionRemovingState.has(this.node.uuid)
|
|
1318
|
+
) {
|
|
1319
|
+
this.nodeClickStartPos = null;
|
|
1320
|
+
this.pendingNodeClick = null;
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
const touch = event.changedTouches[0];
|
|
1325
|
+
if (this.nodeClickStartPos && touch) {
|
|
1326
|
+
const deltaX = touch.clientX - this.nodeClickStartPos.x;
|
|
1327
|
+
const deltaY = touch.clientY - this.nodeClickStartPos.y;
|
|
1328
|
+
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
1329
|
+
|
|
1330
|
+
const editor = this.closest('temba-flow-editor') as any;
|
|
1331
|
+
const editorWasDragging = editor?.dragging;
|
|
1332
|
+
|
|
1333
|
+
if (distance <= 5 && (!editor || !editorWasDragging)) {
|
|
1334
|
+
if (this.node.router) {
|
|
1335
|
+
const origin = this.getTopCenter(this);
|
|
1336
|
+
|
|
1337
|
+
if (this.node.actions && this.node.actions.length === 1) {
|
|
1338
|
+
this.fireCustomEvent(CustomEventType.ActionEditRequested, {
|
|
1339
|
+
action: this.node.actions[0],
|
|
1340
|
+
nodeUuid: this.node.uuid,
|
|
1341
|
+
originX: origin.x,
|
|
1342
|
+
originY: origin.y
|
|
1343
|
+
});
|
|
1344
|
+
} else {
|
|
1345
|
+
this.fireCustomEvent(CustomEventType.NodeEditRequested, {
|
|
1346
|
+
node: this.node,
|
|
1347
|
+
nodeUI: this.ui,
|
|
1348
|
+
originX: origin.x,
|
|
1349
|
+
originY: origin.y
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
this.nodeClickStartPos = null;
|
|
1357
|
+
this.pendingNodeClick = null;
|
|
1358
|
+
}
|
|
1359
|
+
/* c8 ignore stop */
|
|
1360
|
+
|
|
1195
1361
|
private handleAddActionClick(event: MouseEvent): void {
|
|
1196
1362
|
event.preventDefault();
|
|
1197
1363
|
event.stopPropagation();
|
|
@@ -1503,6 +1669,10 @@ export class CanvasNode extends RapidElement {
|
|
|
1503
1669
|
!isDisabled && this.handleActionMouseDown(e, action)}
|
|
1504
1670
|
@mouseup=${(e: MouseEvent) =>
|
|
1505
1671
|
!isDisabled && this.handleActionMouseUp(e, action)}
|
|
1672
|
+
@touchstart=${(e: TouchEvent) =>
|
|
1673
|
+
!isDisabled && this.handleActionTouchStart(e, action)}
|
|
1674
|
+
@touchend=${(e: TouchEvent) =>
|
|
1675
|
+
!isDisabled && this.handleActionTouchEnd(e, action)}
|
|
1506
1676
|
style="cursor: ${isDisabled ? 'not-allowed' : 'pointer'}"
|
|
1507
1677
|
>
|
|
1508
1678
|
${this.renderTitle(config, action, index, isRemoving)}
|
|
@@ -1564,6 +1734,8 @@ export class CanvasNode extends RapidElement {
|
|
|
1564
1734
|
class="body"
|
|
1565
1735
|
@mousedown=${(e: MouseEvent) => this.handleNodeMouseDown(e)}
|
|
1566
1736
|
@mouseup=${(e: MouseEvent) => this.handleNodeMouseUp(e)}
|
|
1737
|
+
@touchstart=${(e: TouchEvent) => this.handleNodeTouchStart(e)}
|
|
1738
|
+
@touchend=${(e: TouchEvent) => this.handleNodeTouchEnd(e)}
|
|
1567
1739
|
style="cursor: pointer;"
|
|
1568
1740
|
>
|
|
1569
1741
|
${renderClamped(
|
|
@@ -1630,6 +1802,8 @@ export class CanvasNode extends RapidElement {
|
|
|
1630
1802
|
})}
|
|
1631
1803
|
@mousedown=${(e: MouseEvent) => this.handleNodeMouseDown(e)}
|
|
1632
1804
|
@mouseup=${(e: MouseEvent) => this.handleNodeMouseUp(e)}
|
|
1805
|
+
@touchstart=${(e: TouchEvent) => this.handleNodeTouchStart(e)}
|
|
1806
|
+
@touchend=${(e: TouchEvent) => this.handleNodeTouchEnd(e)}
|
|
1633
1807
|
style="cursor: pointer;"
|
|
1634
1808
|
>
|
|
1635
1809
|
<div class="cn-title" title="${displayName}">${displayName}</div>
|
|
@@ -1705,6 +1879,8 @@ export class CanvasNode extends RapidElement {
|
|
|
1705
1879
|
<div
|
|
1706
1880
|
@mousedown=${(e: MouseEvent) => this.handleNodeMouseDown(e)}
|
|
1707
1881
|
@mouseup=${(e: MouseEvent) => this.handleNodeMouseUp(e)}
|
|
1882
|
+
@touchstart=${(e: TouchEvent) => this.handleNodeTouchStart(e)}
|
|
1883
|
+
@touchend=${(e: TouchEvent) => this.handleNodeTouchEnd(e)}
|
|
1708
1884
|
style="cursor: pointer;"
|
|
1709
1885
|
>
|
|
1710
1886
|
${this.renderNodeTitle(
|