diff --git a/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.dart b/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.dart index 6c10b297..493fc594 100644 --- a/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.dart +++ b/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:stac/src/parsers/widgets/stac_border_side/stac_border_side.dart'; import 'package:stac/src/parsers/widgets/stac_double/stac_double.dart'; import 'package:stac/src/utils/color_utils.dart'; @@ -9,10 +10,16 @@ part 'stac_border.g.dart'; @freezed abstract class StacBorder with _$StacBorder { const factory StacBorder({ + // Uniform border properties (applies to all sides) String? color, @Default(BorderStyle.solid) BorderStyle borderStyle, @Default(StacDouble(1.0)) StacDouble width, @Default(StacDouble(BorderSide.strokeAlignInside)) StacDouble strokeAlign, + // Individual border sides + StacBorderSide? top, + StacBorderSide? right, + StacBorderSide? bottom, + StacBorderSide? left, }) = _StacBorder; factory StacBorder.fromJson(Map json) => @@ -21,11 +28,26 @@ abstract class StacBorder with _$StacBorder { extension StacBorderParser on StacBorder { Border parse(BuildContext context) { - return Border.all( - color: color.toColor(context) ?? const Color(0xFF000000), - width: width.parse, - style: borderStyle, - strokeAlign: strokeAlign.parse, - ); + // Check if individual border sides are specified + final hasIndividualSides = + top != null || right != null || bottom != null || left != null; + + if (hasIndividualSides) { + // Use individual border sides + return Border( + top: top.parse(context), + right: right.parse(context), + bottom: bottom.parse(context), + left: left.parse(context), + ); + } else { + // Fall back to uniform border behavior for all sides + return Border.all( + color: color.toColor(context) ?? const Color(0xFF000000), + width: width.parse, + style: borderStyle, + strokeAlign: strokeAlign.parse, + ); + } } } diff --git a/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.freezed.dart b/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.freezed.dart index d871d966..6a5ecc5e 100644 --- a/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.freezed.dart +++ b/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.freezed.dart @@ -15,10 +15,15 @@ T _$identity(T value) => value; /// @nodoc mixin _$StacBorder { +// Legacy properties for backward compatibility (Border.all) String? get color; BorderStyle get borderStyle; StacDouble get width; - StacDouble get strokeAlign; + StacDouble get strokeAlign; // Individual border sides + StacBorderSide? get top; + StacBorderSide? get right; + StacBorderSide? get bottom; + StacBorderSide? get left; /// Create a copy of StacBorder /// with the given fields replaced by the non-null parameter values. @@ -40,17 +45,21 @@ mixin _$StacBorder { other.borderStyle == borderStyle) && (identical(other.width, width) || other.width == width) && (identical(other.strokeAlign, strokeAlign) || - other.strokeAlign == strokeAlign)); + other.strokeAlign == strokeAlign) && + (identical(other.top, top) || other.top == top) && + (identical(other.right, right) || other.right == right) && + (identical(other.bottom, bottom) || other.bottom == bottom) && + (identical(other.left, left) || other.left == left)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => - Object.hash(runtimeType, color, borderStyle, width, strokeAlign); + int get hashCode => Object.hash(runtimeType, color, borderStyle, width, + strokeAlign, top, right, bottom, left); @override String toString() { - return 'StacBorder(color: $color, borderStyle: $borderStyle, width: $width, strokeAlign: $strokeAlign)'; + return 'StacBorder(color: $color, borderStyle: $borderStyle, width: $width, strokeAlign: $strokeAlign, top: $top, right: $right, bottom: $bottom, left: $left)'; } } @@ -64,7 +73,16 @@ abstract mixin class $StacBorderCopyWith<$Res> { {String? color, BorderStyle borderStyle, StacDouble width, - StacDouble strokeAlign}); + StacDouble strokeAlign, + StacBorderSide? top, + StacBorderSide? right, + StacBorderSide? bottom, + StacBorderSide? left}); + + $StacBorderSideCopyWith<$Res>? get top; + $StacBorderSideCopyWith<$Res>? get right; + $StacBorderSideCopyWith<$Res>? get bottom; + $StacBorderSideCopyWith<$Res>? get left; } /// @nodoc @@ -83,6 +101,10 @@ class _$StacBorderCopyWithImpl<$Res> implements $StacBorderCopyWith<$Res> { Object? borderStyle = null, Object? width = null, Object? strokeAlign = null, + Object? top = freezed, + Object? right = freezed, + Object? bottom = freezed, + Object? left = freezed, }) { return _then(_self.copyWith( color: freezed == color @@ -101,8 +123,80 @@ class _$StacBorderCopyWithImpl<$Res> implements $StacBorderCopyWith<$Res> { ? _self.strokeAlign : strokeAlign // ignore: cast_nullable_to_non_nullable as StacDouble, + top: freezed == top + ? _self.top + : top // ignore: cast_nullable_to_non_nullable + as StacBorderSide?, + right: freezed == right + ? _self.right + : right // ignore: cast_nullable_to_non_nullable + as StacBorderSide?, + bottom: freezed == bottom + ? _self.bottom + : bottom // ignore: cast_nullable_to_non_nullable + as StacBorderSide?, + left: freezed == left + ? _self.left + : left // ignore: cast_nullable_to_non_nullable + as StacBorderSide?, )); } + + /// Create a copy of StacBorder + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $StacBorderSideCopyWith<$Res>? get top { + if (_self.top == null) { + return null; + } + + return $StacBorderSideCopyWith<$Res>(_self.top!, (value) { + return _then(_self.copyWith(top: value)); + }); + } + + /// Create a copy of StacBorder + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $StacBorderSideCopyWith<$Res>? get right { + if (_self.right == null) { + return null; + } + + return $StacBorderSideCopyWith<$Res>(_self.right!, (value) { + return _then(_self.copyWith(right: value)); + }); + } + + /// Create a copy of StacBorder + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $StacBorderSideCopyWith<$Res>? get bottom { + if (_self.bottom == null) { + return null; + } + + return $StacBorderSideCopyWith<$Res>(_self.bottom!, (value) { + return _then(_self.copyWith(bottom: value)); + }); + } + + /// Create a copy of StacBorder + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $StacBorderSideCopyWith<$Res>? get left { + if (_self.left == null) { + return null; + } + + return $StacBorderSideCopyWith<$Res>(_self.left!, (value) { + return _then(_self.copyWith(left: value)); + }); + } } /// @nodoc @@ -112,10 +206,15 @@ class _StacBorder implements StacBorder { {this.color, this.borderStyle = BorderStyle.solid, this.width = const StacDouble(1.0), - this.strokeAlign = const StacDouble(BorderSide.strokeAlignInside)}); + this.strokeAlign = const StacDouble(BorderSide.strokeAlignInside), + this.top, + this.right, + this.bottom, + this.left}); factory _StacBorder.fromJson(Map json) => _$StacBorderFromJson(json); +// Legacy properties for backward compatibility (Border.all) @override final String? color; @override @@ -127,6 +226,15 @@ class _StacBorder implements StacBorder { @override @JsonKey() final StacDouble strokeAlign; +// Individual border sides + @override + final StacBorderSide? top; + @override + final StacBorderSide? right; + @override + final StacBorderSide? bottom; + @override + final StacBorderSide? left; /// Create a copy of StacBorder /// with the given fields replaced by the non-null parameter values. @@ -153,17 +261,21 @@ class _StacBorder implements StacBorder { other.borderStyle == borderStyle) && (identical(other.width, width) || other.width == width) && (identical(other.strokeAlign, strokeAlign) || - other.strokeAlign == strokeAlign)); + other.strokeAlign == strokeAlign) && + (identical(other.top, top) || other.top == top) && + (identical(other.right, right) || other.right == right) && + (identical(other.bottom, bottom) || other.bottom == bottom) && + (identical(other.left, left) || other.left == left)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => - Object.hash(runtimeType, color, borderStyle, width, strokeAlign); + int get hashCode => Object.hash(runtimeType, color, borderStyle, width, + strokeAlign, top, right, bottom, left); @override String toString() { - return 'StacBorder(color: $color, borderStyle: $borderStyle, width: $width, strokeAlign: $strokeAlign)'; + return 'StacBorder(color: $color, borderStyle: $borderStyle, width: $width, strokeAlign: $strokeAlign, top: $top, right: $right, bottom: $bottom, left: $left)'; } } @@ -179,7 +291,20 @@ abstract mixin class _$StacBorderCopyWith<$Res> {String? color, BorderStyle borderStyle, StacDouble width, - StacDouble strokeAlign}); + StacDouble strokeAlign, + StacBorderSide? top, + StacBorderSide? right, + StacBorderSide? bottom, + StacBorderSide? left}); + + @override + $StacBorderSideCopyWith<$Res>? get top; + @override + $StacBorderSideCopyWith<$Res>? get right; + @override + $StacBorderSideCopyWith<$Res>? get bottom; + @override + $StacBorderSideCopyWith<$Res>? get left; } /// @nodoc @@ -198,6 +323,10 @@ class __$StacBorderCopyWithImpl<$Res> implements _$StacBorderCopyWith<$Res> { Object? borderStyle = null, Object? width = null, Object? strokeAlign = null, + Object? top = freezed, + Object? right = freezed, + Object? bottom = freezed, + Object? left = freezed, }) { return _then(_StacBorder( color: freezed == color @@ -216,8 +345,80 @@ class __$StacBorderCopyWithImpl<$Res> implements _$StacBorderCopyWith<$Res> { ? _self.strokeAlign : strokeAlign // ignore: cast_nullable_to_non_nullable as StacDouble, + top: freezed == top + ? _self.top + : top // ignore: cast_nullable_to_non_nullable + as StacBorderSide?, + right: freezed == right + ? _self.right + : right // ignore: cast_nullable_to_non_nullable + as StacBorderSide?, + bottom: freezed == bottom + ? _self.bottom + : bottom // ignore: cast_nullable_to_non_nullable + as StacBorderSide?, + left: freezed == left + ? _self.left + : left // ignore: cast_nullable_to_non_nullable + as StacBorderSide?, )); } + + /// Create a copy of StacBorder + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $StacBorderSideCopyWith<$Res>? get top { + if (_self.top == null) { + return null; + } + + return $StacBorderSideCopyWith<$Res>(_self.top!, (value) { + return _then(_self.copyWith(top: value)); + }); + } + + /// Create a copy of StacBorder + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $StacBorderSideCopyWith<$Res>? get right { + if (_self.right == null) { + return null; + } + + return $StacBorderSideCopyWith<$Res>(_self.right!, (value) { + return _then(_self.copyWith(right: value)); + }); + } + + /// Create a copy of StacBorder + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $StacBorderSideCopyWith<$Res>? get bottom { + if (_self.bottom == null) { + return null; + } + + return $StacBorderSideCopyWith<$Res>(_self.bottom!, (value) { + return _then(_self.copyWith(bottom: value)); + }); + } + + /// Create a copy of StacBorder + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $StacBorderSideCopyWith<$Res>? get left { + if (_self.left == null) { + return null; + } + + return $StacBorderSideCopyWith<$Res>(_self.left!, (value) { + return _then(_self.copyWith(left: value)); + }); + } } // dart format on diff --git a/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.g.dart b/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.g.dart index 9dc564c9..74c333ff 100644 --- a/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.g.dart +++ b/packages/stac/lib/src/parsers/widgets/stac_border/stac_border.g.dart @@ -17,6 +17,18 @@ _StacBorder _$StacBorderFromJson(Map json) => _StacBorder( strokeAlign: json['strokeAlign'] == null ? const StacDouble(BorderSide.strokeAlignInside) : StacDouble.fromJson(json['strokeAlign']), + top: json['top'] == null + ? null + : StacBorderSide.fromJson(json['top'] as Map), + right: json['right'] == null + ? null + : StacBorderSide.fromJson(json['right'] as Map), + bottom: json['bottom'] == null + ? null + : StacBorderSide.fromJson(json['bottom'] as Map), + left: json['left'] == null + ? null + : StacBorderSide.fromJson(json['left'] as Map), ); Map _$StacBorderToJson(_StacBorder instance) => @@ -25,6 +37,10 @@ Map _$StacBorderToJson(_StacBorder instance) => 'borderStyle': _$BorderStyleEnumMap[instance.borderStyle]!, 'width': instance.width, 'strokeAlign': instance.strokeAlign, + 'top': instance.top, + 'right': instance.right, + 'bottom': instance.bottom, + 'left': instance.left, }; const _$BorderStyleEnumMap = { diff --git a/website/docs/styles/border.md b/website/docs/styles/border.md new file mode 100644 index 00000000..fa4aac06 --- /dev/null +++ b/website/docs/styles/border.md @@ -0,0 +1,159 @@ +# Border + +StacBorder allows you to define the Flutter Border class using JSON with support for both uniform borders (all sides) and individual border sides. +To know more about the Border class in Flutter, refer to the [official documentation](https://api.flutter.dev/flutter/painting/Border-class.html). + +## Features + +- **Uniform Border**: Apply the same border to all sides (backward compatible) +- **Individual Border Sides**: Specify different borders for top, right, bottom, and left sides +- **Automatic Detection**: The system automatically detects whether to use uniform or individual borders + +## Properties + +### Uniform Border (All Sides) + +| Property | Type | Description | +| ----------- | -------------- | ------------------------------------------------------------------------------------------------ | +| color | `String?` | Defines color of the border for all sides. | +| width | `StacDouble?` | Defines thickness of the border for all sides (logical px). | +| borderStyle | `BorderStyle?` | Defines the style of the border for all sides. Can be `solid` or `none`. Defaults to `solid`. | +| strokeAlign | `StacDouble?` | Defines the relative position of the stroke on values range from -1.0 (inside) to 1.0 (outside). | + +### Individual Border Sides + +| Property | Type | Description | +| -------- | ----------------- | --------------------------------------- | +| top | `StacBorderSide?` | Defines the border for the top side. | +| right | `StacBorderSide?` | Defines the border for the right side. | +| bottom | `StacBorderSide?` | Defines the border for the bottom side. | +| left | `StacBorderSide?` | Defines the border for the left side. | + +:::note + +When any individual border side is specified (`top`, `right`, `bottom`, or `left`), the system will use individual border mode and ignore the uniform border properties (`color`, `width`, `borderStyle`, `strokeAlign`). + +::: + +## Examples + +### Uniform Border (All Sides) + +```json +{ + "border": { + "color": "#FF0000", + "width": 2.0, + "borderStyle": "solid", + "strokeAlign": 0.0 + } +} +``` + +### Individual Border Sides + +```json +{ + "border": { + "top": { + "color": "#FF0000", + "width": 2.0, + "borderStyle": "solid", + "strokeAlign": 0.0 + }, + "right": { + "color": "#00FF00", + "width": 1.0, + "borderStyle": "solid" + }, + "bottom": { + "color": "#0000FF", + "width": 3.0, + "borderStyle": "solid" + }, + "left": { + "color": "#FFFF00", + "width": 1.5, + "borderStyle": "solid" + } + } +} +``` + +### Partial Border Sides + +You can specify only some sides, and the others will default to `BorderSide.none`: + +```json +{ + "border": { + "top": { + "color": "#FF0000", + "width": 2.0, + "borderStyle": "solid" + }, + "bottom": { + "color": "#0000FF", + "width": 2.0, + "borderStyle": "solid" + } + } +} +``` + +### Complete Container Example + +```json +{ + "type": "container", + "width": 200, + "height": 100, + "decoration": { + "color": "#F0F0F0", + "border": { + "top": { + "color": "#FF0000", + "width": 3.0, + "borderStyle": "solid" + }, + "right": { + "color": "#00FF00", + "width": 2.0, + "borderStyle": "solid" + }, + "bottom": { + "color": "#0000FF", + "width": 3.0, + "borderStyle": "solid" + }, + "left": { + "color": "#FFFF00", + "width": 2.0, + "borderStyle": "solid" + } + }, + "borderRadius": { + "topLeft": 8.0, + "topRight": 8.0, + "bottomLeft": 8.0, + "bottomRight": 8.0 + } + }, + "child": { + "type": "center", + "child": { + "type": "text", + "data": "Custom Borders", + "style": { + "fontSize": 16, + "fontWeight": "bold" + } + } + } +} +``` + +## See Also + +- [Border Side](./border_side.md) - Learn about StacBorderSide properties +- [Border Radius](./border_radius.md) - Learn about border radius configuration diff --git a/website/docs/styles/border_side.md b/website/docs/styles/border_side.md index 21fd40fb..fe15b2ee 100644 --- a/website/docs/styles/border_side.md +++ b/website/docs/styles/border_side.md @@ -3,6 +3,12 @@ StacBorderSide allows you to define the Flutter BorderSide class using JSON. To know more about the BorderSide class in Flutter, refer to the [official documentation](https://api.flutter.dev/flutter/painting/BorderSide-class.html). +:::info + +BorderSide is used with the new individual border sides feature in [StacBorder](./border.md). You can now specify different border sides for top, right, bottom, and left individually. + +::: + ## Properties | Property | Type | Description | @@ -16,9 +22,13 @@ To know more about the BorderSide class in Flutter, refer to the [official docum ```json { - "color": "#428AF5", - "width": 1.0, - "style":"solid", - "strokeAlign": 1.0, + "color": "#428AF5", + "width": 1.0, + "style": "solid", + "strokeAlign": 1.0 } -``` \ No newline at end of file +``` + +## See Also + +- [Border](./border.md) - Learn about using individual border sides in StacBorder