@nyaruka/temba-components 0.142.1 → 0.142.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/temba-components.js +953 -708
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/Icons.js +1 -0
- package/out-tsc/src/Icons.js.map +1 -1
- package/out-tsc/src/flow/CanvasMenu.js +38 -38
- package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +171 -17
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +491 -22
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +346 -10
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/NodeTypeSelector.js +2 -0
- package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +92 -28
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/StickyNote.js +63 -3
- package/out-tsc/src/flow/StickyNote.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js +2 -6
- package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
- package/out-tsc/src/flow/actions/enter_flow.js +2 -2
- package/out-tsc/src/flow/actions/enter_flow.js.map +1 -1
- package/out-tsc/src/flow/actions/say_msg.js +2 -1
- package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/send_broadcast.js +2 -6
- package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
- package/out-tsc/src/flow/actions/send_email.js +2 -6
- package/out-tsc/src/flow/actions/send_email.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +55 -35
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +4 -5
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +3 -3
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +3 -3
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/actions/start_session.js +2 -2
- package/out-tsc/src/flow/actions/start_session.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm.js +4 -5
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_resthook.js +3 -8
- package/out-tsc/src/flow/nodes/split_by_resthook.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js +4 -2
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_webhook.js +25 -33
- package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +1 -0
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/flow/utils.js +66 -0
- package/out-tsc/src/flow/utils.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +17 -2
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/interfaces.js +1 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/list/SortableList.js +104 -43
- package/out-tsc/src/list/SortableList.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +6 -2
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/test/temba-canvas-menu.test.js +13 -9
- package/out-tsc/test/temba-canvas-menu.test.js.map +1 -1
- package/out-tsc/test/temba-flow-reflow.test.js.map +1 -1
- package/out-tsc/test/temba-node-editor.test.js +9 -10
- package/out-tsc/test/temba-node-editor.test.js.map +1 -1
- package/out-tsc/test/temba-node-type-selector.test.js +3 -3
- package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
- package/out-tsc/test/temba-simulator.test.js +2 -2
- package/out-tsc/test/temba-simulator.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/actions/enter_flow/render/basic-flow.png +0 -0
- package/screenshots/truth/actions/enter_flow/render/long-flow-name.png +0 -0
- package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
- package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
- package/screenshots/truth/canvas-menu/open.png +0 -0
- package/screenshots/truth/node-type-selector/action-mode.png +0 -0
- package/screenshots/truth/node-type-selector/split-mode.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
- package/src/Icons.ts +1 -0
- package/src/flow/CanvasMenu.ts +50 -43
- package/src/flow/CanvasNode.ts +201 -17
- package/src/flow/Editor.ts +585 -25
- package/src/flow/NodeEditor.ts +373 -10
- package/src/flow/NodeTypeSelector.ts +2 -0
- package/src/flow/Plumber.ts +104 -37
- package/src/flow/StickyNote.ts +76 -4
- package/src/flow/actions/add_contact_urn.ts +5 -6
- package/src/flow/actions/enter_flow.ts +2 -2
- package/src/flow/actions/say_msg.ts +2 -1
- package/src/flow/actions/send_broadcast.ts +2 -6
- package/src/flow/actions/send_email.ts +2 -6
- package/src/flow/actions/send_msg.ts +59 -38
- package/src/flow/actions/set_contact_channel.ts +5 -1
- package/src/flow/actions/set_contact_field.ts +10 -5
- package/src/flow/actions/set_contact_language.ts +6 -3
- package/src/flow/actions/set_contact_name.ts +5 -1
- package/src/flow/actions/set_contact_status.ts +5 -1
- package/src/flow/actions/set_run_result.ts +6 -3
- package/src/flow/actions/start_session.ts +2 -2
- package/src/flow/nodes/split_by_llm.ts +5 -5
- package/src/flow/nodes/split_by_resthook.ts +3 -8
- package/src/flow/nodes/split_by_subflow.ts +4 -2
- package/src/flow/nodes/split_by_webhook.ts +26 -34
- package/src/flow/nodes/wait_for_response.ts +1 -0
- package/src/flow/types.ts +25 -2
- package/src/flow/utils.ts +79 -1
- package/src/form/FieldRenderer.ts +32 -3
- package/src/interfaces.ts +1 -0
- package/src/list/SortableList.ts +117 -47
- package/src/simulator/Simulator.ts +6 -2
- package/test/temba-canvas-menu.test.ts +13 -9
- package/test/temba-flow-reflow.test.ts +4 -2
- package/test/temba-node-editor.test.ts +9 -10
- package/test/temba-node-type-selector.test.ts +3 -3
- package/test/temba-simulator.test.ts +2 -2
|
@@ -372,11 +372,13 @@ export class NodeTypeSelector extends RapidElement {
|
|
|
372
372
|
.filter(([type, config]) => {
|
|
373
373
|
// exclude execute_actions (it's the default action-only node)
|
|
374
374
|
// exclude nodes that have showAsAction=true (they appear in action mode)
|
|
375
|
+
// exclude nodes that have hideFromSplits=true (promoted to context menu)
|
|
375
376
|
// exclude aliases (type won't match config.type for aliases)
|
|
376
377
|
return (type !== 'execute_actions' &&
|
|
377
378
|
type === config.type &&
|
|
378
379
|
config.name &&
|
|
379
380
|
!config.showAsAction &&
|
|
381
|
+
!config.hideFromSplits &&
|
|
380
382
|
this.isConfigAvailable(config));
|
|
381
383
|
})
|
|
382
384
|
.forEach(([type, config]) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeTypeSelector.js","sourceRoot":"","sources":["../../../src/flow/NodeTypeSelector.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { NODE_CONFIG, ACTION_CONFIG } from './config';\nimport {\n NodeConfig,\n ActionConfig,\n ACTION_GROUPS,\n SPLIT_GROUPS,\n ACTION_GROUP_METADATA,\n SPLIT_GROUP_METADATA\n} from './types';\n\n/**\n * Event detail for node type selection\n */\nexport interface NodeTypeSelection {\n nodeType: string;\n position: { x: number; y: number };\n}\n\n/**\n * Categorizes node types for display\n */\ninterface NodeCategory {\n name: string;\n description: string;\n color: string;\n items: Array<{ type: string; config: NodeConfig | ActionConfig }>;\n isBranching?: boolean; // true if this category contains actions that branch/split\n}\n\n/**\n * NodeTypeSelector - A dialog for selecting which type of node to create\n * Shows categorized lists of available actions and splits\n */\nexport class NodeTypeSelector extends RapidElement {\n static get styles() {\n return css`\n :host {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 10001;\n display: none;\n }\n\n :host([open]) {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n }\n\n .dialog {\n position: relative;\n background: white;\n border-radius: var(--curvature);\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);\n max-width: 700px;\n max-height: 80vh;\n width: 90%;\n display: flex;\n flex-direction: column;\n }\n\n .header {\n padding: 1.5em;\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n .header h2 {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n color: var(--color-text-dark);\n }\n\n .content {\n overflow-y: auto;\n overflow-x: hidden;\n flex: 1;\n padding: 0;\n }\n\n .section-regular {\n padding: 1.5em;\n }\n\n .section-branching {\n background: linear-gradient(\n 135deg,\n rgba(170, 170, 170, 0.12),\n rgba(170, 170, 170, 0.08)\n );\n padding: 1.5em;\n margin: 0 -1.5em;\n padding-left: 3em;\n padding-right: 3em;\n }\n\n .section-header {\n margin-bottom: 1.5em;\n padding-top: 1em;\n }\n\n .section-title {\n font-weight: 700;\n font-size: 1.1rem;\n color: var(--color-text-dark);\n margin-bottom: 0.35em;\n display: flex;\n align-items: center;\n }\n\n .section-title::before {\n content: '';\n display: inline-block;\n height: 1.2em;\n background: linear-gradient(\n 135deg,\n var(--color-primary-dark),\n var(--color-primary)\n );\n border-radius: 2px;\n }\n\n .section-description {\n font-size: 0.9rem;\n color: var(--color-text);\n opacity: 0.7;\n margin-left: 0em;\n padding-bottom: 1em;\n }\n\n .category {\n margin-bottom: 2em;\n }\n\n .category:last-child {\n margin-bottom: 0;\n }\n\n .category-title {\n font-weight: 600;\n color: var(--color-text-dark);\n margin-bottom: 0.5em;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n font-size: 0.9rem;\n opacity: 0.7;\n }\n\n .category-description {\n font-size: 0.85rem;\n color: var(--color-text);\n opacity: 0.6;\n margin-bottom: 0.75em;\n line-height: 1.4;\n }\n\n .items-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n gap: 0.75em;\n }\n\n .node-item {\n padding: 0.5em;\n padding-left: 1em;\n border: 1px solid rgba(0, 0, 0, 0.1);\n border-radius: calc(var(--curvature) * 0.75);\n cursor: pointer;\n transition: all 0.15s ease;\n background: white;\n position: relative;\n overflow: hidden;\n }\n\n .node-item::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n width: 4px;\n height: 100%;\n background: var(--item-color, rgba(0, 0, 0, 0.1));\n }\n\n .node-item:hover {\n border-color: var(--item-color, var(--color-primary));\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n }\n\n .node-item:hover::before {\n width: 6px;\n }\n\n .node-item-title {\n font-weight: 500;\n font-size: 1rem;\n color: var(--color-text-dark);\n }\n\n .node-item-type {\n font-size: 0.75rem;\n color: var(--color-text);\n opacity: 0.6;\n font-family: monospace;\n }\n\n .footer {\n padding: 1em 1.5em;\n border-top: 1px solid rgba(0, 0, 0, 0.1);\n display: flex;\n justify-content: flex-end;\n }\n\n temba-button {\n --button-y: 0.5em;\n --button-x: 1.25em;\n }\n `;\n }\n\n @property({ type: Boolean, reflect: true })\n public open = false;\n\n @property({ type: String })\n public mode: 'action' | 'split' | 'action-no-branching' = 'action';\n\n @property({ type: String })\n public flowType: string = 'message';\n\n @property({ type: Array })\n public features: string[] = [];\n\n @state()\n private clickPosition = { x: 0, y: 0 };\n\n public show(\n mode: 'action' | 'split' | 'action-no-branching',\n position: { x: number; y: number }\n ) {\n this.mode = mode;\n this.clickPosition = position;\n this.open = true;\n }\n\n public close(fireCanceledEvent: boolean = true) {\n if (this.open) {\n this.open = false;\n // Fire canceled event so parent can clean up, but only if not from a selection\n if (fireCanceledEvent) {\n this.fireCustomEvent(CustomEventType.Canceled, {});\n }\n }\n }\n\n /**\n * Check if a config is available for the current flow type and features\n */\n private isConfigAvailable(config: NodeConfig | ActionConfig): boolean {\n // Check flow type filter\n if (config.flowTypes !== undefined) {\n // Empty array means not available for any flow type in selector\n if (config.flowTypes.length === 0) {\n return false;\n }\n // Non-empty array means check if current flow type is included\n if (!config.flowTypes.includes(this.flowType as any)) {\n return false;\n }\n }\n // undefined/null flowTypes means available for all flow types\n\n // Check features filter - all required features must be present\n if (config.features && config.features.length > 0) {\n for (const requiredFeature of config.features) {\n if (!this.features.includes(requiredFeature)) {\n return false;\n }\n }\n }\n\n return true;\n }\n\n private handleNodeTypeClick(nodeType: string) {\n this.fireCustomEvent(CustomEventType.Selection, {\n nodeType,\n position: this.clickPosition\n } as NodeTypeSelection);\n // Close without firing canceled event since we made a selection\n this.close(false);\n }\n\n private handleOverlayClick() {\n this.close();\n }\n\n private getCategories(): NodeCategory[] {\n if (this.mode === 'action' || this.mode === 'action-no-branching') {\n // Group actions by group\n const actionsByGroup = new Map<\n string,\n Array<{ type: string; config: ActionConfig }>\n >();\n const splitsByGroup = new Map<\n string,\n Array<{ type: string; config: NodeConfig }>\n >();\n\n // Collect regular actions (from ACTION_CONFIG, unless hideFromActions is true)\n Object.entries(ACTION_CONFIG)\n .filter(([type, config]) => {\n // exclude aliases - if config has aliases, check if this type is an alias\n const isAlias = config.aliases && config.aliases.includes(type);\n return (\n !isAlias &&\n config.name &&\n !config.hideFromActions &&\n config.group &&\n this.isConfigAvailable(config)\n );\n })\n .forEach(([type, config]) => {\n const group = config.group;\n if (!actionsByGroup.has(group)) {\n actionsByGroup.set(group, []);\n }\n actionsByGroup.get(group)!.push({ type, config });\n });\n\n // Collect nodes that have showAsAction=true (these appear as \"with split\" actions)\n // Only if we're not in 'action-no-branching' mode\n if (this.mode === 'action') {\n Object.entries(NODE_CONFIG)\n .filter(([type, config]) => {\n return (\n type !== 'execute_actions' &&\n type === config.type && // exclude aliases (type won't match config.type for aliases)\n config.name &&\n config.showAsAction &&\n config.group &&\n this.isConfigAvailable(config)\n );\n })\n .forEach(([type, config]) => {\n const group = config.group!;\n if (!splitsByGroup.has(group)) {\n splitsByGroup.set(group, []);\n }\n splitsByGroup.get(group)!.push({ type, config });\n });\n }\n\n // Build categories - first regular actions, then splitting actions\n const categories: NodeCategory[] = [];\n\n // Get the implicit order from ACTION_GROUPS object\n const actionGroupOrder = Object.keys(ACTION_GROUPS);\n // Get the implicit order of actions from ACTION_CONFIG\n const actionConfigOrder = Object.keys(ACTION_CONFIG);\n\n // Add regular action categories sorted by implicit order\n const sortedActionCategories = Array.from(actionsByGroup.entries()).sort(\n ([groupA], [groupB]) => {\n const orderA = actionGroupOrder.indexOf(groupA);\n const orderB = actionGroupOrder.indexOf(groupB);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n }\n );\n\n sortedActionCategories.forEach(([group, items]) => {\n const metadata = ACTION_GROUP_METADATA[group];\n // Sort items within the category by their order in ACTION_CONFIG\n const sortedItems = items.sort((a, b) => {\n const orderA = actionConfigOrder.indexOf(a.type);\n const orderB = actionConfigOrder.indexOf(b.type);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n });\n categories.push({\n name: metadata.title,\n description: metadata.description,\n color: metadata.color,\n items: sortedItems,\n isBranching: false\n });\n });\n\n // Add splitting action categories (with modified description to indicate they split)\n // Also sorted by implicit order\n // Get the implicit order of nodes from NODE_CONFIG\n const nodeConfigOrder = Object.keys(NODE_CONFIG);\n\n const sortedSplitCategories = Array.from(splitsByGroup.entries()).sort(\n ([groupA], [groupB]) => {\n const orderA = actionGroupOrder.indexOf(groupA);\n const orderB = actionGroupOrder.indexOf(groupB);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n }\n );\n\n sortedSplitCategories.forEach(([group, items]) => {\n const metadata = ACTION_GROUP_METADATA[group];\n // Sort items within the category by their order in NODE_CONFIG\n const sortedItems = items.sort((a, b) => {\n const orderA = nodeConfigOrder.indexOf(a.type);\n const orderB = nodeConfigOrder.indexOf(b.type);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n });\n categories.push({\n name: metadata.title,\n description: metadata.description,\n color: metadata.color,\n items: sortedItems,\n isBranching: true\n });\n });\n\n return categories;\n } else {\n // Group splits by group\n const itemsByGroup = new Map<\n string,\n Array<{ type: string; config: NodeConfig }>\n >();\n\n Object.entries(NODE_CONFIG)\n .filter(([type, config]) => {\n // exclude execute_actions (it's the default action-only node)\n // exclude nodes that have showAsAction=true (they appear in action mode)\n // exclude aliases (type won't match config.type for aliases)\n return (\n type !== 'execute_actions' &&\n type === config.type &&\n config.name &&\n !config.showAsAction &&\n this.isConfigAvailable(config)\n );\n })\n .forEach(([type, config]) => {\n const group = config.group || SPLIT_GROUPS.split;\n if (!itemsByGroup.has(group)) {\n itemsByGroup.set(group, []);\n }\n itemsByGroup.get(group)!.push({ type, config });\n });\n\n // Convert to categories using group metadata, sorted by implicit order from SPLIT_GROUPS\n const splitGroupOrder = Object.keys(SPLIT_GROUPS);\n // Get the implicit order of nodes from NODE_CONFIG\n const nodeConfigOrder = Object.keys(NODE_CONFIG);\n\n return Array.from(itemsByGroup.entries())\n .map(([group, items]) => {\n const metadata =\n SPLIT_GROUP_METADATA[group] || ACTION_GROUP_METADATA[group];\n // Sort items within the category by their order in NODE_CONFIG\n const sortedItems = items.sort((a, b) => {\n const orderA = nodeConfigOrder.indexOf(a.type);\n const orderB = nodeConfigOrder.indexOf(b.type);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n });\n return {\n name: metadata.title,\n description: metadata.description,\n color: metadata.color,\n items: sortedItems\n };\n })\n .sort((a, b) => {\n // Find the group key by looking up metadata by title\n const groupA = Object.keys(SPLIT_GROUP_METADATA).find(\n (key) => SPLIT_GROUP_METADATA[key].title === a.name\n )!;\n const groupB = Object.keys(SPLIT_GROUP_METADATA).find(\n (key) => SPLIT_GROUP_METADATA[key].title === b.name\n )!;\n const orderA = splitGroupOrder.indexOf(groupA);\n const orderB = splitGroupOrder.indexOf(groupB);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n });\n }\n }\n\n public render(): TemplateResult {\n if (!this.open) {\n return html``;\n }\n\n const categories = this.getCategories();\n const title =\n this.mode === 'split'\n ? 'Select a Split'\n : this.mode === 'action-no-branching'\n ? 'Add Action'\n : 'Select an Action';\n\n // Separate regular and branching categories for action mode\n const regularCategories = categories.filter((c) => !c.isBranching);\n const branchingCategories = categories.filter((c) => c.isBranching);\n const hasBranchingSection = branchingCategories.length > 0;\n\n return html`\n <div class=\"overlay\" @click=${this.handleOverlayClick}></div>\n <div class=\"dialog\" @click=${(e: Event) => e.stopPropagation()}>\n <div class=\"header\">\n <h2>${title}</h2>\n </div>\n <div class=\"content\">\n ${this.mode === 'action' || this.mode === 'action-no-branching'\n ? html`\n <div class=\"section-regular\">\n ${regularCategories.map(\n (category) => html`\n <div class=\"category\">\n <div class=\"category-title\">${category.name}</div>\n <div class=\"category-description\">\n ${category.description}\n </div>\n <div class=\"items-grid\">\n ${category.items.map(\n (item) => html`\n <div\n class=\"node-item\"\n style=\"--item-color: ${category.color}\"\n @click=${() =>\n this.handleNodeTypeClick(item.type)}\n >\n <div class=\"node-item-title\">\n ${item.config.name}\n </div>\n </div>\n `\n )}\n </div>\n </div>\n `\n )}\n </div>\n ${hasBranchingSection\n ? html`\n <div class=\"section-branching\">\n <div class=\"section-header\">\n <div class=\"section-title\">Actions that Branch</div>\n <div class=\"section-description\">\n These actions also split the flow based on their\n outcome\n </div>\n </div>\n ${branchingCategories.map(\n (category) => html`\n <div class=\"category\">\n <div class=\"category-title\">${category.name}</div>\n <div class=\"category-description\">\n ${category.description}\n </div>\n <div class=\"items-grid\">\n ${category.items.map(\n (item) => html`\n <div\n class=\"node-item\"\n style=\"--item-color: ${category.color}\"\n @click=${() =>\n this.handleNodeTypeClick(item.type)}\n >\n <div class=\"node-item-title\">\n ${item.config.name}\n </div>\n </div>\n `\n )}\n </div>\n </div>\n `\n )}\n </div>\n `\n : ''}\n `\n : html`\n <div class=\"section-regular\">\n ${categories.map(\n (category) => html`\n <div class=\"category\">\n <div class=\"category-title\">${category.name}</div>\n <div class=\"category-description\">\n ${category.description}\n </div>\n <div class=\"items-grid\">\n ${category.items.map(\n (item) => html`\n <div\n class=\"node-item\"\n style=\"--item-color: ${category.color}\"\n @click=${() =>\n this.handleNodeTypeClick(item.type)}\n >\n <div class=\"node-item-title\">\n ${item.config.name}\n </div>\n </div>\n `\n )}\n </div>\n </div>\n `\n )}\n </div>\n `}\n </div>\n <div class=\"footer\">\n <temba-button @click=${this.close} secondary>Cancel</temba-button>\n </div>\n </div>\n `;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"NodeTypeSelector.js","sourceRoot":"","sources":["../../../src/flow/NodeTypeSelector.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { NODE_CONFIG, ACTION_CONFIG } from './config';\nimport {\n NodeConfig,\n ActionConfig,\n ACTION_GROUPS,\n SPLIT_GROUPS,\n ACTION_GROUP_METADATA,\n SPLIT_GROUP_METADATA\n} from './types';\n\n/**\n * Event detail for node type selection\n */\nexport interface NodeTypeSelection {\n nodeType: string;\n position: { x: number; y: number };\n}\n\n/**\n * Categorizes node types for display\n */\ninterface NodeCategory {\n name: string;\n description: string;\n color: string;\n items: Array<{ type: string; config: NodeConfig | ActionConfig }>;\n isBranching?: boolean; // true if this category contains actions that branch/split\n}\n\n/**\n * NodeTypeSelector - A dialog for selecting which type of node to create\n * Shows categorized lists of available actions and splits\n */\nexport class NodeTypeSelector extends RapidElement {\n static get styles() {\n return css`\n :host {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 10001;\n display: none;\n }\n\n :host([open]) {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n }\n\n .dialog {\n position: relative;\n background: white;\n border-radius: var(--curvature);\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);\n max-width: 700px;\n max-height: 80vh;\n width: 90%;\n display: flex;\n flex-direction: column;\n }\n\n .header {\n padding: 1.5em;\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n .header h2 {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n color: var(--color-text-dark);\n }\n\n .content {\n overflow-y: auto;\n overflow-x: hidden;\n flex: 1;\n padding: 0;\n }\n\n .section-regular {\n padding: 1.5em;\n }\n\n .section-branching {\n background: linear-gradient(\n 135deg,\n rgba(170, 170, 170, 0.12),\n rgba(170, 170, 170, 0.08)\n );\n padding: 1.5em;\n margin: 0 -1.5em;\n padding-left: 3em;\n padding-right: 3em;\n }\n\n .section-header {\n margin-bottom: 1.5em;\n padding-top: 1em;\n }\n\n .section-title {\n font-weight: 700;\n font-size: 1.1rem;\n color: var(--color-text-dark);\n margin-bottom: 0.35em;\n display: flex;\n align-items: center;\n }\n\n .section-title::before {\n content: '';\n display: inline-block;\n height: 1.2em;\n background: linear-gradient(\n 135deg,\n var(--color-primary-dark),\n var(--color-primary)\n );\n border-radius: 2px;\n }\n\n .section-description {\n font-size: 0.9rem;\n color: var(--color-text);\n opacity: 0.7;\n margin-left: 0em;\n padding-bottom: 1em;\n }\n\n .category {\n margin-bottom: 2em;\n }\n\n .category:last-child {\n margin-bottom: 0;\n }\n\n .category-title {\n font-weight: 600;\n color: var(--color-text-dark);\n margin-bottom: 0.5em;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n font-size: 0.9rem;\n opacity: 0.7;\n }\n\n .category-description {\n font-size: 0.85rem;\n color: var(--color-text);\n opacity: 0.6;\n margin-bottom: 0.75em;\n line-height: 1.4;\n }\n\n .items-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n gap: 0.75em;\n }\n\n .node-item {\n padding: 0.5em;\n padding-left: 1em;\n border: 1px solid rgba(0, 0, 0, 0.1);\n border-radius: calc(var(--curvature) * 0.75);\n cursor: pointer;\n transition: all 0.15s ease;\n background: white;\n position: relative;\n overflow: hidden;\n }\n\n .node-item::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n width: 4px;\n height: 100%;\n background: var(--item-color, rgba(0, 0, 0, 0.1));\n }\n\n .node-item:hover {\n border-color: var(--item-color, var(--color-primary));\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n }\n\n .node-item:hover::before {\n width: 6px;\n }\n\n .node-item-title {\n font-weight: 500;\n font-size: 1rem;\n color: var(--color-text-dark);\n }\n\n .node-item-type {\n font-size: 0.75rem;\n color: var(--color-text);\n opacity: 0.6;\n font-family: monospace;\n }\n\n .footer {\n padding: 1em 1.5em;\n border-top: 1px solid rgba(0, 0, 0, 0.1);\n display: flex;\n justify-content: flex-end;\n }\n\n temba-button {\n --button-y: 0.5em;\n --button-x: 1.25em;\n }\n `;\n }\n\n @property({ type: Boolean, reflect: true })\n public open = false;\n\n @property({ type: String })\n public mode: 'action' | 'split' | 'action-no-branching' = 'action';\n\n @property({ type: String })\n public flowType: string = 'message';\n\n @property({ type: Array })\n public features: string[] = [];\n\n @state()\n private clickPosition = { x: 0, y: 0 };\n\n public show(\n mode: 'action' | 'split' | 'action-no-branching',\n position: { x: number; y: number }\n ) {\n this.mode = mode;\n this.clickPosition = position;\n this.open = true;\n }\n\n public close(fireCanceledEvent: boolean = true) {\n if (this.open) {\n this.open = false;\n // Fire canceled event so parent can clean up, but only if not from a selection\n if (fireCanceledEvent) {\n this.fireCustomEvent(CustomEventType.Canceled, {});\n }\n }\n }\n\n /**\n * Check if a config is available for the current flow type and features\n */\n private isConfigAvailable(config: NodeConfig | ActionConfig): boolean {\n // Check flow type filter\n if (config.flowTypes !== undefined) {\n // Empty array means not available for any flow type in selector\n if (config.flowTypes.length === 0) {\n return false;\n }\n // Non-empty array means check if current flow type is included\n if (!config.flowTypes.includes(this.flowType as any)) {\n return false;\n }\n }\n // undefined/null flowTypes means available for all flow types\n\n // Check features filter - all required features must be present\n if (config.features && config.features.length > 0) {\n for (const requiredFeature of config.features) {\n if (!this.features.includes(requiredFeature)) {\n return false;\n }\n }\n }\n\n return true;\n }\n\n private handleNodeTypeClick(nodeType: string) {\n this.fireCustomEvent(CustomEventType.Selection, {\n nodeType,\n position: this.clickPosition\n } as NodeTypeSelection);\n // Close without firing canceled event since we made a selection\n this.close(false);\n }\n\n private handleOverlayClick() {\n this.close();\n }\n\n private getCategories(): NodeCategory[] {\n if (this.mode === 'action' || this.mode === 'action-no-branching') {\n // Group actions by group\n const actionsByGroup = new Map<\n string,\n Array<{ type: string; config: ActionConfig }>\n >();\n const splitsByGroup = new Map<\n string,\n Array<{ type: string; config: NodeConfig }>\n >();\n\n // Collect regular actions (from ACTION_CONFIG, unless hideFromActions is true)\n Object.entries(ACTION_CONFIG)\n .filter(([type, config]) => {\n // exclude aliases - if config has aliases, check if this type is an alias\n const isAlias = config.aliases && config.aliases.includes(type);\n return (\n !isAlias &&\n config.name &&\n !config.hideFromActions &&\n config.group &&\n this.isConfigAvailable(config)\n );\n })\n .forEach(([type, config]) => {\n const group = config.group;\n if (!actionsByGroup.has(group)) {\n actionsByGroup.set(group, []);\n }\n actionsByGroup.get(group)!.push({ type, config });\n });\n\n // Collect nodes that have showAsAction=true (these appear as \"with split\" actions)\n // Only if we're not in 'action-no-branching' mode\n if (this.mode === 'action') {\n Object.entries(NODE_CONFIG)\n .filter(([type, config]) => {\n return (\n type !== 'execute_actions' &&\n type === config.type && // exclude aliases (type won't match config.type for aliases)\n config.name &&\n config.showAsAction &&\n config.group &&\n this.isConfigAvailable(config)\n );\n })\n .forEach(([type, config]) => {\n const group = config.group!;\n if (!splitsByGroup.has(group)) {\n splitsByGroup.set(group, []);\n }\n splitsByGroup.get(group)!.push({ type, config });\n });\n }\n\n // Build categories - first regular actions, then splitting actions\n const categories: NodeCategory[] = [];\n\n // Get the implicit order from ACTION_GROUPS object\n const actionGroupOrder = Object.keys(ACTION_GROUPS);\n // Get the implicit order of actions from ACTION_CONFIG\n const actionConfigOrder = Object.keys(ACTION_CONFIG);\n\n // Add regular action categories sorted by implicit order\n const sortedActionCategories = Array.from(actionsByGroup.entries()).sort(\n ([groupA], [groupB]) => {\n const orderA = actionGroupOrder.indexOf(groupA);\n const orderB = actionGroupOrder.indexOf(groupB);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n }\n );\n\n sortedActionCategories.forEach(([group, items]) => {\n const metadata = ACTION_GROUP_METADATA[group];\n // Sort items within the category by their order in ACTION_CONFIG\n const sortedItems = items.sort((a, b) => {\n const orderA = actionConfigOrder.indexOf(a.type);\n const orderB = actionConfigOrder.indexOf(b.type);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n });\n categories.push({\n name: metadata.title,\n description: metadata.description,\n color: metadata.color,\n items: sortedItems,\n isBranching: false\n });\n });\n\n // Add splitting action categories (with modified description to indicate they split)\n // Also sorted by implicit order\n // Get the implicit order of nodes from NODE_CONFIG\n const nodeConfigOrder = Object.keys(NODE_CONFIG);\n\n const sortedSplitCategories = Array.from(splitsByGroup.entries()).sort(\n ([groupA], [groupB]) => {\n const orderA = actionGroupOrder.indexOf(groupA);\n const orderB = actionGroupOrder.indexOf(groupB);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n }\n );\n\n sortedSplitCategories.forEach(([group, items]) => {\n const metadata = ACTION_GROUP_METADATA[group];\n // Sort items within the category by their order in NODE_CONFIG\n const sortedItems = items.sort((a, b) => {\n const orderA = nodeConfigOrder.indexOf(a.type);\n const orderB = nodeConfigOrder.indexOf(b.type);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n });\n categories.push({\n name: metadata.title,\n description: metadata.description,\n color: metadata.color,\n items: sortedItems,\n isBranching: true\n });\n });\n\n return categories;\n } else {\n // Group splits by group\n const itemsByGroup = new Map<\n string,\n Array<{ type: string; config: NodeConfig }>\n >();\n\n Object.entries(NODE_CONFIG)\n .filter(([type, config]) => {\n // exclude execute_actions (it's the default action-only node)\n // exclude nodes that have showAsAction=true (they appear in action mode)\n // exclude nodes that have hideFromSplits=true (promoted to context menu)\n // exclude aliases (type won't match config.type for aliases)\n return (\n type !== 'execute_actions' &&\n type === config.type &&\n config.name &&\n !config.showAsAction &&\n !config.hideFromSplits &&\n this.isConfigAvailable(config)\n );\n })\n .forEach(([type, config]) => {\n const group = config.group || SPLIT_GROUPS.split;\n if (!itemsByGroup.has(group)) {\n itemsByGroup.set(group, []);\n }\n itemsByGroup.get(group)!.push({ type, config });\n });\n\n // Convert to categories using group metadata, sorted by implicit order from SPLIT_GROUPS\n const splitGroupOrder = Object.keys(SPLIT_GROUPS);\n // Get the implicit order of nodes from NODE_CONFIG\n const nodeConfigOrder = Object.keys(NODE_CONFIG);\n\n return Array.from(itemsByGroup.entries())\n .map(([group, items]) => {\n const metadata =\n SPLIT_GROUP_METADATA[group] || ACTION_GROUP_METADATA[group];\n // Sort items within the category by their order in NODE_CONFIG\n const sortedItems = items.sort((a, b) => {\n const orderA = nodeConfigOrder.indexOf(a.type);\n const orderB = nodeConfigOrder.indexOf(b.type);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n });\n return {\n name: metadata.title,\n description: metadata.description,\n color: metadata.color,\n items: sortedItems\n };\n })\n .sort((a, b) => {\n // Find the group key by looking up metadata by title\n const groupA = Object.keys(SPLIT_GROUP_METADATA).find(\n (key) => SPLIT_GROUP_METADATA[key].title === a.name\n )!;\n const groupB = Object.keys(SPLIT_GROUP_METADATA).find(\n (key) => SPLIT_GROUP_METADATA[key].title === b.name\n )!;\n const orderA = splitGroupOrder.indexOf(groupA);\n const orderB = splitGroupOrder.indexOf(groupB);\n return (\n (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)\n );\n });\n }\n }\n\n public render(): TemplateResult {\n if (!this.open) {\n return html``;\n }\n\n const categories = this.getCategories();\n const title =\n this.mode === 'split'\n ? 'Select a Split'\n : this.mode === 'action-no-branching'\n ? 'Add Action'\n : 'Select an Action';\n\n // Separate regular and branching categories for action mode\n const regularCategories = categories.filter((c) => !c.isBranching);\n const branchingCategories = categories.filter((c) => c.isBranching);\n const hasBranchingSection = branchingCategories.length > 0;\n\n return html`\n <div class=\"overlay\" @click=${this.handleOverlayClick}></div>\n <div class=\"dialog\" @click=${(e: Event) => e.stopPropagation()}>\n <div class=\"header\">\n <h2>${title}</h2>\n </div>\n <div class=\"content\">\n ${this.mode === 'action' || this.mode === 'action-no-branching'\n ? html`\n <div class=\"section-regular\">\n ${regularCategories.map(\n (category) => html`\n <div class=\"category\">\n <div class=\"category-title\">${category.name}</div>\n <div class=\"category-description\">\n ${category.description}\n </div>\n <div class=\"items-grid\">\n ${category.items.map(\n (item) => html`\n <div\n class=\"node-item\"\n style=\"--item-color: ${category.color}\"\n @click=${() =>\n this.handleNodeTypeClick(item.type)}\n >\n <div class=\"node-item-title\">\n ${item.config.name}\n </div>\n </div>\n `\n )}\n </div>\n </div>\n `\n )}\n </div>\n ${hasBranchingSection\n ? html`\n <div class=\"section-branching\">\n <div class=\"section-header\">\n <div class=\"section-title\">Actions that Branch</div>\n <div class=\"section-description\">\n These actions also split the flow based on their\n outcome\n </div>\n </div>\n ${branchingCategories.map(\n (category) => html`\n <div class=\"category\">\n <div class=\"category-title\">${category.name}</div>\n <div class=\"category-description\">\n ${category.description}\n </div>\n <div class=\"items-grid\">\n ${category.items.map(\n (item) => html`\n <div\n class=\"node-item\"\n style=\"--item-color: ${category.color}\"\n @click=${() =>\n this.handleNodeTypeClick(item.type)}\n >\n <div class=\"node-item-title\">\n ${item.config.name}\n </div>\n </div>\n `\n )}\n </div>\n </div>\n `\n )}\n </div>\n `\n : ''}\n `\n : html`\n <div class=\"section-regular\">\n ${categories.map(\n (category) => html`\n <div class=\"category\">\n <div class=\"category-title\">${category.name}</div>\n <div class=\"category-description\">\n ${category.description}\n </div>\n <div class=\"items-grid\">\n ${category.items.map(\n (item) => html`\n <div\n class=\"node-item\"\n style=\"--item-color: ${category.color}\"\n @click=${() =>\n this.handleNodeTypeClick(item.type)}\n >\n <div class=\"node-item-title\">\n ${item.config.name}\n </div>\n </div>\n `\n )}\n </div>\n </div>\n `\n )}\n </div>\n `}\n </div>\n <div class=\"footer\">\n <temba-button @click=${this.close} secondary>Cancel</temba-button>\n </div>\n </div>\n `;\n }\n}\n"]}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { isRightClick } from './utils';
|
|
2
|
+
/** Extract clientX/clientY from a MouseEvent or the first touch of a TouchEvent. */
|
|
3
|
+
function getClientCoords(e) {
|
|
4
|
+
if ('touches' in e) {
|
|
5
|
+
const touch = e.touches[0] || e.changedTouches[0];
|
|
6
|
+
return { clientX: touch.clientX, clientY: touch.clientY };
|
|
7
|
+
}
|
|
8
|
+
return {
|
|
9
|
+
clientX: e.clientX,
|
|
10
|
+
clientY: e.clientY
|
|
11
|
+
};
|
|
12
|
+
}
|
|
2
13
|
// Shared arrow/drag constants used by both Plumber and Editor
|
|
3
14
|
export const ARROW_LENGTH = 13;
|
|
4
15
|
export const ARROW_HALF_WIDTH = 6.5;
|
|
@@ -162,45 +173,62 @@ export class Plumber {
|
|
|
162
173
|
}
|
|
163
174
|
let pendingDrag = null;
|
|
164
175
|
const DRAG_THRESHOLD = 5;
|
|
165
|
-
const
|
|
166
|
-
if (isRightClick(e))
|
|
176
|
+
const beginPendingDrag = (e) => {
|
|
177
|
+
if ('button' in e && isRightClick(e))
|
|
167
178
|
return;
|
|
168
179
|
// Don't start drag from exit if it already has a connection —
|
|
169
180
|
// existing connections are picked up from the arrowhead instead
|
|
170
181
|
if (this.connections.has(exitId))
|
|
171
182
|
return;
|
|
172
|
-
const
|
|
173
|
-
|
|
183
|
+
const isTouch = 'touches' in e;
|
|
184
|
+
if (isTouch)
|
|
185
|
+
e.preventDefault();
|
|
186
|
+
const { clientX: startX, clientY: startY } = getClientCoords(e);
|
|
174
187
|
const nodeEl = element.closest('temba-flow-node');
|
|
175
188
|
const scope = (nodeEl === null || nodeEl === void 0 ? void 0 : nodeEl.getAttribute('uuid')) || '';
|
|
176
189
|
const originalTargetId = null;
|
|
177
190
|
const onMove = (me) => {
|
|
178
|
-
const
|
|
179
|
-
const
|
|
191
|
+
const { clientX, clientY } = getClientCoords(me);
|
|
192
|
+
const dx = clientX - startX;
|
|
193
|
+
const dy = clientY - startY;
|
|
180
194
|
if (Math.sqrt(dx * dx + dy * dy) > DRAG_THRESHOLD) {
|
|
181
195
|
// Exceeded threshold — start actual drag
|
|
182
|
-
|
|
183
|
-
document.removeEventListener('mouseup', onUp);
|
|
184
|
-
pendingDrag = null;
|
|
196
|
+
removePendingListeners();
|
|
185
197
|
this.startDrag(exitId, scope, originalTargetId, me);
|
|
186
198
|
}
|
|
187
199
|
};
|
|
188
200
|
const onUp = () => {
|
|
189
|
-
//
|
|
201
|
+
// Released without dragging — let click handler fire
|
|
202
|
+
removePendingListeners();
|
|
203
|
+
};
|
|
204
|
+
const removePendingListeners = () => {
|
|
190
205
|
document.removeEventListener('mousemove', onMove);
|
|
191
206
|
document.removeEventListener('mouseup', onUp);
|
|
207
|
+
document.removeEventListener('touchmove', onMove);
|
|
208
|
+
document.removeEventListener('touchend', onUp);
|
|
209
|
+
document.removeEventListener('touchcancel', onUp);
|
|
192
210
|
pendingDrag = null;
|
|
193
211
|
};
|
|
194
212
|
document.addEventListener('mousemove', onMove);
|
|
195
213
|
document.addEventListener('mouseup', onUp);
|
|
196
|
-
|
|
214
|
+
document.addEventListener('touchmove', onMove, { passive: false });
|
|
215
|
+
document.addEventListener('touchend', onUp);
|
|
216
|
+
document.addEventListener('touchcancel', onUp);
|
|
217
|
+
pendingDrag = { startX, startY, onMove, onUp, isTouch };
|
|
197
218
|
};
|
|
198
|
-
element.addEventListener('mousedown',
|
|
219
|
+
element.addEventListener('mousedown', beginPendingDrag);
|
|
220
|
+
element.addEventListener('touchstart', beginPendingDrag, {
|
|
221
|
+
passive: false
|
|
222
|
+
});
|
|
199
223
|
this.sources.set(exitId, () => {
|
|
200
|
-
element.removeEventListener('mousedown',
|
|
224
|
+
element.removeEventListener('mousedown', beginPendingDrag);
|
|
225
|
+
element.removeEventListener('touchstart', beginPendingDrag);
|
|
201
226
|
if (pendingDrag) {
|
|
202
227
|
document.removeEventListener('mousemove', pendingDrag.onMove);
|
|
203
228
|
document.removeEventListener('mouseup', pendingDrag.onUp);
|
|
229
|
+
document.removeEventListener('touchmove', pendingDrag.onMove);
|
|
230
|
+
document.removeEventListener('touchend', pendingDrag.onUp);
|
|
231
|
+
document.removeEventListener('touchcancel', pendingDrag.onUp);
|
|
204
232
|
pendingDrag = null;
|
|
205
233
|
}
|
|
206
234
|
});
|
|
@@ -489,29 +517,43 @@ export class Plumber {
|
|
|
489
517
|
});
|
|
490
518
|
// Make arrowhead draggable for picking up existing connections
|
|
491
519
|
const DRAG_THRESHOLD = 5;
|
|
492
|
-
const
|
|
493
|
-
if (isRightClick(e))
|
|
520
|
+
const onArrowDown = (e) => {
|
|
521
|
+
if ('button' in e && isRightClick(e))
|
|
494
522
|
return;
|
|
495
523
|
e.stopPropagation();
|
|
496
|
-
|
|
497
|
-
|
|
524
|
+
if ('touches' in e)
|
|
525
|
+
e.preventDefault();
|
|
526
|
+
const { clientX: startX, clientY: startY } = getClientCoords(e);
|
|
498
527
|
const onMove = (me) => {
|
|
499
|
-
const
|
|
500
|
-
const
|
|
528
|
+
const { clientX, clientY } = getClientCoords(me);
|
|
529
|
+
const dx = clientX - startX;
|
|
530
|
+
const dy = clientY - startY;
|
|
501
531
|
if (Math.sqrt(dx * dx + dy * dy) > DRAG_THRESHOLD) {
|
|
502
532
|
document.removeEventListener('mousemove', onMove);
|
|
503
533
|
document.removeEventListener('mouseup', onUp);
|
|
534
|
+
document.removeEventListener('touchmove', onMove);
|
|
535
|
+
document.removeEventListener('touchend', onUp);
|
|
536
|
+
document.removeEventListener('touchcancel', onUp);
|
|
504
537
|
this.startDrag(exitId, scope, toId, me);
|
|
505
538
|
}
|
|
506
539
|
};
|
|
507
540
|
const onUp = () => {
|
|
508
541
|
document.removeEventListener('mousemove', onMove);
|
|
509
542
|
document.removeEventListener('mouseup', onUp);
|
|
543
|
+
document.removeEventListener('touchmove', onMove);
|
|
544
|
+
document.removeEventListener('touchend', onUp);
|
|
545
|
+
document.removeEventListener('touchcancel', onUp);
|
|
510
546
|
};
|
|
511
547
|
document.addEventListener('mousemove', onMove);
|
|
512
548
|
document.addEventListener('mouseup', onUp);
|
|
549
|
+
document.addEventListener('touchmove', onMove, { passive: false });
|
|
550
|
+
document.addEventListener('touchend', onUp);
|
|
551
|
+
document.addEventListener('touchcancel', onUp);
|
|
513
552
|
};
|
|
514
|
-
arrowEl.addEventListener('mousedown',
|
|
553
|
+
arrowEl.addEventListener('mousedown', onArrowDown);
|
|
554
|
+
arrowEl.addEventListener('touchstart', onArrowDown, { passive: false });
|
|
555
|
+
pathEl.addEventListener('mousedown', onArrowDown);
|
|
556
|
+
pathEl.addEventListener('touchstart', onArrowDown, { passive: false });
|
|
515
557
|
// Mark the exit element as connected
|
|
516
558
|
const exitEl = document.getElementById(exitId);
|
|
517
559
|
if (exitEl) {
|
|
@@ -789,7 +831,9 @@ export class Plumber {
|
|
|
789
831
|
const contactUuid = target.getAttribute('data-uuid');
|
|
790
832
|
if (contactUuid) {
|
|
791
833
|
this.editor.fireCustomEvent('temba-contact-clicked', {
|
|
792
|
-
uuid: contactUuid
|
|
834
|
+
uuid: contactUuid,
|
|
835
|
+
metaKey: e.metaKey,
|
|
836
|
+
ctrlKey: e.ctrlKey
|
|
793
837
|
});
|
|
794
838
|
}
|
|
795
839
|
}
|
|
@@ -889,8 +933,17 @@ export class Plumber {
|
|
|
889
933
|
}
|
|
890
934
|
// --- Drag-and-drop ---
|
|
891
935
|
startDrag(exitId, scope, originalTargetId, e) {
|
|
892
|
-
//
|
|
893
|
-
|
|
936
|
+
// Hide (don't remove) the existing connection SVG while dragging.
|
|
937
|
+
// On iOS Safari, removing the element that received the original
|
|
938
|
+
// touchstart can trigger touchcancel, prematurely ending the drag.
|
|
939
|
+
// We defer removal until the drag ends.
|
|
940
|
+
const oldConn = this.connections.get(exitId);
|
|
941
|
+
if (oldConn) {
|
|
942
|
+
oldConn.svgEl.style.display = 'none';
|
|
943
|
+
const overlay = this.overlays.get(exitId);
|
|
944
|
+
if (overlay)
|
|
945
|
+
overlay.style.display = 'none';
|
|
946
|
+
}
|
|
894
947
|
const { svgEl, pathEl, arrowEl } = this.createSVGElement();
|
|
895
948
|
svgEl.classList.add('dragging');
|
|
896
949
|
// Ensure the drag SVG never intercepts mouse events (e.g. hover detection on nodes)
|
|
@@ -943,22 +996,30 @@ export class Plumber {
|
|
|
943
996
|
}
|
|
944
997
|
};
|
|
945
998
|
// Initial path to cursor (convert viewport to canvas coordinates)
|
|
946
|
-
const
|
|
947
|
-
const
|
|
999
|
+
const { clientX: initX, clientY: initY } = getClientCoords(e);
|
|
1000
|
+
const cursorX = this.toCanvas(initX - canvasRect.left);
|
|
1001
|
+
const cursorY = this.toCanvas(initY - canvasRect.top);
|
|
948
1002
|
updateDragPath(cursorX, cursorY);
|
|
949
1003
|
this.connectionDragging = true;
|
|
950
1004
|
const onMove = (me) => {
|
|
1005
|
+
if ('touches' in me)
|
|
1006
|
+
me.preventDefault();
|
|
951
1007
|
// Re-read canvasRect each move since scroll may have changed
|
|
952
1008
|
const rect = this.canvas.getBoundingClientRect();
|
|
953
|
-
const
|
|
954
|
-
const
|
|
1009
|
+
const { clientX, clientY } = getClientCoords(me);
|
|
1010
|
+
const cx = this.toCanvas(clientX - rect.left);
|
|
1011
|
+
const cy = this.toCanvas(clientY - rect.top);
|
|
955
1012
|
updateDragPath(cx, cy);
|
|
956
1013
|
};
|
|
957
1014
|
const onUp = (_me) => {
|
|
958
1015
|
document.removeEventListener('mousemove', onMove);
|
|
959
1016
|
document.removeEventListener('mouseup', onUp);
|
|
960
|
-
|
|
1017
|
+
document.removeEventListener('touchmove', onMove);
|
|
1018
|
+
document.removeEventListener('touchend', onUp);
|
|
1019
|
+
document.removeEventListener('touchcancel', onUp);
|
|
1020
|
+
// Remove the drag SVG and the hidden old connection SVG
|
|
961
1021
|
svgEl.remove();
|
|
1022
|
+
this.removeConnectionSVG(exitId);
|
|
962
1023
|
this.connectionDragging = false;
|
|
963
1024
|
this.dragState = null;
|
|
964
1025
|
// Fire abort event so Editor can handle connection logic
|
|
@@ -971,6 +1032,9 @@ export class Plumber {
|
|
|
971
1032
|
};
|
|
972
1033
|
document.addEventListener('mousemove', onMove);
|
|
973
1034
|
document.addEventListener('mouseup', onUp);
|
|
1035
|
+
document.addEventListener('touchmove', onMove, { passive: false });
|
|
1036
|
+
document.addEventListener('touchend', onUp);
|
|
1037
|
+
document.addEventListener('touchcancel', onUp);
|
|
974
1038
|
this.dragState = {
|
|
975
1039
|
sourceId: exitId,
|
|
976
1040
|
scope,
|