hsds_mobile 0.3.0 copy "hsds_mobile: ^0.3.0" to clipboard
hsds_mobile: ^0.3.0 copied to clipboard

HeadSpace Design System — mobile component library (Flutter / Dart)

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:hsds_mobile/hsds_mobile.dart';

void main() => runApp(const ExampleApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'HSDS Mobile — Components',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF3D3A5C)),
        useMaterial3: true,
      ),
      home: const ComponentGallery(),
    );
  }
}

// ---------------------------------------------------------------------------
// Top-level gallery — tab bar switches between component sections
// ---------------------------------------------------------------------------

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

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        backgroundColor: const Color(0xFFF5F5F5),
        appBar: AppBar(
          title: const Text('HSDS Components'),
          backgroundColor: Colors.white,
          surfaceTintColor: Colors.transparent,
          elevation: 0,
          bottom: const TabBar(
            tabs: [
              Tab(text: 'Text Input'),
              Tab(text: 'Bottom Nav'),
            ],
            labelColor: Color(0xFF3D3A5C),
            unselectedLabelColor: Color(0xFF63605D),
            indicatorColor: Color(0xFF3D3A5C),
          ),
        ),
        body: const TabBarView(
          children: [
            TextInputGallery(),
            BottomNavGallery(),
          ],
        ),
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Text Input Gallery
// ---------------------------------------------------------------------------

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

  @override
  Widget build(BuildContext context) {
    return HsdsThemeProvider(
      child: SingleChildScrollView(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // ── HsdsTextField ──────────────────────────────────────────────
            _sectionLabel('HsdsTextField — States'),
            const SizedBox(height: 16),
            const HsdsTextField(label: 'Enabled'),
            const SizedBox(height: 16),
            const HsdsTextField(
              label: 'With helper text',
              helperText: "We'll never share your email",
            ),
            const SizedBox(height: 16),
            const HsdsTextField(
              label: 'Error — empty',
              error: true,
              errorMessage: 'This field is required',
            ),
            const SizedBox(height: 16),
            const HsdsTextField(
              label: 'Error — with message',
              error: true,
              errorMessage: 'Invalid email format',
              initialValue: 'bad@',
            ),
            const SizedBox(height: 16),
            const HsdsTextField(
              label: 'Disabled',
              disabled: true,
              initialValue: "Can't touch this",
            ),
            const SizedBox(height: 16),
            const HsdsTextField(
              label: 'Read only',
              readOnly: true,
              initialValue: 'Read-only value',
            ),
            const SizedBox(height: 32),

            _sectionLabel('HsdsTextField — Password'),
            const SizedBox(height: 16),
            const HsdsTextField(
              label: 'Password',
              obscureText: true,
            ),
            const SizedBox(height: 16),
            const HsdsTextField(
              label: 'Password — with value',
              obscureText: true,
              initialValue: 'supersecret',
            ),
            const SizedBox(height: 32),

            // ── HsdsTextArea ───────────────────────────────────────────────
            _sectionLabel('HsdsTextArea — States'),
            const SizedBox(height: 16),
            const HsdsTextArea(label: 'Notes'),
            const SizedBox(height: 16),
            const HsdsTextArea(
              label: 'Default (250 char limit)',
            ),
            const SizedBox(height: 16),
            const HsdsTextArea(
              label: 'With value',
              initialValue: 'Some initial content here.',
            ),
            const SizedBox(height: 16),
            const HsdsTextArea(
              label: 'Error',
              error: true,
              errorMessage: 'Content is too long',
              initialValue: 'This is way too long...',
            ),
            const SizedBox(height: 16),
            const HsdsTextArea(
              label: 'Disabled',
              disabled: true,
            ),
            const SizedBox(height: 16),
            const HsdsTextArea(
              label: 'Custom limit',
              maxLength: 100,
            ),
            const SizedBox(height: 40),
          ],
        ),
      ),
    );
  }
}

Widget _sectionLabel(String text) {
  return Text(
    text.toUpperCase(),
    style: HsdsTextStyles.mobileEyebrow,
  );
}

// ---------------------------------------------------------------------------
// Bottom Nav Gallery (unchanged)
// ---------------------------------------------------------------------------

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

  @override
  State<BottomNavGallery> createState() => _BottomNavGalleryState();
}

class _BottomNavGalleryState extends State<BottomNavGallery> {
  int _sel3 = 0;
  int _sel5 = 0;
  int _selNoIndicator = 0;

  static final _items3 = [
    HsdsBottomNavItem(
      label: 'Today',
      icon: HsdsBottomNavIcons.today.inactive,
      activeIcon: HsdsBottomNavIcons.today.active,
    ),
    HsdsBottomNavItem(
      label: 'Explore',
      icon: HsdsBottomNavIcons.explore.inactive,
      activeIcon: HsdsBottomNavIcons.explore.active,
    ),
    HsdsBottomNavItem(
      label: 'Profile',
      icon: HsdsBottomNavIcons.profile.inactive,
      activeIcon: HsdsBottomNavIcons.profile.active,
    ),
  ];

  static final _items5 = [
    HsdsBottomNavItem(
      label: 'Today',
      icon: HsdsBottomNavIcons.today.inactive,
      activeIcon: HsdsBottomNavIcons.today.active,
    ),
    HsdsBottomNavItem(
      label: 'Explore',
      icon: HsdsBottomNavIcons.explore.inactive,
      activeIcon: HsdsBottomNavIcons.explore.active,
    ),
    HsdsBottomNavItem(
      label: 'Ebb',
      icon: HsdsBottomNavIcons.ebb.inactive,
      activeIcon: HsdsBottomNavIcons.ebb.active,
    ),
    HsdsBottomNavItem(
      label: 'Care',
      icon: HsdsBottomNavIcons.care.inactive,
      activeIcon: HsdsBottomNavIcons.care.active,
    ),
    HsdsBottomNavItem(
      label: 'Profile',
      icon: HsdsBottomNavIcons.profile.inactive,
      activeIcon: HsdsBottomNavIcons.profile.active,
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          _VariantCard(
            label: '3 tabs — with home indicator',
            child: HsdsBottomNav(
              items: _items3,
              selectedIndex: _sel3,
              onTabSelected: (i) => setState(() => _sel3 = i),
            ),
          ),
          _VariantCard(
            label: '5 tabs — with home indicator',
            child: HsdsBottomNav(
              items: _items5,
              selectedIndex: _sel5,
              onTabSelected: (i) => setState(() => _sel5 = i),
            ),
          ),
          _VariantCard(
            label: '3 tabs — no home indicator',
            child: HsdsBottomNav(
              items: _items3,
              selectedIndex: _selNoIndicator,
              onTabSelected: (i) => setState(() => _selNoIndicator = i),
              showHomeIndicator: false,
            ),
          ),
        ],
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Helper widget — section label + full-width component (no card frame)
// ---------------------------------------------------------------------------

class _VariantCard extends StatelessWidget {
  const _VariantCard({required this.label, required this.child});

  final String label;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.fromLTRB(16, 32, 16, 8),
          child: Text(
            label,
            style: HsdsTextStyles.mobileEyebrow,
          ),
        ),
        child,
      ],
    );
  }
}
0
likes
160
points
35
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

HeadSpace Design System — mobile component library (Flutter / Dart)

Homepage
Repository (GitHub)

License

MIT (license)

Dependencies

flutter, flutter_svg

More

Packages that depend on hsds_mobile