From a53a1ae8067f68aa1531e3580ed577520bda0ed2 Mon Sep 17 00:00:00 2001 From: Akhil George Date: Sat, 17 Jan 2026 19:48:27 +0530 Subject: [PATCH 1/3] feat: Add SliverSafeArea widget and its parser with documentation and example --- docs/docs.json | 1 + docs/widgets/sliver_safe_area.mdx | 35 ++++++++ .../stac_gallery/assets/json/home_screen.json | 24 ++++++ .../assets/json/sliver_safe_area_example.json | 27 +++++++ .../stac/lib/src/framework/stac_service.dart | 1 + .../stac_sliver_safe_area_parser.dart | 29 +++++++ .../stac/lib/src/parsers/widgets/widgets.dart | 1 + .../specifications/widget_type.dart | 3 + .../stac_sliver_safe_area.dart | 81 +++++++++++++++++++ .../stac_sliver_safe_area.g.dart | 30 +++++++ packages/stac_core/lib/widgets/widgets.dart | 1 + 11 files changed, 233 insertions(+) create mode 100644 docs/widgets/sliver_safe_area.mdx create mode 100644 examples/stac_gallery/assets/json/sliver_safe_area_example.json create mode 100644 packages/stac/lib/src/parsers/widgets/stac_sliver_safe_area/stac_sliver_safe_area_parser.dart create mode 100644 packages/stac_core/lib/widgets/sliver_safe_area/stac_sliver_safe_area.dart create mode 100644 packages/stac_core/lib/widgets/sliver_safe_area/stac_sliver_safe_area.g.dart 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..dc8fdb12 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 Material Design 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..8b9be6fc --- /dev/null +++ b/packages/stac/lib/src/parsers/widgets/stac_sliver_safe_area/stac_sliver_safe_area_parser.dart @@ -0,0 +1,29 @@ +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 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'; From 2d75b0cf0c06e8990ba47de5b6e100473e055b72 Mon Sep 17 00:00:00 2001 From: Akhil George Date: Sat, 17 Jan 2026 20:02:16 +0530 Subject: [PATCH 2/3] fix: Update subtitle for Sliver Safe Area widget in home_screen.json --- examples/stac_gallery/assets/json/home_screen.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stac_gallery/assets/json/home_screen.json b/examples/stac_gallery/assets/json/home_screen.json index dc8fdb12..b62375c2 100644 --- a/examples/stac_gallery/assets/json/home_screen.json +++ b/examples/stac_gallery/assets/json/home_screen.json @@ -1249,7 +1249,7 @@ }, "subtitle": { "type": "text", - "data": "A Material Design Sliver Safe Area widget" + "data": "A Sliver Safe Area widget" }, "style": "list", "onTap": { From 9946aa3e3e65edb9367283b65f9539385f935787 Mon Sep 17 00:00:00 2001 From: Akhil George Date: Sat, 17 Jan 2026 23:52:15 +0530 Subject: [PATCH 3/3] fix: Update sliver fallback in StacSliverSafeAreaParser to use SliverToBoxAdapter --- .../stac_sliver_safe_area/stac_sliver_safe_area_parser.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 index 8b9be6fc..a73f6815 100644 --- 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 @@ -16,7 +16,9 @@ class StacSliverSafeAreaParser extends StacParser { @override Widget parse(BuildContext context, StacSliverSafeArea model) { - final sliver = model.sliver.parse(context) ?? const SizedBox.shrink(); + final sliver = + model.sliver.parse(context) ?? + const SliverToBoxAdapter(child: SizedBox.shrink()); return SliverSafeArea( left: model.left ?? true, top: model.top ?? true,