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

Refactor libraries (#189)

This commit is contained in:
Jordi Sala Morales 2024-06-26 08:11:57 +02:00 committed by GitHub
parent e8270cfd54
commit aee78de8ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 132 additions and 312 deletions

View file

@ -23,7 +23,11 @@ module.exports = {
rules: { rules: {
'@typescript-eslint/no-unused-vars': [ '@typescript-eslint/no-unused-vars': [
'error', 'error',
{ ignoreRestSiblings: true, argsIgnorePattern: '^_' } {
ignoreRestSiblings: true,
argsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_'
}
] ]
} }
}; };

7
common/map.ts Normal file
View file

@ -0,0 +1,7 @@
export const toObject = <T>(map: Map<string, T>): Record<string, T> => {
return Object.fromEntries(map.entries());
};
export const toArray = <T>(map: Map<string, T>): [string, T][] => {
return Array.from(map.entries());
};

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "penpot-exporter", "name": "penpot-exporter",
"version": "0.7.0", "version": "0.7.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "penpot-exporter", "name": "penpot-exporter",
"version": "0.7.0", "version": "0.7.1",
"license": "MPL2.0", "license": "MPL2.0",
"dependencies": { "dependencies": {
"@create-figma-plugin/ui": "^3.2", "@create-figma-plugin/ui": "^3.2",

View file

@ -1,9 +1,9 @@
class RemoteComponentsLibrary { export class RemoteComponentsLibrary {
private components: Map<string, ComponentNode | ComponentSetNode> = new Map(); private components: Map<string, ComponentNode | ComponentSetNode> = new Map();
private queue: string[] = []; private queue: string[] = [];
public register(id: string, component: ComponentNode | ComponentSetNode) { public register(id: string, component: ComponentNode | ComponentSetNode) {
if (!Object.prototype.hasOwnProperty.call(this.components, id)) { if (!this.components.has(id)) {
this.queue.push(id); this.queue.push(id);
} }
@ -37,5 +37,3 @@ class RemoteComponentsLibrary {
return this.components.size; return this.components.size;
} }
} }
export const remoteComponents = new RemoteComponentsLibrary();

10
plugin-src/libraries.ts Normal file
View file

@ -0,0 +1,10 @@
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
import { RemoteComponentsLibrary } from './RemoteComponents';
export const textStyles: Map<string, TextStyle | undefined> = new Map();
export const paintStyles: Map<string, PaintStyle | undefined> = new Map();
export const overrides: Map<string, NodeChangeProperty[]> = new Map();
export const images: Map<string, Image | null> = new Map();
export const components: Map<string, ComponentShape> = new Map();
export const remoteComponents = new RemoteComponentsLibrary();

View file

@ -1,23 +0,0 @@
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
class Components {
private components: Map<string, ComponentShape> = new Map();
public register(id: string, component: ComponentShape) {
this.components.set(id, component);
}
public get(id: string): ComponentShape | undefined {
return this.components.get(id);
}
public all(): Record<string, ComponentShape> {
return Object.fromEntries(this.components.entries());
}
public init(components: Record<string, ComponentShape>): void {
this.components = new Map(Object.entries(components));
}
}
export const components = new Components();

View file

@ -1,25 +0,0 @@
class Images {
private images: Map<string, Image | null> = new Map();
public register(hash: string, image: Image | null) {
this.images.set(hash, image);
}
public get(hash: string): Image | null | undefined {
return this.images.get(hash);
}
public has(hash: string): boolean {
return this.images.has(hash);
}
public all(): Record<string, Image | null> {
return Object.fromEntries(this.images.entries());
}
public init(images: Record<string, Image | null>): void {
this.images = new Map(Object.entries(images));
}
}
export const images = new Images();

View file

@ -1,13 +0,0 @@
class Overrides {
private overrides: Map<string, NodeChangeProperty[]> = new Map();
public register(nodeId: string, overrides: NodeChangeProperty[]): void {
this.overrides.set(nodeId, overrides);
}
public get(nodeId: string): NodeChangeProperty[] | undefined {
return this.overrides.get(nodeId);
}
}
export const overrides = new Overrides();

View file

@ -1,21 +0,0 @@
class PaintStyles {
private styles: Map<string, PaintStyle | undefined> = new Map();
public register(id: string, styles?: PaintStyle | undefined) {
this.styles.set(id, styles);
}
public get(id: string): PaintStyle | undefined {
return this.styles.get(id);
}
public has(id: string): boolean {
return this.styles.has(id);
}
public all(): Record<string, PaintStyle | undefined> {
return Object.fromEntries(this.styles.entries());
}
}
export const paintStyles = new PaintStyles();

View file

@ -1,21 +0,0 @@
class TextStyles {
private styles: Map<string, TextStyle | undefined> = 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<string, TextStyle | undefined> {
return Object.fromEntries(this.styles.entries());
}
}
export const textStyles = new TextStyles();

View file

@ -1,6 +0,0 @@
export * from './Components';
export * from './Images';
export * from './Overrides';
export * from './RemoteComponents';
export * from './PaintStyles';
export * from './TextStyles';

View file

@ -1,8 +1,10 @@
import { toArray } from '@common/map';
import { sleep } from '@common/sleep';
import { images as imagesLibrary } from '@plugin/libraries'; import { images as imagesLibrary } from '@plugin/libraries';
import { sleep } from '@plugin/utils';
export const processImages = async (): Promise<Record<string, Uint8Array>> => { export const processImages = async (): Promise<Record<string, Uint8Array>> => {
const imageToDownload = Object.entries(imagesLibrary.all()); const imageToDownload = toArray(imagesLibrary);
const images: Record<string, Uint8Array> = {}; const images: Record<string, Uint8Array> = {};
if (imageToDownload.length === 0) return images; if (imageToDownload.length === 0) return images;

View file

@ -1,7 +1,8 @@
import { sleep } from '@common/sleep';
import { remoteComponents } from '@plugin/libraries'; import { remoteComponents } from '@plugin/libraries';
import { transformPageNode } from '@plugin/transformers'; import { transformPageNode } from '@plugin/transformers';
import { translateRemoteChildren } from '@plugin/translators'; import { translateRemoteChildren } from '@plugin/translators';
import { sleep } from '@plugin/utils';
import { PenpotPage } from '@ui/lib/types/penpotPage'; import { PenpotPage } from '@ui/lib/types/penpotPage';

View file

@ -1,6 +1,8 @@
import { toArray } from '@common/map';
import { sleep } from '@common/sleep';
import { paintStyles } from '@plugin/libraries'; import { paintStyles } from '@plugin/libraries';
import { translatePaintStyle } from '@plugin/translators/styles'; import { translatePaintStyle } from '@plugin/translators/styles';
import { sleep } from '@plugin/utils';
import { FillStyle } from '@ui/lib/types/utils/fill'; import { FillStyle } from '@ui/lib/types/utils/fill';
@ -11,12 +13,12 @@ const isPaintStyle = (style: BaseStyle): style is PaintStyle => {
export const registerPaintStyles = async () => { export const registerPaintStyles = async () => {
const localPaintStyles = await figma.getLocalPaintStylesAsync(); const localPaintStyles = await figma.getLocalPaintStylesAsync();
localPaintStyles.forEach(style => { localPaintStyles.forEach(style => {
paintStyles.register(style.id, style); paintStyles.set(style.id, style);
}); });
}; };
export const processPaintStyles = async (): Promise<Record<string, FillStyle>> => { export const processPaintStyles = async (): Promise<Record<string, FillStyle>> => {
const stylesToFetch = Object.entries(paintStyles.all()); const stylesToFetch = toArray(paintStyles);
const styles: Record<string, FillStyle> = {}; const styles: Record<string, FillStyle> = {};
if (stylesToFetch.length === 0) return styles; if (stylesToFetch.length === 0) return styles;

View file

@ -1,6 +1,8 @@
import { toArray } from '@common/map';
import { sleep } from '@common/sleep';
import { textStyles } from '@plugin/libraries'; import { textStyles } from '@plugin/libraries';
import { translateTextStyle } from '@plugin/translators/styles'; import { translateTextStyle } from '@plugin/translators/styles';
import { sleep } from '@plugin/utils';
import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; import { TypographyStyle } from '@ui/lib/types/shapes/textShape';
@ -11,12 +13,12 @@ const isTextStyle = (style: BaseStyle): style is TextStyle => {
export const registerTextStyles = async () => { export const registerTextStyles = async () => {
const localTextStyles = await figma.getLocalTextStylesAsync(); const localTextStyles = await figma.getLocalTextStylesAsync();
localTextStyles.forEach(style => { localTextStyles.forEach(style => {
textStyles.register(style.id, style); textStyles.set(style.id, style);
}); });
}; };
export const processTextStyles = async (): Promise<Record<string, TypographyStyle>> => { export const processTextStyles = async (): Promise<Record<string, TypographyStyle>> => {
const stylesToFetch = Object.entries(textStyles.all()); const stylesToFetch = toArray(textStyles);
const styles: Record<string, TypographyStyle> = {}; const styles: Record<string, TypographyStyle> = {};
if (stylesToFetch.length === 0) return styles; if (stylesToFetch.length === 0) return styles;

View file

@ -19,7 +19,7 @@ import {
import { ComponentRoot } from '@ui/types'; import { ComponentRoot } from '@ui/types';
export const transformComponentNode = async (node: ComponentNode): Promise<ComponentRoot> => { export const transformComponentNode = async (node: ComponentNode): Promise<ComponentRoot> => {
components.register(node.id, { components.set(node.id, {
type: 'component', type: 'component',
name: node.name, name: node.name,
path: node.parent?.type === 'COMPONENT_SET' ? node.parent.name : '', path: node.parent?.type === 'COMPONENT_SET' ? node.parent.name : '',

View file

@ -1,3 +1,5 @@
import { toObject } from '@common/map';
import { components } from '@plugin/libraries'; import { components } from '@plugin/libraries';
import { import {
processImages, processImages,
@ -22,7 +24,7 @@ export const transformDocumentNode = async (node: DocumentNode): Promise<PenpotD
return { return {
name: node.name, name: node.name,
children, children,
components: components.all(), components: toObject(components),
images, images,
paintStyles, paintStyles,
textStyles textStyles

View file

@ -39,7 +39,7 @@ export const transformInstanceNode = async (
registerTextVariableOverrides(node, primaryComponent); registerTextVariableOverrides(node, primaryComponent);
if (node.overrides.length > 0) { if (node.overrides.length > 0) {
node.overrides.forEach(override => overrides.register(override.id, override.overriddenFields)); node.overrides.forEach(override => overrides.set(override.id, override.overriddenFields));
} }
return { return {
@ -128,7 +128,7 @@ const registerTextVariableOverrides = (
}); });
textNodes.forEach(textNode => { textNodes.forEach(textNode => {
overrides.register(textNode.id, ['text']); overrides.set(textNode.id, ['text']);
}); });
} }
}; };

View file

@ -48,7 +48,7 @@ export const translateFillStyleId = (
if (fillStyleId === figma.mixed || fillStyleId === undefined) return; if (fillStyleId === figma.mixed || fillStyleId === undefined) return;
if (!paintStyles.has(fillStyleId)) { if (!paintStyles.has(fillStyleId)) {
paintStyles.register(fillStyleId); paintStyles.set(fillStyleId, undefined);
} }
return fillStyleId; return fillStyleId;

View file

@ -17,7 +17,7 @@ const translateImage = (imageHash: string | null): PartialImageColor | undefined
if (!imageHash) return; if (!imageHash) return;
if (!images.has(imageHash)) { if (!images.has(imageHash)) {
images.register(imageHash, figma.getImageByHash(imageHash)); images.set(imageHash, figma.getImageByHash(imageHash));
} }
return { return {

View file

@ -7,6 +7,7 @@ export const translateCustomFont = (
fontWeight: string fontWeight: string
): Pick<TextTypography, 'fontId' | 'fontVariantId' | 'fontWeight'> | undefined => { ): Pick<TextTypography, 'fontId' | 'fontVariantId' | 'fontWeight'> | undefined => {
const customFontId = getCustomFontId(fontName); const customFontId = getCustomFontId(fontName);
return { return {
fontId: customFontId ? `custom-${customFontId}` : '', fontId: customFontId ? `custom-${customFontId}` : '',
fontVariantId: translateFontVariantId(fontName, fontWeight), fontVariantId: translateFontVariantId(fontName, fontWeight),

View file

@ -68,7 +68,7 @@ const translateTextStyleId = (textStyleId: string | undefined): string | undefin
if (textStyleId === undefined) return; if (textStyleId === undefined) return;
if (!textStyles.has(textStyleId)) { if (!textStyles.has(textStyleId)) {
textStyles.register(textStyleId); textStyles.set(textStyleId, undefined);
} }
return textStyleId; return textStyleId;

View file

@ -1,7 +1,8 @@
import { sleep } from '@common/sleep';
import { remoteComponents } from '@plugin/libraries'; import { remoteComponents } from '@plugin/libraries';
import { transformGroupNodeLike, transformSceneNode } from '@plugin/transformers'; import { transformGroupNodeLike, transformSceneNode } from '@plugin/transformers';
import { transformMaskFigmaIds } from '@plugin/transformers/partials'; import { transformMaskFigmaIds } from '@plugin/transformers/partials';
import { sleep } from '@plugin/utils';
import { PenpotNode } from '@ui/types'; import { PenpotNode } from '@ui/types';

View file

@ -5,4 +5,3 @@ export * from './calculateLinearGradient';
export * from './calculateRadialGradient'; export * from './calculateRadialGradient';
export * from './matrixInvert'; export * from './matrixInvert';
export * from './rgbToHex'; export * from './rgbToHex';
export * from './sleep';

View file

@ -11,7 +11,7 @@ const config = {
trailingComma: 'none', trailingComma: 'none',
useTabs: false, useTabs: false,
plugins: ['@trivago/prettier-plugin-sort-imports'], plugins: ['@trivago/prettier-plugin-sort-imports'],
importOrder: ['^@plugin/(.*)$', '^@ui/(.*)$', '^[./]'], importOrder: ['^@common/(.*)$', '^@plugin/(.*)$', '^@ui/(.*)$', '^[./]'],
importOrderSeparation: true, importOrderSeparation: true,
importOrderSortSpecifiers: true importOrderSortSpecifiers: true
}; };

View file

@ -2,6 +2,7 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@common/*": ["./common/*"],
"@plugin/*": ["./plugin-src/*"], "@plugin/*": ["./plugin-src/*"],
"@ui/*": ["./ui-src/*"] "@ui/*": ["./ui-src/*"]
} }

View file

@ -1,21 +1,21 @@
import { sleep } from '@plugin/utils/sleep'; import { sleep } from '@common/sleep';
import { sendMessage } from '@ui/context'; import { sendMessage } from '@ui/context';
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { PenpotPage } from '@ui/lib/types/penpotPage'; import { PenpotPage } from '@ui/lib/types/penpotPage';
import { components, identifiers } from '@ui/parser';
import { import {
createColorsLibrary, createColorsLibrary,
createComponentsLibrary, createComponentsLibrary,
createPage, createPage,
createTextLibrary createTextLibrary
} from '@ui/parser/creators'; } from '@ui/parser/creators';
import { components, identifiers } from '@ui/parser/libraries';
export const buildFile = async (file: PenpotFile, children: PenpotPage[]) => { export const buildFile = async (file: PenpotFile, children: PenpotPage[]) => {
let pagesBuilt = 1; let pagesBuilt = 1;
components.init(); components.clear();
identifiers.init(); identifiers.clear();
sendMessage({ sendMessage({
type: 'PROGRESS_TOTAL_ITEMS', type: 'PROGRESS_TOTAL_ITEMS',
@ -28,7 +28,7 @@ export const buildFile = async (file: PenpotFile, children: PenpotPage[]) => {
}); });
for (const page of children) { for (const page of children) {
await createPage(file, page); createPage(file, page);
sendMessage({ sendMessage({
type: 'PROGRESS_PROCESSED_ITEMS', type: 'PROGRESS_PROCESSED_ITEMS',

View file

@ -1,12 +1,13 @@
import { sleep } from '@plugin/utils/sleep'; import { toArray } from '@common/map';
import { sleep } from '@common/sleep';
import { sendMessage } from '@ui/context'; import { sendMessage } from '@ui/context';
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { colors } from '@ui/parser/libraries'; import { colors } from '@ui/parser';
export const createColorsLibrary = async (file: PenpotFile) => { export const createColorsLibrary = async (file: PenpotFile) => {
let librariesBuilt = 1; let librariesBuilt = 1;
const libraries = colors.all(); const libraries = toArray(colors);
sendMessage({ sendMessage({
type: 'PROGRESS_TOTAL_ITEMS', type: 'PROGRESS_TOTAL_ITEMS',
@ -18,7 +19,7 @@ export const createColorsLibrary = async (file: PenpotFile) => {
data: 'libraries' data: 'libraries'
}); });
for (const library of libraries) { for (const [_, library] of libraries) {
for (let index = 0; index < library.fills.length; index++) { for (let index = 0; index < library.fills.length; index++) {
file.addLibraryColor({ file.addLibraryColor({
...library.colors[index], ...library.colors[index],

View file

@ -1,20 +1,18 @@
import { components } from '@plugin/libraries/Components';
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { components as uiComponents } from '@ui/parser/libraries'; import { componentShapes, components } from '@ui/parser';
import { ComponentRoot } from '@ui/types'; import { ComponentRoot } from '@ui/types';
import { createArtboard } from '.'; import { createArtboard } from '.';
export const createComponent = (file: PenpotFile, { figmaId }: ComponentRoot) => { export const createComponent = (file: PenpotFile, { figmaId }: ComponentRoot) => {
const component = components.get(figmaId); const componentShape = componentShapes.get(figmaId);
if (!component) { if (!componentShape) {
return; return;
} }
const componentId = getComponentId(file, figmaId); const componentId = getComponentId(file, figmaId);
const { type, ...shape } = component; const { type, ...shape } = componentShape;
shape.componentFile = file.getId(); shape.componentFile = file.getId();
shape.componentId = componentId; shape.componentId = componentId;
@ -27,7 +25,7 @@ export const createComponent = (file: PenpotFile, { figmaId }: ComponentRoot) =>
return; return;
} }
uiComponents.register(figmaId, { components.set(figmaId, {
componentId, componentId,
mainInstancePage: file.getCurrentPageId(), mainInstancePage: file.getCurrentPageId(),
componentFigmaId: figmaId, componentFigmaId: figmaId,
@ -36,7 +34,7 @@ export const createComponent = (file: PenpotFile, { figmaId }: ComponentRoot) =>
}; };
const getComponentId = (file: PenpotFile, figmaId: string) => { const getComponentId = (file: PenpotFile, figmaId: string) => {
const uiComponent = uiComponents.get(figmaId); const component = components.get(figmaId);
return uiComponent?.componentId ?? file.newId(); return component?.componentId ?? file.newId();
}; };

View file

@ -1,6 +1,5 @@
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { parseFigmaId } from '@ui/parser'; import { components, parseFigmaId } from '@ui/parser';
import { components } from '@ui/parser/libraries';
import { ComponentInstance } from '@ui/types'; import { ComponentInstance } from '@ui/types';
import { createArtboard } from '.'; import { createArtboard } from '.';
@ -43,7 +42,7 @@ const createUiComponent = (file: PenpotFile, mainComponentFigmaId: string) => {
mainInstanceId mainInstanceId
}; };
components.register(mainComponentFigmaId, uiComponent); components.set(mainComponentFigmaId, uiComponent);
return uiComponent; return uiComponent;
}; };

View file

@ -1,16 +1,16 @@
import { components } from '@plugin/libraries/Components'; import { toArray } from '@common/map';
import { sleep } from '@plugin/utils/sleep'; import { sleep } from '@common/sleep';
import { sendMessage } from '@ui/context'; import { sendMessage } from '@ui/context';
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { UiComponent, componentShapes, components as uiComponents } from '@ui/parser';
import { symbolFills, symbolStrokes } from '@ui/parser/creators/symbols'; import { symbolFills, symbolStrokes } from '@ui/parser/creators/symbols';
import { UiComponent, components as uiComponents } from '@ui/parser/libraries';
import { createItems } from '.'; import { createItems } from '.';
export const createComponentsLibrary = async (file: PenpotFile) => { export const createComponentsLibrary = async (file: PenpotFile) => {
let componentsBuilt = 1; let componentsBuilt = 1;
const components = uiComponents.all(); const components = toArray(uiComponents);
sendMessage({ sendMessage({
type: 'PROGRESS_TOTAL_ITEMS', type: 'PROGRESS_TOTAL_ITEMS',
@ -22,7 +22,7 @@ export const createComponentsLibrary = async (file: PenpotFile) => {
data: 'components' data: 'components'
}); });
for (const uiComponent of components) { for (const [_, uiComponent] of components) {
createComponentLibrary(file, uiComponent); createComponentLibrary(file, uiComponent);
sendMessage({ sendMessage({
@ -34,14 +34,14 @@ export const createComponentsLibrary = async (file: PenpotFile) => {
} }
}; };
const createComponentLibrary = async (file: PenpotFile, uiComponent: UiComponent) => { const createComponentLibrary = (file: PenpotFile, uiComponent: UiComponent) => {
const component = components.get(uiComponent.componentFigmaId); const componentShape = componentShapes.get(uiComponent.componentFigmaId);
if (!component) { if (!componentShape) {
return; return;
} }
const { children = [], ...shape } = component; const { children = [], ...shape } = componentShape;
shape.fills = symbolFills(shape.fillStyleId, shape.fills); shape.fills = symbolFills(shape.fillStyleId, shape.fills);
shape.strokes = symbolStrokes(shape.strokes); shape.strokes = symbolStrokes(shape.strokes);

View file

@ -1,20 +1,12 @@
// @TODO: Direct import on purpose, to avoid problems with the tsc linting
import { sleep } from '@plugin/utils/sleep';
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { PenpotPage } from '@ui/lib/types/penpotPage'; import { PenpotPage } from '@ui/lib/types/penpotPage';
import { createItems } from '.'; import { createItems } from '.';
export const createPage = async ( export const createPage = (file: PenpotFile, { name, options, children = [] }: PenpotPage) => {
file: PenpotFile,
{ name, options, children = [] }: PenpotPage
) => {
file.addPage(name, options); file.addPage(name, options);
createItems(file, children); createItems(file, children);
await sleep(0);
file.closePage(); file.closePage();
}; };

View file

@ -1,8 +1,7 @@
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { Paragraph, TextContent, TextNode, TextShape } from '@ui/lib/types/shapes/textShape'; import { Paragraph, TextContent, TextNode, TextShape } from '@ui/lib/types/shapes/textShape';
import { parseFigmaId } from '@ui/parser'; import { parseFigmaId, typographies } from '@ui/parser';
import { symbolFills, symbolStrokes } from '@ui/parser/creators/symbols'; import { symbolFills, symbolStrokes } from '@ui/parser/creators/symbols';
import { typographies } from '@ui/parser/libraries';
export const createText = ( export const createText = (
file: PenpotFile, file: PenpotFile,

View file

@ -1,12 +1,13 @@
import { sleep } from '@plugin/utils/sleep'; import { toArray } from '@common/map';
import { sleep } from '@common/sleep';
import { sendMessage } from '@ui/context'; import { sendMessage } from '@ui/context';
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { typographies } from '@ui/parser/libraries'; import { typographies } from '@ui/parser';
export const createTextLibrary = async (file: PenpotFile) => { export const createTextLibrary = async (file: PenpotFile) => {
let librariesBuilt = 1; let librariesBuilt = 1;
const libraries = typographies.all(); const libraries = toArray(typographies);
sendMessage({ sendMessage({
type: 'PROGRESS_TOTAL_ITEMS', type: 'PROGRESS_TOTAL_ITEMS',
@ -18,7 +19,7 @@ export const createTextLibrary = async (file: PenpotFile) => {
data: 'typoLibraries' data: 'typoLibraries'
}); });
for (const library of libraries) { for (const [_, library] of libraries) {
file.addLibraryTypography({ file.addLibraryTypography({
...library.typography, ...library.typography,
fontId: library.textStyle.fontId, fontId: library.textStyle.fontId,

View file

@ -1,6 +1,6 @@
import { Fill } from '@ui/lib/types/utils/fill'; import { Fill } from '@ui/lib/types/utils/fill';
import { ImageColor, PartialImageColor } from '@ui/lib/types/utils/imageColor'; import { ImageColor, PartialImageColor } from '@ui/lib/types/utils/imageColor';
import { colors, images } from '@ui/parser/libraries'; import { colors, images } from '@ui/parser';
export const symbolFills = (fillStyleId?: string, fills?: Fill[]): Fill[] | undefined => { export const symbolFills = (fillStyleId?: string, fills?: Fill[]): Fill[] | undefined => {
const nodeFills = fillStyleId ? colors.get(fillStyleId)?.fills : fills; const nodeFills = fillStyleId ? colors.get(fillStyleId)?.fills : fills;

View file

@ -1,3 +1,4 @@
export * from './libraries';
export * from './parse'; export * from './parse';
export * from './parseImage'; export * from './parseImage';
export * from './parseFigmaId'; export * from './parseFigmaId';

View file

@ -0,0 +1,24 @@
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
import { TypographyStyle } from '@ui/lib/types/shapes/textShape';
import { FillStyle } from '@ui/lib/types/utils/fill';
import { ImageColor } from '@ui/lib/types/utils/imageColor';
import { Uuid } from '@ui/lib/types/utils/uuid';
export type UiComponent = {
componentId: Uuid;
mainInstancePage?: Uuid;
mainInstanceId: Uuid;
componentFigmaId: string;
};
export const init = <T>(records: Record<string, T>, map: Map<string, T>) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
map = new Map(Object.entries(records));
};
export const typographies: Map<string, TypographyStyle> = new Map();
export const images: Map<string, ImageColor> = new Map();
export const identifiers: Map<string, Uuid> = new Map();
export const components: Map<string, UiComponent> = new Map();
export const componentShapes: Map<string, ComponentShape> = new Map();
export const colors: Map<string, FillStyle> = new Map();

View file

@ -1,19 +0,0 @@
import { FillStyle } from '@ui/lib/types/utils/fill';
class Colors {
private libraries: Map<string, FillStyle> = new Map();
public register(id: string, fillStyle: FillStyle) {
this.libraries.set(id, fillStyle);
}
public get(id: string): FillStyle | undefined {
return this.libraries.get(id);
}
public all(): FillStyle[] {
return Array.from(this.libraries.values());
}
}
export const colors = new Colors();

View file

@ -1,30 +0,0 @@
import { Uuid } from '@ui/lib/types/utils/uuid';
export type UiComponent = {
componentId: Uuid;
mainInstancePage?: Uuid;
mainInstanceId: Uuid;
componentFigmaId: string;
};
class Components {
private components: Map<string, UiComponent> = new Map();
public register(id: string, component: UiComponent) {
this.components.set(id, component);
}
public get(id: string): UiComponent | undefined {
return this.components.get(id);
}
public all(): UiComponent[] {
return Array.from(this.components.values());
}
public init() {
this.components.clear();
}
}
export const components = new Components();

View file

@ -1,19 +0,0 @@
import { Uuid } from '@ui/lib/types/utils/uuid';
class Identifiers {
private idMap: Map<string, Uuid> = new Map();
public init() {
this.idMap.clear();
}
public get(figmaId: string): Uuid | undefined {
return this.idMap.get(figmaId);
}
public register(figmaId: string, id: Uuid) {
this.idMap.set(figmaId, id);
}
}
export const identifiers = new Identifiers();

View file

@ -1,23 +0,0 @@
import { ImageColor } from '@ui/lib/types/utils/imageColor';
class Images {
private images: Map<string, ImageColor> = new Map();
public register(id: string, image: ImageColor) {
this.images.set(id, image);
}
public get(id: string): ImageColor | undefined {
return this.images.get(id);
}
public all(): ImageColor[] {
return Array.from(this.images.values());
}
public init() {
this.images.clear();
}
}
export const images = new Images();

View file

@ -1,19 +0,0 @@
import { TypographyStyle } from '@ui/lib/types/shapes/textShape';
class Typographies {
private libraries: Map<string, TypographyStyle> = 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 typographies = new Typographies();

View file

@ -1,5 +0,0 @@
export * from './Identifiers';
export * from './Colors';
export * from './Components';
export * from './Images';
export * from './Typographies';

View file

@ -1,20 +1,18 @@
import { components as componentsLibrary } from '@plugin/libraries/Components'; import { sleep } from '@common/sleep';
// @TODO: Direct import on purpose, to avoid problems with the tsc linting
import { sleep } from '@plugin/utils/sleep';
import { sendMessage } from '@ui/context'; import { sendMessage } from '@ui/context';
import { createFile } from '@ui/lib/penpot'; import { createFile } from '@ui/lib/penpot';
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; import { TypographyStyle } from '@ui/lib/types/shapes/textShape';
import { FillStyle } from '@ui/lib/types/utils/fill'; import { FillStyle } from '@ui/lib/types/utils/fill';
import { colors, componentShapes, images, init, typographies } from '@ui/parser';
import { buildFile } from '@ui/parser/creators'; import { buildFile } from '@ui/parser/creators';
import { colors, typographies, images as uiImages } from '@ui/parser/libraries';
import { PenpotDocument } from '@ui/types'; import { PenpotDocument } from '@ui/types';
import { parseImage } from '.'; import { parseImage } from '.';
const optimizeImages = async (images: Record<string, Uint8Array>) => { const optimizeImages = async (binaryImages: Record<string, Uint8Array>) => {
const imagesToOptimize = Object.entries(images); const imagesToOptimize = Object.entries(binaryImages);
if (imagesToOptimize.length === 0) return; if (imagesToOptimize.length === 0) return;
@ -32,7 +30,7 @@ const optimizeImages = async (images: Record<string, Uint8Array>) => {
for (const [key, bytes] of imagesToOptimize) { for (const [key, bytes] of imagesToOptimize) {
if (bytes) { if (bytes) {
uiImages.register(key, await parseImage(bytes)); images.set(key, await parseImage(bytes));
} }
sendMessage({ sendMessage({
@ -70,7 +68,7 @@ const prepareTypographyLibraries = async (
style.textStyle.typographyRefFile = file.getId(); style.textStyle.typographyRefFile = file.getId();
style.typography.id = typographyId; style.typography.id = typographyId;
typographies.register(key, style); typographies.set(key, style);
sendMessage({ sendMessage({
type: 'PROGRESS_PROCESSED_ITEMS', type: 'PROGRESS_PROCESSED_ITEMS',
@ -107,7 +105,7 @@ const prepareColorLibraries = async (file: PenpotFile, styles: Record<string, Fi
fillStyle.colors[index].refFile = file.getId(); fillStyle.colors[index].refFile = file.getId();
} }
colors.register(key, fillStyle); colors.set(key, fillStyle);
sendMessage({ sendMessage({
type: 'PROGRESS_PROCESSED_ITEMS', type: 'PROGRESS_PROCESSED_ITEMS',
@ -126,7 +124,7 @@ export const parse = async ({
paintStyles, paintStyles,
textStyles textStyles
}: PenpotDocument) => { }: PenpotDocument) => {
componentsLibrary.init(components); init(components, componentShapes);
const file = createFile(name); const file = createFile(name);

View file

@ -1,6 +1,6 @@
import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PenpotFile } from '@ui/lib/types/penpotFile';
import { Uuid } from '@ui/lib/types/utils/uuid'; import { Uuid } from '@ui/lib/types/utils/uuid';
import { identifiers } from '@ui/parser/libraries'; import { identifiers } from '@ui/parser';
export const parseFigmaId = ( export const parseFigmaId = (
file: PenpotFile, file: PenpotFile,
@ -8,19 +8,20 @@ export const parseFigmaId = (
shapeRef: boolean = false shapeRef: boolean = false
): Uuid | undefined => { ): Uuid | undefined => {
if (!figmaId) { if (!figmaId) {
if (shapeRef) { if (shapeRef) return;
return;
}
return file.newId(); return file.newId();
} }
const id = identifiers.get(figmaId); const id = identifiers.get(figmaId);
if (id) { if (id) {
return id; return id;
} }
const newId = file.newId(); const newId = file.newId();
identifiers.register(figmaId, newId);
identifiers.set(figmaId, newId);
return newId; return newId;
}; };

View file

@ -5,7 +5,7 @@
"useDefineForClassFields": true, "useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"], "lib": ["DOM", "DOM.Iterable", "ESNext"],
"paths": { "paths": {
"@plugin/*": ["./plugin-src/*"], "@common/*": ["./common/*"],
"@ui/*": ["./ui-src/*"], "@ui/*": ["./ui-src/*"],
"react": ["./node_modules/preact/compat/"], "react": ["./node_modules/preact/compat/"],
"react-dom": ["./node_modules/preact/compat/"], "react-dom": ["./node_modules/preact/compat/"],