From 4ded73e0e9b9d3d498aa885bdac642c26b4475d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20S=C3=A1nchez?= Date: Fri, 3 May 2024 13:23:07 +0200 Subject: [PATCH] Paragraph Spacing & Indent (#84) * paragraph space and paragraph indent fixes fixes fine tuning fine tuning fine tuning fine tuning fixes * wip * fix * paragraph space and paragraph indent * changeset * Delete .changeset/new-walls-sort.md --------- Co-authored-by: Jordi Sala Morales --- .changeset/tough-islands-warn.md | 5 ++ .../transformers/partials/transformText.ts | 48 +----------- plugin-src/translators/text/index.ts | 2 + .../text/translateParagraphProperties.ts | 75 +++++++++++++++++++ .../text/translateStyleTextSegments.ts | 65 ++++++++++++++++ 5 files changed, 150 insertions(+), 45 deletions(-) create mode 100644 .changeset/tough-islands-warn.md create mode 100644 plugin-src/translators/text/translateParagraphProperties.ts create mode 100644 plugin-src/translators/text/translateStyleTextSegments.ts diff --git a/.changeset/tough-islands-warn.md b/.changeset/tough-islands-warn.md new file mode 100644 index 0000000..592f84a --- /dev/null +++ b/.changeset/tough-islands-warn.md @@ -0,0 +1,5 @@ +--- +"penpot-exporter": minor +--- + +Paragraph spacing and indent support diff --git a/plugin-src/transformers/partials/transformText.ts b/plugin-src/transformers/partials/transformText.ts index 57db0f3..6025442 100644 --- a/plugin-src/transformers/partials/transformText.ts +++ b/plugin-src/transformers/partials/transformText.ts @@ -1,18 +1,11 @@ import { transformFills } from '@plugin/transformers/partials'; -import { translateFills } from '@plugin/translators'; import { - translateFontId, - translateFontStyle, + transformTextStyle, translateGrowType, - translateHorizontalAlign, - translateLetterSpacing, - translateLineHeight, - translateTextDecoration, - translateTextTransform, + translateStyleTextSegments, translateVerticalAlign } from '@plugin/translators/text'; -import { TextStyle } from '@ui/lib/types/text/textContent'; import { TextShape } from '@ui/lib/types/text/textShape'; export const transformText = (node: TextNode): Partial => { @@ -37,11 +30,7 @@ export const transformText = (node: TextNode): Partial => { children: [ { type: 'paragraph', - children: styledTextSegments.map(segment => ({ - fills: translateFills(segment.fills, node.width, node.height), - text: segment.characters, - ...transformTextStyle(node, segment) - })), + children: translateStyleTextSegments(node, styledTextSegments), ...(styledTextSegments.length ? transformTextStyle(node, styledTextSegments[0]) : {}), ...transformFills(node) } @@ -52,34 +41,3 @@ export const transformText = (node: TextNode): Partial => { growType: translateGrowType(node) }; }; - -const transformTextStyle = ( - node: TextNode, - segment: Pick< - StyledTextSegment, - | 'characters' - | 'start' - | 'end' - | 'fontName' - | 'fontSize' - | 'fontWeight' - | 'lineHeight' - | 'letterSpacing' - | 'textCase' - | 'textDecoration' - | 'fills' - > -): Partial => { - return { - ...translateFontId(segment.fontName, segment.fontWeight), - fontFamily: segment.fontName.family, - fontSize: segment.fontSize.toString(), - fontStyle: translateFontStyle(segment.fontName.style), - fontWeight: segment.fontWeight.toString(), - textAlign: translateHorizontalAlign(node.textAlignHorizontal), - textDecoration: translateTextDecoration(segment), - textTransform: translateTextTransform(segment), - letterSpacing: translateLetterSpacing(segment), - lineHeight: translateLineHeight(segment) - }; -}; diff --git a/plugin-src/translators/text/index.ts b/plugin-src/translators/text/index.ts index 9cdbedc..7341705 100644 --- a/plugin-src/translators/text/index.ts +++ b/plugin-src/translators/text/index.ts @@ -4,6 +4,8 @@ export * from './translateGrowType'; export * from './translateHorizontalAlign'; export * from './translateLetterSpacing'; export * from './translateLineHeight'; +export * from './translateParagraphProperties'; +export * from './translateStyleTextSegments'; export * from './translateTextDecoration'; export * from './translateTextTransform'; export * from './translateVerticalAlign'; diff --git a/plugin-src/translators/text/translateParagraphProperties.ts b/plugin-src/translators/text/translateParagraphProperties.ts new file mode 100644 index 0000000..2fb67e8 --- /dev/null +++ b/plugin-src/translators/text/translateParagraphProperties.ts @@ -0,0 +1,75 @@ +import { TextNode as PenpotTextNode } from '@ui/lib/types/text/textContent'; + +export const translateParagraphProperties = ( + node: TextNode, + segments: PenpotTextNode[] +): PenpotTextNode[] => { + if (node.paragraphSpacing === 0 && node.paragraphIndent === 0) return segments; + + const splitSegments: PenpotTextNode[] = [segmentIndent(node.paragraphIndent)]; + + segments.forEach(segment => { + splitSegments.push(...splitTextNodeByEOL(segment)); + }); + + return addParagraphProperties(splitSegments, node.paragraphIndent, node.paragraphSpacing); +}; + +const splitTextNodeByEOL = (node: PenpotTextNode): PenpotTextNode[] => { + const split = node.text.split(/(\n)/).filter(text => text !== ''); + + return split.map(text => ({ + ...node, + text: text + })); +}; + +const addParagraphProperties = ( + nodes: PenpotTextNode[], + indent: number, + paragraphSpacing: number +): PenpotTextNode[] => { + const indentedTextNodes: PenpotTextNode[] = []; + + nodes.forEach(node => { + indentedTextNodes.push(node); + + if (node.text !== '\n') return; + + if (paragraphSpacing !== 0) { + indentedTextNodes.push(segmentParagraphSpacing(paragraphSpacing)); + } + + if (indent !== 0) { + indentedTextNodes.push(segmentIndent(indent)); + } + }); + + return indentedTextNodes; +}; + +const segmentIndent = (indent: number): PenpotTextNode => { + return { + text: ' '.repeat(indent), + fontId: 'sourcesanspro', + fontVariantId: 'regular', + fontSize: '5', + fontStyle: 'normal', + fontWeight: '400', + lineHeight: 1, + letterSpacing: 0 + }; +}; + +const segmentParagraphSpacing = (paragraphSpacing: number): PenpotTextNode => { + return { + text: '\n', + fontId: 'sourcesanspro', + fontVariantId: 'regular', + fontSize: paragraphSpacing.toString(), + fontStyle: 'normal', + fontWeight: '400', + lineHeight: 1, + letterSpacing: 0 + }; +}; diff --git a/plugin-src/translators/text/translateStyleTextSegments.ts b/plugin-src/translators/text/translateStyleTextSegments.ts new file mode 100644 index 0000000..37f5f0a --- /dev/null +++ b/plugin-src/translators/text/translateStyleTextSegments.ts @@ -0,0 +1,65 @@ +import { translateFills } from '@plugin/translators'; +import { + translateFontId, + translateFontStyle, + translateHorizontalAlign, + translateLetterSpacing, + translateLineHeight, + translateParagraphProperties, + translateTextDecoration, + translateTextTransform +} from '@plugin/translators/text'; + +import { TextNode as PenpotTextNode, TextStyle } from '@ui/lib/types/text/textContent'; + +type StyleTextSegment = Pick< + StyledTextSegment, + | 'characters' + | 'start' + | 'end' + | 'fontName' + | 'fontSize' + | 'fontWeight' + | 'lineHeight' + | 'letterSpacing' + | 'textCase' + | 'textDecoration' + | 'fills' +>; + +export const translateStyleTextSegments = ( + node: TextNode, + segments: StyleTextSegment[] +): PenpotTextNode[] => { + const textNodes = segments.map(segment => { + return translateStyleTextSegment(node, segment); + }); + + return translateParagraphProperties(node, textNodes); +}; + +export const transformTextStyle = ( + node: TextNode, + segment: StyleTextSegment +): Partial => { + return { + ...translateFontId(segment.fontName, segment.fontWeight), + fontFamily: segment.fontName.family, + fontSize: segment.fontSize.toString(), + fontStyle: translateFontStyle(segment.fontName.style), + fontWeight: segment.fontWeight.toString(), + textAlign: translateHorizontalAlign(node.textAlignHorizontal), + textDecoration: translateTextDecoration(segment), + textTransform: translateTextTransform(segment), + letterSpacing: translateLetterSpacing(segment), + lineHeight: translateLineHeight(segment) + }; +}; + +const translateStyleTextSegment = (node: TextNode, segment: StyleTextSegment): PenpotTextNode => { + return { + fills: translateFills(segment.fills, node.width, node.height), + text: segment.characters, + ...transformTextStyle(node, segment) + }; +};