mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:58:07 +08:00
添加 search-box 已经多个容器组件添加 onQuery 响应 (#1036)
This commit is contained in:
parent
ef5a24fab4
commit
34c61c5c89
@ -137,6 +137,7 @@ $gap-lg: px2rem(30px) !default;
|
||||
|
||||
$icon-color: $gray600 !default;
|
||||
$icon-onHover-color: $gray900 !default;
|
||||
$icon-onDisabled-color: $gray500 !default;
|
||||
|
||||
$label--default-bg: $gray700 !default;
|
||||
$label--primary-bg: $primary !default;
|
||||
|
@ -39,6 +39,11 @@
|
||||
.#{$ns}Page-toolbar {
|
||||
text-align: right;
|
||||
padding-right: $gap-base;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
}
|
||||
|
||||
&-activeBtn,
|
||||
&-searchBtn,
|
||||
&-cancelBtn {
|
||||
cursor: pointer;
|
||||
color: $icon-color;
|
||||
@ -39,6 +40,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.is-disabled &-activeBtn,
|
||||
&.is-disabled &-searchBtn,
|
||||
&.is-disabled &-cancelBtn {
|
||||
color: $icon-onDisabled-color;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
> input {
|
||||
outline: none;
|
||||
border: none;
|
||||
|
@ -47,14 +47,11 @@ import {WrapperSchema} from './renderers/Wrapper';
|
||||
import {TableSchema} from './renderers/Table';
|
||||
import {DialogSchema} from './renderers/Dialog';
|
||||
import {DrawerSchema} from './renderers/Drawer';
|
||||
import {SearchBoxSchema} from './renderers/SearchBox';
|
||||
|
||||
// 每加个类型,这补充一下。
|
||||
export type SchemaType =
|
||||
| 'page'
|
||||
| 'form'
|
||||
| 'tpl'
|
||||
| 'html'
|
||||
| 'remark'
|
||||
| 'button'
|
||||
| 'submit'
|
||||
| 'reset'
|
||||
@ -99,6 +96,7 @@ export type SchemaType =
|
||||
| 'map'
|
||||
| 'mapping'
|
||||
| 'nav'
|
||||
| 'page'
|
||||
| 'operation'
|
||||
| 'panel'
|
||||
| 'plain'
|
||||
@ -106,12 +104,16 @@ export type SchemaType =
|
||||
| 'progress'
|
||||
| 'qrcode'
|
||||
| 'qr-code'
|
||||
| 'remark'
|
||||
| 'search-box'
|
||||
| 'service'
|
||||
| 'status'
|
||||
| 'switch'
|
||||
| 'table'
|
||||
| 'static-table' // 这个几个跟表单项同名,再form下面用必须带前缀 static-
|
||||
| 'tabs'
|
||||
| 'html'
|
||||
| 'tpl'
|
||||
| 'tasks'
|
||||
| 'vbox'
|
||||
| 'video'
|
||||
@ -157,6 +159,7 @@ export type SchemaObject =
|
||||
| PlainSchema
|
||||
| ProgressSchema
|
||||
| QRCodeSchema
|
||||
| SearchBoxSchema
|
||||
| ServiceSchema
|
||||
| StatusSchema
|
||||
| SwitchSchema
|
||||
|
@ -4,13 +4,19 @@ import {Icon} from './icons';
|
||||
import {uncontrollable} from 'uncontrollable';
|
||||
import {autobind} from '../utils/helper';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
export interface SearchBoxProps extends ThemeProps, LocaleProps {
|
||||
name?: string;
|
||||
disabled?: boolean;
|
||||
mini?: boolean;
|
||||
searchImediately?: boolean;
|
||||
onChange?: (text: string) => void;
|
||||
placeholder?: string;
|
||||
defaultValue?: string;
|
||||
value?: string;
|
||||
active?: boolean;
|
||||
defaultActive?: boolean;
|
||||
onActiveChange?: (active: boolean) => void;
|
||||
onSearch?: (value: string) => void;
|
||||
onCancel?: () => void;
|
||||
@ -18,6 +24,26 @@ export interface SearchBoxProps extends ThemeProps, LocaleProps {
|
||||
|
||||
export class SearchBox extends React.Component<SearchBoxProps> {
|
||||
inputRef: React.RefObject<HTMLInputElement> = React.createRef();
|
||||
static defaultProps = {
|
||||
mini: true,
|
||||
searchImediately: true
|
||||
};
|
||||
|
||||
lazyEmitSearch = debounce(
|
||||
() => {
|
||||
const onSearch = this.props.onSearch;
|
||||
onSearch?.(this.props.value || '');
|
||||
},
|
||||
250,
|
||||
{
|
||||
leading: false,
|
||||
trailing: true
|
||||
}
|
||||
);
|
||||
|
||||
componentWillUnmount() {
|
||||
this.lazyEmitSearch.cancel();
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleActive() {
|
||||
@ -36,9 +62,23 @@ export class SearchBox extends React.Component<SearchBoxProps> {
|
||||
|
||||
@autobind
|
||||
handleChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const {onChange, onSearch} = this.props;
|
||||
const {onChange, onSearch, searchImediately} = this.props;
|
||||
onChange?.(e.currentTarget.value);
|
||||
onSearch?.(e.currentTarget.value);
|
||||
searchImediately && this.lazyEmitSearch();
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSearch() {
|
||||
const {value, onSearch} = this.props;
|
||||
onSearch?.(value || '');
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleKeyUp(e: React.KeyboardEvent<any>) {
|
||||
if (e.key === 'Enter') {
|
||||
this.handleSearch();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -48,21 +88,36 @@ export class SearchBox extends React.Component<SearchBoxProps> {
|
||||
active,
|
||||
name,
|
||||
onChange,
|
||||
disabled,
|
||||
placeholder,
|
||||
mini,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={cx('SearchBox', active ? 'is-active' : '')}>
|
||||
<div
|
||||
className={cx(
|
||||
'SearchBox',
|
||||
disabled ? 'is-disabled' : '',
|
||||
!mini || active ? 'is-active' : ''
|
||||
)}
|
||||
>
|
||||
<input
|
||||
name={name}
|
||||
disabled={disabled}
|
||||
onChange={this.handleChange}
|
||||
value={value || ''}
|
||||
placeholder={__(placeholder || '输入关键字')}
|
||||
ref={this.inputRef}
|
||||
autoComplete="off"
|
||||
onKeyUp={this.handleKeyUp}
|
||||
/>
|
||||
|
||||
{active ? (
|
||||
{!mini ? (
|
||||
<a className={cx('SearchBox-searchBtn')} onClick={this.handleSearch}>
|
||||
<Icon icon="search" className="icon" />
|
||||
</a>
|
||||
) : active ? (
|
||||
<a className={cx('SearchBox-cancelBtn')} onClick={this.handleCancel}>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
|
@ -132,6 +132,7 @@ import './renderers/Switch';
|
||||
import './renderers/Wizard';
|
||||
import './renderers/Chart';
|
||||
import './renderers/Container';
|
||||
import './renderers/SearchBox';
|
||||
import './renderers/Service';
|
||||
import './renderers/Video';
|
||||
import './renderers/Audio';
|
||||
|
@ -396,7 +396,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
this.handleChildPopOverClose = this.handleChildPopOverClose.bind(this);
|
||||
this.search = this.search.bind(this);
|
||||
this.silentSearch = this.silentSearch.bind(this);
|
||||
this.handlQuery = this.handlQuery.bind(this);
|
||||
this.handleQuery = this.handleQuery.bind(this);
|
||||
this.renderHeaderToolbar = this.renderHeaderToolbar.bind(this);
|
||||
this.renderFooterToolbar = this.renderFooterToolbar.bind(this);
|
||||
this.clearSelection = this.clearSelection.bind(this);
|
||||
@ -1345,7 +1345,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
}
|
||||
}
|
||||
|
||||
handlQuery(values: object, forceReload: boolean = false) {
|
||||
handleQuery(values: object, forceReload: boolean = false) {
|
||||
const {store, syncLocation, env, pageField, perPageField} = this.props;
|
||||
|
||||
store.updateQuery(
|
||||
@ -1371,7 +1371,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
}
|
||||
|
||||
receive(values: object) {
|
||||
this.handlQuery(values, true);
|
||||
this.handleQuery(values, true);
|
||||
}
|
||||
|
||||
reloadTarget(target: string, data: any) {
|
||||
@ -1801,6 +1801,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
lastPage: store.lastPage,
|
||||
perPage: store.perPage,
|
||||
total: store.total,
|
||||
onQuery: this.handleQuery,
|
||||
onAction: this.handleAction,
|
||||
onChangePage: this.handleChangePage,
|
||||
onBulkAction: this.handleBulkAction,
|
||||
@ -1992,7 +1993,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
onAction: this.handleAction,
|
||||
onSave: this.handleSave,
|
||||
onSaveOrder: this.handleSaveOrder,
|
||||
onQuery: this.handlQuery,
|
||||
onQuery: this.handleQuery,
|
||||
onSelect: this.handleSelect,
|
||||
onPopOverOpened: this.handleChildPopOverOpen,
|
||||
onPopOverClosed: this.handleChildPopOverClose,
|
||||
|
@ -368,6 +368,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
|
||||
this.onInit = this.onInit.bind(this);
|
||||
this.handleAction = this.handleAction.bind(this);
|
||||
this.handleQuery = this.handleQuery.bind(this);
|
||||
this.handleDialogConfirm = this.handleDialogConfirm.bind(this);
|
||||
this.handleDialogClose = this.handleDialogClose.bind(this);
|
||||
this.handleDrawerConfirm = this.handleDrawerConfirm.bind(this);
|
||||
@ -954,6 +955,14 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
}
|
||||
}
|
||||
|
||||
handleQuery(query: any) {
|
||||
if (this.props.initApi) {
|
||||
this.receive(query);
|
||||
} else {
|
||||
this.props.onQuery?.(query);
|
||||
}
|
||||
}
|
||||
|
||||
handleDialogConfirm(
|
||||
values: object[],
|
||||
action: Action,
|
||||
@ -1188,6 +1197,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
disabled: disabled || (control as Schema).disabled || form.loading,
|
||||
btnDisabled: form.loading || form.validating,
|
||||
onAction: this.handleAction,
|
||||
onQuery: this.handleQuery,
|
||||
onChange:
|
||||
formLazyChange === false ? this.handleChange : this.lazyHandleChange,
|
||||
addHook: this.addHook,
|
||||
@ -1355,6 +1365,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
children: body,
|
||||
actions: this.buildActions(),
|
||||
onAction: this.handleAction,
|
||||
onQuery: this.handleQuery,
|
||||
disabled: store.loading,
|
||||
btnDisabled: store.loading || store.validating,
|
||||
headerClassName,
|
||||
|
@ -184,6 +184,7 @@ export default class Page extends React.Component<PageProps> {
|
||||
// autobind 会让继承里面的 super 指向有问题,所以先这样!
|
||||
bulkBindFunctions<Page /*为毛 this 的类型自动识别不出来?*/>(this, [
|
||||
'handleAction',
|
||||
'handleQuery',
|
||||
'handleDialogConfirm',
|
||||
'handleDialogClose',
|
||||
'handleDrawerConfirm',
|
||||
@ -305,6 +306,10 @@ export default class Page extends React.Component<PageProps> {
|
||||
}
|
||||
}
|
||||
|
||||
handleQuery(query: any) {
|
||||
this.receive(query);
|
||||
}
|
||||
|
||||
handleDialogConfirm(values: object[], action: Action, ...args: Array<any>) {
|
||||
const {store} = this.props;
|
||||
|
||||
@ -428,12 +433,14 @@ export default class Page extends React.Component<PageProps> {
|
||||
toolbar,
|
||||
render,
|
||||
store,
|
||||
initApi,
|
||||
env,
|
||||
classnames: cx
|
||||
} = this.props;
|
||||
|
||||
const subProps = {
|
||||
onAction: this.handleAction
|
||||
onAction: this.handleAction,
|
||||
onQuery: initApi ? this.handleQuery : undefined
|
||||
};
|
||||
let header, right;
|
||||
|
||||
@ -496,11 +503,13 @@ export default class Page extends React.Component<PageProps> {
|
||||
asideClassName,
|
||||
classnames: cx,
|
||||
header,
|
||||
showErrorMsg
|
||||
showErrorMsg,
|
||||
initApi
|
||||
} = this.props;
|
||||
|
||||
const subProps = {
|
||||
onAction: this.handleAction,
|
||||
onQuery: initApi ? this.handleQuery : undefined,
|
||||
loading: store.loading
|
||||
};
|
||||
|
||||
@ -560,7 +569,8 @@ export default class Page extends React.Component<PageProps> {
|
||||
onConfirm: this.handleDialogConfirm,
|
||||
onClose: this.handleDialogClose,
|
||||
show: store.dialogOpen,
|
||||
onAction: this.handleAction
|
||||
onAction: this.handleAction,
|
||||
onQuery: initApi ? this.handleQuery : undefined
|
||||
}
|
||||
)}
|
||||
|
||||
@ -577,7 +587,8 @@ export default class Page extends React.Component<PageProps> {
|
||||
onConfirm: this.handleDrawerConfirm,
|
||||
onClose: this.handleDrawerClose,
|
||||
show: store.drawerOpen,
|
||||
onAction: this.handleAction
|
||||
onAction: this.handleAction,
|
||||
onQuery: initApi ? this.handleQuery : undefined
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
|
89
src/renderers/SearchBox.tsx
Normal file
89
src/renderers/SearchBox.tsx
Normal file
@ -0,0 +1,89 @@
|
||||
import Spinner from '../components/Spinner';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import React from 'react';
|
||||
import {BaseSchema} from '../Schema';
|
||||
import SearchBox from '../components/SearchBox';
|
||||
import {autobind, getVariable, setVariable} from '../utils/helper';
|
||||
|
||||
/**
|
||||
* 搜索框渲染器
|
||||
*/
|
||||
export interface SearchBoxSchema extends BaseSchema {
|
||||
/**
|
||||
* 指定为搜索框。
|
||||
*
|
||||
* 文档:https://baidu.gitee.io/amis/docs/components/search-box
|
||||
*/
|
||||
type: 'search-box';
|
||||
|
||||
/**
|
||||
* 关键字名字。
|
||||
*
|
||||
* @default keywords
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 是否为 Mini 样式。
|
||||
*/
|
||||
mini?: boolean;
|
||||
|
||||
/**
|
||||
* 是否立马搜索。
|
||||
*/
|
||||
searchImediately?: boolean;
|
||||
}
|
||||
|
||||
interface SearchBoxProps extends RendererProps, SearchBoxSchema {
|
||||
name: string;
|
||||
onQuery?: (query: {[propName: string]: string}) => void;
|
||||
}
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)search\-box$/,
|
||||
name: 'search'
|
||||
})
|
||||
export class SearchBoxRenderer extends React.Component<SearchBoxProps> {
|
||||
static defaultProps = {
|
||||
name: 'keywords',
|
||||
mini: false,
|
||||
searchImediately: false
|
||||
};
|
||||
|
||||
static propsList: Array<string> = ['mini', 'searchImediately'];
|
||||
|
||||
@autobind
|
||||
handleCancel() {
|
||||
const name = this.props.name;
|
||||
const onQuery = this.props.onQuery;
|
||||
const data: any = {};
|
||||
setVariable(data, name, '');
|
||||
onQuery?.(data);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSearch(text: string) {
|
||||
const {name, onQuery: onQuery} = this.props;
|
||||
const data: any = {};
|
||||
setVariable(data, name, text);
|
||||
onQuery?.(data);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {data, name, onQuery: onQuery, mini, searchImediately} = this.props;
|
||||
|
||||
const value = getVariable(data, name);
|
||||
return (
|
||||
<SearchBox
|
||||
name={name}
|
||||
disabled={!onQuery}
|
||||
defaultActive={!!value}
|
||||
defaultValue={value}
|
||||
mini={mini}
|
||||
searchImediately={searchImediately}
|
||||
onSearch={this.handleSearch}
|
||||
onCancel={this.handleCancel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@ -261,7 +261,11 @@ export default class Service extends React.Component<ServiceProps> {
|
||||
}
|
||||
|
||||
handleQuery(query: any) {
|
||||
this.receive(query);
|
||||
if (this.props.api || this.props.schemaApi) {
|
||||
this.receive(query);
|
||||
} else {
|
||||
this.props.onQuery?.(query);
|
||||
}
|
||||
}
|
||||
|
||||
reloadTarget(target: string, data?: any) {
|
||||
|
@ -539,6 +539,15 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleQuery(query: any) {
|
||||
if (this.props.initApi) {
|
||||
this.receive(query);
|
||||
} else {
|
||||
this.props.onQuery?.(query);
|
||||
}
|
||||
}
|
||||
|
||||
openFeedback(dialog: any, ctx: any) {
|
||||
return new Promise(resolve => {
|
||||
const {store} = this.props;
|
||||
@ -945,6 +954,7 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
||||
onReset: this.handleReset,
|
||||
onSubmit: this.handleSubmit,
|
||||
onAction: this.handleAction,
|
||||
onQuery: this.handleQuery,
|
||||
disabled: store.loading,
|
||||
popOverContainer:
|
||||
popOverContainer || this.getPopOverContainer,
|
||||
|
Loading…
Reference in New Issue
Block a user