Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/spark_css/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
- **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.
- **Feat**: Added `CssContent` sealed class for `content` property with `.normal`, `.none` keywords, `.value()` for arbitrary content, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssJustifyItems` sealed class for `justify-items` property with `.normal`, `.stretch`, `.start`, `.end`, `.center`, `.left`, `.right`, `.baseline`, `.firstBaseline`, `.lastBaseline` keywords, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssListStyle` sealed class for `list-style` shorthand property with `.none` keyword, shorthand constructor with optional `type`, `position`, and `image` parameters, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssListStyleType` sealed class with `.disc`, `.circle`, `.square`, `.decimal`, `.none` keywords.
- **Feat**: Added `CssListStylePosition` sealed class with `.inside`, `.outside` keywords.

### Changed

Expand Down
61 changes: 61 additions & 0 deletions packages/spark_css/lib/src/css_types/css_content.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import 'css_value.dart';

/// CSS content property values.
sealed class CssContent implements CssValue {
const CssContent._();

static const CssContent normal = _CssContentKeyword('normal');
static const CssContent none = _CssContentKeyword('none');

/// Arbitrary content value (e.g., `'"Hello"'`).
factory CssContent.value(String value) = _CssContentValue;

/// CSS variable reference.
factory CssContent.variable(String varName) = _CssContentVariable;

/// Raw CSS value escape hatch.
factory CssContent.raw(String value) = _CssContentRaw;

/// Global keyword (inherit, initial, unset, revert).
factory CssContent.global(CssGlobal global) = _CssContentGlobal;
}

final class _CssContentKeyword extends CssContent {
final String keyword;
const _CssContentKeyword(this.keyword) : super._();

@override
String toCss() => keyword;
}

final class _CssContentValue extends CssContent {
final String value;
const _CssContentValue(this.value) : super._();

@override
String toCss() => value;
}

final class _CssContentVariable extends CssContent {
final String varName;
const _CssContentVariable(this.varName) : super._();

@override
String toCss() => 'var(--$varName)';
}

final class _CssContentRaw extends CssContent {
final String value;
const _CssContentRaw(this.value) : super._();

@override
String toCss() => value;
}

final class _CssContentGlobal extends CssContent {
final CssGlobal global;
const _CssContentGlobal(this.global) : super._();

@override
String toCss() => global.toCss();
}
62 changes: 62 additions & 0 deletions packages/spark_css/lib/src/css_types/css_justify_items.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'css_value.dart';

/// CSS justify-items property values.
sealed class CssJustifyItems implements CssValue {
const CssJustifyItems._();

static const CssJustifyItems normal = _CssJustifyItemsKeyword('normal');
static const CssJustifyItems stretch = _CssJustifyItemsKeyword('stretch');
static const CssJustifyItems start = _CssJustifyItemsKeyword('start');
static const CssJustifyItems end = _CssJustifyItemsKeyword('end');
static const CssJustifyItems center = _CssJustifyItemsKeyword('center');
static const CssJustifyItems left = _CssJustifyItemsKeyword('left');
static const CssJustifyItems right = _CssJustifyItemsKeyword('right');
static const CssJustifyItems baseline = _CssJustifyItemsKeyword('baseline');
static const CssJustifyItems firstBaseline = _CssJustifyItemsKeyword(
'first baseline',
);
static const CssJustifyItems lastBaseline = _CssJustifyItemsKeyword(
'last baseline',
);

/// CSS variable reference.
factory CssJustifyItems.variable(String varName) = _CssJustifyItemsVariable;

/// Raw CSS value escape hatch.
factory CssJustifyItems.raw(String value) = _CssJustifyItemsRaw;

/// Global keyword (inherit, initial, unset, revert).
factory CssJustifyItems.global(CssGlobal global) = _CssJustifyItemsGlobal;
}

final class _CssJustifyItemsKeyword extends CssJustifyItems {
final String keyword;
const _CssJustifyItemsKeyword(this.keyword) : super._();

@override
String toCss() => keyword;
}

final class _CssJustifyItemsVariable extends CssJustifyItems {
final String varName;
const _CssJustifyItemsVariable(this.varName) : super._();

@override
String toCss() => 'var(--$varName)';
}

final class _CssJustifyItemsRaw extends CssJustifyItems {
final String value;
const _CssJustifyItemsRaw(this.value) : super._();

@override
String toCss() => value;
}

final class _CssJustifyItemsGlobal extends CssJustifyItems {
final CssGlobal global;
const _CssJustifyItemsGlobal(this.global) : super._();

@override
String toCss() => global.toCss();
}
110 changes: 110 additions & 0 deletions packages/spark_css/lib/src/css_types/css_list_style.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import 'css_value.dart';

/// CSS list-style-type values.
sealed class CssListStyleType implements CssValue {
const CssListStyleType._();

static const CssListStyleType disc = _CssListStyleTypeKeyword('disc');
static const CssListStyleType circle = _CssListStyleTypeKeyword('circle');
static const CssListStyleType square = _CssListStyleTypeKeyword('square');
static const CssListStyleType decimal = _CssListStyleTypeKeyword('decimal');
static const CssListStyleType none = _CssListStyleTypeKeyword('none');
}

final class _CssListStyleTypeKeyword extends CssListStyleType {
final String keyword;
const _CssListStyleTypeKeyword(this.keyword) : super._();

@override
String toCss() => keyword;
}

/// CSS list-style-position values.
sealed class CssListStylePosition implements CssValue {
const CssListStylePosition._();

static const CssListStylePosition inside = _CssListStylePositionKeyword(
'inside',
);
static const CssListStylePosition outside = _CssListStylePositionKeyword(
'outside',
);
}

final class _CssListStylePositionKeyword extends CssListStylePosition {
final String keyword;
const _CssListStylePositionKeyword(this.keyword) : super._();

@override
String toCss() => keyword;
}

/// CSS list-style shorthand property values.
sealed class CssListStyle implements CssValue {
const CssListStyle._();

static const CssListStyle none = _CssListStyleKeyword('none');

/// Shorthand with optional type, position, and image.
factory CssListStyle({
CssListStyleType? type,
CssListStylePosition? position,
String? image,
}) = _CssListStyleShorthand;

/// CSS variable reference.
factory CssListStyle.variable(String varName) = _CssListStyleVariable;

/// Raw CSS value escape hatch.
factory CssListStyle.raw(String value) = _CssListStyleRaw;

/// Global keyword (inherit, initial, unset, revert).
factory CssListStyle.global(CssGlobal global) = _CssListStyleGlobal;
}

final class _CssListStyleKeyword extends CssListStyle {
final String keyword;
const _CssListStyleKeyword(this.keyword) : super._();

@override
String toCss() => keyword;
}

final class _CssListStyleShorthand extends CssListStyle {
final CssListStyleType? type;
final CssListStylePosition? position;
final String? image;

const _CssListStyleShorthand({this.type, this.position, this.image})
: super._();

@override
String toCss() {
final parts = <String>[?type?.toCss(), ?position?.toCss(), ?image];
return parts.join(' ');
}
}

final class _CssListStyleVariable extends CssListStyle {
final String varName;
const _CssListStyleVariable(this.varName) : super._();

@override
String toCss() => 'var(--$varName)';
}

final class _CssListStyleRaw extends CssListStyle {
final String value;
const _CssListStyleRaw(this.value) : super._();

@override
String toCss() => value;
}

final class _CssListStyleGlobal extends CssListStyle {
final CssGlobal global;
const _CssListStyleGlobal(this.global) : super._();

@override
String toCss() => global.toCss();
}
3 changes: 3 additions & 0 deletions packages/spark_css/lib/src/css_types/css_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export 'css_border_radius.dart';
export 'css_box_shadow.dart';
export 'css_box_sizing.dart';
export 'css_color.dart';
export 'css_content.dart';
export 'css_cursor.dart';
export 'css_display.dart';
export 'css_filter.dart';
Expand All @@ -25,7 +26,9 @@ export 'css_flex_shorthand.dart';
export 'css_font.dart';
export 'css_gradient_direction.dart';
export 'css_grid_template_columns.dart';
export 'css_justify_items.dart';
export 'css_length.dart';
export 'css_list_style.dart';
export 'css_number.dart';
export 'css_outline.dart';
export 'css_overflow.dart';
Expand Down
18 changes: 18 additions & 0 deletions packages/spark_css/lib/src/style.dart
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,14 @@ class Style implements CssStyle {
CssTransform? transform,
// Background shorthand
CssBackground? background,
// Content
CssContent? content,
// Grid
CssGridTemplateColumns? gridTemplateColumns,
// Alignment
CssJustifyItems? justifyItems,
// Lists
CssListStyle? listStyle,
Stylesheet? css,
}) : stylesheet = css {
// Colors
Expand Down Expand Up @@ -485,10 +491,22 @@ class Style implements CssStyle {

// Background shorthand
if (background != null) _properties['background'] = background.toCss();

// Content
if (content != null) _properties['content'] = content.toCss();

// Grid
if (gridTemplateColumns != null) {
_properties['grid-template-columns'] = gridTemplateColumns.toCss();
}

// Alignment
if (justifyItems != null) {
_properties['justify-items'] = justifyItems.toCss();
}

// Lists
if (listStyle != null) _properties['list-style'] = listStyle.toCss();
}

/// Adds a custom property not covered by the named arguments.
Expand Down
27 changes: 27 additions & 0 deletions packages/spark_css/test/css_content_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:spark_css/spark_css.dart';
import 'package:test/test.dart';

void main() {
group('CssContent', () {
test('keywords output correct CSS', () {
expect(CssContent.normal.toCss(), equals('normal'));
expect(CssContent.none.toCss(), equals('none'));
});
test('value outputs correct CSS', () {
expect(CssContent.value('"Hello"').toCss(), equals('"Hello"'));
});
test('variable outputs correct CSS', () {
expect(CssContent.variable('c').toCss(), equals('var(--c)'));
});
test('raw outputs value as-is', () {
expect(CssContent.raw('counter(item)').toCss(), equals('counter(item)'));
});
test('global outputs correct CSS', () {
expect(CssContent.global(CssGlobal.inherit).toCss(), equals('inherit'));
});
test('Style.typed integration', () {
final style = Style.typed(content: CssContent.normal);
expect(style.toCss(), contains('content: normal;'));
});
});
}
38 changes: 38 additions & 0 deletions packages/spark_css/test/css_justify_items_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'package:spark_css/spark_css.dart';
import 'package:test/test.dart';

void main() {
group('CssJustifyItems', () {
test('keywords output correct CSS', () {
expect(CssJustifyItems.normal.toCss(), equals('normal'));
expect(CssJustifyItems.stretch.toCss(), equals('stretch'));
expect(CssJustifyItems.start.toCss(), equals('start'));
expect(CssJustifyItems.end.toCss(), equals('end'));
expect(CssJustifyItems.center.toCss(), equals('center'));
expect(CssJustifyItems.left.toCss(), equals('left'));
expect(CssJustifyItems.right.toCss(), equals('right'));
expect(CssJustifyItems.baseline.toCss(), equals('baseline'));
expect(CssJustifyItems.firstBaseline.toCss(), equals('first baseline'));
expect(CssJustifyItems.lastBaseline.toCss(), equals('last baseline'));
});
test('variable outputs correct CSS', () {
expect(CssJustifyItems.variable('ji').toCss(), equals('var(--ji)'));
});
test('raw outputs value as-is', () {
expect(
CssJustifyItems.raw('legacy center').toCss(),
equals('legacy center'),
);
});
test('global outputs correct CSS', () {
expect(
CssJustifyItems.global(CssGlobal.inherit).toCss(),
equals('inherit'),
);
});
test('Style.typed integration', () {
final style = Style.typed(justifyItems: CssJustifyItems.center);
expect(style.toCss(), contains('justify-items: center;'));
});
});
}
Loading