diff --git a/example/storybook-nativewind/src/components-example/themed/Accordion/index.tsx b/example/storybook-nativewind/src/components-example/themed/Accordion/index.tsx new file mode 100644 index 0000000000..53786d2c1c --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Accordion/index.tsx @@ -0,0 +1,249 @@ +import { createAccordion } from '@gluestack-ui/accordion'; +import { AsForwarder, styled } from '@gluestack-style/react'; +import { View, Pressable, Text, Platform } from 'react-native'; + +import { H3 } from '@expo/html-elements'; + +const StyleRoot = styled( + View, + { + width: '$full', + _icon: { + color: '$text900', + }, + _titleText: { + color: '$text900', + }, + _contentText: { + color: '$text700', + }, + + variants: { + size: { + sm: { + _titleText: { + fontSize: '$sm', + fontFamily: '$body', + fontWeight: '$bold', + lineHeight: '$sm', + }, + _contentText: { + fontSize: '$sm', + fontFamily: '$body', + fontWeight: '$normal', + lineHeight: '$sm', + }, + }, + md: { + _titleText: { + fontSize: '$md', + fontFamily: '$body', + fontWeight: '$bold', + lineHeight: '$md', + }, + _contentText: { + fontSize: '$md', + fontFamily: '$body', + fontWeight: '$normal', + lineHeight: '$md', + }, + }, + lg: { + _titleText: { + fontSize: '$lg', + fontFamily: '$body', + fontWeight: '$bold', + lineHeight: '$lg', + }, + _contentText: { + fontSize: '$lg', + fontFamily: '$body', + fontWeight: '$normal', + lineHeight: '$lg', + }, + }, + }, + variant: { + filled: { + backgroundColor: '$white', + + _item: { + backgroundColor: '$background0', + }, + + shadowColor: '$background900', + + shadowOffset: { + width: 0, + height: 3, + }, + + shadowRadius: 8, + shadowOpacity: 0.2, + elevation: 10, + }, + unfilled: { + shadowColor: 'transparent', + + shadowOffset: { + width: 0, + height: 0, + }, + + _item: { + backgroundColor: 'transparent', + }, + }, + }, + }, + defaultProps: { + theme: 'light', + size: 'md', + variant: 'filled', + }, + }, + { + descendantStyle: [ + '_item', + '_titleText', + '_button', + '_icon', + '_contentText', + ], + } +); +const StyledItem = styled(View, {}, { ancestorStyle: ['_item'] }); +// @ts-ignore +const StyledHeader = styled(Platform.OS === 'web' ? H3 : View, { + mx: '$0', + my: '$0', +}); +const StyledTrigger = styled( + Pressable, + { + 'width': '$full', + 'py': '$5', + 'px': '$5', + 'flexDirection': 'row', + 'justifyContent': 'space-between', + 'alignItems': 'center', + '_web': { + outlineWidth: 0, + }, + ':disabled': { + opacity: 0.4, + _web: { + cursor: 'not-allowed', + }, + }, + ':focusVisible': { + bg: '$background50', + }, + }, + { + descendantStyle: ['_icon', '_titleText', '_contentText'], + ancestorStyle: ['_button'], + } +); +const StyledTitleText = styled( + Text, + { flex: 1, textAlign: 'left' }, + { ancestorStyle: ['_titleText'] } +); +const StyledContentText = styled(Text, {}, { ancestorStyle: ['_contentText'] }); +const StyledIcon = styled( + AsForwarder, + { + color: '$background800', + + // defaultProps: { + // size: 'md', + // }, + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + + props: { + size: 'md', + }, + }, + { + resolveProps: ['stroke', 'fill'], + ancestorStyle: ['_icon'], + }, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); +const StyledContent = styled(View, { px: '$5', mt: '$2', pb: '$5' }); + +export const Accordion = createAccordion({ + Root: StyleRoot, + Item: StyledItem, + Header: StyledHeader, + Trigger: StyledTrigger, + Icon: StyledIcon, + TitleText: StyledTitleText, + ContentText: StyledContentText, + Content: StyledContent, +}); + +export const AccordionItem = Accordion.Item; +export const AccordionHeader = Accordion.Header; +export const AccordionTrigger = Accordion.Trigger; +export const AccordionTitleText = Accordion.TitleText; +export const AccordionContentText = Accordion.ContentText; +export const AccordionIcon = Accordion.Icon; +export const AccordionContent = Accordion.Content; diff --git a/example/storybook-nativewind/src/components-example/themed/Actionsheet/index.tsx b/example/storybook-nativewind/src/components-example/themed/Actionsheet/index.tsx new file mode 100644 index 0000000000..18cf17944b --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Actionsheet/index.tsx @@ -0,0 +1,473 @@ +import { H1, H2, H3, H4, H5, H6 } from '@expo/html-elements'; +import { + AnimatePresence, + AnimatedPressable, + AnimatedView, +} from '@gluestack-style/animation-resolver'; +import { styled, AsForwarder } from '@gluestack-style/react'; +import { createActionsheet } from '@gluestack-ui/actionsheet'; +import { + Pressable, + View, + Text, + ScrollView, + VirtualizedList, + FlatList, + SectionList, +} from 'react-native'; + +const StyledRoot = styled(View, { + width: '$full', + height: '$full', + _web: { + pointerEvents: 'none', + }, +}); + +const StyledContent = styled( + AnimatedView, + { + alignItems: 'center', + borderTopLeftRadius: '$3xl', + borderTopRightRadius: '$3xl', + h: '$full', + p: '$2', + bg: '$background0', + + _sectionHeaderBackground: { + bg: '$background0', + }, + + defaultProps: { + hardShadow: '5', + }, + + _web: { + userSelect: 'none', + pointerEvents: 'auto', + }, + }, + { + descendantStyle: ['_sectionHeaderBackground'], + } +); + +const StyledItem = styled( + Pressable, + { + 'p': '$3', + 'flexDirection': 'row', + 'alignItems': 'center', + 'rounded': '$sm', + 'w': '$full', + + ':disabled': { + opacity: 0.4, + _web: { + // @ts-ignore + pointerEvents: 'all !important', + cursor: 'not-allowed', + }, + }, + + ':hover': { + bg: '$background50', + }, + + ':active': { + bg: '$background100', + }, + + ':focus': { + bg: '$background100', + }, + + '_web': { + ':focusVisible': { + bg: '$background100', + }, + }, + }, + { + descendantStyle: ['_text', '_icon'], + } +); + +const StyledItemText = styled( + Text, + { + fontWeight: '$normal', + fontFamily: '$body', + fontStyle: 'normal', + letterSpacing: '$md', + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + defaultProps: { + size: 'md', + }, + mx: '$2', + props: { + size: 'md', + }, + color: '$text800', + }, + { + ancestorStyle: ['_text'], + } +); + +const StyledDragIndicator = styled(View, { + w: '$16', + h: '$1', + bg: '$background400', + rounded: '$full', +}); + +const StyledDragIndicatorWrapper = styled(View, { + py: '$1', + w: '$full', + alignItems: 'center', +}); + +const StyledBackdrop = styled(AnimatedPressable, { + ':initial': { + opacity: 0, + }, + + ':animate': { + opacity: 0.5, + }, + + ':exit': { + opacity: 0, + }, + + 'position': 'absolute', + 'left': 0, + 'top': 0, + 'right': 0, + 'bottom': 0, + 'bg': '$background950', + + '_web': { + cursor: 'default', + pointerEvents: 'auto', + }, +}); + +const StyledScrollView = styled(ScrollView, { + w: '$full', + h: 'auto', +}); + +const StyledVirtualizedList = styled(VirtualizedList, { + w: '$full', + h: 'auto', +}); + +const StyledFlatList = styled(FlatList, { + w: '$full', + h: 'auto', +}); + +const StyledSectionList = styled(SectionList, { + w: '$full', + h: 'auto', +}); + +const StyledSectionHeaderText = styled(H4, { + letterSpacing: '$sm', + fontWeight: '$bold', + fontFamily: '$heading', + + // Overrides expo-html default styling + marginVertical: 0, + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '5xl': { + //@ts-ignore + props: { as: H1 }, + fontSize: '$6xl', + }, + '4xl': { + //@ts-ignore + props: { as: H1 }, + fontSize: '$5xl', + }, + + '3xl': { + //@ts-ignore + props: { as: H1 }, + fontSize: '$4xl', + }, + + '2xl': { + //@ts-ignore + props: { as: H2 }, + fontSize: '$3xl', + }, + + 'xl': { + //@ts-ignore + props: { as: H3 }, + fontSize: '$2xl', + }, + + 'lg': { + //@ts-ignore + props: { as: H4 }, + fontSize: '$xl', + }, + + 'md': { + //@ts-ignore + props: { as: H5 }, + fontSize: '$lg', + }, + + 'sm': { + //@ts-ignore + props: { as: H6 }, + fontSize: '$md', + }, + + 'xs': { + //@ts-ignore + props: { as: H6 }, + fontSize: '$sm', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + color: '$text500', + props: { size: 'xs' }, + textTransform: 'uppercase', + p: '$3', +}); + +const StyledIcon = styled( + AsForwarder, + { + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + props: { + size: 'sm', + }, + + color: '$background500', + }, + { + componentName: 'BaseIcon', + resolveProps: ['stroke', 'fill'], + } as const, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); + +export const Actionsheet = createActionsheet({ + Root: StyledRoot, + Content: StyledContent, + Item: StyledItem, + ItemText: StyledItemText, + DragIndicator: StyledDragIndicator, + IndicatorWrapper: StyledDragIndicatorWrapper, + Backdrop: StyledBackdrop, + ScrollView: StyledScrollView, + VirtualizedList: StyledVirtualizedList, + FlatList: StyledFlatList, + SectionList: StyledSectionList, + SectionHeaderText: StyledSectionHeaderText, + Icon: StyledIcon, + AnimatePresence: AnimatePresence, +}); + +export const ActionsheetContent = Actionsheet.Content; +export const ActionsheetItem = Actionsheet.Item; +export const ActionsheetItemText = Actionsheet.ItemText; +export const ActionsheetDragIndicator = Actionsheet.DragIndicator; +export const ActionsheetDragIndicatorWrapper = Actionsheet.DragIndicatorWrapper; +export const ActionsheetBackdrop = Actionsheet.Backdrop; +export const ActionsheetScrollView = Actionsheet.ScrollView; +export const ActionsheetVirtualizedList = Actionsheet.VirtualizedList; +export const ActionsheetFlatList = Actionsheet.FlatList; +export const ActionsheetSectionList = Actionsheet.SectionList; +export const ActionsheetSectionHeaderText = Actionsheet.SectionHeaderText; +export const ActionsheetIcon = Actionsheet.Icon; diff --git a/example/storybook-nativewind/src/components-example/themed/Alert/index.tsx b/example/storybook-nativewind/src/components-example/themed/Alert/index.tsx new file mode 100644 index 0000000000..00f5543885 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Alert/index.tsx @@ -0,0 +1,256 @@ +import { AsForwarder, styled } from '@gluestack-style/react'; +import { createAlert } from '@gluestack-ui/alert'; +import { View, Text } from 'react-native'; + +const StyledRoot = styled( + View, + { + alignItems: 'center', + p: '$3', + flexDirection: 'row', + borderRadius: '$sm', + variants: { + action: { + error: { + bg: '$backgroundError', + borderColor: '$error300', + + _icon: { + color: '$error500', + }, + }, + warning: { + bg: '$backgroundWarning', + borderColor: '$warning300', + + _icon: { + color: '$warning500', + }, + }, + success: { + bg: '$backgroundSuccess', + borderColor: '$success300', + + _icon: { + color: '$success500', + }, + }, + info: { + bg: '$backgroundInfo', + borderColor: '$info300', + + _icon: { + color: '$info500', + }, + }, + muted: { + bg: '$backgroundMuted', + borderColor: '$secondary300', + + _icon: { + color: '$secondary500', + }, + }, + }, + + variant: { + solid: {}, + outline: { + borderWidth: '$1', + bg: '$white', + }, + accent: { + borderLeftWidth: '$4', + }, + }, + }, + + defaultProps: { + variant: 'solid', + action: 'info', + }, + }, + { + descendantStyle: ['_icon', '_text'], + } +); + +const StyledText = styled( + Text, + { + color: '$text700', + flex: 1, + fontWeight: '$normal', + fontFamily: '$body', + fontStyle: 'normal', + letterSpacing: '$md', + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + defaultProps: { + size: 'md', + }, + }, + { + ancestorStyle: ['_text'], + } +); + +const StyledIcon = styled( + AsForwarder, + { + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + props: { + size: 'md', + //@ts-ignore + fill: 'none', + }, + }, + { + ancestorStyle: ['_icon'], + } +); + +export const Alert = createAlert({ + Root: StyledRoot, + Text: StyledText, + Icon: StyledIcon, +}); + +export const AlertText = Alert.Text; +export const AlertIcon = Alert.Icon; diff --git a/example/storybook-nativewind/src/components-example/themed/AlertDialog/index.tsx b/example/storybook-nativewind/src/components-example/themed/AlertDialog/index.tsx new file mode 100644 index 0000000000..d099b38ec1 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/AlertDialog/index.tsx @@ -0,0 +1,219 @@ +import { + AnimatePresence, + AnimatedView, + AnimatedPressable, +} from '@gluestack-style/animation-resolver'; +import { createAlertDialog } from '@gluestack-ui/alert-dialog'; +import { View, Pressable, ScrollView } from 'react-native'; +import { styled } from '@gluestack-style/react'; +const StyledRoot = styled( + View, + { + w: '$full', + h: '$full', + justifyContent: 'center', + alignItems: 'center', + + variants: { + size: { + xs: { _content: { w: '60%', maxWidth: 360 } }, + sm: { _content: { w: '70%', maxWidth: 420 } }, + md: { _content: { w: '80%', maxWidth: 510 } }, + lg: { _content: { w: '90%', maxWidth: 640 } }, + full: { _content: { w: '$full' } }, + }, + }, + defaultProps: { size: 'md' }, + + _web: { + pointerEvents: 'box-none', + }, + }, + { + descendantStyle: ['_content'], + } +); + +const StyledContent = styled( + AnimatedView, + { + 'bg': '$background50', + 'rounded': '$lg', + 'overflow': 'hidden', + + //@ts-ignore + ':initial': { + scale: 0.9, + opacity: 0, + }, + + ':animate': { + scale: 1, + opacity: 1, + }, + + ':exit': { + scale: 0.9, + opacity: 0, + }, + + ':transition': { + type: 'spring', + damping: 18, + stiffness: 250, + // @ts-ignore + opacity: { + type: 'timing', + duration: 250, + }, + }, + + 'defaultProps': { + softShadow: '3', + }, + }, + { + ancestorStyle: ['_content'], + } +); + +const StyledCloseButton = styled( + Pressable, + { + 'zIndex': 1, + 'rounded': '$sm', + 'p': '$2', + + '_icon': { + color: '$background400', + }, + + '_text': { + color: '$background400', + }, + + ':hover': { + _icon: { + color: '$background700', + }, + _text: { + color: '$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'], + } +); +const StyledHeader = styled( + View, + { + p: '$4', + borderColor: '$border300', + justifyContent: 'space-between', + alignItems: 'center', + flexDirection: 'row', + }, + {} +); + +const StyledFooter = styled( + View, + { + p: '$4', + flexDirection: 'row', + justifyContent: 'flex-end', + alignItems: 'center', + flexWrap: 'wrap', + borderColor: '$border300', + }, + {} +); +const StyledBody = styled(ScrollView, { px: '$4', py: '$2' }, {}); + +const StyledBackdrop = styled( + AnimatedPressable, + { + ':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', + }, + }, + {} +); + +const AccessibleAlertDialog = createAlertDialog({ + Root: StyledRoot, + Content: StyledContent, + CloseButton: StyledCloseButton, + Header: StyledHeader, + Footer: StyledFooter, + Body: StyledBody, + Backdrop: StyledBackdrop, + //@ts-ignore + AnimatePresence: AnimatePresence, +}); + +export const AlertDialog = AccessibleAlertDialog; +export const AlertDialogContent = AccessibleAlertDialog.Content; +export const AlertDialogCloseButton = AccessibleAlertDialog.CloseButton; +export const AlertDialogHeader = AccessibleAlertDialog.Header; +export const AlertDialogFooter = AccessibleAlertDialog.Footer; +export const AlertDialogBody = AccessibleAlertDialog.Body; +export const AlertDialogBackdrop = AccessibleAlertDialog.Backdrop; diff --git a/example/storybook-nativewind/src/components-example/themed/Avatar/index.tsx b/example/storybook-nativewind/src/components-example/themed/Avatar/index.tsx new file mode 100644 index 0000000000..0ce4c61163 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Avatar/index.tsx @@ -0,0 +1,203 @@ +import { createAvatar } from '@gluestack-ui/avatar'; + +import { styled } from '@gluestack-style/react'; +import { View, Text, Image } from 'react-native'; +const StyledRoot = styled( + View, + { + borderRadius: '$full', + justifyContent: 'center', + alignItems: 'center', + position: 'relative', + bg: '$primary600', + variants: { + size: { + 'xs': { + w: '$6', + h: '$6', + + _badge: { + w: '$2', + h: '$2', + }, + _image: { + w: '$full', + h: '$full', + }, + + _text: { + props: { size: '2xs' }, + }, + }, + + 'sm': { + w: '$8', + h: '$8', + + _badge: { + w: '$2', + h: '$2', + }, + _image: { + w: '$full', + h: '$full', + }, + + _text: { + props: { size: 'xs' }, + }, + }, + + 'md': { + w: '$12', + h: '$12', + + _badge: { + w: '$3', + h: '$3', + }, + _image: { + w: '$full', + h: '$full', + }, + + _text: { + props: { size: 'md' }, + }, + }, + + 'lg': { + w: '$16', + h: '$16', + + _badge: { + w: '$4', + h: '$4', + }, + _image: { + w: '$full', + h: '$full', + }, + + _text: { + props: { size: 'xl' }, + }, + }, + + 'xl': { + w: '$24', + h: '$24', + + _badge: { + w: '$6', + h: '$6', + }, + _image: { + w: '$full', + h: '$full', + }, + + _text: { + props: { size: '3xl' }, + }, + }, + + '2xl': { + w: '$32', + h: '$32', + + _badge: { + w: '$8', + h: '$8', + }, + _image: { + w: '$full', + h: '$full', + }, + + _text: { + props: { size: '5xl' }, + }, + }, + }, + }, + defaultProps: { + size: 'md', + }, + }, + { + descendantStyle: ['_badge', '_text', '_image'], + ancestorStyle: ['_avatar'], + } +); + +const StyledBadge = styled( + View, + { + w: '$5', + h: '$5', + bg: '$success500', + borderRadius: '$full', + position: 'absolute', + right: 0, + bottom: 0, + borderColor: 'white', + borderWidth: 2, + }, + { + ancestorStyle: ['_badge'], + } +); +const StyledGroup = styled( + View, + { + flexDirection: 'row-reverse', + position: 'relative', + _avatar: { + ml: -10, + }, + }, + { + descendantStyle: ['_avatar'], + } +); + +const StyledImage = styled( + Image, + { w: '$full', h: '$full', borderRadius: '$full', position: 'absolute' }, + { + ancestorStyle: ['_image'], + } +); +const StyledFallbackText = styled( + Text, + { + color: '$text0', + fontWeight: '$semibold', + props: { + size: 'xl', + }, + overflow: 'hidden', + textTransform: 'uppercase', + _web: { + cursor: 'default', + }, + }, + { + ancestorStyle: ['_text'], + } as const +); + +const AccessbileAvatar = createAvatar({ + Root: StyledRoot, + Badge: StyledBadge, + Group: StyledGroup, + Image: StyledImage, + FallbackText: StyledFallbackText, +}); + +export const Avatar = AccessbileAvatar; +export const AvatarBadge = AccessbileAvatar.Badge; +export const AvatarGroup = AccessbileAvatar.Group; +export const AvatarImage = AccessbileAvatar.Image; +export const AvatarFallbackText = AccessbileAvatar.FallbackText; diff --git a/example/storybook-nativewind/src/components-example/themed/Badge/index.tsx b/example/storybook-nativewind/src/components-example/themed/Badge/index.tsx new file mode 100644 index 0000000000..dd4ace986d --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Badge/index.tsx @@ -0,0 +1,319 @@ +import { AsForwarder, styled } from '@gluestack-style/react'; +import { Text, View } from 'react-native'; + +const StyledRoot = styled( + View, + { + 'flexDirection': 'row', + 'alignItems': 'center', + 'borderRadius': '$xs', + 'variants': { + action: { + error: { + bg: '$backgroundError', + borderColor: '$error300', + + _icon: { + color: '$error600', + }, + + _text: { + color: '$error600', + }, + }, + warning: { + bg: '$backgroundWarning', + borderColor: '$warning300', + + _icon: { + color: '$warning600', + }, + + _text: { + color: '$warning600', + }, + }, + success: { + bg: '$backgroundSuccess', + borderColor: '$success300', + + _icon: { + color: '$success600', + }, + + _text: { + color: '$success600', + }, + }, + info: { + bg: '$backgroundInfo', + borderColor: '$info300', + + _icon: { + color: '$info600', + }, + + _text: { + color: '$info600', + }, + }, + muted: { + bg: '$backgroundMuted', + borderColor: '$secondary300', + + _icon: { + color: '$secondary600', + }, + + _text: { + color: '$secondary600', + }, + }, + }, + + variant: { + solid: {}, + outline: { + borderWidth: '$1', + }, + }, + + size: { + sm: { + px: '$2', + _icon: { + props: { + size: '2xs', + }, + }, + _text: { + props: { + size: '2xs', + }, + }, + }, + md: { + px: '$2', + _icon: { + props: { + size: 'xs', + }, + }, + _text: { + props: { + size: 'xs', + }, + }, + }, + lg: { + px: '$2', + _icon: { + props: { size: 'sm' }, + }, + _text: { + props: { size: 'sm' }, + }, + }, + }, + }, + + ':disabled': { + opacity: 0.5, + }, + 'defaultProps': { + action: 'info', + variant: 'solid', + size: 'md', + }, + }, + { + componentName: 'Badge', + descendantStyle: ['_text', '_icon'], + } as const +); + +const StyledText = styled( + Text, + { + color: '$text700', + fontWeight: '$normal', + fontFamily: '$body', + fontStyle: 'normal', + letterSpacing: '$md', + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + defaultProps: { + size: 'md', + }, + textTransform: 'uppercase', + }, + { + componentName: 'BadgeText', + ancestorStyle: ['_text'], + } as const +); + +const StyledIcon = styled( + AsForwarder, + { + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + props: { + size: 'md', + //@ts-ignore + fill: 'none', + }, + + color: '$background500', + }, + { + componentName: 'BaseIcon', + resolveProps: ['stroke', 'fill'], + ancestorStyle: ['_icon'], + } as const, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); + +const Badge = StyledRoot; + +export { Badge, StyledIcon as BadgeIcon, StyledText as BadgeText }; diff --git a/example/storybook-nativewind/src/components-example/themed/Box/index.tsx b/example/storybook-nativewind/src/components-example/themed/Box/index.tsx new file mode 100644 index 0000000000..fa2594ba5a --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Box/index.tsx @@ -0,0 +1,7 @@ +import { View } from 'react-native'; + +import { styled } from '@gluestack-style/react'; + +const StyledRoot = styled(View, {}); + +export const Box = StyledRoot; diff --git a/example/storybook-nativewind/src/components-example/themed/Button/index.tsx b/example/storybook-nativewind/src/components-example/themed/Button/index.tsx new file mode 100644 index 0000000000..ba81ceb164 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Button/index.tsx @@ -0,0 +1,845 @@ +import { ActivityIndicator, Pressable, Text, View } from 'react-native'; + +import { createButton } from '@gluestack-ui/button'; +import { AsForwarder, styled } from '@gluestack-style/react'; + +const StyledRoot = styled( + Pressable, + { + 'borderRadius': '$sm', + 'backgroundColor': '$primary500', + 'flexDirection': 'row', + 'justifyContent': 'center', + 'alignItems': 'center', + + '_text': { + color: '$text0', + fontWeight: '$semibold', + }, + + '_icon': { + color: '$text0', + }, + + '_spinner': { + props: { + color: '$background0', + }, + }, + + 'variants': { + action: { + primary: { + 'bg': '$primary500', + 'borderColor': '$primary300', + + ':hover': { + bg: '$primary600', + borderColor: '$primary400', + }, + + ':active': { + bg: '$primary700', + borderColor: '$primary700', + }, + + '_text': { + 'color': '$primary600', + ':hover': { + color: '$primary600', + }, + ':active': { + color: '$primary700', + }, + }, + + '_icon': { + 'color': '$primary600', + ':hover': { + color: '$primary600', + }, + ':active': { + color: '$primary700', + }, + }, + + '_spinner': { + 'props': { + color: '$primary600', + }, + ':hover': { + props: { + color: '$primary600', + }, + }, + ':active': { + props: { + color: '$primary700', + }, + }, + }, + }, + secondary: { + 'bg': '$secondary500', + 'borderColor': '$secondary300', + + ':hover': { + bg: '$secondary600', + borderColor: '$secondary400', + }, + + ':active': { + bg: '$secondary700', + borderColor: '$secondary700', + }, + + '_text': { + 'color': '$secondary600', + ':hover': { + color: '$secondary600', + }, + ':active': { + color: '$secondary700', + }, + }, + + '_icon': { + 'color': '$secondary600', + ':hover': { + color: '$secondary600', + }, + ':active': { + color: '$secondary700', + }, + }, + + '_spinner': { + 'props': { + color: '$secondary600', + }, + ':hover': { + props: { color: '$secondary600' }, + }, + ':active': { + props: { color: '$secondary700' }, + }, + }, + }, + positive: { + 'bg': '$success500', + 'borderColor': '$success300', + + ':hover': { + bg: '$success600', + borderColor: '$success400', + }, + + ':active': { + bg: '$success700', + borderColor: '$success700', + }, + + '_text': { + 'color': '$success600', + ':hover': { + color: '$success600', + }, + ':active': { + color: '$success700', + }, + }, + + '_icon': { + 'color': '$success600', + ':hover': { + color: '$success600', + }, + ':active': { + color: '$success700', + }, + }, + + '_spinner': { + 'props': { + color: '$success600', + }, + ':hover': { + props: { color: '$success600' }, + }, + ':active': { + props: { color: '$success700' }, + }, + }, + }, + negative: { + 'bg': '$error500', + 'borderColor': '$error300', + + ':hover': { + bg: '$error600', + borderColor: '$error400', + }, + + ':active': { + bg: '$error700', + borderColor: '$error700', + }, + + '_text': { + 'color': '$error600', + ':hover': { + color: '$error600', + }, + ':active': { + color: '$error700', + }, + }, + + '_icon': { + 'color': '$error600', + ':hover': { + color: '$error600', + }, + ':active': { + color: '$error700', + }, + }, + + '_spinner': { + 'props': { + color: '$error600', + }, + ':hover': { + props: { color: '$error600' }, + }, + ':active': { + props: { color: '$error700' }, + }, + }, + }, + + default: { + 'bg': '$transparent', + + ':hover': { + bg: '$background50', + }, + + ':active': { + bg: 'transparent', + }, + }, + }, + + variant: { + link: { + 'px': '$0', + ':hover': { + _text: { + textDecorationLine: 'underline', + }, + }, + ':active': { + _text: { + textDecorationLine: 'underline', + }, + }, + }, + outline: { + 'bg': 'transparent', + 'borderWidth': '$1', + + ':hover': { + bg: '$background50', + }, + + ':active': { + bg: 'transparent', + }, + }, + solid: { + _text: { + 'color': '$text0', + ':hover': { + color: '$text0', + }, + ':active': { + color: '$text0', + }, + }, + + _spinner: { + 'props': { color: '$text0' }, + ':hover': { + props: { color: '$text0' }, + }, + ':active': { + props: { color: '$text0' }, + }, + }, + + _icon: { + 'props': { color: '$text0' }, + ':hover': { + props: { color: '$text0' }, + }, + ':active': { + props: { color: '$text0' }, + }, + }, + }, + }, + + size: { + xs: { + px: '$3.5', + h: '$8', + _icon: { + props: { + size: '2xs', + }, + }, + _text: { + props: { + size: 'xs', + }, + }, + }, + sm: { + px: '$4', + h: '$9', + _icon: { + props: { + size: 'sm', + }, + }, + _text: { + props: { + size: 'sm', + }, + }, + }, + md: { + px: '$5', + h: '$10', + _icon: { + props: { + size: 'md', + }, + }, + _text: { + props: { + size: 'md', + }, + }, + }, + lg: { + px: '$6', + h: '$11', + _icon: { + props: { + size: 'md', + }, + }, + _text: { + props: { + size: 'lg', + }, + }, + }, + xl: { + px: '$7', + h: '$12', + _icon: { + props: { + size: 'lg', + }, + }, + _text: { + props: { + size: 'xl', + }, + }, + }, + }, + }, + 'compoundVariants': [ + { + action: 'primary', + variant: 'link', + value: { + 'px': '$0', + 'bg': 'transparent', + + ':hover': { + bg: 'transparent', + }, + + ':active': { + bg: 'transparent', + }, + }, + }, + { + action: 'secondary', + variant: 'link', + value: { + 'px': '$0', + 'bg': 'transparent', + + ':hover': { + bg: 'transparent', + }, + + ':active': { + bg: 'transparent', + }, + }, + }, + { + action: 'positive', + variant: 'link', + value: { + 'px': '$0', + 'bg': 'transparent', + + ':hover': { + bg: 'transparent', + }, + + ':active': { + bg: 'transparent', + }, + }, + }, + { + action: 'negative', + variant: 'link', + value: { + 'px': '$0', + 'bg': 'transparent', + + ':hover': { + bg: 'transparent', + }, + + ':active': { + bg: 'transparent', + }, + }, + }, + { + action: 'primary', + variant: 'outline', + value: { + 'bg': 'transparent', + + ':hover': { + bg: '$background50', + }, + + ':active': { + bg: 'transparent', + }, + }, + }, + { + action: 'secondary', + variant: 'outline', + value: { + 'bg': 'transparent', + + ':hover': { + bg: '$background50', + }, + + ':active': { + bg: 'transparent', + }, + }, + }, + { + action: 'positive', + variant: 'outline', + value: { + 'bg': 'transparent', + + ':hover': { + bg: '$background50', + }, + + ':active': { + bg: 'transparent', + }, + }, + }, + { + action: 'negative', + variant: 'outline', + value: { + 'bg': 'transparent', + + ':hover': { + bg: '$background50', + }, + + ':active': { + bg: 'transparent', + }, + }, + }, + { + action: 'primary', + variant: 'solid', + value: { + _text: { + 'color': '$text0', + ':hover': { + color: '$text0', + }, + ':active': { + color: '$text0', + }, + }, + + _icon: { + 'color': '$text0', + ':hover': { + color: '$text0', + }, + ':active': { + color: '$text0', + }, + }, + + _spinner: { + 'props': { color: '$text0' }, + ':hover': { + props: { color: '$text0' }, + }, + ':active': { + props: { color: '$text0' }, + }, + }, + }, + }, + { + action: 'secondary', + variant: 'solid', + value: { + _text: { + 'color': '$text0', + ':hover': { + color: '$text0', + }, + ':active': { + color: '$text0', + }, + }, + + _icon: { + 'color': '$text0', + ':hover': { + color: '$text0', + }, + ':active': { + color: '$text0', + }, + }, + + _spinner: { + 'props': { color: '$text0' }, + ':hover': { + props: { color: '$text0' }, + }, + ':active': { + props: { color: '$text0' }, + }, + }, + }, + }, + { + action: 'positive', + variant: 'solid', + value: { + _text: { + 'color': '$text0', + ':hover': { + color: '$text0', + }, + ':active': { + color: '$text0', + }, + }, + + _icon: { + 'color': '$text0', + ':hover': { + color: '$text0', + }, + ':active': { + color: '$text0', + }, + 'props': { color: '$text0' }, + }, + + _spinner: { + 'props': { color: '$text0' }, + ':hover': { + props: { color: '$text0' }, + }, + ':active': { + props: { color: '$text0' }, + }, + }, + }, + }, + { + action: 'negative', + variant: 'solid', + value: { + _text: { + 'color': '$text0', + ':hover': { + color: '$text0', + }, + ':active': { + color: '$text0', + }, + }, + + _icon: { + 'color': '$text0', + ':hover': { + color: '$text0', + }, + ':active': { + color: '$text0', + }, + }, + + _spinner: { + 'props': { color: '$text0' }, + ':hover': { + props: { color: '$text0' }, + }, + ':active': { + props: { color: '$text0' }, + }, + }, + }, + }, + ], + + 'props': { + size: 'md', + variant: 'solid', + action: 'primary', + }, + + '_web': { + ':focusVisible': { + outlineWidth: '$0.5', + outlineColor: '$primary700', + outlineStyle: 'solid', + }, + }, + + ':disabled': { + opacity: 0.4, + }, + }, + { + descendantStyle: ['_text', '_spinner', '_icon'], + ancestorStyle: ['_button'], + } +); +const StyledText = styled( + Text, + { + color: '$textLight0', + _web: { + userSelect: 'none', + }, + }, + { + ancestorStyle: ['_text'], + } +); +const StyledGroup = styled( + View, + { + variants: { + size: { + xs: { + _button: { + props: { + size: 'xs', + }, + }, + }, + sm: { + _button: { + props: { + size: 'sm', + }, + }, + }, + md: { + _button: { + props: { + size: 'md', + }, + }, + }, + lg: { + _button: { + props: { + size: 'lg', + }, + }, + }, + xl: { + _button: { + _button: { + props: { + size: 'xl', + }, + }, + }, + }, + }, + space: { + 'xs': { + gap: '$1', + }, + 'sm': { + gap: '$2', + }, + 'md': { + gap: '$3', + }, + 'lg': { + gap: '$4', + }, + 'xl': { + gap: '$5', + }, + '2xl': { + gap: '$6', + }, + '3xl': { + gap: '$7', + }, + '4xl': { + gap: '$8', + }, + }, + isAttached: { + true: { + gap: 0, + }, + }, + }, + defaultProps: { + size: 'md', + space: 'sm', + }, + }, + { + descendantStyle: ['_button'], + } +); + +const StyledSpinner = styled( + ActivityIndicator, + {}, + { + ancestorStyle: ['_spinner'], + resolveProps: ['color'], + } +); + +const StyledIcon = styled( + AsForwarder, + { + color: '$background800', + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + props: { + size: 'md', + }, + }, + { + resolveProps: ['stroke', 'fill'], + }, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); +const UIButton = createButton({ + Root: StyledRoot, + Text: StyledText, + Group: StyledGroup, + Spinner: StyledSpinner, + Icon: StyledIcon, +}); + +export const Button = UIButton; +export const ButtonText = UIButton.Text; +export const ButtonGroup = UIButton.Group; +export const ButtonSpinner = UIButton.Spinner; +export const ButtonIcon = UIButton.Icon; diff --git a/example/storybook-nativewind/src/components-example/themed/Center/index.tsx b/example/storybook-nativewind/src/components-example/themed/Center/index.tsx new file mode 100644 index 0000000000..c5e80efb57 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Center/index.tsx @@ -0,0 +1,12 @@ +import { View } from 'react-native'; +import { styled } from '@gluestack-style/react'; +const StyledRoot = styled( + View, + { + alignItems: 'center', + justifyContent: 'center', + }, + {} +); + +export const Center = StyledRoot; diff --git a/example/storybook-nativewind/src/components-example/themed/Checkbox/index.tsx b/example/storybook-nativewind/src/components-example/themed/Checkbox/index.tsx new file mode 100644 index 0000000000..4c1c17dfe4 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Checkbox/index.tsx @@ -0,0 +1,294 @@ +import { createCheckbox } from '@gluestack-ui/checkbox'; +import { View, Pressable, Text } from 'react-native'; + +import { Platform } from 'react-native'; + +import { Check } from 'lucide-react-native'; +import { styled } from '@gluestack-style/react'; + +const StyledRoot = styled( + // @ts-ignore + Platform.OS === 'web' ? View : Pressable, + { + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + gap: '$2', + variants: { + size: { + lg: { + _text: { + props: { + size: 'lg', + }, + }, + + _icon: { + props: { + size: 'md', + }, + }, + _indicator: { + borderWidth: 3, + h: '$6', + w: '$6', + }, + }, + + md: { + _text: { + props: { + size: 'md', + }, + }, + + _icon: { + props: { + size: 'sm', + }, + }, + _indicator: { + borderWidth: 2, + h: '$5', + w: '$5', + }, + }, + + sm: { + _text: { + props: { + size: 'sm', + }, + }, + + _icon: { + props: { + size: '2xs', + }, + }, + _indicator: { + borderWidth: 2, + h: '$4', + w: '$4', + }, + }, + }, + }, + + defaultProps: { + size: 'md', + }, + + _web: { + 'cursor': 'pointer', + ':disabled': { + cursor: 'not-allowed', + }, + }, + }, + { descendantStyle: ['_icon', '_text', '_indicator'] } +); + +const StyledIndicator = styled( + View, + { + 'justifyContent': 'center', + 'alignItems': 'center', + 'borderColor': '$border400', + 'bg': '$transparent', + 'borderRadius': 4, + + '_web': { + ':focusVisible': { + outlineWidth: '2px', + outlineColor: '$primary700', + outlineStyle: 'solid', + }, + }, + + ':checked': { + borderColor: '$primary600', + bg: '$primary600', + }, + + ':hover': { + 'borderColor': '$border500', + 'bg': 'transparent', + ':invalid': { + borderColor: '$error700', + }, + ':checked': { + 'bg': '$primary700', + 'borderColor': '$primary700', + ':disabled': { + 'borderColor': '$primary600', + 'bg': '$primary600', + 'opacity': 0.4, + ':invalid': { + borderColor: '$error700', + }, + }, + }, + ':disabled': { + 'borderColor': '$border400', + ':invalid': { + borderColor: '$error700', + }, + }, + }, + + ':active': { + ':checked': { + bg: '$primary800', + borderColor: '$primary800', + }, + }, + + ':invalid': { + borderColor: '$error700', + }, + + ':disabled': { + opacity: 0.4, + }, + }, + { ancestorStyle: ['_indicator'] } +); +const StyledIcon = styled( + Check, + { + 'color': '$background800', + + // defaultProps: { + // size: 'md', + // }, + 'variants': { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + + ':checked': { + color: '$background0', + }, + + ':disabled': { + opacity: 0.4, + }, + }, + { + resolveProps: ['stroke', 'fill'], + ancestorStyle: ['_icon'], + }, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); +const StyledLabel = styled( + Text, + { + 'color': '$text600', + + ':checked': { + color: '$text900', + }, + + ':hover': { + 'color': '$text900', + ':checked': { + 'color': '$text900', + ':disabled': { + color: '$text900', + }, + }, + ':disabled': { + color: '$text600', + }, + }, + + ':active': { + 'color': '$text900', + + ':checked': { + color: '$text900', + }, + }, + + ':disabled': { + opacity: 0.4, + }, + + '_web': { + MozUserSelect: 'none', + WebkitUserSelect: 'none', + msUserSelect: 'none', + userSelect: 'none', + }, + }, + { ancestorStyle: ['_text'] } +); +const StyledGroup = styled(View, {}); + +const UICheckbox = createCheckbox({ + Root: StyledRoot, + Indicator: StyledIndicator, + Icon: StyledIcon, + Label: StyledLabel, + Group: StyledGroup, +}); + +export const Checkbox = UICheckbox; +export const CheckboxIndicator = UICheckbox.Indicator; +export const CheckboxLabel = UICheckbox.Label; +export const CheckboxIcon = UICheckbox.Icon; +export const CheckboxGroup = UICheckbox.Group; diff --git a/example/storybook-nativewind/src/components-example/themed/Divider/index.tsx b/example/storybook-nativewind/src/components-example/themed/Divider/index.tsx new file mode 100644 index 0000000000..e74bb7dadb --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Divider/index.tsx @@ -0,0 +1,30 @@ +import { createDivider } from '@gluestack-ui/divider'; +import { styled } from '@gluestack-style/react'; +import { View } from 'react-native'; + +const StyledRoot = styled( + View, + { + bg: '$background200', + + variants: { + orientation: { + vertical: { + width: '$px', + height: '$full', + }, + horizontal: { + height: '$px', + width: '$full', + }, + }, + }, + + defaultProps: { + orientation: 'horizontal', + }, + }, + {} +); + +export const Divider = createDivider({ Root: StyledRoot }); diff --git a/example/storybook-nativewind/src/components-example/themed/Fab/index.tsx b/example/storybook-nativewind/src/components-example/themed/Fab/index.tsx new file mode 100644 index 0000000000..2a1819d504 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Fab/index.tsx @@ -0,0 +1,336 @@ +import { AsForwarder, styled } from '@gluestack-style/react'; +import { createFab } from '@gluestack-ui/fab'; +import { Text } from 'react-native'; +import { Pressable } from 'react-native'; + +const StyledRoot = styled( + Pressable, + { + 'bg': '$primary500', + 'rounded': '$full', + 'zIndex': 20, + 'p': 16, + 'flexDirection': 'row', + 'alignItems': 'center', + 'justifyContent': 'center', + 'position': 'absolute', + + ':hover': { + bg: '$primary600', + }, + + ':active': { + bg: '$primary700', + }, + + ':disabled': { + opacity: 0.4, + _web: { + // @ts-ignore + pointerEvents: 'all !important', + cursor: 'not-allowed', + }, + }, + + '_text': { + color: '$text50', + fontWeight: '$normal', + }, + + '_icon': { + 'color': '$text50', + + ':hover': { + color: '$text0', + }, + + ':active': { + color: '$text0', + }, + }, + + '_web': { + ':focusVisible': { + outlineWidth: 2, + outlineColor: '$primary700', + outlineStyle: 'solid', + }, + }, + + 'variants': { + size: { + sm: { + px: '$2.5', + py: '$2.5', + _text: { + fontSize: '$sm', + }, + _icon: { + props: { + size: 'sm', + }, + }, + }, + md: { + px: '$3', + py: '$3', + _text: { + fontSize: '$md', + }, + _icon: { + props: { + size: 'md', + }, + }, + }, + lg: { + px: '$4', + py: '$4', + _text: { + fontSize: '$lg', + }, + _icon: { + props: { + size: 'md', + }, + }, + }, + }, + + placement: { + 'top right': { + top: '$4', + right: '$4', + }, + + 'top left': { + top: '$4', + left: '$4', + }, + + 'bottom right': { + bottom: '$4', + right: '$4', + }, + + 'bottom left': { + bottom: '$4', + left: '$4', + }, + + 'top center': { + top: '$4', + alignSelf: 'center', + // TODO: fix this, this is correct way, but React Native doesn't support this on Native + // left: '50%', + // transform: [ + // { + // // @ts-ignore + // translateX: '-50%', + // }, + // ], + }, + + 'bottom center': { + bottom: '$4', + alignSelf: 'center', + // TODO: fix this, this is correct way, but React Native doesn't support this on Native + // left: '50%', + // transform: [ + // { + // // @ts-ignore + // translateX: '-50%', + // }, + // ], + }, + }, + }, + + 'defaultProps': { + placement: 'bottom right', + size: 'md', + hardShadow: '2', + }, + }, + { + descendantStyle: ['_text', '_icon'], + } +); + +const StyledLabel = styled( + Text, + { + fontWeight: '$normal', + fontFamily: '$body', + fontStyle: 'normal', + letterSpacing: '$md', + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + defaultProps: { + size: 'md', + }, + color: '$text50', + }, + { + ancestorStyle: ['_text'], + } +); + +const StyledIcon = styled( + AsForwarder, + { + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + props: { + size: 'md', + //@ts-ignore + fill: 'none', + }, + }, + { + ancestorStyle: ['_icon'], + } +); + +export const Fab = createFab({ + Root: StyledRoot, + Label: StyledLabel, + Icon: StyledIcon, +}); +export const FabLabel = Fab.Label; +export const FabIcon = Fab.Icon; diff --git a/example/storybook-nativewind/src/components-example/themed/FlatList/index.tsx b/example/storybook-nativewind/src/components-example/themed/FlatList/index.tsx new file mode 100644 index 0000000000..ef7356e1bb --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/FlatList/index.tsx @@ -0,0 +1,34 @@ +import { FlatList as RNFlatList } from 'react-native'; +import { styled, useStyled, propertyTokenMap } from '@gluestack-style/react'; + +export const FlatList = styled( + RNFlatList, + {}, + { + componentName: 'FlatList', + resolveProps: ['contentContainerStyle'], + } as const, + { + propertyResolver: { + contentContainerStyle: (rawValue, resolver) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const aliases: any = useStyled()?.config?.aliases; + const newValue = {} as Record; + Object.entries(rawValue).forEach(([key, value]: any) => { + if (Object.hasOwn(aliases, key)) { + newValue[`${aliases[key]}`] = resolver( + value, + //@ts-ignore + propertyTokenMap[aliases[key]] + ); + } else { + //@ts-ignore + newValue[`${key}`] = resolver(value, propertyTokenMap[key]); + } + }); + rawValue = newValue; + return rawValue; + }, + }, + } +); diff --git a/example/storybook-nativewind/src/components-example/themed/FormControl/index.tsx b/example/storybook-nativewind/src/components-example/themed/FormControl/index.tsx new file mode 100644 index 0000000000..bf25887b17 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/FormControl/index.tsx @@ -0,0 +1,227 @@ +import { Text, View } from 'react-native'; + +import { styled } from '@gluestack-style/react'; + +import { createFormControl } from '@gluestack-ui/form-control'; +import { AsForwarder } from '@gluestack-style/react'; + +const StyledRoot = styled( + View, + { + flexDirection: 'column', + variants: { + size: { + sm: { + _labelText: { + props: { size: 'sm' }, + }, + _labelAstrick: { + props: { size: 'sm' }, + }, + _helperText: { + props: { size: 'xs' }, + }, + _errorText: { + props: { size: 'xs' }, + }, + }, + md: { + _labelText: { + props: { size: 'md' }, + }, + _labelAstrick: { + props: { size: 'md' }, + }, + _helperText: { + props: { size: 'sm' }, + }, + _errorText: { + props: { size: 'sm' }, + }, + }, + lg: { + _labelText: { + props: { size: 'lg' }, + }, + _labelAstrick: { + props: { size: 'lg' }, + }, + _helperText: { + props: { size: 'md' }, + }, + _errorText: { + props: { size: 'md' }, + }, + }, + }, + }, + + defaultProps: { + size: 'md', + }, + }, + { + descendantStyle: [ + '_labelText', + '_helperText', + '_errorText', + '_labelAstrick', + ], + } +); + +const StyledErrorIcon = styled( + AsForwarder, + { + color: '$error700', + // @ts-ignore + fill: 'none', + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + props: { + size: 'md', + }, + }, + { + resolveProps: ['stroke', 'fill'], + }, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); + +const StyledFormControlError = styled(View, { + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + mt: '$1', + gap: '$1', +}); + +// const StyeldFormControlErrorIcon = styled(StyledIcon, { +// color: '$error700', +// props: { +// size: 'sm', +// }, +// }); + +const StyledFormControlErrorText = styled( + Text, + { + color: '$error700', + }, + { ancestorStyle: ['_errorText'] } +); + +const StyledFormControlHelper = styled(View, { + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + mt: '$1', +}); + +const StyledFormControlHelperText = styled( + Text, + { + props: { + size: 'xs', + }, + + color: '$text500', + }, + { ancestorStyle: ['_helperText'] } +); + +const StyledFormControlLabel = styled( + View, + { + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + mb: '$1', + }, + { descendantStyle: ['_labelText'] } +); + +const StyledFormControlLabelText = styled(Text, { + fontWeight: '$medium', + color: '$text900', +}); + +const StyledLabelAstrick = styled(Text, {}, { + componentName: 'FormControlErrorText', + ancestorStyle: ['_labelAstrick'], +} as const); + +export const FormControl = createFormControl({ + Root: StyledRoot, + Error: StyledFormControlError, + ErrorText: StyledFormControlErrorText, + ErrorIcon: StyledErrorIcon, + Label: StyledFormControlLabel, + LabelText: StyledFormControlLabelText, + LabelAstrick: StyledLabelAstrick, + Helper: StyledFormControlHelper, + HelperText: StyledFormControlHelperText, +}); +export const FormControlError = FormControl.Error; +export const FormControlErrorText = FormControl.Error.Text; +export const FormControlErrorIcon = FormControl.Error.Icon; +export const FormControlLabel = FormControl.Label; +export const FormControlLabelText = FormControl.Label.Text; +export const FormControlLabelAstrick = FormControl.Label.Astrick; +export const FormControlHelper = FormControl.Helper; +export const FormControlHelperText = FormControl.Helper.Text; diff --git a/example/storybook-nativewind/src/components-example/themed/GluestackUIProvider/config.ts b/example/storybook-nativewind/src/components-example/themed/GluestackUIProvider/config.ts new file mode 100644 index 0000000000..789234f036 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/GluestackUIProvider/config.ts @@ -0,0 +1,847 @@ +import { AnimationResolver } from '@gluestack-style/animation-resolver'; +import { MotionAnimationDriver } from '@gluestack-style/legend-motion-animation-driver'; +import { createConfig } from '@gluestack-style/react'; + +export const gluestackUIConfig = createConfig({ + aliases: { + bg: 'backgroundColor', + bgColor: 'backgroundColor', + h: 'height', + w: 'width', + p: 'padding', + px: 'paddingHorizontal', + py: 'paddingVertical', + pt: 'paddingTop', + pb: 'paddingBottom', + pr: 'paddingRight', + pl: 'paddingLeft', + m: 'margin', + mx: 'marginHorizontal', + my: 'marginVertical', + mt: 'marginTop', + mb: 'marginBottom', + mr: 'marginRight', + ml: 'marginLeft', + rounded: 'borderRadius', + } as const, + tokens: { + colors: { + // Brand Colors + primary0: '#B3B3B3', + primary50: '#999999', + primary100: '#808080', + primary200: '#737373', + primary300: '#666666', + primary400: '#525252', + primary500: '#333333', + primary600: '#292929', + primary700: '#1F1F1F', + primary800: '#0D0D0D', + primary900: '#0A0A0A', + primary950: '#080808', + + secondary0: '#FEFFFF', + secondary50: '#F1F2F2', + secondary100: '#E7E8E8', + secondary200: '#DBDBDB', + secondary300: '#AFB0B0', + secondary400: '#727373', + secondary500: '#5E5F5F', + secondary600: '#515252', + secondary700: '#3F4040', + secondary800: '#272626', + secondary900: '#181717', + secondary950: '#0B0C0C', + + tertiary0: '#FFFAF5', + tertiary50: '#FFF2E5', + tertiary100: '#FFE9D5', + tertiary200: '#FED1AA', + tertiary300: '#FDB474', + tertiary400: '#FB9D4B', + tertiary500: '#E78128', + tertiary600: '#D7751F', + tertiary700: '#B4621A', + tertiary800: '#824917', + tertiary900: '#6C3D13', + tertiary950: '#543112', + + // Action Colors + + error00: '#FEE9E9', + error50: '#FEE2E2', + error100: '#FECACA', + error200: '#FCA5A5', + error300: '#F87171', + error400: '#EF4444', + error500: '#E63535', + error600: '#DC2626', + error700: '#B91C1C', + error800: '#991B1B', + error900: '#7F1D1D', + error950: '#531313', + + success0: '#E4FFF4', + success50: '#CAFFE8', + success100: '#A2F1C0', + success200: '#84D3A2', + success300: '#66B584', + success400: '#489766', + success500: '#348352', + success600: '#2A7948', + success700: '#206F3E', + success800: '#166534', + success900: '#14532D', + success950: '#1B3224', + + warning0: '#FFFDFB', + warning50: '#FFF9F5', + warning100: '#FFE7D5', + warning200: '#FECDAA', + warning300: '#FDAD74', + warning400: '#FB954B', + warning500: '#E77828', + warning600: '#D76C1F', + warning700: '#B45A1A', + warning800: '#824417', + warning900: '#6C3813', + warning950: '#542D12', + + info0: '#ECF8FE', + info50: '#C7EBFC', + info100: '#A2DDFA', + info200: '#7CCFF8', + info300: '#57C2F6', + info400: '#32B4F4', + info500: '#0DA6F2', + info600: '#0B8DCD', + info700: '#0973A8', + info800: '#075A83', + info900: '#05405D', + info950: '#032638', + + // Property Derived Colors + + text0: '#FEFEFF', + text50: '#F5F5F5', + text100: '#E5E5E5', + text200: '#DBDBDC', + text300: '#D4D4D4', + text400: '#A3A3A3', + text500: '#8C8C8C', + text600: '#737373', + text700: '#525252', + text800: '#404040', + text900: '#262627', + text950: '#171717', + + border0: '#FDFEFE', + border50: '#F3F3F3', + border100: '#E6E6E6', + border200: '#DDDCDB', + border300: '#D3D3D3', + border400: '#A5A3A3', + border500: '#8C8D8D', + border600: '#737474', + border700: '#535252', + border800: '#414141', + border900: '#272624', + border950: '#1A1717', + + background0: '#FBFBFB', + background50: '#F6F6F6', + background100: '#F2F1F1', + background200: '#DCDBDB', + background300: '#D5D4D4', + background400: '#A2A3A3', + background500: '#8E8E8E', + background600: '#747474', + background700: '#535252', + background800: '#414040', + background900: '#272625', + background950: '#181718', + + // StandAlone Colors + + backgroundError: '#FEF1F1', + + backgroundWarning: '#FFF4EB', + backgroundSuccess: '#EDFCF2', + backgroundMuted: '#F6F6F7', + backgroundInfo: '#EBF8FE', + + white: '#FFFFFF', + black: '#000000', + + // Extended Colors + rose50: '#fff1f2', + rose100: '#ffe4e6', + rose200: '#fecdd3', + rose300: '#fda4af', + rose400: '#fb7185', + rose500: '#f43f5e', + rose600: '#e11d48', + rose700: '#be123c', + rose800: '#9f1239', + rose900: '#881337', + + pink50: '#fdf2f8', + pink100: '#fce7f3', + pink200: '#fbcfe8', + pink300: '#f9a8d4', + pink400: '#f472b6', + pink500: '#ec4899', + pink600: '#db2777', + pink700: '#be185d', + pink800: '#9d174d', + pink900: '#831843', + + fuchsia50: '#fdf4ff', + fuchsia100: '#fae8ff', + fuchsia200: '#f5d0fe', + fuchsia300: '#f0abfc', + fuchsia400: '#e879f9', + fuchsia500: '#d946ef', + fuchsia600: '#c026d3', + fuchsia700: '#a21caf', + fuchsia800: '#86198f', + fuchsia900: '#701a75', + + purple50: '#faf5ff', + purple100: '#f3e8ff', + purple200: '#e9d5ff', + purple300: '#d8b4fe', + purple400: '#c084fc', + purple500: '#a855f7', + purple600: '#9333ea', + purple700: '#7e22ce', + purple800: '#6b21a8', + purple900: '#581c87', + + violet50: '#f5f3ff', + violet100: '#ede9fe', + violet200: '#ddd6fe', + violet300: '#c4b5fd', + violet400: '#a78bfa', + violet500: '#8b5cf6', + violet600: '#7c3aed', + violet700: '#6d28d9', + violet800: '#5b21b6', + violet900: '#4c1d95', + + indigo50: '#eef2ff', + indigo100: '#e0e7ff', + indigo200: '#c7d2fe', + indigo300: '#a5b4fc', + indigo400: '#818cf8', + indigo500: '#6366f1', + indigo600: '#4f46e5', + indigo700: '#4338ca', + indigo800: '#3730a3', + indigo900: '#312e81', + + blue50: '#eff6ff', + blue100: '#dbeafe', + blue200: '#bfdbfe', + blue300: '#93c5fd', + blue400: '#60a5fa', + blue500: '#3b82f6', + blue600: '#2563eb', + blue700: '#1d4ed8', + blue800: '#1e40af', + blue900: '#1e3a8a', + + lightBlue50: '#f0f9ff', + lightBlue100: '#e0f2fe', + lightBlue200: '#bae6fd', + lightBlue300: '#7dd3fc', + lightBlue400: '#38bdf8', + lightBlue500: '#0ea5e9', + lightBlue600: '#0284c7', + lightBlue700: '#0369a1', + lightBlue800: '#075985', + lightBlue900: '#0c4a6e', + + darkBlue50: '#dbf4ff', + darkBlue100: '#addbff', + darkBlue200: '#7cc2ff', + darkBlue300: '#4aa9ff', + darkBlue400: '#1a91ff', + darkBlue500: '#0077e6', + darkBlue600: '#005db4', + darkBlue700: '#004282', + darkBlue800: '#002851', + darkBlue900: '#000e21', + + cyan50: '#ecfeff', + cyan100: '#cffafe', + cyan200: '#a5f3fc', + cyan300: '#67e8f9', + cyan400: '#22d3ee', + cyan500: '#06b6d4', + cyan600: '#0891b2', + cyan700: '#0e7490', + cyan800: '#155e75', + cyan900: '#164e63', + + teal50: '#f0fdfa', + teal100: '#ccfbf1', + teal200: '#99f6e4', + teal300: '#5eead4', + teal400: '#2dd4bf', + teal500: '#14b8a6', + teal600: '#0d9488', + teal700: '#0f766e', + teal800: '#115e59', + teal900: '#134e4a', + + emerald50: '#ecfdf5', + emerald100: '#d1fae5', + emerald200: '#a7f3d0', + emerald300: '#6ee7b7', + emerald400: '#34d399', + emerald500: '#10b981', + emerald600: '#059669', + emerald700: '#047857', + emerald800: '#065f46', + emerald900: '#064e3b', + + green50: '#f0fdf4', + green100: '#dcfce7', + green200: '#bbf7d0', + green300: '#86efac', + green400: '#4ade80', + green500: '#22c55e', + green600: '#16a34a', + green700: '#15803d', + green800: '#166534', + green900: '#14532d', + + lime50: '#f7fee7', + lime100: '#ecfccb', + lime200: '#d9f99d', + lime300: '#bef264', + lime400: '#a3e635', + lime500: '#84cc16', + lime600: '#65a30d', + lime700: '#4d7c0f', + lime800: '#3f6212', + lime900: '#365314', + + yellow50: '#fefce8', + yellow100: '#fef9c3', + yellow200: '#fef08a', + yellow300: '#fde047', + yellow400: '#facc15', + yellow500: '#eab308', + yellow600: '#ca8a04', + yellow700: '#a16207', + yellow800: '#854d0e', + yellow900: '#713f12', + + amber50: '#fffbeb', + amber100: '#fef3c7', + amber200: '#fde68a', + amber300: '#fcd34d', + amber400: '#fbbf24', + amber500: '#f59e0b', + amber600: '#d97706', + amber700: '#b45309', + amber800: '#92400e', + amber900: '#78350f', + + orange50: '#fff7ed', + orange100: '#ffedd5', + orange200: '#fed7aa', + orange300: '#fdba74', + orange400: '#fb923c', + orange500: '#f97316', + orange600: '#ea580c', + orange700: '#c2410c', + orange800: '#9a3412', + orange900: '#7c2d12', + + red50: '#fef2f2', + red100: '#fee2e2', + red200: '#fecaca', + red300: '#fca5a5', + red400: '#f87171', + red500: '#ef4444', + red600: '#dc2626', + red700: '#b91c1c', + red800: '#991b1b', + red900: '#7f1d1d', + + warmGray50: '#fafaf9', + warmGray100: '#f5f5f4', + warmGray200: '#e7e5e4', + warmGray300: '#d6d3d1', + warmGray400: '#a8a29e', + warmGray500: '#78716c', + warmGray600: '#57534e', + warmGray700: '#44403c', + warmGray800: '#292524', + warmGray900: '#1c1917', + + trueGray50: '#fafafa', + trueGray100: '#f5f5f5', + trueGray200: '#e5e5e5', + trueGray300: '#d4d4d4', + trueGray400: '#a3a3a3', + trueGray500: '#737373', + trueGray600: '#525252', + trueGray700: '#404040', + trueGray800: '#262626', + trueGray900: '#171717', + + coolGray50: '#f9fafb', + coolGray100: '#f3f4f6', + coolGray200: '#e5e7eb', + coolGray300: '#d1d5db', + coolGray400: '#9ca3af', + coolGray500: '#6b7280', + coolGray600: '#4b5563', + coolGray700: '#374151', + coolGray800: '#1f2937', + coolGray900: '#111827', + + blueGray50: '#f8fafc', + blueGray100: '#f1f5f9', + blueGray200: '#e2e8f0', + blueGray300: '#cbd5e1', + blueGray400: '#94a3b8', + blueGray500: '#64748b', + blueGray600: '#475569', + blueGray700: '#334155', + blueGray800: '#1e293b', + blueGray900: '#0f172a', + }, + space: { + 'px': '1px', + '0': 0, + '0.5': 2, + '1': 4, + '1.5': 6, + '2': 8, + '2.5': 10, + '3': 12, + '3.5': 14, + '4': 16, + '4.5': 18, + '5': 20, + '6': 24, + '7': 28, + '8': 32, + '9': 36, + '10': 40, + '11': 44, + '12': 48, + '16': 64, + '20': 80, + '24': 96, + '32': 128, + '40': 160, + '48': 192, + '56': 224, + '64': 256, + '72': 288, + '80': 320, + '96': 384, + '1/2': '50%', + '1/3': '33.333%', + '2/3': '66.666%', + '1/4': '25%', + '2/4': '50%', + '3/4': '75%', + '1/5': '20%', + '2/5': '40%', + '3/5': '60%', + '4/5': '80%', + '1/6': '16.666%', + '2/6': '33.333%', + '3/6': '50%', + '4/6': '66.666%', + '5/6': '83.333%', + 'full': '100%', + }, + borderWidths: { + '0': 0, + '1': 1, + '2': 2, + '4': 4, + '8': 8, + }, + radii: { + 'none': 0, + 'xs': 2, + 'sm': 4, + 'md': 6, + 'lg': 8, + 'xl': 12, + '2xl': 16, + '3xl': 24, + 'full': 9999, + }, + breakpoints: { + base: 0, + sm: 480, + md: 768, + lg: 992, + xl: 1280, + }, + mediaQueries: { + base: '@media screen and (min-width: 0)', + xs: '@media screen and (min-width: 400px)', + sm: '@media screen and (min-width: 480px)', + md: '@media screen and (min-width: 768px)', + lg: '@media screen and (min-width: 992px)', + xl: '@media screen and (min-width: 1280px)', + }, + letterSpacings: { + 'xs': -0.4, + 'sm': -0.2, + 'md': 0, + 'lg': 0.2, + 'xl': 0.4, + '2xl': 1.6, + }, + lineHeights: { + '2xs': 16, + 'xs': 18, + 'sm': 20, + 'md': 22, + 'lg': 24, + 'xl': 28, + '2xl': 32, + '3xl': 40, + '4xl': 48, + '5xl': 56, + '6xl': 72, + '7xl': 90, + }, + fontWeights: { + hairline: '100', + thin: '200', + light: '300', + normal: '400', + medium: '500', + semibold: '600', + bold: '700', + extrabold: '800', + black: '900', + extraBlack: '950', + }, + fonts: { + heading: undefined, + body: undefined, + mono: undefined, + }, + fontSizes: { + '2xs': 10, + 'xs': 12, + 'sm': 14, + 'md': 16, + 'lg': 18, + 'xl': 20, + '2xl': 24, + '3xl': 30, + '4xl': 36, + '5xl': 48, + '6xl': 60, + '7xl': 72, + '8xl': 96, + '9xl': 128, + }, + opacity: { + 0: 0, + 5: 0.05, + 10: 0.1, + 20: 0.2, + 25: 0.25, + 30: 0.3, + 40: 0.4, + 50: 0.5, + 60: 0.6, + 70: 0.7, + 75: 0.75, + 80: 0.8, + 90: 0.9, + 95: 0.95, + 100: 1, + }, + } as const, + themes: { + dark: { + colors: { + primary0: '#828282', + primary50: '#949494', + primary100: '#9E9E9E', + primary200: '#B3B3B3', + primary300: '#C7C7C7', + primary400: '#E6E6E6', + primary500: '#F0F0F0', + primary600: '#FAFAFA', + primary700: '#FCFCFC', + primary800: '#FDFDFD', + primary900: '#FDFCFC', + primary950: '#FDFCFC', + + secondary0: '#0B0C0C', + secondary50: '#181717', + secondary100: '#272626', + secondary200: '#3F4040', + secondary300: '#515252', + secondary400: '#5E5F5F', + secondary500: '#727373', + secondary600: '#AFB0B0', + secondary700: '#DBDBDB', + secondary800: '#E7E8E8', + secondary900: '#F1F2F2', + secondary950: '#FEFFFF', + + tertiary0: '#543112', + tertiary50: '#6C3D13', + tertiary100: '#824917', + tertiary200: '#B4621A', + tertiary300: '#D7751F', + tertiary400: '#E78128', + tertiary500: '#FB9D4B', + tertiary600: '#FDB474', + tertiary700: '#FED1AA', + tertiary800: '#FFE9D5', + tertiary900: '#FFF2E5', + tertiary950: '#FFFAF5', + + text0: '#171717', + text50: '#262627', + text100: '#404040', + text200: '#525252', + text300: '#737373', + text400: '#8C8C8C', + text500: '#A3A3A3', + text600: '#D4D4D4', + text700: '#DBDBDC', + text800: '#E5E5E5', + text900: '#F5F5F5', + text950: '#FEFEFF', + + background0: '#121212', + background50: '#272625', + background100: '#414040', + background200: '#535252', + background300: '#747474', + background400: '#8E8E8E', + background500: '#A2A3A3', + background600: '#D5D4D4', + background700: '#DCDBDB', + background800: '#F2F1F1', + background900: '#F6F6F6', + background950: '#252526', + + border0: '#1A1717', + border50: '#272624', + border100: '#414141', + border200: '#535252', + border300: '#737474', + border400: '#8C8D8D', + border500: '#A5A3A3', + border600: '#D3D3D3', + border700: '#DDDCDB', + border800: '#E6E6E6', + border900: '#F3F3F3', + border950: '#FDFEFE', + + success0: '#1B3224', + success50: '#14532D', + success100: '#166534', + success200: '#206F3E', + success300: '#2A7948', + success400: '#348352', + success500: '#489766', + success600: '#66B584', + success700: '#84D3A2', + success800: '#A2F1C0', + success900: '#CAFFE8', + success950: '#E4FFF4', + + error0: '#531313', + error50: '#7F1D1D', + error100: '#991B1B', + error200: '#B91C1C', + error300: '#DC2626', + error400: '#E63535', + error500: '#EF4444', + error600: '#F87171', + error700: '#E63534', + error800: '#FECACA', + error900: '#FEE2E2', + error950: '#FEE9E9', + + warning0: '#542D12', + warning50: '#6C3813', + warning100: '#824417', + warning200: '#B45A1A', + warning300: '#D76C1F', + warning400: '#E77828', + warning500: '#FB954B', + warning600: '#FDAD74', + warning700: '#FECDAA', + warning800: '#FFE7D5', + warning900: '#FFF9F5', + warning950: '#FFFDFB', + + info0: '#032638', + info50: '#05405D', + info100: '#075A83', + info200: '#0973A8', + info300: '#0B8DCD', + info400: '#0DA6F2', + info500: '#32B4F4', + info600: '#57C2F6', + info700: '#7CCFF8', + info800: '#A2DDFA', + info900: '#C7EBFC', + info950: '#ECF8FE', + + backgroundError: '#422B2B', + backgroundWarning: '#412F23', + backgroundSuccess: '#1C2B21', + backgroundMuted: '#252526', + backgroundInfo: '#1A282E', + }, + }, + }, + globalStyle: { + variants: { + hardShadow: { + '1': { + shadowColor: '$background900', + shadowOffset: { + width: -2, + height: 2, + }, + shadowRadius: 8, + shadowOpacity: 0.5, + elevation: 10, + }, + '2': { + shadowColor: '$background900', + shadowOffset: { + width: 0, + height: 3, + }, + shadowRadius: 8, + shadowOpacity: 0.5, + elevation: 10, + }, + '3': { + shadowColor: '$background900', + shadowOffset: { + width: 2, + height: 2, + }, + shadowRadius: 8, + shadowOpacity: 0.5, + elevation: 10, + }, + '4': { + shadowColor: '$background900', + shadowOffset: { + width: 0, + height: -3, + }, + shadowRadius: 8, + shadowOpacity: 0.5, + elevation: 10, + }, + // this 5th version is only for toast shadow + // temporary + '5': { + shadowColor: '$background900', + shadowOffset: { + width: 0, + height: 3, + }, + shadowRadius: 8, + shadowOpacity: 0.2, + elevation: 10, + }, + }, + softShadow: { + '1': { + shadowColor: '$background900', + shadowOffset: { + width: 0, + height: 0, + }, + shadowRadius: 10, + shadowOpacity: 0.1, + _android: { + shadowColor: '$background500', + elevation: 5, + shadowOpacity: 0.05, + }, + }, + '2': { + shadowColor: '$background900', + shadowOffset: { + width: 0, + height: 0, + }, + shadowRadius: 20, + elevation: 3, + shadowOpacity: 0.1, + _android: { + shadowColor: '$background500', + elevation: 10, + shadowOpacity: 0.1, + }, + }, + '3': { + shadowColor: '$background900', + shadowOffset: { + width: 0, + height: 0, + }, + shadowRadius: 30, + shadowOpacity: 0.1, + elevation: 4, + _android: { + shadowColor: '$background500', + elevation: 15, + shadowOpacity: 0.15, + }, + }, + '4': { + shadowColor: '$background900', + shadowOffset: { + width: 0, + height: 0, + }, + shadowRadius: 40, + shadowOpacity: 0.1, + elevation: 10, + _android: { + shadowColor: '$background500', + elevation: 20, + shadowOpacity: 0.2, + }, + }, + }, + }, + }, + plugins: [new AnimationResolver(MotionAnimationDriver)], +}); + +type Config = typeof gluestackUIConfig; // Assuming `config` is defined elsewhere + +export interface IConfig {} +export interface IComponents {} + +declare module '@gluestack-style/react' { + interface UIConfig extends Omit, IConfig {} +} + +export const config = { + ...gluestackUIConfig, +}; diff --git a/example/storybook-nativewind/src/components-example/themed/GluestackUIProvider/index.tsx b/example/storybook-nativewind/src/components-example/themed/GluestackUIProvider/index.tsx new file mode 100644 index 0000000000..3c66799716 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/GluestackUIProvider/index.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { createProvider } from '@gluestack-ui/provider'; +import { StyledProvider } from '@gluestack-style/react'; +import { OverlayProvider } from '@gluestack-ui/overlay'; +import { ToastProvider } from '@gluestack-ui/toast'; + +// Change the config file path +import { config } from './config'; + +const GluestackUIStyledProvider = createProvider({ StyledProvider }); + +type GluestackUIProviderProps = Partial< + React.ComponentProps +>; + +export const GluestackUIProvider = ({ + children, + ...props +}: GluestackUIProviderProps) => { + return ( + <> + {/** @ts-ignore */} + + + {children} + + + + ); +}; diff --git a/example/storybook-nativewind/src/components-example/themed/HStack/index.tsx b/example/storybook-nativewind/src/components-example/themed/HStack/index.tsx new file mode 100644 index 0000000000..b485e0fec7 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/HStack/index.tsx @@ -0,0 +1,42 @@ +import { View } from 'react-native'; + +import { styled } from '@gluestack-style/react'; + +const StyledRoot = styled(View, { + flexDirection: 'row', + variants: { + space: { + 'xs': { + gap: `$1`, + }, + 'sm': { + gap: `$2`, + }, + 'md': { + gap: `$3`, + }, + 'lg': { + gap: `$4`, + }, + 'xl': { + gap: `$5`, + }, + '2xl': { + gap: `$6`, + }, + '3xl': { + gap: `$7`, + }, + '4xl': { + gap: `$8`, + }, + }, + reversed: { + true: { + flexDirection: 'row-reverse', + }, + }, + }, +}); + +export const HStack = StyledRoot; diff --git a/example/storybook-nativewind/src/components-example/themed/Heading/index.tsx b/example/storybook-nativewind/src/components-example/themed/Heading/index.tsx new file mode 100644 index 0000000000..43b54c696f --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Heading/index.tsx @@ -0,0 +1,114 @@ +import { styled } from '@gluestack-style/react'; +import { H1, H2, H3, H4, H5, H6 } from '@expo/html-elements'; + +const StyledRoot = styled(H4, { + color: '$text900', + letterSpacing: '$sm', + fontWeight: '$bold', + fontFamily: '$heading', + + // Overrides expo-html default styling + marginVertical: 0, + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '5xl': { + //@ts-ignore + props: { as: H1 }, + fontSize: '$6xl', + }, + '4xl': { + //@ts-ignore + props: { as: H1 }, + fontSize: '$5xl', + }, + + '3xl': { + //@ts-ignore + props: { as: H1 }, + fontSize: '$4xl', + }, + + '2xl': { + //@ts-ignore + props: { as: H2 }, + fontSize: '$3xl', + }, + + 'xl': { + //@ts-ignore + props: { as: H3 }, + fontSize: '$2xl', + }, + + 'lg': { + //@ts-ignore + props: { as: H4 }, + fontSize: '$xl', + }, + + 'md': { + //@ts-ignore + props: { as: H5 }, + fontSize: '$lg', + }, + + 'sm': { + //@ts-ignore + props: { as: H6 }, + fontSize: '$md', + }, + + 'xs': { + //@ts-ignore + props: { as: H6 }, + fontSize: '$sm', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + defaultProps: { + size: 'lg', + }, +}); + +export const Heading = StyledRoot; diff --git a/example/storybook-nativewind/src/components-example/themed/Icon/index.tsx b/example/storybook-nativewind/src/components-example/themed/Icon/index.tsx new file mode 100644 index 0000000000..d659a161da --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Icon/index.tsx @@ -0,0 +1,1801 @@ +import React from 'react'; +import { createIcon } from '@gluestack-ui/icon'; +import { styled, AsForwarder } from '@gluestack-style/react'; +import { Path } from 'react-native-svg'; + +const StyledRoot = styled( + AsForwarder, + { + color: '$background800', + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + props: { + size: 'md', + // @ts-ignore + fill: 'none', + }, + }, + { + componentName: 'BaseIcon', + resolveProps: ['stroke', 'fill'], + } as const, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); +const IconRoot = styled( + AsForwarder, + { + color: '$background800', + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + + props: { + size: 'md', + //@ts-ignore + fill: 'none', + }, + }, + { + resolveProps: ['stroke', 'fill'], + } as const, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); +export const Icon = createIcon({ + Root: StyledRoot, +}); + +type ParameterTypes = Omit[0], 'Root'>; +const createIconUI = ({ ...props }: ParameterTypes) => + createIcon({ Root: IconRoot, ...props }); + +export { createIconUI as createIcon }; + +// All Icons +const AddIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +AddIcon.displayName = 'AddIcon'; +export { AddIcon }; + +export const AlertCircleIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +AlertCircleIcon.displayName = 'AlertCircleIcon'; + +const ArrowUpIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowDownIcon = createIcon({ + Root: StyledRoot, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowRightIcon = createIcon({ + Root: StyledRoot, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowLeftIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +// const ArrowTopRightIcon = createIcon({ +// Root: StyledRoot, +// viewBox: '0 0 24 24', +// path: ( +// +// ), +// }); + +ArrowUpIcon.displayName = 'ArrowUpIcon'; +ArrowDownIcon.displayName = 'ArrowDownIcon'; +ArrowRightIcon.displayName = 'ArrowRightIcon'; +ArrowLeftIcon.displayName = 'ArrowLeftIcon'; +// ArrowTopRightIcon.displayName = 'ArrowTopRightIcon'; + +export { + ArrowUpIcon, + ArrowDownIcon, + ArrowRightIcon, + ArrowLeftIcon, + // ArrowTopRightIcon, +}; + +const AtSignIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + <> + + + + + ), +}); + +AtSignIcon.displayName = 'AtSignIcon'; + +export { AtSignIcon }; + +const BellIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +BellIcon.displayName = 'BellIcon'; + +export { BellIcon }; + +const CalendarDaysIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + + ), +}); + +CalendarDaysIcon.displayName = 'CalendarDaysIcon'; + +export { CalendarDaysIcon }; + +const CheckIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const CheckCircleIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CheckIcon.displayName = 'CheckIcon'; +CheckCircleIcon.displayName = 'CheckCircleIcon'; + +export { CheckIcon, CheckCircleIcon }; + +const ChevronUpIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + d: 'M12 10L8 6L4 10', + path: ( + <> + + + ), +}); + +const ChevronDownIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronLeftIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronRightIcon = createIcon({ + Root: StyledRoot, + + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronsLeftIcon = createIcon({ + Root: StyledRoot, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsRightIcon = createIcon({ + Root: StyledRoot, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsUpDownIcon = createIcon({ + Root: StyledRoot, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ChevronUpIcon.displayName = 'ChevronUpIcon'; +ChevronDownIcon.displayName = 'ChevronDownIcon'; +ChevronLeftIcon.displayName = 'ChevronLeftIcon'; +ChevronRightIcon.displayName = 'ChevronRightIcon'; +ChevronsLeftIcon.displayName = 'ChevronsLeftIcon'; +ChevronsRightIcon.displayName = 'ChevronsRightIcon'; +ChevronsUpDownIcon.displayName = 'ChevronsUpDownIcon'; + +export { + ChevronUpIcon, + ChevronDownIcon, + ChevronLeftIcon, + ChevronRightIcon, + ChevronsLeftIcon, + ChevronsRightIcon, + ChevronsUpDownIcon, +}; + +const CircleIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +CircleIcon.displayName = 'CircleIcon'; + +export { CircleIcon }; + +const ClockIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ClockIcon.displayName = 'ClockIcon'; + +export { ClockIcon }; + +const CloseIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const CloseCircleIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +CloseIcon.displayName = 'CloseIcon'; +CloseCircleIcon.displayName = 'CloseCircleIcon'; + +export { CloseIcon, CloseCircleIcon }; + +const CopyIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CopyIcon.displayName = 'CopyIcon'; + +export { CopyIcon }; + +const DownloadIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +DownloadIcon.displayName = 'DownloadIcon'; + +export { DownloadIcon }; + +const EditIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EditIcon.displayName = 'EditIcon'; + +export { EditIcon }; + +const EyeIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EyeIcon.displayName = 'EyeIcon'; + +const EyeOffIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +EyeOffIcon.displayName = 'EyeOffIcon'; + +export { EyeIcon, EyeOffIcon }; + +const FavouriteIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +FavouriteIcon.displayName = 'FavouriteIcon'; + +export { FavouriteIcon }; + +const GlobeIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +GlobeIcon.displayName = 'GlobeIcon'; + +export { GlobeIcon }; + +const GripVerticalIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + ), +}); + +GripVerticalIcon.displayName = 'GripVerticalIcon'; + +export { GripVerticalIcon }; + +export const HelpCircleIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +HelpCircleIcon.displayName = 'HelpCircleIcon'; + +export const InfoIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +InfoIcon.displayName = 'InfoIcon'; + +const LinkIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); +LinkIcon.displayName = 'LinkIcon'; + +const ExternalLinkIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ExternalLinkIcon.displayName = 'ExternalLinkIcon'; + +export { LinkIcon, ExternalLinkIcon }; + +const LoaderIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +LoaderIcon.displayName = 'LoaderIcon'; + +export { LoaderIcon }; + +const LockIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +LockIcon.displayName = 'LockIcon'; + +export { LockIcon }; + +const MailIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +MailIcon.displayName = 'MailIcon'; + +export { MailIcon }; + +export const MenuIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +MenuIcon.displayName = 'MenuIcon'; + +const MessageCircleIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MessageCircleIcon.displayName = 'MessageCircleIcon'; + +export { MessageCircleIcon }; + +export const MoonIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MoonIcon.displayName = 'MoonIcon'; + +const PaperclipIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PaperclipIcon.displayName = 'PaperclipIcon'; + +export { PaperclipIcon }; + +const PhoneIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PhoneIcon.displayName = 'PhoneIcon'; + +export { PhoneIcon }; + +const PlayIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +PlayIcon.displayName = 'PlayIcon'; + +export { PlayIcon }; + +export const RemoveIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +RemoveIcon.displayName = 'RemoveIcon'; + +const RepeatIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +RepeatIcon.displayName = 'RepeatIcon'; + +const Repeat1Icon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +Repeat1Icon.displayName = 'Repeat1Icon'; + +export { RepeatIcon, Repeat1Icon }; + +export const SearchIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SearchIcon.displayName = 'SearchIcon'; + +const SettingsIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SettingsIcon.displayName = 'SettingsIcon'; + +export { SettingsIcon }; + +const ShareIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +ShareIcon.displayName = 'ShareIcon'; + +export { ShareIcon }; + +const SlashIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SlashIcon.displayName = 'SlashIcon'; + +export { SlashIcon }; + +const StarIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +StarIcon.displayName = 'StarIcon'; + +export { StarIcon }; + +export const SunIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + ), +}); + +SunIcon.displayName = 'SunIcon'; + +const ThreeDotsIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ThreeDotsIcon.displayName = 'ThreeDotsIcon'; + +export { ThreeDotsIcon }; + +const TrashIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +TrashIcon.displayName = 'TrashIcon'; + +export { TrashIcon }; + +const UnlockIcon = createIcon({ + Root: StyledRoot, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +UnlockIcon.displayName = 'UnlockIcon'; + +export { UnlockIcon }; diff --git a/example/storybook-nativewind/src/components-example/themed/Image/index.tsx b/example/storybook-nativewind/src/components-example/themed/Image/index.tsx new file mode 100644 index 0000000000..175fa5af3a --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Image/index.tsx @@ -0,0 +1,57 @@ +import { createImage } from '@gluestack-ui/image'; +import { Image as RNImage } from 'react-native'; +import { styled } from '@gluestack-style/react'; + +const StyledRoot = styled( + RNImage, + { + maxWidth: '$full', + variants: { + size: { + '2xs': { + w: '$6', + h: '$6', + }, + + 'xs': { + w: '$10', + h: '$10', + }, + + 'sm': { + w: '$16', + h: '$16', + }, + + 'md': { + w: '$20', + h: '$20', + }, + + 'lg': { + w: '$24', + h: '$24', + }, + + 'xl': { + w: '$32', + h: '$32', + }, + + '2xl': { + w: '$64', + h: '$64', + }, + 'full': { + w: '$full', + h: '$full', + }, + }, + }, + defaultProps: { + size: 'md', + }, + }, + {} +); +export const Image = createImage({ Root: StyledRoot }); diff --git a/example/storybook-nativewind/src/components-example/themed/ImageBackground/index.tsx b/example/storybook-nativewind/src/components-example/themed/ImageBackground/index.tsx new file mode 100644 index 0000000000..2da5eec5ca --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/ImageBackground/index.tsx @@ -0,0 +1,4 @@ +import { styled } from '@gluestack-style/react'; +import { ImageBackground as RNImageBackground } from 'react-native'; + +export const ImageBackground = styled(RNImageBackground, {}); diff --git a/example/storybook-nativewind/src/components-example/themed/Input/index.tsx b/example/storybook-nativewind/src/components-example/themed/Input/index.tsx new file mode 100644 index 0000000000..b940b0c5bc --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Input/index.tsx @@ -0,0 +1,427 @@ +import { createInput } from '@gluestack-ui/input'; +import { styled, AsForwarder } from '@gluestack-style/react'; +import { View, Pressable, TextInput } from 'react-native'; + +const StyledRoot = styled( + View, + { + 'borderWidth': 1, + 'borderColor': '$background300', + 'borderRadius': '$sm', + 'flexDirection': 'row', + 'overflow': 'hidden', + 'alignContent': 'center', + + ':hover': { + borderColor: '$border400', + }, + + ':focus': { + 'borderColor': '$primary700', + ':hover': { + borderColor: '$primary700', + }, + }, + + ':disabled': { + 'opacity': 0.4, + ':hover': { + borderColor: '$background300', + }, + }, + + '_input': { + py: 'auto', + px: '$3', + }, + + '_icon': { + color: '$text400', + }, + + 'variants': { + size: { + xl: { + h: '$12', + _input: { + props: { + size: 'xl', + }, + }, + _icon: { + props: { + size: 'xl', + }, + }, + }, + lg: { + h: '$11', + _input: { + props: { + size: 'lg', + }, + }, + _icon: { + props: { + size: 'lg', + }, + }, + }, + md: { + h: '$10', + _input: { + props: { + size: 'md', + }, + }, + _icon: { + props: { + size: 'sm', + }, + }, + }, + sm: { + h: '$9', + _input: { + props: { + size: 'sm', + }, + }, + _icon: { + props: { + size: 'xs', + }, + }, + }, + }, + variant: { + underlined: { + '_input': { + _web: { + outlineWidth: 0, + outline: 'none', + }, + px: '$0', + }, + + 'borderWidth': 0, + 'borderRadius': 0, + 'borderBottomWidth': '$1', + + ':focus': { + borderColor: '$primary700', + _web: { + boxShadow: 'inset 0 -1px 0 0 $primary700', + }, + }, + + ':invalid': { + 'borderBottomWidth': 2, + 'borderBottomColor': '$error700', + '_web': { + boxShadow: 'inset 0 -1px 0 0 $error700', + }, + ':hover': { + borderBottomColor: '$error700', + }, + ':focus': { + 'borderBottomColor': '$error700', + ':hover': { + borderBottomColor: '$error700', + _web: { + boxShadow: 'inset 0 -1px 0 0 $error700', + }, + }, + }, + ':disabled': { + ':hover': { + borderBottomColor: '$error700', + _web: { + boxShadow: 'inset 0 -1px 0 0 $error700', + }, + }, + }, + }, + }, + + outline: { + '_input': { + _web: { + outlineWidth: 0, + outline: 'none', + }, + }, + + ':focus': { + borderColor: '$primary700', + _web: { + boxShadow: 'inset 0 0 0 1px $primary700', + }, + }, + + ':invalid': { + 'borderColor': '$error700', + '_web': { + boxShadow: 'inset 0 0 0 1px $error700', + }, + ':hover': { + borderColor: '$error700', + }, + ':focus': { + 'borderColor': '$error700', + ':hover': { + borderColor: '$error700', + _web: { + boxShadow: 'inset 0 0 0 1px $error700', + }, + }, + }, + ':disabled': { + ':hover': { + borderColor: '$error700', + _web: { + boxShadow: 'inset 0 0 0 1px $error700', + }, + }, + }, + }, + }, + + rounded: { + 'borderRadius': 999, + + '_input': { + px: '$4', + _web: { + outlineWidth: 0, + outline: 'none', + }, + }, + + ':focus': { + borderColor: '$primary700', + _web: { + boxShadow: 'inset 0 0 0 1px $primary700', + }, + }, + + ':invalid': { + 'borderColor': '$error700', + '_web': { + boxShadow: 'inset 0 0 0 1px $error700', + }, + ':hover': { + borderColor: '$error700', + }, + ':focus': { + 'borderColor': '$error700', + ':hover': { + borderColor: '$error700', + _web: { + boxShadow: 'inset 0 0 0 1px $error700', + }, + }, + }, + ':disabled': { + ':hover': { + borderColor: '$error700', + _web: { + boxShadow: 'inset 0 0 0 1px $error700', + }, + }, + }, + }, + }, + }, + }, + + 'defaultProps': { + size: 'md', + variant: 'outline', + }, + }, + { + descendantStyle: ['_input', '_icon'], + } +); + +const StyledIcon = styled( + AsForwarder, + { + color: '$background800', + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + props: { + size: 'md', + // @ts-ignore + fill: 'none', + }, + }, + { + resolveProps: ['stroke', 'fill'], + ancestorStyle: ['_icon'], + }, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); + +const StyledSlot = styled( + Pressable, + { + justifyContent: 'center', + alignItems: 'center', + _web: { + ':disabled': { + cursor: 'not-allowed', + }, + }, + }, + { + descendantStyle: ['_icon'], + } +); + +const StyledInputField = styled( + TextInput, + { + flex: 1, + color: '$text900', + + props: { + placeholderTextColor: '$text500', + }, + + _web: { + 'cursor': 'text', + ':disabled': { + cursor: 'not-allowed', + }, + }, + + variants: { + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + }, + }, + { + ancestorStyle: ['_input'], + resolveProps: ['placeholderTextColor'], + }, + { + propertyTokenMap: { + placeholderTextColor: 'colors', + }, + } +); +const UIInput = createInput({ + Root: StyledRoot, + Icon: StyledIcon, + Slot: StyledSlot, + Input: StyledInputField, +}); + +export const Input = UIInput; +export const InputIcon = UIInput.Icon; +export const InputSlot = UIInput.Slot; +export const InputField = UIInput.Input; + +/** + * @deprecated Use InputField instead. + */ +export const InputInput = UIInput.Input; diff --git a/example/storybook-nativewind/src/components-example/themed/InputAccessoryView/index.tsx b/example/storybook-nativewind/src/components-example/themed/InputAccessoryView/index.tsx new file mode 100644 index 0000000000..b1bf65a60d --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/InputAccessoryView/index.tsx @@ -0,0 +1,6 @@ +import { styled } from '@gluestack-style/react'; +import { InputAccessoryView as RNInputAccessoryView } from 'react-native'; + +const StyledRoot = styled(RNInputAccessoryView, {}, {}); + +export const InputAccessoryView = StyledRoot; diff --git a/example/storybook-nativewind/src/components-example/themed/KeyboardAvoidingView/index.tsx b/example/storybook-nativewind/src/components-example/themed/KeyboardAvoidingView/index.tsx new file mode 100644 index 0000000000..380c641bda --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/KeyboardAvoidingView/index.tsx @@ -0,0 +1,34 @@ +import { styled, useStyled } from '@gluestack-style/react'; +import { KeyboardAvoidingView as RNKeyboardAvoidingView } from 'react-native'; + +export const KeyboardAvoidingView = styled( + RNKeyboardAvoidingView, + {}, + { + componentName: 'KeyboardAvoidingView', + resolveProps: ['contentContainerStyle'], + } as const, + { + propertyResolver: { + contentContainerStyle: (rawValue, resolver) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const aliases = useStyled()?.config?.aliases; + const newValue = {} as Record; + Object.entries(rawValue).forEach(([key, value]) => { + if (Object.hasOwn(aliases, key)) { + newValue[`${aliases[key]}`] = resolver( + value, + //@ts-ignore + propertyTokenMap[aliases[key]] + ); + } else { + //@ts-ignore + newValue[`${key}`] = resolver(value, propertyTokenMap[key]); + } + }); + rawValue = newValue; + return rawValue; + }, + }, + } +); diff --git a/example/storybook-nativewind/src/components-example/themed/LinearGradient/index.tsx b/example/storybook-nativewind/src/components-example/themed/LinearGradient/index.tsx new file mode 100644 index 0000000000..91aee59bb3 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/LinearGradient/index.tsx @@ -0,0 +1,24 @@ +import { styled } from '@gluestack-style/react'; +import { View } from 'react-native'; + +export const LinearGradient = styled( + View, + {}, + { + componentName: 'LinearGradient', + resolveProps: ['colors'], + } as const, + { + propertyTokenMap: { + colors: 'colors', + }, + propertyResolver: { + colors: (rawValue: any, resolver: any) => { + rawValue.forEach((color: any, index: number) => { + rawValue[index] = resolver(color); + }); + return rawValue; + }, + }, + } +); diff --git a/example/storybook-nativewind/src/components-example/themed/Link/index.tsx b/example/storybook-nativewind/src/components-example/themed/Link/index.tsx new file mode 100644 index 0000000000..f95f84ce27 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Link/index.tsx @@ -0,0 +1,54 @@ +import { styled } from '@gluestack-style/react'; +import { createLink } from '@gluestack-ui/link'; +import { Pressable, Text } from 'react-native'; + +const StyledRoot = styled( + Pressable, + { + _web: { + 'outlineWidth': 0, + ':disabled': { + cursor: 'not-allowed', + }, + ':focusVisible': { + outlineWidth: 2, + outlineColor: '$primary700', + outlineStyle: 'solid', + }, + }, + _text: { + ':hover': { + color: '$info600', + textDecorationLine: 'none', + }, + + ':active': { + color: '$info700', + }, + + ':disabled': { + opacity: 0.4, + }, + }, + }, + { + componentName: 'Link', + } as const +); + +const StyledText = styled( + Text, + { + textDecorationLine: 'underline', + color: '$info700', + }, + { + ancestorStyle: ['_text'], + } as const +); + +export const Link = createLink({ + Root: StyledRoot, + Text: StyledText, +}); +export const LinkText = Link.Text; diff --git a/example/storybook-nativewind/src/components-example/themed/Menu/index.tsx b/example/storybook-nativewind/src/components-example/themed/Menu/index.tsx new file mode 100644 index 0000000000..38c34fffa4 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Menu/index.tsx @@ -0,0 +1,222 @@ +import { AnimatePresence } from '@gluestack-style/animation-resolver'; +import { createMenu } from '@gluestack-ui/menu'; +import { styled } from '@gluestack-style/react'; +import { AnimatedView } from '@gluestack-style/animation-resolver'; +import { Pressable, Text } from 'react-native'; + +const StyledRoot = styled( + AnimatedView, + { + ':initial': { + opacity: 0, + }, + + ':animate': { + opacity: 1, + }, + + ':exit': { + opacity: 0, + }, + + ':transition': { + type: 'spring', + damping: 18, + stiffness: 250, + // @ts-ignore + opacity: { + type: 'timing', + duration: 200, + }, + }, + + 'minWidth': 200, + 'py': '$2', + 'rounded': '$sm', + 'bg': '$background0', + + 'defaultProps': { + softShadow: '3', + }, + }, + {} +); + +const StyledItem = styled( + Pressable, + { + 'p': '$3', + 'flexDirection': 'row', + 'alignItems': 'center', + + ':hover': { + bg: '$background100', + }, + + ':disabled': { + 'opacity': 0.4, + + '_web': { + cursor: 'not-allowed', + }, + + ':focus': { + bg: 'transparent', + }, + }, + + ':active': { + bg: '$background200', + }, + + ':focus': { + bg: '$background100', + // @ts-ignore + outlineWidth: '$0', + outlineStyle: 'none', + }, + + ':focusVisible': { + // @ts-ignore + outlineWidth: '$0.5', + + outlineColor: '$primary700', + outlineStyle: 'solid', + }, + + '_web': { + cursor: 'pointer', + }, + }, + { descendantStyle: ['_text'] } +); + +const StyledBackdrop = styled( + Pressable, + { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + // use this for when you want to give background colour to backdrop + // opacity: 0.5, + // bg: '$background500', + _web: { + cursor: 'default', + }, + }, + {} +); + +const StyledLabel = styled( + Text, + { + color: '$text700', + fontWeight: '$normal', + fontFamily: '$body', + fontStyle: 'normal', + letterSpacing: '$md', + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + defaultProps: { + size: 'md', + }, + }, + { ancestorStyle: ['_text'] } +); +export const Menu = createMenu({ + Root: StyledRoot, + Item: StyledItem, + Label: StyledLabel, + Backdrop: StyledBackdrop, + //@ts-ignore + AnimatePresence: AnimatePresence, +}); +export const MenuItem = Menu.Item; +export const MenuItemLabel = Menu.ItemLabel; diff --git a/example/storybook-nativewind/src/components-example/themed/Modal/index.tsx b/example/storybook-nativewind/src/components-example/themed/Modal/index.tsx new file mode 100644 index 0000000000..cdca1e5dfc --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Modal/index.tsx @@ -0,0 +1,214 @@ +import { createModal } from '@gluestack-ui/modal'; +import { + AnimatePresence, + AnimatedPressable, + AnimatedView, +} from '@gluestack-style/animation-resolver'; +import { Pressable, View, ScrollView } from 'react-native'; + +import { styled } from '@gluestack-style/react'; + +const StyledRoot = styled( + View, + { + 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'], + } +); +const StyledBackdrop = styled( + AnimatedPressable, + { + ':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', + }, + }, + {} +); +const StyledContent = styled( + AnimatedView, + { + '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'] } +); +const StyledBody = styled( + ScrollView, + { px: '$4', paddingTop: 0, paddingBottom: '$2' }, + {} +); +const StyledCloseButton = styled( + Pressable, + { + 'zIndex': 1, + 'p': '$2', + 'rounded': '$sm', + + '_icon': { + color: '$background400', + }, + + '_text': { + color: '$background400', + }, + + ':hover': { + _icon: { + color: '$background700', + }, + _text: { + color: '$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'] } +); +const StyledFooter = styled( + View, + { + p: '$4', + flexDirection: 'row', + justifyContent: 'flex-end', + alignItems: 'center', + flexWrap: 'wrap', + }, + {} +); +const StyledHeader = styled( + View, + { + px: '$4', + paddingTop: '$4', + paddingBottom: '$2', + justifyContent: 'space-between', + alignItems: 'center', + flexDirection: 'row', + }, + {} +); + +const UIModal = createModal({ + Root: StyledRoot, + Backdrop: StyledBackdrop, + Content: StyledContent, + Body: StyledBody, + CloseButton: StyledCloseButton, + Footer: StyledFooter, + Header: StyledHeader, + AnimatePresence: AnimatePresence, // TODO: Add support for this +}); + +export const Modal = UIModal; +export const ModalBackdrop = UIModal.Backdrop; +export const ModalContent = UIModal.Content; +export const ModalCloseButton = UIModal.CloseButton; +export const ModalHeader = UIModal.Header; +export const ModalBody = UIModal.Body; +export const ModalFooter = UIModal.Footer; diff --git a/example/storybook-nativewind/src/components-example/themed/Popover/index.tsx b/example/storybook-nativewind/src/components-example/themed/Popover/index.tsx new file mode 100644 index 0000000000..b556ae780f --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Popover/index.tsx @@ -0,0 +1,214 @@ +import { View, ScrollView, Pressable } from 'react-native'; +import { styled } from '@gluestack-style/react'; +import { + AnimatedView, + AnimatedPressable, + AnimatePresence, +} from '@gluestack-style/animation-resolver'; +import { createPopover } from '@gluestack-ui/popover'; + +const StyledRoot = styled( + View, + { + 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'], + } +); + +const StyledArrow = styled(AnimatedView, {}); + +const StyledBackdrop = styled(AnimatedPressable, { + ':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', + }, +}); + +const StyledBody = styled(ScrollView, { + p: '$4', + pt: '$2', +}); + +const StyledCloseButton = styled( + Pressable, + { + 'zIndex': 1, + 'p': '$2', + 'rounded': '$sm', + + '_icon': { + color: '$background400', + }, + + '_text': { + color: '$background400', + }, + + ':hover': { + _icon: { + color: '$background700', + }, + _text: { + color: '$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'], + } +); + +const StyledContent = styled( + AnimatedView, + { + 'bg': '$background50', + 'rounded': '$lg', + 'overflow': 'hidden', + + ':initial': { + opacity: 0, + }, + + ':animate': { + opacity: 1, + }, + + ':exit': { + opacity: 0, + }, + + ':transition': { + type: 'spring', + damping: 18, + stiffness: 250, + // @ts-ignore + opacity: { + type: 'timing', + duration: 250, + }, + }, + + 'defaultProps': { + softShadow: '3', + }, + }, + { + ancestorStyle: ['_content'], + } +); + +const StyledFooter = styled(View, { + p: '$4', + flexDirection: 'row', + justifyContent: 'flex-end', + alignItems: 'center', + flexWrap: 'wrap', + borderTopWidth: 1, + borderColor: '$border300', +}); + +const StyledHeader = styled(View, { + p: '$4', + pb: '$2', + justifyContent: 'space-between', + alignItems: 'center', + flexDirection: 'row', +}); + +const UIPopover = createPopover({ + Root: StyledRoot, + Arrow: StyledArrow, + Content: StyledContent, + Header: StyledHeader, + Footer: StyledFooter, + Body: StyledBody, + Backdrop: StyledBackdrop, + CloseButton: StyledCloseButton, + //@ts-ignore + AnimatePresence: AnimatePresence, +}); + +export const Popover = UIPopover; +export const PopoverArrow = UIPopover.Arrow; +export const PopoverContent = UIPopover.Content; +export const PopoverHeader = UIPopover.Header; +export const PopoverFooter = UIPopover.Footer; +export const PopoverBody = UIPopover.Body; +export const PopoverBackdrop = UIPopover.Backdrop; +export const PopoverCloseButton = UIPopover.CloseButton; diff --git a/example/storybook-nativewind/src/components-example/themed/Pressable/index.tsx b/example/storybook-nativewind/src/components-example/themed/Pressable/index.tsx new file mode 100644 index 0000000000..8170b28003 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Pressable/index.tsx @@ -0,0 +1,12 @@ +import { styled } from '@gluestack-style/react'; +import { Pressable as RNPressable } from 'react-native'; + +export const Pressable = styled(RNPressable, { + _web: { + ':focusVisible': { + outlineWidth: '2px', + outlineColor: '$primary700', + outlineStyle: 'solid', + }, + }, +}); diff --git a/example/storybook-nativewind/src/components-example/themed/Progress/index.tsx b/example/storybook-nativewind/src/components-example/themed/Progress/index.tsx new file mode 100644 index 0000000000..9c0fe8c862 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Progress/index.tsx @@ -0,0 +1,76 @@ +import { styled } from '@gluestack-style/react'; +import { createProgress } from '@gluestack-ui/progress'; +import { View } from 'react-native'; +const StyledRoot = styled( + View, + { + bg: '$background300', + borderRadius: '$full', + w: '100%', + + variants: { + size: { + 'xs': { + h: '$1', + _filledTrack: { + h: '$1', + }, + }, + 'sm': { + h: '$2', + _filledTrack: { + h: '$2', + }, + }, + 'md': { + h: '$3', + _filledTrack: { + h: '$3', + }, + }, + 'lg': { + h: '$4', + _filledTrack: { + h: '$4', + }, + }, + 'xl': { + h: '$5', + _filledTrack: { + h: '$5', + }, + }, + '2xl': { + h: '$6', + _filledTrack: { + h: '$6', + }, + }, + }, + }, + + defaultProps: { + size: 'md', + }, + }, + { + descendantStyle: ['_filledTrack'], + } +); + +const StyledFilledTrack = styled( + View, + { + bg: '$primary500', + borderRadius: '$full', + }, + { + ancestorStyle: ['_filledTrack'], + } +); + +export const Progress = createProgress({ + Root: StyledRoot, + FilledTrack: StyledFilledTrack, +}); +export const ProgressFilledTrack = Progress.FilledTrack; diff --git a/example/storybook-nativewind/src/components-example/themed/Radio/index.tsx b/example/storybook-nativewind/src/components-example/themed/Radio/index.tsx new file mode 100644 index 0000000000..6ca77c6e71 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Radio/index.tsx @@ -0,0 +1,291 @@ +import { createRadio } from '@gluestack-ui/radio'; +import { Pressable, View, Platform, Text } from 'react-native'; +import { styled, AsForwarder } from '@gluestack-style/react'; + +const StyledRoot = styled( + // @ts-ignore + Platform.OS === 'web' ? View : Pressable, + { + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + + variants: { + size: { + lg: { + _text: { + props: { + size: 'lg', + }, + }, + _icon: { + props: { + size: 'md', + }, + }, + _indicator: { + p: 2, + h: '$6', + w: '$6', + }, + }, + md: { + _text: { + props: { + size: 'md', + }, + }, + _icon: { + props: { + size: 'sm', + }, + }, + _indicator: { + p: 1.5, + h: '$5', + w: '$5', + }, + }, + sm: { + _text: { + props: { + size: 'sm', + }, + }, + _icon: { + props: { + size: '2xs', + }, + }, + _indicator: { + p: 1, + h: '$4', + w: '$4', + }, + }, + }, + }, + + defaultProps: { + size: 'md', + }, + _web: { + 'cursor': 'pointer', + ':disabled': { + cursor: 'not-allowed', + }, + }, + }, + { + descendantStyle: ['_icon', '_text', '_indicator'], + ancestorStyle: ['_radio'], + } +); + +const StyledGroup = styled(View, {}, { descendantStyle: ['_radio'] }); + +const StyledIcon = styled( + AsForwarder, + { + 'color': '$background800', + + // defaultProps: { + // size: 'md', + // }, + 'variants': { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + 'borderRadius': '$full', + + ':checked': { + 'color': '$primary600', + ':hover': { + 'color': '$primary700', + ':disabled': { + color: '$primary600', + }, + }, + }, + }, + { + ancestorStyle: ['_icon'], + resolveProps: ['color'], + }, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); + +const StyledIndicator = styled( + View, + { + 'justifyContent': 'center', + 'alignItems': 'center', + 'bg': 'transparent', + 'borderColor': '$border400', + 'borderWidth': 2, + 'borderRadius': 999, + + '_web': { + ':focusVisible': { + outlineWidth: 2, + outlineColor: '$primary700', + outlineStyle: 'solid', + }, + }, + + ':checked': { + borderColor: '$primary600', + bg: 'transparent', + }, + + ':hover': { + 'borderColor': '$border500', + 'bg': 'transparent', + + ':checked': { + bg: 'transparent', + borderColor: '$primary700', + }, + ':invalid': { + borderColor: '$error700', + }, + ':disabled': { + ':invalid': { + borderColor: '$error400', + opacity: 0.4, + }, + 'borderColor': '$border400', + 'opacity': 0.4, + }, + }, + + ':active': { + bg: 'transparent', + borderColor: '$primary800', + }, + + ':invalid': { + borderColor: '$error700', + }, + + ':disabled': { + 'opacity': 0.4, + ':checked': { + borderColor: '$border400', + bg: 'transparent', + }, + ':invalid': { + borderColor: '$error400', + }, + }, + }, + { ancestorStyle: ['_indicator'] } +); + +const StyledLabel = styled( + Text, + { + 'color': '$text600', + + ':checked': { + color: '$text900', + }, + + ':hover': { + 'color': '$text900', + ':checked': { + color: '$text900', + }, + ':disabled': { + 'color': '$text600', + ':checked': { + color: '$text900', + }, + }, + }, + + ':active': { + 'color': '$text900', + ':checked': { + color: '$text900', + }, + }, + + ':disabled': { + opacity: 0.4, + }, + + '_web': { + MozUserSelect: 'none', + WebkitUserSelect: 'none', + msUserSelect: 'none', + userSelect: 'none', + }, + }, + { ancestorStyle: ['_text'] } +); + +export const Radio = createRadio({ + Root: StyledRoot, + Group: StyledGroup, + Icon: StyledIcon, + Indicator: StyledIndicator, + Label: StyledLabel, +}); +export const RadioGroup = Radio.Group; +export const RadioIcon = Radio.Icon; +export const RadioIndicator = Radio.Indicator; +export const RadioLabel = Radio.Label; diff --git a/example/storybook-nativewind/src/components-example/themed/RefreshControl/index.tsx b/example/storybook-nativewind/src/components-example/themed/RefreshControl/index.tsx new file mode 100644 index 0000000000..95e86d5eeb --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/RefreshControl/index.tsx @@ -0,0 +1,4 @@ +import { styled } from '@gluestack-style/react'; +import { RefreshControl as RNRefreshControl } from 'react-native'; + +export const RefreshControl = styled(RNRefreshControl, {}); diff --git a/example/storybook-nativewind/src/components-example/themed/SafeAreaView/index.tsx b/example/storybook-nativewind/src/components-example/themed/SafeAreaView/index.tsx new file mode 100644 index 0000000000..34e9630893 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/SafeAreaView/index.tsx @@ -0,0 +1,7 @@ +import { SafeAreaView as RNSafeAreaView } from 'react-native'; + +import { styled } from '@gluestack-style/react'; + +const StyledRoot = styled(RNSafeAreaView); + +export const SafeAreaView = StyledRoot; diff --git a/example/storybook-nativewind/src/components-example/themed/ScrollView/index.tsx b/example/storybook-nativewind/src/components-example/themed/ScrollView/index.tsx new file mode 100644 index 0000000000..4b317f5b97 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/ScrollView/index.tsx @@ -0,0 +1,36 @@ +import { ScrollView as RNScrollView } from 'react-native'; + +import { styled, useStyled, propertyTokenMap } from '@gluestack-style/react'; + +const StyledRoot = styled( + RNScrollView, + {}, + { + resolveProps: ['contentContainerStyle'], + }, + { + propertyResolver: { + contentContainerStyle: (rawValue, resolver) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const aliases: any = useStyled()?.config?.aliases; + const newValue = {} as Record; + Object.entries(rawValue).forEach(([key, value]: any) => { + if (Object.hasOwn(aliases, key)) { + newValue[`${aliases[key]}`] = resolver( + value, + //@ts-ignore + propertyTokenMap[aliases[key]] + ); + } else { + //@ts-ignore + newValue[`${key}`] = resolver(value, propertyTokenMap[key]); + } + }); + rawValue = newValue; + return rawValue; + }, + }, + } +); + +export const ScrollView = StyledRoot; diff --git a/example/storybook-nativewind/src/components-example/themed/SectionList/index.tsx b/example/storybook-nativewind/src/components-example/themed/SectionList/index.tsx new file mode 100644 index 0000000000..cf549c9cd2 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/SectionList/index.tsx @@ -0,0 +1 @@ +export { SectionList } from 'react-native'; diff --git a/example/storybook-nativewind/src/components-example/themed/Select/index.tsx b/example/storybook-nativewind/src/components-example/themed/Select/index.tsx new file mode 100644 index 0000000000..e1ad3c380b --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Select/index.tsx @@ -0,0 +1,682 @@ +import { H1, H2, H3, H4, H5, H6 } from '@expo/html-elements'; +import { + AnimatePresence, + AnimatedPressable, + AnimatedView, +} from '@gluestack-style/animation-resolver'; +import { styled, AsForwarder } from '@gluestack-style/react'; +import { createActionsheet } from '@gluestack-ui/actionsheet'; +import { createSelect } from '@gluestack-ui/select'; +import { TextInput } from 'react-native'; +import { + Pressable, + View, + Text, + ScrollView, + VirtualizedList, + FlatList, + SectionList, +} from 'react-native'; + +const StyledRoot = styled(View, { + width: '$full', + height: '$full', + _web: { + pointerEvents: 'none', + }, +}); + +const StyledContent = styled( + AnimatedView, + { + alignItems: 'center', + borderTopLeftRadius: '$3xl', + borderTopRightRadius: '$3xl', + h: '$full', + p: '$2', + bg: '$background0', + + _sectionHeaderBackground: { + bg: '$background0', + }, + + defaultProps: { + hardShadow: '5', + }, + + _web: { + userSelect: 'none', + pointerEvents: 'auto', + }, + }, + { + descendantStyle: ['_sectionHeaderBackground'], + } +); + +const StyledItem = styled( + Pressable, + { + 'p': '$3', + 'flexDirection': 'row', + 'alignItems': 'center', + 'rounded': '$sm', + 'w': '$full', + + ':disabled': { + opacity: 0.4, + _web: { + // @ts-ignore + pointerEvents: 'all !important', + cursor: 'not-allowed', + }, + }, + + ':hover': { + bg: '$background50', + }, + + ':active': { + bg: '$background100', + }, + + ':focus': { + bg: '$background100', + }, + + '_web': { + ':focusVisible': { + bg: '$background100', + }, + }, + }, + { + descendantStyle: ['_text', '_icon'], + } +); + +const StyledItemText = styled( + Text, + { + mx: '$2', + props: { + size: 'md', + }, + color: '$text800', + }, + { + ancestorStyle: ['_text'], + } +); + +const StyledDragIndicator = styled(View, { + w: '$16', + h: '$1', + bg: '$background400', + rounded: '$full', +}); + +const StyledDragIndicatorWrapper = styled(View, { + py: '$1', + w: '$full', + alignItems: 'center', +}); + +const StyledBackdrop = styled(AnimatedPressable, { + ':initial': { + opacity: 0, + }, + + ':animate': { + opacity: 0.5, + }, + + ':exit': { + opacity: 0, + }, + + 'position': 'absolute', + 'left': 0, + 'top': 0, + 'right': 0, + 'bottom': 0, + 'bg': '$background950', + + '_web': { + cursor: 'default', + pointerEvents: 'auto', + }, +}); + +const StyledScrollView = styled(ScrollView, { + w: '$full', + h: 'auto', +}); + +const StyledVirtualizedList = styled(VirtualizedList, { + w: '$full', + h: 'auto', +}); + +const StyledFlatList = styled(FlatList, { + w: '$full', + h: 'auto', +}); + +const StyledSectionList = styled(SectionList, { + w: '$full', + h: 'auto', +}); + +const StyledSectionHeaderText = styled(H4, { + letterSpacing: '$sm', + fontWeight: '$bold', + fontFamily: '$heading', + + // Overrides expo-html default styling + marginVertical: 0, + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '5xl': { + //@ts-ignore + props: { as: H1 }, + fontSize: '$6xl', + }, + '4xl': { + //@ts-ignore + props: { as: H1 }, + fontSize: '$5xl', + }, + + '3xl': { + //@ts-ignore + props: { as: H1 }, + fontSize: '$4xl', + }, + + '2xl': { + //@ts-ignore + props: { as: H2 }, + fontSize: '$3xl', + }, + + 'xl': { + //@ts-ignore + props: { as: H3 }, + fontSize: '$2xl', + }, + + 'lg': { + //@ts-ignore + props: { as: H4 }, + fontSize: '$xl', + }, + + 'md': { + //@ts-ignore + props: { as: H5 }, + fontSize: '$lg', + }, + + 'sm': { + //@ts-ignore + props: { as: H6 }, + fontSize: '$md', + }, + + 'xs': { + //@ts-ignore + props: { as: H6 }, + fontSize: '$sm', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + color: '$text500', + props: { size: 'xs' }, + textTransform: 'uppercase', + p: '$3', +}); + +const StyledIcon = styled( + AsForwarder, + { + variants: { + size: { + '2xs': { + h: '$3', + w: '$3', + props: { + // @ts-ignore + size: 12, + }, + }, + 'xs': { + h: '$3.5', + w: '$3.5', + props: { + //@ts-ignore + size: 14, + }, + }, + 'sm': { + h: '$4', + w: '$4', + props: { + //@ts-ignore + size: 16, + }, + }, + 'md': { + h: '$4.5', + w: '$4.5', + props: { + //@ts-ignore + size: 18, + }, + }, + 'lg': { + h: '$5', + w: '$5', + props: { + //@ts-ignore + size: 20, + }, + }, + 'xl': { + h: '$6', + w: '$6', + props: { + //@ts-ignore + size: 24, + }, + }, + }, + }, + props: { + size: 'sm', + // @ts-ignore + fill: 'none', + }, + + color: '$background500', + }, + { + componentName: 'BaseIcon', + resolveProps: ['stroke', 'fill'], + } as const, + { + propertyTokenMap: { + stroke: 'colors', + fill: 'colors', + }, + } +); + +const StyledSelectRoot = styled(View, {}); + +const StyledSelectTrigger = styled( + Pressable, + { + 'borderWidth': 1, + 'borderColor': '$background300', + 'borderRadius': '$sm', + 'flexDirection': 'row', + 'overflow': 'hidden', + 'alignItems': 'center', + + ':hover': { + borderColor: '$border400', + }, + + ':focus': { + borderColor: '$primary700', + }, + + ':disabled': { + 'opacity': 0.4, + ':hover': { + borderColor: '$background300', + }, + }, + + '_input': { + py: 'auto', + px: '$3', + }, + + '_icon': { + color: '$background500', + }, + + 'variants': { + size: { + xl: { + h: '$12', + _input: { + fontSize: '$xl', + }, + _icon: { + h: '$6', + w: '$6', + }, + }, + lg: { + h: '$11', + _input: { + fontSize: '$lg', + }, + _icon: { + h: '$5', + w: '$5', + }, + }, + md: { + h: '$10', + _input: { + fontSize: '$md', + }, + _icon: { + h: '$4', + w: '$4', + }, + }, + sm: { + h: '$9', + _input: { + fontSize: '$sm', + }, + _icon: { + h: '$3.5', + w: '$3.5', + }, + }, + }, + variant: { + underlined: { + '_input': { + _web: { + outlineWidth: 0, + outline: 'none', + }, + px: '$0', + }, + + 'borderWidth': 0, + 'borderRadius': 0, + 'borderBottomWidth': '$1', + + ':focus': { + 'borderColor': '$primary700', + '_web': { + boxShadow: 'inset 0 -1px 0 0 $primary700', + }, + ':hover': { + borderColor: '$primary700', + _web: { + boxShadow: 'inset 0 -1px 0 0 $primary600', + }, + }, + }, + + ':invalid': { + 'borderBottomWidth': 2, + 'borderBottomColor': '$error700', + '_web': { + boxShadow: 'inset 0 -1px 0 0 $error700', + }, + ':hover': { + borderBottomColor: '$error700', + }, + ':focus': { + 'borderBottomColor': '$error700', + ':hover': { + borderBottomColor: '$error700', + _web: { + boxShadow: 'inset 0 -1px 0 0 $error700', + }, + }, + }, + ':disabled': { + ':hover': { + borderBottomColor: '$error700', + _web: { + boxShadow: 'inset 0 -1px 0 0 $error700', + }, + }, + }, + }, + }, + outline: { + '_input': { + _web: { + outlineWidth: 0, + outline: 'none', + }, + }, + + ':focus': { + 'borderColor': '$primary700', + '_web': { + boxShadow: 'inset 0 0 0 1px $primary700', + }, + ':hover': { + borderColor: '$primary700', + _web: { + boxShadow: 'inset 0 0 0 1px $primary600', + }, + }, + }, + + ':invalid': { + 'borderColor': '$error700', + '_web': { + boxShadow: 'inset 0 0 0 1px $error700', + }, + ':hover': { + borderColor: '$error700', + }, + ':focus': { + 'borderColor': '$error700', + ':hover': { + borderColor: '$error700', + _web: { + boxShadow: 'inset 0 0 0 1px $error700', + }, + }, + }, + ':disabled': { + ':hover': { + borderColor: '$error700', + _web: { + boxShadow: 'inset 0 0 0 1px $error700', + }, + }, + }, + }, + }, + rounded: { + 'borderRadius': 999, + + '_input': { + px: '$4', + _web: { + outlineWidth: 0, + outline: 'none', + }, + }, + + ':focus': { + 'borderColor': '$primary700', + '_web': { + boxShadow: 'inset 0 0 0 1px $primary700', + }, + ':hover': { + borderColor: '$primary700', + _web: { + boxShadow: 'inset 0 0 0 1px $primary600', + }, + }, + }, + + ':invalid': { + 'borderColor': '$error700', + '_web': { + boxShadow: 'inset 0 0 0 1px $error700', + }, + ':hover': { + borderColor: '$error700', + }, + ':focus': { + 'borderColor': '$error700', + ':hover': { + borderColor: '$error700', + _web: { + boxShadow: 'inset 0 0 0 1px $error700', + }, + }, + }, + ':disabled': { + ':hover': { + borderColor: '$error700', + _web: { + boxShadow: 'inset 0 0 0 1px $error700', + }, + }, + }, + }, + }, + }, + }, + + 'defaultProps': { + size: 'md', + variant: 'outline', + }, + }, + + { + descendantStyle: ['_input', '_icon'], + } +); + +const StyledSelectInput = styled( + TextInput, + { + _web: { + w: '$full', + }, + + pointerEvents: 'none', + flex: 1, + h: '$full', + color: '$text900', + + props: { + placeholderTextColor: '$text500', + }, + }, + { + ancestorStyle: ['_input'], + resolveProps: ['placeholderTextColor'], + }, + { + propertyTokenMap: { + placeholderTextColor: 'colors', + }, + } +); + +const Actionsheet = createActionsheet({ + Root: StyledRoot, + Content: StyledContent, + Item: StyledItem, + ItemText: StyledItemText, + DragIndicator: StyledDragIndicator, + IndicatorWrapper: StyledDragIndicatorWrapper, + Backdrop: StyledBackdrop, + ScrollView: StyledScrollView, + VirtualizedList: StyledVirtualizedList, + FlatList: StyledFlatList, + SectionList: StyledSectionList, + SectionHeaderText: StyledSectionHeaderText, + Icon: StyledIcon, + AnimatePresence: AnimatePresence, +}); + +export const Select = createSelect( + { + Root: StyledSelectRoot, + Trigger: StyledSelectTrigger, + Input: StyledSelectInput, + Icon: StyledIcon, + }, + { + Portal: Actionsheet, + Backdrop: Actionsheet.Backdrop, + Content: Actionsheet.Content, + DragIndicator: Actionsheet.DragIndicator, + DragIndicatorWrapper: Actionsheet.DragIndicatorWrapper, + Item: Actionsheet.Item, + ItemText: Actionsheet.ItemText, + ScrollView: Actionsheet.ScrollView, + VirtualizedList: Actionsheet.VirtualizedList, + FlatList: Actionsheet.FlatList, + SectionList: Actionsheet.SectionList, + SectionHeaderText: Actionsheet.SectionHeaderText, + } +); +export const SelectTrigger = Select.Trigger; +export const SelectInput = Select.Input; +export const SelectIcon = Select.Icon; +export const SelectPortal = Select.Portal; +export const SelectBackdrop = Select.Backdrop; +export const SelectContent = Select.Content; +export const SelectDragIndicator = Select.DragIndicator; +export const SelectDragIndicatorWrapper = Select.DragIndicatorWrapper; +export const SelectItem = Select.Item; +export const SelectItemText = Select.ItemText; +export const SelectScrollView = Select.ScrollView; +export const SelectVirtualizedList = Select.VirtualizedList; +export const SelectFlatList = Select.FlatList; +export const SelectSectionList = Select.SectionList; +export const SelectSectionHeaderText = Select.SectionHeaderText; diff --git a/example/storybook-nativewind/src/components-example/themed/Slider/index.tsx b/example/storybook-nativewind/src/components-example/themed/Slider/index.tsx new file mode 100644 index 0000000000..ada50c2688 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Slider/index.tsx @@ -0,0 +1,310 @@ +import { styled } from '@gluestack-style/react'; +import { createSlider } from '@gluestack-ui/slider'; +import { Pressable } from 'react-native'; +import { View } from 'react-native'; + +const StyledRoot = styled( + View, + { + justifyContent: 'center', + alignItems: 'center', + variants: { + orientation: { + horizontal: { + w: '$full', + _track: { + width: '$full', + }, + _filledTrack: { + height: '$full', + }, + }, + vertical: { + h: '$full', + _track: { + height: '$full', + }, + _filledTrack: { + width: '$full', + }, + }, + }, + isReversed: { + true: {}, + false: {}, + }, + size: { + sm: { + _thumb: { + h: '$4', + w: '$4', + }, + }, + md: { + _thumb: { + h: '$5', + w: '$5', + }, + }, + lg: { + _thumb: { + h: '$6', + w: '$6', + }, + }, + }, + }, + compoundVariants: [ + { + orientation: 'horizontal', + size: 'sm', + value: { + _track: { + height: '$1', + flexDirection: 'row', + }, + }, + }, + { + orientation: 'horizontal', + size: 'sm', + isReversed: true, + value: { + _track: { + height: '$1', + flexDirection: 'row-reverse', + }, + }, + }, + { + orientation: 'horizontal', + size: 'md', + value: { + _track: { + height: 5, + flexDirection: 'row', + }, + }, + }, + { + orientation: 'horizontal', + size: 'md', + isReversed: true, + value: { + _track: { + height: 5, + flexDirection: 'row-reverse', + }, + }, + }, + { + orientation: 'horizontal', + size: 'lg', + value: { + _track: { + height: '$1.5', + flexDirection: 'row', + }, + }, + }, + { + orientation: 'horizontal', + size: 'lg', + isReversed: true, + value: { + _track: { + height: '$1.5', + flexDirection: 'row-reverse', + }, + }, + }, + { + orientation: 'vertical', + size: 'sm', + value: { + _track: { + w: '$1', + flexDirection: 'column-reverse', + }, + }, + }, + { + orientation: 'vertical', + size: 'sm', + isReversed: true, + value: { + _track: { + width: '$1', + flexDirection: 'column', + }, + }, + }, + { + orientation: 'vertical', + size: 'md', + value: { + _track: { + width: 5, + flexDirection: 'column-reverse', + }, + }, + }, + { + orientation: 'vertical', + size: 'md', + isReversed: true, + value: { + _track: { + width: 5, + flexDirection: 'column', + }, + }, + }, + { + orientation: 'vertical', + size: 'lg', + value: { + _track: { + width: '$1.5', + flexDirection: 'column-reverse', + }, + }, + }, + { + orientation: 'vertical', + size: 'lg', + isReversed: true, + value: { + _track: { + width: '$1.5', + flexDirection: 'column', + }, + }, + }, + ], + _web: { + ':disabled': { + // @ts-ignore + pointerEvents: 'all !important', + cursor: 'not-allowed', + opacity: 0.4, + }, + }, + defaultProps: { + size: 'md', + orientation: 'horizontal', + }, + }, + { + descendantStyle: ['_thumb', '_track', '_filledTrack'], + } +); + +const StyledThumb = styled( + View, + { + 'bg': '$primary500', + 'position': 'absolute', + 'borderRadius': '$full', + + ':focus': { + bg: '$primary600', + }, + + ':active': { + bg: '$primary600', + }, + + ':hover': { + bg: '$primary600', + }, + + ':disabled': { + bg: '$primary500', + }, + + '_web': { + //@ts-ignore + 'cursor': 'pointer', + ':active': { + outlineWidth: 4, + outlineStyle: 'solid', + outlineColor: '$primary400', + }, + ':focus': { + outlineWidth: 4, + outlineStyle: 'solid', + outlineColor: '$primary400', + }, + }, + + 'defaultProps': { + hardShadow: '1', + }, + }, + { + ancestorStyle: ['_thumb'], + } +); + +const StyledTrack = styled( + Pressable, + { + bg: '$background300', + + borderRadius: '$lg', + overflow: 'hidden', + + variants: { + variant: { + horizontal: { + width: '100%', + }, + vertical: { + height: '100%', + }, + }, + }, + }, + { + ancestorStyle: ['_track'], + } +); + +const StyledFilledTrack = styled( + View, + { + 'bg': '$primary500', + + ':focus': { + bg: '$primary600', + }, + + ':active': { + bg: '$primary600', + }, + + ':hover': { + bg: '$primary600', + }, + }, + { + ancestorStyle: ['_filledTrack'], + } +); + +const StyledThumbInteraction = styled(View, { + borderRadius: 9999, + zIndex: -1, +}); + +export const Slider = createSlider({ + Root: StyledRoot, + Thumb: StyledThumb, + Track: StyledTrack, + FilledTrack: StyledFilledTrack, + ThumbInteraction: StyledThumbInteraction, +}); +export const SliderThumb = Slider.Thumb; +export const SliderTrack = Slider.Track; +export const SliderFilledTrack = Slider.FilledTrack; diff --git a/example/storybook-nativewind/src/components-example/themed/Spinner/index.tsx b/example/storybook-nativewind/src/components-example/themed/Spinner/index.tsx new file mode 100644 index 0000000000..b435326f7a --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Spinner/index.tsx @@ -0,0 +1,23 @@ +import { ActivityIndicator } from 'react-native'; +import { styled } from '@gluestack-style/react'; +import { createSpinner } from '@gluestack-ui/spinner'; + +const StyledRoot = styled( + ActivityIndicator, + { + props: { + color: '$primary500', + }, + }, + { + resolveProps: ['color'], + }, + { + propertyTokenMap: { + // @ts-ignore + size: 'size', + }, + } +); + +export const Spinner = createSpinner({ Root: StyledRoot }); diff --git a/example/storybook-nativewind/src/components-example/themed/StatusBar/index.tsx b/example/storybook-nativewind/src/components-example/themed/StatusBar/index.tsx new file mode 100644 index 0000000000..b1e74de9fe --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/StatusBar/index.tsx @@ -0,0 +1,6 @@ +import { styled } from '@gluestack-style/react'; +import { StatusBar as RNStatusBar } from 'react-native'; + +const StyledRoot = styled(RNStatusBar, {}); + +export const StatusBar = StyledRoot; diff --git a/example/storybook-nativewind/src/components-example/themed/Switch/index.tsx b/example/storybook-nativewind/src/components-example/themed/Switch/index.tsx new file mode 100644 index 0000000000..6bbba26105 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Switch/index.tsx @@ -0,0 +1,146 @@ +import { styled } from '@gluestack-style/react'; +import { Switch as RNSwitch } from 'react-native'; +import { createSwitch } from '@gluestack-ui/switch'; + +const StyledRoot = styled( + RNSwitch, + { + 'props': { + // todo: add support for this in style.gluestack.io + // trackColor: { false: '$background300', true: '$primary600' }, + + // hacky fix for the above + //@ts-ignore + trackColor: { false: '$background300', true: '$primary600' }, + thumbColor: '$background600', + //@ts-ignore + activeThumbColor: '$background200', + + // for ios specifically in unchecked state + ios_backgroundColor: '$background300', + }, + + 'borderRadius': '$full', + + 'variants': { + //@ts-ignore + + size: { + sm: { + transform: [ + { + scale: 0.75, + }, + ], + }, + md: {}, + lg: { + transform: [ + { + scale: 1.25, + }, + ], + }, + }, + }, + + '_web': { + ':focus': { + outlineWidth: 0, + outlineColor: '$primary700', + outlineStyle: 'solid', + }, + }, + + 'defaultProps': { + size: 'md', + }, + + ':disabled': { + '_web': { + 'cursor': 'pointer', + ':disabled': { + cursor: 'not-allowed', + }, + }, + 'opacity': 0.4, + //@ts-ignore + 'trackColor': { false: '$background300', true: '$primary600' }, + // for ios specifically in unchecked state + 'ios_backgroundColor': '$background300', + ':hover': { + props: { + //@ts-ignore + trackColor: { false: '$background300', true: '$primary600' }, + }, + }, + }, + + ':invalid': { + borderColor: '$error700', + borderRadius: 12, + borderWidth: 2, + }, + + ':hover': { + 'props': { + // todo: add support for this in style.gluestack.io + // trackColor: { false: '$background400', true: '$primary700' }, + + // hacky fix for the above + //@ts-ignore + + trackColor: { false: '$background400', true: '$primary700' }, + ios_backgroundColor: '$background400', + }, + ':invalid': { + props: { + // todo: add support for this in style.gluestack.io + // trackColor: { false: '$background400', true: '$primary700' }, + + // hacky fix for the above + //@ts-ignore + + trackColor: { false: '$background300', true: '$primary700' }, + }, + }, + }, + + ':checked': { + props: { + //@ts-ignore + thumbColor: '$background0', + }, + }, + }, + { + componentName: 'Switch', + resolveProps: [ + 'thumbColor', + 'trackColor', + 'activeThumbColor', + 'ios_backgroundColor', + ], + } as const, + { + propertyTokenMap: { + trackColor: 'colors', + thumbColor: 'colors', + activeThumbColor: 'colors', + ios_backgroundColor: 'colors', + }, + propertyResolver: { + trackColor: (rawValue: any, resolver: any) => { + const resolveColor = { + true: resolver(rawValue.true), + false: resolver(rawValue.false), + }; + return resolveColor; + }, + }, + } +); + +export const Switch = createSwitch({ + Root: StyledRoot, +}); diff --git a/example/storybook-nativewind/src/components-example/themed/Text/index.tsx b/example/storybook-nativewind/src/components-example/themed/Text/index.tsx new file mode 100644 index 0000000000..7d13e17a1f --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Text/index.tsx @@ -0,0 +1,106 @@ +import { Text as RNText } from 'react-native'; +import { styled } from '@gluestack-style/react'; + +const StyledText = styled( + RNText, + { + color: '$text700', + fontWeight: '$normal', + fontFamily: '$body', + fontStyle: 'normal', + letterSpacing: '$md', + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + defaultProps: { + size: 'md', + }, + }, + {} +); + +export const Text = StyledText; diff --git a/example/storybook-nativewind/src/components-example/themed/Textarea/index.tsx b/example/storybook-nativewind/src/components-example/themed/Textarea/index.tsx new file mode 100644 index 0000000000..b8844a5e87 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Textarea/index.tsx @@ -0,0 +1,156 @@ +import { createTextarea } from '@gluestack-ui/textarea'; + +import { View, TextInput } from 'react-native'; +import { styled } from '@gluestack-style/react'; +const StyledRoot = styled( + View, + { + 'w': '100%', + 'borderWidth': 1, + 'borderColor': '$background300', + 'borderRadius': '$sm', + 'h': 100, + + '_input': { + p: '$3', + _web: { + outlineWidth: 0, + outline: 'none', + }, + }, + + ':hover': { + borderColor: '$border400', + }, + + ':focus': { + 'borderColor': '$primary700', + ':hover': { + borderColor: '$primary700', + }, + }, + + ':disabled': { + 'opacity': 0.4, + ':hover': { + borderColor: '$background300', + }, + }, + + 'variants': { + size: { + xl: { + _input: { + fontSize: '$xl', + }, + }, + + lg: { + _input: { + fontSize: '$lg', + }, + }, + md: { + _input: { + fontSize: '$md', + }, + }, + sm: { + _input: { + fontSize: '$sm', + }, + }, + }, + variant: { + default: { + '_input': { + _web: { + outlineWidth: '0', + outline: 'none', + }, + }, + + ':focus': { + borderColor: '$primary700', + _web: { + boxShadow: 'inset 0 0 0 1px $primary700', + }, + }, + + ':invalid': { + 'borderColor': '$error700', + '_web': { + boxShadow: 'inset 0 0 0 1px $error700', + }, + ':hover': { + borderColor: '$error700', + }, + ':focus': { + ':hover': { + borderColor: '$primary700', + _web: { + boxShadow: 'inset 0 0 0 1px $primary700', + }, + }, + }, + ':disabled': { + ':hover': { + borderColor: '$error700', + _web: { + boxShadow: 'inset 0 0 0 1px $error700', + }, + }, + }, + }, + }, + }, + }, + + 'defaultProps': { + variant: 'default', + size: 'md', + }, + }, + { + descendantStyle: ['_input'], + }, + {} +); +const StyledInput = styled( + TextInput, + { + p: '$2', + color: '$text900', + textAlignVertical: 'top', + flex: 1, + + props: { + // @ts-ignore + multiline: true, + placeholderTextColor: '$text500', + }, + + _web: { + 'cursor': 'text', + ':disabled': { + cursor: 'not-allowed', + }, + }, + }, + { + ancestorStyle: ['_input'], + resolveProps: ['placeholderTextColor'], + }, + { + propertyTokenMap: { + placeholderTextColor: 'colors', + }, + } +); +const AccessibleTextarea = createTextarea({ + Root: StyledRoot, + Input: StyledInput, +}); + +export const Textarea = AccessibleTextarea; +export const TextareaInput = AccessibleTextarea.Input; diff --git a/example/storybook-nativewind/src/components-example/themed/Toast/index.tsx b/example/storybook-nativewind/src/components-example/themed/Toast/index.tsx new file mode 100644 index 0000000000..b14e5e74b2 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Toast/index.tsx @@ -0,0 +1,297 @@ +import { createToast, createToastHook } from '@gluestack-ui/toast'; +import { + AnimatePresence, + AnimatedView, +} from '@gluestack-style/animation-resolver'; +import { styled } from '@gluestack-style/react'; +import { Text, View } from 'react-native'; + +const StyledRoot = styled( + View, + { + px: '$4', + py: '$3', + borderRadius: '$sm', + flexDirection: 'row', + variants: { + action: { + error: { + bg: '$backgroundError', + borderColor: '$error300', + + _icon: { + color: '$error500', + }, + }, + warning: { + bg: '$backgroundWarning', + borderColor: '$warning300', + + _icon: { + color: '$warning500', + }, + }, + success: { + bg: '$backgroundSuccess', + borderColor: '$success300', + + _icon: { + color: '$success500', + }, + }, + info: { + bg: '$backgroundInfo', + borderColor: '$info300', + + _icon: { + color: '$info500', + }, + }, + attention: { + bg: '$backgroundMuted', + borderColor: '$secondary300', + + _icon: { + color: '$secondary600', + }, + }, + }, + + variant: { + solid: {}, + outline: { + borderWidth: '$1', + bg: '$white', + }, + accent: { + borderLeftWidth: '$4', + }, + }, + }, + m: '$3', + + _web: { + pointerEvents: 'auto', + }, + defaultProps: { + hardShadow: '5', + variant: 'solid', + action: 'attention', + }, + }, + { descendantStyle: ['_icon', '_title', '_description'] } +); +const StyledTitle = styled( + Text, + { + color: '$text700', + fontWeight: '$medium', + fontFamily: '$body', + fontStyle: 'normal', + letterSpacing: '$md', + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + props: { + size: 'md', + }, + }, + { ancestorStyle: ['_title'] } +); + +const StyledDescription = styled( + Text, + { + color: '$text700', + fontWeight: '$normal', + fontFamily: '$body', + fontStyle: 'normal', + letterSpacing: '$md', + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + props: { + size: 'sm', + }, + }, + { ancestorStyle: ['_description'] } +); +const AnimationWrapper = styled(AnimatedView, {}); + +export const useToast = createToastHook(AnimationWrapper, AnimatePresence); + +export const Toast = createToast({ + Root: StyledRoot, + Title: StyledTitle, + Description: StyledDescription, +}); +export const ToastTitle = Toast.Title; +export const ToastDescription = Toast.Description; diff --git a/example/storybook-nativewind/src/components-example/themed/Tooltip/index.tsx b/example/storybook-nativewind/src/components-example/themed/Tooltip/index.tsx new file mode 100644 index 0000000000..ccbc5e1e23 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Tooltip/index.tsx @@ -0,0 +1,188 @@ +import { createTooltip } from '@gluestack-ui/tooltip'; +import { + AnimatePresence, + AnimatedView, +} from '@gluestack-style/animation-resolver'; +import { styled } from '@gluestack-style/react'; +import { View, Text } from 'react-native'; + +const StyledRoot = styled( + View, + { + width: '$full', + height: '$full', + _web: { + pointerEvents: 'none', + }, + }, + {} +); + +const StyledContent = styled( + AnimatedView, + { + ':initial': { + opacity: 0, + scale: 0.5, + }, + + ':animate': { + opacity: 1, + scale: 1, + }, + + ':exit': { + opacity: 0, + scale: 0.5, + }, + + ':transition': { + type: 'spring', + damping: 18, + stiffness: 250, + // @ts-ignore + opacity: { + type: 'timing', + duration: 250, + }, + }, + + 'py': '$1', + 'px': '$3', + 'borderRadius': '$sm', + 'bg': '$background900', + + '_text': { + fontSize: '$xs', + color: '$text50', + }, + + '_web': { + pointerEvents: 'auto', + }, + + 'defaultProps': { + hardShadow: '2', + }, + }, + { + descendantStyle: ['_text'], + } +); + +const StyledText = styled( + Text, + { + fontWeight: '$normal', + fontStyle: 'normal', + letterSpacing: '$md', + + variants: { + isTruncated: { + true: { + props: { + // @ts-ignore + numberOfLines: 1, + ellipsizeMode: 'tail', + }, + }, + }, + bold: { + true: { + fontWeight: '$bold', + }, + }, + underline: { + true: { + textDecorationLine: 'underline', + }, + }, + strikeThrough: { + true: { + textDecorationLine: 'line-through', + }, + }, + size: { + '2xs': { + fontSize: '$2xs', + }, + 'xs': { + fontSize: '$xs', + }, + + 'sm': { + fontSize: '$sm', + }, + + 'md': { + fontSize: '$md', + }, + + 'lg': { + fontSize: '$lg', + }, + + 'xl': { + fontSize: '$xl', + }, + + '2xl': { + fontSize: '$2xl', + }, + + '3xl': { + fontSize: '$3xl', + }, + + '4xl': { + fontSize: '$4xl', + }, + + '5xl': { + fontSize: '$5xl', + }, + + '6xl': { + fontSize: '$6xl', + }, + }, + sub: { + true: { + fontSize: '$xs', + }, + }, + italic: { + true: { + fontStyle: 'italic', + }, + }, + highlight: { + true: { + bg: '$yellow500', + }, + }, + }, + + defaultProps: { + size: 'md', + }, + color: '$red400', + fontFamily: '$body', + _web: { + userSelect: 'none', + }, + }, + { + ancestorStyle: ['_text'], + } +); + +export const Tooltip = createTooltip({ + Root: StyledRoot, + Content: StyledContent, + Text: StyledText, + //@ts-ignore + AnimatePresence: AnimatePresence, +}); +export const TooltipContent = Tooltip.Content; +export const TooltipText = Tooltip.Text; diff --git a/example/storybook-nativewind/src/components-example/themed/VStack/index.tsx b/example/storybook-nativewind/src/components-example/themed/VStack/index.tsx new file mode 100644 index 0000000000..90c3cd8bc5 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/VStack/index.tsx @@ -0,0 +1,45 @@ +import { styled } from '@gluestack-style/react'; +import { View } from 'react-native'; + +const StyledRoot = styled( + View, + { + flexDirection: 'column', + variants: { + space: { + 'xs': { + gap: `$1`, + }, + 'sm': { + gap: `$2`, + }, + 'md': { + gap: `$3`, + }, + 'lg': { + gap: `$4`, + }, + 'xl': { + gap: `$5`, + }, + '2xl': { + gap: `$6`, + }, + '3xl': { + gap: `$7`, + }, + '4xl': { + gap: `$8`, + }, + }, + reversed: { + true: { + flexDirection: 'column-reverse', + }, + }, + }, + }, + {} +); + +export const VStack = StyledRoot; diff --git a/example/storybook-nativewind/src/components-example/themed/View/index.tsx b/example/storybook-nativewind/src/components-example/themed/View/index.tsx new file mode 100644 index 0000000000..8f32b6b168 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/View/index.tsx @@ -0,0 +1 @@ +export { View } from 'react-native'; diff --git a/example/storybook-nativewind/src/components-example/themed/VirtualizedList/index.tsx b/example/storybook-nativewind/src/components-example/themed/VirtualizedList/index.tsx new file mode 100644 index 0000000000..be3e260683 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/VirtualizedList/index.tsx @@ -0,0 +1 @@ +export { VirtualizedList } from 'react-native'; diff --git a/example/storybook-nativewind/src/components-example/themed/Wrapper.tsx b/example/storybook-nativewind/src/components-example/themed/Wrapper.tsx new file mode 100644 index 0000000000..eb3df88161 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/Wrapper.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { Box, Center } from '@gluestack-ui/themed'; +import { StyledProvider, useColorMode } from '@gluestack-style/react'; +import { createProvider } from '@gluestack-ui/provider'; +import { config } from './GluestackUIProvider/config'; + +const Provider = createProvider({ StyledProvider }) as any; +Provider.displayName = 'Provider'; + +const Wrapper = ({ children, ...props }: any) => { + const colorMode = useColorMode(); + return ( + // @ts-ignore + + + +
{children}
+
+
+
+ ); +}; + +export default Wrapper; diff --git a/example/storybook-nativewind/src/components-example/themed/index.ts b/example/storybook-nativewind/src/components-example/themed/index.ts new file mode 100644 index 0000000000..a70e7a7440 --- /dev/null +++ b/example/storybook-nativewind/src/components-example/themed/index.ts @@ -0,0 +1,47 @@ +export * from './Button'; +export * from './Accordion'; +export * from './Actionsheet'; +export * from './Alert'; +export * from './AlertDialog'; +export * from './Avatar'; +export * from './Badge'; +export * from './Box'; +export * from './FlatList'; +export * from './Center'; +export * from './Checkbox'; +export * from './HStack'; +export * from './Pressable'; +export * from './Icon'; +export * from './Heading'; +export * from './Divider'; +export * from './Fab'; +export * from './FormControl'; +export * from './Input'; +export * from './InputAccessoryView'; +export * from './Image'; +export * from './KeyboardAvoidingView'; +export * from './LinearGradient'; +export * from './Link'; +export * from './Menu'; +export * from './Modal'; +export * from './Popover'; +export * from './Progress'; +export * from './Text'; +export * from './Radio'; +export * from './ScrollView'; +export * from './SafeAreaView'; +export * from './Select'; +export * from './Slider'; +export * from './Spinner'; +export * from './StatusBar'; +export * from './SectionList'; +export * from './Switch'; +export * from './Textarea'; +export * from './Toast'; +export * from './Tooltip'; +export * from './View'; +export * from './VStack'; +export { GluestackUIProvider } from './GluestackUIProvider'; +export * from './VirtualizedList'; +export * from './RefreshControl'; +export * from './ImageBackground';