Skip to content

1.4.0

Choose a tag to compare

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

Added

  • Empty — what stands where content would have been, in four slots: icon, title, children and action. It is the other half of Skeleton: one is the shape of something on its way, the other is the shape of something that is not coming, and a list showing neither has a blank rectangle where its answer should be.
  • The headline is defaulted rather than required, because the version that says nothing useful is the version that gets shipped. title falls back to the locale's way of saying that there is nothing here — a new empty namespace in the message table, translated into all eighteen languages the library already speaks — and title={false} drops it for a state that is a glyph and a sentence. icon defaults to an empty tray and takes any node, so an illustration or another set's glyph goes in without a wrapper; action holds the way out, and several of them wrap together in one row.
  • variant defaults to text on this component and on no other: an empty state is nearly always already inside a Card, a Table or a panel, and a second rectangle inside the first is one rectangle too many. outline and solid are the undyed container sheet, so color reaches the hairline and the ring and stops — an empty state arriving in the accent colour is making a claim about content that does not exist. The root is a role="status" live region, which is what lets a list that empties under the reader say so; role={undefined} turns that off for a state that is part of the page on arrival.
  • Mockup — a device with a screen you can put anything on. device is the one prop with no default and picks the machine: a mobile, a tablet, or a desktop that is either a monitor on a stand or a laptop on a base. os draws that system's own chrome — a menu bar and a floating dock, a centred taskbar, a top bar with a dock down the leading edge, a status bar with a home indicator or three navigation glyphs — and systemUi={false} takes all of it away. bezel runs from none (no hardware at all, just the glass) through thin and standard to thick, which is an older device with a forehead and a chin rather than a wider frame; finish is graphite, silver or white; notch is a dynamic-island, a notch, a punch-hole or none, defaulting to whatever the device would really have. orientation turns a handheld, and the screen, the bezel and the cut-out turn with it.
  • The screen is a viewport at the device's real resolution, not a picture scaled down. size is a five-step ladder of genuine resolutions per device — a phone from 320 to 430 CSS pixels wide, a desktop from 1024 to 1920 — and resolution takes a { width, height } pair for anything else. The whole device is then scaled once to whatever width/height come to on the page, so the same component laid out inside a phone and inside a desktop wraps differently in each. The screen is also a container named neba-screen, so content can answer to the device with a container query rather than to the window.
  • scroll lets content taller than the screen scroll instead of being clipped; wallpaper takes any CSS background for what sits behind it; time is the clock, and the only text the chrome draws — every menu title, dock icon and tray glyph is an abstract shape, so there is nothing to translate and no other party's marks in the library. Every part of the device is aria-hidden, which leaves a screen reader with children and nothing else.
  • DataTable — a table for a lot of rows. Table draws a grid; this one is a place to work, and it takes the same two props to get there: headers and items. It is compact by default (sm, compact) with its own row ladder a step below the rest of the library, striped takes true, 'odd' or 'even', and the parity is counted over the whole set so it does not change as the rows are scrolled or sorted.
  • Only the rows on screen are in the DOM, and height is what turns that on. Every row is rowHeight tall — defaulted off the size/density ladder — so the offset of a row is its index times a constant and nothing has to be measured on a scroll frame; the rows that are left out stand up as two spacer rows, which is what keeps the scrollbar honest. Without a height or a maxHeight there is nothing to measure against and every row is rendered, whatever virtual says; virtual={false} asks for that on purpose, for a table small enough that find-in-page matters more than the DOM count. Cells truncate rather than wrap, which is the price of the arithmetic.
  • Selecting is the file manager's, not the form's. A click chooses a row and drops the rest, Ctrl/⌘ adds one, Shift takes the run between, a drag takes the run under the pointer and scrolls when it reaches an edge, and the arrow keys do all three with the same modifiers — plus Home, End, PageUp, PageDown, Space, Ctrl+A, Esc and Enter. selectionMode is none, single or multiple; checkboxes adds a tick column and is deliberately not the default, because a column of checkboxes says the task is choosing and on most tables it is not. With a selection mode the table is a grid with one tab stop and aria-activedescendant, since a virtual row cannot hold the focus.
  • sortable makes the headings pressable and they cycle ascending → descending → unsorted, because the order the rows arrived in is a state nothing else can get back to. sortMode="multiple" lets a Shift-click add a second key rather than replace the first. resizable puts a handle on each boundary; the first drag freezes every column at the width the browser had given it, so pulling one moves one, and a double-click restores it. Adjacent columns sharing a group string merge under one heading in a second header row.
  • paging="pages" swaps the scroll for a footer holding the range, the number of chosen rows, a page-size Select and a Pagination; footer shows that bar on its own, so a scrolling table can have the count without the pages. search matches every column that has not set searchable: false, case- and accent-insensitively, and searchable draws the field with toolbar filling the rest of its bar. manual hands any of 'sort', 'filter' and 'pages' back to the caller — with rowCount for the total — so a table whose rows come from a server is the same component rather than a second one.
  • The i18n table gains a table namespace — the search field's placeholder, the two ticks' labels, the page-size label, and the footer's count and selection sentences — in all eighteen languages. The two that carry numbers are whole templates with {start}, {end}, {total} and {count} in them rather than fragments, because what differs between languages is the order the numbers appear in.

Fixed

  • Forcing a theme on a nested element now works in both directions. .dark / [data-theme='dark'] on an element that is not the document root was already documented, but the light values were declared on :root alone, so .light / [data-theme='light'] inside a dark page had nothing to switch back to. The light block now carries all three selectors.
  • --neba-plate-solid, --neba-plate-glass and the --neba-shadow-1 … --neba-shadow-4 ladder moved into the derived block. Each is a base token spread into a shadow list, and declared only on :root they froze to the light hairline and the light ambient inside any theme root that was not the document root.

Documentation

  • Every live preview carries a theme switch in its top corner, so a component can be read in the theme the page is not in without taking the whole site with it. Untouched previews still follow the site switch, and a preview flipped back to the page's own theme rejoins it.
  • An Empty page in both locales with eight examples, its props rows, its demos, a card in the component gallery, a place on the sample screen beside the placeholder it is the other half of, and its entry in llms.txt.
  • A Mockup page in both locales with eleven examples, its props rows, its demos, a card in the component gallery, a place on the sample screen and its entry in llms.txt.
  • A DataTable page in both locales with seven examples, two props tables, its demos, a card in the component gallery, twelve thousand rows on the sample screen and its entry in llms.txt.
  • The nav bar and the sidebar no longer hang off the edges between 1440px and 1600px. The site raises --vp-layout-max-width to 1600px, and the default theme centres the shell on the article by taking half of what the page has left over — an expression it writes out five times without a floor, because at its own 1440px it cannot come out below zero. At ours it can: the social icons sat 8px outside the viewport and the sidebar climbed over the article's left margin. All five now read one floored --neba-gutter, which reduces every one of them to the gutter plus nothing, the page margin, or the sidebar's width.
  • npm run docs:dev starts in about four seconds instead of fourteen. All three docs:* scripts ran npm run build first — ten seconds of format:fix, tsc and terser that nothing then looked at, since the docs resolve neba to src/index.ts and import src/styles.css directly. Prettier now runs where it always did as part of npm run build, and CI still checks it.

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