@llui/effects
v0.0.3
Published
LLui effect builders — http, cancel, debounce, sequence, race, storage, broadcast
Maintainers
Readme
@llui/effects
Effect builders for LLui. Effects are data -- update() returns them, the runtime dispatches.
pnpm add @llui/effectsUsage
import { http, cancel, debounce, handleEffects } from '@llui/effects'
// Debounced search with cancel
function update(state: State, msg: Msg): [State, Effect[]] {
switch (msg.type) {
case 'search':
return [
{ ...state, query: msg.value },
[
cancel('search'),
debounce(
'search',
300,
http({
url: `/api/search?q=${msg.value}`,
onSuccess: (data) => ({ type: 'results', data }),
onError: (err) => ({ type: 'searchError', err }),
}),
),
],
]
}
}
// Wire up in component
const handler = handleEffects<Effect, Msg>()
.use(httpPlugin)
.else((effect, send) => {
/* custom effects */
})API
Effect Builders
| Function | Description |
| ---------------------------------------------------------- | ----------------------------------------------- |
| http({ url, onSuccess, onError }) | HTTP request effect |
| cancel(token, inner?) | Cancel by token, optionally replace with inner |
| debounce(key, ms, inner) | Debounce inner effect by key |
| timeout(ms, msg) | Fire msg after delay |
| interval(ms, msg) | Fire msg on interval |
| storageSet(key, value, storage?) | Write to localStorage/sessionStorage |
| storageGet(key, onResult, storage?) | Read from storage |
| storageRemove(key, storage?) | Remove from storage |
| storageWatch(key, onChange) | Watch storage for changes |
| broadcast(channel, data) | Send on BroadcastChannel |
| broadcastListen(channel, onMsg) | Listen on BroadcastChannel |
| sequence([...effects]) | Run effects in order |
| race([...effects]) | Run effects concurrently, first wins |
| upload({ url, body, onProgress, onSuccess, onError }) | File upload with progress via XHR |
| clipboardRead({ onSuccess, onError }) | Read text from clipboard |
| clipboardWrite(text) | Write text to clipboard (fire-and-forget) |
| notification(title, opts?) | Show browser notification (requests permission) |
| geolocation({ onSuccess, onError, enableHighAccuracy? }) | One-shot geolocation position |
Upload
Upload files with progress tracking via XMLHttpRequest:
import { upload } from '@llui/effects'
const effect = upload({
url: '/api/upload',
body: formData,
headers: { Authorization: `Bearer ${token}` },
onProgress: (loaded, total) => ({
type: 'uploadProgress',
pct: Math.round((loaded / total) * 100),
}),
onSuccess: (data, status) => ({ type: 'uploadDone', data, status }),
onError: (error) => ({ type: 'uploadFailed', error }),
})Clipboard
Read and write text via the Clipboard API:
import { clipboardRead, clipboardWrite } from '@llui/effects'
// Copy text to clipboard (fire-and-forget)
clipboardWrite('Hello, world!')
// Read text from clipboard
clipboardRead({
onSuccess: (text) => ({ type: 'pasted', text }),
onError: (error) => ({ type: 'clipError', error }),
})Notification
Show browser notifications (requests permission automatically):
import { notification } from '@llui/effects'
notification('New message', {
body: 'You have a new message from Alice',
icon: '/avatar.png',
onClick: () => ({ type: 'openChat' }),
onError: () => ({ type: 'notifBlocked' }),
})Geolocation
One-shot position request:
import { geolocation } from '@llui/effects'
geolocation({
enableHighAccuracy: true,
onSuccess: (pos) => ({
type: 'located',
lat: pos.latitude,
lng: pos.longitude,
}),
onError: (error) => ({ type: 'geoError', error }),
})Effect Handling
| Function | Description |
| ----------------------- | ------------------------------------------------ |
| handleEffects<E, M>() | Chainable effect handler builder |
| .use(plugin) | Add an effect handler plugin |
| .else(handler) | Fallback for unhandled effects |
| resolveEffects(def) | SSR data loading -- resolves effects server-side |
Types
| Type | Description |
| ------------- | -------------------------------------------------------------------------------------------------- |
| Async<T, E> | idle \| loading \| success \| failure -- async data state |
| ApiError | network \| timeout \| notfound \| unauthorized \| forbidden \| ratelimit \| validation \| server |
License
MIT
