diff --git a/.changeset/seven-roses-sniff.md b/.changeset/seven-roses-sniff.md new file mode 100644 index 0000000..2965802 --- /dev/null +++ b/.changeset/seven-roses-sniff.md @@ -0,0 +1,5 @@ +--- +"penpot-exporter": minor +--- + +Rework remote components diff --git a/plugin-src/RemoteComponents.ts b/plugin-src/RemoteComponents.ts deleted file mode 100644 index f0dfbc0..0000000 --- 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 81207c4..7c115a7 100644 --- a/plugin-src/libraries.ts +++ b/plugin-src/libraries.ts @@ -1,10 +1,7 @@ import { ComponentShape } from '@ui/lib/types/shapes/componentShape'; -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 remoteComponents = new RemoteComponentsLibrary(); diff --git a/plugin-src/processors/processPages.ts b/plugin-src/processors/processPages.ts index bc7e634..b0b3ed8 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 5598b7a..174009e 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,18 +28,14 @@ export const transformInstanceNode = async ( } const primaryComponent = getPrimaryComponent(mainComponent); - if (isUnprocessableComponent(primaryComponent)) { - return; - } - - if (primaryComponent.remote) { - registerExternalComponents(primaryComponent); - } - - registerTextVariableOverrides(node, primaryComponent); - - if (node.overrides.length > 0) { - node.overrides.forEach(override => overrides.set(override.id, override.overriddenFields)); + const isOrphan = isOrphanInstance(primaryComponent); + let nodeOverrides = {}; + if (!isOrphan) { + registerTextVariableOverrides(node, primaryComponent); + if (node.overrides.length > 0) { + node.overrides.forEach(override => overrides.set(override.id, override.overriddenFields)); + } + nodeOverrides = transformOverrides(node); } return { @@ -48,6 +44,7 @@ export const transformInstanceNode = async ( mainComponentFigmaId: mainComponent.id, isComponentRoot: isComponentRoot(node), showContent: !node.clipsContent, + isOrphan, ...transformFigmaIds(node), ...transformFills(node), ...transformEffects(node), @@ -62,7 +59,7 @@ export const transformInstanceNode = async ( ...transformConstraints(node), ...transformAutoLayout(node), ...(await transformChildren(node)), - ...transformOverrides(node) + ...nodeOverrides }; }; @@ -74,14 +71,6 @@ 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); -}; - const getComponentTextPropertyOverrides = ( node: InstanceNode, primaryComponent: ComponentNode | ComponentSetNode @@ -133,14 +122,8 @@ const registerTextVariableOverrides = ( } }; -/** - * 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/translateChildren.ts b/plugin-src/translators/translateChildren.ts index 7f58fde..94b37ee 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 dcae13d..09704a5 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 393d611..80c590e 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 03d5c61..48aff57 100644 --- a/ui-src/parser/creators/createComponentInstance.ts +++ b/ui-src/parser/creators/createComponentInstance.ts @@ -1,9 +1,12 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; +import { Uuid } from '@ui/lib/types/utils/uuid'; import { components, parseFigmaId } from '@ui/parser'; import { ComponentInstance } from '@ui/types'; import { createArtboard } from '.'; +let remoteFileId: Uuid | undefined = undefined; + export const createComponentInstance = ( file: PenpotFile, { @@ -23,7 +26,7 @@ export const createComponentInstance = ( } shape.shapeRef = uiComponent.mainInstanceId; - shape.componentFile = file.getId(); + shape.componentFile = shape.isOrphan ? getRemoteFileId(file) : file.getId(); shape.componentRoot = isComponentRoot; shape.componentId = uiComponent.componentId; @@ -46,3 +49,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 eeff6ac..9c5095c 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'; };