From 3118d36f0aad701e6f09f90744bbcce0a51d5a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20S=C3=A1nchez?= Date: Mon, 13 May 2024 17:04:13 +0200 Subject: [PATCH] Fills Refactor (#109) * refactor * changeset * fixes --- .../transformers/partials/transformFills.ts | 2 +- .../partials/transformVectorPaths.ts | 2 +- plugin-src/transformers/transformPageNode.ts | 2 +- .../translators/fills/gradients/index.ts | 2 + .../gradients/translateGradientLinearFill.ts | 24 ++++ .../gradients/translateGradientRadialFill.ts | 24 ++++ plugin-src/translators/fills/index.ts | 3 + .../translators/fills/translateFills.ts | 49 +++++++ .../translators/fills/translateImageFill.ts | 36 +++++ .../translators/fills/translateSolidFill.ts | 10 ++ plugin-src/translators/index.ts | 1 - .../text/translateStyleTextSegments.ts | 2 +- plugin-src/translators/translateFills.ts | 127 ------------------ plugin-src/translators/translateStrokes.ts | 2 +- 14 files changed, 153 insertions(+), 133 deletions(-) create mode 100644 plugin-src/translators/fills/gradients/index.ts create mode 100644 plugin-src/translators/fills/gradients/translateGradientLinearFill.ts create mode 100644 plugin-src/translators/fills/gradients/translateGradientRadialFill.ts create mode 100644 plugin-src/translators/fills/index.ts create mode 100644 plugin-src/translators/fills/translateFills.ts create mode 100644 plugin-src/translators/fills/translateImageFill.ts create mode 100644 plugin-src/translators/fills/translateSolidFill.ts delete mode 100644 plugin-src/translators/translateFills.ts diff --git a/plugin-src/transformers/partials/transformFills.ts b/plugin-src/transformers/partials/transformFills.ts index 5d11687..67e2b2e 100644 --- a/plugin-src/transformers/partials/transformFills.ts +++ b/plugin-src/transformers/partials/transformFills.ts @@ -1,4 +1,4 @@ -import { translateFills } from '@plugin/translators'; +import { translateFills } from '@plugin/translators/fills'; import { ShapeAttributes } from '@ui/lib/types/shapes/shape'; diff --git a/plugin-src/transformers/partials/transformVectorPaths.ts b/plugin-src/transformers/partials/transformVectorPaths.ts index 6d8755f..1b9ffdb 100644 --- a/plugin-src/transformers/partials/transformVectorPaths.ts +++ b/plugin-src/transformers/partials/transformVectorPaths.ts @@ -7,7 +7,7 @@ import { transformStrokes } from '@plugin/transformers/partials'; import { createLineGeometry, translateVectorPath, translateVectorPaths } from '@plugin/translators'; -import { translateFills } from '@plugin/translators'; +import { translateFills } from '@plugin/translators/fills'; import { PathAttributes } from '@ui/lib/types/shapes/pathShape'; import { PathShape } from '@ui/lib/types/shapes/pathShape'; diff --git a/plugin-src/transformers/transformPageNode.ts b/plugin-src/transformers/transformPageNode.ts index 756ba59..5ed6ffd 100644 --- a/plugin-src/transformers/transformPageNode.ts +++ b/plugin-src/transformers/transformPageNode.ts @@ -1,5 +1,5 @@ import { transformChildren } from '@plugin/transformers/partials'; -import { translatePageFill } from '@plugin/translators'; +import { translatePageFill } from '@plugin/translators/fills'; import { PenpotPage } from '@ui/lib/types/penpotPage'; diff --git a/plugin-src/translators/fills/gradients/index.ts b/plugin-src/translators/fills/gradients/index.ts new file mode 100644 index 0000000..e6a6f2b --- /dev/null +++ b/plugin-src/translators/fills/gradients/index.ts @@ -0,0 +1,2 @@ +export * from './translateGradientLinearFill'; +export * from './translateGradientRadialFill'; diff --git a/plugin-src/translators/fills/gradients/translateGradientLinearFill.ts b/plugin-src/translators/fills/gradients/translateGradientLinearFill.ts new file mode 100644 index 0000000..eefd680 --- /dev/null +++ b/plugin-src/translators/fills/gradients/translateGradientLinearFill.ts @@ -0,0 +1,24 @@ +import { calculateLinearGradient, rgbToHex } from '@plugin/utils'; + +import { Fill } from '@ui/lib/types/utils/fill'; + +export const translateGradientLinearFill = (fill: GradientPaint): Fill => { + const points = calculateLinearGradient(fill.gradientTransform); + + return { + fillColorGradient: { + type: 'linear', + startX: points.start[0], + startY: points.start[1], + endX: points.end[0], + endY: points.end[1], + width: 1, + stops: fill.gradientStops.map(stop => ({ + color: rgbToHex(stop.color), + offset: stop.position, + opacity: stop.color.a * (fill.opacity ?? 1) + })) + }, + fillOpacity: !fill.visible ? 0 : fill.opacity + }; +}; diff --git a/plugin-src/translators/fills/gradients/translateGradientRadialFill.ts b/plugin-src/translators/fills/gradients/translateGradientRadialFill.ts new file mode 100644 index 0000000..2b4daaf --- /dev/null +++ b/plugin-src/translators/fills/gradients/translateGradientRadialFill.ts @@ -0,0 +1,24 @@ +import { calculateRadialGradient, rgbToHex } from '@plugin/utils'; + +import { Fill } from '@ui/lib/types/utils/fill'; + +export const translateGradientRadialFill = (fill: GradientPaint): Fill => { + const points = calculateRadialGradient(fill.gradientTransform); + + return { + fillColorGradient: { + type: 'radial', + startX: points.start[0], + startY: points.start[1], + endX: points.end[0], + endY: points.end[1], + width: 1, + stops: fill.gradientStops.map(stop => ({ + color: rgbToHex(stop.color), + offset: stop.position, + opacity: stop.color.a * (fill.opacity ?? 1) + })) + }, + fillOpacity: !fill.visible ? 0 : fill.opacity + }; +}; diff --git a/plugin-src/translators/fills/index.ts b/plugin-src/translators/fills/index.ts new file mode 100644 index 0000000..9db276d --- /dev/null +++ b/plugin-src/translators/fills/index.ts @@ -0,0 +1,3 @@ +export * from './translateFills'; +export * from './translateImageFill'; +export * from './translateSolidFill'; diff --git a/plugin-src/translators/fills/translateFills.ts b/plugin-src/translators/fills/translateFills.ts new file mode 100644 index 0000000..2c83c30 --- /dev/null +++ b/plugin-src/translators/fills/translateFills.ts @@ -0,0 +1,49 @@ +import { translateImageFill, translateSolidFill } from '@plugin/translators/fills'; +import { + translateGradientLinearFill, + translateGradientRadialFill +} from '@plugin/translators/fills/gradients'; +import { rgbToHex } from '@plugin/utils'; + +import { Fill } from '@ui/lib/types/utils/fill'; + +export const translateFill = async (fill: Paint): Promise => { + switch (fill.type) { + case 'SOLID': + return translateSolidFill(fill); + case 'GRADIENT_LINEAR': + return translateGradientLinearFill(fill); + case 'GRADIENT_RADIAL': + return translateGradientRadialFill(fill); + case 'IMAGE': + return await translateImageFill(fill); + } + + console.error(`Unsupported fill type: ${fill.type}`); +}; + +export const translateFills = async ( + fills: readonly Paint[] | typeof figma.mixed +): Promise => { + const figmaFills = fills === figma.mixed ? [] : fills; + const penpotFills: Fill[] = []; + + for (const fill of figmaFills) { + const penpotFill = await translateFill(fill); + if (penpotFill) { + // fills are applied in reverse order in Figma, that's why we unshift + penpotFills.unshift(penpotFill); + } + } + + return penpotFills; +}; + +export const translatePageFill = (fill: Paint): string | undefined => { + switch (fill.type) { + case 'SOLID': + return rgbToHex(fill.color); + } + + console.error(`Unsupported page fill type: ${fill.type}`); +}; diff --git a/plugin-src/translators/fills/translateImageFill.ts b/plugin-src/translators/fills/translateImageFill.ts new file mode 100644 index 0000000..14dab59 --- /dev/null +++ b/plugin-src/translators/fills/translateImageFill.ts @@ -0,0 +1,36 @@ +import { detectMimeType } from '@plugin/utils'; + +import { Fill } from '@ui/lib/types/utils/fill'; +import { ImageColor } from '@ui/lib/types/utils/imageColor'; + +export const translateImageFill = async (fill: ImagePaint): Promise => { + const fillImage = await translateImage(fill.imageHash); + if (!fillImage) return; + + return { + fillOpacity: !fill.visible ? 0 : fill.opacity, + fillImage: fillImage + }; +}; + +const translateImage = async (imageHash: string | null): Promise => { + if (!imageHash) return; + + const image = figma.getImageByHash(imageHash); + if (!image) return; + + const bytes = await image.getBytesAsync(); + const size = await image.getSizeAsync(); + const b64 = figma.base64Encode(bytes); + const mimeType = detectMimeType(b64); + const dataUri = `data:${mimeType};base64,${b64}`; + + return { + width: size.width, + height: size.height, + mtype: mimeType, + keepAspectRatio: true, + dataUri: dataUri, + id: '00000000-0000-0000-0000-000000000000' + }; +}; diff --git a/plugin-src/translators/fills/translateSolidFill.ts b/plugin-src/translators/fills/translateSolidFill.ts new file mode 100644 index 0000000..d6bfeae --- /dev/null +++ b/plugin-src/translators/fills/translateSolidFill.ts @@ -0,0 +1,10 @@ +import { rgbToHex } from '@plugin/utils'; + +import { Fill } from '@ui/lib/types/utils/fill'; + +export const translateSolidFill = (fill: SolidPaint): Fill => { + return { + fillColor: rgbToHex(fill.color), + fillOpacity: !fill.visible ? 0 : fill.opacity + }; +}; diff --git a/plugin-src/translators/index.ts b/plugin-src/translators/index.ts index 7ca0ebd..33b681e 100644 --- a/plugin-src/translators/index.ts +++ b/plugin-src/translators/index.ts @@ -1,6 +1,5 @@ export * from './translateBlendMode'; export * from './translateBlurEffects'; -export * from './translateFills'; export * from './translateShadowEffects'; export * from './translateStrokes'; export * from './translateVectorPaths'; diff --git a/plugin-src/translators/text/translateStyleTextSegments.ts b/plugin-src/translators/text/translateStyleTextSegments.ts index a426646..9a39a63 100644 --- a/plugin-src/translators/text/translateStyleTextSegments.ts +++ b/plugin-src/translators/text/translateStyleTextSegments.ts @@ -1,4 +1,4 @@ -import { translateFills } from '@plugin/translators'; +import { translateFills } from '@plugin/translators/fills'; import { translateFontId } from '@plugin/translators/text/font'; import { StyleTextSegment, translateParagraphProperties } from '@plugin/translators/text/paragraph'; import { diff --git a/plugin-src/translators/translateFills.ts b/plugin-src/translators/translateFills.ts deleted file mode 100644 index 74b1e1b..0000000 --- a/plugin-src/translators/translateFills.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { calculateRadialGradient, detectMimeType, rgbToHex } from '@plugin/utils'; -import { calculateLinearGradient } from '@plugin/utils/calculateLinearGradient'; - -import { Fill } from '@ui/lib/types/utils/fill'; -import { ImageColor } from '@ui/lib/types/utils/imageColor'; - -export const translateFill = async (fill: Paint): Promise => { - switch (fill.type) { - case 'SOLID': - return translateSolidFill(fill); - case 'GRADIENT_LINEAR': - return translateGradientLinearFill(fill); - case 'GRADIENT_RADIAL': - return translateGradientRadialFill(fill); - case 'IMAGE': - return await translateImageFill(fill); - } - - console.error(`Unsupported fill type: ${fill.type}`); -}; - -export const translateFills = async ( - fills: readonly Paint[] | typeof figma.mixed -): Promise => { - const figmaFills = fills === figma.mixed ? [] : fills; - const penpotFills: Fill[] = []; - - for (const fill of figmaFills) { - const penpotFill = await translateFill(fill); - if (penpotFill) { - // fills are applied in reverse order in Figma, that's why we unshift - penpotFills.unshift(penpotFill); - } - } - - return penpotFills; -}; - -export const translatePageFill = (fill: Paint): string | undefined => { - switch (fill.type) { - case 'SOLID': - return rgbToHex(fill.color); - } - - console.error(`Unsupported page fill type: ${fill.type}`); -}; - -const translateImage = async (imageHash: string | null): Promise => { - if (!imageHash) return; - - const image = figma.getImageByHash(imageHash); - if (!image) return; - - const bytes = await image.getBytesAsync(); - const size = await image.getSizeAsync(); - const b64 = figma.base64Encode(bytes); - const mimeType = detectMimeType(b64); - const dataUri = `data:${mimeType};base64,${b64}`; - - return { - width: size.width, - height: size.height, - mtype: mimeType, - keepAspectRatio: true, - dataUri: dataUri, - id: '00000000-0000-0000-0000-000000000000' - }; -}; - -const translateImageFill = async (fill: ImagePaint): Promise => { - const fillImage = await translateImage(fill.imageHash); - if (!fillImage) return; - - return { - fillOpacity: !fill.visible ? 0 : fill.opacity, - fillImage: fillImage - }; -}; - -const translateSolidFill = (fill: SolidPaint): Fill => { - return { - fillColor: rgbToHex(fill.color), - fillOpacity: !fill.visible ? 0 : fill.opacity - }; -}; - -const translateGradientLinearFill = (fill: GradientPaint): Fill => { - const points = calculateLinearGradient(fill.gradientTransform); - - return { - fillColorGradient: { - type: 'linear', - startX: points.start[0], - startY: points.start[1], - endX: points.end[0], - endY: points.end[1], - width: 1, - stops: fill.gradientStops.map(stop => ({ - color: rgbToHex(stop.color), - offset: stop.position, - opacity: stop.color.a * (fill.opacity ?? 1) - })) - }, - fillOpacity: !fill.visible ? 0 : fill.opacity - }; -}; - -const translateGradientRadialFill = (fill: GradientPaint): Fill => { - const points = calculateRadialGradient(fill.gradientTransform); - - return { - fillColorGradient: { - type: 'radial', - startX: points.start[0], - startY: points.start[1], - endX: points.end[0], - endY: points.end[1], - width: 1, - stops: fill.gradientStops.map(stop => ({ - color: rgbToHex(stop.color), - offset: stop.position, - opacity: stop.color.a * (fill.opacity ?? 1) - })) - }, - fillOpacity: !fill.visible ? 0 : fill.opacity - }; -}; diff --git a/plugin-src/translators/translateStrokes.ts b/plugin-src/translators/translateStrokes.ts index 4e52f52..de6bb2a 100644 --- a/plugin-src/translators/translateStrokes.ts +++ b/plugin-src/translators/translateStrokes.ts @@ -1,4 +1,4 @@ -import { translateFill } from '@plugin/translators/translateFills'; +import { translateFill } from '@plugin/translators/fills'; import { Stroke, StrokeAlignment, StrokeCaps } from '@ui/lib/types/utils/stroke';