@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.
Files changed (202) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/CHANGELOG.md +16 -0
  4. package/build/components/Accordion/AccordionTrigger.js +1 -1
  5. package/build/components/Banner/Banner.context.d.ts +7 -0
  6. package/build/components/Banner/Banner.context.js +8 -0
  7. package/build/components/Banner/Banner.js +10 -40
  8. package/build/components/Banner/Banner.props.d.ts +3 -5
  9. package/build/components/Banner/BannerIllustration.d.ts +4 -0
  10. package/build/components/Banner/BannerIllustration.js +53 -0
  11. package/build/components/Banner/BannerImage.d.ts +4 -0
  12. package/build/components/Banner/BannerImage.js +53 -0
  13. package/build/components/Banner/index.d.ts +2 -0
  14. package/build/components/Banner/index.js +2 -0
  15. package/build/components/Card/CardAction/CardAction.props.d.ts +2 -3
  16. package/build/components/Card/CardAction/CardActionRoot.js +1 -2
  17. package/build/components/Checkbox/Checkbox.js +1 -2
  18. package/build/components/Checkbox/Checkbox.props.d.ts +3 -3
  19. package/build/components/Checkbox/CheckboxImage.d.ts +2 -1
  20. package/build/components/Checkbox/CheckboxImage.js +8 -1
  21. package/build/components/Checkbox/CheckboxIndicator.js +3 -3
  22. package/build/components/DatePicker/DatePickerDay.js +3 -3
  23. package/build/components/ExpandableCard/ExpandableCard.props.d.ts +1 -2
  24. package/build/components/ExpandableCard/ExpandableCardTrigger.props.d.ts +4 -5
  25. package/build/components/ExpandableCard/ExpandableCardTriggerRoot.js +1 -14
  26. package/build/components/HighlightBanner/HighlightBanner.js +2 -6
  27. package/build/components/HighlightBanner/HighlightBanner.props.d.ts +2 -3
  28. package/build/components/HighlightBanner/HighlightBannerImage.d.ts +4 -0
  29. package/build/components/HighlightBanner/HighlightBannerImage.js +18 -0
  30. package/build/components/HighlightBanner/index.d.ts +1 -0
  31. package/build/components/HighlightBanner/index.js +1 -0
  32. package/build/components/Input/Input.d.ts +5 -7
  33. package/build/components/Input/Input.js +11 -4
  34. package/build/components/Input/InputField.d.ts +4 -7
  35. package/build/components/Input/InputField.js +6 -5
  36. package/build/components/List/ListItem/ListItem.props.d.ts +2 -2
  37. package/build/components/List/ListItem/ListItemRoot.js +1 -2
  38. package/build/components/Modal/Modal.js +2 -6
  39. package/build/components/Modal/Modal.props.d.ts +3 -2
  40. package/build/components/Modal/Modal.web.js +2 -6
  41. package/build/components/Modal/ModalImage.d.ts +4 -0
  42. package/build/components/Modal/ModalImage.js +18 -0
  43. package/build/components/Modal/index.d.ts +1 -0
  44. package/build/components/Modal/index.js +1 -0
  45. package/build/components/PillGroup/Pill.js +2 -2
  46. package/build/components/Radio/Radio.js +1 -2
  47. package/build/components/Radio/Radio.props.d.ts +3 -3
  48. package/build/components/Radio/RadioImage.d.ts +2 -1
  49. package/build/components/Radio/RadioImage.js +8 -1
  50. package/build/components/Radio/RadioIndicator.js +3 -3
  51. package/build/components/RadioCard/RadioCardIndicator.js +3 -3
  52. package/build/components/RadioCard/RadioCardRoot.js +3 -3
  53. package/build/components/Tabs/Tab.js +5 -5
  54. package/build/components/ToggleButton/ToggleButtonRoot.js +2 -2
  55. package/build/components/ToggleButtonCard/ToggleButtonCardRoot.js +3 -3
  56. package/build/components/UnstyledIconButton/UnstyledIconButtonRoot.js +1 -1
  57. package/build/components/VerificationInput/VerificationInput.d.ts +6 -0
  58. package/build/components/VerificationInput/VerificationInput.js +35 -0
  59. package/build/components/VerificationInput/VerificationInput.props.d.ts +49 -0
  60. package/build/components/VerificationInput/VerificationInput.props.js +1 -0
  61. package/build/components/VerificationInput/VerificationInputSlot.d.ts +9 -0
  62. package/build/components/VerificationInput/VerificationInputSlot.js +72 -0
  63. package/build/components/VerificationInput/index.d.ts +4 -0
  64. package/build/components/VerificationInput/index.js +3 -0
  65. package/build/components/VerificationInput/useVerificationInput.d.ts +14 -0
  66. package/build/components/VerificationInput/useVerificationInput.js +58 -0
  67. package/build/components/index.d.ts +1 -0
  68. package/build/components/index.js +1 -0
  69. package/build/utils/index.d.ts +2 -1
  70. package/build/utils/index.js +2 -1
  71. package/build/utils/isThemedImageProps.d.ts +4 -0
  72. package/build/utils/isThemedImageProps.js +4 -0
  73. package/docs/components/AllComponents.web.tsx +9 -0
  74. package/package.json +11 -12
  75. package/src/components/Accordion/Accordion.figma.tsx +23 -0
  76. package/src/components/Accordion/AccordionItemRoot.figma.tsx +47 -0
  77. package/src/components/Accordion/AccordionTrigger.tsx +1 -1
  78. package/src/components/Alert/Alert.figma.tsx +47 -0
  79. package/src/components/Avatar/Avatar.figma.tsx +33 -0
  80. package/src/components/Badge/Badge.figma.tsx +48 -24
  81. package/src/components/Banner/Banner.context.ts +11 -0
  82. package/src/components/Banner/Banner.docs.mdx +55 -37
  83. package/src/components/Banner/Banner.figma.tsx +15 -0
  84. package/src/components/Banner/Banner.props.ts +3 -5
  85. package/src/components/Banner/Banner.stories.tsx +86 -57
  86. package/src/components/Banner/Banner.tsx +24 -67
  87. package/src/components/Banner/BannerIllustration.figma.tsx +30 -0
  88. package/src/components/Banner/BannerIllustration.tsx +63 -0
  89. package/src/components/Banner/BannerImage.tsx +63 -0
  90. package/src/components/Banner/index.ts +2 -0
  91. package/src/components/BottomSheet/BottomSheetModal.figma.tsx +20 -0
  92. package/src/components/Button/Button.figma.tsx +60 -229
  93. package/src/components/Card/Card.docs.mdx +4 -4
  94. package/src/components/Card/Card.figma.tsx +43 -71
  95. package/src/components/Card/CardAction/CardAction.figma.tsx +44 -0
  96. package/src/components/Card/CardAction/CardAction.props.ts +2 -3
  97. package/src/components/Card/CardAction/CardAction.stories.tsx +5 -4
  98. package/src/components/Card/CardAction/CardActionRoot.tsx +4 -5
  99. package/src/components/Carousel/Carousel.figma.tsx +19 -0
  100. package/src/components/Checkbox/Checkbox.docs.mdx +23 -4
  101. package/src/components/Checkbox/Checkbox.figma.tsx +26 -41
  102. package/src/components/Checkbox/Checkbox.props.ts +3 -3
  103. package/src/components/Checkbox/Checkbox.stories.tsx +14 -8
  104. package/src/components/Checkbox/Checkbox.tsx +1 -2
  105. package/src/components/Checkbox/CheckboxGroup.figma.tsx +20 -0
  106. package/src/components/Checkbox/CheckboxImage.figma.tsx +27 -0
  107. package/src/components/Checkbox/CheckboxImage.tsx +8 -3
  108. package/src/components/Checkbox/CheckboxIndicator.tsx +3 -3
  109. package/src/components/Checkbox/CheckboxTileRoot.figma.tsx +32 -0
  110. package/src/components/CurrencyInput/CurrencyInput.figma.tsx +56 -0
  111. package/src/components/DateInput/DateInput.figma.tsx +75 -0
  112. package/src/components/DatePicker/DatePickerCalendar.figma.tsx +34 -0
  113. package/src/components/DatePicker/DatePickerDay.tsx +3 -3
  114. package/src/components/DatePickerInput/DatePickerInput.figma.tsx +62 -0
  115. package/src/components/DescriptionList/DescriptionList.figma.tsx +23 -0
  116. package/src/components/Divider/Divider.figma.tsx +23 -18
  117. package/src/components/ExpandableCard/ExpandableCard.docs.mdx +2 -2
  118. package/src/components/ExpandableCard/ExpandableCard.figma.tsx +54 -0
  119. package/src/components/ExpandableCard/ExpandableCard.props.ts +1 -2
  120. package/src/components/ExpandableCard/ExpandableCard.stories.tsx +3 -3
  121. package/src/components/ExpandableCard/ExpandableCardGroup.figma.tsx +23 -0
  122. package/src/components/ExpandableCard/ExpandableCardTrigger.props.ts +4 -5
  123. package/src/components/ExpandableCard/ExpandableCardTriggerRoot.tsx +2 -17
  124. package/src/components/FormField/FormField.figma.tsx +23 -0
  125. package/src/components/Helper/HelperText.figma.tsx +23 -0
  126. package/src/components/HighlightBanner/HighlightBanner.docs.mdx +73 -42
  127. package/src/components/HighlightBanner/HighlightBanner.props.ts +2 -3
  128. package/src/components/HighlightBanner/HighlightBanner.stories.tsx +85 -60
  129. package/src/components/HighlightBanner/HighlightBanner.tsx +3 -10
  130. package/src/components/HighlightBanner/HighlightBannerImage.tsx +20 -0
  131. package/src/components/HighlightBanner/index.ts +1 -0
  132. package/src/components/IconButton/IconButton.figma.tsx +55 -161
  133. package/src/components/IconContainer/IconContainer.figma.tsx +50 -0
  134. package/src/components/InlineLink/InlineLink.figma.tsx +33 -0
  135. package/src/components/Input/Input.figma.tsx +52 -110
  136. package/src/components/Input/Input.stories.tsx +76 -3
  137. package/src/components/Input/Input.tsx +110 -98
  138. package/src/components/Input/InputField.tsx +27 -26
  139. package/src/components/Label/Label.figma.tsx +24 -0
  140. package/src/components/Link/Link.figma.tsx +42 -0
  141. package/src/components/List/List.docs.mdx +15 -9
  142. package/src/components/List/List.figma.tsx +29 -108
  143. package/src/components/List/List.stories.tsx +2 -2
  144. package/src/components/List/ListAction/ListAction.figma.tsx +29 -0
  145. package/src/components/List/ListItem/ListItem.figma.tsx +40 -220
  146. package/src/components/List/ListItem/ListItem.props.ts +2 -2
  147. package/src/components/List/ListItem/ListItemLeadingContent.figma.tsx +29 -0
  148. package/src/components/List/ListItem/ListItemRoot.tsx +2 -3
  149. package/src/components/List/ListItem/ListItemTrailingContent.figma.tsx +27 -0
  150. package/src/components/Menu/Menu.figma.tsx +30 -0
  151. package/src/components/Menu/MenuItem.figma.tsx +31 -0
  152. package/src/components/Modal/Modal.docs.mdx +16 -4
  153. package/src/components/Modal/Modal.figma.tsx +56 -0
  154. package/src/components/Modal/Modal.props.ts +3 -2
  155. package/src/components/Modal/Modal.stories.tsx +2 -5
  156. package/src/components/Modal/Modal.tsx +2 -6
  157. package/src/components/Modal/Modal.web.tsx +2 -6
  158. package/src/components/Modal/ModalImage.tsx +20 -0
  159. package/src/components/Modal/index.ts +1 -0
  160. package/src/components/PillGroup/Pill.figma.tsx +25 -0
  161. package/src/components/PillGroup/Pill.tsx +3 -3
  162. package/src/components/PillGroup/PillGroup.figma.tsx +21 -0
  163. package/src/components/PillGroup/PillGroup.stories.tsx +1 -1
  164. package/src/components/ProgressStepper/ProgressStep.figma.tsx +30 -0
  165. package/src/components/ProgressStepper/ProgressStepper.figma.tsx +20 -0
  166. package/src/components/Radio/Radio.docs.mdx +21 -8
  167. package/src/components/Radio/Radio.figma.tsx +22 -42
  168. package/src/components/Radio/Radio.props.ts +3 -3
  169. package/src/components/Radio/Radio.stories.tsx +15 -11
  170. package/src/components/Radio/Radio.tsx +1 -2
  171. package/src/components/Radio/RadioGroup.figma.tsx +54 -0
  172. package/src/components/Radio/RadioImage.figma.tsx +27 -0
  173. package/src/components/Radio/RadioImage.tsx +8 -3
  174. package/src/components/Radio/RadioIndicator.tsx +3 -3
  175. package/src/components/Radio/RadioTileRoot.figma.tsx +31 -0
  176. package/src/components/RadioCard/RadioCardIndicator.tsx +3 -3
  177. package/src/components/RadioCard/RadioCardRoot.tsx +3 -3
  178. package/src/components/SectionHeader/SectionHeader.figma.tsx +30 -16
  179. package/src/components/Select/Select.figma.tsx +55 -0
  180. package/src/components/Select/SelectOption.figma.tsx +36 -0
  181. package/src/components/Spinner/Spinner.figma.tsx +20 -12
  182. package/src/components/Switch/Switch.figma.tsx +31 -23
  183. package/src/components/Tabs/Tab.tsx +5 -5
  184. package/src/components/Tabs/Tabs.figma.tsx +29 -0
  185. package/src/components/ThemedImage/ThemedImage.stories.tsx +1 -1
  186. package/src/components/Toast/ToastItem.figma.tsx +22 -0
  187. package/src/components/ToggleButton/ToggleButtonRoot.tsx +2 -2
  188. package/src/components/ToggleButtonCard/ToggleButtonCardRoot.tsx +3 -3
  189. package/src/components/UnstyledIconButton/UnstyledIconButton.figma.tsx +49 -0
  190. package/src/components/UnstyledIconButton/UnstyledIconButtonRoot.tsx +1 -1
  191. package/src/components/VerificationInput/VerificationInput.docs.mdx +68 -0
  192. package/src/components/VerificationInput/VerificationInput.props.ts +52 -0
  193. package/src/components/VerificationInput/VerificationInput.stories.tsx +140 -0
  194. package/src/components/VerificationInput/VerificationInput.tsx +89 -0
  195. package/src/components/VerificationInput/VerificationInputSlot.tsx +94 -0
  196. package/src/components/VerificationInput/index.ts +5 -0
  197. package/src/components/VerificationInput/useVerificationInput.ts +72 -0
  198. package/src/components/index.ts +1 -0
  199. package/src/utils/index.ts +2 -1
  200. package/src/utils/isThemedImageProps.ts +8 -0
  201. package/src/components/Checkbox/CheckboxIndicator.figma.tsx +0 -19
  202. 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,5 @@
1
+ import VerificationInput from './VerificationInput';
2
+ export { default as VerificationInput } from './VerificationInput';
3
+ export type { default as VerificationInputProps } from './VerificationInput.props';
4
+ export default VerificationInput;
5
+
@@ -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
+ };
@@ -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
 
@@ -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
- );