valtech-components 4.0.231 → 4.0.234
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/esm2022/lib/components/molecules/chat-composer/chat-composer.component.mjs +300 -107
- package/esm2022/lib/components/molecules/message-bubble/message-bubble.component.mjs +19 -4
- package/esm2022/lib/components/organisms/chat-window/chat-window.component.mjs +5 -8
- package/esm2022/lib/components/organisms/thread-panel/thread-panel.component.mjs +6 -4
- package/esm2022/lib/services/chat/conversation.service.mjs +15 -4
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +2 -2
- package/fesm2022/valtech-components.mjs +340 -122
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/molecules/chat-composer/chat-composer.component.d.ts +44 -15
- package/lib/components/molecules/message-bubble/message-bubble.component.d.ts +1 -0
- package/lib/components/organisms/chat-window/chat-window.component.d.ts +4 -4
- package/lib/components/organisms/thread-panel/thread-panel.component.d.ts +4 -1
- package/lib/services/chat/conversation.service.d.ts +5 -3
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +1 -1
|
@@ -56,7 +56,7 @@ import { BrowserMultiFormatReader } from '@zxing/browser';
|
|
|
56
56
|
* Current version of valtech-components.
|
|
57
57
|
* This is automatically updated during the publish process.
|
|
58
58
|
*/
|
|
59
|
-
const VERSION = '4.0.
|
|
59
|
+
const VERSION = '4.0.234';
|
|
60
60
|
|
|
61
61
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
62
62
|
let isRefreshing = false;
|
|
@@ -72209,10 +72209,21 @@ class ConversationService {
|
|
|
72209
72209
|
return this.http.delete(`${this.baseUrl}/conversations/${convId}/participants/${userId}`);
|
|
72210
72210
|
}
|
|
72211
72211
|
/**
|
|
72212
|
-
* Envia un mensaje a una conversacion.
|
|
72212
|
+
* Envia un mensaje a una conversacion, opcionalmente con adjuntos.
|
|
72213
|
+
* El backend espera `attachments: { url, type, name, size }[]` (key `type` = MIME),
|
|
72214
|
+
* mientras que el front usa `mimeType` — se mapea aqui.
|
|
72213
72215
|
*/
|
|
72214
|
-
sendMessage(convId, body) {
|
|
72215
|
-
|
|
72216
|
+
sendMessage(convId, body, attachments) {
|
|
72217
|
+
const payload = { body };
|
|
72218
|
+
if (attachments?.length) {
|
|
72219
|
+
payload['attachments'] = attachments.map(a => ({
|
|
72220
|
+
url: a.url,
|
|
72221
|
+
type: a.mimeType,
|
|
72222
|
+
name: a.name,
|
|
72223
|
+
size: a.size ?? 0,
|
|
72224
|
+
}));
|
|
72225
|
+
}
|
|
72226
|
+
return this.http.post(`${this.baseUrl}/conversations/${convId}/messages`, payload);
|
|
72216
72227
|
}
|
|
72217
72228
|
/**
|
|
72218
72229
|
* Elimina (marca como eliminado) un mensaje.
|
|
@@ -72439,7 +72450,8 @@ class MessageBubbleComponent {
|
|
|
72439
72450
|
return (parts[0][0] + (parts[1]?.[0] ?? '')).toUpperCase();
|
|
72440
72451
|
});
|
|
72441
72452
|
this.imageAttachments = computed(() => (this.msg().attachments ?? []).filter(a => a.mimeType?.startsWith('image/')));
|
|
72442
|
-
this.
|
|
72453
|
+
this.audioAttachments = computed(() => (this.msg().attachments ?? []).filter(a => a.mimeType?.startsWith('audio/')));
|
|
72454
|
+
this.fileAttachments = computed(() => (this.msg().attachments ?? []).filter(a => !a.mimeType?.startsWith('image/') && !a.mimeType?.startsWith('audio/')));
|
|
72443
72455
|
this.statusIcon = computed(() => {
|
|
72444
72456
|
switch (this.msg().status) {
|
|
72445
72457
|
case 'sending':
|
|
@@ -72510,6 +72522,13 @@ class MessageBubbleComponent {
|
|
|
72510
72522
|
}
|
|
72511
72523
|
</div>
|
|
72512
72524
|
}
|
|
72525
|
+
@if (audioAttachments().length > 0) {
|
|
72526
|
+
<div class="audios">
|
|
72527
|
+
@for (att of audioAttachments(); track att.url) {
|
|
72528
|
+
<audio class="att-audio" controls preload="metadata" [src]="att.url"></audio>
|
|
72529
|
+
}
|
|
72530
|
+
</div>
|
|
72531
|
+
}
|
|
72513
72532
|
@if (fileAttachments().length > 0) {
|
|
72514
72533
|
<div class="files">
|
|
72515
72534
|
@for (att of fileAttachments(); track att.url) {
|
|
@@ -72573,7 +72592,7 @@ class MessageBubbleComponent {
|
|
|
72573
72592
|
}
|
|
72574
72593
|
</div>
|
|
72575
72594
|
</div>
|
|
72576
|
-
`, isInline: true, styles: [":host{display:block}.row{display:flex;align-items:flex-end;gap:8px;margin:1px 0}.row.mine{flex-direction:row-reverse}.row.tail{margin-bottom:8px}.avatar{width:28px;height:28px;border-radius:50%;overflow:hidden;flex-shrink:0;display:flex;align-items:center;justify-content:center;background:var(--ion-color-primary);color:#fff;font-size:.6875rem;font-weight:700}.avatar.hidden{visibility:hidden}.avatar img{width:100%;height:100%;object-fit:cover}.bubble-wrap{position:relative;max-width:min(78%,520px);display:flex;flex-direction:column}.row.mine .bubble-wrap{align-items:flex-end}.bubble{position:relative;padding:7px 11px;border-radius:16px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08));color:var(--ion-text-color, #000);font-size:.9375rem;line-height:1.35;cursor:pointer;outline:none;word-break:break-word}.row:not(.mine).tail .bubble{border-bottom-left-radius:5px}.mine .bubble{background:var(--ion-color-primary);border-color:var(--ion-color-primary);color:var(--ion-color-primary-contrast, #fff)}.mine.tail .bubble{border-bottom-right-radius:5px}.bubble.deleted{background:transparent;border-style:dashed;cursor:default}.name{display:block;font-size:.75rem;font-weight:700;color:var(--ion-color-primary);margin-bottom:2px}.reply-preview{display:flex;flex-direction:column;gap:1px;padding:4px 8px;margin-bottom:4px;border-left:3px solid currentColor;border-radius:6px;background:var(--ion-color-step-100, rgba(127, 127, 127, .12));font-size:.8125rem;opacity:.85}.reply-name{font-weight:700}.reply-body{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:240px}.body{white-space:pre-wrap}.deleted-text{font-style:italic;opacity:.6}.attachments{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.att-image{max-width:100%;border-radius:10px;display:block}.files{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.file-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:8px;background:var(--ion-color-step-100, rgba(127, 127, 127, .12));color:inherit;text-decoration:none;font-size:.8125rem}.meta{display:inline-flex;align-items:center;gap:4px;float:right;margin:2px 0 -2px 8px;font-size:.6875rem;opacity:.7}.edited{font-style:italic}.status{font-size:.875rem}.status.read{color:var(--ion-color-secondary, #4fc3f7);opacity:1}.status.failed{color:var(--ion-color-danger, #eb445a);opacity:1}.reactions{display:flex;flex-wrap:wrap;gap:4px;margin-top:3px}.reaction{display:inline-flex;align-items:center;gap:3px;padding:1px 7px;border-radius:999px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-card-background, var(--ion-background-color, #fff));font-size:.75rem;cursor:pointer;color:var(--ion-text-color, #000)}.reaction.active{border-color:var(--ion-color-primary);background:var(--ion-color-primary-tint, var(--ion-color-primary));color:var(--ion-color-primary-contrast, #fff)}.reaction .count{opacity:.75}.actions{position:absolute;top:-14px;display:flex;gap:2px;padding:2px;border-radius:999px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));box-shadow:0 2px 8px #0000001f;opacity:0;pointer-events:none;transition:opacity .12s ease;z-index:2}.row.mine .actions{right:0}.row:not(.mine) .actions{left:0}.bubble-wrap:hover .actions,.actions.open{opacity:1;pointer-events:auto}.act{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;border-radius:50%;background:transparent;color:var(--ion-color-medium, #92949c);cursor:pointer;font-size:1rem}.act:hover{background:var(--ion-color-step-100, rgba(127, 127, 127, .12));color:var(--ion-text-color, #000)}.act.danger:hover{color:var(--ion-color-danger, #eb445a)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
|
|
72595
|
+
`, isInline: true, styles: [":host{display:block}.row{display:flex;align-items:flex-end;gap:8px;margin:1px 0}.row.mine{flex-direction:row-reverse}.row.tail{margin-bottom:8px}.avatar{width:28px;height:28px;border-radius:50%;overflow:hidden;flex-shrink:0;display:flex;align-items:center;justify-content:center;background:var(--ion-color-primary);color:#fff;font-size:.6875rem;font-weight:700}.avatar.hidden{visibility:hidden}.avatar img{width:100%;height:100%;object-fit:cover}.bubble-wrap{position:relative;max-width:min(78%,520px);display:flex;flex-direction:column}.row.mine .bubble-wrap{align-items:flex-end}.bubble{position:relative;padding:7px 11px;border-radius:16px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08));color:var(--ion-text-color, #000);font-size:.9375rem;line-height:1.35;cursor:pointer;outline:none;word-break:break-word}.row:not(.mine).tail .bubble{border-bottom-left-radius:5px}.mine .bubble{background:var(--ion-color-primary);border-color:var(--ion-color-primary);color:var(--ion-color-primary-contrast, #fff)}.mine.tail .bubble{border-bottom-right-radius:5px}.bubble.deleted{background:transparent;border-style:dashed;cursor:default}.name{display:block;font-size:.75rem;font-weight:700;color:var(--ion-color-primary);margin-bottom:2px}.reply-preview{display:flex;flex-direction:column;gap:1px;padding:4px 8px;margin-bottom:4px;border-left:3px solid currentColor;border-radius:6px;background:var(--ion-color-step-100, rgba(127, 127, 127, .12));font-size:.8125rem;opacity:.85}.reply-name{font-weight:700}.reply-body{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:240px}.body{white-space:pre-wrap}.deleted-text{font-style:italic;opacity:.6}.attachments{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.att-image{max-width:100%;border-radius:10px;display:block}.audios{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.att-audio{width:240px;max-width:100%;height:40px}.files{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.file-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:8px;background:var(--ion-color-step-100, rgba(127, 127, 127, .12));color:inherit;text-decoration:none;font-size:.8125rem}.meta{display:inline-flex;align-items:center;gap:4px;float:right;margin:2px 0 -2px 8px;font-size:.6875rem;opacity:.7}.edited{font-style:italic}.status{font-size:.875rem}.status.read{color:var(--ion-color-secondary, #4fc3f7);opacity:1}.status.failed{color:var(--ion-color-danger, #eb445a);opacity:1}.reactions{display:flex;flex-wrap:wrap;gap:4px;margin-top:3px}.reaction{display:inline-flex;align-items:center;gap:3px;padding:1px 7px;border-radius:999px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-card-background, var(--ion-background-color, #fff));font-size:.75rem;cursor:pointer;color:var(--ion-text-color, #000)}.reaction.active{border-color:var(--ion-color-primary);background:var(--ion-color-primary-tint, var(--ion-color-primary));color:var(--ion-color-primary-contrast, #fff)}.reaction .count{opacity:.75}.actions{position:absolute;top:-14px;display:flex;gap:2px;padding:2px;border-radius:999px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));box-shadow:0 2px 8px #0000001f;opacity:0;pointer-events:none;transition:opacity .12s ease;z-index:2}.row.mine .actions{right:0}.row:not(.mine) .actions{left:0}.bubble-wrap:hover .actions,.actions.open{opacity:1;pointer-events:auto}.act{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;border-radius:50%;background:transparent;color:var(--ion-color-medium, #92949c);cursor:pointer;font-size:1rem}.act:hover{background:var(--ion-color-step-100, rgba(127, 127, 127, .12));color:var(--ion-text-color, #000)}.act.danger:hover{color:var(--ion-color-danger, #eb445a)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
|
|
72577
72596
|
}
|
|
72578
72597
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MessageBubbleComponent, decorators: [{
|
|
72579
72598
|
type: Component,
|
|
@@ -72618,6 +72637,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
72618
72637
|
}
|
|
72619
72638
|
</div>
|
|
72620
72639
|
}
|
|
72640
|
+
@if (audioAttachments().length > 0) {
|
|
72641
|
+
<div class="audios">
|
|
72642
|
+
@for (att of audioAttachments(); track att.url) {
|
|
72643
|
+
<audio class="att-audio" controls preload="metadata" [src]="att.url"></audio>
|
|
72644
|
+
}
|
|
72645
|
+
</div>
|
|
72646
|
+
}
|
|
72621
72647
|
@if (fileAttachments().length > 0) {
|
|
72622
72648
|
<div class="files">
|
|
72623
72649
|
@for (att of fileAttachments(); track att.url) {
|
|
@@ -72681,7 +72707,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
72681
72707
|
}
|
|
72682
72708
|
</div>
|
|
72683
72709
|
</div>
|
|
72684
|
-
`, styles: [":host{display:block}.row{display:flex;align-items:flex-end;gap:8px;margin:1px 0}.row.mine{flex-direction:row-reverse}.row.tail{margin-bottom:8px}.avatar{width:28px;height:28px;border-radius:50%;overflow:hidden;flex-shrink:0;display:flex;align-items:center;justify-content:center;background:var(--ion-color-primary);color:#fff;font-size:.6875rem;font-weight:700}.avatar.hidden{visibility:hidden}.avatar img{width:100%;height:100%;object-fit:cover}.bubble-wrap{position:relative;max-width:min(78%,520px);display:flex;flex-direction:column}.row.mine .bubble-wrap{align-items:flex-end}.bubble{position:relative;padding:7px 11px;border-radius:16px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08));color:var(--ion-text-color, #000);font-size:.9375rem;line-height:1.35;cursor:pointer;outline:none;word-break:break-word}.row:not(.mine).tail .bubble{border-bottom-left-radius:5px}.mine .bubble{background:var(--ion-color-primary);border-color:var(--ion-color-primary);color:var(--ion-color-primary-contrast, #fff)}.mine.tail .bubble{border-bottom-right-radius:5px}.bubble.deleted{background:transparent;border-style:dashed;cursor:default}.name{display:block;font-size:.75rem;font-weight:700;color:var(--ion-color-primary);margin-bottom:2px}.reply-preview{display:flex;flex-direction:column;gap:1px;padding:4px 8px;margin-bottom:4px;border-left:3px solid currentColor;border-radius:6px;background:var(--ion-color-step-100, rgba(127, 127, 127, .12));font-size:.8125rem;opacity:.85}.reply-name{font-weight:700}.reply-body{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:240px}.body{white-space:pre-wrap}.deleted-text{font-style:italic;opacity:.6}.attachments{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.att-image{max-width:100%;border-radius:10px;display:block}.files{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.file-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:8px;background:var(--ion-color-step-100, rgba(127, 127, 127, .12));color:inherit;text-decoration:none;font-size:.8125rem}.meta{display:inline-flex;align-items:center;gap:4px;float:right;margin:2px 0 -2px 8px;font-size:.6875rem;opacity:.7}.edited{font-style:italic}.status{font-size:.875rem}.status.read{color:var(--ion-color-secondary, #4fc3f7);opacity:1}.status.failed{color:var(--ion-color-danger, #eb445a);opacity:1}.reactions{display:flex;flex-wrap:wrap;gap:4px;margin-top:3px}.reaction{display:inline-flex;align-items:center;gap:3px;padding:1px 7px;border-radius:999px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-card-background, var(--ion-background-color, #fff));font-size:.75rem;cursor:pointer;color:var(--ion-text-color, #000)}.reaction.active{border-color:var(--ion-color-primary);background:var(--ion-color-primary-tint, var(--ion-color-primary));color:var(--ion-color-primary-contrast, #fff)}.reaction .count{opacity:.75}.actions{position:absolute;top:-14px;display:flex;gap:2px;padding:2px;border-radius:999px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));box-shadow:0 2px 8px #0000001f;opacity:0;pointer-events:none;transition:opacity .12s ease;z-index:2}.row.mine .actions{right:0}.row:not(.mine) .actions{left:0}.bubble-wrap:hover .actions,.actions.open{opacity:1;pointer-events:auto}.act{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;border-radius:50%;background:transparent;color:var(--ion-color-medium, #92949c);cursor:pointer;font-size:1rem}.act:hover{background:var(--ion-color-step-100, rgba(127, 127, 127, .12));color:var(--ion-text-color, #000)}.act.danger:hover{color:var(--ion-color-danger, #eb445a)}\n"] }]
|
|
72710
|
+
`, styles: [":host{display:block}.row{display:flex;align-items:flex-end;gap:8px;margin:1px 0}.row.mine{flex-direction:row-reverse}.row.tail{margin-bottom:8px}.avatar{width:28px;height:28px;border-radius:50%;overflow:hidden;flex-shrink:0;display:flex;align-items:center;justify-content:center;background:var(--ion-color-primary);color:#fff;font-size:.6875rem;font-weight:700}.avatar.hidden{visibility:hidden}.avatar img{width:100%;height:100%;object-fit:cover}.bubble-wrap{position:relative;max-width:min(78%,520px);display:flex;flex-direction:column}.row.mine .bubble-wrap{align-items:flex-end}.bubble{position:relative;padding:7px 11px;border-radius:16px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08));color:var(--ion-text-color, #000);font-size:.9375rem;line-height:1.35;cursor:pointer;outline:none;word-break:break-word}.row:not(.mine).tail .bubble{border-bottom-left-radius:5px}.mine .bubble{background:var(--ion-color-primary);border-color:var(--ion-color-primary);color:var(--ion-color-primary-contrast, #fff)}.mine.tail .bubble{border-bottom-right-radius:5px}.bubble.deleted{background:transparent;border-style:dashed;cursor:default}.name{display:block;font-size:.75rem;font-weight:700;color:var(--ion-color-primary);margin-bottom:2px}.reply-preview{display:flex;flex-direction:column;gap:1px;padding:4px 8px;margin-bottom:4px;border-left:3px solid currentColor;border-radius:6px;background:var(--ion-color-step-100, rgba(127, 127, 127, .12));font-size:.8125rem;opacity:.85}.reply-name{font-weight:700}.reply-body{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:240px}.body{white-space:pre-wrap}.deleted-text{font-style:italic;opacity:.6}.attachments{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.att-image{max-width:100%;border-radius:10px;display:block}.audios{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.att-audio{width:240px;max-width:100%;height:40px}.files{display:flex;flex-direction:column;gap:4px;margin-bottom:4px}.file-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:8px;background:var(--ion-color-step-100, rgba(127, 127, 127, .12));color:inherit;text-decoration:none;font-size:.8125rem}.meta{display:inline-flex;align-items:center;gap:4px;float:right;margin:2px 0 -2px 8px;font-size:.6875rem;opacity:.7}.edited{font-style:italic}.status{font-size:.875rem}.status.read{color:var(--ion-color-secondary, #4fc3f7);opacity:1}.status.failed{color:var(--ion-color-danger, #eb445a);opacity:1}.reactions{display:flex;flex-wrap:wrap;gap:4px;margin-top:3px}.reaction{display:inline-flex;align-items:center;gap:3px;padding:1px 7px;border-radius:999px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-card-background, var(--ion-background-color, #fff));font-size:.75rem;cursor:pointer;color:var(--ion-text-color, #000)}.reaction.active{border-color:var(--ion-color-primary);background:var(--ion-color-primary-tint, var(--ion-color-primary));color:var(--ion-color-primary-contrast, #fff)}.reaction .count{opacity:.75}.actions{position:absolute;top:-14px;display:flex;gap:2px;padding:2px;border-radius:999px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));box-shadow:0 2px 8px #0000001f;opacity:0;pointer-events:none;transition:opacity .12s ease;z-index:2}.row.mine .actions{right:0}.row:not(.mine) .actions{left:0}.bubble-wrap:hover .actions,.actions.open{opacity:1;pointer-events:auto}.act{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;border-radius:50%;background:transparent;color:var(--ion-color-medium, #92949c);cursor:pointer;font-size:1rem}.act:hover{background:var(--ion-color-step-100, rgba(127, 127, 127, .12));color:var(--ion-text-color, #000)}.act.danger:hover{color:var(--ion-color-danger, #eb445a)}\n"] }]
|
|
72685
72711
|
}], ctorParameters: () => [] });
|
|
72686
72712
|
|
|
72687
72713
|
addIcons({ sendOutline });
|
|
@@ -72834,35 +72860,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
72834
72860
|
type: Output
|
|
72835
72861
|
}] } });
|
|
72836
72862
|
|
|
72837
|
-
addIcons({ addOutline, closeOutline,
|
|
72863
|
+
addIcons({ addOutline, checkmarkOutline, closeOutline, documentOutline, micOutline, arrowUpOutline, trashOutline });
|
|
72838
72864
|
const CHAT_COMPOSER_I18N = {
|
|
72839
72865
|
es: {
|
|
72840
72866
|
placeholder: 'Escribe un mensaje',
|
|
72841
72867
|
send: 'Enviar',
|
|
72842
72868
|
attach: 'Adjuntar',
|
|
72843
|
-
emoji: 'Emoji',
|
|
72844
72869
|
voice: 'Mensaje de voz',
|
|
72870
|
+
done: 'Listo',
|
|
72845
72871
|
replyingTo: 'Respondiendo a',
|
|
72846
72872
|
cancel: 'Cancelar',
|
|
72873
|
+
remove: 'Quitar',
|
|
72847
72874
|
},
|
|
72848
72875
|
en: {
|
|
72849
72876
|
placeholder: 'Write a message',
|
|
72850
72877
|
send: 'Send',
|
|
72851
72878
|
attach: 'Attach',
|
|
72852
|
-
emoji: 'Emoji',
|
|
72853
72879
|
voice: 'Voice message',
|
|
72880
|
+
done: 'Done',
|
|
72854
72881
|
replyingTo: 'Replying to',
|
|
72855
72882
|
cancel: 'Cancel',
|
|
72883
|
+
remove: 'Remove',
|
|
72856
72884
|
},
|
|
72857
72885
|
};
|
|
72858
|
-
const QUICK_EMOJIS = ['👍', '❤️', '😂', '🎉', '🙏', '🔥', '😮', '😢'];
|
|
72859
72886
|
/**
|
|
72860
72887
|
* val-chat-composer — barra de redacción de chat moderna (signal inputs).
|
|
72861
72888
|
*
|
|
72862
|
-
* Pill con: adjuntar (+), textarea auto-grow,
|
|
72863
|
-
*
|
|
72864
|
-
*
|
|
72865
|
-
*
|
|
72889
|
+
* Pill con: adjuntar (+), textarea auto-grow, y mic/enviar (mic cuando está vacío,
|
|
72890
|
+
* enviar cuando hay texto o adjuntos). Los adjuntos (botón + / pegar imagen) se
|
|
72891
|
+
* acumulan como PREVIEW (miniaturas) y se emiten por `(attach)` recién al ENVIAR
|
|
72892
|
+
* — no se van solos al chat. Audio grabado se emite directo al parar.
|
|
72893
|
+
* No incluye picker de emoji: el teclado del sistema ya lo trae.
|
|
72866
72894
|
*/
|
|
72867
72895
|
class ChatComposerComponent {
|
|
72868
72896
|
constructor() {
|
|
@@ -72872,20 +72900,30 @@ class ChatComposerComponent {
|
|
|
72872
72900
|
this.maxLength = input(2000);
|
|
72873
72901
|
this.replyingTo = input(null);
|
|
72874
72902
|
this.showAttach = input(true);
|
|
72875
|
-
this.showEmoji = input(true);
|
|
72876
72903
|
this.showMic = input(true);
|
|
72877
72904
|
this.send = output();
|
|
72878
72905
|
this.typing = output();
|
|
72879
|
-
this.attach = output();
|
|
72880
72906
|
this.voice = output();
|
|
72881
72907
|
this.cancelReply = output();
|
|
72882
72908
|
this.body = signal('');
|
|
72883
|
-
this.
|
|
72884
|
-
this.
|
|
72909
|
+
this.pending = signal([]);
|
|
72910
|
+
this.pendingId = 0;
|
|
72911
|
+
// Grabación de audio (MediaRecorder).
|
|
72912
|
+
this.recording = signal(false);
|
|
72913
|
+
this.recSeconds = signal(0);
|
|
72914
|
+
this.recChunks = [];
|
|
72915
|
+
this.recTimeLabel = computed(() => {
|
|
72916
|
+
const s = this.recSeconds();
|
|
72917
|
+
const mm = String(Math.floor(s / 60)).padStart(2, '0');
|
|
72918
|
+
const ss = String(s % 60).padStart(2, '0');
|
|
72919
|
+
return `${mm}:${ss}`;
|
|
72920
|
+
});
|
|
72885
72921
|
this.lastTypingEmit = 0;
|
|
72886
72922
|
this.canSend = computed(() => {
|
|
72887
72923
|
const t = this.body().trim();
|
|
72888
|
-
|
|
72924
|
+
if (this.disabled())
|
|
72925
|
+
return false;
|
|
72926
|
+
return (t.length > 0 && t.length <= this.maxLength()) || this.pending().length > 0;
|
|
72889
72927
|
});
|
|
72890
72928
|
this.placeholderText = computed(() => {
|
|
72891
72929
|
this.i18n.lang();
|
|
@@ -72905,29 +72943,62 @@ class ChatComposerComponent {
|
|
|
72905
72943
|
}
|
|
72906
72944
|
}
|
|
72907
72945
|
onSend() {
|
|
72908
|
-
|
|
72909
|
-
if (!trimmed || trimmed.length > this.maxLength())
|
|
72946
|
+
if (!this.canSend())
|
|
72910
72947
|
return;
|
|
72911
|
-
|
|
72948
|
+
// Un solo evento: texto (caption) + todos los adjuntos staged. El consumer
|
|
72949
|
+
// los sube y manda como UN mensaje con body + attachments.
|
|
72950
|
+
const files = this.pending().map(p => p.file);
|
|
72951
|
+
const text = this.body().trim();
|
|
72952
|
+
this.send.emit({ text, files });
|
|
72953
|
+
for (const att of this.pending()) {
|
|
72954
|
+
if (att.url)
|
|
72955
|
+
URL.revokeObjectURL(att.url);
|
|
72956
|
+
}
|
|
72957
|
+
this.pending.set([]);
|
|
72912
72958
|
this.body.set('');
|
|
72913
|
-
this.emojiOpen.set(false);
|
|
72914
|
-
}
|
|
72915
|
-
toggleEmoji() {
|
|
72916
|
-
this.emojiOpen.update(v => !v);
|
|
72917
|
-
}
|
|
72918
|
-
insertEmoji(emoji) {
|
|
72919
|
-
this.body.update(v => v + emoji);
|
|
72920
72959
|
}
|
|
72921
72960
|
onFile(event) {
|
|
72922
72961
|
const input = event.target;
|
|
72923
72962
|
const file = input.files?.[0];
|
|
72924
72963
|
if (file)
|
|
72925
|
-
this.
|
|
72964
|
+
this.addPending(file);
|
|
72926
72965
|
input.value = '';
|
|
72927
72966
|
}
|
|
72967
|
+
/** Pegar imagen desde el portapapeles (captura de pantalla, copiar imagen). */
|
|
72968
|
+
onPaste(event) {
|
|
72969
|
+
const items = event.clipboardData?.items;
|
|
72970
|
+
if (!items)
|
|
72971
|
+
return;
|
|
72972
|
+
for (const item of Array.from(items)) {
|
|
72973
|
+
if (item.type.startsWith('image/')) {
|
|
72974
|
+
const file = item.getAsFile();
|
|
72975
|
+
if (file) {
|
|
72976
|
+
event.preventDefault();
|
|
72977
|
+
this.addPending(file);
|
|
72978
|
+
}
|
|
72979
|
+
return;
|
|
72980
|
+
}
|
|
72981
|
+
}
|
|
72982
|
+
}
|
|
72983
|
+
addPending(file) {
|
|
72984
|
+
const kind = file.type.startsWith('image/')
|
|
72985
|
+
? 'image'
|
|
72986
|
+
: file.type.startsWith('audio/')
|
|
72987
|
+
? 'audio'
|
|
72988
|
+
: 'file';
|
|
72989
|
+
const url = kind === 'file' ? undefined : URL.createObjectURL(file);
|
|
72990
|
+
this.pending.update(arr => [...arr, { id: this.pendingId++, file, url, kind }]);
|
|
72991
|
+
}
|
|
72992
|
+
removePending(id) {
|
|
72993
|
+
this.pending.update(arr => {
|
|
72994
|
+
const found = arr.find(a => a.id === id);
|
|
72995
|
+
if (found?.url)
|
|
72996
|
+
URL.revokeObjectURL(found.url);
|
|
72997
|
+
return arr.filter(a => a.id !== id);
|
|
72998
|
+
});
|
|
72999
|
+
}
|
|
72928
73000
|
/**
|
|
72929
|
-
* Emite typing como máximo 1 vez cada 2s.
|
|
72930
|
-
* de workflow; aquí estamos en runtime de navegador, performance.now es seguro.
|
|
73001
|
+
* Emite typing como máximo 1 vez cada 2s. performance.now es seguro en runtime.
|
|
72931
73002
|
*/
|
|
72932
73003
|
emitTypingDebounced() {
|
|
72933
73004
|
const now = performance.now();
|
|
@@ -72936,11 +73007,95 @@ class ChatComposerComponent {
|
|
|
72936
73007
|
this.typing.emit();
|
|
72937
73008
|
}
|
|
72938
73009
|
}
|
|
73010
|
+
// ─── Grabación de audio ───────────────────────────────────────────────────
|
|
73011
|
+
/** Selecciona un mimeType de audio soportado por el navegador. */
|
|
73012
|
+
pickAudioMime() {
|
|
73013
|
+
const candidates = ['audio/webm;codecs=opus', 'audio/webm', 'audio/mp4'];
|
|
73014
|
+
const MR = window.MediaRecorder;
|
|
73015
|
+
if (!MR?.isTypeSupported)
|
|
73016
|
+
return '';
|
|
73017
|
+
return candidates.find(c => MR.isTypeSupported(c)) ?? '';
|
|
73018
|
+
}
|
|
73019
|
+
async startRecording() {
|
|
73020
|
+
if (this.recording())
|
|
73021
|
+
return;
|
|
73022
|
+
if (!navigator.mediaDevices?.getUserMedia || !('MediaRecorder' in window)) {
|
|
73023
|
+
this.voice.emit(); // sin soporte: deja que el consumer decida (fallback)
|
|
73024
|
+
return;
|
|
73025
|
+
}
|
|
73026
|
+
try {
|
|
73027
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
73028
|
+
this.recStream = stream;
|
|
73029
|
+
const mimeType = this.pickAudioMime();
|
|
73030
|
+
this.recorder = new MediaRecorder(stream, mimeType ? { mimeType } : undefined);
|
|
73031
|
+
this.recChunks = [];
|
|
73032
|
+
this.recorder.ondataavailable = e => {
|
|
73033
|
+
if (e.data.size > 0)
|
|
73034
|
+
this.recChunks.push(e.data);
|
|
73035
|
+
};
|
|
73036
|
+
this.recorder.start();
|
|
73037
|
+
this.recording.set(true);
|
|
73038
|
+
this.recSeconds.set(0);
|
|
73039
|
+
this.recTimer = setInterval(() => this.recSeconds.update(s => s + 1), 1000);
|
|
73040
|
+
}
|
|
73041
|
+
catch {
|
|
73042
|
+
this.cleanupRecording();
|
|
73043
|
+
}
|
|
73044
|
+
}
|
|
73045
|
+
/** Para la grabación y la stagea como adjunto pendiente (con preview de audio). */
|
|
73046
|
+
finishRecording() {
|
|
73047
|
+
const rec = this.recorder;
|
|
73048
|
+
if (!rec) {
|
|
73049
|
+
this.cleanupRecording();
|
|
73050
|
+
return;
|
|
73051
|
+
}
|
|
73052
|
+
rec.onstop = () => {
|
|
73053
|
+
const type = rec.mimeType || 'audio/webm';
|
|
73054
|
+
const blob = new Blob(this.recChunks, { type });
|
|
73055
|
+
const ext = type.includes('mp4') ? 'm4a' : 'webm';
|
|
73056
|
+
const file = new File([blob], `audio-${this.recSeconds()}s.${ext}`, { type });
|
|
73057
|
+
if (blob.size > 0)
|
|
73058
|
+
this.addPending(file);
|
|
73059
|
+
this.cleanupRecording();
|
|
73060
|
+
};
|
|
73061
|
+
rec.stop();
|
|
73062
|
+
}
|
|
73063
|
+
cancelRecording() {
|
|
73064
|
+
const rec = this.recorder;
|
|
73065
|
+
if (rec)
|
|
73066
|
+
rec.onstop = () => this.cleanupRecording();
|
|
73067
|
+
try {
|
|
73068
|
+
rec?.stop();
|
|
73069
|
+
}
|
|
73070
|
+
catch {
|
|
73071
|
+
this.cleanupRecording();
|
|
73072
|
+
}
|
|
73073
|
+
if (!rec)
|
|
73074
|
+
this.cleanupRecording();
|
|
73075
|
+
}
|
|
73076
|
+
cleanupRecording() {
|
|
73077
|
+
if (this.recTimer)
|
|
73078
|
+
clearInterval(this.recTimer);
|
|
73079
|
+
this.recTimer = undefined;
|
|
73080
|
+
this.recStream?.getTracks().forEach(t => t.stop());
|
|
73081
|
+
this.recStream = undefined;
|
|
73082
|
+
this.recorder = undefined;
|
|
73083
|
+
this.recChunks = [];
|
|
73084
|
+
this.recording.set(false);
|
|
73085
|
+
this.recSeconds.set(0);
|
|
73086
|
+
}
|
|
73087
|
+
ngOnDestroy() {
|
|
73088
|
+
this.cleanupRecording();
|
|
73089
|
+
for (const att of this.pending()) {
|
|
73090
|
+
if (att.url)
|
|
73091
|
+
URL.revokeObjectURL(att.url);
|
|
73092
|
+
}
|
|
73093
|
+
}
|
|
72939
73094
|
t(key) {
|
|
72940
73095
|
return this.i18n.t(key, 'ChatComposer');
|
|
72941
73096
|
}
|
|
72942
73097
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatComposerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
72943
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ChatComposerComponent, isStandalone: true, selector: "val-chat-composer", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, replyingTo: { classPropertyName: "replyingTo", publicName: "replyingTo", isSignal: true, isRequired: false, transformFunction: null }, showAttach: { classPropertyName: "showAttach", publicName: "showAttach", isSignal: true, isRequired: false, transformFunction: null },
|
|
73098
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ChatComposerComponent, isStandalone: true, selector: "val-chat-composer", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, replyingTo: { classPropertyName: "replyingTo", publicName: "replyingTo", isSignal: true, isRequired: false, transformFunction: null }, showAttach: { classPropertyName: "showAttach", publicName: "showAttach", isSignal: true, isRequired: false, transformFunction: null }, showMic: { classPropertyName: "showMic", publicName: "showMic", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { send: "send", typing: "typing", voice: "voice", cancelReply: "cancelReply" }, ngImport: i0, template: `
|
|
72944
73099
|
<div class="composer">
|
|
72945
73100
|
@if (replyingTo()) {
|
|
72946
73101
|
<div class="reply-bar">
|
|
@@ -72954,52 +73109,84 @@ class ChatComposerComponent {
|
|
|
72954
73109
|
</div>
|
|
72955
73110
|
}
|
|
72956
73111
|
|
|
72957
|
-
@if (
|
|
72958
|
-
<div class="
|
|
72959
|
-
@for (
|
|
72960
|
-
|
|
73112
|
+
@if (pending().length > 0) {
|
|
73113
|
+
<div class="pending-row">
|
|
73114
|
+
@for (att of pending(); track att.id) {
|
|
73115
|
+
@if (att.kind === 'audio') {
|
|
73116
|
+
<div class="audio-chip">
|
|
73117
|
+
<audio controls preload="metadata" [src]="att.url"></audio>
|
|
73118
|
+
<button class="thumb-remove inline" [attr.aria-label]="t('remove')" (click)="removePending(att.id)">
|
|
73119
|
+
<ion-icon name="close-outline" aria-hidden="true" />
|
|
73120
|
+
</button>
|
|
73121
|
+
</div>
|
|
73122
|
+
} @else {
|
|
73123
|
+
<div class="thumb" [class.file]="att.kind === 'file'">
|
|
73124
|
+
@if (att.kind === 'image') {
|
|
73125
|
+
<img [src]="att.url" [alt]="att.file.name" />
|
|
73126
|
+
} @else {
|
|
73127
|
+
<ion-icon name="document-outline" aria-hidden="true" />
|
|
73128
|
+
<span class="thumb-name">{{ att.file.name }}</span>
|
|
73129
|
+
}
|
|
73130
|
+
<button class="thumb-remove" [attr.aria-label]="t('remove')" (click)="removePending(att.id)">
|
|
73131
|
+
<ion-icon name="close-outline" aria-hidden="true" />
|
|
73132
|
+
</button>
|
|
73133
|
+
</div>
|
|
73134
|
+
}
|
|
72961
73135
|
}
|
|
72962
73136
|
</div>
|
|
72963
73137
|
}
|
|
72964
73138
|
|
|
72965
|
-
|
|
72966
|
-
|
|
72967
|
-
<
|
|
72968
|
-
<ion-icon name="
|
|
72969
|
-
<input type="file" hidden (change)="onFile($event)" accept="image/*,application/pdf" />
|
|
72970
|
-
</label>
|
|
72971
|
-
}
|
|
72972
|
-
|
|
72973
|
-
<ion-textarea
|
|
72974
|
-
class="field"
|
|
72975
|
-
[placeholder]="placeholderText()"
|
|
72976
|
-
[disabled]="disabled()"
|
|
72977
|
-
[maxlength]="maxLength()"
|
|
72978
|
-
[autoGrow]="true"
|
|
72979
|
-
[rows]="1"
|
|
72980
|
-
[value]="body()"
|
|
72981
|
-
(ionInput)="onInput($event)"
|
|
72982
|
-
(keydown)="onKeydown($event)"
|
|
72983
|
-
></ion-textarea>
|
|
72984
|
-
|
|
72985
|
-
@if (showEmoji()) {
|
|
72986
|
-
<button class="icon-btn" [class.active]="emojiOpen()" [attr.aria-label]="t('emoji')" (click)="toggleEmoji()">
|
|
72987
|
-
<ion-icon name="happy-outline" aria-hidden="true" />
|
|
73139
|
+
@if (recording()) {
|
|
73140
|
+
<div class="rec-bar">
|
|
73141
|
+
<button class="icon-btn danger" [attr.aria-label]="t('cancel')" (click)="cancelRecording()">
|
|
73142
|
+
<ion-icon name="trash-outline" aria-hidden="true" />
|
|
72988
73143
|
</button>
|
|
72989
|
-
|
|
72990
|
-
|
|
72991
|
-
|
|
72992
|
-
<button class="send-btn" [attr.aria-label]="t('
|
|
72993
|
-
<ion-icon name="
|
|
72994
|
-
</button>
|
|
72995
|
-
} @else if (showMic()) {
|
|
72996
|
-
<button class="icon-btn mic" [attr.aria-label]="t('voice')" (click)="voice.emit()">
|
|
72997
|
-
<ion-icon name="mic-outline" aria-hidden="true" />
|
|
73144
|
+
<span class="rec-dot"></span>
|
|
73145
|
+
<span class="rec-time">{{ recTimeLabel() }}</span>
|
|
73146
|
+
<span class="rec-spacer"></span>
|
|
73147
|
+
<button class="send-btn" [attr.aria-label]="t('done')" (click)="finishRecording()">
|
|
73148
|
+
<ion-icon name="checkmark-outline" aria-hidden="true" />
|
|
72998
73149
|
</button>
|
|
72999
|
-
|
|
73000
|
-
|
|
73150
|
+
</div>
|
|
73151
|
+
} @else {
|
|
73152
|
+
<div class="pill">
|
|
73153
|
+
@if (showAttach()) {
|
|
73154
|
+
<label class="icon-btn" [attr.aria-label]="t('attach')">
|
|
73155
|
+
<ion-icon name="add-outline" aria-hidden="true" />
|
|
73156
|
+
<input type="file" hidden (change)="onFile($event)" accept="image/*,application/pdf" />
|
|
73157
|
+
</label>
|
|
73158
|
+
}
|
|
73159
|
+
|
|
73160
|
+
<ion-textarea
|
|
73161
|
+
class="field"
|
|
73162
|
+
[placeholder]="placeholderText()"
|
|
73163
|
+
[disabled]="disabled()"
|
|
73164
|
+
[maxlength]="maxLength()"
|
|
73165
|
+
[autoGrow]="true"
|
|
73166
|
+
[rows]="1"
|
|
73167
|
+
[value]="body()"
|
|
73168
|
+
[spellcheck]="false"
|
|
73169
|
+
autocapitalize="sentences"
|
|
73170
|
+
autocorrect="off"
|
|
73171
|
+
enterkeyhint="enter"
|
|
73172
|
+
(ionInput)="onInput($event)"
|
|
73173
|
+
(keydown)="onKeydown($event)"
|
|
73174
|
+
(paste)="onPaste($event)"
|
|
73175
|
+
></ion-textarea>
|
|
73176
|
+
|
|
73177
|
+
@if (canSend()) {
|
|
73178
|
+
<button class="send-btn" [attr.aria-label]="t('send')" (click)="onSend()">
|
|
73179
|
+
<ion-icon name="arrow-up-outline" aria-hidden="true" />
|
|
73180
|
+
</button>
|
|
73181
|
+
} @else if (showMic()) {
|
|
73182
|
+
<button class="icon-btn mic" [attr.aria-label]="t('voice')" (click)="startRecording()">
|
|
73183
|
+
<ion-icon name="mic-outline" aria-hidden="true" />
|
|
73184
|
+
</button>
|
|
73185
|
+
}
|
|
73186
|
+
</div>
|
|
73187
|
+
}
|
|
73001
73188
|
</div>
|
|
73002
|
-
`, isInline: true, styles: [":host{display:block}.composer{display:flex;flex-direction:column;gap:6px;padding:8px 10px calc(8px + env(safe-area-inset-bottom,0px));background:var(--ion-background-color, #fff);border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .08))}.reply-bar{display:flex;align-items:center;gap:8px;padding:6px 10px;border-left:3px solid var(--ion-color-primary);border-radius:8px;background:var(--ion-color-step-100, rgba(127, 127, 127, .1))}.reply-content{display:flex;flex-direction:column;flex:1;min-width:0;font-size:.8125rem}.reply-name{font-weight:700;color:var(--ion-color-primary)}.reply-body{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ion-color-medium, #92949c)}.
|
|
73189
|
+
`, isInline: true, styles: [":host{display:block}.composer{display:flex;flex-direction:column;gap:6px;padding:8px 10px calc(8px + env(safe-area-inset-bottom,0px));background:var(--ion-background-color, #fff);border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .08))}.reply-bar{display:flex;align-items:center;gap:8px;padding:6px 10px;border-left:3px solid var(--ion-color-primary);border-radius:8px;background:var(--ion-color-step-100, rgba(127, 127, 127, .1))}.reply-content{display:flex;flex-direction:column;flex:1;min-width:0;font-size:.8125rem}.reply-name{font-weight:700;color:var(--ion-color-primary)}.reply-body{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ion-color-medium, #92949c)}.pending-row{display:flex;gap:8px;flex-wrap:wrap;padding:2px 4px}.thumb{position:relative;width:64px;height:64px;border-radius:10px;overflow:hidden;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-color-step-100, rgba(127, 127, 127, .1))}.thumb img{width:100%;height:100%;object-fit:cover}.thumb.file{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:4px;color:var(--ion-color-medium, #92949c);font-size:1.5rem}.thumb-name{font-size:.5625rem;line-height:1.1;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ion-text-color, #000)}.thumb-remove{position:absolute;top:2px;right:2px;width:20px;height:20px;border:none;border-radius:50%;background:#0000008c;color:#fff;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:.875rem}.pill{display:flex;align-items:flex-end;gap:4px;background:var(--ion-color-light, #f4f5f8);border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08));border-radius:24px;padding:2px 6px}.field{flex:1;--background: transparent;--padding-start: 6px;--padding-end: 6px;--padding-top: 8px;--padding-bottom: 8px;margin:0;max-height:120px;font-size:.9375rem}.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;flex-shrink:0;border:none;border-radius:50%;background:transparent;color:var(--ion-color-medium, #92949c);cursor:pointer;font-size:1.375rem}.icon-btn:hover,.icon-btn.active{color:var(--ion-color-primary)}.send-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;flex-shrink:0;border:none;border-radius:50%;background:var(--ion-color-primary);color:var(--ion-color-primary-contrast, #fff);cursor:pointer;font-size:1.25rem;transition:transform .1s ease}.send-btn:active{transform:scale(.92)}.audio-chip{display:flex;align-items:center;gap:6px;width:100%;padding:4px 6px;border-radius:12px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-color-step-100, rgba(127, 127, 127, .1))}.audio-chip audio{flex:1;height:36px;min-width:0}.thumb-remove.inline{position:static;flex-shrink:0;background:var(--ion-color-medium, #92949c)}.icon-btn.danger{color:var(--ion-color-danger, #eb445a)}.rec-bar{display:flex;align-items:center;gap:10px;background:var(--ion-color-light, #f4f5f8);border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08));border-radius:24px;padding:2px 6px}.rec-dot{width:10px;height:10px;border-radius:50%;background:var(--ion-color-danger, #eb445a);animation:rec-pulse 1.2s ease-in-out infinite}.rec-time{font-variant-numeric:tabular-nums;font-size:.9375rem;color:var(--ion-text-color, #000)}.rec-spacer{flex:1}@keyframes rec-pulse{0%,to{opacity:1}50%{opacity:.3}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
|
|
73003
73190
|
}
|
|
73004
73191
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatComposerComponent, decorators: [{
|
|
73005
73192
|
type: Component,
|
|
@@ -73017,52 +73204,84 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
73017
73204
|
</div>
|
|
73018
73205
|
}
|
|
73019
73206
|
|
|
73020
|
-
@if (
|
|
73021
|
-
<div class="
|
|
73022
|
-
@for (
|
|
73023
|
-
|
|
73207
|
+
@if (pending().length > 0) {
|
|
73208
|
+
<div class="pending-row">
|
|
73209
|
+
@for (att of pending(); track att.id) {
|
|
73210
|
+
@if (att.kind === 'audio') {
|
|
73211
|
+
<div class="audio-chip">
|
|
73212
|
+
<audio controls preload="metadata" [src]="att.url"></audio>
|
|
73213
|
+
<button class="thumb-remove inline" [attr.aria-label]="t('remove')" (click)="removePending(att.id)">
|
|
73214
|
+
<ion-icon name="close-outline" aria-hidden="true" />
|
|
73215
|
+
</button>
|
|
73216
|
+
</div>
|
|
73217
|
+
} @else {
|
|
73218
|
+
<div class="thumb" [class.file]="att.kind === 'file'">
|
|
73219
|
+
@if (att.kind === 'image') {
|
|
73220
|
+
<img [src]="att.url" [alt]="att.file.name" />
|
|
73221
|
+
} @else {
|
|
73222
|
+
<ion-icon name="document-outline" aria-hidden="true" />
|
|
73223
|
+
<span class="thumb-name">{{ att.file.name }}</span>
|
|
73224
|
+
}
|
|
73225
|
+
<button class="thumb-remove" [attr.aria-label]="t('remove')" (click)="removePending(att.id)">
|
|
73226
|
+
<ion-icon name="close-outline" aria-hidden="true" />
|
|
73227
|
+
</button>
|
|
73228
|
+
</div>
|
|
73229
|
+
}
|
|
73024
73230
|
}
|
|
73025
73231
|
</div>
|
|
73026
73232
|
}
|
|
73027
73233
|
|
|
73028
|
-
|
|
73029
|
-
|
|
73030
|
-
<
|
|
73031
|
-
<ion-icon name="
|
|
73032
|
-
<input type="file" hidden (change)="onFile($event)" accept="image/*,application/pdf" />
|
|
73033
|
-
</label>
|
|
73034
|
-
}
|
|
73035
|
-
|
|
73036
|
-
<ion-textarea
|
|
73037
|
-
class="field"
|
|
73038
|
-
[placeholder]="placeholderText()"
|
|
73039
|
-
[disabled]="disabled()"
|
|
73040
|
-
[maxlength]="maxLength()"
|
|
73041
|
-
[autoGrow]="true"
|
|
73042
|
-
[rows]="1"
|
|
73043
|
-
[value]="body()"
|
|
73044
|
-
(ionInput)="onInput($event)"
|
|
73045
|
-
(keydown)="onKeydown($event)"
|
|
73046
|
-
></ion-textarea>
|
|
73047
|
-
|
|
73048
|
-
@if (showEmoji()) {
|
|
73049
|
-
<button class="icon-btn" [class.active]="emojiOpen()" [attr.aria-label]="t('emoji')" (click)="toggleEmoji()">
|
|
73050
|
-
<ion-icon name="happy-outline" aria-hidden="true" />
|
|
73051
|
-
</button>
|
|
73052
|
-
}
|
|
73053
|
-
|
|
73054
|
-
@if (canSend()) {
|
|
73055
|
-
<button class="send-btn" [attr.aria-label]="t('send')" (click)="onSend()">
|
|
73056
|
-
<ion-icon name="arrow-up-outline" aria-hidden="true" />
|
|
73234
|
+
@if (recording()) {
|
|
73235
|
+
<div class="rec-bar">
|
|
73236
|
+
<button class="icon-btn danger" [attr.aria-label]="t('cancel')" (click)="cancelRecording()">
|
|
73237
|
+
<ion-icon name="trash-outline" aria-hidden="true" />
|
|
73057
73238
|
</button>
|
|
73058
|
-
|
|
73059
|
-
<
|
|
73060
|
-
|
|
73239
|
+
<span class="rec-dot"></span>
|
|
73240
|
+
<span class="rec-time">{{ recTimeLabel() }}</span>
|
|
73241
|
+
<span class="rec-spacer"></span>
|
|
73242
|
+
<button class="send-btn" [attr.aria-label]="t('done')" (click)="finishRecording()">
|
|
73243
|
+
<ion-icon name="checkmark-outline" aria-hidden="true" />
|
|
73061
73244
|
</button>
|
|
73062
|
-
|
|
73063
|
-
|
|
73245
|
+
</div>
|
|
73246
|
+
} @else {
|
|
73247
|
+
<div class="pill">
|
|
73248
|
+
@if (showAttach()) {
|
|
73249
|
+
<label class="icon-btn" [attr.aria-label]="t('attach')">
|
|
73250
|
+
<ion-icon name="add-outline" aria-hidden="true" />
|
|
73251
|
+
<input type="file" hidden (change)="onFile($event)" accept="image/*,application/pdf" />
|
|
73252
|
+
</label>
|
|
73253
|
+
}
|
|
73254
|
+
|
|
73255
|
+
<ion-textarea
|
|
73256
|
+
class="field"
|
|
73257
|
+
[placeholder]="placeholderText()"
|
|
73258
|
+
[disabled]="disabled()"
|
|
73259
|
+
[maxlength]="maxLength()"
|
|
73260
|
+
[autoGrow]="true"
|
|
73261
|
+
[rows]="1"
|
|
73262
|
+
[value]="body()"
|
|
73263
|
+
[spellcheck]="false"
|
|
73264
|
+
autocapitalize="sentences"
|
|
73265
|
+
autocorrect="off"
|
|
73266
|
+
enterkeyhint="enter"
|
|
73267
|
+
(ionInput)="onInput($event)"
|
|
73268
|
+
(keydown)="onKeydown($event)"
|
|
73269
|
+
(paste)="onPaste($event)"
|
|
73270
|
+
></ion-textarea>
|
|
73271
|
+
|
|
73272
|
+
@if (canSend()) {
|
|
73273
|
+
<button class="send-btn" [attr.aria-label]="t('send')" (click)="onSend()">
|
|
73274
|
+
<ion-icon name="arrow-up-outline" aria-hidden="true" />
|
|
73275
|
+
</button>
|
|
73276
|
+
} @else if (showMic()) {
|
|
73277
|
+
<button class="icon-btn mic" [attr.aria-label]="t('voice')" (click)="startRecording()">
|
|
73278
|
+
<ion-icon name="mic-outline" aria-hidden="true" />
|
|
73279
|
+
</button>
|
|
73280
|
+
}
|
|
73281
|
+
</div>
|
|
73282
|
+
}
|
|
73064
73283
|
</div>
|
|
73065
|
-
`, styles: [":host{display:block}.composer{display:flex;flex-direction:column;gap:6px;padding:8px 10px calc(8px + env(safe-area-inset-bottom,0px));background:var(--ion-background-color, #fff);border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .08))}.reply-bar{display:flex;align-items:center;gap:8px;padding:6px 10px;border-left:3px solid var(--ion-color-primary);border-radius:8px;background:var(--ion-color-step-100, rgba(127, 127, 127, .1))}.reply-content{display:flex;flex-direction:column;flex:1;min-width:0;font-size:.8125rem}.reply-name{font-weight:700;color:var(--ion-color-primary)}.reply-body{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ion-color-medium, #92949c)}.
|
|
73284
|
+
`, styles: [":host{display:block}.composer{display:flex;flex-direction:column;gap:6px;padding:8px 10px calc(8px + env(safe-area-inset-bottom,0px));background:var(--ion-background-color, #fff);border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .08))}.reply-bar{display:flex;align-items:center;gap:8px;padding:6px 10px;border-left:3px solid var(--ion-color-primary);border-radius:8px;background:var(--ion-color-step-100, rgba(127, 127, 127, .1))}.reply-content{display:flex;flex-direction:column;flex:1;min-width:0;font-size:.8125rem}.reply-name{font-weight:700;color:var(--ion-color-primary)}.reply-body{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ion-color-medium, #92949c)}.pending-row{display:flex;gap:8px;flex-wrap:wrap;padding:2px 4px}.thumb{position:relative;width:64px;height:64px;border-radius:10px;overflow:hidden;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-color-step-100, rgba(127, 127, 127, .1))}.thumb img{width:100%;height:100%;object-fit:cover}.thumb.file{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:4px;color:var(--ion-color-medium, #92949c);font-size:1.5rem}.thumb-name{font-size:.5625rem;line-height:1.1;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ion-text-color, #000)}.thumb-remove{position:absolute;top:2px;right:2px;width:20px;height:20px;border:none;border-radius:50%;background:#0000008c;color:#fff;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:.875rem}.pill{display:flex;align-items:flex-end;gap:4px;background:var(--ion-color-light, #f4f5f8);border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08));border-radius:24px;padding:2px 6px}.field{flex:1;--background: transparent;--padding-start: 6px;--padding-end: 6px;--padding-top: 8px;--padding-bottom: 8px;margin:0;max-height:120px;font-size:.9375rem}.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;flex-shrink:0;border:none;border-radius:50%;background:transparent;color:var(--ion-color-medium, #92949c);cursor:pointer;font-size:1.375rem}.icon-btn:hover,.icon-btn.active{color:var(--ion-color-primary)}.send-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;flex-shrink:0;border:none;border-radius:50%;background:var(--ion-color-primary);color:var(--ion-color-primary-contrast, #fff);cursor:pointer;font-size:1.25rem;transition:transform .1s ease}.send-btn:active{transform:scale(.92)}.audio-chip{display:flex;align-items:center;gap:6px;width:100%;padding:4px 6px;border-radius:12px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-color-step-100, rgba(127, 127, 127, .1))}.audio-chip audio{flex:1;height:36px;min-width:0}.thumb-remove.inline{position:static;flex-shrink:0;background:var(--ion-color-medium, #92949c)}.icon-btn.danger{color:var(--ion-color-danger, #eb445a)}.rec-bar{display:flex;align-items:center;gap:10px;background:var(--ion-color-light, #f4f5f8);border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08));border-radius:24px;padding:2px 6px}.rec-dot{width:10px;height:10px;border-radius:50%;background:var(--ion-color-danger, #eb445a);animation:rec-pulse 1.2s ease-in-out infinite}.rec-time{font-variant-numeric:tabular-nums;font-size:.9375rem;color:var(--ion-text-color, #000)}.rec-spacer{flex:1}@keyframes rec-pulse{0%,to{opacity:1}50%{opacity:.3}}\n"] }]
|
|
73066
73285
|
}], ctorParameters: () => [] });
|
|
73067
73286
|
|
|
73068
73287
|
/**
|
|
@@ -73282,7 +73501,6 @@ class ChatWindowComponent {
|
|
|
73282
73501
|
this.replyTo = output();
|
|
73283
73502
|
this.editMessage = output();
|
|
73284
73503
|
this.typing = output();
|
|
73285
|
-
this.attach = output();
|
|
73286
73504
|
this.voice = output();
|
|
73287
73505
|
this.msgsEl = viewChild('msgs');
|
|
73288
73506
|
this.replyingTo = signal(null);
|
|
@@ -73366,8 +73584,8 @@ class ChatWindowComponent {
|
|
|
73366
73584
|
this.atBottom.set(true);
|
|
73367
73585
|
this.hasNew.set(false);
|
|
73368
73586
|
}
|
|
73369
|
-
onSend(
|
|
73370
|
-
this.sendMessage.emit(
|
|
73587
|
+
onSend(event) {
|
|
73588
|
+
this.sendMessage.emit(event);
|
|
73371
73589
|
this.replyingTo.set(null);
|
|
73372
73590
|
}
|
|
73373
73591
|
onAction(event) {
|
|
@@ -73395,7 +73613,7 @@ class ChatWindowComponent {
|
|
|
73395
73613
|
return this.i18n.t(key, 'ChatWindow');
|
|
73396
73614
|
}
|
|
73397
73615
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatWindowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
73398
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ChatWindowComponent, isStandalone: true, selector: "val-chat-window", inputs: { convId: { classPropertyName: "convId", publicName: "convId", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: false, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, typingUsers: { classPropertyName: "typingUsers", publicName: "typingUsers", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sendMessage: "sendMessage", loadMore: "loadMore", reactionClick: "reactionClick", deleteMessage: "deleteMessage", replyTo: "replyTo", editMessage: "editMessage", typing: "typing",
|
|
73616
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ChatWindowComponent, isStandalone: true, selector: "val-chat-window", inputs: { convId: { classPropertyName: "convId", publicName: "convId", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: false, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, typingUsers: { classPropertyName: "typingUsers", publicName: "typingUsers", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sendMessage: "sendMessage", loadMore: "loadMore", reactionClick: "reactionClick", deleteMessage: "deleteMessage", replyTo: "replyTo", editMessage: "editMessage", typing: "typing", voice: "voice" }, viewQueries: [{ propertyName: "msgsEl", first: true, predicate: ["msgs"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
73399
73617
|
<div class="chat">
|
|
73400
73618
|
<div #msgs class="messages" (scroll)="onScroll()">
|
|
73401
73619
|
@if (isLoading()) {
|
|
@@ -73442,7 +73660,6 @@ class ChatWindowComponent {
|
|
|
73442
73660
|
[replyingTo]="replyingTo()"
|
|
73443
73661
|
(send)="onSend($event)"
|
|
73444
73662
|
(typing)="typing.emit()"
|
|
73445
|
-
(attach)="attach.emit($event)"
|
|
73446
73663
|
(voice)="voice.emit()"
|
|
73447
73664
|
(cancelReply)="replyingTo.set(null)"
|
|
73448
73665
|
/>
|
|
@@ -73450,7 +73667,7 @@ class ChatWindowComponent {
|
|
|
73450
73667
|
<div class="closed-banner">{{ t('conversationClosed') }}</div>
|
|
73451
73668
|
}
|
|
73452
73669
|
</div>
|
|
73453
|
-
`, isInline: true, styles: [":host{display:block;height:100%}.chat{position:relative;display:flex;flex-direction:column;height:100%;min-height:0}.messages{flex:1;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:0}.state{margin:auto;display:flex;flex-direction:column;align-items:center;gap:8px;color:var(--ion-color-medium, #92949c);font-size:.9375rem;text-align:center;padding:24px}.state.empty ion-icon{font-size:2.5rem;opacity:.5}.date-sep{position:sticky;top:4px;z-index:1;display:flex;justify-content:center;margin:8px 0}.date-sep span{font-size:.75rem;color:var(--ion-color-medium, #92949c);background:var(--ion-color-step-100, rgba(127, 127, 127, .14));padding:3px 12px;border-radius:999px;backdrop-filter:blur(4px)}.scroll-down{position:absolute;right:14px;bottom:84px;width:40px;height:40px;border-radius:50%;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-card-background, var(--ion-background-color, #fff));color:var(--ion-color-medium, #92949c);box-shadow:0 2px 10px #00000026;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:1.25rem;z-index:3}.scroll-down .dot{position:absolute;top:0;right:0;width:12px;height:12px;border-radius:50%;background:var(--ion-color-primary);border:2px solid var(--ion-card-background, #fff)}.closed-banner{text-align:center;padding:14px;color:var(--ion-color-medium, #92949c);font-size:.875rem;border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .08))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: MessageBubbleComponent, selector: "val-message-bubble", inputs: ["msg", "showAvatar", "showName", "tail", "locale"], outputs: ["action"] }, { kind: "component", type: ChatComposerComponent, selector: "val-chat-composer", inputs: ["placeholder", "disabled", "maxLength", "replyingTo", "showAttach", "
|
|
73670
|
+
`, isInline: true, styles: [":host{display:block;height:100%}.chat{position:relative;display:flex;flex-direction:column;height:100%;min-height:0}.messages{flex:1;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:0}.state{margin:auto;display:flex;flex-direction:column;align-items:center;gap:8px;color:var(--ion-color-medium, #92949c);font-size:.9375rem;text-align:center;padding:24px}.state.empty ion-icon{font-size:2.5rem;opacity:.5}.date-sep{position:sticky;top:4px;z-index:1;display:flex;justify-content:center;margin:8px 0}.date-sep span{font-size:.75rem;color:var(--ion-color-medium, #92949c);background:var(--ion-color-step-100, rgba(127, 127, 127, .14));padding:3px 12px;border-radius:999px;backdrop-filter:blur(4px)}.scroll-down{position:absolute;right:14px;bottom:84px;width:40px;height:40px;border-radius:50%;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-card-background, var(--ion-background-color, #fff));color:var(--ion-color-medium, #92949c);box-shadow:0 2px 10px #00000026;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:1.25rem;z-index:3}.scroll-down .dot{position:absolute;top:0;right:0;width:12px;height:12px;border-radius:50%;background:var(--ion-color-primary);border:2px solid var(--ion-card-background, #fff)}.closed-banner{text-align:center;padding:14px;color:var(--ion-color-medium, #92949c);font-size:.875rem;border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .08))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: MessageBubbleComponent, selector: "val-message-bubble", inputs: ["msg", "showAvatar", "showName", "tail", "locale"], outputs: ["action"] }, { kind: "component", type: ChatComposerComponent, selector: "val-chat-composer", inputs: ["placeholder", "disabled", "maxLength", "replyingTo", "showAttach", "showMic"], outputs: ["send", "typing", "voice", "cancelReply"] }, { kind: "component", type: TypingIndicatorComponent, selector: "val-typing-indicator", inputs: ["typingUsers"] }] }); }
|
|
73454
73671
|
}
|
|
73455
73672
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatWindowComponent, decorators: [{
|
|
73456
73673
|
type: Component,
|
|
@@ -73501,7 +73718,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
73501
73718
|
[replyingTo]="replyingTo()"
|
|
73502
73719
|
(send)="onSend($event)"
|
|
73503
73720
|
(typing)="typing.emit()"
|
|
73504
|
-
(attach)="attach.emit($event)"
|
|
73505
73721
|
(voice)="voice.emit()"
|
|
73506
73722
|
(cancelReply)="replyingTo.set(null)"
|
|
73507
73723
|
/>
|
|
@@ -73615,11 +73831,13 @@ class ThreadPanelComponent {
|
|
|
73615
73831
|
this.conversationSvc.stopTyping(conv.convId, orgId, appId);
|
|
73616
73832
|
}
|
|
73617
73833
|
}
|
|
73618
|
-
onSend(
|
|
73834
|
+
onSend(event) {
|
|
73619
73835
|
const conv = this.conv();
|
|
73620
73836
|
if (!conv || !this.conversationSvc)
|
|
73621
73837
|
return;
|
|
73622
|
-
|
|
73838
|
+
// thread-panel no tiene pipeline de subida de adjuntos; solo envía el texto.
|
|
73839
|
+
if (event.text)
|
|
73840
|
+
this.conversationSvc.sendMessage(conv.convId, event.text).subscribe();
|
|
73623
73841
|
}
|
|
73624
73842
|
onReactionClick(event) {
|
|
73625
73843
|
// Reacciones se implementan a nivel de app consumer
|
|
@@ -73668,7 +73886,7 @@ class ThreadPanelComponent {
|
|
|
73668
73886
|
</div>
|
|
73669
73887
|
}
|
|
73670
73888
|
</div>
|
|
73671
|
-
`, isInline: true, styles: [".thread-panel{display:flex;flex-direction:column;height:100%;background:var(--ion-background-color, #f4f5f8)}.thread-header{padding:12px 16px;border-bottom:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-card-background, var(--ion-background-color, #fff))}.thread-header .thread-title{font-size:1rem;font-weight:600;color:var(--ion-text-color, #000);margin:0}.thread-loading{display:flex;align-items:center;justify-content:center;flex:1;gap:10px;color:var(--ion-color-medium, #92949c);font-size:.875rem}.thread-chat{flex:1;overflow:hidden;display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: ChatWindowComponent, selector: "val-chat-window", inputs: ["convId", "messages", "currentUserId", "isOpen", "typingUsers", "isLoading"], outputs: ["sendMessage", "loadMore", "reactionClick", "deleteMessage", "replyTo", "editMessage", "typing", "
|
|
73889
|
+
`, isInline: true, styles: [".thread-panel{display:flex;flex-direction:column;height:100%;background:var(--ion-background-color, #f4f5f8)}.thread-header{padding:12px 16px;border-bottom:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));background:var(--ion-card-background, var(--ion-background-color, #fff))}.thread-header .thread-title{font-size:1rem;font-weight:600;color:var(--ion-text-color, #000);margin:0}.thread-loading{display:flex;align-items:center;justify-content:center;flex:1;gap:10px;color:var(--ion-color-medium, #92949c);font-size:.875rem}.thread-chat{flex:1;overflow:hidden;display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: ChatWindowComponent, selector: "val-chat-window", inputs: ["convId", "messages", "currentUserId", "isOpen", "typingUsers", "isLoading"], outputs: ["sendMessage", "loadMore", "reactionClick", "deleteMessage", "replyTo", "editMessage", "typing", "voice"] }] }); }
|
|
73672
73890
|
}
|
|
73673
73891
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThreadPanelComponent, decorators: [{
|
|
73674
73892
|
type: Component,
|