@hero-design/rn 8.63.3 → 8.64.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 +1 -1
  2. package/CHANGELOG.md +6 -0
  3. package/es/index.js +85 -38
  4. package/eslint.config.js +42 -0
  5. package/lib/index.js +85 -38
  6. package/package.json +7 -3
  7. package/rollup.config.js +13 -0
  8. package/sonar-project.properties +1 -1
  9. package/src/components/BottomSheet/__tests__/__snapshots__/index.spec.tsx.snap +5 -0
  10. package/src/components/BottomSheet/__tests__/index.spec.tsx +17 -0
  11. package/src/components/BottomSheet/index.tsx +6 -0
  12. package/src/components/Calendar/CalendarRowItem.tsx +3 -1
  13. package/src/components/Calendar/StyledCalendar.tsx +21 -8
  14. package/src/components/Calendar/__tests__/CalendarRowItem.spec.tsx +1 -0
  15. package/src/components/Calendar/__tests__/__snapshots__/CalendarRowItem.spec.tsx.snap +4 -2
  16. package/src/components/Calendar/__tests__/index.spec.tsx +7 -1
  17. package/src/components/Calendar/index.tsx +30 -8
  18. package/src/components/DatePicker/DatePickerCalendar.tsx +14 -10
  19. package/src/components/DatePicker/DatePickerIOS.tsx +2 -0
  20. package/src/components/DatePicker/__tests__/DatePickerCalendar.spec.tsx +37 -0
  21. package/src/components/DatePicker/__tests__/DatePickerIOS.spec.tsx +34 -0
  22. package/src/components/DatePicker/__tests__/__snapshots__/DatePickerIOS.spec.tsx.snap +5 -0
  23. package/src/components/DatePicker/types.ts +4 -0
  24. package/src/components/FAB/ActionGroup/__tests__/__snapshots__/index.spec.tsx.snap +5 -0
  25. package/src/components/FAB/ActionGroup/__tests__/index.spec.tsx +45 -24
  26. package/src/components/FAB/ActionGroup/index.tsx +6 -0
  27. package/src/components/Select/MultiSelect/__tests__/__snapshots__/index.spec.tsx.snap +20 -0
  28. package/src/components/Select/MultiSelect/__tests__/index.spec.tsx +28 -0
  29. package/src/components/Select/MultiSelect/index.tsx +6 -0
  30. package/src/components/Select/SingleSelect/__tests__/__snapshots__/index.spec.tsx.snap +15 -0
  31. package/src/components/Select/SingleSelect/__tests__/index.spec.tsx +25 -0
  32. package/src/components/Select/SingleSelect/index.tsx +6 -0
  33. package/src/components/TimePicker/TimePickerIOS.tsx +2 -0
  34. package/src/components/TimePicker/__tests__/TimePickerIOS.spec.tsx +31 -0
  35. package/src/components/TimePicker/__tests__/__snapshots__/TimePickerIOS.spec.tsx.snap +5 -0
  36. package/src/components/TimePicker/types.ts +4 -0
  37. package/src/testHelpers/utils.ts +21 -0
  38. package/stats/8.63.3/rn-stats.html +4844 -0
  39. package/stats/8.64.0/rn-stats.html +4842 -0
  40. package/types/components/BottomSheet/index.d.ts +5 -1
  41. package/types/components/Calendar/CalendarRowItem.d.ts +2 -1
  42. package/types/components/Calendar/StyledCalendar.d.ts +7 -0
  43. package/types/components/DatePicker/DatePickerCalendar.d.ts +1 -1
  44. package/types/components/DatePicker/DatePickerIOS.d.ts +1 -1
  45. package/types/components/DatePicker/types.d.ts +4 -0
  46. package/types/components/FAB/ActionGroup/index.d.ts +4 -0
  47. package/types/components/Select/MultiSelect/index.d.ts +5 -1
  48. package/types/components/Select/SingleSelect/index.d.ts +5 -1
  49. package/types/components/Select/index.d.ts +1 -1
  50. package/types/components/TimePicker/TimePickerIOS.d.ts +1 -1
  51. package/types/components/TimePicker/types.d.ts +4 -0
  52. package/types/testHelpers/utils.d.ts +1 -0
  53. package/.eslintrc.js +0 -13
  54. package/src/theme/components/.eslintrc.json +0 -10
@@ -3,7 +3,7 @@ import {
3
3
  MonthYearPickerViewIOS,
4
4
  } from '@hero-design/react-native-month-year-picker';
5
5
  import format from 'date-fns/fp/format';
6
- import React from 'react';
6
+ import React, { useMemo, useState } from 'react';
7
7
  import { Platform, TouchableOpacity } from 'react-native';
8
8
  import { useTheme } from '../../theme';
9
9
  import { noop } from '../../utils/functions';
@@ -121,8 +121,13 @@ const Calendar = ({
121
121
  }),
122
122
  {}
123
123
  );
124
- const [monthPickerVisible, setMonthPickerVisible] = React.useState(false);
125
- const [contentHeight, setContentHeight] = React.useState(0);
124
+ const [monthPickerVisible, setMonthPickerVisible] = useState(false);
125
+ const [contentHeight, setContentHeight] = useState(0);
126
+ const [contentWidth, setContentWidth] = useState(0);
127
+ const calendarItemWidth = useMemo(
128
+ () => (contentWidth > 0 ? contentWidth / 7 : undefined),
129
+ [contentWidth]
130
+ );
126
131
 
127
132
  const useMonthPicker = onMonthChange !== noop;
128
133
 
@@ -241,6 +246,7 @@ const Calendar = ({
241
246
  theme.__hd__.calendar.space.iosPickerMarginVertical * 2,
242
247
  marginVertical:
243
248
  -theme.__hd__.calendar.space.iosPickerMarginVertical,
249
+ width: contentWidth,
244
250
  }}
245
251
  />
246
252
  </Box>
@@ -248,14 +254,18 @@ const Calendar = ({
248
254
  <Box
249
255
  onLayout={
250
256
  Platform.OS === 'ios'
251
- ? (e) => setContentHeight(e.nativeEvent.layout.height)
257
+ ? (e) => {
258
+ const { width, height } = e.nativeEvent.layout;
259
+ setContentHeight(height);
260
+ setContentWidth(width);
261
+ }
252
262
  : undefined
253
263
  }
254
264
  >
255
265
  <StyledCalendarRow>
256
266
  {DAYS_OF_WEEK.map((day) => (
257
267
  <StyledCalendarRowItem key={day}>
258
- <StyledCalendarDayNameCell>
268
+ <StyledCalendarDayNameCell themeItemWidth={calendarItemWidth}>
259
269
  <Typography.Body variant="small">{day}</Typography.Body>
260
270
  </StyledCalendarDayNameCell>
261
271
  </StyledCalendarRowItem>
@@ -272,14 +282,19 @@ const Calendar = ({
272
282
  onPress={() => onChange?.(date)}
273
283
  textIntent="subdued"
274
284
  marked={parsedMaskedDate[date.toDateString()]}
285
+ itemWidth={contentWidth > 0 ? contentWidth / 7 : undefined}
275
286
  />
276
287
  ) : (
277
- <StyledDisabledCalendarRowItem testID="calendar-disabled-cell" />
288
+ <StyledDisabledCalendarRowItem
289
+ themeItemWidth={calendarItemWidth}
290
+ testID="calendar-disabled-cell"
291
+ />
278
292
  )
279
293
  )}
280
294
  {daysOfCurrentMonth.map((date) =>
281
295
  date ? (
282
296
  <CalendarRowItem
297
+ itemWidth={calendarItemWidth}
283
298
  key={date.toDateString()}
284
299
  date={date}
285
300
  isCurrent={isEqDate(now, date)}
@@ -288,12 +303,16 @@ const Calendar = ({
288
303
  marked={parsedMaskedDate[date.toDateString()]}
289
304
  />
290
305
  ) : (
291
- <StyledDisabledCalendarRowItem testID="calendar-disabled-cell" />
306
+ <StyledDisabledCalendarRowItem
307
+ themeItemWidth={calendarItemWidth}
308
+ testID="calendar-disabled-cell"
309
+ />
292
310
  )
293
311
  )}
294
312
  {daysOfNextMonth.map((date) =>
295
313
  date ? (
296
314
  <CalendarRowItem
315
+ itemWidth={calendarItemWidth}
297
316
  key={date.toDateString()}
298
317
  date={date}
299
318
  isCurrent={isEqDate(now, date)}
@@ -303,7 +322,10 @@ const Calendar = ({
303
322
  marked={parsedMaskedDate[date.toDateString()]}
304
323
  />
305
324
  ) : (
306
- <StyledDisabledCalendarRowItem testID="calendar-disabled-cell" />
325
+ <StyledDisabledCalendarRowItem
326
+ themeItemWidth={calendarItemWidth}
327
+ testID="calendar-disabled-cell"
328
+ />
307
329
  )
308
330
  )}
309
331
  </StyledCalendarRow>
@@ -1,6 +1,6 @@
1
1
  import formatDate from 'date-fns/fp/format';
2
2
  import React, { useState } from 'react';
3
- import { Platform, TouchableOpacity, View } from 'react-native';
3
+ import { Platform, ScrollView, TouchableOpacity, View } from 'react-native';
4
4
 
5
5
  import BottomSheet from '../BottomSheet';
6
6
  import Button from '../Button';
@@ -77,6 +77,7 @@ const DatePickerCalendar = ({
77
77
  testID,
78
78
  monthPickerConfirmLabel,
79
79
  monthPickerCancelLabel,
80
+ supportedOrientations = ['portrait'],
80
81
  }: Omit<DatePickerProps, 'variant'>) => {
81
82
  const [open, setOpen] = useState(false);
82
83
  const [monthPickerVisible, setMonthPickerVisible] = useState(false);
@@ -121,16 +122,19 @@ const DatePickerCalendar = ({
121
122
  />
122
123
  )
123
124
  }
125
+ supportedOrientations={supportedOrientations}
124
126
  >
125
- <InternalCalendar
126
- minDate={minDate}
127
- maxDate={maxDate}
128
- value={value}
129
- onChange={setSelectingDate}
130
- monthPickerConfirmLabel={monthPickerConfirmLabel}
131
- monthPickerCancelLabel={monthPickerCancelLabel}
132
- onToggleMonthPicker={(visible) => setMonthPickerVisible(visible)}
133
- />
127
+ <ScrollView>
128
+ <InternalCalendar
129
+ minDate={minDate}
130
+ maxDate={maxDate}
131
+ value={value}
132
+ onChange={setSelectingDate}
133
+ monthPickerConfirmLabel={monthPickerConfirmLabel}
134
+ monthPickerCancelLabel={monthPickerCancelLabel}
135
+ onToggleMonthPicker={(visible) => setMonthPickerVisible(visible)}
136
+ />
137
+ </ScrollView>
134
138
  </BottomSheet>
135
139
  </TouchableOpacity>
136
140
  );
@@ -26,6 +26,7 @@ const DatePickerIOS = ({
26
26
  helpText,
27
27
  style,
28
28
  testID,
29
+ supportedOrientations = ['portrait'],
29
30
  }: Omit<
30
31
  DatePickerProps,
31
32
  'variant' | 'monthPickerConfirmLabel' | 'monthPickerCancelLabel'
@@ -71,6 +72,7 @@ const DatePickerIOS = ({
71
72
  }}
72
73
  />
73
74
  }
75
+ supportedOrientations={supportedOrientations}
74
76
  >
75
77
  <StyledPickerWrapper>
76
78
  <DateTimePicker
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import type { ModalProps } from 'react-native';
4
4
  import renderWithTheme from '../../../testHelpers/renderWithTheme';
5
5
  import DatePickerCalendar from '../DatePickerCalendar';
6
+ import { setOrientation } from '../../../testHelpers/utils';
6
7
 
7
8
  jest.mock('react-native/Libraries/Modal/Modal', () => {
8
9
  const Modal = jest.requireActual('react-native/Libraries/Modal/Modal');
@@ -45,6 +46,42 @@ describe('DatePickerCalendar', () => {
45
46
  expect(onChange).toBeCalledWith(new Date('1995-12-14T00:00:00.000Z'));
46
47
  });
47
48
 
49
+ it('renders correctly in landscape mode', () => {
50
+ setOrientation('landscape');
51
+ const onChange = jest.fn();
52
+ const { getByText, queryByTestId } = renderWithTheme(
53
+ <DatePickerCalendar
54
+ value={new Date('1995-12-21T00:00:00.000Z')}
55
+ label="Start date"
56
+ confirmLabel="Confirm"
57
+ onChange={onChange}
58
+ supportedOrientations={['landscape']}
59
+ />
60
+ );
61
+
62
+ expect(getByText('Start date')).toBeDefined();
63
+ expect(queryByTestId('text-input').props.value).toBe('21/12/1995');
64
+ expect(queryByTestId('calendar')).toBeNull();
65
+
66
+ // Open date picker
67
+ fireEvent.press(getByText('Start date'));
68
+ expect(queryByTestId('calendar')).toBeTruthy();
69
+
70
+ expect(getByText('December 1995')).toBeDefined();
71
+ expect(getByText('Mo')).toBeDefined();
72
+ expect(getByText('Tu')).toBeDefined();
73
+ expect(getByText('We')).toBeDefined();
74
+ expect(getByText('Th')).toBeDefined();
75
+ expect(getByText('Fr')).toBeDefined();
76
+ expect(getByText('Sa')).toBeDefined();
77
+ expect(getByText('Su')).toBeDefined();
78
+ // Change date
79
+ fireEvent.press(getByText('14'));
80
+ fireEvent.press(getByText('Confirm'));
81
+
82
+ expect(onChange).toBeCalledWith(new Date('1995-12-14T00:00:00.000Z'));
83
+ });
84
+
48
85
  it('renders correct help text', () => {
49
86
  const { getByText } = renderWithTheme(
50
87
  <DatePickerCalendar
@@ -4,6 +4,7 @@ import type { ModalProps } from 'react-native';
4
4
  import renderWithTheme from '../../../testHelpers/renderWithTheme';
5
5
  import DatePickerIOS from '../DatePickerIOS';
6
6
  import { getDateValue } from '../useCalculateDate';
7
+ import { setOrientation } from '../../../testHelpers/utils';
7
8
 
8
9
  jest.mock('react-native/Libraries/Modal/Modal', () => {
9
10
  const Modal = jest.requireActual('react-native/Libraries/Modal/Modal');
@@ -68,6 +69,39 @@ describe('DatePickerIOS', () => {
68
69
  expect(onChange).toBeCalledWith(new Date('December 17, 1995'));
69
70
  });
70
71
 
72
+ it('renders correctly in landscape mode', () => {
73
+ const onChange = jest.fn();
74
+ setOrientation('landscape');
75
+ const { getByText, queryByTestId } = renderWithTheme(
76
+ <DatePickerIOS
77
+ value={new Date('December 21, 1995')}
78
+ label="Start date"
79
+ confirmLabel="Confirm"
80
+ onChange={onChange}
81
+ supportedOrientations={['landscape']}
82
+ />
83
+ );
84
+
85
+ expect(getByText('Start date')).toBeDefined();
86
+ expect(queryByTestId('text-input').props.value).toBe('21/12/1995');
87
+ expect(queryByTestId('datePickerIOS')).toBeNull();
88
+
89
+ // Open date picker
90
+ fireEvent.press(getByText('Start date'));
91
+ expect(queryByTestId('datePickerIOS')).toBeTruthy();
92
+
93
+ // Change date
94
+ fireEvent(
95
+ queryByTestId('datePickerIOS'),
96
+ 'onChange',
97
+ null,
98
+ new Date('December 17, 1995')
99
+ );
100
+ fireEvent.press(getByText('Confirm'));
101
+
102
+ expect(onChange).toBeCalledWith(new Date('December 17, 1995'));
103
+ });
104
+
71
105
  it('renders correct help text', () => {
72
106
  const { getByText } = renderWithTheme(
73
107
  <DatePickerIOS
@@ -270,6 +270,11 @@ exports[`DatePickerIOS renders correctly 1`] = `
270
270
  "position": "absolute",
271
271
  }
272
272
  }
273
+ supportedOrientations={
274
+ [
275
+ "portrait",
276
+ ]
277
+ }
273
278
  transparent={true}
274
279
  visible={true}
275
280
  >
@@ -72,4 +72,8 @@ export interface DatePickerProps {
72
72
  * Calendar variant prop. Label for the cancel button of the month picker, Android only.
73
73
  */
74
74
  monthPickerCancelLabel?: string;
75
+ /**
76
+ * Supported orientations for the DatePicker modal, iOS only.
77
+ */
78
+ supportedOrientations?: ('portrait' | 'landscape')[];
75
79
  }
@@ -329,6 +329,11 @@ exports[`ActionGroup has active true 1`] = `
329
329
  animationType="fade"
330
330
  hardwareAccelerated={false}
331
331
  statusBarTranslucent={true}
332
+ supportedOrientations={
333
+ [
334
+ "portrait",
335
+ ]
336
+ }
332
337
  transparent={true}
333
338
  visible={true}
334
339
  >
@@ -1,39 +1,38 @@
1
1
  import '@testing-library/jest-native/extend-expect';
2
2
  import { fireEvent } from '@testing-library/react-native';
3
- import React from 'react';
3
+ import React, { ComponentProps } from 'react';
4
4
  import ActionGroup from '..';
5
5
  import renderWithTheme from '../../../../testHelpers/renderWithTheme';
6
+ import { setOrientation } from '../../../../testHelpers/utils';
6
7
 
7
8
  describe('ActionGroup', () => {
9
+ const items: ComponentProps<typeof ActionGroup>['items'] = [
10
+ {
11
+ icon: 'speaker',
12
+ title: 'Give shout out',
13
+ testID: 'speaker-action-item',
14
+ },
15
+ { icon: 'target', title: 'Goal', testID: 'target-action-item' },
16
+ {
17
+ icon: 'plane',
18
+ title: 'Leave request',
19
+ testID: 'plane-action-item',
20
+ },
21
+ {
22
+ icon: 'health-bag',
23
+ title: 'Safety incident',
24
+ testID: 'health-bag-action-item',
25
+ },
26
+ { icon: 'clock', title: 'Timesheets', testID: 'clock-action-item' },
27
+ ];
28
+
8
29
  it.each`
9
30
  active
10
31
  ${true}
11
32
  ${false}
12
33
  `('has active $active', ({ active }) => {
13
34
  const { toJSON, getByTestId, queryByTestId } = renderWithTheme(
14
- <ActionGroup
15
- fabTitle="Shout out"
16
- active={active}
17
- items={[
18
- {
19
- icon: 'speaker',
20
- title: 'Give shout out',
21
- testID: 'speaker-action-item',
22
- },
23
- { icon: 'target', title: 'Goal', testID: 'target-action-item' },
24
- {
25
- icon: 'plane',
26
- title: 'Leave request',
27
- testID: 'plane-action-item',
28
- },
29
- {
30
- icon: 'health-bag',
31
- title: 'Safety incident',
32
- testID: 'health-bag-action-item',
33
- },
34
- { icon: 'clock', title: 'Timesheets', testID: 'clock-action-item' },
35
- ]}
36
- />
35
+ <ActionGroup fabTitle="Shout out" active={active} items={items} />
37
36
  );
38
37
 
39
38
  expect(toJSON()).toMatchSnapshot();
@@ -51,6 +50,28 @@ describe('ActionGroup', () => {
51
50
  }
52
51
  });
53
52
 
53
+ it.each`
54
+ orientation
55
+ ${'portrait'}
56
+ ${'landscape'}
57
+ `('renders correctly in $orientation mode', ({ orientation }) => {
58
+ setOrientation(orientation);
59
+ const { getByTestId, queryByTestId } = renderWithTheme(
60
+ <ActionGroup
61
+ active
62
+ fabTitle="Shout out"
63
+ items={items}
64
+ supportedOrientations={[orientation]}
65
+ />
66
+ );
67
+
68
+ expect(queryByTestId('back-drop')).toBeDefined();
69
+ expect(getByTestId('speaker-action-item')).toBeDefined();
70
+ expect(getByTestId('target-action-item')).toBeDefined();
71
+ expect(getByTestId('plane-action-item')).toBeDefined();
72
+ expect(getByTestId('health-bag-action-item')).toBeDefined();
73
+ });
74
+
54
75
  describe('when user presses', () => {
55
76
  it('calls onPress when active = false', () => {
56
77
  const onPressSpy = jest.fn();
@@ -67,6 +67,10 @@ export interface ActionGroupProps {
67
67
  * Testing id of the component.
68
68
  */
69
69
  testID?: string;
70
+ /**
71
+ * Supported orientations for the ActionGroup modal, iOS only.
72
+ */
73
+ supportedOrientations?: ('portrait' | 'landscape')[];
70
74
  }
71
75
 
72
76
  const ActionGroup = forwardRef<ActionGroupHandles, ActionGroupProps>(
@@ -81,6 +85,7 @@ const ActionGroup = forwardRef<ActionGroupHandles, ActionGroupProps>(
81
85
  fabTitle,
82
86
  onBackdropPress,
83
87
  fabIcon = 'add',
88
+ supportedOrientations = ['portrait'],
84
89
  },
85
90
  ref
86
91
  ) => {
@@ -143,6 +148,7 @@ const ActionGroup = forwardRef<ActionGroupHandles, ActionGroupProps>(
143
148
  animationType="fade"
144
149
  transparent
145
150
  statusBarTranslucent
151
+ supportedOrientations={supportedOrientations}
146
152
  >
147
153
  <StyledContainerInModal testID={testID} style={[style]}>
148
154
  <StyledBackdrop testID="back-drop" onPress={onBackdropPress} />
@@ -266,6 +266,11 @@ exports[`rendering allows custom renderer 1`] = `
266
266
  <Modal
267
267
  hardwareAccelerated={false}
268
268
  onRequestClose={[Function]}
269
+ supportedOrientations={
270
+ [
271
+ "portrait",
272
+ ]
273
+ }
269
274
  transparent={true}
270
275
  visible={true}
271
276
  >
@@ -2084,6 +2089,11 @@ exports[`rendering renders correctly when bottom sheet is visible 1`] = `
2084
2089
  <Modal
2085
2090
  hardwareAccelerated={false}
2086
2091
  onRequestClose={[Function]}
2092
+ supportedOrientations={
2093
+ [
2094
+ "portrait",
2095
+ ]
2096
+ }
2087
2097
  transparent={true}
2088
2098
  visible={true}
2089
2099
  >
@@ -4121,6 +4131,11 @@ exports[`rendering renders correctly when receives sections 1`] = `
4121
4131
  <Modal
4122
4132
  hardwareAccelerated={false}
4123
4133
  onRequestClose={[Function]}
4134
+ supportedOrientations={
4135
+ [
4136
+ "portrait",
4137
+ ]
4138
+ }
4124
4139
  transparent={true}
4125
4140
  visible={true}
4126
4141
  >
@@ -5439,6 +5454,11 @@ exports[`rendering renders correctly when receives sections 2`] = `
5439
5454
  <Modal
5440
5455
  hardwareAccelerated={false}
5441
5456
  onRequestClose={[Function]}
5457
+ supportedOrientations={
5458
+ [
5459
+ "portrait",
5460
+ ]
5461
+ }
5442
5462
  transparent={true}
5443
5463
  visible={true}
5444
5464
  >
@@ -9,6 +9,7 @@ import HeroDesignProvider from '../../../HeroDesignProvider';
9
9
  import List from '../../../List';
10
10
  import Typography from '../../../Typography';
11
11
  import type { ListRenderOptionInfo } from '../../types';
12
+ import { setOrientation } from '../../../../testHelpers/utils';
12
13
 
13
14
  const options = [
14
15
  { text: 'Monday', value: 'mon' },
@@ -113,6 +114,33 @@ describe('rendering', () => {
113
114
  expect(getByText('Confirm')).toBeDefined();
114
115
  });
115
116
 
117
+ it('renders correctly in landscape mode when bottom sheet is visible', () => {
118
+ setOrientation('landscape');
119
+
120
+ const { queryAllByText, getByText, getByTestId } = renderWithTheme(
121
+ <MultiSelect
122
+ label="Allow notifications"
123
+ footerLabel="Confirm"
124
+ options={options}
125
+ value={['mon', 'tue']}
126
+ onConfirm={jest.fn()}
127
+ supportedOrientations={['landscape']}
128
+ />
129
+ );
130
+
131
+ fireEvent.press(getByTestId('text-input'));
132
+
133
+ expect(queryAllByText('Allow notifications')).toHaveLength(2);
134
+ expect(getByText('Monday')).toBeDefined();
135
+ expect(getByText('Tuesday')).toBeDefined();
136
+ expect(getByText('Wednesday')).toBeDefined();
137
+ expect(getByText('Thursday')).toBeDefined();
138
+ expect(getByText('Friday')).toBeDefined();
139
+ expect(getByText('Saturday')).toBeDefined();
140
+ expect(getByText('Sunday')).toBeDefined();
141
+ expect(getByText('Confirm')).toBeDefined();
142
+ });
143
+
116
144
  it('renders correctly when input is loading', () => {
117
145
  const { toJSON, getByTestId } = renderWithTheme(
118
146
  <MultiSelect
@@ -47,6 +47,10 @@ export interface MultiSelectProps<V, T extends OptionType<V> = OptionType<V>>
47
47
  selectedValue: V[],
48
48
  inputProps: NativeTextInputProps
49
49
  ) => React.ReactNode;
50
+ /**
51
+ * Supported orientations for the MultiSelect modal, iOS only.
52
+ */
53
+ supportedOrientations?: ('portrait' | 'landscape')[];
50
54
  }
51
55
 
52
56
  function MultiSelect<V, T extends OptionType<V>>({
@@ -69,6 +73,7 @@ function MultiSelect<V, T extends OptionType<V>>({
69
73
  style,
70
74
  testID,
71
75
  value,
76
+ supportedOrientations = ['portrait'],
72
77
  }: MultiSelectProps<V, T>) {
73
78
  const { isKeyboardVisible, keyboardHeight } = useKeyboard();
74
79
  const [open, setOpen] = useState(false);
@@ -154,6 +159,7 @@ function MultiSelect<V, T extends OptionType<V>>({
154
159
  sectionListRef.current?.scrollToLocation(scrollParams);
155
160
  }
156
161
  }}
162
+ supportedOrientations={supportedOrientations}
157
163
  >
158
164
  {onQueryChange && (
159
165
  <StyledSearchBar>
@@ -265,6 +265,11 @@ exports[`rendering allows custom renderer 1`] = `
265
265
  <Modal
266
266
  hardwareAccelerated={false}
267
267
  onRequestClose={[Function]}
268
+ supportedOrientations={
269
+ [
270
+ "portrait",
271
+ ]
272
+ }
268
273
  transparent={true}
269
274
  visible={true}
270
275
  >
@@ -1999,6 +2004,11 @@ exports[`rendering renders correctly when bottom sheet is visible 1`] = `
1999
2004
  <Modal
2000
2005
  hardwareAccelerated={false}
2001
2006
  onRequestClose={[Function]}
2007
+ supportedOrientations={
2008
+ [
2009
+ "portrait",
2010
+ ]
2011
+ }
2002
2012
  transparent={true}
2003
2013
  visible={true}
2004
2014
  >
@@ -3896,6 +3906,11 @@ exports[`rendering renders correctly when receives sections 1`] = `
3896
3906
  <Modal
3897
3907
  hardwareAccelerated={false}
3898
3908
  onRequestClose={[Function]}
3909
+ supportedOrientations={
3910
+ [
3911
+ "portrait",
3912
+ ]
3913
+ }
3899
3914
  transparent={true}
3900
3915
  visible={true}
3901
3916
  >
@@ -5,6 +5,7 @@ import SingleSelect from '..';
5
5
  import Typography from '../../../Typography';
6
6
  import List from '../../../List';
7
7
  import type { ListRenderOptionInfo } from '../../types';
8
+ import { setOrientation } from '../../../../testHelpers/utils';
8
9
 
9
10
  const options = [
10
11
  { text: 'Monday', value: 'mon' },
@@ -105,6 +106,30 @@ describe('rendering', () => {
105
106
  expect(getByText('Sunday')).toBeDefined();
106
107
  });
107
108
 
109
+ it('renders correctly in landscape mode when bottom sheet is visible', () => {
110
+ setOrientation('landscape');
111
+
112
+ const { queryAllByText, getByText, getByTestId } = renderWithTheme(
113
+ <SingleSelect
114
+ label="Allow notifications"
115
+ options={options}
116
+ value="mon"
117
+ onConfirm={jest.fn()}
118
+ supportedOrientations={['landscape']}
119
+ />
120
+ );
121
+ fireEvent.press(getByTestId('text-input'));
122
+
123
+ expect(queryAllByText('Allow notifications')).toHaveLength(2);
124
+ expect(getByText('Monday')).toBeDefined();
125
+ expect(getByText('Tuesday')).toBeDefined();
126
+ expect(getByText('Wednesday')).toBeDefined();
127
+ expect(getByText('Thursday')).toBeDefined();
128
+ expect(getByText('Friday')).toBeDefined();
129
+ expect(getByText('Saturday')).toBeDefined();
130
+ expect(getByText('Sunday')).toBeDefined();
131
+ });
132
+
108
133
  it('renders correctly when input is loading', () => {
109
134
  const { toJSON, getByTestId } = renderWithTheme(
110
135
  <SingleSelect
@@ -33,6 +33,10 @@ export interface SingleSelectProps<V, T extends OptionType<V> = OptionType<V>>
33
33
  selectedValue: V | null,
34
34
  inputProps: NativeTextInputProps
35
35
  ) => React.ReactNode;
36
+ /**
37
+ * Supported orientations for the Select modal, iOS only.
38
+ */
39
+ supportedOrientations?: ('portrait' | 'landscape')[];
36
40
  }
37
41
 
38
42
  const SingleSelect = <V, T extends OptionType<V>>({
@@ -54,6 +58,7 @@ const SingleSelect = <V, T extends OptionType<V>>({
54
58
  style,
55
59
  testID,
56
60
  value,
61
+ supportedOrientations = ['portrait'],
57
62
  }: SingleSelectProps<V, T>) => {
58
63
  const { isKeyboardVisible, keyboardHeight } = useKeyboard();
59
64
  const [open, setOpen] = useState(false);
@@ -113,6 +118,7 @@ const SingleSelect = <V, T extends OptionType<V>>({
113
118
  sectionListRef.current?.scrollToLocation(scrollParams);
114
119
  }
115
120
  }}
121
+ supportedOrientations={supportedOrientations}
116
122
  >
117
123
  {onQueryChange && (
118
124
  <StyledSearchBar>
@@ -24,6 +24,7 @@ const TimePickerIOS = ({
24
24
  style,
25
25
  testID,
26
26
  showSuffix = true,
27
+ supportedOrientations = ['portrait'],
27
28
  }: TimePickerProps) => {
28
29
  const [selectingDate, setSelectingDate] = useState<Date>(value || new Date());
29
30
  const [open, setOpen] = useState(false);
@@ -64,6 +65,7 @@ const TimePickerIOS = ({
64
65
  }}
65
66
  />
66
67
  }
68
+ supportedOrientations={supportedOrientations}
67
69
  >
68
70
  <StyledPickerWrapper>
69
71
  <DateTimePicker