From d118df7e9ae794b6f0c928bf4833f4f39b477cc3 Mon Sep 17 00:00:00 2001 From: Peace Date: Wed, 3 Sep 2025 17:10:05 +0900 Subject: [PATCH] mfe --- mobile/app/(tabs)/_layout.tsx | 9 + mobile/app/(tabs)/todo.tsx | 114 ++ .../components/containers/todo-container.tsx | 64 + mobile/components/ui/checkbox/index.tsx | 242 +++ mobile/components/ui/form-control/index.tsx | 468 +++++ mobile/components/ui/hstack/index.tsx | 27 + mobile/components/ui/hstack/index.web.tsx | 26 + mobile/components/ui/hstack/styles.tsx | 25 + mobile/components/ui/icon/index.tsx | 1600 +++++++++++++++++ mobile/components/ui/icon/index.web.tsx | 1573 ++++++++++++++++ mobile/components/ui/input/index.tsx | 434 ++--- mobile/package-lock.json | 166 +- mobile/package.json | 14 +- 13 files changed, 4515 insertions(+), 247 deletions(-) create mode 100644 mobile/app/(tabs)/todo.tsx create mode 100644 mobile/components/containers/todo-container.tsx create mode 100644 mobile/components/ui/checkbox/index.tsx create mode 100644 mobile/components/ui/form-control/index.tsx create mode 100644 mobile/components/ui/hstack/index.tsx create mode 100644 mobile/components/ui/hstack/index.web.tsx create mode 100644 mobile/components/ui/hstack/styles.tsx create mode 100644 mobile/components/ui/icon/index.tsx create mode 100644 mobile/components/ui/icon/index.web.tsx diff --git a/mobile/app/(tabs)/_layout.tsx b/mobile/app/(tabs)/_layout.tsx index 6d635ef..a63740c 100644 --- a/mobile/app/(tabs)/_layout.tsx +++ b/mobile/app/(tabs)/_layout.tsx @@ -45,6 +45,15 @@ export default function TabsLayout() { ), }} /> + ( + + ), + }} + /> ([]); + + // 초기 로드 + useEffect(() => { + (async () => { + try { + const raw = await AsyncStorage.getItem(STORAGE_KEY); + if (raw) { + const parsed = JSON.parse(raw) as Todo[]; + setTodos(parsed); + } + } catch (e) { + console.warn("Failed to load todos: ", e); + } + })(); + }, []); + + // 변경 시 저장 (디바운스 300ms) + const saveTimer = useRef | null>(null); + useEffect(() => { + if (saveTimer.current) clearTimeout(saveTimer.current); + saveTimer.current = setTimeout(async () => { + try { + await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(todos)); + } catch (e) { + console.warn("Failed to save todos: ", e); + } + }, 300); + + return () => { + if (saveTimer.current) clearTimeout(saveTimer.current); + }; + }, [todos]); + + const addTodo = (task: string) => { + const lastTodo = todos[todos?.length - 1]; + if (lastTodo?.task !== "" && task !== "") { + setTodos([ + ...todos, + { + id: uuid.v4(), + task: task, + completed: false, + }, + ]); + setItem(""); + } + }; + + const toggleTodo = (id: string) => { + const updatedTodos = todos?.map((todo) => { + if (todo.id === id) { + todo.completed = !todo.completed; + } + return todo; + }); + setTodos(updatedTodos); + }; + + const deleteTodo = (id: string) => { + const updatedTodos = todos.filter((todo) => todo.id !== id); + setTodos(updatedTodos); + }; + + return ( + + + + + setItem(value)} + onSubmitEditing={() => addTodo(item)} + /> + addTodo(item)}> + + + + + {todos?.map((todo: Todo, index: number) => ( + + ))} + + + ); +} diff --git a/mobile/components/containers/todo-container.tsx b/mobile/components/containers/todo-container.tsx new file mode 100644 index 0000000..0febd5c --- /dev/null +++ b/mobile/components/containers/todo-container.tsx @@ -0,0 +1,64 @@ +import { + Checkbox, + CheckboxIcon, + CheckboxIndicator, + CheckboxLabel, +} from "../ui/checkbox"; +import { HStack } from "../ui/hstack"; +import { CheckIcon, CloseIcon, Icon } from "../ui/icon"; +import { Pressable } from "../ui/pressable"; + +export interface Todo { + id: string; + task: string; + completed: boolean; +} + +const TodoContainer = ({ + todo, + toggleTodo, + deleteTodo, + ...props +}: { + todo: Todo; + toggleTodo: (id: string) => void; + deleteTodo: (id: string) => void; +}) => { + return ( + + toggleTodo(todo.id)} + size="sm" + aria-label={todo.task} + value={todo.task} + isChecked={todo.completed} + className="pl-6 py-2 flex-1" + > + + + + + {todo.task} + + + deleteTodo(todo.id)}> + {(state: any) => { + return ( + + ); + }} + + + ); +}; + +export default TodoContainer; diff --git a/mobile/components/ui/checkbox/index.tsx b/mobile/components/ui/checkbox/index.tsx new file mode 100644 index 0000000..27b03d5 --- /dev/null +++ b/mobile/components/ui/checkbox/index.tsx @@ -0,0 +1,242 @@ +'use client'; +import React from 'react'; +import { createCheckbox } from '@gluestack-ui/core/checkbox/creator'; +import { View, Pressable, Text, Platform } from 'react-native'; +import type { TextProps, ViewProps } from 'react-native'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { + PrimitiveIcon, + IPrimitiveIcon, + UIIcon, +} from '@gluestack-ui/core/icon/creator'; +import { + withStyleContext, + useStyleContext, +} from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; + +const IndicatorWrapper = React.forwardRef< + React.ComponentRef, + ViewProps +>(function IndicatorWrapper({ ...props }, ref) { + return ; +}); + +const LabelWrapper = React.forwardRef< + React.ComponentRef, + TextProps +>(function LabelWrapper({ ...props }, ref) { + return ; +}); + +const IconWrapper = React.forwardRef< + React.ComponentRef, + IPrimitiveIcon +>(function IconWrapper({ ...props }, ref) { + return ; +}); + +const SCOPE = 'CHECKBOX'; +const UICheckbox = createCheckbox({ + // @ts-expect-error : internal implementation for r-19/react-native-web + Root: + Platform.OS === 'web' + ? withStyleContext(View, SCOPE) + : withStyleContext(Pressable, SCOPE), + Group: View, + Icon: IconWrapper, + Label: LabelWrapper, + Indicator: IndicatorWrapper, +}); + +cssInterop(PrimitiveIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: 'classNameColor', + stroke: true, + }, + }, +}); + +const checkboxStyle = tva({ + base: 'group/checkbox flex-row items-center justify-start web:cursor-pointer data-[disabled=true]:cursor-not-allowed', + variants: { + size: { + lg: 'gap-2', + md: 'gap-2', + sm: 'gap-1.5', + }, + }, +}); + +const checkboxIndicatorStyle = tva({ + base: 'justify-center items-center border-outline-400 bg-transparent rounded web:data-[focus-visible=true]:outline-none web:data-[focus-visible=true]:ring-2 web:data-[focus-visible=true]:ring-indicator-primary data-[checked=true]:bg-primary-600 data-[checked=true]:border-primary-600 data-[hover=true]:data-[checked=false]:border-outline-500 data-[hover=true]:bg-transparent data-[hover=true]:data-[invalid=true]:border-error-700 data-[hover=true]:data-[checked=true]:bg-primary-700 data-[hover=true]:data-[checked=true]:border-primary-700 data-[hover=true]:data-[checked=true]:data-[disabled=true]:border-primary-600 data-[hover=true]:data-[checked=true]:data-[disabled=true]:bg-primary-600 data-[hover=true]:data-[checked=true]:data-[disabled=true]:opacity-40 data-[hover=true]:data-[checked=true]:data-[disabled=true]:data-[invalid=true]:border-error-700 data-[hover=true]:data-[disabled=true]:border-outline-400 data-[hover=true]:data-[disabled=true]:data-[invalid=true]:border-error-700 data-[active=true]:data-[checked=true]:bg-primary-800 data-[active=true]:data-[checked=true]:border-primary-800 data-[invalid=true]:border-error-700 data-[disabled=true]:opacity-40', + parentVariants: { + size: { + lg: 'w-6 h-6 border-[3px]', + md: 'w-5 h-5 border-2', + sm: 'w-4 h-4 border-2', + }, + }, +}); + +const checkboxLabelStyle = tva({ + base: 'text-typography-600 data-[checked=true]:text-typography-900 data-[hover=true]:text-typography-900 data-[hover=true]:data-[checked=true]:text-typography-900 data-[hover=true]:data-[checked=true]:data-[disabled=true]:text-typography-900 data-[hover=true]:data-[disabled=true]:text-typography-400 data-[active=true]:text-typography-900 data-[active=true]:data-[checked=true]:text-typography-900 data-[disabled=true]:opacity-40 web:select-none', + parentVariants: { + size: { + lg: 'text-lg', + md: 'text-base', + sm: 'text-sm', + }, + }, +}); + +const checkboxIconStyle = tva({ + base: 'text-typography-50 fill-none', + + parentVariants: { + size: { + sm: 'h-3 w-3', + md: 'h-4 w-4', + lg: 'h-5 w-5', + }, + }, +}); + +const CheckboxGroup = UICheckbox.Group; + +type ICheckboxProps = React.ComponentPropsWithoutRef & + VariantProps; + +const Checkbox = React.forwardRef< + React.ComponentRef, + ICheckboxProps +>(function Checkbox({ className, size = 'md', ...props }, ref) { + return ( + + ); +}); + +type ICheckboxIndicatorProps = React.ComponentPropsWithoutRef< + typeof UICheckbox.Indicator +> & + VariantProps; + +const CheckboxIndicator = React.forwardRef< + React.ComponentRef, + ICheckboxIndicatorProps +>(function CheckboxIndicator({ className, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +type ICheckboxLabelProps = React.ComponentPropsWithoutRef< + typeof UICheckbox.Label +> & + VariantProps; +const CheckboxLabel = React.forwardRef< + React.ComponentRef, + ICheckboxLabelProps +>(function CheckboxLabel({ className, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + return ( + + ); +}); + +type ICheckboxIconProps = React.ComponentPropsWithoutRef< + typeof UICheckbox.Icon +> & + VariantProps; + +const CheckboxIcon = React.forwardRef< + React.ComponentRef, + ICheckboxIconProps +>(function CheckboxIcon({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + + return ( + + ); +}); + +Checkbox.displayName = 'Checkbox'; +CheckboxIndicator.displayName = 'CheckboxIndicator'; +CheckboxLabel.displayName = 'CheckboxLabel'; +CheckboxIcon.displayName = 'CheckboxIcon'; + +export { + Checkbox, + CheckboxIndicator, + CheckboxLabel, + CheckboxIcon, + CheckboxGroup, +}; diff --git a/mobile/components/ui/form-control/index.tsx b/mobile/components/ui/form-control/index.tsx new file mode 100644 index 0000000..5f8ab09 --- /dev/null +++ b/mobile/components/ui/form-control/index.tsx @@ -0,0 +1,468 @@ +'use client'; +import { Text, View } from 'react-native'; +import React from 'react'; +import { createFormControl } from '@gluestack-ui/core/form-control/creator'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { + withStyleContext, + useStyleContext, +} from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; + +const SCOPE = 'FORM_CONTROL'; + +const formControlStyle = tva({ + base: 'flex flex-col', + variants: { + size: { + sm: '', + md: '', + lg: '', + }, + }, +}); + +const formControlErrorIconStyle = tva({ + base: 'text-error-700 fill-none', + variants: { + 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 formControlErrorStyle = tva({ + base: 'flex flex-row justify-start items-center mt-1 gap-1', +}); + +const formControlErrorTextStyle = tva({ + base: 'text-error-700', + 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', + }, + }, +}); + +const formControlHelperStyle = tva({ + base: 'flex flex-row justify-start items-center mt-1', +}); + +const formControlHelperTextStyle = tva({ + base: 'text-typography-500', + 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-xs', + 'md': 'text-sm', + 'lg': 'text-base', + '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', + }, + }, +}); + +const formControlLabelStyle = tva({ + base: 'flex flex-row justify-start items-center mb-1', +}); + +const formControlLabelTextStyle = tva({ + base: 'font-medium text-typography-900', + 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', + }, + }, +}); + +const formControlLabelAstrickStyle = tva({ + base: 'font-medium text-typography-900', + 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', + }, + }, +}); + +type IFormControlLabelAstrickProps = React.ComponentPropsWithoutRef< + typeof Text +> & + VariantProps; + +const FormControlLabelAstrick = React.forwardRef< + React.ComponentRef, + IFormControlLabelAstrickProps +>(function FormControlLabelAstrick({ className, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +export const UIFormControl = createFormControl({ + Root: withStyleContext(View, SCOPE), + Error: View, + ErrorText: Text, + ErrorIcon: UIIcon, + Label: View, + LabelText: Text, + LabelAstrick: FormControlLabelAstrick, + Helper: View, + HelperText: Text, +}); + +cssInterop(PrimitiveIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: true, + stroke: true, + }, + }, +}); + +type IFormControlProps = React.ComponentProps & + VariantProps; + +const FormControl = React.forwardRef< + React.ComponentRef, + IFormControlProps +>(function FormControl({ className, size = 'md', ...props }, ref) { + return ( + + ); +}); + +type IFormControlErrorProps = React.ComponentProps & + VariantProps; + +const FormControlError = React.forwardRef< + React.ComponentRef, + IFormControlErrorProps +>(function FormControlError({ className, ...props }, ref) { + return ( + + ); +}); + +type IFormControlErrorTextProps = React.ComponentProps< + typeof UIFormControl.Error.Text +> & + VariantProps; + +const FormControlErrorText = React.forwardRef< + React.ComponentRef, + IFormControlErrorTextProps +>(function FormControlErrorText({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + return ( + + ); +}); + +type IFormControlErrorIconProps = React.ComponentProps< + typeof UIFormControl.Error.Icon +> & + VariantProps & { + height?: number; + width?: number; + }; + +const FormControlErrorIcon = React.forwardRef< + React.ComponentRef, + IFormControlErrorIconProps +>(function FormControlErrorIcon({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); +}); + +type IFormControlLabelProps = React.ComponentProps & + VariantProps; + +const FormControlLabel = React.forwardRef< + React.ComponentRef, + IFormControlLabelProps +>(function FormControlLabel({ className, ...props }, ref) { + return ( + + ); +}); + +type IFormControlLabelTextProps = React.ComponentProps< + typeof UIFormControl.Label.Text +> & + VariantProps; + +const FormControlLabelText = React.forwardRef< + React.ComponentRef, + IFormControlLabelTextProps +>(function FormControlLabelText({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +type IFormControlHelperProps = React.ComponentProps< + typeof UIFormControl.Helper +> & + VariantProps; + +const FormControlHelper = React.forwardRef< + React.ComponentRef, + IFormControlHelperProps +>(function FormControlHelper({ className, ...props }, ref) { + return ( + + ); +}); + +type IFormControlHelperTextProps = React.ComponentProps< + typeof UIFormControl.Helper.Text +> & + VariantProps; + +const FormControlHelperText = React.forwardRef< + React.ComponentRef, + IFormControlHelperTextProps +>(function FormControlHelperText({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +FormControl.displayName = 'FormControl'; +FormControlError.displayName = 'FormControlError'; +FormControlErrorText.displayName = 'FormControlErrorText'; +FormControlErrorIcon.displayName = 'FormControlErrorIcon'; +FormControlLabel.displayName = 'FormControlLabel'; +FormControlLabelText.displayName = 'FormControlLabelText'; +FormControlLabelAstrick.displayName = 'FormControlLabelAstrick'; +FormControlHelper.displayName = 'FormControlHelper'; +FormControlHelperText.displayName = 'FormControlHelperText'; + +export { + FormControl, + FormControlError, + FormControlErrorText, + FormControlErrorIcon, + FormControlLabel, + FormControlLabelText, + FormControlLabelAstrick, + FormControlHelper, + FormControlHelperText, +}; diff --git a/mobile/components/ui/hstack/index.tsx b/mobile/components/ui/hstack/index.tsx new file mode 100644 index 0000000..725dabb --- /dev/null +++ b/mobile/components/ui/hstack/index.tsx @@ -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; + +const HStack = React.forwardRef, IHStackProps>( + function HStack({ className, space, reversed, ...props }, ref) { + return ( + + ); + } +); + +HStack.displayName = 'HStack'; + +export { HStack }; diff --git a/mobile/components/ui/hstack/index.web.tsx b/mobile/components/ui/hstack/index.web.tsx new file mode 100644 index 0000000..39f1e40 --- /dev/null +++ b/mobile/components/ui/hstack/index.web.tsx @@ -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; + +const HStack = React.forwardRef, IHStackProps>( + function HStack({ className, space, reversed, ...props }, ref) { + return ( +
+ ); + } +); + +HStack.displayName = 'HStack'; + +export { HStack }; diff --git a/mobile/components/ui/hstack/styles.tsx b/mobile/components/ui/hstack/styles.tsx new file mode 100644 index 0000000..a070e45 --- /dev/null +++ b/mobile/components/ui/hstack/styles.tsx @@ -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', + }, + }, +}); diff --git a/mobile/components/ui/icon/index.tsx b/mobile/components/ui/icon/index.tsx new file mode 100644 index 0000000..3d9ef61 --- /dev/null +++ b/mobile/components/ui/icon/index.tsx @@ -0,0 +1,1600 @@ +import React from 'react'; +import { createIcon } from '@gluestack-ui/core/icon/creator'; +import { Path } from 'react-native-svg'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { + PrimitiveIcon, + IPrimitiveIcon, + Svg, +} from '@gluestack-ui/core/icon/creator'; + +export const UIIcon = createIcon({ + Root: PrimitiveIcon, +}) as React.ForwardRefExoticComponent< + React.ComponentPropsWithoutRef & + React.RefAttributes> +>; + +const iconStyle = tva({ + base: 'text-typography-950 fill-none stroke-current pointer-events-none', + variants: { + 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', + }, + }, +}); + +cssInterop(UIIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: true, + stroke: true, + }, + }, +}); + +type IIConProps = IPrimitiveIcon & + VariantProps & + React.ComponentPropsWithoutRef; + +const Icon = React.forwardRef, IIConProps>( + function Icon({ size = 'md', className, ...props }, ref) { + const iconProps = { + fill: 'none', + stroke: 'currentColor', + ...props, + }; + + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); + } +); + +export { Icon }; + +type ParameterTypes = Omit[0], 'Root'>; + +const createIconUI = ({ ...props }: ParameterTypes) => { + const UIIconCreateIcon = createIcon({ + Root: Svg, + ...props, + }) as React.ForwardRefExoticComponent< + React.ComponentPropsWithoutRef & + React.RefAttributes> + >; + + return React.forwardRef>(function UIIcon( + { + className, + size, + ...inComingProps + }: VariantProps & + React.ComponentPropsWithoutRef, + ref + ) { + const iconProps = { + fill: 'none', + stroke: 'currentColor', + ...inComingProps, + }; + + return ( + + ); + }); +}; +export { createIconUI as createIcon }; +// All Icons +const AddIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +AddIcon.displayName = 'AddIcon'; +export { AddIcon }; + +const AlertCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +AlertCircleIcon.displayName = 'AlertCircleIcon'; +export { AlertCircleIcon }; + +const ArrowUpIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowDownIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowLeftIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ArrowUpIcon.displayName = 'ArrowUpIcon'; +ArrowDownIcon.displayName = 'ArrowDownIcon'; +ArrowRightIcon.displayName = 'ArrowRightIcon'; +ArrowLeftIcon.displayName = 'ArrowLeftIcon'; + +export { ArrowUpIcon, ArrowDownIcon, ArrowRightIcon, ArrowLeftIcon }; + +const AtSignIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + <> + + + + + ), +}); + +AtSignIcon.displayName = 'AtSignIcon'; + +export { AtSignIcon }; + +const BellIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +BellIcon.displayName = 'BellIcon'; + +export { BellIcon }; + +const CalendarDaysIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + + ), +}); + +CalendarDaysIcon.displayName = 'CalendarDaysIcon'; + +export { CalendarDaysIcon }; + +const CheckIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const CheckCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CheckIcon.displayName = 'CheckIcon'; +CheckCircleIcon.displayName = 'CheckCircleIcon'; + +export { CheckIcon, CheckCircleIcon }; + +const ChevronUpIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + d: 'M12 10L8 6L4 10', + path: ( + <> + + + ), +}); + +const ChevronDownIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronLeftIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronsLeftIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsUpDownIcon = createIcon({ + Root: Svg, + + 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: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +CircleIcon.displayName = 'CircleIcon'; + +export { CircleIcon }; + +const ClockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ClockIcon.displayName = 'ClockIcon'; + +export { ClockIcon }; + +const CloseIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const CloseCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +CloseIcon.displayName = 'CloseIcon'; +CloseCircleIcon.displayName = 'CloseCircleIcon'; + +export { CloseIcon, CloseCircleIcon }; + +const CopyIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CopyIcon.displayName = 'CopyIcon'; + +export { CopyIcon }; + +const DownloadIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +DownloadIcon.displayName = 'DownloadIcon'; +export { DownloadIcon }; + +const EditIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EditIcon.displayName = 'EditIcon'; +export { EditIcon }; + +const EyeIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EyeIcon.displayName = 'EyeIcon'; + +const EyeOffIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +EyeOffIcon.displayName = 'EyeOffIcon'; +export { EyeIcon, EyeOffIcon }; + +const FavouriteIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +FavouriteIcon.displayName = 'FavouriteIcon'; +export { FavouriteIcon }; + +const GlobeIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +GlobeIcon.displayName = 'GlobeIcon'; +export { GlobeIcon }; + +const GripVerticalIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + ), +}); + +GripVerticalIcon.displayName = 'GripVerticalIcon'; +export { GripVerticalIcon }; + +const HelpCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +HelpCircleIcon.displayName = 'HelpCircleIcon'; +export { HelpCircleIcon }; + +const InfoIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +InfoIcon.displayName = 'InfoIcon'; +export { InfoIcon }; + +const LinkIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +LinkIcon.displayName = 'LinkIcon'; + +const ExternalLinkIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ExternalLinkIcon.displayName = 'ExternalLinkIcon'; +export { LinkIcon, ExternalLinkIcon }; + +const LoaderIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +LoaderIcon.displayName = 'LoaderIcon'; +export { LoaderIcon }; + +const LockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +LockIcon.displayName = 'LockIcon'; +export { LockIcon }; + +const MailIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +MailIcon.displayName = 'MailIcon'; +export { MailIcon }; + +const MenuIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +MenuIcon.displayName = 'MenuIcon'; +export { MenuIcon }; + +const MessageCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MessageCircleIcon.displayName = 'MessageCircleIcon'; + +export { MessageCircleIcon }; + +const MoonIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MoonIcon.displayName = 'MoonIcon'; +export { MoonIcon }; + +const PaperclipIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PaperclipIcon.displayName = 'PaperclipIcon'; +export { PaperclipIcon }; + +const PhoneIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PhoneIcon.displayName = 'PhoneIcon'; +export { PhoneIcon }; + +const PlayIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +PlayIcon.displayName = 'PlayIcon'; +export { PlayIcon }; + +const RemoveIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +RemoveIcon.displayName = 'RemoveIcon'; +export { RemoveIcon }; + +const RepeatIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +RepeatIcon.displayName = 'RepeatIcon'; + +const Repeat1Icon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +Repeat1Icon.displayName = 'Repeat1Icon'; +export { RepeatIcon, Repeat1Icon }; + +const SearchIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SearchIcon.displayName = 'SearchIcon'; +export { SearchIcon }; + +const SettingsIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SettingsIcon.displayName = 'SettingsIcon'; +export { SettingsIcon }; + +const ShareIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +ShareIcon.displayName = 'ShareIcon'; +export { ShareIcon }; + +const SlashIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SlashIcon.displayName = 'SlashIcon'; +export { SlashIcon }; + +const StarIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +StarIcon.displayName = 'StarIcon'; +export { StarIcon }; + +const SunIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + ), +}); + +SunIcon.displayName = 'SunIcon'; +export { SunIcon }; + +const ThreeDotsIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ThreeDotsIcon.displayName = 'ThreeDotsIcon'; +export { ThreeDotsIcon }; + +const TrashIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +TrashIcon.displayName = 'TrashIcon'; +export { TrashIcon }; + +const UnlockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +UnlockIcon.displayName = 'UnlockIcon'; +export { UnlockIcon }; diff --git a/mobile/components/ui/icon/index.web.tsx b/mobile/components/ui/icon/index.web.tsx new file mode 100644 index 0000000..3503efd --- /dev/null +++ b/mobile/components/ui/icon/index.web.tsx @@ -0,0 +1,1573 @@ +import React from 'react'; +import { createIcon } from '@gluestack-ui/core/icon/creator'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { PrimitiveIcon, Svg } from '@gluestack-ui/core/icon/creator'; + +export const UIIcon = createIcon({ + Root: PrimitiveIcon, +}); + +const iconStyle = tva({ + base: 'text-typography-950 fill-none pointer-events-none', + variants: { + 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', + }, + }, +}); + +export const Icon = React.forwardRef< + React.ComponentRef, + React.ComponentPropsWithoutRef & + VariantProps & { + height?: number | string; + width?: number | string; + } +>(function Icon({ size = 'md', className, ...props }, ref) { + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); +}); + +type ParameterTypes = Omit[0], 'Root'>; + +const accessClassName = (style: any) => { + const styleObject = Array.isArray(style) ? style[0] : style; + const keys = Object.keys(styleObject); + return styleObject[keys[1]]; +}; + +const createIconUI = ({ ...props }: ParameterTypes) => { + const NewUIIcon = createIcon({ Root: Svg, ...props }); + return React.forwardRef< + React.ComponentRef, + React.ComponentPropsWithoutRef & + VariantProps & { + height?: number | string; + width?: number | string; + } + >(function UIIcon({ className, ...inComingprops }, ref) { + const calculateClassName = React.useMemo(() => { + return className === undefined + ? accessClassName(inComingprops?.style) + : className; + }, [className, inComingprops?.style]); + return ( + + ); + }); +}; + +export { createIconUI as createIcon }; + +// All Icons +const AddIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +AddIcon.displayName = 'AddIcon'; +export { AddIcon }; + +const AlertCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +AlertCircleIcon.displayName = 'AlertCircleIcon'; +export { AlertCircleIcon }; + +const ArrowUpIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowDownIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowLeftIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ArrowUpIcon.displayName = 'ArrowUpIcon'; +ArrowDownIcon.displayName = 'ArrowDownIcon'; +ArrowRightIcon.displayName = 'ArrowRightIcon'; +ArrowLeftIcon.displayName = 'ArrowLeftIcon'; + +export { ArrowUpIcon, ArrowDownIcon, ArrowRightIcon, ArrowLeftIcon }; + +const AtSignIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + <> + + + + + ), +}); + +AtSignIcon.displayName = 'AtSignIcon'; + +export { AtSignIcon }; + +const BellIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +BellIcon.displayName = 'BellIcon'; + +export { BellIcon }; + +const CalendarDaysIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + + ), +}); + +CalendarDaysIcon.displayName = 'CalendarDaysIcon'; + +export { CalendarDaysIcon }; + +const CheckIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const CheckCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CheckIcon.displayName = 'CheckIcon'; +CheckCircleIcon.displayName = 'CheckCircleIcon'; + +export { CheckIcon, CheckCircleIcon }; + +const ChevronUpIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + d: 'M12 10L8 6L4 10', + path: ( + <> + + + ), +}); + +const ChevronDownIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronLeftIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronsLeftIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsUpDownIcon = createIcon({ + Root: Svg, + + 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: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +CircleIcon.displayName = 'CircleIcon'; +export { CircleIcon }; + +const ClockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ClockIcon.displayName = 'ClockIcon'; + +export { ClockIcon }; + +const CloseIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const CloseCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +CloseIcon.displayName = 'CloseIcon'; +CloseCircleIcon.displayName = 'CloseCircleIcon'; + +export { CloseIcon, CloseCircleIcon }; + +const CopyIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CopyIcon.displayName = 'CopyIcon'; + +export { CopyIcon }; + +const DownloadIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +DownloadIcon.displayName = 'DownloadIcon'; +export { DownloadIcon }; + +const EditIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EditIcon.displayName = 'EditIcon'; +export { EditIcon }; + +const EyeIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EyeIcon.displayName = 'EyeIcon'; + +const EyeOffIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +EyeOffIcon.displayName = 'EyeOffIcon'; +export { EyeIcon, EyeOffIcon }; + +const FavouriteIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +FavouriteIcon.displayName = 'FavouriteIcon'; +export { FavouriteIcon }; + +const GlobeIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +GlobeIcon.displayName = 'GlobeIcon'; +export { GlobeIcon }; + +const GripVerticalIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + ), +}); + +GripVerticalIcon.displayName = 'GripVerticalIcon'; +export { GripVerticalIcon }; + +const HelpCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +HelpCircleIcon.displayName = 'HelpCircleIcon'; +export { HelpCircleIcon }; + +const InfoIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +InfoIcon.displayName = 'InfoIcon'; +export { InfoIcon }; + +const LinkIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +LinkIcon.displayName = 'LinkIcon'; + +const ExternalLinkIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ExternalLinkIcon.displayName = 'ExternalLinkIcon'; +export { LinkIcon, ExternalLinkIcon }; + +const LoaderIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +LoaderIcon.displayName = 'LoaderIcon'; +export { LoaderIcon }; + +const LockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +LockIcon.displayName = 'LockIcon'; +export { LockIcon }; + +const MailIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +MailIcon.displayName = 'MailIcon'; +export { MailIcon }; + +const MenuIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +MenuIcon.displayName = 'MenuIcon'; +export { MenuIcon }; + +const MessageCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MessageCircleIcon.displayName = 'MessageCircleIcon'; + +export { MessageCircleIcon }; + +const MoonIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MoonIcon.displayName = 'MoonIcon'; +export { MoonIcon }; + +const PaperclipIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PaperclipIcon.displayName = 'PaperclipIcon'; +export { PaperclipIcon }; + +const PhoneIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PhoneIcon.displayName = 'PhoneIcon'; +export { PhoneIcon }; + +const PlayIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +PlayIcon.displayName = 'PlayIcon'; +export { PlayIcon }; + +const RemoveIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +RemoveIcon.displayName = 'RemoveIcon'; +export { RemoveIcon }; + +const RepeatIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +RepeatIcon.displayName = 'RepeatIcon'; + +const Repeat1Icon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +Repeat1Icon.displayName = 'Repeat1Icon'; +export { RepeatIcon, Repeat1Icon }; + +const SearchIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SearchIcon.displayName = 'SearchIcon'; +export { SearchIcon }; + +const SettingsIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SettingsIcon.displayName = 'SettingsIcon'; +export { SettingsIcon }; + +const ShareIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +ShareIcon.displayName = 'ShareIcon'; +export { ShareIcon }; + +const SlashIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SlashIcon.displayName = 'SlashIcon'; +export { SlashIcon }; + +const StarIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +StarIcon.displayName = 'StarIcon'; +export { StarIcon }; + +const SunIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + ), +}); + +SunIcon.displayName = 'SunIcon'; +export { SunIcon }; + +const ThreeDotsIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ThreeDotsIcon.displayName = 'ThreeDotsIcon'; +export { ThreeDotsIcon }; + +const TrashIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +TrashIcon.displayName = 'TrashIcon'; +export { TrashIcon }; + +const UnlockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +UnlockIcon.displayName = 'UnlockIcon'; +export { UnlockIcon }; diff --git a/mobile/components/ui/input/index.tsx b/mobile/components/ui/input/index.tsx index 03d46eb..c1fbd94 100644 --- a/mobile/components/ui/input/index.tsx +++ b/mobile/components/ui/input/index.tsx @@ -1,217 +1,217 @@ -'use client'; -import React from 'react'; -import { createInput } from '@gluestack-ui/core/input/creator'; -import { View, Pressable, TextInput } from 'react-native'; -import { tva } from '@gluestack-ui/utils/nativewind-utils'; -import { - withStyleContext, - useStyleContext, -} from '@gluestack-ui/utils/nativewind-utils'; -import { cssInterop } from 'nativewind'; -import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; -import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; - -const SCOPE = 'INPUT'; - -const UIInput = createInput({ - Root: withStyleContext(View, SCOPE), - Icon: UIIcon, - Slot: Pressable, - Input: TextInput, -}); - -cssInterop(PrimitiveIcon, { - className: { - target: 'style', - nativeStyleToProp: { - height: true, - width: true, - fill: true, - color: 'classNameColor', - stroke: true, - }, - }, -}); - -const inputStyle = tva({ - base: 'border-background-300 flex-row overflow-hidden content-center data-[hover=true]:border-outline-400 data-[focus=true]:border-primary-700 data-[focus=true]:hover:border-primary-700 data-[disabled=true]:opacity-40 data-[disabled=true]:hover:border-background-300 items-center', - - variants: { - size: { - xl: 'h-12', - lg: 'h-11', - md: 'h-10', - sm: 'h-9', - }, - - variant: { - underlined: - 'rounded-none border-b data-[invalid=true]:border-b-2 data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700', - - outline: - 'rounded border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error', - - rounded: - 'rounded-full border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error', - }, - }, -}); - -const inputIconStyle = tva({ - base: 'justify-center items-center text-typography-400 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 inputSlotStyle = tva({ - base: 'justify-center items-center web:disabled:cursor-not-allowed', -}); - -const inputFieldStyle = tva({ - base: 'flex-1 text-typography-900 py-0 px-3 placeholder:text-typography-500 h-full ios:leading-[0px] web:cursor-text web:data-[disabled=true]:cursor-not-allowed', - - parentVariants: { - variant: { - underlined: 'web:outline-0 web:outline-none px-0', - outline: 'web:outline-0 web:outline-none', - rounded: 'web:outline-0 web:outline-none px-4', - }, - - 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', - }, - }, -}); - -type IInputProps = React.ComponentProps & - VariantProps & { className?: string }; -const Input = React.forwardRef, IInputProps>( - function Input( - { className, variant = 'outline', size = 'md', ...props }, - ref - ) { - return ( - - ); - } -); - -type IInputIconProps = React.ComponentProps & - VariantProps & { - className?: string; - height?: number; - width?: number; - }; - -const InputIcon = React.forwardRef< - React.ComponentRef, - IInputIconProps ->(function InputIcon({ className, size, ...props }, ref) { - const { size: parentSize } = useStyleContext(SCOPE); - - if (typeof size === 'number') { - return ( - - ); - } else if ( - (props.height !== undefined || props.width !== undefined) && - size === undefined - ) { - return ( - - ); - } - return ( - - ); -}); - -type IInputSlotProps = React.ComponentProps & - VariantProps & { className?: string }; - -const InputSlot = React.forwardRef< - React.ComponentRef, - IInputSlotProps ->(function InputSlot({ className, ...props }, ref) { - return ( - - ); -}); - -type IInputFieldProps = React.ComponentProps & - VariantProps & { className?: string }; - -const InputField = React.forwardRef< - React.ComponentRef, - IInputFieldProps ->(function InputField({ className, ...props }, ref) { - const { variant: parentVariant, size: parentSize } = useStyleContext(SCOPE); - - return ( - - ); -}); - -Input.displayName = 'Input'; -InputIcon.displayName = 'InputIcon'; -InputSlot.displayName = 'InputSlot'; -InputField.displayName = 'InputField'; - -export { Input, InputField, InputIcon, InputSlot }; +'use client'; +import React from 'react'; +import { createInput } from '@gluestack-ui/core/input/creator'; +import { View, Pressable, TextInput } from 'react-native'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { + withStyleContext, + useStyleContext, +} from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; + +const SCOPE = 'INPUT'; + +const UIInput = createInput({ + Root: withStyleContext(View, SCOPE), + Icon: UIIcon, + Slot: Pressable, + Input: TextInput, +}); + +cssInterop(PrimitiveIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: 'classNameColor', + stroke: true, + }, + }, +}); + +const inputStyle = tva({ + base: 'border-background-300 flex-row overflow-hidden content-center data-[hover=true]:border-outline-400 data-[focus=true]:border-primary-700 data-[focus=true]:hover:border-primary-700 data-[disabled=true]:opacity-40 data-[disabled=true]:hover:border-background-300 items-center', + + variants: { + size: { + xl: 'h-12', + lg: 'h-11', + md: 'h-10', + sm: 'h-9', + }, + + variant: { + underlined: + 'rounded-none border-b data-[invalid=true]:border-b-2 data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700', + + outline: + 'rounded border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error', + + rounded: + 'rounded-full border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error', + }, + }, +}); + +const inputIconStyle = tva({ + base: 'justify-center items-center text-typography-400 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 inputSlotStyle = tva({ + base: 'justify-center items-center web:disabled:cursor-not-allowed', +}); + +const inputFieldStyle = tva({ + base: 'flex-1 text-typography-900 py-0 px-3 placeholder:text-typography-500 h-full ios:leading-[0px] web:cursor-text web:data-[disabled=true]:cursor-not-allowed', + + parentVariants: { + variant: { + underlined: 'web:outline-0 web:outline-none px-0', + outline: 'web:outline-0 web:outline-none', + rounded: 'web:outline-0 web:outline-none px-4', + }, + + 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', + }, + }, +}); + +type IInputProps = React.ComponentProps & + VariantProps & { className?: string }; +const Input = React.forwardRef, IInputProps>( + function Input( + { className, variant = 'outline', size = 'md', ...props }, + ref + ) { + return ( + + ); + } +); + +type IInputIconProps = React.ComponentProps & + VariantProps & { + className?: string; + height?: number; + width?: number; + }; + +const InputIcon = React.forwardRef< + React.ComponentRef, + IInputIconProps +>(function InputIcon({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); +}); + +type IInputSlotProps = React.ComponentProps & + VariantProps & { className?: string }; + +const InputSlot = React.forwardRef< + React.ComponentRef, + IInputSlotProps +>(function InputSlot({ className, ...props }, ref) { + return ( + + ); +}); + +type IInputFieldProps = React.ComponentProps & + VariantProps & { className?: string }; + +const InputField = React.forwardRef< + React.ComponentRef, + IInputFieldProps +>(function InputField({ className, ...props }, ref) { + const { variant: parentVariant, size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +Input.displayName = 'Input'; +InputIcon.displayName = 'InputIcon'; +InputSlot.displayName = 'InputSlot'; +InputField.displayName = 'InputField'; + +export { Input, InputField, InputIcon, InputSlot }; diff --git a/mobile/package-lock.json b/mobile/package-lock.json index 92134af..b1aeea2 100644 --- a/mobile/package-lock.json +++ b/mobile/package-lock.json @@ -13,11 +13,14 @@ "@gluestack-ui/core": "^3.0.0", "@gluestack-ui/utils": "^3.0.0", "@legendapp/motion": "^2.3.0", + "@react-native-async-storage/async-storage": "^2.2.0", "babel-plugin-module-resolver": "^5.0.2", "expo": "~53.0.22", "expo-linking": "^7.1.7", "expo-router": "^5.1.4", "expo-status-bar": "~2.2.3", + "lucide-react-native": "^0.510.0", + "nanoid": "^5.1.5", "nativewind": "^4.1.23", "react": "19.0.0", "react-aria": "^3.33.0", @@ -26,7 +29,8 @@ "react-native-reanimated": "^4.1.0", "react-native-safe-area-context": "^4.14.1", "react-native-screens": "^4.15.4", - "react-native-svg": "^15.2.0", + "react-native-svg": "^15.12.0", + "react-native-uuid": "^2.0.3", "react-native-worklets": "^0.5.0", "react-native-worklets-core": "^1.6.2", "react-stately": "^3.39.0", @@ -2095,21 +2099,6 @@ "react-native-web": ">=0.19.0" } }, - "node_modules/@gluestack-ui/core/node_modules/react-native-svg": { - "version": "15.12.1", - "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.12.1.tgz", - "integrity": "sha512-vCuZJDf8a5aNC2dlMovEv4Z0jjEUET53lm/iILFnFewa15b4atjVxU6Wirm6O9y6dEsdjDZVD7Q3QM4T1wlI8g==", - "license": "MIT", - "dependencies": { - "css-select": "^5.1.0", - "css-tree": "^1.1.3", - "warn-once": "0.1.1" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, "node_modules/@gluestack-ui/utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@gluestack-ui/utils/-/utils-3.0.0.tgz", @@ -3567,6 +3556,18 @@ "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, + "node_modules/@react-native-async-storage/async-storage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz", + "integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==", + "license": "MIT", + "dependencies": { + "merge-options": "^3.0.4" + }, + "peerDependencies": { + "react-native": "^0.0.0-0 || >=0.65 <1.0" + } + }, "node_modules/@react-native/assets-registry": { "version": "0.79.6", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.6.tgz", @@ -3894,6 +3895,24 @@ "react": ">= 18.2.0" } }, + "node_modules/@react-navigation/core/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/@react-navigation/core/node_modules/react-is": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", @@ -3957,6 +3976,24 @@ "react-native-screens": ">= 4.0.0" } }, + "node_modules/@react-navigation/native/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/@react-navigation/routers": { "version": "7.5.1", "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.1.tgz", @@ -3966,6 +4003,24 @@ "nanoid": "^3.3.11" } }, + "node_modules/@react-navigation/routers/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/@react-stately/calendar": { "version": "3.8.4", "resolved": "https://registry.npmjs.org/@react-stately/calendar/-/calendar-3.8.4.tgz", @@ -7348,6 +7403,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -8092,6 +8156,17 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react-native": { + "version": "0.510.0", + "resolved": "https://registry.npmjs.org/lucide-react-native/-/lucide-react-native-0.510.0.tgz", + "integrity": "sha512-Ggy6NyWNcb/Wp9I0Kguwab5FRjr3GYsxNi0Nmy+skur1yj9TKiF2vcXPL7zWkkcgqk8WWKiIvmN3CntWvaDR1w==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0", + "react-native": "*", + "react-native-svg": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0" + } + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -8119,6 +8194,18 @@ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", "license": "MIT" }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "license": "MIT", + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -8611,9 +8698,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz", + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==", "funding": [ { "type": "github", @@ -8622,10 +8709,10 @@ ], "license": "MIT", "bin": { - "nanoid": "bin/nanoid.cjs" + "nanoid": "bin/nanoid.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^18 || >=20" } }, "node_modules/nativewind": { @@ -9341,6 +9428,24 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -9814,19 +9919,30 @@ } }, "node_modules/react-native-svg": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.2.0.tgz", - "integrity": "sha512-R0E6IhcJfVLsL0lRmnUSm72QO+mTqcAOM5Jb8FVGxJqX3NfJMlMP0YyvcajZiaRR8CqQUpEoqrY25eyZb006kw==", + "version": "15.12.0", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.12.0.tgz", + "integrity": "sha512-iE25PxIJ6V0C6krReLquVw6R0QTsRTmEQc4K2Co3P6zsimU/jltcDBKYDy1h/5j9S/fqmMeXnpM+9LEWKJKI6A==", "license": "MIT", "dependencies": { "css-select": "^5.1.0", - "css-tree": "^1.1.3" + "css-tree": "^1.1.3", + "warn-once": "0.1.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, + "node_modules/react-native-uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.3.tgz", + "integrity": "sha512-f/YfIS2f5UB+gut7t/9BKGSCYbRA9/74A5R1MDp+FLYsuS+OSWoiM/D8Jko6OJB6Jcu3v6ONuddvZKHdIGpeiw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0", + "npm": ">=6.0.0" + } + }, "node_modules/react-native-worklets": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.5.0.tgz", diff --git a/mobile/package.json b/mobile/package.json index b47743c..c2bd819 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -3,10 +3,10 @@ "version": "1.0.0", "main": "expo-router/entry", "scripts": { - "start": "expo start", - "android": "expo start --android", - "ios": "expo start --ios", - "web": "expo start --web" + "start": "expo start --offline", + "android": "expo start --android --offline", + "ios": "expo start --ios --offline", + "web": "expo start --web --offline" }, "dependencies": { "@expo/html-elements": "^0.10.1", @@ -14,11 +14,14 @@ "@gluestack-ui/core": "^3.0.0", "@gluestack-ui/utils": "^3.0.0", "@legendapp/motion": "^2.3.0", + "@react-native-async-storage/async-storage": "^2.2.0", "babel-plugin-module-resolver": "^5.0.2", "expo": "~53.0.22", "expo-linking": "^7.1.7", "expo-router": "^5.1.4", "expo-status-bar": "~2.2.3", + "lucide-react-native": "^0.510.0", + "nanoid": "^5.1.5", "nativewind": "^4.1.23", "react": "19.0.0", "react-aria": "^3.33.0", @@ -27,7 +30,8 @@ "react-native-reanimated": "^4.1.0", "react-native-safe-area-context": "^4.14.1", "react-native-screens": "^4.15.4", - "react-native-svg": "^15.2.0", + "react-native-svg": "^15.12.0", + "react-native-uuid": "^2.0.3", "react-native-worklets": "^0.5.0", "react-native-worklets-core": "^1.6.2", "react-stately": "^3.39.0",