From 96c40715c5e2590ed84e7dfb49d7854f9f2f7653 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 1 May 2026 15:20:21 -0700 Subject: [PATCH 1/3] fix(chat): repair message rendering broken by ng-content in @switch (0.0.4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found via fresh-install smoke test against @ngaf/chat@0.0.3. Multiple critical UX bugs that shipped to npm: 1. Message content never rendered. chat-message used `` inside `@switch @case` blocks; Angular's content projection is resolved at view-creation, so projected text/templates never reached the per-role slots. Result: empty user bubbles and empty assistant bodies. Fix: single root-level `` slot, role-driven CSS class on the body wrapper. Caret + controls visibility now driven by `data-streaming` / `data-current` / `data-role` host attributes + CSS, not @switch. 2. Empty state had no default content and didn't hide. The `[chatEmptyState]` slot in `` had no fallback, so first-time consumers saw a blank tall area. Even worse, the `[hidden]` attribute on the empty container was overridden by `display: flex` so the empty state stayed visible after messages existed. Fix: provide default fallback content in the ng-content slot (How can I help? / Ask anything to get started) and add `.chat-empty[hidden] { display: none; }` rule. 3. Input textarea didn't clear on submit. The new chat-input pill used a getter/setter proxy (messageTextProxy) for ngModel two-way binding, but ngModel doesn't reactively re-read getters when the underlying signal changes. Setting `messageText.set('')` after submit didn't update the textarea. Fix: switch to `[ngModel]="messageText()"` + `(ngModelChange)="messageText.set($event)"` — signal-native binding that updates reactively. Fixes validated end-to-end against a fresh `ng new` consumer with no Tailwind, no postcss, no global stylesheet. Embedded mode renders user bubble + streaming markdown assistant correctly; popup mode opens with full conversation; empty state shows with default content and hides cleanly. Bumps @ngaf/chat to 0.0.4. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../lib/compositions/chat/chat.component.ts | 16 ++++++--- .../chat-input/chat-input.component.ts | 7 ++-- .../chat-message/chat-message.component.ts | 36 +++++++++---------- .../src/lib/styles/chat-message.styles.ts | 12 +++++-- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/libs/chat/src/lib/compositions/chat/chat.component.ts b/libs/chat/src/lib/compositions/chat/chat.component.ts index de94d7372..068180f65 100644 --- a/libs/chat/src/lib/compositions/chat/chat.component.ts +++ b/libs/chat/src/lib/compositions/chat/chat.component.ts @@ -63,7 +63,12 @@ import type { ChatRenderEvent } from './chat-render-event'; padding: 60px 20px; color: var(--ngaf-chat-text-muted); text-align: center; + flex: 1; + min-height: 0; } + .chat-empty[hidden] { display: none; } + .chat-empty__title { font-size: 1.125rem; font-weight: 500; color: var(--ngaf-chat-text); margin: 0; } + .chat-empty__sub { margin: 0; font-size: var(--ngaf-chat-font-size-sm); } .chat-empty__title { font-size: 1.125rem; font-weight: 500; color: var(--ngaf-chat-text); margin: 0; } .chat-empty__sub { margin: 0; font-size: var(--ngaf-chat-font-size-sm); } .chat-scroll { flex: 1; min-height: 0; overflow-y: auto; } @@ -85,11 +90,12 @@ import type { ChatRenderEvent } from './chat-render-event';
- @if (agent().messages().length === 0 && !agent().isLoading()) { -
- -
- } +
+ +

How can I help?

+

Ask anything to get started.

+
+
diff --git a/libs/chat/src/lib/primitives/chat-input/chat-input.component.ts b/libs/chat/src/lib/primitives/chat-input/chat-input.component.ts index 4fa9d6dfe..a1e2e7539 100644 --- a/libs/chat/src/lib/primitives/chat-input/chat-input.component.ts +++ b/libs/chat/src/lib/primitives/chat-input/chat-input.component.ts @@ -44,7 +44,8 @@ export function submitMessage(