Skip to content
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

Add container query support #807

Merged
merged 14 commits into from
Sep 5, 2022
5 changes: 5 additions & 0 deletions .changeset/rare-numbers-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@vanilla-extract/babel-plugin': minor
---

Add support for the new `createContainer` API
28 changes: 28 additions & 0 deletions .changeset/real-cherries-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
'@vanilla-extract/css': minor
---

Add `createContainer` API

`createContainer` creates a single scoped container name for use with CSS Container Queries. This avoids potential naming collisions with other containers.

```ts
import {
style,
createContainer
} from '@vanilla-extract/css';

export const sidebarContainer = createContainer();

export const sidebar = style({
containerName: sidebarContainer
});

export const navigation = style({
'@container': {
[`${sidebarContainer} (min-width: 400px)`]: {
display: 'flex'
}
}
});
```
17 changes: 17 additions & 0 deletions .changeset/tiny-shirts-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@vanilla-extract/css': minor
---

Add support for container queries via the new `@container` key.

```ts
import { style } from '@vanilla-extract/css';

export const myStyle = style({
'@container': {
'(min-width: 400px)': {
display: 'flex'
}
}
});
```
4 changes: 3 additions & 1 deletion fixtures/low-level/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { block } from './styles.css';
import { block, container } from './styles.css';
import testNodes from '../test-nodes.json';

document.body.innerHTML = `
<div class="${container}">
<div id="${testNodes.block}" class="${block}">
I'm a block
</div>
</div>
`;
20 changes: 18 additions & 2 deletions fixtures/low-level/src/styles.css.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import { style, createVar } from '@vanilla-extract/css';
import { style, createVar, createContainer } from '@vanilla-extract/css';

const color = createVar();

const myContainer = createContainer('my-container');

export const container = style({
containerType: 'size',
containerName: myContainer,
width: 500,
});

export const block = style({
vars: {
[color]: 'blue',
},
backgroundColor: color,
color: 'white',
padding: 20,
'@media': {
'screen and (min-width: 200px)': {
'@container': {
[`${myContainer} (min-width: 400px)`]: {
color: 'white',
},
},
},
},
});
19 changes: 19 additions & 0 deletions packages/babel-plugin/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,25 @@ describe('babel plugin', () => {
`);
});

it('should handle createContainer assigned to const', () => {
const source = `
import { createContainer } from '@vanilla-extract/css';

const myContainer = createContainer();
`;

expect(transform(source)).toMatchInlineSnapshot(`
"import * as __vanilla_filescope__ from '@vanilla-extract/css/fileScope';

__vanilla_filescope__.setFileScope(\\"src/dir/mockFilename.css.ts\\", \\"@vanilla-extract/babel-plugin\\");

import { createContainer } from '@vanilla-extract/css';
const myContainer = createContainer(\\"myContainer\\");

__vanilla_filescope__.endFileScope();"
`);
});

it('should handle fontFace assigned to const', () => {
const source = `
import { fontFace } from '@vanilla-extract/css';
Expand Down
3 changes: 3 additions & 0 deletions packages/babel-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const debuggableFunctionConfig = {
recipe: {
maxParams: 2,
},
createContainer: {
maxParams: 1,
},
};

const styleFunctions = [
Expand Down
6 changes: 6 additions & 0 deletions packages/css/src/container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { generateIdentifier } from './identifier';

// createContainer is used for local scoping of CSS containers
// For now it is mostly just an alias of generateIdentifier
mattcompiles marked this conversation as resolved.
Show resolved Hide resolved
export const createContainer = (debugId?: string) =>
generateIdentifier(debugId);
1 change: 1 addition & 0 deletions packages/css/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from './identifier';
export * from './theme';
export * from './style';
export * from './vars';
export { createContainer } from './container';
78 changes: 76 additions & 2 deletions packages/css/src/transformCss.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,41 @@ describe('transformCss', () => {
`);
});

it('should handle nested @supports and @media queries', () => {
it('should handle @container queries', () => {
expect(
transformCss({
composedClassLists: [],
localClassNames: ['testClass'],
cssObjs: [
{
type: 'local',
selector: 'testClass',
rule: {
display: 'flex',
containerName: 'sidebar',
'@container': {
'sidebar (min-width: 700px)': {
display: 'grid',
},
},
},
},
],
}).join('\n'),
).toMatchInlineSnapshot(`
".testClass {
display: flex;
container-name: sidebar;
}
@container sidebar (min-width: 700px) {
.testClass {
display: grid;
}
}"
`);
});

it('should handle nested @supports, @media and @container queries', () => {
expect(
transformCss({
composedClassLists: [],
Expand All @@ -978,16 +1012,27 @@ describe('transformCss', () => {
'@media': {
'screen and (min-width: 700px)': {
display: 'grid',
'@container': {
'sidebar (min-width: 700px)': {
display: 'grid',
},
},
},
},
},
},

'@media': {
'screen and (min-width: 700px)': {
color: 'green',
'@supports': {
'(display: grid)': {
borderColor: 'blue',
'@container': {
'sidebar (min-width: 700px)': {
display: 'grid',
},
},
},
},
},
Expand All @@ -1008,6 +1053,11 @@ describe('transformCss', () => {
.testClass {
border-color: blue;
}
@container sidebar (min-width: 700px) {
.testClass {
display: grid;
}
}
}
}
@supports (display: grid) {
Expand All @@ -1018,12 +1068,17 @@ describe('transformCss', () => {
.testClass {
display: grid;
}
@container sidebar (min-width: 700px) {
.testClass {
display: grid;
}
}
}
}"
`);
});

it('should merge nested @supports and @media queries', () => {
it('should merge nested @supports, @media and @container queries', () => {
expect(
transformCss({
composedClassLists: [],
Expand All @@ -1038,12 +1093,18 @@ describe('transformCss', () => {
'@supports': {
'(display: grid)': {
borderColor: 'blue',
'@container': {
'sidebar (min-width: 700px)': {
display: 'grid',
},
},
},
},
},
},
},
},

{
type: 'local',
selector: 'otherClass',
Expand All @@ -1053,6 +1114,11 @@ describe('transformCss', () => {
'@supports': {
'(display: grid)': {
backgroundColor: 'yellow',
'@container': {
'sidebar (min-width: 700px)': {
display: 'grid',
},
},
},
},
},
Expand All @@ -1070,6 +1136,14 @@ describe('transformCss', () => {
.otherClass {
background-color: yellow;
}
@container sidebar (min-width: 700px) {
.testClass {
display: grid;
}
.otherClass {
display: grid;
}
}
}
}"
`);
Expand Down
Loading