@rijkshuisstijl-community/design-tokens 10.0.0 → 10.0.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +46 -1
  3. package/build.mjs +36 -10
  4. package/cssFixers.mjs +89 -0
  5. package/cssFixers.spec.mjs +98 -0
  6. package/dist/_variables.scss +1 -0
  7. package/dist/index.css +1 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +1 -0
  10. package/dist/kern-lintblauw/_variables.scss +1 -0
  11. package/dist/kern-lintblauw/index.css +1 -0
  12. package/dist/kern-lintblauw/index.d.ts +1 -0
  13. package/dist/kern-lintblauw/index.js +1 -0
  14. package/dist/kern-lintblauw/root.css +1 -0
  15. package/dist/kern-lintblauw/tokens.d.ts +1 -0
  16. package/dist/kern-lintblauw/tokens.js +1 -182
  17. package/dist/root.css +1 -0
  18. package/dist/tokens.d.ts +1 -0
  19. package/dist/tokens.js +1 -182
  20. package/dist/uitvoerend-groen/_variables.scss +1 -0
  21. package/dist/uitvoerend-groen/index.css +1 -0
  22. package/dist/uitvoerend-groen/index.d.ts +1 -0
  23. package/dist/uitvoerend-groen/index.js +1 -0
  24. package/dist/uitvoerend-groen/root.css +1 -0
  25. package/dist/uitvoerend-groen/tokens.d.ts +1 -0
  26. package/dist/uitvoerend-groen/tokens.js +1 -182
  27. package/dist/uitvoerend-hemelblauw/_variables.scss +1 -0
  28. package/dist/uitvoerend-hemelblauw/index.css +1 -0
  29. package/dist/uitvoerend-hemelblauw/index.d.ts +1 -0
  30. package/dist/uitvoerend-hemelblauw/index.js +1 -0
  31. package/dist/uitvoerend-hemelblauw/root.css +1 -0
  32. package/dist/uitvoerend-hemelblauw/tokens.d.ts +1 -0
  33. package/dist/uitvoerend-hemelblauw/tokens.js +1 -182
  34. package/dist/uitvoerend-lintblauw/_variables.scss +1 -0
  35. package/dist/uitvoerend-lintblauw/index.css +1 -0
  36. package/dist/uitvoerend-lintblauw/index.d.ts +1 -0
  37. package/dist/uitvoerend-lintblauw/index.js +1 -0
  38. package/dist/uitvoerend-lintblauw/root.css +1 -0
  39. package/dist/uitvoerend-lintblauw/tokens.d.ts +1 -0
  40. package/dist/uitvoerend-lintblauw/tokens.js +1 -182
  41. package/dist/uitvoerend-oranje/_variables.scss +1 -0
  42. package/dist/uitvoerend-oranje/index.css +1 -0
  43. package/dist/uitvoerend-oranje/index.d.ts +1 -0
  44. package/dist/uitvoerend-oranje/index.js +1 -0
  45. package/dist/uitvoerend-oranje/root.css +1 -0
  46. package/dist/uitvoerend-oranje/tokens.d.ts +1 -0
  47. package/dist/uitvoerend-oranje/tokens.js +1 -182
  48. package/dist/uitvoerend-paars/_variables.scss +1 -0
  49. package/dist/uitvoerend-paars/index.css +1 -0
  50. package/dist/uitvoerend-paars/index.d.ts +1 -0
  51. package/dist/uitvoerend-paars/index.js +1 -0
  52. package/dist/uitvoerend-paars/root.css +1 -0
  53. package/dist/uitvoerend-paars/tokens.d.ts +1 -0
  54. package/dist/uitvoerend-paars/tokens.js +1 -182
  55. package/dist/uitvoerend-robijnrood/_variables.scss +1 -0
  56. package/dist/uitvoerend-robijnrood/index.css +1 -0
  57. package/dist/uitvoerend-robijnrood/index.d.ts +1 -0
  58. package/dist/uitvoerend-robijnrood/index.js +1 -0
  59. package/dist/uitvoerend-robijnrood/root.css +1 -0
  60. package/dist/uitvoerend-robijnrood/tokens.d.ts +1 -0
  61. package/dist/uitvoerend-robijnrood/tokens.js +1 -182
  62. package/figma/figma.tokens.json +1 -92
  63. package/package.json +4 -3
  64. package/src/generated/base.tokens.json +0 -91
  65. package/src/generated/kern-lintblauw/tokens.json +0 -91
  66. package/src/generated/themes.json +0 -637
  67. package/src/generated/uitvoerend-groen/tokens.json +0 -91
  68. package/src/generated/uitvoerend-hemelblauw/tokens.json +0 -91
  69. package/src/generated/uitvoerend-lintblauw/tokens.json +0 -91
  70. package/src/generated/uitvoerend-oranje/tokens.json +0 -91
  71. package/src/generated/uitvoerend-paars/tokens.json +0 -91
  72. package/src/generated/uitvoerend-robijnrood/tokens.json +0 -91
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @rijkshuisstijl-community/design-tokens
2
2
 
3
+ ## 10.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - f5942a6: Parent key is verwijderd uit figma.tokens.json. Deze key is nooit in gebruik geweest, dit heeft geen impact.
8
+ - e7b3d60: Add section about adding new token sets in documentation
9
+ - 5f77bfa: Added transformations on CSS-tokens to allow for calculations with references, power (^) and sanitize any `roundTo` in tokens
10
+
3
11
  ## 10.0.0
4
12
 
5
13
  ### Major Changes
package/README.md CHANGED
@@ -44,7 +44,7 @@ Hieronder vind je instructies hoe je de standaard Rijkshuisstijl-community token
44
44
 
45
45
  ## Nieuw thema toevoegen
46
46
 
47
- Er zijn al verschillende bedrijfsthema's in de @rijkshuisstijl-community/design-tokens package waarvoor (gedeeltelijke) support is vanuit de Rijkshuisstijl-community. Hieronder volgt een uitleg hoe nog meer thema's kunnen worden toegevoegd
47
+ Er zijn al verschillende bedrijfsthema's in de @rijkshuisstijl-community/design-tokens package waarvoor (gedeeltelijke) support is vanuit de Rijkshuisstijl-community. Hieronder volgt een uitleg hoe nog meer thema's kunnen worden toegevoegd.
48
48
 
49
49
  ## Nieuwe thema tokens
50
50
 
@@ -166,3 +166,48 @@ Er zijn al verschillende bedrijfsthema's in de @rijkshuisstijl-community/design-
166
166
  };
167
167
  export default preview;
168
168
  ```
169
+
170
+ ## Nieuwe token set toevoegen
171
+
172
+ Als je tokensets toevoegt vanuit de code in `figma.tokens.json`, zitten daar regels aan vast.
173
+ Voor elke nieuwe tokenset, zoals bijvoorbeeld `components/pagination/ams`:
174
+
175
+ ```json
176
+ "components/pagination/ams": {
177
+ "ams": {
178
+ "pagination": {
179
+ "font-family": {
180
+ "keys...": "values..."
181
+ }
182
+ }
183
+ }
184
+ }
185
+ ```
186
+
187
+ is ook een entry nodig in `.$metadata.tokenSetOrder`: (op alfabetische volgorde aub)
188
+
189
+ ```json
190
+ "$metadata": {
191
+ "tokenSetOrder": [
192
+ "brand/color",
193
+ "components/pagination/ams",
194
+ "etc..."
195
+ ]
196
+ }
197
+ ```
198
+
199
+ én in _elk_ thema `.$themes[x].selectedTokenSets`: (op alfabetische volgorde aub)
200
+
201
+ ```json
202
+ "$themes": [
203
+ {
204
+ "id": "05865788a086eeac7ffc4514736ccd777f1ff95c",
205
+ "name": "wetgevend",
206
+ "$figmaStyleReferences": {},
207
+ "selectedTokenSets": {
208
+ "components/pagination/ams": "enabled",
209
+ "other/groups...": "enabled"
210
+ }
211
+ }
212
+ ]
213
+ ```
package/build.mjs CHANGED
@@ -1,10 +1,11 @@
1
1
  import { existsSync, mkdirSync } from 'fs';
2
2
  import { readFile, writeFile } from 'node:fs/promises';
3
- import path from 'path';
3
+ import { posix } from 'path';
4
4
  import StyleDictionary from 'style-dictionary';
5
-
6
5
  import { register } from '@tokens-studio/sd-transforms';
7
6
 
7
+ import { fixCSSFile } from './cssFixers.mjs';
8
+
8
9
  // Will take the theme name and remove all spaces and make it lowercase
9
10
  const normalizeThemeName = (name) => {
10
11
  return name.toLowerCase().replace(/\s+/g, '');
@@ -22,6 +23,30 @@ const removeUnitlessLineHeightTransform = () => {
22
23
  }
23
24
  };
24
25
 
26
+ StyleDictionary.registerAction({
27
+ name: 'fixCSSTokens',
28
+ do: async function (_dictionary, config) {
29
+ const buildPath = config.buildPath || 'dist/';
30
+ const files = config.files || [];
31
+ // TS allows roundTo(), exponentiation (^) and basic calculations (without `calc()`) in their values, but these are not valid CSS.
32
+ for (const file of files) {
33
+ const filePath = posix.join(buildPath, file.destination);
34
+ console.log('🔧 fixing css:', filePath);
35
+ await fixCSSFile(filePath);
36
+ }
37
+ },
38
+ // No undo action available - files are deleted during cleanup.
39
+ undo: function () {},
40
+ });
41
+
42
+ // Custom header to add generation date
43
+ StyleDictionary.registerFileHeader({
44
+ name: 'nlds-rhc-header',
45
+ fileHeader: function (defaultMessage) {
46
+ return [...defaultMessage, `Generated on ${new Date().toUTCString()}`];
47
+ },
48
+ });
49
+
25
50
  const excludes = [
26
51
  'components/avatar',
27
52
  'components/form-field-option-label',
@@ -43,6 +68,9 @@ const getPlatformsConfig = (buildPath, themeName) => {
43
68
  transforms: ['name/camel'],
44
69
  buildPath,
45
70
  excludes,
71
+ options: {
72
+ fileHeader: 'nlds-rhc-header',
73
+ },
46
74
  files: [
47
75
  {
48
76
  format: 'typescript/es6-declarations',
@@ -75,28 +103,26 @@ const getPlatformsConfig = (buildPath, themeName) => {
75
103
  transforms: ['name/kebab'],
76
104
  buildPath,
77
105
  excludes,
106
+ actions: ['fixCSSTokens'],
107
+ options: {
108
+ fileHeader: 'nlds-rhc-header',
109
+ outputReferences: true,
110
+ },
78
111
  files: [
79
112
  {
80
113
  destination: 'root.css',
81
114
  format: 'css/variables',
82
- options: {
83
- outputReferences: true,
84
- },
85
115
  },
86
116
  {
87
117
  destination: 'index.css',
88
118
  format: 'css/variables',
89
119
  options: {
90
120
  selector: `.${themeName}`,
91
- outputReferences: true,
92
121
  },
93
122
  },
94
123
  {
95
124
  destination: '_variables.scss',
96
125
  format: 'scss/variables',
97
- options: {
98
- outputReferences: true,
99
- },
100
126
  },
101
127
  ],
102
128
  },
@@ -136,7 +162,7 @@ async function buildThemes() {
136
162
  }
137
163
 
138
164
  // Write individual theme tokens
139
- await writeFile(path.join(themesDir, `tokens.json`), JSON.stringify(themeData.tokens, null, 2));
165
+ await writeFile(posix.join(themesDir, `tokens.json`), JSON.stringify(themeData.tokens, null, 2));
140
166
 
141
167
  const config = getPlatformsConfig(`dist/${themeName}/`, themeName);
142
168
  // Create a separate Style Dictionary instance for each theme
package/cssFixers.mjs ADDED
@@ -0,0 +1,89 @@
1
+ import { readFile, writeFile } from 'fs/promises';
2
+
3
+ // When using `outputReferences: true` in Style Dictionary (see `build.mjs`), any calculations/transforms are overwritten by the css-var-names.
4
+ // So you'll end up with invalid CSS like:
5
+ // `--my-var: var(--my-length) + 20px;` - see: https://github.com/style-dictionary/style-dictionary/issues/1055
6
+ // We will need to fix any invalid stuff from Tokens Studio (TS) here as a post-build step.
7
+ // This applies to both .css and .scss files.
8
+
9
+ const varRegex = /(?<prefix>^\s*--[^:]+:\s*)(?<value>[^;]+?)(?<suffix>\s*;)/gm;
10
+
11
+ export async function fixCSSFile(filePath) {
12
+ let content = await readFile(filePath, 'utf-8');
13
+
14
+ content = await fixRoundTo(content);
15
+ content = await fixExponentiation(content);
16
+ content = await fixCalc(content);
17
+
18
+ await writeFile(filePath, content);
19
+ }
20
+
21
+ // This will wrap any calculations in `calc()`.
22
+ export function fixCalc(content) {
23
+ const operatorRegex = /(?:\s\+\s|\s-\s|\/|\*)/;
24
+
25
+ return content.replace(varRegex, (match, prefix, value, suffix) => {
26
+ if (!value.match(operatorRegex)) {
27
+ return match;
28
+ }
29
+
30
+ return `${prefix}calc(${value})${suffix}`;
31
+ });
32
+ }
33
+
34
+ // Exponentiation (^) is not supported in CSS, so we need to convert it to pow(base, exponent)
35
+ export function fixExponentiation(content) {
36
+ const exponentiationRegex =
37
+ /([0-9]*\.?[0-9]+(?:[a-z%]+)?|var\([^)]+\))\s*\^\s*([0-9]*\.?[0-9]+(?:[a-z%]+)?|var\([^)]+\))/g;
38
+
39
+ return content.replace(varRegex, (match, prefix, value, suffix) => {
40
+ if (!value.includes('^')) {
41
+ return match;
42
+ }
43
+
44
+ const fixedValue = value.replace(exponentiationRegex, (_match, base, exponent) => {
45
+ return `pow(${base}, ${exponent})`;
46
+ });
47
+
48
+ return `${prefix}${fixedValue}${suffix}`;
49
+ });
50
+ }
51
+
52
+ // This will strip out any roundTo() calls, as CSS doesn't support it.
53
+ // It does allow round(), but that needs a rounding interval, which is unknown at this point.
54
+ // See https://developer.mozilla.org/en-US/docs/Web/CSS/round
55
+ export function fixRoundTo(content) {
56
+ return content.replace(varRegex, (match, prefix, value, suffix) => {
57
+ if (!value.includes('roundTo(')) {
58
+ return match;
59
+ }
60
+
61
+ // Handle nested parentheses by processing the string character by character
62
+ let fixedValue = value;
63
+ let result = '';
64
+ let i = 0;
65
+
66
+ while (i < fixedValue.length) {
67
+ if (fixedValue.slice(i, i + 8) === 'roundTo(') {
68
+ // Found roundTo(, now find the matching closing parenthesis
69
+ i += 8; // Skip "roundTo("
70
+ let parenCount = 1;
71
+ let start = i;
72
+
73
+ while (i < fixedValue.length && parenCount > 0) {
74
+ if (fixedValue[i] === '(') parenCount++;
75
+ if (fixedValue[i] === ')') parenCount--;
76
+ i++;
77
+ }
78
+
79
+ // Extract the content between parentheses and add to result
80
+ result += fixedValue.slice(start, i - 1);
81
+ } else {
82
+ result += fixedValue[i];
83
+ i++;
84
+ }
85
+ }
86
+
87
+ return `${prefix}${result}${suffix}`;
88
+ });
89
+ }
@@ -0,0 +1,98 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { fixCalc, fixExponentiation, fixRoundTo } from './cssFixers.mjs';
3
+
4
+ describe('css fixers', () => {
5
+ describe('fixCalc', () => {
6
+ test('should wrap adding calculations in calc()', async () => {
7
+ const input = '--some-var: 100px + 50%;';
8
+ const output = '--some-var: calc(100px + 50%);';
9
+ expect(fixCalc(input)).toBe(output);
10
+ });
11
+ test('should wrap calculations with variables in calc()', async () => {
12
+ const input = '--some-var: 100px + var(--some-other-var);';
13
+ const output = '--some-var: calc(100px + var(--some-other-var));';
14
+ expect(fixCalc(input)).toBe(output);
15
+ });
16
+ test('should wrap calculations with variables in calc()', async () => {
17
+ const input = '--some-var: var(--some-other-var) + 100px;';
18
+ const output = '--some-var: calc(var(--some-other-var) + 100px);';
19
+ expect(fixCalc(input)).toBe(output);
20
+ });
21
+ test('should wrap subtraction calculations in calc()', async () => {
22
+ const input = '--some-var: 100px - 50px;';
23
+ const output = '--some-var: calc(100px - 50px);';
24
+ expect(fixCalc(input)).toBe(output);
25
+ });
26
+ test('should wrap multiplication calculations in calc()', async () => {
27
+ const input = '--some-var: 10px * 2;';
28
+ const output = '--some-var: calc(10px * 2);';
29
+ expect(fixCalc(input)).toBe(output);
30
+ });
31
+ test('should wrap division calculations in calc()', async () => {
32
+ const input = '--some-var: 100px / 2;';
33
+ const output = '--some-var: calc(100px / 2);';
34
+ expect(fixCalc(input)).toBe(output);
35
+ });
36
+ test('should wrap mixed calculations in calc()', async () => {
37
+ const input = '--some-var: var(--base) * 2 - 10px;';
38
+ const output = '--some-var: calc(var(--base) * 2 - 10px);';
39
+ expect(fixCalc(input)).toBe(output);
40
+ });
41
+ test('should not wrap single variables in calc()', async () => {
42
+ const input = '--some-var: var(--other-var);';
43
+ const output = '--some-var: var(--other-var);';
44
+ expect(fixCalc(input)).toBe(output);
45
+ });
46
+ test('should not wrap simple values in calc()', async () => {
47
+ const input = '--some-var: 10px;';
48
+ const output = '--some-var: 10px;';
49
+ expect(fixCalc(input)).toBe(output);
50
+ });
51
+ });
52
+
53
+ describe('fixExponentiation', () => {
54
+ test('should convert ^ to pow()', async () => {
55
+ const input = '--some-var: 2^3;';
56
+ const output = '--some-var: pow(2, 3);';
57
+ expect(fixExponentiation(input)).toBe(output);
58
+ });
59
+ test('should convert ^ to pow() with variable as base', async () => {
60
+ const input = '--some-var: var(--base)^3;';
61
+ const output = '--some-var: pow(var(--base), 3);';
62
+ expect(fixExponentiation(input)).toBe(output);
63
+ });
64
+ test('should convert ^ to pow() with variable as exponent', async () => {
65
+ const input = '--some-var: 2^var(--exponent);';
66
+ const output = '--some-var: pow(2, var(--exponent));';
67
+ expect(fixExponentiation(input)).toBe(output);
68
+ });
69
+ test('should convert ^ to pow() with variables as both base and exponent', async () => {
70
+ const input = '--some-var: var(--base)^var(--exponent);';
71
+ const output = '--some-var: pow(var(--base), var(--exponent));';
72
+ expect(fixExponentiation(input)).toBe(output);
73
+ });
74
+ });
75
+
76
+ describe('fixRoundTo', () => {
77
+ test('should remove roundTo()', async () => {
78
+ const input = '--some-var: roundTo(10px);';
79
+ const output = '--some-var: 10px;';
80
+ expect(fixRoundTo(input)).toBe(output);
81
+ });
82
+ test('should remove roundTo() with variable', async () => {
83
+ const input = '--some-var: roundTo(var(--base-size));';
84
+ const output = '--some-var: var(--base-size);';
85
+ expect(fixRoundTo(input)).toBe(output);
86
+ });
87
+ test('should remove roundTo() with calc function', async () => {
88
+ const input = '--some-var: roundTo(calc(10px + 5px));';
89
+ const output = '--some-var: calc(10px + 5px);';
90
+ expect(fixRoundTo(input)).toBe(output);
91
+ });
92
+ test('should remove roundTo() with calc function containing variables', async () => {
93
+ const input = '--some-var: roundTo(calc(var(--base) * 2));';
94
+ const output = '--some-var: calc(var(--base) * 2);';
95
+ expect(fixRoundTo(input)).toBe(output);
96
+ });
97
+ });
98
+ });
@@ -1,5 +1,6 @@
1
1
 
2
2
  // Do not edit directly, this file was auto-generated.
3
+ // Generated on Mon, 15 Dec 2025 18:39:45 GMT
3
4
 
4
5
  $rhc-border-radius-round: 999px;
5
6
  $rhc-border-radius-none: 0px;
package/dist/index.css CHANGED
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
+ * Generated on Mon, 15 Dec 2025 18:39:45 GMT
3
4
  */
4
5
 
5
6
  .rhc-theme {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
+ * Generated on Mon, 15 Dec 2025 18:39:45 GMT
3
4
  */
4
5
 
5
6
  export const rhcBorderRadiusRound: string;
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
+ * Generated on Mon, 15 Dec 2025 18:39:45 GMT
3
4
  */
4
5
 
5
6
  export const rhcBorderRadiusRound = "999px";
@@ -1,5 +1,6 @@
1
1
 
2
2
  // Do not edit directly, this file was auto-generated.
3
+ // Generated on Mon, 15 Dec 2025 18:39:48 GMT
3
4
 
4
5
  $rhc-border-radius-round: 999px;
5
6
  $rhc-border-radius-none: 0px;
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
+ * Generated on Mon, 15 Dec 2025 18:39:48 GMT
3
4
  */
4
5
 
5
6
  .kern-lintblauw {
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
+ * Generated on Mon, 15 Dec 2025 18:39:48 GMT
3
4
  */
4
5
 
5
6
  export const rhcBorderRadiusRound: string;
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
+ * Generated on Mon, 15 Dec 2025 18:39:48 GMT
3
4
  */
4
5
 
5
6
  export const rhcBorderRadiusRound = "999px";
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
+ * Generated on Mon, 15 Dec 2025 18:39:48 GMT
3
4
  */
4
5
 
5
6
  :root {
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
+ * Generated on Mon, 15 Dec 2025 18:39:48 GMT
3
4
  */
4
5
 
5
6
  export default tokens;