@webstudio-is/image 0.1.0 → 0.2.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 (44) hide show
  1. package/lib/__generated__/image.props.json +573 -573
  2. package/lib/cjs/__generated__/image.props.json +573 -573
  3. package/lib/cjs/image-loaders.cjs +48 -33
  4. package/lib/cjs/image-optimize.cjs +101 -171
  5. package/lib/cjs/image.cjs +54 -22
  6. package/lib/cjs/index.cjs +31 -31
  7. package/lib/image-loaders.js +24 -27
  8. package/lib/image-optimize.js +83 -169
  9. package/lib/image.js +30 -15
  10. package/lib/index.js +8 -3
  11. package/package.json +9 -16
  12. package/src/__generated__/image.props.json +575 -0
  13. package/src/image-dev.stories.tsx +128 -0
  14. package/src/image-loaders.ts +47 -0
  15. package/{lib/image-optimize.test.js → src/image-optimize.test.ts} +122 -103
  16. package/{lib/cjs/image-optimize.d.ts → src/image-optimize.ts} +172 -19
  17. package/src/image.tsx +74 -0
  18. package/{lib/cjs/index.d.ts → src/index.ts} +0 -1
  19. package/lib/cjs/image-dev.stories.cjs +0 -77
  20. package/lib/cjs/image-dev.stories.d.ts +0 -35
  21. package/lib/cjs/image-dev.stories.d.ts.map +0 -1
  22. package/lib/cjs/image-loaders.d.ts +0 -14
  23. package/lib/cjs/image-loaders.d.ts.map +0 -1
  24. package/lib/cjs/image-optimize.d.ts.map +0 -1
  25. package/lib/cjs/image-optimize.test.cjs +0 -157
  26. package/lib/cjs/image-optimize.test.d.ts +0 -2
  27. package/lib/cjs/image-optimize.test.d.ts.map +0 -1
  28. package/lib/cjs/image.d.ts +0 -11
  29. package/lib/cjs/image.d.ts.map +0 -1
  30. package/lib/cjs/index.d.ts.map +0 -1
  31. package/lib/image-dev.stories.d.ts +0 -35
  32. package/lib/image-dev.stories.d.ts.map +0 -1
  33. package/lib/image-dev.stories.js +0 -65
  34. package/lib/image-loaders.d.ts +0 -14
  35. package/lib/image-loaders.d.ts.map +0 -1
  36. package/lib/image-optimize.d.ts +0 -107
  37. package/lib/image-optimize.d.ts.map +0 -1
  38. package/lib/image-optimize.test.d.ts +0 -2
  39. package/lib/image-optimize.test.d.ts.map +0 -1
  40. package/lib/image.d.ts +0 -11
  41. package/lib/image.d.ts.map +0 -1
  42. package/lib/index.d.ts +0 -5
  43. package/lib/index.d.ts.map +0 -1
  44. package/lib/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,575 @@
1
+ {
2
+ "slot": {
3
+ "defaultValue": null,
4
+ "required": false,
5
+ "type": "text"
6
+ },
7
+ "style": {
8
+ "defaultValue": null,
9
+ "required": false,
10
+ "type": "text"
11
+ },
12
+ "title": {
13
+ "defaultValue": null,
14
+ "required": false,
15
+ "type": "text"
16
+ },
17
+ "alt": {
18
+ "defaultValue": null,
19
+ "required": false,
20
+ "type": "text"
21
+ },
22
+ "crossOrigin": {
23
+ "defaultValue": null,
24
+ "options": ["\"\"", "anonymous", "use-credentials"],
25
+ "required": false,
26
+ "type": "radio"
27
+ },
28
+ "decoding": {
29
+ "defaultValue": "async",
30
+ "options": ["async", "auto", "sync"],
31
+ "required": false,
32
+ "type": "radio"
33
+ },
34
+ "height": {
35
+ "defaultValue": null,
36
+ "required": false,
37
+ "type": "text"
38
+ },
39
+ "loading": {
40
+ "defaultValue": "lazy",
41
+ "options": ["eager", "lazy"],
42
+ "required": false,
43
+ "type": "radio"
44
+ },
45
+ "referrerPolicy": {
46
+ "defaultValue": null,
47
+ "options": [
48
+ "\"\"",
49
+ "no-referrer",
50
+ "no-referrer-when-downgrade",
51
+ "origin",
52
+ "origin-when-cross-origin",
53
+ "same-origin",
54
+ "strict-origin",
55
+ "strict-origin-when-cross-origin",
56
+ "unsafe-url"
57
+ ],
58
+ "required": false,
59
+ "type": "select"
60
+ },
61
+ "sizes": {
62
+ "defaultValue": null,
63
+ "required": false,
64
+ "type": "text"
65
+ },
66
+ "src": {
67
+ "defaultValue": "",
68
+ "required": false,
69
+ "type": "text"
70
+ },
71
+ "srcSet": {
72
+ "defaultValue": null,
73
+ "required": false,
74
+ "type": "text"
75
+ },
76
+ "useMap": {
77
+ "defaultValue": null,
78
+ "required": false,
79
+ "type": "text"
80
+ },
81
+ "width": {
82
+ "defaultValue": null,
83
+ "required": false,
84
+ "type": "text"
85
+ },
86
+ "defaultChecked": {
87
+ "defaultValue": null,
88
+ "required": false,
89
+ "type": "boolean"
90
+ },
91
+ "defaultValue": {
92
+ "defaultValue": null,
93
+ "required": false,
94
+ "type": "text"
95
+ },
96
+ "suppressContentEditableWarning": {
97
+ "defaultValue": null,
98
+ "required": false,
99
+ "type": "boolean"
100
+ },
101
+ "suppressHydrationWarning": {
102
+ "defaultValue": null,
103
+ "required": false,
104
+ "type": "boolean"
105
+ },
106
+ "accessKey": {
107
+ "defaultValue": null,
108
+ "required": false,
109
+ "type": "text"
110
+ },
111
+ "className": {
112
+ "defaultValue": null,
113
+ "required": false,
114
+ "type": "text"
115
+ },
116
+ "contentEditable": {
117
+ "defaultValue": null,
118
+ "required": false,
119
+ "type": "text"
120
+ },
121
+ "contextMenu": {
122
+ "defaultValue": null,
123
+ "required": false,
124
+ "type": "text"
125
+ },
126
+ "dir": {
127
+ "defaultValue": null,
128
+ "required": false,
129
+ "type": "text"
130
+ },
131
+ "draggable": {
132
+ "defaultValue": null,
133
+ "required": false,
134
+ "type": "boolean"
135
+ },
136
+ "hidden": {
137
+ "defaultValue": null,
138
+ "required": false,
139
+ "type": "boolean"
140
+ },
141
+ "id": {
142
+ "defaultValue": null,
143
+ "required": false,
144
+ "type": "text"
145
+ },
146
+ "lang": {
147
+ "defaultValue": null,
148
+ "required": false,
149
+ "type": "text"
150
+ },
151
+ "placeholder": {
152
+ "defaultValue": null,
153
+ "required": false,
154
+ "type": "text"
155
+ },
156
+ "spellCheck": {
157
+ "defaultValue": null,
158
+ "required": false,
159
+ "type": "boolean"
160
+ },
161
+ "tabIndex": {
162
+ "defaultValue": null,
163
+ "required": false,
164
+ "type": "number"
165
+ },
166
+ "translate": {
167
+ "defaultValue": null,
168
+ "options": ["yes", "no"],
169
+ "required": false,
170
+ "type": "radio"
171
+ },
172
+ "radioGroup": {
173
+ "defaultValue": null,
174
+ "required": false,
175
+ "type": "text"
176
+ },
177
+ "role": {
178
+ "defaultValue": null,
179
+ "required": false,
180
+ "type": "text"
181
+ },
182
+ "about": {
183
+ "defaultValue": null,
184
+ "required": false,
185
+ "type": "text"
186
+ },
187
+ "datatype": {
188
+ "defaultValue": null,
189
+ "required": false,
190
+ "type": "text"
191
+ },
192
+ "inlist": {
193
+ "defaultValue": null,
194
+ "required": false,
195
+ "type": "text"
196
+ },
197
+ "prefix": {
198
+ "defaultValue": null,
199
+ "required": false,
200
+ "type": "text"
201
+ },
202
+ "property": {
203
+ "defaultValue": null,
204
+ "required": false,
205
+ "type": "text"
206
+ },
207
+ "resource": {
208
+ "defaultValue": null,
209
+ "required": false,
210
+ "type": "text"
211
+ },
212
+ "typeof": {
213
+ "defaultValue": null,
214
+ "required": false,
215
+ "type": "text"
216
+ },
217
+ "vocab": {
218
+ "defaultValue": null,
219
+ "required": false,
220
+ "type": "text"
221
+ },
222
+ "autoCapitalize": {
223
+ "defaultValue": null,
224
+ "required": false,
225
+ "type": "text"
226
+ },
227
+ "autoCorrect": {
228
+ "defaultValue": null,
229
+ "required": false,
230
+ "type": "text"
231
+ },
232
+ "autoSave": {
233
+ "defaultValue": null,
234
+ "required": false,
235
+ "type": "text"
236
+ },
237
+ "color": {
238
+ "defaultValue": null,
239
+ "required": false,
240
+ "type": "color"
241
+ },
242
+ "itemProp": {
243
+ "defaultValue": null,
244
+ "required": false,
245
+ "type": "text"
246
+ },
247
+ "itemScope": {
248
+ "defaultValue": null,
249
+ "required": false,
250
+ "type": "boolean"
251
+ },
252
+ "itemType": {
253
+ "defaultValue": null,
254
+ "required": false,
255
+ "type": "text"
256
+ },
257
+ "itemID": {
258
+ "defaultValue": null,
259
+ "required": false,
260
+ "type": "text"
261
+ },
262
+ "itemRef": {
263
+ "defaultValue": null,
264
+ "required": false,
265
+ "type": "text"
266
+ },
267
+ "results": {
268
+ "defaultValue": null,
269
+ "required": false,
270
+ "type": "number"
271
+ },
272
+ "security": {
273
+ "defaultValue": null,
274
+ "required": false,
275
+ "type": "text"
276
+ },
277
+ "unselectable": {
278
+ "defaultValue": null,
279
+ "options": ["on", "off"],
280
+ "required": false,
281
+ "type": "radio"
282
+ },
283
+ "inputMode": {
284
+ "defaultValue": null,
285
+ "options": [
286
+ "text",
287
+ "none",
288
+ "search",
289
+ "tel",
290
+ "url",
291
+ "email",
292
+ "numeric",
293
+ "decimal"
294
+ ],
295
+ "required": false,
296
+ "type": "select"
297
+ },
298
+ "is": {
299
+ "defaultValue": null,
300
+ "required": false,
301
+ "type": "text"
302
+ },
303
+ "aria-activedescendant": {
304
+ "defaultValue": null,
305
+ "required": false,
306
+ "type": "text"
307
+ },
308
+ "aria-atomic": {
309
+ "defaultValue": null,
310
+ "required": false,
311
+ "type": "boolean"
312
+ },
313
+ "aria-autocomplete": {
314
+ "defaultValue": null,
315
+ "options": ["list", "none", "inline", "both"],
316
+ "required": false,
317
+ "type": "radio"
318
+ },
319
+ "aria-busy": {
320
+ "defaultValue": null,
321
+ "required": false,
322
+ "type": "boolean"
323
+ },
324
+ "aria-checked": {
325
+ "defaultValue": null,
326
+ "required": false,
327
+ "type": "text"
328
+ },
329
+ "aria-colcount": {
330
+ "defaultValue": null,
331
+ "required": false,
332
+ "type": "number"
333
+ },
334
+ "aria-colindex": {
335
+ "defaultValue": null,
336
+ "required": false,
337
+ "type": "number"
338
+ },
339
+ "aria-colspan": {
340
+ "defaultValue": null,
341
+ "required": false,
342
+ "type": "number"
343
+ },
344
+ "aria-controls": {
345
+ "defaultValue": null,
346
+ "required": false,
347
+ "type": "text"
348
+ },
349
+ "aria-current": {
350
+ "defaultValue": null,
351
+ "required": false,
352
+ "type": "text"
353
+ },
354
+ "aria-describedby": {
355
+ "defaultValue": null,
356
+ "required": false,
357
+ "type": "text"
358
+ },
359
+ "aria-details": {
360
+ "defaultValue": null,
361
+ "required": false,
362
+ "type": "text"
363
+ },
364
+ "aria-disabled": {
365
+ "defaultValue": null,
366
+ "required": false,
367
+ "type": "boolean"
368
+ },
369
+ "aria-dropeffect": {
370
+ "defaultValue": null,
371
+ "options": ["link", "none", "copy", "execute", "move", "popup"],
372
+ "required": false,
373
+ "type": "select"
374
+ },
375
+ "aria-errormessage": {
376
+ "defaultValue": null,
377
+ "required": false,
378
+ "type": "text"
379
+ },
380
+ "aria-expanded": {
381
+ "defaultValue": null,
382
+ "required": false,
383
+ "type": "boolean"
384
+ },
385
+ "aria-flowto": {
386
+ "defaultValue": null,
387
+ "required": false,
388
+ "type": "text"
389
+ },
390
+ "aria-grabbed": {
391
+ "defaultValue": null,
392
+ "required": false,
393
+ "type": "boolean"
394
+ },
395
+ "aria-haspopup": {
396
+ "defaultValue": null,
397
+ "required": false,
398
+ "type": "text"
399
+ },
400
+ "aria-hidden": {
401
+ "defaultValue": null,
402
+ "required": false,
403
+ "type": "boolean"
404
+ },
405
+ "aria-invalid": {
406
+ "defaultValue": null,
407
+ "required": false,
408
+ "type": "text"
409
+ },
410
+ "aria-keyshortcuts": {
411
+ "defaultValue": null,
412
+ "required": false,
413
+ "type": "text"
414
+ },
415
+ "aria-label": {
416
+ "defaultValue": null,
417
+ "required": false,
418
+ "type": "text"
419
+ },
420
+ "aria-labelledby": {
421
+ "defaultValue": null,
422
+ "required": false,
423
+ "type": "text"
424
+ },
425
+ "aria-level": {
426
+ "defaultValue": null,
427
+ "required": false,
428
+ "type": "number"
429
+ },
430
+ "aria-live": {
431
+ "defaultValue": null,
432
+ "options": ["off", "assertive", "polite"],
433
+ "required": false,
434
+ "type": "radio"
435
+ },
436
+ "aria-modal": {
437
+ "defaultValue": null,
438
+ "required": false,
439
+ "type": "boolean"
440
+ },
441
+ "aria-multiline": {
442
+ "defaultValue": null,
443
+ "required": false,
444
+ "type": "boolean"
445
+ },
446
+ "aria-multiselectable": {
447
+ "defaultValue": null,
448
+ "required": false,
449
+ "type": "boolean"
450
+ },
451
+ "aria-orientation": {
452
+ "defaultValue": null,
453
+ "options": ["horizontal", "vertical"],
454
+ "required": false,
455
+ "type": "radio"
456
+ },
457
+ "aria-owns": {
458
+ "defaultValue": null,
459
+ "required": false,
460
+ "type": "text"
461
+ },
462
+ "aria-placeholder": {
463
+ "defaultValue": null,
464
+ "required": false,
465
+ "type": "text"
466
+ },
467
+ "aria-posinset": {
468
+ "defaultValue": null,
469
+ "required": false,
470
+ "type": "number"
471
+ },
472
+ "aria-pressed": {
473
+ "defaultValue": null,
474
+ "required": false,
475
+ "type": "text"
476
+ },
477
+ "aria-readonly": {
478
+ "defaultValue": null,
479
+ "required": false,
480
+ "type": "boolean"
481
+ },
482
+ "aria-relevant": {
483
+ "defaultValue": null,
484
+ "options": [
485
+ "text",
486
+ "additions",
487
+ "additions removals",
488
+ "additions text",
489
+ "all",
490
+ "removals",
491
+ "removals additions",
492
+ "removals text",
493
+ "text additions",
494
+ "text removals"
495
+ ],
496
+ "required": false,
497
+ "type": "select"
498
+ },
499
+ "aria-required": {
500
+ "defaultValue": null,
501
+ "required": false,
502
+ "type": "boolean"
503
+ },
504
+ "aria-roledescription": {
505
+ "defaultValue": null,
506
+ "required": false,
507
+ "type": "text"
508
+ },
509
+ "aria-rowcount": {
510
+ "defaultValue": null,
511
+ "required": false,
512
+ "type": "number"
513
+ },
514
+ "aria-rowindex": {
515
+ "defaultValue": null,
516
+ "required": false,
517
+ "type": "number"
518
+ },
519
+ "aria-rowspan": {
520
+ "defaultValue": null,
521
+ "required": false,
522
+ "type": "number"
523
+ },
524
+ "aria-selected": {
525
+ "defaultValue": null,
526
+ "required": false,
527
+ "type": "boolean"
528
+ },
529
+ "aria-setsize": {
530
+ "defaultValue": null,
531
+ "required": false,
532
+ "type": "number"
533
+ },
534
+ "aria-sort": {
535
+ "defaultValue": null,
536
+ "options": ["none", "ascending", "descending", "other"],
537
+ "required": false,
538
+ "type": "radio"
539
+ },
540
+ "aria-valuemax": {
541
+ "defaultValue": null,
542
+ "required": false,
543
+ "type": "number"
544
+ },
545
+ "aria-valuemin": {
546
+ "defaultValue": null,
547
+ "required": false,
548
+ "type": "number"
549
+ },
550
+ "aria-valuenow": {
551
+ "defaultValue": null,
552
+ "required": false,
553
+ "type": "number"
554
+ },
555
+ "aria-valuetext": {
556
+ "defaultValue": null,
557
+ "required": false,
558
+ "type": "text"
559
+ },
560
+ "quality": {
561
+ "defaultValue": null,
562
+ "required": false,
563
+ "type": "number"
564
+ },
565
+ "loader": {
566
+ "defaultValue": null,
567
+ "required": true,
568
+ "type": "text"
569
+ },
570
+ "optimize": {
571
+ "defaultValue": true,
572
+ "required": false,
573
+ "type": "boolean"
574
+ }
575
+ }
@@ -0,0 +1,128 @@
1
+ // Story for image development, see https://github.com/webstudio-is/webstudio-designer/issues/387
2
+
3
+ import React, { type ComponentProps, type HTMLAttributes } from "react";
4
+ import type { ComponentMeta, ComponentStory } from "@storybook/react";
5
+ import { Image as ImagePrimitive, loaders } from "./";
6
+
7
+ // to not allow include local assets everywhere, just enable it for this file
8
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
9
+ // @ts-ignore
10
+ import localLogoImage from "../storybook-assets/logo.webp";
11
+
12
+ export default {
13
+ title: "Components/ImageDev",
14
+ } as ComponentMeta<typeof ImagePrimitive>;
15
+
16
+ type ImageProps = ComponentProps<typeof ImagePrimitive>;
17
+
18
+ /**
19
+ * In case you need to test img with real cloudflare trasforms
20
+ * set USE_CLOUDFLARE_IMAGE_TRANSFORM = true
21
+ **/
22
+ const USE_CLOUDFLARE_IMAGE_TRANSFORM = false;
23
+
24
+ // For cloudflare image transform testing, logo should be the most consistent image on the site
25
+ const REMOTE_SELF_DOMAIN_IMAGE = "https://webstudio.is/logo.webp";
26
+
27
+ const imageSrc = USE_CLOUDFLARE_IMAGE_TRANSFORM
28
+ ? REMOTE_SELF_DOMAIN_IMAGE
29
+ : localLogoImage;
30
+
31
+ const imageLoader = USE_CLOUDFLARE_IMAGE_TRANSFORM
32
+ ? loaders.cloudflareImageLoader({ resizeOrigin: "https://webstudio.is" })
33
+ : loaders.localImageLoader();
34
+
35
+ const ImageBase: ComponentStory<
36
+ React.ForwardRefExoticComponent<
37
+ Omit<ImageProps, "loader"> & { style?: HTMLAttributes<"img">["style"] }
38
+ >
39
+ > = (args) => {
40
+ const style = {
41
+ maxWidth: "100%",
42
+ display: "block",
43
+ ...args.style,
44
+ };
45
+
46
+ return (
47
+ <ImagePrimitive
48
+ {...args}
49
+ optimize={true}
50
+ loader={imageLoader}
51
+ style={style}
52
+ />
53
+ );
54
+ };
55
+
56
+ /**
57
+ * Load images depending on image width and device per pixel ratio.
58
+ **/
59
+ export const FixedWidthImage: ComponentStory<React.FunctionComponent> = () => (
60
+ <ImageBase src={imageSrc} width="300" height="400" />
61
+ );
62
+
63
+ /**
64
+ * Preserve ratio using object-fit: cover. Load images depending on image width and device per pixel ratio.
65
+ **/
66
+ export const FixedWidthImageCover: ComponentStory<
67
+ React.FunctionComponent
68
+ > = () => (
69
+ <ImageBase
70
+ src={imageSrc}
71
+ width="300"
72
+ height="400"
73
+ style={{ objectFit: "cover" }}
74
+ />
75
+ );
76
+
77
+ /**
78
+ * Load images depending on the viewport width.
79
+ **/
80
+ export const UnknownWidthImage: ComponentStory<
81
+ React.FunctionComponent
82
+ > = () => <ImageBase src={imageSrc} />;
83
+
84
+ /**
85
+ * Fit width of the parent container, has own aspect-ratio and object-fit=cover.
86
+ * Load images depending on the viewport width.
87
+ **/
88
+ export const AspectRatioImage: ComponentStory<React.FunctionComponent> = () => (
89
+ <div style={{ width: "50%" }}>
90
+ <ImageBase
91
+ src={imageSrc}
92
+ style={{ aspectRatio: "2/1", objectFit: "cover", width: "100%" }}
93
+ />
94
+ </div>
95
+ );
96
+
97
+ /**
98
+ * Fill width and height of the relative parent container, object-fit=cover. Load images depending on the viewport width.
99
+ **/
100
+ export const FillParentImage: ComponentStory<React.FunctionComponent> = () => (
101
+ <div style={{ width: "50%", aspectRatio: "2/1", position: "relative" }}>
102
+ <ImageBase
103
+ src={imageSrc}
104
+ style={{
105
+ objectFit: "cover",
106
+ position: "absolute",
107
+ width: "100%",
108
+ height: "100%",
109
+ }}
110
+ />
111
+ </div>
112
+ );
113
+
114
+ /**
115
+ * "sizes" attribute explicitly equal to 100vw allowing to skip the default behavior.
116
+ * See DEFAULT_SIZES in the Image component. Load images depending on the viewport width.
117
+ **/
118
+ export const HeroImage: ComponentStory<React.FunctionComponent> = () => (
119
+ <ImageBase
120
+ src={imageSrc}
121
+ sizes="100vw"
122
+ style={{
123
+ aspectRatio: "3/1",
124
+ objectFit: "cover",
125
+ width: "100%",
126
+ }}
127
+ />
128
+ );