Skip to content

Commit 8c4fd76

Browse files
committed
Fix prefix issue
1 parent da98eb3 commit 8c4fd76

File tree

5 files changed

+62
-10
lines changed

5 files changed

+62
-10
lines changed

src/__tests__/utils.test.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('propsToPropsWithTypography', () => {
3737
figma.getStyleByIdAsync = (id: string) =>
3838
Promise.resolve(
3939
id === 'ts-1'
40-
? ({ id: 'ts-1', name: 'Typography/Body' } as unknown as BaseStyle)
40+
? ({ id: 'ts-1', name: 'mobile/Body' } as unknown as BaseStyle)
4141
: null,
4242
) as ReturnType<typeof figma.getStyleByIdAsync>
4343

@@ -63,6 +63,45 @@ describe('propsToPropsWithTypography', () => {
6363
figma.getStyleByIdAsync = origGetStyle
6464
})
6565

66+
it('should preserve scoped (non-breakpoint) prefix in typography key', async () => {
67+
const origGetLocal = figma.getLocalTextStylesAsync
68+
const origGetStyle = figma.getStyleByIdAsync
69+
figma.getLocalTextStylesAsync = () =>
70+
Promise.resolve([{ id: 'ts-cms' } as unknown as TextStyle]) as ReturnType<
71+
typeof figma.getLocalTextStylesAsync
72+
>
73+
figma.getStyleByIdAsync = (id: string) =>
74+
Promise.resolve(
75+
id === 'ts-cms'
76+
? ({
77+
id: 'ts-cms',
78+
name: 'cms/bodyLgBold',
79+
} as unknown as BaseStyle)
80+
: null,
81+
) as ReturnType<typeof figma.getStyleByIdAsync>
82+
83+
// Async path — "cms/" is not a breakpoint, so the full name must be
84+
// converted to camelCase to match the devup.json export key.
85+
const r1 = await propsToPropsWithTypography(
86+
{ fontFamily: 'Arial', fontSize: 18 },
87+
'ts-cms',
88+
)
89+
expect(r1.typography).toBe('cmsBodyLgBold')
90+
expect(r1.fontFamily).toBeUndefined()
91+
expect(r1.fontSize).toBeUndefined()
92+
93+
// Sync fast path — same assertion via the resolved cache branch.
94+
const r2 = await propsToPropsWithTypography(
95+
{ fontFamily: 'Inter', fontSize: 20 },
96+
'ts-cms',
97+
)
98+
expect(r2.typography).toBe('cmsBodyLgBold')
99+
expect(r2.fontFamily).toBeUndefined()
100+
101+
figma.getLocalTextStylesAsync = origGetLocal
102+
figma.getStyleByIdAsync = origGetStyle
103+
})
104+
66105
it('should return early from sync path when textStyleId not in resolved set', async () => {
67106
const origGetLocal = figma.getLocalTextStylesAsync
68107
const origGetStyle = figma.getStyleByIdAsync

src/codegen/__tests__/__snapshots__/codegen.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ exports[`Codegen renders text node with TRUNCATE auto resize and fixed sizing 1`
637637
`;
638638

639639
exports[`Codegen renders text node with textStyleId and typography 1`] = `
640-
"<Text boxSize="100%" color="#F00" typography="heading">
640+
"<Text boxSize="100%" color="#F00" typography="typographyHeading">
641641
Heading
642642
</Text>"
643643
`;

src/codegen/props/effect.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { optimizeHex } from '../../utils/optimize-hex'
22
import { rgbaToHex } from '../../utils/rgba-to-hex'
3+
import { styleNameToTypography } from '../../utils/style-name-to-typography'
34
import { toCamel } from '../../utils/to-camel'
45
import { addPx } from '../utils/add-px'
56
import { getVariableByIdCached } from '../utils/variable-cache'
@@ -9,6 +10,10 @@ type BoundVars = Record<string, { id: string } | undefined> | undefined
910
/**
1011
* Resolve effectStyleId to a `$token` for the entire shadow value.
1112
* The effect style name IS the shadow token (not a color token).
13+
*
14+
* Must match the key written by export-devup.ts via styleNameToTypography,
15+
* so only breakpoint prefixes are stripped. Scoped prefixes (e.g. "cms/xyz")
16+
* stay part of the token name.
1217
*/
1318
async function _resolveEffectStyleToken(
1419
node: SceneNode,
@@ -18,9 +23,7 @@ async function _resolveEffectStyleToken(
1823
if (!styleId || typeof styleId !== 'string') return null
1924
const style = await figma.getStyleByIdAsync(styleId)
2025
if (style?.name) {
21-
// Strip responsive level prefix (e.g. "3/testShadow" → "testShadow")
22-
const parts = style.name.split('/')
23-
return `$${toCamel(parts[parts.length - 1])}`
26+
return `$${styleNameToTypography(style.name).name}`
2427
}
2528
return null
2629
}

src/codegen/props/text-shadow.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import { optimizeHex } from '../../utils/optimize-hex'
22
import { rgbaToHex } from '../../utils/rgba-to-hex'
3+
import { styleNameToTypography } from '../../utils/style-name-to-typography'
34
import { toCamel } from '../../utils/to-camel'
45
import { addPx } from '../utils/add-px'
56
import { getVariableByIdCached } from '../utils/variable-cache'
67

78
type BoundVars = Record<string, { id: string } | undefined> | undefined
89

10+
/**
11+
* Resolve effectStyleId to a `$token` for the text shadow value.
12+
*
13+
* Must match the key written by export-devup.ts via styleNameToTypography,
14+
* so only breakpoint prefixes are stripped. Scoped prefixes (e.g. "cms/xyz")
15+
* stay part of the token name.
16+
*/
917
async function _resolveEffectStyleToken(
1018
node: SceneNode,
1119
): Promise<string | null> {
@@ -14,8 +22,7 @@ async function _resolveEffectStyleToken(
1422
if (!styleId || typeof styleId !== 'string') return null
1523
const style = await figma.getStyleByIdAsync(styleId)
1624
if (style?.name) {
17-
const parts = style.name.split('/')
18-
return `$${toCamel(parts[parts.length - 1])}`
25+
return `$${styleNameToTypography(style.name).name}`
1926
}
2027
return null
2128
}

src/utils.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { toCamel } from './utils/to-camel'
1+
import { styleNameToTypography } from './utils/style-name-to-typography'
22
import { toPascal } from './utils/to-pascal'
33

44
// Cache for figma.getStyleByIdAsync() — keyed by style ID
@@ -27,8 +27,11 @@ function applyTypographyStyle(
2727
ret: Record<string, unknown>,
2828
style: BaseStyle,
2929
): void {
30-
const split = style.name.split('/')
31-
ret.typography = toCamel(split[split.length - 1])
30+
// Must match the key that export-devup.ts writes via styleNameToTypography,
31+
// otherwise `typography="..."` references miss the exported devup.json key.
32+
// Only breakpoint prefixes (mobile/tablet/desktop/{number}) are stripped;
33+
// scoped prefixes like `cms/bodyLgBold` stay intact → `cmsBodyLgBold`.
34+
ret.typography = styleNameToTypography(style.name).name
3235
delete ret.fontFamily
3336
delete ret.fontSize
3437
delete ret.fontWeight

0 commit comments

Comments
 (0)