@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.
- package/dist/appbar/index.js +133 -62
- package/dist/button/index.js +125 -33
- package/dist/card/index.js +88 -20
- package/dist/checkbox/index.js +88 -17
- package/dist/chip/index.js +122 -30
- package/dist/icon-button/index.js +107 -36
- package/dist/index.js +335 -251
- package/dist/list/index.js +71 -24
- package/dist/radio/index.js +43 -14
- package/dist/switch/index.js +90 -19
- package/dist/text-field/index.js +82 -26
- package/package.json +4 -23
- package/src/appbar/AppBar.tsx +0 -302
- package/src/appbar/index.ts +0 -2
- package/src/appbar/styles.ts +0 -92
- package/src/appbar/types.ts +0 -67
- package/src/button/Button.tsx +0 -133
- package/src/button/index.ts +0 -2
- package/src/button/styles.ts +0 -287
- package/src/button/types.ts +0 -42
- package/src/card/Card.tsx +0 -69
- package/src/card/index.ts +0 -2
- package/src/card/styles.ts +0 -150
- package/src/card/types.ts +0 -27
- package/src/checkbox/Checkbox.tsx +0 -113
- package/src/checkbox/index.ts +0 -2
- package/src/checkbox/styles.ts +0 -155
- package/src/checkbox/types.ts +0 -20
- package/src/chip/Chip.tsx +0 -188
- package/src/chip/index.ts +0 -2
- package/src/chip/styles.ts +0 -239
- package/src/chip/types.ts +0 -58
- package/src/icon-button/IconButton.tsx +0 -362
- package/src/icon-button/index.ts +0 -6
- package/src/icon-button/styles.ts +0 -259
- package/src/icon-button/types.ts +0 -55
- package/src/index.ts +0 -54
- package/src/keyboard-avoiding-wrapper/KeyboardAvoidingWrapper.tsx +0 -69
- package/src/keyboard-avoiding-wrapper/index.ts +0 -2
- package/src/keyboard-avoiding-wrapper/styles.ts +0 -10
- package/src/keyboard-avoiding-wrapper/types.ts +0 -37
- package/src/layout/Box.tsx +0 -99
- package/src/layout/Column.tsx +0 -16
- package/src/layout/Grid.tsx +0 -49
- package/src/layout/Layout.tsx +0 -81
- package/src/layout/Row.tsx +0 -22
- package/src/layout/index.ts +0 -13
- package/src/layout/resolveSpacing.ts +0 -11
- package/src/layout/types.ts +0 -82
- package/src/list/List.tsx +0 -17
- package/src/list/ListDivider.tsx +0 -20
- package/src/list/ListItem.tsx +0 -128
- package/src/list/index.ts +0 -9
- package/src/list/styles.ts +0 -132
- package/src/list/types.ts +0 -54
- package/src/radio/Radio.tsx +0 -103
- package/src/radio/index.ts +0 -2
- package/src/radio/styles.ts +0 -139
- package/src/radio/types.ts +0 -20
- package/src/switch/Switch.tsx +0 -121
- package/src/switch/index.ts +0 -2
- package/src/switch/styles.ts +0 -172
- package/src/switch/types.ts +0 -32
- package/src/text-field/TextField.tsx +0 -301
- package/src/text-field/index.ts +0 -2
- package/src/text-field/styles.ts +0 -239
- package/src/text-field/types.ts +0 -49
- package/src/typography/Typography.tsx +0 -79
- package/src/typography/index.ts +0 -3
- package/src/typography/types.ts +0 -17
package/src/appbar/styles.ts
DELETED
|
@@ -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
|
-
}
|
package/src/appbar/types.ts
DELETED
|
@@ -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
|
-
}
|
package/src/button/Button.tsx
DELETED
|
@@ -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
|
-
}
|
package/src/button/index.ts
DELETED
package/src/button/styles.ts
DELETED
|
@@ -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
|
-
}
|
package/src/button/types.ts
DELETED
|
@@ -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