Skip to content

Commit b255eb7

Browse files
feat: typed Style API — CssBackground, CssGridTemplateColumns, accent-color, deprecate Style()
- Add CssBackground sealed class for the background shorthand property - Add CssGridTemplateColumns and CssTrackSize sealed classes for grid tracks - Add accent-color support via CssColor param in Style.typed() - Change Style.typed() background and gridTemplateColumns params from String to typed - Deprecate the untyped Style() constructor in favor of Style.typed() - Convert all usages across packages to Style.typed() - Bump spark_css to 1.0.0-alpha.5
1 parent 2e2c937 commit b255eb7

17 files changed

Lines changed: 713 additions & 37 deletions

packages/spark/lib/src/page/spark_page.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,12 @@ abstract class SparkPage<T> {
187187
/// ```dart
188188
/// @override
189189
/// Stylesheet? get inlineStyles => css({
190-
/// 'main': Style(maxWidth: '800px', margin: '0 auto', padding: '20px'),
191-
/// 'h1': Style(color: '#333'),
190+
/// 'main': Style.typed(
191+
/// maxWidth: CssLength.px(800),
192+
/// margin: CssSpacing.symmetric(CssLength.zero, CssLength.auto),
193+
/// padding: CssSpacing.all(CssLength.px(20)),
194+
/// ),
195+
/// 'h1': Style.typed(color: CssColor.hex('333')),
192196
/// });
193197
/// ```
194198
Stylesheet? get inlineStyles => null;

packages/spark/test/component/spark_component_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ class SimpleComponent extends SparkComponent {
1212
Map<String, String> get dumpedAttributes => {'data-test': 'true'};
1313

1414
@override
15-
Stylesheet? get adoptedStyleSheets => css({':host': Style(display: 'block')});
15+
Stylesheet? get adoptedStyleSheets =>
16+
css({':host': Style.typed(display: CssDisplay.block)});
1617
}
1718

1819
void main() {

packages/spark/test/minification_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void main() {
5050
await script.writeAsString('''
5151
import 'package:spark_framework/spark.dart';
5252
void main() {
53-
print(Style(color: 'red').toCss());
53+
print(Style.typed(color: CssColor.named('red')).toCss());
5454
}
5555
''');
5656

@@ -73,7 +73,7 @@ void main() {
7373
await script.writeAsString('''
7474
import 'package:spark_framework/spark.dart';
7575
void main() {
76-
print(Style(color: 'red').toCss());
76+
print(Style.typed(color: CssColor.named('red')).toCss());
7777
}
7878
''');
7979

packages/spark/test/server/render_page_structure_test.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@ void main() {
9191

9292
test('renders inline styles as Stylesheet', () {
9393
final stylesheet = Stylesheet({
94-
'body': Style(backgroundColor: 'red'),
95-
'.container': Style(padding: '10px'),
94+
'body': Style.typed(backgroundColor: CssColor.named('red')),
95+
'.container': Style.typed(
96+
padding: CssSpacing.all(CssLength.px(10)),
97+
),
9698
});
9799

98100
final html = renderPage(

packages/spark_css/CHANGELOG.md

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

3+
## 1.0.0-alpha.5
4+
5+
### Added
6+
7+
- **Feat**: Added `CssBackground` sealed class for the `background` shorthand property with `.none`, `.color()`, `.shorthand()` (assembles full shorthand with `position / size` slash syntax), `.layers()` (multiple backgrounds), plus `.variable()`, `.raw()`, and `.global()` escape hatches.
8+
- **Feat**: Added `CssGridTemplateColumns` sealed class for `grid-template-columns` with `.none`, `.subgrid`, `.tracks()`, `.repeat()`, `.autoFill()`, `.autoFit()`, plus `.variable()`, `.raw()`, and `.global()`.
9+
- **Feat**: Added `CssTrackSize` sealed class for individual grid track sizes with `.fr()`, `.length()`, `.minmax()`, `.fitContent()`, and `.raw()`.
10+
- **Feat**: Added `accent-color` CSS property support via `CssColor? accentColor` parameter in `Style.typed()`.
11+
12+
### Changed
13+
14+
- **Breaking Change**: `Style.typed()` `background` parameter changed from `String?` to `CssBackground?`.
15+
- **Breaking Change**: `Style.typed()` `gridTemplateColumns` parameter changed from `String?` to `CssGridTemplateColumns?`.
16+
17+
### Deprecated
18+
19+
- **Deprecated**: The `Style()` untyped constructor is now deprecated in favor of `Style.typed()`. All CSS properties are now available as typed parameters.
20+
321
## 1.0.0-alpha.4
422

523
### Added

packages/spark_css/README.md

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ A type-safe CSS style system for the Spark framework.
1313
- **CSS Variables**: Every value type supports `variable()` for CSS custom properties.
1414
- **Global Keywords**: Every value type supports `global()` for `inherit`, `initial`, `unset`, `revert`, and `revert-layer`.
1515
- **Filters & Transforms**: Full `CssFilter` and `CssTransform` APIs with composition support.
16-
- **Gradients & Backgrounds**: Linear and radial gradients, plus typed background-size, position, repeat, clip, origin, and attachment.
16+
- **Gradients & Backgrounds**: Linear and radial gradients, `CssBackground` shorthand, plus typed background-size, position, repeat, clip, origin, and attachment.
17+
- **Grid**: `CssGridTemplateColumns` and `CssTrackSize` for type-safe grid track definitions with `repeat()`, `auto-fill`, `auto-fit`, `minmax()`, and `fit-content()`.
1718
- **Shadows**: `CssBoxShadow` and `CssTextShadow` with multi-shadow support.
1819
- **Automatic Minification**: CSS output is minified in production builds via the `dart.vm.product` flag.
1920
- **Component Style Registry**: Server-side style deduplication via `componentStyles`.
@@ -260,6 +261,35 @@ Style.typed(
260261

261262
Typed background properties: `backgroundSize`, `backgroundPosition`, `backgroundRepeat`, `backgroundClip`, `backgroundOrigin`, `backgroundAttachment`.
262263

264+
`CssBackground` provides the `background` shorthand:
265+
266+
```dart
267+
// Simple color background
268+
Style.typed(background: CssBackground.color(CssColor.hex('f5f5f5')))
269+
270+
// Full shorthand with position/size slash syntax
271+
Style.typed(
272+
background: CssBackground.shorthand(
273+
image: CssBackgroundImage.url('bg.png'),
274+
position: CssBackgroundPosition.center,
275+
size: CssBackgroundSize.cover,
276+
repeat: CssBackgroundRepeat.noRepeat,
277+
color: CssColor.white,
278+
),
279+
)
280+
281+
// Multiple background layers
282+
Style.typed(
283+
background: CssBackground.layers([
284+
CssBackground.shorthand(
285+
image: CssBackgroundImage.url('overlay.png'),
286+
repeat: CssBackgroundRepeat.noRepeat,
287+
),
288+
CssBackground.color(CssColor.white),
289+
]),
290+
)
291+
```
292+
263293
### Transitions
264294

265295
`CssTransition` uses typed parameters for property names, durations, and timing functions:
@@ -377,6 +407,45 @@ height: CssLength.svh(100),
377407
height: CssLength.lvh(100),
378408
```
379409

410+
### Grid Template Columns
411+
412+
`CssGridTemplateColumns` and `CssTrackSize` provide type-safe grid track definitions:
413+
414+
```dart
415+
// Explicit tracks
416+
Style.typed(
417+
display: CssDisplay.grid,
418+
gridTemplateColumns: CssGridTemplateColumns.tracks([
419+
CssTrackSize.fr(1),
420+
CssTrackSize.fr(2),
421+
CssTrackSize.length(CssLength.px(200)),
422+
]),
423+
)
424+
425+
// repeat()
426+
Style.typed(
427+
gridTemplateColumns: CssGridTemplateColumns.repeat(3, [CssTrackSize.fr(1)]),
428+
)
429+
430+
// auto-fill with minmax
431+
Style.typed(
432+
gridTemplateColumns: CssGridTemplateColumns.autoFill([
433+
CssTrackSize.minmax(
434+
CssTrackSize.length(CssLength.px(200)),
435+
CssTrackSize.fr(1),
436+
),
437+
]),
438+
)
439+
```
440+
441+
### Accent Color
442+
443+
The `accent-color` CSS property is supported via `CssColor`:
444+
445+
```dart
446+
Style.typed(accentColor: CssColor.hex('0066ff'))
447+
```
448+
380449
### Custom Properties
381450

382451
For properties not covered by the typed constructors, use `.add()`:
@@ -385,7 +454,7 @@ For properties not covered by the typed constructors, use `.add()`:
385454
final style = Style.typed(
386455
display: CssDisplay.grid,
387456
);
388-
style.add('grid-template-columns', 'repeat(3, 1fr)');
457+
style.add('grid-auto-rows', 'minmax(100px, auto)');
389458
```
390459

391460
### Component Style Registry

packages/spark_css/benchmark/style_benchmark.dart

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,21 @@ class StyleBenchmark extends BenchmarkBase {
1111
// Create a moderately complex stylesheet
1212
final rules = <String, Style>{};
1313
for (var i = 0; i < 1000; i++) {
14-
rules['.item-$i'] = Style(
15-
color: 'red',
16-
backgroundColor: 'blue',
17-
margin: '10px',
18-
padding: '20px',
19-
display: 'flex',
20-
fontSize: '${i}px',
21-
width: '100%',
22-
height: '50px',
23-
borderRadius: '5px',
24-
border: '1px solid black',
14+
rules['.item-$i'] = Style.typed(
15+
color: CssColor.red,
16+
backgroundColor: CssColor.blue,
17+
margin: CssSpacing.all(CssLength.px(10)),
18+
padding: CssSpacing.all(CssLength.px(20)),
19+
display: CssDisplay.flex,
20+
fontSize: CssLength.px(i),
21+
width: CssLength.percent(100),
22+
height: CssLength.px(50),
23+
borderRadius: CssBorderRadius.all(CssLength.px(5)),
24+
border: CssBorder(
25+
width: CssLength.px(1),
26+
style: CssBorderStyle.solid,
27+
color: CssColor.black,
28+
),
2529
);
2630
}
2731
_stylesheet = css(rules);
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import 'css_value.dart';
2+
import 'css_color.dart';
3+
import 'css_background_image.dart';
4+
import 'css_background_position.dart';
5+
import 'css_background_size.dart';
6+
import 'css_background_repeat.dart';
7+
import 'css_background_attachment.dart';
8+
import 'css_background_origin.dart';
9+
import 'css_background_clip.dart';
10+
11+
/// CSS `background` shorthand property values.
12+
sealed class CssBackground implements CssValue {
13+
const CssBackground._();
14+
15+
/// The `none` keyword.
16+
static const CssBackground none = _CssBackgroundKeyword('none');
17+
18+
/// Simple color background.
19+
factory CssBackground.color(CssColor color) = _CssBackgroundColor;
20+
21+
/// Full background shorthand with optional components.
22+
///
23+
/// Assembles the shorthand per CSS spec:
24+
/// `<bg-image> <position> / <size> <repeat> <attachment> <origin> <clip> <color>`
25+
///
26+
/// The `position / size` slash syntax is used when both are provided.
27+
factory CssBackground.shorthand({
28+
CssBackgroundImage? image,
29+
CssBackgroundPosition? position,
30+
CssBackgroundSize? size,
31+
CssBackgroundRepeat? repeat,
32+
CssBackgroundAttachment? attachment,
33+
CssBackgroundOrigin? origin,
34+
CssBackgroundClip? clip,
35+
CssColor? color,
36+
}) = _CssBackgroundShorthand;
37+
38+
/// Multiple background layers (comma-separated).
39+
factory CssBackground.layers(List<CssBackground> layers) =
40+
_CssBackgroundLayers;
41+
42+
/// CSS variable reference.
43+
factory CssBackground.variable(String varName) = _CssBackgroundVariable;
44+
45+
/// Raw CSS value escape hatch.
46+
factory CssBackground.raw(String value) = _CssBackgroundRaw;
47+
48+
/// Global keyword (inherit, initial, unset, revert).
49+
factory CssBackground.global(CssGlobal global) = _CssBackgroundGlobal;
50+
}
51+
52+
final class _CssBackgroundKeyword extends CssBackground {
53+
final String keyword;
54+
const _CssBackgroundKeyword(this.keyword) : super._();
55+
56+
@override
57+
String toCss() => keyword;
58+
}
59+
60+
final class _CssBackgroundColor extends CssBackground {
61+
final CssColor color;
62+
const _CssBackgroundColor(this.color) : super._();
63+
64+
@override
65+
String toCss() => color.toCss();
66+
}
67+
68+
final class _CssBackgroundShorthand extends CssBackground {
69+
final CssBackgroundImage? image;
70+
final CssBackgroundPosition? position;
71+
final CssBackgroundSize? size;
72+
final CssBackgroundRepeat? repeat;
73+
final CssBackgroundAttachment? attachment;
74+
final CssBackgroundOrigin? origin;
75+
final CssBackgroundClip? clip;
76+
final CssColor? color;
77+
78+
const _CssBackgroundShorthand({
79+
this.image,
80+
this.position,
81+
this.size,
82+
this.repeat,
83+
this.attachment,
84+
this.origin,
85+
this.clip,
86+
this.color,
87+
}) : super._();
88+
89+
@override
90+
String toCss() {
91+
final parts = <String>[];
92+
93+
if (image != null) parts.add(image!.toCss());
94+
95+
if (position != null && size != null) {
96+
parts.add('${position!.toCss()} / ${size!.toCss()}');
97+
} else if (position != null) {
98+
parts.add(position!.toCss());
99+
} else if (size != null) {
100+
parts.add(size!.toCss());
101+
}
102+
103+
if (repeat != null) parts.add(repeat!.toCss());
104+
if (attachment != null) parts.add(attachment!.toCss());
105+
if (origin != null) parts.add(origin!.toCss());
106+
if (clip != null) parts.add(clip!.toCss());
107+
if (color != null) parts.add(color!.toCss());
108+
109+
return parts.join(' ');
110+
}
111+
}
112+
113+
final class _CssBackgroundLayers extends CssBackground {
114+
final List<CssBackground> layers;
115+
const _CssBackgroundLayers(this.layers) : super._();
116+
117+
@override
118+
String toCss() => layers.map((l) => l.toCss()).join(', ');
119+
}
120+
121+
final class _CssBackgroundVariable extends CssBackground {
122+
final String varName;
123+
const _CssBackgroundVariable(this.varName) : super._();
124+
125+
@override
126+
String toCss() => 'var(--$varName)';
127+
}
128+
129+
final class _CssBackgroundRaw extends CssBackground {
130+
final String value;
131+
const _CssBackgroundRaw(this.value) : super._();
132+
133+
@override
134+
String toCss() => value;
135+
}
136+
137+
final class _CssBackgroundGlobal extends CssBackground {
138+
final CssGlobal global;
139+
const _CssBackgroundGlobal(this.global) : super._();
140+
141+
@override
142+
String toCss() => global.toCss();
143+
}

0 commit comments

Comments
 (0)