@hero-design/rn 8.2.2 → 8.2.3
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 +9 -9
- package/es/index.js +96 -29
- package/lib/index.js +93 -26
- package/package.json +5 -5
- package/src/components/Box/StyledBox.tsx +8 -6
- package/src/components/Card/StyledCard.tsx +1 -1
- package/src/components/Card/__tests__/__snapshots__/index.spec.tsx.snap +74 -0
- package/src/components/Card/__tests__/index.spec.tsx +2 -0
- package/src/components/Card/index.tsx +1 -1
- package/src/components/Icon/index.tsx +28 -2
- package/src/components/TextInput/__tests__/__snapshots__/index.spec.tsx.snap +160 -0
- package/src/components/TextInput/__tests__/index.spec.tsx +50 -3
- package/src/components/TextInput/index.tsx +65 -30
- package/src/components/Toolbar/ToolbarGroup.tsx +20 -14
- package/src/components/Toolbar/ToolbarItem.tsx +9 -1
- package/src/components/Toolbar/__tests__/__snapshots__/ToolbarGroup.spec.tsx.snap +12 -0
- package/src/components/Toolbar/__tests__/__snapshots__/ToolbarItem.spec.tsx.snap +6 -0
- package/src/types.ts +4 -1
- package/src/utils/__tests__/helpers.spec.ts +22 -4
- package/src/utils/helpers.ts +10 -9
- package/types/components/BottomNavigation/StyledBottomNavigation.d.ts +1 -1
- package/types/components/Box/StyledBox.d.ts +2 -2
- package/types/components/Button/StyledButton.d.ts +1 -1
- package/types/components/Button/UtilityButton/StyledUtilityButton.d.ts +1 -1
- package/types/components/Card/StyledCard.d.ts +1 -1
- package/types/components/Card/index.d.ts +1 -1
- package/types/components/Checkbox/StyledCheckbox.d.ts +1 -1
- package/types/components/ContentNavigator/StyledContentNavigator.d.ts +1 -1
- package/types/components/FAB/ActionGroup/StyledActionItem.d.ts +1 -1
- package/types/components/Icon/index.d.ts +3 -3
- package/types/components/TextInput/StyledTextInput.d.ts +7 -7
- package/types/components/TextInput/index.d.ts +25 -3
- package/types/components/Toolbar/ToolbarItem.d.ts +6 -1
- package/types/types.d.ts +3 -2
- package/types/utils/helpers.d.ts +2 -2
|
@@ -1,5 +1,79 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
+
exports[`Card renders correctly when intent is archived 1`] = `
|
|
4
|
+
<View
|
|
5
|
+
style={
|
|
6
|
+
Array [
|
|
7
|
+
Object {
|
|
8
|
+
"backgroundColor": "#abacaf",
|
|
9
|
+
"borderRadius": 12,
|
|
10
|
+
"overflow": "hidden",
|
|
11
|
+
},
|
|
12
|
+
undefined,
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
themeIntent="archived"
|
|
16
|
+
>
|
|
17
|
+
<Text
|
|
18
|
+
style={
|
|
19
|
+
Array [
|
|
20
|
+
Object {
|
|
21
|
+
"color": "#001f23",
|
|
22
|
+
"fontFamily": "BeVietnamPro-Regular",
|
|
23
|
+
"fontSize": 14,
|
|
24
|
+
"letterSpacing": 0.42,
|
|
25
|
+
"lineHeight": 22,
|
|
26
|
+
},
|
|
27
|
+
undefined,
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
themeFontSize="medium"
|
|
31
|
+
themeFontWeight="regular"
|
|
32
|
+
themeIntent="body"
|
|
33
|
+
themeTypeface="neutral"
|
|
34
|
+
>
|
|
35
|
+
Card Content
|
|
36
|
+
</Text>
|
|
37
|
+
</View>
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
exports[`Card renders correctly when intent is danger 1`] = `
|
|
41
|
+
<View
|
|
42
|
+
style={
|
|
43
|
+
Array [
|
|
44
|
+
Object {
|
|
45
|
+
"backgroundColor": "#f46363",
|
|
46
|
+
"borderRadius": 12,
|
|
47
|
+
"overflow": "hidden",
|
|
48
|
+
},
|
|
49
|
+
undefined,
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
themeIntent="danger"
|
|
53
|
+
>
|
|
54
|
+
<Text
|
|
55
|
+
style={
|
|
56
|
+
Array [
|
|
57
|
+
Object {
|
|
58
|
+
"color": "#001f23",
|
|
59
|
+
"fontFamily": "BeVietnamPro-Regular",
|
|
60
|
+
"fontSize": 14,
|
|
61
|
+
"letterSpacing": 0.42,
|
|
62
|
+
"lineHeight": 22,
|
|
63
|
+
},
|
|
64
|
+
undefined,
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
themeFontSize="medium"
|
|
68
|
+
themeFontWeight="regular"
|
|
69
|
+
themeIntent="body"
|
|
70
|
+
themeTypeface="neutral"
|
|
71
|
+
>
|
|
72
|
+
Card Content
|
|
73
|
+
</Text>
|
|
74
|
+
</View>
|
|
75
|
+
`;
|
|
76
|
+
|
|
3
77
|
exports[`Card renders correctly when intent is info 1`] = `
|
|
4
78
|
<View
|
|
5
79
|
style={
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { StyleProp, TextStyle } from 'react-native';
|
|
2
|
+
import type { AccessibilityProps, StyleProp, TextStyle } from 'react-native';
|
|
3
3
|
import IconList from './IconList';
|
|
4
4
|
import HeroIcon from './HeroIcon';
|
|
5
5
|
import AnimatedIcon from './AnimatedIcon';
|
|
@@ -7,7 +7,7 @@ import { useDeprecation } from '../../utils/hooks';
|
|
|
7
7
|
|
|
8
8
|
export type IconName = typeof IconList[number];
|
|
9
9
|
|
|
10
|
-
export interface IconProps {
|
|
10
|
+
export interface IconProps extends AccessibilityProps {
|
|
11
11
|
/**
|
|
12
12
|
* Name of the Icon.
|
|
13
13
|
*/
|
|
@@ -50,6 +50,17 @@ const Icon = ({
|
|
|
50
50
|
intent = 'text',
|
|
51
51
|
testID,
|
|
52
52
|
spin = false,
|
|
53
|
+
accessibilityLabel,
|
|
54
|
+
accessibilityHint,
|
|
55
|
+
accessibilityRole,
|
|
56
|
+
accessibilityState,
|
|
57
|
+
accessibilityValue,
|
|
58
|
+
accessibilityLiveRegion,
|
|
59
|
+
accessibilityElementsHidden,
|
|
60
|
+
accessible,
|
|
61
|
+
accessibilityIgnoresInvertColors,
|
|
62
|
+
accessibilityViewIsModal,
|
|
63
|
+
accessibilityActions,
|
|
53
64
|
}: IconProps) => {
|
|
54
65
|
useDeprecation(
|
|
55
66
|
`${icon} icon is deprecated and will be removed in the next major release, please use ${icon.replace(
|
|
@@ -58,6 +69,19 @@ const Icon = ({
|
|
|
58
69
|
)} instead.`,
|
|
59
70
|
icon.startsWith('carat')
|
|
60
71
|
);
|
|
72
|
+
const accessibilityProps = {
|
|
73
|
+
accessibilityLabel,
|
|
74
|
+
accessibilityHint,
|
|
75
|
+
accessibilityRole,
|
|
76
|
+
accessibilityState,
|
|
77
|
+
accessibilityValue,
|
|
78
|
+
accessibilityLiveRegion,
|
|
79
|
+
accessibilityElementsHidden,
|
|
80
|
+
accessible,
|
|
81
|
+
accessibilityIgnoresInvertColors,
|
|
82
|
+
accessibilityViewIsModal,
|
|
83
|
+
accessibilityActions,
|
|
84
|
+
};
|
|
61
85
|
|
|
62
86
|
return spin ? (
|
|
63
87
|
<AnimatedIcon
|
|
@@ -66,6 +90,7 @@ const Icon = ({
|
|
|
66
90
|
themeSize={size}
|
|
67
91
|
style={style}
|
|
68
92
|
testID={testID}
|
|
93
|
+
{...accessibilityProps}
|
|
69
94
|
/>
|
|
70
95
|
) : (
|
|
71
96
|
<HeroIcon
|
|
@@ -74,6 +99,7 @@ const Icon = ({
|
|
|
74
99
|
themeSize={size}
|
|
75
100
|
style={style}
|
|
76
101
|
testID={testID}
|
|
102
|
+
{...accessibilityProps}
|
|
77
103
|
/>
|
|
78
104
|
);
|
|
79
105
|
};
|
|
@@ -2708,6 +2708,166 @@ exports[`TextInput readonly renders correctly 1`] = `
|
|
|
2708
2708
|
</View>
|
|
2709
2709
|
`;
|
|
2710
2710
|
|
|
2711
|
+
exports[`TextInput ref ref methods work correctly 1`] = `
|
|
2712
|
+
<View
|
|
2713
|
+
pointerEvents="auto"
|
|
2714
|
+
style={
|
|
2715
|
+
Array [
|
|
2716
|
+
Object {
|
|
2717
|
+
"marginVertical": 8,
|
|
2718
|
+
"width": "100%",
|
|
2719
|
+
},
|
|
2720
|
+
undefined,
|
|
2721
|
+
]
|
|
2722
|
+
}
|
|
2723
|
+
>
|
|
2724
|
+
<View
|
|
2725
|
+
style={
|
|
2726
|
+
Array [
|
|
2727
|
+
Object {
|
|
2728
|
+
"alignItems": "center",
|
|
2729
|
+
"flexDirection": "row",
|
|
2730
|
+
"padding": 16,
|
|
2731
|
+
},
|
|
2732
|
+
undefined,
|
|
2733
|
+
]
|
|
2734
|
+
}
|
|
2735
|
+
>
|
|
2736
|
+
<View
|
|
2737
|
+
style={
|
|
2738
|
+
Array [
|
|
2739
|
+
Object {
|
|
2740
|
+
"borderColor": "#001f23",
|
|
2741
|
+
"borderRadius": 8,
|
|
2742
|
+
"borderWidth": 1,
|
|
2743
|
+
"bottom": 0,
|
|
2744
|
+
"left": 0,
|
|
2745
|
+
"position": "absolute",
|
|
2746
|
+
"right": 0,
|
|
2747
|
+
"top": 0,
|
|
2748
|
+
},
|
|
2749
|
+
undefined,
|
|
2750
|
+
]
|
|
2751
|
+
}
|
|
2752
|
+
themeFocused={false}
|
|
2753
|
+
themeVariant="filled"
|
|
2754
|
+
/>
|
|
2755
|
+
<View
|
|
2756
|
+
pointerEvents="none"
|
|
2757
|
+
style={
|
|
2758
|
+
Array [
|
|
2759
|
+
Object {
|
|
2760
|
+
"backgroundColor": "#ffffff",
|
|
2761
|
+
"flexDirection": "row",
|
|
2762
|
+
"left": 16,
|
|
2763
|
+
"paddingHorizontal": 4,
|
|
2764
|
+
"position": "absolute",
|
|
2765
|
+
"top": -10,
|
|
2766
|
+
"zIndex": 1,
|
|
2767
|
+
},
|
|
2768
|
+
undefined,
|
|
2769
|
+
]
|
|
2770
|
+
}
|
|
2771
|
+
>
|
|
2772
|
+
<Text
|
|
2773
|
+
style={
|
|
2774
|
+
Array [
|
|
2775
|
+
Object {
|
|
2776
|
+
"color": "#001f23",
|
|
2777
|
+
"fontFamily": "BeVietnamPro-Regular",
|
|
2778
|
+
"fontSize": 12,
|
|
2779
|
+
"letterSpacing": 0.36,
|
|
2780
|
+
"lineHeight": 20,
|
|
2781
|
+
},
|
|
2782
|
+
Array [
|
|
2783
|
+
Object {
|
|
2784
|
+
"color": "#001f23",
|
|
2785
|
+
},
|
|
2786
|
+
undefined,
|
|
2787
|
+
],
|
|
2788
|
+
]
|
|
2789
|
+
}
|
|
2790
|
+
testID="input-label"
|
|
2791
|
+
themeFontSize="small"
|
|
2792
|
+
themeFontWeight="regular"
|
|
2793
|
+
themeIntent="body"
|
|
2794
|
+
themeTypeface="neutral"
|
|
2795
|
+
themeVariant="filled"
|
|
2796
|
+
>
|
|
2797
|
+
Amount (AUD)
|
|
2798
|
+
</Text>
|
|
2799
|
+
</View>
|
|
2800
|
+
<View
|
|
2801
|
+
style={
|
|
2802
|
+
Array [
|
|
2803
|
+
Object {
|
|
2804
|
+
"alignItems": "center",
|
|
2805
|
+
"alignSelf": "stretch",
|
|
2806
|
+
"flexDirection": "row",
|
|
2807
|
+
"flexGrow": 2,
|
|
2808
|
+
"flexShrink": 1,
|
|
2809
|
+
},
|
|
2810
|
+
undefined,
|
|
2811
|
+
]
|
|
2812
|
+
}
|
|
2813
|
+
>
|
|
2814
|
+
<TextInput
|
|
2815
|
+
accessibilityState={
|
|
2816
|
+
Object {
|
|
2817
|
+
"disabled": false,
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
editable={true}
|
|
2821
|
+
onBlur={[Function]}
|
|
2822
|
+
onChangeText={[Function]}
|
|
2823
|
+
onFocus={[Function]}
|
|
2824
|
+
placeholder=" "
|
|
2825
|
+
style={
|
|
2826
|
+
Array [
|
|
2827
|
+
Object {
|
|
2828
|
+
"alignSelf": "stretch",
|
|
2829
|
+
"flexGrow": 2,
|
|
2830
|
+
"fontSize": 14,
|
|
2831
|
+
"lineHeight": 18,
|
|
2832
|
+
"marginHorizontal": 8,
|
|
2833
|
+
"paddingVertical": 0,
|
|
2834
|
+
"textAlignVertical": "center",
|
|
2835
|
+
},
|
|
2836
|
+
Object {
|
|
2837
|
+
"color": "#001f23",
|
|
2838
|
+
},
|
|
2839
|
+
]
|
|
2840
|
+
}
|
|
2841
|
+
testID="text-input"
|
|
2842
|
+
value="2000"
|
|
2843
|
+
/>
|
|
2844
|
+
</View>
|
|
2845
|
+
</View>
|
|
2846
|
+
<View
|
|
2847
|
+
style={
|
|
2848
|
+
Array [
|
|
2849
|
+
Object {
|
|
2850
|
+
"paddingLeft": 16,
|
|
2851
|
+
},
|
|
2852
|
+
undefined,
|
|
2853
|
+
]
|
|
2854
|
+
}
|
|
2855
|
+
>
|
|
2856
|
+
<View
|
|
2857
|
+
style={
|
|
2858
|
+
Array [
|
|
2859
|
+
Object {
|
|
2860
|
+
"flexDirection": "row",
|
|
2861
|
+
"justifyContent": "space-between",
|
|
2862
|
+
},
|
|
2863
|
+
undefined,
|
|
2864
|
+
]
|
|
2865
|
+
}
|
|
2866
|
+
/>
|
|
2867
|
+
</View>
|
|
2868
|
+
</View>
|
|
2869
|
+
`;
|
|
2870
|
+
|
|
2711
2871
|
exports[`TextInput required renders correctly 1`] = `
|
|
2712
2872
|
<View
|
|
2713
2873
|
pointerEvents="auto"
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { fireEvent, within } from '@testing-library/react-native';
|
|
1
|
+
import { act, fireEvent, within } from '@testing-library/react-native';
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { TextInput as RNTextInput } from 'react-native';
|
|
3
4
|
import { theme } from '../../..';
|
|
4
5
|
import renderWithTheme from '../../../testHelpers/renderWithTheme';
|
|
5
6
|
import Icon from '../../Icon';
|
|
6
|
-
import TextInput, { getVariant } from '../index';
|
|
7
|
+
import TextInput, { getVariant, TextInputHandles } from '../index';
|
|
7
8
|
|
|
8
9
|
describe('getVariant', () => {
|
|
9
10
|
it.each`
|
|
@@ -268,7 +269,10 @@ describe('TextInput', () => {
|
|
|
268
269
|
expect(queryAllByText('Amount (AUD)')).toHaveLength(1);
|
|
269
270
|
expect(queryAllByTestId('input-label')).toHaveLength(1);
|
|
270
271
|
expect(queryAllByTestId('text-input')).toHaveLength(1);
|
|
271
|
-
expect(getByTestId('disabled-text-input')).
|
|
272
|
+
expect(getByTestId('disabled-text-input')).toHaveProp(
|
|
273
|
+
'pointerEvents',
|
|
274
|
+
'none'
|
|
275
|
+
);
|
|
272
276
|
|
|
273
277
|
expect(getByTestId('text-input')).not.toHaveProp('multiline', 'true');
|
|
274
278
|
});
|
|
@@ -375,4 +379,47 @@ describe('TextInput', () => {
|
|
|
375
379
|
});
|
|
376
380
|
});
|
|
377
381
|
});
|
|
382
|
+
|
|
383
|
+
describe('ref', () => {
|
|
384
|
+
it('ref methods work correctly', () => {
|
|
385
|
+
const mockChildMethod = jest.fn();
|
|
386
|
+
jest.spyOn(React, 'useRef').mockReturnValue({
|
|
387
|
+
current: {
|
|
388
|
+
clear: mockChildMethod,
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
const ref = React.createRef<
|
|
392
|
+
TextInputHandles & {
|
|
393
|
+
getNativeTextInputRef(): RNTextInput;
|
|
394
|
+
}
|
|
395
|
+
>();
|
|
396
|
+
const wrapper = renderWithTheme(
|
|
397
|
+
<TextInput label="Amount (AUD)" value="2000" ref={ref} />
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
401
|
+
expect(wrapper.queryByDisplayValue('2000')).toBeTruthy();
|
|
402
|
+
expect(wrapper.queryByDisplayValue('1000')).toBeFalsy();
|
|
403
|
+
|
|
404
|
+
const nativeTextInputRef = ref.current!.getNativeTextInputRef();
|
|
405
|
+
const focusSpy = jest.spyOn(nativeTextInputRef, 'focus');
|
|
406
|
+
const clearSpy = jest.spyOn(nativeTextInputRef, 'clear');
|
|
407
|
+
const blurSpy = jest.spyOn(nativeTextInputRef, 'blur');
|
|
408
|
+
const setNativePropsSpy = jest.spyOn(
|
|
409
|
+
nativeTextInputRef,
|
|
410
|
+
'setNativeProps'
|
|
411
|
+
);
|
|
412
|
+
act(() => {
|
|
413
|
+
ref.current?.focus();
|
|
414
|
+
ref.current?.clear();
|
|
415
|
+
ref.current?.setNativeProps({ text: '1000' });
|
|
416
|
+
ref.current?.blur();
|
|
417
|
+
});
|
|
418
|
+
expect(focusSpy).toHaveBeenCalledTimes(1);
|
|
419
|
+
|
|
420
|
+
expect(clearSpy).toHaveBeenCalledTimes(1);
|
|
421
|
+
expect(setNativePropsSpy).toHaveBeenCalledTimes(1);
|
|
422
|
+
expect(blurSpy).toHaveBeenCalledTimes(1);
|
|
423
|
+
});
|
|
424
|
+
});
|
|
378
425
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
|
-
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { StyleSheet, TextInput as RNTextInput } from 'react-native';
|
|
3
3
|
import type {
|
|
4
4
|
TextInputProps as NativeTextInputProps,
|
|
5
5
|
StyleProp,
|
|
@@ -31,6 +31,11 @@ import type { Variant } from './StyledTextInput';
|
|
|
31
31
|
import type { IconName } from '../Icon';
|
|
32
32
|
import { omit, pick } from '../../utils/helpers';
|
|
33
33
|
|
|
34
|
+
export type TextInputHandles = Pick<
|
|
35
|
+
RNTextInput,
|
|
36
|
+
'focus' | 'clear' | 'blur' | 'isFocused' | 'setNativeProps'
|
|
37
|
+
>;
|
|
38
|
+
|
|
34
39
|
export interface TextInputProps extends NativeTextInputProps {
|
|
35
40
|
/**
|
|
36
41
|
* Field label.
|
|
@@ -66,7 +71,7 @@ export interface TextInputProps extends NativeTextInputProps {
|
|
|
66
71
|
error?: string;
|
|
67
72
|
/**
|
|
68
73
|
* Whether the input is required, if true, an asterisk will be appended to the label.
|
|
69
|
-
|
|
74
|
+
*/
|
|
70
75
|
required?: boolean;
|
|
71
76
|
/**
|
|
72
77
|
* Placeholder text to display.
|
|
@@ -76,27 +81,31 @@ export interface TextInputProps extends NativeTextInputProps {
|
|
|
76
81
|
* Whether the input is editable.
|
|
77
82
|
* */
|
|
78
83
|
editable?: boolean;
|
|
79
|
-
|
|
84
|
+
/**
|
|
80
85
|
* Whether the input is disabled.
|
|
81
86
|
*/
|
|
82
87
|
disabled?: boolean;
|
|
83
|
-
|
|
88
|
+
/**
|
|
84
89
|
* Whether the input is loading.
|
|
85
90
|
*/
|
|
86
91
|
loading?: boolean;
|
|
87
|
-
|
|
92
|
+
/**
|
|
88
93
|
* The max length of the input.
|
|
89
94
|
* If the max length is set, the input will display the current length and the max length.
|
|
90
95
|
* */
|
|
91
96
|
maxLength?: number;
|
|
92
|
-
|
|
97
|
+
/**
|
|
93
98
|
* The helper text to display.
|
|
94
99
|
*/
|
|
95
100
|
helpText?: string;
|
|
96
|
-
|
|
101
|
+
/**
|
|
97
102
|
* Customise input value renderer
|
|
98
103
|
*/
|
|
99
104
|
renderInputValue?: (inputProps: NativeTextInputProps) => React.ReactNode;
|
|
105
|
+
/**
|
|
106
|
+
* Component ref.
|
|
107
|
+
*/
|
|
108
|
+
ref?: React.Ref<TextInputHandles>;
|
|
100
109
|
}
|
|
101
110
|
|
|
102
111
|
export const getVariant = ({
|
|
@@ -132,26 +141,29 @@ export const getVariant = ({
|
|
|
132
141
|
// https://github.com/callstack/react-native-paper/pull/3331
|
|
133
142
|
const EMPTY_PLACEHOLDER_VALUE = ' ';
|
|
134
143
|
|
|
135
|
-
const TextInput = (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
144
|
+
const TextInput = (
|
|
145
|
+
{
|
|
146
|
+
label,
|
|
147
|
+
prefix,
|
|
148
|
+
suffix,
|
|
149
|
+
style,
|
|
150
|
+
textStyle,
|
|
151
|
+
testID,
|
|
152
|
+
accessibilityLabelledBy,
|
|
153
|
+
error,
|
|
154
|
+
required,
|
|
155
|
+
editable = true,
|
|
156
|
+
disabled = false,
|
|
157
|
+
loading = false,
|
|
158
|
+
maxLength,
|
|
159
|
+
helpText,
|
|
160
|
+
value,
|
|
161
|
+
defaultValue,
|
|
162
|
+
renderInputValue,
|
|
163
|
+
...nativeProps
|
|
164
|
+
}: TextInputProps,
|
|
165
|
+
ref?: React.Ref<TextInputHandles>
|
|
166
|
+
) => {
|
|
155
167
|
const displayText = (value !== undefined ? value : defaultValue) ?? '';
|
|
156
168
|
const isEmptyValue = displayText.length === 0;
|
|
157
169
|
const actualSuffix = loading ? 'loading' : suffix;
|
|
@@ -171,6 +183,24 @@ const TextInput = ({
|
|
|
171
183
|
|
|
172
184
|
const theme = useTheme();
|
|
173
185
|
|
|
186
|
+
const innerTextInput = React.useRef<RNTextInput | undefined | null>();
|
|
187
|
+
React.useImperativeHandle(
|
|
188
|
+
ref,
|
|
189
|
+
() => ({
|
|
190
|
+
// we don't expose this method, it's for testing https://medium.com/developer-rants/how-to-test-useref-without-mocking-useref-699165f4994e
|
|
191
|
+
getNativeTextInputRef: () => innerTextInput.current,
|
|
192
|
+
focus: () => {
|
|
193
|
+
innerTextInput.current?.focus();
|
|
194
|
+
},
|
|
195
|
+
clear: () => innerTextInput.current?.clear(),
|
|
196
|
+
setNativeProps: (args: NativeTextInputProps) =>
|
|
197
|
+
innerTextInput.current?.setNativeProps(args),
|
|
198
|
+
isFocused: () => innerTextInput.current?.isFocused() || false,
|
|
199
|
+
blur: () => innerTextInput.current?.blur(),
|
|
200
|
+
}),
|
|
201
|
+
[innerTextInput]
|
|
202
|
+
);
|
|
203
|
+
|
|
174
204
|
const { borderStyle, textStyleWithoutBorderStyle } = useMemo(() => {
|
|
175
205
|
if (!textStyle) {
|
|
176
206
|
return {};
|
|
@@ -179,7 +209,7 @@ const TextInput = ({
|
|
|
179
209
|
const flattenTextStyle = StyleSheet.flatten(textStyle);
|
|
180
210
|
const borderKeys = Object.keys(flattenTextStyle).filter((key) => {
|
|
181
211
|
return key.startsWith('border');
|
|
182
|
-
})
|
|
212
|
+
}) as Array<keyof TextStyle>;
|
|
183
213
|
return {
|
|
184
214
|
borderStyle: pick(borderKeys, flattenTextStyle),
|
|
185
215
|
textStyleWithoutBorderStyle: omit(borderKeys, flattenTextStyle),
|
|
@@ -286,7 +316,12 @@ const TextInput = ({
|
|
|
286
316
|
{renderInputValue ? (
|
|
287
317
|
renderInputValue(nativeInputProps)
|
|
288
318
|
) : (
|
|
289
|
-
<StyledTextInput
|
|
319
|
+
<StyledTextInput
|
|
320
|
+
{...nativeInputProps}
|
|
321
|
+
ref={(reference) => {
|
|
322
|
+
innerTextInput.current = reference;
|
|
323
|
+
}}
|
|
324
|
+
/>
|
|
290
325
|
)}
|
|
291
326
|
</StyledTextInputAndLabelContainer>
|
|
292
327
|
{typeof actualSuffix === 'string' ? (
|
|
@@ -327,4 +362,4 @@ const TextInput = ({
|
|
|
327
362
|
);
|
|
328
363
|
};
|
|
329
364
|
|
|
330
|
-
export default TextInput;
|
|
365
|
+
export default React.forwardRef<TextInputHandles, TextInputProps>(TextInput);
|
|
@@ -14,19 +14,25 @@ export interface ToolbarGroupProps {
|
|
|
14
14
|
align: 'left' | 'center' | 'right';
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const ToolbarGroup = ({ align = 'right', items = [] }: ToolbarGroupProps) =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
const ToolbarGroup = ({ align = 'right', items = [] }: ToolbarGroupProps) => {
|
|
18
|
+
// set maxWidth prevents overflow of items
|
|
19
|
+
// issue: https://github.com/Thinkei/hero-design/issues/1619
|
|
20
|
+
const maxWidth = items.length > 0 ? `${100 / items.length}%` : undefined;
|
|
21
|
+
return (
|
|
22
|
+
<ToolbarGroupWrapper align={align}>
|
|
23
|
+
{items.map(({ label, icon, onPress, disabled, intent }) => (
|
|
24
|
+
<ToolbarItem
|
|
25
|
+
key={`${label}-${icon}`}
|
|
26
|
+
label={label}
|
|
27
|
+
icon={icon}
|
|
28
|
+
intent={intent}
|
|
29
|
+
onPress={onPress}
|
|
30
|
+
disabled={disabled}
|
|
31
|
+
style={{ maxWidth }}
|
|
32
|
+
/>
|
|
33
|
+
))}
|
|
34
|
+
</ToolbarGroupWrapper>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
31
37
|
|
|
32
38
|
export default ToolbarGroup;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
2
3
|
import Icon from '../Icon';
|
|
3
4
|
import Typography from '../Typography';
|
|
4
5
|
import { ToolbarItemWrapper } from './StyledToolbar';
|
|
@@ -25,6 +26,11 @@ export interface ToolbarItemProps {
|
|
|
25
26
|
* Whether the toolbar item is disabled.
|
|
26
27
|
*/
|
|
27
28
|
disabled?: boolean;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Addtitional style.
|
|
32
|
+
*/
|
|
33
|
+
style?: StyleProp<ViewStyle>;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
const ToolbarItem = ({
|
|
@@ -33,8 +39,9 @@ const ToolbarItem = ({
|
|
|
33
39
|
onPress,
|
|
34
40
|
intent = 'primary',
|
|
35
41
|
disabled = false,
|
|
42
|
+
style,
|
|
36
43
|
}: ToolbarItemProps) => (
|
|
37
|
-
<ToolbarItemWrapper onPress={onPress} disabled={disabled}>
|
|
44
|
+
<ToolbarItemWrapper onPress={onPress} disabled={disabled} style={style}>
|
|
38
45
|
{icon ? (
|
|
39
46
|
<Icon
|
|
40
47
|
icon={icon}
|
|
@@ -48,6 +55,7 @@ const ToolbarItem = ({
|
|
|
48
55
|
fontSize={icon ? 'small' : 'large'}
|
|
49
56
|
fontWeight="semi-bold"
|
|
50
57
|
intent={disabled ? 'subdued' : intent}
|
|
58
|
+
maxFontSizeMultiplier={2}
|
|
51
59
|
>
|
|
52
60
|
{label}
|
|
53
61
|
</Typography.Text>
|