@bloonio/chat-angular 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,103 @@
1
+ /**
2
+ * `<bloonio-chat-thread>` — headless variant of the panel. Renders just
3
+ * the message log + input, no header, no floating chrome. Used when the
4
+ * tenant wants to embed the chat *inside* their own layout (e.g. inside
5
+ * a support modal, a sidebar, a help center page).
6
+ *
7
+ * Theming and behaviour are otherwise identical — the same
8
+ * `BloonioChatService` drives state, so a thread and a panel side-by-side
9
+ * stay in sync.
10
+ */
11
+ import { ChangeDetectionStrategy, Component, computed, inject, ViewChild, signal, } from '@angular/core';
12
+ import { BloonioChatService } from '../bloonio-chat.service';
13
+ import { InputBarComponent } from './input-bar.component';
14
+ import { MessageListComponent } from './message-list.component';
15
+ import { QuickRepliesComponent } from './quick-replies.component';
16
+ import * as i0 from "@angular/core";
17
+ export class BloonioChatThreadComponent {
18
+ chat = inject(BloonioChatService);
19
+ messagesRef;
20
+ lastScrollLen = signal(-1);
21
+ themeStyle = computed(() => {
22
+ const color = this.chat.bootstrap()?.branding_primary_color;
23
+ return color ? `--bch-primary: ${color}` : '';
24
+ });
25
+ visibleMessages = computed(() => {
26
+ const b = this.chat.bootstrap();
27
+ const messages = this.chat.messages();
28
+ if (b && !b.is_online && messages.length === 0) {
29
+ return [
30
+ {
31
+ id: 'sys_offline',
32
+ from: 'system',
33
+ content: b.offline_message,
34
+ },
35
+ ];
36
+ }
37
+ return messages;
38
+ });
39
+ ngAfterViewChecked() {
40
+ const el = this.messagesRef?.nativeElement;
41
+ if (!el)
42
+ return;
43
+ const len = this.visibleMessages().length + (this.chat.botTyping() ? 1 : 0);
44
+ if (len !== this.lastScrollLen()) {
45
+ el.scrollTop = el.scrollHeight;
46
+ this.lastScrollLen.set(len);
47
+ }
48
+ }
49
+ /** Convenience: thread is meant to be always-on, so it opens the
50
+ * service-level session as soon as it's instantiated.
51
+ * (Floating panel waits for the launcher click.) */
52
+ constructor() {
53
+ void this.chat.openPanel();
54
+ }
55
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatThreadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
56
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: BloonioChatThreadComponent, isStandalone: true, selector: "bloonio-chat-thread", viewQueries: [{ propertyName: "messagesRef", first: true, predicate: ["messages"], descendants: true }], ngImport: i0, template: `
57
+ <div class="bch-root" data-mode="inline" [style]="themeStyle()">
58
+ <div class="bch-panel">
59
+ <div class="bch-messages" #messages>
60
+ <bloonio-chat-message-list
61
+ [messages]="visibleMessages()"
62
+ [botTyping]="chat.botTyping()"
63
+ />
64
+ </div>
65
+ <bloonio-chat-quick-replies />
66
+ <bloonio-chat-input-bar
67
+ [disabled]="chat.connecting()"
68
+ (send)="chat.sendMessage($event)"
69
+ />
70
+ </div>
71
+ </div>
72
+ `, isInline: true, dependencies: [{ kind: "component", type: InputBarComponent, selector: "bloonio-chat-input-bar", inputs: ["disabled"], outputs: ["send"] }, { kind: "component", type: MessageListComponent, selector: "bloonio-chat-message-list", inputs: ["messages", "botTyping"] }, { kind: "component", type: QuickRepliesComponent, selector: "bloonio-chat-quick-replies" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
73
+ }
74
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatThreadComponent, decorators: [{
75
+ type: Component,
76
+ args: [{
77
+ selector: 'bloonio-chat-thread',
78
+ standalone: true,
79
+ imports: [InputBarComponent, MessageListComponent, QuickRepliesComponent],
80
+ changeDetection: ChangeDetectionStrategy.OnPush,
81
+ template: `
82
+ <div class="bch-root" data-mode="inline" [style]="themeStyle()">
83
+ <div class="bch-panel">
84
+ <div class="bch-messages" #messages>
85
+ <bloonio-chat-message-list
86
+ [messages]="visibleMessages()"
87
+ [botTyping]="chat.botTyping()"
88
+ />
89
+ </div>
90
+ <bloonio-chat-quick-replies />
91
+ <bloonio-chat-input-bar
92
+ [disabled]="chat.connecting()"
93
+ (send)="chat.sendMessage($event)"
94
+ />
95
+ </div>
96
+ </div>
97
+ `,
98
+ }]
99
+ }], ctorParameters: () => [], propDecorators: { messagesRef: [{
100
+ type: ViewChild,
101
+ args: ['messages']
102
+ }] } });
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyZWFkLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy90aHJlYWQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUNILE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsU0FBUyxFQUNULFFBQVEsRUFDUixNQUFNLEVBR04sU0FBUyxFQUNULE1BQU0sR0FDUCxNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQzs7QUF5QmxFLE1BQU0sT0FBTywwQkFBMEI7SUFDbEIsSUFBSSxHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBRXRCLFdBQVcsQ0FBOEI7SUFDaEUsYUFBYSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRWhCLFVBQVUsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQzVDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEVBQUUsc0JBQXNCLENBQUM7UUFDNUQsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLGtCQUFrQixLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ2hELENBQUMsQ0FBQyxDQUFDO0lBRWdCLGVBQWUsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQ2pELE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDaEMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUN0QyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMvQyxPQUFPO2dCQUNMO29CQUNFLEVBQUUsRUFBRSxhQUFhO29CQUNqQixJQUFJLEVBQUUsUUFBaUI7b0JBQ3ZCLE9BQU8sRUFBRSxDQUFDLENBQUMsZUFBZTtpQkFDM0I7YUFDRixDQUFDO1FBQ0osQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0lBRUgsa0JBQWtCO1FBQ2hCLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxXQUFXLEVBQUUsYUFBYSxDQUFDO1FBQzNDLElBQUksQ0FBQyxFQUFFO1lBQUUsT0FBTztRQUNoQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM1RSxJQUFJLEdBQUcsS0FBSyxJQUFJLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQztZQUNqQyxFQUFFLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUM7WUFDL0IsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDOUIsQ0FBQztJQUNILENBQUM7SUFFRDs7eURBRXFEO0lBQ3JEO1FBQ0UsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO0lBQzdCLENBQUM7d0dBekNVLDBCQUEwQjs0RkFBMUIsMEJBQTBCLHdMQWxCM0I7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQlQsNERBbEJTLGlCQUFpQiw0R0FBRSxvQkFBb0IseUdBQUUscUJBQXFCOzs0RkFvQjdELDBCQUEwQjtrQkF2QnRDLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLHFCQUFxQjtvQkFDL0IsVUFBVSxFQUFFLElBQUk7b0JBQ2hCLE9BQU8sRUFBRSxDQUFDLGlCQUFpQixFQUFFLG9CQUFvQixFQUFFLHFCQUFxQixDQUFDO29CQUN6RSxlQUFlLEVBQUUsdUJBQXVCLENBQUMsTUFBTTtvQkFDL0MsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JUO2lCQUNGO3dEQUlnQyxXQUFXO3NCQUF6QyxTQUFTO3VCQUFDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGA8Ymxvb25pby1jaGF0LXRocmVhZD5gIOKAlCBoZWFkbGVzcyB2YXJpYW50IG9mIHRoZSBwYW5lbC4gUmVuZGVycyBqdXN0XG4gKiB0aGUgbWVzc2FnZSBsb2cgKyBpbnB1dCwgbm8gaGVhZGVyLCBubyBmbG9hdGluZyBjaHJvbWUuIFVzZWQgd2hlbiB0aGVcbiAqIHRlbmFudCB3YW50cyB0byBlbWJlZCB0aGUgY2hhdCAqaW5zaWRlKiB0aGVpciBvd24gbGF5b3V0IChlLmcuIGluc2lkZVxuICogYSBzdXBwb3J0IG1vZGFsLCBhIHNpZGViYXIsIGEgaGVscCBjZW50ZXIgcGFnZSkuXG4gKlxuICogVGhlbWluZyBhbmQgYmVoYXZpb3VyIGFyZSBvdGhlcndpc2UgaWRlbnRpY2FsIOKAlCB0aGUgc2FtZVxuICogYEJsb29uaW9DaGF0U2VydmljZWAgZHJpdmVzIHN0YXRlLCBzbyBhIHRocmVhZCBhbmQgYSBwYW5lbCBzaWRlLWJ5LXNpZGVcbiAqIHN0YXkgaW4gc3luYy5cbiAqL1xuaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENvbXBvbmVudCxcbiAgY29tcHV0ZWQsXG4gIGluamVjdCxcbiAgQWZ0ZXJWaWV3Q2hlY2tlZCxcbiAgRWxlbWVudFJlZixcbiAgVmlld0NoaWxkLFxuICBzaWduYWwsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgeyBCbG9vbmlvQ2hhdFNlcnZpY2UgfSBmcm9tICcuLi9ibG9vbmlvLWNoYXQuc2VydmljZSc7XG5pbXBvcnQgeyBJbnB1dEJhckNvbXBvbmVudCB9IGZyb20gJy4vaW5wdXQtYmFyLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBNZXNzYWdlTGlzdENvbXBvbmVudCB9IGZyb20gJy4vbWVzc2FnZS1saXN0LmNvbXBvbmVudCc7XG5pbXBvcnQgeyBRdWlja1JlcGxpZXNDb21wb25lbnQgfSBmcm9tICcuL3F1aWNrLXJlcGxpZXMuY29tcG9uZW50JztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYmxvb25pby1jaGF0LXRocmVhZCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtJbnB1dEJhckNvbXBvbmVudCwgTWVzc2FnZUxpc3RDb21wb25lbnQsIFF1aWNrUmVwbGllc0NvbXBvbmVudF0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgY2xhc3M9XCJiY2gtcm9vdFwiIGRhdGEtbW9kZT1cImlubGluZVwiIFtzdHlsZV09XCJ0aGVtZVN0eWxlKClcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJiY2gtcGFuZWxcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImJjaC1tZXNzYWdlc1wiICNtZXNzYWdlcz5cbiAgICAgICAgICA8Ymxvb25pby1jaGF0LW1lc3NhZ2UtbGlzdFxuICAgICAgICAgICAgW21lc3NhZ2VzXT1cInZpc2libGVNZXNzYWdlcygpXCJcbiAgICAgICAgICAgIFtib3RUeXBpbmddPVwiY2hhdC5ib3RUeXBpbmcoKVwiXG4gICAgICAgICAgLz5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxibG9vbmlvLWNoYXQtcXVpY2stcmVwbGllcyAvPlxuICAgICAgICA8Ymxvb25pby1jaGF0LWlucHV0LWJhclxuICAgICAgICAgIFtkaXNhYmxlZF09XCJjaGF0LmNvbm5lY3RpbmcoKVwiXG4gICAgICAgICAgKHNlbmQpPVwiY2hhdC5zZW5kTWVzc2FnZSgkZXZlbnQpXCJcbiAgICAgICAgLz5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICBgLFxufSlcbmV4cG9ydCBjbGFzcyBCbG9vbmlvQ2hhdFRocmVhZENvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0NoZWNrZWQge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2hhdCA9IGluamVjdChCbG9vbmlvQ2hhdFNlcnZpY2UpO1xuXG4gIEBWaWV3Q2hpbGQoJ21lc3NhZ2VzJykgcHJpdmF0ZSBtZXNzYWdlc1JlZj86IEVsZW1lbnRSZWY8SFRNTERpdkVsZW1lbnQ+O1xuICBwcml2YXRlIGxhc3RTY3JvbGxMZW4gPSBzaWduYWwoLTEpO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSB0aGVtZVN0eWxlID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IGNvbG9yID0gdGhpcy5jaGF0LmJvb3RzdHJhcCgpPy5icmFuZGluZ19wcmltYXJ5X2NvbG9yO1xuICAgIHJldHVybiBjb2xvciA/IGAtLWJjaC1wcmltYXJ5OiAke2NvbG9yfWAgOiAnJztcbiAgfSk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHZpc2libGVNZXNzYWdlcyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBjb25zdCBiID0gdGhpcy5jaGF0LmJvb3RzdHJhcCgpO1xuICAgIGNvbnN0IG1lc3NhZ2VzID0gdGhpcy5jaGF0Lm1lc3NhZ2VzKCk7XG4gICAgaWYgKGIgJiYgIWIuaXNfb25saW5lICYmIG1lc3NhZ2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIFtcbiAgICAgICAge1xuICAgICAgICAgIGlkOiAnc3lzX29mZmxpbmUnLFxuICAgICAgICAgIGZyb206ICdzeXN0ZW0nIGFzIGNvbnN0LFxuICAgICAgICAgIGNvbnRlbnQ6IGIub2ZmbGluZV9tZXNzYWdlLFxuICAgICAgICB9LFxuICAgICAgXTtcbiAgICB9XG4gICAgcmV0dXJuIG1lc3NhZ2VzO1xuICB9KTtcblxuICBuZ0FmdGVyVmlld0NoZWNrZWQoKTogdm9pZCB7XG4gICAgY29uc3QgZWwgPSB0aGlzLm1lc3NhZ2VzUmVmPy5uYXRpdmVFbGVtZW50O1xuICAgIGlmICghZWwpIHJldHVybjtcbiAgICBjb25zdCBsZW4gPSB0aGlzLnZpc2libGVNZXNzYWdlcygpLmxlbmd0aCArICh0aGlzLmNoYXQuYm90VHlwaW5nKCkgPyAxIDogMCk7XG4gICAgaWYgKGxlbiAhPT0gdGhpcy5sYXN0U2Nyb2xsTGVuKCkpIHtcbiAgICAgIGVsLnNjcm9sbFRvcCA9IGVsLnNjcm9sbEhlaWdodDtcbiAgICAgIHRoaXMubGFzdFNjcm9sbExlbi5zZXQobGVuKTtcbiAgICB9XG4gIH1cblxuICAvKiogQ29udmVuaWVuY2U6IHRocmVhZCBpcyBtZWFudCB0byBiZSBhbHdheXMtb24sIHNvIGl0IG9wZW5zIHRoZVxuICAgKiAgc2VydmljZS1sZXZlbCBzZXNzaW9uIGFzIHNvb24gYXMgaXQncyBpbnN0YW50aWF0ZWQuXG4gICAqICAoRmxvYXRpbmcgcGFuZWwgd2FpdHMgZm9yIHRoZSBsYXVuY2hlciBjbGljay4pICovXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHZvaWQgdGhpcy5jaGF0Lm9wZW5QYW5lbCgpO1xuICB9XG59XG4iXX0=