refraction_ui 0.5.0 copy "refraction_ui: ^0.5.0" to clipboard
refraction_ui: ^0.5.0 copied to clipboard

A headless, highly customizable, and fully accessible Flutter UI library matching Refraction UI.

example/lib/main.dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/material.dart';
import 'package:refraction_ui/refraction_ui.dart';

// Import our layouts and pages
import 'pages/home_page.dart';
import 'pages/docs_layout.dart';
import 'pages/bottom_nav_page.dart';
import 'pages/breadcrumbs_page.dart';
import 'pages/footer_page.dart';
import 'pages/carousel_page.dart';
import 'pages/command_menu_page.dart';
import 'pages/command_input_page.dart';
import 'pages/radio_group_page.dart';
import 'pages/progress_slider_page.dart';
import 'pages/alert_page.dart';
import 'pages/avatar_page.dart';
import 'pages/date_picker_page.dart';
import 'pages/file_upload_page.dart';
import 'pages/emoji_picker_page.dart';
import 'pages/code_editor_page.dart';
import 'pages/inline_editor_page.dart';
import 'pages/rich_editor_page.dart';
import 'pages/location_selector_page.dart';
import 'pages/language_selector_page.dart';
import 'pages/data_table_page.dart';
import 'dev_tools/preview_canvas.dart';

// Import the mock applications
import 'apps/family_calendar_app.dart';
import 'apps/pregnancy_tracker_app.dart';
import 'apps/my_prototype.dart';

void main() {
  runApp(const ProviderScope(child: RefractionDemoApp()));
}

class _RouteNotifier extends Notifier<String> {
  @override
  String build() => '/';
  void update(String val) => state = val;
}

final appRouteProvider = NotifierProvider<_RouteNotifier, String>(
  _RouteNotifier.new,
);

class _DarkModeNotifier extends Notifier<bool> {
  @override
  bool build() => true;
  void toggle() => state = !state;
}

final darkModeProvider = NotifierProvider<_DarkModeNotifier, bool>(
  _DarkModeNotifier.new,
);

class _PaletteNotifier extends Notifier<String> {
  @override
  String build() => 'Minimal';
  void update(String val) => state = val;
}

final paletteProvider = NotifierProvider<_PaletteNotifier, String>(
  _PaletteNotifier.new,
);

class RefractionDemoApp extends ConsumerWidget {
  const RefractionDemoApp({super.key});

  final List<String> components = const [
    'Accordion',
    'Menus',
    'Command Menu',
    'Command Input',
    'Radio Group',
    'Progress Slider',
    'Alert',
    'Avatar',
    'Buttons',
    'Badges',
    'Inputs & Forms',
    'Select & Dropdowns',
    'Tabs',
    'Navbar & Navigation',
    'Cards & Layouts',
    'Code Editor',
    'Inline Editor',
    'Rich Editor',
    'Date Picker',
    'Location Selector',
    'Language Selector',
    'Emoji Picker',
    'File Upload',
    'Popovers & Tooltips',
    'Toasts',
    'Data Table',
  ];

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final isDarkMode = ref.watch(darkModeProvider);
    final palette = ref.watch(paletteProvider);

    RefractionThemeData themeData;
    switch (palette) {
      case 'Fintech':
        themeData = isDarkMode
            ? RefractionThemeData.fintechDark()
            : RefractionThemeData.fintechLight();
        break;
      case 'Wellness':
        themeData = isDarkMode
            ? RefractionThemeData.wellnessDark()
            : RefractionThemeData.wellnessLight();
        break;
      case 'Creative':
        themeData = isDarkMode
            ? RefractionThemeData.creativeDark()
            : RefractionThemeData.creativeLight();
        break;
      case 'Productivity':
        themeData = isDarkMode
            ? RefractionThemeData.productivityDark()
            : RefractionThemeData.productivityLight();
        break;
      case 'Minimal':
      default:
        themeData = isDarkMode
            ? RefractionThemeData.minimalDark()
            : RefractionThemeData.minimalLight();
        break;
    }

    return RefractionTheme(
      data: themeData,
      child: MaterialApp(
        title: 'Refraction UI (Flutter)',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          scaffoldBackgroundColor: themeData.colors.background,
          fontFamily: themeData.fontFamily,
          useMaterial3: true,
        ),
        home: _AppShell(components: components),
      ),
    );
  }
}

class _AppShell extends ConsumerWidget {
  final List<String> components;

  const _AppShell({required this.components});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final theme = RefractionTheme.of(context).data;
    final colors = theme.colors;
    final currentRoute = ref.watch(appRouteProvider);

    Widget body;
    if (currentRoute == '/') {
      body = HomePage(
        onGetStarted: () =>
            ref.read(appRouteProvider.notifier).update('/docs/buttons'),
      );
    } else if (currentRoute.startsWith('/docs')) {
      body = DocsLayout(
        currentRoute: currentRoute,
        onNavigate: (r) => ref.read(appRouteProvider.notifier).update(r),
        components: components,
        child: _buildDocsContent(currentRoute, context),
      );
    } else {
      body = const Center(child: Text('404 Not Found'));
    }

    return Scaffold(
      backgroundColor: colors.background,
      appBar: PreferredSize(
        preferredSize: const Size.fromHeight(64),
        child: Container(
          decoration: BoxDecoration(
            color: colors.background,
            border: Border(bottom: BorderSide(color: colors.border)),
          ),
          padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 0),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              InkWell(
                onTap: () => ref.read(appRouteProvider.notifier).update('/'),
                child: Row(
                  children: [
                    Icon(Icons.diamond, color: colors.primary, size: 28),
                    const SizedBox(width: 12),
                    Text(
                      "Refraction UI",
                      style: theme.textStyle.copyWith(
                        fontWeight: FontWeight.bold,
                        fontSize: 18,
                      ),
                    ),
                    const SizedBox(width: 8),
                    RefractionBadge(
                      variant: RefractionBadgeVariant.secondary,
                      child: const Text("Flutter v0.2.0"),
                    ),
                  ],
                ),
              ),
              Row(
                children: [
                  _buildThemePicker(context, ref, theme),
                  const SizedBox(width: 16),
                  _buildDarkModeToggle(ref, theme),
                  const SizedBox(width: 16),
                  RefractionButton(
                    variant: RefractionButtonVariant.outline,
                    onPressed: () {},
                    child: const Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Icon(Icons.code, size: 16),
                        SizedBox(width: 8),
                        Text("GitHub"),
                      ],
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
      body: body,
    );
  }

  Widget _buildDarkModeToggle(WidgetRef ref, RefractionThemeData theme) {
    final isDark = ref.watch(darkModeProvider);
    return InkWell(
      onTap: () => ref.read(darkModeProvider.notifier).toggle(),
      child: Container(
        height: 36,
        width: 36,
        decoration: BoxDecoration(
          border: Border.all(color: theme.colors.border),
          borderRadius: BorderRadius.circular(theme.borderRadius),
        ),
        child: Icon(
          isDark ? Icons.light_mode : Icons.dark_mode,
          size: 16,
          color: theme.colors.foreground,
        ),
      ),
    );
  }

  Widget _buildThemePicker(
    BuildContext context,
    WidgetRef ref,
    RefractionThemeData theme,
  ) {
    final palette = ref.watch(paletteProvider);
    final palettes = [
      {'name': 'Minimal', 'color': const Color(0xFF000000)},
      {'name': 'Fintech', 'color': const Color(0xFF00D632)},
      {'name': 'Wellness', 'color': const Color(0xFFFF6E66)},
      {'name': 'Creative', 'color': const Color(0xFF5046E5)},
      {'name': 'Productivity', 'color': const Color(0xFF3B82F6)},
    ];

    return PopupMenuButton<String>(
      onSelected: (val) => ref.read(paletteProvider.notifier).update(val),
      offset: const Offset(0, 48),
      color: theme.colors.popover,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(theme.borderRadius),
        side: BorderSide(color: theme.colors.border),
      ),
      child: Container(
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
        decoration: BoxDecoration(
          border: Border.all(color: theme.colors.border),
          borderRadius: BorderRadius.circular(theme.borderRadius),
        ),
        child: Row(
          children: [
            Container(
              width: 12,
              height: 12,
              decoration: BoxDecoration(
                shape: BoxShape.circle,
                color:
                    palettes.firstWhere((p) => p['name'] == palette)['color']
                        as Color,
              ),
            ),
            const SizedBox(width: 8),
            Text(palette, style: theme.textStyle.copyWith(fontSize: 14)),
            const SizedBox(width: 4),
            Icon(
              Icons.keyboard_arrow_down,
              size: 16,
              color: theme.colors.foreground,
            ),
          ],
        ),
      ),
      itemBuilder: (context) {
        return palettes.map((p) {
          final isSelected = p['name'] == palette;
          return PopupMenuItem<String>(
            value: p['name'] as String,
            child: Row(
              children: [
                Container(
                  width: 12,
                  height: 12,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    color: p['color'] as Color,
                  ),
                ),
                const SizedBox(width: 12),
                Text(
                  p['name'] as String,
                  style: theme.textStyle.copyWith(
                    fontWeight: isSelected
                        ? FontWeight.bold
                        : FontWeight.normal,
                  ),
                ),
              ],
            ),
          );
        }).toList();
      },
    );
  }

  // Very simple mocked content mapper
  Widget _buildDocsContent(String route, BuildContext context) {
    switch (route) {
      case '/docs/accordion':
        return const AccordionPage();
      case '/docs/menus':
        return const MenusPage();
      case '/docs/command-menu':
        return const CommandMenuPage();
      case '/docs/command-input':
        return const CommandInputPage();
      case '/docs/radio-group':
        return const RadioGroupPage();
      case '/docs/progress-slider':
        return const ProgressSliderPage();
      case '/docs/alert':
        return const AlertPage();
      case '/docs/avatar':
        return const AvatarPage();
      case '/docs/file-upload':
        return const FileUploadPage();
      case '/docs/emoji-picker':
        return const EmojiPickerPage();
      case '/docs/code-editor':
        return const CodeEditorPage();
      case '/docs/inline-editor':
        return const InlineEditorPage();
      case '/docs/rich-editor':
        return const RichEditorPage();
      case '/docs/date-picker':
        return const DatePickerPage();
      case '/docs/location-selector':
        return const LocationSelectorPage();
      case '/docs/language-selector':
        return const LanguageSelectorPage();
      case '/docs/data-table':
        return const DataTablePage();
      case '/docs/pregnancy-tracker':
        return const PreviewCanvas(
          title: "Pregnancy Tracker Layout",
          description:
              "A full stateful demonstration of medical health/wellness tracking using the Refraction architecture.",
          fill: true,
          child: PregnancyTrackerApp(),
        );
      case '/docs/family-calendar':
        return const PreviewCanvas(
          title: "Family Calendar Layout",
          description:
              "A rich data-dense grid structure for productivity displays.",
          fill: true,
          child: FamilyCalendarApp(),
        );
      case '/docs/my-prototype':
        return const PreviewCanvas(
          title: "My Prototype",
          description: "Your local sandbox prototyping environment.",
          fill: true,
          child: MyPrototypeApp(),
        );
      case '/docs/buttons':
        return PreviewCanvas(
          title: "Buttons",
          description: "Primary actions and CTAs.",
          child: Center(
            child: Wrap(
              spacing: 16,
              runSpacing: 16,
              children: [
                RefractionButton(
                  onPressed: () {},
                  child: const Text("Primary"),
                ),
                RefractionButton(
                  variant: RefractionButtonVariant.secondary,
                  onPressed: () {},
                  child: const Text("Secondary"),
                ),
                RefractionButton(
                  variant: RefractionButtonVariant.outline,
                  onPressed: () {},
                  child: const Text("Outline"),
                ),
                RefractionButton(
                  variant: RefractionButtonVariant.ghost,
                  onPressed: () {},
                  child: const Text("Ghost"),
                ),
                RefractionButton(
                  variant: RefractionButtonVariant.destructive,
                  onPressed: () {},
                  child: const Text("Destructive"),
                ),
              ],
            ),
          ),
        );
      case '/docs/badges':
        return PreviewCanvas(
          title: "Badges",
          description: "Small status indicators and labels.",
          child: Center(
            child: Wrap(
              spacing: 16,
              children: const [
                RefractionBadge(child: Text("Primary")),
                RefractionBadge(
                  variant: RefractionBadgeVariant.secondary,
                  child: Text("Secondary"),
                ),
                RefractionBadge(
                  variant: RefractionBadgeVariant.outline,
                  child: Text("Outline"),
                ),
                RefractionBadge(
                  variant: RefractionBadgeVariant.destructive,
                  child: Text("Destructive"),
                ),
              ],
            ),
          ),
        );
      case '/docs/inputs-&-forms':
        return PreviewCanvas(
          title: "Inputs & Forms",
          child: ConstrainedBox(
            constraints: const BoxConstraints(maxWidth: 400),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const RefractionInput(placeholder: "Email address"),
                const SizedBox(height: 16),
                const RefractionInput(
                  placeholder: "Password",
                  obscureText: true,
                ),
                const SizedBox(height: 16),
                const RefractionInput(
                  placeholder: "Disabled Input",
                  disabled: true,
                ),
                const SizedBox(height: 16),
                RefractionButton(
                  onPressed: () {},
                  child: const Center(child: Text("Submit")),
                ),
              ],
            ),
          ),
        );
      case '/docs/chat-input':
        return const ChatInputPage();
      case '/docs/select-&-dropdowns':
        return PreviewCanvas(
          title: "Select & Dropdowns",
          description: "Display a list of choices on temporary surfaces.",
          child: Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 300),
              child: RefractionSelect<String>(
                value: "Option 1",
                placeholder: "Select an option",
                items: const [
                  DropdownMenuItem(value: "Option 1", child: Text("Option 1")),
                  DropdownMenuItem(value: "Option 2", child: Text("Option 2")),
                  DropdownMenuItem(value: "Option 3", child: Text("Option 3")),
                ],
                onChanged: (val) {},
              ),
            ),
          ),
        );
      case '/docs/tabs':
        return PreviewCanvas(
          title: "Tabs",
          description: "A set of layered sections of content.",
          child: Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 400),
              child: RefractionTabs(
                tabs: const ['Account', 'Password', 'Settings'],
                children: const [
                  Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Text("Make changes to your account here."),
                  ),
                  Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Text("Change your password here."),
                  ),
                  Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Text("Manage your settings here."),
                  ),
                ],
              ),
            ),
          ),
        );
      case '/docs/carousel':
        return const CarouselPage();
      case '/docs/cards-&-layouts':
        return PreviewCanvas(
          title: "Cards",
          description: "Displays a card with header, content, and footer.",
          child: Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 350),
              child: RefractionCard(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const RefractionCardHeader(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          RefractionCardTitle("Create project"),
                          SizedBox(height: 4),
                          RefractionCardDescription(
                            "Deploy your new project in one-click.",
                          ),
                        ],
                      ),
                    ),
                    const RefractionCardContent(
                      child: RefractionInput(
                        placeholder: "Name of your project",
                      ),
                    ),
                    RefractionCardFooter(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          RefractionButton(
                            variant: RefractionButtonVariant.outline,
                            onPressed: () {},
                            child: const Text("Cancel"),
                          ),
                          RefractionButton(
                            onPressed: () {},
                            child: const Text("Deploy"),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      case '/docs/popovers-&-tooltips':
        return PreviewCanvas(
          title: "Popovers & Tooltips",
          description: "Floating interactive panels.",
          child: Center(
            child: Wrap(
              spacing: 32,
              children: [
                RefractionTooltip(
                  message: const Text("Add to library"),
                  child: RefractionButton(
                    variant: RefractionButtonVariant.outline,
                    onPressed: () {},
                    child: const Text("Hover me"),
                  ),
                ),
                RefractionPopover(
                  content: const Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Text("Popover content goes here."),
                  ),
                  trigger: RefractionButton(
                    onPressed: () {},
                    child: const Text("Click for Popover"),
                  ),
                ),
              ],
            ),
          ),
        );
      case '/docs/toasts':
        return PreviewCanvas(
          title: "Toasts",
          description: "A succinct message that is displayed temporarily.",
          child: Center(
            child: RefractionButton(
              onPressed: () {
                RefractionToast.show(
                  context: context,
                  title: "Scheduled: Catch up",
                  description: "Friday, February 10, 2024 at 5:57 PM",
                );
              },
              child: const Text("Show Toast"),
            ),
          ),
        );
      case '/docs/navbar-&-navigation':
        return const PreviewCanvas(
          title: "Navbar",
          description: "Top-level routing components.",
          child: RefractionNavbar(
            logo: Text("Brand"),
            currentPath: "/home",
            links: [
              NavLink(label: "Home", href: "/home"),
              NavLink(label: "Features", href: "/features"),
              NavLink(label: "Pricing", href: "/pricing"),
            ],
          ),
        );
      case '/docs/introduction':
        return _buildArticlePage(
          context,
          "Introduction",
          "Refraction UI Flutter is a port of the world-class Refraction UI framework. Designed with painstaking attention to detail, it maps perfectly to Mobbin archetypes, offering you pure production-ready aesthetics instantly.\n\nUse this library to stop reinventing the wheel and build professional, beautiful Flutter web and mobile applications.",
        );
      case '/docs/installation':
        return _buildArticlePage(
          context,
          "Installation",
          "Add the following to your pubspec.yaml:\n\n```yaml\ndependencies:\n  refraction_ui: ^0.2.0\n```\n\nRun `flutter pub get` and wrap your app in a `RefractionTheme` to inject the design tokens globally.",
        );
      case '/docs/theming':
        return _buildArticlePage(
          context,
          "Theming",
          "Refraction UI features 5 beautifully curated archetypes out of the box: Minimal, Fintech, Wellness, Creative, and Productivity. \n\nYou can easily construct these factories like so:\n`RefractionThemeData.minimalDark()` or `RefractionThemeData.fintechLight()` and supply them directly to the `RefractionTheme` container.",
        );
      default:
        // Render a generic placeholder for other components
        final title = route.split('/').last.replaceAll('-', ' ').toUpperCase();
        return PreviewCanvas(
          title: title,
          description: "Component documentation is rendering cleanly.",
          child: const Center(child: Text("Preview rendered here.")),
        );
    }
  }

  Widget _buildArticlePage(BuildContext context, String title, String body) {
    final theme = RefractionTheme.of(context).data;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          title,
          style: theme.textStyle.copyWith(
            fontSize: 48,
            fontWeight: FontWeight.w800,
            letterSpacing: -1,
          ),
        ),
        const SizedBox(height: 24),
        Container(
          width: double.infinity,
          height: 1,
          color: theme.colors.border,
        ),
        const SizedBox(height: 32),
        Text(
          body,
          style: theme.textStyle.copyWith(
            fontSize: 18,
            height: 1.6,
            color: theme.colors.mutedForeground,
          ),
        ),
      ],
    );
  }
}
1
likes
0
points
355
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

A headless, highly customizable, and fully accessible Flutter UI library matching Refraction UI.

Homepage
Repository (GitHub)
View/report issues

Topics

#ui #widget #design-system #components #theme

License

unknown (license)

Dependencies

flutter

More

Packages that depend on refraction_ui