Skip to content

Commit

Permalink
Boolean Groups (#115)
Browse files Browse the repository at this point in the history
* wip

* wip

* fixes

* changeset

* fixes

* fixes

* fixes

* fixes

* minor fixes

* minor fixes
  • Loading branch information
Cenadros authored May 27, 2024
1 parent aafb9cf commit 36afc6d
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/dry-pumas-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"penpot-exporter": minor
---

Added support for boolean groups
1 change: 1 addition & 0 deletions plugin-src/transformers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './transformBooleanNode';
export * from './transformDocumentNode';
export * from './transformEllipseNode';
export * from './transformFrameNode';
Expand Down
33 changes: 33 additions & 0 deletions plugin-src/transformers/transformBooleanNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
transformBlend,
transformChildren,
transformDimensionAndPosition,
transformEffects,
transformFills,
transformProportion,
transformSceneNode,
transformStrokes
} from '@plugin/transformers/partials';
import { translateBoolType } from '@plugin/translators';

import { BoolShape } from '@ui/lib/types/shapes/boolShape';

export const transformBooleanNode = async (
node: BooleanOperationNode,
baseX: number,
baseY: number
): Promise<BoolShape> => {
return {
type: 'bool',
name: node.name,
boolType: translateBoolType(node.booleanOperation),
...(await transformChildren(node, baseX, baseY)),
...(await transformFills(node)),
...transformEffects(node),
...(await transformStrokes(node)),
...transformDimensionAndPosition(node, baseX, baseY),
...transformSceneNode(node),
...transformBlend(node),
...transformProportion(node)
};
};
3 changes: 3 additions & 0 deletions plugin-src/transformers/transformSceneNode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PenpotNode } from '@ui/lib/types/penpotNode';

import {
transformBooleanNode,
transformEllipseNode,
transformFrameNode,
transformGroupNode,
Expand Down Expand Up @@ -33,6 +34,8 @@ export const transformSceneNode = async (
case 'POLYGON':
case 'LINE':
return await transformPathNode(node, baseX, baseY);
case 'BOOLEAN_OPERATION':
return await transformBooleanNode(node, baseX, baseY);
}

console.error(`Unsupported node type: ${node.type}`);
Expand Down
1 change: 1 addition & 0 deletions plugin-src/translators/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './translateBlendMode';
export * from './translateBlurEffects';
export * from './translateBoolType';
export * from './translateShadowEffects';
export * from './translateStrokes';
15 changes: 15 additions & 0 deletions plugin-src/translators/translateBoolType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BoolOperations } from '@ui/lib/types/shapes/boolShape';

type BooleanOperation = 'UNION' | 'INTERSECT' | 'SUBTRACT' | 'EXCLUDE';
export const translateBoolType = (booleanOperation: BooleanOperation): BoolOperations => {
switch (booleanOperation) {
case 'EXCLUDE':
return 'exclude';
case 'INTERSECT':
return 'intersection';
case 'SUBTRACT':
return 'difference';
case 'UNION':
return 'union';
}
};
22 changes: 22 additions & 0 deletions ui-src/converters/createPenpotBool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { createPenpotItem } from '@ui/converters/createPenpotItem';
import { PenpotFile } from '@ui/lib/types/penpotFile';
import { BoolShape } from '@ui/lib/types/shapes/boolShape';
import { translateFillGradients, translateUiBlendMode, translateUiBoolType } from '@ui/translators';

export const createPenpotBool = (
file: PenpotFile,
{ type, fills, boolType, blendMode, children = [], ...rest }: BoolShape
) => {
file.addBool({
fills: translateFillGradients(fills),
blendMode: translateUiBlendMode(blendMode),
boolType: translateUiBoolType(boolType),
...rest
});

for (const child of children) {
createPenpotItem(file, child);
}

file.closeBool();
};
3 changes: 3 additions & 0 deletions ui-src/converters/createPenpotItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PenpotNode } from '@ui/lib/types/penpotNode';

import {
createPenpotArtboard,
createPenpotBool,
createPenpotCircle,
createPenpotGroup,
createPenpotPath,
Expand All @@ -24,5 +25,7 @@ export const createPenpotItem = (file: PenpotFile, node: PenpotNode) => {
return createPenpotPath(file, node);
case 'text':
return createPenpotText(file, node);
case 'bool':
return createPenpotBool(file, node);
}
};
1 change: 1 addition & 0 deletions ui-src/converters/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './createPenpotArtboard';
export * from './createPenpotBool';
export * from './createPenpotCircle';
export * from './createPenpotFile';
export * from './createPenpotGroup';
Expand Down
2 changes: 1 addition & 1 deletion ui-src/lib/types/penpotFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ export interface PenpotFile {
// lookupShape(shapeId: string): void;
// updateObject(id: string, object: any): void;
// deleteObject(id: string): void;
asMap(): unknown;
// asMap(): unknown;
export(): void;
}
10 changes: 9 additions & 1 deletion ui-src/lib/types/penpotNode.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { BoolShape } from '@ui/lib/types/shapes/boolShape';
import { CircleShape } from '@ui/lib/types/shapes/circleShape';
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';

export type PenpotNode = FrameShape | GroupShape | PathShape | RectShape | CircleShape | TextShape;
export type PenpotNode =
| FrameShape
| GroupShape
| PathShape
| RectShape
| CircleShape
| TextShape
| BoolShape;
28 changes: 22 additions & 6 deletions ui-src/lib/types/shapes/boolShape.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
import { LayoutChildAttributes } from '@ui/lib/types/shapes/layout';
import { PathContent } from '@ui/lib/types/shapes/pathShape';
import { ShapeAttributes, ShapeBaseAttributes } from '@ui/lib/types/shapes/shape';
import { Children } from '@ui/lib/types/utils/children';
import { Point } from '@ui/lib/types/utils/point';
import { Uuid } from '@ui/lib/types/utils/uuid';

export const BOOL_DIFFERENCE: unique symbol = Symbol.for('difference');
export const BOOL_UNION: unique symbol = Symbol.for('union');
export const BOOL_INTERSECTION: unique symbol = Symbol.for('intersection');
export const BOOL_EXCLUDE: unique symbol = Symbol.for('exclude');

export type BoolOperations =
| 'difference'
| 'union'
| 'intersection'
| 'exclude'
| typeof BOOL_DIFFERENCE
| typeof BOOL_UNION
| typeof BOOL_INTERSECTION
| typeof BOOL_EXCLUDE;

export type BoolShape = ShapeBaseAttributes &
ShapeAttributes &
BoolAttributes &
LayoutChildAttributes;
LayoutChildAttributes &
Children;

type BoolAttributes = {
type?: 'bool';
shapes?: Uuid[];
boolType: string; // @TODO: in Penpot this is of type :keyword. check if it makes sense
boolContent: BoolContent[];
boolType: BoolOperations;
boolContent?: BoolContent[];
};

type BoolContent = {
command: string; // @TODO: in Penpot this is of type :keyword. check if it makes sense
relative?: boolean;
prevPos?: Point;
params?: { [keyword: string]: number }; // @TODO: in Penpot this is of type :keyword. check if it makes sense
};
} & PathContent;
1 change: 1 addition & 0 deletions ui-src/translators/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './translateFillGradients';
export * from './translatePathContent';
export * from './translateUiBlendMode';
export * from './translateUiBoolType';
22 changes: 22 additions & 0 deletions ui-src/translators/translateUiBoolType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {
BOOL_DIFFERENCE,
BOOL_EXCLUDE,
BOOL_INTERSECTION,
BOOL_UNION,
BoolOperations
} from '@ui/lib/types/shapes/boolShape';

export const translateUiBoolType = (booleanOperation: BoolOperations): BoolOperations => {
switch (booleanOperation) {
case 'union':
return BOOL_UNION;
case 'exclude':
return BOOL_EXCLUDE;
case 'difference':
return BOOL_DIFFERENCE;
case 'intersection':
return BOOL_INTERSECTION;
}

throw new Error(`Unsupported boolean operation: ${String(booleanOperation)}`);
};

0 comments on commit 36afc6d

Please sign in to comment.