forked from amzn/style-dictionary
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(examples): add tailwind preset example (amzn#1344)
Co-authored-by: Jessica Lynch <[email protected]>
- Loading branch information
Showing
17 changed files
with
410 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'style-dictionary': minor | ||
--- | ||
|
||
Add tailwind preset example, remove unused .editorconfig file |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
demo/output.css | ||
build | ||
node_modules | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# Tailwind preset | ||
|
||
Builds [Tailwind preset](https://tailwindcss.com/docs/presets#creating-a-preset) from tokens. | ||
|
||
## Building the preset | ||
|
||
Run `npm run build-tokens` to generate these files in `build/tailwind`: | ||
|
||
### cssVarPlugin.js | ||
|
||
A [Tailwind plugin](https://tailwindcss.com/docs/plugins) for registering new [base styles](https://tailwindcss.com/docs/plugins#adding-base-styles). | ||
|
||
The [rgbChannels](./config/transform.js) transform removes the color space function for compatability with [Tailwind's opacity modifier syntax](https://tailwindcss.com/docs/text-color#changing-the-opacity). | ||
|
||
```js | ||
import plugin from 'tailwindcss/plugin.js'; | ||
|
||
export default plugin(function ({ addBase }) { | ||
addBase({ | ||
':root': { | ||
'--sd-text-small': '0.75', | ||
'--sd-text-base': '46 46 70', | ||
'--sd-text-secondary': '100 100 115', | ||
'--sd-text-tertiary': '129 129 142', | ||
'--sd-text-neutral': '0 0 0 / 0.55', | ||
'--sd-theme': '31 197 191', | ||
'--sd-theme-light': '153 235 226', | ||
'--sd-theme-dark': '0 179 172', | ||
'--sd-theme-secondary': '106 80 150', | ||
'--sd-theme-secondary-dark': '63 28 119', | ||
'--sd-theme-secondary-light': '196 178 225', | ||
}, | ||
}); | ||
}); | ||
``` | ||
|
||
### themeColors.js | ||
|
||
Tailwind theme color values that reference the plugin [css vars](https://tailwindcss.com/docs/customizing-colors#using-css-variables). | ||
|
||
```js | ||
export default { | ||
'sd-text-base': 'rgb(var(--sd-text-base))', | ||
'sd-text-secondary': 'rgb(var(--sd-text-secondary))', | ||
'sd-text-tertiary': 'rgb(var(--sd-text-tertiary))', | ||
'sd-text-neutral': 'rgb(var(--sd-text-neutral))', | ||
'sd-theme': 'rgb(var(--sd-theme))', | ||
'sd-theme-light': 'rgb(var(--sd-theme-light))', | ||
'sd-theme-dark': 'rgb(var(--sd-theme-dark))', | ||
'sd-theme-secondary': 'rgb(var(--sd-theme-secondary))', | ||
'sd-theme-secondary-dark': 'rgb(var(--sd-theme-secondary-dark))', | ||
'sd-theme-secondary-light': 'rgb(var(--sd-theme-secondary-light))', | ||
}; | ||
``` | ||
|
||
### preset.js | ||
|
||
[Tailwind preset](https://tailwindcss.com/docs/presets) file that imports the colors and plugin. | ||
|
||
```js | ||
import themeColors from './themeColors.js'; | ||
import cssVarsPlugin from './cssVarsPlugin.js'; | ||
|
||
export default { | ||
theme: { | ||
extend: { | ||
colors: { | ||
...themeColors, // <-- theme colors defined here | ||
}, | ||
}, | ||
}, | ||
plugins: [cssVarsPlugin], // <-- plugin imported here | ||
}; | ||
``` | ||
|
||
## Building the CSS | ||
|
||
The [Tailwind preset](https://tailwindcss.com/docs/presets#creating-a-preset) is imported from the build directory in `tailwind.config.js`. | ||
|
||
```js | ||
import tailwindPreset from './build/tailwind/preset.js'; | ||
|
||
/** @type {import('tailwindcss').Config} */ | ||
export default { | ||
theme: { | ||
extend: {}, | ||
}, | ||
presets: [tailwindPreset], | ||
content: ['./demo/**/*.{html,js}'], | ||
plugins: [], | ||
}; | ||
``` | ||
|
||
Run `npm run build-css` to watch the `demo/index.html` file for changes -- any Tailwind classes used will be compiled into `demo/output.css`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import StyleDictionary from 'style-dictionary'; | ||
import { isColor } from './config/filter.js'; | ||
import { cssVarsPlugin, preset, themeColors } from './config/format.js'; | ||
import { rgbChannels } from './config/transform.js'; | ||
|
||
StyleDictionary.registerTransform({ | ||
name: 'color/rgb-channels', | ||
type: 'value', | ||
filter: isColor, | ||
transform: rgbChannels, | ||
}); | ||
|
||
StyleDictionary.registerTransformGroup({ | ||
name: 'tailwind', | ||
transforms: ['name/kebab', 'color/rgb', 'color/rgb-channels'], | ||
}); | ||
|
||
StyleDictionary.registerFormat({ | ||
name: 'tailwind/css-vars-plugin', | ||
format: cssVarsPlugin, | ||
}); | ||
|
||
StyleDictionary.registerFormat({ | ||
name: 'tailwind/theme-colors', | ||
format: themeColors, | ||
}); | ||
|
||
StyleDictionary.registerFormat({ | ||
name: 'tailwind/preset', | ||
format: preset, | ||
}); | ||
|
||
export default { | ||
source: ['./tokens/**/*.json'], | ||
platforms: { | ||
tailwindPreset: { | ||
buildPath: 'build/tailwind/', | ||
transformGroup: 'tailwind', | ||
files: [ | ||
{ | ||
destination: 'cssVarsPlugin.js', | ||
format: 'tailwind/css-vars-plugin', | ||
}, | ||
{ | ||
destination: 'themeColors.js', | ||
format: 'tailwind/theme-colors', | ||
}, | ||
{ | ||
destination: 'preset.js', | ||
format: 'tailwind/preset', | ||
}, | ||
], | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export function isColor(token) { | ||
return (token?.$type || token?.type) === 'color'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { expect } from 'chai'; | ||
import { describe, it } from 'mocha'; | ||
import { isColor } from './filter.js'; | ||
|
||
describe('isColor', () => { | ||
it('should handle legacy and dtcg formats', () => { | ||
expect(isColor({ type: 'color' })).to.equal(true); | ||
expect(isColor({ $type: 'color' })).to.equal(true); | ||
expect(isColor({ type: 'fontSize' })).to.equal(false); | ||
expect(isColor({ $type: 'fontSize' })).to.equal(false); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { isColor } from './filter.js'; | ||
|
||
/** | ||
* Exports tailwind plugin for declaring root CSS vars | ||
* @see https://tailwindcss.com/docs/plugins#overview | ||
*/ | ||
export function cssVarsPlugin({ dictionary }) { | ||
const vars = dictionary.allTokens | ||
.map((token) => { | ||
const value = token?.$value || token?.value; | ||
return `'--${token.name}': '${value}'`; | ||
}) | ||
.join(',\n\t\t\t'); | ||
|
||
return `import plugin from 'tailwindcss/plugin.js'; | ||
export default plugin(function ({ addBase }) { | ||
\taddBase({ | ||
\t\t':root': { | ||
\t\t\t${vars}, | ||
\t\t}, | ||
\t}); | ||
});\n`; | ||
} | ||
|
||
/** | ||
* Exports theme color definitions | ||
* @see https://tailwindcss.com/docs/customizing-colors#using-css-variables | ||
*/ | ||
export function themeColors({ dictionary, options }) { | ||
const tokens = dictionary.allTokens.filter((token) => isColor(token, options)); | ||
|
||
const theme = tokens | ||
.map((token) => { | ||
return `\t'${token.name}': 'rgb(var(--${token.name}))'`; | ||
}) | ||
.join(',\n'); | ||
|
||
return `export default {\n${theme},\n};\n`; | ||
} | ||
|
||
/** | ||
* Exports tailwind preset | ||
* @see https://tailwindcss.com/docs/presets | ||
*/ | ||
export function preset() { | ||
return `import themeColors from './themeColors.js'; | ||
import cssVarsPlugin from './cssVarsPlugin.js'; | ||
export default { | ||
\ttheme: { | ||
\t\textend: { | ||
\t\t\tcolors: { | ||
\t\t\t\t...themeColors, // <-- theme colors defined here | ||
\t\t\t}, | ||
\t\t}, | ||
\t}, | ||
\tplugins: [cssVarsPlugin], // <-- plugin imported here | ||
};\n`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
export function rgbChannels(token) { | ||
const value = token?.$value || token?.value; | ||
const { r, g, b, a } = parseRGBA(value); | ||
const hasAlpha = a !== undefined; | ||
return `${r} ${g} ${b}${hasAlpha ? ' / ' + a : ''}`; | ||
} | ||
|
||
function parseRGBA(value) { | ||
const regex = /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+%?))?\s*\)/; | ||
const matches = value.match(regex); | ||
if (!matches) { | ||
throw new Error(`Value '${value}' is not a valid rgb or rgba format.`); | ||
} | ||
const [, r, g, b, a] = matches; | ||
return { | ||
r, | ||
g, | ||
b, | ||
a: a !== undefined ? (a.endsWith('%') ? parseFloat(a) / 100 : parseFloat(a)) : undefined, | ||
}; | ||
} |
37 changes: 37 additions & 0 deletions
37
examples/advanced/tailwind-preset/config/transform.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { expect } from 'chai'; | ||
import { describe, it } from 'mocha'; | ||
import { rgbChannels } from './transform.js'; | ||
|
||
describe('rgbChannels', () => { | ||
it('should extract RGB channels from valid RGB string', () => { | ||
const tokenValue = 'rgb(255, 255, 255)'; | ||
expect(rgbChannels({ value: tokenValue })).to.equal('255 255 255'); | ||
expect(rgbChannels({ $value: tokenValue })).to.equal('255 255 255'); | ||
}); | ||
|
||
it('should extract RGB and alpha channels from valid RGBA string', () => { | ||
const tokenValue = 'rgba(255, 255, 255, 0.5)'; | ||
expect(rgbChannels({ value: tokenValue })).to.equal('255 255 255 / 0.5'); | ||
expect(rgbChannels({ $value: tokenValue })).to.equal('255 255 255 / 0.5'); | ||
}); | ||
|
||
it('should handle different whitespace variations', () => { | ||
let tokenValue = 'rgb( 123 , 45,67 )'; | ||
expect(rgbChannels({ value: tokenValue })).to.equal('123 45 67'); | ||
tokenValue = 'rgba( 12, 34 , 56 , 0.75 )'; | ||
expect(rgbChannels({ value: tokenValue })).to.equal('12 34 56 / 0.75'); | ||
}); | ||
|
||
it('should handle different alpha formats', () => { | ||
const tokenValues = ['rgb(1, 2, 3, 50%)', 'rgb(1, 2, 3, .5)', 'rgb(1, 2, 3, .50)']; | ||
for (const tokenValue of tokenValues) { | ||
expect(rgbChannels({ value: tokenValue })).to.equal('1 2 3 / 0.5'); | ||
} | ||
}); | ||
|
||
it('should throw error for invalid RGB string', () => { | ||
const expectedErr = "Value 'mock' is not a valid rgb or rgba format."; | ||
expect(() => rgbChannels({ value: 'mock' })).to.throw(expectedErr); | ||
expect(() => rgbChannels({ $value: 'mock' })).to.throw(expectedErr); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<!-- | ||
Run `npm run build-tokens` to generate build/preset.js. | ||
Then run `npm run build-css` to generate `output.css`. | ||
--> | ||
<link href="./output.css" rel="stylesheet" /> | ||
</head> | ||
<body> | ||
<div class="h-screen w-full bg-sd-theme-secondary/10"> | ||
<div class="p-4 grid grid-cols-1 gap-4 text-5xl"> | ||
<span class="text-sd-theme-dark">Hello tokens</span> | ||
<span class="text-sd-theme-dark/50">Hello tokens</span> | ||
<span class="text-sd-theme-dark/30">Hello tokens</span> | ||
<span class="text-sd-theme-dark/20">Hello tokens</span> | ||
<span class="text-sd-theme-secondary-dark">Hello tokens</span> | ||
<span class="text-sd-theme-secondary-dark/50">Hello tokens</span> | ||
<span class="text-sd-theme-secondary-dark/30">Hello tokens</span> | ||
<span class="text-sd-theme-secondary-dark/20">Hello tokens</span> | ||
<span class="text-sd-text-neutral">Hello tokens</span> | ||
</div> | ||
</div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "tailwind-preset", | ||
"version": "1.0.0", | ||
"description": "Builds tailwind preset from tokens", | ||
"type": "module", | ||
"scripts": { | ||
"build-tokens": "style-dictionary build --config ./config.js", | ||
"build-css": "npx tailwindcss -i ./demo/input.css -o ./demo/output.css --watch", | ||
"test": "mocha 'config/**/*test.js'" | ||
}, | ||
"license": "Apache-2.0", | ||
"devDependencies": { | ||
"style-dictionary": "^4.0.0", | ||
"tailwindcss": "^3.4.15", | ||
"mocha": "^10.2.0", | ||
"chai": "^5.1.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import tailwindPreset from './build/tailwind/preset.js'; | ||
|
||
/** @type {import('tailwindcss').Config} */ | ||
export default { | ||
theme: { | ||
extend: {}, | ||
}, | ||
presets: [tailwindPreset], | ||
content: ['./demo/**/*.{html,js}'], | ||
plugins: [], | ||
}; |
Oops, something went wrong.