seitu
Version:
61 lines (60 loc) • 1.82 kB
JavaScript
import { createReadableSubscription, createSubscription } from "../../core/subscription/index.mjs";
//#region src/web/media-query/index.ts
/**
* Reactive media query. On the server, `get()` and the SSR snapshot are
* `defaultMatches` (`false`).
*
* @example Vanilla
* ```ts twoslash title="media-query.ts"
* import { createMediaQuery } from 'seitu/web'
* import { useSubscription } from 'seitu/react'
*
* const isDesktop = createMediaQuery({ query: '(min-width: 768px)' })
*
* isDesktop.subscribe(matches => {
* console.log(matches)
* })
*
* const state = isDesktop.get()
* console.log(state)
* ```
*
* @example React
* ```tsx twoslash title="page.tsx"
* import { createMediaQuery } from 'seitu/web'
* import { useSubscription } from 'seitu/react'
*
* const isDesktop = createMediaQuery({ query: '(min-width: 768px)' })
*
* function Layout() {
* const matches = useSubscription(isDesktop)
* return matches ? 'i am desktop' : 'i am mobile'
* }
* ```
*
* @example Errors
* ```tsx twoslash
* import { createMediaQuery } from 'seitu/web'
* import { useSubscription } from 'seitu/react'
*
* // @errors: 2362 2322 1109
* createMediaQuery({ query: '(min-width: ' })
*
* // @errors: 2362 2322 2820
* createMediaQuery({ query: '(min-width: 768' })
* ```
*/
function createMediaQuery(options) {
const match = typeof window === "undefined" ? null : window.matchMedia(options.query);
const { subscribe, notify } = createSubscription({ onFirstSubscribe: () => {
match?.addEventListener("change", notify);
return () => {
match?.removeEventListener("change", notify);
};
} });
const defaultMatches = options.defaultMatches ?? false;
const get = () => match?.matches ?? defaultMatches;
return createReadableSubscription(get, subscribe, notify, () => defaultMatches);
}
//#endregion
export { createMediaQuery };