Skip to content

Commit 12ec075

Browse files
feat(spark_css): add typed CssFlexShorthand class
- Added `CssFlexShorthand` class in `packages/spark_css/lib/src/css_types/css_flex_shorthand.dart` to support typed `flex` property values. - Implemented support for keywords (`auto`, `initial`, `none`) and combinations of `flex-grow`, `flex-shrink`, and `flex-basis`. - Added unit tests in `packages/spark_css/test/css_flex_shorthand_test.dart`.
1 parent 6ff4fed commit 12ec075

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import 'css_length.dart';
2+
import 'css_value.dart';
3+
4+
/// CSS flex shorthand property values.
5+
sealed class CssFlexShorthand implements CssValue {
6+
const CssFlexShorthand._();
7+
8+
static const CssFlexShorthand auto = _CssFlexShorthandKeyword('auto');
9+
static const CssFlexShorthand initial = _CssFlexShorthandKeyword('initial');
10+
static const CssFlexShorthand none = _CssFlexShorthandKeyword('none');
11+
12+
/// Creates a flex shorthand value.
13+
///
14+
/// Supports the following combinations:
15+
/// - [grow]: flex-grow (number)
16+
/// - [basis]: flex-basis (length)
17+
/// - [grow] and [basis]: flex-grow flex-basis
18+
/// - [grow] and [shrink]: flex-grow flex-shrink
19+
/// - [grow], [shrink], and [basis]: flex-grow flex-shrink flex-basis
20+
///
21+
/// If [shrink] is provided, [grow] must also be provided.
22+
factory CssFlexShorthand({num? grow, num? shrink, CssLength? basis}) {
23+
if (grow != null) {
24+
if (shrink != null) {
25+
if (basis != null) {
26+
return _CssFlexShorthandValues(grow, shrink, basis);
27+
}
28+
return _CssFlexShorthandValues(grow, shrink, null);
29+
}
30+
if (basis != null) {
31+
return _CssFlexShorthandValues(grow, null, basis);
32+
}
33+
return _CssFlexShorthandValues(grow, null, null);
34+
} else if (basis != null) {
35+
if (shrink != null) {
36+
throw ArgumentError('flex-shrink requires flex-grow to be specified.');
37+
}
38+
return _CssFlexShorthandValues(null, null, basis);
39+
} else if (shrink != null) {
40+
throw ArgumentError('flex-shrink requires flex-grow to be specified.');
41+
}
42+
43+
throw ArgumentError('At least one of grow or basis must be provided.');
44+
}
45+
46+
/// CSS variable reference.
47+
factory CssFlexShorthand.variable(String varName) = _CssFlexShorthandVariable;
48+
49+
/// Raw CSS value escape hatch.
50+
factory CssFlexShorthand.raw(String value) = _CssFlexShorthandRaw;
51+
52+
/// Global keyword (inherit, initial, unset, revert).
53+
factory CssFlexShorthand.global(CssGlobal global) = _CssFlexShorthandGlobal;
54+
}
55+
56+
final class _CssFlexShorthandKeyword extends CssFlexShorthand {
57+
final String keyword;
58+
const _CssFlexShorthandKeyword(this.keyword) : super._();
59+
@override
60+
String toCss() => keyword;
61+
}
62+
63+
final class _CssFlexShorthandValues extends CssFlexShorthand {
64+
final num? grow;
65+
final num? shrink;
66+
final CssLength? basis;
67+
68+
const _CssFlexShorthandValues(this.grow, this.shrink, this.basis) : super._();
69+
70+
@override
71+
String toCss() {
72+
final parts = <String>[];
73+
if (grow != null) parts.add(grow.toString());
74+
if (shrink != null) parts.add(shrink.toString());
75+
if (basis != null) parts.add(basis!.toCss());
76+
return parts.join(' ');
77+
}
78+
}
79+
80+
final class _CssFlexShorthandVariable extends CssFlexShorthand {
81+
final String varName;
82+
const _CssFlexShorthandVariable(this.varName) : super._();
83+
@override
84+
String toCss() => 'var(--$varName)';
85+
}
86+
87+
final class _CssFlexShorthandRaw extends CssFlexShorthand {
88+
final String value;
89+
const _CssFlexShorthandRaw(this.value) : super._();
90+
@override
91+
String toCss() => value;
92+
}
93+
94+
final class _CssFlexShorthandGlobal extends CssFlexShorthand {
95+
final CssGlobal global;
96+
const _CssFlexShorthandGlobal(this.global) : super._();
97+
@override
98+
String toCss() => global.toCss();
99+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import 'package:spark_css/spark_css.dart';
2+
import 'package:spark_css/src/css_types/css_flex_shorthand.dart';
3+
import 'package:test/test.dart';
4+
5+
void main() {
6+
group('CssFlexShorthand', () {
7+
test('keywords output correct CSS', () {
8+
expect(CssFlexShorthand.auto.toCss(), equals('auto'));
9+
expect(CssFlexShorthand.initial.toCss(), equals('initial'));
10+
expect(CssFlexShorthand.none.toCss(), equals('none'));
11+
});
12+
13+
test('single value (grow) outputs correct CSS', () {
14+
expect(CssFlexShorthand(grow: 1).toCss(), equals('1'));
15+
expect(CssFlexShorthand(grow: 0.5).toCss(), equals('0.5'));
16+
});
17+
18+
test('single value (basis) outputs correct CSS', () {
19+
expect(
20+
CssFlexShorthand(basis: CssLength.px(100)).toCss(),
21+
equals('100px'),
22+
);
23+
expect(CssFlexShorthand(basis: CssLength.auto).toCss(), equals('auto'));
24+
});
25+
26+
test('two values (grow + shrink) outputs correct CSS', () {
27+
expect(CssFlexShorthand(grow: 1, shrink: 2).toCss(), equals('1 2'));
28+
});
29+
30+
test('two values (grow + basis) outputs correct CSS', () {
31+
expect(
32+
CssFlexShorthand(grow: 1, basis: CssLength.percent(50)).toCss(),
33+
equals('1 50%'),
34+
);
35+
});
36+
37+
test('three values (grow + shrink + basis) outputs correct CSS', () {
38+
expect(
39+
CssFlexShorthand(grow: 1, shrink: 0, basis: CssLength.auto).toCss(),
40+
equals('1 0 auto'),
41+
);
42+
});
43+
44+
test('throws ArgumentError when shrink provided without grow', () {
45+
expect(() => CssFlexShorthand(shrink: 1), throwsArgumentError);
46+
expect(
47+
() => CssFlexShorthand(shrink: 1, basis: CssLength.auto),
48+
throwsArgumentError,
49+
);
50+
});
51+
52+
test('throws ArgumentError when neither grow nor basis provided', () {
53+
expect(() => CssFlexShorthand(), throwsArgumentError);
54+
});
55+
56+
test('variable outputs correct CSS', () {
57+
expect(
58+
CssFlexShorthand.variable('flex-val').toCss(),
59+
equals('var(--flex-val)'),
60+
);
61+
});
62+
63+
test('raw outputs value as-is', () {
64+
expect(CssFlexShorthand.raw('1 1 auto').toCss(), equals('1 1 auto'));
65+
});
66+
67+
test('global outputs correct CSS', () {
68+
expect(
69+
CssFlexShorthand.global(CssGlobal.inherit).toCss(),
70+
equals('inherit'),
71+
);
72+
});
73+
});
74+
}

0 commit comments

Comments
 (0)