Merge pull request #3463 from lghxuelang/feat-checkbox

feat: checkbox组件升级
This commit is contained in:
hsm-lv 2022-03-11 13:15:10 +08:00 committed by GitHub
commit bb4538b9f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 308 additions and 17 deletions

View File

@ -199,7 +199,7 @@ exports[`options:linkage 2`] = `
class="cxd-RadiosControl cxd-Form-control is-inline" class="cxd-RadiosControl cxd-Form-control is-inline"
> >
<label <label
class="cxd-Checkbox cxd-Checkbox--radio cxd-Checkbox--full" class="cxd-Checkbox cxd-Checkbox--radio cxd-Checkbox--full cxd-Checkbox--button--disabled--unchecked"
> >
<input <input
disabled="" disabled=""

View File

@ -67,12 +67,31 @@ order: 8
勾选上例中的勾选框,观察数据域变化,会发现勾选后值为`1`,而取消勾选后为`0` 勾选上例中的勾选框,观察数据域变化,会发现勾选后值为`1`,而取消勾选后为`0`
## 按钮模式
```schema: scope="body"
{
"type": "form",
"debug": true,
"body": [
{
"name": "checkbox",
"type": "checkbox",
"label": "勾选框",
"trueValue": true,
"falseValue": false,
"optionType": "button",
"checked": true
}
]
}
```
## 属性表 ## 属性表
除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置 除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置
| 属性名 | 类型 | 默认值 | 说明 ## 二级标题 | | 属性名 | 类型 | 默认值 | 说明 |
| ---------- | -------- | --------- | ---------------- | | ---------- | -------- | --------- | ---------------- |
| option | `string` | | 选项说明 | | option | `string` | | 选项说明 |
| trueValue | `any` | `true` | 标识真值 | | trueValue | `stringnumberboolean` | `true` | 标识真值 |
| falseValue | `any` | `"false"` | 标识假值 | | falseValue | `stringnumberboolean` | `false` | 标识假值 |
| optionType | `defaultbutton` | `default` | 设置option类型 |

View File

@ -43,6 +43,40 @@ order: 9
] ]
} }
``` ```
## 按钮模式
```schema: scope="body"
{
"type": "form",
"api": "/api/mock2/form/saveForm",
"body": [
{
"name": "checkboxes",
"type": "checkboxes",
"label": "复选框",
"optionType": "button",
"options": [
{
"label": "OptionA",
"value": "a"
},
{
"label": "OptionB",
"value": "b"
},
{
"label": "OptionC",
"value": "c"
},
{
"label": "OptionD",
"value": "d"
}
]
}
]
}
```
## 按列显示 ## 按列显示

View File

@ -493,6 +493,12 @@
--Checkbox-onHover-color: var(--info); --Checkbox-onHover-color: var(--info);
--Checkbox-onDisabled-bg: #e5e7eb; --Checkbox-onDisabled-bg: #e5e7eb;
--Checkbox-onDisabled-color: var(--text--muted-color); --Checkbox-onDisabled-color: var(--text--muted-color);
--Checkbox-inner-onDisabled-bg: #D4D6D9;
--Checkbox-disabled-unchecked-bg: #F2F3F3;
--Checkbox-border-width: var(--Form-input-borderWidth);
--Checkbox-paddingX: #{px2rem(12px)};
--Checkbox-button-height: #{px2rem(32px)};
--Checkbox-button-line-height: #{px2rem(30px)};
--ColorPicker-bg: var(--white); --ColorPicker-bg: var(--white);
--ColorPicker-borderColor: var(--Form-input-borderColor); --ColorPicker-borderColor: var(--Form-input-borderColor);

View File

@ -152,12 +152,123 @@
transition: width var(--animation-duration), transition: width var(--animation-duration),
height var(--animation-duration), transform var(--animation-duration); height var(--animation-duration), transform var(--animation-duration);
border-width: 0 0 px2rem(2px) px2rem(2px); border-width: 0 0 px2rem(2px) px2rem(2px);
transform: translate(-50%, -60%) rotate(-40deg); transform: translate(-50%, -90%) rotate(-40deg);
border-style: solid; border-style: solid;
} }
} }
} }
&--partial.#{$ns}Checkbox--checkbox {
input {
margin-left: calc(var(--Checkbox-size) * -1);
& + i {
border-color: var(--Checkbox-onHover-color);
&:before {
width: var(--Checkbox-inner-size);
height: var(--Checkbox-inner-size);
background: var(--Checkbox-onHover-color);
}
}
&[disabled] + i {
border-color: var(--Checkbox-onDisabled-color);
&:before {
width: var(--Checkbox-inner-size);
height: var(--Checkbox-inner-size);
background: var(--Checkbox-inner-onDisabled-bg);
}
}
&:checked[disabled] + i{
width: var(--Checkbox-inner-size);
height: var(--Checkbox-inner-size);
background: var(--Checkbox-onDisabled-bg);
}
}
}
&--button.#{$ns}Checkbox--checkbox {
text-align: center;
height: var(--Checkbox-button-height);
line-height: var(--Checkbox-button-line-height);
padding-left: var(--Checkbox-paddingX);
padding-right: var(--Checkbox-paddingX);
font-size: var(--fontSizeSm);
border: var(--Checkbox-border-width) solid;
cursor: pointer;
position: relative;
display: inline-block;
background-color: var(--Checkbox-gb);
border-color: var(--Checkbox-color);
margin-right: 0;
&:hover:not(:disabled){
color: var(--Checkbox-onHover-color);
}
input {
&:checked + i {
background: transparent;
top: 0;
left: 0;
width: 0;
height: 0;
border-width: px2rem(8px);
border-color: var(--Checkbox-onHover-color) transparent transparent var(--Checkbox-onHover-color);
border-radius: 0;
&:before {
position: absolute;
top: 0;
left: 0;
width: px2rem(8px);
height: px2rem(6px);
transform: translate(-80%, -120%) rotate(-50deg);
background: transparent;
}
}
&[disabled] + i {
border-color: var(--Checkbox-onDisabled-color);
background: transparent;
&:before {
background: transparent;
}
}
&:checked[disabled] + i {
background: transparent;
border-width: px2rem(8px);
border-color: var(--Checkbox-onHover-color) transparent transparent var(--Checkbox-onHover-color);
}
}
> i {
position: absolute;
top: 0;
left:0;
margin-left: 0;
border: 0;
border-style: solid;
+ span {
max-width: px2rem(100px);
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
}
&--button--checked.#{$ns}Checkbox--checkbox {
border-color: var(--Checkbox-onHover-color);
color: var(--Checkbox-onHover-color);
}
&--button--disabled--unchecked.#{$ns}Checkbox--checkbox {
background: var(--Checkbox-disabled-unchecked-bg);
}
&--radio { &--radio {
padding-left: var(--Radio-size); padding-left: var(--Radio-size);
@ -266,10 +377,20 @@
margin-bottom: var(--Form-label-paddingTop); margin-bottom: var(--Form-label-paddingTop);
} }
.#{$ns}Checkbox--button {
margin-bottom: 0;
}
&.is-inline .#{$ns}Checkbox { &.is-inline .#{$ns}Checkbox {
display: inline-block; display: inline-block;
margin-right: var(--gap-md); margin-right: var(--gap-md);
} }
&.is-inline .#{$ns}Checkbox--button {
display: inline-block;
margin-right: 0;
margin-bottom: 0;
}
} }
.#{$ns}RadiosControl-group, .#{$ns}RadiosControl-group,

View File

@ -16,10 +16,10 @@ interface CheckboxProps {
labelClassName?: string; labelClassName?: string;
className?: string; className?: string;
onChange?: (value: any, shift?: boolean) => void; onChange?: (value: any, shift?: boolean) => void;
value?: any; value?: boolean | string | number;
inline?: boolean; inline?: boolean;
trueValue?: any; trueValue?: boolean | string | number;
falseValue?: any; falseValue?: boolean | string | number;
disabled?: boolean; disabled?: boolean;
readOnly?: boolean; readOnly?: boolean;
checked?: boolean; checked?: boolean;
@ -28,6 +28,7 @@ interface CheckboxProps {
classPrefix: string; classPrefix: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
partial?: boolean; partial?: boolean;
optionType?: 'default' | 'button';
} }
export class Checkbox extends React.Component<CheckboxProps, any> { export class Checkbox extends React.Component<CheckboxProps, any> {
@ -70,14 +71,19 @@ export class Checkbox extends React.Component<CheckboxProps, any> {
checked, checked,
type, type,
name, name,
labelClassName labelClassName,
optionType
} = this.props; } = this.props;
return ( return (
<label <label
className={cx(`Checkbox Checkbox--${type}`, className, { className={cx(`Checkbox Checkbox--${type}`, className, {
'Checkbox--full': !partial, 'Checkbox--full': !partial,
[`Checkbox--${size}`]: size 'Checkbox--partial': partial,
[`Checkbox--${size}`]: size,
'Checkbox--button': optionType === 'button',
'Checkbox--button--checked': optionType === 'button' && checked,
'Checkbox--button--disabled--unchecked': disabled && !checked
})} })}
> >
<input <input

View File

@ -19,12 +19,12 @@ export interface CheckboxControlSchema extends FormBaseControl {
/** /**
* *
*/ */
trueValue?: any; trueValue?: boolean | string | number;
/** /**
* *
*/ */
falseValue?: any; falseValue?: boolean | string | number;
/** /**
* *
@ -35,6 +35,9 @@ export interface CheckboxControlSchema extends FormBaseControl {
* *
*/ */
badge?: BadgeSchema; badge?: BadgeSchema;
partial?: boolean;
optionType?: 'default' | 'button';
checked?: boolean;
} }
export interface CheckboxProps export interface CheckboxProps
@ -89,6 +92,9 @@ export default class CheckboxControl extends React.Component<
onChange, onChange,
disabled, disabled,
render, render,
partial,
optionType,
checked,
classPrefix: ns classPrefix: ns
} = this.props; } = this.props;
@ -101,6 +107,9 @@ export default class CheckboxControl extends React.Component<
falseValue={falseValue} falseValue={falseValue}
disabled={disabled} disabled={disabled}
onChange={(value: any) => this.dispatchChangeEvent(value)} onChange={(value: any) => this.dispatchChangeEvent(value)}
partial={partial}
optionType={optionType}
checked={checked}
> >
{option ? render('option', option) : null} {option ? render('option', option) : null}
</Checkbox> </Checkbox>

View File

@ -56,6 +56,7 @@ export interface CheckboxesProps
createBtnLabel: string; createBtnLabel: string;
editable?: boolean; editable?: boolean;
removable?: boolean; removable?: boolean;
optionType?: 'default' | 'button'
} }
export default class CheckboxesControl extends React.Component< export default class CheckboxesControl extends React.Component<
@ -68,7 +69,8 @@ export default class CheckboxesControl extends React.Component<
placeholder: 'placeholder.noOption', placeholder: 'placeholder.noOption',
creatable: false, creatable: false,
inline: true, inline: true,
createBtnLabel: 'Select.createLabel' createBtnLabel: 'Select.createLabel',
optionType: 'default'
}; };
reload() { reload() {
@ -98,6 +100,97 @@ export default class CheckboxesControl extends React.Component<
onDelete && onDelete(item); onDelete && onDelete(item);
} }
componentDidMount() {
this.updateBorderStyle();
window.addEventListener('resize', this.updateBorderStyle);
}
componentWillMount() {
window.removeEventListener('resize', this.updateBorderStyle);
}
@autobind
updateBorderStyle() {
if (this.props.optionType !== 'button') {
return;
}
const wrapDom = this.refs.checkboxRef as HTMLElement;
const wrapWidth = wrapDom.clientWidth;
const childs = Array.from(wrapDom.children) as HTMLElement[];
childs.forEach(child => {
child.style.borderRadius = '0';
child.style.borderLeftWidth = '1px';
child.style.borderTopWidth = '1px';
});
const childTotalWidth = childs.reduce((pre, next) =>
pre + next.clientWidth, 0);
if (childTotalWidth <= wrapWidth) {
if (childs.length === 1) {
childs[0].style.borderRadius = "4px";
}
else {
childs[0].style.borderRadius = "4px 0 0 4px";
childs[childs.length - 1].style.borderRadius = "0 4px 4px 0";
childs.forEach((child, idx) => {
idx !== 0 && (child.style.borderLeftWidth = '0');
});
}
}
else {
let curRowWidth = 0;
let curRow = 0;
const rowNum = Math.floor(childTotalWidth / wrapWidth);
const rowColArr: any[] = [];
for (let i = 0; i <= rowNum; i++) {
const arr: HTMLElement[] = [];
rowColArr[i] = arr;
}
childs.forEach((child: HTMLElement, idx: number) => {
curRowWidth += child.clientWidth;
if (curRowWidth > wrapWidth) {
curRowWidth = child.clientWidth;
curRow++;
}
if (curRow > rowNum) {
return;
}
rowColArr[curRow].push(child);
});
rowColArr.forEach((row: HTMLElement[], rowIdx: number) => {
if (rowIdx === 0) {
row.forEach((r: HTMLElement, colIdx: number) => {
r.style.borderRadius = '0';
colIdx !== 0 && (r.style.borderLeftWidth = '0');
row.length > rowColArr[rowIdx + 1].length
&& (row[row.length - 1].style.borderBottomRightRadius = "4px");
});
row[0].style.borderTopLeftRadius = "4px";
row[row.length - 1].style.borderTopRightRadius = "4px";
}
else if (rowIdx === rowNum) {
row.forEach((r: HTMLElement, colIdx: number) => {
r.style.borderRadius = '0';
colIdx !== 0 && (r.style.borderLeftWidth = '0');
r.style.borderTopWidth = '0';
row[0].style.borderBottomLeftRadius = "4px";
row[row.length - 1].style.borderBottomRightRadius = "4px";
});
}
else {
row.forEach((r: HTMLElement, colIdx: number) => {
r.style.borderRadius = '0';
colIdx !== 0 && (r.style.borderLeftWidth = '0');
r.style.borderTopWidth = '0';
row.length > rowColArr[rowIdx + 1].length
&& (row[row.length - 1].style.borderBottomRightRadius = "4px");
});
}
});
}
}
renderGroup(option: Option, index: number) { renderGroup(option: Option, index: number) {
const {classnames: cx, labelField} = this.props; const {classnames: cx, labelField} = this.props;
@ -136,7 +229,8 @@ export default class CheckboxesControl extends React.Component<
labelField, labelField,
removable, removable,
editable, editable,
translate: __ translate: __,
optionType
} = this.props; } = this.props;
return ( return (
@ -149,6 +243,7 @@ export default class CheckboxesControl extends React.Component<
inline={inline} inline={inline}
labelClassName={labelClassName} labelClassName={labelClassName}
description={option.description} description={option.description}
optionType={optionType}
> >
{String(option[labelField || 'label'])} {String(option[labelField || 'label'])}
{removable && hasAbility(option, 'removable') ? ( {removable && hasAbility(option, 'removable') ? (
@ -191,7 +286,8 @@ export default class CheckboxesControl extends React.Component<
creatable, creatable,
addApi, addApi,
createBtnLabel, createBtnLabel,
translate: __ translate: __,
optionType
} = this.props; } = this.props;
let body: Array<React.ReactNode> = []; let body: Array<React.ReactNode> = [];
@ -200,7 +296,7 @@ export default class CheckboxesControl extends React.Component<
body = options.map((option, key) => this.renderItem(option, key)); body = options.map((option, key) => this.renderItem(option, key));
} }
if (checkAll && body.length) { if (checkAll && body.length && optionType === 'default') {
body.unshift( body.unshift(
<Checkbox <Checkbox
key="checkall" key="checkall"
@ -225,7 +321,7 @@ export default class CheckboxesControl extends React.Component<
body = columnsSplit(body, cx, columnsCount); body = columnsSplit(body, cx, columnsCount);
return ( return (
<div className={cx(`CheckboxesControl`, className)}> <div className={cx(`CheckboxesControl`, className)} ref="checkboxRef">
{body && body.length ? ( {body && body.length ? (
body body
) : ( ) : (