UNPKG

prprompts-flutter-generator

Version:

AI-powered Flutter development with full automation + official extension support - Generate 32 security-audited guides & auto-implement in 2-3 hours. NEW v5.1: Official Claude Code plugin with hooks, Gemini TOML commands, Qwen MCP settings. Features: Comp

437 lines (364 loc) 10.1 kB
# JSX to Flutter Widget Tree Conversion Examples This document demonstrates the complete JSX to Flutter widget tree conversion implementation in `WidgetGenerator.js`. ## Basic Element Conversion ### View → Container ```jsx // React Native <View> <Text>Hello</Text> </View> // Flutter Container( child: Text('Hello') ) ``` ### Text with Content ```jsx // React <Text>Hello World</Text> // Flutter Text('Hello World') ``` ## Interactive Elements ### TouchableOpacity → InkWell ```jsx // React Native <TouchableOpacity onPress={handlePress}> <Text>Click Me</Text> </TouchableOpacity> // Flutter InkWell( onTap: handlePress, child: Text('Click Me') ) ``` ### Button → ElevatedButton ```jsx // React Native <Button title="Submit" onPress={handleSubmit} /> // Flutter ElevatedButton( onTap: handleSubmit, child: Text('Submit') ) ``` ### TextInput → TextField ```jsx // React Native <TextInput placeholder="Enter text" onChangeText={handleChange} secureTextEntry={true} /> // Flutter TextField( hintText: 'Enter text', onChanged: handleChange, obscureText: true ) ``` ## List Rendering ### Array.map() → ListView.builder ```jsx // React {items.map(item => ( <View key={item.id}> <Text>{item.name}</Text> </View> ))} // Flutter ListView.builder( itemCount: items.length, itemBuilder: (context, index) { final item = items[index]; return Container( child: Text(item.name) ); } ) ``` ### FlatList → ListView.builder ```jsx // React Native <FlatList data={users} renderItem={renderUser} /> // Flutter ListView.builder( itemCount: users.length, itemBuilder: (context, index) { final item = users[index]; return renderUser; } ) ``` ## Conditional Rendering ### Ternary Operator ```jsx // React {isVisible ? <Text>Visible</Text> : <Text>Hidden</Text>} // Flutter Builder( builder: (context) => isVisible ? Text('Visible') : Text('Hidden') ) ``` ### Logical AND ```jsx // React {showMessage && <Text>Message</Text>} // Flutter Builder( builder: (context) => showMessage ? Text('Message') : const SizedBox.shrink() ) ``` ## Layout Components ### ScrollView → SingleChildScrollView ```jsx // React Native <ScrollView> <View> <Text>Content</Text> </View> </ScrollView> // Flutter SingleChildScrollView( child: Container( child: Text('Content') ) ) ``` ### SafeAreaView → SafeArea ```jsx // React Native <SafeAreaView> <View> <Text>Content</Text> </View> </SafeAreaView> // Flutter SafeArea( child: Container( child: Text('Content') ) ) ``` ## Fragments ```jsx // React <> <Text>First</Text> <Text>Second</Text> </> // Flutter (no wrapper, children used directly) [ Text('First'), Text('Second') ] ``` ## Image Handling ### Network Image ```jsx // React <Image source={{uri: 'https://example.com/image.png'}} /> // Flutter Image( image: NetworkImage('https://example.com/image.png') ) ``` ### Asset Image ```jsx // React <Image source={require('./assets/logo.png')} /> // Flutter Image( image: AssetImage('./assets/logo.png') ) ``` ## Event Handler Mapping | React Event | Flutter Event | |-------------|---------------| | `onClick` | `onTap` | | `onPress` | `onTap` | | `onPressIn` | `onTapDown` | | `onPressOut` | `onTapUp` | | `onLongPress` | `onLongPress` | | `onChange` | `onChanged` | | `onChangeText` | `onChanged` | | `onSubmit` | `onSubmitted` | | `onSubmitEditing` | `onSubmitted` | | `onFocus` | `onFocusChange` | | `onBlur` | `onFocusChange` | ## Property Mapping | React Prop | Flutter Prop | |------------|--------------| | `placeholder` | `hintText` | | `numberOfLines` | `maxLines` | | `editable` | `enabled` | | `secureTextEntry` | `obscureText` | | `src` / `source` | `image` | | `testID` | `key` | | `accessibilityLabel` | `semanticLabel` | | `autoFocus` | `autofocus` | ## Complex Example ### Complete Component Conversion ```jsx // React Native function UserList({ users, onUserSelect }) { return ( <SafeAreaView> <View> <Text>Users</Text> {users.length > 0 ? ( users.map(user => ( <TouchableOpacity key={user.id} onPress={() => onUserSelect(user)} > <View> <Text>{user.name}</Text> <Text>{user.email}</Text> </View> </TouchableOpacity> )) ) : ( <Text>No users found</Text> )} </View> </SafeAreaView> ); } // Flutter SafeArea( child: Container( children: [ Text('Users'), Builder( builder: (context) => users.length > 0 ? ListView.builder( itemCount: users.length, itemBuilder: (context, index) { final user = users[index]; return InkWell( onTap: () => onUserSelect(user), child: Container( children: [ Text(user.name), Text(user.email) ] ) ); } ) : Text('No users found') ) ] ) ) ``` ## Supported JSX Node Types 1. **JSXElement** - Standard JSX elements (`<View>`, `<Text>`, etc.) 2. **JSXFragment** - Fragments (`<>...</>`) 3. **JSXText** - Text nodes (string content) 4. **JSXExpressionContainer** - Expressions in JSX (`{variable}`, `{condition && <Widget>}`) 5. **ConditionalExpression** - Ternary operators (`condition ? A : B`) 6. **LogicalExpression** - Logical AND (`condition && Widget`) 7. **CallExpression** - Function calls (`.map()` for lists) ## Widget Mappings (60+ Components) ### React Native - View, ScrollView, FlatList, SectionList, SafeAreaView - Text, TextInput - TouchableOpacity, TouchableHighlight, Pressable, Button - Image, ImageBackground - Modal, ActivityIndicator, Switch, Slider, Picker ### HTML Elements (React Web) - div, span, p, h1-h6 - input, button, textarea, select - ul, ol, li - img, a - nav, header, footer, section, article ### Flutter Widgets - Container, SingleChildScrollView, ListView.builder, SafeArea - Text, TextField - InkWell, GestureDetector, ElevatedButton - Image, Icon - Dialog, CircularProgressIndicator, Switch, Slider, DropdownButton ## Limitations & Future Enhancements ### Current Limitations 1. **Style conversion** - Basic style prop handling (placeholder for StyleExtractor integration) 2. **Spread attributes** - Limited support for `{...props}` syntax 3. **Custom components** - Passed through without conversion 4. **Complex expressions** - Some advanced JavaScript expressions may need manual adjustment ### Future Enhancements 1. **Full style integration** - Complete StyleExtractor integration for CSS/inline styles 2. **Animation conversion** - React animations to Flutter animations 3. **Navigation conversion** - React Router to Flutter Navigator 4. **State management** - Redux/MobX to BLoC/Provider 5. **Custom component mapping** - User-defined component mappings ## Testing All conversion features are covered by 43+ unit tests in: - `tests/refactoring/generators/WidgetGenerator.test.js` Run tests: ```bash npm test -- tests/refactoring/generators/WidgetGenerator.test.js ``` ## Implementation Details ### Key Methods 1. **`generateWidgetTree(jsxElement, context)`** - Main entry point for conversion 2. **`_handleJSXElement(jsxElement, context)`** - Convert JSX element to WidgetChild 3. **`_handleJSXExpression(expression, context)`** - Handle conditionals, lists, variables 4. **`_extractJSXProps(attributes, context)`** - Extract and convert props 5. **`_convertPropsToFlutter(props, widget, hasChildren)`** - Map React props to Flutter 6. **`_handleCallExpression(expression, context)`** - Convert `.map()` to ListView.builder 7. **`_handleConditionalExpression(expression, context)`** - Convert ternary operators 8. **`_handleLogicalExpression(expression, context)`** - Convert logical AND ### Data Structures - **WidgetChild** - Represents a Flutter widget node - **Properties** - Key-value pairs of widget properties - **Children** - Array of nested WidgetChild nodes ### AST Traversal Uses Babel's AST parser and types: - `@babel/parser` - Parse JSX to AST - `@babel/types` - AST node type checking - `@babel/generator` - Convert AST back to code - `@babel/traverse` - AST traversal utilities ## Example Usage in Code ```javascript const { WidgetGenerator } = require('./WidgetGenerator'); const parser = require('@babel/parser'); // Parse JSX const jsxCode = '<View><Text>Hello</Text></View>'; const ast = parser.parse(jsxCode, { sourceType: 'module', plugins: ['jsx'], }); // Generate widget tree const generator = new WidgetGenerator(); const widget = generator.generateWidgetTree(ast.program.body[0].expression); console.log(widget); // WidgetChild { // name: 'Container', // type: 'Container', // properties: {}, // children: [ // WidgetChild { // name: 'Text', // type: 'Text', // properties: { data: "'Hello'" }, // children: [] // } // ] // } ``` ## Integration with Refactoring Pipeline The `generateWidgetTree()` method integrates with the complete refactoring pipeline: 1. **ReactParser** → Parses React component to ComponentModel 2. **WidgetGenerator** → Converts ComponentModel to WidgetModel - Uses `generateWidgetTree()` to convert JSX to widget tree 3. **CodeGenerator** → Generates Flutter Dart code from WidgetModel 4. **Validation** → Validates generated code This creates a seamless React → Flutter conversion workflow.