@carbon/layout 11.59.0-rc.0 → 11.60.0-rc.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/src/index.ts CHANGED
@@ -5,7 +5,58 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
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
+
8
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';
9
60
 
10
61
  export { unstable_tokens };
11
62
 
@@ -51,29 +102,29 @@ export const px = (value: number) => {
51
102
  // Initial map of our breakpoints and their values
52
103
  export const breakpoints: Record<BreakpointName, Breakpoint> = {
53
104
  sm: {
54
- width: /*#__PURE__*/ rem(320),
105
+ width: rem(320),
55
106
  columns: 4,
56
107
  margin: '0',
57
108
  },
58
109
  md: {
59
- width: /*#__PURE__*/ rem(672),
110
+ width: rem(672),
60
111
  columns: 8,
61
- margin: /*#__PURE__*/ rem(16),
112
+ margin: rem(16),
62
113
  },
63
114
  lg: {
64
- width: /*#__PURE__*/ rem(1056),
115
+ width: rem(1056),
65
116
  columns: 16,
66
- margin: /*#__PURE__*/ rem(16),
117
+ margin: rem(16),
67
118
  },
68
119
  xlg: {
69
- width: /*#__PURE__*/ rem(1312),
120
+ width: rem(1312),
70
121
  columns: 16,
71
- margin: /*#__PURE__*/ rem(16),
122
+ margin: rem(16),
72
123
  },
73
124
  max: {
74
- width: /*#__PURE__*/ rem(1584),
125
+ width: rem(1584),
75
126
  columns: 16,
76
- margin: /*#__PURE__*/ rem(24),
127
+ margin: rem(24),
77
128
  },
78
129
  };
79
130
 
@@ -94,20 +145,7 @@ export const miniUnits = (count: number) => {
94
145
  return rem(miniUnit * count);
95
146
  };
96
147
 
97
- // Spacing
98
- export const spacing01 = /*#__PURE__*/ miniUnits(0.25);
99
- export const spacing02 = /*#__PURE__*/ miniUnits(0.5);
100
- export const spacing03 = /*#__PURE__*/ miniUnits(1);
101
- export const spacing04 = /*#__PURE__*/ miniUnits(1.5);
102
- export const spacing05 = /*#__PURE__*/ miniUnits(2);
103
- export const spacing06 = /*#__PURE__*/ miniUnits(3);
104
- export const spacing07 = /*#__PURE__*/ miniUnits(4);
105
- export const spacing08 = /*#__PURE__*/ miniUnits(5);
106
- export const spacing09 = /*#__PURE__*/ miniUnits(6);
107
- export const spacing10 = /*#__PURE__*/ miniUnits(8);
108
- export const spacing11 = /*#__PURE__*/ miniUnits(10);
109
- export const spacing12 = /*#__PURE__*/ miniUnits(12);
110
- export const spacing13 = /*#__PURE__*/ miniUnits(20);
148
+ // Spacing — aggregate array (individual tokens come from generated re-export above)
111
149
  export const spacing = [
112
150
  spacing01,
113
151
  spacing02,
@@ -124,11 +162,7 @@ export const spacing = [
124
162
  spacing13,
125
163
  ];
126
164
 
127
- // Fluid spacing
128
- export const fluidSpacing01 = 0;
129
- export const fluidSpacing02 = '2vw';
130
- export const fluidSpacing03 = '5vw';
131
- export const fluidSpacing04 = '10vw';
165
+ // Fluid spacing — aggregate array
132
166
  export const fluidSpacing = [
133
167
  fluidSpacing01,
134
168
  fluidSpacing02,
@@ -136,15 +170,7 @@ export const fluidSpacing = [
136
170
  fluidSpacing04,
137
171
  ];
138
172
 
139
- // Layout
140
- // Deprecated
141
- export const layout01 = /*#__PURE__*/ miniUnits(2);
142
- export const layout02 = /*#__PURE__*/ miniUnits(3);
143
- export const layout03 = /*#__PURE__*/ miniUnits(4);
144
- export const layout04 = /*#__PURE__*/ miniUnits(6);
145
- export const layout05 = /*#__PURE__*/ miniUnits(8);
146
- export const layout06 = /*#__PURE__*/ miniUnits(12);
147
- export const layout07 = /*#__PURE__*/ miniUnits(20);
173
+ // Layout (deprecated) — aggregate array
148
174
  export const layout = [
149
175
  layout01,
150
176
  layout02,
@@ -155,12 +181,7 @@ export const layout = [
155
181
  layout07,
156
182
  ];
157
183
 
158
- // Container
159
- export const container01 = /*#__PURE__*/ miniUnits(3);
160
- export const container02 = /*#__PURE__*/ miniUnits(4);
161
- export const container03 = /*#__PURE__*/ miniUnits(5);
162
- export const container04 = /*#__PURE__*/ miniUnits(6);
163
- export const container05 = /*#__PURE__*/ miniUnits(8);
184
+ // Container — aggregate array
164
185
  export const container = [
165
186
  container01,
166
187
  container02,
@@ -168,12 +189,14 @@ export const container = [
168
189
  container04,
169
190
  container05,
170
191
  ];
171
- export const sizeXSmall = /*#__PURE__*/ rem(24);
172
- export const sizeSmall = /*#__PURE__*/ rem(32);
173
- export const sizeMedium = /*#__PURE__*/ rem(40);
174
- export const sizeLarge = /*#__PURE__*/ rem(48);
175
- export const sizeXLarge = /*#__PURE__*/ rem(64);
176
- export const size2XLarge = /*#__PURE__*/ rem(80);
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;
177
200
  export const sizes: Record<SizeName, string> = {
178
201
  XSmall: sizeXSmall,
179
202
  Small: sizeSmall,
@@ -183,19 +206,10 @@ export const sizes: Record<SizeName, string> = {
183
206
  '2XLarge': size2XLarge,
184
207
  };
185
208
 
186
- // Icon
187
- export const iconSize01 = '1rem';
188
- export const iconSize02 = '1.25rem';
209
+ // Icon — aggregate array
189
210
  export const iconSize = [iconSize01, iconSize02];
190
211
 
191
- // Border radius
192
- export const borderRadius00 = '0px';
193
- export const borderRadius02 = rem(2);
194
- export const borderRadius04 = rem(4);
195
- export const borderRadius08 = rem(8);
196
- export const borderRadius16 = rem(16);
197
- export const borderRadius24 = rem(24);
198
- export const borderRadiusMax = '999999px';
212
+ // Border radius — aggregate record keyed by CSS custom property name
199
213
  export const borderRadius: Record<BorderRadiusToken, string> = {
200
214
  'border-radius-00': borderRadius00,
201
215
  'border-radius-02': borderRadius02,
@@ -0,0 +1,104 @@
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
+ };
@@ -0,0 +1,188 @@
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
+ ];
@@ -0,0 +1,104 @@
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 };