react-datocms 5.0.2 → 6.0.0

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.
Files changed (51) hide show
  1. package/README.md +4 -13
  2. package/dist/cjs/Image/index.js +38 -138
  3. package/dist/cjs/Image/index.js.map +1 -1
  4. package/dist/cjs/Image/utils.js +52 -0
  5. package/dist/cjs/Image/utils.js.map +1 -0
  6. package/dist/cjs/SRCImage/index.js +43 -0
  7. package/dist/cjs/SRCImage/index.js.map +1 -0
  8. package/dist/cjs/SRCImage/utils.js +82 -0
  9. package/dist/cjs/SRCImage/utils.js.map +1 -0
  10. package/dist/cjs/Seo/remixUtils.js +1 -1
  11. package/dist/cjs/Seo/remixUtils.js.map +1 -1
  12. package/dist/cjs/VideoPlayer/index.js +1 -1
  13. package/dist/cjs/index.js +2 -1
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/useSiteSearch/index.js.map +1 -1
  16. package/dist/cjs/useVideoPlayer/index.js.map +1 -1
  17. package/dist/esm/Image/index.js +30 -110
  18. package/dist/esm/Image/index.js.map +1 -1
  19. package/dist/esm/Image/utils.js +46 -0
  20. package/dist/esm/Image/utils.js.map +1 -0
  21. package/dist/esm/SRCImage/index.js +36 -0
  22. package/dist/esm/SRCImage/index.js.map +1 -0
  23. package/dist/esm/SRCImage/utils.js +52 -0
  24. package/dist/esm/SRCImage/utils.js.map +1 -0
  25. package/dist/esm/Seo/remixUtils.js +1 -1
  26. package/dist/esm/Seo/remixUtils.js.map +1 -1
  27. package/dist/esm/VideoPlayer/index.js +1 -1
  28. package/dist/esm/index.js +2 -1
  29. package/dist/esm/index.js.map +1 -1
  30. package/dist/esm/useSiteSearch/index.js.map +1 -1
  31. package/dist/esm/useVideoPlayer/index.js.map +1 -1
  32. package/dist/types/Image/index.d.ts +3 -4
  33. package/dist/types/Image/utils.d.ts +7 -0
  34. package/dist/types/SRCImage/index.d.ts +33 -0
  35. package/dist/types/SRCImage/utils.d.ts +6 -0
  36. package/dist/types/Seo/remixUtils.d.ts +1 -1
  37. package/dist/types/index.d.ts +2 -1
  38. package/package.json +3 -4
  39. package/src/Image/__tests__/__snapshots__/index.test.tsx.snap +387 -60
  40. package/src/Image/__tests__/index.test.tsx +55 -8
  41. package/src/Image/index.tsx +64 -177
  42. package/src/Image/utils.ts +58 -0
  43. package/src/SRCImage/__tests__/__snapshots__/index.test.tsx.snap +268 -0
  44. package/src/SRCImage/__tests__/index.test.tsx +91 -0
  45. package/src/SRCImage/index.tsx +98 -0
  46. package/src/SRCImage/utils.tsx +95 -0
  47. package/src/Seo/remixUtils.ts +1 -1
  48. package/src/VideoPlayer/index.tsx +1 -1
  49. package/src/index.ts +2 -1
  50. package/src/useSiteSearch/index.tsx +27 -27
  51. package/src/useVideoPlayer/index.ts +1 -4
@@ -0,0 +1,268 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Image explicit sizes renders correctly 1`] = `
4
+ <SRCImage
5
+ data={
6
+ {
7
+ "base64": "data:image/jpeg;base64,<IMAGE-DATA>",
8
+ "height": 421,
9
+ "src": "https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750",
10
+ "width": 750,
11
+ }
12
+ }
13
+ sizes="(max-width: 600px) 200px, 50vw"
14
+ >
15
+ <picture>
16
+ <source
17
+ sizes="(max-width: 600px) 200px, 50vw"
18
+ srcSet="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.25 187w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.5 375w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.75 562w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750 750w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=1.5 1125w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=2 1500w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=3 2250w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=4 3000w"
19
+ />
20
+ <img
21
+ loading="lazy"
22
+ src="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750"
23
+ style={
24
+ {
25
+ "aspectRatio": "750 / 421",
26
+ "backgroundImage": "url(data:image/jpeg;base64,<IMAGE-DATA>)",
27
+ "backgroundPosition": "50% 50%",
28
+ "backgroundRepeat": "no-repeat",
29
+ "backgroundSize": "cover",
30
+ "color": "transparent",
31
+ "height": "auto",
32
+ "maxWidth": "750px",
33
+ "width": "100%",
34
+ }
35
+ }
36
+ />
37
+ </picture>
38
+ </SRCImage>
39
+ `;
40
+
41
+ exports[`Image full data renders correctly 1`] = `
42
+ <SRCImage
43
+ data={
44
+ {
45
+ "alt": "DatoCMS swag",
46
+ "aspectRatio": 1.7777777777777777,
47
+ "base64": "data:image/jpeg;base64,<IMAGE-DATA>",
48
+ "height": 421,
49
+ "sizes": "(max-width: 750px) 100vw, 750px",
50
+ "src": "https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750",
51
+ "srcSet": "https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=0.25&fit=crop&w=750 187w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=0.5&fit=crop&w=750 375w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=0.75&fit=crop&w=750 562w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=1&fit=crop&w=750 750w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=1.5&fit=crop&w=750 1125w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=2&fit=crop&w=750 1500w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=3&fit=crop&w=750 2250w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=4&fit=crop&w=750 3000w",
52
+ "title": "These are awesome, we know that.",
53
+ "width": 750,
54
+ }
55
+ }
56
+ >
57
+ <picture>
58
+ <source
59
+ sizes="(max-width: 750px) 100vw, 750px"
60
+ srcSet="https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=0.25&fit=crop&w=750 187w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=0.5&fit=crop&w=750 375w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=0.75&fit=crop&w=750 562w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=1&fit=crop&w=750 750w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=1.5&fit=crop&w=750 1125w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=2&fit=crop&w=750 1500w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=3&fit=crop&w=750 2250w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=4&fit=crop&w=750 3000w"
61
+ />
62
+ <img
63
+ alt="DatoCMS swag"
64
+ loading="lazy"
65
+ src="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750"
66
+ style={
67
+ {
68
+ "aspectRatio": "750 / 421",
69
+ "backgroundImage": "url(data:image/jpeg;base64,<IMAGE-DATA>)",
70
+ "backgroundPosition": "50% 50%",
71
+ "backgroundRepeat": "no-repeat",
72
+ "backgroundSize": "cover",
73
+ "color": "transparent",
74
+ "height": "auto",
75
+ "maxWidth": "750px",
76
+ "width": "100%",
77
+ }
78
+ }
79
+ title="These are awesome, we know that."
80
+ />
81
+ </picture>
82
+ </SRCImage>
83
+ `;
84
+
85
+ exports[`Image minimal data renders correctly 1`] = `
86
+ <SRCImage
87
+ data={
88
+ {
89
+ "base64": "data:image/jpeg;base64,<IMAGE-DATA>",
90
+ "height": 421,
91
+ "src": "https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750",
92
+ "width": 750,
93
+ }
94
+ }
95
+ >
96
+ <picture>
97
+ <source
98
+ srcSet="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.25 187w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.5 375w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.75 562w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750 750w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=1.5 1125w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=2 1500w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=3 2250w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=4 3000w"
99
+ />
100
+ <img
101
+ loading="lazy"
102
+ src="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750"
103
+ style={
104
+ {
105
+ "aspectRatio": "750 / 421",
106
+ "backgroundImage": "url(data:image/jpeg;base64,<IMAGE-DATA>)",
107
+ "backgroundPosition": "50% 50%",
108
+ "backgroundRepeat": "no-repeat",
109
+ "backgroundSize": "cover",
110
+ "color": "transparent",
111
+ "height": "auto",
112
+ "maxWidth": "750px",
113
+ "width": "100%",
114
+ }
115
+ }
116
+ />
117
+ </picture>
118
+ </SRCImage>
119
+ `;
120
+
121
+ exports[`Image minimalDataWithRelativeUrl renders correctly 1`] = `
122
+ <SRCImage
123
+ data={
124
+ {
125
+ "base64": "data:image/jpeg;base64,<IMAGE-DATA>",
126
+ "height": 421,
127
+ "src": "/205/image.png?ar=16%3A9&fit=crop&w=750",
128
+ "width": 750,
129
+ }
130
+ }
131
+ >
132
+ <picture>
133
+ <source
134
+ srcSet="/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.25 187w,/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.5 375w,/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.75 562w,/205/image.png?ar=16%3A9&fit=crop&w=750 750w,/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=1.5 1125w,/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=2 1500w,/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=3 2250w,/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=4 3000w"
135
+ />
136
+ <img
137
+ loading="lazy"
138
+ src="/205/image.png?ar=16%3A9&fit=crop&w=750"
139
+ style={
140
+ {
141
+ "aspectRatio": "750 / 421",
142
+ "backgroundImage": "url(data:image/jpeg;base64,<IMAGE-DATA>)",
143
+ "backgroundPosition": "50% 50%",
144
+ "backgroundRepeat": "no-repeat",
145
+ "backgroundSize": "cover",
146
+ "color": "transparent",
147
+ "height": "auto",
148
+ "maxWidth": "750px",
149
+ "width": "100%",
150
+ }
151
+ }
152
+ />
153
+ </picture>
154
+ </SRCImage>
155
+ `;
156
+
157
+ exports[`Image passing className and/or style renders correctly 1`] = `
158
+ <SRCImage
159
+ className="class-name"
160
+ data={
161
+ {
162
+ "base64": "data:image/jpeg;base64,<IMAGE-DATA>",
163
+ "height": 421,
164
+ "src": "https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750",
165
+ "width": 750,
166
+ }
167
+ }
168
+ style={
169
+ {
170
+ "border": "1px solid red",
171
+ }
172
+ }
173
+ >
174
+ <picture>
175
+ <source
176
+ srcSet="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.25 187w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.5 375w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.75 562w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750 750w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=1.5 1125w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=2 1500w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=3 2250w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=4 3000w"
177
+ />
178
+ <img
179
+ className="class-name"
180
+ loading="lazy"
181
+ src="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750"
182
+ style={
183
+ {
184
+ "aspectRatio": "750 / 421",
185
+ "backgroundImage": "url(data:image/jpeg;base64,<IMAGE-DATA>)",
186
+ "backgroundPosition": "50% 50%",
187
+ "backgroundRepeat": "no-repeat",
188
+ "backgroundSize": "cover",
189
+ "border": "1px solid red",
190
+ "color": "transparent",
191
+ "height": "auto",
192
+ "maxWidth": "750px",
193
+ "width": "100%",
194
+ }
195
+ }
196
+ />
197
+ </picture>
198
+ </SRCImage>
199
+ `;
200
+
201
+ exports[`Image priority=true renders correctly 1`] = `
202
+ <SRCImage
203
+ data={
204
+ {
205
+ "base64": "data:image/jpeg;base64,<IMAGE-DATA>",
206
+ "height": 421,
207
+ "src": "https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750",
208
+ "width": 750,
209
+ }
210
+ }
211
+ priority={true}
212
+ >
213
+ <picture>
214
+ <source
215
+ srcSet="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.25 187w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.5 375w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.75 562w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750 750w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=1.5 1125w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=2 1500w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=3 2250w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=4 3000w"
216
+ />
217
+ <img
218
+ fetchpriority="high"
219
+ src="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750"
220
+ style={
221
+ {
222
+ "aspectRatio": "750 / 421",
223
+ "backgroundImage": "url(data:image/jpeg;base64,<IMAGE-DATA>)",
224
+ "backgroundPosition": "50% 50%",
225
+ "backgroundRepeat": "no-repeat",
226
+ "backgroundSize": "cover",
227
+ "color": "transparent",
228
+ "height": "auto",
229
+ "maxWidth": "750px",
230
+ "width": "100%",
231
+ }
232
+ }
233
+ />
234
+ </picture>
235
+ </SRCImage>
236
+ `;
237
+
238
+ exports[`Image usePlaceholder=false renders correctly 1`] = `
239
+ <SRCImage
240
+ data={
241
+ {
242
+ "base64": "data:image/jpeg;base64,<IMAGE-DATA>",
243
+ "height": 421,
244
+ "src": "https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750",
245
+ "width": 750,
246
+ }
247
+ }
248
+ usePlaceholder={false}
249
+ >
250
+ <picture>
251
+ <source
252
+ srcSet="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.25 187w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.5 375w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=0.75 562w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750 750w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=1.5 1125w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=2 1500w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=3 2250w,https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750&dpr=4 3000w"
253
+ />
254
+ <img
255
+ loading="lazy"
256
+ src="https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750"
257
+ style={
258
+ {
259
+ "aspectRatio": "750 / 421",
260
+ "height": "auto",
261
+ "maxWidth": "750px",
262
+ "width": "100%",
263
+ }
264
+ }
265
+ />
266
+ </picture>
267
+ </SRCImage>
268
+ `;
@@ -0,0 +1,91 @@
1
+ import { mount } from 'enzyme';
2
+ import * as React from 'react';
3
+ import { SRCImage } from '../index.js';
4
+
5
+ const data = {
6
+ alt: 'DatoCMS swag',
7
+ aspectRatio: 1.7777777777777777,
8
+ base64: 'data:image/jpeg;base64,<IMAGE-DATA>',
9
+ height: 421,
10
+ sizes: '(max-width: 750px) 100vw, 750px',
11
+ src: 'https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750',
12
+ srcSet:
13
+ 'https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=0.25&fit=crop&w=750 187w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=0.5&fit=crop&w=750 375w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=0.75&fit=crop&w=750 562w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=1&fit=crop&w=750 750w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=1.5&fit=crop&w=750 1125w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=2&fit=crop&w=750 1500w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=3&fit=crop&w=750 2250w,↵https://www.datocms-assets.com/205/image.png?ar=16%3A9&dpr=4&fit=crop&w=750 3000w',
14
+ title: 'These are awesome, we know that.',
15
+ width: 750,
16
+ };
17
+
18
+ const minimalData = {
19
+ base64: 'data:image/jpeg;base64,<IMAGE-DATA>',
20
+ height: 421,
21
+ src: 'https://www.datocms-assets.com/205/image.png?ar=16%3A9&fit=crop&w=750',
22
+ width: 750,
23
+ };
24
+
25
+ const minimalDataWithRelativeUrl = {
26
+ base64: 'data:image/jpeg;base64,<IMAGE-DATA>',
27
+ height: 421,
28
+ src: '/205/image.png?ar=16%3A9&fit=crop&w=750',
29
+ width: 750,
30
+ };
31
+
32
+ describe('Image', () => {
33
+ describe('full data', () => {
34
+ it('renders correctly', () => {
35
+ const wrapper = mount(<SRCImage data={data} />);
36
+ expect(wrapper).toMatchSnapshot();
37
+ });
38
+ });
39
+
40
+ describe('minimal data', () => {
41
+ it('renders correctly', () => {
42
+ const wrapper = mount(<SRCImage data={minimalData} />);
43
+ expect(wrapper).toMatchSnapshot();
44
+ });
45
+ });
46
+
47
+ describe('minimalDataWithRelativeUrl', () => {
48
+ it('renders correctly', () => {
49
+ const wrapper = mount(<SRCImage data={minimalDataWithRelativeUrl} />);
50
+ expect(wrapper).toMatchSnapshot();
51
+ });
52
+ });
53
+
54
+ describe('passing className and/or style', () => {
55
+ it('renders correctly', () => {
56
+ const wrapper = mount(
57
+ <SRCImage
58
+ data={minimalData}
59
+ className="class-name"
60
+ style={{ border: '1px solid red' }}
61
+ />,
62
+ );
63
+ expect(wrapper).toMatchSnapshot();
64
+ });
65
+ });
66
+
67
+ describe('priority=true', () => {
68
+ it('renders correctly', () => {
69
+ const wrapper = mount(<SRCImage data={minimalData} priority={true} />);
70
+ expect(wrapper).toMatchSnapshot();
71
+ });
72
+ });
73
+
74
+ describe('usePlaceholder=false', () => {
75
+ it('renders correctly', () => {
76
+ const wrapper = mount(
77
+ <SRCImage data={minimalData} usePlaceholder={false} />,
78
+ );
79
+ expect(wrapper).toMatchSnapshot();
80
+ });
81
+ });
82
+
83
+ describe('explicit sizes', () => {
84
+ it('renders correctly', () => {
85
+ const wrapper = mount(
86
+ <SRCImage data={minimalData} sizes="(max-width: 600px) 200px, 50vw" />,
87
+ );
88
+ expect(wrapper).toMatchSnapshot();
89
+ });
90
+ });
91
+ });
@@ -0,0 +1,98 @@
1
+ import React from 'react';
2
+ import type { ResponsiveImageType } from '../Image';
3
+ import { buildRegularSource, buildWebpSource, priorityProp } from './utils.js';
4
+
5
+ export type SRCImagePropTypes = {
6
+ /** The actual response you get from a DatoCMS `responsiveImage` GraphQL query */
7
+ data: ResponsiveImageType;
8
+ /** Additional CSS className for root node */
9
+ className?: string;
10
+ /** Additional CSS rules to add to the root node */
11
+ style?: React.CSSProperties;
12
+ /**
13
+ * When true, the image will be considered high priority. Lazy loading is automatically disabled, and fetchpriority="high" is added to the image.
14
+ * 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.
15
+ * Should only be used when the image is visible above the fold.
16
+ **/
17
+ priority?: boolean;
18
+ /** Whether the component should use a blurred image placeholder */
19
+ usePlaceholder?: boolean;
20
+ /**
21
+ * The HTML5 `sizes` attribute for the image
22
+ *
23
+ * Learn more about srcset and sizes:
24
+ * -> https://web.dev/learn/design/responsive-images/#sizes
25
+ * -> https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
26
+ **/
27
+ sizes?: HTMLImageElement['sizes'];
28
+ /**
29
+ * If `data` does not contain `srcSet`, the candidates for the `srcset` of the image will be auto-generated based on these width multipliers
30
+ *
31
+ * Default candidate multipliers are [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4]
32
+ **/
33
+ srcSetCandidates?: number[];
34
+ };
35
+
36
+ export function SRCImage({
37
+ className,
38
+ style,
39
+ data,
40
+ usePlaceholder = true,
41
+ priority = false,
42
+ sizes,
43
+ srcSetCandidates = [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4],
44
+ }: SRCImagePropTypes) {
45
+ const webpSource = buildWebpSource(data, sizes);
46
+ const regularSource = buildRegularSource(data, sizes, srcSetCandidates);
47
+
48
+ const placeholderStyle: React.CSSProperties | undefined =
49
+ usePlaceholder && data.base64
50
+ ? {
51
+ backgroundImage: `url(${data.base64})`,
52
+ backgroundSize: 'cover',
53
+ backgroundRepeat: 'no-repeat',
54
+ backgroundPosition: '50% 50%',
55
+ color: 'transparent',
56
+ }
57
+ : usePlaceholder && data.bgColor
58
+ ? { backgroundColor: data.bgColor ?? undefined, color: 'transparent' }
59
+ : undefined;
60
+
61
+ const { width } = data;
62
+
63
+ const height =
64
+ data.height ?? Math.round(data.aspectRatio ? width / data.aspectRatio : 0);
65
+
66
+ const sizingStyle = {
67
+ aspectRatio: `${width} / ${height}`,
68
+ width: '100%',
69
+ maxWidth: `${width}px`,
70
+ height: 'auto',
71
+ };
72
+
73
+ const loadingBehaviourProps = priority
74
+ ? priorityProp(priority ? 'high' : undefined)
75
+ : { loading: 'lazy' };
76
+
77
+ return (
78
+ <picture>
79
+ {webpSource}
80
+ {regularSource}
81
+ {data.src && (
82
+ // biome-ignore lint/a11y/useAltText: We do with alt the best we can
83
+ <img
84
+ src={data.src}
85
+ alt={data.alt ?? undefined}
86
+ title={data.title ?? undefined}
87
+ {...loadingBehaviourProps}
88
+ className={className}
89
+ style={{
90
+ ...placeholderStyle,
91
+ ...sizingStyle,
92
+ ...style,
93
+ }}
94
+ />
95
+ )}
96
+ </picture>
97
+ );
98
+ }
@@ -0,0 +1,95 @@
1
+ import React, { version } from 'react';
2
+ import { ResponsiveImageType } from '../Image';
3
+
4
+ export function priorityProp(
5
+ fetchPriority?: string,
6
+ ): Record<string, string | undefined> {
7
+ const [majorStr, minorStr] = version.split('.');
8
+ const major = parseInt(majorStr, 10);
9
+ const minor = parseInt(minorStr, 10);
10
+ if (major > 18 || (major === 18 && minor >= 3)) {
11
+ // In React 18.3.0 or newer, we must use camelCase
12
+ // prop to avoid "Warning: Invalid DOM property".
13
+ // See https://github.com/facebook/react/pull/25927
14
+ return { fetchPriority };
15
+ }
16
+ // In React 18.2.0 or older, we must use lowercase prop
17
+ // to avoid "Warning: Invalid DOM property".
18
+ return { fetchpriority: fetchPriority };
19
+ }
20
+
21
+ const bogusBaseUrl = 'https://example.com/';
22
+
23
+ export const buildSrcSetFromSrc = (
24
+ src: string | null | undefined,
25
+ width: number | undefined,
26
+ candidateMultipliers: number[],
27
+ ) => {
28
+ if (!(src && width)) {
29
+ return undefined;
30
+ }
31
+
32
+ return candidateMultipliers
33
+ .map((multiplier) => {
34
+ const url = new URL(src, bogusBaseUrl);
35
+
36
+ if (multiplier !== 1) {
37
+ url.searchParams.set('dpr', `${multiplier}`);
38
+ const maxH = url.searchParams.get('max-h');
39
+ const maxW = url.searchParams.get('max-w');
40
+ if (maxH) {
41
+ url.searchParams.set(
42
+ 'max-h',
43
+ `${Math.floor(parseInt(maxH) * multiplier)}`,
44
+ );
45
+ }
46
+ if (maxW) {
47
+ url.searchParams.set(
48
+ 'max-w',
49
+ `${Math.floor(parseInt(maxW) * multiplier)}`,
50
+ );
51
+ }
52
+ }
53
+
54
+ const finalWidth = Math.floor(width * multiplier);
55
+
56
+ if (finalWidth < 50) {
57
+ return null;
58
+ }
59
+
60
+ return `${url.toString().replace(bogusBaseUrl, '/')} ${finalWidth}w`;
61
+ })
62
+ .filter(Boolean)
63
+ .join(',');
64
+ };
65
+
66
+ export function buildWebpSource(
67
+ data: ResponsiveImageType,
68
+ sizes: HTMLImageElement['sizes'] | undefined,
69
+ ) {
70
+ return (
71
+ data.webpSrcSet && (
72
+ <source
73
+ srcSet={data.webpSrcSet}
74
+ sizes={sizes ?? data.sizes ?? undefined}
75
+ type="image/webp"
76
+ />
77
+ )
78
+ );
79
+ }
80
+
81
+ export function buildRegularSource(
82
+ data: ResponsiveImageType,
83
+ sizes: HTMLImageElement['sizes'] | undefined,
84
+ srcSetCandidates: number[],
85
+ ) {
86
+ return (
87
+ <source
88
+ srcSet={
89
+ data.srcSet ??
90
+ buildSrcSetFromSrc(data.src, data.width, srcSetCandidates)
91
+ }
92
+ sizes={sizes ?? data.sizes ?? undefined}
93
+ />
94
+ );
95
+ }
@@ -50,5 +50,5 @@ export function toRemixMeta(
50
50
  } as Record<string, string>;
51
51
  }
52
52
  })
53
- .filter(Boolean);
53
+ .filter((x): x is NonNullable<typeof x> => Boolean(x));
54
54
  }
@@ -72,7 +72,7 @@ export const VideoPlayer: (
72
72
  const {
73
73
  data = {},
74
74
  disableCookies = true,
75
- preload = "metadata",
75
+ preload = 'metadata',
76
76
  style: styleFromProps,
77
77
  ...rest
78
78
  } = props;
package/src/index.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export * from './Image/index.js';
2
+ export * from './SRCImage/index.js';
2
3
  export * from './Seo/index.js';
3
- export * from './VideoPlayer/index.js';
4
4
  export * from './StructuredText/index.js';
5
+ export * from './VideoPlayer/index.js';
5
6
 
6
7
  export * from './useQuerySubscription/index.js';
7
8
  export * from './useSiteSearch/index.js';
@@ -243,32 +243,32 @@ export function useSiteSearch<Client extends GenericClient>(
243
243
  totalPages: 0,
244
244
  }
245
245
  : response
246
- ? {
247
- pageResults: response.data.map((rawSearchResult) => ({
248
- id: rawSearchResult.id,
249
- url: rawSearchResult.attributes.url,
250
- title: rawSearchResult.attributes.highlight.title ? (
251
- <MatchHighlighter highlighter={highlighter} context="title">
252
- {rawSearchResult.attributes.highlight.title[0]}
253
- </MatchHighlighter>
254
- ) : (
255
- rawSearchResult.attributes.title
256
- ),
257
- bodyExcerpt: rawSearchResult.attributes.highlight.body ? (
258
- <MatchHighlighter
259
- highlighter={highlighter}
260
- context="bodyExcerpt"
261
- >
262
- {rawSearchResult.attributes.highlight.body[0]}
263
- </MatchHighlighter>
264
- ) : (
265
- rawSearchResult.attributes.body_excerpt
266
- ),
267
- raw: rawSearchResult,
268
- })),
269
- totalResults: response.meta.total_count,
270
- totalPages: Math.ceil(response.meta.total_count / resultsPerPage),
271
- }
272
- : undefined,
246
+ ? {
247
+ pageResults: response.data.map((rawSearchResult) => ({
248
+ id: rawSearchResult.id,
249
+ url: rawSearchResult.attributes.url,
250
+ title: rawSearchResult.attributes.highlight.title ? (
251
+ <MatchHighlighter highlighter={highlighter} context="title">
252
+ {rawSearchResult.attributes.highlight.title[0]}
253
+ </MatchHighlighter>
254
+ ) : (
255
+ rawSearchResult.attributes.title
256
+ ),
257
+ bodyExcerpt: rawSearchResult.attributes.highlight.body ? (
258
+ <MatchHighlighter
259
+ highlighter={highlighter}
260
+ context="bodyExcerpt"
261
+ >
262
+ {rawSearchResult.attributes.highlight.body[0]}
263
+ </MatchHighlighter>
264
+ ) : (
265
+ rawSearchResult.attributes.body_excerpt
266
+ ),
267
+ raw: rawSearchResult,
268
+ })),
269
+ totalResults: response.meta.total_count,
270
+ totalPages: Math.ceil(response.meta.total_count / resultsPerPage),
271
+ }
272
+ : undefined,
273
273
  };
274
274
  }
@@ -18,10 +18,7 @@ const computedPlaybackId = (
18
18
  return { playbackId: `${muxPlaybackId || playbackId}` };
19
19
  };
20
20
 
21
- const computedStyle = (
22
- width: Possibly<number>,
23
- height: Possibly<number>,
24
- ) => {
21
+ const computedStyle = (width: Possibly<number>, height: Possibly<number>) => {
25
22
  if (!(width && height)) return undefined;
26
23
 
27
24
  return {