Skip to content

Add @workflowbuilder/ui + ui-tokens packages (1/3: packages) - #44

Open
librowski wants to merge 23 commits into
mainfrom
ui-package
Open

Add @workflowbuilder/ui + ui-tokens packages (1/3: packages)#44
librowski wants to merge 23 commits into
mainfrom
ui-package

Conversation

@librowski

@librowski librowski commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Part 1 of 3. Stacked series for the @workflowbuilder/ui work, split for review:

  1. this PR - add the package (no consumers touched yet)
  2. Migrate consumers to @workflowbuilder/ui (2/3: consumers) #45 - migrate consumers onto it
  3. UI Library docs: page-per-component + source-generated tables (3/3) #42 - UI Library documentation

Summary

Brings the overflow-ui Base UI rewrite into the monorepo as the publishable @workflowbuilder/ui package (+ private @workflowbuilder/ui-tokens). Nothing consumes it yet - sdk / demo / ai-studio still build against the published @synergycodes/overflow-ui@1.0.0-beta.27 on this branch; the switch-over is Part 2. This keeps the (large but mostly vendored) package addition reviewable on its own.

Changes

  • packages/ui + packages/tokens imported from overflow-ui@base-ui-migration, preserving the multi-entry build, the CSS @layer contract (ui.base / ui.component), combine-css-bundle, and the Style-Dictionary token pipeline (tokens.json → CSS). Dropped decision-logs, the overflow-ui.js back-compat shim, dead deps, and the preview app.
  • Aligned with root tooling (eslint / tsconfig extend root), shared deps onto the catalog:, React 18→19, @base-ui/react added to the catalog (pinned 1.4.1).
  • build:ui builds tokens → ui; build:lib chains tokens → ui → sdk. dist builds on pnpm install via prepare.
  • knip.config.js + CLAUDE.md updated to register the two new workspaces.

Verification

  • pnpm install clean; build:lib, build, build:ai-studio green; pnpm -r typecheck green for all workspaces (the only failures are the pre-existing astro check errors in apps/docs/{head,sidebar}.astro, unrelated).
  • Most of the file count is the vendored library (packages/ui/**) - low review effort; the build/tooling wiring is the real surface here.

Notes

  • @workflowbuilder/ui is a second publishable package; the release tag scheme is already migrated on this branch: release-sdk.yml now triggers on @workflowbuilder/sdk@X.Y.Z and the new release-ui.yml on @workflowbuilder/ui@X.Y.Z (documented in CLAUDE.md / packages/sdk/RELEASE.md). Operational note for the maintainer: plain v* tags no longer trigger releases after this merges.
  • No npm publish.

Update (2026-07-31): review fixes + rebase

An agent-assisted review pass (10 dimensions, findings adversarially verified) landed fixes on this branch, and the stack was rebased onto current main (includes #69).

  • CSS @layer contract enforced: 10 stylesheets that shipped unlayered rules are now wrapped (handle.module.css - the WB-190 hazard file, node-as-port.css, radio/edge-label size variants, snackbar sub-components, node-icon/description; typography.cssui.base). check-built-css.ts now also fails the build on any unlayered rule in dist (allowlisted: bare :root custom-property blocks, the documented react-day-picker override, generated token files), so the WB-190 class can't regress silently.
  • Packaging: @phosphor-icons/react externalized (regular dependency) instead of bundled; license: Apache-2.0 + LICENSE file (matching sdk); publishConfig.access: public.
  • Public surface: CollapsibleProps / IconSwitchProps exported; tooltip internals (delay constants, placement hook) moved out of the barrel.
  • packages/tokens brought up to workspace standard: eslint config + lint/typecheck scripts, README, covered by the pr-check ui job; CLAUDE.md workspace tables updated.
  • Removed the orphaned committed apps/docs/src/generated/ui-api.json (it is generated at docs build time by UI Library docs: page-per-component + source-generated tables (3/3) #46's pipeline).

Verification (fresh): pr-check green on this tip; full-stack gates re-run locally 2026-07-30/31 - pnpm -r typecheck, lint, tests (sdk 202 / execution-core 78 / ui 50 / tokens 4), build:lib / build / build:ai-studio / build:docs all green (known pre-existing astro-check errors in apps/docs/{head,sidebar}.astro excluded).


Concrete changes — files this PR had to touch (beyond the bulk vendored copy)

Most of the 198 files are the verbatim vendored library. The list below is the work that is not a straight copy of overflow-ui: the monorepo wiring, and the edits made to the vendored code after import.

A. Wiring into the existing monorepo (pre-existing files modified)

  • pnpm-workspace.yaml (+5) — add @base-ui/react (pinned 1.4.1) + shared deps to the catalog:; register the two new workspaces.
  • package.json (root) — build:ui (tokens→ui) and build:lib (tokens→ui→sdk) chains.
  • knip.config.js (+11) — register packages/ui + packages/tokens.
  • .github/workflows/release-ui.yml (new, +114) — publish workflow for @workflowbuilder/ui@X.Y.Z.
  • .github/workflows/release-sdk.yml (+18) — retrigger on scoped @workflowbuilder/sdk@X.Y.Z (plain v* no longer releases).
  • .github/workflows/pr-check.yml (+55) — new ui job (build + lint + typecheck + tests for ui/tokens).
  • CLAUDE.md (+71), packages/sdk/RELEASE.md (+36) — document the two workspaces + scoped-tag release model.
  • pnpm-lock.yaml (+1178) — lockfile for the new deps.

B. Edits to the vendored overflow-ui code (changed after the bulk import 434f413)

Build / packaging / meta

  • packages/ui/scripts/check-built-css.ts (+183) — the post-build guard. Fails the build on var(var(...)) (the WB-222 wrong-color class) and on any rule outside @layer (the WB-190 port-collapse class), with an allowlist for the intentionally-unlayered React Flow handle overrides, bare :root token blocks, and the react-day-picker override.
  • packages/ui/package.json (+38) — license: Apache-2.0, @base-ui/react moved to a regular dependency, @phosphor-icons/react externalized, publishConfig.access: public.
  • packages/ui/LICENSE (new, +201) — Apache-2.0.
  • packages/ui/vite.config.mts (+22), vitest.config.mts (new), tsconfig.json, lint-staged.config.mjs, combine-css-bundle.mts — align to root tooling + test setup.
  • packages/ui/src/index.ts — barrel gaps: export WithIcon / CollapsibleProps / IconSwitchProps; drop tooltip internals from the public surface.
  • packages/ui/css-layers.md, README.md, CHANGELOG.md — rename "Overflow UI" → @workflowbuilder/ui, 2.0.0 changelog.

Component / CSS fixes (differ from upstream)

  • Wrapped into cascade layers: node/node-panel/handle.module.css (+116, the WB-190 core), node-as-port-wrapper/node-as-port.css, node-description.module.css, node-icon.module.css, edge/edge-label/edge-label-size.module.css, radio-button/radio-size.module.css, snackbar/components/*.module.css, select/select-button/select-button.module.css, styles/typography.css (→ ui.base).
  • date-picker/date-utils.ts (+ spec), date-picker/variables.css — theming + ship react-day-picker styles so the calendar renders.
  • switch/icon-switch/icon-switch.{tsx,module.css}, switch/switch.tsx — uncontrolled icon-swap + Accordion double-toggle fix.
  • menu/placement.ts (+ spec), tooltip/placement.ts (+ spec), tooltip/* — extract + test placement logic; trim tooltip barrel.
  • segment-picker/utils/get-valid-shape.ts (+ spec), item/context tweaks.
  • node-panel.tsx, modal.tsx, snackbar.tsx — minor prop/behavior fixes.
  • Tests added: arrays.spec.ts, date-utils.spec.ts, get-valid-shape.spec.ts, placement specs (Vitest: ui 50).

C. packages/tokens (private token pipeline) brought to workspace standard

  • eslint.config.mjs, lint-staged.config.mjs, vitest.config.mts (new), tsconfig.json, package.json — lint/typecheck/test scripts + CI coverage.
  • src/eject-tokens.ts, generate-css-bundle.ts, constants.ts, to-file-name.spec.ts — small fixes + a test.
  • README.md (new).

librowski-synergy and others added 18 commits July 30, 2026 18:57
- SegmentPicker: type onChange/onSelect/onClick event as React.MouseEvent
  instead of MouseEventHandler (types vs runtime mismatch in public API)
- Modal: apply className and ...rest to the same root element with ref,
  not split across the modal and content divs
- Button: log a clear error for children that match no variant instead of
  silently rendering null
- tokens: drop the swallowing try/catch in ejectTokens so a failed write
  aborts the build instead of feeding empty/stale JSON to the CSS step
- tokens: lift tsconfig lib to es2021 (String.replaceAll)
- add per-package lint-staged configs so in-package tsc runs on commit
- remove empty output.json and stale TODO in src/index.ts
- rebrand vite lib + combine-css plugin names away from Overflow UI
- Shape: replace '' sentinel with explicit 'default'
- Snackbar/NodePanel JSDoc match actual behavior; check-built-css comment
  no longer references a non-existent stylelint rule
- Switch: drop redundant styles prop (keep className)
- Tooltip: inline the constant open/close delays, drop the speculative
  delay context (placement context kept)
- tokens: scope codeChunks to generateCSSBundle; fix double-slash token dir
Set up Vitest in @workflowbuilder/ui (jsdom) and @workflowbuilder/ui-tokens
(node) and wire both into the root pnpm test.

Extract the pure helpers that were buried in component files into sibling,
non-barrel modules so they can be unit-tested without rendering: date-picker
date-utils (parseDateValue/normalizeInitialValue/dayjsTokenToDateFns), and the
menu/tooltip placement mappers. Public types are re-exported so the package API
is unchanged.

Coverage: button structural guards, rangeBetween, getValidShape, the date
parsing/timezone logic, placement->side/align + offset mapping, and toFileName.
50 ui + 4 tokens tests. Exclude specs from the dts build so they don't ship.
- narrow @base-ui/react peer range to ~1.4.0 (1.5/1.6 regressed transitions)
- resolve the bundle-vs-dependency split: date-fns, react-day-picker, clsx and
  Phosphor are bundled into dist, so move them to devDependencies; only the
  external react-textarea-autosize stays a runtime dependency (peers unchanged)
- rewrite npm description/keywords away from the diagram-library boilerplate
- fix the README dev section (real pnpm --filter commands; no preview-page) and
  drop leftover 'Overflow UI' branding
- correct CLAUDE.md: ui-tokens is private (not in changeset ignore)
Retire the single-package v* tag scheme now that the repo publishes two
packages. Each package releases via its own scoped tag and workflow:
- @workflowbuilder/sdk@X.Y.Z -> release-sdk.yml (trigger + version-parse updated)
- @workflowbuilder/ui@X.Y.Z  -> release-ui.yml (new; OIDC trusted publisher,
  provenance, build:ui, version/idempotency checks, GitHub Release)

Add a UI lint/typecheck/test/build job to pr-check. Update RELEASE.md and
CLAUDE.md for the scoped-tag two-package flow and correct the stale changeset
ignore claim. Each package needs its own npm trusted publisher (manual, noted
in RELEASE.md).
ui is the sole consumer of Base UI and is version-locked to 1.4.x (later
versions regressed transitions), so it should own that pinned version rather
than delegate it to every consumer via a peer range. Move @base-ui/react to
dependencies (catalog: -> 1.4.1 at publish); react / react-dom stay peers as
true singletons. Consistent with react-textarea-autosize, the other external.
react-day-picker v9 ships no styles of its own; the component never imported
its stylesheet, so the calendar grid, month caption and nav rendered with
browser defaults (vertical nav, bordered day buttons). Import
react-day-picker/style.css so libInjectCss bundles it into dist (and the docs
combined index.css), giving the calendar its real layout.
react-day-picker ships a default blue accent and no hover state. Re-theme it
to the design tokens: selected days get a filled --ax selected background
instead of the accent ring, today uses a themed accent color, and day buttons
gain a hover background (react-day-picker has none). New tokens:
--ax-public-date-picker-date-{hover-background,selected,today}-color.
react-day-picker paints the prev/next chevrons with --rdp-accent-color, which
defaulted to a raw blue and clashed with the rest of the themed calendar. Paint
them with a neutral nav token instead, and retheme --rdp-accent-color (focus
rings, range endpoints) to the design-token accent so no raw blue remains.
- IconSwitch picked the thumb icon from the controlled `checked` prop, so in
  uncontrolled mode the icon never swapped. Render both icons and swap them via
  the switch's `data-checked` state in CSS (works controlled + uncontrolled).
- Accordion fired `onToggleOpen` twice when the chevron was clicked: the
  Collapsible button's toggle and the header's onClick both ran. The header is
  the single click target now (Collapsible is display-only, controlled via
  isExpanded); also fixed aria-expanded to reflect isExpanded.
- @base-ui/react is a regular dependency now, not a peer (the entry still
  claimed peer); react / react-dom are the only peers.
- document the review-driven breaking changes (Switch styles prop removed,
  Shape '' -> 'default', SegmentPicker event type, Modal prop target) and add a
  Fixed section (calendar styling, Accordion double-fire, IconSwitch, Button).
First release under the @workflowbuilder/ui name, versioned 2.0.0 to sit on the
Workflow Builder 2.x line. Rewrite CHANGELOG.md from scratch: a short note that
the library moved from @synergycodes/overflow-ui (with a link to its old
changelog) plus a single 2.0.0 entry covering the highlights and the migration
deltas. Update the README technology note to match.
…t regressions

Several component stylesheets (node ports, radio buttons, edge labels,
snackbar, node icon/description, base typography) shipped rule bodies
outside the ui.base/ui.component layers, letting unlayered CSS beat
layered CSS regardless of specificity - the same bug class that shipped
collapsed decision-node ports (WB-190).

Extend check-built-css.ts with a second, independent check that fails
the build if any dist CSS rule sits outside an @layer block, with
documented exceptions for :root custom-property blocks, the deliberate
react-day-picker override, and verbatim ui-tokens output.
…ort barrel gaps

- License: Apache-2.0 (was MIT), LICENSE file copied from root and added
  to the published files array, publishConfig.access set to public -
  matches the packages/sdk precedent.
- @phosphor-icons/react moves from devDependencies to a regular
  dependency and joins the Vite externalPackages list, so it's imported
  rather than bundled - same treatment as @base-ui/react.
- Export CollapsibleProps and IconSwitchProps, which were already
  reachable through the barrel but not exported as types.
- Extract tooltip's open/close delay constants and placement context
  into tooltip-context.ts so the barrel export of tooltip.tsx no longer
  leaks internals.
- Fix a stale "Overflow UI" reference in css-layers.md.
packages/tokens had no eslint config, no lint/typecheck scripts, and no
README, and its checks weren't wired into pr-check.yml despite feeding
packages/ui's build. Add the non-React eslint re-export used by
packages/types and packages/execution-core, document the tokens.json ->
Style Dictionary -> --ax-* CSS pipeline, and fold lint/typecheck/test
into the existing UI CI job.
Stale generated artifact from an earlier TypeDoc setup; unreferenced
anywhere in the repo and not produced by the current docs build.
librowski-synergy added 4 commits July 31, 2026 15:56
Replaces the hand-rolled CSS scanner with postcss (already a
devDependency). Also tightens the :root exemption: a top-level :root
block now passes only when every declaration is a custom property.
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.

2 participants