Skip to content

Commit

Permalink
feat(useMutationObserver): init (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
2nthony authored Sep 16, 2021
1 parent eb25b98 commit f878169
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 1 deletion.
8 changes: 8 additions & 0 deletions indexes.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"Animation",
"Browser",
"Component",
"Sensors",
"Utilities"
],
"functions": [
Expand Down Expand Up @@ -80,6 +81,13 @@
"category": "Browser",
"description": "reactive [Media Query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries)"
},
{
"name": "useMutationObserver",
"package": "core",
"docs": "/core/useMutationObserver/",
"category": "Sensors",
"description": "watch for changes being made to the DOM tree"
},
{
"name": "usePreferredDark",
"package": "core",
Expand Down
1 change: 1 addition & 0 deletions packages/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './useEventListener'
export * from './useMediaQuery'
export * from './useMutationObserver'
export * from './usePreferredDark'
export * from './useStorage'
export * from '@svelte-use/shared'
8 changes: 8 additions & 0 deletions packages/core/indexes.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"Animation",
"Browser",
"Component",
"Sensors",
"Utilities"
],
"functions": [
Expand Down Expand Up @@ -80,6 +81,13 @@
"category": "Browser",
"description": "reactive [Media Query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries)"
},
{
"name": "useMutationObserver",
"package": "core",
"docs": "/core/useMutationObserver/",
"category": "Sensors",
"description": "watch for changes being made to the DOM tree"
},
{
"name": "usePreferredDark",
"package": "core",
Expand Down
36 changes: 36 additions & 0 deletions packages/core/useMutationObserver/demo.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
import { onMount } from 'svelte'
import { useMutationObserver } from '.'
let el: HTMLDivElement
let messages: string[] = []
let className = ''
let style = ''
onMount(() => {
useMutationObserver(el, mutations => {
const mutation = mutations[0]
if (!mutation) {
return
}
messages.push(mutation.attributeName!)
messages = messages
}, { attributes: true })
})
setTimeout(() => {
className = 'test test2'
}, 1000)
setTimeout(() => {
style = 'color: red'
}, 1550)
</script>

<div bind:this={el} class={className} style={style}>
{#each messages as text}
<div>Mutation Attribute: { text }</div>
{/each}
</div>
31 changes: 31 additions & 0 deletions packages/core/useMutationObserver/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
category: Sensors
---

# useMutationObserver

Watch for changes being made to the DOM tree. [MutationObserver MDN](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)

## Usage

```html
<script>
import { useMutationObserver } from '@svelte-use/core'
let el
let messages = []
onMount(() => {
useMutationObserver(
el,
(mutations) => {
if (!mutations[0]) {
messages.push(mutations[0].attributeName)
messages = messages
}
},
{ attributes: true },
)
})
</script>
```
56 changes: 56 additions & 0 deletions packages/core/useMutationObserver/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { MaybeReadable, toReadable, tryOnDestroy } from '@svelte-use/shared'
import { ConfigurableWindow, defaultWindow } from '../_configurable'

export interface MutationObserverOptions
extends MutationObserverInit,
ConfigurableWindow {}

/**
* Watch for changes being made to the DOM tree.
*
* @see https://svelte-use.vercel.app/core/useMutationObserver
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver MutationObserver MDN
* @param target
* @param callback
* @param options
*/
export function useMutationObserver(
target: MaybeReadable<Element | undefined | null>,
callback: MutationCallback,
options: MutationObserverOptions = {},
) {
const { window = defaultWindow, ...mutationOptions } = options
let observer: MutationObserver | undefined
const isSupported = window && 'IntersectionObserver' in window

const cleanup = () => {
if (observer) {
observer.disconnect()
observer = undefined
}
}

const unsubscribe = toReadable(target).subscribe((el) => {
cleanup()

if (isSupported && window && el) {
// @ts-expect-error missing type
observer = new window.MutationObserver(callback)
observer!.observe(el, mutationOptions)
}
})

const stop = () => {
cleanup()
unsubscribe()
}

tryOnDestroy(stop)

return {
isSupported,
stop,
}
}

export type UseMutationObserverReturn = ReturnType<typeof useMutationObserver>
3 changes: 3 additions & 0 deletions packages/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
- [`tryOnDestroy`](/shared/tryOnDestroy/) — safe `onDestroy`
- [`tryOnMount`](/shared/tryOnMount/) — safe `onMount`

### Sensors
- [`useMutationObserver`](/core/useMutationObserver/) — watch for changes being made to the DOM tree

### Utilities
- [`whenever`](/shared/whenever/) — shorthand for watching value to be truthy

Expand Down
12 changes: 12 additions & 0 deletions packages/shared/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { get_current_component } from 'svelte/internal'
import { get, readable } from '@svelte-use/store'
import { MaybeReadable } from './types'
import { isReadable } from './is'
import { Readable } from 'svelte/store'

export * from './is'
export * from './types'
Expand Down Expand Up @@ -30,3 +34,11 @@ export function promiseTimeout(
}
})
}

export function unReadable<T>(val: MaybeReadable<T>): T {
return isReadable(val) ? get(val) : val
}

export function toReadable<T>(val: MaybeReadable<T>): Readable<T> {
return isReadable(val) ? val : readable(val)
}
3 changes: 2 additions & 1 deletion packages/shared/utils/is.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export const isObject = (val: any): val is object =>
toString.call(val) === '[object Object]'
export const isWindow = (val: any): val is Window =>
typeof window !== 'undefined' && toString.call(val) === '[object Window]'
export const isReadable = <T>(val: any): val is Readable<T> => 'subscribe' in val
export const isReadable = <T>(val: any): val is Readable<T> =>
'subscribe' in (val || {})
export const now = () => Date.now()
export const timestamp = () => +Date.now()
export const clamp = (n: number, min: number, max: number) =>
Expand Down

0 comments on commit f878169

Please sign in to comment.