diff --git a/plugin-src/transformers/partials/transformChildren.ts b/plugin-src/transformers/partials/transformChildren.ts index 05b9806..20bb5e5 100644 --- a/plugin-src/transformers/partials/transformChildren.ts +++ b/plugin-src/transformers/partials/transformChildren.ts @@ -6,16 +6,13 @@ const nodeActsAsMask = (node: SceneNode): boolean => { return 'isMask' in node && node.isMask; }; -export const transformChildren = async ( - node: ChildrenMixin, - baseRotation: number = 0 -): Promise => { +export const transformChildren = async (node: ChildrenMixin): Promise => { const maskIndex = node.children.findIndex(nodeActsAsMask); const containsMask = maskIndex !== -1; return { children: containsMask - ? await translateMaskChildren(node.children, maskIndex, baseRotation) - : await translateChildren(node.children, baseRotation) + ? await translateMaskChildren(node.children, maskIndex) + : await translateChildren(node.children) }; }; diff --git a/plugin-src/transformers/partials/transformRotationAndPosition.ts b/plugin-src/transformers/partials/transformRotationAndPosition.ts index 9b2577f..2520580 100644 --- a/plugin-src/transformers/partials/transformRotationAndPosition.ts +++ b/plugin-src/transformers/partials/transformRotationAndPosition.ts @@ -1,13 +1,12 @@ import { translateRotation, translateZeroRotation } from '@plugin/translators'; -import { applyInverseRotation, hasRotation } from '@plugin/utils'; +import { applyInverseRotation, getRotation, hasRotation } from '@plugin/utils'; import { ShapeBaseAttributes, ShapeGeomAttributes } from '@ui/lib/types/shapes/shape'; export const transformRotation = ( - node: LayoutMixin, - baseRotation: number + node: LayoutMixin ): Pick => { - const rotation = node.rotation + baseRotation; + const rotation = getRotation(node.absoluteTransform); if (!hasRotation(rotation)) { return translateZeroRotation(); @@ -17,13 +16,12 @@ export const transformRotation = ( }; export const transformRotationAndPosition = ( - node: LayoutMixin, - baseRotation: number + node: LayoutMixin ): Pick & Pick => { - const rotation = node.rotation + baseRotation; const x = node.absoluteTransform[0][2]; const y = node.absoluteTransform[1][2]; + const rotation = getRotation(node.absoluteTransform); if (!hasRotation(rotation) || !node.absoluteBoundingBox) { return { diff --git a/plugin-src/transformers/partials/transformVectorPaths.ts b/plugin-src/transformers/partials/transformVectorPaths.ts index f9a06ac..b2ee086 100644 --- a/plugin-src/transformers/partials/transformVectorPaths.ts +++ b/plugin-src/transformers/partials/transformVectorPaths.ts @@ -13,7 +13,7 @@ import { translateCommands, translateWindingRule } from '@plugin/translators/vec import { PathShape } from '@ui/lib/types/shapes/pathShape'; -export const transformVectorPaths = (node: VectorNode, baseRotation: number): PathShape[] => { +export const transformVectorPaths = (node: VectorNode): PathShape[] => { const pathShapes = node.vectorPaths .filter((vectorPath, index) => { return ( @@ -22,7 +22,7 @@ export const transformVectorPaths = (node: VectorNode, baseRotation: number): Pa ); }) .map((vectorPath, index) => - transformVectorPath(node, vectorPath, (node.vectorNetwork.regions ?? [])[index], baseRotation) + transformVectorPath(node, vectorPath, (node.vectorNetwork.regions ?? [])[index]) ); const geometryShapes = node.fillGeometry @@ -32,7 +32,7 @@ export const transformVectorPaths = (node: VectorNode, baseRotation: number): Pa vectorPath => normalizePath(vectorPath.data) === normalizePath(geometry.data) ) ) - .map(geometry => transformVectorPath(node, geometry, undefined, baseRotation)); + .map(geometry => transformVectorPath(node, geometry, undefined)); return [...geometryShapes, ...pathShapes]; }; @@ -58,15 +58,14 @@ const nodeHasFills = ( const transformVectorPath = ( node: VectorNode, vectorPath: VectorPath, - vectorRegion: VectorRegion | undefined, - baseRotation: number + vectorRegion: VectorRegion | undefined ): PathShape => { const normalizedPaths = parseSVG(vectorPath.data); return { type: 'path', name: 'svg-path', - content: translateCommands(node, normalizedPaths, baseRotation), + content: translateCommands(node, normalizedPaths), fills: vectorPath.windingRule === 'NONE' ? [] : translateFills(vectorRegion?.fills ?? node.fills), svgAttrs: { diff --git a/plugin-src/transformers/transformBooleanNode.ts b/plugin-src/transformers/transformBooleanNode.ts index defb308..c31481f 100644 --- a/plugin-src/transformers/transformBooleanNode.ts +++ b/plugin-src/transformers/transformBooleanNode.ts @@ -16,21 +16,18 @@ import { translateBoolType } from '@plugin/translators'; import { BoolShape } from '@ui/lib/types/shapes/boolShape'; -export const transformBooleanNode = async ( - node: BooleanOperationNode, - baseRotation: number -): Promise => { +export const transformBooleanNode = async (node: BooleanOperationNode): Promise => { return { type: 'bool', name: node.name, boolType: translateBoolType(node.booleanOperation), ...transformFigmaIds(node), - ...(await transformChildren(node, baseRotation)), + ...(await transformChildren(node)), ...transformFills(node), ...transformEffects(node), ...transformStrokes(node), ...transformDimension(node), - ...transformRotationAndPosition(node, baseRotation), + ...transformRotationAndPosition(node), ...transformSceneNode(node), ...transformBlend(node), ...transformProportion(node), diff --git a/plugin-src/transformers/transformComponentNode.ts b/plugin-src/transformers/transformComponentNode.ts index 5514877..311d872 100644 --- a/plugin-src/transformers/transformComponentNode.ts +++ b/plugin-src/transformers/transformComponentNode.ts @@ -18,10 +18,7 @@ import { import { ComponentRoot } from '@ui/types'; -export const transformComponentNode = async ( - node: ComponentNode, - baseRotation: number -): Promise => { +export const transformComponentNode = async (node: ComponentNode): Promise => { componentsLibrary.register(node.id, { type: 'component', name: node.name, @@ -36,9 +33,9 @@ export const transformComponentNode = async ( ...transformProportion(node), ...transformLayoutAttributes(node, true), ...transformCornerRadius(node), - ...(await transformChildren(node, node.rotation + baseRotation)), + ...(await transformChildren(node)), ...transformDimension(node), - ...transformRotationAndPosition(node, baseRotation), + ...transformRotationAndPosition(node), ...transformConstraints(node), ...transformAutoLayout(node) }); diff --git a/plugin-src/transformers/transformEllipseNode.ts b/plugin-src/transformers/transformEllipseNode.ts index 0675b41..cf0daba 100644 --- a/plugin-src/transformers/transformEllipseNode.ts +++ b/plugin-src/transformers/transformEllipseNode.ts @@ -15,7 +15,7 @@ import { import { CircleShape } from '@ui/lib/types/shapes/circleShape'; -export const transformEllipseNode = (node: EllipseNode, baseRotation: number): CircleShape => { +export const transformEllipseNode = (node: EllipseNode): CircleShape => { return { type: 'circle', name: node.name, @@ -24,7 +24,7 @@ export const transformEllipseNode = (node: EllipseNode, baseRotation: number): C ...transformEffects(node), ...transformStrokes(node), ...transformDimension(node), - ...transformRotationAndPosition(node, baseRotation), + ...transformRotationAndPosition(node), ...transformSceneNode(node), ...transformBlend(node), ...transformProportion(node), diff --git a/plugin-src/transformers/transformFrameNode.ts b/plugin-src/transformers/transformFrameNode.ts index 2dea828..870a7d3 100644 --- a/plugin-src/transformers/transformFrameNode.ts +++ b/plugin-src/transformers/transformFrameNode.ts @@ -24,18 +24,15 @@ const isSectionNode = (node: FrameNode | SectionNode | ComponentSetNode): node i }; export const transformFrameNode = async ( - node: FrameNode | SectionNode | ComponentSetNode, - baseRotation: number + node: FrameNode | SectionNode | ComponentSetNode ): Promise => { let frameSpecificAttributes: Partial = {}; let referencePoint: Point = { x: node.absoluteTransform[0][2], y: node.absoluteTransform[1][2] }; - let rotation = baseRotation; if (!isSectionNode(node)) { - const { x, y, ...transformAndRotation } = transformRotationAndPosition(node, baseRotation); + const { x, y, ...transformAndRotation } = transformRotationAndPosition(node); referencePoint = { x, y }; - rotation += node.rotation; // Figma API does not expose strokes, blend modes, corner radius, or constraint proportions for sections, // they plan to add it in the future. Refactor this when available. @@ -63,7 +60,7 @@ export const transformFrameNode = async ( ...referencePoint, ...frameSpecificAttributes, ...transformDimension(node), - ...(await transformChildren(node, rotation)), + ...(await transformChildren(node)), ...transformSceneNode(node), ...transformOverrides(node) }; diff --git a/plugin-src/transformers/transformGroupNode.ts b/plugin-src/transformers/transformGroupNode.ts index b5246f4..471c718 100644 --- a/plugin-src/transformers/transformGroupNode.ts +++ b/plugin-src/transformers/transformGroupNode.ts @@ -11,29 +11,25 @@ import { transformChildren } from '@plugin/transformers/partials'; import { GroupShape } from '@ui/lib/types/shapes/groupShape'; -export const transformGroupNode = async ( - node: GroupNode, - baseRotation: number -): Promise => { +export const transformGroupNode = async (node: GroupNode): Promise => { return { ...transformFigmaIds(node), - ...transformGroupNodeLike(node, baseRotation), + ...transformGroupNodeLike(node), ...transformEffects(node), ...transformBlend(node), - ...(await transformChildren(node, baseRotation)), + ...(await transformChildren(node)), ...transformOverrides(node) }; }; export const transformGroupNodeLike = ( - node: BaseNodeMixin & LayoutMixin & SceneNodeMixin, - baseRotation: number + node: BaseNodeMixin & LayoutMixin & SceneNodeMixin ): GroupShape => { return { type: 'group', name: node.name, ...transformDimension(node), - ...transformRotationAndPosition(node, baseRotation), + ...transformRotationAndPosition(node), ...transformSceneNode(node) }; }; diff --git a/plugin-src/transformers/transformInstanceNode.ts b/plugin-src/transformers/transformInstanceNode.ts index 08a3862..2843d5c 100644 --- a/plugin-src/transformers/transformInstanceNode.ts +++ b/plugin-src/transformers/transformInstanceNode.ts @@ -21,8 +21,7 @@ import { import { ComponentInstance, ComponentTextPropertyOverride } from '@ui/types'; export const transformInstanceNode = async ( - node: InstanceNode, - baseRotation: number + node: InstanceNode ): Promise => { const mainComponent = await node.getMainComponentAsync(); if (mainComponent === null) { @@ -62,10 +61,10 @@ export const transformInstanceNode = async ( ...transformLayoutAttributes(node, true), ...transformCornerRadius(node), ...transformDimension(node), - ...transformRotationAndPosition(node, baseRotation), + ...transformRotationAndPosition(node), ...transformConstraints(node), ...transformAutoLayout(node), - ...(await transformChildren(node, node.rotation + baseRotation)), + ...(await transformChildren(node)), ...transformOverrides(node) }; }; diff --git a/plugin-src/transformers/transformLineNode.ts b/plugin-src/transformers/transformLineNode.ts index 5120add..827d6ae 100644 --- a/plugin-src/transformers/transformLineNode.ts +++ b/plugin-src/transformers/transformLineNode.ts @@ -20,11 +20,11 @@ import { Segment } from '@ui/lib/types/shapes/pathShape'; * * To represent the line rotated we do take into account the rotation of the line, but only in its content. */ -export const transformLineNode = (node: LineNode, baseRotation: number): PathShape => { +export const transformLineNode = (node: LineNode): PathShape => { return { type: 'path', name: node.name, - content: translateLineNode(node, baseRotation), + content: translateLineNode(node), ...transformFigmaIds(node), ...transformStrokes(node), ...transformEffects(node), @@ -37,23 +37,19 @@ export const transformLineNode = (node: LineNode, baseRotation: number): PathSha }; }; -const translateLineNode = (node: LineNode, baseRotation: number): Segment[] => { - return translateCommands( - node, - [ - { - x: 0, - y: 0, - command: 'moveto', - code: 'M' - }, - { - x: node.width, - y: 0, - command: 'lineto', - code: 'L' - } - ], - baseRotation - ); +const translateLineNode = (node: LineNode): Segment[] => { + return translateCommands(node, [ + { + x: 0, + y: 0, + command: 'moveto', + code: 'M' + }, + { + x: node.width, + y: 0, + command: 'lineto', + code: 'L' + } + ]); }; diff --git a/plugin-src/transformers/transformPathNode.ts b/plugin-src/transformers/transformPathNode.ts index 7ac32a3..40c0d87 100644 --- a/plugin-src/transformers/transformPathNode.ts +++ b/plugin-src/transformers/transformPathNode.ts @@ -17,14 +17,11 @@ import { translateCommands } from '@plugin/translators/vectors'; import { PathShape, Segment } from '@ui/lib/types/shapes/pathShape'; -export const transformPathNode = ( - node: StarNode | PolygonNode, - baseRotation: number -): PathShape => { +export const transformPathNode = (node: StarNode | PolygonNode): PathShape => { return { type: 'path', name: node.name, - content: translatePathNode(node, baseRotation), + content: translatePathNode(node), ...transformFigmaIds(node), ...transformFills(node), ...transformStrokes(node), @@ -32,12 +29,12 @@ export const transformPathNode = ( ...transformSceneNode(node), ...transformBlend(node), ...transformProportion(node), - ...transformRotation(node, baseRotation), + ...transformRotation(node), ...transformLayoutAttributes(node), ...transformConstraints(node), ...transformOverrides(node) }; }; -const translatePathNode = (node: StarNode | PolygonNode, baseRotation: number): Segment[] => - translateCommands(node, parseSVG(node.fillGeometry[0].data), baseRotation); +const translatePathNode = (node: StarNode | PolygonNode): Segment[] => + translateCommands(node, parseSVG(node.fillGeometry[0].data)); diff --git a/plugin-src/transformers/transformRectangleNode.ts b/plugin-src/transformers/transformRectangleNode.ts index 604a582..f27b1aa 100644 --- a/plugin-src/transformers/transformRectangleNode.ts +++ b/plugin-src/transformers/transformRectangleNode.ts @@ -16,7 +16,7 @@ import { import { RectShape } from '@ui/lib/types/shapes/rectShape'; -export const transformRectangleNode = (node: RectangleNode, baseRotation: number): RectShape => { +export const transformRectangleNode = (node: RectangleNode): RectShape => { return { type: 'rect', name: node.name, @@ -25,7 +25,7 @@ export const transformRectangleNode = (node: RectangleNode, baseRotation: number ...transformEffects(node), ...transformStrokes(node), ...transformDimension(node), - ...transformRotationAndPosition(node, baseRotation), + ...transformRotationAndPosition(node), ...transformSceneNode(node), ...transformBlend(node), ...transformProportion(node), diff --git a/plugin-src/transformers/transformSceneNode.ts b/plugin-src/transformers/transformSceneNode.ts index 31105c6..a4a7b90 100644 --- a/plugin-src/transformers/transformSceneNode.ts +++ b/plugin-src/transformers/transformSceneNode.ts @@ -14,10 +14,7 @@ import { transformVectorNode } from '.'; -export const transformSceneNode = async ( - node: SceneNode, - baseRotation: number = 0 -): Promise => { +export const transformSceneNode = async (node: SceneNode): Promise => { let penpotNode: PenpotNode | undefined; figma.ui.postMessage({ @@ -27,40 +24,40 @@ export const transformSceneNode = async ( switch (node.type) { case 'RECTANGLE': - penpotNode = transformRectangleNode(node, baseRotation); + penpotNode = transformRectangleNode(node); break; case 'ELLIPSE': - penpotNode = transformEllipseNode(node, baseRotation); + penpotNode = transformEllipseNode(node); break; case 'SECTION': case 'FRAME': case 'COMPONENT_SET': - penpotNode = await transformFrameNode(node, baseRotation); + penpotNode = await transformFrameNode(node); break; case 'GROUP': - penpotNode = await transformGroupNode(node, baseRotation); + penpotNode = await transformGroupNode(node); break; case 'TEXT': - penpotNode = transformTextNode(node, baseRotation); + penpotNode = transformTextNode(node); break; case 'VECTOR': - penpotNode = transformVectorNode(node, baseRotation); + penpotNode = transformVectorNode(node); break; case 'LINE': - penpotNode = transformLineNode(node, baseRotation); + penpotNode = transformLineNode(node); break; case 'STAR': case 'POLYGON': - penpotNode = transformPathNode(node, baseRotation); + penpotNode = transformPathNode(node); break; case 'BOOLEAN_OPERATION': - penpotNode = await transformBooleanNode(node, baseRotation); + penpotNode = await transformBooleanNode(node); break; case 'COMPONENT': - penpotNode = await transformComponentNode(node, baseRotation); + penpotNode = await transformComponentNode(node); break; case 'INSTANCE': - penpotNode = await transformInstanceNode(node, baseRotation); + penpotNode = await transformInstanceNode(node); break; } diff --git a/plugin-src/transformers/transformTextNode.ts b/plugin-src/transformers/transformTextNode.ts index 727992b..cf52672 100644 --- a/plugin-src/transformers/transformTextNode.ts +++ b/plugin-src/transformers/transformTextNode.ts @@ -15,14 +15,14 @@ import { import { TextShape } from '@ui/lib/types/shapes/textShape'; -export const transformTextNode = (node: TextNode, baseRotation: number): TextShape => { +export const transformTextNode = (node: TextNode): TextShape => { return { type: 'text', name: node.name, ...transformFigmaIds(node), ...transformText(node), ...transformDimension(node), - ...transformRotationAndPosition(node, baseRotation), + ...transformRotationAndPosition(node), ...transformEffects(node), ...transformSceneNode(node), ...transformBlend(node), diff --git a/plugin-src/transformers/transformVectorNode.ts b/plugin-src/transformers/transformVectorNode.ts index 586253d..74c7ae7 100644 --- a/plugin-src/transformers/transformVectorNode.ts +++ b/plugin-src/transformers/transformVectorNode.ts @@ -16,11 +16,8 @@ import { transformGroupNodeLike } from '.'; * If there are no regions on the vector network, we treat it like a normal `PathShape`. * If there are regions, we treat the vector node as a `GroupShape` with multiple `PathShape` children. */ -export const transformVectorNode = ( - node: VectorNode, - baseRotation: number -): GroupShape | PathShape => { - const children = transformVectorPaths(node, baseRotation); +export const transformVectorNode = (node: VectorNode): GroupShape | PathShape => { + const children = transformVectorPaths(node); if (children.length === 1) { return { @@ -33,7 +30,7 @@ export const transformVectorNode = ( } return { - ...transformGroupNodeLike(node, baseRotation), + ...transformGroupNodeLike(node), ...transformFigmaIds(node), ...transformConstraints(node), ...transformOverrides(node), diff --git a/plugin-src/translators/translateChildren.ts b/plugin-src/translators/translateChildren.ts index 529f222..43e103c 100644 --- a/plugin-src/translators/translateChildren.ts +++ b/plugin-src/translators/translateChildren.ts @@ -16,13 +16,12 @@ import { PenpotNode } from '@ui/types'; */ export const translateMaskChildren = async ( children: readonly SceneNode[], - maskIndex: number, - baseRotation: number + maskIndex: number ): Promise => { const maskChild = children[maskIndex]; - const unmaskedChildren = await translateChildren(children.slice(0, maskIndex), baseRotation); - const maskedChildren = await translateChildren(children.slice(maskIndex), baseRotation); + const unmaskedChildren = await translateChildren(children.slice(0, maskIndex)); + const maskedChildren = await translateChildren(children.slice(maskIndex)); if ( maskChild.type === 'STICKY' || @@ -41,7 +40,7 @@ export const translateMaskChildren = async ( const maskGroup = { ...transformMaskFigmaIds(maskChild), - ...transformGroupNodeLike(maskChild, baseRotation), + ...transformGroupNodeLike(maskChild), children: maskedChildren, maskedGroup: true }; @@ -49,14 +48,11 @@ export const translateMaskChildren = async ( return [...unmaskedChildren, maskGroup]; }; -export const translateChildren = async ( - children: readonly SceneNode[], - baseRotation: number = 0 -): Promise => { +export const translateChildren = async (children: readonly SceneNode[]): Promise => { const transformedChildren: PenpotNode[] = []; for (const child of children) { - const penpotNode = await transformSceneNode(child, baseRotation); + const penpotNode = await transformSceneNode(child); if (penpotNode) transformedChildren.push(penpotNode); diff --git a/plugin-src/translators/translateRotation.ts b/plugin-src/translators/translateRotation.ts index d8979bd..fa3af7d 100644 --- a/plugin-src/translators/translateRotation.ts +++ b/plugin-src/translators/translateRotation.ts @@ -3,25 +3,27 @@ import { ShapeBaseAttributes } from '@ui/lib/types/shapes/shape'; export const translateRotation = ( transform: Transform, rotation: number -): Pick => ({ - rotation: -rotation < 0 ? -rotation + 360 : -rotation, - transform: { - a: transform[0][0], - b: transform[1][0], - c: transform[0][1], - d: transform[1][1], - e: 0, - f: 0 - }, - transformInverse: { - a: transform[0][0], - b: transform[0][1], - c: transform[1][0], - d: transform[1][1], - e: 0, - f: 0 - } -}); +): Pick => { + return { + rotation, + transform: { + a: transform[0][0], + b: transform[1][0], + c: transform[0][1], + d: transform[1][1], + e: 0, + f: 0 + }, + transformInverse: { + a: transform[0][0], + b: transform[0][1], + c: transform[1][0], + d: transform[1][1], + e: 0, + f: 0 + } + }; +}; export const translateZeroRotation = (): Pick< ShapeBaseAttributes, diff --git a/plugin-src/translators/vectors/translateCommands.ts b/plugin-src/translators/vectors/translateCommands.ts index 3df1cce..dbb696e 100644 --- a/plugin-src/translators/vectors/translateCommands.ts +++ b/plugin-src/translators/vectors/translateCommands.ts @@ -1,12 +1,14 @@ import { Command } from 'svg-path-parser'; -import { hasRotation } from '@plugin/utils'; +import { getRotation, hasRotation } from '@plugin/utils'; import { translateNonRotatedCommands } from '.'; import { translateRotatedCommands } from './translateRotatedCommands'; -export const translateCommands = (node: LayoutMixin, commands: Command[], baseRotation: number) => { - if (hasRotation(node.rotation + baseRotation) && node.absoluteBoundingBox) { +export const translateCommands = (node: LayoutMixin, commands: Command[]) => { + const rotation = getRotation(node.absoluteTransform); + + if (hasRotation(rotation) && node.absoluteBoundingBox) { return translateRotatedCommands(commands, node.absoluteTransform, node.absoluteBoundingBox); } diff --git a/plugin-src/utils/applyRotation.ts b/plugin-src/utils/applyRotation.ts index 7f5c234..79748c7 100644 --- a/plugin-src/utils/applyRotation.ts +++ b/plugin-src/utils/applyRotation.ts @@ -58,7 +58,10 @@ export const applyInverseRotation = ( boundingBox: Rect ): Point => applyRotation(point, inverseMatrix(transform), boundingBox); -export const hasRotation = (rotation: number): boolean => Math.abs(rotation) > ROTATION_TOLERANCE; +export const getRotation = (transform: Transform): number => + Math.acos(transform[0][0]) * (180 / Math.PI); + +export const hasRotation = (rotation: number): boolean => rotation > ROTATION_TOLERANCE; const inverseMatrix = (matrix: Transform): Transform => [ [matrix[0][0], matrix[1][0], matrix[0][2]],