Skip to content
Merged
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
81 changes: 81 additions & 0 deletions .changeset/shiny-bees-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
'@vanilla-extract/css': minor
---

Add `createGlobalThemeContract` function

Creates a contract of globally scoped variable names for themes to implement.

> 💡 This is useful if you want to make your theme contract available to non-JavaScript environments.

```ts
// themes.css.ts
import {
createGlobalThemeContract,
createGlobalTheme
} from '@vanilla-extract/css';

export const vars = createGlobalThemeContract({
color: {
brand: 'color-brand'
},
font: {
body: 'font-body'
}
});

createGlobalTheme(':root', vars, {
color: {
brand: 'blue'
},
font: {
body: 'arial'
}
});
```

You can also provide a map function as the second argument which has access to the value and the object path.

For example, you can automatically prefix all variable names.

```ts
// themes.css.ts
import {
createGlobalThemeContract,
createGlobalTheme
} from '@vanilla-extract/css';

export const vars = createGlobalThemeContract(
{
color: {
brand: 'color-brand'
},
font: {
body: 'font-body'
}
},
(value) => `prefix-${value}`
);
```

You can also use the map function to automatically generate names from the object path, joining keys with a hyphen.

```ts
// themes.css.ts
import {
createGlobalThemeContract,
createGlobalTheme
} from '@vanilla-extract/css';

export const vars = createGlobalThemeContract(
{
color: {
brand: null
},
font: {
body: null
}
},
(_value, path) => `prefix-${path.join('-')}`
);
```
77 changes: 76 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ createGlobalTheme(':root', vars, {

### createThemeContract

Creates a contract for themes to implement.
Creates a contract of locally scoped variable names for themes to implement.

**Ensure this function is called within a `.css.ts` context, otherwise variable names will be mismatched between files.**

Expand Down Expand Up @@ -623,6 +623,81 @@ export const themeB = createTheme(vars, {
});
```

### createGlobalThemeContract

Creates a contract of globally scoped variable names for themes to implement.

> 💡 This is useful if you want to make your theme contract available to non-JavaScript environments.

```ts
// themes.css.ts

import {
createGlobalThemeContract,
createGlobalTheme
} from '@vanilla-extract/css';

export const vars = createGlobalThemeContract({
color: {
brand: 'color-brand'
},
font: {
body: 'font-body'
}
});

createGlobalTheme(':root', vars, {
color: {
brand: 'blue'
},
font: {
body: 'arial'
}
});
```

You can also provide a map function as the second argument which has access to the value and the object path.

For example, you can automatically prefix all variable names.

```ts
// themes.css.ts

import {
createGlobalThemeContract,
createGlobalTheme
} from '@vanilla-extract/css';

export const vars = createGlobalThemeContract({
color: {
brand: 'color-brand'
},
font: {
body: 'font-body'
}
}, (value) => `prefix-${value}`);
```

You can also use the map function to automatically generate names from the object path, joining keys with a hyphen.

```ts
// themes.css.ts

import {
createGlobalThemeContract,
createGlobalTheme
} from '@vanilla-extract/css';

export const vars = createGlobalThemeContract({
color: {
brand: null
},
font: {
body: null
}
}, (_value, path) => `prefix-${path.join('-')}`);
```

### assignVars

Assigns a collection of CSS Variables anywhere within a style block.
Expand Down
174 changes: 173 additions & 1 deletion packages/css/src/vars.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fallbackVar } from './vars';
import { fallbackVar, createGlobalThemeContract } from './vars';

describe('fallbackVar', () => {
it('supports a single string fallback', () => {
Expand Down Expand Up @@ -67,3 +67,175 @@ describe('fallbackVar', () => {
}).toThrowErrorMatchingInlineSnapshot(`"Invalid variable name: INVALID"`);
});
});

describe('createGlobalThemeContract', () => {
it('supports defining css vars via object properties', () => {
expect(
createGlobalThemeContract({
color: {
red: 'color-red',
blue: 'color-blue',
green: 'color-green',
},
}),
).toMatchInlineSnapshot(`
Object {
"color": Object {
"blue": "var(--color-blue)",
"green": "var(--color-green)",
"red": "var(--color-red)",
},
}
`);
});

it('ignores leading double hyphen', () => {
expect(
createGlobalThemeContract({
color: {
red: '--color-red',
blue: '--color-blue',
green: '--color-green',
},
}),
).toMatchInlineSnapshot(`
Object {
"color": Object {
"blue": "var(--color-blue)",
"green": "var(--color-green)",
"red": "var(--color-red)",
},
}
`);
});

it('supports adding a prefix', () => {
expect(
createGlobalThemeContract(
{
color: {
red: 'color-red',
blue: 'color-blue',
green: 'color-green',
},
},
(value) => `prefix-${value}`,
),
).toMatchInlineSnapshot(`
Object {
"color": Object {
"blue": "var(--prefix-color-blue)",
"green": "var(--prefix-color-green)",
"red": "var(--prefix-color-red)",
},
}
`);
});

it('ignores leading double hyphen when adding a prefix', () => {
expect(
createGlobalThemeContract(
{
color: {
red: 'color-red',
blue: 'color-blue',
green: 'color-green',
},
},
(value) => `--prefix-${value}`,
),
).toMatchInlineSnapshot(`
Object {
"color": Object {
"blue": "var(--prefix-color-blue)",
"green": "var(--prefix-color-green)",
"red": "var(--prefix-color-red)",
},
}
`);
});

it('supports path based names', () => {
expect(
createGlobalThemeContract(
{
color: {
red: null,
blue: null,
green: null,
},
},
(_, path) => `prefix-${path.join('-')}`,
),
).toMatchInlineSnapshot(`
Object {
"color": Object {
"blue": "var(--prefix-color-blue)",
"green": "var(--prefix-color-green)",
"red": "var(--prefix-color-red)",
},
}
`);
});

it('errors when invalid property value', () => {
expect(() =>
createGlobalThemeContract({
color: {
// @ts-expect-error
red: null,
blue: 'color-blue',
green: 'color-green',
},
}),
).toThrowErrorMatchingInlineSnapshot(
`"Invalid variable name for \\"color.red\\": null"`,
);
});

it('errors when escaped property value', () => {
expect(() =>
createGlobalThemeContract({
color: {
red: 'color-red',
blue: "color'blue",
green: 'color-green',
},
}),
).toThrowErrorMatchingInlineSnapshot(
`"Invalid variable name for \\"color.blue\\": color'blue"`,
);
});

it('errors when property value starts with a number', () => {
expect(() =>
createGlobalThemeContract({
color: {
red: 'color-red',
blue: 'color-blue',
green: '123-color-green',
},
}),
).toThrowErrorMatchingInlineSnapshot(
`"Invalid variable name for \\"color.green\\": 123-color-green"`,
);
});

it('errors when invalid map value', () => {
expect(() =>
createGlobalThemeContract(
{
color: {
red: 'color-red',
blue: 'color-blue',
green: 'color-green',
},
},
// @ts-expect-error
() => null,
),
).toThrowErrorMatchingInlineSnapshot(
`"Invalid variable name for \\"color.red\\": null"`,
);
});
});
Loading