0
Fork 0
mirror of https://github.com/penpot/penpot-plugins.git synced 2025-01-21 06:02:34 -05:00

feat: drag plugin modal

This commit is contained in:
Juanfran 2024-05-10 15:12:47 +02:00
parent 385c5bfa09
commit 7d147b06e3
3 changed files with 119 additions and 0 deletions

View file

@ -0,0 +1,79 @@
import { expect, describe, vi } from 'vitest';
import { dragHandler } from './drag-handler.js';
describe('dragHandler', () => {
let element: HTMLElement;
beforeEach(() => {
element = document.createElement('div');
document.body.appendChild(element);
});
afterEach(() => {
document.body.removeChild(element);
vi.clearAllMocks();
});
it('should attach mousedown event listener to the element', () => {
const addEventListenerMock = vi.spyOn(element, 'addEventListener');
dragHandler(element);
expect(addEventListenerMock).toHaveBeenCalledWith(
'mousedown',
expect.any(Function)
);
});
it('should update element transform on mousemove', () => {
const mouseDownEvent = new MouseEvent('mousedown', {
clientX: 100,
clientY: 100,
});
dragHandler(element);
element.dispatchEvent(mouseDownEvent);
const mouseMoveEvent = new MouseEvent('mousemove', {
clientX: 150,
clientY: 150,
});
document.dispatchEvent(mouseMoveEvent);
expect(element.style.transform).toBe('translate(50px, 50px)');
const mouseMoveEvent2 = new MouseEvent('mousemove', {
clientX: 200,
clientY: 200,
});
document.dispatchEvent(mouseMoveEvent2);
expect(element.style.transform).toBe('translate(100px, 100px)');
});
it('should remove event listeners on mouseup', () => {
const removeEventListenerMock = vi.spyOn(document, 'removeEventListener');
const mouseDownEvent = new MouseEvent('mousedown', {
clientX: 100,
clientY: 100,
});
dragHandler(element);
element.dispatchEvent(mouseDownEvent);
const mouseUpEvent = new MouseEvent('mouseup');
document.dispatchEvent(mouseUpEvent);
expect(removeEventListenerMock).toHaveBeenCalledWith(
'mousemove',
expect.any(Function)
);
expect(removeEventListenerMock).toHaveBeenCalledWith(
'mouseup',
expect.any(Function)
);
});
});

View file

@ -0,0 +1,32 @@
export const dragHandler = (el: HTMLElement) => {
let currentTranslate = { x: 0, y: 0 };
let initialTranslate = { x: 0, y: 0 };
let initialClientPosition = { x: 0, y: 0 };
const handleMouseMove = (moveEvent: MouseEvent) => {
const { clientX: moveX, clientY: moveY } = moveEvent;
const deltaX = moveX - initialClientPosition.x + initialTranslate.x;
const deltaY = moveY - initialClientPosition.y + initialTranslate.y;
currentTranslate = { x: deltaX, y: deltaY };
el.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
};
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
const handleMouseDown = (e: MouseEvent) => {
initialClientPosition = { x: e.clientX, y: e.clientY };
initialTranslate = { x: currentTranslate.x, y: currentTranslate.y };
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
};
el.addEventListener('mousedown', handleMouseDown);
return handleMouseUp;
};

View file

@ -2,6 +2,7 @@ const closeSvg = `
<svg width="16" height="16"xmlns="http://www.w3.org/2000/svg" fill="none"><g class="fills"><rect rx="0" ry="0" width="16" height="16" class="frame-background"/></g><g class="frame-children"><path d="M11.997 3.997 8 8l-3.997 4.003m-.006-8L8 8l4.003 3.997" class="fills"/><g class="strokes"><path d="M11.997 3.997 8 8l-3.997 4.003m-.006-8L8 8l4.003 3.997" style="fill: none; stroke-width: 1; stroke: rgb(143, 157, 163); stroke-opacity: 1; stroke-linecap: round;" class="stroke-shape"/></g></g></svg>`;
import type { PenpotTheme } from '@penpot/plugin-types';
import { dragHandler } from './drag-handler.js';
export class PluginModalElement extends HTMLElement {
constructor() {
@ -10,6 +11,7 @@ export class PluginModalElement extends HTMLElement {
}
#wrapper: HTMLElement | null = null;
#dragEvents: ReturnType<typeof dragHandler> | null = null;
setTheme(theme: PenpotTheme) {
if (this.#wrapper) {
@ -17,6 +19,10 @@ export class PluginModalElement extends HTMLElement {
}
}
disconnectedCallback() {
this.#dragEvents?.();
}
connectedCallback() {
const title = this.getAttribute('title');
const iframeSrc = this.getAttribute('iframe-src');
@ -33,6 +39,7 @@ export class PluginModalElement extends HTMLElement {
this.#wrapper = document.createElement('div');
this.#wrapper.classList.add('wrapper');
this.#dragEvents = dragHandler(this.#wrapper);
const header = document.createElement('div');
header.classList.add('header');
@ -149,6 +156,7 @@ export class PluginModalElement extends HTMLElement {
font-weight: var(--font-weight-bold);
margin: 0;
margin-inline-end: var(--spacing-4);
user-select: none;
}
iframe {