Skip to content

Commit 4b59250

Browse files
feat(css): integrate typed CSS properties into Style.typed
Integrates new typed CSS properties into the `spark_css` package. - Updates `css_types.dart` to export new type files. - Updates `Style.typed` constructor to use typed parameters (e.g., `CssBoxShadow`, `CssTransform`) instead of strings. - Adds `css_background_origin.dart`. - Updates `css_types_test.dart` to verify new properties and fix breaking changes.
1 parent 06ce9f1 commit 4b59250

4 files changed

Lines changed: 197 additions & 15 deletions

File tree

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import 'css_value.dart';
2+
3+
/// CSS background-origin property values.
4+
sealed class CssBackgroundOrigin implements CssValue {
5+
const CssBackgroundOrigin._();
6+
7+
/// The background extends to the outside edge of the border.
8+
static const CssBackgroundOrigin borderBox = _CssBackgroundOriginKeyword(
9+
'border-box',
10+
);
11+
12+
/// The background extends to the outside edge of the padding.
13+
static const CssBackgroundOrigin paddingBox = _CssBackgroundOriginKeyword(
14+
'padding-box',
15+
);
16+
17+
/// The background extends to the outside edge of the content.
18+
static const CssBackgroundOrigin contentBox = _CssBackgroundOriginKeyword(
19+
'content-box',
20+
);
21+
22+
/// Multiple background-origin values for multiple background images.
23+
factory CssBackgroundOrigin.multiple(List<CssBackgroundOrigin> values) =
24+
_CssBackgroundOriginMultiple;
25+
26+
/// CSS variable reference.
27+
factory CssBackgroundOrigin.variable(String varName) =
28+
_CssBackgroundOriginVariable;
29+
30+
/// Raw CSS value escape hatch.
31+
factory CssBackgroundOrigin.raw(String value) = _CssBackgroundOriginRaw;
32+
33+
/// Global keyword (inherit, initial, unset, revert).
34+
factory CssBackgroundOrigin.global(CssGlobal global) =
35+
_CssBackgroundOriginGlobal;
36+
}
37+
38+
final class _CssBackgroundOriginKeyword extends CssBackgroundOrigin {
39+
final String keyword;
40+
const _CssBackgroundOriginKeyword(this.keyword) : super._();
41+
42+
@override
43+
String toCss() => keyword;
44+
}
45+
46+
final class _CssBackgroundOriginMultiple extends CssBackgroundOrigin {
47+
final List<CssBackgroundOrigin> values;
48+
const _CssBackgroundOriginMultiple(this.values) : super._();
49+
50+
@override
51+
String toCss() => values.map((e) => e.toCss()).join(', ');
52+
}
53+
54+
final class _CssBackgroundOriginVariable extends CssBackgroundOrigin {
55+
final String varName;
56+
const _CssBackgroundOriginVariable(this.varName) : super._();
57+
58+
@override
59+
String toCss() => 'var(--$varName)';
60+
}
61+
62+
final class _CssBackgroundOriginRaw extends CssBackgroundOrigin {
63+
final String value;
64+
const _CssBackgroundOriginRaw(this.value) : super._();
65+
66+
@override
67+
String toCss() => value;
68+
}
69+
70+
final class _CssBackgroundOriginGlobal extends CssBackgroundOrigin {
71+
final CssGlobal global;
72+
const _CssBackgroundOriginGlobal(this.global) : super._();
73+
74+
@override
75+
String toCss() => global.toCss();
76+
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,17 @@ export 'css_cursor.dart';
1515
export 'css_number.dart';
1616
export 'css_border.dart';
1717
export 'css_transition.dart';
18+
export 'css_box_shadow.dart';
19+
export 'css_transform.dart';
20+
export 'css_text_shadow.dart';
21+
export 'css_filter.dart';
22+
export 'css_border_radius.dart';
23+
export 'css_flex_shorthand.dart';
24+
export 'css_outline.dart';
25+
export 'css_background_image.dart';
26+
export 'css_background_size.dart';
27+
export 'css_background_position.dart';
28+
export 'css_background_repeat.dart';
29+
export 'css_background_clip.dart';
30+
export 'css_background_origin.dart';
31+
export 'css_background_attachment.dart';

packages/spark_css/lib/src/style.dart

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ class Style implements CssStyle {
215215
/// // margin: CssSpacing.trbl(top, right, bottom, left),
216216
/// backgroundColor: CssColor.hex('f5f5f5'),
217217
/// color: CssColor.variable('text-primary'),
218-
/// borderRadius: CssLength.px(8),
218+
/// borderRadius: CssBorderRadius.all(CssLength.px(8)),
219219
/// )
220220
/// ```
221221
Style.typed({
@@ -260,6 +260,7 @@ class Style implements CssStyle {
260260
CssNumber? flexGrow,
261261
CssNumber? flexShrink,
262262
CssLength? gap,
263+
CssFlexShorthand? flex,
263264
// Typography
264265
CssLength? fontSize,
265266
CssFontWeight? fontWeight,
@@ -272,28 +273,39 @@ class Style implements CssStyle {
272273
CssWordBreak? wordBreak,
273274
CssNumber? lineHeight,
274275
CssLength? letterSpacing,
276+
CssTextShadow? textShadow,
275277
// Borders
276278
CssBorder? border,
277279
CssBorder? borderTop,
278280
CssBorder? borderRight,
279281
CssBorder? borderBottom,
280282
CssBorder? borderLeft,
281-
CssLength? borderRadius,
283+
CssBorderRadius? borderRadius,
284+
CssOutline? outline,
285+
CssLength? outlineOffset,
282286
// Visual
283287
CssNumber? opacity,
284288
CssOverflow? overflow,
285289
CssOverflow? overflowX,
286290
CssOverflow? overflowY,
287291
CssZIndex? zIndex,
288292
CssCursor? cursor,
293+
CssBoxShadow? boxShadow,
294+
CssFilter? filter,
295+
CssFilter? backdropFilter,
296+
// Backgrounds
297+
CssBackgroundImage? backgroundImage,
298+
CssBackgroundSize? backgroundSize,
299+
CssBackgroundPosition? backgroundPosition,
300+
CssBackgroundRepeat? backgroundRepeat,
301+
CssBackgroundClip? backgroundClip,
302+
CssBackgroundOrigin? backgroundOrigin,
303+
CssBackgroundAttachment? backgroundAttachment,
289304
// Effects
290305
CssTransition? transition,
306+
CssTransform? transform,
291307
// Complex properties (keep as String for flexibility)
292-
String? transform,
293-
String? boxShadow,
294-
String? backdropFilter,
295308
String? background,
296-
String? flex,
297309
String? gridTemplateColumns,
298310
Stylesheet? css,
299311
}) : stylesheet = css {
@@ -357,6 +369,7 @@ class Style implements CssStyle {
357369
if (flexGrow != null) _properties['flex-grow'] = flexGrow.toCss();
358370
if (flexShrink != null) _properties['flex-shrink'] = flexShrink.toCss();
359371
if (gap != null) _properties['gap'] = gap.toCss();
372+
if (flex != null) _properties['flex'] = flex.toCss();
360373

361374
// Typography
362375
if (fontSize != null) _properties['font-size'] = fontSize.toCss();
@@ -376,6 +389,7 @@ class Style implements CssStyle {
376389
if (letterSpacing != null) {
377390
_properties['letter-spacing'] = letterSpacing.toCss();
378391
}
392+
if (textShadow != null) _properties['text-shadow'] = textShadow.toCss();
379393

380394
// Borders
381395
if (border != null) _properties['border'] = border.toCss();
@@ -388,6 +402,10 @@ class Style implements CssStyle {
388402
if (borderRadius != null) {
389403
_properties['border-radius'] = borderRadius.toCss();
390404
}
405+
if (outline != null) _properties['outline'] = outline.toCss();
406+
if (outlineOffset != null) {
407+
_properties['outline-offset'] = outlineOffset.toCss();
408+
}
391409

392410
// Visual
393411
if (opacity != null) _properties['opacity'] = opacity.toCss();
@@ -396,16 +414,41 @@ class Style implements CssStyle {
396414
if (overflowY != null) _properties['overflow-y'] = overflowY.toCss();
397415
if (zIndex != null) _properties['z-index'] = zIndex.toCss();
398416
if (cursor != null) _properties['cursor'] = cursor.toCss();
417+
if (boxShadow != null) _properties['box-shadow'] = boxShadow.toCss();
418+
if (filter != null) _properties['filter'] = filter.toCss();
419+
if (backdropFilter != null) {
420+
_properties['backdrop-filter'] = backdropFilter.toCss();
421+
}
422+
423+
// Backgrounds
424+
if (backgroundImage != null) {
425+
_properties['background-image'] = backgroundImage.toCss();
426+
}
427+
if (backgroundSize != null) {
428+
_properties['background-size'] = backgroundSize.toCss();
429+
}
430+
if (backgroundPosition != null) {
431+
_properties['background-position'] = backgroundPosition.toCss();
432+
}
433+
if (backgroundRepeat != null) {
434+
_properties['background-repeat'] = backgroundRepeat.toCss();
435+
}
436+
if (backgroundClip != null) {
437+
_properties['background-clip'] = backgroundClip.toCss();
438+
}
439+
if (backgroundOrigin != null) {
440+
_properties['background-origin'] = backgroundOrigin.toCss();
441+
}
442+
if (backgroundAttachment != null) {
443+
_properties['background-attachment'] = backgroundAttachment.toCss();
444+
}
399445

400446
// Effects
401447
if (transition != null) _properties['transition'] = transition.toCss();
448+
if (transform != null) _properties['transform'] = transform.toCss();
402449

403450
// Complex properties (string-based)
404-
if (transform != null) _properties['transform'] = transform;
405-
if (boxShadow != null) _properties['box-shadow'] = boxShadow;
406-
if (backdropFilter != null) _properties['backdrop-filter'] = backdropFilter;
407451
if (background != null) _properties['background'] = background;
408-
if (flex != null) _properties['flex'] = flex;
409452
if (gridTemplateColumns != null) {
410453
_properties['grid-template-columns'] = gridTemplateColumns;
411454
}

packages/spark_css/test/css_types_test.dart

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ void main() {
387387
});
388388

389389
group('CssTransition', () {
390-
test('none outputs correct CSS', () {
390+
test('keywords output correct CSS', () {
391391
expect(CssTransition.none.toCss(), equals('none'));
392392
});
393393

@@ -545,7 +545,7 @@ void main() {
545545
style: CssBorderStyle.solid,
546546
color: CssColor.variable('border-color'),
547547
),
548-
borderRadius: CssLength.px(8),
548+
borderRadius: CssBorderRadius.all(CssLength.px(8)),
549549
);
550550
expect(style.toCss(), contains('border: 1px solid var(--border-color);'));
551551
expect(style.toCss(), contains('border-radius: 8px;'));
@@ -564,10 +564,15 @@ void main() {
564564
expect(style.toCss(), contains('cursor: pointer;'));
565565
});
566566

567-
test('renders string-based complex properties', () {
567+
test('renders complex properties', () {
568568
final style = Style.typed(
569-
transform: 'translateY(-2px)',
570-
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
569+
transform: CssTransform.translateY(CssLength.px(-2)),
570+
boxShadow: CssBoxShadow(
571+
x: CssLength.zero,
572+
y: CssLength.px(4),
573+
blur: CssLength.px(6),
574+
color: CssColor.rgba(0, 0, 0, 0.1),
575+
),
571576
gridTemplateColumns: 'repeat(3, 1fr)',
572577
);
573578
expect(style.toCss(), contains('transform: translateY(-2px);'));
@@ -578,6 +583,50 @@ void main() {
578583
expect(style.toCss(), contains('grid-template-columns: repeat(3, 1fr);'));
579584
});
580585

586+
test('renders new typed properties', () {
587+
final style = Style.typed(
588+
textShadow: CssTextShadow(
589+
x: CssLength.px(1),
590+
y: CssLength.px(1),
591+
color: CssColor.black,
592+
),
593+
filter: CssFilter.blur(CssLength.px(5)),
594+
backdropFilter: CssFilter.brightness(0.5),
595+
flex: CssFlexShorthand(grow: 1),
596+
outline: CssOutline(
597+
width: CssLength.px(2),
598+
style: CssBorderStyle.dashed,
599+
color: CssColor.red,
600+
),
601+
outlineOffset: CssLength.px(2),
602+
);
603+
expect(style.toCss(), contains('text-shadow: 1px 1px black;'));
604+
expect(style.toCss(), contains('filter: blur(5px);'));
605+
expect(style.toCss(), contains('backdrop-filter: brightness(0.5);'));
606+
expect(style.toCss(), contains('flex: 1;'));
607+
expect(style.toCss(), contains('outline: 2px dashed red;'));
608+
expect(style.toCss(), contains('outline-offset: 2px;'));
609+
});
610+
611+
test('renders background properties', () {
612+
final style = Style.typed(
613+
backgroundImage: CssBackgroundImage.url('bg.png'),
614+
backgroundSize: CssBackgroundSize.cover,
615+
backgroundPosition: CssBackgroundPosition.center,
616+
backgroundRepeat: CssBackgroundRepeat.noRepeat,
617+
backgroundClip: CssBackgroundClip.paddingBox,
618+
backgroundOrigin: CssBackgroundOrigin.contentBox,
619+
backgroundAttachment: CssBackgroundAttachment.fixed,
620+
);
621+
expect(style.toCss(), contains('background-image: url(bg.png);'));
622+
expect(style.toCss(), contains('background-size: cover;'));
623+
expect(style.toCss(), contains('background-position: center;'));
624+
expect(style.toCss(), contains('background-repeat: no-repeat;'));
625+
expect(style.toCss(), contains('background-clip: padding-box;'));
626+
expect(style.toCss(), contains('background-origin: content-box;'));
627+
expect(style.toCss(), contains('background-attachment: fixed;'));
628+
});
629+
581630
test('add method still works with v2', () {
582631
final style = Style.typed(color: CssColor.black)
583632
..add('--custom-property', 'custom-value');

0 commit comments

Comments
 (0)