Skip to content

Commit

Permalink
Solid Fills (#39)
Browse files Browse the repository at this point in the history
* structure for fills

* structure for fills in text and improvements

* fixes

* improvements
  • Loading branch information
Cenadros authored Apr 17, 2024
1 parent ebdf3ad commit e2b5b4a
Show file tree
Hide file tree
Showing 15 changed files with 145 additions and 111 deletions.
2 changes: 2 additions & 0 deletions plugin-src/transformers/partials/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export * from './transformBlend';
export * from './transformChildren';
export * from './transformDimensionAndPosition';
export * from './transformFills';
export * from './transformSceneNode';
export * from './transformStrokes';
export * from './transformTextStyle';
export * from './transformVectorPaths';
11 changes: 11 additions & 0 deletions plugin-src/transformers/partials/transformFills.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { translateFills } from '@plugin/translators';

import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes';

export const transformFills = (
node: MinimalFillsMixin & DimensionAndPositionMixin
): Partial<ShapeAttributes> => {
return {
fills: translateFills(node.fills, node.width, node.height)
};
};
29 changes: 29 additions & 0 deletions plugin-src/transformers/partials/transformTextStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { translateTextDecoration, translateTextTransform } from '@plugin/translators';

import { TextStyle } from '@ui/lib/types/text/textContent';

export const transformTextStyle = (
node: Pick<
StyledTextSegment,
| 'characters'
| 'start'
| 'end'
| 'fontName'
| 'fontSize'
| 'fontWeight'
| 'lineHeight'
| 'letterSpacing'
| 'textCase'
| 'textDecoration'
| 'fills'
>
): Partial<TextStyle> => {
return {
fontFamily: node.fontName.family,
fontSize: node.fontSize.toString(),
fontStyle: node.fontName.style,
fontWeight: node.fontWeight.toString(),
textDecoration: translateTextDecoration(node),
textTransform: translateTextTransform(node)
};
};
4 changes: 2 additions & 2 deletions plugin-src/transformers/transformEllipseNode.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
transformBlend,
transformDimensionAndPosition,
transformFills,
transformSceneNode,
transformStrokes
} from '@plugin/transformers/partials';
import { translateFills } from '@plugin/translators';

import { CircleShape } from '@ui/lib/types/circle/circleShape';

Expand All @@ -16,7 +16,7 @@ export const transformEllipseNode = (
return {
type: 'circle',
name: node.name,
fills: translateFills(node.fills, node.width, node.height),
...transformFills(node),
...transformStrokes(node),
...transformDimensionAndPosition(node, baseX, baseY),
...transformSceneNode(node),
Expand Down
6 changes: 3 additions & 3 deletions plugin-src/transformers/transformFrameNode.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {
transformBlend,
transformChildren,
transformDimensionAndPosition,
transformFills,
transformSceneNode,
transformStrokes
} from '@plugin/transformers/partials';
import { transformChildren } from '@plugin/transformers/partials';
import { translateFills } from '@plugin/translators';

import { FrameShape } from '@ui/lib/types/frame/frameShape';

Expand All @@ -21,7 +21,7 @@ export const transformFrameNode = async (
return {
type: 'frame',
name: node.name,
fills: translateFills(node.fills, node.width, node.height),
...transformFills(node),
// Figma API does not expose strokes for sections,
// they plan to add it in the future. Refactor this when available.
// @see: https://forum.figma.com/t/why-are-strokes-not-available-on-section-nodes/41658
Expand Down
8 changes: 6 additions & 2 deletions plugin-src/transformers/transformPathNode.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import {
transformBlend,
transformDimensionAndPosition,
transformFills,
transformSceneNode,
transformStrokes,
transformVectorPaths
} from '@plugin/transformers/partials';
import { translateFills } from '@plugin/translators';

import { PathShape } from '@ui/lib/types/path/pathShape';

const hasFillGeometry = (node: VectorNode | StarNode | LineNode | PolygonNode): boolean => {
return 'fillGeometry' in node && node.fillGeometry.length > 0;
};

export const transformPathNode = (
node: VectorNode | StarNode | LineNode | PolygonNode,
baseX: number,
baseY: number
): PathShape => {
return {
name: node.name,
fills: node.fillGeometry.length ? translateFills(node.fills, node.width, node.height) : [],
...(hasFillGeometry(node) ? transformFills(node) : []),
...transformStrokes(node),
...transformVectorPaths(node, baseX, baseY),
...transformDimensionAndPosition(node, baseX, baseY),
Expand Down
4 changes: 2 additions & 2 deletions plugin-src/transformers/transformRectangleNode.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
transformBlend,
transformDimensionAndPosition,
transformFills,
transformSceneNode,
transformStrokes
} from '@plugin/transformers/partials';
import { translateFills } from '@plugin/translators';

import { RectShape } from '@ui/lib/types/rect/rectShape';

Expand All @@ -16,7 +16,7 @@ export const transformRectangleNode = (
return {
type: 'rect',
name: node.name,
fills: translateFills(node.fills, node.width, node.height),
...transformFills(node),
...transformStrokes(node),
...transformDimensionAndPosition(node, baseX, baseY),
...transformSceneNode(node),
Expand Down
37 changes: 7 additions & 30 deletions plugin-src/transformers/transformTextNode.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import {
transformBlend,
transformDimensionAndPosition,
transformSceneNode
transformFills,
transformSceneNode,
transformTextStyle
} from '@plugin/transformers/partials';
import {
translateFills,
translateTextDecoration,
translateTextTransform
} from '@plugin/translators';
import { translateStyledTextSegments } from '@plugin/translators';

import { TextNode as PenpotTextNode } from '@ui/lib/types/text/textContent';
import { TextShape } from '@ui/lib/types/text/textShape';

export const transformTextNode = (node: TextNode, baseX: number, baseY: number): TextShape => {
Expand All @@ -24,21 +21,6 @@ export const transformTextNode = (node: TextNode, baseX: number, baseY: number):
'fills'
]);

const children: PenpotTextNode[] = styledTextSegments.map(segment => {
figma.ui.postMessage({ type: 'FONT_NAME', data: segment.fontName.family });

return {
text: segment.characters,
fills: translateFills(segment.fills, node.width, node.height),
fontFamily: segment.fontName.family,
fontSize: segment.fontSize.toString(),
fontStyle: segment.fontName.style,
fontWeight: segment.fontWeight.toString(),
textDecoration: translateTextDecoration(segment),
textTransform: translateTextTransform(segment)
};
});

return {
type: 'text',
name: node.name,
Expand All @@ -50,14 +32,9 @@ export const transformTextNode = (node: TextNode, baseX: number, baseY: number):
children: [
{
type: 'paragraph',
fills: translateFills(node.fills, node.width, node.height),
fontFamily: children[0].fontFamily,
fontSize: children[0].fontSize,
fontStyle: children[0].fontStyle,
fontWeight: children[0].fontWeight,
textDecoration: children[0].textDecoration,
textTransform: children[0].textTransform,
children: children
children: translateStyledTextSegments(styledTextSegments, node.width, node.height),
...(styledTextSegments.length ? transformTextStyle(styledTextSegments[0]) : {}),
...transformFills(node)
}
]
}
Expand Down
3 changes: 1 addition & 2 deletions plugin-src/translators/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
export * from './translateBlendMode';
export * from './translateFills';
export * from './translateGradientLinearFill';
export * from './translateSolidFill';
export * from './translateStrokes';
export * from './translateStyledTextSegments';
export * from './translateTextDecoration';
export * from './translateTextTransform';
export * from './translateVectorPaths';
52 changes: 42 additions & 10 deletions plugin-src/translators/translateFills.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Fill } from '@ui/lib/types/utils/fill';
import { rgbToHex } from '@plugin/utils';
import { calculateLinearGradient } from '@plugin/utils/calculateLinearGradient';

import { translateGradientLinearFill } from './translateGradientLinearFill';
import { translateSolidFill } from './translateSolidFill';
import { Fill } from '@ui/lib/types/utils/fill';

export const translateFill = (fill: Paint, width: number, height: number): Fill | undefined => {
switch (fill.type) {
Expand All @@ -19,19 +19,51 @@ export const translateFills = (
width: number,
height: number
): Fill[] => {
// @TODO: think better variable name
// @TODO: make it work with figma.mixed
const fills2 = fills === figma.mixed ? [] : fills;

const penpotFills = [];
const figmaFills = fills === figma.mixed ? [] : fills;
const penpotFills: Fill[] = [];

for (const fill of fills2) {
for (const fill of figmaFills) {
const penpotFill = translateFill(fill, width, height);

if (penpotFill) {
// colors are applied in reverse order in Figma, that's why we unshift
penpotFills.unshift(penpotFill);
}
}

return penpotFills;
};

const translateSolidFill = (fill: SolidPaint): Fill => {
return {
fillColor: rgbToHex(fill.color),
fillOpacity: !fill.visible ? 0 : fill.opacity
};
};

const translateGradientLinearFill = (fill: GradientPaint, width: number, height: number): Fill => {
const points = calculateLinearGradient(width, height, fill.gradientTransform);

return {
fillColorGradient: {
type: 'linear',
startX: points.start[0] / width,
startY: points.start[1] / height,
endX: points.end[0] / width,
endY: points.end[1] / height,
width: 1,
stops: [
{
color: rgbToHex(fill.gradientStops[0].color),
offset: fill.gradientStops[0].position,
opacity: fill.gradientStops[0].color.a * (fill.opacity ?? 1)
},
{
color: rgbToHex(fill.gradientStops[1].color),
offset: fill.gradientStops[1].position,
opacity: fill.gradientStops[1].color.a * (fill.opacity ?? 1)
}
]
},
fillOpacity: fill.visible === false ? 0 : undefined
};
};
36 changes: 0 additions & 36 deletions plugin-src/translators/translateGradientLinearFill.ts

This file was deleted.

10 changes: 0 additions & 10 deletions plugin-src/translators/translateSolidFill.ts

This file was deleted.

33 changes: 33 additions & 0 deletions plugin-src/translators/translateStyledTextSegments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { transformTextStyle } from '@plugin/transformers/partials';
import { translateFills } from '@plugin/translators/translateFills';

import { TextNode } from '@ui/lib/types/text/textContent';

export const translateStyledTextSegments = (
segments: Pick<
StyledTextSegment,
| 'characters'
| 'start'
| 'end'
| 'fontName'
| 'fontSize'
| 'fontWeight'
| 'lineHeight'
| 'letterSpacing'
| 'textCase'
| 'textDecoration'
| 'fills'
>[],
width: number,
height: number
): TextNode[] => {
return segments.map(segment => {
figma.ui.postMessage({ type: 'FONT_NAME', data: segment.fontName.family });

return {
fills: translateFills(segment.fills, width, height),
text: segment.characters,
...transformTextStyle(segment)
};
});
};
2 changes: 1 addition & 1 deletion ui-src/lib/types/frame/frameAttributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ export type FrameAttributes = {
hideFillOnExport?: boolean;
showContent?: boolean;
hideInViewer?: boolean;
fills: Fill[];
fills?: Fill[];
};
Loading

0 comments on commit e2b5b4a

Please sign in to comment.