Skip to content

Commit fe1662b

Browse files
refactor(core)!: autoSizes owns resize tracking; vue/nuxt onCleanup
- autoSizes accepts { updateOnResize: true } and returns a disposer; an <img> argument walks to <source data-sizes="auto"> siblings in the same call. - triggerLoad is one-shot again - TriggerLoadOptions.updateSizesOnResize removed. - lazyLoad keeps updateSizesOnResize as a thin wrapper that delegates to autoSizes. - Drop resizeObserverCache; one disposer per call. - Vue/Nuxt switch to watchEffect((onCleanup) => …) per Vue 3.5+ idiom. - Fix stale picture-callback note in usage.md and stale triggerLoad reference in migration.md.
1 parent 83e8e6c commit fe1662b

14 files changed

Lines changed: 620 additions & 186 deletions

File tree

docs/api/auto-sizes.md

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
11
# `autoSizes`
22

3-
The `autoSizes` function calculates and sets the `sizes` attribute based on the current display width of image or source elements when `data-sizes="auto"` is present.
3+
The `autoSizes` function resolves `data-sizes="auto"` to a numeric pixel width based on the rendered display size. It works on standalone `<img>` elements, on `<source>` siblings inside a `<picture>`, or both.
44

5-
The calculation uses the element's rendered width (`element.offsetWidth`) to determine the appropriate value for the `sizes` attribute, enabling browsers to select the optimal image from a `srcset`.
5+
When called with an `<img>` inside a `<picture>`, `autoSizes` walks to every `<source data-sizes="auto">` sibling and resolves them in the same call. `<source>` elements have no layout box of their own, so the rendered `<img>` width is used instead.
66

77
To lazy load images, refer to the [`lazyLoad`](/api/lazy-load) method.
88

9+
## Options
10+
11+
| Option | Type | Default | Description |
12+
| --- | --- | --- | --- |
13+
| `updateOnResize` | `boolean` | `false` | Install a debounced `ResizeObserver` that re-resolves `data-sizes="auto"` on viewport changes. The returned disposer disconnects it. |
14+
15+
## Return Value
16+
17+
`autoSizes` returns a disposer. When called with `updateOnResize: false` (or no options), the disposer is a no-op. With `updateOnResize: true`, calling it disconnects every `ResizeObserver` created by that call:
18+
19+
```ts
20+
import { autoSizes } from 'unlazy'
21+
22+
const dispose = autoSizes('img[data-sizes="auto"]', { updateOnResize: true })
23+
24+
// Later, when cleaning up
25+
dispose()
26+
```
27+
928
## Type Declarations
1029

30+
<<< @/../packages/core/src/types.ts#AutoSizesOptions{ts}
31+
1132
<<< @/../packages/core/src/lazyLoad.ts#autoSizes{ts}
1233

1334
## Example
@@ -18,3 +39,17 @@ To lazy load images, refer to the [`lazyLoad`](/api/lazy-load) method.
1839
data-sizes="auto"
1940
>
2041
```
42+
43+
```ts
44+
import { autoSizes } from 'unlazy'
45+
46+
// One-shot resolve
47+
autoSizes()
48+
49+
// Or: resolve and keep tracking on resize
50+
const dispose = autoSizes(undefined, { updateOnResize: true })
51+
```
52+
53+
::: tip
54+
For most users, calling [`lazyLoad`](/api/lazy-load) with `updateSizesOnResize: true` is the simpler path – it delegates to `autoSizes` internally and bundles the disposer into the same cleanup callback.
55+
:::

docs/api/lazy-load.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Options can be passed to the function to customize its behavior:
3030
| `hash` | `boolean \| string` | `true` | Whether to use a hash for generating a blurry placeholder. Can be `true` (auto-detect from `data-blurhash`/`data-thumbhash`), `false` (disabled), or a hash string. |
3131
| `hashType` | `'blurhash' \| 'thumbhash'` | `'blurhash'` | The type of hash to use. Ignored when `hash` is boolean (auto-detected from data attributes). |
3232
| `placeholderSize` | `number` | `32` | The size of the longer edge for BlurHash decoding. Ignored for ThumbHash. |
33-
| `updateSizesOnResize` | `boolean` | `false` | Whether to update the `sizes` attribute on resize events using a debounced ResizeObserver. Useful for responsive layouts where image display size changes. |
33+
| `updateSizesOnResize` | `boolean` | `false` | Re-resolve `data-sizes="auto"` on viewport resize – applies to both `<img>` and `<source>` siblings inside a `<picture>`. Internally delegates to [`autoSizes`](/api/auto-sizes); the returned cleanup disconnects every observer. |
3434
| `onImageLoad` | `(image: HTMLImageElement) => void` | - | Callback invoked when an image loads successfully. |
3535
| `onImageError` | `(image: HTMLImageElement, error: Event) => void` | - | Callback invoked when an image fails to load. |
3636

docs/api/trigger-load.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
# `triggerLoad`
22

3-
The `triggerLoad` function programmatically loads an image by updating its attributes from data attributes. It handles both standalone `<img>` elements and images within `<picture>` elements.
3+
The `triggerLoad` function programmatically loads an image by swapping its data attributes to standard ones. It handles both standalone `<img>` elements and images inside `<picture>` elements.
44

55
The function performs the following operations:
66

7-
1. If the image is inside a `<picture>` element, updates all `<source>` elements by converting their `data-srcset` and `data-sizes` attributes to standard attributes synchronously. Callbacks fire after the browser resolves a source on the visible `<img>`.
7+
1. If the image is inside a `<picture>` element, swaps `data-srcset` to `srcset` on every `<source>` and resolves `data-sizes="auto"` to a numeric pixel width before the swap so the browser sees a final value at source-selection time. Callbacks fire after the browser resolves a source on the visible `<img>`.
88
2. For standalone `<img>` elements, preloads the image in a temporary element to ensure proper loading.
9-
3. Calculates the `sizes` attribute if `data-sizes="auto"` is set.
9+
3. Calculates the `sizes` attribute on the temporary element if `data-sizes="auto"` is set on the visible `<img>`.
1010
4. Swaps `data-src` and `data-srcset` to their standard counterparts.
1111
5. Invokes the optional `onImageLoad` callback when loading completes, or `onImageError` if loading fails. On failure, a synthetic `error` event also fires on the visible `<img>`.
1212

1313
`triggerLoad` returns a disposer that detaches its listeners and, for standalone images, aborts the in-flight network fetch. Calling it after the load has already completed is a no-op.
1414

15+
::: tip
16+
`triggerLoad` is one-shot – it does not install any `ResizeObserver`. For ongoing source-size tracking on responsive `<picture>` layouts, pair it with [`autoSizes`](/api/auto-sizes) and `{ updateOnResize: true }`:
17+
18+
```ts
19+
const disposeSizes = autoSizes(image, { updateOnResize: true })
20+
const disposeLoad = triggerLoad(image)
21+
22+
// Later
23+
disposeSizes()
24+
disposeLoad()
25+
```
26+
:::
27+
1528
## Type Declarations
1629

1730
<<< @/../packages/core/src/lazyLoad.ts#triggerLoad{ts}

docs/guide/migration.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ The deprecated `loadImage` alias is gone. Replace every call site with `triggerL
2525
+ // Optional: dispose() to cancel before the load completes
2626
```
2727

28+
### `autoSizes` Owns Ongoing Size Tracking
29+
30+
`triggerLoad` is one-shot again – it no longer accepts `updateSizesOnResize`. Ongoing re-resolution of `data-sizes="auto"` lives on [`autoSizes`](/api/auto-sizes), which now accepts `{ updateOnResize: true }` and returns a disposer:
31+
32+
```diff
33+
- triggerLoad(image, { updateSizesOnResize: true })
34+
+ const disposeSizes = autoSizes(image, { updateOnResize: true })
35+
+ const disposeLoad = triggerLoad(image)
36+
+ // Later: disposeSizes(); disposeLoad()
37+
```
38+
39+
For the common case, [`lazyLoad`](/api/lazy-load) keeps `updateSizesOnResize` and delegates to `autoSizes` internally – no caller change needed.
40+
41+
`autoSizes` itself now always returns a function. With no options, the returned disposer is a no-op; with `updateOnResize: true`, it disconnects every `ResizeObserver` created by the call. Passing an `<img>` inside a `<picture>` walks to every `<source data-sizes="auto">` sibling in the same call, replacing the previous need to invoke `autoSizes` separately on each source.
42+
2843
### `isLazyLoadingSupported` Removal
2944

3045
Native `loading="lazy"` is Baseline Widely Available; the feature-detect was used internally to fall back to immediate swap, and that branch is gone. If you imported the helper directly, replace it with:
@@ -93,6 +108,21 @@ Result: you can safely re-invoke `lazyLoad()` after inserting images into the DO
93108

94109
unlazy now warns in development when the LCP element is still configured for lazy loading. See the [Core Web Vitals guide](/guide/core-web-vitals#dev-mode-lcp-warning).
95110

111+
### `sources` Prop Across Adapters
112+
113+
The `sources` prop is no longer Nuxt-only. Every adapter now renders a `<picture>` when you pass an array of `UnLazySource` objects:
114+
115+
```ts
116+
import type { UnLazySource } from 'unlazy'
117+
118+
const sources: UnLazySource[] = [
119+
{ type: 'image/avif', srcSet: 'hero.avif 1x, hero@2x.avif 2x' },
120+
{ media: '(max-width: 600px)', srcSet: 'hero-mobile.jpg', width: 480, height: 640 },
121+
]
122+
```
123+
124+
Each entry becomes a `<source>` child with `type`, `media`, `width`, `height`, and `data-sizes="auto"` support. Pass `updateSizesOnResize: true` to [`lazyLoad`](/api/lazy-load) (or `{ updateOnResize: true }` directly to [`autoSizes`](/api/auto-sizes)) to re-resolve `<source data-sizes="auto">` siblings on viewport resize.
125+
96126
### Vue / Nuxt: `@image-load` and `@image-error` Emits
97127

98128
The Vue and Nuxt adapters now expose a symmetric pair of emits aligned with the core option names:

docs/guide/usage.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,26 @@ The automatic sizes calculation uses the display width of the image.
9595

9696
When calling [`lazyLoad`](/api/lazy-load), the library automatically calculates the `sizes` attribute for all images with `data-sizes="auto"`.
9797

98-
Alternatively, use the [`autoSizes`](/api/auto-sizes) function to calculate the `sizes` attribute without lazy loading.
99-
100-
To do so, import the [`autoSizes`](/api/auto-sizes) function from the library and call it:
98+
Alternatively, use the [`autoSizes`](/api/auto-sizes) function to calculate the `sizes` attribute without lazy loading. Call it with an `<img>` inside a `<picture>` and it walks to every `<source data-sizes="auto">` sibling in the same call:
10199

102100
```ts
103101
import { autoSizes } from 'unlazy'
104102

105-
// Automatically calculate the sizes attribute for all `img[data-sizes="auto"], source[data-sizes="auto"]` images, without lazy loading them
103+
// One-shot resolve for every matching element in the document
106104
autoSizes()
107105
```
108106

107+
For responsive layouts where the display width changes – fluid containers, breakpoint switches, orientation changes – pass `{ updateOnResize: true }` to keep `sizes` synced. `autoSizes` returns a disposer – call it when you no longer need the observer:
108+
109+
```ts
110+
const dispose = autoSizes(undefined, { updateOnResize: true })
111+
112+
// Later, when unmounting
113+
dispose()
114+
```
115+
116+
The same behavior is available on [`lazyLoad`](/api/lazy-load) via `updateSizesOnResize: true`, which delegates to `autoSizes` internally and bundles the disposer into the same cleanup callback.
117+
109118
## Custom Selectors
110119

111120
You can customize the CSS selectors to target specific images by passing a CSS selector, a DOM element, a list of DOM elements, or an array of DOM elements to [`lazyLoad`](/api/lazy-load) and [`autoSizes`](/api/auto-sizes).
@@ -170,8 +179,4 @@ unlazy fully supports the `<picture>` element for art direction and format selec
170179
</picture>
171180
```
172181

173-
When the image loads, unlazy automatically swaps `data-srcset` to `srcset` on all `<source>` elements within the `<picture>`.
174-
175-
::: info
176-
For `<picture>` elements, the `onImageLoad` and `onImageError` callbacks passed to `lazyLoad` aren't invoked, as the browser handles source selection internally.
177-
:::
182+
When the image loads, unlazy automatically swaps `data-srcset` to `srcset` on all `<source>` elements within the `<picture>`. The `onImageLoad` and `onImageError` callbacks fire once the browser resolves a source on the visible `<img>`.

0 commit comments

Comments
 (0)