Skip to content

Commit

Permalink
New Component: Typography (ant-design#14250)
Browse files Browse the repository at this point in the history
* text with prefix

* add edit style

* support editable

* enhance accessibility & type experience

* optimize IME case

* support copy

* add locale

* add secondary & disabled

* add ellipsis shadow text

* split to 3 components

* update snapshot

* update desc

* change lines also need update ellipsis

* skip aria when is in ellipsis

* add ResizeObserver in _util

* update snapshot

* move TestBase into test file

* update test case

* update doc

* fix typo

* important => level

* use rows

* update demo cols to 1

* fix cssText not work in firefox

* update doc

* add miss point

* support extendable

* update snapshot

* fix doc

* copyable support string

* update snapshot

* update doc

* update doc desc

* adjust style

* full test

* reset after test

* rename

* update snapshot

* fix compile

* adjust style

* update desc

* update prefixCls

* update margin

* adjust

* nest wrap of tag content

* adjust style

* update comment

* rm %

* one more thing

* tmp of measure

* merge string as children

* update snapshot

* update testcase

* remove comment

* use internal variable for configProvider passing

* update snapshot

* use expandable instead of extendable

* less variable it

* update demo

* update less

* adjust code & mark style

* remove mark padding

* update measure logic

* support nest element style

* use childNode.textContent to fix react 15 error

* update css

* popout Typography

* add link style

* adjust doc

* use ellipsis instead of rows & expandable

* update doc

* update doc

* update doc & style

* fix typo

* add css ellipsis support

* client render

* update snapshot

* enhance copyable

* support onExpand

* update test case

* add test of css ellipsis

* fix logic in react 15

* rename onChange -> onSave

* use tagName of article

* fix lint
  • Loading branch information
zombieJ authored Feb 19, 2019
1 parent 1564173 commit c80136a
Show file tree
Hide file tree
Showing 42 changed files with 2,782 additions and 89 deletions.
1 change: 1 addition & 0 deletions components/__tests__/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Array [
"TimePicker",
"Timeline",
"Tooltip",
"Typography",
"Mention",
"Upload",
"version",
Expand Down
4 changes: 3 additions & 1 deletion components/_util/raf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export default function wrapperRaf(callback: () => void, delayFrames: number = 1
return myId;
}

wrapperRaf.cancel = function(pid: number) {
wrapperRaf.cancel = function(pid?: number) {
if (pid === undefined) return;

raf.cancel(ids[pid]);
delete ids[pid];
};
61 changes: 61 additions & 0 deletions components/_util/resizeObserver.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import * as React from 'react';
import { findDOMNode } from 'react-dom';
import ResizeObserver from 'resize-observer-polyfill';

type DomElement = Element | null;

interface ResizeObserverProps {
children?: React.ReactNode;
disabled?: boolean;
onResize?: () => void;
}

class ReactResizeObserver extends React.Component<ResizeObserverProps, {}> {
resizeObserver: ResizeObserver | null = null;

componentDidMount() {
this.onComponentUpdated();
}

componentDidUpdate() {
this.onComponentUpdated();
}

componentWillUnmount() {
this.destroyObserver();
}

onComponentUpdated() {
const { disabled } = this.props;
const element = findDOMNode(this) as DomElement;
if (!this.resizeObserver && !disabled && element) {
// Add resize observer
this.resizeObserver = new ResizeObserver(this.onResize);
this.resizeObserver.observe(element);
} else if (disabled) {
// Remove resize observer
this.destroyObserver();
}
}

onResize = () => {
const { onResize } = this.props;
if (onResize) {
onResize();
}
};

destroyObserver() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
this.resizeObserver = null;
}
}

render() {
const { children } = this.props;
return children;
}
}

export default ReactResizeObserver;
68 changes: 68 additions & 0 deletions components/_util/transButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Wrap of sub component which need use as Button capacity (like Icon component).
* This helps accessibility reader to tread as a interactive button to operation.
*/
import * as React from 'react';
import KeyCode from 'rc-util/lib/KeyCode';

interface TransButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
onClick?: () => void;
}

const inlineStyle: React.CSSProperties = {
border: 0,
background: 'transparent',
padding: 0,
lineHeight: 'inherit',
};

class TransButton extends React.Component<TransButtonProps> {
button?: HTMLButtonElement;
lastKeyCode?: number;

onKeyDown: React.KeyboardEventHandler<HTMLButtonElement> = event => {
const { keyCode } = event;
if (keyCode === KeyCode.ENTER) {
event.preventDefault();
}
};

onKeyUp: React.KeyboardEventHandler<HTMLButtonElement> = event => {
const { keyCode } = event;
const { onClick } = this.props;
if (keyCode === KeyCode.ENTER && onClick) {
onClick();
}
};

setRef = (btn: HTMLButtonElement) => {
this.button = btn;
};

focus() {
if (this.button) {
this.button.focus();
}
}

blur() {
if (this.button) {
this.button.blur();
}
}

render() {
const { style } = this.props;
return (
<button
ref={this.setRef}
{...this.props}
onKeyDown={this.onKeyDown}
onKeyUp={this.onKeyUp}
style={{ ...inlineStyle, ...style }}
/>
);
}
}

export default TransButton;
4 changes: 3 additions & 1 deletion components/_util/type.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
// https://stackoverflow.com/questions/46176165/ways-to-get-string-literal-type-of-array-values-without-enum-overhead
export const tuple = <T extends string[]>(...args: T) => args;
export const tuple = <T extends string[]>(...args: T) => args;

export const tupleNum = <T extends number[]>(...args: T) => args;
24 changes: 22 additions & 2 deletions components/config-provider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ export interface ConfigConsumerProps {
autoInsertSpaceInButton?: boolean;
}

export const configConsumerProps = [
'getPopupContainer',
'rootPrefixCls',
'getPrefixCls',
'renderEmpty',
'csp',
'autoInsertSpaceInButton',
];

interface ConfigProviderProps {
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
prefixCls?: string;
Expand Down Expand Up @@ -89,10 +98,14 @@ interface ConsumerConfig {
prefixCls: string;
}

interface ConstructorProps {
displayName?: string;
}

export function withConfigConsumer<ExportProps extends BasicExportProps>(config: ConsumerConfig) {
return function <ComponentDef>(Component: IReactComponent): React.SFC<ExportProps> & ComponentDef {
return function<ComponentDef>(Component: IReactComponent): React.SFC<ExportProps> & ComponentDef {
// Wrap with ConfigConsumer. Since we need compatible with react 15, be care when using ref methods
return ((props: ExportProps) => (
const SFC = ((props: ExportProps) => (
<ConfigConsumer>
{(configProps: ConfigConsumerProps) => {
const { prefixCls: basicPrefixCls } = config;
Expand All @@ -103,6 +116,13 @@ export function withConfigConsumer<ExportProps extends BasicExportProps>(config:
}}
</ConfigConsumer>
)) as React.SFC<ExportProps> & ComponentDef;

const cons: ConstructorProps = Component.constructor as ConstructorProps;
const name = (cons && cons.displayName) || Component.name || 'Component';

SFC.displayName = `withConfigConsumer(${name})`;

return SFC;
};
}

Expand Down
1 change: 1 addition & 0 deletions components/icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface IconProps {
className?: string;
theme?: ThemeType;
title?: string;
onKeyUp?: React.KeyboardEventHandler<HTMLElement>;
onClick?: React.MouseEventHandler<HTMLElement>;
component?: React.ComponentType<CustomIconComponentProps>;
twoToneColor?: string;
Expand Down
2 changes: 2 additions & 0 deletions components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ export { default as Timeline } from './timeline';

export { default as Tooltip } from './tooltip';

export { default as Typography } from './typography';

export { default as Mention } from './mention';

export { default as Upload } from './upload';
Expand Down
44 changes: 12 additions & 32 deletions components/input/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import * as React from 'react';
import omit from 'omit.js';
import classNames from 'classnames';
import { polyfill } from 'react-lifecycles-compat';
import ResizeObserver from 'resize-observer-polyfill';
import calculateNodeHeight from './calculateNodeHeight';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import ResizeObserver from '../_util/resizeObserver';

function onNextFrame(cb: () => void) {
if (window.requestAnimationFrame) {
Expand Down Expand Up @@ -40,7 +40,6 @@ export interface TextAreaState {

class TextArea extends React.Component<TextAreaProps, TextAreaState> {
nextFrameActionId: number;
resizeObserver: ResizeObserver | null;

state = {
textareaStyles: {},
Expand All @@ -50,21 +49,13 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {

componentDidMount() {
this.resizeTextarea();
this.updateResizeObserverHook();
}

componentDidUpdate(prevProps: TextAreaProps) {
// Re-render with the new content then recalculate the height as required.
if (prevProps.value !== this.props.value) {
this.resizeOnNextFrame();
}
this.updateResizeObserverHook();
}

componentWillUnmount() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
}

resizeOnNextFrame = () => {
Expand All @@ -74,19 +65,6 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
this.nextFrameActionId = onNextFrame(this.resizeTextarea);
};

// We will update hooks if `autosize` prop change
updateResizeObserverHook() {
if (!this.resizeObserver && this.props.autosize) {
// Add resize observer
this.resizeObserver = new ResizeObserver(this.resizeOnNextFrame);
this.resizeObserver.observe(this.textAreaRef);
} else if (this.resizeObserver && !this.props.autosize) {
// Remove resize observer
this.resizeObserver.disconnect();
this.resizeObserver = null;
}
}

focus() {
this.textAreaRef.focus();
}
Expand Down Expand Up @@ -130,7 +108,7 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
};

renderTextArea = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className, disabled } = this.props;
const { prefixCls: customizePrefixCls, className, disabled, autosize } = this.props;
const { ...props } = this.props;
const otherProps = omit(props, ['prefixCls', 'onPressEnter', 'autosize']);
const prefixCls = getPrefixCls('input', customizePrefixCls);
Expand All @@ -148,14 +126,16 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
otherProps.value = otherProps.value || '';
}
return (
<textarea
{...otherProps}
className={cls}
style={style}
onKeyDown={this.handleKeyDown}
onChange={this.handleTextareaChange}
ref={this.saveTextAreaRef}
/>
<ResizeObserver onResize={this.resizeOnNextFrame} disabled={!autosize}>
<textarea
{...otherProps}
className={cls}
style={style}
onKeyDown={this.handleKeyDown}
onChange={this.handleTextareaChange}
ref={this.saveTextAreaRef}
/>
</ResizeObserver>
);
};

Expand Down
36 changes: 23 additions & 13 deletions components/input/__tests__/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -625,13 +625,18 @@ exports[`TextArea should support disabled 1`] = `
disabled={true}
>
<Consumer>
<textarea
className="ant-input ant-input-disabled"
<ReactResizeObserver
disabled={true}
onChange={[Function]}
onKeyDown={[Function]}
style={Object {}}
/>
onResize={[Function]}
>
<textarea
className="ant-input ant-input-disabled"
disabled={true}
onChange={[Function]}
onKeyDown={[Function]}
style={Object {}}
/>
</ReactResizeObserver>
</Consumer>
</TextArea>
`;
Expand All @@ -641,13 +646,18 @@ exports[`TextArea should support maxLength 1`] = `
maxLength={10}
>
<Consumer>
<textarea
className="ant-input"
maxLength={10}
onChange={[Function]}
onKeyDown={[Function]}
style={Object {}}
/>
<ReactResizeObserver
disabled={true}
onResize={[Function]}
>
<textarea
className="ant-input"
maxLength={10}
onChange={[Function]}
onKeyDown={[Function]}
style={Object {}}
/>
</ReactResizeObserver>
</Consumer>
</TextArea>
`;
6 changes: 6 additions & 0 deletions components/locale-provider/default.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,10 @@ export default {
Icon: {
icon: 'icon',
},
Text: {
edit: 'edit',
copy: 'copy',
copied: 'copy success',
expand: 'expand',
},
};
6 changes: 6 additions & 0 deletions components/locale-provider/zh_CN.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,10 @@ export default {
Icon: {
icon: '图标',
},
Text: {
edit: '编辑',
copy: '复制',
copied: '复制成功',
expand: '展开',
},
};
Loading

0 comments on commit c80136a

Please sign in to comment.