Skip to content

Commit 7e08f3a

Browse files
feat(spark_css): add typed CssBackgroundPosition
- Added `CssBackgroundPosition` sealed class in `packages/spark_css/lib/src/css_types/css_background_position.dart`. - Implemented `CssValue` interface. - Added keywords: `left`, `center`, `right`, `top`, `bottom`. - Added factory `parts` for 1-4 value syntax (joining with spaces). - Added factory `multiple` for comma-separated position lists. - Added factories `variable`, `raw`, `global`. - Added tests in `packages/spark_css/test/css_background_position_test.dart` covering all features.
1 parent 9aba058 commit 7e08f3a

2 files changed

Lines changed: 212 additions & 0 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import 'css_value.dart';
2+
3+
/// CSS background-position property values.
4+
sealed class CssBackgroundPosition implements CssValue {
5+
const CssBackgroundPosition._();
6+
7+
// Keyword values
8+
static const CssBackgroundPosition left = _CssBackgroundPositionKeyword(
9+
'left',
10+
);
11+
static const CssBackgroundPosition center = _CssBackgroundPositionKeyword(
12+
'center',
13+
);
14+
static const CssBackgroundPosition right = _CssBackgroundPositionKeyword(
15+
'right',
16+
);
17+
static const CssBackgroundPosition top = _CssBackgroundPositionKeyword('top');
18+
static const CssBackgroundPosition bottom = _CssBackgroundPositionKeyword(
19+
'bottom',
20+
);
21+
22+
/// Creates a position from one to four values (keywords or lengths).
23+
///
24+
/// Example:
25+
/// ```dart
26+
/// CssBackgroundPosition.parts([CssBackgroundPosition.left, CssLength.px(20)])
27+
/// // Output: left 20px
28+
/// ```
29+
factory CssBackgroundPosition.parts(List<CssValue> values) =
30+
_CssBackgroundPositionParts;
31+
32+
/// Multiple background positions (comma-separated).
33+
///
34+
/// Example:
35+
/// ```dart
36+
/// CssBackgroundPosition.multiple([
37+
/// CssBackgroundPosition.parts([CssBackgroundPosition.left]),
38+
/// CssBackgroundPosition.parts([CssBackgroundPosition.right]),
39+
/// ])
40+
/// // Output: left, right
41+
/// ```
42+
factory CssBackgroundPosition.multiple(
43+
List<CssBackgroundPosition> positions,
44+
) = _CssBackgroundPositionMultiple;
45+
46+
/// CSS variable reference.
47+
factory CssBackgroundPosition.variable(String varName) =
48+
_CssBackgroundPositionVariable;
49+
50+
/// Raw CSS value escape hatch.
51+
factory CssBackgroundPosition.raw(String value) = _CssBackgroundPositionRaw;
52+
53+
/// Global keyword (inherit, initial, unset, revert).
54+
factory CssBackgroundPosition.global(CssGlobal global) =
55+
_CssBackgroundPositionGlobal;
56+
}
57+
58+
final class _CssBackgroundPositionKeyword extends CssBackgroundPosition {
59+
final String keyword;
60+
const _CssBackgroundPositionKeyword(this.keyword) : super._();
61+
62+
@override
63+
String toCss() => keyword;
64+
}
65+
66+
final class _CssBackgroundPositionParts extends CssBackgroundPosition {
67+
final List<CssValue> values;
68+
const _CssBackgroundPositionParts(this.values) : super._();
69+
70+
@override
71+
String toCss() => values.map((v) => v.toCss()).join(' ');
72+
}
73+
74+
final class _CssBackgroundPositionMultiple extends CssBackgroundPosition {
75+
final List<CssBackgroundPosition> positions;
76+
const _CssBackgroundPositionMultiple(this.positions) : super._();
77+
78+
@override
79+
String toCss() => positions.map((p) => p.toCss()).join(', ');
80+
}
81+
82+
final class _CssBackgroundPositionVariable extends CssBackgroundPosition {
83+
final String varName;
84+
const _CssBackgroundPositionVariable(this.varName) : super._();
85+
86+
@override
87+
String toCss() => 'var(--$varName)';
88+
}
89+
90+
final class _CssBackgroundPositionRaw extends CssBackgroundPosition {
91+
final String value;
92+
const _CssBackgroundPositionRaw(this.value) : super._();
93+
94+
@override
95+
String toCss() => value;
96+
}
97+
98+
final class _CssBackgroundPositionGlobal extends CssBackgroundPosition {
99+
final CssGlobal global;
100+
const _CssBackgroundPositionGlobal(this.global) : super._();
101+
102+
@override
103+
String toCss() => global.toCss();
104+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import 'package:spark_css/spark_css.dart';
2+
import 'package:spark_css/src/css_types/css_background_position.dart';
3+
import 'package:test/test.dart';
4+
5+
void main() {
6+
group('CssBackgroundPosition', () {
7+
test('keywords output correct CSS', () {
8+
expect(CssBackgroundPosition.left.toCss(), equals('left'));
9+
expect(CssBackgroundPosition.center.toCss(), equals('center'));
10+
expect(CssBackgroundPosition.right.toCss(), equals('right'));
11+
expect(CssBackgroundPosition.top.toCss(), equals('top'));
12+
expect(CssBackgroundPosition.bottom.toCss(), equals('bottom'));
13+
});
14+
15+
test('parts outputs correct CSS with lengths and keywords', () {
16+
// 1 value
17+
expect(
18+
CssBackgroundPosition.parts([CssBackgroundPosition.left]).toCss(),
19+
equals('left'),
20+
);
21+
22+
// 2 values (keyword + length)
23+
expect(
24+
CssBackgroundPosition.parts([
25+
CssBackgroundPosition.left,
26+
CssLength.px(20),
27+
]).toCss(),
28+
equals('left 20px'),
29+
);
30+
31+
// 2 values (length + length)
32+
expect(
33+
CssBackgroundPosition.parts([
34+
CssLength.percent(50),
35+
CssLength.percent(50),
36+
]).toCss(),
37+
equals('50% 50%'),
38+
);
39+
40+
// 3 values
41+
expect(
42+
CssBackgroundPosition.parts([
43+
CssBackgroundPosition.left,
44+
CssLength.px(20),
45+
CssBackgroundPosition.top,
46+
]).toCss(),
47+
equals('left 20px top'),
48+
);
49+
50+
// 4 values
51+
expect(
52+
CssBackgroundPosition.parts([
53+
CssBackgroundPosition.left,
54+
CssLength.px(20),
55+
CssBackgroundPosition.top,
56+
CssLength.px(10),
57+
]).toCss(),
58+
equals('left 20px top 10px'),
59+
);
60+
});
61+
62+
test('multiple outputs correct CSS', () {
63+
expect(
64+
CssBackgroundPosition.multiple([
65+
CssBackgroundPosition.parts([CssBackgroundPosition.left]),
66+
CssBackgroundPosition.parts([CssBackgroundPosition.right]),
67+
]).toCss(),
68+
equals('left, right'),
69+
);
70+
71+
expect(
72+
CssBackgroundPosition.multiple([
73+
CssBackgroundPosition.parts([
74+
CssBackgroundPosition.left,
75+
CssLength.px(20),
76+
]),
77+
CssBackgroundPosition.center,
78+
]).toCss(),
79+
equals('left 20px, center'),
80+
);
81+
});
82+
83+
test('variable outputs correct CSS', () {
84+
expect(
85+
CssBackgroundPosition.variable('bg-pos').toCss(),
86+
equals('var(--bg-pos)'),
87+
);
88+
});
89+
90+
test('raw outputs value as-is', () {
91+
expect(
92+
CssBackgroundPosition.raw('left 20px').toCss(),
93+
equals('left 20px'),
94+
);
95+
});
96+
97+
test('global outputs correct CSS', () {
98+
expect(
99+
CssBackgroundPosition.global(CssGlobal.inherit).toCss(),
100+
equals('inherit'),
101+
);
102+
expect(
103+
CssBackgroundPosition.global(CssGlobal.initial).toCss(),
104+
equals('initial'),
105+
);
106+
});
107+
});
108+
}

0 commit comments

Comments
 (0)