@skbkontur/colors 2.0.1 → 2.0.2

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 (44) hide show
  1. package/lib/get-colors.js +19 -1
  2. package/lib/get-colors.ts +9 -1
  3. package/package.json +2 -2
  4. package/tokens-mobile/brand-blue-deep_accent-brand.json +117 -117
  5. package/tokens-mobile/brand-blue-deep_accent-gray.json +135 -135
  6. package/tokens-mobile/brand-blue_accent-brand.json +117 -117
  7. package/tokens-mobile/brand-blue_accent-gray.json +135 -135
  8. package/tokens-mobile/brand-green_accent-brand.json +117 -117
  9. package/tokens-mobile/brand-green_accent-gray.json +135 -135
  10. package/tokens-mobile/brand-mint_accent-brand.json +117 -117
  11. package/tokens-mobile/brand-mint_accent-gray.json +135 -135
  12. package/tokens-mobile/brand-orange_accent-gray.json +135 -135
  13. package/tokens-mobile/brand-purple_accent-brand.json +117 -117
  14. package/tokens-mobile/brand-purple_accent-gray.json +135 -135
  15. package/tokens-mobile/brand-red_accent-gray.json +135 -135
  16. package/tokens-mobile/brand-violet_accent-brand.json +117 -117
  17. package/tokens-mobile/brand-violet_accent-gray.json +135 -135
  18. package/.gitignore +0 -10
  19. package/.npmignore +0 -10
  20. package/CHANGELOG.md +0 -117
  21. package/__docs__/Colors.docs.stories.tsx +0 -1578
  22. package/__docs__/Colors.mdx +0 -228
  23. package/__docs__/ColorsAPI.docs.stories.tsx +0 -954
  24. package/__docs__/ColorsAPI.mdx +0 -133
  25. package/__stories__/colors.stories.tsx +0 -452
  26. package/__tests__/convert-color.test.ts +0 -23
  27. package/__tests__/create-tokens-from-figma.test.ts +0 -162
  28. package/__tests__/format-variable.test.ts +0 -16
  29. package/__tests__/get-colors-base.test.ts +0 -55
  30. package/__tests__/get-colors.test.ts +0 -75
  31. package/__tests__/get-interactions.test.ts +0 -37
  32. package/__tests__/get-logo.test.ts +0 -24
  33. package/__tests__/get-palette.test.ts +0 -43
  34. package/__tests__/get-promo.test.ts +0 -32
  35. package/colors-default-dark.ts +0 -332
  36. package/colors-default-light.ts +0 -336
  37. package/colors.less +0 -319
  38. package/colors.scss +0 -319
  39. package/colors.ts +0 -319
  40. package/scripts/create-tokens-files.ts +0 -424
  41. package/scripts/create-tokens-from-figma.ts +0 -376
  42. package/scripts/figma-tokens-base.json +0 -3499
  43. package/scripts/figma-tokens.json +0 -710
  44. package/tsconfig.json +0 -8
@@ -1,376 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
-
4
- import { customizable } from '../lib/consts/default-swatch';
5
-
6
- interface Value {
7
- light: string;
8
- dark: string;
9
- }
10
-
11
- type Input = Record<string, string>;
12
- type Groups = Record<string, Partial<Value>>;
13
- type Output = Record<string, Value>;
14
- type Entries = Array<[string, Value]>;
15
-
16
- interface Rule {
17
- rule: string;
18
- fn: (data: any) => any;
19
- }
20
-
21
- const INPUT_FIGMA_BASE_PATH = path.join(import.meta.dirname, 'figma-tokens-base.json');
22
- const INPUT_FIGMA_SEMANTIC_PATH = path.join(import.meta.dirname, 'figma-tokens.json');
23
- const OUTPUT_TOKENS_PATH = './lib/get-colors-default-tokens.ts';
24
- const TOKENS_BASE_MAP: Record<string, string> = JSON.parse(fs.readFileSync(INPUT_FIGMA_BASE_PATH, 'utf-8'));
25
-
26
- export const transformations: Rule[] = [
27
- {
28
- rule: 'Filter',
29
- fn: (inputMap: Input): Input => {
30
- const MANUAL_PATTERNS: RegExp[] = [];
31
- const filtered: Input = {};
32
- for (const [key, value] of Object.entries(inputMap)) {
33
- if (key.startsWith('Effect/')) {
34
- continue;
35
- }
36
- if (MANUAL_PATTERNS.some((pattern) => pattern.test(value))) {
37
- continue;
38
- }
39
- if (value.includes('rgba(') || value.includes('#')) {
40
- continue;
41
- }
42
- filtered[key] = value;
43
- }
44
- return filtered;
45
- },
46
- },
47
- {
48
- rule: 'Group by Theme',
49
- fn: (inputMap: Input): Groups => {
50
- const groups: Groups = {};
51
- for (const [key, value] of Object.entries(inputMap)) {
52
- const parts = key.split(' / ');
53
- const theme = parts.pop()?.toLowerCase() as 'light' | 'dark';
54
- const baseName = parts.join(' / ');
55
-
56
- if (!theme || !['light', 'dark'].includes(theme)) {
57
- continue;
58
- }
59
-
60
- if (!groups[baseName]) {
61
- groups[baseName] = {};
62
- }
63
- groups[baseName][theme] = value;
64
- }
65
-
66
- for (const baseName in groups) {
67
- if (!groups[baseName].light || !groups[baseName].dark) {
68
- delete groups[baseName];
69
- }
70
- }
71
- return groups;
72
- },
73
- },
74
- {
75
- rule: 'Reorder States',
76
- fn: (groups: Groups): Groups => {
77
- const STATE_SUFFIXES = ['Hover', 'Pressed', 'Disabled'];
78
- const reordered: Groups = {};
79
-
80
- for (const [baseName, values] of Object.entries(groups)) {
81
- const parts: string[] = baseName.split('/');
82
- let newParts = [...parts];
83
-
84
- const state = parts.find((p: string) => STATE_SUFFIXES.includes(p));
85
-
86
- if (state) {
87
- newParts = parts.filter((p: string) => p !== state);
88
- newParts.push(state);
89
- }
90
-
91
- reordered[newParts.join('/')] = values;
92
- }
93
- return reordered;
94
- },
95
- },
96
- {
97
- rule: 'Apply Naming',
98
- fn: (groups: Groups): Output => {
99
- const output: Output = {};
100
- for (const [baseName, values] of Object.entries(groups)) {
101
- const tokenPath = baseName;
102
- output[slashToCamelCase(tokenPath)] = values as Value;
103
- }
104
- return output;
105
- },
106
- },
107
- {
108
- rule: 'Map to BaseTokens',
109
- fn: (tokens: Output): Output => {
110
- const CUSTOMIZABLE_KEYS = Object.keys(customizable);
111
- const DIRECT_SCALE_BASE_NAMES = ['onbrand', 'gray', 'whitealpha', 'blackalpha'];
112
-
113
- const transformToken = (rawValue: string): string => {
114
- const parts = rawValue.split('/');
115
- if (parts.length >= 2) {
116
- const last = parts[parts.length - 1];
117
- const path = parts.slice(0, -1);
118
- const mainPart = path[0];
119
- const camelMainPart = slashToCamelCase(mainPart);
120
- let expression: string = CUSTOMIZABLE_KEYS.includes(camelMainPart) ? 'base.customizable' : 'base';
121
-
122
- for (const part of path) {
123
- const camelPart = slashToCamelCase(part);
124
-
125
- if (part === mainPart && expression === 'base') {
126
- if (camelPart === 'brand') {
127
- expression += '.' + camelPart + '.palette?';
128
- continue;
129
- } else if (camelPart === 'accent') {
130
- expression += '.' + camelPart + '?.palette?';
131
- continue;
132
- } else if (camelPart === 'onAccent') {
133
- expression += '.onAccent';
134
- continue;
135
- } else if (DIRECT_SCALE_BASE_NAMES.includes(camelPart)) {
136
- expression += '.' + camelPart;
137
- continue;
138
- }
139
- }
140
-
141
- expression += '.' + camelPart;
142
- }
143
-
144
- const lastIsNumber = last.match(/^\d+$/);
145
- if (lastIsNumber) {
146
- const isIndexAfterOptionalBase = camelMainPart === 'onAccent' && path.length === 1;
147
-
148
- if (isIndexAfterOptionalBase) {
149
- expression += `?.[${last}]`;
150
- } else {
151
- expression += `[${last}]`;
152
- }
153
- } else {
154
- expression += '.' + last.toLowerCase();
155
- }
156
- return expression;
157
- }
158
- return rawValue;
159
- };
160
-
161
- const valueToExpression = (value: string): string => {
162
- let rawValue = value;
163
- const camelValue = slashToCamelCase(rawValue);
164
-
165
- if (/^Light\//.test(rawValue) || /^Dark\//.test(rawValue)) {
166
- const brandValue = TOKENS_BASE_MAP[`${rawValue.replace(/'/g, '')} / Brand`];
167
- const grayValue = TOKENS_BASE_MAP[`${rawValue.replace(/'/g, '')} / Gray`];
168
-
169
- rawValue = `${brandValue.replace('Brand', 'Accent')} || ${grayValue}`;
170
- }
171
-
172
- return rawValue
173
- .split(' || ')
174
- .map((item: string) => {
175
- if (CUSTOMIZABLE_KEYS.includes(camelValue)) {
176
- return `base.customizable.${camelValue}`;
177
- }
178
-
179
- if (item === 'Brand/Normal/0') {
180
- return 'base.brand.promo';
181
- }
182
-
183
- if (item === 'Brand/Normal/100') {
184
- return 'base.brand.original';
185
- }
186
-
187
- if (item.includes('Semantic Tokens/Light') && item.includes('Logo')) {
188
- return 'base.brand.logo.light';
189
- }
190
- if (item.includes('Semantic Tokens/Dark') && item.includes('Logo')) {
191
- return 'base.brand.logo.dark';
192
- }
193
-
194
- if (item.includes('Brand')) {
195
- if (item.includes('Semantic Tokens/Light') && item.includes('Default')) {
196
- return 'base.brand.original';
197
- }
198
-
199
- if (item.includes('Semantic Tokens/Dark') && item.includes('Default')) {
200
- return 'base.brand.original';
201
- }
202
-
203
- if (item.includes('Semantic Tokens/Light') && item.includes('Hover')) {
204
- return 'base.brand.interactions.hover.light';
205
- }
206
-
207
- if (item.includes('Semantic Tokens/Dark') && item.includes('Hover')) {
208
- return 'base.brand.interactions.hover.dark';
209
- }
210
-
211
- if (item.includes('Semantic Tokens/Light') && item.includes('Pressed')) {
212
- return 'base.brand.interactions.pressed.light';
213
- }
214
-
215
- if (item.includes('Semantic Tokens/Dark') && item.includes('Pressed')) {
216
- return 'base.brand.interactions.pressed.dark';
217
- }
218
- }
219
-
220
- if (item.includes('Accent')) {
221
- if (item.includes('Semantic Tokens/Light') && item.includes('Default')) {
222
- return 'base.accent?.original.light';
223
- }
224
-
225
- if (item.includes('Semantic Tokens/Dark') && item.includes('Default')) {
226
- return 'base.accent?.original.dark';
227
- }
228
-
229
- if (item.includes('Semantic Tokens/Light') && item.includes('Hover')) {
230
- return 'base.accent?.interactions.hover.light';
231
- }
232
-
233
- if (item.includes('Semantic Tokens/Dark') && item.includes('Hover')) {
234
- return 'base.accent?.interactions.hover.dark';
235
- }
236
-
237
- if (item.includes('Semantic Tokens/Light') && item.includes('Pressed')) {
238
- return 'base.accent?.interactions.pressed.light';
239
- }
240
-
241
- if (item.includes('Semantic Tokens/Dark') && item.includes('Pressed')) {
242
- return 'base.accent?.interactions.pressed.dark';
243
- }
244
- }
245
-
246
- return transformToken(item);
247
- })
248
- .join(' || ');
249
- };
250
-
251
- const result: Output = {};
252
- for (const [key, values] of Object.entries(tokens)) {
253
- result[key] = {
254
- light: valueToExpression(values.light),
255
- dark: valueToExpression(values.dark),
256
- };
257
- }
258
- return result;
259
- },
260
- },
261
- {
262
- rule: 'Sort Keys',
263
- fn: (tokens: Output): Entries => {
264
- const SORT_ORDER = [
265
- 'text',
266
- 'texInverted',
267
- 'textConst',
268
- 'textOnAccent',
269
- 'textOnBrand',
270
- 'shape',
271
- 'shapeInverted',
272
- 'shapeConst',
273
- 'line',
274
- 'lineInverted',
275
- 'lineConst',
276
- 'surface',
277
- 'illustration',
278
- 'customizable',
279
- ];
280
-
281
- const getSortIndex = (key: string): number => {
282
- let bestIndex = SORT_ORDER.length;
283
- let longestMatchLength = 0;
284
-
285
- for (let i = 0; i < SORT_ORDER.length; i++) {
286
- const prefix = SORT_ORDER[i];
287
- const index = i;
288
-
289
- if (key.startsWith(prefix)) {
290
- if (key === prefix) {
291
- return index;
292
- }
293
-
294
- if (prefix.length > longestMatchLength) {
295
- longestMatchLength = prefix.length;
296
- bestIndex = index;
297
- }
298
- }
299
- }
300
- return bestIndex;
301
- };
302
-
303
- return Object.entries(tokens).sort(([keyA], [keyB]) => {
304
- const indexA = getSortIndex(keyA);
305
- const indexB = getSortIndex(keyB);
306
-
307
- if (indexA !== indexB) {
308
- return indexA - indexB;
309
- }
310
- return keyA.localeCompare(keyB);
311
- }) as Entries;
312
- },
313
- },
314
- {
315
- rule: 'Generate Code',
316
- fn: (sorted: Entries): string => {
317
- const generateBody = (theme: 'light' | 'dark') =>
318
- sorted
319
- .map(([key, values], i) => ` ${key}: ${values[theme]}${i === sorted.length - 1 ? '' : ','}`)
320
- .join('\n');
321
-
322
- const lightBody = generateBody('light');
323
- const darkBody = generateBody('dark');
324
-
325
- return `import type { TokensBase } from './types/tokens-base.js';
326
-
327
- export const getColorsDefaultTokens = (base: TokensBase) => ({
328
- light: {
329
- ${lightBody}
330
- },
331
- dark: {
332
- ${darkBody}
333
- }
334
- });
335
- `;
336
- },
337
- },
338
- ];
339
-
340
- try {
341
- const inputData = JSON.parse(fs.readFileSync(INPUT_FIGMA_SEMANTIC_PATH, 'utf-8')) as Input;
342
- fs.writeFileSync(OUTPUT_TOKENS_PATH, extractTokensFromFigma(inputData));
343
- } catch (error) {
344
- console.error('An error occurred during token transformation:', error);
345
- }
346
-
347
- export function extractTokensFromFigma(figmaJson: Input): string {
348
- let currentData: any = figmaJson;
349
- for (const rule of transformations) {
350
- currentData = rule.fn(currentData);
351
- }
352
- return currentData as string;
353
- }
354
-
355
- export function slashToCamelCase(str: string): string {
356
- let processedStr = str.replace(/onbrand/gi, 'On Brand');
357
- processedStr = processedStr.replace(/[/-]/g, ' ');
358
- processedStr = processedStr.replace(/([a-z])([A-Z])/g, '$1 $2');
359
- const parts = processedStr.split(/\s+/).filter(Boolean);
360
-
361
- if (parts.length === 0) {
362
- return '';
363
- }
364
-
365
- return parts
366
- .map((part, index) => {
367
- const lowerPart = part.toLowerCase();
368
-
369
- if (index === 0) {
370
- return lowerPart;
371
- }
372
-
373
- return lowerPart.charAt(0).toUpperCase() + lowerPart.slice(1);
374
- })
375
- .join('');
376
- }