mirror of
https://github.com/penpot/penpot-exporter-figma-plugin.git
synced 2024-12-22 13:43:03 -05:00
Implement unordered and ordered lists (#88)
* wip * implement bullet points * needs more ifs * refactor * revert * refactor * fix and refactor * refactor * refactor * refactor * add ordered class * wip * wip * fixes * package.json * little refactors * base list * fixes * abstract baselist * refactors * refactor * changeset * fix eslint issue * fix * fixes * fixes --------- Co-authored-by: Alex Sánchez <sion333@gmail.com>
This commit is contained in:
parent
afa47af0a6
commit
2920ac297b
44 changed files with 362 additions and 123 deletions
5
.changeset/curly-clouds-tease.md
Normal file
5
.changeset/curly-clouds-tease.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"penpot-exporter": minor
|
||||
---
|
||||
|
||||
Ordered and unordered list support
|
|
@ -21,6 +21,9 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-vars': ['error', { ignoreRestSiblings: true }]
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ ignoreRestSiblings: true, argsIgnorePattern: '^_' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -12,6 +12,7 @@
|
|||
"react": "^18.3",
|
||||
"react-dom": "^18.3",
|
||||
"react-hook-form": "^7.51",
|
||||
"romans": "^2.0",
|
||||
"slugify": "^1.6",
|
||||
"svg-path-parser": "^1.1"
|
||||
},
|
||||
|
@ -6550,6 +6551,11 @@
|
|||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/romans": {
|
||||
"version": "2.0.15",
|
||||
"resolved": "https://registry.npmjs.org/romans/-/romans-2.0.15.tgz",
|
||||
"integrity": "sha512-/0/Wdz+Q948fkUlBt+JUgkxdYAmlBStLoSIqpBxaEDg9NGORrGaMCu9iYk8eRsiwRe2cLWflJswZP6g9vGIE1w=="
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"react": "^18.3",
|
||||
"react-dom": "^18.3",
|
||||
"react-hook-form": "^7.51",
|
||||
"romans": "^2.0",
|
||||
"slugify": "^1.6",
|
||||
"svg-path-parser": "^1.1"
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { transformDocumentNode } from '@plugin/transformers';
|
||||
|
||||
import { findAllTextNodes } from './findAllTextnodes';
|
||||
import { setCustomFontId } from './translators/text/custom';
|
||||
import { setCustomFontId } from './translators/text/font/custom';
|
||||
|
||||
figma.showUI(__html__, { themeColors: true, height: 300, width: 400 });
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { isGoogleFont } from './translators/text/gfonts';
|
||||
import { isLocalFont } from './translators/text/local';
|
||||
import { isGoogleFont } from './translators/text/font/gfonts';
|
||||
import { isLocalFont } from './translators/text/font/local';
|
||||
|
||||
export const findAllTextNodes = async () => {
|
||||
await figma.loadAllPagesAsync();
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import { transformFills } from '@plugin/transformers/partials';
|
||||
import {
|
||||
transformTextStyle,
|
||||
translateGrowType,
|
||||
translateStyleTextSegments,
|
||||
translateVerticalAlign
|
||||
} from '@plugin/translators/text';
|
||||
import { transformTextStyle, translateStyleTextSegments } from '@plugin/translators/text';
|
||||
import { translateGrowType, translateVerticalAlign } from '@plugin/translators/text/properties';
|
||||
|
||||
import { TextShape } from '@ui/lib/types/shapes/textShape';
|
||||
|
||||
|
@ -17,6 +13,8 @@ export const transformText = (node: TextNode): Partial<TextShape> => {
|
|||
'letterSpacing',
|
||||
'textCase',
|
||||
'textDecoration',
|
||||
'indentation',
|
||||
'listOptions',
|
||||
'fills'
|
||||
]);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export * from './translateBlendMode';
|
||||
export * from './translateShadowEffects';
|
||||
export * from './translateFills';
|
||||
export * from './translateShadowEffects';
|
||||
export * from './translateStrokes';
|
||||
export * from './translateVectorPaths';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { getCustomFontId, translateFontVariantId } from '@plugin/translators/text/custom';
|
||||
import { getCustomFontId, translateFontVariantId } from '@plugin/translators/text/font/custom';
|
||||
|
||||
import { FontId } from '@ui/lib/types/shapes/textShape';
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
export * from './googleFont';
|
||||
export * from './translateGoogleFont';
|
||||
export * from './translateFontVariantId';
|
||||
export * from './translateGoogleFont';
|
|
@ -1,6 +1,6 @@
|
|||
import slugify from 'slugify';
|
||||
|
||||
import { translateFontVariantId } from '@plugin/translators/text/gfonts';
|
||||
import { translateFontVariantId } from '@plugin/translators/text/font/gfonts';
|
||||
|
||||
import { FontId } from '@ui/lib/types/shapes/textShape';
|
||||
|
1
plugin-src/translators/text/font/index.ts
Normal file
1
plugin-src/translators/text/font/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './translateFontId';
|
|
@ -1,3 +1,3 @@
|
|||
export * from './localFont';
|
||||
export * from './translateLocalFont';
|
||||
export * from './translateFontVariantId';
|
||||
export * from './translateLocalFont';
|
|
@ -1,4 +1,4 @@
|
|||
import { LocalFont, translateFontVariantId } from '@plugin/translators/text/local';
|
||||
import { LocalFont, translateFontVariantId } from '@plugin/translators/text/font/local';
|
||||
|
||||
import { FontId } from '@ui/lib/types/shapes/textShape';
|
||||
|
|
@ -1,11 +1 @@
|
|||
export * from './translateFontId';
|
||||
export * from './translateFontStyle';
|
||||
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';
|
||||
|
|
79
plugin-src/translators/text/paragraph/List.ts
Normal file
79
plugin-src/translators/text/paragraph/List.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { StyleTextSegment } from '@plugin/translators/text/paragraph/translateParagraphProperties';
|
||||
|
||||
import { TextNode as PenpotTextNode } from '@ui/lib/types/shapes/textShape';
|
||||
|
||||
import { ListTypeFactory } from './ListTypeFactory';
|
||||
|
||||
type Level = {
|
||||
style: PenpotTextNode;
|
||||
counter: number;
|
||||
type: ListType;
|
||||
};
|
||||
|
||||
type ListType = 'ORDERED' | 'UNORDERED';
|
||||
|
||||
export class List {
|
||||
private levels: Map<number, Level> = new Map();
|
||||
private indentation = 0;
|
||||
protected counter: number[] = [];
|
||||
private listTypeFactory = new ListTypeFactory();
|
||||
|
||||
public update(textNode: PenpotTextNode, segment: StyleTextSegment): void {
|
||||
if (segment.indentation < this.indentation) {
|
||||
for (let i = segment.indentation + 1; i <= this.indentation; i++) {
|
||||
this.levels.delete(i);
|
||||
}
|
||||
}
|
||||
|
||||
let level = this.levels.get(segment.indentation);
|
||||
|
||||
if (!level || level.type !== this.getListType(segment)) {
|
||||
level = {
|
||||
style: this.createStyle(textNode, segment.indentation),
|
||||
counter: 0,
|
||||
type: this.getListType(segment)
|
||||
};
|
||||
|
||||
this.levels.set(segment.indentation, level);
|
||||
}
|
||||
|
||||
level.counter++;
|
||||
this.indentation = segment.indentation;
|
||||
}
|
||||
|
||||
public getCurrentList(textNode: PenpotTextNode, segment: StyleTextSegment): PenpotTextNode {
|
||||
const level = this.levels.get(segment.indentation);
|
||||
if (level === undefined) {
|
||||
throw new Error('Levels not updated');
|
||||
}
|
||||
|
||||
const listType = this.listTypeFactory.getListType(segment.listOptions);
|
||||
|
||||
return this.updateCurrentSymbol(
|
||||
listType.getCurrentSymbol(level.counter, segment.indentation),
|
||||
level.style
|
||||
);
|
||||
}
|
||||
|
||||
private getListType(segment: StyleTextSegment): ListType {
|
||||
if (segment.listOptions.type === 'NONE') {
|
||||
throw new Error('List type not valid');
|
||||
}
|
||||
|
||||
return segment.listOptions.type;
|
||||
}
|
||||
|
||||
private createStyle(node: PenpotTextNode, indentation: number): PenpotTextNode {
|
||||
return {
|
||||
...node,
|
||||
text: `${'\t'.repeat(Math.max(0, indentation - 1))}{currentSymbol}`
|
||||
};
|
||||
}
|
||||
|
||||
private updateCurrentSymbol(character: string, currentStyle: PenpotTextNode): PenpotTextNode {
|
||||
return {
|
||||
...currentStyle,
|
||||
text: currentStyle.text.replace('{currentSymbol}', character)
|
||||
};
|
||||
}
|
||||
}
|
3
plugin-src/translators/text/paragraph/ListType.ts
Normal file
3
plugin-src/translators/text/paragraph/ListType.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export interface ListType {
|
||||
getCurrentSymbol(number: number, indentation: number): string;
|
||||
}
|
19
plugin-src/translators/text/paragraph/ListTypeFactory.ts
Normal file
19
plugin-src/translators/text/paragraph/ListTypeFactory.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { ListType } from './ListType';
|
||||
import { OrderedListType } from './OrderedListType';
|
||||
import { UnorderedListType } from './UnorderedListType';
|
||||
|
||||
export class ListTypeFactory {
|
||||
private unorderedList = new UnorderedListType();
|
||||
private orderedList = new OrderedListType();
|
||||
|
||||
public getListType(textListOptions: TextListOptions): ListType {
|
||||
switch (textListOptions.type) {
|
||||
case 'ORDERED':
|
||||
return this.orderedList;
|
||||
case 'UNORDERED':
|
||||
return this.unorderedList;
|
||||
}
|
||||
|
||||
throw new Error('List type not valid');
|
||||
}
|
||||
}
|
42
plugin-src/translators/text/paragraph/OrderedListType.ts
Normal file
42
plugin-src/translators/text/paragraph/OrderedListType.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import * as romans from 'romans';
|
||||
|
||||
import { ListType } from './ListType';
|
||||
|
||||
export class OrderedListType implements ListType {
|
||||
public getCurrentSymbol(number: number, indentation: number): string {
|
||||
let symbol = '. ';
|
||||
switch (indentation % 3) {
|
||||
case 0:
|
||||
symbol = romans.romanize(number).toLowerCase() + symbol;
|
||||
break;
|
||||
case 2:
|
||||
symbol = this.letterOrderedList(number) + symbol;
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
symbol = number.toString() + symbol;
|
||||
break;
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
private letterOrderedList(number: number): string {
|
||||
let result = '';
|
||||
|
||||
while (number > 0) {
|
||||
let letterCode = number % 26;
|
||||
|
||||
if (letterCode === 0) {
|
||||
letterCode = 26;
|
||||
number = Math.floor(number / 26) - 1;
|
||||
} else {
|
||||
number = Math.floor(number / 26);
|
||||
}
|
||||
|
||||
result = String.fromCharCode(letterCode + 96) + result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
93
plugin-src/translators/text/paragraph/Paragraph.ts
Normal file
93
plugin-src/translators/text/paragraph/Paragraph.ts
Normal file
|
@ -0,0 +1,93 @@
|
|||
import { TextNode as PenpotTextNode } from '@ui/lib/types/shapes/textShape';
|
||||
|
||||
import { List } from './List';
|
||||
import { StyleTextSegment } from './translateParagraphProperties';
|
||||
|
||||
export class Paragraph {
|
||||
private isParagraphStarting = false;
|
||||
private isPreviousNodeAList = false;
|
||||
private firstTextNode: PenpotTextNode | null = null;
|
||||
private list = new List();
|
||||
|
||||
public format(
|
||||
node: TextNode,
|
||||
textNode: PenpotTextNode,
|
||||
segment: StyleTextSegment
|
||||
): PenpotTextNode[] {
|
||||
const textNodes: PenpotTextNode[] = [];
|
||||
|
||||
const spacing = this.applySpacing(segment, node);
|
||||
if (spacing) textNodes.push(spacing);
|
||||
|
||||
const indentation = this.applyIndentation(textNode, segment, node);
|
||||
if (indentation) textNodes.push(indentation);
|
||||
|
||||
textNodes.push(textNode);
|
||||
|
||||
this.isPreviousNodeAList = segment.listOptions.type !== 'NONE';
|
||||
this.isParagraphStarting = textNode.text === '\n';
|
||||
|
||||
return textNodes;
|
||||
}
|
||||
|
||||
private applyIndentation(
|
||||
textNode: PenpotTextNode,
|
||||
segment: StyleTextSegment,
|
||||
node: TextNode
|
||||
): PenpotTextNode | undefined {
|
||||
if (this.isParagraphStarting || this.isFirstTextNode(textNode)) {
|
||||
this.list.update(textNode, segment);
|
||||
|
||||
return segment.listOptions.type !== 'NONE'
|
||||
? this.list.getCurrentList(textNode, segment)
|
||||
: this.segmentIndent(node.paragraphIndent);
|
||||
}
|
||||
}
|
||||
|
||||
private applySpacing(segment: StyleTextSegment, node: TextNode): PenpotTextNode | undefined {
|
||||
if (this.isParagraphStarting) {
|
||||
const isList = segment.listOptions.type !== 'NONE';
|
||||
|
||||
return this.segmentParagraphSpacing(
|
||||
this.isPreviousNodeAList && isList ? node.listSpacing : node.paragraphSpacing
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private isFirstTextNode(textNode: PenpotTextNode) {
|
||||
if (this.firstTextNode === null) {
|
||||
this.firstTextNode = textNode;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private segmentIndent(indent: number): PenpotTextNode {
|
||||
return {
|
||||
text: ' '.repeat(indent),
|
||||
fontId: 'sourcesanspro',
|
||||
fontVariantId: 'regular',
|
||||
fontSize: '5',
|
||||
fontStyle: 'normal',
|
||||
fontWeight: '400',
|
||||
lineHeight: 1,
|
||||
letterSpacing: 0
|
||||
};
|
||||
}
|
||||
|
||||
private segmentParagraphSpacing(paragraphSpacing: number): PenpotTextNode | undefined {
|
||||
if (paragraphSpacing === 0) return;
|
||||
|
||||
return {
|
||||
text: '\n',
|
||||
fontId: 'sourcesanspro',
|
||||
fontVariantId: 'regular',
|
||||
fontSize: paragraphSpacing.toString(),
|
||||
fontStyle: 'normal',
|
||||
fontWeight: '400',
|
||||
lineHeight: 1,
|
||||
letterSpacing: 0
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ListType } from './ListType';
|
||||
|
||||
export class UnorderedListType implements ListType {
|
||||
public getCurrentSymbol(_number: number, _indentation: number): string {
|
||||
return ' • ';
|
||||
}
|
||||
}
|
7
plugin-src/translators/text/paragraph/index.ts
Normal file
7
plugin-src/translators/text/paragraph/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export * from './List';
|
||||
export * from './ListType';
|
||||
export * from './ListTypeFactory';
|
||||
export * from './OrderedListType';
|
||||
export * from './Paragraph';
|
||||
export * from './translateParagraphProperties';
|
||||
export * from './UnorderedListType';
|
|
@ -0,0 +1,66 @@
|
|||
import { TextNode as PenpotTextNode } from '@ui/lib/types/shapes/textShape';
|
||||
|
||||
import { Paragraph } from './Paragraph';
|
||||
|
||||
export type StyleTextSegment = Pick<
|
||||
StyledTextSegment,
|
||||
| 'characters'
|
||||
| 'start'
|
||||
| 'end'
|
||||
| 'fontName'
|
||||
| 'fontSize'
|
||||
| 'fontWeight'
|
||||
| 'lineHeight'
|
||||
| 'letterSpacing'
|
||||
| 'textCase'
|
||||
| 'textDecoration'
|
||||
| 'indentation'
|
||||
| 'listOptions'
|
||||
| 'fills'
|
||||
>;
|
||||
|
||||
type PartialTranslation = {
|
||||
textNodes: PenpotTextNode[];
|
||||
segment: StyleTextSegment;
|
||||
};
|
||||
|
||||
export const translateParagraphProperties = (
|
||||
node: TextNode,
|
||||
partials: { textNode: PenpotTextNode; segment: StyleTextSegment }[]
|
||||
): PenpotTextNode[] => {
|
||||
const splitSegments: PartialTranslation[] = [];
|
||||
|
||||
partials.forEach(({ textNode, segment }) => {
|
||||
splitSegments.push({
|
||||
textNodes: splitTextNodeByEOL(textNode),
|
||||
segment
|
||||
});
|
||||
});
|
||||
|
||||
return addParagraphProperties(node, splitSegments);
|
||||
};
|
||||
|
||||
const splitTextNodeByEOL = (node: PenpotTextNode): PenpotTextNode[] => {
|
||||
const split = node.text.split(/(\n)/).filter(text => text !== '');
|
||||
|
||||
return split.map(text => ({
|
||||
...node,
|
||||
text: text
|
||||
}));
|
||||
};
|
||||
|
||||
const addParagraphProperties = (
|
||||
node: TextNode,
|
||||
partials: PartialTranslation[]
|
||||
): PenpotTextNode[] => {
|
||||
const formattedParagraphs: PenpotTextNode[] = [];
|
||||
const paragraph = new Paragraph();
|
||||
|
||||
partials.forEach(({ textNodes, segment }) =>
|
||||
textNodes.forEach(textNode => {
|
||||
formattedParagraphs.push(...paragraph.format(node, textNode, segment));
|
||||
})
|
||||
);
|
||||
|
||||
return formattedParagraphs;
|
||||
};
|
8
plugin-src/translators/text/properties/index.ts
Normal file
8
plugin-src/translators/text/properties/index.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
export * from './translateFontStyle';
|
||||
export * from './translateGrowType';
|
||||
export * from './translateHorizontalAlign';
|
||||
export * from './translateLetterSpacing';
|
||||
export * from './translateLineHeight';
|
||||
export * from './translateTextDecoration';
|
||||
export * from './translateTextTransform';
|
||||
export * from './translateVerticalAlign';
|
|
@ -1,75 +0,0 @@
|
|||
import { TextNode as PenpotTextNode } from '@ui/lib/types/shapes/textShape';
|
||||
|
||||
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
|
||||
};
|
||||
};
|
|
@ -1,41 +1,27 @@
|
|||
import { translateFills } from '@plugin/translators';
|
||||
import { translateFontId } from '@plugin/translators/text/font';
|
||||
import { StyleTextSegment, translateParagraphProperties } from '@plugin/translators/text/paragraph';
|
||||
import {
|
||||
translateFontId,
|
||||
translateFontStyle,
|
||||
translateHorizontalAlign,
|
||||
translateLetterSpacing,
|
||||
translateLineHeight,
|
||||
translateParagraphProperties,
|
||||
translateTextDecoration,
|
||||
translateTextTransform
|
||||
} from '@plugin/translators/text';
|
||||
} from '@plugin/translators/text/properties';
|
||||
|
||||
import { TextNode as PenpotTextNode, TextStyle } from '@ui/lib/types/shapes/textShape';
|
||||
|
||||
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);
|
||||
});
|
||||
const partials = segments.map(segment => ({
|
||||
textNode: translateStyleTextSegment(node, segment),
|
||||
segment
|
||||
}));
|
||||
|
||||
return translateParagraphProperties(node, textNodes);
|
||||
return translateParagraphProperties(node, partials);
|
||||
};
|
||||
|
||||
export const transformTextStyle = (
|
||||
|
|
Loading…
Reference in a new issue