Core
Browser APIs
@weft-js/core/browser gives you the browser's changing values, such as being online or a tab being visible, as values you read in JSX. It handles the listeners and the cleanup.
tsx
import { state } from '@weft-js/core'import { online, visible, lifecycle, media, on, interval } from '@weft-js/core/browser'export function Toolbar() { const isOnline = online() // Derived<boolean>; server: true const shown = visible() // Derived<boolean>; server: true const page = lifecycle() // 'active' | 'passive' | 'hidden' | 'frozen' | 'terminated' const dark = media('(prefers-color-scheme: dark)', { ssr: false }) // server renders `ssr` const open = state(true) const now = state(Date.now()) on(window, 'keydown', e => { if (e.key === 'Escape') open.value = false }) // e: KeyboardEvent interval('1s', () => { now.value = Date.now() }) // also '500ms', '5m', '1h', or a number of ms return ( <p hidden={!open.value}> {isOnline.value ? 'online' : 'offline'}, {dark.value ? 'dark' : 'light'}, {shown.value ? page.value : 'hidden'}, {new Date(now.value).toLocaleTimeString()} </p> )}- Call them in setup (a component body, a
defineStatesetup, orcreateRoot). Their owner removes them; created anywhere else (module scope, a timer, a handler, afterawait) they throw in dev and are W051. - Values subscribe on first read and share one listener per event, however many components read them.
- On the server a value is its
ssrvalue (online/visible:true,lifecycle:'active').mediahas no default: passssrin server-rendered components (W054). Hydration renders the server value, then the real one. - Not
window.addEventListener/setIntervalin components (W050, with an edit toon/interval), and notwatch(() => live.value, v => { s.value = v })(W056): readlive.valuewhere you need it. tabs.channel('cart', schema)is a validatedBroadcastChannelbetween tabs:.post(msg),.on(fn),.value.state(init, { persist: 'local', sync: 'tabs' })in adefineStatekeeps a box the same in every tab (S008 withoutpersist, or withsession).
In tests (@weft-js/core/test): await net.offline(), net.online(), page.hide(), page.show(), page.blur(), page.focus(), page.freeze(), page.resume(), page.leave({ persisted }), page.restore(), page.media(query, true), tabs.post(name, msg), tabs.posted(name). Each test starts online, visible and focused with every query false. After each test @weft-js/core/test fails if anything is still open (T012); leaks() lists it.