@konce-pt/angular 0.8.3 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +533 -0
- package/chat/src/lib/llms.txt +160 -0
- package/fesm2022/konce-pt-angular-chat.mjs +1270 -0
- package/fesm2022/konce-pt-angular-chat.mjs.map +1 -0
- package/fesm2022/konce-pt-angular-roadmap.mjs +2 -2
- package/fesm2022/konce-pt-angular.mjs +2154 -600
- package/fesm2022/konce-pt-angular.mjs.map +1 -1
- package/package.json +15 -8
- package/src/lib/backdrop/llms.txt +163 -0
- package/src/lib/button/llms.txt +53 -9
- package/src/lib/button-group/llms.txt +17 -1
- package/src/lib/chip/llms.txt +8 -0
- package/src/lib/data-view/llms.txt +18 -2
- package/src/lib/dialog/llms.txt +10 -0
- package/src/lib/icon-button/llms.txt +1 -0
- package/src/lib/mention/llms.txt +60 -0
- package/src/lib/order-list/llms.txt +13 -2
- package/src/lib/peek/llms.txt +45 -0
- package/src/lib/pick-list/llms.txt +18 -2
- package/src/lib/progress/llms.txt +81 -5
- package/src/lib/rich-text/llms.txt +15 -0
- package/types/konce-pt-angular-chat.d.ts +334 -0
- package/types/konce-pt-angular-chat.d.ts.map +1 -0
- package/types/konce-pt-angular.d.ts +550 -38
- package/types/konce-pt-angular.d.ts.map +1 -1
|
@@ -0,0 +1,1270 @@
|
|
|
1
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { input, booleanAttribute, output, inject, ElementRef, signal, computed, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, contentChild, TemplateRef, viewChild, DestroyRef, afterRenderEffect, untracked, afterNextRender, model } from '@angular/core';
|
|
4
|
+
import { KptI18n, KptAvatar, KptIcon, KptIconButton, KptBadge, KptFab } from '@konce-pt/angular';
|
|
5
|
+
import { KPT_CHAT_REACTIONS, toDate, canRetry, KPT_CHAT_GROUP_GAP_MS, buildChatRows, pendingCount, chatDayIndicator } from '@konce-pt/chat';
|
|
6
|
+
export { KPT_CHAT_GROUP_GAP_MS, KPT_CHAT_REACTIONS, buildChatRows, canRetry, chatDayIndicator, dateLabel, diffInDays, isSameDay, mergeStatus, pendingCount, replyRefFrom, startOfDay, statusRank, toDate, toggleReaction } from '@konce-pt/chat';
|
|
7
|
+
|
|
8
|
+
const _c0$3 = ["*"];
|
|
9
|
+
const _c1$2 = a0 => ({ author: a0 });
|
|
10
|
+
const _forTrack0$2 = ($index, $item) => $item.id;
|
|
11
|
+
const _forTrack1 = ($index, $item) => $item.emoji;
|
|
12
|
+
const _forTrack2 = ($index, $item) => $item.kind;
|
|
13
|
+
function KptChatMessage_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
14
|
+
i0.ɵɵelementStart(0, "p", 0);
|
|
15
|
+
i0.ɵɵtext(1);
|
|
16
|
+
i0.ɵɵelementEnd();
|
|
17
|
+
} if (rf & 2) {
|
|
18
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
19
|
+
i0.ɵɵadvance();
|
|
20
|
+
i0.ɵɵtextInterpolate(ctx_r0.resolvedText());
|
|
21
|
+
} }
|
|
22
|
+
function KptChatMessage_Conditional_1_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
23
|
+
i0.ɵɵelement(0, "kpt-avatar", 13);
|
|
24
|
+
} if (rf & 2) {
|
|
25
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
26
|
+
i0.ɵɵproperty("src", ctx_r0.resolvedAuthor()?.avatar ?? null)("name", ctx_r0.resolvedAuthor()?.name ?? "");
|
|
27
|
+
} }
|
|
28
|
+
function KptChatMessage_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
29
|
+
i0.ɵɵelementStart(0, "span", 2);
|
|
30
|
+
i0.ɵɵconditionalCreate(1, KptChatMessage_Conditional_1_Conditional_1_Conditional_1_Template, 1, 2, "kpt-avatar", 13);
|
|
31
|
+
i0.ɵɵelementEnd();
|
|
32
|
+
} if (rf & 2) {
|
|
33
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
34
|
+
i0.ɵɵadvance();
|
|
35
|
+
i0.ɵɵconditional(ctx_r0.showAvatar() ? 1 : -1);
|
|
36
|
+
} }
|
|
37
|
+
function KptChatMessage_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
38
|
+
i0.ɵɵelementStart(0, "span", 4);
|
|
39
|
+
i0.ɵɵtext(1);
|
|
40
|
+
i0.ɵɵelementEnd();
|
|
41
|
+
} if (rf & 2) {
|
|
42
|
+
i0.ɵɵadvance();
|
|
43
|
+
i0.ɵɵtextInterpolate(ctx.name);
|
|
44
|
+
} }
|
|
45
|
+
function KptChatMessage_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
46
|
+
const _r2 = i0.ɵɵgetCurrentView();
|
|
47
|
+
i0.ɵɵelementStart(0, "button", 14);
|
|
48
|
+
i0.ɵɵlistener("click", function KptChatMessage_Conditional_1_Conditional_5_Template_button_click_0_listener() { const quote_r3 = i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.quoted.emit(quote_r3)); });
|
|
49
|
+
i0.ɵɵelementStart(1, "span", 15);
|
|
50
|
+
i0.ɵɵtext(2);
|
|
51
|
+
i0.ɵɵelementEnd();
|
|
52
|
+
i0.ɵɵelementStart(3, "span", 16);
|
|
53
|
+
i0.ɵɵtext(4);
|
|
54
|
+
i0.ɵɵelementEnd()();
|
|
55
|
+
} if (rf & 2) {
|
|
56
|
+
const quote_r3 = ctx;
|
|
57
|
+
i0.ɵɵadvance(2);
|
|
58
|
+
i0.ɵɵtextInterpolate(quote_r3.author);
|
|
59
|
+
i0.ɵɵadvance(2);
|
|
60
|
+
i0.ɵɵtextInterpolate(quote_r3.excerpt);
|
|
61
|
+
} }
|
|
62
|
+
function KptChatMessage_Conditional_1_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
63
|
+
i0.ɵɵelementStart(0, "p", 7);
|
|
64
|
+
i0.ɵɵtext(1);
|
|
65
|
+
i0.ɵɵelementEnd();
|
|
66
|
+
} if (rf & 2) {
|
|
67
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
68
|
+
i0.ɵɵadvance();
|
|
69
|
+
i0.ɵɵtextInterpolate(ctx_r0.resolvedText());
|
|
70
|
+
} }
|
|
71
|
+
function KptChatMessage_Conditional_1_Conditional_8_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
72
|
+
i0.ɵɵelement(0, "img", 18);
|
|
73
|
+
} if (rf & 2) {
|
|
74
|
+
const file_r4 = i0.ɵɵnextContext().$implicit;
|
|
75
|
+
i0.ɵɵproperty("src", file_r4.thumbnail, i0.ɵɵsanitizeUrl)("alt", file_r4.name);
|
|
76
|
+
} }
|
|
77
|
+
function KptChatMessage_Conditional_1_Conditional_8_For_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
78
|
+
i0.ɵɵelement(0, "kpt-icon", 19);
|
|
79
|
+
} }
|
|
80
|
+
function KptChatMessage_Conditional_1_Conditional_8_For_2_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
81
|
+
i0.ɵɵelementStart(0, "span", 21);
|
|
82
|
+
i0.ɵɵtext(1);
|
|
83
|
+
i0.ɵɵelementEnd();
|
|
84
|
+
} if (rf & 2) {
|
|
85
|
+
const file_r4 = i0.ɵɵnextContext().$implicit;
|
|
86
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
87
|
+
i0.ɵɵadvance();
|
|
88
|
+
i0.ɵɵtextInterpolate(ctx_r0.fileSize(file_r4.size));
|
|
89
|
+
} }
|
|
90
|
+
function KptChatMessage_Conditional_1_Conditional_8_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
91
|
+
i0.ɵɵelementStart(0, "li", 17);
|
|
92
|
+
i0.ɵɵconditionalCreate(1, KptChatMessage_Conditional_1_Conditional_8_For_2_Conditional_1_Template, 1, 2, "img", 18)(2, KptChatMessage_Conditional_1_Conditional_8_For_2_Conditional_2_Template, 1, 0, "kpt-icon", 19);
|
|
93
|
+
i0.ɵɵelementStart(3, "a", 20);
|
|
94
|
+
i0.ɵɵtext(4);
|
|
95
|
+
i0.ɵɵelementEnd();
|
|
96
|
+
i0.ɵɵconditionalCreate(5, KptChatMessage_Conditional_1_Conditional_8_For_2_Conditional_5_Template, 2, 1, "span", 21);
|
|
97
|
+
i0.ɵɵelementEnd();
|
|
98
|
+
} if (rf & 2) {
|
|
99
|
+
const file_r4 = ctx.$implicit;
|
|
100
|
+
i0.ɵɵadvance();
|
|
101
|
+
i0.ɵɵconditional(file_r4.thumbnail ? 1 : 2);
|
|
102
|
+
i0.ɵɵadvance(2);
|
|
103
|
+
i0.ɵɵattribute("href", file_r4.url ?? null, i0.ɵɵsanitizeUrl)("download", file_r4.url ? file_r4.name : null);
|
|
104
|
+
i0.ɵɵadvance();
|
|
105
|
+
i0.ɵɵtextInterpolate1(" ", file_r4.name, " ");
|
|
106
|
+
i0.ɵɵadvance();
|
|
107
|
+
i0.ɵɵconditional(file_r4.size ? 5 : -1);
|
|
108
|
+
} }
|
|
109
|
+
function KptChatMessage_Conditional_1_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
110
|
+
i0.ɵɵelementStart(0, "ul", 8);
|
|
111
|
+
i0.ɵɵrepeaterCreate(1, KptChatMessage_Conditional_1_Conditional_8_For_2_Template, 6, 5, "li", 17, _forTrack0$2);
|
|
112
|
+
i0.ɵɵelementEnd();
|
|
113
|
+
} if (rf & 2) {
|
|
114
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
115
|
+
i0.ɵɵadvance();
|
|
116
|
+
i0.ɵɵrepeater(ctx_r0.resolvedAttachments());
|
|
117
|
+
} }
|
|
118
|
+
function KptChatMessage_Conditional_1_Conditional_9_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
119
|
+
i0.ɵɵelementStart(0, "time", 22);
|
|
120
|
+
i0.ɵɵtext(1);
|
|
121
|
+
i0.ɵɵelementEnd();
|
|
122
|
+
} if (rf & 2) {
|
|
123
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
124
|
+
i0.ɵɵattribute("datetime", ctx_r0.isoTime());
|
|
125
|
+
i0.ɵɵadvance();
|
|
126
|
+
i0.ɵɵtextInterpolate(ctx_r0.timeLabel());
|
|
127
|
+
} }
|
|
128
|
+
function KptChatMessage_Conditional_1_Conditional_9_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
129
|
+
i0.ɵɵelement(0, "kpt-icon", 23);
|
|
130
|
+
} if (rf & 2) {
|
|
131
|
+
i0.ɵɵproperty("name", ctx);
|
|
132
|
+
} }
|
|
133
|
+
function KptChatMessage_Conditional_1_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
134
|
+
i0.ɵɵelementStart(0, "span", 9);
|
|
135
|
+
i0.ɵɵconditionalCreate(1, KptChatMessage_Conditional_1_Conditional_9_Conditional_1_Template, 2, 2, "time", 22);
|
|
136
|
+
i0.ɵɵconditionalCreate(2, KptChatMessage_Conditional_1_Conditional_9_Conditional_2_Template, 1, 1, "kpt-icon", 23);
|
|
137
|
+
i0.ɵɵelementEnd();
|
|
138
|
+
} if (rf & 2) {
|
|
139
|
+
let tmp_3_0;
|
|
140
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
141
|
+
i0.ɵɵadvance();
|
|
142
|
+
i0.ɵɵconditional(ctx_r0.timeLabel() ? 1 : -1);
|
|
143
|
+
i0.ɵɵadvance();
|
|
144
|
+
i0.ɵɵconditional((tmp_3_0 = ctx_r0.statusIcon()) ? 2 : -1, tmp_3_0);
|
|
145
|
+
} }
|
|
146
|
+
function KptChatMessage_Conditional_1_Conditional_10_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
147
|
+
i0.ɵɵelementStart(0, "li", 24)(1, "span", 25);
|
|
148
|
+
i0.ɵɵtext(2);
|
|
149
|
+
i0.ɵɵelementEnd();
|
|
150
|
+
i0.ɵɵelementStart(3, "span", 26);
|
|
151
|
+
i0.ɵɵtext(4);
|
|
152
|
+
i0.ɵɵelementEnd()();
|
|
153
|
+
} if (rf & 2) {
|
|
154
|
+
const reaction_r5 = ctx.$implicit;
|
|
155
|
+
i0.ɵɵattribute("data-reacted", reaction_r5.reacted ? "" : null);
|
|
156
|
+
i0.ɵɵadvance(2);
|
|
157
|
+
i0.ɵɵtextInterpolate(reaction_r5.emoji);
|
|
158
|
+
i0.ɵɵadvance(2);
|
|
159
|
+
i0.ɵɵtextInterpolate(reaction_r5.count);
|
|
160
|
+
} }
|
|
161
|
+
function KptChatMessage_Conditional_1_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
162
|
+
i0.ɵɵelementStart(0, "ul", 10);
|
|
163
|
+
i0.ɵɵrepeaterCreate(1, KptChatMessage_Conditional_1_Conditional_10_For_2_Template, 5, 3, "li", 24, _forTrack1);
|
|
164
|
+
i0.ɵɵelementEnd();
|
|
165
|
+
} if (rf & 2) {
|
|
166
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
167
|
+
i0.ɵɵattribute("data-align", ctx_r0.align());
|
|
168
|
+
i0.ɵɵadvance();
|
|
169
|
+
i0.ɵɵrepeater(ctx_r0.resolvedReactions());
|
|
170
|
+
} }
|
|
171
|
+
function KptChatMessage_Conditional_1_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
172
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
173
|
+
i0.ɵɵelementStart(0, "kpt-icon-button", 27);
|
|
174
|
+
i0.ɵɵlistener("click", function KptChatMessage_Conditional_1_Conditional_12_Template_kpt_icon_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.retry.emit()); });
|
|
175
|
+
i0.ɵɵelement(1, "kpt-icon", 28);
|
|
176
|
+
i0.ɵɵelementEnd();
|
|
177
|
+
} if (rf & 2) {
|
|
178
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
179
|
+
i0.ɵɵproperty("ariaLabel", ctx_r0.i18n.t("chat.retry"));
|
|
180
|
+
} }
|
|
181
|
+
function KptChatMessage_Conditional_1_Conditional_13_Conditional_5_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
182
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
183
|
+
i0.ɵɵelementStart(0, "button", 36);
|
|
184
|
+
i0.ɵɵlistener("click", function KptChatMessage_Conditional_1_Conditional_13_Conditional_5_For_2_Template_button_click_0_listener() { const option_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.pick(option_r9.emoji)); });
|
|
185
|
+
i0.ɵɵelementStart(1, "span", 25);
|
|
186
|
+
i0.ɵɵtext(2);
|
|
187
|
+
i0.ɵɵelementEnd()();
|
|
188
|
+
} if (rf & 2) {
|
|
189
|
+
const option_r9 = ctx.$implicit;
|
|
190
|
+
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
191
|
+
i0.ɵɵattribute("aria-label", ctx_r0.reactionLabel(option_r9))("title", ctx_r0.reactionLabel(option_r9))("aria-pressed", ctx_r0.hasReacted(option_r9.emoji));
|
|
192
|
+
i0.ɵɵadvance(2);
|
|
193
|
+
i0.ɵɵtextInterpolate(option_r9.emoji);
|
|
194
|
+
} }
|
|
195
|
+
function KptChatMessage_Conditional_1_Conditional_13_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
196
|
+
i0.ɵɵelementStart(0, "span", 34);
|
|
197
|
+
i0.ɵɵrepeaterCreate(1, KptChatMessage_Conditional_1_Conditional_13_Conditional_5_For_2_Template, 3, 4, "button", 35, _forTrack2);
|
|
198
|
+
i0.ɵɵelementEnd();
|
|
199
|
+
} if (rf & 2) {
|
|
200
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
201
|
+
i0.ɵɵattribute("aria-label", ctx_r0.i18n.t("chat.react"));
|
|
202
|
+
i0.ɵɵadvance();
|
|
203
|
+
i0.ɵɵrepeater(ctx_r0.reactionOptions());
|
|
204
|
+
} }
|
|
205
|
+
function KptChatMessage_Conditional_1_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
206
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
207
|
+
i0.ɵɵelementStart(0, "kpt-icon-button", 29);
|
|
208
|
+
i0.ɵɵlistener("click", function KptChatMessage_Conditional_1_Conditional_13_Template_kpt_icon_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.reply.emit()); });
|
|
209
|
+
i0.ɵɵelement(1, "kpt-icon", 30);
|
|
210
|
+
i0.ɵɵelementEnd();
|
|
211
|
+
i0.ɵɵelementStart(2, "span", 31);
|
|
212
|
+
i0.ɵɵlistener("keydown.escape", function KptChatMessage_Conditional_1_Conditional_13_Template_span_keydown_escape_2_listener() { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.pickerOpen.set(false)); })("focusout", function KptChatMessage_Conditional_1_Conditional_13_Template_span_focusout_2_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onPickerFocusOut($event)); });
|
|
213
|
+
i0.ɵɵelementStart(3, "kpt-icon-button", 32);
|
|
214
|
+
i0.ɵɵlistener("click", function KptChatMessage_Conditional_1_Conditional_13_Template_kpt_icon_button_click_3_listener() { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.pickerOpen.set(!ctx_r0.pickerOpen())); });
|
|
215
|
+
i0.ɵɵelement(4, "kpt-icon", 33);
|
|
216
|
+
i0.ɵɵelementEnd();
|
|
217
|
+
i0.ɵɵconditionalCreate(5, KptChatMessage_Conditional_1_Conditional_13_Conditional_5_Template, 3, 1, "span", 34);
|
|
218
|
+
i0.ɵɵelementEnd();
|
|
219
|
+
} if (rf & 2) {
|
|
220
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
221
|
+
i0.ɵɵproperty("ariaLabel", ctx_r0.i18n.t("chat.replyTo", i0.ɵɵpureFunction1(4, _c1$2, ctx_r0.resolvedAuthor()?.name ?? "")));
|
|
222
|
+
i0.ɵɵadvance(3);
|
|
223
|
+
i0.ɵɵproperty("ariaLabel", ctx_r0.i18n.t("chat.react"))("ariaExpanded", ctx_r0.pickerOpen());
|
|
224
|
+
i0.ɵɵadvance(2);
|
|
225
|
+
i0.ɵɵconditional(ctx_r0.pickerOpen() ? 5 : -1);
|
|
226
|
+
} }
|
|
227
|
+
function KptChatMessage_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
228
|
+
i0.ɵɵelementStart(0, "div", 1);
|
|
229
|
+
i0.ɵɵconditionalCreate(1, KptChatMessage_Conditional_1_Conditional_1_Template, 2, 1, "span", 2);
|
|
230
|
+
i0.ɵɵelementStart(2, "div", 3);
|
|
231
|
+
i0.ɵɵconditionalCreate(3, KptChatMessage_Conditional_1_Conditional_3_Template, 2, 1, "span", 4);
|
|
232
|
+
i0.ɵɵelementStart(4, "div", 5);
|
|
233
|
+
i0.ɵɵconditionalCreate(5, KptChatMessage_Conditional_1_Conditional_5_Template, 5, 2, "button", 6);
|
|
234
|
+
i0.ɵɵconditionalCreate(6, KptChatMessage_Conditional_1_Conditional_6_Template, 2, 1, "p", 7);
|
|
235
|
+
i0.ɵɵprojection(7);
|
|
236
|
+
i0.ɵɵconditionalCreate(8, KptChatMessage_Conditional_1_Conditional_8_Template, 3, 0, "ul", 8);
|
|
237
|
+
i0.ɵɵconditionalCreate(9, KptChatMessage_Conditional_1_Conditional_9_Template, 3, 2, "span", 9);
|
|
238
|
+
i0.ɵɵconditionalCreate(10, KptChatMessage_Conditional_1_Conditional_10_Template, 3, 1, "ul", 10);
|
|
239
|
+
i0.ɵɵelementEnd()();
|
|
240
|
+
i0.ɵɵelementStart(11, "span", 11);
|
|
241
|
+
i0.ɵɵconditionalCreate(12, KptChatMessage_Conditional_1_Conditional_12_Template, 2, 1, "kpt-icon-button", 12)(13, KptChatMessage_Conditional_1_Conditional_13_Template, 6, 6);
|
|
242
|
+
i0.ɵɵelementEnd()();
|
|
243
|
+
} if (rf & 2) {
|
|
244
|
+
let tmp_3_0;
|
|
245
|
+
let tmp_9_0;
|
|
246
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
247
|
+
i0.ɵɵattribute("data-align", ctx_r0.align());
|
|
248
|
+
i0.ɵɵadvance();
|
|
249
|
+
i0.ɵɵconditional(ctx_r0.align() === "start" ? 1 : -1);
|
|
250
|
+
i0.ɵɵadvance(2);
|
|
251
|
+
i0.ɵɵconditional((tmp_3_0 = ctx_r0.showAuthor() && ctx_r0.resolvedAuthor()) ? 3 : -1, tmp_3_0);
|
|
252
|
+
i0.ɵɵadvance();
|
|
253
|
+
i0.ɵɵattribute("data-variant", ctx_r0.resolvedVariant())("data-align", ctx_r0.align())("data-position", ctx_r0.position())("data-status", ctx_r0.resolvedStatus())("data-tail", ctx_r0.hasTail() ? "" : null);
|
|
254
|
+
i0.ɵɵadvance();
|
|
255
|
+
i0.ɵɵconditional((tmp_9_0 = ctx_r0.resolvedReplyTo()) ? 5 : -1, tmp_9_0);
|
|
256
|
+
i0.ɵɵadvance();
|
|
257
|
+
i0.ɵɵconditional(ctx_r0.resolvedText() ? 6 : -1);
|
|
258
|
+
i0.ɵɵadvance(2);
|
|
259
|
+
i0.ɵɵconditional(ctx_r0.resolvedAttachments().length ? 8 : -1);
|
|
260
|
+
i0.ɵɵadvance();
|
|
261
|
+
i0.ɵɵconditional(ctx_r0.showMeta() ? 9 : -1);
|
|
262
|
+
i0.ɵɵadvance();
|
|
263
|
+
i0.ɵɵconditional(ctx_r0.resolvedReactions().length ? 10 : -1);
|
|
264
|
+
i0.ɵɵadvance();
|
|
265
|
+
i0.ɵɵattribute("data-open", ctx_r0.pickerOpen() ? "" : null);
|
|
266
|
+
i0.ɵɵadvance();
|
|
267
|
+
i0.ɵɵconditional(ctx_r0.canRetry() ? 12 : ctx_r0.actions() ? 13 : -1);
|
|
268
|
+
} }
|
|
269
|
+
/** Ikona statusu wysyłki. `read` używa tej samej ikony co `delivered`, różni je kolor. */
|
|
270
|
+
const STATUS_ICONS = {
|
|
271
|
+
sending: 'clock',
|
|
272
|
+
sent: 'check',
|
|
273
|
+
delivered: 'checks',
|
|
274
|
+
read: 'checks',
|
|
275
|
+
failed: 'alert-triangle',
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Pojedyncza wiadomość czatu — bąbel z treścią, godziną, statusem wysyłki i opcjonalnym
|
|
279
|
+
* awatarem, cytatem, załącznikami i reakcjami.
|
|
280
|
+
*
|
|
281
|
+
* Działa na dwa sposoby: dostaje gotowy obiekt przez `[message]` (tak używa go `kpt-chat`)
|
|
282
|
+
* albo pojedyncze inputy, gdy budujesz listę samodzielnie. Treść można też wrzucić
|
|
283
|
+
* przez `<ng-content />` — projekcja wygrywa z `text`, więc bąbel przyjmuje cokolwiek.
|
|
284
|
+
*
|
|
285
|
+
* Wygląd wewnątrz grupy steruje `position`: zapadnięty narożnik od strony nadawcy i ogonek
|
|
286
|
+
* tylko przy ostatnim bąblu. Wylicza to `buildChatRows()` z `@konce-pt/chat`.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* <kpt-chat-message [message]="msg" align="end" position="last" />
|
|
290
|
+
* <kpt-chat-message align="end" status="failed" (retry)="resend()">Nie poszło</kpt-chat-message>
|
|
291
|
+
*/
|
|
292
|
+
class KptChatMessage {
|
|
293
|
+
constructor() {
|
|
294
|
+
/** Cała wiadomość naraz. Pojedyncze inputy poniżej mają nad nią priorytet. */
|
|
295
|
+
this.message = input(null, /* @ts-ignore */
|
|
296
|
+
...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
297
|
+
this.author = input(null, /* @ts-ignore */
|
|
298
|
+
...(ngDevMode ? [{ debugName: "author" }] : /* istanbul ignore next */ []));
|
|
299
|
+
this.text = input(null, /* @ts-ignore */
|
|
300
|
+
...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
301
|
+
this.time = input(null, /* @ts-ignore */
|
|
302
|
+
...(ngDevMode ? [{ debugName: "time" }] : /* istanbul ignore next */ []));
|
|
303
|
+
this.attachments = input(null, /* @ts-ignore */
|
|
304
|
+
...(ngDevMode ? [{ debugName: "attachments" }] : /* istanbul ignore next */ []));
|
|
305
|
+
this.reactions = input(null, /* @ts-ignore */
|
|
306
|
+
...(ngDevMode ? [{ debugName: "reactions" }] : /* istanbul ignore next */ []));
|
|
307
|
+
this.replyTo = input(null, /* @ts-ignore */
|
|
308
|
+
...(ngDevMode ? [{ debugName: "replyTo" }] : /* istanbul ignore next */ []));
|
|
309
|
+
this.status = input(null, /* @ts-ignore */
|
|
310
|
+
...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
311
|
+
/** Strona listy: `start` to cudza wiadomość, `end` własna. */
|
|
312
|
+
this.align = input('start', /* @ts-ignore */
|
|
313
|
+
...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
|
|
314
|
+
/** Wariant kolorystyczny; bez niego wynika z `align` (własna = `primary`). */
|
|
315
|
+
this.variant = input(null, /* @ts-ignore */
|
|
316
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
317
|
+
this.position = input('single', /* @ts-ignore */
|
|
318
|
+
...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
319
|
+
this.system = input(false, { ...(ngDevMode ? { debugName: "system" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
320
|
+
this.showAuthor = input(false, { ...(ngDevMode ? { debugName: "showAuthor" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
321
|
+
this.showAvatar = input(false, { ...(ngDevMode ? { debugName: "showAvatar" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
322
|
+
this.showMeta = input(true, { ...(ngDevMode ? { debugName: "showMeta" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
323
|
+
this.tail = input(true, { ...(ngDevMode ? { debugName: "tail" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
324
|
+
/** Akcje pod kursorem: odpowiedz i zareaguj. Domyślnie wyłączone. */
|
|
325
|
+
this.actions = input(false, { ...(ngDevMode ? { debugName: "actions" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
326
|
+
/** Zestaw wybieraka reakcji. Domyślnie pięć wbudowanych; można go skrócić lub przestawić. */
|
|
327
|
+
this.reactionOptions = input(KPT_CHAT_REACTIONS, /* @ts-ignore */
|
|
328
|
+
...(ngDevMode ? [{ debugName: "reactionOptions" }] : /* istanbul ignore next */ []));
|
|
329
|
+
this.retry = output();
|
|
330
|
+
this.reply = output();
|
|
331
|
+
/** Wybrana reakcja (emoji). Biblioteka niczego nie dopisuje do modelu — robi to aplikacja. */
|
|
332
|
+
this.react = output();
|
|
333
|
+
/** Kliknięcie w cytat — aplikacja może przewinąć listę do oryginału. */
|
|
334
|
+
this.quoted = output();
|
|
335
|
+
this.i18n = inject(KptI18n);
|
|
336
|
+
this.host = inject((ElementRef));
|
|
337
|
+
/** Czy wybierak reakcji jest otwarty. */
|
|
338
|
+
this.pickerOpen = signal(false, /* @ts-ignore */
|
|
339
|
+
...(ngDevMode ? [{ debugName: "pickerOpen" }] : /* istanbul ignore next */ []));
|
|
340
|
+
this.isSystem = computed(() => this.system() || (this.message()?.system ?? false), /* @ts-ignore */
|
|
341
|
+
...(ngDevMode ? [{ debugName: "isSystem" }] : /* istanbul ignore next */ []));
|
|
342
|
+
this.resolvedAuthor = computed(() => this.author() ?? this.message()?.author ?? null, /* @ts-ignore */
|
|
343
|
+
...(ngDevMode ? [{ debugName: "resolvedAuthor" }] : /* istanbul ignore next */ []));
|
|
344
|
+
this.resolvedText = computed(() => this.text() ?? this.message()?.text ?? '', /* @ts-ignore */
|
|
345
|
+
...(ngDevMode ? [{ debugName: "resolvedText" }] : /* istanbul ignore next */ []));
|
|
346
|
+
this.resolvedStatus = computed(() => this.status() ?? this.message()?.status ?? null, /* @ts-ignore */
|
|
347
|
+
...(ngDevMode ? [{ debugName: "resolvedStatus" }] : /* istanbul ignore next */ []));
|
|
348
|
+
this.resolvedReplyTo = computed(() => this.replyTo() ?? this.message()?.replyTo ?? null, /* @ts-ignore */
|
|
349
|
+
...(ngDevMode ? [{ debugName: "resolvedReplyTo" }] : /* istanbul ignore next */ []));
|
|
350
|
+
this.resolvedAttachments = computed(() => this.attachments() ?? this.message()?.attachments ?? [], /* @ts-ignore */
|
|
351
|
+
...(ngDevMode ? [{ debugName: "resolvedAttachments" }] : /* istanbul ignore next */ []));
|
|
352
|
+
this.resolvedReactions = computed(() => this.reactions() ?? this.message()?.reactions ?? [], /* @ts-ignore */
|
|
353
|
+
...(ngDevMode ? [{ debugName: "resolvedReactions" }] : /* istanbul ignore next */ []));
|
|
354
|
+
this.sentAt = computed(() => {
|
|
355
|
+
const value = this.time() ?? this.message()?.sentAt ?? null;
|
|
356
|
+
return value === null ? null : toDate(value);
|
|
357
|
+
}, /* @ts-ignore */
|
|
358
|
+
...(ngDevMode ? [{ debugName: "sentAt" }] : /* istanbul ignore next */ []));
|
|
359
|
+
/**
|
|
360
|
+
* Wariant domyślny bierze się z wyrównania. Własna wiadomość dostaje pełny `solid`,
|
|
361
|
+
* bo motyw biblioteki jest monochromatyczny: pastelowy `primary-subtle` ma tę samą
|
|
362
|
+
* jasność co `muted`, więc własny i cudzy bąbel byłyby nie do odróżnienia. Kto woli
|
|
363
|
+
* ciszej, ustawia `variant="primary"` ręcznie.
|
|
364
|
+
*/
|
|
365
|
+
this.resolvedVariant = computed(() => {
|
|
366
|
+
if (this.isSystem())
|
|
367
|
+
return 'system';
|
|
368
|
+
return this.variant() ?? (this.align() === 'end' ? 'solid' : 'neutral');
|
|
369
|
+
}, /* @ts-ignore */
|
|
370
|
+
...(ngDevMode ? [{ debugName: "resolvedVariant" }] : /* istanbul ignore next */ []));
|
|
371
|
+
/** Ogonek tylko na końcu grupy i tylko tam, gdzie bąbel ma tło, z którego da się go wyciąć. */
|
|
372
|
+
this.hasTail = computed(() => {
|
|
373
|
+
const variant = this.resolvedVariant();
|
|
374
|
+
if (!this.tail() || variant === 'ghost' || variant === 'system')
|
|
375
|
+
return false;
|
|
376
|
+
return this.position() === 'last' || this.position() === 'single';
|
|
377
|
+
}, /* @ts-ignore */
|
|
378
|
+
...(ngDevMode ? [{ debugName: "hasTail" }] : /* istanbul ignore next */ []));
|
|
379
|
+
this.canRetry = computed(() => canRetry(this.resolvedStatus()), /* @ts-ignore */
|
|
380
|
+
...(ngDevMode ? [{ debugName: "canRetry" }] : /* istanbul ignore next */ []));
|
|
381
|
+
this.statusIcon = computed(() => {
|
|
382
|
+
const status = this.resolvedStatus();
|
|
383
|
+
return status ? STATUS_ICONS[status] : null;
|
|
384
|
+
}, /* @ts-ignore */
|
|
385
|
+
...(ngDevMode ? [{ debugName: "statusIcon" }] : /* istanbul ignore next */ []));
|
|
386
|
+
this.timeLabel = computed(() => {
|
|
387
|
+
const date = this.sentAt();
|
|
388
|
+
if (!date)
|
|
389
|
+
return '';
|
|
390
|
+
return new Intl.DateTimeFormat(this.i18n.locale(), { hour: '2-digit', minute: '2-digit' }).format(date);
|
|
391
|
+
}, /* @ts-ignore */
|
|
392
|
+
...(ngDevMode ? [{ debugName: "timeLabel" }] : /* istanbul ignore next */ []));
|
|
393
|
+
this.isoTime = computed(() => this.sentAt()?.toISOString() ?? null, /* @ts-ignore */
|
|
394
|
+
...(ngDevMode ? [{ debugName: "isoTime" }] : /* istanbul ignore next */ []));
|
|
395
|
+
/**
|
|
396
|
+
* Etykieta dla czytnika ekranu. Bez niej z bąbla płynie sama treść — bez nadawcy,
|
|
397
|
+
* godziny i informacji, że wiadomość się nie wysłała.
|
|
398
|
+
*/
|
|
399
|
+
this.ariaLabel = computed(() => {
|
|
400
|
+
if (this.isSystem())
|
|
401
|
+
return this.resolvedText();
|
|
402
|
+
const parts = [this.resolvedAuthor()?.name, this.timeLabel()];
|
|
403
|
+
const status = this.resolvedStatus();
|
|
404
|
+
if (status)
|
|
405
|
+
parts.push(this.i18n.t('chat.' + status));
|
|
406
|
+
return parts.filter(Boolean).join(', ');
|
|
407
|
+
}, /* @ts-ignore */
|
|
408
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
409
|
+
this.statusLabel = computed(() => {
|
|
410
|
+
const status = this.resolvedStatus();
|
|
411
|
+
return status ? this.i18n.t('chat.' + status) : '';
|
|
412
|
+
}, /* @ts-ignore */
|
|
413
|
+
...(ngDevMode ? [{ debugName: "statusLabel" }] : /* istanbul ignore next */ []));
|
|
414
|
+
// Kliknięcie obok zamyka wybierak. Sam `focusout` nie wystarcza: w Safari kliknięcie
|
|
415
|
+
// w przycisk nie przenosi na niego fokusu, więc wybierak zostawałby otwarty na zawsze.
|
|
416
|
+
effect((onCleanup) => {
|
|
417
|
+
if (!this.pickerOpen())
|
|
418
|
+
return;
|
|
419
|
+
const close = (event) => {
|
|
420
|
+
if (!this.host.nativeElement.contains(event.target))
|
|
421
|
+
this.pickerOpen.set(false);
|
|
422
|
+
};
|
|
423
|
+
// Faza przechwytywania: własne `click` na opcji zdąży się wykonać przed zamknięciem,
|
|
424
|
+
// bo wybierak zamyka `pointerdown`, nie `click`.
|
|
425
|
+
document.addEventListener('pointerdown', close, true);
|
|
426
|
+
onCleanup(() => document.removeEventListener('pointerdown', close, true));
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
/** Etykieta opcji wybieraka — `like` → `chat.reactLike`. */
|
|
430
|
+
reactionLabel(option) {
|
|
431
|
+
return this.i18n.t('chat.react' + option.kind[0].toUpperCase() + option.kind.slice(1));
|
|
432
|
+
}
|
|
433
|
+
/** Czy bieżący użytkownik dał już tę reakcję — opcja wybieraka pokazuje to przez `aria-pressed`. */
|
|
434
|
+
hasReacted(emoji) {
|
|
435
|
+
return this.resolvedReactions().some((reaction) => reaction.emoji === emoji && reaction.reacted);
|
|
436
|
+
}
|
|
437
|
+
pick(emoji) {
|
|
438
|
+
this.react.emit(emoji);
|
|
439
|
+
this.pickerOpen.set(false);
|
|
440
|
+
}
|
|
441
|
+
/** Wyjście fokusu poza wybierak zamyka go — przechodzenie Tabem między opcjami nie. */
|
|
442
|
+
onPickerFocusOut(event) {
|
|
443
|
+
const container = event.currentTarget;
|
|
444
|
+
const next = event.relatedTarget;
|
|
445
|
+
if (!next || !container.contains(next))
|
|
446
|
+
this.pickerOpen.set(false);
|
|
447
|
+
}
|
|
448
|
+
/** Rozmiar załącznika w kB/MB — surowe bajty nic nie mówią przy pliku obok nazwy. */
|
|
449
|
+
fileSize(bytes) {
|
|
450
|
+
if (!bytes)
|
|
451
|
+
return '';
|
|
452
|
+
if (bytes < 1024)
|
|
453
|
+
return bytes + ' B';
|
|
454
|
+
if (bytes < 1024 * 1024)
|
|
455
|
+
return Math.round(bytes / 1024) + ' kB';
|
|
456
|
+
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
457
|
+
}
|
|
458
|
+
static { this.ɵfac = function KptChatMessage_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || KptChatMessage)(); }; }
|
|
459
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: KptChatMessage, selectors: [["kpt-chat-message"]], hostAttrs: [1, "kpt-chat-message-host"], hostVars: 2, hostBindings: function KptChatMessage_HostBindings(rf, ctx) { if (rf & 2) {
|
|
460
|
+
i0.ɵɵattribute("role", ctx.isSystem() ? "note" : "article")("aria-label", ctx.ariaLabel());
|
|
461
|
+
} }, inputs: { message: [1, "message"], author: [1, "author"], text: [1, "text"], time: [1, "time"], attachments: [1, "attachments"], reactions: [1, "reactions"], replyTo: [1, "replyTo"], status: [1, "status"], align: [1, "align"], variant: [1, "variant"], position: [1, "position"], system: [1, "system"], showAuthor: [1, "showAuthor"], showAvatar: [1, "showAvatar"], showMeta: [1, "showMeta"], tail: [1, "tail"], actions: [1, "actions"], reactionOptions: [1, "reactionOptions"] }, outputs: { retry: "retry", reply: "reply", react: "react", quoted: "quoted" }, ngContentSelectors: _c0$3, decls: 2, vars: 1, consts: [[1, "kpt-chat-message__system"], [1, "kpt-chat-message__row"], ["aria-hidden", "true", 1, "kpt-chat-message__avatar"], [1, "kpt-chat-message__stack"], [1, "kpt-chat-message__author"], [1, "kpt-chat-message__bubble"], ["type", "button", 1, "kpt-chat-message__quote"], [1, "kpt-chat-message__text"], [1, "kpt-chat-message__files"], [1, "kpt-chat-message__meta"], [1, "kpt-chat-message__reactions"], [1, "kpt-chat-message__actions"], ["size", "sm", 1, "kpt-chat-message__retry", 3, "ariaLabel"], ["size", "sm", 3, "src", "name"], ["type", "button", 1, "kpt-chat-message__quote", 3, "click"], [1, "kpt-chat-message__quote-author"], [1, "kpt-chat-message__quote-text"], [1, "kpt-chat-message__file"], [1, "kpt-chat-message__file-thumb", 3, "src", "alt"], ["name", "paperclip", "aria-hidden", "true"], [1, "kpt-chat-message__file-name"], [1, "kpt-chat-message__file-size"], [1, "kpt-chat-message__time"], ["aria-hidden", "true", 1, "kpt-chat-message__status", 3, "name"], [1, "kpt-chat-message__reaction"], ["aria-hidden", "true"], [1, "kpt-chat-message__reaction-count"], ["size", "sm", 1, "kpt-chat-message__retry", 3, "click", "ariaLabel"], ["name", "refresh"], ["size", "sm", 3, "click", "ariaLabel"], ["name", "corner-up-left"], [1, "kpt-chat-message__react", 3, "keydown.escape", "focusout"], ["size", "sm", 3, "click", "ariaLabel", "ariaExpanded"], ["name", "mood-smile"], ["role", "group", 1, "kpt-chat-message__picker"], ["type", "button", 1, "kpt-chat-message__pick"], ["type", "button", 1, "kpt-chat-message__pick", 3, "click"]], template: function KptChatMessage_Template(rf, ctx) { if (rf & 1) {
|
|
462
|
+
i0.ɵɵprojectionDef();
|
|
463
|
+
i0.ɵɵconditionalCreate(0, KptChatMessage_Conditional_0_Template, 2, 1, "p", 0)(1, KptChatMessage_Conditional_1_Template, 14, 15, "div", 1);
|
|
464
|
+
} if (rf & 2) {
|
|
465
|
+
i0.ɵɵconditional(ctx.isSystem() ? 0 : 1);
|
|
466
|
+
} }, dependencies: [KptAvatar, KptIcon, KptIconButton], styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-message-host{display:block}.kpt-chat-message__system{margin:var(--%NS%kpt-space-2, .5rem) 0;text-align:center;color:var(--%NS%kpt-color-text-muted);font-size:var(--%NS%kpt-font-size-xs, .75rem)}.kpt-chat-message__row{display:flex;align-items:flex-end;gap:var(--%NS%kpt-space-2, .5rem)}.kpt-chat-message__row[data-align=end]{flex-direction:row-reverse}.kpt-chat-message__avatar{flex:0 0 2rem;align-self:flex-end}.kpt-chat-message__stack{display:flex;flex-direction:column;min-width:0;max-inline-size:min(42rem,78%)}.kpt-chat-message__author{margin-inline-start:var(--%NS%kpt-space-3, .75rem);margin-block-end:var(--%NS%kpt-space-1, .25rem);color:var(--%NS%kpt-color-text-muted);font-size:var(--%NS%kpt-font-size-xs, .75rem);font-weight:var(--%NS%kpt-font-weight-medium, 500)}.kpt-chat-message__bubble{--%NS%_bg: var(--%NS%kpt-color-muted);--%NS%_fg: var(--%NS%kpt-color-on-muted);--%NS%_radius: var(--%NS%kpt-radius-lg, .75rem);--%NS%_radius-tight: var(--%NS%kpt-radius-sm, .25rem);position:relative;padding:var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-3, .75rem);border-radius:var(--%NS%_radius);background:var(--%NS%_bg);color:var(--%NS%_fg);font-size:var(--%NS%kpt-font-size-sm, .875rem);line-height:var(--%NS%kpt-font-lineHeight-normal, 1.5)}.kpt-chat-message__bubble[data-variant=primary]{--%NS%_bg: var(--%NS%kpt-color-primary-subtle);--%NS%_fg: var(--%NS%kpt-color-text)}.kpt-chat-message__bubble[data-variant=solid]{--%NS%_bg: var(--%NS%kpt-color-primary);--%NS%_fg: var(--%NS%kpt-color-on-primary)}.kpt-chat-message__bubble[data-variant=ghost]{--%NS%_bg: transparent;--%NS%_fg: var(--%NS%kpt-color-text);padding-inline:0}.kpt-chat-message__bubble[data-status=failed]{--%NS%_bg: var(--%NS%kpt-color-danger-subtle);--%NS%_fg: var(--%NS%kpt-color-text);box-shadow:inset 0 0 0 var(--%NS%kpt-border-width-thin, 1px) var(--%NS%kpt-color-danger-border)}.kpt-chat-message__bubble[data-align=end][data-position=first]{border-end-end-radius:var(--%NS%_radius-tight)}.kpt-chat-message__bubble[data-align=end][data-position=middle]{border-start-end-radius:var(--%NS%_radius-tight);border-end-end-radius:var(--%NS%_radius-tight)}.kpt-chat-message__bubble[data-align=end][data-position=last]{border-start-end-radius:var(--%NS%_radius-tight)}.kpt-chat-message__bubble[data-align=start][data-position=first]{border-end-start-radius:var(--%NS%_radius-tight)}.kpt-chat-message__bubble[data-align=start][data-position=middle]{border-start-start-radius:var(--%NS%_radius-tight);border-end-start-radius:var(--%NS%_radius-tight)}.kpt-chat-message__bubble[data-align=start][data-position=last]{border-start-start-radius:var(--%NS%_radius-tight)}.kpt-chat-message__bubble[data-tail][data-align=end]{border-end-end-radius:0}.kpt-chat-message__bubble[data-tail][data-align=start]{border-end-start-radius:0}.kpt-chat-message__bubble[data-tail]:after{content:\"\";position:absolute;inset-block-end:0;inline-size:.75rem;block-size:.75rem;background:var(--%NS%_bg);-webkit-mask:radial-gradient(circle at 100% 0,transparent 0 .75rem,#000 .75rem);mask:radial-gradient(circle at 100% 0,transparent 0 .75rem,#000 .75rem)}.kpt-chat-message__bubble[data-tail][data-align=end]:after{inset-inline-end:-.5rem}.kpt-chat-message__bubble[data-tail][data-align=start]:after{inset-inline-start:-.5rem;transform:scaleX(-1)}.kpt-chat-message__bubble:has(.kpt-chat-message__reactions){margin-block-end:.875rem}.kpt-chat-message__quote{display:flex;flex-direction:column;gap:.125rem;width:100%;margin-block-end:var(--%NS%kpt-space-1, .25rem);padding:var(--%NS%kpt-space-1, .25rem) var(--%NS%kpt-space-2, .5rem);border:0;border-inline-start:2px solid var(--%NS%kpt-color-primary);border-radius:var(--%NS%kpt-radius-sm, .25rem);background:color-mix(in oklch,currentColor 8%,transparent);color:inherit;font:inherit;text-align:start;cursor:pointer}.kpt-chat-message__quote-author{font-size:var(--%NS%kpt-font-size-xs, .75rem);font-weight:var(--%NS%kpt-font-weight-semibold, 600)}.kpt-chat-message__quote-text{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;font-size:var(--%NS%kpt-font-size-xs, .75rem);opacity:.8}.kpt-chat-message__text{margin:0;white-space:pre-wrap;overflow-wrap:anywhere}.kpt-chat-message__files{display:flex;flex-direction:column;gap:var(--%NS%kpt-space-1, .25rem);margin:var(--%NS%kpt-space-2, .5rem) 0 0;padding:0;list-style:none}.kpt-chat-message__file{display:flex;align-items:center;gap:var(--%NS%kpt-space-2, .5rem);font-size:var(--%NS%kpt-font-size-xs, .75rem)}.kpt-chat-message__file-thumb{width:2rem;height:2rem;border-radius:var(--%NS%kpt-radius-sm, .25rem);object-fit:cover}.kpt-chat-message__file-name{color:inherit;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kpt-chat-message__file-size{color:inherit;opacity:.6}.kpt-chat-message__meta{display:flex;align-items:center;justify-content:flex-end;gap:.25rem;margin-block-start:.125rem;font-size:var(--%NS%kpt-font-size-xs, .75rem);opacity:.7}.kpt-chat-message__status{font-size:.875rem}.kpt-chat-message__bubble[data-status=read] .kpt-chat-message__status{color:var(--%NS%kpt-color-primary);opacity:1}.kpt-chat-message__bubble[data-variant=solid][data-status=read] .kpt-chat-message__status{color:currentcolor}.kpt-chat-message__bubble[data-status=failed] .kpt-chat-message__status{color:var(--%NS%kpt-color-danger);opacity:1}.kpt-chat-message__reactions{position:absolute;inset-block-end:-.75rem;display:flex;gap:.25rem;margin:0;padding:0;list-style:none}.kpt-chat-message__reactions[data-align=end]{inset-inline-end:var(--%NS%kpt-space-2, .5rem)}.kpt-chat-message__reactions[data-align=start]{inset-inline-start:var(--%NS%kpt-space-2, .5rem)}.kpt-chat-message__reaction{display:inline-flex;align-items:center;gap:.125rem;padding:.0625rem .375rem;border:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-border);border-radius:var(--%NS%kpt-radius-full, 9999px);background:var(--%NS%kpt-color-surface-raised);color:var(--%NS%kpt-color-text);font-size:var(--%NS%kpt-font-size-xs, .75rem);line-height:1.25;box-shadow:var(--%NS%kpt-elevation-1)}.kpt-chat-message__reaction[data-reacted]{border-color:var(--%NS%kpt-color-primary-border);background:var(--%NS%kpt-color-primary-subtle)}.kpt-chat-message__reaction-count{opacity:.7}.kpt-chat-message__actions{display:flex;flex:0 0 auto;align-items:center;gap:.125rem}.kpt-chat-message__actions .kpt-icon-button-host{opacity:0;transition:opacity var(--%NS%kpt-motion-duration-fast, .12s) var(--%NS%kpt-motion-easing-standard, ease)}.kpt-chat-message__actions .kpt-chat-message__retry{opacity:1;color:var(--%NS%kpt-color-danger)}.kpt-chat-message__row:hover .kpt-chat-message__actions .kpt-icon-button-host,.kpt-chat-message__row:focus-within .kpt-chat-message__actions .kpt-icon-button-host,.kpt-chat-message__actions[data-open] .kpt-icon-button-host{opacity:1}.kpt-chat-message__react{position:relative;display:inline-flex}.kpt-chat-message__picker{position:absolute;inset-block-end:calc(100% + var(--%NS%kpt-space-1, .25rem));inset-inline-end:0;z-index:var(--%NS%kpt-z-raised, 1);display:flex;gap:.125rem;padding:.1875rem;border:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-border);border-radius:var(--%NS%kpt-radius-full, 9999px);background:var(--%NS%kpt-color-surface-raised);box-shadow:var(--%NS%kpt-elevation-2)}.kpt-chat-message__row[data-align=end] .kpt-chat-message__picker{inset-inline:0 auto}.kpt-chat-message__pick{display:inline-flex;align-items:center;justify-content:center;inline-size:1.75rem;block-size:1.75rem;padding:0;border:0;border-radius:var(--%NS%kpt-radius-full, 9999px);background:transparent;font:inherit;font-size:var(--%NS%kpt-font-size-md, 1rem);line-height:1;cursor:pointer;transition:transform var(--%NS%kpt-motion-duration-fast, .12s) var(--%NS%kpt-motion-easing-standard, ease)}.kpt-chat-message__pick:hover{background:var(--%NS%kpt-color-surface-hover);transform:scale(1.15)}.kpt-chat-message__pick:focus-visible{outline:2px solid var(--%NS%kpt-color-focus-ring);outline-offset:1px}.kpt-chat-message__pick[aria-pressed=true]{background:var(--%NS%kpt-color-primary-subtle)}@media(prefers-reduced-motion:reduce){.kpt-chat-message__actions .kpt-icon-button-host,.kpt-chat-message__pick{transition:none}.kpt-chat-message__pick:hover{transform:none}}}\n"], encapsulation: 2 }); }
|
|
467
|
+
}
|
|
468
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(KptChatMessage, [{
|
|
469
|
+
type: Component,
|
|
470
|
+
args: [{ selector: 'kpt-chat-message', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [KptAvatar, KptIcon, KptIconButton], host: {
|
|
471
|
+
class: 'kpt-chat-message-host',
|
|
472
|
+
'[attr.role]': 'isSystem() ? "note" : "article"',
|
|
473
|
+
'[attr.aria-label]': 'ariaLabel()',
|
|
474
|
+
}, template: "@if (isSystem()) {\n <p class=\"kpt-chat-message__system\">{{ resolvedText() }}</p>\n} @else {\n <div class=\"kpt-chat-message__row\" [attr.data-align]=\"align()\">\n @if (align() === 'start') {\n <span class=\"kpt-chat-message__avatar\" aria-hidden=\"true\">\n @if (showAvatar()) {\n <kpt-avatar size=\"sm\" [src]=\"resolvedAuthor()?.avatar ?? null\" [name]=\"resolvedAuthor()?.name ?? ''\" />\n }\n </span>\n }\n\n <div class=\"kpt-chat-message__stack\">\n @if (showAuthor() && resolvedAuthor(); as author) {\n <span class=\"kpt-chat-message__author\">{{ author.name }}</span>\n }\n\n <div\n class=\"kpt-chat-message__bubble\"\n [attr.data-variant]=\"resolvedVariant()\"\n [attr.data-align]=\"align()\"\n [attr.data-position]=\"position()\"\n [attr.data-status]=\"resolvedStatus()\"\n [attr.data-tail]=\"hasTail() ? '' : null\"\n >\n @if (resolvedReplyTo(); as quote) {\n <button type=\"button\" class=\"kpt-chat-message__quote\" (click)=\"quoted.emit(quote)\">\n <span class=\"kpt-chat-message__quote-author\">{{ quote.author }}</span>\n <span class=\"kpt-chat-message__quote-text\">{{ quote.excerpt }}</span>\n </button>\n }\n\n @if (resolvedText()) {\n <p class=\"kpt-chat-message__text\">{{ resolvedText() }}</p>\n }\n <ng-content />\n\n @if (resolvedAttachments().length) {\n <ul class=\"kpt-chat-message__files\">\n @for (file of resolvedAttachments(); track file.id) {\n <li class=\"kpt-chat-message__file\">\n @if (file.thumbnail) {\n <img class=\"kpt-chat-message__file-thumb\" [src]=\"file.thumbnail\" [alt]=\"file.name\" />\n } @else {\n <kpt-icon name=\"paperclip\" aria-hidden=\"true\" />\n }\n <a class=\"kpt-chat-message__file-name\" [attr.href]=\"file.url ?? null\" [attr.download]=\"file.url ? file.name : null\">\n {{ file.name }}\n </a>\n @if (file.size) {\n <span class=\"kpt-chat-message__file-size\">{{ fileSize(file.size) }}</span>\n }\n </li>\n }\n </ul>\n }\n\n @if (showMeta()) {\n <span class=\"kpt-chat-message__meta\">\n @if (timeLabel()) {\n <time class=\"kpt-chat-message__time\" [attr.datetime]=\"isoTime()\">{{ timeLabel() }}</time>\n }\n @if (statusIcon(); as icon) {\n <kpt-icon class=\"kpt-chat-message__status\" [name]=\"icon\" aria-hidden=\"true\" />\n }\n </span>\n }\n\n @if (resolvedReactions().length) {\n <ul class=\"kpt-chat-message__reactions\" [attr.data-align]=\"align()\">\n @for (reaction of resolvedReactions(); track reaction.emoji) {\n <li class=\"kpt-chat-message__reaction\" [attr.data-reacted]=\"reaction.reacted ? '' : null\">\n <span aria-hidden=\"true\">{{ reaction.emoji }}</span>\n <span class=\"kpt-chat-message__reaction-count\">{{ reaction.count }}</span>\n </li>\n }\n </ul>\n }\n </div>\n </div>\n\n <span class=\"kpt-chat-message__actions\" [attr.data-open]=\"pickerOpen() ? '' : null\">\n @if (canRetry()) {\n <kpt-icon-button\n class=\"kpt-chat-message__retry\"\n size=\"sm\"\n [ariaLabel]=\"i18n.t('chat.retry')\"\n (click)=\"retry.emit()\"\n >\n <kpt-icon name=\"refresh\" />\n </kpt-icon-button>\n } @else if (actions()) {\n <kpt-icon-button size=\"sm\" [ariaLabel]=\"i18n.t('chat.replyTo', { author: resolvedAuthor()?.name ?? '' })\" (click)=\"reply.emit()\">\n <kpt-icon name=\"corner-up-left\" />\n </kpt-icon-button>\n\n <span class=\"kpt-chat-message__react\" (keydown.escape)=\"pickerOpen.set(false)\" (focusout)=\"onPickerFocusOut($event)\">\n <kpt-icon-button\n size=\"sm\"\n [ariaLabel]=\"i18n.t('chat.react')\"\n [ariaExpanded]=\"pickerOpen()\"\n (click)=\"pickerOpen.set(!pickerOpen())\"\n >\n <kpt-icon name=\"mood-smile\" />\n </kpt-icon-button>\n\n @if (pickerOpen()) {\n <span class=\"kpt-chat-message__picker\" role=\"group\" [attr.aria-label]=\"i18n.t('chat.react')\">\n @for (option of reactionOptions(); track option.kind) {\n <button\n type=\"button\"\n class=\"kpt-chat-message__pick\"\n [attr.aria-label]=\"reactionLabel(option)\"\n [attr.title]=\"reactionLabel(option)\"\n [attr.aria-pressed]=\"hasReacted(option.emoji)\"\n (click)=\"pick(option.emoji)\"\n >\n <span aria-hidden=\"true\">{{ option.emoji }}</span>\n </button>\n }\n </span>\n }\n </span>\n }\n </span>\n </div>\n}\n", styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-message-host{display:block}.kpt-chat-message__system{margin:var(--kpt-space-2, .5rem) 0;text-align:center;color:var(--kpt-color-text-muted);font-size:var(--kpt-font-size-xs, .75rem)}.kpt-chat-message__row{display:flex;align-items:flex-end;gap:var(--kpt-space-2, .5rem)}.kpt-chat-message__row[data-align=end]{flex-direction:row-reverse}.kpt-chat-message__avatar{flex:0 0 2rem;align-self:flex-end}.kpt-chat-message__stack{display:flex;flex-direction:column;min-width:0;max-inline-size:min(42rem,78%)}.kpt-chat-message__author{margin-inline-start:var(--kpt-space-3, .75rem);margin-block-end:var(--kpt-space-1, .25rem);color:var(--kpt-color-text-muted);font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-medium, 500)}.kpt-chat-message__bubble{--_bg: var(--kpt-color-muted);--_fg: var(--kpt-color-on-muted);--_radius: var(--kpt-radius-lg, .75rem);--_radius-tight: var(--kpt-radius-sm, .25rem);position:relative;padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border-radius:var(--_radius);background:var(--_bg);color:var(--_fg);font-size:var(--kpt-font-size-sm, .875rem);line-height:var(--kpt-font-lineHeight-normal, 1.5)}.kpt-chat-message__bubble[data-variant=primary]{--_bg: var(--kpt-color-primary-subtle);--_fg: var(--kpt-color-text)}.kpt-chat-message__bubble[data-variant=solid]{--_bg: var(--kpt-color-primary);--_fg: var(--kpt-color-on-primary)}.kpt-chat-message__bubble[data-variant=ghost]{--_bg: transparent;--_fg: var(--kpt-color-text);padding-inline:0}.kpt-chat-message__bubble[data-status=failed]{--_bg: var(--kpt-color-danger-subtle);--_fg: var(--kpt-color-text);box-shadow:inset 0 0 0 var(--kpt-border-width-thin, 1px) var(--kpt-color-danger-border)}.kpt-chat-message__bubble[data-align=end][data-position=first]{border-end-end-radius:var(--_radius-tight)}.kpt-chat-message__bubble[data-align=end][data-position=middle]{border-start-end-radius:var(--_radius-tight);border-end-end-radius:var(--_radius-tight)}.kpt-chat-message__bubble[data-align=end][data-position=last]{border-start-end-radius:var(--_radius-tight)}.kpt-chat-message__bubble[data-align=start][data-position=first]{border-end-start-radius:var(--_radius-tight)}.kpt-chat-message__bubble[data-align=start][data-position=middle]{border-start-start-radius:var(--_radius-tight);border-end-start-radius:var(--_radius-tight)}.kpt-chat-message__bubble[data-align=start][data-position=last]{border-start-start-radius:var(--_radius-tight)}.kpt-chat-message__bubble[data-tail][data-align=end]{border-end-end-radius:0}.kpt-chat-message__bubble[data-tail][data-align=start]{border-end-start-radius:0}.kpt-chat-message__bubble[data-tail]:after{content:\"\";position:absolute;inset-block-end:0;inline-size:.75rem;block-size:.75rem;background:var(--_bg);-webkit-mask:radial-gradient(circle at 100% 0,transparent 0 .75rem,#000 .75rem);mask:radial-gradient(circle at 100% 0,transparent 0 .75rem,#000 .75rem)}.kpt-chat-message__bubble[data-tail][data-align=end]:after{inset-inline-end:-.5rem}.kpt-chat-message__bubble[data-tail][data-align=start]:after{inset-inline-start:-.5rem;transform:scaleX(-1)}.kpt-chat-message__bubble:has(.kpt-chat-message__reactions){margin-block-end:.875rem}.kpt-chat-message__quote{display:flex;flex-direction:column;gap:.125rem;width:100%;margin-block-end:var(--kpt-space-1, .25rem);padding:var(--kpt-space-1, .25rem) var(--kpt-space-2, .5rem);border:0;border-inline-start:2px solid var(--kpt-color-primary);border-radius:var(--kpt-radius-sm, .25rem);background:color-mix(in oklch,currentColor 8%,transparent);color:inherit;font:inherit;text-align:start;cursor:pointer}.kpt-chat-message__quote-author{font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-chat-message__quote-text{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;font-size:var(--kpt-font-size-xs, .75rem);opacity:.8}.kpt-chat-message__text{margin:0;white-space:pre-wrap;overflow-wrap:anywhere}.kpt-chat-message__files{display:flex;flex-direction:column;gap:var(--kpt-space-1, .25rem);margin:var(--kpt-space-2, .5rem) 0 0;padding:0;list-style:none}.kpt-chat-message__file{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);font-size:var(--kpt-font-size-xs, .75rem)}.kpt-chat-message__file-thumb{width:2rem;height:2rem;border-radius:var(--kpt-radius-sm, .25rem);object-fit:cover}.kpt-chat-message__file-name{color:inherit;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kpt-chat-message__file-size{color:inherit;opacity:.6}.kpt-chat-message__meta{display:flex;align-items:center;justify-content:flex-end;gap:.25rem;margin-block-start:.125rem;font-size:var(--kpt-font-size-xs, .75rem);opacity:.7}.kpt-chat-message__status{font-size:.875rem}.kpt-chat-message__bubble[data-status=read] .kpt-chat-message__status{color:var(--kpt-color-primary);opacity:1}.kpt-chat-message__bubble[data-variant=solid][data-status=read] .kpt-chat-message__status{color:currentcolor}.kpt-chat-message__bubble[data-status=failed] .kpt-chat-message__status{color:var(--kpt-color-danger);opacity:1}.kpt-chat-message__reactions{position:absolute;inset-block-end:-.75rem;display:flex;gap:.25rem;margin:0;padding:0;list-style:none}.kpt-chat-message__reactions[data-align=end]{inset-inline-end:var(--kpt-space-2, .5rem)}.kpt-chat-message__reactions[data-align=start]{inset-inline-start:var(--kpt-space-2, .5rem)}.kpt-chat-message__reaction{display:inline-flex;align-items:center;gap:.125rem;padding:.0625rem .375rem;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-raised);color:var(--kpt-color-text);font-size:var(--kpt-font-size-xs, .75rem);line-height:1.25;box-shadow:var(--kpt-elevation-1)}.kpt-chat-message__reaction[data-reacted]{border-color:var(--kpt-color-primary-border);background:var(--kpt-color-primary-subtle)}.kpt-chat-message__reaction-count{opacity:.7}.kpt-chat-message__actions{display:flex;flex:0 0 auto;align-items:center;gap:.125rem}.kpt-chat-message__actions .kpt-icon-button-host{opacity:0;transition:opacity var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard, ease)}.kpt-chat-message__actions .kpt-chat-message__retry{opacity:1;color:var(--kpt-color-danger)}.kpt-chat-message__row:hover .kpt-chat-message__actions .kpt-icon-button-host,.kpt-chat-message__row:focus-within .kpt-chat-message__actions .kpt-icon-button-host,.kpt-chat-message__actions[data-open] .kpt-icon-button-host{opacity:1}.kpt-chat-message__react{position:relative;display:inline-flex}.kpt-chat-message__picker{position:absolute;inset-block-end:calc(100% + var(--kpt-space-1, .25rem));inset-inline-end:0;z-index:var(--kpt-z-raised, 1);display:flex;gap:.125rem;padding:.1875rem;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-raised);box-shadow:var(--kpt-elevation-2)}.kpt-chat-message__row[data-align=end] .kpt-chat-message__picker{inset-inline:0 auto}.kpt-chat-message__pick{display:inline-flex;align-items:center;justify-content:center;inline-size:1.75rem;block-size:1.75rem;padding:0;border:0;border-radius:var(--kpt-radius-full, 9999px);background:transparent;font:inherit;font-size:var(--kpt-font-size-md, 1rem);line-height:1;cursor:pointer;transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard, ease)}.kpt-chat-message__pick:hover{background:var(--kpt-color-surface-hover);transform:scale(1.15)}.kpt-chat-message__pick:focus-visible{outline:2px solid var(--kpt-color-focus-ring);outline-offset:1px}.kpt-chat-message__pick[aria-pressed=true]{background:var(--kpt-color-primary-subtle)}@media(prefers-reduced-motion:reduce){.kpt-chat-message__actions .kpt-icon-button-host,.kpt-chat-message__pick{transition:none}.kpt-chat-message__pick:hover{transform:none}}}\n"] }]
|
|
475
|
+
}], () => [], { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], author: [{ type: i0.Input, args: [{ isSignal: true, alias: "author", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], time: [{ type: i0.Input, args: [{ isSignal: true, alias: "time", required: false }] }], attachments: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachments", required: false }] }], reactions: [{ type: i0.Input, args: [{ isSignal: true, alias: "reactions", required: false }] }], replyTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "replyTo", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], system: [{ type: i0.Input, args: [{ isSignal: true, alias: "system", required: false }] }], showAuthor: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAuthor", required: false }] }], showAvatar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAvatar", required: false }] }], showMeta: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMeta", required: false }] }], tail: [{ type: i0.Input, args: [{ isSignal: true, alias: "tail", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], reactionOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "reactionOptions", required: false }] }], retry: [{ type: i0.Output, args: ["retry"] }], reply: [{ type: i0.Output, args: ["reply"] }], react: [{ type: i0.Output, args: ["react"] }], quoted: [{ type: i0.Output, args: ["quoted"] }] }); })();
|
|
476
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(KptChatMessage, { className: "KptChatMessage", filePath: "lib/chat-message.component.ts", lineNumber: 67 }); })();
|
|
477
|
+
|
|
478
|
+
function KptChatTyping_Conditional_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
479
|
+
i0.ɵɵdomElementStart(0, "span", 3);
|
|
480
|
+
i0.ɵɵtext(1);
|
|
481
|
+
i0.ɵɵdomElementEnd();
|
|
482
|
+
} if (rf & 2) {
|
|
483
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
484
|
+
i0.ɵɵadvance();
|
|
485
|
+
i0.ɵɵtextInterpolate(ctx_r0.text());
|
|
486
|
+
} }
|
|
487
|
+
function KptChatTyping_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
488
|
+
i0.ɵɵdomElementStart(0, "div", 0)(1, "span", 1);
|
|
489
|
+
i0.ɵɵdomElement(2, "span", 2)(3, "span", 2)(4, "span", 2);
|
|
490
|
+
i0.ɵɵdomElementEnd();
|
|
491
|
+
i0.ɵɵconditionalCreate(5, KptChatTyping_Conditional_0_Conditional_5_Template, 2, 1, "span", 3);
|
|
492
|
+
i0.ɵɵdomElementEnd();
|
|
493
|
+
} if (rf & 2) {
|
|
494
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
495
|
+
i0.ɵɵadvance(5);
|
|
496
|
+
i0.ɵɵconditional(ctx_r0.text() ? 5 : -1);
|
|
497
|
+
} }
|
|
498
|
+
/**
|
|
499
|
+
* Wskaźnik pisania — trzy kropki i informacja, kto pisze.
|
|
500
|
+
*
|
|
501
|
+
* Pusta lista autorów nie renderuje niczego, więc można go trzymać w szablonie na stałe
|
|
502
|
+
* i sterować wyłącznie danymi.
|
|
503
|
+
*
|
|
504
|
+
* Element jest `role="status"` z `aria-live="polite"`: czytnik ogłasza wejście i zniknięcie
|
|
505
|
+
* wskaźnika, ale nie przerywa czytania wiadomości. Sama animacja kropek nic nie mówi —
|
|
506
|
+
* informację niesie etykieta.
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* <kpt-chat-typing [authors]="typing()" />
|
|
510
|
+
*/
|
|
511
|
+
class KptChatTyping {
|
|
512
|
+
constructor() {
|
|
513
|
+
/** Osoby piszące w tej chwili. Pusta lista chowa wskaźnik. */
|
|
514
|
+
this.authors = input([], /* @ts-ignore */
|
|
515
|
+
...(ngDevMode ? [{ debugName: "authors" }] : /* istanbul ignore next */ []));
|
|
516
|
+
/** Własna etykieta zamiast tej ze słownika. */
|
|
517
|
+
this.label = input('', /* @ts-ignore */
|
|
518
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
519
|
+
this.i18n = inject(KptI18n);
|
|
520
|
+
this.visible = computed(() => this.authors().length > 0 || !!this.label(), /* @ts-ignore */
|
|
521
|
+
...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
522
|
+
/**
|
|
523
|
+
* Jedna osoba jest wymieniona z imienia, przy większej liczbie liczy się głowy —
|
|
524
|
+
* lista nazwisk rozjeżdża wiersz i i tak nikt jej nie czyta.
|
|
525
|
+
*/
|
|
526
|
+
this.text = computed(() => {
|
|
527
|
+
const custom = this.label();
|
|
528
|
+
if (custom)
|
|
529
|
+
return custom;
|
|
530
|
+
const authors = this.authors();
|
|
531
|
+
if (authors.length === 0)
|
|
532
|
+
return '';
|
|
533
|
+
if (authors.length === 1)
|
|
534
|
+
return this.i18n.t('chat.typing', { name: authors[0].name });
|
|
535
|
+
return this.i18n.t('chat.typingMany', { count: authors.length });
|
|
536
|
+
}, /* @ts-ignore */
|
|
537
|
+
...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
538
|
+
}
|
|
539
|
+
static { this.ɵfac = function KptChatTyping_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || KptChatTyping)(); }; }
|
|
540
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: KptChatTyping, selectors: [["kpt-chat-typing"]], hostAttrs: ["role", "status", "aria-live", "polite", 1, "kpt-chat-typing-host"], inputs: { authors: [1, "authors"], label: [1, "label"] }, decls: 1, vars: 1, consts: [[1, "kpt-chat-typing"], ["aria-hidden", "true", 1, "kpt-chat-typing__bubble"], [1, "kpt-chat-typing__dot"], [1, "kpt-chat-typing__label"]], template: function KptChatTyping_Template(rf, ctx) { if (rf & 1) {
|
|
541
|
+
i0.ɵɵconditionalCreate(0, KptChatTyping_Conditional_0_Template, 6, 1, "div", 0);
|
|
542
|
+
} if (rf & 2) {
|
|
543
|
+
i0.ɵɵconditional(ctx.visible() ? 0 : -1);
|
|
544
|
+
} }, styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-typing-host{display:block}.kpt-chat-typing{display:flex;align-items:center;gap:var(--%NS%kpt-space-2, .5rem);padding-inline-start:calc(2rem + var(--%NS%kpt-space-2, .5rem))}.kpt-chat-typing__bubble{display:inline-flex;align-items:center;gap:.1875rem;padding:var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-3, .75rem);border-radius:var(--%NS%kpt-radius-lg, .75rem);border-end-start-radius:var(--%NS%kpt-radius-sm, .25rem);background:var(--%NS%kpt-color-surface-variant)}.kpt-chat-typing__dot{width:.375rem;height:.375rem;border-radius:var(--%NS%kpt-radius-full, 9999px);background:var(--%NS%kpt-color-text-muted);animation:kpt-chat-typing-bounce 1.2s infinite ease-in-out}.kpt-chat-typing__dot:nth-child(2){animation-delay:.15s}.kpt-chat-typing__dot:nth-child(3){animation-delay:.3s}.kpt-chat-typing__label{color:var(--%NS%kpt-color-text-muted);font-size:var(--%NS%kpt-font-size-xs, .75rem)}@keyframes kpt-chat-typing-bounce{0%,60%,to{transform:translateY(0);opacity:.5}30%{transform:translateY(-.1875rem);opacity:1}}@keyframes kpt-chat-typing-pulse{0%,to{opacity:.35}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.kpt-chat-typing__dot{animation-name:kpt-chat-typing-pulse;animation-duration:1.8s}}}\n"], encapsulation: 2 }); }
|
|
545
|
+
}
|
|
546
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(KptChatTyping, [{
|
|
547
|
+
type: Component,
|
|
548
|
+
args: [{ selector: 'kpt-chat-typing', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
|
|
549
|
+
class: 'kpt-chat-typing-host',
|
|
550
|
+
role: 'status',
|
|
551
|
+
'aria-live': 'polite',
|
|
552
|
+
}, template: "@if (visible()) {\n <div class=\"kpt-chat-typing\">\n <span class=\"kpt-chat-typing__bubble\" aria-hidden=\"true\">\n <span class=\"kpt-chat-typing__dot\"></span>\n <span class=\"kpt-chat-typing__dot\"></span>\n <span class=\"kpt-chat-typing__dot\"></span>\n </span>\n @if (text()) {\n <span class=\"kpt-chat-typing__label\">{{ text() }}</span>\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-typing-host{display:block}.kpt-chat-typing{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding-inline-start:calc(2rem + var(--kpt-space-2, .5rem))}.kpt-chat-typing__bubble{display:inline-flex;align-items:center;gap:.1875rem;padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border-radius:var(--kpt-radius-lg, .75rem);border-end-start-radius:var(--kpt-radius-sm, .25rem);background:var(--kpt-color-surface-variant)}.kpt-chat-typing__dot{width:.375rem;height:.375rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-text-muted);animation:kpt-chat-typing-bounce 1.2s infinite ease-in-out}.kpt-chat-typing__dot:nth-child(2){animation-delay:.15s}.kpt-chat-typing__dot:nth-child(3){animation-delay:.3s}.kpt-chat-typing__label{color:var(--kpt-color-text-muted);font-size:var(--kpt-font-size-xs, .75rem)}@keyframes kpt-chat-typing-bounce{0%,60%,to{transform:translateY(0);opacity:.5}30%{transform:translateY(-.1875rem);opacity:1}}@keyframes kpt-chat-typing-pulse{0%,to{opacity:.35}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.kpt-chat-typing__dot{animation-name:kpt-chat-typing-pulse;animation-duration:1.8s}}}\n"] }]
|
|
553
|
+
}], null, { authors: [{ type: i0.Input, args: [{ isSignal: true, alias: "authors", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] }); })();
|
|
554
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(KptChatTyping, { className: "KptChatTyping", filePath: "lib/chat-typing.component.ts", lineNumber: 30 }); })();
|
|
555
|
+
|
|
556
|
+
const _c0$2 = ["viewport"];
|
|
557
|
+
const _c1$1 = ["day"];
|
|
558
|
+
const _c2$1 = a0 => ({ count: a0 });
|
|
559
|
+
const _c3$1 = (a0, a1) => ({ $implicit: a0, row: a1 });
|
|
560
|
+
const _forTrack0$1 = ($index, $item) => $item.key;
|
|
561
|
+
function KptChat_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
562
|
+
i0.ɵɵelementStart(0, "span", 10);
|
|
563
|
+
i0.ɵɵtext(1);
|
|
564
|
+
i0.ɵɵelementEnd();
|
|
565
|
+
} if (rf & 2) {
|
|
566
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
567
|
+
i0.ɵɵadvance();
|
|
568
|
+
i0.ɵɵtextInterpolate(ctx_r1.i18n.t("chat.pending", i0.ɵɵpureFunction1(1, _c2$1, ctx_r1.pending())));
|
|
569
|
+
} }
|
|
570
|
+
function KptChat_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
571
|
+
i0.ɵɵelementStart(0, "p", 2);
|
|
572
|
+
i0.ɵɵelement(1, "kpt-icon", 9);
|
|
573
|
+
i0.ɵɵelementStart(2, "span");
|
|
574
|
+
i0.ɵɵtext(3);
|
|
575
|
+
i0.ɵɵelementEnd();
|
|
576
|
+
i0.ɵɵconditionalCreate(4, KptChat_Conditional_0_Conditional_4_Template, 2, 3, "span", 10);
|
|
577
|
+
i0.ɵɵelementEnd();
|
|
578
|
+
} if (rf & 2) {
|
|
579
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
580
|
+
i0.ɵɵadvance(3);
|
|
581
|
+
i0.ɵɵtextInterpolate(ctx_r1.i18n.t("chat.offline"));
|
|
582
|
+
i0.ɵɵadvance();
|
|
583
|
+
i0.ɵɵconditional(ctx_r1.pending() ? 4 : -1);
|
|
584
|
+
} }
|
|
585
|
+
function KptChat_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
586
|
+
i0.ɵɵelementStart(0, "p", 5);
|
|
587
|
+
i0.ɵɵtext(1);
|
|
588
|
+
i0.ɵɵelementEnd();
|
|
589
|
+
} if (rf & 2) {
|
|
590
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
591
|
+
i0.ɵɵadvance();
|
|
592
|
+
i0.ɵɵtextInterpolate(ctx_r1.emptyLabel() || ctx_r1.i18n.t("chat.empty"));
|
|
593
|
+
} }
|
|
594
|
+
function KptChat_For_6_Case_0_Template(rf, ctx) { if (rf & 1) {
|
|
595
|
+
i0.ɵɵelementStart(0, "p", 11);
|
|
596
|
+
i0.ɵɵtext(1);
|
|
597
|
+
i0.ɵɵelementEnd();
|
|
598
|
+
} if (rf & 2) {
|
|
599
|
+
const row_r4 = i0.ɵɵnextContext().$implicit;
|
|
600
|
+
i0.ɵɵattribute("aria-label", row_r4.text);
|
|
601
|
+
i0.ɵɵadvance();
|
|
602
|
+
i0.ɵɵtextInterpolate(row_r4.text);
|
|
603
|
+
} }
|
|
604
|
+
function KptChat_For_6_Case_1_Template(rf, ctx) { if (rf & 1) {
|
|
605
|
+
i0.ɵɵelementStart(0, "p", 12)(1, "span");
|
|
606
|
+
i0.ɵɵtext(2);
|
|
607
|
+
i0.ɵɵelementEnd()();
|
|
608
|
+
} if (rf & 2) {
|
|
609
|
+
const row_r4 = i0.ɵɵnextContext().$implicit;
|
|
610
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
611
|
+
i0.ɵɵattribute("aria-label", ctx_r1.i18n.t("chat.newMessages", i0.ɵɵpureFunction1(2, _c2$1, row_r4.count)));
|
|
612
|
+
i0.ɵɵadvance(2);
|
|
613
|
+
i0.ɵɵtextInterpolate(ctx_r1.i18n.t("chat.unread"));
|
|
614
|
+
} }
|
|
615
|
+
function KptChat_For_6_Case_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
616
|
+
i0.ɵɵelementContainer(0, 15);
|
|
617
|
+
} if (rf & 2) {
|
|
618
|
+
const row_r4 = i0.ɵɵnextContext(2).$implicit;
|
|
619
|
+
i0.ɵɵproperty("ngTemplateOutlet", ctx)("ngTemplateOutletContext", i0.ɵɵpureFunction2(2, _c3$1, row_r4.message, row_r4));
|
|
620
|
+
} }
|
|
621
|
+
function KptChat_For_6_Case_2_Template(rf, ctx) { if (rf & 1) {
|
|
622
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
623
|
+
i0.ɵɵelementStart(0, "kpt-chat-message", 14);
|
|
624
|
+
i0.ɵɵlistener("retry", function KptChat_For_6_Case_2_Template_kpt_chat_message_retry_0_listener() { i0.ɵɵrestoreView(_r5); const row_r4 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.retry.emit(row_r4.message)); })("reply", function KptChat_For_6_Case_2_Template_kpt_chat_message_reply_0_listener() { i0.ɵɵrestoreView(_r5); const row_r4 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.reply.emit(row_r4.message)); })("react", function KptChat_For_6_Case_2_Template_kpt_chat_message_react_0_listener($event) { i0.ɵɵrestoreView(_r5); const row_r4 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.react.emit({ message: row_r4.message, emoji: $event })); })("quoted", function KptChat_For_6_Case_2_Template_kpt_chat_message_quoted_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.quoted.emit($event)); });
|
|
625
|
+
i0.ɵɵconditionalCreate(1, KptChat_For_6_Case_2_Conditional_1_Template, 1, 5, "ng-container", 15);
|
|
626
|
+
i0.ɵɵelementEnd();
|
|
627
|
+
} if (rf & 2) {
|
|
628
|
+
let tmp_22_0;
|
|
629
|
+
const row_r4 = i0.ɵɵnextContext().$implicit;
|
|
630
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
631
|
+
i0.ɵɵproperty("message", row_r4.message)("text", ctx_r1.messageTpl() ? "" : null)("align", row_r4.own ? "end" : "start")("position", row_r4.position)("showAuthor", row_r4.showAuthor)("showAvatar", row_r4.showAvatar)("showMeta", row_r4.showMeta)("actions", ctx_r1.actions())("reactionOptions", ctx_r1.reactionOptions());
|
|
632
|
+
i0.ɵɵadvance();
|
|
633
|
+
i0.ɵɵconditional((tmp_22_0 = ctx_r1.messageTpl()) ? 1 : -1, tmp_22_0);
|
|
634
|
+
} }
|
|
635
|
+
function KptChat_For_6_Template(rf, ctx) { if (rf & 1) {
|
|
636
|
+
i0.ɵɵconditionalCreate(0, KptChat_For_6_Case_0_Template, 2, 2, "p", 11)(1, KptChat_For_6_Case_1_Template, 3, 4, "p", 12)(2, KptChat_For_6_Case_2_Template, 2, 10, "kpt-chat-message", 13);
|
|
637
|
+
} if (rf & 2) {
|
|
638
|
+
let tmp_12_0;
|
|
639
|
+
const row_r4 = ctx.$implicit;
|
|
640
|
+
i0.ɵɵconditional((tmp_12_0 = row_r4.kind) === "date" ? 0 : tmp_12_0 === "unread" ? 1 : tmp_12_0 === "message" ? 2 : -1);
|
|
641
|
+
} }
|
|
642
|
+
function KptChat_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
643
|
+
i0.ɵɵelement(0, "kpt-chat-typing", 6);
|
|
644
|
+
} if (rf & 2) {
|
|
645
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
646
|
+
i0.ɵɵproperty("authors", ctx_r1.typing());
|
|
647
|
+
} }
|
|
648
|
+
function KptChat_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
649
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
650
|
+
i0.ɵɵelementStart(0, "button", 16);
|
|
651
|
+
i0.ɵɵlistener("click", function KptChat_Conditional_11_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.jumpToLatest()); });
|
|
652
|
+
i0.ɵɵelement(1, "kpt-icon", 17);
|
|
653
|
+
i0.ɵɵtext(2);
|
|
654
|
+
i0.ɵɵelementEnd();
|
|
655
|
+
} if (rf & 2) {
|
|
656
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
657
|
+
i0.ɵɵadvance(2);
|
|
658
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.i18n.t("chat.newMessages", i0.ɵɵpureFunction1(1, _c2$1, ctx_r1.newCount())), " ");
|
|
659
|
+
} }
|
|
660
|
+
/** Odległość od dołu (px), przy której listę uznajemy jeszcze za przypiętą. */
|
|
661
|
+
const PIN_THRESHOLD = 48;
|
|
662
|
+
/**
|
|
663
|
+
* Wiersze, które nie mogą znaleźć się pod pływającą pigułką dnia: separatory i komunikaty
|
|
664
|
+
* systemowe, czyli wszystko wyśrodkowane, co czyta się jak jej bliźniak. Bąble są poza listą —
|
|
665
|
+
* pigułka nad wypowiedzią to normalny obrazek czatu.
|
|
666
|
+
*/
|
|
667
|
+
const BLOCKING_ROWS = '.kpt-chat__date, .kpt-chat__unread, .kpt-chat-message__system';
|
|
668
|
+
/**
|
|
669
|
+
* Lista rozmowy — grupuje wiadomości, wstawia separatory dni i dzielnik nieprzeczytanych,
|
|
670
|
+
* trzyma widok przy dole i pokazuje pasek offline z liczbą wiadomości czekających na wysłanie.
|
|
671
|
+
*
|
|
672
|
+
* Sama logika wierszy mieszka w `@konce-pt/chat` (`buildChatRows`), więc port Reacta liczy ją
|
|
673
|
+
* tak samo. Komponent nie ma nic wspólnego z transportem: wiadomości dostaje, a `(retry)`
|
|
674
|
+
* i `(loadMore)` tylko zgłasza — ponowieniem wysyłki i dociąganiem historii zajmuje się aplikacja.
|
|
675
|
+
*
|
|
676
|
+
* Treść bąbla można podmienić własnym `<ng-template>`; kontekst dostaje wiadomość jako
|
|
677
|
+
* `$implicit` i cały wiersz jako `row`.
|
|
678
|
+
*
|
|
679
|
+
* Kompozytor (`kpt-chat-composer`) jest osobnym komponentem i stoi obok listy — dzięki temu
|
|
680
|
+
* czat bez pola wpisywania (podgląd, archiwum) nie wozi go ze sobą.
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
* <kpt-chat [messages]="messages()" currentUser="me" [typing]="typing()" (retry)="resend($event)" />
|
|
684
|
+
*/
|
|
685
|
+
class KptChat {
|
|
686
|
+
constructor() {
|
|
687
|
+
/** Wiadomości w kolejności chronologicznej — komponent ich nie sortuje. */
|
|
688
|
+
this.messages = input([], /* @ts-ignore */
|
|
689
|
+
...(ngDevMode ? [{ debugName: "messages" }] : /* istanbul ignore next */ []));
|
|
690
|
+
/** `id` nadawcy uznawanego za „mnie": jego wiadomości idą na prawo i mają status. */
|
|
691
|
+
this.currentUser = input('', /* @ts-ignore */
|
|
692
|
+
...(ngDevMode ? [{ debugName: "currentUser" }] : /* istanbul ignore next */ []));
|
|
693
|
+
/** Przerwa łamiąca grupę wiadomości jednego nadawcy. */
|
|
694
|
+
this.groupGapMs = input(KPT_CHAT_GROUP_GAP_MS, /* @ts-ignore */
|
|
695
|
+
...(ngDevMode ? [{ debugName: "groupGapMs" }] : /* istanbul ignore next */ []));
|
|
696
|
+
/** `id` pierwszej nieprzeczytanej wiadomości — nad nią stanie dzielnik. */
|
|
697
|
+
this.unreadFrom = input(null, /* @ts-ignore */
|
|
698
|
+
...(ngDevMode ? [{ debugName: "unreadFrom" }] : /* istanbul ignore next */ []));
|
|
699
|
+
/** Brak połączenia: pasek u góry listy z liczbą wiadomości czekających na wysłanie. */
|
|
700
|
+
this.offline = input(false, { ...(ngDevMode ? { debugName: "offline" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
701
|
+
/** Osoby piszące w tej chwili. */
|
|
702
|
+
this.typing = input([], /* @ts-ignore */
|
|
703
|
+
...(ngDevMode ? [{ debugName: "typing" }] : /* istanbul ignore next */ []));
|
|
704
|
+
/** Dosuwanie widoku do najnowszej wiadomości, dopóki użytkownik nie odjedzie w górę. */
|
|
705
|
+
this.autoScroll = input(true, { ...(ngDevMode ? { debugName: "autoScroll" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
706
|
+
/** Akcje bąbla pod kursorem: odpowiedz i zareaguj. */
|
|
707
|
+
this.actions = input(false, { ...(ngDevMode ? { debugName: "actions" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
708
|
+
/** Zestaw wybieraka reakcji, przekazywany bąblom. Domyślnie pięć wbudowanych. */
|
|
709
|
+
this.reactionOptions = input(KPT_CHAT_REACTIONS, /* @ts-ignore */
|
|
710
|
+
...(ngDevMode ? [{ debugName: "reactionOptions" }] : /* istanbul ignore next */ []));
|
|
711
|
+
/** Własny komunikat pustej rozmowy. */
|
|
712
|
+
this.emptyLabel = input('', /* @ts-ignore */
|
|
713
|
+
...(ngDevMode ? [{ debugName: "emptyLabel" }] : /* istanbul ignore next */ []));
|
|
714
|
+
this.retry = output();
|
|
715
|
+
this.reply = output();
|
|
716
|
+
/** Kliknięcie w reakcję w wybieraku: wiadomość i wybrane emoji. */
|
|
717
|
+
this.react = output();
|
|
718
|
+
this.quoted = output();
|
|
719
|
+
/** Przewinięcie na sam szczyt — moment na dociągnięcie starszych wiadomości. */
|
|
720
|
+
this.loadMore = output();
|
|
721
|
+
this.i18n = inject(KptI18n);
|
|
722
|
+
this.messageTpl = contentChild(TemplateRef, /* @ts-ignore */
|
|
723
|
+
...(ngDevMode ? [{ debugName: "messageTpl" }] : /* istanbul ignore next */ []));
|
|
724
|
+
this.viewport = viewChild('viewport', /* @ts-ignore */
|
|
725
|
+
...(ngDevMode ? [{ debugName: "viewport" }] : /* istanbul ignore next */ []));
|
|
726
|
+
this.day = viewChild('day', /* @ts-ignore */
|
|
727
|
+
...(ngDevMode ? [{ debugName: "day" }] : /* istanbul ignore next */ []));
|
|
728
|
+
this.destroyRef = inject(DestroyRef);
|
|
729
|
+
/** Czy widok stoi przy dole listy. Odjazd w górę wyłącza dosuwanie. */
|
|
730
|
+
this.pinned = signal(true, /* @ts-ignore */
|
|
731
|
+
...(ngDevMode ? [{ debugName: "pinned" }] : /* istanbul ignore next */ []));
|
|
732
|
+
/** Ile wiadomości przyszło, odkąd użytkownik odjechał w górę. */
|
|
733
|
+
this.newCount = signal(0, /* @ts-ignore */
|
|
734
|
+
...(ngDevMode ? [{ debugName: "newCount" }] : /* istanbul ignore next */ []));
|
|
735
|
+
/** Tekst pływającej pigułki dnia — zostaje po zgaszeniu, żeby jej pas nie zmieniał wysokości. */
|
|
736
|
+
this.dayLabel = signal('', /* @ts-ignore */
|
|
737
|
+
...(ngDevMode ? [{ debugName: "dayLabel" }] : /* istanbul ignore next */ []));
|
|
738
|
+
/** Czy pigułka dnia jest widoczna. */
|
|
739
|
+
this.dayVisible = signal(false, /* @ts-ignore */
|
|
740
|
+
...(ngDevMode ? [{ debugName: "dayVisible" }] : /* istanbul ignore next */ []));
|
|
741
|
+
this.lastCount = 0;
|
|
742
|
+
this.wasAtTop = false;
|
|
743
|
+
this.rows = computed(() => buildChatRows(this.messages(), {
|
|
744
|
+
currentUserId: this.currentUser(),
|
|
745
|
+
gapMs: this.groupGapMs(),
|
|
746
|
+
unreadFrom: this.unreadFrom(),
|
|
747
|
+
}), /* @ts-ignore */
|
|
748
|
+
...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
749
|
+
this.viewRows = computed(() => this.rows().map((row) => (row.kind === 'date' ? { ...row, text: this.dateText(row.label) } : row)), /* @ts-ignore */
|
|
750
|
+
...(ngDevMode ? [{ debugName: "viewRows" }] : /* istanbul ignore next */ []));
|
|
751
|
+
this.pending = computed(() => pendingCount(this.messages()), /* @ts-ignore */
|
|
752
|
+
...(ngDevMode ? [{ debugName: "pending" }] : /* istanbul ignore next */ []));
|
|
753
|
+
afterRenderEffect(() => {
|
|
754
|
+
// Zależność: przerysowanie po każdej zmianie listy.
|
|
755
|
+
this.viewRows();
|
|
756
|
+
const element = this.viewport()?.nativeElement;
|
|
757
|
+
if (!element)
|
|
758
|
+
return;
|
|
759
|
+
untracked(() => {
|
|
760
|
+
const count = this.messages().length;
|
|
761
|
+
const grew = count > this.lastCount;
|
|
762
|
+
const first = this.lastCount === 0;
|
|
763
|
+
this.lastCount = count;
|
|
764
|
+
if (!grew)
|
|
765
|
+
return;
|
|
766
|
+
// Pierwsze wejście zawsze ląduje na dole — rozmowę czyta się od końca.
|
|
767
|
+
if (first || (this.autoScroll() && this.pinned())) {
|
|
768
|
+
this.scrollToBottom(first ? 'auto' : undefined);
|
|
769
|
+
}
|
|
770
|
+
else {
|
|
771
|
+
this.newCount.update((value) => value + 1);
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
untracked(() => this.syncDay());
|
|
775
|
+
});
|
|
776
|
+
// Zmiana szerokości zawija tekst w wierszach i przesuwa je spod pigułki — bez tego pigułka
|
|
777
|
+
// zostałaby zgaszona (albo zapalona) na podstawie układu sprzed zmiany rozmiaru.
|
|
778
|
+
afterNextRender(() => {
|
|
779
|
+
const element = this.viewport()?.nativeElement;
|
|
780
|
+
if (!element || !globalThis.ResizeObserver)
|
|
781
|
+
return;
|
|
782
|
+
const observer = new ResizeObserver(() => this.syncDay());
|
|
783
|
+
observer.observe(element);
|
|
784
|
+
this.destroyRef.onDestroy(() => observer.disconnect());
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
/** Przewija do najnowszej wiadomości i kasuje licznik nowych. */
|
|
788
|
+
jumpToLatest() {
|
|
789
|
+
this.pinned.set(true);
|
|
790
|
+
this.newCount.set(0);
|
|
791
|
+
this.scrollToBottom();
|
|
792
|
+
}
|
|
793
|
+
onScroll(element) {
|
|
794
|
+
const distance = element.scrollHeight - element.scrollTop - element.clientHeight;
|
|
795
|
+
const atBottom = distance < PIN_THRESHOLD;
|
|
796
|
+
this.pinned.set(atBottom);
|
|
797
|
+
if (atBottom)
|
|
798
|
+
this.newCount.set(0);
|
|
799
|
+
// `loadMore` tylko na wejściu w strefę szczytu — przy każdym zdarzeniu scroll
|
|
800
|
+
// aplikacja dostawałaby dziesiątki żądań na jedno przewinięcie.
|
|
801
|
+
const atTop = element.scrollTop < PIN_THRESHOLD;
|
|
802
|
+
if (atTop && !this.wasAtTop)
|
|
803
|
+
this.loadMore.emit();
|
|
804
|
+
this.wasAtTop = atTop;
|
|
805
|
+
this.syncDay();
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Ustawia tekst pływającej pigułki dnia — co ma na niej być, liczy `chatDayIndicator`
|
|
809
|
+
* z `@konce-pt/chat`, tutaj zostaje czytanie prostokątów i przepisanie etykiety.
|
|
810
|
+
*
|
|
811
|
+
* Wszystkie pomiary idą przed zapisem sygnału, więc przeglądarka przelicza układ raz
|
|
812
|
+
* na klatkę zamiast przy każdym wierszu.
|
|
813
|
+
*/
|
|
814
|
+
syncDay() {
|
|
815
|
+
const element = this.viewport()?.nativeElement;
|
|
816
|
+
const pill = this.day()?.nativeElement;
|
|
817
|
+
if (!element || !pill)
|
|
818
|
+
return;
|
|
819
|
+
const separators = Array.from(element.querySelectorAll('.kpt-chat__date'));
|
|
820
|
+
const blockers = Array.from(element.querySelectorAll(BLOCKING_ROWS));
|
|
821
|
+
const box = (node) => {
|
|
822
|
+
const rect = node.getBoundingClientRect();
|
|
823
|
+
return { top: rect.top, bottom: rect.bottom };
|
|
824
|
+
};
|
|
825
|
+
const active = chatDayIndicator(separators.map(box), blockers.map(box), box(pill));
|
|
826
|
+
this.dayVisible.set(active >= 0);
|
|
827
|
+
if (active < 0)
|
|
828
|
+
return;
|
|
829
|
+
// Etykieta zostaje po zgaszeniu pigułki: pusta zmieniałaby jej wysokość, a skrypt mierzy
|
|
830
|
+
// ten pas także wtedy, gdy pigułki nie widać.
|
|
831
|
+
const label = separators[active]?.textContent?.trim() ?? '';
|
|
832
|
+
if (label !== this.dayLabel())
|
|
833
|
+
this.dayLabel.set(label);
|
|
834
|
+
}
|
|
835
|
+
scrollToBottom(behavior) {
|
|
836
|
+
const element = this.viewport()?.nativeElement;
|
|
837
|
+
if (!element)
|
|
838
|
+
return;
|
|
839
|
+
const reduced = globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;
|
|
840
|
+
element.scrollTo({ top: element.scrollHeight, behavior: behavior ?? (reduced ? 'auto' : 'smooth') });
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Etykieta separatora dnia. Rdzeń zwraca rodzaj, słownik daje „dziś"/„wczoraj",
|
|
844
|
+
* a nazwę dnia i pełną datę — `Intl`, żeby nie trzymać w słowniku kalendarza.
|
|
845
|
+
*/
|
|
846
|
+
dateText(label) {
|
|
847
|
+
const locale = this.i18n.locale();
|
|
848
|
+
switch (label.kind) {
|
|
849
|
+
case 'today':
|
|
850
|
+
return this.i18n.t('chat.today');
|
|
851
|
+
case 'yesterday':
|
|
852
|
+
return this.i18n.t('chat.yesterday');
|
|
853
|
+
case 'weekday':
|
|
854
|
+
return new Intl.DateTimeFormat(locale, { weekday: 'long' }).format(label.date);
|
|
855
|
+
default:
|
|
856
|
+
return new Intl.DateTimeFormat(locale, { day: 'numeric', month: 'long', year: 'numeric' }).format(label.date);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
static { this.ɵfac = function KptChat_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || KptChat)(); }; }
|
|
860
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: KptChat, selectors: [["kpt-chat"]], contentQueries: function KptChat_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
|
|
861
|
+
i0.ɵɵcontentQuerySignal(dirIndex, ctx.messageTpl, TemplateRef, 5);
|
|
862
|
+
} if (rf & 2) {
|
|
863
|
+
i0.ɵɵqueryAdvance();
|
|
864
|
+
} }, viewQuery: function KptChat_Query(rf, ctx) { if (rf & 1) {
|
|
865
|
+
i0.ɵɵviewQuerySignal(ctx.viewport, _c0$2, 5)(ctx.day, _c1$1, 5);
|
|
866
|
+
} if (rf & 2) {
|
|
867
|
+
i0.ɵɵqueryAdvance(2);
|
|
868
|
+
} }, hostAttrs: [1, "kpt-chat-host"], inputs: { messages: [1, "messages"], currentUser: [1, "currentUser"], groupGapMs: [1, "groupGapMs"], unreadFrom: [1, "unreadFrom"], offline: [1, "offline"], typing: [1, "typing"], autoScroll: [1, "autoScroll"], actions: [1, "actions"], reactionOptions: [1, "reactionOptions"], emptyLabel: [1, "emptyLabel"] }, outputs: { retry: "retry", reply: "reply", react: "react", quoted: "quoted", loadMore: "loadMore" }, decls: 12, vars: 6, consts: [["viewport", ""], ["day", ""], ["role", "status", 1, "kpt-chat__offline"], [1, "kpt-chat__body"], ["role", "log", "aria-live", "polite", "aria-relevant", "additions", 1, "kpt-chat__viewport", 3, "scroll"], [1, "kpt-chat__empty"], [3, "authors"], ["aria-hidden", "true", 1, "kpt-chat__day"], ["type", "button", 1, "kpt-chat__jump"], ["name", "alert-triangle", "aria-hidden", "true"], [1, "kpt-chat__offline-count"], ["role", "separator", 1, "kpt-chat__date"], ["role", "separator", 1, "kpt-chat__unread"], [3, "message", "text", "align", "position", "showAuthor", "showAvatar", "showMeta", "actions", "reactionOptions"], [3, "retry", "reply", "react", "quoted", "message", "text", "align", "position", "showAuthor", "showAvatar", "showMeta", "actions", "reactionOptions"], [3, "ngTemplateOutlet", "ngTemplateOutletContext"], ["type", "button", 1, "kpt-chat__jump", 3, "click"], ["name", "arrow-down", "aria-hidden", "true"]], template: function KptChat_Template(rf, ctx) { if (rf & 1) {
|
|
869
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
870
|
+
i0.ɵɵconditionalCreate(0, KptChat_Conditional_0_Template, 5, 2, "p", 2);
|
|
871
|
+
i0.ɵɵelementStart(1, "div", 3)(2, "div", 4, 0);
|
|
872
|
+
i0.ɵɵlistener("scroll", function KptChat_Template_div_scroll_2_listener() { i0.ɵɵrestoreView(_r1); const viewport_r3 = i0.ɵɵreference(3); return i0.ɵɵresetView(ctx.onScroll(viewport_r3)); });
|
|
873
|
+
i0.ɵɵconditionalCreate(4, KptChat_Conditional_4_Template, 2, 1, "p", 5);
|
|
874
|
+
i0.ɵɵrepeaterCreate(5, KptChat_For_6_Template, 3, 1, null, null, _forTrack0$1);
|
|
875
|
+
i0.ɵɵconditionalCreate(7, KptChat_Conditional_7_Template, 1, 1, "kpt-chat-typing", 6);
|
|
876
|
+
i0.ɵɵelementEnd();
|
|
877
|
+
i0.ɵɵelementStart(8, "p", 7, 1);
|
|
878
|
+
i0.ɵɵtext(10);
|
|
879
|
+
i0.ɵɵelementEnd();
|
|
880
|
+
i0.ɵɵconditionalCreate(11, KptChat_Conditional_11_Template, 3, 3, "button", 8);
|
|
881
|
+
i0.ɵɵelementEnd();
|
|
882
|
+
} if (rf & 2) {
|
|
883
|
+
i0.ɵɵconditional(ctx.offline() ? 0 : -1);
|
|
884
|
+
i0.ɵɵadvance(4);
|
|
885
|
+
i0.ɵɵconditional(!ctx.viewRows().length ? 4 : -1);
|
|
886
|
+
i0.ɵɵadvance();
|
|
887
|
+
i0.ɵɵrepeater(ctx.viewRows());
|
|
888
|
+
i0.ɵɵadvance(2);
|
|
889
|
+
i0.ɵɵconditional(ctx.typing().length ? 7 : -1);
|
|
890
|
+
i0.ɵɵadvance();
|
|
891
|
+
i0.ɵɵattribute("data-hidden", ctx.dayVisible() ? null : "");
|
|
892
|
+
i0.ɵɵadvance(2);
|
|
893
|
+
i0.ɵɵtextInterpolate(ctx.dayLabel());
|
|
894
|
+
i0.ɵɵadvance();
|
|
895
|
+
i0.ɵɵconditional(ctx.newCount() ? 11 : -1);
|
|
896
|
+
} }, dependencies: [NgTemplateOutlet, KptChatMessage, KptChatTyping, KptIcon], styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-host{--%NS%_gap: var(--%NS%kpt-space-1, .25rem);--%NS%_group-gap: var(--%NS%kpt-space-4, 1rem);display:flex;flex-direction:column;min-height:0;background:var(--%NS%kpt-color-surface);color:var(--%NS%kpt-color-text)}.kpt-chat__offline{display:flex;align-items:center;gap:var(--%NS%kpt-space-2, .5rem);margin:0;padding:var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-3, .75rem);border-block-end:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-warning-border);background:var(--%NS%kpt-color-warning-subtle);color:var(--%NS%kpt-color-text);font-size:var(--%NS%kpt-font-size-sm, .875rem)}.kpt-chat__offline-count{margin-inline-start:auto;color:var(--%NS%kpt-color-text-muted);font-size:var(--%NS%kpt-font-size-xs, .75rem)}.kpt-chat__body{position:relative;display:flex;flex:1 1 auto;min-height:0}.kpt-chat__viewport{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--%NS%_gap);min-height:0;padding:var(--%NS%kpt-space-4, 1rem);overflow-y:auto;overscroll-behavior:contain}.kpt-chat__viewport>.kpt-chat-message-host:has(.kpt-chat-message__bubble[data-position=first]),.kpt-chat__viewport>.kpt-chat-message-host:has(.kpt-chat-message__bubble[data-position=single]){margin-block-start:var(--%NS%_group-gap)}.kpt-chat__viewport>.kpt-chat-message-host:first-child{margin-block-start:0}.kpt-chat__empty{margin:auto;padding:var(--%NS%kpt-space-8, 2rem);color:var(--%NS%kpt-color-text-muted);font-size:var(--%NS%kpt-font-size-sm, .875rem);text-align:center}.kpt-chat__date,.kpt-chat__day{padding:.125rem var(--%NS%kpt-space-3, .75rem);border:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-border);border-radius:var(--%NS%kpt-radius-full, 9999px);background:var(--%NS%kpt-color-surface-raised);color:var(--%NS%kpt-color-text-muted);font-size:var(--%NS%kpt-font-size-xs, .75rem);box-shadow:var(--%NS%kpt-elevation-1)}.kpt-chat__date{align-self:center;margin:var(--%NS%kpt-space-4, 1rem) 0 var(--%NS%kpt-space-2, .5rem)}.kpt-chat__day{position:absolute;inset-block-start:var(--%NS%kpt-space-2, .5rem);inset-inline:0 var(--%NS%kpt-space-3, .75rem);z-index:var(--%NS%kpt-z-raised, 1);width:fit-content;margin:0 auto;pointer-events:none}.kpt-chat__day:before{content:\"\\200b\"}.kpt-chat__day[data-hidden]{visibility:hidden}.kpt-chat__unread{display:flex;align-items:center;gap:var(--%NS%kpt-space-3, .75rem);margin:var(--%NS%kpt-space-4, 1rem) 0 var(--%NS%kpt-space-2, .5rem);color:var(--%NS%kpt-color-primary);font-size:var(--%NS%kpt-font-size-xs, .75rem)}.kpt-chat__unread:before,.kpt-chat__unread:after{content:\"\";flex:1 1 auto;block-size:var(--%NS%kpt-border-width-thin, 1px);background:var(--%NS%kpt-color-primary-border)}.kpt-chat__jump{position:absolute;inset-block-end:var(--%NS%kpt-space-3, .75rem);inset-inline:0;display:inline-flex;align-items:center;gap:var(--%NS%kpt-space-1, .25rem);width:fit-content;margin-inline:auto;padding:var(--%NS%kpt-space-1, .25rem) var(--%NS%kpt-space-3, .75rem);border:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-primary-border);border-radius:var(--%NS%kpt-radius-full, 9999px);background:var(--%NS%kpt-color-surface-raised);color:var(--%NS%kpt-color-primary);font:inherit;font-size:var(--%NS%kpt-font-size-xs, .75rem);cursor:pointer;box-shadow:var(--%NS%kpt-elevation-2)}.kpt-chat__jump:hover{background:var(--%NS%kpt-color-surface-hover)}.kpt-chat__jump:focus-visible{outline:2px solid var(--%NS%kpt-color-focus-ring);outline-offset:2px}}\n"], encapsulation: 2 }); }
|
|
897
|
+
}
|
|
898
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(KptChat, [{
|
|
899
|
+
type: Component,
|
|
900
|
+
args: [{ selector: 'kpt-chat', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgTemplateOutlet, KptChatMessage, KptChatTyping, KptIcon], host: { class: 'kpt-chat-host' }, template: "@if (offline()) {\n <p class=\"kpt-chat__offline\" role=\"status\">\n <kpt-icon name=\"alert-triangle\" aria-hidden=\"true\" />\n <span>{{ i18n.t('chat.offline') }}</span>\n @if (pending()) {\n <span class=\"kpt-chat__offline-count\">{{ i18n.t('chat.pending', { count: pending() }) }}</span>\n }\n </p>\n}\n\n<div class=\"kpt-chat__body\">\n <div\n #viewport\n class=\"kpt-chat__viewport\"\n role=\"log\"\n aria-live=\"polite\"\n aria-relevant=\"additions\"\n (scroll)=\"onScroll(viewport)\"\n >\n @if (!viewRows().length) {\n <p class=\"kpt-chat__empty\">{{ emptyLabel() || i18n.t('chat.empty') }}</p>\n }\n\n @for (row of viewRows(); track row.key) {\n @switch (row.kind) {\n @case ('date') {\n <p class=\"kpt-chat__date\" role=\"separator\" [attr.aria-label]=\"row.text\">{{ row.text }}</p>\n }\n @case ('unread') {\n <p class=\"kpt-chat__unread\" role=\"separator\" [attr.aria-label]=\"i18n.t('chat.newMessages', { count: row.count })\">\n <span>{{ i18n.t('chat.unread') }}</span>\n </p>\n }\n @case ('message') {\n <kpt-chat-message\n [message]=\"row.message\"\n [text]=\"messageTpl() ? '' : null\"\n [align]=\"row.own ? 'end' : 'start'\"\n [position]=\"row.position\"\n [showAuthor]=\"row.showAuthor\"\n [showAvatar]=\"row.showAvatar\"\n [showMeta]=\"row.showMeta\"\n [actions]=\"actions()\"\n [reactionOptions]=\"reactionOptions()\"\n (retry)=\"retry.emit(row.message)\"\n (reply)=\"reply.emit(row.message)\"\n (react)=\"react.emit({ message: row.message, emoji: $event })\"\n (quoted)=\"quoted.emit($event)\"\n >\n @if (messageTpl(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" [ngTemplateOutletContext]=\"{ $implicit: row.message, row: row }\" />\n }\n </kpt-chat-message>\n }\n }\n }\n\n @if (typing().length) {\n <kpt-chat-typing [authors]=\"typing()\" />\n }\n </div>\n\n <!-- Pigu\u0142ka dnia wisi nad list\u0105, a nie w niej: w li\u015Bcie jad\u0105 separatory z `role=\"separator\"`,\n wi\u0119c dla czytnika ekranu jest tylko ich wizualnym echem \u2014 st\u0105d `aria-hidden`. W DOM stoi\n zawsze, bo skrypt musi umie\u0107 zmierzy\u0107 jej pas tak\u017Ce wtedy, gdy jest zgaszona. -->\n <p #day class=\"kpt-chat__day\" aria-hidden=\"true\" [attr.data-hidden]=\"dayVisible() ? null : ''\">{{ dayLabel() }}</p>\n\n @if (newCount()) {\n <button type=\"button\" class=\"kpt-chat__jump\" (click)=\"jumpToLatest()\">\n <kpt-icon name=\"arrow-down\" aria-hidden=\"true\" />\n {{ i18n.t('chat.newMessages', { count: newCount() }) }}\n </button>\n }\n</div>\n", styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-host{--_gap: var(--kpt-space-1, .25rem);--_group-gap: var(--kpt-space-4, 1rem);display:flex;flex-direction:column;min-height:0;background:var(--kpt-color-surface);color:var(--kpt-color-text)}.kpt-chat__offline{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);margin:0;padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border-block-end:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-warning-border);background:var(--kpt-color-warning-subtle);color:var(--kpt-color-text);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-chat__offline-count{margin-inline-start:auto;color:var(--kpt-color-text-muted);font-size:var(--kpt-font-size-xs, .75rem)}.kpt-chat__body{position:relative;display:flex;flex:1 1 auto;min-height:0}.kpt-chat__viewport{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--_gap);min-height:0;padding:var(--kpt-space-4, 1rem);overflow-y:auto;overscroll-behavior:contain}.kpt-chat__viewport>.kpt-chat-message-host:has(.kpt-chat-message__bubble[data-position=first]),.kpt-chat__viewport>.kpt-chat-message-host:has(.kpt-chat-message__bubble[data-position=single]){margin-block-start:var(--_group-gap)}.kpt-chat__viewport>.kpt-chat-message-host:first-child{margin-block-start:0}.kpt-chat__empty{margin:auto;padding:var(--kpt-space-8, 2rem);color:var(--kpt-color-text-muted);font-size:var(--kpt-font-size-sm, .875rem);text-align:center}.kpt-chat__date,.kpt-chat__day{padding:.125rem var(--kpt-space-3, .75rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-raised);color:var(--kpt-color-text-muted);font-size:var(--kpt-font-size-xs, .75rem);box-shadow:var(--kpt-elevation-1)}.kpt-chat__date{align-self:center;margin:var(--kpt-space-4, 1rem) 0 var(--kpt-space-2, .5rem)}.kpt-chat__day{position:absolute;inset-block-start:var(--kpt-space-2, .5rem);inset-inline:0 var(--kpt-space-3, .75rem);z-index:var(--kpt-z-raised, 1);width:fit-content;margin:0 auto;pointer-events:none}.kpt-chat__day:before{content:\"\\200b\"}.kpt-chat__day[data-hidden]{visibility:hidden}.kpt-chat__unread{display:flex;align-items:center;gap:var(--kpt-space-3, .75rem);margin:var(--kpt-space-4, 1rem) 0 var(--kpt-space-2, .5rem);color:var(--kpt-color-primary);font-size:var(--kpt-font-size-xs, .75rem)}.kpt-chat__unread:before,.kpt-chat__unread:after{content:\"\";flex:1 1 auto;block-size:var(--kpt-border-width-thin, 1px);background:var(--kpt-color-primary-border)}.kpt-chat__jump{position:absolute;inset-block-end:var(--kpt-space-3, .75rem);inset-inline:0;display:inline-flex;align-items:center;gap:var(--kpt-space-1, .25rem);width:fit-content;margin-inline:auto;padding:var(--kpt-space-1, .25rem) var(--kpt-space-3, .75rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-primary-border);border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-raised);color:var(--kpt-color-primary);font:inherit;font-size:var(--kpt-font-size-xs, .75rem);cursor:pointer;box-shadow:var(--kpt-elevation-2)}.kpt-chat__jump:hover{background:var(--kpt-color-surface-hover)}.kpt-chat__jump:focus-visible{outline:2px solid var(--kpt-color-focus-ring);outline-offset:2px}}\n"] }]
|
|
901
|
+
}], () => [], { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], currentUser: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUser", required: false }] }], groupGapMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupGapMs", required: false }] }], unreadFrom: [{ type: i0.Input, args: [{ isSignal: true, alias: "unreadFrom", required: false }] }], offline: [{ type: i0.Input, args: [{ isSignal: true, alias: "offline", required: false }] }], typing: [{ type: i0.Input, args: [{ isSignal: true, alias: "typing", required: false }] }], autoScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoScroll", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], reactionOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "reactionOptions", required: false }] }], emptyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyLabel", required: false }] }], retry: [{ type: i0.Output, args: ["retry"] }], reply: [{ type: i0.Output, args: ["reply"] }], react: [{ type: i0.Output, args: ["react"] }], quoted: [{ type: i0.Output, args: ["quoted"] }], loadMore: [{ type: i0.Output, args: ["loadMore"] }], messageTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }], viewport: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], day: [{ type: i0.ViewChild, args: ['day', { isSignal: true }] }] }); })();
|
|
902
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(KptChat, { className: "KptChat", filePath: "lib/chat.component.ts", lineNumber: 80 }); })();
|
|
903
|
+
|
|
904
|
+
const _c0$1 = a0 => ({ author: a0 });
|
|
905
|
+
const _forTrack0 = ($index, $item) => $item.name + $item.size + $item.lastModified;
|
|
906
|
+
function KptChatComposer_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
907
|
+
const _r2 = i0.ɵɵgetCurrentView();
|
|
908
|
+
i0.ɵɵelementStart(0, "div", 2)(1, "span", 8)(2, "span", 9);
|
|
909
|
+
i0.ɵɵtext(3);
|
|
910
|
+
i0.ɵɵelementEnd();
|
|
911
|
+
i0.ɵɵelementStart(4, "span", 10);
|
|
912
|
+
i0.ɵɵtext(5);
|
|
913
|
+
i0.ɵɵelementEnd()();
|
|
914
|
+
i0.ɵɵelementStart(6, "kpt-icon-button", 11);
|
|
915
|
+
i0.ɵɵlistener("click", function KptChatComposer_Conditional_0_Template_kpt_icon_button_click_6_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.replyTo.set(null)); });
|
|
916
|
+
i0.ɵɵelement(7, "kpt-icon", 12);
|
|
917
|
+
i0.ɵɵelementEnd()();
|
|
918
|
+
} if (rf & 2) {
|
|
919
|
+
const quote_r4 = ctx;
|
|
920
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
921
|
+
i0.ɵɵadvance(3);
|
|
922
|
+
i0.ɵɵtextInterpolate(ctx_r2.i18n.t("chat.replyTo", i0.ɵɵpureFunction1(3, _c0$1, quote_r4.author)));
|
|
923
|
+
i0.ɵɵadvance(2);
|
|
924
|
+
i0.ɵɵtextInterpolate(quote_r4.excerpt);
|
|
925
|
+
i0.ɵɵadvance();
|
|
926
|
+
i0.ɵɵproperty("ariaLabel", ctx_r2.i18n.t("chat.cancelReply"));
|
|
927
|
+
} }
|
|
928
|
+
function KptChatComposer_Conditional_1_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
929
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
930
|
+
i0.ɵɵelementStart(0, "li", 13);
|
|
931
|
+
i0.ɵɵelement(1, "kpt-icon", 14);
|
|
932
|
+
i0.ɵɵelementStart(2, "span", 15);
|
|
933
|
+
i0.ɵɵtext(3);
|
|
934
|
+
i0.ɵɵelementEnd();
|
|
935
|
+
i0.ɵɵelementStart(4, "kpt-icon-button", 11);
|
|
936
|
+
i0.ɵɵlistener("click", function KptChatComposer_Conditional_1_For_2_Template_kpt_icon_button_click_4_listener() { const file_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.removeFile(file_r6)); });
|
|
937
|
+
i0.ɵɵelement(5, "kpt-icon", 12);
|
|
938
|
+
i0.ɵɵelementEnd()();
|
|
939
|
+
} if (rf & 2) {
|
|
940
|
+
const file_r6 = ctx.$implicit;
|
|
941
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
942
|
+
i0.ɵɵadvance(3);
|
|
943
|
+
i0.ɵɵtextInterpolate(file_r6.name);
|
|
944
|
+
i0.ɵɵadvance();
|
|
945
|
+
i0.ɵɵproperty("ariaLabel", ctx_r2.i18n.t("chat.removeAttachment"));
|
|
946
|
+
} }
|
|
947
|
+
function KptChatComposer_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
948
|
+
i0.ɵɵelementStart(0, "ul", 3);
|
|
949
|
+
i0.ɵɵrepeaterCreate(1, KptChatComposer_Conditional_1_For_2_Template, 6, 2, "li", 13, _forTrack0);
|
|
950
|
+
i0.ɵɵelementEnd();
|
|
951
|
+
} if (rf & 2) {
|
|
952
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
953
|
+
i0.ɵɵadvance();
|
|
954
|
+
i0.ɵɵrepeater(ctx_r2.files());
|
|
955
|
+
} }
|
|
956
|
+
function KptChatComposer_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
957
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
958
|
+
i0.ɵɵelementStart(0, "input", 16, 1);
|
|
959
|
+
i0.ɵɵlistener("change", function KptChatComposer_Conditional_3_Template_input_change_0_listener() { i0.ɵɵrestoreView(_r7); const picker_r8 = i0.ɵɵreference(1); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onFiles(picker_r8)); });
|
|
960
|
+
i0.ɵɵelementEnd();
|
|
961
|
+
i0.ɵɵelementStart(2, "kpt-icon-button", 17);
|
|
962
|
+
i0.ɵɵlistener("click", function KptChatComposer_Conditional_3_Template_kpt_icon_button_click_2_listener() { i0.ɵɵrestoreView(_r7); const picker_r8 = i0.ɵɵreference(1); return i0.ɵɵresetView(picker_r8.click()); });
|
|
963
|
+
i0.ɵɵelement(3, "kpt-icon", 18);
|
|
964
|
+
i0.ɵɵelementEnd();
|
|
965
|
+
} if (rf & 2) {
|
|
966
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
967
|
+
i0.ɵɵadvance(2);
|
|
968
|
+
i0.ɵɵproperty("disabled", ctx_r2.disabled())("ariaLabel", ctx_r2.i18n.t("chat.attach"));
|
|
969
|
+
} }
|
|
970
|
+
/**
|
|
971
|
+
* Pole pisania wiadomości — autorosnące, z załącznikami i paskiem cytatu.
|
|
972
|
+
*
|
|
973
|
+
* Nie jest kontrolką Signal Forms i celowo nią nie będzie: nie wchodzi do formularza, nie ma
|
|
974
|
+
* stanu `touched`/`invalid`, a jego wartość znika po wysłaniu. `model('')` opisuje to wiernie.
|
|
975
|
+
*
|
|
976
|
+
* `Enter` wysyła, `Shift+Enter` łamie linię (`[enterToSend]="false"` odwraca układ).
|
|
977
|
+
* Przy `[offline]` przycisk zmienia etykietę na kolejkowanie — wiadomość dalej da się napisać
|
|
978
|
+
* i oddać aplikacji, bo to ona decyduje, co zrobić z kolejką.
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* <kpt-chat-composer [(value)]="draft" allowAttachments (send)="onSend($event)" />
|
|
982
|
+
*/
|
|
983
|
+
class KptChatComposer {
|
|
984
|
+
constructor() {
|
|
985
|
+
this.value = model('', /* @ts-ignore */
|
|
986
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
987
|
+
/** Podpowiedź w pustym polu; bez niej etykieta ze słownika. */
|
|
988
|
+
this.placeholder = input('', /* @ts-ignore */
|
|
989
|
+
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
990
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
991
|
+
/** Brak połączenia — przycisk mówi o kolejkowaniu, nie o wysyłce. */
|
|
992
|
+
this.offline = input(false, { ...(ngDevMode ? { debugName: "offline" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
993
|
+
this.allowAttachments = input(false, { ...(ngDevMode ? { debugName: "allowAttachments" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
994
|
+
/** Ile wierszy pole może urosnąć, zanim zacznie się przewijać. */
|
|
995
|
+
this.maxRows = input(6, /* @ts-ignore */
|
|
996
|
+
...(ngDevMode ? [{ debugName: "maxRows" }] : /* istanbul ignore next */ []));
|
|
997
|
+
this.enterToSend = input(true, { ...(ngDevMode ? { debugName: "enterToSend" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
998
|
+
/** Wiadomość, na którą odpowiadamy. Po wysłaniu czyści się razem z treścią. */
|
|
999
|
+
this.replyTo = model(null, /* @ts-ignore */
|
|
1000
|
+
...(ngDevMode ? [{ debugName: "replyTo" }] : /* istanbul ignore next */ []));
|
|
1001
|
+
this.send = output();
|
|
1002
|
+
/** Pierwsze uderzenie w klawiaturę — sygnał „piszę" dla drugiej strony. */
|
|
1003
|
+
this.typing = output();
|
|
1004
|
+
this.i18n = inject(KptI18n);
|
|
1005
|
+
this.files = signal([], /* @ts-ignore */
|
|
1006
|
+
...(ngDevMode ? [{ debugName: "files" }] : /* istanbul ignore next */ []));
|
|
1007
|
+
this.canSend = computed(() => !this.disabled() && (this.value().trim().length > 0 || this.files().length > 0), /* @ts-ignore */
|
|
1008
|
+
...(ngDevMode ? [{ debugName: "canSend" }] : /* istanbul ignore next */ []));
|
|
1009
|
+
this.sendLabel = computed(() => this.offline() ? this.i18n.t('chat.queue') : this.i18n.t('chat.send'), /* @ts-ignore */
|
|
1010
|
+
...(ngDevMode ? [{ debugName: "sendLabel" }] : /* istanbul ignore next */ []));
|
|
1011
|
+
}
|
|
1012
|
+
onInput(element) {
|
|
1013
|
+
this.value.set(element.value);
|
|
1014
|
+
this.grow(element);
|
|
1015
|
+
this.typing.emit();
|
|
1016
|
+
}
|
|
1017
|
+
onKeydown(event, element) {
|
|
1018
|
+
if (event.key !== 'Enter')
|
|
1019
|
+
return;
|
|
1020
|
+
const wantsSend = this.enterToSend() ? !event.shiftKey : event.shiftKey;
|
|
1021
|
+
if (!wantsSend || event.isComposing)
|
|
1022
|
+
return;
|
|
1023
|
+
event.preventDefault();
|
|
1024
|
+
this.submit(element);
|
|
1025
|
+
}
|
|
1026
|
+
submit(element) {
|
|
1027
|
+
if (!this.canSend())
|
|
1028
|
+
return;
|
|
1029
|
+
this.send.emit({ text: this.value().trim(), files: this.files(), replyTo: this.replyTo() });
|
|
1030
|
+
this.value.set('');
|
|
1031
|
+
this.files.set([]);
|
|
1032
|
+
this.replyTo.set(null);
|
|
1033
|
+
if (element) {
|
|
1034
|
+
element.value = '';
|
|
1035
|
+
this.grow(element);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
onFiles(input) {
|
|
1039
|
+
const picked = Array.from(input.files ?? []);
|
|
1040
|
+
if (picked.length)
|
|
1041
|
+
this.files.update((current) => [...current, ...picked]);
|
|
1042
|
+
// Bez wyzerowania ten sam plik wybrany drugi raz nie wywoła `change`.
|
|
1043
|
+
input.value = '';
|
|
1044
|
+
}
|
|
1045
|
+
removeFile(file) {
|
|
1046
|
+
this.files.update((current) => current.filter((item) => item !== file));
|
|
1047
|
+
}
|
|
1048
|
+
/**
|
|
1049
|
+
* Wysokość liczona od treści. Zerowanie przed odczytem `scrollHeight` jest konieczne:
|
|
1050
|
+
* bez niego pole potrafi tylko rosnąć, bo `scrollHeight` nigdy nie zejdzie poniżej
|
|
1051
|
+
* ustawionej wcześniej wysokości. Górny limit trzyma CSS (`--_max-rows`).
|
|
1052
|
+
*/
|
|
1053
|
+
grow(element) {
|
|
1054
|
+
element.style.height = 'auto';
|
|
1055
|
+
// `scrollHeight` liczy treść z paddingiem, ale BEZ ramki, a pole jest `border-box`.
|
|
1056
|
+
// Sama wysokość ze `scrollHeight` zostawia je o grubość ramki za niskie, więc puste
|
|
1057
|
+
// pole na jeden wiersz dostaje pasek przewijania i nigdy się go nie pozbywa.
|
|
1058
|
+
const borders = element.offsetHeight - element.clientHeight;
|
|
1059
|
+
element.style.height = element.scrollHeight + borders + 'px';
|
|
1060
|
+
}
|
|
1061
|
+
static { this.ɵfac = function KptChatComposer_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || KptChatComposer)(); }; }
|
|
1062
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: KptChatComposer, selectors: [["kpt-chat-composer"]], hostAttrs: [1, "kpt-chat-composer-host"], inputs: { value: [1, "value"], placeholder: [1, "placeholder"], disabled: [1, "disabled"], offline: [1, "offline"], allowAttachments: [1, "allowAttachments"], maxRows: [1, "maxRows"], enterToSend: [1, "enterToSend"], replyTo: [1, "replyTo"] }, outputs: { value: "valueChange", replyTo: "replyToChange", send: "send", typing: "typing" }, decls: 8, vars: 12, consts: [["field", ""], ["picker", ""], [1, "kpt-chat-composer__reply"], [1, "kpt-chat-composer__files"], [1, "kpt-chat-composer"], ["rows", "1", 1, "kpt-chat-composer__field", 3, "input", "keydown", "value", "disabled"], ["variant", "filled", 3, "click", "disabled", "ariaLabel"], [3, "name"], [1, "kpt-chat-composer__reply-body"], [1, "kpt-chat-composer__reply-author"], [1, "kpt-chat-composer__reply-text"], ["size", "sm", 3, "click", "ariaLabel"], ["name", "x"], [1, "kpt-chat-composer__file"], ["name", "paperclip", "aria-hidden", "true"], [1, "kpt-chat-composer__file-name"], ["type", "file", "multiple", "", 1, "kpt-chat-composer__picker", 3, "change"], ["size", "sm", 3, "click", "disabled", "ariaLabel"], ["name", "paperclip"]], template: function KptChatComposer_Template(rf, ctx) { if (rf & 1) {
|
|
1063
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
1064
|
+
i0.ɵɵconditionalCreate(0, KptChatComposer_Conditional_0_Template, 8, 5, "div", 2);
|
|
1065
|
+
i0.ɵɵconditionalCreate(1, KptChatComposer_Conditional_1_Template, 3, 0, "ul", 3);
|
|
1066
|
+
i0.ɵɵelementStart(2, "div", 4);
|
|
1067
|
+
i0.ɵɵconditionalCreate(3, KptChatComposer_Conditional_3_Template, 4, 2);
|
|
1068
|
+
i0.ɵɵelementStart(4, "textarea", 5, 0);
|
|
1069
|
+
i0.ɵɵlistener("input", function KptChatComposer_Template_textarea_input_4_listener() { i0.ɵɵrestoreView(_r1); const field_r9 = i0.ɵɵreference(5); return i0.ɵɵresetView(ctx.onInput(field_r9)); })("keydown", function KptChatComposer_Template_textarea_keydown_4_listener($event) { i0.ɵɵrestoreView(_r1); const field_r9 = i0.ɵɵreference(5); return i0.ɵɵresetView(ctx.onKeydown($event, field_r9)); });
|
|
1070
|
+
i0.ɵɵelementEnd();
|
|
1071
|
+
i0.ɵɵelementStart(6, "kpt-icon-button", 6);
|
|
1072
|
+
i0.ɵɵlistener("click", function KptChatComposer_Template_kpt_icon_button_click_6_listener() { i0.ɵɵrestoreView(_r1); const field_r9 = i0.ɵɵreference(5); return i0.ɵɵresetView(ctx.submit(field_r9)); });
|
|
1073
|
+
i0.ɵɵelement(7, "kpt-icon", 7);
|
|
1074
|
+
i0.ɵɵelementEnd()();
|
|
1075
|
+
} if (rf & 2) {
|
|
1076
|
+
let tmp_1_0;
|
|
1077
|
+
i0.ɵɵconditional((tmp_1_0 = ctx.replyTo()) ? 0 : -1, tmp_1_0);
|
|
1078
|
+
i0.ɵɵadvance();
|
|
1079
|
+
i0.ɵɵconditional(ctx.files().length ? 1 : -1);
|
|
1080
|
+
i0.ɵɵadvance(2);
|
|
1081
|
+
i0.ɵɵconditional(ctx.allowAttachments() ? 3 : -1);
|
|
1082
|
+
i0.ɵɵadvance();
|
|
1083
|
+
i0.ɵɵstyleProp("--%NS%_max-rows", ctx.maxRows());
|
|
1084
|
+
i0.ɵɵproperty("value", ctx.value())("disabled", ctx.disabled());
|
|
1085
|
+
i0.ɵɵattribute("placeholder", ctx.placeholder() || ctx.i18n.t("chat.placeholder"))("aria-label", ctx.placeholder() || ctx.i18n.t("chat.placeholder"));
|
|
1086
|
+
i0.ɵɵadvance(2);
|
|
1087
|
+
i0.ɵɵproperty("disabled", !ctx.canSend())("ariaLabel", ctx.sendLabel());
|
|
1088
|
+
i0.ɵɵadvance();
|
|
1089
|
+
i0.ɵɵproperty("name", ctx.offline() ? "clock" : "send");
|
|
1090
|
+
} }, dependencies: [KptIcon, KptIconButton], styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-composer-host{display:block;border-block-start:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-border);background:var(--%NS%kpt-color-surface)}.kpt-chat-composer{display:flex;align-items:flex-end;gap:var(--%NS%kpt-space-2, .5rem);padding:var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-3, .75rem)}.kpt-chat-composer__field{--%NS%_max-rows: 6;--%NS%_line: 1.5em;flex:1 1 auto;min-width:0;max-block-size:calc(var(--%NS%_max-rows) * var(--%NS%_line) + var(--%NS%kpt-space-2, .5rem));padding:var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-3, .75rem);border:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-border);border-radius:var(--%NS%kpt-radius-lg, .75rem);background:var(--%NS%kpt-color-surface-variant);color:var(--%NS%kpt-color-text);font:inherit;font-size:var(--%NS%kpt-font-size-sm, .875rem);line-height:1.5;resize:none;overflow-y:auto}.kpt-chat-composer__field::placeholder{color:var(--%NS%kpt-color-text-subtle)}.kpt-chat-composer__field:focus-visible{outline:2px solid var(--%NS%kpt-color-focus-ring);outline-offset:-1px}.kpt-chat-composer__field:disabled{opacity:.6;cursor:not-allowed}.kpt-chat-composer__picker{display:none}.kpt-chat-composer__reply{display:flex;align-items:center;gap:var(--%NS%kpt-space-2, .5rem);padding:var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-3, .75rem);border-inline-start:2px solid var(--%NS%kpt-color-primary);background:var(--%NS%kpt-color-surface-variant)}.kpt-chat-composer__reply-body{display:flex;flex:1 1 auto;flex-direction:column;min-width:0;font-size:var(--%NS%kpt-font-size-xs, .75rem)}.kpt-chat-composer__reply-author{color:var(--%NS%kpt-color-primary);font-weight:var(--%NS%kpt-font-weight-semibold, 600)}.kpt-chat-composer__reply-text{color:var(--%NS%kpt-color-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kpt-chat-composer__files{display:flex;flex-wrap:wrap;gap:var(--%NS%kpt-space-2, .5rem);margin:0;padding:var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-3, .75rem) 0;list-style:none}.kpt-chat-composer__file{display:inline-flex;align-items:center;gap:.25rem;max-inline-size:14rem;padding-inline-start:var(--%NS%kpt-space-2, .5rem);border:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-border);border-radius:var(--%NS%kpt-radius-full, 9999px);background:var(--%NS%kpt-color-surface-variant);font-size:var(--%NS%kpt-font-size-xs, .75rem)}.kpt-chat-composer__file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}\n"], encapsulation: 2 }); }
|
|
1091
|
+
}
|
|
1092
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(KptChatComposer, [{
|
|
1093
|
+
type: Component,
|
|
1094
|
+
args: [{ selector: 'kpt-chat-composer', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [KptIcon, KptIconButton], host: { class: 'kpt-chat-composer-host' }, template: "@if (replyTo(); as quote) {\n <div class=\"kpt-chat-composer__reply\">\n <span class=\"kpt-chat-composer__reply-body\">\n <span class=\"kpt-chat-composer__reply-author\">{{ i18n.t('chat.replyTo', { author: quote.author }) }}</span>\n <span class=\"kpt-chat-composer__reply-text\">{{ quote.excerpt }}</span>\n </span>\n <kpt-icon-button size=\"sm\" [ariaLabel]=\"i18n.t('chat.cancelReply')\" (click)=\"replyTo.set(null)\">\n <kpt-icon name=\"x\" />\n </kpt-icon-button>\n </div>\n}\n\n@if (files().length) {\n <ul class=\"kpt-chat-composer__files\">\n @for (file of files(); track file.name + file.size + file.lastModified) {\n <li class=\"kpt-chat-composer__file\">\n <kpt-icon name=\"paperclip\" aria-hidden=\"true\" />\n <span class=\"kpt-chat-composer__file-name\">{{ file.name }}</span>\n <kpt-icon-button size=\"sm\" [ariaLabel]=\"i18n.t('chat.removeAttachment')\" (click)=\"removeFile(file)\">\n <kpt-icon name=\"x\" />\n </kpt-icon-button>\n </li>\n }\n </ul>\n}\n\n<div class=\"kpt-chat-composer\">\n @if (allowAttachments()) {\n <input #picker type=\"file\" class=\"kpt-chat-composer__picker\" multiple (change)=\"onFiles(picker)\" />\n <kpt-icon-button\n size=\"sm\"\n [disabled]=\"disabled()\"\n [ariaLabel]=\"i18n.t('chat.attach')\"\n (click)=\"picker.click()\"\n >\n <kpt-icon name=\"paperclip\" />\n </kpt-icon-button>\n }\n\n <textarea\n #field\n class=\"kpt-chat-composer__field\"\n rows=\"1\"\n [style.--_max-rows]=\"maxRows()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"placeholder() || i18n.t('chat.placeholder')\"\n [attr.aria-label]=\"placeholder() || i18n.t('chat.placeholder')\"\n (input)=\"onInput(field)\"\n (keydown)=\"onKeydown($event, field)\"\n ></textarea>\n\n <kpt-icon-button\n variant=\"filled\"\n [disabled]=\"!canSend()\"\n [ariaLabel]=\"sendLabel()\"\n (click)=\"submit(field)\"\n >\n <kpt-icon [name]=\"offline() ? 'clock' : 'send'\" />\n </kpt-icon-button>\n</div>\n", styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-composer-host{display:block;border-block-start:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);background:var(--kpt-color-surface)}.kpt-chat-composer{display:flex;align-items:flex-end;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem)}.kpt-chat-composer__field{--_max-rows: 6;--_line: 1.5em;flex:1 1 auto;min-width:0;max-block-size:calc(var(--_max-rows) * var(--_line) + var(--kpt-space-2, .5rem));padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-lg, .75rem);background:var(--kpt-color-surface-variant);color:var(--kpt-color-text);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);line-height:1.5;resize:none;overflow-y:auto}.kpt-chat-composer__field::placeholder{color:var(--kpt-color-text-subtle)}.kpt-chat-composer__field:focus-visible{outline:2px solid var(--kpt-color-focus-ring);outline-offset:-1px}.kpt-chat-composer__field:disabled{opacity:.6;cursor:not-allowed}.kpt-chat-composer__picker{display:none}.kpt-chat-composer__reply{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border-inline-start:2px solid var(--kpt-color-primary);background:var(--kpt-color-surface-variant)}.kpt-chat-composer__reply-body{display:flex;flex:1 1 auto;flex-direction:column;min-width:0;font-size:var(--kpt-font-size-xs, .75rem)}.kpt-chat-composer__reply-author{color:var(--kpt-color-primary);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-chat-composer__reply-text{color:var(--kpt-color-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kpt-chat-composer__files{display:flex;flex-wrap:wrap;gap:var(--kpt-space-2, .5rem);margin:0;padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem) 0;list-style:none}.kpt-chat-composer__file{display:inline-flex;align-items:center;gap:.25rem;max-inline-size:14rem;padding-inline-start:var(--kpt-space-2, .5rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-variant);font-size:var(--kpt-font-size-xs, .75rem)}.kpt-chat-composer__file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}\n"] }]
|
|
1095
|
+
}], null, { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], offline: [{ type: i0.Input, args: [{ isSignal: true, alias: "offline", required: false }] }], allowAttachments: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowAttachments", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }], enterToSend: [{ type: i0.Input, args: [{ isSignal: true, alias: "enterToSend", required: false }] }], replyTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "replyTo", required: false }] }, { type: i0.Output, args: ["replyToChange"] }], send: [{ type: i0.Output, args: ["send"] }], typing: [{ type: i0.Output, args: ["typing"] }] }); })();
|
|
1096
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(KptChatComposer, { className: "KptChatComposer", filePath: "lib/chat-composer.component.ts", lineNumber: 34 }); })();
|
|
1097
|
+
|
|
1098
|
+
const _c0 = ["panel"];
|
|
1099
|
+
const _c1 = ["trigger"];
|
|
1100
|
+
const _c2 = ["*"];
|
|
1101
|
+
const _c3 = a0 => ({ count: a0 });
|
|
1102
|
+
function KptChatDock_ng_template_11_Template(rf, ctx) { if (rf & 1) {
|
|
1103
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
1104
|
+
i0.ɵɵelementStart(0, "kpt-fab", 12);
|
|
1105
|
+
i0.ɵɵlistener("click", function KptChatDock_ng_template_11_Template_kpt_fab_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggle()); });
|
|
1106
|
+
i0.ɵɵelement(1, "kpt-icon", 13);
|
|
1107
|
+
i0.ɵɵelementEnd();
|
|
1108
|
+
} if (rf & 2) {
|
|
1109
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
1110
|
+
i0.ɵɵproperty("ariaLabel", ctx_r1.triggerLabel());
|
|
1111
|
+
i0.ɵɵadvance();
|
|
1112
|
+
i0.ɵɵproperty("name", ctx_r1.open() ? "x" : ctx_r1.icon());
|
|
1113
|
+
} }
|
|
1114
|
+
function KptChatDock_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
1115
|
+
i0.ɵɵelementStart(0, "kpt-badge", 10);
|
|
1116
|
+
i0.ɵɵelementContainer(1, 11);
|
|
1117
|
+
i0.ɵɵelementEnd();
|
|
1118
|
+
} if (rf & 2) {
|
|
1119
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
1120
|
+
const fab_r3 = i0.ɵɵreference(12);
|
|
1121
|
+
i0.ɵɵproperty("value", ctx_r1.unread());
|
|
1122
|
+
i0.ɵɵattribute("aria-label", ctx_r1.i18n.t("chat.unreadBadge", i0.ɵɵpureFunction1(3, _c3, ctx_r1.unread())));
|
|
1123
|
+
i0.ɵɵadvance();
|
|
1124
|
+
i0.ɵɵproperty("ngTemplateOutlet", fab_r3);
|
|
1125
|
+
} }
|
|
1126
|
+
function KptChatDock_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
1127
|
+
i0.ɵɵelementContainer(0, 11);
|
|
1128
|
+
} if (rf & 2) {
|
|
1129
|
+
i0.ɵɵnextContext();
|
|
1130
|
+
const fab_r3 = i0.ɵɵreference(12);
|
|
1131
|
+
i0.ɵɵproperty("ngTemplateOutlet", fab_r3);
|
|
1132
|
+
} }
|
|
1133
|
+
/**
|
|
1134
|
+
* Pływający czat w rogu ekranu — FAB z licznikiem nieprzeczytanych i panel z rozmową.
|
|
1135
|
+
*
|
|
1136
|
+
* Zawartość panelu jest rzutowana, więc dock nie wie nic o wiadomościach: wkłada się do niego
|
|
1137
|
+
* `kpt-chat` i `kpt-chat-composer` (albo cokolwiek innego). Sam FAB to `kpt-fab` — dock go
|
|
1138
|
+
* używa, nie zastępuje.
|
|
1139
|
+
*
|
|
1140
|
+
* Poniżej `--kpt-breakpoint-sm` panel wchodzi na pełny ekran: 22,5 cm szerokości na telefonie
|
|
1141
|
+
* to nie panel, tylko szpara.
|
|
1142
|
+
*
|
|
1143
|
+
* @example
|
|
1144
|
+
* <kpt-chat-dock [(open)]="chatOpen" [unread]="unread()" header="Wsparcie">
|
|
1145
|
+
* <kpt-chat [messages]="messages()" currentUser="me" />
|
|
1146
|
+
* <kpt-chat-composer (send)="onSend($event)" />
|
|
1147
|
+
* </kpt-chat-dock>
|
|
1148
|
+
*/
|
|
1149
|
+
class KptChatDock {
|
|
1150
|
+
constructor() {
|
|
1151
|
+
this.open = model(false, /* @ts-ignore */
|
|
1152
|
+
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
1153
|
+
this.position = input('bottom-end', /* @ts-ignore */
|
|
1154
|
+
...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
1155
|
+
/** Licznik na plakietce FAB-a. Zero chowa plakietkę. */
|
|
1156
|
+
this.unread = input(0, /* @ts-ignore */
|
|
1157
|
+
...(ngDevMode ? [{ debugName: "unread" }] : /* istanbul ignore next */ []));
|
|
1158
|
+
this.header = input('', /* @ts-ignore */
|
|
1159
|
+
...(ngDevMode ? [{ debugName: "header" }] : /* istanbul ignore next */ []));
|
|
1160
|
+
/** Ikona zamkniętego FAB-a; otwarty zawsze pokazuje krzyżyk. */
|
|
1161
|
+
this.icon = input('message-circle', /* @ts-ignore */
|
|
1162
|
+
...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
1163
|
+
/** Szerokość panelu na ekranach powyżej `--kpt-breakpoint-sm`. */
|
|
1164
|
+
this.width = input('22.5rem', /* @ts-ignore */
|
|
1165
|
+
...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
1166
|
+
/**
|
|
1167
|
+
* Odsunięcie od rogu ekranu (dowolna długość CSS), wspólne dla obu osi.
|
|
1168
|
+
* Domyślnie `--kpt-space-6`. Przydaje się, gdy w tym samym rogu stoi już inny widget —
|
|
1169
|
+
* `kpt-scroll-top` przykleja się dokładnie tam samo i bez tego oba się nakładają.
|
|
1170
|
+
*/
|
|
1171
|
+
this.offset = input('', /* @ts-ignore */
|
|
1172
|
+
...(ngDevMode ? [{ debugName: "offset" }] : /* istanbul ignore next */ []));
|
|
1173
|
+
this.i18n = inject(KptI18n);
|
|
1174
|
+
this.panel = viewChild('panel', /* @ts-ignore */
|
|
1175
|
+
...(ngDevMode ? [{ debugName: "panel" }] : /* istanbul ignore next */ []));
|
|
1176
|
+
this.trigger = viewChild('trigger', /* @ts-ignore */
|
|
1177
|
+
...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
|
|
1178
|
+
this.triggerLabel = computed(() => this.open() ? this.i18n.t('chat.close') : this.i18n.t('chat.open'), /* @ts-ignore */
|
|
1179
|
+
...(ngDevMode ? [{ debugName: "triggerLabel" }] : /* istanbul ignore next */ []));
|
|
1180
|
+
effect(() => {
|
|
1181
|
+
const open = this.open();
|
|
1182
|
+
untracked(() => (open ? this.focusPanel() : undefined));
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
toggle() {
|
|
1186
|
+
this.open.update((value) => !value);
|
|
1187
|
+
}
|
|
1188
|
+
close() {
|
|
1189
|
+
if (!this.open())
|
|
1190
|
+
return;
|
|
1191
|
+
this.open.set(false);
|
|
1192
|
+
// Fokus wraca na FAB — po zamknięciu panelu nie może zostać na elemencie,
|
|
1193
|
+
// który przed chwilą zniknął z drzewa dostępności.
|
|
1194
|
+
this.trigger()?.nativeElement.querySelector('button')?.focus();
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Fokus ląduje na polu pisania, jeśli w panelu jest — po to się czat otwiera.
|
|
1198
|
+
* Bez pola bierze pierwszy element interaktywny, a w ostateczności sam panel.
|
|
1199
|
+
*/
|
|
1200
|
+
focusPanel() {
|
|
1201
|
+
const element = this.panel()?.nativeElement;
|
|
1202
|
+
if (!element)
|
|
1203
|
+
return;
|
|
1204
|
+
requestAnimationFrame(() => {
|
|
1205
|
+
const target = element.querySelector('textarea:not([disabled])') ??
|
|
1206
|
+
element.querySelector('input:not([disabled]), button:not([disabled])') ??
|
|
1207
|
+
element;
|
|
1208
|
+
target.focus();
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
static { this.ɵfac = function KptChatDock_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || KptChatDock)(); }; }
|
|
1212
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: KptChatDock, selectors: [["kpt-chat-dock"]], viewQuery: function KptChatDock_Query(rf, ctx) { if (rf & 1) {
|
|
1213
|
+
i0.ɵɵviewQuerySignal(ctx.panel, _c0, 5)(ctx.trigger, _c1, 5);
|
|
1214
|
+
} if (rf & 2) {
|
|
1215
|
+
i0.ɵɵqueryAdvance(2);
|
|
1216
|
+
} }, hostAttrs: [1, "kpt-chat-dock-host"], hostBindings: function KptChatDock_HostBindings(rf, ctx) { if (rf & 1) {
|
|
1217
|
+
i0.ɵɵlistener("keydown.escape", function KptChatDock_keydown_escape_HostBindingHandler() { return ctx.close(); });
|
|
1218
|
+
} }, inputs: { open: [1, "open"], position: [1, "position"], unread: [1, "unread"], header: [1, "header"], icon: [1, "icon"], width: [1, "width"], offset: [1, "offset"] }, outputs: { open: "openChange" }, ngContentSelectors: _c2, decls: 15, vars: 16, consts: [["panel", ""], ["trigger", ""], ["fab", ""], ["role", "dialog", "tabindex", "-1", 1, "kpt-chat-dock__panel"], [1, "kpt-chat-dock__header"], [1, "kpt-chat-dock__title"], ["size", "sm", 3, "click", "ariaLabel"], ["name", "x"], [1, "kpt-chat-dock__content"], [1, "kpt-chat-dock__trigger"], ["variant", "danger", "size", "sm", "overlay", "", 3, "value"], [3, "ngTemplateOutlet"], [3, "click", "ariaLabel"], [3, "name"]], template: function KptChatDock_Template(rf, ctx) { if (rf & 1) {
|
|
1219
|
+
i0.ɵɵprojectionDef();
|
|
1220
|
+
i0.ɵɵelementStart(0, "div", 3, 0)(2, "header", 4)(3, "span", 5);
|
|
1221
|
+
i0.ɵɵtext(4);
|
|
1222
|
+
i0.ɵɵelementEnd();
|
|
1223
|
+
i0.ɵɵelementStart(5, "kpt-icon-button", 6);
|
|
1224
|
+
i0.ɵɵlistener("click", function KptChatDock_Template_kpt_icon_button_click_5_listener() { return ctx.close(); });
|
|
1225
|
+
i0.ɵɵelement(6, "kpt-icon", 7);
|
|
1226
|
+
i0.ɵɵelementEnd()();
|
|
1227
|
+
i0.ɵɵelementStart(7, "div", 8);
|
|
1228
|
+
i0.ɵɵprojection(8);
|
|
1229
|
+
i0.ɵɵelementEnd()();
|
|
1230
|
+
i0.ɵɵelementStart(9, "span", 9, 1);
|
|
1231
|
+
i0.ɵɵtemplate(11, KptChatDock_ng_template_11_Template, 2, 2, "ng-template", null, 2, i0.ɵɵtemplateRefExtractor);
|
|
1232
|
+
i0.ɵɵconditionalCreate(13, KptChatDock_Conditional_13_Template, 2, 5, "kpt-badge", 10)(14, KptChatDock_Conditional_14_Template, 1, 1, "ng-container", 11);
|
|
1233
|
+
i0.ɵɵelementEnd();
|
|
1234
|
+
} if (rf & 2) {
|
|
1235
|
+
i0.ɵɵstyleProp("--%NS%_width", ctx.width())("--%NS%_offset", ctx.offset() || null);
|
|
1236
|
+
i0.ɵɵclassProp("is-open", ctx.open());
|
|
1237
|
+
i0.ɵɵattribute("data-position", ctx.position())("aria-label", ctx.header() || ctx.i18n.t("chat.open"))("aria-hidden", ctx.open() ? null : "true")("inert", ctx.open() ? null : "");
|
|
1238
|
+
i0.ɵɵadvance(4);
|
|
1239
|
+
i0.ɵɵtextInterpolate(ctx.header());
|
|
1240
|
+
i0.ɵɵadvance();
|
|
1241
|
+
i0.ɵɵproperty("ariaLabel", ctx.i18n.t("chat.close"));
|
|
1242
|
+
i0.ɵɵadvance(4);
|
|
1243
|
+
i0.ɵɵstyleProp("--%NS%_offset", ctx.offset() || null);
|
|
1244
|
+
i0.ɵɵattribute("data-position", ctx.position());
|
|
1245
|
+
i0.ɵɵadvance(4);
|
|
1246
|
+
i0.ɵɵconditional(ctx.unread() > 0 ? 13 : 14);
|
|
1247
|
+
} }, dependencies: [NgTemplateOutlet, KptBadge, KptFab, KptIcon, KptIconButton], styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-dock-host{display:contents}.kpt-chat-dock__trigger{--%NS%_offset: var(--%NS%kpt-space-6, 1.5rem);position:fixed;inset-block-end:var(--%NS%_offset);z-index:var(--%NS%kpt-z-overlay, 1000)}.kpt-chat-dock__panel{--%NS%_width: 22.5rem;--%NS%_offset: var(--%NS%kpt-space-6, 1.5rem);--%NS%_vis-delay: var(--%NS%kpt-motion-duration-base, .2s);position:fixed;inset-block-end:calc(var(--%NS%_offset) + 4.5rem);z-index:var(--%NS%kpt-z-overlay, 1000);display:flex;flex-direction:column;inline-size:var(--%NS%_width);max-inline-size:calc(100vw - 2 * var(--%NS%_offset));block-size:min(32rem,100dvh - 9rem);border:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-border);border-radius:var(--%NS%kpt-radius-lg, .75rem);background:var(--%NS%kpt-color-surface);color:var(--%NS%kpt-color-text);overflow:hidden;box-shadow:var(--%NS%kpt-elevation-3);visibility:hidden;opacity:0;transform:translateY(var(--%NS%kpt-space-4, 1rem)) scale(.98);transform-origin:bottom center;transition:opacity var(--%NS%kpt-motion-duration-base, .2s) var(--%NS%kpt-motion-easing-standard, ease),transform var(--%NS%kpt-motion-duration-base, .2s) var(--%NS%kpt-motion-easing-emphasized, ease),visibility 0s linear var(--%NS%_vis-delay)}.kpt-chat-dock__panel.is-open{visibility:visible;opacity:1;transform:none;transition-delay:0s}.kpt-chat-dock__header{display:flex;flex:0 0 auto;align-items:center;gap:var(--%NS%kpt-space-2, .5rem);padding:var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-2, .5rem) var(--%NS%kpt-space-4, 1rem);border-block-end:var(--%NS%kpt-border-width-thin, 1px) solid var(--%NS%kpt-color-border)}.kpt-chat-dock__title{flex:1 1 auto;font-weight:var(--%NS%kpt-font-weight-semibold, 600)}.kpt-chat-dock__content{display:flex;flex:1 1 auto;flex-direction:column;min-height:0}.kpt-chat-dock__trigger,.kpt-chat-dock__panel{inset-inline-end:var(--%NS%_offset)}.kpt-chat-dock__trigger[data-position=bottom-start],.kpt-chat-dock__panel[data-position=bottom-start]{inset-inline:var(--%NS%_offset) auto}:root:has(.kpt-chat-dock__trigger[data-position=bottom-end]) .kpt-scroll-top{right:calc(var(--%NS%kpt-space-6, 1.5rem) + 4.25rem)}@media(width<640px){.kpt-chat-dock__panel{inset:0;inline-size:auto;max-inline-size:none;block-size:auto;border:0;border-radius:0;transform:translateY(var(--%NS%kpt-space-6, 1.5rem))}}@media(prefers-reduced-motion:reduce){.kpt-chat-dock__panel{transition:opacity var(--%NS%kpt-motion-duration-fast, .12s) linear,visibility 0s linear var(--%NS%_vis-delay);transform:none}}}\n"], encapsulation: 2 }); }
|
|
1248
|
+
}
|
|
1249
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(KptChatDock, [{
|
|
1250
|
+
type: Component,
|
|
1251
|
+
args: [{ selector: 'kpt-chat-dock', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgTemplateOutlet, KptBadge, KptFab, KptIcon, KptIconButton], host: {
|
|
1252
|
+
class: 'kpt-chat-dock-host',
|
|
1253
|
+
'(keydown.escape)': 'close()',
|
|
1254
|
+
}, template: "<div\n #panel\n class=\"kpt-chat-dock__panel\"\n role=\"dialog\"\n tabindex=\"-1\"\n [class.is-open]=\"open()\"\n [attr.data-position]=\"position()\"\n [style.--_width]=\"width()\"\n [style.--_offset]=\"offset() || null\"\n [attr.aria-label]=\"header() || i18n.t('chat.open')\"\n [attr.aria-hidden]=\"open() ? null : 'true'\"\n [attr.inert]=\"open() ? null : ''\"\n>\n <header class=\"kpt-chat-dock__header\">\n <span class=\"kpt-chat-dock__title\">{{ header() }}</span>\n <kpt-icon-button size=\"sm\" [ariaLabel]=\"i18n.t('chat.close')\" (click)=\"close()\">\n <kpt-icon name=\"x\" />\n </kpt-icon-button>\n </header>\n\n <div class=\"kpt-chat-dock__content\">\n <ng-content />\n </div>\n</div>\n\n<span\n #trigger\n class=\"kpt-chat-dock__trigger\"\n [attr.data-position]=\"position()\"\n [style.--_offset]=\"offset() || null\"\n>\n <!-- Plakietka wchodzi dopiero, gdy jest co policzy\u0107: `kpt-badge` z pust\u0105 warto\u015Bci\u0105\n rysuje kropk\u0119, a ta na FAB-ie czatu k\u0142amie o nieprzeczytanych wiadomo\u015Bciach. -->\n <ng-template #fab>\n <kpt-fab [ariaLabel]=\"triggerLabel()\" (click)=\"toggle()\">\n <kpt-icon [name]=\"open() ? 'x' : icon()\" />\n </kpt-fab>\n </ng-template>\n\n @if (unread() > 0) {\n <kpt-badge\n [value]=\"unread()\"\n variant=\"danger\"\n size=\"sm\"\n overlay\n [attr.aria-label]=\"i18n.t('chat.unreadBadge', { count: unread() })\"\n >\n <ng-container [ngTemplateOutlet]=\"fab\" />\n </kpt-badge>\n } @else {\n <ng-container [ngTemplateOutlet]=\"fab\" />\n }\n</span>\n", styles: ["@charset \"UTF-8\";@layer kpt.components{.kpt-chat-dock-host{display:contents}.kpt-chat-dock__trigger{--_offset: var(--kpt-space-6, 1.5rem);position:fixed;inset-block-end:var(--_offset);z-index:var(--kpt-z-overlay, 1000)}.kpt-chat-dock__panel{--_width: 22.5rem;--_offset: var(--kpt-space-6, 1.5rem);--_vis-delay: var(--kpt-motion-duration-base, .2s);position:fixed;inset-block-end:calc(var(--_offset) + 4.5rem);z-index:var(--kpt-z-overlay, 1000);display:flex;flex-direction:column;inline-size:var(--_width);max-inline-size:calc(100vw - 2 * var(--_offset));block-size:min(32rem,100dvh - 9rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-lg, .75rem);background:var(--kpt-color-surface);color:var(--kpt-color-text);overflow:hidden;box-shadow:var(--kpt-elevation-3);visibility:hidden;opacity:0;transform:translateY(var(--kpt-space-4, 1rem)) scale(.98);transform-origin:bottom center;transition:opacity var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard, ease),transform var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-emphasized, ease),visibility 0s linear var(--_vis-delay)}.kpt-chat-dock__panel.is-open{visibility:visible;opacity:1;transform:none;transition-delay:0s}.kpt-chat-dock__header{display:flex;flex:0 0 auto;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-2, .5rem) var(--kpt-space-2, .5rem) var(--kpt-space-4, 1rem);border-block-end:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-chat-dock__title{flex:1 1 auto;font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-chat-dock__content{display:flex;flex:1 1 auto;flex-direction:column;min-height:0}.kpt-chat-dock__trigger,.kpt-chat-dock__panel{inset-inline-end:var(--_offset)}.kpt-chat-dock__trigger[data-position=bottom-start],.kpt-chat-dock__panel[data-position=bottom-start]{inset-inline:var(--_offset) auto}:root:has(.kpt-chat-dock__trigger[data-position=bottom-end]) .kpt-scroll-top{right:calc(var(--kpt-space-6, 1.5rem) + 4.25rem)}@media(width<640px){.kpt-chat-dock__panel{inset:0;inline-size:auto;max-inline-size:none;block-size:auto;border:0;border-radius:0;transform:translateY(var(--kpt-space-6, 1.5rem))}}@media(prefers-reduced-motion:reduce){.kpt-chat-dock__panel{transition:opacity var(--kpt-motion-duration-fast, .12s) linear,visibility 0s linear var(--_vis-delay);transform:none}}}\n"] }]
|
|
1255
|
+
}], () => [], { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], unread: [{ type: i0.Input, args: [{ isSignal: true, alias: "unread", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }], trigger: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }] }); })();
|
|
1256
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(KptChatDock, { className: "KptChatDock", filePath: "lib/chat-dock.component.ts", lineNumber: 35 }); })();
|
|
1257
|
+
|
|
1258
|
+
/*
|
|
1259
|
+
* Public API — @konce-pt/angular/chat
|
|
1260
|
+
* Rodzina komponentów rozmowy (sygnały, zoneless). Rdzeń obliczeń — grupowanie wiadomości,
|
|
1261
|
+
* etykiety dni i arytmetyka statusów — mieszka w `@konce-pt/chat`, paczce bez frameworka,
|
|
1262
|
+
* wspólnej z portem Reacta; tu tylko re-eksport, żeby publiczne API subpathu niosło komplet.
|
|
1263
|
+
*/
|
|
1264
|
+
|
|
1265
|
+
/**
|
|
1266
|
+
* Generated bundle index. Do not edit.
|
|
1267
|
+
*/
|
|
1268
|
+
|
|
1269
|
+
export { KptChat, KptChatComposer, KptChatDock, KptChatMessage, KptChatTyping };
|
|
1270
|
+
//# sourceMappingURL=konce-pt-angular-chat.mjs.map
|