diff --git a/docs/docs.json b/docs/docs.json index fd959aa4..d908d3ef 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -123,6 +123,7 @@ "widgets/single_child_scroll_view", "widgets/slider", "widgets/sliver_app_bar", + "widgets/sliver_safe_area", "widgets/switch", "widgets/tab_bar", "widgets/text_button", diff --git a/docs/widgets/sliver_safe_area.mdx b/docs/widgets/sliver_safe_area.mdx new file mode 100644 index 00000000..c552296c --- /dev/null +++ b/docs/widgets/sliver_safe_area.mdx @@ -0,0 +1,35 @@ +--- +title: "SliverSafeArea" +description: "Documentation for SliverSafeArea" +--- + +The Stac SliverSafeArea allows you to build a Flutter sliver safe area widget using JSON. +To know more about the safe area widget in Flutter, refer to +the [official documentation](https://api.flutter.dev/flutter/widgets/SliverSafeArea-class.html). + +## Properties + +| Property | Type | Description | +|--------|-------------------------|-----------------------------------------------------------------------------| +| left | `bool?` | Whether to avoid intrusions on the left. Defaults to `true`. | +| top | `bool?` | Whether to avoid intrusions at the top. Defaults to `true`. | +| right | `bool?` | Whether to avoid intrusions on the right. Defaults to `true`. | +| bottom | `bool?` | Whether to avoid intrusions at the bottom. Defaults to `true`. | +| minimum| `Map?` | Minimum padding to apply as edge insets. | +| sliver | `Map` | The sliver widget below this widget in the tree. **(Required)** | + +## Example JSON + +```json +{ + "type": "sliverSafeArea", + "top": true, + "sliver": { + "type": "sliverToBoxAdapter", + "child": { + "type": "text", + "data": "Hello World" + } + } +} +``` \ No newline at end of file diff --git a/examples/stac_gallery/assets/json/home_screen.json b/examples/stac_gallery/assets/json/home_screen.json index 5c77c8e9..b62375c2 100644 --- a/examples/stac_gallery/assets/json/home_screen.json +++ b/examples/stac_gallery/assets/json/home_screen.json @@ -1236,6 +1236,30 @@ } } }, + { + "type": "listTile", + "leading": { + "type": "icon", + "iconType": "cupertino", + "icon": "app_fill" + }, + "title": { + "type": "text", + "data": "Stac Sliver Safe Area" + }, + "subtitle": { + "type": "text", + "data": "A Sliver Safe Area widget" + }, + "style": "list", + "onTap": { + "actionType": "navigate", + "widgetJson": { + "type": "exampleScreen", + "assetPath": "assets/json/sliver_safe_area_example.json" + } + } + }, { "type": "listTile", "leading": { diff --git a/examples/stac_gallery/assets/json/sliver_safe_area_example.json b/examples/stac_gallery/assets/json/sliver_safe_area_example.json new file mode 100644 index 00000000..95ac46ed --- /dev/null +++ b/examples/stac_gallery/assets/json/sliver_safe_area_example.json @@ -0,0 +1,27 @@ +{ + "type": "scaffold", + "body": { + "type": "customScrollView", + "slivers": [ + { + "type": "sliverSafeArea", + "top": true, + "bottom": true, + "sliver": { + "type": "sliverToBoxAdapter", + "child": { + "type": "container", + "padding": { + "type": "edgeInsets", + "all": 16 + }, + "child": { + "type": "text", + "data": "Content inside SliverSafeArea" + } + } + } + } + ] + } +} \ No newline at end of file diff --git a/packages/stac/lib/src/framework/stac_service.dart b/packages/stac/lib/src/framework/stac_service.dart index d3dd4f57..55040fd5 100644 --- a/packages/stac/lib/src/framework/stac_service.dart +++ b/packages/stac/lib/src/framework/stac_service.dart @@ -114,6 +114,7 @@ class StacService { const StacRadioGroupParser(), const StacSliderParser(), const StacSliverAppBarParser(), + const StacSliverSafeAreaParser(), const StacOpacityParser(), const StacPlaceholderParser(), const StacAspectRatioParser(), diff --git a/packages/stac/lib/src/parsers/widgets/stac_sliver_safe_area/stac_sliver_safe_area_parser.dart b/packages/stac/lib/src/parsers/widgets/stac_sliver_safe_area/stac_sliver_safe_area_parser.dart new file mode 100644 index 00000000..a73f6815 --- /dev/null +++ b/packages/stac/lib/src/parsers/widgets/stac_sliver_safe_area/stac_sliver_safe_area_parser.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:stac/src/parsers/core/stac_widget_parser.dart'; +import 'package:stac/src/parsers/foundation/geometry/stac_edge_insets_parser.dart'; +import 'package:stac_core/stac_core.dart'; +import 'package:stac_framework/stac_framework.dart'; + +class StacSliverSafeAreaParser extends StacParser { + const StacSliverSafeAreaParser(); + + @override + String get type => WidgetType.sliverSafeArea.name; + + @override + StacSliverSafeArea getModel(Map json) => + StacSliverSafeArea.fromJson(json); + + @override + Widget parse(BuildContext context, StacSliverSafeArea model) { + final sliver = + model.sliver.parse(context) ?? + const SliverToBoxAdapter(child: SizedBox.shrink()); + return SliverSafeArea( + left: model.left ?? true, + top: model.top ?? true, + right: model.right ?? true, + bottom: model.bottom ?? true, + minimum: model.minimum?.parse ?? EdgeInsets.zero, + sliver: sliver, + ); + } +} diff --git a/packages/stac/lib/src/parsers/widgets/widgets.dart b/packages/stac/lib/src/parsers/widgets/widgets.dart index 64af1ef0..b1d1c844 100644 --- a/packages/stac/lib/src/parsers/widgets/widgets.dart +++ b/packages/stac/lib/src/parsers/widgets/widgets.dart @@ -63,6 +63,7 @@ export 'package:stac/src/parsers/widgets/stac_single_child_scroll_view/stac_sing export 'package:stac/src/parsers/widgets/stac_sized_box/stac_sized_box_parser.dart'; export 'package:stac/src/parsers/widgets/stac_slider/stac_slider_parser.dart'; export 'package:stac/src/parsers/widgets/stac_sliver_app_bar/stac_sliver_app_bar_parser.dart'; +export 'package:stac/src/parsers/widgets/stac_sliver_safe_area/stac_sliver_safe_area_parser.dart'; export 'package:stac/src/parsers/widgets/stac_spacer/stac_spacer_parser.dart'; export 'package:stac/src/parsers/widgets/stac_stack/stac_stack_parser.dart'; export 'package:stac/src/parsers/widgets/stac_switch/stac_switch_parser.dart'; diff --git a/packages/stac_core/lib/foundation/specifications/widget_type.dart b/packages/stac_core/lib/foundation/specifications/widget_type.dart index 3ec06747..22f4a564 100644 --- a/packages/stac_core/lib/foundation/specifications/widget_type.dart +++ b/packages/stac_core/lib/foundation/specifications/widget_type.dart @@ -207,6 +207,9 @@ enum WidgetType { /// Sliver app bar widget sliverAppBar, + /// Sliver safe area widget + sliverSafeArea, + /// Spacer widget spacer, diff --git a/packages/stac_core/lib/widgets/sliver_safe_area/stac_sliver_safe_area.dart b/packages/stac_core/lib/widgets/sliver_safe_area/stac_sliver_safe_area.dart new file mode 100644 index 00000000..6eedc2de --- /dev/null +++ b/packages/stac_core/lib/widgets/sliver_safe_area/stac_sliver_safe_area.dart @@ -0,0 +1,81 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:stac_core/core/stac_widget.dart'; +import 'package:stac_core/foundation/foundation.dart'; + +part 'stac_sliver_safe_area.g.dart'; + +/// A Stac model representing Flutter's [SliverSafeArea] widget. +/// +/// Insets its sliver child to avoid system UI intrusions +/// such as status bar, notch, or navigation bar. +/// +/// {@tool snippet} +/// Dart Example: +/// ```dart +/// const StacSliverSafeArea( +/// top: true, +/// sliver: StacSliverToBoxAdapter( +/// child: StacText(data: 'Hello World'), +/// ), +/// ) +/// ``` +/// {@end-tool} +/// +/// {@tool snippet} +/// JSON Example: +/// ```json +/// { +/// "type": "sliverSafeArea", +/// "top": true, +/// "sliver": { +/// "type": "sliverToBoxAdapter", +/// "child": { +/// "type": "text", +/// "data": "Hello World" +/// } +/// } +/// } +/// ``` +/// {@end-tool} +@JsonSerializable() +class StacSliverSafeArea extends StacWidget { + /// Creates a [StacSliverSafeArea]. + const StacSliverSafeArea({ + this.left, + this.top, + this.right, + this.bottom, + this.minimum, + required this.sliver, + }); + + /// Whether to avoid intrusions on the left. + final bool? left; + + /// Whether to avoid intrusions at the top. + final bool? top; + + /// Whether to avoid intrusions on the right. + final bool? right; + + /// Whether to avoid intrusions at the bottom. + final bool? bottom; + + /// Minimum padding to apply. + final StacEdgeInsets? minimum; + + /// The sliver below this widget in the tree. + final StacWidget sliver; + + /// Widget type identifier. + @override + String get type => WidgetType.sliverSafeArea.name; + + /// Creates a [StacSliverSafeArea] from JSON. + factory StacSliverSafeArea.fromJson(Map json) => + _$StacSliverSafeAreaFromJson(json); + + /// Converts this instance to JSON. + @override + Map toJson() => _$StacSliverSafeAreaToJson(this); +} diff --git a/packages/stac_core/lib/widgets/sliver_safe_area/stac_sliver_safe_area.g.dart b/packages/stac_core/lib/widgets/sliver_safe_area/stac_sliver_safe_area.g.dart new file mode 100644 index 00000000..ab3c8990 --- /dev/null +++ b/packages/stac_core/lib/widgets/sliver_safe_area/stac_sliver_safe_area.g.dart @@ -0,0 +1,30 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'stac_sliver_safe_area.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +StacSliverSafeArea _$StacSliverSafeAreaFromJson(Map json) => + StacSliverSafeArea( + left: json['left'] as bool?, + top: json['top'] as bool?, + right: json['right'] as bool?, + bottom: json['bottom'] as bool?, + minimum: json['minimum'] == null + ? null + : StacEdgeInsets.fromJson(json['minimum']), + sliver: StacWidget.fromJson(json['sliver'] as Map), + ); + +Map _$StacSliverSafeAreaToJson(StacSliverSafeArea instance) => + { + 'left': instance.left, + 'top': instance.top, + 'right': instance.right, + 'bottom': instance.bottom, + 'minimum': instance.minimum?.toJson(), + 'sliver': instance.sliver.toJson(), + 'type': instance.type, + }; diff --git a/packages/stac_core/lib/widgets/widgets.dart b/packages/stac_core/lib/widgets/widgets.dart index ce5bf976..dd728d75 100644 --- a/packages/stac_core/lib/widgets/widgets.dart +++ b/packages/stac_core/lib/widgets/widgets.dart @@ -67,6 +67,7 @@ export 'single_child_scroll_view/stac_single_child_scroll_view.dart'; export 'sized_box/stac_sized_box.dart'; export 'slider/stac_slider.dart'; export 'sliver_app_bar/stac_sliver_app_bar.dart'; +export 'sliver_safe_area/stac_sliver_safe_area.dart'; export 'spacer/stac_spacer.dart'; export 'stack/stac_stack.dart'; export 'switch/stac_switch.dart';