@utilitywarehouse/hearth-react-native 0.10.0 → 0.12.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 +18 -0
- package/build/components/Avatar/Avatar.d.ts +6 -0
- package/build/components/Avatar/Avatar.js +80 -0
- package/build/components/Avatar/Avatar.props.d.ts +28 -0
- package/build/components/Avatar/Avatar.props.js +1 -0
- package/build/components/Avatar/index.d.ts +2 -0
- package/build/components/Avatar/index.js +1 -0
- 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/DateInput/DateInput.d.ts +6 -0
- package/build/components/DateInput/DateInput.js +19 -0
- package/build/components/DateInput/DateInput.props.d.ts +79 -0
- package/build/components/DateInput/DateInput.props.js +1 -0
- package/build/components/DateInput/DateInputSegment.d.ts +20 -0
- package/build/components/DateInput/DateInputSegment.js +31 -0
- package/build/components/DateInput/index.d.ts +2 -0
- package/build/components/DateInput/index.js +1 -0
- 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/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/index.d.ts +2 -0
- package/build/components/index.js +2 -0
- package/build/utils/getInitials.d.ts +1 -0
- package/build/utils/getInitials.js +8 -0
- package/build/utils/index.d.ts +2 -0
- package/build/utils/index.js +2 -0
- package/build/utils/isThemedImageProps.d.ts +4 -0
- package/build/utils/isThemedImageProps.js +4 -0
- package/docs/components/AllComponents.web.tsx +18 -1
- package/package.json +2 -2
- package/src/components/Avatar/Avatar.docs.mdx +105 -0
- package/src/components/Avatar/Avatar.props.ts +31 -0
- package/src/components/Avatar/Avatar.stories.tsx +77 -0
- package/src/components/Avatar/Avatar.tsx +136 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/Banner/Banner.context.ts +11 -0
- package/src/components/Banner/Banner.docs.mdx +55 -37
- 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.tsx +63 -0
- package/src/components/Banner/BannerImage.tsx +63 -0
- package/src/components/Banner/index.ts +2 -0
- package/src/components/Card/Card.docs.mdx +4 -4
- package/src/components/Card/CardAction/CardAction.props.ts +2 -3
- package/src/components/Card/CardAction/CardAction.stories.tsx +4 -3
- package/src/components/Card/CardAction/CardActionRoot.tsx +4 -5
- package/src/components/Checkbox/Checkbox.docs.mdx +23 -4
- 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/CheckboxImage.tsx +8 -3
- package/src/components/DateInput/DateInput.docs.mdx +163 -0
- package/src/components/DateInput/DateInput.props.ts +80 -0
- package/src/components/DateInput/DateInput.stories.tsx +269 -0
- package/src/components/DateInput/DateInput.tsx +117 -0
- package/src/components/DateInput/DateInputSegment.tsx +83 -0
- package/src/components/DateInput/index.ts +2 -0
- package/src/components/ExpandableCard/ExpandableCard.docs.mdx +2 -2
- package/src/components/ExpandableCard/ExpandableCard.props.ts +1 -2
- package/src/components/ExpandableCard/ExpandableCard.stories.tsx +3 -3
- package/src/components/ExpandableCard/ExpandableCardTrigger.props.ts +4 -5
- package/src/components/ExpandableCard/ExpandableCardTriggerRoot.tsx +2 -17
- 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/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/List/List.docs.mdx +15 -9
- package/src/components/List/List.stories.tsx +2 -2
- package/src/components/List/ListItem/ListItem.props.ts +2 -2
- package/src/components/List/ListItem/ListItemRoot.tsx +2 -3
- package/src/components/Modal/Modal.docs.mdx +16 -4
- 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/PillGroup.stories.tsx +1 -1
- package/src/components/Radio/Radio.docs.mdx +21 -8
- 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/RadioImage.tsx +8 -3
- package/src/components/index.ts +2 -0
- package/src/utils/getInitials.ts +7 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/isThemedImageProps.ts +8 -0
|
@@ -4,6 +4,7 @@ import { Button } from '../Button';
|
|
|
4
4
|
import { Flex } from '../Flex';
|
|
5
5
|
import { Link } from '../Link';
|
|
6
6
|
import HighlightBanner from './HighlightBanner';
|
|
7
|
+
import HighlightBannerImage from './HighlightBannerImage';
|
|
7
8
|
|
|
8
9
|
const meta = {
|
|
9
10
|
title: 'Stories / HighlightBanner',
|
|
@@ -49,11 +50,13 @@ const meta = {
|
|
|
49
50
|
heading: 'Featured Content',
|
|
50
51
|
headingColor: 'highlight',
|
|
51
52
|
description: 'This is a description of the featured content that appears below the image.',
|
|
52
|
-
image:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
image: (
|
|
54
|
+
<HighlightBannerImage
|
|
55
|
+
source={{
|
|
56
|
+
uri: 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=800&q=80',
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
|
+
),
|
|
57
60
|
},
|
|
58
61
|
} satisfies Meta<typeof HighlightBanner>;
|
|
59
62
|
|
|
@@ -105,11 +108,13 @@ export const ColorVariants: Story = {
|
|
|
105
108
|
{...args}
|
|
106
109
|
heading="Energy Blue"
|
|
107
110
|
headingColor="energy"
|
|
108
|
-
image={
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
image={
|
|
112
|
+
<HighlightBannerImage
|
|
113
|
+
source={{
|
|
114
|
+
uri: 'https://images.unsplash.com/photo-1473186578172-c141e6798cf4?w=800&q=80',
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
}
|
|
113
118
|
description="Featured content with energy blue heading"
|
|
114
119
|
link={<Link onPress={() => console.log('pressed')}>Learn more</Link>}
|
|
115
120
|
/>
|
|
@@ -117,22 +122,26 @@ export const ColorVariants: Story = {
|
|
|
117
122
|
{...args}
|
|
118
123
|
heading="Broadband Green"
|
|
119
124
|
headingColor="broadband"
|
|
120
|
-
image={
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
image={
|
|
126
|
+
<HighlightBannerImage
|
|
127
|
+
source={{
|
|
128
|
+
uri: 'https://images.unsplash.com/photo-1501594907352-04cda38ebc29?w=800&q=80',
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
}
|
|
125
132
|
description="Featured content with broadband green heading"
|
|
126
133
|
/>
|
|
127
134
|
<HighlightBanner
|
|
128
135
|
{...args}
|
|
129
136
|
heading="Insurance Orange"
|
|
130
137
|
headingColor="insurance"
|
|
131
|
-
image={
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
138
|
+
image={
|
|
139
|
+
<HighlightBannerImage
|
|
140
|
+
source={{
|
|
141
|
+
uri: 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=800&q=80',
|
|
142
|
+
}}
|
|
143
|
+
/>
|
|
144
|
+
}
|
|
136
145
|
description="Featured content with insurance orange heading"
|
|
137
146
|
button={<Button onPress={() => console.log('pressed')}>Get Started</Button>}
|
|
138
147
|
/>
|
|
@@ -140,11 +149,13 @@ export const ColorVariants: Story = {
|
|
|
140
149
|
{...args}
|
|
141
150
|
heading="Cashback Lilac"
|
|
142
151
|
headingColor="cashback"
|
|
143
|
-
image={
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
152
|
+
image={
|
|
153
|
+
<HighlightBannerImage
|
|
154
|
+
source={{
|
|
155
|
+
uri: 'https://images.unsplash.com/photo-1506748686214-e9df14d4d9d0?w=800&q=80',
|
|
156
|
+
}}
|
|
157
|
+
/>
|
|
158
|
+
}
|
|
148
159
|
description="Featured content with cashback lilac heading"
|
|
149
160
|
button={<Button onPress={() => console.log('pressed')}>Get Started</Button>}
|
|
150
161
|
/>
|
|
@@ -152,11 +163,13 @@ export const ColorVariants: Story = {
|
|
|
152
163
|
{...args}
|
|
153
164
|
heading="Pig Pink"
|
|
154
165
|
headingColor="pig"
|
|
155
|
-
image={
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
166
|
+
image={
|
|
167
|
+
<HighlightBannerImage
|
|
168
|
+
source={{
|
|
169
|
+
uri: 'https://images.unsplash.com/photo-1494526585095-c41746248156?w=800&q=80',
|
|
170
|
+
}}
|
|
171
|
+
/>
|
|
172
|
+
}
|
|
160
173
|
description="Featured content with pig pink heading"
|
|
161
174
|
link={<Link onPress={() => console.log('pressed')}>Learn more</Link>}
|
|
162
175
|
/>
|
|
@@ -164,22 +177,26 @@ export const ColorVariants: Story = {
|
|
|
164
177
|
{...args}
|
|
165
178
|
heading="Mobile Rose"
|
|
166
179
|
headingColor="mobile"
|
|
167
|
-
image={
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
180
|
+
image={
|
|
181
|
+
<HighlightBannerImage
|
|
182
|
+
source={{
|
|
183
|
+
uri: 'https://images.unsplash.com/photo-1511707171634-5f897ff02aa9?w=800&q=80',
|
|
184
|
+
}}
|
|
185
|
+
/>
|
|
186
|
+
}
|
|
172
187
|
description="Featured content with mobile rose heading"
|
|
173
188
|
/>
|
|
174
189
|
<HighlightBanner
|
|
175
190
|
{...args}
|
|
176
191
|
heading="Highlight Yellow"
|
|
177
192
|
headingColor="highlight"
|
|
178
|
-
image={
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
193
|
+
image={
|
|
194
|
+
<HighlightBannerImage
|
|
195
|
+
source={{
|
|
196
|
+
uri: 'https://images.unsplash.com/photo-1504384308090-c894fdcc538d?w=800&q=80',
|
|
197
|
+
}}
|
|
198
|
+
/>
|
|
199
|
+
}
|
|
183
200
|
description="Featured content with highlight yellow heading"
|
|
184
201
|
/>
|
|
185
202
|
</Flex>
|
|
@@ -226,11 +243,13 @@ export const DifferentImages: Story = {
|
|
|
226
243
|
{...args}
|
|
227
244
|
heading="Nature Landscape"
|
|
228
245
|
headingColor="broadband"
|
|
229
|
-
image={
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
246
|
+
image={
|
|
247
|
+
<HighlightBannerImage
|
|
248
|
+
source={{
|
|
249
|
+
uri: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&q=80',
|
|
250
|
+
}}
|
|
251
|
+
/>
|
|
252
|
+
}
|
|
234
253
|
description="Beautiful mountain landscape with clear blue sky"
|
|
235
254
|
link={<Link onPress={() => console.log('pressed')}>View gallery</Link>}
|
|
236
255
|
/>
|
|
@@ -240,11 +259,13 @@ export const DifferentImages: Story = {
|
|
|
240
259
|
{...args}
|
|
241
260
|
heading="Urban Architecture"
|
|
242
261
|
headingColor="highlight"
|
|
243
|
-
image={
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
262
|
+
image={
|
|
263
|
+
<HighlightBannerImage
|
|
264
|
+
source={{
|
|
265
|
+
uri: 'https://images.unsplash.com/photo-1480714378408-67cf0d13bc1b?w=800&q=80',
|
|
266
|
+
}}
|
|
267
|
+
/>
|
|
268
|
+
}
|
|
248
269
|
description="Modern city buildings and urban design"
|
|
249
270
|
button={<Button onPress={() => console.log('pressed')}>Explore Cities</Button>}
|
|
250
271
|
/>
|
|
@@ -254,11 +275,13 @@ export const DifferentImages: Story = {
|
|
|
254
275
|
{...args}
|
|
255
276
|
heading="Ocean Waves"
|
|
256
277
|
headingColor="energy"
|
|
257
|
-
image={
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
278
|
+
image={
|
|
279
|
+
<HighlightBannerImage
|
|
280
|
+
source={{
|
|
281
|
+
uri: 'https://images.unsplash.com/photo-1505142468610-359e7d316be0?w=800&q=80',
|
|
282
|
+
}}
|
|
283
|
+
/>
|
|
284
|
+
}
|
|
262
285
|
description="Stunning ocean views and coastal beauty"
|
|
263
286
|
/>
|
|
264
287
|
</View>
|
|
@@ -275,11 +298,13 @@ export const LongContent: Story = {
|
|
|
275
298
|
{...args}
|
|
276
299
|
heading="Extended Information Card"
|
|
277
300
|
headingColor="energy"
|
|
278
|
-
image={
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
301
|
+
image={
|
|
302
|
+
<HighlightBannerImage
|
|
303
|
+
source={{
|
|
304
|
+
uri: 'https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=800&q=80',
|
|
305
|
+
}}
|
|
306
|
+
/>
|
|
307
|
+
}
|
|
283
308
|
description="This is a much longer description that demonstrates how the component handles extended text content. It includes multiple sentences and provides more detailed information about the featured content, ensuring the layout remains clean and readable even with more text."
|
|
284
309
|
button={<Button onPress={() => console.log('pressed')}>Read Full Article</Button>}
|
|
285
310
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { View } from 'react-native';
|
|
2
2
|
import { StyleSheet } from 'react-native-unistyles';
|
|
3
3
|
import { BodyText } from '../BodyText';
|
|
4
4
|
import { Card } from '../Card';
|
|
@@ -26,11 +26,7 @@ const HighlightBanner = ({
|
|
|
26
26
|
{heading}
|
|
27
27
|
</BodyText>
|
|
28
28
|
</View>
|
|
29
|
-
{!!image && (
|
|
30
|
-
<View style={styles.imageContainer(imageContainerHeight)}>
|
|
31
|
-
<Image resizeMode="cover" {...image} style={[styles.image, image?.style]} />
|
|
32
|
-
</View>
|
|
33
|
-
)}
|
|
29
|
+
{!!image && <View style={styles.imageContainer(imageContainerHeight)}>{image}</View>}
|
|
34
30
|
<View style={styles.footer}>
|
|
35
31
|
<BodyText size="md" textAlign="center">
|
|
36
32
|
{description}
|
|
@@ -99,10 +95,7 @@ const styles = StyleSheet.create(theme => ({
|
|
|
99
95
|
width: '100%',
|
|
100
96
|
height,
|
|
101
97
|
}),
|
|
102
|
-
|
|
103
|
-
width: '100%',
|
|
104
|
-
height: '100%',
|
|
105
|
-
},
|
|
98
|
+
|
|
106
99
|
footer: {
|
|
107
100
|
padding: theme.components.banner.highlight.padding,
|
|
108
101
|
gap: theme.components.banner.highlight.content.gap,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Image, ImageProps } from 'react-native';
|
|
2
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
3
|
+
import { isThemedImageProps } from '../../utils';
|
|
4
|
+
import { ThemedImage, ThemedImageProps } from '../ThemedImage';
|
|
5
|
+
|
|
6
|
+
const HighlightBannerImage = (props: ImageProps | ThemedImageProps) => {
|
|
7
|
+
if (isThemedImageProps(props)) {
|
|
8
|
+
return <ThemedImage {...props} style={[styles.image, props.style]} />;
|
|
9
|
+
}
|
|
10
|
+
return <Image resizeMode="cover" {...props} style={[styles.image, props.style]} />;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const styles = StyleSheet.create({
|
|
14
|
+
image: {
|
|
15
|
+
width: '100%',
|
|
16
|
+
height: '100%',
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export default HighlightBannerImage;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { Meta, StoryObj } from '@storybook/react-
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-native';
|
|
2
2
|
import * as Icons from '@utilitywarehouse/hearth-react-native-icons';
|
|
3
3
|
import { EmailMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
4
|
-
import { useState } from 'react';
|
|
5
|
-
import { NativeSyntheticEvent, TextInputChangeEventData } from 'react-native';
|
|
4
|
+
import { useRef, useState } from 'react';
|
|
5
|
+
import { NativeSyntheticEvent, TextInput, TextInputChangeEventData, View } from 'react-native';
|
|
6
6
|
import { Input } from '.';
|
|
7
7
|
import { VariantTitle } from '../../../docs/components';
|
|
8
|
+
import { useTheme } from '../../hooks';
|
|
9
|
+
import { BodyText } from '../BodyText';
|
|
10
|
+
import { Button } from '../Button';
|
|
8
11
|
import { Flex } from '../Flex';
|
|
9
12
|
|
|
10
13
|
const meta = {
|
|
@@ -73,6 +76,7 @@ export default meta;
|
|
|
73
76
|
type Story = StoryObj<typeof meta>;
|
|
74
77
|
|
|
75
78
|
export const Playground: Story = {
|
|
79
|
+
// @ts-expect-error - This is a playground
|
|
76
80
|
render: ({ leadingIcon: leading, trailingIcon: trailing, ...args }) => {
|
|
77
81
|
// @ts-expect-error - This is a playground
|
|
78
82
|
const leadingIcon = leading === 'none' ? undefined : Icons[leading];
|
|
@@ -152,3 +156,72 @@ export const Variants: Story = {
|
|
|
152
156
|
);
|
|
153
157
|
},
|
|
154
158
|
};
|
|
159
|
+
|
|
160
|
+
export const RefTest: Story = {
|
|
161
|
+
parameters: {
|
|
162
|
+
controls: { include: [] },
|
|
163
|
+
},
|
|
164
|
+
render: () => {
|
|
165
|
+
const inputRef = useRef<TextInput>(null);
|
|
166
|
+
const [refStatus, setRefStatus] = useState('Ref not tested yet');
|
|
167
|
+
const theme = useTheme();
|
|
168
|
+
|
|
169
|
+
const handleFocus = () => {
|
|
170
|
+
if (inputRef.current) {
|
|
171
|
+
inputRef.current.focus();
|
|
172
|
+
setRefStatus('✅ Ref works! Input focused programmatically');
|
|
173
|
+
} else {
|
|
174
|
+
setRefStatus('❌ Ref is null');
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const handleBlur = () => {
|
|
179
|
+
if (inputRef.current) {
|
|
180
|
+
inputRef.current.blur();
|
|
181
|
+
setRefStatus('✅ Ref works! Input blurred programmatically');
|
|
182
|
+
} else {
|
|
183
|
+
setRefStatus('❌ Ref is null');
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const handleClear = () => {
|
|
188
|
+
if (inputRef.current) {
|
|
189
|
+
inputRef.current.clear();
|
|
190
|
+
setRefStatus('✅ Ref works! Input cleared programmatically');
|
|
191
|
+
} else {
|
|
192
|
+
setRefStatus('❌ Ref is null');
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<Flex direction="column" space="lg">
|
|
198
|
+
<VariantTitle title="Ref Test">
|
|
199
|
+
<Input
|
|
200
|
+
ref={inputRef}
|
|
201
|
+
placeholder="Test ref functionality"
|
|
202
|
+
defaultValue="Try the buttons below"
|
|
203
|
+
/>
|
|
204
|
+
</VariantTitle>
|
|
205
|
+
<VariantTitle title="Status">
|
|
206
|
+
<Flex direction="column" space="sm">
|
|
207
|
+
<Flex direction="row" space="sm">
|
|
208
|
+
<Button onPress={handleFocus}>Focus Input</Button>
|
|
209
|
+
<Button onPress={handleBlur}>Blur Input</Button>
|
|
210
|
+
<Button onPress={handleClear}>Clear Input</Button>
|
|
211
|
+
</Flex>
|
|
212
|
+
<View
|
|
213
|
+
style={{
|
|
214
|
+
marginTop: 8,
|
|
215
|
+
padding: 8,
|
|
216
|
+
backgroundColor: theme.color.background.secondary,
|
|
217
|
+
borderRadius: 4,
|
|
218
|
+
}}
|
|
219
|
+
>
|
|
220
|
+
<BodyText>{refStatus}</BodyText>
|
|
221
|
+
</View>
|
|
222
|
+
</Flex>
|
|
223
|
+
</VariantTitle>
|
|
224
|
+
</Flex>
|
|
225
|
+
);
|
|
226
|
+
},
|
|
227
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createInput } from '@gluestack-ui/input';
|
|
2
|
-
import { ComponentType, useState } from 'react';
|
|
2
|
+
import { ComponentType, forwardRef, useImperativeHandle, useRef, useState } from 'react';
|
|
3
|
+
import { TextInput } from 'react-native';
|
|
3
4
|
import type InputProps from './Input.props';
|
|
4
5
|
|
|
5
6
|
import {
|
|
@@ -29,108 +30,119 @@ export const InputSlot = InputComponent.Slot;
|
|
|
29
30
|
export const InputField = InputComponent.Input;
|
|
30
31
|
export const InputIcon = InputComponent.Icon;
|
|
31
32
|
|
|
32
|
-
const Input = (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
33
|
+
const Input = forwardRef<TextInput, InputProps>(
|
|
34
|
+
(
|
|
35
|
+
{
|
|
36
|
+
validationStatus = 'initial',
|
|
37
|
+
children,
|
|
38
|
+
disabled,
|
|
39
|
+
focused,
|
|
40
|
+
readonly,
|
|
41
|
+
leadingIcon,
|
|
42
|
+
trailingIcon,
|
|
43
|
+
type,
|
|
44
|
+
showPasswordToggle = true,
|
|
45
|
+
onClear,
|
|
46
|
+
format,
|
|
47
|
+
loading,
|
|
48
|
+
clearable = false,
|
|
49
|
+
required,
|
|
50
|
+
inBottomSheet = false,
|
|
51
|
+
...props
|
|
52
|
+
},
|
|
53
|
+
ref
|
|
54
|
+
) => {
|
|
55
|
+
const formFieldContext = useFormFieldContext();
|
|
56
|
+
const { disabled: formFieldDisabled } = formFieldContext;
|
|
57
|
+
const validationStatusFromContext = formFieldContext?.validationStatus ?? validationStatus;
|
|
58
|
+
const isRequired = formFieldContext?.required ?? required;
|
|
59
|
+
const [fieldType, setFieldType] = useState<'password' | 'text'>(
|
|
60
|
+
type === 'password' ? 'password' : 'text'
|
|
61
|
+
);
|
|
62
|
+
const { color } = useTheme();
|
|
63
|
+
const inputRef = useRef<TextInput>(null);
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
// Expose TextInput methods to parent components
|
|
66
|
+
useImperativeHandle(ref, () => inputRef.current as TextInput, []);
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
};
|
|
68
|
+
const shouldShowPasswordToggle = type === 'password' && showPasswordToggle;
|
|
69
|
+
const shouldShowClear = clearable && !!(props as InputWithoutChildrenProps)?.value;
|
|
65
70
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
return leadingIcon;
|
|
71
|
-
})();
|
|
71
|
+
const toggleFieldType = () => {
|
|
72
|
+
setFieldType(fieldType === 'password' ? 'text' : 'password');
|
|
73
|
+
};
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
const leadingIconComponent = ((): ComponentType | undefined => {
|
|
76
|
+
if (type === 'search') {
|
|
77
|
+
return SearchMediumIcon;
|
|
78
|
+
}
|
|
79
|
+
return leadingIcon;
|
|
80
|
+
})();
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
82
|
+
const getInputMode = (() => {
|
|
83
|
+
if (type === 'search') {
|
|
84
|
+
return 'search';
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
})();
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<InputComponent
|
|
91
|
+
{...(children ? props : {})}
|
|
92
|
+
validationStatus={validationStatusFromContext}
|
|
93
|
+
isInvalid={validationStatusFromContext === 'invalid'}
|
|
94
|
+
isReadOnly={readonly}
|
|
95
|
+
isDisabled={formFieldDisabled ?? disabled}
|
|
96
|
+
isFocused={focused}
|
|
97
|
+
type={type as undefined}
|
|
98
|
+
isRequired={isRequired}
|
|
99
|
+
>
|
|
100
|
+
{children ? (
|
|
101
|
+
<>{children}</>
|
|
102
|
+
) : (
|
|
103
|
+
<>
|
|
104
|
+
{!!leadingIconComponent && (
|
|
105
|
+
<InputSlot>
|
|
106
|
+
<InputIcon as={leadingIconComponent} />
|
|
107
|
+
</InputSlot>
|
|
108
|
+
)}
|
|
109
|
+
<InputField
|
|
110
|
+
// @ts-expect-error - ref forwarding issue
|
|
111
|
+
ref={inputRef}
|
|
112
|
+
type={fieldType}
|
|
113
|
+
inputMode={getInputMode}
|
|
114
|
+
inBottomSheet={inBottomSheet}
|
|
115
|
+
{...props}
|
|
116
|
+
/>
|
|
117
|
+
{shouldShowClear && (
|
|
118
|
+
<InputSlot>
|
|
119
|
+
<UnstyledIconButton onPress={onClear} icon={CloseSmallIcon} />
|
|
120
|
+
</InputSlot>
|
|
121
|
+
)}
|
|
122
|
+
{loading && (
|
|
123
|
+
<InputSlot>
|
|
124
|
+
<Spinner size="xs" color={color.icon.primary} />
|
|
125
|
+
</InputSlot>
|
|
126
|
+
)}
|
|
127
|
+
{shouldShowPasswordToggle && (
|
|
128
|
+
<InputSlot>
|
|
129
|
+
<UnstyledIconButton
|
|
130
|
+
onPress={toggleFieldType}
|
|
131
|
+
icon={fieldType === 'password' ? EyeSmallIcon : EyeOffSmallIcon}
|
|
132
|
+
/>
|
|
133
|
+
</InputSlot>
|
|
134
|
+
)}
|
|
135
|
+
{!!trailingIcon && (
|
|
136
|
+
<InputSlot>
|
|
137
|
+
<InputIcon as={trailingIcon} />
|
|
138
|
+
</InputSlot>
|
|
139
|
+
)}
|
|
140
|
+
</>
|
|
141
|
+
)}
|
|
142
|
+
</InputComponent>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
);
|
|
134
146
|
|
|
135
147
|
Input.displayName = 'Input';
|
|
136
148
|
|