Add some form elements
This commit is contained in:
+5
-7
@@ -4,14 +4,10 @@ import type {Mutable} from '#/alf/types'
|
|||||||
export type ThemeName = 'light' | 'dark'
|
export type ThemeName = 'light' | 'dark'
|
||||||
export type ReadonlyTheme = typeof light
|
export type ReadonlyTheme = typeof light
|
||||||
export type Theme = Mutable<ReadonlyTheme>
|
export type Theme = Mutable<ReadonlyTheme>
|
||||||
|
export type ReadonlyPalette = typeof lightPalette
|
||||||
|
export type Palette = Mutable<ReadonlyPalette>
|
||||||
|
|
||||||
export type Palette = {
|
export const lightPalette = {
|
||||||
primary: string
|
|
||||||
positive: string
|
|
||||||
negative: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const lightPalette: Palette = {
|
|
||||||
primary: tokens.color.blue_500,
|
primary: tokens.color.blue_500,
|
||||||
positive: tokens.color.green_500,
|
positive: tokens.color.green_500,
|
||||||
negative: tokens.color.red_500,
|
negative: tokens.color.red_500,
|
||||||
@@ -24,6 +20,7 @@ export const darkPalette: Palette = {
|
|||||||
} as const
|
} as const
|
||||||
|
|
||||||
export const light = {
|
export const light = {
|
||||||
|
name: 'light',
|
||||||
palette: lightPalette,
|
palette: lightPalette,
|
||||||
atoms: {
|
atoms: {
|
||||||
text: {
|
text: {
|
||||||
@@ -66,6 +63,7 @@ export const light = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const dark: Theme = {
|
export const dark: Theme = {
|
||||||
|
name: 'dark',
|
||||||
palette: darkPalette,
|
palette: darkPalette,
|
||||||
atoms: {
|
atoms: {
|
||||||
text: {
|
text: {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
|
|
||||||
import {atoms, tokens, web, native} from '#/alf'
|
import {useTheme, atoms, tokens, web, native} from '#/alf'
|
||||||
|
|
||||||
export type ButtonType = 'primary' | 'secondary' | 'negative'
|
export type ButtonType = 'primary' | 'secondary' | 'negative'
|
||||||
export type ButtonSize = 'small' | 'large'
|
export type ButtonSize = 'small' | 'large'
|
||||||
@@ -217,6 +217,8 @@ export function ButtonText({
|
|||||||
disabled,
|
disabled,
|
||||||
...rest
|
...rest
|
||||||
}: ButtonTextProps) {
|
}: ButtonTextProps) {
|
||||||
|
const t = useTheme()
|
||||||
|
|
||||||
const textStyles = React.useMemo(() => {
|
const textStyles = React.useMemo(() => {
|
||||||
const baseStyles = []
|
const baseStyles = []
|
||||||
|
|
||||||
@@ -244,6 +246,7 @@ export function ButtonText({
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
baseStyles.push(t.atoms.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
@@ -267,7 +270,7 @@ export function ButtonText({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return baseStyles
|
return baseStyles
|
||||||
}, [type, size, disabled])
|
}, [t, type, size, disabled])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text
|
<Text
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
|
||||||
|
import {atoms} from '#/alf'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOT FINISHED, just here as a reference
|
||||||
|
*/
|
||||||
|
export function InputGroup(props: React.PropsWithChildren<{}>) {
|
||||||
|
const children = React.Children.toArray(props.children)
|
||||||
|
const total = children.length
|
||||||
|
return (
|
||||||
|
<View style={[atoms.w_full]}>
|
||||||
|
{children.map((child, i) => {
|
||||||
|
return React.isValidElement(child) ? (
|
||||||
|
<React.Fragment key={i}>
|
||||||
|
{React.cloneElement(child, {
|
||||||
|
// @ts-ignore
|
||||||
|
style: [
|
||||||
|
...(Array.isArray(child.props?.style)
|
||||||
|
? child.props.style
|
||||||
|
: [child.props.style || {}]),
|
||||||
|
{
|
||||||
|
borderTopLeftRadius: i > 0 ? 0 : undefined,
|
||||||
|
borderTopRightRadius: i > 0 ? 0 : undefined,
|
||||||
|
borderBottomLeftRadius: i < total - 1 ? 0 : undefined,
|
||||||
|
borderBottomRightRadius: i < total - 1 ? 0 : undefined,
|
||||||
|
borderBottomWidth: i < total - 1 ? 0 : undefined,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</React.Fragment>
|
||||||
|
) : null
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {View, TextInput, TextInputProps, TextStyle} from 'react-native'
|
||||||
|
|
||||||
|
import {useTheme, atoms, web, tokens} from '#/alf'
|
||||||
|
|
||||||
|
type Props = Omit<TextInputProps, 'placeholder'> & {
|
||||||
|
placeholder: string
|
||||||
|
hasError?: boolean
|
||||||
|
icon?: React.FunctionComponent<any>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InputText({hasError, icon: Icon, ...props}: Props) {
|
||||||
|
const t = useTheme()
|
||||||
|
const [state, setState] = React.useState({
|
||||||
|
hovered: false,
|
||||||
|
focused: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const onHoverIn = React.useCallback(() => {
|
||||||
|
setState(s => ({
|
||||||
|
...s,
|
||||||
|
hovered: true,
|
||||||
|
}))
|
||||||
|
}, [setState])
|
||||||
|
const onHoverOut = React.useCallback(() => {
|
||||||
|
setState(s => ({
|
||||||
|
...s,
|
||||||
|
hovered: false,
|
||||||
|
}))
|
||||||
|
}, [setState])
|
||||||
|
const onFocus = React.useCallback(() => {
|
||||||
|
setState(s => ({
|
||||||
|
...s,
|
||||||
|
focused: true,
|
||||||
|
}))
|
||||||
|
}, [setState])
|
||||||
|
const onBlur = React.useCallback(() => {
|
||||||
|
setState(s => ({
|
||||||
|
...s,
|
||||||
|
focused: false,
|
||||||
|
}))
|
||||||
|
}, [setState])
|
||||||
|
|
||||||
|
const {inputStyles, iconStyles} = React.useMemo(() => {
|
||||||
|
const input: TextStyle[] = []
|
||||||
|
const icon: TextStyle[] = []
|
||||||
|
|
||||||
|
if (Icon) {
|
||||||
|
input.push({
|
||||||
|
paddingLeft: 40,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasError) {
|
||||||
|
input.push({
|
||||||
|
borderColor: tokens.color.red_200,
|
||||||
|
})
|
||||||
|
icon.push({
|
||||||
|
color: tokens.color.red_400,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.hovered || state.focused) {
|
||||||
|
input.push({
|
||||||
|
borderColor: t.atoms.border_contrast_500.borderColor,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (hasError) {
|
||||||
|
input.push({
|
||||||
|
borderColor: tokens.color.red_500,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {inputStyles: input, iconStyles: icon}
|
||||||
|
}, [t, state, hasError, Icon])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={[atoms.relative, atoms.w_full]}>
|
||||||
|
<TextInput
|
||||||
|
{...props}
|
||||||
|
onFocus={onFocus}
|
||||||
|
onBlur={onBlur}
|
||||||
|
{...web({
|
||||||
|
onMouseEnter: onHoverIn,
|
||||||
|
onMouseLeave: onHoverOut,
|
||||||
|
})}
|
||||||
|
placeholderTextColor={t.atoms.text_contrast_500.color}
|
||||||
|
style={[
|
||||||
|
t.name === 'dark' ? t.atoms.bg_contrast_100 : t.atoms.bg,
|
||||||
|
atoms.w_full,
|
||||||
|
atoms.px_lg,
|
||||||
|
atoms.py_md,
|
||||||
|
atoms.rounded_sm,
|
||||||
|
t.atoms.border,
|
||||||
|
t.atoms.text,
|
||||||
|
{borderWidth: 2},
|
||||||
|
web({
|
||||||
|
paddingTop: atoms.pt_md.paddingTop - 1,
|
||||||
|
}),
|
||||||
|
...inputStyles,
|
||||||
|
...(Array.isArray(props.style) ? props.style : [props.style]),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{Icon && (
|
||||||
|
<Icon
|
||||||
|
style={[
|
||||||
|
atoms.absolute,
|
||||||
|
atoms.inset_0,
|
||||||
|
{color: t.atoms.border_contrast_500.borderColor},
|
||||||
|
{
|
||||||
|
left: atoms.px_md.paddingLeft,
|
||||||
|
right: 'auto',
|
||||||
|
width: 20,
|
||||||
|
marginVertical: 'auto',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
},
|
||||||
|
...iconStyles,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import {StyleSheet} from 'react-native'
|
||||||
import Svg, {
|
import Svg, {
|
||||||
Path,
|
Path,
|
||||||
Defs,
|
Defs,
|
||||||
@@ -19,7 +20,8 @@ type Props = {
|
|||||||
export const Logo = React.forwardRef(function LogoImpl(props: Props, ref) {
|
export const Logo = React.forwardRef(function LogoImpl(props: Props, ref) {
|
||||||
const {fill, ...rest} = props
|
const {fill, ...rest} = props
|
||||||
const gradient = fill === 'sky'
|
const gradient = fill === 'sky'
|
||||||
const _fill = gradient ? 'url(#sky)' : fill || colors.blue3
|
const styles = StyleSheet.flatten(props.style)
|
||||||
|
const _fill = gradient ? 'url(#sky)' : fill || styles?.color || colors.blue3
|
||||||
// @ts-ignore it's fiiiiine
|
// @ts-ignore it's fiiiiine
|
||||||
const size = parseInt(rest.width || 32)
|
const size = parseInt(rest.width || 32)
|
||||||
return (
|
return (
|
||||||
@@ -29,7 +31,7 @@ export const Logo = React.forwardRef(function LogoImpl(props: Props, ref) {
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox="0 0 64 57"
|
viewBox="0 0 64 57"
|
||||||
{...rest}
|
{...rest}
|
||||||
style={{width: size, height: size * ratio}}>
|
style={[{width: size, height: size * ratio}, styles]}>
|
||||||
{gradient && (
|
{gradient && (
|
||||||
<Defs>
|
<Defs>
|
||||||
<LinearGradient id="sky" x1="0" y1="0" x2="0" y2="1">
|
<LinearGradient id="sky" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import {atoms as a, useTheme, useBreakpoints, ThemeProvider as Alf} from '#/alf'
|
|||||||
import {Button, ButtonText} from '#/view/com/Button'
|
import {Button, ButtonText} from '#/view/com/Button'
|
||||||
import {Link} from '#/view/com/Link'
|
import {Link} from '#/view/com/Link'
|
||||||
import {Text, H1, H2, H3, H4, H5, H6} from '#/view/com/Typography'
|
import {Text, H1, H2, H3, H4, H5, H6} from '#/view/com/Typography'
|
||||||
|
import {InputText} from '#/view/com/forms/InputText'
|
||||||
|
import {Logo} from '#/view/icons/Logo'
|
||||||
|
|
||||||
function ThemeSelector() {
|
function ThemeSelector() {
|
||||||
const setColorMode = useSetColorMode()
|
const setColorMode = useSetColorMode()
|
||||||
@@ -212,6 +214,16 @@ export function Buttons() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Forms() {
|
||||||
|
return (
|
||||||
|
<View style={[a.gap_md, a.align_start]}>
|
||||||
|
<InputText placeholder="Type here" />
|
||||||
|
<InputText placeholder="Type here" icon={Logo} />
|
||||||
|
<InputText hasError placeholder="Type here" icon={Logo} />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function DebugScreen() {
|
export function DebugScreen() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
|
||||||
@@ -221,6 +233,7 @@ export function DebugScreen() {
|
|||||||
<View style={[a.p_xl, a.gap_xxl, {paddingBottom: 200}]}>
|
<View style={[a.p_xl, a.gap_xxl, {paddingBottom: 200}]}>
|
||||||
<ThemeSelector />
|
<ThemeSelector />
|
||||||
|
|
||||||
|
<Forms />
|
||||||
<Buttons />
|
<Buttons />
|
||||||
|
|
||||||
<Alf theme="light">
|
<Alf theme="light">
|
||||||
|
|||||||
Reference in New Issue
Block a user