@kiva/kv-tokens 4.0.0 → 4.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.
- package/package.json +5 -4
- package/build/build-dtcg.js +0 -31
- package/build/build.js +0 -23
- package/build/dtcg-merge.js +0 -60
- package/build/dtcg-merge.test.js +0 -140
- package/build/formats/css-themes.js +0 -60
- package/build/formats/js-tokens.js +0 -91
- package/build/style-dictionary.config.js +0 -45
- package/build/transforms/dimension-to-number.js +0 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kiva/kv-tokens",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"configs/",
|
|
25
25
|
"dist/",
|
|
26
26
|
"assets/",
|
|
27
|
-
"build/",
|
|
28
27
|
"tokens/"
|
|
29
28
|
],
|
|
30
29
|
"scripts": {
|
|
@@ -45,8 +44,10 @@
|
|
|
45
44
|
"homepage": "https://github.com/kiva/kv-ui-elements/tree/main/%40kiva/kv-tokens#readme",
|
|
46
45
|
"dependencies": {
|
|
47
46
|
"@tailwindcss/typography": "^0.5.1",
|
|
48
|
-
"style-dictionary": "^4.4.0",
|
|
49
47
|
"tailwindcss": "^3.4.3"
|
|
50
48
|
},
|
|
51
|
-
"
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"style-dictionary": "^4.4.0"
|
|
51
|
+
},
|
|
52
|
+
"gitHead": "c36f55448e2b6a170321908075aec0176d22ca57"
|
|
52
53
|
}
|
package/build/build-dtcg.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// Emits dist/dtcg/tokens.json — a single deep-merged DTCG manifest of every
|
|
2
|
-
// source token under tokens/. Aliases (e.g. "{color.brand.DEFAULT}") and
|
|
3
|
-
// $type/$description metadata are preserved verbatim so external consumers
|
|
4
|
-
// (Figma plugins, alternative build pipelines, agent reference docs) get
|
|
5
|
-
// the canonical authored shape, not a transformed view of it.
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
mkdirSync, readFileSync, writeFileSync,
|
|
9
|
-
} from 'node:fs';
|
|
10
|
-
import { dirname, join, relative } from 'node:path';
|
|
11
|
-
import { fileURLToPath } from 'node:url';
|
|
12
|
-
|
|
13
|
-
import { findJsonFiles, mergeTokens } from './dtcg-merge.js';
|
|
14
|
-
|
|
15
|
-
const PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
16
|
-
const TOKENS_DIR = join(PACKAGE_ROOT, 'tokens');
|
|
17
|
-
const OUT_DIR = join(PACKAGE_ROOT, 'dist', 'dtcg');
|
|
18
|
-
const OUT_FILE = join(OUT_DIR, 'tokens.json');
|
|
19
|
-
|
|
20
|
-
const files = findJsonFiles(TOKENS_DIR);
|
|
21
|
-
const sources = files.map((path) => ({
|
|
22
|
-
path: relative(PACKAGE_ROOT, path),
|
|
23
|
-
contents: JSON.parse(readFileSync(path, 'utf8')),
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
const merged = mergeTokens(sources);
|
|
27
|
-
|
|
28
|
-
mkdirSync(OUT_DIR, { recursive: true });
|
|
29
|
-
writeFileSync(OUT_FILE, `${JSON.stringify(merged, null, '\t')}\n`, 'utf8');
|
|
30
|
-
|
|
31
|
-
process.stdout.write(`dtcg: wrote ${relative(PACKAGE_ROOT, OUT_FILE)} from ${files.length} source files\n`);
|
package/build/build.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import { generateExternalSVG } from '../configs/kivaHeadingUnderline.js';
|
|
3
|
-
|
|
4
|
-
// Note: dir is relative to the root of the kv-tokens package
|
|
5
|
-
const dir = '../../dist/kvui';
|
|
6
|
-
|
|
7
|
-
// Create dist folder
|
|
8
|
-
if (!fs.existsSync(dir)) {
|
|
9
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Copy fonts to dist folder
|
|
13
|
-
const fontsDir = './assets/fonts';
|
|
14
|
-
const fontFiles = fs.readdirSync(fontsDir).filter((file) => file.endsWith('.woff2'));
|
|
15
|
-
fontFiles.forEach((file) => {
|
|
16
|
-
const srcPath = `${fontsDir}/${file}`;
|
|
17
|
-
const destPath = `${dir}/${file}`;
|
|
18
|
-
fs.copyFileSync(srcPath, destPath);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// Generate Heading Underline SVG
|
|
22
|
-
const svg = generateExternalSVG();
|
|
23
|
-
fs.writeFileSync(`${dir}/heading-underline.svg`, svg);
|
package/build/dtcg-merge.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Pure merge logic for the raw DTCG manifest. Kept side-effect free so the
|
|
2
|
-
// CLI wrapper (build-dtcg.js) and the test suite share the same code path.
|
|
3
|
-
|
|
4
|
-
import { readdirSync, statSync } from 'node:fs';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
-
|
|
7
|
-
const isLeaf = (node) => node && typeof node === 'object' && '$value' in node;
|
|
8
|
-
|
|
9
|
-
export function findJsonFiles(rootDir) {
|
|
10
|
-
const out = [];
|
|
11
|
-
const walk = (dir) => {
|
|
12
|
-
readdirSync(dir).forEach((entry) => {
|
|
13
|
-
const full = join(dir, entry);
|
|
14
|
-
if (statSync(full).isDirectory()) {
|
|
15
|
-
walk(full);
|
|
16
|
-
} else if (entry.endsWith('.json')) {
|
|
17
|
-
out.push(full);
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
walk(rootDir);
|
|
22
|
-
return out.sort();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Deep-merges DTCG token sources into a single object. Throws if two source
|
|
26
|
-
// files both define a leaf at the same path — the canonical source must not
|
|
27
|
-
// have ambiguous duplicates.
|
|
28
|
-
export function mergeTokens(sources) {
|
|
29
|
-
const out = {};
|
|
30
|
-
const provenance = new Map();
|
|
31
|
-
|
|
32
|
-
const walk = (node, path, fromFile) => {
|
|
33
|
-
if (isLeaf(node)) {
|
|
34
|
-
const pathKey = path.join('.');
|
|
35
|
-
if (provenance.has(pathKey)) {
|
|
36
|
-
throw new Error(
|
|
37
|
-
`Leaf token collision at "${pathKey}" — defined in both `
|
|
38
|
-
+ `${provenance.get(pathKey)} and ${fromFile}`,
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
let cursor = out;
|
|
42
|
-
for (let i = 0; i < path.length - 1; i += 1) {
|
|
43
|
-
cursor[path[i]] = cursor[path[i]] ?? {};
|
|
44
|
-
cursor = cursor[path[i]];
|
|
45
|
-
}
|
|
46
|
-
cursor[path[path.length - 1]] = node;
|
|
47
|
-
provenance.set(pathKey, fromFile);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
if (node && typeof node === 'object' && !Array.isArray(node)) {
|
|
51
|
-
Object.keys(node).forEach((key) => walk(node[key], [...path, key], fromFile));
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
sources.forEach(({ path, contents }) => {
|
|
56
|
-
walk(contents, [], path);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
return out;
|
|
60
|
-
}
|
package/build/dtcg-merge.test.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test';
|
|
2
|
-
import { strict as assert } from 'node:assert';
|
|
3
|
-
|
|
4
|
-
import { mergeTokens } from './dtcg-merge.js';
|
|
5
|
-
|
|
6
|
-
test('merges disjoint top-level keys from multiple sources', () => {
|
|
7
|
-
const result = mergeTokens([
|
|
8
|
-
{
|
|
9
|
-
path: 'a.json',
|
|
10
|
-
contents: { color: { red: { $type: 'color', $value: '#f00' } } },
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
path: 'b.json',
|
|
14
|
-
contents: {
|
|
15
|
-
space: { 1: { $type: 'dimension', $value: { value: 4, unit: 'px' } } },
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
]);
|
|
19
|
-
|
|
20
|
-
assert.equal(result.color.red.$value, '#f00');
|
|
21
|
-
assert.equal(result.space[1].$value.value, 4);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('merges nested keys at the same branch without collision', () => {
|
|
25
|
-
const result = mergeTokens([
|
|
26
|
-
{
|
|
27
|
-
path: 'theme-default.json',
|
|
28
|
-
contents: {
|
|
29
|
-
theme: { DEFAULT: { text: { primary: { $type: 'color', $value: '#000' } } } },
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
path: 'theme-dark.json',
|
|
34
|
-
contents: {
|
|
35
|
-
theme: { dark: { text: { primary: { $type: 'color', $value: '#fff' } } } },
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
]);
|
|
39
|
-
|
|
40
|
-
assert.equal(result.theme.DEFAULT.text.primary.$value, '#000');
|
|
41
|
-
assert.equal(result.theme.dark.text.primary.$value, '#fff');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('preserves alias references as literal strings', () => {
|
|
45
|
-
const result = mergeTokens([
|
|
46
|
-
{
|
|
47
|
-
path: 'core.json',
|
|
48
|
-
contents: { color: { brand: { $type: 'color', $value: '#2AA967' } } },
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
path: 'semantic.json',
|
|
52
|
-
contents: {
|
|
53
|
-
theme: { DEFAULT: { primary: { $type: 'color', $value: '{color.brand}' } } },
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
]);
|
|
57
|
-
|
|
58
|
-
assert.equal(result.theme.DEFAULT.primary.$value, '{color.brand}');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('preserves $type and $description metadata', () => {
|
|
62
|
-
const result = mergeTokens([
|
|
63
|
-
{
|
|
64
|
-
path: 'a.json',
|
|
65
|
-
contents: {
|
|
66
|
-
color: {
|
|
67
|
-
red: {
|
|
68
|
-
$type: 'color',
|
|
69
|
-
$value: '#f00',
|
|
70
|
-
$description: 'danger signal',
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
]);
|
|
76
|
-
|
|
77
|
-
assert.equal(result.color.red.$type, 'color');
|
|
78
|
-
assert.equal(result.color.red.$description, 'danger signal');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('preserves dimension $value object shape (does not unwrap)', () => {
|
|
82
|
-
const result = mergeTokens([
|
|
83
|
-
{
|
|
84
|
-
path: 'a.json',
|
|
85
|
-
contents: {
|
|
86
|
-
space: { 1: { $type: 'dimension', $value: { value: 4, unit: 'px' } } },
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
]);
|
|
90
|
-
|
|
91
|
-
assert.deepEqual(result.space[1].$value, { value: 4, unit: 'px' });
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test('throws on leaf collision with both source paths in the message', () => {
|
|
95
|
-
assert.throws(
|
|
96
|
-
() => mergeTokens([
|
|
97
|
-
{
|
|
98
|
-
path: 'a.json',
|
|
99
|
-
contents: { color: { brand: { $type: 'color', $value: '#000' } } },
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
path: 'b.json',
|
|
103
|
-
contents: { color: { brand: { $type: 'color', $value: '#fff' } } },
|
|
104
|
-
},
|
|
105
|
-
]),
|
|
106
|
-
(err) => {
|
|
107
|
-
assert.match(err.message, /collision/);
|
|
108
|
-
assert.match(err.message, /color\.brand/);
|
|
109
|
-
assert.match(err.message, /a\.json/);
|
|
110
|
-
assert.match(err.message, /b\.json/);
|
|
111
|
-
return true;
|
|
112
|
-
},
|
|
113
|
-
);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test('leaves $value untouched when it is the literal string "0"', () => {
|
|
117
|
-
// Guard against a naive `!$value` check treating falsy values as missing.
|
|
118
|
-
const result = mergeTokens([
|
|
119
|
-
{
|
|
120
|
-
path: 'a.json',
|
|
121
|
-
contents: { opacity: { none: { $type: 'opacity', $value: 0 } } },
|
|
122
|
-
},
|
|
123
|
-
]);
|
|
124
|
-
|
|
125
|
-
assert.equal(result.opacity.none.$value, 0);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test('returns an empty object for empty input', () => {
|
|
129
|
-
assert.deepEqual(mergeTokens([]), {});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
test('merges three sources sharing the same branch', () => {
|
|
133
|
-
const result = mergeTokens([
|
|
134
|
-
{ path: 'a.json', contents: { color: { a: { $type: 'color', $value: '#a' } } } },
|
|
135
|
-
{ path: 'b.json', contents: { color: { b: { $type: 'color', $value: '#b' } } } },
|
|
136
|
-
{ path: 'c.json', contents: { color: { c: { $type: 'color', $value: '#c' } } } },
|
|
137
|
-
]);
|
|
138
|
-
|
|
139
|
-
assert.deepEqual(Object.keys(result.color).sort(), ['a', 'b', 'c']);
|
|
140
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Emit a CSS file with :root (DEFAULT theme) plus [data-theme="..."] blocks
|
|
2
|
-
// for every other theme found under theme tokens.
|
|
3
|
-
|
|
4
|
-
const hexToRGB = (hex) => {
|
|
5
|
-
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
|
6
|
-
const replacedHex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
|
|
7
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(replacedHex);
|
|
8
|
-
return `${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}`;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const CATEGORY_TO_PREFIX = {
|
|
12
|
-
text: 'text',
|
|
13
|
-
background: 'bg',
|
|
14
|
-
border: 'border',
|
|
15
|
-
'heading-underline': 'heading-underline',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const blockFor = (themeTokens) => {
|
|
19
|
-
const lines = [];
|
|
20
|
-
Object.keys(themeTokens).forEach((category) => {
|
|
21
|
-
const prefix = CATEGORY_TO_PREFIX[category] ?? category;
|
|
22
|
-
const props = themeTokens[category];
|
|
23
|
-
Object.keys(props).forEach((prop) => {
|
|
24
|
-
const tokenLeaf = props[prop];
|
|
25
|
-
const raw = tokenLeaf.$value ?? tokenLeaf.value;
|
|
26
|
-
const name = `--${prefix}-${prop}`;
|
|
27
|
-
if (category === 'heading-underline') {
|
|
28
|
-
lines.push(`\t${name}: url('/kvui/heading-underline.svg${raw}');`);
|
|
29
|
-
} else {
|
|
30
|
-
lines.push(`\t${name}: ${hexToRGB(raw)};`);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
return lines.join('\n');
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const cssThemesFormat = {
|
|
38
|
-
name: 'kiva/css-themes',
|
|
39
|
-
format: ({ dictionary }) => {
|
|
40
|
-
const themes = dictionary.tokens.theme ?? {};
|
|
41
|
-
const out = ['/* Do not edit directly. Generated by Style Dictionary. */', ''];
|
|
42
|
-
const defaultTheme = themes.DEFAULT;
|
|
43
|
-
if (defaultTheme) {
|
|
44
|
-
out.push(':root {');
|
|
45
|
-
out.push(blockFor(defaultTheme));
|
|
46
|
-
out.push('}');
|
|
47
|
-
out.push('');
|
|
48
|
-
}
|
|
49
|
-
Object.keys(themes).forEach((name) => {
|
|
50
|
-
if (name === 'DEFAULT') return;
|
|
51
|
-
out.push(`[data-theme="${name}"] {`);
|
|
52
|
-
out.push(blockFor(themes[name]));
|
|
53
|
-
out.push('}');
|
|
54
|
-
out.push('');
|
|
55
|
-
});
|
|
56
|
-
return out.join('\n');
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export default cssThemesFormat;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
// Style Dictionary v4 custom format.
|
|
2
|
-
// Emits:
|
|
3
|
-
// 1. Flat named exports: `export const colorBrandDefault = '#2AA967';`
|
|
4
|
-
// 2. A nested default export matching the legacy primitives.js shape.
|
|
5
|
-
|
|
6
|
-
const DTCG_TO_LEGACY_KEY = {
|
|
7
|
-
color: 'colors',
|
|
8
|
-
'font-family': 'fonts',
|
|
9
|
-
'font-weight': 'fontWeights',
|
|
10
|
-
'font-size': 'fontSizes',
|
|
11
|
-
'semantic-font-size': 'semanticFontSizes',
|
|
12
|
-
'line-height': 'lineHeights',
|
|
13
|
-
'line-height-absolute': 'lineHeightsAbsolute',
|
|
14
|
-
'letter-spacing': 'letterSpacings',
|
|
15
|
-
'border-width': 'borderWidths',
|
|
16
|
-
breakpoint: 'breakpoints',
|
|
17
|
-
radius: 'radii',
|
|
18
|
-
'z-index': 'zIndices',
|
|
19
|
-
space: 'space',
|
|
20
|
-
opacity: 'opacity',
|
|
21
|
-
theme: 'theme',
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const restoreKey = (key) => {
|
|
25
|
-
if (/^n\d+_\d+$/.test(key)) return `-${key.slice(1).replace('_', '.')}`;
|
|
26
|
-
if (/^n\d+$/.test(key)) return `-${key.slice(1)}`;
|
|
27
|
-
if (/^\d+_\d+$/.test(key)) return key.replace('_', '.');
|
|
28
|
-
return key;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// camelCase that preserves underscores as digit separators so `space.1_5`
|
|
32
|
-
// and `space.15` don't collide. Dashes split into word boundaries.
|
|
33
|
-
const camelCase = (parts) => parts
|
|
34
|
-
.flatMap((p) => String(p).split('-').filter(Boolean))
|
|
35
|
-
.map((w, i) => {
|
|
36
|
-
const lower = w.toLowerCase();
|
|
37
|
-
if (i === 0) return lower;
|
|
38
|
-
return lower.charAt(0).toUpperCase() + lower.slice(1);
|
|
39
|
-
})
|
|
40
|
-
.join('');
|
|
41
|
-
|
|
42
|
-
const isLeaf = (node) => node && typeof node === 'object' && '$value' in node;
|
|
43
|
-
|
|
44
|
-
const buildNested = (tokens) => {
|
|
45
|
-
const out = {};
|
|
46
|
-
const walk = (node, path) => {
|
|
47
|
-
if (isLeaf(node)) {
|
|
48
|
-
const legacyPath = path.map((seg, i) => (i === 0 ? (DTCG_TO_LEGACY_KEY[seg] || seg) : restoreKey(seg)));
|
|
49
|
-
const finalPath = legacyPath[0] === 'theme' ? ['colors', ...legacyPath] : legacyPath;
|
|
50
|
-
let cursor = out;
|
|
51
|
-
for (let i = 0; i < finalPath.length - 1; i += 1) {
|
|
52
|
-
cursor[finalPath[i]] = cursor[finalPath[i]] ?? {};
|
|
53
|
-
cursor = cursor[finalPath[i]];
|
|
54
|
-
}
|
|
55
|
-
cursor[finalPath[finalPath.length - 1]] = node.$value;
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
if (node && typeof node === 'object') {
|
|
59
|
-
Object.keys(node).forEach((k) => walk(node[k], [...path, k]));
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
walk(tokens, []);
|
|
63
|
-
out.colors = out.colors ?? {};
|
|
64
|
-
out.shadows = out.shadows ?? {};
|
|
65
|
-
return out;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const jsTokensFormat = {
|
|
69
|
-
name: 'kiva/js-tokens',
|
|
70
|
-
format: ({ dictionary }) => {
|
|
71
|
-
const flatLines = dictionary.allTokens.map((t) => {
|
|
72
|
-
const name = camelCase(t.path);
|
|
73
|
-
const v = t.$value;
|
|
74
|
-
const value = typeof v === 'number' ? v : JSON.stringify(v);
|
|
75
|
-
return `export const ${name} = ${value};`;
|
|
76
|
-
});
|
|
77
|
-
const nested = buildNested(dictionary.tokens);
|
|
78
|
-
return [
|
|
79
|
-
'// Do not edit directly. Generated by Style Dictionary.',
|
|
80
|
-
'',
|
|
81
|
-
...flatLines,
|
|
82
|
-
'',
|
|
83
|
-
`const tokens = ${JSON.stringify(nested, null, '\t')};`,
|
|
84
|
-
'',
|
|
85
|
-
'export default tokens;',
|
|
86
|
-
'',
|
|
87
|
-
].join('\n');
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export default jsTokensFormat;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import StyleDictionary from 'style-dictionary';
|
|
2
|
-
import jsTokensFormat from './formats/js-tokens.js';
|
|
3
|
-
import cssThemesFormat from './formats/css-themes.js';
|
|
4
|
-
import dimensionToNumberTransform from './transforms/dimension-to-number.js';
|
|
5
|
-
|
|
6
|
-
StyleDictionary.registerFormat(jsTokensFormat);
|
|
7
|
-
StyleDictionary.registerFormat(cssThemesFormat);
|
|
8
|
-
StyleDictionary.registerTransform(dimensionToNumberTransform);
|
|
9
|
-
|
|
10
|
-
export default {
|
|
11
|
-
source: ['tokens/**/*.json'],
|
|
12
|
-
platforms: {
|
|
13
|
-
js: {
|
|
14
|
-
transforms: ['attribute/cti', 'name/kebab', 'kiva/dimension-to-number'],
|
|
15
|
-
buildPath: 'dist/js/',
|
|
16
|
-
files: [
|
|
17
|
-
{
|
|
18
|
-
destination: 'tokens.js',
|
|
19
|
-
format: 'kiva/js-tokens',
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
},
|
|
23
|
-
css: {
|
|
24
|
-
transforms: ['attribute/cti', 'name/kebab'],
|
|
25
|
-
buildPath: 'dist/css/',
|
|
26
|
-
files: [
|
|
27
|
-
{
|
|
28
|
-
destination: 'tokens.css',
|
|
29
|
-
format: 'kiva/css-themes',
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
},
|
|
33
|
-
scss: {
|
|
34
|
-
transforms: ['attribute/cti', 'name/kebab', 'kiva/dimension-to-number'],
|
|
35
|
-
buildPath: 'dist/scss/',
|
|
36
|
-
files: [
|
|
37
|
-
{
|
|
38
|
-
destination: 'tokens.scss',
|
|
39
|
-
format: 'scss/variables',
|
|
40
|
-
options: { outputReferences: false },
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// Transform: dimension objects -> raw numeric value.
|
|
2
|
-
// DTCG encodes dimensions as { value: 16, unit: 'px' }; legacy primitives.js
|
|
3
|
-
// stored them as raw numbers. Strip the unit for JS output.
|
|
4
|
-
|
|
5
|
-
const dimensionToNumberTransform = {
|
|
6
|
-
name: 'kiva/dimension-to-number',
|
|
7
|
-
type: 'value',
|
|
8
|
-
transitive: true,
|
|
9
|
-
filter: (token) => token.$type === 'dimension' || token.type === 'dimension',
|
|
10
|
-
transform: (token) => {
|
|
11
|
-
const v = token.$value ?? token.value;
|
|
12
|
-
if (v && typeof v === 'object' && 'value' in v) return v.value;
|
|
13
|
-
return v;
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export default dimensionToNumberTransform;
|