Skip to content

1.5.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 01:48
· 1082 commits to main since this release

Added

  • Charts. Five components on one engine: Sparkline, LineChart, AreaChart, BarChart and PieChart. They take their data the way Table does — series (or, for a pie, data) as a prop rather than markup — and they take it in the same shape as each other, so a dashboard tile can be switched from one chart to another without rewriting what feeds it. Statistic joins them in a new Charts group in the docs.
  • A null is a gap, not a zero, on every one of them. A line breaks at it, an area breaks with it, a bar is not drawn and the table cell is empty; connectNulls bridges it for the case where the gap is an artefact of collection rather than a month in which nothing happened. A chart that renders missing data as zero reports an outage as a collapse.
  • A series' colour follows its place in the array it was passed, never its position among the visible ones — so filtering a legend cannot repaint the survivors, and a reader who learned that Europe is blue keeps that. series.color overrides the slot with a NebaColor family or any CSS colour, and a point's own color overrides that for one mark.
  • LineChart takes curve (linear, a monotone smooth that will not dip below a value both its neighbours are above, or step), markers, gradient, connectNulls, valueLabels and stacked. Its value axis crops to the data, because a line encodes a position and cropping moves every point by the same amount.
  • AreaChart takes the same three curves plus stacked — true for totals, 'full' for a chart about the mix rather than the size, where the axis becomes a percentage and the tooltip and the table keep the caller's own number. Its axis keeps zero, because there the fill's thickness is the magnitude. Unstacked bands are a wash that fades downward so two of them overlapping stay readable; stacked bands are a flat tint parted by two pixels of the surface rather than by a stroke.
  • BarChart takes orientation — horizontal is the right answer whenever the category names are words — plus stacked (true / 'full'), rounded, barSize and valueLabels. Corners are cut off the data end only; a rounded foot makes the axis look scalloped. Bars grow from where zero is rather than from the bottom of the plot, so a negative bar starts on the same line as its neighbours.
  • PieChart takes shape — pie, donut or a semi circle — plus center for what goes in the hole, and valueLabels for each slice's share, drawn only where the text fits with room on both sides and dropped rather than clipped where it does not.
  • Sparkline is not a small chart: no axes, no grid, no legend, and no numbers, because every number it could label is one the sentence around it already has. shape is a line, an area or bars; endDot, baseline, min and max are the rest of it. It fills itself with its own range, which is what makes it legible at twenty pixels tall — and why two of them are only comparable when both are given the same min and max.
  • A hidden table under every chart, always. The drawing is aria-hidden and the data is rendered as a visually clipped <table> captioned with label, so no value is reachable only by pointer. The plot itself is focusable: ←/→ step the crosshair between categories, Home/End jump to the ends, Escape clears it, and the tooltip is a live region. The legend is a list of aria-pressed buttons, so which series are drawn is stated rather than implied by colour.
  • Eight new colour tokens, --neba-chart-1 … --neba-chart-8, per theme — and the one place in the library where a colour is not a semantic role, because a series is an entity and nothing about it means success or danger. They were solved rather than picked: every step inside the OKLCH lightness band, chroma above the floor where a hue stops carrying identity, every adjacent pair at least ΔE 8 apart in OKLab under simulated protanopia and deuteranopia (measured at 13.6 light and 14.5 dark), and every slot above 4:1 on white and 5.3:1 on the dark sheet. Dark is re-solved against the dark surface rather than lightened from the light values. Slots are handed out in order and never cycled: a ninth series is an "Other" row or a second chart, not a ninth hue.
  • --neba-chart-grid, --neba-chart-axis, --neba-chart-baseline and --neba-chart-gap — the chart's chrome, derived from --neba-border and --neba-surface so a chart's rules and a Card's dividers are one family of line. Gridlines are solid hairlines: a dashed grid says "projection" when all it is is a grid.
  • src/types.ts gains the vocabulary the charts share — NebaChartSeries, NebaChartDatum, NebaChartPoint, NebaChartCategory, NebaChartAxis, NebaChartLegend, NebaChartTooltip, NebaChartCurve, NebaChartValueLabels — for the reason NebaSize is there: a series handed to a LineChart has to be the one a BarChart takes.
  • Collapsible. One section that folds, standing on its own — what an Accordion is a set of, for a "Show more" on a form or the detail under a row. title, subtitle, startIcon and action build the header the way AccordionItem does, with action outside the trigger so a header that both folds and holds a switch has two things to press rather than one nested in the other; trigger replaces the header entirely and the element passed becomes the trigger, handed the click, aria-expanded and the aria-controls. keepMounted and hiddenUntilFound decide whether a closed panel is in the DOM, the second of them so the browser's own page search can open it.
  • Rating. A score as a row of stars, and two components in one skin. Choosable, it is a role="radiogroup" of real <input type="radio">s hidden under the half-stars they stand for — one tab stop for the row, arrow keys within it, aria-checked on the one that is taken and a value in a form submission, none of which a row of <button>s would have. readOnly renders no inputs at all and leaves one role="img" carrying the score as a sentence, which is why it is the one read-only in the library that does not drain the saturation: it is not a control being held still, it is the number itself. precision bounds what can be picked and never what is drawn, so a value of 4.3 stays 4.3 — an average is not a choice, and rounding it would report a different number from the one it was handed. The fraction is a filled star laid over an empty one and clipped from the inline start, so nothing is scaled and a half star fills from the right under RTL on its own.
  • BottomNavigation and BottomNavigationItem. An app's main destinations, held against the bottom edge of the window — position defaults to fixed here, against the static everything else defaults to, because that is what the component is. It is a <nav> of ordinary buttons (or <a>s, given an href) with aria-current="page" on the one you are on, and deliberately not a role="tablist": a tab list promises one tab stop for the set and arrow keys within it, and a bottom navigation changes the page rather than which panel of one is showing. labels draws every name, only the current one, or none — and a name it does not draw stays in the document, because a glyph on its own has no accessible name at all. safeArea holds the row clear of a phone's home indicator while the sheet still reaches the bottom of the screen.
  • FloatingActionButton and FloatingAction. The one action a screen is about, floating over it. The button is a Button unchanged — same variants, same elevation ladder, same pointer light — started one step up the size ladder at lg, because this is the control that has to be found and hit with a thumb without being looked at. extended writes label beside the glyph, which is also its accessible name, so the word drawn and the word read can never differ. position adds absolute to the three CSS values NebaPosition has, which is what pins one inside a card or a Mockup rather than to the window; corner and offset place it. Given FloatingAction children it becomes a dial: aria-expanded and aria-controls rather than a role="menu" it would not honour, the actions as ordinary buttons next in the tab order, Escape closing it and handing the focus back, and a press outside putting it away.

Documentation

  • Five component pages in both locales — Sparkline, LineChart, AreaChart, BarChart, PieChart — with the data model written out once on the LineChart page and cross-referenced from the rest, their props rows (including tables for NebaChartAxis, NebaChartLegend and NebaChartTooltip), sixteen demos, a Charts group in the component gallery, three charts and a row of sparklines on the sample screen, and their entries in llms.txt.
  • Statistic moved from Display to Charts, in both locales and in every index that names it.
  • Four component pages in both locales — Collapsible under Surfaces, Rating, BottomNavigation and FloatingActionButton under Inputs — with their props rows, twenty-one demos, four cards in the component gallery, two new blocks on the sample screen, and their entries in llms.txt and the README.
  • A rating namespace in src/internal/i18n.ts, translated into all eighteen locales: the group's name, the sentence one star is read out as, and what an unrated control says. The sentence carries both numbers rather than counting stars, because a count of stars is a plural in most languages and a fraction in none of them.

Every release is in the changelog on the docs site and in CHANGELOG.md at this tag.