0
Fork 0
mirror of https://github.com/penpot/penpot-exporter-figma-plugin.git synced 2024-12-21 21:23:06 -05:00

Dynamic plugin size calculation, and cap the height to a safe value (#98)

* dynamic size

* fixes

* fixes

* fix dynamic size

* add changelog

---------

Co-authored-by: Jordi Sala Morales <jordism91@gmail.com>
This commit is contained in:
Alex Sánchez 2024-05-13 10:08:26 +02:00 committed by GitHub
parent 7cae18460c
commit 8d5c5c15eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 700 additions and 453 deletions

View file

@ -0,0 +1,5 @@
---
"penpot-exporter": patch
---
Recalculate better the plugin height and limit it to a safer value so it does not get out of the screen

934
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -29,27 +29,27 @@
"react-hook-form": "^7.51",
"romans": "^2.0",
"slugify": "^1.6",
"svg-path-parser": "^1.1"
"svg-path-parser": "^1.1",
"use-resize-observer": "^9.1"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5",
"@changesets/cli": "^2.27",
"@figma/eslint-plugin-figma-plugins": "^0.15",
"@figma/plugin-typings": "^1.92",
"@figma/plugin-typings": "^1.93",
"@preact/preset-vite": "^2.8",
"@trivago/prettier-plugin-sort-imports": "^4.3",
"@types/svg-path-parser": "^1.1",
"@typescript-eslint/eslint-plugin": "^7.8",
"@typescript-eslint/parser": "^7.8",
"@vitejs/plugin-react-swc": "^3.6",
"concurrently": "^8.2",
"esbuild": "^0.20",
"esbuild": "^0.21",
"eslint": "^8.57",
"eslint-config-prettier": "^9.1",
"eslint-plugin-prettier": "^5.1",
"eslint-plugin-react": "^7.34",
"prettier": "^3.2",
"stylelint": "^16.4",
"stylelint": "^16.5",
"stylelint-config-standard": "^36.0",
"typescript": "^5.4",
"vite": "^5.2",

View file

@ -1,9 +1,11 @@
import { findAllTextNodes } from './findAllTextnodes';
import { handleExportMessage } from './handleExportMessage';
import { BASE_WIDTH, LOADING_HEIGHT } from './pluginSizes';
import { registerChange } from './registerChange';
figma.showUI(__html__, { themeColors: true, width: BASE_WIDTH, height: LOADING_HEIGHT });
const BASE_HEIGHT = 135;
const BASE_WIDTH = 290;
figma.showUI(__html__, { themeColors: true, width: BASE_WIDTH, height: BASE_HEIGHT });
figma.ui.onmessage = message => {
if (message.type === 'ready') {
@ -21,6 +23,10 @@ figma.ui.onmessage = message => {
if (message.type === 'reload') {
findAllTextNodes();
}
if (message.type === 'resize') {
figma.ui.resize(BASE_WIDTH, message.height);
}
};
figma.on('currentpagechange', () => {

View file

@ -1,9 +1,3 @@
import {
BASE_WIDTH,
MISSING_FONTS_TEXT_HEIGHT,
MISSING_SINGLE_FONT_HEIGHT,
NORMAL_HEIGHT
} from './pluginSizes';
import { registerChange } from './registerChange';
import { isGoogleFont } from './translators/text/font/gfonts';
import { isLocalFont } from './translators/text/font/local';
@ -34,10 +28,5 @@ export const findAllTextNodes = async () => {
data: Array.from(fonts)
});
const newHeight =
NORMAL_HEIGHT +
(fonts.size > 0 ? MISSING_FONTS_TEXT_HEIGHT + fonts.size * MISSING_SINGLE_FONT_HEIGHT : 0);
figma.ui.resize(BASE_WIDTH, newHeight);
figma.currentPage.once('nodechange', registerChange);
};

View file

@ -1,8 +0,0 @@
export const LOADING_HEIGHT = 130;
export const NORMAL_HEIGHT = LOADING_HEIGHT + 5;
export const BASE_WIDTH = 290;
export const MISSING_FONTS_TEXT_HEIGHT = 195;
export const MISSING_SINGLE_FONT_HEIGHT = 65;
export const NEEDS_RELOAD_TEXT_HEIGHT = 90;

View file

@ -1,6 +1,3 @@
import { BASE_WIDTH, NEEDS_RELOAD_TEXT_HEIGHT, NORMAL_HEIGHT } from './pluginSizes';
export const registerChange = () => {
figma.ui.postMessage({ type: 'CHANGES_DETECTED' });
figma.ui.resize(BASE_WIDTH, NORMAL_HEIGHT + NEEDS_RELOAD_TEXT_HEIGHT);
};

View file

@ -1,21 +1,39 @@
import { useEffect } from 'react';
import useResizeObserver from 'use-resize-observer';
import Penpot from '@ui/assets/penpot.svg?react';
import { PenpotExporter } from '@ui/components/PenpotExporter';
import { Stack } from '@ui/components/Stack';
import { Wrapper } from './components/Wrapper/Wrapper';
export const App = () => (
<Wrapper>
<Stack space="medium">
<Penpot
style={{
alignSelf: 'center',
height: 'auto',
width: '8.125rem',
fill: 'var(--figma-color-icon)'
}}
/>
<PenpotExporter />
</Stack>
</Wrapper>
);
// Safe default value to avoid overflowing from the screen
const MAX_HEIGHT = 800;
export const App = () => {
const { ref, height } = useResizeObserver<HTMLDivElement>({ box: 'border-box' });
useEffect(() => {
if (height === undefined) return;
const capHeight = Math.min(height, MAX_HEIGHT);
parent.postMessage({ pluginMessage: { type: 'resize', height: capHeight } }, '*');
}, [height]);
return (
<Wrapper ref={ref} overflowing={(height ?? 0) > MAX_HEIGHT}>
<Stack space="medium">
<Penpot
style={{
alignSelf: 'center',
height: 'auto',
width: '8.125rem',
fill: 'var(--figma-color-icon)'
}}
/>
<PenpotExporter />
</Stack>
</Wrapper>
);
};

View file

@ -6,12 +6,12 @@
flex-direction: var(--direction);
gap: var(--spacing);
& > * {
flex: 1;
}
.stack-row {
--direction: row;
& > * {
flex: 1;
}
}
.stack-small {

View file

@ -1,3 +1,7 @@
.wrapper {
margin: 1.5rem 1rem 0;
padding: 1.5rem 1rem 1rem;
.wrapper-overflow {
/* Empty class used to detect overflow on the body */
}
}

View file

@ -1,15 +1,27 @@
import { CSSProperties, PropsWithChildren } from 'react';
import classNames from 'classnames';
import { CSSProperties, PropsWithChildren, forwardRef } from 'react';
import styles from './Wrapper.module.css';
type WrapperProps = PropsWithChildren & {
style?: CSSProperties;
overflowing?: boolean;
};
export const Wrapper = ({ style, children }: WrapperProps) => {
return (
<div className={styles.wrapper} style={style}>
{children}
</div>
);
};
const Wrapper = forwardRef<HTMLDivElement, WrapperProps>(
({ style, overflowing = false, children }: WrapperProps, ref) => {
return (
<div
ref={ref}
className={classNames({ [styles.wrapper]: true, [styles.wrapperOverflow]: overflowing })}
style={style}
>
{children}
</div>
);
}
);
Wrapper.displayName = 'Wrapper';
export { Wrapper };

View file

@ -1,40 +1,3 @@
*,
*::before,
*::after {
box-sizing: border-box;
}
* {
margin: 0;
}
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
input,
button,
textarea,
select {
font: inherit;
}
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
body :not:has(.wrapper-overflow) {
overflow-y: hidden;
}

View file

@ -4,6 +4,7 @@ import { createRoot } from 'react-dom/client';
import { App } from './App';
import './main.css';
import './reset.css';
createRoot(document.getElementById('root') as HTMLElement).render(
<StrictMode>

40
ui-src/reset.css Normal file
View file

@ -0,0 +1,40 @@
*,
*::before,
*::after {
box-sizing: border-box;
}
* {
margin: 0;
}
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
input,
button,
textarea,
select {
font: inherit;
}
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}