@platform/react
Version:
React refs and helpers.
103 lines (102 loc) • 3.03 kB
JavaScript
import { Subject } from 'rxjs';
import { map, share, takeUntil } from 'rxjs/operators';
import { events } from '../events';
const EMPTY = { x: -1, y: -1 };
export class DragPositionEvent {
constructor(options) {
const { type, el, event, start } = options;
this.type = type;
this.el = el;
this.event = event;
this.start = start;
}
get client() {
const { clientX: x, clientY: y } = this.event;
return { x, y };
}
get screen() {
const { screenX: x, screenY: y } = this.event;
return { x, y };
}
get delta() {
const start = this.start || EMPTY;
const { screenX, screenY } = this.event;
const x = screenX - start.x;
const y = screenY - start.y;
return { x, y };
}
get element() {
const position = offsetPosition(this.el);
const { clientX, clientY } = this.event;
return { x: clientX - position.left, y: clientY - position.top };
}
toObject() {
return {
type: this.type,
client: this.client,
screen: this.screen,
element: this.element,
delta: this.delta,
start: this.start,
};
}
clone(type) {
return new DragPositionEvent({
type,
el: this.el,
event: this.event,
start: this.start,
});
}
}
export const position = (options) => {
const dispose$ = new Subject();
const events$ = new Subject();
const mouseUp$ = events.mouseUp$.pipe(takeUntil(dispose$));
const el = options.el;
let start;
let prev;
const move$ = events.mouseMove$.pipe(takeUntil(dispose$), map((e) => {
if (!start) {
start = { x: e.screenX, y: e.screenY };
}
prev = new DragPositionEvent({
type: 'DRAG',
el,
event: e,
start,
});
return prev;
}), takeUntil(mouseUp$));
move$.subscribe((e) => events$.next(e));
mouseUp$.subscribe((e) => {
const arg = prev
? prev.clone('COMPLETE')
: new DragPositionEvent({
type: 'COMPLETE',
el,
event: e,
start,
});
events$.next(arg);
api.dispose();
});
const api = {
isComplete: false,
events$: events$.pipe(share()),
dispose$: dispose$.pipe(share()),
dispose: () => {
dispose$.next();
dispose$.complete();
api.isComplete = true;
},
};
return api;
};
export const offsetPosition = (el) => {
const rect = el.getBoundingClientRect();
const doc = document.documentElement ? document.documentElement : undefined;
const scrollLeft = window.pageXOffset || (doc ? doc.scrollLeft : 0);
const scrollTop = window.pageYOffset || (doc ? doc.scrollTop : 0);
return { top: rect.top + scrollTop, left: rect.left + scrollLeft };
};