Skip to content

Commit ee9f9fe

Browse files
committed
fix(css): normalize CSSOM properties and flush pending styles
1 parent 92b83dd commit ee9f9fe

3 files changed

Lines changed: 47 additions & 9 deletions

File tree

webf/lib/src/css/style_declaration.dart

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,13 @@ class CSSStyleDeclaration extends DynamicBindingObject
218218
/// Exposed for components (e.g., CSS variable resolver) that need to
219219
/// preserve importance when updating dependent properties.
220220
bool isImportant(String propertyName) {
221-
return _importants[propertyName] == true;
221+
return _importants[_normalizePropertyName(propertyName)] == true;
222222
}
223223

224224
bool get hasImportantDeclarations => _importants.isNotEmpty;
225225

226+
bool get hasPendingProperties => _pendingProperties.isNotEmpty;
227+
226228
bool get hasInheritedPendingProperty {
227229
return _pendingProperties.keys
228230
.any((key) => isInheritedPropertyString(_kebabize(key)));
@@ -243,6 +245,11 @@ class CSSStyleDeclaration extends DynamicBindingObject
243245
/// value is a String containing the value of the property.
244246
/// If not set, returns the empty string.
245247
String getPropertyValue(String propertyName) {
248+
propertyName = _normalizePropertyName(propertyName);
249+
return _getPropertyValueByNormalizedName(propertyName);
250+
}
251+
252+
String _getPropertyValueByNormalizedName(String propertyName) {
246253
// Get the latest pending value first.
247254
return _pendingProperties[propertyName]?.value ??
248255
_properties[propertyName]?.value ??
@@ -251,6 +258,11 @@ class CSSStyleDeclaration extends DynamicBindingObject
251258

252259
/// Returns the baseHref associated with a property value if available.
253260
String? getPropertyBaseHref(String propertyName) {
261+
propertyName = _normalizePropertyName(propertyName);
262+
return _getPropertyBaseHrefByNormalizedName(propertyName);
263+
}
264+
265+
String? _getPropertyBaseHrefByNormalizedName(String propertyName) {
254266
return _pendingProperties[propertyName]?.baseHref ??
255267
_properties[propertyName]?.baseHref;
256268
}
@@ -389,8 +401,8 @@ class CSSStyleDeclaration extends DynamicBindingObject
389401
final List<String> propertyNames = _structuralPropertyNames();
390402
return Object.hashAll(propertyNames.map((propertyName) => Object.hash(
391403
propertyName,
392-
getPropertyValue(propertyName),
393-
getPropertyBaseHref(propertyName),
404+
_getPropertyValueByNormalizedName(propertyName),
405+
_getPropertyBaseHrefByNormalizedName(propertyName),
394406
_importants[propertyName] == true,
395407
)));
396408
}
@@ -405,12 +417,12 @@ class CSSStyleDeclaration extends DynamicBindingObject
405417
for (int index = 0; index < propertyNames.length; index++) {
406418
final String propertyName = propertyNames[index];
407419
if (propertyName != otherPropertyNames[index]) return false;
408-
if (getPropertyValue(propertyName) !=
409-
other.getPropertyValue(propertyName)) {
420+
if (_getPropertyValueByNormalizedName(propertyName) !=
421+
other._getPropertyValueByNormalizedName(propertyName)) {
410422
return false;
411423
}
412-
if (getPropertyBaseHref(propertyName) !=
413-
other.getPropertyBaseHref(propertyName)) {
424+
if (_getPropertyBaseHrefByNormalizedName(propertyName) !=
425+
other._getPropertyBaseHrefByNormalizedName(propertyName)) {
414426
return false;
415427
}
416428
if ((_importants[propertyName] == true) !=
@@ -424,6 +436,7 @@ class CSSStyleDeclaration extends DynamicBindingObject
424436

425437
/// Removes a property from the CSS declaration.
426438
void removeProperty(String propertyName, [bool? isImportant]) {
439+
propertyName = _normalizePropertyName(propertyName);
427440
switch (propertyName) {
428441
case PADDING:
429442
return CSSStyleProperty.removeShorthandPadding(this, isImportant);
@@ -888,7 +901,7 @@ class CSSStyleDeclaration extends DynamicBindingObject
888901
String? baseHref,
889902
bool validate = true,
890903
}) {
891-
propertyName = propertyName.trim();
904+
propertyName = _normalizePropertyName(propertyName);
892905

893906
// Null or empty value means should be removed.
894907
if (isNullOrEmptyValue(value)) {
@@ -1561,3 +1574,14 @@ class CSSStyleDeclaration extends DynamicBindingObject
15611574
String _kebabize(String str) {
15621575
return kebabizeCamelCase(str);
15631576
}
1577+
1578+
String _normalizePropertyName(String propertyName) {
1579+
final String trimmed = propertyName.trim();
1580+
if (trimmed.isEmpty || trimmed.startsWith('--')) {
1581+
return trimmed;
1582+
}
1583+
if (trimmed.contains('-')) {
1584+
return camelize(trimmed.toLowerCase());
1585+
}
1586+
return trimmed;
1587+
}

webf/lib/src/dom/element.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2523,8 +2523,9 @@ abstract class Element extends ContainerNode
25232523
CSSStyleDeclaration newStyle = CSSStyleDeclaration();
25242524
applyStyle(newStyle);
25252525
bool hasInheritedPendingProperty = false;
2526+
final bool hadPendingProperties = style.hasPendingProperties;
25262527
final bool merged = style.merge(newStyle);
2527-
if (merged) {
2528+
if (merged || hadPendingProperties) {
25282529
hasInheritedPendingProperty = style.hasInheritedPendingProperty;
25292530
style.flushPendingProperties();
25302531
}

webf/test/src/css/style_declaration_merge_test.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@ void main() {
99
setupTest();
1010
});
1111

12+
group('CSSStyleDeclaration CSSOM property names', () {
13+
test('accepts kebab-case property names', () {
14+
final CSSStyleDeclaration style = CSSStyleDeclaration();
15+
16+
style.setProperty('background-color', 'blue', isImportant: true);
17+
18+
expect(style.getPropertyValue('background-color'), 'blue');
19+
expect(style.getPropertyValue(BACKGROUND_COLOR), 'blue');
20+
expect(style.isImportant('background-color'), isTrue);
21+
expect(style.isImportant(BACKGROUND_COLOR), isTrue);
22+
});
23+
});
24+
1225
group('CSSStyleDeclaration.union', () {
1326
test('adopts important declarations into an empty receiver', () {
1427
final CSSStyleDeclaration current = CSSStyleDeclaration();

0 commit comments

Comments
 (0)