mirror of
https://github.com/penpot/penpot-exporter-figma-plugin.git
synced 2025-01-08 16:10:07 -05:00
Components Library (#125)
* components library management * components library management * fixes * fixes
This commit is contained in:
parent
32aafbcf9d
commit
5d4ace337b
19 changed files with 138 additions and 70 deletions
plugin-src
ui-src
23
plugin-src/ComponentLibrary.ts
Normal file
23
plugin-src/ComponentLibrary.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
|
||||
|
||||
class ComponentLibrary {
|
||||
private components: Record<string, ComponentShape> = {};
|
||||
|
||||
public register(id: string, component: ComponentShape) {
|
||||
this.components[id] = component;
|
||||
}
|
||||
|
||||
public get(id: string): ComponentShape | undefined {
|
||||
return this.components[id];
|
||||
}
|
||||
|
||||
public all(): Record<string, ComponentShape> {
|
||||
return this.components;
|
||||
}
|
||||
|
||||
public init(components: Record<string, ComponentShape>): void {
|
||||
this.components = components;
|
||||
}
|
||||
}
|
||||
|
||||
export const componentsLibrary = new ComponentLibrary();
|
|
@ -1,5 +1,7 @@
|
|||
import { componentsLibrary } from '@plugin/ComponentLibrary';
|
||||
import {
|
||||
transformBlend,
|
||||
transformChildren,
|
||||
transformCornerRadius,
|
||||
transformDimensionAndPosition,
|
||||
transformEffects,
|
||||
|
@ -8,16 +10,15 @@ import {
|
|||
transformSceneNode,
|
||||
transformStrokes
|
||||
} from '@plugin/transformers/partials';
|
||||
import { transformChildren } from '@plugin/transformers/partials';
|
||||
|
||||
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
|
||||
import { ComponentRoot } from '@ui/types';
|
||||
|
||||
export const transformComponentNode = async (
|
||||
node: ComponentNode,
|
||||
baseX: number,
|
||||
baseY: number
|
||||
): Promise<ComponentShape> => {
|
||||
return {
|
||||
): Promise<ComponentRoot> => {
|
||||
componentsLibrary.register(node.id, {
|
||||
type: 'component',
|
||||
name: node.name,
|
||||
path: '',
|
||||
|
@ -30,5 +31,10 @@ export const transformComponentNode = async (
|
|||
...transformCornerRadius(node),
|
||||
...(await transformChildren(node, baseX + node.x, baseY + node.y)),
|
||||
...transformDimensionAndPosition(node, baseX, baseY)
|
||||
});
|
||||
|
||||
return {
|
||||
figmaId: node.id,
|
||||
type: 'component'
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { PenpotDocument } from '@ui/lib/types/penpotDocument';
|
||||
import { componentsLibrary } from '@plugin/ComponentLibrary';
|
||||
|
||||
import { PenpotDocument } from '@ui/types';
|
||||
|
||||
import { transformPageNode } from '.';
|
||||
|
||||
export const transformDocumentNode = async (node: DocumentNode): Promise<PenpotDocument> => {
|
||||
return {
|
||||
name: node.name,
|
||||
children: await Promise.all(node.children.map(child => transformPageNode(child)))
|
||||
children: await Promise.all(node.children.map(child => transformPageNode(child))),
|
||||
components: componentsLibrary.all()
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { PenpotNode } from '@ui/lib/types/penpotNode';
|
||||
import { PenpotNode } from '@ui/types';
|
||||
|
||||
import {
|
||||
transformBooleanNode,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { transformGroupNodeLike, transformSceneNode } from '@plugin/transformers';
|
||||
|
||||
import { PenpotNode } from '@ui/lib/types/penpotNode';
|
||||
import { PenpotNode } from '@ui/types';
|
||||
|
||||
/**
|
||||
* Translates the children of a node that acts as a mask.
|
||||
|
|
|
@ -3,8 +3,8 @@ import { useEffect, useState } from 'react';
|
|||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
|
||||
import { Stack } from '@ui/components/Stack';
|
||||
import { PenpotDocument } from '@ui/lib/types/penpotDocument';
|
||||
import { parse } from '@ui/parser';
|
||||
import { PenpotDocument } from '@ui/types';
|
||||
|
||||
import { MissingFontsSection } from './MissingFontsSection';
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
import { PenpotPage } from './penpotPage';
|
||||
|
||||
export type PenpotDocument = {
|
||||
name: string;
|
||||
children?: PenpotPage[];
|
||||
};
|
|
@ -1,3 +1,3 @@
|
|||
import { PenpotNode } from '@ui/lib/types/penpotNode';
|
||||
import { PenpotNode } from '@ui/types';
|
||||
|
||||
export type Children = { children?: PenpotNode[] };
|
||||
|
|
|
@ -1,38 +1,34 @@
|
|||
import { componentsLibrary } from '@plugin/ComponentLibrary';
|
||||
|
||||
import { PenpotFile } from '@ui/lib/types/penpotFile';
|
||||
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
|
||||
import { components } from '@ui/parser/libraries';
|
||||
import { uiComponents } from '@ui/parser/libraries';
|
||||
import { ComponentRoot } from '@ui/types';
|
||||
|
||||
import { createArtboard } from '.';
|
||||
|
||||
export const createComponent = (
|
||||
file: PenpotFile,
|
||||
{ type, path, children = [], ...rest }: ComponentShape
|
||||
) => {
|
||||
export const createComponent = (file: PenpotFile, { figmaId }: ComponentRoot) => {
|
||||
const frameId = file.newId();
|
||||
const componentId = file.newId();
|
||||
|
||||
const commonStructure = {
|
||||
...rest,
|
||||
children,
|
||||
const component = componentsLibrary.get(figmaId);
|
||||
if (!component) {
|
||||
return;
|
||||
}
|
||||
|
||||
createArtboard(file, {
|
||||
...component,
|
||||
componentFile: file.getId(),
|
||||
componentId: componentId,
|
||||
componentRoot: true,
|
||||
mainInstance: true
|
||||
};
|
||||
|
||||
createArtboard(file, {
|
||||
...commonStructure,
|
||||
id: frameId,
|
||||
mainInstance: true,
|
||||
id: frameId,
|
||||
type: 'frame'
|
||||
});
|
||||
|
||||
components.add({
|
||||
...commonStructure,
|
||||
id: componentId,
|
||||
mainInstanceId: frameId,
|
||||
uiComponents.register(figmaId, {
|
||||
componentId,
|
||||
mainInstancePage: file.getCurrentPageId(),
|
||||
path,
|
||||
type
|
||||
componentFigmaId: figmaId,
|
||||
mainInstanceId: frameId
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,12 +1,29 @@
|
|||
import { componentsLibrary } from '@plugin/ComponentLibrary';
|
||||
|
||||
import { PenpotFile } from '@ui/lib/types/penpotFile';
|
||||
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
|
||||
import { components } from '@ui/parser/libraries';
|
||||
import { uiComponents } from '@ui/parser/libraries';
|
||||
|
||||
import { createItems } from '.';
|
||||
|
||||
export const createComponentLibrary = (file: PenpotFile) => {
|
||||
components.get().forEach(({ children = [], ...rest }: ComponentShape) => {
|
||||
file.startComponent(rest);
|
||||
uiComponents.all().forEach(uiComponent => {
|
||||
const component = componentsLibrary.get(uiComponent.componentFigmaId);
|
||||
if (!component) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { children = [], ...rest } = component;
|
||||
|
||||
file.startComponent({
|
||||
...rest,
|
||||
id: uiComponent.componentId,
|
||||
componentId: uiComponent.componentId,
|
||||
mainInstancePage: uiComponent.mainInstancePage,
|
||||
mainInstanceId: uiComponent.mainInstanceId,
|
||||
componentRoot: true,
|
||||
mainInstance: true,
|
||||
componentFile: file.getId()
|
||||
});
|
||||
|
||||
createItems(file, children);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { PenpotFile } from '@ui/lib/types/penpotFile';
|
||||
import { PenpotNode } from '@ui/lib/types/penpotNode';
|
||||
import { PenpotNode } from '@ui/types';
|
||||
|
||||
import {
|
||||
createArtboard,
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
|
||||
|
||||
class Components {
|
||||
private components: ComponentShape[] = [];
|
||||
|
||||
public add(component: ComponentShape) {
|
||||
this.components.push(component);
|
||||
}
|
||||
|
||||
public get() {
|
||||
return this.components;
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.components = [];
|
||||
}
|
||||
}
|
||||
|
||||
export const components = new Components();
|
30
ui-src/parser/libraries/UiComponents.ts
Normal file
30
ui-src/parser/libraries/UiComponents.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { Uuid } from '@ui/lib/types/utils/uuid';
|
||||
|
||||
type UiComponent = {
|
||||
componentId: Uuid;
|
||||
mainInstancePage: Uuid;
|
||||
mainInstanceId: Uuid;
|
||||
componentFigmaId: string;
|
||||
};
|
||||
|
||||
class UiComponents {
|
||||
private components: Record<string, UiComponent> = {};
|
||||
|
||||
public register(id: string, component: UiComponent) {
|
||||
this.components[id] = component;
|
||||
}
|
||||
|
||||
public get(id: string): UiComponent | undefined {
|
||||
return this.components[id];
|
||||
}
|
||||
|
||||
public all(): UiComponent[] {
|
||||
return Object.values(this.components);
|
||||
}
|
||||
|
||||
public init() {
|
||||
this.components = {};
|
||||
}
|
||||
}
|
||||
|
||||
export const uiComponents = new UiComponents();
|
|
@ -1 +1 @@
|
|||
export * from './Components';
|
||||
export * from './UiComponents';
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { createFile } from '@ui/lib/penpot';
|
||||
import { PenpotDocument } from '@ui/lib/types/penpotDocument';
|
||||
import { createComponentLibrary, createPage } from '@ui/parser/creators';
|
||||
import { components } from '@ui/parser/libraries';
|
||||
import { componentsLibrary } from '@plugin/ComponentLibrary';
|
||||
|
||||
export const parse = ({ name, children = [] }: PenpotDocument) => {
|
||||
components.clear();
|
||||
import { createFile } from '@ui/lib/penpot';
|
||||
import { createComponentLibrary, createPage } from '@ui/parser/creators';
|
||||
import { uiComponents } from '@ui/parser/libraries/UiComponents';
|
||||
import { PenpotDocument } from '@ui/types';
|
||||
|
||||
export const parse = ({ name, children = [], components }: PenpotDocument) => {
|
||||
componentsLibrary.init(components);
|
||||
uiComponents.init();
|
||||
|
||||
const file = createFile(name);
|
||||
|
||||
|
|
4
ui-src/types/componentRoot.ts
Normal file
4
ui-src/types/componentRoot.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export type ComponentRoot = {
|
||||
figmaId: string;
|
||||
type: 'component';
|
||||
};
|
3
ui-src/types/index.ts
Normal file
3
ui-src/types/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './componentRoot';
|
||||
export * from './penpotDocument';
|
||||
export * from './penpotNode';
|
8
ui-src/types/penpotDocument.ts
Normal file
8
ui-src/types/penpotDocument.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { PenpotPage } from '@ui/lib/types/penpotPage';
|
||||
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
|
||||
|
||||
export type PenpotDocument = {
|
||||
name: string;
|
||||
children?: PenpotPage[];
|
||||
components: Record<string, ComponentShape>;
|
||||
};
|
|
@ -1,11 +1,11 @@
|
|||
import { BoolShape } from '@ui/lib/types/shapes/boolShape';
|
||||
import { CircleShape } from '@ui/lib/types/shapes/circleShape';
|
||||
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
|
||||
import { FrameShape } from '@ui/lib/types/shapes/frameShape';
|
||||
import { GroupShape } from '@ui/lib/types/shapes/groupShape';
|
||||
import { PathShape } from '@ui/lib/types/shapes/pathShape';
|
||||
import { RectShape } from '@ui/lib/types/shapes/rectShape';
|
||||
import { TextShape } from '@ui/lib/types/shapes/textShape';
|
||||
import { ComponentRoot } from '@ui/types';
|
||||
|
||||
export type PenpotNode =
|
||||
| FrameShape
|
||||
|
@ -15,4 +15,4 @@ export type PenpotNode =
|
|||
| CircleShape
|
||||
| TextShape
|
||||
| BoolShape
|
||||
| ComponentShape;
|
||||
| ComponentRoot;
|
Loading…
Reference in a new issue