Files
WRNexusJS/docs/ui-library-audit-2026-08-08.md
T
ClintchizandClaude Opus 5 84dc4e06a2
Quality / quality (ubuntu-latest) (push) Failing after 12m40s
Quality / quality (windows-latest) (push) Canceled after 0s
docs: audit the ui library and record the 0.8.6 migration
A measured pass rather than a bulk rewrite. Numbers come from the source and
from a browser.

The migration entry covers what has accumulated since 0.8.5 and would
otherwise reach upgraders unannounced: the Tabs output contract, the Sidebar
BEM rename, the layout components leaving Tailwind so their rendered class
lists changed, LayoutSplitter and CustomScrollbar changing props and outputs,
the ui.css families that were removed, and the theme tokens that now paint
where they previously resolved to nothing.

The audit records what is still wrong, with counts: 32 outputs across 16
components that nothing emits, 23 components still on the scaffold pattern, 66
without a local style block and therefore dependent on ui.css, and 10 still
using Tailwind. A test pins the dead-output count at 32 as a ceiling that only
moves down, so rebuilding a component tightens it and no new one can be added
quietly.

It also records what is not worth doing. Splitting the runtime saves 3 to 4 kB
gzipped on a first visit to a file cached for a year, and hydration costs
1.5 ms for 21 scopes across 4325 elements, so neither is a real problem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 17:16:57 +05:30

5.4 KiB
Raw Blame History

UI library audit — 2026-08-08

A measured pass over @wrnexus/ui after the navigation and layout groups were rebuilt. Numbers come from the source and from a browser, not from estimates.

Fixed in this pass

Ten theme tokens were referenced and never defined. An undefined custom property does not warn — it resolves to nothing — so the styles that used them silently did nothing:

Token Effect while undefined
--wire-color-focus Focus rings drew with no colour, in 14 components
--wire-color-surface-soft Every soft surface rendered transparent, in 27 components
--wire-color-on-danger Text on danger fills had no colour
--wire-color-surface-subtle Subtle panels rendered transparent
--wire-color-input-* (6) Input backgrounds, borders and placeholders unstyled
*-hover, *-contrast Missing for info, success, warning and danger

They are derived in the theme now, so they follow the palette and the accent. Verified in a browser: 38 tokens referenced, 0 undefined (was 10).

Two mistakes worth recording, because both nearly became wrong conclusions:

  • A first version of the check read the theme source and reported a dozen false positives, because most tokens are generated per palette rather than written as literals. The check now reads the rendered theme CSS.
  • The semantic token spread sat after the primary and secondary palette entries, so it would have overridden them. It now sits before.

Outstanding, with numbers

32 outputs across 16 components have no emitter of any kind. This is the bug LayoutSplitter had: the component advertises an output, a caller binds to it, and nothing ever fires. Native event names are excluded — the runtime binds a DOM-listener fallback on component tags, so click and input do arrive.

Component Dead outputs
FileUpload upload, progress, success, cancel, remove
ToastNotifications add, dismiss, clear, action
AdvancedDatePicker open, close, clear
Card action, navigate, dismiss
Accordion open, close
AdvancedRangeSlider start, end
Chart dataPointClick, legendToggle
Confetti start, complete
TreeView expand, collapse
AnnouncementBar, Badge, Toast, alert dismiss
AvatarGroup overflow
CopyMarkup success
Footer action

A test pins this at 32 as a ceiling that only moves down.

23 components are still on the wire-next scaffold pattern — no style block, no functions, and for 19 of them an outputs block they never honour. These are the same shape as the Table scaffold that was removed and the LayoutSplitter scaffold that was rebuilt.

66 of 108 components have no local style block, so they depend on ui.css. That matters for delivery: a migrated component ships its CSS only when it renders, while ui.css is served whole to every page — 175,848 bytes, 25,908 gzipped. Migrating the remainder would shrink it toward nothing.

10 components still use Tailwind utilities: FeatureIconCard, HeroActions, InputNumber, List, Map, Marquee, SearchBox, TextLink, Timeline, button.

Not worth doing

Splitting the runtime into chunks. Measured rather than assumed: reactive.js is 69,947 bytes minified, roughly 21 kB gzipped, served as its own file with a one-year immutable cache. Component-specific controllers are about 18% of it, so splitting them out saves 34 kB gzipped on a first visit and nothing after that. That is a poor return for lazy-loading complexity.

Hydration is not a bottleneck either: 21 scopes across 4,325 elements rehydrate in 1.5 ms, and the shared document observer cost 0.9 ms across three seconds of the busiest activity in the library.

Known framework defects

  • A component output is not delivered to a parent binding in at least one case. LayoutSplitter emits sizeChange and the component genuinely fires the event, but @sizeChange on the tag is not invoked. Outputs work elsewhere, so this is narrow and unexplained. Renaming away from the native resize did not fix it, so the first hypothesis was wrong.
  • A component tag nested inside another component slot is dropped, leaving only its children.
  • Component props and slot content render once and do not track page state, so the controlled-component pattern does not work.
  • i18n text is not server-rendered. Nav links ship as empty spans and are filled by the client, so navigation is blank until the runtime loads.