Skip to content

Commit 662c917

Browse files
feat(iOS): normalizing html (#435)
# Summary Integrates [gumbo-parser](https://codeberg.org/gumbo-parser/gumbo-parser) to normalize external HTML (Google Docs, Word, web pages) into the canonical tag subset our enriched parser understands. If an unsupported tag is encountered (for example: `<table>`), it will be omitted while preserving and keeping its text content. Nested structures will be flattened where necessary to match the constraints of the enriched format. ### Changes - Added `gumbo-parser.h` amalgamation header - Implemented `gumbo_normalizer.c` — converts arbitrary HTML into canonical tags (`<b>`, `<i>`, `<u>`, `<s>`, `<p>`, `<br>`, lists, headings, etc.) - iOS: integrated through podspec, used in `InputParser.mm` - Controlled by `useHtmlNormalizer` prop (off by default) - Added [gtest](https://google.github.io/googletest/) and `GumboParserTest.cpp` test suite covering tag remapping, span styles, tables, lists ## Test Plan 1. Run example app 2. Try to paste rich content from google docs, slack, gmail 3. Pasted rich content should look the same like in external app ## Screenshots / Videos https://github.com/user-attachments/assets/ae37561d-31f6-45f5-9c07-9e6e23f723cb ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ❌ | ---------
1 parent e420a00 commit 662c917

19 files changed

Lines changed: 35400 additions & 7 deletions

ReactNativeEnriched.podspec

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ Pod::Spec.new do |s|
1313
s.platforms = { :ios => min_ios_version_supported }
1414
s.source = { :git => "https://github.com/software-mansion/react-native-enriched.git", :tag => "#{s.version}" }
1515

16-
s.source_files = "ios/**/*.{h,m,mm,cpp}"
16+
s.source_files = ["ios/**/*.{h,m,mm,cpp}", "cpp/**/*.{h,hpp,c,cpp}"]
17+
s.exclude_files = ["cpp/tests/**"]
1718
s.private_header_files = "ios/**/*.h"
19+
s.pod_target_xcconfig = {
20+
'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}/cpp/parser" "${PODS_TARGET_SRCROOT}/cpp/GumboParser"'
21+
}
1822

1923
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
2024
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.

android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,13 @@ class EnrichedTextInputViewManager :
272272
// no-op
273273
}
274274

275+
override fun setUseHtmlNormalizer(
276+
view: EnrichedTextInputView?,
277+
value: Boolean,
278+
) {
279+
// no-op
280+
}
281+
275282
override fun focus(view: EnrichedTextInputView?) {
276283
view?.requestFocusProgrammatically()
277284
}

apps/example/ios/Podfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2064,7 +2064,7 @@ EXTERNAL SOURCES:
20642064

20652065
SPEC CHECKSUMS:
20662066
FBLazyVector: c12d2108050e27952983d565a232f6f7b1ad5e69
2067-
hermes-engine: 57506c1404e8b80c5386de18743e0d02c8d4f681
2067+
hermes-engine: e5ffaed830497fff782ee4c30c3f8ea61123bf13
20682068
RCTDeprecation: 3280799c14232a56e5a44f92981a8ee33bc69fd9
20692069
RCTRequired: 9854a51b0f65ccf43ea0b744df4d70fce339db32
20702070
RCTSwiftUI: 96986e49a4fdc2c2103929dee2641e1b57edf33d
@@ -2073,7 +2073,7 @@ SPEC CHECKSUMS:
20732073
React: 7ef36630d07638043a134a7dd2ec17e0be10fc3c
20742074
React-callinvoker: af4e8fe1d60ab63dd8d74c2a68988064c2848954
20752075
React-Core: c0fb1df65eb0ed7a8633841831f05f93c3eb3aff
2076-
React-Core-prebuilt: cd92350bf2041dde22a9bc0b8984d9c70d179ca1
2076+
React-Core-prebuilt: 65fb7126c1a54707eac825da605bd09a5a6ec76a
20772077
React-CoreModules: 7dfe7962360355f1547c85ab52e1fc4b57f17127
20782078
React-cxxreact: 9e9c7f1710bc58abebf924813b5e825b99adb8e5
20792079
React-debug: 38389b86e3570558ec73dd4cbc0cd2f2eec47a51
@@ -2135,8 +2135,8 @@ SPEC CHECKSUMS:
21352135
ReactAppDependencyProvider: 625d2f6d9d5ef01acc9dfe2b5385504bbffd2ad0
21362136
ReactCodegen: 27937747ddc743fcb66a8dc19e8edf60188d94cc
21372137
ReactCommon: cc0e38600f82487c5fe5d29150abb6fa9d981986
2138-
ReactNativeDependencies: cebf665879bab2908201494cc5a9760dbdf0a637
2139-
ReactNativeEnriched: cea43cfd577befb70d99a8dde914004625a9a9d0
2138+
ReactNativeDependencies: d49d9d865b7eb4a9884164a4b6f50440edb37e01
2139+
ReactNativeEnriched: 955ecbffda0ae4e899dcec807fb4f9c0d1fa04e0
21402140
Yoga: 772166513f9cd2d61a6251d0dacbbfaa5b537479
21412141

21422142
PODFILE CHECKSUM: 88c10840d02e9884b2dc3f457d5120f83ac3803b

apps/example/src/App.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ export default function App() {
348348
ANDROID_EXPERIMENTAL_SYNCHRONOUS_EVENTS
349349
}
350350
onPasteImages={(e) => handlePasteImagesEvent(e.nativeEvent)}
351+
useHtmlNormalizer
351352
/>
352353
<Toolbar
353354
stylesState={stylesState}

cpp/CMakeLists.txt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
cmake_minimum_required(VERSION 3.14)
2+
project(gumbo_parser_tests C CXX)
3+
4+
# ── Fetch Google Test ────────────────────────────────────────────────────────
5+
include(FetchContent)
6+
FetchContent_Declare(
7+
googletest
8+
GIT_REPOSITORY https://github.com/google/googletest.git
9+
GIT_TAG v1.17.0
10+
)
11+
# For Windows: Prevent overriding the parent project's compiler/linker settings
12+
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
13+
FetchContent_MakeAvailable(googletest)
14+
15+
# ── Shared library: gumbo normalizer + C++ wrapper ──────────────────────────
16+
add_library(gumbo_normalizer_lib SHARED
17+
parser/GumboNormalizer.c
18+
parser/GumboParser.cpp
19+
)
20+
21+
target_include_directories(gumbo_normalizer_lib PUBLIC
22+
${CMAKE_CURRENT_SOURCE_DIR}/GumboParser
23+
${CMAKE_CURRENT_SOURCE_DIR}/parser
24+
)
25+
26+
# Compile the C file as C99, C++ files as C++17
27+
set_source_files_properties(
28+
parser/GumboNormalizer.c
29+
PROPERTIES LANGUAGE C
30+
COMPILE_FLAGS "-std=c99"
31+
)
32+
33+
target_compile_options(gumbo_normalizer_lib PRIVATE
34+
$<$<COMPILE_LANGUAGE:CXX>:-std=c++17>
35+
)
36+
37+
# ── Test executable ──────────────────────────────────────────────────────────
38+
enable_testing()
39+
40+
add_executable(gumbo_parser_tests
41+
tests/GumboParserTest.cpp
42+
)
43+
44+
target_link_libraries(gumbo_parser_tests PRIVATE
45+
gumbo_normalizer_lib
46+
GTest::gtest_main
47+
)
48+
49+
include(GoogleTest)
50+
gtest_discover_tests(gumbo_parser_tests)

0 commit comments

Comments
 (0)