Skip to content

Commit

Permalink
feat: implement steps
Browse files Browse the repository at this point in the history
  • Loading branch information
huang-xiao-jian committed May 30, 2020
1 parent d3d9031 commit 9fdb04c
Show file tree
Hide file tree
Showing 5 changed files with 347 additions and 0 deletions.
143 changes: 143 additions & 0 deletions packages/Steps/Steps.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
.van-steps {
overflow: hidden;
background-color: #fff;
background-color: var(--steps-background-color, #fff);
}
.van-steps--horizontal {
padding: 10px;
}
.van-steps--horizontal .van-step__wrapper {
position: relative;
display: flex;
overflow: hidden;
}
.van-steps--vertical {
padding-left: 10px;
}
.van-steps--vertical .van-step__wrapper {
padding: 0 0 0 20px;
}
.van-step {
position: relative;
flex: 1;
font-size: 14px;
font-size: var(--step-font-size, 14px);
color: #969799;
color: var(--step-text-color, #969799);
}
.van-step--finish {
color: #323233;
color: var(--step-finish-text-color, #323233);
}
.van-step__circle {
border-radius: 50%;
width: 5px;
width: var(--step-circle-size, 5px);
height: 5px;
height: var(--step-circle-size, 5px);
background-color: #969799;
background-color: var(--step-circle-color, #969799);
}
.van-step--horizontal {
padding-bottom: 14px;
}
.van-step--horizontal:first-child .van-step__title {
transform: none;
}
.van-step--horizontal:first-child .van-step__circle-container {
padding: 0 8px 0 0;
transform: translate3d(0, 50%, 0);
}
.van-step--horizontal:last-child {
position: absolute;
right: 0;
width: auto;
}
.van-step--horizontal:last-child .van-step__title {
text-align: right;
transform: none;
}
.van-step--horizontal:last-child .van-step__circle-container {
right: 0;
padding: 0 0 0 8px;
transform: translate3d(0, 50%, 0);
}
.van-step--horizontal .van-step__circle-container {
position: absolute;
bottom: 6px;
z-index: 1;
transform: translate3d(-50%, 50%, 0);
background-color: #fff;
background-color: var(--white, #fff);
padding: 0 8px;
padding: 0 var(--padding-xs, 8px);
}
.van-step--horizontal .van-step__title {
display: inline-block;
transform: translate3d(-50%, 0, 0);
font-size: 12px;
font-size: var(--step-horizontal-title-font-size, 12px);
}
.van-step--horizontal .van-step__line {
position: absolute;
right: 0;
bottom: 6px;
left: 0;
height: 1px;
transform: translate3d(0, 50%, 0);
background-color: #ebedf0;
background-color: var(--step-line-color, #ebedf0);
}
.van-step--horizontal.van-step--process {
color: #323233;
color: var(--step-process-text-color, #323233);
}
.van-step--horizontal.van-step--process .van-step__icon {
display: block;
line-height: 1;
font-size: 12px;
font-size: var(--step-icon-size, 12px);
}
.van-step--vertical {
padding: 10px 10px 10px 0;
line-height: 18px;
}
.van-step--vertical::after {
border-bottom-width: 1px;
}
.van-step--vertical:last-child::after {
border-bottom-width: none;
}
.van-step--vertical:first-child::before {
position: absolute;
top: 0;
left: -15px;
z-index: 1;
width: 1px;
height: 20px;
content: '';
background-color: #fff;
background-color: var(--white, #fff);
}
.van-step--vertical .van-step__icon,
.van-step--vertical .van-step__circle,
.van-step--vertical .van-step__line {
position: absolute;
top: 19px;
left: -14px;
z-index: 2;
transform: translate3d(-50%, -50%, 0);
}
.van-step--vertical .van-step__icon {
line-height: 1;
font-size: 12px;
font-size: var(--step-icon-size, 12px);
}
.van-step--vertical .van-step__line {
z-index: 1;
width: 1px;
height: 100%;
transform: translate3d(-50%, 0, 0);
background-color: #ebedf0;
background-color: var(--step-line-color, #ebedf0);
}
141 changes: 141 additions & 0 deletions packages/Steps/Steps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// packages
import React, { FunctionComponent, CSSProperties, ReactElement } from 'react';
import clsx from 'clsx';
import { View } from 'remax/wechat';
// internal
import Icon from '../Icon';
import withDefaultProps from '../tools/with-default-props-advance';
import pickStyle from '../tools/pick-style';
import './Steps.css';

interface StepItem {
text: string;
desc: string;
}

// 默认值填充属性
interface NeutralStepsProps {
active: number;
direction: 'horizontal' | 'vertical';
activeColor: string;
inactiveColor: string;
// 自定义图标占位
renderActiveCircle: (color: string) => ReactElement;
renderInactiveCircel: (color: string) => ReactElement;
}

interface ExogenousStepsProps {
// 步骤定义
steps: StepItem[];
onClickStep?: (event: { detail: number }) => void;
// 容器类名,用以覆盖内部
className?: string;
}

type StepsProps = NeutralStepsProps & ExogenousStepsProps;

const DefaultStepsProps: NeutralStepsProps = {
active: 0,
direction: 'horizontal',
activeColor: '#07c160',
inactiveColor: '#969799',
// 默认渲染逻辑,平行移植 vant-weapp,.van-step__icon
renderActiveCircle: (color) => (
<Icon name="checked" className="van-step__icon" color={color} />
),
renderInactiveCircel: (color) => (
<View
className="van-step__circle"
style={{
backgroundColor: color,
}}
/>
),
};

const Steps: FunctionComponent<StepsProps> = (props) => {
const {
className,
direction,
steps,
active,
activeColor,
inactiveColor,
} = props;
const classnames = {
container: clsx(className, 'van-steps', `van-steps--${direction}`),
};
const children = steps.map((step, index) => {
const { onClickStep, renderActiveCircle, renderInactiveCircel } = props;
// 派生状态
const status =
// eslint-disable-next-line no-nested-ternary
index < active ? 'finish' : index === active ? 'process' : 'inactive';
const styles: Record<'container' | 'title' | 'line', CSSProperties> = {
container: {
color: status === 'inactive' ? inactiveColor : undefined,
},
title: {
color: status === 'process' ? activeColor : undefined,
},
line: {
backgroundColor: status === 'finish' ? activeColor : inactiveColor,
},
};
const classNameStep = clsx(
'van-step',
'van-hairline',
`van-step--${direction}`,
`van-step--${status}`
);
// 新增 van-step__title-text,van-step__title-desc 便于样式覆盖
const title = (
<View className="van-step__title" style={pickStyle(styles.title)}>
<View className="van-step__title-text">{step.text}</View>
<View className="van-step__title-desc">{step.desc}</View>
</View>
);
const currentColor = status === 'inactive' ? inactiveColor : activeColor;
const circle = (
<View className="van-step__circle-container">
{index === active
? renderActiveCircle(currentColor)
: renderInactiveCircel(currentColor)}
</View>
);
// 非末尾填充线条
const line = index !== steps.length - 1 && (
<View style={pickStyle(styles.line)} className="van-step__line" />
);
// 事件绑定
const onClick = () => {
if (typeof onClickStep === 'function') {
onClickStep({ detail: index });
}
};

return (
/* eslint-disable react/no-array-index-key */
<View
key={index}
style={pickStyle(styles.container)}
className={classNameStep}
onClick={onClick}
>
{title}
{circle}
{line}
</View>
);
});

return (
<View className={classnames.container}>
<View className="van-step__wrapper">{children}</View>
</View>
);
};

export default withDefaultProps<ExogenousStepsProps, NeutralStepsProps>(
DefaultStepsProps
)(Steps);
4 changes: 4 additions & 0 deletions packages/Steps/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* @description - nothing but export component
*/
export { default } from './Steps';
1 change: 1 addition & 0 deletions public/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AppConfig } from 'remax/wechat';

const config: AppConfig = {
pages: [
'pages/steps/index',
'pages/progress/index',
'pages/divider/index',
'pages/grid/index',
Expand Down
58 changes: 58 additions & 0 deletions public/pages/steps/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// packages
import React, { useState } from 'react';
import { View, Text } from 'remax/wechat';

// internal
import Steps from '../../../packages/Steps';
import Icon from '../../../packages/Icon';

export default () => {
const [active, setActive] = useState(0);
const steps = [
{
text: '步骤一',
desc: '描述信息',
},
{
text: '步骤二',
desc: '描述信息',
},
{
text: '步骤三',
desc: '描述信息',
},
{
text: '步骤四',
desc: '描述信息',
},
];

return (
<View className="demo-block">
<Text className="demo-block__title">基础用法</Text>
<View>
<Steps
steps={steps}
active={active}
onClickStep={(event) => setActive(event.detail)}
/>
</View>
<Text className="demo-block__title">竖向步骤条</Text>
<View>
<Steps direction="vertical" steps={steps} active={active} />
</View>
<Text className="demo-block__title">自定义样式</Text>
<View>
<Steps
steps={steps}
active={active}
activeColor="#ee0a24"
renderActiveCircle={(color) => <Icon name="success" color={color} />}
renderInactiveCircel={(color) => (
<Icon name="clock-o" color={color} />
)}
/>
</View>
</View>
);
};

0 comments on commit 9fdb04c

Please sign in to comment.