添加 ResultBox 组件

This commit is contained in:
2betop 2020-05-14 20:47:05 +08:00
parent 7bbc723b42
commit c4dd46bafc
10 changed files with 396 additions and 106 deletions

View File

@ -1,3 +1,6 @@
import React from 'react';
import ResultBox from '../../../src/components/ResultBox';
export default {
type: 'page',
title: '表单页面',
@ -17,6 +20,38 @@ export default {
label: 'Email',
type: 'email',
name: 'email'
},
{
name: 'checkboxes',
type: 'checkboxes',
joinValues: false,
options: [
{
label: '张学友',
value: 'a'
},
{
label: '刘德华',
value: 'b'
},
{
label: '黎明',
value: 'c'
},
{
label: '郭富城',
value: 'd'
}
]
},
{
label: 'Result',
name: 'checkboxes',
component: ({value, onChange}) => {
return <ResultBox value={value} onChange={onChange} allowInput />;
}
}
]
}

View File

@ -279,3 +279,106 @@
border-color: $active-border;
}
}
@mixin input-clear {
padding: px2rem(3px);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
svg {
fill: $Form-input-iconColor;
top: 0;
width: px2rem(10px);
height: px2rem(10px);
}
&:hover svg {
fill: darken($color: $Form-input-iconColor, $amount: 20%);
}
}
@mixin input-input {
display: flex;
background-color: $Form-input-bg;
border: $Form-input-borderWidth solid $Form-input-borderColor;
border-radius: $Form-input-borderRadius;
// height: $Form-input-height;
line-height: $Form-input-lineHeight;
padding: $Form-input-paddingY $Form-input-paddingX;
font-size: $Form-input-fontSize;
flex-wrap: wrap;
input {
flex-basis: px2rem(80px);
flex-grow: 1;
outline: none;
background: transparent;
border: none;
color: $Form-input-color;
width: 100%;
height: $Form-input-lineHeight * $Form-input-fontSize;
&::placeholder {
color: $Form-input-placeholderColor;
user-select: none;
}
}
}
@mixin input-text {
position: relative;
min-width: $Form-control-widthBase;
&.is-inline {
display: inline-block;
}
&-input {
@include input-input();
}
&.is-error > &-input {
border-color: $Form-input-onError-borderColor;
background-color: $Form-input-onError-bg;
}
&.is-focused > &-input {
border-color: $Form-input-onFocused-borderColor;
box-shadow: $Form-input-boxShadow;
@if $Form-input-onFocused-bg !=$Form-input-bg {
background-color: $Form-input-onFocused-bg;
}
}
&.is-error.is-focused > &-input {
border-color: $Form-input-onError-borderColor;
}
&.is-disabled > &-input {
color: $text--muted-color;
background: $Form-input-onDisabled-bg;
border-color: $Form-input-onDisabled-borderColor;
}
&-spinner {
line-height: $Form-input-lineHeight * $Form-input-fontSize;
}
&-clear {
@include input-clear();
}
// 需要能撑开
@include media-breakpoint-up(sm) {
&.#{$ns}Form-control--sizeXs > &-input,
&.#{$ns}Form-control--sizeSm > &-input,
&.#{$ns}Form-control--sizeMd > &-input,
&.#{$ns}Form-control--sizeLg > &-input {
min-width: 100%;
display: inline-flex;
}
}
}

View File

@ -589,6 +589,14 @@ $Remark-borderColor: $borderColor !default;
$Remark-onHover-borderColor: $borderColor !default;
$Remark-marginLeft: $gap-sm !default;
$ResultBox-value-bg: #f5f5f5 !default;
$ResultBox-value--onHover-bg: #ebebeb !default;
$ResultBox-value-color: #000 !default;
$ResultBox-value--onDisabled-color: #cccccc !default;
$ResultBox-icon-color: #999 !default;
$ResultBox-icon--onHover-color: #666666 !default;
$ResultBox-icon--onDisabled-color: #ebebeb !default;
// Form
$Form-fontSize: $fontSizeBase !default;
$Form-description-color: lighten($text-color, 10%) !default;

View File

@ -0,0 +1,95 @@
.#{$ns}ResultBox {
@include input-input();
flex-wrap: wrap;
padding: 0 3px;
min-height: $Form-input-height;
align-items: center;
&.is-error {
border-color: $Form-input-onError-borderColor;
background-color: $Form-input-onError-bg;
}
&.is-focused {
border-color: $Form-input-onFocused-borderColor;
box-shadow: $Form-input-boxShadow;
@if $Form-input-onFocused-bg !=$Form-input-bg {
background-color: $Form-input-onFocused-bg;
}
}
&.is-error.is-focused {
border-color: $Form-input-onError-borderColor;
}
&.is-disabled {
color: $text--muted-color;
background: $Form-input-onDisabled-bg;
border-color: $Form-input-onDisabled-borderColor;
}
&-clear {
@include input-clear();
}
> svg {
display: inline-block;
width: 14px;
color: $icon-color;
}
> a {
cursor: pointer;
}
&-mid {
flex-grow: 1;
}
&-value {
background: $ResultBox-value-bg;
color: $ResultBox-value-color;
font-size: $Form-input-fontSize;
padding: 0 5px;
min-height: 24px;
flex-wrap: nowrap;
display: inline-flex;
align-items: center;
margin: 2px 3px;
user-select: none;
> a {
cursor: pointer;
margin-left: 5px;
color: $ResultBox-icon-color;
&:hover {
color: $ResultBox-icon--onHover-color;
}
}
&:hover {
background: $ResultBox-value--onHover-bg;
}
&.is-disabled {
pointer-events: none;
color: $ResultBox-value--onDisabled-color;
> a {
color: $ResultBox-icon--onDisabled-color;
}
}
}
&-placeholder {
color: $Form-input-placeholderColor;
user-select: none;
margin-left: 8px;
}
> input {
padding-left: 8px;
min-height: 24px;
}
}

View File

@ -1,106 +1,3 @@
@mixin input-clear {
padding: px2rem(3px);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
svg {
fill: $Form-input-iconColor;
top: 0;
width: px2rem(10px);
height: px2rem(10px);
}
&:hover svg {
fill: darken($color: $Form-input-iconColor, $amount: 20%);
}
}
@mixin input-input {
display: flex;
background-color: $Form-input-bg;
border: $Form-input-borderWidth solid $Form-input-borderColor;
border-radius: $Form-input-borderRadius;
// height: $Form-input-height;
line-height: $Form-input-lineHeight;
padding: $Form-input-paddingY $Form-input-paddingX;
font-size: $Form-input-fontSize;
flex-wrap: wrap;
input {
flex-basis: px2rem(80px);
flex-grow: 1;
outline: none;
background: transparent;
border: none;
color: $Form-input-color;
width: 100%;
height: $Form-input-lineHeight * $Form-input-fontSize;
&::placeholder {
color: $Form-input-placeholderColor;
user-select: none;
}
}
}
@mixin input-text {
position: relative;
min-width: $Form-control-widthBase;
&.is-inline {
display: inline-block;
}
&-input {
@include input-input();
}
&.is-error > &-input {
border-color: $Form-input-onError-borderColor;
background-color: $Form-input-onError-bg;
}
&.is-focused > &-input {
border-color: $Form-input-onFocused-borderColor;
box-shadow: $Form-input-boxShadow;
@if $Form-input-onFocused-bg !=$Form-input-bg {
background-color: $Form-input-onFocused-bg;
}
}
&.is-error.is-focused > &-input {
border-color: $Form-input-onError-borderColor;
}
&.is-disabled > &-input {
color: $text--muted-color;
background: $Form-input-onDisabled-bg;
border-color: $Form-input-onDisabled-borderColor;
}
&-spinner {
line-height: $Form-input-lineHeight * $Form-input-fontSize;
}
&-clear {
@include input-clear();
}
// 需要能撑开
@include media-breakpoint-up(sm) {
&.#{$ns}Form-control--sizeXs > &-input,
&.#{$ns}Form-control--sizeSm > &-input,
&.#{$ns}Form-control--sizeMd > &-input,
&.#{$ns}Form-control--sizeLg > &-input {
min-width: 100%;
display: inline-flex;
}
}
}
.#{$ns}TextControl {
@include input-text();

View File

@ -539,6 +539,8 @@ $Combo--horizontal-dragger-top: px2rem(5px);
@import '../components/carousel';
@import '../components/image-gallery';
@import '../components/images';
@import '../components/input-box';
@import '../components/result-box';
@import '../components/form/fieldset';
@import '../components/form/group';
@ -558,7 +560,7 @@ $Combo--horizontal-dragger-top: px2rem(5px);
@import '../components/form/date';
@import '../components/form/date-range';
@import '../components/form/image';
@import '../components/form/input-box';
@import '../components/form/file';
@import '../components/form/editor';
@import '../components/form/rich-text';

View File

@ -202,6 +202,8 @@ pre {
@import '../components/carousel';
@import '../components/image-gallery';
@import '../components/images';
@import '../components/input-box';
@import '../components/result-box';
@import '../components/form/fieldset';
@import '../components/form/group';
@ -221,7 +223,7 @@ pre {
@import '../components/form/date';
@import '../components/form/date-range';
@import '../components/form/image';
@import '../components/form/input-box';
@import '../components/form/file';
@import '../components/form/editor';
@import '../components/form/rich-text';

View File

@ -67,6 +67,8 @@ $Form-input-borderColor: #cfdadd;
@import '../components/carousel';
@import '../components/image-gallery';
@import '../components/images';
@import '../components/input-box';
@import '../components/result-box';
@import '../components/form/fieldset';
@import '../components/form/group';
@ -86,7 +88,7 @@ $Form-input-borderColor: #cfdadd;
@import '../components/form/date';
@import '../components/form/date-range';
@import '../components/form/image';
@import '../components/form/input-box';
@import '../components/form/file';
@import '../components/form/editor';
@import '../components/form/rich-text';

View File

@ -0,0 +1,146 @@
import {ThemeProps, themeable} from '../theme';
import React from 'react';
import {InputBoxProps} from './InputBox';
import uncontrollable from 'uncontrollable';
import {Icon} from './icons';
import Input from './Input';
import {autobind} from '../utils/helper';
export interface ResultBoxProps
extends ThemeProps,
Omit<InputBoxProps, 'value' | 'onChange'> {
value?: Array<any>;
itemRender: (value: any) => JSX.Element;
onChange?: (value: Array<any>) => void;
allowInput?: boolean;
inputValue?: string;
onInputChange?: (value: string) => void;
}
export class ResultBox extends React.Component<ResultBoxProps> {
static defaultProps: Pick<
ResultBoxProps,
'clearable' | 'placeholder' | 'itemRender'
> = {
clearable: false,
placeholder: '暂无结果',
itemRender: (option: any) => <span>{String(option.label)}</span>
};
state = {
isFocused: false
};
@autobind
clearValue() {
const onChange = this.props.onChange;
onChange && onChange([]);
}
@autobind
handleInputChange(e: React.ChangeEvent<HTMLInputElement>) {
const onInputChange = this.props.onInputChange;
onInputChange && onInputChange(e.currentTarget.value);
}
@autobind
handleFocus(e: any) {
const onFocus = this.props.onFocus;
onFocus && onFocus(e);
this.setState({
isFocused: true
});
}
@autobind
handleBlur(e: any) {
const onBlur = this.props.onBlur;
onBlur && onBlur(e);
this.setState({
isFocused: false
});
}
render() {
const {
className,
classnames: cx,
classPrefix,
clearable,
disabled,
hasError,
value,
placeholder,
result,
children,
itemRender,
onInputChange,
inputValue,
allowInput,
...rest
} = this.props;
const isFocused = this.state.isFocused;
return (
<div
className={cx(
'ResultBox',
className,
isFocused ? 'is-focused' : '',
disabled ? 'is-disabled' : '',
hasError ? 'is-error' : ''
)}
>
{Array.isArray(value) && value.length ? (
value.map((item, index) => (
<div className={cx('ResultBox-value')} key={index}>
<span className={cx('ResultBox-valueLabel')}>
{itemRender(item)}
</span>
<a>
<Icon icon="close" />
</a>
</div>
))
) : allowInput ? null : (
<span className={cx('ResultBox-placeholder')}>
{placeholder || '无'}
</span>
)}
{allowInput ? (
<Input
{...rest}
value={inputValue || ''}
onChange={this.handleInputChange}
placeholder={
Array.isArray(value) && value.length
? '手动输入内容'
: placeholder
}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
) : (
<span className={cx('ResultBox-mid')} />
)}
{clearable && !disabled && Array.isArray(value) && value.length ? (
<a onClick={this.clearValue} className={cx('ResultBox-clear')}>
<Icon icon="close" className="icon" />
</a>
) : null}
{children}
</div>
);
}
}
export default themeable(
uncontrollable(ResultBox, {
value: 'onChange',
inputValue: 'onInputChange'
})
);