@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.
- package/README.md +112 -0
- package/esm2022/bloonio-chat-angular.mjs +5 -0
- package/esm2022/index.mjs +25 -0
- package/esm2022/lib/bloonio-chat.service.mjs +311 -0
- package/esm2022/lib/bloonio-chat.token.mjs +46 -0
- package/esm2022/lib/components/input-bar.component.mjs +91 -0
- package/esm2022/lib/components/launcher.component.mjs +81 -0
- package/esm2022/lib/components/message-list.component.mjs +58 -0
- package/esm2022/lib/components/panel.component.mjs +211 -0
- package/esm2022/lib/components/quick-replies.component.mjs +58 -0
- package/esm2022/lib/components/thread.component.mjs +103 -0
- package/fesm2022/bloonio-chat-angular.mjs +958 -0
- package/fesm2022/bloonio-chat-angular.mjs.map +1 -0
- package/index.d.ts +27 -0
- package/lib/bloonio-chat.service.d.ts +79 -0
- package/lib/bloonio-chat.token.d.ts +67 -0
- package/lib/components/input-bar.component.d.ts +18 -0
- package/lib/components/launcher.component.d.ts +14 -0
- package/lib/components/message-list.component.d.ts +8 -0
- package/lib/components/panel.component.d.ts +31 -0
- package/lib/components/quick-replies.component.d.ts +10 -0
- package/lib/components/thread.component.d.ts +27 -0
- package/package.json +38 -0
- package/src/lib/styles/chat.css +268 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bloonio-chat-angular.mjs","sources":["../../src/lib/bloonio-chat.token.ts","../../src/lib/bloonio-chat.service.ts","../../src/lib/components/launcher.component.ts","../../src/lib/components/input-bar.component.ts","../../src/lib/components/message-list.component.ts","../../src/lib/components/quick-replies.component.ts","../../src/lib/components/panel.component.ts","../../src/lib/components/thread.component.ts","../../src/index.ts","../../src/bloonio-chat-angular.ts"],"sourcesContent":["/**\n * Dependency-injection plumbing for the Angular chat SDK.\n *\n * Consumers wire the SDK into their app via the standard Angular pattern\n * documented in docs/12 §7.3:\n *\n * // app.config.ts\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideBloonioChat({\n * tenantId: env.CHAT_TENANT_ID,\n * publicKey: env.CHAT_PUBLIC_KEY,\n * baseUrl: 'https://chat-relay.bloonio.com',\n * visitorTokenProvider: () => inject(HttpClient).get<{token: string}>(\n * '/api/chat/visitor-token'\n * ).pipe(map(r => r.token)),\n * locale: 'fr',\n * }),\n * ],\n * };\n */\n\nimport {\n inject,\n InjectionToken,\n type EnvironmentProviders,\n makeEnvironmentProviders,\n} from '@angular/core';\nimport type { Observable } from 'rxjs';\n\nimport type { Attachment } from '@bloonio/chat-client-core';\n\n/** Caller-supplied resolver for the tenant-signed visitor token.\n *\n * Two acceptable shapes:\n * - Returns nothing (or `null`) → SDK falls back to anonymous mode.\n * A session is minted via `/create/visitor-session` and the visitor\n * stays unidentified until you supply one.\n * - Returns a string / Observable<string> → SDK calls `/identify/visitor`\n * with this signed token to bind the anonymous session to a tenant user.\n */\nexport type VisitorTokenProvider =\n | (() => string | null | Promise<string | null> | Observable<string | null>)\n | undefined;\n\nexport interface BloonioChatConfig {\n /** Tenant UUID v7 (the canonical handle issued by chat_relay). */\n tenantId: string;\n /** `pk_…` widget key bound to the tenant's `allowed_origins`. */\n publicKey: string;\n /** Base URL of the chat relay (https://chat-relay.bloonio.com or local). */\n baseUrl: string;\n /** Visitor-identification resolver. See {@link VisitorTokenProvider}. */\n visitorTokenProvider?: VisitorTokenProvider;\n /** Default locale for new conversations. */\n locale?: string;\n /** Free-form metadata attached to every visitor session. */\n metadata?: Record<string, unknown>;\n /** Optional override of `window.location.origin` (tests / SSR). */\n origin?: string;\n /**\n * Pre-fetched attachments to attach to the first outbound message.\n * Reserved for phase 11; kept on the interface for forward compat.\n */\n attachments?: Attachment[];\n}\n\nexport const BLOONIO_CHAT_CONFIG = new InjectionToken<BloonioChatConfig>(\n 'BLOONIO_CHAT_CONFIG',\n);\n\n/** Standalone-provider factory.\n *\n * Returns ``EnvironmentProviders`` so consumers can spread it into\n * ``app.config.ts``'s providers array. The service itself is\n * ``providedIn: 'root'`` so we don't need an explicit provider entry — we\n * only need the config token to be registered.\n */\nexport function provideBloonioChat(\n config: BloonioChatConfig,\n): EnvironmentProviders {\n return makeEnvironmentProviders([\n { provide: BLOONIO_CHAT_CONFIG, useValue: config },\n ]);\n}\n\n/** Internal accessor used by the components to fail loud when the\n * consumer forgot ``provideBloonioChat()``. */\nexport function injectBloonioChatConfig(): BloonioChatConfig {\n const cfg = inject(BLOONIO_CHAT_CONFIG, { optional: true });\n if (!cfg) {\n throw new Error(\n '[bloonio-chat-angular] provideBloonioChat() was not called in your app.config.ts. ' +\n 'Add it to providers: [...] alongside provideRouter/provideHttpClient.',\n );\n }\n return cfg;\n}\n","/**\n * BloonioChatService — signals-based reactive state container.\n *\n * Mirrors the Preact widget's `Widget.tsx` state machine but uses Angular\n * signals so templates auto-track the slots they read. Public surface:\n *\n * readonly bootstrap = signal<WidgetBootstrapConfig | null>(null);\n * readonly session = signal<CreateVisitorSessionResponse | null>(null);\n * readonly messages = signal<ChatMessage[]>([]);\n * readonly botTyping = signal(false);\n * readonly open = signal(false);\n * readonly connecting= signal(false);\n * readonly unreadCount = computed(...);\n *\n * async open(): Promise<void>\n * close(): void\n * async toggle(): Promise<void>\n * sendMessage(text: string): void\n *\n * SSR-safe: every transport call (fetch, WebSocket) is gated behind a\n * platform check via `afterNextRender()` so server pre-rendering doesn't\n * try to open sockets.\n */\n\nimport {\n afterNextRender,\n computed,\n DestroyRef,\n inject,\n Injectable,\n signal,\n type Signal,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { PLATFORM_ID } from '@angular/core';\nimport { firstValueFrom, isObservable } from 'rxjs';\n\nimport {\n ChatClient,\n WSClient,\n type CreateVisitorSessionResponse,\n type ServerMsgFrame,\n type WidgetBootstrapConfig,\n} from '@bloonio/chat-client-core';\n\nimport { injectBloonioChatConfig } from './bloonio-chat.token';\n\nexport interface ChatMessage {\n id: string;\n from: 'visitor' | 'bot' | 'agent' | 'system';\n content: string;\n pending?: boolean;\n client_msg_id?: string;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class BloonioChatService {\n private readonly config = injectBloonioChatConfig();\n private readonly platformId = inject(PLATFORM_ID);\n private readonly destroyRef = inject(DestroyRef);\n\n /** True when running in the browser (vs. server pre-render). */\n private readonly isBrowser = isPlatformBrowser(this.platformId);\n\n /** Bootstrap config — populated by the first `loadBootstrap()` call. */\n readonly bootstrap = signal<WidgetBootstrapConfig | null>(null);\n /** Visitor session (id + JWT + expires_at) — set lazily on first open. */\n readonly session = signal<CreateVisitorSessionResponse | null>(null);\n /** Message log, oldest → newest. */\n readonly messages = signal<ChatMessage[]>([]);\n /** True between bot's typing(start) and typing(stop) frames. */\n readonly botTyping = signal(false);\n /** Panel visibility — drives Launcher / Panel rendering. */\n readonly open = signal(false);\n /** True while `ensureSession()` is in flight (initial WS handshake). */\n readonly connecting = signal(false);\n /** Set when the WS handshake fails permanently (e.g. tenant suspended). */\n readonly fatalError = signal<string | null>(null);\n\n /** Number of bot/agent messages received while the panel was closed.\n * Resets to 0 the moment the panel opens. */\n private readonly _seenCount = signal(0);\n readonly unreadCount: Signal<number> = computed(() => {\n if (this.open()) return 0;\n const total = this.messages().filter(\n (m) => m.from === 'bot' || m.from === 'agent',\n ).length;\n return Math.max(0, total - this._seenCount());\n });\n\n private client: ChatClient | null = null;\n private ws: WSClient | null = null;\n private bootstrapPromise: Promise<WidgetBootstrapConfig | null> | null = null;\n private sessionPromise: Promise<CreateVisitorSessionResponse | null> | null = null;\n\n constructor() {\n // SSR safety: schedule the initial bootstrap fetch on first browser render.\n afterNextRender(() => {\n this.loadBootstrap();\n });\n\n this.destroyRef.onDestroy(() => {\n this.ws?.close();\n this.ws = null;\n });\n }\n\n // ── Public methods ─────────────────────────────────────────────────────\n\n /** Toggle panel visibility. First open also opens the WS session. */\n async toggle(): Promise<void> {\n const next = !this.open();\n this.open.set(next);\n if (next) {\n this._seenCount.set(\n this.messages().filter((m) => m.from === 'bot' || m.from === 'agent').length,\n );\n await this.ensureSession();\n }\n }\n\n /** Force the panel open. */\n async openPanel(): Promise<void> {\n if (this.open()) return;\n await this.toggle();\n }\n\n /** Force the panel closed. Keeps the WS open so reopening is instant. */\n closePanel(): void {\n this.open.set(false);\n }\n\n /** Send a visitor message. No-op if the WS isn't connected. */\n sendMessage(content: string): void {\n const trimmed = content.trim();\n if (!trimmed || !this.ws) return;\n const clientMsgId = `c_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n this.messages.update((prev) => [\n ...prev,\n {\n id: clientMsgId,\n client_msg_id: clientMsgId,\n from: 'visitor',\n content: trimmed,\n pending: true,\n },\n ]);\n this.ws.send({ type: 'msg', client_msg_id: clientMsgId, content: trimmed });\n }\n\n // ── Internals ──────────────────────────────────────────────────────────\n\n private async loadBootstrap(): Promise<WidgetBootstrapConfig | null> {\n if (!this.isBrowser) return null;\n if (this.bootstrap()) return this.bootstrap();\n if (this.bootstrapPromise) return this.bootstrapPromise;\n\n this.bootstrapPromise = (async () => {\n try {\n const client = this.getClient();\n const cfg = await client.fetchWidgetConfig({\n tenantId: this.config.tenantId,\n widgetPublicKey: this.config.publicKey,\n origin: this.resolvedOrigin(),\n });\n this.bootstrap.set(cfg);\n return cfg;\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'unknown error';\n this.fatalError.set(`Bootstrap failed: ${msg}`);\n return null;\n }\n })();\n return this.bootstrapPromise;\n }\n\n private async ensureSession(): Promise<CreateVisitorSessionResponse | null> {\n if (!this.isBrowser) return null;\n if (this.session()) return this.session();\n if (this.sessionPromise) return this.sessionPromise;\n\n this.connecting.set(true);\n this.sessionPromise = (async () => {\n try {\n // Make sure bootstrap is resolved first — the visibility/online\n // flags it carries influence whether we connect at all.\n await this.loadBootstrap();\n\n const client = this.getClient();\n const session = await client.createVisitorSession({\n tenantId: this.config.tenantId,\n widgetPublicKey: this.config.publicKey,\n origin: this.resolvedOrigin(),\n locale: this.config.locale ?? 'fr',\n metadata: this.config.metadata ?? {},\n });\n this.session.set(session);\n this.openWebSocket(session);\n // Optional: identify the visitor server-side if the consumer wired\n // a token provider.\n this.tryIdentify(session).catch(() => undefined);\n return session;\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'unknown error';\n this.fatalError.set(`Session failed: ${msg}`);\n return null;\n } finally {\n this.connecting.set(false);\n }\n })();\n return this.sessionPromise;\n }\n\n private openWebSocket(session: CreateVisitorSessionResponse): void {\n if (this.ws) return;\n const ws = new WSClient(\n {\n baseUrl: this.config.baseUrl,\n visitorToken: session.visitor_token,\n heartbeatIntervalMs: 30_000,\n },\n {\n onWelcome: () => undefined,\n onMessage: (frame: ServerMsgFrame) => {\n this.messages.update((prev) => [\n ...prev,\n { id: frame.id, from: frame.from, content: frame.content },\n ]);\n },\n onAck: (frame) => {\n this.messages.update((prev) =>\n prev.map((m) =>\n m.client_msg_id === frame.client_msg_id\n ? { ...m, id: frame.server_msg_id, pending: false }\n : m,\n ),\n );\n },\n onTyping: (frame) => {\n if (frame.from === 'bot' || frame.from === 'agent') {\n this.botTyping.set(frame.state === 'start');\n }\n },\n onError: (frame) => {\n this.messages.update((prev) => [\n ...prev,\n { id: `err_${Date.now()}`, from: 'system', content: `Error: ${frame.message}` },\n ]);\n },\n // Phase 10c — agent takeover visibility. Renders a system message\n // and clears any stale bot-typing indicator (the bot's mid-stream\n // turn may have been pre-empted by the operator claim).\n onAgentJoined: (frame) => {\n this.messages.update((prev) => [\n ...prev,\n {\n id: `sys_join_${Date.now()}`,\n from: 'system',\n content: `${frame.agent_display_name} has joined the chat.`,\n },\n ]);\n this.botTyping.set(false);\n },\n onAgentLeft: () => {\n this.messages.update((prev) => [\n ...prev,\n {\n id: `sys_left_${Date.now()}`,\n from: 'system',\n content: 'The agent has left the chat.',\n },\n ]);\n this.botTyping.set(false);\n },\n // Phase 10f — chat_api opened a support ticket.\n onTicketCreated: (frame) => {\n const sla =\n frame.sla_hours === 1\n ? 'within 1h'\n : frame.sla_hours <= 24\n ? `within ${frame.sla_hours}h`\n : `within ${Math.round(frame.sla_hours / 24)}d`;\n this.messages.update((prev) => [\n ...prev,\n {\n id: `sys_ticket_${frame.ticket_id}`,\n from: 'system',\n content:\n `🎫 Support ticket #${frame.ticket_number} created — ` +\n `${frame.category} · ${frame.priority}. ` +\n `We'll follow up ${sla}.`,\n },\n ]);\n },\n },\n );\n this.ws = ws;\n ws.connect();\n }\n\n private async tryIdentify(\n session: CreateVisitorSessionResponse,\n ): Promise<void> {\n const provider = this.config.visitorTokenProvider;\n if (!provider) return;\n\n let raw: string | null | undefined;\n const result = provider();\n if (typeof result === 'string') {\n raw = result;\n } else if (isObservable(result)) {\n raw = await firstValueFrom(result);\n } else {\n raw = await result;\n }\n if (!raw) return;\n\n // Caller's token is `userId:signature` (colon-delimited). Falling back\n // to plain user_id when no colon is present is too easy to misuse —\n // require explicit signature to avoid identity forgery footguns.\n const sep = raw.indexOf(':');\n if (sep < 0) {\n this.fatalError.set(\n 'visitorTokenProvider returned a value without \"userId:signature\" — refusing to identify.',\n );\n return;\n }\n const userId = raw.slice(0, sep);\n const userSignature = raw.slice(sep + 1);\n await this.getClient().identifyVisitor({\n visitorToken: session.visitor_token,\n userId,\n userSignature,\n });\n }\n\n private getClient(): ChatClient {\n if (!this.client) {\n this.client = new ChatClient({ baseUrl: this.config.baseUrl });\n }\n return this.client;\n }\n\n private resolvedOrigin(): string {\n if (this.config.origin) return this.config.origin;\n if (this.isBrowser && typeof window !== 'undefined') {\n return window.location.origin;\n }\n // SSR-safe fallback; the relay validates origins server-side anyway.\n return '';\n }\n}\n","/**\n * Floating launcher — circular chat bubble with optional label.\n * Wraps the `BloonioChatService` so consumers just drop\n * `<bloonio-chat-launcher />` somewhere and the SDK handles state.\n */\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\n\nimport { BloonioChatService } from '../bloonio-chat.service';\n\n@Component({\n selector: 'bloonio-chat-launcher',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"bch-root\" [attr.data-position]=\"position()\" [style]=\"themeStyle()\">\n <button\n type=\"button\"\n class=\"bch-launcher\"\n [attr.aria-label]=\"ariaLabel()\"\n (click)=\"onToggle()\"\n >\n @if (label()) {\n <span class=\"bch-launcher-label\">{{ label() }}</span>\n }\n <span class=\"bch-launcher-bubble\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\" />\n </svg>\n </span>\n </button>\n </div>\n `,\n})\nexport class BloonioChatLauncherComponent {\n protected readonly chat = inject(BloonioChatService);\n\n protected readonly position = computed(\n () => this.chat.bootstrap()?.widget_position ?? 'right',\n );\n\n /** Tint the bubble with the tenant's brand colour (falls back to the\n * stylesheet default until bootstrap config loads). */\n protected readonly themeStyle = computed(() => {\n const color = this.chat.bootstrap()?.branding_primary_color;\n return color ? `--bch-primary: ${color}` : '';\n });\n\n protected readonly label = computed(() => {\n const b = this.chat.bootstrap();\n return b?.button_label_enabled ? b.button_label_text : null;\n });\n\n protected readonly ariaLabel = computed(() => {\n const unread = this.chat.unreadCount();\n return unread > 0\n ? `Open chat (${unread} unread)`\n : 'Open chat';\n });\n\n onToggle(): void {\n void this.chat.toggle();\n }\n}\n","/**\n * Visitor input bar — multi-line textarea + send button. Enter sends,\n * Shift+Enter inserts a newline. Emits `send` with the trimmed content\n * once it's non-empty.\n */\nimport {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n Output,\n signal,\n} from '@angular/core';\n\n@Component({\n selector: 'bloonio-chat-input-bar',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"bch-input\">\n <textarea\n rows=\"1\"\n placeholder=\"Enter your message...\"\n [disabled]=\"disabled\"\n [value]=\"value()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKey($event)\"\n ></textarea>\n <button\n type=\"button\"\n class=\"bch-input-send\"\n aria-label=\"Send\"\n [disabled]=\"!canSend()\"\n (click)=\"submit()\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\" />\n </svg>\n </button>\n </div>\n `,\n})\nexport class InputBarComponent {\n @Input() disabled = false;\n @Output() send = new EventEmitter<string>();\n\n protected readonly value = signal('');\n\n protected canSend(): boolean {\n return !this.disabled && this.value().trim().length > 0;\n }\n\n onInput(e: Event): void {\n this.value.set((e.target as HTMLTextAreaElement).value);\n }\n\n onKey(e: KeyboardEvent): void {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.submit();\n }\n }\n\n submit(): void {\n if (!this.canSend()) return;\n const trimmed = this.value().trim();\n this.send.emit(trimmed);\n this.value.set('');\n }\n}\n","/**\n * Renders the message log + typing indicator. Pure presentational —\n * receives messages + typing flag as inputs so it can also be used\n * outside the panel (custom layouts, debug screens).\n */\nimport {\n ChangeDetectionStrategy,\n Component,\n Input,\n} from '@angular/core';\n\nimport type { ChatMessage } from '../bloonio-chat.service';\n\n@Component({\n selector: 'bloonio-chat-message-list',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @for (m of messages; track m.id) {\n <div\n class=\"bch-bubble\"\n [attr.data-from]=\"m.from\"\n [attr.data-pending]=\"m.pending ? 'true' : null\"\n >\n {{ m.content }}\n </div>\n }\n @if (botTyping) {\n <div class=\"bch-typing\" aria-label=\"Assistant is typing\">\n <span></span><span></span><span></span>\n </div>\n }\n `,\n})\nexport class MessageListComponent {\n @Input({ required: true }) messages: ChatMessage[] = [];\n @Input() botTyping = false;\n}\n","/**\n * `<bloonio-chat-quick-replies>` — tenant-configured opening prompt chips,\n * shown under the welcome message until the visitor sends their first\n * message. Tapping a chip sends its text as that first message.\n *\n * Driven by `BloonioChatService` (reads `bootstrap().quick_replies` +\n * `messages()`), so it self-hides once the conversation starts. Used inside\n * both the floating panel and the headless thread.\n */\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\n\nimport { BloonioChatService } from '../bloonio-chat.service';\n\n@Component({\n selector: 'bloonio-chat-quick-replies',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (replies().length) {\n <div class=\"bch-quick-replies\" role=\"group\" aria-label=\"Suggested replies\">\n @for (reply of replies(); track reply) {\n <button type=\"button\" class=\"bch-quick-reply\" (click)=\"pick(reply)\">\n {{ reply }}\n </button>\n }\n </div>\n }\n `,\n})\nexport class QuickRepliesComponent {\n protected readonly chat = inject(BloonioChatService);\n\n /** Show the configured chips only until the visitor's first message. */\n protected readonly replies = computed<string[]>(() => {\n const bootstrap = this.chat.bootstrap();\n if (!bootstrap || bootstrap.quick_replies.length === 0) return [];\n const visitorSpoke = this.chat.messages().some((m) => m.from === 'visitor');\n return visitorSpoke ? [] : bootstrap.quick_replies;\n });\n\n protected pick(text: string): void {\n this.chat.sendMessage(text);\n }\n}\n","/**\n * Floating or docked chat panel. Renders the header, message list, input,\n * and footer. Sits inside `<bloonio-chat-launcher>` for the floating\n * variant, or stand-alone for `mode=\"docked\"`/`mode=\"inline\"`.\n */\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n Input,\n signal,\n type AfterViewChecked,\n ElementRef,\n ViewChild,\n} from '@angular/core';\n\nimport { BloonioChatService } from '../bloonio-chat.service';\nimport { InputBarComponent } from './input-bar.component';\nimport { MessageListComponent } from './message-list.component';\nimport { QuickRepliesComponent } from './quick-replies.component';\n\nexport type ChatPanelMode = 'floating' | 'docked' | 'inline';\n\n@Component({\n selector: 'bloonio-chat-panel',\n standalone: true,\n imports: [InputBarComponent, MessageListComponent, QuickRepliesComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div\n class=\"bch-root\"\n [class.bch-open]=\"visible()\"\n [attr.data-position]=\"position()\"\n [attr.data-mode]=\"mode\"\n >\n <div class=\"bch-panel\" [style]=\"themeStyle()\">\n <header class=\"bch-header\">\n <div class=\"bch-header-avatar\">\n @if (logoUrl()) {\n <img [src]=\"logoUrl()\" alt=\"\" />\n } @else {\n <span style=\"font-weight:600;font-size:15px\">{{ initials() }}</span>\n }\n </div>\n <div class=\"bch-header-title\">\n <div class=\"bch-header-name\">Chat with {{ displayName() }}</div>\n <div class=\"bch-header-status\">\n <span class=\"bch-header-status-dot\" [attr.data-online]=\"isOnlineStr()\"></span>\n {{ statusText() }}\n </div>\n </div>\n <button\n type=\"button\"\n class=\"bch-header-close\"\n aria-label=\"Close\"\n (click)=\"onClose()\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </header>\n\n <div class=\"bch-messages\" #messages>\n <bloonio-chat-message-list\n [messages]=\"visibleMessages()\"\n [botTyping]=\"chat.botTyping()\"\n />\n </div>\n\n <bloonio-chat-quick-replies />\n\n <bloonio-chat-input-bar\n [disabled]=\"chat.connecting()\"\n (send)=\"onSend($event)\"\n />\n\n <div class=\"bch-footer\">\n Powered by\n <a href=\"https://bloonio.com\" target=\"_blank\" rel=\"noopener noreferrer\">Bloonio</a>\n </div>\n </div>\n </div>\n `,\n})\nexport class BloonioChatPanelComponent implements AfterViewChecked {\n /** floating = paired with launcher (default). docked/inline = always-on\n * inside the page flow (use for SSR landing pages or sidebar layouts). */\n @Input() mode: ChatPanelMode = 'floating';\n\n protected readonly chat = inject(BloonioChatService);\n\n @ViewChild('messages') private messagesRef?: ElementRef<HTMLDivElement>;\n private lastScrollLen = signal(-1);\n\n protected readonly position = computed(\n () => this.chat.bootstrap()?.widget_position ?? 'right',\n );\n\n protected readonly visible = computed(() => {\n // Floating mode: only when service.open() is true.\n // Docked/inline: always rendered if bootstrap is loaded.\n if (this.mode === 'floating') return this.chat.open();\n return !!this.chat.bootstrap();\n });\n\n protected readonly themeStyle = computed(() => {\n const color = this.chat.bootstrap()?.branding_primary_color;\n return color ? `--bch-primary: ${color}` : '';\n });\n\n protected readonly displayName = computed(\n () => this.chat.bootstrap()?.branding_display_name\n ?? this.chat.bootstrap()?.tenant_name\n ?? 'Support',\n );\n\n protected readonly logoUrl = computed(\n () => this.chat.bootstrap()?.branding_logo_url ?? null,\n );\n\n protected readonly initials = computed(() =>\n this.displayName()\n .split(/\\s+/)\n .slice(0, 2)\n .map((w) => w[0]?.toUpperCase() ?? '')\n .join('') || '?',\n );\n\n protected readonly statusText = computed(() => {\n const b = this.chat.bootstrap();\n if (!b) return '';\n return b.is_online ? b.online_status_text : b.offline_status_text;\n });\n\n protected readonly isOnlineStr = computed(\n () => String(this.chat.bootstrap()?.is_online ?? false),\n );\n\n protected readonly visibleMessages = computed(() => {\n const b = this.chat.bootstrap();\n const messages = this.chat.messages();\n if (b && !b.is_online && messages.length === 0) {\n return [\n {\n id: 'sys_offline',\n from: 'system' as const,\n content: b.offline_message,\n },\n ];\n }\n return messages;\n });\n\n ngAfterViewChecked(): void {\n // Scroll-to-bottom whenever message count changes. We compare against a\n // stamped length so we don't churn when only typing/status updates fire.\n const el = this.messagesRef?.nativeElement;\n if (!el) return;\n const len = this.visibleMessages().length + (this.chat.botTyping() ? 1 : 0);\n if (len !== this.lastScrollLen()) {\n el.scrollTop = el.scrollHeight;\n this.lastScrollLen.set(len);\n }\n }\n\n onClose(): void {\n this.chat.closePanel();\n }\n\n onSend(content: string): void {\n this.chat.sendMessage(content);\n }\n}\n","/**\n * `<bloonio-chat-thread>` — headless variant of the panel. Renders just\n * the message log + input, no header, no floating chrome. Used when the\n * tenant wants to embed the chat *inside* their own layout (e.g. inside\n * a support modal, a sidebar, a help center page).\n *\n * Theming and behaviour are otherwise identical — the same\n * `BloonioChatService` drives state, so a thread and a panel side-by-side\n * stay in sync.\n */\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n AfterViewChecked,\n ElementRef,\n ViewChild,\n signal,\n} from '@angular/core';\n\nimport { BloonioChatService } from '../bloonio-chat.service';\nimport { InputBarComponent } from './input-bar.component';\nimport { MessageListComponent } from './message-list.component';\nimport { QuickRepliesComponent } from './quick-replies.component';\n\n@Component({\n selector: 'bloonio-chat-thread',\n standalone: true,\n imports: [InputBarComponent, MessageListComponent, QuickRepliesComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"bch-root\" data-mode=\"inline\" [style]=\"themeStyle()\">\n <div class=\"bch-panel\">\n <div class=\"bch-messages\" #messages>\n <bloonio-chat-message-list\n [messages]=\"visibleMessages()\"\n [botTyping]=\"chat.botTyping()\"\n />\n </div>\n <bloonio-chat-quick-replies />\n <bloonio-chat-input-bar\n [disabled]=\"chat.connecting()\"\n (send)=\"chat.sendMessage($event)\"\n />\n </div>\n </div>\n `,\n})\nexport class BloonioChatThreadComponent implements AfterViewChecked {\n protected readonly chat = inject(BloonioChatService);\n\n @ViewChild('messages') private messagesRef?: ElementRef<HTMLDivElement>;\n private lastScrollLen = signal(-1);\n\n protected readonly themeStyle = computed(() => {\n const color = this.chat.bootstrap()?.branding_primary_color;\n return color ? `--bch-primary: ${color}` : '';\n });\n\n protected readonly visibleMessages = computed(() => {\n const b = this.chat.bootstrap();\n const messages = this.chat.messages();\n if (b && !b.is_online && messages.length === 0) {\n return [\n {\n id: 'sys_offline',\n from: 'system' as const,\n content: b.offline_message,\n },\n ];\n }\n return messages;\n });\n\n ngAfterViewChecked(): void {\n const el = this.messagesRef?.nativeElement;\n if (!el) return;\n const len = this.visibleMessages().length + (this.chat.botTyping() ? 1 : 0);\n if (len !== this.lastScrollLen()) {\n el.scrollTop = el.scrollHeight;\n this.lastScrollLen.set(len);\n }\n }\n\n /** Convenience: thread is meant to be always-on, so it opens the\n * service-level session as soon as it's instantiated.\n * (Floating panel waits for the launcher click.) */\n constructor() {\n void this.chat.openPanel();\n }\n}\n","/**\n * @bloonio/chat-angular — Angular library for the bloonio chat PaaS.\n *\n * Public surface:\n * - {@link provideBloonioChat} — environment-provider factory for app.config.ts\n * - {@link BloonioChatService} — signals-based reactive state\n * - Three standalone components:\n * <bloonio-chat-launcher> floating bubble (collapsed)\n * <bloonio-chat-panel> expandable card (the full chat UX)\n * <bloonio-chat-thread> headless variant for inline embedding\n *\n * Styles ship separately at `@bloonio/chat-angular/styles.css` — import once\n * in your global stylesheet (see README).\n */\n\nexport { provideBloonioChat, BLOONIO_CHAT_CONFIG, injectBloonioChatConfig } from './lib/bloonio-chat.token';\nexport type {\n BloonioChatConfig,\n VisitorTokenProvider,\n} from './lib/bloonio-chat.token';\n\nexport { BloonioChatService } from './lib/bloonio-chat.service';\nexport type { ChatMessage } from './lib/bloonio-chat.service';\n\nexport { BloonioChatLauncherComponent } from './lib/components/launcher.component';\nexport {\n BloonioChatPanelComponent,\n type ChatPanelMode,\n} from './lib/components/panel.component';\nexport { BloonioChatThreadComponent } from './lib/components/thread.component';\nexport { MessageListComponent } from './lib/components/message-list.component';\nexport { InputBarComponent } from './lib/components/input-bar.component';\nexport { QuickRepliesComponent } from './lib/components/quick-replies.component';\n\n// Re-export the bits of @bloonio/chat-client-core a consumer is likely to\n// touch (types, error classes). Keeps `import {…} from '@bloonio/chat-angular'`\n// the one entry point for most cases.\nexport type {\n WidgetBootstrapConfig,\n WidgetPosition,\n WidgetVisibility,\n ServerMsgFrame,\n MessageSender,\n} from '@bloonio/chat-client-core';\nexport {\n BloonioChatError,\n BloonioChatNetworkError,\n BloonioChatServerError,\n BloonioChatAuthError,\n} from '@bloonio/chat-client-core';\n\nexport const VERSION = '0.1.0';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bloonio/chat-angular — Angular library for the bloonio chat PaaS.
|
|
3
|
+
*
|
|
4
|
+
* Public surface:
|
|
5
|
+
* - {@link provideBloonioChat} — environment-provider factory for app.config.ts
|
|
6
|
+
* - {@link BloonioChatService} — signals-based reactive state
|
|
7
|
+
* - Three standalone components:
|
|
8
|
+
* <bloonio-chat-launcher> floating bubble (collapsed)
|
|
9
|
+
* <bloonio-chat-panel> expandable card (the full chat UX)
|
|
10
|
+
* <bloonio-chat-thread> headless variant for inline embedding
|
|
11
|
+
*
|
|
12
|
+
* Styles ship separately at `@bloonio/chat-angular/styles.css` — import once
|
|
13
|
+
* in your global stylesheet (see README).
|
|
14
|
+
*/
|
|
15
|
+
export { provideBloonioChat, BLOONIO_CHAT_CONFIG, injectBloonioChatConfig } from './lib/bloonio-chat.token';
|
|
16
|
+
export type { BloonioChatConfig, VisitorTokenProvider, } from './lib/bloonio-chat.token';
|
|
17
|
+
export { BloonioChatService } from './lib/bloonio-chat.service';
|
|
18
|
+
export type { ChatMessage } from './lib/bloonio-chat.service';
|
|
19
|
+
export { BloonioChatLauncherComponent } from './lib/components/launcher.component';
|
|
20
|
+
export { BloonioChatPanelComponent, type ChatPanelMode, } from './lib/components/panel.component';
|
|
21
|
+
export { BloonioChatThreadComponent } from './lib/components/thread.component';
|
|
22
|
+
export { MessageListComponent } from './lib/components/message-list.component';
|
|
23
|
+
export { InputBarComponent } from './lib/components/input-bar.component';
|
|
24
|
+
export { QuickRepliesComponent } from './lib/components/quick-replies.component';
|
|
25
|
+
export type { WidgetBootstrapConfig, WidgetPosition, WidgetVisibility, ServerMsgFrame, MessageSender, } from '@bloonio/chat-client-core';
|
|
26
|
+
export { BloonioChatError, BloonioChatNetworkError, BloonioChatServerError, BloonioChatAuthError, } from '@bloonio/chat-client-core';
|
|
27
|
+
export declare const VERSION = "0.1.0";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BloonioChatService — signals-based reactive state container.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the Preact widget's `Widget.tsx` state machine but uses Angular
|
|
5
|
+
* signals so templates auto-track the slots they read. Public surface:
|
|
6
|
+
*
|
|
7
|
+
* readonly bootstrap = signal<WidgetBootstrapConfig | null>(null);
|
|
8
|
+
* readonly session = signal<CreateVisitorSessionResponse | null>(null);
|
|
9
|
+
* readonly messages = signal<ChatMessage[]>([]);
|
|
10
|
+
* readonly botTyping = signal(false);
|
|
11
|
+
* readonly open = signal(false);
|
|
12
|
+
* readonly connecting= signal(false);
|
|
13
|
+
* readonly unreadCount = computed(...);
|
|
14
|
+
*
|
|
15
|
+
* async open(): Promise<void>
|
|
16
|
+
* close(): void
|
|
17
|
+
* async toggle(): Promise<void>
|
|
18
|
+
* sendMessage(text: string): void
|
|
19
|
+
*
|
|
20
|
+
* SSR-safe: every transport call (fetch, WebSocket) is gated behind a
|
|
21
|
+
* platform check via `afterNextRender()` so server pre-rendering doesn't
|
|
22
|
+
* try to open sockets.
|
|
23
|
+
*/
|
|
24
|
+
import { type Signal } from '@angular/core';
|
|
25
|
+
import { type CreateVisitorSessionResponse, type WidgetBootstrapConfig } from '@bloonio/chat-client-core';
|
|
26
|
+
import * as i0 from "@angular/core";
|
|
27
|
+
export interface ChatMessage {
|
|
28
|
+
id: string;
|
|
29
|
+
from: 'visitor' | 'bot' | 'agent' | 'system';
|
|
30
|
+
content: string;
|
|
31
|
+
pending?: boolean;
|
|
32
|
+
client_msg_id?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare class BloonioChatService {
|
|
35
|
+
private readonly config;
|
|
36
|
+
private readonly platformId;
|
|
37
|
+
private readonly destroyRef;
|
|
38
|
+
/** True when running in the browser (vs. server pre-render). */
|
|
39
|
+
private readonly isBrowser;
|
|
40
|
+
/** Bootstrap config — populated by the first `loadBootstrap()` call. */
|
|
41
|
+
readonly bootstrap: import("@angular/core").WritableSignal<WidgetBootstrapConfig>;
|
|
42
|
+
/** Visitor session (id + JWT + expires_at) — set lazily on first open. */
|
|
43
|
+
readonly session: import("@angular/core").WritableSignal<CreateVisitorSessionResponse>;
|
|
44
|
+
/** Message log, oldest → newest. */
|
|
45
|
+
readonly messages: import("@angular/core").WritableSignal<ChatMessage[]>;
|
|
46
|
+
/** True between bot's typing(start) and typing(stop) frames. */
|
|
47
|
+
readonly botTyping: import("@angular/core").WritableSignal<boolean>;
|
|
48
|
+
/** Panel visibility — drives Launcher / Panel rendering. */
|
|
49
|
+
readonly open: import("@angular/core").WritableSignal<boolean>;
|
|
50
|
+
/** True while `ensureSession()` is in flight (initial WS handshake). */
|
|
51
|
+
readonly connecting: import("@angular/core").WritableSignal<boolean>;
|
|
52
|
+
/** Set when the WS handshake fails permanently (e.g. tenant suspended). */
|
|
53
|
+
readonly fatalError: import("@angular/core").WritableSignal<string>;
|
|
54
|
+
/** Number of bot/agent messages received while the panel was closed.
|
|
55
|
+
* Resets to 0 the moment the panel opens. */
|
|
56
|
+
private readonly _seenCount;
|
|
57
|
+
readonly unreadCount: Signal<number>;
|
|
58
|
+
private client;
|
|
59
|
+
private ws;
|
|
60
|
+
private bootstrapPromise;
|
|
61
|
+
private sessionPromise;
|
|
62
|
+
constructor();
|
|
63
|
+
/** Toggle panel visibility. First open also opens the WS session. */
|
|
64
|
+
toggle(): Promise<void>;
|
|
65
|
+
/** Force the panel open. */
|
|
66
|
+
openPanel(): Promise<void>;
|
|
67
|
+
/** Force the panel closed. Keeps the WS open so reopening is instant. */
|
|
68
|
+
closePanel(): void;
|
|
69
|
+
/** Send a visitor message. No-op if the WS isn't connected. */
|
|
70
|
+
sendMessage(content: string): void;
|
|
71
|
+
private loadBootstrap;
|
|
72
|
+
private ensureSession;
|
|
73
|
+
private openWebSocket;
|
|
74
|
+
private tryIdentify;
|
|
75
|
+
private getClient;
|
|
76
|
+
private resolvedOrigin;
|
|
77
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BloonioChatService, never>;
|
|
78
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<BloonioChatService>;
|
|
79
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-injection plumbing for the Angular chat SDK.
|
|
3
|
+
*
|
|
4
|
+
* Consumers wire the SDK into their app via the standard Angular pattern
|
|
5
|
+
* documented in docs/12 §7.3:
|
|
6
|
+
*
|
|
7
|
+
* // app.config.ts
|
|
8
|
+
* export const appConfig: ApplicationConfig = {
|
|
9
|
+
* providers: [
|
|
10
|
+
* provideBloonioChat({
|
|
11
|
+
* tenantId: env.CHAT_TENANT_ID,
|
|
12
|
+
* publicKey: env.CHAT_PUBLIC_KEY,
|
|
13
|
+
* baseUrl: 'https://chat-relay.bloonio.com',
|
|
14
|
+
* visitorTokenProvider: () => inject(HttpClient).get<{token: string}>(
|
|
15
|
+
* '/api/chat/visitor-token'
|
|
16
|
+
* ).pipe(map(r => r.token)),
|
|
17
|
+
* locale: 'fr',
|
|
18
|
+
* }),
|
|
19
|
+
* ],
|
|
20
|
+
* };
|
|
21
|
+
*/
|
|
22
|
+
import { InjectionToken, type EnvironmentProviders } from '@angular/core';
|
|
23
|
+
import type { Observable } from 'rxjs';
|
|
24
|
+
import type { Attachment } from '@bloonio/chat-client-core';
|
|
25
|
+
/** Caller-supplied resolver for the tenant-signed visitor token.
|
|
26
|
+
*
|
|
27
|
+
* Two acceptable shapes:
|
|
28
|
+
* - Returns nothing (or `null`) → SDK falls back to anonymous mode.
|
|
29
|
+
* A session is minted via `/create/visitor-session` and the visitor
|
|
30
|
+
* stays unidentified until you supply one.
|
|
31
|
+
* - Returns a string / Observable<string> → SDK calls `/identify/visitor`
|
|
32
|
+
* with this signed token to bind the anonymous session to a tenant user.
|
|
33
|
+
*/
|
|
34
|
+
export type VisitorTokenProvider = (() => string | null | Promise<string | null> | Observable<string | null>) | undefined;
|
|
35
|
+
export interface BloonioChatConfig {
|
|
36
|
+
/** Tenant UUID v7 (the canonical handle issued by chat_relay). */
|
|
37
|
+
tenantId: string;
|
|
38
|
+
/** `pk_…` widget key bound to the tenant's `allowed_origins`. */
|
|
39
|
+
publicKey: string;
|
|
40
|
+
/** Base URL of the chat relay (https://chat-relay.bloonio.com or local). */
|
|
41
|
+
baseUrl: string;
|
|
42
|
+
/** Visitor-identification resolver. See {@link VisitorTokenProvider}. */
|
|
43
|
+
visitorTokenProvider?: VisitorTokenProvider;
|
|
44
|
+
/** Default locale for new conversations. */
|
|
45
|
+
locale?: string;
|
|
46
|
+
/** Free-form metadata attached to every visitor session. */
|
|
47
|
+
metadata?: Record<string, unknown>;
|
|
48
|
+
/** Optional override of `window.location.origin` (tests / SSR). */
|
|
49
|
+
origin?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Pre-fetched attachments to attach to the first outbound message.
|
|
52
|
+
* Reserved for phase 11; kept on the interface for forward compat.
|
|
53
|
+
*/
|
|
54
|
+
attachments?: Attachment[];
|
|
55
|
+
}
|
|
56
|
+
export declare const BLOONIO_CHAT_CONFIG: InjectionToken<BloonioChatConfig>;
|
|
57
|
+
/** Standalone-provider factory.
|
|
58
|
+
*
|
|
59
|
+
* Returns ``EnvironmentProviders`` so consumers can spread it into
|
|
60
|
+
* ``app.config.ts``'s providers array. The service itself is
|
|
61
|
+
* ``providedIn: 'root'`` so we don't need an explicit provider entry — we
|
|
62
|
+
* only need the config token to be registered.
|
|
63
|
+
*/
|
|
64
|
+
export declare function provideBloonioChat(config: BloonioChatConfig): EnvironmentProviders;
|
|
65
|
+
/** Internal accessor used by the components to fail loud when the
|
|
66
|
+
* consumer forgot ``provideBloonioChat()``. */
|
|
67
|
+
export declare function injectBloonioChatConfig(): BloonioChatConfig;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visitor input bar — multi-line textarea + send button. Enter sends,
|
|
3
|
+
* Shift+Enter inserts a newline. Emits `send` with the trimmed content
|
|
4
|
+
* once it's non-empty.
|
|
5
|
+
*/
|
|
6
|
+
import { EventEmitter } from '@angular/core';
|
|
7
|
+
import * as i0 from "@angular/core";
|
|
8
|
+
export declare class InputBarComponent {
|
|
9
|
+
disabled: boolean;
|
|
10
|
+
send: EventEmitter<string>;
|
|
11
|
+
protected readonly value: import("@angular/core").WritableSignal<string>;
|
|
12
|
+
protected canSend(): boolean;
|
|
13
|
+
onInput(e: Event): void;
|
|
14
|
+
onKey(e: KeyboardEvent): void;
|
|
15
|
+
submit(): void;
|
|
16
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<InputBarComponent, never>;
|
|
17
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<InputBarComponent, "bloonio-chat-input-bar", never, { "disabled": { "alias": "disabled"; "required": false; }; }, { "send": "send"; }, never, never, true, never>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BloonioChatService } from '../bloonio-chat.service';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class BloonioChatLauncherComponent {
|
|
4
|
+
protected readonly chat: BloonioChatService;
|
|
5
|
+
protected readonly position: import("@angular/core").Signal<import("@bloonio/chat-client-core").WidgetPosition>;
|
|
6
|
+
/** Tint the bubble with the tenant's brand colour (falls back to the
|
|
7
|
+
* stylesheet default until bootstrap config loads). */
|
|
8
|
+
protected readonly themeStyle: import("@angular/core").Signal<string>;
|
|
9
|
+
protected readonly label: import("@angular/core").Signal<string>;
|
|
10
|
+
protected readonly ariaLabel: import("@angular/core").Signal<string>;
|
|
11
|
+
onToggle(): void;
|
|
12
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BloonioChatLauncherComponent, never>;
|
|
13
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<BloonioChatLauncherComponent, "bloonio-chat-launcher", never, {}, {}, never, never, true, never>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ChatMessage } from '../bloonio-chat.service';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class MessageListComponent {
|
|
4
|
+
messages: ChatMessage[];
|
|
5
|
+
botTyping: boolean;
|
|
6
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MessageListComponent, never>;
|
|
7
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MessageListComponent, "bloonio-chat-message-list", never, { "messages": { "alias": "messages"; "required": true; }; "botTyping": { "alias": "botTyping"; "required": false; }; }, {}, never, never, true, never>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Floating or docked chat panel. Renders the header, message list, input,
|
|
3
|
+
* and footer. Sits inside `<bloonio-chat-launcher>` for the floating
|
|
4
|
+
* variant, or stand-alone for `mode="docked"`/`mode="inline"`.
|
|
5
|
+
*/
|
|
6
|
+
import { type AfterViewChecked } from '@angular/core';
|
|
7
|
+
import { BloonioChatService } from '../bloonio-chat.service';
|
|
8
|
+
import * as i0 from "@angular/core";
|
|
9
|
+
export type ChatPanelMode = 'floating' | 'docked' | 'inline';
|
|
10
|
+
export declare class BloonioChatPanelComponent implements AfterViewChecked {
|
|
11
|
+
/** floating = paired with launcher (default). docked/inline = always-on
|
|
12
|
+
* inside the page flow (use for SSR landing pages or sidebar layouts). */
|
|
13
|
+
mode: ChatPanelMode;
|
|
14
|
+
protected readonly chat: BloonioChatService;
|
|
15
|
+
private messagesRef?;
|
|
16
|
+
private lastScrollLen;
|
|
17
|
+
protected readonly position: import("@angular/core").Signal<import("@bloonio/chat-client-core").WidgetPosition>;
|
|
18
|
+
protected readonly visible: import("@angular/core").Signal<boolean>;
|
|
19
|
+
protected readonly themeStyle: import("@angular/core").Signal<string>;
|
|
20
|
+
protected readonly displayName: import("@angular/core").Signal<string>;
|
|
21
|
+
protected readonly logoUrl: import("@angular/core").Signal<string>;
|
|
22
|
+
protected readonly initials: import("@angular/core").Signal<string>;
|
|
23
|
+
protected readonly statusText: import("@angular/core").Signal<string>;
|
|
24
|
+
protected readonly isOnlineStr: import("@angular/core").Signal<string>;
|
|
25
|
+
protected readonly visibleMessages: import("@angular/core").Signal<import("../bloonio-chat.service").ChatMessage[]>;
|
|
26
|
+
ngAfterViewChecked(): void;
|
|
27
|
+
onClose(): void;
|
|
28
|
+
onSend(content: string): void;
|
|
29
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BloonioChatPanelComponent, never>;
|
|
30
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<BloonioChatPanelComponent, "bloonio-chat-panel", never, { "mode": { "alias": "mode"; "required": false; }; }, {}, never, never, true, never>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BloonioChatService } from '../bloonio-chat.service';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class QuickRepliesComponent {
|
|
4
|
+
protected readonly chat: BloonioChatService;
|
|
5
|
+
/** Show the configured chips only until the visitor's first message. */
|
|
6
|
+
protected readonly replies: import("@angular/core").Signal<string[]>;
|
|
7
|
+
protected pick(text: string): void;
|
|
8
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<QuickRepliesComponent, never>;
|
|
9
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<QuickRepliesComponent, "bloonio-chat-quick-replies", never, {}, {}, never, never, true, never>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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 { AfterViewChecked } from '@angular/core';
|
|
12
|
+
import { BloonioChatService } from '../bloonio-chat.service';
|
|
13
|
+
import * as i0 from "@angular/core";
|
|
14
|
+
export declare class BloonioChatThreadComponent implements AfterViewChecked {
|
|
15
|
+
protected readonly chat: BloonioChatService;
|
|
16
|
+
private messagesRef?;
|
|
17
|
+
private lastScrollLen;
|
|
18
|
+
protected readonly themeStyle: import("@angular/core").Signal<string>;
|
|
19
|
+
protected readonly visibleMessages: import("@angular/core").Signal<import("../bloonio-chat.service").ChatMessage[]>;
|
|
20
|
+
ngAfterViewChecked(): void;
|
|
21
|
+
/** Convenience: thread is meant to be always-on, so it opens the
|
|
22
|
+
* service-level session as soon as it's instantiated.
|
|
23
|
+
* (Floating panel waits for the launcher click.) */
|
|
24
|
+
constructor();
|
|
25
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BloonioChatThreadComponent, never>;
|
|
26
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<BloonioChatThreadComponent, "bloonio-chat-thread", never, {}, {}, never, never, true, never>;
|
|
27
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bloonio/chat-angular",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Angular library for the bloonio chat PaaS — standalone components, signals-based service, SSR-safe. Built on @bloonio/chat-client-core.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
"./styles.css": "./src/lib/styles/chat.css",
|
|
8
|
+
"./package.json": {
|
|
9
|
+
"default": "./package.json"
|
|
10
|
+
},
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./index.d.ts",
|
|
13
|
+
"esm2022": "./esm2022/bloonio-chat-angular.mjs",
|
|
14
|
+
"esm": "./esm2022/bloonio-chat-angular.mjs",
|
|
15
|
+
"default": "./fesm2022/bloonio-chat-angular.mjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"keywords": [
|
|
20
|
+
"bloonio",
|
|
21
|
+
"chat",
|
|
22
|
+
"angular",
|
|
23
|
+
"widget",
|
|
24
|
+
"sdk"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@angular/common": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
29
|
+
"@angular/core": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
30
|
+
"@bloonio/chat-client-core": "*",
|
|
31
|
+
"rxjs": "^7.0.0"
|
|
32
|
+
},
|
|
33
|
+
"module": "fesm2022/bloonio-chat-angular.mjs",
|
|
34
|
+
"typings": "index.d.ts",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"tslib": "^2.3.0"
|
|
37
|
+
}
|
|
38
|
+
}
|