@carbon/layout 12.0.0-alpha.1 → 12.0.0-alpha.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/es/index.js +205 -0
- package/lib/__tests__/tokens-test.d.ts +1 -0
- package/package.json +11 -2
- package/umd/index.js +277 -0
- package/docs/sass.md +0 -65
- package/src/dtcg/README.md +0 -266
- package/src/dtcg/layout.json +0 -432
- package/src/index.ts +0 -221
- package/src/tokens.ts +0 -56
- package/style-dictionary/formats/js-layout.js +0 -104
- package/style-dictionary/formats/scss-layout.js +0 -188
- package/style-dictionary/sd.config.js +0 -104
- package/tsconfig.json +0 -8
- package/tsconfig.types.json +0 -10
package/src/index.ts
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright IBM Corp. 2018, 2026
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// Re-export individual token constants generated from src/dtcg/layout.json
|
|
9
|
-
// via the Style Dictionary pipeline (tasks/build.mjs → style-dictionary/sd.config.js).
|
|
10
|
-
// The generated file is kept in sync with the DTCG source of truth.
|
|
11
|
-
export * from '../js/generated/layout-tokens';
|
|
12
|
-
|
|
13
|
-
import { unstable_tokens } from './tokens';
|
|
14
|
-
import {
|
|
15
|
-
spacing01,
|
|
16
|
-
spacing02,
|
|
17
|
-
spacing03,
|
|
18
|
-
spacing04,
|
|
19
|
-
spacing05,
|
|
20
|
-
spacing06,
|
|
21
|
-
spacing07,
|
|
22
|
-
spacing08,
|
|
23
|
-
spacing09,
|
|
24
|
-
spacing10,
|
|
25
|
-
spacing11,
|
|
26
|
-
spacing12,
|
|
27
|
-
spacing13,
|
|
28
|
-
fluidSpacing01,
|
|
29
|
-
fluidSpacing02,
|
|
30
|
-
fluidSpacing03,
|
|
31
|
-
fluidSpacing04,
|
|
32
|
-
container01,
|
|
33
|
-
container02,
|
|
34
|
-
container03,
|
|
35
|
-
container04,
|
|
36
|
-
container05,
|
|
37
|
-
sizeXs,
|
|
38
|
-
sizeSm,
|
|
39
|
-
sizeMd,
|
|
40
|
-
sizeLg,
|
|
41
|
-
sizeXl,
|
|
42
|
-
size2xl,
|
|
43
|
-
iconSize01,
|
|
44
|
-
iconSize02,
|
|
45
|
-
layout01,
|
|
46
|
-
layout02,
|
|
47
|
-
layout03,
|
|
48
|
-
layout04,
|
|
49
|
-
layout05,
|
|
50
|
-
layout06,
|
|
51
|
-
layout07,
|
|
52
|
-
borderRadius00,
|
|
53
|
-
borderRadius02,
|
|
54
|
-
borderRadius04,
|
|
55
|
-
borderRadius08,
|
|
56
|
-
borderRadius16,
|
|
57
|
-
borderRadius24,
|
|
58
|
-
borderRadiusMax,
|
|
59
|
-
} from '../js/generated/layout-tokens';
|
|
60
|
-
|
|
61
|
-
export { unstable_tokens };
|
|
62
|
-
|
|
63
|
-
export type BreakpointName = 'sm' | 'md' | 'lg' | 'xlg' | 'max';
|
|
64
|
-
export type Breakpoint = {
|
|
65
|
-
width: string;
|
|
66
|
-
columns: number;
|
|
67
|
-
margin: string;
|
|
68
|
-
};
|
|
69
|
-
export type SizeName =
|
|
70
|
-
| 'XSmall'
|
|
71
|
-
| 'Small'
|
|
72
|
-
| 'Medium'
|
|
73
|
-
| 'Large'
|
|
74
|
-
| 'XLarge'
|
|
75
|
-
| '2XLarge';
|
|
76
|
-
export type BorderRadiusToken =
|
|
77
|
-
| 'border-radius-00'
|
|
78
|
-
| 'border-radius-02'
|
|
79
|
-
| 'border-radius-04'
|
|
80
|
-
| 'border-radius-08'
|
|
81
|
-
| 'border-radius-16'
|
|
82
|
-
| 'border-radius-24'
|
|
83
|
-
| 'border-radius-max';
|
|
84
|
-
|
|
85
|
-
// Convert
|
|
86
|
-
// Default, Use with em() and rem() functions
|
|
87
|
-
export const baseFontSize = 16;
|
|
88
|
-
|
|
89
|
-
export const rem = (px: number) => {
|
|
90
|
-
return `${px / baseFontSize}rem`;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export const em = (px: number) => {
|
|
94
|
-
return `${px / baseFontSize}em`;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export const px = (value: number) => {
|
|
98
|
-
return `${value}px`;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// Breakpoint
|
|
102
|
-
// Initial map of our breakpoints and their values
|
|
103
|
-
export const breakpoints: Record<BreakpointName, Breakpoint> = {
|
|
104
|
-
sm: {
|
|
105
|
-
width: rem(320),
|
|
106
|
-
columns: 4,
|
|
107
|
-
margin: '0',
|
|
108
|
-
},
|
|
109
|
-
md: {
|
|
110
|
-
width: rem(672),
|
|
111
|
-
columns: 8,
|
|
112
|
-
margin: rem(16),
|
|
113
|
-
},
|
|
114
|
-
lg: {
|
|
115
|
-
width: rem(1056),
|
|
116
|
-
columns: 16,
|
|
117
|
-
margin: rem(16),
|
|
118
|
-
},
|
|
119
|
-
xlg: {
|
|
120
|
-
width: rem(1312),
|
|
121
|
-
columns: 16,
|
|
122
|
-
margin: rem(16),
|
|
123
|
-
},
|
|
124
|
-
max: {
|
|
125
|
-
width: rem(1584),
|
|
126
|
-
columns: 16,
|
|
127
|
-
margin: rem(24),
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
export const breakpointUp = (name: BreakpointName) => {
|
|
132
|
-
return `@media (min-width: ${breakpoints[name].width})`;
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
export const breakpointDown = (name: BreakpointName) => {
|
|
136
|
-
return `@media (max-width: ${breakpoints[name].width})`;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
export const breakpoint = breakpointUp;
|
|
140
|
-
|
|
141
|
-
// Mini-unit
|
|
142
|
-
export const miniUnit = 8;
|
|
143
|
-
|
|
144
|
-
export const miniUnits = (count: number) => {
|
|
145
|
-
return rem(miniUnit * count);
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
// Spacing — aggregate array (individual tokens come from generated re-export above)
|
|
149
|
-
export const spacing = [
|
|
150
|
-
spacing01,
|
|
151
|
-
spacing02,
|
|
152
|
-
spacing03,
|
|
153
|
-
spacing04,
|
|
154
|
-
spacing05,
|
|
155
|
-
spacing06,
|
|
156
|
-
spacing07,
|
|
157
|
-
spacing08,
|
|
158
|
-
spacing09,
|
|
159
|
-
spacing10,
|
|
160
|
-
spacing11,
|
|
161
|
-
spacing12,
|
|
162
|
-
spacing13,
|
|
163
|
-
];
|
|
164
|
-
|
|
165
|
-
// Fluid spacing — aggregate array
|
|
166
|
-
export const fluidSpacing = [
|
|
167
|
-
fluidSpacing01,
|
|
168
|
-
fluidSpacing02,
|
|
169
|
-
fluidSpacing03,
|
|
170
|
-
fluidSpacing04,
|
|
171
|
-
];
|
|
172
|
-
|
|
173
|
-
// Layout (deprecated) — aggregate array
|
|
174
|
-
export const layout = [
|
|
175
|
-
layout01,
|
|
176
|
-
layout02,
|
|
177
|
-
layout03,
|
|
178
|
-
layout04,
|
|
179
|
-
layout05,
|
|
180
|
-
layout06,
|
|
181
|
-
layout07,
|
|
182
|
-
];
|
|
183
|
-
|
|
184
|
-
// Container — aggregate array
|
|
185
|
-
export const container = [
|
|
186
|
-
container01,
|
|
187
|
-
container02,
|
|
188
|
-
container03,
|
|
189
|
-
container04,
|
|
190
|
-
container05,
|
|
191
|
-
];
|
|
192
|
-
|
|
193
|
-
// Size — camelCase aliases matching the existing SizeName API
|
|
194
|
-
export const sizeXSmall = sizeXs;
|
|
195
|
-
export const sizeSmall = sizeSm;
|
|
196
|
-
export const sizeMedium = sizeMd;
|
|
197
|
-
export const sizeLarge = sizeLg;
|
|
198
|
-
export const sizeXLarge = sizeXl;
|
|
199
|
-
export const size2XLarge = size2xl;
|
|
200
|
-
export const sizes: Record<SizeName, string> = {
|
|
201
|
-
XSmall: sizeXSmall,
|
|
202
|
-
Small: sizeSmall,
|
|
203
|
-
Medium: sizeMedium,
|
|
204
|
-
Large: sizeLarge,
|
|
205
|
-
XLarge: sizeXLarge,
|
|
206
|
-
'2XLarge': size2XLarge,
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
// Icon — aggregate array
|
|
210
|
-
export const iconSize = [iconSize01, iconSize02];
|
|
211
|
-
|
|
212
|
-
// Border radius — aggregate record keyed by CSS custom property name
|
|
213
|
-
export const borderRadius: Record<BorderRadiusToken, string> = {
|
|
214
|
-
'border-radius-00': borderRadius00,
|
|
215
|
-
'border-radius-02': borderRadius02,
|
|
216
|
-
'border-radius-04': borderRadius04,
|
|
217
|
-
'border-radius-08': borderRadius08,
|
|
218
|
-
'border-radius-16': borderRadius16,
|
|
219
|
-
'border-radius-24': borderRadius24,
|
|
220
|
-
'border-radius-max': borderRadiusMax,
|
|
221
|
-
};
|
package/src/tokens.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright IBM Corp. 2018, 2026
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export const unstable_tokens = [
|
|
9
|
-
// Spacing
|
|
10
|
-
'spacing01',
|
|
11
|
-
'spacing02',
|
|
12
|
-
'spacing03',
|
|
13
|
-
'spacing04',
|
|
14
|
-
'spacing05',
|
|
15
|
-
'spacing06',
|
|
16
|
-
'spacing07',
|
|
17
|
-
'spacing08',
|
|
18
|
-
'spacing09',
|
|
19
|
-
'spacing10',
|
|
20
|
-
'spacing11',
|
|
21
|
-
'spacing12',
|
|
22
|
-
'spacing13',
|
|
23
|
-
|
|
24
|
-
// Fluid spacing
|
|
25
|
-
'fluidSpacing01',
|
|
26
|
-
'fluidSpacing02',
|
|
27
|
-
'fluidSpacing03',
|
|
28
|
-
'fluidSpacing04',
|
|
29
|
-
|
|
30
|
-
// Containers
|
|
31
|
-
'container01',
|
|
32
|
-
'container02',
|
|
33
|
-
'container03',
|
|
34
|
-
'container04',
|
|
35
|
-
'container05',
|
|
36
|
-
'sizeXSmall',
|
|
37
|
-
'sizeSmall',
|
|
38
|
-
'sizeMedium',
|
|
39
|
-
'sizeLarge',
|
|
40
|
-
'sizeXLarge',
|
|
41
|
-
'size2XLarge',
|
|
42
|
-
|
|
43
|
-
// Icon sizes
|
|
44
|
-
'iconSize01',
|
|
45
|
-
'iconSize02',
|
|
46
|
-
|
|
47
|
-
// Layout
|
|
48
|
-
// Deprecated
|
|
49
|
-
'layout01',
|
|
50
|
-
'layout02',
|
|
51
|
-
'layout03',
|
|
52
|
-
'layout04',
|
|
53
|
-
'layout05',
|
|
54
|
-
'layout06',
|
|
55
|
-
'layout07',
|
|
56
|
-
] as const;
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright IBM Corp. 2018, 2026
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
'use strict';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Style Dictionary format — carbon/js-layout
|
|
12
|
-
*
|
|
13
|
-
* Emits either:
|
|
14
|
-
* - An ES module (.js) with `export const camelName = value;`
|
|
15
|
-
* - A TypeScript declaration file (.d.ts) with `export declare const camelName: string;`
|
|
16
|
-
*
|
|
17
|
-
* Token names arrive as kebab-case from SD (e.g. "spacing-01") and are
|
|
18
|
-
* converted to camelCase ("spacing01") so the output matches the existing
|
|
19
|
-
* hand-authored exports in src/index.ts.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
const FILE_BANNER = `// Code generated by @carbon/layout. DO NOT EDIT.
|
|
23
|
-
//
|
|
24
|
-
// Copyright IBM Corp. 2018, 2026
|
|
25
|
-
//
|
|
26
|
-
// This source code is licensed under the Apache-2.0 license found in the
|
|
27
|
-
// LICENSE file in the root directory of this source tree.
|
|
28
|
-
`;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Convert kebab-case to camelCase.
|
|
32
|
-
* "spacing-01" → "spacing01"
|
|
33
|
-
* "fluid-spacing-02" → "fluidSpacing02"
|
|
34
|
-
* "border-radius-08" → "borderRadius08"
|
|
35
|
-
* "size-xs" → "sizeXs" (kept for completeness; index re-exports under SizeName aliases)
|
|
36
|
-
* "icon-size-01" → "iconSize01"
|
|
37
|
-
* "layout-03" → "layout03"
|
|
38
|
-
*
|
|
39
|
-
* @param {string} str
|
|
40
|
-
* @returns {string}
|
|
41
|
-
*/
|
|
42
|
-
function kebabToCamel(str) {
|
|
43
|
-
return str.replace(/-([a-z0-9])/g, (_, ch) => ch.toUpperCase());
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const BASE_FONT_SIZE = 16;
|
|
47
|
-
const MINI_UNIT = 8;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Resolve a token's raw $value using the carbon.layout.converter extension.
|
|
51
|
-
* - "miniUnits": steps × 8px ÷ 16 → rem string
|
|
52
|
-
* - "rem": px ÷ 16 → rem string
|
|
53
|
-
* - (none): value is already a resolved CSS string, returned as-is
|
|
54
|
-
*
|
|
55
|
-
* @param {string|number} value
|
|
56
|
-
* @param {object|undefined} carbonLayout — token.$extensions?.['carbon.layout']
|
|
57
|
-
* @returns {string}
|
|
58
|
-
*/
|
|
59
|
-
function resolveValue(value, carbonLayout) {
|
|
60
|
-
const converter = carbonLayout?.converter;
|
|
61
|
-
if (converter === 'miniUnits') {
|
|
62
|
-
return `${(Number(value) * MINI_UNIT) / BASE_FONT_SIZE}rem`;
|
|
63
|
-
}
|
|
64
|
-
if (converter === 'rem') {
|
|
65
|
-
return `${Number(value) / BASE_FONT_SIZE}rem`;
|
|
66
|
-
}
|
|
67
|
-
// Unitless zero — preserve as number 0, not the string "0", to match the
|
|
68
|
-
// original hand-authored export: `export const fluidSpacing01 = 0`
|
|
69
|
-
if (value === '0' || value === 0) return 0;
|
|
70
|
-
return String(value);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* @param {{ dictionary: import('style-dictionary').Dictionary, options: object }} args
|
|
75
|
-
* @returns {string}
|
|
76
|
-
*/
|
|
77
|
-
function carbonJsLayoutFormat({ dictionary, options }) {
|
|
78
|
-
const outputMode = options?.output ?? 'js'; // 'js' | 'dts'
|
|
79
|
-
const lines = [FILE_BANNER];
|
|
80
|
-
|
|
81
|
-
for (const token of dictionary.allTokens) {
|
|
82
|
-
const camelName = kebabToCamel(token.name);
|
|
83
|
-
const carbonLayout =
|
|
84
|
-
token.$extensions?.['carbon.layout'] ??
|
|
85
|
-
token.extensions?.['carbon.layout'];
|
|
86
|
-
const resolved = resolveValue(token.value ?? token.$value, carbonLayout);
|
|
87
|
-
|
|
88
|
-
const tsType = resolved === 0 ? 'number' : 'string';
|
|
89
|
-
if (outputMode === 'js') {
|
|
90
|
-
// Numeric 0 is emitted bare (no quotes) to preserve the original type.
|
|
91
|
-
const src = resolved === 0 ? '0' : `'${resolved}'`;
|
|
92
|
-
lines.push(`export const ${camelName} = ${src};`);
|
|
93
|
-
} else {
|
|
94
|
-
lines.push(`export declare const ${camelName}: ${tsType};`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return lines.join('\n') + '\n';
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
module.exports = {
|
|
102
|
-
name: 'carbon/js-layout',
|
|
103
|
-
format: carbonJsLayoutFormat,
|
|
104
|
-
};
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright IBM Corp. 2018, 2026
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
'use strict';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Style Dictionary format — carbon/scss-layout
|
|
12
|
-
*
|
|
13
|
-
* Generates per-category Sass files from layout.json whose content is
|
|
14
|
-
* byte-for-byte identical to what build.mjs / @carbon/scss-generator produced,
|
|
15
|
-
* so that nothing downstream breaks.
|
|
16
|
-
*
|
|
17
|
-
* Files emitted:
|
|
18
|
-
* _spacing.scss variables + map, !default
|
|
19
|
-
* _fluid-spacing.scss variables + map, !default
|
|
20
|
-
* _container.scss variables + map, !default
|
|
21
|
-
* _icon-size.scss variables + map, !default
|
|
22
|
-
* _border-radius.scss variables + map, !default
|
|
23
|
-
* _layout.scss variables + map, !default (deprecated tokens)
|
|
24
|
-
* _size.scss bare assignments, no !default, no map
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
// ── Banners ───────────────────────────────────────────────────────────────────
|
|
28
|
-
// Most files use 2023; _size.scss uses 2026 — match exactly.
|
|
29
|
-
const BANNER_2023 = `// Code generated by @carbon/layout. DO NOT EDIT.
|
|
30
|
-
//
|
|
31
|
-
// Copyright IBM Corp. 2018, 2023
|
|
32
|
-
//
|
|
33
|
-
// This source code is licensed under the Apache-2.0 license found in the
|
|
34
|
-
// LICENSE file in the root directory of this source tree.
|
|
35
|
-
//`;
|
|
36
|
-
|
|
37
|
-
const BANNER_2026 = `// Code generated by @carbon/layout. DO NOT EDIT.
|
|
38
|
-
//
|
|
39
|
-
// Copyright IBM Corp. 2018, 2026
|
|
40
|
-
//
|
|
41
|
-
// This source code is licensed under the Apache-2.0 license found in the
|
|
42
|
-
// LICENSE file in the root directory of this source tree.
|
|
43
|
-
//`;
|
|
44
|
-
|
|
45
|
-
const VAR_COMMENT = `/// @type Number
|
|
46
|
-
/// @access public
|
|
47
|
-
/// @group @carbon/layout`;
|
|
48
|
-
|
|
49
|
-
const MAP_COMMENT = `/// @type Map
|
|
50
|
-
/// @access public
|
|
51
|
-
/// @group @carbon/layout`;
|
|
52
|
-
|
|
53
|
-
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
54
|
-
const BASE_FONT_SIZE = 16;
|
|
55
|
-
const MINI_UNIT = 8;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Resolve a token's $value using carbon.layout.converter if present.
|
|
59
|
-
* @param {string|number} value
|
|
60
|
-
* @param {object|undefined} carbonLayout
|
|
61
|
-
* @returns {string}
|
|
62
|
-
*/
|
|
63
|
-
function resolveValue(value, carbonLayout) {
|
|
64
|
-
const converter = carbonLayout?.converter;
|
|
65
|
-
if (converter === 'miniUnits') {
|
|
66
|
-
return `${(Number(value) * MINI_UNIT) / BASE_FONT_SIZE}rem`;
|
|
67
|
-
}
|
|
68
|
-
if (converter === 'rem') {
|
|
69
|
-
return `${Number(value) / BASE_FONT_SIZE}rem`;
|
|
70
|
-
}
|
|
71
|
-
return String(value);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Build a standard file: banner + (comment + $var: value !default;) * n + map.
|
|
76
|
-
* @param {Array<{name: string, resolved: string}>} tokens
|
|
77
|
-
* @param {string} mapName — Sass map variable name
|
|
78
|
-
* @param {string} banner
|
|
79
|
-
* @returns {string}
|
|
80
|
-
*/
|
|
81
|
-
function buildStandardFile(tokens, mapName, banner) {
|
|
82
|
-
const lines = [banner, ''];
|
|
83
|
-
|
|
84
|
-
for (const { name, resolved } of tokens) {
|
|
85
|
-
lines.push(VAR_COMMENT);
|
|
86
|
-
lines.push(`$${name}: ${resolved} !default;`);
|
|
87
|
-
lines.push('');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
lines.push(MAP_COMMENT);
|
|
91
|
-
lines.push(`$${mapName}: (`);
|
|
92
|
-
for (const { name } of tokens) {
|
|
93
|
-
lines.push(` ${name}: $${name},`);
|
|
94
|
-
}
|
|
95
|
-
lines.push(');');
|
|
96
|
-
|
|
97
|
-
return lines.join('\n') + '\n';
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Build _size.scss — no !default, no map, no per-variable comments.
|
|
102
|
-
* @param {Array<{name: string, resolved: string}>} tokens
|
|
103
|
-
* @returns {string}
|
|
104
|
-
*/
|
|
105
|
-
function buildSizeFile(tokens) {
|
|
106
|
-
const lines = [BANNER_2026, ''];
|
|
107
|
-
lines.push(VAR_COMMENT);
|
|
108
|
-
for (const { name, resolved } of tokens) {
|
|
109
|
-
lines.push(`$${name}: ${resolved};`);
|
|
110
|
-
}
|
|
111
|
-
return lines.join('\n') + '\n';
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Extract tokens belonging to a DTCG group from the SD dictionary.
|
|
116
|
-
* Routing is done by token.path[0] — the group name in the JSON — which is
|
|
117
|
-
* the native DTCG mechanism. No prefix inference needed.
|
|
118
|
-
*
|
|
119
|
-
* @param {import('style-dictionary').Dictionary} dictionary
|
|
120
|
-
* @param {string} groupName — top-level DTCG group key (e.g. "spacing")
|
|
121
|
-
* @returns {Array<{name: string, resolved: string}>}
|
|
122
|
-
*/
|
|
123
|
-
function tokensForGroup(dictionary, groupName) {
|
|
124
|
-
return dictionary.allTokens
|
|
125
|
-
.filter((t) => t.path[0] === groupName)
|
|
126
|
-
.map((t) => {
|
|
127
|
-
const carbonLayout =
|
|
128
|
-
t.$extensions?.['carbon.layout'] ?? t.extensions?.['carbon.layout'];
|
|
129
|
-
return {
|
|
130
|
-
name: t.name,
|
|
131
|
-
resolved: resolveValue(t.value ?? t.$value, carbonLayout),
|
|
132
|
-
};
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// ── Format functions — one per DTCG group ─────────────────────────────────────
|
|
137
|
-
|
|
138
|
-
function formatSpacing({ dictionary }) {
|
|
139
|
-
const tokens = tokensForGroup(dictionary, 'spacing');
|
|
140
|
-
return buildStandardFile(tokens, 'spacing', BANNER_2023);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function formatFluidSpacing({ dictionary }) {
|
|
144
|
-
const tokens = tokensForGroup(dictionary, 'fluid-spacing');
|
|
145
|
-
// Sass expects unitless 0, not the string "0"
|
|
146
|
-
const fixed = tokens.map((t) => ({
|
|
147
|
-
...t,
|
|
148
|
-
resolved: t.resolved === '0' ? '0' : t.resolved,
|
|
149
|
-
}));
|
|
150
|
-
return buildStandardFile(fixed, 'fluid-spacing', BANNER_2023);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function formatContainer({ dictionary }) {
|
|
154
|
-
const tokens = tokensForGroup(dictionary, 'container');
|
|
155
|
-
return buildStandardFile(tokens, 'container', BANNER_2023);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function formatIconSize({ dictionary }) {
|
|
159
|
-
const tokens = tokensForGroup(dictionary, 'icon-size');
|
|
160
|
-
return buildStandardFile(tokens, 'icon-size', BANNER_2023);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function formatBorderRadius({ dictionary }) {
|
|
164
|
-
const tokens = tokensForGroup(dictionary, 'border-radius');
|
|
165
|
-
return buildStandardFile(tokens, 'border-radius', BANNER_2023);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function formatLayout({ dictionary }) {
|
|
169
|
-
const tokens = tokensForGroup(dictionary, 'layout');
|
|
170
|
-
return buildStandardFile(tokens, 'layout', BANNER_2023);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function formatSize({ dictionary }) {
|
|
174
|
-
const tokens = tokensForGroup(dictionary, 'size');
|
|
175
|
-
return buildSizeFile(tokens);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// ── Exports ───────────────────────────────────────────────────────────────────
|
|
179
|
-
|
|
180
|
-
module.exports = [
|
|
181
|
-
{ name: 'carbon/scss-spacing', format: formatSpacing },
|
|
182
|
-
{ name: 'carbon/scss-fluid-spacing', format: formatFluidSpacing },
|
|
183
|
-
{ name: 'carbon/scss-container', format: formatContainer },
|
|
184
|
-
{ name: 'carbon/scss-icon-size', format: formatIconSize },
|
|
185
|
-
{ name: 'carbon/scss-border-radius', format: formatBorderRadius },
|
|
186
|
-
{ name: 'carbon/scss-layout', format: formatLayout },
|
|
187
|
-
{ name: 'carbon/scss-size', format: formatSize },
|
|
188
|
-
];
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright IBM Corp. 2018, 2026
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
'use strict';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Style Dictionary configuration for @carbon/layout.
|
|
12
|
-
*
|
|
13
|
-
* Reads src/dtcg/layout.json and generates:
|
|
14
|
-
* scss/generated/*.scss — Sass variables + maps (one file per token group)
|
|
15
|
-
* js/generated/layout-tokens.js — ES module named exports
|
|
16
|
-
* js/generated/layout-tokens.d.ts — TypeScript declarations
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const path = require('path');
|
|
20
|
-
const { default: StyleDictionary } = require('style-dictionary');
|
|
21
|
-
|
|
22
|
-
const scssFormats = require('./formats/scss-layout');
|
|
23
|
-
const carbonJsLayout = require('./formats/js-layout');
|
|
24
|
-
|
|
25
|
-
// ── Paths ─────────────────────────────────────────────────────────────────────
|
|
26
|
-
const ROOT = path.resolve(__dirname, '..');
|
|
27
|
-
const DTCG_SOURCE = path.join(ROOT, 'src', 'dtcg', 'layout.json');
|
|
28
|
-
const SCSS_GENERATED = path.join(ROOT, 'scss', 'generated');
|
|
29
|
-
const JS_GENERATED = path.join(ROOT, 'js', 'generated');
|
|
30
|
-
|
|
31
|
-
// ── Custom name transform ─────────────────────────────────────────────────────
|
|
32
|
-
// Uses only the token's own key (last path segment) as the name, discarding
|
|
33
|
-
// the group prefix. With DTCG groups, path is ["spacing", "spacing-01"] so
|
|
34
|
-
// joining would produce "spacing-spacing-01" — we want just "spacing-01".
|
|
35
|
-
const carbonNameKebab = {
|
|
36
|
-
name: 'carbon/name-kebab',
|
|
37
|
-
type: 'name',
|
|
38
|
-
transform(token) {
|
|
39
|
-
return token.path[token.path.length - 1];
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// ── Transform group ───────────────────────────────────────────────────────────
|
|
44
|
-
const CARBON_TRANSFORMS = ['attribute/cti', 'carbon/name-kebab'];
|
|
45
|
-
|
|
46
|
-
// ── SD config ─────────────────────────────────────────────────────────────────
|
|
47
|
-
const config = {
|
|
48
|
-
source: [DTCG_SOURCE],
|
|
49
|
-
platforms: {
|
|
50
|
-
scss: {
|
|
51
|
-
transformGroup: 'carbon',
|
|
52
|
-
buildPath: SCSS_GENERATED + '/',
|
|
53
|
-
files: [
|
|
54
|
-
{ destination: '_spacing.scss', format: 'carbon/scss-spacing' },
|
|
55
|
-
{
|
|
56
|
-
destination: '_fluid-spacing.scss',
|
|
57
|
-
format: 'carbon/scss-fluid-spacing',
|
|
58
|
-
},
|
|
59
|
-
{ destination: '_container.scss', format: 'carbon/scss-container' },
|
|
60
|
-
{ destination: '_icon-size.scss', format: 'carbon/scss-icon-size' },
|
|
61
|
-
{
|
|
62
|
-
destination: '_border-radius.scss',
|
|
63
|
-
format: 'carbon/scss-border-radius',
|
|
64
|
-
},
|
|
65
|
-
{ destination: '_layout.scss', format: 'carbon/scss-layout' },
|
|
66
|
-
{ destination: '_size.scss', format: 'carbon/scss-size' },
|
|
67
|
-
],
|
|
68
|
-
},
|
|
69
|
-
js: {
|
|
70
|
-
transformGroup: 'carbon',
|
|
71
|
-
buildPath: JS_GENERATED + '/',
|
|
72
|
-
files: [
|
|
73
|
-
{
|
|
74
|
-
destination: 'layout-tokens.js',
|
|
75
|
-
format: 'carbon/js-layout',
|
|
76
|
-
options: { output: 'js' },
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
destination: 'layout-tokens.d.ts',
|
|
80
|
-
format: 'carbon/js-layout',
|
|
81
|
-
options: { output: 'dts' },
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// ── Build a registered SD instance ────────────────────────────────────────────
|
|
89
|
-
function createInstance() {
|
|
90
|
-
const sd = new StyleDictionary({});
|
|
91
|
-
sd.registerTransform(carbonNameKebab);
|
|
92
|
-
sd.registerTransformGroup({ name: 'carbon', transforms: CARBON_TRANSFORMS });
|
|
93
|
-
for (const fmt of scssFormats) sd.registerFormat(fmt);
|
|
94
|
-
sd.registerFormat(carbonJsLayout);
|
|
95
|
-
return sd;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ── run ───────────────────────────────────────────────────────────────────────
|
|
99
|
-
async function run() {
|
|
100
|
-
const sd = await createInstance().extend(config);
|
|
101
|
-
await sd.buildAllPlatforms();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
module.exports = { run };
|
package/tsconfig.json
DELETED