@cdx-ui/theme-editor
v0.1.2
Published

Readme
@cdx-ui/theme-editor
A guided, web-only editor for authoring Forge Design System ThemeOverride JSON. Financial institutions choose generative inputs and package-owned semantic selections through Forge UI controls while a live panel previews real Forge UI components. The editor emits FI intent only; consuming apps persist it and apply it at runtime through @cdx-ui/styles.
Web-only. The editor uses browser APIs and React Native Web. It is not available on native platforms.
Installation
pnpm add @cdx-ui/theme-editor @cdx-ui/components @cdx-ui/stylesreact, react-dom, react-native-web, and uniwind are peer dependencies — apps already consuming @cdx-ui/components will have these in place. Declare @cdx-ui/components and @cdx-ui/styles directly when importing their provider and types as shown below; the editor resolves its internal Forge UI dependencies automatically.
Usage
1. Add the editor to your Tailwind sources
The preview renders Forge UI components with Uniwind utility classes. Like the
other @cdx-ui/* packages, this package ships no precompiled CSS or tokens —
its ./styles.css is a Tailwind v4 @source directive that adds the editor's
source to your content scan so the preview's utilities are generated. Import it
in your Tailwind entry stylesheet, alongside the rest of the design system:
@import 'tailwindcss';
@import 'uniwind';
@import '@cdx-ui/styles/theme.css';
@import '@cdx-ui/styles/utilities.css';
@import '@cdx-ui/components/styles.css';
@import '@cdx-ui/theme-editor/styles.css';2. Mount the editor
onChange fires (debounced, ~200ms) after the user edits a control with a valid target
ThemeOverride. It is not called on mount. Persist the payload from onChange; production
consumers apply it once during app startup:
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { ThemeEditor } from '@cdx-ui/theme-editor';
import { ForgeDesignProvider } from '@cdx-ui/components';
import type { ThemeOverride } from '@cdx-ui/styles';
function ThemeConfigPage() {
const handleChange = (override: ThemeOverride) => {
void persistOverride(override); // your save (e.g. POST /api/themes)
};
return (
<SafeAreaProvider>
<ForgeDesignProvider>
<ThemeEditor onChange={handleChange} showGetCode showThemeModeToggle />
</ForgeDesignProvider>
</SafeAreaProvider>
);
}showGetCode opens a Forge UI Dialog. Mount exactly one portal host near the app root:
ForgeDesignProvider includes it automatically and must remain inside the app-owned
SafeAreaProvider. If the app does not use the Forge provider, keep SafeAreaProvider and mount
one PortalHost from @cdx-ui/primitives instead. Do not mount both; without either one, the
dialog opens in state but renders no popup.
The editor parses and expands through @cdx-ui/styles, evaluates shared rules, and drives preview
through a stateful covering session. Clears restore managed baseline values without dumping
unrelated variables. Reload remains the recovery boundary after a physical writer failure.
3. Edit an existing override
Pass a previously saved override as initialValue to enter edit mode; the controls seed from its inputs:
<ThemeEditor initialValue={savedOverride} onChange={handleChange} />Props
| Prop | Type | Default | Description |
| --------------------- | ----------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| onChange | (override: ThemeOverride) => void | — | Required. Called (debounced, ~200ms) after the user edits a control with the current ThemeOverride. Not called on mount or while a color input is invalid. |
| initialValue | unknown | — | Parses a persisted value for edit mode and surfaces invalid or unsupported payload diagnostics. |
| showGetCode | boolean | false | Shows a "Get code" button that opens a Dialog with the override output and a copy-to-clipboard button. |
| showThemeModeToggle | boolean | false | Shows a light/dark toggle that switches the preview surface. |
The ThemeOverride shape and runtime are documented in @cdx-ui/styles.
Behavior notes
- Intent-only output. Untouched preview defaults, derived Base, recipe members, and generated palettes are omitted. Incoming additive unknown fields are preserved.
- Base. Base derives from Brand until explicitly pinned; unpinning removes
basePrimaryintent. - Fonts. Every catalog family is available. Choosing Default clears authored font intent and restores the generated baseline family.
- Rules. Approved structural/source-set errors block output. Provisional visual calibration remains warning-only.
- Live preview. The covering session writes the current sparse intent plus concrete fallback values needed to clear prior managed writes.
- Preview isolation. The preview is wrapped in
ScopedThemeso the light/dark toggle only affects the preview surface, not the editor chrome.
Package structure
theme-editor/
├── src/
│ ├── index.ts # Public exports (ThemeEditor, ThemeEditorProps)
│ ├── styles.css # `@source` directive — published as the ./styles.css export
│ ├── ThemeEditor.tsx # Top-level component: state, debounced apply/emit, Dialog, toggle
│ ├── PreviewPanel.tsx # Live preview surface (ScopedTheme + banking artboard)
│ ├── override/ # Draft provenance, serialization, controls, rules/runtime handoff
│ ├── validation.ts # Hex validation
│ ├── fonts.ts # Exact Google Fonts loading for display/platform families
│ ├── controls/ # FontControl, ColorControl, catalog-driven renderer
│ ├── components/ # ColorPickerInput
│ └── previews/ # Forge UI sample cards rendered in the preview
├── global.css # Tailwind/Uniwind entry for the build (not published)
├── vite.config.ts
└── package.jsonBuilding
pnpm --filter @cdx-ui/theme-editor buildVite bundles src/index.ts to dist/index.js (externalizing React, React Native Web, Uniwind, and the @cdx-ui/* packages); tsc emits declarations. No CSS is emitted — src/styles.css (the @source directive) is published as-is and composes with the consumer's Tailwind build.
Further reading
- Design tokens — how tokens and themes work
@cdx-ui/styles— baseline tokens, overrides, and runtime application- The repository's token-architecture documentation records the override payload contract and the build/runtime boundary.
License
MIT © 2026 Digital First Holdings LLC. The full license text ships in the package as LICENSE.
