Merge pull request #312 from reuters-graphics/mf-visible

Fixes rootMargin logic in `Visible`
This commit is contained in:
MinamiFunakoshiTR 2025-06-25 12:31:44 -05:00 committed by GitHub
commit 359ed2b032
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 76 additions and 41 deletions

View file

@ -0,0 +1,5 @@
---
'@reuters-graphics/graphics-components': patch
---
Updates Visible to allow unit specification for top, bototm, right, left and adds a demo

View file

@ -19,7 +19,8 @@ By default, `visible` will switch between `false` and `true` whenever the elemen
import { Visible } from '@reuters-graphics/graphics-components';
</script>
<Visible>
<!-- Optionally set your own `top`, `bottom`, `right` and `left` values with `px` or `%` units -->
<Visible top="10px">
{#snippet children(visible)}
{#if visible}
<p>Visible!</p>

View file

@ -2,6 +2,7 @@
import { defineMeta } from '@storybook/addon-svelte-csf';
import Visible from './Visible.svelte';
import VisibleDemo from './demo/VisibleDemo.svelte';
const { Story } = defineMeta({
title: 'Components/Utilities/Visible',
@ -9,14 +10,6 @@
});
</script>
<Story name="Demo" tags={['!autodocs', '!dev']}>
<Visible>
{#snippet children(visible)}
{#if visible}
<p>Visible!</p>
{:else}
<p>Not yet visible.</p>
{/if}
{/snippet}
</Visible>
<Story name="Demo">
<VisibleDemo />
</Story>

View file

@ -9,14 +9,14 @@
* Useful for loading expensive images or other media and then keeping them around once they're first loaded.
*/
once?: boolean;
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `top`. */
top?: number;
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `bottom`. */
bottom?: number;
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `left`. */
left?: number;
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `right`. */
right?: number;
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `top` with units. Units must be `px` or other [absolute lengths units](https://arc.net/l/quote/jkukcxqq), or `%`. */
top?: string;
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `bottom` with units. Units must be `px` or other [absolute lengths units](https://arc.net/l/quote/jkukcxqq), or `%`. */
bottom?: string;
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `left` with units. Units must be `px` or other [absolute lengths units](https://arc.net/l/quote/jkukcxqq), or `%`. */
left?: string;
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `right` with units. Units must be `px` or other [absolute lengths units](https://arc.net/l/quote/jkukcxqq), or `%`. */
right?: string;
/** Set the Intersection Observer [threshold](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#threshold). */
threshold?: number;
children?: Snippet<[boolean]>;
@ -24,10 +24,10 @@
let {
once = false,
top = 0,
bottom = 0,
left = 0,
right = 0,
top = '0px',
bottom = '0px',
left = '0px',
right = '0px',
threshold = 0,
children,
}: Props = $props();
@ -37,7 +37,7 @@
onMount(() => {
if (typeof IntersectionObserver !== 'undefined') {
const rootMargin = `${bottom}px ${left}px ${top}px ${right}px`;
const rootMargin = `${bottom} ${left} ${top} ${right}`;
const observer = new IntersectionObserver(
(entries) => {
@ -53,28 +53,18 @@
);
if (container) observer.observe(container);
return () => {
if (container) observer.observe(container);
if (container) observer.unobserve(container);
};
}
function handler() {
if (container) {
const bcr = container.getBoundingClientRect();
visible =
bcr.bottom + bottom > 0 &&
bcr.right + right > 0 &&
bcr.top - top < window.innerHeight &&
bcr.left - left < window.innerWidth;
}
if (visible && once) {
window.removeEventListener('scroll', handler);
}
}
window.addEventListener('scroll', handler);
return () => window.removeEventListener('scroll', handler);
});
</script>
<div bind:this={container}>
<div
bind:this={container}
class="visibility-tracker"
class:visible
class:not-visible={!visible}
>
{#if children}
{@render children(visible)}
{/if}

View file

@ -0,0 +1,46 @@
<script lang="ts">
import Visible from '../Visible.svelte';
import BodyText from '../../BodyText/BodyText.svelte';
import Block from '../../Block/Block.svelte';
import FeaturePhoto from '../../FeaturePhoto/FeaturePhoto.svelte';
import sharkSrc from '../../FeaturePhoto/images/shark.jpg';
let top = '150px';
const demoText =
'Take a look at the *Elements* tab in Inspector to see how the photo in the middle of the page appears in the DOM only when its container comes into view.';
let demoText2 = $derived(
`The top value for \`rootMargin\` is set to \`${top}px\` in this demo. Read about how \`rootMargin\` affects the <a href='https://codepen.io/michellebarker/full/xxwLpRG'>Intersection Observer's behaviour here</a>.`
);
const text =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
</script>
<BodyText text={`**${demoText}**`} />
<BodyText text={`**${demoText2}**`} />
<BodyText {text} />
<BodyText {text} />
<BodyText {text} />
<BodyText {text} />
<Visible {top} once={false}>
{#snippet children(visible)}
{#if visible}
<FeaturePhoto
src={sharkSrc}
altText="A shark!"
caption="Carcharodon carcharias - REUTERS"
/>
{:else}
<Block><h2>Not yet visible.</h2></Block>
{/if}
{/snippet}
</Visible>
<BodyText {text} />
<BodyText {text} />
<BodyText {text} />
<BodyText {text} />
<BodyText {text} />