diff --git a/examples/chat/angular/src/app/modes/welcome-suggestions.component.ts b/examples/chat/angular/src/app/modes/welcome-suggestions.component.ts index 2e2d10b7..59b2298a 100644 --- a/examples/chat/angular/src/app/modes/welcome-suggestions.component.ts +++ b/examples/chat/angular/src/app/modes/welcome-suggestions.component.ts @@ -43,11 +43,15 @@ import { FEATURED_SUGGESTIONS, MORE_SUGGESTIONS } from './welcome-suggestions'; :host { display: flex; justify-content: center; + width: 100%; + padding: 0 12px; + box-sizing: border-box; } .welcome-suggestions__row { display: flex; align-items: center; gap: 12px; + max-width: 100%; } .welcome-suggestions__featured { flex: 1 1 0; @@ -55,10 +59,25 @@ import { FEATURED_SUGGESTIONS, MORE_SUGGESTIONS } from './welcome-suggestions'; max-width: 380px; overflow: hidden; } + /* chat-welcome-suggestion host is display: inline-block by default + * (sizes to content). At narrow viewports this lets the inner + * button overflow the wrapper and get clipped at the wrapper's + * right edge ("hard right border"). Force block sizing here so + * the host follows the wrapper's flex-shrunk width and the + * label inside ellipsizes. */ + .welcome-suggestions__featured ::ng-deep chat-welcome-suggestion { + display: block; + width: 100%; + } + .welcome-suggestions__featured ::ng-deep .chat-welcome-suggestion { + width: 100%; + } .welcome-suggestions__featured ::ng-deep .chat-welcome-suggestion__label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + min-width: 0; + flex: 1 1 auto; } /* Make the "More prompts" dropdown match the featured chip visually. Scoped to .welcome-suggestions__row so the model picker (also diff --git a/examples/chat/angular/src/app/shell/demo-shell.component.css b/examples/chat/angular/src/app/shell/demo-shell.component.css index be95153e..a46ee7d7 100644 --- a/examples/chat/angular/src/app/shell/demo-shell.component.css +++ b/examples/chat/angular/src/app/shell/demo-shell.component.css @@ -46,7 +46,7 @@ .demo-shell__main[data-sidenav-mode="collapsed"] { padding-left: var(--ngaf-chat-sidenav-width-collapsed, 56px); } -@media (max-width: 1023px) { +@media (max-width: 767px) { .demo-shell__main[data-sidenav-mode] { padding-left: 0; } } @@ -185,6 +185,11 @@ * viewport minus the toolbar. */ height: calc(100% - var(--demo-toolbar-height)); } +/* chat-sidebar panel renders top-aligned with the page, NOT under the + * toolbar — so the panel's close button sits at the same viewport-y as + * the hamburger inside the toolbar (both at surface-top + 8 padding). + * The panel's z-index is below the toolbar's so the toolbar still + * renders above it where they overlap on the right edge. */ .demo-shell ::ng-deep .chat-sidebar__panel { - top: var(--demo-toolbar-height); + top: 0; } diff --git a/examples/chat/angular/src/app/shell/demo-shell.component.ts b/examples/chat/angular/src/app/shell/demo-shell.component.ts index 75c703dd..2e69ac65 100644 --- a/examples/chat/angular/src/app/shell/demo-shell.component.ts +++ b/examples/chat/angular/src/app/shell/demo-shell.component.ts @@ -180,8 +180,9 @@ export class DemoShell { (this.persistence.read('colorScheme') as 'light' | 'dark' | null) ?? 'dark', ); - /** Whether the threads drawer is open. Persisted across reloads. */ - protected readonly drawerOpen = signal(this.persistence.read('drawerOpen') ?? false); + /** Whether the threads drawer is open. Always starts closed on a fresh + * load — drawer mode is a transient UI state, not a persisted preference. */ + protected readonly drawerOpen = signal(false); /** Whether the Cmd+K search palette is open. */ protected readonly paletteOpen = signal(false); @@ -201,15 +202,15 @@ export class DemoShell { /** * User's chosen desktop sidenav mode. Persisted across reloads. - * Below 1024px the shell ignores this and forces drawer mode. + * Below 768px the shell ignores this and forces drawer mode. */ private readonly storedDesktopMode = signal<'expanded' | 'collapsed'>( (this.persistence.read('sidenavMode') as 'expanded' | 'collapsed' | null) ?? 'expanded', ); - /** Computed sidenav mode: viewport forces drawer below 1024px, else user preference. */ + /** Computed sidenav mode: viewport forces drawer below 768px, else user preference. */ protected readonly sidenavMode = computed(() => - this.viewportWidth() >= 1024 ? this.storedDesktopMode() : 'drawer', + this.viewportWidth() >= 768 ? this.storedDesktopMode() : 'drawer', ); /** Active threads filtered by the selected project (or all when none selected). */ @@ -399,7 +400,6 @@ export class DemoShell { protected onSidenavOpenChange(next: boolean): void { this.drawerOpen.set(next); - this.persistence.write('drawerOpen', next); } protected toggleSidenav(): void { diff --git a/libs/a2ui/package.json b/libs/a2ui/package.json index f4cc6a31..a5bcc9d5 100644 --- a/libs/a2ui/package.json +++ b/libs/a2ui/package.json @@ -1,6 +1,6 @@ { "name": "@ngaf/a2ui", - "version": "0.0.44", + "version": "0.0.46", "license": "MIT", "repository": { "type": "git", diff --git a/libs/ag-ui/package.json b/libs/ag-ui/package.json index af761f51..839eaccc 100644 --- a/libs/ag-ui/package.json +++ b/libs/ag-ui/package.json @@ -1,6 +1,6 @@ { "name": "@ngaf/ag-ui", - "version": "0.0.44", + "version": "0.0.46", "peerDependencies": { "@ngaf/chat": "*", "@ngaf/licensing": "*", diff --git a/libs/chat/package.json b/libs/chat/package.json index 560b8a3c..ff0db163 100644 --- a/libs/chat/package.json +++ b/libs/chat/package.json @@ -1,6 +1,6 @@ { "name": "@ngaf/chat", - "version": "0.0.44", + "version": "0.0.46", "exports": { "./chat.css": "./chat.css", "./themes/default-dark.css": "./themes/default-dark.css", diff --git a/libs/chat/src/lib/styles/chat-history-search-palette.styles.ts b/libs/chat/src/lib/styles/chat-history-search-palette.styles.ts index 366909f5..3a6cdecd 100644 --- a/libs/chat/src/lib/styles/chat-history-search-palette.styles.ts +++ b/libs/chat/src/lib/styles/chat-history-search-palette.styles.ts @@ -6,7 +6,7 @@ export const CHAT_HISTORY_SEARCH_PALETTE_STYLES = ` position: fixed; inset: 0; background: rgba(0, 0, 0, 0.4); - z-index: 50; + z-index: var(--ngaf-chat-z-modal-scrim, 1100); border: 0; padding: 0; cursor: pointer; @@ -22,7 +22,7 @@ export const CHAT_HISTORY_SEARCH_PALETTE_STYLES = ` border: 1px solid var(--ngaf-chat-separator); border-radius: 12px; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.25); - z-index: 51; + z-index: var(--ngaf-chat-z-modal, 1101); display: flex; flex-direction: column; overflow: hidden; diff --git a/libs/chat/src/lib/styles/chat-sidenav.styles.ts b/libs/chat/src/lib/styles/chat-sidenav.styles.ts index d56d4def..c3f28deb 100644 --- a/libs/chat/src/lib/styles/chat-sidenav.styles.ts +++ b/libs/chat/src/lib/styles/chat-sidenav.styles.ts @@ -65,6 +65,10 @@ export const CHAT_SIDENAV_STYLES = ` flex-shrink: 0; padding: var(--ngaf-chat-space-3); } + /* Collapse the header slot when the consumer doesn't project content + * — matches the chat-window pattern. Avoids 24px of dead space above + * the New chat button. */ + .chat-sidenav__header:empty { display: none; } .chat-sidenav__topbar { flex-shrink: 0; display: flex; diff --git a/libs/chat/src/lib/styles/chat-tokens.ts b/libs/chat/src/lib/styles/chat-tokens.ts index 6cb8745e..a0f494a3 100644 --- a/libs/chat/src/lib/styles/chat-tokens.ts +++ b/libs/chat/src/lib/styles/chat-tokens.ts @@ -122,10 +122,14 @@ const SPACING_TOKENS = ` const LAYER_TOKENS = ` /* Z-index layers — documented for consumers + future primitives. - * Default values listed; overridable per-app via :root or :host. */ + * Default values listed; overridable per-app via :root or :host. + * Modal layers sit above drawer so palettes/dialogs stay reachable + * when the drawer is open. */ --ngaf-chat-z-overlay-content: 30; /* chat-sidebar panel, chat-popup window */ --ngaf-chat-z-drawer-scrim: 1000; /* chat-sidenav-scrim backdrop */ --ngaf-chat-z-drawer: 1001; /* chat-sidenav drawer mode host */ + --ngaf-chat-z-modal-scrim: 1100; /* chat-history-search-palette backdrop */ + --ngaf-chat-z-modal: 1101; /* chat-history-search-palette dialog */ `; const EDGE_CLAIM_TOKENS = ` diff --git a/libs/chat/src/lib/styles/chat-window.styles.ts b/libs/chat/src/lib/styles/chat-window.styles.ts index bb97c35b..006ac27e 100644 --- a/libs/chat/src/lib/styles/chat-window.styles.ts +++ b/libs/chat/src/lib/styles/chat-window.styles.ts @@ -21,6 +21,11 @@ export const CHAT_WINDOW_STYLES = ` color: var(--ngaf-chat-primary); } .chat-window__header:empty { display: none; } + /* When the consumer doesn't project a header, balance the chat content + * with breathing room at the top equivalent to the input gap at the bottom. */ + .chat-window__header:empty + .chat-window__body { + padding-top: var(--ngaf-chat-input-gap); + } .chat-window__body { flex: 1; min-height: 0; diff --git a/libs/langgraph/package.json b/libs/langgraph/package.json index 4d401722..b85b225a 100644 --- a/libs/langgraph/package.json +++ b/libs/langgraph/package.json @@ -1,6 +1,6 @@ { "name": "@ngaf/langgraph", - "version": "0.0.44", + "version": "0.0.46", "peerDependencies": { "@ngaf/chat": "*", "@ngaf/licensing": "*", diff --git a/libs/licensing/package.json b/libs/licensing/package.json index 2d2f9d43..e35502ab 100644 --- a/libs/licensing/package.json +++ b/libs/licensing/package.json @@ -1,6 +1,6 @@ { "name": "@ngaf/licensing", - "version": "0.0.44", + "version": "0.0.46", "license": "MIT", "repository": { "type": "git", diff --git a/libs/render/package.json b/libs/render/package.json index 22699762..b44fba78 100644 --- a/libs/render/package.json +++ b/libs/render/package.json @@ -1,6 +1,6 @@ { "name": "@ngaf/render", - "version": "0.0.44", + "version": "0.0.46", "peerDependencies": { "@angular/core": "^20.0.0 || ^21.0.0", "@angular/common": "^20.0.0 || ^21.0.0", diff --git a/libs/telemetry/package.json b/libs/telemetry/package.json index 118a9bc9..ee6071d3 100644 --- a/libs/telemetry/package.json +++ b/libs/telemetry/package.json @@ -1,6 +1,6 @@ { "name": "@ngaf/telemetry", - "version": "0.0.44", + "version": "0.0.46", "license": "MIT", "publishConfig": { "access": "public"