@synpuls/when
v1.0.0
Published
react-display-switch に倣って作った、宣言的な条件表示コンポーネントを生成するライブラリ
Maintainers
Readme
When
A tiny library for generating declarative conditional-rendering components, inspired by react-display-switch.
Generate When / WhenNot components from an arbitrary set of conditions, and combine them with and / or to toggle what is displayed.
- https://www.npmjs.com/package/@synpuls/when
Installation
npm install @synpuls/whenreact (>=18) is a peer dependency.
Usage
import { useState } from 'react'
import { createWhen } from '@synpuls/when'
// A trivial "store". Conditions are plain `() => boolean` predicates,
// so they can read from anywhere in scope.
const store = { user: null as { role: string } | null }
// Register your conditions once.
const { When, WhenNot } = createWhen({
isLoggedIn: () => store.user !== null,
isAdmin: () => store.user?.role === 'admin',
})
const App = () => {
// Conditions are re-evaluated on every render, so trigger a re-render
// (here via state) after the data they read changes.
const [, forceRender] = useState(0)
const signInAsAdmin = () => {
store.user = { role: 'admin' }
forceRender((n) => n + 1)
}
return (
<>
<When isLoggedIn>Welcome back!</When>
<WhenNot isLoggedIn>
<button onClick={signInAsAdmin}>Sign in</button>
</WhenNot>
{/* Multiple conditions require an explicit `and` / `or` */}
<When isLoggedIn and isAdmin>
Admin dashboard
</When>
</>
)
}Case props are boolean flags — write <When isLoggedIn> (equivalent to isLoggedIn={true}). You can also read a condition's current value directly with When.case('isLoggedIn').
API
createWhen(cases)— build{ When, WhenNot }from a condition map. Requires at least one condition.When/WhenNot— show / hide children based on the conditions.WhenNotrenders the logical negation ofWhen.- Passing multiple conditions requires an explicit
andoror(they are mutually exclusive). When.case(label)returns the condition's current boolean;When.casesexposes the (frozen) registered map.
- Passing multiple conditions requires an explicit
children,and,orare reserved and cannot be used as condition labels.
Behavior & limitations
- Evaluated on render, not subscribed. Conditions are re-run every time the component renders; the library does not subscribe to external sources. To reflect a change (viewport size, store, etc.), make sure something triggers a re-render, and keep predicates side-effect-free and cheap. For viewport-based conditions, read from React state fed by a listener rather than calling
window.matchMediadirectly inside a predicate (which is also not SSR-safe). - Flat, single operator only. You can express
a and b and cora or b or c, but not mixed logic like(a and b) or c. Compose complex conditions increateWheninstead, e.g.phonePortrait: () => isPhone() && isPortrait(). true-only flags. Case props andand/oraccept onlytrue(or omission); the types reject non-truevalues at compile time. Passing a non-truevalue to a case prop throws at runtime. Forand/or, a non-truevalue is treated as "not specified" (so multiple cases without an effective operator still throw "must specify an operator").
Development
npm run typecheck # type check (includes *.test-d.tsx type tests)
npm test # tests (vitest)
npm run lint # lint / format check (biome)
npm run format # auto-fix
npm run build # generate dist (tsup)License
MIT
