Skip to content

Move the image block and inner container styles to styles/content.css (#199 A3) - #205

Open
sneridagh wants to merge 5 commits into
a2-content-css-entry-pointfrom
a3-content-css-pilot
Open

sneridagh wants to merge 5 commits into
a2-content-css-entry-pointfrom
a3-content-css-pilot

Conversation

@sneridagh

@sneridagh sneridagh commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Step A3 of #199: the pilot. The first real block styles go through the styles/content.css entry point from A2, end to end, for one Plate concern and one Plone block.

Stacked on #204 (A2), which is stacked on #203 (A1). The base is a2-content-css-entry-point. This PR's own change is only the last commit.

Changes

  • @plone/plate:
    • .block-inner-container moves into a new styles/content.css, wrapped in :where(). The duplicated rules in styles/publicui.css and styles/cmsui.css are removed. Those two files stay, because the registry needs them to emit plate's Tailwind @source.
    • plone-block-adapter.tsx drops the selection outline of a floated image block with Tailwind variants ([&.block-image[data-style-align=left]]:outline-none). The selection outline is an editor affordance, so the rule that hides it belongs with the selection utilities, in the utilities layer. Before, the CSS Module did it with an unlayered rule.
  • @plone/blocks:
    • No more CSS Module: Image/ImageBlock.module.css is replaced by styles/content.css, with plain classnames and every selector inside :where().
    • The "intentionally unlayered" workaround is gone. The rules now sit in plone-content, above the reset.
    • Link class: the link around a linked image gets block-image__link, the Track B (Remove Tailwind from block content in @plone/plate and @plone/blocks #200) contract name. The figure keeps image-block until Track B renames it.
    • Bottom spacing while floated is expressed as --block-bottom-spacing: 0 on the floated block, the token @plone/layout's content-area.css reads. A plain padding-bottom in plone-content would lose to content-area.css in custom.
    • vitest now excludes acceptance/**, as in plate and cmsui. This is the package's first acceptance folder.
  • @plone/cmsui: the block editor gets the content-area class, the same content root as the Public UI. Themes declare content tokens on .content-area, and they now reach the editor's blocks without touching the CMS chrome. plate's discussion popover already looked up .content-area for its collision padding; it now finds it in the editor too.
  • @plone/agave: a first styles/content.css, declaring --block-float-max-size: 66% on .content-area. That's the same value as the framework fallback, so nothing changes visually. It's the theme's content-token entry point, and the test below uses it to prove the token reaches both UIs.

Proofs (#199 A3 criteria)

Criterion How Result
Zero visual diff Full visual suite, pixel-exact (CI=1 --retries=0), against reference screenshots generated from the pre-change build 22/22 identical, including 2 new image block screenshots
Theme token reaches the block in both UIs blocks/acceptance/tests/image-block-content-css.test.ts: --block-float-max-size on .image-block is 66% in the public view and the editor. The framework only reads it with a fallback, so the value can only come from Agave's content.css ✅
CMS chrome unaffected by theme content tokens The chrome screenshots from #202 are unchanged ✅
Works under any public theme reset Same test file: image block geometry (relative to its inner container), float, margin and the img display match for (1) Agave's Tailwind preflight, (2) no reset (all rules in the base layer removed), (3) a different reset in base. A plain <figure> confirms which reset is active in each case ✅

New visual tests

blocks/acceptance/visual/image-block.test.ts covers the image block floated left (with text and a list after it), floated right, and centered with a link, in the public view (full page) and in the editor (floated image selected, outline hidden).

Baselines: these two tests are new. Run "Update VRT Screenshots" with grep set to Image block alignments, so only they're added. They capture the current look, since this PR has zero diff.

Things to look at

  1. justify-items drift is left alone. The Public UI's copy had justify-items: start; the CMS copy didn't. Unifying them in the editor changed it visibly: nested blocks such as quoted paragraphs shrank, and the list after a floated image stopped wrapping. The Public UI doesn't need plate's copy, because content-area.css sets justify-items on every inner container. So it's dropped, and both UIs keep their current behavior. Moving content-area.css into the shared content styles is Remove Tailwind from block content in @plone/plate and @plone/blocks #200 Phase 1, which will unify this with listed diffs.
  2. Existing view/edit drift is now visible in the screenshots: in the public view, the list after a floated image doesn't wrap beside it, while in the editor it does. That's current behavior, unchanged here, for the same Phase 1.
  3. Exception to the authoring rule "framework CSS reads custom properties and never declares them": --block-bottom-spacing: 0 is declared on floated image blocks, inside :where(), so any theme rule still overrides it.
  4. Agave's neutral token: it's mainly there as the theme's entry point and the test anchor. Moving Agave's real block styling (title, headings, listing, currently public-only in publicui.css → custom) into content.css would change how the editor looks, so it's left for Track B.

A flaky test, fixed on main

cmsui/acceptance/tests/image-block-style-fields.test.ts › "combinations set in the editor render correctly after saving" started failing intermittently on this branch (about 4 in 5 runs). Right after a page load, React replaced the image block's server-rendered nodes, and the test measured the detached ones (0/0 = NaN).

The replacement wasn't caused by this PR: it happened on every load on main too, and this PR only changed the timing. The cause was the server not loading the translations, so React discarded the whole server-rendered page on hydration. That's fixed in #207, which is now merged into this branch, and widthRatio() is back to measuring once, as on main. With that, the style fields and hydration tests passed 80/80 with --repeat-each=8, and the full pnpm acceptance-test suite passed (168).

Validation

  • CI=1 pnpm visual-test --retries=0: 22 passed, pixel-exact against the pre-change reference.
  • pnpm acceptance-test: 166 passed. The image-block-style-fields tests also passed 48/48 with --repeat-each=6.
  • Unit tests: @plone/plate 74, @plone/blocks 29, @plone/cmsui 189, all passed.
  • check:ts for plate, blocks and cmsui: clean. stylelint, eslint and prettier on changed files: clean.

Part of #199.

Step A3 of #199, the pilot for the content CSS architecture. The image
block drops its CSS Module and the block inner container its duplicated
Public UI and CMSUI rules: both now live in styles/content.css, loaded in
both user interfaces inside the plone-content cascade layer. The editor
gets the .content-area content root, and Agave ships its first content
token. Acceptance tests prove that a theme token reaches the image block
in both user interfaces and that its layout doesn't depend on the
public theme's reset.
A centered image right after a float is pushed below it by an amount
that depends on how tall the text next to the float is, which varies with
the fonts installed. The test page now puts the floated image last.
* a2-content-css-entry-point:
  Fix the server not loading translations, which broke hydration (#207)
The retry worked around React replacing the server-rendered DOM on
hydration. #207 fixed the cause (the server didn't load the
translations), so the nodes now stay connected.
* a2-content-css-entry-point:
  Move the table drag handle fragment to @plone/quanta
  Releasing @plone/aurora 1.0.0-alpha.16
  Release @plone/contents 1.0.0-alpha.3
  Release @plone/publicui 1.0.0-alpha.8
  Release @plone/cmsui 1.0.0-alpha.11
  Release @plone/agave 1.0.0-alpha.8
  Release @plone/theming 1.0.0-alpha.8
  Release @plone/layout 1.0.0-alpha.13
  Release @plone/blocks 1.0.0-alpha.17
  Release @plone/plate 1.0.0-alpha.22
  Release @plone/react-router 2.0.0-alpha.7
  Release @plone/helpers 2.0.0-alpha.9
  Release @plone/registry 4.0.0-alpha.4
  Release @plone/quanta 1.0.0-alpha.1
  Release @plone/components 5.0.0-alpha.5
  Release @plone/client 2.0.0-alpha.8
  Release @plone/icons 1.0.0-alpha.1
  Release @plone/types 3.0.0-alpha.7
  Split Quanta and icons out of @plone/components into @plone/quanta and @plone/icons (#212)
@sneridagh

Copy link
Copy Markdown
Member Author

LGTM!

This branch has not been deployed

No deployments
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.

1 participant