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
3 changes: 3 additions & 0 deletions packages/spark_css/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
- **Feat**: Added `CssTouchAction` sealed class for `touch-action` property with `.auto`, `.none`, `.manipulation` standalone keywords, `.panX`, `.panLeft`, `.panRight`, `.panY`, `.panUp`, `.panDown`, `.pinchZoom` combinable keywords, and `.combine()` factory, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssUserSelect` sealed class for `user-select` property with `.none`, `.auto`, `.text`, `.all`, `.contain` keywords, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssHyphens` sealed class for `hyphens` property with `.none`, `.manual`, `.auto` keywords, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssScrollPadding` sealed class for `scroll-padding` property with `.all()`, `.symmetric()`, `.only()` factories, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssOverscrollBehavior` sealed class for `overscroll-behavior` property with `.auto`, `.contain`, `.none` keywords, `.xy()` for two-value syntax, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssAppearance` sealed class for `appearance` property with `.none`, `.auto`, `.menulistButton`, `.textfield` keywords, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssTabSize` sealed class for `tab-size` property with `.number()`, `.length()` factories, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssCaretColor` sealed class for `caret-color` property with `.auto` keyword, `.color()` factory, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
- **Feat**: Added `CssScrollSnapType` sealed class for `scroll-snap-type` property with `.none` keyword, `.axis()` factory with optional strictness, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
Expand Down
54 changes: 54 additions & 0 deletions packages/spark_css/lib/src/css_types/css_appearance.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'css_value.dart';

/// CSS appearance property values.
sealed class CssAppearance implements CssValue {
const CssAppearance._();

static const CssAppearance none = _CssAppearanceKeyword('none');
static const CssAppearance auto = _CssAppearanceKeyword('auto');
static const CssAppearance menulistButton = _CssAppearanceKeyword(
'menulist-button',
);
static const CssAppearance textfield = _CssAppearanceKeyword('textfield');

/// CSS variable reference.
factory CssAppearance.variable(String varName) = _CssAppearanceVariable;

/// Raw CSS value escape hatch.
factory CssAppearance.raw(String value) = _CssAppearanceRaw;

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

final class _CssAppearanceKeyword extends CssAppearance {
final String keyword;
const _CssAppearanceKeyword(this.keyword) : super._();

@override
String toCss() => keyword;
}

final class _CssAppearanceVariable extends CssAppearance {
final String varName;
const _CssAppearanceVariable(this.varName) : super._();

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

final class _CssAppearanceRaw extends CssAppearance {
final String value;
const _CssAppearanceRaw(this.value) : super._();

@override
String toCss() => value;
}

final class _CssAppearanceGlobal extends CssAppearance {
final CssGlobal global;
const _CssAppearanceGlobal(this.global) : super._();

@override
String toCss() => global.toCss();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import 'css_value.dart';

/// CSS overscroll-behavior property values.
sealed class CssOverscrollBehavior implements CssValue {
const CssOverscrollBehavior._();

static const CssOverscrollBehavior auto = _CssOverscrollBehaviorKeyword(
'auto',
);
static const CssOverscrollBehavior contain = _CssOverscrollBehaviorKeyword(
'contain',
);
static const CssOverscrollBehavior none = _CssOverscrollBehaviorKeyword(
'none',
);

/// Two-value syntax for x and y axes.
///
/// Example: `CssOverscrollBehavior.xy(CssOverscrollBehavior.contain, CssOverscrollBehavior.none)` → `contain none`
factory CssOverscrollBehavior.xy(
CssOverscrollBehavior x,
CssOverscrollBehavior y,
) = _CssOverscrollBehaviorXY;

/// CSS variable reference.
factory CssOverscrollBehavior.variable(String varName) =
_CssOverscrollBehaviorVariable;

/// Raw CSS value escape hatch.
factory CssOverscrollBehavior.raw(String value) = _CssOverscrollBehaviorRaw;

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

final class _CssOverscrollBehaviorKeyword extends CssOverscrollBehavior {
final String keyword;
const _CssOverscrollBehaviorKeyword(this.keyword) : super._();

@override
String toCss() => keyword;
}

final class _CssOverscrollBehaviorXY extends CssOverscrollBehavior {
final CssOverscrollBehavior x;
final CssOverscrollBehavior y;
const _CssOverscrollBehaviorXY(this.x, this.y) : super._();

@override
String toCss() => '${x.toCss()} ${y.toCss()}';
}

final class _CssOverscrollBehaviorVariable extends CssOverscrollBehavior {
final String varName;
const _CssOverscrollBehaviorVariable(this.varName) : super._();

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

final class _CssOverscrollBehaviorRaw extends CssOverscrollBehavior {
final String value;
const _CssOverscrollBehaviorRaw(this.value) : super._();

@override
String toCss() => value;
}

final class _CssOverscrollBehaviorGlobal extends CssOverscrollBehavior {
final CssGlobal global;
const _CssOverscrollBehaviorGlobal(this.global) : super._();

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

/// CSS scroll-padding property values.
sealed class CssScrollPadding implements CssValue {
const CssScrollPadding._();

/// Same value for all four sides.
factory CssScrollPadding.all(CssLength value) = _CssScrollPaddingAll;

/// Symmetric scroll padding (vertical and horizontal).
factory CssScrollPadding.symmetric(CssLength vertical, CssLength horizontal) =
_CssScrollPaddingSymmetric;

/// Individual sides.
factory CssScrollPadding.only({
CssLength? top,
CssLength? right,
CssLength? bottom,
CssLength? left,
}) = _CssScrollPaddingOnly;

/// CSS variable reference.
factory CssScrollPadding.variable(String varName) = _CssScrollPaddingVariable;

/// Raw CSS value escape hatch.
factory CssScrollPadding.raw(String value) = _CssScrollPaddingRaw;

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

final class _CssScrollPaddingAll extends CssScrollPadding {
final CssLength value;
const _CssScrollPaddingAll(this.value) : super._();

@override
String toCss() => value.toCss();
}

final class _CssScrollPaddingSymmetric extends CssScrollPadding {
final CssLength vertical;
final CssLength horizontal;
const _CssScrollPaddingSymmetric(this.vertical, this.horizontal) : super._();

@override
String toCss() => '${vertical.toCss()} ${horizontal.toCss()}';
}

final class _CssScrollPaddingOnly extends CssScrollPadding {
final CssLength? top;
final CssLength? right;
final CssLength? bottom;
final CssLength? left;
const _CssScrollPaddingOnly({this.top, this.right, this.bottom, this.left})
: super._();

@override
String toCss() {
final t = top ?? CssLength.zero;
final r = right ?? CssLength.zero;
final b = bottom ?? CssLength.zero;
final l = left ?? CssLength.zero;
return '${t.toCss()} ${r.toCss()} ${b.toCss()} ${l.toCss()}';
}
}

final class _CssScrollPaddingVariable extends CssScrollPadding {
final String varName;
const _CssScrollPaddingVariable(this.varName) : super._();

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

final class _CssScrollPaddingRaw extends CssScrollPadding {
final String value;
const _CssScrollPaddingRaw(this.value) : super._();

@override
String toCss() => value;
}

final class _CssScrollPaddingGlobal extends CssScrollPadding {
final CssGlobal global;
const _CssScrollPaddingGlobal(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 @@ -3,6 +3,7 @@ library;

export 'css_animation.dart';
export 'css_angle.dart';
export 'css_appearance.dart';
export 'css_aspect_ratio.dart';
export 'css_background.dart';
export 'css_background_attachment.dart';
Expand Down Expand Up @@ -41,6 +42,7 @@ export 'css_number.dart';
export 'css_object_fit.dart';
export 'css_outline.dart';
export 'css_overflow.dart';
export 'css_overscroll_behavior.dart';
export 'css_place_content.dart';
export 'css_place_items.dart';
export 'css_place_self.dart';
Expand All @@ -51,6 +53,7 @@ export 'css_radial_size.dart';
export 'css_resize.dart';
export 'css_scroll_behavior.dart';
export 'css_scroll_margin.dart';
export 'css_scroll_padding.dart';
export 'css_scroll_snap_align.dart';
export 'css_scroll_snap_type.dart';
export 'css_spacing.dart';
Expand Down
12 changes: 12 additions & 0 deletions packages/spark_css/lib/src/style.dart
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@ class Style implements CssStyle {
CssScrollSnapType? scrollSnapType,
CssScrollSnapAlign? scrollSnapAlign,
CssScrollMargin? scrollMargin,
CssScrollPadding? scrollPadding,
CssOverscrollBehavior? overscrollBehavior,
CssAppearance? appearance,
// Backgrounds
CssBackgroundImage? backgroundImage,
CssBackgroundSize? backgroundSize,
Expand Down Expand Up @@ -530,6 +533,15 @@ class Style implements CssStyle {
if (scrollMargin != null) {
_properties['scroll-margin'] = scrollMargin.toCss();
}
if (scrollPadding != null) {
_properties['scroll-padding'] = scrollPadding.toCss();
}
if (overscrollBehavior != null) {
_properties['overscroll-behavior'] = overscrollBehavior.toCss();
}
if (appearance != null) {
_properties['appearance'] = appearance.toCss();
}

// Backgrounds
if (backgroundImage != null) {
Expand Down
43 changes: 43 additions & 0 deletions packages/spark_css/test/css_appearance_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'package:spark_css/spark_css.dart';
import 'package:test/test.dart';

void main() {
group('CssAppearance', () {
test('keywords output correct CSS', () {
expect(CssAppearance.none.toCss(), equals('none'));
expect(CssAppearance.auto.toCss(), equals('auto'));
expect(CssAppearance.menulistButton.toCss(), equals('menulist-button'));
expect(CssAppearance.textfield.toCss(), equals('textfield'));
});

test('variable outputs correct CSS', () {
expect(CssAppearance.variable('ap').toCss(), equals('var(--ap)'));
});

test('raw outputs value as-is', () {
expect(CssAppearance.raw('none').toCss(), equals('none'));
});

test('global outputs correct CSS', () {
expect(
CssAppearance.global(CssGlobal.inherit).toCss(),
equals('inherit'),
);
expect(
CssAppearance.global(CssGlobal.initial).toCss(),
equals('initial'),
);
expect(CssAppearance.global(CssGlobal.unset).toCss(), equals('unset'));
expect(CssAppearance.global(CssGlobal.revert).toCss(), equals('revert'));
expect(
CssAppearance.global(CssGlobal.revertLayer).toCss(),
equals('revert-layer'),
);
});

test('Style.typed integration', () {
final style = Style.typed(appearance: CssAppearance.none);
expect(style.toCss(), contains('appearance: none;'));
});
});
}
70 changes: 70 additions & 0 deletions packages/spark_css/test/css_overscroll_behavior_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import 'package:spark_css/spark_css.dart';
import 'package:test/test.dart';

void main() {
group('CssOverscrollBehavior', () {
test('keywords output correct CSS', () {
expect(CssOverscrollBehavior.auto.toCss(), equals('auto'));
expect(CssOverscrollBehavior.contain.toCss(), equals('contain'));
expect(CssOverscrollBehavior.none.toCss(), equals('none'));
});

test('xy outputs correct CSS', () {
expect(
CssOverscrollBehavior.xy(
CssOverscrollBehavior.contain,
CssOverscrollBehavior.none,
).toCss(),
equals('contain none'),
);
expect(
CssOverscrollBehavior.xy(
CssOverscrollBehavior.auto,
CssOverscrollBehavior.contain,
).toCss(),
equals('auto contain'),
);
});

test('variable outputs correct CSS', () {
expect(CssOverscrollBehavior.variable('ob').toCss(), equals('var(--ob)'));
});

test('raw outputs value as-is', () {
expect(
CssOverscrollBehavior.raw('contain none').toCss(),
equals('contain none'),
);
});

test('global outputs correct CSS', () {
expect(
CssOverscrollBehavior.global(CssGlobal.inherit).toCss(),
equals('inherit'),
);
expect(
CssOverscrollBehavior.global(CssGlobal.initial).toCss(),
equals('initial'),
);
expect(
CssOverscrollBehavior.global(CssGlobal.unset).toCss(),
equals('unset'),
);
expect(
CssOverscrollBehavior.global(CssGlobal.revert).toCss(),
equals('revert'),
);
expect(
CssOverscrollBehavior.global(CssGlobal.revertLayer).toCss(),
equals('revert-layer'),
);
});

test('Style.typed integration', () {
final style = Style.typed(
overscrollBehavior: CssOverscrollBehavior.contain,
);
expect(style.toCss(), contains('overscroll-behavior: contain;'));
});
});
}
Loading