forked from mirrors/material_3_expressive
Bump package versions to 0.3.0 across most packages; update navigation_rail_m3e to 0.3.2, add new features, enhancements, and documentation to navigation_rail_m3e. Update melos.yaml with new scripts. Refactor update_versions.dart script.
This commit is contained in:
parent
ba16b94a9a
commit
a255494ec1
28 changed files with 280 additions and 48 deletions
|
|
@ -11,6 +11,8 @@ scripts:
|
||||||
bootstrap: melos bootstrap
|
bootstrap: melos bootstrap
|
||||||
clean: melos exec -- flutter clean
|
clean: melos exec -- flutter clean
|
||||||
get: melos exec -- flutter pub get
|
get: melos exec -- flutter pub get
|
||||||
|
upgrade: melos exec -- flutter pub upgrade
|
||||||
|
upgrade-major: melos exec -- flutter pub upgrade --major-versions
|
||||||
format: melos exec -- dart format --set-exit-if-changed .
|
format: melos exec -- dart format --set-exit-if-changed .
|
||||||
analyze: melos exec -- dart analyze --fatal-infos --fatal-warnings
|
analyze: melos exec -- dart analyze --fatal-infos --fatal-warnings
|
||||||
test: melos exec -- flutter test --coverage
|
test: melos exec -- flutter test --coverage
|
||||||
|
|
@ -31,6 +33,3 @@ scripts:
|
||||||
noPrivate: true
|
noPrivate: true
|
||||||
dirExists:
|
dirExists:
|
||||||
- lib
|
- lib
|
||||||
set-version:
|
|
||||||
run: dart run tool/update_versions.dart
|
|
||||||
description: "Set version for all packages (usage: melos run set-version -- version=1.2.3)"
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: app_bar_m3e
|
name: app_bar_m3e
|
||||||
description: Expressive App Bar (Material 3 Expressive) with small/medium/large variants and Sliver integration.
|
description: Expressive App Bar (Material 3 Expressive) with small/medium/large variants and Sliver integration.
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/app_bar_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/app_bar_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: button_group_m3e
|
name: button_group_m3e
|
||||||
description: Wrapper-only Button Group for Material 3 Expressive (layout, shape, size propagation).
|
description: Wrapper-only Button Group for Material 3 Expressive (layout, shape, size propagation).
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/button_group_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/button_group_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
name: button_m3e
|
name: button_m3e
|
||||||
description: Material 3 Expressive Buttons for Flutter with 5 styles, 5 sizes, round/square shapes, and toggle selection.
|
description: Material 3 Expressive Buttons for Flutter with 5 styles, 5 sizes, round/square shapes, and toggle selection.
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/button_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/button_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: fab_m3e
|
name: fab_m3e
|
||||||
description: Material 3 Expressive Floating Action Button (FAB), Extended FAB, and FAB Menu for Flutter using M3E tokens.
|
description: Material 3 Expressive Floating Action Button (FAB), Extended FAB, and FAB Menu for Flutter using M3E tokens.
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/fab_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/fab_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,22 @@
|
||||||
<excludeFolder url="file://$MODULE_DIR$/example/macos/Flutter" />
|
<excludeFolder url="file://$MODULE_DIR$/example/macos/Flutter" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/example/macos/Pods" />
|
<excludeFolder url="file://$MODULE_DIR$/example/macos/Pods" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/example/macos/.symlinks" />
|
<excludeFolder url="file://$MODULE_DIR$/example/macos/.symlinks" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/example/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/example/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/windows/flutter/ephemeral/.plugin_symlinks/dynamic_color/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/windows/flutter/ephemeral/.plugin_symlinks/dynamic_color/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/windows/flutter/ephemeral/.plugin_symlinks/dynamic_color/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/windows/flutter/ephemeral/.plugin_symlinks/dynamic_color/example/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/windows/flutter/ephemeral/.plugin_symlinks/dynamic_color/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/windows/flutter/ephemeral/.plugin_symlinks/dynamic_color/example/build" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||||
<orderEntry type="library" name="Flutter Plugins" level="project" />
|
<orderEntry type="library" name="Flutter Plugins" level="project" />
|
||||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: icon_button_m3e
|
name: icon_button_m3e
|
||||||
description: "Material 3 Expressive IconButton with sizes, variants, shapes, toggle, and accessible hit targets."
|
description: "Material 3 Expressive IconButton with sizes, variants, shapes, toggle, and accessible hit targets."
|
||||||
version: 0.2.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/icon_button_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/icon_button_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ dependencies:
|
||||||
m3e_design: ^0.1.0
|
m3e_design: ^0.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_lints: ^4.0.0
|
flutter_lints: ^6.0.0
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: loading_indicator_m3e
|
name: loading_indicator_m3e
|
||||||
description: Material 3 Expressive Loading Indicator (morphing polygons) for Flutter, with Default and Contained variants.
|
description: Material 3 Expressive Loading Indicator (morphing polygons) for Flutter, with Default and Contained variants.
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/loading_indicator_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/loading_indicator_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: m3e_collection
|
name: m3e_collection
|
||||||
description: Aggregated exports of all Material 3 Expressive components for Flutter.
|
description: Aggregated exports of all Material 3 Expressive components for Flutter.
|
||||||
version: 0.1.0
|
version: 0.3.2
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/m3e_collection
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/m3e_collection
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
@ -20,7 +20,7 @@ dependencies:
|
||||||
m3e_design: ^0.1.0
|
m3e_design: ^0.1.0
|
||||||
material_new_shapes: ^1.0.0
|
material_new_shapes: ^1.0.0
|
||||||
navigation_bar_m3e: ^0.1.0
|
navigation_bar_m3e: ^0.1.0
|
||||||
navigation_rail_m3e: ^0.1.1
|
navigation_rail_m3e: ^0.3.2
|
||||||
progress_indicator_m3e: ^0.1.0
|
progress_indicator_m3e: ^0.1.0
|
||||||
slider_m3e: ^0.1.0
|
slider_m3e: ^0.1.0
|
||||||
split_button_m3e: ^0.2.0
|
split_button_m3e: ^0.2.0
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: m3e_design
|
name: m3e_design
|
||||||
description: Material 3 Expressive design language for Flutter (tokens, ThemeExtension, motion).
|
description: Material 3 Expressive design language for Flutter (tokens, ThemeExtension, motion).
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/m3e_design
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/m3e_design
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: navigation_bar_m3e
|
name: navigation_bar_m3e
|
||||||
description: Material 3 Expressive Navigation Bar for Flutter with token-driven colors, shapes, and badges.
|
description: Material 3 Expressive Navigation Bar for Flutter with token-driven colors, shapes, and badges.
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/navigation_bar_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/navigation_bar_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ void main() {
|
||||||
runApp(const DemoApp());
|
runApp(const DemoApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Simple demo application for NavigationRailM3E.
|
||||||
class DemoApp extends StatefulWidget {
|
class DemoApp extends StatefulWidget {
|
||||||
|
/// Creates the demo app widget.
|
||||||
const DemoApp({super.key});
|
const DemoApp({super.key});
|
||||||
@override
|
@override
|
||||||
State<DemoApp> createState() => _DemoAppState();
|
State<DemoApp> createState() => _DemoAppState();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// ignore_for_file: public_member_api_docs
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
library navigation_rail_m3e;
|
library;
|
||||||
|
|
||||||
export 'src/modality.dart';
|
export 'src/modality.dart';
|
||||||
export 'src/navigation_rail_m3e_widget.dart';
|
export 'src/navigation_rail_m3e_widget.dart';
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class NavigationRailM3E extends StatefulWidget {
|
||||||
/// Creates a Material 3 Expressive navigation rail.
|
/// Creates a Material 3 Expressive navigation rail.
|
||||||
const NavigationRailM3E({
|
const NavigationRailM3E({
|
||||||
super.key,
|
super.key,
|
||||||
required this.type,
|
this.type = NavigationRailM3EType.expanded,
|
||||||
this.modality = NavigationRailM3EModality.standard,
|
this.modality = NavigationRailM3EModality.standard,
|
||||||
required this.sections,
|
required this.sections,
|
||||||
required this.selectedIndex,
|
required this.selectedIndex,
|
||||||
|
|
@ -27,9 +27,12 @@ class NavigationRailM3E extends StatefulWidget {
|
||||||
this.onDismissModal,
|
this.onDismissModal,
|
||||||
this.onTypeChanged,
|
this.onTypeChanged,
|
||||||
this.labelBehavior = NavigationRailM3ELabelBehavior.alwaysShow,
|
this.labelBehavior = NavigationRailM3ELabelBehavior.alwaysShow,
|
||||||
|
this.scrollable = true,
|
||||||
|
this.trailing,
|
||||||
|
this.trailingAtBottom = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Presentation type for the rail (collapsed or expanded).
|
/// Presentation type for the rail (collapsed or expanded or alwaysCollapsed or alwaysExpanded).
|
||||||
final NavigationRailM3EType type;
|
final NavigationRailM3EType type;
|
||||||
|
|
||||||
/// How the rail is shown (standard or modal overlay).
|
/// How the rail is shown (standard or modal overlay).
|
||||||
|
|
@ -62,6 +65,21 @@ class NavigationRailM3E extends StatefulWidget {
|
||||||
/// Controls how labels are shown when the rail is expanded.
|
/// Controls how labels are shown when the rail is expanded.
|
||||||
final NavigationRailM3ELabelBehavior labelBehavior;
|
final NavigationRailM3ELabelBehavior labelBehavior;
|
||||||
|
|
||||||
|
/// Whether the rail's main content area should be scrollable.
|
||||||
|
/// Defaults to true to match the current behavior.
|
||||||
|
final bool scrollable;
|
||||||
|
|
||||||
|
/// Optional trailing widget, always conceptually placed after the sections.
|
||||||
|
/// When [trailingAtBottom] is true, it's pinned to the bottom of the rail,
|
||||||
|
/// leaving flexible space between the sections and the trailing.
|
||||||
|
/// When false, it's inserted immediately after the sections within the content.
|
||||||
|
final Widget? trailing;
|
||||||
|
|
||||||
|
/// Controls where the trailing is placed relative to the rail's bottom.
|
||||||
|
/// If true, [trailing] is pinned to the bottom with space to the sections.
|
||||||
|
/// If false, [trailing] appears directly after the sections.
|
||||||
|
final bool trailingAtBottom;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<NavigationRailM3E> createState() => _NavigationRailM3EState();
|
State<NavigationRailM3E> createState() => _NavigationRailM3EState();
|
||||||
}
|
}
|
||||||
|
|
@ -73,15 +91,37 @@ class _NavigationRailM3EState extends State<NavigationRailM3E>
|
||||||
final LayerLink _anchor = LayerLink();
|
final LayerLink _anchor = LayerLink();
|
||||||
bool _suppressInk = false;
|
bool _suppressInk = false;
|
||||||
|
|
||||||
bool get _isExpanded => widget.type == NavigationRailM3EType.expanded;
|
// Internal expanded/collapsed state. Initialized from widget.type and then
|
||||||
|
// controlled internally by the rail's menu button.
|
||||||
|
bool _expanded = false;
|
||||||
|
|
||||||
|
bool get _isExpanded => _expanded;
|
||||||
bool get _isModal => widget.modality == NavigationRailM3EModality.modal;
|
bool get _isModal => widget.modality == NavigationRailM3EModality.modal;
|
||||||
bool get _needsOverlay => _isModal && _isExpanded;
|
bool get _needsOverlay => _isModal && _isExpanded;
|
||||||
bool get _needsCollapsedPeek =>
|
bool get _needsCollapsedPeek =>
|
||||||
!_isExpanded && !_isModal && widget.hideWhenCollapsed;
|
!_isExpanded && !_isModal && widget.hideWhenCollapsed && _canToggle;
|
||||||
|
|
||||||
|
bool get _canToggle =>
|
||||||
|
widget.type == NavigationRailM3EType.collapsed ||
|
||||||
|
widget.type == NavigationRailM3EType.expanded;
|
||||||
|
|
||||||
|
NavigationRailM3EType get _notifiedType => _expanded
|
||||||
|
? NavigationRailM3EType.expanded
|
||||||
|
: NavigationRailM3EType.collapsed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
// Initialize internal expanded state from the provided type.
|
||||||
|
// When toggleable (collapsed/expanded), mirror the provided type.
|
||||||
|
// When locked (alwaysCollapse/alwaysExpand), infer via enum name.
|
||||||
|
if (_canToggle) {
|
||||||
|
_expanded = widget.type == NavigationRailM3EType.expanded;
|
||||||
|
} else {
|
||||||
|
final name = widget.type.toString();
|
||||||
|
final isAlwaysCollapse = name.contains('alwaysCollapse');
|
||||||
|
_expanded = !isAlwaysCollapse; // alwaysExpand => true
|
||||||
|
}
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _syncOverlay());
|
WidgetsBinding.instance.addPostFrameCallback((_) => _syncOverlay());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,6 +137,27 @@ class _NavigationRailM3EState extends State<NavigationRailM3E>
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep internal state in sync with locking semantics of `always*` types.
|
||||||
|
final bool oldCanToggle =
|
||||||
|
oldWidget.type == NavigationRailM3EType.collapsed ||
|
||||||
|
oldWidget.type == NavigationRailM3EType.expanded;
|
||||||
|
final bool newCanToggle = _canToggle;
|
||||||
|
|
||||||
|
if (!newCanToggle) {
|
||||||
|
// Force the locked state.
|
||||||
|
final name = widget.type.toString();
|
||||||
|
final bool lockExpanded = !name.contains('alwaysCollapse');
|
||||||
|
if (_expanded != lockExpanded) {
|
||||||
|
setState(() => _expanded = lockExpanded);
|
||||||
|
}
|
||||||
|
} else if (!oldCanToggle && newCanToggle) {
|
||||||
|
// Transition from locked to toggleable: seed from the new default.
|
||||||
|
final bool startExpanded = widget.type == NavigationRailM3EType.expanded;
|
||||||
|
if (_expanded != startExpanded) {
|
||||||
|
setState(() => _expanded = startExpanded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _syncOverlay());
|
WidgetsBinding.instance.addPostFrameCallback((_) => _syncOverlay());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,6 +217,19 @@ class _NavigationRailM3EState extends State<NavigationRailM3E>
|
||||||
_collapsedPeekEntry = null;
|
_collapsedPeekEntry = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _setExpanded(bool value) {
|
||||||
|
if (_expanded == value) return;
|
||||||
|
setState(() {
|
||||||
|
_expanded = value;
|
||||||
|
_suppressInk = true;
|
||||||
|
});
|
||||||
|
Future.delayed(const Duration(milliseconds: 320), () {
|
||||||
|
if (mounted) setState(() => _suppressInk = false);
|
||||||
|
});
|
||||||
|
// Notify listeners (if any) for backward compatibility.
|
||||||
|
widget.onTypeChanged?.call(_notifiedType);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildModalOverlay(BuildContext context) {
|
Widget _buildModalOverlay(BuildContext context) {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -192,9 +266,7 @@ class _NavigationRailM3EState extends State<NavigationRailM3E>
|
||||||
Widget btn = IconButtonM3E(
|
Widget btn = IconButtonM3E(
|
||||||
icon: const Icon(Icons.menu),
|
icon: const Icon(Icons.menu),
|
||||||
tooltip: 'Expand',
|
tooltip: 'Expand',
|
||||||
onPressed: widget.onTypeChanged == null
|
onPressed: _canToggle ? () => _setExpanded(true) : null,
|
||||||
? null
|
|
||||||
: () => widget.onTypeChanged!(NavigationRailM3EType.expanded),
|
|
||||||
);
|
);
|
||||||
if (_suppressInk) {
|
if (_suppressInk) {
|
||||||
final t = Theme.of(context);
|
final t = Theme.of(context);
|
||||||
|
|
@ -232,17 +304,13 @@ class _NavigationRailM3EState extends State<NavigationRailM3E>
|
||||||
|
|
||||||
Widget _buildMenuButton(BuildContext context,
|
Widget _buildMenuButton(BuildContext context,
|
||||||
{required Alignment alignment}) {
|
{required Alignment alignment}) {
|
||||||
|
if (!_canToggle) return const SizedBox.shrink();
|
||||||
|
|
||||||
final isExpanded = _isExpanded;
|
final isExpanded = _isExpanded;
|
||||||
Widget button = IconButtonM3E(
|
Widget button = IconButtonM3E(
|
||||||
icon: Icon(isExpanded ? Icons.menu_open : Icons.menu),
|
icon: Icon(isExpanded ? Icons.menu_open : Icons.menu),
|
||||||
tooltip: isExpanded ? 'Collapse' : 'Expand',
|
tooltip: isExpanded ? 'Collapse' : 'Expand',
|
||||||
onPressed: widget.onTypeChanged == null
|
onPressed: () => _setExpanded(!isExpanded),
|
||||||
? null
|
|
||||||
: () => widget.onTypeChanged!(
|
|
||||||
isExpanded
|
|
||||||
? NavigationRailM3EType.collapsed
|
|
||||||
: NavigationRailM3EType.expanded,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_suppressInk) {
|
if (_suppressInk) {
|
||||||
|
|
@ -301,6 +369,19 @@ class _NavigationRailM3EState extends State<NavigationRailM3E>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget? _buildTrailing(BuildContext context) {
|
||||||
|
final tr = widget.trailing;
|
||||||
|
if (tr == null) return null;
|
||||||
|
final isExpanded = _isExpanded;
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.only(start: 16, end: 16, bottom: 12),
|
||||||
|
child: Align(
|
||||||
|
alignment: isExpanded ? Alignment.centerLeft : Alignment.center,
|
||||||
|
child: tr,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
List<Widget> _buildChildren(BuildContext context,
|
List<Widget> _buildChildren(BuildContext context,
|
||||||
{required bool showLabels}) {
|
{required bool showLabels}) {
|
||||||
final theme = Theme.of(context).extension<NavigationRailM3ETheme>() ??
|
final theme = Theme.of(context).extension<NavigationRailM3ETheme>() ??
|
||||||
|
|
@ -364,6 +445,11 @@ class _NavigationRailM3EState extends State<NavigationRailM3E>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Place trailing after sections when not bottom-pinned.
|
||||||
|
if (widget.trailing != null && !widget.trailingAtBottom) {
|
||||||
|
final trailingWidget = _buildTrailing(context);
|
||||||
|
if (trailingWidget != null) children.add(trailingWidget);
|
||||||
|
}
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,10 +464,49 @@ class _NavigationRailM3EState extends State<NavigationRailM3E>
|
||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
builder: (ctx, constraints) {
|
builder: (ctx, constraints) {
|
||||||
final showLabels = _isExpanded && constraints.maxWidth >= 180;
|
final showLabels = _isExpanded && constraints.maxWidth >= 180;
|
||||||
return ListView(
|
final children = _buildChildren(ctx, showLabels: showLabels);
|
||||||
padding: EdgeInsets.zero,
|
final bottomTrailing =
|
||||||
children: _buildChildren(ctx, showLabels: showLabels),
|
(widget.trailing != null && widget.trailingAtBottom)
|
||||||
);
|
? _buildTrailing(ctx)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (widget.scrollable) {
|
||||||
|
if (bottomTrailing != null) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ListView(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
children: children,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomTrailing,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ListView(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (bottomTrailing != null) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: children,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomTrailing,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
/// Model for a navigation destination. One class per file.
|
/// Model for a navigation destination. One class per file.
|
||||||
class NavigationRailM3EDestination {
|
class NavigationRailM3EDestination {
|
||||||
|
/// Creates a [NavigationRailM3EDestination].
|
||||||
const NavigationRailM3EDestination({
|
const NavigationRailM3EDestination({
|
||||||
required this.icon,
|
required this.icon,
|
||||||
this.selectedIcon,
|
this.selectedIcon,
|
||||||
|
|
@ -11,10 +12,19 @@ class NavigationRailM3EDestination {
|
||||||
this.short = false,
|
this.short = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Icon shown for the destination.
|
||||||
final Widget icon;
|
final Widget icon;
|
||||||
|
|
||||||
|
/// Optional icon when selected; falls back to [icon].
|
||||||
final Widget? selectedIcon;
|
final Widget? selectedIcon;
|
||||||
|
|
||||||
|
/// Text label for the destination.
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
|
/// Optional badge count to show.
|
||||||
final int? badgeCount;
|
final int? badgeCount;
|
||||||
|
|
||||||
|
/// Optional semantic label for accessibility.
|
||||||
final String? semanticLabel;
|
final String? semanticLabel;
|
||||||
|
|
||||||
/// If true, uses short item height (56dp) instead of 64dp.
|
/// If true, uses short item height (56dp) instead of 64dp.
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import 'package:flutter/material.dart';
|
||||||
/// Consumers provide values (icon, label, onPressed, etc.) instead of a widget.
|
/// Consumers provide values (icon, label, onPressed, etc.) instead of a widget.
|
||||||
@immutable
|
@immutable
|
||||||
class NavigationRailM3EFabSlot {
|
class NavigationRailM3EFabSlot {
|
||||||
|
/// Creates a [NavigationRailM3EFabSlot].
|
||||||
const NavigationRailM3EFabSlot({
|
const NavigationRailM3EFabSlot({
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.label,
|
required this.label,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:navigation_rail_m3e/navigation_rail_m3e.dart';
|
||||||
/// switching widget types. This avoids animation hitches when the
|
/// switching widget types. This avoids animation hitches when the
|
||||||
/// rail animates between collapsed and expanded.
|
/// rail animates between collapsed and expanded.
|
||||||
class RailItemButtonM3E extends StatelessWidget {
|
class RailItemButtonM3E extends StatelessWidget {
|
||||||
|
/// Creates a [RailItemButtonM3E].
|
||||||
const RailItemButtonM3E({
|
const RailItemButtonM3E({
|
||||||
super.key,
|
super.key,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
|
|
@ -21,15 +22,34 @@ class RailItemButtonM3E extends StatelessWidget {
|
||||||
this.badgeCount,
|
this.badgeCount,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Icon to display.
|
||||||
final Widget icon;
|
final Widget icon;
|
||||||
|
|
||||||
|
/// Optional icon to display when [isSelected] is true; falls back to [icon].
|
||||||
final Widget? selectedIcon;
|
final Widget? selectedIcon;
|
||||||
|
|
||||||
|
/// Whether this destination is currently selected.
|
||||||
final bool isSelected;
|
final bool isSelected;
|
||||||
|
|
||||||
|
/// Callback when the button is tapped.
|
||||||
final VoidCallback onPressed;
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
/// Whether the rail is in expanded layout.
|
||||||
final bool expanded;
|
final bool expanded;
|
||||||
|
|
||||||
|
/// Controls when the text label is visible in collapsed mode.
|
||||||
final NavigationRailM3ELabelBehavior labelBehavior;
|
final NavigationRailM3ELabelBehavior labelBehavior;
|
||||||
|
|
||||||
|
/// Text label for the destination.
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
|
/// Semantic label used for accessibility (and tooltip when collapsed).
|
||||||
final String? semanticLabel;
|
final String? semanticLabel;
|
||||||
|
|
||||||
|
/// If true, suppresses Ink splash/hover effects.
|
||||||
final bool suppressInk;
|
final bool suppressInk;
|
||||||
|
|
||||||
|
/// Optional numeric badge value to show.
|
||||||
final int? badgeCount;
|
final int? badgeCount;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
/// Menu slot at the top of the rail (non-selectable). One class per file.
|
/// Menu slot at the top of the rail (non-selectable). One class per file.
|
||||||
class NavigationRailM3EMenu extends StatelessWidget {
|
class NavigationRailM3EMenu extends StatelessWidget {
|
||||||
|
/// Creates a [NavigationRailM3EMenu].
|
||||||
const NavigationRailM3EMenu({super.key, required this.child});
|
const NavigationRailM3EMenu({super.key, required this.child});
|
||||||
|
|
||||||
|
/// Content widget placed in the menu slot.
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,18 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'rail_destination_m3e.dart';
|
import 'rail_destination_m3e.dart';
|
||||||
|
|
||||||
/// Section groups a header and a list of destinations. One class per file.
|
/// Section groups a header and a list of destinations. One class per file.
|
||||||
class NavigationRailM3ESection {
|
class NavigationRailM3ESection {
|
||||||
|
/// Creates a [NavigationRailM3ESection].
|
||||||
const NavigationRailM3ESection({
|
const NavigationRailM3ESection({
|
||||||
required this.destinations,
|
required this.destinations,
|
||||||
this.header,
|
this.header,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Destinations shown in this section.
|
||||||
final List<NavigationRailM3EDestination> destinations;
|
final List<NavigationRailM3EDestination> destinations;
|
||||||
|
|
||||||
|
/// Optional header widget displayed above the destinations.
|
||||||
final Widget? header;
|
final Widget? header;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
/// Theme extension for NavigationRailM3E token values.
|
/// Theme extension for NavigationRailM3E token values.
|
||||||
class NavigationRailM3ETheme extends ThemeExtension<NavigationRailM3ETheme> {
|
class NavigationRailM3ETheme extends ThemeExtension<NavigationRailM3ETheme> {
|
||||||
|
/// Creates a [NavigationRailM3ETheme] with default token values.
|
||||||
const NavigationRailM3ETheme({
|
const NavigationRailM3ETheme({
|
||||||
this.collapsedWidth = 96.0,
|
this.collapsedWidth = 96.0,
|
||||||
this.expandedMinWidth = 220.0,
|
this.expandedMinWidth = 220.0,
|
||||||
|
|
@ -20,18 +21,43 @@ class NavigationRailM3ETheme extends ThemeExtension<NavigationRailM3ETheme> {
|
||||||
this.sectionHeaderSpacingBottom = 8.0,
|
this.sectionHeaderSpacingBottom = 8.0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Width of the rail when collapsed.
|
||||||
final double collapsedWidth;
|
final double collapsedWidth;
|
||||||
|
|
||||||
|
/// Minimum width of the rail when expanded.
|
||||||
final double expandedMinWidth;
|
final double expandedMinWidth;
|
||||||
|
|
||||||
|
/// Maximum width of the rail when expanded.
|
||||||
final double expandedMaxWidth;
|
final double expandedMaxWidth;
|
||||||
|
|
||||||
|
/// Default height of an item.
|
||||||
final double itemHeight;
|
final double itemHeight;
|
||||||
|
|
||||||
|
/// Short item height variant.
|
||||||
final double itemShortHeight;
|
final double itemShortHeight;
|
||||||
|
|
||||||
|
/// Default icon size used for items.
|
||||||
final double iconSize;
|
final double iconSize;
|
||||||
|
|
||||||
|
/// Leading inset for the active indicator in expanded mode.
|
||||||
final double indicatorLeading;
|
final double indicatorLeading;
|
||||||
|
|
||||||
|
/// Trailing inset for the active indicator in expanded mode.
|
||||||
final double indicatorTrailing;
|
final double indicatorTrailing;
|
||||||
|
|
||||||
|
/// Gap between icon and label.
|
||||||
final double iconLabelGap;
|
final double iconLabelGap;
|
||||||
|
|
||||||
|
/// Vertical gap between items.
|
||||||
final double itemVerticalGap;
|
final double itemVerticalGap;
|
||||||
|
|
||||||
|
/// Minimum spacing between the top and the first header.
|
||||||
final double headerMinSpace;
|
final double headerMinSpace;
|
||||||
|
|
||||||
|
/// Top spacing around a section header.
|
||||||
final double sectionHeaderSpacingTop;
|
final double sectionHeaderSpacingTop;
|
||||||
|
|
||||||
|
/// Bottom spacing around a section header.
|
||||||
final double sectionHeaderSpacingBottom;
|
final double sectionHeaderSpacingBottom;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -3,33 +3,40 @@ import 'package:m3e_design/m3e_design.dart' as m3e;
|
||||||
|
|
||||||
/// Provides colors & shapes from `m3e_design` with safe fallbacks to Theme.of(context).
|
/// Provides colors & shapes from `m3e_design` with safe fallbacks to Theme.of(context).
|
||||||
class NavigationRailTokensAdapter {
|
class NavigationRailTokensAdapter {
|
||||||
|
/// Creates a [NavigationRailTokensAdapter].
|
||||||
const NavigationRailTokensAdapter(this.context);
|
const NavigationRailTokensAdapter(this.context);
|
||||||
|
|
||||||
|
/// Source context for resolving Theme and m3e tokens.
|
||||||
final BuildContext context;
|
final BuildContext context;
|
||||||
|
|
||||||
ColorScheme get _cs => Theme.of(context).colorScheme;
|
ColorScheme get _cs => Theme.of(context).colorScheme;
|
||||||
|
|
||||||
// Colors per spec
|
// Colors per spec
|
||||||
|
/// Background color of the rail container.
|
||||||
Color get containerColor {
|
Color get containerColor {
|
||||||
// Use surface container token if present, else fallback.
|
// Use surface container token if present, else fallback.
|
||||||
return _maybe(() => context.m3e.colors.surfaceContainer) ??
|
return _maybe(() => context.m3e.colors.surfaceContainer) ??
|
||||||
_cs.surfaceContainer;
|
_cs.surfaceContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Background color of the active item indicator.
|
||||||
Color get activeIndicatorColor {
|
Color get activeIndicatorColor {
|
||||||
return _maybe(() => context.m3e.colors.secondaryContainer) ??
|
return _maybe(() => context.m3e.colors.secondaryContainer) ??
|
||||||
_cs.secondaryContainer;
|
_cs.secondaryContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Color for the icon and label when the item is active.
|
||||||
Color get activeIconAndLabel {
|
Color get activeIconAndLabel {
|
||||||
return _maybe(() => context.m3e.colors.secondary) ?? _cs.secondary;
|
return _maybe(() => context.m3e.colors.secondary) ?? _cs.secondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Color for the icon and label when the item is inactive.
|
||||||
Color get inactiveIconAndLabel {
|
Color get inactiveIconAndLabel {
|
||||||
return _maybe(() => context.m3e.colors.onSurfaceVariant) ??
|
return _maybe(() => context.m3e.colors.onSurfaceVariant) ??
|
||||||
_cs.onSurfaceVariant;
|
_cs.onSurfaceVariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Foreground color used for the menu (top) slot.
|
||||||
Color get menuColor {
|
Color get menuColor {
|
||||||
return _maybe(() => context.m3e.colors.onSecondaryContainer) ??
|
return _maybe(() => context.m3e.colors.onSecondaryContainer) ??
|
||||||
_cs.onSecondaryContainer;
|
_cs.onSecondaryContainer;
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,22 @@ enum NavigationRailM3EType {
|
||||||
/// Slim 96dp rail.
|
/// Slim 96dp rail.
|
||||||
collapsed,
|
collapsed,
|
||||||
|
|
||||||
|
/// Slim 96dp rail with no button to expand.
|
||||||
|
alwaysCollapse,
|
||||||
|
|
||||||
/// Wide 220–360dp rail that replaces the drawer.
|
/// Wide 220–360dp rail that replaces the drawer.
|
||||||
expanded,
|
expanded,
|
||||||
|
|
||||||
|
/// Wide 220–360dp rail that replaces the drawer with no button to collapse.
|
||||||
|
alwaysExpand,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience extension for checking the current rail type.
|
||||||
extension NavigationRailM3ETypeX on NavigationRailM3EType {
|
extension NavigationRailM3ETypeX on NavigationRailM3EType {
|
||||||
|
/// Whether this type equals [NavigationRailM3EType.collapsed].
|
||||||
bool get isCollapsed => this == NavigationRailM3EType.collapsed;
|
bool get isCollapsed => this == NavigationRailM3EType.collapsed;
|
||||||
|
|
||||||
|
/// Whether this type equals [NavigationRailM3EType.expanded].
|
||||||
bool get isExpanded => this == NavigationRailM3EType.expanded;
|
bool get isExpanded => this == NavigationRailM3EType.expanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,7 +28,12 @@ extension NavigationRailM3ETypeX on NavigationRailM3EType {
|
||||||
/// - onlySelected: show the label only for the selected destination.
|
/// - onlySelected: show the label only for the selected destination.
|
||||||
/// - alwaysHide: never show labels even when expanded.
|
/// - alwaysHide: never show labels even when expanded.
|
||||||
enum NavigationRailM3ELabelBehavior {
|
enum NavigationRailM3ELabelBehavior {
|
||||||
|
/// Always show labels (subject to width constraints).
|
||||||
alwaysShow,
|
alwaysShow,
|
||||||
|
|
||||||
|
/// Show the label only for the selected destination.
|
||||||
onlySelected,
|
onlySelected,
|
||||||
|
|
||||||
|
/// Never show labels even when expanded.
|
||||||
alwaysHide,
|
alwaysHide,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: navigation_rail_m3e
|
name: navigation_rail_m3e
|
||||||
description: Material 3 Expressive navigation rail (collapsed & expanded) with modal/standard modes, badges, sections, and m3e_design token integration.
|
description: Material 3 Expressive navigation rail (collapsed & expanded) with modal/standard modes, badges, sections, and m3e_design token integration.
|
||||||
version: 0.1.1
|
version: 0.3.2
|
||||||
homepage: https://github.com/EmilyMonestone/material_3_expressive
|
homepage: https://github.com/EmilyMonestone/material_3_expressive
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/navigation_rail_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/navigation_rail_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
@ -20,7 +20,7 @@ dependencies:
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_lints: ^4.0.0
|
flutter_lints: ^6.0.0
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: progress_indicator_m3e
|
name: progress_indicator_m3e
|
||||||
description: "Material 3 Expressive progress indicators."
|
description: "Material 3 Expressive progress indicators."
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/progress_indicator_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/progress_indicator_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: slider_m3e
|
name: slider_m3e
|
||||||
description: Material 3 Expressive Sliders (single & range) for Flutter, powered by M3E tokens.
|
description: Material 3 Expressive Sliders (single & range) for Flutter, powered by M3E tokens.
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/slider_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/slider_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: split_button_m3e
|
name: split_button_m3e
|
||||||
description: "Material 3 Expressive Split Button with sizes, variants, shapes, a11y, and menu."
|
description: "Material 3 Expressive Split Button with sizes, variants, shapes, a11y, and menu."
|
||||||
version: 0.2.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/split_button_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/split_button_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: toolbar_m3e
|
name: toolbar_m3e
|
||||||
description: Material 3 Expressive Toolbars for Flutter with token-driven colors, shapes, density, and overflow handling.
|
description: Material 3 Expressive Toolbars for Flutter with token-driven colors, shapes, density, and overflow handling.
|
||||||
version: 0.1.0
|
version: 0.3.0
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/toolbar_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/toolbar_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@ void main(List<String> args) {
|
||||||
(a) => a.startsWith('version='),
|
(a) => a.startsWith('version='),
|
||||||
orElse: () => 'version=',
|
orElse: () => 'version=',
|
||||||
);
|
);
|
||||||
final version = versionArg.split('=', 2).last.trim();
|
final version = versionArg.split('=').last.trim();
|
||||||
if (version.isEmpty) {
|
if (version.isEmpty) {
|
||||||
stderr.writeln('Usage: dart run tool/update_versions.dart -- version=<semver>');
|
stderr.writeln(
|
||||||
|
'Usage: dart run tool/update_versions.dart -- version=<semver>');
|
||||||
exit(64);
|
exit(64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,22 +42,28 @@ void main(List<String> args) {
|
||||||
// Skip if it's clearly an app (heuristic): has 'flutter:' and 'uses-material-design:' at top-level
|
// Skip if it's clearly an app (heuristic): has 'flutter:' and 'uses-material-design:' at top-level
|
||||||
// but the requirement is to update all packages under packages/*. We will proceed regardless.
|
// but the requirement is to update all packages under packages/*. We will proceed regardless.
|
||||||
|
|
||||||
final nameMatch = RegExp(r'^name:\s*(.+)$', multiLine: true).firstMatch(content);
|
final nameMatch =
|
||||||
final pkgName = nameMatch != null ? nameMatch.group(1)!.trim() : file.parent.path.split('\\').last;
|
RegExp(r'^name:\s*(.+)$', multiLine: true).firstMatch(content);
|
||||||
|
final pkgName = nameMatch != null
|
||||||
|
? nameMatch.group(1)!.trim()
|
||||||
|
: file.parent.path.split('\\').last;
|
||||||
|
|
||||||
String updatedContent;
|
String updatedContent;
|
||||||
final versionRe = RegExp(r'^version:\s*.*$', multiLine: true);
|
final versionRe = RegExp(r'^version:\s*.*$', multiLine: true);
|
||||||
if (versionRe.hasMatch(content)) {
|
if (versionRe.hasMatch(content)) {
|
||||||
updatedContent = content.replaceFirstMapped(versionRe, (_) => 'version: $version');
|
updatedContent =
|
||||||
|
content.replaceFirstMapped(versionRe, (_) => 'version: $version');
|
||||||
} else {
|
} else {
|
||||||
// Insert after description if present, otherwise after name.
|
// Insert after description if present, otherwise after name.
|
||||||
final descRe = RegExp(r'^(description:.*)$', multiLine: true);
|
final descRe = RegExp(r'^(description:.*)$', multiLine: true);
|
||||||
if (descRe.hasMatch(content)) {
|
if (descRe.hasMatch(content)) {
|
||||||
updatedContent = content.replaceFirstMapped(descRe, (m) => '${m.group(1)}\nversion: $version');
|
updatedContent = content.replaceFirstMapped(
|
||||||
|
descRe, (m) => '${m.group(1)}\nversion: $version');
|
||||||
} else {
|
} else {
|
||||||
final nameRe = RegExp(r'^(name:.*)$', multiLine: true);
|
final nameRe = RegExp(r'^(name:.*)$', multiLine: true);
|
||||||
if (nameRe.hasMatch(content)) {
|
if (nameRe.hasMatch(content)) {
|
||||||
updatedContent = content.replaceFirstMapped(nameRe, (m) => '${m.group(1)}\nversion: $version');
|
updatedContent = content.replaceFirstMapped(
|
||||||
|
nameRe, (m) => '${m.group(1)}\nversion: $version');
|
||||||
} else {
|
} else {
|
||||||
// If neither present, prepend version at top.
|
// If neither present, prepend version at top.
|
||||||
updatedContent = 'version: $version\n$content';
|
updatedContent = 'version: $version\n$content';
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue