feat(canvas): remove setMode; host A2UI in scaffold

This commit is contained in:
Peter Steinberger
2025-12-18 13:18:24 +01:00
parent dda6d7f9e1
commit 790079c3b6
12 changed files with 174 additions and 144 deletions

View File

@@ -1,10 +1,5 @@
import Foundation
public enum ClawdisCanvasMode: String, Codable, Sendable {
case canvas
case web
}
public struct ClawdisCanvasNavigateParams: Codable, Sendable, Equatable {
public var url: String
@@ -13,14 +8,6 @@ public struct ClawdisCanvasNavigateParams: Codable, Sendable, Equatable {
}
}
public struct ClawdisCanvasSetModeParams: Codable, Sendable, Equatable {
public var mode: ClawdisCanvasMode
public init(mode: ClawdisCanvasMode) {
self.mode = mode
}
}
public struct ClawdisCanvasEvalParams: Codable, Sendable, Equatable {
public var javaScript: String

View File

@@ -3,7 +3,6 @@ import Foundation
public enum ClawdisCanvasCommand: String, Codable, Sendable {
case show = "canvas.show"
case hide = "canvas.hide"
case setMode = "canvas.setMode"
case navigate = "canvas.navigate"
case evalJS = "canvas.eval"
case snapshot = "canvas.snapshot"

View File

@@ -69,10 +69,13 @@
100% { transform: translate3d(-10px, 8px, 0) scale(1.03); opacity: 0.43; }
}
canvas {
position: fixed;
inset: 0;
display:block;
width:100vw;
height:100vh;
touch-action: none;
z-index: 1;
}
#clawdis-status {
position: fixed;
@@ -80,6 +83,17 @@
display: grid;
place-items: center;
pointer-events: none;
z-index: 3;
}
#clawdis-a2ui-wrap {
position: fixed;
inset: 0;
display: none;
z-index: 2;
}
#clawdis-a2ui-wrap clawdis-a2ui-host {
display: block;
height: 100%;
}
#clawdis-status .card {
text-align: center;
@@ -112,6 +126,9 @@
<div class="subtitle" id="clawdis-status-subtitle">Waiting for agent</div>
</div>
</div>
<div id="clawdis-a2ui-wrap">
<clawdis-a2ui-host></clawdis-a2ui-host>
</div>
<script>
(() => {
const canvas = document.getElementById('clawdis-canvas');
@@ -152,7 +169,93 @@
}
};
})();
(() => {
const wrap = document.getElementById('clawdis-a2ui-wrap');
if (!wrap) return;
const candidates = [
// iOS (SwiftPM resources flattened)
"a2ui.bundle.js",
// Android (assets keep directory structure)
"../CanvasA2UI/a2ui.bundle.js",
"CanvasA2UI/a2ui.bundle.js",
];
const loadScript = (src) =>
new Promise((resolve, reject) => {
const el = document.createElement("script");
el.src = src;
el.async = true;
el.onload = () => resolve();
el.onerror = () => reject(new Error(`failed to load ${src}`));
document.head.appendChild(el);
});
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const installVisibilityHooks = () => {
const api = globalThis.clawdisA2UI;
if (!api || typeof api.applyMessages !== "function") return false;
if (globalThis.__clawdisA2UIVisibilityHooksInstalled) return true;
globalThis.__clawdisA2UIVisibilityHooksInstalled = true;
const show = () => { wrap.style.display = "block"; };
const hide = () => { wrap.style.display = "none"; };
const sync = () => {
try {
const surfaces =
typeof api.getSurfaces === "function" ? api.getSurfaces() : [];
if (Array.isArray(surfaces) && surfaces.length > 0) show();
else hide();
} catch {
hide();
}
};
const origApply = api.applyMessages.bind(api);
api.applyMessages = (messages) => {
const res = origApply(messages);
sync();
return res;
};
const origReset = api.reset.bind(api);
api.reset = () => {
const res = origReset();
hide();
return res;
};
hide();
return true;
};
(async () => {
if (globalThis.clawdisA2UI) {
installVisibilityHooks();
return;
}
let loaded = false;
for (const src of candidates) {
try {
await loadScript(src);
loaded = true;
break;
} catch {
// try next
}
}
if (!loaded) return;
// Wait for custom element upgrade + connectedCallback to publish globalThis.clawdisA2UI.
for (let i = 0; i < 60; i += 1) {
if (installVisibilityHooks()) return;
await sleep(50);
}
})().catch(() => {});
})();
</script>
</body>
</html>