@behold/widget 0.5.63 → 0.5.65

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1032 @@
1
+ import { c as createElement, p as pushWithLimit, g as getAsyncRect, s as setCssVars, a as setClasses, h as hasChanges } from './index-zGq7k0wG.js';
2
+ import { B as BaseWidget, I as ImagePost, V as VideoPost, A as AlbumPost, b as baseGridStyles, g as getMedianHSL } from './base-D7ZLOWQ5.js';
3
+ import { c as caretLeftIcon, a as caretRightIcon } from './caret-right-S2XSTDFy.js';
4
+
5
+ class Gyre {
6
+ containerEl;
7
+ slideEls;
8
+ height;
9
+ gap;
10
+ borderRadius;
11
+ applyBorderRadiusToContainer;
12
+ snapToSlide;
13
+ bindToScrollPos;
14
+ resizeObserver;
15
+ onSlideChange;
16
+ _containerWidth;
17
+ _contentWidth;
18
+ _slideContentEls;
19
+ _slideDimensions;
20
+ _isInitialized;
21
+ _isDragging;
22
+ _isScrolling;
23
+ _velocity;
24
+ _settledPosition;
25
+ _currentPosition;
26
+ _targetPosition;
27
+ _points;
28
+ _momentumArray;
29
+ _lastLoopRun;
30
+ _minSlideWidth;
31
+ _adjustment;
32
+ _numInitialSlides;
33
+ _frameRate;
34
+ _shrinkStartMultiplier;
35
+ _adjustmentMultiplier;
36
+ _windowHeight;
37
+ _containerRect;
38
+ _scrollProgress;
39
+ _abortScrollCheck;
40
+ _virtualize;
41
+ _raf;
42
+ anchorSlide;
43
+ finalAnchorSlide;
44
+ constructor({ onSlideChange }) {
45
+ this._slideDimensions = [];
46
+ this._isInitialized = false;
47
+ this._isDragging = false;
48
+ this._isScrolling = false;
49
+ this._velocity = 0;
50
+ this._settledPosition = 0;
51
+ this._currentPosition = 0;
52
+ this.anchorSlide = 0;
53
+ this._targetPosition = 0;
54
+ this._points = { start: 0, previous: 0 };
55
+ this._momentumArray = [];
56
+ this._lastLoopRun = 0;
57
+ this._frameRate = 1 / 60;
58
+ this._shrinkStartMultiplier = 3;
59
+ this._adjustmentMultiplier = 2;
60
+ this.borderRadius = 20;
61
+ this.applyBorderRadiusToContainer = false;
62
+ this.gap = 20;
63
+ this.height = 300;
64
+ this.snapToSlide = false;
65
+ this.bindToScrollPos = false;
66
+ this._minSlideWidth = 40;
67
+ this._adjustment = 0;
68
+ this._numInitialSlides = 0;
69
+ this._windowHeight = window.innerHeight;
70
+ this._containerRect = null;
71
+ this._scrollProgress = 0;
72
+ this._abortScrollCheck = () => { };
73
+ this._virtualize = false;
74
+ this.onSlideChange = onSlideChange;
75
+ let ResizeObserver = window.ResizeObserver;
76
+ if ('ResizeObserver' in window === false) {
77
+ // @ts-ignore
78
+ ResizeObserver = window.BeholdResizeObserver;
79
+ }
80
+ this.resizeObserver = new ResizeObserver((entries) => this.handleResize(entries));
81
+ this.handlePointerdown = this.handlePointerdown.bind(this);
82
+ this.handlePointermove = this.handlePointermove.bind(this);
83
+ this.handlePointerup = this.handlePointerup.bind(this);
84
+ }
85
+ init({ containerEl, slideEls, height = 300, gap = 20, borderRadius = 40, applyBorderRadiusToContainer = true, snapToSlide = false, bindToScrollPos = false, }) {
86
+ this.containerEl = containerEl;
87
+ this.slideEls = slideEls.map((slide) => {
88
+ return createElement({
89
+ classes: 'ec-slide',
90
+ contents: slide,
91
+ });
92
+ });
93
+ this._slideContentEls = slideEls;
94
+ this._containerWidth = containerEl.offsetWidth;
95
+ this._contentWidth = containerEl?.scrollWidth || 0;
96
+ this.updateSettings({
97
+ height,
98
+ gap,
99
+ borderRadius,
100
+ applyBorderRadiusToContainer,
101
+ snapToSlide,
102
+ bindToScrollPos,
103
+ });
104
+ this.addEventListeners();
105
+ this.containerEl.style.setProperty('--ec-container-width', `${this._containerWidth}px`);
106
+ this.containerEl.beholdReplaceChildren(...this.slideEls);
107
+ this.updateDimensions();
108
+ this._isInitialized = true;
109
+ this.loop();
110
+ }
111
+ updateSettings({ height = 300, gap = 20, borderRadius = 40, applyBorderRadiusToContainer = true, snapToSlide = false, bindToScrollPos = false, }) {
112
+ cancelAnimationFrame(this._raf);
113
+ this._raf = requestAnimationFrame(() => {
114
+ this.height = height;
115
+ this.gap = gap;
116
+ this.borderRadius = Math.min((borderRadius / 100) * this.height, (this._containerWidth * 0.45) / 2);
117
+ this._minSlideWidth = Math.max(this.borderRadius, 40);
118
+ this.applyBorderRadiusToContainer = applyBorderRadiusToContainer;
119
+ this.snapToSlide = snapToSlide;
120
+ this.bindToScrollPos = bindToScrollPos;
121
+ this.containerEl.style.setProperty('--ec-height', `${this.height}px`);
122
+ this.containerEl.style.setProperty('--ec-border-radius', this.applyBorderRadiusToContainer ? `${this.borderRadius}px` : '0px');
123
+ if (this.snapToSlide) {
124
+ this._targetPosition = -this.getClosestSlideToPoint(this._targetPosition).leftEdge;
125
+ }
126
+ });
127
+ }
128
+ destroy() {
129
+ this._isInitialized = false;
130
+ cancelAnimationFrame(this._raf);
131
+ this.removeEventListeners();
132
+ if (this.slideEls?.length) {
133
+ this.slideEls.forEach((slide) => {
134
+ slide.remove();
135
+ });
136
+ }
137
+ this.slideEls = null;
138
+ this.containerEl = null;
139
+ }
140
+ handleResize(entries) {
141
+ let containerWidth = null;
142
+ if (entries) {
143
+ entries.forEach((entry) => {
144
+ if (entry.target === this.containerEl) {
145
+ containerWidth = entry.borderBoxSize
146
+ ? entry.borderBoxSize[0].inlineSize
147
+ : entry.contentRect.width;
148
+ }
149
+ });
150
+ }
151
+ this.updateDimensions(containerWidth);
152
+ this._targetPosition = Math.max(Math.min(0, this._targetPosition), this._containerWidth - this._contentWidth);
153
+ }
154
+ addEventListeners() {
155
+ this.removeEventListeners();
156
+ if (this.slideEls.length) {
157
+ this.slideEls.forEach((slide) => {
158
+ this.resizeObserver.observe(slide);
159
+ });
160
+ }
161
+ if (this.containerEl) {
162
+ this.resizeObserver.observe(this.containerEl);
163
+ this.containerEl.addEventListener('pointerdown', this.handlePointerdown);
164
+ document.addEventListener('pointermove', this.handlePointermove, { passive: true });
165
+ document.addEventListener('pointerup', this.handlePointerup);
166
+ document.body.addEventListener('pointerleave', this.handlePointerup);
167
+ }
168
+ }
169
+ removeEventListeners() {
170
+ this.resizeObserver.disconnect();
171
+ if (this.containerEl) {
172
+ this.containerEl.removeEventListener('pointerdown', this.handlePointerdown);
173
+ document.removeEventListener('pointermove', this.handlePointermove);
174
+ document.removeEventListener('pointerup', this.handlePointerup);
175
+ }
176
+ }
177
+ handlePointerdown(e) {
178
+ this._isDragging = true;
179
+ this._settledPosition = this._currentPosition;
180
+ this._targetPosition = this._currentPosition;
181
+ this._points.start = e.clientX;
182
+ this._points.previous = e.clientX;
183
+ this.updateDimensions();
184
+ }
185
+ handlePointermove(e) {
186
+ if (!this._isDragging)
187
+ return;
188
+ const delta = e.clientX - this._points.start;
189
+ if (Math.abs(delta) > 10) {
190
+ this.containerEl.classList.add('ec-is-dragging');
191
+ }
192
+ this._targetPosition = this._settledPosition + delta;
193
+ pushWithLimit(this._momentumArray, e.clientX - this._points.previous, 10);
194
+ this._points.previous = e.clientX;
195
+ }
196
+ handlePointerup() {
197
+ this.containerEl.classList.remove('ec-is-dragging');
198
+ this._isDragging = false;
199
+ this._targetPosition += getArrayAverage(this._momentumArray) * 10;
200
+ // Keep in bounds
201
+ this._targetPosition = Math.max(Math.min(0, this._targetPosition), this._containerWidth - this._contentWidth);
202
+ // Snap to slide
203
+ if (this.snapToSlide) {
204
+ this._targetPosition = -this.getClosestSlideToPoint(this._targetPosition)
205
+ .leftEdge;
206
+ }
207
+ }
208
+ updateDimensions(containerWidth) {
209
+ this._containerWidth = containerWidth || this.containerEl.offsetWidth;
210
+ let contentWidth = 0;
211
+ this._slideDimensions = this.slideEls.map((slide, i) => {
212
+ let width = slide.offsetWidth;
213
+ let x = contentWidth;
214
+ contentWidth += width;
215
+ if (i < this._slideDimensions.length - 1) {
216
+ contentWidth += this.gap;
217
+ }
218
+ return { width, x };
219
+ });
220
+ this._contentWidth = contentWidth;
221
+ this.finalAnchorSlide = this.getFinalAnchorSlide();
222
+ this.containerEl.style.setProperty('--ec-container-width', `${this._containerWidth}px`);
223
+ }
224
+ getAcceleration({ displacement, velocity, stiffness = 7, mass = 17, friction = 1.25, }) {
225
+ let val = (-stiffness * displacement) / mass - friction * velocity;
226
+ if (Math.abs(val) < 0.001)
227
+ val = 0;
228
+ return val * this._frameRate;
229
+ }
230
+ getClosestSlideToPoint(x) {
231
+ return this._slideDimensions.reduce((acc, curr, i) => {
232
+ const distanceFromTarget = Math.abs(acc.cumulativeWidth + x);
233
+ if (distanceFromTarget < acc.distanceFromTarget) {
234
+ return {
235
+ index: i,
236
+ distanceFromTarget,
237
+ leftEdge: acc.cumulativeWidth,
238
+ cumulativeWidth: acc.cumulativeWidth + curr.width + this.gap,
239
+ };
240
+ }
241
+ return {
242
+ ...acc,
243
+ cumulativeWidth: acc.cumulativeWidth + curr.width + this.gap,
244
+ };
245
+ }, {
246
+ index: 0,
247
+ distanceFromTarget: Infinity,
248
+ leftEdge: 0,
249
+ cumulativeWidth: 0,
250
+ });
251
+ }
252
+ getFinalAnchorSlide() {
253
+ const res = this.slideEls.reduceRight((acc, curr, i) => {
254
+ if (acc.cumulativeWidth < this._containerWidth) {
255
+ acc.index = i;
256
+ acc.cumulativeWidth += this._slideDimensions[i]?.width || 0;
257
+ }
258
+ return acc;
259
+ }, {
260
+ index: 0,
261
+ cumulativeWidth: 0,
262
+ });
263
+ return res.index;
264
+ }
265
+ updateScrollPos() {
266
+ this._abortScrollCheck();
267
+ this._abortScrollCheck = getAsyncRect(this.containerEl, (rect) => {
268
+ this._containerWidth = rect.width;
269
+ const newProgress = Math.max(Math.min((this._windowHeight - rect.top) /
270
+ (this._windowHeight + rect.height), 1), 0);
271
+ if (newProgress !== this._scrollProgress) {
272
+ this._isScrolling = true;
273
+ const progressDelta = this._scrollProgress - newProgress;
274
+ const pixelDelta = this._windowHeight * progressDelta * 0.5;
275
+ this._targetPosition += pixelDelta;
276
+ this._targetPosition = Math.max(Math.min(0, this._targetPosition), this._containerWidth - this._contentWidth);
277
+ this._scrollProgress = newProgress;
278
+ }
279
+ this._containerRect = rect;
280
+ });
281
+ }
282
+ updatePosition() {
283
+ const delta = this._currentPosition - this._targetPosition;
284
+ let stiffness = 200;
285
+ let friction = 23;
286
+ let mass = 80;
287
+ if (this._isScrolling) {
288
+ stiffness = 600;
289
+ friction = 40;
290
+ mass = 40;
291
+ }
292
+ if (this._targetPosition === 0 ||
293
+ this._targetPosition <= this._containerWidth - this._contentWidth) {
294
+ stiffness = 100;
295
+ friction = 16;
296
+ mass = 45;
297
+ }
298
+ const acceleration = this.getAcceleration({
299
+ displacement: delta,
300
+ velocity: this._velocity,
301
+ stiffness,
302
+ friction,
303
+ mass,
304
+ });
305
+ this._velocity += acceleration;
306
+ this._currentPosition += roundToDigits(this._velocity);
307
+ }
308
+ getSlidePositions() {
309
+ const currentPosition = roundToDigits(this._currentPosition);
310
+ let xPos = currentPosition;
311
+ let needsAdjustment = false;
312
+ const values = this.slideEls.map((el, i) => {
313
+ const contentEl = this._slideContentEls[i];
314
+ const slideWidth = this._slideDimensions[i]?.width;
315
+ if (i > 0) {
316
+ xPos += this._slideDimensions[i - 1]?.width + this.gap;
317
+ }
318
+ let innerTranslate = 0;
319
+ let leftClipInset = 0;
320
+ let rightClipInset = 0;
321
+ let xOffset = 0;
322
+ let shrinkStartPoint = Math.min(slideWidth * this._shrinkStartMultiplier, this._containerWidth);
323
+ const dimensions = this._slideDimensions[i];
324
+ const isEndingSlide = dimensions &&
325
+ dimensions.x + dimensions.width * this._shrinkStartMultiplier >
326
+ this._contentWidth;
327
+ // Final slides that would be shrunk when at the end of scroll
328
+ if (isEndingSlide) {
329
+ shrinkStartPoint =
330
+ slideWidth * (this.slideEls.length - i) + Math.round(this._adjustment);
331
+ }
332
+ let shrinkProgress = Math.min(Math.max(shrinkStartPoint -
333
+ Math.max(this._containerWidth - xPos + Math.round(this._adjustment), 0), 0) /
334
+ (shrinkStartPoint - this._minSlideWidth), 1);
335
+ const baseOffset = (slideWidth - this._minSlideWidth) * shrinkProgress;
336
+ rightClipInset = baseOffset;
337
+ innerTranslate = -baseOffset / 2;
338
+ xOffset -= baseOffset;
339
+ const isRightmost = xPos < this._containerWidth &&
340
+ xPos + slideWidth - rightClipInset + this.gap >= this._containerWidth;
341
+ if (isRightmost && currentPosition <= 0) {
342
+ const visualWidth = slideWidth - leftClipInset - rightClipInset;
343
+ const overflow = this._minSlideWidth - (this._containerWidth - xPos);
344
+ const visible = overflow <= 0 ? visualWidth : this._containerWidth - xPos;
345
+ const visibleGap = this._containerWidth - (xPos + visible);
346
+ // There is a gap between the last slide and the container edge
347
+ if (visibleGap > 0 && !this._adjustment) {
348
+ this._adjustment = visibleGap * this._adjustmentMultiplier;
349
+ this._numInitialSlides = i + 1;
350
+ needsAdjustment = true;
351
+ }
352
+ // The last slide isn't showing enough
353
+ if (visible < this._minSlideWidth / 2 && !this._adjustment) {
354
+ this._adjustment = (visible + this.gap) * this._adjustmentMultiplier;
355
+ this._numInitialSlides = i + 1;
356
+ needsAdjustment = true;
357
+ }
358
+ }
359
+ // Leftmost visible slide
360
+ if (Math.round(xPos - this.gap) <= 0 &&
361
+ Math.round(slideWidth + xPos) > 0) {
362
+ if (i !== this.anchorSlide && this.onSlideChange) {
363
+ this.onSlideChange(i);
364
+ }
365
+ this.anchorSlide = i;
366
+ }
367
+ if (xPos <= 0) {
368
+ const baseOffset = Math.min(Math.abs(xPos), slideWidth - this._minSlideWidth);
369
+ leftClipInset = baseOffset;
370
+ innerTranslate = xPos / -2;
371
+ }
372
+ // Virtualize
373
+ if (this._virtualize) {
374
+ if (xPos > this._containerWidth + 250 || xPos + slideWidth < -250) {
375
+ contentEl.remove();
376
+ }
377
+ else if (!contentEl.isConnected) {
378
+ el.append(contentEl);
379
+ }
380
+ }
381
+ const slideValues = {
382
+ el,
383
+ contentEl,
384
+ xPos,
385
+ rightClipInset,
386
+ leftClipInset,
387
+ innerTranslate,
388
+ };
389
+ xPos += xOffset;
390
+ return slideValues;
391
+ });
392
+ if (needsAdjustment) {
393
+ return this.getSlidePositions();
394
+ }
395
+ return values;
396
+ }
397
+ positionSlides() {
398
+ let calculatedValues = this.getSlidePositions();
399
+ calculatedValues.forEach(({ el, contentEl, xPos, rightClipInset, leftClipInset, innerTranslate }, i) => {
400
+ const borderRadius = Math.min(this.borderRadius, this._slideDimensions[i]?.width / 2);
401
+ el.style.transform = `translate3d(${xPos}px, 0 ,0)`;
402
+ el.style.clipPath = `inset(0 ${rightClipInset}px 0 ${leftClipInset}px round ${borderRadius}px)`;
403
+ contentEl.style.transform = `translate3d(${innerTranslate}px, 0, 0)`;
404
+ });
405
+ }
406
+ goToSlide(slideIndex) {
407
+ this.updateDimensions();
408
+ this._targetPosition =
409
+ -this._slideDimensions[slideIndex]?.x ?? this._targetPosition;
410
+ this._targetPosition = Math.max(Math.min(0, this._targetPosition), this._containerWidth - this._contentWidth);
411
+ }
412
+ advance() {
413
+ this.goToSlide(Math.min(this.getClosestSlideToPoint(this._targetPosition).index + 1, this.slideEls.length - 1));
414
+ }
415
+ retreat() {
416
+ this.goToSlide(Math.max(this.getClosestSlideToPoint(this._targetPosition).index - 1, 0));
417
+ }
418
+ render() {
419
+ this._momentumArray.shift();
420
+ if (!this.slideEls)
421
+ return;
422
+ if (this.bindToScrollPos) {
423
+ this.updateScrollPos();
424
+ }
425
+ this.updatePosition();
426
+ this.positionSlides();
427
+ this._isScrolling = false;
428
+ }
429
+ loop() {
430
+ if (!this._isInitialized)
431
+ return;
432
+ const now = performance.now();
433
+ if (now - this._lastLoopRun > 16) {
434
+ this.render();
435
+ this._lastLoopRun = now;
436
+ }
437
+ requestAnimationFrame(() => this.loop());
438
+ }
439
+ }
440
+ function getArrayAverage(arr) {
441
+ if (!arr.length)
442
+ return 0;
443
+ return arr.reduce((acc, curr) => acc + curr, 0) / arr.length;
444
+ }
445
+ function roundToDigits(num, digits = 3) {
446
+ return parseFloat(num.toFixed(digits));
447
+ }
448
+
449
+ var instagramIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1000 1000\"><path d=\"M295.42,6c-53.2,2.51-89.53,11-121.29,23.48-32.87,12.81-60.73,30-88.45,57.82S40.89,143,28.17,175.92c-12.31,31.83-20.65,68.19-23,121.42S2.3,367.68,2.56,503.46,3.42,656.26,6,709.6c2.54,53.19,11,89.51,23.48,121.28,12.83,32.87,30,60.72,57.83,88.45S143,964.09,176,976.83c31.8,12.29,68.17,20.67,121.39,23s70.35,2.87,206.09,2.61,152.83-.86,206.16-3.39S799.1,988,830.88,975.58c32.87-12.86,60.74-30,88.45-57.84S964.1,862,976.81,829.06c12.32-31.8,20.69-68.17,23-121.35,2.33-53.37,2.88-70.41,2.62-206.17s-.87-152.78-3.4-206.1-11-89.53-23.47-121.32c-12.85-32.87-30-60.7-57.82-88.45S862,40.87,829.07,28.19c-31.82-12.31-68.17-20.7-121.39-23S637.33,2.3,501.54,2.56,348.75,3.4,295.42,6m5.84,903.88c-48.75-2.12-75.22-10.22-92.86-17-23.36-9-40-19.88-57.58-37.29s-28.38-34.11-37.5-57.42c-6.85-17.64-15.1-44.08-17.38-92.83-2.48-52.69-3-68.51-3.29-202s.22-149.29,2.53-202c2.08-48.71,10.23-75.21,17-92.84,9-23.39,19.84-40,37.29-57.57s34.1-28.39,57.43-37.51c17.62-6.88,44.06-15.06,92.79-17.38,52.73-2.5,68.53-3,202-3.29s149.31.21,202.06,2.53c48.71,2.12,75.22,10.19,92.83,17,23.37,9,40,19.81,57.57,37.29s28.4,34.07,37.52,57.45c6.89,17.57,15.07,44,17.37,92.76,2.51,52.73,3.08,68.54,3.32,202s-.23,149.31-2.54,202c-2.13,48.75-10.21,75.23-17,92.89-9,23.35-19.85,40-37.31,57.56s-34.09,28.38-57.43,37.5c-17.6,6.87-44.07,15.07-92.76,17.39-52.73,2.48-68.53,3-202.05,3.29s-149.27-.25-202-2.53m407.6-674.61a60,60,0,1,0,59.88-60.1,60,60,0,0,0-59.88,60.1M245.77,503c.28,141.8,115.44,256.49,257.21,256.22S759.52,643.8,759.25,502,643.79,245.48,502,245.76,245.5,361.22,245.77,503m90.06-.18a166.67,166.67,0,1,1,167,166.34,166.65,166.65,0,0,1-167-166.34\" transform=\"translate(-2.5 -2.5)\"/><title>Instagram</title></svg>";
450
+
451
+ var css_248z = ".ec-carousel{--ec-controls-margin:20px;--ec-button-border-radius:40%;--ec-icon-color:#4a4a4a;--ec-text-color:#4a4a4a;--ec-button-color:#f4f4f4;--ec-button-hover-color:#ececec;--ec-button-icon-color:#4a4a4a;--ec-button-icon-hover-color:#2e2e2e;--ec-button-gap:min(calc(var(--ec-controls-margin)/2),5px);flex-direction:column;height:var(--ec-height);margin:0;overflow:hidden;width:100%}.ec-carousel,.ec-inner{display:flex;justify-content:center}.ec-inner{align-items:center}.ec-slides{border-radius:var(--ec-border-radius);contain:style paint;cursor:grab;height:var(--ec-height);justify-content:flex-start;overflow:hidden;position:relative;touch-action:none;width:100%}.ec-slide,.ec-slides{display:flex;isolation:isolate}.ec-slide{contain:content;flex-shrink:0;height:100%;left:0;max-width:calc(var(--ec-container-width)*.45);position:absolute;top:0;-moz-user-select:none;user-select:none;-webkit-user-select:none;will-change:clip-path,transform}.ec-slide .post--placeholder{aspect-ratio:unset;height:100%}.ec-is-dragging{cursor:grabbing}.ec-is-dragging .ec-slide{pointer-events:none}.ec-footer,.ec-header{display:flex;justify-content:center}.ec-carousel--controls-sides .ec-footer,.ec-carousel--controls-sides .ec-header{padding:0 64px}.ec-header{margin-bottom:var(--ec-controls-margin)}.ec-footer{margin-top:var(--ec-controls-margin)}.ec-label{align-items:center;display:flex;flex-shrink:1;gap:7px 5px;line-height:1.2;min-width:0;overflow:hidden;text-overflow:ellipsis;-moz-user-select:none;user-select:none;-webkit-user-select:none}.ec-carousel--controls-center .ec-button+.ec-label,.ec-carousel--controls-split .ec-button+.ec-label{margin:0 max(calc(var(--ec-controls-margin)*1.5),20px)}.ec-carousel--label-right .ec-label{margin-left:auto}.ec-carousel--label-left .ec-label{margin-right:auto}.ec-label svg{flex-shrink:0;height:24px;margin-right:5px;width:24px}.ec-label svg path{fill:var(--ec-icon-color)}.ec-label a,.ec-label div{color:var(--ec-text-color);display:inline-block;font-family:inherit;font-size:19px;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.ec-button,.ec-carousel--controls-center .ec-footer,.ec-carousel--controls-center .ec-header{justify-content:center}.ec-button{align-items:center;background-color:transparent;border:none;cursor:pointer;display:flex;flex-shrink:0;height:44px;padding:0;transition:all .3s ease;width:44px}.ec-carousel--controls-sides .ec-button{height:var(--ec-height);width:64px}.ec-button:disabled{cursor:default;opacity:.5}.ec-button:before{background-color:var(--ec-button-color);border-radius:var(--ec-button-border-radius);content:\"\";height:44px;position:absolute;transition:all .3s ease;width:44px}.ec-button:not(:disabled):hover:before{background-color:var(--ec-button-hover-color)}.ec-button svg{height:14px;position:relative;width:auto;z-index:1}.ec-button svg path{fill:var(--ec-button-icon-color);transition:all .3s ease}.ec-button:not(:disabled):hover svg path{fill:var(--ec-button-icon-hover-color)}.ec-retreat{padding-right:var(--ec-button-gap);width:calc(44px + var(--ec-button-gap))}.ec-carousel--controls-split .ec-retreat{margin-right:auto}.ec-carousel--controls-right .ec-retreat{margin-left:auto}.ec-advance{padding-left:var(--ec-button-gap);width:calc(44px + var(--ec-button-gap))}.ec-carousel--controls-split .ec-advance{margin-left:auto}.ec-carousel--controls-left .ec-advance{margin-right:auto}.ec-carousel--controls-sides .ec-retreat{padding-right:20px}.ec-carousel--controls-sides .ec-advance{padding-left:20px}.post{height:100%;max-width:calc(var(--ec-container-width)*.45)}.post a{-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.post--placeholder{background-color:#dedede;height:0;padding-bottom:calc(100%/var(--post-aspect-ratio))}";
452
+ var styles = css_248z;
453
+
454
+ /*
455
+ * Grid
456
+ */
457
+ class ElasticCarousel extends BaseWidget {
458
+ label = 'ElasticCarousel';
459
+ // Provided
460
+ widgetSettings;
461
+ feedMetadata;
462
+ posts;
463
+ previewLoadingColors = null;
464
+ // Internal
465
+ containerEl;
466
+ headerEl;
467
+ innerEl;
468
+ footerEl;
469
+ instagramLogoEl;
470
+ labelEl;
471
+ leftArrowEl;
472
+ rightArrowEl;
473
+ slidesContainerEl;
474
+ postEls;
475
+ popoverGalleryEl;
476
+ appliedBreakpoint;
477
+ medianPaletteHSL;
478
+ gyre;
479
+ constructor() {
480
+ super();
481
+ // Define which props will trigger _handlePropChange
482
+ this.onPropChange(this._handlePropChange, ['widgetSettings', 'feedMetadata', 'posts', 'previewLoadingColors'], ['widgetSettings', 'feedMetadata', 'posts'], this.setup);
483
+ // Register child components
484
+ ImagePost.register();
485
+ VideoPost.register();
486
+ AlbumPost.register();
487
+ // Create Gyre carousel
488
+ this.gyre = new Gyre({ onSlideChange: (i) => this._handleSlideChange(i) });
489
+ // Bind event handlers
490
+ this._handlePostClick = this._handlePostClick.bind(this);
491
+ // Listen to focus
492
+ this.addEventListener('post-focus-next', this._handleFocusNextPost);
493
+ this.addEventListener('post-focus-previous', this._handleFocusPreviousPost);
494
+ // Connect
495
+ this.onConnect(() => {
496
+ this.slidesContainerEl = createElement({
497
+ classes: 'ec-slides',
498
+ });
499
+ this.headerEl = createElement({
500
+ type: 'header',
501
+ classes: 'ec-header',
502
+ });
503
+ this.innerEl = createElement({
504
+ classes: 'ec-inner',
505
+ contents: [this.slidesContainerEl],
506
+ });
507
+ this.footerEl = createElement({
508
+ type: 'footer',
509
+ classes: 'ec-footer',
510
+ });
511
+ this.labelEl = createElement({
512
+ classes: 'ec-label',
513
+ });
514
+ this.leftArrowEl = createElement({
515
+ type: 'button',
516
+ classes: 'ec-button ec-retreat',
517
+ contents: [caretLeftIcon],
518
+ listeners: {
519
+ click: () => this._retreat(),
520
+ },
521
+ attributes: {
522
+ tabindex: -1,
523
+ disabled: true,
524
+ },
525
+ });
526
+ this.rightArrowEl = createElement({
527
+ type: 'button',
528
+ classes: 'ec-button ec-advance',
529
+ contents: [caretRightIcon],
530
+ listeners: {
531
+ click: () => this._advance(),
532
+ },
533
+ attributes: {
534
+ tabindex: -1,
535
+ },
536
+ });
537
+ this.containerEl = createElement({
538
+ type: 'figure',
539
+ classes: 'ec-carousel',
540
+ contents: [this.innerEl],
541
+ });
542
+ this.renderWidget(this.containerEl, [baseGridStyles, styles]);
543
+ // A11y stuff
544
+ this.setAttribute('tabindex', '0');
545
+ this.setAttribute('aria-label', 'Gallery of Instagram posts. Shift + arrow keys to navigate');
546
+ // listen to resize
547
+ this.onResize(this, this, this._handleResize);
548
+ });
549
+ }
550
+ /*
551
+ * Run initial setup that requires data to be fully loaded
552
+ */
553
+ setup() {
554
+ // Calculate medianPaletteHSL
555
+ if (this.widgetSettings.loadingColor !== 'transparent') {
556
+ const palettes = this.posts
557
+ .filter((post) => post.colorPalette)
558
+ .map((post) => post.colorPalette);
559
+ this.medianPaletteHSL = getMedianHSL(palettes, this.widgetSettings.loadingColor);
560
+ }
561
+ // Find initial breakpoint
562
+ const matchingBreakpoint = this.getMatchingBreakpoint(this.offsetWidth, this.widgetSettings.breakpoints);
563
+ // Render posts with current breakpoint styles
564
+ this.renderBreakpoint(matchingBreakpoint);
565
+ // Add non-breakpoint CSS vars
566
+ setCssVars(this.containerEl, {
567
+ '--ec-icon-color': this.widgetSettings.iconColor,
568
+ '--ec-text-color': this.widgetSettings.textColor,
569
+ '--ec-button-color': this.widgetSettings.buttonColor,
570
+ '--ec-button-hover-color': this.widgetSettings.buttonHoverColor,
571
+ '--ec-button-icon-color': this.widgetSettings.buttonIconColor,
572
+ '--ec-button-icon-hover-color': this.widgetSettings.buttonIconHoverColor,
573
+ });
574
+ // Pass settings and metadata to posts
575
+ if (this.postEls) {
576
+ this.postEls.forEach((postEl) => {
577
+ postEl.widgetSettings = this.widgetSettings;
578
+ postEl.feedMetadata = this.feedMetadata;
579
+ });
580
+ }
581
+ // Build label
582
+ this._buildLabel();
583
+ // Enable popoverGallery if necessary
584
+ if (this.widgetSettings.onPostClick === 'openPopupGallery') {
585
+ this.enablePopoverGallery();
586
+ }
587
+ }
588
+ _buildLabel() {
589
+ const iconTemplate = document.createElement('template');
590
+ iconTemplate.innerHTML = instagramIcon;
591
+ if (this.widgetSettings.label) {
592
+ const customLabelEl = createElement({
593
+ type: this.widgetSettings.labelLink ? 'a' : 'div',
594
+ contents: this.widgetSettings.label,
595
+ attributes: {
596
+ href: this.widgetSettings.labelLink || null,
597
+ target: this.widgetSettings.labelLink ? '_blank' : null,
598
+ },
599
+ });
600
+ this.labelEl.beholdReplaceChildren(iconTemplate.content, customLabelEl);
601
+ }
602
+ else if (this.feedMetadata.hashtags?.length) {
603
+ const hashtags = this.feedMetadata.hashtags;
604
+ const linkEls = hashtags.map((hashtag, i, arr) => {
605
+ return createElement({
606
+ type: 'a',
607
+ contents: ['#', hashtag, i < arr.length - 1 ? ', ' : ''],
608
+ attributes: {
609
+ target: '_blank',
610
+ href: `https://instagram.com/explore/tags/${hashtag}`,
611
+ },
612
+ });
613
+ });
614
+ this.labelEl.beholdReplaceChildren(iconTemplate.content, ...linkEls);
615
+ }
616
+ else {
617
+ const profileLinkEl = createElement({
618
+ type: 'a',
619
+ contents: [this.feedMetadata.username],
620
+ attributes: {
621
+ target: '_blank',
622
+ href: `https://instagram.com/${this.feedMetadata.username}`,
623
+ },
624
+ });
625
+ this.labelEl.beholdReplaceChildren(iconTemplate.content, profileLinkEl);
626
+ }
627
+ }
628
+ /**
629
+ * Handle a slide change
630
+ */
631
+ _handleSlideChange(index) {
632
+ if (index === 0 && this.leftArrowEl) {
633
+ this.leftArrowEl.disabled = true;
634
+ }
635
+ else {
636
+ this.leftArrowEl.disabled = false;
637
+ }
638
+ if (index >= this.gyre.finalAnchorSlide) {
639
+ this.rightArrowEl.disabled = true;
640
+ }
641
+ else {
642
+ this.rightArrowEl.disabled = false;
643
+ }
644
+ }
645
+ /*
646
+ * Handle prop change
647
+ */
648
+ _handlePropChange({ changedProp, oldValue, newValue }) {
649
+ switch (changedProp) {
650
+ case 'posts':
651
+ this._handlePostsChange({ oldValue, newValue });
652
+ break;
653
+ case 'widgetSettings':
654
+ this._handleSettingsChange(oldValue, newValue);
655
+ break;
656
+ case 'feedMetadata':
657
+ this._handleMetadataChange();
658
+ break;
659
+ case 'previewLoadingColors':
660
+ this.postEls.forEach((postEl) => {
661
+ postEl.previewLoadingColors = this.previewLoadingColors;
662
+ });
663
+ setClasses(this, {
664
+ 'is-previewing-loading-colors': !!this.previewLoadingColors,
665
+ });
666
+ break;
667
+ }
668
+ }
669
+ /*
670
+ * Handle posts change
671
+ */
672
+ _handlePostsChange({ oldValue, newValue }) {
673
+ this.postEls = [];
674
+ this.renderBreakpoint(this.getMatchingBreakpoint(this.offsetWidth, this.widgetSettings.breakpoints), true);
675
+ // Pass settings and metadata to posts
676
+ this.postEls.forEach((postEl) => {
677
+ postEl.widgetSettings = this.widgetSettings;
678
+ postEl.feedMetadata = this.feedMetadata;
679
+ });
680
+ if (this.popoverGalleryEl) {
681
+ this.popoverGalleryEl.posts = this.posts;
682
+ }
683
+ }
684
+ /*
685
+ * Handle settings change
686
+ */
687
+ _handleSettingsChange(oldValue, newValue) {
688
+ let forceRender = false;
689
+ if (!this.postEls?.length ||
690
+ hasChanges(oldValue.breakpoints, newValue.breakpoints, ['postHeight'], 1)) {
691
+ forceRender = true;
692
+ }
693
+ setCssVars(this.containerEl, {
694
+ '--ec-icon-color': this.widgetSettings.iconColor,
695
+ '--ec-text-color': this.widgetSettings.textColor,
696
+ '--ec-button-color': this.widgetSettings.buttonColor,
697
+ '--ec-button-hover-color': this.widgetSettings.buttonHoverColor,
698
+ '--ec-button-icon-color': this.widgetSettings.buttonIconColor,
699
+ '--ec-button-icon-hover-color': this.widgetSettings.buttonIconHoverColor,
700
+ });
701
+ if (hasChanges(oldValue, newValue, ['label', 'labelLink'])) {
702
+ this._buildLabel();
703
+ }
704
+ if (oldValue?.onPostClick !== 'openPopupGallery' &&
705
+ newValue?.onPostClick === 'openPopupGallery') {
706
+ this.enablePopoverGallery();
707
+ }
708
+ const matchingBreakpoint = this.getMatchingBreakpoint(this.offsetWidth, this.widgetSettings.breakpoints);
709
+ this.renderBreakpoint(matchingBreakpoint, forceRender);
710
+ this.postEls.forEach((postEl) => {
711
+ postEl.widgetSettings = this.widgetSettings;
712
+ });
713
+ if (this.popoverGalleryEl) {
714
+ this.popoverGalleryEl.widgetSettings = this.widgetSettings;
715
+ }
716
+ }
717
+ /*
718
+ * Handle settings change
719
+ */
720
+ _handleMetadataChange() {
721
+ let description = `from @${this.feedMetadata.username}`;
722
+ if (this.feedMetadata.hashtags?.length) {
723
+ description = `from hashtag${this.feedMetadata.hashtags.length > 1 ? 's' : ''} ${this.feedMetadata.hashtags.join(', ')}`;
724
+ }
725
+ this.setAttribute('aria-label', `Gallery of Instagram posts ${description}. Shift + arrow keys to navigate`);
726
+ this.postEls.forEach((postEl) => {
727
+ postEl.feedMetadata = this.feedMetadata;
728
+ });
729
+ if (this.popoverGalleryEl) {
730
+ this.popoverGalleryEl.feedMetadata = this.feedMetadata;
731
+ }
732
+ }
733
+ /**
734
+ * Enable popup carousel
735
+ */
736
+ async enablePopoverGallery() {
737
+ if (this.popoverGalleryEl)
738
+ return;
739
+ const { default: PopoverGallery } = await import('./PopoverGallery-oswhxqGK.js');
740
+ PopoverGallery.register();
741
+ this.popoverGalleryEl = document.createElement('behold-popover-gallery');
742
+ Object.assign(this.popoverGalleryEl, {
743
+ widgetSettings: this.widgetSettings,
744
+ feedMetadata: this.feedMetadata,
745
+ posts: this.posts,
746
+ closeFocusEl: this,
747
+ onSlideChange: (slideIndex) => {
748
+ this.gyre.goToSlide(slideIndex);
749
+ this.popoverGalleryEl.closeFocusEl = this.postEls[slideIndex];
750
+ },
751
+ });
752
+ }
753
+ /*
754
+ * Handle resize
755
+ */
756
+ _handleResize(entry) {
757
+ const widgetWidth = entry.contentBoxSize?.[0]?.inlineSize;
758
+ const breakpoints = this.widgetSettings.breakpoints;
759
+ const matchingBreakpoint = this.getMatchingBreakpoint(widgetWidth, breakpoints);
760
+ this.renderBreakpoint(matchingBreakpoint);
761
+ }
762
+ /**
763
+ * Handle prev post focus
764
+ */
765
+ _handleFocusPreviousPost() {
766
+ if (!this.postEls.length)
767
+ return;
768
+ let currentFocusIndex = [...this.postEls].indexOf(this.shadow.activeElement?.parentElement);
769
+ if (currentFocusIndex > 0) {
770
+ currentFocusIndex = currentFocusIndex - 1;
771
+ }
772
+ this.postEls[currentFocusIndex].focus();
773
+ this.gyre.goToSlide(currentFocusIndex);
774
+ }
775
+ /**
776
+ * Handle next post focus
777
+ */
778
+ _handleFocusNextPost() {
779
+ if (!this.postEls.length)
780
+ return;
781
+ let currentFocusIndex = [...this.postEls].indexOf(this.shadow.activeElement?.parentElement);
782
+ if (this.gyre.anchorSlide > 0 &&
783
+ currentFocusIndex < this.gyre.anchorSlide) {
784
+ currentFocusIndex = this.gyre.anchorSlide;
785
+ }
786
+ if (currentFocusIndex > -1 && currentFocusIndex < this.postEls.length - 1) {
787
+ currentFocusIndex = currentFocusIndex + 1;
788
+ }
789
+ if (currentFocusIndex < 0) {
790
+ currentFocusIndex = 0;
791
+ }
792
+ this.postEls[currentFocusIndex].focus();
793
+ this.gyre.goToSlide(currentFocusIndex);
794
+ }
795
+ /**
796
+ * Handle post click
797
+ */
798
+ _handlePostClick(post) {
799
+ this.popoverGalleryEl.open(this.postEls.indexOf(post), post);
800
+ }
801
+ /**
802
+ * Advance to next slide
803
+ */
804
+ _advance() {
805
+ if (this.gyre) {
806
+ this.gyre.advance();
807
+ }
808
+ }
809
+ /**
810
+ * Retreat to previous slide
811
+ */
812
+ _retreat() {
813
+ if (this.gyre) {
814
+ this.gyre.retreat();
815
+ }
816
+ }
817
+ /*
818
+ * Update postEls
819
+ */
820
+ renderPosts(breakpoint) {
821
+ this.postEls = this.createPostEls(breakpoint);
822
+ this.raf(() => {
823
+ this.gyre.destroy();
824
+ this.gyre.init({
825
+ containerEl: this.slidesContainerEl,
826
+ slideEls: this.postEls,
827
+ height: breakpoint.postHeight,
828
+ gap: breakpoint.gap.x,
829
+ borderRadius: parseInt(breakpoint.borderRadius),
830
+ applyBorderRadiusToContainer: breakpoint.applyBorderRadiusToContainer || true,
831
+ snapToSlide: breakpoint.snapToSlide || false,
832
+ bindToScrollPos: breakpoint.bindToScrollPos || false,
833
+ });
834
+ }, 'renderPosts');
835
+ }
836
+ /*
837
+ * Get breakpoint that matches a width
838
+ */
839
+ getMatchingBreakpoint(width, breakpoints) {
840
+ return Object.entries(breakpoints)
841
+ .map(([key, value]) => ({ width: key, ...value }))
842
+ .filter((bp) => bp.width !== 'default')
843
+ .sort((a, b) => parseInt(b.width) - parseInt(a.width))
844
+ .reduce((acc, curr) => {
845
+ return width <= parseInt(curr.width) ? curr : acc;
846
+ }, breakpoints.default);
847
+ }
848
+ /*
849
+ * Render posts with breakpoint
850
+ */
851
+ renderBreakpoint(breakpoint, forceRender = false) {
852
+ if (!this.posts || !this.containerEl)
853
+ return;
854
+ const applied = this.appliedBreakpoint;
855
+ const { showControls, controlsPosition, controlsJustification, showLabel, labelPosition, labelJustification, buttonBorderRadius, controlsMargin, } = breakpoint;
856
+ if (!this.postEls?.length ||
857
+ hasChanges(applied, breakpoint, [
858
+ 'numPosts',
859
+ 'forcePostAspectRatio',
860
+ 'postAspectRatio',
861
+ 'postHeight',
862
+ ])) {
863
+ forceRender = true;
864
+ }
865
+ if (this.widgetSettings.maxWidth &&
866
+ this.widgetSettings.constrainWidth &&
867
+ this.containerEl.style.maxWidth !== `${this.widgetSettings.maxWidth}px`) {
868
+ this.containerEl.style.maxWidth = `${this.widgetSettings.maxWidth}px`;
869
+ }
870
+ if (!this.widgetSettings.constrainWidth) {
871
+ this.containerEl.style.maxWidth = '';
872
+ }
873
+ this.leftArrowEl.remove();
874
+ this.rightArrowEl.remove();
875
+ if (hasChanges(applied, breakpoint, [
876
+ 'showControls',
877
+ 'controlsPosition',
878
+ 'controlsJustification',
879
+ 'showLabel',
880
+ 'labelPosition',
881
+ 'labelJustification',
882
+ ]) ||
883
+ (showControls && !this.leftArrowEl.isConnected) ||
884
+ (showLabel && !this.labelEl.isConnected)) {
885
+ this.leftArrowEl.remove();
886
+ this.rightArrowEl.remove();
887
+ this.labelEl.remove();
888
+ this.headerEl.remove();
889
+ this.footerEl.remove();
890
+ setCssVars(this.containerEl, {
891
+ '--ec-button-border-radius': `${buttonBorderRadius}%`,
892
+ '--ec-controls-margin': `${controlsMargin}px`,
893
+ });
894
+ setClasses(this.containerEl, {
895
+ 'ec-carousel--controls-sides': controlsPosition === 'sides',
896
+ 'ec-carousel--controls-left': controlsJustification === 'left',
897
+ 'ec-carousel--controls-right': controlsJustification === 'right',
898
+ 'ec-carousel--controls-center': controlsJustification === 'center',
899
+ 'ec-carousel--controls-split': controlsJustification === 'split',
900
+ 'ec-carousel--label-left': labelJustification === 'left',
901
+ 'ec-carousel--label-right': labelJustification === 'right',
902
+ 'ec-carousel--label-center': labelJustification === 'left',
903
+ });
904
+ // Show label?
905
+ if (showLabel) {
906
+ if (labelPosition === 'top') {
907
+ this.headerEl.append(this.labelEl);
908
+ }
909
+ if (labelPosition === 'bottom') {
910
+ this.footerEl.append(this.labelEl);
911
+ }
912
+ }
913
+ // Set controls container
914
+ let controlsContainerEl = this.innerEl;
915
+ if (controlsPosition === 'top') {
916
+ controlsContainerEl = this.headerEl;
917
+ }
918
+ if (controlsPosition === 'bottom') {
919
+ controlsContainerEl = this.footerEl;
920
+ }
921
+ // Add controls
922
+ if (showControls && controlsPosition === 'sides') {
923
+ controlsContainerEl.prepend(this.leftArrowEl);
924
+ controlsContainerEl.append(this.rightArrowEl);
925
+ }
926
+ else if (showControls) {
927
+ switch (controlsJustification) {
928
+ case 'left':
929
+ controlsContainerEl.prepend(this.rightArrowEl);
930
+ controlsContainerEl.prepend(this.leftArrowEl);
931
+ break;
932
+ case 'right':
933
+ controlsContainerEl.append(this.leftArrowEl);
934
+ controlsContainerEl.append(this.rightArrowEl);
935
+ break;
936
+ default:
937
+ controlsContainerEl.prepend(this.leftArrowEl);
938
+ controlsContainerEl.append(this.rightArrowEl);
939
+ break;
940
+ }
941
+ }
942
+ if (this.headerEl.childElementCount) {
943
+ this.containerEl.prepend(this.headerEl);
944
+ }
945
+ if (this.footerEl.childElementCount) {
946
+ this.containerEl.append(this.footerEl);
947
+ }
948
+ }
949
+ this.containerEl.setAttribute('data-hover-effect', this.widgetSettings.hoverEffect);
950
+ // Then render posts into updated container
951
+ if (forceRender) {
952
+ this.renderPosts(breakpoint);
953
+ }
954
+ else {
955
+ this.gyre.updateSettings({
956
+ height: breakpoint.postHeight,
957
+ gap: breakpoint.gap.x,
958
+ borderRadius: parseInt(breakpoint.borderRadius),
959
+ applyBorderRadiusToContainer: breakpoint.applyBorderRadiusToContainer,
960
+ snapToSlide: breakpoint.snapToSlide,
961
+ bindToScrollPos: breakpoint.bindToScrollPos,
962
+ });
963
+ }
964
+ this.appliedBreakpoint = breakpoint;
965
+ }
966
+ /*
967
+ * Create post Els based on a breakpoint
968
+ */
969
+ createPostEls(breakpoint) {
970
+ const { numPosts, postHeight, postAspectRatio, forcePostAspectRatio } = breakpoint;
971
+ const filteredArray = this.posts.filter((p, i) => {
972
+ const numPosts = breakpoint?.numPosts || this.posts?.length || 12;
973
+ return i < numPosts;
974
+ });
975
+ const postEls = filteredArray.map((post, i) => {
976
+ const naturalAspectRatio = [post.sizes.full.width, post.sizes.full.height];
977
+ const aspectRatioArray = forcePostAspectRatio
978
+ ? postAspectRatio || [1, 1]
979
+ : naturalAspectRatio;
980
+ const aspectRatio = aspectRatioArray.reduce((w, h) => w / h);
981
+ let postType = 'behold-image-post';
982
+ if (post.mediaType === 'VIDEO') {
983
+ postType = 'behold-video-post';
984
+ }
985
+ if (post.mediaType === 'CAROUSEL_ALBUM') {
986
+ postType = 'behold-album-post';
987
+ }
988
+ const postEl = createElement({
989
+ type: postType,
990
+ props: {
991
+ post,
992
+ widgetSettings: this.widgetSettings,
993
+ feedMetadata: this.feedMetadata,
994
+ medianPaletteHSL: this.medianPaletteHSL,
995
+ onClick: this._handlePostClick,
996
+ hasRowGap: true,
997
+ isLastRow: false,
998
+ index: i,
999
+ aspectRatio: aspectRatioArray,
1000
+ totalPosts: filteredArray?.length || numPosts || this.posts?.length || 0,
1001
+ },
1002
+ style: {
1003
+ width: `${postHeight * aspectRatio}px`,
1004
+ '--post-aspect-ratio': aspectRatio,
1005
+ },
1006
+ });
1007
+ return postEl;
1008
+ });
1009
+ while (postEls.length < breakpoint.numPosts) {
1010
+ const placeholderEl = createElement({
1011
+ classes: 'post post--placeholder',
1012
+ style: {
1013
+ width: `${postHeight}px`,
1014
+ '--post-aspect-ratio': 1,
1015
+ },
1016
+ });
1017
+ postEls.push(placeholderEl);
1018
+ }
1019
+ return postEls;
1020
+ }
1021
+ /*
1022
+ * Register
1023
+ */
1024
+ static register(name = 'behold-elastic-carousel') {
1025
+ if (!customElements.get(name)) {
1026
+ customElements.define(name, ElasticCarousel);
1027
+ }
1028
+ return name;
1029
+ }
1030
+ }
1031
+
1032
+ export { ElasticCarousel as default };