seitu
Version:
79 lines (55 loc) • 1.96 kB
Markdown
Reactive width and height of an element, driven by `ResizeObserver`.
```ts
import { createElementSize } from 'seitu/web'
const size = createElementSize({
element: document.querySelector('.container'),
box: 'content-box',
})
size.get() // { width, height }
size.subscribe(({ width }) => console.log(width))
```
| Option | Type | Description |
|--------|------|-------------|
| `element` | `Element \| null \| (() => Element \| null)` | Target element; getter is resolved once on first subscribe |
| `box?` | `'content-box' \| 'border-box'` | Box to measure (default `'border-box'`) |
## Interface
```ts
interface ElementSize extends Subscribable<ElementSizeValue>, ServerReadable<ElementSizeValue> {}
interface ElementSizeValue {
width: number
height: number
}
```
Sizes ignore CSS transforms, like `ResizeObserver`. A null element and the
server snapshot return `{ width: 0, height: 0 }`.
```tsx
const [el, setEl] = useState<HTMLDivElement | null>(null)
const { width, height } = useSubscription(
() => createElementSize({ element: el }),
{ deps: [el] }
)
return <div ref={setEl} />
```
Wrong:
```tsx
const ref = useRef<HTMLDivElement>(null)
useSubscription(() => createElementSize({ element: () => ref.current }), { deps: [] })
```
The getter runs once on first subscribe. If the element is not mounted yet, or
unmounts and remounts, the observer never attaches to the live element.
Correct:
```tsx
const [el, setEl] = useState<HTMLDivElement | null>(null)
useSubscription(() => createElementSize({ element: el }), { deps: [el] })
return <div ref={setEl} />
```
Replace a `useEffect` that creates a `ResizeObserver` and copies the size into
state with `createElementSize` + `useSubscription`.
`src/web/element-size/index.ts`