react-native-molecules 0.5.0-beta.22 → 0.5.0-beta.24

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 (82) hide show
  1. package/components/Accordion/Accordion.tsx +1 -1
  2. package/components/Accordion/AccordionItem.tsx +1 -1
  3. package/components/Button/Button.tsx +3 -1
  4. package/components/Checkbox/Checkbox.tsx +2 -1
  5. package/components/DateField/useDateFieldState.ts +2 -2
  6. package/components/DatePicker/DatePickerProvider.tsx +1 -1
  7. package/components/DatePicker/utils.ts +2 -0
  8. package/components/DatePickerInline/DatePickerInline.tsx +1 -1
  9. package/components/DatePickerInline/DatePickerInlineBase.tsx +1 -1
  10. package/components/DatePickerInline/Day.tsx +1 -1
  11. package/components/DatePickerInline/MonthPicker.tsx +24 -40
  12. package/components/DatePickerInline/Swiper.tsx +1 -1
  13. package/components/DatePickerInline/SwiperUtils.ts +1 -1
  14. package/components/DatePickerInline/YearPicker.tsx +44 -79
  15. package/components/DatePickerInline/dateUtils.tsx +1 -1
  16. package/components/DatePickerInline/store.tsx +2 -1
  17. package/components/Divider/index.tsx +2 -3
  18. package/components/ElementGroup/ElementGroup.tsx +1 -1
  19. package/components/FilePicker/FilePicker.tsx +1 -1
  20. package/components/Icon/iconFactory.tsx +2 -1
  21. package/components/IconButton/IconButton.tsx +39 -13
  22. package/components/IconButton/index.tsx +1 -0
  23. package/components/IconButton/types.ts +2 -0
  24. package/components/List/List.tsx +156 -387
  25. package/components/List/context.tsx +4 -5
  26. package/components/List/index.ts +0 -1
  27. package/components/List/types.ts +77 -109
  28. package/components/List/utils.ts +4 -37
  29. package/components/Menu/Menu.tsx +13 -30
  30. package/components/Menu/index.tsx +0 -2
  31. package/components/Popover/Popover.tsx +7 -10
  32. package/components/Popover/PopoverRoot.tsx +6 -20
  33. package/components/Popover/common.ts +4 -0
  34. package/components/Popover/index.ts +2 -8
  35. package/components/Popover/usePlatformMeasure.ts +4 -2
  36. package/components/Portal/Portal.tsx +1 -2
  37. package/components/RadioButton/RadioButtonGroup.tsx +1 -2
  38. package/components/Rating/Rating.tsx +1 -1
  39. package/components/Select/Select.tsx +304 -71
  40. package/components/Select/context.tsx +30 -3
  41. package/components/Select/index.ts +20 -2
  42. package/components/Select/types.ts +43 -25
  43. package/components/Select/utils.ts +18 -4
  44. package/components/Switch/Switch.ios.tsx +1 -1
  45. package/components/Switch/Switch.tsx +2 -1
  46. package/components/Tabs/Tabs.tsx +2 -2
  47. package/components/TextInput/TextInput.tsx +4 -3
  48. package/components/TimePicker/AnalogClock.tsx +1 -1
  49. package/components/TimePicker/TimeInputs.tsx +1 -1
  50. package/components/TimePicker/TimePicker.tsx +1 -1
  51. package/components/TimePicker/TimePickerModal.tsx +1 -1
  52. package/components/Tooltip/Tooltip.tsx +1 -1
  53. package/components/TouchableRipple/TouchableRipple.tsx +76 -152
  54. package/hocs/index.tsx +1 -1
  55. package/hocs/withKeyboardAccessibility.tsx +2 -3
  56. package/hooks/index.tsx +2 -6
  57. package/hooks/useContrastColor.ts +1 -2
  58. package/hooks/useFilePicker.tsx +1 -1
  59. package/hooks/useHandleNumberFormat.tsx +2 -2
  60. package/hooks/useMediaQuery.tsx +1 -2
  61. package/package.json +5 -28
  62. package/shortcuts-manager/ShortcutsManager/ShortcutsManager.tsx +1 -1
  63. package/shortcuts-manager/ShortcutsManager/utils.tsx +1 -1
  64. package/shortcuts-manager/useSetScopes/useSetScopes.tsx +1 -1
  65. package/shortcuts-manager/useShortcut/useShortcut.tsx +1 -1
  66. package/utils/extractTextStyles.ts +1 -2
  67. package/utils/formatNumberWithMask/formatNumberWithMask.ts +2 -1
  68. package/utils/index.ts +0 -3
  69. package/utils/normalizeToNumberString/normalizeToNumberString.ts +1 -1
  70. package/context-bridge/index.tsx +0 -87
  71. package/fast-context/index.tsx +0 -190
  72. package/hocs/typedMemo.tsx +0 -5
  73. package/hooks/useControlledValue.tsx +0 -84
  74. package/hooks/useLatest.tsx +0 -9
  75. package/hooks/useMergedRefs.ts +0 -14
  76. package/hooks/usePrevious.ts +0 -13
  77. package/hooks/useToggle.tsx +0 -24
  78. package/hooks/useWhatHasUpdated.tsx +0 -48
  79. package/utils/color.ts +0 -22
  80. package/utils/compare/index.ts +0 -54
  81. package/utils/lodash.ts +0 -121
  82. package/utils/repository.ts +0 -53
@@ -1,3 +1,4 @@
1
+ import { useControlledValue } from '@react-native-molecules/utils/hooks';
1
2
  import {
2
3
  type ComponentPropsWithRef,
3
4
  createContext,
@@ -9,7 +10,6 @@ import {
9
10
  } from 'react';
10
11
  import { View } from 'react-native';
11
12
 
12
- import { useControlledValue } from '../../hooks';
13
13
  import { accordionStyles } from './utils';
14
14
 
15
15
  export type Props = Omit<ComponentPropsWithRef<typeof View>, 'children'> & {
@@ -1,3 +1,4 @@
1
+ import { useControlledValue } from '@react-native-molecules/utils/hooks';
1
2
  import {
2
3
  forwardRef,
3
4
  memo,
@@ -9,7 +10,6 @@ import {
9
10
  } from 'react';
10
11
  import { View, type ViewProps } from 'react-native';
11
12
 
12
- import { useControlledValue } from '../../hooks';
13
13
  import type { WithElements } from '../../types';
14
14
  import { extractSubcomponents } from '../../utils/extractSubcomponents';
15
15
  import { AccordionContext } from './Accordion';
@@ -81,6 +81,8 @@ export type Props = Omit<SurfaceProps, 'style'> &
81
81
  disabledPress?: boolean;
82
82
  };
83
83
 
84
+ const emptyObj = {};
85
+
84
86
  const Button = (
85
87
  {
86
88
  disabled = false,
@@ -97,7 +99,7 @@ const Button = (
97
99
  style: styleProp,
98
100
  testID,
99
101
  accessible,
100
- stateLayerProps = {},
102
+ stateLayerProps = emptyObj,
101
103
  elevation: elevationProp,
102
104
  textRelatedStyle,
103
105
  disabledPress,
@@ -1,7 +1,7 @@
1
+ import { useControlledValue } from '@react-native-molecules/utils/hooks';
1
2
  import { forwardRef, memo, useCallback, useMemo } from 'react';
2
3
  import { View } from 'react-native';
3
4
 
4
- import { useControlledValue } from '../../hooks';
5
5
  import { resolveStateVariant } from '../../utils';
6
6
  import { Text } from '../Text';
7
7
  import CheckboxBase from './CheckboxBase';
@@ -50,6 +50,7 @@ const Checkbox = (
50
50
  // @ts-ignore // TODO - fix this
51
51
  state: state as States,
52
52
  isLeading,
53
+ // @ts-ignore // TODO - fix this
53
54
  size,
54
55
  });
55
56
  }
@@ -1,9 +1,9 @@
1
+ import { isNil } from '@react-native-molecules/utils/helpers/lodash';
2
+ import { useLatest } from '@react-native-molecules/utils/hooks';
1
3
  import { type RefObject, useCallback, useEffect, useState } from 'react';
2
4
  import type { BlurEvent, FocusEvent } from 'react-native';
3
5
 
4
- import { useLatest } from '../../hooks';
5
6
  import { endOfDay, format, isValid, parse } from '../../utils/date-fns';
6
- import { isNil } from '../../utils/lodash';
7
7
  import type { ValidRangeType } from '../DatePickerInline';
8
8
  import { useRangeChecker } from '../DatePickerInline/dateUtils';
9
9
 
@@ -1,8 +1,8 @@
1
+ import { useControlledValue } from '@react-native-molecules/utils/hooks';
1
2
  import type { ReactNode } from 'react';
2
3
  import { memo, useCallback, useMemo, useRef, useState } from 'react';
3
4
 
4
5
  import { getRegisteredComponentWithFallback } from '../../core';
5
- import { useControlledValue } from '../../hooks';
6
6
  import type { ValidRangeType } from '../DatePickerInline';
7
7
  import type {
8
8
  DatePickerContextType,
@@ -232,6 +232,8 @@ const datePickerPopoverMonthItemStylesDefault = StyleSheet.create(theme => ({
232
232
  width: '100%',
233
233
  overflow: 'hidden',
234
234
  padding: theme.spacings['0'],
235
+ justifyContent: 'flex-start',
236
+
235
237
  variants: {
236
238
  state: {
237
239
  selected: {
@@ -1,7 +1,7 @@
1
+ import { useControlledValue } from '@react-native-molecules/utils/hooks';
1
2
  import { memo, useCallback } from 'react';
2
3
  import { View, type ViewStyle } from 'react-native';
3
4
 
4
- import { useControlledValue } from '../../hooks';
5
5
  import DatePickerDockedHeader from './DatePickerDockedHeader';
6
6
  import DatePickerInlineBase from './DatePickerInlineBase';
7
7
  import DatePickerInlineHeader from './DatePickerInlineHeader';
@@ -1,7 +1,7 @@
1
+ import { useLatest } from '@react-native-molecules/utils/hooks';
1
2
  import { memo, useCallback, useEffect, useMemo } from 'react';
2
3
  import { StyleSheet, View } from 'react-native';
3
4
 
4
- import { useLatest } from '../../hooks';
5
5
  import { areDatesOnSameDay, dateToUnix, getEndOfDay, getInitialIndex } from './dateUtils';
6
6
  import Month from './Month';
7
7
  import MonthPicker from './MonthPicker';
@@ -1,7 +1,7 @@
1
1
  import { memo, useCallback, useMemo } from 'react';
2
2
  import { type StyleProp, View, type ViewStyle } from 'react-native';
3
3
 
4
- import { useActionState } from '../../hooks/useActionState';
4
+ import { useActionState } from '../../hooks';
5
5
  import { resolveStateVariant } from '../../utils';
6
6
  import { StateLayer } from '../StateLayer';
7
7
  import { Text } from '../Text';
@@ -1,6 +1,6 @@
1
1
  import { setMonth } from 'date-fns';
2
2
  import { memo, useCallback, useMemo } from 'react';
3
- import { FlatList, type FlatListProps, View, type ViewStyle } from 'react-native';
3
+ import { FlatList, View, type ViewStyle } from 'react-native';
4
4
  import { StyleSheet } from 'react-native-unistyles';
5
5
 
6
6
  import { resolveStateVariant } from '../../utils';
@@ -9,7 +9,7 @@ import type { DatePickerLocale } from '../DatePicker/context';
9
9
  import { datePickerMonthItemStyles, datePickerMonthPickerStyles } from '../DatePicker/utils';
10
10
  import { Divider } from '../Divider';
11
11
  import { Icon } from '../Icon';
12
- import { List, type ListContentProcessPropsArgs, useListContextValue } from '../List';
12
+ import { List, type ListItemId, useListContextValue } from '../List';
13
13
  import { Text } from '../Text';
14
14
  import { useDatePickerInlineStore, useDatePickerInlineStoreValue } from './store';
15
15
 
@@ -28,48 +28,22 @@ export default function MonthPicker({ locale }: { locale?: DatePickerLocale }) {
28
28
  );
29
29
 
30
30
  const handleOnChange = useCallback(
31
- (month: number | null) => {
32
- if (month === null) return;
31
+ (value: ListItemId | null) => {
32
+ if (typeof value !== 'number') return;
33
33
  setStore(prev => ({
34
- localDate: setMonth(prev.localDate, month),
34
+ localDate: setMonth(prev.localDate, value),
35
35
  pickerType: undefined,
36
36
  }));
37
37
  },
38
38
  [setStore],
39
39
  );
40
40
 
41
- const processFlatListProps = useCallback(
42
- ({
43
- props,
44
- items,
45
- }: ListContentProcessPropsArgs<
46
- MonthListItem,
47
- Omit<FlatListProps<MonthListItem>, 'children' | 'ref'>
48
- >): FlatListProps<MonthListItem> => ({
49
- ...props,
50
- data: items,
51
- renderItem: ({ item }) => (
52
- <Month
53
- month={item.id}
54
- monthStyles={datePickerMonthPickerStyles.root}
55
- locale={locale}
56
- />
57
- ),
58
- keyExtractor: item => `${item.id}`,
59
- }),
60
- [locale],
61
- );
62
-
63
41
  if (!selectingMonth) {
64
42
  return null;
65
43
  }
66
44
 
67
45
  return (
68
- <List
69
- items={monthItems}
70
- multiple={false}
71
- value={localDate.getMonth()}
72
- onChange={handleOnChange}>
46
+ <List multiple={false} value={localDate.getMonth()} onChange={handleOnChange}>
73
47
  <View
74
48
  style={[
75
49
  StyleSheet.absoluteFill,
@@ -78,10 +52,17 @@ export default function MonthPicker({ locale }: { locale?: DatePickerLocale }) {
78
52
  ]}
79
53
  pointerEvents={selectingMonth ? 'auto' : 'none'}>
80
54
  <Divider />
81
- <List.Content<MonthListItem, typeof FlatList<MonthListItem>>
82
- ContainerComponent={FlatList<MonthListItem>}
55
+ <FlatList<MonthListItem>
83
56
  style={styles.list}
84
- processProps={processFlatListProps}
57
+ data={monthItems}
58
+ renderItem={({ item }) => (
59
+ <Month
60
+ month={item.id}
61
+ monthStyles={datePickerMonthPickerStyles.root}
62
+ locale={locale}
63
+ />
64
+ )}
65
+ keyExtractor={item => `${item.id}`}
85
66
  />
86
67
  </View>
87
68
  </List>
@@ -131,16 +112,16 @@ function MonthPure({
131
112
  accessibilityLabel={String(month)}
132
113
  accessibilityState={accessibilityState}
133
114
  style={monthButtonStyle}
134
- testID={`pick-month-${month}`}
135
- left={
136
- isSelected ? (
115
+ testID={`pick-month-${month}`}>
116
+ <View style={styles.left}>
117
+ {isSelected ? (
137
118
  <View style={styles.checkIconView}>
138
119
  <Icon name="check" size={24} />
139
120
  </View>
140
121
  ) : (
141
122
  <View style={styles.spacer} />
142
- )
143
- }>
123
+ )}
124
+ </View>
144
125
  <View style={datePickerMonthItemStyles.monthInner}>
145
126
  <Text style={datePickerMonthItemStyles.monthLabel} selectable={false}>
146
127
  {monthLabel}
@@ -165,6 +146,9 @@ const styles = StyleSheet.create(theme => ({
165
146
  spacer: {
166
147
  width: 44,
167
148
  },
149
+ left: {
150
+ marginRight: theme.spacings['2'],
151
+ },
168
152
 
169
153
  list: {
170
154
  flex: 1,
@@ -1,3 +1,4 @@
1
+ import { useLatest } from '@react-native-molecules/utils/hooks';
1
2
  import {
2
3
  type CSSProperties,
3
4
  memo,
@@ -10,7 +11,6 @@ import {
10
11
  useState,
11
12
  } from 'react';
12
13
 
13
- import { useLatest } from '../../hooks';
14
14
  import AutoSizer from './AutoSizer';
15
15
  import { beginOffset, estimatedMonthHeight, getInitialIndex, totalMonths } from './dateUtils';
16
16
  import { addMonths, getRealIndex } from './dateUtils';
@@ -1,6 +1,6 @@
1
+ import { useLatest } from '@react-native-molecules/utils/hooks';
1
2
  import { type RefObject, useEffect } from 'react';
2
3
 
3
- import { useLatest } from '../../hooks';
4
4
  import { addMonths, differenceInMonths, getRealIndex, startAtIndex } from './dateUtils';
5
5
 
6
6
  export type SwiperProps = {
@@ -1,12 +1,12 @@
1
1
  import { setYear } from 'date-fns';
2
2
  import { memo, useCallback, useLayoutEffect, useMemo, useRef } from 'react';
3
- import { FlatList, type FlatListProps, StyleSheet, View } from 'react-native';
3
+ import { FlatList, StyleSheet, View } from 'react-native';
4
4
 
5
5
  import { getYearRange, resolveStateVariant } from '../../utils';
6
6
  import { datePickerMonthItemStyles, datePickerMonthPickerStyles } from '../DatePicker/utils';
7
7
  import { Divider } from '../Divider';
8
8
  import { Icon } from '../Icon';
9
- import { List, type ListContentProcessPropsArgs, useListContextValue } from '../List';
9
+ import { List, type ListItemId, useListContextValue } from '../List';
10
10
  import { Text } from '../Text';
11
11
  import { useDatePickerInlineStore } from './store';
12
12
  import { datePickerYearItemStyles, datePickerYearPickerStyles } from './utils';
@@ -69,10 +69,10 @@ function YearPickerGrid() {
69
69
  }, [selectingYear]);
70
70
 
71
71
  const handleOnChange = useCallback(
72
- (year: number | null) => {
73
- if (year === null) return;
72
+ (value: ListItemId | null) => {
73
+ if (typeof value !== 'number') return;
74
74
  setStore(prev => ({
75
- localDate: setYear(prev.localDate, year),
75
+ localDate: setYear(prev.localDate, value),
76
76
  pickerType: undefined,
77
77
  }));
78
78
  },
@@ -88,48 +88,26 @@ function YearPickerGrid() {
88
88
  [],
89
89
  );
90
90
 
91
- const processGridFlatListProps = useCallback(
92
- ({
93
- props,
94
- items,
95
- isEmpty,
96
- emptyState,
97
- }: ListContentProcessPropsArgs<
98
- YearListItem,
99
- Omit<FlatListProps<YearListItem>, 'children' | 'ref'>
100
- >): FlatListProps<YearListItem> => ({
101
- ...props,
102
- data: items,
103
- numColumns: NUM_COLUMNS,
104
- contentContainerStyle: gridStyles.grid,
105
- columnWrapperStyle: gridStyles.row,
106
- renderItem: ({ item }) => (
107
- <View style={gridStyles.cell}>
108
- <YearPill year={item.id} yearStyles={yearStyle} />
109
- </View>
110
- ),
111
- keyExtractor: item => `${item.id}`,
112
- getItemLayout: getRowLayout,
113
- initialScrollIndex: Math.floor(initialScrollOffset / GRID_ITEM_HEIGHT),
114
- removeClippedSubviews: true,
115
- ListEmptyComponent: isEmpty
116
- ? function GridListEmpty() {
117
- return <>{emptyState}</>;
118
- }
119
- : undefined,
120
- }),
121
- [getRowLayout, initialScrollOffset, yearStyle],
122
- );
123
-
124
91
  return (
125
- <List items={yearItems} multiple={false} value={selectedYear} onChange={handleOnChange}>
92
+ <List multiple={false} value={selectedYear} onChange={handleOnChange}>
126
93
  <View style={containerStyle} pointerEvents={selectingYear ? 'auto' : 'none'}>
127
94
  <Divider />
128
- <List.Content<YearListItem, typeof FlatList<YearListItem>>
95
+ <FlatList<YearListItem>
129
96
  ref={flatListRef}
130
- ContainerComponent={FlatList<YearListItem>}
131
97
  style={gridStyles.list}
132
- processProps={processGridFlatListProps}
98
+ data={yearItems}
99
+ numColumns={NUM_COLUMNS}
100
+ contentContainerStyle={gridStyles.grid}
101
+ columnWrapperStyle={gridStyles.row}
102
+ renderItem={({ item }) => (
103
+ <View style={gridStyles.cell}>
104
+ <YearPill year={item.id} yearStyles={yearStyle} />
105
+ </View>
106
+ )}
107
+ keyExtractor={item => `${item.id}`}
108
+ getItemLayout={getRowLayout}
109
+ initialScrollIndex={Math.floor(initialScrollOffset / GRID_ITEM_HEIGHT)}
110
+ removeClippedSubviews
133
111
  />
134
112
  </View>
135
113
  </List>
@@ -149,17 +127,18 @@ function YearPillPure({ year, yearStyles }: { year: number; yearStyles: Record<s
149
127
  return (
150
128
  <List.Item
151
129
  value={year}
152
- contentStyle={datePickerYearItemStyles.content}
153
130
  accessibilityRole="button"
154
131
  accessibilityLabel={String(year)}
155
132
  style={[yearStyles, datePickerYearItemStyles.yearButton]}
156
133
  testID={`pick-year-${year}`}>
157
- <Text
158
- typescale="bodyLarge"
159
- style={datePickerYearItemStyles.yearLabel}
160
- selectable={false}>
161
- {year}
162
- </Text>
134
+ <View style={datePickerYearItemStyles.content}>
135
+ <Text
136
+ typescale="bodyLarge"
137
+ style={datePickerYearItemStyles.yearLabel}
138
+ selectable={false}>
139
+ {year}
140
+ </Text>
141
+ </View>
163
142
  </List.Item>
164
143
  );
165
144
  }
@@ -186,10 +165,10 @@ function YearPickerList() {
186
165
  }, [selectedYear, years]);
187
166
 
188
167
  const handleOnChange = useCallback(
189
- (year: number | null) => {
190
- if (year === null) return;
168
+ (value: ListItemId | null) => {
169
+ if (typeof value !== 'number') return;
191
170
  setStore(prev => ({
192
- localDate: setYear(prev.localDate, year),
171
+ localDate: setYear(prev.localDate, value),
193
172
  pickerType: undefined,
194
173
  }));
195
174
  },
@@ -205,34 +184,19 @@ function YearPickerList() {
205
184
  [],
206
185
  );
207
186
 
208
- const processFlatListProps = useCallback(
209
- ({
210
- props,
211
- items,
212
- }: ListContentProcessPropsArgs<
213
- YearListItem,
214
- Omit<FlatListProps<YearListItem>, 'children' | 'ref'>
215
- >): FlatListProps<YearListItem> => ({
216
- ...props,
217
- data: items,
218
- renderItem: ({ item }) => <YearRow year={item.id} />,
219
- keyExtractor: item => `${item.id}`,
220
- initialScrollIndex,
221
- getItemLayout,
222
- }),
223
- [getItemLayout, initialScrollIndex],
224
- );
225
-
226
187
  if (!selectingYear) return null;
227
188
 
228
189
  return (
229
- <List items={yearItems} multiple={false} value={selectedYear} onChange={handleOnChange}>
190
+ <List multiple={false} value={selectedYear} onChange={handleOnChange}>
230
191
  <View style={[StyleSheet.absoluteFill, listStyles.root]} pointerEvents="auto">
231
192
  <Divider />
232
- <List.Content<YearListItem, typeof FlatList<YearListItem>>
233
- ContainerComponent={FlatList<YearListItem>}
193
+ <FlatList<YearListItem>
234
194
  style={listStyles.list}
235
- processProps={processFlatListProps}
195
+ data={yearItems}
196
+ renderItem={({ item }) => <YearRow year={item.id} />}
197
+ keyExtractor={item => `${item.id}`}
198
+ initialScrollIndex={initialScrollIndex}
199
+ getItemLayout={getItemLayout}
236
200
  />
237
201
  </View>
238
202
  </List>
@@ -255,16 +219,16 @@ function YearRowPure({ year }: { year: number }) {
255
219
  accessibilityRole="button"
256
220
  accessibilityLabel={String(year)}
257
221
  style={datePickerMonthItemStyles.monthButton}
258
- testID={`pick-year-${year}`}
259
- left={
260
- isSelected ? (
222
+ testID={`pick-year-${year}`}>
223
+ <View style={listStyles.left}>
224
+ {isSelected ? (
261
225
  <View style={listStyles.checkIconView}>
262
226
  <Icon name="check" size={24} />
263
227
  </View>
264
228
  ) : (
265
229
  <View style={listStyles.spacer} />
266
- )
267
- }>
230
+ )}
231
+ </View>
268
232
  <View style={datePickerMonthItemStyles.monthInner}>
269
233
  <Text style={datePickerMonthItemStyles.monthLabel} selectable={false}>
270
234
  {year}
@@ -313,4 +277,5 @@ const listStyles = StyleSheet.create({
313
277
  list: { flex: 1 },
314
278
  checkIconView: { marginLeft: 16 },
315
279
  spacer: { width: 44 },
280
+ left: { marginRight: 8 },
316
281
  });
@@ -1,6 +1,6 @@
1
+ import { useLatest } from '@react-native-molecules/utils/hooks';
1
2
  import { useCallback } from 'react';
2
3
 
3
- import { useLatest } from '../../hooks';
4
4
  import type { CalendarDate, CalendarDates, ValidRangeType } from './types';
5
5
 
6
6
  export type DisableWeekDaysType = number[];
@@ -1,4 +1,5 @@
1
- import { createFastContext } from '../../fast-context';
1
+ import { createFastContext } from '@react-native-molecules/utils/fast-context';
2
+
2
3
  import { registerPortalContext } from '../Portal/Portal';
3
4
 
4
5
  export type Store = {
@@ -1,11 +1,10 @@
1
1
  export {
2
2
  Divider,
3
+ type DividerProps,
3
4
  horizontalDividerStyles,
4
5
  horizontalDividerStylesDefault,
6
+ type Props,
5
7
  verticalDividerStyles,
6
8
  verticalDividerStylesDefault,
7
- type DividerProps,
8
- type Props,
9
9
  } from './Divider';
10
-
11
10
  export { default } from './Divider';
@@ -1,8 +1,8 @@
1
+ import { isNil } from '@react-native-molecules/utils/helpers/lodash';
1
2
  import { Children, cloneElement, forwardRef, memo, type ReactElement, useMemo } from 'react';
2
3
  import { View, type ViewProps, type ViewStyle } from 'react-native';
3
4
 
4
5
  import { extractPropertiesFromStyles } from '../../utils/extractPropertiesFromStyles';
5
- import { isNil } from '../../utils/lodash';
6
6
  import { elementGroupStyles } from './utils';
7
7
 
8
8
  export enum Orientation {
@@ -1,6 +1,6 @@
1
+ import { useControlledValue } from '@react-native-molecules/utils/hooks';
1
2
  import { memo, useCallback, useMemo } from 'react';
2
3
 
3
- import useControlledValue from '../../hooks/useControlledValue';
4
4
  import useFilePicker from '../../hooks/useFilePicker';
5
5
  import type { DocumentPickerOptions, DocumentResult } from '../../utils/DocumentPicker';
6
6
  import { IconButton } from '../IconButton';
@@ -1,5 +1,6 @@
1
1
  // import { textFactory } from '../Text/textFactory';
2
- import { memoize } from '../../utils/lodash';
2
+ import { memoize } from '@react-native-molecules/utils/helpers/lodash';
3
+
3
4
  import type { IconType } from './types';
4
5
 
5
6
  const customIcons: any = {};
@@ -6,16 +6,20 @@ import {
6
6
  type ViewProps,
7
7
  } from 'react-native';
8
8
 
9
- import { useActionState } from '../../hooks/useActionState';
9
+ import { useActionState } from '../../hooks';
10
10
  import { resolveStateVariant } from '../../utils';
11
11
  import { Icon, type IconProps, type IconType } from '../Icon';
12
12
  import CrossFadeIcon from '../Icon/CrossFadeIcon';
13
13
  import { StateLayer } from '../StateLayer';
14
14
  import { TouchableRipple, type TouchableRippleProps } from '../TouchableRipple';
15
- import type { IconButtonVariant } from './types';
15
+ import type { IconButtonShape, IconButtonVariant, IconButtonWidth } from './types';
16
16
  import { defaultStyles, iconButtonSizeToIconSizeMap } from './utils';
17
17
 
18
- const whiteSpace = 12;
18
+ const ICON_BUTTON_MIN_CONTAINER_SIZE = 32;
19
+ const ICON_BUTTON_CONTAINER_PADDING = 16;
20
+ const M3_ICON_BUTTON_NARROW_WIDTH_ADJUSTMENT = -8;
21
+ const M3_ICON_BUTTON_WIDE_WIDTH_ADJUSTMENT = 12;
22
+ const M3_ICON_BUTTON_SQUARE_CORNER_RADIUS = 12;
19
23
 
20
24
  export type Props = Omit<TouchableRippleProps, 'children' | 'style'> & {
21
25
  /**
@@ -26,6 +30,14 @@ export type Props = Omit<TouchableRippleProps, 'children' | 'style'> & {
26
30
  * Mode of the icon button. By default there is no specified mode - only pressable icon will be rendered.
27
31
  */
28
32
  variant?: IconButtonVariant;
33
+ /**
34
+ * Container shape. Material 3 supports round and square icon buttons.
35
+ */
36
+ shape?: IconButtonShape;
37
+ /**
38
+ * Container width option. `default` maps to Material 3's uniform width.
39
+ */
40
+ width?: IconButtonWidth;
29
41
  /**
30
42
  * Whether icon button is selected. A selected button receives alternative combination of icon and container colors.
31
43
  */
@@ -85,6 +97,8 @@ const IconButton = (
85
97
  selected = false,
86
98
  animated = false,
87
99
  variant = 'default',
100
+ shape = 'round',
101
+ width = 'default',
88
102
  style,
89
103
  testID,
90
104
  stateLayerProps = emptyObject,
@@ -126,33 +140,45 @@ const IconButton = (
126
140
  } = useMemo(() => {
127
141
  const iconSizeInNum =
128
142
  iconButtonSizeToIconSizeMap[size as keyof typeof iconButtonSizeToIconSizeMap] ??
129
- (typeof size === 'number' && size ? (size as number) : undefined);
143
+ (typeof size === 'number' && size ? (size as number) : 24);
144
+ const containerHeight = Math.max(
145
+ ICON_BUTTON_MIN_CONTAINER_SIZE,
146
+ iconSizeInNum + ICON_BUTTON_CONTAINER_PADDING,
147
+ );
148
+ const widthAdjustment =
149
+ width === 'narrow'
150
+ ? M3_ICON_BUTTON_NARROW_WIDTH_ADJUSTMENT
151
+ : width === 'wide'
152
+ ? M3_ICON_BUTTON_WIDE_WIDTH_ADJUSTMENT
153
+ : 0;
154
+ const containerWidth = Math.max(iconSizeInNum, containerHeight + widthAdjustment);
155
+ const borderRadius =
156
+ shape === 'round' ? containerHeight / 2 : M3_ICON_BUTTON_SQUARE_CORNER_RADIUS;
130
157
 
131
158
  return {
132
159
  iconColor: _iconColor,
133
160
  iconSize: iconSizeInNum,
134
161
  containerStyle: [
135
- iconSizeInNum
136
- ? {
137
- width: iconSizeInNum + whiteSpace,
138
- height: iconSizeInNum + whiteSpace,
139
- }
140
- : {},
141
162
  defaultStyles.root,
163
+ {
164
+ width: containerWidth,
165
+ height: containerHeight,
166
+ borderRadius,
167
+ },
142
168
  style,
143
169
  ],
144
170
  iconStyle: [defaultStyles.icon, iconStyleProp],
145
171
  // accessibilityTraits: disabled ? ['button', 'disabled'] : 'button',
146
172
  accessibilityState: { disabled },
147
- stateLayerStyle: [defaultStyles.stateLayer, stateLayerProps?.style],
173
+ stateLayerStyle: [defaultStyles.stateLayer, { borderRadius }, stateLayerProps?.style],
148
174
  };
149
175
  // eslint-disable-next-line react-hooks/exhaustive-deps
150
- }, [_iconColor, disabled, size, stateLayerProps?.style, style, state, variant]);
176
+ }, [_iconColor, disabled, shape, size, stateLayerProps?.style, style, state, variant, width]);
151
177
 
152
178
  return (
153
179
  <TouchableRipple
154
180
  borderless
155
- centered
181
+ centered={shape === 'round' && width === 'default'}
156
182
  onPress={onPress}
157
183
  rippleAlpha={0.12}
158
184
  accessibilityLabel={accessibilityLabel}
@@ -4,4 +4,5 @@ import IconButtonDefault from './IconButton';
4
4
  export const IconButton = getRegisteredComponentWithFallback('IconButton', IconButtonDefault);
5
5
 
6
6
  export type { Props as IconButtonProps } from './IconButton';
7
+ export type * from './types';
7
8
  export { defaultStyles } from './utils';
@@ -1 +1,3 @@
1
1
  export type IconButtonVariant = 'default' | 'outlined' | 'contained' | 'contained-tonal';
2
+ export type IconButtonShape = 'round' | 'square';
3
+ export type IconButtonWidth = 'narrow' | 'default' | 'wide';