mirror of
https://github.com/penpot/penpot-exporter-figma-plugin.git
synced 2024-12-22 13:43:03 -05:00
Add shadows to the export (#58)
This commit is contained in:
parent
c464ff9bda
commit
e732887399
13 changed files with 94 additions and 15 deletions
5
.changeset/flat-balloons-exercise.md
Normal file
5
.changeset/flat-balloons-exercise.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"penpot-exporter": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Shadows
|
|
@ -2,6 +2,7 @@ export * from './transformBlend';
|
||||||
export * from './transformChildren';
|
export * from './transformChildren';
|
||||||
export * from './transformCornerRadius';
|
export * from './transformCornerRadius';
|
||||||
export * from './transformDimensionAndPosition';
|
export * from './transformDimensionAndPosition';
|
||||||
|
export * from './transformEffects';
|
||||||
export * from './transformFills';
|
export * from './transformFills';
|
||||||
export * from './transformProportion';
|
export * from './transformProportion';
|
||||||
export * from './transformSceneNode';
|
export * from './transformSceneNode';
|
||||||
|
|
9
plugin-src/transformers/partials/transformEffects.ts
Normal file
9
plugin-src/transformers/partials/transformEffects.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { translateShadowEffects } from '@plugin/translators';
|
||||||
|
|
||||||
|
import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes';
|
||||||
|
|
||||||
|
export const transformEffects = (node: BlendMixin): Partial<ShapeAttributes> => {
|
||||||
|
return {
|
||||||
|
shadow: translateShadowEffects(node.effects)
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
transformBlend,
|
transformBlend,
|
||||||
transformDimensionAndPosition,
|
transformDimensionAndPosition,
|
||||||
|
transformEffects,
|
||||||
transformFills,
|
transformFills,
|
||||||
transformProportion,
|
transformProportion,
|
||||||
transformSceneNode,
|
transformSceneNode,
|
||||||
|
@ -18,6 +19,7 @@ export const transformEllipseNode = (
|
||||||
type: 'circle',
|
type: 'circle',
|
||||||
name: node.name,
|
name: node.name,
|
||||||
...transformFills(node),
|
...transformFills(node),
|
||||||
|
...transformEffects(node),
|
||||||
...transformStrokes(node),
|
...transformStrokes(node),
|
||||||
...transformDimensionAndPosition(node, baseX, baseY),
|
...transformDimensionAndPosition(node, baseX, baseY),
|
||||||
...transformSceneNode(node),
|
...transformSceneNode(node),
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
transformChildren,
|
transformChildren,
|
||||||
transformCornerRadius,
|
transformCornerRadius,
|
||||||
transformDimensionAndPosition,
|
transformDimensionAndPosition,
|
||||||
|
transformEffects,
|
||||||
transformFills,
|
transformFills,
|
||||||
transformProportion,
|
transformProportion,
|
||||||
transformSceneNode,
|
transformSceneNode,
|
||||||
|
@ -20,25 +21,30 @@ export const transformFrameNode = async (
|
||||||
baseX: number,
|
baseX: number,
|
||||||
baseY: number
|
baseY: number
|
||||||
): Promise<FrameShape> => {
|
): Promise<FrameShape> => {
|
||||||
|
let frameSpecificAttributes: Partial<FrameShape> = {};
|
||||||
|
|
||||||
|
if (!isSectionNode(node)) {
|
||||||
|
// 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.
|
||||||
|
frameSpecificAttributes = {
|
||||||
|
// @see: https://forum.figma.com/t/why-are-strokes-not-available-on-section-nodes/41658
|
||||||
|
...transformStrokes(node),
|
||||||
|
// @see: https://forum.figma.com/t/add-a-blendmode-property-for-sectionnode/58560
|
||||||
|
...transformBlend(node),
|
||||||
|
...transformProportion(node),
|
||||||
|
...transformCornerRadius(node),
|
||||||
|
...transformEffects(node)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'frame',
|
type: 'frame',
|
||||||
name: node.name,
|
name: node.name,
|
||||||
showContent: isSectionNode(node) ? true : !node.clipsContent,
|
showContent: isSectionNode(node) ? true : !node.clipsContent,
|
||||||
...transformFills(node),
|
...transformFills(node),
|
||||||
// Figma API does not expose strokes for sections,
|
...frameSpecificAttributes,
|
||||||
// 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
|
|
||||||
...(isSectionNode(node) ? [] : transformStrokes(node)),
|
|
||||||
...(await transformChildren(node, baseX + node.x, baseY + node.y)),
|
...(await transformChildren(node, baseX + node.x, baseY + node.y)),
|
||||||
...transformDimensionAndPosition(node, baseX, baseY),
|
...transformDimensionAndPosition(node, baseX, baseY),
|
||||||
// Figma API does not expose blend modes for sections,
|
...transformSceneNode(node)
|
||||||
// they plan to add it in the future. Refactor this when available.
|
|
||||||
// @see: https://forum.figma.com/t/add-a-blendmode-property-for-sectionnode/58560
|
|
||||||
...(isSectionNode(node) ? [] : transformBlend(node)),
|
|
||||||
...transformSceneNode(node),
|
|
||||||
// Figma API does not expose constraints proportions for sections
|
|
||||||
...(isSectionNode(node) ? [] : transformProportion(node)),
|
|
||||||
// Figma API does not expose corner radius for sections
|
|
||||||
...(isSectionNode(node) ? [] : transformCornerRadius(node))
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
transformBlend,
|
transformBlend,
|
||||||
transformDimensionAndPosition,
|
transformDimensionAndPosition,
|
||||||
|
transformEffects,
|
||||||
transformSceneNode
|
transformSceneNode
|
||||||
} from '@plugin/transformers/partials';
|
} from '@plugin/transformers/partials';
|
||||||
import { transformChildren } from '@plugin/transformers/partials';
|
import { transformChildren } from '@plugin/transformers/partials';
|
||||||
|
@ -17,6 +18,7 @@ export const transformGroupNode = async (
|
||||||
name: node.name,
|
name: node.name,
|
||||||
...(await transformChildren(node, baseX, baseY)),
|
...(await transformChildren(node, baseX, baseY)),
|
||||||
...transformDimensionAndPosition(node, baseX, baseY),
|
...transformDimensionAndPosition(node, baseX, baseY),
|
||||||
|
...transformEffects(node),
|
||||||
...transformSceneNode(node),
|
...transformSceneNode(node),
|
||||||
...transformBlend(node)
|
...transformBlend(node)
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
transformBlend,
|
transformBlend,
|
||||||
transformDimensionAndPosition,
|
transformDimensionAndPosition,
|
||||||
|
transformEffects,
|
||||||
transformFills,
|
transformFills,
|
||||||
transformProportion,
|
transformProportion,
|
||||||
transformSceneNode,
|
transformSceneNode,
|
||||||
|
@ -23,6 +24,7 @@ export const transformPathNode = (
|
||||||
name: node.name,
|
name: node.name,
|
||||||
...(hasFillGeometry(node) ? transformFills(node) : []),
|
...(hasFillGeometry(node) ? transformFills(node) : []),
|
||||||
...transformStrokes(node),
|
...transformStrokes(node),
|
||||||
|
...transformEffects(node),
|
||||||
...transformVectorPaths(node, baseX, baseY),
|
...transformVectorPaths(node, baseX, baseY),
|
||||||
...transformDimensionAndPosition(node, baseX, baseY),
|
...transformDimensionAndPosition(node, baseX, baseY),
|
||||||
...transformSceneNode(node),
|
...transformSceneNode(node),
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {
|
||||||
transformBlend,
|
transformBlend,
|
||||||
transformCornerRadius,
|
transformCornerRadius,
|
||||||
transformDimensionAndPosition,
|
transformDimensionAndPosition,
|
||||||
|
transformEffects,
|
||||||
transformFills,
|
transformFills,
|
||||||
transformProportion,
|
transformProportion,
|
||||||
transformSceneNode,
|
transformSceneNode,
|
||||||
|
@ -19,6 +20,7 @@ export const transformRectangleNode = (
|
||||||
type: 'rect',
|
type: 'rect',
|
||||||
name: node.name,
|
name: node.name,
|
||||||
...transformFills(node),
|
...transformFills(node),
|
||||||
|
...transformEffects(node),
|
||||||
...transformStrokes(node),
|
...transformStrokes(node),
|
||||||
...transformDimensionAndPosition(node, baseX, baseY),
|
...transformDimensionAndPosition(node, baseX, baseY),
|
||||||
...transformSceneNode(node),
|
...transformSceneNode(node),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
transformBlend,
|
transformBlend,
|
||||||
transformDimensionAndPosition,
|
transformDimensionAndPosition,
|
||||||
|
transformEffects,
|
||||||
transformFills,
|
transformFills,
|
||||||
transformProportion,
|
transformProportion,
|
||||||
transformSceneNode,
|
transformSceneNode,
|
||||||
|
@ -42,6 +43,7 @@ export const transformTextNode = (node: TextNode, baseX: number, baseY: number):
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
...transformDimensionAndPosition(node, baseX, baseY),
|
...transformDimensionAndPosition(node, baseX, baseY),
|
||||||
|
...transformEffects(node),
|
||||||
...transformSceneNode(node),
|
...transformSceneNode(node),
|
||||||
...transformBlend(node),
|
...transformBlend(node),
|
||||||
...transformProportion(node)
|
...transformProportion(node)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export * from './translateBlendMode';
|
export * from './translateBlendMode';
|
||||||
|
export * from './translateShadowEffects';
|
||||||
export * from './translateFills';
|
export * from './translateFills';
|
||||||
export * from './translateStrokes';
|
export * from './translateStrokes';
|
||||||
export * from './translateStyledTextSegments';
|
export * from './translateStyledTextSegments';
|
||||||
|
|
45
plugin-src/translators/translateShadowEffects.ts
Normal file
45
plugin-src/translators/translateShadowEffects.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { rgbToHex } from '@plugin/utils';
|
||||||
|
|
||||||
|
import { Shadow, ShadowStyle } from '@ui/lib/types/utils/shadow';
|
||||||
|
|
||||||
|
export const translateShadowEffect = (effect: Effect): Shadow | undefined => {
|
||||||
|
if (effect.type !== 'DROP_SHADOW' && effect.type !== 'INNER_SHADOW') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
style: translateShadowType(effect),
|
||||||
|
offsetX: effect.offset.x,
|
||||||
|
offsetY: effect.offset.y,
|
||||||
|
blur: effect.radius,
|
||||||
|
spread: effect.spread ?? 0,
|
||||||
|
hidden: !effect.visible,
|
||||||
|
color: {
|
||||||
|
color: rgbToHex(effect.color),
|
||||||
|
opacity: effect.color.a
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const translateShadowEffects = (effects: readonly Effect[]): Shadow[] => {
|
||||||
|
const shadows: Shadow[] = [];
|
||||||
|
|
||||||
|
for (const effect of effects) {
|
||||||
|
const shadow = translateShadowEffect(effect);
|
||||||
|
if (shadow) {
|
||||||
|
// effects are applied in reverse order in Figma, that's why we unshift
|
||||||
|
shadows.unshift(shadow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadows;
|
||||||
|
};
|
||||||
|
|
||||||
|
const translateShadowType = (effect: DropShadowEffect | InnerShadowEffect): ShadowStyle => {
|
||||||
|
switch (effect.type) {
|
||||||
|
case 'DROP_SHADOW':
|
||||||
|
return 'drop-shadow';
|
||||||
|
case 'INNER_SHADOW':
|
||||||
|
return 'inner-shadow';
|
||||||
|
}
|
||||||
|
};
|
2
ui-src/lib/types/utils/color.d.ts
vendored
2
ui-src/lib/types/utils/color.d.ts
vendored
|
@ -12,6 +12,6 @@ export type Color = {
|
||||||
modifiedAt?: string; //@TODO: check this attribute in penpot
|
modifiedAt?: string; //@TODO: check this attribute in penpot
|
||||||
refId?: Uuid;
|
refId?: Uuid;
|
||||||
refFile?: Uuid;
|
refFile?: Uuid;
|
||||||
gradient: Gradient;
|
gradient?: Gradient;
|
||||||
image?: ImageColor;
|
image?: ImageColor;
|
||||||
};
|
};
|
||||||
|
|
4
ui-src/lib/types/utils/shadow.d.ts
vendored
4
ui-src/lib/types/utils/shadow.d.ts
vendored
|
@ -2,9 +2,11 @@ import { Color } from '@ui/lib/types/utils/color';
|
||||||
|
|
||||||
import { Uuid } from './uuid';
|
import { Uuid } from './uuid';
|
||||||
|
|
||||||
|
export type ShadowStyle = 'drop-shadow' | 'inner-shadow';
|
||||||
|
|
||||||
export type Shadow = {
|
export type Shadow = {
|
||||||
id?: Uuid;
|
id?: Uuid;
|
||||||
style: symbol; // 'drop-shadow' | 'inner-shadow'
|
style: ShadowStyle;
|
||||||
offsetX: number;
|
offsetX: number;
|
||||||
offsetY: number;
|
offsetY: number;
|
||||||
blur: number;
|
blur: number;
|
||||||
|
|
Loading…
Reference in a new issue