From 95d34923c426017ec11dceab4dcd7433309fa678 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Tue, 19 May 2026 10:34:22 -0300 Subject: [PATCH] feat: default block alignment to centerLeft Blocks (@block, @widget, @image, and custom widgets) now render with centerLeft alignment when `align` is not set explicitly, instead of center. Paragraph-like content is easier to read and scan when left-aligned. Set `align: center` explicitly to restore the previous default. Closes #65 Co-Authored-By: Claude Opus 4.7 --- docs/reference/block-types.mdx | 5 ++- docs/reference/markdown-syntax.mdx | 2 +- packages/core/lib/src/deck/block_model.dart | 8 +++++ .../core/test/src/deck/block_model_test.dart | 36 +++++++++++++++++++ .../lib/src/builtins/image_widget.dart | 4 +-- .../src/rendering/blocks/block_widget.dart | 4 +-- .../test/src/rendering/block_widget_test.dart | 17 +++++++++ 7 files changed, 70 insertions(+), 6 deletions(-) diff --git a/docs/reference/block-types.mdx b/docs/reference/block-types.mdx index ad20c238..c2dd66fb 100644 --- a/docs/reference/block-types.mdx +++ b/docs/reference/block-types.mdx @@ -13,13 +13,16 @@ Content and widget blocks support these properties. Sections support `align` and `flex`, but scrolling is configured on child blocks or widgets. ### `align` -**Type:** String | **Default:** `center` +**Type:** String | **Default:** `centerLeft` Controls content alignment: - `topLeft`, `topCenter`, `topRight` - `centerLeft`, `center`, `centerRight` - `bottomLeft`, `bottomCenter`, `bottomRight` +Blocks default to `centerLeft` because paragraph-like content reads better +left-aligned. Set `align: center` explicitly for titles or short callouts. + ### `flex` **Type:** Number | **Default:** `1` diff --git a/docs/reference/markdown-syntax.mdx b/docs/reference/markdown-syntax.mdx index 49919602..6f7a8015 100644 --- a/docs/reference/markdown-syntax.mdx +++ b/docs/reference/markdown-syntax.mdx @@ -51,7 +51,7 @@ Built-in widgets (`image`, `dartpad`, `qrcode`) use the same widget syntax as `@ ### `align` - Type: string -- Default: `center` +- Default: `centerLeft` - Values: `topLeft`, `topCenter`, `topRight`, `centerLeft`, `center`, `centerRight`, `bottomLeft`, `bottomCenter`, `bottomRight` ### `scrollable` diff --git a/packages/core/lib/src/deck/block_model.dart b/packages/core/lib/src/deck/block_model.dart index 62db197c..61b0b5a8 100644 --- a/packages/core/lib/src/deck/block_model.dart +++ b/packages/core/lib/src/deck/block_model.dart @@ -48,6 +48,14 @@ sealed class Block with BlockMappable { ); static final fromMap = BlockMapper.fromMap; + + /// The effective alignment for this block. + /// + /// When [align] is not set explicitly, defaults to + /// [ContentAlignment.centerLeft] because paragraph-like content is easier + /// to read and scan when left-aligned. Set `align: center` explicitly to + /// restore the previous default. + ContentAlignment get resolvedAlign => align ?? ContentAlignment.centerLeft; } /// A section that contains multiple child blocks arranged horizontally. diff --git a/packages/core/test/src/deck/block_model_test.dart b/packages/core/test/src/deck/block_model_test.dart index b85f8206..61ca79d4 100644 --- a/packages/core/test/src/deck/block_model_test.dart +++ b/packages/core/test/src/deck/block_model_test.dart @@ -287,6 +287,24 @@ void main() { expect(block.scrollable, true); }); + group('resolvedAlign', () { + test('defaults to centerLeft when align is not set', () { + final block = ContentBlock('Content'); + + expect(block.align, isNull); + expect(block.resolvedAlign, ContentAlignment.centerLeft); + }); + + test('uses explicit align when set', () { + final block = ContentBlock( + 'Content', + align: ContentAlignment.center, + ); + + expect(block.resolvedAlign, ContentAlignment.center); + }); + }); + group('copyWith', () { test('copies with new content', () { final original = ContentBlock('Original'); @@ -730,6 +748,24 @@ void main() { }); }); + group('resolvedAlign', () { + test('defaults to centerLeft when align is not set', () { + final widget = WidgetBlock(name: 'Test'); + + expect(widget.align, isNull); + expect(widget.resolvedAlign, ContentAlignment.centerLeft); + }); + + test('uses explicit align when set', () { + final widget = WidgetBlock( + name: 'Test', + align: ContentAlignment.topRight, + ); + + expect(widget.resolvedAlign, ContentAlignment.topRight); + }); + }); + group('copyWith', () { test('copies with new name', () { final original = WidgetBlock(name: 'Original'); diff --git a/packages/superdeck/lib/src/builtins/image_widget.dart b/packages/superdeck/lib/src/builtins/image_widget.dart index d1c4ad48..65980fe1 100644 --- a/packages/superdeck/lib/src/builtins/image_widget.dart +++ b/packages/superdeck/lib/src/builtins/image_widget.dart @@ -119,7 +119,7 @@ class ImageWidget extends StatelessWidget { styleSpec: StyleSpec( spec: spec.image.spec.copyWith( fit: _data.fit.toBoxFit, - alignment: alignment?.toAlignment ?? Alignment.center, + alignment: alignment?.toAlignment ?? Alignment.centerLeft, ), ), ); @@ -129,7 +129,7 @@ class ImageWidget extends StatelessWidget { : image; return Align( - alignment: alignment?.toAlignment ?? Alignment.center, + alignment: alignment?.toAlignment ?? Alignment.centerLeft, child: constrained, ); } diff --git a/packages/superdeck/lib/src/rendering/blocks/block_widget.dart b/packages/superdeck/lib/src/rendering/blocks/block_widget.dart index 69ca4471..4e4c831f 100644 --- a/packages/superdeck/lib/src/rendering/blocks/block_widget.dart +++ b/packages/superdeck/lib/src/rendering/blocks/block_widget.dart @@ -62,9 +62,9 @@ class _BlockContainerState extends State<_BlockContainer> { child: content, ); - // Apply alignment + // Apply alignment, falling back to the block's default when unset. content = Align( - alignment: widget.block.align?.toAlignment ?? Alignment.center, + alignment: widget.block.resolvedAlign.toAlignment, child: content, ); diff --git a/packages/superdeck/test/src/rendering/block_widget_test.dart b/packages/superdeck/test/src/rendering/block_widget_test.dart index 1ab3f418..86062aa0 100644 --- a/packages/superdeck/test/src/rendering/block_widget_test.dart +++ b/packages/superdeck/test/src/rendering/block_widget_test.dart @@ -52,6 +52,23 @@ void main() { tester.expectBlockCount(9); expect(tester.takeException(), isNull); }); + + testWidgets('block without explicit align defaults to centerLeft', ( + tester, + ) async { + await SlideTestHarness.pumpSlide( + tester, + Slide( + key: 'default-align', + sections: [ + SectionBlock([ContentBlock('# No explicit align')]), + ], + ), + ); + + final align = tester.widget(find.byType(Align).first); + expect(align.alignment, Alignment.centerLeft); + }); }); group('scrollable behavior', () {