Skip to content

Commit

Permalink
Merge pull request #205 from Enterwell/stage
Browse files Browse the repository at this point in the history
Stage
  • Loading branch information
AleksandarDev authored Nov 28, 2023
2 parents 972ced3 + f8921a2 commit 1fd56ff
Show file tree
Hide file tree
Showing 14 changed files with 278 additions and 126 deletions.
33 changes: 33 additions & 0 deletions apps/docs/components/ExampleUseMutationObserver.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useState } from 'react';
import { useMutationObserver } from '@enterwell/react-hooks';

export function ExampleUseMutationObserver() {
const [mutations, setMutations] = useState<MutationRecord[]>([]);

// @highlight-start
useMutationObserver(
document.querySelector('html'),
(mutations) => {
setMutations((curr) => [...curr, ...mutations]);
}, {
attributes: true,
characterData: true,
childList: true,
});
// @highlight-end

return (
<div>
<p>Try changing theme to trigger DOM changes.</p>
<br />
<div>Mutations:</div>
<ul>
{mutations.map((mutation, index) => (
<li key={index}>
<pre>{JSON.stringify(mutation, null, 2)}</pre>
</li>
))}
</ul>
</div>
);
}
4 changes: 2 additions & 2 deletions apps/docs/components/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ const roboto = Roboto({
display: 'swap',
});

export const theme = createTheme({
export const theme = (mode: string | undefined) => createTheme({
palette: {
mode: 'dark',
mode: mode === 'light' ? 'light' : 'dark',
primary: {
main: '#eeeeee',
},
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
},
"devDependencies": {
"@types/node": "18.18.13",
"@types/react": "18.2.38",
"@types/react": "18.2.39",
"@types/react-dom": "18.2.17",
"autoprefixer": "10.4.16",
"postcss": "8.4.31",
Expand Down
20 changes: 18 additions & 2 deletions apps/docs/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,28 @@ import { ThemeProvider } from '@mui/material';
import { inter } from '../src/fonts';
import '../styles/global.css';
import { AppProps } from 'next/app';
import { useMutationObserver } from '@enterwell/react-hooks';
import { useState } from 'react';

export default function App({ Component, pageProps }: AppProps) {
const [resolvedTheme, setResolvedTheme] = useState(
typeof window !== 'undefined' ? document.querySelector('html')?.style.colorScheme === 'dark' ? 'dark' : 'light' : 'light'
);

if (typeof window !== 'undefined') {
useMutationObserver(
document.querySelector('html'),
() => {
document.querySelector('html')?.style.colorScheme === 'dark' ? setResolvedTheme('dark') : setResolvedTheme('light');
}, {
attributes: true
});
}

return (
<main className={`${inter.variable} font-sans`}>
<ThemeProvider theme={theme}>
<Component {...pageProps} />
<ThemeProvider theme={theme(resolvedTheme)}>
<Component {...pageProps}></Component>
</ThemeProvider>
</main>
);
Expand Down
33 changes: 33 additions & 0 deletions apps/docs/pages/react-hooks/hooks/use-mutation-observer.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: useMutationObserver
---

import { useResizeObserver } from '@enterwell/react-hooks';
import { ComponentWithSource } from '../../../components/docs/ComponentWithSource.tsx';
import { ComponentDescription, ComponentParameters, ComponentSource } from '../../../components/docs/ComponentDocs';
import { ExampleUseMutationObserver } from '../../../components/ExampleUseMutationObserver';

# useMutationObserver

## Description

<ComponentDescription name="useMutationObserver" />

### Parameters

<ComponentParameters name="useMutationObserver" />

## Example

<ComponentWithSource component={ ExampleUseMutationObserver } centered />

## Inspect

<details>
<summary>Source code</summary>
<ComponentSource
package="@enterwell/react-hooks"
directory="hooks"
name="useMutationObserver"
/>
</details>
Empty file.
64 changes: 64 additions & 0 deletions packages/react-hooks/hooks/useMutationObserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { MutableRefObject, useCallback, useEffect, useRef } from 'react'

/**
* A type that represents either a React ref or a DOM node.
* @public
*/
export type MaybeRef<T> = T | MutableRefObject<T>

function isRef(obj: unknown): boolean {
return obj !== null &&
typeof obj === 'object' &&
Object.prototype.hasOwnProperty.call(obj, 'current');
}

function unRef<T = HTMLElement>(target: MaybeRef<T>): T {
return isRef(target)
? (target as MutableRefObject<T>).current
: (target as T);
}

/**
* Watch for changes being made to the DOM tree.
*
* @param target - React ref or DOM node
* @param callback - callback to execute when mutations are observed
* @param options - Options passed to mutation observer
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver MutationObserver MDN
* @see https://react-hooks-library.vercel.app/core/useMutationObserver
*
* @public
*/
export function useMutationObserver(
target: MaybeRef<Element | null | undefined>,
callback: MutationCallback,
options: MutationObserverInit = {}
) {
const observer = useRef<MutationObserver | null>(null)

const stop = useCallback(() => {
if (!observer.current) return

observer.current.disconnect()
observer.current = null
}, [])

// On unmount, cleanup
useEffect(() => stop, [stop]);

useEffect(() => {
const el = unRef(target);

if (!(el && window)) return

observer.current = new window.MutationObserver(callback)
observer.current?.observe(el, options)

return stop
}, [callback, stop, options, target])

return {
stop
}
}
3 changes: 2 additions & 1 deletion packages/react-hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export * from "./hooks/usePromise";
export * from "./hooks/useDebouncedEffect";
export * from "./hooks/useDebounce";
export * from "./hooks/useIsomorphicLayoutEffect";
export * from "./hooks/useResizeObserver";
export * from "./hooks/useResizeObserver";
export * from "./hooks/useMutationObserver";
2 changes: 1 addition & 1 deletion packages/react-hooks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"devDependencies": {
"@microsoft/api-extractor": "7.38.3",
"@types/node": "18.18.13",
"@types/react": "18.2.38",
"@types/react": "18.2.39",
"@types/react-dom": "18.2.17",
"eslint-config-custom": "workspace:*",
"react": "18.2.0",
Expand Down
9 changes: 9 additions & 0 deletions packages/react-hooks/temp/react-hooks.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
```ts

import { MutableRefObject } from 'react';
import * as react from 'react';
import { useEffect } from 'react';

// @public
export type MaybeRef<T> = T | MutableRefObject<T>;

// @public
export type PromiseFunction<T> = (Promise<T> | undefined) | (() => Promise<T> | undefined);

Expand All @@ -19,6 +23,11 @@ export function useDebouncedEffect(effect: Function, deps: unknown[], delay: num
// @public
export const useIsomorphicLayoutEffect: typeof useEffect;

// @public
export function useMutationObserver(target: MaybeRef<Element | null | undefined>, callback: MutationCallback, options?: MutationObserverInit): {
stop: () => void;
};

// @public
export function usePromise<T>(promise?: PromiseFunction<T>): UsePromiseResult<T>;

Expand Down
2 changes: 1 addition & 1 deletion packages/react-mui-hooks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@mui/x-data-grid": "6.18.2",
"@mui/x-data-grid-pro": "6.18.2",
"@types/node": "18.18.13",
"@types/react": "18.2.38",
"@types/react": "18.2.39",
"@types/react-dom": "18.2.17",
"date-fns": "2.30.0",
"eslint-config-custom": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"@mui/x-date-pickers-pro": "5.0.20",
"@mui/x-date-pickers": "5.0.20",
"@types/node": "18.18.13",
"@types/react": "18.2.38",
"@types/react": "18.2.39",
"@types/react-dom": "18.2.17",
"date-fns": "2.30.0",
"eslint-config-custom": "workspace:*",
Expand Down
5 changes: 2 additions & 3 deletions packages/react-ui/temp/react-ui.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
```ts

import { AutocompleteProps } from '@mui/material/Autocomplete';
import { Button } from '@mui/material';
import { ButtonGroupProps } from '@mui/material';
import { ButtonProps } from '@mui/material';
import { ChipTypeMap } from '@mui/material';
Expand Down Expand Up @@ -36,14 +35,14 @@ export type ConfirmButtonProps = Omit<ButtonProps, "onClick"> & Pick<ConfirmDial
};

// @public
export function ConfirmDialog({ isOpen, header, message, maxWidth, fullWidth, color, confirmButtonText, cancelButtonText, onConfirm, onCancel, ...rest }: ConfirmDialogProps): react_jsx_runtime.JSX.Element;
export function ConfirmDialog({ isOpen, header, message, maxWidth, color, confirmButtonText, cancelButtonText, onConfirm, onCancel, ...rest }: ConfirmDialogProps): react_jsx_runtime.JSX.Element;

// @public
export type ConfirmDialogProps = Omit<DialogProps, "open" | "onClose" | "color"> & {
isOpen: boolean;
header: string;
message?: string;
color?: ComponentProps<typeof Button>['color'];
color?: ButtonProps["color"];
confirmButtonText?: string;
cancelButtonText?: string;
onConfirm: () => void;
Expand Down
Loading

0 comments on commit 1fd56ff

Please sign in to comment.