-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
587 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Dotfiles | ||
.babelrc | ||
.eslintignore | ||
.eslintrc.json | ||
.gitattributes | ||
_config.yml | ||
.editorconfig | ||
|
||
|
||
#Config files | ||
babel.config.js | ||
|
||
# Documents | ||
CONTRIBUTING.md | ||
ISSUE_TEMPLATE.txt | ||
img | ||
|
||
# Test cases | ||
__tests__ | ||
dist/__tests__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# @gluestack-ui/pin-input | ||
|
||
## 0.0.2 | ||
|
||
### Patch Changes | ||
|
||
- V 0.0.2 | ||
|
||
## 0.0.1 | ||
|
||
### Patch Changes | ||
|
||
- initial release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# @gluestack-style/input | ||
|
||
## Installation | ||
|
||
To use `@gluestack-ui/input`, all you need to do is install the | ||
`@gluestack-ui/input` package: | ||
|
||
```sh | ||
$ yarn add @gluestack-ui/pin-input | ||
|
||
# or | ||
|
||
$ npm i @gluestack-ui/pin-input | ||
``` | ||
|
||
## Usage | ||
|
||
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. Here's an example how to use this package to create one: | ||
|
||
```jsx | ||
import { Root, Input } from '../components/core/input/styled-components'; | ||
import { createInput } from '@gluestack-ui/input'; | ||
const InputField = createInput({ | ||
Root, | ||
Input, | ||
}); | ||
``` | ||
|
||
## Customizing the input: | ||
|
||
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/development/example/storybook/src/ui-components/Input/index.tsx) 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> | ||
<InputInput placeholder="your text goes here..." /> | ||
</Input> | ||
); | ||
``` | ||
|
||
More guides on how to get started are available | ||
[here](https://ui.gluestack.io/docs/components/forms/input). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
const path = require('path'); | ||
|
||
module.exports = function (api) { | ||
api.cache(true); | ||
return { | ||
presets: ['babel-preset-expo'], | ||
plugins: [ | ||
process.env.NODE_ENV !== 'production' | ||
? [ | ||
'module-resolver', | ||
{ | ||
alias: { | ||
['@gluestack-ui/form-control']: path.resolve( | ||
__dirname, | ||
'../form-control/src' | ||
), | ||
['@gluestack-ui/utils']: path.resolve( | ||
__dirname, | ||
'../utils/src' | ||
), | ||
// ['@gluestack-ui/utils']: path.resolve(__dirname, '../utils/src'), | ||
// For development, we want to alias the library to the source | ||
}, | ||
}, | ||
] | ||
: ['babel-plugin-react-docgen-typescript', { exclude: 'node_modules' }], | ||
], | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
{ | ||
"name": "@gluestack-ui/pin-input", | ||
"description": "A universal headless pin-input component for React Native, Next.js & React", | ||
"version": "0.0.2", | ||
"main": "lib/index", | ||
"module": "lib/index", | ||
"types": "lib/index.d.ts", | ||
"react-native": "src/index", | ||
"source": "src/index", | ||
"typings": "lib/index.d.ts", | ||
"scripts": { | ||
"prepare": "tsc", | ||
"release": "release-it", | ||
"watch": "tsc --watch", | ||
"build": "tsc", | ||
"clean": "rm -rf lib", | ||
"dev:web": "cd example/native && yarn web --clear", | ||
"storybook": "cd example/native/storybook && yarn web" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "^18.0.22", | ||
"@types/react-native": "^0.72.3", | ||
"babel-plugin-transform-remove-console": "^6.9.4", | ||
"react": "^18.1.0", | ||
"react-dom": "^18.1.0", | ||
"react-native": "^0.72.4", | ||
"react-native-builder-bob": "^0.20.1", | ||
"react-native-web": "^0.19.9", | ||
"tsconfig": "7", | ||
"typescript": "^5.6.3" | ||
}, | ||
"dependencies": { | ||
"@gluestack-ui/form-control": "^0.1.19", | ||
"@gluestack-ui/utils": "^0.1.14", | ||
"@react-native-aria/focus": "^0.2.9", | ||
"@react-native-aria/interactions": "0.2.13", | ||
"@react-native-clipboard/clipboard": "^1.15.0" | ||
}, | ||
"peerDependencies": { | ||
"react": ">=16", | ||
"react-dom": ">=16" | ||
}, | ||
"homepage": "https://github.com/gluestack/gluestack-ui/tree/main/packages/unstyled/pin-input#readme", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/gluestack/gluestack-ui.git" | ||
}, | ||
"files": [ | ||
"lib/", | ||
"src/" | ||
], | ||
"jest": { | ||
"preset": "jest-expo", | ||
"transform": { | ||
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js" | ||
}, | ||
"modulePathIgnorePatterns": [ | ||
"<rootDir>/example/*", | ||
"<rootDir>/lib/" | ||
], | ||
"transformIgnorePatterns": [ | ||
"node_modules/(?!(@react-native|react-native|expo-asset|expo-constants|@unimodules|react-native-unimodules|expo-font|react-native-svg|@expo/vector-icons|react-native-vector-icons|@react-native-aria/checkbox|@react-native-aria/interactions|@react-native-aria/button|@react-native-aria/switch|@react-native-aria/toggle|@react-native-aria/utils|@react-native-aria/*))" | ||
], | ||
"setupFiles": [ | ||
"<rootDir>/src/jest/mock.ts" | ||
] | ||
}, | ||
"keywords": [ | ||
"react", | ||
"native", | ||
"react-native", | ||
"pin-input", | ||
"gluestack-ui", | ||
"universal", | ||
"headless", | ||
"typescript", | ||
"component", | ||
"android", | ||
"ios", | ||
"nextjs" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import React, { forwardRef, useMemo, useRef, useState } from 'react'; | ||
import { Platform } from 'react-native'; | ||
import { useHover } from '@react-native-aria/interactions'; | ||
import { useFocusRing } from '@react-native-aria/focus'; | ||
import { useFormControl } from '@gluestack-ui/form-control'; | ||
import { usePinInput } from './PinInputContext'; | ||
import { mergeRefs } from '@gluestack-ui/utils'; | ||
|
||
export const PinInput = (StyledPinInput: any) => | ||
forwardRef( | ||
( | ||
{ | ||
children, | ||
onKeyPress, | ||
type, | ||
'aria-label': ariaLabel = 'Input Field', | ||
secureTextEntry, | ||
editable, | ||
disabled, | ||
index, | ||
...props | ||
}: any, | ||
ref?: any | ||
) => { | ||
const { | ||
isDisabled, | ||
isReadOnly, | ||
isInvalid, | ||
childRefs, | ||
isRequired, | ||
setInputValue, | ||
inputValue, | ||
handleBackSpace, | ||
} = usePinInput('PinInputContext'); | ||
|
||
// @ts-ignore | ||
const value = inputValue?.length > index ? inputValue[index] : ''; | ||
|
||
const inputRef = useRef(); | ||
|
||
const [isFocused, setIsFocused] = useState(false); | ||
|
||
const { isHovered } = useHover({}, inputRef); | ||
|
||
const inputProps = useFormControl({ | ||
isDisabled: props.isDisabled || disabled, | ||
isInvalid: props.isInvalid, | ||
isReadOnly: props.isReadOnly, | ||
isRequired: props.isRequired, | ||
id: props.id, | ||
}); | ||
|
||
const handlePaste = (pastedValue: any) => { | ||
// const newPastedValue = pastedValue.slice(0, -1); | ||
// // console.log('newPastedValue', newPastedValue); | ||
setInputValue(pastedValue); | ||
}; | ||
|
||
const { isFocusVisible }: any = useFocusRing(); | ||
|
||
const mergedRef = mergeRefs([ref, inputRef, childRefs[index]]); | ||
|
||
const handleFocus = (focusState: boolean, callback: any) => { | ||
setIsFocused(focusState); | ||
callback(); | ||
}; | ||
|
||
const editableProp = useMemo(() => { | ||
if (editable !== undefined) { | ||
return editable; | ||
} else { | ||
return isDisabled || inputProps.isDisabled || isReadOnly | ||
? false | ||
: true; | ||
} | ||
}, [isDisabled, inputProps.isDisabled, isReadOnly, editable]); | ||
|
||
const handleChange = (currentValue: string) => { | ||
if (currentValue.length > 2) { | ||
handlePaste(currentValue); | ||
} else { | ||
setInputValue((prev: string) => { | ||
if (currentValue === '') { | ||
return prev.slice(0, -1); | ||
} | ||
if (currentValue.length === 1) { | ||
prev += currentValue; | ||
return prev; | ||
} | ||
let newPrev = prev.slice(0, -1); | ||
newPrev = newPrev + currentValue.slice(-1); | ||
return newPrev; | ||
}); | ||
} | ||
props.onChange && props.onChange(currentValue); | ||
}; | ||
|
||
return ( | ||
<StyledPinInput | ||
keyboardType="numeric" | ||
{...props} | ||
value={value} | ||
states={{ | ||
focus: isFocused, | ||
invalid: isInvalid, | ||
readonly: isReadOnly, | ||
required: isRequired, | ||
hover: isHovered, | ||
focusVisible: isFocusVisible, | ||
disabled: isDisabled || inputProps.isDisabled, | ||
}} | ||
dataSet={{ | ||
focus: isFocused ? 'true' : 'false', | ||
invalid: isInvalid ? 'true' : 'false', | ||
readonly: isReadOnly ? 'true' : 'false', | ||
required: isRequired ? 'true' : 'false', | ||
hover: isHovered ? 'true' : 'false', | ||
focusVisible: isFocusVisible ? 'true' : 'false', | ||
disabled: isDisabled || inputProps.isDisabled ? 'true' : 'false', | ||
}} | ||
disabled={isDisabled || inputProps.isDisabled} | ||
secureTextEntry={secureTextEntry || type === 'password'} | ||
accessible | ||
aria-label={ariaLabel} | ||
aria-required={isRequired || inputProps.isRequired} | ||
aria-invalid={isInvalid || inputProps.isInvalid} | ||
aria-disabled={isDisabled || inputProps.isDisabled} | ||
aria-selected={Platform.OS !== 'web' ? isFocused : undefined} | ||
// ios accessibility | ||
accessibilityElementsHidden={isDisabled || inputProps.isDisabled} | ||
autoComplete="one-time-code" | ||
textContentType="oneTimeCode" | ||
readOnly={!editableProp} | ||
onKeyPress={(e: any) => { | ||
e.nativeEvent.key !== 'Backspace' && e.persist(); | ||
onKeyPress && onKeyPress(e); | ||
e.nativeEvent.key === 'Backspace' && handleBackSpace(index, value); | ||
}} | ||
onFocus={(e: any) => { | ||
handleFocus( | ||
true, | ||
props?.onFocus ? () => props?.onFocus(e) : () => {} | ||
); | ||
}} | ||
onBlur={(e: any) => { | ||
handleFocus( | ||
false, | ||
props?.onBlur ? () => props?.onBlur(e) : () => {} | ||
); | ||
}} | ||
onChangeText={handleChange} | ||
ref={mergedRef} | ||
> | ||
{children} | ||
</StyledPinInput> | ||
); | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import type { IPinInputContext } from './types'; | ||
import { createContext } from '@gluestack-ui/utils'; | ||
|
||
export const [PinInputProvider, usePinInput] = | ||
createContext<IPinInputContext>('PinInputContext'); |
Oops, something went wrong.