publ-echo 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/bin/cli.js +8 -0
- package/bitbucket-pipelines.yml +35 -0
- package/package.json +51 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +43 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +25 -0
- package/public/robots.txt +3 -0
- package/src/App.tsx +28 -0
- package/src/examples/ReactGridLayout/ReactGridLayoutShowcase01.tsx +80 -0
- package/src/examples/ReactGridLayout/index.ts +1 -0
- package/src/examples/ResponsiveGridLayout/ResponsiveGridLayoutShowcase01.tsx +114 -0
- package/src/examples/ResponsiveGridLayout/index.ts +1 -0
- package/src/examples/index.ts +2 -0
- package/src/examples/utils.ts +15 -0
- package/src/index.tsx +21 -0
- package/src/lib/Draggable/Draggable.tsx +303 -0
- package/src/lib/Draggable/DraggableCore.tsx +352 -0
- package/src/lib/Draggable/constants.ts +12 -0
- package/src/lib/Draggable/index.ts +2 -0
- package/src/lib/Draggable/types.ts +74 -0
- package/src/lib/Draggable/utils/domHelpers.ts +284 -0
- package/src/lib/Draggable/utils/getPrefix.ts +42 -0
- package/src/lib/Draggable/utils/positionHelpers.ts +49 -0
- package/src/lib/Draggable/utils/types.ts +41 -0
- package/src/lib/Draggable/utils/validationHelpers.ts +23 -0
- package/src/lib/GridItem/GridItem.tsx +493 -0
- package/src/lib/GridItem/index.ts +1 -0
- package/src/lib/GridItem/types.ts +121 -0
- package/src/lib/GridItem/utils/calculateUtils.ts +173 -0
- package/src/lib/GridLayoutEditor/ReactGridLayout.tsx +662 -0
- package/src/lib/GridLayoutEditor/ResponsiveGridLayout.tsx +204 -0
- package/src/lib/GridLayoutEditor/index.ts +9 -0
- package/src/lib/GridLayoutEditor/styles/styles.css +133 -0
- package/src/lib/GridLayoutEditor/types.ts +199 -0
- package/src/lib/GridLayoutEditor/utils/renderHelpers.ts +737 -0
- package/src/lib/GridLayoutEditor/utils/responsiveUtils.ts +111 -0
- package/src/lib/PreviewGLE/ReactGridLayoutPreview.tsx +46 -0
- package/src/lib/PreviewGLE/ResponsiveGridLayoutPreview.tsx +54 -0
- package/src/lib/PreviewGLE/index.ts +2 -0
- package/src/lib/Resizable/Resizable.tsx +323 -0
- package/src/lib/Resizable/ResizableBox.tsx +109 -0
- package/src/lib/Resizable/index.ts +1 -0
- package/src/lib/Resizable/styles/styles.css +76 -0
- package/src/lib/Resizable/types.ts +96 -0
- package/src/lib/Resizable/utils/cloneElement.ts +15 -0
- package/src/lib/components/WidthProvider.tsx +71 -0
- package/src/lib/components/index.ts +1 -0
- package/src/lib/components/types.ts +19 -0
- package/src/lib/index.ts +4 -0
- package/src/react-app-env.d.ts +1 -0
- package/src/reportWebVitals.ts +15 -0
- package/src/setupTests.ts +5 -0
- package/src/utils/types.ts +3 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ReactElement, RefObject } from "react";
|
|
2
|
+
import {
|
|
3
|
+
ControlPosition,
|
|
4
|
+
DraggableEventHandler,
|
|
5
|
+
PositionOffsetControlPosition,
|
|
6
|
+
} from "./utils/types";
|
|
7
|
+
|
|
8
|
+
// draggableCore
|
|
9
|
+
export type DraggableCoreState = {
|
|
10
|
+
dragging: boolean;
|
|
11
|
+
lastX: number;
|
|
12
|
+
lastY: number;
|
|
13
|
+
touchIdentifier?: number | null;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type DraggableData = {
|
|
17
|
+
node: HTMLElement;
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
deltaX: number;
|
|
21
|
+
deltaY: number;
|
|
22
|
+
lastX: number;
|
|
23
|
+
lastY: number;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type DraggableCoreDefaultProps = {
|
|
27
|
+
allowAnyClick?: boolean;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
enableUserSelectHack?: boolean;
|
|
30
|
+
onStart?: DraggableEventHandler | Function;
|
|
31
|
+
onDrag?: DraggableEventHandler | Function;
|
|
32
|
+
onStop?: DraggableEventHandler | Function;
|
|
33
|
+
onMouseDown?: (e: MouseEvent) => void;
|
|
34
|
+
scale?: number;
|
|
35
|
+
cancel?: string;
|
|
36
|
+
children: ReactElement<any>;
|
|
37
|
+
offsetParent?: HTMLElement;
|
|
38
|
+
grid?: [number, number];
|
|
39
|
+
handle?: string;
|
|
40
|
+
nodeRef?: RefObject<HTMLElement>;
|
|
41
|
+
className?: string;
|
|
42
|
+
style?: Object;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// draggable type
|
|
46
|
+
export type DraggableState = {
|
|
47
|
+
dragging: boolean;
|
|
48
|
+
dragged: boolean;
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
slackX: number;
|
|
52
|
+
slackY: number;
|
|
53
|
+
isElementSVG: boolean;
|
|
54
|
+
prevPropsPosition?: ControlPosition;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type DraggablePositionType = {
|
|
58
|
+
positionOffset?: PositionOffsetControlPosition;
|
|
59
|
+
position?: ControlPosition;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type DraggableProps = DraggablePositionType & DraggableCoreDefaultProps;
|
|
63
|
+
|
|
64
|
+
export type PropsWithChildren<P> = P & {
|
|
65
|
+
children: ReactElement<any>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type AxisType = "both" | "x" | "y" | "none";
|
|
69
|
+
|
|
70
|
+
export type DraggableEvent =
|
|
71
|
+
| React.MouseEvent<HTMLElement | SVGElement>
|
|
72
|
+
| React.TouchEvent<HTMLElement | SVGElement>
|
|
73
|
+
| MouseEvent
|
|
74
|
+
| TouchEvent;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import browserPrefix, { browserPrefixToKey } from "./getPrefix";
|
|
3
|
+
import type {
|
|
4
|
+
ControlPosition,
|
|
5
|
+
PositionOffsetControlPosition,
|
|
6
|
+
MouseTouchEvent,
|
|
7
|
+
EventWithOffset,
|
|
8
|
+
EventHandler,
|
|
9
|
+
} from "./types";
|
|
10
|
+
import { findInArray, int, isFunction } from "./validationHelpers";
|
|
11
|
+
|
|
12
|
+
export const matchSelector = (el: Node, selector: string): boolean => {
|
|
13
|
+
let matchedSelector = "";
|
|
14
|
+
const selectors = [
|
|
15
|
+
"matches",
|
|
16
|
+
"webkitMatchesSelector",
|
|
17
|
+
// "mozMatchesSelector",
|
|
18
|
+
// "msMatchesSelector",
|
|
19
|
+
// "oMatchesSelector",
|
|
20
|
+
];
|
|
21
|
+
const callback = (method: keyof Element) => {
|
|
22
|
+
return isFunction((el as Element)[method]);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
if (!matchedSelector) {
|
|
26
|
+
matchedSelector = findInArray(selectors, callback);
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
matchedSelector === "matches" ||
|
|
30
|
+
matchedSelector === "webkitMatchesSelector"
|
|
31
|
+
) {
|
|
32
|
+
return (el as Element)[matchedSelector](selector);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const matchSelectorAndParentsTo = (
|
|
40
|
+
el: Node,
|
|
41
|
+
selector: string,
|
|
42
|
+
baseNode: Node
|
|
43
|
+
): boolean => {
|
|
44
|
+
let node = el;
|
|
45
|
+
|
|
46
|
+
do {
|
|
47
|
+
if (matchSelector(node, selector)) return true;
|
|
48
|
+
if (node === baseNode) return false;
|
|
49
|
+
if (node.parentNode) node = node.parentNode;
|
|
50
|
+
} while (node);
|
|
51
|
+
|
|
52
|
+
return false;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const addEvent = (
|
|
56
|
+
el: Node,
|
|
57
|
+
eventType: string,
|
|
58
|
+
handler: EventHandler<any>,
|
|
59
|
+
inputOptions?: Object
|
|
60
|
+
): void => {
|
|
61
|
+
if (!el) return;
|
|
62
|
+
|
|
63
|
+
const options = { capture: true, ...inputOptions };
|
|
64
|
+
|
|
65
|
+
if (el.addEventListener) {
|
|
66
|
+
el.addEventListener(eventType, handler, options);
|
|
67
|
+
}
|
|
68
|
+
// if (el.addEventListener) {
|
|
69
|
+
// el.addEventListener(eventType, handler, options);
|
|
70
|
+
// } else {
|
|
71
|
+
// (el as { [key: string]: any })['on' + eventType] = handler;
|
|
72
|
+
// }
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const removeEvent = (
|
|
76
|
+
el: Node,
|
|
77
|
+
eventType: string,
|
|
78
|
+
handler: EventHandler<any>,
|
|
79
|
+
inputOptions?: Object
|
|
80
|
+
): void => {
|
|
81
|
+
if (!el) return;
|
|
82
|
+
|
|
83
|
+
const options = { capture: true, ...inputOptions };
|
|
84
|
+
|
|
85
|
+
if (el.removeEventListener) {
|
|
86
|
+
el.removeEventListener(eventType, handler, options);
|
|
87
|
+
}
|
|
88
|
+
// if (el.removeEventListener) {
|
|
89
|
+
// el.removeEventListener(eventType, handler, options);
|
|
90
|
+
// } else {
|
|
91
|
+
// (el as { [key: string]: any })['on' + eventType] = null;
|
|
92
|
+
// }
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const outerHeight = (node: HTMLElement): number => {
|
|
96
|
+
let height = node.clientHeight;
|
|
97
|
+
const computedStyle = node.ownerDocument.defaultView?.getComputedStyle(node);
|
|
98
|
+
|
|
99
|
+
if (computedStyle) {
|
|
100
|
+
height += int(computedStyle.borderTopWidth);
|
|
101
|
+
height += int(computedStyle.borderBottomWidth);
|
|
102
|
+
return height;
|
|
103
|
+
} else {
|
|
104
|
+
return height;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const outerWidth = (node: HTMLElement): number => {
|
|
109
|
+
let width = node.clientWidth;
|
|
110
|
+
const computedStyle = node.ownerDocument.defaultView?.getComputedStyle(node);
|
|
111
|
+
|
|
112
|
+
if (computedStyle) {
|
|
113
|
+
width += int(computedStyle.borderLeftWidth);
|
|
114
|
+
width += int(computedStyle.borderRightWidth);
|
|
115
|
+
return width;
|
|
116
|
+
} else {
|
|
117
|
+
return width;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
export const innerHeight = (node: HTMLElement): number => {
|
|
121
|
+
let height = node.clientHeight;
|
|
122
|
+
const computedStyle = node.ownerDocument.defaultView?.getComputedStyle(node);
|
|
123
|
+
|
|
124
|
+
if (computedStyle) {
|
|
125
|
+
height -= int(computedStyle.paddingTop);
|
|
126
|
+
height -= int(computedStyle.paddingBottom);
|
|
127
|
+
return height;
|
|
128
|
+
} else {
|
|
129
|
+
return height;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const innerWidth = (node: HTMLElement): number => {
|
|
134
|
+
let width = node.clientWidth;
|
|
135
|
+
|
|
136
|
+
const computedStyle = node.ownerDocument.defaultView?.getComputedStyle(node);
|
|
137
|
+
|
|
138
|
+
if (computedStyle) {
|
|
139
|
+
width -= int(computedStyle.paddingLeft);
|
|
140
|
+
width -= int(computedStyle.paddingRight);
|
|
141
|
+
|
|
142
|
+
return width;
|
|
143
|
+
} else {
|
|
144
|
+
return width;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const offsetXYFromParent = (
|
|
149
|
+
evt: EventWithOffset,
|
|
150
|
+
offsetParent: Element,
|
|
151
|
+
scale: number
|
|
152
|
+
): ControlPosition => {
|
|
153
|
+
const isBody = offsetParent.ownerDocument.body;
|
|
154
|
+
const offsetParentRect = isBody
|
|
155
|
+
? { left: 0, top: 0 }
|
|
156
|
+
: offsetParent.getBoundingClientRect();
|
|
157
|
+
|
|
158
|
+
const x =
|
|
159
|
+
(evt.clientX + offsetParent.scrollLeft - offsetParentRect.left) / scale;
|
|
160
|
+
const y =
|
|
161
|
+
(evt.clientY + offsetParent.scrollTop - offsetParentRect.top) / scale;
|
|
162
|
+
|
|
163
|
+
return { x, y };
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export const createCSSTransform = (
|
|
167
|
+
controlPos: ControlPosition,
|
|
168
|
+
positionOffset?: PositionOffsetControlPosition
|
|
169
|
+
): Object => {
|
|
170
|
+
const translation = getTranslation(controlPos, "px", positionOffset);
|
|
171
|
+
return { [browserPrefixToKey("transform", browserPrefix)]: translation };
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export const createSVGTransform = (
|
|
175
|
+
controlPos: ControlPosition,
|
|
176
|
+
positionOffset?: PositionOffsetControlPosition
|
|
177
|
+
): string => {
|
|
178
|
+
const translation = getTranslation(controlPos, "", positionOffset);
|
|
179
|
+
|
|
180
|
+
return translation;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const getTranslation = (
|
|
184
|
+
{ x, y }: ControlPosition,
|
|
185
|
+
unitSuffix: string,
|
|
186
|
+
positionOffset?: PositionOffsetControlPosition
|
|
187
|
+
): string => {
|
|
188
|
+
let translation = `translate(${x}${unitSuffix},${y}${unitSuffix})`;
|
|
189
|
+
|
|
190
|
+
if (positionOffset) {
|
|
191
|
+
const defaultX = `${
|
|
192
|
+
typeof positionOffset.x === "string"
|
|
193
|
+
? positionOffset.x
|
|
194
|
+
: positionOffset.x + unitSuffix
|
|
195
|
+
}`;
|
|
196
|
+
const defaultY = `${
|
|
197
|
+
typeof positionOffset.y === "string"
|
|
198
|
+
? positionOffset.y
|
|
199
|
+
: positionOffset.y + unitSuffix
|
|
200
|
+
}`;
|
|
201
|
+
|
|
202
|
+
translation = `translate(${defaultX}, ${defaultY})` + translation;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return translation;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
export const getTouch = (
|
|
209
|
+
e: MouseTouchEvent,
|
|
210
|
+
identifier: number
|
|
211
|
+
): { clientX: number; clientY: number } => {
|
|
212
|
+
return (
|
|
213
|
+
(e.targetTouches &&
|
|
214
|
+
findInArray(e.targetTouches, (t: any) => identifier === t.identifier)) ||
|
|
215
|
+
(e.changedTouches &&
|
|
216
|
+
findInArray(e.changedTouches, (t: any) => identifier === t.identifier))
|
|
217
|
+
);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export const getTouchIdentifier = (e: MouseTouchEvent): number | undefined => {
|
|
221
|
+
if (e.targetTouches && e.targetTouches[0]) {
|
|
222
|
+
return e.targetTouches[0].identifier;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (e.changedTouches && e.changedTouches[0]) {
|
|
226
|
+
return e.changedTouches[0].identifier;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export const addUserSelectStyles = (doc?: Document) => {
|
|
231
|
+
if (!doc) return;
|
|
232
|
+
|
|
233
|
+
let styleEl = doc.getElementById("react-draggable-style-el");
|
|
234
|
+
|
|
235
|
+
if (!styleEl) {
|
|
236
|
+
styleEl = doc.createElement("style");
|
|
237
|
+
styleEl.id = "react-draggable-style-el";
|
|
238
|
+
styleEl.innerHTML =
|
|
239
|
+
".react-draggable-transparent-selection *::-moz-selection {all: inherit;}\n";
|
|
240
|
+
styleEl.innerHTML +=
|
|
241
|
+
".react-draggable-transparent-selection *::selection {all: inherit;}\n";
|
|
242
|
+
doc.getElementsByTagName("head")[0].appendChild(styleEl);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (doc.body) addClassName(doc.body, "react-draggable-transparent-selection");
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
export const removeUserSelectStyles = (doc?: Document) => {
|
|
249
|
+
if (!doc) return;
|
|
250
|
+
|
|
251
|
+
if (doc.body) {
|
|
252
|
+
removeClassName(doc.body, "react-draggable-transparent-selection");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (doc.getSelection()) {
|
|
256
|
+
doc.getSelection()?.empty();
|
|
257
|
+
} else {
|
|
258
|
+
const selection = (doc.defaultView || window).getSelection();
|
|
259
|
+
if (selection && selection.type !== "Caret") {
|
|
260
|
+
selection.removeAllRanges();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
export const addClassName = (el: HTMLElement, className: string) => {
|
|
266
|
+
if (el.classList) {
|
|
267
|
+
el.classList.add(className);
|
|
268
|
+
} else {
|
|
269
|
+
if (!el.className.match(new RegExp(`(?:^|\\s)${className}(?!\\S)`))) {
|
|
270
|
+
el.className += ` ${className}`;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
export const removeClassName = (el: HTMLElement, className: string) => {
|
|
276
|
+
if (el.classList) {
|
|
277
|
+
el.classList.remove(className);
|
|
278
|
+
} else {
|
|
279
|
+
el.className = el.className.replace(
|
|
280
|
+
new RegExp(`(?:^|\\s)${className}(?!\\S)`, "g"),
|
|
281
|
+
""
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const prefixes = ["Moz", "Webkit", "O", "ms"];
|
|
2
|
+
|
|
3
|
+
export function getPrefix(prop: string = "transform"): string {
|
|
4
|
+
if (typeof window === "undefined") return "";
|
|
5
|
+
|
|
6
|
+
const style = window.document?.documentElement?.style;
|
|
7
|
+
if (!style) return "";
|
|
8
|
+
|
|
9
|
+
if (prop in style) return "";
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < prefixes.length; i++) {
|
|
12
|
+
if (browserPrefixToKey(prop, prefixes[i]) in style) return prefixes[i];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function browserPrefixToKey(prop: string, prefix: string): string {
|
|
19
|
+
return prefix ? `${prefix}${kebabToTitleCase(prop)}` : prop;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function browserPrefixToStyle(prop: string, prefix: string): string {
|
|
23
|
+
return prefix ? `-${prefix.toLowerCase()}-${prop}` : prop;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function kebabToTitleCase(str: string): string {
|
|
27
|
+
let out = "";
|
|
28
|
+
let shouldCapitalize = true;
|
|
29
|
+
for (let i = 0; i < str.length; i++) {
|
|
30
|
+
if (shouldCapitalize) {
|
|
31
|
+
out += str[i].toUpperCase();
|
|
32
|
+
shouldCapitalize = false;
|
|
33
|
+
} else if (str[i] === "-") {
|
|
34
|
+
shouldCapitalize = true;
|
|
35
|
+
} else {
|
|
36
|
+
out += str[i];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default getPrefix();
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { AxisType, DraggableData, DraggableState } from "./../types";
|
|
2
|
+
import type { Bounds } from "./types";
|
|
3
|
+
|
|
4
|
+
export function snapToGrid(
|
|
5
|
+
grid: [number, number],
|
|
6
|
+
pendingX: number,
|
|
7
|
+
pendingY: number
|
|
8
|
+
): [number, number] {
|
|
9
|
+
const x = Math.round(pendingX / grid[0]) * grid[0];
|
|
10
|
+
const y = Math.round(pendingY / grid[1]) * grid[1];
|
|
11
|
+
|
|
12
|
+
return [x, y];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function canDragX(axis: AxisType): boolean {
|
|
16
|
+
return axis === "both" || axis === "x";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function canDragY(axis: AxisType): boolean {
|
|
20
|
+
return axis === "both" || axis === "y";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const cloneBounds = (bounds: Bounds): Bounds => {
|
|
24
|
+
return {
|
|
25
|
+
left: bounds.left,
|
|
26
|
+
top: bounds.top,
|
|
27
|
+
right: bounds.right,
|
|
28
|
+
bottom: bounds.bottom,
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const createDraggableData = (
|
|
33
|
+
draggableState: DraggableState,
|
|
34
|
+
scale: number,
|
|
35
|
+
coreData: DraggableData
|
|
36
|
+
): DraggableData => {
|
|
37
|
+
const deltaX = coreData.deltaX / scale;
|
|
38
|
+
const deltaY = coreData.deltaY / scale;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
node: coreData.node,
|
|
42
|
+
x: draggableState.x + deltaX,
|
|
43
|
+
y: draggableState.y + deltaY,
|
|
44
|
+
deltaX,
|
|
45
|
+
deltaY,
|
|
46
|
+
lastX: draggableState.x,
|
|
47
|
+
lastY: draggableState.y,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { DraggableData } from "../types";
|
|
2
|
+
|
|
3
|
+
export type DraggableEvent =
|
|
4
|
+
| React.MouseEvent<HTMLElement | SVGElement>
|
|
5
|
+
| React.TouchEvent<HTMLElement | SVGElement>
|
|
6
|
+
| MouseEvent
|
|
7
|
+
| TouchEvent;
|
|
8
|
+
|
|
9
|
+
export type DraggableEventHandler = (
|
|
10
|
+
e: MouseEvent,
|
|
11
|
+
data: DraggableData,
|
|
12
|
+
el?: HTMLElement | null
|
|
13
|
+
) => void | false;
|
|
14
|
+
|
|
15
|
+
export type Bounds = {
|
|
16
|
+
left: number;
|
|
17
|
+
top: number;
|
|
18
|
+
right: number;
|
|
19
|
+
bottom: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ControlPosition = { x: number; y: number };
|
|
23
|
+
export type PositionOffsetControlPosition = {
|
|
24
|
+
x: number | string;
|
|
25
|
+
y: number | string;
|
|
26
|
+
};
|
|
27
|
+
export type EventHandler<T> = (e: T) => void | false;
|
|
28
|
+
|
|
29
|
+
export interface SVGElement extends HTMLElement {}
|
|
30
|
+
|
|
31
|
+
export interface TouchEvent2 extends TouchEvent {
|
|
32
|
+
changedTouches: TouchList;
|
|
33
|
+
targetTouches: TouchList;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type MouseTouchEvent = MouseEvent & TouchEvent2;
|
|
37
|
+
|
|
38
|
+
export type EventWithOffset = {
|
|
39
|
+
clientX: number;
|
|
40
|
+
clientY: number;
|
|
41
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const findInArray = (
|
|
2
|
+
array: Array<any> | TouchList,
|
|
3
|
+
callback: Function
|
|
4
|
+
): any => {
|
|
5
|
+
for (let i = 0, length = array.length; i < length; i++) {
|
|
6
|
+
if (callback.apply(callback, [array[i], i, array])) return array[i];
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const isFunction = (func: any): boolean => {
|
|
11
|
+
return (
|
|
12
|
+
typeof func === "function" ||
|
|
13
|
+
Object.prototype.toString.call(func) === "[object Function]"
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const isNum = (num: any): boolean => {
|
|
18
|
+
return typeof num === "number" && !isNaN(num);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const int = (a: string): number => {
|
|
22
|
+
return parseInt(a, 10);
|
|
23
|
+
};
|