feat: 编辑器【链式下拉框】、【下拉按钮】支持新版外观配置 (#11026)

* feat: 编辑器链式下拉框支持新版外观配置

* feat: 下拉按钮支持外观配置

---------

Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>
This commit is contained in:
qkiroc 2024-10-15 13:55:49 +08:00 committed by GitHub
parent 7f3aa7e39b
commit 0d5606c5b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 286 additions and 65 deletions

View File

@ -13,6 +13,7 @@ import {getEventControlConfig} from '../renderer/event-control/helper';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
import type {SchemaObject} from 'amis';
import {getOldActionSchema} from '../renderer/event-control/helper';
import {buttonStateFunc} from '../renderer/style-control/helper';
export class ButtonPlugin extends BasePlugin {
static id = 'ButtonPlugin';
@ -133,56 +134,6 @@ export class ButtonPlugin extends BasePlugin {
// const isInDropdown = /(?:\/|^)dropdown-button\/.+$/.test(context.path);
const isInDropdown = /^button-group\/.+$/.test(context.path);
const buttonStateFunc = (visibleOn: string, state: string) => {
return [
getSchemaTpl('theme:font', {
label: '文字',
name: `themeCss.className.font:${state}`,
visibleOn: visibleOn,
editorValueToken: {
'color': `--button-\${level || "default"}-${state}-font-color`,
'*': '--button-size-${size || "default"}'
},
state
}),
getSchemaTpl('theme:colorPicker', {
label: '背景',
name: `themeCss.className.background:${state}`,
labelMode: 'input',
needGradient: true,
needImage: true,
visibleOn: visibleOn,
editorValueToken: `--button-\${level || "default"}-${state}-bg-color`,
state
}),
getSchemaTpl('theme:border', {
name: `themeCss.className.border:${state}`,
visibleOn: visibleOn,
editorValueToken: `--button-\${level || "default"}-${state}`,
state
}),
getSchemaTpl('theme:paddingAndMargin', {
name: `themeCss.className.padding-and-margin:${state}`,
visibleOn: visibleOn,
editorValueToken: '--button-size-${size || "default"}',
state
}),
getSchemaTpl('theme:radius', {
name: `themeCss.className.radius:${state}`,
visibleOn: visibleOn,
editorValueToken: '--button-size-${size || "default"}',
state
}),
getSchemaTpl('theme:select', {
label: '图标尺寸',
name: `themeCss.iconClassName.iconSize:${state}`,
visibleOn: visibleOn,
editorValueToken: '--button-size-${size || "default"}-icon-size',
state
})
];
};
return getSchemaTpl('tabs', [
{
title: '属性',

View File

@ -13,6 +13,7 @@ import {
diff
} from 'amis-editor-core';
import {BUTTON_DEFAULT_ACTION} from '../component/BaseControl';
import {buttonStateFunc} from '../renderer/style-control/helper';
export class DropDownButtonPlugin extends BasePlugin {
static id = 'DropDownButtonPlugin';
static scene = ['layout'];
@ -162,6 +163,38 @@ export class DropDownButtonPlugin extends BasePlugin {
})
]
},
{
title: '基本样式',
body: [
{
type: 'select',
name: '__editorState',
label: '状态',
selectFirst: true,
options: [
{
label: '常规',
value: 'default'
},
{
label: '悬浮',
value: 'hover'
},
{
label: '点击',
value: 'active'
}
]
},
...buttonStateFunc(
"${__editorState == 'default' || !__editorState}",
'default'
),
...buttonStateFunc("${__editorState == 'hover'}", 'hover'),
...buttonStateFunc("${__editorState == 'active'}", 'active')
]
},
{
title: '图标',
body: [
@ -185,6 +218,14 @@ export class DropDownButtonPlugin extends BasePlugin {
})
]
},
getSchemaTpl('theme:cssCode', {
themeClass: [
{
value: '',
state: ['default', 'hover', 'active']
}
]
}),
getSchemaTpl('style:classNames', {
isFormItem: false,
schema: [

View File

@ -19,6 +19,7 @@ import {ValidatorTag} from '../../validator';
import {getEventControlConfig} from '../../renderer/event-control/helper';
import type {Schema} from 'amis';
import {resolveOptionEventDataSchame} from '../../util';
import {inputStateTpl} from '../../renderer/style-control/helper';
export class ChainedSelectControlPlugin extends BasePlugin {
static id = 'ChainedSelectControlPlugin';
@ -210,15 +211,32 @@ export class ChainedSelectControlPlugin extends BasePlugin {
title: '外观',
body: [
getSchemaTpl('collapseGroup', [
getSchemaTpl('style:formItem', {renderer: context.info.renderer}),
getSchemaTpl('style:classNames', {
schema: [
getSchemaTpl('className', {
name: 'descriptionClassName',
label: '描述'
})
getSchemaTpl('theme:formItem'),
getSchemaTpl('theme:form-label'),
getSchemaTpl('theme:form-description'),
{
title: '选择框样式',
body: [
...inputStateTpl(
'themeCss.chainedSelectControlClassName',
'--chained-select'
)
]
})
},
{
title: '下拉框样式',
body: [
...inputStateTpl(
'themeCss.chainedSelectPopoverClassName',
'--chained-select',
{
state: ['default', 'hover', 'focused']
}
)
]
},
getSchemaTpl('theme:cssCode'),
getSchemaTpl('style:classNames')
])
]
},

View File

@ -108,3 +108,53 @@ export const inputStateFunc = (
...options
];
};
export const buttonStateFunc = (visibleOn: string, state: string) => {
return [
getSchemaTpl('theme:font', {
label: '文字',
name: `themeCss.className.font:${state}`,
visibleOn: visibleOn,
editorValueToken: {
'color': `--button-\${level || "default"}-${state}-font-color`,
'*': '--button-size-${size || "default"}'
},
state
}),
getSchemaTpl('theme:colorPicker', {
label: '背景',
name: `themeCss.className.background:${state}`,
labelMode: 'input',
needGradient: true,
needImage: true,
visibleOn: visibleOn,
editorValueToken: `--button-\${level || "default"}-${state}-bg-color`,
state
}),
getSchemaTpl('theme:border', {
name: `themeCss.className.border:${state}`,
visibleOn: visibleOn,
editorValueToken: `--button-\${level || "default"}-${state}`,
state
}),
getSchemaTpl('theme:paddingAndMargin', {
name: `themeCss.className.padding-and-margin:${state}`,
visibleOn: visibleOn,
editorValueToken: '--button-size-${size || "default"}',
state
}),
getSchemaTpl('theme:radius', {
name: `themeCss.className.radius:${state}`,
visibleOn: visibleOn,
editorValueToken: '--button-size-${size || "default"}',
state
}),
getSchemaTpl('theme:select', {
label: '图标尺寸',
name: `themeCss.iconClassName.iconSize:${state}`,
visibleOn: visibleOn,
editorValueToken: '--button-size-${size || "default"}-icon-size',
state
})
];
};

View File

@ -85,6 +85,7 @@ export interface OptionProps {
virtualThreshold?: number; // 数据量多大的时候开启虚拟渲染
hasError?: boolean;
block?: boolean;
controlStyle?: any;
onAdd?: (
idx?: number | Array<number>,
value?: any,
@ -1329,7 +1330,8 @@ export class Select extends React.Component<SelectProps, SelectState> {
mobileUI,
hasError,
testIdBuilder,
loadingConfig
loadingConfig,
controlStyle
} = this.props;
const selection = this.state.selection;
@ -1378,6 +1380,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
className
)}
data-amis-name={this.props.dataName}
style={controlStyle}
>
<div
className={cx(`Select-valueWrap`, {

View File

@ -1,5 +1,11 @@
import React from 'react';
import {createObject, Renderer, RendererProps} from 'amis-core';
import {
createObject,
CustomStyle,
Renderer,
RendererProps,
setThemeClassName
} from 'amis-core';
import {Overlay} from 'amis-core';
import {PopOver} from 'amis-core';
import {TooltipWrapper} from 'amis-ui';
@ -433,7 +439,10 @@ export default class DropDownButton extends React.Component<
data,
hideCaret,
env,
testIdBuilder
testIdBuilder,
id,
wrapperCustomStyle,
themeCss
} = this.props;
return (
@ -478,13 +487,49 @@ export default class DropDownButton extends React.Component<
'Button--primary': primary,
'Button--iconOnly': iconOnly
},
`Button--size-${size}`
`Button--size-${size}`,
setThemeClassName({
...this.props,
name: 'wrapperCustomStyle',
id,
themeCss: wrapperCustomStyle
}),
setThemeClassName({
...this.props,
name: 'className',
id,
themeCss: themeCss
})
)}
>
<Icon c={cx} icon={icon} className="icon m-r-xs" />
<Icon
c={cx}
icon={icon}
className={cx(
'icon m-r-xs',
setThemeClassName({
...this.props,
name: 'iconClassName',
id,
themeCss: themeCss
})
)}
/>
{typeof label === 'string' ? filter(label, data) : label}
{rightIcon && (
<Icon cx={cx} icon={rightIcon} className="icon m-l-xs" />
<Icon
cx={cx}
icon={rightIcon}
className={cx(
'icon m-l-xs',
setThemeClassName({
...this.props,
name: 'iconClassName',
id,
themeCss: themeCss
})
)}
/>
)}
{!hideCaret ? (
<span className={cx('DropDown-caret')}>
@ -494,6 +539,43 @@ export default class DropDownButton extends React.Component<
</button>
</TooltipWrapper>
{this.state.isOpened ? this.renderOuter() : null}
<CustomStyle
{...this.props}
config={{
themeCss: themeCss,
classNames: [
{
key: 'className',
weights: {
hover: {
suf: ':not(:disabled):not(.is-disabled)'
},
active: {suf: ':not(:disabled):not(.is-disabled)'}
}
},
{
key: 'iconClassName',
weights: {
default: {
important: true
},
hover: {
important: true,
suf: ':not(:disabled):not(.is-disabled)'
},
active: {
important: true,
suf: ':not(:disabled):not(.is-disabled)'
}
}
}
],
wrapperCustomStyle,
id
}}
env={env}
/>
</div>
);
}

View File

@ -6,7 +6,9 @@ import {
Option,
FormOptionsControl,
resolveEventData,
getVariable
getVariable,
setThemeClassName,
CustomStyle
} from 'amis-core';
import {Select, Spinner} from 'amis-ui';
import {Api, ApiObject} from 'amis-core';
@ -327,6 +329,7 @@ export default class ChainedSelectControl extends React.Component<
mobileUI,
env,
testIdBuilder,
popoverClassName,
...rest
} = this.props;
const arr = Array.isArray(value)
@ -335,6 +338,8 @@ export default class ChainedSelectControl extends React.Component<
? value.split(delimiter || ',')
: [];
const {themeCss, id} = this.props;
const hasStackLoading = this.state.stack.find((a: StackItem) => a.loading);
return (
@ -347,6 +352,24 @@ export default class ChainedSelectControl extends React.Component<
? env?.getModalContainer
: rest.popOverContainer || env?.getModalContainer
}
className={cx(
setThemeClassName({
...this.props,
name: 'chainedSelectControlClassName',
id,
themeCss: themeCss
})
)}
popoverClassName={cx(
popoverClassName,
setThemeClassName({
...this.props,
name: 'chainedSelectPopoverClassName',
id,
themeCss: themeCss
})
)}
controlStyle={style}
classPrefix={ns}
key="base"
testIdBuilder={testIdBuilder?.getChild('base')}
@ -375,6 +398,24 @@ export default class ChainedSelectControl extends React.Component<
value={arr[index + 1]}
onChange={this.handleChange.bind(this, index + 1)}
inline
controlStyle={style}
className={cx(
setThemeClassName({
...this.props,
name: 'chainedSelectControlClassName',
id,
themeCss: themeCss
})
)}
popoverClassName={cx(
popoverClassName,
setThemeClassName({
...this.props,
name: 'chainedSelectPopoverClassName',
id,
themeCss: themeCss
})
)}
/>
)
)}
@ -385,6 +426,41 @@ export default class ChainedSelectControl extends React.Component<
className={cx(`${ns}ChainedSelectControl-spinner`)}
/>
)}
<CustomStyle
{...this.props}
config={{
themeCss: themeCss,
classNames: [
{
key: 'chainedSelectControlClassName',
weights: {
focused: {
suf: '.is-opened:not(.is-mobile)'
},
disabled: {
suf: '.is-disabled'
}
}
},
{
key: 'chainedSelectPopoverClassName',
weights: {
default: {
suf: ` .${ns}Select-option`
},
hover: {
suf: ` .${ns}Select-option.is-highlight`
},
focused: {
inner: `.${ns}Select-option.is-active`
}
}
}
],
id: id
}}
env={env}
/>
</div>
);
}