@azmr/ui
Release history for @azmr/ui.
View as Markdown for coding assistants, or see llms.txt.
0.12.1
Patch Changes
- 1baf44e:
StateViewtitleAsacceptsh1, for a state that is the whole page (a 404 page, a root error page) with no other heading.
0.12.0
Minor Changes
- d31c392: Add loading states (PAZM-122).
Spinnergainssize(xstoxl, orinheritfor 1em; default unchanged),tone(Progress's tones; default still the text colour) anddelay(milliseconds before it fades in, in CSS, so it works in Server Components). New@azmr/ui/loading(Server Components):Loading, a spinner with a visible, announced message (beside, below or screen-reader only) asinline,section(Suspense fallbacks) orpage(loading.tsx, 200 ms delay by default), with an optionallogothat a ring spins around while the logo stays upright, or that pulses. New@azmr/ui/loading/client:LoadingOverlaykeeps refetching content on screen, dimmed andaria-busy, with a spinner and message over it;LoadingBaris a GitHub-style bar fixed to the top of the page that creeps towards 90% while loading, then fills and fades, or shows a knownvalue;useLoadingState(loading, { delay, minDuration })gives the same show-late, stay-long timing for your own indicator.progressTonesmoved to its own module (still exported from@azmr/ui/progress). - 54c7ca1: Add route-level states (PAZM-82). New
@azmr/ui/state-view(Server Component):StateView, one layout (icon, title, description, action) for a region'sloading,emptyanderrorstates, as a section or a full page; loading is a polite status built onLoading(logo and delay included, so it doubles as the page loader), error is an alert, and the title's heading level is configurable. New@azmr/ui/error-boundary:ErrorBoundarywith anonError(error, info)reporting hook for any service,resetandresetKeysfor recovery, a customfallbackorfallbackProps, andrethrowto let framework errors through (pass Next.js'sunstable_rethrowsoredirect()andnotFound()keep working). The default fallback never shows the error's message. Add theinboxicon to@azmr/ui/icons/lucide.
0.11.0
Minor Changes
-
caeef37: Forms now work with controls from other libraries, and rows can be changed from code.
Fieldaccepts a function child for any control that isn't a Base UI one, such as a Radix (shadcn) Select trigger, a native<select>or a third-party date picker. It gets{ id, aria-labelledby, aria-describedby, aria-invalid, aria-required, aria-errormessage }to spread on the control, so the label points at it and the description and error describe it. New type:FieldControlProps.FormField'srendergets the same props ascontrol. Spread them on the element that takes focus. The elementrenderreturns no longer getsaria-requiredoraria-errormessagecloned onto it, becausecontrolcarries them.FormFieldArraytakesfieldArray, your ownuseFieldArrayresult, so other parts of the form canreplace()orappend()rows. Itsrow.name()is typed:row.name("qty")is`lines.${number}.qty`, ready forFormField'sname, and an unknown field fails to compile. In an untyped form it stays astring. New type:FormFieldArrayRow.NumberFieldandMoneyFieldtakegroupClassNamefor the border, height and radius around the input, and mark their parts withdata-slot(number-field,number-field-group,number-field-input).
0.10.0
Minor Changes
- 724dcff: Add
@azmr/ui/field-array:FieldArray, a repeating group of fields (invoice lines, contacts, addresses) that works with any form state. Rows are added, removed and reordered by pointer drag (mouse, touch, pen; Escape cancels), by the arrow keys, Home and End on each row's handle, or with optional move buttons.minandmaxdisable the remove and add buttons without taking them out of the tab order;emptyshows when there are no rows,headeradds column headings for a table-like layout andfooterrenders totals from them. Focus moves to a new row's first field, to the neighbour of a removed row and back to a moved row's handle, and every change is announced in a polite live region; all text is replaceable throughmessages. AddFormFieldArrayto@azmr/ui/rhf, which runsuseFieldArray, shows the array's own error under its legend and feedsfooterthe current values without re-rendering the rows. FixFormFieldreplacing the control's ownrefwhen it registers it: both refs now get the element.
0.9.0
Minor Changes
-
1322095: Per-component class lists replace the stylesheet's
@sourcescan, so an app only generates CSS for the components it uses.tokens.css(and sostyles.css) no longer contains@source "./**/*.js". That rule made Tailwind scan every file in the package, so an app that used Button and Input still generated the CSS for toast, the drawer, the accordion and every other component: in app.azmara.io, 523 of its 1,289 utility classes, about 10 kB gzip of render-blocking CSS and roughly 150 ms of first paint.Instead, each entry point ships a class list, generated at build time with Tailwind's own scanner:
@azmr/ui/classes/<entry>.cssholds exactly the classes that entry's JavaScript uses (shared chunks included), and@azmr/ui/classes.cssholds them all.Migration (required): add the class lists to your global CSS, after the stylesheet. Either list the entries you use:
@import "tailwindcss"; @import "@azmr/ui/styles.css"; @import "@azmr/ui/classes/button.css"; @import "@azmr/ui/classes/input.css";or keep generating everything, as before, with one line:
@import "@azmr/ui/classes.css";Without either, components render unstyled. A Button and Input app goes from about 13 kB to about 6 kB of CSS (gzip). The build checks that
classes.cssgenerates exactly what the old scan did, and that a Button and Input app stays within a 6.5 kB budget.
0.8.0
Minor Changes
- 480388b: Add the debounce contract to
Input:debounceMsdelaysonValueChange,onCommitfires on blur or Enter (not while an input method is composing) after sending any waiting value,data-pendingmarks a waiting value, a waiting value is dropped on unmount, and an unchanged value is never reported or committed twice. The nativeonChangestays immediate, soregister()is unaffected.@azmr/ui/hooksnow exportsuseDebouncedCallback(stable, withflush,cancelandisPending) anduseDebouncedValue. - b5585b6: Add the form adapters.
@azmr/ui/rhf(React Hook Form 7, optional peer):Form(anoValidateform withFormProviderandhandleSubmit),FormField(aFieldthat registers its control withregister(), so there is noController, shows the field's error and required state, and switches touseControllerwithcontrolledorrenderfor controls without an input ref) andFormErrorSummary.@azmr/ui/zod(Zod 4, optional peer, server-safe):zodResolver(async refinements, parsed output, nested and array paths,rootfor object-level issues,criteriaMode: "all") andfieldsFromSchema/fieldFromSchema, which describe a schema's fields (label, control type, required, limits, enum options, metadata) for generated forms.ErrorSummarynow lists errors in the order their fields appear on the page, with form-level errors first. - 4deeaee: Add
@azmr/ui/number-field:NumberFieldandMoneyFieldon Base UI's NumberField. They format withIntl.NumberFormatfor the locale (LocaleProvider, en-NZ and NZD without one), report a realnumberornulland never a formatted string, clamp tomin/max, supportstep,allowNegative,decimalScale,grouping,format, an optional stepper, paste parsing and a wheel guard, and follow thedebounceMs/onCommitcontract.MoneyFieldrounds to the currency's minor unit.register()works without aController:refis the named hidden number input,onChange/onBlurget real DOM events on it, andnumberOrNullis a readysetValueAs. Both fit inside anInputGroup.
0.7.0
Minor Changes
- aaace08: Add
@azmr/ui/password-input:PasswordInputwith a show/hide toggle (a button witharia-pressedand a fixed "Show password" name), an optional strength meter (strength, with a small length-first default scorer or your own, such as zxcvbn-ts) and an optional requirement checklist (requirements, with ready-madepasswordRequirements) whose changes are announced politely.autoCompletedefaults tocurrent-password, paste is never blocked, and the password is hidden again when its form submits so password managers offer to save it. Therefis the real<input>, soregister()works without aController.
0.6.0
Minor Changes
- e085ee5: Add
@azmr/ui/form:Fieldset(legend, description and group error for grouped controls),FormSection(titled sections for long forms, with one or two columns and an optional heading-beside-fields layout that responds to the section's own width) andErrorSummary(the GOV.UK error summary: after a failed submit it takes focus and lists each error as a link that moves focus to its field).ErrorSummaryreads React Hook Form'sformState.errors, Base UI Form'serrorsor a plain record, so it needs noController. - 16ab0f1: Add
@azmr/ui/input-group:InputGroup,InputGroupInput,InputGroupAddonandInputGroupButtonput text, icons and buttons inside an input's border (a currency or unit, a search icon, a clear or copy button). The border and focus ring wrap the whole group and the height follows the density tokens. Text addons join the input's accessible description and icon addons are hidden from screen readers. Buttons aretype="button"and sit in the tab order after the input. Inside aField,aria-requiredandaria-errormessagereach the input, andInputGroupInputforwards the real<input>ref soregister()works without aController.
0.5.0
Minor Changes
- 690ba1f: Add
Field(@azmr/ui/field) andTextarea(@azmr/ui/input).Fieldwraps one control with a label, description, error and required marker on Base UI's Field, and wiresid,aria-labelledby,aria-describedby,aria-invalid,aria-errormessageandaria-required; errors are announced through a polite live region. Passerrors.<name>?.messagefrom React Hook Form aserror.FieldRoot,FieldLabel,FieldDescriptionandFieldErrorcompose custom layouts.Textareaforwards the real<textarea>ref and has anautoResizeoption.
0.4.1
Patch Changes
- ea59e9b: Package metadata:
homepagenow points at each package's page on platform.azmara.io (docs.azmara.io never resolved),bugslinks to the GitHub issues, and README doc links follow.@azmr/uigets a description that matches the design system it now is.
0.4.0
Minor Changes
-
d756ee0: Make the server-safe entries truly server-safe. lucide-react 1.x's icons are client components, so
@azmr/ui/display,@azmr/ui/stepper,@azmr/ui/breadcrumb,@azmr/ui/paginationand@azmr/ui/icons/lucidesent Lucide's runtime (about 44 kB before compression) to every page that used them, even from a Server Component.- Built-in icons are now glyphs: plain SVG rendered on the server from the
lucidepackage's shape data, with exactly the markup lucide-react renders (attributes,lucide lucide-<name>classes and alias classes,aria-hidden), tested against lucide-react for every icon. The client components (menu, modal, toast, accordion, split button) use them too. lucideIconsand the namedIconfrom@azmr/ui/icons/lucidenow hold these glyphs. They take the same props as lucide-react's icons (size,color,strokeWidth,absoluteStrokeWidth), but their TypeScript type isGlyphrather thanLucideIcon.lucidebecomes a dependency (shape data only, no React).lucide-reactstays a dependency and is upgraded to 1.59.0.- The build now fails if a server-safe entry imports
lucide-react, and the consumer check builds a Next.js page from every server-safe entry and fails if its client manifest gains anything from@azmr/uior Lucide.
- Built-in icons are now glyphs: plain SVG rendered on the server from the
0.3.0
Minor Changes
-
d7d6b2b: Add
@azmr/ui/motion, an optional module for themotionlibrary.MotionProvidersets upLazyMotion(the animation features load on demand,domby default ormaxfor layout animation, drag and reorder) andMotionConfig reducedMotion="user", and is strict by default so the fullmotioncomponent cannot be pulled into your bundle by accident. The module re-exportsm,AnimatePresence,Reorder,animate,useAnimate,useInView,useMotionValue,useSpring,useTransformanduseDragControls, and addssprings(gentle,snappy,bouncy).motionis an optional peer dependency (^14.0.0, tested against 14.2.0): installing@azmr/uidoes not install it, and nothing outside this module imports it. The wrapper is about 0.5 kB.
0.2.0
Minor Changes
-
7edd869: Add the button family.
@azmr/ui/buttongainsIconButton(a requiredlabelis its accessible name, type-enforced) andButtonGroup(a named, joined group). New entries:@azmr/ui/toggle(Toggle,ToggleGroup: single or multiple selection, roving keyboard) and@azmr/ui/split-button(SplitButton: a primary action plus a menu of related ones). -
3efa36a: Add
Button,InputandSpinner, built on Base UI primitives, the design tokens and CVA variants.Button: variantsdefault | secondary | outline | ghost | destructive | link, sizessm | md | lg | icon,loading/loadingText/startIcon/endIcon,type="button"by default,renderfor links. A loading button ignores activation but stays focusable. Icon-only buttons are type-checked to requirearia-labeloraria-labelledby.Input:refis the real<input>, soreact-hook-form'sregister()works with noController; nativeonChangeand typedonValueChange; density-token height and padding; full-strength focus ring.Spinner: decorative by default or a labelled status; stays animated under reduced motion.- New subpaths
@azmr/ui/button,@azmr/ui/input,@azmr/ui/spinner(client entries) and root exports for all three, plusbuttonVariants. @base-ui/reactandclass-variance-authoritybecome dependencies. Tree-shaking is budget-tested: importing onlyuseSignalfrom the root costs 0.1 kB.
-
4b117dc: Add the
@azmr/ui/styles.cssdesign tokens and Tailwind v4 theme mapping.- shadcn-compatible token names (
--background,--primary,--ring,--radius,--sidebar-*) plus--success,--warning,--info,--chart-1..8,--motion-*,--elevation-*,--z-*and--density-*. - OKLCH colours with
light-dark(): follows the system by default, or force a mode with.dark/.light/data-theme. No JavaScript, no flash. - Density via
data-density="compact|spacious"; reduced motion collapses the motion tokens and adds a safety net (spare essential motion withdata-motion="essential"). - Verified by tests: WCAG AA contrast for every token pair in both modes, 3:1 for the focus ring and chart colours, chart colours distinguishable under protan/deutan/tritan simulation, and the real Tailwind v4 compiler generating every utility.
package.jsonnow exports./styles.cssand marks only CSS as side-effectful (sideEffects: ["**/*.css"]).
- shadcn-compatible token names (
-
0fb248b: Add
@azmr/ui/disclosure:Accordion,CollapsibleandTabs(horizontal and vertical), built on Base UI with token styling, heading-wrapped accordion triggers, full keyboard maps (including accordion arrow navigation, which Base UI 1.9 does not implement) and height animation that follows the motion tokens. AdduseUrlTabto@azmr/ui/hooks, which keeps the selected tab in a search parameter and ignores any value not in the allowed list. -
fe55409: Add
Progress,Avatar,AvatarGroupandChip.@azmr/ui/progress: linear and circular, determinate and indeterminate (value={null}), withmin/max, tones,showValueand a required accessible name. An indeterminate indicator is partial and pulses, and keeps pulsing under reduced motion (a still full bar would read as complete). Tone colours are tested for 3:1 against the track and the page in both themes; thewarningtone uses--warning-text.@azmr/ui/avatar: an image with initials as the fallback when it is missing or fails to load, sizes and shapes, a required name,altordecorative,getInitials(whole characters, never half a surrogate pair), andAvatarGroupwith a labelled+Noverflow.Chip(in@azmr/ui/display, a Server Component): a removable Badge with an accessible remove button.
-
fed8637: Add the display components (
@azmr/ui/display), all Server Components:Card(with Header, Title, Description, Content, Footer),Badge(default, secondary, outline and the status variants),Alert(info, success, warning, destructive; assertiverole="alert"for problems and politerole="status"otherwise, a default icon per variant, optional labelled dismiss button),Skeleton(decorative, pulses, stilled by the reduced-motion rule) andEmptyState. The status colours are checked for contrast on the blended tint surface in light and dark, over both the page and a card, from the component class names; this found and fixed a destructive badge at 4.26:1. -
6a86517: Add
@azmr/ui/floating:Tooltip(withTooltipProviderand the sharedTOOLTIP_DELAY_MS),PopoverandHoverCard. Collision-aware, portalled above overlays, capped to the available space, and animated with the motion tokens. The tooltip addsrole="tooltip"andaria-describedbyon its trigger while open, which Base UI 1.9 omits. -
2799969: Foundation for the
@azmr/uiredesign (seedocs/superpowers/specs/2026-10-15-azmr-ui-design.md).@azmr/coreis now a peer dependency (>=0.0.2 <1.0.0) instead of an exact-pinned dependency. Two copies of core give separate scheduler/tracking state and incompatibleSignaltypes, so the app's own copy must be the one@azmr/uiuses. If you already followed the README and installed both packages, nothing changes; otherwise add@azmr/coreto your dependencies.- New entry points:
@azmr/ui/hooks(client) and@azmr/ui/lib(server-safe, exportscn).cn()is also exported from the package root. "use client"is now emitted on the client entries (@azmr/uiand@azmr/ui/hooks), so they can be imported from Next.js App Router Server Components' client boundaries without wrapping.@azmr/ui/libhas no directive and can be imported from Server Components.useSignalno longer resubscribes on every render.subscribeandgetSnapshotare memoised on the signal; passing a different signal resubscribes once. Also verified againstcomputed()signals.- The build now verifies its own output (
scripts/verify-dist.mjs): directives per entry, type declarations present, and theexportsmap matching the build entries.
-
eb89693: Add the icon system.
@azmr/ui/icons:Iconrenders any icon component (Lucide, Tabler or your own SVG) with size tokens (xs..xlor a number),strokeWidth,spinand accessibility (decorative by default;aria-label/aria-labelledbymake it a labelled image). It is a Server Component.createIconSet()builds a typed<Icon name>for a fixed set, andregisterIcons()registers custom SVGs by name. An unknown name renders nothing and warns once in development.@azmr/ui/icons/lucide: a curated set of about 60 Lucide icons by name, with Lucide's own kebab-case names.@azmr/ui/icons/mui-map: migration data mapping over 300@mui/icons-materialicons (variants and the legacyOutlinespelling resolved) to Lucide and Tabler, validated in tests against the real packages, with the deliberately unmapped common names listed.Spinneris now a Server Component (no"use client"), so it can be used inloading.tsxand Suspense fallbacks.lucide-reactbecomes a dependency.react-iconsis deliberately not bundled.- The build gains a
serverComponentsentry kind:verify-distnow allows stateless React (no hooks, no context) in server entries and follows imports through nested shared chunks.
-
04f06eb: Add the layout components (
@azmr/ui/layout), all Server Components:Stack(responsive direction, gap on the 4px scale or the density token, align, justify, wrap, dividers between children),GridandGridItem(CSS grid with a responsive 1 to 12 column count, spans per breakpoint, andminItemWidthfor an auto-fit grid),Container,Separator(a realhr, a labelled vertical separator, or decorative) andAspectRatio. They replace MUIBox,Stack,GridandContainer.@azmr/ui/layout/mui-mapis data and helpers for the migration codemod (spacing to gap, breakpoints, ContainermaxWidth, Grid item props), returningundefinedorunsupportedfor what has no equivalent. Inputs that reach a style attribute (minItemWidth,ratio) are validated. The responsive class tables are generated and checked for drift so Tailwind always sees the class names. -
6825a0f: Add
@azmr/ui/menu:DropdownMenuandContextMenuwith items, link, checkbox and radio items, groups, separators, shortcut hints and submenus. Menus sit on the popover layer so they appear above dialogs. Full WAI-ARIA keyboard map (open keys, arrows with wrap, Home and End, typeahead, submenu keys, Escape one level at a time). -
d2275af: Add
@azmr/ui/modal:Dialog(sizes, stackable),AlertDialog(no outside dismissal, focus starts on Cancel) andDrawer(four edges, swipe to dismiss). All trap focus, make the page inert, lock scroll and return focus. Add the--scrimcolour token (and thebg-scrimutility) for the dimming layer behind modal surfaces. -
259c350: Add the motion system.
@azmr/ui/styles.cssnow includes CSS presets (fade, scale, four slides, collapse, stagger, shimmer, check draw, a page cross-fade) driven by the motion tokens, with a reduced-motion rule for each; new tokens--motion-stagger-stepand--motion-duration-ambient. New entries:@azmr/ui/presets(server-safeCollapse, which animatesgrid-template-rowsand is inert while closed,Stagger,AnimatedCheck, and the typedmotionPresetsmap) and@azmr/ui/transition(Transition, a feature-detecting wrapper for React'sViewTransitionthat is a no-op until your React has it, andCountUp).useReducedMotionis exported from@azmr/ui/hooks.Skeletongainsshimmer. -
538a678: Add a shadcn-compatible registry (namespace
@azmr, served athttps://platform.azmara.io/r/{name}.json).npx shadcn@latest add @azmr/buttoncopiesbutton.tsxandspinner.tsxinto the app, installs@base-ui/reactandclass-variance-authority, and adds atokensitem (density, motion, elevation and a few colours, never overriding the app's own palette) toglobals.css. The registry source is generated from the package source with only import paths rewritten, and an unmapped relative import fails the build. The L2 primitive wrappers now re-export Base UI under its own names; the public API is unchanged. Registry files and fixtures are not published to npm. -
d707f33: Add
ScrollArea(@azmr/ui/scroll-area), built on Base UI: a scrollable region with token-styled scrollbars that fade with the motion tokens (and stop animating under reduced motion). The viewport is a keyboard-focusablerole="region", soaria-labeloraria-labelledbyis required by the types.orientation(vertical, horizontal, both),scrollbar(hoveroralways),keepMounted,viewportClassNameandviewportRef. Adds theprimitives/scroll-areaL2 wrapper. -
63884e3: Add four server-safe components, each its own entry:
@azmr/ui/table(a semanticTablewith caption, header, footer, sticky header, striping, a named scroll region andnumericcells),@azmr/ui/breadcrumb(Breadcrumbparts and a data-drivenBreadcrumbswithmaxItemscollapsing),@azmr/ui/pagination(Paginationas real links or buttons, plus the puregetPageRangethe data grid can reuse) and@azmr/ui/stepper(a statusStepper, horizontal or vertical, with every state also said in text).buttonVariantsnow lives in a pure module so server components can use it. -
630d373: Status colours in buttons and in
createTheme.Buttongainssuccess,warningandinfovariants (destructivewas already the "danger" button).createThemenow acceptssecondary,success,warning,infoanddestructivealongsideprimary. Each is derived to be AA in both modes. Labels stay at least 4.5:1 on a solid button's hover surface, checked with the same gamma-space blend a browser uses (this also tightensprimary: a brand colour that only just passed at rest could fall below 4.5:1 on hover).success,infoanddestructiveare also readable as text on the page and on cards, andwarninggets a readable--warning-text. Errors name the option that was wrong.- The default light
successcolour is slightly darker: its button label measured 4.46:1 on hover. - Hover contrast of every solid Button variant is now tested over the page and a card in both modes.
-
f534058: Theme, density and locale support.
@azmr/ui/theme(server-safe, no React):createTheme({ primary, radius, font, density })turns a brand colour into token overrides with guaranteed WCAG AA (primary pair >= 4.5:1, focus ring >= 3:1, both modes); cookie helpers (readCookie,serializeCookie,parseThemePreference,parseDensity);htmlAttributes/htmlAttributes.fromCookies(header)to renderdata-themeanddata-densityon the server with no inline script;createLocale(en-NZ / NZD / Monday week start by default, cachedIntlformatters, date-only strings never shift across time zones);themeInitScript()as an optional inline fallback for static sites.@azmr/ui/react(client):ThemeProvider/useTheme(system tracking, cookie persistence, density) andLocaleProvider/useLocale.styles.cssgains a--font-sans-stacktoken mapped to Tailwind'sfont-sans.- Build and conventions: the verifier now fails if a server-safe entry can reach React (including through shared chunks), and a new
server-safe-no-reactconvention enforces the same at source level.
-
c835cbf: Add
@azmr/ui/toast: aToasterand an imperativetoastAPI (toast.success,error,info,warning,loading,promise,update,dismiss). Toasts stack, dedupe by id, pause while hovered or focused, can be swiped away, take an action such as Undo, and are announced politely (errors urgently). Six positions, on the--z-toastlayer. -
12aef93: Add
@azmr/ui/tokens.css: the design tokens, themes, density, motion and Tailwind mapping without the global base rules.styles.cssis nowtokens.cssplus those rules (thebodycolours and the default border and outline colour), so existing imports render exactly as before. Usetokens.cssin an app that already has global styles, such as one migrating from another UI library, or a docs site. -
1cffcfd: Add
Typography,Heading,Text,Link,CodeandKbd(@azmr/ui/typography), all Server Components.Typography: a type scale (h1toh6,lead,body,small,caption,overline) where the variant picks the semantic element and the look, from colour tokens only.asoverrides the element without changing the look;align,noWrapandgutterBottommatch the MUI props.Headingseparates the semanticlevelfrom the visualsize.Texthassize,tone(muted, destructive, success, warning, info) andweight.Linkis underlined by default (not colour alone), has a full-strength focus ring, andexternaladdstarget,rel="noopener noreferrer"and a screen-reader hint.asrenders a router link.@azmr/ui/typography/mui-map: data mapping MUI Typography variants and props to ours, flagging the approximate ones, for the migration codemod.
Patch Changes
-
a5a2134: Fix
exportscondition order (typesbeforeimport) and declare"sideEffects": falseon@azmr/core,@azmr/ui, and@azmr/security(both the.and./browserconditions onsecurity).The
types-first order previously worked only because TypeScript falls back to the siblingindex.d.tswhen the condition order doesn't matter to it — bundlers with stricterexportsresolution (e.g. Next.js's Turbopack/webpack) are not guaranteed to be as forgiving.sideEffects: falselets bundlers tree-shake unused named exports out of consuming bundles; verified with an esbuild bundle of a single named import from@azmr/security/browser— no unrelated exports leak in.No public API change.
-
343204f: Fix scoped themes when the bundler lowers
light-dark()(Next.js does, for older browser targets). Lowered tokens are resolved where they are declared and inherited, so a nesteddata-theme="light"inside a dark page, or.darkon a panel, had no effect on colours; only the root worked..light,.darkanddata-themescopes now re-declare every colour token explicitly (a test keeps them identical to the:rootvalues), so nesting works however the CSS is processed. Adds about 0.6 kB gzip to the stylesheet (budget now 4 kB). Also exports theButtonOwnPropstype and aligns the workspace on a single React version. -
ef12296:
useSignalis now built onuseSyncExternalStoreinstead ofuseState+useEffect+Signal.subscribe, the exact patternuseSyncExternalStoreexists to replace. Under concurrent rendering, an update that lands between render and commit could previously produce a torn UI;useSyncExternalStorecloses that window by re-checking the snapshot immediately after subscribing and forcing a synchronous re-render if it changed.getSnapshot/getServerSnapshotboth read viaSignal.peek()(which never registers a dependency), and the hook no longer depends onSignal.subscribe()firing immediately with the current value on subscribe — it deliberately doesn't; the snapshot is read independently, asuseSyncExternalStore's contract expects.New render tests (via
react-dom/client+React.act, no new dependency — the package's existingreact/react-domdevDependencies cover it) verify the hook actually renders correctly: initial value shown without waiting on subscribe, updates after mount reflected, and rapid sequentialset()calls before the next flush don't leave a stale value. The previous test file had zero real render tests. Atest-setup.tssetsIS_REACT_ACT_ENVIRONMENTfor React 19'sact.No public API change.
-
1cffcfd: Add a
--warning-texttoken (andtext-warning-text): a warning colour that is readable as text on the page and on cards in light and dark (the yellow--warningand the near-black--warning-foregroundare surface colours, and the latter was unreadable as text on the dark theme).Text tone="warning"now uses it. Contrast of all four semantic tone colours as text on the background and card is now tested in both modes.
0.1.0
Minor Changes
- d70fccb: Upgrade workspace dependencies across the monorepo (pnpm 10 -> 11 tooling
migration): React 18.3 -> 19.2 (
@azmr/ui), Zod 3.24 -> 4.4 (@azmr/security), better-sqlite3 11.7 -> 12.11 (@azmr/db), plus vitest, tsup, and@types/nodebumped to latest across all packages.typescriptstays pinned at^5.7.3(TypeScript 7 currently breakstsup's.d.tsbundling viarollup-plugin-dts).
Patch Changes
-
5bf56bb: Fix package metadata: mojibake in the description field (encoding mismatch, was showing garbled text on npm) and a missing LICENSE file in the published tarball despite being listed in
files.@azmr/aigot the same fixes plus missinghomepage/repository/author/keywords, but isn't included in this changeset - it's on changesets' ignore list and doesn't take version bumps this way. -
Updated dependencies [5bf56bb]
-
Updated dependencies [d70fccb]
- @azmr/core@0.0.2
All notable changes to this project will be documented in this file.
[0.0.1]
Added
- Initial release of React UI components wired to reactive Signals
- XSS-safe Grid component
- useSignal hook for automatic re-renders
- Zero boilerplate reactive UI development