Skip to content

Commit

Permalink
feat: support setting rootMargin for client:visible (#9363)
Browse files Browse the repository at this point in the history
* feat: support setting rootMargin for `client:visible`

This support adding optional `rootMargin` to the `IntersectionObserver` options.

This gives the developer the optional choice to hydrate a bit before the astro-island enters the viewport.

* chore: update type for client:visible

* chore: added changeset

* chore: update types

* fix: check if value is string

* Update stupid-peas-juggle.md

* fix: update .changeset/stupid-peas-juggle.md

Co-authored-by: Sarah Rainsberger <[email protected]>

---------

Co-authored-by: Florian Lefebvre <[email protected]>
Co-authored-by: Bjorn Lu <[email protected]>
Co-authored-by: Sarah Rainsberger <[email protected]>
  • Loading branch information
4 people authored Jan 3, 2024
1 parent f33fe31 commit 769826e
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 3 deletions.
10 changes: 10 additions & 0 deletions .changeset/stupid-peas-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'astro': minor
---

Extends the `client:visible` directive by adding an optional `rootMargin` property. This allows a component to be hydrated when it is close to the viewport instead of waiting for it to become visible.

```html
<!-- Load component when it's within 200px away from entering the viewport -->
<Component client:visible="200px" />
```
2 changes: 1 addition & 1 deletion packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export interface AstroBuiltinProps {
'client:load'?: boolean;
'client:idle'?: boolean;
'client:media'?: string;
'client:visible'?: boolean;
'client:visible'?: string|boolean;
'client:only'?: boolean | string;
}

Expand Down
8 changes: 6 additions & 2 deletions packages/astro/src/runtime/client/visible.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import type { ClientDirective } from '../../@types/astro.js';
* We target the children because `astro-island` is set to `display: contents`
* which doesn't work with IntersectionObserver
*/
const visibleDirective: ClientDirective = (load, _options, el) => {
const visibleDirective: ClientDirective = (load, options, el) => {
const cb = async () => {
const hydrate = await load();
await hydrate();
};

const ioOptions = {
rootMargin: typeof options.value === 'string' ? options.value : undefined,
};

const io = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue;
Expand All @@ -19,7 +23,7 @@ const visibleDirective: ClientDirective = (load, _options, el) => {
cb();
break; // break loop on first match
}
});
}, ioOptions);

for (const child of el.children) {
io.observe(child);
Expand Down

0 comments on commit 769826e

Please sign in to comment.