@behold/widget 0.5.65 → 0.5.66

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,339 +0,0 @@
1
- import { c as createElement, a as setClasses, f as forceLayout, s as setCssVars } 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
-
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
- // Define which props will trigger _handlePropChange
26
- this.onPropChange(this._handlePropChange, ['widgetSettings', 'feedMetadata', 'posts', 'previewLoadingColors'], ['widgetSettings', 'feedMetadata', 'posts'], this.setup);
27
- // Register child components
28
- ImagePost.register();
29
- VideoPost.register();
30
- AlbumPost.register();
31
- // Bind event handlers
32
- this._handlePostClick = this._handlePostClick.bind(this);
33
- // Listen to focus
34
- this.addEventListener('post-focus-next', this._handleFocusNextPost);
35
- this.addEventListener('post-focus-previous', this._handleFocusPreviousPost);
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-oswhxqGK.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
- const matchingBreakpoint = 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
- return { numPosts: this.posts.length, ...breakpoints.default, ...matchingBreakpoint };
232
- }
233
- /*
234
- * Render posts with breakpoint
235
- */
236
- renderBreakpoint(breakpoint, forceRender = false) {
237
- if (!this.posts || !this.containerEl)
238
- return;
239
- if (!this.postEls?.length)
240
- forceRender = true;
241
- const applied = this.appliedBreakpoint;
242
- const { numColumns, gap, borderRadius, numPosts, postAspectRatio } = breakpoint;
243
- // If we're reducing the # of posts, first remove them all to prevent fouc
244
- if (applied?.numPosts > numPosts) {
245
- this.containerEl.beholdReplaceChildren();
246
- forceLayout();
247
- }
248
- // First apply container styles to prevent FOUC
249
- switch (this.widgetSettings.alignment) {
250
- case 'left':
251
- this.style.justifyContent = 'flex-start';
252
- break;
253
- case 'right':
254
- this.style.justifyContent = 'flex-end';
255
- break;
256
- default:
257
- this.style.justifyContent = 'center';
258
- break;
259
- }
260
- if (this.widgetSettings.maxWidth &&
261
- this.widgetSettings.constrainWidth &&
262
- this.containerEl.style.maxWidth !== `${this.widgetSettings.maxWidth}px`) {
263
- this.containerEl.style.maxWidth = `${this.widgetSettings.maxWidth}px`;
264
- }
265
- if (!this.widgetSettings.constrainWidth) {
266
- this.containerEl.style.maxWidth = '';
267
- }
268
- this.containerEl.style.gridTemplateColumns = `repeat(${numColumns}, 1fr)`;
269
- this.containerEl.style.gap = `${gap.y}px ${gap.x}px`;
270
- this.containerEl.setAttribute('data-hover-effect', this.widgetSettings.hoverEffect);
271
- let aspectRatio = (postAspectRatio || [1, 1]).reduce((w, h) => w / h);
272
- setCssVars(this.containerEl, {
273
- '--post-border-radius': `${borderRadius}%`,
274
- '--post-aspect-ratio': `${aspectRatio}`,
275
- });
276
- // Then render posts into updated container
277
- if (applied?.numPosts !== numPosts || forceRender) {
278
- this.renderPosts(breakpoint);
279
- }
280
- this.postEls.forEach((el, i) => {
281
- el.hasRowGap = `${breakpoint.gap.y}` !== '0';
282
- });
283
- this.appliedBreakpoint = breakpoint;
284
- }
285
- /*
286
- * Create post Els based on a breakpoint
287
- */
288
- createPostEls(breakpoint) {
289
- const { numPosts, numColumns, gap, postAspectRatio } = breakpoint;
290
- const filteredArray = this.posts.filter((p, i) => {
291
- const numPosts = breakpoint?.numPosts || this.posts?.length || 200;
292
- return i < numPosts;
293
- });
294
- const postEls = filteredArray.map((post, i) => {
295
- const numRows = Math.ceil((numPosts || this.posts.length) / numColumns);
296
- let postType = 'behold-image-post';
297
- if (post.mediaType === 'VIDEO') {
298
- postType = 'behold-video-post';
299
- }
300
- if (post.mediaType === 'CAROUSEL_ALBUM') {
301
- postType = 'behold-album-post';
302
- }
303
- const postEl = createElement({
304
- type: postType,
305
- props: {
306
- post,
307
- widgetSettings: this.widgetSettings,
308
- feedMetadata: this.feedMetadata,
309
- medianPaletteHSL: this.medianPaletteHSL,
310
- onClick: this._handlePostClick,
311
- hasRowGap: `${gap.y}` !== '0',
312
- isLastRow: Math.ceil((i + 1) / numColumns) === numRows,
313
- index: i,
314
- aspectRatio: postAspectRatio || [1, 1],
315
- totalPosts: filteredArray?.length || numPosts || this.posts?.length || 0,
316
- },
317
- });
318
- return postEl;
319
- });
320
- while (postEls.length < breakpoint.numPosts) {
321
- const placeholderEl = createElement({
322
- classes: 'post post--placeholder',
323
- });
324
- postEls.push(placeholderEl);
325
- }
326
- return postEls;
327
- }
328
- /*
329
- * Register
330
- */
331
- static register(name = 'behold-grid') {
332
- if (!customElements.get(name)) {
333
- customElements.define(name, Grid);
334
- }
335
- return name;
336
- }
337
- }
338
-
339
- export { Grid as default };