valtech-components 4.0.218 → 4.0.220

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.
Files changed (56) hide show
  1. package/esm2022/lib/components/molecules/chat-input/chat-input.component.mjs +157 -0
  2. package/esm2022/lib/components/molecules/chat-input/types.mjs +2 -0
  3. package/esm2022/lib/components/molecules/message-bubble/message-bubble.component.mjs +244 -0
  4. package/esm2022/lib/components/molecules/message-bubble/types.mjs +2 -0
  5. package/esm2022/lib/components/molecules/typing-indicator/typing-indicator.component.mjs +76 -0
  6. package/esm2022/lib/components/organisms/account-view/account-view.component.mjs +2 -2
  7. package/esm2022/lib/components/organisms/chat-window/chat-window.component.mjs +246 -0
  8. package/esm2022/lib/components/organisms/chat-window/types.mjs +2 -0
  9. package/esm2022/lib/components/organisms/thread-panel/thread-panel.component.mjs +211 -0
  10. package/esm2022/lib/services/chat/config.mjs +35 -0
  11. package/esm2022/lib/services/chat/conversation.service.mjs +274 -0
  12. package/esm2022/lib/services/chat/types.mjs +10 -0
  13. package/esm2022/lib/services/entity-feed/entity-feed.service.mjs +103 -0
  14. package/esm2022/lib/services/entity-feed/index.mjs +2 -0
  15. package/esm2022/lib/services/entity-feed/types.mjs +2 -0
  16. package/esm2022/lib/services/i18n/default-content.mjs +65 -1
  17. package/esm2022/public-api.mjs +16 -1
  18. package/fesm2022/valtech-components.mjs +1370 -3
  19. package/fesm2022/valtech-components.mjs.map +1 -1
  20. package/lib/components/atoms/glow/glow.component.d.ts +1 -1
  21. package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +2 -2
  22. package/lib/components/atoms/text/text.component.d.ts +1 -1
  23. package/lib/components/atoms/user-avatar/user-avatar.component.d.ts +2 -2
  24. package/lib/components/molecules/article-card/article-card.component.d.ts +1 -1
  25. package/lib/components/molecules/chat-input/chat-input.component.d.ts +38 -0
  26. package/lib/components/molecules/chat-input/types.d.ts +20 -0
  27. package/lib/components/molecules/content-reaction/content-reaction.component.d.ts +2 -2
  28. package/lib/components/molecules/cta-card/cta-card.component.d.ts +1 -1
  29. package/lib/components/molecules/features-list/features-list.component.d.ts +4 -4
  30. package/lib/components/molecules/load-more/load-more.component.d.ts +1 -1
  31. package/lib/components/molecules/media-object/media-object.component.d.ts +1 -1
  32. package/lib/components/molecules/message-bubble/message-bubble.component.d.ts +40 -0
  33. package/lib/components/molecules/message-bubble/types.d.ts +64 -0
  34. package/lib/components/molecules/metric-card/metric-card.component.d.ts +1 -1
  35. package/lib/components/molecules/typing-indicator/typing-indicator.component.d.ts +19 -0
  36. package/lib/components/organisms/account-view/account-view.component.d.ts +1 -1
  37. package/lib/components/organisms/article/article.component.d.ts +6 -6
  38. package/lib/components/organisms/auth-cta/auth-cta.component.d.ts +1 -1
  39. package/lib/components/organisms/bottom-nav/bottom-nav.component.d.ts +1 -1
  40. package/lib/components/organisms/chat-window/chat-window.component.d.ts +63 -0
  41. package/lib/components/organisms/chat-window/types.d.ts +36 -0
  42. package/lib/components/organisms/landing-steps/landing-steps.component.d.ts +1 -1
  43. package/lib/components/organisms/login/login.component.d.ts +1 -1
  44. package/lib/components/organisms/member-import-modal/member-import-modal.component.d.ts +1 -1
  45. package/lib/components/organisms/notification-preferences-view/notification-preferences-view.component.d.ts +1 -1
  46. package/lib/components/organisms/organization-view/organization-view.component.d.ts +1 -1
  47. package/lib/components/organisms/thread-panel/thread-panel.component.d.ts +55 -0
  48. package/lib/components/templates/page-wrapper/page-wrapper.component.d.ts +2 -2
  49. package/lib/services/chat/config.d.ts +37 -0
  50. package/lib/services/chat/conversation.service.d.ts +147 -0
  51. package/lib/services/chat/types.d.ts +145 -0
  52. package/lib/services/entity-feed/entity-feed.service.d.ts +71 -0
  53. package/lib/services/entity-feed/index.d.ts +2 -0
  54. package/lib/services/entity-feed/types.d.ts +26 -0
  55. package/package.json +1 -1
  56. package/public-api.d.ts +13 -0
@@ -0,0 +1,157 @@
1
+ import { Component, Input, Output, EventEmitter, inject, signal, computed } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { IonTextarea, IonButton, IonIcon } from '@ionic/angular/standalone';
4
+ import { addIcons } from 'ionicons';
5
+ import { sendOutline } from 'ionicons/icons';
6
+ import { I18nService } from '../../../services/i18n';
7
+ import * as i0 from "@angular/core";
8
+ addIcons({ sendOutline });
9
+ const CHAT_INPUT_I18N = {
10
+ es: {
11
+ placeholder: 'Escribe un mensaje',
12
+ send: 'Enviar',
13
+ counter: '{count}/{max}',
14
+ },
15
+ en: {
16
+ placeholder: 'Write a message',
17
+ send: 'Send',
18
+ counter: '{count}/{max}',
19
+ },
20
+ };
21
+ /**
22
+ * val-chat-input
23
+ *
24
+ * Campo de entrada para mensajes de chat. Textarea auto-grow con contador
25
+ * de caracteres y boton de enviar. Emite send() al pulsar el boton o Enter
26
+ * (sin Shift), y typing() en cada keydown.
27
+ *
28
+ * @example
29
+ * <val-chat-input
30
+ * [props]="{ placeholder: 'Mensaje...', maxLength: 1000 }"
31
+ * (send)="onSend($event)"
32
+ * (typing)="onTyping()"
33
+ * />
34
+ */
35
+ export class ChatInputComponent {
36
+ constructor() {
37
+ this.i18n = inject(I18nService);
38
+ this.props = {};
39
+ this.send = new EventEmitter();
40
+ this.typing = new EventEmitter();
41
+ this.body = signal('');
42
+ this.maxLen = computed(() => this.props?.maxLength ?? 2000);
43
+ this.canSend = computed(() => {
44
+ const trimmed = this.body().trim();
45
+ return trimmed.length > 0 && trimmed.length <= this.maxLen();
46
+ });
47
+ this.isNearLimit = computed(() => {
48
+ const len = this.body().length;
49
+ const max = this.maxLen();
50
+ return len >= max * 0.85 && len < max;
51
+ });
52
+ this.isAtLimit = computed(() => this.body().length >= this.maxLen());
53
+ this.placeholderText = computed(() => {
54
+ this.i18n.lang();
55
+ return this.props?.placeholder ?? this.i18n.t('placeholder', 'ChatInput');
56
+ });
57
+ this.sendLabel = computed(() => {
58
+ this.i18n.lang();
59
+ return this.i18n.t('send', 'ChatInput');
60
+ });
61
+ this.counterText = computed(() => {
62
+ this.i18n.lang();
63
+ return this.i18n.t('counter', 'ChatInput', {
64
+ count: String(this.body().length),
65
+ max: String(this.maxLen()),
66
+ });
67
+ });
68
+ this.i18n.registerDefaults('ChatInput', CHAT_INPUT_I18N);
69
+ }
70
+ onInput(event) {
71
+ const target = event.target;
72
+ this.body.set(target.value ?? '');
73
+ }
74
+ onKeydown(event) {
75
+ this.typing.emit();
76
+ if (event.key === 'Enter' && !event.shiftKey) {
77
+ event.preventDefault();
78
+ this.onSend();
79
+ }
80
+ }
81
+ onSend() {
82
+ const trimmed = this.body().trim();
83
+ if (!trimmed || trimmed.length > this.maxLen())
84
+ return;
85
+ this.send.emit(trimmed);
86
+ this.body.set('');
87
+ }
88
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
89
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ChatInputComponent, isStandalone: true, selector: "val-chat-input", inputs: { props: "props" }, outputs: { send: "send", typing: "typing" }, ngImport: i0, template: `
90
+ <div class="chat-input-wrapper">
91
+ <div class="textarea-wrap">
92
+ <ion-textarea
93
+ [placeholder]="placeholderText()"
94
+ [disabled]="props?.disabled ?? false"
95
+ [maxlength]="maxLen()"
96
+ [autoGrow]="true"
97
+ [rows]="1"
98
+ [value]="body()"
99
+ (ionInput)="onInput($event)"
100
+ (keydown)="onKeydown($event)"
101
+ ></ion-textarea>
102
+ <span class="char-counter" [class.near-limit]="isNearLimit()" [class.at-limit]="isAtLimit()">
103
+ {{ counterText() }}
104
+ </span>
105
+ </div>
106
+
107
+ <ion-button
108
+ class="send-btn"
109
+ shape="round"
110
+ [disabled]="!canSend()"
111
+ (click)="onSend()"
112
+ [attr.aria-label]="sendLabel()"
113
+ >
114
+ <ion-icon name="send-outline" slot="icon-only" aria-hidden="true"></ion-icon>
115
+ </ion-button>
116
+ </div>
117
+ `, isInline: true, styles: [".chat-input-wrapper{display:flex;align-items:flex-end;gap:8px;padding:8px 12px;background:var(--ion-card-background, var(--ion-background-color, #fff));border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .1))}.textarea-wrap{flex:1;position:relative}.textarea-wrap ion-textarea{--background: var(--ion-color-light, #f4f5f8);--border-radius: 20px;--padding-start: 14px;--padding-end: 14px;--padding-top: 8px;--padding-bottom: 8px;font-size:.9375rem;min-height:40px}.char-counter{position:absolute;bottom:4px;right:14px;font-size:.6875rem;color:var(--ion-color-medium, #92949c);pointer-events:none}.char-counter.near-limit{color:var(--ion-color-warning, #ffc409)}.char-counter.at-limit{color:var(--ion-color-danger, #eb445a)}.send-btn{--border-radius: 50%;--padding-start: 0;--padding-end: 0;width:40px;height:40px;flex-shrink:0;margin:0}.send-btn ion-icon{font-size:1.25rem}\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: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
118
+ }
119
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatInputComponent, decorators: [{
120
+ type: Component,
121
+ args: [{ selector: 'val-chat-input', standalone: true, imports: [CommonModule, IonTextarea, IonButton, IonIcon], template: `
122
+ <div class="chat-input-wrapper">
123
+ <div class="textarea-wrap">
124
+ <ion-textarea
125
+ [placeholder]="placeholderText()"
126
+ [disabled]="props?.disabled ?? false"
127
+ [maxlength]="maxLen()"
128
+ [autoGrow]="true"
129
+ [rows]="1"
130
+ [value]="body()"
131
+ (ionInput)="onInput($event)"
132
+ (keydown)="onKeydown($event)"
133
+ ></ion-textarea>
134
+ <span class="char-counter" [class.near-limit]="isNearLimit()" [class.at-limit]="isAtLimit()">
135
+ {{ counterText() }}
136
+ </span>
137
+ </div>
138
+
139
+ <ion-button
140
+ class="send-btn"
141
+ shape="round"
142
+ [disabled]="!canSend()"
143
+ (click)="onSend()"
144
+ [attr.aria-label]="sendLabel()"
145
+ >
146
+ <ion-icon name="send-outline" slot="icon-only" aria-hidden="true"></ion-icon>
147
+ </ion-button>
148
+ </div>
149
+ `, styles: [".chat-input-wrapper{display:flex;align-items:flex-end;gap:8px;padding:8px 12px;background:var(--ion-card-background, var(--ion-background-color, #fff));border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .1))}.textarea-wrap{flex:1;position:relative}.textarea-wrap ion-textarea{--background: var(--ion-color-light, #f4f5f8);--border-radius: 20px;--padding-start: 14px;--padding-end: 14px;--padding-top: 8px;--padding-bottom: 8px;font-size:.9375rem;min-height:40px}.char-counter{position:absolute;bottom:4px;right:14px;font-size:.6875rem;color:var(--ion-color-medium, #92949c);pointer-events:none}.char-counter.near-limit{color:var(--ion-color-warning, #ffc409)}.char-counter.at-limit{color:var(--ion-color-danger, #eb445a)}.send-btn{--border-radius: 50%;--padding-start: 0;--padding-end: 0;width:40px;height:40px;flex-shrink:0;margin:0}.send-btn ion-icon{font-size:1.25rem}\n"] }]
150
+ }], ctorParameters: () => [], propDecorators: { props: [{
151
+ type: Input
152
+ }], send: [{
153
+ type: Output
154
+ }], typing: [{
155
+ type: Output
156
+ }] } });
157
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC1pbnB1dC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvbW9sZWN1bGVzL2NoYXQtaW5wdXQvY2hhdC1pbnB1dC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNqRyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNwQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDOztBQUdyRCxRQUFRLENBQUMsRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO0FBRTFCLE1BQU0sZUFBZSxHQUFHO0lBQ3RCLEVBQUUsRUFBRTtRQUNGLFdBQVcsRUFBRSxvQkFBb0I7UUFDakMsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsZUFBZTtLQUN6QjtJQUNELEVBQUUsRUFBRTtRQUNGLFdBQVcsRUFBRSxpQkFBaUI7UUFDOUIsSUFBSSxFQUFFLE1BQU07UUFDWixPQUFPLEVBQUUsZUFBZTtLQUN6QjtDQUNGLENBQUM7QUFFRjs7Ozs7Ozs7Ozs7OztHQWFHO0FBb0NILE1BQU0sT0FBTyxrQkFBa0I7SUFVN0I7UUFUVSxTQUFJLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRTVCLFVBQUssR0FBc0IsRUFBRSxDQUFDO1FBRTdCLFNBQUksR0FBRyxJQUFJLFlB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LE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUFFLE9BQU87UUFDdkQsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEIsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDcEIsQ0FBQzsrR0FqRVUsa0JBQWtCO21HQUFsQixrQkFBa0IsbUpBL0JuQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTRCVCwwN0JBN0JTLFlBQVksK0JBQUUsV0FBVyxpYUFBRSxTQUFTLG9QQUFFLE9BQU87OzRGQWdDNUMsa0JBQWtCO2tCQW5DOUIsU0FBUzsrQkFDRSxnQkFBZ0IsY0FDZCxJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxPQUFPLENBQUMsWUFDOUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E0QlQ7d0RBTVEsS0FBSztzQkFBYixLQUFLO2dCQUVJLElBQUk7c0JBQWIsTUFBTTtnQkFDRyxNQUFNO3NCQUFmLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgaW5qZWN0LCBzaWduYWwsIGNvbXB1dGVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgSW9uVGV4dGFyZWEsIElvbkJ1dHRvbiwgSW9uSWNvbiB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyL3N0YW5kYWxvbmUnO1xuaW1wb3J0IHsgYWRkSWNvbnMgfSBmcm9tICdpb25pY29ucyc7XG5pbXBvcnQgeyBzZW5kT3V0bGluZSB9IGZyb20gJ2lvbmljb25zL2ljb25zJztcbmltcG9ydCB7IEkxOG5TZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvaTE4bic7XG5pbXBvcnQgeyBDaGF0SW5wdXRNZXRhZGF0YSwgQ2hhdElucHV0U2VuZEV2ZW50IH0gZnJvbSAnLi90eXBlcyc7XG5cbmFkZEljb25zKHsgc2VuZE91dGxpbmUgfSk7XG5cbmNvbnN0IENIQVRfSU5QVVRfSTE4TiA9IHtcbiAgZXM6IHtcbiAgICBwbGFjZWhvbGRlcjogJ0VzY3JpYmUgdW4gbWVuc2FqZScsXG4gICAgc2VuZDogJ0VudmlhcicsXG4gICAgY291bnRlcjogJ3tjb3VudH0ve21heH0nLFxuICB9LFxuICBlbjoge1xuICAgIHBsYWNlaG9sZGVyOiAnV3JpdGUgYSBtZXNzYWdlJyxcbiAgICBzZW5kOiAnU2VuZCcsXG4gICAgY291bnRlcjogJ3tjb3VudH0ve21heH0nLFxuICB9LFxufTtcblxuLyoqXG4gKiB2YWwtY2hhdC1pbnB1dFxuICpcbiAqIENhbXBvIGRlIGVudHJhZGEgcGFyYSBtZW5zYWplcyBkZSBjaGF0LiBUZXh0YXJlYSBhdXRvLWdyb3cgY29uIGNvbnRhZG9yXG4gKiBkZSBjYXJhY3RlcmVzIHkgYm90b24gZGUgZW52aWFyLiBFbWl0ZSBzZW5kKCkgYWwgcHVsc2FyIGVsIGJvdG9uIG8gRW50ZXJcbiAqIChzaW4gU2hpZnQpLCB5IHR5cGluZygpIGVuIGNhZGEga2V5ZG93bi5cbiAqXG4gKiBAZXhhbXBsZVxuICogPHZhbC1jaGF0LWlucHV0XG4gKiAgIFtwcm9wc109XCJ7IHBsYWNlaG9sZGVyOiAnTWVuc2FqZS4uLicsIG1heExlbmd0aDogMTAwMCB9XCJcbiAqICAgKHNlbmQpPVwib25TZW5kKCRldmVudClcIlxuICogICAodHlwaW5nKT1cIm9uVHlwaW5nKClcIlxuICogLz5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAndmFsLWNoYXQtaW5wdXQnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBJb25UZXh0YXJlYSwgSW9uQnV0dG9uLCBJb25JY29uXSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwiY2hhdC1pbnB1dC13cmFwcGVyXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwidGV4dGFyZWEtd3JhcFwiPlxuICAgICAgICA8aW9uLXRleHRhcmVhXG4gICAgICAgICAgW3BsYWNlaG9sZGVyXT1cInBsYWNlaG9sZGVyVGV4dCgpXCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwicHJvcHM/LmRpc2FibGVkID8/IGZhbHNlXCJcbiAgICAgICAgICBbbWF4bGVuZ3RoXT1cIm1heExlbigpXCJcbiAgICAgICAgICBbYXV0b0dyb3ddPVwidHJ1ZVwiXG4gICAgICAgICAgW3Jvd3NdPVwiMVwiXG4gICAgICAgICAgW3ZhbHVlXT1cImJvZHkoKVwiXG4gICAgICAgICAgKGlvbklucHV0KT1cIm9uSW5wdXQoJGV2ZW50KVwiXG4gICAgICAgICAgKGtleWRvd24pPVwib25LZXlkb3duKCRldmVudClcIlxuICAgICAgICA+PC9pb24tdGV4dGFyZWE+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwiY2hhci1jb3VudGVyXCIgW2NsYXNzLm5lYXItbGltaXRdPVwiaXNOZWFyTGltaXQoKVwiIFtjbGFzcy5hdC1saW1pdF09XCJpc0F0TGltaXQoKVwiPlxuICAgICAgICAgIHt7IGNvdW50ZXJUZXh0KCkgfX1cbiAgICAgICAgPC9zcGFuPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgIGNsYXNzPVwic2VuZC1idG5cIlxuICAgICAgICBzaGFwZT1cInJvdW5kXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cIiFjYW5TZW5kKClcIlxuICAgICAgICAoY2xpY2spPVwib25TZW5kKClcIlxuICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cInNlbmRMYWJlbCgpXCJcbiAgICAgID5cbiAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJzZW5kLW91dGxpbmVcIiBzbG90PVwiaWNvbi1vbmx5XCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+PC9pb24taWNvbj5cbiAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICA8L2Rpdj5cbiAgYCxcbiAgc3R5bGVVcmxzOiBbJy4vY2hhdC1pbnB1dC5jb21wb25lbnQuc2NzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBDaGF0SW5wdXRDb21wb25lbnQge1xuICBwcm90ZWN0ZWQgaTE4biA9IGluamVjdChJMThuU2VydmljZSk7XG5cbiAgQElucHV0KCkgcHJvcHM6IENoYXRJbnB1dE1ldGFkYXRhID0ge307XG5cbiAgQE91dHB1dCgpIHNlbmQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcbiAgQE91dHB1dCgpIHR5cGluZyA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICBwcm90ZWN0ZWQgYm9keSA9IHNpZ25hbCgnJyk7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5pMThuLnJlZ2lzdGVyRGVmYXVsdHMoJ0NoYXRJbnB1dCcsIENIQVRfSU5QVVRfSTE4Tik7XG4gIH1cblxuICBwcm90ZWN0ZWQgbWF4TGVuID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5wcm9wcz8ubWF4TGVuZ3RoID8/IDIwMDApO1xuXG4gIHByb3RlY3RlZCBjYW5TZW5kID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IHRyaW1tZWQgPSB0aGlzLmJvZHkoKS50cmltKCk7XG4gICAgcmV0dXJuIHRyaW1tZWQubGVuZ3RoID4gMCAmJiB0cmltbWVkLmxlbmd0aCA8PSB0aGlzLm1heExlbigpO1xuICB9KTtcblxuICBwcm90ZWN0ZWQgaXNOZWFyTGltaXQgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgY29uc3QgbGVuID0gdGhpcy5ib2R5KCkubGVuZ3RoO1xuICAgIGNvbnN0IG1heCA9IHRoaXMubWF4TGVuKCk7XG4gICAgcmV0dXJuIGxlbiA+PSBtYXggKiAwLjg1ICYmIGxlbiA8IG1heDtcbiAgfSk7XG5cbiAgcHJvdGVjdGVkIGlzQXRMaW1pdCA9IGNvbXB1dGVkKCgpID0+IHRoaXMuYm9keSgpLmxlbmd0aCA+PSB0aGlzLm1heExlbigpKTtcblxuICBwcm90ZWN0ZWQgcGxhY2Vob2xkZXJUZXh0ID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIHRoaXMuaTE4bi5sYW5nKCk7XG4gICAgcmV0dXJuIHRoaXMucHJvcHM/LnBsYWNlaG9sZGVyID8/IHRoaXMuaTE4bi50KCdwbGFjZWhvbGRlcicsICdDaGF0SW5wdXQnKTtcbiAgfSk7XG5cbiAgcHJvdGVjdGVkIHNlbmRMYWJlbCA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICB0aGlzLmkxOG4ubGFuZygpO1xuICAgIHJldHVybiB0aGlzLmkxOG4udCgnc2VuZCcsICdDaGF0SW5wdXQnKTtcbiAgfSk7XG5cbiAgcHJvdGVjdGVkIGNvdW50ZXJUZXh0ID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIHRoaXMuaTE4bi5sYW5nKCk7XG4gICAgcmV0dXJuIHRoaXMuaTE4bi50KCdjb3VudGVyJywgJ0NoYXRJbnB1dCcsIHtcbiAgICAgIGNvdW50OiBTdHJpbmcodGhpcy5ib2R5KCkubGVuZ3RoKSxcbiAgICAgIG1heDogU3RyaW5nKHRoaXMubWF4TGVuKCkpLFxuICAgIH0pO1xuICB9KTtcblxuICBwcm90ZWN0ZWQgb25JbnB1dChldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQgYXMgSFRNTElvblRleHRhcmVhRWxlbWVudDtcbiAgICB0aGlzLmJvZHkuc2V0KHRhcmdldC52YWx1ZSA/PyAnJyk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25LZXlkb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgdGhpcy50eXBpbmcuZW1pdCgpO1xuICAgIGlmIChldmVudC5rZXkgPT09ICdFbnRlcicgJiYgIWV2ZW50LnNoaWZ0S2V5KSB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgdGhpcy5vblNlbmQoKTtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgb25TZW5kKCk6IHZvaWQge1xuICAgIGNvbnN0IHRyaW1tZWQgPSB0aGlzLmJvZHkoKS50cmltKCk7XG4gICAgaWYgKCF0cmltbWVkIHx8IHRyaW1tZWQubGVuZ3RoID4gdGhpcy5tYXhMZW4oKSkgcmV0dXJuO1xuICAgIHRoaXMuc2VuZC5lbWl0KHRyaW1tZWQpO1xuICAgIHRoaXMuYm9keS5zZXQoJycpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvbW9sZWN1bGVzL2NoYXQtaW5wdXQvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29uZmlndXJhY2lvbiBkZWwgY29tcG9uZW50ZSBkZSBpbnB1dCBkZSBjaGF0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENoYXRJbnB1dE1ldGFkYXRhIHtcbiAgLyoqIFBsYWNlaG9sZGVyIGRlbCB0ZXh0YXJlYSAob3BjaW9uYWwpLiAqL1xuICBwbGFjZWhvbGRlcj86IHN0cmluZztcbiAgLyoqIFNpIGVsIGlucHV0IGVzdGEgZGVzaGFiaWxpdGFkby4gKi9cbiAgZGlzYWJsZWQ/OiBib29sZWFuO1xuICAvKiogQ2FudGlkYWQgbWF4aW1hIGRlIGNhcmFjdGVyZXMgKGRlZmF1bHQ6IDIwMDApLiAqL1xuICBtYXhMZW5ndGg/OiBudW1iZXI7XG4gIC8qKiBTaSBzZSBwZXJtaXRlbiBhcmNoaXZvcyBhZGp1bnRvcyAobm8gaW1wbGVtZW50YWRvIGVuIGVzdGEgdmVyc2lvbikuICovXG4gIGFsbG93QXR0YWNobWVudHM/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEV2ZW50byBlbWl0aWRvIGFsIGVudmlhciB1biBtZW5zYWplLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENoYXRJbnB1dFNlbmRFdmVudCB7XG4gIC8qKiBDdWVycG8gZGVsIG1lbnNhamUuICovXG4gIGJvZHk6IHN0cmluZztcbn1cbiJdfQ==
@@ -0,0 +1,244 @@
1
+ import { Component, Input, Output, EventEmitter, inject } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { IonIcon, IonButton } from '@ionic/angular/standalone';
4
+ import { addIcons } from 'ionicons';
5
+ import { checkmark, checkmarkDone, timeOutline, alertCircle, pencil, trash, returnDownBackOutline, } from 'ionicons/icons';
6
+ import { I18nService } from '../../../services/i18n';
7
+ import * as i0 from "@angular/core";
8
+ addIcons({
9
+ checkmark,
10
+ checkmarkDone,
11
+ timeOutline,
12
+ alertCircle,
13
+ pencil,
14
+ trash,
15
+ returnDownBackOutline,
16
+ });
17
+ const CHAT_I18N = {
18
+ es: {
19
+ messageDeleted: '[mensaje eliminado]',
20
+ edited: '(editado)',
21
+ react: 'Reaccionar',
22
+ reply: 'Responder',
23
+ edit: 'Editar',
24
+ delete: 'Eliminar',
25
+ },
26
+ en: {
27
+ messageDeleted: '[message deleted]',
28
+ edited: '(edited)',
29
+ react: 'React',
30
+ reply: 'Reply',
31
+ edit: 'Edit',
32
+ delete: 'Delete',
33
+ },
34
+ };
35
+ /**
36
+ * val-message-bubble
37
+ *
38
+ * Burbuja de mensaje para el chat. Alineada a la derecha si isMine, a la izquierda si no.
39
+ * Muestra nombre del emisor, cuerpo, timestamp, estado de envio, reacciones y acciones.
40
+ * Si el mensaje fue eliminado muestra un texto en gris sin acciones.
41
+ *
42
+ * @example
43
+ * <val-message-bubble
44
+ * [props]="msg"
45
+ * (reactionClick)="onReaction($event)"
46
+ * (replyClick)="onReply($event)"
47
+ * (deleteClick)="onDelete($event)"
48
+ * />
49
+ */
50
+ export class MessageBubbleComponent {
51
+ constructor() {
52
+ this.i18n = inject(I18nService);
53
+ this.reactionClick = new EventEmitter();
54
+ this.replyClick = new EventEmitter();
55
+ this.deleteClick = new EventEmitter();
56
+ this.editClick = new EventEmitter();
57
+ if (!this.i18n.hasNamespace('Chat')) {
58
+ this.i18n.registerDefaults('Chat', CHAT_I18N);
59
+ }
60
+ }
61
+ ngOnInit() { }
62
+ deletedText() {
63
+ this.i18n.lang();
64
+ return this.i18n.t('messageDeleted', 'Chat');
65
+ }
66
+ editedLabel() {
67
+ this.i18n.lang();
68
+ return this.i18n.t('edited', 'Chat');
69
+ }
70
+ formatTime(date) {
71
+ if (!date)
72
+ return '';
73
+ const d = date instanceof Date ? date : new Date(date);
74
+ return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
75
+ }
76
+ statusIcon() {
77
+ switch (this.props.status) {
78
+ case 'sending':
79
+ return 'time-outline';
80
+ case 'failed':
81
+ return 'alert-circle';
82
+ case 'sent':
83
+ default:
84
+ return 'checkmark';
85
+ }
86
+ }
87
+ onReactionClick(reaction) {
88
+ this.reactionClick.emit({ token: reaction.token, msgId: this.props.msgId });
89
+ }
90
+ onReplyClick() {
91
+ this.replyClick.emit({ msgId: this.props.msgId });
92
+ }
93
+ onDeleteClick() {
94
+ this.deleteClick.emit({ msgId: this.props.msgId });
95
+ }
96
+ onEditClick() {
97
+ this.editClick.emit({ msgId: this.props.msgId });
98
+ }
99
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MessageBubbleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
100
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: MessageBubbleComponent, isStandalone: true, selector: "val-message-bubble", inputs: { props: "props" }, outputs: { reactionClick: "reactionClick", replyClick: "replyClick", deleteClick: "deleteClick", editClick: "editClick" }, ngImport: i0, template: `
101
+ <div class="message-bubble-wrapper" [class.is-mine]="props.isMine">
102
+ @if (!props.isMine && !props.isDeleted) {
103
+ <span class="sender-name">{{ props.senderName }}</span>
104
+ }
105
+
106
+ <div class="bubble">
107
+ @if (props.replyTo && !props.isDeleted) {
108
+ <div class="reply-preview">
109
+ <div class="reply-sender">{{ props.replyTo.senderName }}</div>
110
+ <div class="reply-body">{{ props.replyTo.body }}</div>
111
+ </div>
112
+ }
113
+
114
+ @if (props.isDeleted) {
115
+ <span class="deleted-text">{{ deletedText() }}</span>
116
+ } @else {
117
+ <div class="bubble-body">{{ props.body }}</div>
118
+ }
119
+
120
+ <div class="bubble-meta">
121
+ <span class="timestamp">{{ formatTime(props.createdAt) }}</span>
122
+ @if (props.isEdited && !props.isDeleted) {
123
+ <span class="edited-label">{{ editedLabel() }}</span>
124
+ }
125
+ @if (props.isMine && props.status) {
126
+ <ion-icon
127
+ [name]="statusIcon()"
128
+ [class]="'status-icon ' + (props.status ?? '')"
129
+ aria-hidden="true"
130
+ ></ion-icon>
131
+ }
132
+ </div>
133
+ </div>
134
+
135
+ @if (!props.isDeleted && props.reactions && props.reactions.length > 0) {
136
+ <div class="reactions-bar">
137
+ @for (reaction of props.reactions; track reaction.token) {
138
+ <button class="reaction-btn" [class.active]="reaction.active" (click)="onReactionClick(reaction)">
139
+ <span>{{ reaction.token }}</span>
140
+ @if (reaction.count > 0) {
141
+ <span class="reaction-count">{{ reaction.count }}</span>
142
+ }
143
+ </button>
144
+ }
145
+ </div>
146
+ }
147
+
148
+ @if (!props.isDeleted) {
149
+ <div class="bubble-actions">
150
+ <ion-button fill="clear" size="small" (click)="onReplyClick()">
151
+ <ion-icon name="return-down-back-outline" slot="icon-only" aria-hidden="true"></ion-icon>
152
+ </ion-button>
153
+ @if (props.isMine) {
154
+ <ion-button fill="clear" size="small" (click)="onEditClick()">
155
+ <ion-icon name="pencil" slot="icon-only" aria-hidden="true"></ion-icon>
156
+ </ion-button>
157
+ <ion-button fill="clear" size="small" color="danger" (click)="onDeleteClick()">
158
+ <ion-icon name="trash" slot="icon-only" aria-hidden="true"></ion-icon>
159
+ </ion-button>
160
+ }
161
+ </div>
162
+ }
163
+ </div>
164
+ `, isInline: true, styles: [".message-bubble-wrapper{display:flex;flex-direction:column;align-items:flex-start;margin-bottom:4px}.message-bubble-wrapper.is-mine{align-items:flex-end}.message-bubble-wrapper.is-mine .bubble{background:var(--ion-color-primary);color:#fff;border-radius:18px 18px 4px}.message-bubble-wrapper.is-mine .bubble-meta{justify-content:flex-end}.message-bubble-wrapper:not(.is-mine) .bubble{background:var(--ion-card-background, var(--ion-background-color, #fff));color:var(--ion-text-color, #000);border-radius:18px 18px 18px 4px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08))}.sender-name{font-size:.75rem;font-weight:600;color:var(--ion-color-medium, #92949c);margin:0 0 2px 12px}.bubble{max-width:75%;min-width:60px;padding:10px 14px;word-break:break-word;position:relative;box-shadow:0 1px 2px #0000000f}.reply-preview{background:#0000000f;border-left:3px solid var(--ion-color-primary);border-radius:6px;padding:6px 8px;margin-bottom:6px;font-size:.75rem;opacity:.85}.reply-preview .reply-sender{font-weight:700;margin-bottom:2px}.reply-preview .reply-body{opacity:.8;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px}.bubble-body{font-size:.9375rem;line-height:1.4;white-space:pre-wrap}.deleted-text{font-size:.875rem;font-style:italic;opacity:.6}.bubble-meta{display:flex;align-items:center;gap:4px;margin-top:4px;font-size:.6875rem;opacity:.7}.edited-label{font-style:italic}.status-icon{font-size:.75rem}.status-icon.sending{color:var(--ion-color-medium)}.status-icon.sent{color:#fff}.status-icon.failed{color:var(--ion-color-danger)}.reactions-bar{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.reactions-bar .reaction-btn{display:inline-flex;align-items:center;gap:3px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));border-radius:12px;padding:2px 8px;font-size:.8125rem;cursor:pointer;transition:background .15s ease}.reactions-bar .reaction-btn.active{background:var(--ion-color-primary-tint, #4c8dff);color:#fff;border-color:var(--ion-color-primary)}.reactions-bar .reaction-btn .reaction-count{font-weight:600}.bubble-actions{display:flex;gap:4px;margin-top:2px}.bubble-actions ion-button{--padding-start: 6px;--padding-end: 6px;font-size:.75rem}\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: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }] }); }
165
+ }
166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MessageBubbleComponent, decorators: [{
167
+ type: Component,
168
+ args: [{ selector: 'val-message-bubble', standalone: true, imports: [CommonModule, IonIcon, IonButton], template: `
169
+ <div class="message-bubble-wrapper" [class.is-mine]="props.isMine">
170
+ @if (!props.isMine && !props.isDeleted) {
171
+ <span class="sender-name">{{ props.senderName }}</span>
172
+ }
173
+
174
+ <div class="bubble">
175
+ @if (props.replyTo && !props.isDeleted) {
176
+ <div class="reply-preview">
177
+ <div class="reply-sender">{{ props.replyTo.senderName }}</div>
178
+ <div class="reply-body">{{ props.replyTo.body }}</div>
179
+ </div>
180
+ }
181
+
182
+ @if (props.isDeleted) {
183
+ <span class="deleted-text">{{ deletedText() }}</span>
184
+ } @else {
185
+ <div class="bubble-body">{{ props.body }}</div>
186
+ }
187
+
188
+ <div class="bubble-meta">
189
+ <span class="timestamp">{{ formatTime(props.createdAt) }}</span>
190
+ @if (props.isEdited && !props.isDeleted) {
191
+ <span class="edited-label">{{ editedLabel() }}</span>
192
+ }
193
+ @if (props.isMine && props.status) {
194
+ <ion-icon
195
+ [name]="statusIcon()"
196
+ [class]="'status-icon ' + (props.status ?? '')"
197
+ aria-hidden="true"
198
+ ></ion-icon>
199
+ }
200
+ </div>
201
+ </div>
202
+
203
+ @if (!props.isDeleted && props.reactions && props.reactions.length > 0) {
204
+ <div class="reactions-bar">
205
+ @for (reaction of props.reactions; track reaction.token) {
206
+ <button class="reaction-btn" [class.active]="reaction.active" (click)="onReactionClick(reaction)">
207
+ <span>{{ reaction.token }}</span>
208
+ @if (reaction.count > 0) {
209
+ <span class="reaction-count">{{ reaction.count }}</span>
210
+ }
211
+ </button>
212
+ }
213
+ </div>
214
+ }
215
+
216
+ @if (!props.isDeleted) {
217
+ <div class="bubble-actions">
218
+ <ion-button fill="clear" size="small" (click)="onReplyClick()">
219
+ <ion-icon name="return-down-back-outline" slot="icon-only" aria-hidden="true"></ion-icon>
220
+ </ion-button>
221
+ @if (props.isMine) {
222
+ <ion-button fill="clear" size="small" (click)="onEditClick()">
223
+ <ion-icon name="pencil" slot="icon-only" aria-hidden="true"></ion-icon>
224
+ </ion-button>
225
+ <ion-button fill="clear" size="small" color="danger" (click)="onDeleteClick()">
226
+ <ion-icon name="trash" slot="icon-only" aria-hidden="true"></ion-icon>
227
+ </ion-button>
228
+ }
229
+ </div>
230
+ }
231
+ </div>
232
+ `, styles: [".message-bubble-wrapper{display:flex;flex-direction:column;align-items:flex-start;margin-bottom:4px}.message-bubble-wrapper.is-mine{align-items:flex-end}.message-bubble-wrapper.is-mine .bubble{background:var(--ion-color-primary);color:#fff;border-radius:18px 18px 4px}.message-bubble-wrapper.is-mine .bubble-meta{justify-content:flex-end}.message-bubble-wrapper:not(.is-mine) .bubble{background:var(--ion-card-background, var(--ion-background-color, #fff));color:var(--ion-text-color, #000);border-radius:18px 18px 18px 4px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .08))}.sender-name{font-size:.75rem;font-weight:600;color:var(--ion-color-medium, #92949c);margin:0 0 2px 12px}.bubble{max-width:75%;min-width:60px;padding:10px 14px;word-break:break-word;position:relative;box-shadow:0 1px 2px #0000000f}.reply-preview{background:#0000000f;border-left:3px solid var(--ion-color-primary);border-radius:6px;padding:6px 8px;margin-bottom:6px;font-size:.75rem;opacity:.85}.reply-preview .reply-sender{font-weight:700;margin-bottom:2px}.reply-preview .reply-body{opacity:.8;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px}.bubble-body{font-size:.9375rem;line-height:1.4;white-space:pre-wrap}.deleted-text{font-size:.875rem;font-style:italic;opacity:.6}.bubble-meta{display:flex;align-items:center;gap:4px;margin-top:4px;font-size:.6875rem;opacity:.7}.edited-label{font-style:italic}.status-icon{font-size:.75rem}.status-icon.sending{color:var(--ion-color-medium)}.status-icon.sent{color:#fff}.status-icon.failed{color:var(--ion-color-danger)}.reactions-bar{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.reactions-bar .reaction-btn{display:inline-flex;align-items:center;gap:3px;background:var(--ion-card-background, var(--ion-background-color, #fff));border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));border-radius:12px;padding:2px 8px;font-size:.8125rem;cursor:pointer;transition:background .15s ease}.reactions-bar .reaction-btn.active{background:var(--ion-color-primary-tint, #4c8dff);color:#fff;border-color:var(--ion-color-primary)}.reactions-bar .reaction-btn .reaction-count{font-weight:600}.bubble-actions{display:flex;gap:4px;margin-top:2px}.bubble-actions ion-button{--padding-start: 6px;--padding-end: 6px;font-size:.75rem}\n"] }]
233
+ }], ctorParameters: () => [], propDecorators: { props: [{
234
+ type: Input
235
+ }], reactionClick: [{
236
+ type: Output
237
+ }], replyClick: [{
238
+ type: Output
239
+ }], deleteClick: [{
240
+ type: Output
241
+ }], editClick: [{
242
+ type: Output
243
+ }] } });
244
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZS1idWJibGUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL21vbGVjdWxlcy9tZXNzYWdlLWJ1YmJsZS9tZXNzYWdlLWJ1YmJsZS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQVUsTUFBTSxlQUFlLENBQUM7QUFDdkYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDL0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNwQyxPQUFPLEVBQ0wsU0FBUyxFQUNULGFBQWEsRUFDYixXQUFXLEVBQ1gsV0FBVyxFQUNYLE1BQU0sRUFDTixLQUFLLEVBQ0wscUJBQXFCLEdBQ3RCLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDOztBQVVyRCxRQUFRLENBQUM7SUFDUCxTQUFTO0lBQ1QsYUFBYTtJQUNiLFdBQVc7SUFDWCxXQUFXO0lBQ1gsTUFBTTtJQUNOLEtBQUs7SUFDTCxxQkFBcUI7Q0FDdEIsQ0FBQyxDQUFDO0FBRUgsTUFBTSxTQUFTLEdBQUc7SUFDaEIsRUFBRSxFQUFFO1FBQ0YsY0FBYyxFQUFFLHFCQUFxQjtRQUNyQyxNQUFNLEVBQUUsV0FBVztRQUNuQixLQUFLLEVBQUUsWUFBWTtRQUNuQixLQUFLLEVBQUUsV0FBVztRQUNsQixJQUFJLEVBQUUsUUFBUTtRQUNkLE1BQU0sRUFBRSxVQUFVO0tBQ25CO0lBQ0QsRUFBRSxFQUFFO1FBQ0YsY0FBYyxFQUFFLG1CQUFtQjtRQUNuQyxNQUFNLEVBQUUsVUFBVTtRQUNsQixL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Ozs7Ozs7Ozs7Ozs7R0FnRVQsc3pFQWpFUyxZQUFZLCtCQUFFLE9BQU8sMkpBQUUsU0FBUzs7NEZBb0UvQixzQkFBc0I7a0JBdkVsQyxTQUFTOytCQUNFLG9CQUFvQixjQUNsQixJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsT0FBTyxFQUFFLFNBQVMsQ0FBQyxZQUNqQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWdFVDt3REFNUSxLQUFLO3NCQUFiLEtBQUs7Z0JBRUksYUFBYTtzQkFBdEIsTUFBTTtnQkFDRyxVQUFVO3NCQUFuQixNQUFNO2dCQUNHLFdBQVc7c0JBQXBCLE1BQU07Z0JBQ0csU0FBUztzQkFBbEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBpbmplY3QsIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IElvbkljb24sIElvbkJ1dHRvbiB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyL3N0YW5kYWxvbmUnO1xuaW1wb3J0IHsgYWRkSWNvbnMgfSBmcm9tICdpb25pY29ucyc7XG5pbXBvcnQge1xuICBjaGVja21hcmssXG4gIGNoZWNrbWFya0RvbmUsXG4gIHRpbWVPdXRsaW5lLFxuICBhbGVydENpcmNsZSxcbiAgcGVuY2lsLFxuICB0cmFzaCxcbiAgcmV0dXJuRG93bkJhY2tPdXRsaW5lLFxufSBmcm9tICdpb25pY29ucy9pY29ucyc7XG5pbXBvcnQgeyBJMThuU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2kxOG4nO1xuaW1wb3J0IHtcbiAgTWVzc2FnZUJ1YmJsZU1ldGFkYXRhLFxuICBNZXNzYWdlUmVhY3Rpb25DbGlja0V2ZW50LFxuICBNZXNzYWdlUmVwbHlDbGlja0V2ZW50LFxuICBNZXNzYWdlRGVsZXRlQ2xpY2tFdmVudCxcbiAgTWVzc2FnZUVkaXRDbGlja0V2ZW50LFxufSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7IE1lc3NhZ2VSZWFjdGlvbiB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2NoYXQvdHlwZXMnO1xuXG5hZGRJY29ucyh7XG4gIGNoZWNrbWFyayxcbiAgY2hlY2ttYXJrRG9uZSxcbiAgdGltZU91dGxpbmUsXG4gIGFsZXJ0Q2lyY2xlLFxuICBwZW5jaWwsXG4gIHRyYXNoLFxuICByZXR1cm5Eb3duQmFja091dGxpbmUsXG59KTtcblxuY29uc3QgQ0hBVF9JMThOID0ge1xuICBlczoge1xuICAgIG1lc3NhZ2VEZWxldGVkOiAnW21lbnNhamUgZWxpbWluYWRvXScsXG4gICAgZWRpdGVkOiAnKGVkaXRhZG8pJyxcbiAgICByZWFjdDogJ1JlYWNjaW9uYXInLFxuICAgIHJlcGx5OiAnUmVzcG9uZGVyJyxcbiAgICBlZGl0OiAnRWRpdGFyJyxcbiAgICBkZWxldGU6ICdFbGltaW5hcicsXG4gIH0sXG4gIGVuOiB7XG4gICAgbWVzc2FnZURlbGV0ZWQ6ICdbbWVzc2FnZSBkZWxldGVkXScsXG4gICAgZWRpdGVkOiAnKGVkaXRlZCknLFxuICAgIHJlYWN0OiAnUmVhY3QnLFxuICAgIHJlcGx5OiAnUmVwbHknLFxuICAgIGVkaXQ6ICdFZGl0JyxcbiAgICBkZWxldGU6ICdEZWxldGUnLFxuICB9LFxufTtcblxuLyoqXG4gKiB2YWwtbWVzc2FnZS1idWJibGVcbiAqXG4gKiBCdXJidWphIGRlIG1lbnNhamUgcGFyYSBlbCBjaGF0LiBBbGluZWFkYSBhIGxhIGRlcmVjaGEgc2kgaXNNaW5lLCBhIGxhIGl6cXVpZXJkYSBzaSBuby5cbiAqIE11ZXN0cmEgbm9tYnJlIGRlbCBlbWlzb3IsIGN1ZXJwbywgdGltZXN0YW1wLCBlc3RhZG8gZGUgZW52aW8sIHJlYWNjaW9uZXMgeSBhY2Npb25lcy5cbiAqIFNpIGVsIG1lbnNhamUgZnVlIGVsaW1pbmFkbyBtdWVzdHJhIHVuIHRleHRvIGVuIGdyaXMgc2luIGFjY2lvbmVzLlxuICpcbiAqIEBleGFtcGxlXG4gKiA8dmFsLW1lc3NhZ2UtYnViYmxlXG4gKiAgIFtwcm9wc109XCJtc2dcIlxuICogICAocmVhY3Rpb25DbGljayk9XCJvblJlYWN0aW9uKCRldmVudClcIlxuICogICAocmVwbHlDbGljayk9XCJvblJlcGx5KCRldmVudClcIlxuICogICAoZGVsZXRlQ2xpY2spPVwib25EZWxldGUoJGV2ZW50KVwiXG4gKiAvPlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd2YWwtbWVzc2FnZS1idWJibGUnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBJb25JY29uLCBJb25CdXR0b25dLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgY2xhc3M9XCJtZXNzYWdlLWJ1YmJsZS13cmFwcGVyXCIgW2NsYXNzLmlzLW1pbmVdPVwicHJvcHMuaXNNaW5lXCI+XG4gICAgICBAaWYgKCFwcm9wcy5pc01pbmUgJiYgIXByb3BzLmlzRGVsZXRlZCkge1xuICAgICAgICA8c3BhbiBjbGFzcz1cInNlbmRlci1uYW1lXCI+e3sgcHJvcHMuc2VuZGVyTmFtZSB9fTwvc3Bhbj5cbiAgICAgIH1cblxuICAgICAgPGRpdiBjbGFzcz1cImJ1YmJsZVwiPlxuICAgICAgICBAaWYgKHByb3BzLnJlcGx5VG8gJiYgIXByb3BzLmlzRGVsZXRlZCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJyZXBseS1wcmV2aWV3XCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwicmVwbHktc2VuZGVyXCI+e3sgcHJvcHMucmVwbHlUby5zZW5kZXJOYW1lIH19PC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwicmVwbHktYm9keVwiPnt7IHByb3BzLnJlcGx5VG8uYm9keSB9fTwvZGl2PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG5cbiAgICAgICAgQGlmIChwcm9wcy5pc0RlbGV0ZWQpIHtcbiAgICAgICAgICA8c3BhbiBjbGFzcz1cImRlbGV0ZWQtdGV4dFwiPnt7IGRlbGV0ZWRUZXh0KCkgfX08L3NwYW4+XG4gICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJidWJibGUtYm9keVwiPnt7IHByb3BzLmJvZHkgfX08L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJidWJibGUtbWV0YVwiPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGltZXN0YW1wXCI+e3sgZm9ybWF0VGltZShwcm9wcy5jcmVhdGVkQXQpIH19PC9zcGFuPlxuICAgICAgICAgIEBpZiAocHJvcHMuaXNFZGl0ZWQgJiYgIXByb3BzLmlzRGVsZXRlZCkge1xuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJlZGl0ZWQtbGFiZWxcIj57eyBlZGl0ZWRMYWJlbCgpIH19PC9zcGFuPlxuICAgICAgICAgIH1cbiAgICAgICAgICBAaWYgKHByb3BzLmlzTWluZSAmJiBwcm9wcy5zdGF0dXMpIHtcbiAgICAgICAgICAgIDxpb24taWNvblxuICAgICAgICAgICAgICBbbmFtZV09XCJzdGF0dXNJY29uKClcIlxuICAgICAgICAgICAgICBbY2xhc3NdPVwiJ3N0YXR1cy1pY29uICcgKyAocHJvcHMuc3RhdHVzID8/ICcnKVwiXG4gICAgICAgICAgICAgIGFyaWEtaGlkZGVuPVwidHJ1ZVwiXG4gICAgICAgICAgICA+PC9pb24taWNvbj5cbiAgICAgICAgICB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIEBpZiAoIXByb3BzLmlzRGVsZXRlZCAmJiBwcm9wcy5yZWFjdGlvbnMgJiYgcHJvcHMucmVhY3Rpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgPGRpdiBjbGFzcz1cInJlYWN0aW9ucy1iYXJcIj5cbiAgICAgICAgICBAZm9yIChyZWFjdGlvbiBvZiBwcm9wcy5yZWFjdGlvbnM7IHRyYWNrIHJlYWN0aW9uLnRva2VuKSB7XG4gICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwicmVhY3Rpb24tYnRuXCIgW2NsYXNzLmFjdGl2ZV09XCJyZWFjdGlvbi5hY3RpdmVcIiAoY2xpY2spPVwib25SZWFjdGlvbkNsaWNrKHJlYWN0aW9uKVwiPlxuICAgICAgICAgICAgICA8c3Bhbj57eyByZWFjdGlvbi50b2tlbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgQGlmIChyZWFjdGlvbi5jb3VudCA+IDApIHtcbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInJlYWN0aW9uLWNvdW50XCI+e3sgcmVhY3Rpb24uY291bnQgfX08L3NwYW4+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIH1cbiAgICAgICAgPC9kaXY+XG4gICAgICB9XG5cbiAgICAgIEBpZiAoIXByb3BzLmlzRGVsZXRlZCkge1xuICAgICAgICA8ZGl2IGNsYXNzPVwiYnViYmxlLWFjdGlvbnNcIj5cbiAgICAgICAgICA8aW9uLWJ1dHRvbiBmaWxsPVwiY2xlYXJcIiBzaXplPVwic21hbGxcIiAoY2xpY2spPVwib25SZXBseUNsaWNrKClcIj5cbiAgICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwicmV0dXJuLWRvd24tYmFjay1vdXRsaW5lXCIgc2xvdD1cImljb24tb25seVwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPjwvaW9uLWljb24+XG4gICAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICAgIEBpZiAocHJvcHMuaXNNaW5lKSB7XG4gICAgICAgICAgICA8aW9uLWJ1dHRvbiBmaWxsPVwiY2xlYXJcIiBzaXplPVwic21hbGxcIiAoY2xpY2spPVwib25FZGl0Q2xpY2soKVwiPlxuICAgICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cInBlbmNpbFwiIHNsb3Q9XCJpY29uLW9ubHlcIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICAgICAgPGlvbi1idXR0b24gZmlsbD1cImNsZWFyXCIgc2l6ZT1cInNtYWxsXCIgY29sb3I9XCJkYW5nZXJcIiAoY2xpY2spPVwib25EZWxldGVDbGljaygpXCI+XG4gICAgICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwidHJhc2hcIiBzbG90PVwiaWNvbi1vbmx5XCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+PC9pb24taWNvbj5cbiAgICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgICAgICB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgfVxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZVVybHM6IFsnLi9tZXNzYWdlLWJ1YmJsZS5jb21wb25lbnQuc2NzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBNZXNzYWdlQnViYmxlQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgcHJvdGVjdGVkIGkxOG4gPSBpbmplY3QoSTE4blNlcnZpY2UpO1xuXG4gIEBJbnB1dCgpIHByb3BzITogTWVzc2FnZUJ1YmJsZU1ldGFkYXRhO1xuXG4gIEBPdXRwdXQoKSByZWFjdGlvbkNsaWNrID0gbmV3IEV2ZW50RW1pdHRlcjxNZXNzYWdlUmVhY3Rpb25DbGlja0V2ZW50PigpO1xuICBAT3V0cHV0KCkgcmVwbHlDbGljayA9IG5ldyBFdmVudEVtaXR0ZXI8TWVzc2FnZVJlcGx5Q2xpY2tFdmVudD4oKTtcbiAgQE91dHB1dCgpIGRlbGV0ZUNsaWNrID0gbmV3IEV2ZW50RW1pdHRlcjxNZXNzYWdlRGVsZXRlQ2xpY2tFdmVudD4oKTtcbiAgQE91dHB1dCgpIGVkaXRDbGljayA9IG5ldyBFdmVudEVtaXR0ZXI8TWVzc2FnZUVkaXRDbGlja0V2ZW50PigpO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIGlmICghdGhpcy5pMThuLmhhc05hbWVzcGFjZSgnQ2hhdCcpKSB7XG4gICAgICB0aGlzLmkxOG4ucmVnaXN0ZXJEZWZhdWx0cygnQ2hhdCcsIENIQVRfSTE4Tik7XG4gICAgfVxuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7fVxuXG4gIGRlbGV0ZWRUZXh0KCk6IHN0cmluZyB7XG4gICAgdGhpcy5pMThuLmxhbmcoKTtcbiAgICByZXR1cm4gdGhpcy5pMThuLnQoJ21lc3NhZ2VEZWxldGVkJywgJ0NoYXQnKTtcbiAgfVxuXG4gIGVkaXRlZExhYmVsKCk6IHN0cmluZyB7XG4gICAgdGhpcy5pMThuLmxhbmcoKTtcbiAgICByZXR1cm4gdGhpcy5pMThuLnQoJ2VkaXRlZCcsICdDaGF0Jyk7XG4gIH1cblxuICBmb3JtYXRUaW1lKGRhdGU6IERhdGUpOiBzdHJpbmcge1xuICAgIGlmICghZGF0ZSkgcmV0dXJuICcnO1xuICAgIGNvbnN0IGQgPSBkYXRlIGluc3RhbmNlb2YgRGF0ZSA/IGRhdGUgOiBuZXcgRGF0ZShkYXRlKTtcbiAgICByZXR1cm4gZC50b0xvY2FsZVRpbWVTdHJpbmcoW10sIHsgaG91cjogJzItZGlnaXQnLCBtaW51dGU6ICcyLWRpZ2l0JyB9KTtcbiAgfVxuXG4gIHN0YXR1c0ljb24oKTogc3RyaW5nIHtcbiAgICBzd2l0Y2ggKHRoaXMucHJvcHMuc3RhdHVzKSB7XG4gICAgICBjYXNlICdzZW5kaW5nJzpcbiAgICAgICAgcmV0dXJuICd0aW1lLW91dGxpbmUnO1xuICAgICAgY2FzZSAnZmFpbGVkJzpcbiAgICAgICAgcmV0dXJuICdhbGVydC1jaXJjbGUnO1xuICAgICAgY2FzZSAnc2VudCc6XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gJ2NoZWNrbWFyayc7XG4gICAgfVxuICB9XG5cbiAgb25SZWFjdGlvbkNsaWNrKHJlYWN0aW9uOiBNZXNzYWdlUmVhY3Rpb24pOiB2b2lkIHtcbiAgICB0aGlzLnJlYWN0aW9uQ2xpY2suZW1pdCh7IHRva2VuOiByZWFjdGlvbi50b2tlbiwgbXNnSWQ6IHRoaXMucHJvcHMubXNnSWQgfSk7XG4gIH1cblxuICBvblJlcGx5Q2xpY2soKTogdm9pZCB7XG4gICAgdGhpcy5yZXBseUNsaWNrLmVtaXQoeyBtc2dJZDogdGhpcy5wcm9wcy5tc2dJZCB9KTtcbiAgfVxuXG4gIG9uRGVsZXRlQ2xpY2soKTogdm9pZCB7XG4gICAgdGhpcy5kZWxldGVDbGljay5lbWl0KHsgbXNnSWQ6IHRoaXMucHJvcHMubXNnSWQgfSk7XG4gIH1cblxuICBvbkVkaXRDbGljaygpOiB2b2lkIHtcbiAgICB0aGlzLmVkaXRDbGljay5lbWl0KHsgbXNnSWQ6IHRoaXMucHJvcHMubXNnSWQgfSk7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvbW9sZWN1bGVzL21lc3NhZ2UtYnViYmxlL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBNZXNzYWdlQXR0YWNobWVudCxcbiAgTWVzc2FnZVJlYWN0aW9uLFxuICBNZXNzYWdlUmVwbHlUbyxcbiAgTWVzc2FnZVN0YXR1cyxcbiAgTWVzc2FnZVR5cGUsXG59IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2NoYXQvdHlwZXMnO1xuXG4vKipcbiAqIERhdG9zIG5lY2VzYXJpb3MgcGFyYSByZW5kZXJpemFyIHVuYSBidXJidWphIGRlIG1lbnNhamUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZUJ1YmJsZU1ldGFkYXRhIHtcbiAgLyoqIElEIHVuaWNvIGRlbCBtZW5zYWplLiAqL1xuICBtc2dJZDogc3RyaW5nO1xuICAvKiogSUQgZGVsIGVtaXNvci4gKi9cbiAgc2VuZGVySWQ6IHN0cmluZztcbiAgLyoqIE5vbWJyZSB2aXNpYmxlIGRlbCBlbWlzb3IuICovXG4gIHNlbmRlck5hbWU6IHN0cmluZztcbiAgLyoqIFVSTCBkZWwgYXZhdGFyIGRlbCBlbWlzb3IgKG9wY2lvbmFsKS4gKi9cbiAgc2VuZGVyQXZhdGFyPzogc3RyaW5nO1xuICAvKiogQ3VlcnBvIGRlbCBtZW5zYWplLiAqL1xuICBib2R5OiBzdHJpbmc7XG4gIC8qKiBUaXBvIGRlIG1lbnNhamUuICovXG4gIHR5cGU6IE1lc3NhZ2VUeXBlO1xuICAvKiogRmVjaGEgZGUgY3JlYWNpb24gZGVsIG1lbnNhamUuICovXG4gIGNyZWF0ZWRBdDogRGF0ZTtcbiAgLyoqIFNpIGVsIG1lbnNhamUgZXMgZGVsIHVzdWFyaW8gYWN0dWFsIChhbGluZWFjaW9uIGRlcmVjaGEpLiAqL1xuICBpc01pbmU6IGJvb2xlYW47XG4gIC8qKiBTaSBlbCBtZW5zYWplIGZ1ZSBlbGltaW5hZG8uICovXG4gIGlzRGVsZXRlZD86IGJvb2xlYW47XG4gIC8qKiBTaSBlbCBtZW5zYWplIGZ1ZSBlZGl0YWRvLiAqL1xuICBpc0VkaXRlZD86IGJvb2xlYW47XG4gIC8qKiBNZW5zYWplIGFsIHF1ZSByZXNwb25kZSAob3BjaW9uYWwpLiAqL1xuICByZXBseVRvPzogTWVzc2FnZVJlcGx5VG87XG4gIC8qKiBBcmNoaXZvcyBhZGp1bnRvcyAob3BjaW9uYWwpLiAqL1xuICBhdHRhY2htZW50cz86IE1lc3NhZ2VBdHRhY2htZW50W107XG4gIC8qKiBSZWFjY2lvbmVzIGRlbCBtZW5zYWplIChvcGNpb25hbCkuICovXG4gIHJlYWN0aW9ucz86IE1lc3NhZ2VSZWFjdGlvbltdO1xuICAvKiogRXN0YWRvIGRlIGVudmlvIChwYXJhIG1lbnNhamVzIG9wdGltaXN0YXMgZGVsIGxhZG8gZGVsIGNsaWVudGUpLiAqL1xuICBzdGF0dXM/OiBNZXNzYWdlU3RhdHVzO1xufVxuXG4vKipcbiAqIEV2ZW50byBlbWl0aWRvIGN1YW5kbyBlbCB1c3VhcmlvIGhhY2UgY2xpYyBlbiB1bmEgcmVhY2Npb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZVJlYWN0aW9uQ2xpY2tFdmVudCB7XG4gIC8qKiBUb2tlbiBkZSBsYSByZWFjY2lvbiBjbGlja2VhZGEuICovXG4gIHRva2VuOiBzdHJpbmc7XG4gIC8qKiBJRCBkZWwgbWVuc2FqZS4gKi9cbiAgbXNnSWQ6IHN0cmluZztcbn1cblxuLyoqXG4gKiBFdmVudG8gZW1pdGlkbyBjdWFuZG8gZWwgdXN1YXJpbyByZXNwb25kZSBhIHVuIG1lbnNhamUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZVJlcGx5Q2xpY2tFdmVudCB7XG4gIC8qKiBJRCBkZWwgbWVuc2FqZSBhbCBxdWUgc2UgcmVzcG9uZGUuICovXG4gIG1zZ0lkOiBzdHJpbmc7XG59XG5cbi8qKlxuICogRXZlbnRvIGVtaXRpZG8gY3VhbmRvIGVsIHVzdWFyaW8gZWxpbWluYSB1biBtZW5zYWplLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1lc3NhZ2VEZWxldGVDbGlja0V2ZW50IHtcbiAgLyoqIElEIGRlbCBtZW5zYWplIGEgZWxpbWluYXIuICovXG4gIG1zZ0lkOiBzdHJpbmc7XG59XG5cbi8qKlxuICogRXZlbnRvIGVtaXRpZG8gY3VhbmRvIGVsIHVzdWFyaW8gZWRpdGEgdW4gbWVuc2FqZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNZXNzYWdlRWRpdENsaWNrRXZlbnQge1xuICAvKiogSUQgZGVsIG1lbnNhamUgYSBlZGl0YXIuICovXG4gIG1zZ0lkOiBzdHJpbmc7XG59XG4iXX0=
@@ -0,0 +1,76 @@
1
+ import { Component, Input, inject, computed } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { I18nService } from '../../../services/i18n';
4
+ import * as i0 from "@angular/core";
5
+ const TYPING_I18N = {
6
+ es: {
7
+ one: '{name} esta escribiendo',
8
+ two: '{name} y {other} estan escribiendo',
9
+ many: 'Varios estan escribiendo',
10
+ },
11
+ en: {
12
+ one: '{name} is typing',
13
+ two: '{name} and {other} are typing',
14
+ many: 'Several people are typing',
15
+ },
16
+ };
17
+ /**
18
+ * val-typing-indicator
19
+ *
20
+ * Muestra quienes estan escribiendo en el chat con animacion de tres puntos.
21
+ * Se oculta automaticamente si typingUsers esta vacio.
22
+ *
23
+ * @example
24
+ * <val-typing-indicator [typingUsers]="['Maria', 'Carlos']" />
25
+ */
26
+ export class TypingIndicatorComponent {
27
+ constructor() {
28
+ this.i18n = inject(I18nService);
29
+ this.typingUsers = [];
30
+ this.typingText = computed(() => {
31
+ this.i18n.lang();
32
+ const users = this.typingUsers ?? [];
33
+ if (users.length === 0)
34
+ return '';
35
+ if (users.length === 1) {
36
+ return this.i18n.t('one', 'TypingIndicator', { name: users[0] });
37
+ }
38
+ if (users.length === 2) {
39
+ return this.i18n.t('two', 'TypingIndicator', { name: users[0], other: users[1] });
40
+ }
41
+ return this.i18n.t('many', 'TypingIndicator');
42
+ });
43
+ this.i18n.registerDefaults('TypingIndicator', TYPING_I18N);
44
+ }
45
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TypingIndicatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
46
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: TypingIndicatorComponent, isStandalone: true, selector: "val-typing-indicator", inputs: { typingUsers: "typingUsers" }, ngImport: i0, template: `
47
+ @if (typingUsers && typingUsers.length > 0) {
48
+ <div class="typing-indicator">
49
+ <div class="dots">
50
+ <span></span>
51
+ <span></span>
52
+ <span></span>
53
+ </div>
54
+ <span class="typing-text">{{ typingText() }}</span>
55
+ </div>
56
+ }
57
+ `, isInline: true, styles: [".typing-indicator{display:flex;align-items:center;gap:8px;padding:4px 12px;min-height:28px}.typing-text{font-size:.8125rem;color:var(--ion-color-medium, #92949c);font-style:italic}.dots{display:flex;align-items:center;gap:3px}.dots span{display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--ion-color-medium, #92949c);animation:typing-dot 1.2s infinite ease-in-out}.dots span:nth-child(1){animation-delay:0s}.dots span:nth-child(2){animation-delay:.2s}.dots span:nth-child(3){animation-delay:.4s}@keyframes typing-dot{0%,60%,to{transform:translateY(0);opacity:.4}30%{transform:translateY(-4px);opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
58
+ }
59
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TypingIndicatorComponent, decorators: [{
60
+ type: Component,
61
+ args: [{ selector: 'val-typing-indicator', standalone: true, imports: [CommonModule], template: `
62
+ @if (typingUsers && typingUsers.length > 0) {
63
+ <div class="typing-indicator">
64
+ <div class="dots">
65
+ <span></span>
66
+ <span></span>
67
+ <span></span>
68
+ </div>
69
+ <span class="typing-text">{{ typingText() }}</span>
70
+ </div>
71
+ }
72
+ `, styles: [".typing-indicator{display:flex;align-items:center;gap:8px;padding:4px 12px;min-height:28px}.typing-text{font-size:.8125rem;color:var(--ion-color-medium, #92949c);font-style:italic}.dots{display:flex;align-items:center;gap:3px}.dots span{display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--ion-color-medium, #92949c);animation:typing-dot 1.2s infinite ease-in-out}.dots span:nth-child(1){animation-delay:0s}.dots span:nth-child(2){animation-delay:.2s}.dots span:nth-child(3){animation-delay:.4s}@keyframes typing-dot{0%,60%,to{transform:translateY(0);opacity:.4}30%{transform:translateY(-4px);opacity:1}}\n"] }]
73
+ }], ctorParameters: () => [], propDecorators: { typingUsers: [{
74
+ type: Input
75
+ }] } });
76
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwaW5nLWluZGljYXRvci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvbW9sZWN1bGVzL3R5cGluZy1pbmRpY2F0b3IvdHlwaW5nLWluZGljYXRvci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDOztBQUVyRCxNQUFNLFdBQVcsR0FBRztJQUNsQixFQUFFLEVBQUU7UUFDRixHQUFHLEVBQUUseUJBQXlCO1FBQzlCLEdBQUcsRUFBRSxvQ0FBb0M7UUFDekMsSUFBSSxFQUFFLDBCQUEwQjtLQUNqQztJQUNELEVBQUUsRUFBRTtRQUNGLEdBQUcsRUFBRSxrQkFBa0I7UUFDdkIsR0FBRyxFQUFFLCtCQUErQjtRQUNwQyxJQUFJLEVBQUUsMkJBQTJCO0tBQ2xDO0NBQ0YsQ0FBQztBQUVGOzs7Ozs7OztHQVFHO0FBbUJILE1BQU0sT0FBTyx3QkFBd0I7SUFLbkM7UUFKVSxTQUFJLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRTVCLGdCQUFXLEdBQWEsRUFBRSxDQUFDO1FBTTFCLGVBQVUsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1lBQ25DLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDakIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFdBQVcsSUFBSSxFQUFFLENBQUM7WUFDckMsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUM7Z0JBQUUsT0FBTyxFQUFFLENBQUM7WUFDbEMsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUN2QixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ25FLENBQUM7WUFDRCxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3ZCLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLGlCQUFpQixFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNwRixDQUFDO1lBQ0QsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztRQUNoRCxDQUFDLENBQUMsQ0FBQztRQWRELElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsaUJBQWlCLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDN0QsQ0FBQzsrR0FQVSx3QkFBd0I7bUdBQXhCLHdCQUF3Qix3SEFkekI7Ozs7Ozs7Ozs7O0dBV1QsK3JCQVpTLFlBQVk7OzRGQWVYLHdCQUF3QjtrQkFsQnBDLFNBQVM7K0JBQ0Usc0JBQXNCLGNBQ3BCLElBQUksV0FDUCxDQUFDLFlBQVksQ0FBQyxZQUNiOzs7Ozs7Ozs7OztHQVdUO3dEQU1RLFdBQVc7c0JBQW5CLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBpbmplY3QsIGNvbXB1dGVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgSTE4blNlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9zZXJ2aWNlcy9pMThuJztcblxuY29uc3QgVFlQSU5HX0kxOE4gPSB7XG4gIGVzOiB7XG4gICAgb25lOiAne25hbWV9IGVzdGEgZXNjcmliaWVuZG8nLFxuICAgIHR3bzogJ3tuYW1lfSB5IHtvdGhlcn0gZXN0YW4gZXNjcmliaWVuZG8nLFxuICAgIG1hbnk6ICdWYXJpb3MgZXN0YW4gZXNjcmliaWVuZG8nLFxuICB9LFxuICBlbjoge1xuICAgIG9uZTogJ3tuYW1lfSBpcyB0eXBpbmcnLFxuICAgIHR3bzogJ3tuYW1lfSBhbmQge290aGVyfSBhcmUgdHlwaW5nJyxcbiAgICBtYW55OiAnU2V2ZXJhbCBwZW9wbGUgYXJlIHR5cGluZycsXG4gIH0sXG59O1xuXG4vKipcbiAqIHZhbC10eXBpbmctaW5kaWNhdG9yXG4gKlxuICogTXVlc3RyYSBxdWllbmVzIGVzdGFuIGVzY3JpYmllbmRvIGVuIGVsIGNoYXQgY29uIGFuaW1hY2lvbiBkZSB0cmVzIHB1bnRvcy5cbiAqIFNlIG9jdWx0YSBhdXRvbWF0aWNhbWVudGUgc2kgdHlwaW5nVXNlcnMgZXN0YSB2YWNpby5cbiAqXG4gKiBAZXhhbXBsZVxuICogPHZhbC10eXBpbmctaW5kaWNhdG9yIFt0eXBpbmdVc2Vyc109XCJbJ01hcmlhJywgJ0NhcmxvcyddXCIgLz5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAndmFsLXR5cGluZy1pbmRpY2F0b3InLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXSxcbiAgdGVtcGxhdGU6IGBcbiAgICBAaWYgKHR5cGluZ1VzZXJzICYmIHR5cGluZ1VzZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgIDxkaXYgY2xhc3M9XCJ0eXBpbmctaW5kaWNhdG9yXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkb3RzXCI+XG4gICAgICAgICAgPHNwYW4+PC9zcGFuPlxuICAgICAgICAgIDxzcGFuPjwvc3Bhbj5cbiAgICAgICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8c3BhbiBjbGFzcz1cInR5cGluZy10ZXh0XCI+e3sgdHlwaW5nVGV4dCgpIH19PC9zcGFuPlxuICAgICAgPC9kaXY+XG4gICAgfVxuICBgLFxuICBzdHlsZVVybHM6IFsnLi90eXBpbmctaW5kaWNhdG9yLmNvbXBvbmVudC5zY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIFR5cGluZ0luZGljYXRvckNvbXBvbmVudCB7XG4gIHByb3RlY3RlZCBpMThuID0gaW5qZWN0KEkxOG5TZXJ2aWNlKTtcblxuICBASW5wdXQoKSB0eXBpbmdVc2Vyczogc3RyaW5nW10gPSBbXTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLmkxOG4ucmVnaXN0ZXJEZWZhdWx0cygnVHlwaW5nSW5kaWNhdG9yJywgVFlQSU5HX0kxOE4pO1xuICB9XG5cbiAgcHJvdGVjdGVkIHR5cGluZ1RleHQgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgdGhpcy5pMThuLmxhbmcoKTtcbiAgICBjb25zdCB1c2VycyA9IHRoaXMudHlwaW5nVXNlcnMgPz8gW107XG4gICAgaWYgKHVzZXJzLmxlbmd0aCA9PT0gMCkgcmV0dXJuICcnO1xuICAgIGlmICh1c2Vycy5sZW5ndGggPT09IDEpIHtcbiAgICAgIHJldHVybiB0aGlzLmkxOG4udCgnb25lJywgJ1R5cGluZ0luZGljYXRvcicsIHsgbmFtZTogdXNlcnNbMF0gfSk7XG4gICAgfVxuICAgIGlmICh1c2Vycy5sZW5ndGggPT09IDIpIHtcbiAgICAgIHJldHVybiB0aGlzLmkxOG4udCgndHdvJywgJ1R5cGluZ0luZGljYXRvcicsIHsgbmFtZTogdXNlcnNbMF0sIG90aGVyOiB1c2Vyc1sxXSB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaTE4bi50KCdtYW55JywgJ1R5cGluZ0luZGljYXRvcicpO1xuICB9KTtcbn1cbiJdfQ==