Skip to content

Support CSS3 Variables in font family #91

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/__tests__/font.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,31 @@ it('transforms font without quotes', () => {
lineHeight: 18,
})
})

it('transforms font with css variables', () => {
expect(
transformCss([['font', 'bold italic small-caps 16px/18px var(--test)']])
).toEqual({
fontFamily: 'var(--test)',
fontSize: 16,
fontWeight: 'bold',
fontStyle: 'italic',
fontVariant: ['small-caps'],
lineHeight: 18,
})
})

it('transforms font with css variables and default value', () => {
expect(
transformCss([
['font', 'bold italic small-caps 16px/18px var(--test, arial)'],
])
).toEqual({
fontFamily: 'var(--test, arial)',
fontSize: 16,
fontWeight: 'bold',
fontStyle: 'italic',
fontVariant: ['small-caps'],
lineHeight: 18,
})
})
32 changes: 32 additions & 0 deletions src/__tests__/fontFamily.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,35 @@ it('does not transform invalid unquoted font-family', () => {
transformCss([['font-family', 'Goudy Bookletter 1911']])
).toThrow()
})

it('transforms font-family with css variable', () => {
expect(transformCss([['font-family', 'var(--test)']])).toEqual({
fontFamily: 'var(--test)',
})
})

it('transforms font-family with css variable and default value', () => {
expect(transformCss([['font-family', 'var(--test, arial)']])).toEqual({
fontFamily: 'var(--test, arial)',
})
})

it('transforms font-family with css variable and default quoted value', () => {
expect(transformCss([['font-family', "var(--test, 'arial')"]])).toEqual({
fontFamily: "var(--test, 'arial')",
})
})

it('transforms font-family with css variable and two default values', () => {
expect(transformCss([['font-family', 'var(--test, hello, world)']])).toEqual({
fontFamily: 'var(--test, hello, world)',
})
})

it('does not transform font-family with css variable and invalid default value', () => {
expect(() => transformCss([['font-family', 'var(--test,)']])).toThrow()
})

it('does not transform font-family with multiple bad css variable default values', () => {
expect(() => transformCss([['font-family', 'var(--test,,)']])).toThrow()
})
31 changes: 31 additions & 0 deletions src/tokenTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,36 @@ const matchString = node => {
.replace(/\\/g, '')
}

const matchVariable = node => {
if (
(node.type !== 'function' && node.value !== 'var') ||
node.nodes.length === 0
)
return null

const variableName = node.nodes[0].value

if (node.nodes.length === 1) {
return `var(${variableName})`
}

const defaultValues = node.nodes
.slice(1)
.filter(subnode => subnode.type !== 'div')
.map(subnode => {
if (subnode.type === 'string') {
return `'${matchString(subnode)}'`
}
return subnode.value
})

if (defaultValues.length !== (node.nodes.length - 1) / 2) {
return null
}

return `var(${variableName}, ${defaultValues.join`, `})`
}

const hexColorRe = /^(#(?:[0-9a-f]{3,4}){1,2})$/i
const cssFunctionNameRe = /^(rgba?|hsla?|hwb|lab|lch|gray|color)$/

Expand Down Expand Up @@ -68,4 +98,5 @@ export const tokens = {
STRING: matchString,
COLOR: matchColor,
LINE: regExpToken(/^(none|underline|line-through)$/i),
VARIABLE: matchVariable,
}
4 changes: 2 additions & 2 deletions src/transforms/fontFamily.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { tokens } from '../tokenTypes'

const { SPACE, IDENT, STRING } = tokens
const { SPACE, IDENT, STRING, VARIABLE } = tokens

export default tokenStream => {
let fontFamily

if (tokenStream.matches(STRING)) {
if (tokenStream.matches(STRING) || tokenStream.matches(VARIABLE)) {
fontFamily = tokenStream.lastValue
} else {
fontFamily = tokenStream.expect(IDENT)
Expand Down