0
Fork 0
mirror of https://github.com/penpot/penpot-exporter-figma-plugin.git synced 2025-01-03 05:10:13 -05:00

Added text basic properties (#61)

* fixes in text nodes

* fix comment

* allow design.penpot.app

* wip

* wip

* add position data

* wip agaaain

* added translate growtype

* use a random url just to get a 404 on gfonts call

* leave the config, just in case someone wants to try it

* translated line height & letter spacing; Created new type for text positionData

* text strokes

* several fixes

* compiled penpot lib with fix

* updated penpot lib

* fix lint

* remove proxy

* correctly translate font style

* fix grow type to reflect vertical trim

* Fix font segments

* remove comment

* changeset

---------

Co-authored-by: Alex Sánchez <sion333@gmail.com>
This commit is contained in:
Jordi Sala Morales 2024-04-29 10:17:08 +02:00 committed by GitHub
parent 942b39370f
commit 881ccabe86
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 5525 additions and 5475 deletions

View file

@ -0,0 +1,5 @@
---
"penpot-exporter": minor
---
Added text basic properties

View file

@ -1,9 +1,20 @@
import { translateTextDecoration, translateTextTransform } from '@plugin/translators'; import slugify from 'slugify';
import {
translateFontStyle,
translateFontVariantId,
translateHorizontalAlign,
translateLetterSpacing,
translateLineHeight,
translateTextDecoration,
translateTextTransform
} from '@plugin/translators';
import { TextStyle } from '@ui/lib/types/text/textContent'; import { TextStyle } from '@ui/lib/types/text/textContent';
export const transformTextStyle = ( export const transformTextStyle = (
node: Pick< node: TextNode,
segment: Pick<
StyledTextSegment, StyledTextSegment,
| 'characters' | 'characters'
| 'start' | 'start'
@ -19,11 +30,16 @@ export const transformTextStyle = (
> >
): Partial<TextStyle> => { ): Partial<TextStyle> => {
return { return {
fontFamily: node.fontName.family, fontFamily: segment.fontName.family,
fontSize: node.fontSize.toString(), fontId: `gfont-${slugify(segment.fontName.family.toLowerCase())}`,
fontStyle: node.fontName.style, fontSize: segment.fontSize.toString(),
fontWeight: node.fontWeight.toString(), fontStyle: translateFontStyle(segment.fontName.style),
textDecoration: translateTextDecoration(node), fontWeight: segment.fontWeight.toString(),
textTransform: translateTextTransform(node) fontVariantId: translateFontVariantId(segment.fontName.style),
textAlign: translateHorizontalAlign(node.textAlignHorizontal),
textDecoration: translateTextDecoration(segment),
textTransform: translateTextTransform(segment),
letterSpacing: translateLetterSpacing(segment),
lineHeight: translateLineHeight(segment)
}; };
}; };

View file

@ -5,9 +5,14 @@ import {
transformFills, transformFills,
transformProportion, transformProportion,
transformSceneNode, transformSceneNode,
transformStrokes,
transformTextStyle transformTextStyle
} from '@plugin/transformers/partials'; } from '@plugin/transformers/partials';
import { translateStyledTextSegments } from '@plugin/translators'; import {
translateGrowType,
translateStyledTextSegments,
translateVerticalAlign
} from '@plugin/translators';
import { TextShape } from '@ui/lib/types/text/textShape'; import { TextShape } from '@ui/lib/types/text/textShape';
@ -28,24 +33,27 @@ export const transformTextNode = (node: TextNode, baseX: number, baseY: number):
name: node.name, name: node.name,
content: { content: {
type: 'root', type: 'root',
verticalAlign: translateVerticalAlign(node.textAlignVertical),
children: [ children: [
{ {
type: 'paragraph-set', type: 'paragraph-set',
children: [ children: [
{ {
type: 'paragraph', type: 'paragraph',
children: translateStyledTextSegments(styledTextSegments, node.width, node.height), children: translateStyledTextSegments(node, styledTextSegments),
...(styledTextSegments.length ? transformTextStyle(styledTextSegments[0]) : {}), ...(styledTextSegments.length ? transformTextStyle(node, styledTextSegments[0]) : {}),
...transformFills(node) ...transformFills(node)
} }
] ]
} }
] ]
}, },
growType: translateGrowType(node),
...transformDimensionAndPosition(node, baseX, baseY), ...transformDimensionAndPosition(node, baseX, baseY),
...transformEffects(node), ...transformEffects(node),
...transformSceneNode(node), ...transformSceneNode(node),
...transformBlend(node), ...transformBlend(node),
...transformProportion(node) ...transformProportion(node),
...transformStrokes(node)
}; };
}; };

View file

@ -1,8 +1,15 @@
export * from './translateBlendMode'; export * from './translateBlendMode';
export * from './translateShadowEffects'; export * from './translateShadowEffects';
export * from './translateFills'; export * from './translateFills';
export * from './translateFontStyle';
export * from './translateFontVariantId';
export * from './translateGrowType';
export * from './translateHorizontalAlign';
export * from './translateLetterSpacing';
export * from './translateLineHeight';
export * from './translateStrokes'; export * from './translateStrokes';
export * from './translateStyledTextSegments'; export * from './translateStyledTextSegments';
export * from './translateTextDecoration'; export * from './translateTextDecoration';
export * from './translateTextTransform'; export * from './translateTextTransform';
export * from './translateVectorPaths'; export * from './translateVectorPaths';
export * from './translateVerticalAlign';

View file

@ -0,0 +1,9 @@
import { TextFontStyle } from '@ui/lib/types/text/textContent';
export const translateFontStyle = (style: string): TextFontStyle => {
if (style.toLowerCase().includes('italic')) {
return 'italic';
}
return 'normal';
};

View file

@ -0,0 +1,3 @@
export const translateFontVariantId = (style: string) => {
return style.toLowerCase().replace(/\s/g, '');
};

View file

@ -0,0 +1,17 @@
import { GrowType } from '@ui/lib/types/shape/shapeAttributes';
export const translateGrowType = (node: TextNode): GrowType => {
if (node.leadingTrim === 'CAP_HEIGHT') {
return 'fixed';
}
switch (node.textAutoResize) {
case 'WIDTH_AND_HEIGHT':
return 'auto-width';
case 'HEIGHT':
return 'auto-height';
case 'TRUNCATE':
default:
return 'fixed';
}
};

View file

@ -0,0 +1,16 @@
import { TextHorizontalAlign } from '@ui/lib/types/text/textContent';
export const translateHorizontalAlign = (
align: 'LEFT' | 'CENTER' | 'RIGHT' | 'JUSTIFIED'
): TextHorizontalAlign => {
switch (align) {
case 'RIGHT':
return 'right';
case 'CENTER':
return 'center';
case 'JUSTIFIED':
return 'justify';
default:
return 'left';
}
};

View file

@ -0,0 +1,12 @@
export const translateLetterSpacing = (
segment: Pick<StyledTextSegment, 'letterSpacing' | 'fontSize'>
): number => {
switch (segment.letterSpacing.unit) {
case 'PIXELS':
return segment.letterSpacing.value;
case 'PERCENT':
return (segment.fontSize * segment.letterSpacing.value) / 100;
default:
return 0;
}
};

View file

@ -0,0 +1,10 @@
export const translateLineHeight = (
segment: Pick<StyledTextSegment, 'lineHeight' | 'fontSize'>
): number | undefined => {
switch (segment.lineHeight.unit) {
case 'PIXELS':
return segment.lineHeight.value / segment.fontSize;
case 'PERCENT':
return segment.lineHeight.value / 100;
}
};

View file

@ -1,9 +1,10 @@
import { transformTextStyle } from '@plugin/transformers/partials'; import { transformTextStyle } from '@plugin/transformers/partials';
import { translateFills } from '@plugin/translators/translateFills'; import { translateFills } from '@plugin/translators/translateFills';
import { TextNode } from '@ui/lib/types/text/textContent'; import { TextNode as PenpotTextNode } from '@ui/lib/types/text/textContent';
export const translateStyledTextSegments = ( export const translateStyledTextSegments = (
node: TextNode,
segments: Pick< segments: Pick<
StyledTextSegment, StyledTextSegment,
| 'characters' | 'characters'
@ -17,17 +18,15 @@ export const translateStyledTextSegments = (
| 'textCase' | 'textCase'
| 'textDecoration' | 'textDecoration'
| 'fills' | 'fills'
>[], >[]
width: number, ): PenpotTextNode[] => {
height: number
): TextNode[] => {
return segments.map(segment => { return segments.map(segment => {
figma.ui.postMessage({ type: 'FONT_NAME', data: segment.fontName.family }); figma.ui.postMessage({ type: 'FONT_NAME', data: segment.fontName.family });
return { return {
fills: translateFills(segment.fills, width, height), fills: translateFills(segment.fills, node.width, node.height),
text: segment.characters, text: segment.characters,
...transformTextStyle(segment) ...transformTextStyle(node, segment)
}; };
}); });
}; };

View file

@ -0,0 +1,12 @@
import { TextVerticalAlign } from '@ui/lib/types/text/textContent';
export const translateVerticalAlign = (align: 'TOP' | 'CENTER' | 'BOTTOM'): TextVerticalAlign => {
switch (align) {
case 'BOTTOM':
return 'bottom';
case 'CENTER':
return 'center';
default:
return 'top';
}
};

File diff suppressed because it is too large Load diff

View file

@ -45,5 +45,7 @@ export type ShapeAttributes = {
interactions?: Interaction[]; interactions?: Interaction[];
shadow?: Shadow[]; shadow?: Shadow[];
blur?: Blur; blur?: Blur;
growType?: 'auto-width' | 'auto-height' | 'fixed'; growType?: GrowType;
}; };
export type GrowType = 'auto-width' | 'auto-height' | 'fixed';

View file

@ -3,9 +3,14 @@ import { Fill } from '@ui/lib/types/utils/fill';
export type TextContent = { export type TextContent = {
type: 'root'; type: 'root';
key?: string; key?: string;
verticalAlign?: TextVerticalAlign;
children?: ParagraphSet[]; children?: ParagraphSet[];
}; };
export type TextVerticalAlign = 'top' | 'bottom' | 'center';
export type TextHorizontalAlign = 'left' | 'right' | 'center' | 'justify';
export type TextFontStyle = 'normal' | 'italic';
type ParagraphSet = { type ParagraphSet = {
type: 'paragraph-set'; type: 'paragraph-set';
key?: string; key?: string;
@ -24,14 +29,20 @@ type TextNode = {
} & TextStyle; } & TextStyle;
type TextStyle = { type TextStyle = {
fontId?: string;
fontFamily?: string; fontFamily?: string;
fontVariantId?: string;
fontSize?: string; fontSize?: string;
fontStyle?: string; fontStyle?: TextFontStyle;
fontWeight?: string; fontWeight?: string;
textDecoration?: string; textDecoration?: string;
textTransform?: string; textTransform?: string;
direction?: string; direction?: string;
typographyRefId?: string; typographyRefId?: string;
typographyRefFile?: string; typographyRefFile?: string;
lineHeight?: number;
letterSpacing?: number;
textAlign?: TextHorizontalAlign;
textDirection?: 'ltr' | 'rtl' | 'auto';
fills?: Fill[]; fills?: Fill[];
}; };

View file

@ -1,6 +1,3 @@
export * from './translateFillGradients'; export * from './translateFillGradients';
export * from './translateFontStyle';
export * from './translateHorizontalAlign';
export * from './translatePathContent'; export * from './translatePathContent';
export * from './translateUiBlendMode'; export * from './translateUiBlendMode';
export * from './translateVerticalAlign';

View file

@ -1,3 +0,0 @@
export const translateFontStyle = (style: string) => {
return style.toLowerCase().replace(/\s/g, '');
};

View file

@ -1,9 +0,0 @@
export const translateHorizontalAlign = (align: string) => {
if (align === 'RIGHT') {
return Symbol.for('right');
}
if (align === 'CENTER') {
return Symbol.for('center');
}
return Symbol.for('left');
};

View file

@ -1,9 +0,0 @@
export const translateVerticalAlign = (align: string) => {
if (align === 'BOTTOM') {
return Symbol.for('bottom');
}
if (align === 'CENTER') {
return Symbol.for('center');
}
return Symbol.for('top');
};