Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 8 additions & 1 deletion apps/website/content/docs/chat/api/api-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -2801,7 +2801,14 @@
"description": "",
"params": [],
"examples": [],
"properties": [],
"properties": [
{
"name": "clicked",
"type": "OutputEmitterRef<void>",
"description": "Fires when the inner <button> receives a click. Prefer this over\n binding `(click)` on the host element — explicit output gives\n consumers (and Playwright) an unambiguous click target that won't\n be intercepted by sibling overlays in higher stacking contexts.\n Native `(click)` on the host still works for back-compat: the\n click event bubbles through unchanged.",
"optional": false
}
],
"methods": []
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import { CHAT_HOST_TOKENS } from '../../styles/chat-tokens';
`],
template: `
<div class="chat-popup__launcher">
<chat-launcher-button (click)="toggle()" />
<chat-launcher-button (clicked)="toggle()" />
</div>
<div class="chat-popup__window" [attr.data-open]="open() ? 'true' : 'false'" role="dialog" aria-modal="false">
<button type="button" class="chat-popup__close" (click)="closeWindow()" aria-label="Close chat">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import { CHAT_HOST_TOKENS } from '../../styles/chat-tokens';
template: `
<div class="chat-sidebar__content"><ng-content /></div>
<div class="chat-sidebar__launcher">
<chat-launcher-button (click)="toggle()" />
<chat-launcher-button (clicked)="toggle()" />
</div>
<aside class="chat-sidebar__panel" [attr.data-open]="open() ? 'true' : 'false'" role="complementary" [attr.aria-hidden]="open() ? 'false' : 'true'">
<button type="button" class="chat-sidebar__close" (click)="closeWindow()" aria-label="Close chat">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,28 @@ describe('ChatLauncherButtonComponent', () => {
const svg = (fx.nativeElement as HTMLElement).querySelector('.chat-launcher-button svg');
expect(svg).toBeTruthy();
});

it('emits clicked output when the inner button is clicked', () => {
TestBed.configureTestingModule({});
const fx = TestBed.createComponent(ChatLauncherButtonComponent);
fx.detectChanges();
let fired = 0;
fx.componentInstance.clicked.subscribe(() => fired++);
const btn = (fx.nativeElement as HTMLElement).querySelector('button.chat-launcher-button') as HTMLButtonElement;
btn.click();
expect(fired).toBe(1);
});

it('keeps native (click) on the host working — event bubbles through', () => {
// Back-compat: existing consumers that bind `(click)` on
// <chat-launcher-button> must continue to fire on inner-button clicks.
TestBed.configureTestingModule({});
const fx = TestBed.createComponent(ChatLauncherButtonComponent);
fx.detectChanges();
let hostClicks = 0;
fx.nativeElement.addEventListener('click', () => hostClicks++);
const btn = (fx.nativeElement as HTMLElement).querySelector('button.chat-launcher-button') as HTMLButtonElement;
btn.click();
expect(hostClicks).toBe(1);
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Component, ChangeDetectionStrategy, output } from '@angular/core';
import { CHAT_HOST_TOKENS } from '../../styles/chat-tokens';
import { CHAT_LAUNCHER_BUTTON_STYLES } from '../../styles/chat-launcher-button.styles';

Expand All @@ -9,11 +9,19 @@ import { CHAT_LAUNCHER_BUTTON_STYLES } from '../../styles/chat-launcher-button.s
changeDetection: ChangeDetectionStrategy.OnPush,
styles: [CHAT_HOST_TOKENS, CHAT_LAUNCHER_BUTTON_STYLES],
template: `
<button type="button" class="chat-launcher-button" aria-label="Open chat">
<button type="button" class="chat-launcher-button" aria-label="Open chat" (click)="clicked.emit()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg>
</button>
`,
})
export class ChatLauncherButtonComponent {}
export class ChatLauncherButtonComponent {
/** Fires when the inner <button> receives a click. Prefer this over
* binding `(click)` on the host element — explicit output gives
* consumers (and Playwright) an unambiguous click target that won't
* be intercepted by sibling overlays in higher stacking contexts.
* Native `(click)` on the host still works for back-compat: the
* click event bubbles through unchanged. */
readonly clicked = output<void>();
}
Loading