Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
38f3b29
feat(docs): add live @workflowbuilder/ui component gallery
librowski-synergy Jun 23, 2026
40ddd5e
docs: point UI-library references at @workflowbuilder/ui
librowski-synergy Jun 23, 2026
21ef28c
feat(docs): expand UI Library into page-per-component reference
librowski-synergy Jun 24, 2026
36e76d4
refactor(ui): export component prop types and add @default tags
librowski-synergy Jun 24, 2026
0fb56c4
feat(docs): generate UI Library props and CSS tables from source via …
librowski-synergy Jun 24, 2026
5f7e52b
docs(ui): render examples in isolated fixed-size previews with card-s…
librowski-synergy Jun 24, 2026
2416797
docs(ui): add live previews to diagram-component pages
librowski-synergy Jun 24, 2026
70f0bbc
docs(ui): anchor the Status example to a positioned container
librowski-synergy Jun 26, 2026
a538128
docs(ui): @base-ui/react is no longer a peer dependency
librowski-synergy Jun 26, 2026
056528a
ci(docs): build UI before docs in the deploy workflow
Jul 30, 2026
c54baf8
fix(docs): harden the UI API generator and guard component coverage
Jul 30, 2026
eed6c84
docs(ui): document Collapsible and Icon switch, align Styles guidance
Jul 30, 2026
25aa8d8
fix(ui): correct segment-picker shape prop's @default doc tag
Jul 30, 2026
17dd33e
chore: sync pnpm-lock.yaml with workspace typescript resolution
Jul 30, 2026
143f5e5
refactor(ui): drop redundant Partial around WithIcon in ModalProps
Jul 31, 2026
87e4541
fix(docs): include shared prop types in TypeDoc entry points
Jul 31, 2026
59fd7d1
fix(docs): load the ui stylesheet at document level for portalled pre…
Aug 10, 2026
7ddf67f
docs: drop the stale import-order requirement from the ui setup page
Aug 10, 2026
9896a41
refactor(ui): export the full DatePicker props surface
Aug 10, 2026
5fba064
fix(docs): document union and overload components through the variant…
Aug 10, 2026
22d8207
fix(docs): fail loudly on every silent-empty path in the ui-api pipeline
Aug 10, 2026
fc8acd3
ci: build the docs site on PRs that can break it
Aug 10, 2026
e8cc0c1
docs(changeset): record the exported ui prop-type surface
Aug 10, 2026
a01d8ff
docs: pin section index pages to the top of their sidebar groups
Aug 10, 2026
faaf69d
fix(ui): export the NavButton variant prop types from the barrel
Aug 11, 2026
1969d94
docs(ui): add default tags for runtime defaults missing from the tables
Aug 11, 2026
8ea8c37
fix(docs): stop marking variant-only props as globally required
Aug 11, 2026
a2c3a77
ci(docs): require an MDX page for every generated component entry
Aug 11, 2026
bf8a92b
ci(docs): widen the docs gate path filter
Aug 11, 2026
105e75c
fix(docs): let oversized examples shrink or grow the preview stage
Aug 11, 2026
c78d6dd
docs: complete the stateful examples and describe Snackbar's scope
Aug 11, 2026
5612940
docs: align pages with what the code actually does
Aug 11, 2026
a7decef
docs: fix the dead ui-library link and the headless heading
librowski Aug 12, 2026
92a9358
fix(docs): scope and classify the generated CSS variable tables
librowski Aug 12, 2026
b03f08d
refactor(docs): share the component list between generator and guard
librowski Aug 12, 2026
319247f
style(docs): rename a loop variable flagged by the lint rule
librowski Aug 13, 2026
331bb48
fix(docs): follow interface references when collecting props
librowski Aug 13, 2026
ae4e0a6
fix(docs): generate the last two hand-written API tables
librowski Aug 13, 2026
18a2757
docs: drop the private icons package from the NodeIcon example
librowski Aug 13, 2026
e23ca19
fix(docs): say when a component forwards native attributes
librowski Aug 13, 2026
78b5c6b
docs: say that example icons need installing
librowski Aug 13, 2026
74751d6
docs: drop the prose about icon libraries
librowski Aug 13, 2026
8ded18f
docs: drop the missing-token section
librowski Aug 13, 2026
ebd93b1
refactor(docs): trim inline comments to the traps worth keeping
librowski Aug 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/ui-export-prop-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@workflowbuilder/ui': minor
---

Component prop types are now exported: `AvatarProps`, `CheckboxProps`, `RadioProps`, `StatusProps`, `TooltipProps`, `MenuProps`, `ModalProps`, `EdgeLabelProps`, `NodeIconProps`, `NodeDescriptionProps`, `NodeAsPortWrapperProps`, `SegmentPickerProps` (with its controlled/uncontrolled variants), the NavButton variant prop types, and `DatePickerProps` now covers the component's full runtime surface (`value`, `defaultValue`, `placeholder`, `valueFormat`, `type`, `error`). Supporting types used in those signatures (`Shape`, `IconNode`) are exported as well.
5 changes: 5 additions & 0 deletions .changeset/ui-export-use-edge-style-params.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@workflowbuilder/ui': minor
---

`UseEdgeStyleParams`, the parameter type of the `useEdgeStyle` hook, is now exported.
5 changes: 5 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile

# UI must build first: docs imports @workflowbuilder/ui/{styles,tokens}.css
# and its components, both resolved from packages/ui/dist.
- name: Build UI
run: pnpm build:ui

# SDK must build first so TypeDoc can read its compiled types.
- name: Build SDK
run: pnpm --filter @workflowbuilder/sdk build:lib
Expand Down
57 changes: 57 additions & 0 deletions .github/workflows/pr-check-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: PR Check (docs)

# The docs site is generated from packages/ui source (ui-api tables, live
# examples) and consumes its built dist, so a PR touching either can break
# the docs build - which otherwise first runs at release-time deploy.
# Full `astro build` is the gate: it runs the ui-api generator, the
# component-coverage guard, and page rendering (loud failures included).
# Typecheck is deliberately absent: apps/docs tolerates known starlight
# virtual-module type errors.

on:
pull_request:
branches:
- main
paths:
- 'apps/docs/**'
- 'packages/ui/**'
- 'packages/tokens/**'
# starlight-typedoc generates the /api reference from SDK sources.
- 'packages/sdk/**'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- 'package.json'
- '.github/workflows/pr-check-docs.yml'

permissions:
contents: read

jobs:
docs:
name: Docs build (ui-api generator + coverage + astro)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: true

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Enable Corepack
run: npm i -g corepack@latest

- name: Install pnpm
run: corepack prepare

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build UI library
run: pnpm build:ui

- name: Build docs
run: pnpm build:docs
6 changes: 3 additions & 3 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ name: PR Check
# Runs on every PR to give reviewers fast feedback on whether the change
# is safe to merge. Focus on the published packages @workflowbuilder/sdk and
# @workflowbuilder/ui (plus its private @workflowbuilder/ui-tokens build) +
# global format consistency. Other workspaces (apps/docs, demo, ai-studio, …)
# are not checked here — they're internal and have their own broken-state
# tolerances (e.g. starlight virtual-module type errors).
# global format consistency. apps/docs has its own path-filtered workflow
# (pr-check-docs.yml); demo and ai-studio are not checked here — they're
# internal and have their own broken-state tolerances.

on:
pull_request:
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,8 @@ CLAUDE.local.md
# and is copied into this dir by a tiny Astro integration after typedoc
# generation (see astro.config.mjs).
apps/docs/src/content/docs/api/

# UI Library props + CSS-variable data, generated from @workflowbuilder/ui by
# apps/docs/scripts/generate-ui-api.mjs (TypeDoc + CSS extraction) on every
# docs build / dev. Source of truth is the library, so keep it out of git.
apps/docs/src/generated/
25 changes: 24 additions & 1 deletion apps/docs/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { copyFileSync, mkdirSync } from 'node:fs';
import path from 'node:path';

import react from '@astrojs/react';
import starlight from '@astrojs/starlight';
import umami from '@yeskunall/astro-umami';
import { defineConfig, passthroughImageService } from 'astro/config';
Expand Down Expand Up @@ -70,6 +71,7 @@ export default defineConfig({
},
integrations: [
icon(),
react(),
umami({ id: UMAMI_WEBSITE_ID }),
starlight({
plugins: [
Expand Down Expand Up @@ -113,7 +115,19 @@ export default defineConfig({
},
}),
],
customCss: ['./src/styles/custom.css'],
// `@workflowbuilder/ui` styles are safe to load globally: everything is
// layered (no global reset), classes are hashed or opt-in, and tokens.css
// only defines `--ax-*` custom properties keyed on `html[data-theme]` —
// which Starlight already toggles, so the live component showcases follow
// the docs light/dark theme. index.css is required at document level:
// Modal/Menu/Select/Tooltip/DatePicker portal their popups to body,
// outside the shadow roots that carry the preview styles.
customCss: [
'./src/styles/custom.css',
'@workflowbuilder/ui/styles.css',
'@workflowbuilder/ui/tokens.css',
'@workflowbuilder/ui/index.css',
],
components: {
Head: './src/components/head.astro',
Search: './src/components/search.astro',
Expand Down Expand Up @@ -159,6 +173,15 @@ export default defineConfig({
{ label: 'Node Schemas', autogenerate: { directory: 'node-schemas' } },
{ label: 'Built-in Nodes', autogenerate: { directory: 'nodes' } },
{ label: 'Plugins', autogenerate: { directory: 'plugins' } },
{
label: 'UI Library',
items: [
{ label: 'Overview', link: '/ui-library/overview/' },
{ label: 'Design tokens', link: '/ui-library/design-tokens/' },
{ label: 'UI Components', autogenerate: { directory: 'ui-library/ui-components' } },
{ label: 'Diagram Components', autogenerate: { directory: 'ui-library/diagram-components' } },
],
},
// API Reference — pages auto-generated by `starlight-typedoc` from
// packages/sdk's barrel into `src/content/docs/api/<Category>/`.
// Folder names match the `@category` tag in source TSDoc verbatim.
Expand Down
15 changes: 12 additions & 3 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,37 @@
"private": true,
"type": "module",
"scripts": {
"dev": "pnpm clean:typedoc && astro dev",
"build": "pnpm clean:typedoc && node scripts/check-sidebar-categories.mjs && astro build && node scripts/touch-distribution-index.mjs && node scripts/copy-swa-config.mjs",
"dev": "pnpm clean:typedoc && pnpm generate:ui-api && astro dev",
"build": "pnpm clean:typedoc && pnpm generate:ui-api && node scripts/check-sidebar-categories.mjs && astro build && node scripts/touch-distribution-index.mjs && node scripts/copy-swa-config.mjs",
"generate:ui-api": "node scripts/generate-ui-api.mjs && node scripts/check-ui-component-coverage.mjs",
"clean:typedoc": "node -e \"import('node:fs').then(fs => fs.rmSync('src/content/docs/api', { recursive: true, force: true }))\"",
"preview": "astro preview",
"typecheck": "astro check",
"typecheck": "pnpm generate:ui-api && astro check",
"format": "prettier --write --log-level silent \"**/*.astro\"",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"dependencies": {
"@astrojs/react": "^4.4.0",
"@astrojs/starlight": "^0.37.6",
"@base-ui/react": "catalog:",
"@iconify-json/ph": "^1.2.2",
"@phosphor-icons/react": "catalog:",
"@workflowbuilder/sdk": "workspace:*",
"@workflowbuilder/ui": "workspace:*",
"@yeskunall/astro-umami": "^0.0.7",
"astro": "^5.18.0",
"astro-icon": "^1.1.5",
"marked": "^15.0.0",
"react": "catalog:",
"react-dom": "catalog:",
"rehype-external-links": "^3.0.0",
"starlight-image-zoom": "^0.13.2"
},
"devDependencies": {
"@astrojs/check": "^0.9.6",
"@types/react": "catalog:",
"@types/react-dom": "^19.1.0",
"eslint-plugin-astro": "^1.3.1",
"starlight-typedoc": "^0.21.3",
"typedoc": "^0.28.9",
Expand Down
77 changes: 77 additions & 0 deletions apps/docs/scripts/check-ui-component-coverage.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Cross-checks the documented component surface: every publishable subpath in
// packages/ui/vite.config.mts has a COMPONENTS entry, and every COMPONENTS
// entry is rendered by an MDX page. Without it a component ships to npm with
// no docs page and nothing in the build complains. Runs as part of
// `generate:ui-api`.

import { globSync, readFileSync } from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import { fileURLToPath } from 'node:url';

import { COMPONENTS } from './ui-components.mjs';

const here = path.dirname(fileURLToPath(import.meta.url));
const documentsRoot = path.resolve(here, '..');
const repoRoot = path.resolve(documentsRoot, '../..');
const viteConfigPath = path.resolve(repoRoot, 'packages/ui/vite.config.mts');

const NARRATIVE_ONLY = new Set([]);

// Read as text, not imported - it is TypeScript. Empty means the shape changed.
function extractComponentEntries(source) {
const match = /const componentEntries = \[([\s\S]*?)] as const;/.exec(source);
if (!match) throw new Error('Could not find `componentEntries` in packages/ui/vite.config.mts');
const entries = [...match[1].matchAll(/'([^']+)'/g)].map((m) => m[1]);
if (entries.length === 0) {
throw new Error('Extracted zero entries from `componentEntries` in packages/ui/vite.config.mts');
}
return entries;
}

const componentEntries = extractComponentEntries(readFileSync(viteConfigPath, 'utf8'));
const componentDirectories = COMPONENTS.map((component) => component.dir).filter(Boolean);
const componentSlugs = COMPONENTS.map((component) => component.slug);

const missing = componentEntries.filter((entry) => {
if (NARRATIVE_ONLY.has(entry)) return false;
return !componentDirectories.some((directory) => directory === entry || directory.startsWith(`${entry}/`));
});

const contentRoot = path.resolve(documentsRoot, 'src/content/docs');
const pageSources = globSync('**/*.mdx', { cwd: contentRoot }).map((file) =>
readFileSync(path.resolve(contentRoot, file), 'utf8'),
);
const unrendered = componentSlugs.filter(
(slug) => !pageSources.some((source) => source.includes(`slug="${slug}"`)),
);

if (missing.length > 0) {
console.error('error: componentEntries in packages/ui/vite.config.mts have no matching COMPONENTS entry.\n');
for (const entry of missing) {
console.error(` - ${entry}`);
}
console.error(
'\nAdd a COMPONENTS entry in apps/docs/scripts/generate-ui-api.mjs with a matching `dir`, ' +
'or add the entry to NARRATIVE_ONLY in this script if it is deliberately prose-only.',
);
process.exitCode = 1;
}

if (unrendered.length > 0) {
console.error('error: COMPONENTS entries in generate-ui-api.mjs are rendered by no MDX page.\n');
for (const slug of unrendered) {
console.error(` - ${slug}`);
}
console.error(
'\nAdd a docs page that uses <PropsTable slug="..."> / <CssVariablesTable slug="...">, ' +
'or remove the generator entry.',
);
process.exitCode = 1;
}

if (missing.length === 0 && unrendered.length === 0) {
console.log(
`✓ component coverage ok — ${componentEntries.length} vite entries and ${componentSlugs.length} docs slugs cross-checked.`,
);
}
Loading
Loading