Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions demo_app/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -620,10 +620,10 @@ packages:
dependency: transitive
description:
name: path_provider_android
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db"
url: "https://pub.dev"
source: hosted
version: "2.2.17"
version: "2.2.18"
path_provider_foundation:
dependency: transitive
description:
Expand Down Expand Up @@ -945,10 +945,10 @@ packages:
dependency: transitive
description:
name: url_launcher_android
sha256: "0aedad096a85b49df2e4725fa32118f9fa580f3b14af7a2d2221896a02cd5656"
sha256: "69ee86740f2847b9a4ba6cffa74ed12ce500bbe2b07f3dc1e643439da60637b7"
url: "https://pub.dev"
source: hosted
version: "6.3.17"
version: "6.3.18"
url_launcher_ios:
dependency: transitive
description:
Expand Down Expand Up @@ -1049,10 +1049,10 @@ packages:
dependency: transitive
description:
name: video_player_android
sha256: "53f3b57c7ac88c18e6074d0f94c7146e128c515f0a4503c3061b8e71dea3a0f2"
sha256: "59e5a457ddcc1688f39e9aef0efb62aa845cf0cbbac47e44ac9730dc079a2385"
url: "https://pub.dev"
source: hosted
version: "2.8.12"
version: "2.8.13"
video_player_avfoundation:
dependency: transitive
description:
Expand Down Expand Up @@ -1153,10 +1153,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_android
sha256: "0a42444056b24ed832bdf3442d65c5194f6416f7e782152384944053c2ecc9a3"
sha256: "9a25f6b4313978ba1c2cda03a242eea17848174912cfb4d2d8ee84a556f248e3"
url: "https://pub.dev"
source: hosted
version: "4.10.0"
version: "4.10.1"
webview_flutter_platform_interface:
dependency: transitive
description:
Expand Down
3 changes: 3 additions & 0 deletions packages/core/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
coverage/
pubspec.lock

# Test failures
test/failures/

# Miscellaneous
*.class
*.log
Expand Down
34 changes: 33 additions & 1 deletion packages/core/lib/src/core_widget_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,12 @@ class WidgetFactory extends WidgetFactoryResetter with AnchorWidgetFactory {
return buildText(tree, resolved, TextSpan(style: textStyle, text: text));
}

// If text is empty and listStyleType is not a predefined type,
// treat it as an empty string literal (no marker)
if (!_isPredefinedListStyleType(listStyleType)) {
return null;
}

switch (listStyleType) {
case kCssListStyleTypeCircle:
return HtmlListMarker.circle(textStyle);
Expand All @@ -396,6 +402,23 @@ class WidgetFactory extends WidgetFactoryResetter with AnchorWidgetFactory {
}
}

/// Checks if the given list style type is a predefined CSS keyword.
bool _isPredefinedListStyleType(String type) {
return const {
kCssListStyleTypeAlphaLower,
kCssListStyleTypeAlphaLatinLower,
kCssListStyleTypeAlphaUpper,
kCssListStyleTypeAlphaLatinUpper,
kCssListStyleTypeCircle,
kCssListStyleTypeDecimal,
kCssListStyleTypeDisc,
kCssListStyleTypeNone,
kCssListStyleTypeRomanLower,
kCssListStyleTypeRomanUpper,
kCssListStyleTypeSquare,
}.contains(type);
}

/// Builds [Padding].
Widget? buildPadding(
BuildTree tree,
Expand Down Expand Up @@ -550,11 +573,20 @@ class WidgetFactory extends WidgetFactoryResetter with AnchorWidgetFactory {
final roman = intToRomanNumerals(i);
return roman != null ? '$roman.' : '';
case kCssListStyleTypeNone:
default:
case kCssListStyleTypeCircle:
case kCssListStyleTypeDisc:
case kCssListStyleTypeSquare:
// These are handled by geometric markers in buildListMarker
return '';
default:
// For any unrecognized type, treat it as a string literal
// CSS parser has already extracted the content if it was quoted
return type;
}
}



/// Returns an [AssetImage].
ImageProvider? imageProviderFromAsset(String url) {
final uri = Uri.parse(url);
Expand Down
42 changes: 42 additions & 0 deletions packages/core/test/tag_li_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,48 @@ Future<void> main() async {
);
});
});

group('string literals', () {
testWidgets('renders double quoted string', (WidgetTester tester) async {
const html = '<ul style="list-style-type: &quot;① &quot;"><li>Foo</li></ul>';
final explained = await explain(tester, html);
expect(explained, equals(padding(item('① ', 'Foo'))));
});

testWidgets('renders single quoted string', (WidgetTester tester) async {
const html = "<ul style=\"list-style-type: '② '\"><li>Bar</li></ul>";
final explained = await explain(tester, html);
expect(explained, equals(padding(item('② ', 'Bar'))));
});

testWidgets('renders complex string with symbols', (WidgetTester tester) async {
const html = '<ul style="list-style-type: &quot;★ &quot;"><li>Special</li></ul>';
final explained = await explain(tester, html);
expect(explained, equals(padding(item('★ ', 'Special'))));
});

testWidgets('renders empty string', (WidgetTester tester) async {
const html = '<ul style="list-style-type: &quot;&quot;"><li>Empty</li></ul>';
final explained = await explain(tester, html);
expect(explained, equals(padding('[RichText:(:Empty)]')));
});

testWidgets('renders string on ordered list', (WidgetTester tester) async {
const html = '<ol style="list-style-type: &quot;Step &quot;"><li>One</li><li>Two</li></ol>';
final explained = await explain(tester, html);
expect(
explained,
equals(
padding(
list([
item('Step ', 'One'),
item('Step ', 'Two'),
]),
),
),
);
});
});
});

group('padding-inline-start', () {
Expand Down
Loading