Skip to content

Commit

Permalink
Remote components (External design systems) (#140)
Browse files Browse the repository at this point in the history
* remote components processing

* changeset

* fixes

* fixes

* fixes

* fixes

* fix everything

* revert for now

* fixes

* change delete nodes flag

---------

Co-authored-by: Jordi Sala Morales <[email protected]>
  • Loading branch information
Cenadros and jordisala1991 authored Jun 6, 2024
1 parent 3094f05 commit be5ff3b
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-lamps-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"penpot-exporter": minor
---

Remote components processing
30 changes: 30 additions & 0 deletions plugin-src/RemoteComponentLibrary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class RemoteComponentsLibrary {
private components: Record<string, ComponentNode | ComponentSetNode> = {};
private queue: string[] = [];

public register(id: string, component: ComponentNode | ComponentSetNode) {
if (!Object.prototype.hasOwnProperty.call(this.components, id)) {
this.queue.push(id);
}

this.components[id] = component;
}

public get(id: string): ComponentNode | ComponentSetNode | undefined {
return this.components[id];
}

public next(): ComponentNode | ComponentSetNode {
const lastKey = this.queue.pop();

if (!lastKey) throw new Error('No components to pop');

return this.components[lastKey];
}

public remaining(): number {
return this.queue.length;
}
}

export const remoteComponentLibrary = new RemoteComponentsLibrary();
1 change: 1 addition & 0 deletions plugin-src/transformers/transformComponentNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const transformComponentNode = async (
type: 'component',
name: node.name,
path: node.parent?.type === 'COMPONENT_SET' ? node.parent.name : '',
showContent: !node.clipsContent,
...transformFigmaIds(node),
...transformFills(node),
...transformEffects(node),
Expand Down
9 changes: 9 additions & 0 deletions plugin-src/transformers/transformDocumentNode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { componentsLibrary } from '@plugin/ComponentLibrary';
import { imagesLibrary } from '@plugin/ImageLibrary';
import { remoteComponentLibrary } from '@plugin/RemoteComponentLibrary';
import { translateRemoteChildren } from '@plugin/translators';
import { sleep } from '@plugin/utils';

import { PenpotDocument } from '@ui/types';
Expand Down Expand Up @@ -28,6 +30,13 @@ export const transformDocumentNode = async (node: DocumentNode): Promise<PenpotD
await sleep(0);
}

if (remoteComponentLibrary.remaining() > 0) {
children.push({
name: 'External Components',
children: await translateRemoteChildren()
});
}

const images: Record<string, Uint8Array> = {};

for (const [key, image] of Object.entries(imagesLibrary.all())) {
Expand Down
38 changes: 32 additions & 6 deletions plugin-src/transformers/transformInstanceNode.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { remoteComponentLibrary } from '@plugin/RemoteComponentLibrary';
import {
transformBlend,
transformChildren,
Expand All @@ -24,11 +25,16 @@ export const transformInstanceNode = async (
return;
}

if (isExternalComponent(mainComponent)) {
await registerExternalComponents(mainComponent);
}

return {
type: 'instance',
name: node.name,
mainComponentFigmaId: mainComponent.id,
isComponentRoot: isComponentRoot(node),
showContent: !node.clipsContent,
...transformFigmaIds(node),
...transformFills(node),
...transformEffects(node),
Expand All @@ -42,19 +48,39 @@ export const transformInstanceNode = async (
};
};

const registerExternalComponents = async (mainComponent: ComponentNode): Promise<void> => {
let component: ComponentSetNode | ComponentNode = mainComponent;

if (component.parent?.type === 'COMPONENT_SET') {
component = component.parent;
}

if (remoteComponentLibrary.get(component.id) !== undefined) {
return;
}

remoteComponentLibrary.register(component.id, component);
};

const isExternalComponent = (mainComponent: ComponentNode): boolean => {
return (
mainComponent.remote ||
(mainComponent.parent?.type === 'COMPONENT_SET' && mainComponent.parent.remote)
);
};

/**
* We do not want to process component instances in the following scenarios:
*
* 1. If the component comes from an external design system.
* 2. If the component does not have a parent. (it's been removed)
* 3. Main component can be in a ComponentSet (the same logic applies to the parent).
* 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 = (mainComponent: ComponentNode): boolean => {
return (
mainComponent.remote ||
mainComponent.parent === null ||
(mainComponent.parent === null && !mainComponent.remote) ||
(mainComponent.parent?.type === 'COMPONENT_SET' &&
(mainComponent.parent.parent === null || mainComponent.parent.remote))
mainComponent.parent.parent === null &&
!mainComponent.parent.remote)
);
};

Expand Down
17 changes: 17 additions & 0 deletions plugin-src/translators/translateChildren.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { remoteComponentLibrary } from '@plugin/RemoteComponentLibrary';
import { transformGroupNodeLike, transformSceneNode } from '@plugin/transformers';
import { transformMaskFigmaIds } from '@plugin/transformers/partials';
import { sleep } from '@plugin/utils';
Expand Down Expand Up @@ -50,3 +51,19 @@ export const translateChildren = async (

return transformedChildren;
};

export const translateRemoteChildren = async (): Promise<PenpotNode[]> => {
const transformedChildren: PenpotNode[] = [];

while (remoteComponentLibrary.remaining() > 0) {
const child = remoteComponentLibrary.next();

const penpotNode = await transformSceneNode(child);

if (penpotNode) transformedChildren.push(penpotNode);

await sleep(0);
}

return transformedChildren;
};
1 change: 1 addition & 0 deletions ui-src/lib/types/shapes/componentShape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type ComponentAttributes = {
type?: 'component';
name: string;
path: string;
showContent?: boolean;
mainInstanceId?: Uuid;
mainInstancePage?: Uuid;
};
1 change: 0 additions & 1 deletion ui-src/parser/creators/createComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export const createComponent = (file: PenpotFile, { figmaId }: ComponentRoot) =>

const frameId = createArtboard(file, {
...component,
showContent: true,
componentFile: file.getId(),
componentId,
componentRoot: true,
Expand Down
1 change: 0 additions & 1 deletion ui-src/parser/creators/createComponentInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export const createComponentInstance = (

createArtboard(file, {
...rest,
showContent: true,
shapeRef: uiComponent.mainInstanceId,
componentFile: file.getId(),
componentRoot: isComponentRoot,
Expand Down
1 change: 1 addition & 0 deletions ui-src/types/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export type ComponentInstance = ShapeGeomAttributes &
figmaId?: string;
figmaRelatedId?: string;
isComponentRoot: boolean;
showContent?: boolean;
type: 'instance';
};

0 comments on commit be5ff3b

Please sign in to comment.