demo/docs: contract-templates use custom SDT styling variables (SD-3322)#3591
Merged
Merged
Conversation
…D-3322) Rewrite the contract-templates demo's SDT styling onto SuperDoc's public --sd-content-controls-custom-* variables (from #3590), proving the new API in the real legal-template use case. The demo now styles its inline fields and block clauses with zero !important and zero internal state selectors (.ProseMirror-selectednode, .sdt-group-hover); the painter applies the variables across rest, hover, selected, and locked-hover. This is the copy-pasteable pattern for styling custom SDTs under chrome:'none'. - style.css: replace the per-state !important rules with one variable-setting rule per tag (inline + block); update the host-owned-styling comment. - test: add state coverage - the custom hover background drives a painted field (and wins over the built-in lock-hover tint), the border stays constant across states (no jitter), and no built-in label/chrome leaks. Demo suite 13/13. - docs (Document API > Content controls): correct the contentLocked wording (it rejects Document API content writes too, not just the editor); document the locked-template pattern (unlock -> write -> relock, incl. a locked parent for nested fields); add the single-use governed clause-library pattern alongside versioned reusable sections (kept - it's a valid pattern). - docs (Custom UI > Content controls): add a "Build a custom field system" walkthrough; describe the demo as a full custom contract-template UI. - README: note the demo styles through the public custom variables. Stacked on #3590 (the painter variable layer); retarget to main once it merges.
There was a problem hiding this comment.
cubic analysis
No issues found across 5 files
Linked issue analysis
Linked issue: SD-3322: feat(ui): first-class custom styling for content controls under chrome:none
| Status | Acceptance criteria | Notes |
|---|---|---|
| ✅ | Demo CSS uses the public --sd-content-controls-custom-* variables instead of per-state !important rules | The demo's style.css replaces per-state rules with --sd-content-controls-custom-inline-* and --sd-content-controls-custom-block-* variables and removes the prior !important overrides. |
| ✅ | Demo contains no consumer !important and does not target internal state classes (.ProseMirror-selectednode, .sdt-group-hover) | All per-state .ProseMirror-selectednode / .sdt-group-hover rules and !important usages were removed; comments and CSS now rely on the public variables. |
| Styled behavior covers rest and hover (and uses variables for selected/locked states) with painter-driven application (no consumer hacks) | The CSS defines hover and selected variables and the new test asserts hover behavior and border stability. However, the diff includes only an explicit automated assertion for hover/rest (not explicit automated checks for selected or locked-state visuals), so coverage for selected/locked states is shown in CSS but not fully exercised by tests in this PR. | |
| ✅ | Works with modules.contentControls.chrome: 'none' (demo scoped to chrome-none environment) | The demo CSS is explicitly scoped under .superdoc-cc-chrome-none and the PR is tested in the demo suite; the PR notes it is stacked on #3590 (painter change) and the test is run against a build that bundles that change, showing the variables drive the painted fields under chrome:'none'. |
| ✅ | Docs and README updated to explain the split and show the demo as the copy-pasteable example | Documentation pages and the demo README were updated to describe using the public custom variables, the demo's pattern, and the locked-template pattern; text changes explicitly call out the demo as a full custom contract-template UI and point to the variables. |
| ✅ | Contract-templates demo rewritten to be the copy-pasteable example (no internal-selector CSS / !important) | The demo CSS, README, and tests were modified to remove internal selectors and !important, and to document the public-variable approach; the PR description and diffs show the demo is now implemented with the public variables. |
Tip: cubic could auto-approve low-risk PRs like this, if it thinks it's safe to merge. Learn more
Re-trigger cubic
Base automatically changed from
caio/sd-3322-content-controls-chrome-none-css-vars
to
main
May 31, 2026 10:03
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rewrites the contract-templates demo's SDT styling onto the public
--sd-content-controls-custom-*variables from #3590, so the demo becomes the copy-pasteable example for styling custom SDTs underchrome:'none'. The demo now has zero!importantand zero internal state selectors (.ProseMirror-selectednode,.sdt-group-hover); SuperDoc applies the variables across rest, hover, selected, and locked-hover, and the box stays constant (no jitter).Stacked on #3590 - this PR's base is the #3590 branch, so the diff is just the demo and docs. Retarget to
mainonce #3590 merges.!importantrules.contentLockedwording (it rejects Document API content writes too -text.setValue/replaceContentreturnLOCK_VIOLATION); document the locked-template pattern (unlock -> write -> relock, including a locked parent for nested fields); add the single-use governed clause-library pattern alongside versioned reusable sections (kept - both are valid).Verified: demo suite 13/13, including a new state-coverage test (the custom hover background drives a painted field and wins over the built-in lock-hover tint, the border stays constant across states, no built-in label leaks), against a freshly built
superdocthat bundles #3590's painter change.