tuya-panel-kit
Version:
a functional component library for developing tuya device panels!
484 lines (441 loc) • 13 kB
JavaScript
import React from 'react';
import { View, TouchableOpacity, StyleSheet } from 'react-native';
import styled from 'styled-components/native';
import { RatioUtils, ThemeUtils } from '../../utils';
import Button from '../button';
import TYText from '../TYText';
import Slider from '../slider';
import IconFont from '../iconfont';
import TimerPicker from '../timer-picker';
import TYFlatList from '../TYLists/list';
import DatePicker from '../date-picker';
import SwitchButton from '../switch-button';
import { defaultTheme, getDefaultTheme } from '../theme';
const DEFAULT_LIST_THEME = defaultTheme.popup.basic;
const DEFAULT_PICKER_THEME = defaultTheme.picker.light;
export const backIcon =
'M770.673778 21.959111a56.888889 56.888889 0 0 1 0 80.440889l-402.204445 402.318222 402.204445 402.204445a56.888889 56.888889 0 0 1-80.440889 80.497777L247.751111 544.938667a56.888889 56.888889 0 0 1 0-80.497778L690.232889 21.959111a56.888889 56.888889 0 0 1 80.440889 0z';
const { convertX: cx, isIphoneX, isIos } = RatioUtils;
const { getTheme, ThemeConsumer } = ThemeUtils;
const {
cellHeight,
cellBg,
cellFontSize,
cellFontColor,
titleRadius,
titleHeight,
titleBg,
footerRadius,
bottomBg,
lineColor,
titleFontSize,
titleFontColor,
cancelFontSize,
cancelFontColor,
confirmFontSize,
confirmFontColor,
subTitleFontColor,
backIconColor,
pressColor,
} = getDefaultTheme.popup;
/**
* Common Popup
*/
export const Row = styled(View)`
flex-direction: row;
align-items: center;
justify-content: center;
height: ${cellHeight}px;
background-color: ${cellBg};
`;
// 为了处理安卓 Modal 在内容框内同时双击会出现Modal关闭问题
export const StyledContainer = styled(TouchableOpacity).attrs({
activeOpacity: 1,
})`
/* bottom: -100%; */
border-top-left-radius: ${titleRadius};
border-top-right-radius: ${titleRadius};
border-bottom-left-radius: ${footerRadius};
border-bottom-right-radius: ${footerRadius};
background-color: ${bottomBg};
`;
export const StyledTitle = styled(Row)`
justify-content: space-around;
height: ${titleHeight}px;
padding: 0 16px;
background-color: ${titleBg};
border-top-left-radius: ${titleRadius};
border-top-right-radius: ${titleRadius};
`;
export const StyledTitleText = styled(TYText)`
font-size: ${titleFontSize};
color: ${titleFontColor};
`;
export const StyledSwitch = styled(SwitchButton).attrs({
tintColor: props => getTheme(props, 'popup.tintColor', '#e5e5e5'),
})``;
export const StyledCheckout = styled(View).attrs({})`
width: 18px;
height: 18px;
border-radius: 9px;
border-width: 1px;
align-items: center;
justify-content: center;
border-color: ${props => (props.active ? confirmFontColor : '#e5e5e5')};
background-color: ${props => (props.active ? confirmFontColor : 'transparent')};
`;
export const StyledFooter = styled(Row)`
padding-bottom: ${isIphoneX ? 20 : 0};
margin-top: ${cx(6)}px;
border-bottom-left-radius: ${footerRadius};
border-bottom-right-radius: ${footerRadius};
height: ${props => {
const height = cellHeight(props);
return isIphoneX ? height + 20 : height;
}}px;
`;
export const StyledConfirmButton = styled(TouchableOpacity).attrs({
activeOpacity: 0.8,
})`
flex: 1;
padding: 12px 0;
align-self: stretch;
align-items: center;
justify-content: center;
border-right-width: ${props => (props.bordered ? StyleSheet.hairlineWidth : 0)};
border-right-color: ${lineColor};
background-color: ${props => (props.pressActive ? pressColor : cellBg)};
`;
export const StyledCancelButton = styled(TouchableOpacity).attrs({
activeOpacity: 0.8,
})`
flex: 1;
padding: 12px 0;
align-self: stretch;
align-items: center;
justify-content: center;
background-color: ${props => (props.pressActive ? pressColor : cellBg)};
`;
export const StyledMiddleDivider = styled(View).attrs({})`
width: ${StyleSheet.hairlineWidth};
height: ${props => {
const height = cellHeight(props);
return height - 32;
}}px;
background-color: ${lineColor};
`;
export const StyledCancelText = styled(TYText)`
font-size: ${cancelFontSize};
color: ${cancelFontColor};
`;
export const StyledConfirmText = styled(TYText)`
font-weight: bold;
font-size: ${confirmFontSize};
color: ${confirmFontColor};
`;
export const StyledSubTitleText = styled(TYText)`
font-size: ${props => {
const size = getTheme(props, 'popup.titleFontSize', DEFAULT_LIST_THEME.titleFontSize);
return (size * 6) / 7;
}};
color: ${subTitleFontColor};
margin-top: ${cx(5)}px;
`;
export const StyledTouchView = styled(TouchableOpacity).attrs({
activeOpacity: 0.7,
})`
flex-direction: row;
align-items: center;
justify-content: center;
position: absolute;
left: 12px;
`;
export const StyledBackText = styled(TYText).attrs({
color: backIconColor,
size: titleFontSize,
})`
margin-left: 2px;
`;
export const StyledBackIcon = props => {
/* eslint-disable react/prop-types */
const { color, ...rest } = props;
return (
<ThemeConsumer>
{theme => {
const propsWithTheme = { ...props, theme };
return (
<IconFont
size={cx(18)}
color={
color ||
getTheme(propsWithTheme, 'popup.backIconColor', DEFAULT_LIST_THEME.backIconColor)
}
{...rest}
/>
);
}}
</ThemeConsumer>
);
};
/**
* Popup.picker
*/
export const StyledPickerContainer = styled(View)`
flex-direction: row;
align-items: center;
justify-content: center;
background-color: ${cellBg};
opacity: ${props => (props.disabled ? 0.6 : 1)};
`;
export const StyledPickerUnit = styled(View)`
position: absolute;
top: 0;
align-items: center;
justify-content: center;
`;
export const StyledPickerUnitText = styled(TYText)`
font-size: ${props => getTheme(props, 'picker.unitFontSize', DEFAULT_PICKER_THEME.unitFontSize)};
font-weight: bold;
color: ${props => props.pickerUnitColor || cellFontColor};
`;
/**
* Popup.countdown
*/
export const StyledCountdownContainer = styled(View)`
flex-direction: row;
align-items: center;
padding: 1px 0;
background-color: ${cellBg};
`;
export const StyledCountdownContent = styled(View)`
flex-direction: row;
align-items: center;
margin: 0px 30px;
background-color: ${cellBg};
`;
export const StyledCountdownOnePickerContent = styled(View)`
flex-direction: row;
align-items: center;
background-color: ${cellBg};
`;
export const StyledOverview = styled(View)`
flex-direction: row;
align-items: center;
overflow: hidden;
`;
/**
* Popup.timerPicker
*/
export const StyledTimerPickerContainer = styled(View)`
height: 300px;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 0 24px;
`;
export const StyledTimerPickerRow = styled(View)`
flex: 1;
flex-direction: row;
`;
export const StyledSymbolText = styled(TYText)`
padding: 0 18px;
font-size: ${props => getTheme(props, 'picker.unitFontSize', DEFAULT_PICKER_THEME.unitFontSize)};
color: ${props => getTheme(props, 'picker.unitFontColor', DEFAULT_PICKER_THEME.unitFontColor)};
`;
export const StyledTimerText = styled(TYText)`
flex: 1;
align-items: center;
justify-content: center;
font-size: 12;
text-align: center;
color: ${cellFontColor};
background-color: ${cellBg};
`;
export const StyledTimerPicker = props => {
return (
<ThemeConsumer>
{globalTheme => {
const timerPickerTheme = { ...props, theme: globalTheme };
const fontColor = getTheme(timerPickerTheme, 'popup.cellFontColor');
let timerStyle;
/* eslint-disable react/prop-types */
if (props.style && props.style.backgroundColor) {
timerStyle = props.style;
} else if (props.style) {
timerStyle = {
...props.style,
backgroundColor: getTheme(timerPickerTheme, 'popup.cellBg'),
};
} else {
timerStyle = { backgroundColor: getTheme(timerPickerTheme, 'popup.cellBg') };
}
return (
<View
style={{
backgroundColor: getTheme(timerPickerTheme, 'popup.cellBg'),
}}
>
{props.startTitle && props.endTitle && (
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: cx(30),
position: 'absolute',
top: cx(26),
zIndex: 1,
backgroundColor: getTheme(timerPickerTheme, 'popup.cellBg'),
opacity: props.disabled ? 0.6 : 1,
}}
>
<StyledTimerText style={{ marginLeft: cx(15) }}>{props.startTitle}</StyledTimerText>
<StyledTimerText style={{ marginRight: cx(13) }}>{props.endTitle}</StyledTimerText>
</View>
)}
<TimerPicker
{...props}
pickerFontColor={fontColor}
style={[
isIos && { height: cx(216), marginTop: cx(36) },
!isIos && { height: cx(216), marginTop: cx(57), marginBottom: cx(26) },
timerStyle,
]}
/>
</View>
);
}}
</ThemeConsumer>
);
};
/**
* Popup.numberSelector
*/
export const StyledSliderContent = styled(View)`
padding: 32px 0px;
flex-direction: row;
align-items: center;
justify-content: center;
background-color: ${cellBg};
`;
export const StyledSliderContainer = styled(View)`
height: 56px;
margin-top: 16px;
flex-direction: ${props => props.flexDirection || 'row'};
align-items: center;
justify-content: center;
`;
export const StyledSlider = styled(Slider).attrs({
minimumTrackTintColor: '#0B7CFF',
maximumTrackTintColor: props => getTheme(props, 'popup.numberSelector.maximumTrackTintColor'),
})`
width: ${cx(220)}px;
margin: 0 12px;
`;
export const StyledSliderBtn = styled(Button).attrs({
iconSize: 26,
iconColor: props => getTheme(props, 'popup.numberSelector.cellPlusColor'),
})`
opacity: ${props => (props.disabled ? 0.6 : 1)};
`;
export const StyledDisplayText = styled(TYText).attrs({
numberOfLines: 1,
})`
width: ${cx(200)}; /* 避免显示过长文案 */
text-align: center;
font-weight: 500;
font-size: 56px;
color: ${cellFontColor};
background-color: transparent;
`;
export const StyleDividerView = styled(View)`
background-color: ${cellBg};
`;
export const StyleDivider = styled(View)`
background-color: ${lineColor};
height: ${StyleSheet.hairlineWidth};
`;
/**
* DatePicker
*/
export const StyledDatePicker = props => {
return (
<ThemeConsumer>
{globalTheme => {
const datePickerTheme = { ...props, theme: globalTheme };
const fontColor = getTheme(datePickerTheme, 'popup.cellFontColor');
let dateStyle;
/* eslint-disable react/prop-types */
if (props.style && props.style.backgroundColor) {
dateStyle = props.style;
} else if (props.style) {
dateStyle = {
...props.style,
backgroundColor: getTheme(datePickerTheme, 'popup.cellBg'),
};
} else {
dateStyle = { backgroundColor: getTheme(datePickerTheme, 'popup.cellBg') };
}
return (
<DatePicker
{...props}
pickerFontColor={fontColor}
style={[
!isIos && { height: cx(260), paddingTop: cx(32), paddingBottom: cx(32) },
{ paddingLeft: cx(30), paddingRight: cx(30) },
dateStyle,
]}
/>
);
}}
</ThemeConsumer>
);
};
/**
* Popup.List
*/
export const StyledFlatList = props => {
return (
<ThemeConsumer>
{globalTheme => {
const listTheme = { ...props, theme: globalTheme };
return (
<TYFlatList
ItemSeparatorComponent={() => (
<View style={{ backgroundColor: getTheme(listTheme, 'popup.cellBg') }}>
<View
style={{
backgroundColor: getTheme(listTheme, 'popup.lineColor'),
marginLeft: 16,
marginRight: 16,
height: StyleSheet.hairlineWidth,
}}
/>
</View>
)}
{...props}
/>
);
}}
</ThemeConsumer>
);
};
export const StyledIconFont = props => {
const { color, ...rest } = props;
return (
<ThemeConsumer>
{theme => {
const propsWithTheme = { ...props, theme };
return (
<IconFont
size={cx(28)}
color={
color ||
getTheme(propsWithTheme, 'popup.checkboxColor', DEFAULT_LIST_THEME.checkboxColor)
}
{...rest}
/>
);
}}
</ThemeConsumer>
);
};