Releases: losol/ratio-ui
Release list
@eventuras/ratio-ui@2.16.0
Minor Changes
-
1fbf082: Two-tone (split) chips:
<Chip split>renders a segmented key/value pill —
<Chip.Key>(darker, meta voice built in) +<Chip.Value>(lighter,
semibold, family-neutral) sharing one border and radius. Segment colors read
from new--chip-key-bg/-fgand--chip-value-bg/-fgtokens, so scopes
re-skin them like any chip (colored keys, square corners) without extra
variants. -
477960f: Make
Footercomposable with a set of building blocks.New compound subcomponents let you assemble editorial or compact footers from
parts instead of hand-writing markup:Footer.Brand— logo + wordmark + a serif mission lineFooter.LinkColumn+Footer.Link— titled link stacks; a link can carry a
tagbadge or anexternalarrow, and takes anasprop for router linksFooter.Publisher— the imprint block (reuses thePublishershape)Footer.Newsletter— frames a label/hint around your own signup formFooter.Social+Footer.Social.Item— a row of round icon linksFooter.BottomBar— the thin copyright/legal row, with an optional top rule
Everything is token-driven; a
darkfooter now re-scopes the text and border
tokens so blocks stay legible on the deep surface without hardcoded colours.
FooterandFooter.Classicare unchanged, so existing footers keep working. -
442bbc7: Two small primitives for editorial outlines (className-free consumers):
Textgainsfamily('sans' | 'serif' | 'mono', from the theme's font
tokens) andtransform('none' | 'uppercase'— uppercase bundles a modest
letter-spacing). Together withsize="xs"+variant="subtle"this is the
small meta/caption voice (type labels, counts) previously only reachable via
className. Text prop types are now exported fromcore/Text.Stackgainsrail— a--border-1hairline down the left edge with a
matching inset, marking children as one level deeper in a hierarchy
(outlines, threads, tree levels). Vertical stacks only.Stackalignaccepts'baseline'— for horizontal stacks pairing text at
different sizes (a title and its caption), so baselines line up instead of
boxes.
@eventuras/markdown@0.14.0
Minor Changes
- ce9a5a7: Add a
codeBlockcomponent slot toMarkdownContent— the opt-in seam for
syntax highlighting. Pass@eventuras/ratio-ui-shiki's CodeBlock and fenced
code blocks highlight (theme-aware, client-side); by default nothing changes
and no highlighter code is bundled. The slot receives the exact props the
built-in CodeBlock rendering uses (MarkdownCodeBlockProps, exported), so
CodeBlock-compatible components are drop-ins that match the default
appearance. Inline code and unknown-language fallback are unaffected.
@eventuras/ratio-ui@2.15.0
Minor Changes
-
68a188a:
Headingnow forwards standard DOM and ARIA attributes to the rendered
element.id,style,role,aria-*, event handlers and the other HTML heading
attributes now reach the element, so anchor targets like
<Heading as="h2" id={slug}>work without wrapping the heading in an
id-bearing element. Spacing props are still compiled to utility classes, and
className/testIdkeep their explicit meaning — spacing keys never leak onto
the DOM (they are split out withextractSpacingProps). -
71c0a89: Add
InlineCodeandDividercore components.InlineCoderenders a<code>pill styled with the shared--code-*tokens,
so inline snippets matchCodeBlockand stay legible in every theme.Dividerrenders a token-driven thematic break (--border-2) rather than a
fixed grey rule.
Both ship their own theme-aware CSS that travels with the component import, so
they work regardless of which CSS entrypoint the app uses. -
937f5c4: Behavior change:
global.cssno longer hides the page until a theme is set.The light theme is fully defined on bare
:root, so a page with nodata-theme
is already correctly styled. The previoushtml { opacity: 0 }guard hid it
anyway until a theme attribute appeared — which meant any consumer who never set
data-themegot a permanently blank white page, with no error. For a design
system that is the worst possible first-run experience.The visibility guard is now opt-in and forgiving:
html[data-theme-loading]:not([data-theme]):not([data-color-scheme]) { opacity: 0; }
- Import the CSS and render — the page is visible in the light theme. No
attribute required. - Set
data-themefor another palette; it can be set late without the page
ever going blank. - Resolving the theme in JS after first paint and want no flash? Set
data-themein a blocking<head>script (correct first paint), or add
data-theme-loadingto<html>and setdata-themeonce resolved.
Migration. If you already set
data-themein a blocking<head>script,
nothing changes. If you relied on the defaultopacity: 0to mask a
JS-resolved theme applied after paint, adddata-theme-loadingto<html>to
keep the same hide-until-resolved behavior. - Import the CSS and render — the page is visible in the light theme. No
-
80cbd81: Add
slugifyandgetTextContentutilities (@eventuras/ratio-ui/utils).slugifyis the single source of truth for heading anchor ids — the same
GitHub-flavoured slug used both to id a heading and to build the table of
contents that links to it, so the two never drift.getTextContentflattens a React node tree to plain text, e.g. for slugging
a heading whose children mix strings and inline elements.
Together with the existing
TableOfContentscomponent andTocHeadingtype,
these let a consumer render an anchored, scroll-spied TOC without re-inventing
the slug convention.
@eventuras/markdown@0.13.0
Minor Changes
-
71c0a89: Fix dark mode. Code blocks, inline code, blockquotes and rules were rendered
with hardcoded light Tailwind greys and turned near-invisible under
data-theme="dark". Rendering now delegates to ratio-ui's theme-aware
components, so no hardcoded colours remain in the component map:- fenced code blocks →
CodeBlock - inline code →
InlineCode - blockquotes →
Blockquote - thematic breaks →
Divider
Requires
@eventuras/ratio-ui^2.15.0(peer range raised from^2.13.0) for
the newInlineCodeandDividerprimitives. - fenced code blocks →
-
80cbd81: Add
extractHeadings(markdown), which pulls the h2/h3 headings out of raw
markdown as aTocHeading[]for an "on this page" table of contents. Ids are
produced with ratio-ui'sslugify, so they match the anchors a heading
renderer puts on the page; fenced code blocks are skipped and link/emphasis
syntax is stripped from the visible text. Pairs with
@eventuras/ratio-ui/core/TableOfContents. -
f8207a1: Move the markdown engine into runtime dependencies, and name its component type.
react-markdown,rehype-raw,rehype-sanitizeandremark-gfmmove from
peer to regular dependencies. They are internal implementation — the component
builds its own render pipeline and shares no instance across the package
boundary — so consumers no longer have to install them by hand. Onlyreact,
react-domand@eventuras/ratio-ui, which genuinely need one shared copy,
remain peers.- New exported type
MarkdownComponentsforcustomComponents. It is
react-markdown'sComponents(plus custom element names from remark plugins),
aliased so consumers import it from this package instead of reaching into
react-markdown, and so the name survives a future change of renderer.
@eventuras/ratio-ui@2.14.0
Minor Changes
-
69c337d: CodeBlock: inline annotations.
annotationsrenders notes directly beneath the line they refer to — validation
output, review comments, explanations:<CodeBlock code={source} annotations={[ { line: 8, severity: "error", code: "circular-ref", path: "Event.prerequisite.ref", message: "An event cannot be its own prerequisite.", }, ]} />
Each note takes a
severity(error | warning | info | success, tinted with the
matching semantic tokens so it follows light/dark), an optional machine-readable
codeshown as a pill, and an optionalpathfor where it points.messageis
a React node rather than an HTML string, so this stays injection-safe like the
rest ofCodeBlock.Unlike a hover tooltip the notes stay put: long messages get room to wrap, the
whole set is scannable at a glance, and the text lives in the document — so
keyboard and screen-reader users reach it, and a screenshot captures it.Companion packages that wrap the core
CodeBlock(e.g.
@eventuras/ratio-ui-shiki) pick this up without any change of their own. -
c4a6a95: CommandPalette: injection-safe result highlighting (
description+highlights),descriptionHtmldeprecated.CommandPaletteItemnow takes a plain-textdescriptionplus optional
highlights—[start, end)character ranges the component wraps in<mark>
itself. No HTML is injected, so search-result excerpts from untrusted content
are safe by default:{ id, title, description: 'Streaming logs and audit trails', highlights: [[0, 9]] }
Out-of-bounds ranges are clamped and overlapping ones skipped, so a provider
can hand over raw match offsets without pre-validating them.descriptionHtmlis deprecated — it injects raw HTML via
dangerouslySetInnerHTMLand is an XSS vector for untrusted values. It still
renders (trusted/pre-sanitized content only) but is ignored when
descriptionis set, and will be removed in the next major. Migrate excerpt
highlighting from an HTML string todescription+highlights.
This takes raw HTML off CommandPalette's default render path — the library's
only remainingdangerouslySetInnerHTMLis now the opt-in, deprecated
descriptionHtmlfallback.
Patch Changes
-
ceaeb95: NavTree: content items require a stable
id, and content is detected by key presence.NavTreeContentItemnow requiresid: string. With nohrefor string
titleto key on, an index-based fallback would remount the (often stateful)
content — e.g. aSearchFieldfiltering its own group loses focus — when
siblings are filtered or reordered.- Content vs. link rows are distinguished by
'content' in noderather than a
truthiness check, so a content value of0/''/nullis no longer misread
as a link row.
ratio-ui-shiki v0.1.0
What's Changed
- Commandpalette safe highlights by @losolio in #68
- feat: add @eventuras/ratio-ui-shiki (alpha) — Shiki highlighting for CodeBlock by @losolio in #71
- feat(ratio-ui-shiki): add useShikiHighlighter hook by @losolio in #72
- CodeBlock: Use fine-grained shiki/core for minimal bundles by @losolio in #74
- CodeBlock: Add inline annotations by @losolio in #76
- feat: move datatable from eventuras by @losolio in #77
- datatable: Make publishable and wire up npm release by @losolio in #79
- feat(markdown): add @eventuras/markdown by @losolio in #80
- chore: version packages by @github-actions[bot] in #69
Full Changelog: https://github.com/losol/ratio-ui/compare/@eventuras/ratio-ui@2.13.0...@eventuras/ratio-ui-shiki@0.1.0
@eventuras/markdown@0.12.0
Minor Changes
-
2f52323: Moved into
losol/ratio-ui. The package now lives beside the design system
it renders with, and is released from this repository.- Relicensed from MIT to MPL-2.0, matching the rest of the Ratio UI family.
- Renumbered onto a
0.xline. The package was never published to npm — its
old version tracked theeventurasmonorepo rather than this package's own
API — so9.0.6became0.11.6, each former major bump becoming a minor one. - The
@eventuras/ratio-uipeer range tightens from>=1to^2.13.0. The old
range accepted a v1 design system against components written for v2. - Shared config now comes from this repository's
@ratio-ui/*packages
(typescript, vite and eslint config) instead of the@eventuras/*ones. testrunsvitest runrather than watch mode, and the package is registered
as a vitest project at the repo root so its jsdom environment and setup files
apply — without that, its tests would silently skip locally and fail in CI.- Fixed: extending the sanitize schema dropped the default attributes for
any tag the extension also named. BothmergeSanitizeSchemasand
MarkdownContent's own merge used a shallow spread, so extendingawith a
single attribute discarded the rest of GitHub's allowlist fora— including
href, silently breaking every link. Attribute lists are now concatenated
per tag and de-duplicated. - Documentation fix: the README claimed
data:URLs were blocked outright. They
are blocked in links but allowed for images, per GitHub's default schema.
Versions before the move were renumbered. This package was developed in
theeventurasmonorepo and never published to npm, so its version tracked
that repository rather than this package's own API. On moving here it was
renumbered onto a0.xline: each former major bump became a minor bump
(the breaking slot in0.x), so9.0.6became0.11.6. The entries below
keep their original text — only the version headings changed.
@eventuras/datatable@0.6.0
Minor Changes
-
fe53b07: Publishable from this repository, and fixed for Node consumers.
- Added
"type": "module". The build emits ESM, but without this Node read
dist/index.jsas CommonJS and threwCannot use import statement outside a modulethe moment anyone imported the package. - Breaking:
@eventuras/ratio-uimoved fromdependenciesto
peerDependencies(^2.13.0), matching the other Ratio UI companion
packages. As a regular dependency it resolved to a pinned copy at publish
time, so consumers ended up with a second ratio-ui beside their own —
duplicated styles and two module instances. Install@eventuras/ratio-ui
alongside this package. - Ships a LICENSE (MPL-2.0), a README and a
description; the published
package carried none of them.
- Added
Patch Changes
-
5b5777c: Moved into
losol/ratio-ui. The package consumes@eventuras/ratio-uifrom the
workspace again rather than from npm — which supersedes the note on 0.5.29, where
that entry described the arrangement while datatable still lived in
losol/eventuras. It no longer depends on@eventuras/ratio-ui-nextat all.Alongside the move:
- Column headers declare
scope="col", so screen readers announce them as
column headers while navigating the grid. - The client-side page-size effect now re-runs when
pageSizeor
clientsidePaginationchange, instead of only on mount — page size no longer
goes stale when those props change.
- Column headers declare
@eventuras/ratio-ui@2.13.0
Minor Changes
-
fdee141: NavTree:
defaultOpenon branches anddefaultExpandedDepthon the tree.{ title: 'Resources', defaultOpen: true, … }— one branch starts expanded
without containing the current page.defaultExpandedDepth={1}— every top-level branch starts expanded
(Infinityopens everything).
Both share the active branch's semantics: the user's toggle wins until
currentPathchanges, then the defaults re-assert — and the chevron's first
click now collapses a branch that's open via a default (the toggle shares the
derived base).NavTreeItemis now a union (NavTreeLinkItem | NavTreeContentItem):
regular rows keep a requiredtitle— the accessible name — whilecontent
items may omit it, so no more placeholdertitle: "". Mixingcontentwith
row props (href,icon,children, …) is now a type error instead of
being silently ignored.The
LinkComponentprop type now declares everything NavTree actually passes
(stylefor the depth indent,aria-current, railaria-label/title) —
adapters that only forwardclassNamesilently lose the indent and the
active/rail semantics, so spread the rest:({ href, ...rest }) => <Link to={href} {...rest} />.
@eventuras/ratio-ui@2.12.0
Minor Changes
-
e7246c5: Navbar — composition parts for app headers.
The navbar can now be assembled from parts (existing
Brand/Contentare
untouched):-
Navbar.Search— a growing, width-capped zone for a search control.
It's a slot: drop aSearchFieldin from the call site (core/can't
depend onforms/). -
Navbar.Links+Navbar.Link— horizontal pill links withicon,
isCurrent(tinted pill +aria-current="page"), andLinkComponent
injection for SPA routers. -
Navbar.Actions— the right-hand cluster (bell, theme, user menu). -
Navbar.Spacer— flexible gap. -
Navbar.Row— stack rows for the editorial 2-row layout, with
variantsutility(slim tinted strip),brand, andnav. Rows are
separated by background tone, never borders.
Root gains
elevated— elevation instead of lines, per the design
("baren står på en subtil skygge"): card background and a soft shadow, never
borders. Centered it's a floating card (rounded frommd, full-bleed below);
withfluid(full-width row for admin consoles) it's a flat app header.Drawergains asideprop ('left' | 'right' | 'top' | 'bottom',
defaultright) — nav sheets from the left, action sheets from the bottom
(rounded lip, content-sized up to 85vh), notification trays from the top. Its
close affordance is now a round ghostActionButtoninstead of a full
secondaryButtonpill.Navbar.Toggle+Navbar.Collapseown the mobile pattern: a round
burger button that morphs into an X in place, and a disclosure panel folding
out under the bar —aria-expanded/aria-controlsand panel ids wired
automatically (no state at the call site). Pairs are linked by
controls/id(default'menu'), so a navbar can host several independent
panels — e.g. a search toggle and a burger — with one open at a time. Panels
unmount when closed.Navbaris now a Client Component ('use client').The stories use staged collapse (search needs
lg, linksmd) so nothing
wraps awkwardly at mid widths.<Navbar sticky elevated fluid> <Navbar.Brand>…logo…</Navbar.Brand> <Navbar.Links> <Navbar.Link href="/" isCurrent>Dashboard</Navbar.Link> </Navbar.Links> <Navbar.Search><SearchField size="sm" … /></Navbar.Search> <Navbar.Spacer /> <Navbar.Actions>…bell, user menu…</Navbar.Actions> </Navbar>
-
-
b2998e4: NavTree: horizontal orientation, accent active marker, and a content slot.
orientation="horizontal"— the top-level items as a tab row with an
accent underline on the active item (the navbar nav-row form, per the
design's navbar spec). Groups flatten and nesting isn't rendered.- Visual change: the vertical active row now uses the accent (Ochre)
tint with a 3px accent bar — the same "current" marker as Menu — replacing
the primary tint. NavTreeItem.content— render arbitrary JSX as an item (no row
chrome), e.g. a compactSearchFieldliving inside a group and filtering
its siblings. Composed from the call site; NavTree stays incore.
Hidden iniconOnlyandhorizontalmodes.
-
58bc0cd: SearchField & ActionButton — sizes, a real clear button, round variant, and React Aria alignment.
SearchField:size—'sm' | 'md' | 'lg'(defaultmd);smis the compact
variant for sidebars and toolbars (the "Filter types…" pattern).- The clear button now actually renders — the docs always claimed one, but
React Aria only wires a clear button when the field contains a button. It's
anActionButton roundhooked up automatically through React Aria's
ButtonContext, shown only while the field has content (Escape still clears). - More React Aria surface:
onClear,name,autoFocus, plustestId. - Visual change:
md/lgnow match Button's heights (~38px/~50px) instead
of the chunkyp-4+border-2form default, so a SearchField sits level
with buttons in the same toolbar row. - New
FilterNavigationstory shows the sidebar pattern: a small SearchField
live-filtering aNavTree.
ActionButton:- Rebuilt on React Aria's
Button— unified press handling and RAC
context participation (which is what powers the SearchField clear button).
onPressandisDisabledare available;onClick/disabledkeep working. round— fully circular chrome for burger/bell buttons and clear-X
affordances.- The
subtlelook is now the default (card-toned chrome); the former
transparent default is available asvariant="ghost", and thesubtle
variant name is gone (beta). Token-scoped consumers (Console, CodeBlock)
re-skin via--action-button-*and are unaffected. - Fixed: icon + plain-text buttons lost their horizontal padding. The
CSS-based icon-only check (:only-child) doesn't see text nodes, so
<Pause /> Pausewas treated as icon-only and rendered flush. Icon-only
detection is now element-based; icon-only buttons still stay square. - Now a Client Component (
'use client'), as required by React Aria.
Also exports
Bell,Pause, andPlayicons, and the ActionButton stories are consolidated to five scriptorium-themed examples. -
5d57df5: SearchField
shortcut+ a genericuseKeyboardShortcuthook.New in
hooks/:useKeyboardShortcut(combo, handler, options)— parses a
'mod+k'-style combo (mod= ⌘ on Apple platforms, Ctrl elsewhere), binds a
global listener, keeps the handler in a ref, SSR-safe. Ships with
shortcutLabel(combo)(platform-correct⌘K/Ctrl+Ktext forKbd
hints) andisApplePlatform(). Reusable for command palettes, dialogs, and
anything shortcut-shaped.SearchFieldgainsshortcutas the first consumer: the combo focuses
the field from anywhere, and aKbdhint with the platform-correct label
shows inside the field while it's empty and unfocused.
Patch Changes
- bd4435e: SearchField: remove the double clear button. WebKit renders a native
cancel button oninput[type=search]next to SearchField's own clear
ActionButton; the native one is now suppressed.