@sb1/ffe-core 100.0.0 → 100.0.4

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 (39) hide show
  1. package/README.md +8 -8
  2. package/css/ffe.css +0 -1
  3. package/less/dimensions.less +1 -0
  4. package/less/variables.less +0 -1
  5. package/package.json +6 -4
  6. package/scripts/build-colors/build-colors.cjs +115 -0
  7. package/scripts/build-colors/json/json.cjs +12 -0
  8. package/scripts/build-colors/mobile/android.cjs +99 -0
  9. package/scripts/build-colors/mobile/android.test.js +98 -0
  10. package/scripts/build-colors/mobile/ios.cjs +205 -0
  11. package/scripts/build-colors/web/chevron.cjs +44 -0
  12. package/scripts/build-colors/web/color-names.cjs +24 -0
  13. package/scripts/build-colors/web/css.cjs +78 -0
  14. package/scripts/build-colors/web/js.cjs +44 -0
  15. package/scripts/build-colors/web/tailwind.cjs +36 -0
  16. package/scripts/build-colors/web/tailwind4.cjs +24 -0
  17. package/scripts/build-colors/web/web.cjs +18 -0
  18. package/scripts/build-custom-mq.cjs +45 -0
  19. package/scripts/build.cjs +38 -0
  20. package/scripts/figma-api/color.spec.tsx +126 -0
  21. package/scripts/figma-api/color.ts +52 -0
  22. package/scripts/figma-api/figma_api.ts +41 -0
  23. package/scripts/figma-api/sync_figma_to_tokens.ts +57 -0
  24. package/scripts/figma-api/token_export.spec.tsx +359 -0
  25. package/scripts/figma-api/token_export.ts +99 -0
  26. package/scripts/figma-api/token_import.spec.tsx +1097 -0
  27. package/scripts/figma-api/token_import.ts +430 -0
  28. package/scripts/figma-api/token_types.ts +55 -0
  29. package/scripts/figma-api/utils.ts +11 -0
  30. package/scripts/lib/extractCustomProps.cjs +24 -0
  31. package/scripts/lib/genTypeScript.cjs +7 -0
  32. package/scripts/lib/renderLessVarsToCSSProps.cjs +23 -0
  33. package/scripts/lib/writeToFile.cjs +9 -0
  34. package/scripts/utils.cjs +27 -0
  35. package/tokens/01 Primitive.value.json +4726 -0
  36. package/tokens/02 Semantic.Dark.json +3942 -0
  37. package/tokens/02 Semantic.Light.json +3942 -0
  38. package/tokens/03 Context.Accent.json +2273 -0
  39. package/tokens/03 Context.Default.json +2273 -0
package/README.md CHANGED
@@ -14,9 +14,9 @@ npm install --save-dev less less-plugin-npm-import # less-plugin is optional,
14
14
 
15
15
  Full documentation on usage is available at:
16
16
 
17
- * https://design.sparebank1.no/komponenter/typografi/
18
- * https://design.sparebank1.no/profil/farger/
19
- * https://design.sparebank1.no/profil/spacing/
17
+ - https://design.sparebank1.no/komponenter/typografi/
18
+ - https://design.sparebank1.no/profil/farger/
19
+ - https://design.sparebank1.no/profil/spacing/
20
20
 
21
21
  ```less
22
22
  /* Your project's main .less import file */
@@ -66,11 +66,11 @@ If your project uses the core styling, you're probably good to go. If not, make
66
66
 
67
67
  This package provides a set of less files containing variables for colors and other reusable constants. These files are:
68
68
 
69
- - less/breakpoints.less
70
- - less/colors.less
71
- - less/dimensions.less
72
- - less/motion.less
73
- - less/spacing.less
69
+ - less/breakpoints.less
70
+ - less/colors.less
71
+ - less/dimensions.less
72
+ - less/motion.less
73
+ - less/spacing.less
74
74
 
75
75
  The less variables specified in this package are also available as named JavaScript imports. This can be useful for consumers that use CSS-in-JS, or that need access to these values in their JavaScript for other reasons. They are named the same as their LESS siblings, but are camelCased, and do not have the `@ffe-` prefix.
76
76
 
package/css/ffe.css CHANGED
@@ -1810,7 +1810,6 @@ html,
1810
1810
  }
1811
1811
  :root,
1812
1812
  :host {
1813
- /* Form element borders */
1814
1813
  --ffe-g-border-radius-sm: 4px;
1815
1814
  --ffe-g-border-radius: 8px;
1816
1815
  --ffe-g-border-radius-lg: 16px;
@@ -1,3 +1,4 @@
1
+ //dimensjoner
1
2
  @app-width: 1280px;
2
3
  @app-width-min: 320px;
3
4
  @app-margin: 20px;
@@ -1,6 +1,5 @@
1
1
  :root,
2
2
  :host {
3
- /* Form element borders */
4
3
  --ffe-g-border-radius-sm: 4px;
5
4
  --ffe-g-border-radius: 8px;
6
5
  --ffe-g-border-radius-lg: 16px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sb1/ffe-core",
3
- "version": "100.0.0",
3
+ "version": "100.0.4",
4
4
  "description": "Rammeverk for Felles Front End",
5
5
  "license": "MIT",
6
6
  "author": "SpareBank 1",
@@ -9,7 +9,9 @@
9
9
  "lib",
10
10
  "es",
11
11
  "less",
12
- "css"
12
+ "css",
13
+ "scripts",
14
+ "tokens"
13
15
  ],
14
16
  "main": "lib/index.js",
15
17
  "module": "es/index.js",
@@ -35,7 +37,7 @@
35
37
  "build-colors": "./scripts/build-colors.cjs"
36
38
  },
37
39
  "devDependencies": {
38
- "@sb1/ffe-buildtool": "^100.0.0",
40
+ "@sb1/ffe-buildtool": "^100.0.4",
39
41
  "case": "^1.5.5",
40
42
  "less": "^4.1.2",
41
43
  "postcss": "^8.3.6"
@@ -43,5 +45,5 @@
43
45
  "publishConfig": {
44
46
  "access": "public"
45
47
  },
46
- "gitHead": "9712f28655bee888c86c90d2e93ac1a67e7989e4"
48
+ "gitHead": "3671afc1060e06a9f224892510b38fb923a33e06"
47
49
  }
@@ -0,0 +1,115 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { buildAndroidColors } = require('./mobile/android.cjs');
4
+ const { buildIosColors } = require('./mobile/ios.cjs');
5
+ const { buildWebColors } = require('./web/web.cjs');
6
+ const { buildJSONColors } = require('./json/json.cjs');
7
+
8
+ const tokensPath = '../../tokens';
9
+ const files = {
10
+ primitive: '01 Primitive.value.json',
11
+ semanticLight: '02 Semantic.Light.json',
12
+ semanticDark: '02 Semantic.Dark.json',
13
+ context: '03 Context.Default.json',
14
+ contextAccent: '03 Context.Accent.json',
15
+ };
16
+
17
+ function filePath(filename) {
18
+ return path.resolve(__dirname, tokensPath, filename);
19
+ }
20
+
21
+ function loadColorsFromTokens(fileName, referenceDict) {
22
+ const colorDict = {};
23
+ const jsonContent = JSON.parse(
24
+ fs
25
+ .readFileSync(filePath(fileName), 'utf8')
26
+ .replaceAll('-', '.')
27
+ .toLowerCase(),
28
+ );
29
+ const processColorTokens = (obj, prefix = '') => {
30
+ for (const [key, value] of Object.entries(obj)) {
31
+ if (value.$type === 'color') {
32
+ const cssVarName = `${prefix}${key}`;
33
+ if (!referenceDict) {
34
+ colorDict[cssVarName] = value.$value;
35
+ } else {
36
+ const colorValue = referenceDict[value.$value.slice(1, -1)];
37
+ if (!colorValue) {
38
+ throw new Error(
39
+ `In file ${fileName} .Color value (${colorValue}) for ${cssVarName} is missing in the reference dictionary.`,
40
+ );
41
+ }
42
+ colorDict[cssVarName] = colorValue;
43
+ }
44
+ } else if (typeof value === 'object') {
45
+ processColorTokens(value, `${prefix}${key}.`);
46
+ }
47
+ }
48
+ };
49
+ processColorTokens(jsonContent);
50
+ return colorDict;
51
+ }
52
+
53
+ function buildColorDict() {
54
+ const primitiveColors = loadColorsFromTokens(files.primitive);
55
+ const semanticLightColors = loadColorsFromTokens(
56
+ files.semanticLight,
57
+ primitiveColors,
58
+ );
59
+ const semanticDarkColors = loadColorsFromTokens(
60
+ files.semanticDark,
61
+ primitiveColors,
62
+ );
63
+
64
+ return {
65
+ light: loadColorsFromTokens(files.context, semanticLightColors),
66
+ dark: loadColorsFromTokens(files.context, semanticDarkColors),
67
+ lightAccent: loadColorsFromTokens(
68
+ files.contextAccent,
69
+ semanticLightColors,
70
+ ),
71
+ darkAccent: loadColorsFromTokens(
72
+ files.contextAccent,
73
+ semanticDarkColors,
74
+ ),
75
+ };
76
+ }
77
+
78
+ function buildColors(platforms, iosPaths, androidPaths, jsonPaths, webPaths) {
79
+ console.log(platforms, iosPaths, androidPaths);
80
+ if (!platforms || (!androidPaths && !iosPaths && !jsonPaths && !webPaths)) {
81
+ console.error('Platform and path arguments are required.');
82
+ return;
83
+ }
84
+ if (
85
+ !platforms.includes('android') &&
86
+ !platforms.includes('ios') &&
87
+ !platforms.includes('json') &&
88
+ !platforms.includes('web')
89
+ ) {
90
+ console.error(
91
+ "Platform must include 'android', 'ios', 'json, or 'web'.",
92
+ );
93
+ return;
94
+ }
95
+
96
+ const colorDict = buildColorDict();
97
+ if (platforms.includes('android')) {
98
+ buildAndroidColors(androidPaths, colorDict);
99
+ }
100
+ if (platforms.includes('ios')) {
101
+ buildIosColors(iosPaths, colorDict);
102
+ }
103
+ if (platforms.includes('web')) {
104
+ buildWebColors(webPaths, colorDict);
105
+ }
106
+ if (platforms.includes('json')) {
107
+ buildJSONColors(jsonPaths, colorDict);
108
+ }
109
+ }
110
+
111
+ module.exports = {
112
+ loadColorsFromTokens,
113
+ buildColorDict,
114
+ buildColors,
115
+ };
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ const { writeToFile } = require('../../utils.cjs');
3
+
4
+ function buildJSONColors(paths, colors) {
5
+ paths.forEach(path => {
6
+ writeToFile(path + '/colors-semantic.json')(
7
+ JSON.stringify(colors, null, 2),
8
+ );
9
+ });
10
+ }
11
+
12
+ module.exports = { buildJSONColors };
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ const { writeToFile } = require('../../utils.cjs');
3
+
4
+ const removeHash = value => (value.startsWith('#') ? value.slice(1) : value);
5
+ const cssHexToAndroidHex = str => str.slice(-2) + str.slice(0, -2);
6
+
7
+ function transformToAndroidHex(value) {
8
+ value = removeHash(value).toUpperCase();
9
+ if (value.length === 6) {
10
+ return `0xFF${value}`;
11
+ } else if (value.length === 8) {
12
+ return `0x${cssHexToAndroidHex(value)}`;
13
+ } else {
14
+ throw new Error(
15
+ `Invalid color value: ${value}. Expected 6 or 8 characters (with or without #).`,
16
+ );
17
+ }
18
+ }
19
+
20
+ function transformToAndroidColorName(name) {
21
+ return name
22
+ .split('.')
23
+ .map((part, idx) =>
24
+ idx === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1),
25
+ )
26
+ .join('');
27
+ }
28
+
29
+ function generateAndroidColorFileContent(colors) {
30
+ return `
31
+ /* Generated from Figma tokens */
32
+ /* Dokumentasjon på: https://sparebank1.github.io/designsystem/?path=/docs/design-farger-native--docs */
33
+ /* Fargene er bygget fra FFE Core versjon: ${require('../../../package.json').version} */
34
+
35
+ object Colors {
36
+
37
+ object LightDefault {
38
+ ${Object.entries(colors.light)
39
+ .map(
40
+ ([name, value]) =>
41
+ `val ${transformToAndroidColorName(
42
+ name,
43
+ )} = Color(${transformToAndroidHex(value)})`,
44
+ )
45
+ .join('\n')}
46
+ }
47
+
48
+ object DarkDefault {
49
+ ${Object.entries(colors.dark)
50
+ .map(
51
+ ([name, value]) =>
52
+ `val ${transformToAndroidColorName(
53
+ name,
54
+ )} = Color(${transformToAndroidHex(value)})`,
55
+ )
56
+ .join('\n')}
57
+ }
58
+
59
+ object LightAccent {
60
+ ${Object.entries(colors.lightAccent)
61
+ .map(
62
+ ([name, value]) =>
63
+ `val ${transformToAndroidColorName(
64
+ name,
65
+ )} = Color(${transformToAndroidHex(value)})`,
66
+ )
67
+ .join('\n')}
68
+ }
69
+
70
+ object DarkAccent {
71
+ ${Object.entries(colors.darkAccent)
72
+ .map(
73
+ ([name, value]) =>
74
+ `\t\tval ${transformToAndroidColorName(
75
+ name,
76
+ )} = Color(${transformToAndroidHex(value)})`,
77
+ )
78
+ .join('\n')}
79
+ }
80
+ }
81
+
82
+
83
+ `;
84
+ }
85
+
86
+ function buildAndroidColors(paths, colors) {
87
+ paths.forEach(path => {
88
+ writeToFile(path + '/Colors.kt')(
89
+ generateAndroidColorFileContent(colors),
90
+ );
91
+ });
92
+ }
93
+
94
+ module.exports = {
95
+ buildAndroidColors,
96
+ generateAndroidColorFileContent,
97
+ transformToAndroidHex,
98
+ transformToAndroidColorName,
99
+ };
@@ -0,0 +1,98 @@
1
+ const mockWrite = jest.fn();
2
+ const mockWriteToFile = jest.fn(() => mockWrite);
3
+
4
+ jest.mock("../../utils.cjs", () => ({
5
+ writeToFile: mockWriteToFile,
6
+ }));
7
+
8
+ const android = require("./android.cjs");
9
+
10
+ describe("android.cjs", () => {
11
+ describe("transformToAndroidHex", () => {
12
+ it("should convert #hex to C0xFF... (uppercase)", () => {
13
+ expect(android.transformToAndroidHex("#123abc")).toBe("C0xFF123ABC");
14
+ expect(android.transformToAndroidHex("#ABCDEF")).toBe("C0xFFABCDEF");
15
+ });
16
+
17
+ it("should convert 0x hex to uppercase", () => {
18
+ expect(android.transformToAndroidHex("0xFFAABBCC")).toBe("0XFFAABBCC");
19
+ });
20
+
21
+ it("should throw on invalid format", () => {
22
+ expect(() => android.transformToAndroidHex("red")).toThrow(
23
+ "Invalid color format"
24
+ );
25
+ expect(() => android.transformToAndroidHex("123456")).toThrow(
26
+ "Invalid color format"
27
+ );
28
+ expect(() => android.transformToAndroidHex("")).toThrow(
29
+ "Invalid color format"
30
+ );
31
+ });
32
+ });
33
+
34
+ describe("transformToAndroidColorName", () => {
35
+ it("should convert dot notation to camelCase", () => {
36
+ expect(android.transformToAndroidColorName("primary.color")).toBe(
37
+ "primaryColor"
38
+ );
39
+ expect(android.transformToAndroidColorName("a.b.c")).toBe("aBC");
40
+ expect(android.transformToAndroidColorName("single")).toBe("single");
41
+ });
42
+
43
+ it("should handle empty string", () => {
44
+ expect(android.transformToAndroidColorName("")).toBe("");
45
+ });
46
+ });
47
+
48
+ describe("generateAndroidColorFileContent", () => {
49
+ it("should generate Kotlin color file content", () => {
50
+ const colors = {
51
+ "primary.color": "#123456",
52
+ "secondary.color": "#abcdef",
53
+ };
54
+ const content = android.generateAndroidColorFileContent(colors);
55
+ expect(content).toContain("val primaryColor = Color(C0xFF123456)");
56
+ expect(content).toContain("val secondaryColor = Color(C0xFFABCDEF)");
57
+ expect(content).toContain(
58
+ "package com.<domain_name>.<app_name>.ui.theme"
59
+ );
60
+ });
61
+
62
+ it("should throw if color value is invalid", () => {
63
+ const colors = { "bad.color": "notacolor" };
64
+ expect(() => android.generateAndroidColorFileContent(colors)).toThrow(
65
+ "Invalid color format"
66
+ );
67
+ });
68
+ });
69
+
70
+ describe("buildAndroidColors", () => {
71
+ it("should call writeToFile for each color variant", () => {
72
+ const paths = ["/tmp/test"];
73
+ const colors = {
74
+ light: { "a.b": "#111111" },
75
+ dark: { "a.b": "#222222" },
76
+ lightAccent: { "a.b": "#333333" },
77
+ darkAccent: { "a.b": "#444444" },
78
+ };
79
+
80
+ android.buildAndroidColors(paths, colors);
81
+
82
+ expect(mockWriteToFile).toHaveBeenCalledTimes(4);
83
+ expect(mockWriteToFile).toHaveBeenCalledWith(
84
+ "/tmp/test/ColorsDefaultLight.kt"
85
+ );
86
+ expect(mockWriteToFile).toHaveBeenCalledWith(
87
+ "/tmp/test/ColorsDefaultDark.kt"
88
+ );
89
+ expect(mockWriteToFile).toHaveBeenCalledWith(
90
+ "/tmp/test/ColorsAccentLight.kt"
91
+ );
92
+ expect(mockWriteToFile).toHaveBeenCalledWith(
93
+ "/tmp/test/ColorsAccentDark.kt"
94
+ );
95
+ expect(mockWrite).toHaveBeenCalledTimes(4);
96
+ });
97
+ });
98
+ });
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env node
2
+ const { writeToFile } = require('../../utils.cjs');
3
+
4
+ function buildContents(paths) {
5
+ paths.forEach(path => {
6
+ writeToFile(path + '/SemanticColors.xcassets/Contents.json')(
7
+ `{
8
+ "info" : {
9
+ "author" : "xcode",
10
+ "version" : 1
11
+ }
12
+ }`,
13
+ );
14
+ writeToFile(path + '/SemanticColors.xcassets/README.md')(
15
+ `# Semantic Colors
16
+
17
+ Fargene er bygget fra FFE Core versjon: ${require('../../../package.json').version}
18
+
19
+ Dokumentasjon på: https://sparebank1.github.io/designsystem/?path=/docs/design-farger-native--docs
20
+ `,
21
+ );
22
+ writeToFile(path + '/SemanticColors.xcassets/default/Contents.json')(
23
+ `{
24
+ "info" : {
25
+ "author" : "xcode",
26
+ "version" : 1
27
+ }
28
+ }`,
29
+ );
30
+ writeToFile(path + '/SemanticColors.xcassets/accent/Contents.json')(
31
+ `{
32
+ "info" : {
33
+ "author" : "xcode",
34
+ "version" : 1
35
+ }
36
+ }`,
37
+ );
38
+ });
39
+ }
40
+
41
+ function buildSRGBComponentsFromHex(hex) {
42
+ // Remove # if present and convert to lowercase
43
+ const cleanHex = hex.replace('#', '').toLowerCase();
44
+
45
+ let r,
46
+ g,
47
+ b,
48
+ a = 255; // Default alpha to 255 (fully opaque)
49
+
50
+ if (cleanHex.length === 3) {
51
+ // RGB format: aaa -> aaaaaa
52
+ r = parseInt(cleanHex[0] + cleanHex[0], 16);
53
+ g = parseInt(cleanHex[1] + cleanHex[1], 16);
54
+ b = parseInt(cleanHex[2] + cleanHex[2], 16);
55
+ } else if (cleanHex.length === 4) {
56
+ // RGBA format: aaaf -> aaaaafff
57
+ r = parseInt(cleanHex[0] + cleanHex[0], 16);
58
+ g = parseInt(cleanHex[1] + cleanHex[1], 16);
59
+ b = parseInt(cleanHex[2] + cleanHex[2], 16);
60
+ a = parseInt(cleanHex[3] + cleanHex[3], 16);
61
+ } else if (cleanHex.length === 6) {
62
+ // RRGGBB format: aaaaaa
63
+ r = parseInt(cleanHex.slice(0, 2), 16);
64
+ g = parseInt(cleanHex.slice(2, 4), 16);
65
+ b = parseInt(cleanHex.slice(4, 6), 16);
66
+ } else if (cleanHex.length === 8) {
67
+ // RRGGBBAA format: aaaaaaff
68
+ r = parseInt(cleanHex.slice(0, 2), 16);
69
+ g = parseInt(cleanHex.slice(2, 4), 16);
70
+ b = parseInt(cleanHex.slice(4, 6), 16);
71
+ a = parseInt(cleanHex.slice(6, 8), 16);
72
+ } else {
73
+ throw new Error(`Invalid hex color format: ${hex}`);
74
+ }
75
+
76
+ // Convert to 0-1 range and format to 3 decimal places
77
+ return `{
78
+ "alpha": "${(a / 255).toFixed(3)}",
79
+ "blue": "${(b / 255).toFixed(3)}",
80
+ "green": "${(g / 255).toFixed(3)}",
81
+ "red": "${(r / 255).toFixed(3)}"
82
+ }`;
83
+ }
84
+
85
+ function colorNameToFolderName(name, prefix = '') {
86
+ const str = prefix ? prefix + '.' : '';
87
+ const parts = (str + name).split('.').filter(part => part !== 'color'); // Remove 'color' prefix if present
88
+
89
+ if (parts.length === 0) return '.colorset';
90
+
91
+ // First part: lowercase first letter, rest unchanged
92
+ const first = parts[0].charAt(0).toLowerCase() + parts[0].slice(1);
93
+
94
+ // Remaining parts: uppercase first letter, rest unchanged
95
+ const rest = parts
96
+ .slice(1)
97
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1));
98
+
99
+ return [first, ...rest].join('') + '.colorset';
100
+ }
101
+
102
+ function buildColorFileContents(
103
+ path,
104
+ name,
105
+ light,
106
+ lightAccent,
107
+ dark,
108
+ darkAccent,
109
+ ) {
110
+ writeToFile(
111
+ path +
112
+ '/SemanticColors.xcassets/default/' +
113
+ colorNameToFolderName(name) +
114
+ '/Contents.json',
115
+ )(
116
+ `{
117
+ "colors" : [
118
+ {
119
+ "color" : {
120
+ "color-space" : "srgb",
121
+ "components" : ${buildSRGBComponentsFromHex(light)}
122
+ },
123
+ "idiom" : "universal"
124
+ },
125
+ {
126
+ "appearances" : [
127
+ {
128
+ "appearance" : "luminosity",
129
+ "value" : "dark"
130
+ }
131
+ ],
132
+ "color" : {
133
+ "color-space" : "srgb",
134
+ "components" : ${buildSRGBComponentsFromHex(dark)}
135
+ },
136
+ "idiom" : "universal"
137
+ }
138
+ ],
139
+ "info" : {
140
+ "author" : "xcode",
141
+ "version" : 1
142
+ }
143
+ }
144
+ `,
145
+ );
146
+
147
+ writeToFile(
148
+ path +
149
+ '/SemanticColors.xcassets/accent/' +
150
+ colorNameToFolderName(name, 'accent') +
151
+ '/Contents.json',
152
+ )(
153
+ `{
154
+ "colors" : [
155
+ {
156
+ "color" : {
157
+ "color-space" : "srgb",
158
+ "components" : ${buildSRGBComponentsFromHex(lightAccent)}
159
+ },
160
+ "idiom" : "universal"
161
+ },
162
+ {
163
+ "appearances" : [
164
+ {
165
+ "appearance" : "luminosity",
166
+ "value" : "dark"
167
+ }
168
+ ],
169
+ "color" : {
170
+ "color-space" : "srgb",
171
+ "components" : ${buildSRGBComponentsFromHex(darkAccent)}
172
+ },
173
+ "idiom" : "universal"
174
+ }
175
+ ],
176
+ "info" : {
177
+ "author" : "xcode",
178
+ "version" : 1
179
+ }
180
+ }
181
+ `,
182
+ );
183
+ }
184
+
185
+ function buildColorFiles(paths, colors) {
186
+ Object.keys(colors.light).forEach(name => {
187
+ paths.forEach(path => {
188
+ buildColorFileContents(
189
+ path,
190
+ name,
191
+ colors.light[name],
192
+ colors.lightAccent[name],
193
+ colors.dark[name],
194
+ colors.darkAccent[name],
195
+ );
196
+ });
197
+ });
198
+ }
199
+
200
+ function buildIosColors(paths, colors) {
201
+ buildContents(paths);
202
+ buildColorFiles(paths, colors);
203
+ }
204
+
205
+ module.exports = { buildIosColors };
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ const { writeToFile } = require('../../utils.cjs');
3
+
4
+ function transformToCssProperty(name, value) {
5
+ return `--ffe-${name.replaceAll('.', '-')}: ${value};`;
6
+ }
7
+
8
+ function generateChevronCssColorFileContent(colors) {
9
+ return `
10
+ /* Generated from Figma tokens */
11
+
12
+
13
+
14
+ // Chevron colors to make it work with semantic colors
15
+ @ffe-color-chevron-light-default: ${Object.entries(colors.light)
16
+ .filter(([name]) => name === 'color.foreground.default')
17
+ .map(([_, value]) => value)[0]
18
+ .substring(1)};
19
+ @ffe-color-chevron-dark-default: ${Object.entries(colors.lightAccent)
20
+ .filter(([name]) => name === 'color.foreground.default')
21
+ .map(([_, value]) => value)[0]
22
+ .substring(1)};
23
+ @ffe-color-chevron-light-accent: ${Object.entries(colors.dark)
24
+ .filter(([name]) => name === 'color.foreground.default')
25
+ .map(([_, value]) => value)[0]
26
+ .substring(1)};
27
+ @ffe-color-chevron-dark-accent: ${Object.entries(colors.darkAccent)
28
+ .filter(([name]) => name === 'color.foreground.default')
29
+ .map(([_, value]) => value)[0]
30
+ .substring(1)};
31
+
32
+
33
+
34
+ `;
35
+ }
36
+
37
+ function buildChevronCssColors(paths, colors) {
38
+ paths.forEach(path => {
39
+ const content = generateChevronCssColorFileContent(colors);
40
+ writeToFile(path + 'less/colors-semantic-chevron.less')(content);
41
+ });
42
+ }
43
+
44
+ module.exports = { buildChevronCssColors };
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ const { writeToFile } = require('../../utils.cjs');
3
+
4
+ function transformToCssProperty(name) {
5
+ return `--ffe-${name.replaceAll('.', '-')}`;
6
+ }
7
+
8
+ function generateColorNamesFileContent(colors) {
9
+ const colorNames = {
10
+ colors: Object.entries(colors.light).map(([name]) =>
11
+ transformToCssProperty(name),
12
+ ),
13
+ };
14
+ return JSON.stringify(colorNames, null, 2);
15
+ }
16
+
17
+ function buildColorsNames(paths, colors) {
18
+ paths.forEach(path => {
19
+ const content = generateColorNamesFileContent(colors);
20
+ writeToFile(path + 'gen-src/semantic-color-names.json')(content);
21
+ });
22
+ }
23
+
24
+ module.exports = { buildColorsNames };