Skip to content

Commit 468590e

Browse files
committed
Update var typo
1 parent fe521ff commit 468590e

File tree

5 files changed

+320
-28
lines changed

5 files changed

+320
-28
lines changed

src/Element.ts

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
checkSvgImageChildrenType,
3+
colorFromFills,
34
createInterface,
45
cssToProps,
56
filterPropsByChildrenCountAndType,
@@ -325,34 +326,73 @@ export class Element {
325326

326327
if (this.node.type === 'TEXT') {
327328
const segs = this.node.getStyledTextSegments(SEGMENT_TYPE)
329+
330+
// select main color, 가장 자주 사용되는 색상
331+
const propsArray = await Promise.all(
332+
segs.map(async (seg) =>
333+
propsToComponentProps(
334+
organizeProps(
335+
Object.fromEntries(
336+
Object.entries(
337+
await propsToPropsWithTypography(
338+
{
339+
...mergedProps,
340+
...((await textSegmentToTypography(seg)) as any),
341+
color: await colorFromFills(seg.fills as any),
342+
},
343+
seg.textStyleId,
344+
),
345+
)
346+
.filter(([_, value]) => Boolean(value))
347+
.map(([key, value]) => [key, String(value)]),
348+
),
349+
),
350+
'Text',
351+
1,
352+
),
353+
),
354+
)
355+
let mainColor = ''
356+
let mainColorCount = 0
357+
let mainTypography = ''
358+
let mainTypographyCount = 0
359+
360+
propsArray.forEach((props) => {
361+
const filterdColor = propsArray.filter((p) => p.color === props.color)
362+
if (filterdColor.length > mainColorCount) {
363+
mainColor = props.color
364+
mainColorCount = filterdColor.length
365+
}
366+
367+
const filterdTypography = propsArray.filter(
368+
(p) => p.typography === props.typography,
369+
)
370+
if (filterdTypography.length > mainTypographyCount) {
371+
mainTypography = props.typography
372+
mainTypographyCount = filterdTypography.length
373+
}
374+
})
375+
328376
const children = (
329377
await Promise.all(
330-
segs.map(async (seg) => {
331-
const props = propsToComponentProps(
332-
organizeProps(
333-
Object.fromEntries(
334-
Object.entries(
335-
await propsToPropsWithTypography(
336-
{
337-
...mergedProps,
338-
...((await textSegmentToTypography(seg)) as any),
339-
},
340-
seg.textStyleId,
341-
),
342-
)
343-
.filter(([_, value]) => Boolean(value))
344-
.map(([key, value]) => [key, String(value)]),
345-
),
346-
),
347-
'Text',
348-
1,
349-
)
378+
segs.map(async (seg, idx) => {
379+
const props = propsArray[idx]
380+
if (segs.length > 1 && mainColor === props.color) delete props.color
381+
if (segs.length > 1 && mainTypography === props.typography)
382+
delete props.typography
350383
let text = fixChildrenText(seg.characters)
351384
let textComponent: 'ul' | 'ol' | null = null
352385
const textDep = segs.length > 1 ? dep + 2 : dep + 1
353386

387+
const propsStr = Object.entries(props)
388+
.map(([key, value]) => `${key}="${value}"`)
389+
.join(' ')
390+
const pureText = segs.length > 1 && !propsStr
391+
354392
if (seg.listOptions.type === 'NONE') {
355-
text = space(textDep) + text.replaceAll('\n', '<br />')
393+
text =
394+
space(pureText ? textDep - 1 : textDep) +
395+
text.replaceAll('\n', '<br />')
356396
} else {
357397
switch (seg.listOptions.type) {
358398
case 'UNORDERED': {
@@ -369,18 +409,29 @@ export class Element {
369409
.map((line) => `${space(textDep)}<li>${line}</li>`)
370410
.join('\n')
371411
}
412+
if (pureText) return text
372413

373414
return `${segs.length > 1 ? space(textDep - 1) : ''}<Text${
374415
textComponent ? ` as="${textComponent}" my="0px" pl="1.5em"` : ''
375-
} ${Object.entries(props)
376-
.map(([key, value]) => `${key}="${value}"`)
377-
.join(' ')}>\n${text}\n${space(textDep - 1)}</Text>`
416+
} ${propsStr}>\n${text}\n${space(textDep - 1)}</Text>`
378417
}),
379418
)
380419
).join('\n')
420+
421+
const propsStr = Object.entries(
422+
organizeProps({
423+
color: mainColor,
424+
typography: mainTypography,
425+
}),
426+
)
427+
.map(([key, value]) => `${key}="${value}"`)
428+
.join(' ')
429+
381430
return (
382431
space(dep) +
383-
(segs.length > 1 ? `<>\n${children}\n${space(dep)}</>` : children)
432+
(segs.length > 1
433+
? `<Text${propsStr ? ' ' + propsStr : ''}>\n${children}\n${space(dep)}</Text>`
434+
: children)
384435
)
385436
}
386437

src/__tests__/Element.test.ts

Lines changed: 210 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,7 @@ describe('Element', () => {
994994
})
995995
expect(await element.getComponentType()).toEqual('Text')
996996
expect(await element.render()).toEqual(
997-
'<>\n <Text fontFamily="Roboto" fontStyle="italic" fontWeight="400" fontSize="16px" textTransform="upper" lineHeight="20px" letterSpacing="20px">\n a\n </Text>\n <Text fontFamily="Roboto" fontStyle="italic" fontWeight="700" fontSize="16px" textTransform="upper" lineHeight="20px" letterSpacing="20px">\n b\n </Text>\n</>',
997+
'<Text>\n <Text fontFamily="Roboto" fontStyle="italic" fontWeight="400" fontSize="16px" textTransform="upper" lineHeight="20px" letterSpacing="20px">\n a\n </Text>\n <Text fontFamily="Roboto" fontStyle="italic" fontWeight="700" fontSize="16px" textTransform="upper" lineHeight="20px" letterSpacing="20px">\n b\n </Text>\n</Text>',
998998
)
999999
})
10001000
it('should render Text with list', async () => {
@@ -1067,6 +1067,215 @@ describe('Element', () => {
10671067
)
10681068
}
10691069
})
1070+
it('should render many Text with typography and color', async () => {
1071+
const getStyleByIdAsync = vi
1072+
.fn()
1073+
.mockResolvedValueOnce({
1074+
fontName: {
1075+
family: 'Roboto',
1076+
style: 'Italic',
1077+
},
1078+
name: 'button-title',
1079+
})
1080+
.mockResolvedValueOnce({
1081+
fontName: {
1082+
family: 'Roboto',
1083+
style: 'Bold',
1084+
},
1085+
name: 'button-title-2',
1086+
})
1087+
.mockResolvedValue({
1088+
fontName: {
1089+
family: 'Roboto',
1090+
style: 'Italic',
1091+
},
1092+
name: 'button-title',
1093+
})
1094+
1095+
const getVariableByIdAsync = vi.fn().mockResolvedValueOnce({
1096+
name: 'red',
1097+
})
1098+
1099+
;(globalThis as any).figma = {
1100+
getStyleByIdAsync,
1101+
variables: {
1102+
getVariableByIdAsync,
1103+
},
1104+
util: {
1105+
rgba: (color: RGBA) => {
1106+
return {
1107+
r: color.r,
1108+
g: color.g,
1109+
b: color.b,
1110+
a: color.a ?? 1,
1111+
}
1112+
},
1113+
},
1114+
}
1115+
const element = createElement('TEXT', {
1116+
characters: 'a',
1117+
'font-family': 'Roboto',
1118+
'font-style': 'Italic',
1119+
'font-weight': '400',
1120+
'font-size': '16px',
1121+
textStyleId: '1',
1122+
styledTextSegments: [
1123+
{
1124+
characters: 'a ',
1125+
start: 0,
1126+
end: 1,
1127+
textStyleId: '1',
1128+
fontName: {
1129+
family: 'Roboto',
1130+
style: 'Italic',
1131+
},
1132+
textDecoration: 'NONE',
1133+
textCase: 'ORIGINAL',
1134+
letterSpacing: {
1135+
value: 20,
1136+
unit: 'PIXELS',
1137+
},
1138+
lineHeight: {
1139+
value: 20,
1140+
unit: 'PIXELS',
1141+
},
1142+
fontSize: 16,
1143+
listOptions: {
1144+
type: 'NONE',
1145+
},
1146+
fills: [
1147+
{
1148+
type: 'SOLID',
1149+
color: {
1150+
r: 1,
1151+
g: 0,
1152+
b: 0,
1153+
a: 1,
1154+
},
1155+
visible: true,
1156+
},
1157+
],
1158+
},
1159+
{
1160+
textStyleId: '2',
1161+
characters: 'b',
1162+
start: 0,
1163+
end: 1,
1164+
fontName: {
1165+
family: 'Roboto',
1166+
style: 'Bold',
1167+
},
1168+
textDecoration: 'NONE',
1169+
textCase: 'ORIGINAL',
1170+
letterSpacing: {
1171+
value: 20,
1172+
unit: 'PIXELS',
1173+
},
1174+
lineHeight: {
1175+
value: 20,
1176+
unit: 'PIXELS',
1177+
},
1178+
fontSize: 16,
1179+
listOptions: {
1180+
type: 'NONE',
1181+
},
1182+
fills: [
1183+
{
1184+
type: 'SOLID',
1185+
color: {
1186+
r: 1,
1187+
g: 1,
1188+
b: 1,
1189+
a: 1,
1190+
},
1191+
visible: true,
1192+
},
1193+
],
1194+
},
1195+
{
1196+
textStyleId: '1',
1197+
characters: ' c',
1198+
start: 0,
1199+
end: 1,
1200+
fontName: {
1201+
family: 'Roboto',
1202+
style: 'Italic',
1203+
},
1204+
textDecoration: 'NONE',
1205+
textCase: 'ORIGINAL',
1206+
letterSpacing: {
1207+
value: 20,
1208+
unit: 'PIXELS',
1209+
},
1210+
lineHeight: {
1211+
value: 20,
1212+
unit: 'PIXELS',
1213+
},
1214+
fontSize: 16,
1215+
listOptions: {
1216+
type: 'NONE',
1217+
},
1218+
fills: [
1219+
{
1220+
type: 'SOLID',
1221+
color: {
1222+
r: 1,
1223+
g: 0,
1224+
b: 0,
1225+
a: 1,
1226+
},
1227+
visible: true,
1228+
},
1229+
],
1230+
},
1231+
{
1232+
textStyleId: '1',
1233+
characters: ' d ',
1234+
start: 0,
1235+
end: 1,
1236+
fontName: {
1237+
family: 'Roboto',
1238+
style: 'Italic',
1239+
},
1240+
textDecoration: 'NONE',
1241+
textCase: 'ORIGINAL',
1242+
letterSpacing: {
1243+
value: 20,
1244+
unit: 'PIXELS',
1245+
},
1246+
lineHeight: {
1247+
value: 20,
1248+
unit: 'PIXELS',
1249+
},
1250+
fontSize: 16,
1251+
listOptions: {
1252+
type: 'NONE',
1253+
},
1254+
fills: [
1255+
{
1256+
type: 'SOLID',
1257+
color: {
1258+
r: 1,
1259+
g: 0,
1260+
b: 0,
1261+
a: 1,
1262+
},
1263+
boundVariables: {
1264+
color: {
1265+
id: '1',
1266+
},
1267+
},
1268+
visible: true,
1269+
},
1270+
],
1271+
},
1272+
],
1273+
})
1274+
expect(await element.getComponentType()).toEqual('Text')
1275+
expect(await element.render()).toEqual(
1276+
'<Text color="#FF0000" typography="buttonTitle">\n a{" "}\n <Text color="#FFFFFF" typography="buttonTitle2">\n b\n </Text>\n {" "}c\n <Text color="$red">\n {" "}d{" "}\n </Text>\n</Text>',
1277+
)
1278+
})
10701279
})
10711280
describe('Flex', () => {
10721281
it('should render Flex', async () => {

src/__tests__/utils.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ describe('formatSvg', () => {
236236

237237
describe('fixChildrenText', () => {
238238
it.each([
239+
['aa', 'aa'],
240+
[' aa', '{" "}aa'],
241+
['aa ', 'aa{" "}'],
242+
[' aa ', '{" "}aa{" "}'],
243+
[' aa ', '{" "}aa{" "}'],
239244
['{', '{"{"}'],
240245
['}', '{"}"}'],
241246
['&', '{"&"}'],

0 commit comments

Comments
 (0)