valtech-components 4.0.227 → 4.0.229

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.
@@ -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.227';
59
+ const VERSION = '4.0.229';
60
60
 
61
61
  // Control de estado de refresco (singleton a nivel de módulo)
62
62
  let isRefreshing = false;
@@ -72822,35 +72822,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
72822
72822
  type: Output
72823
72823
  }] } });
72824
72824
 
72825
- addIcons({ addOutline, closeOutline, happyOutline, micOutline, arrowUpOutline, trashOutline });
72825
+ addIcons({ addOutline, closeOutline, documentOutline, micOutline, arrowUpOutline, trashOutline });
72826
72826
  const CHAT_COMPOSER_I18N = {
72827
72827
  es: {
72828
72828
  placeholder: 'Escribe un mensaje',
72829
72829
  send: 'Enviar',
72830
72830
  attach: 'Adjuntar',
72831
- emoji: 'Emoji',
72832
72831
  voice: 'Mensaje de voz',
72833
72832
  replyingTo: 'Respondiendo a',
72834
72833
  cancel: 'Cancelar',
72834
+ remove: 'Quitar',
72835
72835
  },
72836
72836
  en: {
72837
72837
  placeholder: 'Write a message',
72838
72838
  send: 'Send',
72839
72839
  attach: 'Attach',
72840
- emoji: 'Emoji',
72841
72840
  voice: 'Voice message',
72842
72841
  replyingTo: 'Replying to',
72843
72842
  cancel: 'Cancel',
72843
+ remove: 'Remove',
72844
72844
  },
72845
72845
  };
72846
- const QUICK_EMOJIS = ['👍', '❤️', '😂', '🎉', '🙏', '🔥', '😮', '😢'];
72847
72846
  /**
72848
72847
  * val-chat-composer — barra de redacción de chat moderna (signal inputs).
72849
72848
  *
72850
- * Pill con: adjuntar (+), textarea auto-grow, emoji (fila rápida) y mic/enviar
72851
- * (mic cuando está vacío, enviar cuando hay texto patrón WhatsApp/Telegram).
72852
- * Muestra una barra de contexto "respondiendo a" cuando `replyingTo` está seteado.
72853
- * `typing` se emite con debounce (máx. 1 vez cada 2s) para no spamear writes.
72849
+ * Pill con: adjuntar (+), textarea auto-grow, y mic/enviar (mic cuando está vacío,
72850
+ * enviar cuando hay texto o adjuntos). Los adjuntos (botón + / pegar imagen) se
72851
+ * acumulan como PREVIEW (miniaturas) y se emiten por `(attach)` recién al ENVIAR
72852
+ * no se van solos al chat. Audio grabado se emite directo al parar.
72853
+ * No incluye picker de emoji: el teclado del sistema ya lo trae.
72854
72854
  */
72855
72855
  class ChatComposerComponent {
72856
72856
  constructor() {
@@ -72860,7 +72860,6 @@ class ChatComposerComponent {
72860
72860
  this.maxLength = input(2000);
72861
72861
  this.replyingTo = input(null);
72862
72862
  this.showAttach = input(true);
72863
- this.showEmoji = input(true);
72864
72863
  this.showMic = input(true);
72865
72864
  this.send = output();
72866
72865
  this.typing = output();
@@ -72868,8 +72867,8 @@ class ChatComposerComponent {
72868
72867
  this.voice = output();
72869
72868
  this.cancelReply = output();
72870
72869
  this.body = signal('');
72871
- this.emojiOpen = signal(false);
72872
- this.quickEmojis = QUICK_EMOJIS;
72870
+ this.pending = signal([]);
72871
+ this.pendingId = 0;
72873
72872
  // Grabación de audio (MediaRecorder).
72874
72873
  this.recording = signal(false);
72875
72874
  this.recSeconds = signal(0);
@@ -72883,7 +72882,9 @@ class ChatComposerComponent {
72883
72882
  this.lastTypingEmit = 0;
72884
72883
  this.canSend = computed(() => {
72885
72884
  const t = this.body().trim();
72886
- return t.length > 0 && t.length <= this.maxLength() && !this.disabled();
72885
+ if (this.disabled())
72886
+ return false;
72887
+ return (t.length > 0 && t.length <= this.maxLength()) || this.pending().length > 0;
72887
72888
  });
72888
72889
  this.placeholderText = computed(() => {
72889
72890
  this.i18n.lang();
@@ -72903,24 +72904,28 @@ class ChatComposerComponent {
72903
72904
  }
72904
72905
  }
72905
72906
  onSend() {
72906
- const trimmed = this.body().trim();
72907
- if (!trimmed || trimmed.length > this.maxLength())
72907
+ if (!this.canSend())
72908
72908
  return;
72909
- this.send.emit(trimmed);
72909
+ // Primero los adjuntos pendientes (cada uno se sube y manda en el consumer),
72910
+ // luego el texto como mensaje aparte si lo hay.
72911
+ const files = this.pending();
72912
+ for (const att of files) {
72913
+ this.attach.emit(att.file);
72914
+ if (att.url)
72915
+ URL.revokeObjectURL(att.url);
72916
+ }
72917
+ this.pending.set([]);
72918
+ const trimmed = this.body().trim();
72919
+ if (trimmed && trimmed.length <= this.maxLength()) {
72920
+ this.send.emit(trimmed);
72921
+ }
72910
72922
  this.body.set('');
72911
- this.emojiOpen.set(false);
72912
- }
72913
- toggleEmoji() {
72914
- this.emojiOpen.update(v => !v);
72915
- }
72916
- insertEmoji(emoji) {
72917
- this.body.update(v => v + emoji);
72918
72923
  }
72919
72924
  onFile(event) {
72920
72925
  const input = event.target;
72921
72926
  const file = input.files?.[0];
72922
72927
  if (file)
72923
- this.attach.emit(file);
72928
+ this.addPending(file);
72924
72929
  input.value = '';
72925
72930
  }
72926
72931
  /** Pegar imagen desde el portapapeles (captura de pantalla, copiar imagen). */
@@ -72933,15 +72938,27 @@ class ChatComposerComponent {
72933
72938
  const file = item.getAsFile();
72934
72939
  if (file) {
72935
72940
  event.preventDefault();
72936
- this.attach.emit(file);
72941
+ this.addPending(file);
72937
72942
  }
72938
72943
  return;
72939
72944
  }
72940
72945
  }
72941
72946
  }
72947
+ addPending(file) {
72948
+ const isImage = file.type.startsWith('image/');
72949
+ const url = isImage ? URL.createObjectURL(file) : undefined;
72950
+ this.pending.update(arr => [...arr, { id: this.pendingId++, file, url, isImage }]);
72951
+ }
72952
+ removePending(id) {
72953
+ this.pending.update(arr => {
72954
+ const found = arr.find(a => a.id === id);
72955
+ if (found?.url)
72956
+ URL.revokeObjectURL(found.url);
72957
+ return arr.filter(a => a.id !== id);
72958
+ });
72959
+ }
72942
72960
  /**
72943
- * Emite typing como máximo 1 vez cada 2s. No usa Date.now() directo en plantillas
72944
- * de workflow; aquí estamos en runtime de navegador, performance.now es seguro.
72961
+ * Emite typing como máximo 1 vez cada 2s. performance.now es seguro en runtime.
72945
72962
  */
72946
72963
  emitTypingDebounced() {
72947
72964
  const now = performance.now();
@@ -73028,12 +73045,16 @@ class ChatComposerComponent {
73028
73045
  }
73029
73046
  ngOnDestroy() {
73030
73047
  this.cleanupRecording();
73048
+ for (const att of this.pending()) {
73049
+ if (att.url)
73050
+ URL.revokeObjectURL(att.url);
73051
+ }
73031
73052
  }
73032
73053
  t(key) {
73033
73054
  return this.i18n.t(key, 'ChatComposer');
73034
73055
  }
73035
73056
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatComposerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
73036
- 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 }, showEmoji: { classPropertyName: "showEmoji", publicName: "showEmoji", isSignal: true, isRequired: false, transformFunction: null }, showMic: { classPropertyName: "showMic", publicName: "showMic", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { send: "send", typing: "typing", attach: "attach", voice: "voice", cancelReply: "cancelReply" }, ngImport: i0, template: `
73057
+ 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", attach: "attach", voice: "voice", cancelReply: "cancelReply" }, ngImport: i0, template: `
73037
73058
  <div class="composer">
73038
73059
  @if (replyingTo()) {
73039
73060
  <div class="reply-bar">
@@ -73047,10 +73068,20 @@ class ChatComposerComponent {
73047
73068
  </div>
73048
73069
  }
73049
73070
 
73050
- @if (emojiOpen()) {
73051
- <div class="emoji-row">
73052
- @for (e of quickEmojis; track e) {
73053
- <button class="emoji" (click)="insertEmoji(e)">{{ e }}</button>
73071
+ @if (pending().length > 0) {
73072
+ <div class="pending-row">
73073
+ @for (att of pending(); track att.id) {
73074
+ <div class="thumb" [class.file]="!att.isImage">
73075
+ @if (att.isImage) {
73076
+ <img [src]="att.url" [alt]="att.file.name" />
73077
+ } @else {
73078
+ <ion-icon name="document-outline" aria-hidden="true" />
73079
+ <span class="thumb-name">{{ att.file.name }}</span>
73080
+ }
73081
+ <button class="thumb-remove" [attr.aria-label]="t('remove')" (click)="removePending(att.id)">
73082
+ <ion-icon name="close-outline" aria-hidden="true" />
73083
+ </button>
73084
+ </div>
73054
73085
  }
73055
73086
  </div>
73056
73087
  }
@@ -73093,17 +73124,6 @@ class ChatComposerComponent {
73093
73124
  (paste)="onPaste($event)"
73094
73125
  ></ion-textarea>
73095
73126
 
73096
- @if (showEmoji()) {
73097
- <button
73098
- class="icon-btn"
73099
- [class.active]="emojiOpen()"
73100
- [attr.aria-label]="t('emoji')"
73101
- (click)="toggleEmoji()"
73102
- >
73103
- <ion-icon name="happy-outline" aria-hidden="true" />
73104
- </button>
73105
- }
73106
-
73107
73127
  @if (canSend()) {
73108
73128
  <button class="send-btn" [attr.aria-label]="t('send')" (click)="onSend()">
73109
73129
  <ion-icon name="arrow-up-outline" aria-hidden="true" />
@@ -73116,7 +73136,7 @@ class ChatComposerComponent {
73116
73136
  </div>
73117
73137
  }
73118
73138
  </div>
73119
- `, 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)}.emoji-row{display:flex;gap:4px;flex-wrap:wrap}.emoji{border:none;background:var(--ion-color-step-100, rgba(127, 127, 127, .1));border-radius:10px;padding:4px 8px;font-size:1.25rem;cursor:pointer}.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,.icon-btn.mic:hover{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)}.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"] }] }); }
73139
+ `, 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)}.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"] }] }); }
73120
73140
  }
73121
73141
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatComposerComponent, decorators: [{
73122
73142
  type: Component,
@@ -73134,10 +73154,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
73134
73154
  </div>
73135
73155
  }
73136
73156
 
73137
- @if (emojiOpen()) {
73138
- <div class="emoji-row">
73139
- @for (e of quickEmojis; track e) {
73140
- <button class="emoji" (click)="insertEmoji(e)">{{ e }}</button>
73157
+ @if (pending().length > 0) {
73158
+ <div class="pending-row">
73159
+ @for (att of pending(); track att.id) {
73160
+ <div class="thumb" [class.file]="!att.isImage">
73161
+ @if (att.isImage) {
73162
+ <img [src]="att.url" [alt]="att.file.name" />
73163
+ } @else {
73164
+ <ion-icon name="document-outline" aria-hidden="true" />
73165
+ <span class="thumb-name">{{ att.file.name }}</span>
73166
+ }
73167
+ <button class="thumb-remove" [attr.aria-label]="t('remove')" (click)="removePending(att.id)">
73168
+ <ion-icon name="close-outline" aria-hidden="true" />
73169
+ </button>
73170
+ </div>
73141
73171
  }
73142
73172
  </div>
73143
73173
  }
@@ -73180,17 +73210,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
73180
73210
  (paste)="onPaste($event)"
73181
73211
  ></ion-textarea>
73182
73212
 
73183
- @if (showEmoji()) {
73184
- <button
73185
- class="icon-btn"
73186
- [class.active]="emojiOpen()"
73187
- [attr.aria-label]="t('emoji')"
73188
- (click)="toggleEmoji()"
73189
- >
73190
- <ion-icon name="happy-outline" aria-hidden="true" />
73191
- </button>
73192
- }
73193
-
73194
73213
  @if (canSend()) {
73195
73214
  <button class="send-btn" [attr.aria-label]="t('send')" (click)="onSend()">
73196
73215
  <ion-icon name="arrow-up-outline" aria-hidden="true" />
@@ -73203,7 +73222,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
73203
73222
  </div>
73204
73223
  }
73205
73224
  </div>
73206
- `, 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)}.emoji-row{display:flex;gap:4px;flex-wrap:wrap}.emoji{border:none;background:var(--ion-color-step-100, rgba(127, 127, 127, .1));border-radius:10px;padding:4px 8px;font-size:1.25rem;cursor:pointer}.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,.icon-btn.mic:hover{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)}.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"] }]
73225
+ `, 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)}.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"] }]
73207
73226
  }], ctorParameters: () => [] });
73208
73227
 
73209
73228
  /**
@@ -73591,7 +73610,7 @@ class ChatWindowComponent {
73591
73610
  <div class="closed-banner">{{ t('conversationClosed') }}</div>
73592
73611
  }
73593
73612
  </div>
73594
- `, 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", "showEmoji", "showMic"], outputs: ["send", "typing", "attach", "voice", "cancelReply"] }, { kind: "component", type: TypingIndicatorComponent, selector: "val-typing-indicator", inputs: ["typingUsers"] }] }); }
73613
+ `, 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", "attach", "voice", "cancelReply"] }, { kind: "component", type: TypingIndicatorComponent, selector: "val-typing-indicator", inputs: ["typingUsers"] }] }); }
73595
73614
  }
73596
73615
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatWindowComponent, decorators: [{
73597
73616
  type: Component,