Skip to content

Conversation

@faizahmaddae
Copy link
Contributor

Summary

This PR adds support for persisting text shadow properties when exporting and importing state history.

Problem

When a user adds a shadow to a text layer and saves the project, the shadow is lost when reopening the project because the shadow property was not being serialized/deserialized in the export/import flow.

Changes

  • Added 'shadow': 'sh' to kMinifiedLayerKeys for compact JSON export
  • Added shadow parsing in TextLayer.fromMap() to restore shadow on import
  • Added shadow serialization in TextLayer.toMap() and toMapFromReference() to export shadow

Shadow format in JSON

{
  "shadow": {
    "color": 3019893248,
    "blurRadius": 4.0,
    "offsetX": 2.0,
    "offsetY": 2.0
  }
}

Backward Compatibility

This change is fully backward compatible:

  • Projects saved without shadow will continue to work (shadow parsing is wrapped in try-catch)
  • Only adds new optional data to the export format

Testing

  • ✅ Added shadow to text layer
  • ✅ Saved project with state history
  • ✅ Reopened project - shadow correctly restored
  • ✅ Shadow visible and editable after reload

Removed hardcoded height: 0.0 from the editable TextField's style.
This preserves the original height from the TextStyle, ensuring proper
alignment between the editable text and its rounded background.

Previously, the forced height: 0.0 caused misalignment with fonts that
have custom line heights (e.g., Persian/Arabic fonts), resulting in
the background not properly fitting the text during editing.
- Added 'shadow': 'sh' to minified keys for compact JSON export
- Added shadow parsing in TextLayer.fromMap() to restore shadow on import
- Added shadow serialization in TextLayer.toMap() and toMapFromReference()

Shadow format in JSON:
{
  "shadow": {
    "color": <int>,
    "blurRadius": <double>,
    "offsetX": <double>,
    "offsetY": <double>
  }
}

This is backward compatible - projects without shadow will continue to work.
- Remove shadows: [] override in text_editor_input.dart that was clearing shadows
- Add finalStyle logic in layer_widget_text_item.dart to properly merge textStyle including shadows
Copy link
Owner

@hm21 hm21 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @faizahmaddae,

Thanks for creating the PR, that’s definitely a cool feature! I took a quick look and made just a few small changes locally but can’t push the commit to this PR, since it looks like maintainers are blocked from editing it. Here’s what I changed, feel free to either update the PR settings so I can push directly, or fix the points below yourself (would be much appreciated) what i do locally already:

  1. I noticed that when exporting a layer in toMap, it currently uses only the first shadow in the list. I updated it so we export the full list of shadows instead.
  2. I also saw you removed the hardcoded height: 0.0 from the textfield style. That value is actually important, since we had issues on various platforms where the text wasn’t perfectly centered without it. I’ve now added a textHeight option to the TextEditorStyle, so you can set it to null or any other value you prefer.

Let me know if that works for you, once you're good with it, I’ll go ahead and merge it :)

@faizahmaddae
Copy link
Contributor Author

Hi @hm21

Thanks for the feedback! I've pushed a commit with the following changes:

✅ Shadow export now uses the full list instead of just the first shadow
✅ Added textHeight property to TextEditorStyle (defaults to 0.0, can be set to null for default line height)
Let me know if anything else needs adjustment!

Copy link
Owner

@hm21 hm21 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @faizahmaddae

Thanks for checking it out so quickly. I just had a look but didn’t see any new commits here. What I did notice, though, is that in your other PR #732, the changes seem to be mixed, it includes both the fix and the updates for that PR.

However I do now a full review here, and added a few suggestions that you can apply directly if you agree with them.

As for PR #732, I’m not entirely sure what the exact fix is at the moment since it’s currently mixed with the code from this PR. I’m totally fine if you want to apply the changes here instead, or you can clean up PR #732 so it only includes the relevant fix. Totally up to you what you prefer :)

- Simplify shadow parsing using safeParseInt/safeParseDouble
- Use 'shadows' (plural) key instead of 'shadow' for list export
- Export full shadows list in both toMap and toMapFromReference
- Add fontWeight and shadows to layer_widget_text_item
- Use textHeight config in TextField style
@faizahmaddae
Copy link
Contributor Author

Hi @hm21,

Thanks for the detailed review! I've applied all your suggestions:

  • ✅ Simplified shadow parsing using safeParseInt/safeParseDouble with List.from().map() pattern
  • ✅ Using 'shadows' (plural) key throughout for list export
  • ✅ Exporting full shadows list in both toMap and toMapFromReference
  • ✅ Added fontWeight and shadows to layer_widget_text_item
  • ✅ Using textHeight config in TextField style

I've also closed PR #732 since all changes are now consolidated here with the proper implementation.

Let me know if anything else needs adjustment!

@faizahmaddae faizahmaddae requested a review from hm21 January 19, 2026 14:09
Copy link
Owner

@hm21 hm21 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thank you for fixing everything so quickly. I'll merge it now and create a new release :)

@hm21 hm21 merged commit 9ab0a64 into hm21:stable Jan 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants