@utilitywarehouse/hearth-react-native 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +16 -0
- package/build/components/Accordion/AccordionTrigger.js +1 -1
- package/build/components/Banner/Banner.context.d.ts +7 -0
- package/build/components/Banner/Banner.context.js +8 -0
- package/build/components/Banner/Banner.js +10 -40
- package/build/components/Banner/Banner.props.d.ts +3 -5
- package/build/components/Banner/BannerIllustration.d.ts +4 -0
- package/build/components/Banner/BannerIllustration.js +53 -0
- package/build/components/Banner/BannerImage.d.ts +4 -0
- package/build/components/Banner/BannerImage.js +53 -0
- package/build/components/Banner/index.d.ts +2 -0
- package/build/components/Banner/index.js +2 -0
- package/build/components/Card/CardAction/CardAction.props.d.ts +2 -3
- package/build/components/Card/CardAction/CardActionRoot.js +1 -2
- package/build/components/Checkbox/Checkbox.js +1 -2
- package/build/components/Checkbox/Checkbox.props.d.ts +3 -3
- package/build/components/Checkbox/CheckboxImage.d.ts +2 -1
- package/build/components/Checkbox/CheckboxImage.js +8 -1
- package/build/components/Checkbox/CheckboxIndicator.js +3 -3
- package/build/components/DatePicker/DatePickerDay.js +3 -3
- package/build/components/ExpandableCard/ExpandableCard.props.d.ts +1 -2
- package/build/components/ExpandableCard/ExpandableCardTrigger.props.d.ts +4 -5
- package/build/components/ExpandableCard/ExpandableCardTriggerRoot.js +1 -14
- package/build/components/HighlightBanner/HighlightBanner.js +2 -6
- package/build/components/HighlightBanner/HighlightBanner.props.d.ts +2 -3
- package/build/components/HighlightBanner/HighlightBannerImage.d.ts +4 -0
- package/build/components/HighlightBanner/HighlightBannerImage.js +18 -0
- package/build/components/HighlightBanner/index.d.ts +1 -0
- package/build/components/HighlightBanner/index.js +1 -0
- package/build/components/Input/Input.d.ts +5 -7
- package/build/components/Input/Input.js +11 -4
- package/build/components/Input/InputField.d.ts +4 -7
- package/build/components/Input/InputField.js +6 -5
- package/build/components/List/ListItem/ListItem.props.d.ts +2 -2
- package/build/components/List/ListItem/ListItemRoot.js +1 -2
- package/build/components/Modal/Modal.js +2 -6
- package/build/components/Modal/Modal.props.d.ts +3 -2
- package/build/components/Modal/Modal.web.js +2 -6
- package/build/components/Modal/ModalImage.d.ts +4 -0
- package/build/components/Modal/ModalImage.js +18 -0
- package/build/components/Modal/index.d.ts +1 -0
- package/build/components/Modal/index.js +1 -0
- package/build/components/PillGroup/Pill.js +2 -2
- package/build/components/Radio/Radio.js +1 -2
- package/build/components/Radio/Radio.props.d.ts +3 -3
- package/build/components/Radio/RadioImage.d.ts +2 -1
- package/build/components/Radio/RadioImage.js +8 -1
- package/build/components/Radio/RadioIndicator.js +3 -3
- package/build/components/RadioCard/RadioCardIndicator.js +3 -3
- package/build/components/RadioCard/RadioCardRoot.js +3 -3
- package/build/components/Tabs/Tab.js +5 -5
- package/build/components/ToggleButton/ToggleButtonRoot.js +2 -2
- package/build/components/ToggleButtonCard/ToggleButtonCardRoot.js +3 -3
- package/build/components/UnstyledIconButton/UnstyledIconButtonRoot.js +1 -1
- package/build/components/VerificationInput/VerificationInput.d.ts +6 -0
- package/build/components/VerificationInput/VerificationInput.js +35 -0
- package/build/components/VerificationInput/VerificationInput.props.d.ts +49 -0
- package/build/components/VerificationInput/VerificationInput.props.js +1 -0
- package/build/components/VerificationInput/VerificationInputSlot.d.ts +9 -0
- package/build/components/VerificationInput/VerificationInputSlot.js +72 -0
- package/build/components/VerificationInput/index.d.ts +4 -0
- package/build/components/VerificationInput/index.js +3 -0
- package/build/components/VerificationInput/useVerificationInput.d.ts +14 -0
- package/build/components/VerificationInput/useVerificationInput.js +58 -0
- package/build/components/index.d.ts +1 -0
- package/build/components/index.js +1 -0
- package/build/utils/index.d.ts +2 -1
- package/build/utils/index.js +2 -1
- package/build/utils/isThemedImageProps.d.ts +4 -0
- package/build/utils/isThemedImageProps.js +4 -0
- package/docs/components/AllComponents.web.tsx +9 -0
- package/package.json +11 -12
- package/src/components/Accordion/Accordion.figma.tsx +23 -0
- package/src/components/Accordion/AccordionItemRoot.figma.tsx +47 -0
- package/src/components/Accordion/AccordionTrigger.tsx +1 -1
- package/src/components/Alert/Alert.figma.tsx +47 -0
- package/src/components/Avatar/Avatar.figma.tsx +33 -0
- package/src/components/Badge/Badge.figma.tsx +48 -24
- package/src/components/Banner/Banner.context.ts +11 -0
- package/src/components/Banner/Banner.docs.mdx +55 -37
- package/src/components/Banner/Banner.figma.tsx +15 -0
- package/src/components/Banner/Banner.props.ts +3 -5
- package/src/components/Banner/Banner.stories.tsx +86 -57
- package/src/components/Banner/Banner.tsx +24 -67
- package/src/components/Banner/BannerIllustration.figma.tsx +30 -0
- package/src/components/Banner/BannerIllustration.tsx +63 -0
- package/src/components/Banner/BannerImage.tsx +63 -0
- package/src/components/Banner/index.ts +2 -0
- package/src/components/BottomSheet/BottomSheetModal.figma.tsx +20 -0
- package/src/components/Button/Button.figma.tsx +60 -229
- package/src/components/Card/Card.docs.mdx +4 -4
- package/src/components/Card/Card.figma.tsx +43 -71
- package/src/components/Card/CardAction/CardAction.figma.tsx +44 -0
- package/src/components/Card/CardAction/CardAction.props.ts +2 -3
- package/src/components/Card/CardAction/CardAction.stories.tsx +5 -4
- package/src/components/Card/CardAction/CardActionRoot.tsx +4 -5
- package/src/components/Carousel/Carousel.figma.tsx +19 -0
- package/src/components/Checkbox/Checkbox.docs.mdx +23 -4
- package/src/components/Checkbox/Checkbox.figma.tsx +26 -41
- package/src/components/Checkbox/Checkbox.props.ts +3 -3
- package/src/components/Checkbox/Checkbox.stories.tsx +14 -8
- package/src/components/Checkbox/Checkbox.tsx +1 -2
- package/src/components/Checkbox/CheckboxGroup.figma.tsx +20 -0
- package/src/components/Checkbox/CheckboxImage.figma.tsx +27 -0
- package/src/components/Checkbox/CheckboxImage.tsx +8 -3
- package/src/components/Checkbox/CheckboxIndicator.tsx +3 -3
- package/src/components/Checkbox/CheckboxTileRoot.figma.tsx +32 -0
- package/src/components/CurrencyInput/CurrencyInput.figma.tsx +56 -0
- package/src/components/DateInput/DateInput.figma.tsx +75 -0
- package/src/components/DatePicker/DatePickerCalendar.figma.tsx +34 -0
- package/src/components/DatePicker/DatePickerDay.tsx +3 -3
- package/src/components/DatePickerInput/DatePickerInput.figma.tsx +62 -0
- package/src/components/DescriptionList/DescriptionList.figma.tsx +23 -0
- package/src/components/Divider/Divider.figma.tsx +23 -18
- package/src/components/ExpandableCard/ExpandableCard.docs.mdx +2 -2
- package/src/components/ExpandableCard/ExpandableCard.figma.tsx +54 -0
- package/src/components/ExpandableCard/ExpandableCard.props.ts +1 -2
- package/src/components/ExpandableCard/ExpandableCard.stories.tsx +3 -3
- package/src/components/ExpandableCard/ExpandableCardGroup.figma.tsx +23 -0
- package/src/components/ExpandableCard/ExpandableCardTrigger.props.ts +4 -5
- package/src/components/ExpandableCard/ExpandableCardTriggerRoot.tsx +2 -17
- package/src/components/FormField/FormField.figma.tsx +23 -0
- package/src/components/Helper/HelperText.figma.tsx +23 -0
- package/src/components/HighlightBanner/HighlightBanner.docs.mdx +73 -42
- package/src/components/HighlightBanner/HighlightBanner.props.ts +2 -3
- package/src/components/HighlightBanner/HighlightBanner.stories.tsx +85 -60
- package/src/components/HighlightBanner/HighlightBanner.tsx +3 -10
- package/src/components/HighlightBanner/HighlightBannerImage.tsx +20 -0
- package/src/components/HighlightBanner/index.ts +1 -0
- package/src/components/IconButton/IconButton.figma.tsx +55 -161
- package/src/components/IconContainer/IconContainer.figma.tsx +50 -0
- package/src/components/InlineLink/InlineLink.figma.tsx +33 -0
- package/src/components/Input/Input.figma.tsx +52 -110
- package/src/components/Input/Input.stories.tsx +76 -3
- package/src/components/Input/Input.tsx +110 -98
- package/src/components/Input/InputField.tsx +27 -26
- package/src/components/Label/Label.figma.tsx +24 -0
- package/src/components/Link/Link.figma.tsx +42 -0
- package/src/components/List/List.docs.mdx +15 -9
- package/src/components/List/List.figma.tsx +29 -108
- package/src/components/List/List.stories.tsx +2 -2
- package/src/components/List/ListAction/ListAction.figma.tsx +29 -0
- package/src/components/List/ListItem/ListItem.figma.tsx +40 -220
- package/src/components/List/ListItem/ListItem.props.ts +2 -2
- package/src/components/List/ListItem/ListItemLeadingContent.figma.tsx +29 -0
- package/src/components/List/ListItem/ListItemRoot.tsx +2 -3
- package/src/components/List/ListItem/ListItemTrailingContent.figma.tsx +27 -0
- package/src/components/Menu/Menu.figma.tsx +30 -0
- package/src/components/Menu/MenuItem.figma.tsx +31 -0
- package/src/components/Modal/Modal.docs.mdx +16 -4
- package/src/components/Modal/Modal.figma.tsx +56 -0
- package/src/components/Modal/Modal.props.ts +3 -2
- package/src/components/Modal/Modal.stories.tsx +2 -5
- package/src/components/Modal/Modal.tsx +2 -6
- package/src/components/Modal/Modal.web.tsx +2 -6
- package/src/components/Modal/ModalImage.tsx +20 -0
- package/src/components/Modal/index.ts +1 -0
- package/src/components/PillGroup/Pill.figma.tsx +25 -0
- package/src/components/PillGroup/Pill.tsx +3 -3
- package/src/components/PillGroup/PillGroup.figma.tsx +21 -0
- package/src/components/PillGroup/PillGroup.stories.tsx +1 -1
- package/src/components/ProgressStepper/ProgressStep.figma.tsx +30 -0
- package/src/components/ProgressStepper/ProgressStepper.figma.tsx +20 -0
- package/src/components/Radio/Radio.docs.mdx +21 -8
- package/src/components/Radio/Radio.figma.tsx +22 -42
- package/src/components/Radio/Radio.props.ts +3 -3
- package/src/components/Radio/Radio.stories.tsx +15 -11
- package/src/components/Radio/Radio.tsx +1 -2
- package/src/components/Radio/RadioGroup.figma.tsx +54 -0
- package/src/components/Radio/RadioImage.figma.tsx +27 -0
- package/src/components/Radio/RadioImage.tsx +8 -3
- package/src/components/Radio/RadioIndicator.tsx +3 -3
- package/src/components/Radio/RadioTileRoot.figma.tsx +31 -0
- package/src/components/RadioCard/RadioCardIndicator.tsx +3 -3
- package/src/components/RadioCard/RadioCardRoot.tsx +3 -3
- package/src/components/SectionHeader/SectionHeader.figma.tsx +30 -16
- package/src/components/Select/Select.figma.tsx +55 -0
- package/src/components/Select/SelectOption.figma.tsx +36 -0
- package/src/components/Spinner/Spinner.figma.tsx +20 -12
- package/src/components/Switch/Switch.figma.tsx +31 -23
- package/src/components/Tabs/Tab.tsx +5 -5
- package/src/components/Tabs/Tabs.figma.tsx +29 -0
- package/src/components/ThemedImage/ThemedImage.stories.tsx +1 -1
- package/src/components/Toast/ToastItem.figma.tsx +22 -0
- package/src/components/ToggleButton/ToggleButtonRoot.tsx +2 -2
- package/src/components/ToggleButtonCard/ToggleButtonCardRoot.tsx +3 -3
- package/src/components/UnstyledIconButton/UnstyledIconButton.figma.tsx +49 -0
- package/src/components/UnstyledIconButton/UnstyledIconButtonRoot.tsx +1 -1
- package/src/components/VerificationInput/VerificationInput.docs.mdx +68 -0
- package/src/components/VerificationInput/VerificationInput.props.ts +52 -0
- package/src/components/VerificationInput/VerificationInput.stories.tsx +140 -0
- package/src/components/VerificationInput/VerificationInput.tsx +89 -0
- package/src/components/VerificationInput/VerificationInputSlot.tsx +94 -0
- package/src/components/VerificationInput/index.ts +5 -0
- package/src/components/VerificationInput/useVerificationInput.ts +72 -0
- package/src/components/index.ts +1 -0
- package/src/utils/index.ts +2 -1
- package/src/utils/isThemedImageProps.ts +8 -0
- package/src/components/Checkbox/CheckboxIndicator.figma.tsx +0 -19
- package/src/components/Radio/RadioIndicator.figma.tsx +0 -21
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { InfoMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { VerificationInput } from '.';
|
|
5
|
+
import { VariantTitle } from '../../../docs/components';
|
|
6
|
+
import { Flex } from '../Flex';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Stories / VerificationInput',
|
|
10
|
+
component: VerificationInput,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'centered',
|
|
13
|
+
},
|
|
14
|
+
argTypes: {
|
|
15
|
+
value: { control: 'text' },
|
|
16
|
+
label: { control: 'text' },
|
|
17
|
+
helperText: { control: 'text' },
|
|
18
|
+
validationStatus: {
|
|
19
|
+
control: 'select',
|
|
20
|
+
options: ['initial', 'valid', 'invalid'],
|
|
21
|
+
},
|
|
22
|
+
validText: { control: 'text' },
|
|
23
|
+
invalidText: { control: 'text' },
|
|
24
|
+
disabled: { control: 'boolean' },
|
|
25
|
+
readonly: { control: 'boolean' },
|
|
26
|
+
secureTextEntry: { control: 'boolean' },
|
|
27
|
+
},
|
|
28
|
+
args: {
|
|
29
|
+
label: 'Verification Code',
|
|
30
|
+
validationStatus: 'initial',
|
|
31
|
+
},
|
|
32
|
+
} satisfies Meta<typeof VerificationInput>;
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<typeof meta>;
|
|
36
|
+
|
|
37
|
+
export const Playground: Story = {
|
|
38
|
+
render: args => {
|
|
39
|
+
const [value, setValue] = useState(args.value || '');
|
|
40
|
+
return (
|
|
41
|
+
<VerificationInput
|
|
42
|
+
{...args}
|
|
43
|
+
value={value}
|
|
44
|
+
onChangeText={text => {
|
|
45
|
+
setValue(text);
|
|
46
|
+
args.onChangeText?.(text);
|
|
47
|
+
}}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const Variants: Story = {
|
|
54
|
+
parameters: {
|
|
55
|
+
controls: { include: [] },
|
|
56
|
+
},
|
|
57
|
+
render: () => {
|
|
58
|
+
const [values, setValues] = useState({
|
|
59
|
+
default: '',
|
|
60
|
+
filled: '123456',
|
|
61
|
+
invalid: '123',
|
|
62
|
+
valid: '123456',
|
|
63
|
+
disabled: '',
|
|
64
|
+
secure: '123',
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const updateValue = (key: keyof typeof values) => (text: string) => {
|
|
68
|
+
setValues(prev => ({ ...prev, [key]: text }));
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Flex direction="column" space="lg" style={{ width: 400 }}>
|
|
73
|
+
<VariantTitle title="Default">
|
|
74
|
+
<VerificationInput
|
|
75
|
+
label="Verification Code"
|
|
76
|
+
helperText="Enter the code sent to your phone"
|
|
77
|
+
value={values.default}
|
|
78
|
+
onChangeText={updateValue('default')}
|
|
79
|
+
/>
|
|
80
|
+
</VariantTitle>
|
|
81
|
+
|
|
82
|
+
<VariantTitle title="Filled">
|
|
83
|
+
<VerificationInput
|
|
84
|
+
label="Filled Input"
|
|
85
|
+
value={values.filled}
|
|
86
|
+
onChangeText={updateValue('filled')}
|
|
87
|
+
/>
|
|
88
|
+
</VariantTitle>
|
|
89
|
+
|
|
90
|
+
<VariantTitle title="Invalid">
|
|
91
|
+
<VerificationInput
|
|
92
|
+
label="Invalid Input"
|
|
93
|
+
validationStatus="invalid"
|
|
94
|
+
invalidText="The code you entered is incorrect"
|
|
95
|
+
value={values.invalid}
|
|
96
|
+
onChangeText={updateValue('invalid')}
|
|
97
|
+
/>
|
|
98
|
+
</VariantTitle>
|
|
99
|
+
|
|
100
|
+
<VariantTitle title="Valid">
|
|
101
|
+
<VerificationInput
|
|
102
|
+
label="Valid Input"
|
|
103
|
+
validationStatus="valid"
|
|
104
|
+
validText="Code verified!"
|
|
105
|
+
value={values.valid}
|
|
106
|
+
onChangeText={updateValue('valid')}
|
|
107
|
+
/>
|
|
108
|
+
</VariantTitle>
|
|
109
|
+
|
|
110
|
+
<VariantTitle title="Disabled">
|
|
111
|
+
<VerificationInput
|
|
112
|
+
label="Disabled Input"
|
|
113
|
+
disabled
|
|
114
|
+
value={values.disabled}
|
|
115
|
+
onChangeText={updateValue('disabled')}
|
|
116
|
+
/>
|
|
117
|
+
</VariantTitle>
|
|
118
|
+
|
|
119
|
+
<VariantTitle title="Secure Text Entry">
|
|
120
|
+
<VerificationInput
|
|
121
|
+
label="Secure Input"
|
|
122
|
+
secureTextEntry
|
|
123
|
+
value={values.secure}
|
|
124
|
+
onChangeText={updateValue('secure')}
|
|
125
|
+
/>
|
|
126
|
+
</VariantTitle>
|
|
127
|
+
|
|
128
|
+
<VariantTitle title="With Helper Icon">
|
|
129
|
+
<VerificationInput
|
|
130
|
+
label="Helper Icon"
|
|
131
|
+
helperText="Some information"
|
|
132
|
+
helperIcon={InfoMediumIcon}
|
|
133
|
+
value={values.default}
|
|
134
|
+
onChangeText={updateValue('default')}
|
|
135
|
+
/>
|
|
136
|
+
</VariantTitle>
|
|
137
|
+
</Flex>
|
|
138
|
+
);
|
|
139
|
+
},
|
|
140
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { View } from 'react-native';
|
|
2
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
3
|
+
import { FormField } from '../FormField';
|
|
4
|
+
import { useVerificationInput } from './useVerificationInput';
|
|
5
|
+
import VerificationInputProps from './VerificationInput.props';
|
|
6
|
+
import { VerificationInputSlot } from './VerificationInputSlot';
|
|
7
|
+
|
|
8
|
+
const VerificationInput = ({
|
|
9
|
+
value = '',
|
|
10
|
+
onChangeText,
|
|
11
|
+
label,
|
|
12
|
+
helperText,
|
|
13
|
+
helperIcon,
|
|
14
|
+
validationStatus = 'initial',
|
|
15
|
+
validText,
|
|
16
|
+
invalidText,
|
|
17
|
+
disabled = false,
|
|
18
|
+
readonly = false,
|
|
19
|
+
secureTextEntry = false,
|
|
20
|
+
style,
|
|
21
|
+
...props
|
|
22
|
+
}: VerificationInputProps) => {
|
|
23
|
+
const length = 6;
|
|
24
|
+
const { inputRefs, focusedIndex, handleFocus, handleBlur, handleChangeText, handleKeyPress } =
|
|
25
|
+
useVerificationInput({
|
|
26
|
+
value,
|
|
27
|
+
onChangeText,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const slots = Array.from({ length }, (_, index) => index);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<FormField
|
|
34
|
+
label={label}
|
|
35
|
+
helperText={helperText}
|
|
36
|
+
helperIcon={helperIcon}
|
|
37
|
+
validationStatus={validationStatus}
|
|
38
|
+
validText={validText}
|
|
39
|
+
invalidText={invalidText}
|
|
40
|
+
disabled={disabled}
|
|
41
|
+
readonly={readonly}
|
|
42
|
+
style={[styles.root, style]}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
<View style={styles.slotsContainer}>
|
|
46
|
+
{slots.map(index => {
|
|
47
|
+
const char = value[index] || '';
|
|
48
|
+
const isActive = focusedIndex === index;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<VerificationInputSlot
|
|
52
|
+
key={index}
|
|
53
|
+
ref={ref => {
|
|
54
|
+
inputRefs.current[index] = ref;
|
|
55
|
+
}}
|
|
56
|
+
value={char}
|
|
57
|
+
isActive={isActive}
|
|
58
|
+
validationStatus={validationStatus}
|
|
59
|
+
disabled={disabled}
|
|
60
|
+
readonly={readonly}
|
|
61
|
+
secureTextEntry={secureTextEntry}
|
|
62
|
+
onChangeText={text => handleChangeText(text, index)}
|
|
63
|
+
onKeyPress={e => handleKeyPress(e, index)}
|
|
64
|
+
onFocus={() => handleFocus(index)}
|
|
65
|
+
onBlur={handleBlur}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
})}
|
|
69
|
+
</View>
|
|
70
|
+
</FormField>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const styles = StyleSheet.create(theme => ({
|
|
75
|
+
root: {
|
|
76
|
+
gap: theme.components.input.verification.gap,
|
|
77
|
+
width: '100%',
|
|
78
|
+
maxWidth: theme.components.input.maxWidth,
|
|
79
|
+
},
|
|
80
|
+
slotsContainer: {
|
|
81
|
+
flexDirection: 'row',
|
|
82
|
+
gap: theme.components.input.verification.gap,
|
|
83
|
+
width: '100%',
|
|
84
|
+
},
|
|
85
|
+
}));
|
|
86
|
+
|
|
87
|
+
VerificationInput.displayName = 'VerificationInput';
|
|
88
|
+
|
|
89
|
+
export default VerificationInput;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
import { TextInput, TextInputProps } from 'react-native';
|
|
3
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
4
|
+
import InputField from '../Input/InputField';
|
|
5
|
+
|
|
6
|
+
interface VerificationInputSlotProps extends TextInputProps {
|
|
7
|
+
isActive: boolean;
|
|
8
|
+
validationStatus: 'initial' | 'valid' | 'invalid';
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
readonly?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const VerificationInputSlot = forwardRef<TextInput, VerificationInputSlotProps>(
|
|
14
|
+
({ isActive, validationStatus, disabled, readonly, style, ...props }, ref) => {
|
|
15
|
+
styles.useVariants({
|
|
16
|
+
disabled,
|
|
17
|
+
readonly,
|
|
18
|
+
validationStatus,
|
|
19
|
+
active: isActive,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<InputField
|
|
24
|
+
ref={ref}
|
|
25
|
+
{...props}
|
|
26
|
+
editable={!disabled && !readonly}
|
|
27
|
+
selectTextOnFocus
|
|
28
|
+
keyboardType="number-pad"
|
|
29
|
+
style={[styles.slot, style]}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
VerificationInputSlot.displayName = 'VerificationInputSlot';
|
|
36
|
+
|
|
37
|
+
const styles = StyleSheet.create(theme => ({
|
|
38
|
+
slot: {
|
|
39
|
+
flex: 0,
|
|
40
|
+
width: theme.components.input.height,
|
|
41
|
+
height: theme.components.input.height,
|
|
42
|
+
borderWidth: theme.components.input.borderWidth,
|
|
43
|
+
borderColor: theme.color.border.strong,
|
|
44
|
+
borderRadius: theme.components.input.borderRadius,
|
|
45
|
+
backgroundColor: theme.color.surface.neutral.strong,
|
|
46
|
+
textAlign: 'center',
|
|
47
|
+
padding: 0,
|
|
48
|
+
variants: {
|
|
49
|
+
disabled: {
|
|
50
|
+
true: {
|
|
51
|
+
opacity: theme.opacity.disabled,
|
|
52
|
+
color: theme.color.text.secondary,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
readonly: {
|
|
56
|
+
true: {
|
|
57
|
+
borderColor: theme.color.border.subtle,
|
|
58
|
+
backgroundColor: theme.color.surface.neutral.subtle,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
validationStatus: {
|
|
62
|
+
initial: {},
|
|
63
|
+
valid: {
|
|
64
|
+
borderColor: theme.color.feedback.positive.border,
|
|
65
|
+
},
|
|
66
|
+
invalid: {
|
|
67
|
+
borderColor: theme.color.feedback.danger.border,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
active: {
|
|
71
|
+
true: {
|
|
72
|
+
borderColor: theme.color.border.strong,
|
|
73
|
+
borderWidth: theme.components.input.borderWidthFocused,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
compoundVariants: [
|
|
78
|
+
{
|
|
79
|
+
validationStatus: 'invalid',
|
|
80
|
+
active: true,
|
|
81
|
+
styles: {
|
|
82
|
+
borderColor: theme.color.feedback.danger.border,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
validationStatus: 'valid',
|
|
87
|
+
active: true,
|
|
88
|
+
styles: {
|
|
89
|
+
borderColor: theme.color.border.strong,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
}));
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useRef, useState } from 'react';
|
|
2
|
+
import { NativeSyntheticEvent, TextInput, TextInputKeyPressEventData } from 'react-native';
|
|
3
|
+
|
|
4
|
+
interface UseVerificationInputProps {
|
|
5
|
+
value: string;
|
|
6
|
+
onChangeText?: (text: string) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const useVerificationInput = ({ value, onChangeText }: UseVerificationInputProps) => {
|
|
10
|
+
const length = 6;
|
|
11
|
+
const inputRefs = useRef<(TextInput | null)[]>([]);
|
|
12
|
+
const [focusedIndex, setFocusedIndex] = useState<number | null>(null);
|
|
13
|
+
|
|
14
|
+
const handleFocus = (index: number) => {
|
|
15
|
+
setFocusedIndex(index);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const handleBlur = () => {
|
|
19
|
+
setFocusedIndex(null);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const handleChangeText = (text: string, index: number) => {
|
|
23
|
+
// Break down the text into an array of characters
|
|
24
|
+
const chars = Array(length).fill('');
|
|
25
|
+
for (let i = 0; i < value.length && i < length; i++) {
|
|
26
|
+
chars[i] = value[i];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (text.length > 1) {
|
|
30
|
+
// Handle paste
|
|
31
|
+
const pastedChars = text.slice(0, length - index).split('');
|
|
32
|
+
for (let i = 0; i < pastedChars.length; i++) {
|
|
33
|
+
chars[index + i] = pastedChars[i];
|
|
34
|
+
}
|
|
35
|
+
const nextIndex = Math.min(index + pastedChars.length, length - 1);
|
|
36
|
+
inputRefs.current[nextIndex]?.focus();
|
|
37
|
+
} else {
|
|
38
|
+
// Handle single char input
|
|
39
|
+
chars[index] = text;
|
|
40
|
+
if (text.length === 1 && index < length - 1) {
|
|
41
|
+
inputRefs.current[index + 1]?.focus();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
onChangeText?.(chars.join(''));
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleKeyPress = (e: NativeSyntheticEvent<TextInputKeyPressEventData>, index: number) => {
|
|
49
|
+
if (e.nativeEvent.key === 'Backspace') {
|
|
50
|
+
if (!value[index] && index > 0) {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
inputRefs.current[index - 1]?.focus();
|
|
53
|
+
|
|
54
|
+
const chars = Array(length).fill('');
|
|
55
|
+
for (let i = 0; i < value.length && i < length; i++) {
|
|
56
|
+
chars[i] = value[i];
|
|
57
|
+
}
|
|
58
|
+
chars[index - 1] = '';
|
|
59
|
+
onChangeText?.(chars.join(''));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
inputRefs,
|
|
66
|
+
focusedIndex,
|
|
67
|
+
handleFocus,
|
|
68
|
+
handleBlur,
|
|
69
|
+
handleChangeText,
|
|
70
|
+
handleKeyPress,
|
|
71
|
+
};
|
|
72
|
+
};
|
package/src/components/index.ts
CHANGED
|
@@ -54,6 +54,7 @@ export * from './Textarea';
|
|
|
54
54
|
export * from './ThemedImage';
|
|
55
55
|
export * from './Toast';
|
|
56
56
|
export * from './ToggleButtonCard';
|
|
57
|
+
export * from './VerificationInput';
|
|
57
58
|
|
|
58
59
|
export { FlatList, Image, KeyboardAvoidingView, ScrollView, SectionList, View } from 'react-native';
|
|
59
60
|
|
package/src/utils/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export { default as coloursAsArray, extractLightColorValues } from './coloursAsArray';
|
|
2
2
|
export { default as formatThousands } from './formatThousands';
|
|
3
3
|
export { default as getFlattenedColorValue } from './getFlattenedColorValue';
|
|
4
|
+
export { getInitials } from './getInitials';
|
|
4
5
|
export { default as getStyleValue } from './getStyleValue';
|
|
5
6
|
export { default as hexWithOpacity } from './hexWithOpacity';
|
|
6
|
-
export { getInitials } from './getInitials';
|
|
7
7
|
export { default as isEqual } from './isEqual';
|
|
8
|
+
export { default as isThemedImageProps } from './isThemedImageProps';
|
|
8
9
|
export * from './styleUtils';
|
|
9
10
|
export * from './themeValueHelpers';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ImageProps } from 'react-native';
|
|
2
|
+
import { ThemedImageProps } from 'src/components';
|
|
3
|
+
|
|
4
|
+
const isThemedImageProps = (props: ThemedImageProps | ImageProps): props is ThemedImageProps => {
|
|
5
|
+
return 'light' in props && 'dark' in props;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export default isThemedImageProps;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Checkbox } from './';
|
|
2
|
-
import figma from '@figma/code-connect';
|
|
3
|
-
|
|
4
|
-
const value = 'some-value';
|
|
5
|
-
const setValue = (isChecked: boolean) => console.log(isChecked);
|
|
6
|
-
|
|
7
|
-
figma.connect(
|
|
8
|
-
Checkbox,
|
|
9
|
-
'https://www.figma.com/design/3RY3OvLA88yZksRjOfjQJm/UW-App-UI?node-id=4454-3759&m=dev',
|
|
10
|
-
{
|
|
11
|
-
props: {
|
|
12
|
-
checked: figma.boolean('checked'),
|
|
13
|
-
disabled: figma.boolean('disabled'),
|
|
14
|
-
},
|
|
15
|
-
example: ({ disabled, checked }) => (
|
|
16
|
-
<Checkbox value={value} onChange={setValue} disabled={disabled} checked={checked} />
|
|
17
|
-
),
|
|
18
|
-
}
|
|
19
|
-
);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Radio, RadioGroup } from './';
|
|
2
|
-
import figma from '@figma/code-connect';
|
|
3
|
-
|
|
4
|
-
const value = 'some-value';
|
|
5
|
-
const setValue = (value: string) => console.log(value);
|
|
6
|
-
|
|
7
|
-
figma.connect(
|
|
8
|
-
Radio,
|
|
9
|
-
'https://www.figma.com/design/3RY3OvLA88yZksRjOfjQJm/UW-App-UI?node-id=4461-7535&m=dev',
|
|
10
|
-
{
|
|
11
|
-
props: {
|
|
12
|
-
checked: figma.boolean('checked', { true: 'some-value', false: undefined }),
|
|
13
|
-
disabled: figma.boolean('disabled'),
|
|
14
|
-
},
|
|
15
|
-
example: ({ disabled, checked }) => (
|
|
16
|
-
<RadioGroup value={checked} onChange={setValue}>
|
|
17
|
-
<Radio value={value} disabled={disabled} />
|
|
18
|
-
</RadioGroup>
|
|
19
|
-
),
|
|
20
|
-
}
|
|
21
|
-
);
|