style-dictionary 3.7.0 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/examples/advanced/assets-base64-embed/package.json +1 -1
- package/examples/advanced/auto-rebuild-watcher/package.json +1 -1
- package/examples/advanced/component-cti/package.json +1 -1
- package/examples/advanced/create-react-app/package.json +1 -1
- package/examples/advanced/create-react-native-app/package.json +1 -1
- package/examples/advanced/custom-file-header/package.json +1 -1
- package/examples/advanced/custom-filters/package.json +1 -1
- package/examples/advanced/custom-formats-with-templates/package.json +1 -1
- package/examples/advanced/custom-parser/package.json +1 -1
- package/examples/advanced/custom-transforms/package.json +1 -1
- package/examples/advanced/font-face-rules/README.md +71 -0
- package/examples/advanced/font-face-rules/package.json +13 -0
- package/examples/advanced/font-face-rules/sd.config.js +102 -0
- package/examples/advanced/font-face-rules/tokens.json +28 -0
- package/examples/advanced/format-helpers/package.json +1 -1
- package/examples/advanced/matching-build-files/package.json +1 -1
- package/examples/advanced/multi-brand-multi-platform/package.json +1 -1
- package/examples/advanced/node-modules-as-config-and-properties/package.json +1 -1
- package/examples/advanced/npm-module/package.json +1 -1
- package/examples/advanced/referencing_aliasing/package.json +1 -1
- package/examples/advanced/s3/package.json +1 -1
- package/examples/advanced/tokens-deprecation/package.json +1 -1
- package/examples/advanced/transitive-transforms/package.json +1 -1
- package/examples/advanced/transitive-transforms/tokens/color/font.json5 +2 -1
- package/examples/advanced/variables-in-outputs/package.json +1 -1
- package/examples/advanced/yaml-tokens/package.json +1 -1
- package/lib/common/formatHelpers/formattedVariables.js +5 -1
- package/lib/common/formatHelpers/getTypeScriptType.js +2 -2
- package/lib/common/formatHelpers/sortByReference.js +7 -0
- package/lib/common/transforms.js +2 -2
- package/lib/utils/references/getReferences.js +6 -5
- package/lib/utils/resolveObject.js +15 -7
- package/package.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
## Generating @font-face rules
|
|
2
|
+
|
|
3
|
+
To generate `@font-face` rules, we will need a few moving parts (described below). The final output will look like:
|
|
4
|
+
|
|
5
|
+
```css
|
|
6
|
+
/** build/css/fonts.css */
|
|
7
|
+
@font-face {
|
|
8
|
+
font-family: "Roboto";
|
|
9
|
+
font-style: normal;
|
|
10
|
+
font-weight: 400;
|
|
11
|
+
src: url("../fonts/Roboto.woff2") format("woff2"),
|
|
12
|
+
url("../fonts/Roboto.woff") format("woff");
|
|
13
|
+
font-display: fallback;
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```scss
|
|
18
|
+
// build/scss/_fonts.scss
|
|
19
|
+
@font-face {
|
|
20
|
+
font-family: "Roboto";
|
|
21
|
+
font-style: normal;
|
|
22
|
+
font-weight: 400;
|
|
23
|
+
src: url("#{$font-path}/fonts/Roboto.woff2") format("woff2"),
|
|
24
|
+
url("#{$font-path}/fonts/Roboto.woff") format("woff");
|
|
25
|
+
font-display: fallback;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
#### Running the example
|
|
30
|
+
|
|
31
|
+
Set up the required dependencies by running the command `npm install` in your local CLI environment (if you prefer to use _yarn_, update the commands accordingly).
|
|
32
|
+
|
|
33
|
+
At this point, if you want to build the tokens you can run `npm run build`. This command will generate the files in the `build` folder.
|
|
34
|
+
|
|
35
|
+
Note, running this example will generate a "While building fonts.css, token collisions were found; output may be unexpected." warning. The warning is expected and can be ignored.
|
|
36
|
+
|
|
37
|
+
#### How does it work
|
|
38
|
+
|
|
39
|
+
- Each font is defined using a specific structure:
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"asset": {
|
|
43
|
+
"font": {
|
|
44
|
+
"<family>": {
|
|
45
|
+
"<weight>": {
|
|
46
|
+
"<style>": {
|
|
47
|
+
"value": "<path>",
|
|
48
|
+
"formats": ["<list of formats, e.g. woff2, woff>"]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
- A custom _transform_ will promote the family name, weight and style to their own named attributes on the token object.
|
|
57
|
+
- A custom _format_ will generate the `@font-face` rules.
|
|
58
|
+
- A _platform_ ties it all together.
|
|
59
|
+
|
|
60
|
+
#### What to look at
|
|
61
|
+
|
|
62
|
+
Open `tokens.json`:
|
|
63
|
+
|
|
64
|
+
- To distinguish font-face tokens from other font tokens, the "**asset**" category is used.
|
|
65
|
+
- Each font-face token is structured so that the font's _family name_, _weight_ (400, 700, etc.), and _style_ (normal or italics) can be determined at runtime.
|
|
66
|
+
|
|
67
|
+
Compare this example's `tokens.json` to the generated files `css/fonts.css`, and `scss/_fonts.scss`.
|
|
68
|
+
|
|
69
|
+
Next up, open `sd.config.js` to see how the "css-font-face" and "scss-font-face" platforms are configured. Note the `transforms`, `format`, `filter`, and the custom `options.fontPathPrefix` properties.
|
|
70
|
+
|
|
71
|
+
Lastly, in the same file, check out the code for the `attribute/font` transform, and `font-face` format.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "font-face-rules",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Example showing one way to generate @font-face rules",
|
|
5
|
+
"main": "sd.config.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "style-dictionary build --config ./sd.config.js"
|
|
8
|
+
},
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"style-dictionary": "3.7.1"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const StyleDictionary = require('style-dictionary');
|
|
2
|
+
|
|
3
|
+
// Register an "attribute" transform to codify the font's details
|
|
4
|
+
// as named attributes.
|
|
5
|
+
StyleDictionary.registerTransform({
|
|
6
|
+
name: 'attribute/font',
|
|
7
|
+
type: 'attribute',
|
|
8
|
+
transformer: prop => ({
|
|
9
|
+
category: prop.path[0],
|
|
10
|
+
type: prop.path[1],
|
|
11
|
+
family: prop.path[2],
|
|
12
|
+
weight: prop.path[3],
|
|
13
|
+
style: prop.path[4]
|
|
14
|
+
})
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Register a custom format to generate @font-face rules.
|
|
18
|
+
StyleDictionary.registerFormat({
|
|
19
|
+
name: 'font-face',
|
|
20
|
+
formatter: ({ dictionary: { allTokens }, options }) => {
|
|
21
|
+
const fontPathPrefix = options.fontPathPrefix || '../';
|
|
22
|
+
|
|
23
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src
|
|
24
|
+
const formatsMap = {
|
|
25
|
+
'woff2': 'woff2',
|
|
26
|
+
'woff': 'woff',
|
|
27
|
+
'ttf': 'truetype',
|
|
28
|
+
'otf': 'opentype',
|
|
29
|
+
'svg': 'svg',
|
|
30
|
+
'eot': 'embedded-opentype'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return allTokens.reduce((fontList, prop) => {
|
|
34
|
+
const {
|
|
35
|
+
attributes: { family, weight, style },
|
|
36
|
+
formats,
|
|
37
|
+
value: path
|
|
38
|
+
} = prop;
|
|
39
|
+
|
|
40
|
+
const urls = formats
|
|
41
|
+
.map(extension => `url("${fontPathPrefix}${path}.${extension}") format("${formatsMap[extension]}")`);
|
|
42
|
+
|
|
43
|
+
const fontCss = [
|
|
44
|
+
'@font-face {',
|
|
45
|
+
`\n\tfont-family: "${family}";`,
|
|
46
|
+
`\n\tfont-style: ${style};`,
|
|
47
|
+
`\n\tfont-weight: ${weight};`,
|
|
48
|
+
`\n\tsrc: ${urls.join(',\n\t\t\t ')};`,
|
|
49
|
+
'\n\tfont-display: fallback;',
|
|
50
|
+
'\n}\n'
|
|
51
|
+
].join('');
|
|
52
|
+
|
|
53
|
+
fontList.push(fontCss);
|
|
54
|
+
|
|
55
|
+
return fontList;
|
|
56
|
+
}, []).join('\n');
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
source: ['tokens.json'],
|
|
62
|
+
platforms: {
|
|
63
|
+
'css-font-face': {
|
|
64
|
+
transforms: ['attribute/font'],
|
|
65
|
+
buildPath: 'build/css/',
|
|
66
|
+
files: [
|
|
67
|
+
{
|
|
68
|
+
destination: 'fonts.css',
|
|
69
|
+
format: 'font-face',
|
|
70
|
+
filter: {
|
|
71
|
+
attributes: {
|
|
72
|
+
category: 'asset',
|
|
73
|
+
type: 'font'
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
options: {
|
|
77
|
+
fontPathPrefix: '../'
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
'scss-font-face': {
|
|
83
|
+
transforms: ['attribute/font'],
|
|
84
|
+
buildPath: 'build/scss/',
|
|
85
|
+
files: [
|
|
86
|
+
{
|
|
87
|
+
destination: '_fonts.scss',
|
|
88
|
+
format: 'font-face',
|
|
89
|
+
filter: {
|
|
90
|
+
attributes: {
|
|
91
|
+
category: 'asset',
|
|
92
|
+
type: 'font'
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
options: {
|
|
96
|
+
fontPathPrefix: '#{$font-path}/'
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"asset": {
|
|
3
|
+
"font": {
|
|
4
|
+
"Roboto": {
|
|
5
|
+
"400": {
|
|
6
|
+
"normal": {
|
|
7
|
+
"value": "fonts/roboto-V20-latin-regular",
|
|
8
|
+
"formats": ["woff2", "woff"]
|
|
9
|
+
},
|
|
10
|
+
"italic": {
|
|
11
|
+
"value": "fonts/roboto-V20-latin-italic",
|
|
12
|
+
"formats": ["woff2", "woff"]
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"700": {
|
|
16
|
+
"normal": {
|
|
17
|
+
"value": "fonts/roboto-V20-latin-700",
|
|
18
|
+
"formats": ["woff2", "woff"]
|
|
19
|
+
},
|
|
20
|
+
"italic": {
|
|
21
|
+
"value": "fonts/roboto-V20-latin-700italic",
|
|
22
|
+
"formats": ["woff2", "woff"]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
},
|
|
14
14
|
tertiary: {
|
|
15
15
|
// transitive transforms allow you to modify a modified reference
|
|
16
|
-
|
|
16
|
+
// You can use references with or without `.value`
|
|
17
|
+
value: "{color.font.secondary}",
|
|
17
18
|
modify: [{
|
|
18
19
|
// this will brighten the secondary value, which is a brightened version
|
|
19
20
|
// of primary
|
|
@@ -34,7 +34,11 @@ const defaultFormatting = {
|
|
|
34
34
|
* StyleDictionary.registerFormat({
|
|
35
35
|
* name: 'myCustomFormat',
|
|
36
36
|
* formatter: function({ dictionary, options }) {
|
|
37
|
-
* return formattedVariables(
|
|
37
|
+
* return formattedVariables({
|
|
38
|
+
* format: 'less',
|
|
39
|
+
* dictionary,
|
|
40
|
+
* outputReferences: options.outputReferences
|
|
41
|
+
* });
|
|
38
42
|
* }
|
|
39
43
|
* });
|
|
40
44
|
* ```
|
|
@@ -30,10 +30,10 @@ const { unique } = require('../../utils/es6_');
|
|
|
30
30
|
* }).join('\n');
|
|
31
31
|
* }
|
|
32
32
|
* });
|
|
33
|
-
|
|
33
|
+
*```
|
|
34
34
|
* @param {*} value A value to check the type of.
|
|
35
35
|
* @return {String} A valid name for a TypeScript type.
|
|
36
|
-
*
|
|
36
|
+
*
|
|
37
37
|
*/
|
|
38
38
|
function getTypeScriptType(value) {
|
|
39
39
|
if (Array.isArray(value)) return getArrayType(value)
|
|
@@ -30,6 +30,13 @@
|
|
|
30
30
|
const aComesFirst = -1;
|
|
31
31
|
const bComesFirst = 1;
|
|
32
32
|
|
|
33
|
+
// return early if a or b ar undefined
|
|
34
|
+
if (typeof a === 'undefined') {
|
|
35
|
+
return aComesFirst;
|
|
36
|
+
} else if (typeof b === 'undefined') {
|
|
37
|
+
return bComesFirst;
|
|
38
|
+
}
|
|
39
|
+
|
|
33
40
|
// If token a uses a reference and token b doesn't, b might come before a
|
|
34
41
|
// read on..
|
|
35
42
|
if (a.original && dictionary.usesReference(a.original.value)) {
|
package/lib/common/transforms.js
CHANGED
|
@@ -629,7 +629,7 @@ module.exports = {
|
|
|
629
629
|
},
|
|
630
630
|
|
|
631
631
|
/**
|
|
632
|
-
* Transforms the value from a REM size on web into a scale-independent pixel (sp) value for font sizes on Android. It WILL scale the number by a factor of 16 (
|
|
632
|
+
* Transforms the value from a REM size on web into a scale-independent pixel (sp) value for font sizes on Android. It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
|
|
633
633
|
*
|
|
634
634
|
* ```js
|
|
635
635
|
* // Matches: token.attributes.category === 'size' && token.attributes.type === 'font'
|
|
@@ -739,7 +739,7 @@ module.exports = {
|
|
|
739
739
|
},
|
|
740
740
|
|
|
741
741
|
/**
|
|
742
|
-
* Transforms the value from a REM size on web into a scale-independent pixel (sp) value for font sizes in Compose. It WILL scale the number by a factor of 16 (
|
|
742
|
+
* Transforms the value from a REM size on web into a scale-independent pixel (sp) value for font sizes in Compose. It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
|
|
743
743
|
*
|
|
744
744
|
* ```kotlin
|
|
745
745
|
* // Matches: prop.attributes.category === 'size' && prop.attributes.type === 'font'
|
|
@@ -28,16 +28,13 @@ const GroupMessages = require('../groupMessages');
|
|
|
28
28
|
*
|
|
29
29
|
* @memberof Dictionary
|
|
30
30
|
* @param {string} value the value that contains a reference
|
|
31
|
+
* @param {object[]} references array of token's references because a token's value can contain multiple references due to string interpolation
|
|
31
32
|
* @returns {any}
|
|
32
33
|
*/
|
|
33
|
-
function getReferences(value) {
|
|
34
|
+
function getReferences(value, references=[]) {
|
|
34
35
|
// `this` is the dictionary object passed to formats and actions
|
|
35
36
|
const self = this;
|
|
36
37
|
const regex = createReferenceRegex({});
|
|
37
|
-
// because a token's value can contain multiple references due to string interpolation
|
|
38
|
-
// "{size.padding.base.value} {color.border.primary.value}"
|
|
39
|
-
// references is an array of 0 or more references
|
|
40
|
-
const references = [];
|
|
41
38
|
|
|
42
39
|
// this will update the references array with the referenced tokens it finds.
|
|
43
40
|
function findReference(match, variable) {
|
|
@@ -70,6 +67,10 @@ function getReferences(value) {
|
|
|
70
67
|
if (value.hasOwnProperty(key) && typeof value[key] === 'string') {
|
|
71
68
|
value[key].replace(regex, findReference);
|
|
72
69
|
}
|
|
70
|
+
// if it is an object, we go further down the rabbit hole
|
|
71
|
+
if (value.hasOwnProperty(key) && typeof value[key] === 'object') {
|
|
72
|
+
self.getReferences(value[key], references);
|
|
73
|
+
}
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
@@ -85,16 +85,20 @@ function compile_value(value, stack) {
|
|
|
85
85
|
// references can be part of the value such as "1px solid {color.border.light}"
|
|
86
86
|
value.replace(regex, function(match, variable) {
|
|
87
87
|
variable = variable.trim();
|
|
88
|
-
if (options.ignorePaths.indexOf(variable) !== -1) {
|
|
89
|
-
return value;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
stack.push(variable);
|
|
93
88
|
|
|
94
89
|
// Find what the value is referencing
|
|
95
90
|
const pathName = getPath(variable, options);
|
|
96
91
|
const context = getName(current_context, options);
|
|
97
92
|
const refHasValue = pathName[pathName.length-1] === 'value';
|
|
93
|
+
|
|
94
|
+
if (refHasValue && options.ignorePaths.indexOf(variable) !== -1) {
|
|
95
|
+
return value;
|
|
96
|
+
} else if (!refHasValue && options.ignorePaths.indexOf(`${variable}.value`) !== -1) {
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
stack.push(variable);
|
|
101
|
+
|
|
98
102
|
ref = resolveReference(pathName, updated_object);
|
|
99
103
|
|
|
100
104
|
// If the reference doesn't end in 'value'
|
|
@@ -108,7 +112,7 @@ function compile_value(value, stack) {
|
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
if (typeof ref !== 'undefined') {
|
|
111
|
-
if (typeof ref === 'string') {
|
|
115
|
+
if (typeof ref === 'string' || typeof ref === 'number') {
|
|
112
116
|
to_ret = value.replace(match, ref);
|
|
113
117
|
|
|
114
118
|
// Recursive, therefore we can compute multi-layer variables like a = b, b = c, eventually a = c
|
|
@@ -145,8 +149,12 @@ function compile_value(value, stack) {
|
|
|
145
149
|
to_ret = compile_value( to_ret, stack );
|
|
146
150
|
}
|
|
147
151
|
}
|
|
152
|
+
// if evaluated value is a number and equal to the reference, we want to keep the type
|
|
153
|
+
if (typeof ref === 'number' && ref.toString() === to_ret) {
|
|
154
|
+
to_ret = ref;
|
|
155
|
+
}
|
|
148
156
|
} else {
|
|
149
|
-
// if evaluated value is not a string, we want to keep the type
|
|
157
|
+
// if evaluated value is not a string or number, we want to keep the type
|
|
150
158
|
to_ret = ref;
|
|
151
159
|
}
|
|
152
160
|
} else {
|