Skip to content

Commit

Permalink
Merge e968934 into 8c6ae8c
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieJ committed Jun 4, 2018
2 parents 8c6ae8c + e968934 commit 1fc3693
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 41 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,15 @@ will align child with target when mounted or align is changed
</tr>
<tr>
<td>target</td>
<td>function():HTMLElement</td>
<td>
function():HTMLElement ||
{ pageX: number, pageY: number } ||
{ clientX: number, clientY: number }
</td>
<td>function(){return window;}</td>
<td>a function which returned value is used for target from https://github.com/yiminghe/dom-align</td>
<td>
a function which returned value or point is used for target from https://github.com/yiminghe/dom-align
</td>
</tr>
<tr>
<td>monitorWindowResize</td>
Expand Down
1 change: 1 addition & 0 deletions examples/point.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
placeholder
43 changes: 43 additions & 0 deletions examples/point.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Align from 'rc-align';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

const align = {
points: ['cc', 'cc'],
};

class Demo extends Component {
state = {
point: null,
};

onClick = ({ pageX, pageY }) => {
this.setState({ point: { pageX, pageY }});
}

render() {
return (
<div style={{ marginBottom: 170 }}>
<div
style={{ margin: 20, border: '1px solid red', padding: '100px 0', textAlign: 'center' }}
onClick={this.onClick}
>
Click this region please : )
</div>

<Align
ref={this.alignRef}
target={this.state.point}
align={align}
>
<div
style={{ position: 'absolute', width: 100, height: 100, background: 'rgba(0, 255, 0, 0.5)', pointerEvents: 'none' }}
>Align</div>
</Align>
</div>
);
}
}

ReactDOM.render(<Demo />, document.getElementById('__react-content'));

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,19 @@
"devDependencies": {
"core-js": "^2.5.1",
"expect.js": "0.3.x",
"jquery": "^3.3.1",
"pre-commit": "1.x",
"rc-test": "6.x",
"rc-tools": "8.x",
"react": "^16.1.1",
"react-dom": "^16.1.1"
"react": "^16.3.0",
"react-dom": "^16.3.0"
},
"pre-commit": [
"lint"
],
"dependencies": {
"babel-runtime": "^6.26.0",
"dom-align": "1.x",
"dom-align": "^1.7.0",
"prop-types": "^15.5.8",
"rc-util": "^4.0.4",
"shallowequal": "^1.0.2"
Expand Down
74 changes: 47 additions & 27 deletions src/Align.jsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import align from 'dom-align';
import { alignElement, alignPoint } from 'dom-align';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import shallowequal from 'shallowequal';
import isWindow from './isWindow';

function buffer(fn, ms) {
let timer;
import { isWindow, buffer, isSamePoint } from './util';

function clear() {
if (timer) {
clearTimeout(timer);
timer = null;
}
}

function bufferFn() {
clear();
timer = setTimeout(fn, ms);
}

bufferFn.clear = clear;
function getElement(func) {
if (typeof func !== 'function' || !func) return null;
return func();
}

return bufferFn;
function getPoint(point) {
if (typeof point !== 'object' || !point) return null;
return point;
}

class Align extends Component {
static propTypes = {
childrenProps: PropTypes.object,
align: PropTypes.object.isRequired,
target: PropTypes.func,
target: PropTypes.oneOfType([
PropTypes.func,
PropTypes.shape({
clientX: PropTypes.number,
clientY: PropTypes.number,
pageX: PropTypes.number,
pageY: PropTypes.number,
}),
]),
onAlign: PropTypes.func,
monitorBufferTime: PropTypes.number,
monitorWindowResize: PropTypes.bool,
Expand All @@ -40,7 +39,6 @@ class Align extends Component {

static defaultProps = {
target: () => window,
onAlign: () => {},
monitorBufferTime: 50,
monitorWindowResize: false,
disabled: false,
Expand All @@ -63,11 +61,20 @@ class Align extends Component {
if (prevProps.disabled || !shallowequal(prevProps.align, props.align)) {
reAlign = true;
} else {
const lastTarget = prevProps.target();
const currentTarget = props.target();
if (isWindow(lastTarget) && isWindow(currentTarget)) {
const lastElement = getElement(prevProps.target);
const currentElement = getElement(props.target);
const lastPoint = getPoint(prevProps.target);
const currentPoint = getPoint(props.target);

if (isWindow(lastElement) && isWindow(currentElement)) {
// Skip if is window
reAlign = false;
} else if (lastTarget !== currentTarget) {
} else if (
lastElement !== currentElement || // Element change
(!lastElement && currentPoint) || // Change from element to point
(!lastPoint && currentElement) || // Change from point to element
(currentPoint && !isSamePoint(lastPoint, currentPoint))
) {
reAlign = true;
}
}
Expand Down Expand Up @@ -104,10 +111,23 @@ class Align extends Component {
}

forceAlign = () => {
const props = this.props;
if (!props.disabled) {
const { disabled, target, align, onAlign } = this.props;
if (!disabled && target) {
const source = ReactDOM.findDOMNode(this);
props.onAlign(source, align(source, props.target(), props.align));

let result;
const element = getElement(target);
const point = getPoint(target);

if (element) {
result = alignElement(source, element, align);
} else if (point) {
result = alignPoint(source, point, align);
}

if (onAlign) {
onAlign(source, result);
}
}
}

Expand Down
5 changes: 0 additions & 5 deletions src/isWindow.js

This file was deleted.

31 changes: 31 additions & 0 deletions src/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export function buffer(fn, ms) {
let timer;

function clear() {
if (timer) {
clearTimeout(timer);
timer = null;
}
}

function bufferFn() {
clear();
timer = setTimeout(fn, ms);
}

bufferFn.clear = clear;

return bufferFn;
}

export function isSamePoint(prev, next) {
if (prev === next) return true;
if (!prev || !next) return false;

return (prev.pageX === next.pageX && prev.pageY === next.pageY) ||
(prev.clientX === next.clientX && prev.clientY === next.clientY);
}

export function isWindow(obj) {
return obj && typeof obj === 'object' && obj.window === obj;
}
13 changes: 9 additions & 4 deletions tests/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
require('core-js/es6/map');
require('core-js/es6/set');
const expect = require('expect.js');
const Align = require('../');
import 'core-js/es6/map';
import 'core-js/es6/set';
import $ from 'jquery';
import Align from '../src';

$('<style>html,body {padding:0;margin:0;border:none;}</style>')
.appendTo(document.getElementsByTagName('head'));

describe('rc-align', () => {
it('exists', () => {
expect(Align).to.be.ok();
});
});

require('./point.spec');
87 changes: 87 additions & 0 deletions tests/point.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* eslint react/no-render-return-value:0 */

import React from 'react';
import ReactDOM from 'react-dom';
import $ from 'jquery';
import expect from 'expect.js';
import Align from '../src';

describe('point align', () => {
let container;

function createAlign(props, callback) {
class Test extends React.Component {
state = {};

render() {
return (
<Align {...props} {...this.state}>
<div
id="align"
style={{ width: 20, height: 20, position: 'fixed' }}
/>
</Align>
);
}
}

return ReactDOM.render(<Test />, container[0], callback);
}

beforeEach(() => {
container = $('<div>').appendTo(document.body);
});

afterEach(() => {
try {
ReactDOM.unmountComponentAtNode(container[0]);
} catch (e) {
// do nothing...
}
if (container) container.remove();
container = null;
});

it('not pass point', (done) => {
createAlign(
{
align: { points: ['cc'] },
target: null,
},
() => {
const $align = $('#align')[0];
expect($align).to.be.ok();
expect($align.style.left).to.not.be.ok();
expect($align.style.top).to.not.be.ok();
done();
},
);
});

it('pass point', (done) => {
const wrapper = createAlign(
{
align: { points: ['tc'] },
target: null,
},
);

wrapper.setState({
target: { pageX: 1128, pageY: 903 },
}, () => {
const $align = $('#align');
expect($align[0]).to.be.ok();
expect($align.offset().left).to.be(1118);
expect($align.offset().top).to.be(903);

wrapper.setState({
target: { pageX: 321, pageY: 613 },
}, () => {
expect($align.offset().left).to.be(311);
expect($align.offset().top).to.be(613);

done();
});
});
});
});

0 comments on commit 1fc3693

Please sign in to comment.