diff --git a/app/assets/html/bzGraflow/nodesEIC.html b/app/assets/html/bzGraflow/nodesEIC.html
index 0e6f91a..ea17fc3 100644
--- a/app/assets/html/bzGraflow/nodesEIC.html
+++ b/app/assets/html/bzGraflow/nodesEIC.html
@@ -61,8 +61,7 @@
align-items: center;
justify-content: center;
}
- .bzgf-node[data-nodetype="refnodein"] .body{ background: #0F0; }
- .bzgf-node[data-nodetype="refnodeout"] .body{ background: #FF0; }
+ .bzgf-node[data-nodetype="refnodein"] .body, .bzgf-node[data-nodetype="refnodeout"] .body{ background: var(--eicui-base-color-grey-25); }
.bzgf-wire{ stroke: var(--eicui-base-color-info); stroke-width: 4px; stroke-dasharray: 10,5; }
diff --git a/app/assets/html/bzGraflow/nodesTest1.html b/app/assets/html/bzGraflow/nodesTest1.html
index be1d2aa..07533b6 100644
--- a/app/assets/html/bzGraflow/nodesTest1.html
+++ b/app/assets/html/bzGraflow/nodesTest1.html
@@ -96,8 +96,18 @@
.bzgf-node[data-nodetype="input"] .title,
.bzgf-node[data-nodetype="console"] .title{ background: #555; }
- .bzgf-node[data-nodetype="refnodein"] .body, .bzgf-node[data-nodetype="refnodeout"] body{
+ .bzgf-node[data-nodetype="refnodein"], .bzgf-node[data-nodetype="refnodeout"] {
+ width:3em;
+ height:3em;
+ padding: 2px;
+ }
+ .bzgf-node[data-nodetype="refnodein"] .body, .bzgf-node[data-nodetype="refnodeout"] .body{
border-radius: 50%;
+ width: 3em;
+ height: 3em;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
.bzgf-node[data-nodetype="refnodein"] .body{ background: #0F0; }
.bzgf-node[data-nodetype="refnodeout"] .body{ background: #FF0; }
@@ -181,11 +191,13 @@
\ No newline at end of file
diff --git a/app/assets/html/test.html b/app/assets/html/test.html
index a4cd4e6..096f89f 100644
--- a/app/assets/html/test.html
+++ b/app/assets/html/test.html
@@ -58,6 +58,9 @@
grflw1.addEventListener('subflowLoaded',
(evt) => { evt.target.querySelector('.demooptions').style.display = 'none'; }
)
+ grflw1.addEventListener('subflowExited',
+ (evt) => { evt.target.querySelector('.demooptions').style.display = 'block'; }
+ )
document.querySelector('[data-trigger="onAutoplace1H"]').addEventListener('click',
(evt) => { grflw1.autoPlace('horizontal', 80, 30, 1000, document.querySelector('[data-id="compunet"]').value) }
)
diff --git a/app/assets/json/bzGraflow/testFlow1.json b/app/assets/json/bzGraflow/testFlow1.json
index 8e4e638..eb8c1fe 100644
--- a/app/assets/json/bzGraflow/testFlow1.json
+++ b/app/assets/json/bzGraflow/testFlow1.json
@@ -7,19 +7,21 @@
"coords": { "x": 220, "y": 120}
},
{ "nodeType": "inc",
- "subflow": "/app/assets/json/bzGraflow/testFlowEic.json",
- "portLinks": [
- { "refNodeType": "refnodein", "refnodePort": "out1",
- "parentPort": "in1",
- "subflowNode":"aze2", "subflowPort": "in1",
- "direction": "in"
- },
- { "refNodeType": "refnodeout", "refnodePort": "in1",
- "parentPort": "out1",
- "subflowNode":"aze5", "subflowPort": "out1",
- "direction": "out"
- }
- ],
+ "subflow": {
+ "url": "/app/assets/json/bzGraflow/testFlowEic.json",
+ "portLinks": [
+ { "refNodeType": "refnodein", "refnodePort": "out1",
+ "parentPort": "in1",
+ "subflowNode":"aze2", "subflowPort": "in1",
+ "direction": "in"
+ },
+ { "refNodeType": "refnodeout", "refnodePort": "in1",
+ "parentPort": "out1",
+ "subflowNode":"aze5", "subflowPort": "out1",
+ "direction": "out"
+ }
+ ]
+ },
"id": "aze2",
"coords": { "x": 220, "y": 10}
},
diff --git a/app/assets/json/bzGraflow/testFlowEic.json b/app/assets/json/bzGraflow/testFlowEic.json
index d80d441..3f5058c 100644
--- a/app/assets/json/bzGraflow/testFlowEic.json
+++ b/app/assets/json/bzGraflow/testFlowEic.json
@@ -27,7 +27,22 @@
"title": "Data mapping",
"subtitle": "Associate content variables with attendees data"
},
- "data": { "a": "a3", "b":"b3"}
+ "data": { "a": "a3", "b":"b3"},
+ "subflow": {
+ "url": "/app/assets/json/bzGraflow/testFlowICMP.json",
+ "portLinks": [
+ { "refNodeType": "refnodein", "refnodePort": "out1",
+ "parentPort": "in1",
+ "subflowNode":"cid", "subflowPort": "in3",
+ "direction": "in"
+ },
+ { "refNodeType": "refnodeout", "refnodePort": "in1",
+ "parentPort": "out1",
+ "subflowNode":"signature", "subflowPort": "out2",
+ "direction": "out"
+ }
+ ]
+ }
},
{ "nodeType": "eicBasic",
"id": "aze4",
diff --git a/app/thirdparty/buildoz/bzGraflow.js b/app/thirdparty/buildoz/bzGraflow.js
index 72f64a9..4c634f7 100644
--- a/app/thirdparty/buildoz/bzGraflow.js
+++ b/app/thirdparty/buildoz/bzGraflow.js
@@ -202,30 +202,25 @@ class BZgraflow extends Buildoz{
const parentBB = this.getBoundingClientRect()
const flowNode = this.flow?.nodes?.find(n => n.id === id)
- const flowUrl = flowNode?.subflow
+ const flowUrl = flowNode.subflow.url
const childEl = document.createElement('bz-graflow')
childEl.setAttribute('flow', flowUrl)
childEl.setAttribute('tension', this.getBZAttribute('tension') || '60')
// Remember which node we "came from" so exitSubflow() can animate back to it.
childEl.dataset.enterNodeId = id
- // Match the clicked node's border so the transition feels like we're "expanding" it.
- const nodeStyle = getComputedStyle(nodeEl)
- childEl.style.border = nodeStyle.border
- childEl.style.borderRadius = nodeStyle.borderRadius
- childEl.style.backgroundColor = nodeStyle.backgroundColor
const btnExitSubflow = document.createElement('button')
btnExitSubflow.classList.add('bzgf-zoom-out')
this.addIcon(btnExitSubflow, 'zoomout')
btnExitSubflow.addEventListener('click', () => {
this.exitSubflow(childEl)
})
- childEl.appendChild(btnExitSubflow)
// Put the child in the exact same viewport rect as the parent (fixed overlay)
this.invade(this, childEl)
+ childEl.hostContainer.appendChild(btnExitSubflow)
childEl.addEventListener('flowLoaded', (e) => {
- for(const portLink of flowNode.portLinks){
+ for(const portLink of flowNode.subflow.portLinks){
const nid = crypto.randomUUID()
childEl.addNode({
"nodeType": portLink.refNodeType,
@@ -280,6 +275,12 @@ class BZgraflow extends Buildoz{
childEl.addEventListener('transitionend', (e) => {
if(e.propertyName !== 'transform') return
this.hostContainer.style.visibility = 'hidden'
+ // Important for nested subflows:
+ // A non-'none' transform on this element creates a containing block, which would make
+ // any nested `position:fixed` subflow overlay position relative to this element instead
+ // of the viewport (showing up as an extra offset like 8px).
+ childEl.style.transform = 'none'
+ childEl.style.willChange = ''
this.dispatchEvent(new CustomEvent('subflowLoaded', {
detail: { flowUrl },
bubbles: true,
@@ -330,7 +331,14 @@ class BZgraflow extends Buildoz{
this.hostContainer.style.opacity = '0'
this.hostContainer.style.transition = `opacity ${durMs}ms ease-in-out`
- // Ensure child animates (it should already have the transform transition set)
+ // Ensure child animates (it may have had transform cleared after enter)
+ childEl.style.transformOrigin = 'top left'
+ childEl.style.willChange = 'transform'
+ childEl.style.transform = 'translate(var(--tx, 0px), var(--ty, 0px)) scale(var(--sx, 1), var(--sy, 1))'
+ childEl.style.setProperty('--tx', '0px')
+ childEl.style.setProperty('--ty', '0px')
+ childEl.style.setProperty('--sx', 1)
+ childEl.style.setProperty('--sy', 1)
childEl.style.transition = `transform ${durMs}ms ease-in-out`
childEl.getBoundingClientRect() // flush
@@ -350,6 +358,12 @@ class BZgraflow extends Buildoz{
// Cleanup: ensure parent is fully visible and no longer hidden
this.hostContainer.style.opacity = '1'
this.hostContainer.style.visibility = 'visible'
+ childEl.style.willChange = ''
+ this.dispatchEvent(new CustomEvent('subflowExited', {
+ detail: { },
+ bubbles: true,
+ composed: true,
+ }))
}, { once:true })
}