@@ -13,6 +13,8 @@ import {
1313} from "../common/commonTextHeightSpacing" ;
1414
1515export class FlutterTextBuilder extends FlutterDefaultBuilder {
16+ node ?: TextNode ;
17+
1618 constructor ( optChild : string = "" ) {
1719 super ( optChild ) ;
1820 }
@@ -22,6 +24,7 @@ export class FlutterTextBuilder extends FlutterDefaultBuilder {
2224 }
2325
2426 createText ( node : TextNode ) : this {
27+ this . node = node ;
2528 let alignHorizontal =
2629 node . textAlignHorizontal ?. toString ( ) ?. toLowerCase ( ) ?? "left" ;
2730 alignHorizontal =
@@ -106,6 +109,12 @@ export class FlutterTextBuilder extends FlutterDefaultBuilder {
106109 styleProperties . fontFeatures = `[FontFeature.enable("sups")]` ;
107110 }
108111
112+ // Add text-shadow if a drop shadow is applied
113+ const shadow = this . textShadow ( ) ;
114+ if ( shadow ) {
115+ styleProperties . shadows = shadow ;
116+ }
117+
109118 const style = generateWidgetCode ( "TextStyle" , styleProperties ) ;
110119
111120 let text = segment . characters ;
@@ -155,6 +164,10 @@ export class FlutterTextBuilder extends FlutterDefaultBuilder {
155164
156165 textAutoSize ( node : TextNode ) : this {
157166 this . child = wrapTextAutoResize ( node , this . child ) ;
167+ // First wrap with SizedBox/Expanded as before, then apply layer blur if any.
168+ let wrapped = wrapTextAutoResize ( node , this . child ) ;
169+ wrapped = wrapTextWithLayerBlur ( node , wrapped ) ;
170+ this . child = wrapped ;
158171 return this ;
159172 }
160173
@@ -165,6 +178,39 @@ export class FlutterTextBuilder extends FlutterDefaultBuilder {
165178 }
166179 return "" ;
167180 } ;
181+
182+ /**
183+ * New method to handle text shadow.
184+ * Checks if a drop shadow effect is applied to the node and
185+ * returns Flutter code for the TextStyle "shadows" property.
186+ */
187+ textShadow ( ) : string {
188+ if ( this . node && ( this . node as TextNode ) . effects ) {
189+ const effects = ( this . node as TextNode ) . effects ;
190+ const dropShadow = effects . find (
191+ ( effect ) =>
192+ effect . type === "DROP_SHADOW" && effect . visible !== false ,
193+ ) ;
194+ if ( dropShadow ) {
195+ const ds = dropShadow as DropShadowEffect ;
196+ const offsetX = Math . round ( ds . offset . x ) ;
197+ const offsetY = Math . round ( ds . offset . y ) ;
198+ const blurRadius = Math . round ( ds . radius ) ;
199+ const r = Math . round ( ds . color . r * 255 ) ;
200+ const g = Math . round ( ds . color . g * 255 ) ;
201+ const b = Math . round ( ds . color . b * 255 ) ;
202+ // Convert to hex for Flutter Color (e.g., Color(0xFF112233))
203+ const hex = ( ( 1 << 24 ) + ( r << 16 ) + ( g << 8 ) + b )
204+ . toString ( 16 )
205+ . slice ( 1 )
206+ . toUpperCase ( ) ;
207+ return `[Shadow(offset: Offset(${ offsetX } , ${ offsetY } ), blurRadius: ${ blurRadius } , color: Color(0xFF${ hex } ).withOpacity(${ ds . color . a . toFixed (
208+ 2 ,
209+ ) } ))]`;
210+ }
211+ }
212+ return "" ;
213+ }
168214}
169215
170216export const wrapTextAutoResize = ( node : TextNode , child : string ) : string => {
@@ -201,5 +247,25 @@ export const wrapTextAutoResize = (node: TextNode, child: string): string => {
201247 return child ;
202248} ;
203249
250+ // New helper to wrap with layer blur using Flutter's ImageFiltered widget.
251+ export const wrapTextWithLayerBlur = (
252+ node : TextNode ,
253+ child : string ,
254+ ) : string => {
255+ if ( node . effects ) {
256+ const blurEffect = node . effects . find (
257+ ( effect ) =>
258+ effect . type === "LAYER_BLUR" && effect . visible !== false && effect . radius > 0 ,
259+ ) ;
260+ if ( blurEffect ) {
261+ return generateWidgetCode ( "ImageFiltered" , {
262+ imageFilter : `ImageFilter.blur(sigmaX: ${ blurEffect . radius } , sigmaY: ${ blurEffect . radius } )` ,
263+ child : child ,
264+ } ) ;
265+ }
266+ }
267+ return child ;
268+ } ;
269+
204270export const parseTextAsCode = ( originalText : string ) =>
205271 originalText . replace ( / \n / g, "\\n" ) ;
0 commit comments