Skip to content

Commit d8e3bd7

Browse files
committed
fix(chatbot): disambiguate panel focus check and avoid color-mix on canvas (#325)
Address the fifth Copilot review: - isViewingChat keyed on `.filigran-chatbot`, which the toggle button also carries, so focusing the toggle was mistaken for viewing the chat and suppressed the completion notice. Key on `.filigran-chatbot.fixed` instead - the panel root carries both classes in every mode, the toggle button does not. - The waiting game set the canvas fillStyle to a color-mix() string, which is not reliably accepted as a canvas colour (some browsers fall back to opaque black). Use a single solid accent fillStyle and vary opacity via globalAlpha.
1 parent 394eb3a commit d8e3bd7

2 files changed

Lines changed: 13 additions & 9 deletions

File tree

packages/filigran-chatbot/src/components/ChatPanel.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,10 @@ export const ChatPanel: FunctionComponent<ChatPanelProps> = ({
184184
t,
185185
enabled: notifyOnComplete,
186186
onComplete: onTaskComplete,
187-
isViewingChat: () => typeof document !== 'undefined' && !!document.activeElement?.closest('.filigran-chatbot'),
187+
// Key on `.filigran-chatbot.fixed` (the panel root carries both in every
188+
// mode) rather than `.filigran-chatbot` alone, which the toggle button also
189+
// uses — otherwise focusing the toggle would be mistaken for viewing the chat.
190+
isViewingChat: () => typeof document !== 'undefined' && !!document.activeElement?.closest('.filigran-chatbot.fixed'),
188191
});
189192

190193
// Download an agent-generated file. The URL is resolved against the host

packages/filigran-chatbot/src/components/ChatWaitingGame.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,33 +232,34 @@ function createInvaderGame(canvas: HTMLCanvasElement, messages: string[], onMess
232232
}
233233
}
234234

235-
function withAlpha(a: number): string {
236-
return `color-mix(in srgb, ${accent} ${Math.round(a * 100)}%, transparent)`;
237-
}
238-
239235
function draw(): void {
240236
ctx.clearRect(0, 0, cssW, cssH);
241237

238+
// Single solid fill colour throughout; vary opacity via globalAlpha rather
239+
// than CSS color-mix() strings, which are not reliably accepted as a canvas
240+
// fillStyle on every browser (some fall back to opaque black).
241+
ctx.fillStyle = accent;
242+
242243
ctx.font = arcadeFont(fontPx);
243244
ctx.textBaseline = 'middle';
244-
ctx.fillStyle = withAlpha(0.85);
245+
ctx.globalAlpha = 0.85;
245246
for (const l of letters) {
246247
if (l.alive) ctx.fillText(l.char, l.x, letterY);
247248
}
248249

249-
ctx.fillStyle = accent;
250+
ctx.globalAlpha = 1;
250251
for (const b of bullets) {
251252
ctx.fillRect(b.x - 1, b.y, 2, 7);
252253
}
253254

254255
for (const p of particles) {
255-
ctx.fillStyle = withAlpha(Math.max(p.life, 0) * 0.9);
256+
ctx.globalAlpha = Math.max(p.life, 0) * 0.9;
256257
ctx.fillRect(p.x - 1.5, p.y - 1.5, 3, 3);
257258
}
258259

260+
ctx.globalAlpha = 1;
259261
const frame = INVADER_FRAMES[legFrame];
260262
const ox = Math.round(shipX - SPRITE_W / 2);
261-
ctx.fillStyle = accent;
262263
for (let r = 0; r < frame.length; r++) {
263264
const row = frame[r];
264265
for (let c = 0; c < row.length; c++) {

0 commit comments

Comments
 (0)