feat: checkbox\radios支持外观配置 (#11095)

Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>
This commit is contained in:
qkiroc 2024-10-28 14:42:04 +08:00 committed by GitHub
parent dc8dcc6828
commit 75b3e03b29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 451 additions and 48 deletions

View File

@ -21,6 +21,7 @@ import {ValidatorTag} from '../../validator';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core'; import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
import {getEventControlConfig} from '../../renderer/event-control/helper'; import {getEventControlConfig} from '../../renderer/event-control/helper';
import omit from 'lodash/omit'; import omit from 'lodash/omit';
import {inputStateTpl} from '../../renderer/style-control/helper';
setSchemaTpl('option', { setSchemaTpl('option', {
name: 'option', name: 'option',
@ -45,7 +46,8 @@ export class CheckboxControlPlugin extends BasePlugin {
scaffold = { scaffold = {
type: 'checkbox', type: 'checkbox',
option: '勾选框', option: '勾选框',
name: 'checkbox' name: 'checkbox',
label: '勾选框'
}; };
previewSchema: any = { previewSchema: any = {
type: 'form', type: 'form',
@ -227,7 +229,70 @@ export class CheckboxControlPlugin extends BasePlugin {
title: '外观', title: '外观',
body: [ body: [
getSchemaTpl('collapseGroup', [ getSchemaTpl('collapseGroup', [
getSchemaTpl('style:formItem', {renderer: context.info.renderer}), getSchemaTpl('theme:formItem', {hidSize: true}),
getSchemaTpl('theme:form-label'),
getSchemaTpl('theme:form-description'),
{
title: '勾选框样式',
body: [
...inputStateTpl('themeCss.checkboxClassName', '--checkbox', {
hideFont: true,
hideMargin: true,
hidePadding: true,
state: [
{
label: '常规',
value: 'checkbox-default'
},
{
label: '悬浮',
value: 'checkbox-hover'
},
{
label: '禁用',
value: 'checkbox-disabled'
},
{
label: '选中',
value: 'checked-default'
},
{
label: '选中态悬浮',
value: 'checked-hover'
},
{
label: '选中禁用',
value: 'checked-disabled'
}
]
})
]
},
{
title: '选项说明样式',
body: [
...inputStateTpl('themeCss.checkboxLabelClassName', '', {
hidePadding: true,
hideRadius: true,
hideBorder: true,
state: [
{
label: '常规',
value: 'default'
},
{
label: '悬浮',
value: 'hover'
},
{
label: '禁用',
value: 'disabled'
}
]
})
]
},
getSchemaTpl('theme:cssCode'),
getSchemaTpl('style:classNames') getSchemaTpl('style:classNames')
]) ])
] ]

View File

@ -13,6 +13,7 @@ import {getEventControlConfig} from '../../renderer/event-control/helper';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core'; import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
import {resolveOptionEventDataSchame, resolveOptionType} from '../../util'; import {resolveOptionEventDataSchame, resolveOptionType} from '../../util';
import type {Schema, SchemaType} from 'amis'; import type {Schema, SchemaType} from 'amis';
import {inputStateTpl} from '../../renderer/style-control/helper';
export class RadiosControlPlugin extends BasePlugin { export class RadiosControlPlugin extends BasePlugin {
static id = 'RadiosControlPlugin'; static id = 'RadiosControlPlugin';
@ -157,8 +158,8 @@ export class RadiosControlPlugin extends BasePlugin {
title: '外观', title: '外观',
body: [ body: [
getSchemaTpl('collapseGroup', [ getSchemaTpl('collapseGroup', [
getSchemaTpl('style:formItem', { getSchemaTpl('theme:formItem', {
renderer: context.info.renderer, hidSize: true,
schema: [ schema: [
getSchemaTpl('switch', { getSchemaTpl('switch', {
label: '一行选项显示', label: '一行选项显示',
@ -177,6 +178,92 @@ export class RadiosControlPlugin extends BasePlugin {
} }
] ]
}), }),
getSchemaTpl('theme:form-label'),
getSchemaTpl('theme:form-description'),
{
title: '单选框样式',
body: [
...inputStateTpl('themeCss.radiosClassName', '--radio', {
hideFont: true,
hideMargin: true,
hidePadding: true,
state: [
{
label: '常规',
value: 'radios-default'
},
{
label: '悬浮',
value: 'radios-hover'
},
{
label: '禁用',
value: 'radios-disabled'
},
{
label: '选中',
value: 'checked-default'
},
{
label: '选中态悬浮',
value: 'checked-hover'
},
{
label: '选中禁用',
value: 'checked-disabled'
}
],
schema: [
getSchemaTpl('theme:colorPicker', {
name: 'themeCss.radiosCheckedInnerClassName.background:default',
labelMode: 'input',
label: '圆点颜色',
visibleOn:
"${__editorStatethemeCss.radiosClassName == 'checked-default'}"
}),
getSchemaTpl('theme:colorPicker', {
name: 'themeCss.radiosCheckedInnerClassName.background:hover',
labelMode: 'input',
label: '圆点颜色',
visibleOn:
"${__editorStatethemeCss.radiosClassName == 'checked-hover'}"
}),
getSchemaTpl('theme:colorPicker', {
name: 'themeCss.radiosCheckedInnerClassName.background:disabled',
labelMode: 'input',
label: '圆点颜色',
visibleOn:
"${__editorStatethemeCss.radiosClassName == 'checked-disabled'}"
})
]
})
]
},
{
title: '选项说明样式',
body: [
...inputStateTpl('themeCss.radiosLabelClassName', '', {
hidePadding: true,
hideRadius: true,
hideBorder: true,
state: [
{
label: '常规',
value: 'default'
},
{
label: '悬浮',
value: 'hover'
},
{
label: '禁用',
value: 'disabled'
}
]
})
]
},
getSchemaTpl('theme:cssCode'),
getSchemaTpl('style:classNames', { getSchemaTpl('style:classNames', {
schema: [ schema: [
getSchemaTpl('className', { getSchemaTpl('className', {

View File

@ -1,21 +1,23 @@
import {getSchemaTpl} from 'amis-editor-core'; import {getSchemaTpl} from 'amis-editor-core';
interface InputStateOptions {
state?: {
label: string;
value: string;
token?: string;
}[];
hideFont?: boolean;
hidePadding?: boolean;
hideMargin?: boolean;
hideRadius?: boolean;
hideBackground?: boolean;
hideBorder?: boolean;
schema?: any[];
}
export const inputStateTpl = ( export const inputStateTpl = (
className: string, className: string,
token: string = '', token: string = '',
options?: { options?: InputStateOptions
state?: {
label: string;
value: string;
token?: string;
}[];
hideFont?: boolean;
hidePadding?: boolean;
hideMargin?: boolean;
hideRadius?: boolean;
hideBackground?: boolean;
hideBorder?: boolean;
}
) => { ) => {
const stateOptions = options?.state || [ const stateOptions = options?.state || [
{ {
@ -67,7 +69,7 @@ export const inputStateFunc = (
state: string, state: string,
className: string, className: string,
token: string, token: string,
options: any options?: InputStateOptions
) => { ) => {
const cssTokenState = state === 'focused' ? 'active' : state; const cssTokenState = state === 'focused' ? 'active' : state;

View File

@ -127,6 +127,13 @@
vertical-align: top; vertical-align: top;
} }
&--flex {
margin: calc(var(--Form-item-gap) / 2);
&:last-child {
margin-bottom: calc(var(--Form-item-gap) / 2);
}
}
&--inline { &--inline {
margin-right: var(--Form-mode-inline-item-gap); margin-right: var(--Form-mode-inline-item-gap);
} }
@ -428,7 +435,6 @@
flex-basis: 0; flex-basis: 0;
flex-grow: 1; flex-grow: 1;
flex-shrink: 1; flex-shrink: 1;
padding: calc(var(--Form-item-gap) / 2);
min-width: 0; min-width: 0;
min-height: 0; min-height: 0;
} }

View File

@ -4,7 +4,9 @@ import {
FormControlProps, FormControlProps,
FormBaseControl, FormBaseControl,
resolveEventData, resolveEventData,
getVariable getVariable,
setThemeClassName,
CustomStyle
} from 'amis-core'; } from 'amis-core';
import cx from 'classnames'; import cx from 'classnames';
import {Checkbox} from 'amis-ui'; import {Checkbox} from 'amis-ui';
@ -128,6 +130,29 @@ export default class CheckboxControl extends React.Component<
); );
} }
formateThemeCss(themeCss: any) {
if (!themeCss) {
return {};
}
const {checkboxClassName = {}} = themeCss;
const defaultThemeCss: any = {};
const checkedThemeCss: any = {};
Object.keys(checkboxClassName).forEach(key => {
if (key.includes('checked-')) {
const newKey = key.replace('checked-', '');
checkedThemeCss[newKey] = checkboxClassName[key];
} else if (key.includes('checkbox-')) {
const newKey = key.replace('checkbox-', '');
defaultThemeCss[newKey] = checkboxClassName[key];
}
});
return {
...themeCss,
checkboxClassName: defaultThemeCss,
checkboxCheckedClassName: checkedThemeCss
};
}
@supportStatic() @supportStatic()
render() { render() {
const { const {
@ -145,11 +170,39 @@ export default class CheckboxControl extends React.Component<
checked, checked,
labelClassName, labelClassName,
testIdBuilder, testIdBuilder,
classPrefix: ns classPrefix: ns,
id,
env,
themeCss
} = this.props; } = this.props;
const css = this.formateThemeCss(themeCss);
return ( return (
<div className={cx(`${ns}CheckboxControl`, className)}> <div
className={cx(
`${ns}CheckboxControl`,
className,
setThemeClassName({
...this.props,
name: 'checkboxClassName',
id,
themeCss: css
}),
setThemeClassName({
...this.props,
name: 'checkboxCheckedClassName',
id,
themeCss: css
}),
setThemeClassName({
...this.props,
name: 'checkboxLabelClassName',
id,
themeCss: css
})
)}
>
<Checkbox <Checkbox
inline inline
value={value || ''} value={value || ''}
@ -165,6 +218,64 @@ export default class CheckboxControl extends React.Component<
> >
{option ? render('option', option) : null} {option ? render('option', option) : null}
</Checkbox> </Checkbox>
<CustomStyle
{...this.props}
config={{
themeCss: this.formateThemeCss(themeCss),
classNames: [
{
key: 'checkboxClassName',
weights: {
default: {
suf: ' label',
inner: 'i'
},
hover: {
suf: ' label',
inner: 'i'
},
disabled: {
inner: `.${ns}Checkbox--checkbox input[disabled] + i`
}
}
},
{
key: 'checkboxCheckedClassName',
weights: {
default: {
inner: `.${ns}Checkbox--checkbox input:checked + i`
},
hover: {
suf: ` .${ns}Checkbox--checkbox`,
inner: 'input:checked + i'
},
disabled: {
inner: `.${ns}Checkbox--checkbox input:checked[disabled] + i`
}
}
},
{
key: 'checkboxLabelClassName',
weights: {
default: {
suf: ' label',
inner: 'span'
},
hover: {
suf: ' label',
inner: 'span'
},
disabled: {
inner: `.${ns}Checkbox--checkbox input[disabled] + i + span`
}
}
}
],
id: id
}}
env={env}
/>
</div> </div>
); );
} }

View File

@ -343,7 +343,7 @@ export default class CheckboxesControl extends React.Component<
if (!themeCss) { if (!themeCss) {
return {}; return {};
} }
const {checkboxesClassName} = themeCss; const {checkboxesClassName = {}} = themeCss;
const defaultThemeCss: any = {}; const defaultThemeCss: any = {};
const checkedThemeCss: any = {}; const checkedThemeCss: any = {};
Object.keys(checkboxesClassName).forEach(key => { Object.keys(checkboxesClassName).forEach(key => {

View File

@ -8,7 +8,9 @@ import {
FormOptionsControl, FormOptionsControl,
resolveEventData, resolveEventData,
TestIdBuilder, TestIdBuilder,
getVariable getVariable,
setThemeClassName,
CustomStyle
} from 'amis-core'; } from 'amis-core';
import {autobind, isEmpty, createObject} from 'amis-core'; import {autobind, isEmpty, createObject} from 'amis-core';
import {ActionObject} from 'amis-core'; import {ActionObject} from 'amis-core';
@ -105,6 +107,30 @@ export default class RadiosControl extends React.Component<RadiosProps, any> {
return <>{typeof label === 'string' ? filter(label, data) : `${label}`}</>; return <>{typeof label === 'string' ? filter(label, data) : `${label}`}</>;
} }
formateThemeCss(themeCss: any) {
if (!themeCss) {
return {};
}
const {radiosClassName = {}} = themeCss;
const defaultThemeCss: any = {};
const checkedThemeCss: any = {};
Object.keys(radiosClassName).forEach(key => {
if (key.includes('checked-')) {
const newKey = key.replace('checked-', '');
checkedThemeCss[newKey] = radiosClassName[key];
} else if (key.includes('radios-')) {
const newKey = key.replace('radios-', '');
defaultThemeCss[newKey] = radiosClassName[key];
}
});
return {
...themeCss,
radiosClassName: defaultThemeCss,
radiosCheckedClassName: checkedThemeCss
};
}
@supportStatic() @supportStatic()
render() { render() {
const { const {
@ -132,33 +158,139 @@ export default class RadiosControl extends React.Component<RadiosProps, any> {
translate: __, translate: __,
optionType, optionType,
level, level,
testIdBuilder testIdBuilder,
themeCss,
id,
env
} = this.props; } = this.props;
const css = this.formateThemeCss(themeCss);
return ( return (
<Radios <>
inline={inline || formMode === 'inline'} <Radios
className={cx(`${ns}RadiosControl`, className)} inline={inline || formMode === 'inline'}
value={typeof value === 'undefined' || value === null ? '' : value} className={cx(
disabled={disabled} `${ns}RadiosControl`,
onChange={this.handleChange} className,
joinValues={joinValues} setThemeClassName({
extractValue={extractValue!} ...this.props,
delimiter={delimiter!} name: 'radiosClassName',
/** 兼容一下错误的用法 */ id,
labelClassName={optionClassName ?? labelClassName} themeCss: css
labelField={labelField} }),
valueField={valueField} setThemeClassName({
placeholder={__(placeholder)} ...this.props,
options={options} name: 'radiosCheckedInnerClassName',
renderLabel={this.renderLabel} id,
columnsCount={columnsCount} themeCss: css
classPrefix={classPrefix} }),
itemClassName={itemClassName} setThemeClassName({
optionType={optionType} ...this.props,
level={level} name: 'radiosCheckedClassName',
testIdBuilder={testIdBuilder} id,
/> themeCss: css
}),
setThemeClassName({
...this.props,
name: 'radiosLabelClassName',
id,
themeCss: css
})
)}
value={typeof value === 'undefined' || value === null ? '' : value}
disabled={disabled}
onChange={this.handleChange}
joinValues={joinValues}
extractValue={extractValue!}
delimiter={delimiter!}
/** 兼容一下错误的用法 */
labelClassName={optionClassName ?? labelClassName}
labelField={labelField}
valueField={valueField}
placeholder={__(placeholder)}
options={options}
renderLabel={this.renderLabel}
columnsCount={columnsCount}
classPrefix={classPrefix}
itemClassName={itemClassName}
optionType={optionType}
level={level}
testIdBuilder={testIdBuilder}
/>
<CustomStyle
{...this.props}
config={{
themeCss: this.formateThemeCss(themeCss),
classNames: [
{
key: 'radiosClassName',
weights: {
default: {
suf: ' label',
inner: 'i'
},
hover: {
suf: ' label',
inner: 'i'
},
disabled: {
inner: `.${ns}Checkbox--radio input[disabled] + i`
}
}
},
{
key: 'radiosCheckedClassName',
weights: {
default: {
inner: `.${ns}Checkbox--radio input:checked + i`
},
hover: {
suf: ` .${ns}Checkbox--radio`,
inner: 'input:checked + i'
},
disabled: {
inner: `.${ns}Checkbox--radio input:checked[disabled] + i`
}
}
},
{
key: 'radiosCheckedInnerClassName',
weights: {
default: {
inner: `.${ns}Checkbox--radio input:checked + i:before`
},
hover: {
suf: ` .${ns}Checkbox--radio`,
inner: 'input:checked + i:before'
},
disabled: {
inner: `.${ns}Checkbox--radio input:checked[disabled] + i:before`
}
}
},
{
key: 'radiosLabelClassName',
weights: {
default: {
suf: ' label',
inner: 'span'
},
hover: {
suf: ' label',
inner: 'span'
},
disabled: {
inner: `.${ns}Checkbox--radio input[disabled] + i + span`
}
}
}
],
id: id
}}
env={env}
/>
</>
); );
} }
} }