Repository navigation
Conversation
# Summary Add custom style for foreground and background colors handling ## Test Plan Run the example app and experiment with applying foreground and background colors through the toolbar across different text styles. ## Screenshots / Videos https://github.com/user-attachments/assets/b922cb42-4911-4285-9385-4c4f6a6d7b9c ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ❌ | ## Checklist - [x] E2E tests are passing - [x] Required E2E tests have been added (if applicable)
# Summary Add custom style to support foreground and background colors ## Test Plan Run the example app and experiment with applying foreground and background colors through the toolbar across different text styles. ## Screenshots / Videos https://github.com/user-attachments/assets/d3ae479f-b274-415a-9bec-a0fc39e7d9cd ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ❌ | | Android | ✅ | ## Checklist - [x] E2E tests are passing - [X] Required E2E tests have been added (if applicable) --------- Co-authored-by: Krystian Sienkiewicz <krystian.sienkiewicz@swmansion.com>
# Summary Add custom style for foreground and background colors handling ## Test Plan - Run the example web app and experiment with applying foreground and background colors through the toolbar across different text styles. - Run yarn test:e2e:web to see if all the tests pass ## Screenshots / Videos https://github.com/user-attachments/assets/5490888b-7f2b-431d-99b0-36c15da1fd7d ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ❌ | | Android | ❌ | | Web | ✅ | ## Checklist - [X] E2E tests are passing - [x] Required E2E tests have been added (if applicable) --------- Co-authored-by: Krystian Sienkiewicz <krystian.sienkiewicz@swmansion.com>
# Summary Add fontSize and fontFamily to customStyle ## Test Plan Run example app and experiment with applying `fontSize` and `fontFamily` through the toolbar across different text styles. ## Screenshots / Videos https://github.com/user-attachments/assets/20adf200-2661-44bf-a931-1948e1419afa ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ❌ | | Web | ❌ | ## Checklist - [x] E2E tests are passing - [x] Required E2E tests have been added (if applicable) --------- Co-authored-by: Krystian Sienkiewicz <krystian.sienkiewicz@swmansion.com>
# Summary Add fontSize and fontFamily to customStyle ## Test Plan Run example app and experiment with applying `fontSize` and `fontFamily` through the toolbar across different text styles. ## Screenshots / Videos ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ❌ | | Android | ✅ | | Web | ❌ | ## Checklist - [x] E2E tests are passing - [X] Required E2E tests have been added (if applicable) --------- Co-authored-by: Krystian Sienkiewicz <krystian.sienkiewicz@swmansion.com>
# Summary Add fontSize and font Family to customStyle ## Test Plan Run example web app and experiment with applying `fontSize` and `fontFamily` through the toolbar across different text styles. ## Screenshots / Videos https://github.com/user-attachments/assets/29268496-e19d-4fb0-a8ea-2cc4e4c850dd ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ❌ | | Android | ❌ | | Web | ✅ | ## Checklist - [X] E2E tests are passing - [X] Required E2E tests have been added (if applicable) --------- Co-authored-by: Krystian Sienkiewicz <krystian.sienkiewicz@swmansion.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved HTML escaping, style preservation, Unicode deletion, and layout defects block approval.
18 open findings
HTML-escape serialized CSS style values · New Escape foreground and background values in HTML · New Escape font-family values in generated HTML · New Match span closures to their corresponding openings · New Use the first family in CSS font fallback lists · New Resolve nested span inheritance into non-overlapping runs · New Use current scaling when reconstructing custom spans · New Rebuild custom-size spans when scaling changes · New Invalidate layout after applying font styles · New Add visible focus indicators to style controls · New Add accessible labels and selection state to color swatches · New Make color swatches accessible buttons with labels · New Preserve font size and family during HTML normalization · New Support four-digit CSS hex colors · New Track nested custom styles with opening-span stacks · New Parse quoted style attributes using the matching delimiter · New Preserve inherited properties in nested style spans · New Delete complete grapheme clusters on Backspace · New
What changed in this PR
Adds custom colors, font sizes, and font families to the rich-text editor and viewer across iOS, Android, and web.
Changes:
- Introduces
setStyle()and custom-style selection state. - Extends platform rendering, HTML handling, and font scaling.
- Adds example controls and custom-style regression tests.
| File | Description |
|---|---|
| src/web/utils/useBaseFontFamily.ts | Reads inherited fonts. |
| src/web/tiptapWatchers/useOnChangeState.ts | Reports custom-style state. |
| src/web/styleConversion/enrichedStyleToCSSVariables.ts | Defines font fallback variables. |
| src/web/pmPlugins/StripMarksInCodeBlockPlugin.ts | Preserves custom-style marks. |
| src/web/normalization/tiptapHtmlNormalizer.ts | Normalizes exported colors. |
| src/web/normalization/prepareHtmlForWeb.ts | Adds viewer font fallbacks. |
| src/web/normalization/htmlNormalizer.ts | Preserves custom span styles. |
| src/web/normalization/colorNormalizer.ts | Converts color representations. |
| src/web/formats/EnrichedCustomStyle.ts | Implements custom-style marks. |
| src/web/EnrichedTextInput.tsx | Connects styling commands and fonts. |
| src/web/EnrichedText.tsx | Supplies viewer font fallbacks. |
| src/web/EnrichedText.css | Adjusts code backgrounds. |
| src/types.ts | Exposes styling API and state. |
| src/spec/EnrichedTextInputNativeComponent.ts | Extends native bridge contracts. |
| src/native/EnrichedTextInput.tsx | Serializes native styling commands. |
| ios/utils/StyleUtils.mm | Registers custom styles. |
| ios/textHtmlParser/TextHtmlParser.mm | Applies parsed viewer styles. |
| ios/styles/EnrichedTextStyles.mm | Implements viewer style subclass. |
| ios/styles/CustomStyle.mm | Applies and merges custom styles. |
| ios/interfaces/StyleTypeEnum.h | Adds custom-style identifier. |
| ios/interfaces/StyleHeaders.h | Declares custom-style methods. |
| ios/interfaces/StyleBase.mm | Clarifies priority comments. |
| ios/interfaces/EnrichedTextStyleHeaders.h | Declares viewer style subclass. |
| ios/interfaces/CustomStyleData.mm | Implements style data operations. |
| ios/interfaces/CustomStyleData.h | Defines custom-style data. |
| ios/inputHtmlParser/InputHtmlParser.mm | Applies imported editor styles. |
| ios/htmlParser/HtmlParser.mm | Parses and serializes custom spans. |
| ios/extensions/ColorExtension.mm | Adds CSS color conversion. |
| ios/extensions/ColorExtension.h | Declares color conversion methods. |
| ios/EnrichedTextInputView.mm | Handles styling commands and events. |
| ios/config/EnrichedConfig.mm | Centralizes font scaling. |
| ios/config/EnrichedConfig.h | Exposes font scaling helper. |
| cpp/tests/GumboParserTest.cpp | Tests colored-span normalization. |
| cpp/parser/GumboNormalizer.c | Preserves colored spans. |
| apps/example/src/screens/TestScreen.tsx | Adds keyboard-aware padding. |
| apps/example/src/hooks/useKeyboardHeight.ts | Tracks keyboard height. |
| apps/example/src/constants/editorConfig.ts | Initializes custom-style state. |
| apps/example/src/components/Toolbar.tsx | Adds styling controls. |
| apps/example/src/components/FontSizePickerRow.tsx | Adds font-size picker. |
| apps/example/src/components/FontFamilyPickerRow.tsx | Adds font-family picker. |
| apps/example/src/components/ColorPickerRow.tsx | Adds color picker. |
| apps/example/ios/Podfile.lock | Updates native package lock. |
| apps/example-web/src/components/Toolbar.tsx | Adds web styling controls. |
| apps/example-web/src/components/Toolbar.css | Styles web pickers. |
| android/src/main/java/com/swmansion/enriched/textinput/watchers/EnrichedTextWatcher.kt | Applies styles during editing. |
| android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpanState.kt | Reports custom-style values. |
| android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSelection.kt | Reads selection styles. |
| android/src/main/java/com/swmansion/enriched/textinput/styles/HtmlStyle.kt | Reuses background-opacity helper. |
| android/src/main/java/com/swmansion/enriched/textinput/styles/CustomStyles.kt | Applies and merges style updates. |
| android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedSpans.kt | Registers custom spans. |
| android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCustomStyleSpan.kt | Defines editor custom spans. |
| android/src/main/java/com/swmansion/enriched/textinput/MeasurementStore.kt | Supplies font measurement configuration. |
| android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt | Routes styling commands. |
| android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt | Connects custom-style handling. |
| android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputSpannableFactory.kt | Creates editor custom spans. |
| android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextCustomStyleSpan.kt | Defines viewer custom spans. |
| android/src/main/java/com/swmansion/enriched/text/MeasurementStore.kt | Supplies viewer font configuration. |
| android/src/main/java/com/swmansion/enriched/text/EnrichedTextView.kt | Configures viewer span factories. |
| android/src/main/java/com/swmansion/enriched/text/EnrichedTextStyle.kt | Reuses background-opacity helper. |
| android/src/main/java/com/swmansion/enriched/text/EnrichedTextSpanFactory.kt | Creates viewer custom spans. |
| android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCustomStyleSpan.kt | Renders custom fonts and colors. |
| android/src/main/java/com/swmansion/enriched/common/parser/EnrichedSpanFactory.kt | Extends span creation contract. |
| android/src/main/java/com/swmansion/enriched/common/parser/EnrichedParser.java | Imports and exports custom styles. |
| android/src/main/java/com/swmansion/enriched/common/parser/EnrichedColorParser.kt | Converts CSS colors. |
| android/src/main/java/com/swmansion/enriched/common/EnrichedSpanFlags.kt | Defines custom-style priority. |
| android/src/main/java/com/swmansion/enriched/common/CustomStyle.kt | Defines custom-style values. |
| android/src/main/java/com/swmansion/enriched/common/ColorUtils.kt | Shares background-opacity logic. |
| .playwright/tests/customStyleFonts.spec.ts | Tests web font styling. |
| .playwright/tests/customStyleColors.spec.ts | Tests web color styling. |
| .maestro/enrichedText/flows/custom_style_fonts_visual.yaml | Checks native viewer fonts. |
| .maestro/enrichedText/flows/custom_style_colors_visual.yaml | Checks native viewer colors. |
| .maestro/enrichedInput/flows/custom_style_fonts_visual.yaml | Checks native editor fonts. |
| .maestro/enrichedInput/flows/custom_style_colors_visual.yaml | Checks native editor colors. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| cssProps.append("font-family: ").append(fontFamily).append(";"); | ||
| } | ||
| } | ||
| out.append("<span style=\"").append(cssProps).append("\">"); |
Comment on lines
+869
to
+881
| if (has_fg) { | ||
| buffer_append_str(out, "color: "); | ||
| buffer_append(out, fg, fg_len); | ||
| } | ||
|
|
||
| if (has_fg && has_bg) { | ||
| buffer_append_str(out, "; "); | ||
| } | ||
|
|
||
| if (has_bg) { | ||
| buffer_append_str(out, "background-color: "); | ||
| buffer_append(out, bg, bg_len); | ||
| } |
| } | ||
| } | ||
| if (cssProps.length > 0) { | ||
| return [NSString stringWithFormat:@"span style=\"%@\"", cssProps]; |
Comment on lines
+1028
to
+1030
| if (!new CustomStyle(fg, bg, fontSize, fontFamily).isEmpty()) { | ||
| start(text, new CustomStyleMark(fg, bg, fontSize, fontFamily)); | ||
| } |
|
|
||
| private static String parseCssFontFamily(String raw) { | ||
| if (raw == null) return null; | ||
| String value = raw.trim(); |
| r = ((value >> 8) & 0xF) / 15.0; | ||
| g = ((value >> 4) & 0xF) / 15.0; | ||
| b = (value & 0xF) / 15.0; | ||
| } else if (len == 6) { |
Comment on lines
+840
to
+841
| } else if ([tagName isEqualToString:@"span"]) { | ||
| CustomStyleData *data = [self parseCustomStyleDataFromSpanParams:params]; |
| static dispatch_once_t onceToken; | ||
| dispatch_once(&onceToken, ^{ | ||
| styleAttrRegex = [NSRegularExpression | ||
| regularExpressionWithPattern:@"style\\s*=\\s*[\"']([^\"']*)[\"']" |
Comment on lines
+108
to
+109
| tag: 'span', | ||
| getAttrs: (el: HTMLElement) => { |
| // Cursor sits right at the plain-styled boundary. | ||
| // Handle deletion ourselves so Chrome's contenteditable | ||
| // normalization never touches the styled <span>. | ||
| const tr = state.tr.delete($from.pos - 1, $from.pos); |
exploIF
approved these changes
Oct 16, 2026
exploIF
left a comment
Collaborator
There was a problem hiding this comment.
Recent commits look good. Previous were already approved.
Please go through Copilot comments and address them if they make sense
2 tasks
# Summary Added documentation around the new `custom style` feature --------- Co-authored-by: Igor Furgała <74370735+exploIF@users.noreply.github.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Implements the custom style functionality. It introduces
backgroundColor,foregroundColor,fontSizeandfontFamilyformats. For more info, visit relevant sub-PRsCompatibility
Checklist