Skip to content

Commit

Permalink
[docs] Add use-mutation-observer hook
Browse files Browse the repository at this point in the history
  • Loading branch information
rtivital committed Mar 4, 2024
1 parent a0850de commit 0795aaf
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 1 deletion.
4 changes: 4 additions & 0 deletions docs/src/mdx/data/mdx-hooks-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,8 @@ export const MDX_HOOKS_DATA: Record<string, Frontmatter> = {
useWindowScroll: hDocs('useWindowScroll', 'Tracks window scroll position'),
usePagination: hDocs('usePagination', 'Manages pagination state'),
useInViewport: hDocs('useInViewport', 'Detects if element is visible in the viewport'),
useMutationObserver: hDocs(
'useMutationObserver',
'Subscribe to changes being made to the DOM tree'
),
};
1 change: 1 addition & 0 deletions docs/src/mdx/mdx-pages-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const MDX_PAGES_GROUPS: MdxPagesGroup[] = [
MDX_DATA.useMove,
MDX_DATA.useReducedMotion,
MDX_DATA.useResizeObserver,
MDX_DATA.useMutationObserver,
MDX_DATA.useScrollIntoView,
MDX_DATA.useViewportSize,
MDX_DATA.useWindowEvent,
Expand Down
13 changes: 13 additions & 0 deletions docs/src/pages/changelog/7-7-0.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
import { HooksDemos, ScatterChartDemos } from '@docs/demos';
import { Layout } from '@/layout';
import { MDX_DATA } from '@/mdx';

export default Layout(MDX_DATA.Changelog770);

## ScatterChart component

New [ScatterChart](/charts/scatter-chart) component:

<Demo data={ScatterChartDemos.usage} />

## use-mutation-observer hook

New [useMutationObserver](/hooks/use-mutation-observer) hook:

<Demo data={HooksDemos.useMutationObserverTarget} />
29 changes: 29 additions & 0 deletions docs/src/pages/hooks/use-mutation-observer.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { HooksDemos } from '@docs/demos';
import { Layout } from '@/layout';
import { MDX_DATA } from '@/mdx';

export default Layout(MDX_DATA.useMutationObserver);

## Usage

`use-mutation-observer` is a wrapper for the [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
It allows subscribing changes being made to the DOM tree.

<Demo data={HooksDemos.useMutationObserverUsage} />

## Target element

If you cannot pass `ref` to the target element, you can pass a function to resolve
the target element as a third argument.

<Demo data={HooksDemos.useMutationObserverTarget} />

## Definition

```tsx
function useMutationObserver<Element extends HTMLElement>(
callback: MutationCallback,
options: MutationObserverInit,
target?: HTMLElement | (() => HTMLElement) | null
): RefObject<Element>;
```
10 changes: 10 additions & 0 deletions packages/@docs/demos/src/demos/hooks/Hooks.demos.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,13 @@ export const Demo_useInViewportUsage = {
name: '⭐ Demo: useInViewportUsage',
render: renderDemo(demos.useInViewportDemo),
};

export const Demo_useMutationObserverUsage = {
name: '⭐ Demo: useMutationObserverUsage',
render: renderDemo(demos.useMutationObserverUsage),
};

export const Demo_useMutationObserverTarget = {
name: '⭐ Demo: useMutationObserverTarget',
render: renderDemo(demos.useMutationObserverTarget),
};
2 changes: 2 additions & 0 deletions packages/@docs/demos/src/demos/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,5 @@ export { usePreviousUsage } from './use-previous.demo.usage';
export { useFaviconUsage } from './use-favicon.demo.usage';
export { useEyeDropperUsage } from './use-eye-dropper.demo.usage';
export { useInViewportDemo } from './use-in-viewport.demo.usage';
export { useMutationObserverUsage } from './use-mutation-observer.demo.usage';
export { useMutationObserverTarget } from './use-mutation-observer.demo.target';
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useState } from 'react';
import { Kbd, Text } from '@mantine/core';
import { useMutationObserver } from '@mantine/hooks';
import { MantineDemo } from '@mantinex/demo';

const code = `
import { useState } from 'react';
import { Kbd, Text } from '@mantine/core';
import { useMutationObserver } from '@mantine/hooks';
function Demo() {
const [lastMutation, setLastMutation] = useState('');
useMutationObserver(
(mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'dir') {
mutation.target instanceof HTMLElement &&
setLastMutation(mutation.target.getAttribute('dir') || '');
}
});
},
{
attributes: true,
attributeFilter: ['dir'],
},
() => document.documentElement
);
return (
<>
<Text>
Press <Kbd>Ctrl</Kbd> + <Kbd>Shift</Kbd> + <Kbd>L</Kbd> to change direction
</Text>
<Text mt={10}>Direction was changed to: {lastMutation || 'Not changed yet'}</Text>
</>
);
}
`;

function Demo() {
const [lastMutation, setLastMutation] = useState('');

useMutationObserver(
(mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'dir') {
mutation.target instanceof HTMLElement &&
setLastMutation(mutation.target.getAttribute('dir') || '');
}
});
},
{
attributes: true,
attributeFilter: ['dir'],
},
() => document.documentElement
);

return (
<>
<Text>
Press <Kbd>Ctrl</Kbd> + <Kbd>Shift</Kbd> + <Kbd>L</Kbd> to change direction
</Text>

<Text mt={10}>Direction was changed to: {lastMutation || 'Not changed yet'}</Text>
</>
);
}

export const useMutationObserverTarget: MantineDemo = {
type: 'code',
component: Demo,
code,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { useState } from 'react';
import { Button, Text } from '@mantine/core';
import { useMutationObserver } from '@mantine/hooks';
import { MantineDemo } from '@mantinex/demo';

const code = `
import { useState } from 'react';
import { Button, Text } from '@mantine/core';
import { useMutationObserver } from '@mantine/hooks';
function Demo() {
const [lastMutation, setLastMutation] = useState('');
const ref = useMutationObserver<HTMLButtonElement>(
(mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'data-mutation') {
mutation.target instanceof HTMLElement &&
setLastMutation(mutation.target.dataset.mutation || '');
}
});
},
{
attributes: true,
attributeFilter: ['data-mutation'],
}
);
return (
<>
<Button
ref={ref}
onClick={(event) => {
event.currentTarget.dataset.mutation = Math.random().toFixed(3);
}}
>
Click to change to data-mutation attribute
</Button>
<Text mt={10} size="sm">
Last detected mutation: {lastMutation || 'Not mutated yet'}
</Text>
</>
);
}
`;

function Demo() {
const [lastMutation, setLastMutation] = useState('');

const ref = useMutationObserver<HTMLButtonElement>(
(mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'dir') {
mutation.target instanceof HTMLElement &&
setLastMutation(mutation.target.dataset.mutation || '');
}
});
},
{
attributes: true,
attributeFilter: ['data-mutation'],
}
);

return (
<>
<Button
ref={ref}
onClick={(event) => {
event.currentTarget.dataset.mutation = Math.random().toFixed(3);
}}
>
Click to change to data-mutation attribute
</Button>
<Text mt={10} size="sm">
Last detected mutation: {lastMutation || 'Not mutated yet'}
</Text>
</>
);
}

export const useMutationObserverUsage: MantineDemo = {
type: 'code',
component: Demo,
code,
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { RefObject, useEffect, useRef } from 'react';

export function useMutationObserver<Element extends HTMLLIElement>(
export function useMutationObserver<Element extends HTMLElement>(
callback: MutationCallback,
options: MutationObserverInit,
target?: HTMLElement | (() => HTMLElement) | null
Expand Down

0 comments on commit 0795aaf

Please sign in to comment.