Skip to content

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 12:35
· 62 commits to main since this release
a2e32f6

A minor that builds out the "analytical & generated-report UI" identity: a
full suite of opt-in communication primitives — SVG annotations, legends,
text/evidence marks, leader-line connectors, a guided-focus spotlight, a
crosshair/readout, a selection-state vocabulary, label declutter + direct labels
(declutterLabels/directLabels), and a source/citation/provenance trust
layer
— plus a consolidation pass over them. Each owns its visual grammar and
pure geometry and refuses to own scales/state/hit-testing (no chart engine).

Per the project's versioning policy, breaking changes ship in the minor. This
release carries three: the opt-in report kit's chart data key moved into the new
legend layer (.ui-chart__legend/__swatch removed — see Changed and
MIGRATIONS.json), annotation arrowheads now render via
the shared connectors geometry kernel (a small path-shape change), and the
opt-in marks' rationed-accent tone was renamed evidenceaccent to match the
rest of the analytical tone vocabulary. Everything else is additive and opt-in,
save for the tiny .ui-shortcut keyboard-hint primitive that joins the core
layer; the rest of the default dist/bronto.css is unchanged. Also folds in the
0.4.x maintenance hardening that had not yet been released.

Added

  • SVG annotations (@ponchia/ui/css/annotations.css,
    @ponchia/ui/annotations, .ui-annotation*, ui.annotation()): an opt-in
    annotation layer for charts, reports, and analytical figures, following the
    d3-annotation grammar (a subject marks the thing, a connector points
    away, a note carries the text). Ships a class grammar (variants for
    label/callout/elbow/curve/circle/rect/threshold/badge/bracket/band/slope/
    compare/cluster/axis/timeline/evidence, six tones, and opt-in
    draw/reveal/pulse/focus motion that respects prefers-reduced-motion)
    plus tiny geometry helpers that return SVG strings only — they own no chart
    scales, mutate no DOM, and provide no edit mode. Documented in
    docs/annotations.md and gated by check:report.
  • Legends / data keys (@ponchia/ui/css/legend.css, .ui-legend*,
    ui.legend()/ui.legendItem()/ui.legendSwatch(), initLegend): an opt-in,
    standalone data-key layer that reads the --chart-* palette tokens.
    Categorical, continuous gradient (sequential + --diverging), threshold, and
    pattern keys; swatch colour set inline (--chart-color) or via
    .ui-legend__swatch--1..8 index helpers; vertical/compact/with-values
    layouts. WCAG 1.4.1 by construction (the text label is the non-colour
    channel), with forced-colors and print care. Optional interactive
    (series-toggling) entries are <button aria-pressed> controls: initLegend
    flips aria-pressed/.is-inactive and emits bronto:legend:toggle
    ({ series, active }) — the host owns hiding the series and any aria-live
    announcement (it is never a chart engine). Optional useLegend hook in the
    React/Solid/Qwik bindings. New check:legend gate proves swatch colours are a
    subset of tokens/charts.js and never a raw hex. Documented in
    docs/legends.md.
  • Text marks / evidence (@ponchia/ui/css/marks.css, .ui-mark*,
    .ui-bracket-note*, ui.mark()/ui.bracketNote()): an opt-in layer of
    sober, report-grade emphasis for running prose — the counterpart to SVG
    annotations (annotations call out a figure, marks call out a sentence). Inline
    .ui-mark (highlight/underline/box/strike; --accent + status
    tones; --draw reduced-motion-safe sweep) for use on <mark>, and
    .ui-bracket-note for bracketing a whole passage. Pure CSS on semantic
    tokens, monochrome by default, with forced-colors care. Documented in
    docs/marks.md.
  • Connectors / leader lines (@ponchia/ui/css/connectors.css,
    @ponchia/ui/connectors, .ui-connector*, initConnectors, ui.connector()):
    an opt-in layer that draws a line between two DOM elements (the
    page-coordinate cousin of annotations). Pure geometry helpers
    (connectRects/connectorPath/arrowHead/…) that return SVG strings and own
    no DOM, an .ui-connector overlay grammar (straight/elbow/curve, arrow/dot
    ends, tones, dashed, --draw), and an optional initConnectors behavior that
    draws + tracks on resize/scroll. useConnectors in the bindings. Documented in
    docs/connectors.md.
  • Spotlight / guided focus (@ponchia/ui/css/spotlight.css, .ui-spotlight*,
    .ui-tour-note*, initSpotlight, ui.spotlight()): an opt-in guided-focus
    overlay — a box-shadow cutout over a target element, optional ring, and a
    callout note. initSpotlight positions the cutout (--spot-x/y/w/h) and
    re-places on resize/scroll and when data-target changes. Deliberately not
    a tour engine — the host owns step order/advancing/visibility. useSpotlight
    in the bindings. Documented in docs/spotlight.md.
  • Crosshair / readout (@ponchia/ui/css/crosshair.css, .ui-crosshair*,
    .ui-readout, initCrosshair, ui.crosshair()): an opt-in plot ruler +
    pinned readout. initCrosshair tracks the pointer over a
    [data-bronto-crosshair] plot, sets --crosshair-x/y, and dispatches
    bronto:crosshair:move with px + 0–1 fractions — it reports position only and
    never maps pixels to data (that needs the host's scales). useCrosshair in the
    bindings. Documented in docs/crosshair.md.
  • Selection states (@ponchia/ui/css/selection.css, .ui-sel*,
    ui.sel()): a tiny cross-cutting selection-emphasis vocabulary
    (--on/--off/--maybe) reusable on chart marks, table rows, list items, or
    map regions. The carve-out from brush/lasso — Bronto styles the states; the
    host owns the selection/hit-test logic. Documented in
    docs/selection.md.
  • Sources, citations & provenance (@ponchia/ui/css/sources.css,
    .ui-citation/.ui-source-card/.ui-source-list/.ui-provenance,
    ui.citation()/ui.source()/ui.provenance()): an opt-in, CSS-only trust
    layer
    for generated reports and AI output — the grammar for "where did this
    come from?". A cross-cutting .ui-src--* state (verified/reviewed/generated/
    unverified/stale/conflict) sets a rationed tone, always paired with an
    author-written label (never colour alone). Bronto owns the grammar + states;
    the host owns fetching, citation numbering, and trust. The first
    frontier-primitive beyond the analytical suite. Documented in
    docs/sources.md.
  • Keyboard-shortcut hint (.ui-shortcut + .ui-shortcut__sep, core): a tiny
    universal-chrome primitive that lays out one or more .ui-kbd keys as a chord
    (+K) or sequence (G then I) with a dim connective. The command tier's
    smallest piece, broadly useful outside a palette (menu items, buttons,
    tooltips). Class-only, like .ui-kbd.
  • Lifecycle / system state (@ponchia/ui/css/state.css, .ui-state
    (+__label/__detail/--busy) with canonical state modifiers
    (saving/saved/queued/offline/stale/conflict/error/locked/reviewed/
    needs-review), .ui-syncbar, ui.state()): an opt-in, CSS-only vocabulary for
    the states apps actually live in — a labelled state object with a rationed tone
    and a page/document sync bar. The label is the state (never colour alone);
    --busy pulses the indicator (reduced-motion-safe). Bronto ships the visual
    states + canonical wording; the host owns the state machine, retry, and
    persistence. Frontier candidate #2. Documented in docs/state.md.
  • Generated content & AI trust (@ponchia/ui/css/generated.css,
    .ui-generated/.ui-origin-label/.ui-reasoning/.ui-tool-log/.ui-tool-call,
    ui.originLabel()): an opt-in, CSS-only set of trust surfaces for AI /
    system-generated content — a marked region, an origin label, and quiet
    native-<details> reasoning + tool-call logs. Not a chat kit; no
    fabricated-confidence widget. Bronto styles disclosure/origin/trace, the host
    owns model metadata, redaction, and safety. Pairs with the source layer.
    Documented in docs/generated.md.
  • Workbench (@ponchia/ui/css/workbench.css, .ui-inspector/.ui-property/
    .ui-selectionbar): an opt-in, CSS-only core for tool UIs — a selected-object
    inspector panel, denser property rows, and a raised selection action bar.
    Layout + affordances only; resizable split panes and drag handles are
    deferred. Documented in docs/workbench.md.
  • Command palette (@ponchia/ui/css/command.css, .ui-command (+
    __input/__list/__group/__item/__shortcut/__meta/__empty),
    initCommand, useCommand): an opt-in CSS shell + behavior — filter +
    keyboard-navigate a DOM-authored command list (roving focus, group hiding,
    full keyboard), emitting bronto:command:select ({ value, label }) and
    bronto:command:close. Bronto navigates; the host owns the action registry,
    routing, and execution. No global Cmd/Ctrl+K. Completes the command tier
    (frontier #3) atop the shipped ui-shortcut. Documented in
    docs/command.md.
  • Label declutter (@ponchia/ui/annotations declutterLabels): a
    deterministic, order-preserving 1-D label de-overlap helper (sort, push
    apart by size + gap, slide to fit max) — pure, no DOM/scales. Not a 2-D
    collision solver. Documented in docs/annotations.md.
  • Direct labels (@ponchia/ui/annotations directLabels): the
    direct-labeling companion to declutterLabels — it declutters labels along an
    axis and draws the leader from each anchor to its placed label, reusing the
    connectors geometry kernel. Returns [{ x, y, anchor, key, d }] (the d feeds
    a ui-annotation__connector). Deterministic and pure: no scales, no DOM, no
    2-D placement (the 1-D core of Labella, completed with leaders). Documented in
    docs/annotations.md.
  • Connectors (@ponchia/ui/connectors, @ponchia/ui/css/connectors.css,
    initConnectors, useConnectors, ui.connector()) and Spotlight
    (css/spotlight.css, initSpotlight, ui.spotlight()) — leader lines between
    DOM elements and a guided-focus overlay; both opt-in, geometry/visual only
    (the host owns layout/tour state).
  • Crosshair / readout (css/crosshair.css, initCrosshair,
    ui.crosshair()) and selection states (css/selection.css, ui.sel()) —
    a plot ruler that reports pointer position (not data), and a cross-cutting
    .ui-sel--on/off/maybe emphasis vocabulary (the host owns brush/hit-test).
  • @ponchia/ui/css/analytical.css — a convenience roll-up that bundles the
    seven analytical leaves (annotations, legend, marks, connectors, spotlight,
    crosshair, selection) into one import. Add dataviz.css/report.css
    separately as needed.

Fixed

  • The optional Qwik binding (@ponchia/ui/qwik) is now built from the packed
    tarball in CI and release, alongside React/Solid — closing a coverage gap
    (it was documented as optimizer-proven but no job actually built it). Also
    covered by check:pack, the size report, and the dead-code config.

Changed

  • Breaking (opt-in report kit): the chart data key moved out of
    css/report.css into the standalone css/legend.css. .ui-chart__legend
    .ui-legend (now with .ui-legend__item/.ui-legend__label rows) and
    .ui-chart__swatch.ui-legend__swatch. Import @ponchia/ui/css/legend.css
    beside the report kit; see MIGRATIONS.json and
    docs/legends.md. The --chart-color/--chart-pattern
    swatch contract is unchanged, so the rename is mechanical.
  • Breaking (opt-in marks): the rationed-accent tone on .ui-mark and
    .ui-bracket-note was renamed evidenceaccent (ui-mark--evidence
    ui-mark--accent, ui-bracket-note--evidenceui-bracket-note--accent;
    ui.mark({ tone: 'accent' }) / ui.bracketNote({ tone: 'accent' })) so the
    accent tone reads the same across every analytical primitive (it already was
    accent on ui.connector/ui.annotation). .ui-annotation--evidence is
    unchanged — it is a marker variant (a proof/source shape), not a tone.
    Mechanical whole-token rename; see MIGRATIONS.json.
  • Consolidation: the SVG geometry is single-sourced in the connectors
    kernel — @ponchia/ui/annotations now builds its connectors on it, so a
    line/curve/arrow/dot is drawn one way across both. connectorLine/Curve/
    EndDot output is byte-identical; connectorEndArrow is the one
    (minor-breaking) shape change
    — the arrowhead now matches the connectors
    arrowhead. New check:helpers-dts gate keeps the hand-maintained
    annotations/connectors .d.ts in parity with their runtime exports.
  • The Doto webfont now ships as woff2 only (Brotli) instead of uncompressed
    TTF: ~5.7 kB per weight vs ~137 kB, cutting the six-weight payload from ~823 kB
    to ~35 kB (the dot-matrix glyphs compress ~96%) and shrinking the unpacked
    tarball by roughly the same. No TTF fallback is carried — woff2 is supported by
    the entire browser floor (ADR-0002: Chrome 125 / Safari 18 / Firefox 129).
    @font-face is internal, so this is transparent to consumers; only self-hosts
    that referenced fonts/doto-*.ttf directly need to point at *.woff2.
  • docs/architecture.md now ships in the package, so the offline rationale the
    shipped ADRs link to resolves inside the tarball.
  • docs/stability.md clarifies that data-surface/data-density/
    data-contrast are convenience presets, not part of the stability
    contract; data-theme (light/dark) remains the contractual base.

Internal

  • Token values are single-sourced in tokens/index.js (cssVars); the
    css/tokens.css palette is generated from it, so the dark palette is authored
    once instead of in three places (the shipped CSS is byte-identical).
  • behaviors/index.js is split into per-behavior modules behind the same public
    barrel (no surface change).
  • Drift-gate consolidation (assertFresh), a Qwik type smoke + stronger
    class-recipe wiring test, the APCA advisory widened to the accent text across
    the core palette and every colorway (still advisory; WCAG 2.1 AA stays the
    hard gate), an OLED computed-style smoke test, and several doc reconciliations.
  • New demos.spec e2e sweep runs the console-error / uncaught-exception /
    failed-response guards and an axe scan over every per-feature demo page
    (annotations, legends, marks, connectors, spotlight, crosshair, selection,
    report) in both themes and cross-browser — previously only /demo/ was
    guarded, so a throw or 404 on those SVG-heavy pages could not fail CI.
  • The check:dist payload ceiling was raised to 80 kB raw / 14.5 kB gzip (from
    78 kB / 13.5 kB). The default bundle was sitting ~21 bytes under the old gzip
    gate — the analytical primitives are opt-in leaves and stay out of it, so this
    is residual prior growth; the bump restores a real ~3% raw / ~7% gzip margin
    so an ordinary token addition no longer trips an unrelated PR.