Skip to content

Ship the renderer-independent Components 4 foundation - #177

Open
woksin wants to merge 35 commits into
mainfrom
feat/react-aria-foundation
Open

Ship the renderer-independent Components 4 foundation#177
woksin wants to merge 35 commits into
mainfrom
feat/react-aria-foundation

Conversation

@woksin

@woksinwoksin commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Components 3 stabilization shipped first in #169, with the independent pre-major additions in #171 and release recovery in #172. That work is published as @cratis/components@3.5.0, so consumers can take correctness and accessibility fixes without silently receiving a rendering-foundation migration.

This focused Components 4 change replaces the mandatory PrimeReact/PrimeUI foundation with Cratis-owned React markup, public types, behavior, semantic tokens, stable parts, and state attributes. React Aria remains an internal implementation dependency for difficult accessible interactions; semantic native HTML is used where it is simpler and stronger.

The maintained baseline remains deliberately familiar to Components 2/3 users: Lara-adjacent blue actions, neutral light/dark surfaces, 6px radii, comparable control density, and familiar overlays. It differs intentionally where stronger focus, control-boundary, status, disabled-state, or text contrast improves accessibility.

A product design system maps its canonical values directly to --cratis-* and styles documented data-cratis-part / typed pt surfaces. Components no longer places a Prime preset, provider, variable bridge, DOM contract, runtime, or license between the product and its UI.

Applications that still import Prime directly must retain their installed-version Prime provider, styling, dependencies, and licensing obligations around those remaining surfaces. Components 4 does not make direct Prime usage license-free. No Prime compatibility package is published without written licensing/OEM clarification.

This PR is intentionally opened for maintainer and RC review and must remain unmerged until @woksin and @einari approve the public API, baseline appearance, migration guidance, accessibility behavior, and downstream pilot plan.

Migration guide: https://cratis.io/components/migration/

Added

Changed

Removed

  • @cratis/components/styled
  • @cratis/components/compatibility
  • @cratis/components/primereact-v10-palette
  • styledMode, StyledModeOptions, CratisPreset, primeReactStyles, Prime layer/dark-selector constants, and Prime pass-through compatibility/sentinel exports
  • Mandatory PrimeReact/PrimeUI/PrimeIcons package, provider, palette, preset, declaration, and runtime references

Verification

Fresh evidence for the exact final candidate (509cdcf; semantic approval at 7a62e23):

  • Components CI: 262/262 test files, 795/795 tests
  • Lint and TypeScript: passed
  • Published exports: 25/25 loaded
  • Emitted JavaScript/declarations: Prime-free
  • Source maps: every retained reference/map valid; rewritten files publish no dishonest map
  • CSS: prefixed internal utilities, named Cratis layers, no Tailwind Preflight, no token duplication
  • Package notices/assets: Cratis MIT, Allotment MIT, Tailwind MIT, Patrick Hand OFL, and all font binaries verified
  • Storybook production build: passed with accessibility addon
  • Storybook visual QA: baseline light, baseline dark, product-token, and mobile representative screenshots reviewed
  • Automated axe scan over representative foundation surfaces: passed
  • Markdown: 95 files, zero issues
  • AI corpus validation: passed
  • npm exact-artifact consumers: Arc 20.3.1, 21.19.4, 22.1.0 passed
  • pnpm exact-artifact consumer: passed
  • Yarn PnP exact-artifact consumer: passed with the explicit upstream Arc React rxjs package-extension workaround
  • Custom-token design-system representative compile: passed after strict provider typing correctly rejected stale Prime-era provider keys
  • Deeply customized canvas/compositor host representative Dialog/Stepper/Toolbar parts: passed
  • Packed artifact: 404 KB
  • SHA-256: 1d769e97283d4f57ce70aa2a9ce85952d9e96c182d3d045026b2cfe8e0d71fe2

Public type validation:

Consumer status

  • Custom-token design system: representative provider/token/form/date/dropdown/table/filter migration compiles. This archetype is not claimed fully migrated; locale-aware number input remains an intentional bounded Prime island (Add a locale-aware renderer-independent number input #175).
  • Deeply customized canvas/compositor host: representative Dialog, CommandDialog, Stepper, Toolbar, and stable-part usage compiles. Broad direct Prime and local canvas usage make this a staged migration.
  • Components 2/PrimeReact 10 application: the documented direct-to-Components-4 path avoids an unnecessary PrimeReact 11 intermediate migration while direct PrimeReact 10 usage remains bounded.
  • Components 3/PrimeReact 11 multi-entry application with an advanced table adapter: the documented baseline-first coexistence path retains its application-owned advanced table adapter and separate PrimeReact provider during migration.

Follow-up plan

Closes#162
Closes#163
Closes#170

woksin added 30 commits August 23, 2026 02:25
Preserve practical migration aliases and Cratis-owned paginator/filter contracts for deeply customized consumers. Validate the packed artifact across package managers, remove stale Prime Storybook modes, and align the migration documentation with the shipped renderer-independent foundation.
Close the independently identified accessibility, pass-through, SSR hydration, multi-select, documentation, Storybook, packaging, and guidance gaps before exposing the major release for human review.
Apply the repository formatters after the accessibility and migration review changes, and remove the last stale PrimeReact architecture reference from the authoritative corpus.
…ation
# Conflicts:
#	Source/.storybook/main.ts
#	Source/package.json
Connect tooltip behavior to real focusable controls, associate Arc field titles and errors with every command control, make DataPage selection truly typed and controlled, complete pass-through forwarding, and align dialog callbacks and documentation with runtime behavior.
Remove the remaining Prime-specific application recipes, expose DataPage paginator customization, display filtered multi-select values, make breadcrumbs natively keyboard accessible, and align the merged marker specs with stable Cratis parts.
Remove late-merged Prime icon and legacy-token dependencies, make Canvas overlays SSR-safe, block busy dialog dismissal, localize and expose stable filter parts, document Canvas and public part contracts, and verify current Arc 22.1 compatibility.
Exercise the owned dialog and stepper markup directly, update Storybook and toolbar examples to Cratis contracts, preserve selection without a data key by object reference, and broaden DatePicker part attributes without leaking implementation types.
Make the date trigger discoverable by default, align Chips behavior and accessibility, document removed renderer subpaths, expose stable Toolbar parts, clarify React-only renderer independence, and preserve controlled DataPage typing without internal any.
Forward localized search labels, expose integrated Canvas labels and glass surfaces with a safe default, and honor arbitrary Dropdown tab order values with regression coverage.
Remove residual renderer icon and token assumptions, fix PivotViewer token overrides and Chips duplicate/max semantics, ship the bundled font license, complete public part exports, and expand migration guidance for removed APIs plus Ada and Studio.
Add stable Toolbar composition seams, make hidden tools inert, preserve controlled table selection through loaded-page transforms, enforce busy dialog scopes, make PivotViewer SSR-safe and color-reactive, and complete the Arc, Ada, Studio, and public API guidance.
Align the baseline with familiar Lara-era visuals while improving contrast, isolate prefixed no-Preflight styles, add Storybook accessibility and visual matrices, complete consumer migration guidance, harden overlays/SSR/selection/source maps/licensing, and expose product-owned Canvas and Toolbar seams.
Use accessible action pairs for selected controls, complete reduced-motion coverage, make visual stories deterministic and responsive, and add familiar Dropdown hover/pressed states.
Publish the Tailwind MIT notice, enforce it in archive verification, honor reduced motion in standalone event timelines, and keep reduced-motion Toolbar panels unclipped.
Make explicit light schemes override ambient dark without blocking an explicitly dark subtree, add selector regression coverage, and map Ada's scheme-aware elevation tokens.
@woksin

woksin commented Aug 23, 2026

Copy link
Copy Markdown
ContributorAuthor

@woksin@einari — this comment records why this major takes this direction, why now, what was proven, and what we are deliberately not claiming yet.

Why this is not merely a renderer swap

Components 3 placed Cratis application behavior behind PrimeReact runtime, provider configuration, public types, pass-through slots, theme variables, DOM assumptions, and licensing. PrimeUI's published terms explicitly say that an internal wrapper/design system does not remove developer-seat requirements, and SDK/framework-style redistribution is OEM territory requiring separate clarification.

That meant the commercial renderer was not actually an implementation detail. It was an invisible condition of using Arc-bound dialogs, fields, tables, pages, and notifications.

The technical cost matched the licensing cost:

  • renderer types leaked into every product provider and pt contract;
  • products translated their tokens through Prime presets/variables before Components could use them;
  • exact renderer DOM and slot changes made deep consumer customization brittle;
  • accessibility improvements depended on another product's composition/release decisions;
  • consumers with their own design system still installed and licensed a UI kit they were replacing.

We shipped Components 3 stabilization first (#169, #171, #172 → v3.5.0) so correctness and accessibility were not held hostage by this major migration.

The long-lived boundary

Components 4 now owns:

  • React props, events, markup, and product behavior;
  • semantic --cratis-* tokens;
  • typed pt parts;
  • stable data-cratis-part and state attributes;
  • accessibility composition and regression specs;
  • a maintained baseline appearance and Storybook.

React Aria remains internal for focus, overlays, collections, keyboard behavior, and internationalized dates. It is Apache-2.0 and style-free, but its types/classes/DOM are not the consumer contract. Native HTML is used when simpler.

Arc and @cratis/arc.react continue to own command/query state and generated bindings. Components owns visual policy. This avoids moving UI choices into Arc and preserves the right future seam.

Why no TanStack or compatibility package now

TanStack Table is a good headless engine, but current Components tables do not yet need enough grouping/pinning/faceting complexity to justify another abstraction. #109 should extract query/table state into Arc React only after a second renderer or real consumer proves the contract.

A Prime compatibility package is not published without written licensing/OEM clarity. Components 3 is the compatibility line while consumers migrate.

Baseline appearance and styling

The default UI is intentionally familiar to Components 2/3 users rather than looking like an unrelated redesign:

  • Lara-adjacent blue actions and neutral surfaces;
  • familiar 6px radii, control density, overlays, tables, and light/dark depth;
  • default Button remains the expected primary action.

We intentionally differ where exact Lara reproduction would retain weaker contrast or semantics. Actions/statuses, focus rings, control boundaries, disabled state, forced colors, and reduced motion are stronger.

The stylesheet contract is now real rather than aspirational:

  • tokens — semantic seam with conservative light defaults;
  • styles — prefixed internal utilities and layered structure, with no Tailwind Preflight/reset or token duplication;
  • theme — optional explicit/automatic dark/light, forced colors, and subtree behavior.

Products can override unlayered CSS without specificity wars. Mixed Prime products receive explicit Cratis z-index controls while configuring Prime independently.

Consumer evidence

Custom-token design system

A representative custom-token design system maps its canonical tokens directly to --cratis-*, including actions, controls, statuses, elevation, and focus. Strict provider typing caught a stale attempted migration that still passed Prime-era global pt/unstyled/ripple; correcting it produced a passing representative compile.

Its locale-aware Prime InputNumber remains an honest bounded Prime island until #175 supplies proven parity. We do not claim this archetype is fully migrated.

Deeply customized canvas/compositor host

Representative Dialog, CommandDialog, Stepper, Toolbar, and stable-part usage compiles. Stable parts, state attributes, and product-owned compositor markers preserve deep customization without making product vocabulary part of the Components contract.

Broad direct Prime and local canvas usage make this a staged migration, with existing obligations retained while those surfaces remain.

Components 2/PrimeReact 10 application

This archetype can move directly to Components 4 while retaining PrimeReact 10 as a bounded direct-use island. It does not need an intermediate PrimeReact 11 migration.

Components 3/PrimeReact 11 multi-entry application with an advanced table adapter

This archetype can start baseline-first with Components light/dark while retaining its separate PrimeReact 11 provider and application-owned advanced table adapter. Components does not force canvas-specific Toolbar composition onto ordinary page actions or claim that its default table implements advanced server state.

Verification

The exact candidate has:

  • 262 test files / 795 tests passing;
  • 25/25 export subpaths loading;
  • Prime-free emitted JS/declarations;
  • valid source maps and extension-complete ESM;
  • prefixed/no-Preflight CSS gates;
  • complete MIT/OFL notices and asset verification;
  • Storybook production build plus a11y addon and representative light/dark/product/mobile visual review;
  • automated axe foundation scan;
  • npm Arc 20.3.1 / 21.19.4 / 22.1.0, pnpm, and Yarn PnP exact-artifact validation;
  • representative compile evidence for the custom-token design system and deeply customized canvas/compositor host;
  • 404 KB tarball, SHA-256 1d769e97283d4f57ce70aa2a9ce85952d9e96c182d3d045026b2cfe8e0d71fe2.

What remains deliberately open

A future Vue/Svelte frontend should use Arc transport/generated-client contracts and framework-native state/components. We should extract cross-framework contracts only after another implementation proves them, not pre-abstract React details today.

Requested review focus

  1. Public API ergonomics and named behavior versus pt precedence.
  2. Keyboard/focus/SSR/hydration behavior.
  3. Baseline light/dark familiarity and accessibility.
  4. Custom-token ownership and deeply customized canvas/compositor seams.
  5. Arc/Arc React versus Components ownership.
  6. Migration honesty around direct Prime and advanced tables.
  7. Storybook usefulness as the maintained visual contract.

Please treat renderer leakage, inaccessible behavior, undocumented migration edits, misleading compatibility, or a custom-design-system dead end as blockers. This PR should remain unmerged until you are both comfortable with the major and the RC pilot plan.

Resolve links from each source page, validate extensionless routes and anchors, and report site-root/network exclusions instead of silently scanning zero links.
Comment threadDocumentation/verify-local-links.mjs Fixed
Comment threadDocumentation/verify-local-links.mjs Fixed
Replace vulnerable regex sanitization with deterministic Markdown destination and heading parsing, including adversarial self-tests.
@woksin

Copy link
Copy Markdown
ContributorAuthor

Final review update: all latest checks on 3d340d6 are green, including aggregate CodeQL, JavaScript build, 25 exports, Arc 20/21/22, pnpm, Yarn PnP, semver label, Markdown, and the truthful local-link gate (101 docs files / 107 local links / 0 broken). The two earlier CodeQL threads are outdated and resolved after replacing the vulnerable regex/sanitizer with deterministic parsing and adversarial self-tests. No human review has arrived. This major remains intentionally unmerged for @woksin and @einari plus RC-pilot review.

Keep public consumer guidance evidence-based through generic archetypes, remove private product provenance and local paths, and retain only legitimate framework/tooling references.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants

@woksin@github-advanced-security