@dialpad/dialtone-css 8.81.0-next.2 → 8.81.0-next.3

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/README.md CHANGED
@@ -25,6 +25,14 @@ npm install @dialpad/dialtone-css@latest
25
25
  import '@dialpad/dialtone-css';
26
26
  ```
27
27
 
28
+ #### No-Layers Build
29
+
30
+ If your project cannot use CSS Cascade Layers, import the no-layers variant. You will likely need to use the no-layers build if you are upgrading from Dialtone <=9, unless you migrate your application CSS to support layers. See the [CSS Cascade Layers migration guide](https://dialtone.dialpad.com/guides/migration/css-cascade-layers/) for more details.
31
+
32
+ ```js
33
+ import '@dialpad/dialtone-css/no-layers';
34
+ ```
35
+
28
36
  ### Add dialtone's theme class to the `<body>`
29
37
 
30
38
  - Light mode
@@ -743,8 +743,8 @@ async function runConfigMigration (migration, opts) {
743
743
  // Loop until convergence: some config regexes only match one token per
744
744
  // property declaration per pass (e.g. border-width with two var(--dt-size-*)).
745
745
  for (const entry of matched) {
746
- let changed = true;
747
- while (changed) {
746
+ let changed;
747
+ do {
748
748
  changed = false;
749
749
  for (const expr of configData.expressions) {
750
750
  const before = entry.data;
@@ -758,7 +758,7 @@ async function runConfigMigration (migration, opts) {
758
758
  changed = true;
759
759
  }
760
760
  }
761
- }
761
+ } while (changed && !configData.singlePass);
762
762
  if (entry.matches > 0) {
763
763
  await fs.writeFile(entry.file, entry.data, 'utf8');
764
764
  const shortname = path.relative(opts.cwd, entry.file);
@@ -28,8 +28,8 @@ export default {
28
28
  'eg. var(--dt-space-400) → var(--dt-spacing-100)\n' +
29
29
  '- Replaces var(--dt-space-{stop}-negative) with var(--dt-spacing-{newSuffix}-negative)\n\t' +
30
30
  'eg. var(--dt-space-400-negative) → var(--dt-spacing-100-negative)\n' +
31
- '- Replaces var(--dt-space-{stop}-percent) with var(--dt-spacing-{newSuffix}-percent)\n\t' +
32
- 'eg. var(--dt-space-400-percent) var(--dt-spacing-100-percent)\n' +
31
+ '- var(--dt-space-{stop}-percent) is left unchanged — percent tokens live under\n\t' +
32
+ '--dt-layout-*-percent (a different stop axis), so there is no safe automated mapping.\n' +
33
33
  '- Tokens with no equivalent (720, 730, 750+) are left unchanged for manual review.\n',
34
34
  patterns: ['**/*.{css,less,scss,sass,styl,html,vue,md,js,ts,jsx,tsx}'],
35
35
  globbyConfig: {
@@ -37,7 +37,10 @@ export default {
37
37
  },
38
38
  expressions: [
39
39
  {
40
- from: /var\(--dt-space-([0-9]+)(-negative|-percent)?\)/g,
40
+ // -percent variants are intentionally excluded: --dt-spacing-*-percent tokens do not
41
+ // exist. Percent tokens live under --dt-layout-*-percent with a different stop axis
42
+ // (0/5/10…100 = percentages) and cannot be automatically mapped from space pixel stops.
43
+ from: /var\(--dt-space-([0-9]+)(-negative)?\)/g,
41
44
  to: (match, stop, suffix) => {
42
45
  const newSuffix = MAP[Number(stop)];
43
46
  if (newSuffix == null) return match;
@@ -35,6 +35,9 @@ function isAlreadyMigrated (content) {
35
35
  }
36
36
 
37
37
  export default {
38
+ // Gap values map directly to new spacing stops; the output of one pass (e.g. 200)
39
+ // is also a valid old input (200 → 25). A second pass would double-transform.
40
+ singlePass: true,
38
41
  description:
39
42
  'Migrates DtStack and DtDescriptionList gap prop values from old size stops to new spacing stops.\n' +
40
43
  '- Replaces gap="400" with gap="100" (8px)\n' +
@@ -36,7 +36,7 @@ const NEGATIVE_SPACING_MAP = {
36
36
  32: '400', 48: '600', 64: '800',
37
37
  };
38
38
 
39
- // Layout sizes for margin/padding (96px, 128px use layout tokens)
39
+ // Layout sizes for sizing (96px, 128px use layout tokens)
40
40
  const SPACING_LAYOUT_MAP = {
41
41
  96: '150', 128: '200',
42
42
  };
@@ -77,8 +77,8 @@ export default {
77
77
  'Migrates pixel-based utility class names to token-stop-based names.\n' +
78
78
  '- Sizing: d-h16 → d-h-25, d-w64 → d-w-100, d-hmn96 → d-hmn-150\n' +
79
79
  '- Off-scale sizing: d-w1 → d-w-1px, d-h24 → d-h-24px (pixel-indexed exceptions)\n' +
80
- '- Margin: d-m8 → d-m-100, d-mt16 → d-mt-200, d-mtn8 → d-mt-n100\n' +
81
- '- Padding: d-p8 → d-p-100, d-pt16 → d-pt-200\n' +
80
+ '- Margin: d-m8 → d-m-100, d-mt16 → d-mt-200, d-mtn8 → d-mt-n100 (values ≥ 96px left unchanged)\n' +
81
+ '- Padding: d-p8 → d-p-100, d-pt16 → d-pt-200 (values ≥ 96px left unchanged — no layout-token padding class exists)\n' +
82
82
  '- Gap: d-g8 → d-g-100, d-rg16 → d-rg-200\n' +
83
83
  '- Position: d-t8 → d-t-100, d-tn8 → d-t-n100\n' +
84
84
  '- Border-radius all: d-bar6 → d-bar-350, d-bar24 → d-bar-550\n' +
@@ -134,18 +134,13 @@ export default {
134
134
  ]),
135
135
 
136
136
  // ── Margin: d-m{px} → d-m-{spacing-stop} ─────────────────────────────
137
- ...['m', 'mt', 'mr', 'mb', 'ml', 'mx', 'my'].flatMap(prefix => [
138
- // Spacing sizes (0-64px)
139
- {
140
- from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
141
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
142
- },
143
- // Layout sizes (96, 128px)
144
- {
145
- from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
146
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
147
- },
148
- ]),
137
+ // Only spacing-scale values (0-64px) are migrated. Values ≥ 96px (e.g. d-mt96)
138
+ // are left unchanged: token-stop margin classes use spacing tokens only, so
139
+ // d-mt-150 resolves to --dt-spacing-150 (12px), not --dt-layout-150 (96px).
140
+ ...['m', 'mt', 'mr', 'mb', 'ml', 'mx', 'my'].map(prefix => ({
141
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
142
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
143
+ })),
149
144
 
150
145
  // ── Negative margin: d-m{dir}n{px} → d-m{dir}-n{spacing-stop} ────────
151
146
  ...['mt', 'mr', 'mb', 'ml', 'mx', 'my', 'm'].map(prefix => ({
@@ -154,16 +149,13 @@ export default {
154
149
  })),
155
150
 
156
151
  // ── Padding: d-p{px} → d-p-{spacing-stop} ────────────────────────────
157
- ...['p', 'pt', 'pr', 'pb', 'pl', 'px', 'py'].flatMap(prefix => [
158
- {
159
- from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
160
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
161
- },
162
- {
163
- from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
164
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
165
- },
166
- ]),
152
+ // Only spacing-scale values (0-64px) are migrated. Values ≥ 96px (e.g. d-pt96)
153
+ // are left unchanged: token-stop padding classes use spacing tokens only, so
154
+ // d-pt-150 resolves to --dt-spacing-150 (12px), not --dt-layout-150 (96px).
155
+ ...['p', 'pt', 'pr', 'pb', 'pl', 'px', 'py'].map(prefix => ({
156
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
157
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
158
+ })),
167
159
 
168
160
  // ── Gap: d-g{px} → d-g-{spacing-stop} ────────────────────────────────
169
161
  ...['g', 'rg', 'cg'].map(prefix => ({
@@ -172,17 +164,13 @@ export default {
172
164
  })),
173
165
 
174
166
  // ── Position: d-t{px} → d-t-{spacing-stop} ───────────────────────────
175
- ...['t', 'r', 'b', 'l', 'x', 'y', 'all'].flatMap(prefix => [
176
- {
177
- from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
178
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
179
- },
180
- // Layout position sizes (96px)
181
- {
182
- from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
183
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
184
- },
185
- ]),
167
+ // Only spacing-scale values (0-64px) are migrated. Values ≥ 96px (e.g. d-t96)
168
+ // are left unchanged: token-stop position classes use spacing tokens only, so
169
+ // d-t-150 resolves to --dt-spacing-150 (12px), not --dt-layout-150 (96px).
170
+ ...['t', 'r', 'b', 'l', 'x', 'y', 'all'].map(prefix => ({
171
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
172
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
173
+ })),
186
174
 
187
175
  // ── Negative position: d-{dir}n{px} → d-{dir}-n{spacing-stop} ────────
188
176
  ...['t', 'r', 'b', 'l', 'x', 'y', 'all'].map(prefix => ({
@@ -149,23 +149,19 @@
149
149
  }
150
150
 
151
151
  /* ============================================ */
152
- /* PERCENT VARIANTS */
152
+ /* SKIP CASES (should NOT be modified) */
153
153
  /* ============================================ */
154
154
 
155
- /* space-400-percent spacing-100-percent */
156
- .test-percent-400 {
155
+ /* -percent variants — no --dt-spacing-*-percent tokens exist; percent tokens live under
156
+ --dt-layout-*-percent with a different stop axis, so these are left for manual review */
157
+ .test-skip-percent-400 {
157
158
  padding: var(--dt-space-400-percent);
158
159
  }
159
160
 
160
- /* space-600-percent → spacing-400-percent */
161
- .test-percent-600 {
161
+ .test-skip-percent-600 {
162
162
  gap: var(--dt-space-600-percent);
163
163
  }
164
164
 
165
- /* ============================================ */
166
- /* SKIP CASES (should NOT be modified) */
167
- /* ============================================ */
168
-
169
165
  /* Stops with no --dt-spacing-* equivalent — leave unchanged */
170
166
  .test-skip-720 {
171
167
  padding: var(--dt-space-720); /* 72px — no spacing equivalent */
@@ -89,6 +89,28 @@ describe('utility-class-to-token-stops config', () => {
89
89
  });
90
90
  });
91
91
 
92
+
93
+ // ─── Large spacing values (≥ 96px) pass through unchanged ────────────
94
+ //
95
+ // Token-stop margin/padding/position classes (d-mt-{stop}, d-pt-{stop}, d-t-{stop})
96
+ // use spacing tokens only. d-mt-150 = --dt-spacing-150 (12px), not --dt-layout-150 (96px).
97
+ // These classes must be left for manual review rather than silently changed.
98
+
99
+ describe('large margin/padding/position values — pass through unchanged', () => {
100
+ const unchanged = [
101
+ 'd-mt96', 'd-mb96', 'd-ml96', 'd-mr96', 'd-mx96', 'd-my96', 'd-m96',
102
+ 'd-mt128', 'd-mb128', 'd-ml128', 'd-mr128', 'd-mx128', 'd-my128', 'd-m128',
103
+ 'd-pt96', 'd-pb96', 'd-pl96', 'd-pr96', 'd-px96', 'd-py96', 'd-p96',
104
+ 'd-pt128', 'd-pb128', 'd-pl128', 'd-pr128', 'd-px128', 'd-py128', 'd-p128',
105
+ 'd-t96', 'd-r96', 'd-b96', 'd-l96',
106
+ ];
107
+ for (const cls of unchanged) {
108
+ it(`${cls} is left unchanged`, () => {
109
+ assert.equal(apply(`<div class="${cls}" />`), `<div class="${cls}" />`);
110
+ });
111
+ }
112
+ });
113
+
92
114
  // ─── Border-radius migration (DLT-3329) ───────────────────────────────
93
115
 
94
116
  describe('border-radius all-corners — legacy pixel-suffix to token stop', () => {
@@ -743,8 +743,8 @@ async function runConfigMigration (migration, opts) {
743
743
  // Loop until convergence: some config regexes only match one token per
744
744
  // property declaration per pass (e.g. border-width with two var(--dt-size-*)).
745
745
  for (const entry of matched) {
746
- let changed = true;
747
- while (changed) {
746
+ let changed;
747
+ do {
748
748
  changed = false;
749
749
  for (const expr of configData.expressions) {
750
750
  const before = entry.data;
@@ -758,7 +758,7 @@ async function runConfigMigration (migration, opts) {
758
758
  changed = true;
759
759
  }
760
760
  }
761
- }
761
+ } while (changed && !configData.singlePass);
762
762
  if (entry.matches > 0) {
763
763
  await fs.writeFile(entry.file, entry.data, 'utf8');
764
764
  const shortname = path.relative(opts.cwd, entry.file);
@@ -28,8 +28,8 @@ export default {
28
28
  'eg. var(--dt-space-400) → var(--dt-spacing-100)\n' +
29
29
  '- Replaces var(--dt-space-{stop}-negative) with var(--dt-spacing-{newSuffix}-negative)\n\t' +
30
30
  'eg. var(--dt-space-400-negative) → var(--dt-spacing-100-negative)\n' +
31
- '- Replaces var(--dt-space-{stop}-percent) with var(--dt-spacing-{newSuffix}-percent)\n\t' +
32
- 'eg. var(--dt-space-400-percent) var(--dt-spacing-100-percent)\n' +
31
+ '- var(--dt-space-{stop}-percent) is left unchanged — percent tokens live under\n\t' +
32
+ '--dt-layout-*-percent (a different stop axis), so there is no safe automated mapping.\n' +
33
33
  '- Tokens with no equivalent (720, 730, 750+) are left unchanged for manual review.\n',
34
34
  patterns: ['**/*.{css,less,scss,sass,styl,html,vue,md,js,ts,jsx,tsx}'],
35
35
  globbyConfig: {
@@ -37,7 +37,10 @@ export default {
37
37
  },
38
38
  expressions: [
39
39
  {
40
- from: /var\(--dt-space-([0-9]+)(-negative|-percent)?\)/g,
40
+ // -percent variants are intentionally excluded: --dt-spacing-*-percent tokens do not
41
+ // exist. Percent tokens live under --dt-layout-*-percent with a different stop axis
42
+ // (0/5/10…100 = percentages) and cannot be automatically mapped from space pixel stops.
43
+ from: /var\(--dt-space-([0-9]+)(-negative)?\)/g,
41
44
  to: (match, stop, suffix) => {
42
45
  const newSuffix = MAP[Number(stop)];
43
46
  if (newSuffix == null) return match;
@@ -35,6 +35,9 @@ function isAlreadyMigrated (content) {
35
35
  }
36
36
 
37
37
  export default {
38
+ // Gap values map directly to new spacing stops; the output of one pass (e.g. 200)
39
+ // is also a valid old input (200 → 25). A second pass would double-transform.
40
+ singlePass: true,
38
41
  description:
39
42
  'Migrates DtStack and DtDescriptionList gap prop values from old size stops to new spacing stops.\n' +
40
43
  '- Replaces gap="400" with gap="100" (8px)\n' +
@@ -36,7 +36,7 @@ const NEGATIVE_SPACING_MAP = {
36
36
  32: '400', 48: '600', 64: '800',
37
37
  };
38
38
 
39
- // Layout sizes for margin/padding (96px, 128px use layout tokens)
39
+ // Layout sizes for sizing (96px, 128px use layout tokens)
40
40
  const SPACING_LAYOUT_MAP = {
41
41
  96: '150', 128: '200',
42
42
  };
@@ -77,8 +77,8 @@ export default {
77
77
  'Migrates pixel-based utility class names to token-stop-based names.\n' +
78
78
  '- Sizing: d-h16 → d-h-25, d-w64 → d-w-100, d-hmn96 → d-hmn-150\n' +
79
79
  '- Off-scale sizing: d-w1 → d-w-1px, d-h24 → d-h-24px (pixel-indexed exceptions)\n' +
80
- '- Margin: d-m8 → d-m-100, d-mt16 → d-mt-200, d-mtn8 → d-mt-n100\n' +
81
- '- Padding: d-p8 → d-p-100, d-pt16 → d-pt-200\n' +
80
+ '- Margin: d-m8 → d-m-100, d-mt16 → d-mt-200, d-mtn8 → d-mt-n100 (values ≥ 96px left unchanged)\n' +
81
+ '- Padding: d-p8 → d-p-100, d-pt16 → d-pt-200 (values ≥ 96px left unchanged — no layout-token padding class exists)\n' +
82
82
  '- Gap: d-g8 → d-g-100, d-rg16 → d-rg-200\n' +
83
83
  '- Position: d-t8 → d-t-100, d-tn8 → d-t-n100\n' +
84
84
  '- Border-radius all: d-bar6 → d-bar-350, d-bar24 → d-bar-550\n' +
@@ -134,18 +134,13 @@ export default {
134
134
  ]),
135
135
 
136
136
  // ── Margin: d-m{px} → d-m-{spacing-stop} ─────────────────────────────
137
- ...['m', 'mt', 'mr', 'mb', 'ml', 'mx', 'my'].flatMap(prefix => [
138
- // Spacing sizes (0-64px)
139
- {
140
- from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
141
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
142
- },
143
- // Layout sizes (96, 128px)
144
- {
145
- from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
146
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
147
- },
148
- ]),
137
+ // Only spacing-scale values (0-64px) are migrated. Values ≥ 96px (e.g. d-mt96)
138
+ // are left unchanged: token-stop margin classes use spacing tokens only, so
139
+ // d-mt-150 resolves to --dt-spacing-150 (12px), not --dt-layout-150 (96px).
140
+ ...['m', 'mt', 'mr', 'mb', 'ml', 'mx', 'my'].map(prefix => ({
141
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
142
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
143
+ })),
149
144
 
150
145
  // ── Negative margin: d-m{dir}n{px} → d-m{dir}-n{spacing-stop} ────────
151
146
  ...['mt', 'mr', 'mb', 'ml', 'mx', 'my', 'm'].map(prefix => ({
@@ -154,16 +149,13 @@ export default {
154
149
  })),
155
150
 
156
151
  // ── Padding: d-p{px} → d-p-{spacing-stop} ────────────────────────────
157
- ...['p', 'pt', 'pr', 'pb', 'pl', 'px', 'py'].flatMap(prefix => [
158
- {
159
- from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
160
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
161
- },
162
- {
163
- from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
164
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
165
- },
166
- ]),
152
+ // Only spacing-scale values (0-64px) are migrated. Values ≥ 96px (e.g. d-pt96)
153
+ // are left unchanged: token-stop padding classes use spacing tokens only, so
154
+ // d-pt-150 resolves to --dt-spacing-150 (12px), not --dt-layout-150 (96px).
155
+ ...['p', 'pt', 'pr', 'pb', 'pl', 'px', 'py'].map(prefix => ({
156
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
157
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
158
+ })),
167
159
 
168
160
  // ── Gap: d-g{px} → d-g-{spacing-stop} ────────────────────────────────
169
161
  ...['g', 'rg', 'cg'].map(prefix => ({
@@ -172,17 +164,13 @@ export default {
172
164
  })),
173
165
 
174
166
  // ── Position: d-t{px} → d-t-{spacing-stop} ───────────────────────────
175
- ...['t', 'r', 'b', 'l', 'x', 'y', 'all'].flatMap(prefix => [
176
- {
177
- from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
178
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
179
- },
180
- // Layout position sizes (96px)
181
- {
182
- from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
183
- to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
184
- },
185
- ]),
167
+ // Only spacing-scale values (0-64px) are migrated. Values ≥ 96px (e.g. d-t96)
168
+ // are left unchanged: token-stop position classes use spacing tokens only, so
169
+ // d-t-150 resolves to --dt-spacing-150 (12px), not --dt-layout-150 (96px).
170
+ ...['t', 'r', 'b', 'l', 'x', 'y', 'all'].map(prefix => ({
171
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
172
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
173
+ })),
186
174
 
187
175
  // ── Negative position: d-{dir}n{px} → d-{dir}-n{spacing-stop} ────────
188
176
  ...['t', 'r', 'b', 'l', 'x', 'y', 'all'].map(prefix => ({
@@ -149,23 +149,19 @@
149
149
  }
150
150
 
151
151
  /* ============================================ */
152
- /* PERCENT VARIANTS */
152
+ /* SKIP CASES (should NOT be modified) */
153
153
  /* ============================================ */
154
154
 
155
- /* space-400-percent spacing-100-percent */
156
- .test-percent-400 {
155
+ /* -percent variants — no --dt-spacing-*-percent tokens exist; percent tokens live under
156
+ --dt-layout-*-percent with a different stop axis, so these are left for manual review */
157
+ .test-skip-percent-400 {
157
158
  padding: var(--dt-space-400-percent);
158
159
  }
159
160
 
160
- /* space-600-percent → spacing-400-percent */
161
- .test-percent-600 {
161
+ .test-skip-percent-600 {
162
162
  gap: var(--dt-space-600-percent);
163
163
  }
164
164
 
165
- /* ============================================ */
166
- /* SKIP CASES (should NOT be modified) */
167
- /* ============================================ */
168
-
169
165
  /* Stops with no --dt-spacing-* equivalent — leave unchanged */
170
166
  .test-skip-720 {
171
167
  padding: var(--dt-space-720); /* 72px — no spacing equivalent */
@@ -89,6 +89,28 @@ describe('utility-class-to-token-stops config', () => {
89
89
  });
90
90
  });
91
91
 
92
+
93
+ // ─── Large spacing values (≥ 96px) pass through unchanged ────────────
94
+ //
95
+ // Token-stop margin/padding/position classes (d-mt-{stop}, d-pt-{stop}, d-t-{stop})
96
+ // use spacing tokens only. d-mt-150 = --dt-spacing-150 (12px), not --dt-layout-150 (96px).
97
+ // These classes must be left for manual review rather than silently changed.
98
+
99
+ describe('large margin/padding/position values — pass through unchanged', () => {
100
+ const unchanged = [
101
+ 'd-mt96', 'd-mb96', 'd-ml96', 'd-mr96', 'd-mx96', 'd-my96', 'd-m96',
102
+ 'd-mt128', 'd-mb128', 'd-ml128', 'd-mr128', 'd-mx128', 'd-my128', 'd-m128',
103
+ 'd-pt96', 'd-pb96', 'd-pl96', 'd-pr96', 'd-px96', 'd-py96', 'd-p96',
104
+ 'd-pt128', 'd-pb128', 'd-pl128', 'd-pr128', 'd-px128', 'd-py128', 'd-p128',
105
+ 'd-t96', 'd-r96', 'd-b96', 'd-l96',
106
+ ];
107
+ for (const cls of unchanged) {
108
+ it(`${cls} is left unchanged`, () => {
109
+ assert.equal(apply(`<div class="${cls}" />`), `<div class="${cls}" />`);
110
+ });
111
+ }
112
+ });
113
+
92
114
  // ─── Border-radius migration (DLT-3329) ───────────────────────────────
93
115
 
94
116
  describe('border-radius all-corners — legacy pixel-suffix to token stop', () => {