sdui_library 0.0.1 copy "sdui_library: ^0.0.1" to clipboard
sdui_library: ^0.0.1 copied to clipboard

Server-Driven UI library for Flutter — render widgets from JSON and export widget trees to JSON via CLI.

example/lib/main.dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:sdui_library/sdui_library.dart';
import 'sdui_widgets/sdui_custom_widgets.dart';

void main() {
  // Register custom widgets scaffolded by `dart run sdui add-widget`.
  registerCustomWidgets();

  // Register an inline custom widget (old-style, still supported).
  SduiParser.registerWidget('MyBadge', (json) {
    final props = (json['properties'] as Map<String, dynamic>?) ?? {};
    final label = props['label'] as String? ?? '';
    final color = parseColor(props['color']);
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
      decoration: BoxDecoration(
        color: color,
        borderRadius: BorderRadius.circular(20),
      ),
      child: Text(
        label,
        style: const TextStyle(
          color: Colors.white,
          fontSize: 12,
          fontWeight: FontWeight.w600,
        ),
      ),
    );
  });

  runApp(const SduiExampleApp());
}

// ─── Sample JSON Definitions ───────────────────────────────────────────────────

const Map<String, dynamic> profileCardJson = {
  "widget": "Card",
  "properties": {"elevation": 6, "borderRadius": 20, "margin": 0},
  "child": {
    "widget": "Container",
    "properties": {
      "padding": 20,
      "gradient": {
        "type": "linear",
        "colors": ["#6C63FF", "#3B82F6"],
        "begin": "topLeft",
        "end": "bottomRight",
      },
      "borderRadius": 20,
    },
    "child": {
      "widget": "Column",
      "properties": {"crossAxisAlignment": "start", "mainAxisSize": "min"},
      "children": [
        {
          "widget": "Row",
          "properties": {"mainAxisAlignment": "spaceBetween"},
          "children": [
            {
              "widget": "Column",
              "properties": {
                "crossAxisAlignment": "start",
                "mainAxisSize": "min",
              },
              "children": [
                {
                  "widget": "Text",
                  "properties": {
                    "data": "Vishnu Prakash",
                    "fontSize": 22,
                    "fontWeight": "bold",
                    "color": "#FFFFFF",
                  },
                },
                {
                  "widget": "Text",
                  "properties": {
                    "data": "Flutter Developer",
                    "fontSize": 14,
                    "color": "#C7D2FE",
                  },
                },
              ],
            },
            {
              "widget": "Icon",
              "properties": {"icon": "person", "color": "#FFFFFF", "size": 40},
            },
          ],
        },
        {
          "widget": "Container",
          "properties": {"height": 16},
        },
        {
          "widget": "Row",
          "properties": {"mainAxisAlignment": "start"},
          "children": [
            {
              "widget": "MyBadge",
              "properties": {"label": "Pro", "color": "#22C55E"},
            },
            {
              "widget": "Container",
              "properties": {"width": 8},
            },
            {
              "widget": "MyBadge",
              "properties": {"label": "Verified", "color": "#F59E0B"},
            },
          ],
        },
      ],
    },
  },
};

const Map<String, dynamic> statsRowJson = {
  "widget": "Row",
  "properties": {"mainAxisAlignment": "spaceBetween"},
  "children": [
    {
      "widget": "Card",
      "properties": {"elevation": 3, "borderRadius": 16, "margin": 0},
      "child": {
        "widget": "Container",
        "properties": {"padding": 16, "width": 100},
        "child": {
          "widget": "Column",
          "properties": {"crossAxisAlignment": "center", "mainAxisSize": "min"},
          "children": [
            {
              "widget": "Icon",
              "properties": {
                "icon": "trending_up",
                "color": "#22C55E",
                "size": 28,
              },
            },
            {
              "widget": "Text",
              "properties": {
                "data": "2.4K",
                "fontSize": 20,
                "fontWeight": "bold",
                "color": "#1F2937",
              },
            },
            {
              "widget": "Text",
              "properties": {
                "data": "Followers",
                "fontSize": 12,
                "color": "#6B7280",
              },
            },
          ],
        },
      },
    },
    {
      "widget": "Card",
      "properties": {"elevation": 3, "borderRadius": 16, "margin": 0},
      "child": {
        "widget": "Container",
        "properties": {"padding": 16, "width": 100},
        "child": {
          "widget": "Column",
          "properties": {"crossAxisAlignment": "center", "mainAxisSize": "min"},
          "children": [
            {
              "widget": "Icon",
              "properties": {"icon": "star", "color": "#F59E0B", "size": 28},
            },
            {
              "widget": "Text",
              "properties": {
                "data": "4.9",
                "fontSize": 20,
                "fontWeight": "bold",
                "color": "#1F2937",
              },
            },
            {
              "widget": "Text",
              "properties": {
                "data": "Rating",
                "fontSize": 12,
                "color": "#6B7280",
              },
            },
          ],
        },
      },
    },
    {
      "widget": "Card",
      "properties": {"elevation": 3, "borderRadius": 16, "margin": 0},
      "child": {
        "widget": "Container",
        "properties": {"padding": 16, "width": 100},
        "child": {
          "widget": "Column",
          "properties": {"crossAxisAlignment": "center", "mainAxisSize": "min"},
          "children": [
            {
              "widget": "Icon",
              "properties": {
                "icon": "check_circle",
                "color": "#6C63FF",
                "size": 28,
              },
            },
            {
              "widget": "Text",
              "properties": {
                "data": "128",
                "fontSize": 20,
                "fontWeight": "bold",
                "color": "#1F2937",
              },
            },
            {
              "widget": "Text",
              "properties": {
                "data": "Projects",
                "fontSize": 12,
                "color": "#6B7280",
              },
            },
          ],
        },
      },
    },
  ],
};

const Map<String, dynamic> actionsRowJson = {
  "widget": "Row",
  "properties": {"mainAxisAlignment": "spaceEvenly"},
  "children": [
    {
      "widget": "ElevatedButton",
      "properties": {
        "label": "Follow",
        "backgroundColor": "#6C63FF",
        "labelColor": "#FFFFFF",
        "borderRadius": 12,
        "fontSize": 15,
        "fontWeight": "w600",
        "padding": {"horizontal": 28, "vertical": 14},
      },
      "icon": {
        "widget": "Icon",
        "properties": {"icon": "person", "color": "#FFFFFF", "size": 18},
      },
      "onTap": {
        "type": "follow",
        "payload": {"userId": "alex_johnson"},
      },
    },
    {
      "widget": "OutlinedButton",
      "properties": {
        "label": "Message",
        "labelColor": "#6C63FF",
        "borderColor": "#6C63FF",
        "borderRadius": 12,
        "fontSize": 15,
        "fontWeight": "w600",
        "padding": {"horizontal": 24, "vertical": 14},
      },
      "icon": {
        "widget": "Icon",
        "properties": {"icon": "chat", "color": "#6C63FF", "size": 18},
      },
      "onTap": {
        "type": "navigate",
        "payload": {"route": "/chat", "userId": "alex_johnson"},
      },
    },
  ],
};

// A card demonstrating the fallback widget for unknown types
const Map<String, dynamic> unknownWidgetJson = {
  "widget": "SuperFancyWidget3000",
  "properties": {"data": "This widget does not exist"},
};

const Map<String, dynamic> featureListJson = {
  "widget": "ListView",
  "properties": {"shrinkWrap": true, "physics": "never", "padding": 0},
  "children": [
    {
      "widget": "Card",
      "properties": {
        "elevation": 2,
        "borderRadius": 14,
        "margin": {"bottom": 10},
      },
      "child": {
        "widget": "Container",
        "properties": {"padding": 16},
        "child": {
          "widget": "Row",
          "properties": {"mainAxisAlignment": "start"},
          "children": [
            {
              "widget": "Container",
              "properties": {
                "width": 44,
                "height": 44,
                "color": "#EDE9FE",
                "borderRadius": 12,
              },
              "child": {
                "widget": "Center",
                "child": {
                  "widget": "Icon",
                  "properties": {
                    "icon": "notifications",
                    "color": "#6C63FF",
                    "size": 22,
                  },
                },
              },
            },
            {
              "widget": "Container",
              "properties": {"width": 14},
            },
            {
              "widget": "Column",
              "properties": {
                "crossAxisAlignment": "start",
                "mainAxisSize": "min",
              },
              "children": [
                {
                  "widget": "Text",
                  "properties": {
                    "data": "Push Notifications",
                    "fontSize": 15,
                    "fontWeight": "w600",
                    "color": "#1F2937",
                  },
                },
                {
                  "widget": "Text",
                  "properties": {
                    "data": "Real-time alerts from the server",
                    "fontSize": 12,
                    "color": "#6B7280",
                  },
                },
              ],
            },
          ],
        },
      },
    },
    {
      "widget": "Card",
      "properties": {
        "elevation": 2,
        "borderRadius": 14,
        "margin": {"bottom": 10},
      },
      "child": {
        "widget": "Container",
        "properties": {"padding": 16},
        "child": {
          "widget": "Row",
          "properties": {"mainAxisAlignment": "start"},
          "children": [
            {
              "widget": "Container",
              "properties": {
                "width": 44,
                "height": 44,
                "color": "#DCFCE7",
                "borderRadius": 12,
              },
              "child": {
                "widget": "Center",
                "child": {
                  "widget": "Icon",
                  "properties": {
                    "icon": "bar_chart",
                    "color": "#22C55E",
                    "size": 22,
                  },
                },
              },
            },
            {
              "widget": "Container",
              "properties": {"width": 14},
            },
            {
              "widget": "Column",
              "properties": {
                "crossAxisAlignment": "start",
                "mainAxisSize": "min",
              },
              "children": [
                {
                  "widget": "Text",
                  "properties": {
                    "data": "Dynamic Analytics",
                    "fontSize": 15,
                    "fontWeight": "w600",
                    "color": "#1F2937",
                  },
                },
                {
                  "widget": "Text",
                  "properties": {
                    "data": "Charts and widgets from JSON",
                    "fontSize": 12,
                    "color": "#6B7280",
                  },
                },
              ],
            },
          ],
        },
      },
    },
  ],
};

// ─── App ──────────────────────────────────────────────────────────────────────

class SduiExampleApp extends StatelessWidget {
  const SduiExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SDUI Library Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF6C63FF)),
        useMaterial3: true,
        fontFamily: 'Roboto',
      ),
      home: const SduiDemoPage(),
    );
  }
}

class SduiDemoPage extends StatefulWidget {
  const SduiDemoPage({super.key});

  @override
  State<SduiDemoPage> createState() => _SduiDemoPageState();
}

class _SduiDemoPageState extends State<SduiDemoPage> {
  String _lastAction = 'No action yet';
  bool _showRawJson = false;

  void _handleAction(SduiAction action) {
    setState(() {
      _lastAction =
          'Action: ${action.type}\nPayload: ${jsonEncode(action.payload)}';
    });
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('🚀 ${action.type} → ${jsonEncode(action.payload)}'),
        behavior: SnackBarBehavior.floating,
        backgroundColor: const Color(0xFF6C63FF),
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFF8F7FF),
      appBar: AppBar(
        backgroundColor: const Color(0xFF6C63FF),
        foregroundColor: Colors.white,
        title: const Text(
          'SDUI Library Demo',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        actions: [
          TextButton.icon(
            onPressed: () => setState(() => _showRawJson = !_showRawJson),
            icon: Icon(
              _showRawJson ? Icons.widgets : Icons.code,
              color: Colors.white,
            ),
            label: Text(
              _showRawJson ? 'UI' : 'JSON',
              style: const TextStyle(color: Colors.white),
            ),
          ),
        ],
      ),
      body: _showRawJson ? _buildJsonView() : _buildUiView(),
    );
  }

  Widget _buildUiView() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _sectionLabel('Profile Card (gradient + custom widget)'),
          const SizedBox(height: 8),
          SduiParser.buildWidget(profileCardJson, onAction: _handleAction),

          const SizedBox(height: 20),
          _sectionLabel('Stats Row (nested cards)'),
          const SizedBox(height: 8),
          SduiParser.buildWidget(statsRowJson, onAction: _handleAction),

          const SizedBox(height: 20),
          _sectionLabel('Action Buttons (dispatches SduiAction)'),
          const SizedBox(height: 8),
          SduiParser.buildWidget(actionsRowJson, onAction: _handleAction),

          const SizedBox(height: 12),
          // Action log
          Container(
            width: double.infinity,
            padding: const EdgeInsets.all(14),
            decoration: BoxDecoration(
              color: const Color(0xFFEDE9FE),
              borderRadius: BorderRadius.circular(12),
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text(
                  '📋 Action Log',
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Color(0xFF4C1D95),
                  ),
                ),
                const SizedBox(height: 4),
                Text(
                  _lastAction,
                  style: const TextStyle(
                    fontFamily: 'monospace',
                    fontSize: 12,
                    color: Color(0xFF5B21B6),
                  ),
                ),
              ],
            ),
          ),

          const SizedBox(height: 20),
          _sectionLabel('Feature List (ListView in JSON)'),
          const SizedBox(height: 8),
          SduiParser.buildWidget(featureListJson, onAction: _handleAction),

          const SizedBox(height: 20),
          _sectionLabel('⚠️ Fallback Widget (unknown type)'),
          const SizedBox(height: 8),
          SduiParser.buildWidget(unknownWidgetJson, onAction: _handleAction),

          const SizedBox(height: 32),
        ],
      ),
    );
  }

  Widget _buildJsonView() {
    final sections = [
      ('Profile Card JSON', profileCardJson),
      ('Stats Row JSON', statsRowJson),
      ('Action Buttons JSON', actionsRowJson),
      ('Feature List JSON', featureListJson),
      ('Unknown Widget JSON (fallback)', unknownWidgetJson),
    ];

    return ListView(
      padding: const EdgeInsets.all(16),
      children: sections.map((entry) {
        final (title, json) = entry;
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _sectionLabel(title),
            const SizedBox(height: 6),
            Container(
              width: double.infinity,
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                color: const Color(0xFF1E1B4B),
                borderRadius: BorderRadius.circular(12),
              ),
              child: SelectableText(
                const JsonEncoder.withIndent('  ').convert(json),
                style: const TextStyle(
                  color: Color(0xFF93C5FD),
                  fontFamily: 'monospace',
                  fontSize: 12,
                ),
              ),
            ),
            const SizedBox(height: 20),
          ],
        );
      }).toList(),
    );
  }

  Widget _sectionLabel(String text) {
    return Text(
      text,
      style: const TextStyle(
        fontSize: 13,
        fontWeight: FontWeight.w700,
        color: Color(0xFF6C63FF),
        letterSpacing: 0.5,
      ),
    );
  }
}
1
likes
160
points
9
downloads

Documentation

API reference

Publisher

verified publisherbaasautotraders.in

Weekly Downloads

Server-Driven UI library for Flutter — render widgets from JSON and export widget trees to JSON via CLI.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, path

More

Packages that depend on sdui_library