Skip to content

UI Library docs: page-per-component + source-generated tables (3/3) - #46

Open
librowski wants to merge 32 commits into
ui-consumersfrom
ui-docs
Open

UI Library docs: page-per-component + source-generated tables (3/3)#46
librowski wants to merge 32 commits into
ui-consumersfrom
ui-docs

Conversation

@librowski

@librowski librowski commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Part 3 of 3 of the @workflowbuilder/ui series (#44 packages → #45 consumers → this PR).

Summary

Adds the UI Library section to the docs site: an overview + design-tokens guide, 19 component pages and 5 diagram-component pages, each with a live example rendered from the real @workflowbuilder/ui build and a props table generated from source (TypeDoc) plus a CSS-variables table scraped from the component stylesheets. Generated data (ui-api.json) is gitignored and rebuilt on every dev/build/typecheck run.

How to review

  1. apps/docs/scripts/generate-ui-api.mjs - the generator. Union/overload components (Button, NavButton, SegmentPicker) document through an explicit variant merge (collectVariantProps); a variant's foo?: never exclusion counts as "absent in that variant". Every silent-empty path now fails the build: missing component directory, unknown table slug, first-party props hidden behind an unresolvable utility wrapper (Partial<X>), ambiguous type names.
  2. apps/docs/scripts/check-ui-component-coverage.mjs - parity guard: every ui vite entry must have a docs entry.
  3. apps/docs/src/components/ui-examples/** - live previews render inside shadow roots; portalled popups (Modal, Menu, Select, Tooltip, DatePicker) escape to document.body, so the library stylesheet also loads at document level (astro.config.mjs customCss) - it is fully layered with no reset, safe for the Starlight theme.
  4. .github/workflows/pr-check-docs.yml - new path-filtered PR gate (apps/docs/**, packages/ui/**, packages/tokens/**): full build:docs. Previously every docs gate first ran at release-time deploy.
  5. packages/ui changes riding here (by series convention: type exports needed by the generator): ~12 export type XProps promotions, DatePickerProps now covers the component's full runtime surface (value, defaultValue, placeholder, valueFormat, type, error), plus accurate @default tags. Covered by a minor changeset for @workflowbuilder/ui.

Review history

Three-reviewer adversarial pass (pipeline / content accuracy / coupling & hygiene). Fixed since: unstyled portalled previews (5 of 23 examples), a setup page teaching the pre-#44 import-order requirement that no longer exists, a DatePicker table that documented none of the props its own example used, SegmentPicker/NavButton tables contradicting their prose (first-wins union flattening), four silent-empty generator paths, the missing PR CI gate, sidebar ordering of section index pages.

2026-08-11 - OpenCode (GPT-5.6) adversarial round. 15 findings, all verified on code; fixed here:

  • Changeset overpromise (CRITICAL): the NavButton variant prop types (NavIconButtonProps, NavLabelButtonProps, NavIconLabelButtonProps) were announced but reachable from no barrel - now re-exported via types.ts and proven importable with a consumer-side tsc probe against dist.
  • Generator fidelity: variant-only props are no longer marked globally required (SegmentPicker documented value and defaultValue as simultaneously required - an impossible call); missing @default tags added for Tooltip/IconSwitch/EdgeLabel runtime defaults.
  • Copyable examples: nine stateful usage blocks gained their missing useState import.
  • Pages aligned with code: NodeAsPortWrapper now documents the real mechanism (stretches the existing target handle's hit area; no built-in highlight; requires a target Handle), the "missing token" note describes the markers as historical, overview drops the 1.4.x pin claim, Snackbar states it is purely presentational, and the custom-node guide gains the @workflowbuilder/ui install step.
  • Preview stage: oversized examples (Snackbar) shrink to the stage or grow it instead of being clipped (verified at a 320px column).
  • Guards: the coverage check now also requires an MDX page rendering each generated slug; the docs CI gate's path filter covers packages/sdk/** (starlight-typedoc reads it), root manifests, and the workflow file itself.
  • Tracked as tasks: reference-type resolution + CSS-variable attribution by import graph, stale missing token comment sweep.

Verification

  • Full production astro build: 208 pages, green - identical to the new CI job's gate.
  • Live-docs checks: portalled modal renders fully styled in dark/light; DatePicker/SegmentPicker/NavButton tables verified against generated output (variant notes included); negative tests confirmed loud failures (renamed component dir → exit 1; unknown slug → render error pointing at the file).
  • Post-Starlight-migration sweep: no Docusaurus leftovers (configs, @theme imports, frontmatter fields, unsupported admonitions).

Notes

@librowski
librowski marked this pull request as ready for review June 24, 2026 12:31
@librowski
librowski force-pushed the ui-consumers branch 2 times, most recently from 7970aa1 to 6192878 Compare July 31, 2026 08:41
librowski-synergy and others added 27 commits August 11, 2026 12:25
…tyle props/CSS tables

Wrap every UI Library example in a shadow-DOM ComponentPreview so components
are styled only by @workflowbuilder/ui (isolated from Starlight CSS), shown in
a fixed 2:1 dotted preview box that matches the original Overflow UI docs.
Collapse each example island to a single representative instance.

Rework the generated Props and CSS-variable references from tables into card
lists: props show a 'required' chip (required-first) instead of a line-wrapping
'?' marker, with Type/Default/description rows; CSS variables group into
Color/Size. Drop the now-unused example-frame styles.
Give the Edge, NodeIcon, NodeDescription and NodePanel pages the same shadow-DOM
ComponentPreview the UI components use, rendering each as a standalone example
(NodePanel compositions; EdgeLabel variants positioned relatively outside a
canvas) for parity with the original Overflow UI docs. NodeAsPortWrapper stays
props-only, matching the reference. Adds @phosphor-icons/react to the docs app
for the example icons.
Status is an absolutely-positioned corner badge; rendered standalone it had no
positioned ancestor and floated to the wrong place. Wrap it in a relative box
that stands in for the node/field it marks, so it sits in the top-right corner
as intended.
The UI Library overview told consumers to install @base-ui/react alongside the
package. It is now a regular dependency that installs automatically; react and
react-dom are the only peers.
@workflowbuilder/ui components and generate-ui-api.mjs's TypeDoc pass both
need packages/ui/dist to exist; add a Build UI step ahead of Build docs,
mirroring the existing Build SDK step.
- Fix the generator's lint errors (renamed vars for clarity, imported
  node:process, top-level await with process.exitCode instead of
  process.exit/main().catch, matching tools/preflight.mjs's pattern).
- Strip internal engineering notes (matching /missing token/i) out of CSS
  variable comments instead of rendering them on the public docs pages.
- Treat an unresolved props type as fatal (process.exitCode = 1) instead of
  a warning, so a renamed/typo'd type can't silently ship an empty page.
- Add collectVariantProps() to merge Button's discriminated-union variant
  props (Label/Icon/IconLabel) into one deduped table with per-variant
  notes, and switch the TypeDoc entry point from index.ts (resolve) to
  src/components (expand) so those variant-only prop types get full
  reflections.
- Add a check-ui-component-coverage.mjs guard, wired into generate:ui-api,
  asserting every packages/ui/vite.config.mts componentEntries item has a
  matching COMPONENTS entry, so a new published component can't ship
  without a docs page.
- Run generate:ui-api before astro check in typecheck, so the coverage
  guard and generator failures surface there too.

The unrelated PropRow/CssVar -> PropertyRow/CssVariable renames in
props-table.astro / css-variables-table.astro are a lint-driven cleanup in
the same generator/docs-api area.
- Add a Collapsible page: intro, live example, Usage, a hand-authored
  Parts table for Collapsible.Button/Collapsible.Content (no exported
  prop type to key a generated table on, same precedent as NodePanel),
  and generated Props/CSS variables tables. List it in the components
  index.
- Add an Icon switch section to the Switch page documenting IconSwitch
  (live example, Usage, generated Props/CSS variables tables).
- Rewrite the overview's Styles section: importing from the package root
  auto-injects the layer order/reset/tokens setup, so only tokens.css is
  needed; the styles.css + tokens.css pair only applies to the
  per-component subpath-import path. Matches packages/ui/README.md and
  packages/ui/css-layers.md.

Depends on the collapsible/icon-switch COMPONENTS entries and the
Button-variant TypeDoc entry point switch landed in the generator commit.
The runtime default (shape = 'default' in the forwardRef destructure) was
documented as @default '' in the TSDoc comment, which the UI Library docs
render verbatim.
Resolves vite-plugin-dts, vite-plugin-svgr, and i18next/react-i18next to a
single typescript@5.9.3 peer resolution instead of a stale mixed
5.6.3/5.9.3 set, matching --frozen-lockfile.
Helper types like WithIcon live in src/shared, outside the components
entry tree, so they got no reflection and their members (Accordion's
and Modal's icon prop) silently vanished from the generated tables.
…views

Modal, Menu, Select, Tooltip and DatePicker portal their popups to body,
outside the shadow roots that carry the preview styles - the popups
rendered unstyled. The library CSS is fully layered with no reset, so
loading it globally is safe for the Starlight theme.
Every built stylesheet has carried the @layer order statement since the
stamping fix, so 'import styles.css before any component' is no longer a
correctness requirement; styles.css also ships no reset, only typography.
The docs generator reads the exported DatePickerProps, but the props the
component actually accepts (value, defaultValue, placeholder, valueFormat,
type, error) lived on an unexported local widening type - the generated
table documented none of the props the page's own example uses. The
widening moves into the exported type, TSDoc included.
… merge

SegmentPicker's discriminated union was flattened first-wins: the table
claimed value is always required and typed defaultValue as never,
contradicting the page's own controlled/uncontrolled prose. NavButton
was generated from its flat base type, so children - the prop its page
is about - never appeared. Both now list their variant prop types, and
a variant's 'foo?: never' exclusion counts as the prop being absent
there instead of polluting the merged type.
Four holes of the same class - the tool swallowing a problem and shipping
a plausible-looking page:
- a moved/renamed component directory made extractCssVariables glob
  nothing and exit 0 (page claims 'no CSS variables')
- an unknown slug in PropsTable/CssVariablesTable rendered the empty
  state instead of failing the build (typo = false page in production)
- a first-party type hidden behind an unresolvable utility wrapper
  (Partial/Omit) dropped its props with no trace - the class that once
  got the library reshaped to suit the generator
- findTypeByName picked the first of duplicate type names silently
Every docs gate (ui-api generator, component-coverage guard, astro page
rendering) used to run for the first time at release-time deploy - a
broken docs change merged green and surfaced weeks later as a red
deploy. Path-filtered to docs/ui/tokens changes so unrelated PRs pay
nothing.
The index pages sorted alphabetically inside their own groups (the 'UI
Components' link sat 7th within UI Components). Order 0 plus an Overview
label matches the plugins/nodes convention; link lists use exact
component symbol names, and the section description gains sentence case.
The changeset announced them, but only NavBaseButtonProps left the
package - the variant types lived in component files outside every
barrel. Verified with a consumer-side tsc probe against dist.
The generator reads defaults from JSDoc only; Tooltip placement,
IconSwitch variant and EdgeLabel size/state/type had runtime defaults
with no tag, so their table cells rendered empty.
Absent variants were filtered out before the every() check, so
SegmentPicker documented value (controlled) and defaultValue
(uncontrolled) as simultaneously required - a call that cannot exist.
Required now means required in every variant; the variant note says
where a prop is required otherwise.
The coverage guard only cross-checked vite entries against generator
entries; an entry with no page rendering its slug passed silently.
starlight-typedoc reads packages/sdk sources, and root manifests plus
the workflow file itself shape the build - none of them triggered the
gate, so an SDK change could break the docs build unnoticed until
deploy.
The fixed 2/1 stage with overflow:hidden clipped wide examples
(Snackbar) on narrow layouts. The ratio is now a preferred size:
shadow-root children cap at the stage width and content restores the
automatic minimum height. Also corrects the isolation comment -
inherited typography crosses the shadow boundary by design.
Nine usage blocks called useState without importing it, so a copied
example failed to compile. Snackbar now says it is purely
presentational - no positioning, stacking, or auto-dismiss.
NodeAsPortWrapper stretches the existing target handle's hit area and
adds no highlight of its own - the page claimed the whole node becomes
a highlighted port with no preconditions. The missing-token note now
describes the comments as historical markers (several referenced tokens
exist in the export today). Overview drops the 1.4.x pin claim, and the
custom-node guide gains the missing ui package install step.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants