diff --git a/.changeset/five-teachers-cheat.md b/.changeset/five-teachers-cheat.md deleted file mode 100644 index 69a36c60..00000000 --- a/.changeset/five-teachers-cheat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"penpot-exporter": patch ---- - -Add additional layout properties diff --git a/.changeset/heavy-timers-sit.md b/.changeset/heavy-timers-sit.md deleted file mode 100644 index 3387d394..00000000 --- a/.changeset/heavy-timers-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"penpot-exporter": minor ---- - -Add support for typographies diff --git a/.changeset/mean-clouds-jog.md b/.changeset/mean-clouds-jog.md deleted file mode 100644 index e4099469..00000000 --- a/.changeset/mean-clouds-jog.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"penpot-exporter": patch ---- - -Improve font weight translation diff --git a/.changeset/selfish-spies-cover.md b/.changeset/selfish-spies-cover.md deleted file mode 100644 index 6dcad8f1..00000000 --- a/.changeset/selfish-spies-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"penpot-exporter": patch ---- - -Fix letter spacing diff --git a/.changeset/strange-gorillas-knock.md b/.changeset/seven-roses-sniff.md similarity index 54% rename from .changeset/strange-gorillas-knock.md rename to .changeset/seven-roses-sniff.md index e9186d90..29658027 100644 --- a/.changeset/strange-gorillas-knock.md +++ b/.changeset/seven-roses-sniff.md @@ -2,4 +2,4 @@ "penpot-exporter": minor --- -Support for color libraries +Rework remote components diff --git a/.changeset/sixty-colts-sleep.md b/.changeset/sixty-colts-sleep.md deleted file mode 100644 index 21837c2f..00000000 --- a/.changeset/sixty-colts-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"penpot-exporter": patch ---- - -Improve paragraph indent using letter spacing diff --git a/CHANGELOG.md b/CHANGELOG.md index 418519c6..21c89bc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # penpot-exporter +## 0.8.1 + +### Patch Changes + +- [#194](https://github.com/penpot/penpot-exporter-figma-plugin/pull/194) [`53672d8`](https://github.com/penpot/penpot-exporter-figma-plugin/commit/53672d8b43111efa1dedc5deac358410943c2bc5) Thanks [@jordisala1991](https://github.com/jordisala1991)! - Fix local styles categorization system + +## 0.8.0 + +### Minor Changes + +- [#185](https://github.com/penpot/penpot-exporter-figma-plugin/pull/185) [`d3c144e`](https://github.com/penpot/penpot-exporter-figma-plugin/commit/d3c144e5e99777bc54635ad3f0067c6927041a90) Thanks [@Cenadros](https://github.com/Cenadros)! - Add support for typographies + +- [#183](https://github.com/penpot/penpot-exporter-figma-plugin/pull/183) [`a58f9e9`](https://github.com/penpot/penpot-exporter-figma-plugin/commit/a58f9e913de800047207dc86e4df01e3e3b3f235) Thanks [@Cenadros](https://github.com/Cenadros)! - Support for color libraries + +### Patch Changes + +- [#190](https://github.com/penpot/penpot-exporter-figma-plugin/pull/190) [`511b842`](https://github.com/penpot/penpot-exporter-figma-plugin/commit/511b842b129a9c97c917f5991acfbf1927494b7d) Thanks [@Cenadros](https://github.com/Cenadros)! - Add additional layout properties + +- [#185](https://github.com/penpot/penpot-exporter-figma-plugin/pull/185) [`d3c144e`](https://github.com/penpot/penpot-exporter-figma-plugin/commit/d3c144e5e99777bc54635ad3f0067c6927041a90) Thanks [@Cenadros](https://github.com/Cenadros)! - Improve font weight translation + +- [#185](https://github.com/penpot/penpot-exporter-figma-plugin/pull/185) [`d3c144e`](https://github.com/penpot/penpot-exporter-figma-plugin/commit/d3c144e5e99777bc54635ad3f0067c6927041a90) Thanks [@Cenadros](https://github.com/Cenadros)! - Fix letter spacing + +- [#191](https://github.com/penpot/penpot-exporter-figma-plugin/pull/191) [`b003704`](https://github.com/penpot/penpot-exporter-figma-plugin/commit/b00370410c0b50f4a177dc1a53c87bdad964d368) Thanks [@jordisala1991](https://github.com/jordisala1991)! - Improve paragraph indent using letter spacing + ## 0.7.1 ### Patch Changes diff --git a/package.json b/package.json index 5de93b4c..2844105e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "penpot-exporter", - "version": "0.7.1", + "version": "0.8.1", "description": "Penpot exporter", "type": "module", "scripts": { diff --git a/plugin-src/RemoteComponents.ts b/plugin-src/RemoteComponents.ts deleted file mode 100644 index f0dfbc04..00000000 --- a/plugin-src/RemoteComponents.ts +++ /dev/null @@ -1,39 +0,0 @@ -export class RemoteComponentsLibrary { - private components: Map = new Map(); - private queue: string[] = []; - - public register(id: string, component: ComponentNode | ComponentSetNode) { - if (!this.components.has(id)) { - this.queue.push(id); - } - - this.components.set(id, component); - } - - public get(id: string): ComponentNode | ComponentSetNode | undefined { - return this.components.get(id); - } - - public has(id: string): boolean { - return this.components.has(id); - } - - public next(): ComponentNode | ComponentSetNode { - const lastKey = this.queue.pop(); - - if (!lastKey) throw new Error('No components to pop'); - - const component = this.components.get(lastKey); - if (!component) throw new Error('Component not found'); - - return component; - } - - public remaining(): number { - return this.queue.length; - } - - public total(): number { - return this.components.size; - } -} diff --git a/plugin-src/libraries.ts b/plugin-src/libraries.ts index 07714633..86f07784 100644 --- a/plugin-src/libraries.ts +++ b/plugin-src/libraries.ts @@ -1,12 +1,9 @@ import { ComponentShape } from '@ui/lib/types/shapes/componentShape'; import { ComponentProperty } from '@ui/types'; -import { RemoteComponentsLibrary } from './RemoteComponents'; - export const textStyles: Map = new Map(); export const paintStyles: Map = new Map(); export const overrides: Map = new Map(); export const images: Map = new Map(); export const components: Map = new Map(); export const componentProperties: Map = new Map(); -export const remoteComponents = new RemoteComponentsLibrary(); diff --git a/plugin-src/processors/processPages.ts b/plugin-src/processors/processPages.ts index bc7e6349..b0b3ed8b 100644 --- a/plugin-src/processors/processPages.ts +++ b/plugin-src/processors/processPages.ts @@ -1,31 +1,10 @@ import { sleep } from '@common/sleep'; -import { remoteComponents } from '@plugin/libraries'; import { transformPageNode } from '@plugin/transformers'; -import { translateRemoteChildren } from '@plugin/translators'; import { PenpotPage } from '@ui/lib/types/penpotPage'; export const processPages = async (node: DocumentNode): Promise => { - const children = await processLocalDocument(node); - const remoteComponents = await processRemoteComponents(); - if (remoteComponents) { - children.push(remoteComponents); - } - - return children; -}; - -const processRemoteComponents = async (): Promise => { - if (remoteComponents.remaining() > 0) { - return { - name: 'External Components', - children: await translateRemoteChildren() - }; - } -}; - -const processLocalDocument = async (node: DocumentNode): Promise => { const children = []; let currentPage = 1; diff --git a/plugin-src/transformers/transformInstanceNode.ts b/plugin-src/transformers/transformInstanceNode.ts index 8efe1a83..05b32518 100644 --- a/plugin-src/transformers/transformInstanceNode.ts +++ b/plugin-src/transformers/transformInstanceNode.ts @@ -1,4 +1,4 @@ -import { overrides, remoteComponents } from '@plugin/libraries'; +import { overrides } from '@plugin/libraries'; import { transformAutoLayout, transformBlend, @@ -28,16 +28,11 @@ export const transformInstanceNode = async ( } const primaryComponent = getPrimaryComponent(mainComponent); - if (isUnprocessableComponent(primaryComponent)) { - return; - } - - if (primaryComponent.remote) { - registerExternalComponents(primaryComponent); - } - - if (node.overrides.length > 0) { + const isOrphan = isOrphanInstance(primaryComponent); + let nodeOverrides = {}; + if (!isOrphan && node.overrides.length > 0) { node.overrides.forEach(override => overrides.set(override.id, override.overriddenFields)); + nodeOverrides = transformOverrides(node); } if (node.visible !== mainComponent.visible) { @@ -53,6 +48,7 @@ export const transformInstanceNode = async ( mainComponentFigmaId: mainComponent.id, isComponentRoot: isComponentRoot(node), showContent: !node.clipsContent, + isOrphan, ...transformFigmaIds(node), ...transformFills(node), ...transformEffects(node), @@ -67,7 +63,7 @@ export const transformInstanceNode = async ( ...transformConstraints(node), ...transformAutoLayout(node), ...(await transformChildren(node)), - ...transformOverrides(node) + ...nodeOverrides }; }; @@ -79,22 +75,8 @@ const getPrimaryComponent = (mainComponent: ComponentNode): ComponentNode | Comp return mainComponent; }; -const registerExternalComponents = (primaryComponent: ComponentNode | ComponentSetNode): void => { - if (remoteComponents.has(primaryComponent.id)) { - return; - } - - remoteComponents.register(primaryComponent.id, primaryComponent); -}; - -/** - * We do not want to process component instances in the following scenarios: - * - * 1. If the component does not have a parent. (it's been removed) - * 2. Main component can be in a ComponentSet (the same logic applies to the parent). - */ -const isUnprocessableComponent = (primaryComponent: ComponentNode | ComponentSetNode): boolean => { - return primaryComponent.parent === null && !primaryComponent.remote; +const isOrphanInstance = (primaryComponent: ComponentNode | ComponentSetNode): boolean => { + return primaryComponent.parent === null || primaryComponent.remote; }; const isComponentRoot = (node: InstanceNode): boolean => { diff --git a/plugin-src/translators/styles/index.ts b/plugin-src/translators/styles/index.ts index 7a370c9d..c08dcedc 100644 --- a/plugin-src/translators/styles/index.ts +++ b/plugin-src/translators/styles/index.ts @@ -1,2 +1,4 @@ export * from './translatePaintStyle'; +export * from './translateStyleName'; +export * from './translateStylePath'; export * from './translateTextStyle'; diff --git a/plugin-src/translators/styles/translatePaintStyle.ts b/plugin-src/translators/styles/translatePaintStyle.ts index 8950d131..2a6d9f58 100644 --- a/plugin-src/translators/styles/translatePaintStyle.ts +++ b/plugin-src/translators/styles/translatePaintStyle.ts @@ -2,6 +2,8 @@ import { translateFill } from '@plugin/translators/fills/translateFills'; import { FillStyle } from '@ui/lib/types/utils/fill'; +import { translateStyleName, translateStylePath } from '.'; + export const translatePaintStyle = (figmaStyle: PaintStyle): FillStyle => { const fillStyle: FillStyle = { name: figmaStyle.name, @@ -10,12 +12,11 @@ export const translatePaintStyle = (figmaStyle: PaintStyle): FillStyle => { }; const colorName = (figmaStyle: PaintStyle, index: number): string => { - return figmaStyle.paints.length > 1 ? `Color ${index + 1}` : figmaStyle.name; + return figmaStyle.paints.length > 1 ? `Color ${index + 1}` : translateStyleName(figmaStyle); }; let index = 0; - const path = - (figmaStyle.remote ? 'Remote / ' : '') + (figmaStyle.paints.length > 1 ? figmaStyle.name : ''); + const path = translatePaintStylePath(figmaStyle); for (const fill of figmaStyle.paints) { const penpotFill = translateFill(fill); @@ -32,3 +33,13 @@ export const translatePaintStyle = (figmaStyle: PaintStyle): FillStyle => { return fillStyle; }; + +const translatePaintStylePath = (figmaStyle: PaintStyle) => { + const path = translateStylePath(figmaStyle); + + if (figmaStyle.paints.length <= 1) { + return path; + } + + return path + (path !== '' ? ' / ' : '') + translateStyleName(figmaStyle); +}; diff --git a/plugin-src/translators/styles/translateStyleName.ts b/plugin-src/translators/styles/translateStyleName.ts new file mode 100644 index 00000000..e7ee8422 --- /dev/null +++ b/plugin-src/translators/styles/translateStyleName.ts @@ -0,0 +1,9 @@ +export const translateStyleName = (figmaStyle: BaseStyle): string => { + const splitName = figmaStyle.name.split('/'); + + if (splitName.length > 0) { + return splitName.pop() as string; + } + + return figmaStyle.name; +}; diff --git a/plugin-src/translators/styles/translateStylePath.ts b/plugin-src/translators/styles/translateStylePath.ts new file mode 100644 index 00000000..cb07b560 --- /dev/null +++ b/plugin-src/translators/styles/translateStylePath.ts @@ -0,0 +1,16 @@ +export const translateStylePath = (figmaStyle: BaseStyleMixin) => { + const path = []; + + if (figmaStyle.remote) { + path.push('Remote'); + } + + if (figmaStyle.name.includes('/')) { + const pathParts = figmaStyle.name.split('/'); + pathParts.pop(); + + path.push(...pathParts); + } + + return path.join(' / '); +}; diff --git a/plugin-src/translators/styles/translateTextStyle.ts b/plugin-src/translators/styles/translateTextStyle.ts index 933c213b..69adaada 100644 --- a/plugin-src/translators/styles/translateTextStyle.ts +++ b/plugin-src/translators/styles/translateTextStyle.ts @@ -9,11 +9,11 @@ import { import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; -export const translateTextStyle = (figmaStyle: TextStyle): TypographyStyle => { - const name = (figmaStyle.remote ? 'Remote / ' : '') + figmaStyle.name; +import { translateStyleName, translateStylePath } from '.'; +export const translateTextStyle = (figmaStyle: TextStyle): TypographyStyle => { return { - name: figmaStyle.name, + name: translateStyleName(figmaStyle), textStyle: { ...translateFontName(figmaStyle.fontName), fontFamily: figmaStyle.fontName.family, @@ -25,8 +25,8 @@ export const translateTextStyle = (figmaStyle: TextStyle): TypographyStyle => { lineHeight: translateLineHeight(figmaStyle) }, typography: { - path: '', - name + path: translateStylePath(figmaStyle), + name: translateStyleName(figmaStyle) } }; }; diff --git a/plugin-src/translators/translateChildren.ts b/plugin-src/translators/translateChildren.ts index 7f58fdee..94b37ee0 100644 --- a/plugin-src/translators/translateChildren.ts +++ b/plugin-src/translators/translateChildren.ts @@ -1,6 +1,5 @@ import { sleep } from '@common/sleep'; -import { remoteComponents } from '@plugin/libraries'; import { transformGroupNodeLike, transformSceneNode } from '@plugin/transformers'; import { transformMaskFigmaIds } from '@plugin/transformers/partials'; @@ -62,35 +61,3 @@ export const translateChildren = async (children: readonly SceneNode[]): Promise return transformedChildren; }; - -export const translateRemoteChildren = async (): Promise => { - const transformedChildren: PenpotNode[] = []; - let currentRemote = 1; - - figma.ui.postMessage({ - type: 'PROGRESS_STEP', - data: 'remote' - }); - - while (remoteComponents.remaining() > 0) { - figma.ui.postMessage({ - type: 'PROGRESS_TOTAL_ITEMS', - data: remoteComponents.total() - }); - - const child = remoteComponents.next(); - - const penpotNode = await transformSceneNode(child); - - if (penpotNode) transformedChildren.push(penpotNode); - - figma.ui.postMessage({ - type: 'PROGRESS_PROCESSED_ITEMS', - data: currentRemote++ - }); - - await sleep(0); - } - - return transformedChildren; -}; diff --git a/ui-src/components/ExporterProgress.tsx b/ui-src/components/ExporterProgress.tsx index dcae13d5..09704a59 100644 --- a/ui-src/components/ExporterProgress.tsx +++ b/ui-src/components/ExporterProgress.tsx @@ -15,10 +15,6 @@ const stepMessages: Record = { total: 'pages processed 💪', current: 'Currently processing layer' }, - remote: { - total: 'remote components processed 📦', - current: 'Currently processing layer' - }, images: { total: 'images downloaded 📸' }, @@ -74,7 +70,6 @@ const StepProgress = (): JSX.Element | null => { switch (step) { case 'processing': - case 'remote': case 'images': case 'optimization': case 'building': diff --git a/ui-src/context/useFigma.ts b/ui-src/context/useFigma.ts index 393d6118..80c590e5 100644 --- a/ui-src/context/useFigma.ts +++ b/ui-src/context/useFigma.ts @@ -21,7 +21,6 @@ export type UseFigmaHook = { export type Steps = | 'processing' - | 'remote' | 'images' | 'optimization' | 'building' diff --git a/ui-src/parser/creators/createComponentInstance.ts b/ui-src/parser/creators/createComponentInstance.ts index 676d9661..18d47816 100644 --- a/ui-src/parser/creators/createComponentInstance.ts +++ b/ui-src/parser/creators/createComponentInstance.ts @@ -1,10 +1,13 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; +import { Uuid } from '@ui/lib/types/utils/uuid'; import { components, parseFigmaId } from '@ui/parser'; import { symbolTouched } from '@ui/parser/creators/symbols'; import { ComponentInstance } from '@ui/types'; import { createArtboard } from '.'; +let remoteFileId: Uuid | undefined = undefined; + export const createComponentInstance = ( file: PenpotFile, { type, mainComponentFigmaId, isComponentRoot, ...shape }: ComponentInstance @@ -19,7 +22,7 @@ export const createComponentInstance = ( if (!shape.figmaRelatedId) { shape.shapeRef = uiComponent.mainInstanceId; } - shape.componentFile = file.getId(); + shape.componentFile = shape.isOrphan ? getRemoteFileId(file) : file.getId(); shape.componentRoot = isComponentRoot; shape.componentId = uiComponent.componentId; shape.touched = symbolTouched( @@ -48,3 +51,11 @@ const createUiComponent = (file: PenpotFile, mainComponentFigmaId: string) => { return uiComponent; }; + +const getRemoteFileId = (file: PenpotFile): Uuid => { + if (!remoteFileId) { + remoteFileId = file.newId(); + } + + return remoteFileId; +}; diff --git a/ui-src/types/component.ts b/ui-src/types/component.ts index 6bcb8fa8..eab772b8 100644 --- a/ui-src/types/component.ts +++ b/ui-src/types/component.ts @@ -26,6 +26,7 @@ export type ComponentInstance = ShapeGeomAttributes & figmaRelatedId?: string; isComponentRoot: boolean; showContent?: boolean; + isOrphan: boolean; type: 'instance'; };