Skip to content

feat: add predictable layout primitives#99

Merged
leoafarias merged 13 commits into
mainfrom
feat/predictable-layout-primitives
Jul 13, 2026
Merged

feat: add predictable layout primitives#99
leoafarias merged 13 commits into
mainfrom
feat/predictable-layout-primitives

Conversation

@leoafarias

@leoafarias leoafarias commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a complete set of predictable layout primitives to slides.md — section spacing, block margin and padding, alignment inheritance, image paint scaling, and debug overflow diagnostics — and constrains the framework-owned block container to a new modifier-free BlockStyler. Authors get polished layouts in Markdown; the style API can no longer express competing geometry owners.

Changes and impact

  • Section spacing: @section spacing adds finite, non-negative gaps only between sibling blocks and clamps oversized gaps to the available width. Spacing owns sibling gutters.
  • Block margin and padding: content and widget blocks accept scalar, symmetric, or physical-edge margin and padding. Margin is consumed inside a block's allocated frame, outside its decoration; padding sits between the decoration and content. Overrides replace only the matching resolved inset after style variants resolve, preserving decoration, foreground decoration, clipping, and animation. Absent means inherit; explicit zero removes the inset. Both keys are reserved block metadata and never reach widget args. Margin never changes section spacing or flex ratios.
  • Constrained BlockStyler: SlideStyle.blockContainer now takes BlockStyler (resolving to Mix BoxSpec) exposing only padding, margin, decoration, foreground decoration, clip behavior, context/BlockVariant variants, and animation. Widget modifiers, constraints, transforms, and box alignment are unrepresentable — StyleSpec.widgetModifiers is always null for block containers.
  • Authoring vs. contract split: Markdown shorthand normalizes through explicit authoring parsers (Block.parseAuthoring, BlockInsets.parseAuthoring with exact field/edge errors); compiled contracts accept only closed four-edge top/right/bottom/left objects and reject shorthand. The exported JSON schema reflects the normalized contract.
  • Canonical nested directive formatting: the serializer emits scalar options inline and nested maps as multiline flow mappings with required commas, one key per line, physical edges in clockwise order. Output is idempotent, and arbitrary widget-arg maps/lists/quoted strings round-trip exactly.
  • Playground schema dedup: the AI generation schema derives its slide portion from the new core aiSlideSchema projection (flattened for structured-output adapters); the copied block/section/alignment/flex schemas and their generated types are deleted. Sanitization preserves spacing, padding, and margin and feeds normalized data through the canonical parser.
  • Alignment inheritance: effective alignment is block -> section -> centerLeft, reaching built-in and custom block rendering.
  • Image scaling and numeric args: @image scale paints inside an aligned, clipped frame without changing flex geometry; width, height, and scale accept integers or doubles through one finite-positive rule (width: 300, scale: 1).
  • Overflow diagnostics: debug mode outlines the overflowing frame (no filled corner square obscuring aligned content) and deduplicates size/axis logs per block.
  • Stricter flex contract: section and block flex values must be positive integers everywhere, so invalid layout geometry fails early.

Authoring example

@section {
  spacing: 32
  align: center
}

@block {
  flex: 2
  margin: { 
    top: 8,
    right: 12,
    bottom: 8,
    left: 12,
  }
  padding: {
    horizontal: 48,
    vertical: 24,
  }
}

## Product story

@image {
  src: assets/concepta-icon.png
  flex: 1
  width: 300
  height: 300
  scale: 1.25
  padding: 0
}

The inner braces are YAML flow mappings, so multiline entries require commas. Scalar shorthand stays inline (@block { padding: 16 }).

Compatibility

This is an intentional hard break with no compatibility shims:

  • SlideStyle.blockContainer changes from BoxStyler? to BlockStyler?; block-container modifiers are no longer expressible.
  • Compiled contracts must be rebuilt: padding/margin are normalized four-edge objects only.
  • Non-positive flex values are rejected; section alignment affects children without explicit block alignment; margin joins the reserved widget-arg keys.

Validation

  • melos run build_runner:build, contracts:export, contracts:check — clean, no drift on second run
  • melos run analyze:dart (dart analyze --fatal-infos) — clean across all packages
  • melos run test — all packages pass, including new contract, formatter, BlockStyler, margin rendering, image numeric, Playground parity, and overflow regression tests
  • Slide goldens reviewed and stable; demo contracts rebuilt; demo layout matrix integration test passes on macOS
  • DCM unused-code/unused-files gates could not run locally (no DCM license in this environment); rely on CI for that gate

@docs-page

docs-page Bot commented Jul 11, 2026

Copy link
Copy Markdown

To preview the documentation for this pull request, visit the following URL:

docs.page/btwld/superdeck~99

Documentation is deployed and generated using docs.page

@leoafarias leoafarias marked this pull request as ready for review July 11, 2026 15:09
@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown

Visit the preview URL for this PR (updated for commit 4881c97):

https://superdeck-dev--pr99-feat-predictable-lay-0iwgkttd.web.app

(expires Wed, 12 Aug 2026 23:34:41 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: bd68fc230762285849207e7e120aaf87cd4ca2f9

Replace SlideStyle.blockContainer's BoxStyler with a constrained,
modifier-free BlockStyler; add first-class block margin beside padding
across authoring, models, contracts, serializer, rendering, docs, and
demo; split inset authoring from the normalized compiled contract;
canonicalize nested directive formatting; derive the Playground AI
slide schema from the core contract; normalize image numeric args; and
make the debug overflow indicator a non-obscuring frame outline.
The integration-test TestApp harness hardcodes its own deck styles map,
which drifted from lib/main.dart when the boxed style was added. Loading
the real demo deck in startup_test then threw "Unknown style boxed"
inside the slides computed, surfacing as a SignalEffectException from
DeckSessionState and failing the Integration Tests CI job.

Register boxedStyle() in the harness so it resolves every style used in
slides.md.
Extend the layout showcase deck from 11 to 13 slides with frame-size
and treatment-matrix examples, document spacing controls, and add
block margin to the panel style.
Adopt the generated Mix styling layer while retaining BlockStyler's constrained API, render-boundary sanitization, and the branch's layout showcase changes.
@leoafarias leoafarias merged commit c1afbb7 into main Jul 13, 2026
6 checks passed
@leoafarias leoafarias deleted the feat/predictable-layout-primitives branch July 13, 2026 23:38
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