mirror of
https://github.com/penpot/penpot-plugins.git
synced 2025-01-04 13:50:13 -05:00
chore: allow user to resize modal window
This commit is contained in:
parent
51625c3e82
commit
13ea206eab
6 changed files with 66 additions and 20 deletions
1
libs/plugins-runtime/src/lib/assets/resize.svg
Normal file
1
libs/plugins-runtime/src/lib/assets/resize.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg width="16.022" xmlns="http://www.w3.org/2000/svg" height="16.022" viewBox="-0.011 -0.011 16.022 16.022" fill="none"><g data-testid="Group"><g data-testid="Path"><path d="M.011 15.917 15.937-.011" class="fills"/><g class="strokes"><path d="M.011 15.917 15.937-.011" style="fill: none; stroke-width: 1; stroke: rgb(111, 111, 111); stroke-opacity: 1; stroke-linecap: round;" class="stroke-shape"/></g></g><g data-testid="Path"><path d="m11.207 14.601 3.361-3.401" class="fills"/><g class="strokes"><path d="m11.207 14.601 3.361-3.401" style="fill: none; stroke-width: 1; stroke: rgb(111, 111, 111); stroke-opacity: 1; stroke-linecap: round;" class="stroke-shape"/></g></g><g data-testid="Path"><path d="m4.884 16.004 11.112-11.17" class="fills"/><g class="strokes"><path d="m4.884 16.004 11.112-11.17" style="fill: none; stroke-width: 1; stroke: rgb(111, 111, 111); stroke-opacity: 1; stroke-linecap: round;" class="stroke-shape"/></g></g></g></svg>
|
After Width: | Height: | Size: 951 B |
|
@ -44,10 +44,6 @@ describe('createModal', () => {
|
|||
'--modal-block-start',
|
||||
'40px'
|
||||
);
|
||||
expect(modal.style.setProperty).toHaveBeenCalledWith(
|
||||
'--modal-inline-end',
|
||||
'320px'
|
||||
);
|
||||
|
||||
expect(modal.setAttribute).toHaveBeenCalledWith('title', 'Test Modal');
|
||||
expect(modal.setAttribute).toHaveBeenCalledWith(
|
||||
|
@ -83,7 +79,7 @@ describe('createModal', () => {
|
|||
options
|
||||
);
|
||||
|
||||
const expectedWidth = 680; // 1000 - 320 (initialPosition.inlineEnd)
|
||||
const expectedWidth = 710; // 1000 - 270 (initialPosition.inlineEnd)
|
||||
const expectedHeight = 760; // 800 - 40 (initialPosition.blockStart)
|
||||
|
||||
expect(modal.setAttribute).toHaveBeenCalledWith(
|
||||
|
|
|
@ -18,9 +18,16 @@ export function createModal(
|
|||
const defaultWidth = 335;
|
||||
const defaultHeight = 590;
|
||||
|
||||
const maxWidth =
|
||||
(options?.width ?? defaultWidth) > window.innerWidth
|
||||
? window.innerWidth - 290
|
||||
: options?.width ?? defaultWidth;
|
||||
|
||||
const initialPosition = {
|
||||
blockStart: 40,
|
||||
inlineEnd: 320,
|
||||
// To be able to resize the element as expected the position must be absolute from the right.
|
||||
// This value is the length of the window minus the width of the element plus the width of the design tab.
|
||||
inlineStart: window.innerWidth - maxWidth - 290,
|
||||
};
|
||||
|
||||
modal.style.setProperty(
|
||||
|
@ -28,11 +35,10 @@ export function createModal(
|
|||
`${initialPosition.blockStart}px`
|
||||
);
|
||||
modal.style.setProperty(
|
||||
'--modal-inline-end',
|
||||
`${initialPosition.inlineEnd}px`
|
||||
'--modal-inline-start',
|
||||
`${initialPosition.inlineStart}px`
|
||||
);
|
||||
|
||||
const maxWidth = window.innerWidth - initialPosition.inlineEnd;
|
||||
const maxHeight = window.innerHeight - initialPosition.blockStart;
|
||||
let width = Math.min(options?.width || defaultWidth, maxWidth);
|
||||
let height = Math.min(options?.height || defaultHeight, maxHeight);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export const dragHandler = (el: HTMLElement, move?: () => void) => {
|
||||
export const dragHandler = (el: HTMLElement, target: HTMLElement = el, move?: () => void) => {
|
||||
let currentTranslate = { x: 0, y: 0 };
|
||||
let initialTranslate = { x: 0, y: 0 };
|
||||
let initialClientPosition = { x: 0, y: 0 };
|
||||
|
@ -10,7 +10,7 @@ export const dragHandler = (el: HTMLElement, move?: () => void) => {
|
|||
|
||||
currentTranslate = { x: deltaX, y: deltaY };
|
||||
|
||||
el.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
|
||||
target.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
|
||||
|
||||
move?.();
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@ export class PluginModalElement extends HTMLElement {
|
|||
}
|
||||
|
||||
#wrapper: HTMLElement | null = null;
|
||||
#inner: HTMLElement | null = null;
|
||||
#dragEvents: ReturnType<typeof dragHandler> | null = null;
|
||||
|
||||
setTheme(theme: Theme) {
|
||||
|
@ -54,12 +55,20 @@ export class PluginModalElement extends HTMLElement {
|
|||
}
|
||||
|
||||
this.#wrapper = document.createElement('div');
|
||||
this.#inner = document.createElement('div');
|
||||
|
||||
this.#inner.classList.add('inner');
|
||||
|
||||
this.#wrapper.classList.add('wrapper');
|
||||
this.#wrapper.style.inlineSize = `${width}px`;
|
||||
this.#wrapper.style.minInlineSize = `${width}px`;
|
||||
this.#wrapper.style.blockSize = `${height}px`;
|
||||
this.#wrapper.style.minBlockSize = `${height}px`;
|
||||
this.#wrapper.style.maxInlineSize = '90vw';
|
||||
this.#wrapper.style.maxBlockSize = '90vh';
|
||||
|
||||
// move modal to the top
|
||||
this.#dragEvents = dragHandler(this.#wrapper, () => {
|
||||
this.#dragEvents = dragHandler(this.#inner, this.#wrapper, () => {
|
||||
this.calculateZIndex();
|
||||
});
|
||||
|
||||
|
@ -124,8 +133,9 @@ export class PluginModalElement extends HTMLElement {
|
|||
|
||||
this.shadowRoot.appendChild(this.#wrapper);
|
||||
|
||||
this.#wrapper.appendChild(header);
|
||||
this.#wrapper.appendChild(iframe);
|
||||
this.#wrapper.appendChild(this.#inner);
|
||||
this.#inner.appendChild(header);
|
||||
this.#inner.appendChild(iframe);
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.textContent = modalCss;
|
||||
|
|
|
@ -25,18 +25,51 @@
|
|||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
::-webkit-resizer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
inset-block-start: var(--modal-block-start);
|
||||
inset-inline-end: var(--modal-inline-end);
|
||||
inset-inline-start: var(--modal-inline-start);
|
||||
z-index: 1000;
|
||||
padding: 25px;
|
||||
padding: 10px;
|
||||
border-radius: 15px;
|
||||
border: 2px solid var(--color-background-quaternary);
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.3);
|
||||
overflow: hidden;
|
||||
min-inline-size: 25px;
|
||||
min-block-size: 200px;
|
||||
resize: both;
|
||||
&:after {
|
||||
content: '';
|
||||
cursor: se-resize;
|
||||
inline-size: 1rem;
|
||||
block-size: 1rem;
|
||||
background-image: url('../assets/resize.svg');
|
||||
background-position: center;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.inner {
|
||||
padding: 10px;
|
||||
cursor: grab;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
block-size: 100%;
|
||||
& > * {
|
||||
flex: 1;
|
||||
}
|
||||
& > .header {
|
||||
flex: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
|
|
Loading…
Reference in a new issue