syntaxify 0.2.0 copy "syntaxify: ^0.2.0" to clipboard
syntaxify: ^0.2.0 copied to clipboard

The Flutter UI Compiler. Define once, compile to any design system. , Build Your Next Flutter App Designs in Minutes, And Toggle Design Systems in Seconds.

Syntaxify ⚡ #

The Flutter UI Compiler. Define once, compile to any design system. Build Your Next Flutter App Designs in Minutes, And Toggle Design Systems in Seconds, throughout the app with Syntaxify.

Stop writing repetitive UI code. Define components once, render in any design system.

pub package GitHub stars License: MIT Buy Me A Coffee


👀 See It In Action #

Syntaxify Demo

Check out the example app - A working Flutter app demonstrating all features with live style switching!

cd example && flutter run

⚡ Quick Win: Generate Screens in Seconds #

// Create meta/login.screen.dart
final loginScreen = ScreenDefinition(
  id: 'login',
  appBar: App.appBar(title: 'Login'),
  layout: App.column(children: [
    App.text(text: 'Welcome', variant: TextVariant.headlineLarge),
    App.textField(label: 'Email', keyboardType: KeyboardType.email),
    App.textField(label: 'Password', obscureText: true),
    
    // New Interactive Components
    App.row(children: [
        App.checkbox(label: 'Remember me', binding: 'rememberMe'),
        App.toggle(label: 'Dark Mode', binding: 'isDarkMode'),
    ]),
    App.slider(min: 0, max: 100, binding: 'volume'),
    
    App.button(label: 'Login', onPressed: 'handleLogin'),
  ]),
);

Run: dart run syntaxify build Get: Complete Flutter screen in lib/screens/login_screen.dart


// GENERATED by Syntaxify

import 'package:flutter/material.dart';
import 'package:test_app/syntaxify/index.dart';
import 'package:test_app/syntaxify/design_system/design_system.dart';

class LoginScreen extends StatefulWidget {
  const LoginScreen({super.key, this.handleLogin});

  final VoidCallback? handleLogin;

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  late final TextEditingController _emailController;

  late final TextEditingController _passwordController;

  bool _rememberMe = false;

  bool _isDarkMode = false;

  double _volume = 0.0;

  @override
  void initState() {
    super.initState();
    _emailController = TextEditingController();
    _passwordController = TextEditingController();
  }

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: AppText(text: 'Login')),
      body: Column(
        children: [
          AppText(text: 'Welcome', variant: TextVariant.headlineMedium),
          AppInput(
            label: 'Email',
            controller: _emailController,
            keyboardType: TextInputType.emailAddress,
          ),
          AppInput(
            label: 'Password',
            controller: _passwordController,
            obscureText: true,
          ),
          Row(
            children: [
              AppCheckbox(
                value: _rememberMe,
                onChanged: (value) {
                  setState(() {
                    _rememberMe = value ?? false;
                  });
                },
              ),
              SizedBox(width: 8),
              Text('Remember me'),
            ],
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text('Dark Mode'),
              AppToggle(
                value: _isDarkMode,
                onChanged: (value) {
                  setState(() {
                    _isDarkMode = value;
                  });
                },
              ),
            ],
          ),
          AppSlider(
            value: _volume,
            onChanged: (value) {
              setState(() {
                _volume = value;
              });
            },
            min: 0.0,
            max: 100.0,
          ),
          AppButton(
            label: 'Login',
            onPressed: widget.handleLogin,
            variant: ButtonVariant.primary,
          ),
        ],
      ),
    );
  }
}


No boilerplate. No repetition. Just results.


🤔 Why Syntaxify? #

The Problem: Flutter's Design System Scalability Crisis #

Flutter developers face a fundamental dilemma when building production apps:

The Multi-Platform UI Duplication Problem:

  • Material Design for Android
  • Cupertino for iOS
  • Custom designs for brand identity

Traditional approach means writing everything 3 times:

// You write this for EVERY component!
Widget buildButton() {
  if (Platform.isIOS) {
    return CupertinoButton(
      onPressed: onPressed,
      child: Text(label),
    );
  } else if (useCustom) {
    return CustomButton(
      onPressed: onPressed,
      label: label,
    );
  } else {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(label),
    );
  }
}

Real-World Impact:

  • 🏢 Large Apps: 100+ screens, 1000+ components
  • 👥 Team Scale: Multiple developers, changing requirements
  • 🔄 Maintenance Nightmare: "Change all buttons to rounded corners" = touching 500+ files
  • 💸 Cost: "Toggle from Material to Cupertino" = rewriting the entire app
  • 🎨 Design Changes: "Our designer wants a custom look" = building everything from scratch

The Solution: Separation of WHAT and HOW #

Syntaxify delivers on Flutter's original promise: "write once, run anywhere" - but for design systems.

With Syntaxify:

// Write once
AppButton(label: 'Click Me', onPressed: ...)

// Renders appropriately everywhere
AppTheme(style: MaterialStyle())   // Material on Android
AppTheme(style: CupertinoStyle())  // iOS-native on iPhone
AppTheme(style: NeoStyle())        // Custom brand design

Change your entire app's design system in one line:

// Before: Material Design
AppTheme(style: MaterialStyle(), child: MyApp())

// After: iOS-native Cupertino
AppTheme(style: CupertinoStyle(), child: MyApp())
// Zero component code changes needed!

What Makes Syntaxify Different #

Most Flutter solutions offer partial fixes:

  • Widget libraries - Still manual integration, not design-system-aware
  • Themes - Only styling, not structure
  • Code generation - Not multi-platform aware

Syntaxify combines all three:

  • Code generation - Eliminate boilerplate
  • Design system architecture - WHAT vs HOW separation
  • Multi-platform rendering - One component, any design
  • Type-safe APIs - Compile-time safety

🎨 The Design System Architecture #

The Renderer Pattern #

Syntaxify uses a unique renderer pattern that separates concerns:

WHAT (Component Definition):

AppButton.primary(
  label: 'Click Me',
  onPressed: () => print('Hello!'),
)

HOW (Style Rendering):

  • Material: Renders as ElevatedButton with Material Design tokens
  • Cupertino: Renders as CupertinoButton with iOS styling
  • Neo: Renders with modern, neumorphic design

The Magic: Same component code, different visual output based on AppTheme:

AppTheme(
  style: MaterialStyle(),  // or CupertinoStyle() or NeoStyle()
  child: MaterialApp(home: YourApp()),
)

Why This Matters #

  1. Write Once, Render Anywhere - One component definition works across all design systems
  2. Easy Theme Switching - Change one line to switch your entire app's design
  3. Consistent Behavior - Button logic stays the same, only visuals change
  4. Custom Styles - Create your own design system by implementing DesignStyle

📦 What's Currently Available #

🌟 Screen Generation from .screen.dart Files (Star Feature!) #

The fastest way to build Flutter screens:

// meta/login.screen.dart
final loginScreen = ScreenDefinition(
  id: 'login',
  layout: App.column(children: [
    App.text(text: 'Welcome Back'),
    App.textField(label: 'Email'),
    App.button(label: 'Sign In', onPressed: 'handleLogin'),
  ]),
);

Run syntaxify build → Get a complete Flutter screen!

  • ✅ Generate entire screens from simple definitions
  • ✅ Editable after generation (you own the code)
  • ✅ Type-safe callbacks and imports
  • ✅ Proper structure and scaffolding
  • ✅ No boilerplate, no repetition

✅ Supported Components #

Syntaxify's component system is categorized into three types:

1. Interactive Nodes (Design System Wrappers)

These nodes render using the active DesignStyle (Material/Cupertino/Neo).

  • AppButton (App.button) - With variants (primary, secondary, etc.)
  • AppInput (App.textField) - Text fields with validation
  • AppCheckbox (App.checkbox) - Tri-state checkboxes
  • AppToggle (App.toggle) - Toggle switches
  • AppSlider (App.slider) - Range sliders
  • AppRadio (App.radio) - Radio groups

2. Structural Nodes (Layout)

These define the layout structure of your screen.

  • Column/Row (App.column, App.row)
  • Container (App.container)
  • Card (App.card)
  • ListView/GridView (App.listView, App.gridView)
  • Stack (App.stack)

3. Primitive Nodes (Display)

Basic display elements without complex interaction.

  • Text (App.text)
  • Icon (App.icon)
  • Image (App.image)
  • Divider (App.divider)

7 interactive components × 3 styles = 21 styled variants!

🛠️ Custom Components (NEW in v0.2.0) #

You can define any custom component (e.g., Card, Avatar), and Syntaxify will:

  • ✅ Generate the component class (AppCard)
  • ✅ Add a renderCard() method to DesignStyle
  • ✅ Generate stub renderers (MaterialCardRenderer, etc.) that you can implement

How It Works:

  1. Define your component in meta/card.meta.dart:
@SyntaxComponent(
  name: 'Card',
  variants: ['elevated', 'outlined'],
)
class CardMeta {
  final Widget child;
  final CardVariant variant;
}
  1. Run syntaxify build → Generator creates:

    • lib/syntaxify/generated/components/app_card.dart
    • lib/syntaxify/design_system/components/card/material_renderer.dart (stub)
    • Updates DesignStyle with Widget renderCard(...)
  2. Implement the renderer (optional - stubs work by default):

mixin MaterialCardRenderer on DesignStyle {
  @override
  Widget renderCard({required Widget child, required CardVariant variant}) {
    return Card(
      child: child,
      elevation: variant == CardVariant.elevated ? 4 : 0,
    );
  }
}

Result: Your custom component works with ALL design styles automatically!


🚀 Complete Getting Started Guide #

Step 1: Install Syntaxify #

Option A: From pub.flutter-io.cn (Recommended)

# pubspec.yaml
dev_dependencies:
  syntaxify: ^0.2.0

Then run:

dart pub get

Option B: From GitHub (Latest)

# pubspec.yaml
dev_dependencies:
  syntaxify:
    git:
      url: https://github.com/ihardk/syntaxify.git
      ref: v0.2.0
      path: generator

Optional: Global Installation

If you want syntaxify available system-wide (not just in your project):

dart pub global activate syntaxify

Then you can run syntaxify commands from anywhere. Otherwise, use dart run syntaxify in your project.

Step 2: Initialize Your Project #

cd your_flutter_project
dart run syntaxify init

This creates:

  • meta/ - Where you define component APIs
  • lib/syntaxify/design_system/ - Customizable design system

Step 3: Define Components #

Edit meta/button.meta.dart:

import 'package:syntaxify/syntaxify.dart';

@SyntaxComponent(description: 'A customizable button')
class ButtonMeta {
  /// The button label text
  @Required()
  final String label;

  /// The action to trigger (e.g. 'action:login')
  @Optional()
  final String? onPressed;

  /// Button variant (filled, outlined, etc)
  @Optional()
  final String? variant;

  /// Button size (sm, md, lg)
  @Optional()
  final String? size;

  /// Whether the button shows loading state
  @Optional()
  @Default('false')
  final bool isLoading;

  /// Whether the button is disabled
  @Optional()
  @Default('false')
  final bool isDisabled;
}

Step 4: Build #

dart run syntaxify build

This generates:

  • lib/syntaxify/generated/components/app_button.dart - The component
  • lib/syntaxify/design_system/ - Design system files (Material, Cupertino, Neo)
  • lib/syntaxify/index.dart - Barrel export

Step 5: Use in Your App #

import 'package:flutter/material.dart';
import 'package:your_app/syntaxify/index.dart';

void main() {
  runApp(
    AppTheme(
      style: MaterialStyle(),  // Try CupertinoStyle() or NeoStyle()!
      child: MaterialApp(
        home: Scaffold(
          body: Center(
            child: AppButton.primary(
              label: 'Click Me',
              onPressed: () => print('Hello from Syntaxify!'),
            ),
          ),
        ),
      ),
    ),
  );
}

Step 6: Generate Screens (Optional) #

Create meta/login.screen.dart:

import 'package:syntaxify/syntaxify.dart';

final loginScreen = ScreenDefinition(
  id: 'login',
  layout: App.column(children: [
    App.text(text: 'Welcome Back'),
    App.textField(label: 'Email', keyboardType: KeyboardType.emailAddress),
    App.textField(label: 'Password', obscureText: true),
    App.button(label: 'Sign In', onPressed: 'handleLogin'),
  ]),
);

Run dart run syntaxify build again - generates lib/screens/login_screen.dart (editable!)


🎯 Real-World Example #

Before Syntaxify (Manual Approach) #

Material Button:

ElevatedButton(
  onPressed: onPressed,
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.blue,
    padding: EdgeInsets.all(16),
  ),
  child: Text(label),
)

Cupertino Button:

CupertinoButton.filled(
  onPressed: onPressed,
  padding: EdgeInsets.all(16),
  child: Text(label),
)

Custom Button:

Container(
  decoration: BoxDecoration(
    gradient: LinearGradient(...),
    borderRadius: BorderRadius.circular(12),
    boxShadow: [BoxShadow(...)],
  ),
  child: Material(
    color: Colors.transparent,
    child: InkWell(
      onTap: onPressed,
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Text(label),
      ),
    ),
  ),
)

Problem: 3 different implementations, hard to maintain, inconsistent behavior.

After Syntaxify #

One Definition:

AppButton.primary(label: 'Submit', onPressed: handleSubmit)

Three Renderings:

  • Wrap with MaterialStyle() → Material Design
  • Wrap with CupertinoStyle() → iOS Design
  • Wrap with NeoStyle() → Modern Design

Result: Consistent API, different visuals, easy to switch.


📂 Project Structure #

your_project/
├── meta/                          # YOU EDIT: Component & screen definitions
│   ├── button.meta.dart
│   ├── input.meta.dart
│   ├── text.meta.dart
│   ├── login.screen.dart
│   └── app_icons.dart
│
└── lib/
    ├── screens/                   # EDITABLE: Generated screens
    │   └── login_screen.dart      # Generated once, then you own it
    │
    └── syntaxify/
        ├── design_system/         # CUSTOMIZABLE: Styles & tokens
        │   ├── design_system.dart
        │   ├── app_theme.dart
        │   ├── styles/
        │   │   ├── material_style.dart
        │   │   ├── cupertino_style.dart
        │   │   └── neo_style.dart
        │   └── tokens/
        │       ├── button_tokens.dart
        │       └── input_tokens.dart
        │
        ├── generated/             # DON'T EDIT: Auto-regenerated
        │   └── components/
        │       ├── app_button.dart
        │       ├── app_input.dart
        │       └── app_text.dart
        │
        └── index.dart             # Barrel export

📖 API Reference #

For detailed API documentation, see API Reference.

Quick Overview:

Component Description
AppButton Primary, secondary, outlined button variants
AppText Typography with 6 text style variants
AppInput Text fields with keyboard types & validation
AppCheckbox Checkboxes with design-aware styling
AppToggle Toggle switches
AppSlider Range sliders with custom themes
AppRadio Radio buttons

Design Styles: MaterialStyle(), CupertinoStyle(), NeoStyle()

Import: import 'package:your_app/syntaxify/index.dart';


🔄 Development Workflow #

  1. Define - Edit meta/*.meta.dart to define component APIs
  2. Build - Run dart run syntaxify build to generate implementations
  3. Use - Import from package:your_app/syntaxify/ and use
  4. Customize - Edit design system tokens in lib/syntaxify/design_system/
  5. Toggle Styles - Change AppTheme(style: ...) to try different designs

Understanding Generated Code #

Important: Two types of generated code with different lifecycles:

Components (Regenerate Every Build)

Location: lib/syntaxify/generated/components/ Behavior: Regenerated on EVERY syntaxify build Rule: ⚠️ DO NOT EDIT - Your changes will be lost!

// lib/syntaxify/generated/components/app_button.dart
// This file is REGENERATED on every build
class AppButton extends StatelessWidget {
  // Generated code - DO NOT MODIFY
}

Screens (Generate Once)

Location: lib/screens/ Behavior: Generated ONCE, then YOU own it Rule:FREELY EDIT - Won't be overwritten

// lib/screens/login_screen.dart
// Generated once, then it's yours to edit
class LoginScreen extends StatelessWidget {
  // Edit this freely - it won't be regenerated
}

What happens when you rebuild?

  • Components: Completely regenerated from meta files
  • Screens: Skipped (only generated if file doesn't exist)

🛠️ Advanced Usage #

For advanced topics, see the detailed documentation:


🐛 Troubleshooting #

Having issues? See Troubleshooting Guide for common errors and solutions.

Quick fixes:

  • TextVariant.headline → Use TextVariant.headlineMedium
  • KeyboardType.email → Use TextInputType.emailAddress
  • Component not updating? → Edit meta/*.meta.dart, not generated files

Need help? GitHub Issues


✨ Features #

  • AST-Based Generation - Type-safe, declarative UI definitions
  • Renderer Pattern - Separates WHAT (behavior) from HOW (rendering)
  • Multi-Style Support - Material, Cupertino, Neo (3 components currently, more coming)
  • Smart Defaults - Auto-detects project structure
  • Screen Generation - Generate editable screen scaffolds
  • Design Tokens - Centralized styling with tokens
  • Git-Friendly - Clean, readable generated code
  • Extensible - Create custom design styles by implementing DesignStyle

🗺️ Roadmap #

v0.2.0 (Current)

  • ✅ Core architecture with renderer pattern
  • ✅ 7 components (Button, Text, Input, Checkbox, Toggle, Slider, Radio)
  • ✅ 3 design styles (Material, Cupertino, Neo)
  • ✅ Screen generation
  • ✅ Configuration file (syntaxify.yaml)
  • ✅ Watch mode (--watch)
  • ✅ Dry run mode (--dry-run)
  • ✅ 303 tests passing

v0.3.0 (Next)

  • 🔄 More components
  • 🔄 Golden tests for visual regression
  • 🔄 Improved error messages

v1.0.0 (Future)

  • 🔮 Complete component library
  • 🔮 Theme editor UI
  • 🔮 VS Code extension
  • 🔮 Component marketplace

📚 Documentation #

Guide Description
Getting Started Installation & first steps
API Reference Component usage & options
Design System Renderer pattern & custom styles
Troubleshooting Common issues & solutions
User Manual Comprehensive user guide
Developer Manual Architecture & contributing

🤝 Contributing #

See Developer Manual for architecture details and contribution guidelines.

📄 License #

MIT License - See LICENSE for details


Built with ❤️ for Flutter developers who value consistency, productivity, and beautiful code

⭐ Star us on GitHub📦 pub.flutter-io.cn☕ Buy Me a Coffee

3
likes
80
points
476
downloads

Publisher

unverified uploader

Weekly Downloads

The Flutter UI Compiler. Define once, compile to any design system. , Build Your Next Flutter App Designs in Minutes, And Toggle Design Systems in Seconds.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

analyzer, args, code_builder, crypto, custom_lint_builder, dart_style, file, freezed_annotation, json_annotation, mason_logger, path, watcher, yaml

More

Packages that depend on syntaxify