|
1 | | -# ResponsiveRow & ResponsiveCol Skill |
| 1 | +--- |
| 2 | +name: responsive-row |
| 3 | +description: ResponsiveRow and ResponsiveCol — Material 3 responsive grid layouts with breakpoint-based column sizing |
| 4 | +--- |
2 | 5 |
|
3 | 6 | ## Overview |
4 | 7 |
|
5 | | -ResponsiveRow and ResponsiveCol form a 12-column responsive grid system for Flutter. ResponsiveRow wraps ResponsiveCol children and uses Dart's `Wrap` widget for layout. ResponsiveCol applies responsive sizing based on breakpoints (xs, sm, md, lg, xl). |
| 8 | +`ResponsiveRow` and `ResponsiveCol` provide a responsive 12-column grid system for layrz_theme. ResponsiveRow acts as a flex container using Wrap layout, while ResponsiveCol defines column width at different breakpoints (xs, sm, md, lg, xl). Together they create layouts that adapt to screen size without manual media queries. |
6 | 9 |
|
7 | | -**File locations:** |
8 | | -- `lib/src/grid/src/row.dart` — ResponsiveRow |
9 | | -- `lib/src/grid/src/col.dart` — ResponsiveCol |
10 | | -- `lib/src/grid/src/sizes.dart` — Sizes enum and extensions |
| 10 | +| Feature | Details | |
| 11 | +|---|---| |
| 12 | +| Responsive Breakpoints | xs (0-600), sm (600-960), md (960-1264), lg (1264-1904), xl (1904+) | |
| 13 | +| 12-Column Grid | Sizes enum with col1-col12 for flexible width specification | |
| 14 | +| Wrap Layout | ResponsiveRow uses Wrap for automatic line breaking when space insufficient | |
| 15 | +| Builder Pattern | ResponsiveRow.builder for dynamic child generation | |
| 16 | +| Spacing Control | Configurable gap between columns | |
| 17 | +| Alignment Options | Main axis and cross axis alignment control | |
| 18 | +| Full-Width Enforcement | ResponsiveRow always spans full parent width | |
| 19 | +| Fallback Chain | Missing breakpoints cascade to larger breakpoints automatically | |
11 | 20 |
|
12 | | -## Components |
| 21 | +**When to use:** Responsive dashboards, card grids, sidebar + content layouts, responsive forms. Prefer when you need width-based column sizing without MediaQuery or custom LayoutDelegate. |
13 | 22 |
|
14 | | -### ResponsiveRow |
| 23 | +## ResponsiveRow |
15 | 24 |
|
16 | | -Horizontal flex container that arranges ResponsiveCol children using a Wrap widget. All children are arranged horizontally with configurable spacing and alignment. |
| 25 | +Horizontal container that arranges ResponsiveCol children using a Wrap widget. All children are laid out horizontally with configurable spacing and alignment. Wraps to next line when space is insufficient. |
17 | 26 |
|
18 | | -**Parameters:** |
19 | | -- `children: List<ResponsiveCol>` — **Required.** Must be ResponsiveCol widgets only. Type-safe at compile time. |
20 | | -- `spacing: double` — Space between children (default: 0) |
21 | | -- `mainAxisAlignment: WrapAlignment` — Horizontal alignment (default: .start) |
22 | | -- `crossAxisAlignment: WrapCrossAlignment` — Vertical alignment (default: .start) |
23 | | -- `key: Key?` — Optional widget key |
| 27 | +### Key Parameters |
24 | 28 |
|
25 | | -**Constructor:** |
26 | | -```dart |
27 | | -const ResponsiveRow({ |
28 | | - required this.children, |
29 | | - this.mainAxisAlignment = .start, |
30 | | - this.crossAxisAlignment = .start, |
31 | | - this.spacing = 0, |
32 | | -}) |
33 | | -``` |
| 29 | +| Parameter | Type | Default | Notes | |
| 30 | +|---|---|---|---| |
| 31 | +| `children` | `List<Widget>` | required (OR `builder`) | List of ResponsiveCol widgets. Type-safe at compile time | |
| 32 | +| `builder` | `IndexedWidgetBuilder?` | required (OR `children`) | Build function for dynamic children. Use with `itemCount` | |
| 33 | +| `itemCount` | `int?` | `null` | Number of items to build when using `builder` | |
| 34 | +| `spacing` | `double` | `0` | Horizontal gap between columns (in pixels) | |
| 35 | +| `mainAxisAlignment` | `WrapAlignment` | `.start` | Horizontal alignment of columns | |
| 36 | +| `crossAxisAlignment` | `WrapCrossAlignment` | `.start` | Vertical alignment of columns | |
| 37 | + |
| 38 | +### Minimal responsive row |
34 | 39 |
|
35 | | -**Factory Constructor (builder):** |
36 | 40 | ```dart |
37 | | -static ResponsiveRow builder({ |
38 | | - required int itemCount, |
39 | | - required ResponsiveCol Function(int) itemBuilder, |
40 | | - WrapAlignment mainAxisAlignment = .start, |
41 | | - WrapCrossAlignment crossAxisAlignment = .start, |
42 | | - double spacing = 0, |
43 | | -}) |
| 41 | +ResponsiveRow( |
| 42 | + children: [ |
| 43 | + ResponsiveCol(xs: Sizes.col12, sm: Sizes.col6, md: Sizes.col4, child: CardWidget()), |
| 44 | + ResponsiveCol(xs: Sizes.col12, sm: Sizes.col6, md: Sizes.col4, child: CardWidget()), |
| 45 | + ResponsiveCol(xs: Sizes.col12, sm: Sizes.col6, md: Sizes.col4, child: CardWidget()), |
| 46 | + ], |
| 47 | +) |
44 | 48 | ``` |
45 | 49 |
|
46 | | -Generates ResponsiveRow with `itemCount` children by calling `itemBuilder` for each index. |
| 50 | +### Row with spacing and alignment |
47 | 51 |
|
48 | | -**Gotchas:** |
49 | | -1. **itemCount must be >= 0** — builder will iterate 0 times if itemCount is 0 (valid, renders empty Wrap) |
50 | | -2. **Type safety** — Dart prevents non-ResponsiveCol widgets at compile time. No runtime validation needed. |
51 | | -3. **Wrap behavior** — Children wrap to next line when they exceed container width |
52 | | -4. **Full width enforced** — ResponsiveRow always has `width: double.infinity` |
53 | | - |
54 | | -**Example:** |
55 | 52 | ```dart |
56 | | -// Manual children |
57 | 53 | ResponsiveRow( |
58 | 54 | spacing: 16, |
59 | 55 | mainAxisAlignment: WrapAlignment.spaceEvenly, |
| 56 | + crossAxisAlignment: WrapCrossAlignment.center, |
60 | 57 | children: [ |
61 | | - ResponsiveCol(xs: .col6, md: .col4, child: Container()), |
62 | | - ResponsiveCol(xs: .col6, md: .col4, child: Container()), |
63 | | - ResponsiveCol(xs: .col12, md: .col4, child: Container()), |
| 58 | + ResponsiveCol(xs: Sizes.col12, md: Sizes.col6, child: SidebarWidget()), |
| 59 | + ResponsiveCol(xs: Sizes.col12, md: Sizes.col6, child: ContentWidget()), |
64 | 60 | ], |
65 | 61 | ) |
| 62 | +``` |
66 | 63 |
|
67 | | -// Using builder |
| 64 | +### Row with builder for dynamic children |
| 65 | + |
| 66 | +```dart |
68 | 67 | ResponsiveRow.builder( |
| 68 | + spacing: 12, |
69 | 69 | itemCount: 12, |
70 | | - spacing: 8, |
71 | | - itemBuilder: (index) => ResponsiveCol( |
72 | | - xs: .col12, |
73 | | - md: .col6, |
74 | | - lg: .col4, |
75 | | - child: Card(child: Text('Item $index')), |
76 | | - ), |
| 70 | + itemBuilder: (context, index) { |
| 71 | + return ResponsiveCol( |
| 72 | + xs: Sizes.col12, |
| 73 | + sm: Sizes.col6, |
| 74 | + md: Sizes.col4, |
| 75 | + lg: Sizes.col3, |
| 76 | + child: ProductCard(product: products[index]), |
| 77 | + ); |
| 78 | + }, |
77 | 79 | ) |
78 | 80 | ``` |
79 | 81 |
|
80 | | -### ResponsiveCol |
81 | | - |
82 | | -Responsive column wrapper that applies a width based on current screen size and breakpoint configuration. |
| 82 | +## ResponsiveCol |
83 | 83 |
|
84 | | -**Parameters:** |
85 | | -- `child: Widget` — **Required.** Widget to wrap (can be any widget type) |
86 | | -- `xs: Sizes` — Extra small (< 600px), **Required** (default: .col12) |
87 | | -- `sm: Sizes?` — Small (≥ 600px, < 960px), fallback to xs if null |
88 | | -- `md: Sizes?` — Medium (≥ 960px, < 1264px), fallback chain: md → sm → xs |
89 | | -- `lg: Sizes?` — Large (≥ 1264px, < 1904px), fallback chain: lg → md → sm → xs |
90 | | -- `xl: Sizes?` — Extra large (≥ 1904px), fallback chain: xl → lg → md → sm → xs |
91 | | -- `key: Key?` — Optional widget key |
| 84 | +Defines a column's width at different breakpoints. Must be a child of ResponsiveRow. Uses LayoutBuilder internally to detect current breakpoint and apply responsive sizing. |
92 | 85 |
|
93 | | -**Constructor:** |
94 | | -```dart |
95 | | -const ResponsiveCol({ |
96 | | - this.xs = .col12, |
97 | | - this.sm, |
98 | | - this.md, |
99 | | - this.lg, |
100 | | - this.xl, |
101 | | - required this.child, |
102 | | -}) |
103 | | -``` |
104 | | - |
105 | | -**Breakpoint Values (constants):** |
106 | | -```dart |
107 | | -const double kExtraSmallGrid = 600; // xs |
108 | | -const double kSmallGrid = 960; // sm |
109 | | -const double kMediumGrid = 1264; // md |
110 | | -const double kLargeGrid = 1904; // lg |
111 | | -// xl is anything >= kLargeGrid |
112 | | -``` |
| 86 | +### Key Parameters |
113 | 87 |
|
114 | | -**Sizes Enum:** |
115 | | -- `col1` through `col12` — grid columns (1/12 to 12/12 of available width) |
116 | | -- Each size calculates: `width = (containerWidth / 12) * gridSize` |
| 88 | +| Parameter | Type | Default | Notes | |
| 89 | +|---|---|---|---| |
| 90 | +| `child` | `Widget` | required | Content widget displayed in this column | |
| 91 | +| `xs` | `Sizes` | `col12` | Width at extra small breakpoint (0-600px) | |
| 92 | +| `sm` | `Sizes?` | `null` | Width at small breakpoint (600-960px). Falls back to xs if null | |
| 93 | +| `md` | `Sizes?` | `null` | Width at medium breakpoint (960-1264px). Falls back to sm→xs if null | |
| 94 | +| `lg` | `Sizes?` | `null` | Width at large breakpoint (1264-1904px). Falls back to md→sm→xs if null | |
| 95 | +| `xl` | `Sizes?` | `null` | Width at extra large breakpoint (1904px+). Falls back to lg→md→sm→xs if null | |
117 | 96 |
|
118 | | -**Gotchas:** |
119 | | -1. **Fallback chain is critical** — If md is null, ResponsiveCol will use sm or xs. This allows "lazy" specification: |
120 | | - ```dart |
121 | | - ResponsiveCol( |
122 | | - xs: .col12, // mobile: full width |
123 | | - lg: .col6, // desktop: half width |
124 | | - // sm and md inherit: sm→xs (col12), md→xs (col12) |
125 | | - ) |
126 | | - ``` |
| 97 | +### Sizes Enum |
127 | 98 |
|
128 | | -2. **LayoutBuilder is used internally** — Breakpoints are re-evaluated when constraints change (window resize, parent reflow) |
| 99 | +Column widths specified using Sizes enum with 12-column system: |
| 100 | +- `Sizes.col1` through `Sizes.col12` — represents 1 to 12 columns |
| 101 | +- Width = `(containerWidth / 12) * columnCount` |
129 | 102 |
|
130 | | -3. **Width calculation is proportional** — All widths are based on 12-column system: |
131 | | - - col6 at 1200px = 600px |
132 | | - - col3 at 600px = 150px |
133 | | - - col1 at 1200px = 100px |
| 103 | +### Minimal column |
134 | 104 |
|
135 | | -4. **Width never exceeds container** — ResponsiveCol fits within parent constraints |
| 105 | +```dart |
| 106 | +ResponsiveCol( |
| 107 | + xs: Sizes.col12, |
| 108 | + md: Sizes.col6, |
| 109 | + child: CardWidget(), |
| 110 | +) |
| 111 | +``` |
136 | 112 |
|
137 | | -5. **All nullable sizes default to xs if specified** — You don't need to specify all breakpoints |
| 113 | +### Column with all breakpoints |
138 | 114 |
|
139 | | -**Example:** |
140 | 115 | ```dart |
141 | | -// Responsive across all breakpoints |
142 | 116 | ResponsiveCol( |
143 | | - xs: .col12, // Mobile: full width |
144 | | - sm: .col6, // Tablet portrait: 50% |
145 | | - md: .col4, // Tablet landscape: 33% |
146 | | - lg: .col3, // Desktop: 25% |
147 | | - xl: .col2, // Ultra-wide: 16% |
148 | | - child: Card(child: Text('Responsive!')), |
| 117 | + xs: Sizes.col12, // Mobile: full width |
| 118 | + sm: Sizes.col6, // Tablet: half width |
| 119 | + md: Sizes.col4, // Desktop: one-third |
| 120 | + lg: Sizes.col3, // Large: one-quarter |
| 121 | + xl: Sizes.col2, // Extra large: one-sixth |
| 122 | + child: ProductCard(), |
149 | 123 | ) |
| 124 | +``` |
150 | 125 |
|
151 | | -// Lazy specification (some breakpoints inherit) |
| 126 | +### Column with fallback chain (lazy specification) |
| 127 | + |
| 128 | +```dart |
152 | 129 | ResponsiveCol( |
153 | | - xs: .col12, |
154 | | - lg: .col6, |
155 | | - child: Button(onPressed: () {}), |
| 130 | + xs: Sizes.col12, // Mobile: full width (explicit) |
| 131 | + md: Sizes.col8, // Desktop: two-thirds (sm and lg fall back to this) |
| 132 | + // sm → falls back to md (col8) |
| 133 | + // lg → falls back to xl (col12) → defaults to col12 |
| 134 | + child: ArticleView(), |
156 | 135 | ) |
157 | | -// At sm/md: uses xs (.col12) |
158 | | -// At lg/xl: uses lg (.col6) |
159 | 136 | ``` |
160 | 137 |
|
161 | 138 | ## Sizes Enum & Extension |
|
0 commit comments