Skip to content

Commit

Permalink
fix: 抽离Popover实现复用性
Browse files Browse the repository at this point in the history
  • Loading branch information
ShanaMaid committed Oct 30, 2018
1 parent 56f1d08 commit 4b19532
Show file tree
Hide file tree
Showing 13 changed files with 229 additions and 98 deletions.
132 changes: 132 additions & 0 deletions components/PopOver/PopOver.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// tslint:disable no-any
import {Component} from 'react';
import * as React from 'react';
import {IBaseComponent} from '../template/component';
import { RenderInRootDom } from '../utils/';
import Helpers from '../Helpers';
import Transitions from '../Transitions';

const { Scale } = Transitions;
const { ClickOutside } = Helpers;

export interface IPopOverProps extends IBaseComponent {
/**
* 面板是否展开
*/
open: boolean;
/**
* 面板展开回调
*/
onOpenChange?: (v: boolean) => void;
/**
* 浮层内容
*/
pop: any;
/**
* 进入后
*/
onEntered?: () => void;
}

export interface IPopOverState {
popPos: {
left: number;
top: number;
};
}

/**
* **组件中文名称**-组件描述。
*/
export class PopOver extends Component<IPopOverProps, IPopOverState> {
preCls = 'yoshino-pop-over';
refPopOverContainer: Element;

static defaultProps = {
};

state = {
popPos: {
left: 0,
top: 0,
},
};

setPopOverPosition = () => {
if (!this.refPopOverContainer) {
return;
}
const rect = this.refPopOverContainer.getBoundingClientRect();
const pageY = window.pageYOffset; // 当前滚动条y轴偏移量
const pageX = window.pageXOffset; // 当前滚动条x轴偏移量
this.setState({
popPos: {
left: rect.left + pageX,
top: rect.top + pageY,
}
});
}

onOpenChange = (open: boolean) => {
const { onOpenChange } = this.props;
if (onOpenChange) {
onOpenChange(open);
}
// 调整面板位置
this.setPopOverPosition();
}

render() {
const {
children, pop, open,
onEntered,
} = this.props;
const preCls = this.preCls;
const child = React.Children.only(children);
return (
<React.Fragment>
{
React.cloneElement(child, {
onClick: () => {
if (child.props.onClick) {
child.props.onClick();
}
this.onOpenChange(true);
},
ref: (v: any) => {
if (child.props.ref) {
child.props.ref(v);
}
if (v) {
this.refPopOverContainer = v;
}
}
})
}
<RenderInRootDom>
<ClickOutside
clickOutside={() => {
this.onOpenChange(false);
}}
>
<div className={`${preCls}-box`} style={this.state.popPos}>
<Scale
timeout={300}
active={open}
onEntered={() => {
if (onEntered) {
onEntered();
}
}}
>
{pop}
</Scale>
</div>
</ClickOutside>
</RenderInRootDom>
</React.Fragment>
);
}
}

export default PopOver;
12 changes: 12 additions & 0 deletions components/PopOver/__tests__/e2e.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';
import {Simulate, renderIntoDocument, scryRenderedComponentsWithType} from 'react-dom/test-utils';
import {findDOMNode} from 'react-dom';
import PopOver from '../index';

describe('多选', () => {
test('点击其中一个选项后可通过 onChange 拿到最新的值', () => {
const component = renderIntoDocument(
<PopOver/>,
) as PopOver;
});
});
14 changes: 14 additions & 0 deletions components/PopOver/__tests__/props.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as renderer from 'react-test-renderer';
import * as React from 'react';
import PopOver from '../index';

describe('Props', () => {

test('默认', () => {
const component = renderer.create(
<PopOver/>,
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});
3 changes: 3 additions & 0 deletions components/PopOver/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import PopOver from './PopOver';

export default PopOver;
3 changes: 3 additions & 0 deletions components/PopOver/style/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import '../../Transitions/style/';
import '../../Helpers/style/';
import './index.css';
9 changes: 9 additions & 0 deletions components/PopOver/style/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import './var.less';

@popOver-prefix-cls: ~"@{css-prefix}-pop-over";

.@{popOver-prefix-cls} {
&-box {
position: absolute;
}
}
3 changes: 3 additions & 0 deletions components/PopOver/style/less.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import '../../Transitions/style/less.js';
import '../../Helpers/style/less.js';
import './index.less'
1 change: 1 addition & 0 deletions components/PopOver/style/var.less
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import '../../styles/var.less';
139 changes: 46 additions & 93 deletions components/TimePicker/TimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ import * as classNames from 'classnames';
import {IBaseComponent, TSize} from '../template/component';
import Input from '../Input';
import Icon from '../Icon';
import Transitions from '../Transitions';
import { RenderInRootDom, valueTransition } from '../utils/';
import Helpers from '../Helpers';
import { valueTransition } from '../utils/';
import Popover from '../PopOver';
import * as moment from 'moment';

const { Scale } = Transitions;
const { ClickOutside } = Helpers;

export interface ITimePickerProps extends IBaseComponent {
/**
* 默认提示文本
Expand Down Expand Up @@ -63,10 +59,6 @@ export interface ITimePickerProps extends IBaseComponent {
}

export interface ITimePickerState {
panelPos: {
left: number;
top: number;
};
open: boolean;
value: string;
}
Expand Down Expand Up @@ -106,10 +98,6 @@ export class TimePicker extends Component<ITimePickerProps, ITimePickerState> {
value: this.props.defaultValue!,
};

componentDidMount() {
this.setPanelPosition();
}

getOpen = () => {
const { open } = this.props;
return open !== undefined ? open : this.state.open;
Expand All @@ -120,21 +108,6 @@ export class TimePicker extends Component<ITimePickerProps, ITimePickerState> {
return value !== undefined ? value : this.state.value;
}

setPanelPosition = () => {
if (!this.refTimePickerConatainer) {
return;
}
const rect = this.refTimePickerConatainer.getBoundingClientRect();
const pageY = window.pageYOffset; // 当前滚动条y轴偏移量
const pageX = window.pageXOffset; // 当前滚动条x轴偏移量
this.setState({
panelPos: {
left: rect.left + pageX,
top: rect.top + pageY,
}
});
}

renderSelectItem = (type: 'h' | 'm' | 's') => {
const values: string[] = [];
let selectedItem = 0;
Expand Down Expand Up @@ -263,9 +236,6 @@ export class TimePicker extends Component<ITimePickerProps, ITimePickerState> {
open,
});
}, 10);

// 调整面板位置
this.setPanelPosition();
}

onChange = (value: string) => {
Expand All @@ -292,70 +262,53 @@ export class TimePicker extends Component<ITimePickerProps, ITimePickerState> {
);
const valueR = this.getValue();
const openR = this.getOpen();
return (
<div
className={clsName}
style={style}
ref={(v) => {
if (v) {
this.refTimePickerConatainer = v;
}
}}
{...otherProps}
>
<Input
size={size}
placeholder={placeholder}
onClick={this.onOpenChange.bind(this, true)}
value={valueR}
readOnly
/>
<Icon className={`${preCls}-icon`} type='md-time'/>
<RenderInRootDom>
<ClickOutside
clickOutside={() => {
this.onOpenChange(false);
const pop = (
<div className={`${preCls}-panel`}>
<div className={`${preCls}-input-wrap`}>
<input
placeholder={placeholder}
readOnly
value={valueR}
ref={(v) => {
if (v) {
this.refPanelInput = v;
}
}}
>
<div className={`${preCls}-box`} style={this.state.panelPos}>
<Scale
timeout={300}
active={openR}
onEntered={() => {
if (this.refPanelInput) {
this.refPanelInput.focus();
}
}}
>
<div className={`${preCls}-panel`}>
<div className={`${preCls}-input-wrap`}>
<input
placeholder={placeholder}
readOnly
value={valueR}
ref={(v) => {
if (v) {
this.refPanelInput = v;
}
}}
/>
<Icon
type='ios-close-circle'
onClick={this.onChange.bind(this, '')}
/>
</div>
<div className={`${preCls}-select-container`}>
{disabledHours ? null : this.renderSelectItem('h')}
{disabledMinutes ? null : this.renderSelectItem('m')}
{disabledSeconds ? null : this.renderSelectItem('s')}
</div>
</div>
</Scale>
</div>
</ClickOutside>
</RenderInRootDom>
/>
<Icon
type='ios-close-circle'
onClick={this.onChange.bind(this, '')}
/>
</div>
<div className={`${preCls}-select-container`}>
{disabledHours ? null : this.renderSelectItem('h')}
{disabledMinutes ? null : this.renderSelectItem('m')}
{disabledSeconds ? null : this.renderSelectItem('s')}
</div>
</div>
);
return (
<Popover
pop={pop}
open={openR}
onOpenChange={this.onOpenChange}
>
<div
className={clsName}
style={style}
{...otherProps}
>
<Input
size={size}
placeholder={placeholder}
onClick={this.onOpenChange.bind(this, true)}
value={valueR}
readOnly
/>
<Icon className={`${preCls}-icon`} type='md-time'/>
</div>
</Popover>
);
}
}

Expand Down
3 changes: 1 addition & 2 deletions components/TimePicker/style/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import '../../Icon/style/';
import '../../Input/style/';
import '../../Transitions/style/';
import '../../Helpers/style/';
import '../../PopOver/style/';
import './index.css';
3 changes: 1 addition & 2 deletions components/TimePicker/style/less.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import '../../Icon/style/less.js';
import '../../Input/style/less.js';
import '../../Transitions/style/less.js';
import '../../Helpers/style/less.js';
import '../../PopOver/style/less.js';
import './index.less';
Loading

0 comments on commit 4b19532

Please sign in to comment.