From d1868948cdc2aa9057ab3b6c9e1fffc9bd02927e Mon Sep 17 00:00:00 2001 From: Kevin Segaud Date: Sun, 1 Mar 2026 11:40:11 +0100 Subject: [PATCH] feat: add typed CssBoxSizing property support --- packages/spark_css/CHANGELOG.md | 1 + .../lib/src/css_types/css_box_sizing.dart | 50 +++++++++++++++++++ .../lib/src/css_types/css_types.dart | 1 + packages/spark_css/lib/src/style.dart | 2 + .../spark_css/test/css_box_sizing_test.dart | 24 +++++++++ 5 files changed, 78 insertions(+) create mode 100644 packages/spark_css/lib/src/css_types/css_box_sizing.dart create mode 100644 packages/spark_css/test/css_box_sizing_test.dart diff --git a/packages/spark_css/CHANGELOG.md b/packages/spark_css/CHANGELOG.md index 375602d..32cce2b 100644 --- a/packages/spark_css/CHANGELOG.md +++ b/packages/spark_css/CHANGELOG.md @@ -12,6 +12,7 @@ - **Feat**: Added `CssAnimationDirection`, `CssAnimationFillMode`, `CssAnimationPlayState`, and `CssAnimationIterationCount` sealed classes for animation sub-properties. Reuses existing `CssDuration` and `CssTimingFunction` from `CssTransition`. - **Feat**: Added `CssBorderCollapse` sealed class for `border-collapse` property with `.separate`, `.collapse` keywords, plus `.variable()`, `.raw()`, and `.global()` escape hatches. - **Feat**: Added `border-top-color`, `border-right-color`, `border-bottom-color`, and `border-left-color` CSS property support via `CssColor?` parameters in `Style.typed()`. +- **Feat**: Added `CssBoxSizing` sealed class for `box-sizing` property with `.contentBox`, `.borderBox` keywords, plus `.variable()`, `.raw()`, and `.global()` escape hatches. ### Changed diff --git a/packages/spark_css/lib/src/css_types/css_box_sizing.dart b/packages/spark_css/lib/src/css_types/css_box_sizing.dart new file mode 100644 index 0000000..2b02854 --- /dev/null +++ b/packages/spark_css/lib/src/css_types/css_box_sizing.dart @@ -0,0 +1,50 @@ +import 'css_value.dart'; + +/// CSS box-sizing property values. +sealed class CssBoxSizing implements CssValue { + const CssBoxSizing._(); + + static const CssBoxSizing contentBox = _CssBoxSizingKeyword('content-box'); + static const CssBoxSizing borderBox = _CssBoxSizingKeyword('border-box'); + + /// CSS variable reference. + factory CssBoxSizing.variable(String varName) = _CssBoxSizingVariable; + + /// Raw CSS value escape hatch. + factory CssBoxSizing.raw(String value) = _CssBoxSizingRaw; + + /// Global keyword (inherit, initial, unset, revert). + factory CssBoxSizing.global(CssGlobal global) = _CssBoxSizingGlobal; +} + +final class _CssBoxSizingKeyword extends CssBoxSizing { + final String keyword; + const _CssBoxSizingKeyword(this.keyword) : super._(); + + @override + String toCss() => keyword; +} + +final class _CssBoxSizingVariable extends CssBoxSizing { + final String varName; + const _CssBoxSizingVariable(this.varName) : super._(); + + @override + String toCss() => 'var(--$varName)'; +} + +final class _CssBoxSizingRaw extends CssBoxSizing { + final String value; + const _CssBoxSizingRaw(this.value) : super._(); + + @override + String toCss() => value; +} + +final class _CssBoxSizingGlobal extends CssBoxSizing { + final CssGlobal global; + const _CssBoxSizingGlobal(this.global) : super._(); + + @override + String toCss() => global.toCss(); +} diff --git a/packages/spark_css/lib/src/css_types/css_types.dart b/packages/spark_css/lib/src/css_types/css_types.dart index c6a9ef2..51eb763 100644 --- a/packages/spark_css/lib/src/css_types/css_types.dart +++ b/packages/spark_css/lib/src/css_types/css_types.dart @@ -15,6 +15,7 @@ export 'css_border.dart'; export 'css_border_collapse.dart'; export 'css_border_radius.dart'; export 'css_box_shadow.dart'; +export 'css_box_sizing.dart'; export 'css_color.dart'; export 'css_cursor.dart'; export 'css_display.dart'; diff --git a/packages/spark_css/lib/src/style.dart b/packages/spark_css/lib/src/style.dart index eb539c0..0f41291 100644 --- a/packages/spark_css/lib/src/style.dart +++ b/packages/spark_css/lib/src/style.dart @@ -306,6 +306,7 @@ class Style implements CssStyle { CssZIndex? zIndex, CssCursor? cursor, CssBoxShadow? boxShadow, + CssBoxSizing? boxSizing, CssFilter? filter, CssFilter? backdropFilter, // Backgrounds @@ -448,6 +449,7 @@ class Style implements CssStyle { if (zIndex != null) _properties['z-index'] = zIndex.toCss(); if (cursor != null) _properties['cursor'] = cursor.toCss(); if (boxShadow != null) _properties['box-shadow'] = boxShadow.toCss(); + if (boxSizing != null) _properties['box-sizing'] = boxSizing.toCss(); if (filter != null) _properties['filter'] = filter.toCss(); if (backdropFilter != null) { _properties['backdrop-filter'] = backdropFilter.toCss(); diff --git a/packages/spark_css/test/css_box_sizing_test.dart b/packages/spark_css/test/css_box_sizing_test.dart new file mode 100644 index 0000000..c63dd65 --- /dev/null +++ b/packages/spark_css/test/css_box_sizing_test.dart @@ -0,0 +1,24 @@ +import 'package:spark_css/spark_css.dart'; +import 'package:test/test.dart'; + +void main() { + group('CssBoxSizing', () { + test('keywords output correct CSS', () { + expect(CssBoxSizing.contentBox.toCss(), equals('content-box')); + expect(CssBoxSizing.borderBox.toCss(), equals('border-box')); + }); + test('variable outputs correct CSS', () { + expect(CssBoxSizing.variable('bs').toCss(), equals('var(--bs)')); + }); + test('raw outputs value as-is', () { + expect(CssBoxSizing.raw('border-box').toCss(), equals('border-box')); + }); + test('global outputs correct CSS', () { + expect(CssBoxSizing.global(CssGlobal.inherit).toCss(), equals('inherit')); + }); + test('Style.typed integration', () { + final style = Style.typed(boxSizing: CssBoxSizing.borderBox); + expect(style.toCss(), contains('box-sizing: border-box;')); + }); + }); +}