sketch: remove shadowDOM dependency from tool card components
Replace shadowDOM-based slot system with property-based composition in all
sketch-tool-card-[TOOL_NAME] components to support shadowDOM-free architecture.
Problem Analysis:
- sketch-tool-card component relied on HTML5 template slots which require shadowDOM
- 13 tool card components used sketch-tool-card as composition base via slots
- shadowDOM dependency blocked broader effort to reduce shadowDOM usage
- Need to preserve all existing functionality while removing slot dependency
Solution Implementation:
- Created sketch-tool-card-base component with property-based content injection
- Replaced slot system with summaryContent, inputContent, resultContent properties
- Maintained all existing styling, behavior, and expand/collapse functionality
- Migrated all 13 existing tool card components to use new base component
Components Migrated:
- sketch-tool-card-about-sketch
- sketch-tool-card-browser-clear-console-logs
- sketch-tool-card-browser-click
- sketch-tool-card-browser-eval
- sketch-tool-card-browser-get-text
- sketch-tool-card-browser-navigate
- sketch-tool-card-browser-recent-console-logs
- sketch-tool-card-browser-resize
- sketch-tool-card-browser-scroll-into-view
- sketch-tool-card-browser-type
- sketch-tool-card-browser-wait-for
- sketch-tool-card-read-image
- sketch-tool-card-take-screenshot
Migration Pattern:
- Changed from: <slot name="summary">content</slot>
- Changed to: .summaryContent=html content
- Preserved all component-specific styling and logic
- Maintained existing API surface for parent components
Architecture Benefits:
- Removes shadowDOM requirement from 13+ components
- Enables future shadowDOM-free component development
- Maintains backward compatibility during migration
- Preserves all existing tool card functionality
Files Added:
- sketch/webui/src/web-components/sketch-tool-card-base.ts (new shadowDOM-free base)
Files Modified:
- All 13 sketch-tool-card-[TOOL_NAME].ts components migrated to use new base
Verification:
- TypeScript compilation passes without errors
- Demo pages render correctly with consistent styling
- Expand/collapse behavior preserved across all tool types
Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: sa3288c1d986356e5k
diff --git a/webui/src/web-components/sketch-tool-card-browser-eval.ts b/webui/src/web-components/sketch-tool-card-browser-eval.ts
index 8a1ec54..4030b02 100644
--- a/webui/src/web-components/sketch-tool-card-browser-eval.ts
+++ b/webui/src/web-components/sketch-tool-card-browser-eval.ts
@@ -1,32 +1,17 @@
-import { css, html, LitElement } from "lit";
+import { html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ToolCall } from "../types";
+import { SketchTailwindElement } from "./sketch-tailwind-element";
+import "./sketch-tool-card-base";
@customElement("sketch-tool-card-browser-eval")
-export class SketchToolCardBrowserEval extends LitElement {
+export class SketchToolCardBrowserEval extends SketchTailwindElement {
@property()
toolCall: ToolCall;
@property()
open: boolean;
- static styles = css`
- .summary-text {
- font-family: monospace;
- color: #444;
- word-break: break-all;
- }
-
- .expression-input {
- font-family: monospace;
- background: rgba(0, 0, 0, 0.05);
- padding: 4px 8px;
- border-radius: 4px;
- display: inline-block;
- word-break: break-all;
- }
- `;
-
render() {
// Parse the input to get expression
let expression = "";
@@ -43,22 +28,33 @@
const displayExpression =
expression.length > 50 ? expression.substring(0, 50) + "..." : expression;
+ const summaryContent = html`<span class="font-mono text-gray-700 break-all">
+ 📱 ${displayExpression}
+ </span>`;
+ const inputContent = html`<div>
+ Evaluate:
+ <span
+ class="font-mono bg-black/[0.05] px-2 py-1 rounded inline-block break-all"
+ >${expression}</span
+ >
+ </div>`;
+ const resultContent = this.toolCall?.result_message?.tool_result
+ ? html`<pre
+ class="bg-gray-200 text-black p-2 rounded whitespace-pre-wrap break-words max-w-full w-full box-border"
+ >
+${this.toolCall.result_message.tool_result}</pre
+ >`
+ : "";
+
return html`
- <sketch-tool-card .open=${this.open} .toolCall=${this.toolCall}>
- <span slot="summary" class="summary-text">
- 📱 ${displayExpression}
- </span>
- <div slot="input">
- <div>
- Evaluate: <span class="expression-input">${expression}</span>
- </div>
- </div>
- <div slot="result">
- ${this.toolCall?.result_message?.tool_result
- ? html`<pre>${this.toolCall.result_message.tool_result}</pre>`
- : ""}
- </div>
- </sketch-tool-card>
+ <sketch-tool-card-base
+ .open=${this.open}
+ .toolCall=${this.toolCall}
+ .summaryContent=${summaryContent}
+ .inputContent=${inputContent}
+ .resultContent=${resultContent}
+ >
+ </sketch-tool-card-base>
`;
}
}