Skip to content

Commit 1f6e746

Browse files
daohoangsonclaude
andauthored
fix: support 3-value CSS shorthand for margin and padding (#1577)
Related to #1327 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ca27d62 commit 1f6e746

5 files changed

Lines changed: 96 additions & 4 deletions

File tree

packages/core/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,11 @@ These tags and their contents will be ignored:
169169
- font-style: italic/normal
170170
- font-weight: bold/normal/100..900
171171
- line-height: `normal`, number or value in `em`, `%`, `pt` and `px`
172-
- margin: 4 values, 2 values or 1 value in `em`, `pt` and `px`
172+
- margin: 4 values, 3 values, 2 values or 1 value in `em`, `pt` and `px`
173173
- margin-top, margin-right, margin-bottom, margin-left
174174
- margin-block-start, margin-block-end
175175
- margin-inline-start, margin-inline-end
176-
- padding: 4 values, 2 values or 1 value in `em`, `pt` and `px`
176+
- padding: 4 values, 3 values, 2 values or 1 value in `em`, `pt` and `px`
177177
- padding-top, padding-right, padding-bottom, padding-left
178178
- padding-block-start, padding-block-end
179179
- padding-inline-start, padding-inline-end

packages/core/lib/src/internal/parser/length.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ CssLengthBox? _parseCssLengthBoxAll(List<css.Expression> expressions) {
4545
bottom: tryParseCssLength(expressions[2]),
4646
inlineStart: tryParseCssLength(expressions[3]),
4747
);
48+
case 3:
49+
final inlineEnd = tryParseCssLength(expressions[1]);
50+
return CssLengthBox(
51+
top: tryParseCssLength(expressions[0]),
52+
inlineEnd: inlineEnd,
53+
bottom: tryParseCssLength(expressions[2]),
54+
inlineStart: inlineEnd,
55+
);
4856
case 2:
4957
final topBottom = tryParseCssLength(expressions[0]);
5058
final leftRight = tryParseCssLength(expressions[1]);

packages/core/test/style_margin_test.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,49 @@ void main() {
117117
});
118118
});
119119

120+
group('3 values', () {
121+
testWidgets('parses all', (WidgetTester tester) async {
122+
const html = '<div style="margin: 1px 2px 3px">Foo</div>';
123+
final explained = await explain(tester, html);
124+
expect(
125+
explained,
126+
equals(
127+
'[SizedBox:0.0x1.0],'
128+
'[HorizontalMargin:left=2,right=2,child=[CssBlock:child=[RichText:(:Foo)]]],'
129+
'[SizedBox:0.0x3.0]',
130+
),
131+
);
132+
});
133+
134+
testWidgets('parses all (rtl)', (WidgetTester tester) async {
135+
const html = '<div style="margin: 1px 2px 3px">Foo</div>';
136+
final explained = await explain(tester, html, rtl: true);
137+
expect(
138+
explained,
139+
equals(
140+
'[SizedBox:0.0x1.0],'
141+
'[HorizontalMargin:left=2,right=2,child='
142+
'[CssBlock:child=[RichText:dir=rtl,(:Foo)]]'
143+
'],'
144+
'[SizedBox:0.0x3.0]',
145+
),
146+
);
147+
});
148+
149+
testWidgets('parses top and bottom only', (WidgetTester tester) async {
150+
const html = '<div style="margin: 1px 0 3px">Foo</div>';
151+
final explained = await explain(tester, html);
152+
expect(
153+
explained,
154+
equals(
155+
'[SizedBox:0.0x1.0],'
156+
'[CssBlock:child=[RichText:(:Foo)]],'
157+
'[SizedBox:0.0x3.0]',
158+
),
159+
);
160+
});
161+
});
162+
120163
group('2 values', () {
121164
testWidgets('parses both', (WidgetTester tester) async {
122165
const html = '<div style="margin: 5px 10px">Foo</div>';

packages/core/test/style_padding_test.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,47 @@ void main() {
121121
});
122122
});
123123

124+
group('3 values', () {
125+
testWidgets('parses all', (WidgetTester tester) async {
126+
const html = '<div style="padding: 1px 2px 3px">Foo</div>';
127+
final explained = await explain(tester, html);
128+
expect(
129+
explained,
130+
equals(
131+
'[Padding:(1,2,3,2),child='
132+
'[CssBlock:child='
133+
'[RichText:(:Foo)]]]',
134+
),
135+
);
136+
});
137+
138+
testWidgets('parses all (rtl)', (WidgetTester tester) async {
139+
const html = '<div style="padding: 1px 2px 3px">Foo</div>';
140+
final explained = await explain(tester, html, rtl: true);
141+
expect(
142+
explained,
143+
equals(
144+
'[Padding:(1,2,3,2),child='
145+
'[CssBlock:child='
146+
'[RichText:dir=rtl,(:Foo)]]]',
147+
),
148+
);
149+
});
150+
151+
testWidgets('parses top and bottom only', (WidgetTester tester) async {
152+
const html = '<div style="padding: 1px 0 3px">Foo</div>';
153+
final explained = await explain(tester, html);
154+
expect(
155+
explained,
156+
equals(
157+
'[Padding:(1,0,3,0),child='
158+
'[CssBlock:child='
159+
'[RichText:(:Foo)]]]',
160+
),
161+
);
162+
});
163+
});
164+
124165
group('2 values', () {
125166
testWidgets('parses both', (WidgetTester tester) async {
126167
const html = '<div style="padding: 5px 10px">Foo</div>';

packages/enhanced/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,11 @@ These tags and their contents will be ignored:
189189
- font-style: italic/normal
190190
- font-weight: bold/normal/100..900
191191
- line-height: `normal`, number or value in `em`, `%`, `pt` and `px`
192-
- margin: 4 values, 2 values or 1 value in `em`, `pt` and `px`
192+
- margin: 4 values, 3 values, 2 values or 1 value in `em`, `pt` and `px`
193193
- margin-top, margin-right, margin-bottom, margin-left
194194
- margin-block-start, margin-block-end
195195
- margin-inline-start, margin-inline-end
196-
- padding: 4 values, 2 values or 1 value in `em`, `pt` and `px`
196+
- padding: 4 values, 3 values, 2 values or 1 value in `em`, `pt` and `px`
197197
- padding-top, padding-right, padding-bottom, padding-left
198198
- padding-block-start, padding-block-end
199199
- padding-inline-start, padding-inline-end

0 commit comments

Comments
 (0)