@massimo-cassandro/minimo 1.14.4 → 1.14.6
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/package.json
CHANGED
|
@@ -5,10 +5,13 @@ import { classnames } from './classnames.js';
|
|
|
5
5
|
/**
|
|
6
6
|
* @typedef {Object} PictureSizeEntry
|
|
7
7
|
* @property {number} [from] - Breakpoint (px) the size applies from (`width >=` media condition); omitted in the (single) mobile-first default entry.
|
|
8
|
-
* @property {number | [number, number]} size - Rendered width (px, height computed with `ratio
|
|
8
|
+
* @property {number | [number, number]} size - Rendered width (px, height computed with `ratio`, if set) or explicit `[width, height]` pair (px).
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
// TODO aggiungere compatibilità con immagini Unsplash basate su imgix
|
|
12
|
+
// TODO parametri viewer: le convenzioni attuali (`bb=WxH`, `bb=Wx` per il resize width-only,
|
|
13
|
+
// `q`, `fd`, `f`) sono legate al viewer interno; prevedere un meccanismo di astrazione
|
|
14
|
+
// per altri servizi con parametri diversi (es. imgix/Unsplash)
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* Creates a `picture` domBuilder item for an image rendered through the viewer.
|
|
@@ -20,7 +23,9 @@ import { classnames } from './classnames.js';
|
|
|
20
23
|
* `(width >= …)` media condition (range syntax).
|
|
21
24
|
*
|
|
22
25
|
* @example
|
|
23
|
-
* // fixed-width thumb (250px,
|
|
26
|
+
* // fixed-width thumb (250px, 1x and 2x candidates); with no `ratio` nor explicit
|
|
27
|
+
* // heights, the viewer gets a width-only resize (bb=250x) and the `img` has no
|
|
28
|
+
* // `height` attribute
|
|
24
29
|
* buildPictureTag({ baseSrc: 'https://img-viewer.example.com/abc123', alt: '…' });
|
|
25
30
|
* // sizes="250px", srcset="… 250w, … 500w"
|
|
26
31
|
*
|
|
@@ -55,15 +60,25 @@ import { classnames } from './classnames.js';
|
|
|
55
60
|
* // dev environment (no avif) and above-the-fold img (no loading="lazy")
|
|
56
61
|
* buildPictureTag({ baseSrc, devMode: true, lazy: false });
|
|
57
62
|
*
|
|
63
|
+
* @example
|
|
64
|
+
* // onLoad callback: reveal the image once it has finished loading
|
|
65
|
+
* buildPictureTag({
|
|
66
|
+
* baseSrc,
|
|
67
|
+
* imgExtraClass: 'img-loading',
|
|
68
|
+
* onLoad: img => img.classList.remove('img-loading'),
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
58
71
|
* @param {Object} args
|
|
59
72
|
* @param {string} args.baseSrc - Image base URL (viewer endpoint); its query params are preserved.
|
|
60
73
|
* @param {(number | [number, number] | PictureSizeEntry)[]} [args.sizes=[250]] - Rendered image sizes, in any order. Each entry is a `{from, size}` object (see {@link PictureSizeEntry}); a bare number or `[width, height]` pair is a shorthand for the mobile-first default entry (the one without `from`), expected exactly once.
|
|
61
|
-
* @param {number} [args.ratio=
|
|
74
|
+
* @param {number|null} [args.ratio=null] - Default aspect ratio (width / height, as in the CSS `aspect-ratio` property) used to compute the height of numeric sizes. When null, no height is computed: the height-related output (`height` attribute, height in the `bb` param) is omitted and the viewer preserves the image's own ratio.
|
|
62
75
|
* @param {number} [args.dpr=2] - Maximum pixel density (integer): `srcset` candidates are generated for every density from 1 to `dpr`.
|
|
63
|
-
* @param {[string, string|number][]} [args.img_params=[['q','60']
|
|
76
|
+
* @param {[string, string|number][]} [args.img_params=[['q','60']]] - Query params (`[name, value]` pairs) added to every generated URL.
|
|
64
77
|
* @param {string[]} [args.formats=['avif','webp','pjpg']] - Image formats: the last one is used for the `img` fallback element, the others for the `source` elements.
|
|
65
78
|
* @param {boolean} [args.devMode=false] - When true, `avif` is excluded from `formats` (not supported by the local dev environment).
|
|
66
79
|
* @param {boolean} [args.lazy=true] - When true, the `img` element gets `loading="lazy"`.
|
|
80
|
+
* @param {'high'|'low'|null} [args.fetchpriority=null] - `fetchpriority` attribute for the `img` element: use `high` for the LCP/above-the-fold image (typically with `lazy: false`). When null the attribute is omitted (browser default `auto`).
|
|
81
|
+
* @param {((img: HTMLImageElement) => void) | null} [args.onLoad=null] - Called once the image has finished loading, receiving the `img` element (called immediately if the image is already complete).
|
|
67
82
|
* @param {boolean} [args.condition=true] - When false, the function returns `null` without building anything.
|
|
68
83
|
* @param {boolean} [args.legacyMediaSyntax=false] - When true, the `sizes` media conditions use `(min-width: …)` instead of the range syntax `(width >= …)`, for older browsers (pre Chrome/Edge 104, Firefox 102, Safari 16.4).
|
|
69
84
|
* @param {string|null} [args.pictureExtraClass=null] - Extra class(es) for the `picture` element.
|
|
@@ -76,12 +91,14 @@ import { classnames } from './classnames.js';
|
|
|
76
91
|
export function buildPictureTag({
|
|
77
92
|
baseSrc,
|
|
78
93
|
sizes = [250],
|
|
79
|
-
ratio =
|
|
94
|
+
ratio = null,
|
|
80
95
|
dpr = 2,
|
|
81
96
|
img_params = [ ['q', '60'] ],
|
|
82
97
|
formats = ['avif', 'webp', 'pjpg'],
|
|
83
98
|
devMode = false,
|
|
84
99
|
lazy = true,
|
|
100
|
+
fetchpriority = null,
|
|
101
|
+
onLoad = null,
|
|
85
102
|
condition = true,
|
|
86
103
|
legacyMediaSyntax = false,
|
|
87
104
|
pictureExtraClass = null,
|
|
@@ -107,14 +124,14 @@ export function buildPictureTag({
|
|
|
107
124
|
const dprList = Array.from({length: dpr}, (_, i) => i + 1);
|
|
108
125
|
|
|
109
126
|
// entry di `sizes` normalizzate in oggetti {from, width, height}
|
|
110
|
-
// (per le size numeriche l'altezza è calcolata con `ratio
|
|
127
|
+
// (per le size numeriche l'altezza è calcolata con `ratio`, se presente, altrimenti è null),
|
|
111
128
|
// ordinate per breakpoint, con il default (from = null) per primo
|
|
112
129
|
const sizeEntries = sizes.map(entry => {
|
|
113
130
|
if(typeof entry === 'object' && !Array.isArray(entry)) {
|
|
114
|
-
const [width, height] = Array.isArray(entry.size)? entry.size : [entry.size, Math.floor(entry.size / ratio)];
|
|
131
|
+
const [width, height] = Array.isArray(entry.size)? entry.size : [entry.size, ratio == null? null : Math.floor(entry.size / ratio)];
|
|
115
132
|
return { from: entry.from ?? null, width, height };
|
|
116
133
|
}
|
|
117
|
-
const [width, height] = Array.isArray(entry)? entry : [entry, Math.floor(entry / ratio)];
|
|
134
|
+
const [width, height] = Array.isArray(entry)? entry : [entry, ratio == null? null : Math.floor(entry / ratio)];
|
|
118
135
|
return { from: null, width, height };
|
|
119
136
|
}).sort((a, b) => (a.from ?? 0) - (b.from ?? 0));
|
|
120
137
|
|
|
@@ -133,7 +150,7 @@ export function buildPictureTag({
|
|
|
133
150
|
// dimensioni dei candidati srcset (una per ogni densità da 1 a `dpr`),
|
|
134
151
|
// senza duplicati (per larghezza), in ordine crescente
|
|
135
152
|
,srcsetSizes = sizeEntries
|
|
136
|
-
.flatMap(({width, height}) => dprList.map(d => /** @type {[number, number]} */ ([width * d, height * d])))
|
|
153
|
+
.flatMap(({width, height}) => dprList.map(d => /** @type {[number, number|null]} */ ([width * d, height == null? null : height * d])))
|
|
137
154
|
.filter((pair, idx, arr) => arr.findIndex(p => p[0] === pair[0]) === idx)
|
|
138
155
|
.sort((a, b) => a[0] - b[0])
|
|
139
156
|
|
|
@@ -184,7 +201,8 @@ export function buildPictureTag({
|
|
|
184
201
|
searchParams.set('f', fmt);
|
|
185
202
|
|
|
186
203
|
srcsetSizes.forEach(([w, h]) => {
|
|
187
|
-
|
|
204
|
+
// TODO senza altezza `bb=<w>x` vale per questo viewer: prevedere altre convenzioni (es. imgix)
|
|
205
|
+
searchParams.set('bb', `${w}x${h ?? ''}`);
|
|
188
206
|
base_url.search = searchParams.toString();
|
|
189
207
|
srcsetArray.push(`${base_url.toString()} ${w}w`);
|
|
190
208
|
});
|
|
@@ -202,8 +220,18 @@ export function buildPictureTag({
|
|
|
202
220
|
width: imgWidth,
|
|
203
221
|
height: imgHeight,
|
|
204
222
|
loading: lazy? 'lazy' : null,
|
|
223
|
+
decoding: 'async',
|
|
224
|
+
fetchpriority: fetchpriority,
|
|
205
225
|
...imgExtraAttrs
|
|
206
226
|
},
|
|
227
|
+
callback: onLoad == null? undefined : el => {
|
|
228
|
+
const img = /** @type {HTMLImageElement} */ (el);
|
|
229
|
+
if(img.complete) {
|
|
230
|
+
onLoad(img);
|
|
231
|
+
} else {
|
|
232
|
+
img.addEventListener('load', () => onLoad(img), {once: true});
|
|
233
|
+
}
|
|
234
|
+
},
|
|
207
235
|
// TODO classe popover, se attivato
|
|
208
236
|
// callback: options.addPopover
|
|
209
237
|
// ? el => el.addEventListener('click', () => zoomPopoverEl.togglePopover())
|