@behold/widget 0.5.57 → 0.5.59

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,338 +0,0 @@
1
- import { c as createElement, a as setClasses, f as forceLayout, s as setCssVars } from './index-R4lEDZFo.js';
2
- import { B as BaseWidget, I as ImagePost, V as VideoPost, A as AlbumPost, b as baseGridStyles, g as getMedianHSL } from './base-GZO73SkY.js';
3
-
4
- var css_248z = ".post--placeholder{background-color:#dedede;height:0;padding-bottom:calc(100%/var(--post-aspect-ratio))}";
5
- var styles = css_248z;
6
-
7
- /*
8
- * Grid
9
- */
10
- class Grid extends BaseWidget {
11
- label = 'Grid';
12
- // Provided
13
- widgetSettings;
14
- feedMetadata;
15
- posts;
16
- previewLoadingColors = null;
17
- // Internal
18
- containerEl;
19
- postEls;
20
- popoverGalleryEl;
21
- appliedBreakpoint;
22
- medianPaletteHSL;
23
- constructor() {
24
- super();
25
- // Register child components
26
- ImagePost.register();
27
- VideoPost.register();
28
- AlbumPost.register();
29
- // Bind event handlers
30
- this._handlePostClick = this._handlePostClick.bind(this);
31
- // Listen to focus
32
- this.addEventListener('post-focus-next', this._handleFocusNextPost);
33
- this.addEventListener('post-focus-previous', this._handleFocusPreviousPost);
34
- // Define which props will trigger _handlePropChange
35
- this.onPropChange(this._handlePropChange, ['widgetSettings', 'feedMetadata', 'posts', 'previewLoadingColors'], ['widgetSettings', 'feedMetadata', 'posts'], this.setup);
36
- // Connect
37
- this.onConnect(() => {
38
- this.containerEl = createElement({
39
- type: 'figure',
40
- classes: 'posts',
41
- });
42
- this.renderWidget(this.containerEl, [baseGridStyles, styles]);
43
- // A11y stuff
44
- this.setAttribute('tabindex', '0');
45
- this.setAttribute('aria-label', 'Gallery of Instagram posts. Shift + arrow keys to navigate');
46
- // listen to resize
47
- this.onResize(this, this, this._handleResize);
48
- });
49
- }
50
- /*
51
- * Run initial setup that requires data to be fully loaded
52
- */
53
- setup() {
54
- // Calculate medianPaletteHSL
55
- if (this.widgetSettings.loadingColor !== 'transparent') {
56
- const palettes = this.posts
57
- .filter((post) => post.colorPalette)
58
- .map((post) => post.colorPalette);
59
- this.medianPaletteHSL = getMedianHSL(palettes, this.widgetSettings.loadingColor);
60
- }
61
- // Find initial breakpoint
62
- const matchingBreakpoint = this.getMatchingBreakpoint(this.offsetWidth, this.widgetSettings.breakpoints);
63
- // Render posts with current breakpoint styles
64
- this.renderBreakpoint(matchingBreakpoint);
65
- // Pass settings and metadata to posts
66
- if (this.postEls) {
67
- this.postEls.forEach((postEl) => {
68
- postEl.widgetSettings = this.widgetSettings;
69
- postEl.feedMetadata = this.feedMetadata;
70
- });
71
- }
72
- // Enable popoverGallery if necessary
73
- if (this.widgetSettings.onPostClick === 'openPopupGallery') {
74
- this.enablePopoverGallery();
75
- }
76
- }
77
- /*
78
- * Handle prop change
79
- */
80
- _handlePropChange({ changedProp, oldValue, newValue }) {
81
- switch (changedProp) {
82
- case 'posts':
83
- this._handlePostsChange({ oldValue, newValue });
84
- break;
85
- case 'widgetSettings':
86
- this._handleSettingsChange(oldValue, newValue);
87
- break;
88
- case 'feedMetadata':
89
- this._handleMetadataChange();
90
- break;
91
- case 'previewLoadingColors':
92
- this.postEls.forEach((postEl) => {
93
- postEl.previewLoadingColors = this.previewLoadingColors;
94
- });
95
- setClasses(this, {
96
- 'is-previewing-loading-colors': !!this.previewLoadingColors,
97
- });
98
- break;
99
- }
100
- }
101
- /*
102
- * Handle posts change
103
- */
104
- _handlePostsChange({ oldValue, newValue }) {
105
- this.postEls = [];
106
- this.renderBreakpoint(this.getMatchingBreakpoint(this.offsetWidth, this.widgetSettings.breakpoints), true);
107
- if (this.popoverGalleryEl) {
108
- this.popoverGalleryEl.posts = this.posts;
109
- }
110
- }
111
- /*
112
- * Handle settings change
113
- */
114
- _handleSettingsChange(oldValue, newValue) {
115
- if (oldValue?.onPostClick !== 'openPopupGallery' &&
116
- newValue?.onPostClick === 'openPopupGallery') {
117
- this.enablePopoverGallery();
118
- }
119
- const matchingBreakpoint = this.getMatchingBreakpoint(this.offsetWidth, this.widgetSettings.breakpoints);
120
- this.renderBreakpoint(matchingBreakpoint);
121
- this.postEls.forEach((postEl) => {
122
- postEl.widgetSettings = this.widgetSettings;
123
- });
124
- if (this.popoverGalleryEl) {
125
- this.popoverGalleryEl.widgetSettings = this.widgetSettings;
126
- }
127
- }
128
- /*
129
- * Handle settings change
130
- */
131
- _handleMetadataChange() {
132
- let description = `from @${this.feedMetadata.username}`;
133
- if (this.feedMetadata.hashtags?.length) {
134
- description = `from hashtag${this.feedMetadata.hashtags.length > 1 ? 's' : ''} ${this.feedMetadata.hashtags.join(', ')}`;
135
- }
136
- this.setAttribute('aria-label', `Gallery of Instagram posts ${description}. Shift + arrow keys to navigate`);
137
- this.postEls.forEach((postEl) => {
138
- postEl.feedMetadata = this.feedMetadata;
139
- });
140
- if (this.popoverGalleryEl) {
141
- this.popoverGalleryEl.feedMetadata = this.feedMetadata;
142
- }
143
- }
144
- /**
145
- * Enable popup carousel
146
- */
147
- async enablePopoverGallery() {
148
- if (this.popoverGalleryEl)
149
- return;
150
- const { default: PopoverGallery } = await import('./PopoverGallery-pssVDO_O.js');
151
- PopoverGallery.register();
152
- this.popoverGalleryEl = document.createElement('behold-popover-gallery');
153
- Object.assign(this.popoverGalleryEl, {
154
- widgetSettings: this.widgetSettings,
155
- feedMetadata: this.feedMetadata,
156
- posts: this.posts,
157
- closeFocusEl: this,
158
- onSlideChange: (slideIndex) => {
159
- this.popoverGalleryEl.closeFocusEl = this.postEls[slideIndex];
160
- },
161
- });
162
- }
163
- /*
164
- * Handle resize
165
- */
166
- _handleResize(entry) {
167
- const widgetWidth = entry.contentBoxSize?.[0]?.inlineSize;
168
- const breakpoints = this.widgetSettings.breakpoints;
169
- const matchingBreakpoint = this.getMatchingBreakpoint(widgetWidth, breakpoints);
170
- this.renderBreakpoint(matchingBreakpoint);
171
- }
172
- /**
173
- * Handle prev post focus
174
- */
175
- _handleFocusPreviousPost() {
176
- if (!this.postEls.length)
177
- return;
178
- let currentFocusIndex = [...this.containerEl.children].indexOf(this.shadow.activeElement?.parentElement);
179
- if (currentFocusIndex > 0) {
180
- currentFocusIndex = currentFocusIndex - 1;
181
- }
182
- else {
183
- currentFocusIndex = this.postEls.length - 1;
184
- }
185
- this.postEls[currentFocusIndex].focus();
186
- }
187
- /**
188
- * Handle next post focus
189
- */
190
- _handleFocusNextPost() {
191
- if (!this.postEls.length)
192
- return;
193
- let currentFocusIndex = [...this.containerEl.children].indexOf(this.shadow.activeElement?.parentElement);
194
- if (currentFocusIndex > -1 && currentFocusIndex < this.postEls.length - 1) {
195
- currentFocusIndex = currentFocusIndex + 1;
196
- }
197
- else {
198
- currentFocusIndex = 0;
199
- }
200
- this.postEls[currentFocusIndex].focus();
201
- }
202
- /**
203
- * Handle post click
204
- */
205
- _handlePostClick(post) {
206
- this.popoverGalleryEl.open(this.postEls.indexOf(post), post);
207
- }
208
- /*
209
- * Update postEls
210
- */
211
- renderPosts(breakpoint) {
212
- this.postEls = this.createPostEls(breakpoint);
213
- this.raf(() => {
214
- this.containerEl.beholdReplaceChildren(...this.postEls);
215
- }, 'renderPosts');
216
- }
217
- /*
218
- * Get breakpoint that matches a width
219
- */
220
- getMatchingBreakpoint(width, breakpoints) {
221
- return Object.entries(breakpoints)
222
- .map(([key, value]) => ({ width: key, ...value }))
223
- .filter((bp) => bp.width !== 'default')
224
- .sort((a, b) => parseInt(b.width) - parseInt(a.width))
225
- .reduce((acc, curr) => {
226
- return width <= parseInt(curr.width) ? curr : acc;
227
- },
228
- // numPosts doesn't exist on default breakpoint for some reason
229
- // @todo fix that
230
- { numPosts: this.posts.length, ...breakpoints.default });
231
- }
232
- /*
233
- * Render posts with breakpoint
234
- */
235
- renderBreakpoint(breakpoint, forceRender = false) {
236
- if (!this.posts || !this.containerEl)
237
- return;
238
- if (!this.postEls?.length)
239
- forceRender = true;
240
- const applied = this.appliedBreakpoint;
241
- const { numColumns, gap, borderRadius, numPosts, postAspectRatio } = breakpoint;
242
- // If we're reducing the # of posts, first remove them all to prevent fouc
243
- if (applied?.numPosts > numPosts) {
244
- this.containerEl.beholdReplaceChildren();
245
- forceLayout();
246
- }
247
- // First apply container styles to prevent FOUC
248
- switch (this.widgetSettings.alignment) {
249
- case 'left':
250
- this.style.justifyContent = 'flex-start';
251
- break;
252
- case 'right':
253
- this.style.justifyContent = 'flex-end';
254
- break;
255
- default:
256
- this.style.justifyContent = 'center';
257
- break;
258
- }
259
- if (this.widgetSettings.maxWidth &&
260
- this.widgetSettings.constrainWidth &&
261
- this.containerEl.style.maxWidth !== `${this.widgetSettings.maxWidth}px`) {
262
- this.containerEl.style.maxWidth = `${this.widgetSettings.maxWidth}px`;
263
- }
264
- if (!this.widgetSettings.constrainWidth) {
265
- this.containerEl.style.maxWidth = '';
266
- }
267
- this.containerEl.style.gridTemplateColumns = `repeat(${numColumns}, 1fr)`;
268
- this.containerEl.style.gap = `${gap.y}px ${gap.x}px`;
269
- this.containerEl.setAttribute('data-hover-effect', this.widgetSettings.hoverEffect);
270
- let aspectRatio = (postAspectRatio || [1, 1]).reduce((w, h) => w / h);
271
- setCssVars(this.containerEl, {
272
- '--post-border-radius': `${borderRadius}%`,
273
- '--post-aspect-ratio': `${aspectRatio}`,
274
- });
275
- // Then render posts into updated container
276
- if (applied?.numPosts !== numPosts || forceRender) {
277
- this.renderPosts(breakpoint);
278
- }
279
- this.postEls.forEach((el, i) => {
280
- el.hasRowGap = `${breakpoint.gap.y}` !== '0';
281
- });
282
- this.appliedBreakpoint = breakpoint;
283
- }
284
- /*
285
- * Create post Els based on a breakpoint
286
- */
287
- createPostEls(breakpoint) {
288
- const { numPosts, numColumns, gap, postAspectRatio } = breakpoint;
289
- const filteredArray = this.posts.filter((p, i) => {
290
- const numPosts = breakpoint?.numPosts || this.posts?.length || 200;
291
- return i < numPosts;
292
- });
293
- const postEls = filteredArray.map((post, i) => {
294
- const numRows = Math.ceil((numPosts || this.posts.length) / numColumns);
295
- let postType = 'behold-image-post';
296
- if (post.mediaType === 'VIDEO') {
297
- postType = 'behold-video-post';
298
- }
299
- if (post.mediaType === 'CAROUSEL_ALBUM') {
300
- postType = 'behold-album-post';
301
- }
302
- const postEl = createElement({
303
- type: postType,
304
- props: {
305
- post,
306
- widgetSettings: this.widgetSettings,
307
- feedMetadata: this.feedMetadata,
308
- medianPaletteHSL: this.medianPaletteHSL,
309
- onClick: this._handlePostClick,
310
- hasRowGap: `${gap.y}` !== '0',
311
- isLastRow: Math.ceil((i + 1) / numColumns) === numRows,
312
- index: i,
313
- aspectRatio: postAspectRatio || [1, 1],
314
- totalPosts: filteredArray?.length || numPosts || this.posts?.length || 0,
315
- },
316
- });
317
- return postEl;
318
- });
319
- while (postEls.length < breakpoint.numPosts) {
320
- const placeholderEl = createElement({
321
- classes: 'post post--placeholder',
322
- });
323
- postEls.push(placeholderEl);
324
- }
325
- return postEls;
326
- }
327
- /*
328
- * Register
329
- */
330
- static register(name = 'behold-grid') {
331
- if (!customElements.get(name)) {
332
- customElements.define(name, Grid);
333
- }
334
- return name;
335
- }
336
- }
337
-
338
- export { Grid as default };