Releases: foo-stack/usemotif
v1.0.1 — RTL, reduced motion, and six more fixes
A patch release: eight fixes across the renderers, the token presets, the headless layer, and the docs. Every package ships at 1.0.1.
Merged via #19.
Added
- RTL / bidirectional layout. A
<Direction>provider anduseDirection()hook on both renderers. New logical style props —ps/pe/ms/me, thestart/endinsets, and thepaddingInline*/marginInline*/insetInline*long forms.px/mxresolve to the logicalpaddingInline/marginInline, so they adapt to writing direction. (#11, #16) useReducedMotion(). A cross-platform hook in@usemotif/headless—matchMediaon web,AccessibilityInfoon native. Headless components skip their enter/exit animation when the user prefers reduced motion. (#12)- Default
borderWidthsandletterSpacingstoken scales. The default light and dark themes ship both scales, so$borderWidths.*/$letterSpacings.*references resolve out of the box. (#13) @usemotif/react/svgentry. A dedicated, tree-shakeable export for theIconandSvgprimitives. (#10)
Changed
- Smaller icon imports.
@usemotif/iconsglyphs import through@usemotif/react/svg— a single-icon import drops from ~6.2 KB to ~0.6 KB gzip. No API change. (#10) @usemotif/compiler-swcpackage description. Corrected to describe the package as it is — a universalunpluginrunning the Babel-based transform, not an SWC plugin. (#14)
Fixed
- Invisible native
<Heading>/<Paragraph>text. A unitlesslineHeightwas read as absolute pixels by React Native and clipped glyphs to nothing; it is now resolved against the font size. (#17) - Next.js setup docs. The bundler guide now documents the
transpilePackagesconfiguration the official example app relies on. (#15)
v1.0.0 — the @usemotif/* graduation
motif graduates to a deliberate v1.0.0 — the full library, consolidated under
a single @usemotif/* scope.
motif spent its pre-1.0 life under the @motif-js/* scope — v0.1.0 through
an unintended early 1.0.0, then two namespace renames the migration guides
call v2 and v3. 1.0.0 is the deliberate v1, with the meta package as the
unscoped usemotif. The legacy @motif-js/* packages stay on npm, frozen,
with deprecation notices pointing at the migration guides.
The runtime, the token model, and the component API are unchanged from the
final @motif-js/* releases — 1.0.0 is a packaging and stability milestone,
not a behaviour change.
Install
yarn add usemotif @usemotif/tokensAdded
- Styling core — style-prop API and
styled()factory; two-layer token
system (primitive palette + semantic intent); nestable<Theme>sub-themes. - Responsive system — container and media queries through three syntaxes
(object, array, string DSL), with a native container-query polyfill. - ~50 primitives — layout, typography, media, forms, scroll, and a11y,
cross-platform. - ~38 headless behaviour components — Dialog, Popover, Menu, Combobox,
Tabs, Tooltip, ColorPicker, CommandPalette, MultiSelect, TreeView, and the
rest — unstyled, WAI-ARIA correct, keyboard + screen-reader complete on both
platforms. - Animation — mount/unmount transitions via
enterStyle/exitStyle/
transition; native timing driver + optional Reanimated spring driver. - Progressive compiler —
@usemotif/compiler-core,-babel,-swc,
-metro. The runtime path works unchanged with no plugin installed. @usemotif/icons— generator-driven, lucide-backed icon set.@usemotif/reset— opt-in CSS reset that does not fight the runtime.@usemotif/test-utils— cross-renderer conformance suite + Vitest matchers.- SSR —
SSRStyleCollectorand a streaming style registry for Next.js.
Changed
- Namespace consolidated to
@usemotif/*— all thirteen scoped packages
moved from@motif-js/*; the meta package stays unscoped asusemotif.
Every package ships a fresh1.0.0on the new scope.
Deprecated
- The
@motif-js/*scope — existing installs keep working; new installs
see npm deprecation notices. Runnpx @usemotif/migrate rename-v3to migrate.
Fixed
- SWC compiler CSS delivery — emits aggregated CSS through a virtual module.
- Workspace dependency publishing —
workspace:*ranges rewrite correctly.
Docs: https://usemotif.dev · Full changelog: CHANGELOG.md
v0.3.0 — Phase D: Compiler
motif-js's progressive compiler ships. The runtime keeps working as before; opt-in compile-time
extraction folds static motif call sites into baked style + className + at-rule CSS, and the runtime
fast-paths the result. Compiled output is byte-identical to runtime output — half-compiled
half-runtime apps dedupe to one set of m- classes, not two.
Highlights
🔧 Four new @motif-js/compiler-* packages
- @motif-js/compiler-core — renderer-agnostic Babel-AST classifier. Splits each motif JSX call site
into static / partial-static / dynamic. Reuses @motif-js/core's resolver so compiler and runtime
always agree. - @motif-js/compiler-babel — the canonical Babel plugin (164 LOC). Drops consumed style props, merges
baked attrs with user-supplied ones (user values win), aggregates per-file CSS via onCss. - @motif-js/compiler-swc — universal unplugin@3 shim (107 LOC). One source, six bundlers: vite /
rollup / webpack / rspack / esbuild / farm. Layers BEFORE the host's SWC pass on Next /
@vitejs/plugin-react-swc. - @motif-js/compiler-metro — Metro/Expo Babel-tuple wrapper (41 LOC). Drops into babel.config.js's
plugins array.
⚡ 1.73× faster on render-heavy paths (200-Box bench, server-side render with cold style cache):
┌─────────────────────────────────────────────────┬───────┬─────────┬──────────────┐
│ variant │ hz │ mean │ speedup │
├─────────────────────────────────────────────────┼───────┼─────────┼──────────────┤
│ runtime — │ 1,096 │ 0.91 ms │ 1.00× │
├─────────────────────────────────────────────────┼───────┼─────────┼──────────────┤
│ compiled — post-plugin shape │ 1,895 │ 0.53 ms │ 1.73× faster │
├─────────────────────────────────────────────────┼───────┼─────────┼──────────────┤
│ vanilla
└─────────────────────────────────────────────────┴───────┴─────────┴──────────────┘
Compiled closes 80% of the runtime → vanilla gap. The original 5–10× target retires — actual
measurement is the source of truth.
🚀 Box runtime fast-path. After the compiler strips static style props, early-returns a plain
Try it
yarn add @motif-js/compiler-swc -D
// vite.config.ts
import motif from '@motif-js/compiler-swc';
import react from '@vitejs/plugin-react-swc';
export default {
plugins: [motif.vite(), react()],
};
That's it — every whose props are compile-time literals turns
into pre-baked style + className. Dynamic props stay at runtime untouched.
What's not in this release
- Wrapper-stripping for fully-static cases (replacing with in compiled output) — open
lever to push perf higher in a later release. - Pseudo-state extraction (_hover / _focus / _active) on Pressable — 3 differential cases skip these
today. - Native StyleSheet.create({...}) hoisting in compiler-metro — the native target is currently a
Babel-side no-op while the runtime keeps resolving. Future minor. - Cross-library bench comparisons (Tamagui, NativeWind, Stitches) — legitimacy data, not a release
gate.
What's next
Phase E: primitives buildout. Filling out the components roster (forms, layout primitives, surfaces)
on the foundation Phases A–D laid down.
Full changelog
v0.2.0 — Phase C native parity
Phase C — Native parity
@motif-js/react-native reaches feature parity with the web renderer. Same prop schema, same theming
model, same responsive shapes, same container-query semantics — running on RN's StyleSheet, with
theming via JS context, and container queries polyfilled via View.onLayout.
The cross-renderer conformance suite (@motif-js/test-utils's standardCases) passes 18/18
against both renderers' adapters. "Same input → same resolved values" holds across the two trees.
Install
yarn add @motif-js/react-native @motif-js/tokens
# also works:
# npm install @motif-js/react-native @motif-js/tokens
# pnpm add @motif-js/react-native @motif-js/tokens What's in
- Native primitives —
Box,Stack/HStack/VStack,Text,Pressable,Image,
Container. Same prop schema as@motif-js/react-web; literal-mode style resolution (no CSS
variables on RN). - Theming —
ThemeProvider,<Theme name>boundary,useTheme/useThemeNamehooks.
JS-context based — theme switches re-render consumers. - Viewport-driven responsive resolution — every responsive shape (object / array / DSL) resolves
against the current viewport width viaDimensions.addEventListener('change', …). Re-renders on
rotation / split-screen / window resize. - Container-query polyfill —
<Container name?>measures itself viaView.onLayout, exposes
width via React context.@<bp>/@<name>.<bp>keys resolve against the matching container's
width.rateCapMsprop tunes re-measure throttle (default 16ms = 1 frame at 60fps; opt out with
0). - Cross-renderer conformance — native ships its own
RendererAdapter; the samestandardCases
from@motif-js/test-utilsrun against both adapters. Web 18/18, native 18/18. - Expo demo app —
apps/playground-native(in the repo, not published) exercises the full
surface end-to-end.
What's not in
- Visual regression (Detox + Playwright) — deferred to v0.8+.
- Bare RN demo app — Expo Router demo covers the same surface.
- Compiler (Phase D) — still placeholder stubs.
Workspace stats
- 341 vitest tests pass (103 core + 99 react-web + 88 react-native + 20 tokens + 31 utils)
- 19/19 packages build clean
- 23/23 typecheck clean
- 0 lint errors
- All 16 publishable packages bumped from
0.1.0→0.2.0
Phase C ROADMAP at release
- ✅ All
@motif-js/react-nativeengineering boxes - ✅ Container query polyfill (
onLayout+ context + rate cap) - ✅ Conformance suite running both renderers (zero divergences)
- ✅ Snapshot tests across primitives (web + native)
- ✅ Expo Router demo (typechecks + bundles cleanly via Metro; runs on iOS / Android / web)
- 🟦 Visual regression / on-device benchmarks — deferred to v0.8+
Full changelog: v0.1.0...v0.2.0