Skip to content

Commit de8caff

Browse files
feat(spark_css)!: add typed CssTransitionProperty and CssDuration classes
Replace raw String parameters in CssTransition with typed sealed classes for property names and durations, matching the existing CssTimingFunction pattern.
1 parent 25ba555 commit de8caff

7 files changed

Lines changed: 282 additions & 23 deletions

File tree

packages/spark_css/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## 1.0.0-alpha.4
4+
5+
### Added
6+
7+
- **Feat**: Added `CssTransitionProperty` sealed class with typed constants for common animatable CSS properties (`all`, `opacity`, `transform`, `backgroundColor`, `color`, `width`, `height`, `margin`, `padding`, `border`, `borderRadius`, `boxShadow`, `top`, `right`, `bottom`, `left`, `visibility`, `fontSize`, `lineHeight`, `letterSpacing`, `gap`) plus `variable()` and `raw()` constructors.
8+
- **Feat**: Added `CssDuration` sealed class with `ms()`, `s()`, `variable()`, and `raw()` constructors for type-safe CSS duration values.
9+
10+
### Changed
11+
12+
- **Breaking Change**: `CssTransition` now accepts `CssTransitionProperty` instead of `String` for the `property` parameter, and `CssDuration` instead of `String` for `duration` and `delay` parameters.
13+
314
## 1.0.0-alpha.3
415

516
### Added

packages/spark_css/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,47 @@ Style.typed(
9898
)
9999
```
100100

101+
### Transitions
102+
103+
`CssTransition` uses typed parameters for property names, durations, and timing functions:
104+
105+
```dart
106+
Style.typed(
107+
transition: CssTransition.simple(
108+
CssTransitionProperty.opacity,
109+
CssDuration.ms(200),
110+
CssTimingFunction.ease,
111+
),
112+
)
113+
```
114+
115+
Use the named constructor for full control including delay:
116+
117+
```dart
118+
CssTransition(
119+
property: CssTransitionProperty.transform,
120+
duration: CssDuration.s(0.3),
121+
timingFunction: CssTimingFunction.easeInOut,
122+
delay: CssDuration.ms(100),
123+
)
124+
```
125+
126+
Combine multiple transitions:
127+
128+
```dart
129+
CssTransition.multiple([
130+
CssTransition.simple(CssTransitionProperty.opacity, CssDuration.ms(200)),
131+
CssTransition.simple(CssTransitionProperty.transform, CssDuration.ms(300)),
132+
])
133+
```
134+
135+
Use `.raw()` for values not covered by the typed constructors:
136+
137+
```dart
138+
CssTransitionProperty.raw('max-width')
139+
CssDuration.raw('200ms')
140+
```
141+
101142
### Custom Properties
102143

103144
For properties not covered by the typed constructors, use `.add()`:

packages/spark_css/lib/src/css_types/css_transition.dart

Lines changed: 138 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,134 @@ final class _CssTimingFunctionRaw extends CssTimingFunction {
8888
String toCss() => value;
8989
}
9090

91+
/// CSS transition property names.
92+
sealed class CssTransitionProperty implements CssValue {
93+
const CssTransitionProperty._();
94+
95+
static const CssTransitionProperty all =
96+
_CssTransitionPropertyKeyword('all');
97+
static const CssTransitionProperty opacity =
98+
_CssTransitionPropertyKeyword('opacity');
99+
static const CssTransitionProperty transform =
100+
_CssTransitionPropertyKeyword('transform');
101+
static const CssTransitionProperty backgroundColor =
102+
_CssTransitionPropertyKeyword('background-color');
103+
static const CssTransitionProperty color =
104+
_CssTransitionPropertyKeyword('color');
105+
static const CssTransitionProperty width =
106+
_CssTransitionPropertyKeyword('width');
107+
static const CssTransitionProperty height =
108+
_CssTransitionPropertyKeyword('height');
109+
static const CssTransitionProperty margin =
110+
_CssTransitionPropertyKeyword('margin');
111+
static const CssTransitionProperty padding =
112+
_CssTransitionPropertyKeyword('padding');
113+
static const CssTransitionProperty border =
114+
_CssTransitionPropertyKeyword('border');
115+
static const CssTransitionProperty borderRadius =
116+
_CssTransitionPropertyKeyword('border-radius');
117+
static const CssTransitionProperty boxShadow =
118+
_CssTransitionPropertyKeyword('box-shadow');
119+
static const CssTransitionProperty top =
120+
_CssTransitionPropertyKeyword('top');
121+
static const CssTransitionProperty right =
122+
_CssTransitionPropertyKeyword('right');
123+
static const CssTransitionProperty bottom =
124+
_CssTransitionPropertyKeyword('bottom');
125+
static const CssTransitionProperty left =
126+
_CssTransitionPropertyKeyword('left');
127+
static const CssTransitionProperty visibility =
128+
_CssTransitionPropertyKeyword('visibility');
129+
static const CssTransitionProperty fontSize =
130+
_CssTransitionPropertyKeyword('font-size');
131+
static const CssTransitionProperty lineHeight =
132+
_CssTransitionPropertyKeyword('line-height');
133+
static const CssTransitionProperty letterSpacing =
134+
_CssTransitionPropertyKeyword('letter-spacing');
135+
static const CssTransitionProperty gap =
136+
_CssTransitionPropertyKeyword('gap');
137+
138+
/// CSS variable reference.
139+
factory CssTransitionProperty.variable(String varName) =
140+
_CssTransitionPropertyVariable;
141+
142+
/// Raw CSS value escape hatch.
143+
factory CssTransitionProperty.raw(String value) = _CssTransitionPropertyRaw;
144+
}
145+
146+
final class _CssTransitionPropertyKeyword extends CssTransitionProperty {
147+
final String keyword;
148+
const _CssTransitionPropertyKeyword(this.keyword) : super._();
149+
150+
@override
151+
String toCss() => keyword;
152+
}
153+
154+
final class _CssTransitionPropertyVariable extends CssTransitionProperty {
155+
final String varName;
156+
const _CssTransitionPropertyVariable(this.varName) : super._();
157+
158+
@override
159+
String toCss() => 'var(--$varName)';
160+
}
161+
162+
final class _CssTransitionPropertyRaw extends CssTransitionProperty {
163+
final String value;
164+
const _CssTransitionPropertyRaw(this.value) : super._();
165+
166+
@override
167+
String toCss() => value;
168+
}
169+
170+
/// CSS duration values.
171+
sealed class CssDuration implements CssValue {
172+
const CssDuration._();
173+
174+
/// Duration in milliseconds.
175+
factory CssDuration.ms(num milliseconds) = _CssDurationMs;
176+
177+
/// Duration in seconds.
178+
factory CssDuration.s(num seconds) = _CssDurationS;
179+
180+
/// CSS variable reference.
181+
factory CssDuration.variable(String varName) = _CssDurationVariable;
182+
183+
/// Raw CSS value escape hatch.
184+
factory CssDuration.raw(String value) = _CssDurationRaw;
185+
}
186+
187+
final class _CssDurationMs extends CssDuration {
188+
final num milliseconds;
189+
const _CssDurationMs(this.milliseconds) : super._();
190+
191+
@override
192+
String toCss() => '${milliseconds}ms';
193+
}
194+
195+
final class _CssDurationS extends CssDuration {
196+
final num seconds;
197+
const _CssDurationS(this.seconds) : super._();
198+
199+
@override
200+
String toCss() => '${seconds}s';
201+
}
202+
203+
final class _CssDurationVariable extends CssDuration {
204+
final String varName;
205+
const _CssDurationVariable(this.varName) : super._();
206+
207+
@override
208+
String toCss() => 'var(--$varName)';
209+
}
210+
211+
final class _CssDurationRaw extends CssDuration {
212+
final String value;
213+
const _CssDurationRaw(this.value) : super._();
214+
215+
@override
216+
String toCss() => value;
217+
}
218+
91219
/// CSS transition value.
92220
sealed class CssTransition implements CssValue {
93221
const CssTransition._();
@@ -96,16 +224,16 @@ sealed class CssTransition implements CssValue {
96224

97225
/// Single transition.
98226
factory CssTransition({
99-
required String property,
100-
required String duration,
227+
required CssTransitionProperty property,
228+
required CssDuration duration,
101229
CssTimingFunction? timingFunction,
102-
String? delay,
230+
CssDuration? delay,
103231
}) = _CssTransitionSingle;
104232

105233
/// Shorthand for a simple transition.
106234
factory CssTransition.simple(
107-
String property,
108-
String duration, [
235+
CssTransitionProperty property,
236+
CssDuration duration, [
109237
CssTimingFunction? timingFunction,
110238
]) => _CssTransitionSingle(
111239
property: property,
@@ -136,10 +264,10 @@ final class _CssTransitionKeyword extends CssTransition {
136264
}
137265

138266
final class _CssTransitionSingle extends CssTransition {
139-
final String property;
140-
final String duration;
267+
final CssTransitionProperty property;
268+
final CssDuration duration;
141269
final CssTimingFunction? timingFunction;
142-
final String? delay;
270+
final CssDuration? delay;
143271

144272
const _CssTransitionSingle({
145273
required this.property,
@@ -150,9 +278,9 @@ final class _CssTransitionSingle extends CssTransition {
150278

151279
@override
152280
String toCss() {
153-
final parts = [property, duration];
281+
final parts = [property.toCss(), duration.toCss()];
154282
if (timingFunction != null) parts.add(timingFunction!.toCss());
155-
if (delay != null) parts.add(delay!);
283+
if (delay != null) parts.add(delay!.toCss());
156284
return parts.join(' ');
157285
}
158286
}

packages/spark_css/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: spark_css
22
description: Type-safe CSS style system for Spark framework.
3-
version: 1.0.0-alpha.3
3+
version: 1.0.0-alpha.4
44
resolution: workspace
55

66
homepage: https://spark.kleak.dev

packages/spark_css/test/css_transition_test.dart

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,95 @@ void main() {
3232
});
3333
});
3434

35+
group('CssTransitionProperty', () {
36+
test('keywords output correct CSS', () {
37+
expect(CssTransitionProperty.all.toCss(), equals('all'));
38+
expect(CssTransitionProperty.opacity.toCss(), equals('opacity'));
39+
expect(CssTransitionProperty.transform.toCss(), equals('transform'));
40+
expect(
41+
CssTransitionProperty.backgroundColor.toCss(),
42+
equals('background-color'),
43+
);
44+
expect(CssTransitionProperty.color.toCss(), equals('color'));
45+
expect(CssTransitionProperty.width.toCss(), equals('width'));
46+
expect(CssTransitionProperty.height.toCss(), equals('height'));
47+
expect(CssTransitionProperty.margin.toCss(), equals('margin'));
48+
expect(CssTransitionProperty.padding.toCss(), equals('padding'));
49+
expect(CssTransitionProperty.border.toCss(), equals('border'));
50+
expect(
51+
CssTransitionProperty.borderRadius.toCss(),
52+
equals('border-radius'),
53+
);
54+
expect(CssTransitionProperty.boxShadow.toCss(), equals('box-shadow'));
55+
expect(CssTransitionProperty.top.toCss(), equals('top'));
56+
expect(CssTransitionProperty.right.toCss(), equals('right'));
57+
expect(CssTransitionProperty.bottom.toCss(), equals('bottom'));
58+
expect(CssTransitionProperty.left.toCss(), equals('left'));
59+
expect(CssTransitionProperty.visibility.toCss(), equals('visibility'));
60+
expect(CssTransitionProperty.fontSize.toCss(), equals('font-size'));
61+
expect(CssTransitionProperty.lineHeight.toCss(), equals('line-height'));
62+
expect(
63+
CssTransitionProperty.letterSpacing.toCss(),
64+
equals('letter-spacing'),
65+
);
66+
expect(CssTransitionProperty.gap.toCss(), equals('gap'));
67+
});
68+
test('variable outputs correct CSS', () {
69+
expect(
70+
CssTransitionProperty.variable('prop').toCss(),
71+
equals('var(--prop)'),
72+
);
73+
});
74+
test('raw outputs value as-is', () {
75+
expect(
76+
CssTransitionProperty.raw('max-width').toCss(),
77+
equals('max-width'),
78+
);
79+
});
80+
});
81+
82+
group('CssDuration', () {
83+
test('ms outputs correct CSS', () {
84+
expect(CssDuration.ms(200).toCss(), equals('200ms'));
85+
expect(CssDuration.ms(1.5).toCss(), equals('1.5ms'));
86+
});
87+
test('s outputs correct CSS', () {
88+
expect(CssDuration.s(1).toCss(), equals('1s'));
89+
expect(CssDuration.s(0.3).toCss(), equals('0.3s'));
90+
});
91+
test('variable outputs correct CSS', () {
92+
expect(CssDuration.variable('dur').toCss(), equals('var(--dur)'));
93+
});
94+
test('raw outputs value as-is', () {
95+
expect(CssDuration.raw('200ms').toCss(), equals('200ms'));
96+
});
97+
});
98+
3599
group('CssTransition', () {
36100
test('none outputs correct CSS', () {
37101
expect(CssTransition.none.toCss(), equals('none'));
38102
});
39103
test('single outputs correct CSS', () {
40104
expect(
41105
CssTransition(
42-
property: 'opacity',
43-
duration: '1s',
44-
delay: '0.5s',
106+
property: CssTransitionProperty.opacity,
107+
duration: CssDuration.s(1),
108+
delay: CssDuration.s(0.5),
45109
).toCss(),
46110
equals('opacity 1s 0.5s'),
47111
);
48112
});
49113
test('multiple outputs correct CSS', () {
50114
expect(
51115
CssTransition.multiple([
52-
CssTransition.simple('opacity', '1s'),
53-
CssTransition.simple('width', '2s'),
116+
CssTransition.simple(
117+
CssTransitionProperty.opacity,
118+
CssDuration.s(1),
119+
),
120+
CssTransition.simple(
121+
CssTransitionProperty.width,
122+
CssDuration.s(2),
123+
),
54124
]).toCss(),
55125
equals('opacity 1s, width 2s'),
56126
);

packages/spark_css/test/css_types_test.dart

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,8 @@ void main() {
424424
test('single transition outputs correct CSS', () {
425425
expect(
426426
CssTransition(
427-
property: 'all',
428-
duration: '0.3s',
427+
property: CssTransitionProperty.all,
428+
duration: CssDuration.s(0.3),
429429
timingFunction: CssTimingFunction.ease,
430430
).toCss(),
431431
equals('all 0.3s ease'),
@@ -434,18 +434,24 @@ void main() {
434434

435435
test('simple transition outputs correct CSS', () {
436436
expect(
437-
CssTransition.simple('opacity', '200ms').toCss(),
437+
CssTransition.simple(
438+
CssTransitionProperty.opacity,
439+
CssDuration.ms(200),
440+
).toCss(),
438441
equals('opacity 200ms'),
439442
);
440443
});
441444

442445
test('multiple transitions output correct CSS', () {
443446
expect(
444447
CssTransition.multiple([
445-
CssTransition.simple('opacity', '200ms'),
446448
CssTransition.simple(
447-
'transform',
448-
'300ms',
449+
CssTransitionProperty.opacity,
450+
CssDuration.ms(200),
451+
),
452+
CssTransition.simple(
453+
CssTransitionProperty.transform,
454+
CssDuration.ms(300),
449455
CssTimingFunction.easeInOut,
450456
),
451457
]).toCss(),

0 commit comments

Comments
 (0)