The Garage SDKs, in the open
garage_auth, garage_entitlements, garage_iap and garage_ui, moved out of Garage-Services and Metro-Map-Maker into one public repo. MIT, one readme, docs under docs/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013F4NWNvYcdeSgqbWMT1VQ7
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import "package:flutter/widgets.dart";
|
||||
|
||||
import "package:garage_ui/theme/garage_theme.dart";
|
||||
|
||||
// A chrome panel - the bordered, rounded surface the shell docks things in.
|
||||
// Fills with the scheme's panel colour and lights its border with the
|
||||
// highlighted colour when active.
|
||||
//
|
||||
// Two modes:
|
||||
// - standalone: leave [active] null and it tracks its own hover.
|
||||
// - controlled: pass [active] and the parent drives the lit state (used by the
|
||||
// shell so it can keep the panels mutually exclusive - only one lit at once,
|
||||
// which also dodges flutter dropping an onExit during a fast mouse move and
|
||||
// leaving a panel stuck on).
|
||||
class Panel extends StatefulWidget {
|
||||
const Panel({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.active,
|
||||
this.borderRadius,
|
||||
this.borderWidth = 1.15,
|
||||
this.clip = true,
|
||||
this.clipBehavior = Clip.antiAlias,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
|
||||
// null = self-track hover; non-null = parent controls the lit state.
|
||||
final bool? active;
|
||||
|
||||
// null = use the theme's panelRadius.
|
||||
final double? borderRadius;
|
||||
final double borderWidth;
|
||||
|
||||
// clip the child to the rounded corners.
|
||||
final bool clip;
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
State<Panel> createState() => _PanelState();
|
||||
}
|
||||
|
||||
class _PanelState extends State<Panel> {
|
||||
bool _hovered = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = GarageTheme.of(context);
|
||||
final cs = theme.colorScheme;
|
||||
final controlled = widget.active != null;
|
||||
final lit = controlled ? widget.active! : _hovered;
|
||||
final radius = BorderRadius.circular(
|
||||
widget.borderRadius ?? theme.panelRadius,
|
||||
);
|
||||
|
||||
Widget content = widget.child;
|
||||
if (widget.clip) {
|
||||
final clipRadius = BorderRadius.circular(
|
||||
((widget.borderRadius ?? theme.panelRadius) - 1)
|
||||
.clamp(0, double.infinity)
|
||||
.toDouble(),
|
||||
);
|
||||
content = ClipRRect(
|
||||
borderRadius: clipRadius,
|
||||
clipBehavior: widget.clipBehavior,
|
||||
child: content,
|
||||
);
|
||||
}
|
||||
|
||||
Widget box = Container(
|
||||
decoration: BoxDecoration(
|
||||
color: cs.background,
|
||||
borderRadius: radius,
|
||||
border: Border.all(
|
||||
color: lit ? cs.panelBorderHighlighted : cs.panelBorder,
|
||||
width: widget.borderWidth,
|
||||
),
|
||||
),
|
||||
child: content,
|
||||
);
|
||||
|
||||
// controlled panels let the parent own the MouseRegion.
|
||||
if (controlled) return box;
|
||||
|
||||
return MouseRegion(
|
||||
onEnter: (_) => setState(() => _hovered = true),
|
||||
onExit: (_) => setState(() => _hovered = false),
|
||||
child: box,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user