From caea1d385d74c78357d69b1ae776d0d5e981b61d Mon Sep 17 00:00:00 2001 From: Kevin Segaud Date: Sun, 1 Mar 2026 11:24:39 +0100 Subject: [PATCH] feat: add typed CssBorderCollapse property support Add CssBorderCollapse sealed class with separate/collapse keywords and standard escape hatches (variable, raw, global). Wire it into Style.typed() as borderCollapse parameter. Closes #67 --- packages/spark_css/CHANGELOG.md | 1 + .../src/css_types/css_border_collapse.dart | 55 +++++++++++++++++++ .../lib/src/css_types/css_types.dart | 1 + packages/spark_css/lib/src/style.dart | 4 ++ .../test/css_border_collapse_test.dart | 27 +++++++++ 5 files changed, 88 insertions(+) create mode 100644 packages/spark_css/lib/src/css_types/css_border_collapse.dart create mode 100644 packages/spark_css/test/css_border_collapse_test.dart diff --git a/packages/spark_css/CHANGELOG.md b/packages/spark_css/CHANGELOG.md index 5df5a0f..dd7fd38 100644 --- a/packages/spark_css/CHANGELOG.md +++ b/packages/spark_css/CHANGELOG.md @@ -10,6 +10,7 @@ - **Feat**: Added `accent-color` CSS property support via `CssColor? accentColor` parameter in `Style.typed()`. - **Feat**: Added `CssAnimation` sealed class for the `animation` shorthand property with `.none`, single animation (name, duration, timingFunction, delay, iterationCount, direction, fillMode, playState), `.multiple()`, plus `.variable()`, `.raw()`, and `.global()` escape hatches. - **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. ### Changed diff --git a/packages/spark_css/lib/src/css_types/css_border_collapse.dart b/packages/spark_css/lib/src/css_types/css_border_collapse.dart new file mode 100644 index 0000000..7817912 --- /dev/null +++ b/packages/spark_css/lib/src/css_types/css_border_collapse.dart @@ -0,0 +1,55 @@ +import 'css_value.dart'; + +/// CSS border-collapse property values. +sealed class CssBorderCollapse implements CssValue { + const CssBorderCollapse._(); + + static const CssBorderCollapse separate = _CssBorderCollapseKeyword( + 'separate', + ); + static const CssBorderCollapse collapse = _CssBorderCollapseKeyword( + 'collapse', + ); + + /// CSS variable reference. + factory CssBorderCollapse.variable(String varName) = + _CssBorderCollapseVariable; + + /// Raw CSS value escape hatch. + factory CssBorderCollapse.raw(String value) = _CssBorderCollapseRaw; + + /// Global keyword (inherit, initial, unset, revert). + factory CssBorderCollapse.global(CssGlobal global) = _CssBorderCollapseGlobal; +} + +final class _CssBorderCollapseKeyword extends CssBorderCollapse { + final String keyword; + const _CssBorderCollapseKeyword(this.keyword) : super._(); + + @override + String toCss() => keyword; +} + +final class _CssBorderCollapseVariable extends CssBorderCollapse { + final String varName; + const _CssBorderCollapseVariable(this.varName) : super._(); + + @override + String toCss() => 'var(--$varName)'; +} + +final class _CssBorderCollapseRaw extends CssBorderCollapse { + final String value; + const _CssBorderCollapseRaw(this.value) : super._(); + + @override + String toCss() => value; +} + +final class _CssBorderCollapseGlobal extends CssBorderCollapse { + final CssGlobal global; + const _CssBorderCollapseGlobal(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 bd5d281..c6a9ef2 100644 --- a/packages/spark_css/lib/src/css_types/css_types.dart +++ b/packages/spark_css/lib/src/css_types/css_types.dart @@ -12,6 +12,7 @@ export 'css_background_position.dart'; export 'css_background_repeat.dart'; export 'css_background_size.dart'; export 'css_border.dart'; +export 'css_border_collapse.dart'; export 'css_border_radius.dart'; export 'css_box_shadow.dart'; export 'css_color.dart'; diff --git a/packages/spark_css/lib/src/style.dart b/packages/spark_css/lib/src/style.dart index d66784f..1da65f6 100644 --- a/packages/spark_css/lib/src/style.dart +++ b/packages/spark_css/lib/src/style.dart @@ -291,6 +291,7 @@ class Style implements CssStyle { CssBorder? borderBottom, CssBorder? borderLeft, CssBorderRadius? borderRadius, + CssBorderCollapse? borderCollapse, CssOutline? outline, CssLength? outlineOffset, // Visual @@ -415,6 +416,9 @@ class Style implements CssStyle { if (borderRadius != null) { _properties['border-radius'] = borderRadius.toCss(); } + if (borderCollapse != null) { + _properties['border-collapse'] = borderCollapse.toCss(); + } if (outline != null) _properties['outline'] = outline.toCss(); if (outlineOffset != null) { _properties['outline-offset'] = outlineOffset.toCss(); diff --git a/packages/spark_css/test/css_border_collapse_test.dart b/packages/spark_css/test/css_border_collapse_test.dart new file mode 100644 index 0000000..e9fa578 --- /dev/null +++ b/packages/spark_css/test/css_border_collapse_test.dart @@ -0,0 +1,27 @@ +import 'package:spark_css/spark_css.dart'; +import 'package:test/test.dart'; + +void main() { + group('CssBorderCollapse', () { + test('keywords output correct CSS', () { + expect(CssBorderCollapse.separate.toCss(), equals('separate')); + expect(CssBorderCollapse.collapse.toCss(), equals('collapse')); + }); + test('variable outputs correct CSS', () { + expect(CssBorderCollapse.variable('bc').toCss(), equals('var(--bc)')); + }); + test('raw outputs value as-is', () { + expect(CssBorderCollapse.raw('collapse').toCss(), equals('collapse')); + }); + test('global outputs correct CSS', () { + expect( + CssBorderCollapse.global(CssGlobal.inherit).toCss(), + equals('inherit'), + ); + }); + test('Style.typed integration', () { + final style = Style.typed(borderCollapse: CssBorderCollapse.collapse); + expect(style.toCss(), contains('border-collapse: collapse;')); + }); + }); +}