@nyaruka/temba-components 0.141.0 → 0.142.0

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 (206) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/static/svg/index.svg +1 -1
  3. package/dist/temba-components.js +859 -656
  4. package/dist/temba-components.js.map +1 -1
  5. package/out-tsc/src/Icons.js +3 -1
  6. package/out-tsc/src/Icons.js.map +1 -1
  7. package/out-tsc/src/display/Button.js +2 -2
  8. package/out-tsc/src/display/Button.js.map +1 -1
  9. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  10. package/out-tsc/src/flow/CanvasMenu.js +24 -1
  11. package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
  12. package/out-tsc/src/flow/CanvasNode.js +7 -2
  13. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  14. package/out-tsc/src/flow/Editor.js +665 -67
  15. package/out-tsc/src/flow/Editor.js.map +1 -1
  16. package/out-tsc/src/flow/NodeEditor.js +8 -5
  17. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  18. package/out-tsc/src/flow/Plumber.js +40 -28
  19. package/out-tsc/src/flow/Plumber.js.map +1 -1
  20. package/out-tsc/src/flow/actions/send_msg.js +2 -1
  21. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  22. package/out-tsc/src/flow/nodes/wait_for_response.js +1 -1
  23. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  24. package/out-tsc/src/flow/reflow.js +393 -0
  25. package/out-tsc/src/flow/reflow.js.map +1 -0
  26. package/out-tsc/src/flow/types.js.map +1 -1
  27. package/out-tsc/src/flow/utils.js +18 -3
  28. package/out-tsc/src/flow/utils.js.map +1 -1
  29. package/out-tsc/src/form/Compose.js +5 -0
  30. package/out-tsc/src/form/Compose.js.map +1 -1
  31. package/out-tsc/src/form/FieldRenderer.js +1 -3
  32. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  33. package/out-tsc/src/layout/Dialog.js +2 -0
  34. package/out-tsc/src/layout/Dialog.js.map +1 -1
  35. package/out-tsc/src/list/SortableList.js +39 -19
  36. package/out-tsc/src/list/SortableList.js.map +1 -1
  37. package/out-tsc/src/live/ContactChat.js +10 -1
  38. package/out-tsc/src/live/ContactChat.js.map +1 -1
  39. package/out-tsc/src/version.js +9 -0
  40. package/out-tsc/src/version.js.map +1 -0
  41. package/out-tsc/test/temba-canvas-menu.test.js +44 -0
  42. package/out-tsc/test/temba-canvas-menu.test.js.map +1 -1
  43. package/out-tsc/test/temba-contact-chat.test.js +12 -0
  44. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  45. package/out-tsc/test/temba-flow-collision.test.js +25 -0
  46. package/out-tsc/test/temba-flow-collision.test.js.map +1 -1
  47. package/out-tsc/test/temba-flow-editor-zoom.test.js +491 -0
  48. package/out-tsc/test/temba-flow-editor-zoom.test.js.map +1 -0
  49. package/out-tsc/test/temba-flow-editor.test.js +164 -1
  50. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  51. package/out-tsc/test/temba-flow-node-drag.test.js +123 -0
  52. package/out-tsc/test/temba-flow-node-drag.test.js.map +1 -1
  53. package/out-tsc/test/temba-flow-plumber.test.js +31 -0
  54. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  55. package/out-tsc/test/temba-flow-reflow.test.js +472 -0
  56. package/out-tsc/test/temba-flow-reflow.test.js.map +1 -0
  57. package/out-tsc/test/temba-sortable-list.test.js +93 -0
  58. package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
  59. package/package.json +1 -1
  60. package/rollup.components.mjs +7 -1
  61. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  62. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  63. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  64. package/screenshots/truth/actions/add_contact_urn/editor/expression-facebook.png +0 -0
  65. package/screenshots/truth/actions/add_contact_urn/editor/expression-phone.png +0 -0
  66. package/screenshots/truth/actions/add_contact_urn/editor/facebook-id.png +0 -0
  67. package/screenshots/truth/actions/add_contact_urn/editor/instagram-handle.png +0 -0
  68. package/screenshots/truth/actions/add_contact_urn/editor/line-id.png +0 -0
  69. package/screenshots/truth/actions/add_contact_urn/editor/phone-number.png +0 -0
  70. package/screenshots/truth/actions/add_contact_urn/editor/telegram-id.png +0 -0
  71. package/screenshots/truth/actions/add_contact_urn/editor/viber-id.png +0 -0
  72. package/screenshots/truth/actions/add_contact_urn/editor/wechat-id.png +0 -0
  73. package/screenshots/truth/actions/add_contact_urn/editor/whatsapp.png +0 -0
  74. package/screenshots/truth/actions/enter_flow/editor/basic-flow.png +0 -0
  75. package/screenshots/truth/actions/enter_flow/editor/long-flow-name.png +0 -0
  76. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  77. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  78. package/screenshots/truth/actions/say_msg/editor/multiline-text.png +0 -0
  79. package/screenshots/truth/actions/say_msg/editor/simple-text.png +0 -0
  80. package/screenshots/truth/actions/say_msg/editor/text-with-audio-url.png +0 -0
  81. package/screenshots/truth/actions/send_broadcast/editor/contacts-only.png +0 -0
  82. package/screenshots/truth/actions/send_broadcast/editor/groups-and-contacts.png +0 -0
  83. package/screenshots/truth/actions/send_broadcast/editor/groups-only.png +0 -0
  84. package/screenshots/truth/actions/send_broadcast/editor/many-groups.png +0 -0
  85. package/screenshots/truth/actions/send_broadcast/editor/multiline-text.png +0 -0
  86. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  87. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  88. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  89. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  90. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  91. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  92. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  93. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  94. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  95. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  96. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  97. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  98. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  99. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  100. package/screenshots/truth/actions/set_contact_channel/editor/sms-channel.png +0 -0
  101. package/screenshots/truth/actions/set_contact_channel/editor/whatsapp-channel.png +0 -0
  102. package/screenshots/truth/actions/set_contact_field/editor/clear-value.png +0 -0
  103. package/screenshots/truth/actions/set_contact_field/editor/set-value.png +0 -0
  104. package/screenshots/truth/actions/set_contact_language/editor/english.png +0 -0
  105. package/screenshots/truth/actions/set_contact_language/editor/french.png +0 -0
  106. package/screenshots/truth/actions/set_contact_status/editor/active.png +0 -0
  107. package/screenshots/truth/actions/set_contact_status/editor/archived.png +0 -0
  108. package/screenshots/truth/actions/set_contact_status/editor/blocked.png +0 -0
  109. package/screenshots/truth/actions/set_run_result/editor/expression-value.png +0 -0
  110. package/screenshots/truth/actions/set_run_result/editor/with-category.png +0 -0
  111. package/screenshots/truth/actions/start_session/editor/contact-query.png +0 -0
  112. package/screenshots/truth/actions/start_session/editor/contacts-only.png +0 -0
  113. package/screenshots/truth/actions/start_session/editor/create-contact.png +0 -0
  114. package/screenshots/truth/actions/start_session/editor/groups-and-contacts.png +0 -0
  115. package/screenshots/truth/actions/start_session/editor/groups-only.png +0 -0
  116. package/screenshots/truth/actions/start_session/editor/many-recipients.png +0 -0
  117. package/screenshots/truth/list/fields-dragging.png +0 -0
  118. package/screenshots/truth/list/sortable-dragging.png +0 -0
  119. package/screenshots/truth/modax/simple.png +0 -0
  120. package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
  121. package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
  122. package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
  123. package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
  124. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  125. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  126. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  127. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  128. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  129. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  130. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  131. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  132. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  133. package/screenshots/truth/nodes/wait_for_dial/editor/dial-with-limits.png +0 -0
  134. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  135. package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.png +0 -0
  136. package/screenshots/truth/nodes/wait_for_menu/editor/menu-with-digits.png +0 -0
  137. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  138. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  139. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  140. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  141. package/src/Icons.ts +3 -1
  142. package/src/display/Button.ts +2 -2
  143. package/src/display/FloatingTab.ts +1 -1
  144. package/src/flow/CanvasMenu.ts +28 -3
  145. package/src/flow/CanvasNode.ts +7 -2
  146. package/src/flow/Editor.ts +769 -76
  147. package/src/flow/NodeEditor.ts +8 -4
  148. package/src/flow/Plumber.ts +65 -35
  149. package/src/flow/actions/send_msg.ts +2 -1
  150. package/src/flow/nodes/wait_for_response.ts +1 -1
  151. package/src/flow/reflow.ts +534 -0
  152. package/src/flow/types.ts +1 -0
  153. package/src/flow/utils.ts +19 -3
  154. package/src/form/Compose.ts +5 -0
  155. package/src/form/FieldRenderer.ts +1 -3
  156. package/src/layout/Dialog.ts +2 -0
  157. package/src/list/SortableList.ts +40 -19
  158. package/src/live/ContactChat.ts +10 -1
  159. package/src/store/flow-definition.d.ts +1 -0
  160. package/src/version.ts +10 -0
  161. package/static/svg/index.svg +1 -1
  162. package/static/svg/work/traced/expand-06.svg +1 -0
  163. package/static/svg/work/used/expand-06.svg +3 -0
  164. package/test/temba-canvas-menu.test.ts +55 -0
  165. package/test/temba-contact-chat.test.ts +17 -0
  166. package/test/temba-flow-collision.test.ts +31 -0
  167. package/test/temba-flow-editor-zoom.test.ts +583 -0
  168. package/test/temba-flow-editor.test.ts +211 -1
  169. package/test/temba-flow-node-drag.test.ts +171 -0
  170. package/test/temba-flow-plumber.test.ts +38 -0
  171. package/test/temba-flow-reflow.test.ts +703 -0
  172. package/test/temba-sortable-list.test.ts +120 -0
  173. package/web-dev-server.config.mjs +5 -1
  174. package/web-test-runner.config.mjs +4 -1
  175. package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
  176. package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
  177. package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
  178. package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
  179. package/screenshots/truth/actions/call_llm/render/information-extraction.png +0 -0
  180. package/screenshots/truth/actions/call_llm/render/sentiment-analysis.png +0 -0
  181. package/screenshots/truth/actions/call_llm/render/summarization.png +0 -0
  182. package/screenshots/truth/actions/call_llm/render/translation-task.png +0 -0
  183. package/screenshots/truth/actions/send_broadcast/editor/with-attachments.png +0 -0
  184. package/screenshots/truth/actions/send_broadcast/render/with-attachments.png +0 -0
  185. package/screenshots/truth/compose/attachments-with-failures.png +0 -0
  186. package/screenshots/truth/compose/attachments-with-files-and-failures.png +0 -0
  187. package/screenshots/truth/contacts/tickets-assignment.png +0 -0
  188. package/screenshots/truth/contacts/tickets.png +0 -0
  189. package/screenshots/truth/flow/editor-basic.png +0 -0
  190. package/screenshots/truth/formfield/markdown-errors.png +0 -0
  191. package/screenshots/truth/formfield/no-errors.png +0 -0
  192. package/screenshots/truth/formfield/plain-text-errors.png +0 -0
  193. package/screenshots/truth/formfield/widget-only-markdown-errors.png +0 -0
  194. package/screenshots/truth/omnibox/selected.png +0 -0
  195. package/screenshots/truth/select/enabled-multi-selection.png +0 -0
  196. package/screenshots/truth/select/endpoint-initial-value-updated.png +0 -0
  197. package/screenshots/truth/select/endpoint-initial-value.png +0 -0
  198. package/screenshots/truth/select/initial-value.png +0 -0
  199. package/screenshots/truth/select/multi-reorder-final.png +0 -0
  200. package/screenshots/truth/select/multi-reorder-initial.png +0 -0
  201. package/screenshots/truth/select/selected-multi-test.png +0 -0
  202. package/screenshots/truth/select/value-initial.png +0 -0
  203. package/screenshots/truth/wait-for-response/rules-editor.png +0 -0
  204. package/screenshots/truth/wait-for-response/timeout-editor-unchecked.png +0 -0
  205. package/screenshots/truth/wait-for-response/timeout-editor.png +0 -0
  206. package/screenshots/truth/webchat/connecting-state.png +0 -0
@@ -81,7 +81,8 @@ export class SortableList extends RapidElement {
81
81
 
82
82
  ghostElement: HTMLDivElement = null;
83
83
  downEle: HTMLDivElement = null;
84
- originalElementRect: DOMRect = null; // Store original dimensions
84
+ originalElementRect: DOMRect = null; // Store viewport dimensions for ghost
85
+ originalLayoutSize: { width: number; height: number } = null; // Store layout dimensions for placeholders
85
86
  originalDragIndex: number = -1; // Store original index before moving element
86
87
  xOffset = 0;
87
88
  yOffset = 0;
@@ -319,16 +320,17 @@ export class SortableList extends RapidElement {
319
320
 
320
321
  this.dropPlaceholder.className = 'drop-placeholder sortable';
321
322
 
322
- // Copy dimensions from the original element (before it was hidden)
323
- if (this.originalElementRect) {
324
- const rect = this.originalElementRect;
325
- this.dropPlaceholder.style.width = rect.width + 'px';
326
- this.dropPlaceholder.style.height = rect.height + 'px';
327
- this.dropPlaceholder.style.minHeight = rect.height + 'px';
323
+ // Use layout-space dimensions for placeholders (unaffected by ancestor transforms)
324
+ if (this.originalLayoutSize) {
325
+ const size = this.originalLayoutSize;
326
+ this.dropPlaceholder.style.width = size.width + 'px';
327
+ this.dropPlaceholder.style.height = size.height + 'px';
328
+ this.dropPlaceholder.style.minHeight = size.height + 'px';
328
329
  this.dropPlaceholder.style.borderRadius = 'var(--curvature)';
329
330
  this.dropPlaceholder.style.flexShrink = '0';
330
331
  this.dropPlaceholder.style.background = '#f3f4f6';
331
- this.dropPlaceholder.style.border = '2px dashed #d1d5db';
332
+ this.dropPlaceholder.style.outline = '2px dashed #d1d5db';
333
+ this.dropPlaceholder.style.outlineOffset = '-2px';
332
334
  }
333
335
 
334
336
  // Insert the placeholder in the correct position in the DOM
@@ -352,15 +354,16 @@ export class SortableList extends RapidElement {
352
354
  this.dropPlaceholder = document.createElement('div');
353
355
  this.dropPlaceholder.className = 'drop-placeholder sortable';
354
356
 
355
- // Copy dimensions from the original element
356
- const rect = this.originalElementRect;
357
- this.dropPlaceholder.style.width = rect.width + 'px';
358
- this.dropPlaceholder.style.height = rect.height + 'px';
359
- this.dropPlaceholder.style.minHeight = rect.height + 'px';
357
+ // Use layout-space dimensions for placeholders (unaffected by ancestor transforms)
358
+ const size = this.originalLayoutSize;
359
+ this.dropPlaceholder.style.width = size.width + 'px';
360
+ this.dropPlaceholder.style.height = size.height + 'px';
361
+ this.dropPlaceholder.style.minHeight = size.height + 'px';
360
362
  this.dropPlaceholder.style.borderRadius = 'var(--curvature)';
361
363
  this.dropPlaceholder.style.flexShrink = '0';
362
364
  this.dropPlaceholder.style.background = '#f3f4f6';
363
- this.dropPlaceholder.style.border = '2px dashed #d1d5db';
365
+ this.dropPlaceholder.style.outline = '2px dashed #d1d5db';
366
+ this.dropPlaceholder.style.outlineOffset = '-2px';
364
367
 
365
368
  // Insert the placeholder right after the hidden original element
366
369
  this.downEle.insertAdjacentElement('afterend', this.dropPlaceholder);
@@ -387,7 +390,11 @@ export class SortableList extends RapidElement {
387
390
 
388
391
  // Use getBoundingClientRect for accurate offsets and store original dimensions
389
392
  const rect = ele.getBoundingClientRect();
390
- this.originalElementRect = rect; // Store the original rect before hiding
393
+ this.originalElementRect = rect; // Store viewport rect for ghost positioning
394
+ this.originalLayoutSize = {
395
+ width: ele.offsetWidth,
396
+ height: ele.offsetHeight
397
+ }; // Store layout dimensions for placeholders
391
398
  this.xOffset = event.clientX - rect.left;
392
399
  this.yOffset = event.clientY - rect.top;
393
400
  this.yDown = event.clientY;
@@ -424,17 +431,31 @@ export class SortableList extends RapidElement {
424
431
  // Style the clone as a ghost
425
432
  this.ghostElement.classList.add('ghost');
426
433
 
427
- // Use the stored original dimensions for positioning
434
+ // Detect ancestor scale transform (e.g. zoom) by comparing viewport
435
+ // to layout dimensions, so the ghost renders content at the right scale
428
436
  const rect = this.originalElementRect;
437
+ const layoutSize = this.originalLayoutSize;
438
+ const ancestorScale =
439
+ layoutSize.width > 0 ? rect.width / layoutSize.width : 1;
440
+ const hasAncestorScale = Math.abs(ancestorScale - 1) > 0.001;
429
441
 
430
442
  this.ghostElement.style.position = 'fixed';
431
443
  this.ghostElement.style.left = event.clientX - this.xOffset + 'px';
432
444
  this.ghostElement.style.top = event.clientY - this.yOffset + 'px';
433
- this.ghostElement.style.width = rect.width + 'px';
434
- this.ghostElement.style.height = rect.height + 'px';
435
445
  this.ghostElement.style.zIndex = '99999';
436
446
  this.ghostElement.style.opacity = '0.8';
437
- this.ghostElement.style.transform = 'scale(1.03)';
447
+
448
+ if (hasAncestorScale) {
449
+ // Use layout dimensions with ancestor scale so content renders correctly
450
+ this.ghostElement.style.width = layoutSize.width + 'px';
451
+ this.ghostElement.style.height = layoutSize.height + 'px';
452
+ this.ghostElement.style.transform = `scale(${ancestorScale * 1.03})`;
453
+ this.ghostElement.style.transformOrigin = '0 0';
454
+ } else {
455
+ this.ghostElement.style.width = rect.width + 'px';
456
+ this.ghostElement.style.height = rect.height + 'px';
457
+ this.ghostElement.style.transform = 'scale(1.03)';
458
+ }
438
459
 
439
460
  // allow component to customize the ghost node
440
461
  if (this.prepareGhost) {
@@ -162,6 +162,15 @@ export class ContactChat extends ContactStoreElement {
162
162
  opacity: 0.9;
163
163
  }
164
164
 
165
+ .flow-footer {
166
+ text-align: center;
167
+ pointer-events: none;
168
+ }
169
+
170
+ .flow-footer .in-flow {
171
+ pointer-events: auto;
172
+ }
173
+
165
174
  .in-flow:hover {
166
175
  opacity: 1;
167
176
  }
@@ -780,7 +789,7 @@ export class ContactChat extends ContactStoreElement {
780
789
  >
781
790
  ${inFlow
782
791
  ? html`
783
- <div slot="footer" style="text-align:center;">
792
+ <div slot="footer" class="flow-footer">
784
793
  <div class="in-flow">
785
794
  <div class="flow-name">
786
795
  <temba-icon name="flow" size="1.2"></temba-icon>
@@ -325,6 +325,7 @@ export interface FlowUI {
325
325
  languages: Record<string, string>[];
326
326
  translation_filters?: { categories: boolean };
327
327
  auto_translations?: Record<string, Record<string, string[]>>;
328
+ editor?: string;
328
329
  }
329
330
 
330
331
  export interface FlowDefinition {
package/src/version.ts ADDED
@@ -0,0 +1,10 @@
1
+ declare const __TEMBA_COMPONENTS_VERSION__: string;
2
+
3
+ let _version = 'dev';
4
+ try {
5
+ _version = __TEMBA_COMPONENTS_VERSION__;
6
+ } catch {
7
+ // not replaced by build tooling; keep default
8
+ }
9
+
10
+ export const TEMBA_COMPONENTS_VERSION = _version;