@digdir/designsystemet 0.1.0-alpha.18 → 0.1.0-alpha.19
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/LICENSE +7 -0
- package/dist/bin/designsystemet.js +24 -28
- package/dist/src/colors/colorUtils.js +223 -315
- package/dist/src/colors/index.js +3 -3
- package/dist/src/colors/themeUtils.js +227 -319
- package/dist/src/colors/types.js +0 -1
- package/dist/src/init/createTokensPackage.js +223 -203
- package/dist/src/init/generateMetadataJson.js +19 -14
- package/dist/src/init/generateThemesJson.js +49 -40
- package/dist/src/init/index.js +7 -4
- package/dist/src/init/nextStepsMarkdown.js +15 -13
- package/dist/src/init/template/prettier.config.js +5 -7
- package/dist/src/init/template/template-files/package.json +1 -0
- package/dist/src/init/utils.js +11 -7
- package/dist/src/migrations/beta-to-v1.js +342 -339
- package/dist/src/migrations/codemods/css/plugins.js +40 -36
- package/dist/src/migrations/codemods/css/run.js +15 -20
- package/dist/src/migrations/codemods/jsx/classname-prefix.js +57 -63
- package/dist/src/migrations/codemods/jsx/run.js +17 -19
- package/dist/src/migrations/index.js +6 -3
- package/dist/src/migrations/react-beta-to-v1.js +4 -3
- package/dist/src/tokens/actions.js +25 -23
- package/dist/src/tokens/build.js +65 -51
- package/dist/src/tokens/configs.js +188 -223
- package/dist/src/tokens/formats/css.js +143 -150
- package/dist/src/tokens/formats/js-tokens.js +27 -26
- package/dist/src/tokens/transformers.js +39 -41
- package/dist/src/tokens/utils/noCase.js +25 -25
- package/dist/src/tokens/utils/permutateThemes.js +50 -64
- package/dist/src/tokens/utils/utils.js +12 -25
- package/package.json +8 -3
- package/dist/src/test/a.css +0 -39
- package/dist/src/test/jsx-test.js +0 -12
- package/dist/types/bin/designsystemet.d.ts +0 -3
- package/dist/types/bin/designsystemet.d.ts.map +0 -1
- package/dist/types/src/colors/colorUtils.d.ts +0 -126
- package/dist/types/src/colors/colorUtils.d.ts.map +0 -1
- package/dist/types/src/colors/index.d.ts +0 -4
- package/dist/types/src/colors/index.d.ts.map +0 -1
- package/dist/types/src/colors/themeUtils.d.ts +0 -102
- package/dist/types/src/colors/themeUtils.d.ts.map +0 -1
- package/dist/types/src/colors/types.d.ts +0 -16
- package/dist/types/src/colors/types.d.ts.map +0 -1
- package/dist/types/src/init/createTokensPackage.d.ts +0 -5
- package/dist/types/src/init/createTokensPackage.d.ts.map +0 -1
- package/dist/types/src/init/generateMetadataJson.d.ts +0 -6
- package/dist/types/src/init/generateMetadataJson.d.ts.map +0 -1
- package/dist/types/src/init/generateThemesJson.d.ts +0 -3
- package/dist/types/src/init/generateThemesJson.d.ts.map +0 -1
- package/dist/types/src/init/index.d.ts +0 -3
- package/dist/types/src/init/index.d.ts.map +0 -1
- package/dist/types/src/init/nextStepsMarkdown.d.ts +0 -3
- package/dist/types/src/init/nextStepsMarkdown.d.ts.map +0 -1
- package/dist/types/src/init/template/prettier.config.d.mts +0 -9
- package/dist/types/src/init/template/prettier.config.d.mts.map +0 -1
- package/dist/types/src/init/utils.d.ts +0 -4
- package/dist/types/src/init/utils.d.ts.map +0 -1
- package/dist/types/src/migrations/beta-to-v1.d.ts +0 -3
- package/dist/types/src/migrations/beta-to-v1.d.ts.map +0 -1
- package/dist/types/src/migrations/codemods/css/plugins.d.ts +0 -6
- package/dist/types/src/migrations/codemods/css/plugins.d.ts.map +0 -1
- package/dist/types/src/migrations/codemods/css/run.d.ts +0 -8
- package/dist/types/src/migrations/codemods/css/run.d.ts.map +0 -1
- package/dist/types/src/migrations/codemods/jsx/classname-prefix.d.ts +0 -10
- package/dist/types/src/migrations/codemods/jsx/classname-prefix.d.ts.map +0 -1
- package/dist/types/src/migrations/codemods/jsx/run.d.ts +0 -7
- package/dist/types/src/migrations/codemods/jsx/run.d.ts.map +0 -1
- package/dist/types/src/migrations/index.d.ts +0 -6
- package/dist/types/src/migrations/index.d.ts.map +0 -1
- package/dist/types/src/migrations/react-beta-to-v1.d.ts +0 -3
- package/dist/types/src/migrations/react-beta-to-v1.d.ts.map +0 -1
- package/dist/types/src/test/jsx-test.d.ts +0 -4
- package/dist/types/src/test/jsx-test.d.ts.map +0 -1
- package/dist/types/src/tokens/actions.d.ts +0 -6
- package/dist/types/src/tokens/actions.d.ts.map +0 -1
- package/dist/types/src/tokens/build.d.ts +0 -11
- package/dist/types/src/tokens/build.d.ts.map +0 -1
- package/dist/types/src/tokens/configs.d.ts +0 -31
- package/dist/types/src/tokens/configs.d.ts.map +0 -1
- package/dist/types/src/tokens/formats/css.d.ts +0 -5
- package/dist/types/src/tokens/formats/css.d.ts.map +0 -1
- package/dist/types/src/tokens/formats/js-tokens.d.ts +0 -6
- package/dist/types/src/tokens/formats/js-tokens.d.ts.map +0 -1
- package/dist/types/src/tokens/transformers.d.ts +0 -5
- package/dist/types/src/tokens/transformers.d.ts.map +0 -1
- package/dist/types/src/tokens/utils/noCase.d.ts +0 -11
- package/dist/types/src/tokens/utils/noCase.d.ts.map +0 -1
- package/dist/types/src/tokens/utils/permutateThemes.d.ts +0 -17
- package/dist/types/src/tokens/utils/permutateThemes.d.ts.map +0 -1
- package/dist/types/src/tokens/utils/utils.d.ts +0 -24
- package/dist/types/src/tokens/utils/utils.d.ts.map +0 -1
|
@@ -2,229 +2,249 @@ import path from "node:path";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import prompts from "prompts";
|
|
5
|
-
import packageJsonTemplate from "./template/template-files/package.json" with {
|
|
6
|
-
type: 'json'
|
|
7
|
-
};
|
|
5
|
+
import packageJsonTemplate from "./template/template-files/package.json" with { type: "json" };
|
|
8
6
|
import generateMetadata from "./generateMetadataJson.js";
|
|
9
7
|
import generateThemes from "./generateThemesJson.js";
|
|
10
8
|
import { toGeneratedCssFileName, normalizeTokenSetName, toValidPackageName } from "./utils.js";
|
|
11
9
|
import { nextStepsMarkdown } from "./nextStepsMarkdown.js";
|
|
12
|
-
const MODES = [
|
|
13
|
-
'Light',
|
|
14
|
-
'Dark',
|
|
15
|
-
'Contrast'
|
|
16
|
-
];
|
|
10
|
+
const MODES = ["Light", "Dark", "Contrast"];
|
|
17
11
|
const promptOptions = {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
onCancel: () => {
|
|
13
|
+
console.log(`${chalk.red("\u2716")} Operation cancelled`);
|
|
14
|
+
process.exit();
|
|
15
|
+
}
|
|
22
16
|
};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
} else {
|
|
39
|
-
console.error(err);
|
|
40
|
-
console.log('Continuing...');
|
|
41
|
-
}
|
|
17
|
+
async function createTokensPackage(targetDir) {
|
|
18
|
+
const DIRNAME = import.meta.dirname || __dirname;
|
|
19
|
+
const DEFAULT_FILES_PATH = path.join(DIRNAME, "./template/default-files");
|
|
20
|
+
const TOKEN_TEMPLATE_FILES_PATH = path.join(DIRNAME, "./template/template-files/design-tokens");
|
|
21
|
+
const TARGET_DIR = path.resolve(process.cwd(), targetDir);
|
|
22
|
+
const initialPackageName = toValidPackageName(path.basename(TARGET_DIR));
|
|
23
|
+
let isTargetDirEmpty = true;
|
|
24
|
+
try {
|
|
25
|
+
const files = await fs.readdir(TARGET_DIR);
|
|
26
|
+
isTargetDirEmpty = files.length === 0;
|
|
27
|
+
} catch (err) {
|
|
28
|
+
if (err.code === "ENOENT") {
|
|
29
|
+
} else {
|
|
30
|
+
console.error(err);
|
|
31
|
+
console.log("Continuing...");
|
|
42
32
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
value: 'clean',
|
|
51
|
-
description: 'Empty the directory and continue'
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
title: 'Ignore',
|
|
55
|
-
value: 'ignore',
|
|
56
|
-
description: 'Keep directory as is. Files may be overwritten with new output.'
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
title: 'Exit',
|
|
60
|
-
value: 'exit',
|
|
61
|
-
description: 'Exit without doing anything.'
|
|
62
|
-
}
|
|
63
|
-
]
|
|
64
|
-
}, promptOptions);
|
|
65
|
-
if (directoryAction === 'exit') {
|
|
66
|
-
process.exit();
|
|
67
|
-
}
|
|
68
|
-
const { packageName } = await prompts([
|
|
33
|
+
}
|
|
34
|
+
const { directoryAction } = await prompts(
|
|
35
|
+
{
|
|
36
|
+
name: "directoryAction",
|
|
37
|
+
type: isTargetDirEmpty ? null : "select",
|
|
38
|
+
message: "Target directory is not empty. How should we proceed?",
|
|
39
|
+
choices: [
|
|
69
40
|
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
], promptOptions);
|
|
76
|
-
const { modes, themeCount, tokensDir } = await prompts([
|
|
41
|
+
title: "Clean",
|
|
42
|
+
value: "clean",
|
|
43
|
+
description: "Empty the directory and continue"
|
|
44
|
+
},
|
|
77
45
|
{
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
initial: 1,
|
|
82
|
-
min: 1
|
|
46
|
+
title: "Ignore",
|
|
47
|
+
value: "ignore",
|
|
48
|
+
description: "Keep directory as is. Files may be overwritten with new output."
|
|
83
49
|
},
|
|
84
50
|
{
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
51
|
+
title: "Exit",
|
|
52
|
+
value: "exit",
|
|
53
|
+
description: "Exit without doing anything."
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
promptOptions
|
|
58
|
+
);
|
|
59
|
+
if (directoryAction === "exit") {
|
|
60
|
+
process.exit();
|
|
61
|
+
}
|
|
62
|
+
const { packageName } = await prompts(
|
|
63
|
+
[
|
|
64
|
+
{
|
|
65
|
+
name: "packageName",
|
|
66
|
+
type: "text",
|
|
67
|
+
message: "Enter a package name (for package.json)",
|
|
68
|
+
initial: initialPackageName
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
promptOptions
|
|
72
|
+
);
|
|
73
|
+
const { modes, themeCount, tokensDir } = await prompts(
|
|
74
|
+
[
|
|
75
|
+
{
|
|
76
|
+
name: "themeCount",
|
|
77
|
+
type: "number",
|
|
78
|
+
message: "How many themes do you want?",
|
|
79
|
+
initial: 1,
|
|
80
|
+
min: 1
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "modes",
|
|
84
|
+
type: "multiselect",
|
|
85
|
+
choices: MODES.filter((x) => x !== "Light").map((mode) => ({
|
|
86
|
+
title: mode,
|
|
87
|
+
value: mode
|
|
88
|
+
})),
|
|
89
|
+
message: "Which color modes do you want?",
|
|
90
|
+
instructions: `
|
|
93
91
|
Instructions:
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
\u2191/\u2193: Highlight option
|
|
93
|
+
\u2190/\u2192/[space]: Toggle selection
|
|
96
94
|
a: Toggle all
|
|
97
95
|
enter/return: Complete answer
|
|
98
|
-
${chalk.green(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
96
|
+
${chalk.green("\u25C9")} Light ${chalk.dim("- This is the default mode, and cannot be disabled")}`,
|
|
97
|
+
onState: (obj) => {
|
|
98
|
+
obj.value.unshift({ title: "Light", value: "Light", selected: true });
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "tokensDir",
|
|
103
|
+
type: "text",
|
|
104
|
+
initial: "design-tokens",
|
|
105
|
+
message: `Enter the desired path for the design tokens`
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
promptOptions
|
|
109
|
+
);
|
|
110
|
+
const themes = [];
|
|
111
|
+
const TOKENS_TARGET_DIR = path.join(TARGET_DIR, tokensDir);
|
|
112
|
+
for (let n = 1; n <= themeCount; n++) {
|
|
113
|
+
const theme = await prompts(
|
|
114
|
+
[
|
|
107
115
|
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
116
|
+
name: "name",
|
|
117
|
+
type: "text",
|
|
118
|
+
message: `Enter the name of the ${ordinal(n)} theme`,
|
|
119
|
+
validate: (value) => isValidThemeName(themes, value)
|
|
112
120
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
message: 'Select the default theme to export in package.json',
|
|
131
|
-
choices: themes.map((theme)=>({
|
|
132
|
-
title: theme,
|
|
133
|
-
value: theme
|
|
134
|
-
})),
|
|
135
|
-
initial: 0
|
|
136
|
-
}, promptOptions);
|
|
137
|
-
console.log(`
|
|
121
|
+
],
|
|
122
|
+
promptOptions
|
|
123
|
+
);
|
|
124
|
+
themes.push(theme.name);
|
|
125
|
+
}
|
|
126
|
+
const { defaultTheme = themes[0] } = await prompts(
|
|
127
|
+
{
|
|
128
|
+
name: "defaultTheme",
|
|
129
|
+
type: themeCount === 1 ? null : "select",
|
|
130
|
+
message: "Select the default theme to export in package.json",
|
|
131
|
+
choices: themes.map((theme) => ({ title: theme, value: theme })),
|
|
132
|
+
initial: 0
|
|
133
|
+
},
|
|
134
|
+
promptOptions
|
|
135
|
+
);
|
|
136
|
+
console.log(
|
|
137
|
+
`
|
|
138
138
|
Will now create the following:
|
|
139
|
-
${chalk.bold(
|
|
140
|
-
${chalk.bold(
|
|
141
|
-
${chalk.bold(
|
|
142
|
-
${chalk.bold(
|
|
143
|
-
${chalk.bold(
|
|
144
|
-
${chalk.bold(
|
|
145
|
-
`
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
139
|
+
${chalk.bold("Package name")}: ${packageName}
|
|
140
|
+
${chalk.bold("Directory")}: ${TARGET_DIR}
|
|
141
|
+
${chalk.bold("Tokens directory")}: ${TOKENS_TARGET_DIR}
|
|
142
|
+
${chalk.bold("Themes")}: ${themes.join(", ")}
|
|
143
|
+
${chalk.bold("Default theme")}: ${defaultTheme}
|
|
144
|
+
${chalk.bold("Color modes")}: ${modes.join(", ")}
|
|
145
|
+
`
|
|
146
|
+
);
|
|
147
|
+
if (directoryAction === "clean") {
|
|
148
|
+
console.log(chalk.bold.red(`Warning: Contents of ${TARGET_DIR} will be deleted`));
|
|
149
|
+
}
|
|
150
|
+
if (directoryAction === "ignore") {
|
|
151
|
+
console.log(chalk.bold.yellow(`Warning: Existing files in ${TARGET_DIR} may be overwritten`));
|
|
152
|
+
}
|
|
153
|
+
const res = await prompts(
|
|
154
|
+
{
|
|
155
|
+
name: "proceed",
|
|
156
|
+
type: "confirm",
|
|
157
|
+
message: "Proceed?",
|
|
158
|
+
initial: directoryAction === void 0
|
|
159
|
+
// default to proceeding if the output directory is empty
|
|
160
|
+
},
|
|
161
|
+
promptOptions
|
|
162
|
+
);
|
|
163
|
+
if (!res.proceed) {
|
|
164
|
+
process.exit();
|
|
165
|
+
}
|
|
166
|
+
if (directoryAction === "clean") {
|
|
167
|
+
await fs.rm(TARGET_DIR, { recursive: true });
|
|
168
|
+
}
|
|
169
|
+
await fs.cp(DEFAULT_FILES_PATH, path.join(TARGET_DIR), {
|
|
170
|
+
recursive: true
|
|
171
|
+
});
|
|
172
|
+
if (tokensDir !== "design-tokens") {
|
|
173
|
+
await fs.rename(path.join(TARGET_DIR, "design-tokens"), path.join(TOKENS_TARGET_DIR));
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
await fs.mkdir(path.join(TOKENS_TARGET_DIR, "themes"));
|
|
177
|
+
} catch {
|
|
178
|
+
}
|
|
179
|
+
for (const theme of themes.map(normalizeTokenSetName)) {
|
|
180
|
+
for (const mode of modes.map(normalizeTokenSetName)) {
|
|
181
|
+
await fs.cp(
|
|
182
|
+
path.join(TOKEN_TEMPLATE_FILES_PATH, `primitives/colors/${mode}/global.json`),
|
|
183
|
+
path.join(TOKENS_TARGET_DIR, `primitives/colors/${mode}/global.json`),
|
|
184
|
+
{ recursive: true }
|
|
185
|
+
);
|
|
186
|
+
const template2 = await fs.readFile(
|
|
187
|
+
path.join(TOKEN_TEMPLATE_FILES_PATH, `primitives/colors/${mode}/theme-template.json`)
|
|
188
|
+
);
|
|
189
|
+
await fs.writeFile(
|
|
190
|
+
path.join(TOKENS_TARGET_DIR, `primitives/colors/${mode}/${theme}.json`),
|
|
191
|
+
template2.toString("utf-8").replaceAll("<theme>", theme)
|
|
192
|
+
);
|
|
151
193
|
}
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
await fs.cp(path.join(TOKEN_TEMPLATE_FILES_PATH, `primitives/colors/${mode}/global.json`), path.join(TOKENS_TARGET_DIR, `primitives/colors/${mode}/global.json`), {
|
|
181
|
-
recursive: true
|
|
182
|
-
});
|
|
183
|
-
// Create theme primitives for the color mode
|
|
184
|
-
const template = await fs.readFile(path.join(TOKEN_TEMPLATE_FILES_PATH, `primitives/colors/${mode}/theme-template.json`));
|
|
185
|
-
await fs.writeFile(path.join(TOKENS_TARGET_DIR, `primitives/colors/${mode}/${theme}.json`), template.toString('utf-8').replaceAll('<theme>', theme));
|
|
186
|
-
}
|
|
187
|
-
// Create main theme token set
|
|
188
|
-
const template = await fs.readFile(path.join(TOKEN_TEMPLATE_FILES_PATH, `themes/theme-template.json`));
|
|
189
|
-
await fs.writeFile(path.join(TOKENS_TARGET_DIR, `themes/${theme}.json`), template.toString('utf-8').replaceAll('<theme>', theme));
|
|
190
|
-
await fs.writeFile(path.join(TOKENS_TARGET_DIR, '$metadata.json'), JSON.stringify(generateMetadata(modes, themes), undefined, 2));
|
|
191
|
-
await fs.writeFile(path.join(TOKENS_TARGET_DIR, '$themes.json'), JSON.stringify(generateThemes(modes, themes), undefined, 2));
|
|
192
|
-
}
|
|
193
|
-
// Configure package.json file
|
|
194
|
-
packageJsonTemplate.name = packageName;
|
|
195
|
-
packageJsonTemplate.main = packageJsonTemplate.main.replace('<default-theme>', toGeneratedCssFileName(defaultTheme));
|
|
196
|
-
await fs.writeFile(path.join(TARGET_DIR, 'package.json'), JSON.stringify(packageJsonTemplate, undefined, 2));
|
|
197
|
-
const readmePath = path.join(TARGET_DIR, 'README.md');
|
|
198
|
-
const currentReadme = await fs.readFile(readmePath);
|
|
199
|
-
await fs.writeFile(readmePath, [
|
|
200
|
-
currentReadme.toString('utf-8'),
|
|
201
|
-
nextStepsMarkdown(themes, modes, tokensDir, packageName)
|
|
202
|
-
].join('\n'));
|
|
203
|
-
console.log('🎉 Files successfully generated!');
|
|
204
|
-
console.log(`Read about the next steps in the generated README at ${readmePath}`);
|
|
194
|
+
const template = await fs.readFile(path.join(TOKEN_TEMPLATE_FILES_PATH, `themes/theme-template.json`));
|
|
195
|
+
await fs.writeFile(
|
|
196
|
+
path.join(TOKENS_TARGET_DIR, `themes/${theme}.json`),
|
|
197
|
+
template.toString("utf-8").replaceAll("<theme>", theme)
|
|
198
|
+
);
|
|
199
|
+
await fs.writeFile(
|
|
200
|
+
path.join(TOKENS_TARGET_DIR, "$metadata.json"),
|
|
201
|
+
JSON.stringify(generateMetadata(modes, themes), void 0, 2)
|
|
202
|
+
);
|
|
203
|
+
await fs.writeFile(
|
|
204
|
+
path.join(TOKENS_TARGET_DIR, "$themes.json"),
|
|
205
|
+
JSON.stringify(generateThemes(modes, themes), void 0, 2)
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
packageJsonTemplate.name = packageName;
|
|
209
|
+
packageJsonTemplate.main = packageJsonTemplate.main.replaceAll(
|
|
210
|
+
"<default-theme>",
|
|
211
|
+
toGeneratedCssFileName(defaultTheme)
|
|
212
|
+
);
|
|
213
|
+
await fs.writeFile(path.join(TARGET_DIR, "package.json"), JSON.stringify(packageJsonTemplate, void 0, 2));
|
|
214
|
+
const readmePath = path.join(TARGET_DIR, "README.md");
|
|
215
|
+
const currentReadme = await fs.readFile(readmePath);
|
|
216
|
+
await fs.writeFile(
|
|
217
|
+
readmePath,
|
|
218
|
+
[currentReadme.toString("utf-8"), nextStepsMarkdown(themes, modes, tokensDir, packageName)].join("\n")
|
|
219
|
+
);
|
|
220
|
+
console.log("\u{1F389} Files successfully generated!");
|
|
221
|
+
console.log(`Read about the next steps in the generated README at ${readmePath}`);
|
|
205
222
|
}
|
|
206
223
|
function isValidThemeName(themes, value) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
224
|
+
const s = value.trim();
|
|
225
|
+
if (s.length === 0) {
|
|
226
|
+
return "Theme name cannot be empty.";
|
|
227
|
+
}
|
|
228
|
+
if (themes.includes(s)) {
|
|
229
|
+
return "Theme names must be unique.";
|
|
230
|
+
}
|
|
231
|
+
if (/[^a-zæøå0-9 _-]/i.test(s)) {
|
|
232
|
+
return "Theme name can only contain letters, numbers, dashes and underscores.";
|
|
233
|
+
}
|
|
234
|
+
return true;
|
|
218
235
|
}
|
|
219
236
|
function ordinal(n) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
237
|
+
switch (n) {
|
|
238
|
+
case 1:
|
|
239
|
+
return "1st";
|
|
240
|
+
case 2:
|
|
241
|
+
return "2nd";
|
|
242
|
+
case 3:
|
|
243
|
+
return "3rd";
|
|
244
|
+
default:
|
|
245
|
+
return `${n}th`;
|
|
246
|
+
}
|
|
230
247
|
}
|
|
248
|
+
export {
|
|
249
|
+
createTokensPackage
|
|
250
|
+
};
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { normalizeTokenSetName } from "./utils.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
function generateMetadataJson(modes, themes) {
|
|
3
|
+
return {
|
|
4
|
+
tokenSetOrder: [
|
|
5
|
+
"primitives/globals",
|
|
6
|
+
"primitives/typography/default",
|
|
7
|
+
...modes.flatMap((mode) => [
|
|
8
|
+
`primitives/colors/${normalizeTokenSetName(mode)}/global`,
|
|
9
|
+
...themes.map(
|
|
10
|
+
(theme) => `primitives/colors/${normalizeTokenSetName(mode)}/${normalizeTokenSetName(theme)}`
|
|
11
|
+
)
|
|
12
|
+
]),
|
|
13
|
+
...themes.map((theme) => `themes/${normalizeTokenSetName(theme)}`),
|
|
14
|
+
"semantic/color",
|
|
15
|
+
"semantic/style"
|
|
16
|
+
]
|
|
17
|
+
};
|
|
16
18
|
}
|
|
19
|
+
export {
|
|
20
|
+
generateMetadataJson as default
|
|
21
|
+
};
|
|
@@ -1,50 +1,59 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { TokenSetStatus } from "@tokens-studio/types";
|
|
3
3
|
import { normalizeTokenSetName } from "./utils.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
function generateThemesJson(modes, themes) {
|
|
5
|
+
return [
|
|
6
|
+
...generateModesGroup(modes, themes),
|
|
7
|
+
...generateThemesGroup(themes),
|
|
8
|
+
generateSemanticGroup()
|
|
9
|
+
];
|
|
10
10
|
}
|
|
11
11
|
function generateModesGroup(modes, themes) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
return modes.map(
|
|
13
|
+
(mode) => ({
|
|
14
|
+
id: randomUUID(),
|
|
15
|
+
name: mode,
|
|
16
|
+
selectedTokenSets: Object.fromEntries([
|
|
17
|
+
[
|
|
18
|
+
`primitives/colors/${normalizeTokenSetName(mode)}/global`,
|
|
19
|
+
TokenSetStatus.ENABLED
|
|
20
|
+
],
|
|
21
|
+
...themes.map(
|
|
22
|
+
(theme) => [
|
|
23
|
+
`primitives/colors/${normalizeTokenSetName(mode)}/${normalizeTokenSetName(theme)}`,
|
|
24
|
+
TokenSetStatus.ENABLED
|
|
25
|
+
]
|
|
26
|
+
)
|
|
27
|
+
]),
|
|
28
|
+
group: "Mode"
|
|
29
|
+
})
|
|
30
|
+
);
|
|
27
31
|
}
|
|
28
32
|
function generateThemesGroup(themes) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
return themes.map(
|
|
34
|
+
(theme) => ({
|
|
35
|
+
id: randomUUID(),
|
|
36
|
+
name: theme,
|
|
37
|
+
selectedTokenSets: {
|
|
38
|
+
[`themes/${normalizeTokenSetName(theme)}`]: TokenSetStatus.ENABLED
|
|
39
|
+
},
|
|
40
|
+
group: "Theme"
|
|
41
|
+
})
|
|
42
|
+
);
|
|
37
43
|
}
|
|
38
44
|
function generateSemanticGroup() {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
return {
|
|
46
|
+
id: randomUUID(),
|
|
47
|
+
name: "Semantic",
|
|
48
|
+
selectedTokenSets: {
|
|
49
|
+
"semantic/style": TokenSetStatus.ENABLED,
|
|
50
|
+
"semantic/color": TokenSetStatus.ENABLED,
|
|
51
|
+
"primitives/globals": TokenSetStatus.SOURCE,
|
|
52
|
+
"primitives/typography/default": TokenSetStatus.SOURCE
|
|
53
|
+
},
|
|
54
|
+
group: "Semantic"
|
|
55
|
+
};
|
|
50
56
|
}
|
|
57
|
+
export {
|
|
58
|
+
generateThemesJson as default
|
|
59
|
+
};
|
package/dist/src/init/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Argument } from "@commander-js/extra-typings";
|
|
2
2
|
import { createTokensPackage } from "./createTokensPackage.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
function makeInitCommand(command) {
|
|
4
|
+
return command.showHelpAfterError().description("create an initial token structure for Designsystemet").addArgument(new Argument("<targetDir>", "Target directory for the generated code")).action(async (targetDir) => {
|
|
5
|
+
await createTokensPackage(targetDir);
|
|
6
|
+
});
|
|
7
7
|
}
|
|
8
|
+
export {
|
|
9
|
+
makeInitCommand
|
|
10
|
+
};
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { normalizeTokenSetName, toGeneratedCssFileName } from "./utils.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return `
|
|
2
|
+
function nextStepsMarkdown(themes, modes, tokensTargetDir, packageName) {
|
|
3
|
+
const themeModeCombinations = themes.flatMap(
|
|
4
|
+
(theme) => modes.map((mode) => [theme, mode])
|
|
5
|
+
);
|
|
6
|
+
const themeOrThemes = `theme${themes.length > 1 ? "s" : ""}`;
|
|
7
|
+
const isOrAre = themes.length > 1 ? "are" : "is";
|
|
8
|
+
return `
|
|
10
9
|
## Next steps
|
|
11
10
|
|
|
12
11
|
### Using the ${themeOrThemes} in Figma
|
|
@@ -23,14 +22,14 @@ export function nextStepsMarkdown(themes, modes, tokensTargetDir, packageName) {
|
|
|
23
22
|
|
|
24
23
|
1. Go to https://theme.designsystemet.no and set up a color theme
|
|
25
24
|
2. Press "Kopier tema"
|
|
26
|
-
3. Under "Json til Figma", copy the contents under ${modes.join(
|
|
25
|
+
3. Under "Json til Figma", copy the contents under ${modes.join(" / ")} to
|
|
27
26
|
the corresponding file under \`${tokensTargetDir}\`:
|
|
28
|
-
${themeModeCombinations.map(([theme, mode])
|
|
27
|
+
${themeModeCombinations.map(([theme, mode]) => ` **${theme}, ${mode}**: \`primitives/colors/${normalizeTokenSetName(mode)}/${normalizeTokenSetName(theme)}.json\` `).join("\n")}
|
|
29
28
|
This can also be done in Tokens Studio for Figma.
|
|
30
29
|
4. **IMPORTANT!** In the JSON data you copied, replace \`theme\` on line 2
|
|
31
30
|
with the correct theme identifier, depending on the theme you're customizing.
|
|
32
|
-
This is the same as the json filename without extension (e.g. ${themes.map((x)
|
|
33
|
-
${themes.length > 1 ?
|
|
31
|
+
This is the same as the json filename without extension (e.g. ${themes.map((x) => `\`${normalizeTokenSetName(x)}\``).join(", ")}).
|
|
32
|
+
${themes.length > 1 ? "5. Repeat steps 1\u20144 for the remaining themes" : ""}
|
|
34
33
|
|
|
35
34
|
### Using the correct ${themeOrThemes} in Figma components
|
|
36
35
|
|
|
@@ -86,5 +85,8 @@ ${themes.length > 1 ? `
|
|
|
86
85
|
\`\`\`js
|
|
87
86
|
import '${packageName}/${toGeneratedCssFileName(themes[1])}';
|
|
88
87
|
\`\`\`
|
|
89
|
-
`.trim() :
|
|
88
|
+
`.trim() : ""}`;
|
|
90
89
|
}
|
|
90
|
+
export {
|
|
91
|
+
nextStepsMarkdown
|
|
92
|
+
};
|