@digdir/designsystemet 0.1.0-alpha.6 → 0.1.0-alpha.7

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.
Files changed (30) hide show
  1. package/dist/build/src/index.js +1 -0
  2. package/dist/build/src/migrations/beta-to-v1.js +3 -1
  3. package/dist/build/src/tokens/actions.js +9 -6
  4. package/dist/build/src/tokens/build.js +28 -163
  5. package/dist/build/src/tokens/configs.js +169 -0
  6. package/dist/build/src/tokens/formats/css-classes.js +53 -0
  7. package/dist/build/src/tokens/formats/css-variables.js +17 -0
  8. package/dist/build/src/tokens/formats/{groupedTokens.js → js-tokens.js} +2 -2
  9. package/dist/build/src/tokens/transformers.js +1 -1
  10. package/dist/build/tsconfig.tsbuildinfo +1 -1
  11. package/dist/types/src/index.d.ts +2 -0
  12. package/dist/types/src/index.d.ts.map +1 -0
  13. package/dist/types/src/migrations/beta-to-v1.d.ts.map +1 -1
  14. package/dist/types/src/tokens/actions.d.ts.map +1 -1
  15. package/dist/types/src/tokens/build.d.ts.map +1 -1
  16. package/dist/types/src/tokens/configs.d.ts +21 -0
  17. package/dist/types/src/tokens/configs.d.ts.map +1 -0
  18. package/dist/types/src/tokens/formats/{typographyClasses.d.ts → css-classes.d.ts} +2 -2
  19. package/dist/types/src/tokens/formats/css-classes.d.ts.map +1 -0
  20. package/dist/types/src/tokens/formats/css-variables.d.ts +3 -0
  21. package/dist/types/src/tokens/formats/css-variables.d.ts.map +1 -0
  22. package/dist/types/src/tokens/formats/{groupedTokens.d.ts → js-tokens.d.ts} +2 -2
  23. package/dist/types/src/tokens/formats/js-tokens.d.ts.map +1 -0
  24. package/package.json +3 -3
  25. package/dist/build/src/tokens/formats/scopedReferenceVariables.js +0 -51
  26. package/dist/build/src/tokens/formats/typographyClasses.js +0 -31
  27. package/dist/types/src/tokens/formats/groupedTokens.d.ts.map +0 -1
  28. package/dist/types/src/tokens/formats/scopedReferenceVariables.d.ts +0 -6
  29. package/dist/types/src/tokens/formats/scopedReferenceVariables.d.ts.map +0 -1
  30. package/dist/types/src/tokens/formats/typographyClasses.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ export {};
@@ -3,7 +3,9 @@ import { runCssCodemod } from './codemods/css/run.js';
3
3
  export default (glob) => runCssCodemod({
4
4
  globPattern: glob,
5
5
  plugins: [
6
- cssClassRename({}),
6
+ cssClassRename({
7
+ '.fds-': '.ds-',
8
+ }),
7
9
  // New component token prefixes
8
10
  cssVarRename({
9
11
  '--fds-accordion': '--dsc-accordion',
@@ -4,14 +4,17 @@ import chalk from 'chalk';
4
4
  import * as R from 'ramda';
5
5
  export const makeEntryFile = {
6
6
  name: 'make_entryfile',
7
- do: async function (dictionary, config) {
8
- console.log(chalk.green('Creating entry file'));
9
- const { outPath, folderName } = config;
10
- const files = await glob(`**/*`, { cwd: config.buildPath });
7
+ do: async function (dictionary, platform) {
8
+ const { outPath, theme, log } = platform;
9
+ const writePath = `${outPath}/${theme}.css`;
10
+ if (log?.verbosity !== 'silent') {
11
+ console.log(chalk.green(`Creating entry file: ${writePath}`));
12
+ }
13
+ const files = await glob(`**/*`, { cwd: platform.buildPath });
11
14
  const content = R.reverse(R.sortBy(R.includes('light'), files))
12
- .map((file) => `@import url('./${folderName}/${file}');`)
15
+ .map((file) => `@import url('./${theme}/${file}');`)
13
16
  .join('\n');
14
- await fs.writeFile(`${outPath}/${folderName}.css`, content);
17
+ await fs.writeFile(writePath, content);
15
18
  },
16
19
  undo: async function noOp() { },
17
20
  };
@@ -1,190 +1,55 @@
1
1
  import path from 'path';
2
2
  import fs from 'fs';
3
- import { registerTransforms, permutateThemes } from '@tokens-studio/sd-transforms';
4
3
  import StyleDictionary from 'style-dictionary';
5
4
  import * as R from 'ramda';
6
- import { nameKebab, typographyShorthand, sizeRem } from './transformers.js';
7
- import { groupedTokens } from './formats/groupedTokens.js';
8
- import { scopedReferenceVariables } from './formats/scopedReferenceVariables.js';
9
- import { typographyClasses } from './formats/typographyClasses.js';
10
- import { makeEntryFile } from './actions.js';
11
- void registerTransforms(StyleDictionary);
12
- const prefix = 'ds';
13
- const basePxFontSize = 16;
14
- const separator = '_';
15
- const fileHeader = () => [`These files are generated from design tokens defind using Token Studio`];
16
- StyleDictionary.registerTransform(sizeRem);
17
- StyleDictionary.registerTransform(nameKebab);
18
- StyleDictionary.registerTransform(typographyShorthand);
19
- StyleDictionary.registerFormat(groupedTokens);
20
- StyleDictionary.registerFormat(scopedReferenceVariables);
21
- StyleDictionary.registerFormat(typographyClasses);
22
- StyleDictionary.registerAction(makeEntryFile);
23
- StyleDictionary.registerTransformGroup({
24
- name: 'fds/css',
25
- transforms: [
26
- `ts/resolveMath`,
27
- nameKebab.name,
28
- sizeRem.name,
29
- typographyShorthand.name,
30
- 'ts/color/modifiers',
31
- 'ts/color/css/hexrgba',
32
- 'ts/size/lineheight',
33
- 'ts/size/px',
34
- 'ts/shadow/css/shorthand',
35
- ],
36
- });
37
- const processThemeName = R.pipe(R.replace(`${separator}semantic`, ''), R.toLower, R.split(separator));
38
- const getCSSConfig = ({ fileName = 'unknown', buildPath = 'unknown', mode = 'light', outPath, folderName, }) => {
39
- return {
40
- preprocessors: ['tokens-studio'],
41
- platforms: {
42
- css: {
43
- // custom
44
- outPath,
45
- fileName,
46
- folderName,
47
- basePxFontSize,
48
- //
49
- prefix,
50
- buildPath: buildPath ?? `${outPath}/${folderName}/`,
51
- transformGroup: 'fds/css',
52
- actions: [makeEntryFile.name],
53
- files: [
54
- {
55
- destination: `${fileName}.css`,
56
- format: scopedReferenceVariables.name,
57
- },
58
- ],
59
- options: {
60
- mode,
61
- fileHeader,
62
- includeReferences: (token) => {
63
- if (R.test(/accent|neutral|brand1|brand2|brand3|success|danger|warning/, token.name) &&
64
- R.includes('semantic/color', token.filePath)) {
65
- return true;
66
- }
67
- return false;
68
- },
69
- },
70
- },
71
- },
72
- };
73
- };
74
- const getStorefrontConfig = ({ fileName = 'unknown', buildPath = 'unknown' }) => {
75
- return {
76
- preprocessors: ['tokens-studio'],
77
- platforms: {
78
- storefront: {
79
- prefix,
80
- basePxFontSize,
81
- transformGroup: 'fds/css',
82
- buildPath,
83
- files: [
84
- {
85
- destination: `${fileName}.ts`,
86
- format: groupedTokens.name,
87
- filter: (token) => {
88
- if (R.test(/accent|neutral|brand1|brand2|brand3|success|danger|warning/, token.name) ||
89
- R.includes('semantic', token.filePath)) {
90
- return true;
91
- }
92
- return false;
93
- },
94
- },
95
- ],
96
- options: {
97
- fileHeader,
98
- },
99
- },
100
- },
101
- };
102
- };
103
- const getTypographyConfig = ({ buildPath = 'unknown' }) => {
104
- return {
105
- log: { verbosity: 'verbose' },
106
- preprocessors: ['tokens-studio'],
107
- platforms: {
108
- css: {
109
- prefix,
110
- buildPath,
111
- basePxFontSize,
112
- transforms: [nameKebab.name, 'ts/size/lineheight', 'ts/size/px'],
113
- files: [
114
- {
115
- destination: 'typography.css',
116
- format: typographyClasses.name,
117
- filter: (token) => token.type === 'typography',
118
- },
119
- ],
120
- options: {
121
- fileHeader,
122
- },
123
- },
124
- },
125
- };
126
- };
5
+ import { getConfigs, cssVariablesConfig, tsTokensConfig, cssTypographyConfig, permutateThemes } from './configs.js';
6
+ // type FormattedCSSPlatform = { css: { output: string; destination: string }[] };
127
7
  const sd = new StyleDictionary();
128
- const getConfigs = (getConfig, outPath, tokensDir, themes) => Object.entries(themes)
129
- .map(([name, tokensets]) => {
130
- const setsWithPaths = tokensets.map((x) => `${tokensDir}/${x}.json`);
131
- const [fileName, folderName] = processThemeName(name);
132
- const paritionPrimitives = /(?!.*global\.json).*primitives.*/;
133
- const [source, include] = R.partition(R.test(paritionPrimitives), setsWithPaths);
134
- const config_ = getConfig({
135
- fileName: fileName,
136
- outPath,
137
- folderName,
138
- buildPath: `${outPath}/${folderName}/`,
139
- mode: fileName,
140
- });
141
- const config = {
142
- ...config_,
143
- source,
144
- include,
145
- };
146
- // console.log(config);
147
- return [`${folderName}: ${fileName}`, config];
148
- })
149
- .sort();
150
8
  export async function run(options) {
151
9
  const tokensDir = options.tokens;
152
10
  const storefrontOutDir = path.resolve('../../apps/storefront/tokens');
153
11
  const tokensOutDir = path.resolve(options.out);
154
12
  const $themes = JSON.parse(fs.readFileSync(path.resolve(`${tokensDir}/$themes.json`), 'utf-8'));
155
- const themes = permutateThemes($themes, {
156
- separator,
13
+ const relevant$themes = $themes.filter((theme) => {
14
+ const group = R.toLower(R.defaultTo('')(theme.group));
15
+ if (group === 'typography' && theme.name !== 'default')
16
+ return false;
17
+ if (group === 'fontsize' && theme.name !== 'default')
18
+ return false;
19
+ return true;
157
20
  });
158
- const tokenConfigs = getConfigs(getCSSConfig, tokensOutDir, tokensDir, themes);
159
- const storefrontConfigs = getConfigs(getStorefrontConfig, storefrontOutDir, tokensDir, themes);
160
- const typographyConfigs = getConfigs(getTypographyConfig, tokensOutDir, tokensDir, R.pickBy((val, key) => R.startsWith('light', R.toLower(key)), themes));
21
+ const themes = permutateThemes(relevant$themes);
22
+ const typographyThemes = R.pickBy((_, key) => R.startsWith('light', R.toLower(key)), themes);
23
+ const themeVariableConfigs = getConfigs(cssVariablesConfig, tokensOutDir, tokensDir, themes);
24
+ const storefrontConfigs = getConfigs(tsTokensConfig, storefrontOutDir, tokensDir, themes);
25
+ const typographyConfigs = getConfigs(cssTypographyConfig, tokensOutDir, tokensDir, typographyThemes);
161
26
  if (typographyConfigs.length > 0) {
162
- console.log('🍱 Bulding typography classes');
163
- console.log('➡️ Tokens path: ', tokensDir);
164
- await Promise.all(typographyConfigs.map(async ([name, config]) => {
165
- console.log(`👷 Processing ${name}`);
27
+ console.log('\n🍱 Building Typography classes');
28
+ await Promise.all(typographyConfigs.map(async ({ name, config }) => {
29
+ const typographyTheme = name.split('-')[0];
30
+ console.log(`👷 Processing: ${typographyTheme}`);
166
31
  const typographyClasses = await sd.extend(config);
167
32
  return typographyClasses.buildAllPlatforms();
168
33
  }));
169
34
  console.log('🏁 Finished building Typography classes!');
170
35
  }
171
- if (tokenConfigs.length > 0) {
172
- console.log('🍱 Building CSS variables from tokens');
36
+ if (themeVariableConfigs.length > 0) {
37
+ console.log('\n🍱 Building CSS variables from tokens');
173
38
  console.log('➡️ Tokens path: ', tokensDir);
174
- await Promise.all(tokenConfigs.map(async ([name, config]) => {
175
- console.log(`👷 Processing ${name}`);
176
- const tokensPackageSD = await sd.extend(config);
177
- return tokensPackageSD.buildAllPlatforms();
39
+ await Promise.all(themeVariableConfigs.map(async ({ name, config }) => {
40
+ console.log(`👷 Processing: ${name}`);
41
+ const themeVariablesSD = await sd.extend(config);
42
+ return themeVariablesSD.buildAllPlatforms();
178
43
  }));
179
44
  console.log('🏁 Finished building CSS variables!');
180
45
  }
181
46
  if (storefrontConfigs.length > 0 && options.preview) {
182
- console.log('\n🏗️ Building storefront js tokens');
183
- await Promise.all(storefrontConfigs.map(async ([name, config]) => {
184
- console.log(`👷 Processing ${name}`);
47
+ console.log('\n🏗️ Building Storefront tokens');
48
+ await Promise.all(storefrontConfigs.map(async ({ name, config }) => {
49
+ console.log(`👷 Processing: ${name}`);
185
50
  const storefrontSD = await sd.extend(config);
186
51
  return storefrontSD.buildAllPlatforms();
187
52
  }));
188
- console.log('🏁 Finished building storefront tokens');
53
+ console.log('🏁 Finished building Storefront tokens');
189
54
  }
190
55
  }
@@ -0,0 +1,169 @@
1
+ import * as tokenStudio from '@tokens-studio/sd-transforms';
2
+ import StyleDictionary from 'style-dictionary';
3
+ import * as R from 'ramda';
4
+ import { nameKebab, typographyShorthand, sizeRem } from './transformers.js';
5
+ import { jsTokens } from './formats/js-tokens.js';
6
+ import { cssVariables } from './formats/css-variables.js';
7
+ import { cssClassesTypography } from './formats/css-classes.js';
8
+ import { makeEntryFile } from './actions.js';
9
+ void tokenStudio.registerTransforms(StyleDictionary);
10
+ const prefix = 'ds';
11
+ const basePxFontSize = 16;
12
+ const separator = '_';
13
+ const fileHeader = () => [`These files are generated from design tokens defind using Token Studio`];
14
+ StyleDictionary.registerTransform(sizeRem);
15
+ StyleDictionary.registerTransform(nameKebab);
16
+ StyleDictionary.registerTransform(typographyShorthand);
17
+ StyleDictionary.registerFormat(jsTokens);
18
+ StyleDictionary.registerFormat(cssVariables);
19
+ StyleDictionary.registerFormat(cssClassesTypography);
20
+ StyleDictionary.registerAction(makeEntryFile);
21
+ StyleDictionary.registerTransformGroup({
22
+ name: 'ds/css',
23
+ transforms: [
24
+ `ts/resolveMath`,
25
+ 'ts/typography/fontWeight',
26
+ nameKebab.name,
27
+ sizeRem.name,
28
+ typographyShorthand.name,
29
+ 'ts/color/modifiers',
30
+ 'ts/color/css/hexrgba',
31
+ 'ts/size/lineheight',
32
+ 'ts/size/px',
33
+ 'ts/shadow/css/shorthand',
34
+ ],
35
+ });
36
+ const processThemeName = R.pipe(R.replace(`${separator}semantic`, ''), R.toLower, R.split(separator));
37
+ const outputColorReferences = (token) => {
38
+ if (R.test(/accent|neutral|brand1|brand2|brand3|success|danger|warning/, token.name) &&
39
+ R.includes('semantic/color', token.filePath)) {
40
+ return true;
41
+ }
42
+ return false;
43
+ };
44
+ export const permutateThemes = ($themes) => tokenStudio.permutateThemes($themes, {
45
+ separator,
46
+ });
47
+ export const cssVariablesConfig = ({ mode = 'light', outPath, theme }) => {
48
+ const selector = `${mode === 'light' ? ':root, ' : ''}[data-ds-color-mode="${mode}"]`;
49
+ return {
50
+ log: { verbosity: 'silent' },
51
+ preprocessors: ['tokens-studio'],
52
+ platforms: {
53
+ css: {
54
+ // custom
55
+ outPath,
56
+ mode,
57
+ theme,
58
+ basePxFontSize,
59
+ selector,
60
+ //
61
+ prefix,
62
+ buildPath: `${outPath}/${theme}/`,
63
+ transformGroup: 'ds/css',
64
+ actions: [makeEntryFile.name],
65
+ files: [
66
+ {
67
+ destination: `${mode}.css`,
68
+ format: cssVariables.name,
69
+ filter: (token) => !token.isSource,
70
+ },
71
+ ],
72
+ options: {
73
+ fileHeader,
74
+ outputReferences: outputColorReferences,
75
+ },
76
+ },
77
+ },
78
+ };
79
+ };
80
+ export const tsTokensConfig = ({ mode = 'unknown', outPath, theme }) => {
81
+ return {
82
+ log: { verbosity: 'silent' },
83
+ preprocessors: ['tokens-studio'],
84
+ platforms: {
85
+ ts: {
86
+ prefix,
87
+ basePxFontSize,
88
+ transformGroup: 'ds/css',
89
+ buildPath: `${outPath}/${theme}/`,
90
+ files: [
91
+ {
92
+ destination: `${mode}.ts`,
93
+ format: jsTokens.name,
94
+ outputReferences: outputColorReferences,
95
+ filter: (token) => {
96
+ if (R.test(/primitives\/colors|\/themes/, token.filePath)) {
97
+ return false;
98
+ }
99
+ if (R.test(/accent|neutral|brand1|brand2|brand3|success|danger|warning/, token.name) ||
100
+ R.includes('semantic', token.filePath)) {
101
+ return true;
102
+ }
103
+ return false;
104
+ },
105
+ },
106
+ ],
107
+ options: {
108
+ fileHeader,
109
+ },
110
+ },
111
+ },
112
+ };
113
+ };
114
+ export const cssTypographyConfig = ({ outPath, theme, typography }) => {
115
+ // const selector = `${typography === 'default' ? ':root, ' : ''}[data-ds-typography="${typography}"]`;
116
+ return {
117
+ log: { verbosity: 'silent' },
118
+ preprocessors: ['tokens-studio'],
119
+ platforms: {
120
+ css: {
121
+ prefix,
122
+ typography,
123
+ // selector,
124
+ buildPath: `${outPath}/${theme}/`,
125
+ basePxFontSize,
126
+ transforms: [nameKebab.name, 'ts/size/lineheight', 'ts/size/px', 'ts/typography/fontWeight'],
127
+ files: [
128
+ {
129
+ destination: `typography.css`,
130
+ format: cssClassesTypography.name,
131
+ filter: (token) => ['typography', 'fontWeights'].includes(token.type),
132
+ outputColorReferences: (token) => {
133
+ const type = token.$type ?? token.type;
134
+ if (type === 'fontWeights') {
135
+ return true;
136
+ }
137
+ return false;
138
+ },
139
+ },
140
+ ],
141
+ options: {
142
+ fileHeader,
143
+ },
144
+ },
145
+ },
146
+ };
147
+ };
148
+ export const getConfigs = (getConfig, outPath, tokensDir, themes) => Object.entries(themes)
149
+ .map(([name, tokensets]) => {
150
+ const setsWithPaths = tokensets.map((x) => `${tokensDir}/${x}.json`);
151
+ const [mode, theme, semantic, fontSize, typography] = processThemeName(name);
152
+ const paritionPrimitives = /(?!.*global\.json).*primitives.*/;
153
+ const [source, include] = R.partition(R.test(paritionPrimitives), setsWithPaths);
154
+ const config_ = getConfig({
155
+ outPath,
156
+ theme,
157
+ mode,
158
+ semantic,
159
+ fontSize,
160
+ typography,
161
+ });
162
+ const config = {
163
+ ...config_,
164
+ source,
165
+ include,
166
+ };
167
+ return { name: `${theme}-${mode}`, config };
168
+ })
169
+ .sort();
@@ -0,0 +1,53 @@
1
+ import * as R from 'ramda';
2
+ import { fileHeader, createPropertyFormatter, getReferences } from 'style-dictionary/utils';
3
+ const sortByType = R.sortBy((token) => token?.type === 'typography');
4
+ const getVariableName = R.pipe(R.split(':'), R.head, R.defaultTo(''), R.trim);
5
+ /**
6
+ * Creates CSS classes from typography tokens
7
+ */
8
+ export const cssClassesTypography = {
9
+ name: 'ds/css-classes-typography',
10
+ format: async function ({ dictionary, file, options, platform }) {
11
+ const { usesDtcg, outputReferences } = options;
12
+ const { basePxFontSize, selector } = platform;
13
+ const header = await fileHeader({ file });
14
+ const format = createPropertyFormatter({
15
+ outputReferences,
16
+ dictionary,
17
+ format: 'css',
18
+ });
19
+ const formattedTokens = R.pipe(sortByType, R.reduce((acc, token) => {
20
+ const type = token.type ?? token.$type;
21
+ if (type === 'fontWeights') {
22
+ const variable = format(token);
23
+ return { ...acc, variables: [...acc.variables, variable] };
24
+ }
25
+ if (type === 'typography') {
26
+ const typography = (usesDtcg ? token.$value : token.value);
27
+ const baseFontPx = basePxFontSize || 16;
28
+ const fontSize = `${parseInt(typography.fontSize) / baseFontPx}rem`;
29
+ const classSelector = R.replace('-typography', '', token.name);
30
+ // const formattedTypography = format(token);
31
+ const references = getReferences(token.original.value.fontWeight, dictionary.tokens);
32
+ const fontWeight = R.last(references);
33
+ let fontWeightName = '';
34
+ if (fontWeight) {
35
+ fontWeightName = getVariableName(format(fontWeight));
36
+ }
37
+ const className = `
38
+ .${classSelector} {
39
+ font-size: ${fontSize};
40
+ line-height: ${typography?.lineHeight};
41
+ ${fontWeightName && `font-weight: var(${fontWeightName});`}
42
+ }`;
43
+ return { ...acc, classes: [...acc.classes, className] };
44
+ }
45
+ return acc;
46
+ }, { variables: [], classes: [] }))(dictionary.allTokens);
47
+ const classes = formattedTokens.classes.join('\n');
48
+ const variables = formattedTokens.variables.join('\n');
49
+ const variables_ = `:root {\n${variables}\n}\n`;
50
+ const content = selector ? `${selector} {\n${classes}\n}` : classes;
51
+ return header + `@layer ds.typography {\n${variables_}\n${content}\n}\n`;
52
+ },
53
+ };
@@ -0,0 +1,17 @@
1
+ import { fileHeader, createPropertyFormatter } from 'style-dictionary/utils';
2
+ export const cssVariables = {
3
+ name: 'ds/css-variables',
4
+ format: async function ({ dictionary, file, options, platform }) {
5
+ const { allTokens } = dictionary;
6
+ const { outputReferences } = options;
7
+ const { selector } = platform;
8
+ const header = await fileHeader({ file });
9
+ const format = createPropertyFormatter({
10
+ outputReferences,
11
+ dictionary,
12
+ format: 'css',
13
+ });
14
+ const formattedVariables = allTokens.map(format);
15
+ return header + `${selector} {\n${formattedVariables.join('\n')}\n}\n`;
16
+ },
17
+ };
@@ -7,8 +7,8 @@ const toCssVarName = R.pipe(R.split(':'), R.head, R.trim);
7
7
  /**
8
8
  * Format for displaying tokens in storefront
9
9
  */
10
- export const groupedTokens = {
11
- name: 'groupedTokens',
10
+ export const jsTokens = {
11
+ name: 'ds/js-tokens',
12
12
  format: async function ({ dictionary, file }) {
13
13
  const format = createPropertyFormatter({
14
14
  dictionary,
@@ -1,6 +1,6 @@
1
1
  import { noCase } from './noCase.js';
2
2
  export const sizeRem = {
3
- name: 'fds/size/toRem',
3
+ name: 'ds/size/toRem',
4
4
  type: 'value',
5
5
  transitive: true,
6
6
  filter: (token) => ['sizing', 'spacing'].includes(token.type) && !token.name.includes('base'),