Initial commit
This commit is contained in:
184
node_modules/react-draggable/lib/utils/domFns.js
generated
vendored
Normal file
184
node_modules/react-draggable/lib/utils/domFns.js
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
// @flow
|
||||
import {findInArray, isFunction, int} from './shims';
|
||||
import browserPrefix, {browserPrefixToKey} from './getPrefix';
|
||||
|
||||
import type {ControlPosition, MouseTouchEvent} from './types';
|
||||
|
||||
let matchesSelectorFunc = '';
|
||||
export function matchesSelector(el: Node, selector: string): boolean {
|
||||
if (!matchesSelectorFunc) {
|
||||
matchesSelectorFunc = findInArray([
|
||||
'matches',
|
||||
'webkitMatchesSelector',
|
||||
'mozMatchesSelector',
|
||||
'msMatchesSelector',
|
||||
'oMatchesSelector'
|
||||
], function(method){
|
||||
// $FlowIgnore: Doesn't think elements are indexable
|
||||
return isFunction(el[method]);
|
||||
});
|
||||
}
|
||||
|
||||
// Might not be found entirely (not an Element?) - in that case, bail
|
||||
// $FlowIgnore: Doesn't think elements are indexable
|
||||
if (!isFunction(el[matchesSelectorFunc])) return false;
|
||||
|
||||
// $FlowIgnore: Doesn't think elements are indexable
|
||||
return el[matchesSelectorFunc](selector);
|
||||
}
|
||||
|
||||
// Works up the tree to the draggable itself attempting to match selector.
|
||||
export function matchesSelectorAndParentsTo(el: Node, selector: string, baseNode: Node): boolean {
|
||||
let node = el;
|
||||
do {
|
||||
if (matchesSelector(node, selector)) return true;
|
||||
if (node === baseNode) return false;
|
||||
node = node.parentNode;
|
||||
} while (node);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function addEvent(el: ?Node, event: string, handler: Function): void {
|
||||
if (!el) { return; }
|
||||
if (el.attachEvent) {
|
||||
el.attachEvent('on' + event, handler);
|
||||
} else if (el.addEventListener) {
|
||||
el.addEventListener(event, handler, true);
|
||||
} else {
|
||||
// $FlowIgnore: Doesn't think elements are indexable
|
||||
el['on' + event] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
export function removeEvent(el: ?Node, event: string, handler: Function): void {
|
||||
if (!el) { return; }
|
||||
if (el.detachEvent) {
|
||||
el.detachEvent('on' + event, handler);
|
||||
} else if (el.removeEventListener) {
|
||||
el.removeEventListener(event, handler, true);
|
||||
} else {
|
||||
// $FlowIgnore: Doesn't think elements are indexable
|
||||
el['on' + event] = null;
|
||||
}
|
||||
}
|
||||
|
||||
export function outerHeight(node: HTMLElement): number {
|
||||
// This is deliberately excluding margin for our calculations, since we are using
|
||||
// offsetTop which is including margin. See getBoundPosition
|
||||
let height = node.clientHeight;
|
||||
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
|
||||
height += int(computedStyle.borderTopWidth);
|
||||
height += int(computedStyle.borderBottomWidth);
|
||||
return height;
|
||||
}
|
||||
|
||||
export function outerWidth(node: HTMLElement): number {
|
||||
// This is deliberately excluding margin for our calculations, since we are using
|
||||
// offsetLeft which is including margin. See getBoundPosition
|
||||
let width = node.clientWidth;
|
||||
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
|
||||
width += int(computedStyle.borderLeftWidth);
|
||||
width += int(computedStyle.borderRightWidth);
|
||||
return width;
|
||||
}
|
||||
export function innerHeight(node: HTMLElement): number {
|
||||
let height = node.clientHeight;
|
||||
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
|
||||
height -= int(computedStyle.paddingTop);
|
||||
height -= int(computedStyle.paddingBottom);
|
||||
return height;
|
||||
}
|
||||
|
||||
export function innerWidth(node: HTMLElement): number {
|
||||
let width = node.clientWidth;
|
||||
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
|
||||
width -= int(computedStyle.paddingLeft);
|
||||
width -= int(computedStyle.paddingRight);
|
||||
return width;
|
||||
}
|
||||
|
||||
// Get from offsetParent
|
||||
export function offsetXYFromParent(evt: {clientX: number, clientY: number}, offsetParent: HTMLElement): ControlPosition {
|
||||
const isBody = offsetParent === offsetParent.ownerDocument.body;
|
||||
const offsetParentRect = isBody ? {left: 0, top: 0} : offsetParent.getBoundingClientRect();
|
||||
|
||||
const x = evt.clientX + offsetParent.scrollLeft - offsetParentRect.left;
|
||||
const y = evt.clientY + offsetParent.scrollTop - offsetParentRect.top;
|
||||
|
||||
return {x, y};
|
||||
}
|
||||
|
||||
export function createCSSTransform({x, y}: {x: number, y: number}): Object {
|
||||
// Replace unitless items with px
|
||||
return {[browserPrefixToKey('transform', browserPrefix)]: 'translate(' + x + 'px,' + y + 'px)'};
|
||||
}
|
||||
|
||||
export function createSVGTransform({x, y}: {x: number, y: number}): string {
|
||||
return 'translate(' + x + ',' + y + ')';
|
||||
}
|
||||
|
||||
export function getTouch(e: MouseTouchEvent, identifier: number): ?{clientX: number, clientY: number} {
|
||||
return (e.targetTouches && findInArray(e.targetTouches, t => identifier === t.identifier)) ||
|
||||
(e.changedTouches && findInArray(e.changedTouches, t => identifier === t.identifier));
|
||||
}
|
||||
|
||||
export function getTouchIdentifier(e: MouseTouchEvent): ?number {
|
||||
if (e.targetTouches && e.targetTouches[0]) return e.targetTouches[0].identifier;
|
||||
if (e.changedTouches && e.changedTouches[0]) return e.changedTouches[0].identifier;
|
||||
}
|
||||
|
||||
// User-select Hacks:
|
||||
//
|
||||
// Useful for preventing blue highlights all over everything when dragging.
|
||||
|
||||
// Note we're passing `document` b/c we could be iframed
|
||||
export function addUserSelectStyles(doc: ?Document) {
|
||||
if (!doc) return;
|
||||
let styleEl = doc.getElementById('react-draggable-style-el');
|
||||
if (!styleEl) {
|
||||
styleEl = doc.createElement('style');
|
||||
styleEl.type = 'text/css';
|
||||
styleEl.id = 'react-draggable-style-el';
|
||||
styleEl.innerHTML = '.react-draggable-transparent-selection *::-moz-selection {background: transparent;}\n';
|
||||
styleEl.innerHTML += '.react-draggable-transparent-selection *::selection {background: transparent;}\n';
|
||||
doc.getElementsByTagName('head')[0].appendChild(styleEl);
|
||||
}
|
||||
if (doc.body) addClassName(doc.body, 'react-draggable-transparent-selection');
|
||||
}
|
||||
|
||||
export function removeUserSelectStyles(doc: ?Document) {
|
||||
try {
|
||||
if (doc && doc.body) removeClassName(doc.body, 'react-draggable-transparent-selection');
|
||||
window.getSelection().removeAllRanges(); // remove selection caused by scroll
|
||||
} catch (e) {
|
||||
// probably IE
|
||||
}
|
||||
}
|
||||
|
||||
export function styleHacks(childStyle: Object = {}): Object {
|
||||
// Workaround IE pointer events; see #51
|
||||
// https://github.com/mzabriskie/react-draggable/issues/51#issuecomment-103488278
|
||||
return {
|
||||
touchAction: 'none',
|
||||
...childStyle
|
||||
};
|
||||
}
|
||||
|
||||
export function addClassName(el: HTMLElement, className: string) {
|
||||
if (el.classList) {
|
||||
el.classList.add(className);
|
||||
} else {
|
||||
if (!el.className.match(new RegExp(`(?:^|\\s)${className}(?!\\S)`))) {
|
||||
el.className += ` ${className}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function removeClassName(el: HTMLElement, className: string) {
|
||||
if (el.classList) {
|
||||
el.classList.remove(className);
|
||||
} else {
|
||||
el.className = el.className.replace(new RegExp(`(?:^|\\s)${className}(?!\\S)`, 'g'), '');
|
||||
}
|
||||
}
|
||||
47
node_modules/react-draggable/lib/utils/getPrefix.js
generated
vendored
Normal file
47
node_modules/react-draggable/lib/utils/getPrefix.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// @flow
|
||||
const prefixes = ['Moz', 'Webkit', 'O', 'ms'];
|
||||
export function getPrefix(prop: string='transform'): string {
|
||||
// Checking specifically for 'window.document' is for pseudo-browser server-side
|
||||
// environments that define 'window' as the global context.
|
||||
// E.g. React-rails (see https://github.com/reactjs/react-rails/pull/84)
|
||||
if (typeof window === 'undefined' || typeof window.document === 'undefined') return '';
|
||||
|
||||
const style = window.document.documentElement.style;
|
||||
|
||||
if (prop in style) return '';
|
||||
|
||||
for (let i = 0; i < prefixes.length; i++) {
|
||||
if (browserPrefixToKey(prop, prefixes[i]) in style) return prefixes[i];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
export function browserPrefixToKey(prop: string, prefix: string): string {
|
||||
return prefix ? `${prefix}${kebabToTitleCase(prop)}` : prop;
|
||||
}
|
||||
|
||||
export function browserPrefixToStyle(prop: string, prefix: string): string {
|
||||
return prefix ? `-${prefix.toLowerCase()}-${prop}` : prop;
|
||||
}
|
||||
|
||||
function kebabToTitleCase(str: string): string {
|
||||
let out = '';
|
||||
let shouldCapitalize = true;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (shouldCapitalize) {
|
||||
out += str[i].toUpperCase();
|
||||
shouldCapitalize = false;
|
||||
} else if (str[i] === '-') {
|
||||
shouldCapitalize = true;
|
||||
} else {
|
||||
out += str[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Default export is the prefix itself, like 'Moz', 'Webkit', etc
|
||||
// Note that you may have to re-test for certain things; for instance, Chrome 50
|
||||
// can handle unprefixed `transform`, but not unprefixed `user-select`
|
||||
export default getPrefix();
|
||||
5
node_modules/react-draggable/lib/utils/log.js
generated
vendored
Normal file
5
node_modules/react-draggable/lib/utils/log.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// @flow
|
||||
/*eslint no-console:0*/
|
||||
export default function log(...args: any) {
|
||||
if (process.env.DRAGGABLE_DEBUG) console.log(...args);
|
||||
}
|
||||
134
node_modules/react-draggable/lib/utils/positionFns.js
generated
vendored
Normal file
134
node_modules/react-draggable/lib/utils/positionFns.js
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
// @flow
|
||||
import {isNum, int} from './shims';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {getTouch, innerWidth, innerHeight, offsetXYFromParent, outerWidth, outerHeight} from './domFns';
|
||||
|
||||
import type Draggable from '../Draggable';
|
||||
import type {Bounds, ControlPosition, DraggableData, MouseTouchEvent} from './types';
|
||||
import type DraggableCore from '../DraggableCore';
|
||||
|
||||
export function getBoundPosition(draggable: Draggable, x: number, y: number): [number, number] {
|
||||
// If no bounds, short-circuit and move on
|
||||
if (!draggable.props.bounds) return [x, y];
|
||||
|
||||
// Clone new bounds
|
||||
let {bounds} = draggable.props;
|
||||
bounds = typeof bounds === 'string' ? bounds : cloneBounds(bounds);
|
||||
const node = findDOMNode(draggable);
|
||||
|
||||
if (typeof bounds === 'string') {
|
||||
const {ownerDocument} = node;
|
||||
const ownerWindow = ownerDocument.defaultView;
|
||||
let boundNode;
|
||||
if (bounds === 'parent') {
|
||||
boundNode = node.parentNode;
|
||||
} else {
|
||||
boundNode = ownerDocument.querySelector(bounds);
|
||||
}
|
||||
if (!(boundNode instanceof HTMLElement)) {
|
||||
throw new Error('Bounds selector "' + bounds + '" could not find an element.');
|
||||
}
|
||||
const nodeStyle = ownerWindow.getComputedStyle(node);
|
||||
const boundNodeStyle = ownerWindow.getComputedStyle(boundNode);
|
||||
// Compute bounds. This is a pain with padding and offsets but this gets it exactly right.
|
||||
bounds = {
|
||||
left: -node.offsetLeft + int(boundNodeStyle.paddingLeft) + int(nodeStyle.marginLeft),
|
||||
top: -node.offsetTop + int(boundNodeStyle.paddingTop) + int(nodeStyle.marginTop),
|
||||
right: innerWidth(boundNode) - outerWidth(node) - node.offsetLeft +
|
||||
int(boundNodeStyle.paddingRight) - int(nodeStyle.marginRight),
|
||||
bottom: innerHeight(boundNode) - outerHeight(node) - node.offsetTop +
|
||||
int(boundNodeStyle.paddingBottom) - int(nodeStyle.marginBottom)
|
||||
};
|
||||
}
|
||||
|
||||
// Keep x and y below right and bottom limits...
|
||||
if (isNum(bounds.right)) x = Math.min(x, bounds.right);
|
||||
if (isNum(bounds.bottom)) y = Math.min(y, bounds.bottom);
|
||||
|
||||
// But above left and top limits.
|
||||
if (isNum(bounds.left)) x = Math.max(x, bounds.left);
|
||||
if (isNum(bounds.top)) y = Math.max(y, bounds.top);
|
||||
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
export function snapToGrid(grid: [number, number], pendingX: number, pendingY: number): [number, number] {
|
||||
const x = Math.round(pendingX / grid[0]) * grid[0];
|
||||
const y = Math.round(pendingY / grid[1]) * grid[1];
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
export function canDragX(draggable: Draggable): boolean {
|
||||
return draggable.props.axis === 'both' || draggable.props.axis === 'x';
|
||||
}
|
||||
|
||||
export function canDragY(draggable: Draggable): boolean {
|
||||
return draggable.props.axis === 'both' || draggable.props.axis === 'y';
|
||||
}
|
||||
|
||||
// Get {x, y} positions from event.
|
||||
export function getControlPosition(e: MouseTouchEvent, touchIdentifier: ?number, draggableCore: DraggableCore): ?ControlPosition {
|
||||
const touchObj = typeof touchIdentifier === 'number' ? getTouch(e, touchIdentifier) : null;
|
||||
if (typeof touchIdentifier === 'number' && !touchObj) return null; // not the right touch
|
||||
const node = findDOMNode(draggableCore);
|
||||
// User can provide an offsetParent if desired.
|
||||
const offsetParent = draggableCore.props.offsetParent || node.offsetParent || node.ownerDocument.body;
|
||||
return offsetXYFromParent(touchObj || e, offsetParent);
|
||||
}
|
||||
|
||||
// Create an data object exposed by <DraggableCore>'s events
|
||||
export function createCoreData(draggable: DraggableCore, x: number, y: number): DraggableData {
|
||||
const state = draggable.state;
|
||||
const isStart = !isNum(state.lastX);
|
||||
const node = findDOMNode(draggable);
|
||||
|
||||
if (isStart) {
|
||||
// If this is our first move, use the x and y as last coords.
|
||||
return {
|
||||
node,
|
||||
deltaX: 0, deltaY: 0,
|
||||
lastX: x, lastY: y,
|
||||
x, y,
|
||||
};
|
||||
} else {
|
||||
// Otherwise calculate proper values.
|
||||
return {
|
||||
node,
|
||||
deltaX: x - state.lastX, deltaY: y - state.lastY,
|
||||
lastX: state.lastX, lastY: state.lastY,
|
||||
x, y,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Create an data exposed by <Draggable>'s events
|
||||
export function createDraggableData(draggable: Draggable, coreData: DraggableData): DraggableData {
|
||||
return {
|
||||
node: coreData.node,
|
||||
x: draggable.state.x + coreData.deltaX,
|
||||
y: draggable.state.y + coreData.deltaY,
|
||||
deltaX: coreData.deltaX,
|
||||
deltaY: coreData.deltaY,
|
||||
lastX: draggable.state.x,
|
||||
lastY: draggable.state.y
|
||||
};
|
||||
}
|
||||
|
||||
// A lot faster than stringify/parse
|
||||
function cloneBounds(bounds: Bounds): Bounds {
|
||||
return {
|
||||
left: bounds.left,
|
||||
top: bounds.top,
|
||||
right: bounds.right,
|
||||
bottom: bounds.bottom
|
||||
};
|
||||
}
|
||||
|
||||
function findDOMNode(draggable: Draggable | DraggableCore): HTMLElement {
|
||||
const node = ReactDOM.findDOMNode(draggable);
|
||||
if (!node) {
|
||||
throw new Error('<DraggableCore>: Unmounted during event!');
|
||||
}
|
||||
// $FlowIgnore we can't assert on HTMLElement due to tests... FIXME
|
||||
return node;
|
||||
}
|
||||
25
node_modules/react-draggable/lib/utils/shims.js
generated
vendored
Normal file
25
node_modules/react-draggable/lib/utils/shims.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// @flow
|
||||
// @credits https://gist.github.com/rogozhnikoff/a43cfed27c41e4e68cdc
|
||||
export function findInArray(array: Array<any> | TouchList, callback: Function): any {
|
||||
for (let i = 0, length = array.length; i < length; i++) {
|
||||
if (callback.apply(callback, [array[i], i, array])) return array[i];
|
||||
}
|
||||
}
|
||||
|
||||
export function isFunction(func: any): boolean {
|
||||
return typeof func === 'function' || Object.prototype.toString.call(func) === '[object Function]';
|
||||
}
|
||||
|
||||
export function isNum(num: any): boolean {
|
||||
return typeof num === 'number' && !isNaN(num);
|
||||
}
|
||||
|
||||
export function int(a: string): number {
|
||||
return parseInt(a, 10);
|
||||
}
|
||||
|
||||
export function dontSetMe(props: Object, propName: string, componentName: string) {
|
||||
if (props[propName]) {
|
||||
return new Error(`Invalid prop ${propName} passed to ${componentName} - do not set this, set it on the child.`);
|
||||
}
|
||||
}
|
||||
29
node_modules/react-draggable/lib/utils/types.js
generated
vendored
Normal file
29
node_modules/react-draggable/lib/utils/types.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// @flow
|
||||
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
export type DraggableEventHandler = (e: MouseEvent, data: DraggableData) => void | false;
|
||||
|
||||
export type DraggableData = {
|
||||
node: HTMLElement,
|
||||
x: number, y: number,
|
||||
deltaX: number, deltaY: number,
|
||||
lastX: number, lastY: number
|
||||
};
|
||||
|
||||
export type Bounds = {
|
||||
left: number, top: number, right: number, bottom: number
|
||||
};
|
||||
export type ControlPosition = {x: number, y: number};
|
||||
export type EventHandler<T> = (e: T) => void | false;
|
||||
|
||||
// Missing in Flow
|
||||
export class SVGElement extends HTMLElement {
|
||||
}
|
||||
|
||||
// Missing targetTouches
|
||||
export class TouchEvent2 extends TouchEvent {
|
||||
changedTouches: TouchList;
|
||||
targetTouches: TouchList;
|
||||
}
|
||||
|
||||
export type MouseTouchEvent = MouseEvent & TouchEvent2;
|
||||
Reference in New Issue
Block a user