pragma_design_system 1.4.0 copy "pragma_design_system: ^1.4.0" to clipboard
pragma_design_system: ^1.4.0 copied to clipboard

Flutter library that gathers Pragma's design tokens, themes, and base components for mobile apps.

pragma_design_system #

Flutter library focused on mobile experiences that bundles Pragma's design tokens, base themes, and reusable UI components.

Features #

  • Consistent color, typography, spacing, and responsive grid tokens.
  • PragmaTheme with light/dark variants and Material 3 enabled by default.
  • Glow-based loading components (PragmaLoadingWidget) with circular and linear variants.
  • Multi-state tables (PragmaTableWidget) with hover glow, tone presets, and compact density.
  • Neon pagination rows (PragmaPaginationWidget) with gradient capsule, summary builder, per-page dropdown, and light/dark surfaces.
  • Filter capsules (PragmaFilterWidget) with multi-select overlays, helper text, tag summaries, and light/dark surfaces.
  • Gradient tooltips (PragmaTooltipWidget) with arrow placements, optional title/icon/button combos, delays, and touch-friendly toggles.
  • Search-first input (PragmaSearchWidget) with neon glow, tone presets, size options, and dropdown-ready callbacks.
  • Rich text areas (PragmaTextAreaWidget) with multi-line support, focus glow, validation states, and optional character counter.
  • Neon tags (PragmaTagWidget) with gradient capsules, avatar slot, hover/pressed glow, and removable actions.
  • Radio pills (PragmaRadioButtonWidget) with neon stroke, optional helper text, hover/pressed glow, and disabled styling.
  • Glow checkboxes (PragmaCheckboxWidget) with multi-select support, indeterminate state, dense mode, and hover/pressed neon outline.
  • Status badges (PragmaBadgeWidget) with light/dark palettes, icon slot, tone presets, and compact padding.
  • Accessible components (PragmaButton, PragmaCard, PragmaIconButtonWidget, PragmaInputWidget, PragmaToastWidget, PragmaAccordionWidget, PragmaColorTokenRowWidget, PragmaThemeEditorWidget, PragmaLogoWidget).
  • Theme lab sample that lets you edit colors/typography in real time and export a JSON payload backed by ModelThemePragma.
  • PragmaGridTokens, viewport helpers, and the PragmaGridContainer widget to debug layouts.
  • Component modeling (ModelPragmaComponent, ModelAnatomyAttribute) to sync documentation and showcases from JSON.
  • Example app ready to run and validate (includes a "Grid debugger" page).

Installation #

Add the package to your pubspec.yaml:

dependencies:
	pragma_design_system: ^1.3.0

Then run:

flutter pub get

Quick start #

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

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

	@override
	Widget build(BuildContext context) {
		return MaterialApp(
			title: 'Pragma Design System',
			theme: PragmaTheme.light(),
			darkTheme: PragmaTheme.dark(),
			home: const PragmaHome(),
		);
	}
}

Tokens and components #

  • Colors: PragmaColors exposes brand-aware ColorScheme definitions for light and dark modes.
  • Typography: PragmaTypography defines responsive scales built on top of Google Fonts.
  • Spacing: PragmaSpacing concentrates 4pt-system values and handy utilities.
  • Radius: PragmaBorderRadiusTokens and PragmaBorderRadius keep rounded corners consistent in 4/8dp steps.
  • Rounded-corner guidance lives in doc/rounded_corners.md, covering increments, implementation, and heuristics per component size.
  • Glow search guidance vive en doc/search.md, explicando anatomia, estados y patrones con dropdown list.
  • Text area guidance vive en doc/textarea.md, detallando anatomía, estados focus/error/success y mejores prácticas para copy largo.
  • Tag guidance vive en doc/tags.md, cubriendo anatomía, estados active/hover/pressed/disabled y flujos para remover participantes.
  • Radio guidance vive en doc/radio_button.md, describiendo anatomía, tokens y combinaciones unselected/hover/disabled para grupos exclusivos.
  • Checkbox guidance vive en doc/checkbox.md, explicando estados unchecked/checked/indeterminate, glow morado y patrones de "seleccionar todos".
  • Filter guidance vive en doc/filter.md, cubriendo estados default/hover/open, paneles con checkboxes y uso de tags persistentes.
  • Tooltip guidance vive en doc/tooltip.md, detallando anatomía light/dark, delays, arrow placements y patrones touch.
  • Pagination guidance vive en doc/pagination.md, documentando cápsula, gaps, summary y selector por página.
  • Badge guidance vive en doc/badge.md, detallando tonos light/dark, anatomía y casos de uso informativos.
  • Opacity: PragmaOpacityTokens and PragmaOpacity constrain overlays to 8/30/60 intervals using Color.withValues for Flutter 3.22+.
  • Domain models: ModelPragmaComponent, ModelAnatomyAttribute, ModelFieldState, ModelColorToken, and ModelThemePragma serialize the documentation sourced from Figma, power the input widgets, and guarantee JSON roundtrips.
  • Grid: PragmaGridTokens, getGridConfigFromContext, PragmaGridContainer, and PragmaScaleBox help replicate the official grid, respect gutters, and scale full mockups.
  • Components: Widgets such as PragmaPrimaryButton, PragmaSecondaryButton, PragmaButton.icon, PragmaCard, PragmaCardWidget, PragmaDropdownWidget, PragmaInputWidget, PragmaToastWidget, PragmaAvatarWidget, PragmaBreadcrumbWidget, PragmaAccordionWidget, PragmaColorTokenRowWidget, PragmaThemeEditorWidget, PragmaLogoWidget, PragmaCalendarWidget, PragmaLoadingWidget, or PragmaTableWidget ship consistent states and elevation.

Avatar quick sample #

PragmaAvatarWidget(
	radius: 28,
	initials: 'PD',
	imageUrl: 'https://cdn.pragma.co/avatar.jpg',
	style: PragmaAvatarStyle.primary,
	tooltip: 'Pragma Designer',
)

Button quick sample #

PragmaPrimaryButton(
	label: 'Guardar cambios',
	one: PragmaButtonTone.brand,
	onPressed: () {},
)

PragmaButton.icon(
	label: 'Ver detalles',
	icon: Icons.open_in_new,
	hierarchy: PragmaButtonHierarchy.tertiary,
	onPressed: () {},
)

Icon button quick sample #

PragmaIconButtonWidget(
	icon: Icons.add,
	style: PragmaIconButtonStyle.filledLight,
	onPressed: () {},
)

PragmaIconButtonWidget(
	icon: Icons.close,
	style: PragmaIconButtonStyle.outlinedDark,
	size: PragmaIconButtonSize.compact,
	onPressed: () {},
)

Input quick sample #

final PragmaInputController controller = PragmaInputController(
	ModelFieldState(
		suggestions: <String>['Discovery Lab', 'Growth', 'Mobile Core'],
	),
);

PragmaInputWidget(
	label: 'Nombre del squad',
	controller: controller,
	placeholder: 'Escribe un equipo',
	helperText: 'Filtramos sugerencias automáticamente',
	enablePasswordToggle: true,
	obscureText: true,
	onChanged: (String value) {
		controller
			..setValidation(isDirty: true, isValid: value.isNotEmpty)
			..setError(value.isEmpty ? 'Dato requerido' : null);
	},
);

Search quick sample #

final TextEditingController searchController = TextEditingController();

PragmaSearchWidget(
	controller: searchController,
	placeholder: 'Busca squads o features',
	tone: PragmaSearchTone.dark,
	size: PragmaSearchSize.large,
	infoText: 'Escribe una palabra clave o abre el dropdown list',
	onChanged: (String value) {
		// Actualiza sugerencias o dropdown list
	},
	onSubmitted: (String value) {
		debugPrint('Buscar: $value');
	},
	onClear: () {
		debugPrint('Busqueda reiniciada');
	},
);

Text area quick sample #

final TextEditingController notesController = TextEditingController();

PragmaTextAreaWidget(
	label: 'Notas del requerimiento',
	controller: notesController,
	placeholder: 'Describe alcance, riesgos y pendientes...',
	description: 'Ideal para copy largo o acuerdos del squad.',
	maxLength: 320,
	minLines: 4,
	successText: 'Notas listas para compartir con el squad.',
);

Tag quick sample #

PragmaTagWidget(
	label: '[email protected]',
	leading: SizedBox(
		width: 28,
		height: 28,
		child: CircleAvatar(
			backgroundColor: Colors.white.withValues(alpha: 0.2),
			child: const Text('ES'),
		),
	),
	onPressed: () {
		debugPrint('Abrir perfil de Eugenia');
	},
	onRemove: () {
		debugPrint('Eliminar tag de Eugenia');
	},
);

Radio button quick sample #

class _AccessLevelField extends StatelessWidget {
	const _AccessLevelField({required this.value, required this.onChanged});

	final String value;
	final ValueChanged<String?> onChanged;

	@override
	Widget build(BuildContext context) {
		return Column(
			children: <Widget>[
				PragmaRadioButtonWidget<String>(
					value: 'full',
					groupValue: value,
					label: 'Acceso total',
					description: 'Puede editar entregables y aprobar despliegues.',
					onChanged: onChanged,
				),
				PragmaRadioButtonWidget<String>(
					value: 'readonly',
					groupValue: value,
					label: 'Solo lectura',
					description: 'Ideal para stakeholders o clientes.',
					onChanged: onChanged,
				),
			],
		);
	}
}

Checkbox quick sample #

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

	@override
	State<_ScopeChecklist> createState() => _ScopeChecklistState();
}

class _ScopeChecklistState extends State<_ScopeChecklist> {
	bool design = true;
	bool qa = false;

	bool? get selectAll {
		if (design && qa) return true;
		if (!design && !qa) return false;
		return null;
	}

	@override
	Widget build(BuildContext context) {
		return Column(
			children: <Widget>[
				PragmaCheckboxWidget(
					value: selectAll,
					tristate: true,
					label: 'Seleccionar todo',
					onChanged: (bool? value) {
						final bool shouldSelect = value ?? false;
						setState(() {
							design = shouldSelect;
							qa = shouldSelect;
						});
					},
				),
				PragmaCheckboxWidget(
					value: design,
					label: 'Diseño listo',
					description: 'Entregables revisados y compartidos.',
					onChanged: (bool? value) {
						setState(() => design = value ?? false);
					},
				),
				PragmaCheckboxWidget(
					value: qa,
					label: 'QA finalizado',
					onChanged: (bool? value) {
						setState(() => qa = value ?? false);
					},
				),
			],
		);
	}
}

Badge quick sample #

Wrap(
	spacing: PragmaSpacing.xs,
	runSpacing: PragmaSpacing.xs,
	children: <Widget>[
		PragmaBadgeWidget(
			label: 'Nuevo',
			icon: Icons.bolt,
		),
		PragmaBadgeWidget(
			label: 'QA',
			tone: PragmaBadgeTone.success,
			brightness: PragmaBadgeBrightness.dark,
		),
		PragmaBadgeWidget(
			label: 'Alert',
			tone: PragmaBadgeTone.warning,
		),
	],
);

Color token row quick sample #

ModelColorToken token = ModelColorToken(
	label: 'Primary',
	color: '#6750A4',
);

PragmaColorTokenRowWidget(
	token: token,
	onChanged: (ModelColorToken updated) {
		token = updated;
	},
);

Logo quick sample #

PragmaLogoWidget(
	width: 200,
	variant: PragmaLogoVariant.wordmark,
);

PragmaLogoWidget(
	width: 96,
	variant: PragmaLogoVariant.isotypeCircle,
);

Calendar quick sample #

final PragmaCalendarController controller = PragmaCalendarController(
	initialMonth: DateTime.now(),
);

PragmaCalendarWidget(
	controller: controller,
	selectionMode: PragmaCalendarSelectionMode.range,
	onSelectionChanged: (PragmaCalendarSelection value) {
		debugPrint('Rango: ${value.start} -> ${value.end}');
	},
);

Loading quick sample #

PragmaLoadingWidget(
	value: 0.75,
	caption: 'Circular',
);

PragmaLoadingWidget(
	variant: PragmaLoadingVariant.linear,
	value: 0.5,
	linearWidth: 280,
	caption: 'Progress bar',
);

Table quick sample #

final List<PragmaTableColumn> columns = <PragmaTableColumn>[
	const PragmaTableColumn(label: 'Nombre', flex: 3),
	const PragmaTableColumn(label: 'Proyecto', flex: 2),
	const PragmaTableColumn(
		label: 'Acción',
		flex: 1,
		alignment: Alignment.centerRight,
	),
];

PragmaTableWidget(
	columns: columns,
	rows: <PragmaTableRowData>[
		PragmaTableRowData(
			cells: <Widget>[
				const Text('Andreina Yajaira Francesca Serrano'),
				const Text('Discovery Lab'),
				PragmaTertiaryButton(
					label: 'Abrir',
					size: PragmaButtonSize.small,
					onPressed: () => debugPrint('Abrir ficha'),
				),
			],
		),
	],
);

Theme editor quick sample #

ModelThemePragma theme = ModelThemePragma();

PragmaThemeEditorWidget(
	theme: theme,
	onChanged: (ModelThemePragma updated) {
		theme = updated;
		final ThemeData data = PragmaThemeBuilder.buildTheme(updated);
		// Usa [data] para recargar tu MaterialApp o persistir el JSON generado.
	},
);

Theme Lab workflow #

  1. Ejecuta el example/ y presiona el botón Theme lab del AppBar (junto al Grid debugger) para abrir la página dedicada.
  2. Ajusta la tipografía, el modo (claro/oscuro) y cada ModelColorToken desde los PragmaColorTokenRowWidget dentro del panel izquierdo.
  3. Observa los cambios en vivo en el panel derecho: los botones, tarjetas (PragmaCardWidget) y gradientes usan el ThemeData generado por PragmaThemeBuilder.
  4. Copia el JSON resultante desde la sección "JSON listo para exportar" para versionarlo o compartirlo con tu squad.
  5. Carga el JSON dentro de tu app (ModelThemePragma.fromJson(payload)) y construye un ThemeData con PragmaThemeBuilder.buildTheme para aplicar el tema en caliente o persistirlo como configuración.

Toast quick sample #

PragmaToastService.showToast(
	context: context,
	title: 'Operación exitosa',
	message: 'Synced con Discovery Lab hace 10 segundos.',
	variant: PragmaToastVariant.success,
	duration: const Duration(milliseconds: 4500),
	alignment: PragmaToastAlignment.topRight,
	actionLabel: 'Ver log',
	onActionPressed: () {
		debugPrint('Mostrar detalles');
	},
);
PragmaBreadcrumbWidget(
	items: const <PragmaBreadcrumbItem>[
		PragmaBreadcrumbItem(label: 'Home', onTap: _navigateHome),
		PragmaBreadcrumbItem(label: 'Components', onTap: _goToComponents),
		PragmaBreadcrumbItem(label: 'Breadcrumb', isCurrent: true),
	],
	type: PragmaBreadcrumbType.underline,
)

Filter quick sample #

final List<PragmaFilterOption> statusOptions = <PragmaFilterOption>[
	const PragmaFilterOption(value: 'new', label: 'Nuevo'),
	const PragmaFilterOption(value: 'qa', label: 'QA'),
	const PragmaFilterOption(value: 'done', label: 'Completado'),
];

class _StatusFilter extends StatefulWidget {
	const _StatusFilter();

	@override
	State<_StatusFilter> createState() => _StatusFilterState();
}

class _StatusFilterState extends State<_StatusFilter> {
	Set<String> statuses = <String>{'new'};

	@override
	Widget build(BuildContext context) {
		return PragmaFilterWidget(
			label: 'Estado',
			options: statusOptions,
			selectedValues: statuses,
			helperText: 'Selecciona múltiples estados para refinar el listado.',
			summaryLabel: 'Filtros activos',
			onChanged: (Set<String> values) {
				setState(() => statuses = values);
				debugPrint('Filtros aplicados: $values');
			},
		);
	}
}

Pagination quick sample #

class _PaginationDemo extends StatefulWidget {
	const _PaginationDemo();

	@override
	State<_PaginationDemo> createState() => _PaginationDemoState();
}

class _PaginationDemoState extends State<_PaginationDemo> {
	int currentPage = 2;
	int itemsPerPage = 25;
	final int totalItems = 280;

	int get totalPages => (totalItems / itemsPerPage).ceil();

	@override
	Widget build(BuildContext context) {
		return PragmaPaginationWidget(
			currentPage: currentPage,
			totalPages: totalPages,
			itemsPerPage: itemsPerPage,
			itemsPerPageOptions: const <int>[10, 25, 50, 100],
			totalItems: totalItems,
			tone: PragmaPaginationTone.dark,
			onPageChanged: (int page) {
				setState(() => currentPage = page);
				_fetchPage();
			},
			onItemsPerPageChanged: (int value) {
				setState(() {
					itemsPerPage = value;
					currentPage = 1;
				});
				_fetchPage();
			},
		);
	}

	void _fetchPage() {
		// Refresca la tabla o lista con los nuevos parámetros.
	}
}

Tooltip quick sample #

class _TooltipPreview extends StatelessWidget {
	const _TooltipPreview();

	@override
	Widget build(BuildContext context) {
		return PragmaTooltipWidget(
			title: 'Title (optional)',
			message: 'Texto descriptivo para explicar la acción.',
			icon: Icons.info_outline,
			action: PragmaTooltipAction(
				label: 'Button',
				onPressed: () => debugPrint('Tooltip action'),
			),
			tone: PragmaTooltipTone.dark,
			placement: PragmaTooltipPlacement.right,
			child: PragmaButton.icon(
				label: 'Hover me',
				icon: Icons.touch_app,
				hierarchy: PragmaButtonHierarchy.secondary,
				size: PragmaButtonSize.small,
				onPressed: () => debugPrint('CTA tocado'),
			),
		);
	}
}

See doc/opacity_tokens.md for the full opacity table and Color.withValues examples.

Read doc/component_modeling.md to structure JSON payloads and reuse them in showcases.

Explore lib/src for additional utilities, run the example app, and check doc/grid_utilities.md to adopt the grid helpers.

Review doc/logo.md for asset usage guidelines and doc/fonts.md for typography, licensing, and offline distribution tips. Check doc/loading.md for anatomy, gradients, and scenarios for PragmaLoadingWidget. Conoce la guía de filas, estados hover y casos de uso del componente en doc/tables.md.

Typography and license #

  • See doc/fonts.md for the complete typography contract plus license highlights.
  • The official typeface is Poppins and PragmaTypography applies it through GoogleFonts.poppins.
  • The family ships under the SIL Open Font License 1.1; see the full text in licenses/Poppins-OFL.txt.
  • If your app must work offline on first launch, bundle the .ttf files in your assets and disable runtime fetching.
  • Follow doc/poppins_offline.md for the step-by-step guide and download links.

How to prepare an offline fallback #

  1. Download the weights you use (for example Regular, SemiBold, and Bold) from Google Fonts and store them inside assets/fonts/.

  2. Declare them in pubspec.yaml:

    flutter:
    	 fonts:
    		 - family: Poppins
    			 fonts:
    				 - asset: assets/fonts/Poppins-Regular.ttf
    				 - asset: assets/fonts/Poppins-SemiBold.ttf
    				 - asset: assets/fonts/Poppins-Bold.ttf
    
  3. Disable runtime fetching during startup:

    void main() {
    	 GoogleFonts.config.allowRuntimeFetching = false;
    	 runApp(const PragmaApp());
    }
    

    Remember to import package:google_fonts/google_fonts.dart.

If you skip bundling the files, the responsibility of providing the typeface falls on the app that consumes this package.

Example #

cd example
flutter run

The sample app toggles themes, tokens, and staple components.

Development #

Card quick sample #

PragmaCardWidget(
	title: 'Funnel weekly',
	subtitle: 'Actualizado hace 5 min',
	body: Column(
		crossAxisAlignment: CrossAxisAlignment.start,
		children: const <Widget>[
			Text('Sesiones: 18.4K'),
			SizedBox(height: PragmaSpacing.xs),
			Text('CTR: 4.1% vs semana anterior'),
		],
	),
	variant: PragmaCardVariant.tonal,
	actions: <Widget>[
		PragmaButton.icon(
			label: 'Ver dashboard',
			icon: Icons.open_in_new,
			hierarchy: PragmaButtonHierarchy.tertiary,
			onPressed: () {},
		),
	],
)
PragmaDropdownWidget<String>(
	label: 'Rol asignado',
	placeholder: 'Selecciona un rol',
	helperText: 'Usaremos este rol en los tableros',
	options: const <PragmaDropdownOption<String>>[
		PragmaDropdownOption(label: 'Product Designer', value: 'ux'),
		PragmaDropdownOption(label: 'Product Manager', value: 'pm'),
		PragmaDropdownOption(label: 'iOS Engineer', value: 'ios'),
	],
	onChanged: (String? value) {
		debugPrint('Role: $value');
	},
)
  • flutter test to run the tests.
PragmaDropdownListWidget<String>(
	label: 'Equipo colaborador',
	placeholder: 'Selecciona perfiles',
	options: const <PragmaDropdownOption<String>>[
		PragmaDropdownOption(label: 'UX Research', value: 'research'),
		PragmaDropdownOption(label: 'Mobile iOS', value: 'ios'),
		PragmaDropdownOption(label: 'Mobile Android', value: 'android'),
	],
	initialSelectedValues: const <String>['ios'],
	onSelectionChanged: (List<String> roles) {
		debugPrint('Seleccionados: $roles');
	},
	onItemRemoved: (String value) {
		debugPrint('Eliminado: $value');
	},
)
- `dart format .` to keep formatting consistent.
- `flutter analyze` to validate against `analysis_options.yaml`.
1
likes
160
points
419
downloads

Publisher

verified publisherpragma.co

Weekly Downloads

Flutter library that gathers Pragma's design tokens, themes, and base components for mobile apps.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, google_fonts, intl, meta

More

Packages that depend on pragma_design_system