@crestapps/ai-chat-ui 2.0.0-preview.215 → 2.0.0-preview.223
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/dist/ai-chat-widget.js +762 -964
- package/dist/ai-chat-widget.js.map +1 -1
- package/dist/ai-chat-widget.min.js +1 -1
- package/dist/ai-chat-widget.min.js.map +1 -1
- package/dist/ai-chat.css +0 -2
- package/dist/ai-chat.js +2380 -3698
- package/dist/ai-chat.js.map +1 -1
- package/dist/ai-chat.min.css +1 -1
- package/dist/ai-chat.min.js +78 -1
- package/dist/ai-chat.min.js.map +1 -1
- package/dist/chat-image-carousel.css +0 -2
- package/dist/chat-image-carousel.js +306 -482
- package/dist/chat-image-carousel.js.map +1 -1
- package/dist/chat-image-carousel.min.css +1 -1
- package/dist/chat-image-carousel.min.js +1 -1
- package/dist/chat-image-carousel.min.js.map +1 -1
- package/dist/chat-interaction-settings.js +221 -293
- package/dist/chat-interaction-settings.js.map +1 -1
- package/dist/chat-interaction-settings.min.js +1 -1
- package/dist/chat-interaction-settings.min.js.map +1 -1
- package/dist/chat-interaction.js +2330 -3557
- package/dist/chat-interaction.js.map +1 -1
- package/dist/chat-interaction.min.js +62 -1
- package/dist/chat-interaction.min.js.map +1 -1
- package/dist/chat-markers.js +193 -485
- package/dist/chat-markers.js.map +1 -1
- package/dist/chat-markers.min.js +2 -1
- package/dist/chat-markers.min.js.map +1 -1
- package/dist/chat-widget.css +0 -2
- package/dist/chat-widget.min.css +1 -1
- package/dist/document-drop-zone.css +0 -2
- package/dist/document-drop-zone.js +127 -153
- package/dist/document-drop-zone.js.map +1 -1
- package/dist/document-drop-zone.min.css +1 -1
- package/dist/document-drop-zone.min.js +1 -1
- package/dist/document-drop-zone.min.js.map +1 -1
- package/dist/realtime-audio.js +1639 -2504
- package/dist/realtime-audio.js.map +1 -1
- package/dist/realtime-audio.min.js +3 -1
- package/dist/realtime-audio.min.js.map +1 -1
- package/dist/technical-name-generator.js +58 -80
- package/dist/technical-name-generator.js.map +1 -1
- package/dist/technical-name-generator.min.js +1 -1
- package/dist/technical-name-generator.min.js.map +1 -1
- package/package.json +1 -5
- package/dist/ai-chat.css.map +0 -1
- package/dist/chat-image-carousel.css.map +0 -1
- package/dist/chat-widget.css.map +0 -1
- package/dist/document-drop-zone.css.map +0 -1
|
@@ -1,485 +1,309 @@
|
|
|
1
1
|
/*
|
|
2
|
-
** NOTE: This file is generated by
|
|
3
|
-
**
|
|
2
|
+
** NOTE: This file is generated by the assets build (npm run build) and should not be edited directly!
|
|
3
|
+
** Edit its sources under Assets/ and rebuild; see Assets.json for the files it is built from.
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
var activeIndex = Math.max(0, Math.min(items.length - 1, requestedIndex));
|
|
310
|
-
var dots = carousel.querySelector('.ai-image-carousel-dots');
|
|
311
|
-
while (dots.children.length > items.length) {
|
|
312
|
-
dots.lastElementChild.remove();
|
|
313
|
-
}
|
|
314
|
-
items.forEach(function (item, index) {
|
|
315
|
-
var offset = index - activeIndex;
|
|
316
|
-
var isActive = offset === 0;
|
|
317
|
-
var downloadLink = item.querySelector('a');
|
|
318
|
-
item.dataset.stackOffset = Math.max(-furthestVisibleOffset - 1, Math.min(furthestVisibleOffset + 1, offset));
|
|
319
|
-
item.classList.toggle('is-active', isActive);
|
|
320
|
-
item.setAttribute('aria-hidden', isActive ? 'false' : 'true');
|
|
321
|
-
|
|
322
|
-
// A card behind the current one is hidden from assistive technology, so nothing in it may take focus.
|
|
323
|
-
if (downloadLink) {
|
|
324
|
-
downloadLink.tabIndex = isActive ? 0 : -1;
|
|
325
|
-
}
|
|
326
|
-
dots.children[index].classList.toggle('is-active', isActive);
|
|
327
|
-
dots.children[index].setAttribute('aria-current', isActive ? 'true' : 'false');
|
|
328
|
-
});
|
|
329
|
-
var activeImage = items[activeIndex].querySelector('img');
|
|
330
|
-
var altText = activeImage ? activeImage.getAttribute('alt') : '';
|
|
331
|
-
carousel.dataset.activeIndex = activeIndex;
|
|
332
|
-
carousel.dataset.imageCount = items.length;
|
|
333
|
-
carousel.querySelector('[data-carousel-step="-1"]').disabled = activeIndex === 0;
|
|
334
|
-
carousel.querySelector('[data-carousel-step="1"]').disabled = activeIndex === items.length - 1;
|
|
335
|
-
carousel.querySelector('.ai-image-carousel-caption').textContent = altText ? "".concat(activeIndex + 1, " / ").concat(items.length, " \xB7 ").concat(altText) : "".concat(activeIndex + 1, " / ").concat(items.length);
|
|
336
|
-
activeIndexByCarouselKey.set(carousel.dataset.carouselKey, activeIndex);
|
|
337
|
-
}
|
|
338
|
-
function stopEvent(event) {
|
|
339
|
-
event.preventDefault();
|
|
340
|
-
event.stopPropagation();
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Captured, so it runs before anything bound to the picture itself: a card behind the current one is brought
|
|
344
|
-
// to the front, and is not zoomed or downloaded on the way.
|
|
345
|
-
function onClick(event) {
|
|
346
|
-
var carousel = event.target.closest && event.target.closest('.ai-image-carousel');
|
|
347
|
-
if (!carousel) {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// A click raised from the keyboard has no pointer behind it, so a swipe that ended without one -- a touch
|
|
352
|
-
// swipe, or a drag released outside the carousel -- must not swallow it.
|
|
353
|
-
if (suppressNextClick && event.detail > 0) {
|
|
354
|
-
suppressNextClick = false;
|
|
355
|
-
stopEvent(event);
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
var stepButton = event.target.closest('[data-carousel-step]');
|
|
359
|
-
if (stepButton) {
|
|
360
|
-
stopEvent(event);
|
|
361
|
-
showImage(carousel, getActiveIndex(carousel) + Number(stepButton.dataset.carouselStep));
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
var sizeButton = event.target.closest('[data-carousel-size-option]');
|
|
365
|
-
if (sizeButton) {
|
|
366
|
-
stopEvent(event);
|
|
367
|
-
setPreferredSize(sizeButton.dataset.carouselSizeOption);
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
var dot = event.target.closest('[data-carousel-target]');
|
|
371
|
-
if (dot) {
|
|
372
|
-
stopEvent(event);
|
|
373
|
-
showImage(carousel, Number(dot.dataset.carouselTarget));
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
var item = event.target.closest('.ai-image-carousel-item');
|
|
377
|
-
if (item && !item.classList.contains('is-active')) {
|
|
378
|
-
stopEvent(event);
|
|
379
|
-
showImage(carousel, Array.prototype.indexOf.call(getItems(carousel), item));
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Only while the carousel has focus, so the arrow keys still move the caret in the prompt.
|
|
384
|
-
function onKeyDown(event) {
|
|
385
|
-
if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') {
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
var carousel = event.target.closest && event.target.closest('.ai-image-carousel');
|
|
389
|
-
if (!carousel) {
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
event.preventDefault();
|
|
393
|
-
showImage(carousel, getActiveIndex(carousel) + (event.key === 'ArrowRight' ? 1 : -1));
|
|
394
|
-
}
|
|
395
|
-
function onPointerDown(event) {
|
|
396
|
-
suppressNextClick = false;
|
|
397
|
-
var stage = event.button === 0 && event.target.closest && event.target.closest('.ai-image-carousel-stage');
|
|
398
|
-
if (!stage) {
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
drag = {
|
|
402
|
-
stage: stage,
|
|
403
|
-
pointerId: event.pointerId,
|
|
404
|
-
startX: event.clientX,
|
|
405
|
-
startY: event.clientY,
|
|
406
|
-
distance: 0,
|
|
407
|
-
isSwiping: false
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// The pointer is not captured: a captured pointer retargets the click that follows to the stage, and the click
|
|
412
|
-
// is what brings a card forward or opens the zoom. Listening on the document follows the pointer anyway.
|
|
413
|
-
function onPointerMove(event) {
|
|
414
|
-
if (!drag || event.pointerId !== drag.pointerId) {
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
var distance = event.clientX - drag.startX;
|
|
418
|
-
if (!drag.isSwiping) {
|
|
419
|
-
if (Math.abs(distance) < dragStartThreshold || Math.abs(distance) < Math.abs(event.clientY - drag.startY)) {
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
drag.isSwiping = true;
|
|
423
|
-
drag.stage.classList.add('is-dragging');
|
|
424
|
-
}
|
|
425
|
-
drag.distance = distance;
|
|
426
|
-
drag.stage.style.setProperty('--ai-image-carousel-drag', "".concat(distance, "px"));
|
|
427
|
-
}
|
|
428
|
-
function onPointerUp(event) {
|
|
429
|
-
if (!drag || event.pointerId !== drag.pointerId) {
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
var _drag = drag,
|
|
433
|
-
stage = _drag.stage,
|
|
434
|
-
distance = _drag.distance,
|
|
435
|
-
isSwiping = _drag.isSwiping;
|
|
436
|
-
endDrag();
|
|
437
|
-
if (!isSwiping) {
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// The click the browser fires at the end of a drag is not a click on whatever the pointer ended over.
|
|
442
|
-
suppressNextClick = true;
|
|
443
|
-
if (Math.abs(distance) >= swipeThreshold) {
|
|
444
|
-
var carousel = stage.closest('.ai-image-carousel');
|
|
445
|
-
showImage(carousel, getActiveIndex(carousel) + (distance < 0 ? 1 : -1));
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
function endDrag() {
|
|
449
|
-
if (!drag) {
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
drag.stage.classList.remove('is-dragging');
|
|
453
|
-
drag.stage.style.removeProperty('--ai-image-carousel-drag');
|
|
454
|
-
drag = null;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// A picture the server will not serve is taken out of the stack and put back just after it, where the
|
|
458
|
-
// surface's own handler hides it and says it could not be loaded, exactly as it does for a lone picture.
|
|
459
|
-
// Captured on the document because an image's error event does not bubble.
|
|
460
|
-
function onImageError(event) {
|
|
461
|
-
var item = event.target.tagName === 'IMG' && event.target.closest('.ai-image-carousel-item');
|
|
462
|
-
if (!item) {
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
var carousel = item.closest('.ai-image-carousel');
|
|
466
|
-
item.classList.remove('ai-image-carousel-item', 'is-active');
|
|
467
|
-
item.removeAttribute('data-stack-offset');
|
|
468
|
-
item.removeAttribute('aria-hidden');
|
|
469
|
-
carousel.after(item);
|
|
470
|
-
showImage(carousel, getActiveIndex(carousel));
|
|
471
|
-
}
|
|
472
|
-
if (typeof document !== 'undefined') {
|
|
473
|
-
document.addEventListener('click', onClick, true);
|
|
474
|
-
document.addEventListener('keydown', onKeyDown);
|
|
475
|
-
document.addEventListener('pointerdown', onPointerDown);
|
|
476
|
-
document.addEventListener('pointermove', onPointerMove);
|
|
477
|
-
document.addEventListener('pointerup', onPointerUp);
|
|
478
|
-
document.addEventListener('pointercancel', endDrag);
|
|
479
|
-
document.addEventListener('error', onImageError, true);
|
|
480
|
-
}
|
|
481
|
-
return {
|
|
482
|
-
stackAdjacentImages: stackAdjacentImages
|
|
483
|
-
};
|
|
484
|
-
}();
|
|
5
|
+
(function() {
|
|
6
|
+
//#region src/Resources/CrestApps.AI.Resources/Assets/js/chat-image-carousel.js
|
|
7
|
+
window.CoreAIChatImageCarousel = window.CoreAIChatImageCarousel || (function() {
|
|
8
|
+
"use strict";
|
|
9
|
+
const imageContainerClass = "generated-image-container";
|
|
10
|
+
const swipeThreshold = 40;
|
|
11
|
+
const dragStartThreshold = 8;
|
|
12
|
+
const contentBetweenSelector = "img, svg, canvas, video, audio, iframe, table, hr, input";
|
|
13
|
+
const previousIcon = "<svg viewBox=\"0 0 16 16\" width=\"12\" height=\"12\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M10 3 5 8l5 5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path></svg>";
|
|
14
|
+
const nextIcon = "<svg viewBox=\"0 0 16 16\" width=\"12\" height=\"12\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m6 3 5 5-5 5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path></svg>";
|
|
15
|
+
const sizes = [
|
|
16
|
+
{
|
|
17
|
+
name: "small",
|
|
18
|
+
text: "S",
|
|
19
|
+
label: "Small previews"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "medium",
|
|
23
|
+
text: "M",
|
|
24
|
+
label: "Medium previews"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "large",
|
|
28
|
+
text: "L",
|
|
29
|
+
label: "Large previews"
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
const defaultSize = "medium";
|
|
33
|
+
const sizeStorageKey = "coreai-image-carousel-size";
|
|
34
|
+
const activeIndexByCarouselKey = /* @__PURE__ */ new Map();
|
|
35
|
+
let drag = null;
|
|
36
|
+
let suppressNextClick = false;
|
|
37
|
+
function stackAdjacentImages(html) {
|
|
38
|
+
if (typeof document === "undefined" || !html) return html;
|
|
39
|
+
const firstContainerIndex = html.indexOf(imageContainerClass);
|
|
40
|
+
if (firstContainerIndex < 0 || html.indexOf(imageContainerClass, firstContainerIndex + 25) < 0) return html;
|
|
41
|
+
const template = document.createElement("template");
|
|
42
|
+
template.innerHTML = html;
|
|
43
|
+
const runs = findImageRuns(template.content);
|
|
44
|
+
if (runs.length === 0) return html;
|
|
45
|
+
for (const run of runs) buildCarousel(run);
|
|
46
|
+
return template.innerHTML;
|
|
47
|
+
}
|
|
48
|
+
function findImageRuns(root) {
|
|
49
|
+
const runs = [];
|
|
50
|
+
let run = [];
|
|
51
|
+
for (const container of root.querySelectorAll("." + imageContainerClass)) {
|
|
52
|
+
if (!container.parentElement || container.parentElement.tagName !== "P") {
|
|
53
|
+
runs.push(run);
|
|
54
|
+
run = [];
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (run.length > 0 && !isOnlyWhitespaceBetween(run[run.length - 1], container)) {
|
|
58
|
+
runs.push(run);
|
|
59
|
+
run = [];
|
|
60
|
+
}
|
|
61
|
+
run.push(container);
|
|
62
|
+
}
|
|
63
|
+
runs.push(run);
|
|
64
|
+
return runs.filter((candidate) => candidate.length > 1);
|
|
65
|
+
}
|
|
66
|
+
function isOnlyWhitespaceBetween(previous, next) {
|
|
67
|
+
const range = previous.ownerDocument.createRange();
|
|
68
|
+
range.setStartAfter(previous);
|
|
69
|
+
range.setEndBefore(next);
|
|
70
|
+
const between = range.cloneContents();
|
|
71
|
+
return between.textContent.trim() === "" && !between.querySelector(contentBetweenSelector);
|
|
72
|
+
}
|
|
73
|
+
function buildCarousel(containers) {
|
|
74
|
+
const ownerDocument = containers[0].ownerDocument;
|
|
75
|
+
const firstParagraph = containers[0].parentElement;
|
|
76
|
+
const vacatedParagraphs = /* @__PURE__ */ new Set();
|
|
77
|
+
const carousel = createElement(ownerDocument, "span", "ai-image-carousel");
|
|
78
|
+
carousel.tabIndex = 0;
|
|
79
|
+
carousel.setAttribute("role", "region");
|
|
80
|
+
carousel.setAttribute("aria-roledescription", "carousel");
|
|
81
|
+
carousel.setAttribute("aria-label", `${containers.length} images`);
|
|
82
|
+
carousel.dataset.carouselKey = getCarouselKey(containers);
|
|
83
|
+
carousel.dataset.carouselSize = getPreferredSize();
|
|
84
|
+
const stage = createElement(ownerDocument, "span", "ai-image-carousel-stage");
|
|
85
|
+
const controls = createElement(ownerDocument, "span", "ai-image-carousel-controls");
|
|
86
|
+
const caption = createElement(ownerDocument, "span", "ai-image-carousel-caption");
|
|
87
|
+
const navigation = createElement(ownerDocument, "span", "ai-image-carousel-navigation");
|
|
88
|
+
const dots = createElement(ownerDocument, "span", "ai-image-carousel-dots");
|
|
89
|
+
caption.setAttribute("aria-live", "polite");
|
|
90
|
+
containers[0].before(carousel);
|
|
91
|
+
containers.forEach((container, index) => {
|
|
92
|
+
removeSeparatorsBefore(container);
|
|
93
|
+
if (container.parentElement !== firstParagraph) vacatedParagraphs.add(container.parentElement);
|
|
94
|
+
container.classList.add("ai-image-carousel-item");
|
|
95
|
+
const image = container.querySelector("img");
|
|
96
|
+
if (image) image.setAttribute("draggable", "false");
|
|
97
|
+
const dot = createElement(ownerDocument, "button", "ai-image-carousel-dot");
|
|
98
|
+
dot.type = "button";
|
|
99
|
+
dot.dataset.carouselTarget = index;
|
|
100
|
+
dot.setAttribute("aria-label", `Show image ${index + 1}`);
|
|
101
|
+
dots.appendChild(dot);
|
|
102
|
+
stage.appendChild(container);
|
|
103
|
+
});
|
|
104
|
+
navigation.append(createStepButton(ownerDocument, -1, "Previous image", previousIcon), dots, createStepButton(ownerDocument, 1, "Next image", nextIcon));
|
|
105
|
+
controls.append(caption, createSizePicker(ownerDocument, carousel.dataset.carouselSize), navigation);
|
|
106
|
+
carousel.append(stage, controls);
|
|
107
|
+
for (const paragraph of vacatedParagraphs) if (paragraph.textContent.trim() === "" && !paragraph.querySelector(contentBetweenSelector)) paragraph.remove();
|
|
108
|
+
showImage(carousel, activeIndexByCarouselKey.get(carousel.dataset.carouselKey) || 0);
|
|
109
|
+
}
|
|
110
|
+
function removeSeparatorsBefore(container) {
|
|
111
|
+
let sibling = container.previousSibling;
|
|
112
|
+
while (sibling && (sibling.nodeType === Node.TEXT_NODE && sibling.textContent.trim() === "" || sibling.nodeName === "BR")) {
|
|
113
|
+
const previousSibling = sibling.previousSibling;
|
|
114
|
+
sibling.remove();
|
|
115
|
+
sibling = previousSibling;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function getCarouselKey(containers) {
|
|
119
|
+
const firstImage = containers[0].querySelector("img");
|
|
120
|
+
const firstSource = firstImage ? firstImage.getAttribute("src") || "" : "";
|
|
121
|
+
return `${containers.length}:${firstSource.slice(-120)}`;
|
|
122
|
+
}
|
|
123
|
+
function createElement(ownerDocument, tagName, className) {
|
|
124
|
+
const element = ownerDocument.createElement(tagName);
|
|
125
|
+
element.className = className;
|
|
126
|
+
return element;
|
|
127
|
+
}
|
|
128
|
+
function createStepButton(ownerDocument, step, label, icon) {
|
|
129
|
+
const button = createElement(ownerDocument, "button", "ai-image-carousel-button");
|
|
130
|
+
button.type = "button";
|
|
131
|
+
button.dataset.carouselStep = step;
|
|
132
|
+
button.setAttribute("aria-label", label);
|
|
133
|
+
button.innerHTML = icon;
|
|
134
|
+
return button;
|
|
135
|
+
}
|
|
136
|
+
function createSizePicker(ownerDocument, selectedSize) {
|
|
137
|
+
const picker = createElement(ownerDocument, "span", "ai-image-carousel-sizes");
|
|
138
|
+
picker.setAttribute("role", "group");
|
|
139
|
+
picker.setAttribute("aria-label", "Preview size");
|
|
140
|
+
for (const size of sizes) {
|
|
141
|
+
const button = createElement(ownerDocument, "button", "ai-image-carousel-size");
|
|
142
|
+
button.type = "button";
|
|
143
|
+
button.title = size.label;
|
|
144
|
+
button.textContent = size.text;
|
|
145
|
+
button.dataset.carouselSizeOption = size.name;
|
|
146
|
+
button.setAttribute("aria-label", size.label);
|
|
147
|
+
button.setAttribute("aria-pressed", size.name === selectedSize ? "true" : "false");
|
|
148
|
+
picker.appendChild(button);
|
|
149
|
+
}
|
|
150
|
+
return picker;
|
|
151
|
+
}
|
|
152
|
+
function getPreferredSize() {
|
|
153
|
+
try {
|
|
154
|
+
const storedSize = localStorage.getItem(sizeStorageKey);
|
|
155
|
+
return sizes.some((size) => size.name === storedSize) ? storedSize : defaultSize;
|
|
156
|
+
} catch (_) {
|
|
157
|
+
return defaultSize;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function setPreferredSize(selectedSize) {
|
|
161
|
+
try {
|
|
162
|
+
localStorage.setItem(sizeStorageKey, selectedSize);
|
|
163
|
+
} catch (_) {}
|
|
164
|
+
for (const carousel of document.querySelectorAll(".ai-image-carousel")) carousel.dataset.carouselSize = selectedSize;
|
|
165
|
+
for (const button of document.querySelectorAll("[data-carousel-size-option]")) button.setAttribute("aria-pressed", button.dataset.carouselSizeOption === selectedSize ? "true" : "false");
|
|
166
|
+
}
|
|
167
|
+
function getItems(carousel) {
|
|
168
|
+
return carousel.querySelectorAll(".ai-image-carousel-stage > .ai-image-carousel-item");
|
|
169
|
+
}
|
|
170
|
+
function getActiveIndex(carousel) {
|
|
171
|
+
return Number(carousel.dataset.activeIndex) || 0;
|
|
172
|
+
}
|
|
173
|
+
function showImage(carousel, requestedIndex) {
|
|
174
|
+
const items = getItems(carousel);
|
|
175
|
+
if (items.length === 0) {
|
|
176
|
+
carousel.remove();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const activeIndex = Math.max(0, Math.min(items.length - 1, requestedIndex));
|
|
180
|
+
const dots = carousel.querySelector(".ai-image-carousel-dots");
|
|
181
|
+
while (dots.children.length > items.length) dots.lastElementChild.remove();
|
|
182
|
+
items.forEach((item, index) => {
|
|
183
|
+
const offset = index - activeIndex;
|
|
184
|
+
const isActive = offset === 0;
|
|
185
|
+
const downloadLink = item.querySelector("a");
|
|
186
|
+
item.dataset.stackOffset = Math.max(-3, Math.min(3, offset));
|
|
187
|
+
item.classList.toggle("is-active", isActive);
|
|
188
|
+
item.setAttribute("aria-hidden", isActive ? "false" : "true");
|
|
189
|
+
if (downloadLink) downloadLink.tabIndex = isActive ? 0 : -1;
|
|
190
|
+
dots.children[index].classList.toggle("is-active", isActive);
|
|
191
|
+
dots.children[index].setAttribute("aria-current", isActive ? "true" : "false");
|
|
192
|
+
});
|
|
193
|
+
const activeImage = items[activeIndex].querySelector("img");
|
|
194
|
+
const altText = activeImage ? activeImage.getAttribute("alt") : "";
|
|
195
|
+
carousel.dataset.activeIndex = activeIndex;
|
|
196
|
+
carousel.dataset.imageCount = items.length;
|
|
197
|
+
carousel.querySelector("[data-carousel-step=\"-1\"]").disabled = activeIndex === 0;
|
|
198
|
+
carousel.querySelector("[data-carousel-step=\"1\"]").disabled = activeIndex === items.length - 1;
|
|
199
|
+
carousel.querySelector(".ai-image-carousel-caption").textContent = altText ? `${activeIndex + 1} / ${items.length} · ${altText}` : `${activeIndex + 1} / ${items.length}`;
|
|
200
|
+
activeIndexByCarouselKey.set(carousel.dataset.carouselKey, activeIndex);
|
|
201
|
+
}
|
|
202
|
+
function stopEvent(event) {
|
|
203
|
+
event.preventDefault();
|
|
204
|
+
event.stopPropagation();
|
|
205
|
+
}
|
|
206
|
+
function onClick(event) {
|
|
207
|
+
const carousel = event.target.closest && event.target.closest(".ai-image-carousel");
|
|
208
|
+
if (!carousel) return;
|
|
209
|
+
if (suppressNextClick && event.detail > 0) {
|
|
210
|
+
suppressNextClick = false;
|
|
211
|
+
stopEvent(event);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const stepButton = event.target.closest("[data-carousel-step]");
|
|
215
|
+
if (stepButton) {
|
|
216
|
+
stopEvent(event);
|
|
217
|
+
showImage(carousel, getActiveIndex(carousel) + Number(stepButton.dataset.carouselStep));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const sizeButton = event.target.closest("[data-carousel-size-option]");
|
|
221
|
+
if (sizeButton) {
|
|
222
|
+
stopEvent(event);
|
|
223
|
+
setPreferredSize(sizeButton.dataset.carouselSizeOption);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const dot = event.target.closest("[data-carousel-target]");
|
|
227
|
+
if (dot) {
|
|
228
|
+
stopEvent(event);
|
|
229
|
+
showImage(carousel, Number(dot.dataset.carouselTarget));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const item = event.target.closest(".ai-image-carousel-item");
|
|
233
|
+
if (item && !item.classList.contains("is-active")) {
|
|
234
|
+
stopEvent(event);
|
|
235
|
+
showImage(carousel, Array.prototype.indexOf.call(getItems(carousel), item));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function onKeyDown(event) {
|
|
239
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
240
|
+
const carousel = event.target.closest && event.target.closest(".ai-image-carousel");
|
|
241
|
+
if (!carousel) return;
|
|
242
|
+
event.preventDefault();
|
|
243
|
+
showImage(carousel, getActiveIndex(carousel) + (event.key === "ArrowRight" ? 1 : -1));
|
|
244
|
+
}
|
|
245
|
+
function onPointerDown(event) {
|
|
246
|
+
suppressNextClick = false;
|
|
247
|
+
const stage = event.button === 0 && event.target.closest && event.target.closest(".ai-image-carousel-stage");
|
|
248
|
+
if (!stage) return;
|
|
249
|
+
drag = {
|
|
250
|
+
stage,
|
|
251
|
+
pointerId: event.pointerId,
|
|
252
|
+
startX: event.clientX,
|
|
253
|
+
startY: event.clientY,
|
|
254
|
+
distance: 0,
|
|
255
|
+
isSwiping: false
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function onPointerMove(event) {
|
|
259
|
+
if (!drag || event.pointerId !== drag.pointerId) return;
|
|
260
|
+
const distance = event.clientX - drag.startX;
|
|
261
|
+
if (!drag.isSwiping) {
|
|
262
|
+
if (Math.abs(distance) < dragStartThreshold || Math.abs(distance) < Math.abs(event.clientY - drag.startY)) return;
|
|
263
|
+
drag.isSwiping = true;
|
|
264
|
+
drag.stage.classList.add("is-dragging");
|
|
265
|
+
}
|
|
266
|
+
drag.distance = distance;
|
|
267
|
+
drag.stage.style.setProperty("--ai-image-carousel-drag", `${distance}px`);
|
|
268
|
+
}
|
|
269
|
+
function onPointerUp(event) {
|
|
270
|
+
if (!drag || event.pointerId !== drag.pointerId) return;
|
|
271
|
+
const { stage, distance, isSwiping } = drag;
|
|
272
|
+
endDrag();
|
|
273
|
+
if (!isSwiping) return;
|
|
274
|
+
suppressNextClick = true;
|
|
275
|
+
if (Math.abs(distance) >= swipeThreshold) {
|
|
276
|
+
const carousel = stage.closest(".ai-image-carousel");
|
|
277
|
+
showImage(carousel, getActiveIndex(carousel) + (distance < 0 ? 1 : -1));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function endDrag() {
|
|
281
|
+
if (!drag) return;
|
|
282
|
+
drag.stage.classList.remove("is-dragging");
|
|
283
|
+
drag.stage.style.removeProperty("--ai-image-carousel-drag");
|
|
284
|
+
drag = null;
|
|
285
|
+
}
|
|
286
|
+
function onImageError(event) {
|
|
287
|
+
const item = event.target.tagName === "IMG" && event.target.closest(".ai-image-carousel-item");
|
|
288
|
+
if (!item) return;
|
|
289
|
+
const carousel = item.closest(".ai-image-carousel");
|
|
290
|
+
item.classList.remove("ai-image-carousel-item", "is-active");
|
|
291
|
+
item.removeAttribute("data-stack-offset");
|
|
292
|
+
item.removeAttribute("aria-hidden");
|
|
293
|
+
carousel.after(item);
|
|
294
|
+
showImage(carousel, getActiveIndex(carousel));
|
|
295
|
+
}
|
|
296
|
+
if (typeof document !== "undefined") {
|
|
297
|
+
document.addEventListener("click", onClick, true);
|
|
298
|
+
document.addEventListener("keydown", onKeyDown);
|
|
299
|
+
document.addEventListener("pointerdown", onPointerDown);
|
|
300
|
+
document.addEventListener("pointermove", onPointerMove);
|
|
301
|
+
document.addEventListener("pointerup", onPointerUp);
|
|
302
|
+
document.addEventListener("pointercancel", endDrag);
|
|
303
|
+
document.addEventListener("error", onImageError, true);
|
|
304
|
+
}
|
|
305
|
+
return { stackAdjacentImages };
|
|
306
|
+
})();
|
|
307
|
+
//#endregion
|
|
308
|
+
})();
|
|
485
309
|
//# sourceMappingURL=chat-image-carousel.js.map
|