You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
7.1 KiB
215 lines
7.1 KiB
"use client";
|
|
import React from "react";
|
|
import { createInput } from "@gluestack-ui/input";
|
|
import { View, Pressable, TextInput } from "react-native";
|
|
import { tva } from "@gluestack-ui/nativewind-utils/tva";
|
|
import {
|
|
withStyleContext,
|
|
useStyleContext,
|
|
} from "@gluestack-ui/nativewind-utils/withStyleContext";
|
|
import { cssInterop } from "nativewind";
|
|
import type { VariantProps } from "@gluestack-ui/nativewind-utils";
|
|
import { PrimitiveIcon, UIIcon } from "@gluestack-ui/icon";
|
|
|
|
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-orange-400 data-[focus=true]:hover:border-primary-700 data-[disabled=true]:opacity-40 data-[disabled=true]:hover:border-background-300 items-center",
|
|
|
|
variants: {
|
|
size: {
|
|
xl: "px-4 h-16",
|
|
lg: "px-4 h-11",
|
|
md: "px-4 h-10",
|
|
sm: "px-4 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-3xl 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<typeof UIInput> &
|
|
VariantProps<typeof inputStyle> & { className?: string };
|
|
const Input = React.forwardRef<React.ElementRef<typeof UIInput>, IInputProps>(
|
|
({ className, variant = "outline", size = "md", ...props }, ref) => {
|
|
return (
|
|
<UIInput
|
|
ref={ref}
|
|
{...props}
|
|
className={inputStyle({ variant, size, class: className })}
|
|
context={{ variant, size }}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
type IInputIconProps = React.ComponentProps<typeof UIInput.Icon> &
|
|
VariantProps<typeof inputIconStyle> & {
|
|
className?: string;
|
|
height?: number;
|
|
width?: number;
|
|
};
|
|
|
|
const InputIcon = React.forwardRef<
|
|
React.ElementRef<typeof UIInput.Icon>,
|
|
IInputIconProps
|
|
>(({ className, size, ...props }, ref) => {
|
|
const { size: parentSize } = useStyleContext(SCOPE);
|
|
|
|
if (typeof size === "number") {
|
|
return (
|
|
<UIInput.Icon
|
|
ref={ref}
|
|
{...props}
|
|
className={inputIconStyle({ class: className })}
|
|
size={size}
|
|
/>
|
|
);
|
|
} else if (
|
|
(props.height !== undefined || props.width !== undefined) &&
|
|
size === undefined
|
|
) {
|
|
return (
|
|
<UIInput.Icon
|
|
ref={ref}
|
|
{...props}
|
|
className={inputIconStyle({ class: className })}
|
|
/>
|
|
);
|
|
}
|
|
return (
|
|
<UIInput.Icon
|
|
ref={ref}
|
|
{...props}
|
|
className={inputIconStyle({
|
|
parentVariants: {
|
|
size: parentSize,
|
|
},
|
|
class: className,
|
|
})}
|
|
/>
|
|
);
|
|
});
|
|
|
|
type IInputSlotProps = React.ComponentProps<typeof UIInput.Slot> &
|
|
VariantProps<typeof inputSlotStyle> & { className?: string };
|
|
|
|
const InputSlot = React.forwardRef<
|
|
React.ElementRef<typeof UIInput.Slot>,
|
|
IInputSlotProps
|
|
>(({ className, ...props }, ref) => {
|
|
return (
|
|
<UIInput.Slot
|
|
ref={ref}
|
|
{...props}
|
|
className={inputSlotStyle({
|
|
class: className,
|
|
})}
|
|
/>
|
|
);
|
|
});
|
|
|
|
type IInputFieldProps = React.ComponentProps<typeof UIInput.Input> &
|
|
VariantProps<typeof inputFieldStyle> & { className?: string };
|
|
|
|
const InputField = React.forwardRef<
|
|
React.ElementRef<typeof UIInput.Input>,
|
|
IInputFieldProps
|
|
>(({ className, ...props }, ref) => {
|
|
const { variant: parentVariant, size: parentSize } = useStyleContext(SCOPE);
|
|
|
|
return (
|
|
<UIInput.Input
|
|
ref={ref}
|
|
{...props}
|
|
className={inputFieldStyle({
|
|
parentVariants: {
|
|
variant: parentVariant,
|
|
size: parentSize,
|
|
},
|
|
class: className,
|
|
})}
|
|
/>
|
|
);
|
|
});
|
|
|
|
Input.displayName = "Input";
|
|
InputIcon.displayName = "InputIcon";
|
|
InputSlot.displayName = "InputSlot";
|
|
InputField.displayName = "InputField";
|
|
|
|
export { Input, InputField, InputIcon, InputSlot };
|