svelte-intersection-observer 0.10.2 → 1.1.0
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/README.md +102 -40
- package/package.json +23 -43
- package/src/IntersectionObserver.svelte +10 -7
- package/src/IntersectionObserver.svelte.d.ts +79 -0
- package/src/MultipleIntersectionObserver.svelte +137 -0
- package/src/MultipleIntersectionObserver.svelte.d.ts +82 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +2 -3
- package/CHANGELOG.md +0 -124
- package/lib/index.js +0 -720
- package/lib/index.mjs +0 -712
- package/types/IntersectionObserver.svelte.d.ts +0 -84
- package/types/index.d.ts +0 -1
package/README.md
CHANGED
|
@@ -12,22 +12,19 @@ Try it in the [Svelte REPL](https://svelte.dev/repl/8cd2327a580c4f429c71f7df999b
|
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
```sh
|
|
16
|
+
# NPM
|
|
17
|
+
npm i svelte-intersection-observer
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**NPM**
|
|
19
|
+
# pnpm
|
|
20
|
+
pnpm i svelte-intersection-observer
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```
|
|
22
|
+
# Bun
|
|
23
|
+
bun i svelte-intersection-observer
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
# Yarn
|
|
26
|
+
yarn add svelte-intersection-observer
|
|
28
27
|
|
|
29
|
-
```bash
|
|
30
|
-
pnpm i -D svelte-intersection-observer
|
|
31
28
|
```
|
|
32
29
|
|
|
33
30
|
## Usage
|
|
@@ -139,29 +136,109 @@ As an alternative to binding the `intersecting` prop, you can listen to the `int
|
|
|
139
136
|
</IntersectionObserver>
|
|
140
137
|
```
|
|
141
138
|
|
|
139
|
+
### Multiple elements
|
|
140
|
+
|
|
141
|
+
For performance, use `MultipleIntersectionObserver` to observe multiple elements.
|
|
142
|
+
|
|
143
|
+
This avoids instantiating a new observer for every element.
|
|
144
|
+
|
|
145
|
+
```svelte
|
|
146
|
+
<script>
|
|
147
|
+
import { MultipleIntersectionObserver } from "svelte-intersection-observer";
|
|
148
|
+
|
|
149
|
+
let ref1;
|
|
150
|
+
let ref2;
|
|
151
|
+
|
|
152
|
+
$: elements = [ref1, ref2];
|
|
153
|
+
</script>
|
|
154
|
+
|
|
155
|
+
<MultipleIntersectionObserver {elements} let:elementIntersections>
|
|
156
|
+
<header>
|
|
157
|
+
<div class:intersecting={elementIntersections.get(ref1)}>
|
|
158
|
+
Item 1: {elementIntersections.get(ref1) ? "✓" : "✗"}
|
|
159
|
+
</div>
|
|
160
|
+
<div class:intersecting={elementIntersections.get(ref2)}>
|
|
161
|
+
Item 2: {elementIntersections.get(ref2) ? "✓" : "✗"}
|
|
162
|
+
</div>
|
|
163
|
+
</header>
|
|
164
|
+
|
|
165
|
+
<div bind:this={ref1}>Item 1</div>
|
|
166
|
+
<div bind:this={ref2}>Item 2</div>
|
|
167
|
+
</MultipleIntersectionObserver>
|
|
168
|
+
```
|
|
169
|
+
|
|
142
170
|
## API
|
|
143
171
|
|
|
144
|
-
###
|
|
172
|
+
### IntersectionObserver
|
|
173
|
+
|
|
174
|
+
#### Props
|
|
145
175
|
|
|
146
|
-
| Name | Description | Type
|
|
147
|
-
| :----------- | :---------------------------------------------------------- |
|
|
148
|
-
| element | Observed element | `HTMLElement` | `null` |
|
|
149
|
-
| once | Unobserve the element after the first intersection event | `boolean`
|
|
150
|
-
| intersecting | `true` if the observed element is intersecting the viewport | `boolean`
|
|
151
|
-
| root | Containing element | `null` or `HTMLElement`
|
|
152
|
-
| rootMargin | Margin offset of the containing element | `string`
|
|
153
|
-
| threshold | Percentage of element
|
|
154
|
-
| entry | Observed element metadata | [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) | `null` |
|
|
155
|
-
| observer | `IntersectionObserver` instance | [`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) | `null` |
|
|
176
|
+
| Name | Description | Type | Default value |
|
|
177
|
+
| :----------- | :---------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------ | :------------ |
|
|
178
|
+
| element | Observed element | `null` or `HTMLElement` | `null` |
|
|
179
|
+
| once | Unobserve the element after the first intersection event | `boolean` | `false` |
|
|
180
|
+
| intersecting | `true` if the observed element is intersecting the viewport | `boolean` | `false` |
|
|
181
|
+
| root | Containing element | `null` or `HTMLElement` | `null` |
|
|
182
|
+
| rootMargin | Margin offset of the containing element | `string` | `"0px"` |
|
|
183
|
+
| threshold | Percentage of element visibility to trigger an event | `number` between 0 and 1, or an array of `number`s between 0 and 1 | `0` |
|
|
184
|
+
| entry | Observed element metadata | `null` or [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) | `null` |
|
|
185
|
+
| observer | `IntersectionObserver` instance | `null` or [`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) | `null` |
|
|
156
186
|
|
|
157
|
-
|
|
187
|
+
#### Dispatched events
|
|
158
188
|
|
|
159
189
|
- **on:observe**: fired when the element is first observed or whenever an intersection change occurs
|
|
160
190
|
- **on:intersect**: fired when the element is intersecting the viewport
|
|
161
191
|
|
|
162
192
|
The `e.detail` dispatched by the `observe` and `intersect` events is an [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) interface.
|
|
163
193
|
|
|
164
|
-
|
|
194
|
+
#### Slot props
|
|
195
|
+
|
|
196
|
+
| Name | Type |
|
|
197
|
+
| :----------- | :------------------------------------------------------------------------------------------------------------------ |
|
|
198
|
+
| intersecting | `boolean` |
|
|
199
|
+
| entry | `null` or [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) |
|
|
200
|
+
| observer | [`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) |
|
|
201
|
+
|
|
202
|
+
### MultipleIntersectionObserver
|
|
203
|
+
|
|
204
|
+
#### Props
|
|
205
|
+
|
|
206
|
+
| Name | Description | Type | Default value |
|
|
207
|
+
| :------------------- | :---------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- | :------------ |
|
|
208
|
+
| elements | Array of HTML elements to observe | `Array<HTMLElement \| null>` | `[]` |
|
|
209
|
+
| once | Unobserve elements after the first intersection event | `boolean` | `false` |
|
|
210
|
+
| root | Containing element | `null` or `HTMLElement` | `null` |
|
|
211
|
+
| rootMargin | Margin offset of the containing element | `string` | `"0px"` |
|
|
212
|
+
| threshold | Percentage of element visibility to trigger an event | `number` between 0 and 1, or an array of `number`s between 0 and 1 | `0` |
|
|
213
|
+
| elementIntersections | Map of each element to its intersection state | `Map<HTMLElement \| null, boolean>` | `new Map()` |
|
|
214
|
+
| elementEntries | Map of each element to its latest entry | `Map<HTMLElement \| null,` [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry)`>` | `new Map()` |
|
|
215
|
+
| observer | `IntersectionObserver` instance | `null` or [`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) | `null` |
|
|
216
|
+
|
|
217
|
+
#### Dispatched events
|
|
218
|
+
|
|
219
|
+
- **on:observe**: fired when an element is first observed or whenever an intersection change occurs
|
|
220
|
+
- **on:intersect**: fired when an element is intersecting the viewport
|
|
221
|
+
|
|
222
|
+
The `e.detail` for both events includes:
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
{
|
|
226
|
+
entry: IntersectionObserverEntry;
|
|
227
|
+
target: HTMLElement;
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### Slot props
|
|
232
|
+
|
|
233
|
+
| Name | Type |
|
|
234
|
+
| :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
|
|
235
|
+
| observer | [`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) |
|
|
236
|
+
| elementIntersections | `Map<HTMLElement \| null, boolean>` |
|
|
237
|
+
| elementEntries | `Map<HTMLElement \| null,` [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry)`>` |
|
|
238
|
+
|
|
239
|
+
### `IntersectionObserverEntry` interface
|
|
240
|
+
|
|
241
|
+
Note that all properties in [IntersectionObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) are read-only.
|
|
165
242
|
|
|
166
243
|
<details>
|
|
167
244
|
<summary><code>IntersectionObserverEntry</code></summary>
|
|
@@ -208,21 +285,6 @@ interface IntersectionObserverEntry {
|
|
|
208
285
|
|
|
209
286
|
</details>
|
|
210
287
|
|
|
211
|
-
## Examples
|
|
212
|
-
|
|
213
|
-
The [examples folder](examples/) contains sample set-ups.
|
|
214
|
-
|
|
215
|
-
- [examples/sveltekit](examples/sveltekit)
|
|
216
|
-
- [examples/vite](examples/vite)
|
|
217
|
-
- [examples/rollup](examples/rollup)
|
|
218
|
-
- [examples/webpack](examples/webpack)
|
|
219
|
-
|
|
220
|
-
## TypeScript support
|
|
221
|
-
|
|
222
|
-
Svelte version 3.31 or greater is required to use this module with TypeScript.
|
|
223
|
-
|
|
224
|
-
TypeScript definitions for this component are located in the [types folder](types/).
|
|
225
|
-
|
|
226
288
|
## Changelog
|
|
227
289
|
|
|
228
290
|
[Changelog](CHANGELOG.md)
|
package/package.json
CHANGED
|
@@ -1,59 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-intersection-observer",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Detect if an element is in the viewport using the Intersection Observer API",
|
|
6
6
|
"author": "Eric Liu (https://github.com/metonym)",
|
|
7
|
+
"type": "module",
|
|
7
8
|
"svelte": "./src/index.js",
|
|
8
|
-
"main": "./lib/index.js",
|
|
9
|
-
"module": "./lib/index.mjs",
|
|
10
|
-
"types": "./types/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./types/index.d.ts",
|
|
14
|
-
"svelte": "./src/index.js"
|
|
15
|
-
},
|
|
16
|
-
"./src/*.svelte": {
|
|
17
|
-
"types": "./types/*.svelte.d.ts",
|
|
18
|
-
"import": "./src/*.svelte"
|
|
19
|
-
},
|
|
20
|
-
"./src/*": {
|
|
21
|
-
"types": "./types/*.d.ts",
|
|
22
|
-
"import": "./src/*.js"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"scripts": {
|
|
26
|
-
"dev": "rollup -cw",
|
|
27
|
-
"build": "rollup -c",
|
|
28
|
-
"prepack": "BUNDLE=true rollup -c",
|
|
29
|
-
"test:types": "svelte-check --workspace test",
|
|
30
|
-
"test:examples": "node test/examples",
|
|
31
|
-
"format": "prettier --ignore-path .gitignore --write '.'"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"prettier": "^3.0.0",
|
|
35
|
-
"prettier-plugin-svelte": "^3.0.0",
|
|
36
|
-
"svelte": "^4.1.0",
|
|
37
|
-
"svelte-check": "^3.4.6",
|
|
38
|
-
"svelte-readme": "^3.6.3"
|
|
39
|
-
},
|
|
40
9
|
"repository": {
|
|
41
10
|
"type": "git",
|
|
42
|
-
"url": "https://github.com/metonym/svelte-intersection-observer.git"
|
|
11
|
+
"url": "git+https://github.com/metonym/svelte-intersection-observer.git"
|
|
43
12
|
},
|
|
44
13
|
"homepage": "https://github.com/metonym/svelte-intersection-observer",
|
|
45
14
|
"bugs": "https://github.com/metonym/svelte-intersection-observer/issues",
|
|
46
15
|
"keywords": [
|
|
16
|
+
"svelte",
|
|
17
|
+
"svelte component",
|
|
47
18
|
"intersection observer",
|
|
48
19
|
"viewport",
|
|
49
20
|
"lazy-loading",
|
|
50
|
-
"conditional"
|
|
51
|
-
"svelte",
|
|
52
|
-
"svelte component"
|
|
21
|
+
"conditional"
|
|
53
22
|
],
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
23
|
+
"main": "./index.js",
|
|
24
|
+
"types": "./index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./index.d.ts",
|
|
28
|
+
"svelte": "./index.js"
|
|
29
|
+
},
|
|
30
|
+
"./*.svelte": {
|
|
31
|
+
"types": "./*.svelte.d.ts",
|
|
32
|
+
"import": "./*.svelte"
|
|
33
|
+
},
|
|
34
|
+
"./*": {
|
|
35
|
+
"types": "./*.d.ts",
|
|
36
|
+
"import": "./*.js"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
/**
|
|
3
3
|
* The HTML Element to observe.
|
|
4
|
-
* @type {HTMLElement}
|
|
4
|
+
* @type {null | HTMLElement}
|
|
5
5
|
*/
|
|
6
6
|
export let element = null;
|
|
7
7
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
/**
|
|
22
22
|
* Specify the containing element.
|
|
23
23
|
* Defaults to the browser viewport.
|
|
24
|
-
* @type {HTMLElement}
|
|
24
|
+
* @type {null | HTMLElement}
|
|
25
25
|
*/
|
|
26
26
|
export let root = null;
|
|
27
27
|
|
|
@@ -50,7 +50,10 @@
|
|
|
50
50
|
|
|
51
51
|
const dispatch = createEventDispatcher();
|
|
52
52
|
|
|
53
|
+
/** @type {null | string} */
|
|
53
54
|
let prevRootMargin = null;
|
|
55
|
+
|
|
56
|
+
/** @type {null | HTMLElement} */
|
|
54
57
|
let prevElement = null;
|
|
55
58
|
|
|
56
59
|
const initialize = () => {
|
|
@@ -61,7 +64,7 @@
|
|
|
61
64
|
intersecting = _entry.isIntersecting;
|
|
62
65
|
});
|
|
63
66
|
},
|
|
64
|
-
{ root, rootMargin, threshold }
|
|
67
|
+
{ root, rootMargin, threshold },
|
|
65
68
|
);
|
|
66
69
|
};
|
|
67
70
|
|
|
@@ -83,21 +86,21 @@
|
|
|
83
86
|
if (entry.isIntersecting) {
|
|
84
87
|
dispatch("intersect", entry);
|
|
85
88
|
|
|
86
|
-
if (once) observer
|
|
89
|
+
if (element && once) observer?.unobserve(element);
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
await tick();
|
|
91
94
|
|
|
92
95
|
if (element !== null && element !== prevElement) {
|
|
93
|
-
observer
|
|
96
|
+
observer?.observe(element);
|
|
94
97
|
|
|
95
|
-
if (prevElement !== null) observer
|
|
98
|
+
if (prevElement !== null) observer?.unobserve(prevElement);
|
|
96
99
|
prevElement = element;
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
if (prevRootMargin && rootMargin !== prevRootMargin) {
|
|
100
|
-
observer
|
|
103
|
+
observer?.disconnect();
|
|
101
104
|
prevElement = null;
|
|
102
105
|
initialize();
|
|
103
106
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { SvelteComponentTyped } from "svelte";
|
|
2
|
+
|
|
3
|
+
export default class extends SvelteComponentTyped<
|
|
4
|
+
{
|
|
5
|
+
/**
|
|
6
|
+
* The HTML Element to observe.
|
|
7
|
+
* @default null
|
|
8
|
+
*/
|
|
9
|
+
element?: null | HTMLElement;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Set to `true` to unobserve the element
|
|
13
|
+
* after it intersects the viewport.
|
|
14
|
+
* @default false
|
|
15
|
+
*/
|
|
16
|
+
once?: boolean;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* `true` if the observed element
|
|
20
|
+
* is intersecting the viewport.
|
|
21
|
+
* @default false
|
|
22
|
+
*/
|
|
23
|
+
intersecting?: boolean;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Specify the containing element.
|
|
27
|
+
* Defaults to the browser viewport.
|
|
28
|
+
* @default null
|
|
29
|
+
*/
|
|
30
|
+
root?: null | HTMLElement;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Margin offset of the containing element.
|
|
34
|
+
* @default "0px"
|
|
35
|
+
*/
|
|
36
|
+
rootMargin?: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Percentage of element visibility to trigger an event.
|
|
40
|
+
* Value must be a number between 0 and 1, or an array of numbers between 0 and 1.
|
|
41
|
+
* @default 0
|
|
42
|
+
*/
|
|
43
|
+
threshold?: number | number[];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Observed element metadata.
|
|
47
|
+
* @default null
|
|
48
|
+
*/
|
|
49
|
+
entry?: null | IntersectionObserverEntry;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* `IntersectionObserver` instance.
|
|
53
|
+
* @default null
|
|
54
|
+
*/
|
|
55
|
+
observer?: null | IntersectionObserver;
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
/**
|
|
59
|
+
* Dispatched when the element is first observed
|
|
60
|
+
* and also whenever an intersection event occurs.
|
|
61
|
+
*/
|
|
62
|
+
observe: CustomEvent<IntersectionObserverEntry>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Dispatched only when the element is intersecting the viewport.
|
|
66
|
+
* `event.detail.isIntersecting` will only be `true`
|
|
67
|
+
*/
|
|
68
|
+
intersect: CustomEvent<
|
|
69
|
+
IntersectionObserverEntry & { isIntersecting: true }
|
|
70
|
+
>;
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
default: {
|
|
74
|
+
intersecting: boolean;
|
|
75
|
+
entry: null | IntersectionObserverEntry;
|
|
76
|
+
observer: IntersectionObserver;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
> {}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/**
|
|
3
|
+
* Array of HTML Elements to observe.
|
|
4
|
+
* Use this for better performance when observing multiple elements.
|
|
5
|
+
* @type {(HTMLElement | null)[]}
|
|
6
|
+
*/
|
|
7
|
+
export let elements = [];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Set to `true` to unobserve the element
|
|
11
|
+
* after it intersects the viewport.
|
|
12
|
+
* @type {boolean}
|
|
13
|
+
*/
|
|
14
|
+
export let once = false;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Specify the containing element.
|
|
18
|
+
* Defaults to the browser viewport.
|
|
19
|
+
* @type {null | HTMLElement}
|
|
20
|
+
*/
|
|
21
|
+
export let root = null;
|
|
22
|
+
|
|
23
|
+
/** Margin offset of the containing element. */
|
|
24
|
+
export let rootMargin = "0px";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Percentage of element visibility to trigger an event.
|
|
28
|
+
* Value must be between 0 and 1.
|
|
29
|
+
*/
|
|
30
|
+
export let threshold = 0;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Map of element to its intersection state.
|
|
34
|
+
* @type {Map<HTMLElement | null, boolean>}
|
|
35
|
+
*/
|
|
36
|
+
export let elementIntersections = new Map();
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Map of element to its latest entry.
|
|
40
|
+
* @type {Map<HTMLElement | null, IntersectionObserverEntry>}
|
|
41
|
+
*/
|
|
42
|
+
export let elementEntries = new Map();
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* `IntersectionObserver` instance.
|
|
46
|
+
* @type {null | IntersectionObserver}
|
|
47
|
+
*/
|
|
48
|
+
export let observer = null;
|
|
49
|
+
|
|
50
|
+
import { tick, createEventDispatcher, afterUpdate, onMount } from "svelte";
|
|
51
|
+
|
|
52
|
+
const dispatch = createEventDispatcher();
|
|
53
|
+
|
|
54
|
+
/** @type {null | string} */
|
|
55
|
+
let prevRootMargin = null;
|
|
56
|
+
|
|
57
|
+
/** @type {null | HTMLElement} */
|
|
58
|
+
let prevElement = null;
|
|
59
|
+
|
|
60
|
+
/** @type {(HTMLElement | null)[]} */
|
|
61
|
+
let prevElements = [];
|
|
62
|
+
|
|
63
|
+
const initialize = () => {
|
|
64
|
+
observer = new IntersectionObserver(
|
|
65
|
+
(entries) => {
|
|
66
|
+
entries.forEach((_entry) => {
|
|
67
|
+
const target = /** @type {HTMLElement} */ (_entry.target);
|
|
68
|
+
|
|
69
|
+
elementIntersections.set(target, _entry.isIntersecting);
|
|
70
|
+
elementEntries.set(target, _entry);
|
|
71
|
+
|
|
72
|
+
// Trigger reactivity.
|
|
73
|
+
elementIntersections = new Map(elementIntersections);
|
|
74
|
+
elementEntries = new Map(elementEntries);
|
|
75
|
+
|
|
76
|
+
dispatch("observe", { entry: _entry, target });
|
|
77
|
+
|
|
78
|
+
if (_entry.isIntersecting) {
|
|
79
|
+
dispatch("intersect", { entry: _entry, target });
|
|
80
|
+
if (once) observer?.unobserve(target);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
{ root, rootMargin, threshold },
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
onMount(() => {
|
|
89
|
+
initialize();
|
|
90
|
+
|
|
91
|
+
return () => {
|
|
92
|
+
if (observer) {
|
|
93
|
+
observer.disconnect();
|
|
94
|
+
observer = null;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
afterUpdate(async () => {
|
|
100
|
+
await tick();
|
|
101
|
+
|
|
102
|
+
if (elements.length > 0) {
|
|
103
|
+
const newElements = elements.filter(
|
|
104
|
+
(el) => el && !prevElements.includes(el),
|
|
105
|
+
);
|
|
106
|
+
newElements.forEach((el) => {
|
|
107
|
+
if (el) observer?.observe(el);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const removedElements = prevElements.filter(
|
|
111
|
+
(el) => el && !elements.includes(el),
|
|
112
|
+
);
|
|
113
|
+
removedElements.forEach((el) => {
|
|
114
|
+
if (el) observer?.unobserve(el);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
prevElements = [...elements];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (prevRootMargin && rootMargin !== prevRootMargin) {
|
|
121
|
+
observer?.disconnect();
|
|
122
|
+
prevElement = null;
|
|
123
|
+
prevElements = [];
|
|
124
|
+
initialize();
|
|
125
|
+
|
|
126
|
+
elements
|
|
127
|
+
.filter((el) => el)
|
|
128
|
+
.forEach((el) => {
|
|
129
|
+
if (el) observer?.observe(el);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
prevRootMargin = rootMargin;
|
|
134
|
+
});
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
<slot {observer} {elementIntersections} {elementEntries} />
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { SvelteComponentTyped } from "svelte";
|
|
2
|
+
|
|
3
|
+
export default class extends SvelteComponentTyped<
|
|
4
|
+
{
|
|
5
|
+
/**
|
|
6
|
+
* Array of HTML Elements to observe.
|
|
7
|
+
* Use this for better performance when observing multiple elements.
|
|
8
|
+
* @default []
|
|
9
|
+
*/
|
|
10
|
+
elements?: (HTMLElement | null)[];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Set to `true` to unobserve the element
|
|
14
|
+
* after it intersects the viewport.
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
once?: boolean;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Specify the containing element.
|
|
21
|
+
* Defaults to the browser viewport.
|
|
22
|
+
* @default null
|
|
23
|
+
*/
|
|
24
|
+
root?: null | HTMLElement;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Margin offset of the containing element.
|
|
28
|
+
* @default "0px"
|
|
29
|
+
*/
|
|
30
|
+
rootMargin?: string;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Percentage of element visibility to trigger an event.
|
|
34
|
+
* Value must be a number between 0 and 1, or an array of numbers between 0 and 1.
|
|
35
|
+
* @default 0
|
|
36
|
+
*/
|
|
37
|
+
threshold?: number | number[];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Map of element to its intersection state.
|
|
41
|
+
* @default new Map()
|
|
42
|
+
*/
|
|
43
|
+
elementIntersections?: Map<HTMLElement | null, boolean>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Map of element to its latest entry.
|
|
47
|
+
* @default new Map()
|
|
48
|
+
*/
|
|
49
|
+
elementEntries?: Map<HTMLElement | null, IntersectionObserverEntry>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* `IntersectionObserver` instance.
|
|
53
|
+
* @default null
|
|
54
|
+
*/
|
|
55
|
+
observer?: null | IntersectionObserver;
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
/**
|
|
59
|
+
* Dispatched when an element is first observed
|
|
60
|
+
* and also whenever an intersection event occurs.
|
|
61
|
+
*/
|
|
62
|
+
observe: CustomEvent<{
|
|
63
|
+
entry: IntersectionObserverEntry;
|
|
64
|
+
target: HTMLElement;
|
|
65
|
+
}>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Dispatched only when an element is intersecting the viewport.
|
|
69
|
+
*/
|
|
70
|
+
intersect: CustomEvent<{
|
|
71
|
+
entry: IntersectionObserverEntry & { isIntersecting: true };
|
|
72
|
+
target: HTMLElement;
|
|
73
|
+
}>;
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
default: {
|
|
77
|
+
observer: IntersectionObserver;
|
|
78
|
+
elementIntersections: Map<HTMLElement | null, boolean>;
|
|
79
|
+
elementEntries: Map<HTMLElement | null, IntersectionObserverEntry>;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
> {}
|
package/src/index.d.ts
ADDED
package/src/index.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export default IntersectionObserver;
|
|
1
|
+
export { default } from "./IntersectionObserver.svelte";
|
|
2
|
+
export { default as MultipleIntersectionObserver } from "./MultipleIntersectionObserver.svelte";
|