@progressiveui/themes-core 0.4.0

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/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@progressiveui/themes-core",
3
+ "description": "Themes for un core",
4
+ "version": "0.4.0",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/wfp/designsystem.git",
9
+ "directory": "packages/styles"
10
+ },
11
+ "bugs": "https://github.com/wfp/designsystem/issues",
12
+ "keywords": [
13
+ "colors",
14
+ "themes",
15
+ "un",
16
+ "un core",
17
+ "components",
18
+ "react"
19
+ ],
20
+ "type": "module",
21
+ "scripts": {
22
+ "build": "node --stack-size=9900 scripts/runTheme.js",
23
+ "filter:theme": "node scripts/filterJson.js",
24
+ "sync:tokens": "node scripts/syncTokens.js",
25
+ "build:tokens": "yarn sync:tokens && yarn filter:theme && yarn build"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "devDependencies": {
31
+ "change-case": "^5.2.0",
32
+ "deepdash": "^5.3.9",
33
+ "dotenv": "^16.3.1",
34
+ "lodash": "^4.17.21",
35
+ "style-dictionary": "^3.9.0",
36
+ "token-transformer": "^0.0.33"
37
+ },
38
+ "gitHead": "a5bec728bba7e239d3d00104c0e24d1b13dd554b"
39
+ }
@@ -0,0 +1,315 @@
1
+ import StyleDictionary from "style-dictionary";
2
+ import * as changeCase from "change-case";
3
+
4
+ const { formatHelpers } = StyleDictionary;
5
+
6
+ const { fileHeader, formattedVariables } = StyleDictionary.formatHelpers;
7
+
8
+ export const config = ({
9
+ source = `tokens/**/*.json`,
10
+ buildPath = `dist`,
11
+ themeName = "default",
12
+ } = {}) => {
13
+ /* CSS Variables */
14
+ StyleDictionary.registerFormat({
15
+ name: "css/variables-theme",
16
+ formatter: function ({ dictionary, file, options }) {
17
+ const { outputReferences, theme } = options;
18
+ console.log("dictionary", outputReferences);
19
+
20
+ return (
21
+ fileHeader({ file, commentStyle: "short" }) +
22
+ `@mixin theme-${theme} () {\n` +
23
+ dictionary.allTokens
24
+ .map((token) => {
25
+ if (typeof token.value === "string") {
26
+ return `--${token.name}: ${token.value};`;
27
+ } else if (typeof token.value === "object") {
28
+ const tokensObject = Object.entries(token.value).map(([k, t]) => {
29
+ if (k === "fontFamily") {
30
+ return `--${`${token.name}__${k}`}: "${t}";`;
31
+ }
32
+ return `--${`${token.name}__${k}`}: ${t};`;
33
+ });
34
+
35
+ var addition = "";
36
+ if (Object.keys(token.value).find((t) => t === "fontFamily")) {
37
+ addition = `\n--${token.name}: ${token.value.fontWeight} ${token.value.fontSize}/${token.value.lineHeight} "${token.value.fontFamily}", sans-serif;`;
38
+ }
39
+
40
+ if (Object.keys(token.value).find((t) => t === "spread")) {
41
+ addition = `\n--${token.name}: box-shadow: ${token.value.x}px ${token.value.y}px ${token.value.blur}px ${token.value.spread}px ${token.value.color};`;
42
+ }
43
+
44
+ return tokensObject.join("\n") + addition;
45
+ }
46
+ })
47
+ .join("\n") +
48
+ "\n}\n"
49
+ );
50
+
51
+ return (
52
+ fileHeader({ file }) +
53
+ `@mixin theme-${theme} () {\n` +
54
+ formattedVariables({
55
+ format: "css",
56
+ dictionary,
57
+ outputReferences,
58
+ }) +
59
+ "\n}\n"
60
+ );
61
+ },
62
+ });
63
+
64
+ StyleDictionary.registerFormat({
65
+ name: `scss/variables`,
66
+ formatter: function ({ dictionary }) {
67
+ return dictionary.allTokens
68
+ .map((token) => {
69
+ if (typeof token.value === "object") {
70
+ return null;
71
+ }
72
+ let value = JSON.stringify(token.value);
73
+ // the `dictionary` object now has `usesReference()` and
74
+ // `getReferences()` methods. `usesReference()` will return true if
75
+ // the value has a reference in it. `getReferences()` will return
76
+ // an array of references to the whole tokens so that you can access their
77
+ // names or any other attributes.
78
+ if (dictionary.usesReference(token.original.value)) {
79
+ // Note: make sure to use `token.original.value` because
80
+ // `token.value` is already resolved at this point.
81
+ const refs = dictionary.getReferences(token.original.value);
82
+ refs.forEach((ref) => {
83
+ value = value.replace(ref.value, function () {
84
+ return `${ref.name}`;
85
+ });
86
+ });
87
+ }
88
+
89
+ return `$${token.name}: var(--${token.name}, ${value}) !default;`;
90
+ })
91
+ .join(`\n`);
92
+ },
93
+ });
94
+
95
+ const scssTokenName = (token, options) => {
96
+ const tokenPath = token.path.filter(function (item, i) {
97
+ return !(
98
+ item === "color" ||
99
+ //(item === 'primary' && i === 1) ||
100
+ (item === "form" && i === 1)
101
+ );
102
+ });
103
+
104
+ return changeCase.kebabCase([options.prefix].concat(tokenPath).join(" "));
105
+ };
106
+
107
+ StyleDictionary.registerTransform({
108
+ type: "name",
109
+ transitive: true,
110
+ name: `name/scss`,
111
+ transformer: (token, options) => scssTokenName(token, options),
112
+ });
113
+
114
+ StyleDictionary.registerTransform({
115
+ type: "name",
116
+ transitive: true,
117
+ name: `name/jsonFlat`,
118
+ transformer: (token, options) => scssTokenName(token, options),
119
+ });
120
+
121
+ StyleDictionary.registerTransform({
122
+ type: "name",
123
+ transitive: true,
124
+ name: `name/scssDarkName`,
125
+ transformer: (token, options) =>
126
+ scssTokenName(token, options).replace("dark-", ""),
127
+ });
128
+
129
+ StyleDictionary.registerTransform({
130
+ type: `value`,
131
+ name: `value/fontSizePxToRem`,
132
+ matcher: (token) => token.type === "dimension",
133
+ transformer: (token) => token.value / 16 + "em",
134
+ });
135
+
136
+ StyleDictionary.registerTransform({
137
+ type: `value`,
138
+ name: `value/spacingPxToRem`,
139
+ matcher: (token) => token.type === "spacing",
140
+ transformer: (token) => parseInt(token.value.replace("px", "")) / 16 + "em",
141
+ });
142
+
143
+ StyleDictionary.registerTransform({
144
+ type: `attribute`,
145
+ name: `attribute/variablenames`,
146
+ matcher: (token) => true,
147
+ transformer: (token, options) => {
148
+ token.cssName = scssTokenName(token, options);
149
+ return token;
150
+ },
151
+ });
152
+
153
+ StyleDictionary.extend({
154
+ parsers: [
155
+ {
156
+ pattern: /\.json$/,
157
+ parse: ({ contents, filePath }) => {
158
+ var content = JSON.parse(contents);
159
+
160
+ // console.log(content);
161
+ //return content;
162
+ if (content.color) {
163
+ const { color, typography, ...other } = content;
164
+ let { primary, form, background, dark, ...otherColors } = color;
165
+ //console.log('color', color);
166
+ //console.log(JSON.parse(color.background));
167
+ /*let {
168
+ primary: primaryDark,
169
+ form: formDark,
170
+ //background: backgroundDark,
171
+ ...otherDarkColors
172
+ } = dark;
173
+ return {
174
+ ...primaryDark,
175
+ ...formDark,
176
+ // ...backgroundDark,
177
+ ...otherDarkColors,
178
+ };*/
179
+ return {
180
+ ...otherColors,
181
+ //...color.background,
182
+ ...form,
183
+ ...typography,
184
+ ...primary,
185
+ background: background,
186
+ ...other,
187
+ //background: color.background.background,
188
+ };
189
+ }
190
+ return content;
191
+ },
192
+ },
193
+ ],
194
+ source: [source],
195
+ platforms: {
196
+ figma: {
197
+ buildPath: buildPath + "/json/",
198
+ transforms: [
199
+ /// 'attribute/cti',
200
+ "attribute/color",
201
+ "attribute/variablenames",
202
+ "size/rem",
203
+ "name/jsonFlat",
204
+ ],
205
+ files: [
206
+ {
207
+ destination: "variables-full.json",
208
+ format: "json",
209
+ },
210
+ ],
211
+ },
212
+ scss: {
213
+ transformGroup: "scss",
214
+ buildPath: buildPath + "/scss/",
215
+ transforms: ["name/scss", "value/fontSizePxToRem", "size/rem"],
216
+ files: [
217
+ {
218
+ destination: "tokens.scss",
219
+ format: "scss/variables",
220
+ options: {
221
+ themeable: true,
222
+ },
223
+ },
224
+ ],
225
+ },
226
+ scssMapFlat: {
227
+ transformGroup: "scss",
228
+ buildPath: buildPath + "/scss/",
229
+ transforms: ["name/scss", "value/fontSizePxToRem", "size/rem"],
230
+ files: [
231
+ {
232
+ destination: "tokensMapFlat.scss",
233
+ format: "scss/map-flat",
234
+ options: {
235
+ themeable: true,
236
+ },
237
+ },
238
+ ],
239
+ },
240
+ scssMapDeep: {
241
+ transformGroup: "scss",
242
+ buildPath: buildPath + "/scss/",
243
+ transforms: ["name/scss", "value/fontSizePxToRem", "size/rem"],
244
+ files: [
245
+ {
246
+ destination: "tokensMapDeep.scss",
247
+ format: "scss/map-deep",
248
+ options: {
249
+ themeable: true,
250
+ },
251
+ },
252
+ ],
253
+ },
254
+ scssDefaultTheme: {
255
+ transformGroup: "css",
256
+ buildPath: buildPath + "/scss/",
257
+ transforms: [
258
+ "name/scss",
259
+ "value/fontSizePxToRem",
260
+ "size/rem",
261
+ "size/px",
262
+ ],
263
+ files: [
264
+ {
265
+ destination: "default-css-theme.scss",
266
+ format: "css/variables-theme",
267
+ options: {
268
+ outputReferences: true,
269
+ theme: themeName,
270
+ },
271
+ },
272
+ ],
273
+ },
274
+ /*scssDark: {
275
+ transformGroup: 'css',
276
+ buildPath: buildPath + '/scss/',
277
+ transforms: ['name/scssDarkName', 'value/fontSizePxToRem'],
278
+ files: [
279
+ {
280
+ destination: 'dark-css-theme.scss',
281
+ format: 'css/variables-theme',
282
+ filter: function (token) {
283
+ return token.path[1] === 'dark';
284
+ },
285
+ options: {
286
+ outputReferences: true,
287
+ theme: 'dark',
288
+ },
289
+ },
290
+ ],
291
+
292
+ parse: ({ contents, filePath }) => {
293
+ var content = JSON.parse(contents);
294
+ return null;
295
+ // return content;
296
+ if (content.color) {
297
+ const { color, typography, ...other } = content;
298
+ const { primary, form, background, ...otherColors } = color;
299
+ return {
300
+ // ...otherColors,
301
+ //...color.background,
302
+ //...form,
303
+ ...typography,
304
+ ...primary,
305
+ //background: background,
306
+ // ...other,
307
+ //background: color.background.background,
308
+ };
309
+ }
310
+ return content;
311
+ },
312
+ },*/
313
+ },
314
+ }).buildAllPlatforms();
315
+ };
@@ -0,0 +1,99 @@
1
+ import { readFileSync, writeFileSync } from "fs";
2
+
3
+ let json = JSON.parse(readFileSync("./figmaTokenStudio/tokens.json", "utf8"));
4
+
5
+ export function isObject(item) {
6
+ return item && typeof item === "object" && !Array.isArray(item);
7
+ }
8
+
9
+ export function mergeDeep(target, ...sources) {
10
+ if (!sources.length) return target;
11
+ const source = sources.shift();
12
+
13
+ if (isObject(target) && isObject(source)) {
14
+ for (const key in source) {
15
+ if (isObject(source[key])) {
16
+ if (!target[key]) Object.assign(target, { [key]: {} });
17
+ mergeDeep(target[key], source[key]);
18
+ } else {
19
+ Object.assign(target, { [key]: source[key] });
20
+ }
21
+ }
22
+ }
23
+
24
+ return mergeDeep(target, ...sources);
25
+ }
26
+
27
+ function removeUnusedKeys(obj) {
28
+ if (typeof obj !== "object" || obj === null) {
29
+ return obj;
30
+ }
31
+
32
+ // List of keys to remove
33
+ const keysToRemove = [
34
+ "textDecoration",
35
+ "textCase",
36
+ "paragraphSpacing",
37
+ "paragraphIndent",
38
+ ];
39
+
40
+ // If the object has any of the keys to be removed, delete them
41
+ for (const key of keysToRemove) {
42
+ if (key in obj) {
43
+ delete obj[key];
44
+ }
45
+ }
46
+
47
+ // Iterate over the object's keys and apply the function recursively
48
+ for (let key in obj) {
49
+ obj[key] = removeUnusedKeys(obj[key]);
50
+ }
51
+
52
+ return obj;
53
+ }
54
+
55
+ if (!String.prototype.endsWith) {
56
+ Object.defineProperty(String.prototype, "endsWith", {
57
+ enumerable: false,
58
+ configurable: false,
59
+ writable: false,
60
+ value: function (searchString, position) {
61
+ position = position || this.length;
62
+ position = position - searchString.length;
63
+ var lastIndex = this.lastIndexOf(searchString);
64
+ return lastIndex !== -1 && lastIndex === position;
65
+ },
66
+ });
67
+ }
68
+
69
+ function addCategoryToLeaves(obj, category) {
70
+ let newObj = Array.isArray(obj) ? [] : {};
71
+
72
+ Object.keys(obj).forEach((key) => {
73
+ if (key === "value") {
74
+ newObj["category"] = category;
75
+ }
76
+ if (typeof obj[key] === "object" && obj[key] !== null) {
77
+ newObj[key] = addCategoryToLeaves(obj[key], category);
78
+ } else {
79
+ newObj[key] = obj[key];
80
+ }
81
+ });
82
+ return newObj;
83
+ }
84
+
85
+ // TODO: Cleanup duplicate names in tokens
86
+ json = mergeDeep(
87
+ mergeDeep(
88
+ addCategoryToLeaves(json.Global, "global"),
89
+ addCategoryToLeaves(json.System, "system")
90
+ ),
91
+ addCategoryToLeaves(json.Component, "component")
92
+ );
93
+
94
+ json = removeUnusedKeys(json);
95
+
96
+ writeFileSync(
97
+ "./tokens/design-tokens.tokens.new.json",
98
+ JSON.stringify(json, null, 2)
99
+ );
@@ -0,0 +1,7 @@
1
+ import { config } from "./config.js";
2
+
3
+ config({
4
+ source: `tokens/**/*.json`,
5
+ buildPath: "dist", //`distDark`,
6
+ //themeName: 'default', //'dark',
7
+ });
@@ -0,0 +1,46 @@
1
+ import axios from "axios";
2
+ import fs from "fs";
3
+ import "dotenv/config";
4
+
5
+ if (!process.env.GIT_ACCESS_TOKEN) {
6
+ console.error("No GIT_ACCESS_TOKEN found in .env");
7
+ process.exit(1);
8
+ }
9
+
10
+ // Azure DevOps details
11
+ const organization = "worldfoodprogramme";
12
+ const project = "Design%20System";
13
+ const repository = "tokens";
14
+ const filePath = "tokens.json";
15
+ const apiVersion = "7.0";
16
+
17
+ const url = `https://dev.azure.com/${organization}/${project}/_apis/git/repositories/${repository}/items?path=/${filePath}&api-version=${apiVersion}&download=true`;
18
+
19
+ axios
20
+ .get(url, {
21
+ headers: {
22
+ Authorization: `Basic ${Buffer.from(
23
+ process.env.GIT_ACCESS_TOKEN
24
+ ).toString("base64")}`,
25
+ Accept: "application/text",
26
+ },
27
+ })
28
+ .then((response) => {
29
+ fs.writeFileSync(
30
+ "figmaTokenStudio/tokens.json",
31
+ JSON.stringify(response.data, null, 2)
32
+ );
33
+ console.log(
34
+ "🐝 Tokens downloaded successfully and saved under figmaTokenStudio/tokens.json"
35
+ );
36
+ })
37
+ .catch((error) => {
38
+ console.log(error.response.status);
39
+ if (error.response.status === 401) {
40
+ console.error(
41
+ "Invalid GIT_ACCESS_TOKEN found in .env file. Correct format is username:private_access_token"
42
+ );
43
+ } else {
44
+ console.error("Error fetching file:", error);
45
+ }
46
+ });