From 87cb9b5984a07ca3920f903efdb403b2ae1f2715 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Mon, 12 Aug 2024 12:49:18 +0530 Subject: [PATCH 01/20] WIP : Working on GSModal --- example/lib/home.dart | 6 +- example/lib/routes/router.dart | 5 + .../components/widgets/modal_example.dart | 112 ++++++++++++++++++ .../storybook/widgets/modal_story.dart | 62 ++++++++++ .../lib/widgets/storybook/widgets/public.dart | 2 + lib/gluestack_ui.dart | 1 + lib/src/provider/gluestack_provider.dart | 29 +++++ lib/src/provider/provider.dart | 7 ++ lib/src/style/gs_config_style_internal.dart | 50 ++++++-- lib/src/style/gs_style_external_inline.dart | 6 + lib/src/theme/config/enums.dart | 4 +- lib/src/theme/config/modal/modal.dart | 32 +++++ .../theme/config/modal/modal_backdrop.dart | 36 ++++++ lib/src/theme/config/modal/modal_body.dart | 5 + .../config/modal/modal_close_button.dart | 42 +++++++ lib/src/theme/config/modal/modal_content.dart | 39 ++++++ lib/src/theme/config/modal/modal_footer.dart | 7 ++ lib/src/theme/config/modal/modal_header.dart | 8 ++ lib/src/utils/resolver.dart | 19 ++- .../gs_modal/gs_modal_backdrop_style.dart | 4 + lib/src/widgets/gs_modal/gs_modal_body.dart | 26 ++++ .../widgets/gs_modal/gs_modal_body_style.dart | 4 + .../gs_modal/gs_modal_close_button_style.dart | 9 ++ .../widgets/gs_modal/gs_modal_content.dart | 36 ++++++ .../gs_modal/gs_modal_content_style.dart | 10 ++ .../gs_modal/gs_modal_footer_style.dart | 4 + 26 files changed, 549 insertions(+), 16 deletions(-) create mode 100644 example/lib/widgets/components/widgets/modal_example.dart create mode 100644 example/lib/widgets/storybook/widgets/modal_story.dart create mode 100644 lib/src/theme/config/modal/modal.dart create mode 100644 lib/src/theme/config/modal/modal_backdrop.dart create mode 100644 lib/src/theme/config/modal/modal_body.dart create mode 100644 lib/src/theme/config/modal/modal_close_button.dart create mode 100644 lib/src/theme/config/modal/modal_content.dart create mode 100644 lib/src/theme/config/modal/modal_footer.dart create mode 100644 lib/src/theme/config/modal/modal_header.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_backdrop_style.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_body.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_body_style.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_close_button_style.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_content.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_content_style.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_footer_style.dart diff --git a/example/lib/home.dart b/example/lib/home.dart index 6e555557..0ba17a0f 100644 --- a/example/lib/home.dart +++ b/example/lib/home.dart @@ -187,10 +187,14 @@ class _HomePageState extends State { title: "GS Navigation Rail", routePath: "/navigation-rail-preview", ), - const NavButton( + const NavButton( title: "GS Slider", routePath: "/slider-example", ), + const NavButton( + title: "GS Modal", + routePath: "/modal-example", + ), // // ===== Internal Testing Widgets ===== // const NavButton( diff --git a/example/lib/routes/router.dart b/example/lib/routes/router.dart index b8608de1..aaf79207 100644 --- a/example/lib/routes/router.dart +++ b/example/lib/routes/router.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:gluestack_ui_example/home.dart'; import 'package:gluestack_ui_example/widgets/components/widgets/accordian_example.dart'; import 'package:gluestack_ui_example/widgets/components/widgets/bottom_sheet_example.dart'; +import 'package:gluestack_ui_example/widgets/components/widgets/modal_example.dart'; import 'package:gluestack_ui_example/widgets/components/widgets/navigation_rail_example.dart'; import 'package:gluestack_ui_example/widgets/components/widgets/slider_example.dart'; import 'package:gluestack_ui_example/widgets/storybook/storybook.dart'; @@ -198,6 +199,10 @@ final GoRouter router = GoRouter( path: "slider-example", builder: (context, state) => const SliderExample(), ), + GoRoute( + path: "modal-example", + builder: (context, state) => const ModalExample(), + ), // Generate individual Storybook screens for every widget. This is referenced in docs website iframe. ...kStories.map( diff --git a/example/lib/widgets/components/widgets/modal_example.dart b/example/lib/widgets/components/widgets/modal_example.dart new file mode 100644 index 00000000..0984d4c5 --- /dev/null +++ b/example/lib/widgets/components/widgets/modal_example.dart @@ -0,0 +1,112 @@ + +import 'package:gluestack_ui/gluestack_ui.dart'; +import 'package:gluestack_ui_example/widgets/components/layout/base_layout.dart'; +import 'package:gluestack_ui_example/widgets/components/layout/custom_gs_layout.dart'; +import 'package:gluestack_ui_example/widgets/components/layout/drop_down.dart'; +import 'package:go_router/go_router.dart'; + +class ModalExample extends StatefulWidget { + const ModalExample({super.key}); + + @override + State createState() => _ModalExampleState(); +} + +class _ModalExampleState extends State { + final List dropdownSizeOptions = [ + GSModalSizes.$xs, + GSModalSizes.$sm, + GSModalSizes.$md, + GSModalSizes.$lg, + GSModalSizes.$full, + ]; + GSModalSizes selectedSizeOption = GSModalSizes.$md; + + void updateSizeSelectedOption(dynamic newOption) { + setState(() { + selectedSizeOption = newOption; + }); + } + + @override + Widget build(BuildContext context) { + var code = ''' +GSSlider( + size: $selectedSizeOption, + + onChanged: (value) { + setState(() { + currentValue = value; + }); + }, +), + '''; + + return CustomGSLayout( + title: "Modal", + style: GSStyle( + dark: GSStyle(bg: $GSColors.black), + ), + body: BaseLayout( + code: code, + component: GSModal( + size: selectedSizeOption, + content: GSModalContent( + header: const GSModalHeader( + // style: GSStyle( + // bg: Colors.pink, + // ), + child: GSText( + text: "Invite your team", + ), + ), + body: const GSModalBody( + child: GSText( + text: + "Elevate user interactions with our versatile modals. Seamlessly integrate notifications, forms, and media displays. Make an impact effortlessly.", + ), + ), + footer: GSModalFooter( + child: GSButtonGroup( + buttons: [ + GSButton( + action: GSButtonActions.positive, + variant: GSButtonVariants.outline, + child: const GSText( + text: "Cancel", + ), + onPressed: () { + context.pop(); + }), + GSButton( + action: GSButtonActions.negative, + variant: GSButtonVariants.outline, + child: const GSText( + text: "Explore", + ), + onPressed: () { + context.pop(); + }), + ], + ), + ), + ), + child: const GSBadge( + text: GSBadgeText("Show Modal"), + )), + controls: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CustomDropDown( + title: "size", + dropdownOptions: dropdownSizeOptions, + selectedOption: selectedSizeOption, + onChanged: updateSizeSelectedOption, + ), + ], + ), + ), + ); + } +} diff --git a/example/lib/widgets/storybook/widgets/modal_story.dart b/example/lib/widgets/storybook/widgets/modal_story.dart new file mode 100644 index 00000000..b5f40f1d --- /dev/null +++ b/example/lib/widgets/storybook/widgets/modal_story.dart @@ -0,0 +1,62 @@ + +import 'package:gluestack_ui/gluestack_ui.dart'; +import 'base_story_widget.dart'; +import 'package:storybook_flutter/storybook_flutter.dart'; + +final List> sizeOptions = generateEnumOptions(GSModalSizes.values); + +final class ModalStory extends StoryWidget { + @override + Story createStoryWidget() { + return Story( + name: storyName, + builder: (context) => GSModal( + size: GSModalSizes.values[context.knobs + .options(label: 'Size', initial: 0, options: sizeOptions)], + content: GSModalContent( + header: const GSModalHeader( + // style: GSStyle( + // bg: Colors.pink, + // ), + child: GSText( + text: "Header", + ), + ), + body: const GSModalBody( + child: GSText( + text: + "Are you sure you want to deactivate your account? Your data will be permanently removed and cannot be undone.", + ), + ), + footer: GSModalFooter( + child: GSButtonGroup( + buttons: [ + GSButton( + action: GSButtonActions.positive, + variant: GSButtonVariants.outline, + child: const GSText( + text: "Yes", + ), + onPressed: () {}), + GSButton( + action: GSButtonActions.negative, + variant: GSButtonVariants.outline, + child: const GSText( + text: "No", + ), + onPressed: () {}), + ], + ), + ), + ), + child: const GSBadge( + text: GSBadgeText("Show Modal"), + ))); + } + + @override + String get routePath => "modal-preview"; + + @override + String get storyName => "Modal"; +} diff --git a/example/lib/widgets/storybook/widgets/public.dart b/example/lib/widgets/storybook/widgets/public.dart index db3f37b5..ba172980 100644 --- a/example/lib/widgets/storybook/widgets/public.dart +++ b/example/lib/widgets/storybook/widgets/public.dart @@ -1,4 +1,5 @@ import 'package:gluestack_ui_example/widgets/storybook/widgets/header_story.dart'; +import 'package:gluestack_ui_example/widgets/storybook/widgets/modal_story.dart'; import 'package:gluestack_ui_example/widgets/storybook/widgets/slider_story.dart'; import 'package:gluestack_ui_example/widgets/storybook/widgets/tab_story.dart'; import 'alert_dialog_story.dart'; @@ -68,6 +69,7 @@ final List kStories = [ ToastStory(), VStackStory(), HeaderStory(), + ModalStory(), ModalBottomSheetStory(), NavigationRailStory(), StepperStory(), diff --git a/lib/gluestack_ui.dart b/lib/gluestack_ui.dart index edb7233b..18fdb370 100644 --- a/lib/gluestack_ui.dart +++ b/lib/gluestack_ui.dart @@ -47,3 +47,4 @@ export 'src/widgets/gs_tabs/public.dart'; export 'src/widgets/gs_layout/public.dart'; export 'src/widgets/gs_header/public.dart'; export 'src/widgets/gs_slider/public.dart'; +export 'src/widgets/gs_modal/public.dart'; diff --git a/lib/src/provider/gluestack_provider.dart b/lib/src/provider/gluestack_provider.dart index 772523d6..4ba3c583 100644 --- a/lib/src/provider/gluestack_provider.dart +++ b/lib/src/provider/gluestack_provider.dart @@ -146,6 +146,15 @@ class GluestackCustomConfig { Map? sliderThumb; Map? sliderFilledTrack; + //modal + Map? modal; + Map? modalHeader; + Map? modalFooter; + Map? modalContent; + Map? modalCloseButton; + Map? modalBody; + Map? modalBackdrop; + //GS Layout Map? layout; @@ -156,6 +165,16 @@ class GluestackCustomConfig { this.sliderTrack, this.sliderThumb, this.sliderFilledTrack, + + // modal + + this.modal, + this.modalBackdrop, + this.modalBody, + this.modalCloseButton, + this.modalContent, + this.modalFooter, + this.modalHeader, //tabs this.tabs, this.tabsTab, @@ -316,6 +335,16 @@ class GluestackCustomConfig { sliderThumb = mergeConfigs(sliderThumbData, sliderThumb); sliderFilledTrack = mergeConfigs(sliderFilledTrackData, sliderFilledTrack); + // modal + + modal = mergeConfigs(modalData, modal); + modalBackdrop = mergeConfigs(modalBackdropData, modalBackdrop); + modalBody = mergeConfigs(modalBodyData, modalBody); + modalFooter = mergeConfigs(modalFooterData, modalFooter); + modalHeader = mergeConfigs(modalHeaderData, modalHeader); + modalContent = mergeConfigs(modalContentData, modalContent); + modalCloseButton = mergeConfigs(modalCloseButtonData, modalCloseButton); + //tabs tabs = mergeConfigs(tabsData, tabs); tabsTab = mergeConfigs(tabsTabData, tabsTab); diff --git a/lib/src/provider/provider.dart b/lib/src/provider/provider.dart index 63703b99..dffde10e 100644 --- a/lib/src/provider/provider.dart +++ b/lib/src/provider/provider.dart @@ -84,3 +84,10 @@ export 'package:gluestack_ui/src/theme/config/slider/slider_track.dart'; export 'package:gluestack_ui/src/theme/config/slider/slider_thumb.dart'; export 'package:gluestack_ui/src/theme/config/slider/slider_thumb_interaction.dart'; export 'package:gluestack_ui/src/theme/config/slider/slider_filled_track.dart'; +export 'package:gluestack_ui/src/theme/config/modal/modal.dart'; +export 'package:gluestack_ui/src/theme/config/modal/modal_backdrop.dart'; +export 'package:gluestack_ui/src/theme/config/modal/modal_body.dart'; +export 'package:gluestack_ui/src/theme/config/modal/modal_close_button.dart'; +export 'package:gluestack_ui/src/theme/config/modal/modal_content.dart'; +export 'package:gluestack_ui/src/theme/config/modal/modal_footer.dart'; +export 'package:gluestack_ui/src/theme/config/modal/modal_header.dart'; diff --git a/lib/src/style/gs_config_style_internal.dart b/lib/src/style/gs_config_style_internal.dart index 513fbd51..242ac31c 100644 --- a/lib/src/style/gs_config_style_internal.dart +++ b/lib/src/style/gs_config_style_internal.dart @@ -343,6 +343,7 @@ class GSConfigStyle extends BaseStyle { // String? highlightColor; // String? splashColor; GSConfigStyle? badge; + GSConfigStyle? modal; GSTextTransform? textTransform; GSSizes? iconSize; @@ -425,6 +426,7 @@ class GSConfigStyle extends BaseStyle { this.alignment, this.maxWidth, this.badge, + this.modal, // this.highlightColor, // this.splashColor, this.textTransform, @@ -565,6 +567,7 @@ class GSConfigStyle extends BaseStyle { width: overrideStyle?.width ?? width, height: overrideStyle?.height ?? height, badge: overrideStyle?.badge ?? badge, + modal: overrideStyle?.modal ?? modal, dark: dark != null ? dark?.merge(overrideStyle?.dark) : overrideStyle?.dark, @@ -684,6 +687,9 @@ class GSConfigStyle extends BaseStyle { badge: gsStyle.badge != null ? GSConfigStyle.fromGSStyle(gsStyle.badge!) : null, + modal: gsStyle.modal != null + ? GSConfigStyle.fromGSStyle(gsStyle.modal!) + : null, item: gsStyle.item != null ? GSConfigStyle.fromGSStyle(gsStyle.item!) : null, @@ -738,6 +744,18 @@ class GSConfigStyle extends BaseStyle { data?['_badge']?['w'], ), ), + modal: GSConfigStyle( + maxWidth: data?['_content']?['maxWidth'], + width: data?['_content']?['width'] != null + ? data?['_content']?['width']?.contains('100%') + ? double.infinity + : data?['_content']?['width']?.contains('%') + ? double.tryParse( + data?['_content']?['width']?.replaceAll('%', ''))! / + 100 + : resolveSpaceFromString(data?['_content']?['width']) + : resolveSpaceFromString(data?['_content']?['width']), + ), textTransform: resolveTextTransformFromString(data?['textTransform']), maxWidth: data?['maxWidth'] != null ? double.tryParse(data?['maxWidth']?.toString() ?? "") @@ -747,16 +765,24 @@ class GSConfigStyle extends BaseStyle { : data?['px'] != null && data?['py'] != null ? resolvePaddingFromString(data?['px'].toString(), 'symmetric', paddingy: data?['py'].toString()) - : data?['px'] != null - ? resolvePaddingFromString( - data?['px'].toString(), 'horizontal') - : data?['py'] != null + : data?['px'] != null && + data?["paddingTop"] != null && + data?["paddingBottom"] != null + ? resolvePaddingFromString(data?['px'].toString(), 'only', + paddingTop: data?["paddingTop"].toString(), + paddingBottom: data?["paddingBottom"].toString(), + paddingLeft: data?['px'].toString(), + paddingRight: data?['px'].toString()) + : data?['px'] != null ? resolvePaddingFromString( - data?['py'].toString(), 'vertical') - : data?['pb'] != null + data?['px'].toString(), 'horizontal') + : data?['py'] != null ? resolvePaddingFromString( - data?['pb'].toString(), 'only') - : null, + data?['py'].toString(), 'vertical') + : data?['pb'] != null + ? resolvePaddingFromString( + data?['pb'].toString(), 'only') + : null, margin: data?['m'] != null ? resolvePaddingFromString(data?['m'].toString(), 'all') : data?['mx'] != null && data?['my'] != null @@ -998,7 +1024,7 @@ class GSConfigStyle extends BaseStyle { ), onDisabled: GSConfigStyle( opacity: data?[':disabled']?['opacity'], - bg : resolveColorTokenFromString(data?[':disabled']?['bg']), + bg: resolveColorTokenFromString(data?[':disabled']?['bg']), // textStyle: TextStyle( // color: resolveColorFromString(data?[':disabled']?['color']), // ), @@ -1147,7 +1173,7 @@ class GSConfigStyle extends BaseStyle { ), ), onDisabled: GSConfigStyle( - bg : resolveColorTokenFromString(data?[':disabled']?['bg']), + bg: resolveColorTokenFromString(data?[':disabled']?['bg']), borderColor: resolveColorTokenFromString( data?['_dark']?[':disabled']?['borderColor']), trackColorTrue: resolveColorTokenFromString( @@ -1260,7 +1286,7 @@ class GSConfigStyle extends BaseStyle { ? (data?['transform'].first as Map)['scale'] : null : null, - trackHeight: data?['_track'] != null + trackHeight: data?['_track'] != null ? (data?['_track']['height'] is int ? double.parse('${data?['_track']['height']}.0') : resolveSpaceFromString( @@ -1268,7 +1294,7 @@ class GSConfigStyle extends BaseStyle { data?['_track']['height'].toString(), )) : null, - trackWidth: data?['_track'] != null + trackWidth: data?['_track'] != null ? (data?['_track']['width'] is int ? double.parse('${data?['_track']['width']}.0') : resolveSpaceFromString( diff --git a/lib/src/style/gs_style_external_inline.dart b/lib/src/style/gs_style_external_inline.dart index 9e398baa..26487246 100644 --- a/lib/src/style/gs_style_external_inline.dart +++ b/lib/src/style/gs_style_external_inline.dart @@ -33,6 +33,7 @@ class GSStyle extends BaseStyle { // Color? highlightColor; // Color? splashColor; GSStyle? badge; + GSStyle? modal; GSTextTransform? textTransform; GSSizes? iconSize; @@ -110,6 +111,7 @@ class GSStyle extends BaseStyle { this.alignment, this.maxWidth, this.badge, + this.modal, // this.highlightColor, // this.splashColor, this.textTransform, @@ -215,6 +217,7 @@ class GSStyle extends BaseStyle { width: overrideStyle?.width ?? width, height: overrideStyle?.height ?? height, badge: overrideStyle?.badge ?? badge, + modal : overrideStyle?.modal ?? modal, dark: dark != null ? dark?.merge(overrideStyle?.dark) : overrideStyle?.dark, @@ -336,6 +339,9 @@ class GSStyle extends BaseStyle { badge: styler.badge != null ? fromGSConfigStyle(styler.badge!, context) : null, + modal: styler.modal != null + ? fromGSConfigStyle(styler.modal!, context) + : null, item: styler.item != null ? fromGSConfigStyle(styler.item!, context) : null, checked: styler.checked != null diff --git a/lib/src/theme/config/enums.dart b/lib/src/theme/config/enums.dart index 7a7cdb7d..51f278cc 100644 --- a/lib/src/theme/config/enums.dart +++ b/lib/src/theme/config/enums.dart @@ -299,4 +299,6 @@ enum GSSliderSizes { $sm, $md, $lg, -} \ No newline at end of file +} + +enum GSModalSizes { $xs, $sm, $md, $lg, $full } diff --git a/lib/src/theme/config/modal/modal.dart b/lib/src/theme/config/modal/modal.dart new file mode 100644 index 00000000..dad864b1 --- /dev/null +++ b/lib/src/theme/config/modal/modal.dart @@ -0,0 +1,32 @@ +const Map modalData = { + "width": '\$full', + "height": '\$full', + "justifyContent": 'center', + "alignItems": 'center', + "variants": { + "size": { + "xs": { + "_content": {"width": '60%', "maxWidth": 360} + }, + "sm": { + "_content": {"width": '70%', "maxWidth": 420} + }, + "md": { + "_content": {"width": '80%', "maxWidth": 510} + }, + "lg": { + "_content": {"width": '90%', "maxWidth": 640} + }, + "full": { + "_content": {"width": '100%'} + }, + }, + }, + "defaultProps": {"size": 'md'}, + "_web": { + "pointerEvents": 'box-none', + }, +}; + // { + // descendantStyle: ['_content'], + // } diff --git a/lib/src/theme/config/modal/modal_backdrop.dart b/lib/src/theme/config/modal/modal_backdrop.dart new file mode 100644 index 00000000..8dbda180 --- /dev/null +++ b/lib/src/theme/config/modal/modal_backdrop.dart @@ -0,0 +1,36 @@ +const Map modalBackdropData = { + ':initial': { + "opacity": 0, + }, + + ':animate': { + "opacity": 0.5, + }, + + ':exit': { + "opacity": 0, + }, + + ':transition': { + // @ts-ignore + "type": 'spring', + "damping": 18, + "stiffness": 250, + "opacity": { + "type": 'timing', + "duration": 250, + }, + }, + + 'position': 'absolute', + 'left': 0, + 'top': 0, + 'right': 0, + 'bottom': 0, + 'bg': '\$background950', + + // @ts-ignore + '_web': { + "cursor": 'default', + }, +}; diff --git a/lib/src/theme/config/modal/modal_body.dart b/lib/src/theme/config/modal/modal_body.dart new file mode 100644 index 00000000..6d214336 --- /dev/null +++ b/lib/src/theme/config/modal/modal_body.dart @@ -0,0 +1,5 @@ +const Map modalBodyData = { + "px": '\$4', + "paddingTop": 0, + "paddingBottom": '\$2' +}; diff --git a/lib/src/theme/config/modal/modal_close_button.dart b/lib/src/theme/config/modal/modal_close_button.dart new file mode 100644 index 00000000..1d2123cd --- /dev/null +++ b/lib/src/theme/config/modal/modal_close_button.dart @@ -0,0 +1,42 @@ +const Map modalCloseButtonData = { + 'zIndex': 1, + 'p': '\$2', + 'rounded': '\$sm', + '_icon': { + "color": '\$background400', + }, + '_text': { + "color": '\$background400', + }, + ':hover': { + "_icon": { + "color": '\$background700', + }, + "_text": { + "colo": '\$background700', + }, + }, + ':active': { + "_icon": { + "color": '\$background900', + }, + "_text": { + "color": '\$background900', + }, + }, + ':focusVisible': { + "bg": '\$background100', + "_icon": { + "color": '\$background900', + }, + "_text": { + "color": '\$background900', + }, + }, + '_web': { + "outlineWidth": 0, + "cursor": 'pointer', + }, +}; + // { descendantStyle: ['_icon', '_text'] } + diff --git a/lib/src/theme/config/modal/modal_content.dart b/lib/src/theme/config/modal/modal_content.dart new file mode 100644 index 00000000..6cb5b41d --- /dev/null +++ b/lib/src/theme/config/modal/modal_content.dart @@ -0,0 +1,39 @@ + +const Map modalContentData = { + 'bg': '\$background50', + 'rounded': '\$lg', + 'overflow': 'hidden', + + ':initial': { + "opacity": 0, + "scale": 0.9, + }, + ':animate': { + "opacity": 1, + "scale": 1, + }, + + ':exit': { + "opacity": 0, + }, + ':transition': { + "type": 'spring', + "damping": 18, + "stiffness": 250, + // @ts-ignore + "opacity": { + "type": 'timing', + "duration": 250, + }, + }, + + 'defaultProps': { + "softShadow": '3', + }, + }; + // { ancestorStyle: ['_content'] } + + + + + diff --git a/lib/src/theme/config/modal/modal_footer.dart b/lib/src/theme/config/modal/modal_footer.dart new file mode 100644 index 00000000..7a01a814 --- /dev/null +++ b/lib/src/theme/config/modal/modal_footer.dart @@ -0,0 +1,7 @@ +const Map modalFooterData = { + "p": '\$4', + "flexDirection": 'row', + "justifyContent": 'flex-end', + "alignItems": 'center', + "flexWrap": 'wrap', +}; diff --git a/lib/src/theme/config/modal/modal_header.dart b/lib/src/theme/config/modal/modal_header.dart new file mode 100644 index 00000000..6cbbdcac --- /dev/null +++ b/lib/src/theme/config/modal/modal_header.dart @@ -0,0 +1,8 @@ +const Map modalHeaderData = { + "px": '\$4', + "paddingTop": '\$4', + "paddingBottom": '\$2', + "justifyContent": 'space-between', + "alignItems": 'center', + "flexDirection": 'row', +}; diff --git a/lib/src/utils/resolver.dart b/lib/src/utils/resolver.dart index 0f2e7efe..be73b545 100644 --- a/lib/src/utils/resolver.dart +++ b/lib/src/utils/resolver.dart @@ -137,7 +137,12 @@ double? resolveSpaceFromString(String? space) { } EdgeInsetsGeometry? resolvePaddingFromString(String? padding, String type, - {String? paddingy, String? side = 'b'}) { + {String? paddingy, + String? side = 'b', + String? paddingTop, + String? paddingBottom, + String? paddingLeft, + String? paddingRight}) { if (padding == null) { return null; } @@ -157,7 +162,17 @@ EdgeInsetsGeometry? resolvePaddingFromString(String? padding, String type, return EdgeInsets.symmetric(vertical: resolveSpaceFromString(padding)!); } if (type == 'only') { - if (side == 'b') { + if (paddingTop != null && + paddingBottom != null && + paddingLeft != null && + paddingRight != null) { + return EdgeInsets.only( + top: resolveSpaceFromString(paddingTop)!, + left: resolveSpaceFromString(paddingLeft)!, + right: resolveSpaceFromString(paddingRight)!, + bottom: resolveSpaceFromString(paddingBottom)!, + ); + } else if (side == 'b') { return EdgeInsets.only(bottom: resolveSpaceFromString(padding)!); } else if (side == 'r') { return EdgeInsets.only(right: resolveSpaceFromString(padding)!); diff --git a/lib/src/widgets/gs_modal/gs_modal_backdrop_style.dart b/lib/src/widgets/gs_modal/gs_modal_backdrop_style.dart new file mode 100644 index 00000000..04267f54 --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_backdrop_style.dart @@ -0,0 +1,4 @@ +import 'package:gluestack_ui/gluestack_ui.dart'; + +final GSConfigStyle gsModalBackdropStyle = + GSConfigStyle.fromMap(data: getIt().modalBackdrop); diff --git a/lib/src/widgets/gs_modal/gs_modal_body.dart b/lib/src/widgets/gs_modal/gs_modal_body.dart new file mode 100644 index 00000000..69b6d99d --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_body.dart @@ -0,0 +1,26 @@ +import 'package:gluestack_ui/src/style/gs_config_style_internal.dart'; +import 'package:gluestack_ui/src/style/style_resolver.dart'; +import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_body_style.dart'; + +class GSModalBody extends StatelessWidget { + final Widget? child; + final GSStyle? style; + const GSModalBody({super.key, this.child, this.style}); + + @override + Widget build(BuildContext context) { + GSConfigStyle styler = resolveStyles( + context: context, + styles: [gsModalBodyStyle], + inlineStyle: style, + isFirst: true, + ); + return Container( + color: styler.bg?.getColor(context), + padding: styler.padding, + height: styler.height, + width: styler.width ?? double.infinity, + child: child, + ); + } +} diff --git a/lib/src/widgets/gs_modal/gs_modal_body_style.dart b/lib/src/widgets/gs_modal/gs_modal_body_style.dart new file mode 100644 index 00000000..6840185b --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_body_style.dart @@ -0,0 +1,4 @@ +import 'package:gluestack_ui/gluestack_ui.dart'; + +final GSConfigStyle gsModalBodyStyle = + GSConfigStyle.fromMap(data: getIt().modalBody); diff --git a/lib/src/widgets/gs_modal/gs_modal_close_button_style.dart b/lib/src/widgets/gs_modal/gs_modal_close_button_style.dart new file mode 100644 index 00000000..356ced1b --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_close_button_style.dart @@ -0,0 +1,9 @@ +import 'package:gluestack_ui/gluestack_ui.dart'; +import 'package:gluestack_ui/src/style/gs_style_config.dart'; + +const GSStyleConfig gsModalCloseButtonConfig = + GSStyleConfig(componentName: 'Modal', descendantStyle: ['_icon', '_text']); + +final GSConfigStyle gsModalCloseButtonStyle = GSConfigStyle.fromMap( + data: getIt().modalCloseButton, + descendantStyle: gsModalCloseButtonConfig.descendantStyle); diff --git a/lib/src/widgets/gs_modal/gs_modal_content.dart b/lib/src/widgets/gs_modal/gs_modal_content.dart new file mode 100644 index 00000000..90021c16 --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_content.dart @@ -0,0 +1,36 @@ +import 'package:gluestack_ui/src/style/gs_config_style_internal.dart'; +import 'package:gluestack_ui/src/style/style_resolver.dart'; +import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_content_style.dart'; + +class GSModalContent extends StatelessWidget { + final GSModalHeader? header; + final GSModalBody? body; + final GSModalFooter? footer; + final GSStyle? style; + const GSModalContent( + {super.key, this.header, this.body, this.footer, this.style}); + + @override + Widget build(BuildContext context) { + GSConfigStyle styler = resolveStyles( + context: context, + styles: [gsModalContentStyle], + inlineStyle: style, + ); + + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(styler.borderRadius ?? 8), + color: styler.bg?.getColor(context), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + header ?? const SizedBox(), + body ?? const SizedBox(), + footer ?? const SizedBox(), + ], + ), + ); + } +} diff --git a/lib/src/widgets/gs_modal/gs_modal_content_style.dart b/lib/src/widgets/gs_modal/gs_modal_content_style.dart new file mode 100644 index 00000000..795a99ab --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_content_style.dart @@ -0,0 +1,10 @@ +import 'package:gluestack_ui/gluestack_ui.dart'; +import 'package:gluestack_ui/src/style/gs_style_config.dart'; + +const GSStyleConfig gsModalContentConfig = GSStyleConfig( + componentName: 'Modal', + ancestorStyle: ['_content'], +); + +final GSConfigStyle gsModalContentStyle = + GSConfigStyle.fromMap(data: getIt().modalContent); diff --git a/lib/src/widgets/gs_modal/gs_modal_footer_style.dart b/lib/src/widgets/gs_modal/gs_modal_footer_style.dart new file mode 100644 index 00000000..cc79de92 --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_footer_style.dart @@ -0,0 +1,4 @@ +import 'package:gluestack_ui/gluestack_ui.dart'; + +final GSConfigStyle gsModalFooterStyle = + GSConfigStyle.fromMap(data: getIt().modalFooter); From 8b32fae81269b577b72b78c7b82a71e6bfae4db2 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Mon, 12 Aug 2024 12:49:53 +0530 Subject: [PATCH 02/20] added config files --- lib/src/widgets/gs_modal/gs_modal.dart | 120 ++++++++++++++++++ lib/src/widgets/gs_modal/gs_modal_footer.dart | 36 ++++++ lib/src/widgets/gs_modal/gs_modal_header.dart | 29 +++++ .../gs_modal/gs_modal_header_style.dart | 4 + lib/src/widgets/gs_modal/gs_modal_style.dart | 8 ++ lib/src/widgets/gs_modal/public.dart | 5 + 6 files changed, 202 insertions(+) create mode 100644 lib/src/widgets/gs_modal/gs_modal.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_footer.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_header.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_header_style.dart create mode 100644 lib/src/widgets/gs_modal/gs_modal_style.dart create mode 100644 lib/src/widgets/gs_modal/public.dart diff --git a/lib/src/widgets/gs_modal/gs_modal.dart b/lib/src/widgets/gs_modal/gs_modal.dart new file mode 100644 index 00000000..be2f2684 --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal.dart @@ -0,0 +1,120 @@ +import 'package:flutter/material.dart'; +import 'package:gluestack_ui/gluestack_ui.dart'; +import 'package:gluestack_ui/src/style/style_resolver.dart'; +import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_style.dart'; +import 'package:gluestack_ui/src/widgets/gs_style_builder/gs_style_builder.dart'; + +class GSModal extends StatefulWidget { + final GSModalSizes size; + final Widget child; + final GSStyle? style; + final GSModalContent content; + final AlignmentGeometry? alignment; + + const GSModal( + {super.key, + required this.size, + required this.child, + this.style, + required this.content, + this.alignment}); + + @override + State createState() => _GSModalState(); +} + +class _GSModalState extends State { + @override + Widget build(BuildContext context) { + return GsGestureDetector( + onPressed: () { + showCustomModal(context, size: widget.size, content: widget.content); + }, + child: widget.child, + ); + } +} + +void showCustomModal( + BuildContext context, { + GSStyle? style, + GSModalSizes? size, + required GSModalContent content, +}) { + final overlayState = Overlay.of(context); + late OverlayEntry overlayEntry; + + overlayEntry = OverlayEntry( + builder: (context) { + final modalSize = size?.toGSSize ?? modalStyle.props?.size; + return GSStyleBuilder(child: Builder(builder: (context) { + GSConfigStyle styler = resolveStyles( + context: context, + styles: [ + modalStyle, + modalStyle.sizeMap(modalSize), + ], + inlineStyle: style, + ); + + return GSAncestor( + decedentStyles: styler.descendantStyles, + child: Positioned.fill( + child: Stack( + children: [ + GsGestureDetector( + onPressed: () { + overlayEntry.remove(); + }, + child: Container( + color: const Color.fromRGBO(0, 0, 0, 0.5), + ), + ), + Align( + alignment: styler.alignment ?? Alignment.center, + child: SizedBox( + width: (styler.modal?.maxWidth ?? + 200 * (styler.modal?.width ?? 1)), + child: content), + ), + ], + ), + ), + ); + })); + }, + ); + + overlayState.insert(overlayEntry); +} + +void showModal( + BuildContext context, + GSStyle? style, + GSModalSizes? size, + GSModalContent content, +) { + showDialog( + context: context, + builder: (BuildContext context) { + final modalSize = size?.toGSSize ?? modalStyle.props?.size; + return GSStyleBuilder( + child: Builder(builder: (context) { + GSConfigStyle styler = resolveStyles( + context: context, + styles: [ + modalStyle, + modalStyle.sizeMap(modalSize), + ], + inlineStyle: style, + ); + + return GSAncestor( + decedentStyles: styler.descendantStyles, + child: Dialog(child: content), + ); + }), + ); + }, + ); +} diff --git a/lib/src/widgets/gs_modal/gs_modal_footer.dart b/lib/src/widgets/gs_modal/gs_modal_footer.dart new file mode 100644 index 00000000..c0f89862 --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_footer.dart @@ -0,0 +1,36 @@ +import 'package:gluestack_ui/src/style/gs_config_style_internal.dart'; +import 'package:gluestack_ui/src/style/style_resolver.dart'; +import 'package:gluestack_ui/src/utils/resolver.dart'; +import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_footer_style.dart'; + +class GSModalFooter extends StatelessWidget { + final Widget? child; + final GSStyle? style; + const GSModalFooter({super.key, this.child, this.style}); + + @override + Widget build(BuildContext context) { + return Builder(builder: (context) { + GSConfigStyle styler = resolveStyles( + context: context, + styles: [gsModalFooterStyle], + inlineStyle: style, + isFirst: true, + ); + final x = resolveAlignment(styler.justifyContent); + final alignment = resolveAlignmentFromNum(x); + return Container( + color: styler.bg?.getColor(context), + padding: styler.padding, + height: styler.height, + width: styler.width, + child: Row( + mainAxisAlignment: alignment, + children: [ + child ?? const SizedBox(), + ], + ), + ); + }); + } +} diff --git a/lib/src/widgets/gs_modal/gs_modal_header.dart b/lib/src/widgets/gs_modal/gs_modal_header.dart new file mode 100644 index 00000000..e60b758d --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_header.dart @@ -0,0 +1,29 @@ +import 'package:gluestack_ui/src/style/gs_config_style_internal.dart'; +import 'package:gluestack_ui/src/style/style_resolver.dart'; +import 'package:gluestack_ui/src/utils/resolver.dart'; +import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_header_style.dart'; + +class GSModalHeader extends StatelessWidget { + final Widget? child; + final GSStyle? style; + const GSModalHeader({super.key, this.child, this.style}); + + @override + Widget build(BuildContext context) { + GSConfigStyle styler = resolveStyles( + context: context, + styles: [gsModalHeaderStyle], + inlineStyle: style, + ); + final y = resolveAlignment(styler.alignItems), + x = resolveAlignment(styler.justifyContent); + return Container( + color: styler.bg?.getColor(context), + alignment: Alignment(x, y), + padding: styler.padding, + height: styler.height, + width: styler.width ?? double.infinity, + child: child, + ); + } +} diff --git a/lib/src/widgets/gs_modal/gs_modal_header_style.dart b/lib/src/widgets/gs_modal/gs_modal_header_style.dart new file mode 100644 index 00000000..21db9b67 --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_header_style.dart @@ -0,0 +1,4 @@ +import 'package:gluestack_ui/gluestack_ui.dart'; + + GSConfigStyle gsModalHeaderStyle = + GSConfigStyle.fromMap(data: getIt().modalHeader); diff --git a/lib/src/widgets/gs_modal/gs_modal_style.dart b/lib/src/widgets/gs_modal/gs_modal_style.dart new file mode 100644 index 00000000..5ce06883 --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_style.dart @@ -0,0 +1,8 @@ +import 'package:gluestack_ui/gluestack_ui.dart'; +import 'package:gluestack_ui/src/style/gs_style_config.dart'; + +const GSStyleConfig gsModalConfig = + GSStyleConfig(componentName: 'Modal', descendantStyle: ['_content']); + GSConfigStyle modalStyle = GSConfigStyle.fromMap( + data: getIt().modal, + descendantStyle: gsModalConfig.descendantStyle); diff --git a/lib/src/widgets/gs_modal/public.dart b/lib/src/widgets/gs_modal/public.dart new file mode 100644 index 00000000..be76892f --- /dev/null +++ b/lib/src/widgets/gs_modal/public.dart @@ -0,0 +1,5 @@ +export 'gs_modal.dart'; +export 'gs_modal_body.dart'; +export 'gs_modal_footer.dart'; +export 'gs_modal_header.dart'; +export 'gs_modal_content.dart'; \ No newline at end of file From ccc5c879afd7f4a9ea15233a760df03c495f322e Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Mon, 12 Aug 2024 15:26:55 +0530 Subject: [PATCH 03/20] worked on overlay alignment --- .../components/widgets/modal_example.dart | 20 +++--- .../storybook/widgets/modal_story.dart | 34 ++++++---- lib/src/widgets/gs_modal/gs_modal.dart | 65 +++++++------------ 3 files changed, 53 insertions(+), 66 deletions(-) diff --git a/example/lib/widgets/components/widgets/modal_example.dart b/example/lib/widgets/components/widgets/modal_example.dart index 0984d4c5..526a6f40 100644 --- a/example/lib/widgets/components/widgets/modal_example.dart +++ b/example/lib/widgets/components/widgets/modal_example.dart @@ -1,4 +1,3 @@ - import 'package:gluestack_ui/gluestack_ui.dart'; import 'package:gluestack_ui_example/widgets/components/layout/base_layout.dart'; import 'package:gluestack_ui_example/widgets/components/layout/custom_gs_layout.dart'; @@ -52,12 +51,13 @@ GSSlider( component: GSModal( size: selectedSizeOption, content: GSModalContent( - header: const GSModalHeader( - // style: GSStyle( - // bg: Colors.pink, - // ), + header: GSModalHeader( child: GSText( text: "Invite your team", + style: GSStyle( + textStyle: TextStyle( + color: GSTheme.of(context).background900, + fontWeight: FontWeight.bold)), ), ), body: const GSModalBody( @@ -70,22 +70,22 @@ GSSlider( child: GSButtonGroup( buttons: [ GSButton( - action: GSButtonActions.positive, + action: GSButtonActions.primary, variant: GSButtonVariants.outline, child: const GSText( text: "Cancel", ), onPressed: () { - context.pop(); + // context.pop(); }), GSButton( - action: GSButtonActions.negative, - variant: GSButtonVariants.outline, + action: GSButtonActions.primary, + variant: GSButtonVariants.solid, child: const GSText( text: "Explore", ), onPressed: () { - context.pop(); + // context.pop(); }), ], ), diff --git a/example/lib/widgets/storybook/widgets/modal_story.dart b/example/lib/widgets/storybook/widgets/modal_story.dart index b5f40f1d..4600ab97 100644 --- a/example/lib/widgets/storybook/widgets/modal_story.dart +++ b/example/lib/widgets/storybook/widgets/modal_story.dart @@ -1,4 +1,3 @@ - import 'package:gluestack_ui/gluestack_ui.dart'; import 'base_story_widget.dart'; import 'package:storybook_flutter/storybook_flutter.dart'; @@ -14,37 +13,44 @@ final class ModalStory extends StoryWidget { size: GSModalSizes.values[context.knobs .options(label: 'Size', initial: 0, options: sizeOptions)], content: GSModalContent( - header: const GSModalHeader( - // style: GSStyle( - // bg: Colors.pink, - // ), + header: GSModalHeader( + style: GSStyle( + textStyle: TextStyle( + color: GSTheme.of(context).background900, + fontWeight: FontWeight.bold + ) + ), child: GSText( - text: "Header", + text: "Invite your team", ), ), body: const GSModalBody( child: GSText( text: - "Are you sure you want to deactivate your account? Your data will be permanently removed and cannot be undone.", + "Elevate user interactions with our versatile modals. Seamlessly integrate notifications, forms, and media displays. Make an impact effortlessly.", ), ), footer: GSModalFooter( child: GSButtonGroup( buttons: [ GSButton( - action: GSButtonActions.positive, + action: GSButtonActions.primary, variant: GSButtonVariants.outline, child: const GSText( - text: "Yes", + text: "Cancel", ), - onPressed: () {}), + onPressed: () { + // context.pop(); + }), GSButton( - action: GSButtonActions.negative, - variant: GSButtonVariants.outline, + action: GSButtonActions.primary, + variant: GSButtonVariants.solid, child: const GSText( - text: "No", + text: "Explore", ), - onPressed: () {}), + onPressed: () { + // context.pop(); + }), ], ), ), diff --git a/lib/src/widgets/gs_modal/gs_modal.dart b/lib/src/widgets/gs_modal/gs_modal.dart index be2f2684..e309e504 100644 --- a/lib/src/widgets/gs_modal/gs_modal.dart +++ b/lib/src/widgets/gs_modal/gs_modal.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:gluestack_ui/gluestack_ui.dart'; import 'package:gluestack_ui/src/style/style_resolver.dart'; import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_style.dart'; @@ -10,6 +9,7 @@ class GSModal extends StatefulWidget { final GSStyle? style; final GSModalContent content; final AlignmentGeometry? alignment; + final bool? barrierDismissible; const GSModal( {super.key, @@ -17,6 +17,7 @@ class GSModal extends StatefulWidget { required this.child, this.style, required this.content, + this.barrierDismissible = true, this.alignment}); @override @@ -28,7 +29,10 @@ class _GSModalState extends State { Widget build(BuildContext context) { return GsGestureDetector( onPressed: () { - showCustomModal(context, size: widget.size, content: widget.content); + showCustomModal(context, + size: widget.size, + content: widget.content, + barrierDismissible: widget.barrierDismissible); }, child: widget.child, ); @@ -39,6 +43,7 @@ void showCustomModal( BuildContext context, { GSStyle? style, GSModalSizes? size, + bool? barrierDismissible, required GSModalContent content, }) { final overlayState = Overlay.of(context); @@ -59,26 +64,33 @@ void showCustomModal( return GSAncestor( decedentStyles: styler.descendantStyles, - child: Positioned.fill( - child: Stack( - children: [ - GsGestureDetector( - onPressed: () { - overlayEntry.remove(); + child: Stack( + children: [ + MouseRegion( + cursor: SystemMouseCursors.basic, + child: GestureDetector( + onTap: () { + overlayEntry + .remove(); // Remove the overlay when tapping outside the content }, child: Container( color: const Color.fromRGBO(0, 0, 0, 0.5), ), ), - Align( + ), + GestureDetector( + onTap: () { + // Do nothing to prevent the modal from closing when tapped + }, + child: Align( alignment: styler.alignment ?? Alignment.center, child: SizedBox( width: (styler.modal?.maxWidth ?? 200 * (styler.modal?.width ?? 1)), child: content), ), - ], - ), + ), + ], ), ); })); @@ -87,34 +99,3 @@ void showCustomModal( overlayState.insert(overlayEntry); } - -void showModal( - BuildContext context, - GSStyle? style, - GSModalSizes? size, - GSModalContent content, -) { - showDialog( - context: context, - builder: (BuildContext context) { - final modalSize = size?.toGSSize ?? modalStyle.props?.size; - return GSStyleBuilder( - child: Builder(builder: (context) { - GSConfigStyle styler = resolveStyles( - context: context, - styles: [ - modalStyle, - modalStyle.sizeMap(modalSize), - ], - inlineStyle: style, - ); - - return GSAncestor( - decedentStyles: styler.descendantStyles, - child: Dialog(child: content), - ); - }), - ); - }, - ); -} From e483df8b49e24fef993735cf31e6b83378c0c8e7 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Mon, 12 Aug 2024 15:33:55 +0530 Subject: [PATCH 04/20] refactor code --- example/lib/widgets/components/widgets/modal_example.dart | 1 - example/lib/widgets/storybook/widgets/modal_story.dart | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/example/lib/widgets/components/widgets/modal_example.dart b/example/lib/widgets/components/widgets/modal_example.dart index 526a6f40..cb9a79f6 100644 --- a/example/lib/widgets/components/widgets/modal_example.dart +++ b/example/lib/widgets/components/widgets/modal_example.dart @@ -2,7 +2,6 @@ import 'package:gluestack_ui/gluestack_ui.dart'; import 'package:gluestack_ui_example/widgets/components/layout/base_layout.dart'; import 'package:gluestack_ui_example/widgets/components/layout/custom_gs_layout.dart'; import 'package:gluestack_ui_example/widgets/components/layout/drop_down.dart'; -import 'package:go_router/go_router.dart'; class ModalExample extends StatefulWidget { const ModalExample({super.key}); diff --git a/example/lib/widgets/storybook/widgets/modal_story.dart b/example/lib/widgets/storybook/widgets/modal_story.dart index 4600ab97..7313ff64 100644 --- a/example/lib/widgets/storybook/widgets/modal_story.dart +++ b/example/lib/widgets/storybook/widgets/modal_story.dart @@ -20,7 +20,7 @@ final class ModalStory extends StoryWidget { fontWeight: FontWeight.bold ) ), - child: GSText( + child: const GSText( text: "Invite your team", ), ), From 67e62d2a8deb93afb99d67b5ee5d5f9aace1ba8f Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Mon, 12 Aug 2024 15:44:39 +0530 Subject: [PATCH 05/20] fix version issue --- lib/src/widgets/gs_app/gs_app.dart | 8 ++++---- lib/src/widgets/gs_radio/gs_radio_raw.dart | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/src/widgets/gs_app/gs_app.dart b/lib/src/widgets/gs_app/gs_app.dart index fab61f54..7c047e05 100644 --- a/lib/src/widgets/gs_app/gs_app.dart +++ b/lib/src/widgets/gs_app/gs_app.dart @@ -284,8 +284,8 @@ class _GSAppState extends State { localeListResolutionCallback: widget.localeListResolutionCallback, supportedLocales: widget.supportedLocales, showPerformanceOverlay: widget.showPerformanceOverlay, - checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages, - checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers, + // checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages, + // checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers, showSemanticsDebugger: widget.showSemanticsDebugger, debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner, shortcuts: widget.shortcuts, @@ -310,8 +310,8 @@ class _GSAppState extends State { localeResolutionCallback: widget.localeResolutionCallback, supportedLocales: widget.supportedLocales, showPerformanceOverlay: widget.showPerformanceOverlay, - checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages, - checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers, + // checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages, + // checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers, showSemanticsDebugger: widget.showSemanticsDebugger, debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner, shortcuts: widget.shortcuts, diff --git a/lib/src/widgets/gs_radio/gs_radio_raw.dart b/lib/src/widgets/gs_radio/gs_radio_raw.dart index 4e29b440..24d56347 100644 --- a/lib/src/widgets/gs_radio/gs_radio_raw.dart +++ b/lib/src/widgets/gs_radio/gs_radio_raw.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/cupertino.dart'; import 'package:gluestack_ui/gluestack_ui.dart'; -import 'gs_toggleable.dart'; +import 'gs_toggleable.dart' as custom_toggleable; const Size _size = Size(18.0, 18.0); const double _kOuterRadius = 8.0; @@ -59,7 +59,7 @@ class GSRawRadio extends StatefulWidget { } class _GSRawRadioState extends State> - with TickerProviderStateMixin, ToggleableStateMixin { + with TickerProviderStateMixin, custom_toggleable.ToggleableStateMixin { bool focused = false; void _handleChanged(bool? selected) { @@ -150,7 +150,7 @@ class _GSRawRadioState extends State> } } -class _RadioPainter extends ToggleablePainter { +class _RadioPainter extends custom_toggleable.ToggleablePainter { final double? radioSize; _RadioPainter({ From 943e4ab617d546964d5d509659ae51dc4ffd98e1 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Mon, 12 Aug 2024 16:06:14 +0530 Subject: [PATCH 06/20] remove depricated parameters from form control --- lib/src/widgets/gs_form_control/gs_form_control.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/widgets/gs_form_control/gs_form_control.dart b/lib/src/widgets/gs_form_control/gs_form_control.dart index bd4de956..fe5c19da 100644 --- a/lib/src/widgets/gs_form_control/gs_form_control.dart +++ b/lib/src/widgets/gs_form_control/gs_form_control.dart @@ -16,7 +16,7 @@ Form Control Compatible Components: class GSFormControl extends StatefulWidget { final GlobalKey formKey; final Widget child; - final PopInvokedCallback? onPopInvoked; + // final PopInvokedCallback? onPopInvoked; final VoidCallback? onChanged; final AutovalidateMode autovalidateMode; final bool? canPop; @@ -32,7 +32,7 @@ class GSFormControl extends StatefulWidget { const GSFormControl({ super.key, required this.child, - this.onPopInvoked, + // this.onPopInvoked, this.onChanged, this.autovalidateMode = AutovalidateMode.disabled, this.canPop, @@ -84,7 +84,7 @@ class _GSFormControlState extends State { key: widget.formKey, canPop: widget.canPop, onChanged: widget.onChanged, - onPopInvoked: widget.onPopInvoked, + // onPopInvoked: widget.onPopInvoked, autovalidateMode: widget.autovalidateMode, child: widget.child, ), From e1394b782553bbf667f8e3d47aa398c039358cc8 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Mon, 12 Aug 2024 17:32:07 +0530 Subject: [PATCH 07/20] added backdrop color --- lib/src/widgets/gs_modal/gs_modal.dart | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/src/widgets/gs_modal/gs_modal.dart b/lib/src/widgets/gs_modal/gs_modal.dart index e309e504..05c12aaf 100644 --- a/lib/src/widgets/gs_modal/gs_modal.dart +++ b/lib/src/widgets/gs_modal/gs_modal.dart @@ -1,5 +1,6 @@ import 'package:gluestack_ui/gluestack_ui.dart'; import 'package:gluestack_ui/src/style/style_resolver.dart'; +import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_backdrop_style.dart'; import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_style.dart'; import 'package:gluestack_ui/src/widgets/gs_style_builder/gs_style_builder.dart'; @@ -62,6 +63,14 @@ void showCustomModal( inlineStyle: style, ); + GSConfigStyle backdropStyler = resolveStyles( + context: context, + styles: [ + gsModalBackdropStyle, + ], + inlineStyle: style, + ); + return GSAncestor( decedentStyles: styler.descendantStyles, child: Stack( @@ -70,11 +79,15 @@ void showCustomModal( cursor: SystemMouseCursors.basic, child: GestureDetector( onTap: () { - overlayEntry - .remove(); // Remove the overlay when tapping outside the content + if (barrierDismissible == true) { + overlayEntry + .remove(); // Remove the overlay when tapping outside the content + } }, child: Container( - color: const Color.fromRGBO(0, 0, 0, 0.5), + color: + backdropStyler.bg?.getColor(context).withOpacity(0.5) ?? + const Color.fromRGBO(0, 0, 0, 0.5), ), ), ), From 245ddc7d7d9fa6619c63a91961dfe52e87ca2406 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Mon, 12 Aug 2024 17:39:19 +0530 Subject: [PATCH 08/20] fix radio file changes --- lib/src/widgets/gs_radio/gs_radio_icon.dart | 2 -- lib/src/widgets/gs_radio/gs_radio_raw.dart | 5 ++--- lib/src/widgets/gs_radio/public.dart | 1 + 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/src/widgets/gs_radio/gs_radio_icon.dart b/lib/src/widgets/gs_radio/gs_radio_icon.dart index 9689cb76..6e8c1e58 100644 --- a/lib/src/widgets/gs_radio/gs_radio_icon.dart +++ b/lib/src/widgets/gs_radio/gs_radio_icon.dart @@ -2,8 +2,6 @@ import 'package:gluestack_ui/src/style/gs_config_style_internal.dart'; import 'package:gluestack_ui/src/style/style_resolver.dart'; import 'package:gluestack_ui/src/widgets/gs_radio/gs_radio_icon_style.dart'; -import 'package:gluestack_ui/src/widgets/gs_radio/gs_radio_raw.dart'; - class GSRadioIcon extends StatelessWidget { final Color? activeColor; final bool autofocus; diff --git a/lib/src/widgets/gs_radio/gs_radio_raw.dart b/lib/src/widgets/gs_radio/gs_radio_raw.dart index 24d56347..00a078b5 100644 --- a/lib/src/widgets/gs_radio/gs_radio_raw.dart +++ b/lib/src/widgets/gs_radio/gs_radio_raw.dart @@ -1,7 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/cupertino.dart'; import 'package:gluestack_ui/gluestack_ui.dart'; -import 'gs_toggleable.dart' as custom_toggleable; const Size _size = Size(18.0, 18.0); const double _kOuterRadius = 8.0; @@ -59,7 +58,7 @@ class GSRawRadio extends StatefulWidget { } class _GSRawRadioState extends State> - with TickerProviderStateMixin, custom_toggleable.ToggleableStateMixin { + with TickerProviderStateMixin, ToggleableStateMixin { bool focused = false; void _handleChanged(bool? selected) { @@ -150,7 +149,7 @@ class _GSRawRadioState extends State> } } -class _RadioPainter extends custom_toggleable.ToggleablePainter { +class _RadioPainter extends ToggleablePainter { final double? radioSize; _RadioPainter({ diff --git a/lib/src/widgets/gs_radio/public.dart b/lib/src/widgets/gs_radio/public.dart index cec54ad8..35d80cfe 100644 --- a/lib/src/widgets/gs_radio/public.dart +++ b/lib/src/widgets/gs_radio/public.dart @@ -2,3 +2,4 @@ export 'gs_radio_icon.dart'; export 'gs_radio_provider.dart'; export 'gs_radio_text.dart'; export 'gs_radio.dart'; +export 'gs_radio_raw.dart'; From ef65f6e871f88021c01140a3da14adca0d279fbd Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Tue, 13 Aug 2024 11:33:54 +0530 Subject: [PATCH 09/20] fix close button config --- .../config/modal/modal_close_button.dart | 2 +- lib/src/widgets/gs_modal/gs_modal_header.dart | 24 ++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/src/theme/config/modal/modal_close_button.dart b/lib/src/theme/config/modal/modal_close_button.dart index 1d2123cd..0a355111 100644 --- a/lib/src/theme/config/modal/modal_close_button.dart +++ b/lib/src/theme/config/modal/modal_close_button.dart @@ -13,7 +13,7 @@ const Map modalCloseButtonData = { "color": '\$background700', }, "_text": { - "colo": '\$background700', + "color": '\$background700', }, }, ':active': { diff --git a/lib/src/widgets/gs_modal/gs_modal_header.dart b/lib/src/widgets/gs_modal/gs_modal_header.dart index e60b758d..bfb0810d 100644 --- a/lib/src/widgets/gs_modal/gs_modal_header.dart +++ b/lib/src/widgets/gs_modal/gs_modal_header.dart @@ -5,8 +5,9 @@ import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_header_style.dart'; class GSModalHeader extends StatelessWidget { final Widget? child; + final GSButton? closeButton; final GSStyle? style; - const GSModalHeader({super.key, this.child, this.style}); + const GSModalHeader({super.key, this.child, this.closeButton, this.style}); @override Widget build(BuildContext context) { @@ -17,13 +18,20 @@ class GSModalHeader extends StatelessWidget { ); final y = resolveAlignment(styler.alignItems), x = resolveAlignment(styler.justifyContent); - return Container( - color: styler.bg?.getColor(context), - alignment: Alignment(x, y), - padding: styler.padding, - height: styler.height, - width: styler.width ?? double.infinity, - child: child, + return Row( + children: [ + Expanded( + child: Container( + color: styler.bg?.getColor(context), + alignment: Alignment(x, y), + padding: styler.padding, + height: styler.height, + width: styler.width ?? double.infinity, + child: child, + ), + ), + closeButton ?? SizedBox.shrink(), + ], ); } } From 8c9fa4f80bdbd5ff856f703a0c3ff45cc19884ac Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Wed, 14 Aug 2024 11:22:46 +0530 Subject: [PATCH 10/20] working on close button --- .../components/widgets/modal_example.dart | 98 +++++++- .../storybook/widgets/modal_story.dart | 5 + lib/src/widgets/gs_modal/gs_modal.dart | 227 +++++++++++------- .../gs_modal/gs_modal_close_button.dart | 94 ++++++++ lib/src/widgets/gs_modal/gs_modal_header.dart | 8 +- lib/src/widgets/gs_modal/gs_remove_modal.dart | 7 + lib/src/widgets/gs_modal/public.dart | 3 +- 7 files changed, 344 insertions(+), 98 deletions(-) create mode 100644 lib/src/widgets/gs_modal/gs_modal_close_button.dart create mode 100644 lib/src/widgets/gs_modal/gs_remove_modal.dart diff --git a/example/lib/widgets/components/widgets/modal_example.dart b/example/lib/widgets/components/widgets/modal_example.dart index cb9a79f6..88f7f1e4 100644 --- a/example/lib/widgets/components/widgets/modal_example.dart +++ b/example/lib/widgets/components/widgets/modal_example.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:gluestack_ui/gluestack_ui.dart'; import 'package:gluestack_ui_example/widgets/components/layout/base_layout.dart'; import 'package:gluestack_ui_example/widgets/components/layout/custom_gs_layout.dart'; @@ -26,19 +27,78 @@ class _ModalExampleState extends State { }); } + bool isOpen = false; + @override Widget build(BuildContext context) { var code = ''' -GSSlider( +GSModal( + isOpen: $isOpen, + onClose: () { + setState(() {}); + }, size: $selectedSizeOption, - - onChanged: (value) { - setState(() { - currentValue = value; - }); - }, -), - '''; + content: GSModalContent( + header: GSModalHeader( + closeButton: GSModalCloseButton( + icon: GSIcon(icon: Icons.close), + onPressed: () { + setState(() { + isOpen = false; + }); + }, + ), + child: GSText( + text: "Invite your team", + style: GSStyle( + textStyle: TextStyle( + color: GSTheme.of(context).background900, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + body: GSModalBody( + child: GSText( + text: "Elevate user interactions with our versatile modals. Seamlessly integrate notifications, forms, and media displays. Make an impact effortlessly.", + ), + ), + footer: GSModalFooter( + child: GSButtonGroup( + buttons: [ + GSButton( + action: GSButtonActions.primary, + variant: GSButtonVariants.outline, + child: GSText( + text: "Cancel", + ), + onPressed: () { + setState(() { + isOpen = false; + }); + }, + ), + GSButton( + action: GSButtonActions.primary, + variant: GSButtonVariants.solid, + child: GSText( + text: "Explore", + ), + onPressed: () { + setState(() { + isOpen = false; + }); + }, + ), + ], + ), + ), + ), + child: GSBadge( + text: GSBadgeText("Show Modal"), + ), +) +'''; return CustomGSLayout( title: "Modal", @@ -48,9 +108,21 @@ GSSlider( body: BaseLayout( code: code, component: GSModal( + onClose: () { + setState(() {}); + }, + isOpen: isOpen, size: selectedSizeOption, content: GSModalContent( header: GSModalHeader( + closeButton: GSModalCloseButton( + icon: const GSIcon(icon: Icons.close), + onPressed: () { + setState(() { + isOpen = false; + }); + }, + ), child: GSText( text: "Invite your team", style: GSStyle( @@ -75,7 +147,9 @@ GSSlider( text: "Cancel", ), onPressed: () { - // context.pop(); + setState(() { + isOpen = false; + }); }), GSButton( action: GSButtonActions.primary, @@ -84,7 +158,9 @@ GSSlider( text: "Explore", ), onPressed: () { - // context.pop(); + setState(() { + isOpen = false; + }); }), ], ), diff --git a/example/lib/widgets/storybook/widgets/modal_story.dart b/example/lib/widgets/storybook/widgets/modal_story.dart index 7313ff64..06c63edf 100644 --- a/example/lib/widgets/storybook/widgets/modal_story.dart +++ b/example/lib/widgets/storybook/widgets/modal_story.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:gluestack_ui/gluestack_ui.dart'; import 'base_story_widget.dart'; import 'package:storybook_flutter/storybook_flutter.dart'; @@ -14,6 +15,10 @@ final class ModalStory extends StoryWidget { .options(label: 'Size', initial: 0, options: sizeOptions)], content: GSModalContent( header: GSModalHeader( + closeButton: GSModalCloseButton( + icon: const GSIcon(icon: Icons.close), + onPressed: () {}, + ), style: GSStyle( textStyle: TextStyle( color: GSTheme.of(context).background900, diff --git a/lib/src/widgets/gs_modal/gs_modal.dart b/lib/src/widgets/gs_modal/gs_modal.dart index 05c12aaf..af10c273 100644 --- a/lib/src/widgets/gs_modal/gs_modal.dart +++ b/lib/src/widgets/gs_modal/gs_modal.dart @@ -11,104 +11,163 @@ class GSModal extends StatefulWidget { final GSModalContent content; final AlignmentGeometry? alignment; final bool? barrierDismissible; + final bool isOpen; + final Function()? onClose; - const GSModal( - {super.key, - required this.size, - required this.child, - this.style, - required this.content, - this.barrierDismissible = true, - this.alignment}); + const GSModal({ + super.key, + required this.size, + required this.child, + this.style, + required this.content, + this.barrierDismissible = true, + this.alignment, + this.onClose, + this.isOpen = false, + }); @override State createState() => _GSModalState(); } class _GSModalState extends State { + OverlayEntry? _overlayEntry; + late bool _isOpen; + @override - Widget build(BuildContext context) { - return GsGestureDetector( - onPressed: () { - showCustomModal(context, - size: widget.size, - content: widget.content, - barrierDismissible: widget.barrierDismissible); - }, - child: widget.child, - ); + void initState() { + super.initState(); + _isOpen = widget.isOpen; + if (_isOpen) { + _showModal(); + } } -} -void showCustomModal( - BuildContext context, { - GSStyle? style, - GSModalSizes? size, - bool? barrierDismissible, - required GSModalContent content, -}) { - final overlayState = Overlay.of(context); - late OverlayEntry overlayEntry; - - overlayEntry = OverlayEntry( - builder: (context) { - final modalSize = size?.toGSSize ?? modalStyle.props?.size; - return GSStyleBuilder(child: Builder(builder: (context) { - GSConfigStyle styler = resolveStyles( - context: context, - styles: [ - modalStyle, - modalStyle.sizeMap(modalSize), - ], - inlineStyle: style, - ); + // @override + // void didUpdateWidget(GSModal oldWidget) { + // super.didUpdateWidget(oldWidget); + // if (widget.isOpen && !_isOpen) { + // _showModal(); + // } else if (!widget.isOpen && _isOpen) { + // _removeModal(); + // } + // } - GSConfigStyle backdropStyler = resolveStyles( - context: context, - styles: [ - gsModalBackdropStyle, - ], - inlineStyle: style, - ); + @override + void didUpdateWidget(GSModal oldWidget) { + super.didUpdateWidget(oldWidget); - return GSAncestor( - decedentStyles: styler.descendantStyles, - child: Stack( - children: [ - MouseRegion( - cursor: SystemMouseCursors.basic, - child: GestureDetector( - onTap: () { - if (barrierDismissible == true) { - overlayEntry - .remove(); // Remove the overlay when tapping outside the content - } - }, - child: Container( - color: - backdropStyler.bg?.getColor(context).withOpacity(0.5) ?? - const Color.fromRGBO(0, 0, 0, 0.5), - ), - ), - ), - GestureDetector( - onTap: () { - // Do nothing to prevent the modal from closing when tapped - }, - child: Align( - alignment: styler.alignment ?? Alignment.center, - child: SizedBox( - width: (styler.modal?.maxWidth ?? - 200 * (styler.modal?.width ?? 1)), - child: content), + if (widget.isOpen && !_isOpen) { + _showModal(); + } else if (!widget.isOpen && _isOpen) { + _removeModal(); + } + } + + void _showModal() { + _overlayEntry = _createOverlayEntry(); + Overlay.of(context).insert(_overlayEntry!); + setState(() { + _isOpen = true; + }); + } + + OverlayEntry _createOverlayEntry() { + return OverlayEntry( + builder: (context) { + final modalSize = widget.size.toGSSize ?? modalStyle.props?.size; + + return GSStyleBuilder( + child: Builder( + builder: (context) { + GSConfigStyle styler = resolveStyles( + context: context, + styles: [ + modalStyle, + modalStyle.sizeMap(modalSize), + ], + inlineStyle: widget.style, + ); + + GSConfigStyle backdropStyler = resolveStyles( + context: context, + styles: [ + gsModalBackdropStyle, + ], + inlineStyle: widget.style, + ); + + return GSAncestor( + decedentStyles: styler.descendantStyles, + child: Stack( + children: [ + MouseRegion( + cursor: SystemMouseCursors.basic, + child: GestureDetector( + onTap: () { + if (widget.barrierDismissible == true) { + _removeModal(); + } + }, + child: Container( + color: backdropStyler.bg + ?.getColor(context) + .withOpacity(0.5) ?? + const Color.fromRGBO(0, 0, 0, 0.5), + ), + ), + ), + GestureDetector( + onTap: () { + // Do nothing to prevent the modal from closing when tapped + }, + child: Align( + alignment: styler.alignment ?? Alignment.center, + child: SizedBox( + width: (styler.modal?.maxWidth ?? + 1 * (styler.modal?.width ?? 1)), + height: styler.modal?.height, + child: widget.content, + ), + ), + ), + ], ), - ), - ], + ); + }, ), ); - })); - }, - ); + }, + ); + } + + void _removeModal() { + // Guard clause to prevent double execution + if (!_isOpen || _overlayEntry == null) { + return; // Exit if modal is already closed or there's no overlay to remove + } + // Remove the overlay entry + _overlayEntry!.remove(); + _overlayEntry = null; + + // Update the state to closed + _isOpen = false; + + // Defer the onClose callback to avoid conflicts with the current build + WidgetsBinding.instance.addPostFrameCallback((_) { + if (widget.onClose != null) { + widget.onClose!(); + } + }); + } - overlayState.insert(overlayEntry); + @override + Widget build(BuildContext context) { + return GsGestureDetector( + onPressed: () { + _isOpen ? _removeModal() : _showModal(); + }, + child: widget.child, + ); + } } diff --git a/lib/src/widgets/gs_modal/gs_modal_close_button.dart b/lib/src/widgets/gs_modal/gs_modal_close_button.dart new file mode 100644 index 00000000..94718e06 --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_close_button.dart @@ -0,0 +1,94 @@ +import 'package:flutter/gestures.dart'; +import 'package:gluestack_ui/gluestack_ui.dart'; +import 'package:gluestack_ui/src/style/style_resolver.dart'; +import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_close_button_style.dart'; + +/// predefined sizes for [GSModalCloseButton], providing a consistent set of size options for icon buttons. +enum GSModalCloseButtonSizes { + $xs, + $sm, + $md, + $lg, +} + +/// A widget that represents an icon button, +/// [GSModalCloseButton] allows for the creation of buttons with icon content, supporting various interactions +/// such as taps, long presses, and double taps. +class GSModalCloseButton extends StatelessWidget { + /// The icon to display within the button. + final GSIcon icon; + + /// The callback that is called when the button is tapped. + final VoidCallback onPressed; + + /// The callback that is called when the button is long-pressed. + final VoidCallback? onLongPress; + + /// The callback that is called when the button is double-tapped. + final GestureDoubleTapCallback? onDoubleTap; + + /// An optional semantic label for the button, used by screen readers. + final String? semanticsLabel; + + /// The size of the icon button, affecting its overall dimensions. + final GSModalCloseButtonSizes? size; + + /// Custom [GSConfigStyle] to apply to the button, enabling detailed customization of its appearance. + final GSStyle? style; + + final GSButtonVariants? variant; + + final GSButtonActions? action; + + ///Constructor for [GSModalCloseButton] + const GSModalCloseButton({ + super.key, + required this.icon, + required this.onPressed, + this.onLongPress, + this.onDoubleTap, + this.style, + this.semanticsLabel, + this.action, + this.variant, + this.size = GSModalCloseButtonSizes.$md, + }); + + @override + Widget build(BuildContext context) { + GSButtonSizes? sizeAdapt(GSModalCloseButtonSizes buttonSize) { + for (GSButtonSizes bSize in GSButtonSizes.values) { + if (bSize.name == buttonSize.name) { + return bSize; + } + } + return null; + } + + GSConfigStyle styler = resolveStyles( + context: context, + styles: [gsModalCloseButtonStyle], + inlineStyle: style, + ); + + // widget. + + return GSButton( + variant: variant ?? GSButtonVariants.link, + action: action ?? GSButtonActions.primary, + onPressed: onPressed, + onLongPress: onLongPress, + onDoubleTap: onDoubleTap, + semanticsLabel: semanticsLabel, + style: style ?? + GSStyle( + color: styler.color?.getColor(context), + iconColor: styler.iconColor?.getColor(context), + padding: styler.padding, + borderRadius: style?.borderRadius, + ), + size: sizeAdapt(size!), + child: icon, + ); + } +} diff --git a/lib/src/widgets/gs_modal/gs_modal_header.dart b/lib/src/widgets/gs_modal/gs_modal_header.dart index bfb0810d..449d99d7 100644 --- a/lib/src/widgets/gs_modal/gs_modal_header.dart +++ b/lib/src/widgets/gs_modal/gs_modal_header.dart @@ -5,7 +5,7 @@ import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_header_style.dart'; class GSModalHeader extends StatelessWidget { final Widget? child; - final GSButton? closeButton; + final GSModalCloseButton? closeButton; final GSStyle? style; const GSModalHeader({super.key, this.child, this.closeButton, this.style}); @@ -30,7 +30,11 @@ class GSModalHeader extends StatelessWidget { child: child, ), ), - closeButton ?? SizedBox.shrink(), + Container( + color: styler.bg?.getColor(context), + alignment: Alignment(x, y), + padding: styler.padding, + child: closeButton ?? SizedBox.shrink()), ], ); } diff --git a/lib/src/widgets/gs_modal/gs_remove_modal.dart b/lib/src/widgets/gs_modal/gs_remove_modal.dart new file mode 100644 index 00000000..baef2c20 --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_remove_modal.dart @@ -0,0 +1,7 @@ +import 'package:gluestack_ui/gluestack_ui.dart'; + +removeOverlayEntry(OverlayEntry? overlayEntry) { + if (overlayEntry != null) { + overlayEntry.remove(); + } +} diff --git a/lib/src/widgets/gs_modal/public.dart b/lib/src/widgets/gs_modal/public.dart index be76892f..9a676cb1 100644 --- a/lib/src/widgets/gs_modal/public.dart +++ b/lib/src/widgets/gs_modal/public.dart @@ -2,4 +2,5 @@ export 'gs_modal.dart'; export 'gs_modal_body.dart'; export 'gs_modal_footer.dart'; export 'gs_modal_header.dart'; -export 'gs_modal_content.dart'; \ No newline at end of file +export 'gs_modal_content.dart'; +export 'gs_modal_close_button.dart'; \ No newline at end of file From 83121f11014450e63e4eb6cbb1e7ad435530382f Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Wed, 14 Aug 2024 11:39:22 +0530 Subject: [PATCH 11/20] added const --- lib/src/widgets/gs_modal/gs_modal_header.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/widgets/gs_modal/gs_modal_header.dart b/lib/src/widgets/gs_modal/gs_modal_header.dart index 449d99d7..7b37e6fe 100644 --- a/lib/src/widgets/gs_modal/gs_modal_header.dart +++ b/lib/src/widgets/gs_modal/gs_modal_header.dart @@ -34,7 +34,7 @@ class GSModalHeader extends StatelessWidget { color: styler.bg?.getColor(context), alignment: Alignment(x, y), padding: styler.padding, - child: closeButton ?? SizedBox.shrink()), + child: closeButton ?? const SizedBox.shrink()), ], ); } From 3e40821abc0903cabb7f5aa87191a8e46d2f0bd1 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Wed, 14 Aug 2024 11:53:09 +0530 Subject: [PATCH 12/20] added showBackdrop boolean --- lib/src/widgets/gs_modal/gs_modal.dart | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/lib/src/widgets/gs_modal/gs_modal.dart b/lib/src/widgets/gs_modal/gs_modal.dart index af10c273..98cdbaf0 100644 --- a/lib/src/widgets/gs_modal/gs_modal.dart +++ b/lib/src/widgets/gs_modal/gs_modal.dart @@ -13,6 +13,7 @@ class GSModal extends StatefulWidget { final bool? barrierDismissible; final bool isOpen; final Function()? onClose; + final bool showBackdrop; const GSModal({ super.key, @@ -24,6 +25,7 @@ class GSModal extends StatefulWidget { this.alignment, this.onClose, this.isOpen = false, + this.showBackdrop = true, }); @override @@ -43,16 +45,6 @@ class _GSModalState extends State { } } - // @override - // void didUpdateWidget(GSModal oldWidget) { - // super.didUpdateWidget(oldWidget); - // if (widget.isOpen && !_isOpen) { - // _showModal(); - // } else if (!widget.isOpen && _isOpen) { - // _removeModal(); - // } - // } - @override void didUpdateWidget(GSModal oldWidget) { super.didUpdateWidget(oldWidget); @@ -110,10 +102,12 @@ class _GSModalState extends State { } }, child: Container( - color: backdropStyler.bg - ?.getColor(context) - .withOpacity(0.5) ?? - const Color.fromRGBO(0, 0, 0, 0.5), + color: widget.showBackdrop + ? backdropStyler.bg + ?.getColor(context) + .withOpacity(0.5) ?? + const Color.fromRGBO(0, 0, 0, 0.5) + : const Color.fromRGBO(0, 0, 0, 0), ), ), ), From 27647dbc029f53ac6ce1be32b723eaf9cf763ecd Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Wed, 14 Aug 2024 12:24:48 +0530 Subject: [PATCH 13/20] add close button functionality --- .../components/widgets/modal_example.dart | 10 +-- .../storybook/widgets/modal_story.dart | 23 +++--- lib/src/widgets/gs_modal/gs_modal.dart | 72 ++++++++++--------- .../gs_modal/gs_modal_close_button.dart | 11 ++- .../widgets/gs_modal/gs_modal_provider.dart | 19 +++++ lib/src/widgets/gs_modal/gs_remove_modal.dart | 7 -- 6 files changed, 73 insertions(+), 69 deletions(-) create mode 100644 lib/src/widgets/gs_modal/gs_modal_provider.dart delete mode 100644 lib/src/widgets/gs_modal/gs_remove_modal.dart diff --git a/example/lib/widgets/components/widgets/modal_example.dart b/example/lib/widgets/components/widgets/modal_example.dart index 88f7f1e4..c2fb34eb 100644 --- a/example/lib/widgets/components/widgets/modal_example.dart +++ b/example/lib/widgets/components/widgets/modal_example.dart @@ -115,13 +115,9 @@ GSModal( size: selectedSizeOption, content: GSModalContent( header: GSModalHeader( - closeButton: GSModalCloseButton( - icon: const GSIcon(icon: Icons.close), - onPressed: () { - setState(() { - isOpen = false; - }); - }, + closeButton: const GSModalCloseButton( + icon: GSIcon(icon: Icons.close), + ), child: GSText( text: "Invite your team", diff --git a/example/lib/widgets/storybook/widgets/modal_story.dart b/example/lib/widgets/storybook/widgets/modal_story.dart index 06c63edf..0d8ec1c8 100644 --- a/example/lib/widgets/storybook/widgets/modal_story.dart +++ b/example/lib/widgets/storybook/widgets/modal_story.dart @@ -14,17 +14,14 @@ final class ModalStory extends StoryWidget { size: GSModalSizes.values[context.knobs .options(label: 'Size', initial: 0, options: sizeOptions)], content: GSModalContent( - header: GSModalHeader( - closeButton: GSModalCloseButton( - icon: const GSIcon(icon: Icons.close), - onPressed: () {}, + header: GSModalHeader( + closeButton: const GSModalCloseButton( + icon: GSIcon(icon: Icons.close), ), style: GSStyle( - textStyle: TextStyle( - color: GSTheme.of(context).background900, - fontWeight: FontWeight.bold - ) - ), + textStyle: TextStyle( + color: GSTheme.of(context).background900, + fontWeight: FontWeight.bold)), child: const GSText( text: "Invite your team", ), @@ -44,18 +41,14 @@ final class ModalStory extends StoryWidget { child: const GSText( text: "Cancel", ), - onPressed: () { - // context.pop(); - }), + onPressed: () {}), GSButton( action: GSButtonActions.primary, variant: GSButtonVariants.solid, child: const GSText( text: "Explore", ), - onPressed: () { - // context.pop(); - }), + onPressed: () {}), ], ), ), diff --git a/lib/src/widgets/gs_modal/gs_modal.dart b/lib/src/widgets/gs_modal/gs_modal.dart index 98cdbaf0..9277c82a 100644 --- a/lib/src/widgets/gs_modal/gs_modal.dart +++ b/lib/src/widgets/gs_modal/gs_modal.dart @@ -1,6 +1,7 @@ import 'package:gluestack_ui/gluestack_ui.dart'; import 'package:gluestack_ui/src/style/style_resolver.dart'; import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_backdrop_style.dart'; +import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_provider.dart'; import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_style.dart'; import 'package:gluestack_ui/src/widgets/gs_style_builder/gs_style_builder.dart'; @@ -89,43 +90,46 @@ class _GSModalState extends State { inlineStyle: widget.style, ); - return GSAncestor( - decedentStyles: styler.descendantStyles, - child: Stack( - children: [ - MouseRegion( - cursor: SystemMouseCursors.basic, - child: GestureDetector( - onTap: () { - if (widget.barrierDismissible == true) { - _removeModal(); - } - }, - child: Container( - color: widget.showBackdrop - ? backdropStyler.bg - ?.getColor(context) - .withOpacity(0.5) ?? - const Color.fromRGBO(0, 0, 0, 0.5) - : const Color.fromRGBO(0, 0, 0, 0), + return GSModalProvider( + removeModal: _removeModal, + child: GSAncestor( + decedentStyles: styler.descendantStyles, + child: Stack( + children: [ + MouseRegion( + cursor: SystemMouseCursors.basic, + child: GestureDetector( + onTap: () { + if (widget.barrierDismissible == true) { + _removeModal(); + } + }, + child: Container( + color: widget.showBackdrop + ? backdropStyler.bg + ?.getColor(context) + .withOpacity(0.5) ?? + const Color.fromRGBO(0, 0, 0, 0.5) + : const Color.fromRGBO(0, 0, 0, 0), + ), ), ), - ), - GestureDetector( - onTap: () { - // Do nothing to prevent the modal from closing when tapped - }, - child: Align( - alignment: styler.alignment ?? Alignment.center, - child: SizedBox( - width: (styler.modal?.maxWidth ?? - 1 * (styler.modal?.width ?? 1)), - height: styler.modal?.height, - child: widget.content, + GestureDetector( + onTap: () { + // Do nothing to prevent the modal from closing when tapped + }, + child: Align( + alignment: styler.alignment ?? Alignment.center, + child: SizedBox( + width: (styler.modal?.maxWidth ?? + 1 * (styler.modal?.width ?? 1)), + height: styler.modal?.height, + child: widget.content, + ), ), ), - ), - ], + ], + ), ), ); }, @@ -135,7 +139,7 @@ class _GSModalState extends State { ); } - void _removeModal() { + _removeModal() { // Guard clause to prevent double execution if (!_isOpen || _overlayEntry == null) { return; // Exit if modal is already closed or there's no overlay to remove diff --git a/lib/src/widgets/gs_modal/gs_modal_close_button.dart b/lib/src/widgets/gs_modal/gs_modal_close_button.dart index 94718e06..ea490713 100644 --- a/lib/src/widgets/gs_modal/gs_modal_close_button.dart +++ b/lib/src/widgets/gs_modal/gs_modal_close_button.dart @@ -2,6 +2,7 @@ import 'package:flutter/gestures.dart'; import 'package:gluestack_ui/gluestack_ui.dart'; import 'package:gluestack_ui/src/style/style_resolver.dart'; import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_close_button_style.dart'; +import 'package:gluestack_ui/src/widgets/gs_modal/gs_modal_provider.dart'; /// predefined sizes for [GSModalCloseButton], providing a consistent set of size options for icon buttons. enum GSModalCloseButtonSizes { @@ -18,9 +19,6 @@ class GSModalCloseButton extends StatelessWidget { /// The icon to display within the button. final GSIcon icon; - /// The callback that is called when the button is tapped. - final VoidCallback onPressed; - /// The callback that is called when the button is long-pressed. final VoidCallback? onLongPress; @@ -44,7 +42,6 @@ class GSModalCloseButton extends StatelessWidget { const GSModalCloseButton({ super.key, required this.icon, - required this.onPressed, this.onLongPress, this.onDoubleTap, this.style, @@ -71,12 +68,14 @@ class GSModalCloseButton extends StatelessWidget { inlineStyle: style, ); - // widget. + final removeModal = GSModalProvider.of(context)?.removeModal; return GSButton( variant: variant ?? GSButtonVariants.link, action: action ?? GSButtonActions.primary, - onPressed: onPressed, + onPressed: () { + removeModal!(); + }, onLongPress: onLongPress, onDoubleTap: onDoubleTap, semanticsLabel: semanticsLabel, diff --git a/lib/src/widgets/gs_modal/gs_modal_provider.dart b/lib/src/widgets/gs_modal/gs_modal_provider.dart new file mode 100644 index 00000000..c9629e4d --- /dev/null +++ b/lib/src/widgets/gs_modal/gs_modal_provider.dart @@ -0,0 +1,19 @@ +import 'package:gluestack_ui/gluestack_ui.dart'; + +class GSModalProvider extends InheritedWidget { + final VoidCallback removeModal; + + const GSModalProvider({ + required this.removeModal, + required Widget child, + }) : super(child: child); + + @override + bool updateShouldNotify(GSModalProvider oldWidget) { + return removeModal != oldWidget.removeModal; + } + + static GSModalProvider? of(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } +} \ No newline at end of file diff --git a/lib/src/widgets/gs_modal/gs_remove_modal.dart b/lib/src/widgets/gs_modal/gs_remove_modal.dart deleted file mode 100644 index baef2c20..00000000 --- a/lib/src/widgets/gs_modal/gs_remove_modal.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:gluestack_ui/gluestack_ui.dart'; - -removeOverlayEntry(OverlayEntry? overlayEntry) { - if (overlayEntry != null) { - overlayEntry.remove(); - } -} From 9b3f4a7d4bc0c756ee6120d5ddf2e3a122b6b314 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Wed, 14 Aug 2024 16:40:42 +0530 Subject: [PATCH 14/20] close button hover --- .../components/widgets/modal_example.dart | 6 -- .../gs_modal/gs_modal_close_button.dart | 59 ++++++++++++------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/example/lib/widgets/components/widgets/modal_example.dart b/example/lib/widgets/components/widgets/modal_example.dart index c2fb34eb..667b8f93 100644 --- a/example/lib/widgets/components/widgets/modal_example.dart +++ b/example/lib/widgets/components/widgets/modal_example.dart @@ -42,11 +42,6 @@ GSModal( header: GSModalHeader( closeButton: GSModalCloseButton( icon: GSIcon(icon: Icons.close), - onPressed: () { - setState(() { - isOpen = false; - }); - }, ), child: GSText( text: "Invite your team", @@ -117,7 +112,6 @@ GSModal( header: GSModalHeader( closeButton: const GSModalCloseButton( icon: GSIcon(icon: Icons.close), - ), child: GSText( text: "Invite your team", diff --git a/lib/src/widgets/gs_modal/gs_modal_close_button.dart b/lib/src/widgets/gs_modal/gs_modal_close_button.dart index ea490713..71df60ad 100644 --- a/lib/src/widgets/gs_modal/gs_modal_close_button.dart +++ b/lib/src/widgets/gs_modal/gs_modal_close_button.dart @@ -15,7 +15,7 @@ enum GSModalCloseButtonSizes { /// A widget that represents an icon button, /// [GSModalCloseButton] allows for the creation of buttons with icon content, supporting various interactions /// such as taps, long presses, and double taps. -class GSModalCloseButton extends StatelessWidget { +class GSModalCloseButton extends StatefulWidget { /// The icon to display within the button. final GSIcon icon; @@ -51,6 +51,12 @@ class GSModalCloseButton extends StatelessWidget { this.size = GSModalCloseButtonSizes.$md, }); + @override + State createState() => _GSModalCloseButtonState(); +} + +class _GSModalCloseButtonState extends State { + bool hovered = false; @override Widget build(BuildContext context) { GSButtonSizes? sizeAdapt(GSModalCloseButtonSizes buttonSize) { @@ -65,29 +71,42 @@ class GSModalCloseButton extends StatelessWidget { GSConfigStyle styler = resolveStyles( context: context, styles: [gsModalCloseButtonStyle], - inlineStyle: style, + inlineStyle: widget.style, ); - final removeModal = GSModalProvider.of(context)?.removeModal; - return GSButton( - variant: variant ?? GSButtonVariants.link, - action: action ?? GSButtonActions.primary, - onPressed: () { - removeModal!(); + void _handleHoveHighlight(bool value) { + setState(() { + hovered = value; + }); + } + + return FocusableActionDetector( + onShowHoverHighlight: (value) { + _handleHoveHighlight(value); }, - onLongPress: onLongPress, - onDoubleTap: onDoubleTap, - semanticsLabel: semanticsLabel, - style: style ?? - GSStyle( - color: styler.color?.getColor(context), - iconColor: styler.iconColor?.getColor(context), - padding: styler.padding, - borderRadius: style?.borderRadius, - ), - size: sizeAdapt(size!), - child: icon, + child: GSButton( + variant: widget.variant ?? GSButtonVariants.link, + action: widget.action ?? GSButtonActions.primary, + onPressed: () { + removeModal!(); + }, + onLongPress: widget.onLongPress, + onDoubleTap: widget.onDoubleTap, + semanticsLabel: widget.semanticsLabel, + style: widget.style ?? + GSStyle( + color: styler.color?.getColor(context), + iconColor: styler.iconColor?.getColor(context), + padding: styler.padding, + borderRadius: widget.style?.borderRadius, + ), + size: sizeAdapt(widget.size!), + child: Icon(widget.icon.icon, + size: styler.width ?? styler.height, + color: hovered == true + ? styler.onHover?.color?.getColor(context) + : styler.iconColor?.getColor(context))), ); } } From 0d3fc9e6e5ac64da2c610b647e739895d63ef2aa Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Thu, 15 Aug 2024 12:39:16 +0530 Subject: [PATCH 15/20] fix function naming --- lib/src/widgets/gs_modal/gs_modal_close_button.dart | 4 ++-- lib/src/widgets/gs_modal/gs_modal_provider.dart | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/widgets/gs_modal/gs_modal_close_button.dart b/lib/src/widgets/gs_modal/gs_modal_close_button.dart index 71df60ad..9c78a1a0 100644 --- a/lib/src/widgets/gs_modal/gs_modal_close_button.dart +++ b/lib/src/widgets/gs_modal/gs_modal_close_button.dart @@ -75,7 +75,7 @@ class _GSModalCloseButtonState extends State { ); final removeModal = GSModalProvider.of(context)?.removeModal; - void _handleHoveHighlight(bool value) { + void handleHoveHighlight(bool value) { setState(() { hovered = value; }); @@ -83,7 +83,7 @@ class _GSModalCloseButtonState extends State { return FocusableActionDetector( onShowHoverHighlight: (value) { - _handleHoveHighlight(value); + handleHoveHighlight(value); }, child: GSButton( variant: widget.variant ?? GSButtonVariants.link, diff --git a/lib/src/widgets/gs_modal/gs_modal_provider.dart b/lib/src/widgets/gs_modal/gs_modal_provider.dart index c9629e4d..902b58e7 100644 --- a/lib/src/widgets/gs_modal/gs_modal_provider.dart +++ b/lib/src/widgets/gs_modal/gs_modal_provider.dart @@ -4,12 +4,13 @@ class GSModalProvider extends InheritedWidget { final VoidCallback removeModal; const GSModalProvider({ + Key? key, required this.removeModal, required Widget child, - }) : super(child: child); + }) : super(key: key, child: child); @override - bool updateShouldNotify(GSModalProvider oldWidget) { + bool updateShouldNotify(covariant GSModalProvider oldWidget) { return removeModal != oldWidget.removeModal; } From 978782dec31847898df21612255b7d0e5b229a60 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Thu, 15 Aug 2024 12:44:56 +0530 Subject: [PATCH 16/20] fix minor issue --- lib/src/widgets/gs_modal/gs_modal_provider.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/widgets/gs_modal/gs_modal_provider.dart b/lib/src/widgets/gs_modal/gs_modal_provider.dart index 902b58e7..3bcad95a 100644 --- a/lib/src/widgets/gs_modal/gs_modal_provider.dart +++ b/lib/src/widgets/gs_modal/gs_modal_provider.dart @@ -2,11 +2,12 @@ import 'package:gluestack_ui/gluestack_ui.dart'; class GSModalProvider extends InheritedWidget { final VoidCallback removeModal; + final Widget child; const GSModalProvider({ Key? key, required this.removeModal, - required Widget child, + required this.child, }) : super(key: key, child: child); @override @@ -17,4 +18,4 @@ class GSModalProvider extends InheritedWidget { static GSModalProvider? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType(); } -} \ No newline at end of file +} From 57c4367e1d99fb80a54036e982bfec91e545c1a9 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Thu, 15 Aug 2024 12:51:47 +0530 Subject: [PATCH 17/20] fix modal provider issue --- lib/src/widgets/gs_modal/gs_modal_provider.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/src/widgets/gs_modal/gs_modal_provider.dart b/lib/src/widgets/gs_modal/gs_modal_provider.dart index 3bcad95a..512a89b3 100644 --- a/lib/src/widgets/gs_modal/gs_modal_provider.dart +++ b/lib/src/widgets/gs_modal/gs_modal_provider.dart @@ -2,13 +2,12 @@ import 'package:gluestack_ui/gluestack_ui.dart'; class GSModalProvider extends InheritedWidget { final VoidCallback removeModal; - final Widget child; const GSModalProvider({ - Key? key, + super.key, required this.removeModal, - required this.child, - }) : super(key: key, child: child); + required super.child, + }); @override bool updateShouldNotify(covariant GSModalProvider oldWidget) { @@ -18,4 +17,4 @@ class GSModalProvider extends InheritedWidget { static GSModalProvider? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType(); } -} +} \ No newline at end of file From 2b2d1dc26636011a89c887926efe5bcdc9f6dd9f Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Thu, 15 Aug 2024 17:37:06 +0530 Subject: [PATCH 18/20] update close button --- .../gs_modal/gs_modal_close_button.dart | 106 +++++++++++++----- 1 file changed, 78 insertions(+), 28 deletions(-) diff --git a/lib/src/widgets/gs_modal/gs_modal_close_button.dart b/lib/src/widgets/gs_modal/gs_modal_close_button.dart index 9c78a1a0..f501a642 100644 --- a/lib/src/widgets/gs_modal/gs_modal_close_button.dart +++ b/lib/src/widgets/gs_modal/gs_modal_close_button.dart @@ -17,7 +17,9 @@ enum GSModalCloseButtonSizes { /// such as taps, long presses, and double taps. class GSModalCloseButton extends StatefulWidget { /// The icon to display within the button. - final GSIcon icon; + final GSIcon? icon; + + final GSText? text; /// The callback that is called when the button is long-pressed. final VoidCallback? onLongPress; @@ -41,7 +43,8 @@ class GSModalCloseButton extends StatefulWidget { ///Constructor for [GSModalCloseButton] const GSModalCloseButton({ super.key, - required this.icon, + this.icon, + this.text, this.onLongPress, this.onDoubleTap, this.style, @@ -82,31 +85,78 @@ class _GSModalCloseButtonState extends State { } return FocusableActionDetector( - onShowHoverHighlight: (value) { - handleHoveHighlight(value); - }, - child: GSButton( - variant: widget.variant ?? GSButtonVariants.link, - action: widget.action ?? GSButtonActions.primary, - onPressed: () { - removeModal!(); - }, - onLongPress: widget.onLongPress, - onDoubleTap: widget.onDoubleTap, - semanticsLabel: widget.semanticsLabel, - style: widget.style ?? - GSStyle( - color: styler.color?.getColor(context), - iconColor: styler.iconColor?.getColor(context), - padding: styler.padding, - borderRadius: widget.style?.borderRadius, - ), - size: sizeAdapt(widget.size!), - child: Icon(widget.icon.icon, - size: styler.width ?? styler.height, - color: hovered == true - ? styler.onHover?.color?.getColor(context) - : styler.iconColor?.getColor(context))), - ); + onShowHoverHighlight: (value) { + handleHoveHighlight(value); + }, + child: GSButton( + variant: widget.variant ?? GSButtonVariants.link, + action: widget.action ?? GSButtonActions.primary, + onPressed: () { + if (widget.icon == null && widget.text == null) { + } else { + removeModal!(); + } + }, + onLongPress: widget.onLongPress, + onDoubleTap: widget.onDoubleTap, + semanticsLabel: widget.semanticsLabel, + style: widget.style ?? + GSStyle( + color: styler.color?.getColor(context), + iconColor: styler.iconColor?.getColor(context), + padding: styler.padding, + borderRadius: widget.style?.borderRadius, + ), + size: sizeAdapt(widget.size!), + child: widget.icon == null && widget.text == null + ? SizedBox.shrink() + : widget.icon != null + ? Icon( + widget.icon?.icon, + size: widget.icon?.style?.width ?? + styler.width ?? + widget.icon?.style?.height ?? + styler.height, + color: hovered == true + ? widget.icon?.style?.onHover?.color ?? + styler.onHover?.iconColor?.getColor(context) + : widget.icon?.style?.iconColor ?? + styler.iconColor?.getColor(context), + fill: widget.icon?.fill, + grade: widget.icon?.grade, + opticalSize: widget.icon?.opticalSize, + semanticLabel: widget.icon?.semanticLabel, + shadows: widget.icon?.shadows, + textDirection: widget.icon?.textDirection, + weight: widget.icon?.weight, + ) + : Text(widget.text!.text, + locale: widget.text!.locale, + maxLines: widget.text!.maxLines, + overflow: widget.text!.overflow, + selectionColor: widget.text!.selectionColor, + semanticsLabel: widget.text!.semanticsLabel, + softWrap: widget.text!.softWrap, + strutStyle: widget.text!.strutStyle, + textAlign: widget.text!.style?.textAlign, + textDirection: widget.text!.textDirection, + textHeightBehavior: widget.text!.textHeightBehavior, + textScaler: widget.text!.textScaler, + textWidthBasis: widget.text!.textWidthBasis, + style: widget.text?.style?.textStyle?.copyWith( + color: hovered == true + ? styler.onHover?.color?.getColor(context) + : styler.color?.getColor(context), + ) ?? + TextStyle( + color: hovered == true + ? styler.onHover?.color?.getColor(context) + : styler.color?.getColor(context), + fontSize: + widget.text?.style?.textStyle?.fontSize, + fontWeight: + widget.text?.style?.textStyle?.fontWeight, + fontFamily: widget + .text?.style?.textStyle?.fontFamily)))); } } From eb5bdfeffab4a57023edf559c482502aed942b43 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Thu, 15 Aug 2024 17:40:00 +0530 Subject: [PATCH 19/20] fix minor issue --- lib/src/widgets/gs_modal/gs_modal_close_button.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/widgets/gs_modal/gs_modal_close_button.dart b/lib/src/widgets/gs_modal/gs_modal_close_button.dart index f501a642..bee4ea95 100644 --- a/lib/src/widgets/gs_modal/gs_modal_close_button.dart +++ b/lib/src/widgets/gs_modal/gs_modal_close_button.dart @@ -109,7 +109,7 @@ class _GSModalCloseButtonState extends State { ), size: sizeAdapt(widget.size!), child: widget.icon == null && widget.text == null - ? SizedBox.shrink() + ? const SizedBox.shrink() : widget.icon != null ? Icon( widget.icon?.icon, From 42ae889187d6ed4a5dba24ea532717815f112090 Mon Sep 17 00:00:00 2001 From: singlapriyanka315 Date: Fri, 16 Aug 2024 11:42:01 +0530 Subject: [PATCH 20/20] add more parameters to modal --- .../components/widgets/modal_example.dart | 35 ++++++++++++++++--- .../storybook/widgets/modal_story.dart | 4 +++ lib/src/widgets/gs_modal/gs_modal.dart | 4 +-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/example/lib/widgets/components/widgets/modal_example.dart b/example/lib/widgets/components/widgets/modal_example.dart index 667b8f93..e57247cc 100644 --- a/example/lib/widgets/components/widgets/modal_example.dart +++ b/example/lib/widgets/components/widgets/modal_example.dart @@ -3,6 +3,7 @@ import 'package:gluestack_ui/gluestack_ui.dart'; import 'package:gluestack_ui_example/widgets/components/layout/base_layout.dart'; import 'package:gluestack_ui_example/widgets/components/layout/custom_gs_layout.dart'; import 'package:gluestack_ui_example/widgets/components/layout/drop_down.dart'; +import 'package:gluestack_ui_example/widgets/components/layout/toggle.dart'; class ModalExample extends StatefulWidget { const ModalExample({super.key}); @@ -12,6 +13,9 @@ class ModalExample extends StatefulWidget { } class _ModalExampleState extends State { + bool barrierDismissible = false; + bool isOpen = false; + bool showBackdrop = false; final List dropdownSizeOptions = [ GSModalSizes.$xs, GSModalSizes.$sm, @@ -27,16 +31,25 @@ class _ModalExampleState extends State { }); } - bool isOpen = false; + void updateBarrierDismissible(bool value) { + setState(() { + barrierDismissible = value; + }); + } + + void updateShowBackdrop(bool value) { + setState(() { + showBackdrop = value; + }); + } @override Widget build(BuildContext context) { var code = ''' GSModal( isOpen: $isOpen, - onClose: () { - setState(() {}); - }, + barrierDismissible: $barrierDismissible, + showBackdrop: $showBackdrop, size: $selectedSizeOption, content: GSModalContent( header: GSModalHeader( @@ -106,6 +119,8 @@ GSModal( onClose: () { setState(() {}); }, + barrierDismissible: barrierDismissible, + showBackdrop: showBackdrop, isOpen: isOpen, size: selectedSizeOption, content: GSModalContent( @@ -169,6 +184,18 @@ GSModal( selectedOption: selectedSizeOption, onChanged: updateSizeSelectedOption, ), + const SizedBox(height: 20), + CustomToggle( + title: "barrierDismissible", + value: barrierDismissible, + onToggle: updateBarrierDismissible, + ), + const SizedBox(height: 20), + CustomToggle( + title: "showBackdrop", + value: showBackdrop, + onToggle: updateShowBackdrop, + ), ], ), ), diff --git a/example/lib/widgets/storybook/widgets/modal_story.dart b/example/lib/widgets/storybook/widgets/modal_story.dart index 0d8ec1c8..0b3e9be7 100644 --- a/example/lib/widgets/storybook/widgets/modal_story.dart +++ b/example/lib/widgets/storybook/widgets/modal_story.dart @@ -13,6 +13,10 @@ final class ModalStory extends StoryWidget { builder: (context) => GSModal( size: GSModalSizes.values[context.knobs .options(label: 'Size', initial: 0, options: sizeOptions)], + barrierDismissible: context.knobs + .boolean(label: "barrierDismissible", initial: true), + showBackdrop: + context.knobs.boolean(label: "showBackdrop", initial: true), content: GSModalContent( header: GSModalHeader( closeButton: const GSModalCloseButton( diff --git a/lib/src/widgets/gs_modal/gs_modal.dart b/lib/src/widgets/gs_modal/gs_modal.dart index 9277c82a..a8c2e9cd 100644 --- a/lib/src/widgets/gs_modal/gs_modal.dart +++ b/lib/src/widgets/gs_modal/gs_modal.dart @@ -11,7 +11,7 @@ class GSModal extends StatefulWidget { final GSStyle? style; final GSModalContent content; final AlignmentGeometry? alignment; - final bool? barrierDismissible; + final bool barrierDismissible; final bool isOpen; final Function()? onClose; final bool showBackdrop; @@ -139,7 +139,7 @@ class _GSModalState extends State { ); } - _removeModal() { + _removeModal() { // Guard clause to prevent double execution if (!_isOpen || _overlayEntry == null) { return; // Exit if modal is already closed or there's no overlay to remove