@onlynative/components 0.1.0-alpha.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 (87) hide show
  1. package/README.md +99 -0
  2. package/dist/appbar/index.d.ts +71 -0
  3. package/dist/appbar/index.js +952 -0
  4. package/dist/button/index.d.ts +41 -0
  5. package/dist/button/index.js +454 -0
  6. package/dist/card/index.d.ts +31 -0
  7. package/dist/card/index.js +264 -0
  8. package/dist/checkbox/index.d.ts +25 -0
  9. package/dist/checkbox/index.js +291 -0
  10. package/dist/chip/index.d.ts +62 -0
  11. package/dist/chip/index.js +452 -0
  12. package/dist/icon-button/index.d.ts +10 -0
  13. package/dist/icon-button/index.js +575 -0
  14. package/dist/index.d.ts +19 -0
  15. package/dist/index.js +3374 -0
  16. package/dist/layout/index.d.ts +98 -0
  17. package/dist/layout/index.js +282 -0
  18. package/dist/list/index.d.ts +60 -0
  19. package/dist/list/index.js +300 -0
  20. package/dist/radio/index.d.ts +25 -0
  21. package/dist/radio/index.js +250 -0
  22. package/dist/switch/index.d.ts +37 -0
  23. package/dist/switch/index.js +315 -0
  24. package/dist/text-field/index.d.ts +52 -0
  25. package/dist/text-field/index.js +496 -0
  26. package/dist/types-D3hlyvz-.d.ts +51 -0
  27. package/dist/typography/index.d.ts +28 -0
  28. package/dist/typography/index.js +69 -0
  29. package/package.json +166 -0
  30. package/src/appbar/AppBar.tsx +302 -0
  31. package/src/appbar/index.ts +2 -0
  32. package/src/appbar/styles.ts +92 -0
  33. package/src/appbar/types.ts +67 -0
  34. package/src/button/Button.tsx +130 -0
  35. package/src/button/index.ts +2 -0
  36. package/src/button/styles.ts +288 -0
  37. package/src/button/types.ts +42 -0
  38. package/src/card/Card.tsx +69 -0
  39. package/src/card/index.ts +2 -0
  40. package/src/card/styles.ts +151 -0
  41. package/src/card/types.ts +27 -0
  42. package/src/checkbox/Checkbox.tsx +109 -0
  43. package/src/checkbox/index.ts +2 -0
  44. package/src/checkbox/styles.ts +155 -0
  45. package/src/checkbox/types.ts +20 -0
  46. package/src/chip/Chip.tsx +182 -0
  47. package/src/chip/index.ts +2 -0
  48. package/src/chip/styles.ts +240 -0
  49. package/src/chip/types.ts +58 -0
  50. package/src/icon-button/IconButton.tsx +358 -0
  51. package/src/icon-button/index.ts +6 -0
  52. package/src/icon-button/styles.ts +259 -0
  53. package/src/icon-button/types.ts +55 -0
  54. package/src/index.ts +51 -0
  55. package/src/layout/Box.tsx +99 -0
  56. package/src/layout/Column.tsx +16 -0
  57. package/src/layout/Grid.tsx +49 -0
  58. package/src/layout/Layout.tsx +81 -0
  59. package/src/layout/Row.tsx +22 -0
  60. package/src/layout/index.ts +13 -0
  61. package/src/layout/resolveSpacing.ts +11 -0
  62. package/src/layout/types.ts +82 -0
  63. package/src/list/List.tsx +17 -0
  64. package/src/list/ListDivider.tsx +20 -0
  65. package/src/list/ListItem.tsx +128 -0
  66. package/src/list/index.ts +9 -0
  67. package/src/list/styles.ts +132 -0
  68. package/src/list/types.ts +54 -0
  69. package/src/radio/Radio.tsx +103 -0
  70. package/src/radio/index.ts +2 -0
  71. package/src/radio/styles.ts +139 -0
  72. package/src/radio/types.ts +20 -0
  73. package/src/switch/Switch.tsx +118 -0
  74. package/src/switch/index.ts +2 -0
  75. package/src/switch/styles.ts +172 -0
  76. package/src/switch/types.ts +32 -0
  77. package/src/test-utils/render-with-theme.tsx +13 -0
  78. package/src/text-field/TextField.tsx +298 -0
  79. package/src/text-field/index.ts +2 -0
  80. package/src/text-field/styles.ts +240 -0
  81. package/src/text-field/types.ts +49 -0
  82. package/src/typography/Typography.tsx +65 -0
  83. package/src/typography/index.ts +3 -0
  84. package/src/typography/types.ts +17 -0
  85. package/src/utils/color.ts +64 -0
  86. package/src/utils/elevation.ts +33 -0
  87. package/src/utils/rtl.ts +19 -0
@@ -0,0 +1,240 @@
1
+ import { StyleSheet } from 'react-native'
2
+ import type { Theme } from '@onlynative/core'
3
+
4
+ import type { ChipVariant } from './types'
5
+ import { alphaColor, blendColor } from '../utils/color'
6
+ import { elevationStyle } from '../utils/elevation'
7
+
8
+ interface VariantColors {
9
+ backgroundColor: string
10
+ textColor: string
11
+ borderColor: string
12
+ borderWidth: number
13
+ hoveredBackgroundColor: string
14
+ pressedBackgroundColor: string
15
+ disabledBackgroundColor: string
16
+ disabledTextColor: string
17
+ disabledBorderColor: string
18
+ }
19
+
20
+ function getVariantColors(
21
+ theme: Theme,
22
+ variant: ChipVariant,
23
+ elevated: boolean,
24
+ selected: boolean,
25
+ ): VariantColors {
26
+ const disabledContainerColor = alphaColor(theme.colors.onSurface, 0.12)
27
+ const disabledLabelColor = alphaColor(theme.colors.onSurface, 0.38)
28
+ const disabledOutlineColor = alphaColor(theme.colors.onSurface, 0.12)
29
+
30
+ // Filter chip — selected state
31
+ if (variant === 'filter' && selected) {
32
+ return {
33
+ backgroundColor: theme.colors.secondaryContainer,
34
+ textColor: theme.colors.onSecondaryContainer,
35
+ borderColor: 'transparent',
36
+ borderWidth: 0,
37
+ hoveredBackgroundColor: blendColor(
38
+ theme.colors.secondaryContainer,
39
+ theme.colors.onSecondaryContainer,
40
+ theme.stateLayer.hoveredOpacity,
41
+ ),
42
+ pressedBackgroundColor: blendColor(
43
+ theme.colors.secondaryContainer,
44
+ theme.colors.onSecondaryContainer,
45
+ theme.stateLayer.pressedOpacity,
46
+ ),
47
+ disabledBackgroundColor: disabledContainerColor,
48
+ disabledTextColor: disabledLabelColor,
49
+ disabledBorderColor: 'transparent',
50
+ }
51
+ }
52
+
53
+ // Elevated variants (assist, filter unselected, suggestion)
54
+ // Input variant ignores elevated — always outlined
55
+ if (elevated && variant !== 'input') {
56
+ const textColor =
57
+ variant === 'assist'
58
+ ? theme.colors.onSurface
59
+ : theme.colors.onSurfaceVariant
60
+ return {
61
+ backgroundColor: theme.colors.surfaceContainerLow,
62
+ textColor,
63
+ borderColor: 'transparent',
64
+ borderWidth: 0,
65
+ hoveredBackgroundColor: blendColor(
66
+ theme.colors.surfaceContainerLow,
67
+ textColor,
68
+ theme.stateLayer.hoveredOpacity,
69
+ ),
70
+ pressedBackgroundColor: blendColor(
71
+ theme.colors.surfaceContainerLow,
72
+ textColor,
73
+ theme.stateLayer.pressedOpacity,
74
+ ),
75
+ disabledBackgroundColor: disabledContainerColor,
76
+ disabledTextColor: disabledLabelColor,
77
+ disabledBorderColor: 'transparent',
78
+ }
79
+ }
80
+
81
+ // Flat (outlined) variants
82
+ const textColor =
83
+ variant === 'assist'
84
+ ? theme.colors.onSurface
85
+ : theme.colors.onSurfaceVariant
86
+
87
+ return {
88
+ backgroundColor: theme.colors.surface,
89
+ textColor,
90
+ borderColor: theme.colors.outline,
91
+ borderWidth: 1,
92
+ hoveredBackgroundColor: blendColor(
93
+ theme.colors.surface,
94
+ textColor,
95
+ theme.stateLayer.hoveredOpacity,
96
+ ),
97
+ pressedBackgroundColor: blendColor(
98
+ theme.colors.surface,
99
+ textColor,
100
+ theme.stateLayer.pressedOpacity,
101
+ ),
102
+ disabledBackgroundColor: disabledContainerColor,
103
+ disabledTextColor: disabledLabelColor,
104
+ disabledBorderColor: disabledOutlineColor,
105
+ }
106
+ }
107
+
108
+ function applyColorOverrides(
109
+ theme: Theme,
110
+ colors: VariantColors,
111
+ containerColor?: string,
112
+ contentColor?: string,
113
+ ): VariantColors {
114
+ if (!containerColor && !contentColor) return colors
115
+
116
+ const result = { ...colors }
117
+
118
+ if (contentColor) {
119
+ result.textColor = contentColor
120
+ }
121
+
122
+ if (containerColor) {
123
+ const overlay = contentColor ?? colors.textColor
124
+ result.backgroundColor = containerColor
125
+ result.borderColor = containerColor
126
+ result.hoveredBackgroundColor = blendColor(
127
+ containerColor,
128
+ overlay,
129
+ theme.stateLayer.hoveredOpacity,
130
+ )
131
+ result.pressedBackgroundColor = blendColor(
132
+ containerColor,
133
+ overlay,
134
+ theme.stateLayer.pressedOpacity,
135
+ )
136
+ } else if (contentColor) {
137
+ if (colors.backgroundColor === 'transparent') {
138
+ result.hoveredBackgroundColor = alphaColor(
139
+ contentColor,
140
+ theme.stateLayer.hoveredOpacity,
141
+ )
142
+ result.pressedBackgroundColor = alphaColor(
143
+ contentColor,
144
+ theme.stateLayer.pressedOpacity,
145
+ )
146
+ } else {
147
+ result.hoveredBackgroundColor = blendColor(
148
+ colors.backgroundColor,
149
+ contentColor,
150
+ theme.stateLayer.hoveredOpacity,
151
+ )
152
+ result.pressedBackgroundColor = blendColor(
153
+ colors.backgroundColor,
154
+ contentColor,
155
+ theme.stateLayer.pressedOpacity,
156
+ )
157
+ }
158
+ }
159
+
160
+ return result
161
+ }
162
+
163
+ export function createStyles(
164
+ theme: Theme,
165
+ variant: ChipVariant,
166
+ elevated: boolean,
167
+ selected: boolean,
168
+ hasLeadingContent: boolean,
169
+ hasTrailingContent: boolean,
170
+ containerColor?: string,
171
+ contentColor?: string,
172
+ ) {
173
+ const baseColors = getVariantColors(theme, variant, elevated, selected)
174
+ const colors = applyColorOverrides(
175
+ theme,
176
+ baseColors,
177
+ containerColor,
178
+ contentColor,
179
+ )
180
+ const labelStyle = theme.typography.labelLarge
181
+ const elevationLevel0 = elevationStyle(theme.elevation.level0)
182
+ const elevationLevel1 = elevationStyle(theme.elevation.level1)
183
+ const elevationLevel2 = elevationStyle(theme.elevation.level2)
184
+ const isElevated = elevated && variant !== 'input'
185
+ const baseElevation = isElevated ? elevationLevel1 : elevationLevel0
186
+
187
+ return StyleSheet.create({
188
+ container: {
189
+ alignSelf: 'flex-start',
190
+ alignItems: 'center',
191
+ flexDirection: 'row',
192
+ height: 32,
193
+ paddingStart: hasLeadingContent ? 8 : 16,
194
+ paddingEnd: hasTrailingContent ? 8 : 16,
195
+ borderRadius: theme.shape.cornerSmall,
196
+ backgroundColor: colors.backgroundColor,
197
+ borderColor: colors.borderColor,
198
+ borderWidth: colors.borderWidth,
199
+ cursor: 'pointer',
200
+ ...baseElevation,
201
+ },
202
+ hoveredContainer: {
203
+ backgroundColor: colors.hoveredBackgroundColor,
204
+ ...(isElevated ? elevationLevel2 : undefined),
205
+ },
206
+ pressedContainer: {
207
+ backgroundColor: colors.pressedBackgroundColor,
208
+ },
209
+ disabledContainer: {
210
+ backgroundColor: colors.disabledBackgroundColor,
211
+ borderColor: colors.disabledBorderColor,
212
+ cursor: 'auto',
213
+ ...elevationLevel0,
214
+ },
215
+ label: {
216
+ fontFamily: labelStyle.fontFamily,
217
+ fontSize: labelStyle.fontSize,
218
+ lineHeight: labelStyle.lineHeight,
219
+ fontWeight: labelStyle.fontWeight,
220
+ letterSpacing: labelStyle.letterSpacing,
221
+ color: colors.textColor,
222
+ },
223
+ disabledLabel: {
224
+ color: colors.disabledTextColor,
225
+ },
226
+ leadingIcon: {
227
+ marginEnd: theme.spacing.sm,
228
+ },
229
+ avatar: {
230
+ marginEnd: theme.spacing.sm,
231
+ width: 24,
232
+ height: 24,
233
+ borderRadius: 12,
234
+ overflow: 'hidden' as const,
235
+ },
236
+ closeButton: {
237
+ marginStart: theme.spacing.sm,
238
+ },
239
+ })
240
+ }
@@ -0,0 +1,58 @@
1
+ import type MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons'
2
+ import type { ComponentProps, ReactNode } from 'react'
3
+ import type { PressableProps, StyleProp, TextStyle } from 'react-native'
4
+
5
+ /** Visual variant of the chip following Material Design 3 chip types. */
6
+ export type ChipVariant = 'assist' | 'filter' | 'input' | 'suggestion'
7
+
8
+ export interface ChipProps extends Omit<PressableProps, 'children'> {
9
+ /** Text label rendered inside the chip. */
10
+ children: string
11
+ /**
12
+ * Chip type variant. Controls appearance, allowed interactions, and icon behavior.
13
+ * @default 'assist'
14
+ */
15
+ variant?: ChipVariant
16
+ /**
17
+ * Whether the chip uses an elevated surface instead of an outline border.
18
+ * Available on `assist`, `filter`, and `suggestion` variants.
19
+ * Ignored on `input` variant (always outlined).
20
+ * @default false
21
+ */
22
+ elevated?: boolean
23
+ /**
24
+ * Whether the chip is in a selected (toggled-on) state.
25
+ * Only meaningful for the `filter` variant. Ignored by other variants.
26
+ */
27
+ selected?: boolean
28
+ /** Name of a MaterialCommunityIcons icon to show before the label. */
29
+ leadingIcon?: ComponentProps<typeof MaterialCommunityIcons>['name']
30
+ /**
31
+ * Size of the leading icon in dp.
32
+ * @default 18
33
+ */
34
+ iconSize?: number
35
+ /**
36
+ * Custom avatar content (e.g. a small Image or View) to render before the label.
37
+ * Only applicable to the `input` variant. Takes precedence over `leadingIcon`.
38
+ */
39
+ avatar?: ReactNode
40
+ /**
41
+ * Callback fired when the close/remove icon is pressed.
42
+ * When provided, renders a trailing close icon.
43
+ * Only renders on `input` and `filter` (when selected) variants.
44
+ */
45
+ onClose?: () => void
46
+ /**
47
+ * Override the container (background) color.
48
+ * State-layer colors (hover, press) are derived automatically.
49
+ */
50
+ containerColor?: string
51
+ /**
52
+ * Override the content (label and icon) color.
53
+ * State-layer colors are derived automatically when no containerColor is set.
54
+ */
55
+ contentColor?: string
56
+ /** Additional style applied to the label text. */
57
+ labelStyle?: StyleProp<TextStyle>
58
+ }
@@ -0,0 +1,358 @@
1
+ import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons'
2
+ import { useMemo } from 'react'
3
+ import { Pressable } from 'react-native'
4
+ import type { StyleProp, ViewStyle } from 'react-native'
5
+ import { useTheme } from '@onlynative/core'
6
+
7
+ import { createStyles } from './styles'
8
+ import type {
9
+ IconButtonProps,
10
+ IconButtonSize,
11
+ IconButtonVariant,
12
+ } from './types'
13
+ import { alphaColor, blendColor } from '../utils/color'
14
+
15
+ function getIconColor(
16
+ variant: IconButtonVariant,
17
+ theme: ReturnType<typeof useTheme>,
18
+ disabled: boolean,
19
+ isToggle: boolean,
20
+ selected: boolean,
21
+ ): string {
22
+ if (disabled) {
23
+ return alphaColor(theme.colors.onSurface, 0.38)
24
+ }
25
+
26
+ if (isToggle) {
27
+ if (variant === 'filled') {
28
+ return selected ? theme.colors.onPrimary : theme.colors.primary
29
+ }
30
+
31
+ if (variant === 'tonal') {
32
+ return selected
33
+ ? theme.colors.onSecondaryContainer
34
+ : theme.colors.onSurfaceVariant
35
+ }
36
+
37
+ if (variant === 'outlined') {
38
+ return selected
39
+ ? theme.colors.inverseOnSurface
40
+ : theme.colors.onSurfaceVariant
41
+ }
42
+
43
+ return selected ? theme.colors.primary : theme.colors.onSurfaceVariant
44
+ }
45
+
46
+ if (variant === 'filled') {
47
+ return theme.colors.onPrimary
48
+ }
49
+
50
+ if (variant === 'tonal') {
51
+ return theme.colors.onSecondaryContainer
52
+ }
53
+
54
+ return theme.colors.onSurfaceVariant
55
+ }
56
+
57
+ function getColorStyle(
58
+ styles: ReturnType<typeof createStyles>,
59
+ variant: IconButtonVariant,
60
+ isToggle: boolean,
61
+ selected: boolean,
62
+ ) {
63
+ if (isToggle) {
64
+ if (variant === 'tonal') {
65
+ return selected
66
+ ? styles.colorTonalToggleSelected
67
+ : styles.colorTonalToggleUnselected
68
+ }
69
+
70
+ if (variant === 'outlined') {
71
+ return selected
72
+ ? styles.colorOutlinedToggleSelected
73
+ : styles.colorOutlined
74
+ }
75
+
76
+ if (variant === 'standard') {
77
+ return selected
78
+ ? styles.colorStandardToggleSelected
79
+ : styles.colorStandard
80
+ }
81
+
82
+ return selected
83
+ ? styles.colorFilledToggleSelected
84
+ : styles.colorFilledToggleUnselected
85
+ }
86
+
87
+ if (variant === 'tonal') {
88
+ return styles.colorTonal
89
+ }
90
+
91
+ if (variant === 'outlined') {
92
+ return styles.colorOutlined
93
+ }
94
+
95
+ if (variant === 'standard') {
96
+ return styles.colorStandard
97
+ }
98
+
99
+ return styles.colorFilled
100
+ }
101
+
102
+ function getSizeStyle(
103
+ styles: ReturnType<typeof createStyles>,
104
+ size: IconButtonSize,
105
+ ) {
106
+ if (size === 'small') {
107
+ return styles.sizeSmall
108
+ }
109
+
110
+ if (size === 'large') {
111
+ return styles.sizeLarge
112
+ }
113
+
114
+ return styles.sizeMedium
115
+ }
116
+
117
+ function getIconPixelSize(size: IconButtonSize): number {
118
+ if (size === 'small') {
119
+ return 18
120
+ }
121
+
122
+ if (size === 'large') {
123
+ return 28
124
+ }
125
+
126
+ return 24
127
+ }
128
+
129
+ function getDefaultHitSlop(size: IconButtonSize): number {
130
+ if (size === 'small') {
131
+ return 8
132
+ }
133
+
134
+ if (size === 'large') {
135
+ return 0
136
+ }
137
+
138
+ return 4
139
+ }
140
+
141
+ function getHoveredStyle(
142
+ styles: ReturnType<typeof createStyles>,
143
+ variant: IconButtonVariant,
144
+ isToggle: boolean,
145
+ selected: boolean,
146
+ ) {
147
+ if (isToggle) {
148
+ if (variant === 'tonal') {
149
+ return selected
150
+ ? styles.hoveredTonalToggleSelected
151
+ : styles.hoveredTonalToggleUnselected
152
+ }
153
+
154
+ if (variant === 'outlined') {
155
+ return selected
156
+ ? styles.hoveredOutlinedToggleSelected
157
+ : styles.hoveredOutlinedToggleUnselected
158
+ }
159
+
160
+ if (variant === 'standard') {
161
+ return selected
162
+ ? styles.hoveredStandardToggleSelected
163
+ : styles.hoveredStandardToggleUnselected
164
+ }
165
+
166
+ return selected
167
+ ? styles.hoveredFilledToggleSelected
168
+ : styles.hoveredFilledToggleUnselected
169
+ }
170
+
171
+ if (variant === 'tonal') {
172
+ return styles.hoveredTonal
173
+ }
174
+
175
+ if (variant === 'outlined') {
176
+ return styles.hoveredOutlined
177
+ }
178
+
179
+ if (variant === 'standard') {
180
+ return styles.hoveredStandard
181
+ }
182
+
183
+ return styles.hoveredFilled
184
+ }
185
+
186
+ function getPressedStyle(
187
+ styles: ReturnType<typeof createStyles>,
188
+ variant: IconButtonVariant,
189
+ isToggle: boolean,
190
+ selected: boolean,
191
+ ) {
192
+ if (isToggle) {
193
+ if (variant === 'tonal') {
194
+ return selected
195
+ ? styles.pressedTonalToggleSelected
196
+ : styles.pressedTonalToggleUnselected
197
+ }
198
+
199
+ if (variant === 'outlined') {
200
+ return selected
201
+ ? styles.pressedOutlinedToggleSelected
202
+ : styles.pressedOutlinedToggleUnselected
203
+ }
204
+
205
+ if (variant === 'standard') {
206
+ return selected
207
+ ? styles.pressedStandardToggleSelected
208
+ : styles.pressedStandardToggleUnselected
209
+ }
210
+
211
+ return selected
212
+ ? styles.pressedFilledToggleSelected
213
+ : styles.pressedFilledToggleUnselected
214
+ }
215
+
216
+ if (variant === 'tonal') {
217
+ return styles.pressedTonal
218
+ }
219
+
220
+ if (variant === 'outlined') {
221
+ return styles.pressedOutlined
222
+ }
223
+
224
+ if (variant === 'standard') {
225
+ return styles.pressedStandard
226
+ }
227
+
228
+ return styles.pressedFilled
229
+ }
230
+
231
+ function getDisabledStyle(
232
+ styles: ReturnType<typeof createStyles>,
233
+ variant: IconButtonVariant,
234
+ ) {
235
+ if (variant === 'tonal') {
236
+ return styles.disabledTonal
237
+ }
238
+
239
+ if (variant === 'outlined') {
240
+ return styles.disabledOutlined
241
+ }
242
+
243
+ if (variant === 'standard') {
244
+ return styles.disabledStandard
245
+ }
246
+
247
+ return styles.disabledFilled
248
+ }
249
+
250
+ export function IconButton({
251
+ icon,
252
+ selectedIcon,
253
+ iconColor,
254
+ contentColor,
255
+ containerColor,
256
+ style,
257
+ onPress,
258
+ disabled = false,
259
+ variant = 'filled',
260
+ selected,
261
+ size = 'medium',
262
+ hitSlop,
263
+ accessibilityLabel,
264
+ ...props
265
+ }: IconButtonProps) {
266
+ const theme = useTheme()
267
+ const styles = useMemo(() => createStyles(theme), [theme])
268
+ const isDisabled = Boolean(disabled)
269
+ const isToggle = selected !== undefined
270
+ const isSelected = Boolean(selected)
271
+ const resolvedIconColor =
272
+ contentColor ??
273
+ iconColor ??
274
+ getIconColor(variant, theme, isDisabled, isToggle, isSelected)
275
+ const displayIcon =
276
+ isToggle && isSelected && selectedIcon ? selectedIcon : icon
277
+ const iconPixelSize = getIconPixelSize(size)
278
+ const accessibilityState = isToggle
279
+ ? { disabled: isDisabled, selected: isSelected }
280
+ : { disabled: isDisabled }
281
+
282
+ const containerOverrides = useMemo(() => {
283
+ if (!containerColor) return null
284
+ const overlay = resolvedIconColor
285
+ return {
286
+ base: {
287
+ backgroundColor: containerColor,
288
+ borderColor: containerColor,
289
+ borderWidth: 0,
290
+ } as ViewStyle,
291
+ hovered: {
292
+ backgroundColor: blendColor(
293
+ containerColor,
294
+ overlay,
295
+ theme.stateLayer.hoveredOpacity,
296
+ ),
297
+ } as ViewStyle,
298
+ pressed: {
299
+ backgroundColor: blendColor(
300
+ containerColor,
301
+ overlay,
302
+ theme.stateLayer.pressedOpacity,
303
+ ),
304
+ } as ViewStyle,
305
+ }
306
+ }, [containerColor, resolvedIconColor, theme.stateLayer])
307
+
308
+ return (
309
+ <Pressable
310
+ {...props}
311
+ accessibilityRole="button"
312
+ accessibilityLabel={accessibilityLabel}
313
+ accessibilityState={accessibilityState}
314
+ disabled={isDisabled}
315
+ hitSlop={hitSlop ?? getDefaultHitSlop(size)}
316
+ onPress={onPress}
317
+ style={({
318
+ pressed,
319
+ hovered,
320
+ }: {
321
+ pressed: boolean
322
+ hovered?: boolean
323
+ }) => {
324
+ const base: StyleProp<ViewStyle>[] = [
325
+ styles.container,
326
+ getSizeStyle(styles, size),
327
+ getColorStyle(styles, variant, isToggle, isSelected),
328
+ containerOverrides?.base,
329
+ hovered && !pressed && !isDisabled
330
+ ? containerOverrides
331
+ ? containerOverrides.hovered
332
+ : getHoveredStyle(styles, variant, isToggle, isSelected)
333
+ : undefined,
334
+ pressed && !isDisabled
335
+ ? containerOverrides
336
+ ? containerOverrides.pressed
337
+ : getPressedStyle(styles, variant, isToggle, isSelected)
338
+ : undefined,
339
+ isDisabled ? getDisabledStyle(styles, variant) : undefined,
340
+ ]
341
+
342
+ if (typeof style === 'function') {
343
+ base.push(style({ pressed }))
344
+ } else if (style) {
345
+ base.push(style)
346
+ }
347
+
348
+ return base
349
+ }}
350
+ >
351
+ <MaterialCommunityIcons
352
+ name={displayIcon}
353
+ size={iconPixelSize}
354
+ color={resolvedIconColor}
355
+ />
356
+ </Pressable>
357
+ )
358
+ }
@@ -0,0 +1,6 @@
1
+ export { IconButton } from './IconButton'
2
+ export type {
3
+ IconButtonProps,
4
+ IconButtonSize,
5
+ IconButtonVariant,
6
+ } from './types'