Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
9c226d2
feat(docs): add live @workflowbuilder/ui component gallery
librowski-synergy Jun 23, 2026
a97905b
docs: point UI-library references at @workflowbuilder/ui
librowski-synergy Jun 23, 2026
95a49b6
feat(docs): expand UI Library into page-per-component reference
librowski-synergy Jun 24, 2026
d01577b
refactor(ui): export component prop types and add @default tags
librowski-synergy Jun 24, 2026
6d83389
feat(docs): generate UI Library props and CSS tables from source via …
librowski-synergy Jun 24, 2026
bb534ad
docs(ui): render examples in isolated fixed-size previews with card-s…
librowski-synergy Jun 24, 2026
1a9bc1d
docs(ui): add live previews to diagram-component pages
librowski-synergy Jun 24, 2026
fb209ad
docs(ui): anchor the Status example to a positioned container
librowski-synergy Jun 26, 2026
26c9bce
docs(ui): @base-ui/react is no longer a peer dependency
librowski-synergy Jun 26, 2026
f811fe5
ci(docs): build UI before docs in the deploy workflow
Jul 30, 2026
6cacfac
fix(docs): harden the UI API generator and guard component coverage
Jul 30, 2026
4329ddd
docs(ui): document Collapsible and Icon switch, align Styles guidance
Jul 30, 2026
d88dc6c
fix(ui): correct segment-picker shape prop's @default doc tag
Jul 30, 2026
ec1e704
chore: sync pnpm-lock.yaml with workspace typescript resolution
Jul 30, 2026
2dcb6fd
refactor(ui): drop redundant Partial around WithIcon in ModalProps
Jul 31, 2026
0e0cdd6
fix(docs): include shared prop types in TypeDoc entry points
Jul 31, 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 .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
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/
18 changes: 17 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,12 @@ export default defineConfig({
},
}),
],
customCss: ['./src/styles/custom.css'],
// `@workflowbuilder/ui` styles are safe to load globally: styles.css is
// just the @layer order + one :root var + opt-in `.ax-public-*` typography
// classes (no global reset), 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.
customCss: ['./src/styles/custom.css', '@workflowbuilder/ui/styles.css', '@workflowbuilder/ui/tokens.css'],
components: {
Head: './src/components/head.astro',
Search: './src/components/search.astro',
Expand Down Expand Up @@ -159,6 +166,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",
"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",
"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
68 changes: 68 additions & 0 deletions apps/docs/scripts/check-ui-component-coverage.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Asserts that every entry in packages/ui/vite.config.mts's `componentEntries`
// (the list of publishable subpath bundles) has at least one matching entry
// in generate-ui-api.mjs's `COMPONENTS` (the list of docs pages with a
// generated Props / CSS variables table).
//
// Without this guard, a new component can be added to the package's public
// entry points and shipped to npm without ever getting a docs page - nothing
// else in the build fails, the page just silently never exists. TypeDoc's
// strict mode doesn't catch this either: it only checks that exported types
// have doc comments, not that a docs page renders them.
//
// A vite entry counts as covered if COMPONENTS has a `dir` equal to the entry
// name, or nested under it (`${entry}/...`) - entries like `node` bundle
// several flat docs pages (node-icon, node-description, ...) rather than
// mapping 1:1 by name. `NARRATIVE_ONLY` is an escape hatch for a vite entry
// that is deliberately docs-only-by-prose with no generated props table at
// all (none today - kept for the next one, e.g. a future compound component
// documented like NodePanel).
//
// Wired into apps/docs/package.json's `generate:ui-api` script, right after
// the generator runs, so `dev` / `build` / `typecheck` all catch the drift.

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

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 generatorPath = path.resolve(here, 'generate-ui-api.mjs');

const NARRATIVE_ONLY = new Set([]);

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');
return [...match[1].matchAll(/'([^']+)'/g)].map((m) => m[1]);
}

function extractComponentDirectories(source) {
const match = /const COMPONENTS = \[([\s\S]*?)];/.exec(source);
if (!match) throw new Error('Could not find `COMPONENTS` in generate-ui-api.mjs');
return [...match[1].matchAll(/dir:\s*'([^']+)'/g)].map((m) => m[1]);
}

const componentEntries = extractComponentEntries(readFileSync(viteConfigPath, 'utf8'));
const componentDirectories = extractComponentDirectories(readFileSync(generatorPath, 'utf8'));

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

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;
} else {
console.log(`✓ component coverage ok — ${componentEntries.length} vite entries cross-checked.`);
}
Loading