This commit is contained in:
oneao committed 2025-12-01 22:27:11 +08:00
1 parent 494f1ad01f
commit 0ab2796dd4
21 files changed
+1583 -472

No files matched your search

@@ -1,6 +1,6 @@
import type { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record'
import React, { useCallback, useState } from 'react'
import { RefreshControl, SectionList, Text, TouchableHighlight, View } from 'react-native'
import { RefreshControl, SectionList, Text, TouchableHighlight, Vibration, View } from 'react-native'
import {
Menu,
MenuOption,
@@ -120,7 +120,6 @@ export default function StaticTransactions({
renderItem={({ item, index }) => {
const category = moneyCategoryStore.getCategoryById(item.category_id)
return (
<Menu
renderer={renderers.Popover}
@@ -135,7 +134,12 @@ export default function StaticTransactions({
onOpen={() => setSelectedId(item.id)}
onClose={() => setSelectedId(null)}
>
<MenuTrigger triggerOnLongPress>
<MenuTrigger
triggerOnLongPress
onPress={() => {
Vibration.vibrate(50)
}}
>
<View
className="flex-row items-center gap-4 py-2 px-5"
style={{
@@ -179,7 +183,6 @@ export default function StaticTransactions({
},
}}
>
<MenuOption
customStyles={{
OptionTouchableComponent: TouchableHighlight,
@@ -1,12 +1,34 @@
import type { AFormRef } from '@/components/common/ao'
import { SquareUserRound } from 'lucide-react-native'
import * as React from 'react'
import { useRef, useState } from 'react'
import { Text, View } from 'react-native'
import { AButton, AForm, AFormItem, AInput, ASegmentedTabs, ATab, LucideIcon } from '@/components/common/ao'
import { FlatList, Pressable, TouchableOpacity, View } from 'react-native'
import QRCode from 'react-native-qrcode-svg'
import { AButton, ADivider, AForm, AFormItem, AInput, LucideIcon } from '@/components/common/ao'
import CustomHeader from '@/components/custom/Header'
import { Badge, BadgeIcon, BadgeText } from '@/components/ui/badge'
import { Divider } from '@/components/ui/divider'
import {
Accordion,
AccordionContent,
AccordionHeader,
AccordionIcon,
AccordionItem,
AccordionTitleText,
AccordionTrigger,
} from '@/components/ui/accordion'
import {
Avatar,
AvatarBadge,
AvatarFallbackText,
AvatarImage,
} from '@/components/ui/avatar'
import { Badge, BadgeText } from '@/components/ui/badge'
import { Heading } from '@/components/ui/heading'
import { HStack } from '@/components/ui/hstack'
import { ChevronDownIcon, ChevronUpIcon } from '@/components/ui/icon'
import { Link, LinkText } from '@/components/ui/link'
import { Menu, MenuItem, MenuItemLabel } from '@/components/ui/menu'
import { Text } from '@/components/ui/text'
import { VStack } from '@/components/ui/vstack'
export default function PagerWithTab() {
const formRef = useRef<AFormRef>(null)
@@ -14,9 +36,11 @@ export default function PagerWithTab() {
code: '',
})
const [accordion, setAccordion] = useState(['a'])
function EnterSapce() {
return (
<View>
<View className="px-4 items-center">
<AForm ref={formRef} form={form}>
<AFormItem
name="username"
@@ -26,7 +50,7 @@ export default function PagerWithTab() {
</AFormItem>
</AForm>
<AButton>加入空间</AButton>
<AButton className="w-full">加入空间</AButton>
<View
className="flex-row items-center w-full"
style={{
@@ -35,19 +59,27 @@ export default function PagerWithTab() {
}}
>
<View className="flex-1">
<Divider />
<ADivider />
</View>
<Text className="mx-3 text-gray-500 text-sm">或</Text>
<View className="flex-1">
<Divider />
<ADivider />
</View>
</View>
<AButton variant="outline">扫码加入</AButton>
<AButton variant="outline" className="w-full">扫码加入</AButton>
<Link className="mt-4">
<LinkText>返回</LinkText>
</Link>
</View>
)
}
const members = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' },
]
return (
<View className="flex-1">
@@ -79,24 +111,65 @@ export default function PagerWithTab() {
<AButton variant="outline">加入已有空间</AButton>
</View> */}
<View className="p-4">
<View>
<View className="flex flex-row items-center justify-between">
<Text className="font-semibold text-lg">邀请好友加入</Text>
</View>
<View
className="flex-row items-center justify-between px-2 py-2 mt-4 border-round"
style={{
backgroundColor: '#f8f9fa',
{/* <View className="px-4 flex-1">
<Accordion
size="md"
variant="unfilled"
type="multiple"
isCollapsible={true}
isDisabled={false}
value={accordion}
onValueChange={(value) => {
setAccordion(value)
}}
>
<AccordionItem value="a">
<AccordionHeader>
<AccordionTrigger
style={{
paddingLeft: 0,
paddingRight: 0,
}}
>
{({ isExpanded }: { isExpanded: boolean }) => {
return (
<>
<AccordionTitleText className="font-semibold text-lg">
我的邀请码
</AccordionTitleText>
{isExpanded
? (
<AccordionIcon as={ChevronUpIcon} className="ml-3" />
)
: (
<AccordionIcon as={ChevronDownIcon} className="ml-3" />
)}
</>
)
}}
</AccordionTrigger>
</AccordionHeader>
<AccordionContent style={{
marginBottom: 0,
paddingBottom: 0,
}}
>
<Text>123456</Text>
<AButton size="xs">复制代码</AButton>
</View>
</View>
>
<TouchableOpacity className="flex-row items-center justify-center ">
<Text className="font-bold text-3xl tracking-[4px] mr-3">123456</Text>
<LucideIcon icon="Copy" size={16} color="blue" clickable={false} />
</TouchableOpacity>
<View className="mt-8">
<View className="items-center justify-center">
<ADivider direction="horizontal" text="扫描二维码" />
<QRCode
size={120}
value="http://awesome.link.qr"
/>
</View>
</AccordionContent>
</AccordionItem>
</Accordion>
<View className="mt-4 flex-1">
<View className="flex flex-row items-center justify-between">
<Text className="font-semibold text-lg">空间成员</Text>
<Badge size="lg" variant="solid" action="muted">
@@ -104,12 +177,65 @@ export default function PagerWithTab() {
</Badge>
</View>
<View className="mt-2">
<Text>列表</Text>
<View>
<FlatList
data={members}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => (
<TouchableOpacity>
<HStack space="md" className="my-2 items-center">
<Avatar className="bg-indigo-600">
<AvatarFallbackText className="text-white text-lg">
{item.name}
</AvatarFallbackText>
<AvatarBadge />
</Avatar>
<VStack>
<HStack space="sm">
<Heading size="sm">{item.name}</Heading>
<Badge size="sm" variant="solid" action="muted">
<BadgeText>管理员</BadgeText>
</Badge>
</HStack>
<Text size="sm">Marketing Coordinator</Text>
</VStack>
<View className="ml-auto">
<Menu
placement="top"
offset={5}
trigger={triggerProps => (
<Pressable
{...triggerProps}
style={{
padding: 8,
justifyContent: 'center',
alignItems: 'center',
}}
>
<LucideIcon icon="EllipsisVertical" size={20} clickable={false} />
</Pressable>
)}
>
<MenuItem key="Add account" textValue="Add account">
<MenuItemLabel size="sm">添加为管理员</MenuItemLabel>
</MenuItem>
<MenuItem key="Community" textValue="Community">
<MenuItemLabel size="sm">移出空间</MenuItemLabel>
</MenuItem>
</Menu>
</View>
</HStack>
</TouchableOpacity>
)}
/>
</View>
<AButton size="sm" className="mb-8 mt-4">退出该空间</AButton>
</View>
</View>
</View> */}
<EnterSapce />
</View>
</View>
)
@@ -0,0 +1,74 @@
import type { ViewStyle } from 'react-native'
import React from 'react'
import { Text, View } from 'react-native'
interface DividerProps {
direction?: 'horizontal' | 'vertical'
text?: string | React.ReactNode
textPosition?: 'left' | 'center' | 'right'
style?: ViewStyle
className?: string
}
export default function Divider({
direction = 'horizontal',
text,
textPosition = 'center',
style,
className,
}: DividerProps) {
const isString = typeof text === 'string'
// 垂直分割线
if (direction === 'vertical') {
return (
<View
style={style}
className={`w-px bg-gray-300 mx-2 h-4 ${className ?? ''}`}
/>
)
}
// 水平,无文字
if (!text) {
return (
<View
style={style}
className={`h-px bg-gray-300 my-2 w-full ${className ?? ''}`}
/>
)
}
// 水平 + 文本
return (
<View
style={style}
className={`flex-row items-center my-2 ${className ?? ''}`}
>
{/* 左线 */}
<View
className={`h-px bg-gray-300 ${
textPosition === 'left' ? 'w-2' : 'flex-1'
}`}
/>
{/* 文本(字符串 → 自动包裹 Text;node → 直接渲染) */}
<View className="mx-3">
{isString
? (
<Text className="text-gray-500 text-sm">{text}</Text>
)
: (
text
)}
</View>
{/* 右线 */}
<View
className={`h-px bg-gray-300 ${
textPosition === 'right' ? 'w-2' : 'flex-1'
}`}
/>
</View>
)
}
@@ -2,6 +2,7 @@ import Button from './Button'
import { Cell, CellGroup } from './Cell'
import Checkbox from './Checkbox'
import DatePicker from './DatePicker'
import Divider from './Divider'
import Form, { FormRef } from './Form'
import FormItem from './FormItem'
import Input from './Input'
@@ -16,6 +17,7 @@ export {
CellGroup as ACellGroup,
Checkbox as ACheckbox,
DatePicker as ADatePicker,
Divider as ADivider,
Form as AForm,
FormItem as AFormItem,
FormRef as AFormRef,
@@ -0,0 +1,331 @@
'use client';
import React from 'react';
import { createAccordion } from '@gluestack-ui/core/accordion/creator';
import { View, Pressable, Text, Platform, TextProps } from 'react-native';
import { tva } from '@gluestack-ui/utils/nativewind-utils';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import {
withStyleContext,
useStyleContext,
} from '@gluestack-ui/utils/nativewind-utils';
import { H3 } from '@expo/html-elements';
import { cssInterop } from 'nativewind';
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator';
const SCOPE = 'ACCORDION';
/** Styles */
const accordionStyle = tva({
base: 'w-full',
variants: {
variant: {
filled: 'bg-white shadow-hard-2',
unfilled: '',
},
size: {
sm: '',
md: '',
lg: '',
},
},
});
const accordionItemStyle = tva({
base: '',
parentVariants: {
variant: {
filled: 'bg-background-0',
unfilled: 'bg-transparent',
},
},
});
const accordionTitleTextStyle = tva({
base: 'text-typography-900 font-bold flex-1 text-left',
parentVariants: {
size: {
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg',
},
},
});
const accordionIconStyle = tva({
base: 'text-typography-900 fill-none',
parentVariants: {
size: {
'2xs': 'h-3 w-3',
'xs': 'h-3.5 w-3.5',
'sm': 'h-4 w-4',
'md': 'h-[18px] w-[18px]',
'lg': 'h-5 w-5',
'xl': 'h-6 w-6',
},
},
});
const accordionContentTextStyle = tva({
base: 'text-typography-700 font-normal',
parentVariants: {
size: {
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg',
},
},
});
const accordionHeaderStyle = tva({
base: 'mx-0 my-0',
});
const accordionContentStyle = tva({
base: 'pt-1 pb-3 px-4',
});
const accordionTriggerStyle = tva({
base: 'w-full flex-row justify-between items-center web:outline-none focus:outline-none data-[disabled=true]:opacity-40 data-[disabled=true]:cursor-not-allowed data-[focus-visible=true]:bg-background-50 py-3 px-4',
});
const Root = withStyleContext(View, SCOPE);
const Header = (
Platform.OS === 'web' ? H3 : View
) as React.ComponentType<TextProps>;
/** Creator */
const UIAccordion = createAccordion({
Root: Root,
Item: View,
Header: Header,
Trigger: Pressable,
Icon: UIIcon,
TitleText: Text,
ContentText: Text,
Content: View,
});
cssInterop(PrimitiveIcon, {
className: {
target: 'style',
nativeStyleToProp: {
height: true,
width: true,
fill: true,
color: 'classNameColor',
stroke: true,
},
},
});
cssInterop(H3, {
className: {
target: 'style',
},
});
type IAccordionProps = React.ComponentPropsWithoutRef<typeof UIAccordion> &
VariantProps<typeof accordionStyle>;
type IAccordionItemProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.Item
> &
VariantProps<typeof accordionItemStyle>;
type IAccordionContentProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.Content
> &
VariantProps<typeof accordionContentStyle>;
type IAccordionContentTextProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.ContentText
> &
VariantProps<typeof accordionContentTextStyle>;
type IAccordionIconProps = VariantProps<typeof accordionIconStyle> &
React.ComponentPropsWithoutRef<typeof UIAccordion.Icon> & {
as?: React.ElementType;
height?: number;
width?: number;
};
type IAccordionHeaderProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.Header
> &
VariantProps<typeof accordionHeaderStyle>;
type IAccordionTriggerProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.Trigger
> &
VariantProps<typeof accordionTriggerStyle>;
type IAccordionTitleTextProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.TitleText
> &
VariantProps<typeof accordionTitleTextStyle>;
/** Components */
const Accordion = React.forwardRef<
React.ComponentRef<typeof UIAccordion>,
IAccordionProps
>(({ className, variant = 'filled', size = 'md', ...props }, ref) => {
return (
<UIAccordion
ref={ref}
{...props}
className={accordionStyle({ variant, class: className })}
context={{ variant, size }}
/>
);
});
const AccordionItem = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Item>,
IAccordionItemProps
>(({ className, ...props }, ref) => {
const { variant } = useStyleContext(SCOPE);
return (
<UIAccordion.Item
ref={ref}
{...props}
className={accordionItemStyle({
parentVariants: { variant },
class: className,
})}
/>
);
});
const AccordionContent = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Content>,
IAccordionContentProps
>(function AccordionContent({ className, ...props }, ref) {
return (
<UIAccordion.Content
ref={ref}
{...props}
className={accordionContentStyle({
class: className,
})}
/>
);
});
const AccordionContentText = React.forwardRef<
React.ComponentRef<typeof UIAccordion.ContentText>,
IAccordionContentTextProps
>(function AccordionContentText({ className, ...props }, ref) {
const { size } = useStyleContext(SCOPE);
return (
<UIAccordion.ContentText
ref={ref}
{...props}
className={accordionContentTextStyle({
parentVariants: { size },
class: className,
})}
/>
);
});
const AccordionIcon = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Icon>,
IAccordionIconProps
>(function AccordionIcon({ size, className, ...props }, ref) {
const { size: parentSize } = useStyleContext(SCOPE);
if (typeof size === 'number') {
return (
<UIAccordion.Icon
ref={ref}
{...props}
className={accordionIconStyle({ class: className })}
size={size}
/>
);
} else if (
(props.height !== undefined || props.width !== undefined) &&
size === undefined
) {
return (
<UIAccordion.Icon
ref={ref}
{...props}
className={accordionIconStyle({ class: className })}
/>
);
}
return (
<UIAccordion.Icon
ref={ref}
{...props}
className={accordionIconStyle({
size,
class: className,
parentVariants: { size: parentSize },
})}
/>
);
});
const AccordionHeader = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Header>,
IAccordionHeaderProps
>(function AccordionHeader({ className, ...props }, ref) {
return (
<UIAccordion.Header
ref={ref}
{...props}
className={accordionHeaderStyle({
class: className,
})}
/>
);
});
const AccordionTrigger = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Trigger>,
IAccordionTriggerProps
>(function AccordionTrigger({ className, ...props }, ref) {
return (
<UIAccordion.Trigger
ref={ref}
{...props}
className={accordionTriggerStyle({
class: className,
})}
/>
);
});
const AccordionTitleText = React.forwardRef<
React.ComponentRef<typeof UIAccordion.TitleText>,
IAccordionTitleTextProps
>(function AccordionTitleText({ className, ...props }, ref) {
const { size } = useStyleContext(SCOPE);
return (
<UIAccordion.TitleText
ref={ref}
{...props}
className={accordionTitleTextStyle({
parentVariants: { size },
class: className,
})}
/>
);
});
Accordion.displayName = 'Accordion';
AccordionItem.displayName = 'AccordionItem';
AccordionHeader.displayName = 'AccordionHeader';
AccordionTrigger.displayName = 'AccordionTrigger';
AccordionTitleText.displayName = 'AccordionTitleText';
AccordionContentText.displayName = 'AccordionContentText';
AccordionIcon.displayName = 'AccordionIcon';
AccordionContent.displayName = 'AccordionContent';
export {
Accordion,
AccordionItem,
AccordionHeader,
AccordionTrigger,
AccordionTitleText,
AccordionContentText,
AccordionIcon,
AccordionContent,
};
@@ -0,0 +1,220 @@
import React, { forwardRef, memo } from 'react';
import { H1, H2, H3, H4, H5, H6 } from '@expo/html-elements';
import { headingStyle } from './styles';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { cssInterop } from 'nativewind';
type IHeadingProps = VariantProps<typeof headingStyle> &
React.ComponentPropsWithoutRef<typeof H1> & {
as?: React.ElementType;
};
cssInterop(H1, { className: 'style' });
cssInterop(H2, { className: 'style' });
cssInterop(H3, { className: 'style' });
cssInterop(H4, { className: 'style' });
cssInterop(H5, { className: 'style' });
cssInterop(H6, { className: 'style' });
const MappedHeading = memo(
forwardRef<React.ComponentRef<typeof H1>, IHeadingProps>(
function MappedHeading(
{
size,
className,
isTruncated,
bold,
underline,
strikeThrough,
sub,
italic,
highlight,
...props
},
ref
) {
switch (size) {
case '5xl':
case '4xl':
case '3xl':
return (
<H1
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case '2xl':
return (
<H2
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case 'xl':
return (
<H3
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case 'lg':
return (
<H4
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case 'md':
return (
<H5
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case 'sm':
case 'xs':
return (
<H6
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
default:
return (
<H4
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
}
}
)
);
const Heading = memo(
forwardRef<React.ComponentRef<typeof H1>, IHeadingProps>(function Heading(
{ className, size = 'lg', as: AsComp, ...props },
ref
) {
const {
isTruncated,
bold,
underline,
strikeThrough,
sub,
italic,
highlight,
} = props;
if (AsComp) {
return (
<AsComp
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
/>
);
}
return (
<MappedHeading className={className} size={size} ref={ref} {...props} />
);
})
);
Heading.displayName = 'Heading';
export { Heading };
@@ -0,0 +1,202 @@
import React, { forwardRef, memo } from 'react';
import { headingStyle } from './styles';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
type IHeadingProps = VariantProps<typeof headingStyle> &
React.ComponentPropsWithoutRef<'h1'> & {
as?: React.ElementType;
};
const MappedHeading = memo(
forwardRef<HTMLHeadingElement, IHeadingProps>(function MappedHeading(
{
size,
className,
isTruncated,
bold,
underline,
strikeThrough,
sub,
italic,
highlight,
...props
},
ref
) {
switch (size) {
case '5xl':
case '4xl':
case '3xl':
return (
<h1
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case '2xl':
return (
<h2
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case 'xl':
return (
<h3
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case 'lg':
return (
<h4
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case 'md':
return (
<h5
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case 'sm':
case 'xs':
return (
<h6
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
default:
return (
<h4
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
})
);
const Heading = memo(
forwardRef<HTMLHeadingElement, IHeadingProps>(function Heading(
{ className, size = 'lg', as: AsComp, ...props },
ref
) {
const {
isTruncated,
bold,
underline,
strikeThrough,
sub,
italic,
highlight,
} = props;
if (AsComp) {
return (
<AsComp
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
return (
<MappedHeading className={className} size={size} ref={ref} {...props} />
);
})
);
Heading.displayName = 'Heading';
export { Heading };
@@ -0,0 +1,43 @@
import { tva } from '@gluestack-ui/utils/nativewind-utils';
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'font-sans tracking-sm bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word'
: '';
export const headingStyle = tva({
base: `text-typography-900 font-bold font-heading tracking-sm my-0 ${baseStyle}`,
variants: {
isTruncated: {
true: 'truncate',
},
bold: {
true: 'font-bold',
},
underline: {
true: 'underline',
},
strikeThrough: {
true: 'line-through',
},
sub: {
true: 'text-xs',
},
italic: {
true: 'italic',
},
highlight: {
true: 'bg-yellow-500',
},
size: {
'5xl': 'text-6xl',
'4xl': 'text-5xl',
'3xl': 'text-4xl',
'2xl': 'text-3xl',
'xl': 'text-2xl',
'lg': 'text-xl',
'md': 'text-lg',
'sm': 'text-base',
'xs': 'text-sm',
},
},
});
@@ -0,0 +1,27 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { View } from 'react-native';
import type { ViewProps } from 'react-native';
import { hstackStyle } from './styles';
type IHStackProps = ViewProps & VariantProps<typeof hstackStyle>;
const HStack = React.forwardRef<React.ComponentRef<typeof View>, IHStackProps>(
function HStack({ className, space, reversed, ...props }, ref) {
return (
<View
className={hstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
HStack.displayName = 'HStack';
export { HStack };
@@ -0,0 +1,26 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { hstackStyle } from './styles';
type IHStackProps = React.ComponentPropsWithoutRef<'div'> &
VariantProps<typeof hstackStyle>;
const HStack = React.forwardRef<React.ComponentRef<'div'>, IHStackProps>(
function HStack({ className, space, reversed, ...props }, ref) {
return (
<div
className={hstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
HStack.displayName = 'HStack';
export { HStack };
@@ -0,0 +1,25 @@
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
import { tva } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'flex relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none'
: '';
export const hstackStyle = tva({
base: `flex-row ${baseStyle}`,
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: 'flex-row-reverse',
},
},
});
@@ -0,0 +1,48 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { Text as RNText } from 'react-native';
import { textStyle } from './styles';
type ITextProps = React.ComponentProps<typeof RNText> &
VariantProps<typeof textStyle>;
const Text = React.forwardRef<React.ComponentRef<typeof RNText>, ITextProps>(
function Text(
{
className,
isTruncated,
bold,
underline,
strikeThrough,
size = 'md',
sub,
italic,
highlight,
...props
},
ref
) {
return (
<RNText
className={textStyle({
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
size,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
Text.displayName = 'Text';
export { Text };
@@ -0,0 +1,45 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { textStyle } from './styles';
type ITextProps = React.ComponentProps<'span'> & VariantProps<typeof textStyle>;
const Text = React.forwardRef<React.ComponentRef<'span'>, ITextProps>(
function Text(
{
className,
isTruncated,
bold,
underline,
strikeThrough,
size = 'md',
sub,
italic,
highlight,
...props
}: { className?: string } & ITextProps,
ref
) {
return (
<span
className={textStyle({
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
size,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
Text.displayName = 'Text';
export { Text };
@@ -0,0 +1,47 @@
import { tva } from '@gluestack-ui/utils/nativewind-utils';
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'font-sans tracking-sm my-0 bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word'
: '';
export const textStyle = tva({
base: `text-typography-700 font-body ${baseStyle}`,
variants: {
isTruncated: {
true: 'web:truncate',
},
bold: {
true: 'font-bold',
},
underline: {
true: 'underline',
},
strikeThrough: {
true: 'line-through',
},
size: {
'2xs': 'text-2xs',
'xs': 'text-xs',
'sm': 'text-sm',
'md': 'text-base',
'lg': 'text-lg',
'xl': 'text-xl',
'2xl': 'text-2xl',
'3xl': 'text-3xl',
'4xl': 'text-4xl',
'5xl': 'text-5xl',
'6xl': 'text-6xl',
},
sub: {
true: 'text-xs',
},
italic: {
true: 'italic',
},
highlight: {
true: 'bg-yellow-500',
},
},
});
@@ -0,0 +1,28 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { View } from 'react-native';
import { vstackStyle } from './styles';
type IVStackProps = React.ComponentProps<typeof View> &
VariantProps<typeof vstackStyle>;
const VStack = React.forwardRef<React.ComponentRef<typeof View>, IVStackProps>(
function VStack({ className, space, reversed, ...props }, ref) {
return (
<View
className={vstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
VStack.displayName = 'VStack';
export { VStack };
@@ -0,0 +1,27 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { vstackStyle } from './styles';
type IVStackProps = React.ComponentProps<'div'> &
VariantProps<typeof vstackStyle>;
const VStack = React.forwardRef<React.ComponentRef<'div'>, IVStackProps>(
function VStack({ className, space, reversed, ...props }, ref) {
return (
<div
className={vstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
VStack.displayName = 'VStack';
export { VStack };
@@ -0,0 +1,25 @@
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
import { tva } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'flex flex-col relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none'
: '';
export const vstackStyle = tva({
base: `flex-col ${baseStyle}`,
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: 'flex-col-reverse',
},
},
});
@@ -32,8 +32,8 @@ function isWhiteListed(url: string) {
}
const alovaInstance = createAlova({
// baseURL: 'http://192.168.5.6:8086/app',
baseURL: 'http://192.168.1.136:8086/app',
baseURL: 'http://192.168.5.6:8086/app',
// baseURL: 'http://192.168.1.136:8086/app',
requestAdapter: axiosRequestAdapter(),
timeout: 5000,
cacheFor: null,