arcane_jaspr
A Jaspr web framework port of the Arcane UI component library. Build beautiful web applications with Dart using familiar Arcane patterns.
3.4.0
ArcaneArts/arcane_jaspr
What this package is like to depend on
Last release 5 days ago
18 Aug 2026
Ships fairly regularly
a new release about every 2 months
Rarely documented
notes for 2 of 13 stable releases
Nothing withdrawn
no release was ever pulled
8 months old
13 releases · first in 2025
13 releases in the last 12 months
see the full history below
Release timeline
13 releases · Dec 2025 to Aug 2026Releases
latest 13-
3.4.018 Aug 2026Release notes
Open source →Fixed
- CI render-golden suite is green again. The 42 goldens for buttons and
dialogs were regenerated for jaspr 0.23.2, which moved the
typeattribute after thedata-*attributes in rendered<button>markup. Attribute reorder only — the rendered DOM is semantically unchanged.
Added
ArcaneGalleryarea controls. Packed galleries can now setminimumTileAreaandtargetTileAreain grid cells (columnSpan × rowSpan). The packer excludes undersized candidate spans when the floor is attainable and uses one ratio-independent target area for every item. Galleries that omit both controls retain the existing aspect-derived sizing behavior.- Nested cards flatten by default (all four themes). An arcane
Cardrendered inside another arcaneCardnow drops its own frame — background, border, and shadow — so stacked panels no longer read as a "card-in-card" border-in-border, most visibly under Shadcn and Neubrutalism. The inner card re-asserts a distinct frame by opting out withdecoration:/styles:(which set thedata-arcane-decoratedattribute the flatten rule excludes). Implemented as pure per-theme CSS (#arcane-root.arcane-theme-* .<theme>-card .<theme>-card:not([data-arcane-decorated])), scoped and!importantso it beats both inline variant styles (shadcn/neubrutalism) and the theme's own!importantsurface rules (neubrutalism); golden-neutral (the render snapshot suite excludes theme CSS by design). Note: a layout container that a host app styles as a card via its own CSS is outside the library's reach — only real nested arcane Cards flatten. - Web-safe theme packages + new
arcane_jaspr_kb. Split each theme's*_kb_renderers(which importarcane_lexicon, a server-sidedart:io/jaspr_contentdocs package) out of the theme packages into a new opt-inarcane_jaspr_kbpackage. The theme packages (arcane_jaspr_shadcn/_neubrutalism/_neon/_win95) no longer depend onarcane_lexicon, so importing them in a Jaspr client app no longer dragsdart:iointo the client entry (which silently droppedmain.client.dartand shipped a blank app). Docs sites now depend onarcane_jaspr_kbfor the knowledge-base chrome renderers. - Theme-permeable styling (M0 foundations). New
ArcaneDecoration(core/decoration/arcane_decoration.dart) — a Flutter-BoxDecoration-shaped, theme-permeable surface with universal fields (color, gradient, borderRadius, border, padding, backdropFilter) plus anElevationintent every theme maps to its own idiom (shadcn ambient blur, neubrutalism hard offset, neon glow) and a theme-specificshadowColorhonored-or-ignored per theme.ButtonandCardnow acceptdecoration:(semantic) andstyles: ArcaneStyleData?(literal escape hatch that always wins). Render bases expose a concrete-defaultdecorationStyles(ArcaneDecoration?)hook (returns{}) so themes opt in without a breaking change; the merge seam layerstheme base -> variant -> size -> decoration -> literal styles. ArcaneColorOpsextension onString—.opacity(double)and.on(base, double)emitcolor-mix()for any CSS color (hex,var(--x),ArcaneColor.*.css, runtime accents), replacing rawcolor-mixstrings and the fragile${color}30hex-alpha hack (which produces invalid CSS forvar()colors).ArcaneStyleDatagained the typed fields that previously forcedraw:maps: single-side padding (paddingTop/Right/Bottom/Left), per-side custom border strings (borderTopCustom/…, which can carry a runtime color ornone),boxSizing(BoxSizingenum),backgroundClip(emits standard +-webkit-), andbackdropFilterCustom.- M1: the
styles:/decoration:surface now covers all ~60 wired themed-visual components — every actionable component across buttons, cards, feedback (Alert/Avatar/StatusBadge/Toast/Kbd/Breadcrumbs/Progress/CircularProgress/Skeleton/LoadingSpinner/EmptyState), interactive (Accordion/Disclosure/Cycle/Toggle/ToggleGroup/ToggleSwitch/Checkbox/RadioGroup/Slider/Separator), overlays (Dialog/Sheet/Drawer/Command/Floating/ContextMenu/DropdownMenu/Menubar/Toolbar), inputs (TextInput/Select/NativeSelect/OtpInput/TimePicker/DatePicker/Calendar/FieldWrapper/InputGroup), tabs/pagination, and the promo chrome (TopAnnouncementBar/PromoModal/…/SlotCounter). For overlay components the override routes to the visible panel, never the scrim; for standalone theme renderers that don't extend the shared base the merge is applied directly; components with no core render base use the 2-spread form. Calendar's per-theme style member was migrated fromdom.StylestoMap<String,String>to host the seam. Every addition is golden-neutral (rendered output unchanged when the new fields are unset). - M2: shipped the orphaned card family +
IconBadge. The card props + renderer-contracts that existed as dead code (StatCardProps,FeatureCardProps,CTACardProps,TestimonialCardProps,PricingCardProps) now have public widgets and per-theme renderers wired into all three themes:StatCard/StatCardRow,FeatureCard/IconCard,CtaCard,TestimonialCard/RatingStars, andPricingCard/PricingGrid. Each renders from theme CSS variables (adapts to any palette), is permeable (styles:/decoration:), and composes via a shared render base + thin theme subclasses. NewIconBadgecomponent makes the ubiquitous colored-icon-circle idiom first-class. - M3: Flutter-parity ergonomics.
cx(List<String?>)class-join helper (util/classes.dart, exported) collapses the_joinClassesidiom copy-pasted across sites;Containergained a semantictag:('nav'/'section'/'header'/…) so structural markup no longer drops to rawdom.*— the defaultdivpath is byte-identical. - M4: card-family surface completed against a real consumer.
CtaCardgainedaccentColor(tints the icon chip + CTA) andisExternal(opens in a new tab withrel="noopener noreferrer"and a↗affordance);PricingCardgainedhighlighted(an accent wash + a solid, row-outranking CTA) and per-rowSpecEntry.highlight. These are what let QualityNode's marketing pages migrate onto the library cards with zero visual change. - M3 breaking type cleanups (Flutter-parity, no back-compat).
Card.padding/Card.borderRadiusare now typedEdgeInsets?/BorderRadius?(were raw-CSSString?), aligningCardwithArcaneStructuredCard. Theclasses:parameter on the arcane wrapper widgets (ArcaneDiv/ArcaneSpan/ArcaneSection/ArcaneParagraph/ArcaneHeading/ArcaneLink/ArcaneNav/… and the layout/HTML wrappers) now takesList<String>?(wasString?), joined internally viacx— conditional class lists (['card', if (active) 'is-active']) no longer need a manual join.ArcaneStyleData.backgroundClipis now a typedBackgroundClipenum (borderBox/paddingBox/contentBox/text) instead of a rawString?. ArcaneGallery— themeable media masonry. Newcomponent/collection/gallery.dart+core/props/gallery_props.dart+ sharedcore/rendering/base/gallery_render_base.dart, wired intoComponentRenderersviaGalleryRendererContract, with a per-theme renderer in every theme package (packages/*/lib/src/renderers/gallery.dart). Each theme renders the SAMEArcaneGalleryTile{media(aspectRatio,src?),mediaChild?,title,meta,href/onTap,overlay,footer}list natively: win95 = titled windows on the teal desktop, shadcn = clean cards, neubrutalism = hard-shadow blocks, neon = glow. The CSS-grid base uses coarse rows (grid-auto-rows: minColumnWidth/2) + aspect-driven COLUMN spans (galleryColumnSpan: wide→2, panorama→3) +grid-auto-flow: densefor a variable-width mosaic, refined by an opt-in packing script (util/interactivity/scripts/gallery/gallery_scripts.dart, emitted viaincludeFallbackScripts). Media covers its cell (object-fit: cover).- Win95 theme: runtime accent override. The Windows 95 theme's desktop backdrop, title-bar gradient and selection color now read
var(--w95-desktop-in, …)/--w95-title-a-in/--w95-title-b-in/--w95-selection-in(plus--primary/--accent/--ring), falling back to the active [Win95Theme] scheme when unset. A host app can inject those--w95-*-invariables (scoped to#arcane-root.arcane-theme-win95) to re-tint the desktop + title bars from a runtime account accent live, without a rebuild — while the silver#c0c0c0control face and 3D bevels stay fixed across every accent.
Fixed
-
Rounded emphasis surfaces no longer render orphaned edge accents. Accent alerts, feature cards, testimonial cards, Neon cards, prose/knowledge-base callouts, and active rounded navigation now use a complete perimeter, fill, icon, or symmetric ring instead of a one-sided border or clipped stripe. The component docs teach the same invariant, the alert showcase exercises the accent variant, and a render/CSS contract prevents the crescent treatment from returning.
-
Confirm and alert dialogs are visible when rendered. Their shared renderer now opens the underlying dialog surface instead of emitting it with the default closed state and
hiddenattribute. -
ArcaneGallerypacked tiles can no longer overlap around fragmented gaps. Placement now searches through the complete occupied board and always includes the first wholly empty row. Its defensive fallback also appends below occupied cells instead of forcing a multi-cell tile into the first undersized gap. -
Owner-sized
ArcaneGallerypacking no longer strands interior cells. Each source-ordered tile anchors at the earliest unfilled cell while retaining its independent ratio-scored row and column spans. Normal masonry gutters and a ragged terminal edge remain unchanged; later tiles cannot skip an interior cell, overlap earlier art, or fall below the configured minimum. -
Shadcn: the dropdown panel no longer claims the open-trigger accent fill.
.arcane-dropdown-menu[data-state='open']sat in the shared "open/active trigger" selector list that paintsbackground-color: var(--accent); color: var(--accent-foreground), so the popover surface was told to drop off the--popover/--popover-foregroundpair every other floating surface uses. It was masked in practice by the renderer's inlinebackground-color: var(--popover), but any consumer that overrode the panel's inline styles (styles:/decoration:) inherited an accent-tinted panel instead of a popover one. Only the trigger selectors remain in the list. -
ArcaneGallerytile caption is now theme-opt-in. The render base only emits the title/meta header block when the theme opts in viashowsTileHeader(win95 renders it as the window title bar). The card-style themes (shadcn/neubrutalism/neon) previously rendered the caption after the media, where a rounded tile clipped its bottom corners into a stray "caption strip"; they now render clean media-only tiles and expose the title to assistive tech via the tile'saria-label. -
Permeability internals hardening. Rolled the
layerStyles"literal-wins" helper out to 20 more single-root render bases (avatar, breadcrumbs, alert, skeleton, accordion, disclosure, toggle-group, kbd, menubar, toast, slider, radio-group, sidebar, field-wrapper/input-group, separator, time-picker, cycle-button, tab-bar, spinner, calendar) — byte-identical output, so adecorationshorthand can no longer out-emit a literalstyles:longhand anywhere. Removed a deaddecorationStylesspread from the checkbox/toggle-switch renderers (no theme mapped it; universaldecoration:fields + literalstyles:still apply). Renamed the Calendar renderer base's abstractstylesgetter torootStylesto disambiguate it from the permeableprops.styles. Neubrutalism decorated toasts opt out of the variant-border!importantreset viadata-arcane-decorated, matching the card opt-out. -
Permeability precedence hardening (quality pass). The seam now guarantees literal
styles:wins the cascade via alayerStyleshelper (lib/core/rendering/base/style_layering.dart) that remove-then-reinserts override keys, so "later layer" == "later in the emitted CSS" — closing a Dart map key-position pitfall where adecorationshorthand (background) could beat a literalstyles:longhand (background-color). Also fixed: trailing button-resets on tappableCard/anchorButtonthat clobberedstyles:; StatusBadge applying its position/card-color mutations after the permeability merge;ArcaneStyleData.merge()silently droppingalignItems/justifyContent;ArcaneNativeSelect/TextArea/SlotCounterfactory constructors not threading the new fields; andArcaneColorOps.opacityquantizing to whole percent. Neubrutalism per-instance shadow recolor now bakes the color into thebox-shadow(CSS custom properties resolve at the theme root, so the priorvar(--nb-shadow-color)override never inherited), and decorated cards opt out of the theme's!importantsurface reset via adata-arcane-decoratedattribute. -
Form controls no longer throw on every interaction under dart2js (Dart 3.11). Event handlers read DOM properties via
dynamicmember access ((event.target as dynamic).value,.checked,.selectedIndex,.key,.stopPropagation()), which throwsTypeError: <name> is not a functiononpackage:webextension types — silently breaking every text input, textarea, OTP input, select search, and clear button (values never reached the callbacks). Addedcore/dom_value.dart(conditional web/stub helpers using explicitgetProperty/callMethodinterop) and routedtext_input/field/text_input_render_base/otp_input_render_base/select_render_basethrough it. The helper is conditionally imported so styled components keep compiling during off-web style extraction (wheredart:js_interopis unavailable). -
ArcaneApp.headis now actually rendered. Thehead: List<Widget>?parameter was declared but never injected into the document;ArcaneAppnow emits the supplied widgets through jaspr's cross-platformDocument.head, so app-level<link>/<script>/<meta>widgets reach<head>during both SSR and client hydration. No change whenheadis null/empty. -
Server-side rendering crash in the form-field widgets (
ArcaneStringField,ArcaneBoolField,ArcaneColorField,ArcaneDateField,ArcaneTimeField,ArcaneEnumField).ArcaneFieldnow guards its asynchronous value load to the client (kIsWeb), so SSR renders the loading placeholder instead of throwing a build-phasesetStateassertion. Client behavior is unchanged. -
shadcn knowledge-base sidebar: pinned directly below the sticky top bar (was offset ~56px too low, leaving a gap above the nav) and made independently scrollable (
max-height+overflow-y: auto) instead of requiring the whole page to scroll. -
shadcn top bar: restored
position: sticky(it wasstatic, so it scrolled off-screen) with a solid background and bottom hairline, so it stays pinned while scrolling. -
shadcn docs content layout: the content area now centers (capped at
--container-2xlwith auto margins instead of stretching edge-to-edge), and the right-hand table-of-contents column is only reserved when a TOC is actually present — TOC-less pages (e.g. component docs) now center the article instead of leaving an empty reserved column. -
shadcn docs sidebar: nested nav items (sub-folder contents) now have vertical spacing —
.sidebar-treewas missing agap, so deeply nested items packed together; addedgap: 0.25remso they match the top-level spacing. -
Neon docs sidebar: pinned directly below the sticky top bar (was offset by a doubled top, leaving a gap above the nav) and given its own scroll rail (
max-height+overflow-y: auto) instead of scrolling with the page. The shadcn layout port had keyed this on the.shadcn-kb-sidebarclass; the rule now targets.neon-kb-sidebarso it actually matches the Neon DOM. -
Theme CSS is no longer re-materialized on stylesheet cache hits.
ArcaneStylesheetCss.resolvenow takes the component CSS as a thunk (String Function()) invoked only on a cache miss, so the large per-theme CSS string (e.g. the Win95 theme's ~5,600 lines) is built once and skipped entirely when the Expando cache is warm. Output is byte-identical. -
Removed the last two
dynamicpublic-API fields (strong-typing):TreeNodeData.datais nowObject?, and the fourFileUploadPropsdrag/input handlers are typedvoid Function(web.Event)?(the concrete type jaspr's events layer delivers) instead ofvoid Function(dynamic)?.
Removed
- Deleted ~1,300 lines of unreachable scaffolding that could not be distinguished from the live contract surface: the 514-line
style_presets.dartcatalog (8 preset classes, zero references — the live preset vocabulary is theArcaneStyleDatastatics) and 11 orphan*_props.dartfiles whose widgets already ship without them (tile,card_section,center_body,expander,glass,section,radio_cards,fab,icon_button,header, plus the deadSearchProps/BarPropsclasses). Live symbols trapped in dead files (theBarBackButtonModeenum,SearchResult) were preserved. Verified: every deleted symbol had zero references acrosslib/packages/test/tool/bin/docs,dart analyzestays 0-error, and the suite holds at 42 pre-existing golden failures. - Added a direct unit test for the
layerStylescascade helper (test/unit/layer_styles_test.dart) — the core "literalstyles:always wins" guarantee was only exercised indirectly through Card SSR cases; 7 tests now assert later-override-wins, key-moved-to-last, null-skip, and left-to-right multi-override behavior. - Removed 47 more orphan
*_props.dartfiles (lib/core/props/went from 114 files to 67) — everyPropsclass +RendererContractwith zero references to any widget, render base, theme renderer, or dispatch aggregator (ComponentRenderers/LayoutRenderers). These were scaffolding for components that were never built. Verified by a per-symbol zero-reference scan (file_upload,tree_view,timeline,stepper,tracker,meter,hero_section,game_tile,carpet,marquee,switcher, and ~36 others, plus afooter_props/footer_column_propsdead cluster).status_indicator_props.dartwas stripped to just its liveStatusTypeenum; live symbols trapped in otherwise-dead files were preserved.dart analyzestays 0-error and the suite holds at its 42 pre-existing golden failures.
Changed
-
Loaders now have one theme-renderer source of truth. Standalone spinners, loading buttons, authentication guards, loading toasts (including the JavaScript fallback), and Shadcn loading selects all resolve through
ComponentRenderers.loadingSpinner, so a theme's loader updates every loading surface. -
Preset
stylefield renamed tovariant(breaking, no back-compat). The 8 components that exposed a preset-enum selector asstyle:(ArcaneAlert,ArcaneKbd,ArcaneEmptyState,ArcanePagination,InlineHeroBanner,CodeBlock,MutableText,ArcaneDropdownItem) now expose it asvariant:— matchingCard/PricingCardwhich already usedvariant, and eliminating the one-letter collision with the permeablestyles:escape hatch (a typo betweenstyle:andstyles:previously compiled and did the opposite thing). Enum type names (AlertStyle,KbdStyle, …) are unchanged; only the field/param. Rendered output is byte-identical (identifier-only change). -
StatCard.iconis nowWidget?(wasString?, breaking). It matchesFeatureCard/CtaCard/PricingCard— icons are Widgets, as in Flutter. The sharedStatCardRenderBasenow places the widget directly in the icon badge instead of emitting the string as text. -
Dropped the
onClickalias on theCardfamily (breaking). All nineCard/ArcaneStructuredCard/ArcaneImageCardconstructors kept bothonTapandonClick(_onTap = onTap ?? onClick);onClickis removed, leavingonTap(Flutter parity, no-alias rule). No call sites passedonClickto a card. -
Internal: deduplicated the
arcane_jaspr_shadcn,arcane_jaspr_neon, andarcane_jaspr_neubrutalismrenderer implementations into shared base classes underlib/core/rendering/base/. Public renderer class names and rendered HTML output are unchanged (verified byte-identical across all three themes via golden snapshots). Removed the per-packagecontrol_styles.dart. -
PricingCardlayout tuned to match real plan/hosting cards. The spec table now renders above the feature list inside a bordered, rounded box (was plain rows below the features); a non-highlighted card's CTA is a neutral outline (foreground label,--borderedge) so ahighlightedcard's solid accent CTA visibly outranks its row; and the badge pill is no longer force-uppercased — it renders the label exactly as passed. -
Neon theme:
PricingCardandTestimonialCardnow lift on hover (whole-cardtranslateY+ shadow), matching the neon card feel. Delivered from the theme layer (neon_css.dart) so consumers get it for free instead of stapling it into site CSS. -
arcane_jaspr_neonrebuilt as a dark-first "gamer" theme (replaces the prior neutralized skeleton). Distilled from the QualityNode aesthetic: the defaultNeonTheme.greenis an emerald-to-cyan palette, with seven other neon variants. The palette is fully seeded fromNeonThemevialightSeed/darkSeed(like the shadcn and neubrutalism themes); the dark seed enablesaccentGlow, so shadows carry a neon glow. NewNeonCsssupplies a restrained, glow-and-gradient component layer (Oxanium display font, uniform accent frames, uppercase tracked badges, accent focus rings) — every rule scoped to#arcane-root.arcane-theme-neon, so the shadcn and neubrutalism themes are unaffected.NeonCssalso styles the documentation knowledge-base chrome (top bar, sidebar, content grid, TOC) so the Neon docs render correctly (the bespoke Neon docs layout was retired inarcane_lexicon; Neon now uses the standard chrome). Neon is back in the golden snapshot tests.
- CI render-golden suite is green again. The 42 goldens for buttons and
dialogs were regenerated for jaspr 0.23.2, which moved the
-
3.3.007 May 2026Release notes
Open source →Changed
-
Flutter-First Primary Surface
package:arcane_jaspr/arcane_jaspr.dartnow exposes a curated Flutter-shaped surface instead of re-exporting raw Jaspr and DOM APIs- Added
Widget,StatelessWidget,StatefulWidget,State,InheritedWidget,BuildContext,Key, and the normalrunApppath on the primary import - Moved low-level HTML wrappers and raw Jaspr escape hatches onto explicit secondary imports
-
Secondary Surface Split
- Added
package:arcane_jaspr/flutter.dart - Added
package:arcane_jaspr/html.dart - Added
package:arcane_jaspr/web.dart - Updated package internals that still needed low-level access to import those surfaces explicitly
- Added
-
Developer Experience Reset
- Removed HTML-first wrappers from the primary docs path and rewrote the default documentation flow around the Flutter-first authoring model
- Added plain Jaspr versus Arcane Jaspr comparison examples in the docs intro to explain the intended Flutter-like goal directly
- Reworked the docs demo system around a central registry and generated component catalog output to keep examples and counts in sync
- Updated the repo-owned Oracular ArcaneJaspr templates to teach the new primary surface instead of old Jaspr component base classes
Added
- Primary Surface Guardrails
- Added
tool/check_primary_surface.dartto scan docs, demos, and templates for banned primary-surface examples such as old component base classes,htmlFor, and explicit generic angle-bracket usage
- Added
Removed
- Counter Smoke App
- Removed the temporary counter smoke app fixture created during the parity reset work
-
-
3.1.014 Mar 2026Nothing published for this version
-
3.0.004 Mar 2026Nothing published for this version
-
2.9.010 Jan 2026Nothing published for this version
-
2.8.007 Jan 2026Nothing published for this version
-
2.7.105 Jan 2026Nothing published for this version
-
2.7.025 Dec 2025Nothing published for this version
-
2.5.025 Dec 2025Nothing published for this version
-
2.4.023 Dec 2025Nothing published for this version
-
2.0.020 Dec 2025Nothing published for this version
-
1.0.019 Dec 2025Nothing published for this version
-
0.0.118 Dec 2025Nothing published for this version