@trixwell/ngx-parl 4.2.0 → 5.0.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 +90 -12
- package/fesm2022/trixwell-ngx-parl.mjs +141 -13
- package/fesm2022/trixwell-ngx-parl.mjs.map +1 -1
- package/index.d.ts +48 -3
- package/package.json +4 -2
- package/src/assets/i18n/en.json +2 -0
- package/src/assets/i18n/uk.json +2 -0
- package/src/assets/icons/avatar_manager.svg +9 -4
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, inject, model, computed, effect, ViewChild, Component, Injectable, Pipe, signal, Optional, isDevMode } from '@angular/core';
|
|
2
|
+
import { input, inject, model, computed, effect, ViewChild, Component, Injectable, Pipe, signal, ViewEncapsulation, Optional, isDevMode } from '@angular/core';
|
|
3
3
|
import { NgClass, NgOptimizedImage, DatePipe } from '@angular/common';
|
|
4
|
+
import { toSignal } from '@angular/core/rxjs-interop';
|
|
4
5
|
import { FormsModule } from '@angular/forms';
|
|
5
6
|
import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
|
|
6
7
|
import * as i2 from '@ngneat/transloco';
|
|
7
|
-
import { TranslocoPipe, TranslocoModule, provideTransloco } from '@ngneat/transloco';
|
|
8
|
+
import { TranslocoPipe, TranslocoService, TranslocoModule, provideTransloco } from '@ngneat/transloco';
|
|
8
9
|
import { FocusTrapFactory } from '@angular/cdk/a11y';
|
|
10
|
+
import { IonButton, IonAlert } from '@ionic/angular/standalone';
|
|
9
11
|
import * as i1 from '@angular/common/http';
|
|
10
12
|
import { InfiniteScrollDirective } from 'ngx-infinite-scroll';
|
|
11
13
|
import * as i3 from '@angular/material/dialog';
|
|
@@ -25,6 +27,7 @@ class ChatMessage {
|
|
|
25
27
|
avatar;
|
|
26
28
|
file_path;
|
|
27
29
|
file_list;
|
|
30
|
+
actions;
|
|
28
31
|
checked;
|
|
29
32
|
edit = false;
|
|
30
33
|
pending = false;
|
|
@@ -42,6 +45,7 @@ class ChatMessage {
|
|
|
42
45
|
this.pending = data.pending ?? false;
|
|
43
46
|
this.file_path = data.file_path ?? null;
|
|
44
47
|
this.file_list = data.file_list ?? null;
|
|
48
|
+
this.actions = Array.isArray(data.actions) ? data.actions : [];
|
|
45
49
|
}
|
|
46
50
|
get dateSimple() {
|
|
47
51
|
const d = new Date(this.cr_time.replace(' ', 'T'));
|
|
@@ -279,6 +283,9 @@ class ChatMessageComponent {
|
|
|
279
283
|
closePreviewHandler = () => this.closePreview();
|
|
280
284
|
requestEdit = model(null, ...(ngDevMode ? [{ debugName: "requestEdit" }] : []));
|
|
281
285
|
requestDelete = model(null, ...(ngDevMode ? [{ debugName: "requestDelete" }] : []));
|
|
286
|
+
mobileMode = input(false, ...(ngDevMode ? [{ debugName: "mobileMode" }] : []));
|
|
287
|
+
quickActions = input([], ...(ngDevMode ? [{ debugName: "quickActions" }] : []));
|
|
288
|
+
quickActionClick = model(null, ...(ngDevMode ? [{ debugName: "quickActionClick" }] : []));
|
|
282
289
|
constructor(utils) {
|
|
283
290
|
this.utils = utils;
|
|
284
291
|
}
|
|
@@ -321,7 +328,27 @@ class ChatMessageComponent {
|
|
|
321
328
|
: 'assets/ngx-parl/icons/avatar_manager.svg';
|
|
322
329
|
return message.avatar || fallback;
|
|
323
330
|
}, ...(ngDevMode ? [{ debugName: "avatarSrc" }] : []));
|
|
331
|
+
showAvatar = computed(() => {
|
|
332
|
+
const isMobile = this.mobileMode();
|
|
333
|
+
const isOutgoing = this.currentMessage().type === this.messageType.Outgoing;
|
|
334
|
+
return !(isMobile && isOutgoing);
|
|
335
|
+
}, ...(ngDevMode ? [{ debugName: "showAvatar" }] : []));
|
|
336
|
+
showQuickActions = computed(() => {
|
|
337
|
+
const isOutgoing = this.currentMessage().type === this.messageType.Outgoing;
|
|
338
|
+
return isOutgoing && this.quickActions().length > 0;
|
|
339
|
+
}, ...(ngDevMode ? [{ debugName: "showQuickActions" }] : []));
|
|
340
|
+
showMessageBubble = computed(() => !this.showQuickActions(), ...(ngDevMode ? [{ debugName: "showMessageBubble" }] : []));
|
|
341
|
+
showMessageBody = computed(() => this.showMessageBubble() || this.attachments().length > 0, ...(ngDevMode ? [{ debugName: "showMessageBody" }] : []));
|
|
342
|
+
canOpenContextMenu = computed(() => {
|
|
343
|
+
const message = this.currentMessage();
|
|
344
|
+
const isOutgoing = message.type === this.messageType.Outgoing;
|
|
345
|
+
const isSent = message.pending !== true;
|
|
346
|
+
return isOutgoing && isSent;
|
|
347
|
+
}, ...(ngDevMode ? [{ debugName: "canOpenContextMenu" }] : []));
|
|
324
348
|
openContextMenu(event, trigger, triggerElement) {
|
|
349
|
+
if (!this.canOpenContextMenu()) {
|
|
350
|
+
return this;
|
|
351
|
+
}
|
|
325
352
|
event.preventDefault();
|
|
326
353
|
event.stopPropagation();
|
|
327
354
|
if (event instanceof MouseEvent) {
|
|
@@ -360,12 +387,22 @@ class ChatMessageComponent {
|
|
|
360
387
|
queueMicrotask(() => this.requestDelete.set(null));
|
|
361
388
|
return this;
|
|
362
389
|
}
|
|
390
|
+
onQuickAction(action) {
|
|
391
|
+
const messageId = this.currentMessage().id;
|
|
392
|
+
const value = (action.value ?? '').trim();
|
|
393
|
+
if (!value) {
|
|
394
|
+
return this;
|
|
395
|
+
}
|
|
396
|
+
this.quickActionClick.set({ actionId: action.id, messageId, value });
|
|
397
|
+
setTimeout(() => this.quickActionClick.set(null), 0);
|
|
398
|
+
return this;
|
|
399
|
+
}
|
|
363
400
|
canDelete(message) {
|
|
364
401
|
return message.type === this.messageType.Outgoing;
|
|
365
402
|
}
|
|
366
403
|
messageType = MessageType;
|
|
367
404
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ChatMessageComponent, deps: [{ token: UtilsService }], target: i0.ɵɵFactoryTarget.Component });
|
|
368
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: ChatMessageComponent, isStandalone: true, selector: "lib-chat-message", inputs: { currentMessage: { classPropertyName: "currentMessage", publicName: "currentMessage", isSignal: true, isRequired: true, transformFunction: null }, edit: { classPropertyName: "edit", publicName: "edit", isSignal: true, isRequired: false, transformFunction: null }, previewList: { classPropertyName: "previewList", publicName: "previewList", isSignal: true, isRequired: false, transformFunction: null }, previewIndex: { classPropertyName: "previewIndex", publicName: "previewIndex", isSignal: true, isRequired: false, transformFunction: null }, previewOpener: { classPropertyName: "previewOpener", publicName: "previewOpener", isSignal: true, isRequired: false, transformFunction: null }, requestEdit: { classPropertyName: "requestEdit", publicName: "requestEdit", isSignal: true, isRequired: false, transformFunction: null }, requestDelete: { classPropertyName: "requestDelete", publicName: "requestDelete", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { edit: "editChange", previewList: "previewListChange", previewIndex: "previewIndexChange", previewOpener: "previewOpenerChange", requestEdit: "requestEditChange", requestDelete: "requestDeleteChange" }, ngImport: i0, template: "<div class=\"message\"\n [ngClass]=\"{\n 'message--outgoing': currentMessage().type === messageType.Outgoing,\n 'message--incoming': currentMessage().type === messageType.Incoming\n }\">\n <div class=\"message__avatar\">\n <img [ngSrc]=\"avatarSrc()\" width=\"36\" height=\"36\" alt=\"avatar\"/>\n </div>\n\n <div class=\"message__body\"\n [class.message__body--attachments-1]=\"attachments().length === 1\"\n [class.message__body--attachments-2]=\"attachments().length === 2\"\n [class.message__body--attachments-3]=\"attachments().length >= 3\"\n (contextmenu)=\"openContextMenu($event, menuTrigger, menuTriggerEl)\"\n (keydown.shift.F10)=\"$event.preventDefault(); menuTrigger.openMenu()\">\n <button type=\"button\"\n class=\"message__menu-trigger\"\n aria-hidden=\"true\"\n tabindex=\"-1\"\n #menuTrigger=\"matMenuTrigger\"\n #menuTriggerEl\n [matMenuTriggerFor]=\"messageMenu\"\n >\n </button>\n\n @if (attachments().length) {\n <div class=\"message__attachments\">\n @for (file of attachments(); track file; let i = $index) {\n <button type=\"button\"\n class=\"message__image-button\"\n (click)=\"openPreview(i, $event)\"\n [attr.aria-label]=\"'chat.photo_preview' | transloco\">\n <img [src]=\"file\"\n alt=\"attachment\"\n class=\"message__image\"\n loading=\"lazy\"/>\n </button>\n }\n </div>\n }\n\n <div class=\"message__bubble\" tabindex=\"0\">\n <div class=\"message__text\">{{ currentMessage().content }}</div>\n\n <div class=\"message__meta\">\n <time class=\"message__time\">\n {{ currentMessage().cr_time | date:'HH:mm' }}\n </time>\n @if (currentMessage().type === messageType.Outgoing) {\n @if (currentMessage().pending) {\n <span class=\"message__loading\" aria-label=\"Sending\"></span>\n } @else if (currentMessage().checked) {\n <img ngSrc=\"assets/ngx-parl/icons/checked-message.svg\"\n class=\"message__icon\"\n width=\"18\" height=\"18\" alt=\"hide\"/>\n } @else {\n <img ngSrc=\"assets/ngx-parl/icons/no-check.svg\"\n class=\"message__icon\"\n width=\"18\" height=\"18\" alt=\"hide\"/>\n }\n }\n </div>\n </div>\n </div>\n</div>\n<div class=\"message__user\">\n @if (currentMessage().type === messageType.Outgoing) {\n <span class=\"message__user-name\">{{ currentMessage().user }}</span>\n }\n</div>\n\n@if (previewList().length) {\n <lib-preview-file\n [srcList]=\"previewList()\"\n [startIndex]=\"previewIndex()\"\n [openerElement]=\"previewOpener()\"\n [closeHandler]=\"closePreviewHandler\">\n </lib-preview-file>\n}\n\n<mat-menu #messageMenu=\"matMenu\" yPosition=\"below\" xPosition=\"before\" class=\"message__menu\">\n @if (currentMessage().type === messageType.Outgoing) {\n <button mat-menu-item (click)=\"editMessage(currentMessage())\">\n <img ngSrc=\"assets/ngx-parl/icons/icon-edit.svg\"\n class=\"message__icon--menu\"\n width=\"20\" height=\"20\" alt=\"hide\"/>\n <span>{{ 'chat.edit' | transloco }}</span>\n </button>\n }\n @if (canDelete(currentMessage())) {\n <button mat-menu-item (click)=\"deleteMessage(currentMessage())\">\n <img ngSrc=\"assets/ngx-parl/icons/trash.svg\"\n class=\"message__icon--menu\"\n width=\"20\" height=\"20\" alt=\"hide\"/>\n <span>{{ 'chat.remove' | transloco }}</span>\n </button>\n }\n</mat-menu>\n", styles: [".flow-theme-primary ::ng-deep .modal-chat__header{background-color:#5a72d7;color:#fff}.flow-theme-primary ::ng-deep .message--incoming .message__body{background:#e9ecef;color:#343a40}.flow-theme-primary ::ng-deep .message--outgoing .message__body{background:#4656ca;color:#fff}:root{--shadow-sm: 0px 1px 2px 0px rgba(0, 0, 0, .05);--shadow-md: 0px 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0px 8px 24px rgba(0, 0, 0, .12);--shadow-soft: 0px 0px 6px 0px rgba(46, 46, 46, .12) }.flow-theme-secondary ::ng-deep .modal-chat__header{background-color:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--incoming .message__body{background:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--outgoing .message__body{background:#efefef;color:#464646}.message{display:flex;gap:8px;align-items:flex-end;max-width:80%;animation:pop .12s ease-out}.message__avatar img{display:block;border-radius:1000px}.message__body{padding:8px 12px;min-width:0;font:400 16px/20px inter,sans-serif;border-radius:16px;position:relative}.message__bubble{display:grid;grid-template-columns:1fr auto;column-gap:8px;align-items:end;max-width:100%;word-break:break-word;white-space:pre-wrap}.message__text{min-width:0}.message__meta{display:inline-flex;align-items:center;gap:4px;-webkit-user-select:none;user-select:none;line-height:1;margin:0}.message__time{font:400 12px/16px inter,sans-serif}.message__attachments{display:grid;gap:8px;justify-content:start;width:100%;margin-bottom:8px}.message__attachments:has(:only-child){grid-template-columns:repeat(1,minmax(0,140px))}.message__attachments:has(:nth-child(2):last-child){grid-template-columns:repeat(2,minmax(0,145px))}.message__attachments:has(:nth-child(3)){grid-template-columns:repeat(3,minmax(0,150px))}.message__body--attachments-1{max-width:164px}.message__body--attachments-2{max-width:312px}.message__body--attachments-3{max-width:460px}.message__body--attachments-1 .message__bubble,.message__body--attachments-2 .message__bubble,.message__body--attachments-3 .message__bubble{grid-template-columns:1fr;row-gap:4px}.message__body--attachments-1 .message__meta,.message__body--attachments-2 .message__meta,.message__body--attachments-3 .message__meta{justify-self:end}.message__image-button{display:block;border:none;padding:0;background:transparent;border-radius:12px;overflow:hidden;cursor:pointer}.message__image-button:focus-visible{outline:2px solid #5A72D7;outline-offset:4px}.message__menu-trigger{position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;pointer-events:none}.message__image{display:block;width:100%;height:140px;object-fit:cover;border-radius:12px;aspect-ratio:1/1}.message__bubble:after{content:\"\";display:block;clear:both}.message__time{font:400 12px/16px inter,sans-serif;min-width:30px}.message__icon{width:14px;height:14px;vertical-align:middle}.message__icon--menu{width:20px;height:20px}.message__loading{display:inline-block;width:10px;height:10px;border:2px solid #E9ECEF;border-top-color:#5a72d7;border-radius:50%;animation:message-loading-spin .8s linear infinite}.message--incoming{margin-right:auto}.message--incoming .message__body{border-bottom-right-radius:16px}.message--incoming .message__bubble{border-top-left-radius:4px}.message--incoming .message__time{color:#adb5bd}.message--outgoing{margin-left:auto;flex-direction:row-reverse}.message--outgoing .message__body{border-bottom-left-radius:16px}.message--outgoing .message__bubble{border-top-right-radius:4px}.message--outgoing .message__time{color:#e9ecef}.message--outgoing .message__menu-trigger{right:auto}.message__user{display:flex;justify-content:flex-end;max-width:80%;margin-left:auto;margin-top:4px;padding-right:46px}.message__user-name{font:400 12px/16px inter,sans-serif;color:#ced4da}@keyframes pop{0%{transform:translateY(2px);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes message-loading-spin{to{transform:rotate(360deg)}}::ng-deep .mat-mdc-menu-content{background:#fff;width:160px;border-radius:8px;gap:4px;border:1px solid #E1E7F8;padding:8px 4px;box-shadow:0 2px 4px #0000001a;overflow:hidden;font:400 14px/18px inter,sans-serif}::ng-deep .mat-mdc-menu-item-text{font:400 14px/18px inter,sans-serif!important;font-weight:500!important;color:#343a40!important;display:flex;justify-content:flex-start;align-items:center;gap:4px}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: PreviewFile, selector: "lib-preview-file", inputs: ["srcList", "startIndex", "title", "openerElement", "closeHandler", "activeIndex", "viewReady", "userNavigated", "previousListLength"], outputs: ["activeIndexChange", "viewReadyChange", "userNavigatedChange", "previousListLengthChange"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
|
|
405
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: ChatMessageComponent, isStandalone: true, selector: "lib-chat-message", inputs: { currentMessage: { classPropertyName: "currentMessage", publicName: "currentMessage", isSignal: true, isRequired: true, transformFunction: null }, edit: { classPropertyName: "edit", publicName: "edit", isSignal: true, isRequired: false, transformFunction: null }, previewList: { classPropertyName: "previewList", publicName: "previewList", isSignal: true, isRequired: false, transformFunction: null }, previewIndex: { classPropertyName: "previewIndex", publicName: "previewIndex", isSignal: true, isRequired: false, transformFunction: null }, previewOpener: { classPropertyName: "previewOpener", publicName: "previewOpener", isSignal: true, isRequired: false, transformFunction: null }, requestEdit: { classPropertyName: "requestEdit", publicName: "requestEdit", isSignal: true, isRequired: false, transformFunction: null }, requestDelete: { classPropertyName: "requestDelete", publicName: "requestDelete", isSignal: true, isRequired: false, transformFunction: null }, mobileMode: { classPropertyName: "mobileMode", publicName: "mobileMode", isSignal: true, isRequired: false, transformFunction: null }, quickActions: { classPropertyName: "quickActions", publicName: "quickActions", isSignal: true, isRequired: false, transformFunction: null }, quickActionClick: { classPropertyName: "quickActionClick", publicName: "quickActionClick", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { edit: "editChange", previewList: "previewListChange", previewIndex: "previewIndexChange", previewOpener: "previewOpenerChange", requestEdit: "requestEditChange", requestDelete: "requestDeleteChange", quickActionClick: "quickActionClickChange" }, ngImport: i0, template: "<div class=\"message\"\n [ngClass]=\"{\n 'message--outgoing': currentMessage().type === messageType.Outgoing,\n 'message--incoming': currentMessage().type === messageType.Incoming,\n 'message--mobile': mobileMode()\n }\">\n @if (showAvatar()) {\n <div class=\"message__avatar\">\n <img [ngSrc]=\"avatarSrc()\" width=\"36\" height=\"36\" alt=\"avatar\"/>\n </div>\n }\n\n @if (showMessageBody()) {\n <div class=\"message__body\"\n (contextmenu)=\"openContextMenu($event, menuTrigger, menuTriggerEl)\"\n (keydown.shift.F10)=\"openContextMenu($event, menuTrigger, menuTriggerEl)\">\n <button type=\"button\"\n class=\"message__menu-trigger\"\n aria-hidden=\"true\"\n tabindex=\"-1\"\n #menuTrigger=\"matMenuTrigger\"\n #menuTriggerEl\n [matMenuTriggerFor]=\"messageMenu\">\n </button>\n\n @if (attachments().length) {\n <div class=\"message__attachments\">\n @for (file of attachments(); track file; let i = $index) {\n <button type=\"button\"\n class=\"message__image-button\"\n (click)=\"openPreview(i, $event)\"\n [attr.aria-label]=\"'chat.photo_preview' | transloco\">\n <img [src]=\"file\"\n alt=\"attachment\"\n class=\"message__image\"\n loading=\"lazy\"/>\n </button>\n }\n </div>\n }\n\n @if (showMessageBubble()) {\n <div class=\"message__bubble\" tabindex=\"0\">\n <div class=\"message__text\">{{ currentMessage().content }}</div>\n\n <div class=\"message__meta\">\n <time class=\"message__time\">\n {{ currentMessage().cr_time | date:'HH:mm' }}\n </time>\n @if (currentMessage().type === messageType.Outgoing) {\n @if (currentMessage().pending) {\n <span class=\"message__loading\" aria-label=\"Sending\"></span>\n } @else if (currentMessage().checked) {\n <img ngSrc=\"assets/ngx-parl/icons/checked-message.svg\"\n class=\"message__icon\"\n width=\"18\" height=\"18\" alt=\"hide\"/>\n } @else {\n <img ngSrc=\"assets/ngx-parl/icons/no-check.svg\"\n class=\"message__icon\"\n width=\"18\" height=\"18\" alt=\"hide\"/>\n }\n }\n </div>\n </div>\n }\n\n </div>\n }\n\n @if (showQuickActions()) {\n <div class=\"message__quick-actions-wrap\" role=\"group\" aria-label=\"Quick actions\">\n <div class=\"message__quick-actions\">\n @for (action of quickActions(); track action.id) {\n <ion-button\n class=\"message__quick-action-button\"\n fill=\"outline\"\n expand=\"block\"\n [disabled]=\"action.disabled === true\"\n (click)=\"onQuickAction(action)\">\n {{ action.title }}\n </ion-button>\n }\n </div>\n </div>\n }\n</div>\n@if (!showQuickActions()) {\n <div class=\"message__user\" [ngClass]=\"{'message__user--mobile': mobileMode()}\">\n @if (currentMessage().type === messageType.Outgoing) {\n <span class=\"message__user-name\">{{ currentMessage().user }}</span>\n }\n </div>\n}\n\n@if (previewList().length) {\n <lib-preview-file\n [srcList]=\"previewList()\"\n [startIndex]=\"previewIndex()\"\n [openerElement]=\"previewOpener()\"\n [closeHandler]=\"closePreviewHandler\">\n </lib-preview-file>\n}\n\n<mat-menu #messageMenu=\"matMenu\" yPosition=\"below\" xPosition=\"before\" class=\"message__menu\">\n @if (currentMessage().type === messageType.Outgoing) {\n <button mat-menu-item (click)=\"editMessage(currentMessage())\">\n <img ngSrc=\"assets/ngx-parl/icons/icon-edit.svg\"\n class=\"message__icon--menu\"\n width=\"20\" height=\"20\" alt=\"hide\"/>\n <span>{{ 'chat.edit' | transloco }}</span>\n </button>\n }\n @if (canDelete(currentMessage())) {\n <button mat-menu-item (click)=\"deleteMessage(currentMessage())\">\n <img ngSrc=\"assets/ngx-parl/icons/trash.svg\"\n class=\"message__icon--menu\"\n width=\"20\" height=\"20\" alt=\"hide\"/>\n <span>{{ 'chat.remove' | transloco }}</span>\n </button>\n }\n</mat-menu>\n", styles: [".flow-theme-primary ::ng-deep .modal-chat__header{background-color:#5a72d7;color:#fff}.flow-theme-primary ::ng-deep .message--incoming .message__body{background:#e9ecef;color:#343a40}.flow-theme-primary ::ng-deep .message--outgoing .message__body{background:#4656ca;color:#fff}:root{--shadow-sm: 0px 1px 2px 0px rgba(0, 0, 0, .05);--shadow-md: 0px 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0px 8px 24px rgba(0, 0, 0, .12);--shadow-soft: 0px 0px 6px 0px rgba(46, 46, 46, .12) }.flow-theme-secondary ::ng-deep .modal-chat__header{background-color:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--incoming .message__body{background:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--outgoing .message__body{background:#efefef;color:#464646}.message{display:flex;gap:8px;align-items:flex-end;max-width:80%;animation:pop .12s ease-out}.message__avatar img{display:block;border-radius:1000px}.message__body{padding:8px 12px;min-width:0;font:400 16px/20px inter,sans-serif;border-radius:16px;position:relative}.message__bubble{display:grid;grid-template-columns:1fr auto;column-gap:8px;align-items:end;max-width:100%;word-break:break-word;white-space:pre-wrap}.message__quick-actions-wrap{display:flex;margin-top:12px;width:100%;background:transparent}.message__quick-actions{display:grid;gap:8px;width:234px;max-width:100%;background:transparent}.message__quick-action-button{--border-radius: 16px;--border-width: 1px;--border-style: solid;--border-color: #2563EB;--color: #2563EB;--padding-top: tokens.$space-3;--padding-bottom: tokens.$space-3;--padding-start: tokens.$space-6;--padding-end: tokens.$space-6;height:48px;text-transform:none;font:500 14px/18px inter,sans-serif;margin:0}.message__text{min-width:0}.message__meta{display:inline-flex;align-items:center;gap:4px;-webkit-user-select:none;user-select:none;line-height:1;margin:0}.message__time{font:400 12px/16px inter,sans-serif}.message__attachments{display:grid;gap:8px;justify-content:start;width:100%;margin-bottom:8px}.message__attachments:has(:only-child){grid-template-columns:repeat(1,minmax(0,140px))}.message__attachments:has(:nth-child(2):last-child){grid-template-columns:repeat(2,minmax(0,145px))}.message__attachments:has(:nth-child(3)){grid-template-columns:repeat(3,minmax(0,150px))}.message__body--attachments-1{max-width:164px}.message__body--attachments-2{max-width:312px}.message__body--attachments-3{max-width:460px}.message__body--attachments-1 .message__bubble,.message__body--attachments-2 .message__bubble,.message__body--attachments-3 .message__bubble{grid-template-columns:1fr;row-gap:4px}.message__body--attachments-1 .message__meta,.message__body--attachments-2 .message__meta,.message__body--attachments-3 .message__meta{justify-self:end}.message__image-button{display:block;border:none;padding:0;background:transparent;border-radius:12px;overflow:hidden;cursor:pointer}.message__image-button:focus-visible{outline:2px solid #5A72D7;outline-offset:4px}.message__menu-trigger{position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;pointer-events:none}.message__image{display:block;width:100%;height:140px;object-fit:cover;border-radius:12px;aspect-ratio:1/1}.message__bubble:after{content:\"\";display:block;clear:both}.message__time{font:400 12px/16px inter,sans-serif;min-width:30px}.message__icon{width:14px;height:14px;vertical-align:middle}.message__icon--menu{width:20px;height:20px}.message__loading{display:inline-block;width:10px;height:10px;border:2px solid #E9ECEF;border-top-color:#5a72d7;border-radius:50%;animation:message-loading-spin .8s linear infinite}.message--incoming{margin-right:auto}.message--incoming .message__body{border-bottom-right-radius:16px}.message--incoming .message__bubble{border-top-left-radius:4px}.message--incoming .message__time{color:#adb5bd}.message--incoming .message__quick-actions-wrap{justify-content:flex-start}.message--outgoing{margin-left:auto;flex-direction:row-reverse}.message--outgoing .message__body{border-bottom-right-radius:0}.message--outgoing .message__bubble{border-top-right-radius:4px}.message--outgoing .message__time{color:#e9ecef}.message--outgoing .message__menu-trigger{right:auto}.message--outgoing .message__quick-actions-wrap{justify-content:flex-end}.message--mobile .message__user{padding-right:5px!important}.message--mobile.message--outgoing .message__body{border-bottom-right-radius:0}.message__user{display:flex;justify-content:flex-end;max-width:80%;margin-left:auto;margin-top:4px;padding-right:46px}.message__user--mobile{padding-right:5px!important}.message__user-name{font:400 12px/16px inter,sans-serif;color:#ced4da}@keyframes pop{0%{transform:translateY(2px);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes message-loading-spin{to{transform:rotate(360deg)}}::ng-deep .mat-mdc-menu-content{background:#fff;width:160px;border-radius:8px;gap:4px;border:1px solid #E1E7F8;padding:8px 4px;box-shadow:0 2px 4px #0000001a;overflow:hidden;font:400 14px/18px inter,sans-serif}::ng-deep .mat-mdc-menu-item-text{font:400 14px/18px inter,sans-serif!important;font-weight:500!important;color:#343a40!important;display:flex;justify-content:flex-start;align-items:center;gap:4px}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: PreviewFile, selector: "lib-preview-file", inputs: ["srcList", "startIndex", "title", "openerElement", "closeHandler", "activeIndex", "viewReady", "userNavigated", "previousListLength"], outputs: ["activeIndexChange", "viewReadyChange", "userNavigatedChange", "previousListLengthChange"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
|
|
369
406
|
}
|
|
370
407
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ChatMessageComponent, decorators: [{
|
|
371
408
|
type: Component,
|
|
@@ -378,8 +415,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
378
415
|
MatMenuTrigger,
|
|
379
416
|
TranslocoPipe,
|
|
380
417
|
PreviewFile,
|
|
381
|
-
|
|
382
|
-
}], ctorParameters: () => [{ type: UtilsService }], propDecorators: { currentMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentMessage", required: true }] }], edit: [{ type: i0.Input, args: [{ isSignal: true, alias: "edit", required: false }] }, { type: i0.Output, args: ["editChange"] }], previewList: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewList", required: false }] }, { type: i0.Output, args: ["previewListChange"] }], previewIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewIndex", required: false }] }, { type: i0.Output, args: ["previewIndexChange"] }], previewOpener: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewOpener", required: false }] }, { type: i0.Output, args: ["previewOpenerChange"] }], requestEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestEdit", required: false }] }, { type: i0.Output, args: ["requestEditChange"] }], requestDelete: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestDelete", required: false }] }, { type: i0.Output, args: ["requestDeleteChange"] }] } });
|
|
418
|
+
IonButton,
|
|
419
|
+
], standalone: true, template: "<div class=\"message\"\n [ngClass]=\"{\n 'message--outgoing': currentMessage().type === messageType.Outgoing,\n 'message--incoming': currentMessage().type === messageType.Incoming,\n 'message--mobile': mobileMode()\n }\">\n @if (showAvatar()) {\n <div class=\"message__avatar\">\n <img [ngSrc]=\"avatarSrc()\" width=\"36\" height=\"36\" alt=\"avatar\"/>\n </div>\n }\n\n @if (showMessageBody()) {\n <div class=\"message__body\"\n (contextmenu)=\"openContextMenu($event, menuTrigger, menuTriggerEl)\"\n (keydown.shift.F10)=\"openContextMenu($event, menuTrigger, menuTriggerEl)\">\n <button type=\"button\"\n class=\"message__menu-trigger\"\n aria-hidden=\"true\"\n tabindex=\"-1\"\n #menuTrigger=\"matMenuTrigger\"\n #menuTriggerEl\n [matMenuTriggerFor]=\"messageMenu\">\n </button>\n\n @if (attachments().length) {\n <div class=\"message__attachments\">\n @for (file of attachments(); track file; let i = $index) {\n <button type=\"button\"\n class=\"message__image-button\"\n (click)=\"openPreview(i, $event)\"\n [attr.aria-label]=\"'chat.photo_preview' | transloco\">\n <img [src]=\"file\"\n alt=\"attachment\"\n class=\"message__image\"\n loading=\"lazy\"/>\n </button>\n }\n </div>\n }\n\n @if (showMessageBubble()) {\n <div class=\"message__bubble\" tabindex=\"0\">\n <div class=\"message__text\">{{ currentMessage().content }}</div>\n\n <div class=\"message__meta\">\n <time class=\"message__time\">\n {{ currentMessage().cr_time | date:'HH:mm' }}\n </time>\n @if (currentMessage().type === messageType.Outgoing) {\n @if (currentMessage().pending) {\n <span class=\"message__loading\" aria-label=\"Sending\"></span>\n } @else if (currentMessage().checked) {\n <img ngSrc=\"assets/ngx-parl/icons/checked-message.svg\"\n class=\"message__icon\"\n width=\"18\" height=\"18\" alt=\"hide\"/>\n } @else {\n <img ngSrc=\"assets/ngx-parl/icons/no-check.svg\"\n class=\"message__icon\"\n width=\"18\" height=\"18\" alt=\"hide\"/>\n }\n }\n </div>\n </div>\n }\n\n </div>\n }\n\n @if (showQuickActions()) {\n <div class=\"message__quick-actions-wrap\" role=\"group\" aria-label=\"Quick actions\">\n <div class=\"message__quick-actions\">\n @for (action of quickActions(); track action.id) {\n <ion-button\n class=\"message__quick-action-button\"\n fill=\"outline\"\n expand=\"block\"\n [disabled]=\"action.disabled === true\"\n (click)=\"onQuickAction(action)\">\n {{ action.title }}\n </ion-button>\n }\n </div>\n </div>\n }\n</div>\n@if (!showQuickActions()) {\n <div class=\"message__user\" [ngClass]=\"{'message__user--mobile': mobileMode()}\">\n @if (currentMessage().type === messageType.Outgoing) {\n <span class=\"message__user-name\">{{ currentMessage().user }}</span>\n }\n </div>\n}\n\n@if (previewList().length) {\n <lib-preview-file\n [srcList]=\"previewList()\"\n [startIndex]=\"previewIndex()\"\n [openerElement]=\"previewOpener()\"\n [closeHandler]=\"closePreviewHandler\">\n </lib-preview-file>\n}\n\n<mat-menu #messageMenu=\"matMenu\" yPosition=\"below\" xPosition=\"before\" class=\"message__menu\">\n @if (currentMessage().type === messageType.Outgoing) {\n <button mat-menu-item (click)=\"editMessage(currentMessage())\">\n <img ngSrc=\"assets/ngx-parl/icons/icon-edit.svg\"\n class=\"message__icon--menu\"\n width=\"20\" height=\"20\" alt=\"hide\"/>\n <span>{{ 'chat.edit' | transloco }}</span>\n </button>\n }\n @if (canDelete(currentMessage())) {\n <button mat-menu-item (click)=\"deleteMessage(currentMessage())\">\n <img ngSrc=\"assets/ngx-parl/icons/trash.svg\"\n class=\"message__icon--menu\"\n width=\"20\" height=\"20\" alt=\"hide\"/>\n <span>{{ 'chat.remove' | transloco }}</span>\n </button>\n }\n</mat-menu>\n", styles: [".flow-theme-primary ::ng-deep .modal-chat__header{background-color:#5a72d7;color:#fff}.flow-theme-primary ::ng-deep .message--incoming .message__body{background:#e9ecef;color:#343a40}.flow-theme-primary ::ng-deep .message--outgoing .message__body{background:#4656ca;color:#fff}:root{--shadow-sm: 0px 1px 2px 0px rgba(0, 0, 0, .05);--shadow-md: 0px 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0px 8px 24px rgba(0, 0, 0, .12);--shadow-soft: 0px 0px 6px 0px rgba(46, 46, 46, .12) }.flow-theme-secondary ::ng-deep .modal-chat__header{background-color:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--incoming .message__body{background:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--outgoing .message__body{background:#efefef;color:#464646}.message{display:flex;gap:8px;align-items:flex-end;max-width:80%;animation:pop .12s ease-out}.message__avatar img{display:block;border-radius:1000px}.message__body{padding:8px 12px;min-width:0;font:400 16px/20px inter,sans-serif;border-radius:16px;position:relative}.message__bubble{display:grid;grid-template-columns:1fr auto;column-gap:8px;align-items:end;max-width:100%;word-break:break-word;white-space:pre-wrap}.message__quick-actions-wrap{display:flex;margin-top:12px;width:100%;background:transparent}.message__quick-actions{display:grid;gap:8px;width:234px;max-width:100%;background:transparent}.message__quick-action-button{--border-radius: 16px;--border-width: 1px;--border-style: solid;--border-color: #2563EB;--color: #2563EB;--padding-top: tokens.$space-3;--padding-bottom: tokens.$space-3;--padding-start: tokens.$space-6;--padding-end: tokens.$space-6;height:48px;text-transform:none;font:500 14px/18px inter,sans-serif;margin:0}.message__text{min-width:0}.message__meta{display:inline-flex;align-items:center;gap:4px;-webkit-user-select:none;user-select:none;line-height:1;margin:0}.message__time{font:400 12px/16px inter,sans-serif}.message__attachments{display:grid;gap:8px;justify-content:start;width:100%;margin-bottom:8px}.message__attachments:has(:only-child){grid-template-columns:repeat(1,minmax(0,140px))}.message__attachments:has(:nth-child(2):last-child){grid-template-columns:repeat(2,minmax(0,145px))}.message__attachments:has(:nth-child(3)){grid-template-columns:repeat(3,minmax(0,150px))}.message__body--attachments-1{max-width:164px}.message__body--attachments-2{max-width:312px}.message__body--attachments-3{max-width:460px}.message__body--attachments-1 .message__bubble,.message__body--attachments-2 .message__bubble,.message__body--attachments-3 .message__bubble{grid-template-columns:1fr;row-gap:4px}.message__body--attachments-1 .message__meta,.message__body--attachments-2 .message__meta,.message__body--attachments-3 .message__meta{justify-self:end}.message__image-button{display:block;border:none;padding:0;background:transparent;border-radius:12px;overflow:hidden;cursor:pointer}.message__image-button:focus-visible{outline:2px solid #5A72D7;outline-offset:4px}.message__menu-trigger{position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;pointer-events:none}.message__image{display:block;width:100%;height:140px;object-fit:cover;border-radius:12px;aspect-ratio:1/1}.message__bubble:after{content:\"\";display:block;clear:both}.message__time{font:400 12px/16px inter,sans-serif;min-width:30px}.message__icon{width:14px;height:14px;vertical-align:middle}.message__icon--menu{width:20px;height:20px}.message__loading{display:inline-block;width:10px;height:10px;border:2px solid #E9ECEF;border-top-color:#5a72d7;border-radius:50%;animation:message-loading-spin .8s linear infinite}.message--incoming{margin-right:auto}.message--incoming .message__body{border-bottom-right-radius:16px}.message--incoming .message__bubble{border-top-left-radius:4px}.message--incoming .message__time{color:#adb5bd}.message--incoming .message__quick-actions-wrap{justify-content:flex-start}.message--outgoing{margin-left:auto;flex-direction:row-reverse}.message--outgoing .message__body{border-bottom-right-radius:0}.message--outgoing .message__bubble{border-top-right-radius:4px}.message--outgoing .message__time{color:#e9ecef}.message--outgoing .message__menu-trigger{right:auto}.message--outgoing .message__quick-actions-wrap{justify-content:flex-end}.message--mobile .message__user{padding-right:5px!important}.message--mobile.message--outgoing .message__body{border-bottom-right-radius:0}.message__user{display:flex;justify-content:flex-end;max-width:80%;margin-left:auto;margin-top:4px;padding-right:46px}.message__user--mobile{padding-right:5px!important}.message__user-name{font:400 12px/16px inter,sans-serif;color:#ced4da}@keyframes pop{0%{transform:translateY(2px);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes message-loading-spin{to{transform:rotate(360deg)}}::ng-deep .mat-mdc-menu-content{background:#fff;width:160px;border-radius:8px;gap:4px;border:1px solid #E1E7F8;padding:8px 4px;box-shadow:0 2px 4px #0000001a;overflow:hidden;font:400 14px/18px inter,sans-serif}::ng-deep .mat-mdc-menu-item-text{font:400 14px/18px inter,sans-serif!important;font-weight:500!important;color:#343a40!important;display:flex;justify-content:flex-start;align-items:center;gap:4px}\n"] }]
|
|
420
|
+
}], ctorParameters: () => [{ type: UtilsService }], propDecorators: { currentMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentMessage", required: true }] }], edit: [{ type: i0.Input, args: [{ isSignal: true, alias: "edit", required: false }] }, { type: i0.Output, args: ["editChange"] }], previewList: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewList", required: false }] }, { type: i0.Output, args: ["previewListChange"] }], previewIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewIndex", required: false }] }, { type: i0.Output, args: ["previewIndexChange"] }], previewOpener: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewOpener", required: false }] }, { type: i0.Output, args: ["previewOpenerChange"] }], requestEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestEdit", required: false }] }, { type: i0.Output, args: ["requestEditChange"] }], requestDelete: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestDelete", required: false }] }, { type: i0.Output, args: ["requestDeleteChange"] }], mobileMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileMode", required: false }] }], quickActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickActions", required: false }] }], quickActionClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickActionClick", required: false }] }, { type: i0.Output, args: ["quickActionClickChange"] }] } });
|
|
383
421
|
|
|
384
422
|
class ToggleDisplayChatStartDayPipe {
|
|
385
423
|
utils;
|
|
@@ -438,12 +476,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
438
476
|
|
|
439
477
|
class ChatFlowComponent {
|
|
440
478
|
flowRef;
|
|
479
|
+
transloco = inject(TranslocoService);
|
|
480
|
+
translocoLang = toSignal(this.transloco.langChanges$, {
|
|
481
|
+
initialValue: this.transloco.getActiveLang(),
|
|
482
|
+
});
|
|
441
483
|
scrollToBottomTrigger = model(0, ...(ngDevMode ? [{ debugName: "scrollToBottomTrigger" }] : []));
|
|
442
484
|
loadHistory = model(false, ...(ngDevMode ? [{ debugName: "loadHistory" }] : []));
|
|
443
485
|
messageListInput = model.required(...(ngDevMode ? [{ debugName: "messageListInput" }] : []));
|
|
444
486
|
messageList = computed(() => this.messageListInput(), ...(ngDevMode ? [{ debugName: "messageList" }] : []));
|
|
445
487
|
selectedForEdit = model.required(...(ngDevMode ? [{ debugName: "selectedForEdit" }] : []));
|
|
446
488
|
requestDelete = model(null, ...(ngDevMode ? [{ debugName: "requestDelete" }] : []));
|
|
489
|
+
mobileMode = input(false, ...(ngDevMode ? [{ debugName: "mobileMode" }] : []));
|
|
490
|
+
quickActionsResolver = input(null, ...(ngDevMode ? [{ debugName: "quickActionsResolver" }] : []));
|
|
491
|
+
quickActionClick = model(null, ...(ngDevMode ? [{ debugName: "quickActionClick" }] : []));
|
|
492
|
+
deleteConfirmOpen = signal(false, ...(ngDevMode ? [{ debugName: "deleteConfirmOpen" }] : []));
|
|
493
|
+
pendingDeleteMessageId = signal(null, ...(ngDevMode ? [{ debugName: "pendingDeleteMessageId" }] : []));
|
|
494
|
+
deleteAlertButtons = computed(() => {
|
|
495
|
+
this.translocoLang();
|
|
496
|
+
return [
|
|
497
|
+
{
|
|
498
|
+
text: this.transloco.translate('chat.cancel'),
|
|
499
|
+
role: 'cancel',
|
|
500
|
+
handler: () => this.closeDeleteConfirm(),
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
text: this.transloco.translate('chat.remove'),
|
|
504
|
+
role: 'destructive',
|
|
505
|
+
cssClass: 'chat__delete-alert-destructive',
|
|
506
|
+
handler: () => this.confirmDelete(),
|
|
507
|
+
},
|
|
508
|
+
];
|
|
509
|
+
}, ...(ngDevMode ? [{ debugName: "deleteAlertButtons" }] : []));
|
|
510
|
+
quickActionsByMessageId = computed(() => {
|
|
511
|
+
const messages = this.messageList();
|
|
512
|
+
const resolver = this.quickActionsResolver();
|
|
513
|
+
const isMobile = this.mobileMode();
|
|
514
|
+
const map = new Map();
|
|
515
|
+
if (!resolver || !isMobile) {
|
|
516
|
+
return map;
|
|
517
|
+
}
|
|
518
|
+
for (const message of messages) {
|
|
519
|
+
const actions = resolver({ message, isMobile });
|
|
520
|
+
if (Array.isArray(actions) && actions.length) {
|
|
521
|
+
map.set(message.id, actions);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return map;
|
|
525
|
+
}, ...(ngDevMode ? [{ debugName: "quickActionsByMessageId" }] : []));
|
|
447
526
|
viewInitialized = false;
|
|
448
527
|
previousMessageCount = 0;
|
|
449
528
|
previousFirstMessageId = null;
|
|
@@ -625,6 +704,26 @@ class ChatFlowComponent {
|
|
|
625
704
|
return this;
|
|
626
705
|
}
|
|
627
706
|
this.selectedForEdit.set(null);
|
|
707
|
+
if (!this.mobileMode()) {
|
|
708
|
+
this.requestDelete.set(messageId);
|
|
709
|
+
queueMicrotask(() => this.requestDelete.set(null));
|
|
710
|
+
return this;
|
|
711
|
+
}
|
|
712
|
+
this.pendingDeleteMessageId.set(messageId);
|
|
713
|
+
this.deleteConfirmOpen.set(true);
|
|
714
|
+
return this;
|
|
715
|
+
}
|
|
716
|
+
closeDeleteConfirm() {
|
|
717
|
+
this.deleteConfirmOpen.set(false);
|
|
718
|
+
this.pendingDeleteMessageId.set(null);
|
|
719
|
+
return this;
|
|
720
|
+
}
|
|
721
|
+
confirmDelete() {
|
|
722
|
+
const messageId = this.pendingDeleteMessageId();
|
|
723
|
+
if (messageId == null) {
|
|
724
|
+
return this.closeDeleteConfirm();
|
|
725
|
+
}
|
|
726
|
+
this.closeDeleteConfirm();
|
|
628
727
|
this.requestDelete.set(messageId);
|
|
629
728
|
queueMicrotask(() => this.requestDelete.set(null));
|
|
630
729
|
return this;
|
|
@@ -634,7 +733,7 @@ class ChatFlowComponent {
|
|
|
634
733
|
}
|
|
635
734
|
Math = Math;
|
|
636
735
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ChatFlowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
637
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: ChatFlowComponent, isStandalone: true, selector: "app-chat-flow", inputs: { scrollToBottomTrigger: { classPropertyName: "scrollToBottomTrigger", publicName: "scrollToBottomTrigger", isSignal: true, isRequired: false, transformFunction: null }, loadHistory: { classPropertyName: "loadHistory", publicName: "loadHistory", isSignal: true, isRequired: false, transformFunction: null }, messageListInput: { classPropertyName: "messageListInput", publicName: "messageListInput", isSignal: true, isRequired: true, transformFunction: null }, selectedForEdit: { classPropertyName: "selectedForEdit", publicName: "selectedForEdit", isSignal: true, isRequired: true, transformFunction: null }, requestDelete: { classPropertyName: "requestDelete", publicName: "requestDelete", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { scrollToBottomTrigger: "scrollToBottomTriggerChange", loadHistory: "loadHistoryChange", messageListInput: "messageListInputChange", selectedForEdit: "selectedForEditChange", requestDelete: "requestDeleteChange" }, viewQueries: [{ propertyName: "flowRef", first: true, predicate: ["chatFlowRef"], descendants: true }], ngImport: i0, template: "<div class=\"chat\">\n @if (messageList()) {\n <div #chatFlowRef\n class=\"chat__flow\"\n infiniteScroll\n [scrollWindow]=\"false\"\n [infiniteScrollUpDistance]=\"Math.max(historyLoadThreshold(), 2)\"\n [infiniteScrollThrottle]=\"100\"\n (scrolledUp)=\"onScrollUp()\"\n >\n @for (message of messageList(); track trackByMessageId(i, message); let i = $index) {\n @if (message | toggleDisplayChatStartDay: messageList() : i) {\n <span class=\"chat__start-day\">\n {{ message.cr_time | chatStartDay:'d MMMM' }}\n </span>\n }\n\n <div class=\"chat__message\" [attr.data-message-id]=\"message.id\">\n <lib-chat-message\n [currentMessage]=\"message\"\n [edit]=\"message.edit\"\n (editChange)=\"onEditChange(message.id, $event)\"\n (requestEditChange)=\"onRequestEdit($event)\"\n (requestDeleteChange)=\"onRequestDelete($event)\">\n </lib-chat-message>\n </div>\n }\n </div>\n\n @if (showScrollToBottom()) {\n <button class=\"chat__scroll-button\"\n type=\"button\"\n (click)=\"scrollToBottomSmooth()\"\n aria-label=\"Scroll to bottom\">\n <img ngSrc=\"assets/ngx-parl/icons/bottom-scroll.svg\"\n alt=\"\"\n width=\"14\"\n height=\"14\"/>\n </button>\n }\n } @else {\n <div class=\"chat__flow__empty\">\n <img ngSrc=\"assets/ngx-parl/icons/lucide_send.svg\"\n class=\"message__icon\"\n width=\"18\" height=\"24\" alt=\"hide\"/>\n\n\n <div class=\"chat__flow__empty--header\">\n <h3 class=\"chat__flow__empty--title\">{{ 'chat.chat_empty_title' | transloco }}</h3>\n <p class=\"chat__flow__empty--subscription\">{{ 'chat.chat_empty_subscription' | transloco }}</p>\n </div>\n </div>\n }\n</div>\n\n", styles: [":host{display:block;height:100%;min-height:0}.chat{background:#fff;height:100%;display:flex;flex-direction:column;min-height:0;width:100%;position:relative}.chat__flow{flex:1 1 auto;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:12px;padding:12px 16px;overscroll-behavior:contain}.chat__flow__empty{display:flex;gap:16px;flex-direction:column;align-items:center;justify-content:center;padding:72px 16px;height:100%}.chat__flow__empty .message__icon{width:56px;height:56px}.chat__flow__empty--header{width:285px;display:flex;gap:12px;flex-direction:column;align-items:center}.chat__flow__empty--title{margin:0;font:600 16px/20px inter,sans-serif;color:#212529}.chat__flow__empty--subscription{margin:0;font:400 16px/20px inter,sans-serif;color:#495057}.chat__start-day{display:flex;justify-content:center;background:#f8f9fa;color:#6c757d;font:400 12px/16px inter,sans-serif;width:
|
|
736
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: ChatFlowComponent, isStandalone: true, selector: "app-chat-flow", inputs: { scrollToBottomTrigger: { classPropertyName: "scrollToBottomTrigger", publicName: "scrollToBottomTrigger", isSignal: true, isRequired: false, transformFunction: null }, loadHistory: { classPropertyName: "loadHistory", publicName: "loadHistory", isSignal: true, isRequired: false, transformFunction: null }, messageListInput: { classPropertyName: "messageListInput", publicName: "messageListInput", isSignal: true, isRequired: true, transformFunction: null }, selectedForEdit: { classPropertyName: "selectedForEdit", publicName: "selectedForEdit", isSignal: true, isRequired: true, transformFunction: null }, requestDelete: { classPropertyName: "requestDelete", publicName: "requestDelete", isSignal: true, isRequired: false, transformFunction: null }, mobileMode: { classPropertyName: "mobileMode", publicName: "mobileMode", isSignal: true, isRequired: false, transformFunction: null }, quickActionsResolver: { classPropertyName: "quickActionsResolver", publicName: "quickActionsResolver", isSignal: true, isRequired: false, transformFunction: null }, quickActionClick: { classPropertyName: "quickActionClick", publicName: "quickActionClick", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { scrollToBottomTrigger: "scrollToBottomTriggerChange", loadHistory: "loadHistoryChange", messageListInput: "messageListInputChange", selectedForEdit: "selectedForEditChange", requestDelete: "requestDeleteChange", quickActionClick: "quickActionClickChange" }, viewQueries: [{ propertyName: "flowRef", first: true, predicate: ["chatFlowRef"], descendants: true }], ngImport: i0, template: "<div class=\"chat\">\n @if (messageList()) {\n <div #chatFlowRef\n class=\"chat__flow\"\n infiniteScroll\n [scrollWindow]=\"false\"\n [infiniteScrollUpDistance]=\"Math.max(historyLoadThreshold(), 2)\"\n [infiniteScrollThrottle]=\"100\"\n (scrolledUp)=\"onScrollUp()\"\n >\n <div class=\"chat__manager-header\" aria-hidden=\"true\">\n <div class=\"chat__manager-icon\">\n <img ngSrc=\"assets/ngx-parl/icons/avatar_manager.svg\"\n alt=\"manager\"\n width=\"72\"\n height=\"72\"/>\n </div>\n </div>\n\n @for (message of messageList(); track trackByMessageId(i, message); let i = $index) {\n @if (message | toggleDisplayChatStartDay: messageList() : i) {\n <span class=\"chat__start-day\">\n {{ message.cr_time | chatStartDay:'d MMMM' }}\n </span>\n }\n\n <div class=\"chat__message\" [attr.data-message-id]=\"message.id\">\n <lib-chat-message\n [currentMessage]=\"message\"\n [edit]=\"message.edit\"\n [mobileMode]=\"mobileMode()\"\n [quickActions]=\"quickActionsByMessageId().get(message.id) ?? []\"\n [(quickActionClick)]=\"quickActionClick\"\n (editChange)=\"onEditChange(message.id, $event)\"\n (requestEditChange)=\"onRequestEdit($event)\"\n (requestDeleteChange)=\"onRequestDelete($event)\">\n </lib-chat-message>\n </div>\n }\n </div>\n\n @if (mobileMode()) {\n <ion-alert mode=\"md\"\n [header]=\"'chat.delete_message_title' | transloco\"\n cssClass=\"chat__delete-alert\"\n [isOpen]=\"deleteConfirmOpen()\"\n [buttons]=\"deleteAlertButtons()\"\n (didDismiss)=\"closeDeleteConfirm()\"\n [backdropDismiss]=\"false\">\n </ion-alert>\n }\n\n @if (showScrollToBottom()) {\n <button class=\"chat__scroll-button\"\n type=\"button\"\n (click)=\"scrollToBottomSmooth()\"\n aria-label=\"Scroll to bottom\">\n <img ngSrc=\"assets/ngx-parl/icons/bottom-scroll.svg\"\n alt=\"\"\n width=\"14\"\n height=\"14\"/>\n </button>\n }\n } @else {\n <div class=\"chat__flow__empty\">\n <img ngSrc=\"assets/ngx-parl/icons/lucide_send.svg\"\n class=\"message__icon\"\n width=\"18\" height=\"24\" alt=\"hide\"/>\n\n\n <div class=\"chat__flow__empty--header\">\n <h3 class=\"chat__flow__empty--title\">{{ 'chat.chat_empty_title' | transloco }}</h3>\n <p class=\"chat__flow__empty--subscription\">{{ 'chat.chat_empty_subscription' | transloco }}</p>\n </div>\n </div>\n }\n</div>\n\n", styles: [":host{display:block;height:100%;min-height:0}.chat{background:#fff;height:100%;display:flex;flex-direction:column;min-height:0;width:100%;position:relative}.chat__flow{flex:1 1 auto;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:12px;padding:12px 16px;overscroll-behavior:contain}.chat__flow__empty{display:flex;gap:16px;flex-direction:column;align-items:center;justify-content:center;padding:72px 16px;height:100%}.chat__flow__empty .message__icon{width:56px;height:56px}.chat__flow__empty--header{width:285px;display:flex;gap:12px;flex-direction:column;align-items:center}.chat__flow__empty--title{margin:0;font:600 16px/20px inter,sans-serif;color:#212529}.chat__flow__empty--subscription{margin:0;font:400 16px/20px inter,sans-serif;color:#495057}.chat__manager-header{display:flex;justify-content:center;padding:24px 16px 8px}.chat__manager-icon{width:132px;height:132px;border-radius:1000px;display:grid;place-items:center}.chat__manager-icon img{display:block;border-radius:1000px}.chat__start-day{display:flex;justify-content:center;background:#f8f9fa;color:#6c757d;font:400 12px/16px inter,sans-serif;width:92px;height:22px;margin:0 auto;border-radius:1000px;gap:8px;padding:4px 8px}.chat__scroll-button{position:absolute;right:8px;bottom:8px;width:35px;height:35px;display:inline-flex;align-items:center;justify-content:center;padding:8px;border:none;border-radius:1000px;background:#c9d4f4;box-shadow:0 2px 4px #0000001a;opacity:.6;cursor:pointer;transition:background-color .15s ease,opacity .15s ease}.chat__scroll-button:hover,.chat__scroll-button:focus-visible{background:#dee2e6;opacity:1}.chat__scroll-button img{display:block}.chat ::-webkit-scrollbar{width:6px}.chat ::-webkit-scrollbar-track{background:transparent}.chat ::-webkit-scrollbar-thumb{background-color:#e9ecef;border-radius:4px;border:1px solid #E9ECEF}.chat ::-webkit-scrollbar-button{display:none}.chat__delete-alert{--background: #ffffff;--backdrop-opacity: .32;--max-width: 520px}.chat__delete-alert .alert-wrapper{border-radius:16px;box-shadow:0 10px 30px #00000026}.chat__delete-alert .alert-head{padding-top:18px}.chat__delete-alert .alert-title{color:#0f172a;font-weight:500}.chat__delete-alert .alert-button-group{padding:8px 12px 12px}.chat__delete-alert .alert-button{color:#2563eb;font-weight:500}.chat__delete-alert .alert-button-role-destructive,.chat__delete-alert .alert-button-role-destructive .alert-button-inner{color:#dc2626!important}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: ChatMessageComponent, selector: "lib-chat-message", inputs: ["currentMessage", "edit", "previewList", "previewIndex", "previewOpener", "requestEdit", "requestDelete", "mobileMode", "quickActions", "quickActionClick"], outputs: ["editChange", "previewListChange", "previewIndexChange", "previewOpenerChange", "requestEditChange", "requestDeleteChange", "quickActionClickChange"] }, { kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }, { kind: "directive", type: InfiniteScrollDirective, selector: "[infiniteScroll], [infinite-scroll], [data-infinite-scroll]", inputs: ["infiniteScrollDistance", "infiniteScrollUpDistance", "infiniteScrollThrottle", "infiniteScrollDisabled", "infiniteScrollContainer", "scrollWindow", "immediateCheck", "horizontal", "alwaysCallback", "fromRoot"], outputs: ["scrolled", "scrolledUp"] }, { kind: "component", type: IonAlert, selector: "ion-alert", inputs: ["animated", "backdropDismiss", "buttons", "cssClass", "enterAnimation", "header", "htmlAttributes", "inputs", "isOpen", "keyboardClose", "leaveAnimation", "message", "mode", "subHeader", "translucent", "trigger"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: ToggleDisplayChatStartDayPipe, name: "toggleDisplayChatStartDay" }, { kind: "pipe", type: ChatStartDayPipe, name: "chatStartDay" }], encapsulation: i0.ViewEncapsulation.None });
|
|
638
737
|
}
|
|
639
738
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ChatFlowComponent, decorators: [{
|
|
640
739
|
type: Component,
|
|
@@ -645,12 +744,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
645
744
|
NgOptimizedImage,
|
|
646
745
|
InfiniteScrollDirective,
|
|
647
746
|
ToggleDisplayChatStartDayPipe,
|
|
648
|
-
ChatStartDayPipe
|
|
649
|
-
|
|
747
|
+
ChatStartDayPipe,
|
|
748
|
+
IonAlert,
|
|
749
|
+
], standalone: true, encapsulation: ViewEncapsulation.None, template: "<div class=\"chat\">\n @if (messageList()) {\n <div #chatFlowRef\n class=\"chat__flow\"\n infiniteScroll\n [scrollWindow]=\"false\"\n [infiniteScrollUpDistance]=\"Math.max(historyLoadThreshold(), 2)\"\n [infiniteScrollThrottle]=\"100\"\n (scrolledUp)=\"onScrollUp()\"\n >\n <div class=\"chat__manager-header\" aria-hidden=\"true\">\n <div class=\"chat__manager-icon\">\n <img ngSrc=\"assets/ngx-parl/icons/avatar_manager.svg\"\n alt=\"manager\"\n width=\"72\"\n height=\"72\"/>\n </div>\n </div>\n\n @for (message of messageList(); track trackByMessageId(i, message); let i = $index) {\n @if (message | toggleDisplayChatStartDay: messageList() : i) {\n <span class=\"chat__start-day\">\n {{ message.cr_time | chatStartDay:'d MMMM' }}\n </span>\n }\n\n <div class=\"chat__message\" [attr.data-message-id]=\"message.id\">\n <lib-chat-message\n [currentMessage]=\"message\"\n [edit]=\"message.edit\"\n [mobileMode]=\"mobileMode()\"\n [quickActions]=\"quickActionsByMessageId().get(message.id) ?? []\"\n [(quickActionClick)]=\"quickActionClick\"\n (editChange)=\"onEditChange(message.id, $event)\"\n (requestEditChange)=\"onRequestEdit($event)\"\n (requestDeleteChange)=\"onRequestDelete($event)\">\n </lib-chat-message>\n </div>\n }\n </div>\n\n @if (mobileMode()) {\n <ion-alert mode=\"md\"\n [header]=\"'chat.delete_message_title' | transloco\"\n cssClass=\"chat__delete-alert\"\n [isOpen]=\"deleteConfirmOpen()\"\n [buttons]=\"deleteAlertButtons()\"\n (didDismiss)=\"closeDeleteConfirm()\"\n [backdropDismiss]=\"false\">\n </ion-alert>\n }\n\n @if (showScrollToBottom()) {\n <button class=\"chat__scroll-button\"\n type=\"button\"\n (click)=\"scrollToBottomSmooth()\"\n aria-label=\"Scroll to bottom\">\n <img ngSrc=\"assets/ngx-parl/icons/bottom-scroll.svg\"\n alt=\"\"\n width=\"14\"\n height=\"14\"/>\n </button>\n }\n } @else {\n <div class=\"chat__flow__empty\">\n <img ngSrc=\"assets/ngx-parl/icons/lucide_send.svg\"\n class=\"message__icon\"\n width=\"18\" height=\"24\" alt=\"hide\"/>\n\n\n <div class=\"chat__flow__empty--header\">\n <h3 class=\"chat__flow__empty--title\">{{ 'chat.chat_empty_title' | transloco }}</h3>\n <p class=\"chat__flow__empty--subscription\">{{ 'chat.chat_empty_subscription' | transloco }}</p>\n </div>\n </div>\n }\n</div>\n\n", styles: [":host{display:block;height:100%;min-height:0}.chat{background:#fff;height:100%;display:flex;flex-direction:column;min-height:0;width:100%;position:relative}.chat__flow{flex:1 1 auto;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:12px;padding:12px 16px;overscroll-behavior:contain}.chat__flow__empty{display:flex;gap:16px;flex-direction:column;align-items:center;justify-content:center;padding:72px 16px;height:100%}.chat__flow__empty .message__icon{width:56px;height:56px}.chat__flow__empty--header{width:285px;display:flex;gap:12px;flex-direction:column;align-items:center}.chat__flow__empty--title{margin:0;font:600 16px/20px inter,sans-serif;color:#212529}.chat__flow__empty--subscription{margin:0;font:400 16px/20px inter,sans-serif;color:#495057}.chat__manager-header{display:flex;justify-content:center;padding:24px 16px 8px}.chat__manager-icon{width:132px;height:132px;border-radius:1000px;display:grid;place-items:center}.chat__manager-icon img{display:block;border-radius:1000px}.chat__start-day{display:flex;justify-content:center;background:#f8f9fa;color:#6c757d;font:400 12px/16px inter,sans-serif;width:92px;height:22px;margin:0 auto;border-radius:1000px;gap:8px;padding:4px 8px}.chat__scroll-button{position:absolute;right:8px;bottom:8px;width:35px;height:35px;display:inline-flex;align-items:center;justify-content:center;padding:8px;border:none;border-radius:1000px;background:#c9d4f4;box-shadow:0 2px 4px #0000001a;opacity:.6;cursor:pointer;transition:background-color .15s ease,opacity .15s ease}.chat__scroll-button:hover,.chat__scroll-button:focus-visible{background:#dee2e6;opacity:1}.chat__scroll-button img{display:block}.chat ::-webkit-scrollbar{width:6px}.chat ::-webkit-scrollbar-track{background:transparent}.chat ::-webkit-scrollbar-thumb{background-color:#e9ecef;border-radius:4px;border:1px solid #E9ECEF}.chat ::-webkit-scrollbar-button{display:none}.chat__delete-alert{--background: #ffffff;--backdrop-opacity: .32;--max-width: 520px}.chat__delete-alert .alert-wrapper{border-radius:16px;box-shadow:0 10px 30px #00000026}.chat__delete-alert .alert-head{padding-top:18px}.chat__delete-alert .alert-title{color:#0f172a;font-weight:500}.chat__delete-alert .alert-button-group{padding:8px 12px 12px}.chat__delete-alert .alert-button{color:#2563eb;font-weight:500}.chat__delete-alert .alert-button-role-destructive,.chat__delete-alert .alert-button-role-destructive .alert-button-inner{color:#dc2626!important}\n"] }]
|
|
650
750
|
}], ctorParameters: () => [], propDecorators: { flowRef: [{
|
|
651
751
|
type: ViewChild,
|
|
652
752
|
args: ['chatFlowRef']
|
|
653
|
-
}], scrollToBottomTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollToBottomTrigger", required: false }] }, { type: i0.Output, args: ["scrollToBottomTriggerChange"] }], loadHistory: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadHistory", required: false }] }, { type: i0.Output, args: ["loadHistoryChange"] }], messageListInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageListInput", required: true }] }, { type: i0.Output, args: ["messageListInputChange"] }], selectedForEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedForEdit", required: true }] }, { type: i0.Output, args: ["selectedForEditChange"] }], requestDelete: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestDelete", required: false }] }, { type: i0.Output, args: ["requestDeleteChange"] }] } });
|
|
753
|
+
}], scrollToBottomTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollToBottomTrigger", required: false }] }, { type: i0.Output, args: ["scrollToBottomTriggerChange"] }], loadHistory: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadHistory", required: false }] }, { type: i0.Output, args: ["loadHistoryChange"] }], messageListInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageListInput", required: true }] }, { type: i0.Output, args: ["messageListInputChange"] }], selectedForEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedForEdit", required: true }] }, { type: i0.Output, args: ["selectedForEditChange"] }], requestDelete: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestDelete", required: false }] }, { type: i0.Output, args: ["requestDeleteChange"] }], mobileMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileMode", required: false }] }], quickActionsResolver: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickActionsResolver", required: false }] }], quickActionClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickActionClick", required: false }] }, { type: i0.Output, args: ["quickActionClickChange"] }] } });
|
|
654
754
|
|
|
655
755
|
class ImageFile {
|
|
656
756
|
id;
|
|
@@ -1064,6 +1164,10 @@ class NgxParlComponent {
|
|
|
1064
1164
|
transportType = input('', ...(ngDevMode ? [{ debugName: "transportType" }] : []));
|
|
1065
1165
|
transportTypeIcon = input('', ...(ngDevMode ? [{ debugName: "transportTypeIcon" }] : []));
|
|
1066
1166
|
transportTypeIconSrc = computed(() => this.utils.normalizeSourcePath(this.transportTypeIcon()), ...(ngDevMode ? [{ debugName: "transportTypeIconSrc" }] : []));
|
|
1167
|
+
mobileMode = input(false, ...(ngDevMode ? [{ debugName: "mobileMode" }] : []));
|
|
1168
|
+
quickActionsResolver = input(null, ...(ngDevMode ? [{ debugName: "quickActionsResolver" }] : []));
|
|
1169
|
+
quickActionClick = model(null, ...(ngDevMode ? [{ debugName: "quickActionClick" }] : []));
|
|
1170
|
+
quickActionsAutoSend = input(true, ...(ngDevMode ? [{ debugName: "quickActionsAutoSend" }] : []));
|
|
1067
1171
|
hideHandler = input(null, ...(ngDevMode ? [{ debugName: "hideHandler" }] : []));
|
|
1068
1172
|
closeHandler = input(null, ...(ngDevMode ? [{ debugName: "closeHandler" }] : []));
|
|
1069
1173
|
scrollToBottomTrigger = model(0, ...(ngDevMode ? [{ debugName: "scrollToBottomTrigger" }] : []));
|
|
@@ -1098,6 +1202,24 @@ class NgxParlComponent {
|
|
|
1098
1202
|
});
|
|
1099
1203
|
this.scrollToBottom();
|
|
1100
1204
|
});
|
|
1205
|
+
effect(() => {
|
|
1206
|
+
const event = this.quickActionClick();
|
|
1207
|
+
if (!event || !this.quickActionsAutoSend()) {
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
const content = (event.value ?? '').trim();
|
|
1211
|
+
if (!content) {
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
setTimeout(() => {
|
|
1215
|
+
try {
|
|
1216
|
+
this.sendMessage({ content });
|
|
1217
|
+
}
|
|
1218
|
+
catch (error) {
|
|
1219
|
+
console.error('Quick action send failed', error);
|
|
1220
|
+
}
|
|
1221
|
+
}, 0);
|
|
1222
|
+
});
|
|
1101
1223
|
}
|
|
1102
1224
|
ngAfterViewInit() {
|
|
1103
1225
|
if (this.dialogRef) {
|
|
@@ -1230,6 +1352,7 @@ class NgxParlComponent {
|
|
|
1230
1352
|
file_list: [],
|
|
1231
1353
|
checked: true,
|
|
1232
1354
|
pending: true,
|
|
1355
|
+
actions: [],
|
|
1233
1356
|
};
|
|
1234
1357
|
this.messageList.update((list) => [...list, new ChatMessage(dto)]);
|
|
1235
1358
|
this.scrollToBottomTrigger.update(v => v + 1);
|
|
@@ -1277,6 +1400,7 @@ class NgxParlComponent {
|
|
|
1277
1400
|
file_list: hasFileList ? file_list : [],
|
|
1278
1401
|
checked: true,
|
|
1279
1402
|
pending: true,
|
|
1403
|
+
actions: [],
|
|
1280
1404
|
};
|
|
1281
1405
|
this.messageList.update((list) => [...list, new ChatMessage(dto)]);
|
|
1282
1406
|
this.scrollToBottomTrigger.update(v => v + 1);
|
|
@@ -1358,7 +1482,7 @@ class NgxParlComponent {
|
|
|
1358
1482
|
}
|
|
1359
1483
|
FlowTheme = FlowTheme;
|
|
1360
1484
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NgxParlComponent, deps: [{ token: UtilsService }, { token: i2.TranslocoService }, { token: i3.MatDialogRef, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
1361
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: NgxParlComponent, isStandalone: true, selector: "ngx-parl", inputs: { dragActive: { classPropertyName: "dragActive", publicName: "dragActive", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, messageList: { classPropertyName: "messageList", publicName: "messageList", isSignal: true, isRequired: false, transformFunction: null }, messageUpdate: { classPropertyName: "messageUpdate", publicName: "messageUpdate", isSignal: true, isRequired: false, transformFunction: null }, selectedForEdit: { classPropertyName: "selectedForEdit", publicName: "selectedForEdit", isSignal: true, isRequired: false, transformFunction: null }, messageAction: { classPropertyName: "messageAction", publicName: "messageAction", isSignal: true, isRequired: false, transformFunction: null }, incomingUser: { classPropertyName: "incomingUser", publicName: "incomingUser", isSignal: true, isRequired: false, transformFunction: null }, transportType: { classPropertyName: "transportType", publicName: "transportType", isSignal: true, isRequired: false, transformFunction: null }, transportTypeIcon: { classPropertyName: "transportTypeIcon", publicName: "transportTypeIcon", isSignal: true, isRequired: false, transformFunction: null }, hideHandler: { classPropertyName: "hideHandler", publicName: "hideHandler", isSignal: true, isRequired: false, transformFunction: null }, closeHandler: { classPropertyName: "closeHandler", publicName: "closeHandler", isSignal: true, isRequired: false, transformFunction: null }, scrollToBottomTrigger: { classPropertyName: "scrollToBottomTrigger", publicName: "scrollToBottomTrigger", isSignal: true, isRequired: false, transformFunction: null }, loadHistory: { classPropertyName: "loadHistory", publicName: "loadHistory", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dragActive: "dragActiveChange", messageList: "messageListChange", messageUpdate: "messageUpdateChange", selectedForEdit: "selectedForEditChange", messageAction: "messageActionChange", scrollToBottomTrigger: "scrollToBottomTriggerChange", loadHistory: "loadHistoryChange" }, providers: [], viewQueries: [{ propertyName: "chatFlow", first: true, predicate: ChatFlowComponent, descendants: true }, { propertyName: "inputMessage", first: true, predicate: InputMessageComponent, descendants: true }], ngImport: i0, template: "<div class=\"modal-chat\" [ngClass]=\"'flow-theme-' + theme()\">\n <div class=\"modal-chat__body\">\n @if (header()) {\n <header class=\"modal-chat__header\" mat-dialog-title>\n <div class=\"modal-chat__hide-block\"></div>\n\n <div class=\"modal-chat__title\">\n <h1 class=\"modal-chat__heading\" id=\"modal-chat__heading\">\n @if (transportTypeIconSrc()) {\n <img [ngSrc]=\"transportTypeIconSrc()\"\n class=\"modal-chat__heading-icon\"\n width=\"20\"\n height=\"20\"\n [attr.alt]=\"transportType() || 'transport icon'\"/>\n }\n <span class=\"modal-chat__heading-text\">\n {{ transportType() }} {{ incomingUser() }}\n </span>\n </h1>\n </div>\n\n <div class=\"modal-chat__actions\">\n <img ngSrc=\"assets/ngx-parl/icons/hide.svg\" class=\"modal-chat__icon modal-chat__icon--hide\"\n width=\"24\" height=\"24\" alt=\"hide\"\n (click)=\"onHideClick()\"/>\n <img ngSrc=\"assets/ngx-parl/icons/close.svg\" class=\"modal-chat__icon modal-chat__icon--close\"\n width=\"24\" height=\"24\" alt=\"close\"\n (click)=\"onCloseClick()\"/>\n </div>\n </header>\n }\n\n <mat-dialog-content class=\"modal-chat__content\"\n [class.modal-chat__content--header]=\"header() === false\"\n [class.modal-chat__content--dragover]=\"dragActive()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n @if (dragActive()) {\n <div class=\"modal-chat__drag-overlay\"\n role=\"status\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'chat.drag_title' | transloco\">\n <div class=\"modal-chat__drag-card\">\n <img ngSrc=\"assets/ngx-parl/icons/attach-filled.svg\"\n class=\"modal-chat__drag-icon\"\n alt=\"\"\n width=\"56\"\n height=\"56\"/>\n\n <div class=\"modal-chat__drag-title\">\n {{ 'chat.drag_title' | transloco }}\n </div>\n <div class=\"modal-chat__drag-subtitle\">\n {{ 'chat.drag_subtitle' | transloco }}\n </div>\n </div>\n </div>\n }\n <app-chat-flow [messageListInput]=\"messageList()\"\n [(selectedForEdit)]=\"selectedForEdit\"\n (requestDeleteChange)=\"onRequestDelete($event)\"\n [(scrollToBottomTrigger)]=\"scrollToBottomTrigger\"\n [(loadHistory)]=\"loadHistory\">\n </app-chat-flow>\n\n <app-input-message [editMessage]=\"selectedForEdit()\"\n (cancelEditChange)=\"onCancelEdit($event)\"\n (input_textChange)=\"sendMessage($event)\">\n @if (ai_run_in_progress) {\n <mat-spinner [diameter]=\"30\"></mat-spinner>\n }\n </app-input-message>\n </mat-dialog-content>\n </div>\n</div>\n", styles: [".flow-theme-primary ::ng-deep .modal-chat__header{background-color:#5a72d7;color:#fff}.flow-theme-primary ::ng-deep .message--incoming .message__body{background:#e9ecef;color:#343a40}.flow-theme-primary ::ng-deep .message--outgoing .message__body{background:#4656ca;color:#fff}:root{--shadow-sm: 0px 1px 2px 0px rgba(0, 0, 0, .05);--shadow-md: 0px 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0px 8px 24px rgba(0, 0, 0, .12);--shadow-soft: 0px 0px 6px 0px rgba(46, 46, 46, .12) }.flow-theme-secondary ::ng-deep .modal-chat__header{background-color:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--incoming .message__body{background:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--outgoing .message__body{background:#efefef;color:#464646}.modal-chat{width:800px;height:600px;border-radius:16px}.modal-chat__body{display:flex;flex-direction:column;height:100%}.modal-chat__header{height:56px;min-height:56px;max-height:56px;display:flex;align-items:center;justify-content:space-between;padding:0 16px;gap:12px;border-top-left-radius:16px;border-top-right-radius:16px;flex-direction:row}.modal-chat__hide-block{width:48px;color:#5a72d7}.modal-chat__title #modal-chat__heading{color:#fff;font:600 16px/20px inter,sans-serif;display:inline-flex;align-items:center;gap:8px}.modal-chat__heading-icon{width:20px;height:20px;border-radius:1000px;flex:0 0 auto}.modal-chat__actions{display:flex;gap:8px}.modal-chat__content{flex:1 1 auto;display:flex;flex-direction:column;background:#fff;border-bottom-left-radius:16px;border-bottom-right-radius:16px;transition:background-color .16s ease,box-shadow .16s ease;position:relative}.modal-chat__content--header{border-top-left-radius:16px;border-top-right-radius:16px}.modal-chat__content--dragover:after{content:\"\";position:absolute;inset:0;border-radius:inherit;box-shadow:0 0 0 2px #e9ecef inset;background:#fff0;pointer-events:none;z-index:1000}.modal-chat__content app-chat-flow{flex:1 1 auto;min-height:0px;overflow:auto;display:flex;align-items:flex-end}.modal-chat__drag-overlay{position:absolute;inset:16px;display:flex;align-items:center;justify-content:center;border-radius:16px;border:2px dashed #7A95E0;background:#ffffffeb;z-index:1000;pointer-events:none}.modal-chat__drag-card{display:flex;flex-direction:column;align-items:center;gap:8px;padding:20px 24px;border-radius:16px;background:#fff;box-shadow:0 2px 4px #0000001a;text-align:center}.modal-chat__drag-icon{filter:drop-shadow(0 2px 4px rgba(0,0,0,.2))}.modal-chat__drag-title{font:600 20px/24px inter,sans-serif;color:#4656ca}.modal-chat__drag-subtitle{font:400 14px/18px inter,sans-serif;color:#6c757d}.modal-chat__input{flex:0px 0px auto;border-bottom-left-radius:16px;border-bottom-right-radius:16px}:host ::ng-deep .mat-mdc-dialog-content.modal-chat__content{flex:1 1 auto;display:flex;flex-direction:column;padding:0;max-height:none;overflow:hidden}img{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "component", type: MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: ChatFlowComponent, selector: "app-chat-flow", inputs: ["scrollToBottomTrigger", "loadHistory", "messageListInput", "selectedForEdit", "requestDelete"], outputs: ["scrollToBottomTriggerChange", "loadHistoryChange", "messageListInputChange", "selectedForEditChange", "requestDeleteChange"] }, { kind: "component", type: InputMessageComponent, selector: "app-input-message", inputs: ["editMessage", "cancelEdit", "input_text", "files", "previews", "messageEvent"], outputs: ["cancelEditChange", "input_textChange", "filesChange", "previewsChange", "messageEventChange"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }] });
|
|
1485
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: NgxParlComponent, isStandalone: true, selector: "ngx-parl", inputs: { dragActive: { classPropertyName: "dragActive", publicName: "dragActive", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, messageList: { classPropertyName: "messageList", publicName: "messageList", isSignal: true, isRequired: false, transformFunction: null }, messageUpdate: { classPropertyName: "messageUpdate", publicName: "messageUpdate", isSignal: true, isRequired: false, transformFunction: null }, selectedForEdit: { classPropertyName: "selectedForEdit", publicName: "selectedForEdit", isSignal: true, isRequired: false, transformFunction: null }, messageAction: { classPropertyName: "messageAction", publicName: "messageAction", isSignal: true, isRequired: false, transformFunction: null }, incomingUser: { classPropertyName: "incomingUser", publicName: "incomingUser", isSignal: true, isRequired: false, transformFunction: null }, transportType: { classPropertyName: "transportType", publicName: "transportType", isSignal: true, isRequired: false, transformFunction: null }, transportTypeIcon: { classPropertyName: "transportTypeIcon", publicName: "transportTypeIcon", isSignal: true, isRequired: false, transformFunction: null }, mobileMode: { classPropertyName: "mobileMode", publicName: "mobileMode", isSignal: true, isRequired: false, transformFunction: null }, quickActionsResolver: { classPropertyName: "quickActionsResolver", publicName: "quickActionsResolver", isSignal: true, isRequired: false, transformFunction: null }, quickActionClick: { classPropertyName: "quickActionClick", publicName: "quickActionClick", isSignal: true, isRequired: false, transformFunction: null }, quickActionsAutoSend: { classPropertyName: "quickActionsAutoSend", publicName: "quickActionsAutoSend", isSignal: true, isRequired: false, transformFunction: null }, hideHandler: { classPropertyName: "hideHandler", publicName: "hideHandler", isSignal: true, isRequired: false, transformFunction: null }, closeHandler: { classPropertyName: "closeHandler", publicName: "closeHandler", isSignal: true, isRequired: false, transformFunction: null }, scrollToBottomTrigger: { classPropertyName: "scrollToBottomTrigger", publicName: "scrollToBottomTrigger", isSignal: true, isRequired: false, transformFunction: null }, loadHistory: { classPropertyName: "loadHistory", publicName: "loadHistory", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dragActive: "dragActiveChange", messageList: "messageListChange", messageUpdate: "messageUpdateChange", selectedForEdit: "selectedForEditChange", messageAction: "messageActionChange", quickActionClick: "quickActionClickChange", scrollToBottomTrigger: "scrollToBottomTriggerChange", loadHistory: "loadHistoryChange" }, providers: [], viewQueries: [{ propertyName: "chatFlow", first: true, predicate: ChatFlowComponent, descendants: true }, { propertyName: "inputMessage", first: true, predicate: InputMessageComponent, descendants: true }], ngImport: i0, template: "<div class=\"modal-chat\" [ngClass]=\"'flow-theme-' + theme()\">\n <div class=\"modal-chat__body\">\n @if (header()) {\n <header class=\"modal-chat__header\" mat-dialog-title>\n <div class=\"modal-chat__hide-block\"></div>\n\n <div class=\"modal-chat__title\">\n <h1 class=\"modal-chat__heading\" id=\"modal-chat__heading\">\n @if (transportTypeIconSrc()) {\n <img [ngSrc]=\"transportTypeIconSrc()\"\n class=\"modal-chat__heading-icon\"\n width=\"20\"\n height=\"20\"\n [attr.alt]=\"transportType() || 'transport icon'\"/>\n }\n <span class=\"modal-chat__heading-text\">\n {{ transportType() }} {{ incomingUser() }}\n </span>\n </h1>\n </div>\n\n <div class=\"modal-chat__actions\">\n <img ngSrc=\"assets/ngx-parl/icons/hide.svg\" class=\"modal-chat__icon modal-chat__icon--hide\"\n width=\"24\" height=\"24\" alt=\"hide\"\n (click)=\"onHideClick()\"/>\n <img ngSrc=\"assets/ngx-parl/icons/close.svg\" class=\"modal-chat__icon modal-chat__icon--close\"\n width=\"24\" height=\"24\" alt=\"close\"\n (click)=\"onCloseClick()\"/>\n </div>\n </header>\n }\n\n <mat-dialog-content class=\"modal-chat__content\"\n [class.modal-chat__content--header]=\"header() === false\"\n [class.modal-chat__content--dragover]=\"dragActive()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n @if (dragActive()) {\n <div class=\"modal-chat__drag-overlay\"\n role=\"status\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'chat.drag_title' | transloco\">\n <div class=\"modal-chat__drag-card\">\n <img ngSrc=\"assets/ngx-parl/icons/attach-filled.svg\"\n class=\"modal-chat__drag-icon\"\n alt=\"\"\n width=\"56\"\n height=\"56\"/>\n\n <div class=\"modal-chat__drag-title\">\n {{ 'chat.drag_title' | transloco }}\n </div>\n <div class=\"modal-chat__drag-subtitle\">\n {{ 'chat.drag_subtitle' | transloco }}\n </div>\n </div>\n </div>\n }\n <app-chat-flow [messageListInput]=\"messageList()\"\n [(selectedForEdit)]=\"selectedForEdit\"\n (requestDeleteChange)=\"onRequestDelete($event)\"\n [mobileMode]=\"mobileMode()\"\n [quickActionsResolver]=\"quickActionsResolver()\"\n [(quickActionClick)]=\"quickActionClick\"\n [(scrollToBottomTrigger)]=\"scrollToBottomTrigger\"\n [(loadHistory)]=\"loadHistory\">\n </app-chat-flow>\n\n <app-input-message [editMessage]=\"selectedForEdit()\"\n (cancelEditChange)=\"onCancelEdit($event)\"\n (input_textChange)=\"sendMessage($event)\">\n @if (ai_run_in_progress) {\n <mat-spinner [diameter]=\"30\"></mat-spinner>\n }\n </app-input-message>\n </mat-dialog-content>\n </div>\n</div>\n", styles: [".flow-theme-primary ::ng-deep .modal-chat__header{background-color:#5a72d7;color:#fff}.flow-theme-primary ::ng-deep .message--incoming .message__body{background:#e9ecef;color:#343a40}.flow-theme-primary ::ng-deep .message--outgoing .message__body{background:#4656ca;color:#fff}:root{--shadow-sm: 0px 1px 2px 0px rgba(0, 0, 0, .05);--shadow-md: 0px 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0px 8px 24px rgba(0, 0, 0, .12);--shadow-soft: 0px 0px 6px 0px rgba(46, 46, 46, .12) }.flow-theme-secondary ::ng-deep .modal-chat__header{background-color:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--incoming .message__body{background:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--outgoing .message__body{background:#efefef;color:#464646}.modal-chat{width:800px;height:600px;border-radius:16px}.modal-chat__body{display:flex;flex-direction:column;height:100%}.modal-chat__header{height:56px;min-height:56px;max-height:56px;display:flex;align-items:center;justify-content:space-between;padding:0 16px;gap:12px;border-top-left-radius:16px;border-top-right-radius:16px;flex-direction:row}.modal-chat__hide-block{width:48px;color:#5a72d7}.modal-chat__title #modal-chat__heading{color:#fff;font:600 16px/20px inter,sans-serif;display:inline-flex;align-items:center;gap:8px}.modal-chat__heading-icon{width:20px;height:20px;border-radius:1000px;flex:0 0 auto}.modal-chat__actions{display:flex;gap:8px}.modal-chat__content{flex:1 1 auto;display:flex;flex-direction:column;background:#fff;border-bottom-left-radius:16px;border-bottom-right-radius:16px;transition:background-color .16s ease,box-shadow .16s ease;position:relative}.modal-chat__content--header{border-top-left-radius:16px;border-top-right-radius:16px}.modal-chat__content--dragover:after{content:\"\";position:absolute;inset:0;border-radius:inherit;box-shadow:0 0 0 2px #e9ecef inset;background:#fff0;pointer-events:none;z-index:1000}.modal-chat__content app-chat-flow{flex:1 1 auto;min-height:0px;overflow:auto;display:flex;align-items:flex-end}.modal-chat__drag-overlay{position:absolute;inset:16px;display:flex;align-items:center;justify-content:center;border-radius:16px;border:2px dashed #7A95E0;background:#ffffffeb;z-index:1000;pointer-events:none}.modal-chat__drag-card{display:flex;flex-direction:column;align-items:center;gap:8px;padding:20px 24px;border-radius:16px;background:#fff;box-shadow:0 2px 4px #0000001a;text-align:center}.modal-chat__drag-icon{filter:drop-shadow(0 2px 4px rgba(0,0,0,.2))}.modal-chat__drag-title{font:600 20px/24px inter,sans-serif;color:#4656ca}.modal-chat__drag-subtitle{font:400 14px/18px inter,sans-serif;color:#6c757d}.modal-chat__input{flex:0px 0px auto;border-bottom-left-radius:16px;border-bottom-right-radius:16px}:host ::ng-deep .mat-mdc-dialog-content.modal-chat__content{flex:1 1 auto;display:flex;flex-direction:column;padding:0;max-height:none;overflow:hidden}img{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "component", type: MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: ChatFlowComponent, selector: "app-chat-flow", inputs: ["scrollToBottomTrigger", "loadHistory", "messageListInput", "selectedForEdit", "requestDelete", "mobileMode", "quickActionsResolver", "quickActionClick"], outputs: ["scrollToBottomTriggerChange", "loadHistoryChange", "messageListInputChange", "selectedForEditChange", "requestDeleteChange", "quickActionClickChange"] }, { kind: "component", type: InputMessageComponent, selector: "app-input-message", inputs: ["editMessage", "cancelEdit", "input_text", "files", "previews", "messageEvent"], outputs: ["cancelEditChange", "input_textChange", "filesChange", "previewsChange", "messageEventChange"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }] });
|
|
1362
1486
|
}
|
|
1363
1487
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NgxParlComponent, decorators: [{
|
|
1364
1488
|
type: Component,
|
|
@@ -1366,7 +1490,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1366
1490
|
NgOptimizedImage, NgClass, MatDialogContent, MatDialogTitle, MatProgressSpinner, ChatFlowComponent, InputMessageComponent,
|
|
1367
1491
|
TranslocoModule,
|
|
1368
1492
|
TranslocoPipe
|
|
1369
|
-
], providers: [], template: "<div class=\"modal-chat\" [ngClass]=\"'flow-theme-' + theme()\">\n <div class=\"modal-chat__body\">\n @if (header()) {\n <header class=\"modal-chat__header\" mat-dialog-title>\n <div class=\"modal-chat__hide-block\"></div>\n\n <div class=\"modal-chat__title\">\n <h1 class=\"modal-chat__heading\" id=\"modal-chat__heading\">\n @if (transportTypeIconSrc()) {\n <img [ngSrc]=\"transportTypeIconSrc()\"\n class=\"modal-chat__heading-icon\"\n width=\"20\"\n height=\"20\"\n [attr.alt]=\"transportType() || 'transport icon'\"/>\n }\n <span class=\"modal-chat__heading-text\">\n {{ transportType() }} {{ incomingUser() }}\n </span>\n </h1>\n </div>\n\n <div class=\"modal-chat__actions\">\n <img ngSrc=\"assets/ngx-parl/icons/hide.svg\" class=\"modal-chat__icon modal-chat__icon--hide\"\n width=\"24\" height=\"24\" alt=\"hide\"\n (click)=\"onHideClick()\"/>\n <img ngSrc=\"assets/ngx-parl/icons/close.svg\" class=\"modal-chat__icon modal-chat__icon--close\"\n width=\"24\" height=\"24\" alt=\"close\"\n (click)=\"onCloseClick()\"/>\n </div>\n </header>\n }\n\n <mat-dialog-content class=\"modal-chat__content\"\n [class.modal-chat__content--header]=\"header() === false\"\n [class.modal-chat__content--dragover]=\"dragActive()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n @if (dragActive()) {\n <div class=\"modal-chat__drag-overlay\"\n role=\"status\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'chat.drag_title' | transloco\">\n <div class=\"modal-chat__drag-card\">\n <img ngSrc=\"assets/ngx-parl/icons/attach-filled.svg\"\n class=\"modal-chat__drag-icon\"\n alt=\"\"\n width=\"56\"\n height=\"56\"/>\n\n <div class=\"modal-chat__drag-title\">\n {{ 'chat.drag_title' | transloco }}\n </div>\n <div class=\"modal-chat__drag-subtitle\">\n {{ 'chat.drag_subtitle' | transloco }}\n </div>\n </div>\n </div>\n }\n <app-chat-flow [messageListInput]=\"messageList()\"\n [(selectedForEdit)]=\"selectedForEdit\"\n (requestDeleteChange)=\"onRequestDelete($event)\"\n [(scrollToBottomTrigger)]=\"scrollToBottomTrigger\"\n [(loadHistory)]=\"loadHistory\">\n </app-chat-flow>\n\n <app-input-message [editMessage]=\"selectedForEdit()\"\n (cancelEditChange)=\"onCancelEdit($event)\"\n (input_textChange)=\"sendMessage($event)\">\n @if (ai_run_in_progress) {\n <mat-spinner [diameter]=\"30\"></mat-spinner>\n }\n </app-input-message>\n </mat-dialog-content>\n </div>\n</div>\n", styles: [".flow-theme-primary ::ng-deep .modal-chat__header{background-color:#5a72d7;color:#fff}.flow-theme-primary ::ng-deep .message--incoming .message__body{background:#e9ecef;color:#343a40}.flow-theme-primary ::ng-deep .message--outgoing .message__body{background:#4656ca;color:#fff}:root{--shadow-sm: 0px 1px 2px 0px rgba(0, 0, 0, .05);--shadow-md: 0px 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0px 8px 24px rgba(0, 0, 0, .12);--shadow-soft: 0px 0px 6px 0px rgba(46, 46, 46, .12) }.flow-theme-secondary ::ng-deep .modal-chat__header{background-color:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--incoming .message__body{background:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--outgoing .message__body{background:#efefef;color:#464646}.modal-chat{width:800px;height:600px;border-radius:16px}.modal-chat__body{display:flex;flex-direction:column;height:100%}.modal-chat__header{height:56px;min-height:56px;max-height:56px;display:flex;align-items:center;justify-content:space-between;padding:0 16px;gap:12px;border-top-left-radius:16px;border-top-right-radius:16px;flex-direction:row}.modal-chat__hide-block{width:48px;color:#5a72d7}.modal-chat__title #modal-chat__heading{color:#fff;font:600 16px/20px inter,sans-serif;display:inline-flex;align-items:center;gap:8px}.modal-chat__heading-icon{width:20px;height:20px;border-radius:1000px;flex:0 0 auto}.modal-chat__actions{display:flex;gap:8px}.modal-chat__content{flex:1 1 auto;display:flex;flex-direction:column;background:#fff;border-bottom-left-radius:16px;border-bottom-right-radius:16px;transition:background-color .16s ease,box-shadow .16s ease;position:relative}.modal-chat__content--header{border-top-left-radius:16px;border-top-right-radius:16px}.modal-chat__content--dragover:after{content:\"\";position:absolute;inset:0;border-radius:inherit;box-shadow:0 0 0 2px #e9ecef inset;background:#fff0;pointer-events:none;z-index:1000}.modal-chat__content app-chat-flow{flex:1 1 auto;min-height:0px;overflow:auto;display:flex;align-items:flex-end}.modal-chat__drag-overlay{position:absolute;inset:16px;display:flex;align-items:center;justify-content:center;border-radius:16px;border:2px dashed #7A95E0;background:#ffffffeb;z-index:1000;pointer-events:none}.modal-chat__drag-card{display:flex;flex-direction:column;align-items:center;gap:8px;padding:20px 24px;border-radius:16px;background:#fff;box-shadow:0 2px 4px #0000001a;text-align:center}.modal-chat__drag-icon{filter:drop-shadow(0 2px 4px rgba(0,0,0,.2))}.modal-chat__drag-title{font:600 20px/24px inter,sans-serif;color:#4656ca}.modal-chat__drag-subtitle{font:400 14px/18px inter,sans-serif;color:#6c757d}.modal-chat__input{flex:0px 0px auto;border-bottom-left-radius:16px;border-bottom-right-radius:16px}:host ::ng-deep .mat-mdc-dialog-content.modal-chat__content{flex:1 1 auto;display:flex;flex-direction:column;padding:0;max-height:none;overflow:hidden}img{cursor:pointer}\n"] }]
|
|
1493
|
+
], providers: [], template: "<div class=\"modal-chat\" [ngClass]=\"'flow-theme-' + theme()\">\n <div class=\"modal-chat__body\">\n @if (header()) {\n <header class=\"modal-chat__header\" mat-dialog-title>\n <div class=\"modal-chat__hide-block\"></div>\n\n <div class=\"modal-chat__title\">\n <h1 class=\"modal-chat__heading\" id=\"modal-chat__heading\">\n @if (transportTypeIconSrc()) {\n <img [ngSrc]=\"transportTypeIconSrc()\"\n class=\"modal-chat__heading-icon\"\n width=\"20\"\n height=\"20\"\n [attr.alt]=\"transportType() || 'transport icon'\"/>\n }\n <span class=\"modal-chat__heading-text\">\n {{ transportType() }} {{ incomingUser() }}\n </span>\n </h1>\n </div>\n\n <div class=\"modal-chat__actions\">\n <img ngSrc=\"assets/ngx-parl/icons/hide.svg\" class=\"modal-chat__icon modal-chat__icon--hide\"\n width=\"24\" height=\"24\" alt=\"hide\"\n (click)=\"onHideClick()\"/>\n <img ngSrc=\"assets/ngx-parl/icons/close.svg\" class=\"modal-chat__icon modal-chat__icon--close\"\n width=\"24\" height=\"24\" alt=\"close\"\n (click)=\"onCloseClick()\"/>\n </div>\n </header>\n }\n\n <mat-dialog-content class=\"modal-chat__content\"\n [class.modal-chat__content--header]=\"header() === false\"\n [class.modal-chat__content--dragover]=\"dragActive()\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n @if (dragActive()) {\n <div class=\"modal-chat__drag-overlay\"\n role=\"status\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'chat.drag_title' | transloco\">\n <div class=\"modal-chat__drag-card\">\n <img ngSrc=\"assets/ngx-parl/icons/attach-filled.svg\"\n class=\"modal-chat__drag-icon\"\n alt=\"\"\n width=\"56\"\n height=\"56\"/>\n\n <div class=\"modal-chat__drag-title\">\n {{ 'chat.drag_title' | transloco }}\n </div>\n <div class=\"modal-chat__drag-subtitle\">\n {{ 'chat.drag_subtitle' | transloco }}\n </div>\n </div>\n </div>\n }\n <app-chat-flow [messageListInput]=\"messageList()\"\n [(selectedForEdit)]=\"selectedForEdit\"\n (requestDeleteChange)=\"onRequestDelete($event)\"\n [mobileMode]=\"mobileMode()\"\n [quickActionsResolver]=\"quickActionsResolver()\"\n [(quickActionClick)]=\"quickActionClick\"\n [(scrollToBottomTrigger)]=\"scrollToBottomTrigger\"\n [(loadHistory)]=\"loadHistory\">\n </app-chat-flow>\n\n <app-input-message [editMessage]=\"selectedForEdit()\"\n (cancelEditChange)=\"onCancelEdit($event)\"\n (input_textChange)=\"sendMessage($event)\">\n @if (ai_run_in_progress) {\n <mat-spinner [diameter]=\"30\"></mat-spinner>\n }\n </app-input-message>\n </mat-dialog-content>\n </div>\n</div>\n", styles: [".flow-theme-primary ::ng-deep .modal-chat__header{background-color:#5a72d7;color:#fff}.flow-theme-primary ::ng-deep .message--incoming .message__body{background:#e9ecef;color:#343a40}.flow-theme-primary ::ng-deep .message--outgoing .message__body{background:#4656ca;color:#fff}:root{--shadow-sm: 0px 1px 2px 0px rgba(0, 0, 0, .05);--shadow-md: 0px 4px 12px rgba(0, 0, 0, .08);--shadow-lg: 0px 8px 24px rgba(0, 0, 0, .12);--shadow-soft: 0px 0px 6px 0px rgba(46, 46, 46, .12) }.flow-theme-secondary ::ng-deep .modal-chat__header{background-color:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--incoming .message__body{background:#848af5;color:#fefefe}.flow-theme-secondary ::ng-deep .message--outgoing .message__body{background:#efefef;color:#464646}.modal-chat{width:800px;height:600px;border-radius:16px}.modal-chat__body{display:flex;flex-direction:column;height:100%}.modal-chat__header{height:56px;min-height:56px;max-height:56px;display:flex;align-items:center;justify-content:space-between;padding:0 16px;gap:12px;border-top-left-radius:16px;border-top-right-radius:16px;flex-direction:row}.modal-chat__hide-block{width:48px;color:#5a72d7}.modal-chat__title #modal-chat__heading{color:#fff;font:600 16px/20px inter,sans-serif;display:inline-flex;align-items:center;gap:8px}.modal-chat__heading-icon{width:20px;height:20px;border-radius:1000px;flex:0 0 auto}.modal-chat__actions{display:flex;gap:8px}.modal-chat__content{flex:1 1 auto;display:flex;flex-direction:column;background:#fff;border-bottom-left-radius:16px;border-bottom-right-radius:16px;transition:background-color .16s ease,box-shadow .16s ease;position:relative}.modal-chat__content--header{border-top-left-radius:16px;border-top-right-radius:16px}.modal-chat__content--dragover:after{content:\"\";position:absolute;inset:0;border-radius:inherit;box-shadow:0 0 0 2px #e9ecef inset;background:#fff0;pointer-events:none;z-index:1000}.modal-chat__content app-chat-flow{flex:1 1 auto;min-height:0px;overflow:auto;display:flex;align-items:flex-end}.modal-chat__drag-overlay{position:absolute;inset:16px;display:flex;align-items:center;justify-content:center;border-radius:16px;border:2px dashed #7A95E0;background:#ffffffeb;z-index:1000;pointer-events:none}.modal-chat__drag-card{display:flex;flex-direction:column;align-items:center;gap:8px;padding:20px 24px;border-radius:16px;background:#fff;box-shadow:0 2px 4px #0000001a;text-align:center}.modal-chat__drag-icon{filter:drop-shadow(0 2px 4px rgba(0,0,0,.2))}.modal-chat__drag-title{font:600 20px/24px inter,sans-serif;color:#4656ca}.modal-chat__drag-subtitle{font:400 14px/18px inter,sans-serif;color:#6c757d}.modal-chat__input{flex:0px 0px auto;border-bottom-left-radius:16px;border-bottom-right-radius:16px}:host ::ng-deep .mat-mdc-dialog-content.modal-chat__content{flex:1 1 auto;display:flex;flex-direction:column;padding:0;max-height:none;overflow:hidden}img{cursor:pointer}\n"] }]
|
|
1370
1494
|
}], ctorParameters: () => [{ type: UtilsService }, { type: i2.TranslocoService }, { type: i3.MatDialogRef, decorators: [{
|
|
1371
1495
|
type: Optional
|
|
1372
1496
|
}] }], propDecorators: { chatFlow: [{
|
|
@@ -1375,7 +1499,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1375
1499
|
}], inputMessage: [{
|
|
1376
1500
|
type: ViewChild,
|
|
1377
1501
|
args: [InputMessageComponent]
|
|
1378
|
-
}], dragActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragActive", required: false }] }, { type: i0.Output, args: ["dragActiveChange"] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], language: [{ type: i0.Input, args: [{ isSignal: true, alias: "language", required: false }] }], messageList: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageList", required: false }] }, { type: i0.Output, args: ["messageListChange"] }], messageUpdate: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageUpdate", required: false }] }, { type: i0.Output, args: ["messageUpdateChange"] }], selectedForEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedForEdit", required: false }] }, { type: i0.Output, args: ["selectedForEditChange"] }], messageAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageAction", required: false }] }, { type: i0.Output, args: ["messageActionChange"] }], incomingUser: [{ type: i0.Input, args: [{ isSignal: true, alias: "incomingUser", required: false }] }], transportType: [{ type: i0.Input, args: [{ isSignal: true, alias: "transportType", required: false }] }], transportTypeIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "transportTypeIcon", required: false }] }], hideHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideHandler", required: false }] }], closeHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeHandler", required: false }] }], scrollToBottomTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollToBottomTrigger", required: false }] }, { type: i0.Output, args: ["scrollToBottomTriggerChange"] }], loadHistory: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadHistory", required: false }] }, { type: i0.Output, args: ["loadHistoryChange"] }] } });
|
|
1502
|
+
}], dragActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragActive", required: false }] }, { type: i0.Output, args: ["dragActiveChange"] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], language: [{ type: i0.Input, args: [{ isSignal: true, alias: "language", required: false }] }], messageList: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageList", required: false }] }, { type: i0.Output, args: ["messageListChange"] }], messageUpdate: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageUpdate", required: false }] }, { type: i0.Output, args: ["messageUpdateChange"] }], selectedForEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedForEdit", required: false }] }, { type: i0.Output, args: ["selectedForEditChange"] }], messageAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageAction", required: false }] }, { type: i0.Output, args: ["messageActionChange"] }], incomingUser: [{ type: i0.Input, args: [{ isSignal: true, alias: "incomingUser", required: false }] }], transportType: [{ type: i0.Input, args: [{ isSignal: true, alias: "transportType", required: false }] }], transportTypeIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "transportTypeIcon", required: false }] }], mobileMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileMode", required: false }] }], quickActionsResolver: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickActionsResolver", required: false }] }], quickActionClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickActionClick", required: false }] }, { type: i0.Output, args: ["quickActionClickChange"] }], quickActionsAutoSend: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickActionsAutoSend", required: false }] }], hideHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideHandler", required: false }] }], closeHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeHandler", required: false }] }], scrollToBottomTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollToBottomTrigger", required: false }] }, { type: i0.Output, args: ["scrollToBottomTriggerChange"] }], loadHistory: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadHistory", required: false }] }, { type: i0.Output, args: ["loadHistoryChange"] }] } });
|
|
1379
1503
|
|
|
1380
1504
|
var chat$1 = {
|
|
1381
1505
|
title: "Telegram",
|
|
@@ -1390,6 +1514,8 @@ var chat$1 = {
|
|
|
1390
1514
|
video: "Video",
|
|
1391
1515
|
edit: "Edit",
|
|
1392
1516
|
remove: "Delete",
|
|
1517
|
+
cancel: "Cancel",
|
|
1518
|
+
delete_message_title: "Delete this message?",
|
|
1393
1519
|
chat_empty_title: "No messages",
|
|
1394
1520
|
chat_empty_subscription: "Your chat history will be displayed here. Write your first message to get started!",
|
|
1395
1521
|
photo_preview: "Photo preview",
|
|
@@ -1417,6 +1543,8 @@ var chat = {
|
|
|
1417
1543
|
video: "Відео",
|
|
1418
1544
|
edit: "Редагувати",
|
|
1419
1545
|
remove: "Видалити",
|
|
1546
|
+
cancel: "Скасувати",
|
|
1547
|
+
delete_message_title: "Видалити це повідомлення?",
|
|
1420
1548
|
chat_empty_title: "Повідомлень ще немає",
|
|
1421
1549
|
chat_empty_subscription: "Тут буде відображатись ваша історія спілкування. Напишіть перше повідомлення, щоб почати!",
|
|
1422
1550
|
photo_preview: "Перегляд фото",
|
|
@@ -1464,5 +1592,5 @@ function provideNgxParl() {
|
|
|
1464
1592
|
* Generated bundle index. Do not edit.
|
|
1465
1593
|
*/
|
|
1466
1594
|
|
|
1467
|
-
export { NgxParlComponent, provideNgxParl };
|
|
1595
|
+
export { ChatMessage, MessageType, NgxParlComponent, provideNgxParl };
|
|
1468
1596
|
//# sourceMappingURL=trixwell-ngx-parl.mjs.map
|