@onlynative/components 0.1.0 → 0.1.1-alpha.1

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 (70) hide show
  1. package/dist/appbar/index.js +133 -62
  2. package/dist/button/index.js +125 -33
  3. package/dist/card/index.js +88 -20
  4. package/dist/checkbox/index.js +88 -17
  5. package/dist/chip/index.js +122 -30
  6. package/dist/icon-button/index.js +107 -36
  7. package/dist/index.js +335 -251
  8. package/dist/list/index.js +71 -24
  9. package/dist/radio/index.js +43 -14
  10. package/dist/switch/index.js +90 -19
  11. package/dist/text-field/index.js +82 -26
  12. package/package.json +4 -23
  13. package/src/appbar/AppBar.tsx +0 -302
  14. package/src/appbar/index.ts +0 -2
  15. package/src/appbar/styles.ts +0 -92
  16. package/src/appbar/types.ts +0 -67
  17. package/src/button/Button.tsx +0 -133
  18. package/src/button/index.ts +0 -2
  19. package/src/button/styles.ts +0 -287
  20. package/src/button/types.ts +0 -42
  21. package/src/card/Card.tsx +0 -69
  22. package/src/card/index.ts +0 -2
  23. package/src/card/styles.ts +0 -150
  24. package/src/card/types.ts +0 -27
  25. package/src/checkbox/Checkbox.tsx +0 -113
  26. package/src/checkbox/index.ts +0 -2
  27. package/src/checkbox/styles.ts +0 -155
  28. package/src/checkbox/types.ts +0 -20
  29. package/src/chip/Chip.tsx +0 -188
  30. package/src/chip/index.ts +0 -2
  31. package/src/chip/styles.ts +0 -239
  32. package/src/chip/types.ts +0 -58
  33. package/src/icon-button/IconButton.tsx +0 -362
  34. package/src/icon-button/index.ts +0 -6
  35. package/src/icon-button/styles.ts +0 -259
  36. package/src/icon-button/types.ts +0 -55
  37. package/src/index.ts +0 -54
  38. package/src/keyboard-avoiding-wrapper/KeyboardAvoidingWrapper.tsx +0 -69
  39. package/src/keyboard-avoiding-wrapper/index.ts +0 -2
  40. package/src/keyboard-avoiding-wrapper/styles.ts +0 -10
  41. package/src/keyboard-avoiding-wrapper/types.ts +0 -37
  42. package/src/layout/Box.tsx +0 -99
  43. package/src/layout/Column.tsx +0 -16
  44. package/src/layout/Grid.tsx +0 -49
  45. package/src/layout/Layout.tsx +0 -81
  46. package/src/layout/Row.tsx +0 -22
  47. package/src/layout/index.ts +0 -13
  48. package/src/layout/resolveSpacing.ts +0 -11
  49. package/src/layout/types.ts +0 -82
  50. package/src/list/List.tsx +0 -17
  51. package/src/list/ListDivider.tsx +0 -20
  52. package/src/list/ListItem.tsx +0 -128
  53. package/src/list/index.ts +0 -9
  54. package/src/list/styles.ts +0 -132
  55. package/src/list/types.ts +0 -54
  56. package/src/radio/Radio.tsx +0 -103
  57. package/src/radio/index.ts +0 -2
  58. package/src/radio/styles.ts +0 -139
  59. package/src/radio/types.ts +0 -20
  60. package/src/switch/Switch.tsx +0 -121
  61. package/src/switch/index.ts +0 -2
  62. package/src/switch/styles.ts +0 -172
  63. package/src/switch/types.ts +0 -32
  64. package/src/text-field/TextField.tsx +0 -301
  65. package/src/text-field/index.ts +0 -2
  66. package/src/text-field/styles.ts +0 -239
  67. package/src/text-field/types.ts +0 -49
  68. package/src/typography/Typography.tsx +0 -79
  69. package/src/typography/index.ts +0 -3
  70. package/src/typography/types.ts +0 -17
@@ -1,92 +0,0 @@
1
- import { StyleSheet } from 'react-native'
2
- import { defaultTopAppBarTokens } from '@onlynative/core'
3
- import type { MaterialTheme } from '@onlynative/core'
4
-
5
- export function createStyles(theme: MaterialTheme) {
6
- const topAppBar = theme.topAppBar ?? defaultTopAppBarTokens
7
-
8
- return StyleSheet.create({
9
- root: {
10
- backgroundColor: theme.colors.surface,
11
- },
12
- safeArea: {
13
- backgroundColor: theme.colors.surface,
14
- },
15
- elevatedRoot: {
16
- backgroundColor: theme.colors.surfaceContainer,
17
- },
18
- elevatedSafeArea: {
19
- backgroundColor: theme.colors.surfaceContainer,
20
- },
21
- smallContainer: {
22
- height: topAppBar.smallContainerHeight,
23
- position: 'relative',
24
- },
25
- mediumContainer: {
26
- height: topAppBar.mediumContainerHeight,
27
- },
28
- largeContainer: {
29
- height: topAppBar.largeContainerHeight,
30
- },
31
- expandedContainer: {
32
- position: 'relative',
33
- },
34
- topRow: {
35
- height: topAppBar.topRowHeight,
36
- paddingHorizontal: topAppBar.horizontalPadding,
37
- flexDirection: 'row',
38
- alignItems: 'center',
39
- },
40
- expandedTitleContainer: {
41
- flex: 1,
42
- justifyContent: 'flex-end',
43
- minWidth: 0,
44
- paddingEnd: theme.spacing.md,
45
- pointerEvents: 'none',
46
- },
47
- topRowSpacer: {
48
- flex: 1,
49
- },
50
- sideSlot: {
51
- flexDirection: 'row',
52
- alignItems: 'center',
53
- minHeight: topAppBar.sideSlotMinHeight,
54
- },
55
- actionsRow: {
56
- flexDirection: 'row',
57
- alignItems: 'center',
58
- },
59
- iconFrame: {
60
- width: topAppBar.iconFrameSize,
61
- height: topAppBar.iconFrameSize,
62
- alignItems: 'center',
63
- justifyContent: 'center',
64
- },
65
- overlayTitleContainer: {
66
- position: 'absolute',
67
- top: 0,
68
- bottom: 0,
69
- justifyContent: 'center',
70
- minWidth: 0,
71
- pointerEvents: 'none',
72
- },
73
- centeredTitle: {
74
- textAlign: 'center',
75
- },
76
- startAlignedTitle: {
77
- textAlign: 'auto',
78
- },
79
- mediumTitlePadding: {
80
- paddingBottom: topAppBar.mediumTitleBottomPadding,
81
- },
82
- largeTitlePadding: {
83
- paddingBottom: topAppBar.largeTitleBottomPadding,
84
- },
85
- title: {
86
- flexShrink: 1,
87
- maxWidth: '100%',
88
- includeFontPadding: false,
89
- textAlignVertical: 'center',
90
- },
91
- })
92
- }
@@ -1,67 +0,0 @@
1
- import type { ReactNode } from 'react'
2
- import type { StyleProp, TextStyle, ViewStyle } from 'react-native'
3
- import type { IconButtonProps } from '../icon-button'
4
-
5
- /** Size/layout variant of the AppBar. */
6
- export type AppBarVariant = 'small' | 'center-aligned' | 'medium' | 'large'
7
-
8
- /** A single action item rendered in the AppBar trailing slot. */
9
- export interface AppBarAction {
10
- /** MaterialCommunityIcons icon name to render. */
11
- icon: IconButtonProps['icon']
12
- /** Accessibility label for screen readers (required). */
13
- accessibilityLabel: string
14
- /** Called when the action icon is pressed. */
15
- onPress?: () => void
16
- /**
17
- * Disables the action icon.
18
- * @default false
19
- */
20
- disabled?: boolean
21
- }
22
-
23
- export interface AppBarProps {
24
- /** Title text displayed in the bar. */
25
- title: string
26
- /**
27
- * Layout variant.
28
- * @default 'small'
29
- */
30
- variant?: AppBarVariant
31
- /**
32
- * When `true`, renders a back button in the leading slot.
33
- * @default false
34
- */
35
- canGoBack?: boolean
36
- /** Called when the auto-rendered back button is pressed. */
37
- onBackPress?: () => void
38
- /**
39
- * When `true`, wraps the bar in a SafeAreaView that handles the top inset.
40
- * @default false
41
- */
42
- insetTop?: boolean
43
- /**
44
- * When `true`, adds shadow/elevation to indicate the bar is scrolled.
45
- * @default false
46
- */
47
- elevated?: boolean
48
- /** Custom leading content. When provided, overrides `canGoBack`. */
49
- leading?: ReactNode
50
- /** Custom trailing content. When provided, overrides `actions`. */
51
- trailing?: ReactNode
52
- /** Array of icon-button actions rendered in the trailing slot. */
53
- actions?: AppBarAction[]
54
- /**
55
- * Override the container (background) color.
56
- * Applied to both normal and elevated states.
57
- */
58
- containerColor?: string
59
- /**
60
- * Override the content (title and icon) color.
61
- */
62
- contentColor?: string
63
- /** Additional style applied to the title text. */
64
- titleStyle?: StyleProp<TextStyle>
65
- /** Custom style applied to the root container. */
66
- style?: StyleProp<ViewStyle>
67
- }
@@ -1,133 +0,0 @@
1
- import { useMemo } from 'react'
2
- import { Platform, Pressable } from 'react-native'
3
- import { StyleSheet } from 'react-native'
4
- import { Text } from 'react-native'
5
- import type { StyleProp, ViewStyle } from 'react-native'
6
- import { useTheme } from '@onlynative/core'
7
-
8
- import { getMaterialCommunityIcons } from '@onlynative/utils'
9
- import { createStyles } from './styles'
10
- import type { ButtonProps } from './types'
11
-
12
- interface PressableState {
13
- pressed: boolean
14
- hovered?: boolean
15
- }
16
-
17
- function resolveStyle(
18
- containerStyle: StyleProp<ViewStyle>,
19
- hoveredContainerStyle: StyleProp<ViewStyle>,
20
- pressedContainerStyle: StyleProp<ViewStyle>,
21
- disabledContainerStyle: StyleProp<ViewStyle>,
22
- disabled: boolean,
23
- style: ButtonProps['style'],
24
- ): (state: PressableState) => StyleProp<ViewStyle> {
25
- if (typeof style === 'function') {
26
- return (state) => [
27
- containerStyle,
28
- state.hovered && !state.pressed && !disabled
29
- ? hoveredContainerStyle
30
- : undefined,
31
- state.pressed && !disabled ? pressedContainerStyle : undefined,
32
- disabled ? disabledContainerStyle : undefined,
33
- style(state),
34
- ]
35
- }
36
-
37
- return (state) => [
38
- containerStyle,
39
- state.hovered && !state.pressed && !disabled
40
- ? hoveredContainerStyle
41
- : undefined,
42
- state.pressed && !disabled ? pressedContainerStyle : undefined,
43
- disabled ? disabledContainerStyle : undefined,
44
- style,
45
- ]
46
- }
47
-
48
- export function Button({
49
- children,
50
- style,
51
- variant = 'filled',
52
- leadingIcon,
53
- trailingIcon,
54
- iconSize = 18,
55
- containerColor,
56
- contentColor,
57
- labelStyle: labelStyleOverride,
58
- disabled = false,
59
- ...props
60
- }: ButtonProps) {
61
- const isDisabled = Boolean(disabled)
62
- const hasLeading = Boolean(leadingIcon)
63
- const hasTrailing = Boolean(trailingIcon)
64
- const theme = useTheme()
65
- const styles = useMemo(
66
- () =>
67
- createStyles(
68
- theme,
69
- variant,
70
- hasLeading,
71
- hasTrailing,
72
- containerColor,
73
- contentColor,
74
- ),
75
- [theme, variant, hasLeading, hasTrailing, containerColor, contentColor],
76
- )
77
-
78
- const MaterialCommunityIcons =
79
- leadingIcon || trailingIcon ? getMaterialCommunityIcons() : null
80
-
81
- const resolvedIconColor = useMemo(() => {
82
- const base = StyleSheet.flatten([
83
- styles.label,
84
- isDisabled ? styles.disabledLabel : undefined,
85
- ])
86
- return typeof base?.color === 'string' ? base.color : undefined
87
- }, [styles.label, styles.disabledLabel, isDisabled])
88
-
89
- const computedLabelStyle = useMemo(
90
- () => [
91
- styles.label,
92
- isDisabled ? styles.disabledLabel : undefined,
93
- labelStyleOverride,
94
- ],
95
- [isDisabled, styles.disabledLabel, styles.label, labelStyleOverride],
96
- )
97
-
98
- return (
99
- <Pressable
100
- {...props}
101
- accessibilityRole="button"
102
- accessibilityState={{ disabled: isDisabled }}
103
- hitSlop={Platform.OS === 'web' ? undefined : 4}
104
- disabled={isDisabled}
105
- style={resolveStyle(
106
- styles.container,
107
- styles.hoveredContainer,
108
- styles.pressedContainer,
109
- styles.disabledContainer,
110
- isDisabled,
111
- style,
112
- )}
113
- >
114
- {leadingIcon ? (
115
- <MaterialCommunityIcons
116
- name={leadingIcon}
117
- size={iconSize}
118
- color={resolvedIconColor}
119
- style={styles.leadingIcon}
120
- />
121
- ) : null}
122
- <Text style={computedLabelStyle}>{children}</Text>
123
- {trailingIcon ? (
124
- <MaterialCommunityIcons
125
- name={trailingIcon}
126
- size={iconSize}
127
- color={resolvedIconColor}
128
- style={styles.trailingIcon}
129
- />
130
- ) : null}
131
- </Pressable>
132
- )
133
- }
@@ -1,2 +0,0 @@
1
- export { Button } from './Button'
2
- export type { ButtonProps, ButtonVariant } from './types'
@@ -1,287 +0,0 @@
1
- import { StyleSheet } from 'react-native'
2
- import type { MaterialTheme } from '@onlynative/core'
3
-
4
- import type { ButtonVariant } from './types'
5
- import { alphaColor, blendColor, elevationStyle } from '@onlynative/utils'
6
-
7
- interface VariantColors {
8
- backgroundColor: string
9
- textColor: string
10
- borderColor: string
11
- borderWidth: number
12
- hoveredBackgroundColor: string
13
- pressedBackgroundColor: string
14
- disabledBackgroundColor: string
15
- disabledTextColor: string
16
- disabledBorderColor: string
17
- }
18
-
19
- function getVariantColors(theme: MaterialTheme, variant: ButtonVariant): VariantColors {
20
- const disabledContainerColor = alphaColor(theme.colors.onSurface, 0.12)
21
- const disabledLabelColor = alphaColor(theme.colors.onSurface, 0.38)
22
- const disabledOutlineColor = alphaColor(theme.colors.onSurface, 0.12)
23
-
24
- if (variant === 'outlined') {
25
- return {
26
- backgroundColor: 'transparent',
27
- textColor: theme.colors.primary,
28
- borderColor: theme.colors.outline,
29
- borderWidth: 1,
30
- hoveredBackgroundColor: alphaColor(
31
- theme.colors.primary,
32
- theme.stateLayer.hoveredOpacity,
33
- ),
34
- pressedBackgroundColor: alphaColor(
35
- theme.colors.primary,
36
- theme.stateLayer.pressedOpacity,
37
- ),
38
- disabledBackgroundColor: 'transparent',
39
- disabledTextColor: disabledLabelColor,
40
- disabledBorderColor: disabledOutlineColor,
41
- }
42
- }
43
-
44
- if (variant === 'text') {
45
- return {
46
- backgroundColor: 'transparent',
47
- textColor: theme.colors.primary,
48
- borderColor: 'transparent',
49
- borderWidth: 0,
50
- hoveredBackgroundColor: alphaColor(
51
- theme.colors.primary,
52
- theme.stateLayer.hoveredOpacity,
53
- ),
54
- pressedBackgroundColor: alphaColor(
55
- theme.colors.primary,
56
- theme.stateLayer.pressedOpacity,
57
- ),
58
- disabledBackgroundColor: 'transparent',
59
- disabledTextColor: disabledLabelColor,
60
- disabledBorderColor: 'transparent',
61
- }
62
- }
63
-
64
- if (variant === 'elevated') {
65
- return {
66
- backgroundColor: theme.colors.surfaceContainerLow,
67
- textColor: theme.colors.primary,
68
- borderColor: theme.colors.surfaceContainerLow,
69
- borderWidth: 0,
70
- hoveredBackgroundColor: blendColor(
71
- theme.colors.surfaceContainerLow,
72
- theme.colors.primary,
73
- theme.stateLayer.hoveredOpacity,
74
- ),
75
- pressedBackgroundColor: blendColor(
76
- theme.colors.surfaceContainerLow,
77
- theme.colors.primary,
78
- theme.stateLayer.pressedOpacity,
79
- ),
80
- disabledBackgroundColor: disabledContainerColor,
81
- disabledTextColor: disabledLabelColor,
82
- disabledBorderColor: disabledContainerColor,
83
- }
84
- }
85
-
86
- if (variant === 'tonal') {
87
- return {
88
- backgroundColor: theme.colors.secondaryContainer,
89
- textColor: theme.colors.onSecondaryContainer,
90
- borderColor: theme.colors.secondaryContainer,
91
- borderWidth: 0,
92
- hoveredBackgroundColor: blendColor(
93
- theme.colors.secondaryContainer,
94
- theme.colors.onSecondaryContainer,
95
- theme.stateLayer.hoveredOpacity,
96
- ),
97
- pressedBackgroundColor: blendColor(
98
- theme.colors.secondaryContainer,
99
- theme.colors.onSecondaryContainer,
100
- theme.stateLayer.pressedOpacity,
101
- ),
102
- disabledBackgroundColor: disabledContainerColor,
103
- disabledTextColor: disabledLabelColor,
104
- disabledBorderColor: disabledContainerColor,
105
- }
106
- }
107
-
108
- // filled (default)
109
- return {
110
- backgroundColor: theme.colors.primary,
111
- textColor: theme.colors.onPrimary,
112
- borderColor: theme.colors.primary,
113
- borderWidth: 0,
114
- hoveredBackgroundColor: blendColor(
115
- theme.colors.primary,
116
- theme.colors.onPrimary,
117
- theme.stateLayer.hoveredOpacity,
118
- ),
119
- pressedBackgroundColor: blendColor(
120
- theme.colors.primary,
121
- theme.colors.onPrimary,
122
- theme.stateLayer.pressedOpacity,
123
- ),
124
- disabledBackgroundColor: disabledContainerColor,
125
- disabledTextColor: disabledLabelColor,
126
- disabledBorderColor: disabledContainerColor,
127
- }
128
- }
129
-
130
- function getHorizontalPadding(
131
- theme: MaterialTheme,
132
- variant: ButtonVariant,
133
- hasLeadingIcon: boolean,
134
- hasTrailingIcon: boolean,
135
- ): { paddingStart: number; paddingEnd: number } {
136
- if (variant === 'text') {
137
- // M3: text button uses 12dp base, opposite side of icon gets 16dp
138
- return {
139
- paddingStart: hasLeadingIcon
140
- ? 12
141
- : hasTrailingIcon
142
- ? theme.spacing.md
143
- : 12,
144
- paddingEnd: hasTrailingIcon ? 12 : hasLeadingIcon ? theme.spacing.md : 12,
145
- }
146
- }
147
-
148
- // M3: filled/elevated/tonal/outlined use 24dp base, icon side gets 16dp
149
- return {
150
- paddingStart: hasLeadingIcon ? theme.spacing.md : theme.spacing.lg,
151
- paddingEnd: hasTrailingIcon ? theme.spacing.md : theme.spacing.lg,
152
- }
153
- }
154
-
155
- function applyColorOverrides(
156
- theme: MaterialTheme,
157
- colors: VariantColors,
158
- containerColor?: string,
159
- contentColor?: string,
160
- ): VariantColors {
161
- if (!containerColor && !contentColor) return colors
162
-
163
- const result = { ...colors }
164
-
165
- if (contentColor) {
166
- result.textColor = contentColor
167
- }
168
-
169
- if (containerColor) {
170
- const overlay = contentColor ?? colors.textColor
171
- result.backgroundColor = containerColor
172
- result.borderColor = containerColor
173
- result.hoveredBackgroundColor = blendColor(
174
- containerColor,
175
- overlay,
176
- theme.stateLayer.hoveredOpacity,
177
- )
178
- result.pressedBackgroundColor = blendColor(
179
- containerColor,
180
- overlay,
181
- theme.stateLayer.pressedOpacity,
182
- )
183
- } else if (contentColor) {
184
- if (colors.backgroundColor === 'transparent') {
185
- result.hoveredBackgroundColor = alphaColor(
186
- contentColor,
187
- theme.stateLayer.hoveredOpacity,
188
- )
189
- result.pressedBackgroundColor = alphaColor(
190
- contentColor,
191
- theme.stateLayer.pressedOpacity,
192
- )
193
- } else {
194
- result.hoveredBackgroundColor = blendColor(
195
- colors.backgroundColor,
196
- contentColor,
197
- theme.stateLayer.hoveredOpacity,
198
- )
199
- result.pressedBackgroundColor = blendColor(
200
- colors.backgroundColor,
201
- contentColor,
202
- theme.stateLayer.pressedOpacity,
203
- )
204
- }
205
- }
206
-
207
- return result
208
- }
209
-
210
- export function createStyles(
211
- theme: MaterialTheme,
212
- variant: ButtonVariant,
213
- hasLeadingIcon: boolean,
214
- hasTrailingIcon: boolean,
215
- containerColor?: string,
216
- contentColor?: string,
217
- ) {
218
- const baseColors = getVariantColors(theme, variant)
219
- const colors = applyColorOverrides(
220
- theme,
221
- baseColors,
222
- containerColor,
223
- contentColor,
224
- )
225
- const labelStyle = theme.typography.labelLarge
226
- const padding = getHorizontalPadding(
227
- theme,
228
- variant,
229
- hasLeadingIcon,
230
- hasTrailingIcon,
231
- )
232
- const elevationLevel0 = elevationStyle(theme.elevation.level0)
233
- const elevationLevel1 = elevationStyle(theme.elevation.level1)
234
- const elevationLevel2 = elevationStyle(theme.elevation.level2)
235
- const baseElevation =
236
- variant === 'elevated' ? elevationLevel1 : elevationLevel0
237
-
238
- return StyleSheet.create({
239
- container: {
240
- alignSelf: 'flex-start',
241
- alignItems: 'center',
242
- flexDirection: 'row',
243
- justifyContent: 'center',
244
- minWidth: 58,
245
- minHeight: 40,
246
- paddingStart: padding.paddingStart,
247
- paddingEnd: padding.paddingEnd,
248
- paddingVertical: 10,
249
- borderRadius: theme.shape.cornerFull,
250
- backgroundColor: colors.backgroundColor,
251
- borderColor: colors.borderColor,
252
- borderWidth: colors.borderWidth,
253
- cursor: 'pointer',
254
- ...baseElevation,
255
- },
256
- hoveredContainer: {
257
- backgroundColor: colors.hoveredBackgroundColor,
258
- ...(variant === 'elevated' ? elevationLevel2 : undefined),
259
- },
260
- pressedContainer: {
261
- backgroundColor: colors.pressedBackgroundColor,
262
- },
263
- disabledContainer: {
264
- backgroundColor: colors.disabledBackgroundColor,
265
- borderColor: colors.disabledBorderColor,
266
- cursor: 'auto',
267
- ...elevationLevel0,
268
- },
269
- label: {
270
- fontFamily: labelStyle.fontFamily,
271
- fontSize: labelStyle.fontSize,
272
- lineHeight: labelStyle.lineHeight,
273
- fontWeight: labelStyle.fontWeight,
274
- letterSpacing: labelStyle.letterSpacing,
275
- color: colors.textColor,
276
- },
277
- leadingIcon: {
278
- marginEnd: theme.spacing.sm,
279
- },
280
- trailingIcon: {
281
- marginStart: theme.spacing.sm,
282
- },
283
- disabledLabel: {
284
- color: colors.disabledTextColor,
285
- },
286
- })
287
- }
@@ -1,42 +0,0 @@
1
- import type MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons'
2
- import type { ComponentProps } from 'react'
3
- import type { PressableProps, StyleProp, TextStyle } from 'react-native'
4
-
5
- /** Visual style variant of the button following Material Design 3 roles. */
6
- export type ButtonVariant =
7
- | 'filled'
8
- | 'elevated'
9
- | 'outlined'
10
- | 'text'
11
- | 'tonal'
12
-
13
- export interface ButtonProps extends Omit<PressableProps, 'children'> {
14
- /** Text label rendered inside the button. */
15
- children: string
16
- /**
17
- * Visual variant. Controls background, border, and text color.
18
- * @default 'filled'
19
- */
20
- variant?: ButtonVariant
21
- /** Name of a MaterialCommunityIcons icon to show before the label. */
22
- leadingIcon?: ComponentProps<typeof MaterialCommunityIcons>['name']
23
- /** Name of a MaterialCommunityIcons icon to show after the label. */
24
- trailingIcon?: ComponentProps<typeof MaterialCommunityIcons>['name']
25
- /**
26
- * Size of leading and trailing icons in dp.
27
- * @default 18
28
- */
29
- iconSize?: number
30
- /**
31
- * Override the container (background) color.
32
- * State-layer colors (hover, press) are derived automatically.
33
- */
34
- containerColor?: string
35
- /**
36
- * Override the content (label and icon) color.
37
- * State-layer colors are derived automatically when no containerColor is set.
38
- */
39
- contentColor?: string
40
- /** Additional style applied to the label text. */
41
- labelStyle?: StyleProp<TextStyle>
42
- }
package/src/card/Card.tsx DELETED
@@ -1,69 +0,0 @@
1
- import { useMemo } from 'react'
2
- import { Platform, Pressable, View } from 'react-native'
3
- import type { StyleProp, ViewStyle } from 'react-native'
4
- import { useTheme } from '@onlynative/core'
5
-
6
- import { createStyles } from './styles'
7
- import type { CardProps } from './types'
8
-
9
- interface PressableState {
10
- pressed: boolean
11
- hovered?: boolean
12
- }
13
-
14
- export function Card({
15
- children,
16
- style,
17
- variant = 'elevated',
18
- onPress,
19
- disabled = false,
20
- containerColor,
21
- ...props
22
- }: CardProps) {
23
- const isDisabled = Boolean(disabled)
24
- const isInteractive = onPress !== undefined
25
- const theme = useTheme()
26
- const styles = useMemo(
27
- () => createStyles(theme, variant, containerColor),
28
- [theme, variant, containerColor],
29
- )
30
-
31
- if (!isInteractive) {
32
- return (
33
- <View {...props} style={[styles.container, style]}>
34
- {children}
35
- </View>
36
- )
37
- }
38
-
39
- const resolvedStyle = (state: PressableState): StyleProp<ViewStyle> => [
40
- styles.container,
41
- styles.interactiveContainer,
42
- state.hovered && !state.pressed && !isDisabled
43
- ? styles.hoveredContainer
44
- : undefined,
45
- state.pressed && !isDisabled ? styles.pressedContainer : undefined,
46
- isDisabled ? styles.disabledContainer : undefined,
47
- typeof style === 'function'
48
- ? (style as (state: PressableState) => ViewStyle)(state)
49
- : style,
50
- ]
51
-
52
- return (
53
- <Pressable
54
- {...props}
55
- role="button"
56
- accessibilityState={{ disabled: isDisabled }}
57
- hitSlop={Platform.OS === 'web' ? undefined : 4}
58
- disabled={isDisabled}
59
- onPress={onPress}
60
- style={resolvedStyle}
61
- >
62
- {isDisabled ? (
63
- <View style={styles.disabledContent}>{children}</View>
64
- ) : (
65
- children
66
- )}
67
- </Pressable>
68
- )
69
- }
package/src/card/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export { Card } from './Card'
2
- export type { CardProps, CardVariant } from './types'