初始化 antd-pro

This commit is contained in:
sin
2019-02-27 11:06:55 +08:00
parent 9f4fdb7f6e
commit b2068ae44b
458 changed files with 28090 additions and 2 deletions

View File

@@ -0,0 +1,31 @@
---
order: 1
title:
zh-CN: 按照行数省略
en-US: Truncate according to the number of rows
---
## zh-CN
通过设置 `lines` 属性指定最大行数,如果超过这个行数的文本会自动截取。但是在这种模式下所有 `children` 将会被转换成纯文本。
并且注意在这种模式下,外容器需要有指定的宽度(或设置自身宽度)。
## en-US
`lines` attribute specifies the maximum number of rows where the text will automatically be truncated when exceeded. In this mode, all children will be converted to plain text.
Also note that, in this mode, the outer container needs to have a specified width (or set its own width).
````jsx
import Ellipsis from 'ant-design-pro/lib/Ellipsis';
const article = <p>There were injuries alleged in three <a href="#cover">cases in 2015</a>, and a fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.</p>;
ReactDOM.render(
<div style={{ width: 200 }}>
<Ellipsis tooltip lines={3}>{article}</Ellipsis>
</div>
, mountNode);
````

View File

@@ -0,0 +1,28 @@
---
order: 0
title:
zh-CN: 按照字符数省略
en-US: Truncate according to the number of character
---
## zh-CN
通过设置 `length` 属性指定文本最长长度,如果超过这个长度会自动截取。
## en-US
`length` attribute specifies the maximum length where the text will automatically be truncated when exceeded.
````jsx
import Ellipsis from 'ant-design-pro/lib/Ellipsis';
const article = 'There were injuries alleged in three cases in 2015, and a fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.';
ReactDOM.render(
<div>
<Ellipsis length={100}>{article}</Ellipsis>
<h4 style={{ marginTop: 24 }}>Show Tooltip</h4>
<Ellipsis length={100} tooltip>{article}</Ellipsis>
</div>
, mountNode);
````

View File

@@ -0,0 +1,21 @@
import * as React from 'react';
import { TooltipProps } from 'antd/lib/tooltip';
export interface IEllipsisTooltipProps extends TooltipProps {
title?: undefined;
overlayStyle?: undefined;
}
export interface IEllipsisProps {
tooltip?: boolean | IEllipsisTooltipProps;
length?: number;
lines?: number;
style?: React.CSSProperties;
className?: string;
fullWidthRecognition?: boolean;
}
export function getStrFullLength(str: string): number;
export function cutStrByFullLength(str: string, maxLength: number): string;
export default class Ellipsis extends React.Component<IEllipsisProps, any> {}

View File

@@ -0,0 +1,16 @@
---
title: Ellipsis
cols: 1
order: 10
---
When the text is too long, the Ellipsis automatically shortens it according to its length or the maximum number of lines.
## API
Property | Description | Type | Default
----|------|-----|------
tooltip | tooltip for showing the full text content when hovering over | boolean | -
length | maximum number of characters in the text before being truncated | number | -
lines | maximum number of rows in the text before being truncated | number | `1`
fullWidthRecognition | whether consider full-width character length as 2 when calculate string length | boolean | -

View File

@@ -0,0 +1,270 @@
import React, { Component } from 'react';
import { Tooltip } from 'antd';
import classNames from 'classnames';
import styles from './index.less';
/* eslint react/no-did-mount-set-state: 0 */
/* eslint no-param-reassign: 0 */
const isSupportLineClamp = document.body.style.webkitLineClamp !== undefined;
const TooltipOverlayStyle = {
overflowWrap: 'break-word',
wordWrap: 'break-word',
};
export const getStrFullLength = (str = '') =>
str.split('').reduce((pre, cur) => {
const charCode = cur.charCodeAt(0);
if (charCode >= 0 && charCode <= 128) {
return pre + 1;
}
return pre + 2;
}, 0);
export const cutStrByFullLength = (str = '', maxLength) => {
let showLength = 0;
return str.split('').reduce((pre, cur) => {
const charCode = cur.charCodeAt(0);
if (charCode >= 0 && charCode <= 128) {
showLength += 1;
} else {
showLength += 2;
}
if (showLength <= maxLength) {
return pre + cur;
}
return pre;
}, '');
};
const getTooltip = ({ tooltip, overlayStyle, title, children }) => {
if (tooltip) {
const props = tooltip === true ? { overlayStyle, title } : { ...tooltip, overlayStyle, title };
return <Tooltip {...props}>{children}</Tooltip>;
}
return children;
};
const EllipsisText = ({ text, length, tooltip, fullWidthRecognition, ...other }) => {
if (typeof text !== 'string') {
throw new Error('Ellipsis children must be string.');
}
const textLength = fullWidthRecognition ? getStrFullLength(text) : text.length;
if (textLength <= length || length < 0) {
return <span {...other}>{text}</span>;
}
const tail = '...';
let displayText;
if (length - tail.length <= 0) {
displayText = '';
} else {
displayText = fullWidthRecognition ? cutStrByFullLength(text, length) : text.slice(0, length);
}
const spanAttrs = tooltip ? {} : { ...other };
return getTooltip({
tooltip,
overlayStyle: TooltipOverlayStyle,
title: text,
children: (
<span {...spanAttrs}>
{displayText}
{tail}
</span>
),
});
};
export default class Ellipsis extends Component {
state = {
text: '',
targetCount: 0,
};
componentDidMount() {
if (this.node) {
this.computeLine();
}
}
componentDidUpdate(perProps) {
const { lines } = this.props;
if (lines !== perProps.lines) {
this.computeLine();
}
}
computeLine = () => {
const { lines } = this.props;
if (lines && !isSupportLineClamp) {
const text = this.shadowChildren.innerText || this.shadowChildren.textContent;
const lineHeight = parseInt(getComputedStyle(this.root).lineHeight, 10);
const targetHeight = lines * lineHeight;
this.content.style.height = `${targetHeight}px`;
const totalHeight = this.shadowChildren.offsetHeight;
const shadowNode = this.shadow.firstChild;
if (totalHeight <= targetHeight) {
this.setState({
text,
targetCount: text.length,
});
return;
}
// bisection
const len = text.length;
const mid = Math.ceil(len / 2);
const count = this.bisection(targetHeight, mid, 0, len, text, shadowNode);
this.setState({
text,
targetCount: count,
});
}
};
bisection = (th, m, b, e, text, shadowNode) => {
const suffix = '...';
let mid = m;
let end = e;
let begin = b;
shadowNode.innerHTML = text.substring(0, mid) + suffix;
let sh = shadowNode.offsetHeight;
if (sh <= th) {
shadowNode.innerHTML = text.substring(0, mid + 1) + suffix;
sh = shadowNode.offsetHeight;
if (sh > th || mid === begin) {
return mid;
}
begin = mid;
if (end - begin === 1) {
mid = 1 + begin;
} else {
mid = Math.floor((end - begin) / 2) + begin;
}
return this.bisection(th, mid, begin, end, text, shadowNode);
}
if (mid - 1 < 0) {
return mid;
}
shadowNode.innerHTML = text.substring(0, mid - 1) + suffix;
sh = shadowNode.offsetHeight;
if (sh <= th) {
return mid - 1;
}
end = mid;
mid = Math.floor((end - begin) / 2) + begin;
return this.bisection(th, mid, begin, end, text, shadowNode);
};
handleRoot = n => {
this.root = n;
};
handleContent = n => {
this.content = n;
};
handleNode = n => {
this.node = n;
};
handleShadow = n => {
this.shadow = n;
};
handleShadowChildren = n => {
this.shadowChildren = n;
};
render() {
const { text, targetCount } = this.state;
const {
children,
lines,
length,
className,
tooltip,
fullWidthRecognition,
...restProps
} = this.props;
const cls = classNames(styles.ellipsis, className, {
[styles.lines]: lines && !isSupportLineClamp,
[styles.lineClamp]: lines && isSupportLineClamp,
});
if (!lines && !length) {
return (
<span className={cls} {...restProps}>
{children}
</span>
);
}
// length
if (!lines) {
return (
<EllipsisText
className={cls}
length={length}
text={children || ''}
tooltip={tooltip}
fullWidthRecognition={fullWidthRecognition}
{...restProps}
/>
);
}
const id = `antd-pro-ellipsis-${`${new Date().getTime()}${Math.floor(Math.random() * 100)}`}`;
// support document.body.style.webkitLineClamp
if (isSupportLineClamp) {
const style = `#${id}{-webkit-line-clamp:${lines};-webkit-box-orient: vertical;}`;
const node = (
<div id={id} className={cls} {...restProps}>
<style>{style}</style>
{children}
</div>
);
return getTooltip({
tooltip,
overlayStyle: TooltipOverlayStyle,
title: children,
children: node,
});
}
const childNode = (
<span ref={this.handleNode}>
{targetCount > 0 && text.substring(0, targetCount)}
{targetCount > 0 && targetCount < text.length && '...'}
</span>
);
return (
<div {...restProps} ref={this.handleRoot} className={cls}>
<div ref={this.handleContent}>
{getTooltip({
tooltip,
overlayStyle: TooltipOverlayStyle,
title: text,
children: childNode,
})}
<div className={styles.shadow} ref={this.handleShadowChildren}>
{children}
</div>
<div className={styles.shadow} ref={this.handleShadow}>
<span>{text}</span>
</div>
</div>
</div>
);
}
}

View File

@@ -0,0 +1,24 @@
.ellipsis {
display: inline-block;
width: 100%;
overflow: hidden;
word-break: break-all;
}
.lines {
position: relative;
.shadow {
position: absolute;
z-index: -999;
display: block;
color: transparent;
opacity: 0;
}
}
.lineClamp {
position: relative;
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
}

View File

@@ -0,0 +1,13 @@
import { getStrFullLength, cutStrByFullLength } from './index';
describe('test calculateShowLength', () => {
it('get full length', () => {
expect(getStrFullLength('一二a,')).toEqual(8);
});
it('cut str by full length', () => {
expect(cutStrByFullLength('一二a,', 7)).toEqual('一二a');
});
it('cut str when length small', () => {
expect(cutStrByFullLength('一22三', 5)).toEqual('一22');
});
});

View File

@@ -0,0 +1,17 @@
---
title: Ellipsis
subtitle: 文本自动省略号
cols: 1
order: 10
---
文本过长自动处理省略号,支持按照文本长度和最大行数两种方式截取。
## API
参数 | 说明 | 类型 | 默认值
----|------|-----|------
tooltip | 移动到文本展示完整内容的提示 | boolean | -
length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | -
lines | 在按照行数截取下最大的行数,超过则截取省略 | number | `1`
fullWidthRecognition | 是否将全角字符的长度视为2来计算字符串长度 | boolean | -