From b6127adf3ecafa218ac733a8e4d2555c5af2e830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20S=C3=A1nchez?= Date: Thu, 20 Jun 2024 09:22:19 +0200 Subject: [PATCH 01/15] color library --- ui-src/components/ExporterProgress.tsx | 8 +++++++- ui-src/parser/creators/createComponentsLibrary.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ui-src/components/ExporterProgress.tsx b/ui-src/components/ExporterProgress.tsx index bc9e64a6..4bbe155b 100644 --- a/ui-src/components/ExporterProgress.tsx +++ b/ui-src/components/ExporterProgress.tsx @@ -30,7 +30,13 @@ const stepMessages: Record = { current: 'Currently processing layer' }, fills: { - total: 'color libraries fetched 🎨' + total: 'color libraries fetched ' + }, + format: { + total: 'formatting color libraries 🎨' + }, + libraries: { + total: 'color libraries built 🎨' }, format: { total: 'formatting color libraries 🎨' diff --git a/ui-src/parser/creators/createComponentsLibrary.ts b/ui-src/parser/creators/createComponentsLibrary.ts index a00837f2..40541fcc 100644 --- a/ui-src/parser/creators/createComponentsLibrary.ts +++ b/ui-src/parser/creators/createComponentsLibrary.ts @@ -23,7 +23,7 @@ export const createComponentsLibrary = async (file: PenpotFile) => { }); for (const uiComponent of components) { - createComponentLibrary(file, uiComponent); + await createComponentLibrary(file, uiComponent); sendMessage({ type: 'PROGRESS_PROCESSED_ITEMS', From 908acfb99d025566634ec779042eae55d108db6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20S=C3=A1nchez?= Date: Thu, 20 Jun 2024 10:05:18 +0200 Subject: [PATCH 02/15] fixes --- ui-src/components/ExporterProgress.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-src/components/ExporterProgress.tsx b/ui-src/components/ExporterProgress.tsx index 4bbe155b..04155660 100644 --- a/ui-src/components/ExporterProgress.tsx +++ b/ui-src/components/ExporterProgress.tsx @@ -30,7 +30,7 @@ const stepMessages: Record = { current: 'Currently processing layer' }, fills: { - total: 'color libraries fetched ' + total: 'color libraries fetched 🎨' }, format: { total: 'formatting color libraries 🎨' From 5776d977c5a71056d1a2b78535c8b5af5cb8be91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20S=C3=A1nchez?= Date: Mon, 24 Jun 2024 11:17:08 +0200 Subject: [PATCH 03/15] wip --- plugin-src/TextLibrary.ts | 21 ++++++++ .../transformers/partials/transformText.ts | 3 +- .../transformers/transformDocumentNode.ts | 54 ++++++++++++++++++- plugin-src/transformers/transformTextNode.ts | 1 + .../paragraph/translateParagraphProperties.ts | 1 + .../text/translateStyleTextSegments.ts | 36 +++++++++++-- .../translators/text/translateTextStyles.ts | 33 ++++++++++++ ui-src/components/ExporterProgress.tsx | 12 +++++ ui-src/context/useFigma.ts | 5 +- ui-src/lib/types/shapes/textShape.ts | 27 +++++++--- ui-src/lib/types/utils/typography.ts | 8 +++ ui-src/parser/creators/createText.ts | 34 +++++++++--- ui-src/parser/libraries/UiTextLibraries.ts | 19 +++++++ ui-src/parser/parse.ts | 46 ++++++++++++++-- ui-src/types/penpotDocument.ts | 2 + 15 files changed, 277 insertions(+), 25 deletions(-) create mode 100644 plugin-src/TextLibrary.ts create mode 100644 plugin-src/translators/text/translateTextStyles.ts create mode 100644 ui-src/lib/types/utils/typography.ts create mode 100644 ui-src/parser/libraries/UiTextLibraries.ts diff --git a/plugin-src/TextLibrary.ts b/plugin-src/TextLibrary.ts new file mode 100644 index 00000000..647c6113 --- /dev/null +++ b/plugin-src/TextLibrary.ts @@ -0,0 +1,21 @@ +class TextLibrary { + private styles: Map = new Map(); + + public register(id: string, styles?: TextStyle | undefined) { + this.styles.set(id, styles); + } + + public get(id: string): TextStyle | undefined { + return this.styles.get(id); + } + + public has(id: string): boolean { + return this.styles.has(id); + } + + public all(): Record { + return Object.fromEntries(this.styles.entries()); + } +} + +export const textLibrary = new TextLibrary(); diff --git a/plugin-src/transformers/partials/transformText.ts b/plugin-src/transformers/partials/transformText.ts index 207945b4..22fdf626 100644 --- a/plugin-src/transformers/partials/transformText.ts +++ b/plugin-src/transformers/partials/transformText.ts @@ -16,7 +16,8 @@ export const transformText = (node: TextNode): TextAttributes & Pick { return style.type === 'PAINT'; }; +const getTextStyles = async (): Promise> => { + const stylesToFetch = Object.entries(textLibrary.all()); + const styles: Record = {}; + + if (stylesToFetch.length === 0) return styles; + + let currentStyle = 1; + + figma.ui.postMessage({ + type: 'PROGRESS_TOTAL_ITEMS', + data: stylesToFetch.length + }); + + figma.ui.postMessage({ + type: 'PROGRESS_STEP', + data: 'typographies' + }); + + for (const [styleId] of stylesToFetch) { + const figmaStyle = await figma.getStyleByIdAsync(styleId); + if (figmaStyle && isTextStyle(figmaStyle)) { + styles[styleId] = translateTextStyles(figmaStyle); + } + + figma.ui.postMessage({ + type: 'PROGRESS_PROCESSED_ITEMS', + data: currentStyle++ + }); + + await sleep(0); + } + + await sleep(20); + + return styles; +}; + +const isTextStyle = (style: BaseStyle): style is TextStyle => { + return style.type === 'TEXT'; +}; + const processPages = async (node: DocumentNode): Promise => { const children = []; let currentPage = 1; @@ -122,6 +166,11 @@ export const transformDocumentNode = async (node: DocumentNode): Promise { + textLibrary.register(style.id, style); + }); + const children = await processPages(node); if (remoteComponentLibrary.remaining() > 0) { @@ -135,11 +184,14 @@ export const transformDocumentNode = async (node: DocumentNode): Promise { + console.log(transformText(node)); return { type: 'text', name: node.name, diff --git a/plugin-src/translators/text/paragraph/translateParagraphProperties.ts b/plugin-src/translators/text/paragraph/translateParagraphProperties.ts index 35153a74..23818554 100644 --- a/plugin-src/translators/text/paragraph/translateParagraphProperties.ts +++ b/plugin-src/translators/text/paragraph/translateParagraphProperties.ts @@ -18,6 +18,7 @@ export type StyleTextSegment = Pick< | 'listOptions' | 'fills' | 'fillStyleId' + | 'textStyleId' >; type PartialTranslation = { diff --git a/plugin-src/translators/text/translateStyleTextSegments.ts b/plugin-src/translators/text/translateStyleTextSegments.ts index 21127641..22bda4b5 100644 --- a/plugin-src/translators/text/translateStyleTextSegments.ts +++ b/plugin-src/translators/text/translateStyleTextSegments.ts @@ -1,3 +1,4 @@ +import { textLibrary } from '@plugin/TextLibrary'; import { transformFills } from '@plugin/transformers/partials'; import { translateFontId } from '@plugin/translators/text/font'; import { StyleTextSegment, translateParagraphProperties } from '@plugin/translators/text/paragraph'; @@ -25,20 +26,33 @@ export const translateStyleTextSegments = ( }; export const transformTextStyle = (node: TextNode, segment: StyleTextSegment): TextStyle => { + if (hasTextStyle(segment)) { + return { + ...partialTransformTextStyle(node, segment), + textStyleId: translateTextStyleId(segment.textStyleId) + }; + } + return { - ...translateFontId(segment.fontName, segment.fontWeight), + ...partialTransformTextStyle(node, segment), fontFamily: segment.fontName.family, fontSize: segment.fontSize.toString(), fontStyle: translateFontStyle(segment.fontName.style), - fontWeight: segment.fontWeight.toString(), - textAlign: translateHorizontalAlign(node.textAlignHorizontal), textDecoration: translateTextDecoration(segment), - textTransform: translateTextTransform(segment), letterSpacing: translateLetterSpacing(segment), lineHeight: translateLineHeight(segment) }; }; +export const partialTransformTextStyle = (node: TextNode, segment: StyleTextSegment): TextStyle => { + return { + ...translateFontId(segment.fontName, segment.fontWeight), + fontWeight: segment.fontWeight.toString(), + textAlign: translateHorizontalAlign(node.textAlignHorizontal), + textTransform: translateTextTransform(segment) + }; +}; + const translateStyleTextSegment = (node: TextNode, segment: StyleTextSegment): PenpotTextNode => { return { text: segment.characters, @@ -46,3 +60,17 @@ const translateStyleTextSegment = (node: TextNode, segment: StyleTextSegment): P ...transformFills(segment) }; }; + +const hasTextStyle = (segment: StyleTextSegment): boolean => { + return segment.textStyleId !== undefined && segment.textStyleId.length > 0; +}; + +const translateTextStyleId = (textStyleId: string | undefined): string | undefined => { + if (textStyleId === undefined) return; + + if (!textLibrary.has(textStyleId)) { + textLibrary.register(textStyleId); + } + + return textStyleId; +}; diff --git a/plugin-src/translators/text/translateTextStyles.ts b/plugin-src/translators/text/translateTextStyles.ts new file mode 100644 index 00000000..da7b0330 --- /dev/null +++ b/plugin-src/translators/text/translateTextStyles.ts @@ -0,0 +1,33 @@ +import { + translateFontStyle, + translateLetterSpacing, + translateLineHeight, + translateTextDecoration +} from '@plugin/translators/text/properties'; + +import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; + +export const translateTextStyles = (figmaStyle: TextStyle): TypographyStyle => { + const typographyStyle: TypographyStyle = { + name: figmaStyle.name, + textStyle: {}, + typography: {} + }; + + const path = (figmaStyle.remote ? 'Remote / ' : '') + figmaStyle.name; + + typographyStyle.textStyle = { + fontFamily: figmaStyle.fontName.family, + fontSize: figmaStyle.fontSize.toString(), + fontStyle: translateFontStyle(figmaStyle.fontName.style), + textDecoration: translateTextDecoration(figmaStyle), + letterSpacing: translateLetterSpacing(figmaStyle), + lineHeight: translateLineHeight(figmaStyle) + }; + typographyStyle.typography = { + path, + name: figmaStyle.name + }; + + return typographyStyle; +}; diff --git a/ui-src/components/ExporterProgress.tsx b/ui-src/components/ExporterProgress.tsx index 04155660..4653efa1 100644 --- a/ui-src/components/ExporterProgress.tsx +++ b/ui-src/components/ExporterProgress.tsx @@ -51,6 +51,15 @@ const stepMessages: Record = { exporting: { total: 'Generating Penpot file 🚀', current: 'Please wait, this process might take a while...' + }, + typographies: { + total: 'text styles fetched 📝' + }, + typoFormat: { + total: 'formatting text styles 📝' + }, + typoLibraries: { + total: 'text styles built 📝' } }; @@ -79,6 +88,9 @@ const StepProgress = (): JSX.Element | null => { case 'components': case 'format': case 'libraries': + case 'typographies': + case 'typoFormat': + case 'typoLibraries': return ( <> {processedItems} of {totalItems} {stepMessages[step].total} diff --git a/ui-src/context/useFigma.ts b/ui-src/context/useFigma.ts index 462f5454..393d6118 100644 --- a/ui-src/context/useFigma.ts +++ b/ui-src/context/useFigma.ts @@ -29,7 +29,10 @@ export type Steps = | 'exporting' | 'fills' | 'format' - | 'libraries'; + | 'libraries' + | 'typographies' + | 'typoFormat' + | 'typoLibraries'; export const useFigma = (): UseFigmaHook => { const [missingFonts, setMissingFonts] = useState(); diff --git a/ui-src/lib/types/shapes/textShape.ts b/ui-src/lib/types/shapes/textShape.ts index c6f02b2f..f9cab5ef 100644 --- a/ui-src/lib/types/shapes/textShape.ts +++ b/ui-src/lib/types/shapes/textShape.ts @@ -5,6 +5,7 @@ import { ShapeGeomAttributes } from '@ui/lib/types/shapes/shape'; import { Fill } from '@ui/lib/types/utils/fill'; +import { Typography } from '@ui/lib/types/utils/typography'; export type TextShape = ShapeBaseAttributes & ShapeGeomAttributes & @@ -45,25 +46,35 @@ export type TextNode = { key?: string; } & TextStyle; -export type TextStyle = FontId & { - fontFamily?: string; - fontSize?: string; - fontStyle?: TextFontStyle; - fontWeight?: string; +export type TextStyle = TextTypography & { textDecoration?: string; - textTransform?: string; direction?: string; typographyRefId?: string; typographyRefFile?: string; - lineHeight?: number; - letterSpacing?: number; textAlign?: TextHorizontalAlign; textDirection?: 'ltr' | 'rtl' | 'auto'; fills?: Fill[]; fillStyleId?: string; // @TODO: move to any other place + textStyleId?: string; // @TODO: move to any other place +}; + +export type TextTypography = FontId & { + fontFamily?: string; + fontSize?: string; + fontWeight?: string; + fontStyle?: TextFontStyle; + lineHeight?: number; + letterSpacing?: number; + textTransform?: string; }; export type FontId = { fontId?: string; fontVariantId?: string; }; + +export type TypographyStyle = { + name: string; + textStyle: TextStyle; + typography: Typography; +}; diff --git a/ui-src/lib/types/utils/typography.ts b/ui-src/lib/types/utils/typography.ts new file mode 100644 index 00000000..42ef91e5 --- /dev/null +++ b/ui-src/lib/types/utils/typography.ts @@ -0,0 +1,8 @@ +import { TextTypography } from '@ui/lib/types/shapes/textShape'; +import { Uuid } from '@ui/lib/types/utils/uuid'; + +export type Typography = TextTypography & { + id?: Uuid; + name?: string; + path?: string; +}; diff --git a/ui-src/parser/creators/createText.ts b/ui-src/parser/creators/createText.ts index cba45013..05c5ae0b 100644 --- a/ui-src/parser/creators/createText.ts +++ b/ui-src/parser/creators/createText.ts @@ -1,7 +1,8 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; -import { TextContent, TextShape } from '@ui/lib/types/shapes/textShape'; +import { Paragraph, TextContent, TextNode, TextShape } from '@ui/lib/types/shapes/textShape'; import { parseFigmaId } from '@ui/parser'; import { symbolFills, symbolStrokes } from '@ui/parser/creators/symbols'; +import { uiTextLibraries } from '@ui/parser/libraries/UiTextLibraries'; export const createText = ( file: PenpotFile, @@ -18,15 +19,34 @@ export const createText = ( const parseContent = (content: TextContent | undefined): TextContent | undefined => { if (!content) return; - content.children?.forEach(paragraphSet => { - paragraphSet.children.forEach(paragraph => { - paragraph.children.forEach(textNode => { - textNode.fills = symbolFills(textNode.fillStyleId, textNode.fills); + content.children = content.children?.map(paragraphSet => { + paragraphSet.children = paragraphSet.children.map(paragraph => { + paragraph.children = paragraph.children.map(textNode => { + return parseTextStyle(textNode, textNode.textStyleId) as TextNode; }); - - paragraph.fills = symbolFills(paragraph.fillStyleId, paragraph.fills); + return parseTextStyle(paragraph, paragraph.textStyleId) as Paragraph; }); + return paragraphSet; }); return content; }; + +const parseTextStyle = (text: Paragraph | TextNode, textStyleId?: string): Paragraph | TextNode => { + const textStyle = textStyleId + ? uiTextLibraries.get(textStyleId)?.textStyle + : { + fontFamily: text.fontFamily, + fontSize: text.fontSize, + fontStyle: text.fontStyle, + textDecoration: text.textDecoration, + letterSpacing: text.letterSpacing, + lineHeight: text.lineHeight + }; + + return { + ...textStyle, + ...text, + fills: symbolFills(text.fillStyleId, text.fills) + }; +}; diff --git a/ui-src/parser/libraries/UiTextLibraries.ts b/ui-src/parser/libraries/UiTextLibraries.ts new file mode 100644 index 00000000..208ac571 --- /dev/null +++ b/ui-src/parser/libraries/UiTextLibraries.ts @@ -0,0 +1,19 @@ +import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; + +class UiTextLibraries { + private libraries: Map = new Map(); + + public register(id: string, textStyle: TypographyStyle) { + this.libraries.set(id, textStyle); + } + + public get(id: string): TypographyStyle | undefined { + return this.libraries.get(id); + } + + public all(): TypographyStyle[] { + return Array.from(this.libraries.values()); + } +} + +export const uiTextLibraries = new UiTextLibraries(); diff --git a/ui-src/parser/parse.ts b/ui-src/parser/parse.ts index 7e4a2fbc..9ccf5076 100644 --- a/ui-src/parser/parse.ts +++ b/ui-src/parser/parse.ts @@ -5,10 +5,11 @@ import { sleep } from '@plugin/utils/sleep'; import { sendMessage } from '@ui/context'; import { createFile } from '@ui/lib/penpot'; import { PenpotFile } from '@ui/lib/types/penpotFile'; +import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; import { FillStyle } from '@ui/lib/types/utils/fill'; import { buildFile } from '@ui/parser/creators'; -import { uiImages } from '@ui/parser/libraries'; -import { uiColorLibraries } from '@ui/parser/libraries'; +import { uiColorLibraries, uiImages } from '@ui/parser/libraries'; +import { uiTextLibraries } from '@ui/parser/libraries/UiTextLibraries'; import { PenpotDocument } from '@ui/types'; import { parseImage } from '.'; @@ -44,6 +45,43 @@ const optimizeImages = async (images: Record) => { } }; +const prepareTypographyLibraries = async ( + file: PenpotFile, + styles: Record +) => { + const stylesToRegister = Object.entries(styles); + + if (stylesToRegister.length === 0) return; + + let stylesRegistered = 1; + + sendMessage({ + type: 'PROGRESS_TOTAL_ITEMS', + data: stylesToRegister.length + }); + + sendMessage({ + type: 'PROGRESS_STEP', + data: 'typoFormat' + }); + + for (const [key, style] of stylesToRegister) { + const typographyId = file.newId(); + style.textStyle.typographyRefId = typographyId; + style.textStyle.typographyRefFile = file.getId(); + style.typography.id = typographyId; + + uiTextLibraries.register(key, style); + + sendMessage({ + type: 'PROGRESS_PROCESSED_ITEMS', + data: stylesRegistered++ + }); + + await sleep(0); + } +}; + const prepareColorLibraries = async (file: PenpotFile, styles: Record) => { const stylesToRegister = Object.entries(styles); @@ -86,7 +124,8 @@ export const parse = async ({ children = [], components, images, - styles + styles, + typographies }: PenpotDocument) => { componentsLibrary.init(components); @@ -94,6 +133,7 @@ export const parse = async ({ await optimizeImages(images); await prepareColorLibraries(file, styles); + await prepareTypographyLibraries(file, typographies); return buildFile(file, children); }; diff --git a/ui-src/types/penpotDocument.ts b/ui-src/types/penpotDocument.ts index 6a5e9c1f..0bdc3173 100644 --- a/ui-src/types/penpotDocument.ts +++ b/ui-src/types/penpotDocument.ts @@ -1,5 +1,6 @@ import { PenpotPage } from '@ui/lib/types/penpotPage'; import { ComponentShape } from '@ui/lib/types/shapes/componentShape'; +import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; import { FillStyle } from '@ui/lib/types/utils/fill'; export type PenpotDocument = { @@ -8,4 +9,5 @@ export type PenpotDocument = { components: Record; images: Record; styles: Record; + typographies: Record; }; From 084838a4bec37bdc991bf14d4e4161b6d22aa6d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20S=C3=A1nchez?= Date: Mon, 24 Jun 2024 11:39:05 +0200 Subject: [PATCH 04/15] wip --- plugin-src/transformers/transformTextNode.ts | 1 - ui-src/parser/creators/createText.ts | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin-src/transformers/transformTextNode.ts b/plugin-src/transformers/transformTextNode.ts index b7132615..cf526727 100644 --- a/plugin-src/transformers/transformTextNode.ts +++ b/plugin-src/transformers/transformTextNode.ts @@ -16,7 +16,6 @@ import { import { TextShape } from '@ui/lib/types/shapes/textShape'; export const transformTextNode = (node: TextNode): TextShape => { - console.log(transformText(node)); return { type: 'text', name: node.name, diff --git a/ui-src/parser/creators/createText.ts b/ui-src/parser/creators/createText.ts index 05c5ae0b..4cb182ee 100644 --- a/ui-src/parser/creators/createText.ts +++ b/ui-src/parser/creators/createText.ts @@ -13,6 +13,8 @@ export const createText = ( shape.content = parseContent(shape.content); shape.strokes = symbolStrokes(shape.strokes); + console.log(shape); + file.createText(shape); }; From 753affdec25fc08ec2192470e4ce17285ef1ab2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20S=C3=A1nchez?= Date: Mon, 24 Jun 2024 13:09:07 +0200 Subject: [PATCH 05/15] wip --- .../transformers/transformDocumentNode.ts | 4 +- .../translators/text/translateTextStyles.ts | 10 +- ui-src/lib/penpot.js | 8477 ++++++++--------- ui-src/lib/types/penpotFile.ts | 6 +- ui-src/lib/types/utils/typography.ts | 13 +- ui-src/parser/creators/buildFile.ts | 8 +- ui-src/parser/creators/createText.ts | 42 +- ui-src/parser/creators/createTextLibrary.ts | 44 + ui-src/parser/creators/index.ts | 1 + 9 files changed, 4306 insertions(+), 4299 deletions(-) create mode 100644 ui-src/parser/creators/createTextLibrary.ts diff --git a/plugin-src/transformers/transformDocumentNode.ts b/plugin-src/transformers/transformDocumentNode.ts index 0e5cd7e1..ef248bff 100644 --- a/plugin-src/transformers/transformDocumentNode.ts +++ b/plugin-src/transformers/transformDocumentNode.ts @@ -112,8 +112,8 @@ const getTextStyles = async (): Promise> => { data: 'typographies' }); - for (const [styleId] of stylesToFetch) { - const figmaStyle = await figma.getStyleByIdAsync(styleId); + for (const [styleId, style] of stylesToFetch) { + const figmaStyle = style ?? (await figma.getStyleByIdAsync(styleId)); if (figmaStyle && isTextStyle(figmaStyle)) { styles[styleId] = translateTextStyles(figmaStyle); } diff --git a/plugin-src/translators/text/translateTextStyles.ts b/plugin-src/translators/text/translateTextStyles.ts index da7b0330..681740f9 100644 --- a/plugin-src/translators/text/translateTextStyles.ts +++ b/plugin-src/translators/text/translateTextStyles.ts @@ -2,7 +2,8 @@ import { translateFontStyle, translateLetterSpacing, translateLineHeight, - translateTextDecoration + translateTextDecoration, + translateTextTransform } from '@plugin/translators/text/properties'; import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; @@ -14,7 +15,9 @@ export const translateTextStyles = (figmaStyle: TextStyle): TypographyStyle => { typography: {} }; - const path = (figmaStyle.remote ? 'Remote / ' : '') + figmaStyle.name; + const path = figmaStyle.remote ? 'Remote / ' : ''; + + const lineHeight = translateLineHeight(figmaStyle); typographyStyle.textStyle = { fontFamily: figmaStyle.fontName.family, @@ -22,7 +25,8 @@ export const translateTextStyles = (figmaStyle: TextStyle): TypographyStyle => { fontStyle: translateFontStyle(figmaStyle.fontName.style), textDecoration: translateTextDecoration(figmaStyle), letterSpacing: translateLetterSpacing(figmaStyle), - lineHeight: translateLineHeight(figmaStyle) + textTransform: translateTextTransform(figmaStyle), + ...(lineHeight ? { lineHeight } : {}) }; typographyStyle.typography = { path, diff --git a/ui-src/lib/penpot.js b/ui-src/lib/penpot.js index 85574202..e047b116 100644 --- a/ui-src/lib/penpot.js +++ b/ui-src/lib/penpot.js @@ -1,99 +1,37 @@ -var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(a){var b=0;return function(){return b>>0,$jscomp.propertyToPolyfillSymbol[e]=$jscomp.IS_SYMBOL_NATIVE? -$jscomp.global.Symbol(e):$jscomp.POLYFILL_PREFIX+c+"$"+e),$jscomp.defineProperty(d,$jscomp.propertyToPolyfillSymbol[e],{configurable:!0,writable:!0,value:b})))};$jscomp.underscoreProtoCanBeSet=function(){var a={a:!0},b={};try{return b.__proto__=a,b.a}catch(c){}return!1}; -$jscomp.setPrototypeOf=$jscomp.TRUST_ES6_POLYFILLS&&"function"==typeof Object.setPrototypeOf?Object.setPrototypeOf:$jscomp.underscoreProtoCanBeSet()?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null;$jscomp.generator={};$jscomp.generator.ensureIteratorResultIsObject_=function(a){if(!(a instanceof Object))throw new TypeError("Iterator result "+a+" is not an object");}; -$jscomp.generator.Context=function(){this.isRunning_=!1;this.yieldAllIterator_=null;this.yieldResult=void 0;this.nextAddress=1;this.finallyAddress_=this.catchAddress_=0;this.finallyContexts_=this.abruptCompletion_=null};$jscomp.generator.Context.prototype.start_=function(){if(this.isRunning_)throw new TypeError("Generator is already running");this.isRunning_=!0};$jscomp.generator.Context.prototype.stop_=function(){this.isRunning_=!1}; -$jscomp.generator.Context.prototype.jumpToErrorHandler_=function(){this.nextAddress=this.catchAddress_||this.finallyAddress_};$jscomp.generator.Context.prototype.next_=function(a){this.yieldResult=a};$jscomp.generator.Context.prototype.throw_=function(a){this.abruptCompletion_={exception:a,isException:!0};this.jumpToErrorHandler_()};$jscomp.generator.Context.prototype.return=function(a){this.abruptCompletion_={return:a};this.nextAddress=this.finallyAddress_}; -$jscomp.generator.Context.prototype.jumpThroughFinallyBlocks=function(a){this.abruptCompletion_={jumpTo:a};this.nextAddress=this.finallyAddress_};$jscomp.generator.Context.prototype.yield=function(a,b){this.nextAddress=b;return{value:a}};$jscomp.generator.Context.prototype.yieldAll=function(a,b){a=$jscomp.makeIterator(a);var c=a.next();$jscomp.generator.ensureIteratorResultIsObject_(c);if(c.done)this.yieldResult=c.value,this.nextAddress=b;else return this.yieldAllIterator_=a,this.yield(c.value,b)}; -$jscomp.generator.Context.prototype.jumpTo=function(a){this.nextAddress=a};$jscomp.generator.Context.prototype.jumpToEnd=function(){this.nextAddress=0};$jscomp.generator.Context.prototype.setCatchFinallyBlocks=function(a,b){this.catchAddress_=a;void 0!=b&&(this.finallyAddress_=b)};$jscomp.generator.Context.prototype.setFinallyBlock=function(a){this.catchAddress_=0;this.finallyAddress_=a||0};$jscomp.generator.Context.prototype.leaveTryBlock=function(a,b){this.nextAddress=a;this.catchAddress_=b||0}; -$jscomp.generator.Context.prototype.enterCatchBlock=function(a){this.catchAddress_=a||0;a=this.abruptCompletion_.exception;this.abruptCompletion_=null;return a};$jscomp.generator.Context.prototype.enterFinallyBlock=function(a,b,c){c?this.finallyContexts_[c]=this.abruptCompletion_:this.finallyContexts_=[this.abruptCompletion_];this.catchAddress_=a||0;this.finallyAddress_=b||0}; -$jscomp.generator.Context.prototype.leaveFinallyBlock=function(a,b){b=this.finallyContexts_.splice(b||0)[0];if(b=this.abruptCompletion_=this.abruptCompletion_||b){if(b.isException)return this.jumpToErrorHandler_();void 0!=b.jumpTo&&this.finallyAddress_>>0)+"_",d=0,e=function(f){if(this instanceof e)throw new TypeError("Symbol is not a constructor");return new b(c+(f||"")+"_"+d++,f)};return e},"es6","es3"); -$jscomp.polyfill("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;c>>0,$jscomp.propertyToPolyfillSymbol[e]=$jscomp.IS_SYMBOL_NATIVE? +$jscomp.global.Symbol(e):$jscomp.POLYFILL_PREFIX+b+"$"+e),$jscomp.defineProperty(d,$jscomp.propertyToPolyfillSymbol[e],{configurable:!0,writable:!0,value:c})))};$jscomp.arrayIteratorImpl=function(a){var c=0;return function(){return c>>0)+"_",d=0,e=function(f){if(this instanceof e)throw new TypeError("Symbol is not a constructor");return new c(b+(f||"")+"_"+d++,f)};return e},"es6","es3"); +$jscomp.polyfill("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var c="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),b=0;b>>0,$jscomp.propertyToPolyfillSymbol[e]=$jscomp.IS_SYMBOL_NATIVE? -$jscomp.global.Symbol(e):$jscomp.POLYFILL_PREFIX+c+"$"+e),$jscomp.defineProperty(d,$jscomp.propertyToPolyfillSymbol[e],{configurable:!0,writable:!0,value:b})))};$jscomp.underscoreProtoCanBeSet=function(){var a={a:!0},b={};try{return b.__proto__=a,b.a}catch(c){}return!1}; -$jscomp.setPrototypeOf=$jscomp.TRUST_ES6_POLYFILLS&&"function"==typeof Object.setPrototypeOf?Object.setPrototypeOf:$jscomp.underscoreProtoCanBeSet()?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null;$jscomp.generator={};$jscomp.generator.ensureIteratorResultIsObject_=function(a){if(!(a instanceof Object))throw new TypeError("Iterator result "+a+" is not an object");}; -$jscomp.generator.Context=function(){this.isRunning_=!1;this.yieldAllIterator_=null;this.yieldResult=void 0;this.nextAddress=1;this.finallyAddress_=this.catchAddress_=0;this.finallyContexts_=this.abruptCompletion_=null};$jscomp.generator.Context.prototype.start_=function(){if(this.isRunning_)throw new TypeError("Generator is already running");this.isRunning_=!0};$jscomp.generator.Context.prototype.stop_=function(){this.isRunning_=!1}; -$jscomp.generator.Context.prototype.jumpToErrorHandler_=function(){this.nextAddress=this.catchAddress_||this.finallyAddress_};$jscomp.generator.Context.prototype.next_=function(a){this.yieldResult=a};$jscomp.generator.Context.prototype.throw_=function(a){this.abruptCompletion_={exception:a,isException:!0};this.jumpToErrorHandler_()};$jscomp.generator.Context.prototype.return=function(a){this.abruptCompletion_={return:a};this.nextAddress=this.finallyAddress_}; -$jscomp.generator.Context.prototype.jumpThroughFinallyBlocks=function(a){this.abruptCompletion_={jumpTo:a};this.nextAddress=this.finallyAddress_};$jscomp.generator.Context.prototype.yield=function(a,b){this.nextAddress=b;return{value:a}};$jscomp.generator.Context.prototype.yieldAll=function(a,b){a=$jscomp.makeIterator(a);var c=a.next();$jscomp.generator.ensureIteratorResultIsObject_(c);if(c.done)this.yieldResult=c.value,this.nextAddress=b;else return this.yieldAllIterator_=a,this.yield(c.value,b)}; -$jscomp.generator.Context.prototype.jumpTo=function(a){this.nextAddress=a};$jscomp.generator.Context.prototype.jumpToEnd=function(){this.nextAddress=0};$jscomp.generator.Context.prototype.setCatchFinallyBlocks=function(a,b){this.catchAddress_=a;void 0!=b&&(this.finallyAddress_=b)};$jscomp.generator.Context.prototype.setFinallyBlock=function(a){this.catchAddress_=0;this.finallyAddress_=a||0};$jscomp.generator.Context.prototype.leaveTryBlock=function(a,b){this.nextAddress=a;this.catchAddress_=b||0}; -$jscomp.generator.Context.prototype.enterCatchBlock=function(a){this.catchAddress_=a||0;a=this.abruptCompletion_.exception;this.abruptCompletion_=null;return a};$jscomp.generator.Context.prototype.enterFinallyBlock=function(a,b,c){c?this.finallyContexts_[c]=this.abruptCompletion_:this.finallyContexts_=[this.abruptCompletion_];this.catchAddress_=a||0;this.finallyAddress_=b||0}; -$jscomp.generator.Context.prototype.leaveFinallyBlock=function(a,b){b=this.finallyContexts_.splice(b||0)[0];if(b=this.abruptCompletion_=this.abruptCompletion_||b){if(b.isException)return this.jumpToErrorHandler_();void 0!=b.jumpTo&&this.finallyAddress_>>0)+"_",d=0,e=function(f){if(this instanceof e)throw new TypeError("Symbol is not a constructor");return new b(c+(f||"")+"_"+d++,f)};return e},"es6","es3"); -$jscomp.polyfill("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;c>>0,$jscomp.propertyToPolyfillSymbol[e]=$jscomp.IS_SYMBOL_NATIVE? +$jscomp.global.Symbol(e):$jscomp.POLYFILL_PREFIX+b+"$"+e),$jscomp.defineProperty(d,$jscomp.propertyToPolyfillSymbol[e],{configurable:!0,writable:!0,value:c})))};$jscomp.arrayIteratorImpl=function(a){var c=0;return function(){return c>>0)+"_",d=0,e=function(f){if(this instanceof e)throw new TypeError("Symbol is not a constructor");return new c(b+(f||"")+"_"+d++,f)};return e},"es6","es3"); +$jscomp.polyfill("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var c="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),b=0;b