Commit 529c500
feat: theming with css variables (#2386)
* feat: css vars theming
* fix: add backward compat aliases, fix hardcoded values, add theming docs (#2441)
* fix: add backward compat aliases, fix hardcoded values, add theming docs
- Add compat.css with aliases mapping old CSS variable names to new ones
(prevents breaking change for customers using --sd-comment-*, --sd-track-*, etc.)
- Fix hardcoded #ffffff in CommentDialog.vue input backgrounds (use token)
- Fix hardcoded #dbdbdb in CommentHeader.vue hover (use token)
- Add --sd-ui-comments-panel-input-background token to variables.css and neon-night theme
- Extract cssToken() helper in renderer.ts to eliminate fallback duplication
- Simplify applyDevTheme() to single template literal
- Add theming overview page (getting-started/theming.mdx)
- Add custom themes guide with full per-component variable reference
- Add CSS variable migration guide with old-to-new mapping table
* fix: wire CSS variable cascade so semantic tier changes propagate to all components
Component-specific variables (dropdown, context menu, comments panel,
content controls, layout) now reference semantic-tier variables instead
of hardcoding hex values. This means setting --sd-ui-surface, --sd-ui-text,
--sd-ui-border, --sd-ui-action, and --sd-ui-font-family cascades through
every component automatically.
Shadows and intentional deviations (tooltip inverse palette, comment card
tint, highlight colors) remain component-specific.
* refactor: rename CSS variables for consistency and DX
Standardize naming convention across all CSS variables:
- surface/background → bg (consistent property naming)
- context-menu → menu (shorter, no disambiguation needed)
- comments-panel → comments (drop redundant -panel-)
- State placement: standardize to {state}-{property} pattern
(e.g., dropdown-hover-bg not dropdown-surface-hover)
Average variable name length drops from ~42 to ~28 chars.
62 variables renamed across 29 files. Backward compat aliases
in compat.css already point old (pre-PR) names to new names.
* docs: rewrite theming docs to match CLAUDE.md voice and style guidelines
- Sentence case headings throughout
- Developer register: show code first, explain after
- "You" framing, short sentences, no buzzwords
- Getting Started page is high-level overview, links to detail
- Custom themes guide: resolved default values (not var() refs),
"inherits X" for cascading vars, scannable tables
- Migration guide: tighter tables, less prose
- Remove Tips/Warnings from Getting Started page per page depth rules
* fix: add tokens to link popover and comment action buttons
- LinkInput: title text, input icon, high-contrast mode, and submit
button now use --sd-ui-* tokens instead of hardcoded colors
- CommentDialog: reply button text and cancel button use tokens
* test: add tests for cssToken helper and compat alias integrity
- Extract cssToken() to css-token.ts for testability
- Test that cssToken builds correct var() strings with synced fallbacks
- Test that every compat alias points to a variable defined in variables.css
- Test that compat doesn't re-declare any variable from variables.css
- Test key old→new mappings (comment-bg, surface-card, track-insert, etc.)
* fix(docs): theme class must be on <html>, not any wrapper element
Some SuperDoc elements (popovers, dropdowns) are appended to <body>,
so they only inherit CSS variables from <html>.
* fix: make old CSS variable overrides actually work (two-way compat)
The compat aliases were one-way: setting --sd-comment-bg on a wrapper
had no effect because components read --sd-ui-comments-card-bg directly.
Fix: new tokens in variables.css now fall back to old names via var():
--sd-ui-comments-card-bg: var(--sd-comment-bg, #f3f6fd);
CSS resolves var() at computed-value time, so customer overrides of old
names propagate automatically. Setting the new name still works too —
it overrides the whole expression.
compat.css is trimmed to only aliases where the old name maps to a
different concept (no direct fallback possible). All 1:1 renames are
handled by the fallbacks in variables.css.
* docs: update migration guide to reflect two-way compat mechanism
The compat approach changed from one-way aliases in compat.css to var()
fallbacks in variables.css. Updated the explanation and code examples.
* feat: add createTheme() and buildTheme() helpers for JS-based theming
createTheme() takes a typed config object and returns a CSS class name.
Apply it to <html> to theme the entire UI. Maps a small set of high-level
options (colors, font, radius) to the full CSS variable system.
- colors: action, bg, text, border cascade to every component
- Component overrides: toolbar, dropdown, menu, comments, highlights, etc.
- buildTheme() returns { className, css } for SSR
- Style element auto-injected, idempotent on re-call with same name
- Exported from superdoc package: import { createTheme } from 'superdoc'
- 11 unit tests
- Docs updated to lead with createTheme(), CSS variables as advanced option
* Revert "feat: add createTheme() and buildTheme() helpers for JS-based theming"
This reverts commit 2bf71ff.
* feat(theme): add createTheme() and buildTheme() helpers (SD-2255) (#2445)
* feat(theme): add createTheme() and buildTheme() helpers (SD-2255)
Shadcn-inspired JS theming API. Set ~10 semantic color properties and
the entire UI updates. A `vars` escape hatch covers any CSS variable
not in the semantic layer.
API:
createTheme({ colors, font, radius, shadow, vars }) → className
buildTheme(config) → { className, css } (for SSR)
- colors: action, bg, text, border, etc. map to --sd-ui-* variables
- font/radius/shadow: top-level shortcuts
- vars: raw CSS variable overrides for power users
- Style element auto-injected, idempotent on re-call
- Exported from superdoc package
- 17 unit tests
* refactor(theme): extract generateTheme() to eliminate _lastCss side-channel
buildTheme() was reading CSS from a mutable property on createTheme(),
which returned stale data when called with an empty config. Both
functions now call a shared generateTheme() that returns { className, css }
directly. Also extracted injectThemeStyle() for clarity.
* docs: update theming pages with createTheme() as primary API
Theming overview now leads with createTheme() JS helper. CSS variables
moved to "advanced" section. Custom themes guide shows full API options
including the vars escape hatch and a dark theme example.
* feat: ship AGENTS.md with npm package for AI agent discovery
Bun-style approach: agents working in projects that use SuperDoc read
node_modules/superdoc/AGENTS.md and instantly know how to use
createTheme(), configure the editor, and find all CSS variables.
* feat: add theming example and update CLAUDE.md for agent discovery
- Add examples/features/theming/ — React + TypeScript demo with 7 themes
(3 via createTheme(), 3 presets, 1 default). Follows existing example
pattern (comments, track-changes, etc.)
- Add theming section to packages/superdoc/CLAUDE.md — agents working in
the repo or reading node_modules/superdoc/ find createTheme() API,
file pointers, and common vars keys
- Add theming rows to root CLAUDE.md "Where to Look" table
* chore: update lock file
* fix(theme): make buildTheme() pure, document CSP nonce limitation
- buildTheme() no longer injects styles into the DOM. It returns
{ className, css } without side effects, matching its SSR purpose.
- createTheme() JSDoc notes that strict CSP environments should use
buildTheme() + manual injection with a nonce attribute.
- Added test verifying buildTheme does not inject styles.
* fix(examples): fix Laravel and Nuxt smoke test failures
- Laravel: bind artisan serve to 0.0.0.0 so Playwright can reach it
in CI containers (was only listening on 127.0.0.1)
- Nuxt: increase body visibility timeout to 10s and use domcontentloaded
wait strategy (Nuxt hydration briefly hides body during init)
* refactor(theme): convert createTheme to TypeScript
Replace JSDoc types with native TypeScript interfaces (ThemeColors,
ThemeConfig, ThemeResult). Exports typed interfaces for consumers.
Also fix theming example height and restore smoke test assertion.
* test: add consumer type checks for theme exports and preset theme validation (#2469)
* test: add consumer type checks for theme exports and preset theme validation
- Add createTheme/buildTheme imports to consumer-types smoke test
so broken .d.ts exports are caught during CI
- Add preset theme structural validation to compat.test.ts:
verifies all three presets exist and every variable they declare
is defined in variables.css
* fix(test): use constrained generic so type assertions actually fail on mismatch
`type X = never` compiles without error, so the previous assertions
were no-ops. `AssertExtends<false>` violates the `extends true`
constraint and produces a real compile error.
* fix(theme): sanitize theme names and add --sd-ui-action-text variable
- Sanitize `name` in createTheme() to strip characters invalid in CSS
class names (spaces, slashes, etc.) — prevents classList.add() crash
and invalid CSS selectors
- Add `--sd-ui-action-text` variable (default #ffffff) for text on
action-colored buttons. Replaces incorrect use of `--sd-ui-bg` which
produced poor contrast in dark themes
- Add `actionText` to ThemeColors interface and COLORS_TO_VARS mapping
- Update docs variable reference and dark theme example
* docs: add actionText to createTheme() examples
---------
Co-authored-by: Caio Pizzol <97641911+caio-pizzol@users.noreply.github.com>
Co-authored-by: Caio Pizzol <caio@harbourshare.com>1 parent 2e10e26 commit 529c500
62 files changed
Lines changed: 2390 additions & 532 deletions
File tree
- apps/docs
- getting-started
- guides
- general
- migration
- brand
- examples
- features/theming
- src
- getting-started/laravel
- packages
- layout-engine/painters/dom/src
- super-editor/src
- assets/styles
- elements
- extensions
- components
- rulers
- toolbar
- superdoc
- src
- assets/styles
- helpers
- components/CommentsLayer
- core/theme
- dev
- components
- themes
- tests/consumer-types
- skills/superdoc/brand-guidelines
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
70 | 74 | | |
71 | 75 | | |
72 | 76 | | |
| |||
193 | 197 | | |
194 | 198 | | |
195 | 199 | | |
196 | | - | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
197 | 203 | | |
198 | 204 | | |
199 | | - | |
200 | | - | |
201 | | - | |
202 | | - | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
203 | 210 | | |
204 | 211 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
68 | | - | |
| 68 | + | |
| 69 | + | |
69 | 70 | | |
70 | 71 | | |
71 | 72 | | |
| |||
238 | 239 | | |
239 | 240 | | |
240 | 241 | | |
| 242 | + | |
241 | 243 | | |
242 | 244 | | |
243 | 245 | | |
| |||
251 | 253 | | |
252 | 254 | | |
253 | 255 | | |
254 | | - | |
| 256 | + | |
| 257 | + | |
255 | 258 | | |
256 | 259 | | |
257 | 260 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
0 commit comments