@nyaruka/temba-components 0.142.1 → 0.142.2

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 (131) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/temba-components.js +825 -654
  3. package/dist/temba-components.js.map +1 -1
  4. package/out-tsc/src/Icons.js +1 -0
  5. package/out-tsc/src/Icons.js.map +1 -1
  6. package/out-tsc/src/flow/CanvasMenu.js +30 -35
  7. package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
  8. package/out-tsc/src/flow/CanvasNode.js +13 -8
  9. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  10. package/out-tsc/src/flow/Editor.js +18 -5
  11. package/out-tsc/src/flow/Editor.js.map +1 -1
  12. package/out-tsc/src/flow/NodeEditor.js +346 -10
  13. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  14. package/out-tsc/src/flow/NodeTypeSelector.js +2 -0
  15. package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -1
  16. package/out-tsc/src/flow/Plumber.js +3 -1
  17. package/out-tsc/src/flow/Plumber.js.map +1 -1
  18. package/out-tsc/src/flow/actions/add_contact_urn.js +2 -6
  19. package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
  20. package/out-tsc/src/flow/actions/enter_flow.js +2 -2
  21. package/out-tsc/src/flow/actions/enter_flow.js.map +1 -1
  22. package/out-tsc/src/flow/actions/say_msg.js +2 -1
  23. package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
  24. package/out-tsc/src/flow/actions/send_broadcast.js +2 -6
  25. package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
  26. package/out-tsc/src/flow/actions/send_email.js +2 -6
  27. package/out-tsc/src/flow/actions/send_email.js.map +1 -1
  28. package/out-tsc/src/flow/actions/send_msg.js +52 -35
  29. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  30. package/out-tsc/src/flow/actions/set_contact_channel.js +2 -1
  31. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  32. package/out-tsc/src/flow/actions/set_contact_field.js +4 -5
  33. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
  34. package/out-tsc/src/flow/actions/set_contact_language.js +3 -3
  35. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
  36. package/out-tsc/src/flow/actions/set_contact_name.js +2 -1
  37. package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
  38. package/out-tsc/src/flow/actions/set_contact_status.js +2 -1
  39. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  40. package/out-tsc/src/flow/actions/set_run_result.js +3 -3
  41. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
  42. package/out-tsc/src/flow/actions/start_session.js +2 -2
  43. package/out-tsc/src/flow/actions/start_session.js.map +1 -1
  44. package/out-tsc/src/flow/nodes/split_by_llm.js +4 -5
  45. package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
  46. package/out-tsc/src/flow/nodes/split_by_resthook.js +3 -8
  47. package/out-tsc/src/flow/nodes/split_by_resthook.js.map +1 -1
  48. package/out-tsc/src/flow/nodes/split_by_subflow.js +2 -2
  49. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
  50. package/out-tsc/src/flow/nodes/split_by_webhook.js +25 -33
  51. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
  52. package/out-tsc/src/flow/nodes/wait_for_response.js +1 -0
  53. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  54. package/out-tsc/src/flow/types.js.map +1 -1
  55. package/out-tsc/src/flow/utils.js +68 -0
  56. package/out-tsc/src/flow/utils.js.map +1 -1
  57. package/out-tsc/src/form/FieldRenderer.js +17 -2
  58. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  59. package/out-tsc/src/interfaces.js +1 -0
  60. package/out-tsc/src/interfaces.js.map +1 -1
  61. package/out-tsc/src/simulator/Simulator.js +1 -1
  62. package/out-tsc/src/simulator/Simulator.js.map +1 -1
  63. package/out-tsc/test/temba-canvas-menu.test.js +13 -9
  64. package/out-tsc/test/temba-canvas-menu.test.js.map +1 -1
  65. package/out-tsc/test/temba-flow-reflow.test.js.map +1 -1
  66. package/out-tsc/test/temba-node-editor.test.js +9 -10
  67. package/out-tsc/test/temba-node-editor.test.js.map +1 -1
  68. package/out-tsc/test/temba-node-type-selector.test.js +3 -3
  69. package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
  70. package/out-tsc/test/temba-simulator.test.js +2 -2
  71. package/out-tsc/test/temba-simulator.test.js.map +1 -1
  72. package/package.json +1 -1
  73. package/screenshots/truth/actions/enter_flow/render/basic-flow.png +0 -0
  74. package/screenshots/truth/actions/enter_flow/render/long-flow-name.png +0 -0
  75. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  76. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  77. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  78. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  79. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  80. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  81. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  82. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  83. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  84. package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
  85. package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
  86. package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
  87. package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
  88. package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
  89. package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
  90. package/screenshots/truth/canvas-menu/open.png +0 -0
  91. package/screenshots/truth/node-type-selector/action-mode.png +0 -0
  92. package/screenshots/truth/node-type-selector/split-mode.png +0 -0
  93. package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
  94. package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
  95. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  96. package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
  97. package/src/Icons.ts +1 -0
  98. package/src/flow/CanvasMenu.ts +38 -39
  99. package/src/flow/CanvasNode.ts +16 -8
  100. package/src/flow/Editor.ts +33 -6
  101. package/src/flow/NodeEditor.ts +373 -10
  102. package/src/flow/NodeTypeSelector.ts +2 -0
  103. package/src/flow/Plumber.ts +3 -1
  104. package/src/flow/actions/add_contact_urn.ts +5 -6
  105. package/src/flow/actions/enter_flow.ts +2 -2
  106. package/src/flow/actions/say_msg.ts +2 -1
  107. package/src/flow/actions/send_broadcast.ts +2 -6
  108. package/src/flow/actions/send_email.ts +2 -6
  109. package/src/flow/actions/send_msg.ts +56 -38
  110. package/src/flow/actions/set_contact_channel.ts +5 -1
  111. package/src/flow/actions/set_contact_field.ts +10 -5
  112. package/src/flow/actions/set_contact_language.ts +6 -3
  113. package/src/flow/actions/set_contact_name.ts +5 -1
  114. package/src/flow/actions/set_contact_status.ts +5 -1
  115. package/src/flow/actions/set_run_result.ts +6 -3
  116. package/src/flow/actions/start_session.ts +2 -2
  117. package/src/flow/nodes/split_by_llm.ts +5 -5
  118. package/src/flow/nodes/split_by_resthook.ts +3 -8
  119. package/src/flow/nodes/split_by_subflow.ts +2 -2
  120. package/src/flow/nodes/split_by_webhook.ts +26 -34
  121. package/src/flow/nodes/wait_for_response.ts +1 -0
  122. package/src/flow/types.ts +25 -2
  123. package/src/flow/utils.ts +81 -1
  124. package/src/form/FieldRenderer.ts +32 -3
  125. package/src/interfaces.ts +1 -0
  126. package/src/simulator/Simulator.ts +1 -1
  127. package/test/temba-canvas-menu.test.ts +13 -9
  128. package/test/temba-flow-reflow.test.ts +4 -2
  129. package/test/temba-node-editor.test.ts +9 -10
  130. package/test/temba-node-type-selector.test.ts +3 -3
  131. package/test/temba-simulator.test.ts +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"Simulator.js","sourceRoot":"","sources":["../../../src/simulator/Simulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, TemplateResult } from 'lit-html';\nimport { RapidElement } from '../RapidElement';\nimport { FloatingWindow } from '../layout/FloatingWindow';\nimport { css, PropertyValueMap } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { postJSON, fromCookie, generateUUIDv7 } from '../utils';\nimport { getStore } from '../store/Store';\nimport { AppState, fromStore, zustand } from '../store/AppState';\nimport { FlowDefinition } from '../store/flow-definition';\nimport { CustomEventType } from '../interfaces';\nimport { Chat, ContactEvent, MessageType } from '../display/Chat';\nimport { Events, renderEvent } from '../events/eventRenderers';\n\n// test attachment URLs\nconst TEST_IMAGES = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_a.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_b.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_c.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_d.jpg'\n];\n\nconst TEST_VIDEOS = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_video_a.mp4'\n];\n\nconst TEST_AUDIO = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_audio_a.mp3'\n];\n\nconst TEST_LOCATIONS = [\n 'geo:47.6062,-122.3321', // Seattle\n 'geo:-0.1807,-78.4678', // Quito\n 'geo:-2.9001,-79.0059', // Cuenca\n 'geo:-1.9536,30.0606' // Kigali\n];\n\ninterface Contact {\n uuid: string;\n name?: string;\n urns: string[];\n fields?: { [key: string]: any };\n groups?: any[];\n language?: string;\n status?: string;\n created_on?: string;\n}\n\ninterface Session {\n environment: any;\n runs: any[];\n status: string;\n trigger: any;\n wait?: any;\n}\n\ninterface Message {\n uuid: string;\n text?: string;\n urn: string;\n attachments?: string[];\n quick_replies?: any[];\n}\n\ninterface Event {\n type: string;\n created_on: string;\n msg?: Message;\n [key: string]: any;\n}\n\ninterface RunContext {\n session: Session;\n events: Event[];\n context?: any;\n contact?: Contact;\n}\n\ninterface SimulatorSize {\n phoneWidth: number;\n phoneTotalHeight: number;\n phoneScreenHeight: number;\n contextWidth: number;\n contextHeight: number;\n contextOffset: number;\n optionPaneWidth: number;\n optionPaneGap: number;\n windowPadding: number;\n cutoutHeight: number;\n cutoutPadding: number;\n cutoutFontSize: number;\n cutoutIslandWidth: number;\n cutoutIslandHeight: number;\n cutoutIslandTop: number;\n}\n\nconst SIMULATOR_SIZES: Record<string, SimulatorSize> = {\n small: {\n phoneWidth: 270,\n phoneTotalHeight: 530,\n phoneScreenHeight: 376,\n contextWidth: 336,\n contextHeight: 416,\n contextOffset: 48,\n optionPaneWidth: 44,\n optionPaneGap: 10,\n windowPadding: 24,\n cutoutHeight: 32,\n cutoutPadding: 12,\n cutoutFontSize: 10,\n cutoutIslandWidth: 80,\n cutoutIslandHeight: 20,\n cutoutIslandTop: 6\n },\n medium: {\n phoneWidth: 300,\n phoneTotalHeight: 600,\n phoneScreenHeight: 470,\n contextWidth: 420,\n contextHeight: 520,\n contextOffset: 60,\n optionPaneWidth: 44,\n optionPaneGap: 12,\n windowPadding: 30,\n cutoutHeight: 40,\n cutoutPadding: 16,\n cutoutFontSize: 12,\n cutoutIslandWidth: 100,\n cutoutIslandHeight: 24,\n cutoutIslandTop: 8\n },\n large: {\n phoneWidth: 360,\n phoneTotalHeight: 700,\n phoneScreenHeight: 564,\n contextWidth: 504,\n contextHeight: 624,\n contextOffset: 72,\n optionPaneWidth: 44,\n optionPaneGap: 14,\n windowPadding: 36,\n cutoutHeight: 50,\n cutoutPadding: 20,\n cutoutFontSize: 14,\n cutoutIslandWidth: 120,\n cutoutIslandHeight: 30,\n cutoutIslandTop: 10\n }\n};\n\nexport class Simulator extends RapidElement {\n static get styles() {\n return css`\n temba-floating-tab {\n --floating-tab-right: 15px;\n }\n\n :host {\n /* size-specific dimensions are set dynamically via inline styles */\n --phone-width: 300px;\n --phone-total-height: 720px;\n --context-width: 420px;\n --context-offset: 60px;\n --option-pane-width: 44px;\n --option-pane-gap: 12px;\n --window-padding: 30px;\n --phone-screen-height: 470px;\n --context-height: 520px;\n --context-closed-left: 332px;\n --animation-time: 200ms;\n }\n\n .phone-simulator {\n padding-left: calc(var(--context-width) + var(--context-offset));\n padding-top: var(--window-padding);\n padding-bottom: var(--window-padding);\n position: relative;\n display: flex;\n align-items: flex-start;\n }\n\n .option-pane {\n margin-top: var(--window-padding);\n margin-left: var(--option-pane-gap);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 6px;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(10px);\n border-radius: 16px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n }\n .option-btn {\n background: rgba(255, 255, 255, 0.1);\n border: none;\n border-radius: 12px;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all var(--animation-time) ease;\n color: white;\n }\n .option-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(1.05);\n }\n .option-btn:active {\n transform: scale(0.95);\n }\n .option-btn.active {\n background: var(--color-primary-dark);\n color: white;\n }\n .option-btn.active:hover {\n background: var(--color-primary-dark);\n }\n\n .phone-frame {\n width: var(--phone-width);\n height: var(--phone-total-height);\n border-radius: 40px;\n border: 6px solid #1f2937;\n box-shadow: 0 0px 30px rgba(0, 0, 0, 0.4);\n background: #000;\n position: relative;\n overflow: hidden;\n z-index: 2;\n }\n\n .context-explorer {\n width: var(--context-width);\n height: var(--context-height);\n border-top-left-radius: 16px;\n border-bottom-left-radius: 16px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n position: absolute;\n left: var(--context-closed-left);\n top: calc(var(--window-padding) + 40px);\n z-index: 1;\n font-size: 13px;\n color: #374151;\n transition: left calc(var(--animation-time) * 1.5) ease-out,\n opacity calc(var(--animation-time) * 1.5) ease-out;\n opacity: 0;\n pointer-events: none;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(10px);\n display: flex;\n flex-direction: column;\n padding: 12px;\n }\n\n .context-gutter {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 6px;\n\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 4px;\n margin-right: 32px;\n margin-top: 8px;\n flex-shrink: 0;\n }\n\n .context-gutter-btn {\n width: 14px;\n height: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n border-radius: 6px;\n transition: background var(--animation-time) ease;\n color: rgba(255, 255, 255, 0.6);\n padding: 4px;\n }\n\n .context-gutter-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.9);\n }\n\n .context-gutter-btn.active {\n color: #c084fc;\n }\n\n .context-gutter-spacer {\n flex: 1;\n }\n\n .context-explorer-scroll {\n scrollbar-color: rgba(255, 255, 255, 0.3) #4a4a4a;\n scrollbar-width: thin;\n height: 100%;\n overflow-y: scroll;\n padding-right: 10px;\n margin-right: 30px;\n flex-grow: 1;\n }\n\n .context-explorer-bleed {\n height: 100%;\n width: 0px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar {\n width: 18px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 4px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.5);\n }\n\n /* Custom scrollbar for chat area to allow content to flow behind input */\n .custom-scrollbar-container {\n position: absolute;\n top: 40px;\n bottom: var(--bottom-input-height, 60px);\n right: 4px;\n width: 10px;\n z-index: 20;\n overflow-y: auto;\n overflow-x: hidden;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar {\n width: 6px;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.4);\n }\n\n .custom-scrollbar-content {\n width: 100%;\n }\n\n .context-explorer.open {\n left: var(--context-offset);\n opacity: 1;\n pointer-events: auto;\n }\n\n .context-explorer.hidden {\n pointer-events: none !important;\n }\n\n .context-item {\n display: flex;\n align-items: flex-start;\n padding: 2px 4px;\n cursor: pointer;\n user-select: none;\n }\n\n .context-item:hover {\n background: rgba(0, 0, 0, 0.05);\n }\n\n .context-item-expandable {\n display: flex;\n align-items: center;\n }\n\n .context-expand-icon {\n width: 16px;\n display: inline-block;\n text-align: center;\n flex-shrink: 0;\n transition: transform var(--animation-time) ease;\n color: #ffffff;\n }\n\n .context-expand-icon.expanded {\n transform: rotate(90deg);\n }\n\n .context-key {\n color: #ffffff;\n flex-shrink: 0;\n margin-right: 8px;\n display: flex;\n }\n\n .context-key.has-value {\n color: #e8b5e8;\n }\n\n .context-value {\n color: #aaa;\n flex: 1;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .context-children {\n margin-left: 16px;\n }\n\n .context-copy-icon {\n opacity: 0;\n margin-left: 4px;\n transition: opacity var(--animation-time) ease;\n cursor: pointer;\n color: #ccc;\n }\n\n .context-item:hover .context-copy-icon {\n opacity: 1;\n }\n\n .context-toast {\n position: absolute;\n bottom: 60px;\n left: 50%;\n transform: translateX(-50%);\n background: #666;\n color: white;\n padding: 12px 12px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n font-size: 13px;\n z-index: 10;\n animation: slideInUp var(--animation-time) ease-out;\n }\n\n .context-toast .expression {\n color: #e8b5e8;\n font-weight: 600;\n }\n\n @keyframes slideInUp {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n }\n\n .phone-top {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 10;\n cursor: grab;\n }\n .phone-notch {\n background: transparent;\n height: var(--cutout-height);\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 var(--cutout-padding);\n }\n .phone-notch::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background: linear-gradient(\n to bottom,\n rgba(0, 0, 0, 0.3) 0%,\n rgba(0, 0, 0, 0.2) 50%,\n transparent 100%\n );\n z-index: -1;\n }\n .dynamic-island {\n top: var(--cutout-island-top);\n left: 50%;\n\n width: var(--cutout-island-width);\n height: var(--cutout-island-height);\n background: #000;\n border-radius: calc(var(--cutout-island-height) / 1.5);\n z-index: 1;\n }\n .phone-notch .time {\n color: #000;\n font-size: var(--cutout-font-size);\n font-weight: 600;\n }\n .phone-notch .status-icons {\n display: flex;\n gap: 4px;\n align-items: center;\n }\n .phone-notch .status-icons span {\n color: #000;\n font-size: var(--cutout-font-size);\n }\n .phone-header {\n background: transparent;\n padding: 10px 15px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n cursor: move;\n user-select: none;\n border-bottom: none;\n pointer-events: all;\n }\n\n .phone-screen {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: white;\n display: flex;\n flex-direction: column;\n }\n\n temba-chat {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n --color-chat-in: #e5e5ea;\n --color-chat-out: #007aff;\n --chat-top-padding: calc(var(--cutout-height));\n --chat-bottom-padding: calc(var(--bottom-input-height, 80px) - 10px);\n }\n\n .bottom-input-container {\n position: absolute;\n bottom: 0px;\n left: 0px;\n right: 0px;\n z-index: 10;\n }\n\n .bottom-input-container::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.45);\n backdrop-filter: blur(10px);\n -webkit-mask-image: linear-gradient(to bottom, transparent, black 20px);\n mask-image: linear-gradient(to bottom, transparent, black 20px);\n z-index: -1;\n }\n\n .quick-replies-container {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 6px;\n z-index: 9;\n }\n\n .quick-reply-btn {\n padding: 4px 8px;\n border-radius: 18px;\n border: 1px solid var(--color-primary, #007aff);\n background: white;\n color: var(--color-primary, #007aff);\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n }\n\n .quick-reply-btn:hover:not(:disabled) {\n background: var(--color-primary, #007aff);\n color: white;\n }\n\n .quick-reply-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .message-input {\n padding: 8px 12px;\n border-top: none;\n display: flex;\n align-items: center;\n gap: 8px;\n z-index: 10;\n }\n .message-input input {\n flex: 1;\n border: 1px solid #c6c6c857;\n border-radius: 20px;\n padding: 8px 15px;\n font-size: 15px;\n margin-bottom: 5px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n outline: none;\n }\n .message-input input::placeholder {\n color: #8e8e93;\n }\n .attachment-button {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: #fff;\n border: 1px solid #c6c6c857;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n flex-shrink: 0;\n margin-bottom: 5px;\n transition: all var(--animation-time) ease;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n color: #000;\n }\n .attachment-button:hover {\n background: #f8f8f8ff;\n transform: scale(1.05);\n }\n .attachment-button:active {\n transform: scale(0.95);\n }\n .attachment-menu {\n position: absolute;\n bottom: 55px;\n left: 12px;\n background: white;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n padding: 8px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n opacity: 0;\n pointer-events: none;\n transform: translateY(10px);\n transition: opacity var(--animation-time) ease, transform 0.2s ease;\n z-index: 20;\n }\n .attachment-menu.open {\n opacity: 1;\n pointer-events: all;\n transform: translateY(0);\n }\n .attachment-menu-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n cursor: pointer;\n transition: background var(--animation-time) ease;\n white-space: nowrap;\n font-size: 14px;\n color: #1f2937;\n }\n .attachment-menu-item:hover {\n background: #f3f4f6;\n }\n .attachment-menu-item temba-icon {\n color: #007aff;\n }\n `;\n }\n\n @fromStore(zustand, (state: AppState) => state.flowDefinition)\n private definition!: FlowDefinition;\n\n @fromStore(zustand, (state: AppState) => state.viewingRevision)\n private viewingRevision!: boolean;\n\n @property({ type: String })\n flow = '';\n\n @property({ type: String })\n endpoint = '';\n\n @property({ type: Number })\n animationTime = 200;\n\n @fromCookie('simulator-size', 'small')\n size: 'small' | 'medium' | 'large';\n\n @property({ type: Array })\n private events: ContactEvent[] = [];\n\n private previousEventCount = 0;\n private chat: Chat = null;\n\n @property({ type: Object })\n private session: Session | null = null;\n\n @property({ type: Object })\n private context: any = null;\n\n @property({ type: Object })\n private contact: Contact = {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {},\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n };\n\n @property({ type: Boolean })\n private sprinting = false;\n\n @property({ type: String })\n private inputValue = '';\n\n @fromCookie('simulator-follow', true)\n private following: boolean;\n\n @fromCookie('simulator-context-open', false)\n private contextExplorerOpen: boolean;\n\n @property({ type: Object })\n private expandedPaths: Set<string> = new Set();\n\n @property({ type: String })\n private copiedExpression = '';\n\n @property({ type: String })\n private toastMessage = '';\n\n @property({ type: Boolean })\n private showAllKeys = true;\n\n private previousWindowWidth = 0;\n\n @property({ type: Array })\n private currentQuickReplies: any[] = [];\n\n @property({ type: Boolean })\n private isVisible = false;\n\n @property({ type: Boolean })\n private attachmentMenuOpen = false;\n\n private boundClickOutsideHandler: ((event: MouseEvent) => void) | null = null;\n\n // attachment cycling indices - initialized randomly\n private imageIndex = Math.floor(Math.random() * TEST_IMAGES.length);\n private videoIndex = Math.floor(Math.random() * TEST_VIDEOS.length);\n private audioIndex = Math.floor(Math.random() * TEST_AUDIO.length);\n private locationIndex = Math.floor(Math.random() * TEST_LOCATIONS.length);\n\n // method to reset attachment indices for testing\n public resetAttachmentIndices() {\n this.imageIndex = 2;\n this.videoIndex = 0;\n this.audioIndex = 0;\n this.locationIndex = 0;\n }\n\n private get sizeConfig(): SimulatorSize {\n return SIMULATOR_SIZES[this.size] || SIMULATOR_SIZES.medium;\n }\n\n private get windowWidth(): number {\n const config = this.sizeConfig;\n return (\n config.contextWidth +\n config.phoneWidth +\n config.optionPaneWidth +\n config.optionPaneGap +\n config.contextOffset\n );\n }\n\n private get leftBoundaryMargin(): number {\n const config = this.sizeConfig;\n return config.contextWidth + config.contextOffset;\n }\n\n private get contextClosedLeft(): number {\n const config = this.sizeConfig;\n return config.contextWidth + config.contextOffset - config.phoneWidth;\n }\n\n public connectedCallback() {\n super.connectedCallback();\n }\n\n protected firstUpdated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changes);\n this.chat = this.shadowRoot.querySelector('temba-chat');\n\n // if we have events that were collected before chat was ready, add them now\n if (this.chat && this.events.length > 0) {\n this.chat.addMessages(this.events, null, true);\n }\n\n this.setupCustomScrollbar();\n }\n\n private setupCustomScrollbar() {\n const chat = this.shadowRoot?.querySelector('temba-chat') as Chat;\n const scrollContainer = this.shadowRoot?.querySelector(\n '.custom-scrollbar-container'\n ) as HTMLElement;\n const scrollContent = this.shadowRoot?.querySelector(\n '.custom-scrollbar-content'\n ) as HTMLElement;\n\n if (!chat || !scrollContainer || !scrollContent) return;\n\n chat.updateComplete.then(() => {\n const chatScroll = chat.shadowRoot?.querySelector(\n '.scroll'\n ) as HTMLElement;\n if (!chatScroll) return;\n\n let ignoreScroll = false;\n\n // Sync from chat to custom scrollbar\n chatScroll.addEventListener('scroll', () => {\n if (!ignoreScroll) {\n ignoreScroll = true;\n // Chat: 0 (bottom) ... -Max (top) (Negative scrolling)\n // Custom: Max (bottom) ... 0 (top) (Positive scrolling)\n\n const maxScroll =\n scrollContainer.scrollHeight - scrollContainer.clientHeight;\n // Math.abs to handle negative scrollTop\n const distanceFromBottom = Math.abs(chatScroll.scrollTop);\n const newCustomScrollTop = maxScroll - distanceFromBottom;\n\n scrollContainer.scrollTop = newCustomScrollTop;\n\n requestAnimationFrame(() => (ignoreScroll = false));\n }\n });\n\n // Sync from custom scrollbar to chat\n scrollContainer.addEventListener('scroll', () => {\n if (!ignoreScroll) {\n ignoreScroll = true;\n\n const maxScroll =\n scrollContainer.scrollHeight - scrollContainer.clientHeight;\n const distanceFromBottom = maxScroll - scrollContainer.scrollTop;\n\n // chat scrollTop should be -distanceFromBottom\n chatScroll.scrollTop = -distanceFromBottom;\n\n requestAnimationFrame(() => (ignoreScroll = false));\n }\n });\n\n // Sync height\n const syncHeight = () => {\n const chatMaxScroll = chatScroll.scrollHeight - chatScroll.clientHeight;\n const customClientHeight = scrollContainer.clientHeight;\n\n // ensure minimum height\n if (chatMaxScroll <= 0) {\n scrollContent.style.height = '100%';\n return;\n }\n\n const newHeight = chatMaxScroll + customClientHeight;\n scrollContent.style.height = `${newHeight}px`;\n\n // If we were effectively at the bottom, stay at the bottom\n // This is a heuristic, assuming if we're close enough we're \"at bottom\"\n // But the Chat component handles scrollToBottom on new messages, which fires scroll event,\n // which updates us. So we might not need to force it here unless resize happens without message.\n if (Math.abs(chatScroll.scrollTop) < 5) {\n scrollContainer.scrollTop = scrollContainer.scrollHeight;\n }\n };\n\n // Observe changes\n const observer = new MutationObserver(syncHeight);\n observer.observe(chatScroll, {\n childList: true,\n subtree: true,\n attributes: true\n });\n\n const resizeObserver = new ResizeObserver(syncHeight);\n resizeObserver.observe(chatScroll);\n\n // Initial sync\n syncHeight();\n });\n }\n\n protected updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n\n if (\n changes.has('currentQuickReplies') ||\n changes.has('keyboardVisible') ||\n changes.has('attachmentMenuOpen')\n ) {\n this.updateBottomInputHeight();\n }\n\n if (changes.has('flow') && this.flow) {\n this.endpoint = `/flow/simulate/${this.flow}/`;\n }\n\n // handle attachment menu click outside listener\n if (changes.has('attachmentMenuOpen')) {\n if (this.attachmentMenuOpen) {\n // create bound handler if it doesn't exist\n if (!this.boundClickOutsideHandler) {\n this.boundClickOutsideHandler =\n this.handleClickOutsideAttachmentMenu.bind(this);\n }\n // add listener when menu opens\n setTimeout(() => {\n document.addEventListener('click', this.boundClickOutsideHandler);\n }, 0);\n } else {\n // remove listener when menu closes\n if (this.boundClickOutsideHandler) {\n document.removeEventListener('click', this.boundClickOutsideHandler);\n }\n }\n }\n\n // update floating window boundaries when size changes\n if (changes.has('size')) {\n requestAnimationFrame(() => {\n const phoneWindow = this.shadowRoot?.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n if (phoneWindow) {\n // use the stored previous width since phoneWindow.width has already been updated\n const oldWidth = this.previousWindowWidth || phoneWindow.width;\n const oldRight = phoneWindow.left + oldWidth;\n\n const config = this.sizeConfig;\n const newWidth = this.windowWidth;\n\n // store current width for next size change\n this.previousWindowWidth = newWidth;\n\n // update dimensions and boundaries\n phoneWindow.width = newWidth;\n phoneWindow.leftBoundaryMargin = this.leftBoundaryMargin;\n phoneWindow.topBoundaryMargin = config.windowPadding;\n phoneWindow.bottomBoundaryMargin = config.windowPadding;\n\n // keep right edge in same position by adjusting left\n let newLeft = oldRight - newWidth;\n\n // apply same boundary logic as FloatingWindow.handleMouseMove\n const padding = 20;\n const minLeft = padding - this.leftBoundaryMargin;\n const maxLeft =\n window.innerWidth -\n newWidth -\n padding +\n phoneWindow.rightBoundaryMargin;\n\n // clamp to boundaries\n newLeft = Math.max(minLeft, Math.min(newLeft, maxLeft));\n\n phoneWindow.left = newLeft;\n\n // adjust vertical position if needed\n const windowElement = phoneWindow.shadowRoot?.querySelector(\n '.window'\n ) as HTMLElement;\n const currentHeight =\n windowElement?.offsetHeight || config.phoneTotalHeight;\n const maxTop = Math.max(\n padding - config.windowPadding,\n window.innerHeight - currentHeight - padding + config.windowPadding\n );\n\n phoneWindow.top = Math.max(\n padding - config.windowPadding,\n Math.min(phoneWindow.top, maxTop)\n );\n }\n });\n } else {\n // store initial width when first rendered\n if (!this.previousWindowWidth) {\n this.previousWindowWidth = this.windowWidth;\n }\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n // clean up event listener when component is removed\n if (this.boundClickOutsideHandler) {\n document.removeEventListener('click', this.boundClickOutsideHandler);\n }\n }\n\n private handleShow() {\n const phoneWindow = this.shadowRoot.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n phoneWindow.show();\n this.isVisible = true;\n getStore().getState().setSimulatorActive(true);\n\n // ensure chat component is available\n if (!this.chat) {\n this.chat = this.shadowRoot.querySelector('temba-chat');\n }\n\n // start the simulation if we haven't already\n if (!this.session) {\n this.startFlow();\n }\n }\n\n private async startFlow() {\n const now = new Date().toISOString();\n\n // set created_on to simulation start time\n this.contact = { ...this.contact, created_on: now };\n\n const body = {\n contact: this.contact,\n trigger: {\n type: 'manual',\n triggered_on: now,\n flow: { uuid: this.flow, name: 'New Chat' },\n params: {}\n }\n };\n\n try {\n const response = await postJSON(this.endpoint, body);\n this.updateRunContext(response.json as RunContext);\n } catch (error) {\n console.error('Failed to start simulation:', error);\n const errorEvent = {\n uuid: generateUUIDv7(),\n type: 'error',\n created_on: new Date(now),\n _rendered: {\n html: html`<p>Failed to start simulation</p>`,\n type: MessageType.Error\n }\n } as ContactEvent;\n if (this.chat) {\n this.chat.addMessages([errorEvent], null, true);\n } else {\n this.events = [...this.events, errorEvent];\n }\n }\n }\n\n private updateRunContext(runContext: RunContext, msgInEvt?: ContactEvent) {\n const newEvents: ContactEvent[] = [];\n\n // add the user's message if provided\n if (msgInEvt) {\n // ensure it has a UUID\n if (!msgInEvt.uuid) {\n msgInEvt.uuid = generateUUIDv7();\n }\n // ensure created_on is a Date object\n if (typeof msgInEvt.created_on === 'string') {\n msgInEvt.created_on = new Date(msgInEvt.created_on);\n }\n newEvents.push(msgInEvt);\n }\n\n if (runContext.session) {\n this.session = runContext.session;\n\n // update our contact with the latest from the session\n if (runContext.contact) {\n this.contact = runContext.contact;\n }\n }\n\n // store the context from the response\n if (runContext.context) {\n this.context = runContext.context;\n }\n\n // extract quick replies from the most recent sprint\n this.currentQuickReplies = [];\n\n if (runContext.events && runContext.events.length > 0) {\n for (const rawEvent of runContext.events) {\n // skip msg_received events from the server since we already added the user's message\n if (rawEvent.type === 'msg_received') {\n continue;\n }\n\n // skip msg_created/ivr_created events without a proper msg property\n if (\n (rawEvent.type === 'msg_created' ||\n rawEvent.type === 'ivr_created') &&\n !(rawEvent as any).msg\n ) {\n continue;\n }\n\n // convert to ContactEvent\n const event: ContactEvent = {\n ...rawEvent,\n uuid: rawEvent.uuid || generateUUIDv7(),\n created_on:\n typeof rawEvent.created_on === 'string'\n ? new Date(rawEvent.created_on)\n : rawEvent.created_on\n } as ContactEvent;\n\n // pre-render non-message events\n this.prerenderEvent(event);\n\n // extract quick replies from msg_created events\n if (event.type === 'msg_created' && (event as any).msg?.quick_replies) {\n this.currentQuickReplies = (event as any).msg.quick_replies;\n }\n\n const isMessage =\n event.type === 'msg_created' || event.type === 'ivr_created';\n const msg = (event as any).msg;\n\n // Check if the event should be displayed.\n // 1. If it's a message, it must have text or attachments\n if (isMessage) {\n const hasText = msg.text && msg.text.trim().length > 0;\n const hasAttachments = msg.attachments && msg.attachments.length > 0;\n if (!hasText && !hasAttachments) {\n continue;\n }\n }\n // 2. If it's not a message, it must have been rendered by prerenderEvent\n else if (!event._rendered) {\n continue;\n }\n\n newEvents.push(event);\n }\n }\n\n // add all new events to chat component if it exists\n if (this.chat) {\n this.chat.addMessages(newEvents, null, true);\n } else {\n // fallback: store events and add them once chat is ready\n this.events = [...this.events, ...newEvents];\n }\n\n this.sprinting = false;\n this.requestUpdate(); // trigger re-render for quick replies\n this.scrollToBottom();\n this.updateActivity();\n }\n\n private updateActivity() {\n if (!this.session) {\n return;\n }\n\n const pathCounts: { [key: string]: number } = {};\n const nodeCounts: { [nodeUUID: string]: number } = {};\n\n // iterate through all runs to get path segment counts\n for (const run of this.session.runs) {\n if (run.path) {\n for (let i = 0; i < run.path.length - 1; i++) {\n const step = run.path[i];\n const nextStep = run.path[i + 1];\n if (step.exit_uuid && nextStep.node_uuid) {\n const key = step.exit_uuid + ':' + nextStep.node_uuid;\n pathCounts[key] = (pathCounts[key] || 0) + 1;\n }\n }\n }\n\n // set node counts on the last step of any active/waiting runs\n if (run.status === 'active' || run.status === 'waiting') {\n if (run.path && run.path.length > 0) {\n const finalStep = run.path[run.path.length - 1];\n if (finalStep && finalStep.node_uuid) {\n nodeCounts[finalStep.node_uuid] =\n (nodeCounts[finalStep.node_uuid] || 0) + 1;\n }\n }\n }\n }\n\n // Update simulator activity in the store\n getStore().getState().updateSimulatorActivity({\n segments: pathCounts,\n nodes: nodeCounts\n });\n\n // Fire follow event if following is enabled\n if (this.following) {\n this.fireFollowEvent();\n }\n }\n\n private fireFollowEvent() {\n if (!this.session || !this.session.runs || this.session.runs.length === 0) {\n return;\n }\n\n // Find the first active or waiting run\n let activeRun = this.session.runs.find(\n (run: any) => run.status === 'active' || run.status === 'waiting'\n );\n\n // If no active/waiting run and simulation has ended, use the first completed run\n if (!activeRun) {\n activeRun = this.session.runs.find(\n (run: any) => run.status === 'completed'\n );\n }\n\n if (activeRun && activeRun.path && activeRun.path.length > 0) {\n const finalStep = activeRun.path[activeRun.path.length - 1];\n if (finalStep && finalStep.node_uuid) {\n this.fireCustomEvent(CustomEventType.FollowSimulation, {\n flowUuid: activeRun.flow?.uuid || this.flow,\n nodeUuid: finalStep.node_uuid\n });\n }\n }\n }\n\n private scrollToBottom() {\n if (this.chat) {\n // chat component handles scrolling, but we still need to focus input\n this.chat.scrollToBottom();\n setTimeout(() => {\n const input = this.shadowRoot?.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n if (input) {\n input.focus();\n }\n }, 50);\n return;\n }\n // wait for render, then scroll to bottom\n setTimeout(() => {\n const screen = this.shadowRoot?.querySelector('.phone-screen');\n if (screen) {\n screen.scrollTop = screen.scrollHeight;\n }\n // update previous count after animation completes\n this.previousEventCount = this.events.length;\n\n // return focus to input\n const input = this.shadowRoot?.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n if (input) {\n input.focus();\n }\n }, 50);\n }\n\n private prerenderEvent(event: ContactEvent) {\n // skip if already rendered or is a message event\n if (\n event._rendered ||\n event.type === Events.MSG_CREATED ||\n event.type === Events.MSG_RECEIVED\n ) {\n return;\n }\n\n // handle simulator-specific events (errors, warnings, failures)\n if (event.type === 'error' || event.type === 'failure') {\n event._rendered = {\n html: renderEvent(event, true),\n type: MessageType.Error\n };\n return;\n }\n\n if (event.type === 'warning') {\n event._rendered = {\n html: renderEvent(event, true),\n type: MessageType.Note\n };\n return;\n }\n\n // try to render as a standard event\n const rendered = renderEvent(event, true);\n if (rendered) {\n event._rendered = {\n html: rendered,\n type: MessageType.Inline\n };\n }\n }\n\n private handleClose() {\n const phoneWindow = this.shadowRoot.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n phoneWindow.handleClose();\n this.isVisible = false;\n getStore().getState().setSimulatorActive(false);\n }\n\n private handleReset() {\n // reset simulation state\n this.events = [];\n this.session = null;\n this.context = null;\n this.inputValue = '';\n this.sprinting = false;\n this.previousEventCount = 0;\n this.currentQuickReplies = [];\n\n // reset chat component\n if (this.chat) {\n this.chat.reset();\n }\n\n // Clear simulator activity data\n getStore().getState().updateSimulatorActivity({\n segments: {},\n nodes: {}\n });\n\n // reset contact to initial state\n this.contact = {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {},\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n };\n\n // restart the flow\n this.startFlow();\n }\n\n private handleToggleFollow() {\n this.following = !this.following;\n }\n\n private handleCycleSize() {\n const sizes: Array<'small' | 'medium' | 'large'> = [\n 'small',\n 'medium',\n 'large'\n ];\n const currentIndex = sizes.indexOf(this.size);\n const nextIndex = (currentIndex + 1) % sizes.length;\n this.size = sizes[nextIndex];\n }\n\n private handleToggleContextExplorer() {\n this.contextExplorerOpen = !this.contextExplorerOpen;\n\n // if opening the context explorer, ensure it's not off-screen\n if (this.contextExplorerOpen) {\n requestAnimationFrame(() => {\n const phoneWindow = this.shadowRoot?.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n if (phoneWindow) {\n const padding = 20;\n const contextExplorerLeft = this.sizeConfig.contextOffset;\n const minWindowLeft = padding - contextExplorerLeft;\n\n if (phoneWindow.left < minWindowLeft) {\n phoneWindow.left = minWindowLeft;\n }\n }\n });\n }\n }\n\n private togglePath(path: string) {\n if (this.expandedPaths.has(path)) {\n this.expandedPaths.delete(path);\n } else {\n this.expandedPaths.add(path);\n }\n this.requestUpdate();\n }\n\n private isExpandable(value: any): boolean {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n if (Array.isArray(value)) {\n return value.length > 0;\n }\n\n // check if object has keys other than __default__\n const keys = Object.keys(value).filter((key) => key !== '__default__');\n return keys.length > 0;\n }\n\n private renderContextValue(value: any): TemplateResult | string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'boolean')\n return html`<span class=\"context-value\">${value}</span>`;\n if (typeof value === 'number')\n return html`<span class=\"context-value\">${value}</span>`;\n if (typeof value === 'string')\n return html`<span class=\"context-value\">${value}</span>`;\n if (Array.isArray(value))\n return html`<span class=\"context-value\">[${value.length}]</span>`;\n return '';\n }\n\n private buildExpression(path: string): string {\n return `@${path}`;\n }\n\n private async handleCopyExpression(\n path: string,\n event: Event\n ): Promise<void> {\n event.stopPropagation();\n const expression = this.buildExpression(path);\n try {\n await navigator.clipboard.writeText(expression);\n this.copiedExpression = expression;\n // clear the toast after 2 seconds\n setTimeout(() => {\n this.copiedExpression = '';\n }, 2000);\n } catch (err) {\n console.error('Failed to copy expression:', err);\n }\n }\n\n private handleToggleShowAllKeys() {\n this.showAllKeys = !this.showAllKeys;\n this.toastMessage = this.showAllKeys\n ? 'Showing all keys'\n : 'Filtering out keys without values';\n // clear the toast after 2 seconds\n setTimeout(() => {\n this.toastMessage = '';\n }, 2000);\n }\n\n private renderContextTree(\n obj: any,\n path: string = ''\n ): TemplateResult | TemplateResult[] {\n if (!obj || typeof obj !== 'object') {\n return html``;\n }\n\n let entries = Array.isArray(obj)\n ? obj.map((v, i) => [String(i), v])\n : Object.entries(obj).filter(([key]) => key !== '__default__');\n\n // filter out keys without values if showAllKeys is false\n if (!this.showAllKeys) {\n entries = entries.filter(([, value]) => {\n // keep if expandable (has children)\n if (this.isExpandable(value)) return true;\n // keep if it has a displayable value (not null/undefined)\n if (value === null || value === undefined) return false;\n // keep primitives with values\n return (\n typeof value === 'boolean' ||\n typeof value === 'number' ||\n typeof value === 'string' ||\n Array.isArray(value)\n );\n });\n }\n\n return html`${entries.map(([key, value]) => {\n const currentPath = path ? `${path}.${key}` : key;\n const isExpanded = this.expandedPaths.has(currentPath);\n const expandable = this.isExpandable(value);\n\n // check if this object has a __default__ value\n let displayValue = value;\n\n if (\n expandable &&\n !Array.isArray(value) &&\n value !== null &&\n typeof value === 'object' &&\n '__default__' in value\n ) {\n displayValue = value.__default__;\n }\n\n return html`\n <div>\n <div\n class=\"context-item ${expandable ? 'context-item-expandable' : ''}\"\n @click=${() => expandable && this.togglePath(currentPath)}\n >\n ${expandable\n ? html`<span\n class=\"context-expand-icon ${isExpanded ? 'expanded' : ''}\"\n >›</span\n >`\n : html`<span class=\"context-expand-icon\"></span>`}\n <span class=\"context-key ${expandable ? 'has-value' : ''}\"\n >${key}\n <temba-icon\n class=\"context-copy-icon\"\n name=\"copy\"\n size=\"0.9\"\n @click=${(e: Event) =>\n this.handleCopyExpression(currentPath, e)}\n ></temba-icon>\n </span>\n ${!isExpanded ? this.renderContextValue(displayValue) : html``}\n </div>\n ${isExpanded\n ? html`<div class=\"context-children\">\n ${this.renderContextTree(value, currentPath)}\n </div>`\n : html``}\n </div>\n `;\n })}`;\n }\n\n private async resume(text: string, attachment?: string) {\n if ((!text && !attachment) || !this.session) {\n return;\n }\n\n this.sprinting = true;\n this.inputValue = '';\n this.currentQuickReplies = [];\n this.attachmentMenuOpen = false;\n\n const now = new Date().toISOString();\n\n // create the event for the API (with ISO string date)\n const msgInEvtForAPI = {\n uuid: generateUUIDv7(),\n type: 'msg_received',\n created_on: now,\n msg: {\n uuid: generateUUIDv7(),\n text: text || '',\n urn: this.contact.urns[0],\n direction: 'in',\n type: 'text',\n attachments: attachment ? [attachment] : [],\n quick_replies: [],\n channel: { uuid: generateUUIDv7(), name: 'Simulator' }\n }\n };\n\n // create the ContactEvent for display (with Date object)\n const msgInEvt = {\n ...msgInEvtForAPI,\n created_on: new Date(now)\n } as ContactEvent;\n\n // show user's message immediately via chat component\n if (this.chat) {\n this.chat.addMessages([msgInEvt], null, true);\n } else {\n this.events = [...this.events, msgInEvt];\n }\n this.requestUpdate();\n this.scrollToBottom();\n\n const body = {\n session: this.session,\n contact: this.contact,\n resume: {\n type: 'msg',\n event: msgInEvtForAPI,\n resumed_on: now\n }\n };\n\n try {\n const response = await postJSON(this.endpoint, body);\n\n // add a small delay before showing the reply to simulate typing\n await new Promise((resolve) => setTimeout(resolve, 400));\n\n // pass null for msgInEvt since we already added it\n this.updateRunContext(response.json as RunContext, null);\n } catch (error) {\n console.error('Failed to resume simulation:', error);\n const errorEvent = {\n uuid: generateUUIDv7(),\n type: 'error',\n created_on: new Date(now),\n _rendered: {\n html: html`<p>Failed to send message</p>`,\n type: MessageType.Error\n }\n } as ContactEvent;\n if (this.chat) {\n this.chat.addMessages([errorEvent], null, true);\n } else {\n this.events = [...this.events, errorEvent];\n }\n this.sprinting = false;\n }\n }\n\n private handleKeyUp(evt: KeyboardEvent) {\n if (evt.key === 'Enter') {\n const input = evt.target as HTMLInputElement;\n const text = input.value.trim();\n if (text) {\n this.resume(text);\n }\n }\n }\n\n private handleInput(evt: Event) {\n const input = evt.target as HTMLInputElement;\n this.inputValue = input.value;\n }\n\n private handleQuickReplyClick(text: string) {\n if (!this.sprinting && text) {\n this.resume(text);\n }\n }\n\n private handleToggleAttachmentMenu() {\n this.attachmentMenuOpen = !this.attachmentMenuOpen;\n }\n\n private handleClickOutsideAttachmentMenu(event: MouseEvent) {\n if (!this.attachmentMenuOpen) {\n return;\n }\n\n const menu = this.shadowRoot?.querySelector('.attachment-menu');\n const button = this.shadowRoot?.querySelector('.attachment-button');\n\n if (!menu || !button) {\n return;\n }\n\n // check if click is outside both menu and button\n const clickedInsideMenu = menu.contains(event.target as Node);\n const clickedInsideButton = button.contains(event.target as Node);\n\n if (!clickedInsideMenu && !clickedInsideButton) {\n this.attachmentMenuOpen = false;\n }\n }\n\n private handleSendAttachment(attachmentType: string) {\n let attachment = '';\n switch (attachmentType) {\n case 'image':\n attachment = `image/jpeg:${TEST_IMAGES[this.imageIndex]}`;\n this.imageIndex = (this.imageIndex + 1) % TEST_IMAGES.length;\n break;\n case 'video':\n attachment = `video/mp4:${TEST_VIDEOS[this.videoIndex]}`;\n this.videoIndex = (this.videoIndex + 1) % TEST_VIDEOS.length;\n break;\n case 'audio':\n attachment = `audio/mp3:${TEST_AUDIO[this.audioIndex]}`;\n this.audioIndex = (this.audioIndex + 1) % TEST_AUDIO.length;\n break;\n case 'location':\n attachment = TEST_LOCATIONS[this.locationIndex];\n this.locationIndex = (this.locationIndex + 1) % TEST_LOCATIONS.length;\n break;\n }\n\n if (attachment) {\n this.resume('', attachment);\n }\n }\n\n private updateBottomInputHeight() {\n requestAnimationFrame(() => {\n const bottomContainer = this.shadowRoot?.querySelector(\n '.bottom-input-container'\n ) as HTMLElement;\n if (bottomContainer) {\n const height = bottomContainer.offsetHeight;\n this.style.setProperty('--bottom-input-height', `${height}px`);\n }\n });\n }\n\n protected render(): TemplateResult {\n if (this.viewingRevision || this.definition?.nodes.length === 0) {\n return html``;\n }\n\n const config = this.sizeConfig;\n\n // set CSS custom properties dynamically based on size\n const styleVars = `\n --phone-width: ${config.phoneWidth}px;\n --phone-total-height: ${config.phoneTotalHeight}px;\n --context-width: ${config.contextWidth}px;\n --context-offset: ${config.contextOffset}px;\n --option-pane-width: ${config.optionPaneWidth}px;\n --option-pane-gap: ${config.optionPaneGap}px;\n --window-padding: ${config.windowPadding}px;\n --phone-screen-height: ${config.phoneScreenHeight}px;\n --context-height: ${config.contextHeight}px;\n --context-closed-left: ${this.contextClosedLeft}px;\n --cutout-height: ${config.cutoutHeight}px;\n --cutout-padding: ${config.cutoutPadding}px;\n --cutout-font-size: ${config.cutoutFontSize}px;\n --cutout-island-width: ${config.cutoutIslandWidth}px;\n --cutout-island-height: ${config.cutoutIslandHeight}px;\n --cutout-island-top: ${config.cutoutIslandTop}px;\n --animation-time: ${this.animationTime}ms;\n `;\n\n return html`\n <temba-floating-window\n style=\"--transition-duration: ${this.animationTime}ms\"\n id=\"phone-window\"\n width=\"${this.windowWidth}\"\n leftBoundaryMargin=\"${this.leftBoundaryMargin}\"\n bottomBoundaryMargin=\"${config.windowPadding}\"\n topBoundaryMargin=\"${config.windowPadding}\"\n height=\"${config.phoneTotalHeight}\"\n top=\"0\"\n chromeless\n >\n <div class=\"phone-simulator\" style=\"${styleVars}\">\n <div\n class=\"context-explorer ${this.contextExplorerOpen\n ? 'open'\n : ''} ${this.isVisible ? 'visible' : 'hidden'}\"\n >\n <div class=\"context-explorer-scroll\">\n ${this.context\n ? this.renderContextTree(this.context)\n : html`<div\n style=\"color: #9ca3af; padding: 8px; text-align: center;\"\n >\n No context available\n </div>`}\n </div>\n <div class=\"context-gutter\">\n <div\n class=\"context-gutter-btn ${this.showAllKeys ? '' : 'active'}\"\n @click=${this.handleToggleShowAllKeys}\n title=\"${this.showAllKeys\n ? 'Show keys with values only'\n : 'Show all keys'}\"\n >\n <temba-icon\n name=\"${this.showAllKeys ? 'filter' : 'filter'}\"\n size=\"1\"\n ></temba-icon>\n </div>\n <div class=\"context-gutter-spacer\"></div>\n <div\n class=\"context-gutter-btn\"\n @click=${this.handleToggleContextExplorer}\n title=\"Close\"\n >\n <temba-icon name=\"x\" size=\"1\"></temba-icon>\n </div>\n </div>\n ${this.copiedExpression\n ? html`<div class=\"context-toast\">\n Copied\n <span class=\"expression\">${this.copiedExpression}</span>\n to the clipboard\n </div>`\n : this.toastMessage\n ? html`<div class=\"context-toast\">${this.toastMessage}</div>`\n : html``}\n </div>\n\n <div\n class=\"phone-frame\"\n style=\"pointer-events: ${this.isVisible ? 'all' : 'none'}\"\n >\n <div class=\"phone-top drag-handle\">\n <div class=\"phone-notch\">\n <div class=\"dynamic-island\"></div>\n </div>\n </div>\n <temba-chat class=\"phone-screen\" .showTimestamps=${false}>\n </temba-chat>\n <div class=\"custom-scrollbar-container\">\n <div class=\"custom-scrollbar-content\"></div>\n </div>\n\n <div class=\"bottom-input-container\">\n ${this.currentQuickReplies.length > 0\n ? html`<div class=\"quick-replies-container\">\n ${this.currentQuickReplies.map(\n (qr) => html`\n <button\n class=\"quick-reply-btn\"\n @click=${() => this.handleQuickReplyClick(qr.text)}\n ?disabled=${this.sprinting}\n >\n ${qr.text}\n </button>\n `\n )}\n </div>`\n : null}\n <div class=\"message-input\">\n <button\n class=\"attachment-button\"\n @click=${this.handleToggleAttachmentMenu}\n ?disabled=${this.sprinting}\n >\n <temba-icon name=\"plus\" size=\"1.5\"></temba-icon>\n </button>\n <input\n type=\"text\"\n placeholder=\"Enter Message\"\n .value=${this.inputValue}\n @input=${this.handleInput}\n @keyup=${this.handleKeyUp}\n ?disabled=${this.sprinting}\n />\n <div\n class=\"attachment-menu ${this.attachmentMenuOpen\n ? 'open'\n : ''}\"\n >\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('image')}\n >\n <temba-icon name=\"attachment_image\" size=\"1.2\"></temba-icon>\n <span>Image</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('video')}\n >\n <temba-icon name=\"attachment_video\" size=\"1.2\"></temba-icon>\n <span>Video</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('audio')}\n >\n <temba-icon name=\"attachment_audio\" size=\"1.2\"></temba-icon>\n <span>Audio</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('location')}\n >\n <temba-icon\n name=\"attachment_location\"\n size=\"1.2\"\n ></temba-icon>\n <span>Location</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div\n class=\"option-pane\"\n style=\"pointer-events:${this.isVisible ? 'all' : 'none'}\"\n >\n <button class=\"option-btn\" @click=${this.handleClose} title=\"Close\">\n <temba-icon name=\"x\" size=\"1.5\"></temba-icon>\n </button>\n <button\n class=\"option-btn ${this.following ? 'active' : ''}\"\n @click=${this.handleToggleFollow}\n title=\"${this.following ? 'Following' : 'Follow'}\"\n >\n <temba-icon name=\"follow\" size=\"1.5\"></temba-icon>\n </button>\n\n <button\n class=\"option-btn ${this.contextExplorerOpen ? 'active' : ''}\"\n @click=${this.handleToggleContextExplorer}\n title=\"Context Explorer\"\n >\n <temba-icon name=\"expressions\" size=\"1.5\"></temba-icon>\n </button>\n\n <button\n class=\"option-btn\"\n @click=${this.handleCycleSize}\n title=\"Size: ${this.size}\"\n >\n ${this.size === 'small'\n ? 'S'\n : this.size === 'medium'\n ? 'M'\n : 'L'}\n </button>\n\n <button class=\"option-btn\" @click=${this.handleReset} title=\"Reset\">\n <temba-icon name=\"delete\" size=\"1.5\"></temba-icon>\n </button>\n </div>\n </div>\n </temba-floating-window>\n\n <temba-floating-tab\n id=\"phone-tab\"\n icon=\"simulator\"\n label=\"Phone Simulator\"\n color=\"#10b981\"\n order=\"4\"\n .hidden=${this.isVisible}\n @temba-button-clicked=${this.handleShow}\n ></temba-floating-tab>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"Simulator.js","sourceRoot":"","sources":["../../../src/simulator/Simulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, TemplateResult } from 'lit-html';\nimport { RapidElement } from '../RapidElement';\nimport { FloatingWindow } from '../layout/FloatingWindow';\nimport { css, PropertyValueMap } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { postJSON, fromCookie, generateUUIDv7 } from '../utils';\nimport { getStore } from '../store/Store';\nimport { AppState, fromStore, zustand } from '../store/AppState';\nimport { FlowDefinition } from '../store/flow-definition';\nimport { CustomEventType } from '../interfaces';\nimport { Chat, ContactEvent, MessageType } from '../display/Chat';\nimport { Events, renderEvent } from '../events/eventRenderers';\n\n// test attachment URLs\nconst TEST_IMAGES = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_a.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_b.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_c.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_d.jpg'\n];\n\nconst TEST_VIDEOS = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_video_a.mp4'\n];\n\nconst TEST_AUDIO = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_audio_a.mp3'\n];\n\nconst TEST_LOCATIONS = [\n 'geo:47.6062,-122.3321', // Seattle\n 'geo:-0.1807,-78.4678', // Quito\n 'geo:-2.9001,-79.0059', // Cuenca\n 'geo:-1.9536,30.0606' // Kigali\n];\n\ninterface Contact {\n uuid: string;\n name?: string;\n urns: string[];\n fields?: { [key: string]: any };\n groups?: any[];\n language?: string;\n status?: string;\n created_on?: string;\n}\n\ninterface Session {\n environment: any;\n runs: any[];\n status: string;\n trigger: any;\n wait?: any;\n}\n\ninterface Message {\n uuid: string;\n text?: string;\n urn: string;\n attachments?: string[];\n quick_replies?: any[];\n}\n\ninterface Event {\n type: string;\n created_on: string;\n msg?: Message;\n [key: string]: any;\n}\n\ninterface RunContext {\n session: Session;\n events: Event[];\n context?: any;\n contact?: Contact;\n}\n\ninterface SimulatorSize {\n phoneWidth: number;\n phoneTotalHeight: number;\n phoneScreenHeight: number;\n contextWidth: number;\n contextHeight: number;\n contextOffset: number;\n optionPaneWidth: number;\n optionPaneGap: number;\n windowPadding: number;\n cutoutHeight: number;\n cutoutPadding: number;\n cutoutFontSize: number;\n cutoutIslandWidth: number;\n cutoutIslandHeight: number;\n cutoutIslandTop: number;\n}\n\nconst SIMULATOR_SIZES: Record<string, SimulatorSize> = {\n small: {\n phoneWidth: 270,\n phoneTotalHeight: 530,\n phoneScreenHeight: 376,\n contextWidth: 336,\n contextHeight: 416,\n contextOffset: 48,\n optionPaneWidth: 44,\n optionPaneGap: 10,\n windowPadding: 24,\n cutoutHeight: 32,\n cutoutPadding: 12,\n cutoutFontSize: 10,\n cutoutIslandWidth: 80,\n cutoutIslandHeight: 20,\n cutoutIslandTop: 6\n },\n medium: {\n phoneWidth: 300,\n phoneTotalHeight: 600,\n phoneScreenHeight: 470,\n contextWidth: 420,\n contextHeight: 520,\n contextOffset: 60,\n optionPaneWidth: 44,\n optionPaneGap: 12,\n windowPadding: 30,\n cutoutHeight: 40,\n cutoutPadding: 16,\n cutoutFontSize: 12,\n cutoutIslandWidth: 100,\n cutoutIslandHeight: 24,\n cutoutIslandTop: 8\n },\n large: {\n phoneWidth: 360,\n phoneTotalHeight: 700,\n phoneScreenHeight: 564,\n contextWidth: 504,\n contextHeight: 624,\n contextOffset: 72,\n optionPaneWidth: 44,\n optionPaneGap: 14,\n windowPadding: 36,\n cutoutHeight: 50,\n cutoutPadding: 20,\n cutoutFontSize: 14,\n cutoutIslandWidth: 120,\n cutoutIslandHeight: 30,\n cutoutIslandTop: 10\n }\n};\n\nexport class Simulator extends RapidElement {\n static get styles() {\n return css`\n temba-floating-tab {\n --floating-tab-right: 15px;\n }\n\n :host {\n /* size-specific dimensions are set dynamically via inline styles */\n --phone-width: 300px;\n --phone-total-height: 720px;\n --context-width: 420px;\n --context-offset: 60px;\n --option-pane-width: 44px;\n --option-pane-gap: 12px;\n --window-padding: 30px;\n --phone-screen-height: 470px;\n --context-height: 520px;\n --context-closed-left: 332px;\n --animation-time: 200ms;\n }\n\n .phone-simulator {\n padding-left: calc(var(--context-width) + var(--context-offset));\n padding-top: var(--window-padding);\n padding-bottom: var(--window-padding);\n position: relative;\n display: flex;\n align-items: flex-start;\n }\n\n .option-pane {\n margin-top: var(--window-padding);\n margin-left: var(--option-pane-gap);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 6px;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(10px);\n border-radius: 16px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n }\n .option-btn {\n background: rgba(255, 255, 255, 0.1);\n border: none;\n border-radius: 12px;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all var(--animation-time) ease;\n color: white;\n }\n .option-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(1.05);\n }\n .option-btn:active {\n transform: scale(0.95);\n }\n .option-btn.active {\n background: var(--color-primary-dark);\n color: white;\n }\n .option-btn.active:hover {\n background: var(--color-primary-dark);\n }\n\n .phone-frame {\n width: var(--phone-width);\n height: var(--phone-total-height);\n border-radius: 40px;\n border: 6px solid #1f2937;\n box-shadow: 0 0px 30px rgba(0, 0, 0, 0.4);\n background: #000;\n position: relative;\n overflow: hidden;\n z-index: 2;\n }\n\n .context-explorer {\n width: var(--context-width);\n height: var(--context-height);\n border-top-left-radius: 16px;\n border-bottom-left-radius: 16px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n position: absolute;\n left: var(--context-closed-left);\n top: calc(var(--window-padding) + 40px);\n z-index: 1;\n font-size: 13px;\n color: #374151;\n transition: left calc(var(--animation-time) * 1.5) ease-out,\n opacity calc(var(--animation-time) * 1.5) ease-out;\n opacity: 0;\n pointer-events: none;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(10px);\n display: flex;\n flex-direction: column;\n padding: 12px;\n }\n\n .context-gutter {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 6px;\n\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 4px;\n margin-right: 32px;\n margin-top: 8px;\n flex-shrink: 0;\n }\n\n .context-gutter-btn {\n width: 14px;\n height: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n border-radius: 6px;\n transition: background var(--animation-time) ease;\n color: rgba(255, 255, 255, 0.6);\n padding: 4px;\n }\n\n .context-gutter-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.9);\n }\n\n .context-gutter-btn.active {\n color: #c084fc;\n }\n\n .context-gutter-spacer {\n flex: 1;\n }\n\n .context-explorer-scroll {\n scrollbar-color: rgba(255, 255, 255, 0.3) #4a4a4a;\n scrollbar-width: thin;\n height: 100%;\n overflow-y: scroll;\n padding-right: 10px;\n margin-right: 30px;\n flex-grow: 1;\n }\n\n .context-explorer-bleed {\n height: 100%;\n width: 0px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar {\n width: 18px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 4px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.5);\n }\n\n /* Custom scrollbar for chat area to allow content to flow behind input */\n .custom-scrollbar-container {\n position: absolute;\n top: 40px;\n bottom: var(--bottom-input-height, 60px);\n right: 4px;\n width: 10px;\n z-index: 20;\n overflow-y: auto;\n overflow-x: hidden;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar {\n width: 6px;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.4);\n }\n\n .custom-scrollbar-content {\n width: 100%;\n }\n\n .context-explorer.open {\n left: var(--context-offset);\n opacity: 1;\n pointer-events: auto;\n }\n\n .context-explorer.hidden {\n pointer-events: none !important;\n }\n\n .context-item {\n display: flex;\n align-items: flex-start;\n padding: 2px 4px;\n cursor: pointer;\n user-select: none;\n }\n\n .context-item:hover {\n background: rgba(0, 0, 0, 0.05);\n }\n\n .context-item-expandable {\n display: flex;\n align-items: center;\n }\n\n .context-expand-icon {\n width: 16px;\n display: inline-block;\n text-align: center;\n flex-shrink: 0;\n transition: transform var(--animation-time) ease;\n color: #ffffff;\n }\n\n .context-expand-icon.expanded {\n transform: rotate(90deg);\n }\n\n .context-key {\n color: #ffffff;\n flex-shrink: 0;\n margin-right: 8px;\n display: flex;\n }\n\n .context-key.has-value {\n color: #e8b5e8;\n }\n\n .context-value {\n color: #aaa;\n flex: 1;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .context-children {\n margin-left: 16px;\n }\n\n .context-copy-icon {\n opacity: 0;\n margin-left: 4px;\n transition: opacity var(--animation-time) ease;\n cursor: pointer;\n color: #ccc;\n }\n\n .context-item:hover .context-copy-icon {\n opacity: 1;\n }\n\n .context-toast {\n position: absolute;\n bottom: 60px;\n left: 50%;\n transform: translateX(-50%);\n background: #666;\n color: white;\n padding: 12px 12px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n font-size: 13px;\n z-index: 10;\n animation: slideInUp var(--animation-time) ease-out;\n }\n\n .context-toast .expression {\n color: #e8b5e8;\n font-weight: 600;\n }\n\n @keyframes slideInUp {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n }\n\n .phone-top {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 10;\n cursor: grab;\n }\n .phone-notch {\n background: transparent;\n height: var(--cutout-height);\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 var(--cutout-padding);\n }\n .phone-notch::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background: linear-gradient(\n to bottom,\n rgba(0, 0, 0, 0.3) 0%,\n rgba(0, 0, 0, 0.2) 50%,\n transparent 100%\n );\n z-index: -1;\n }\n .dynamic-island {\n top: var(--cutout-island-top);\n left: 50%;\n\n width: var(--cutout-island-width);\n height: var(--cutout-island-height);\n background: #000;\n border-radius: calc(var(--cutout-island-height) / 1.5);\n z-index: 1;\n }\n .phone-notch .time {\n color: #000;\n font-size: var(--cutout-font-size);\n font-weight: 600;\n }\n .phone-notch .status-icons {\n display: flex;\n gap: 4px;\n align-items: center;\n }\n .phone-notch .status-icons span {\n color: #000;\n font-size: var(--cutout-font-size);\n }\n .phone-header {\n background: transparent;\n padding: 10px 15px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n cursor: move;\n user-select: none;\n border-bottom: none;\n pointer-events: all;\n }\n\n .phone-screen {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: white;\n display: flex;\n flex-direction: column;\n }\n\n temba-chat {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n --color-chat-in: #e5e5ea;\n --color-chat-out: #007aff;\n --chat-top-padding: calc(var(--cutout-height));\n --chat-bottom-padding: calc(var(--bottom-input-height, 80px) - 10px);\n }\n\n .bottom-input-container {\n position: absolute;\n bottom: 0px;\n left: 0px;\n right: 0px;\n z-index: 10;\n }\n\n .bottom-input-container::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.45);\n backdrop-filter: blur(10px);\n -webkit-mask-image: linear-gradient(to bottom, transparent, black 20px);\n mask-image: linear-gradient(to bottom, transparent, black 20px);\n z-index: -1;\n }\n\n .quick-replies-container {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 6px;\n z-index: 9;\n }\n\n .quick-reply-btn {\n padding: 4px 8px;\n border-radius: 18px;\n border: 1px solid var(--color-primary, #007aff);\n background: white;\n color: var(--color-primary, #007aff);\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n }\n\n .quick-reply-btn:hover:not(:disabled) {\n background: var(--color-primary, #007aff);\n color: white;\n }\n\n .quick-reply-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .message-input {\n padding: 8px 12px;\n border-top: none;\n display: flex;\n align-items: center;\n gap: 8px;\n z-index: 10;\n }\n .message-input input {\n flex: 1;\n border: 1px solid #c6c6c857;\n border-radius: 20px;\n padding: 8px 15px;\n font-size: 15px;\n margin-bottom: 5px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n outline: none;\n }\n .message-input input::placeholder {\n color: #8e8e93;\n }\n .attachment-button {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: #fff;\n border: 1px solid #c6c6c857;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n flex-shrink: 0;\n margin-bottom: 5px;\n transition: all var(--animation-time) ease;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n color: #000;\n }\n .attachment-button:hover {\n background: #f8f8f8ff;\n transform: scale(1.05);\n }\n .attachment-button:active {\n transform: scale(0.95);\n }\n .attachment-menu {\n position: absolute;\n bottom: 55px;\n left: 12px;\n background: white;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n padding: 8px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n opacity: 0;\n pointer-events: none;\n transform: translateY(10px);\n transition: opacity var(--animation-time) ease, transform 0.2s ease;\n z-index: 20;\n }\n .attachment-menu.open {\n opacity: 1;\n pointer-events: all;\n transform: translateY(0);\n }\n .attachment-menu-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n cursor: pointer;\n transition: background var(--animation-time) ease;\n white-space: nowrap;\n font-size: 14px;\n color: #1f2937;\n }\n .attachment-menu-item:hover {\n background: #f3f4f6;\n }\n .attachment-menu-item temba-icon {\n color: #007aff;\n }\n `;\n }\n\n @fromStore(zustand, (state: AppState) => state.flowDefinition)\n private definition!: FlowDefinition;\n\n @fromStore(zustand, (state: AppState) => state.viewingRevision)\n private viewingRevision!: boolean;\n\n @property({ type: String })\n flow = '';\n\n @property({ type: String })\n endpoint = '';\n\n @property({ type: Number })\n animationTime = 200;\n\n @fromCookie('simulator-size', 'small')\n size: 'small' | 'medium' | 'large';\n\n @property({ type: Array })\n private events: ContactEvent[] = [];\n\n private previousEventCount = 0;\n private chat: Chat = null;\n\n @property({ type: Object })\n private session: Session | null = null;\n\n @property({ type: Object })\n private context: any = null;\n\n @property({ type: Object })\n private contact: Contact = {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {},\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n };\n\n @property({ type: Boolean })\n private sprinting = false;\n\n @property({ type: String })\n private inputValue = '';\n\n @fromCookie('simulator-follow', true)\n private following: boolean;\n\n @fromCookie('simulator-context-open', false)\n private contextExplorerOpen: boolean;\n\n @property({ type: Object })\n private expandedPaths: Set<string> = new Set();\n\n @property({ type: String })\n private copiedExpression = '';\n\n @property({ type: String })\n private toastMessage = '';\n\n @property({ type: Boolean })\n private showAllKeys = true;\n\n private previousWindowWidth = 0;\n\n @property({ type: Array })\n private currentQuickReplies: any[] = [];\n\n @property({ type: Boolean })\n private isVisible = false;\n\n @property({ type: Boolean })\n private attachmentMenuOpen = false;\n\n private boundClickOutsideHandler: ((event: MouseEvent) => void) | null = null;\n\n // attachment cycling indices - initialized randomly\n private imageIndex = Math.floor(Math.random() * TEST_IMAGES.length);\n private videoIndex = Math.floor(Math.random() * TEST_VIDEOS.length);\n private audioIndex = Math.floor(Math.random() * TEST_AUDIO.length);\n private locationIndex = Math.floor(Math.random() * TEST_LOCATIONS.length);\n\n // method to reset attachment indices for testing\n public resetAttachmentIndices() {\n this.imageIndex = 2;\n this.videoIndex = 0;\n this.audioIndex = 0;\n this.locationIndex = 0;\n }\n\n private get sizeConfig(): SimulatorSize {\n return SIMULATOR_SIZES[this.size] || SIMULATOR_SIZES.medium;\n }\n\n private get windowWidth(): number {\n const config = this.sizeConfig;\n return (\n config.contextWidth +\n config.phoneWidth +\n config.optionPaneWidth +\n config.optionPaneGap +\n config.contextOffset\n );\n }\n\n private get leftBoundaryMargin(): number {\n const config = this.sizeConfig;\n return config.contextWidth + config.contextOffset;\n }\n\n private get contextClosedLeft(): number {\n const config = this.sizeConfig;\n return config.contextWidth + config.contextOffset - config.phoneWidth;\n }\n\n public connectedCallback() {\n super.connectedCallback();\n }\n\n protected firstUpdated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changes);\n this.chat = this.shadowRoot.querySelector('temba-chat');\n\n // if we have events that were collected before chat was ready, add them now\n if (this.chat && this.events.length > 0) {\n this.chat.addMessages(this.events, null, true);\n }\n\n this.setupCustomScrollbar();\n }\n\n private setupCustomScrollbar() {\n const chat = this.shadowRoot?.querySelector('temba-chat') as Chat;\n const scrollContainer = this.shadowRoot?.querySelector(\n '.custom-scrollbar-container'\n ) as HTMLElement;\n const scrollContent = this.shadowRoot?.querySelector(\n '.custom-scrollbar-content'\n ) as HTMLElement;\n\n if (!chat || !scrollContainer || !scrollContent) return;\n\n chat.updateComplete.then(() => {\n const chatScroll = chat.shadowRoot?.querySelector(\n '.scroll'\n ) as HTMLElement;\n if (!chatScroll) return;\n\n let ignoreScroll = false;\n\n // Sync from chat to custom scrollbar\n chatScroll.addEventListener('scroll', () => {\n if (!ignoreScroll) {\n ignoreScroll = true;\n // Chat: 0 (bottom) ... -Max (top) (Negative scrolling)\n // Custom: Max (bottom) ... 0 (top) (Positive scrolling)\n\n const maxScroll =\n scrollContainer.scrollHeight - scrollContainer.clientHeight;\n // Math.abs to handle negative scrollTop\n const distanceFromBottom = Math.abs(chatScroll.scrollTop);\n const newCustomScrollTop = maxScroll - distanceFromBottom;\n\n scrollContainer.scrollTop = newCustomScrollTop;\n\n requestAnimationFrame(() => (ignoreScroll = false));\n }\n });\n\n // Sync from custom scrollbar to chat\n scrollContainer.addEventListener('scroll', () => {\n if (!ignoreScroll) {\n ignoreScroll = true;\n\n const maxScroll =\n scrollContainer.scrollHeight - scrollContainer.clientHeight;\n const distanceFromBottom = maxScroll - scrollContainer.scrollTop;\n\n // chat scrollTop should be -distanceFromBottom\n chatScroll.scrollTop = -distanceFromBottom;\n\n requestAnimationFrame(() => (ignoreScroll = false));\n }\n });\n\n // Sync height\n const syncHeight = () => {\n const chatMaxScroll = chatScroll.scrollHeight - chatScroll.clientHeight;\n const customClientHeight = scrollContainer.clientHeight;\n\n // ensure minimum height\n if (chatMaxScroll <= 0) {\n scrollContent.style.height = '100%';\n return;\n }\n\n const newHeight = chatMaxScroll + customClientHeight;\n scrollContent.style.height = `${newHeight}px`;\n\n // If we were effectively at the bottom, stay at the bottom\n // This is a heuristic, assuming if we're close enough we're \"at bottom\"\n // But the Chat component handles scrollToBottom on new messages, which fires scroll event,\n // which updates us. So we might not need to force it here unless resize happens without message.\n if (Math.abs(chatScroll.scrollTop) < 5) {\n scrollContainer.scrollTop = scrollContainer.scrollHeight;\n }\n };\n\n // Observe changes\n const observer = new MutationObserver(syncHeight);\n observer.observe(chatScroll, {\n childList: true,\n subtree: true,\n attributes: true\n });\n\n const resizeObserver = new ResizeObserver(syncHeight);\n resizeObserver.observe(chatScroll);\n\n // Initial sync\n syncHeight();\n });\n }\n\n protected updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n\n if (\n changes.has('currentQuickReplies') ||\n changes.has('keyboardVisible') ||\n changes.has('attachmentMenuOpen')\n ) {\n this.updateBottomInputHeight();\n }\n\n if (changes.has('flow') && this.flow) {\n this.endpoint = `/flow/simulate/${this.flow}/`;\n }\n\n // handle attachment menu click outside listener\n if (changes.has('attachmentMenuOpen')) {\n if (this.attachmentMenuOpen) {\n // create bound handler if it doesn't exist\n if (!this.boundClickOutsideHandler) {\n this.boundClickOutsideHandler =\n this.handleClickOutsideAttachmentMenu.bind(this);\n }\n // add listener when menu opens\n setTimeout(() => {\n document.addEventListener('click', this.boundClickOutsideHandler);\n }, 0);\n } else {\n // remove listener when menu closes\n if (this.boundClickOutsideHandler) {\n document.removeEventListener('click', this.boundClickOutsideHandler);\n }\n }\n }\n\n // update floating window boundaries when size changes\n if (changes.has('size')) {\n requestAnimationFrame(() => {\n const phoneWindow = this.shadowRoot?.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n if (phoneWindow) {\n // use the stored previous width since phoneWindow.width has already been updated\n const oldWidth = this.previousWindowWidth || phoneWindow.width;\n const oldRight = phoneWindow.left + oldWidth;\n\n const config = this.sizeConfig;\n const newWidth = this.windowWidth;\n\n // store current width for next size change\n this.previousWindowWidth = newWidth;\n\n // update dimensions and boundaries\n phoneWindow.width = newWidth;\n phoneWindow.leftBoundaryMargin = this.leftBoundaryMargin;\n phoneWindow.topBoundaryMargin = config.windowPadding;\n phoneWindow.bottomBoundaryMargin = config.windowPadding;\n\n // keep right edge in same position by adjusting left\n let newLeft = oldRight - newWidth;\n\n // apply same boundary logic as FloatingWindow.handleMouseMove\n const padding = 20;\n const minLeft = padding - this.leftBoundaryMargin;\n const maxLeft =\n window.innerWidth -\n newWidth -\n padding +\n phoneWindow.rightBoundaryMargin;\n\n // clamp to boundaries\n newLeft = Math.max(minLeft, Math.min(newLeft, maxLeft));\n\n phoneWindow.left = newLeft;\n\n // adjust vertical position if needed\n const windowElement = phoneWindow.shadowRoot?.querySelector(\n '.window'\n ) as HTMLElement;\n const currentHeight =\n windowElement?.offsetHeight || config.phoneTotalHeight;\n const maxTop = Math.max(\n padding - config.windowPadding,\n window.innerHeight - currentHeight - padding + config.windowPadding\n );\n\n phoneWindow.top = Math.max(\n padding - config.windowPadding,\n Math.min(phoneWindow.top, maxTop)\n );\n }\n });\n } else {\n // store initial width when first rendered\n if (!this.previousWindowWidth) {\n this.previousWindowWidth = this.windowWidth;\n }\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n // clean up event listener when component is removed\n if (this.boundClickOutsideHandler) {\n document.removeEventListener('click', this.boundClickOutsideHandler);\n }\n }\n\n private handleShow() {\n const phoneWindow = this.shadowRoot.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n phoneWindow.show();\n this.isVisible = true;\n getStore().getState().setSimulatorActive(true);\n\n // ensure chat component is available\n if (!this.chat) {\n this.chat = this.shadowRoot.querySelector('temba-chat');\n }\n\n // start the simulation if we haven't already\n if (!this.session) {\n this.startFlow();\n }\n }\n\n private async startFlow() {\n const now = new Date().toISOString();\n\n // set created_on to simulation start time\n this.contact = { ...this.contact, created_on: now };\n\n const body = {\n contact: this.contact,\n trigger: {\n type: 'manual',\n triggered_on: now,\n flow: { uuid: this.flow, name: 'New Chat' },\n params: {}\n }\n };\n\n try {\n const response = await postJSON(this.endpoint, body);\n this.updateRunContext(response.json as RunContext);\n } catch (error) {\n console.error('Failed to start simulation:', error);\n const errorEvent = {\n uuid: generateUUIDv7(),\n type: 'error',\n created_on: new Date(now),\n _rendered: {\n html: html`<p>Failed to start simulation</p>`,\n type: MessageType.Error\n }\n } as ContactEvent;\n if (this.chat) {\n this.chat.addMessages([errorEvent], null, true);\n } else {\n this.events = [...this.events, errorEvent];\n }\n }\n }\n\n private updateRunContext(runContext: RunContext, msgInEvt?: ContactEvent) {\n const newEvents: ContactEvent[] = [];\n\n // add the user's message if provided\n if (msgInEvt) {\n // ensure it has a UUID\n if (!msgInEvt.uuid) {\n msgInEvt.uuid = generateUUIDv7();\n }\n // ensure created_on is a Date object\n if (typeof msgInEvt.created_on === 'string') {\n msgInEvt.created_on = new Date(msgInEvt.created_on);\n }\n newEvents.push(msgInEvt);\n }\n\n if (runContext.session) {\n this.session = runContext.session;\n\n // update our contact with the latest from the session\n if (runContext.contact) {\n this.contact = runContext.contact;\n }\n }\n\n // store the context from the response\n if (runContext.context) {\n this.context = runContext.context;\n }\n\n // extract quick replies from the most recent sprint\n this.currentQuickReplies = [];\n\n if (runContext.events && runContext.events.length > 0) {\n for (const rawEvent of runContext.events) {\n // skip msg_received events from the server since we already added the user's message\n if (rawEvent.type === 'msg_received') {\n continue;\n }\n\n // skip msg_created/ivr_created events without a proper msg property\n if (\n (rawEvent.type === 'msg_created' ||\n rawEvent.type === 'ivr_created') &&\n !(rawEvent as any).msg\n ) {\n continue;\n }\n\n // convert to ContactEvent\n const event: ContactEvent = {\n ...rawEvent,\n uuid: rawEvent.uuid || generateUUIDv7(),\n created_on:\n typeof rawEvent.created_on === 'string'\n ? new Date(rawEvent.created_on)\n : rawEvent.created_on\n } as ContactEvent;\n\n // pre-render non-message events\n this.prerenderEvent(event);\n\n // extract quick replies from msg_created events\n if (event.type === 'msg_created' && (event as any).msg?.quick_replies) {\n this.currentQuickReplies = (event as any).msg.quick_replies;\n }\n\n const isMessage =\n event.type === 'msg_created' || event.type === 'ivr_created';\n const msg = (event as any).msg;\n\n // Check if the event should be displayed.\n // 1. If it's a message, it must have text or attachments\n if (isMessage) {\n const hasText = msg.text && msg.text.trim().length > 0;\n const hasAttachments = msg.attachments && msg.attachments.length > 0;\n if (!hasText && !hasAttachments) {\n continue;\n }\n }\n // 2. If it's not a message, it must have been rendered by prerenderEvent\n else if (!event._rendered) {\n continue;\n }\n\n newEvents.push(event);\n }\n }\n\n // add all new events to chat component if it exists\n if (this.chat) {\n this.chat.addMessages(newEvents, null, true);\n } else {\n // fallback: store events and add them once chat is ready\n this.events = [...this.events, ...newEvents];\n }\n\n this.sprinting = false;\n this.requestUpdate(); // trigger re-render for quick replies\n this.scrollToBottom();\n this.updateActivity();\n }\n\n private updateActivity() {\n if (!this.session) {\n return;\n }\n\n const pathCounts: { [key: string]: number } = {};\n const nodeCounts: { [nodeUUID: string]: number } = {};\n\n // iterate through all runs to get path segment counts\n for (const run of this.session.runs) {\n if (run.path) {\n for (let i = 0; i < run.path.length - 1; i++) {\n const step = run.path[i];\n const nextStep = run.path[i + 1];\n if (step.exit_uuid && nextStep.node_uuid) {\n const key = step.exit_uuid + ':' + nextStep.node_uuid;\n pathCounts[key] = (pathCounts[key] || 0) + 1;\n }\n }\n }\n\n // set node counts on the last step of any active/waiting runs\n if (run.status === 'active' || run.status === 'waiting') {\n if (run.path && run.path.length > 0) {\n const finalStep = run.path[run.path.length - 1];\n if (finalStep && finalStep.node_uuid) {\n nodeCounts[finalStep.node_uuid] =\n (nodeCounts[finalStep.node_uuid] || 0) + 1;\n }\n }\n }\n }\n\n // Update simulator activity in the store\n getStore().getState().updateSimulatorActivity({\n segments: pathCounts,\n nodes: nodeCounts\n });\n\n // Fire follow event if following is enabled\n if (this.following) {\n this.fireFollowEvent();\n }\n }\n\n private fireFollowEvent() {\n if (!this.session || !this.session.runs || this.session.runs.length === 0) {\n return;\n }\n\n // Find the first active or waiting run\n let activeRun = this.session.runs.find(\n (run: any) => run.status === 'active' || run.status === 'waiting'\n );\n\n // If no active/waiting run and simulation has ended, use the first completed run\n if (!activeRun) {\n activeRun = this.session.runs.find(\n (run: any) => run.status === 'completed'\n );\n }\n\n if (activeRun && activeRun.path && activeRun.path.length > 0) {\n const finalStep = activeRun.path[activeRun.path.length - 1];\n if (finalStep && finalStep.node_uuid) {\n this.fireCustomEvent(CustomEventType.FollowSimulation, {\n flowUuid: activeRun.flow?.uuid || this.flow,\n nodeUuid: finalStep.node_uuid\n });\n }\n }\n }\n\n private scrollToBottom() {\n if (this.chat) {\n // chat component handles scrolling, but we still need to focus input\n this.chat.scrollToBottom();\n setTimeout(() => {\n const input = this.shadowRoot?.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n if (input) {\n input.focus();\n }\n }, 50);\n return;\n }\n // wait for render, then scroll to bottom\n setTimeout(() => {\n const screen = this.shadowRoot?.querySelector('.phone-screen');\n if (screen) {\n screen.scrollTop = screen.scrollHeight;\n }\n // update previous count after animation completes\n this.previousEventCount = this.events.length;\n\n // return focus to input\n const input = this.shadowRoot?.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n if (input) {\n input.focus();\n }\n }, 50);\n }\n\n private prerenderEvent(event: ContactEvent) {\n // skip if already rendered or is a message event\n if (\n event._rendered ||\n event.type === Events.MSG_CREATED ||\n event.type === Events.MSG_RECEIVED\n ) {\n return;\n }\n\n // handle simulator-specific events (errors, warnings, failures)\n if (event.type === 'error' || event.type === 'failure') {\n event._rendered = {\n html: renderEvent(event, true),\n type: MessageType.Error\n };\n return;\n }\n\n if (event.type === 'warning') {\n event._rendered = {\n html: renderEvent(event, true),\n type: MessageType.Note\n };\n return;\n }\n\n // try to render as a standard event\n const rendered = renderEvent(event, true);\n if (rendered) {\n event._rendered = {\n html: rendered,\n type: MessageType.Inline\n };\n }\n }\n\n private handleClose() {\n const phoneWindow = this.shadowRoot.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n phoneWindow.handleClose();\n this.isVisible = false;\n getStore().getState().setSimulatorActive(false);\n }\n\n private handleReset() {\n // reset simulation state\n this.events = [];\n this.session = null;\n this.context = null;\n this.inputValue = '';\n this.sprinting = false;\n this.previousEventCount = 0;\n this.currentQuickReplies = [];\n\n // reset chat component\n if (this.chat) {\n this.chat.reset();\n }\n\n // Clear simulator activity data\n getStore().getState().updateSimulatorActivity({\n segments: {},\n nodes: {}\n });\n\n // reset contact to initial state\n this.contact = {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {},\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n };\n\n // restart the flow\n this.startFlow();\n }\n\n private handleToggleFollow() {\n this.following = !this.following;\n }\n\n private handleCycleSize() {\n const sizes: Array<'small' | 'medium' | 'large'> = [\n 'small',\n 'medium',\n 'large'\n ];\n const currentIndex = sizes.indexOf(this.size);\n const nextIndex = (currentIndex + 1) % sizes.length;\n this.size = sizes[nextIndex];\n }\n\n private handleToggleContextExplorer() {\n this.contextExplorerOpen = !this.contextExplorerOpen;\n\n // if opening the context explorer, ensure it's not off-screen\n if (this.contextExplorerOpen) {\n requestAnimationFrame(() => {\n const phoneWindow = this.shadowRoot?.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n if (phoneWindow) {\n const padding = 20;\n const contextExplorerLeft = this.sizeConfig.contextOffset;\n const minWindowLeft = padding - contextExplorerLeft;\n\n if (phoneWindow.left < minWindowLeft) {\n phoneWindow.left = minWindowLeft;\n }\n }\n });\n }\n }\n\n private togglePath(path: string) {\n if (this.expandedPaths.has(path)) {\n this.expandedPaths.delete(path);\n } else {\n this.expandedPaths.add(path);\n }\n this.requestUpdate();\n }\n\n private isExpandable(value: any): boolean {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n if (Array.isArray(value)) {\n return value.length > 0;\n }\n\n // check if object has keys other than __default__\n const keys = Object.keys(value).filter((key) => key !== '__default__');\n return keys.length > 0;\n }\n\n private renderContextValue(value: any): TemplateResult | string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'boolean')\n return html`<span class=\"context-value\">${value}</span>`;\n if (typeof value === 'number')\n return html`<span class=\"context-value\">${value}</span>`;\n if (typeof value === 'string')\n return html`<span class=\"context-value\">${value}</span>`;\n if (Array.isArray(value))\n return html`<span class=\"context-value\">[${value.length}]</span>`;\n return '';\n }\n\n private buildExpression(path: string): string {\n return `@${path}`;\n }\n\n private async handleCopyExpression(\n path: string,\n event: Event\n ): Promise<void> {\n event.stopPropagation();\n const expression = this.buildExpression(path);\n try {\n await navigator.clipboard.writeText(expression);\n this.copiedExpression = expression;\n // clear the toast after 2 seconds\n setTimeout(() => {\n this.copiedExpression = '';\n }, 2000);\n } catch (err) {\n console.error('Failed to copy expression:', err);\n }\n }\n\n private handleToggleShowAllKeys() {\n this.showAllKeys = !this.showAllKeys;\n this.toastMessage = this.showAllKeys\n ? 'Showing all keys'\n : 'Filtering out keys without values';\n // clear the toast after 2 seconds\n setTimeout(() => {\n this.toastMessage = '';\n }, 2000);\n }\n\n private renderContextTree(\n obj: any,\n path: string = ''\n ): TemplateResult | TemplateResult[] {\n if (!obj || typeof obj !== 'object') {\n return html``;\n }\n\n let entries = Array.isArray(obj)\n ? obj.map((v, i) => [String(i), v])\n : Object.entries(obj).filter(([key]) => key !== '__default__');\n\n // filter out keys without values if showAllKeys is false\n if (!this.showAllKeys) {\n entries = entries.filter(([, value]) => {\n // keep if expandable (has children)\n if (this.isExpandable(value)) return true;\n // keep if it has a displayable value (not null/undefined)\n if (value === null || value === undefined) return false;\n // keep primitives with values\n return (\n typeof value === 'boolean' ||\n typeof value === 'number' ||\n typeof value === 'string' ||\n Array.isArray(value)\n );\n });\n }\n\n return html`${entries.map(([key, value]) => {\n const currentPath = path ? `${path}.${key}` : key;\n const isExpanded = this.expandedPaths.has(currentPath);\n const expandable = this.isExpandable(value);\n\n // check if this object has a __default__ value\n let displayValue = value;\n\n if (\n expandable &&\n !Array.isArray(value) &&\n value !== null &&\n typeof value === 'object' &&\n '__default__' in value\n ) {\n displayValue = value.__default__;\n }\n\n return html`\n <div>\n <div\n class=\"context-item ${expandable ? 'context-item-expandable' : ''}\"\n @click=${() => expandable && this.togglePath(currentPath)}\n >\n ${expandable\n ? html`<span\n class=\"context-expand-icon ${isExpanded ? 'expanded' : ''}\"\n >›</span\n >`\n : html`<span class=\"context-expand-icon\"></span>`}\n <span class=\"context-key ${expandable ? 'has-value' : ''}\"\n >${key}\n <temba-icon\n class=\"context-copy-icon\"\n name=\"copy\"\n size=\"0.9\"\n @click=${(e: Event) =>\n this.handleCopyExpression(currentPath, e)}\n ></temba-icon>\n </span>\n ${!isExpanded ? this.renderContextValue(displayValue) : html``}\n </div>\n ${isExpanded\n ? html`<div class=\"context-children\">\n ${this.renderContextTree(value, currentPath)}\n </div>`\n : html``}\n </div>\n `;\n })}`;\n }\n\n private async resume(text: string, attachment?: string) {\n if ((!text && !attachment) || !this.session) {\n return;\n }\n\n this.sprinting = true;\n this.inputValue = '';\n this.currentQuickReplies = [];\n this.attachmentMenuOpen = false;\n\n const now = new Date().toISOString();\n\n // create the event for the API (with ISO string date)\n const msgInEvtForAPI = {\n uuid: generateUUIDv7(),\n type: 'msg_received',\n created_on: now,\n msg: {\n uuid: generateUUIDv7(),\n text: text || '',\n urn: this.contact.urns[0],\n direction: 'in',\n type: 'text',\n attachments: attachment ? [attachment] : [],\n quick_replies: [],\n channel: { uuid: generateUUIDv7(), name: 'Simulator' }\n }\n };\n\n // create the ContactEvent for display (with Date object)\n const msgInEvt = {\n ...msgInEvtForAPI,\n created_on: new Date(now)\n } as ContactEvent;\n\n // show user's message immediately via chat component\n if (this.chat) {\n this.chat.addMessages([msgInEvt], null, true);\n } else {\n this.events = [...this.events, msgInEvt];\n }\n this.requestUpdate();\n this.scrollToBottom();\n\n const body = {\n session: this.session,\n contact: this.contact,\n resume: {\n type: 'msg',\n event: msgInEvtForAPI,\n resumed_on: now\n }\n };\n\n try {\n const response = await postJSON(this.endpoint, body);\n\n // add a small delay before showing the reply to simulate typing\n await new Promise((resolve) => setTimeout(resolve, 400));\n\n // pass null for msgInEvt since we already added it\n this.updateRunContext(response.json as RunContext, null);\n } catch (error) {\n console.error('Failed to resume simulation:', error);\n const errorEvent = {\n uuid: generateUUIDv7(),\n type: 'error',\n created_on: new Date(now),\n _rendered: {\n html: html`<p>Failed to send message</p>`,\n type: MessageType.Error\n }\n } as ContactEvent;\n if (this.chat) {\n this.chat.addMessages([errorEvent], null, true);\n } else {\n this.events = [...this.events, errorEvent];\n }\n this.sprinting = false;\n }\n }\n\n private handleKeyUp(evt: KeyboardEvent) {\n if (evt.key === 'Enter') {\n const input = evt.target as HTMLInputElement;\n const text = input.value.trim();\n if (text) {\n this.resume(text);\n }\n }\n }\n\n private handleInput(evt: Event) {\n const input = evt.target as HTMLInputElement;\n this.inputValue = input.value;\n }\n\n private handleQuickReplyClick(text: string) {\n if (!this.sprinting && text) {\n this.resume(text);\n }\n }\n\n private handleToggleAttachmentMenu() {\n this.attachmentMenuOpen = !this.attachmentMenuOpen;\n }\n\n private handleClickOutsideAttachmentMenu(event: MouseEvent) {\n if (!this.attachmentMenuOpen) {\n return;\n }\n\n const menu = this.shadowRoot?.querySelector('.attachment-menu');\n const button = this.shadowRoot?.querySelector('.attachment-button');\n\n if (!menu || !button) {\n return;\n }\n\n // check if click is outside both menu and button\n const clickedInsideMenu = menu.contains(event.target as Node);\n const clickedInsideButton = button.contains(event.target as Node);\n\n if (!clickedInsideMenu && !clickedInsideButton) {\n this.attachmentMenuOpen = false;\n }\n }\n\n private handleSendAttachment(attachmentType: string) {\n let attachment = '';\n switch (attachmentType) {\n case 'image':\n attachment = `image/jpeg:${TEST_IMAGES[this.imageIndex]}`;\n this.imageIndex = (this.imageIndex + 1) % TEST_IMAGES.length;\n break;\n case 'video':\n attachment = `video/mp4:${TEST_VIDEOS[this.videoIndex]}`;\n this.videoIndex = (this.videoIndex + 1) % TEST_VIDEOS.length;\n break;\n case 'audio':\n attachment = `audio/mp3:${TEST_AUDIO[this.audioIndex]}`;\n this.audioIndex = (this.audioIndex + 1) % TEST_AUDIO.length;\n break;\n case 'location':\n attachment = TEST_LOCATIONS[this.locationIndex];\n this.locationIndex = (this.locationIndex + 1) % TEST_LOCATIONS.length;\n break;\n }\n\n if (attachment) {\n this.resume('', attachment);\n }\n }\n\n private updateBottomInputHeight() {\n requestAnimationFrame(() => {\n const bottomContainer = this.shadowRoot?.querySelector(\n '.bottom-input-container'\n ) as HTMLElement;\n if (bottomContainer) {\n const height = bottomContainer.offsetHeight;\n this.style.setProperty('--bottom-input-height', `${height}px`);\n }\n });\n }\n\n protected render(): TemplateResult {\n if (this.viewingRevision || this.definition?.nodes.length === 0) {\n return html``;\n }\n\n const config = this.sizeConfig;\n\n // set CSS custom properties dynamically based on size\n const styleVars = `\n --phone-width: ${config.phoneWidth}px;\n --phone-total-height: ${config.phoneTotalHeight}px;\n --context-width: ${config.contextWidth}px;\n --context-offset: ${config.contextOffset}px;\n --option-pane-width: ${config.optionPaneWidth}px;\n --option-pane-gap: ${config.optionPaneGap}px;\n --window-padding: ${config.windowPadding}px;\n --phone-screen-height: ${config.phoneScreenHeight}px;\n --context-height: ${config.contextHeight}px;\n --context-closed-left: ${this.contextClosedLeft}px;\n --cutout-height: ${config.cutoutHeight}px;\n --cutout-padding: ${config.cutoutPadding}px;\n --cutout-font-size: ${config.cutoutFontSize}px;\n --cutout-island-width: ${config.cutoutIslandWidth}px;\n --cutout-island-height: ${config.cutoutIslandHeight}px;\n --cutout-island-top: ${config.cutoutIslandTop}px;\n --animation-time: ${this.animationTime}ms;\n `;\n\n return html`\n <temba-floating-window\n style=\"--transition-duration: ${this.animationTime}ms\"\n id=\"phone-window\"\n width=\"${this.windowWidth}\"\n leftBoundaryMargin=\"${this.leftBoundaryMargin}\"\n bottomBoundaryMargin=\"${config.windowPadding}\"\n topBoundaryMargin=\"${config.windowPadding}\"\n height=\"${config.phoneTotalHeight}\"\n top=\"0\"\n chromeless\n >\n <div class=\"phone-simulator\" style=\"${styleVars}\">\n <div\n class=\"context-explorer ${this.contextExplorerOpen\n ? 'open'\n : ''} ${this.isVisible ? 'visible' : 'hidden'}\"\n >\n <div class=\"context-explorer-scroll\">\n ${this.context\n ? this.renderContextTree(this.context)\n : html`<div\n style=\"color: #9ca3af; padding: 8px; text-align: center;\"\n >\n No context available\n </div>`}\n </div>\n <div class=\"context-gutter\">\n <div\n class=\"context-gutter-btn ${this.showAllKeys ? '' : 'active'}\"\n @click=${this.handleToggleShowAllKeys}\n title=\"${this.showAllKeys\n ? 'Show keys with values only'\n : 'Show all keys'}\"\n >\n <temba-icon\n name=\"${this.showAllKeys ? 'filter' : 'filter'}\"\n size=\"1\"\n ></temba-icon>\n </div>\n <div class=\"context-gutter-spacer\"></div>\n <div\n class=\"context-gutter-btn\"\n @click=${this.handleToggleContextExplorer}\n title=\"Close\"\n >\n <temba-icon name=\"x\" size=\"1\"></temba-icon>\n </div>\n </div>\n ${this.copiedExpression\n ? html`<div class=\"context-toast\">\n Copied\n <span class=\"expression\">${this.copiedExpression}</span>\n to the clipboard\n </div>`\n : this.toastMessage\n ? html`<div class=\"context-toast\">${this.toastMessage}</div>`\n : html``}\n </div>\n\n <div\n class=\"phone-frame\"\n style=\"pointer-events: ${this.isVisible ? 'all' : 'none'}\"\n >\n <div class=\"phone-top drag-handle\">\n <div class=\"phone-notch\">\n <div class=\"dynamic-island\"></div>\n </div>\n </div>\n <temba-chat class=\"phone-screen\" .showTimestamps=${false}>\n </temba-chat>\n <div class=\"custom-scrollbar-container\">\n <div class=\"custom-scrollbar-content\"></div>\n </div>\n\n <div class=\"bottom-input-container\">\n ${this.currentQuickReplies.length > 0\n ? html`<div class=\"quick-replies-container\">\n ${this.currentQuickReplies.map(\n (qr) => html`\n <button\n class=\"quick-reply-btn\"\n @click=${() => this.handleQuickReplyClick(qr.text)}\n ?disabled=${this.sprinting}\n >\n ${qr.text}\n </button>\n `\n )}\n </div>`\n : null}\n <div class=\"message-input\">\n <button\n class=\"attachment-button\"\n @click=${this.handleToggleAttachmentMenu}\n ?disabled=${this.sprinting}\n >\n <temba-icon name=\"plus\" size=\"1.5\"></temba-icon>\n </button>\n <input\n type=\"text\"\n placeholder=\"Enter Message\"\n .value=${this.inputValue}\n @input=${this.handleInput}\n @keyup=${this.handleKeyUp}\n ?disabled=${this.sprinting}\n />\n <div\n class=\"attachment-menu ${this.attachmentMenuOpen\n ? 'open'\n : ''}\"\n >\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('image')}\n >\n <temba-icon name=\"attachment_image\" size=\"1.2\"></temba-icon>\n <span>Image</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('video')}\n >\n <temba-icon name=\"attachment_video\" size=\"1.2\"></temba-icon>\n <span>Video</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('audio')}\n >\n <temba-icon name=\"attachment_audio\" size=\"1.2\"></temba-icon>\n <span>Audio</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('location')}\n >\n <temba-icon\n name=\"attachment_location\"\n size=\"1.2\"\n ></temba-icon>\n <span>Location</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div\n class=\"option-pane\"\n style=\"pointer-events:${this.isVisible ? 'all' : 'none'}\"\n >\n <button class=\"option-btn\" @click=${this.handleClose} title=\"Close\">\n <temba-icon name=\"x\" size=\"1.5\"></temba-icon>\n </button>\n <button\n class=\"option-btn ${this.following ? 'active' : ''}\"\n @click=${this.handleToggleFollow}\n title=\"${this.following ? 'Following' : 'Follow'}\"\n >\n <temba-icon name=\"follow\" size=\"1.5\"></temba-icon>\n </button>\n\n <button\n class=\"option-btn ${this.contextExplorerOpen ? 'active' : ''}\"\n @click=${this.handleToggleContextExplorer}\n title=\"Context Explorer\"\n >\n <temba-icon name=\"expressions\" size=\"1.5\"></temba-icon>\n </button>\n\n <button\n class=\"option-btn\"\n @click=${this.handleCycleSize}\n title=\"Size: ${this.size}\"\n >\n ${this.size === 'small'\n ? 'S'\n : this.size === 'medium'\n ? 'M'\n : 'L'}\n </button>\n\n <button class=\"option-btn\" @click=${this.handleReset} title=\"Reset\">\n <temba-icon name=\"refresh\" size=\"1.5\"></temba-icon>\n </button>\n </div>\n </div>\n </temba-floating-window>\n\n <temba-floating-tab\n id=\"phone-tab\"\n icon=\"simulator\"\n label=\"Phone Simulator\"\n color=\"#10b981\"\n order=\"4\"\n .hidden=${this.isVisible}\n @temba-button-clicked=${this.handleShow}\n ></temba-floating-tab>\n `;\n }\n}\n"]}
@@ -34,16 +34,18 @@ describe('temba-canvas-menu', () => {
34
34
  expect(menuElement).to.not.be.null;
35
35
  await assertScreenshot('canvas-menu/open', getClip(menu));
36
36
  });
37
- it('has three menu items', async () => {
37
+ it('has five menu items', async () => {
38
38
  var _a;
39
39
  const menu = await createCanvasMenu();
40
40
  menu.show(100, 100, { x: 50, y: 50 });
41
41
  await menu.updateComplete;
42
42
  const menuItems = (_a = menu.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.menu-item');
43
- expect(menuItems === null || menuItems === void 0 ? void 0 : menuItems.length).to.equal(3);
43
+ expect(menuItems === null || menuItems === void 0 ? void 0 : menuItems.length).to.equal(5);
44
44
  // check menu item titles
45
45
  const titles = Array.from(menuItems || []).map((item) => { var _a; return (_a = item.querySelector('.menu-item-title')) === null || _a === void 0 ? void 0 : _a.textContent; });
46
46
  expect(titles).to.deep.equal([
47
+ 'Send Message',
48
+ 'Wait for Response',
47
49
  'Add Action',
48
50
  'Add Split',
49
51
  'Add Sticky Note'
@@ -69,9 +71,9 @@ describe('temba-canvas-menu', () => {
69
71
  selectionFired = true;
70
72
  selectionDetail = event.detail;
71
73
  });
72
- // click on sticky note option (now the third item)
74
+ // click on sticky note option (now the fifth item)
73
75
  const menuItems = (_a = menu.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.menu-item');
74
- const stickyItem = menuItems === null || menuItems === void 0 ? void 0 : menuItems[2];
76
+ const stickyItem = menuItems === null || menuItems === void 0 ? void 0 : menuItems[4];
75
77
  stickyItem.click();
76
78
  await menu.updateComplete;
77
79
  expect(selectionFired).to.be.true;
@@ -87,9 +89,11 @@ describe('temba-canvas-menu', () => {
87
89
  menu.show(100, 100, { x: 50, y: 50 }, true, true);
88
90
  await menu.updateComplete;
89
91
  const menuItems = (_a = menu.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.menu-item');
90
- expect(menuItems === null || menuItems === void 0 ? void 0 : menuItems.length).to.equal(4);
92
+ expect(menuItems === null || menuItems === void 0 ? void 0 : menuItems.length).to.equal(6);
91
93
  const titles = Array.from(menuItems || []).map((item) => { var _a; return (_a = item.querySelector('.menu-item-title')) === null || _a === void 0 ? void 0 : _a.textContent; });
92
94
  expect(titles).to.deep.equal([
95
+ 'Send Message',
96
+ 'Wait for Response',
93
97
  'Add Action',
94
98
  'Add Split',
95
99
  'Add Sticky Note',
@@ -106,7 +110,7 @@ describe('temba-canvas-menu', () => {
106
110
  selectionDetail = event.detail;
107
111
  });
108
112
  const menuItems = (_a = menu.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.menu-item');
109
- const reflowItem = menuItems === null || menuItems === void 0 ? void 0 : menuItems[3];
113
+ const reflowItem = menuItems === null || menuItems === void 0 ? void 0 : menuItems[5];
110
114
  reflowItem.click();
111
115
  await menu.updateComplete;
112
116
  expect(selectionDetail).to.deep.equal({
@@ -121,7 +125,7 @@ describe('temba-canvas-menu', () => {
121
125
  menu.show(100, 100, { x: 50, y: 50 });
122
126
  await menu.updateComplete;
123
127
  const menuItems = (_a = menu.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.menu-item');
124
- expect(menuItems === null || menuItems === void 0 ? void 0 : menuItems.length).to.equal(3);
128
+ expect(menuItems === null || menuItems === void 0 ? void 0 : menuItems.length).to.equal(5);
125
129
  const titles = Array.from(menuItems || []).map((item) => { var _a; return (_a = item.querySelector('.menu-item-title')) === null || _a === void 0 ? void 0 : _a.textContent; });
126
130
  expect(titles).to.not.include('Reflow');
127
131
  });
@@ -155,8 +159,8 @@ describe('temba-canvas-menu', () => {
155
159
  selectionDetail = event.detail;
156
160
  });
157
161
  const menuItems = (_b = menu.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelectorAll('.menu-item');
158
- const actionItem = menuItems === null || menuItems === void 0 ? void 0 : menuItems[0];
159
- actionItem.click();
162
+ const sendMsgItem = menuItems === null || menuItems === void 0 ? void 0 : menuItems[0];
163
+ sendMsgItem.click();
160
164
  await menu.updateComplete;
161
165
  expect(selectionFired).to.be.true;
162
166
  // click position should remain unchanged
@@ -1 +1 @@
1
- {"version":3,"file":"temba-canvas-menu.test.js","sourceRoot":"","sources":["../../test/temba-canvas-menu.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { CanvasMenu } from '../src/flow/CanvasMenu';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-canvas-menu', () => {\n const createCanvasMenu = async () => {\n const component = (await getComponent(\n 'temba-canvas-menu',\n {},\n '',\n 250,\n 250\n )) as CanvasMenu;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const menu = await createCanvasMenu();\n assert.instanceOf(menu, CanvasMenu);\n expect(menu.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const menu = await createCanvasMenu();\n expect(menu.open).to.be.false;\n\n // verify no menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.be.null;\n });\n\n it('shows menu when opened', async () => {\n const menu = await createCanvasMenu();\n\n // open the menu\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n expect(menu.x).to.equal(100);\n expect(menu.y).to.equal(100);\n\n // verify menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.not.be.null;\n\n await assertScreenshot('canvas-menu/open', getClip(menu));\n });\n\n it('has three menu items', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(3);\n\n // check menu item titles\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note'\n ]);\n });\n\n it('closes when close() is called', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n\n menu.close();\n await menu.updateComplete;\n\n expect(menu.open).to.be.false;\n });\n\n it('fires selection event when menu item is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on sticky note option (now the third item)\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const stickyItem = menuItems?.[2] as HTMLElement;\n stickyItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.deep.equal({\n action: 'sticky',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('shows reflow option when showReflow is true', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 }, true, true);\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(4);\n\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note',\n 'Reflow'\n ]);\n });\n\n it('fires reflow selection event when reflow is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 }, true, true);\n await menu.updateComplete;\n\n let selectionDetail = null;\n menu.addEventListener('temba-selection', (event: any) => {\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const reflowItem = menuItems?.[3] as HTMLElement;\n reflowItem.click();\n await menu.updateComplete;\n\n expect(selectionDetail).to.deep.equal({\n action: 'reflow',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('hides reflow option by default', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(3);\n\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.not.include('Reflow');\n });\n\n it('adjusts position to stay within viewport bounds', async () => {\n const menu = await createCanvasMenu();\n\n // open menu at position that would go off screen\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const margin = 10; // matches the margin in CanvasMenu\n\n // position that would go off the right and bottom edges\n menu.show(viewportWidth - 50, viewportHeight - 50, {\n x: 100,\n y: 100\n });\n await menu.updateComplete;\n\n // wait for position adjustment\n await new Promise((resolve) => setTimeout(resolve, 100));\n await menu.updateComplete;\n\n const menuElement = menu.shadowRoot?.querySelector('.menu') as HTMLElement;\n expect(menuElement).to.not.be.null;\n\n const menuRect = menuElement.getBoundingClientRect();\n\n // verify menu stays within viewport with margin\n expect(menuRect.right).to.be.at.most(viewportWidth - margin);\n expect(menuRect.bottom).to.be.at.most(viewportHeight - margin);\n\n // verify click position is preserved (not adjusted)\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const actionItem = menuItems?.[0] as HTMLElement;\n actionItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n // click position should remain unchanged\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n });\n});\n"]}
1
+ {"version":3,"file":"temba-canvas-menu.test.js","sourceRoot":"","sources":["../../test/temba-canvas-menu.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { CanvasMenu } from '../src/flow/CanvasMenu';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-canvas-menu', () => {\n const createCanvasMenu = async () => {\n const component = (await getComponent(\n 'temba-canvas-menu',\n {},\n '',\n 250,\n 250\n )) as CanvasMenu;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const menu = await createCanvasMenu();\n assert.instanceOf(menu, CanvasMenu);\n expect(menu.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const menu = await createCanvasMenu();\n expect(menu.open).to.be.false;\n\n // verify no menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.be.null;\n });\n\n it('shows menu when opened', async () => {\n const menu = await createCanvasMenu();\n\n // open the menu\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n expect(menu.x).to.equal(100);\n expect(menu.y).to.equal(100);\n\n // verify menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.not.be.null;\n\n await assertScreenshot('canvas-menu/open', getClip(menu));\n });\n\n it('has five menu items', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(5);\n\n // check menu item titles\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Send Message',\n 'Wait for Response',\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note'\n ]);\n });\n\n it('closes when close() is called', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n\n menu.close();\n await menu.updateComplete;\n\n expect(menu.open).to.be.false;\n });\n\n it('fires selection event when menu item is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on sticky note option (now the fifth item)\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const stickyItem = menuItems?.[4] as HTMLElement;\n stickyItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.deep.equal({\n action: 'sticky',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('shows reflow option when showReflow is true', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 }, true, true);\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(6);\n\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Send Message',\n 'Wait for Response',\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note',\n 'Reflow'\n ]);\n });\n\n it('fires reflow selection event when reflow is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 }, true, true);\n await menu.updateComplete;\n\n let selectionDetail = null;\n menu.addEventListener('temba-selection', (event: any) => {\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const reflowItem = menuItems?.[5] as HTMLElement;\n reflowItem.click();\n await menu.updateComplete;\n\n expect(selectionDetail).to.deep.equal({\n action: 'reflow',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('hides reflow option by default', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(5);\n\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.not.include('Reflow');\n });\n\n it('adjusts position to stay within viewport bounds', async () => {\n const menu = await createCanvasMenu();\n\n // open menu at position that would go off screen\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const margin = 10; // matches the margin in CanvasMenu\n\n // position that would go off the right and bottom edges\n menu.show(viewportWidth - 50, viewportHeight - 50, {\n x: 100,\n y: 100\n });\n await menu.updateComplete;\n\n // wait for position adjustment\n await new Promise((resolve) => setTimeout(resolve, 100));\n await menu.updateComplete;\n\n const menuElement = menu.shadowRoot?.querySelector('.menu') as HTMLElement;\n expect(menuElement).to.not.be.null;\n\n const menuRect = menuElement.getBoundingClientRect();\n\n // verify menu stays within viewport with margin\n expect(menuRect.right).to.be.at.most(viewportWidth - margin);\n expect(menuRect.bottom).to.be.at.most(viewportHeight - margin);\n\n // verify click position is preserved (not adjusted)\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const sendMsgItem = menuItems?.[0] as HTMLElement;\n sendMsgItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n // click position should remain unchanged\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n });\n});\n"]}