fix: Transak modal not opening — namespace querySelector + wallet check
- Use DOM API (createElementNS + createElement) to build foreignObject panel instead of innerHTML, ensuring proper HTML namespace for querySelector to traverse SVG→HTML boundary - Query buttons/inputs from HTML panel root instead of SVG overlay - Remove wallet address requirement for demo mode (use zero address) - Add console logging and .catch() for Transak widget debugging Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1335c38d48
commit
f9bafc8ef0
|
|
@ -2491,28 +2491,34 @@ class FolkFlowsApp extends HTMLElement {
|
|||
return;
|
||||
}
|
||||
|
||||
// Source/outcome: keep config panel
|
||||
// Source/outcome: keep config panel — use DOM APIs for proper namespace handling
|
||||
const panelW = 280;
|
||||
const panelH = 260;
|
||||
const panelX = s.w + 12;
|
||||
const panelY = 0;
|
||||
|
||||
overlay.innerHTML += `
|
||||
<foreignObject x="${panelX}" y="${panelY}" width="${panelW}" height="${panelH}">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" class="inline-config-panel" style="height:${panelH}px">
|
||||
<div class="icp-tabs">
|
||||
<button class="icp-tab icp-tab--active" data-icp-tab="config">Config</button>
|
||||
<button class="icp-tab" data-icp-tab="analytics">Analytics</button>
|
||||
<button class="icp-tab" data-icp-tab="allocations">Alloc</button>
|
||||
</div>
|
||||
<div class="icp-body">${this.renderInlineConfigContent(node)}</div>
|
||||
<div class="icp-toolbar">
|
||||
<button class="iet-done" style="background:var(--rflows-btn-done);color:white">Done</button>
|
||||
<button class="iet-delete" style="background:var(--rflows-btn-delete);color:white">Delete</button>
|
||||
<button class="iet-panel" style="background:var(--rs-border-strong);color:var(--rs-text-primary)">...</button>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>`;
|
||||
const fo = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject");
|
||||
fo.setAttribute("x", String(panelX));
|
||||
fo.setAttribute("y", String(panelY));
|
||||
fo.setAttribute("width", String(panelW));
|
||||
fo.setAttribute("height", String(panelH));
|
||||
const panelDiv = document.createElement("div");
|
||||
panelDiv.className = "inline-config-panel";
|
||||
panelDiv.style.height = `${panelH}px`;
|
||||
panelDiv.innerHTML = `
|
||||
<div class="icp-tabs">
|
||||
<button class="icp-tab icp-tab--active" data-icp-tab="config">Config</button>
|
||||
<button class="icp-tab" data-icp-tab="analytics">Analytics</button>
|
||||
<button class="icp-tab" data-icp-tab="allocations">Alloc</button>
|
||||
</div>
|
||||
<div class="icp-body">${this.renderInlineConfigContent(node)}</div>
|
||||
<div class="icp-toolbar">
|
||||
<button class="iet-done" style="background:var(--rflows-btn-done);color:white">Done</button>
|
||||
<button class="iet-delete" style="background:var(--rflows-btn-delete);color:white">Delete</button>
|
||||
<button class="iet-panel" style="background:var(--rs-border-strong);color:var(--rs-text-primary)">...</button>
|
||||
</div>`;
|
||||
fo.appendChild(panelDiv);
|
||||
overlay.appendChild(fo);
|
||||
|
||||
g.appendChild(overlay);
|
||||
this.attachInlineConfigListeners(g, node);
|
||||
|
|
@ -2801,57 +2807,60 @@ class FolkFlowsApp extends HTMLElement {
|
|||
const overlay = g.querySelector(".inline-edit-overlay");
|
||||
if (!overlay) return;
|
||||
|
||||
// Get the HTML panel inside foreignObject for reliable cross-namespace queries
|
||||
const htmlPanel = overlay.querySelector("foreignObject")?.querySelector(".inline-config-panel") as HTMLElement | null;
|
||||
const queryRoot = htmlPanel || overlay;
|
||||
|
||||
// Tab switching
|
||||
overlay.querySelectorAll(".icp-tab").forEach((el) => {
|
||||
queryRoot.querySelectorAll(".icp-tab").forEach((el) => {
|
||||
el.addEventListener("click", (e: Event) => {
|
||||
e.stopPropagation();
|
||||
const tab = (el as HTMLElement).dataset.icpTab as "config" | "analytics" | "allocations";
|
||||
if (!tab || tab === this.inlineConfigTab) return;
|
||||
this.inlineConfigTab = tab;
|
||||
overlay.querySelectorAll(".icp-tab").forEach((t) => t.classList.remove("icp-tab--active"));
|
||||
queryRoot.querySelectorAll(".icp-tab").forEach((t) => t.classList.remove("icp-tab--active"));
|
||||
el.classList.add("icp-tab--active");
|
||||
const body = overlay.querySelector(".icp-body") as HTMLElement;
|
||||
const body = queryRoot.querySelector(".icp-body") as HTMLElement;
|
||||
if (body) body.innerHTML = this.renderInlineConfigContent(node);
|
||||
this.attachInlineConfigFieldListeners(overlay as Element, node);
|
||||
this.attachInlineConfigFieldListeners(queryRoot as Element, node);
|
||||
});
|
||||
});
|
||||
|
||||
// Field listeners
|
||||
this.attachInlineConfigFieldListeners(overlay, node);
|
||||
this.attachInlineConfigFieldListeners(queryRoot, node);
|
||||
|
||||
// Threshold drag handles (funnel)
|
||||
// Threshold drag handles (funnel — on SVG overlay, not HTML panel)
|
||||
this.attachThresholdDragListeners(overlay, node);
|
||||
|
||||
// Done button
|
||||
overlay.querySelector(".iet-done")?.addEventListener("click", (e: Event) => {
|
||||
queryRoot.querySelector(".iet-done")?.addEventListener("click", (e: Event) => {
|
||||
e.stopPropagation();
|
||||
this.exitInlineEdit();
|
||||
});
|
||||
|
||||
// Delete button
|
||||
overlay.querySelector(".iet-delete")?.addEventListener("click", (e: Event) => {
|
||||
queryRoot.querySelector(".iet-delete")?.addEventListener("click", (e: Event) => {
|
||||
e.stopPropagation();
|
||||
this.deleteNode(node.id);
|
||||
this.exitInlineEdit();
|
||||
});
|
||||
|
||||
// "..." panel button
|
||||
overlay.querySelector(".iet-panel")?.addEventListener("click", (e: Event) => {
|
||||
queryRoot.querySelector(".iet-panel")?.addEventListener("click", (e: Event) => {
|
||||
e.stopPropagation();
|
||||
this.exitInlineEdit();
|
||||
this.openEditor(node.id);
|
||||
});
|
||||
|
||||
// Fund Now button (source card type)
|
||||
overlay.querySelector("[data-icp-action='fund']")?.addEventListener("click", (e: Event) => {
|
||||
const fundBtn = queryRoot.querySelector("[data-icp-action='fund']");
|
||||
fundBtn?.addEventListener("click", (e: Event) => {
|
||||
e.stopPropagation();
|
||||
const sd = node.data as SourceNodeData;
|
||||
const flowId = this.flowId || this.getAttribute("flow-id") || "";
|
||||
if (!sd.walletAddress) {
|
||||
alert("Configure a wallet address first");
|
||||
return;
|
||||
}
|
||||
this.openTransakWidget(flowId, sd.walletAddress);
|
||||
// Use configured wallet or demo default (Transak staging accepts any valid address)
|
||||
const wallet = sd.walletAddress || "0x0000000000000000000000000000000000000000";
|
||||
this.openTransakWidget(flowId, wallet).catch((err) => console.error("[Transak] Error:", err));
|
||||
});
|
||||
|
||||
// Click-outside handler — listen on shadow root to avoid retargeting issues
|
||||
|
|
@ -3174,6 +3183,7 @@ class FolkFlowsApp extends HTMLElement {
|
|||
}
|
||||
|
||||
private async openTransakWidget(flowId: string, walletAddress: string) {
|
||||
console.log("[Transak] Opening widget for flow:", flowId, "wallet:", walletAddress);
|
||||
// Fetch Transak config from server
|
||||
let apiKey = "STAGING_KEY";
|
||||
let env = "STAGING";
|
||||
|
|
@ -3633,11 +3643,8 @@ class FolkFlowsApp extends HTMLElement {
|
|||
// Fund with card
|
||||
backdrop.querySelector('[data-action="fund-with-card"]')?.addEventListener("click", () => {
|
||||
const flowId = this.flowId || this.getAttribute("flow-id") || "";
|
||||
if (!d.walletAddress) {
|
||||
alert("Configure a wallet address first (use rIdentity passkey or enter manually)");
|
||||
return;
|
||||
}
|
||||
this.openTransakWidget(flowId, d.walletAddress);
|
||||
const wallet = d.walletAddress || "0x0000000000000000000000000000000000000000";
|
||||
this.openTransakWidget(flowId, wallet);
|
||||
});
|
||||
|
||||
// Connect with EncryptID
|
||||
|
|
|
|||
Loading…
Reference in New Issue