Merge pull request #644 from 2betop/master
Locale 多语言支持 & 修复 ts 3.9 的一些错误
This commit is contained in:
commit
830a86c753
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"editor.formatOnSave": true
|
||||
"editor.formatOnSave": true,
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import Layout from '../../src/components/Layout';
|
|||
import AsideNav from '../../src/components/AsideNav';
|
||||
import {AlertComponent, ToastComponent} from '../../src/components/index';
|
||||
import {mapTree} from '../../src/utils/helper';
|
||||
import '../../src/locale/en';
|
||||
import {
|
||||
Router,
|
||||
Route,
|
||||
|
@ -560,6 +561,18 @@ const themes = [
|
|||
}
|
||||
];
|
||||
|
||||
const locales = [
|
||||
{
|
||||
label: '默认',
|
||||
value: 'zh-cn'
|
||||
},
|
||||
|
||||
{
|
||||
label: 'English',
|
||||
value: 'en'
|
||||
}
|
||||
];
|
||||
|
||||
@withRouter
|
||||
export class App extends React.PureComponent {
|
||||
state = {
|
||||
|
@ -568,7 +581,8 @@ export class App extends React.PureComponent {
|
|||
headerVisible: true,
|
||||
themeIndex: 0,
|
||||
themes: themes,
|
||||
theme: themes[localStorage.getItem('themeIndex') || 0]
|
||||
theme: themes[localStorage.getItem('themeIndex') || 0],
|
||||
locale: localStorage.getItem('locale') || ''
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -767,10 +781,27 @@ export class App extends React.PureComponent {
|
|||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="hidden-xs p-t-sm pull-right m-l-sm">
|
||||
语言:
|
||||
{
|
||||
<Select
|
||||
clearable={false}
|
||||
theme={this.state.theme.value}
|
||||
value={this.state.locale || 'zh-cn'}
|
||||
options={locales}
|
||||
onChange={locale => {
|
||||
this.setState({locale: locale.value});
|
||||
localStorage.setItem('locale', locale.value);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="hidden-xs p-t-sm pull-right">
|
||||
主题:
|
||||
{
|
||||
<Select
|
||||
clearable={false}
|
||||
theme={this.state.theme.value}
|
||||
value={this.state.theme}
|
||||
options={this.state.themes}
|
||||
|
@ -802,14 +833,15 @@ export class App extends React.PureComponent {
|
|||
folded={this.state.asideFolded}
|
||||
aside={this.renderAside()}
|
||||
>
|
||||
<ToastComponent theme={theme.value} />
|
||||
<AlertComponent theme={theme.value} />
|
||||
<ToastComponent theme={theme.value} locale={this.state.locale} />
|
||||
<AlertComponent theme={theme.value} locale={this.state.locale} />
|
||||
{React.cloneElement(this.props.children, {
|
||||
...this.props.children.props,
|
||||
setAsideFolded: this.setAsideFolded,
|
||||
setHeaderVisible: this.setHeaderVisible,
|
||||
theme: theme.value,
|
||||
classPrefix: theme.ns
|
||||
classPrefix: theme.ns,
|
||||
locale: this.state.locale
|
||||
})}
|
||||
</Layout>
|
||||
);
|
||||
|
|
|
@ -161,13 +161,14 @@ export default function (schema) {
|
|||
}
|
||||
|
||||
renderSchema() {
|
||||
const {router, location, theme} = this.props;
|
||||
const {router, location, theme, locale} = this.props;
|
||||
|
||||
return render(
|
||||
schema,
|
||||
{
|
||||
location,
|
||||
theme
|
||||
theme,
|
||||
locale
|
||||
},
|
||||
this.env
|
||||
);
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
"@types/classnames": "^2.2.3",
|
||||
"@types/dom-helpers": "^3.4.1",
|
||||
"@types/history": "^4.6.0",
|
||||
"@types/hoist-non-react-statics": "^3.0.1",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/jest": "^24.0.11",
|
||||
"@types/jquery": "^3.3.1",
|
||||
"@types/lodash": "^4.14.76",
|
||||
|
@ -89,7 +89,7 @@
|
|||
"@types/pretty-bytes": "^4.0.0",
|
||||
"@types/prop-types": "^15.5.2",
|
||||
"@types/qs": "^6.5.1",
|
||||
"@types/react": "^16.8.1",
|
||||
"@types/react": "^16.9.35",
|
||||
"@types/react-addons-update": "^0.14.19",
|
||||
"@types/react-color": "^2.13.3",
|
||||
"@types/react-cropper": "^0.10.1",
|
||||
|
@ -139,7 +139,7 @@
|
|||
"react-testing-library": "6.0.4",
|
||||
"strip-json-comments": "^2.0.1",
|
||||
"ts-jest": "^24.0.0",
|
||||
"typescript": "^3.9.2"
|
||||
"typescript": "^3.9.3"
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "jsdom",
|
||||
|
|
|
@ -11,7 +11,7 @@ rm -rf lib/node_modules
|
|||
rm -rf sdk && fis3 release publish-sdk -c
|
||||
|
||||
# 生成 .d.ts 文件
|
||||
tsc --allowJs --declaration
|
||||
./node_modules/.bin/tsc --allowJs --declaration
|
||||
|
||||
cd output
|
||||
|
||||
|
|
|
@ -7,18 +7,16 @@ import React from 'react';
|
|||
import {render} from 'react-dom';
|
||||
import Modal from './Modal';
|
||||
import Button from './Button';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface AlertProps {
|
||||
export interface AlertProps extends ThemeProps, LocaleProps {
|
||||
container?: any;
|
||||
confirmText?: string;
|
||||
cancelText?: string;
|
||||
title?: string;
|
||||
confirmBtnLevel?: string;
|
||||
alertBtnLevel?: string;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
export interface AlertState {
|
||||
|
@ -37,7 +35,7 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
const container = document.body;
|
||||
const div = document.createElement('div');
|
||||
container.appendChild(div);
|
||||
render(<ThemedAlert />, div);
|
||||
render(<FinnalAlert />, div);
|
||||
}
|
||||
|
||||
return Alert.instance;
|
||||
|
@ -150,6 +148,8 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
classnames: cx,
|
||||
classPrefix
|
||||
} = this.props;
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
show={this.state.show}
|
||||
|
@ -158,20 +158,22 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
ref={this.modalRef}
|
||||
>
|
||||
<div className={cx('Modal-header')}>
|
||||
<div className={cx('Modal-title')}>{this.state.title || title}</div>
|
||||
<div className={cx('Modal-title')}>
|
||||
{__(this.state.title || title)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={cx('Modal-body')}>
|
||||
<div ref={this.bodyRef} />
|
||||
</div>
|
||||
<div className={cx('Modal-footer')}>
|
||||
{this.state.confirm ? (
|
||||
<Button onClick={this.handleCancel}>{cancelText}</Button>
|
||||
<Button onClick={this.handleCancel}>{__(cancelText)}</Button>
|
||||
) : null}
|
||||
<Button
|
||||
level={this.state.confirm ? confirmBtnLevel : alertBtnLevel}
|
||||
onClick={this.handleConfirm}
|
||||
>
|
||||
{this.state.confirmText || confirmText}
|
||||
{__(this.state.confirmText || confirmText)}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
@ -189,5 +191,5 @@ export const confirm: (
|
|||
confirmText?: string
|
||||
) => Promise<any> = (content, title, confirmText) =>
|
||||
Alert.getInstance().confirm(content, title, confirmText);
|
||||
export const ThemedAlert = themeable(Alert);
|
||||
export default ThemedAlert;
|
||||
export const FinnalAlert = themeable(localeable(Alert));
|
||||
export default FinnalAlert;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {CheckboxesProps, Checkboxes} from './Checkboxes';
|
||||
import {BaseCheckboxesProps, BaseCheckboxes} from './Checkboxes';
|
||||
import {Options, Option} from './Select';
|
||||
import ListMenu from './ListMenu';
|
||||
import {autobind} from '../utils/helper';
|
||||
|
@ -19,8 +19,9 @@ import ChainedCheckboxes from './ChainedCheckboxes';
|
|||
import Spinner from './Spinner';
|
||||
import TreeRadios from './TreeRadios';
|
||||
import {Icon} from './icons';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export interface AssociatedCheckboxesProps extends CheckboxesProps {
|
||||
export interface AssociatedCheckboxesProps extends BaseCheckboxesProps {
|
||||
leftOptions: Options;
|
||||
leftDefaultValue?: any;
|
||||
leftMode?: 'tree' | 'list';
|
||||
|
@ -42,7 +43,7 @@ export interface AssociatedCheckboxesState {
|
|||
leftValue?: Option;
|
||||
}
|
||||
|
||||
export class AssociatedCheckboxes extends Checkboxes<
|
||||
export class AssociatedCheckboxes extends BaseCheckboxes<
|
||||
AssociatedCheckboxesProps,
|
||||
AssociatedCheckboxesState
|
||||
> {
|
||||
|
@ -58,7 +59,7 @@ export class AssociatedCheckboxes extends Checkboxes<
|
|||
const selectdOption = ListRadios.resolveSelected(
|
||||
leftValue,
|
||||
options,
|
||||
option => option.ref
|
||||
(option: Option) => option.ref
|
||||
);
|
||||
|
||||
if (selectdOption && onDeferLoad && selectdOption.defer) {
|
||||
|
@ -80,7 +81,7 @@ export class AssociatedCheckboxes extends Checkboxes<
|
|||
const selectdOption = ListRadios.resolveSelected(
|
||||
value,
|
||||
options,
|
||||
option => option.ref
|
||||
(option: Option) => option.ref
|
||||
);
|
||||
|
||||
if (selectdOption && onDeferLoad && selectdOption.defer) {
|
||||
|
@ -111,8 +112,9 @@ export class AssociatedCheckboxes extends Checkboxes<
|
|||
const selectdOption = ListRadios.resolveSelected(
|
||||
this.state.leftValue,
|
||||
options,
|
||||
option => option.ref
|
||||
(option: Option) => option.ref
|
||||
);
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div className={cx('AssociatedCheckboxes', className)}>
|
||||
|
@ -155,9 +157,9 @@ export class AssociatedCheckboxes extends Checkboxes<
|
|||
</div>
|
||||
|
||||
{selectdOption.loading ? (
|
||||
<p>加载中</p>
|
||||
<p>{__('加载中')}</p>
|
||||
) : (
|
||||
<p>点击刷新重新加载</p>
|
||||
<p>{__('点击刷新重新加载')}</p>
|
||||
)}
|
||||
</div>
|
||||
) : rightMode === 'table' ? (
|
||||
|
@ -193,12 +195,12 @@ export class AssociatedCheckboxes extends Checkboxes<
|
|||
)
|
||||
) : (
|
||||
<div className={cx('AssociatedCheckboxes-box')}>
|
||||
配置错误,选项无法与左侧选项对应
|
||||
{__('配置错误,选项无法与左侧选项对应')}
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<div className={cx('AssociatedCheckboxes-box')}>
|
||||
请先选择左侧数据
|
||||
{__('请先选择左侧数据')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -208,7 +210,9 @@ export class AssociatedCheckboxes extends Checkboxes<
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(AssociatedCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(AssociatedCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* 级联多选框,支持无限极。从左侧到右侧一层层点选。
|
||||
*/
|
||||
import {Checkboxes, CheckboxesProps} from './Checkboxes';
|
||||
import {BaseCheckboxes, BaseCheckboxesProps} from './Checkboxes';
|
||||
import {themeable} from '../theme';
|
||||
import React from 'react';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
|
@ -10,8 +10,9 @@ import {Option} from './Select';
|
|||
import {getTreeDepth} from '../utils/helper';
|
||||
import times from 'lodash/times';
|
||||
import Spinner from './Spinner';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export interface ChainedCheckboxesProps extends CheckboxesProps {
|
||||
export interface ChainedCheckboxesProps extends BaseCheckboxesProps {
|
||||
defaultSelectedIndex?: string;
|
||||
}
|
||||
|
||||
|
@ -19,7 +20,7 @@ export interface ChainedCheckboxesState {
|
|||
selected: Array<string>;
|
||||
}
|
||||
|
||||
export class ChainedCheckboxes extends Checkboxes<
|
||||
export class ChainedCheckboxes extends BaseCheckboxes<
|
||||
ChainedCheckboxesProps,
|
||||
ChainedCheckboxesState
|
||||
> {
|
||||
|
@ -122,7 +123,7 @@ export class ChainedCheckboxes extends Checkboxes<
|
|||
itemRender
|
||||
} = this.props;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
this.valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
if (Array.isArray(options) && options.length) {
|
||||
|
@ -188,13 +189,15 @@ export class ChainedCheckboxes extends Checkboxes<
|
|||
);
|
||||
}
|
||||
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div className={cx('ChainedCheckboxes', className)}>
|
||||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('ChainedCheckboxes-placeholder')}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -203,7 +206,9 @@ export class ChainedCheckboxes extends Checkboxes<
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(ChainedCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(ChainedCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -13,9 +13,10 @@ import {Option, value2array, Options} from './Select';
|
|||
import find from 'lodash/find';
|
||||
import {autobind, findTree} from '../utils/helper';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
// import isPlainObject from 'lodash/isPlainObject';
|
||||
|
||||
export interface CheckboxesProps extends ThemeProps {
|
||||
export interface BaseCheckboxesProps extends ThemeProps, LocaleProps {
|
||||
options: Options;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
|
@ -31,8 +32,8 @@ export interface CheckboxesProps extends ThemeProps {
|
|||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export class Checkboxes<
|
||||
T extends CheckboxesProps = CheckboxesProps,
|
||||
export class BaseCheckboxes<
|
||||
T extends BaseCheckboxesProps = BaseCheckboxesProps,
|
||||
S = any
|
||||
> extends React.Component<T, S> {
|
||||
static defaultProps = {
|
||||
|
@ -68,7 +69,7 @@ export class Checkboxes<
|
|||
return;
|
||||
}
|
||||
|
||||
let valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
let valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
let idx = valueArray.indexOf(option);
|
||||
|
||||
if (~idx) {
|
||||
|
@ -115,7 +116,9 @@ export class Checkboxes<
|
|||
itemRender
|
||||
} = this.props;
|
||||
|
||||
let valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
const __ = this.props.translate;
|
||||
|
||||
let valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
if (Array.isArray(options) && options.length) {
|
||||
|
@ -142,14 +145,18 @@ export class Checkboxes<
|
|||
inline ? 'Checkboxes--inline' : ''
|
||||
)}
|
||||
>
|
||||
{body && body.length ? body : <div>{placeholder}</div>}
|
||||
{body && body.length ? body : <div>{__(placeholder)}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Checkboxes extends BaseCheckboxes {}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Checkboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(Checkboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -12,10 +12,11 @@ import {Icon} from './icons';
|
|||
import Overlay from './Overlay';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import PopOver from './PopOver';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {autobind} from '../utils/helper';
|
||||
import {localeable, LocaleProps} from '../locale';
|
||||
|
||||
export interface ColorProps {
|
||||
export interface ColorProps extends LocaleProps, ThemeProps {
|
||||
placeholder?: string;
|
||||
format: string;
|
||||
// closeOnSelect:boolean;
|
||||
|
@ -25,8 +26,6 @@ export interface ColorProps {
|
|||
popOverContainer?: any;
|
||||
placement?: string;
|
||||
value: any;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
onChange: (value: any) => void;
|
||||
presetColors?: string[];
|
||||
resetValue?: string;
|
||||
|
@ -219,6 +218,7 @@ export class ColorControl extends React.PureComponent<
|
|||
allowCustomColor
|
||||
} = this.props;
|
||||
|
||||
const __ = this.props.translate;
|
||||
const isOpened = this.state.isOpened;
|
||||
const isFocused = this.state.isFocused;
|
||||
|
||||
|
@ -240,7 +240,7 @@ export class ColorControl extends React.PureComponent<
|
|||
size={10}
|
||||
className={cx('ColorPicker-input')}
|
||||
value={this.state.inputValue || ''}
|
||||
placeholder={placeholder}
|
||||
placeholder={__(placeholder)}
|
||||
disabled={disabled}
|
||||
onChange={this.handleInputChange}
|
||||
onFocus={this.handleFocus}
|
||||
|
@ -300,7 +300,9 @@ export class ColorControl extends React.PureComponent<
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(ColorControl, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(ColorControl, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -11,10 +11,11 @@ import 'moment/locale/zh-cn';
|
|||
import {Icon} from './icons';
|
||||
import PopOver from './PopOver';
|
||||
import Overlay from './Overlay';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {PlainObject} from '../types';
|
||||
import Calendar from './calendar/Calendar';
|
||||
import 'react-datetime/css/react-datetime.css';
|
||||
import {localeable, LocaleProps, TranslateFn} from '../locale';
|
||||
|
||||
const availableShortcuts: {[propName: string]: any} = {
|
||||
now: {
|
||||
|
@ -97,9 +98,9 @@ const availableShortcuts: {[propName: string]: any} = {
|
|||
const advancedShortcuts = [
|
||||
{
|
||||
regexp: /^(\d+)hoursago$/,
|
||||
resolve: (_: string, hours: string) => {
|
||||
resolve: (__: TranslateFn, _: string, hours: string) => {
|
||||
return {
|
||||
label: `${hours}小时前`,
|
||||
label: __('{{hours}}小时前', {hours}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.subtract(hours, 'hours');
|
||||
}
|
||||
|
@ -108,9 +109,9 @@ const advancedShortcuts = [
|
|||
},
|
||||
{
|
||||
regexp: /^(\d+)hourslater$/,
|
||||
resolve: (_: string, hours: string) => {
|
||||
resolve: (__: TranslateFn, _: string, hours: string) => {
|
||||
return {
|
||||
label: `${hours}小时后`,
|
||||
label: __('{{hours}}小时后', {hours}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.add(hours, 'hours');
|
||||
}
|
||||
|
@ -119,9 +120,9 @@ const advancedShortcuts = [
|
|||
},
|
||||
{
|
||||
regexp: /^(\d+)daysago$/,
|
||||
resolve: (_: string, days: string) => {
|
||||
resolve: (__: TranslateFn, _: string, days: string) => {
|
||||
return {
|
||||
label: `${days}天前`,
|
||||
label: __('{{days}}天前', {days}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.subtract(days, 'days');
|
||||
}
|
||||
|
@ -130,9 +131,9 @@ const advancedShortcuts = [
|
|||
},
|
||||
{
|
||||
regexp: /^(\d+)dayslater$/,
|
||||
resolve: (_: string, days: string) => {
|
||||
resolve: (__: TranslateFn, _: string, days: string) => {
|
||||
return {
|
||||
label: `${days}天后`,
|
||||
label: __('{{days}}天后', {days}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.add(days, 'days');
|
||||
}
|
||||
|
@ -141,9 +142,9 @@ const advancedShortcuts = [
|
|||
},
|
||||
{
|
||||
regexp: /^(\d+)weeksago$/,
|
||||
resolve: (_: string, weeks: string) => {
|
||||
resolve: (__: TranslateFn, _: string, weeks: string) => {
|
||||
return {
|
||||
label: `${weeks}周前`,
|
||||
label: __('{{weeks}}周前', {weeks}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.subtract(weeks, 'weeks');
|
||||
}
|
||||
|
@ -152,9 +153,9 @@ const advancedShortcuts = [
|
|||
},
|
||||
{
|
||||
regexp: /^(\d+)weekslater$/,
|
||||
resolve: (_: string, weeks: string) => {
|
||||
resolve: (__: TranslateFn, _: string, weeks: string) => {
|
||||
return {
|
||||
label: `${weeks}周后`,
|
||||
label: __('{{weeks}}周后', {weeks}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.add(weeks, 'weeks');
|
||||
}
|
||||
|
@ -163,9 +164,9 @@ const advancedShortcuts = [
|
|||
},
|
||||
{
|
||||
regexp: /^(\d+)monthsago$/,
|
||||
resolve: (_: string, months: string) => {
|
||||
resolve: (__: TranslateFn, _: string, months: string) => {
|
||||
return {
|
||||
label: `${months}月前`,
|
||||
label: __('{{months}}月前', {months}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.subtract(months, 'months');
|
||||
}
|
||||
|
@ -174,9 +175,9 @@ const advancedShortcuts = [
|
|||
},
|
||||
{
|
||||
regexp: /^(\d+)monthslater$/,
|
||||
resolve: (_: string, months: string) => {
|
||||
resolve: (__: TranslateFn, _: string, months: string) => {
|
||||
return {
|
||||
label: `${months}月后`,
|
||||
label: __('{{months}}月后', {months}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.add(months, 'months');
|
||||
}
|
||||
|
@ -185,9 +186,9 @@ const advancedShortcuts = [
|
|||
},
|
||||
{
|
||||
regexp: /^(\d+)quartersago$/,
|
||||
resolve: (_: string, quarters: string) => {
|
||||
resolve: (__: TranslateFn, _: string, quarters: string) => {
|
||||
return {
|
||||
label: `${quarters}季度前`,
|
||||
label: __('{{quarters}}季度前', {quarters}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.subtract(quarters, 'quarters');
|
||||
}
|
||||
|
@ -196,9 +197,9 @@ const advancedShortcuts = [
|
|||
},
|
||||
{
|
||||
regexp: /^(\d+)quarterslater$/,
|
||||
resolve: (_: string, quarters: string) => {
|
||||
resolve: (__: TranslateFn, _: string, quarters: string) => {
|
||||
return {
|
||||
label: `${quarters}季度后`,
|
||||
label: __('{{quarters}}季度后', {quarters}),
|
||||
date: (now: moment.Moment) => {
|
||||
return now.add(quarters, 'quarters');
|
||||
}
|
||||
|
@ -226,17 +227,15 @@ export type ShortCuts =
|
|||
| ShortCutDate
|
||||
| ShortCutDateRange;
|
||||
|
||||
export interface DateProps {
|
||||
export interface DateProps extends LocaleProps, ThemeProps {
|
||||
viewMode: 'years' | 'months' | 'days' | 'time';
|
||||
className?: string;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
placeholder?: string;
|
||||
inputFormat?: string;
|
||||
timeFormat?: string;
|
||||
format?: string;
|
||||
timeConstrainst?: object;
|
||||
closeOnSelect?: boolean;
|
||||
closeOnSelect: boolean;
|
||||
disabled?: boolean;
|
||||
minDate?: moment.Moment;
|
||||
maxDate?: moment.Moment;
|
||||
|
@ -247,7 +246,14 @@ export interface DateProps {
|
|||
value: any;
|
||||
shortcuts: string | Array<ShortCuts>;
|
||||
overlayPlacement: string;
|
||||
[propName: string]: any;
|
||||
minTime?: moment.Moment;
|
||||
maxTime?: moment.Moment;
|
||||
dateFormat?: string;
|
||||
timeConstraints?: any;
|
||||
popOverContainer?: any;
|
||||
|
||||
// 下面那个千万不要写,写了就会导致 keyof DateProps 得到的结果是 string | number;
|
||||
// [propName: string]: any;
|
||||
}
|
||||
|
||||
export interface DatePickerState {
|
||||
|
@ -257,11 +263,8 @@ export interface DatePickerState {
|
|||
}
|
||||
|
||||
export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
static defaultProps: Pick<
|
||||
DateProps,
|
||||
'viewMode' | 'shortcuts' | 'closeOnSelect' | 'overlayPlacement'
|
||||
> = {
|
||||
viewMode: 'days',
|
||||
static defaultProps = {
|
||||
viewMode: 'days' as 'years' | 'months' | 'days' | 'time',
|
||||
shortcuts: '',
|
||||
closeOnSelect: true,
|
||||
overlayPlacement: 'auto'
|
||||
|
@ -429,12 +432,14 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
return availableShortcuts[key];
|
||||
}
|
||||
|
||||
const __ = this.props.translate;
|
||||
|
||||
for (let i = 0, len = advancedShortcuts.length; i < len; i++) {
|
||||
let item = advancedShortcuts[i];
|
||||
const m = item.regexp.exec(key);
|
||||
|
||||
if (m) {
|
||||
return item.resolve.apply(item, m);
|
||||
return item.resolve.apply(item, [__, ...m]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -452,6 +457,8 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
} else {
|
||||
shortcutArr = shortcuts;
|
||||
}
|
||||
|
||||
const __ = this.props.translate;
|
||||
return (
|
||||
<ul className={`${ns}DatePicker-shortcuts`}>
|
||||
{shortcutArr.map(item => {
|
||||
|
@ -474,7 +481,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
onClick={() => this.selectRannge(shortcut)}
|
||||
key={shortcut.key || shortcut.label}
|
||||
>
|
||||
<a>{shortcut.label}</a>
|
||||
<a>{__(shortcut.label)}</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
@ -498,9 +505,11 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
clearable,
|
||||
shortcuts,
|
||||
utc,
|
||||
overlayPlacement
|
||||
overlayPlacement,
|
||||
locale
|
||||
} = this.props;
|
||||
|
||||
const __ = this.props.translate;
|
||||
const isOpened = this.state.isOpened;
|
||||
let date: moment.Moment | undefined = this.state.value;
|
||||
|
||||
|
@ -526,7 +535,9 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
{date.format(inputFormat)}
|
||||
</span>
|
||||
) : (
|
||||
<span className={`${ns}DatePicker-placeholder`}>{placeholder}</span>
|
||||
<span className={`${ns}DatePicker-placeholder`}>
|
||||
{__(placeholder)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{clearable && !disabled && value ? (
|
||||
|
@ -565,6 +576,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
timeConstraints={timeConstraints}
|
||||
input={false}
|
||||
onClose={this.close}
|
||||
locale={locale}
|
||||
// utc={utc}
|
||||
/>
|
||||
</PopOver>
|
||||
|
@ -575,4 +587,4 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(DatePicker);
|
||||
export default themeable(localeable(DatePicker));
|
||||
|
|
|
@ -13,14 +13,13 @@ import Overlay from './Overlay';
|
|||
import {ShortCuts, ShortCutDateRange} from './DatePicker';
|
||||
import Calendar from './calendar/Calendar';
|
||||
import PopOver from './PopOver';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {PlainObject} from '../types';
|
||||
import {noop} from '../utils/helper';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface DateRangePickerProps {
|
||||
export interface DateRangePickerProps extends ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
placeholder?: string;
|
||||
theme?: any;
|
||||
format: string;
|
||||
|
@ -39,7 +38,10 @@ export interface DateRangePickerProps {
|
|||
disabled?: boolean;
|
||||
closeOnSelect?: boolean;
|
||||
overlayPlacement: string;
|
||||
[propName: string]: any;
|
||||
timeFormat?: string;
|
||||
resetValue?: any;
|
||||
popOverContainer?: any;
|
||||
dateFormat?: string;
|
||||
}
|
||||
|
||||
export interface DateRangePickerState {
|
||||
|
@ -106,10 +108,7 @@ const availableRanges: {[propName: string]: any} = {
|
|||
return now.startOf('week').add(-1, 'weeks');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now
|
||||
.startOf('week')
|
||||
.add(-1, 'days')
|
||||
.endOf('day');
|
||||
return now.startOf('week').add(-1, 'days').endOf('day');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -129,10 +128,7 @@ const availableRanges: {[propName: string]: any} = {
|
|||
return now.startOf('month').add(-1, 'month');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now
|
||||
.startOf('month')
|
||||
.add(-1, 'day')
|
||||
.endOf('day');
|
||||
return now.startOf('month').add(-1, 'day').endOf('day');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -142,10 +138,7 @@ const availableRanges: {[propName: string]: any} = {
|
|||
return now.startOf('quarter').add(-1, 'quarter');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now
|
||||
.startOf('quarter')
|
||||
.add(-1, 'day')
|
||||
.endOf('day');
|
||||
return now.startOf('quarter').add(-1, 'day').endOf('day');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -416,6 +409,8 @@ export class DateRangePicker extends React.Component<
|
|||
} else {
|
||||
rangeArr = ranges;
|
||||
}
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<ul className={`${ns}DateRangePicker-rangers`}>
|
||||
{rangeArr.map(item => {
|
||||
|
@ -442,7 +437,7 @@ export class DateRangePicker extends React.Component<
|
|||
onClick={() => this.selectRannge(range)}
|
||||
key={range.key || range.label}
|
||||
>
|
||||
<a>{range.label}</a>
|
||||
<a>{__(range.label)}</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
@ -551,6 +546,7 @@ export class DateRangePicker extends React.Component<
|
|||
const arr = [];
|
||||
startViewValue && arr.push(startViewValue);
|
||||
endViewValue && arr.push(endViewValue);
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -571,11 +567,11 @@ export class DateRangePicker extends React.Component<
|
|||
>
|
||||
{arr.length ? (
|
||||
<span className={`${ns}DateRangePicker-value`}>
|
||||
{arr.join(' 至 ')}
|
||||
{arr.join(__(' 至 '))}
|
||||
</span>
|
||||
) : (
|
||||
<span className={`${ns}DateRangePicker-placeholder`}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
|
@ -646,10 +642,10 @@ export class DateRangePicker extends React.Component<
|
|||
})}
|
||||
onClick={this.confirm}
|
||||
>
|
||||
确认
|
||||
{__('确认')}
|
||||
</a>
|
||||
<a className="rdtBtn rdtBtnCancel" onClick={this.close}>
|
||||
取消
|
||||
{__('取消')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -661,4 +657,4 @@ export class DateRangePicker extends React.Component<
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(DateRangePicker);
|
||||
export default themeable(localeable(DateRangePicker));
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import React from 'react';
|
||||
import {themeable, ClassNamesFn} from '../theme';
|
||||
import {themeable, ClassNamesFn, ThemeProps} from '../theme';
|
||||
import {autobind} from '../utils/helper';
|
||||
import Modal from './Modal';
|
||||
import {Icon} from './icons';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ImageGalleryProps {
|
||||
classnames: ClassNamesFn;
|
||||
classPrefix: string;
|
||||
export interface ImageGalleryProps extends ThemeProps, LocaleProps {
|
||||
children: React.ReactNode;
|
||||
modalContainer?: () => HTMLElement;
|
||||
}
|
||||
|
@ -87,6 +86,7 @@ export class ImageGallery extends React.Component<
|
|||
render() {
|
||||
const {children, classnames: cx, modalContainer} = this.props;
|
||||
const {index, items} = this.state;
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -103,7 +103,7 @@ export class ImageGallery extends React.Component<
|
|||
container={modalContainer}
|
||||
>
|
||||
<a
|
||||
data-tooltip="关闭"
|
||||
data-tooltip={__('关闭')}
|
||||
data-position="left"
|
||||
className={cx('ImageGallery-close')}
|
||||
onClick={this.close}
|
||||
|
@ -176,4 +176,4 @@ export class ImageGallery extends React.Component<
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(ImageGallery);
|
||||
export default themeable(localeable(ImageGallery));
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import {Checkboxes} from './Checkboxes';
|
||||
import {BaseCheckboxes} from './Checkboxes';
|
||||
import {themeable} from '../theme';
|
||||
import React from 'react';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import Checkbox from './Checkbox';
|
||||
import {Option} from './Select';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export class ListCheckboxes extends Checkboxes {
|
||||
export class ListCheckboxes extends BaseCheckboxes {
|
||||
valueArray: Array<Option>;
|
||||
|
||||
renderOption(option: Option, index: number) {
|
||||
|
@ -72,8 +73,9 @@ export class ListCheckboxes extends Checkboxes {
|
|||
classnames: cx,
|
||||
option2value
|
||||
} = this.props;
|
||||
const __ = this.props.translate;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
this.valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
if (Array.isArray(options) && options.length) {
|
||||
|
@ -85,7 +87,9 @@ export class ListCheckboxes extends Checkboxes {
|
|||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('ListCheckboxes-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('ListCheckboxes-placeholder')}>
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -93,7 +97,9 @@ export class ListCheckboxes extends Checkboxes {
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(ListCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(ListCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import {ThemeProps, themeable} from '../theme';
|
||||
import React from 'react';
|
||||
import {Options, Option} from './Select';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ListMenuProps extends ThemeProps {
|
||||
export interface ListMenuProps extends ThemeProps, LocaleProps {
|
||||
options: Options;
|
||||
disabled?: boolean;
|
||||
selectedOptions?: Options;
|
||||
|
@ -85,6 +86,8 @@ export class ListMenu extends React.Component<ListMenuProps> {
|
|||
|
||||
render() {
|
||||
const {classnames: cx, options, placeholder, prefix, children} = this.props;
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div className={cx('ListMenu')}>
|
||||
{prefix}
|
||||
|
@ -98,7 +101,7 @@ export class ListMenu extends React.Component<ListMenuProps> {
|
|||
}
|
||||
).items
|
||||
) : (
|
||||
<span className={cx('ListMenu-placeholder')}>{placeholder}</span>
|
||||
<span className={cx('ListMenu-placeholder')}>{__(placeholder)}</span>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
|
@ -106,4 +109,4 @@ export class ListMenu extends React.Component<ListMenuProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(ListMenu);
|
||||
export default themeable(localeable(ListMenu));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {Checkboxes} from './Checkboxes';
|
||||
import {BaseCheckboxes} from './Checkboxes';
|
||||
import {themeable, ThemeProps} from '../theme';
|
||||
import React from 'react';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
|
@ -6,8 +6,9 @@ import Checkbox from './Checkbox';
|
|||
import {Option, Options} from './Select';
|
||||
import {findTree, autobind} from '../utils/helper';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ListRadiosProps extends ThemeProps {
|
||||
export interface BaseRadiosProps extends ThemeProps, LocaleProps {
|
||||
options: Options;
|
||||
className?: string;
|
||||
placeholder: string;
|
||||
|
@ -22,9 +23,9 @@ export interface ListRadiosProps extends ThemeProps {
|
|||
showRadio?: boolean;
|
||||
}
|
||||
|
||||
export class ListRadios<
|
||||
T extends ListRadiosProps = ListRadiosProps,
|
||||
S = any
|
||||
export class BaseRadios<
|
||||
T extends BaseRadiosProps = BaseRadiosProps,
|
||||
S = {}
|
||||
> extends React.Component<T, S> {
|
||||
selected: Option | undefined | null;
|
||||
|
||||
|
@ -47,7 +48,7 @@ export class ListRadios<
|
|||
let newValue: Option | null = option;
|
||||
|
||||
if (clearable) {
|
||||
const prevSelected = ListRadios.resolveSelected(
|
||||
const prevSelected = BaseRadios.resolveSelected(
|
||||
value,
|
||||
options,
|
||||
option2value
|
||||
|
@ -120,8 +121,9 @@ export class ListRadios<
|
|||
classnames: cx,
|
||||
option2value
|
||||
} = this.props;
|
||||
const __ = this.props.translate;
|
||||
|
||||
this.selected = ListRadios.resolveSelected(value, options, option2value);
|
||||
this.selected = BaseRadios.resolveSelected(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
if (Array.isArray(options) && options.length) {
|
||||
|
@ -133,19 +135,23 @@ export class ListRadios<
|
|||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('ListRadios-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('ListRadios-placeholder')}>{__(placeholder)}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class ListRadios extends BaseRadios {}
|
||||
|
||||
const themedListRadios = themeable(
|
||||
uncontrollable(ListRadios, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(ListRadios, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
themedListRadios.resolveSelected = ListRadios.resolveSelected;
|
||||
themedListRadios.resolveSelected = BaseRadios.resolveSelected;
|
||||
|
||||
export default themedListRadios;
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import React from 'react';
|
||||
import {themeable, ClassNamesFn} from '../theme';
|
||||
import {themeable, ClassNamesFn, ThemeProps} from '../theme';
|
||||
import Overlay from './Overlay';
|
||||
import PopOver from './PopOver';
|
||||
import {Icon} from './icons';
|
||||
import {autobind} from '../utils/helper';
|
||||
import Alert2 from './Alert2';
|
||||
import BaiduMapPicker from './BaiduMapPicker';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface LocationProps {
|
||||
export interface LocationProps extends ThemeProps, LocaleProps {
|
||||
vendor: 'baidu' | 'gaode' | 'tenxun';
|
||||
placeholder: string;
|
||||
clearable: boolean;
|
||||
|
@ -21,8 +22,6 @@ export interface LocationProps {
|
|||
disabled?: boolean;
|
||||
className?: string;
|
||||
onChange: (value: any) => void;
|
||||
classnames: ClassNamesFn;
|
||||
classPrefix: string;
|
||||
popOverContainer?: any;
|
||||
}
|
||||
|
||||
|
@ -137,6 +136,7 @@ export class LocationPicker extends React.Component<
|
|||
vendor,
|
||||
ak
|
||||
} = this.props;
|
||||
const __ = this.props.translate;
|
||||
const {isFocused, isOpened} = this.state;
|
||||
|
||||
return (
|
||||
|
@ -161,7 +161,7 @@ export class LocationPicker extends React.Component<
|
|||
<span className={cx('LocationPicker-value')}>{value.address}</span>
|
||||
) : (
|
||||
<span className={cx('LocationPicker-placeholder')}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
|
@ -189,8 +189,14 @@ export class LocationPicker extends React.Component<
|
|||
style={{width: this.getTarget()?.offsetWidth}}
|
||||
>
|
||||
{vendor === 'baidu' ? (
|
||||
<BaiduMapPicker ak={ak} value={value} onChange={this.handleChange} />
|
||||
) : (<Alert2>{vendor} 地图控件不支持</Alert2>)}
|
||||
<BaiduMapPicker
|
||||
ak={ak}
|
||||
value={value}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
) : (
|
||||
<Alert2>{__('${vendor} 地图控件不支持', {vendor})}</Alert2>
|
||||
)}
|
||||
</PopOver>
|
||||
</Overlay>
|
||||
</div>
|
||||
|
@ -198,5 +204,5 @@ export class LocationPicker extends React.Component<
|
|||
}
|
||||
}
|
||||
|
||||
const ThemedCity = themeable(LocationPicker);
|
||||
const ThemedCity = themeable(localeable(LocationPicker));
|
||||
export default ThemedCity;
|
||||
|
|
|
@ -14,8 +14,9 @@ import {Portal} from 'react-overlays';
|
|||
import {current, addModal, removeModal} from './ModalManager';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {Icon} from './icons';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ModalProps extends ThemeProps {
|
||||
export interface ModalProps extends ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
contentClassName?: string;
|
||||
size?: any;
|
||||
|
@ -44,33 +45,37 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
|||
};
|
||||
|
||||
static Header = themeable(
|
||||
({
|
||||
classnames: cx,
|
||||
className,
|
||||
showCloseButton,
|
||||
onClose,
|
||||
children,
|
||||
classPrefix,
|
||||
...rest
|
||||
}: ThemeProps & {
|
||||
className?: string;
|
||||
showCloseButton?: boolean;
|
||||
onClose?: () => void;
|
||||
children?: React.ReactNode;
|
||||
} & React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div {...rest} className={cx('Modal-header', className)}>
|
||||
{showCloseButton !== false ? (
|
||||
<a
|
||||
data-tooltip="关闭弹窗"
|
||||
data-position="left"
|
||||
onClick={onClose}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
) : null}
|
||||
{children}
|
||||
</div>
|
||||
localeable(
|
||||
({
|
||||
classnames: cx,
|
||||
className,
|
||||
showCloseButton,
|
||||
onClose,
|
||||
children,
|
||||
classPrefix,
|
||||
translate: __,
|
||||
...rest
|
||||
}: ThemeProps &
|
||||
LocaleProps & {
|
||||
className?: string;
|
||||
showCloseButton?: boolean;
|
||||
onClose?: () => void;
|
||||
children?: React.ReactNode;
|
||||
} & React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div {...rest} className={cx('Modal-header', className)}>
|
||||
{showCloseButton !== false ? (
|
||||
<a
|
||||
data-tooltip={__('关闭弹窗')}
|
||||
data-position="left"
|
||||
onClick={onClose}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
) : null}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -216,9 +221,9 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
|||
}
|
||||
}
|
||||
|
||||
const themedModal = themeable(Modal);
|
||||
const FinalModal = themeable(localeable(Modal));
|
||||
|
||||
export default themedModal as typeof themedModal & {
|
||||
export default FinalModal as typeof FinalModal & {
|
||||
Header: typeof Modal.Header;
|
||||
Title: typeof Modal.Title;
|
||||
Body: typeof Modal.Body;
|
||||
|
|
|
@ -5,10 +5,12 @@ import uncontrollable from 'uncontrollable';
|
|||
import {Icon} from './icons';
|
||||
import Input from './Input';
|
||||
import {autobind} from '../utils/helper';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ResultBoxProps
|
||||
extends ThemeProps,
|
||||
Omit<InputBoxProps, 'result' | 'prefix' | 'onChange'> {
|
||||
LocaleProps,
|
||||
Omit<InputBoxProps, 'result' | 'prefix' | 'onChange' | 'translate'> {
|
||||
onChange?: (value: string) => void;
|
||||
onResultClick?: (e: React.MouseEvent<HTMLElement>) => void;
|
||||
result?: Array<any>;
|
||||
|
@ -96,6 +98,8 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
|||
onResultChange,
|
||||
onChange,
|
||||
onResultClick,
|
||||
translate: __,
|
||||
locale,
|
||||
...rest
|
||||
} = this.props;
|
||||
const isFocused = this.state.isFocused;
|
||||
|
@ -124,7 +128,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
|||
))
|
||||
) : allowInput ? null : (
|
||||
<span className={cx('ResultBox-placeholder')}>
|
||||
{placeholder || '无'}
|
||||
{__(placeholder || '无')}
|
||||
</span>
|
||||
)}
|
||||
|
||||
|
@ -163,8 +167,10 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(ResultBox, {
|
||||
value: 'onChange',
|
||||
result: 'onResultChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(ResultBox, {
|
||||
value: 'onChange',
|
||||
result: 'onResultChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -8,8 +8,9 @@ import {Icon} from './icons';
|
|||
import {autobind, guid} from '../utils/helper';
|
||||
import Sortable from 'sortablejs';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ResultListProps extends ThemeProps {
|
||||
export interface ResultListProps extends ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
value?: Array<Option>;
|
||||
onChange?: (value: Array<Option>) => void;
|
||||
|
@ -123,7 +124,8 @@ export class ResultList extends React.Component<ResultListProps> {
|
|||
disabled,
|
||||
title,
|
||||
itemClassName,
|
||||
sortable
|
||||
sortable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
@ -163,11 +165,11 @@ export class ResultList extends React.Component<ResultListProps> {
|
|||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className={cx('Selections-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('Selections-placeholder')}>{__(placeholder)}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(ResultList);
|
||||
export default themeable(localeable(ResultList));
|
||||
|
|
|
@ -3,8 +3,9 @@ import {ThemeProps, themeable} from '../theme';
|
|||
import {Icon} from './icons';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import {autobind} from '../utils/helper';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface SearchBoxProps extends ThemeProps {
|
||||
export interface SearchBoxProps extends ThemeProps, LocaleProps {
|
||||
name?: string;
|
||||
onChange?: (text: string) => void;
|
||||
placeholder?: string;
|
||||
|
@ -47,7 +48,8 @@ export class SearchBox extends React.Component<SearchBoxProps> {
|
|||
active,
|
||||
name,
|
||||
onChange,
|
||||
placeholder
|
||||
placeholder,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
@ -56,7 +58,7 @@ export class SearchBox extends React.Component<SearchBoxProps> {
|
|||
name={name}
|
||||
onChange={this.handleChange}
|
||||
value={value || ''}
|
||||
placeholder={placeholder || '输入关键字'}
|
||||
placeholder={__(placeholder || '输入关键字')}
|
||||
ref={this.inputRef}
|
||||
/>
|
||||
|
||||
|
@ -75,8 +77,10 @@ export class SearchBox extends React.Component<SearchBoxProps> {
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(SearchBox, {
|
||||
active: 'onActiveChange',
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(SearchBox, {
|
||||
active: 'onActiveChange',
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -19,10 +19,11 @@ import isPlainObject from 'lodash/isPlainObject';
|
|||
import union from 'lodash/union';
|
||||
import {highlight} from '../renderers/Form/Options';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import Checkbox from './Checkbox';
|
||||
import Input from './Input';
|
||||
import {Api} from '../types';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface Option {
|
||||
label?: string;
|
||||
|
@ -273,9 +274,7 @@ export function normalizeOptions(
|
|||
|
||||
const DownshiftChangeTypes = Downshift.stateChangeTypes;
|
||||
|
||||
interface SelectProps extends OptionProps {
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
interface SelectProps extends OptionProps, ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
creatable: boolean;
|
||||
createBtnLabel: string;
|
||||
|
@ -629,7 +628,8 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
placeholder,
|
||||
classPrefix: ns,
|
||||
labelField,
|
||||
disabled
|
||||
disabled,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const selection = this.state.selection;
|
||||
|
@ -638,7 +638,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
if (!selection.length) {
|
||||
return (
|
||||
<div key="placeholder" className={`${ns}Select-placeholder`}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -693,7 +693,8 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
searchPromptText,
|
||||
editable,
|
||||
removable,
|
||||
overlayPlacement
|
||||
overlayPlacement,
|
||||
translate: __
|
||||
} = this.props;
|
||||
const {selection} = this.state;
|
||||
|
||||
|
@ -732,7 +733,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
onFocus: this.onFocus,
|
||||
onBlur: this.onBlur,
|
||||
disabled: disabled,
|
||||
placeholder: searchPromptText,
|
||||
placeholder: __(searchPromptText),
|
||||
onChange: this.handleInputChange,
|
||||
ref: this.inputRef
|
||||
})}
|
||||
|
@ -747,7 +748,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
partial={checkedPartial && !checkedAll}
|
||||
onChange={this.toggleCheckAll}
|
||||
>
|
||||
{checkAllLabel}
|
||||
{__(checkAllLabel)}
|
||||
</Checkbox>
|
||||
</div>
|
||||
) : null}
|
||||
|
@ -830,13 +831,13 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
);
|
||||
})
|
||||
) : (
|
||||
<div className={cx('Select-noResult')}>{noResultsText}</div>
|
||||
<div className={cx('Select-noResult')}>{__(noResultsText)}</div>
|
||||
)}
|
||||
|
||||
{creatable && !disabled ? (
|
||||
<a className={cx('Select-addBtn')} onClick={this.handleAddClick}>
|
||||
<Icon icon="plus" className="icon" />
|
||||
{createBtnLabel}
|
||||
{__(createBtnLabel)}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -942,7 +943,9 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Select, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(Select, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import {Checkboxes, CheckboxesProps} from './Checkboxes';
|
||||
import {BaseCheckboxes, BaseCheckboxesProps} from './Checkboxes';
|
||||
import {themeable} from '../theme';
|
||||
import React from 'react';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import Checkbox from './Checkbox';
|
||||
import {Option} from './Select';
|
||||
import {resolveVariable} from '../utils/tpl-builtin';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export interface TableCheckboxesProps extends CheckboxesProps {
|
||||
export interface TableCheckboxesProps extends BaseCheckboxesProps {
|
||||
columns: Array<{
|
||||
name: string;
|
||||
label: string;
|
||||
|
@ -24,9 +25,9 @@ export interface TableCheckboxesProps extends CheckboxesProps {
|
|||
) => JSX.Element;
|
||||
}
|
||||
|
||||
export class TableCheckboxes extends Checkboxes<TableCheckboxesProps> {
|
||||
export class TableCheckboxes extends BaseCheckboxes<TableCheckboxesProps> {
|
||||
static defaultProps = {
|
||||
...Checkboxes.defaultProps,
|
||||
...BaseCheckboxes.defaultProps,
|
||||
cellRender: (
|
||||
column: {
|
||||
name: string;
|
||||
|
@ -51,7 +52,7 @@ export class TableCheckboxes extends Checkboxes<TableCheckboxesProps> {
|
|||
renderTHead() {
|
||||
const {options, classnames: cx, value, option2value} = this.props;
|
||||
let columns = this.getColumns();
|
||||
let valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
let valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
const availableOptions = options.filter(option => !option.disabled);
|
||||
let partialChecked = false;
|
||||
let allChecked = !!availableOptions.length;
|
||||
|
@ -94,10 +95,11 @@ export class TableCheckboxes extends Checkboxes<TableCheckboxesProps> {
|
|||
classnames: cx,
|
||||
cellRender,
|
||||
value,
|
||||
option2value
|
||||
option2value,
|
||||
translate: __
|
||||
} = this.props;
|
||||
const columns = this.getColumns();
|
||||
let valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
let valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
|
||||
return (
|
||||
<tbody>
|
||||
|
@ -123,7 +125,7 @@ export class TableCheckboxes extends Checkboxes<TableCheckboxesProps> {
|
|||
})
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={columns.length}>{placeholder}</td>
|
||||
<td colSpan={columns.length}>{__(placeholder)}</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
|
@ -143,7 +145,7 @@ export class TableCheckboxes extends Checkboxes<TableCheckboxesProps> {
|
|||
itemRender
|
||||
} = this.props;
|
||||
|
||||
let valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
let valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
if (Array.isArray(options) && options.length) {
|
||||
|
@ -187,7 +189,9 @@ export class TableCheckboxes extends Checkboxes<TableCheckboxesProps> {
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(TableCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(TableCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -10,6 +10,7 @@ import {Options, Option} from './Select';
|
|||
import Transfer, {TransferProps} from './Transfer';
|
||||
import {themeable} from '../theme';
|
||||
import AssociatedCheckboxes from './AssociatedCheckboxes';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export interface TabsTransferProps
|
||||
extends Omit<
|
||||
|
@ -101,13 +102,14 @@ export class TabsTransfer extends React.Component<TabsTransferProps> {
|
|||
onSearch: searchable,
|
||||
option2value,
|
||||
onDeferLoad,
|
||||
cellRender
|
||||
cellRender,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (!Array.isArray(options) || !options.length) {
|
||||
return (
|
||||
<div className={cx('TabsTransfer-placeholder')}>
|
||||
{placeholder || '暂无可选项'}
|
||||
{__(placeholder || '暂无选项')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -128,7 +130,7 @@ export class TabsTransfer extends React.Component<TabsTransferProps> {
|
|||
>
|
||||
{searchResult !== null
|
||||
? [
|
||||
<Tab title="搜索结果" key={0} eventKey={0}>
|
||||
<Tab title={__('搜索结果')} key={0} eventKey={0}>
|
||||
{this.renderSearchResult(searchResult)}
|
||||
</Tab>
|
||||
]
|
||||
|
@ -210,4 +212,4 @@ export class TabsTransfer extends React.Component<TabsTransferProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(TabsTransfer);
|
||||
export default themeable(localeable(TabsTransfer));
|
||||
|
|
|
@ -35,8 +35,9 @@ import 'tinymce/plugins/template';
|
|||
import 'tinymce/plugins/nonbreaking';
|
||||
import 'tinymce/plugins/emoticons';
|
||||
import 'tinymce/plugins/emoticons/js/emojis';
|
||||
import {LocaleProps} from '../locale';
|
||||
|
||||
interface TinymceEditorProps {
|
||||
interface TinymceEditorProps extends LocaleProps {
|
||||
model: string;
|
||||
onModelChange?: (value: string) => void;
|
||||
onFocus?: () => void;
|
||||
|
@ -58,12 +59,14 @@ export default class TinymceEditor extends React.Component<TinymceEditorProps> {
|
|||
elementRef: React.RefObject<HTMLTextAreaElement> = React.createRef();
|
||||
|
||||
componentDidMount() {
|
||||
const locale = this.props.locale;
|
||||
|
||||
this.config = {
|
||||
inline: false,
|
||||
skin: false,
|
||||
content_css: false,
|
||||
height: 400,
|
||||
language: 'zh_CN',
|
||||
language: !locale || locale === 'zh-cn' ? 'zh_CN' : 'en',
|
||||
plugins: [
|
||||
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker',
|
||||
'searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import {ThemeProps, themeable} from '../theme';
|
||||
import {CheckboxesProps, Checkboxes} from './Checkboxes';
|
||||
import {BaseCheckboxesProps, BaseCheckboxes} from './Checkboxes';
|
||||
import {Options, Option} from './Select';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import ResultList from './ResultList';
|
||||
|
@ -13,8 +13,12 @@ import {Icon} from './icons';
|
|||
import debounce from 'lodash/debounce';
|
||||
import ChainedCheckboxes from './ChainedCheckboxes';
|
||||
import AssociatedCheckboxes from './AssociatedCheckboxes';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface TransferProps extends ThemeProps, CheckboxesProps {
|
||||
export interface TransferProps
|
||||
extends ThemeProps,
|
||||
LocaleProps,
|
||||
BaseCheckboxesProps {
|
||||
inline?: boolean;
|
||||
statistics?: boolean;
|
||||
showArrow?: boolean;
|
||||
|
@ -98,7 +102,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
@autobind
|
||||
toggleAll() {
|
||||
const {options, option2value, onChange, value} = this.props;
|
||||
let valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
let valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
const availableOptions = flattenTree(options).filter(
|
||||
(option, index, list) =>
|
||||
!option.disabled &&
|
||||
|
@ -185,7 +189,8 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
onSearch,
|
||||
disabled,
|
||||
options,
|
||||
statistics
|
||||
statistics,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (selectRender) {
|
||||
|
@ -206,7 +211,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
)}
|
||||
>
|
||||
<span>
|
||||
{selectTitle}
|
||||
{__(selectTitle)}
|
||||
{statistics !== false ? (
|
||||
<span>
|
||||
({this.valueArray.length}/{this.availableOptions.length})
|
||||
|
@ -221,7 +226,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
disabled || !options.length ? 'is-disabled' : ''
|
||||
)}
|
||||
>
|
||||
全选
|
||||
{__('全选')}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -231,7 +236,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
<InputBox
|
||||
value={this.state.inputValue}
|
||||
onChange={this.handleSearch}
|
||||
placeholder="请输入关键字"
|
||||
placeholder={__('请输入关键字')}
|
||||
clearable={false}
|
||||
>
|
||||
{this.state.searchResult !== null ? (
|
||||
|
@ -393,10 +398,11 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
option2value,
|
||||
disabled,
|
||||
statistics,
|
||||
showArrow
|
||||
showArrow,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
this.valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
this.availableOptions = flattenTree(options).filter(
|
||||
(option, index, list) =>
|
||||
!option.disabled &&
|
||||
|
@ -419,7 +425,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
<div className={cx('Transfer-result')}>
|
||||
<div className={cx('Transfer-title')}>
|
||||
<span>
|
||||
{resultTitle}
|
||||
{__(resultTitle)}
|
||||
{statistics !== false ? (
|
||||
<span>
|
||||
({this.valueArray.length}/{this.availableOptions.length})
|
||||
|
@ -433,7 +439,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
disabled || !this.valueArray.length ? 'is-disabled' : ''
|
||||
)}
|
||||
>
|
||||
清空
|
||||
{__('清空')}
|
||||
</a>
|
||||
</div>
|
||||
<ResultList
|
||||
|
@ -441,7 +447,7 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
sortable={sortable}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder="请先选择左侧数据"
|
||||
placeholder={__('请先选择左侧数据')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -450,7 +456,9 @@ export class Transfer extends React.Component<TransferProps, TransferState> {
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Transfer, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(Transfer, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -14,15 +14,13 @@ import {
|
|||
createObject
|
||||
} from '../utils/helper';
|
||||
import {Option, Options, value2array} from './Select';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {highlight} from '../renderers/Form/Options';
|
||||
import {Icon} from './icons';
|
||||
import Checkbox from './Checkbox';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
interface TreeSelectorProps {
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
|
||||
interface TreeSelectorProps extends ThemeProps, LocaleProps {
|
||||
highlightTxt?: string;
|
||||
|
||||
showIcon?: boolean;
|
||||
|
@ -421,7 +419,7 @@ export class TreeSelector extends React.Component<
|
|||
}
|
||||
|
||||
renderInput(prfix: JSX.Element | null = null) {
|
||||
const {classnames: cx} = this.props;
|
||||
const {classnames: cx, translate: __} = this.props;
|
||||
const {inputValue} = this.state;
|
||||
|
||||
return (
|
||||
|
@ -431,12 +429,12 @@ export class TreeSelector extends React.Component<
|
|||
<input
|
||||
onChange={this.handleInputChange}
|
||||
value={inputValue}
|
||||
placeholder="请输入"
|
||||
placeholder={__('请输入')}
|
||||
/>
|
||||
<a data-tooltip="取消" onClick={this.handleCancel}>
|
||||
<a data-tooltip={__('取消')} onClick={this.handleCancel}>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
<a data-tooltip="确认" onClick={this.handleConfirm}>
|
||||
<a data-tooltip={__('确认')} onClick={this.handleConfirm}>
|
||||
<Icon icon="check" className="icon" />
|
||||
</a>
|
||||
</div>
|
||||
|
@ -473,7 +471,8 @@ export class TreeSelector extends React.Component<
|
|||
removable,
|
||||
createTip,
|
||||
editTip,
|
||||
removeTip
|
||||
removeTip,
|
||||
translate: __
|
||||
} = this.props;
|
||||
const {
|
||||
unfolded,
|
||||
|
@ -611,7 +610,7 @@ export class TreeSelector extends React.Component<
|
|||
{creatable && hasAbility(item, 'creatable') ? (
|
||||
<a
|
||||
onClick={this.handleAdd.bind(this, item)}
|
||||
data-tooltip={createTip}
|
||||
data-tooltip={__(createTip)}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="plus" className="icon" />
|
||||
|
@ -621,7 +620,7 @@ export class TreeSelector extends React.Component<
|
|||
{removable && hasAbility(item, 'removable') ? (
|
||||
<a
|
||||
onClick={this.handleRemove.bind(this, item)}
|
||||
data-tooltip={removeTip}
|
||||
data-tooltip={__(removeTip)}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="minus" className="icon" />
|
||||
|
@ -631,7 +630,7 @@ export class TreeSelector extends React.Component<
|
|||
{editable && hasAbility(item, 'editable') ? (
|
||||
<a
|
||||
onClick={this.handleEdit.bind(this, item)}
|
||||
data-tooltip={editTip}
|
||||
data-tooltip={__(editTip)}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="pencil" className="icon" />
|
||||
|
@ -689,7 +688,8 @@ export class TreeSelector extends React.Component<
|
|||
creatable,
|
||||
rootCreatable,
|
||||
rootCreateTip,
|
||||
disabled
|
||||
disabled,
|
||||
translate: __
|
||||
} = this.props;
|
||||
let options = this.props.options;
|
||||
const {value, isAdding, addingParent, isEditing, inputValue} = this.state;
|
||||
|
@ -705,7 +705,7 @@ export class TreeSelector extends React.Component<
|
|||
onClick={this.handleAdd.bind(this, null)}
|
||||
>
|
||||
<Icon icon="plus" className="icon" />
|
||||
<span>{rootCreateTip}</span>
|
||||
<span>{__(rootCreateTip)}</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
@ -772,4 +772,4 @@ export class TreeSelector extends React.Component<
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(TreeSelector);
|
||||
export default themeable(localeable(TreeSelector));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {Checkboxes, CheckboxesProps} from './Checkboxes';
|
||||
import {BaseCheckboxes, BaseCheckboxesProps} from './Checkboxes';
|
||||
import {themeable} from '../theme';
|
||||
import React from 'react';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
|
@ -6,8 +6,9 @@ import Checkbox from './Checkbox';
|
|||
import {Option} from './Select';
|
||||
import {autobind, eachTree, everyTree} from '../utils/helper';
|
||||
import Spinner from './Spinner';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export interface TreeCheckboxesProps extends CheckboxesProps {
|
||||
export interface TreeCheckboxesProps extends BaseCheckboxesProps {
|
||||
expand?: 'all' | 'first' | 'root' | 'none';
|
||||
}
|
||||
|
||||
|
@ -15,7 +16,7 @@ export interface TreeCheckboxesState {
|
|||
expanded: Array<string>;
|
||||
}
|
||||
|
||||
export class TreeCheckboxes extends Checkboxes<
|
||||
export class TreeCheckboxes extends BaseCheckboxes<
|
||||
TreeCheckboxesProps,
|
||||
TreeCheckboxesState
|
||||
> {
|
||||
|
@ -25,7 +26,7 @@ export class TreeCheckboxes extends Checkboxes<
|
|||
};
|
||||
|
||||
static defaultProps = {
|
||||
...Checkboxes.defaultProps,
|
||||
...BaseCheckboxes.defaultProps,
|
||||
expand: 'first' as 'first'
|
||||
};
|
||||
|
||||
|
@ -83,7 +84,7 @@ export class TreeCheckboxes extends Checkboxes<
|
|||
return;
|
||||
}
|
||||
|
||||
let valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
let valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
|
||||
if (
|
||||
option.value === void 0 &&
|
||||
|
@ -257,10 +258,11 @@ export class TreeCheckboxes extends Checkboxes<
|
|||
className,
|
||||
placeholder,
|
||||
classnames: cx,
|
||||
option2value
|
||||
option2value,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
this.valueArray = BaseCheckboxes.value2array(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
if (Array.isArray(options) && options.length) {
|
||||
|
@ -272,7 +274,9 @@ export class TreeCheckboxes extends Checkboxes<
|
|||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('TreeCheckboxes-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('TreeCheckboxes-placeholder')}>
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -280,7 +284,9 @@ export class TreeCheckboxes extends Checkboxes<
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(TreeCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(TreeCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -5,23 +5,24 @@ import Checkbox from './Checkbox';
|
|||
import {Option} from './Select';
|
||||
import {autobind, eachTree, everyTree} from '../utils/helper';
|
||||
import Spinner from './Spinner';
|
||||
import {ListRadiosProps, ListRadios} from './ListRadios';
|
||||
import {BaseRadiosProps, BaseRadios} from './ListRadios';
|
||||
import {localeable} from '../locale';
|
||||
|
||||
export interface TreeRadiosProps extends ListRadiosProps {
|
||||
expand?: 'all' | 'first' | 'root' | 'none';
|
||||
export interface TreeRadiosProps extends BaseRadiosProps {
|
||||
expand: 'all' | 'first' | 'root' | 'none';
|
||||
}
|
||||
|
||||
export interface TreeRadiosState {
|
||||
expanded: Array<string>;
|
||||
}
|
||||
|
||||
export class TreeRadios extends ListRadios<TreeRadiosProps, TreeRadiosState> {
|
||||
export class TreeRadios extends BaseRadios<TreeRadiosProps, TreeRadiosState> {
|
||||
state: TreeRadiosState = {
|
||||
expanded: []
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
...ListRadios.defaultProps,
|
||||
...BaseRadios.defaultProps,
|
||||
expand: 'first' as 'first'
|
||||
};
|
||||
|
||||
|
@ -168,10 +169,11 @@ export class TreeRadios extends ListRadios<TreeRadiosProps, TreeRadiosState> {
|
|||
className,
|
||||
placeholder,
|
||||
classnames: cx,
|
||||
option2value
|
||||
option2value,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.selected = ListRadios.resolveSelected(value, options, option2value);
|
||||
this.selected = BaseRadios.resolveSelected(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
if (Array.isArray(options) && options.length) {
|
||||
|
@ -183,7 +185,7 @@ export class TreeRadios extends ListRadios<TreeRadiosProps, TreeRadiosState> {
|
|||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('TreeRadios-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('TreeRadios-placeholder')}>{__(placeholder)}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -191,7 +193,9 @@ export class TreeRadios extends ListRadios<TreeRadiosProps, TreeRadiosState> {
|
|||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(TreeRadios, {
|
||||
value: 'onChange'
|
||||
})
|
||||
localeable(
|
||||
uncontrollable(TreeRadios, {
|
||||
value: 'onChange'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -2,8 +2,9 @@ import moment from 'moment';
|
|||
// @ts-ignore
|
||||
import DaysView from 'react-datetime/src/DaysView';
|
||||
import React from 'react';
|
||||
import {LocaleProps, localeable} from '../../locale';
|
||||
|
||||
interface CustomDaysViewProps {
|
||||
interface CustomDaysViewProps extends LocaleProps {
|
||||
classPrefix?: string;
|
||||
prevIcon?: string;
|
||||
nextIcon?: string;
|
||||
|
@ -36,7 +37,7 @@ interface CustomDaysViewProps {
|
|||
handleClickOutside: () => void;
|
||||
}
|
||||
|
||||
export default class CustomDaysView extends DaysView {
|
||||
export class CustomDaysView extends DaysView {
|
||||
props: CustomDaysViewProps;
|
||||
getDaysOfWeek: (locale: any) => any;
|
||||
renderDays: () => JSX.Element;
|
||||
|
@ -160,6 +161,8 @@ export default class CustomDaysView extends DaysView {
|
|||
return null;
|
||||
}
|
||||
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<tfoot key="tf">
|
||||
<tr>
|
||||
|
@ -168,10 +171,10 @@ export default class CustomDaysView extends DaysView {
|
|||
{this.props.requiredConfirm ? (
|
||||
<div key="button" className="rdtActions">
|
||||
<a className="rdtBtn rdtBtnConfirm" onClick={this.confirm}>
|
||||
确认
|
||||
{__('确认')}
|
||||
</a>
|
||||
<a className="rdtBtn rdtBtnCancel" onClick={this.cancel}>
|
||||
取消
|
||||
{__('取消')}
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
|
@ -185,6 +188,7 @@ export default class CustomDaysView extends DaysView {
|
|||
const footer = this.renderFooter();
|
||||
const date = this.props.viewDate;
|
||||
const locale = date.localeData();
|
||||
const __ = this.props.translate;
|
||||
|
||||
const tableChildren = [
|
||||
<thead key="th">
|
||||
|
@ -206,13 +210,13 @@ export default class CustomDaysView extends DaysView {
|
|||
|
||||
<div className="rdtCenter">
|
||||
<a className="rdtSwitch" onClick={this.props.showView('years')}>
|
||||
{date.format('YYYY年')}
|
||||
{date.format(__('YYYY年'))}
|
||||
</a>
|
||||
<a
|
||||
className="rdtSwitch"
|
||||
onClick={this.props.showView('months')}
|
||||
>
|
||||
{date.format('MM月')}
|
||||
{date.format(__('MMM'))}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
@ -246,3 +250,7 @@ export default class CustomDaysView extends DaysView {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default localeable(
|
||||
(CustomDaysView as any) as React.ComponentClass<CustomDaysViewProps>
|
||||
);
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
import MonthsView from 'react-datetime/src/MonthsView';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import {LocaleProps, localeable} from '../../locale';
|
||||
|
||||
export default class CustomMonthsView extends MonthsView {
|
||||
export class CustomMonthsView extends MonthsView {
|
||||
props: {
|
||||
viewDate: moment.Moment;
|
||||
subtractTime: (
|
||||
|
@ -16,7 +17,7 @@ export default class CustomMonthsView extends MonthsView {
|
|||
type: string,
|
||||
toSelected?: moment.Moment
|
||||
) => () => void;
|
||||
};
|
||||
} & LocaleProps;
|
||||
renderMonths: () => JSX.Element;
|
||||
renderMonth = (props: any, month: number) => {
|
||||
var localMoment = this.props.viewDate;
|
||||
|
@ -34,6 +35,8 @@ export default class CustomMonthsView extends MonthsView {
|
|||
);
|
||||
};
|
||||
render() {
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div className="rdtMonths">
|
||||
<table>
|
||||
|
@ -45,7 +48,9 @@ export default class CustomMonthsView extends MonthsView {
|
|||
>
|
||||
«
|
||||
</th>
|
||||
<th className="rdtSwitch">{this.props.viewDate.year()}年</th>
|
||||
<th className="rdtSwitch">
|
||||
{this.props.viewDate.format(__('YYYY年'))}
|
||||
</th>
|
||||
<th className="rdtNext" onClick={this.props.addTime(1, 'years')}>
|
||||
»
|
||||
</th>
|
||||
|
@ -59,3 +64,5 @@ export default class CustomMonthsView extends MonthsView {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default localeable(CustomMonthsView as any);
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
import YearsView from 'react-datetime/src/YearsView';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import {LocaleProps, localeable} from '../../locale';
|
||||
|
||||
export default class CustomYearsView extends YearsView {
|
||||
export class CustomYearsView extends YearsView {
|
||||
props: {
|
||||
viewDate: moment.Moment;
|
||||
subtractTime: (
|
||||
|
@ -17,7 +18,7 @@ export default class CustomYearsView extends YearsView {
|
|||
toSelected?: moment.Moment
|
||||
) => () => void;
|
||||
showView: (view: string) => () => void;
|
||||
};
|
||||
} & LocaleProps;
|
||||
renderYears: (year: number) => JSX.Element;
|
||||
renderYear = (props: any, year: number) => {
|
||||
return (
|
||||
|
@ -29,6 +30,7 @@ export default class CustomYearsView extends YearsView {
|
|||
render() {
|
||||
let year = this.props.viewDate.year();
|
||||
year = year - (year % 10);
|
||||
const __ = this.props.translate;
|
||||
|
||||
return (
|
||||
<div className="rdtYears">
|
||||
|
@ -42,7 +44,7 @@ export default class CustomYearsView extends YearsView {
|
|||
«
|
||||
</th>
|
||||
<th className="rdtSwitch">
|
||||
{year}年-{year + 9}年
|
||||
{__('{{from}}年-{{to}}年', {from: year, to: year + 9})}
|
||||
</th>
|
||||
<th className="rdtNext" onClick={this.props.addTime(10, 'years')}>
|
||||
»
|
||||
|
@ -57,3 +59,5 @@ export default class CustomYearsView extends YearsView {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default localeable(CustomYearsView as any);
|
||||
|
|
|
@ -24,7 +24,6 @@ import {
|
|||
SchemaNode,
|
||||
Schema,
|
||||
Action,
|
||||
Omit,
|
||||
RendererData
|
||||
} from './types';
|
||||
import {observer} from 'mobx-react';
|
||||
|
@ -34,11 +33,24 @@ import omit from 'lodash/omit';
|
|||
import difference from 'lodash/difference';
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
import Scoped from './Scoped';
|
||||
import {getTheme, ThemeInstance, ClassNamesFn, ThemeContext} from './theme';
|
||||
import {
|
||||
getTheme,
|
||||
ThemeInstance,
|
||||
ClassNamesFn,
|
||||
ThemeContext,
|
||||
ThemeProps
|
||||
} from './theme';
|
||||
import find from 'lodash/find';
|
||||
import Alert from './components/Alert2';
|
||||
import {LazyComponent} from './components';
|
||||
import ImageGallery from './components/ImageGallery';
|
||||
import {
|
||||
TranslateFn,
|
||||
getDefaultLocale,
|
||||
makeTranslator,
|
||||
LocaleContext,
|
||||
LocaleProps
|
||||
} from './locale';
|
||||
|
||||
export interface TestFunc {
|
||||
(
|
||||
|
@ -98,11 +110,9 @@ export interface RendererEnv {
|
|||
[propName: string]: any;
|
||||
}
|
||||
|
||||
export interface RendererProps {
|
||||
export interface RendererProps extends ThemeProps, LocaleProps {
|
||||
render: (region: string, node: SchemaNode, props?: any) => JSX.Element;
|
||||
env: RendererEnv;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
$path: string; // 当前组件所在的层级信息
|
||||
store?: IIRendererStore;
|
||||
syncSuperStore?: boolean;
|
||||
|
@ -193,7 +203,7 @@ export function filterSchema(
|
|||
}
|
||||
|
||||
export function Renderer(config: RendererBasicConfig) {
|
||||
return function<T extends RendererComponent>(component: T): T {
|
||||
return function <T extends RendererComponent>(component: T): T {
|
||||
const renderer = registerRenderer({
|
||||
...config,
|
||||
component: component
|
||||
|
@ -215,9 +225,7 @@ export function registerRenderer(config: RendererConfig): RendererConfig {
|
|||
|
||||
if (~rendererNames.indexOf(config.name)) {
|
||||
throw new Error(
|
||||
`The renderer with name "${
|
||||
config.name
|
||||
}" has already exists, please try another name!`
|
||||
`The renderer with name "${config.name}" has already exists, please try another name!`
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -322,6 +330,8 @@ export interface RootRendererProps {
|
|||
env: RendererEnv;
|
||||
theme: string;
|
||||
pathPrefix?: string;
|
||||
locale?: string;
|
||||
translate?: TranslateFn;
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
|
@ -362,6 +372,8 @@ export class RootRenderer extends React.Component<RootRendererProps> {
|
|||
pathPrefix,
|
||||
location,
|
||||
data,
|
||||
locale,
|
||||
translate,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
|
@ -385,28 +397,32 @@ export class RootRenderer extends React.Component<RootRendererProps> {
|
|||
return (
|
||||
<RootStoreContext.Provider value={rootStore}>
|
||||
<ThemeContext.Provider value={this.props.theme || 'default'}>
|
||||
<ImageGallery modalContainer={env.getModalContainer}>
|
||||
{
|
||||
renderChild(
|
||||
pathPrefix || '',
|
||||
isPlainObject(schema)
|
||||
? {
|
||||
type: 'page',
|
||||
...(schema as Schema)
|
||||
}
|
||||
: schema,
|
||||
{
|
||||
...rest,
|
||||
resolveDefinitions: this.resolveDefinitions,
|
||||
location: location,
|
||||
data: finalData,
|
||||
env,
|
||||
classnames: theme.classnames,
|
||||
classPrefix: theme.classPrefix
|
||||
}
|
||||
) as JSX.Element
|
||||
}
|
||||
</ImageGallery>
|
||||
<LocaleContext.Provider value={this.props.locale!}>
|
||||
<ImageGallery modalContainer={env.getModalContainer}>
|
||||
{
|
||||
renderChild(
|
||||
pathPrefix || '',
|
||||
isPlainObject(schema)
|
||||
? {
|
||||
type: 'page',
|
||||
...(schema as any)
|
||||
}
|
||||
: schema,
|
||||
{
|
||||
...rest,
|
||||
resolveDefinitions: this.resolveDefinitions,
|
||||
location: location,
|
||||
data: finalData,
|
||||
env,
|
||||
classnames: theme.classnames,
|
||||
classPrefix: theme.classPrefix,
|
||||
locale,
|
||||
translate
|
||||
}
|
||||
) as JSX.Element
|
||||
}
|
||||
</ImageGallery>
|
||||
</LocaleContext.Provider>
|
||||
</ThemeContext.Provider>
|
||||
</RootStoreContext.Provider>
|
||||
);
|
||||
|
@ -634,7 +650,7 @@ export function HocStoreFactory(renderer: {
|
|||
storeType: string;
|
||||
extendsData?: boolean;
|
||||
}): any {
|
||||
return function<T extends React.ComponentType<RendererProps>>(Component: T) {
|
||||
return function <T extends React.ComponentType<RendererProps>>(Component: T) {
|
||||
type Props = Omit<
|
||||
RendererProps,
|
||||
'store' | 'data' | 'dataUpdatedAt' | 'scope'
|
||||
|
@ -646,8 +662,9 @@ export function HocStoreFactory(renderer: {
|
|||
|
||||
@observer
|
||||
class StoreFactory extends React.Component<Props> {
|
||||
static displayName = `WithStore(${Component.displayName ||
|
||||
Component.name})`;
|
||||
static displayName = `WithStore(${
|
||||
Component.displayName || Component.name
|
||||
})`;
|
||||
static ComposedComponent = Component;
|
||||
static contextType = RootStoreContext;
|
||||
store: IIRendererStore;
|
||||
|
@ -839,7 +856,7 @@ export function HocStoreFactory(renderer: {
|
|||
return (
|
||||
<Component
|
||||
{
|
||||
...rest as any /* todo */
|
||||
...(rest as any) /* todo */
|
||||
}
|
||||
{...exprProps}
|
||||
ref={this.refFn}
|
||||
|
@ -956,6 +973,8 @@ export function render(
|
|||
const env = getEnv(store);
|
||||
const theme = props.theme || options.theme || 'default';
|
||||
env.theme = getTheme(theme);
|
||||
const locale = props.locale || getDefaultLocale();
|
||||
const translate = props.translate || makeTranslator(locale);
|
||||
|
||||
return (
|
||||
<ScopedRootRenderer
|
||||
|
@ -965,6 +984,8 @@ export function render(
|
|||
rootStore={store}
|
||||
env={env}
|
||||
theme={theme}
|
||||
locale={locale}
|
||||
translate={translate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
// 多语言支持
|
||||
import React from 'react';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
import {resolveVariable} from './utils/tpl-builtin';
|
||||
|
||||
export type TranslateFn<T = any> = (str: T, data?: object) => T;
|
||||
|
||||
interface LocaleConfig {
|
||||
[propsName: string]: string;
|
||||
}
|
||||
|
||||
let defaultLocale: string = 'zh-cn';
|
||||
|
||||
const locales: {
|
||||
[propName: string]: LocaleConfig;
|
||||
} = {};
|
||||
|
||||
export function register(name: string, config: LocaleConfig) {
|
||||
locales[name] = config;
|
||||
}
|
||||
|
||||
const fns: {
|
||||
[propName: string]: TranslateFn;
|
||||
} = {};
|
||||
|
||||
function format(str: string, data?: object) {
|
||||
return str.replace(/(\\)?\{\{([\s\S]+?)\}\}/g, (_, escape, key) => {
|
||||
if (escape) {
|
||||
return _.substring(1);
|
||||
}
|
||||
|
||||
return resolveVariable(key, data || {});
|
||||
});
|
||||
}
|
||||
|
||||
export function makeTranslator(locale?: string): TranslateFn {
|
||||
if (locale && fns[locale]) {
|
||||
return fns[locale];
|
||||
}
|
||||
|
||||
const fn = (str: any, ...args: any[]) => {
|
||||
if (!str || typeof str !== 'string') {
|
||||
return str;
|
||||
}
|
||||
|
||||
const dict = locales[locale!] || locales[defaultLocale];
|
||||
return format(dict?.[str] || str, ...args);
|
||||
};
|
||||
|
||||
locale && (fns[locale] = fn);
|
||||
return fn;
|
||||
}
|
||||
|
||||
export function getDefaultLocale() {
|
||||
return defaultLocale;
|
||||
}
|
||||
|
||||
export function setDefaultLocale(loacle: string) {
|
||||
defaultLocale = loacle;
|
||||
}
|
||||
|
||||
export interface LocaleProps {
|
||||
locale: string;
|
||||
translate: TranslateFn;
|
||||
}
|
||||
|
||||
export const LocaleContext = React.createContext('');
|
||||
|
||||
export function localeable<
|
||||
T extends React.ComponentType<React.ComponentProps<T> & LocaleProps>
|
||||
>(ComposedComponent: T) {
|
||||
type OuterProps = JSX.LibraryManagedAttributes<
|
||||
T,
|
||||
Omit<React.ComponentProps<T>, keyof LocaleProps>
|
||||
> & {
|
||||
locale?: string;
|
||||
translate?: (str: string, ...args: any[]) => string;
|
||||
};
|
||||
|
||||
const result = hoistNonReactStatic(
|
||||
class extends React.Component<OuterProps> {
|
||||
static displayName = `I18N(${
|
||||
ComposedComponent.displayName || ComposedComponent.name
|
||||
})`;
|
||||
static contextType = LocaleContext;
|
||||
static ComposedComponent = ComposedComponent;
|
||||
|
||||
render() {
|
||||
const locale: string =
|
||||
this.props.locale || this.context || defaultLocale;
|
||||
const translate = this.props.translate || makeTranslator(locale);
|
||||
const injectedProps: {
|
||||
locale: string;
|
||||
translate: TranslateFn;
|
||||
} = {
|
||||
locale,
|
||||
translate: translate!
|
||||
};
|
||||
|
||||
return (
|
||||
<LocaleContext.Provider value={locale}>
|
||||
<ComposedComponent
|
||||
{...(this.props as JSX.LibraryManagedAttributes<
|
||||
T,
|
||||
React.ComponentProps<T>
|
||||
>)}
|
||||
{...injectedProps}
|
||||
/>
|
||||
</LocaleContext.Provider>
|
||||
);
|
||||
}
|
||||
},
|
||||
ComposedComponent
|
||||
);
|
||||
|
||||
return result as typeof result & {
|
||||
ComposedComponent: T;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
import {register} from '../locale';
|
||||
|
||||
register('en', {
|
||||
'确认': 'Confirm',
|
||||
'取消': 'Cancel',
|
||||
'YYYY年': 'YYYY',
|
||||
'MM月': 'MMM',
|
||||
'{{from}}年-{{to}}年': '{{from}} - {{to}}',
|
||||
'请选择日期': 'Select Date',
|
||||
'请选择日期以及时间': 'Select Datetime',
|
||||
'请选择时间': 'Select time',
|
||||
'系统消息': 'System Info',
|
||||
'加载中': 'Loading',
|
||||
'点击刷新重新加载': 'Click to refresh',
|
||||
'请先选择左侧数据': 'Select from left first.',
|
||||
'请选择颜色': 'Select color',
|
||||
'现在': 'now',
|
||||
'今天': 'today',
|
||||
'昨天': 'yesterday',
|
||||
'本周一': 'this monday',
|
||||
'本月初': 'early this month',
|
||||
'上个月初': 'early prev month',
|
||||
'上个季节初': 'early this quarter',
|
||||
'明天': 'tomorrow',
|
||||
'本周日': 'last day of this week',
|
||||
'本月底': 'last day of this month',
|
||||
'{{hours}}小时前': '{{hours}} hour(s) ago',
|
||||
'{{hours}}小时后': '{{hours}} hour(s) after',
|
||||
'{{days}}天前': '{{days}} day(s) ago',
|
||||
'{{days}}天后': '{{days}} day(s) after',
|
||||
'{{weeks}}周前': '{{weeks}} week(s) ago',
|
||||
'{{weeks}}周后': '{{weeks}} week(s) after',
|
||||
'{{months}}月前': '{{months}} month(s) ago',
|
||||
'{{months}}月后': '{{months}} month(s) after',
|
||||
'{{quarters}}季度前': '{{quarters}} quarter(s) ago',
|
||||
'{{quarters}}季度后': '{{quarters}} quarter(s) after',
|
||||
' 至 ': ' to ',
|
||||
'最近1天': 'last day',
|
||||
'最近7天': 'last week',
|
||||
'最近90天': 'last 90 days',
|
||||
'上周': 'prev week',
|
||||
'本月': 'this month',
|
||||
'上个月': 'prev month',
|
||||
'上个季节': 'prev quarter',
|
||||
'本季度': 'this quarter',
|
||||
'请选择日期范围': 'Select daterange',
|
||||
'关闭': 'Close',
|
||||
'暂无选项': 'No options',
|
||||
'请选择位置': 'Pick location',
|
||||
'无': 'None',
|
||||
'没有数据': 'No data',
|
||||
'请先选择数据': 'Select data first',
|
||||
'请选择': 'Select',
|
||||
'全选': 'Check all',
|
||||
'搜索结果': 'Search result',
|
||||
'清空': 'Clear',
|
||||
'当前选择': 'Selected',
|
||||
'添加一级节点': 'Add root node',
|
||||
'添加孩子节点': 'Add child',
|
||||
'编辑该节点': 'Edit this node',
|
||||
'移除该节点': 'Remove this node',
|
||||
'请输入': 'Enter',
|
||||
'请输入关键字': 'Enter keywords',
|
||||
'新增选项': 'New option',
|
||||
'请输入街道信息': 'Enter street info',
|
||||
'删除': 'Delete',
|
||||
'新增': 'New',
|
||||
'新增一条数据': 'Create a new data',
|
||||
'类型': 'Type',
|
||||
'拖拽排序': 'Drag to sort',
|
||||
'删除失败': 'Delete failed',
|
||||
'确认要删除?': 'Are you sure you want to delete?',
|
||||
'组合表单成员数量不够,低于设定的最小{{minLenth}}个,请添加更多的成员。':
|
||||
'The number of combined form members is not enough. It is lower than the minimum {{minlenth}} set. Please add more members.',
|
||||
'组合表单成员数量超出,超出设定的最大{{maxLength}}个,请删除多余的成员。':
|
||||
'The number of combined form members exceeds the set maximum of {{MaxLength}}}. Please delete the extra members.',
|
||||
'子表单验证失败,请仔细检查': 'Validate failed, please check this Subform.',
|
||||
'成员{{index}}': 'Member {{index}}',
|
||||
'清空数据': 'Clear data',
|
||||
'您选择的文件 {{filename}} 大小为 {{actualSize}} 超出了最大为 {{maxSize}} 的限制,请重新选择。':
|
||||
'The file {{filename}} you selected has a size of {actualsize}} which exceeds the maximum limit of {{maxsize}}. Please select again.',
|
||||
|
||||
'您添加的文件{{files}}不符合类型的`{{accept}}`的设定,请仔细检查。':
|
||||
'The file you added {{files}} does not match the setting of the type `{{accept}}`. Please check it carefully.',
|
||||
'把文件拖到这,然后松完成添加!':
|
||||
'Drag the file here, then release to finish adding!',
|
||||
'把图片拖到这,然后松开完成添加!':
|
||||
'Drag the picture here, then release to finish adding!',
|
||||
'重新上传': 'Repick',
|
||||
'重试上传': 'Retry',
|
||||
'继续添加': 'Continue add',
|
||||
'上传文件': 'Upload file',
|
||||
'移除': 'Remove',
|
||||
'暂停上传': 'Pause uplaod',
|
||||
'开始上传': 'Start upload',
|
||||
'已成功上传{{uploaded}}个文件,{{failed}}个文件上传失败,':
|
||||
'Successfully uploaded {{uploaded}} files, failed to upload {{failed}} files,',
|
||||
'失败文件': 'failed files.',
|
||||
'高度{{height}}px': 'height: {{height}}px',
|
||||
'宽度{{width}}px': 'width: {{width}}px',
|
||||
'尺寸({{width}} x {{height}})': 'size: ({{width}}px x {{height}}px)',
|
||||
'您选择的图片不符合尺寸要求, 请上传{{info}}的图片':
|
||||
'The picture you selected does not meet the size requirements. Please upload the picture of {{info}}',
|
||||
'您选择的图片不符合尺寸要求, 请上传不要超过{{info}}的图片':
|
||||
'The picture you selected does not meet the size requirements. Please upload a picture that does not exceed {{info}}`.',
|
||||
'您选择的图片不符合尺寸要求, 请上传不要小于{{info}}的图片':
|
||||
'The picture you selected does not meet the size requirements. Please upload a picture no less than {{info}}',
|
||||
'您选择的图片不符合尺寸要求, 请上传尺寸比率为 {{ratio}} 的图片':
|
||||
'The picture you selected does not meet the size requirements. Please upload the picture with the size ratio of ${ration}',
|
||||
'文件上传失败请重试': 'File upload failed, please try again',
|
||||
'文件上传中': 'File uploading',
|
||||
'查看大图': 'Zoom',
|
||||
'裁剪图片': 'Crop picture',
|
||||
'当前状态支持从剪切板中粘贴图片文件。':
|
||||
'The current state supports pasting picture files from the clipboard.',
|
||||
'表单': 'Form',
|
||||
'提交': 'Submit',
|
||||
'初始化失败': 'Initialization failed',
|
||||
'保存成功': 'Saved successfully',
|
||||
'保存失败': 'Save failed',
|
||||
'依赖的部分字段没有通过验证,请注意填写!':
|
||||
'Some of the dependent fields failed to pass the verification, please fill in!',
|
||||
'请输入名称': 'Please enter a name',
|
||||
'编辑{{label}}': 'Edit {{label}}',
|
||||
'每': 'Per',
|
||||
'编辑详情': 'Detail',
|
||||
'删除当前行': 'Delete current row',
|
||||
'操作': 'Operation',
|
||||
'新增一行': 'Add a new row',
|
||||
'暂无标签': 'No tag yet',
|
||||
'新增:{{label}}': 'New {{label}}',
|
||||
'顶级': 'Root',
|
||||
'点击复制': 'Copy',
|
||||
'{{page}}/{{lastPage}} 总共:{{total}} 项。':
|
||||
'{{page}} of {{lastPage}} total: {{total}}.',
|
||||
'每页显示': 'Per page',
|
||||
'加载更多': 'Load more',
|
||||
'筛选': 'Filter',
|
||||
'搜索': 'Search',
|
||||
'日期无效': 'Invalid date',
|
||||
'关闭弹窗': 'Close',
|
||||
'链接': 'Link',
|
||||
'当前有 {{modified}} 条记录修改了内容, 但并没有提交。请选择:':
|
||||
'There are currently {{modified}} records that have modified the contents, but they have not been submitted. Please select:',
|
||||
'放弃': 'Give up',
|
||||
'当前有 {{moved}} 条记录修改了顺序, 但并没有提交。请选择:':
|
||||
'There are currently {{moved}} records that have changed the order, but have not been committed. Please select:',
|
||||
'点击开始排序': 'Click to start sorting',
|
||||
'请拖动左边的按钮进行排序': 'Please drag the button on the left to sort',
|
||||
'排序': 'Sort',
|
||||
'正序': 'Asc',
|
||||
'降序': 'Desc'
|
||||
});
|
|
@ -40,7 +40,6 @@ const ActionProps = [
|
|||
];
|
||||
import {filterContents} from './Remark';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {Omit} from '../types';
|
||||
import {autobind} from '../utils/helper';
|
||||
|
||||
export interface ActionProps {
|
||||
|
|
|
@ -1335,16 +1335,20 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
}
|
||||
|
||||
renderStatistics() {
|
||||
const {store, classnames: cx} = this.props;
|
||||
const {store, classnames: cx, translate: __} = this.props;
|
||||
|
||||
if (store.lastPage <= 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx('Crud-statistics')}>{`${
|
||||
store.page + '/' + store.lastPage
|
||||
}总共${store.total}项。`}</div>
|
||||
<div className={cx('Crud-statistics')}>
|
||||
{__('{{page}}/{{lastPage}} 总共:{{total}} 项。', {
|
||||
page: store.page,
|
||||
lastPage: store.lastPage,
|
||||
total: store.total
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1353,7 +1357,8 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
store,
|
||||
perPageAvailable,
|
||||
classnames: cx,
|
||||
classPrefix: ns
|
||||
classPrefix: ns,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const items = childProps.items;
|
||||
|
@ -1371,11 +1376,11 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
|
||||
return (
|
||||
<div className={cx('Crud-pageSwitch')}>
|
||||
每页显示
|
||||
{__('每页显示')}
|
||||
<Select
|
||||
classPrefix={ns}
|
||||
searchable={false}
|
||||
placeholder="请选择.."
|
||||
placeholder={__('请选择')}
|
||||
options={perPages}
|
||||
value={store.perPage + ''}
|
||||
onChange={(value: any) => this.handleChangePage(1, value.value)}
|
||||
|
@ -1386,7 +1391,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
}
|
||||
|
||||
renderLoadMore() {
|
||||
const {store, classPrefix: ns, classnames: cx} = this.props;
|
||||
const {store, classPrefix: ns, classnames: cx, translate: __} = this.props;
|
||||
const {page, lastPage} = store;
|
||||
|
||||
return page < lastPage ? (
|
||||
|
@ -1399,7 +1404,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
size="sm"
|
||||
className="btn-primary"
|
||||
>
|
||||
加载更多
|
||||
{__('加载更多')}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
|
@ -1408,7 +1413,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
}
|
||||
|
||||
renderFilterToggler() {
|
||||
const {store, classnames: cx} = this.props;
|
||||
const {store, classnames: cx, translate: __} = this.props;
|
||||
|
||||
if (!store.filterTogggable) {
|
||||
return null;
|
||||
|
@ -1422,7 +1427,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
})}
|
||||
>
|
||||
<i className="fa fa-sliders m-r-sm" />
|
||||
筛选
|
||||
{__('筛选')}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
@ -1574,7 +1579,8 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
classnames: cx,
|
||||
labelField,
|
||||
labelTpl,
|
||||
primaryField
|
||||
primaryField,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (!store.selectedItems.length) {
|
||||
|
@ -1587,7 +1593,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
{store.selectedItems.map((item, index) => (
|
||||
<div key={index} className={cx(`Crud-value`)}>
|
||||
<span
|
||||
data-tooltip="删除"
|
||||
data-tooltip={__('删除')}
|
||||
data-position="bottom"
|
||||
className={cx('Crud-valueIcon')}
|
||||
onClick={this.unSelectItem.bind(this, item, index)}
|
||||
|
@ -1605,7 +1611,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
</div>
|
||||
))}
|
||||
<a onClick={this.clearSelection} className={cx('Crud-selectionClear')}>
|
||||
清空
|
||||
{__('清空')}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
@ -1633,6 +1639,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
keepItemSelectionOnPageChange,
|
||||
onAction,
|
||||
popOverContainer,
|
||||
translate: __,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
|
@ -1646,9 +1653,9 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
? render(
|
||||
'filter',
|
||||
{
|
||||
title: '条件过滤',
|
||||
title: __('条件过滤'),
|
||||
mode: 'inline',
|
||||
submitText: '搜索',
|
||||
submitText: __('搜索'),
|
||||
...filter,
|
||||
type: 'form',
|
||||
api: null
|
||||
|
|
|
@ -177,9 +177,9 @@ export default class Cards extends React.Component<GridProps, object> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
let parent: HTMLElement | Window | null = getScrollParent(findDOMNode(
|
||||
this
|
||||
) as HTMLElement);
|
||||
let parent: HTMLElement | Window | null = getScrollParent(
|
||||
findDOMNode(this) as HTMLElement
|
||||
);
|
||||
if (!parent || parent === document.body) {
|
||||
parent = window;
|
||||
}
|
||||
|
@ -282,9 +282,7 @@ export default class Cards extends React.Component<GridProps, object> {
|
|||
const afixedDom = dom.querySelector(`.${ns}Cards-fixedTop`) as HTMLElement;
|
||||
|
||||
this.body.offsetWidth &&
|
||||
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${
|
||||
this.body.offsetWidth
|
||||
}px;`);
|
||||
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${this.body.offsetWidth}px;`);
|
||||
affixed ? afixedDom.classList.add('in') : afixedDom.classList.remove('in');
|
||||
// store.markHeaderAffix(clip.top < offsetY && (clip.top + clip.height - 40) > offsetY);
|
||||
}
|
||||
|
@ -520,9 +518,7 @@ export default class Cards extends React.Component<GridProps, object> {
|
|||
<div className={cx('Cards-heading')}>
|
||||
{store.modified && !hideQuickSaveBtn ? (
|
||||
<span>
|
||||
{`当前有 ${
|
||||
store.modified
|
||||
} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
{`当前有 ${store.modified} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
<button
|
||||
type="button"
|
||||
className={cx('Button Button--xs Button--success m-l-sm')}
|
||||
|
@ -753,7 +749,8 @@ export default class Cards extends React.Component<GridProps, object> {
|
|||
masonryLayout,
|
||||
itemsClassName,
|
||||
classnames: cx,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.renderedToolbars = []; // 用来记录哪些 toolbar 已经渲染了,已经渲染了就不重复渲染了。
|
||||
|
@ -840,7 +837,7 @@ export default class Cards extends React.Component<GridProps, object> {
|
|||
</div>
|
||||
) : (
|
||||
<div className={cx('Cards-placeholder')}>
|
||||
{filter(placeholder, data)}
|
||||
{filter(__(placeholder), data)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ export const HocCopyable = () => (Component: React.ComponentType<any>): any => {
|
|||
className,
|
||||
data,
|
||||
noHoc,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (copyable && !noHoc) {
|
||||
|
@ -55,7 +56,7 @@ export const HocCopyable = () => (Component: React.ComponentType<any>): any => {
|
|||
<Component {...this.props} wrapperComponent={''} noHoc />
|
||||
<i
|
||||
key="edit-btn"
|
||||
data-tooltip="点击复制"
|
||||
data-tooltip={__('点击复制')}
|
||||
className={cx('Field-copyBtn fa fa-clipboard')}
|
||||
onClick={this.handleClick.bind(this, content)}
|
||||
/>
|
||||
|
|
|
@ -55,7 +55,8 @@ export class DateField extends React.Component<DateProps, DateState> {
|
|||
placeholder,
|
||||
fromNow,
|
||||
className,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
translate: __
|
||||
} = this.props;
|
||||
let viewValue: React.ReactNode = (
|
||||
<span className="text-muted">{placeholder}</span>
|
||||
|
@ -77,7 +78,7 @@ export class DateField extends React.Component<DateProps, DateState> {
|
|||
}
|
||||
|
||||
viewValue = !viewValue ? (
|
||||
<span className="text-danger">日期无效</span>
|
||||
<span className="text-danger">{__('日期无效')}</span>
|
||||
) : (
|
||||
viewValue
|
||||
);
|
||||
|
|
|
@ -122,7 +122,7 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
|||
}
|
||||
|
||||
buildActions(): Array<Action> {
|
||||
const {actions, confirm} = this.props;
|
||||
const {actions, confirm, translate: __} = this.props;
|
||||
|
||||
if (typeof actions !== 'undefined') {
|
||||
return actions;
|
||||
|
@ -132,14 +132,14 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
|||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'cancel',
|
||||
label: '取消'
|
||||
label: __('取消')
|
||||
});
|
||||
|
||||
if (confirm) {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '确认',
|
||||
label: __('确认'),
|
||||
primary: true
|
||||
});
|
||||
}
|
||||
|
@ -380,7 +380,8 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
|||
showCloseButton,
|
||||
env,
|
||||
classnames: cx,
|
||||
classPrefix
|
||||
classPrefix,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
// console.log('Render Dialog');
|
||||
|
@ -408,7 +409,7 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
|||
<div className={cx('Modal-header', headerClassName)}>
|
||||
{showCloseButton !== false && !store.loading ? (
|
||||
<a
|
||||
data-tooltip="关闭弹窗"
|
||||
data-tooltip={__('关闭弹窗')}
|
||||
data-position="left"
|
||||
onClick={this.handleSelfClose}
|
||||
className={cx('Modal-close')}
|
||||
|
@ -417,14 +418,14 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
|||
</a>
|
||||
) : null}
|
||||
<div className={cx('Modal-title')}>
|
||||
{filter(title, store.formData)}
|
||||
{filter(__(title), store.formData)}
|
||||
</div>
|
||||
</div>
|
||||
) : title ? (
|
||||
<div className={cx('Modal-header', headerClassName)}>
|
||||
{showCloseButton !== false && !store.loading ? (
|
||||
<a
|
||||
data-tooltip="关闭弹窗"
|
||||
data-tooltip={__('关闭弹窗')}
|
||||
onClick={this.handleSelfClose}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
|
@ -437,7 +438,7 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
|||
</div>
|
||||
) : showCloseButton !== false && !store.loading ? (
|
||||
<a
|
||||
data-tooltip="关闭弹窗"
|
||||
data-tooltip={__('关闭弹窗')}
|
||||
onClick={this.handleSelfClose}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
|
|
|
@ -113,7 +113,7 @@ export default class Drawer extends React.Component<DrawerProps, object> {
|
|||
}
|
||||
|
||||
buildActions(): Array<Action> {
|
||||
const {actions, confirm} = this.props;
|
||||
const {actions, confirm, translate: __} = this.props;
|
||||
|
||||
if (typeof actions !== 'undefined') {
|
||||
return actions;
|
||||
|
@ -123,14 +123,14 @@ export default class Drawer extends React.Component<DrawerProps, object> {
|
|||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'close',
|
||||
label: '取消'
|
||||
label: __('取消')
|
||||
});
|
||||
|
||||
if (confirm) {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '确认',
|
||||
label: __('确认'),
|
||||
primary: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -165,7 +165,8 @@ export default class CheckboxesControl extends React.Component<
|
|||
labelClassName,
|
||||
creatable,
|
||||
addApi,
|
||||
createBtnLabel
|
||||
createBtnLabel,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
@ -217,13 +218,13 @@ export default class CheckboxesControl extends React.Component<
|
|||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<span className={`Form-placeholder`}>{placeholder}</span>
|
||||
<span className={`Form-placeholder`}>{__(placeholder)}</span>
|
||||
)}
|
||||
|
||||
{(creatable || addApi) && !disabled ? (
|
||||
<a className={cx('Checkboxes-addBtn')} onClick={this.handleAddClick}>
|
||||
<Icon icon="plus" className="icon" />
|
||||
{createBtnLabel}
|
||||
{__(createBtnLabel)}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
@ -5,8 +5,9 @@ import {ClassNamesFn, themeable} from '../../theme';
|
|||
import {Select} from '../../components';
|
||||
import {autobind} from '../../utils/helper';
|
||||
import {Option} from './Options';
|
||||
import {localeable, LocaleProps} from '../../locale';
|
||||
|
||||
export interface CityPickerProps {
|
||||
export interface CityPickerProps extends LocaleProps {
|
||||
value: any;
|
||||
onChange: (value: any) => void;
|
||||
extractValue: boolean;
|
||||
|
@ -226,7 +227,8 @@ export class CityPicker extends React.Component<
|
|||
disabled,
|
||||
allowCity,
|
||||
allowDistrict,
|
||||
allowStreet
|
||||
allowStreet,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const {provinceCode, cityCode, districtCode, street} = this.state;
|
||||
|
@ -290,7 +292,7 @@ export class CityPicker extends React.Component<
|
|||
value={street}
|
||||
onChange={this.handleStreetChange}
|
||||
onBlur={this.handleStreetEnd}
|
||||
placeholder="请输入街道信息"
|
||||
placeholder={__('请输入街道信息')}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -298,7 +300,7 @@ export class CityPicker extends React.Component<
|
|||
}
|
||||
}
|
||||
|
||||
const ThemedCity = themeable(CityPicker);
|
||||
const ThemedCity = themeable(localeable(CityPicker));
|
||||
export default ThemedCity;
|
||||
|
||||
export interface LocationControlProps extends FormControlProps {
|
||||
|
|
|
@ -321,7 +321,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
deleteApi,
|
||||
deleteConfirmText,
|
||||
data,
|
||||
env
|
||||
env,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (disabled) {
|
||||
|
@ -333,7 +334,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
|
||||
if (isEffectiveApi(deleteApi, ctx)) {
|
||||
const confirmed = await env.confirm(
|
||||
deleteConfirmText ? filter(deleteConfirmText, ctx) : '确认要删除?'
|
||||
deleteConfirmText ? filter(deleteConfirmText, ctx) : __('确认要删除?')
|
||||
);
|
||||
if (!confirmed) {
|
||||
// 如果不确认,则跳过!
|
||||
|
@ -343,7 +344,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
const result = await env.fetcher(deleteApi as Api, ctx);
|
||||
|
||||
if (!result.ok) {
|
||||
env.notify('error', '删除失败');
|
||||
env.notify('error', __('删除失败'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -480,25 +481,34 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
}
|
||||
|
||||
validate(): any {
|
||||
const {value, minLength, maxLength, messages, nullable} = this.props;
|
||||
const {
|
||||
value,
|
||||
minLength,
|
||||
maxLength,
|
||||
messages,
|
||||
nullable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (minLength && (!Array.isArray(value) || value.length < minLength)) {
|
||||
return (
|
||||
return __(
|
||||
(messages && messages.minLengthValidateFailed) ||
|
||||
`组合表单成员数量不够,低于设定的最小${minLength}个,请添加更多的成员。`
|
||||
'组合表单成员数量不够,低于设定的最小{{minLenth}}个,请添加更多的成员。',
|
||||
{minLength}
|
||||
);
|
||||
} else if (maxLength && Array.isArray(value) && value.length > maxLength) {
|
||||
return (
|
||||
return __(
|
||||
(messages && messages.maxLengthValidateFailed) ||
|
||||
`组合表单成员数量超出,超出设定的最大${maxLength}个,请删除多余的成员。`
|
||||
'组合表单成员数量超出,超出设定的最大{{maxLength}}个,请删除多余的成员。',
|
||||
{maxLength}
|
||||
);
|
||||
} else if (this.subForms.length && (!nullable || value)) {
|
||||
return Promise.all(this.subForms.map(item => item.validate())).then(
|
||||
values => {
|
||||
if (~values.indexOf(false)) {
|
||||
return (
|
||||
return __(
|
||||
(messages && messages.validateFailed) ||
|
||||
'子表单验证失败,请仔细检查'
|
||||
'子表单验证失败,请仔细检查'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -698,9 +708,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
}
|
||||
|
||||
renderPlaceholder() {
|
||||
return (
|
||||
<span className="text-muted">{this.props.placeholder || '没有数据'}</span>
|
||||
);
|
||||
const {placeholder, translate: __} = this.props;
|
||||
return <span className="text-muted">{__(placeholder || '没有数据')}</span>;
|
||||
}
|
||||
|
||||
renderTabsMode() {
|
||||
|
@ -725,7 +734,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
deleteIcon,
|
||||
tabsLabelTpl,
|
||||
conditions,
|
||||
changeImmediately
|
||||
changeImmediately,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let controls = this.props.controls;
|
||||
|
@ -762,7 +772,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
{
|
||||
type: 'dropdown-button',
|
||||
icon: addIcon,
|
||||
label: addButtonText || '新增',
|
||||
label: __(addButtonText || '新增'),
|
||||
level: 'info',
|
||||
size: 'sm',
|
||||
closeOnClick: true
|
||||
|
@ -781,10 +791,10 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
<a
|
||||
onClick={this.addItem}
|
||||
data-position="left"
|
||||
data-tooltip="新增一条数据"
|
||||
data-tooltip={__('新增一条数据')}
|
||||
>
|
||||
{addIcon ? <i className={cx('m-r-xs', addIcon)} /> : null}
|
||||
<span>{addButtonText || '新增'}</span>
|
||||
<span>{__(addButtonText || '新增')}</span>
|
||||
</a>
|
||||
)
|
||||
) : null}
|
||||
|
@ -808,7 +818,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
className={cx(
|
||||
`Combo-toolbarBtn ${!store.removable ? 'is-disabled' : ''}`
|
||||
)}
|
||||
data-tooltip="删除"
|
||||
data-tooltip={__('删除')}
|
||||
data-position="bottom"
|
||||
>
|
||||
{deleteIcon ? (
|
||||
|
@ -837,7 +847,11 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
|
||||
return (
|
||||
<Tab
|
||||
title={filter(tabsLabelTpl || '成员${index|plus}', data)}
|
||||
title={filter(
|
||||
tabsLabelTpl ||
|
||||
__('成员{{index}}', {index: (data as any).index + 1}),
|
||||
data
|
||||
)}
|
||||
key={this.keys[index] || (this.keys[index] = guid())}
|
||||
toolbar={toolbar}
|
||||
eventKey={index}
|
||||
|
@ -847,7 +861,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
>
|
||||
{condition && typeSwitchable !== false ? (
|
||||
<div className={cx('Combo-itemTag')}>
|
||||
<label>类型</label>
|
||||
<label>{__('类型')}</label>
|
||||
<Select
|
||||
onChange={this.handleComboTypeChange.bind(this, index)}
|
||||
options={(conditions as Array<Condition>).map(item => ({
|
||||
|
@ -888,7 +902,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
)
|
||||
) : (
|
||||
<Alert2 level="warning" className="m-b-none">
|
||||
数据非法,或者数据已失效,请移除
|
||||
{__('数据非法,或者数据已失效,请移除')}
|
||||
</Alert2>
|
||||
)}
|
||||
</div>
|
||||
|
@ -931,7 +945,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
conditions,
|
||||
lazyLoad,
|
||||
changeImmediately,
|
||||
placeholder
|
||||
placeholder,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let controls = this.props.controls;
|
||||
|
@ -990,7 +1005,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
!store.removable ? 'is-disabled' : ''
|
||||
}`
|
||||
)}
|
||||
data-tooltip="删除"
|
||||
data-tooltip={__('删除')}
|
||||
data-position="bottom"
|
||||
>
|
||||
{deleteIcon ? (
|
||||
|
@ -1029,7 +1044,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
<div className={cx('Combo-itemDrager')}>
|
||||
<a
|
||||
key="drag"
|
||||
data-tooltip="拖拽排序"
|
||||
data-tooltip={__('拖拽排序')}
|
||||
data-position="bottom"
|
||||
>
|
||||
{dragIcon ? (
|
||||
|
@ -1042,7 +1057,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
) : null}
|
||||
{condition && typeSwitchable !== false ? (
|
||||
<div className={cx('Combo-itemTag')}>
|
||||
<label>类型</label>
|
||||
<label>{__('类型')}</label>
|
||||
<Select
|
||||
onChange={this.handleComboTypeChange.bind(this, index)}
|
||||
options={(conditions as Array<Condition>).map(item => ({
|
||||
|
@ -1084,7 +1099,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
)
|
||||
) : (
|
||||
<Alert2 level="warning" className="m-b-none">
|
||||
数据非法,或者数据已失效,请移除
|
||||
{__('数据非法,或者数据已失效,请移除')}
|
||||
</Alert2>
|
||||
)}
|
||||
</div>
|
||||
|
@ -1107,7 +1122,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
{
|
||||
type: 'dropdown-button',
|
||||
icon: addIcon,
|
||||
label: addButtonText || '新增',
|
||||
label: __(addButtonText || '新增'),
|
||||
level: 'info',
|
||||
size: 'sm',
|
||||
closeOnClick: true
|
||||
|
@ -1127,18 +1142,20 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
type="button"
|
||||
onClick={this.addItem}
|
||||
className={cx(`Button Combo-addBtn`, addButtonClassName)}
|
||||
data-tooltip="新增一条数据"
|
||||
data-tooltip={__('新增一条数据')}
|
||||
>
|
||||
{addIcon ? (
|
||||
<i className={cx('Button-icon', addIcon)} />
|
||||
) : null}
|
||||
<span>{addButtonText || '新增'}</span>
|
||||
<span>{__(addButtonText || '新增')}</span>
|
||||
</button>
|
||||
)
|
||||
) : null}
|
||||
{draggable ? (
|
||||
<span className={cx(`Combo-dragableTip`)} ref={this.dragTipRef}>
|
||||
{Array.isArray(value) && value.length > 1 ? draggableTip : ''}
|
||||
{Array.isArray(value) && value.length > 1
|
||||
? __(draggableTip)
|
||||
: ''}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -1159,7 +1176,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
noBorder,
|
||||
disabled,
|
||||
typeSwitchable,
|
||||
nullable
|
||||
nullable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let controls = this.props.controls;
|
||||
|
@ -1183,7 +1201,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
<div className={cx(`Combo-item`)}>
|
||||
{condition && typeSwitchable !== false ? (
|
||||
<div className={cx('Combo-itemTag')}>
|
||||
<label>类型</label>
|
||||
<label>{__('类型')}</label>
|
||||
<Select
|
||||
onChange={this.handleComboTypeChange.bind(this, 0)}
|
||||
options={(conditions as Array<Condition>).map(item => ({
|
||||
|
@ -1219,14 +1237,14 @@ export default class ComboControl extends React.Component<ComboProps> {
|
|||
)
|
||||
) : (
|
||||
<Alert2 level="warning" className="m-b-none">
|
||||
数据非法,或者数据已失效,请移除
|
||||
{__('数据非法,或者数据已失效,请移除')}
|
||||
</Alert2>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{value && nullable ? (
|
||||
<a className={cx('Combo-setNullBtn')} href="#" onClick={this.setNull}>
|
||||
清空数据
|
||||
{__('清空数据')}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
@ -101,6 +101,8 @@ export default class DateControl extends React.PureComponent<
|
|||
defaultValue,
|
||||
defaultData,
|
||||
classnames: cx,
|
||||
minDate,
|
||||
maxDate,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
|
|
|
@ -271,7 +271,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
return;
|
||||
}
|
||||
|
||||
const {maxSize, multiple, maxLength} = this.props;
|
||||
const {maxSize, multiple, maxLength, translate: __} = this.props;
|
||||
let allowed =
|
||||
multiple && maxLength
|
||||
? maxLength - this.state.files.length
|
||||
|
@ -282,11 +282,14 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
[].slice.call(files, 0, allowed).forEach((file: FileX) => {
|
||||
if (maxSize && file.size > maxSize) {
|
||||
this.props.env.alert(
|
||||
`您选择的文件 ${file.name} 大小为 ${ImageControl.formatFileSize(
|
||||
file.size
|
||||
)} 超出了最大为 ${ImageControl.formatFileSize(
|
||||
maxSize
|
||||
)} 的限制,请重新选择`
|
||||
__(
|
||||
'您选择的文件 {{filename}} 大小为 {{actualSize}} 超出了最大为 {{maxSize}} 的限制,请重新选择。',
|
||||
{
|
||||
filename: file.name,
|
||||
actualSize: ImageControl.formatFileSize(file.size),
|
||||
maxSize: ImageControl.formatFileSize(maxSize)
|
||||
}
|
||||
)
|
||||
);
|
||||
file.state = 'invalid';
|
||||
} else {
|
||||
|
@ -320,7 +323,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
if (evt.type !== 'change' && evt.type !== 'drop') {
|
||||
return;
|
||||
}
|
||||
const {multiple, env, accept} = this.props;
|
||||
const {multiple, env, accept, translate: __} = this.props;
|
||||
|
||||
const files = rejectedFiles.map((file: any) => ({
|
||||
...file,
|
||||
|
@ -338,9 +341,10 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
});
|
||||
|
||||
env.alert(
|
||||
`您添加的文件${files.map(
|
||||
(item: any) => `【${item.name}】`
|
||||
)}不符合类型的\`${accept}\`设定,请仔细检查。`
|
||||
__('您添加的文件{{files}}不符合类型的`{{accept}}`的设定,请仔细检查。', {
|
||||
files: files.map((item: any) => `「${item.name}」`).join(' '),
|
||||
accept
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -393,6 +397,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
return;
|
||||
}
|
||||
|
||||
const __ = this.props.translate;
|
||||
const file = find(
|
||||
this.state.files,
|
||||
item => item.state === 'pending'
|
||||
|
@ -463,7 +468,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
if (this.resolve) {
|
||||
this.resolve(
|
||||
this.state.files.some(file => file.state === 'error')
|
||||
? '文件上传失败请重试'
|
||||
? __('文件上传失败请重试')
|
||||
: null
|
||||
);
|
||||
this.resolve = undefined;
|
||||
|
@ -489,7 +494,8 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
finishChunkApi,
|
||||
asBase64,
|
||||
asBlob,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (asBase64) {
|
||||
|
@ -545,7 +551,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
)
|
||||
.then(ret => {
|
||||
if (ret.status || !ret.data) {
|
||||
throw new Error(ret.msg || '上传失败, 请重试');
|
||||
throw new Error(ret.msg || __('上传失败, 请重试'));
|
||||
}
|
||||
|
||||
onProgress(1);
|
||||
|
@ -565,7 +571,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
});
|
||||
})
|
||||
.catch(error => {
|
||||
cb(error.message || '上传失败, 请重试', file);
|
||||
cb(error.message || __('上传失败, 请重试'), file);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -660,6 +666,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
let startProgress = 0.2;
|
||||
let endProgress = 0.9;
|
||||
let progressArr: Array<number>;
|
||||
const __ = this.props.translate;
|
||||
|
||||
interface ObjectState {
|
||||
key: string;
|
||||
|
@ -692,10 +699,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
}
|
||||
);
|
||||
|
||||
self
|
||||
._send(startApi)
|
||||
.then(startChunk)
|
||||
.catch(reject);
|
||||
self._send(startApi).then(startChunk).catch(reject);
|
||||
|
||||
function startChunk(ret: Payload) {
|
||||
onProgress(startProgress);
|
||||
|
@ -703,7 +707,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
progressArr = tasks.map(() => 0);
|
||||
|
||||
if (!ret.data) {
|
||||
throw new Error('接口返回错误,请仔细检查');
|
||||
throw new Error(__('接口返回错误,请仔细检查'));
|
||||
}
|
||||
|
||||
state = {
|
||||
|
@ -713,7 +717,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
total: tasks.length
|
||||
};
|
||||
|
||||
mapLimit(tasks, 3, uploadPartFile(state, config), function(
|
||||
mapLimit(tasks, 3, uploadPartFile(state, config), function (
|
||||
err,
|
||||
results
|
||||
) {
|
||||
|
@ -755,10 +759,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
}
|
||||
);
|
||||
|
||||
self
|
||||
._send(endApi)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
self._send(endApi).then(resolve).catch(reject);
|
||||
}
|
||||
|
||||
function uploadPartFile(state: ObjectState, conf: Partial<FileProps>) {
|
||||
|
@ -853,6 +854,8 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
}
|
||||
|
||||
validate(): any {
|
||||
const __ = this.props.translate;
|
||||
|
||||
if (
|
||||
this.state.uploading ||
|
||||
this.state.files.some(item => item.state === 'pending')
|
||||
|
@ -862,7 +865,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
this.startUpload();
|
||||
});
|
||||
} else if (this.state.files.some(item => item.state === 'error')) {
|
||||
return '文件上传失败请重试';
|
||||
return __('文件上传失败请重试');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -878,6 +881,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
hideUploadButton,
|
||||
className,
|
||||
classnames: cx,
|
||||
translate: __,
|
||||
render
|
||||
} = this.props;
|
||||
let {files, uploading, error} = this.state;
|
||||
|
@ -921,7 +925,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
|
||||
{isDragActive ? (
|
||||
<div className={cx('FileControl-acceptTip')}>
|
||||
把文件拖到这,然后松完成添加!
|
||||
{__('把文件拖到这,然后松完成添加!')}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
@ -935,10 +939,10 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
>
|
||||
<Icon icon="upload" className="icon" />
|
||||
{!multiple && files.length
|
||||
? '重新上传'
|
||||
? __('重新上传')
|
||||
: multiple && files.length
|
||||
? '继续添加'
|
||||
: '上传文件'}
|
||||
? __('继续添加')
|
||||
: __('上传文件')}
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
|
@ -980,7 +984,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
) : null}
|
||||
{file.state !== 'uploading' ? (
|
||||
<a
|
||||
data-tooltip="移除"
|
||||
data-tooltip={__('移除')}
|
||||
className={cx('FileControl-clear')}
|
||||
onClick={() => this.removeFile(file, index)}
|
||||
>
|
||||
|
@ -1024,8 +1028,12 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
|
||||
{failed ? (
|
||||
<div className={cx('FileControl-sum')}>
|
||||
已成功上传{uploaded}个文件,{failed}个文件上传失败,
|
||||
<a onClick={this.retry}>重新上传</a>失败文件
|
||||
{__('已成功上传{{uploaded}}个文件,{{failed}}个文件上传失败,', {
|
||||
uploaded,
|
||||
failed
|
||||
})}
|
||||
<a onClick={this.retry}>{__('重试上传')}</a>
|
||||
{__('失败文件。')}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
|
@ -1036,7 +1044,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
|||
className={cx('FileControl-uploadBtn')}
|
||||
onClick={this.toggleUpload}
|
||||
>
|
||||
{uploading ? '暂停上传' : '开始上传'}
|
||||
{__(uploading ? '暂停上传' : '开始上传')}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
@ -201,7 +201,8 @@ export default class IconPickerControl extends React.PureComponent<
|
|||
classnames: cx,
|
||||
name,
|
||||
value,
|
||||
noDataTip
|
||||
noDataTip,
|
||||
translate: __
|
||||
} = this.props;
|
||||
const options = this.formatOptions();
|
||||
const vendors = this.getVendors();
|
||||
|
@ -311,7 +312,7 @@ export default class IconPickerControl extends React.PureComponent<
|
|||
: 'IconPickerControl-singleVendor'
|
||||
)}
|
||||
>
|
||||
{noDataTip}
|
||||
{__(noDataTip)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -15,6 +15,7 @@ import Button from '../../components/Button';
|
|||
import accepts from 'attr-accept';
|
||||
import {getNameFromUrl} from './File';
|
||||
import ImageComponent, {ImageThumbProps} from '../Image';
|
||||
import {TranslateFn} from '../../locale';
|
||||
|
||||
let preventEvent = (e: any) => e.stopPropagation();
|
||||
|
||||
|
@ -139,14 +140,18 @@ export default class ImageControl extends React.Component<
|
|||
: undefined;
|
||||
}
|
||||
|
||||
static sizeInfo(width?: number, height?: number): string {
|
||||
static sizeInfo(
|
||||
width: number | undefined,
|
||||
height: number | undefined,
|
||||
__: TranslateFn
|
||||
): string {
|
||||
if (!width) {
|
||||
return `高度${height}px`;
|
||||
return __('高度{{height}}px', {height: height});
|
||||
} else if (!height) {
|
||||
return `宽度${width}px`;
|
||||
return __('宽度{{width}}px', {width: width});
|
||||
}
|
||||
|
||||
return `尺寸(${width} x ${height})`;
|
||||
return __('尺寸({{width}} x {{height}})', {width, height});
|
||||
}
|
||||
|
||||
state: ImageState = {
|
||||
|
@ -268,11 +273,12 @@ export default class ImageControl extends React.Component<
|
|||
|
||||
buildCrop(props: ImageProps) {
|
||||
let crop = props.crop;
|
||||
const __ = this.props.translate;
|
||||
|
||||
if (crop && props.multiple) {
|
||||
props.env &&
|
||||
props.env.alert &&
|
||||
props.env.alert('图片多选配置和裁剪配置冲突,目前不能二者都支持!');
|
||||
props.env.alert(__('图片多选配置和裁剪配置冲突,目前不能二者都支持!'));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -299,7 +305,7 @@ export default class ImageControl extends React.Component<
|
|||
if (evt.type !== 'change' && evt.type !== 'drop') {
|
||||
return;
|
||||
}
|
||||
const {multiple, env, accept} = this.props;
|
||||
const {multiple, env, accept, translate: __} = this.props;
|
||||
|
||||
const files = rejectedFiles.map((file: any) => ({
|
||||
...file,
|
||||
|
@ -317,9 +323,10 @@ export default class ImageControl extends React.Component<
|
|||
// });
|
||||
|
||||
env.alert(
|
||||
`您添加的文件${files.map(
|
||||
(item: any) => `【${item.name}】`
|
||||
)}不符合类型的\`${accept}\`设定,请仔细检查。`
|
||||
__('您添加的文件{{files}}不符合类型的`{{accept}}`的设定,请仔细检查。', {
|
||||
files: files.map((file: any) => `「${file.name}」`).join(' '),
|
||||
accept
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -365,6 +372,7 @@ export default class ImageControl extends React.Component<
|
|||
}
|
||||
|
||||
const env = this.props.env;
|
||||
const __ = this.props.translate;
|
||||
const file = find(this.files, item => item.state === 'pending') as FileX;
|
||||
if (file) {
|
||||
this.current = file;
|
||||
|
@ -405,7 +413,7 @@ export default class ImageControl extends React.Component<
|
|||
);
|
||||
}
|
||||
|
||||
env.notify('error', error || '图片上传失败,请重试');
|
||||
env.notify('error', error || __('图片上传失败,请重试'));
|
||||
} else {
|
||||
newFile = {
|
||||
...obj,
|
||||
|
@ -449,7 +457,7 @@ export default class ImageControl extends React.Component<
|
|||
if (this.resolve) {
|
||||
this.resolve(
|
||||
this.files.some(file => file.state === 'error')
|
||||
? '文件上传失败请重试'
|
||||
? __('文件上传失败请重试')
|
||||
: null
|
||||
);
|
||||
this.resolve = undefined;
|
||||
|
@ -631,7 +639,7 @@ export default class ImageControl extends React.Component<
|
|||
return;
|
||||
}
|
||||
|
||||
const {multiple, maxLength, maxSize, accept} = this.props;
|
||||
const {multiple, maxLength, maxSize, accept, translate: __} = this.props;
|
||||
let currentFiles = this.files;
|
||||
|
||||
if (!multiple && currentFiles.length) {
|
||||
|
@ -649,11 +657,14 @@ export default class ImageControl extends React.Component<
|
|||
[].slice.call(files, 0, allowed).forEach((file: FileX) => {
|
||||
if (maxSize && file.size > maxSize) {
|
||||
alert(
|
||||
`您选择的文件 ${file.name} 大小为 ${ImageControl.formatFileSize(
|
||||
file.size
|
||||
)} 超出了最大为 ${ImageControl.formatFileSize(
|
||||
maxSize
|
||||
)} 的限制,请重新选择`
|
||||
__(
|
||||
'您选择的文件 {{filename}} 大小为 {{actualSize}} 超出了最大为 {{maxSize}} 的限制,请重新选择。',
|
||||
{
|
||||
filename: file.name,
|
||||
actualSize: ImageControl.formatFileSize(file.size),
|
||||
maxSize: ImageControl.formatFileSize(maxSize)
|
||||
}
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -691,7 +702,7 @@ export default class ImageControl extends React.Component<
|
|||
cb: (error: null | string, file: FileX, obj?: FileValue) => void,
|
||||
onProgress: (progress: number) => void
|
||||
) {
|
||||
const {limit} = this.props;
|
||||
const {limit, translate: __} = this.props;
|
||||
|
||||
if (!limit) {
|
||||
return this._upload(file, cb, onProgress);
|
||||
|
@ -707,32 +718,33 @@ export default class ImageControl extends React.Component<
|
|||
(limit.width && limit.width != width) ||
|
||||
(limit.height && limit.height != height)
|
||||
) {
|
||||
error = `您选择的图片不符合尺寸要求, 请上传${ImageControl.sizeInfo(
|
||||
limit.width,
|
||||
limit.height
|
||||
)}的图片`;
|
||||
error = __('您选择的图片不符合尺寸要求, 请上传{{info}}的图片', {
|
||||
info: ImageControl.sizeInfo(limit.width, limit.height, __)
|
||||
});
|
||||
} else if (
|
||||
(limit.maxWidth && limit.maxWidth < width) ||
|
||||
(limit.maxHeight && limit.maxHeight < height)
|
||||
) {
|
||||
error = `您选择的图片不符合尺寸要求, 请上传不要超过${ImageControl.sizeInfo(
|
||||
limit.maxWidth,
|
||||
limit.maxHeight
|
||||
)}的图片`;
|
||||
error = __('您选择的图片不符合尺寸要求, 请上传不要超过{{info}}的图片', {
|
||||
info: ImageControl.sizeInfo(limit.maxWidth, limit.maxHeight, __)
|
||||
});
|
||||
} else if (
|
||||
(limit.minWidth && limit.minWidth > width) ||
|
||||
(limit.minHeight && limit.minHeight > height)
|
||||
) {
|
||||
error = `您选择的图片不符合尺寸要求, 请上传不要小于${ImageControl.sizeInfo(
|
||||
limit.minWidth,
|
||||
limit.minHeight
|
||||
)}的图片`;
|
||||
error = __('您选择的图片不符合尺寸要求, 请上传不要小于{{info}}的图片', {
|
||||
info: ImageControl.sizeInfo(limit.minWidth, limit.minHeight, __)
|
||||
});
|
||||
} else if (
|
||||
limit.aspectRatio &&
|
||||
Math.abs(width / height - limit.aspectRatio) > 0.01
|
||||
) {
|
||||
error = `您选择的图片不符合尺寸要求, 请上传尺寸比率为 ${limit.aspectRatioLabel ||
|
||||
limit.aspectRatio} 的图片`;
|
||||
error = __(
|
||||
'您选择的图片不符合尺寸要求, 请上传尺寸比率为 {{ratio}} 的图片',
|
||||
{
|
||||
ratio: limit.aspectRatioLabel || limit.aspectRatio
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
|
@ -750,10 +762,11 @@ export default class ImageControl extends React.Component<
|
|||
cb: (error: null | string, file: Blob, obj?: FileValue) => void,
|
||||
onProgress: (progress: number) => void
|
||||
) {
|
||||
const __ = this.props.translate;
|
||||
this._send(file, this.props.reciever as string, {}, onProgress)
|
||||
.then((ret: Payload) => {
|
||||
if (ret.status) {
|
||||
throw new Error(ret.msg || '上传失败, 请重试');
|
||||
throw new Error(ret.msg || __('上传失败, 请重试'));
|
||||
}
|
||||
|
||||
const obj: FileValue = {
|
||||
|
@ -764,7 +777,7 @@ export default class ImageControl extends React.Component<
|
|||
|
||||
cb(null, file, obj);
|
||||
})
|
||||
.catch(error => cb(error.message || '上传失败,请重试', file));
|
||||
.catch(error => cb(error.message || __('上传失败,请重试'), file));
|
||||
}
|
||||
|
||||
_send(
|
||||
|
@ -854,6 +867,8 @@ export default class ImageControl extends React.Component<
|
|||
}
|
||||
|
||||
validate(): any {
|
||||
const __ = this.props.translate;
|
||||
|
||||
if (this.state.locked && this.state.lockedReason) {
|
||||
return this.state.lockedReason;
|
||||
} else if (this.state.cropFile) {
|
||||
|
@ -870,7 +885,7 @@ export default class ImageControl extends React.Component<
|
|||
this.startUpload();
|
||||
});
|
||||
} else if (this.files.some(item => item.state === 'error')) {
|
||||
return '文件上传失败请重试';
|
||||
return __('文件上传失败请重试');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -887,7 +902,8 @@ export default class ImageControl extends React.Component<
|
|||
hideUploadButton,
|
||||
thumbMode,
|
||||
thumbRatio,
|
||||
reCropable
|
||||
reCropable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const {files, error, crop, uploading, cropFile} = this.state;
|
||||
|
@ -902,7 +918,7 @@ export default class ImageControl extends React.Component<
|
|||
<a
|
||||
className={cx('ImageControl-cropCancel')}
|
||||
onClick={this.cancelCrop}
|
||||
data-tooltip="取消"
|
||||
data-tooltip={__('取消')}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
|
@ -910,7 +926,7 @@ export default class ImageControl extends React.Component<
|
|||
<a
|
||||
className={cx('ImageControl-cropConfirm')}
|
||||
onClick={this.handleCrop}
|
||||
data-tooltip="确认"
|
||||
data-tooltip={__('确认')}
|
||||
data-position="left"
|
||||
>
|
||||
<Icon icon="check" className="icon" />
|
||||
|
@ -954,7 +970,7 @@ export default class ImageControl extends React.Component<
|
|||
'is-reject': isDragReject
|
||||
})}
|
||||
>
|
||||
把图片拖到这,然后松开完成添加!
|
||||
{__('把图片拖到这,然后松开完成添加!')}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
@ -974,7 +990,7 @@ export default class ImageControl extends React.Component<
|
|||
<>
|
||||
<a
|
||||
className={cx('ImageControl-itemClear')}
|
||||
data-tooltip="移除"
|
||||
data-tooltip={__('移除')}
|
||||
data-position="bottom"
|
||||
onClick={this.removeFile.bind(
|
||||
this,
|
||||
|
@ -993,7 +1009,7 @@ export default class ImageControl extends React.Component<
|
|||
>
|
||||
<Icon icon="retry" className="icon" />
|
||||
<p className="ImageControl-itemInfoError">
|
||||
重新上传
|
||||
{__('重新上传')}
|
||||
</p>
|
||||
</a>
|
||||
</>
|
||||
|
@ -1007,7 +1023,7 @@ export default class ImageControl extends React.Component<
|
|||
)}
|
||||
key="clear"
|
||||
className={cx('ImageControl-itemClear')}
|
||||
data-tooltip="移除"
|
||||
data-tooltip={__('移除')}
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
|
@ -1015,7 +1031,7 @@ export default class ImageControl extends React.Component<
|
|||
key="info"
|
||||
className={cx('ImageControl-itemInfo')}
|
||||
>
|
||||
<p>文件上传中</p>
|
||||
<p>{__('文件上传中')}</p>
|
||||
<div className={cx('ImageControl-progress')}>
|
||||
<span
|
||||
style={{
|
||||
|
@ -1067,7 +1083,7 @@ export default class ImageControl extends React.Component<
|
|||
)}
|
||||
|
||||
<a
|
||||
data-tooltip="查看大图"
|
||||
data-tooltip={__('查看大图')}
|
||||
data-position="bottom"
|
||||
target="_blank"
|
||||
href={file.url || file.preview}
|
||||
|
@ -1084,7 +1100,7 @@ export default class ImageControl extends React.Component<
|
|||
reCropable !== false &&
|
||||
!disabled ? (
|
||||
<a
|
||||
data-tooltip="裁剪图片"
|
||||
data-tooltip={__('裁剪图片')}
|
||||
data-position="bottom"
|
||||
onClick={this.editImage.bind(this, key)}
|
||||
>
|
||||
|
@ -1093,7 +1109,7 @@ export default class ImageControl extends React.Component<
|
|||
) : null}
|
||||
{!disabled ? (
|
||||
<a
|
||||
data-tooltip="移除"
|
||||
data-tooltip={__('移除')}
|
||||
data-position="bottom"
|
||||
onClick={this.removeFile.bind(
|
||||
this,
|
||||
|
@ -1128,14 +1144,14 @@ export default class ImageControl extends React.Component<
|
|||
'is-disabled': disabled
|
||||
})}
|
||||
onClick={this.handleSelect}
|
||||
data-tooltip={placeholder}
|
||||
data-tooltip={__(placeholder)}
|
||||
data-position="right"
|
||||
>
|
||||
<Icon icon="plus" className="icon" />
|
||||
|
||||
{isFocused ? (
|
||||
<span className={cx('ImageControl-pasteTip')}>
|
||||
当前状态支持从剪切板中粘贴图片文件。
|
||||
{__('当前状态支持从剪切板中粘贴图片文件。')}
|
||||
</span>
|
||||
) : null}
|
||||
</label>
|
||||
|
@ -1148,7 +1164,7 @@ export default class ImageControl extends React.Component<
|
|||
disabled={!hasPending}
|
||||
onClick={this.toggleUpload}
|
||||
>
|
||||
{uploading ? '暂停上传' : '开始上传'}
|
||||
{__(uploading ? '暂停上传' : '开始上传')}
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ export default class MatrixCheckbox extends React.Component<
|
|||
}
|
||||
|
||||
async reload() {
|
||||
const {source, data, env, onChange} = this.props;
|
||||
const {source, data, env, onChange, translate: __} = this.props;
|
||||
|
||||
if (!isEffectiveApi(source, data) || this.state.loading) {
|
||||
return;
|
||||
|
@ -159,7 +159,7 @@ export default class MatrixCheckbox extends React.Component<
|
|||
.fetcher(source, data)
|
||||
.then(ret => {
|
||||
if (!ret.ok) {
|
||||
throw new Error(ret.msg || '数据请求错误');
|
||||
throw new Error(ret.msg || __('数据请求错误'));
|
||||
}
|
||||
if (!this.mounted) {
|
||||
return resolve();
|
||||
|
|
|
@ -393,7 +393,8 @@ export default class NestedSelectControl extends React.Component<
|
|||
options,
|
||||
disabled,
|
||||
searchable,
|
||||
searchPromptText
|
||||
searchPromptText,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const stack = this.state.stack;
|
||||
|
@ -410,7 +411,7 @@ export default class NestedSelectControl extends React.Component<
|
|||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
disabled={disabled!!}
|
||||
placeholder={searchPromptText}
|
||||
placeholder={__(searchPromptText)}
|
||||
onChange={this.handleInputChange}
|
||||
ref={this.inputRef}
|
||||
/>
|
||||
|
|
|
@ -539,7 +539,8 @@ export function registerOptionsControl(config: OptionsConfig) {
|
|||
valueField,
|
||||
formItem: model,
|
||||
createBtnLabel,
|
||||
env
|
||||
env,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
// 禁用或者没有配置 name
|
||||
|
@ -554,7 +555,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
|||
type: 'text',
|
||||
name: labelField || 'label',
|
||||
label: false,
|
||||
placeholder: '请输入名称'
|
||||
placeholder: __('请输入名称')
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -650,7 +651,8 @@ export function registerOptionsControl(config: OptionsConfig) {
|
|||
source,
|
||||
data,
|
||||
formItem: model,
|
||||
optionLabel
|
||||
optionLabel,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (disabled || !model) {
|
||||
|
@ -663,7 +665,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
|||
type: 'text',
|
||||
name: labelField || 'label',
|
||||
label: false,
|
||||
placeholder: '请输入名称'
|
||||
placeholder: __('请输入名称')
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -673,7 +675,9 @@ export function registerOptionsControl(config: OptionsConfig) {
|
|||
: await onOpenDialog(
|
||||
{
|
||||
type: 'dialog',
|
||||
title: `编辑${optionLabel || '选项'}`,
|
||||
title: __('编辑{{label}}', {
|
||||
label: optionLabel || '选项'
|
||||
}),
|
||||
body: {
|
||||
type: 'form',
|
||||
api: editApi,
|
||||
|
@ -695,7 +699,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
|||
);
|
||||
|
||||
if (!payload.ok) {
|
||||
env.notify('error', payload.msg || '保存失败,请仔细检查');
|
||||
env.notify('error', payload.msg || __('保存失败,请仔细检查'));
|
||||
result = null;
|
||||
} else {
|
||||
result = payload.data || result;
|
||||
|
@ -738,7 +742,8 @@ export function registerOptionsControl(config: OptionsConfig) {
|
|||
env,
|
||||
formItem: model,
|
||||
source,
|
||||
valueField
|
||||
valueField,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (disabled || !model) {
|
||||
|
@ -758,7 +763,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
|||
// 通过 deleteApi 删除。
|
||||
try {
|
||||
if (!deleteApi) {
|
||||
throw new Error('请配置 deleteApi');
|
||||
throw new Error(__('请配置 deleteApi'));
|
||||
}
|
||||
|
||||
const result = await env.fetcher(deleteApi!, ctx, {
|
||||
|
@ -766,7 +771,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
|||
});
|
||||
|
||||
if (!result.ok) {
|
||||
env.notify('error', result.msg || '删除失败,请重试');
|
||||
env.notify('error', result.msg || __('删除失败,请重试'));
|
||||
} else if (source) {
|
||||
this.reload();
|
||||
} else {
|
||||
|
|
|
@ -382,7 +382,8 @@ export default class PickerControl extends React.PureComponent<
|
|||
placeholder,
|
||||
embed,
|
||||
value,
|
||||
selectedOptions
|
||||
selectedOptions,
|
||||
translate: __
|
||||
} = this.props;
|
||||
return (
|
||||
<div className={cx(`PickerControl`, className)}>
|
||||
|
@ -399,7 +400,9 @@ export default class PickerControl extends React.PureComponent<
|
|||
>
|
||||
<div onClick={this.handleClick} className={cx('Picker-input')}>
|
||||
{!selectedOptions.length && placeholder ? (
|
||||
<div className={cx('Picker-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('Picker-placeholder')}>
|
||||
{__(placeholder)}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className={cx('Picker-valueWrap')}>
|
||||
|
@ -427,7 +430,7 @@ export default class PickerControl extends React.PureComponent<
|
|||
{render(
|
||||
'modal',
|
||||
{
|
||||
title: '请选择',
|
||||
title: __('请选择'),
|
||||
size: size,
|
||||
type: modalMode,
|
||||
body: {
|
||||
|
|
|
@ -63,7 +63,8 @@ export default class RadiosControl extends React.Component<RadiosProps, any> {
|
|||
classPrefix,
|
||||
itemClassName,
|
||||
labelClassName,
|
||||
labelField
|
||||
labelField,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
@ -78,7 +79,7 @@ export default class RadiosControl extends React.Component<RadiosProps, any> {
|
|||
delimiter={delimiter!}
|
||||
labelClassName={labelClassName}
|
||||
labelField={labelField}
|
||||
placeholder={placeholder}
|
||||
placeholder={__(placeholder)}
|
||||
options={options}
|
||||
columnsCount={columnsCount}
|
||||
classPrefix={classPrefix}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*
|
||||
* 不建议用,以后可能会删除。可以直接用组合出来,不需要新建一个组件。
|
||||
*/
|
||||
/* eslint fecs-indent: [0, "space", 2, 2] */
|
||||
|
||||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
|
@ -59,7 +58,13 @@ export default class RepeatControl extends React.Component<RepeatProps, any> {
|
|||
renderInput() {
|
||||
const value = this.props.value;
|
||||
const parts = value ? value.split(':') : [];
|
||||
let {options, placeholder, disabled, classPrefix: ns} = this.props;
|
||||
let {
|
||||
options,
|
||||
placeholder,
|
||||
disabled,
|
||||
classPrefix: ns,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let optionsArray: Array<Option> = [];
|
||||
|
||||
|
@ -69,7 +74,7 @@ export default class RepeatControl extends React.Component<RepeatProps, any> {
|
|||
}));
|
||||
|
||||
optionsArray.unshift({
|
||||
label: placeholder as string,
|
||||
label: __(placeholder as string),
|
||||
value: ''
|
||||
});
|
||||
|
||||
|
@ -182,7 +187,7 @@ export default class RepeatControl extends React.Component<RepeatProps, any> {
|
|||
<div className="repeat-control hbox">
|
||||
{input ? (
|
||||
<div className="col v-middle" style={{width: 30}}>
|
||||
<span>每</span>
|
||||
<span>{__('每')}</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
|
@ -193,7 +198,7 @@ export default class RepeatControl extends React.Component<RepeatProps, any> {
|
|||
classPrefix={ns}
|
||||
className={input ? 'pull-right' : ''}
|
||||
options={optionsArray}
|
||||
placeholder={placeholder}
|
||||
placeholder={__(placeholder)}
|
||||
onChange={this.handleOptionChange}
|
||||
value={parts[0]}
|
||||
clearable={false}
|
||||
|
|
|
@ -34,7 +34,6 @@ export default class RichTextControl extends React.Component<
|
|||
videoReciever: '/api/upload/video',
|
||||
placeholder: '请输入',
|
||||
options: {
|
||||
language: 'zh_cn',
|
||||
toolbarButtonsSM: [
|
||||
'paragraphFormat',
|
||||
'quote',
|
||||
|
@ -156,7 +155,9 @@ export default class RichTextControl extends React.Component<
|
|||
...(props.options && props.options.events),
|
||||
'froalaEditor.focus': this.handleFocus,
|
||||
'froalaEditor.blur': this.handleBlur
|
||||
}
|
||||
},
|
||||
language:
|
||||
!this.props.locale || this.props.locale === 'zh-cn' ? 'zh_cn' : ''
|
||||
};
|
||||
|
||||
if (props.buttons) {
|
||||
|
@ -178,10 +179,15 @@ export default class RichTextControl extends React.Component<
|
|||
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
||||
try {
|
||||
const response = await fetcher(props.reciever, formData, {
|
||||
method: 'post',
|
||||
method: 'post'
|
||||
});
|
||||
if (response.ok) {
|
||||
ok(response.data?.link || response.data?.url || response.data?.value || (response as any).link);
|
||||
ok(
|
||||
response.data?.link ||
|
||||
response.data?.url ||
|
||||
response.data?.value ||
|
||||
(response as any).link
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
fail(e);
|
||||
|
@ -212,7 +218,9 @@ export default class RichTextControl extends React.Component<
|
|||
disabled,
|
||||
size,
|
||||
vendor,
|
||||
env
|
||||
env,
|
||||
locale,
|
||||
translate
|
||||
} = this.props;
|
||||
|
||||
const finnalVendor = vendor || (env.richTextToken ? 'froala' : 'tinymce');
|
||||
|
@ -232,6 +240,8 @@ export default class RichTextControl extends React.Component<
|
|||
onBlur={this.handleBlur}
|
||||
config={this.config}
|
||||
disabled={disabled}
|
||||
locale={locale}
|
||||
translate={translate}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -151,7 +151,8 @@ export default class SubFormControl extends React.PureComponent<
|
|||
value,
|
||||
btnLabel,
|
||||
render,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return [
|
||||
|
@ -169,7 +170,7 @@ export default class SubFormControl extends React.PureComponent<
|
|||
key={key}
|
||||
>
|
||||
<span
|
||||
data-tooltip="删除"
|
||||
data-tooltip={__('删除')}
|
||||
data-position="bottom"
|
||||
className={`${ns}Select-valueIcon`}
|
||||
onClick={this.removeItem.bind(this, key)}
|
||||
|
@ -179,7 +180,7 @@ export default class SubFormControl extends React.PureComponent<
|
|||
<span
|
||||
onClick={this.open.bind(this, key)}
|
||||
className={`${ns}SubForm-valueLabel`}
|
||||
data-tooltip="编辑详情"
|
||||
data-tooltip={__('编辑详情')}
|
||||
data-position="bottom"
|
||||
>
|
||||
{(value &&
|
||||
|
@ -190,7 +191,7 @@ export default class SubFormControl extends React.PureComponent<
|
|||
'label',
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: btnLabel
|
||||
tpl: __(btnLabel)
|
||||
},
|
||||
{
|
||||
data: createObject(data, value)
|
||||
|
@ -207,10 +208,10 @@ export default class SubFormControl extends React.PureComponent<
|
|||
onClick={this.addItem}
|
||||
className={cx(`${ns}Button ${ns}SubForm-addBtn`, addButtonClassName)}
|
||||
disabled={disabled}
|
||||
data-tooltip="新增一条数据"
|
||||
data-tooltip={__('新增一条数据')}
|
||||
>
|
||||
<i className="fa fa-plus m-r-xs" />
|
||||
<span>新增</span>
|
||||
<span>{__('新增')}</span>
|
||||
</button>
|
||||
];
|
||||
}
|
||||
|
@ -224,7 +225,8 @@ export default class SubFormControl extends React.PureComponent<
|
|||
labelField,
|
||||
btnLabel,
|
||||
render,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
@ -238,7 +240,7 @@ export default class SubFormControl extends React.PureComponent<
|
|||
btnClassName
|
||||
)}
|
||||
onClick={this.open.bind(this, 0)}
|
||||
data-tooltip="编辑详情"
|
||||
data-tooltip={__('编辑详情')}
|
||||
data-position="bottom"
|
||||
>
|
||||
<span className={`${ns}SubForm-valueLabel`}>
|
||||
|
@ -250,7 +252,7 @@ export default class SubFormControl extends React.PureComponent<
|
|||
'label',
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: btnLabel
|
||||
tpl: __(btnLabel)
|
||||
},
|
||||
{
|
||||
data: createObject(data, value)
|
||||
|
|
|
@ -10,7 +10,7 @@ import omit from 'lodash/omit';
|
|||
import {dataMapping} from '../../utils/tpl-builtin';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import memoize from 'lodash/memoize';
|
||||
import { SimpleMap } from '../../utils/SimpleMap';
|
||||
import {SimpleMap} from '../../utils/SimpleMap';
|
||||
|
||||
export interface TableProps extends FormControlProps {
|
||||
placeholder?: string;
|
||||
|
@ -103,12 +103,18 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
}
|
||||
|
||||
validate(): any {
|
||||
const {value, minLength, maxLength} = this.props;
|
||||
const {value, minLength, maxLength, translate: __} = this.props;
|
||||
|
||||
if (minLength && (!Array.isArray(value) || value.length < minLength)) {
|
||||
return `组合表单成员数量不够,低于最小的设定${minLength}个,请添加更多的成员。`;
|
||||
return __(
|
||||
'组合表单成员数量不够,低于设定的最小{{minLenth}}个,请添加更多的成员。',
|
||||
{minLength}
|
||||
);
|
||||
} else if (maxLength && Array.isArray(value) && value.length > maxLength) {
|
||||
return `组合表单成员数量超出,超出最大的设定${maxLength}个,请删除多余的成员。`;
|
||||
return __(
|
||||
'组合表单成员数量超出,超出设定的最大{{maxLength}}个,请删除多余的成员。',
|
||||
{maxLength}
|
||||
);
|
||||
} else {
|
||||
const subForms: Array<any> = [];
|
||||
Object.keys(this.subForms).forEach(
|
||||
|
@ -118,7 +124,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
return Promise.all(subForms.map(item => item.validate())).then(
|
||||
values => {
|
||||
if (~values.indexOf(false)) {
|
||||
return '内部表单验证失败';
|
||||
return __('内部表单验证失败');
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -129,7 +135,15 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
}
|
||||
|
||||
doAction(action: Action, ctx: RendererData, ...rest: Array<any>) {
|
||||
const {onAction, value, valueField, env, onChange, editable} = this.props;
|
||||
const {
|
||||
onAction,
|
||||
value,
|
||||
valueField,
|
||||
env,
|
||||
onChange,
|
||||
editable,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (action.actionType === 'add') {
|
||||
const rows = Array.isArray(value) ? value.concat() : [];
|
||||
|
@ -166,9 +180,9 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
action.actionType === 'delete'
|
||||
) {
|
||||
if (!valueField) {
|
||||
return env.alert('请配置 valueField');
|
||||
return env.alert(__('请配置 valueField'));
|
||||
} else if (!action.payload) {
|
||||
return env.alert('action 上请配置 payload, 否则不清楚要删除哪个');
|
||||
return env.alert(__('action 上请配置 payload, 否则不清楚要删除哪个'));
|
||||
}
|
||||
|
||||
const rows = Array.isArray(value) ? value.concat() : [];
|
||||
|
@ -226,7 +240,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
addApi,
|
||||
updateApi,
|
||||
data,
|
||||
env
|
||||
env,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
// form 是 lazyChange 的,先让他们 flush, 即把未提交的数据提交。
|
||||
|
@ -252,11 +267,13 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
}
|
||||
|
||||
if (remote && !remote.ok) {
|
||||
env.notify('error', remote.msg || '保存失败');
|
||||
env.notify('error', remote.msg || __('保存失败'));
|
||||
return;
|
||||
} else if (remote && remote.ok) {
|
||||
item = {
|
||||
...((isNew ? addApi : updateApi) as ApiObject).replaceData ? {} : item,
|
||||
...(((isNew ? addApi : updateApi) as ApiObject).replaceData
|
||||
? {}
|
||||
: item),
|
||||
...remote.data
|
||||
};
|
||||
}
|
||||
|
@ -291,7 +308,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
deleteApi,
|
||||
deleteConfirmText,
|
||||
env,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
let newValue = Array.isArray(value) ? value.concat() : [];
|
||||
const item = newValue[index];
|
||||
|
@ -303,7 +321,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
const ctx = createObject(data, item);
|
||||
if (isEffectiveApi(deleteApi, ctx)) {
|
||||
const confirmed = await env.confirm(
|
||||
deleteConfirmText ? filter(deleteConfirmText, ctx) : '确认要删除?'
|
||||
deleteConfirmText ? filter(deleteConfirmText, ctx) : __('确认要删除?')
|
||||
);
|
||||
if (!confirmed) {
|
||||
// 如果不确认,则跳过!
|
||||
|
@ -313,7 +331,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
const result = await env.fetcher(deleteApi, ctx);
|
||||
|
||||
if (!result.ok) {
|
||||
env.notify('error', '删除失败');
|
||||
env.notify('error', __('删除失败'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -339,6 +357,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
? props.columns.concat()
|
||||
: [];
|
||||
const ns = this.props.classPrefix;
|
||||
const __ = this.props.translate;
|
||||
|
||||
let btns = [];
|
||||
if (props.addable && props.showAddBtn !== false) {
|
||||
|
@ -350,7 +369,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="新增一行"
|
||||
tooltip={__('新增一行')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
|
@ -399,7 +418,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="编辑当前行"
|
||||
tooltip={__('编辑当前行')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
|
@ -423,7 +442,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="保存"
|
||||
tooltip={__('保存')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
|
@ -447,7 +466,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="取消"
|
||||
tooltip={__('取消')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
|
@ -481,7 +500,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
size="sm"
|
||||
key={key}
|
||||
level="link"
|
||||
tooltip="删除当前行"
|
||||
tooltip={__('删除当前行')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
|
@ -503,7 +522,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
type: 'operation',
|
||||
buttons: btns,
|
||||
width: 150,
|
||||
label: '操作'
|
||||
label: __('操作')
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -576,7 +595,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
buildItems = memoize(
|
||||
(value: Array<any>, editIndex: number) => {
|
||||
return value.map((value: any, index: number) =>
|
||||
index === editIndex ? this.state.editting : value)
|
||||
index === editIndex ? this.state.editting : value
|
||||
);
|
||||
},
|
||||
(...args: Array<any>) => JSON.stringify(args)
|
||||
);
|
||||
|
@ -592,7 +612,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
draggable,
|
||||
addable,
|
||||
columnsTogglable,
|
||||
combineNum
|
||||
combineNum,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
@ -601,7 +622,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
'body',
|
||||
{
|
||||
type: 'table',
|
||||
placeholder,
|
||||
placeholder: __(placeholder),
|
||||
columns: this.state.columns,
|
||||
affixHeader: false
|
||||
},
|
||||
|
@ -610,12 +631,14 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
|||
saveImmediately: true,
|
||||
disabled,
|
||||
draggable: draggable && !~this.state.editIndex,
|
||||
items: this.buildItems((Array.isArray(value) && value.length
|
||||
? value
|
||||
: addable && showAddBtn !== false
|
||||
? [{__isPlaceholder: true}]
|
||||
: []
|
||||
), this.state.editIndex),
|
||||
items: this.buildItems(
|
||||
Array.isArray(value) && value.length
|
||||
? value
|
||||
: addable && showAddBtn !== false
|
||||
? [{__isPlaceholder: true}]
|
||||
: [],
|
||||
this.state.editIndex
|
||||
),
|
||||
getEntryId: this.getEntryId,
|
||||
onSave: this.handleTableSave,
|
||||
onSaveOrder: this.handleSaveTableOrder,
|
||||
|
|
|
@ -2,7 +2,7 @@ import {OptionsControlProps, OptionsControl} from './Options';
|
|||
import React from 'react';
|
||||
import {Api} from '../../types';
|
||||
import Spinner from '../../components/Spinner';
|
||||
import {TransferRenderer} from './Transfer';
|
||||
import {BaseTransferRenderer} from './Transfer';
|
||||
import TabsTransfer from '../../components/TabsTransfer';
|
||||
|
||||
export interface TabsTransferProps extends OptionsControlProps {
|
||||
|
@ -16,7 +16,9 @@ export interface TabsTransferProps extends OptionsControlProps {
|
|||
@OptionsControl({
|
||||
type: 'tabs-transfer'
|
||||
})
|
||||
export class TabsTransferRenderer extends TransferRenderer<TabsTransferProps> {
|
||||
export class TabsTransferRenderer extends BaseTransferRenderer<
|
||||
TabsTransferProps
|
||||
> {
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
|
|
|
@ -271,7 +271,8 @@ export default class TagControl extends React.PureComponent<
|
|||
popOverContainer,
|
||||
dropdown,
|
||||
options,
|
||||
optionsTip
|
||||
optionsTip,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
const finnalOptions = Array.isArray(options)
|
||||
|
@ -300,7 +301,7 @@ export default class TagControl extends React.PureComponent<
|
|||
{...getInputProps({
|
||||
name,
|
||||
ref: this.input,
|
||||
placeholder: placeholder || '暂无标签',
|
||||
placeholder: __(placeholder || '暂无标签'),
|
||||
value: this.state.inputValue,
|
||||
onKeyDown: this.handleKeyDown,
|
||||
onFocus: this.handleFocus,
|
||||
|
@ -348,7 +349,9 @@ export default class TagControl extends React.PureComponent<
|
|||
// 保留原来的展现方式,不推荐
|
||||
<div className={cx('TagControl-sug')}>
|
||||
{optionsTip ? (
|
||||
<div className={cx('TagControl-sugTip')}>{optionsTip}</div>
|
||||
<div className={cx('TagControl-sugTip')}>
|
||||
{__(optionsTip)}
|
||||
</div>
|
||||
) : null}
|
||||
{options.map((item, index) => (
|
||||
<div
|
||||
|
|
|
@ -415,7 +415,8 @@ export default class TextControl extends React.PureComponent<
|
|||
labelField,
|
||||
valueField,
|
||||
multiple,
|
||||
spinnerClassName
|
||||
spinnerClassName,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
@ -542,7 +543,7 @@ export default class TextControl extends React.PureComponent<
|
|||
>
|
||||
{option.isNew ? (
|
||||
<span>
|
||||
新增:{option.label}
|
||||
{__('新增:{{label}}', {label: option.label})}
|
||||
<Icon icon="enter" className="icon" />
|
||||
</span>
|
||||
) : (
|
||||
|
|
|
@ -15,7 +15,7 @@ import find from 'lodash/find';
|
|||
import {optionValueCompare} from '../../components/Select';
|
||||
import {resolveVariable} from '../../utils/tpl-builtin';
|
||||
|
||||
export interface TransferProps extends OptionsControlProps {
|
||||
export interface BaseTransferProps extends OptionsControlProps {
|
||||
showArrow?: boolean;
|
||||
sortable?: boolean;
|
||||
selectMode?: 'table' | 'list' | 'tree' | 'chained' | 'associated';
|
||||
|
@ -29,8 +29,8 @@ export interface TransferProps extends OptionsControlProps {
|
|||
searchApi?: Api;
|
||||
}
|
||||
|
||||
export class TransferRenderer<
|
||||
T extends OptionsControlProps = TransferProps
|
||||
export class BaseTransferRenderer<
|
||||
T extends OptionsControlProps = BaseTransferProps
|
||||
> extends React.Component<T> {
|
||||
@autobind
|
||||
handleChange(value: Array<Option>) {
|
||||
|
@ -212,6 +212,9 @@ export class TransferRenderer<
|
|||
}
|
||||
}
|
||||
|
||||
// ts 3.9 里面非得这样才不报错,鬼知道为何。
|
||||
export class TransferRender extends BaseTransferRenderer {}
|
||||
|
||||
export default OptionsControl({
|
||||
type: 'transfer'
|
||||
})(TransferRenderer);
|
||||
})(TransferRender);
|
||||
|
|
|
@ -69,7 +69,8 @@ export default class TreeControl extends React.Component<TreeProps> {
|
|||
removeTip,
|
||||
onDelete,
|
||||
rootCreatable,
|
||||
rootCreateTip
|
||||
rootCreateTip,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
@ -84,7 +85,7 @@ export default class TreeControl extends React.Component<TreeProps> {
|
|||
joinValues={joinValues}
|
||||
extractValue={extractValue}
|
||||
delimiter={delimiter}
|
||||
placeholder={placeholder}
|
||||
placeholder={__(placeholder)}
|
||||
options={options}
|
||||
multiple={multiple}
|
||||
initiallyOpen={initiallyOpen}
|
||||
|
|
|
@ -132,15 +132,21 @@ export default class TreeSelectControl extends React.Component<
|
|||
}
|
||||
|
||||
validate(): any {
|
||||
const {value, minLength, maxLength, delimiter} = this.props;
|
||||
const {value, minLength, maxLength, delimiter, translate: __} = this.props;
|
||||
|
||||
let curValue = Array.isArray(value)
|
||||
? value
|
||||
: (value ? String(value) : '').split(delimiter || ',');
|
||||
if (minLength && curValue.length < minLength) {
|
||||
return `已选择数量低于设定的最小个数${minLength},请选择更多的选项。`;
|
||||
return __(
|
||||
'已选择数量低于设定的最小个数${minLength},请选择更多的选项。',
|
||||
{minLength}
|
||||
);
|
||||
} else if (maxLength && curValue.length > maxLength) {
|
||||
return `已选择数量超出设定的最大个数${maxLength},请取消选择超出的选项。`;
|
||||
return __(
|
||||
'已选择数量超出设定的最大个数{{maxLength}},请取消选择超出的选项。',
|
||||
{maxLength}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,7 +327,8 @@ export default class TreeSelectControl extends React.Component<
|
|||
labelField,
|
||||
disabled,
|
||||
placeholder,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if ((!multiple || !selectedOptions.length) && this.state.inputValue) {
|
||||
|
@ -355,7 +362,7 @@ export default class TreeSelectControl extends React.Component<
|
|||
)
|
||||
) : (
|
||||
<span key="placeholder" className={cx('TreeSelect-placeholder')}>
|
||||
{placeholder}
|
||||
{__(placeholder)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
@ -386,7 +393,8 @@ export default class TreeSelectControl extends React.Component<
|
|||
searchable,
|
||||
autoComplete,
|
||||
maxLength,
|
||||
minLength
|
||||
minLength,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let filtedOptions =
|
||||
|
@ -420,14 +428,14 @@ export default class TreeSelectControl extends React.Component<
|
|||
joinValues={joinValues}
|
||||
extractValue={extractValue}
|
||||
delimiter={delimiter}
|
||||
placeholder={optionsPlaceholder}
|
||||
placeholder={__(optionsPlaceholder)}
|
||||
options={filtedOptions}
|
||||
highlightTxt={this.state.inputValue}
|
||||
multiple={multiple}
|
||||
initiallyOpen={initiallyOpen}
|
||||
unfoldedLevel={unfoldedLevel}
|
||||
withChildren={withChildren}
|
||||
rootLabel={rootLabel}
|
||||
rootLabel={__(rootLabel)}
|
||||
rootValue={rootValue}
|
||||
showIcon={showIcon}
|
||||
showRadio={showRadio}
|
||||
|
|
|
@ -460,13 +460,13 @@ export default class Form extends React.Component<FormProps, object> {
|
|||
}
|
||||
|
||||
submit(fn?: (values: object) => Promise<any>): Promise<any> {
|
||||
const {store, messages} = this.props;
|
||||
const {store, messages, translate: __} = this.props;
|
||||
this.flush();
|
||||
|
||||
return store.submit(
|
||||
fn,
|
||||
this.hooks['validate' || []],
|
||||
messages && messages.validateFailed
|
||||
__(messages && messages.validateFailed)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -563,7 +563,8 @@ export default class Form extends React.Component<FormProps, object> {
|
|||
env,
|
||||
onChange,
|
||||
clearPersistDataAfterSubmit,
|
||||
trimValues
|
||||
trimValues,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
// 做动作之前,先把数据同步一下。
|
||||
|
@ -581,7 +582,7 @@ export default class Form extends React.Component<FormProps, object> {
|
|||
if (Array.isArray(action.required) && action.required.length) {
|
||||
return store.validateFields(action.required).then(result => {
|
||||
if (!result) {
|
||||
env.notify('error', '依赖的部分字段没有通过验证,请注意填写!');
|
||||
env.notify('error', __('依赖的部分字段没有通过验证,请注意填写!'));
|
||||
} else {
|
||||
this.handleAction(
|
||||
e,
|
||||
|
@ -706,15 +707,17 @@ export default class Form extends React.Component<FormProps, object> {
|
|||
} else if (action.actionType === 'ajax') {
|
||||
store.setCurrentAction(action);
|
||||
if (!isEffectiveApi(action.api)) {
|
||||
return env.alert(`当 actionType 为 ajax 时,请设置 api 属性`);
|
||||
return env.alert(__(`当 actionType 为 ajax 时,请设置 api 属性`));
|
||||
}
|
||||
|
||||
return store
|
||||
.saveRemote(action.api as Api, data, {
|
||||
successMessage:
|
||||
(action.messages && action.messages.success) || saveSuccess,
|
||||
errorMessage:
|
||||
successMessage: __(
|
||||
(action.messages && action.messages.success) || saveSuccess
|
||||
),
|
||||
errorMessage: __(
|
||||
(action.messages && action.messages.failed) || saveFailed
|
||||
)
|
||||
})
|
||||
.then(async response => {
|
||||
response &&
|
||||
|
@ -833,7 +836,7 @@ export default class Form extends React.Component<FormProps, object> {
|
|||
}
|
||||
|
||||
buildActions() {
|
||||
const {actions, submitText, controls} = this.props;
|
||||
const {actions, submitText, controls, translate: __} = this.props;
|
||||
|
||||
if (
|
||||
typeof actions !== 'undefined' ||
|
||||
|
@ -852,7 +855,7 @@ export default class Form extends React.Component<FormProps, object> {
|
|||
return [
|
||||
{
|
||||
type: 'submit',
|
||||
label: submitText,
|
||||
label: __(submitText),
|
||||
primary: true
|
||||
}
|
||||
];
|
||||
|
@ -1126,7 +1129,8 @@ export default class Form extends React.Component<FormProps, object> {
|
|||
bodyClassName,
|
||||
classnames: cx,
|
||||
affixFooter,
|
||||
lazyLoad
|
||||
lazyLoad,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let body: JSX.Element = this.renderBody();
|
||||
|
@ -1136,7 +1140,7 @@ export default class Form extends React.Component<FormProps, object> {
|
|||
'body',
|
||||
{
|
||||
type: 'panel',
|
||||
title: title
|
||||
title: __(title)
|
||||
},
|
||||
{
|
||||
className: cx(panelClassName, 'Panel--form'),
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React from 'react';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import {filter} from '../utils/tpl';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {autobind} from '../utils/helper';
|
||||
import {Icon} from '../components/icons';
|
||||
import {LocaleProps, localeable} from '../locale';
|
||||
|
||||
export interface ImageThumbProps {
|
||||
export interface ImageThumbProps extends LocaleProps, ThemeProps {
|
||||
src: string;
|
||||
originalSrc?: string; // 原图
|
||||
enlargeAble?: boolean;
|
||||
|
@ -19,8 +20,6 @@ export interface ImageThumbProps {
|
|||
caption?: string;
|
||||
thumbMode?: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||
thumbRatio?: '1:1' | '4:3' | '16:9';
|
||||
classnames: ClassNamesFn;
|
||||
classPrefix: string;
|
||||
onLoad?: React.EventHandler<any>;
|
||||
}
|
||||
|
||||
|
@ -43,7 +42,8 @@ export class ImageThumb extends React.Component<ImageThumbProps> {
|
|||
title,
|
||||
caption,
|
||||
onLoad,
|
||||
enlargeAble
|
||||
enlargeAble,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
@ -65,7 +65,7 @@ export class ImageThumb extends React.Component<ImageThumbProps> {
|
|||
{enlargeAble ? (
|
||||
<div key="overlay" className={cx('Image-overlay')}>
|
||||
<a
|
||||
data-tooltip="查看大图"
|
||||
data-tooltip={__('查看大图')}
|
||||
data-position="bottom"
|
||||
target="_blank"
|
||||
onClick={this.handleEnlarge}
|
||||
|
@ -87,7 +87,7 @@ export class ImageThumb extends React.Component<ImageThumbProps> {
|
|||
);
|
||||
}
|
||||
}
|
||||
const ThemedImageThumb = themeable(ImageThumb);
|
||||
const ThemedImageThumb = themeable(localeable(ImageThumb));
|
||||
export default ThemedImageThumb;
|
||||
|
||||
export interface ImageFieldProps extends RendererProps {
|
||||
|
|
|
@ -24,7 +24,8 @@ export class LinkField extends React.Component<LinkProps, object> {
|
|||
blank,
|
||||
htmlTarget,
|
||||
data,
|
||||
render
|
||||
render,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
let value = this.props.value;
|
||||
|
@ -36,7 +37,7 @@ export class LinkField extends React.Component<LinkProps, object> {
|
|||
target={htmlTarget || (blank ? '_blank' : '_self')}
|
||||
className={cx('Link', className)}
|
||||
>
|
||||
{body ? render('body', body) : finnalHref || value || '链接'}
|
||||
{body ? render('body', body) : finnalHref || value || __('链接')}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -167,9 +167,9 @@ export default class List extends React.Component<ListProps, object> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
let parent: HTMLElement | Window | null = getScrollParent(findDOMNode(
|
||||
this
|
||||
) as HTMLElement);
|
||||
let parent: HTMLElement | Window | null = getScrollParent(
|
||||
findDOMNode(this) as HTMLElement
|
||||
);
|
||||
if (!parent || parent === document.body) {
|
||||
parent = window;
|
||||
}
|
||||
|
@ -251,9 +251,7 @@ export default class List extends React.Component<ListProps, object> {
|
|||
const affixed = clip.top < offsetY && clip.top + clip.height - 40 > offsetY;
|
||||
|
||||
this.body.offsetWidth &&
|
||||
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${
|
||||
this.body.offsetWidth
|
||||
}px;`);
|
||||
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${this.body.offsetWidth}px;`);
|
||||
affixed ? afixedDom.classList.add('in') : afixedDom.classList.remove('in');
|
||||
// store.markHeaderAffix(clip.top < offsetY && (clip.top + clip.height - 40) > offsetY);
|
||||
}
|
||||
|
@ -494,9 +492,7 @@ export default class List extends React.Component<ListProps, object> {
|
|||
<div className={cx('List-heading')}>
|
||||
{store.modified && !hideQuickSaveBtn ? (
|
||||
<span>
|
||||
{`当前有 ${
|
||||
store.modified
|
||||
} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
{`当前有 ${store.modified} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
<button
|
||||
type="button"
|
||||
className={cx('Button Button--xs Button--success m-l-sm')}
|
||||
|
@ -732,7 +728,8 @@ export default class List extends React.Component<ListProps, object> {
|
|||
checkOnItemClick,
|
||||
affixHeader,
|
||||
classnames: cx,
|
||||
size
|
||||
size,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
this.renderedToolbars = [];
|
||||
|
@ -791,7 +788,7 @@ export default class List extends React.Component<ListProps, object> {
|
|||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className={cx('List-placeholder')}>{placeholder}</div>
|
||||
<div className={cx('List-placeholder')}>{__(placeholder)}</div>
|
||||
)}
|
||||
|
||||
{this.renderFooter()}
|
||||
|
|
|
@ -128,7 +128,7 @@ export class Navigation extends React.Component<
|
|||
return this.receive(query);
|
||||
}
|
||||
|
||||
const {data, env, source} = this.props;
|
||||
const {data, env, source, translate: __} = this.props;
|
||||
const finalData = values ? createObject(data, values) : data;
|
||||
|
||||
if (!isEffectiveApi(source, data)) {
|
||||
|
@ -144,7 +144,7 @@ export class Navigation extends React.Component<
|
|||
|
||||
if (!payload.ok) {
|
||||
this.setState({
|
||||
error: payload.msg || '获取链接错误'
|
||||
error: payload.msg || __('获取链接错误')
|
||||
});
|
||||
} else {
|
||||
const links = Array.isArray(payload.data)
|
||||
|
|
|
@ -91,7 +91,7 @@ export const HocPopOver = (config: Partial<PopOverConfig> = {}) => (
|
|||
}
|
||||
|
||||
buildSchema() {
|
||||
const {popOver, name, label} = this.props;
|
||||
const {popOver, name, label, translate: __} = this.props;
|
||||
|
||||
let schema;
|
||||
|
||||
|
@ -108,7 +108,7 @@ export const HocPopOver = (config: Partial<PopOverConfig> = {}) => (
|
|||
type: popOver.mode,
|
||||
actions: [
|
||||
{
|
||||
label: '关闭',
|
||||
label: __('关闭'),
|
||||
type: 'button',
|
||||
actionType: 'cancel'
|
||||
}
|
||||
|
|
|
@ -304,7 +304,7 @@ export const HocQuickEdit = (config: Partial<QuickEditConfig> = {}) => (
|
|||
}
|
||||
|
||||
buildSchema() {
|
||||
const {quickEdit, name, label} = this.props;
|
||||
const {quickEdit, name, label, translate: __} = this.props;
|
||||
|
||||
let schema;
|
||||
|
||||
|
@ -372,12 +372,12 @@ export const HocQuickEdit = (config: Partial<QuickEditConfig> = {}) => (
|
|||
: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '取消',
|
||||
label: __('取消'),
|
||||
actionType: 'cancel'
|
||||
},
|
||||
|
||||
{
|
||||
label: '确认',
|
||||
label: __('确认'),
|
||||
type: 'submit',
|
||||
primary: true
|
||||
}
|
||||
|
|
|
@ -213,14 +213,14 @@ export default class Service extends React.Component<ServiceProps> {
|
|||
throwErrors: boolean = false,
|
||||
delegate?: IScopedContext
|
||||
) {
|
||||
const {onAction, store, env, api} = this.props;
|
||||
const {onAction, store, env, api, translate: __} = this.props;
|
||||
|
||||
if (api && action.actionType === 'ajax') {
|
||||
store.setCurrentAction(action);
|
||||
store
|
||||
.saveRemote(action.api as string, data, {
|
||||
successMessage: action.messages && action.messages.success,
|
||||
errorMessage: action.messages && action.messages.failed
|
||||
successMessage: __(action.messages && action.messages.success),
|
||||
errorMessage: __(action.messages && action.messages.failed)
|
||||
})
|
||||
.then(async () => {
|
||||
if (action.feedback && isVisible(action.feedback, store.data)) {
|
||||
|
|
|
@ -959,7 +959,8 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
data,
|
||||
classnames: cx,
|
||||
saveImmediately,
|
||||
headingClassName
|
||||
headingClassName,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
|
@ -971,14 +972,19 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
<div className={cx('Table-heading', headingClassName)} key="heading">
|
||||
{!saveImmediately && store.modified && !hideQuickSaveBtn ? (
|
||||
<span>
|
||||
{`当前有 ${store.modified} 条记录修改了内容, 但并没有提交。请选择:`}
|
||||
{__(
|
||||
'当前有 {{modified}} 条记录修改了内容, 但并没有提交。请选择:',
|
||||
{
|
||||
modified: store.modified
|
||||
}
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className={cx('Button Button--xs Button--success m-l-sm')}
|
||||
onClick={this.handleSave}
|
||||
>
|
||||
<i className="fa fa-check m-r-xs" />
|
||||
提交
|
||||
{__('提交')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
|
@ -986,19 +992,21 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
onClick={this.reset}
|
||||
>
|
||||
<i className="fa fa-times m-r-xs" />
|
||||
放弃
|
||||
{__('放弃')}
|
||||
</button>
|
||||
</span>
|
||||
) : store.moved ? (
|
||||
<span>
|
||||
{`当前有 ${store.moved} 条记录修改了顺序, 但并没有提交。请选择:`}
|
||||
{__('当前有 {{moved}} 条记录修改了顺序, 但并没有提交。请选择:', {
|
||||
moved: store.moved
|
||||
})}
|
||||
<button
|
||||
type="button"
|
||||
className={cx('Button Button--xs Button--success m-l-sm')}
|
||||
onClick={this.handleSaveOrder}
|
||||
>
|
||||
<i className="fa fa-check m-r-xs" />
|
||||
提交
|
||||
{__('提交')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
|
@ -1006,7 +1014,7 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
onClick={this.reset}
|
||||
>
|
||||
<i className="fa fa-times m-r-xs" />
|
||||
放弃
|
||||
{__('放弃')}
|
||||
</button>
|
||||
</span>
|
||||
) : title ? (
|
||||
|
@ -1497,7 +1505,14 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
}
|
||||
|
||||
renderDragToggler() {
|
||||
const {store, env, draggable, classPrefix: ns, dragIcon} = this.props;
|
||||
const {
|
||||
store,
|
||||
env,
|
||||
draggable,
|
||||
classPrefix: ns,
|
||||
dragIcon,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (!draggable || store.isNested) {
|
||||
return null;
|
||||
|
@ -1508,7 +1523,7 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
disabled={!!store.modified}
|
||||
classPrefix={ns}
|
||||
key="dragging-toggle"
|
||||
tooltip="点击开始排序"
|
||||
tooltip={__('点击开始排序')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
|
@ -1587,7 +1602,8 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
showHeader,
|
||||
store,
|
||||
classnames: cx,
|
||||
data
|
||||
data,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (showHeader === false) {
|
||||
|
@ -1625,7 +1641,7 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
{child}
|
||||
{store.dragging ? (
|
||||
<div className={cx('Table-dragTip')} ref={this.dragTipRef}>
|
||||
请拖动左边的按钮进行排序
|
||||
{__('请拖动左边的按钮进行排序')}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -1767,7 +1783,7 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
? filter(rowClassNameExpr, item.data)
|
||||
: rowClassName
|
||||
)}
|
||||
columns={columns}
|
||||
columns={store.footableColumns}
|
||||
renderCell={this.renderCell}
|
||||
render={render}
|
||||
onAction={onAction}
|
||||
|
@ -2160,7 +2176,7 @@ export class HeadCellSearchDropDown extends React.Component<
|
|||
}
|
||||
|
||||
buildSchema() {
|
||||
const {searchable, sortable, name, label} = this.props;
|
||||
const {searchable, sortable, name, label, translate: __} = this.props;
|
||||
|
||||
let schema;
|
||||
|
||||
|
@ -2207,14 +2223,14 @@ export class HeadCellSearchDropDown extends React.Component<
|
|||
{
|
||||
type: 'button-group',
|
||||
name: 'orderDir',
|
||||
label: '排序',
|
||||
label: __('排序'),
|
||||
options: [
|
||||
{
|
||||
label: '正序',
|
||||
label: __('正序'),
|
||||
value: 'asc'
|
||||
},
|
||||
{
|
||||
label: '降序',
|
||||
label: __('降序'),
|
||||
value: 'desc'
|
||||
}
|
||||
]
|
||||
|
@ -2230,12 +2246,12 @@ export class HeadCellSearchDropDown extends React.Component<
|
|||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '取消',
|
||||
label: __('取消'),
|
||||
actionType: 'cancel'
|
||||
},
|
||||
|
||||
{
|
||||
label: '搜索',
|
||||
label: __('搜索'),
|
||||
type: 'submit',
|
||||
primary: true
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
* @file video
|
||||
* @author fex
|
||||
*/
|
||||
/* eslint fecs-indent: [0, "space", 2, 2] */
|
||||
|
||||
import React from 'react';
|
||||
|
||||
|
|
|
@ -650,7 +650,8 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
|||
actionNextLabel,
|
||||
actionNextSaveLabel,
|
||||
actionFinishLabel,
|
||||
render
|
||||
render,
|
||||
translate: __
|
||||
} = this.props;
|
||||
|
||||
if (!Array.isArray(steps)) {
|
||||
|
@ -698,7 +699,7 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
|||
`prev-btn`,
|
||||
{
|
||||
type: 'button',
|
||||
label: actionPrevLabel,
|
||||
label: __(actionPrevLabel),
|
||||
actionType: 'prev',
|
||||
className: actionClassName
|
||||
},
|
||||
|
@ -713,10 +714,10 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
|||
{
|
||||
type: 'button',
|
||||
label: !nextStep
|
||||
? actionFinishLabel
|
||||
? __(actionFinishLabel)
|
||||
: !step.api
|
||||
? actionNextLabel
|
||||
: actionNextSaveLabel,
|
||||
? __(actionNextLabel)
|
||||
: __(actionNextSaveLabel),
|
||||
actionType: 'next',
|
||||
primary: !nextStep || !!step.api,
|
||||
className: actionClassName
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import cx from 'classnames';
|
||||
import React from 'react';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
import {ExtractProps, Omit} from './types';
|
||||
|
||||
export type ClassValue =
|
||||
| string
|
||||
|
@ -117,17 +116,19 @@ export const ThemeContext = React.createContext('theme');
|
|||
export let defaultTheme: string = 'default';
|
||||
|
||||
export function themeable<
|
||||
T extends React.ComponentType<ThemeProps & ExtractProps<T>>
|
||||
T extends React.ComponentType<React.ComponentProps<T> & ThemeProps>
|
||||
>(ComposedComponent: T) {
|
||||
type ComposedProps = JSX.LibraryManagedAttributes<T, ExtractProps<T>>;
|
||||
type Props = Omit<ComposedProps, keyof ThemeProps> & {
|
||||
type OuterProps = JSX.LibraryManagedAttributes<
|
||||
T,
|
||||
Omit<React.ComponentProps<T>, keyof ThemeProps>
|
||||
> & {
|
||||
theme?: string;
|
||||
classPrefix?: string;
|
||||
classnames?: ClassNamesFn;
|
||||
};
|
||||
|
||||
const result = hoistNonReactStatic(
|
||||
class extends React.Component<Props> {
|
||||
class extends React.Component<OuterProps> {
|
||||
static displayName = `Themeable(${
|
||||
ComposedComponent.displayName || ComposedComponent.name
|
||||
})`;
|
||||
|
@ -150,9 +151,10 @@ export function themeable<
|
|||
return (
|
||||
<ThemeContext.Provider value={theme}>
|
||||
<ComposedComponent
|
||||
{
|
||||
...(this.props as any) /* todo, 解决这个类型问题 */
|
||||
}
|
||||
{...(this.props as JSX.LibraryManagedAttributes<
|
||||
T,
|
||||
React.ComponentProps<T>
|
||||
>)}
|
||||
{...injectedProps}
|
||||
/>
|
||||
</ThemeContext.Provider>
|
||||
|
|
12
src/types.ts
12
src/types.ts
|
@ -140,15 +140,15 @@ export interface RendererData {
|
|||
type RendererDataAlis = RendererData;
|
||||
|
||||
export type FunctionPropertyNames<T> = {
|
||||
[K in keyof T]: T[K] extends Function ? K : never
|
||||
[K in keyof T]: T[K] extends Function ? K : never;
|
||||
}[keyof T];
|
||||
|
||||
export interface JSONSchema {
|
||||
[propsName: string]: any;
|
||||
}
|
||||
|
||||
export type Omit<T, K extends keyof T & any> = Pick<T, Exclude<keyof T, K>>;
|
||||
export type Override<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
|
||||
export type ExtractProps<
|
||||
TComponentOrTProps
|
||||
> = TComponentOrTProps extends React.ComponentType<infer P> ? P : never;
|
||||
// export type Omit<T, K extends keyof T & any> = Pick<T, Exclude<keyof T, K>>;
|
||||
// export type Override<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
|
||||
// export type ExtractProps<
|
||||
// TComponentOrTProps
|
||||
// > = TComponentOrTProps extends React.ComponentType<infer P> ? P : never;
|
||||
|
|
|
@ -607,7 +607,7 @@ export function isBreakpoint(str: string): boolean {
|
|||
|
||||
const breaks = str.split(/\s*,\s*|\s+/);
|
||||
|
||||
if (window.matchMedia) {
|
||||
if ((window as any).matchMedia) {
|
||||
return breaks.some(
|
||||
item =>
|
||||
item === '*' ||
|
||||
|
@ -1095,7 +1095,7 @@ export function sortArray<T extends any>(
|
|||
field: string,
|
||||
dir: -1 | 1
|
||||
): Array<T> {
|
||||
return items.sort((a, b) => {
|
||||
return items.sort((a: any, b: any) => {
|
||||
let ret: number;
|
||||
const a1 = a[field];
|
||||
const b1 = b[field];
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
* @file resize-sensor.js.
|
||||
* @author fex
|
||||
*/
|
||||
/* eslint-disable */
|
||||
|
||||
class EventQueue {
|
||||
q: Array<Function> = [];
|
||||
|
@ -70,7 +69,7 @@ function attachResizeEvent(element: HTMLElement, resized: Function) {
|
|||
|
||||
let lastWidth: number, lastHeight: number;
|
||||
|
||||
const reset = function() {
|
||||
const reset = function () {
|
||||
expandChild.style.width = expand.offsetWidth + 10 + 'px';
|
||||
expandChild.style.height = expand.offsetHeight + 10 + 'px';
|
||||
expand.scrollLeft = expand.scrollWidth;
|
||||
|
@ -83,13 +82,13 @@ function attachResizeEvent(element: HTMLElement, resized: Function) {
|
|||
|
||||
reset();
|
||||
|
||||
let changed = function() {
|
||||
let changed = function () {
|
||||
if ((element as any).resizedAttached) {
|
||||
(element as any).resizedAttached.call();
|
||||
}
|
||||
};
|
||||
|
||||
let addEvent = function(el: HTMLElement, name: string, cb: Function) {
|
||||
let addEvent = function (el: HTMLElement, name: string, cb: Function) {
|
||||
if ((el as any).attachEvent) {
|
||||
(el as any).attachEvent('on' + name, cb);
|
||||
} else {
|
||||
|
@ -97,7 +96,7 @@ function attachResizeEvent(element: HTMLElement, resized: Function) {
|
|||
}
|
||||
};
|
||||
|
||||
let onScroll = function(e: Event) {
|
||||
let onScroll = function (e: Event) {
|
||||
if (
|
||||
element.offsetWidth != lastWidth ||
|
||||
element.offsetHeight != lastHeight
|
||||
|
@ -132,7 +131,7 @@ export function resizeSensor(
|
|||
once: boolean = false
|
||||
) {
|
||||
if (once) {
|
||||
attachResizeEvent(element, function(this: any) {
|
||||
attachResizeEvent(element, function (this: any) {
|
||||
callback.apply(this, arguments);
|
||||
detach(element);
|
||||
});
|
||||
|
@ -142,7 +141,7 @@ export function resizeSensor(
|
|||
attachResizeEvent(element, callback);
|
||||
let detached = false;
|
||||
|
||||
return function() {
|
||||
return function () {
|
||||
if (detached) return;
|
||||
detached = true;
|
||||
detach(element);
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
declare module 'uncontrollable' {
|
||||
function uncontrollable<T extends React.ComponentType<any>, P extends {
|
||||
[propName:string]: any
|
||||
}>(arg:T, config:P):T;
|
||||
function uncontrollable<
|
||||
T extends Raect.ComponentType<any>,
|
||||
P extends {
|
||||
[propName: string]: any;
|
||||
}
|
||||
>(arg: T, config: P): T;
|
||||
|
||||
export = uncontrollable;
|
||||
export = uncontrollable;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue