@hero-design/rn 7.16.1 → 7.17.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 (54) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/es/index.js +228 -187
  3. package/lib/index.js +227 -186
  4. package/package.json +2 -2
  5. package/src/components/DatePicker/DatePickerIOS.tsx +2 -2
  6. package/src/components/List/BasicListItem.tsx +8 -4
  7. package/src/components/List/StyledBasicListItem.tsx +2 -2
  8. package/src/components/Select/MultiSelect/Option.tsx +21 -15
  9. package/src/components/Select/MultiSelect/OptionList.tsx +47 -41
  10. package/src/components/Select/MultiSelect/__tests__/OptionList.spec.tsx +25 -14
  11. package/src/components/Select/MultiSelect/__tests__/__snapshots__/Option.spec.tsx.snap +41 -21
  12. package/src/components/Select/MultiSelect/__tests__/__snapshots__/OptionList.spec.tsx.snap +1995 -352
  13. package/src/components/Select/MultiSelect/__tests__/__snapshots__/index.spec.tsx.snap +5611 -523
  14. package/src/components/Select/MultiSelect/__tests__/index.spec.tsx +122 -1
  15. package/src/components/Select/MultiSelect/index.tsx +26 -36
  16. package/src/components/Select/SingleSelect/Option.tsx +20 -13
  17. package/src/components/Select/SingleSelect/OptionList.tsx +47 -39
  18. package/src/components/Select/SingleSelect/__tests__/OptionList.spec.tsx +23 -12
  19. package/src/components/Select/SingleSelect/__tests__/__snapshots__/Option.spec.tsx.snap +23 -14
  20. package/src/components/Select/SingleSelect/__tests__/__snapshots__/OptionList.spec.tsx.snap +1846 -258
  21. package/src/components/Select/SingleSelect/__tests__/__snapshots__/index.spec.tsx.snap +5140 -412
  22. package/src/components/Select/SingleSelect/__tests__/index.spec.tsx +117 -1
  23. package/src/components/Select/SingleSelect/index.tsx +26 -37
  24. package/src/components/Select/StyledOptionList.tsx +43 -44
  25. package/src/components/Select/StyledSelect.tsx +6 -15
  26. package/src/components/Select/__tests__/StyledSelect.spec.tsx +1 -23
  27. package/src/components/Select/__tests__/__snapshots__/StyledSelect.spec.tsx.snap +0 -67
  28. package/src/components/Select/__tests__/helpers.spec.tsx +74 -0
  29. package/src/components/Select/helpers.tsx +87 -4
  30. package/src/components/Select/types.ts +99 -0
  31. package/src/components/TextInput/__tests__/__snapshots__/index.spec.tsx.snap +157 -1
  32. package/src/components/TextInput/__tests__/index.spec.tsx +29 -8
  33. package/src/components/TextInput/index.tsx +18 -7
  34. package/src/components/TimePicker/TimePickerIOS.tsx +2 -2
  35. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +3 -5
  36. package/src/theme/components/select.ts +3 -5
  37. package/src/types.ts +7 -1
  38. package/types/components/List/BasicListItem.d.ts +1 -1
  39. package/types/components/Select/MultiSelect/Option.d.ts +4 -2
  40. package/types/components/Select/MultiSelect/OptionList.d.ts +6 -7
  41. package/types/components/Select/MultiSelect/index.d.ts +5 -5
  42. package/types/components/Select/SingleSelect/Option.d.ts +4 -2
  43. package/types/components/Select/SingleSelect/OptionList.d.ts +6 -7
  44. package/types/components/Select/SingleSelect/index.d.ts +5 -5
  45. package/types/components/Select/StyledOptionList.d.ts +10 -16
  46. package/types/components/Select/StyledSelect.d.ts +5 -7
  47. package/types/components/Select/__tests__/helpers.spec.d.ts +1 -0
  48. package/types/components/Select/helpers.d.ts +14 -2
  49. package/types/components/Select/index.d.ts +1 -1
  50. package/types/components/Select/types.d.ts +32 -7
  51. package/types/components/TextInput/index.d.ts +4 -2
  52. package/types/theme/components/select.d.ts +3 -5
  53. package/types/types.d.ts +2 -1
  54. package/src/components/Select/types.tsx +0 -52
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hero-design/rn",
3
- "version": "7.16.1",
3
+ "version": "7.17.0",
4
4
  "license": "MIT",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "@emotion/native": "^11.9.3",
22
22
  "@emotion/react": "^11.9.3",
23
- "@hero-design/colors": "7.16.1",
23
+ "@hero-design/colors": "7.17.0",
24
24
  "date-fns": "^2.16.1",
25
25
  "events": "^3.2.0",
26
26
  "hero-editor": "^1.9.9"
@@ -23,7 +23,7 @@ const DatePickerIOS = ({
23
23
  style,
24
24
  testID,
25
25
  }: DatePickerProps) => {
26
- const [selectingDate, setSelectingDate] = useState<Date | undefined>(value);
26
+ const [selectingDate, setSelectingDate] = useState<Date>(value || new Date());
27
27
  const [open, setOpen] = useState(false);
28
28
 
29
29
  const displayValue = value ? formatDate(displayFormat, value) : '';
@@ -70,7 +70,7 @@ const DatePickerIOS = ({
70
70
  <StyledPickerWrapper>
71
71
  <DateTimePicker
72
72
  testID="datePickerIOS"
73
- value={selectingDate || new Date()}
73
+ value={selectingDate}
74
74
  mode="date"
75
75
  onChange={(_: any, date: Date | undefined) => {
76
76
  if (date) {
@@ -23,7 +23,7 @@ export interface ListItemProps {
23
23
  /**
24
24
  * The title of the component.
25
25
  */
26
- title: string;
26
+ title: string | React.ReactElement;
27
27
  /**
28
28
  * The subtile title of the component.
29
29
  */
@@ -82,9 +82,13 @@ const BasicListItem = ({
82
82
  </StyledPrefixContainer>
83
83
  )}
84
84
  <StyledTitleContainer>
85
- <Typography.Text intent="body" fontSize="large">
86
- {title}
87
- </Typography.Text>
85
+ {typeof title === 'string' ? (
86
+ <Typography.Text intent="body" fontSize="large">
87
+ {title}
88
+ </Typography.Text>
89
+ ) : (
90
+ title
91
+ )}
88
92
  {subtitle && (
89
93
  <Typography.Text intent="subdued" fontSize="small">
90
94
  {subtitle}
@@ -18,8 +18,8 @@ const StyledListItemContainer = styled(TouchableHighlight)<{
18
18
  alignItems: 'center',
19
19
  flexDirection: 'row',
20
20
  backgroundColor: themeSelected
21
- ? theme.__hd__.select.colors.checkedOption
22
- : theme.__hd__.select.colors.option,
21
+ ? theme.__hd__.list.colors.checkedListItemContainerBackground
22
+ : theme.__hd__.list.colors.listItemContainerBackground,
23
23
  padding: theme.__hd__.list.space.listItemContainerPadding,
24
24
  opacity: themeDisabled
25
25
  ? theme.__hd__.list.opacity.disabled
@@ -1,25 +1,31 @@
1
- import React from 'react';
2
- import { View } from 'react-native';
3
- import Icon from '../../Icon';
4
-
5
- import Typography from '../../Typography';
6
- import { OptionWrapper } from '../StyledSelect';
1
+ import React, { ReactElement } from 'react';
2
+ import { useTheme } from '../../../theme';
3
+ import List from '../../List';
7
4
 
8
5
  const Option = ({
9
6
  text,
7
+ disabled = false,
10
8
  selected,
11
9
  onPress,
12
10
  }: {
13
- text: string;
11
+ text: string | ReactElement;
12
+ disabled?: boolean;
14
13
  selected: boolean;
15
14
  onPress: () => void;
16
- }) => (
17
- <OptionWrapper themeSelected={selected} onPress={onPress}>
18
- <View style={{ flex: 1 }}>
19
- <Typography.Text fontSize="large">{text}</Typography.Text>
20
- </View>
21
- {selected && <Icon icon="checkmark" size="small" />}
22
- </OptionWrapper>
23
- );
15
+ }) => {
16
+ const theme = useTheme();
17
+ return (
18
+ <List.BasicItem
19
+ selected={selected}
20
+ disabled={disabled}
21
+ onPress={onPress}
22
+ title={text}
23
+ suffix={selected ? 'checkmark' : undefined}
24
+ style={{
25
+ marginHorizontal: theme.__hd__.select.space.optionHorizontalMargin,
26
+ }}
27
+ />
28
+ );
29
+ };
24
30
 
25
31
  export default Option;
@@ -1,63 +1,69 @@
1
1
  import React from 'react';
2
+ import { SectionListRenderItemInfo } from 'react-native';
2
3
  import { MultiSelectProps } from '.';
3
-
4
- import StyledOptionList, { RenderItemProps } from '../StyledOptionList';
4
+ import { getScrollParams } from '../helpers';
5
+ import StyledOptionList from '../StyledOptionList';
6
+ import { OptionType, SectionData, SectionType } from '../types';
5
7
  import Option from './Option';
6
8
 
7
- interface OptionListProps<T> extends MultiSelectProps<T> {
8
- /**
9
- * event handler for select
10
- */
11
- onPress: (value: T[]) => void;
12
- }
9
+ type OptionListProps<V, T extends OptionType<V>> = Pick<
10
+ MultiSelectProps<V, T>,
11
+ | 'keyExtractor'
12
+ | 'loading'
13
+ | 'onEndReached'
14
+ | 'onQueryChange'
15
+ | 'value'
16
+ | 'renderOption'
17
+ > & {
18
+ onPress: (value: V[]) => void;
19
+ sections: SectionData<V, T>[];
20
+ };
13
21
 
14
- const OptionList = <T,>({
22
+ const OptionList = <V, T extends OptionType<V>>({
15
23
  keyExtractor,
16
24
  loading,
17
25
  onEndReached,
18
26
  onPress,
19
27
  onQueryChange,
20
- options,
28
+ sections,
29
+ renderOption,
21
30
  value,
22
- }: Pick<
23
- OptionListProps<T>,
24
- | 'keyExtractor'
25
- | 'loading'
26
- | 'onEndReached'
27
- | 'onPress'
28
- | 'onQueryChange'
29
- | 'options'
30
- | 'value'
31
- >) => {
31
+ }: OptionListProps<V, T>) => {
32
32
  const firstValue = value?.[0];
33
- const rawScrollIndex = firstValue
34
- ? options.findIndex(option => option.value === firstValue)
35
- : 0;
36
- const scrollIndex = rawScrollIndex - 2 >= 0 ? rawScrollIndex - 2 : 0;
33
+ const scrollParams = getScrollParams(firstValue, sections);
37
34
 
38
- const RenderItem = React.memo(({ item }: RenderItemProps<T>) => (
39
- <Option
40
- text={item.text}
41
- selected={value.includes(item.value)}
42
- onPress={() => {
43
- if (value.includes(item.value)) {
44
- onPress(value.filter(val => val !== item.value));
45
- } else {
46
- onPress([...value, item.value]);
47
- }
48
- }}
49
- />
50
- ));
35
+ const renderItem = (info: SectionListRenderItemInfo<T, SectionType>) => {
36
+ const { item } = info;
37
+ const selected = value.includes(info.item.value);
38
+ const onItemPress = () => {
39
+ if (value.includes(info.item.value)) {
40
+ onPress(value.filter(val => val !== info.item.value));
41
+ } else {
42
+ onPress([...value, info.item.value]);
43
+ }
44
+ };
45
+
46
+ return renderOption ? (
47
+ renderOption({ ...info, selected, onPress: onItemPress })
48
+ ) : (
49
+ <Option
50
+ selected={selected}
51
+ text={item.text}
52
+ disabled={item.disabled}
53
+ onPress={onItemPress}
54
+ />
55
+ );
56
+ };
51
57
 
52
58
  return (
53
- <StyledOptionList<T>
59
+ <StyledOptionList
54
60
  keyExtractor={keyExtractor}
55
61
  loading={loading}
56
62
  onEndReached={onEndReached}
57
63
  onQueryChange={onQueryChange}
58
- options={options}
59
- RenderItem={RenderItem}
60
- scrollIndex={scrollIndex}
64
+ sections={sections}
65
+ renderItem={renderItem}
66
+ scrollParams={scrollParams}
61
67
  />
62
68
  );
63
69
  };
@@ -3,49 +3,60 @@ import { fireEvent } from '@testing-library/react-native';
3
3
  import OptionList from '../OptionList';
4
4
  import renderWithTheme from '../../../../testHelpers/renderWithTheme';
5
5
 
6
- const mockOptions = [
7
- { text: 'A', value: 'a' },
8
- { text: 'B', value: 'b' },
9
- { text: 'C', value: 'c' },
6
+ const sections = [
7
+ { category: 'A', data: [{ text: 'A1', value: 'a1' }] },
8
+ {
9
+ category: 'B',
10
+ data: [
11
+ { text: 'B1', value: 'b1' },
12
+ { text: 'B2', value: 'b2' },
13
+ ],
14
+ },
10
15
  ];
11
16
 
12
17
  describe('OptionList', () => {
13
18
  it('renders correctly', () => {
14
19
  const pressFn = jest.fn();
15
- const { toJSON } = renderWithTheme(
16
- <OptionList value={['a']} options={mockOptions} onPress={pressFn} />
20
+ const { toJSON, getByText } = renderWithTheme(
21
+ <OptionList value={['a1']} sections={sections} onPress={pressFn} />
17
22
  );
23
+
24
+ expect(getByText('A')).toBeTruthy();
25
+ expect(getByText('A1')).toBeTruthy();
26
+ expect(getByText('B')).toBeTruthy();
27
+ expect(getByText('B1')).toBeTruthy();
28
+ expect(getByText('B2')).toBeTruthy();
18
29
  expect(toJSON()).toMatchSnapshot();
19
30
  });
20
31
 
21
32
  it('trigger onPress correctly on select additional value', () => {
22
33
  const pressFn = jest.fn();
23
34
  const { toJSON, getByText } = renderWithTheme(
24
- <OptionList value={['a']} options={mockOptions} onPress={pressFn} />
35
+ <OptionList value={['a1']} sections={sections} onPress={pressFn} />
25
36
  );
26
37
  expect(toJSON()).toMatchSnapshot();
27
- fireEvent.press(getByText('B'));
38
+ fireEvent.press(getByText('B1'));
28
39
  expect(pressFn).toBeCalledTimes(1);
29
- expect(pressFn).toHaveBeenCalledWith(['a', 'b']);
40
+ expect(pressFn).toHaveBeenCalledWith(['a1', 'b1']);
30
41
  });
31
42
 
32
43
  it('trigger onPress correctly on changing selection', () => {
33
44
  const pressFn = jest.fn();
34
45
  const { toJSON, getByText } = renderWithTheme(
35
- <OptionList value={['a', 'b']} options={mockOptions} onPress={pressFn} />
46
+ <OptionList value={['a1', 'b1']} sections={sections} onPress={pressFn} />
36
47
  );
37
48
  expect(toJSON()).toMatchSnapshot();
38
- fireEvent.press(getByText('A'));
49
+ fireEvent.press(getByText('A1'));
39
50
  expect(pressFn).toBeCalledTimes(1);
40
- expect(pressFn).toHaveBeenCalledWith(['b']);
51
+ expect(pressFn).toHaveBeenCalledWith(['b1']);
41
52
  });
42
53
 
43
54
  it('render isLoading correctly', () => {
44
55
  const pressFn = jest.fn();
45
56
  const { toJSON } = renderWithTheme(
46
57
  <OptionList
47
- value={['a']}
48
- options={mockOptions}
58
+ value={['a1']}
59
+ sections={sections}
49
60
  onPress={pressFn}
50
61
  loading
51
62
  />
@@ -2,10 +2,13 @@
2
2
 
3
3
  exports[`Option renders correctly 1`] = `
4
4
  <View
5
+ accessibilityState={
6
+ Object {
7
+ "disabled": false,
8
+ }
9
+ }
5
10
  accessible={true}
6
- collapsable={false}
7
11
  focusable={true}
8
- nativeID="animatedComponent"
9
12
  onClick={[Function]}
10
13
  onResponderGrant={[Function]}
11
14
  onResponderMove={[Function]}
@@ -14,22 +17,28 @@ exports[`Option renders correctly 1`] = `
14
17
  onResponderTerminationRequest={[Function]}
15
18
  onStartShouldSetResponder={[Function]}
16
19
  style={
17
- Object {
18
- "alignItems": "center",
19
- "backgroundColor": "#f1e9fb",
20
- "borderRadius": 4,
21
- "flexDirection": "row",
22
- "justifyContent": "space-between",
23
- "opacity": 1,
24
- "padding": 16,
25
- }
20
+ Array [
21
+ Object {
22
+ "alignItems": "center",
23
+ "backgroundColor": "#f1e9fb",
24
+ "flexDirection": "row",
25
+ "opacity": 1,
26
+ "padding": 16,
27
+ },
28
+ Object {
29
+ "marginHorizontal": 12,
30
+ },
31
+ ]
26
32
  }
27
33
  >
28
34
  <View
29
35
  style={
30
- Object {
31
- "flex": 1,
32
- }
36
+ Array [
37
+ Object {
38
+ "flex": 1,
39
+ },
40
+ undefined,
41
+ ]
33
42
  }
34
43
  >
35
44
  <Text
@@ -52,19 +61,30 @@ exports[`Option renders correctly 1`] = `
52
61
  testOption
53
62
  </Text>
54
63
  </View>
55
- <HeroIcon
56
- name="checkmark"
64
+ <View
57
65
  style={
58
66
  Array [
59
67
  Object {
60
- "color": "#292a2b",
61
- "fontSize": 20,
68
+ "marginLeft": 8,
62
69
  },
63
70
  undefined,
64
71
  ]
65
72
  }
66
- themeIntent="text"
67
- themeSize="small"
68
- />
73
+ >
74
+ <HeroIcon
75
+ name="checkmark"
76
+ style={
77
+ Array [
78
+ Object {
79
+ "color": "#292a2b",
80
+ "fontSize": 20,
81
+ },
82
+ undefined,
83
+ ]
84
+ }
85
+ themeIntent="text"
86
+ themeSize="small"
87
+ />
88
+ </View>
69
89
  </View>
70
90
  `;