Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
614cfd6
chore(workflow): upgrade npm CLI for trusted publishing OIDC support
blove May 1, 2026
570b031
docs(chat): document Tailwind v4 requirement for compositions
blove May 1, 2026
1b6b630
docs(specs): add chat library redesign design doc
blove May 1, 2026
a14184a
docs(plans): add chat redesign implementation plan
blove May 1, 2026
c4d5d38
feat(chat): add CHAT_HOST_TOKENS design-token constant
blove May 1, 2026
1db7ec8
feat(chat): ship optional chat.css global stylesheet
blove May 1, 2026
a0a0093
feat(chat): add chat-trace primitive
blove May 1, 2026
8362d7f
feat(chat): add chat-window primitive
blove May 1, 2026
29446c2
feat(chat): add chat-launcher-button primitive
blove May 1, 2026
59ec087
feat(chat): add chat-suggestions primitive
blove May 1, 2026
448df26
feat(chat): add chat-message primitive (asymmetric user/assistant)
blove May 1, 2026
5d9acc7
refactor(chat): rename chat-messages -> chat-message-list
blove May 1, 2026
6cab3ea
refactor(chat): rewrite chat-input with new pill design
blove May 1, 2026
dcd3013
refactor(chat): restyle chat-typing-indicator as 3-dot animation
blove May 1, 2026
2ea7ee2
refactor(chat): restyle chat-error
blove May 1, 2026
3924af5
refactor(chat): restyle chat-interrupt
blove May 1, 2026
88b2ec6
refactor(chat): restyle chat-thread-list, add optional new-thread button
blove May 1, 2026
fd274be
refactor(chat): restyle chat-generative-ui wrapper
blove May 1, 2026
6fe07b5
refactor(chat): rewrite chat-tool-call-card on chat-trace
blove May 1, 2026
83ea6ba
refactor(chat): rewrite chat-subagent-card on chat-trace
blove May 1, 2026
27f8d0f
refactor(chat): rewrite chat-timeline-slider as vertical history walk
blove May 1, 2026
0258555
feat(chat): default-render trace-based cards for tool-calls and subag…
blove May 1, 2026
b9a7115
refactor(chat): rewrite <chat> composition for new asymmetric design
blove May 1, 2026
207f157
feat(chat): add chat-popup floating composition
blove May 1, 2026
968c9fd
feat(chat): add chat-sidebar slide-in composition
blove May 1, 2026
e8cde56
refactor(chat): restyle chat-interrupt-panel
blove May 1, 2026
825b151
refactor(chat): restyle chat-debug + helpers (no Tailwind, new tokens)
blove May 1, 2026
f6fd430
refactor(chat): drop legacy chat-theme/chat-markdown style modules
blove May 1, 2026
5cc226d
refactor(chat): update public-api for new components
blove May 1, 2026
5258fda
chore(release): bump @ngaf/chat to 0.0.3
blove May 1, 2026
0e1da61
refactor(example-layouts): rewrite example-chat-layout without Tailwind
blove May 1, 2026
82447ce
refactor(example-layouts): rewrite example-split-layout without Tailwind
blove May 1, 2026
67623e5
chore(cockpit): update demos for @ngaf/chat 0.0.3 (rename + token mig…
blove May 1, 2026
95ca9ec
docs(chat): rewrite install/quickstart/theming for 0.0.3
blove May 1, 2026
f8361a0
docs(chat): add chat-popup/chat-sidebar/chat-trace pages + layout-mod…
blove May 1, 2026
5638be2
fix(chat): drop click-to-focus on input pill (a11y lint)
blove May 1, 2026
88e52da
fix(chat): repair message rendering broken by ng-content in @switch (…
blove May 1, 2026
a8ef972
chore(release): bump @ngaf/chat to 0.0.4
blove May 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ jobs:

- run: npm ci

# Trusted publishing requires npm CLI 11.5.1+. Node 22's bundled npm
# is 10.x which has partial OIDC support but doesn't fully implement
# the trusted-publishing flow against npm registry's OIDC endpoint.
- name: Upgrade npm to support trusted publishing
run: npm install -g npm@latest

- name: Lint, test, build publishable projects
run: npx nx run-many -t lint,test,build --projects=$NPM_PUBLISHABLE_PROJECTS --skip-nx-cache

Expand Down
16 changes: 8 additions & 8 deletions apps/website/content/docs/chat/components/chat-input.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ The component renders a `<form>` containing a `<textarea>` and a `<button>`. It

| Variable | Applied To |
|----------|-----------|
| `--chat-input-bg` | Form background |
| `--chat-input-border` | Form border (unfocused) |
| `--chat-input-focus-border` | Form border (focused) |
| `--chat-radius-input` | Form border radius |
| `--chat-text` | Textarea text color |
| `--chat-font-family` | Textarea font |
| `--chat-send-bg` | Send button background |
| `--chat-send-text` | Send button icon color |
| `--ngaf-chat-surface-alt` | Form background |
| `--ngaf-chat-separator` | Form border (unfocused) |
| `--ngaf-chat-muted` | Form border (focused) |
| `--ngaf-chat-radius-input` | Form border radius |
| `--ngaf-chat-text` | Textarea text color |
| `--ngaf-chat-font-family` | Textarea font |
| `--ngaf-chat-primary` | Send button background |
| `--ngaf-chat-on-primary` | Send button icon color |

## ARIA

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ The panel uses the chat theme's warning variables:

| Variable | Applied To |
|----------|-----------|
| `--chat-warning-bg` | Panel background |
| `--chat-warning-text` | Header and message text |
| `--chat-border` | Panel border |
| `--chat-radius-card` | Panel border radius |
| `--chat-bg-alt` | Action button backgrounds |
| `--chat-text` | Action button text |
| `--chat-text-muted` | Ignore button text |
| `--ngaf-chat-warning-bg` | Panel background |
| `--ngaf-chat-warning-text` | Header and message text |
| `--ngaf-chat-separator` | Panel border |
| `--ngaf-chat-radius-card` | Panel border radius |
| `--ngaf-chat-surface-alt` | Action button backgrounds |
| `--ngaf-chat-text` | Action button text |
| `--ngaf-chat-text-muted` | Ignore button text |

## Primitive Alternative: ChatInterruptComponent

Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
# ChatMessagesComponent
# ChatMessageListComponent

`ChatMessagesComponent` is the core primitive for rendering chat messages. It iterates over the messages from a `LangGraphAgent` and renders each one using a matching `MessageTemplateDirective`. This gives you full control over how each message type is displayed.
`ChatMessageListComponent` is the core primitive for rendering chat messages. It iterates over the messages from a `LangGraphAgent` and renders each one using a matching `MessageTemplateDirective`. This gives you full control over how each message type is displayed.

**Selector:** `chat-messages`
**Selector:** `chat-message-list`

**Import:**

```typescript
import {
ChatMessagesComponent,
ChatMessageListComponent,
MessageTemplateDirective,
getMessageType,
} from '@ngaf/chat';
```

## How It Works

1. The component reads `ref().messages()` to get the current message list
1. The component reads `agent().messages()` to get the current message list
2. For each message, it calls `getMessageType()` to determine the template type
3. It finds the matching `MessageTemplateDirective` among its content children
4. It renders the message using `ngTemplateOutlet` with the message as the implicit context

## Basic Usage

```html
<chat-messages [ref]="chatRef">
<chat-message-list [agent]="chatAgent">
<ng-template chatMessageTemplate="human" let-message>
<div class="user-bubble">{{ message.content }}</div>
</ng-template>
Expand All @@ -40,7 +40,7 @@ import {
<ng-template chatMessageTemplate="system" let-message>
<em>{{ message.content }}</em>
</ng-template>
</chat-messages>
</chat-message-list>
```

## API
Expand All @@ -49,7 +49,7 @@ import {

| Input | Type | Default | Description |
|-------|------|---------|-------------|
| `ref` | `LangGraphAgent<any, any>` | **Required** | The agent providing streaming state |
| `agent` | `LangGraphAgent<any, any>` | **Required** | The agent providing streaming state |

### Content Children

Expand Down Expand Up @@ -144,55 +144,50 @@ import { DomSanitizer } from '@angular/platform-browser';
import { agent } from '@ngaf/langgraph';
import type { BaseMessage } from '@langchain/core/messages';
import {
ChatMessagesComponent,
ChatMessageListComponent,
MessageTemplateDirective,
CHAT_MARKDOWN_STYLES,
renderMarkdown,
} from '@ngaf/chat';

@Component({
selector: 'app-messages-demo',
standalone: true,
imports: [ChatMessagesComponent, MessageTemplateDirective],
styles: [CHAT_MARKDOWN_STYLES],
imports: [ChatMessageListComponent, MessageTemplateDirective],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<chat-messages [ref]="chatRef">
<chat-message-list [agent]="chatAgent">
<ng-template chatMessageTemplate="human" let-message>
<div class="flex justify-end mb-4">
<div class="bg-blue-600 text-white rounded-2xl px-4 py-2 max-w-[70%]">
<div style="display: flex; justify-content: flex-end; margin-bottom: 1rem;">
<div style="background: var(--ngaf-chat-primary); color: var(--ngaf-chat-on-primary); border-radius: var(--ngaf-chat-radius-bubble); padding: 0.5rem 1rem; max-width: 70%;">
{{ message.content }}
</div>
</div>
</ng-template>

<ng-template chatMessageTemplate="ai" let-message>
<div class="flex gap-3 mb-4">
<div class="w-8 h-8 bg-gray-200 rounded-lg flex items-center justify-center text-xs font-bold">
AI
</div>
<div class="chat-md flex-1" [innerHTML]="renderMd(message.content)"></div>
<div style="display: flex; gap: 0.75rem; margin-bottom: 1rem;">
<div style="flex: 1;" [innerHTML]="renderMd(message.content)"></div>
</div>
</ng-template>

<ng-template chatMessageTemplate="tool" let-message>
<div class="bg-gray-100 rounded-lg p-3 font-mono text-sm mb-4">
<div style="background: var(--ngaf-chat-surface-alt); border-radius: var(--ngaf-chat-radius-card); padding: 0.75rem; font-family: var(--ngaf-chat-font-mono); font-size: var(--ngaf-chat-font-size-sm); margin-bottom: 1rem;">
{{ message.content }}
</div>
</ng-template>

<ng-template chatMessageTemplate="system" let-message>
<div class="text-center text-gray-500 text-xs italic mb-4">
<div style="text-align: center; color: var(--ngaf-chat-text-muted); font-size: var(--ngaf-chat-font-size-xs); font-style: italic; margin-bottom: 1rem;">
{{ message.content }}
</div>
</ng-template>
</chat-messages>
</chat-message-list>
`,
})
export class MessagesDemoComponent {
private sanitizer = inject(DomSanitizer);

chatRef = agent<{ messages: BaseMessage[] }>({
chatAgent = agent<{ messages: BaseMessage[] }>({
assistantId: 'chat_agent',
threadId: signal(null),
});
Expand Down
115 changes: 115 additions & 0 deletions apps/website/content/docs/chat/components/chat-popup.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# ChatPopupComponent

`ChatPopupComponent` is a composition that renders a floating launcher button in the bottom-right corner of the screen. Clicking the launcher opens a chat window as an overlay. The window can be toggled open and closed without destroying conversation state.

**Selector:** `chat-popup`

**Import:**

```typescript
import { ChatPopupComponent } from '@ngaf/chat';
```

## When to Use It

Use `ChatPopupComponent` when you want an unobtrusive chat entry point that does not occupy permanent screen real estate. The popup stays out of the way until the user chooses to engage, making it ideal for support chat, contextual help, and assistant features embedded in existing applications.

If you need the chat to always be visible, use [`<chat>`](/docs/chat/components/chat) (embedded) instead. If you need a slide-in panel alongside your app content, use [`<chat-sidebar>`](/docs/chat/components/chat-sidebar).

## Basic Usage

```typescript
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { agent } from '@ngaf/langgraph';
import { ChatPopupComponent } from '@ngaf/chat';

@Component({
selector: 'app-root',
standalone: true,
imports: [ChatPopupComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- your app content here -->
<chat-popup [agent]="chatAgent" />
`,
})
export class AppComponent {
protected readonly chatAgent = agent({
assistantId: 'chat_agent',
threadId: signal(null),
});
}
```

<Callout type="tip" title="Place at the root level">
`ChatPopupComponent` uses `position: fixed` internally. Place it as a direct child of your root component or app shell so it is not clipped by a parent with `overflow: hidden`.
</Callout>

## API

### Inputs

| Input | Type | Default | Description |
|-------|------|---------|-------------|
| `agent` | `LangGraphAgent<any, any>` | **Required** | The agent providing streaming state |
| `open` | `boolean` | `false` | Two-way bindable. Controls whether the chat window is open |

### Outputs

| Output | Type | Description |
|--------|------|-------------|
| `openChange` | `boolean` | Emits when the window opens or closes. Use with `[(open)]` for two-way binding |

### Slots

| Slot | Selector | Description |
|------|----------|-------------|
| Header content | `[chatHeader]` | Projected into the chat window header bar. Replaces the default title |

### Methods

| Method | Description |
|--------|-------------|
| `toggle()` | Toggles the window between open and closed |
| `openWindow()` | Opens the chat window |
| `closeWindow()` | Closes the chat window |

## Two-Way Binding

Control the open state from your component:

```typescript
@Component({
template: `
<button (click)="popup.openWindow()">Open Chat</button>
<chat-popup [(open)]="chatOpen" [agent]="chatAgent" #popup />
`,
})
export class AppComponent {
chatOpen = false;
chatAgent = agent({ assistantId: 'chat_agent', threadId: signal(null) });
}
```

## Custom Header

Project content into the window header with the `[chatHeader]` slot:

```html
<chat-popup [agent]="chatAgent">
<span chatHeader>Support Chat</span>
</chat-popup>
```

## Styling

The popup uses the standard `--ngaf-chat-*` token system. To adjust the launcher position:

```css
chat-popup {
--ngaf-chat-launcher-offset-x: 1.5rem;
--ngaf-chat-launcher-offset-y: 1.5rem;
}
```

See [Theming](/docs/chat/guides/theming) for the full token reference.
Loading