Skip to content

Commit f1d2073

Browse files
Merge pull request #99 from KLEAK-Development/feat/css-animation-property
feat: add typed CssAnimation property support
2 parents 5f584fe + a42b3b0 commit f1d2073

5 files changed

Lines changed: 530 additions & 0 deletions

File tree

packages/spark_css/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
- **Feat**: Added `CssGridTemplateColumns` sealed class for `grid-template-columns` with `.none`, `.subgrid`, `.tracks()`, `.repeat()`, `.autoFill()`, `.autoFit()`, plus `.variable()`, `.raw()`, and `.global()`.
99
- **Feat**: Added `CssTrackSize` sealed class for individual grid track sizes with `.fr()`, `.length()`, `.minmax()`, `.fitContent()`, and `.raw()`.
1010
- **Feat**: Added `accent-color` CSS property support via `CssColor? accentColor` parameter in `Style.typed()`.
11+
- **Feat**: Added `CssAnimation` sealed class for the `animation` shorthand property with `.none`, single animation (name, duration, timingFunction, delay, iterationCount, direction, fillMode, playState), `.multiple()`, plus `.variable()`, `.raw()`, and `.global()` escape hatches.
12+
- **Feat**: Added `CssAnimationDirection`, `CssAnimationFillMode`, `CssAnimationPlayState`, and `CssAnimationIterationCount` sealed classes for animation sub-properties. Reuses existing `CssDuration` and `CssTimingFunction` from `CssTransition`.
1113

1214
### Changed
1315

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
import 'css_transition.dart';
2+
import 'css_value.dart';
3+
4+
/// CSS animation-direction values.
5+
sealed class CssAnimationDirection implements CssValue {
6+
const CssAnimationDirection._();
7+
8+
static const CssAnimationDirection normal = _CssAnimationDirectionKeyword(
9+
'normal',
10+
);
11+
static const CssAnimationDirection reverse = _CssAnimationDirectionKeyword(
12+
'reverse',
13+
);
14+
static const CssAnimationDirection alternate = _CssAnimationDirectionKeyword(
15+
'alternate',
16+
);
17+
static const CssAnimationDirection alternateReverse =
18+
_CssAnimationDirectionKeyword('alternate-reverse');
19+
20+
/// CSS variable reference.
21+
factory CssAnimationDirection.variable(String varName) =
22+
_CssAnimationDirectionVariable;
23+
24+
/// Raw CSS value escape hatch.
25+
factory CssAnimationDirection.raw(String value) = _CssAnimationDirectionRaw;
26+
27+
/// Global keyword (inherit, initial, unset, revert).
28+
factory CssAnimationDirection.global(CssGlobal global) =
29+
_CssAnimationDirectionGlobal;
30+
}
31+
32+
final class _CssAnimationDirectionKeyword extends CssAnimationDirection {
33+
final String keyword;
34+
const _CssAnimationDirectionKeyword(this.keyword) : super._();
35+
36+
@override
37+
String toCss() => keyword;
38+
}
39+
40+
final class _CssAnimationDirectionVariable extends CssAnimationDirection {
41+
final String varName;
42+
const _CssAnimationDirectionVariable(this.varName) : super._();
43+
44+
@override
45+
String toCss() => 'var(--$varName)';
46+
}
47+
48+
final class _CssAnimationDirectionRaw extends CssAnimationDirection {
49+
final String value;
50+
const _CssAnimationDirectionRaw(this.value) : super._();
51+
52+
@override
53+
String toCss() => value;
54+
}
55+
56+
final class _CssAnimationDirectionGlobal extends CssAnimationDirection {
57+
final CssGlobal global;
58+
const _CssAnimationDirectionGlobal(this.global) : super._();
59+
60+
@override
61+
String toCss() => global.toCss();
62+
}
63+
64+
/// CSS animation-fill-mode values.
65+
sealed class CssAnimationFillMode implements CssValue {
66+
const CssAnimationFillMode._();
67+
68+
static const CssAnimationFillMode none = _CssAnimationFillModeKeyword('none');
69+
static const CssAnimationFillMode forwards = _CssAnimationFillModeKeyword(
70+
'forwards',
71+
);
72+
static const CssAnimationFillMode backwards = _CssAnimationFillModeKeyword(
73+
'backwards',
74+
);
75+
static const CssAnimationFillMode both = _CssAnimationFillModeKeyword('both');
76+
77+
/// CSS variable reference.
78+
factory CssAnimationFillMode.variable(String varName) =
79+
_CssAnimationFillModeVariable;
80+
81+
/// Raw CSS value escape hatch.
82+
factory CssAnimationFillMode.raw(String value) = _CssAnimationFillModeRaw;
83+
84+
/// Global keyword (inherit, initial, unset, revert).
85+
factory CssAnimationFillMode.global(CssGlobal global) =
86+
_CssAnimationFillModeGlobal;
87+
}
88+
89+
final class _CssAnimationFillModeKeyword extends CssAnimationFillMode {
90+
final String keyword;
91+
const _CssAnimationFillModeKeyword(this.keyword) : super._();
92+
93+
@override
94+
String toCss() => keyword;
95+
}
96+
97+
final class _CssAnimationFillModeVariable extends CssAnimationFillMode {
98+
final String varName;
99+
const _CssAnimationFillModeVariable(this.varName) : super._();
100+
101+
@override
102+
String toCss() => 'var(--$varName)';
103+
}
104+
105+
final class _CssAnimationFillModeRaw extends CssAnimationFillMode {
106+
final String value;
107+
const _CssAnimationFillModeRaw(this.value) : super._();
108+
109+
@override
110+
String toCss() => value;
111+
}
112+
113+
final class _CssAnimationFillModeGlobal extends CssAnimationFillMode {
114+
final CssGlobal global;
115+
const _CssAnimationFillModeGlobal(this.global) : super._();
116+
117+
@override
118+
String toCss() => global.toCss();
119+
}
120+
121+
/// CSS animation-play-state values.
122+
sealed class CssAnimationPlayState implements CssValue {
123+
const CssAnimationPlayState._();
124+
125+
static const CssAnimationPlayState running = _CssAnimationPlayStateKeyword(
126+
'running',
127+
);
128+
static const CssAnimationPlayState paused = _CssAnimationPlayStateKeyword(
129+
'paused',
130+
);
131+
132+
/// CSS variable reference.
133+
factory CssAnimationPlayState.variable(String varName) =
134+
_CssAnimationPlayStateVariable;
135+
136+
/// Raw CSS value escape hatch.
137+
factory CssAnimationPlayState.raw(String value) = _CssAnimationPlayStateRaw;
138+
139+
/// Global keyword (inherit, initial, unset, revert).
140+
factory CssAnimationPlayState.global(CssGlobal global) =
141+
_CssAnimationPlayStateGlobal;
142+
}
143+
144+
final class _CssAnimationPlayStateKeyword extends CssAnimationPlayState {
145+
final String keyword;
146+
const _CssAnimationPlayStateKeyword(this.keyword) : super._();
147+
148+
@override
149+
String toCss() => keyword;
150+
}
151+
152+
final class _CssAnimationPlayStateVariable extends CssAnimationPlayState {
153+
final String varName;
154+
const _CssAnimationPlayStateVariable(this.varName) : super._();
155+
156+
@override
157+
String toCss() => 'var(--$varName)';
158+
}
159+
160+
final class _CssAnimationPlayStateRaw extends CssAnimationPlayState {
161+
final String value;
162+
const _CssAnimationPlayStateRaw(this.value) : super._();
163+
164+
@override
165+
String toCss() => value;
166+
}
167+
168+
final class _CssAnimationPlayStateGlobal extends CssAnimationPlayState {
169+
final CssGlobal global;
170+
const _CssAnimationPlayStateGlobal(this.global) : super._();
171+
172+
@override
173+
String toCss() => global.toCss();
174+
}
175+
176+
/// CSS animation-iteration-count values.
177+
sealed class CssAnimationIterationCount implements CssValue {
178+
const CssAnimationIterationCount._();
179+
180+
static const CssAnimationIterationCount infinite =
181+
_CssAnimationIterationCountKeyword('infinite');
182+
183+
/// Numeric iteration count.
184+
factory CssAnimationIterationCount.count(num value) =
185+
_CssAnimationIterationCountNumber;
186+
187+
/// CSS variable reference.
188+
factory CssAnimationIterationCount.variable(String varName) =
189+
_CssAnimationIterationCountVariable;
190+
191+
/// Raw CSS value escape hatch.
192+
factory CssAnimationIterationCount.raw(String value) =
193+
_CssAnimationIterationCountRaw;
194+
195+
/// Global keyword (inherit, initial, unset, revert).
196+
factory CssAnimationIterationCount.global(CssGlobal global) =
197+
_CssAnimationIterationCountGlobal;
198+
}
199+
200+
final class _CssAnimationIterationCountKeyword
201+
extends CssAnimationIterationCount {
202+
final String keyword;
203+
const _CssAnimationIterationCountKeyword(this.keyword) : super._();
204+
205+
@override
206+
String toCss() => keyword;
207+
}
208+
209+
final class _CssAnimationIterationCountNumber
210+
extends CssAnimationIterationCount {
211+
final num value;
212+
const _CssAnimationIterationCountNumber(this.value) : super._();
213+
214+
@override
215+
String toCss() => '$value';
216+
}
217+
218+
final class _CssAnimationIterationCountVariable
219+
extends CssAnimationIterationCount {
220+
final String varName;
221+
const _CssAnimationIterationCountVariable(this.varName) : super._();
222+
223+
@override
224+
String toCss() => 'var(--$varName)';
225+
}
226+
227+
final class _CssAnimationIterationCountRaw extends CssAnimationIterationCount {
228+
final String value;
229+
const _CssAnimationIterationCountRaw(this.value) : super._();
230+
231+
@override
232+
String toCss() => value;
233+
}
234+
235+
final class _CssAnimationIterationCountGlobal
236+
extends CssAnimationIterationCount {
237+
final CssGlobal global;
238+
const _CssAnimationIterationCountGlobal(this.global) : super._();
239+
240+
@override
241+
String toCss() => global.toCss();
242+
}
243+
244+
/// CSS animation shorthand value.
245+
sealed class CssAnimation implements CssValue {
246+
const CssAnimation._();
247+
248+
static const CssAnimation none = _CssAnimationKeyword('none');
249+
250+
/// Single animation.
251+
factory CssAnimation({
252+
required String name,
253+
CssDuration? duration,
254+
CssTimingFunction? timingFunction,
255+
CssDuration? delay,
256+
CssAnimationIterationCount? iterationCount,
257+
CssAnimationDirection? direction,
258+
CssAnimationFillMode? fillMode,
259+
CssAnimationPlayState? playState,
260+
}) = _CssAnimationSingle;
261+
262+
/// Multiple animations.
263+
factory CssAnimation.multiple(List<CssAnimation> animations) =
264+
_CssAnimationMultiple;
265+
266+
/// CSS variable reference.
267+
factory CssAnimation.variable(String varName) = _CssAnimationVariable;
268+
269+
/// Raw CSS value escape hatch.
270+
factory CssAnimation.raw(String value) = _CssAnimationRaw;
271+
272+
/// Global keyword (inherit, initial, unset, revert).
273+
factory CssAnimation.global(CssGlobal global) = _CssAnimationGlobal;
274+
}
275+
276+
final class _CssAnimationKeyword extends CssAnimation {
277+
final String keyword;
278+
const _CssAnimationKeyword(this.keyword) : super._();
279+
280+
@override
281+
String toCss() => keyword;
282+
}
283+
284+
final class _CssAnimationSingle extends CssAnimation {
285+
final String name;
286+
final CssDuration? duration;
287+
final CssTimingFunction? timingFunction;
288+
final CssDuration? delay;
289+
final CssAnimationIterationCount? iterationCount;
290+
final CssAnimationDirection? direction;
291+
final CssAnimationFillMode? fillMode;
292+
final CssAnimationPlayState? playState;
293+
294+
const _CssAnimationSingle({
295+
required this.name,
296+
this.duration,
297+
this.timingFunction,
298+
this.delay,
299+
this.iterationCount,
300+
this.direction,
301+
this.fillMode,
302+
this.playState,
303+
}) : super._();
304+
305+
@override
306+
String toCss() {
307+
final parts = [name];
308+
if (duration != null) parts.add(duration!.toCss());
309+
if (timingFunction != null) parts.add(timingFunction!.toCss());
310+
if (delay != null) parts.add(delay!.toCss());
311+
if (iterationCount != null) parts.add(iterationCount!.toCss());
312+
if (direction != null) parts.add(direction!.toCss());
313+
if (fillMode != null) parts.add(fillMode!.toCss());
314+
if (playState != null) parts.add(playState!.toCss());
315+
return parts.join(' ');
316+
}
317+
}
318+
319+
final class _CssAnimationMultiple extends CssAnimation {
320+
final List<CssAnimation> animations;
321+
const _CssAnimationMultiple(this.animations) : super._();
322+
323+
@override
324+
String toCss() => animations.map((a) => a.toCss()).join(', ');
325+
}
326+
327+
final class _CssAnimationVariable extends CssAnimation {
328+
final String varName;
329+
const _CssAnimationVariable(this.varName) : super._();
330+
331+
@override
332+
String toCss() => 'var(--$varName)';
333+
}
334+
335+
final class _CssAnimationRaw extends CssAnimation {
336+
final String value;
337+
const _CssAnimationRaw(this.value) : super._();
338+
339+
@override
340+
String toCss() => value;
341+
}
342+
343+
final class _CssAnimationGlobal extends CssAnimation {
344+
final CssGlobal global;
345+
const _CssAnimationGlobal(this.global) : super._();
346+
347+
@override
348+
String toCss() => global.toCss();
349+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/// CSS type system for type-safe style declarations.
22
library;
33

4+
export 'css_animation.dart';
45
export 'css_angle.dart';
56
export 'css_background.dart';
67
export 'css_background_attachment.dart';

packages/spark_css/lib/src/style.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ class Style implements CssStyle {
312312
CssBackgroundOrigin? backgroundOrigin,
313313
CssBackgroundAttachment? backgroundAttachment,
314314
// Effects
315+
CssAnimation? animation,
315316
CssTransition? transition,
316317
CssTransform? transform,
317318
// Background shorthand
@@ -456,6 +457,7 @@ class Style implements CssStyle {
456457
}
457458

458459
// Effects
460+
if (animation != null) _properties['animation'] = animation.toCss();
459461
if (transition != null) _properties['transition'] = transition.toCss();
460462
if (transform != null) _properties['transform'] = transform.toCss();
461463

0 commit comments

Comments
 (0)