diff --git a/src/ui/PenpotExporter.tsx b/src/ui/PenpotExporter.tsx new file mode 100644 index 0000000..49ee19b --- /dev/null +++ b/src/ui/PenpotExporter.tsx @@ -0,0 +1,110 @@ +import { Component } from 'react'; +import slugify from 'slugify'; + +import { createPenpotFile } from './converters'; +import { validateFont } from './validators'; + +type PenpotExporterState = { + missingFonts: Set; + exporting: boolean; +}; + +export default class PenpotExporter extends Component { + state: PenpotExporterState = { + missingFonts: new Set(), + exporting: false + }; + + componentDidMount = () => { + window.addEventListener('message', this.onMessage); + }; + + componentDidUpdate = () => { + this.setDimensions(); + }; + + componentWillUnmount = () => { + window.removeEventListener('message', this.onMessage); + }; + addFontWarning(font: string) { + const newMissingFonts = this.state.missingFonts; + newMissingFonts.add(font); + + this.setState(() => ({ missingFonts: newMissingFonts })); + } + + onCreatePenpot = () => { + this.setState(() => ({ exporting: true })); + parent.postMessage({ pluginMessage: { type: 'export' } }, '*'); + }; + + onCancel = () => { + parent.postMessage({ pluginMessage: { type: 'cancel' } }, '*'); + }; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onMessage = (event: any) => { + if (event.data.pluginMessage.type == 'FIGMAFILE') { + const file = createPenpotFile(event.data.pluginMessage.data); + // validate file.fontNames + file.fontNames.forEach(font => { + if (!validateFont(font)) { + this.addFontWarning(slugify(font.family.toLowerCase())); + } + }); + file.penpotFile.export(); + this.setState(() => ({ exporting: false })); + } + }; + + setDimensions = () => { + const isMissingFonts = this.state.missingFonts.size > 0; + + let width = 300; + let height = 280; + + if (isMissingFonts) { + height += this.state.missingFonts.size * 20; + width = 400; + parent.postMessage({ pluginMessage: { type: 'resize', width: width, height: height } }, '*'); + } + }; + + renderFontWarnings = () => { + return ( + + ); + }; + + render() { + // Update the dimensions of the plugin window based on available data and selections + return ( +
+
+ +

Penpot Exporter

+
+
+
0 ? 'inline' : 'none' }}> +
+ {this.state.missingFonts.size} non-default font + {this.state.missingFonts.size > 1 ? 's' : ''}:{' '} +
+ Ensure fonts are installed in Penpot before importing. +
{this.renderFontWarnings()}
+
+
+
+ + +
+
+ ); + } +} diff --git a/src/ui/ui.tsx b/src/ui/ui.tsx index ed31995..7fae224 100644 --- a/src/ui/ui.tsx +++ b/src/ui/ui.tsx @@ -1,118 +1,11 @@ -import * as React from 'react'; +import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; -import slugify from 'slugify'; -import { createPenpotFile } from './converters'; +import PenpotExporter from './PenpotExporter'; import './ui.css'; -import { validateFont } from './validators'; - -type PenpotExporterState = { - missingFonts: Set; - exporting: boolean; -}; - -export default class PenpotExporter extends React.Component { - state: PenpotExporterState = { - missingFonts: new Set(), - exporting: false - }; - - componentDidMount = () => { - window.addEventListener('message', this.onMessage); - }; - - componentDidUpdate = () => { - this.setDimensions(); - }; - - componentWillUnmount = () => { - window.removeEventListener('message', this.onMessage); - }; - addFontWarning(font: string) { - const newMissingFonts = this.state.missingFonts; - newMissingFonts.add(font); - - this.setState(() => ({ missingFonts: newMissingFonts })); - } - - onCreatePenpot = () => { - this.setState(() => ({ exporting: true })); - parent.postMessage({ pluginMessage: { type: 'export' } }, '*'); - }; - - onCancel = () => { - parent.postMessage({ pluginMessage: { type: 'cancel' } }, '*'); - }; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onMessage = (event: any) => { - if (event.data.pluginMessage.type == 'FIGMAFILE') { - const file = createPenpotFile(event.data.pluginMessage.data); - // validate file.fontNames - file.fontNames.forEach(font => { - if (!validateFont(font)) { - this.addFontWarning(slugify(font.family.toLowerCase())); - } - }); - file.penpotFile.export(); - this.setState(() => ({ exporting: false })); - } - }; - - setDimensions = () => { - const isMissingFonts = this.state.missingFonts.size > 0; - - let width = 300; - let height = 280; - - if (isMissingFonts) { - height += this.state.missingFonts.size * 20; - width = 400; - parent.postMessage({ pluginMessage: { type: 'resize', width: width, height: height } }, '*'); - } - }; - - renderFontWarnings = () => { - return ( -
    - {Array.from(this.state.missingFonts).map(font => ( -
  • {font}
  • - ))} -
- ); - }; - - render() { - // Update the dimensions of the plugin window based on available data and selections - return ( -
-
- -

Penpot Exporter

-
-
-
0 ? 'inline' : 'none' }}> -
- {this.state.missingFonts.size} non-default font - {this.state.missingFonts.size > 1 ? 's' : ''}:{' '} -
- Ensure fonts are installed in Penpot before importing. -
{this.renderFontWarnings()}
-
-
-
- - -
-
- ); - } -} createRoot(document.getElementById('penpot-export-page') as HTMLElement).render( - + - + ); diff --git a/tsconfig.json b/tsconfig.json index 75d4625..d869851 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "esModuleInterop": true, "isolatedModules": true, "skipLibCheck": true, - "jsx": "react", + "jsx": "react-jsx", "lib": ["DOM", "ES6"], "target": "es2017", "module": "ESNext",