Skip to content

Commit 58e4f8a

Browse files
authored
Add Sprinkles (#53)
1 parent 2d98bcc commit 58e4f8a

File tree

24 files changed

+1949
-18
lines changed

24 files changed

+1949
-18
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@vanilla-extract/esbuild-plugin': minor
3+
'@vanilla-extract/webpack-plugin': minor
4+
---
5+
6+
Support exporting functions from `.css.ts` files via recipes

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ dist
33
tsconfig.tsbuildinfo
44
yarn-error.log
55
packages/**/README.md
6+
!packages/sprinkles/README.md
7+
68

79
.yarn/*
810
!.yarn/patches

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ document.write(`
7676

7777
---
7878

79+
Want to work at a higher level while maximising style re-use? Check out 🍨 [Sprinkles](https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles), our official zero-runtime atomic CSS framework, built on top of vanilla-extract.
80+
81+
---
82+
7983
- [Setup](#setup)
8084
- [webpack](#webpack)
8185
- [esbuild](#esbuild)
@@ -115,7 +119,7 @@ There are currently a few integrations to choose from.
115119
1. Install the dependencies.
116120

117121
```bash
118-
$ yarn add --dev @vanilla-extract/css @vanilla-extract/babel-plugin @vanilla-extract/webpack-plugin
122+
$ npm install @vanilla-extract/css @vanilla-extract/babel-plugin @vanilla-extract/webpack-plugin
119123
```
120124

121125
2. Add the [Babel](https://babeljs.io) plugin.
@@ -171,7 +175,7 @@ module.exports = {
171175
1. Install the dependencies.
172176

173177
```bash
174-
$ yarn add --dev @vanilla-extract/css @vanilla-extract/esbuild-plugin
178+
$ npm install @vanilla-extract/css @vanilla-extract/esbuild-plugin
175179
```
176180

177181
2. Add the [esbuild](https://esbuild.github.io/) plugin to your build script.
@@ -620,7 +624,7 @@ export const green = composeStyles(base, style({
620624
We also provide a lightweight standalone package to support dynamic runtime theming.
621625

622626
```bash
623-
$ yarn add --dev @vanilla-extract/dynamic
627+
$ npm install @vanilla-extract/dynamic
624628
```
625629

626630
### createInlineTheme
@@ -681,7 +685,7 @@ We also provide a standalone package of optional utility functions to make it ea
681685
> 💡 This package can be used with any CSS-in-JS library.
682686
683687
```bash
684-
$ yarn add --dev @vanilla-extract/css-utils
688+
$ npm install @vanilla-extract/css-utils
685689
```
686690

687691
### calc

fixtures/sprinkles/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "@fixtures/sprinkles",
3+
"version": "0.0.0",
4+
"main": "src/index.ts",
5+
"sideEffects": true,
6+
"author": "SEEK",
7+
"private": true,
8+
"dependencies": {
9+
"@vanilla-extract/css": "0.3.2",
10+
"@vanilla-extract/sprinkles": "0.1.0"
11+
}
12+
}

fixtures/sprinkles/src/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { atoms } from './styles.css';
2+
import testNodes from '../test-nodes.json';
3+
4+
function render() {
5+
document.body.innerHTML = `
6+
<div id="${testNodes.root}" class="${atoms({
7+
display: 'block',
8+
paddingTop: {
9+
mobile: 'small',
10+
desktop: 'medium',
11+
},
12+
})}">
13+
Sprinkles
14+
</div>
15+
`;
16+
}
17+
18+
render();
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { createAtomicStyles, createAtomsFn } from '@vanilla-extract/sprinkles';
2+
3+
export const atoms = createAtomsFn(
4+
createAtomicStyles({
5+
defaultCondition: 'mobile',
6+
conditions: {
7+
mobile: {},
8+
tablet: {
9+
'@media': 'screen and (min-width: 768px)',
10+
},
11+
desktop: {
12+
'@media': 'screen and (min-width: 1024px)',
13+
},
14+
darkDesktop: {
15+
'@supports': 'not (display: grid)',
16+
'@media': 'screen and (min-width: 1024px)',
17+
selector: '[data-dark-mode] &',
18+
},
19+
},
20+
properties: {
21+
display: ['flex', 'none', 'block'],
22+
paddingTop: {
23+
small: '10px',
24+
medium: '20px',
25+
},
26+
},
27+
}),
28+
);

fixtures/sprinkles/test-nodes.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"root": "root"
3+
}

packages/esbuild-plugin/src/index.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import { build as esbuild, Plugin } from 'esbuild';
1111
import evalCode from 'eval';
1212
import { stringify } from 'javascript-stringify';
1313
import isPlainObject from 'lodash/isPlainObject';
14+
import crypto from 'crypto';
15+
16+
const hash = (value: string) =>
17+
crypto.createHash('md5').update(value).digest('hex');
1418

1519
const vanillaCssNamespace = 'vanilla-extract-css-ns';
1620

@@ -192,7 +196,7 @@ export function vanillaExtractPlugin({
192196
};
193197
}
194198

195-
const stringifyExports = (value: any) =>
199+
const stringifyExports = (recipeImports: Set<string>, value: any): any =>
196200
stringify(
197201
value,
198202
(value, _indent, next) => {
@@ -208,6 +212,37 @@ const stringifyExports = (value: any) =>
208212
return next(value);
209213
}
210214

215+
if (valueType === 'function' && value.__recipe__) {
216+
const { importPath, importName, args } = value.__recipe__;
217+
218+
if (
219+
typeof importPath !== 'string' ||
220+
typeof importName !== 'string' ||
221+
!Array.isArray(args)
222+
) {
223+
throw new Error('Invalid recipe');
224+
}
225+
226+
try {
227+
const hashedImportName = `_${hash(`${importName}${importPath}`).slice(
228+
0,
229+
5,
230+
)}`;
231+
232+
recipeImports.add(
233+
`import { ${importName} as ${hashedImportName} } from '${importPath}';`,
234+
);
235+
236+
return `${hashedImportName}(${args
237+
.map((arg) => stringifyExports(recipeImports, arg))
238+
.join(',')})`;
239+
} catch (err) {
240+
console.error(err);
241+
242+
throw new Error('Invalid recipe.');
243+
}
244+
}
245+
211246
throw new Error(dedent`
212247
Invalid exports.
213248
@@ -230,13 +265,15 @@ const serializeVanillaModule = (
230265
return `import '${request}';`;
231266
});
232267

268+
const recipeImports = new Set<string>();
269+
233270
const moduleExports = Object.keys(exports).map((key) =>
234271
key === 'default'
235-
? `export default ${stringifyExports(exports[key])};`
236-
: `export var ${key} = ${stringifyExports(exports[key])};`,
272+
? `export default ${stringifyExports(recipeImports, exports[key])};`
273+
: `export var ${key} = ${stringifyExports(recipeImports, exports[key])};`,
237274
);
238275

239-
const outputCode = [...cssImports, ...moduleExports];
276+
const outputCode = [...cssImports, ...recipeImports, ...moduleExports];
240277

241278
return outputCode.join('\n');
242279
};

0 commit comments

Comments
 (0)