vue-datocms 3.0.3 → 4.0.1
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/index.cjs.js +107 -45
- package/dist/index.d.ts +79 -6
- package/dist/index.esm.mjs +108 -46
- package/package.json +10 -1
package/dist/index.cjs.js
CHANGED
|
@@ -190,6 +190,36 @@ const imageShowStrategy = ({ lazyLoad, loaded }) => {
|
|
|
190
190
|
}
|
|
191
191
|
return true;
|
|
192
192
|
};
|
|
193
|
+
const buildSrcSet = (src, width, candidateMultipliers) => {
|
|
194
|
+
if (!src || !width) {
|
|
195
|
+
return void 0;
|
|
196
|
+
}
|
|
197
|
+
return candidateMultipliers.map((multiplier) => {
|
|
198
|
+
const url = new URL(src);
|
|
199
|
+
if (multiplier !== 1) {
|
|
200
|
+
url.searchParams.set("dpr", `${multiplier}`);
|
|
201
|
+
const maxH = url.searchParams.get("max-h");
|
|
202
|
+
const maxW = url.searchParams.get("max-w");
|
|
203
|
+
if (maxH) {
|
|
204
|
+
url.searchParams.set(
|
|
205
|
+
"max-h",
|
|
206
|
+
`${Math.floor(parseInt(maxH) * multiplier)}`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
if (maxW) {
|
|
210
|
+
url.searchParams.set(
|
|
211
|
+
"max-w",
|
|
212
|
+
`${Math.floor(parseInt(maxW) * multiplier)}`
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const finalWidth = Math.floor(width * multiplier);
|
|
217
|
+
if (finalWidth < 50) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
return `${url.toString()} ${finalWidth}w`;
|
|
221
|
+
}).filter(Boolean).join(",");
|
|
222
|
+
};
|
|
193
223
|
const Image = vueDemi.defineComponent({
|
|
194
224
|
name: "DatocmsImage",
|
|
195
225
|
props: {
|
|
@@ -239,6 +269,24 @@ const Image = vueDemi.defineComponent({
|
|
|
239
269
|
},
|
|
240
270
|
objectPosition: {
|
|
241
271
|
type: String
|
|
272
|
+
},
|
|
273
|
+
usePlaceholder: {
|
|
274
|
+
type: Boolean,
|
|
275
|
+
default: true
|
|
276
|
+
},
|
|
277
|
+
sizes: {
|
|
278
|
+
type: String
|
|
279
|
+
},
|
|
280
|
+
priority: {
|
|
281
|
+
type: Boolean,
|
|
282
|
+
default: false
|
|
283
|
+
},
|
|
284
|
+
srcSetCandidates: {
|
|
285
|
+
type: Array,
|
|
286
|
+
validator: (values) => values.every((value) => {
|
|
287
|
+
return typeof value === "number";
|
|
288
|
+
}),
|
|
289
|
+
default: () => [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4]
|
|
242
290
|
}
|
|
243
291
|
},
|
|
244
292
|
setup(props) {
|
|
@@ -250,21 +298,33 @@ const Image = vueDemi.defineComponent({
|
|
|
250
298
|
threshold: props.intersectionThreshold || props.intersectionTreshold || 0,
|
|
251
299
|
rootMargin: props.intersectionMargin || "0px 0px 0px 0px"
|
|
252
300
|
});
|
|
301
|
+
const computedLazyLoad = vueDemi.ref(props.priority ? false : props.lazyLoad);
|
|
302
|
+
const imageRef = vueDemi.ref();
|
|
303
|
+
vueDemi.watchEffect(() => {
|
|
304
|
+
if (!imageRef.value) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (imageRef.value.complete && imageRef.value.naturalWidth) {
|
|
308
|
+
handleLoad();
|
|
309
|
+
}
|
|
310
|
+
});
|
|
253
311
|
return {
|
|
254
312
|
inView,
|
|
255
313
|
elRef,
|
|
256
314
|
loaded,
|
|
257
|
-
handleLoad
|
|
315
|
+
handleLoad,
|
|
316
|
+
computedLazyLoad,
|
|
317
|
+
imageRef
|
|
258
318
|
};
|
|
259
319
|
},
|
|
260
320
|
render() {
|
|
261
321
|
const addImage = imageAddStrategy({
|
|
262
|
-
lazyLoad: this.
|
|
322
|
+
lazyLoad: this.computedLazyLoad,
|
|
263
323
|
inView: this.inView,
|
|
264
324
|
loaded: this.loaded
|
|
265
325
|
});
|
|
266
326
|
const showImage = imageShowStrategy({
|
|
267
|
-
lazyLoad: this.
|
|
327
|
+
lazyLoad: this.computedLazyLoad,
|
|
268
328
|
inView: this.inView,
|
|
269
329
|
loaded: this.loaded
|
|
270
330
|
});
|
|
@@ -272,30 +332,30 @@ const Image = vueDemi.defineComponent({
|
|
|
272
332
|
...vueDemi.isVue2 && {
|
|
273
333
|
props: {
|
|
274
334
|
srcset: this.data.webpSrcSet,
|
|
275
|
-
sizes: this.data.sizes,
|
|
335
|
+
sizes: this.sizes ?? this.data.sizes ?? void 0,
|
|
276
336
|
type: "image/webp"
|
|
277
337
|
}
|
|
278
338
|
},
|
|
279
339
|
...vueDemi.isVue3 && {
|
|
280
340
|
srcset: this.data.webpSrcSet,
|
|
281
|
-
sizes: this.data.sizes,
|
|
341
|
+
sizes: this.sizes ?? this.data.sizes ?? void 0,
|
|
282
342
|
type: "image/webp"
|
|
283
343
|
}
|
|
284
344
|
});
|
|
285
345
|
const regularSource = this.data.srcSet && vueDemi.h(Source, {
|
|
286
346
|
...vueDemi.isVue2 && {
|
|
287
347
|
props: {
|
|
288
|
-
srcset: this.data.srcSet,
|
|
289
|
-
sizes: this.data.sizes
|
|
348
|
+
srcset: this.data.srcSet ?? buildSrcSet(this.data.src, this.data.width, this.srcSetCandidates),
|
|
349
|
+
sizes: this.sizes ?? this.data.sizes ?? void 0
|
|
290
350
|
}
|
|
291
351
|
},
|
|
292
352
|
...vueDemi.isVue3 && {
|
|
293
|
-
srcset: this.data.srcSet,
|
|
294
|
-
sizes: this.data.sizes
|
|
353
|
+
srcset: this.data.srcSet ?? buildSrcSet(this.data.src, this.data.width, this.srcSetCandidates),
|
|
354
|
+
sizes: this.sizes ?? this.data.sizes ?? void 0
|
|
295
355
|
}
|
|
296
356
|
});
|
|
297
357
|
const transition = typeof this.fadeInDuration === "undefined" || this.fadeInDuration > 0 ? `opacity ${this.fadeInDuration || 500}ms ${this.fadeInDuration || 500}ms` : void 0;
|
|
298
|
-
const placeholder = vueDemi.h("div", {
|
|
358
|
+
const placeholder = this.usePlaceholder && (this.data.bgColor || this.data.base64) ? vueDemi.h("div", {
|
|
299
359
|
style: {
|
|
300
360
|
backgroundImage: this.data.base64 ? `url(${this.data.base64})` : null,
|
|
301
361
|
backgroundColor: this.data.bgColor,
|
|
@@ -304,11 +364,15 @@ const Image = vueDemi.defineComponent({
|
|
|
304
364
|
objectFit: this.objectFit,
|
|
305
365
|
objectPosition: this.objectPosition,
|
|
306
366
|
transition,
|
|
307
|
-
|
|
367
|
+
position: "absolute",
|
|
368
|
+
left: "-5%",
|
|
369
|
+
top: "-5%",
|
|
370
|
+
width: "110%",
|
|
371
|
+
height: "110%"
|
|
308
372
|
}
|
|
309
|
-
});
|
|
373
|
+
}) : null;
|
|
310
374
|
const { width, aspectRatio } = this.data;
|
|
311
|
-
const height = this.data.height
|
|
375
|
+
const height = this.data.height ?? (aspectRatio ? width / aspectRatio : 0);
|
|
312
376
|
const sizer = this.layout !== "fill" ? vueDemi.h(Sizer, {
|
|
313
377
|
...vueDemi.isVue2 && {
|
|
314
378
|
props: {
|
|
@@ -349,7 +413,8 @@ const Image = vueDemi.defineComponent({
|
|
|
349
413
|
attrs: {
|
|
350
414
|
src: this.data.src,
|
|
351
415
|
alt: this.data.alt,
|
|
352
|
-
title: this.data.title
|
|
416
|
+
title: this.data.title,
|
|
417
|
+
fetchpriority: this.priority ? "high" : void 0
|
|
353
418
|
},
|
|
354
419
|
on: {
|
|
355
420
|
load: this.handleLoad
|
|
@@ -359,16 +424,18 @@ const Image = vueDemi.defineComponent({
|
|
|
359
424
|
src: this.data.src,
|
|
360
425
|
alt: this.data.alt,
|
|
361
426
|
title: this.data.title,
|
|
427
|
+
fetchpriority: this.priority ? "high" : void 0,
|
|
362
428
|
onLoad: this.handleLoad
|
|
363
429
|
},
|
|
430
|
+
ref: "imageRef",
|
|
364
431
|
class: this.pictureClass,
|
|
365
432
|
style: {
|
|
366
|
-
...absolutePositioning,
|
|
367
|
-
...this.pictureStyle,
|
|
368
433
|
opacity: showImage ? 1 : 0,
|
|
369
434
|
transition,
|
|
435
|
+
...absolutePositioning,
|
|
370
436
|
objectFit: this.objectFit,
|
|
371
|
-
objectPosition: this.objectPosition
|
|
437
|
+
objectPosition: this.objectPosition,
|
|
438
|
+
...this.pictureStyle
|
|
372
439
|
}
|
|
373
440
|
})
|
|
374
441
|
]),
|
|
@@ -390,8 +457,14 @@ const Image = vueDemi.defineComponent({
|
|
|
390
457
|
alt: this.data.alt,
|
|
391
458
|
title: this.data.title,
|
|
392
459
|
class: this.pictureClass,
|
|
393
|
-
style: toCss({
|
|
394
|
-
|
|
460
|
+
style: toCss({
|
|
461
|
+
...absolutePositioning,
|
|
462
|
+
objectFit: this.objectFit,
|
|
463
|
+
objectPosition: this.objectPosition,
|
|
464
|
+
...this.pictureStyle
|
|
465
|
+
}),
|
|
466
|
+
loading: this.computedLazyLoad ? "lazy" : void 0,
|
|
467
|
+
fetchpriority: this.priority ? "high" : void 0
|
|
395
468
|
})
|
|
396
469
|
])
|
|
397
470
|
}
|
|
@@ -413,7 +486,8 @@ const Image = vueDemi.defineComponent({
|
|
|
413
486
|
title: this.data.title,
|
|
414
487
|
class: this.pictureClass,
|
|
415
488
|
style: toCss({ ...this.pictureStyle, ...absolutePositioning }),
|
|
416
|
-
loading: "lazy"
|
|
489
|
+
loading: this.computedLazyLoad ? "lazy" : void 0,
|
|
490
|
+
fetchpriority: this.priority ? "high" : void 0
|
|
417
491
|
})
|
|
418
492
|
])
|
|
419
493
|
}
|
|
@@ -589,46 +663,34 @@ const DatocmsStructuredTextPlugin = {
|
|
|
589
663
|
}
|
|
590
664
|
};
|
|
591
665
|
|
|
592
|
-
|
|
593
|
-
const { enabled, initialData, ...other } = options;
|
|
666
|
+
const useQuerySubscription = ({ enabled = true, initialData, query, token, ...other }) => {
|
|
594
667
|
const error = vueDemi.ref(null);
|
|
595
|
-
const data = vueDemi.ref(null);
|
|
596
|
-
const status = vueDemi.ref(
|
|
597
|
-
enabled ? "connecting" : "closed"
|
|
598
|
-
);
|
|
668
|
+
const data = vueDemi.ref(vueDemi.unref(initialData) || null);
|
|
669
|
+
const status = vueDemi.ref(vueDemi.unref(enabled) ? "connecting" : "closed");
|
|
599
670
|
const subscribeToQueryOptions = other;
|
|
600
|
-
vueDemi.watchEffect((onCleanup) => {
|
|
601
|
-
if (
|
|
602
|
-
|
|
603
|
-
return () => {
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
let unsubscribe;
|
|
607
|
-
async function subscribe() {
|
|
608
|
-
unsubscribe = await datocmsListen.subscribeToQuery({
|
|
671
|
+
vueDemi.watchEffect(async (onCleanup) => {
|
|
672
|
+
if (query && token && vueDemi.unref(enabled)) {
|
|
673
|
+
const unsubscribe = await datocmsListen.subscribeToQuery({
|
|
609
674
|
...subscribeToQueryOptions,
|
|
675
|
+
query,
|
|
676
|
+
token,
|
|
610
677
|
onStatusChange: (connectionStatus) => {
|
|
611
678
|
status.value = connectionStatus;
|
|
612
679
|
},
|
|
613
|
-
onUpdate: (
|
|
680
|
+
onUpdate: ({ response }) => {
|
|
614
681
|
error.value = null;
|
|
615
|
-
data.value =
|
|
682
|
+
data.value = response.data;
|
|
616
683
|
},
|
|
617
684
|
onChannelError: (errorData) => {
|
|
618
685
|
data.value = null;
|
|
619
686
|
error.value = errorData;
|
|
620
687
|
}
|
|
621
688
|
});
|
|
689
|
+
onCleanup(unsubscribe);
|
|
622
690
|
}
|
|
623
|
-
subscribe();
|
|
624
|
-
onCleanup(() => {
|
|
625
|
-
if (unsubscribe) {
|
|
626
|
-
unsubscribe();
|
|
627
|
-
}
|
|
628
|
-
});
|
|
629
691
|
});
|
|
630
|
-
return {
|
|
631
|
-
}
|
|
692
|
+
return { data, status, error };
|
|
693
|
+
};
|
|
632
694
|
|
|
633
695
|
const highlightPieces = (textWithHighlightMarker) => {
|
|
634
696
|
return textWithHighlightMarker.split(/\[h\](.+?)\[\/h\]/g).map((text, index) => ({
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { Options, ConnectionStatus } from 'datocms-listen';
|
|
|
8
8
|
|
|
9
9
|
declare type ResponsiveImageType = {
|
|
10
10
|
/** The aspect ratio (width/height) of the image */
|
|
11
|
-
aspectRatio
|
|
11
|
+
aspectRatio?: number;
|
|
12
12
|
/** A base64-encoded thumbnail to offer during image loading */
|
|
13
13
|
base64?: string;
|
|
14
14
|
/** The height of the image */
|
|
@@ -100,11 +100,47 @@ declare const Image: vue_demi.DefineComponent<{
|
|
|
100
100
|
objectPosition: {
|
|
101
101
|
type: StringConstructor;
|
|
102
102
|
};
|
|
103
|
+
/** Whether the component should use a blurred image placeholder */
|
|
104
|
+
usePlaceholder: {
|
|
105
|
+
type: BooleanConstructor;
|
|
106
|
+
default: boolean;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* The HTML5 `sizes` attribute for the image
|
|
110
|
+
*
|
|
111
|
+
* Learn more about srcset and sizes:
|
|
112
|
+
* -> https://web.dev/learn/design/responsive-images/#sizes
|
|
113
|
+
* -> https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
|
|
114
|
+
**/
|
|
115
|
+
sizes: {
|
|
116
|
+
type: StringConstructor;
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* When true, the image will be considered high priority. Lazy loading is automatically disabled, and fetchpriority="high" is added to the image.
|
|
120
|
+
* You should use the priority property on any image detected as the Largest Contentful Paint (LCP) element. It may be appropriate to have multiple priority images, as different images may be the LCP element for different viewport sizes.
|
|
121
|
+
* Should only be used when the image is visible above the fold.
|
|
122
|
+
**/
|
|
123
|
+
priority: {
|
|
124
|
+
type: BooleanConstructor;
|
|
125
|
+
default: boolean;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* If `data` does not contain `srcSet`, the candidates for the `srcset` of the image will be auto-generated based on these width multipliers
|
|
129
|
+
*
|
|
130
|
+
* Default candidate multipliers are [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4]
|
|
131
|
+
**/
|
|
132
|
+
srcSetCandidates: {
|
|
133
|
+
type: ArrayConstructor;
|
|
134
|
+
validator: (values: any[]) => values is number[];
|
|
135
|
+
default: () => number[];
|
|
136
|
+
};
|
|
103
137
|
}, {
|
|
104
138
|
inView: vue_demi.Ref<boolean>;
|
|
105
139
|
elRef: vue_demi.Ref<HTMLElement | null>;
|
|
106
140
|
loaded: vue_demi.Ref<boolean>;
|
|
107
141
|
handleLoad: () => void;
|
|
142
|
+
computedLazyLoad: vue_demi.Ref<boolean>;
|
|
143
|
+
imageRef: vue_demi.Ref<HTMLImageElement | undefined>;
|
|
108
144
|
}, unknown, {}, {}, vue_demi.ComponentOptionsMixin, vue_demi.ComponentOptionsMixin, {}, string, vue_demi.VNodeProps & vue_demi.AllowedComponentProps & vue_demi.ComponentCustomProps, Readonly<vue_demi.ExtractPropTypes<{
|
|
109
145
|
/** The actual response you get from a DatoCMS `responsiveImage` GraphQL query */
|
|
110
146
|
data: {
|
|
@@ -175,6 +211,40 @@ declare const Image: vue_demi.DefineComponent<{
|
|
|
175
211
|
objectPosition: {
|
|
176
212
|
type: StringConstructor;
|
|
177
213
|
};
|
|
214
|
+
/** Whether the component should use a blurred image placeholder */
|
|
215
|
+
usePlaceholder: {
|
|
216
|
+
type: BooleanConstructor;
|
|
217
|
+
default: boolean;
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* The HTML5 `sizes` attribute for the image
|
|
221
|
+
*
|
|
222
|
+
* Learn more about srcset and sizes:
|
|
223
|
+
* -> https://web.dev/learn/design/responsive-images/#sizes
|
|
224
|
+
* -> https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
|
|
225
|
+
**/
|
|
226
|
+
sizes: {
|
|
227
|
+
type: StringConstructor;
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* When true, the image will be considered high priority. Lazy loading is automatically disabled, and fetchpriority="high" is added to the image.
|
|
231
|
+
* You should use the priority property on any image detected as the Largest Contentful Paint (LCP) element. It may be appropriate to have multiple priority images, as different images may be the LCP element for different viewport sizes.
|
|
232
|
+
* Should only be used when the image is visible above the fold.
|
|
233
|
+
**/
|
|
234
|
+
priority: {
|
|
235
|
+
type: BooleanConstructor;
|
|
236
|
+
default: boolean;
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* If `data` does not contain `srcSet`, the candidates for the `srcset` of the image will be auto-generated based on these width multipliers
|
|
240
|
+
*
|
|
241
|
+
* Default candidate multipliers are [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4]
|
|
242
|
+
**/
|
|
243
|
+
srcSetCandidates: {
|
|
244
|
+
type: ArrayConstructor;
|
|
245
|
+
validator: (values: any[]) => values is number[];
|
|
246
|
+
default: () => number[];
|
|
247
|
+
};
|
|
178
248
|
}>>, {
|
|
179
249
|
explicitWidth: boolean;
|
|
180
250
|
lazyLoad: boolean;
|
|
@@ -183,6 +253,9 @@ declare const Image: vue_demi.DefineComponent<{
|
|
|
183
253
|
rootStyle: Record<string, any>;
|
|
184
254
|
pictureStyle: Record<string, any>;
|
|
185
255
|
layout: string;
|
|
256
|
+
usePlaceholder: boolean;
|
|
257
|
+
priority: boolean;
|
|
258
|
+
srcSetCandidates: unknown[];
|
|
186
259
|
}>;
|
|
187
260
|
declare const DatocmsImagePlugin: {
|
|
188
261
|
install: (Vue: any) => void;
|
|
@@ -308,26 +381,26 @@ declare const DatocmsStructuredTextPlugin: {
|
|
|
308
381
|
declare type SubscribeToQueryOptions<QueryResult, QueryVariables> = Omit<Options<QueryResult, QueryVariables>, 'onStatusChange' | 'onUpdate' | 'onChannelError'>;
|
|
309
382
|
declare type EnabledQueryListenerOptions<QueryResult, QueryVariables> = {
|
|
310
383
|
/** Whether the subscription has to be performed or not */
|
|
311
|
-
enabled?: true
|
|
384
|
+
enabled?: true | Ref<boolean>;
|
|
312
385
|
/** The initial data to use while the initial request is being performed */
|
|
313
386
|
initialData?: QueryResult;
|
|
314
387
|
} & SubscribeToQueryOptions<QueryResult, QueryVariables>;
|
|
315
388
|
declare type DisabledQueryListenerOptions<QueryResult, QueryVariables> = {
|
|
316
389
|
/** Whether the subscription has to be performed or not */
|
|
317
|
-
enabled: false
|
|
390
|
+
enabled: false | Ref<boolean>;
|
|
318
391
|
/** The initial data to use while the initial request is being performed */
|
|
319
392
|
initialData?: QueryResult;
|
|
320
393
|
} & Partial<SubscribeToQueryOptions<QueryResult, QueryVariables>>;
|
|
321
394
|
declare type QueryListenerOptions<QueryResult, QueryVariables> = EnabledQueryListenerOptions<QueryResult, QueryVariables> | DisabledQueryListenerOptions<QueryResult, QueryVariables>;
|
|
322
|
-
declare
|
|
395
|
+
declare const useQuerySubscription: <QueryResult = any, QueryVariables = Record<string, any>>({ enabled, initialData, query, token, ...other }: QueryListenerOptions<QueryResult, QueryVariables>) => {
|
|
396
|
+
data: Ref<vue_demi.UnwrapRef<NonNullable<QueryResult>> | null>;
|
|
397
|
+
status: Ref<ConnectionStatus>;
|
|
323
398
|
error: Ref<{
|
|
324
399
|
code: string;
|
|
325
400
|
message: string;
|
|
326
401
|
fatal: boolean;
|
|
327
402
|
response?: any;
|
|
328
403
|
} | null>;
|
|
329
|
-
status: Ref<ConnectionStatus>;
|
|
330
|
-
data: Ref<QueryResult | null>;
|
|
331
404
|
};
|
|
332
405
|
|
|
333
406
|
declare type SearchResultInstancesHrefSchema = {
|
package/dist/index.esm.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import hypenateStyleName from 'hyphenate-style-name';
|
|
2
|
-
import { ref, onMounted, onBeforeUnmount, defineComponent, h, isVue2, isVue3, watchEffect, reactive, computed, toRaw } from 'vue-demi';
|
|
2
|
+
import { ref, onMounted, onBeforeUnmount, defineComponent, h, isVue2, isVue3, watchEffect, unref, reactive, computed, toRaw } from 'vue-demi';
|
|
3
3
|
import { render, renderNodeRule, defaultMetaTransformer } from 'datocms-structured-text-generic-html-renderer';
|
|
4
4
|
export { renderMarkRule, renderNodeRule, renderNodeRule as renderRule } from 'datocms-structured-text-generic-html-renderer';
|
|
5
5
|
import { isRoot, isInlineItem, RenderError, isStructuredText, isItemLink, isBlock } from 'datocms-structured-text-utils';
|
|
@@ -184,6 +184,36 @@ const imageShowStrategy = ({ lazyLoad, loaded }) => {
|
|
|
184
184
|
}
|
|
185
185
|
return true;
|
|
186
186
|
};
|
|
187
|
+
const buildSrcSet = (src, width, candidateMultipliers) => {
|
|
188
|
+
if (!src || !width) {
|
|
189
|
+
return void 0;
|
|
190
|
+
}
|
|
191
|
+
return candidateMultipliers.map((multiplier) => {
|
|
192
|
+
const url = new URL(src);
|
|
193
|
+
if (multiplier !== 1) {
|
|
194
|
+
url.searchParams.set("dpr", `${multiplier}`);
|
|
195
|
+
const maxH = url.searchParams.get("max-h");
|
|
196
|
+
const maxW = url.searchParams.get("max-w");
|
|
197
|
+
if (maxH) {
|
|
198
|
+
url.searchParams.set(
|
|
199
|
+
"max-h",
|
|
200
|
+
`${Math.floor(parseInt(maxH) * multiplier)}`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (maxW) {
|
|
204
|
+
url.searchParams.set(
|
|
205
|
+
"max-w",
|
|
206
|
+
`${Math.floor(parseInt(maxW) * multiplier)}`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const finalWidth = Math.floor(width * multiplier);
|
|
211
|
+
if (finalWidth < 50) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
return `${url.toString()} ${finalWidth}w`;
|
|
215
|
+
}).filter(Boolean).join(",");
|
|
216
|
+
};
|
|
187
217
|
const Image = defineComponent({
|
|
188
218
|
name: "DatocmsImage",
|
|
189
219
|
props: {
|
|
@@ -233,6 +263,24 @@ const Image = defineComponent({
|
|
|
233
263
|
},
|
|
234
264
|
objectPosition: {
|
|
235
265
|
type: String
|
|
266
|
+
},
|
|
267
|
+
usePlaceholder: {
|
|
268
|
+
type: Boolean,
|
|
269
|
+
default: true
|
|
270
|
+
},
|
|
271
|
+
sizes: {
|
|
272
|
+
type: String
|
|
273
|
+
},
|
|
274
|
+
priority: {
|
|
275
|
+
type: Boolean,
|
|
276
|
+
default: false
|
|
277
|
+
},
|
|
278
|
+
srcSetCandidates: {
|
|
279
|
+
type: Array,
|
|
280
|
+
validator: (values) => values.every((value) => {
|
|
281
|
+
return typeof value === "number";
|
|
282
|
+
}),
|
|
283
|
+
default: () => [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4]
|
|
236
284
|
}
|
|
237
285
|
},
|
|
238
286
|
setup(props) {
|
|
@@ -244,21 +292,33 @@ const Image = defineComponent({
|
|
|
244
292
|
threshold: props.intersectionThreshold || props.intersectionTreshold || 0,
|
|
245
293
|
rootMargin: props.intersectionMargin || "0px 0px 0px 0px"
|
|
246
294
|
});
|
|
295
|
+
const computedLazyLoad = ref(props.priority ? false : props.lazyLoad);
|
|
296
|
+
const imageRef = ref();
|
|
297
|
+
watchEffect(() => {
|
|
298
|
+
if (!imageRef.value) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (imageRef.value.complete && imageRef.value.naturalWidth) {
|
|
302
|
+
handleLoad();
|
|
303
|
+
}
|
|
304
|
+
});
|
|
247
305
|
return {
|
|
248
306
|
inView,
|
|
249
307
|
elRef,
|
|
250
308
|
loaded,
|
|
251
|
-
handleLoad
|
|
309
|
+
handleLoad,
|
|
310
|
+
computedLazyLoad,
|
|
311
|
+
imageRef
|
|
252
312
|
};
|
|
253
313
|
},
|
|
254
314
|
render() {
|
|
255
315
|
const addImage = imageAddStrategy({
|
|
256
|
-
lazyLoad: this.
|
|
316
|
+
lazyLoad: this.computedLazyLoad,
|
|
257
317
|
inView: this.inView,
|
|
258
318
|
loaded: this.loaded
|
|
259
319
|
});
|
|
260
320
|
const showImage = imageShowStrategy({
|
|
261
|
-
lazyLoad: this.
|
|
321
|
+
lazyLoad: this.computedLazyLoad,
|
|
262
322
|
inView: this.inView,
|
|
263
323
|
loaded: this.loaded
|
|
264
324
|
});
|
|
@@ -266,30 +326,30 @@ const Image = defineComponent({
|
|
|
266
326
|
...isVue2 && {
|
|
267
327
|
props: {
|
|
268
328
|
srcset: this.data.webpSrcSet,
|
|
269
|
-
sizes: this.data.sizes,
|
|
329
|
+
sizes: this.sizes ?? this.data.sizes ?? void 0,
|
|
270
330
|
type: "image/webp"
|
|
271
331
|
}
|
|
272
332
|
},
|
|
273
333
|
...isVue3 && {
|
|
274
334
|
srcset: this.data.webpSrcSet,
|
|
275
|
-
sizes: this.data.sizes,
|
|
335
|
+
sizes: this.sizes ?? this.data.sizes ?? void 0,
|
|
276
336
|
type: "image/webp"
|
|
277
337
|
}
|
|
278
338
|
});
|
|
279
339
|
const regularSource = this.data.srcSet && h(Source, {
|
|
280
340
|
...isVue2 && {
|
|
281
341
|
props: {
|
|
282
|
-
srcset: this.data.srcSet,
|
|
283
|
-
sizes: this.data.sizes
|
|
342
|
+
srcset: this.data.srcSet ?? buildSrcSet(this.data.src, this.data.width, this.srcSetCandidates),
|
|
343
|
+
sizes: this.sizes ?? this.data.sizes ?? void 0
|
|
284
344
|
}
|
|
285
345
|
},
|
|
286
346
|
...isVue3 && {
|
|
287
|
-
srcset: this.data.srcSet,
|
|
288
|
-
sizes: this.data.sizes
|
|
347
|
+
srcset: this.data.srcSet ?? buildSrcSet(this.data.src, this.data.width, this.srcSetCandidates),
|
|
348
|
+
sizes: this.sizes ?? this.data.sizes ?? void 0
|
|
289
349
|
}
|
|
290
350
|
});
|
|
291
351
|
const transition = typeof this.fadeInDuration === "undefined" || this.fadeInDuration > 0 ? `opacity ${this.fadeInDuration || 500}ms ${this.fadeInDuration || 500}ms` : void 0;
|
|
292
|
-
const placeholder = h("div", {
|
|
352
|
+
const placeholder = this.usePlaceholder && (this.data.bgColor || this.data.base64) ? h("div", {
|
|
293
353
|
style: {
|
|
294
354
|
backgroundImage: this.data.base64 ? `url(${this.data.base64})` : null,
|
|
295
355
|
backgroundColor: this.data.bgColor,
|
|
@@ -298,11 +358,15 @@ const Image = defineComponent({
|
|
|
298
358
|
objectFit: this.objectFit,
|
|
299
359
|
objectPosition: this.objectPosition,
|
|
300
360
|
transition,
|
|
301
|
-
|
|
361
|
+
position: "absolute",
|
|
362
|
+
left: "-5%",
|
|
363
|
+
top: "-5%",
|
|
364
|
+
width: "110%",
|
|
365
|
+
height: "110%"
|
|
302
366
|
}
|
|
303
|
-
});
|
|
367
|
+
}) : null;
|
|
304
368
|
const { width, aspectRatio } = this.data;
|
|
305
|
-
const height = this.data.height
|
|
369
|
+
const height = this.data.height ?? (aspectRatio ? width / aspectRatio : 0);
|
|
306
370
|
const sizer = this.layout !== "fill" ? h(Sizer, {
|
|
307
371
|
...isVue2 && {
|
|
308
372
|
props: {
|
|
@@ -343,7 +407,8 @@ const Image = defineComponent({
|
|
|
343
407
|
attrs: {
|
|
344
408
|
src: this.data.src,
|
|
345
409
|
alt: this.data.alt,
|
|
346
|
-
title: this.data.title
|
|
410
|
+
title: this.data.title,
|
|
411
|
+
fetchpriority: this.priority ? "high" : void 0
|
|
347
412
|
},
|
|
348
413
|
on: {
|
|
349
414
|
load: this.handleLoad
|
|
@@ -353,16 +418,18 @@ const Image = defineComponent({
|
|
|
353
418
|
src: this.data.src,
|
|
354
419
|
alt: this.data.alt,
|
|
355
420
|
title: this.data.title,
|
|
421
|
+
fetchpriority: this.priority ? "high" : void 0,
|
|
356
422
|
onLoad: this.handleLoad
|
|
357
423
|
},
|
|
424
|
+
ref: "imageRef",
|
|
358
425
|
class: this.pictureClass,
|
|
359
426
|
style: {
|
|
360
|
-
...absolutePositioning,
|
|
361
|
-
...this.pictureStyle,
|
|
362
427
|
opacity: showImage ? 1 : 0,
|
|
363
428
|
transition,
|
|
429
|
+
...absolutePositioning,
|
|
364
430
|
objectFit: this.objectFit,
|
|
365
|
-
objectPosition: this.objectPosition
|
|
431
|
+
objectPosition: this.objectPosition,
|
|
432
|
+
...this.pictureStyle
|
|
366
433
|
}
|
|
367
434
|
})
|
|
368
435
|
]),
|
|
@@ -384,8 +451,14 @@ const Image = defineComponent({
|
|
|
384
451
|
alt: this.data.alt,
|
|
385
452
|
title: this.data.title,
|
|
386
453
|
class: this.pictureClass,
|
|
387
|
-
style: toCss({
|
|
388
|
-
|
|
454
|
+
style: toCss({
|
|
455
|
+
...absolutePositioning,
|
|
456
|
+
objectFit: this.objectFit,
|
|
457
|
+
objectPosition: this.objectPosition,
|
|
458
|
+
...this.pictureStyle
|
|
459
|
+
}),
|
|
460
|
+
loading: this.computedLazyLoad ? "lazy" : void 0,
|
|
461
|
+
fetchpriority: this.priority ? "high" : void 0
|
|
389
462
|
})
|
|
390
463
|
])
|
|
391
464
|
}
|
|
@@ -407,7 +480,8 @@ const Image = defineComponent({
|
|
|
407
480
|
title: this.data.title,
|
|
408
481
|
class: this.pictureClass,
|
|
409
482
|
style: toCss({ ...this.pictureStyle, ...absolutePositioning }),
|
|
410
|
-
loading: "lazy"
|
|
483
|
+
loading: this.computedLazyLoad ? "lazy" : void 0,
|
|
484
|
+
fetchpriority: this.priority ? "high" : void 0
|
|
411
485
|
})
|
|
412
486
|
])
|
|
413
487
|
}
|
|
@@ -583,46 +657,34 @@ const DatocmsStructuredTextPlugin = {
|
|
|
583
657
|
}
|
|
584
658
|
};
|
|
585
659
|
|
|
586
|
-
|
|
587
|
-
const { enabled, initialData, ...other } = options;
|
|
660
|
+
const useQuerySubscription = ({ enabled = true, initialData, query, token, ...other }) => {
|
|
588
661
|
const error = ref(null);
|
|
589
|
-
const data = ref(null);
|
|
590
|
-
const status = ref(
|
|
591
|
-
enabled ? "connecting" : "closed"
|
|
592
|
-
);
|
|
662
|
+
const data = ref(unref(initialData) || null);
|
|
663
|
+
const status = ref(unref(enabled) ? "connecting" : "closed");
|
|
593
664
|
const subscribeToQueryOptions = other;
|
|
594
|
-
watchEffect((onCleanup) => {
|
|
595
|
-
if (
|
|
596
|
-
|
|
597
|
-
return () => {
|
|
598
|
-
};
|
|
599
|
-
}
|
|
600
|
-
let unsubscribe;
|
|
601
|
-
async function subscribe() {
|
|
602
|
-
unsubscribe = await subscribeToQuery({
|
|
665
|
+
watchEffect(async (onCleanup) => {
|
|
666
|
+
if (query && token && unref(enabled)) {
|
|
667
|
+
const unsubscribe = await subscribeToQuery({
|
|
603
668
|
...subscribeToQueryOptions,
|
|
669
|
+
query,
|
|
670
|
+
token,
|
|
604
671
|
onStatusChange: (connectionStatus) => {
|
|
605
672
|
status.value = connectionStatus;
|
|
606
673
|
},
|
|
607
|
-
onUpdate: (
|
|
674
|
+
onUpdate: ({ response }) => {
|
|
608
675
|
error.value = null;
|
|
609
|
-
data.value =
|
|
676
|
+
data.value = response.data;
|
|
610
677
|
},
|
|
611
678
|
onChannelError: (errorData) => {
|
|
612
679
|
data.value = null;
|
|
613
680
|
error.value = errorData;
|
|
614
681
|
}
|
|
615
682
|
});
|
|
683
|
+
onCleanup(unsubscribe);
|
|
616
684
|
}
|
|
617
|
-
subscribe();
|
|
618
|
-
onCleanup(() => {
|
|
619
|
-
if (unsubscribe) {
|
|
620
|
-
unsubscribe();
|
|
621
|
-
}
|
|
622
|
-
});
|
|
623
685
|
});
|
|
624
|
-
return {
|
|
625
|
-
}
|
|
686
|
+
return { data, status, error };
|
|
687
|
+
};
|
|
626
688
|
|
|
627
689
|
const highlightPieces = (textWithHighlightMarker) => {
|
|
628
690
|
return textWithHighlightMarker.split(/\[h\](.+?)\[\/h\]/g).map((text, index) => ({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-datocms",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "A set of components and utilities to work faster with DatoCMS in Vue.js environments",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"datocms",
|
|
@@ -11,7 +11,16 @@
|
|
|
11
11
|
"main": "./dist/index.cjs.js",
|
|
12
12
|
"module": "./dist/index.esm.mjs",
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git://github.com/datocms/vue-datocms.git"
|
|
17
|
+
},
|
|
14
18
|
"license": "MIT",
|
|
19
|
+
"author": "Stefano Verna <s.verna@datocms.com>",
|
|
20
|
+
"contributors": [
|
|
21
|
+
"Silvano Stralla <silvano@datocms.com>"
|
|
22
|
+
],
|
|
23
|
+
"homepage": "https://github.com/datocms/vue-datocms",
|
|
15
24
|
"exports": {
|
|
16
25
|
".": {
|
|
17
26
|
"import": "./dist/index.esm.mjs",
|