pragma_design_system 1.4.0
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.
PragmaThemewith 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 thePragmaGridContainerwidget 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:
PragmaColorsexposes brand-awareColorSchemedefinitions for light and dark modes. - Typography:
PragmaTypographydefines responsive scales built on top of Google Fonts. - Spacing:
PragmaSpacingconcentrates 4pt-system values and handy utilities. - Radius:
PragmaBorderRadiusTokensandPragmaBorderRadiuskeep 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:
PragmaOpacityTokensandPragmaOpacityconstrain overlays to 8/30/60 intervals usingColor.withValuesfor Flutter 3.22+. - Domain models:
ModelPragmaComponent,ModelAnatomyAttribute,ModelFieldState,ModelColorToken, andModelThemePragmaserialize the documentation sourced from Figma, power the input widgets, and guarantee JSON roundtrips. - Grid:
PragmaGridTokens,getGridConfigFromContext,PragmaGridContainer, andPragmaScaleBoxhelp 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, orPragmaTableWidgetship 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: 'eugenia.sarmiento@pragma.com.co',
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 #
- Ejecuta el
example/y presiona el botón Theme lab delAppBar(junto al Grid debugger) para abrir la página dedicada. - Ajusta la tipografía, el modo (claro/oscuro) y cada
ModelColorTokendesde losPragmaColorTokenRowWidgetdentro del panel izquierdo. - Observa los cambios en vivo en el panel derecho: los botones, tarjetas (
PragmaCardWidget) y gradientes usan elThemeDatagenerado porPragmaThemeBuilder. - Copia el JSON resultante desde la sección "JSON listo para exportar" para versionarlo o compartirlo con tu squad.
- Carga el JSON dentro de tu app (
ModelThemePragma.fromJson(payload)) y construye unThemeDataconPragmaThemeBuilder.buildThemepara 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');
},
);
Breadcrumb quick sample #
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
PragmaTypographyapplies it throughGoogleFonts.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
.ttffiles 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 #
-
Download the weights you use (for example Regular, SemiBold, and Bold) from Google Fonts and store them inside
assets/fonts/. -
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 -
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: () {},
),
],
)
Dropdown quick sample #
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 testto run the tests.
Dropdown list quick sample #
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`.