mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 19:19:57 +08:00
commit
7fcfa13c24
2
components/calendar/locale/th_TH.tsx
Normal file
2
components/calendar/locale/th_TH.tsx
Normal file
@ -0,0 +1,2 @@
|
||||
import th_TH from '../../date-picker/locale/th_TH';
|
||||
export default th_TH;
|
17
components/date-picker/locale/th_TH.tsx
Normal file
17
components/date-picker/locale/th_TH.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import CalendarLocale from 'rc-calendar/lib/locale/th_TH';
|
||||
import TimePickerLocale from '../../time-picker/locale/th_TH';
|
||||
import assign from 'object-assign';
|
||||
|
||||
// Merge into a locale object
|
||||
const locale = {
|
||||
lang: assign({
|
||||
placeholder: 'เลือกวันที่',
|
||||
rangePlaceholder: ['วันเริ่มต้น', 'วันสิ้นสุด'],
|
||||
}, CalendarLocale),
|
||||
timePickerLocale: assign({}, TimePickerLocale),
|
||||
};
|
||||
|
||||
// All settings at:
|
||||
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
|
||||
|
||||
export default locale;
|
@ -1,10 +1,10 @@
|
||||
/* tslint:disable jsx-no-multiline-js */
|
||||
import React from 'react';
|
||||
import { Component, cloneElement } from 'react';
|
||||
import React, { Component, cloneElement } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import calculateNodeHeight from './calculateNodeHeight';
|
||||
import omit from 'omit.js';
|
||||
import Group from './Group';
|
||||
import Search from './Search';
|
||||
import TextArea from './TextArea';
|
||||
|
||||
function fixControlledValue(value) {
|
||||
if (typeof value === 'undefined' || value === null) {
|
||||
@ -13,49 +13,31 @@ function fixControlledValue(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
function onNextFrame(cb) {
|
||||
if (window.requestAnimationFrame) {
|
||||
return window.requestAnimationFrame(cb);
|
||||
}
|
||||
return window.setTimeout(cb, 1);
|
||||
}
|
||||
|
||||
function clearNextFrameAction(nextFrameId) {
|
||||
if (window.cancelAnimationFrame) {
|
||||
window.cancelAnimationFrame(nextFrameId);
|
||||
} else {
|
||||
window.clearTimeout(nextFrameId);
|
||||
}
|
||||
}
|
||||
|
||||
export interface AutoSizeType {
|
||||
minRows?: number;
|
||||
maxRows?: number;
|
||||
}
|
||||
|
||||
export interface InputProps {
|
||||
export interface AbstractInputProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
defaultValue?: any;
|
||||
value?: any;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export interface InputProps extends AbstractInputProps {
|
||||
placeholder?: string;
|
||||
type?: string;
|
||||
id?: number | string;
|
||||
name?: string;
|
||||
value?: any;
|
||||
defaultValue?: any;
|
||||
placeholder?: string;
|
||||
size?: 'large' | 'default' | 'small';
|
||||
disabled?: boolean;
|
||||
readOnly?: boolean;
|
||||
addonBefore?: React.ReactNode;
|
||||
addonAfter?: React.ReactNode;
|
||||
onPressEnter?: React.FormEventHandler<any>;
|
||||
onKeyDown?: React.FormEventHandler<any>;
|
||||
onChange?: React.FormEventHandler<any>;
|
||||
onPressEnter?: React.FormEventHandler<any>;
|
||||
onClick?: React.FormEventHandler<any>;
|
||||
onFocus?: React.FormEventHandler<any>;
|
||||
onBlur?: React.FormEventHandler<any>;
|
||||
autosize?: boolean | AutoSizeType;
|
||||
autoComplete?: 'on' | 'off';
|
||||
style?: React.CSSProperties;
|
||||
prefix?: React.ReactNode;
|
||||
suffix?: React.ReactNode;
|
||||
spellCheck?: boolean;
|
||||
@ -63,13 +45,14 @@ export interface InputProps {
|
||||
}
|
||||
|
||||
export default class Input extends Component<InputProps, any> {
|
||||
static Group: any;
|
||||
static Search: any;
|
||||
static Group: typeof Group;
|
||||
static Search: typeof Search;
|
||||
static TextArea: typeof TextArea;
|
||||
|
||||
static defaultProps = {
|
||||
disabled: false,
|
||||
prefixCls: 'ant-input',
|
||||
type: 'text',
|
||||
autosize: false,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
@ -95,30 +78,10 @@ export default class Input extends Component<InputProps, any> {
|
||||
suffix: PropTypes.node,
|
||||
};
|
||||
|
||||
nextFrameActionId?: number;
|
||||
refs: {
|
||||
input: any;
|
||||
input: HTMLInputElement;
|
||||
};
|
||||
|
||||
state = {
|
||||
textareaStyles: null,
|
||||
isFocus: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.resizeTextarea();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Re-render with the new content then recalculate the height as required.
|
||||
if (this.props.value !== nextProps.value) {
|
||||
if (this.nextFrameActionId) {
|
||||
clearNextFrameAction(this.nextFrameActionId);
|
||||
}
|
||||
this.nextFrameActionId = onNextFrame(this.resizeTextarea);
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown = (e) => {
|
||||
const { onPressEnter, onKeyDown } = this.props;
|
||||
if (e.keyCode === 13 && onPressEnter) {
|
||||
@ -129,37 +92,18 @@ export default class Input extends Component<InputProps, any> {
|
||||
}
|
||||
}
|
||||
|
||||
handleTextareaChange = (e) => {
|
||||
if (!('value' in this.props)) {
|
||||
this.resizeTextarea();
|
||||
}
|
||||
const onChange = this.props.onChange;
|
||||
if (onChange) {
|
||||
onChange(e);
|
||||
}
|
||||
}
|
||||
|
||||
resizeTextarea = () => {
|
||||
const { type, autosize } = this.props;
|
||||
if (type !== 'textarea' || !autosize || !this.refs.input) {
|
||||
return;
|
||||
}
|
||||
const minRows = autosize ? (autosize as AutoSizeType).minRows : null;
|
||||
const maxRows = autosize ? (autosize as AutoSizeType).maxRows : null;
|
||||
const textareaStyles = calculateNodeHeight(this.refs.input, false, minRows, maxRows);
|
||||
this.setState({ textareaStyles });
|
||||
this.nextFrameActionId = undefined;
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.refs.input.focus();
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.refs.input.blur();
|
||||
}
|
||||
|
||||
renderLabeledInput(children) {
|
||||
const props = this.props;
|
||||
|
||||
// Not wrap when there is not addons
|
||||
if (props.type === 'textarea' || (!props.addonBefore && !props.addonAfter)) {
|
||||
if ((!props.addonBefore && !props.addonAfter)) {
|
||||
return children;
|
||||
}
|
||||
|
||||
@ -208,8 +152,7 @@ export default class Input extends Component<InputProps, any> {
|
||||
|
||||
renderLabeledIcon(children) {
|
||||
const { props } = this;
|
||||
|
||||
if (props.type === 'textarea' || !('prefix' in props || 'suffix' in props)) {
|
||||
if (!('prefix' in props || 'suffix' in props)) {
|
||||
return children;
|
||||
}
|
||||
|
||||
@ -239,10 +182,9 @@ export default class Input extends Component<InputProps, any> {
|
||||
...this.props,
|
||||
};
|
||||
// Fix https://fb.me/react-unknown-prop
|
||||
const otherProps = omit(this.props, [
|
||||
const otherProps = omit(props, [
|
||||
'prefixCls',
|
||||
'onPressEnter',
|
||||
'autosize',
|
||||
'addonBefore',
|
||||
'addonAfter',
|
||||
'prefix',
|
||||
@ -250,10 +192,6 @@ export default class Input extends Component<InputProps, any> {
|
||||
]);
|
||||
|
||||
const prefixCls = props.prefixCls;
|
||||
if (!props.type) {
|
||||
return props.children;
|
||||
}
|
||||
|
||||
const inputClassName = classNames(prefixCls, {
|
||||
[`${prefixCls}-sm`]: props.size === 'small',
|
||||
[`${prefixCls}-lg`]: props.size === 'large',
|
||||
@ -265,35 +203,20 @@ export default class Input extends Component<InputProps, any> {
|
||||
// specify either the value prop, or the defaultValue prop, but not both.
|
||||
delete otherProps.defaultValue;
|
||||
}
|
||||
|
||||
switch (props.type) {
|
||||
case 'textarea':
|
||||
return (
|
||||
<textarea
|
||||
{...otherProps}
|
||||
style={{
|
||||
...props.style,
|
||||
...this.state.textareaStyles,
|
||||
}}
|
||||
className={inputClassName}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onChange={this.handleTextareaChange}
|
||||
ref="input"
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return this.renderLabeledIcon(
|
||||
<input
|
||||
{...otherProps}
|
||||
className={inputClassName}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
ref="input"
|
||||
/>,
|
||||
);
|
||||
}
|
||||
return this.renderLabeledIcon(
|
||||
<input
|
||||
{...otherProps}
|
||||
className={inputClassName}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
ref="input"
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.type === 'textarea') {
|
||||
return <TextArea {...this.props as any} ref="input" />;
|
||||
}
|
||||
return this.renderLabeledInput(this.renderInput());
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,10 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Input from './Input';
|
||||
import Input, { AbstractInputProps } from './Input';
|
||||
import Icon from '../icon';
|
||||
|
||||
export interface SearchProps {
|
||||
className?: string;
|
||||
export interface SearchProps extends AbstractInputProps {
|
||||
placeholder?: string;
|
||||
prefixCls?: string;
|
||||
style?: React.CSSProperties;
|
||||
defaultValue?: any;
|
||||
value?: any;
|
||||
onSearch?: (value: string) => any;
|
||||
onChange?: React.FormEventHandler<any>;
|
||||
size?: 'large' | 'default' | 'small';
|
||||
@ -21,7 +16,6 @@ export interface SearchProps {
|
||||
export default class Search extends React.Component<SearchProps, any> {
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-input-search',
|
||||
onSearch() {},
|
||||
};
|
||||
input: any;
|
||||
onSearch = () => {
|
||||
@ -29,7 +23,7 @@ export default class Search extends React.Component<SearchProps, any> {
|
||||
if (onSearch) {
|
||||
onSearch(this.input.refs.input.value);
|
||||
}
|
||||
this.input.refs.input.focus();
|
||||
this.input.focus();
|
||||
}
|
||||
render() {
|
||||
const { className, prefixCls, ...others } = this.props;
|
||||
@ -45,8 +39,8 @@ export default class Search extends React.Component<SearchProps, any> {
|
||||
<Input
|
||||
onPressEnter={this.onSearch}
|
||||
{...others}
|
||||
suffix={searchSuffix}
|
||||
className={classNames(prefixCls, className)}
|
||||
suffix={searchSuffix}
|
||||
ref={node => this.input = node}
|
||||
/>
|
||||
);
|
||||
|
124
components/input/TextArea.tsx
Normal file
124
components/input/TextArea.tsx
Normal file
@ -0,0 +1,124 @@
|
||||
import React from 'react';
|
||||
import omit from 'omit.js';
|
||||
import classNames from 'classnames';
|
||||
import { AbstractInputProps } from './Input';
|
||||
import calculateNodeHeight from './calculateNodeHeight';
|
||||
|
||||
function onNextFrame(cb) {
|
||||
if (window.requestAnimationFrame) {
|
||||
return window.requestAnimationFrame(cb);
|
||||
}
|
||||
return window.setTimeout(cb, 1);
|
||||
}
|
||||
|
||||
function clearNextFrameAction(nextFrameId) {
|
||||
if (window.cancelAnimationFrame) {
|
||||
window.cancelAnimationFrame(nextFrameId);
|
||||
} else {
|
||||
window.clearTimeout(nextFrameId);
|
||||
}
|
||||
}
|
||||
|
||||
export interface AutoSizeType {
|
||||
minRows?: number;
|
||||
maxRows?: number;
|
||||
}
|
||||
|
||||
export interface TextAreaProps extends AbstractInputProps {
|
||||
autosize?: boolean | AutoSizeType;
|
||||
onPressEnter?: React.FormEventHandler<any>;
|
||||
}
|
||||
|
||||
export type HTMLTextareaProps = React.HTMLProps<HTMLTextAreaElement>;
|
||||
|
||||
export default class TextArea extends React.Component<TextAreaProps & HTMLTextareaProps, any> {
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-input',
|
||||
};
|
||||
|
||||
nextFrameActionId: number;
|
||||
textAreaRef: HTMLTextAreaElement;
|
||||
state = {
|
||||
textareaStyles: null,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.resizeTextarea();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Re-render with the new content then recalculate the height as required.
|
||||
if (this.props.value !== nextProps.value) {
|
||||
if (this.nextFrameActionId) {
|
||||
clearNextFrameAction(this.nextFrameActionId);
|
||||
}
|
||||
this.nextFrameActionId = onNextFrame(this.resizeTextarea);
|
||||
}
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.textAreaRef.focus();
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.textAreaRef.blur();
|
||||
}
|
||||
|
||||
resizeTextarea = () => {
|
||||
const { autosize } = this.props;
|
||||
if (!autosize || !this.textAreaRef) {
|
||||
return;
|
||||
}
|
||||
const minRows = autosize ? (autosize as AutoSizeType).minRows : null;
|
||||
const maxRows = autosize ? (autosize as AutoSizeType).maxRows : null;
|
||||
const textareaStyles = calculateNodeHeight(this.textAreaRef, false, minRows, maxRows);
|
||||
this.setState({ textareaStyles });
|
||||
}
|
||||
|
||||
handleTextareaChange = (e) => {
|
||||
if (!('value' in this.props)) {
|
||||
this.resizeTextarea();
|
||||
}
|
||||
const { onChange } = this.props;
|
||||
if (onChange) {
|
||||
onChange(e);
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown = (e) => {
|
||||
const { onPressEnter, onKeyDown } = this.props;
|
||||
if (e.keyCode === 13 && onPressEnter) {
|
||||
onPressEnter(e);
|
||||
}
|
||||
if (onKeyDown) {
|
||||
onKeyDown(e);
|
||||
}
|
||||
}
|
||||
|
||||
saveTextAreaRef = (textArea) => {
|
||||
this.textAreaRef = textArea;
|
||||
}
|
||||
|
||||
render() {
|
||||
const props = this.props;
|
||||
const otherProps = omit(props, [
|
||||
'prefixCls',
|
||||
'onPressEnter',
|
||||
'autosize',
|
||||
]);
|
||||
const style = {
|
||||
...props.style,
|
||||
...this.state.textareaStyles,
|
||||
};
|
||||
return (
|
||||
<textarea
|
||||
{...otherProps}
|
||||
className={classNames(props.prefixCls, props.className)}
|
||||
style={style}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onChange={this.handleTextareaChange}
|
||||
ref={this.saveTextAreaRef}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@ -152,7 +152,6 @@ exports[`renders ./components/input/demo/autosize-textarea.md correctly 1`] = `
|
||||
<textarea
|
||||
class="ant-input"
|
||||
placeholder="Autosize height based on content lines"
|
||||
type="textarea"
|
||||
/>
|
||||
<div
|
||||
style="margin:24px 0;"
|
||||
@ -160,7 +159,6 @@ exports[`renders ./components/input/demo/autosize-textarea.md correctly 1`] = `
|
||||
<textarea
|
||||
class="ant-input"
|
||||
placeholder="Autosize height with minimum and maximum number of lines"
|
||||
type="textarea"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
@ -712,7 +710,6 @@ exports[`renders ./components/input/demo/textarea.md correctly 1`] = `
|
||||
<textarea
|
||||
class="ant-input"
|
||||
rows="4"
|
||||
type="textarea"
|
||||
/>
|
||||
`;
|
||||
|
||||
|
@ -17,12 +17,13 @@ An options object can be provided to `autosize` to specify the minimum and maxim
|
||||
|
||||
````jsx
|
||||
import { Input } from 'antd';
|
||||
const { TextArea } = Input;
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Input type="textarea" placeholder="Autosize height based on content lines" autosize />
|
||||
<TextArea placeholder="Autosize height based on content lines" autosize />
|
||||
<div style={{ margin: '24px 0' }} />
|
||||
<Input type="textarea" placeholder="Autosize height with minimum and maximum number of lines" autosize={{ minRows: 2, maxRows: 6 }} />
|
||||
<TextArea placeholder="Autosize height with minimum and maximum number of lines" autosize={{ minRows: 2, maxRows: 6 }} />
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
@ -15,6 +15,7 @@ For multi-line user input cases, an input whose `type` prop has the value of `"t
|
||||
|
||||
````jsx
|
||||
import { Input } from 'antd';
|
||||
const { TextArea } = Input;
|
||||
|
||||
ReactDOM.render(<Input type="textarea" rows={4} />, mountNode);
|
||||
ReactDOM.render(<TextArea rows={4} />, mountNode);
|
||||
````
|
||||
|
@ -18,7 +18,7 @@ Keyboard and mouse can be used for providing or changing data.
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
|----------------|-----------------------|----------|---------------|
|
||||
| type | The type of input, `text` or `textarea` | string | `text` |
|
||||
| type | The type of input, `text` or `textarea`(`type=textarea` are deprecated after `2.12`, please use `Input.TextArea`) | string | `text` |
|
||||
| id | The ID for input | string | |
|
||||
| value | The input content value | string | |
|
||||
| defaultValue | The initial input content | string | |
|
||||
@ -29,13 +29,24 @@ Keyboard and mouse can be used for providing or changing data.
|
||||
| prefix | The Input with prefix icon. | string\|ReactNode | |
|
||||
| suffix | The Input with suffix icon. | string\|ReactNode | |
|
||||
| onPressEnter | The callback function that is triggered when pressing Enter key. | function(e) | |
|
||||
| autosize | Height autosize feature, available when type="textarea", can be set to `true|false` or a object `{ minRows: 2, maxRows: 6 }` | boolean\|object | false |
|
||||
|
||||
> When `Input` is used in a `Form.Item` context, if the `Form.Item` has the `id` and `options` props defined
|
||||
then `value`, `defaultValue`, and `id` props are automatically set.
|
||||
|
||||
The rest props fo Input is exactly same as original [input](https://facebook.github.io/react/docs/events.html#supported-events).
|
||||
The rest props of Input is exactly same as original [input](https://facebook.github.io/react/docs/events.html#supported-events).
|
||||
|
||||
### Input.TextArea
|
||||
|
||||
> It you are using `antd@<2.12`, please use `Input[type=textarea]`.
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
|----------------|-----------------------|----------|---------------|
|
||||
| defaultValue | The initial input content | string | |
|
||||
| value | The input content value | string | |
|
||||
| onPressEnter | The callback function that is triggered when pressing Enter key. | function(e) | |
|
||||
| autosize | Height autosize feature, can be set to `true|false` or a object `{ minRows: 2, maxRows: 6 }` | boolean\|object | false |
|
||||
|
||||
The rest props of `Input.TextArea` is the same as original [textarea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea).
|
||||
|
||||
#### Input.Search
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import Input from './Input';
|
||||
import Group from './Group';
|
||||
import Search from './Search';
|
||||
import TextArea from './TextArea';
|
||||
|
||||
Input.Group = Group;
|
||||
Input.Search = Search;
|
||||
Input.TextArea = TextArea;
|
||||
export default Input;
|
||||
|
@ -18,7 +18,7 @@ title: Input
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|-----------|-----------------------------------------|------------|-------|--------|
|
||||
| type | 声明 input 类型,同原生 input 标签的 type 属性。另外提供 `type="textarea"`。 | string | `text` |
|
||||
| type | 声明 input 类型,同原生 input 标签的 type 属性。另外提供 `type="textarea"`(该 type `2.12` 后废弃,请直接使用 `Input.TextArea`)。 | string | `text` |
|
||||
| id | 输入框的 id | string | |
|
||||
| value | 输入框内容 | string | |
|
||||
| defaultValue | 输入框默认内容 | string | |
|
||||
@ -29,12 +29,24 @@ title: Input
|
||||
| prefix | 带有前缀图标的 input | string\|ReactNode | |
|
||||
| suffix | 带有后缀图标的 input | string\|ReactNode | |
|
||||
| onPressEnter | 按下回车的回调 | function(e) | |
|
||||
| autosize | 自适应内容高度,只对 `type="textarea"` 有效,可设置为 `true|false` 或对象:`{ minRows: 2, maxRows: 6 }` | boolean\|object | false |
|
||||
|
||||
> 如果 `Input` 在 `Form.Item` 内,并且 `Form.Item` 设置了 `id` 和 `options` 属性,则 `value` `defaultValue` 和 `id` 属性会被自动设置。
|
||||
|
||||
Input 的其他属性和 React 自带的 [input](https://facebook.github.io/react/docs/events.html#supported-events) 一致。
|
||||
|
||||
### Input.TextArea
|
||||
|
||||
> `2.12` 后新增的组件,旧版请使用 `Input[type=textarea]`。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|-----------|-----------------------------------------|------------|-------|--------|
|
||||
| defaultValue | 输入框默认内容 | string | |
|
||||
| value | 输入框内容 | string | |
|
||||
| onPressEnter | 按下回车的回调 | function(e) | |
|
||||
| autosize | 自适应内容高度,可设置为 `true|false` 或对象:`{ minRows: 2, maxRows: 6 }` | boolean\|object | false |
|
||||
|
||||
`Input.TextArea` 的其他属性和浏览器自带的 [textarea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) 一致。
|
||||
|
||||
#### Input.Search
|
||||
|
||||
`Added in 2.5.0`
|
||||
|
@ -17,6 +17,7 @@ if (typeof window !== 'undefined') {
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'omit.js';
|
||||
import PropTypes from 'prop-types';
|
||||
import Icon from '../icon';
|
||||
|
||||
const dimensionMap = {
|
||||
@ -55,6 +56,10 @@ export default class Sider extends React.Component<SiderProps, any> {
|
||||
style: {},
|
||||
};
|
||||
|
||||
static childContextTypes = {
|
||||
siderCollapsed: PropTypes.bool,
|
||||
};
|
||||
|
||||
private mql: any;
|
||||
|
||||
constructor(props) {
|
||||
@ -78,6 +83,12 @@ export default class Sider extends React.Component<SiderProps, any> {
|
||||
};
|
||||
}
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
siderCollapsed: this.props.collapsed,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if ('collapsed' in nextProps) {
|
||||
this.setState({
|
||||
|
@ -139,7 +139,7 @@ exports[`renders ./components/layout/demo/custom-trigger.md correctly 1`] = `
|
||||
/>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
>
|
||||
@ -152,9 +152,7 @@ exports[`renders ./components/layout/demo/custom-trigger.md correctly 1`] = `
|
||||
<i
|
||||
class="anticon anticon-user"
|
||||
/>
|
||||
<span
|
||||
class="nav-text"
|
||||
>
|
||||
<span>
|
||||
nav 1
|
||||
</span>
|
||||
</li>
|
||||
@ -167,9 +165,7 @@ exports[`renders ./components/layout/demo/custom-trigger.md correctly 1`] = `
|
||||
<i
|
||||
class="anticon anticon-video-camera"
|
||||
/>
|
||||
<span
|
||||
class="nav-text"
|
||||
>
|
||||
<span>
|
||||
nav 2
|
||||
</span>
|
||||
</li>
|
||||
@ -182,9 +178,7 @@ exports[`renders ./components/layout/demo/custom-trigger.md correctly 1`] = `
|
||||
<i
|
||||
class="anticon anticon-upload"
|
||||
/>
|
||||
<span
|
||||
class="nav-text"
|
||||
>
|
||||
<span>
|
||||
nav 3
|
||||
</span>
|
||||
</li>
|
||||
@ -225,7 +219,7 @@ exports[`renders ./components/layout/demo/fixed.md correctly 1`] = `
|
||||
/>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-horizontal ant-menu-dark ant-menu-root"
|
||||
class="ant-menu ant-menu-horizontal ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
style="line-height:64px;"
|
||||
tabindex="0"
|
||||
@ -330,7 +324,7 @@ exports[`renders ./components/layout/demo/fixed-sider.md correctly 1`] = `
|
||||
/>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
>
|
||||
@ -594,7 +588,7 @@ exports[`renders ./components/layout/demo/responsive.md correctly 1`] = `
|
||||
/>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
>
|
||||
@ -704,10 +698,36 @@ exports[`renders ./components/layout/demo/side.md correctly 1`] = `
|
||||
/>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
aria-selected="true"
|
||||
class="ant-menu-item-selected ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:24px;"
|
||||
>
|
||||
<i
|
||||
class="anticon anticon-pie-chart"
|
||||
/>
|
||||
<span>
|
||||
Option 1
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
aria-selected="false"
|
||||
class="ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:24px;"
|
||||
>
|
||||
<i
|
||||
class="anticon anticon-desktop"
|
||||
/>
|
||||
<span>
|
||||
Option 2
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
class="ant-menu-submenu-inline ant-menu-submenu"
|
||||
>
|
||||
@ -722,9 +742,7 @@ exports[`renders ./components/layout/demo/side.md correctly 1`] = `
|
||||
<i
|
||||
class="anticon anticon-user"
|
||||
/>
|
||||
<span
|
||||
class="nav-text"
|
||||
>
|
||||
<span>
|
||||
User
|
||||
</span>
|
||||
</span>
|
||||
@ -744,29 +762,23 @@ exports[`renders ./components/layout/demo/side.md correctly 1`] = `
|
||||
<i
|
||||
class="anticon anticon-team"
|
||||
/>
|
||||
<span
|
||||
class="nav-text"
|
||||
>
|
||||
<span>
|
||||
Team
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
aria-selected="true"
|
||||
class="ant-menu-item-selected ant-menu-item"
|
||||
aria-selected="false"
|
||||
class="ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:24px;"
|
||||
>
|
||||
<i
|
||||
class="anticon anticon-file"
|
||||
/>
|
||||
<span>
|
||||
<i
|
||||
class="anticon anticon-file"
|
||||
/>
|
||||
<span
|
||||
class="nav-text"
|
||||
>
|
||||
File
|
||||
</span>
|
||||
File
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
@ -847,7 +859,7 @@ exports[`renders ./components/layout/demo/top.md correctly 1`] = `
|
||||
/>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-horizontal ant-menu-dark ant-menu-root"
|
||||
class="ant-menu ant-menu-horizontal ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
style="line-height:64px;"
|
||||
tabindex="0"
|
||||
@ -947,7 +959,7 @@ exports[`renders ./components/layout/demo/top-side.md correctly 1`] = `
|
||||
/>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-horizontal ant-menu-dark ant-menu-root"
|
||||
class="ant-menu ant-menu-horizontal ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
style="line-height:64px;"
|
||||
tabindex="0"
|
||||
@ -1033,13 +1045,13 @@ exports[`renders ./components/layout/demo/top-side.md correctly 1`] = `
|
||||
>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
role="menu"
|
||||
style="height:100%;"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu-selected ant-menu-submenu"
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu"
|
||||
>
|
||||
<div
|
||||
aria-expanded="true"
|
||||
@ -1163,7 +1175,7 @@ exports[`renders ./components/layout/demo/top-side-2.md correctly 1`] = `
|
||||
/>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-horizontal ant-menu-dark ant-menu-root"
|
||||
class="ant-menu ant-menu-horizontal ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
style="line-height:64px;"
|
||||
tabindex="0"
|
||||
@ -1203,13 +1215,13 @@ exports[`renders ./components/layout/demo/top-side-2.md correctly 1`] = `
|
||||
>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
role="menu"
|
||||
style="height:100%;border-right:0;"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu-selected ant-menu-submenu"
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu"
|
||||
>
|
||||
<div
|
||||
aria-expanded="true"
|
||||
|
@ -38,15 +38,15 @@ class SiderDemo extends React.Component {
|
||||
<Menu theme="dark" mode="inline" defaultSelectedKeys={['1']}>
|
||||
<Menu.Item key="1">
|
||||
<Icon type="user" />
|
||||
<span className="nav-text">nav 1</span>
|
||||
<span>nav 1</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="2">
|
||||
<Icon type="video-camera" />
|
||||
<span className="nav-text">nav 2</span>
|
||||
<span>nav 2</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="3">
|
||||
<Icon type="upload" />
|
||||
<span className="nav-text">nav 3</span>
|
||||
<span>nav 3</span>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</Sider>
|
||||
@ -89,12 +89,4 @@ ReactDOM.render(<SiderDemo />, mountNode);
|
||||
border-radius: 6px;
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
#components-layout-demo-custom-trigger .ant-layout-sider-collapsed .anticon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#components-layout-demo-custom-trigger .ant-layout-sider-collapsed .nav-text {
|
||||
display: none;
|
||||
}
|
||||
````
|
||||
|
@ -27,14 +27,10 @@ const SubMenu = Menu.SubMenu;
|
||||
class SiderDemo extends React.Component {
|
||||
state = {
|
||||
collapsed: false,
|
||||
mode: 'inline',
|
||||
};
|
||||
onCollapse = (collapsed) => {
|
||||
console.log(collapsed);
|
||||
this.setState({
|
||||
collapsed,
|
||||
mode: collapsed ? 'vertical' : 'inline',
|
||||
});
|
||||
this.setState({ collapsed });
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
@ -45,27 +41,33 @@ class SiderDemo extends React.Component {
|
||||
onCollapse={this.onCollapse}
|
||||
>
|
||||
<div className="logo" />
|
||||
<Menu theme="dark" mode={this.state.mode} defaultSelectedKeys={['6']}>
|
||||
<Menu theme="dark" defaultSelectedKeys={['1']} mode="inline">
|
||||
<Menu.Item key="1">
|
||||
<Icon type="pie-chart" />
|
||||
<span>Option 1</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="2">
|
||||
<Icon type="desktop" />
|
||||
<span>Option 2</span>
|
||||
</Menu.Item>
|
||||
<SubMenu
|
||||
key="sub1"
|
||||
title={<span><Icon type="user" /><span className="nav-text">User</span></span>}
|
||||
title={<span><Icon type="user" /><span>User</span></span>}
|
||||
>
|
||||
<Menu.Item key="1">Tom</Menu.Item>
|
||||
<Menu.Item key="2">Bill</Menu.Item>
|
||||
<Menu.Item key="3">Alex</Menu.Item>
|
||||
<Menu.Item key="3">Tom</Menu.Item>
|
||||
<Menu.Item key="4">Bill</Menu.Item>
|
||||
<Menu.Item key="5">Alex</Menu.Item>
|
||||
</SubMenu>
|
||||
<SubMenu
|
||||
key="sub2"
|
||||
title={<span><Icon type="team" /><span className="nav-text">Team</span></span>}
|
||||
title={<span><Icon type="team" /><span>Team</span></span>}
|
||||
>
|
||||
<Menu.Item key="4">Team 1</Menu.Item>
|
||||
<Menu.Item key="5">Team 2</Menu.Item>
|
||||
<Menu.Item key="6">Team 1</Menu.Item>
|
||||
<Menu.Item key="8">Team 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="6">
|
||||
<span>
|
||||
<Icon type="file" />
|
||||
<span className="nav-text">File</span>
|
||||
</span>
|
||||
<Menu.Item key="8">
|
||||
<Icon type="file" />
|
||||
<span>File</span>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</Sider>
|
||||
@ -99,17 +101,4 @@ ReactDOM.render(<SiderDemo />, mountNode);
|
||||
border-radius: 6px;
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
#components-layout-demo-side .ant-layout-sider-collapsed .anticon {
|
||||
font-size: 16px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
#components-layout-demo-side .ant-layout-sider-collapsed .nav-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#components-layout-demo-side .ant-layout-sider-collapsed .ant-menu-submenu-vertical > .ant-menu-submenu-title:after {
|
||||
display: none;
|
||||
}
|
||||
````
|
||||
|
@ -27,8 +27,9 @@ import fiFI from '../fi_FI';
|
||||
import plPL from '../pl_PL';
|
||||
import bgBG from '../bg_BG';
|
||||
import viVN from '../vi_VN';
|
||||
import thTH from '../th_TH';
|
||||
|
||||
const locales = [enUS, ptBR, ruRU, esES, svSE, frBE, deDE, nlNL, caES, csCZ, koKR, etEE, skSK, jaJP, trTR, zhTW, fiFI, plPL, bgBG, enGB, frFR, nlBE, itIT, viVN];
|
||||
const locales = [enUS, ptBR, ruRU, esES, svSE, frBE, deDE, nlNL, caES, csCZ, koKR, etEE, skSK, jaJP, trTR, zhTW, fiFI, plPL, bgBG, enGB, frFR, nlBE, itIT, viVN, thTH];
|
||||
|
||||
const Option = Select.Option;
|
||||
const RangePicker = DatePicker.RangePicker;
|
||||
|
47
components/locale-provider/th_TH.tsx
Normal file
47
components/locale-provider/th_TH.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import moment from 'moment';
|
||||
moment.locale('th');
|
||||
|
||||
import Pagination from 'rc-pagination/lib/locale/th_TH';
|
||||
import DatePicker from '../date-picker/locale/th_TH';
|
||||
import TimePicker from '../time-picker/locale/th_TH';
|
||||
import Calendar from '../calendar/locale/th_TH';
|
||||
|
||||
export default {
|
||||
locale: 'th',
|
||||
Pagination,
|
||||
DatePicker,
|
||||
TimePicker,
|
||||
Calendar,
|
||||
Table: {
|
||||
filterTitle: 'ตัวกรอง',
|
||||
filterConfirm: 'ยืนยัน',
|
||||
filterReset: 'รีเซ็ต',
|
||||
emptyText: 'ไม่มีข้อมูล',
|
||||
selectAll: 'เลือกทั้งหมดในหน้านี้',
|
||||
selectInvert: 'เลือกสถานะตรงกันข้าม',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'ตกลง',
|
||||
cancelText: 'ยกเลิก',
|
||||
justOkText: 'ตกลง',
|
||||
},
|
||||
Popconfirm: {
|
||||
okText: 'ตกลง',
|
||||
cancelText: 'ยกเลิก',
|
||||
},
|
||||
Transfer: {
|
||||
notFoundContent: 'ไม่พบข้อมูล',
|
||||
searchPlaceholder: 'ค้นหา',
|
||||
itemUnit: 'ชิ้น',
|
||||
itemsUnit: 'ชิ้น',
|
||||
},
|
||||
Select: {
|
||||
notFoundContent: 'ไม่พบข้อมูล',
|
||||
},
|
||||
Upload: {
|
||||
uploading: 'กำลังอัปโหลด...',
|
||||
removeFile: 'ลบไฟล์',
|
||||
uploadError: 'เกิดข้อผิดพลาดในการอัปโหลด',
|
||||
previewFile: 'ดูตัวอย่างไฟล์',
|
||||
},
|
||||
};
|
@ -21,6 +21,9 @@ class App extends React.Component {
|
||||
state = {
|
||||
value: toContentState('@afc163'),
|
||||
}
|
||||
componentDidMount() {
|
||||
this.mention.focus();
|
||||
}
|
||||
handleChange = (editorState) => {
|
||||
this.setState({
|
||||
value: editorState,
|
||||
@ -29,6 +32,7 @@ class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Mention
|
||||
ref={ele => this.mention = ele}
|
||||
suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
|
||||
value={this.state.value}
|
||||
onChange={this.handleChange}
|
||||
|
@ -51,6 +51,12 @@ When need to mention someone or something.
|
||||
| readOnly | Tell if the input is readonly. | boolean | false |
|
||||
| disabled | Tell if the input is disabled. | boolean | false |
|
||||
|
||||
### Mention methods
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
|----------|---------------|----------|--------------|
|
||||
| focus | Force focus back onto the editor node. | - | - |
|
||||
|
||||
### Nav
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
|
@ -46,6 +46,7 @@ export default class Mention extends React.Component<MentionProps, MentionState>
|
||||
console.warn('Mention.toEditorState is deprecated. Use toContentState instead.');
|
||||
return toEditorState(text);
|
||||
}
|
||||
private mentionEle: any;
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@ -102,6 +103,12 @@ export default class Mention extends React.Component<MentionProps, MentionState>
|
||||
this.props.onBlur(ev);
|
||||
}
|
||||
}
|
||||
focus = () => {
|
||||
this.mentionEle._editor.focus();
|
||||
}
|
||||
mentionRef = ele => {
|
||||
this.mentionEle = ele;
|
||||
}
|
||||
render() {
|
||||
const { className = '', prefixCls, loading } = this.props;
|
||||
const { suggestions, focus } = this.state;
|
||||
@ -117,6 +124,7 @@ export default class Mention extends React.Component<MentionProps, MentionState>
|
||||
<RcMention
|
||||
{...this.props}
|
||||
className={cls}
|
||||
ref={this.mentionRef}
|
||||
onSearchChange={this.onSearchChange}
|
||||
onChange={this.onChange}
|
||||
onFocus={this.onFocus}
|
||||
|
@ -51,6 +51,12 @@ title: Mention
|
||||
| readOnly | 是否只读. | boolean | false |
|
||||
| disabled | 是否禁用状态. | boolean | false |
|
||||
|
||||
### Mention methods
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
|----------|---------------|----------|--------------|
|
||||
| focus | 强制获得焦点. | - | - |
|
||||
|
||||
### Nav
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|
22
components/menu/MenuItem.tsx
Normal file
22
components/menu/MenuItem.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import { Item } from 'rc-menu';
|
||||
import PropTypes from 'prop-types';
|
||||
import Tooltip from '../tooltip';
|
||||
|
||||
const MenuItem: any = (props, { inlineCollapsed }) => {
|
||||
return (
|
||||
<Tooltip
|
||||
title={inlineCollapsed && props.level === 1 ? props.children : ''}
|
||||
placement="right"
|
||||
overlayClassName={`${props.rootPrefixCls}-inline-collapsed-tooltip`}
|
||||
>
|
||||
<Item {...props} />
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
MenuItem.contextTypes = {
|
||||
inlineCollapsed: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default MenuItem;
|
@ -3,7 +3,7 @@
|
||||
exports[`renders ./components/menu/demo/horizontal.md correctly 1`] = `
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-horizontal ant-menu-light ant-menu-root"
|
||||
class="ant-menu ant-menu-horizontal ant-menu-light ant-menu-root"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
>
|
||||
@ -61,16 +61,16 @@ exports[`renders ./components/menu/demo/horizontal.md correctly 1`] = `
|
||||
</ul>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/menu/demo/sider.md correctly 1`] = `
|
||||
exports[`renders ./components/menu/demo/inline.md correctly 1`] = `
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
role="menu"
|
||||
style="width:240px;"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu-selected ant-menu-submenu"
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu"
|
||||
>
|
||||
<div
|
||||
aria-expanded="true"
|
||||
@ -197,16 +197,157 @@ exports[`renders ./components/menu/demo/sider.md correctly 1`] = `
|
||||
</ul>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/menu/demo/inline-collapsed.md correctly 1`] = `
|
||||
<div
|
||||
style="width:240px;"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
style="margin-bottom:16px;"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
class="anticon anticon-menu-fold"
|
||||
/>
|
||||
</button>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
aria-selected="true"
|
||||
class="ant-menu-item-selected ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:24px;"
|
||||
>
|
||||
<i
|
||||
class="anticon anticon-pie-chart"
|
||||
/>
|
||||
<span>
|
||||
Option 1
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
aria-selected="false"
|
||||
class="ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:24px;"
|
||||
>
|
||||
<i
|
||||
class="anticon anticon-desktop"
|
||||
/>
|
||||
<span>
|
||||
Option 2
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
aria-selected="false"
|
||||
class="ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:24px;"
|
||||
>
|
||||
<i
|
||||
class="anticon anticon-inbox"
|
||||
/>
|
||||
<span>
|
||||
Option 3
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu"
|
||||
>
|
||||
<div
|
||||
aria-expanded="true"
|
||||
aria-haspopup="true"
|
||||
aria-owns="sub1$Menu"
|
||||
class="ant-menu-submenu-title"
|
||||
style="padding-left:24px;"
|
||||
>
|
||||
<span>
|
||||
<i
|
||||
class="anticon anticon-mail"
|
||||
/>
|
||||
<span>
|
||||
Navigation One
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-sub"
|
||||
id="sub1$Menu"
|
||||
role="menu"
|
||||
>
|
||||
<li
|
||||
aria-selected="false"
|
||||
class="ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:48px;"
|
||||
>
|
||||
Option 5
|
||||
</li>
|
||||
<li
|
||||
aria-selected="false"
|
||||
class="ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:48px;"
|
||||
>
|
||||
Option 6
|
||||
</li>
|
||||
<li
|
||||
aria-selected="false"
|
||||
class="ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:48px;"
|
||||
>
|
||||
Option 7
|
||||
</li>
|
||||
<li
|
||||
aria-selected="false"
|
||||
class="ant-menu-item"
|
||||
role="menuitem"
|
||||
style="padding-left:48px;"
|
||||
>
|
||||
Option 8
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li
|
||||
class="ant-menu-submenu-inline ant-menu-submenu"
|
||||
>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-owns="sub2$Menu"
|
||||
class="ant-menu-submenu-title"
|
||||
style="padding-left:24px;"
|
||||
>
|
||||
<span>
|
||||
<i
|
||||
class="anticon anticon-appstore"
|
||||
/>
|
||||
<span>
|
||||
Navigation Two
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/menu/demo/sider-current.md correctly 1`] = `
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
role="menu"
|
||||
style="width:240px;"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-selected ant-menu-submenu"
|
||||
class="ant-menu-submenu-inline ant-menu-submenu"
|
||||
>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
@ -296,7 +437,7 @@ exports[`renders ./components/menu/demo/switch-mode.md correctly 1`] = `
|
||||
<br />
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"
|
||||
role="menu"
|
||||
style="width:240px;"
|
||||
tabindex="0"
|
||||
@ -420,13 +561,13 @@ exports[`renders ./components/menu/demo/theme.md correctly 1`] = `
|
||||
<br />
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
class="ant-menu ant-menu-inline ant-menu-dark ant-menu-root"
|
||||
role="menu"
|
||||
style="width:240px;"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu-selected ant-menu-submenu"
|
||||
class="ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu"
|
||||
>
|
||||
<div
|
||||
aria-expanded="true"
|
||||
@ -531,7 +672,7 @@ exports[`renders ./components/menu/demo/theme.md correctly 1`] = `
|
||||
exports[`renders ./components/menu/demo/vertical.md correctly 1`] = `
|
||||
<ul
|
||||
aria-activedescendant=""
|
||||
class="ant-menu ant-menu-vertical ant-menu-light ant-menu-root"
|
||||
class="ant-menu ant-menu-vertical ant-menu-light ant-menu-root"
|
||||
role="menu"
|
||||
style="width:240px;"
|
||||
tabindex="0"
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Menu from '..';
|
||||
import Icon from '../../icon';
|
||||
|
||||
const SubMenu = Menu.SubMenu;
|
||||
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout));
|
||||
@ -129,6 +130,33 @@ describe('Menu', () => {
|
||||
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
|
||||
});
|
||||
|
||||
it('should always follow openKeys when mode is switched', () => {
|
||||
const wrapper = mount(
|
||||
<Menu defaultOpenKeys={['1']} mode="inline">
|
||||
<Menu.Item key="menu1">
|
||||
<Icon type="inbox" />
|
||||
<span>Option</span>
|
||||
</Menu.Item>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">
|
||||
Option
|
||||
</Menu.Item>
|
||||
<Menu.Item key="submenu2">
|
||||
Option
|
||||
</Menu.Item>
|
||||
</SubMenu>
|
||||
</Menu>
|
||||
);
|
||||
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-inline')).toBe(true);
|
||||
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false);
|
||||
wrapper.setProps({ inlineCollapsed: true });
|
||||
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-vertical')).toBe(true);
|
||||
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(true);
|
||||
wrapper.setProps({ inlineCollapsed: false });
|
||||
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-inline')).toBe(true);
|
||||
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false);
|
||||
});
|
||||
|
||||
it('should open submenu when click submenu title (inline)', async () => {
|
||||
const wrapper = mount(
|
||||
<Menu mode="inline">
|
||||
|
75
components/menu/demo/inline-collapsed.md
Normal file
75
components/menu/demo/inline-collapsed.md
Normal file
@ -0,0 +1,75 @@
|
||||
---
|
||||
order: 2
|
||||
title:
|
||||
zh-CN: 缩起内嵌菜单
|
||||
en-US: Collapsed inline menu
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
内嵌菜单可以被缩起/展开。
|
||||
|
||||
## en-US
|
||||
|
||||
Inline menu could be collapsed.
|
||||
|
||||
````jsx
|
||||
import { Menu, Icon, Button } from 'antd';
|
||||
const SubMenu = Menu.SubMenu;
|
||||
|
||||
class App extends React.Component {
|
||||
state = {
|
||||
collapsed: false,
|
||||
}
|
||||
toggleCollapsed = () => {
|
||||
this.setState({
|
||||
collapsed: !this.state.collapsed,
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div style={{ width: 240 }}>
|
||||
<Button type="primary" onClick={this.toggleCollapsed} style={{ marginBottom: 16 }}>
|
||||
<Icon type={this.state.collapsed ? 'menu-unfold' : 'menu-fold'} />
|
||||
</Button>
|
||||
<Menu
|
||||
defaultSelectedKeys={['1']}
|
||||
defaultOpenKeys={['sub1']}
|
||||
mode="inline"
|
||||
theme="dark"
|
||||
inlineCollapsed={this.state.collapsed}
|
||||
>
|
||||
<Menu.Item key="1">
|
||||
<Icon type="pie-chart" />
|
||||
<span>Option 1</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="2">
|
||||
<Icon type="desktop" />
|
||||
<span>Option 2</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="3">
|
||||
<Icon type="inbox" />
|
||||
<span>Option 3</span>
|
||||
</Menu.Item>
|
||||
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>Navigation One</span></span>}>
|
||||
<Menu.Item key="5">Option 5</Menu.Item>
|
||||
<Menu.Item key="6">Option 6</Menu.Item>
|
||||
<Menu.Item key="7">Option 7</Menu.Item>
|
||||
<Menu.Item key="8">Option 8</Menu.Item>
|
||||
</SubMenu>
|
||||
<SubMenu key="sub2" title={<span><Icon type="appstore" /><span>Navigation Two</span></span>}>
|
||||
<Menu.Item key="9">Option 9</Menu.Item>
|
||||
<Menu.Item key="10">Option 10</Menu.Item>
|
||||
<SubMenu key="sub3" title="Submenu">
|
||||
<Menu.Item key="11">Option 11</Menu.Item>
|
||||
<Menu.Item key="12">Option 12</Menu.Item>
|
||||
</SubMenu>
|
||||
</SubMenu>
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, mountNode);
|
||||
````
|
@ -2,7 +2,7 @@
|
||||
order: 1
|
||||
title:
|
||||
zh-CN: 内嵌菜单
|
||||
en-US: Vertical menu with inline children
|
||||
en-US: Inline menu
|
||||
---
|
||||
|
||||
## zh-CN
|
@ -42,6 +42,7 @@ More layouts with navigation: [layout](/components/layout).
|
||||
| style | style of the root node | object | |
|
||||
| inlineIndent | indent px of inline menu item on each level | number | 24 |
|
||||
| multiple | Allow select multiple item | boolean | false |
|
||||
| inlineCollapsed | specified the collapsed status when menu is inline mode | boolean | - |
|
||||
|
||||
> More options in [rc-menu](https://github.com/react-component/menu#api)
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React from 'react';
|
||||
import RcMenu, { Item, Divider, SubMenu, ItemGroup } from 'rc-menu';
|
||||
import RcMenu, { Divider, SubMenu, ItemGroup } from 'rc-menu';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import animation from '../_util/openAnimation';
|
||||
import warning from '../_util/warning';
|
||||
import Item from './MenuItem';
|
||||
|
||||
export interface SelectParam {
|
||||
key: string;
|
||||
@ -39,6 +42,7 @@ export interface MenuProps {
|
||||
prefixCls?: string;
|
||||
multiple?: boolean;
|
||||
inlineIndent?: number;
|
||||
inlineCollapsed?: boolean;
|
||||
}
|
||||
|
||||
export default class Menu extends React.Component<MenuProps, any> {
|
||||
@ -51,7 +55,14 @@ export default class Menu extends React.Component<MenuProps, any> {
|
||||
className: '',
|
||||
theme: 'light', // or dark
|
||||
};
|
||||
static childContextTypes = {
|
||||
inlineCollapsed: PropTypes.bool,
|
||||
};
|
||||
static contextTypes = {
|
||||
siderCollapsed: PropTypes.bool,
|
||||
};
|
||||
switchModeFromInline: boolean;
|
||||
inlineOpenKeys = [];
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@ -61,6 +72,11 @@ export default class Menu extends React.Component<MenuProps, any> {
|
||||
'see: http://u.ant.design/menu-on-open-change.',
|
||||
);
|
||||
|
||||
warning(
|
||||
!('inlineCollapsed' in props && props.mode !== 'inline'),
|
||||
'`inlineCollapsed` should only be used when Menu\'s `mode` is inline.',
|
||||
);
|
||||
|
||||
let openKeys;
|
||||
if ('defaultOpenKeys' in props) {
|
||||
openKeys = props.defaultOpenKeys;
|
||||
@ -72,11 +88,27 @@ export default class Menu extends React.Component<MenuProps, any> {
|
||||
openKeys: openKeys || [],
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
getChildContext() {
|
||||
return {
|
||||
inlineCollapsed: this.getInlineCollapsed(),
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps, nextContext) {
|
||||
if (this.props.mode === 'inline' &&
|
||||
nextProps.mode !== 'inline') {
|
||||
this.switchModeFromInline = true;
|
||||
}
|
||||
if ((nextProps.inlineCollapsed && !this.props.inlineCollapsed) ||
|
||||
(nextContext.siderCollapsed && !this.context.siderCollapsed)) {
|
||||
this.switchModeFromInline = true;
|
||||
this.inlineOpenKeys = this.state.openKeys;
|
||||
this.setOpenKeys([]);
|
||||
}
|
||||
if ((!nextProps.inlineCollapsed && this.props.inlineCollapsed) ||
|
||||
(!nextContext.siderCollapsed && this.context.siderCollapsed)) {
|
||||
this.setOpenKeys(this.inlineOpenKeys);
|
||||
this.inlineOpenKeys = [];
|
||||
}
|
||||
if ('openKeys' in nextProps) {
|
||||
this.setState({ openKeys: nextProps.openKeys });
|
||||
}
|
||||
@ -102,48 +134,68 @@ export default class Menu extends React.Component<MenuProps, any> {
|
||||
this.setState({ openKeys });
|
||||
}
|
||||
}
|
||||
render() {
|
||||
let openAnimation = this.props.openAnimation || this.props.openTransitionName;
|
||||
if (this.props.openAnimation === undefined && this.props.openTransitionName === undefined) {
|
||||
switch (this.props.mode) {
|
||||
getRealMenuMode() {
|
||||
const { mode } = this.props;
|
||||
return this.getInlineCollapsed() ? 'vertical' : mode;
|
||||
}
|
||||
getInlineCollapsed() {
|
||||
const { inlineCollapsed } = this.props;
|
||||
if (this.context.siderCollapsed !== undefined) {
|
||||
return this.context.siderCollapsed;
|
||||
}
|
||||
return inlineCollapsed;
|
||||
}
|
||||
getMenuOpenAnimation() {
|
||||
const { openAnimation, openTransitionName } = this.props;
|
||||
const menuMode = this.getRealMenuMode();
|
||||
let menuOpenAnimation = openAnimation || openTransitionName;
|
||||
if (openAnimation === undefined && openTransitionName === undefined) {
|
||||
switch (menuMode) {
|
||||
case 'horizontal':
|
||||
openAnimation = 'slide-up';
|
||||
menuOpenAnimation = 'slide-up';
|
||||
break;
|
||||
case 'vertical':
|
||||
// When mode switch from inline
|
||||
// submenu should hide without animation
|
||||
if (this.switchModeFromInline) {
|
||||
openAnimation = '';
|
||||
menuOpenAnimation = '';
|
||||
this.switchModeFromInline = false;
|
||||
} else {
|
||||
openAnimation = 'zoom-big';
|
||||
menuOpenAnimation = 'zoom-big';
|
||||
}
|
||||
break;
|
||||
case 'inline':
|
||||
openAnimation = animation;
|
||||
menuOpenAnimation = animation;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
return menuOpenAnimation;
|
||||
}
|
||||
render() {
|
||||
const { prefixCls, className, theme } = this.props;
|
||||
const menuMode = this.getRealMenuMode();
|
||||
const menuOpenAnimation = this.getMenuOpenAnimation();
|
||||
|
||||
let props = {};
|
||||
const className = `${this.props.className} ${this.props.prefixCls}-${this.props.theme}`;
|
||||
if (this.props.mode !== 'inline') {
|
||||
// There is this.state.openKeys for
|
||||
const menuClassName = classNames(className, `${prefixCls}-${theme}`, {
|
||||
[`${prefixCls}-inline-collapsed`]: this.getInlineCollapsed(),
|
||||
});
|
||||
|
||||
const menuProps: MenuProps = {
|
||||
openKeys: this.state.openKeys,
|
||||
onOpenChange: this.handleOpenChange,
|
||||
className: menuClassName,
|
||||
mode: menuMode,
|
||||
};
|
||||
|
||||
if (menuMode !== 'inline') {
|
||||
// closing vertical popup submenu after click it
|
||||
props = {
|
||||
openKeys: this.state.openKeys,
|
||||
onClick: this.handleClick,
|
||||
onOpenChange: this.handleOpenChange,
|
||||
openTransitionName: openAnimation,
|
||||
className,
|
||||
};
|
||||
menuProps.onClick = this.handleClick;
|
||||
menuProps.openTransitionName = menuOpenAnimation;
|
||||
} else {
|
||||
props = {
|
||||
openAnimation,
|
||||
className,
|
||||
};
|
||||
menuProps.openAnimation = menuOpenAnimation;
|
||||
}
|
||||
return <RcMenu {...this.props} {...props} />;
|
||||
|
||||
return <RcMenu {...this.props} {...menuProps} />;
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ subtitle: 导航菜单
|
||||
| style | 根节点样式 | object | |
|
||||
| inlineIndent | inline 模式的菜单缩进宽度 | number | 24 |
|
||||
| multiple | 是否允许多选 | boolean | false |
|
||||
| inlineCollapsed | inline 时菜单是否收起状态 | boolean | - |
|
||||
|
||||
> More options in [rc-menu](https://github.com/react-component/menu#api)
|
||||
|
||||
|
@ -158,6 +158,8 @@
|
||||
}
|
||||
|
||||
&-inline {
|
||||
width: 100%;
|
||||
transition: width .24s;
|
||||
.@{menu-prefix-cls}-selected,
|
||||
.@{menu-prefix-cls}-item-selected {
|
||||
&:after {
|
||||
@ -166,6 +168,37 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-inline-collapsed {
|
||||
width: 64px;
|
||||
transition: all .3s;
|
||||
> .@{menu-prefix-cls}-item,
|
||||
> .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
|
||||
text-align: center;
|
||||
left: 0;
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.@{menu-prefix-cls}-item,
|
||||
.@{menu-prefix-cls}-submenu-title {
|
||||
padding: 0;
|
||||
.@{iconfont-css-prefix} {
|
||||
font-size: 16px;
|
||||
line-height: 42px;
|
||||
margin: 0;
|
||||
+ span {
|
||||
max-width: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-tooltip {
|
||||
.@{iconfont-css-prefix} {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-submenu-horizontal > & {
|
||||
top: 100%;
|
||||
left: 0;
|
||||
@ -199,6 +232,15 @@
|
||||
.@{iconfont-css-prefix} {
|
||||
min-width: 14px;
|
||||
margin-right: 8px;
|
||||
transition: all .3s;
|
||||
vertical-align: middle;
|
||||
+ span {
|
||||
max-width: 100%;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
transition: all .3s;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,2 +1,5 @@
|
||||
import '../../style/index.less';
|
||||
import './index.less';
|
||||
|
||||
// style dependencies
|
||||
import '../../tooltip/style';
|
||||
|
@ -25,6 +25,7 @@ export interface PaginationProps {
|
||||
className?: string;
|
||||
prefixCls?: string;
|
||||
selectPrefixCls?: string;
|
||||
itemRender?: (page: number, type: 'page' | 'prev' | 'next' | 'jump-prev' | 'jump-next') => React.ReactNode;
|
||||
}
|
||||
|
||||
abstract class Pagination extends React.Component<PaginationProps, any> {
|
||||
|
@ -33,3 +33,4 @@ showQuickJumper | determine whether you can jump to a page directly | boolean |
|
||||
size | specify the size of `Pagination`, can be set to `small` | string | ""
|
||||
simple | whether to use simple mode | boolean | -
|
||||
showTotal | to display the total number and range | Function(total, range) | -
|
||||
itemRender | to customize item innerHTML | (page, type: 'page' | 'prev' | 'next') => React.ReactNode | - |
|
||||
|
@ -34,3 +34,4 @@ cols: 1
|
||||
| size | 当为「small」时,是小尺寸分页 | string | "" |
|
||||
| simple | 当添加该属性时,显示为简单分页 | boolean | - |
|
||||
| showTotal | 用于显示数据总量和当前数据顺序 | Function(total, range) | - |
|
||||
| itemRender | 用于自定义页码的结构,可用于优化 SEO | (page, type: 'page' | 'prev' | 'next') => React.ReactNode | - |
|
||||
|
5
components/time-picker/locale/th_TH.tsx
Normal file
5
components/time-picker/locale/th_TH.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
const locale = {
|
||||
placeholder: 'เลือกเวลา',
|
||||
};
|
||||
|
||||
export default locale;
|
44
components/tooltip/demo/auto-adjust-overflow.md
Normal file
44
components/tooltip/demo/auto-adjust-overflow.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
order: 3
|
||||
title:
|
||||
zh-CN: 自动调整位置
|
||||
en-US: Adjust placement automatically
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
气泡框不可见时自动调整位置
|
||||
|
||||
## en-US
|
||||
|
||||
Adjust popup placement automatically when popup is invisible
|
||||
|
||||
````jsx
|
||||
import { Tooltip, Button } from 'antd';
|
||||
|
||||
const wrapStyles = {
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
padding: '24px',
|
||||
border: '1px solid #e9e9e9',
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<div style={wrapStyles}>
|
||||
<Tooltip placement="left" title="Prompt Text" getPopupContainer={trigger => trigger.parentElement}>
|
||||
<Button>Adjust automatically / 自动调整</Button>
|
||||
</Tooltip>
|
||||
<br />
|
||||
<Tooltip placement="left" title="Prompt Text" getPopupContainer={trigger => trigger.parentElement} autoAdjustOverflow={false}>
|
||||
<Button>Ingore / 不处理</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-btn {
|
||||
margin-right: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
</style>
|
@ -26,6 +26,7 @@ The following APIs are shared by Tooltip, Popconfirm, Popover.
|
||||
| placement | to set the position, which can be one of `top` `left` `right` `bottom` `topLeft` `topRight` `bottomLeft` `bottomRight` `leftTop` `leftBottom` `rightTop` `rightBottom` | string | top |
|
||||
| getPopupContainer | to set the container of the tip, while the default is to create a `div` element in `body`. Use `getTooltipContainer` if you are using `antd@<2.5.2` | Function(triggerNode) | () => document.body |
|
||||
| arrowPointAtCenter | whether arrow pointed at the center of target, supported after `antd@1.11+` | boolean | `false` |
|
||||
| autoAdjustOverflow | whether adjust popup placement automatically when popup is invisible | boolean | `true` |
|
||||
| visible | make the float card visible or not | boolean | false |
|
||||
| onVisibleChange | callback of the visible attribute changed | (visible) => void | none |
|
||||
| mouseEnterDelay | delay time to show when mouse enter.unit: s | number | 0 |
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { cloneElement } from 'react';
|
||||
import RcTooltip from 'rc-tooltip';
|
||||
import classNames from 'classnames';
|
||||
import getPlacements from './placements';
|
||||
import getPlacements, { AdjustOverflow } from './placements';
|
||||
|
||||
export type TooltipPlacement =
|
||||
'top' | 'left' | 'right' | 'bottom' |
|
||||
@ -24,6 +24,7 @@ export interface AbstractTooltipProps {
|
||||
trigger?: 'hover' | 'focus' | 'click';
|
||||
openClassName?: string;
|
||||
arrowPointAtCenter?: boolean;
|
||||
autoAdjustOverflow?: boolean | AdjustOverflow;
|
||||
// getTooltipContainer had been rename to getPopupContainer
|
||||
getTooltipContainer?: (triggerNode: Element) => HTMLElement;
|
||||
getPopupContainer?: (triggerNode: Element) => HTMLElement;
|
||||
@ -55,6 +56,7 @@ export default class Tooltip extends React.Component<TooltipProps, any> {
|
||||
mouseEnterDelay: 0.1,
|
||||
mouseLeaveDelay: 0.1,
|
||||
arrowPointAtCenter: false,
|
||||
autoAdjustOverflow: true,
|
||||
};
|
||||
|
||||
refs: {
|
||||
@ -90,10 +92,11 @@ export default class Tooltip extends React.Component<TooltipProps, any> {
|
||||
}
|
||||
|
||||
getPlacements() {
|
||||
const { builtinPlacements, arrowPointAtCenter } = this.props;
|
||||
const { builtinPlacements, arrowPointAtCenter, autoAdjustOverflow } = this.props;
|
||||
return builtinPlacements || getPlacements({
|
||||
arrowPointAtCenter,
|
||||
verticalArrowShift: 8,
|
||||
autoAdjustOverflow,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ title: Tooltip
|
||||
| placement | 气泡框位置,可选 `top` `left` `right` `bottom` `topLeft` `topRight` `bottomLeft` `bottomRight` `leftTop` `leftBottom` `rightTop` `rightBottom` | string | top |
|
||||
| getPopupContainer | 浮层渲染父节点,默认渲染到 body 上。`2.5.2` 之前请使用 `getTooltipContainer` | Function(triggerNode) | () => document.body |
|
||||
| arrowPointAtCenter | 箭头是否指向目标元素中心,`antd@1.11+` 支持 | boolean | `false` |
|
||||
| autoAdjustOverflow | 气泡被遮挡时自动调整位置 | boolean | `true` |
|
||||
| visible | 用于手动控制浮层显隐 | boolean | false |
|
||||
| onVisibleChange | 显示隐藏的回调 | (visible) => void | 无 |
|
||||
| mouseEnterDelay | 鼠标移入后延时多少才显示 Tooltip,单位:秒 | number | 0 |
|
||||
|
@ -1,96 +1,99 @@
|
||||
import { placements } from 'rc-tooltip/lib/placements';
|
||||
import { placements as rcPlacements } from 'rc-tooltip/lib/placements';
|
||||
|
||||
const autoAdjustOverflow = {
|
||||
const autoAdjustOverflowEnabled = {
|
||||
adjustX: 1,
|
||||
adjustY: 1,
|
||||
};
|
||||
|
||||
const autoAdjustOverflowDisabled = {
|
||||
adjustX: 0,
|
||||
adjustY: 0,
|
||||
};
|
||||
|
||||
const targetOffset = [0, 0];
|
||||
|
||||
export interface AdjustOverflow {
|
||||
adjustX?: 0 | 1;
|
||||
adjustY?: 0 | 1;
|
||||
}
|
||||
|
||||
export interface PlacementsConfig {
|
||||
arrowWidth?: number;
|
||||
horizontalArrowShift?: number;
|
||||
verticalArrowShift?: number;
|
||||
arrowPointAtCenter?: boolean;
|
||||
autoAdjustOverflow?: any;
|
||||
}
|
||||
|
||||
export function getOverflowOptions(autoAdjustOverflow: any) {
|
||||
if (typeof autoAdjustOverflow === 'boolean') {
|
||||
return autoAdjustOverflow ? autoAdjustOverflowEnabled : autoAdjustOverflowDisabled;
|
||||
}
|
||||
return {
|
||||
...autoAdjustOverflowDisabled,
|
||||
...autoAdjustOverflow,
|
||||
};
|
||||
}
|
||||
|
||||
export default function getPlacements(config: PlacementsConfig = {}) {
|
||||
if (!config.arrowPointAtCenter) {
|
||||
return placements;
|
||||
}
|
||||
const { arrowWidth = 5, horizontalArrowShift = 16, verticalArrowShift = 12 } = config;
|
||||
return {
|
||||
const { arrowWidth = 5, horizontalArrowShift = 16, verticalArrowShift = 12, autoAdjustOverflow = true } = config;
|
||||
const placementMap = {
|
||||
left: {
|
||||
points: ['cr', 'cl'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [-4, 0],
|
||||
targetOffset,
|
||||
},
|
||||
right: {
|
||||
points: ['cl', 'cr'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [4, 0],
|
||||
targetOffset,
|
||||
},
|
||||
top: {
|
||||
points: ['bc', 'tc'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [0, -4],
|
||||
targetOffset,
|
||||
},
|
||||
bottom: {
|
||||
points: ['tc', 'bc'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [0, 4],
|
||||
targetOffset,
|
||||
},
|
||||
topLeft: {
|
||||
points: ['bl', 'tc'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [-(horizontalArrowShift + arrowWidth), -4],
|
||||
targetOffset,
|
||||
},
|
||||
leftTop: {
|
||||
points: ['tr', 'cl'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [-4, -(verticalArrowShift + arrowWidth)],
|
||||
targetOffset,
|
||||
},
|
||||
topRight: {
|
||||
points: ['br', 'tc'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [horizontalArrowShift + arrowWidth, -4],
|
||||
targetOffset,
|
||||
},
|
||||
rightTop: {
|
||||
points: ['tl', 'cr'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [4, -(verticalArrowShift + arrowWidth)],
|
||||
targetOffset,
|
||||
},
|
||||
bottomRight: {
|
||||
points: ['tr', 'bc'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [horizontalArrowShift + arrowWidth, 4],
|
||||
targetOffset,
|
||||
},
|
||||
rightBottom: {
|
||||
points: ['bl', 'cr'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [4, verticalArrowShift + arrowWidth],
|
||||
targetOffset,
|
||||
},
|
||||
bottomLeft: {
|
||||
points: ['tl', 'bc'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [-(horizontalArrowShift + arrowWidth), 4],
|
||||
targetOffset,
|
||||
},
|
||||
leftBottom: {
|
||||
points: ['br', 'cl'],
|
||||
overflow: autoAdjustOverflow,
|
||||
offset: [-4, verticalArrowShift + arrowWidth],
|
||||
targetOffset,
|
||||
},
|
||||
};
|
||||
Object.keys(placementMap).forEach(key => {
|
||||
placementMap[key] = {
|
||||
...placementMap[key],
|
||||
overflow: getOverflowOptions(autoAdjustOverflow),
|
||||
offset: (config.arrowPointAtCenter ? rcPlacements[key] : placementMap[key]).offset,
|
||||
targetOffset,
|
||||
};
|
||||
});
|
||||
return placementMap;
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ exports[`Search should show cross icon when input value exists 1`] = `
|
||||
>
|
||||
<div>
|
||||
<Input
|
||||
autosize={false}
|
||||
disabled={false}
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
@ -47,7 +46,6 @@ exports[`Search should show cross icon when input value exists 2`] = `
|
||||
>
|
||||
<div>
|
||||
<Input
|
||||
autosize={false}
|
||||
disabled={false}
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
|
@ -51,6 +51,7 @@ Supported languages:
|
||||
|Swedish|sv_SE|
|
||||
|Turkish|tr_TR|
|
||||
|Vietnamese|vi_VN|
|
||||
|Thai|th_TH|
|
||||
|
||||
See usage and contributing way of a new locale package at [LocaleProvider](/components/locale-provider).
|
||||
|
||||
|
@ -49,6 +49,7 @@ return (
|
||||
|瑞典语|sv_SE|
|
||||
|土耳其语|tr_TR|
|
||||
|越南语|vi_VN|
|
||||
|泰国语言|th_TH|
|
||||
|
||||
具体的使用方法和新语言包贡献方式请参考 [LocaleProvider 文档](/components/locale-provider)。
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "2.11.2",
|
||||
"version": "2.12.0-beta1",
|
||||
"title": "Ant Design",
|
||||
"description": "An enterprise-class UI design language and React-based implementation",
|
||||
"homepage": "http://ant.design/",
|
||||
@ -57,14 +57,14 @@
|
||||
"rc-input-number": "~3.6.0",
|
||||
"rc-menu": "~5.0.10",
|
||||
"rc-notification": "~2.0.0",
|
||||
"rc-pagination": "~1.9.4",
|
||||
"rc-pagination": "~1.10.0",
|
||||
"rc-progress": "~2.1.2",
|
||||
"rc-rate": "~2.1.1",
|
||||
"rc-select": "~6.8.6",
|
||||
"rc-slider": "~8.2.0",
|
||||
"rc-steps": "~2.5.1",
|
||||
"rc-switch": "~1.5.1",
|
||||
"rc-table": "~5.3.3",
|
||||
"rc-table": "~5.4.0",
|
||||
"rc-tabs": "~8.0.0",
|
||||
"rc-time-picker": "~2.4.1",
|
||||
"rc-tooltip": "~3.4.6",
|
||||
|
Loading…
Reference in New Issue
Block a user