UI Library docs: page-per-component + source-generated tables (3/3) - #46
Merged
Conversation
This was referenced Jun 24, 2026
librowski
marked this pull request as ready for review
June 24, 2026 12:31
librowski
requested review from
lukasz-jazwa,
piotrblaszczyk and
szymon-t-sc
as code owners
June 24, 2026 12:31
…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.
/ui-library/ has no index page - the section entry is /ui-library/overview/. The 'Headless components' heading sat above a paragraph describing a fully styled library built on headless primitives.
Subcomponents with their own page had their variables repeated on the parent: Button listed 17 of NavButton's, Switch 12 of IconSwitch's, and overriding them there does nothing. The Color/Size split now follows the value through the design tokens instead of guessing from the name, which put edge-stroke-width under Color and the snackbar status borders under Size.
The guard regex-scraped COMPONENTS out of the generator source, so a change in quote style would yield an empty list and pass having checked nothing. Both now import the same module; the remaining scrape (the vite entry list, which is TypeScript) fails on an empty result.
The reference branch accepted only type aliases, so a prop type written as an interface would drop its members from the table with no warning - the entry point of the same function already handled both forms.
NodePanel had no generator entry: its CSS variable list was written by hand and covered 10 of the 20 variables in source. The useEdgeStyle parameter table was hand-written too, so its type is now exported and documented from source. An entry may carry dir: null when it documents an API but owns no stylesheet - the edge variables stay on the Edge page instead of splitting off to the hook.
The snippet imported Icon from @workflow-builder/icons, which is marked private and cannot be installed from npm - a consumer copying it hits an unresolvable dependency. It now uses Phosphor, which ships with the package, and says that any icon library works.
Input documented four props while its own example used placeholder, value and onChange - and no page said the component extends a native element's attributes. The generator now detects the forwarded element by walking the prop type (through Omit/DetailedHTMLProps wrappers and first-party aliases) and each affected page states it in one line, instead of the table listing ~280 DOM attributes or staying silent.
The examples import @phosphor-icons/react. It is a dependency of the library, not something a consumer may import without declaring it - under pnpm's strict node_modules that import does not resolve. The install page now says so once, and the NodeIcon page points at it.
The example's import speaks for itself.
The comments it describes are stripped from the generated tables and do not survive minification into dist, so a reader of the docs has no way to encounter them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part 3 of 3 of the
@workflowbuilder/uiseries (#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/uibuild 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
apps/docs/scripts/generate-ui-api.mjs- the generator. Union/overload components (Button, NavButton, SegmentPicker) document through an explicit variant merge (collectVariantProps); a variant'sfoo?: neverexclusion 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.apps/docs/scripts/check-ui-component-coverage.mjs- parity guard: every ui vite entry must have a docs entry.apps/docs/src/components/ui-examples/**- live previews render inside shadow roots; portalled popups (Modal, Menu, Select, Tooltip, DatePicker) escape todocument.body, so the library stylesheet also loads at document level (astro.config.mjscustomCss) - it is fully layered with no reset, safe for the Starlight theme..github/workflows/pr-check-docs.yml- new path-filtered PR gate (apps/docs/**,packages/ui/**,packages/tokens/**): fullbuild:docs. Previously every docs gate first ran at release-time deploy.packages/uichanges riding here (by series convention: type exports needed by the generator): ~12export type XPropspromotions,DatePickerPropsnow covers the component's full runtime surface (value,defaultValue,placeholder,valueFormat,type,error), plus accurate@defaulttags. Covered by aminorchangeset 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:
NavIconButtonProps,NavLabelButtonProps,NavIconLabelButtonProps) were announced but reachable from no barrel - now re-exported viatypes.tsand proven importable with a consumer-side tsc probe against dist.valueanddefaultValueas simultaneously required - an impossible call); missing@defaulttags added for Tooltip/IconSwitch/EdgeLabel runtime defaults.useStateimport.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/uiinstall step.packages/sdk/**(starlight-typedoc reads it), root manifests, and the workflow file itself.missing tokencomment sweep.2026-08-13 - maintainer review round. Eight findings, all confirmed and addressed:
edge-stroke-widthsat under Color and the snackbar status borders under Size; the generator now resolvesvar()chains through the design tokens. 317 variables, zero misfiled in either direction.COMPONENTSout of the generator source, so a change in quote style would produce an empty list and a green check over nothing. Both sides now importscripts/ui-components.mjs; the remaining scrape (the vite entry list, which is TypeScript) fails on an empty result. The guard also requires every generated slug to be rendered by an MDX page.useEdgeStyle's parameter table was hand-written and its type unexported. Both now come from source.Partial<X>silently produced a slimmer table./ui-library/link, the "Headless components" heading over a paragraph describing a styled library, the stale "pinned to 1.4.x" claim,useStateimports missing from nine copyable examples, the NodeAsPortWrapper page describing behaviour the CSS does not implement, the "missing token" note, the private icons package in an example, Snackbar's scope, and the preview stage clipping wide examples.Verification
astro build: 208 pages, green - identical to the new CI job's gate.@themeimports, frontmatter fields, unsupported admonitions).Notes
pnpm-lock.yaml(regenerated).@workflowbuilder/ui@2.0.0tag no later than the docs deploy - the docs tell readers tonpm install @workflowbuilder/ui.