From 18c6efb69e28300cc2929fd87a4e48ffd965452e Mon Sep 17 00:00:00 2001 From: Rajat Chaudhary <rajatchaudhary.rc693@gmail.com> Date: Thu, 22 Feb 2024 16:59:34 +0530 Subject: [PATCH 1/2] feat: added input component --- .../nativewind/Input/index.tsx | 580 ++++++------------ .../src/components/Input/Input.tsx | 5 +- .../src/components/Input/index.nw.stories.mdx | 486 +++++++++++++++ .../components/Input/index.themed.stories.mdx | 486 +++++++++++++++ 4 files changed, 1158 insertions(+), 399 deletions(-) create mode 100644 example/storybook-nativewind/src/components/Input/index.nw.stories.mdx create mode 100644 example/storybook-nativewind/src/components/Input/index.themed.stories.mdx diff --git a/example/storybook-nativewind/src/components-example/nativewind/Input/index.tsx b/example/storybook-nativewind/src/components-example/nativewind/Input/index.tsx index a93e3c7910..5d01969463 100644 --- a/example/storybook-nativewind/src/components-example/nativewind/Input/index.tsx +++ b/example/storybook-nativewind/src/components-example/nativewind/Input/index.tsx @@ -1,426 +1,214 @@ +import React from 'react'; import { createInput } from '@gluestack-ui/input'; -import { styled, AsForwarder } from '@gluestack-style/react'; -import { View, Pressable, TextInput } from 'react-native'; +import { AsForwarder } from '@gluestack-style/react'; +import { View, Pressable, TextInput, Platform } from 'react-native'; +import { + tva, + withStyleContextAndStates, + useStyleContext, + withStyleContext, + withStates, + VariantProps, + cssInterop, +} from '@gluestack-ui/nativewind-utils'; -const StyledRoot = styled( - View, - { - 'borderWidth': 1, - 'borderColor': '$background300', - 'borderRadius': '$sm', - 'flexDirection': 'row', - 'overflow': 'hidden', - 'alignContent': 'center', +const UIInput = createInput({ + // @ts-ignore + Root: + Platform.OS === 'web' + ? withStyleContext(View) + : withStyleContextAndStates(View), + Icon: AsForwarder, + Slot: Pressable, + Input: Platform.OS === 'web' ? TextInput : withStates(TextInput), +}); - ':hover': { - borderColor: '$border400', - }, +const inputStyle = tva({ + base: 'border-background-300 flex-row overflow-hidden content-center data-[hover=true]:border-border-400 data-[focus=true]:border-primary-700 focus:hover:border-primary-700 data-[disabled=true]:opacity-40 data-[disabled=true]:hover:border-background-300', - ':focus': { - 'borderColor': '$primary700', - ':hover': { - borderColor: '$primary700', - }, + variants: { + size: { + xl: 'h-12', + lg: 'h-11', + md: 'h-10', + sm: 'h-9', }, - ':disabled': { - 'opacity': 0.4, - ':hover': { - borderColor: '$background300', - }, - }, + 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]:focus:border-error-700 data-[invalid=true]:focus:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 focus:web:ring-1 focus:web:ring-inset focus:web:ring-primary-700 data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-error-700 data-[invalid=true]:focus:hover:web:ring-1 data-[invalid=true]:focus:hover:web:ring-inset data-[invalid=true]:focus:hover:web:ring-error-700 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-error-700', - '_input': { - py: 'auto', - px: '$3', - }, + outline: + 'rounded border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:focus:border-error-700 data-[invalid=true]:focus:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 focus:web:ring-1 focus:web:ring-inset focus:web:ring-primary-700 data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-error-700 data-[invalid=true]:focus:hover:web:ring-1 data-[invalid=true]:focus:hover:web:ring-inset data-[invalid=true]:focus:hover:web:ring-error-700 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-error-700', - '_icon': { - color: '$text400', + rounded: + 'rounded-full border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:focus:border-error-700 data-[invalid=true]:focus:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 focus:web:ring-1 focus:web:ring-inset focus:web:ring-primary-700 data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-error-700 data-[invalid=true]:focus:hover:web:ring-1 data-[invalid=true]:focus:hover:web:ring-inset data-[invalid=true]:focus:hover:web:ring-error-700 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-error-700', }, + }, +}); - 'variants': { - size: { - xl: { - h: '$12', - _input: { - props: { - size: 'xl', - }, - }, - _icon: { - props: { - size: 'xl', - }, - }, - }, - lg: { - h: '$11', - _input: { - props: { - size: 'lg', - }, - }, - _icon: { - props: { - size: 'lg', - }, - }, - }, - md: { - h: '$10', - _input: { - props: { - size: 'md', - }, - }, - _icon: { - props: { - size: 'sm', - }, - }, - }, - sm: { - h: '$9', - _input: { - props: { - size: 'sm', - }, - }, - _icon: { - props: { - size: 'xs', - }, - }, - }, - }, - variant: { - underlined: { - '_input': { - _web: { - outlineWidth: 0, - outline: 'none', - }, - px: '$0', - }, - - 'borderWidth': 0, - 'borderRadius': 0, - 'borderBottomWidth': '$1', - - ':focus': { - borderColor: '$primary700', - _web: { - boxShadow: 'inset 0 -1px 0 0 $primary700', - }, - }, - - ':invalid': { - 'borderBottomWidth': 2, - 'borderBottomColor': '$error700', - '_web': { - boxShadow: 'inset 0 -1px 0 0 $error700', - }, - ':hover': { - borderBottomColor: '$error700', - }, - ':focus': { - 'borderBottomColor': '$error700', - ':hover': { - borderBottomColor: '$error700', - _web: { - boxShadow: 'inset 0 -1px 0 0 $error700', - }, - }, - }, - ':disabled': { - ':hover': { - borderBottomColor: '$error700', - _web: { - boxShadow: 'inset 0 -1px 0 0 $error700', - }, - }, - }, - }, - }, - - outline: { - '_input': { - _web: { - outlineWidth: 0, - outline: 'none', - }, - }, - - ':focus': { - borderColor: '$primary700', - _web: { - boxShadow: 'inset 0 0 0 1px $primary700', - }, - }, - - ':invalid': { - 'borderColor': '$error700', - '_web': { - boxShadow: 'inset 0 0 0 1px $error700', - }, - ':hover': { - borderColor: '$error700', - }, - ':focus': { - 'borderColor': '$error700', - ':hover': { - borderColor: '$error700', - _web: { - boxShadow: 'inset 0 0 0 1px $error700', - }, - }, - }, - ':disabled': { - ':hover': { - borderColor: '$error700', - _web: { - boxShadow: 'inset 0 0 0 1px $error700', - }, - }, - }, - }, - }, - - rounded: { - 'borderRadius': 999, +const inputIconStyle = tva({ + base: 'stroke-2 stroke-typography-400', + parentVariants: { + size: { + '2xs': 'h-3 w-3', + 'xs': 'h-3.5 w-3.5', + 'sm': 'h-4 w-4', + 'md': 'h-4.5 w-4.5', + 'lg': 'h-5 w-5', + 'xl': 'h-6 w-6', + }, + }, +}); - '_input': { - px: '$4', - _web: { - outlineWidth: 0, - outline: 'none', - }, - }, +const inputSlotStyle = tva({ + base: 'justify-center items-center web:disabled:cursor-not-allowed', +}); - ':focus': { - borderColor: '$primary700', - _web: { - boxShadow: 'inset 0 0 0 1px $primary700', - }, - }, +const inputFieldStyle = tva({ + base: 'flex-1 text-text-900 web:cursor-text web:data-[disabled=true]:cursor-not-allowed py-auto px-3 placeholder:text-typography-500', - ':invalid': { - 'borderColor': '$error700', - '_web': { - boxShadow: 'inset 0 0 0 1px $error700', - }, - ':hover': { - borderColor: '$error700', - }, - ':focus': { - 'borderColor': '$error700', - ':hover': { - borderColor: '$error700', - _web: { - boxShadow: 'inset 0 0 0 1px $error700', - }, - }, - }, - ':disabled': { - ':hover': { - borderColor: '$error700', - _web: { - boxShadow: 'inset 0 0 0 1px $error700', - }, - }, - }, - }, - }, - }, + 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', }, - 'defaultProps': { - size: 'md', - variant: 'outline', + 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', }, }, - { - descendantStyle: ['_input', '_icon'], +}); + +cssInterop(UIInput, { className: 'style' }); +cssInterop(UIInput.Icon, { className: 'style' }); +cssInterop(UIInput.Slot, { className: 'style' }); +cssInterop(UIInput.Input, { className: 'style' }); + +type IInputProps = React.ComponentProps<typeof UIInput> & + VariantProps<typeof inputStyle>; + +const Input = React.forwardRef( + ( + { + className, + variant = 'outline', + size = 'md', + ...props + }: { className?: string } & IInputProps, + ref + ) => { + return ( + <UIInput + ref={ref} + {...props} + className={inputStyle({ variant, size, class: className })} + context={{ variant, size }} + /> + ); } ); -const StyledIcon = styled( - AsForwarder, - { - color: '$background800', - variants: { - size: { - '2xs': { - h: '$3', - w: '$3', - props: { - // @ts-ignore - size: 12, - }, - }, - 'xs': { - h: '$3.5', - w: '$3.5', - props: { - //@ts-ignore - size: 14, - }, - }, - 'sm': { - h: '$4', - w: '$4', - props: { - //@ts-ignore - size: 16, - }, - }, - 'md': { - h: '$4.5', - w: '$4.5', - props: { - //@ts-ignore - size: 18, - }, - }, - 'lg': { - h: '$5', - w: '$5', - props: { - //@ts-ignore - size: 20, - }, - }, - 'xl': { - h: '$6', - w: '$6', - props: { - //@ts-ignore - size: 24, - }, - }, - }, - }, - props: { - size: 'md', - fill: 'none', - }, - }, - { - resolveProps: ['stroke', 'fill'], - ancestorStyle: ['_icon'], - }, - { - propertyTokenMap: { - stroke: 'colors', - fill: 'colors', - }, +type IInputIconProps = React.ComponentProps<typeof UIInput.Icon> & + VariantProps<typeof inputIconStyle>; + +const InputIcon = React.forwardRef( + ( + { + className, + as: AsComp, + fill = 'none', + ...props + }: { className?: any } & IInputIconProps, + ref + ) => { + const { size: parentSize } = useStyleContext(); + + if (AsComp) { + return ( + <AsComp + ref={ref} + {...props} + fill={fill} + className={inputIconStyle({ + parentVariants: { + size: parentSize, + }, + class: className, + })} + /> + ); + } + return ( + <UIInput.Icon + ref={ref} + {...props} + fill={fill} + className={inputIconStyle({ + parentVariants: { + size: parentSize, + }, + class: className, + })} + /> + ); } ); -const StyledSlot = styled( - Pressable, - { - justifyContent: 'center', - alignItems: 'center', - _web: { - ':disabled': { - cursor: 'not-allowed', - }, - }, - }, - { - descendantStyle: ['_icon'], +type IInputSlotProps = React.ComponentProps<typeof UIInput.Slot> & + VariantProps<typeof inputSlotStyle>; + +const InputSlot = React.forwardRef( + ({ className, ...props }: { className?: string } & IInputSlotProps, ref) => { + return ( + <UIInput.Slot + ref={ref} + {...props} + className={inputSlotStyle({ + class: className, + })} + /> + ); } ); -const StyledInputField = styled( - TextInput, - { - flex: 1, - color: '$text900', - - props: { - placeholderTextColor: '$text500', - }, - - _web: { - 'cursor': 'text', - ':disabled': { - cursor: 'not-allowed', - }, - }, - - variants: { - size: { - '2xs': { - fontSize: '$2xs', - }, - 'xs': { - fontSize: '$xs', - }, - - 'sm': { - fontSize: '$sm', - }, - - 'md': { - fontSize: '$md', - }, - - 'lg': { - fontSize: '$lg', - }, - - 'xl': { - fontSize: '$xl', - }, - - '2xl': { - fontSize: '$2xl', - }, - - '3xl': { - fontSize: '$3xl', - }, - - '4xl': { - fontSize: '$4xl', - }, - - '5xl': { - fontSize: '$5xl', - }, - - '6xl': { - fontSize: '$6xl', - }, - }, - }, - }, - { - ancestorStyle: ['_input'], - resolveProps: ['placeholderTextColor'], - }, - { - propertyTokenMap: { - placeholderTextColor: 'colors', - }, +type IInputFieldProps = React.ComponentProps<typeof UIInput.Input> & + VariantProps<typeof inputFieldStyle>; + +const InputField = React.forwardRef( + ({ className, ...props }: { className?: string } & IInputFieldProps, ref) => { + const { variant: parentVariant, size: parentSize } = useStyleContext(); + + return ( + <UIInput.Input + ref={ref} + {...props} + className={inputFieldStyle({ + parentVariants: { + variant: parentVariant, + size: parentSize, + }, + class: className, + })} + /> + ); } ); -const UIInput = createInput({ - Root: StyledRoot, - Icon: StyledIcon, - Slot: StyledSlot, - Input: StyledInputField, -}); -export const Input = UIInput; -export const InputIcon = UIInput.Icon; -export const InputSlot = UIInput.Slot; -export const InputField = UIInput.Input; +Input.displayName = 'Input'; +InputIcon.displayName = 'InputIcon'; +InputSlot.displayName = 'InputSlot'; +InputField.displayName = 'InputField'; -/** - * @deprecated Use InputField instead. - */ -export const InputInput = UIInput.Input; +export { Input, InputField, InputIcon, InputSlot }; diff --git a/example/storybook-nativewind/src/components/Input/Input.tsx b/example/storybook-nativewind/src/components/Input/Input.tsx index 207164bdc5..743be8c2a4 100644 --- a/example/storybook-nativewind/src/components/Input/Input.tsx +++ b/example/storybook-nativewind/src/components/Input/Input.tsx @@ -5,14 +5,13 @@ import { Box, Heading, Icon, - SearchIcon, FormControl, } from '@gluestack-ui/themed'; import { Input, InputField, InputIcon, InputSlot } from '@/components/ui/Input'; import { Center } from '@/components/ui/Center'; import { VStack } from '@/components/ui/VStack'; import { Text } from '@/components/ui/Text'; -import { EyeIcon, EyeOffIcon } from 'lucide-react-native'; +import { EyeIcon, EyeOffIcon, SearchIcon } from 'lucide-react-native'; import { useState } from 'react'; const InputBasic = ({ ...props }: any) => { @@ -27,7 +26,7 @@ const InputBasic = ({ ...props }: any) => { value={value} placeholder="Enter Text here" /> - <InputSlot pr={props.variant === 'underlined' ? '$0' : '$4'}> + <InputSlot className={props.variant === 'underlined' ? `pr-0` : `pr-4`}> <InputIcon as={SearchIcon} /> </InputSlot> </Input> diff --git a/example/storybook-nativewind/src/components/Input/index.nw.stories.mdx b/example/storybook-nativewind/src/components/Input/index.nw.stories.mdx new file mode 100644 index 0000000000..8bee360808 --- /dev/null +++ b/example/storybook-nativewind/src/components/Input/index.nw.stories.mdx @@ -0,0 +1,486 @@ +--- +title: gluestack-ui Input Component | Installation, Usage, and API + +description: The Input component is your go-to tool for gathering user input in a sleek and user-friendly text field. Whether you're designing a simple login form or a complex search feature, this component has got you covered. + +pageTitle: Input + +pageDescription: The Input component is your go-to tool for gathering user input in a sleek and user-friendly text field. Whether you're designing a simple login form or a complex search feature, this component has got you covered. + +showHeader: true +--- + +import { Meta } from '@storybook/addon-docs'; + +<Meta title="with-nativewind/components/Forms/Input" /> + +import { Input, InputField, InputIcon, InputSlot } from './Input'; +import { + Button, + ButtonText, + VStack, + Text as GSText, + Center, + Box, + FormControl, +} from '@gluestack-ui/themed'; +import { Heading, useState } from '@gluestack-ui/themed'; +import { Icon, SearchIcon, EyeIcon, EyeOffIcon } from '@gluestack-ui/themed'; +import { transformedCode } from '../../utils'; +import { + AppProvider, + CodePreview, + Table, + TableContainer, + Text, + InlineCode, +} from '@gluestack/design-system'; + +import Wrapper from '../../components-example/nativewind/Wrapper'; + +This is an illustration of **Input** component. + +<> + <CodePreview + showComponentRenderer={true} + showArgsController={true} + metaData={{ + code: ` + <Input {...props}> + <InputField + placeholder='Enter Text here' + /> + </Input> + `, + transformCode: (code) => { + return transformedCode(code); + }, + scope: { + Wrapper, + Input, + InputField, + InputIcon, + }, + argsType: { + variant: { + control: 'select', + options: ['rounded', 'outline', 'underlined'], + default: 'outline', + }, + size: { + control: 'select', + options: ['sm', 'md', 'lg', 'xl'], + default: 'md', + }, + isDisabled: { + control: 'boolean', + default: false, + }, + isInvalid: { + control: 'boolean', + default: false, + }, + isReadOnly: { + control: 'boolean', + default: false, + }, + }, + }} + /> +</> + +<br /> + +## Installation + +### Step 1: Install the following dependencies: + +```bash + +npm i @gluestack-ui/input + +``` + +### Step 2: Copy and paste the following code into your project. + +<CollapsibleCode> + ```jsx + %%-- File: components-example/nativewind/Input/index.tsx --%% + ``` +</CollapsibleCode> + +### Step 3: Update the import paths to match your project setup. + +## API Reference + +To use this component in your project, include the following import statement in your file. + +```jsx +import { Input } from '@/components/ui/Input'; +``` + +```jsx +export default () => ( + <Input> + <InputField /> + <InputSlot> + <InputIcon>{/* Some Icon Component */}</InputIcon> + </InputSlot> + </Input> +); +``` + +### Component Props + +This section provides a comprehensive reference list for the component props, detailing descriptions, properties, types, and default behavior for easy project integration. + +#### Input + +It inherits all the properties of React Native's [View](https://reactnative.dev/docs/view) component. + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Prop</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Type</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Default</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Description</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isInvalid</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`When true, the input displays an error state.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isDisabled</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`When true, the input is disabled and cannot be edited.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isHovered</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`When true, the input displays a hover state.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isFocused</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`When true, the input displays a focus state.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isRequired</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`If true, sets aria-required="true" on the input.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isReadOnly</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`If true, the input value cannot be edited.`}</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +**Descendants Styling Props** +Props to style child components. + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Sx Prop</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Description</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>_input</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`Prop to style InputField Component`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>_icon</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`Prop to style InputIcon Component`}</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +#### InputField + +Contains all TextInput related layout style props and actions. +It inherits all the properties of React Native's [TextInput](https://reactnative.dev/docs/textInput#props) component. + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Prop</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Type</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Default</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Description</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>type</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText> 'text' | 'password'</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>'text'</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`If true, the input component obscures the text entered so that sensitive text like passwords stay secure.`}</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +#### InputSlot + +It inherits all the properties of React Native's [Pressable](https://reactnative.dev/docs/pressable) component. + +**Descendants Styling Props** +Props to style child components. + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Sx Prop</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Description</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>_icon</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`Prop to style InputIcon Component`}</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +#### InputIcon + +Contains all Icon related layout style props and actions. It inherits all the properties of React Native's [View](https://reactnative.dev/docs/view) component. + +### Features + +- Keyboard support for actions. +- Support for hover, focus and active states. +- Option to add your styles or use the default styles. + +### Accessibility + +We have outlined the various features that ensure the Input component is accessible to all users, including those with disabilities. These features help ensure that your application is inclusive and meets accessibility standards.Adheres to the [WAI-ARIA design pattern](https://www.w3.org/TR/wai-aria-1.2/#textbox). + +#### Keyboard + +- Setting the `aria-label` and `aria-hint` to help users understand the purpose and function of the Input + +#### Screen Reader + +- Compatible with screen readers such as VoiceOver and Talk-back. +- The `accessible` and `aria-label` props to provide descriptive information about the Input +- Setting `aria-traits` and `aria-hint` to provide contextual information about the various states of the Input, such as "double tap to edit". + +#### Focus Management + +- The `onFocus` and `onBlur` props to manage focus states and provide visual cues to users. This is especially important for users who rely on keyboard navigation. + +#### States + +- In error state, `aria-invalid` will be passed to indicate that the Input has an error, and providing support for an `aria-errormessage` to describe the error in more detail. +- In disabled state, `aria-hidden` will be passed to make input not focusable. +- In required state, `aria-required` will be passed to indicate that the Input is required. + +### Props + +Input component is created using TextInput component from react-native. It extends all the props supported by [React Native Text Input](https://reactnative.dev/docs/textinput#props), [utility props](/ui/docs/styling/utility-and-sx-props) and the props mentioned below. + +#### Input + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Name</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Value</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Default</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>size</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>xl | lg | md | sm</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>md</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>variant</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>underlined | outline | rounded</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>outline</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +## Spec Doc + +Explore the comprehensive details of the Input in this document, including its implementation details, checklist, and potential future additions. Dive into the thought process behind the component and gain insights into its development journey. + +<iframe + style={{ + borderRadius: '8px', + border: ' 1px solid rgba(0, 0, 0, 0.1)', + aspectRatio: 736 / 585, + }} + src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Fproto%2FNcXOxqKbdnGsLQNex3H76u%2F%25C2%25A0%25F0%259F%2593%259Agluestack-UI-handbook%3Fpage-id%3D213%253A12091%26type%3Ddesign%26node-id%3D213-12092%26viewport%3D256%252C289%252C0.03%26t%3DYlY4Jjtl91JuXCZS-1%26scaling%3Dscale-down%26starting-point-node-id%3D213%253A12092%26mode%3Ddesign" + allowFullScreen +></iframe> diff --git a/example/storybook-nativewind/src/components/Input/index.themed.stories.mdx b/example/storybook-nativewind/src/components/Input/index.themed.stories.mdx new file mode 100644 index 0000000000..edb2469f84 --- /dev/null +++ b/example/storybook-nativewind/src/components/Input/index.themed.stories.mdx @@ -0,0 +1,486 @@ +--- +title: gluestack-ui Input Component | Installation, Usage, and API + +description: The Input component is your go-to tool for gathering user input in a sleek and user-friendly text field. Whether you're designing a simple login form or a complex search feature, this component has got you covered. + +pageTitle: Input + +pageDescription: The Input component is your go-to tool for gathering user input in a sleek and user-friendly text field. Whether you're designing a simple login form or a complex search feature, this component has got you covered. + +showHeader: true +--- + +import { Meta } from '@storybook/addon-docs'; + +<Meta title="with-gluestack-style/components/Forms/Input" /> + +import { Input, InputField, InputIcon, InputSlot } from './Input'; +import { + Button, + ButtonText, + VStack, + Text as GSText, + Center, + Box, + FormControl, +} from '@gluestack-ui/themed'; +import { Heading, useState } from '@gluestack-ui/themed'; +import { Icon, SearchIcon, EyeIcon, EyeOffIcon } from '@gluestack-ui/themed'; +import { transformedCode } from '../../utils'; +import { + AppProvider, + CodePreview, + Table, + TableContainer, + Text, + InlineCode, +} from '@gluestack/design-system'; + +import Wrapper from '../../components-example/themed/Wrapper'; + +This is an illustration of **Input** component. + +<> + <CodePreview + showComponentRenderer={true} + showArgsController={true} + metaData={{ + code: ` + <Input {...props}> + <InputField + placeholder='Enter Text here' + /> + </Input> + `, + transformCode: (code) => { + return transformedCode(code); + }, + scope: { + Wrapper, + Input, + InputField, + InputIcon, + }, + argsType: { + variant: { + control: 'select', + options: ['rounded', 'outline', 'underlined'], + default: 'outline', + }, + size: { + control: 'select', + options: ['sm', 'md', 'lg', 'xl'], + default: 'md', + }, + isDisabled: { + control: 'boolean', + default: false, + }, + isInvalid: { + control: 'boolean', + default: false, + }, + isReadOnly: { + control: 'boolean', + default: false, + }, + }, + }} + /> +</> + +<br /> + +## Installation + +### Step 1: Install the following dependencies: + +```bash + +npm i @gluestack-ui/input + +``` + +### Step 2: Copy and paste the following code into your project. + +<CollapsibleCode> + ```jsx + %%-- File: components-example/themed/Input/index.tsx --%% + ``` +</CollapsibleCode> + +### Step 3: Update the import paths to match your project setup. + +## API Reference + +To use this component in your project, include the following import statement in your file. + +```jsx +import { Input } from '@/components/ui/Input'; +``` + +```jsx +export default () => ( + <Input> + <InputField /> + <InputSlot> + <InputIcon>{/* Some Icon Component */}</InputIcon> + </InputSlot> + </Input> +); +``` + +### Component Props + +This section provides a comprehensive reference list for the component props, detailing descriptions, properties, types, and default behavior for easy project integration. + +#### Input + +It inherits all the properties of React Native's [View](https://reactnative.dev/docs/view) component. + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Prop</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Type</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Default</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Description</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isInvalid</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`When true, the input displays an error state.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isDisabled</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`When true, the input is disabled and cannot be edited.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isHovered</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`When true, the input displays a hover state.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isFocused</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`When true, the input displays a focus state.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isRequired</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`If true, sets aria-required="true" on the input.`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>isReadOnly</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>bool</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>false</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`If true, the input value cannot be edited.`}</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +**Descendants Styling Props** +Props to style child components. + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Sx Prop</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Description</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>_input</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`Prop to style InputField Component`}</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>_icon</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`Prop to style InputIcon Component`}</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +#### InputField + +Contains all TextInput related layout style props and actions. +It inherits all the properties of React Native's [TextInput](https://reactnative.dev/docs/textInput#props) component. + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Prop</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Type</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Default</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Description</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>type</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText> 'text' | 'password'</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>'text'</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`If true, the input component obscures the text entered so that sensitive text like passwords stay secure.`}</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +#### InputSlot + +It inherits all the properties of React Native's [Pressable](https://reactnative.dev/docs/pressable) component. + +**Descendants Styling Props** +Props to style child components. + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Sx Prop</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Description</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>_icon</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>{`Prop to style InputIcon Component`}</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +#### InputIcon + +Contains all Icon related layout style props and actions. It inherits all the properties of React Native's [View](https://reactnative.dev/docs/view) component. + +### Features + +- Keyboard support for actions. +- Support for hover, focus and active states. +- Option to add your styles or use the default styles. + +### Accessibility + +We have outlined the various features that ensure the Input component is accessible to all users, including those with disabilities. These features help ensure that your application is inclusive and meets accessibility standards.Adheres to the [WAI-ARIA design pattern](https://www.w3.org/TR/wai-aria-1.2/#textbox). + +#### Keyboard + +- Setting the `aria-label` and `aria-hint` to help users understand the purpose and function of the Input + +#### Screen Reader + +- Compatible with screen readers such as VoiceOver and Talk-back. +- The `accessible` and `aria-label` props to provide descriptive information about the Input +- Setting `aria-traits` and `aria-hint` to provide contextual information about the various states of the Input, such as "double tap to edit". + +#### Focus Management + +- The `onFocus` and `onBlur` props to manage focus states and provide visual cues to users. This is especially important for users who rely on keyboard navigation. + +#### States + +- In error state, `aria-invalid` will be passed to indicate that the Input has an error, and providing support for an `aria-errormessage` to describe the error in more detail. +- In disabled state, `aria-hidden` will be passed to make input not focusable. +- In required state, `aria-required` will be passed to indicate that the Input is required. + +### Props + +Input component is created using TextInput component from react-native. It extends all the props supported by [React Native Text Input](https://reactnative.dev/docs/textinput#props), [utility props](/ui/docs/styling/utility-and-sx-props) and the props mentioned below. + +#### Input + +<> + <TableContainer> + <Table> + <Table.THead> + <Table.TR> + <Table.TH> + <Table.TText>Name</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Value</Table.TText> + </Table.TH> + <Table.TH> + <Table.TText>Default</Table.TText> + </Table.TH> + </Table.TR> + </Table.THead> + <Table.TBody> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>size</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>xl | lg | md | sm</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>md</Table.TText> + </Table.TD> + </Table.TR> + <Table.TR> + <Table.TD> + <Table.TText> + <InlineCode>variant</InlineCode> + </Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>underlined | outline | rounded</Table.TText> + </Table.TD> + <Table.TD> + <Table.TText>outline</Table.TText> + </Table.TD> + </Table.TR> + </Table.TBody> + </Table> + </TableContainer> +</> + +## Spec Doc + +Explore the comprehensive details of the Input in this document, including its implementation details, checklist, and potential future additions. Dive into the thought process behind the component and gain insights into its development journey. + +<iframe + style={{ + borderRadius: '8px', + border: ' 1px solid rgba(0, 0, 0, 0.1)', + aspectRatio: 736 / 585, + }} + src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Fproto%2FNcXOxqKbdnGsLQNex3H76u%2F%25C2%25A0%25F0%259F%2593%259Agluestack-UI-handbook%3Fpage-id%3D213%253A12091%26type%3Ddesign%26node-id%3D213-12092%26viewport%3D256%252C289%252C0.03%26t%3DYlY4Jjtl91JuXCZS-1%26scaling%3Dscale-down%26starting-point-node-id%3D213%253A12092%26mode%3Ddesign" + allowFullScreen +></iframe> From 56bc8d79cd509f49de726be92c70c9fae5e02e33 Mon Sep 17 00:00:00 2001 From: Rajat Chaudhary <rajatchaudhary.rc693@gmail.com> Date: Fri, 23 Feb 2024 15:46:14 +0530 Subject: [PATCH 2/2] fix: input- icon component --- .../nativewind/Input/index.tsx | 19 +- .../src/components/Input/index.stories.mdx | 653 ------------------ 2 files changed, 5 insertions(+), 667 deletions(-) delete mode 100644 example/storybook-nativewind/src/components/Input/index.stories.mdx diff --git a/example/storybook-nativewind/src/components-example/nativewind/Input/index.tsx b/example/storybook-nativewind/src/components-example/nativewind/Input/index.tsx index 5d01969463..ab20694599 100644 --- a/example/storybook-nativewind/src/components-example/nativewind/Input/index.tsx +++ b/example/storybook-nativewind/src/components-example/nativewind/Input/index.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { createInput } from '@gluestack-ui/input'; -import { AsForwarder } from '@gluestack-style/react'; import { View, Pressable, TextInput, Platform } from 'react-native'; import { tva, @@ -18,7 +17,7 @@ const UIInput = createInput({ Platform.OS === 'web' ? withStyleContext(View) : withStyleContextAndStates(View), - Icon: AsForwarder, + Icon: View, Slot: Pressable, Input: Platform.OS === 'web' ? TextInput : withStates(TextInput), }); @@ -48,7 +47,7 @@ const inputStyle = tva({ }); const inputIconStyle = tva({ - base: 'stroke-2 stroke-typography-400', + base: 'text-typography-400 fill-none', parentVariants: { size: { '2xs': 'h-3 w-3', @@ -98,7 +97,7 @@ cssInterop(UIInput.Input, { className: 'style' }); type IInputProps = React.ComponentProps<typeof UIInput> & VariantProps<typeof inputStyle>; - +//@ts-ignore const Input = React.forwardRef( ( { @@ -120,17 +119,11 @@ const Input = React.forwardRef( } ); -type IInputIconProps = React.ComponentProps<typeof UIInput.Icon> & - VariantProps<typeof inputIconStyle>; +type IInputIconProps = React.ComponentProps<typeof UIInput.Icon> & { as: any }; const InputIcon = React.forwardRef( ( - { - className, - as: AsComp, - fill = 'none', - ...props - }: { className?: any } & IInputIconProps, + { className, as: AsComp, ...props }: { className?: any } & IInputIconProps, ref ) => { const { size: parentSize } = useStyleContext(); @@ -140,7 +133,6 @@ const InputIcon = React.forwardRef( <AsComp ref={ref} {...props} - fill={fill} className={inputIconStyle({ parentVariants: { size: parentSize, @@ -154,7 +146,6 @@ const InputIcon = React.forwardRef( <UIInput.Icon ref={ref} {...props} - fill={fill} className={inputIconStyle({ parentVariants: { size: parentSize, diff --git a/example/storybook-nativewind/src/components/Input/index.stories.mdx b/example/storybook-nativewind/src/components/Input/index.stories.mdx deleted file mode 100644 index cfc257da61..0000000000 --- a/example/storybook-nativewind/src/components/Input/index.stories.mdx +++ /dev/null @@ -1,653 +0,0 @@ ---- -title: Input | gluestack-ui | Installation, Usage, and API - -description: The Input component is your go-to tool for gathering user input in a sleek and user-friendly text field. Whether you're designing a simple login form or a complex search feature, this component has got you covered. - -pageTitle: Input - -pageDescription: The Input component is your go-to tool for gathering user input in a sleek and user-friendly text field. Whether you're designing a simple login form or a complex search feature, this component has got you covered. - -showHeader: true ---- - -import { Meta } from '@storybook/addon-docs'; - -<Meta title="common/components/Input" /> - -import { Input, InputField, InputIcon, InputSlot } from './Input'; -import { - Button, - ButtonText, - VStack, - Text as GSText, - Center, - Box, - FormControl, -} from '@gluestack-ui/themed'; -import { Heading, useState } from '@gluestack-ui/themed'; -import { Icon, SearchIcon, EyeIcon, EyeOffIcon } from '@gluestack-ui/themed'; -import { transformedCode } from '../../utils'; -import { - AppProvider, - CodePreview, - Table, - TableContainer, - Text, - InlineCode, -} from '@gluestack/design-system'; - -import Wrapper from '../../components-example/themed/Wrapper'; - -This is an illustration of **Input** component. - -<> - <CodePreview - showComponentRenderer={true} - showArgsController={true} - metaData={{ - code: ` - <Input {...props}> - <InputField - placeholder='Enter Text here' - /> - </Input> - `, - transformCode: (code) => { - return transformedCode(code); - }, - scope: { - Wrapper, - Input, - InputField, - InputIcon, - }, - argsType: { - variant: { - control: 'select', - options: ['rounded', 'outline', 'underlined'], - default: 'outline', - }, - size: { - control: 'select', - options: ['sm', 'md', 'lg', 'xl'], - default: 'md', - }, - isDisabled: { - control: 'boolean', - default: false, - }, - isInvalid: { - control: 'boolean', - default: false, - }, - isReadOnly: { - control: 'boolean', - default: false, - }, - }, - }} - /> -</> - -<br /> - -## API Reference - -### Import - -To use this component in your project, include the following import statement in your file. - -```bash -import { Input } from '@gluestack-ui/themed'; -``` - -### Anatomy - -The structure provided below can help you identify and understand a Input component's various parts. - -```jsx -export default () => ( - <Input> - <InputField /> - <InputSlot> - <InputIcon>{/* Some Icon Component */}</InputIcon> - </InputSlot> - </Input> -); -``` - -### Component Props - -This section provides a comprehensive reference list for the component props, detailing descriptions, properties, types, and default behavior for easy project integration. - -#### Input - -It inherits all the properties of React Native's [View](https://reactnative.dev/docs/view) component. - -<> - <TableContainer> - <Table> - <Table.THead> - <Table.TR> - <Table.TH> - <Table.TText>Prop</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Type</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Default</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Description</Table.TText> - </Table.TH> - </Table.TR> - </Table.THead> - <Table.TBody> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>isInvalid</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>bool</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>false</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`When true, the input displays an error state.`}</Table.TText> - </Table.TD> - </Table.TR> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>isDisabled</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>bool</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>false</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`When true, the input is disabled and cannot be edited.`}</Table.TText> - </Table.TD> - </Table.TR> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>isHovered</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>bool</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>false</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`When true, the input displays a hover state.`}</Table.TText> - </Table.TD> - </Table.TR> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>isFocused</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>bool</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>false</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`When true, the input displays a focus state.`}</Table.TText> - </Table.TD> - </Table.TR> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>isRequired</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>bool</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>false</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`If true, sets aria-required="true" on the input.`}</Table.TText> - </Table.TD> - </Table.TR> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>isReadOnly</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>bool</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>false</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`If true, the input value cannot be edited.`}</Table.TText> - </Table.TD> - </Table.TR> - </Table.TBody> - </Table> - </TableContainer> -</> - -**Descendants Styling Props** -Props to style child components. - -<> - <TableContainer> - <Table> - <Table.THead> - <Table.TR> - <Table.TH> - <Table.TText>Sx Prop</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Description</Table.TText> - </Table.TH> - </Table.TR> - </Table.THead> - <Table.TBody> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>_input</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`Prop to style InputField Component`}</Table.TText> - </Table.TD> - </Table.TR> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>_icon</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`Prop to style InputIcon Component`}</Table.TText> - </Table.TD> - </Table.TR> - </Table.TBody> - </Table> - </TableContainer> -</> - -#### InputField - -Contains all TextInput related layout style props and actions. -It inherits all the properties of React Native's [TextInput](https://reactnative.dev/docs/textInput#props) component. - -<> - <TableContainer> - <Table> - <Table.THead> - <Table.TR> - <Table.TH> - <Table.TText>Prop</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Type</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Default</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Description</Table.TText> - </Table.TH> - </Table.TR> - </Table.THead> - <Table.TBody> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>type</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText> 'text' | 'password'</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>'text'</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`If true, the input component obscures the text entered so that sensitive text like passwords stay secure.`}</Table.TText> - </Table.TD> - </Table.TR> - </Table.TBody> - </Table> - </TableContainer> -</> - -#### InputSlot - -It inherits all the properties of React Native's [Pressable](https://reactnative.dev/docs/pressable) component. - -**Descendants Styling Props** -Props to style child components. - -<> - <TableContainer> - <Table> - <Table.THead> - <Table.TR> - <Table.TH> - <Table.TText>Sx Prop</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Description</Table.TText> - </Table.TH> - </Table.TR> - </Table.THead> - <Table.TBody> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>_icon</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>{`Prop to style InputIcon Component`}</Table.TText> - </Table.TD> - </Table.TR> - </Table.TBody> - </Table> - </TableContainer> -</> - -#### InputIcon - -Contains all Icon related layout style props and actions. It inherits all the properties of React Native's [View](https://reactnative.dev/docs/view) component. - -### Features - -- Keyboard support for actions. -- Support for hover, focus and active states. -- Option to add your styles or use the default styles. - -### Accessibility - -We have outlined the various features that ensure the Input component is accessible to all users, including those with disabilities. These features help ensure that your application is inclusive and meets accessibility standards.Adheres to the [WAI-ARIA design pattern](https://www.w3.org/TR/wai-aria-1.2/#textbox). - -#### Keyboard - -- Setting the `aria-label` and `aria-hint` to help users understand the purpose and function of the Input - -#### Screen Reader - -- Compatible with screen readers such as VoiceOver and Talk-back. -- The `accessible` and `aria-label` props to provide descriptive information about the Input -- Setting `aria-traits` and `aria-hint` to provide contextual information about the various states of the Input, such as "double tap to edit". - -#### Focus Management - -- The `onFocus` and `onBlur` props to manage focus states and provide visual cues to users. This is especially important for users who rely on keyboard navigation. - -#### States - -- In error state, `aria-invalid` will be passed to indicate that the Input has an error, and providing support for an `aria-errormessage` to describe the error in more detail. -- In disabled state, `aria-hidden` will be passed to make input not focusable. -- In required state, `aria-required` will be passed to indicate that the Input is required. - -## Themed - -The themed version of the component is a pre-styled version of the component, which allows you to quickly integrate the component into your project. The component's design and functionality are fully defined, allowing you to focus on the more important aspects of your project. To know more about Themed Library please visit this [link](https://gluestack.io/ui/docs/core-concepts/themed-library). - -### Props - -Input component is created using TextInput component from react-native. It extends all the props supported by [React Native Text Input](https://reactnative.dev/docs/textinput#props), [utility props](/ui/docs/styling/utility-and-sx-props) and the props mentioned below. - -#### Input - -<> - <TableContainer> - <Table> - <Table.THead> - <Table.TR> - <Table.TH> - <Table.TText>Name</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Value</Table.TText> - </Table.TH> - <Table.TH> - <Table.TText>Default</Table.TText> - </Table.TH> - </Table.TR> - </Table.THead> - <Table.TBody> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>size</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>xl | lg | md | sm</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>md</Table.TText> - </Table.TD> - </Table.TR> - <Table.TR> - <Table.TD> - <Table.TText> - <InlineCode>variant</InlineCode> - </Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>underlined | outline | rounded</Table.TText> - </Table.TD> - <Table.TD> - <Table.TText>outline</Table.TText> - </Table.TD> - </Table.TR> - </Table.TBody> - </Table> - </TableContainer> -</> - -### Examples - -The Examples section provides visual representations of the different variants of the component, allowing you to quickly and easily determine which one best fits your needs. Simply copy the code and integrate it into your project. - -#### Input type password with FormControl - -The Input component integrates with an icon and a button, providing users with a comprehensive login window inside a FormControl component. - -<> - <CodePreview - _rendererWrapper={{ py: '$8' }} - showComponentRenderer={true} - showArgsController={false} - metaData={{ - code: ` - function App() { - const [showPassword, setShowPassword] = useState(false); - const handleState = () => { - setShowPassword((showState) => { - return !showState; - }); - }; - return ( - <FormControl - p='$4' - borderWidth='$1' - borderRadius='$lg' - borderColor='$borderLight300' - $dark-borderWidth='$1' $dark-borderRadius='$lg' $dark-borderColor='$borderDark800' - > - <VStack space='xl'> - <Heading color='$text900' lineHeight='$md'> - Login - </Heading> - <VStack space='xs'> - <Text color='$text500' lineHeight='$xs'> - Email - </Text> - <Input> - <InputField - type="text" - /> - </Input> - </VStack> - <VStack space='xs'> - <Text color='$text500' lineHeight='$xs'> - Password - </Text> - <Input textAlign='center'> - <InputField - type={showPassword ? 'text' : 'password'} - /> - <InputSlot pr='$3' onPress={handleState}> - {/* EyeIcon, EyeOffIcon are both imported from 'lucide-react-native' */} - <InputIcon as={showPassword ? EyeIcon : EyeOffIcon} color='$darkBlue500'/> - </InputSlot> - </Input> - </VStack> - <Button - ml='auto' - onPress={()=>{ - setShowModal(false); - }} - > - <ButtonText color='$white'> - Save - </ButtonText> - </Button> - </VStack> - </FormControl> - ); - } - `, - transformCode: (code) => { - return transformedCode(code, 'function', 'App'); - }, - scope: { - Wrapper, - Input, - InputField, - InputIcon, - Button, - ButtonText, - VStack, - Text: GSText, - Heading, - useState, - Icon, - EyeIcon, - EyeOffIcon, - FormControl, - InputSlot, - }, - argsType: {}, - }} - /> -</> - -### Input with Icons - -The Input with Icons is a variation of the Input component that displays icons next to input field. It's commonly used in apps for a more visual representation of options and easier navigation. - -<> - <CodePreview - showComponentRenderer={true} - showArgsController={false} - metaData={{ - code: ` - <Input> - <InputSlot pl='$3'> - <InputIcon as={SearchIcon}/> - </InputSlot> - <InputField - placeholder="Search..." - /> - </Input> - `, - transformCode: (code) => { - return transformedCode(code); - }, - scope: { - Wrapper, - Input, - InputField, - InputIcon, - SearchIcon, - Icon, - InputSlot, - }, - argsType: {}, - }} -/> - -</> - -## Unstyled - -All the components in `gluestack-ui` are unstyled by default. To customize your UI using the extendedTheme, please refer to this [link](https://gluestack.io/ui/docs/theme-configuration/customizing-theme). The import names of components serve as keys to customize each component. - -<!-- - -### Customizing the Input - -We have a function called `createInput` which can be used to create a custom Input component. This function takes in a configuration object which contains the styled components that you want to use for the Input You can refer [gluestack.io/style](/style/docs/getting-started/styled) on how to use styled components. - -#### Usage - -Default styling of all these components can be found in the `components/core/input` file. For reference, you can view the [source code](https://github.com/gluestack/gluestack-ui/blob/main/packages/themed/src/components/Input) of the styled `Input` components. - -```jsx -// import the styles -import { Root, Input } from 'components/core/input/styled-components'; - -// import the createInput function -import { createInput } from '@gluestack-ui/input'; - -//import any icon -import { searchIcon } from '@gluestack/icons'; - -// Understanding the API -const InputField = createInput({ - Root, - Input, -}); - -// Using the input component -export default () => ( - <Input> - <InputSlot pl="$3"> - <InputIcon as={SearchIcon} /> - </InputSlot> - <InputField placeholder="your text goes here..." /> - </Input> -); -``` ---> - -## Spec Doc - -Explore the comprehensive details of the Input in this document, including its implementation details, checklist, and potential future additions. Dive into the thought process behind the component and gain insights into its development journey. - -<iframe - style={{ - borderRadius: '8px', - border: ' 1px solid rgba(0, 0, 0, 0.1)', - aspectRatio: 736 / 585, - }} - src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Fproto%2FNcXOxqKbdnGsLQNex3H76u%2F%25C2%25A0%25F0%259F%2593%259Agluestack-UI-handbook%3Fpage-id%3D213%253A12091%26type%3Ddesign%26node-id%3D213-12092%26viewport%3D256%252C289%252C0.03%26t%3DYlY4Jjtl91JuXCZS-1%26scaling%3Dscale-down%26starting-point-node-id%3D213%253A12092%26mode%3Ddesign" - allowFullScreen -></iframe>