Skip to content

Commit 65103be

Browse files
committed
Show dialog: placement (center, bottom sheet, adaptive, anchored)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AjsYaRkTHNKszSHjd3j264
1 parent f88201c commit 65103be

3 files changed

Lines changed: 83 additions & 0 deletions

File tree

‎lib/src/api/models/action/show_dialog_action.dart‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,31 @@ import '../models.dart';
66

77
part 'show_dialog_action.g.dart';
88

9+
/// Where a [ShowDialogAction] puts its canvas.
10+
enum DialogPlacement {
11+
/// Centered over the screen at its design size.
12+
center,
13+
14+
/// Pinned to the bottom edge, full width, sliding up.
15+
bottomSheet,
16+
17+
/// A bottom sheet on screens narrower than 600 (mobile), centered
18+
/// otherwise.
19+
adaptive,
20+
21+
/// A popover just below the widget that opened it, like a menu, kept on
22+
/// screen. Falls back to [center] when the opener has no position.
23+
anchored;
24+
25+
/// Displayable label.
26+
String get prettify => switch (this) {
27+
DialogPlacement.center => 'Center',
28+
DialogPlacement.bottomSheet => 'Bottom sheet',
29+
DialogPlacement.adaptive => 'Sheet on mobile',
30+
DialogPlacement.anchored => 'Below trigger',
31+
};
32+
}
33+
934
/// An action that navigates to a new page.
1035
@JsonSerializable()
1136
class ShowDialogAction extends ActionModel with Equatable, SerializableMixin {
@@ -24,13 +49,21 @@ class ShowDialogAction extends ActionModel with Equatable, SerializableMixin {
2449
/// Whether to show a close button on the dialog.
2550
final bool showCloseButton;
2651

52+
/// Where the dialog shows.
53+
final DialogPlacement placement;
54+
55+
/// Space between the opener and an [DialogPlacement.anchored] dialog.
56+
final double anchorGap;
57+
2758
/// Creates a new [ShowDialogAction].
2859
ShowDialogAction({
2960
required this.destinationId,
3061
Map<String, String>? params,
3162
this.barrierColor = ColorRGBA.black54,
3263
this.barrierDismissible = true,
3364
this.showCloseButton = false,
65+
this.placement = DialogPlacement.center,
66+
this.anchorGap = 6,
3467
super.nonBlocking,
3568
super.enabled,
3669
}) : params = {...params ?? {}},
@@ -43,6 +76,8 @@ class ShowDialogAction extends ActionModel with Equatable, SerializableMixin {
4376
barrierDismissible,
4477
barrierColor,
4578
showCloseButton,
79+
placement,
80+
anchorGap,
4681
];
4782

4883
/// Duplicates this [ShowDialogAction] with given data overrides.
@@ -52,12 +87,16 @@ class ShowDialogAction extends ActionModel with Equatable, SerializableMixin {
5287
bool? barrierDismissible,
5388
ColorRGBA? barrierColor,
5489
bool? showCloseButton,
90+
DialogPlacement? placement,
91+
double? anchorGap,
5592
}) => ShowDialogAction(
5693
destinationId: destinationId ?? this.destinationId,
5794
params: {...this.params, ...params ?? {}},
5895
barrierDismissible: barrierDismissible ?? this.barrierDismissible,
5996
barrierColor: barrierColor ?? this.barrierColor,
6097
showCloseButton: showCloseButton ?? this.showCloseButton,
98+
placement: placement ?? this.placement,
99+
anchorGap: anchorGap ?? this.anchorGap,
61100
);
62101

63102
/// Creates a new [ShowDialogAction] instance from a JSON data.

‎lib/src/api/models/action/show_dialog_action.g.dart‎

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import 'package:codelessly_api/codelessly_api.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
test('a dialog from before placements reads as centered', () {
6+
final action = ActionModel.fromJson({
7+
'type': 'showDialog',
8+
'destinationId': 'menu',
9+
}) as ShowDialogAction;
10+
expect(action.placement, DialogPlacement.center);
11+
expect(action.anchorGap, 6);
12+
});
13+
14+
test('placement and gap round-trip; defaults are omitted', () {
15+
final action = ShowDialogAction(
16+
destinationId: 'menu',
17+
placement: DialogPlacement.anchored,
18+
anchorGap: 4,
19+
);
20+
final json = action.toJson();
21+
expect(json['placement'], 'anchored');
22+
expect(ActionModel.fromJson(json), action);
23+
expect(
24+
ShowDialogAction(destinationId: 'x').toJson().containsKey('placement'),
25+
isFalse,
26+
);
27+
});
28+
}

0 commit comments

Comments
 (0)