@bootnodedev/canton-dappbooster
v0.4.0
Published
Reusable UI components for Canton dApps
Keywords
Readme
@bootnodedev/canton-dappbooster
Reusable UI components for Canton dApps — reading Canton identifiers (display, truncation,
copy-to-clipboard, explorer links) and entering them (validated party-id input). Amounts are the
other half: a token-amount field, plus the exact-decimal utilities under it, because a number
cannot carry a Canton amount without losing digits.
src/index.ts is the public API, and every export carries JSDoc that your editor will surface at
the call site and that is published at
docs.dappbooster.cc. The wallet
buttons sit behind the /connect sub-path instead, because they reach for the wallet session and so
pull in the Canton SDK. Authoring rules for
new components live in CLAUDE.md.
Scripts
| Script | What it does |
| --- | --- |
| pnpm build | tsdown → dist/ (ESM index.js + connect.js, each with its .d.ts) |
| pnpm test | vitest (jsdom + Testing Library), against src |
| pnpm typecheck | tsc --noEmit |
Build & dev loop
tsdown builds ESM + .d.ts to dist/. Components carry no CSS, so sideEffects: false holds and
the bundle tree-shakes cleanly. exports carries a development condition → src, so Vite serves
source live in dev; dist is used for production and publish.
Consumers resolve source in dev and typecheck (no kit build needed); their production build resolves
dist. Build the kit first, or run pnpm build from the repo root, which builds workspaces in order.
React 19 only, peer and dev alike.
A consumer whose React resolves to a different copy than the kit's ends up with two Reacts in one
bundle, where hooks read a null dispatcher and every render throws. Only a production build shows
it, since the development condition resolves the kit to source. resolve.dedupe in the bundler
is the fix.
Styling: components carry none
Components (L2) ship zero styling opinion. Styling lives in the separate
@bootnodedev/canton-theme package (L3), which consumers import explicitly:
import '@bootnodedev/canton-theme/tokens.css'
import '@bootnodedev/canton-theme/default.css'The contract between the two is the DOM each component renders — not code. See
architecture.md for the seam and the reasoning.
Light / dark / system
The one styling-adjacent runtime this package does ship. <ThemeProvider> owns the mode and writes
data-theme to <html>, which is what the theme keys its dark values on; useTheme() reads and
sets it. No token names live here.
A reload flashes the page background before React applies the attribute, and this package ships
nothing to prevent it. architecture.md has the reasoning.
Client-only: the provider reads the OS preference as it mounts, so a server render throws.
import { ThemeProvider, useTheme } from '@bootnodedev/canton-dappbooster'
const App = () => (
<ThemeProvider>
<Page />
</ThemeProvider>
)
const ModeToggle = () => {
const { resolved, toggle } = useTheme()
return <button onClick={toggle}>{resolved === 'dark' ? 'Light' : 'Dark'}</button>
}