GithubHelp home page GithubHelp logo

maciekgrzybek / svelte-inview Goto Github PK

View Code? Open in Web Editor NEW
732.0 8.0 19.0 3.27 MB

A Svelte action that monitors an element enters or leaves the viewport.๐Ÿ”ฅ

License: MIT License

JavaScript 8.72% TypeScript 75.99% HTML 4.24% Svelte 11.05%
hacktoberfest svelte observer intersectionobserver intersection-observer javascript intersectionobserver-api svelte3 svelte-js svelte-component

svelte-inview's Introduction

Svelte Inview

A Svelte action that monitors an element enters or leaves the viewport/parent element. Performant and efficient thanks to using Intersection Observer under the hood. Can be used in multiple projects including lazy loading images, infinite scrolling, playing/pausing the video when in the viewport, tracking user behaviour firing link pre-fetching and animations and many many more.

๐Ÿ”ฅ Check it out live here

Support if you like it โ˜• ๐Ÿ”ฅ
"Buy Me A Coffee"

Why bother?

  • ๐Ÿ‘“๏ธ Watch for any element that enters or leaves the viewport (or another wrapper/parent element).
  • ๐ŸŽ๏ธ Thanks to using Intersection Observer, Svelte Inview is blazing fast and doesn't block the main thread.
  • ๐Ÿ“ฆ๏ธ Tiny, yet powerful (just ~2kb). No external dependencies (well, apart from Svelte).
  • ๐ŸŽ›๏ธ Use it in several different scenarios such as lazy loading images, infinite scrolling, playing/pausing the video when in the viewport, firing link pre-fetching, animations and many many more.
  • ๐Ÿฅ Easy to use API.
  • โ†•๏ธ Detects the scrolling direction.

Installation

The only thing you need is Svelte itself.

Svelte Inview is distributed via npm.

$ yarn add svelte-inview
# or
$ npm install --save svelte-inview

โš ๏ธ Modern browsers have the full support of Intersection Observer, but if you need to support ones like IE you can use this simple polyfill. Just install it and import it in your project.

Usage

Basic Use Case

This is the most basic use case for svelte-inview. Just add the action to the element you want to track - use:inview. You can also pass other configuration props. You can see if the element is visible by checking the inView or from the inside of the callback method - on:inview_change.

<script lang="ts">
  import { inview } from 'svelte-inview';

  let isInView: boolean;
  const options = {};
</script>

  <div
    use:inview={options}
    on:inview_change={(event) => {
      const { inView, entry, scrollDirection, observer, node} = event.detail;
      isInView = inView;
    }}
    on:inview_enter={(event) => {
      const { inView, entry, scrollDirection, observer, node} = event.detail;
      isInView = inView;
    }}
    on:inview_leave={(event) => {
      const { inView, entry, scrollDirection, observer, node} = event.detail;
      isInView = inView;
    }}
    on:inview_init={(event) => {
      const { observer, node } = event.detail;
    }}>{isInView ? 'Hey I am in the viewport' : 'Bye, Bye'}</div>

Lazy Loading Images

Svelte Inview lets you easily lazy load images. For a better UX we can pass a rootMargin="50px" props, so the image will be loaded when scroll is 50px before the viewport. After it appears in the viewport, you don't want to observe it anymore, hence the unobserveOnEnter props set to true.

<script lang="ts">
  import { inview } from 'svelte-inview';
  import type { ObserverEventDetails, Options } from 'svelte-inview';

  let isInView;
  const options: Options = {
    rootMargin: '50px',
    unobserveOnEnter: true,
  };

  const handleChange = ({ detail }: CustomEvent<ObserverEventDetails>) =>
    (isInView = detail.inView);
</script>

<div use:inview="{options}" on:inview_change="{handleChange}">
  {#if isInView}
  <img src="path/to/image.jpg" />
  {:else}
  <div class="placeholder" />
  {/if}
</div>

Video Control

You can play/pause a video when it's in/out of the viewport. Simply pass correct methods in on:inview_enter and on:inview_leave callbacks.

<script lang="ts">
  import { inview } from 'svelte-inview';
  import type { ObserverEventDetails } from 'svelte-inview';

  let isInView: boolean;
  let videoRef: HTMLElement;
</script>

  <div
    use:inview
    on:inview_enter={() => videoRef.play()}
    on:inview_leave={() => videoRef.pause()}
  >
    <video width="500" controls bind:this={videoRef}>
      <source src="path/to/video.mp4" type="video/mp4" />
    </video>
  </div>

Animations

You can also add some cool animations when an element enters the viewport. To make sure the animation won't fire too soon you can pass a negative value to rootMargin. When inView is true, add an animation class to your target. Additionally, you can detect the scroll direction to make the animations even cooler!

<script lang="ts">
  import { inview } from 'svelte-inview';
  import type { ObserverEventDetails, ScrollDirection, Options } from 'svelte-inview';

  let isInView: boolean;
  let scrollDirection: ScrollDirection;
  const options: Options = {
    rootMargin: '-50px',
    unobserveOnEnter: true,
  };

  const handleChange = ({ detail }: CustomEvent<ObserverEventDetails>) => {
    isInView = detail.inView;
    scrollDirection = detail.scrollDirection.vertical;
  };
</script>

  <div use:inview={options} on:inview_change={handleChange}>
    <div
      class:animate={isInView}
      class:animateFromBottom={scrollDirection === 'down'}
      class:animateFromTop={scrollDirection === 'up'}>
      Animate me!
    </div>
  </div>

Important information about breaking changes in previous versions

Version 4 introduces new names for events. Before they were 'change' | 'leave' | 'enter' | 'init'. In version 4 they're changed to 'inview_change' | 'inview_leave' | 'inview_enter' | 'inview_init'.

This change was needed to satisfy Typescript, as the package was messing up the default types coming from svelte typings. To ensure backward compatibility, the original events names will still work for some time, but they won't be properly recognized by Typescript. To sum up, this will still work, but TS won't be happy about it:

on:change={(event) => {
  const { inView, entry, scrollDirection, observer, node} = event.detail;
  isInView = inView;
}}

To make sure it works properly and satisfy TS you'll need to change it to this:

on:inview_change={(event) => {
  const { inView, entry, scrollDirection, observer, node} = event.detail;
  isInView = inView;
}}

Version 2 was returning observe and unobserve methods on the events. In version 3 they were removed, and the observer and node are being returned instead. So if you used those methods before like this:

event.detail.observe(node);

You'll need to change it to:

event.detail.observer.observe(node);

Version 1 was using an Inview component. In version 2 that was changed to action - API is easier to consume, plus the obsolete wrapper is not longer needed. If you still want to use the component, check the documentation for version 1.

API

Props

Name Type Default Description Required
options.root HTMLElement window The element that is used as the viewport for checking visibility of the target. Must be the ancestor of the target. false
options.rootMargin string 0px Margin around the root element. Values similar to the CSS margin property, e.g. "10px 20px 30px 40px". Can also be a percentage. See more. false
options.threshold number or number[] 0 Either a single number or an array of numbers which indicate at what percentage of the target's visibility the observer's callback should be executed. If you only want to detect when visibility passes the 50% mark, you can use a value of 0.5. If you want the callback to run every time visibility passes another 25%, you would specify the array [0, 0.25, 0.5, 0.75, 1]. The default is 0 (meaning as soon as even one pixel is visible, the callback will be run) false
options.unobserveOnEnter boolean false If true, target element stops being observed after the first time it appears in the viewport. Can be used when you want to fire the callback only once. false
on:inview_change function - Event fired every time the target element meets the specified threshold. Receives event object as an argument. Inside of event.detail you can find all the arguments specified here. false
on:inview_enter function - Event fired every time the target element enters the viewport. Receives event object as an argument. Inside of event.detail you can find all the arguments specified here . false
on:inview_leave function - Event fired every time the target element leaves the viewport. Receives event object as an argument. Inside of event.detail you can find all the arguments specified here . false
on:inview_init function - Event fired on action initialization, before the observer starts observing the element. Receives lifecycle arguments specified here false

Observer events arguments

Name Type Description
inView boolean Visibility state of the target element. If it's true, target passed at least the value of the threshold props.
entry IntersectionObserverEntry Intersection Observer entry object generated every time when IO callback is fired.
scrollDirection.vertical up or down Vertical scrolling direction.
scrollDirection.horizontal left or right Horizontal scrolling direction.
node HTMLElement Element that is being observed
observer IntersectionObserver Intersection Observer instance for the observed element. Among others, it allows to "turn off" the observer at the very beginning.

Lifecycle events arguments

Name Type Description
node HTMLElement Element that is being observed
observer IntersectionObserver Intersection Observer instance for the observed element. Among others, it allows to "turn off" the observer at the very beginning.

Additional Info

Usage with rootMargin

If you want to increase or decrease the area of the root, just pass the rootMargin. On the image below you can see the blue area being the root. It means that every time, the target element will enter or leave that area (or meet the specified threshold), a callback will be fired.

Usage of rootMargin

License

Distributed under the MIT License. See LICENSE for more information.

Contact

Maciek Grzybek - @grzybek_maciek - [email protected] - www.maciekgrzybek.dev

svelte-inview's People

Contributors

maciekgrzybek avatar mindvoxel avatar nosovk avatar oekazuma avatar phocks avatar timsully avatar trombach avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

svelte-inview's Issues

Netlify Deploy Issue v4

Hi me again,

I'm having some issues deploying my app to Netlify. I get the following error:

pnpm run build

[vite-plugin-pwa:build] Failed to resolve entry for package "svelte-inview". The package may have incorrect main/module/exports specified in its package.json.
10:51:07 PM: error during build:
10:51:07 PM: Error: Failed to resolve entry for package "svelte-inview". The package may have incorrect main/module/exports specified in its package.json.
10:51:07 PM:     at packageEntryFailure (file:///opt/build/repo/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-3007b26d.js:22004:11)
10:51:07 PM:     at resolvePackageEntry (file:///opt/build/repo/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-3007b26d.js:22001:5)
10:51:07 PM:     at tryNodeResolve (file:///opt/build/repo/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-3007b26d.js:21736:20)
10:51:07 PM:     at Object.resolveId (file:///opt/build/repo/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-3007b26d.js:21487:28)
10:51:07 PM:     at Object.handler (file:///opt/build/repo/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-3007b26d.js:44852:19)
10:51:07 PM:     at file:///opt/build/repo/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:23785:40
10:51:07 PM:     at async PluginDriver.hookFirstAndGetPlugin (file:///opt/build/repo/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:23685:28)
10:51:07 PM:     at async resolveId (file:///opt/build/repo/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:22629:26)
10:51:07 PM:     at async ModuleLoader.resolveId (file:///opt/build/repo/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:22893:15)
10:51:07 PM:     at async Object.resolveId (file:///opt/build/repo/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-3007b26d.js:7972:10)
10:51:07 PM: โ€‰ELIFECYCLEโ€‰ Command failed with exit code 1. (https://ntl.fyi/exit-code-1)

I cannot tell if this is an issue with this library or something else. Mind you it seems to build locally. So I don't know if this is an issue with Netlify or if its using slightly different env variables to what I expect.

Thanks

Related MR: https://gitlab.com/bookmarkey/gui/-/merge_requests/125

on:enter called immediately on page load

Hi there!

Noticed the on:enter is being right when the page loads; and this makes it so unobserveOnEnter.
Additionally, I tried putting rootMargin:'50px' and that did not work.

Since the event is called right away, it breaks functions that require a one-time accurate call of the intersection.

Thanks!

Visiting page directly using Inview with SSR behaves differently

I have a hunch this is a problem with the newer version of svelte...

I haven't figured it out so wanted to document the issue here.

package.json:

	"devDependencies": {
		"@inlang/paraglide-js": "1.2.2",
		"@inlang/paraglide-js-adapter-sveltekit": "^0.2.5",
		"@playwright/test": "^1.41.1",
		"@sveltejs/adapter-vercel": "^5.1.0",
		"@sveltejs/kit": "^2.5.0",
		"@types/cookie": "^0.6.0",
		"eslint": "^8.56.0",
		"eslint-config-prettier": "^9.1.0",
		"eslint-plugin-svelte": "^2.35.1",
		"prettier": "^3.2.4",
		"prettier-plugin-svelte": "^3.1.2",
		"svelte": "^4.2.9",
		"svelte-check": "^3.6.3",
		"svelte-inview": "^4.0.2",
		"svelte-preprocess": "^5.1.3",
		"typescript": "^5.3.3",
		"vite": "^5.0.12",
		"vitest": "^1.2.2",
		"web-vitals": "^3.5.2"
	},

Using latest versions of things...

If you load the page as production directly, this code breaks (the Grid toggle buttons no longer function):

src/lib/components/InviewSrcset.svelte:

<script lang="ts">
	import { inview } from 'svelte-inview';
	import { createEventDispatcher } from 'svelte';
	import Srcset from '$lib/components/Srcset.svelte';

	let ref: HTMLOrSVGElement;
	export let src: string;

	const dispatch = createEventDispatcher();
</script>

<div
	use:inview={{ threshold: 0.5 }}
	on:enter={({ detail }) =>
		dispatch('entry', {
			verticalDirection: detail.scrollDirection.vertical,
			src
		})}
>

    <Srcset
        src={src}
        alt=""
        width="640"
        height="480"
        widths={[640, 960]}
        sizes="(max-width: 640px) 640px, 960px"
        quality={80}
        lazy={true}
        decoding="async"
        bind:this={ref}
    />
</div>

src/routes/photos/+page.svelte:

<script>
	import * as m from '$paraglide/messages';
	import Highlight from '$lib/components/Highlight.svelte';
	import InviewSrcset from '$lib/components/InviewSrcset.svelte';

	let gridenabled = false;

	const yesGridEnabled = () => gridenabled = true;
	const notGridEnabled = () => gridenabled = false;
</script>

<svelte:head>
	<title>{m.pageNamePhotos()}</title>
</svelte:head>

<div>
	<Highlight text={m.pageNamePhotos()} />

	<div class="buttons">
		<button class="button" class:active={!gridenabled} on:click={notGridEnabled}
			>Full View</button
		>
		<button class="button" class:active={gridenabled} on:click={yesGridEnabled}
			>Grid View</button
		>
	</div>

	<div class="grid" class:gridenabled>
		{#each { length: 30 } as _, i}
			<InviewSrcset src="/images/photos/{i + 1}.jpg" />
		{/each}
	</div>
</div>

<style>
	.gridenabled {
		display: grid;
		grid-gap: 0.5rem;
		grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
	}

	@media only screen and (max-width: 974px) {
		.buttons {
			display: none;
		}
	}

	.grid :global(img) {
		width: auto;
		height: auto;
		margin: auto;
		max-width: 100%;
		border-radius: 5px;
		/* border: 4px solid transparent; */
		box-shadow: 0 3px 5px -3px #000;
		background-color: var(--color-bg-3);
	}

	.button:not(.active) {
		cursor: pointer;
		background-color: gray;
	}

	.buttons {
		cursor: default;
		text-align: center;
	}

	.button {
		border: none;
		color: #ffffff;
		position: relative;
		text-align: center;
		padding: 0.7em 1.4em;
		display: inline-block;
		border-radius: 0.15em;
		text-decoration: none;
		box-sizing: border-box;
		margin: 0 0.3em 1em 0;
		text-transform: uppercase;
		background-color: green;
		box-shadow: inset 0 -0.6em 0 -0.35em rgba(0, 0, 0, 0.17);
	}
	.button:active {
		top: 0.1em;
	}
</style>

However, the code is fine using dev.

The code also is fine in prod if you visit the home page first before the page using Inview...

Here is an HTML difference from dev to prod:

Dev:

<div class="buttons s-KG-x8XkR0-JV"><button class="button s-KG-x8XkR0-JV active">Full View</button> <button class="button s-KG-x8XkR0-JV">Grid View</button></div>

Prod direct:

<div class="buttons svelte-h8u9lh"><button class="button svelte-h8u9lh active" data-svelte-h="svelte-1ckqtup">Full View</button> <button class="button svelte-h8u9lh" data-svelte-h="svelte-1om8nfn">Grid View</button></div>

Prod home then photos page:

<div class="buttons svelte-h8u9lh"><button class="button svelte-h8u9lh active">Full View</button> <button class="button svelte-h8u9lh">Grid View</button></div>

It is not clear why visiting the photos page directly causes the data-svelte-h="svelte-1ckqtup" but I assume it must be an SSR issue. If anyone has a had this issue please let me know what I should try.

Write tests

Currently, this project doesn't have any tests. The plan is to add either:

  • e2e tests with Cypress or something similar
  • classic unit tests (less safe as Intersection Observer will have to be mocked)

Uncaught TypeError: Cannot read property 'unobserveOnEnter' of undefined

Hello!

I'm noticing the following error when the user scrolls out of focus for an item:

image

I don't have an on:leave event, code is basically:

<div use:inview on:enter={({ detail: { inView } }) => (isInView = inView)}>
  {#if isInView}
    Stuff here...
  {/if}
</div>

Using latest version.

Any idea why this is occurring?

"inview_change" doesn't work for after updating from 3.0.4 to 4.0.0

I tried updating the package to the latest version, and when I changed "on:change" to "on:inview_change", it stopped working. Changing back to "on:change" made this work normally (but there are a lot of type errors as expected). I tried to console.log() the handleChange() function that's used for "on:inview_change" but it seems like the function doesn't run at all. I just tried copying what was on the docs btw

Animating elements on the same line

Hi, thanks for this helpful svelte component.
It seems that elements are ignored when they share Y position with other. In other words if you have 2

on the same line, only one will be animated. I'll start digging in the codebase to see if I can detect the reason.

Export type definitions

Hey,

first of all - pretty cool Svelte component, thanks for sharing it! :)

One issue I have, though, is that the package doesn't seem to expose the type definitions you wrote, so my compiler is giving me warnings on import and even a false error when using any of the on:-actions:

(JSX attribute) onenter: () => void
Type '{ onenter: () => void; }' is not assignable to type 'HTMLProps'.
Property 'onenter' does not exist on type 'HTMLProps'.ts(2322)

It'd be neat if you could export your type definitions so it's compatible with TypeScript projects out of the box.

Binding element 'detail' implicitly has an 'any' type.ts(7031)

Hey, I'm trying to use the provided animation example but I'm getting multiple errors.
The detail element throws the error in the title and on:change is throwing the following error:

Type '({ detail }: { detail: any; }) => void' is not assignable to type 'FormEventHandler<HTMLDivElement>'.
Types of parameters '__0' and 'event' are incompatible.
Property 'detail' is missing in type 'Event & { currentTarget: EventTarget & HTMLDivElement; }' but required in type '{ detail: any; }'.
ts(2322)

finally, the class:animate{inView} just gives me an error that inView is not defined.

Sorry if this has an obvious solution, I couldn't find anything online and am still a little too new to programming to fully understand the error messages.

Thanks!

Another Typescript issue

Hi, thanks for the great code. It is working great.

However, I'm still getting Typescript errors, despite trying everything mentioned in the docs and other issues:

Type '{ onleave: ({ detail }: CustomEvent<ObserverEventDetails>) => void; }' is not assignable to type 'HTMLProps<HTMLDivElement>'.
  Property 'onleave' does not exist on type 'HTMLProps<HTMLDivElement>'.

My code is basically this:

<script lang="ts">
  import type { ObserverEventDetails } from 'svelte-inview'
  import { inview } from 'svelte-inview'

  let state = false

  const leaveHandler = ({ detail }: CustomEvent<ObserverEventDetails>) => {
    if (detail.scrollDirection.vertical === 'up') state = true
  }
</script>

<div use:inview on:leave={leaveHandler}>
  Hello {state}
</div>

I notice in your Typescript definitions that "on:leave" is set for HTMLAttributes. But I'm not sure how this ends up as "onleave" for HTMLProps.

Any ideas? Not a showstopper, just an annoyance. Thanks for any help.

Support Svelte v4

Currently Svelte is listed as a peerDependency with version ^3.0.0. It would be nice to start testing with Svelte 4 (beta) to check if there's any breaking changes. If all works, maybe v4 can be added to the list of supported peerDependencies.

Many IntersectObserver object created

I have been looking into code and if I understand code correctly new IntersectObserver is created for every component, that has inview action.

My scenario has one root element which has many (thousands) of child elements/components , which lazy load an image, when they get into view.

As per this article: https://www.bennadel.com/blog/3954-intersectionobserver-api-performance-many-vs-shared-in-angular-11-0-5.htm it looks that there is notable performance advantage for single IntersectObserver having many observed elements, comparing to many IntersectObservers, each one just with one observed element.

What do you think?

2.0.0 is broken in sveltekit?

Hi,

I tried the new version with the docs but I don't have success with it.

The message a received:

Importing binding name 'inview' is not found.`

I try:

import { inview } from 'svelte-inview';
console.log(inview);

And it returns undefined.

The demo on https://svelte-inview.netlify.app is also broken.

proposal: onInit callback

i would like to propose an additional method to setup initial values.

use case

the use case is for animation. consider that i want to animate some stuff into the view by changing opacity and translateY. I am currently using sal.js and first set the opacity to 0 so that i actually see the items fading in (not using css because then people with js disabled will be unhappy)

of course i can also do this with your library, but it would be nice to have this coupled to the dom element instead of just at the top of the onMount method. do you agree?

additional function

In addition one could maybe also think about returning false or true in that callback method and on false remove the observer again. the use case here would be to check for reducedmotion setting of the users browser and then return false so that neither the initial setting (opacity=0) nor the observer is set.

example

<script>
  import { inview } from 'svelte-inview';

  let isInView;
  const options = {
    rootMargin: '-50px',
    unobserveOnEnter: true,
  };
  const handleInit = ()=>{
    const isReduced = window.matchMedia(`(prefers-reduced-motion: reduce)`) === true || window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true;
    if(isReduced) return false; //of course this could also be something for a global inview function, or even a reactive variable just passed to inview options
    else {
      //do something like setting opacity to 0 to init animation
    }
    return true;
  }
  const handleEnter = ({ detail }) => {
    //animate me
  };
</script>

<div use:inview={options} on:init={handleInit} on:enter={handleEnter}>

of course there is also a way to do this with CSS alone. i just picked it because of simplicity. but if my little example uses a fancy js animation library, then again it would make sense.

Error: Could not resolve './inview'

Hi, I'm trying to use this component but have been getting the error below. I've tried reinstalling (deleted node_modules and package-lock.json) and also tried npm install --legacy-peer-deps. They didn't fix the problem.

Appreciate any help anyone can provide! Thanks!

โžœ  yourfeed-frontend git:(main) โœ— npm run dev

> [email protected] dev
> rollup -c -w

rollup v2.56.3
bundles src/main.js โ†’ public/build/bundle.js...
[!] Error: Could not resolve './inview' from node_modules/svelte-inview/src/index.ts
Error: Could not resolve './inview' from node_modules/svelte-inview/src/index.ts
    at error (../node_modules/rollup/dist/shared/rollup.js:151:30)
    at ModuleLoader.handleResolveId (../node_modules/rollup/dist/shared/rollup.js:19862:24)
    at ../node_modules/rollup/dist/shared/rollup.js:19856:26

Here's my package.json:

{
  "name": "svelte-app",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w",
    "start": "sirv public --single"
  },
  "devDependencies": {
    "@iconify/icons-bi": "^1.1.6",
    "@iconify/icons-bx": "^1.1.2",
    "@iconify/icons-ic": "^1.1.11",
    "@iconify/svelte": "^2.0.0",
    "@rollup/plugin-commonjs": "^17.0.0",
    "@rollup/plugin-node-resolve": "^11.0.0",
    "rollup": "^2.3.4",
    "rollup-plugin-css-only": "^3.1.0",
    "rollup-plugin-livereload": "^2.0.0",
    "rollup-plugin-svelte": "^7.0.0",
    "rollup-plugin-terser": "^7.0.0",
    "svelte": "^3.0.0",
    "tinro": "^0.6.6"
  },
  "dependencies": {
    "sirv-cli": "^1.0.0",
    "svelte-file-dropzone": "^0.0.15",
    "svelte-infinite-loading": "^1.3.6",
    "svelte-inview": "^2.0.1"
  }
}

rollup.config.js

import svelte from 'rollup-plugin-svelte';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import css from 'rollup-plugin-css-only';

const production = !process.env.ROLLUP_WATCH;

function serve() {
	let server;

	function toExit() {
		if (server) server.kill(0);
	}

	return {
		writeBundle() {
			if (server) return;
			server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
				stdio: ['ignore', 'inherit', 'inherit'],
				shell: true
			});

			process.on('SIGTERM', toExit);
			process.on('exit', toExit);
		}
	};
}

export default {
	input: 'src/main.js',
	output: {
		sourcemap: true,
		format: 'iife',
		name: 'app',
		file: 'public/build/bundle.js'
	},
	plugins: [
		svelte({
			compilerOptions: {
				// enable run-time checks when not in production
				dev: !production
			}
		}),
		css({ output: 'bundle.css' }),

		resolve({
			browser: true,
			dedupe: ['svelte']
		}),
		commonjs(),
		!production && serve(),
		!production && livereload('public'),
		production && terser()
	],
	watch: {
		clearScreen: false
	}
};

"TypeError: 'observe' called on an object that does not implement interface IntersectionObserver." when calling event.detail.observe()

Hello, I'm getting a TypeError when calling the event.detail.observer() function in an inview event callback:

Uncaught (in promise) TypeError: 'observe' called on an object that does not implement interface IntersectionObserver.

Context
I use svelte-inview handleOnEnter to start an async function myAsyncFunction. Only 1 instance of myAsyncFunction should run at a time. So I thought about setting props={unobserverOnEnter: true} and then calling the event.detail.observe() method after myAsyncFunction is finished. This would disable the observer while myAsyncFunction is running and afterwards start observing again.

function handleOnEnter(event) {
    myAsyncFunction().then(() => {
        event.detail.observe(); // start observing the div again (this call results in the error)
    }
}

<div use:inview={{unobserveOnEnter: true}} on:enter={handleOnEnter} />

I'm not sure whether it's an issue or maybe I just misunderstood the event.detail.observe function.

Thanks for the great package and kind regards
Stijn

TypeScript error in 4.0.0

Hi, since the event name changed from on:change to on:inview_change, TypeScript doesn't seem to recognize it any more and displays an error:

Argument of type '{ class: string; "on:inview_change": ({ detail }: any) => void; }' is not assignable to parameter of type 'Omit<Omit<HTMLAttributes<HTMLDivElement>, "data-sveltekit-keepfocus" | "data-sveltekit-noscroll" | "data-sveltekit-preload-code" | "data-sveltekit-preload-data" | ... 49 more ... | "aria-valuetext"> & EventsWithColon<...>, keyof HTMLAttributes<...>> & HTMLAttributes<...>'.
  Object literal may only specify known properties, and '"on:inview_change"' does not exist in type 'Omit<Omit<HTMLAttributes<HTMLDivElement>, "data-sveltekit-keepfocus" | "data-sveltekit-noscroll" | "data-sveltekit-preload-code" | "data-sveltekit-preload-data" | ... 49 more ... | "aria-valuetext"> & EventsWithColon<...>, keyof HTMLAttributes<...>> & HTMLAttributes<...>'.ts(2345)
No quick fixes available

Is there some way to work around this? I'm using TypeScript 5.0.

missing license

Hi there! There's no license file on the repo even if README.md says

Distributed under the MIT License. See LICENSE for more information.

Thank you for your work ๐Ÿ™

Maybe use `tick()`

// This dispatcher has to be wrapped in setTimeout, as it won't work otherwise.
// Not sure why is it happening, maybe a callstack has to pass between the listeners?
// Definitely something to investigate to understand better.
setTimeout(() => {
node.dispatchEvent(
createEvent<LifecycleEventDetails>('init', { observer, node })
);
}, 0);

This is likely due to having to wait for the Svelte microtask to complete. I think it's better to use tick().

await tick()
node.dispatchEvent(createEvent<LifecycleEventDetails>('init', { observer, node }));

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.