Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
# `useMobile()` — viewport-width breakpoint hook
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Returns `true` when the viewport width is at or below the supplied
`breakpointPx` (defaulting to 768px, which mirrors Tailwind's `md`
breakpoint). The hook subscribes to a `matchMedia` listener — NOT a
polling timer — so layout changes propagate without forcing a re-render
on every scroll/resize tick. SSR-safe.
## Features
- Subscribes via `matchMedia` so re-renders happen only on actual
threshold crossings
- Returns `false` server-side (no `window`) so SSR HTML matches the
desktop layout by default
- Configurable breakpoint per-call site
- Cleans up the listener on unmount
## Usage: Basic example
```tsx
import { useMobile } from "@suaveplan/react-ui/hooks/use-mobile";
function Layout() {
const isMobile = useMobile();
return <div data-mobile={isMobile}>{isMobile ? <Drawer /> : <Sidebar />}</div>;
}
```
## Usage: Advanced example
```tsx
import { useMobile } from "@suaveplan/react-ui/hooks/use-mobile";
function ResponsiveTable() {
const isCompact = useMobile(640);
return (
<table>
<thead>
{isCompact ? <th>Item</th> : <><th>SKU</th><th>Name</th><th>Price</th></>}
</thead>
…
</table>
);
}
```
## API Reference
- `useMobile(breakpointPx?: number = 768): boolean`
## Implementation notes
The hook holds a `useState` initialised by reading
`window.matchMedia(...).matches` synchronously inside the initialiser
when `window` is available — this gets the post-mount state right
without an extra render. The post-mount `useEffect` then calls the
listener once to sync against any state drift between SSR and the
client. The `change` listener tears down on unmount AND when
`breakpointPx` changes so a parent that swaps the breakpoint mid-life
gets a fresh subscription. The chassis defaults to 768px (Tailwind's
`md` boundary) but consumers picking other breakpoints get the same
zero-extra-render behaviour. Defensive guards: when `matchMedia`
itself throws (some restricted-permissions browsers), the listener
setup short-circuits and `isMobile` stays at its initial value.