@utilitywarehouse/hearth-react-native 0.15.3 → 0.16.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 (83) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +1 -3
  3. package/CHANGELOG.md +67 -6
  4. package/build/components/Checkbox/CheckboxGroup.d.ts +1 -1
  5. package/build/components/Checkbox/CheckboxGroup.js +2 -2
  6. package/build/components/Checkbox/CheckboxGroup.props.d.ts +2 -1
  7. package/build/components/CurrencyInput/CurrencyInput.d.ts +1 -1
  8. package/build/components/CurrencyInput/CurrencyInput.js +2 -6
  9. package/build/components/CurrencyInput/CurrencyInput.props.d.ts +6 -0
  10. package/build/components/DateInput/DateInputSegment.js +0 -1
  11. package/build/components/DatePickerInput/DatePickerInput.d.ts +1 -1
  12. package/build/components/DatePickerInput/DatePickerInput.js +2 -2
  13. package/build/components/DatePickerInput/DatePickerInput.props.d.ts +6 -0
  14. package/build/components/FormField/FormField.context.d.ts +8 -2
  15. package/build/components/FormField/FormField.d.ts +1 -1
  16. package/build/components/FormField/FormField.js +24 -4
  17. package/build/components/FormField/FormField.props.d.ts +2 -0
  18. package/build/components/FormField/FormFieldLabel.d.ts +1 -1
  19. package/build/components/FormField/FormFieldLabel.js +3 -3
  20. package/build/components/FormField/FormFieldValid.js +2 -2
  21. package/build/components/Input/Input.js +48 -10
  22. package/build/components/Input/Input.props.d.ts +7 -1
  23. package/build/components/Label/Label.d.ts +1 -1
  24. package/build/components/Label/Label.js +5 -1
  25. package/build/components/Label/Label.props.d.ts +3 -2
  26. package/build/components/Radio/RadioGroup.d.ts +1 -1
  27. package/build/components/Radio/RadioGroup.js +2 -2
  28. package/build/components/Radio/RadioGroup.props.d.ts +1 -0
  29. package/build/components/RadioCard/RadioCard.d.ts +1 -1
  30. package/build/components/RadioCard/RadioCard.js +2 -2
  31. package/build/components/RadioCard/RadioCard.props.d.ts +1 -0
  32. package/build/components/Select/Select.d.ts +1 -1
  33. package/build/components/Select/Select.js +2 -2
  34. package/build/components/Select/Select.props.d.ts +10 -0
  35. package/build/components/Textarea/Textarea.d.ts +1 -1
  36. package/build/components/Textarea/Textarea.js +43 -6
  37. package/build/components/Textarea/Textarea.props.d.ts +8 -0
  38. package/build/components/VerificationInput/VerificationInput.d.ts +1 -1
  39. package/build/components/VerificationInput/VerificationInput.js +2 -2
  40. package/build/components/VerificationInput/VerificationInput.props.d.ts +4 -0
  41. package/docs/components/AllComponents.web.tsx +3 -2
  42. package/docs/theme-tokens.mdx +390 -2
  43. package/package.json +3 -3
  44. package/src/components/Checkbox/Checkbox.docs.mdx +32 -31
  45. package/src/components/Checkbox/CheckboxGroup.props.ts +2 -1
  46. package/src/components/Checkbox/CheckboxGroup.tsx +6 -1
  47. package/src/components/CurrencyInput/CurrencyInput.docs.mdx +52 -9
  48. package/src/components/CurrencyInput/CurrencyInput.props.ts +6 -0
  49. package/src/components/CurrencyInput/CurrencyInput.stories.tsx +30 -1
  50. package/src/components/CurrencyInput/CurrencyInput.tsx +16 -8
  51. package/src/components/DateInput/DateInputSegment.tsx +0 -1
  52. package/src/components/DatePickerInput/DatePickerInput.docs.mdx +22 -0
  53. package/src/components/DatePickerInput/DatePickerInput.props.ts +6 -0
  54. package/src/components/DatePickerInput/DatePickerInput.tsx +17 -3
  55. package/src/components/FormField/FormField.context.ts +6 -1
  56. package/src/components/FormField/FormField.docs.mdx +30 -30
  57. package/src/components/FormField/FormField.props.ts +2 -0
  58. package/src/components/FormField/FormField.stories.tsx +8 -2
  59. package/src/components/FormField/FormField.tsx +38 -4
  60. package/src/components/FormField/FormFieldLabel.tsx +7 -3
  61. package/src/components/FormField/FormFieldValid.tsx +2 -2
  62. package/src/components/Input/Input.docs.mdx +67 -22
  63. package/src/components/Input/Input.props.ts +7 -1
  64. package/src/components/Input/Input.stories.tsx +9 -1
  65. package/src/components/Input/Input.tsx +124 -59
  66. package/src/components/Label/Label.props.ts +3 -2
  67. package/src/components/Label/Label.tsx +11 -1
  68. package/src/components/Radio/Radio.docs.mdx +31 -30
  69. package/src/components/Radio/RadioGroup.props.ts +1 -0
  70. package/src/components/Radio/RadioGroup.stories.tsx +6 -0
  71. package/src/components/Radio/RadioGroup.tsx +6 -1
  72. package/src/components/RadioCard/RadioCard.docs.mdx +31 -30
  73. package/src/components/RadioCard/RadioCard.props.ts +1 -0
  74. package/src/components/RadioCard/RadioCard.tsx +8 -2
  75. package/src/components/Select/Select.props.ts +10 -0
  76. package/src/components/Select/Select.tsx +3 -2
  77. package/src/components/Textarea/Textarea.docs.mdx +65 -17
  78. package/src/components/Textarea/Textarea.props.ts +8 -0
  79. package/src/components/Textarea/Textarea.stories.tsx +23 -2
  80. package/src/components/Textarea/Textarea.tsx +84 -19
  81. package/src/components/VerificationInput/VerificationInput.docs.mdx +1 -0
  82. package/src/components/VerificationInput/VerificationInput.props.ts +4 -1
  83. package/src/components/VerificationInput/VerificationInput.tsx +2 -0
@@ -14,6 +14,7 @@ const RadioGroup = ({
14
14
  readonly,
15
15
  validationStatus,
16
16
  label,
17
+ labelVariant = 'body',
17
18
  helperText,
18
19
  invalidText,
19
20
  validText,
@@ -49,7 +50,11 @@ const RadioGroup = ({
49
50
  >
50
51
  {showHeader && (
51
52
  <RadioGroupTextContent>
52
- {!!label && <Label disabled={disabled}>{label}</Label>}
53
+ {!!label && (
54
+ <Label disabled={disabled} variant={labelVariant}>
55
+ {label}
56
+ </Label>
57
+ )}
53
58
  {!!helperText && <Helper disabled={disabled} icon={helperIcon} text={helperText} />}
54
59
  {validationStatus === 'invalid' && !!invalidText && (
55
60
  <Helper
@@ -1,18 +1,18 @@
1
- import { Meta, Canvas, Story, Controls } from '@storybook/addon-docs/blocks';
2
- import * as Stories from './RadioCardGroup.stories';
1
+ import { Canvas, Controls, Meta, Story } from '@storybook/addon-docs/blocks';
2
+ import { TickSmallIcon } from '@utilitywarehouse/hearth-react-native-icons';
3
3
  import {
4
- RadioCard,
5
- RadioCardGroup,
6
- Center,
7
- Box,
8
- Heading,
9
4
  BodyText,
5
+ Box,
6
+ Center,
10
7
  DetailText,
11
- UL,
8
+ Heading,
12
9
  LI,
10
+ RadioCard,
11
+ RadioCardGroup,
12
+ UL,
13
13
  } from '../..';
14
- import { TickSmallIcon } from '@utilitywarehouse/hearth-react-native-icons';
15
- import { ViewFigmaButton, BackToTopButton, UsageWrap } from '../../../docs/components';
14
+ import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
15
+ import * as Stories from './RadioCardGroup.stories';
16
16
 
17
17
  <Meta title="Components / Radio Card" />
18
18
 
@@ -92,16 +92,17 @@ const MyComponent = () => {
92
92
 
93
93
  The `RadioCard` component accepts the following props:
94
94
 
95
- | Property | Type | Default | Description |
96
- | ---------------- | ------------------------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------- |
97
- | `value` | string | - | The value to be used in the radio card input. This is the value that will be returned on form submission. |
98
- | `onChange` | `(isSelected: boolean) => void` | - | Function called when the state of the radio card changes. |
99
- | `children` | `React.ReactNode` | - | The content to be displayed inside the radio card. |
100
- | `label` | `string` | - | The label to be displayed next to the radio card. |
101
- | `flexDirection` | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | - | Sets the direction of the flex items. |
102
- | `flexWrap` | `'wrap' \| 'nowrap' \| 'wrap-reverse'` | - | Sets whether flex items are forced onto one line or can wrap. |
103
- | `alignItems` | `'flex-start' \| 'flex-end' \| 'center' \|`<br />` 'stretch' \| 'baseline'` | - | Sets the alignment of flex items on the cross axis. |
104
- | `justifyContent` | `'flex-start' \| 'flex-end' \| 'center' \|`<br />` 'space-between' \| 'space-around' \| 'space-evenly'` | - | Sets the alignment of flex items on the main axis. |
95
+ | Property | Type | Default | Description |
96
+ | ---------------- | ------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------- |
97
+ | `value` | string | - | The value to be used in the radio card input. This is the value that will be returned on form submission. |
98
+ | `onChange` | `(isSelected: boolean) => void` | - | Function called when the state of the radio card changes. |
99
+ | `children` | `React.ReactNode` | - | The content to be displayed inside the radio card. |
100
+ | `label` | `string` | - | The label to be displayed next to the radio card. |
101
+ | `labelVariant` | `'heading' \| 'body'` | `'body'` | The variant of the label text. |
102
+ | `flexDirection` | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | - | Sets the direction of the flex items. |
103
+ | `flexWrap` | `'wrap' \| 'nowrap' \| 'wrap-reverse'` | - | Sets whether flex items are forced onto one line or can wrap. |
104
+ | `alignItems` | `'flex-start' \| 'flex-end' \| 'center' \|`<br />` 'stretch' \| 'baseline'` | - | Sets the alignment of flex items on the cross axis. |
105
+ | `justifyContent` | `'flex-start' \| 'flex-end' \| 'center' \|`<br />` 'space-between' \| 'space-around' \| 'space-evenly'` | - | Sets the alignment of flex items on the main axis. |
105
106
 
106
107
  ## Components
107
108
 
@@ -113,13 +114,13 @@ Contains all RadioCard related layout style props and actions. It inherits all t
113
114
 
114
115
  Contains all Group related layout style props and actions. It inherits all the properties of React Native's [View component](https://reactnative.dev/docs/view).
115
116
 
116
- | Property | Type | Default | Description |
117
- | ---------------- | -------------------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------- |
118
- | `value` | `string` | - | The value of the currently selected `RadioCard`. |
119
- | `onChange` | `(value: string) => void` | - | Callback fired when the selected `RadioCard` changes. |
120
- | `gap` | `keyof typeof space` | - | The gap between the `RadioCard` items. |
121
- | `columns` | `GridProps['columns']` | - | If set, the group will use a grid layout with the specified number of columns. Otherwise, it uses flexbox. |
122
- | `flexDirection` | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | `row` | (Flexbox only) Sets the direction of the flex items. |
123
- | `flexWrap` | `'wrap' \| 'nowrap' \| 'wrap-reverse'` | `wrap` | (Flexbox only) Sets whether flex items are forced onto one line or can wrap. |
124
- | `alignItems` | `'flex-start' \| 'flex-end' \| 'center' \| `<br />`'stretch' \| 'baseline'` | - | (Flexbox only) Sets the alignment of flex items on the cross axis. |
125
- | `justifyContent` | `'flex-start' \| 'flex-end' \| 'center' \| `<br /> `'space-between' \| 'space-around' \| 'space-evenly'` | - | (Flexbox only) Sets the alignment of flex items on the main axis. |
117
+ | Property | Type | Default | Description |
118
+ | ---------------- | -------------------------------------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------- |
119
+ | `value` | `string` | - | The value of the currently selected `RadioCard`. |
120
+ | `onChange` | `(value: string) => void` | - | Callback fired when the selected `RadioCard` changes. |
121
+ | `gap` | `keyof typeof space` | - | The gap between the `RadioCard` items. |
122
+ | `columns` | `GridProps['columns']` | - | If set, the group will use a grid layout with the specified number of columns. Otherwise, it uses flexbox. |
123
+ | `flexDirection` | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | `'row'` | (Flexbox only) Sets the direction of the flex items. |
124
+ | `flexWrap` | `'wrap' \| 'nowrap' \| 'wrap-reverse'` | `'wrap'` | (Flexbox only) Sets whether flex items are forced onto one line or can wrap. |
125
+ | `alignItems` | `'flex-start' \| 'flex-end' \| 'center' \| `<br />`'stretch' \| 'baseline'` | - | (Flexbox only) Sets the alignment of flex items on the cross axis. |
126
+ | `justifyContent` | `'flex-start' \| 'flex-end' \| 'center' \| `<br /> `'space-between' \| 'space-around' \| 'space-evenly'` | - | (Flexbox only) Sets the alignment of flex items on the main axis. |
@@ -7,6 +7,7 @@ interface RadioCardProps extends Omit<PressableProps, 'children'> {
7
7
  onChange?: (isSelected: boolean) => void;
8
8
  children?: ViewProps['children'];
9
9
  label?: string;
10
+ labelVariant?: 'heading' | 'body';
10
11
  flexDirection?: ViewStyle['flexDirection'];
11
12
  flexWrap?: ViewStyle['flexWrap'];
12
13
  alignItems?: ViewStyle['alignItems'];
@@ -27,7 +27,13 @@ RadioCardIndicator.displayName = 'RadioCardIndicator';
27
27
  RadioCardIcon.displayName = 'RadioCardIcon';
28
28
  RadioCardLabel.displayName = 'RadioCardLabel';
29
29
 
30
- const RadioCard = ({ children, label, contentStyle, ...props }: RadioCardProps) => {
30
+ const RadioCard = ({
31
+ children,
32
+ label,
33
+ labelVariant = 'body',
34
+ contentStyle,
35
+ ...props
36
+ }: RadioCardProps) => {
31
37
  const { computedStyles } = useStyleProps(props);
32
38
  return (
33
39
  <RadioCardComponent {...props}>
@@ -35,7 +41,7 @@ const RadioCard = ({ children, label, contentStyle, ...props }: RadioCardProps)
35
41
  <RadioCardIndicator>
36
42
  <RadioCardIcon />
37
43
  </RadioCardIndicator>
38
- {!!label && <RadioCardLabel>{label}</RadioCardLabel>}
44
+ {!!label && <RadioCardLabel variant={labelVariant}>{label}</RadioCardLabel>}
39
45
  </View>
40
46
  {!!children && <View style={[computedStyles, contentStyle]}>{children}</View>}
41
47
  </RadioCardComponent>
@@ -43,6 +43,16 @@ interface SelectProps extends ViewProps {
43
43
  * Label for the select
44
44
  */
45
45
  label?: string;
46
+ /**
47
+ * The variant of the label text.
48
+ *
49
+ * Supported values are:
50
+ * - `'heading'` – use heading text styling for the label.
51
+ * - `'body'` – use body text styling for the label.
52
+ *
53
+ * @default 'body'.
54
+ */
55
+ labelVariant?: 'heading' | 'body';
46
56
  /**
47
57
  * Placeholder text to show when no value is selected
48
58
  */
@@ -23,6 +23,7 @@ const Select = ({
23
23
  value,
24
24
  onValueChange,
25
25
  label,
26
+ labelVariant = 'body',
26
27
  placeholder = 'Select an option',
27
28
  disabled = false,
28
29
  leadingIcon: LeadingIcon,
@@ -123,9 +124,9 @@ const Select = ({
123
124
  <View {...rest} style={[styles.container, rest.style]}>
124
125
  {!!label && (
125
126
  <View>
126
- <Label>
127
+ <Label variant={labelVariant}>
127
128
  {label}
128
- {!isRequired && <Label> (Optional)</Label>}
129
+ {!isRequired && <Label variant={labelVariant}> (Optional)</Label>}
129
130
  </Label>
130
131
  </View>
131
132
  )}
@@ -1,8 +1,8 @@
1
- import { Meta, Controls, Story, Canvas } from '@storybook/addon-docs/blocks';
2
- import * as Stories from './Textarea.stories';
3
- import { Textarea, TextareaField, Center, Pressable } from '../..';
1
+ import { Canvas, Controls, Meta, Story } from '@storybook/addon-docs/blocks';
4
2
  import { EmailMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
5
- import { ViewFigmaButton, BackToTopButton, UsageWrap } from '../../../docs/components';
3
+ import { Center, Pressable, Textarea, TextareaField } from '../..';
4
+ import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
5
+ import * as Stories from './Textarea.stories';
6
6
 
7
7
  <Meta title="Forms / Textarea" />
8
8
 
@@ -19,6 +19,7 @@ The input component is a text field that allows users to enter text, numbers, or
19
19
  - [Props](#props)
20
20
  - [`Textarea`](#input)
21
21
  - [`TextareaField`](#inputfield)
22
+ - [Examples](#examples)
22
23
  - [Accessibility](#accessibility)
23
24
 
24
25
  ## Playground
@@ -61,14 +62,21 @@ all of the React Native [`View` props](https://reactnative.dev/docs/view).
61
62
  | ---------------- | ---------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
62
63
  | type | `'text' \| 'password'` | `'text'` | The type of the input. |
63
64
  | validationStatus | `'initial' \| 'valid' \| 'invalid` | `'initial'` | The validation status of the input. |
64
- | disabled | boolean | `false` | Disables the input. |
65
- | readonly | boolean | `false` | Makes the input read-only. |
66
- | focused | boolean | `false` | Sets focus on the input. |
67
- | value | string | `-` | The value of the input. **(Only to be used if the input has no children)** |
68
- | onChange | function | `-` | Callback function that is triggered when the input value changes. **(Only to be used if the input has no children)** **(Only to be used if the input has no children)** |
69
- | onBlur | function | `-` | Callback function that is triggered when the input loses focus. **(Only to be used if the input has no children)** |
70
- | onFocus | function | `-` | Callback function that is triggered when the input gains focus. **(Only to be used if the input has no children)** |
71
- | placeholder | string | `-` | The placeholder text for the input. **(Only to be used if the input has no children)** |
65
+ | disabled | `boolean` | `false` | Disables the input. |
66
+ | readonly | `boolean` | `false` | Makes the input read-only. |
67
+ | focused | `boolean` | `false` | Sets focus on the input. |
68
+ | label | `string` | `-` | The label for the input. **(Only to be used if the input has no children)** |
69
+ | labelVariant | `'heading' \| 'body'` | `'body'` | The variant of the label text. **(Only to be used if the input has no children)** |
70
+ | helperText | `string` | `-` | Helper text to display below the input. **(Only to be used if the input has no children)** |
71
+ | helperIcon | `ComponentType` | `-` | Icon to display alongside the helper text. **(Only to be used if the input has no children)** |
72
+ | validText | `string` | `-` | Text to display when validation status is 'valid'. **(Only to be used if the input has no children)** |
73
+ | invalidText | `string` | `-` | Text to display when validation status is 'invalid'. |
74
+ | required | `boolean` | `false` | Whether the input is required. **(Only to be used if the input has no children)** |
75
+ | value | `string` | `-` | The value of the input. **(Only to be used if the input has no children)** |
76
+ | onChange | `function` | `-` | Callback function that is triggered when the input value changes. **(Only to be used if the input has no children)** **(Only to be used if the input has no children)** |
77
+ | onBlur | `function` | `-` | Callback function that is triggered when the input loses focus. **(Only to be used if the input has no children)** |
78
+ | onFocus | `function` | `-` | Callback function that is triggered when the input gains focus. **(Only to be used if the input has no children)** |
79
+ | placeholder | `string` | `-` | The placeholder text for the input. **(Only to be used if the input has no children)** |
72
80
 
73
81
  If the `leadingIcon` or `trailingIcon` props are used, the `Textarea` component should not have any children.
74
82
 
@@ -79,11 +87,48 @@ The `TextareaField` inherits all of the React Native [`TextTextarea` props](http
79
87
  | Prop | Type | Default | Description |
80
88
  | ----------- | ---------------------- | -------- | ----------------------------------------------------------------- |
81
89
  | type | `'text' \| 'password'` | `'text'` | The type of the input. |
82
- | value | string | `-` | The value of the input. |
83
- | onChange | function | `-` | Callback function that is triggered when the input value changes. |
84
- | onBlur | function | `-` | Callback function that is triggered when the input loses focus. |
85
- | onFocus | function | `-` | Callback function that is triggered when the input gains focus. |
86
- | placeholder | string | `-` | The placeholder text for the input. |
90
+ | value | `string` | `-` | The value of the input. |
91
+ | onChange | `function` | `-` | Callback function that is triggered when the input value changes. |
92
+ | onBlur | `function` | `-` | Callback function that is triggered when the input loses focus. |
93
+ | onFocus | `function` | `-` | Callback function that is triggered when the input gains focus. |
94
+ | placeholder | `string` | `-` | The placeholder text for the input. |
95
+
96
+ ## Examples
97
+
98
+ ### With Label and Helper Text
99
+
100
+ The `Textarea` component can display a label and helper text by passing the appropriate props.
101
+
102
+ <UsageWrap>
103
+ <Center>
104
+ <Textarea
105
+ label="Description"
106
+ helperText="Provide a detailed description"
107
+ placeholder="Enter your text here..."
108
+ onChange={() => console.log('###')}
109
+ />
110
+ </Center>
111
+ </UsageWrap>
112
+
113
+ ```tsx
114
+ import { Textarea } from '@utilitywarehouse/hearth-react-native';
115
+
116
+ const MyComponent = () => {
117
+ const [value, setValue] = useState('');
118
+ const handleChange = e => {
119
+ setValue(e.target.value);
120
+ };
121
+ return (
122
+ <Textarea
123
+ label="Description"
124
+ helperText="Provide a detailed description"
125
+ placeholder="Enter your text here..."
126
+ value={value}
127
+ onTextChange={handleChange}
128
+ />
129
+ );
130
+ };
131
+ ```
87
132
 
88
133
  ## Accessibility
89
134
 
@@ -95,6 +140,9 @@ We have outlined the various features that ensure the Textarea component is acce
95
140
 
96
141
  ### Screen Reader
97
142
 
143
+ - When setting the label prop, it is associated with the Textarea using aria-label.
144
+ - When setting the helperText prop, it is associated with the Textarea using aria-describedby.
145
+ - The required prop to indicate if the Textarea is required or optional and is read out by screen readers.
98
146
  - Compatible with screen readers such as VoiceOver and Talk-back.
99
147
  - The accessible and aria-label props to provide descriptive information about the Textarea
100
148
  - Setting aria-traits and aria-hint to provide contextual information about the various states of the Textarea, such as "double tap to edit".
@@ -24,6 +24,14 @@ export interface TextareaBaseProps {
24
24
  readonly?: boolean;
25
25
  focused?: boolean;
26
26
  placeholder?: string;
27
+ label?: string;
28
+ labelVariant?: 'heading' | 'body';
29
+ helperText?: string;
30
+ helperIcon?: React.ComponentType;
31
+ validText?: string;
32
+ invalidText?: string;
33
+ required?: boolean;
34
+ isInBottomSheet?: boolean;
27
35
  }
28
36
 
29
37
  export interface TextareaWithChildrenProps extends TextareaBaseProps, ViewProps {}
@@ -1,5 +1,5 @@
1
- import { Textarea } from '.';
2
1
  import { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Textarea } from '.';
3
3
 
4
4
  const meta = {
5
5
  title: 'Stories / Textarea',
@@ -13,13 +13,34 @@ const meta = {
13
13
  description: 'The Textarea field placeholder',
14
14
  defaultValue: '',
15
15
  },
16
-
16
+ label: {
17
+ control: 'text',
18
+ description: 'The label for the Textarea component',
19
+ defaultValue: 'Textarea label',
20
+ },
21
+ labelVariant: {
22
+ control: 'radio',
23
+ options: ['heading', 'body'],
24
+ description: 'The label variant for the Textarea component',
25
+ },
26
+ helperText: {
27
+ control: 'text',
28
+ description: 'The helper text for the Textarea component',
29
+ },
17
30
  validationStatus: {
18
31
  control: 'select',
19
32
  options: ['initial', 'valid', 'invalid'],
20
33
  description: 'The validation status of the Textarea component',
21
34
  defaultValue: 'initial',
22
35
  },
36
+ invalidText: {
37
+ control: 'text',
38
+ description: 'The invalid text for the Textarea component',
39
+ },
40
+ validText: {
41
+ control: 'text',
42
+ description: 'The valid text for the Textarea component',
43
+ },
23
44
  disabled: {
24
45
  control: 'boolean',
25
46
  description: 'Disable the Textarea component',
@@ -1,9 +1,10 @@
1
1
  import { createTextarea } from '@gluestack-ui/textarea';
2
2
  import type TextareaProps from './Textarea.props';
3
3
 
4
- import TextareaRoot from './TextareaRoot';
4
+ import { useEffect } from 'react';
5
+ import { FormField, useFormFieldContext } from '../FormField';
5
6
  import TextareaFieldComponent from './TextareaField';
6
- import { useFormFieldContext } from '../FormField';
7
+ import TextareaRoot from './TextareaRoot';
7
8
 
8
9
  export const TextareaComponent = createTextarea({
9
10
  Root: TextareaRoot,
@@ -18,29 +19,93 @@ const Textarea = ({
18
19
  disabled,
19
20
  focused,
20
21
  readonly,
22
+ label,
23
+ labelVariant,
24
+ helperText,
25
+ validText,
26
+ invalidText,
27
+ required,
28
+ helperIcon,
21
29
  ...props
22
30
  }: TextareaProps) => {
23
31
  const formFieldContext = useFormFieldContext();
24
- const { disabled: formFieldDisabled } = formFieldContext;
25
- const validationStatusFromContext = formFieldContext?.validationStatus ?? validationStatus;
32
+ const textareaLabel = label ?? formFieldContext?.label;
33
+ const textareaHelperText = helperText ?? formFieldContext?.helperText;
34
+ const textareaValidText = validText ?? formFieldContext?.validText;
35
+ const textareaInvalidText = invalidText ?? formFieldContext?.invalidText;
36
+ const textareaRequired = required ?? formFieldContext?.required;
37
+ const textareaDisabled = disabled ?? formFieldContext?.disabled;
38
+ const textareaReadonly = readonly ?? formFieldContext?.readonly;
39
+ const textareaValidationStatus = formFieldContext?.validationStatus ?? validationStatus;
40
+
41
+ useEffect(() => {
42
+ if (formFieldContext?.setShouldHandleAccessibility) {
43
+ formFieldContext.setShouldHandleAccessibility(true);
44
+ }
45
+ }, []);
46
+
47
+ const getAccessibilityLabel = () => {
48
+ let accessibilityLabel = '';
49
+ if (textareaLabel) {
50
+ accessibilityLabel = accessibilityLabel + textareaLabel;
51
+ }
52
+ if (textareaRequired) {
53
+ accessibilityLabel = accessibilityLabel + ', required';
54
+ }
55
+
56
+ return accessibilityLabel || props.accessibilityLabel;
57
+ };
58
+
59
+ const getAccessibilityHint = () => {
60
+ let accessibilityHint = '';
61
+ if (textareaValidationStatus !== 'initial') {
62
+ if (accessibilityHint.length > 0) {
63
+ accessibilityHint = accessibilityHint + ', ';
64
+ }
65
+ if (textareaValidationStatus === 'invalid' && textareaInvalidText) {
66
+ accessibilityHint = accessibilityHint + textareaInvalidText;
67
+ }
68
+ if (textareaValidationStatus === 'valid' && textareaValidText) {
69
+ accessibilityHint = accessibilityHint + textareaValidText;
70
+ }
71
+ }
72
+ return accessibilityHint || props.accessibilityHint;
73
+ };
26
74
 
27
75
  return (
28
- <TextareaComponent
29
- {...(children ? props : {})}
30
- validationStatus={validationStatusFromContext}
31
- isInvalid={validationStatusFromContext === 'invalid'}
32
- isReadOnly={readonly}
33
- isDisabled={formFieldDisabled ?? disabled}
34
- isFocused={focused}
76
+ <FormField
77
+ label={label}
78
+ labelVariant={labelVariant}
79
+ helperText={helperText}
80
+ helperIcon={helperIcon}
81
+ validText={validText}
82
+ invalidText={invalidText}
83
+ required={required}
84
+ validationStatus={validationStatus}
85
+ disabled={disabled}
86
+ readonly={readonly}
87
+ accessibilityHandledByChildren
35
88
  >
36
- {children ? (
37
- <>{children}</>
38
- ) : (
39
- <>
40
- <TextareaField {...props} />
41
- </>
42
- )}
43
- </TextareaComponent>
89
+ <TextareaComponent
90
+ {...(children ? props : {})}
91
+ validationStatus={textareaValidationStatus}
92
+ isInvalid={textareaValidationStatus === 'invalid'}
93
+ isReadOnly={textareaReadonly}
94
+ isDisabled={textareaDisabled}
95
+ isFocused={focused}
96
+ required={textareaRequired}
97
+ aria-label={getAccessibilityLabel()}
98
+ accessibilityHint={getAccessibilityHint()}
99
+ >
100
+ {children ? (
101
+ <>{children}</>
102
+ ) : (
103
+ <>
104
+ <TextareaField {...props} />
105
+ </>
106
+ )}
107
+ </TextareaComponent>
108
+ </FormField>
44
109
  );
45
110
  };
46
111
 
@@ -54,6 +54,7 @@ The component accepts the following props:
54
54
  | `value` | `string` | - | The value of the input. |
55
55
  | `onChangeText` | `(text: string) => void` | - | Callback when the value changes. |
56
56
  | `label` | `string` | - | The label for the input. |
57
+ | `labelVariant` | `'heading' \| 'body'` | `'body'` | The variant of the label text. |
57
58
  | `helperText` | `string` | - | Helper text to display below the input. |
58
59
  | `helperIcon` | `ComponentType` | - | Icon to display alongside the helper text. |
59
60
  | `validationStatus` | `'initial' \| 'valid' \| 'invalid'` | `'initial'` | The validation status of the input. |
@@ -14,6 +14,10 @@ export interface VerificationInputProps extends ViewProps {
14
14
  * The label for the input.
15
15
  */
16
16
  label?: string;
17
+ /**
18
+ * The label variant for the input.
19
+ */
20
+ labelVariant?: 'heading' | 'body';
17
21
  /**
18
22
  * Helper text to display below the input.
19
23
  */
@@ -49,4 +53,3 @@ export interface VerificationInputProps extends ViewProps {
49
53
  }
50
54
 
51
55
  export default VerificationInputProps;
52
-
@@ -9,6 +9,7 @@ const VerificationInput = ({
9
9
  value = '',
10
10
  onChangeText,
11
11
  label,
12
+ labelVariant = 'body',
12
13
  helperText,
13
14
  helperIcon,
14
15
  validationStatus = 'initial',
@@ -32,6 +33,7 @@ const VerificationInput = ({
32
33
  return (
33
34
  <FormField
34
35
  label={label}
36
+ labelVariant={labelVariant}
35
37
  helperText={helperText}
36
38
  helperIcon={helperIcon}
37
39
  validationStatus={validationStatus}