parent
84ee08acba
commit
d118df7e9a
@ -0,0 +1,114 @@ |
|||||||
|
import { VStack } from "@/components/ui/vstack"; |
||||||
|
import { Text } from "@/components/ui/text"; |
||||||
|
import { View } from "react-native"; |
||||||
|
import { |
||||||
|
Checkbox, |
||||||
|
CheckboxIcon, |
||||||
|
CheckboxIndicator, |
||||||
|
CheckboxLabel, |
||||||
|
} from "@/components/ui/checkbox"; |
||||||
|
import { useActionState, useEffect, useRef, useState } from "react"; |
||||||
|
import { AddIcon, CheckIcon } from "@/components/ui/icon"; |
||||||
|
import TodoContainer, { Todo } from "@/components/containers/todo-container"; |
||||||
|
import { FormControl } from "@/components/ui/form-control"; |
||||||
|
import { Input, InputField, InputIcon } from "@/components/ui/input"; |
||||||
|
import { Pressable } from "@/components/ui/pressable"; |
||||||
|
import uuid from "react-native-uuid"; |
||||||
|
import AsyncStorage from "@react-native-async-storage/async-storage"; |
||||||
|
|
||||||
|
const STORAGE_KEY = "todos:v1"; |
||||||
|
|
||||||
|
export default function TodoTab() { |
||||||
|
const [item, setItem] = useState(""); |
||||||
|
const [todos, setTodos] = useState<Todo[]>([]); |
||||||
|
|
||||||
|
// 초기 로드
|
||||||
|
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<ReturnType<typeof setTimeout> | 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 ( |
||||||
|
<VStack className="flex-1 bg-secondary-100 md:items-center md:justify-center"> |
||||||
|
<VStack className="rounded-md bg-secondary-100 md:h-[500px] md:w-[700px]"> |
||||||
|
<FormControl className="my-4"> |
||||||
|
<Input variant="underlined" size="sm" className="mx-6 my-2"> |
||||||
|
<InputField |
||||||
|
placeholder="다음 할 일은 무엇인가요?" |
||||||
|
value={item} |
||||||
|
onChangeText={(value) => setItem(value)} |
||||||
|
onSubmitEditing={() => addTodo(item)} |
||||||
|
/> |
||||||
|
<Pressable onPress={() => addTodo(item)}> |
||||||
|
<InputIcon as={AddIcon} className="cursor-pointer h-3 w-3" /> |
||||||
|
</Pressable> |
||||||
|
</Input> |
||||||
|
</FormControl> |
||||||
|
{todos?.map((todo: Todo, index: number) => ( |
||||||
|
<TodoContainer |
||||||
|
key={index} |
||||||
|
todo={todo} |
||||||
|
toggleTodo={toggleTodo} |
||||||
|
deleteTodo={deleteTodo} |
||||||
|
/> |
||||||
|
))} |
||||||
|
</VStack> |
||||||
|
</VStack> |
||||||
|
); |
||||||
|
} |
@ -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 ( |
||||||
|
<HStack |
||||||
|
{...props} |
||||||
|
className="rounded-md hover:bg-secondary-200 justify-between items-center" |
||||||
|
> |
||||||
|
<Checkbox |
||||||
|
onChange={(_isChecked) => toggleTodo(todo.id)} |
||||||
|
size="sm" |
||||||
|
aria-label={todo.task} |
||||||
|
value={todo.task} |
||||||
|
isChecked={todo.completed} |
||||||
|
className="pl-6 py-2 flex-1" |
||||||
|
> |
||||||
|
<CheckboxIndicator> |
||||||
|
<CheckboxIcon as={CheckIcon} /> |
||||||
|
</CheckboxIndicator> |
||||||
|
<CheckboxLabel className="text-sm data-[checked=true]:line-through"> |
||||||
|
{todo.task} |
||||||
|
</CheckboxLabel> |
||||||
|
</Checkbox> |
||||||
|
<Pressable className="pr-6 py-2" onPress={() => deleteTodo(todo.id)}> |
||||||
|
{(state: any) => { |
||||||
|
return ( |
||||||
|
<Icon |
||||||
|
as={CloseIcon} |
||||||
|
size="xs" |
||||||
|
className={ |
||||||
|
state?.hovered ? "stroke-red-400" : "stroke-primary-50" |
||||||
|
} |
||||||
|
/> |
||||||
|
); |
||||||
|
}} |
||||||
|
</Pressable> |
||||||
|
</HStack> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default TodoContainer; |
@ -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<typeof View>, |
||||||
|
ViewProps |
||||||
|
>(function IndicatorWrapper({ ...props }, ref) { |
||||||
|
return <View {...props} ref={ref} />; |
||||||
|
}); |
||||||
|
|
||||||
|
const LabelWrapper = React.forwardRef< |
||||||
|
React.ComponentRef<typeof Text>, |
||||||
|
TextProps |
||||||
|
>(function LabelWrapper({ ...props }, ref) { |
||||||
|
return <Text {...props} ref={ref} />; |
||||||
|
}); |
||||||
|
|
||||||
|
const IconWrapper = React.forwardRef< |
||||||
|
React.ComponentRef<typeof PrimitiveIcon>, |
||||||
|
IPrimitiveIcon |
||||||
|
>(function IconWrapper({ ...props }, ref) { |
||||||
|
return <UIIcon {...props} ref={ref} />; |
||||||
|
}); |
||||||
|
|
||||||
|
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<typeof UICheckbox> & |
||||||
|
VariantProps<typeof checkboxStyle>; |
||||||
|
|
||||||
|
const Checkbox = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UICheckbox>, |
||||||
|
ICheckboxProps |
||||||
|
>(function Checkbox({ className, size = 'md', ...props }, ref) { |
||||||
|
return ( |
||||||
|
<UICheckbox |
||||||
|
className={checkboxStyle({ |
||||||
|
class: className, |
||||||
|
size, |
||||||
|
})} |
||||||
|
{...props} |
||||||
|
context={{ |
||||||
|
size, |
||||||
|
}} |
||||||
|
ref={ref} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type ICheckboxIndicatorProps = React.ComponentPropsWithoutRef< |
||||||
|
typeof UICheckbox.Indicator |
||||||
|
> & |
||||||
|
VariantProps<typeof checkboxIndicatorStyle>; |
||||||
|
|
||||||
|
const CheckboxIndicator = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UICheckbox.Indicator>, |
||||||
|
ICheckboxIndicatorProps |
||||||
|
>(function CheckboxIndicator({ className, ...props }, ref) { |
||||||
|
const { size: parentSize } = useStyleContext(SCOPE); |
||||||
|
|
||||||
|
return ( |
||||||
|
<UICheckbox.Indicator |
||||||
|
className={checkboxIndicatorStyle({ |
||||||
|
parentVariants: { |
||||||
|
size: parentSize, |
||||||
|
}, |
||||||
|
class: className, |
||||||
|
})} |
||||||
|
{...props} |
||||||
|
ref={ref} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type ICheckboxLabelProps = React.ComponentPropsWithoutRef< |
||||||
|
typeof UICheckbox.Label |
||||||
|
> & |
||||||
|
VariantProps<typeof checkboxLabelStyle>; |
||||||
|
const CheckboxLabel = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UICheckbox.Label>, |
||||||
|
ICheckboxLabelProps |
||||||
|
>(function CheckboxLabel({ className, ...props }, ref) { |
||||||
|
const { size: parentSize } = useStyleContext(SCOPE); |
||||||
|
return ( |
||||||
|
<UICheckbox.Label |
||||||
|
className={checkboxLabelStyle({ |
||||||
|
parentVariants: { |
||||||
|
size: parentSize, |
||||||
|
}, |
||||||
|
class: className, |
||||||
|
})} |
||||||
|
{...props} |
||||||
|
ref={ref} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type ICheckboxIconProps = React.ComponentPropsWithoutRef< |
||||||
|
typeof UICheckbox.Icon |
||||||
|
> & |
||||||
|
VariantProps<typeof checkboxIconStyle>; |
||||||
|
|
||||||
|
const CheckboxIcon = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UICheckbox.Icon>, |
||||||
|
ICheckboxIconProps |
||||||
|
>(function CheckboxIcon({ className, size, ...props }, ref) { |
||||||
|
const { size: parentSize } = useStyleContext(SCOPE); |
||||||
|
|
||||||
|
if (typeof size === 'number') { |
||||||
|
return ( |
||||||
|
<UICheckbox.Icon |
||||||
|
ref={ref} |
||||||
|
{...props} |
||||||
|
className={checkboxIconStyle({ class: className })} |
||||||
|
size={size} |
||||||
|
/> |
||||||
|
); |
||||||
|
} else if ( |
||||||
|
(props.height !== undefined || props.width !== undefined) && |
||||||
|
size === undefined |
||||||
|
) { |
||||||
|
return ( |
||||||
|
<UICheckbox.Icon |
||||||
|
ref={ref} |
||||||
|
{...props} |
||||||
|
className={checkboxIconStyle({ class: className })} |
||||||
|
/> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<UICheckbox.Icon |
||||||
|
className={checkboxIconStyle({ |
||||||
|
parentVariants: { |
||||||
|
size: parentSize, |
||||||
|
}, |
||||||
|
size, |
||||||
|
class: className, |
||||||
|
})} |
||||||
|
{...props} |
||||||
|
ref={ref} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
Checkbox.displayName = 'Checkbox'; |
||||||
|
CheckboxIndicator.displayName = 'CheckboxIndicator'; |
||||||
|
CheckboxLabel.displayName = 'CheckboxLabel'; |
||||||
|
CheckboxIcon.displayName = 'CheckboxIcon'; |
||||||
|
|
||||||
|
export { |
||||||
|
Checkbox, |
||||||
|
CheckboxIndicator, |
||||||
|
CheckboxLabel, |
||||||
|
CheckboxIcon, |
||||||
|
CheckboxGroup, |
||||||
|
}; |
@ -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<typeof formControlLabelAstrickStyle>; |
||||||
|
|
||||||
|
const FormControlLabelAstrick = React.forwardRef< |
||||||
|
React.ComponentRef<typeof Text>, |
||||||
|
IFormControlLabelAstrickProps |
||||||
|
>(function FormControlLabelAstrick({ className, ...props }, ref) { |
||||||
|
const { size: parentSize } = useStyleContext(SCOPE); |
||||||
|
|
||||||
|
return ( |
||||||
|
<Text |
||||||
|
ref={ref} |
||||||
|
className={formControlLabelAstrickStyle({ |
||||||
|
parentVariants: { size: parentSize }, |
||||||
|
class: className, |
||||||
|
})} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
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<typeof UIFormControl> & |
||||||
|
VariantProps<typeof formControlStyle>; |
||||||
|
|
||||||
|
const FormControl = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UIFormControl>, |
||||||
|
IFormControlProps |
||||||
|
>(function FormControl({ className, size = 'md', ...props }, ref) { |
||||||
|
return ( |
||||||
|
<UIFormControl |
||||||
|
ref={ref} |
||||||
|
className={formControlStyle({ size, class: className })} |
||||||
|
{...props} |
||||||
|
context={{ size }} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type IFormControlErrorProps = React.ComponentProps<typeof UIFormControl.Error> & |
||||||
|
VariantProps<typeof formControlErrorStyle>; |
||||||
|
|
||||||
|
const FormControlError = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UIFormControl.Error>, |
||||||
|
IFormControlErrorProps |
||||||
|
>(function FormControlError({ className, ...props }, ref) { |
||||||
|
return ( |
||||||
|
<UIFormControl.Error |
||||||
|
ref={ref} |
||||||
|
className={formControlErrorStyle({ class: className })} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type IFormControlErrorTextProps = React.ComponentProps< |
||||||
|
typeof UIFormControl.Error.Text |
||||||
|
> & |
||||||
|
VariantProps<typeof formControlErrorTextStyle>; |
||||||
|
|
||||||
|
const FormControlErrorText = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UIFormControl.Error.Text>, |
||||||
|
IFormControlErrorTextProps |
||||||
|
>(function FormControlErrorText({ className, size, ...props }, ref) { |
||||||
|
const { size: parentSize } = useStyleContext(SCOPE); |
||||||
|
return ( |
||||||
|
<UIFormControl.Error.Text |
||||||
|
className={formControlErrorTextStyle({ |
||||||
|
parentVariants: { size: parentSize }, |
||||||
|
size, |
||||||
|
class: className, |
||||||
|
})} |
||||||
|
ref={ref} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type IFormControlErrorIconProps = React.ComponentProps< |
||||||
|
typeof UIFormControl.Error.Icon |
||||||
|
> & |
||||||
|
VariantProps<typeof formControlErrorIconStyle> & { |
||||||
|
height?: number; |
||||||
|
width?: number; |
||||||
|
}; |
||||||
|
|
||||||
|
const FormControlErrorIcon = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UIFormControl.Error.Icon>, |
||||||
|
IFormControlErrorIconProps |
||||||
|
>(function FormControlErrorIcon({ className, size, ...props }, ref) { |
||||||
|
const { size: parentSize } = useStyleContext(SCOPE); |
||||||
|
|
||||||
|
if (typeof size === 'number') { |
||||||
|
return ( |
||||||
|
<UIFormControl.Error.Icon |
||||||
|
ref={ref} |
||||||
|
{...props} |
||||||
|
className={formControlErrorIconStyle({ class: className })} |
||||||
|
size={size} |
||||||
|
/> |
||||||
|
); |
||||||
|
} else if ( |
||||||
|
(props.height !== undefined || props.width !== undefined) && |
||||||
|
size === undefined |
||||||
|
) { |
||||||
|
return ( |
||||||
|
<UIFormControl.Error.Icon |
||||||
|
ref={ref} |
||||||
|
{...props} |
||||||
|
className={formControlErrorIconStyle({ class: className })} |
||||||
|
/> |
||||||
|
); |
||||||
|
} |
||||||
|
return ( |
||||||
|
<UIFormControl.Error.Icon |
||||||
|
className={formControlErrorIconStyle({ |
||||||
|
parentVariants: { size: parentSize }, |
||||||
|
size, |
||||||
|
class: className, |
||||||
|
})} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type IFormControlLabelProps = React.ComponentProps<typeof UIFormControl.Label> & |
||||||
|
VariantProps<typeof formControlLabelStyle>; |
||||||
|
|
||||||
|
const FormControlLabel = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UIFormControl.Label>, |
||||||
|
IFormControlLabelProps |
||||||
|
>(function FormControlLabel({ className, ...props }, ref) { |
||||||
|
return ( |
||||||
|
<UIFormControl.Label |
||||||
|
ref={ref} |
||||||
|
className={formControlLabelStyle({ class: className })} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type IFormControlLabelTextProps = React.ComponentProps< |
||||||
|
typeof UIFormControl.Label.Text |
||||||
|
> & |
||||||
|
VariantProps<typeof formControlLabelTextStyle>; |
||||||
|
|
||||||
|
const FormControlLabelText = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UIFormControl.Label.Text>, |
||||||
|
IFormControlLabelTextProps |
||||||
|
>(function FormControlLabelText({ className, size, ...props }, ref) { |
||||||
|
const { size: parentSize } = useStyleContext(SCOPE); |
||||||
|
|
||||||
|
return ( |
||||||
|
<UIFormControl.Label.Text |
||||||
|
className={formControlLabelTextStyle({ |
||||||
|
parentVariants: { size: parentSize }, |
||||||
|
size, |
||||||
|
class: className, |
||||||
|
})} |
||||||
|
ref={ref} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type IFormControlHelperProps = React.ComponentProps< |
||||||
|
typeof UIFormControl.Helper |
||||||
|
> & |
||||||
|
VariantProps<typeof formControlHelperStyle>; |
||||||
|
|
||||||
|
const FormControlHelper = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UIFormControl.Helper>, |
||||||
|
IFormControlHelperProps |
||||||
|
>(function FormControlHelper({ className, ...props }, ref) { |
||||||
|
return ( |
||||||
|
<UIFormControl.Helper |
||||||
|
ref={ref} |
||||||
|
className={formControlHelperStyle({ |
||||||
|
class: className, |
||||||
|
})} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
type IFormControlHelperTextProps = React.ComponentProps< |
||||||
|
typeof UIFormControl.Helper.Text |
||||||
|
> & |
||||||
|
VariantProps<typeof formControlHelperTextStyle>; |
||||||
|
|
||||||
|
const FormControlHelperText = React.forwardRef< |
||||||
|
React.ComponentRef<typeof UIFormControl.Helper.Text>, |
||||||
|
IFormControlHelperTextProps |
||||||
|
>(function FormControlHelperText({ className, size, ...props }, ref) { |
||||||
|
const { size: parentSize } = useStyleContext(SCOPE); |
||||||
|
|
||||||
|
return ( |
||||||
|
<UIFormControl.Helper.Text |
||||||
|
className={formControlHelperTextStyle({ |
||||||
|
parentVariants: { size: parentSize }, |
||||||
|
size, |
||||||
|
class: className, |
||||||
|
})} |
||||||
|
ref={ref} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
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, |
||||||
|
}; |
@ -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', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}); |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,217 +1,217 @@ |
|||||||
'use client'; |
'use client'; |
||||||
import React from 'react'; |
import React from 'react'; |
||||||
import { createInput } from '@gluestack-ui/core/input/creator'; |
import { createInput } from '@gluestack-ui/core/input/creator'; |
||||||
import { View, Pressable, TextInput } from 'react-native'; |
import { View, Pressable, TextInput } from 'react-native'; |
||||||
import { tva } from '@gluestack-ui/utils/nativewind-utils'; |
import { tva } from '@gluestack-ui/utils/nativewind-utils'; |
||||||
import { |
import { |
||||||
withStyleContext, |
withStyleContext, |
||||||
useStyleContext, |
useStyleContext, |
||||||
} from '@gluestack-ui/utils/nativewind-utils'; |
} from '@gluestack-ui/utils/nativewind-utils'; |
||||||
import { cssInterop } from 'nativewind'; |
import { cssInterop } from 'nativewind'; |
||||||
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; |
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; |
||||||
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; |
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; |
||||||
|
|
||||||
const SCOPE = 'INPUT'; |
const SCOPE = 'INPUT'; |
||||||
|
|
||||||
const UIInput = createInput({ |
const UIInput = createInput({ |
||||||
Root: withStyleContext(View, SCOPE), |
Root: withStyleContext(View, SCOPE), |
||||||
Icon: UIIcon, |
Icon: UIIcon, |
||||||
Slot: Pressable, |
Slot: Pressable, |
||||||
Input: TextInput, |
Input: TextInput, |
||||||
}); |
}); |
||||||
|
|
||||||
cssInterop(PrimitiveIcon, { |
cssInterop(PrimitiveIcon, { |
||||||
className: { |
className: { |
||||||
target: 'style', |
target: 'style', |
||||||
nativeStyleToProp: { |
nativeStyleToProp: { |
||||||
height: true, |
height: true, |
||||||
width: true, |
width: true, |
||||||
fill: true, |
fill: true, |
||||||
color: 'classNameColor', |
color: 'classNameColor', |
||||||
stroke: true, |
stroke: true, |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
}); |
}); |
||||||
|
|
||||||
const inputStyle = tva({ |
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', |
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: { |
variants: { |
||||||
size: { |
size: { |
||||||
xl: 'h-12', |
xl: 'h-12', |
||||||
lg: 'h-11', |
lg: 'h-11', |
||||||
md: 'h-10', |
md: 'h-10', |
||||||
sm: 'h-9', |
sm: 'h-9', |
||||||
}, |
}, |
||||||
|
|
||||||
variant: { |
variant: { |
||||||
underlined: |
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', |
'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: |
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 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: |
||||||
'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', |
'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({ |
const inputIconStyle = tva({ |
||||||
base: 'justify-center items-center text-typography-400 fill-none', |
base: 'justify-center items-center text-typography-400 fill-none', |
||||||
parentVariants: { |
parentVariants: { |
||||||
size: { |
size: { |
||||||
'2xs': 'h-3 w-3', |
'2xs': 'h-3 w-3', |
||||||
'xs': 'h-3.5 w-3.5', |
'xs': 'h-3.5 w-3.5', |
||||||
'sm': 'h-4 w-4', |
'sm': 'h-4 w-4', |
||||||
'md': 'h-[18px] w-[18px]', |
'md': 'h-[18px] w-[18px]', |
||||||
'lg': 'h-5 w-5', |
'lg': 'h-5 w-5', |
||||||
'xl': 'h-6 w-6', |
'xl': 'h-6 w-6', |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
}); |
}); |
||||||
|
|
||||||
const inputSlotStyle = tva({ |
const inputSlotStyle = tva({ |
||||||
base: 'justify-center items-center web:disabled:cursor-not-allowed', |
base: 'justify-center items-center web:disabled:cursor-not-allowed', |
||||||
}); |
}); |
||||||
|
|
||||||
const inputFieldStyle = tva({ |
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', |
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: { |
parentVariants: { |
||||||
variant: { |
variant: { |
||||||
underlined: 'web:outline-0 web:outline-none px-0', |
underlined: 'web:outline-0 web:outline-none px-0', |
||||||
outline: 'web:outline-0 web:outline-none', |
outline: 'web:outline-0 web:outline-none', |
||||||
rounded: 'web:outline-0 web:outline-none px-4', |
rounded: 'web:outline-0 web:outline-none px-4', |
||||||
}, |
}, |
||||||
|
|
||||||
size: { |
size: { |
||||||
'2xs': 'text-2xs', |
'2xs': 'text-2xs', |
||||||
'xs': 'text-xs', |
'xs': 'text-xs', |
||||||
'sm': 'text-sm', |
'sm': 'text-sm', |
||||||
'md': 'text-base', |
'md': 'text-base', |
||||||
'lg': 'text-lg', |
'lg': 'text-lg', |
||||||
'xl': 'text-xl', |
'xl': 'text-xl', |
||||||
'2xl': 'text-2xl', |
'2xl': 'text-2xl', |
||||||
'3xl': 'text-3xl', |
'3xl': 'text-3xl', |
||||||
'4xl': 'text-4xl', |
'4xl': 'text-4xl', |
||||||
'5xl': 'text-5xl', |
'5xl': 'text-5xl', |
||||||
'6xl': 'text-6xl', |
'6xl': 'text-6xl', |
||||||
}, |
}, |
||||||
}, |
}, |
||||||
}); |
}); |
||||||
|
|
||||||
type IInputProps = React.ComponentProps<typeof UIInput> & |
type IInputProps = React.ComponentProps<typeof UIInput> & |
||||||
VariantProps<typeof inputStyle> & { className?: string }; |
VariantProps<typeof inputStyle> & { className?: string }; |
||||||
const Input = React.forwardRef<React.ComponentRef<typeof UIInput>, IInputProps>( |
const Input = React.forwardRef<React.ComponentRef<typeof UIInput>, IInputProps>( |
||||||
function Input( |
function Input( |
||||||
{ className, variant = 'outline', size = 'md', ...props }, |
{ className, variant = 'outline', size = 'md', ...props }, |
||||||
ref |
ref |
||||||
) { |
) { |
||||||
return ( |
return ( |
||||||
<UIInput |
<UIInput |
||||||
ref={ref} |
ref={ref} |
||||||
{...props} |
{...props} |
||||||
className={inputStyle({ variant, size, class: className })} |
className={inputStyle({ variant, size, class: className })} |
||||||
context={{ variant, size }} |
context={{ variant, size }} |
||||||
/> |
/> |
||||||
); |
); |
||||||
} |
} |
||||||
); |
); |
||||||
|
|
||||||
type IInputIconProps = React.ComponentProps<typeof UIInput.Icon> & |
type IInputIconProps = React.ComponentProps<typeof UIInput.Icon> & |
||||||
VariantProps<typeof inputIconStyle> & { |
VariantProps<typeof inputIconStyle> & { |
||||||
className?: string; |
className?: string; |
||||||
height?: number; |
height?: number; |
||||||
width?: number; |
width?: number; |
||||||
}; |
}; |
||||||
|
|
||||||
const InputIcon = React.forwardRef< |
const InputIcon = React.forwardRef< |
||||||
React.ComponentRef<typeof UIInput.Icon>, |
React.ComponentRef<typeof UIInput.Icon>, |
||||||
IInputIconProps |
IInputIconProps |
||||||
>(function InputIcon({ className, size, ...props }, ref) { |
>(function InputIcon({ className, size, ...props }, ref) { |
||||||
const { size: parentSize } = useStyleContext(SCOPE); |
const { size: parentSize } = useStyleContext(SCOPE); |
||||||
|
|
||||||
if (typeof size === 'number') { |
if (typeof size === 'number') { |
||||||
return ( |
return ( |
||||||
<UIInput.Icon |
<UIInput.Icon |
||||||
ref={ref} |
ref={ref} |
||||||
{...props} |
{...props} |
||||||
className={inputIconStyle({ class: className })} |
className={inputIconStyle({ class: className })} |
||||||
size={size} |
size={size} |
||||||
/> |
/> |
||||||
); |
); |
||||||
} else if ( |
} else if ( |
||||||
(props.height !== undefined || props.width !== undefined) && |
(props.height !== undefined || props.width !== undefined) && |
||||||
size === undefined |
size === undefined |
||||||
) { |
) { |
||||||
return ( |
return ( |
||||||
<UIInput.Icon |
<UIInput.Icon |
||||||
ref={ref} |
ref={ref} |
||||||
{...props} |
{...props} |
||||||
className={inputIconStyle({ class: className })} |
className={inputIconStyle({ class: className })} |
||||||
/> |
/> |
||||||
); |
); |
||||||
} |
} |
||||||
return ( |
return ( |
||||||
<UIInput.Icon |
<UIInput.Icon |
||||||
ref={ref} |
ref={ref} |
||||||
{...props} |
{...props} |
||||||
className={inputIconStyle({ |
className={inputIconStyle({ |
||||||
parentVariants: { |
parentVariants: { |
||||||
size: parentSize, |
size: parentSize, |
||||||
}, |
}, |
||||||
class: className, |
class: className, |
||||||
})} |
})} |
||||||
/> |
/> |
||||||
); |
); |
||||||
}); |
}); |
||||||
|
|
||||||
type IInputSlotProps = React.ComponentProps<typeof UIInput.Slot> & |
type IInputSlotProps = React.ComponentProps<typeof UIInput.Slot> & |
||||||
VariantProps<typeof inputSlotStyle> & { className?: string }; |
VariantProps<typeof inputSlotStyle> & { className?: string }; |
||||||
|
|
||||||
const InputSlot = React.forwardRef< |
const InputSlot = React.forwardRef< |
||||||
React.ComponentRef<typeof UIInput.Slot>, |
React.ComponentRef<typeof UIInput.Slot>, |
||||||
IInputSlotProps |
IInputSlotProps |
||||||
>(function InputSlot({ className, ...props }, ref) { |
>(function InputSlot({ className, ...props }, ref) { |
||||||
return ( |
return ( |
||||||
<UIInput.Slot |
<UIInput.Slot |
||||||
ref={ref} |
ref={ref} |
||||||
{...props} |
{...props} |
||||||
className={inputSlotStyle({ |
className={inputSlotStyle({ |
||||||
class: className, |
class: className, |
||||||
})} |
})} |
||||||
/> |
/> |
||||||
); |
); |
||||||
}); |
}); |
||||||
|
|
||||||
type IInputFieldProps = React.ComponentProps<typeof UIInput.Input> & |
type IInputFieldProps = React.ComponentProps<typeof UIInput.Input> & |
||||||
VariantProps<typeof inputFieldStyle> & { className?: string }; |
VariantProps<typeof inputFieldStyle> & { className?: string }; |
||||||
|
|
||||||
const InputField = React.forwardRef< |
const InputField = React.forwardRef< |
||||||
React.ComponentRef<typeof UIInput.Input>, |
React.ComponentRef<typeof UIInput.Input>, |
||||||
IInputFieldProps |
IInputFieldProps |
||||||
>(function InputField({ className, ...props }, ref) { |
>(function InputField({ className, ...props }, ref) { |
||||||
const { variant: parentVariant, size: parentSize } = useStyleContext(SCOPE); |
const { variant: parentVariant, size: parentSize } = useStyleContext(SCOPE); |
||||||
|
|
||||||
return ( |
return ( |
||||||
<UIInput.Input |
<UIInput.Input |
||||||
ref={ref} |
ref={ref} |
||||||
{...props} |
{...props} |
||||||
className={inputFieldStyle({ |
className={inputFieldStyle({ |
||||||
parentVariants: { |
parentVariants: { |
||||||
variant: parentVariant, |
variant: parentVariant, |
||||||
size: parentSize, |
size: parentSize, |
||||||
}, |
}, |
||||||
class: className, |
class: className, |
||||||
})} |
})} |
||||||
/> |
/> |
||||||
); |
); |
||||||
}); |
}); |
||||||
|
|
||||||
Input.displayName = 'Input'; |
Input.displayName = 'Input'; |
||||||
InputIcon.displayName = 'InputIcon'; |
InputIcon.displayName = 'InputIcon'; |
||||||
InputSlot.displayName = 'InputSlot'; |
InputSlot.displayName = 'InputSlot'; |
||||||
InputField.displayName = 'InputField'; |
InputField.displayName = 'InputField'; |
||||||
|
|
||||||
export { Input, InputField, InputIcon, InputSlot }; |
export { Input, InputField, InputIcon, InputSlot }; |
||||||
|
Loading…
Reference in new issue