@dialpad/dialtone-css 8.78.0-next.1 → 8.78.0-next.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 (102) hide show
  1. package/README.md +0 -2
  2. package/lib/build/js/dialtone_migrate_flex_to_stack/examples-edge-cases.vue +26 -0
  3. package/lib/build/js/dialtone_migrate_flex_to_stack/index.mjs +56 -15
  4. package/lib/build/js/dialtone_migration_helper/configs/size-to-layout.mjs +212 -0
  5. package/lib/build/js/dialtone_migration_helper/configs/space-to-spacing.mjs +48 -0
  6. package/lib/build/js/dialtone_migration_helper/configs/stack-gap-to-spacing.mjs +88 -0
  7. package/lib/build/js/dialtone_migration_helper/configs/utility-class-to-token-stops.mjs +135 -0
  8. package/lib/build/js/dialtone_migration_helper/tests/size-to-layout-test-examples.vue +275 -0
  9. package/lib/build/js/dialtone_migration_helper/tests/space-to-spacing-test-examples.vue +193 -0
  10. package/lib/build/less/components/avatar.less +8 -19
  11. package/lib/build/less/components/badge.less +22 -20
  12. package/lib/build/less/components/banner.less +5 -5
  13. package/lib/build/less/components/breadcrumbs.less +4 -4
  14. package/lib/build/less/components/button.less +39 -39
  15. package/lib/build/less/components/card.less +4 -4
  16. package/lib/build/less/components/chip.less +41 -51
  17. package/lib/build/less/components/codeblock.less +2 -2
  18. package/lib/build/less/components/collapsible.less +2 -2
  19. package/lib/build/less/components/combobox-multi-select.less +8 -8
  20. package/lib/build/less/components/combobox-with-popover.less +1 -1
  21. package/lib/build/less/components/combobox.less +5 -5
  22. package/lib/build/less/components/datepicker.less +6 -6
  23. package/lib/build/less/components/description-list.less +14 -3
  24. package/lib/build/less/components/dropdown.less +4 -4
  25. package/lib/build/less/components/emoji-picker.less +35 -35
  26. package/lib/build/less/components/empty-state.less +5 -5
  27. package/lib/build/less/components/filter-pill.less +5 -5
  28. package/lib/build/less/components/forms.less +10 -10
  29. package/lib/build/less/components/image-viewer.less +2 -2
  30. package/lib/build/less/components/input.less +17 -22
  31. package/lib/build/less/components/item-layout.less +8 -8
  32. package/lib/build/less/components/keyboard-shortcut.less +3 -3
  33. package/lib/build/less/components/link.less +5 -5
  34. package/lib/build/less/components/list-group.less +1 -1
  35. package/lib/build/less/components/list-item-group.less +1 -1
  36. package/lib/build/less/components/list-item.less +9 -9
  37. package/lib/build/less/components/modal.less +20 -20
  38. package/lib/build/less/components/notice.less +11 -11
  39. package/lib/build/less/components/pagination.less +5 -5
  40. package/lib/build/less/components/popover.less +5 -5
  41. package/lib/build/less/components/radio-checkbox.less +11 -10
  42. package/lib/build/less/components/rich-text-editor.less +13 -13
  43. package/lib/build/less/components/scrollbar.less +2 -2
  44. package/lib/build/less/components/segmented-control.less +6 -6
  45. package/lib/build/less/components/selects.less +18 -13
  46. package/lib/build/less/components/skeleton.less +4 -4
  47. package/lib/build/less/components/stack.less +24 -69
  48. package/lib/build/less/components/table.less +6 -7
  49. package/lib/build/less/components/tabs.less +24 -24
  50. package/lib/build/less/components/toast.less +16 -16
  51. package/lib/build/less/components/toggle.less +23 -23
  52. package/lib/build/less/components/tooltip.less +27 -27
  53. package/lib/build/less/dialtone-reset.less +3 -3
  54. package/lib/build/less/dialtone-transitions.less +4 -4
  55. package/lib/build/less/dialtone.less +2 -2
  56. package/lib/build/less/recipes/attachment_carousel.less +13 -13
  57. package/lib/build/less/recipes/callbar_button.less +1 -1
  58. package/lib/build/less/recipes/callbar_button_with_dropdown.less +7 -7
  59. package/lib/build/less/recipes/callbar_button_with_popover.less +8 -8
  60. package/lib/build/less/recipes/callbox.less +6 -6
  61. package/lib/build/less/recipes/contact_info.less +9 -9
  62. package/lib/build/less/recipes/editor.less +12 -12
  63. package/lib/build/less/recipes/emoji_row.less +8 -8
  64. package/lib/build/less/recipes/feed_item_pill.less +13 -13
  65. package/lib/build/less/recipes/feed_item_row.less +10 -10
  66. package/lib/build/less/recipes/grouped_chip.less +2 -2
  67. package/lib/build/less/recipes/ivr_node.less +13 -13
  68. package/lib/build/less/recipes/leftbar_row.less +23 -23
  69. package/lib/build/less/recipes/message_input.less +16 -16
  70. package/lib/build/less/recipes/settings_menu_button.less +10 -10
  71. package/lib/build/less/recipes/time_pill.less +1 -1
  72. package/lib/build/less/recipes/top_banner_info.less +8 -8
  73. package/lib/build/less/recipes/unread_pill.less +2 -2
  74. package/lib/build/less/themes/default.less +1 -1
  75. package/lib/build/less/utilities/backgrounds.less +3 -3
  76. package/lib/build/less/utilities/effects.less +20 -20
  77. package/lib/build/less/utilities/flex.less +11 -11
  78. package/lib/build/less/utilities/layout.less +4 -4
  79. package/lib/build/less/utilities/sizing.less +172 -0
  80. package/lib/build/less/utilities/spacing.less +49 -49
  81. package/lib/build/less/utilities/typography.less +2 -2
  82. package/lib/build/less/variables/sizes.less +8 -8
  83. package/lib/dist/dialtone-default-theme.css +5220 -1117
  84. package/lib/dist/dialtone-default-theme.min.css +1 -1
  85. package/lib/dist/dialtone-docs.json +1 -1
  86. package/lib/dist/dialtone.css +5203 -1117
  87. package/lib/dist/dialtone.min.css +1 -1
  88. package/lib/dist/js/dialtone_migrate_flex_to_stack/examples-edge-cases.vue +26 -0
  89. package/lib/dist/js/dialtone_migrate_flex_to_stack/index.mjs +56 -15
  90. package/lib/dist/js/dialtone_migration_helper/configs/size-to-layout.mjs +212 -0
  91. package/lib/dist/js/dialtone_migration_helper/configs/space-to-spacing.mjs +48 -0
  92. package/lib/dist/js/dialtone_migration_helper/configs/stack-gap-to-spacing.mjs +88 -0
  93. package/lib/dist/js/dialtone_migration_helper/configs/utility-class-to-token-stops.mjs +135 -0
  94. package/lib/dist/js/dialtone_migration_helper/tests/size-to-layout-test-examples.vue +275 -0
  95. package/lib/dist/js/dialtone_migration_helper/tests/space-to-spacing-test-examples.vue +193 -0
  96. package/lib/dist/tokens/tokens-base-dark.css +17 -0
  97. package/lib/dist/tokens/tokens-base-light.css +17 -0
  98. package/lib/dist/tokens/tokens-debug-base.css +17 -0
  99. package/lib/dist/tokens-docs.json +1 -1
  100. package/package.json +3 -3
  101. package/lib/build/js/dialtone_migration_helper/configs/space-to-size.mjs +0 -15
  102. package/lib/dist/js/dialtone_migration_helper/configs/space-to-size.mjs +0 -15
@@ -292,6 +292,32 @@
292
292
 
293
293
  <!-- TEST 47: Empty element with flex - Should convert -->
294
294
  <div class="d-d-flex d-fd-column"></div>
295
+
296
+ <!-- ============================================ -->
297
+ <!-- NEW TESTS: NEW-FORMAT GAP UTILITIES (d-g-*) -->
298
+ <!-- ============================================ -->
299
+
300
+ <!-- TEST 48: New-format gap d-g-100 (8px) - Should convert to gap="100" -->
301
+ <div class="d-d-flex d-ai-center d-g-100">
302
+ <span>New gap format 8px</span>
303
+ </div>
304
+
305
+ <!-- TEST 49: New-format gap d-g-200 (16px) - Should convert to gap="200" -->
306
+ <div class="d-d-flex d-fd-row d-g-200">
307
+ <span>Item 1</span>
308
+ <span>Item 2</span>
309
+ </div>
310
+
311
+ <!-- TEST 50: New-format gap d-g-400 (32px) with other props - Should convert -->
312
+ <div class="d-d-flex d-fd-column d-ai-center d-jc-between d-g-400">
313
+ <span>Full props with new gap</span>
314
+ <span>Example</span>
315
+ </div>
316
+
317
+ <!-- TEST 51: New-format gap d-g-50 (4px) - Should convert to gap="50" -->
318
+ <div class="d-d-flex d-ai-center d-g-50">
319
+ <span>Small gap 4px</span>
320
+ </div>
295
321
  </template>
296
322
 
297
323
  <script setup>
@@ -142,23 +142,64 @@ const FLEX_TO_PROP = {
142
142
  'd-fd-row-reverse': { prop: 'direction', value: 'row-reverse' },
143
143
  'd-fd-column-reverse': { prop: 'direction', value: 'column-reverse' },
144
144
 
145
- // Gap mappings (d-g* → gap prop)
145
+ // Gap mappings (d-g* → gap prop) — old pixel-based utilities
146
146
  'd-g0': { prop: 'gap', value: '0' },
147
- 'd-g8': { prop: 'gap', value: '400' },
148
- 'd-g16': { prop: 'gap', value: '500' },
149
- 'd-g24': { prop: 'gap', value: '550' },
150
- 'd-g32': { prop: 'gap', value: '600' },
151
- 'd-g48': { prop: 'gap', value: '650' },
152
- 'd-g64': { prop: 'gap', value: '700' },
153
-
154
- // Grid-gap mappings (d-gg* gap prop) - deprecated utilities, same as d-g*
147
+ 'd-g1': { prop: 'gap', value: '1' },
148
+ 'd-g2': { prop: 'gap', value: '25' },
149
+ 'd-g4': { prop: 'gap', value: '50' },
150
+ 'd-g6': { prop: 'gap', value: '75' },
151
+ 'd-g8': { prop: 'gap', value: '100' },
152
+ 'd-g10': { prop: 'gap', value: '125' },
153
+ 'd-g12': { prop: 'gap', value: '150' },
154
+ 'd-g14': { prop: 'gap', value: '175' },
155
+ 'd-g16': { prop: 'gap', value: '200' },
156
+ 'd-g20': { prop: 'gap', value: '250' },
157
+ 'd-g24': { prop: 'gap', value: '300' },
158
+ 'd-g32': { prop: 'gap', value: '400' },
159
+ 'd-g48': { prop: 'gap', value: '600' },
160
+ 'd-g64': { prop: 'gap', value: '800' },
161
+
162
+ // Gap mappings (d-g-* → gap prop) — new token-stop-based utilities
163
+ 'd-g-0': { prop: 'gap', value: '0' },
164
+ 'd-g-1': { prop: 'gap', value: '1' },
165
+ 'd-g-25': { prop: 'gap', value: '25' },
166
+ 'd-g-50': { prop: 'gap', value: '50' },
167
+ 'd-g-75': { prop: 'gap', value: '75' },
168
+ 'd-g-100': { prop: 'gap', value: '100' },
169
+ 'd-g-125': { prop: 'gap', value: '125' },
170
+ 'd-g-150': { prop: 'gap', value: '150' },
171
+ 'd-g-175': { prop: 'gap', value: '175' },
172
+ 'd-g-200': { prop: 'gap', value: '200' },
173
+ 'd-g-250': { prop: 'gap', value: '250' },
174
+ 'd-g-300': { prop: 'gap', value: '300' },
175
+ 'd-g-350': { prop: 'gap', value: '350' },
176
+ 'd-g-400': { prop: 'gap', value: '400' },
177
+ 'd-g-450': { prop: 'gap', value: '450' },
178
+ 'd-g-500': { prop: 'gap', value: '500' },
179
+ 'd-g-525': { prop: 'gap', value: '525' },
180
+ 'd-g-550': { prop: 'gap', value: '550' },
181
+ 'd-g-600': { prop: 'gap', value: '600' },
182
+ 'd-g-650': { prop: 'gap', value: '650' },
183
+ 'd-g-700': { prop: 'gap', value: '700' },
184
+ 'd-g-750': { prop: 'gap', value: '750' },
185
+ 'd-g-800': { prop: 'gap', value: '800' },
186
+
187
+ // Grid-gap mappings (d-gg* → gap prop) — deprecated utilities
155
188
  'd-gg0': { prop: 'gap', value: '0' },
156
- 'd-gg8': { prop: 'gap', value: '400' },
157
- 'd-gg16': { prop: 'gap', value: '500' },
158
- 'd-gg24': { prop: 'gap', value: '550' },
159
- 'd-gg32': { prop: 'gap', value: '600' },
160
- 'd-gg48': { prop: 'gap', value: '650' },
161
- 'd-gg64': { prop: 'gap', value: '700' },
189
+ 'd-gg1': { prop: 'gap', value: '1' },
190
+ 'd-gg2': { prop: 'gap', value: '25' },
191
+ 'd-gg4': { prop: 'gap', value: '50' },
192
+ 'd-gg6': { prop: 'gap', value: '75' },
193
+ 'd-gg8': { prop: 'gap', value: '100' },
194
+ 'd-gg10': { prop: 'gap', value: '125' },
195
+ 'd-gg12': { prop: 'gap', value: '150' },
196
+ 'd-gg14': { prop: 'gap', value: '175' },
197
+ 'd-gg16': { prop: 'gap', value: '200' },
198
+ 'd-gg20': { prop: 'gap', value: '250' },
199
+ 'd-gg24': { prop: 'gap', value: '300' },
200
+ 'd-gg32': { prop: 'gap', value: '400' },
201
+ 'd-gg48': { prop: 'gap', value: '600' },
202
+ 'd-gg64': { prop: 'gap', value: '800' },
162
203
  };
163
204
 
164
205
  // Classes to remove (redundant on dt-stack)
@@ -0,0 +1,212 @@
1
+ // Mapping: --dt-size-{stop} → --dt-spacing-{suffix}
2
+ // For tokens used in spacing context (padding, margin, gap, inset, etc.)
3
+ const SPACING_MAP = {
4
+ 0: 'spacing-0', // 0px
5
+ 50: 'spacing-1', // 0.5px → 1px (nearest non-subpixel)
6
+ 100: 'spacing-1', // 1px
7
+ 200: 'spacing-25', // 2px
8
+ 300: 'spacing-50', // 4px
9
+ 350: 'spacing-75', // 6px
10
+ 400: 'spacing-100', // 8px
11
+ 450: 'spacing-150', // 12px
12
+ 500: 'spacing-200', // 16px
13
+ 525: 'spacing-250', // 20px
14
+ 550: 'spacing-300', // 24px
15
+ 600: 'spacing-400', // 32px
16
+ 625: 'spacing-525', // 42px
17
+ 650: 'spacing-600', // 48px
18
+ 700: 'spacing-800', // 64px
19
+ };
20
+
21
+ // Mapping: --dt-size-{stop} → --dt-layout-{suffix}
22
+ // For tokens used in layout context (width, height, etc.)
23
+ // Exact matches are labeled; nearest-neighbor approximations note the delta.
24
+ const LAYOUT_MAP = {
25
+ // Exact scale matches
26
+ 500: '25', // 16px
27
+ 600: '50', // 32px
28
+ 650: '75', // 48px
29
+ 700: '100', // 64px
30
+ 750: '150', // 96px
31
+ 800: '200', // 128px
32
+ 850: '300', // 192px
33
+ 900: '400', // 256px
34
+ 950: '600', // 384px
35
+ 1000: '800', // 512px
36
+ 1050: '1200', // 768px
37
+ 1100: '1600', // 1024px
38
+ // Nearest-neighbor (no exact match in --dt-layout-* scale)
39
+ 825: '250', // 164px → 160px (Δ4px)
40
+ 875: '350', // 216px → 224px (Δ8px)
41
+ 905: '400', // 264px → 256px (Δ8px)
42
+ 925: '500', // 332px → 320px (Δ12px)
43
+ 975: '700', // 464px → 448px (Δ16px)
44
+ 1020: '1000', // 628px → 640px (Δ12px)
45
+ 1040: '1200', // 764px → 768px (Δ4px)
46
+ 1060: '1300', // 828px → 832px (Δ4px)
47
+ 1080: '1400', // 912px → 896px (Δ16px)
48
+ // Previously missing — these old stops silently passed through
49
+ 720: '100', // 72px → 64px (Δ8px)
50
+ 730: '125', // 84px → 80px (Δ4px)
51
+ 760: '150', // 102px → 96px (Δ6px)
52
+ 775: '175', // 114px → 112px (Δ2px)
53
+ };
54
+
55
+ // Tokens that exceed the --dt-layout-* scale (max 1024px at layout-1600).
56
+ // Converted to raw rem values with a TODO comment for future token replacement.
57
+ const RAW_FALLBACK = {
58
+ 1115: '71.25rem', // 1140px
59
+ 1120: '79.25rem', // 1268px
60
+ 1125: '80rem', // 1280px
61
+ 1130: '83.75rem', // 1340px
62
+ 1150: '96rem', // 1536px
63
+ 1200: '128rem', // 2048px
64
+ };
65
+
66
+ // Valid stops for semantic border and radius tokens
67
+ const BORDER_STOPS = new Set([0, 50, 100, 150, 200, 300, 400]);
68
+ const RADIUS_STOPS = new Set([0, 100, 200, 300, 350, 400, 450, 500, 600]);
69
+
70
+ // ── Replacer factories ─────────────────────────────────────────────────────
71
+
72
+ function spacingReplacer (match, pre, stop, suffix) {
73
+ const token = SPACING_MAP[Number(stop)];
74
+ return token ? `${pre}var(--dt-${token}${suffix || ''})` : match;
75
+ }
76
+
77
+ function layoutReplacer (match, pre, stop, suffix) {
78
+ const s = Number(stop);
79
+ if (LAYOUT_MAP[s]) return `${pre}var(--dt-layout-${LAYOUT_MAP[s]}${suffix || ''})`;
80
+ if (RAW_FALLBACK[s]) {
81
+ return `${pre}${RAW_FALLBACK[s]} /* TODO: no --dt-layout-* equivalent for --dt-size-${s} — replace with a layout token when one is added */`;
82
+ }
83
+ return match;
84
+ }
85
+
86
+ function borderReplacer (match, pre, stop) {
87
+ const s = Number(stop);
88
+ return BORDER_STOPS.has(s) ? `${pre}var(--dt-size-border-${s})` : match;
89
+ }
90
+
91
+ function radiusReplacer (match, pre, stop) {
92
+ const s = Number(stop);
93
+ return RADIUS_STOPS.has(s) ? `${pre}var(--dt-size-radius-${s})` : match;
94
+ }
95
+
96
+ // Spacing property names (physical + logical)
97
+ const SPACING_PROPS =
98
+ 'padding(?:-(?:top|right|bottom|left|block(?:-(?:start|end))?|inline(?:-(?:start|end))?))?|' +
99
+ 'margin(?:-(?:top|right|bottom|left|block(?:-(?:start|end))?|inline(?:-(?:start|end))?))?|' +
100
+ 'gap|row-gap|column-gap|' +
101
+ 'inset(?:-(?:block(?:-(?:start|end))?|inline(?:-(?:start|end))?))?|' +
102
+ // Custom properties whose name contains spacing-related keywords
103
+ // e.g. --badge-padding-x, --badge-gap, --badge-letter-spacing
104
+ '--[a-z0-9-]*(?:padding|margin|gap|spacing|inset|offset)[a-z0-9-]*';
105
+
106
+ // Layout property names (physical + logical)
107
+ const LAYOUT_PROPS =
108
+ '(?:min-|max-)?width|' +
109
+ '(?:min-|max-)?height|' +
110
+ 'flex-basis|' +
111
+ '(?:min-|max-)?inline-size|' +
112
+ '(?:min-|max-)?block-size|' +
113
+ // Custom properties whose name contains layout-related keywords
114
+ // e.g. --badge-min-width
115
+ // Note: "height" is intentionally excluded — "line-height" custom props would misroute.
116
+ // Note: "radius" is handled by RADIUS_PROPS, not here.
117
+ '--[a-z0-9-]*(?:width|basis)[a-z0-9-]*';
118
+
119
+ // Border-width property names → --dt-size-border-*
120
+ // Matches border shorthand, border-width, directional border-*, outline, outline-width.
121
+ // Does NOT match border-color, border-style, border-image, or border-radius.
122
+ const BORDER_PROPS =
123
+ 'border(?:-(?:top|right|bottom|left|block(?:-(?:start|end))?|inline(?:-(?:start|end))?))?(?:-width)?|' +
124
+ 'outline(?:-width)?|' +
125
+ // Custom properties with "border-width" in name (e.g. --popover-border-width)
126
+ '--[a-z0-9-]*border-width[a-z0-9-]*';
127
+
128
+ // Border-radius property names → --dt-size-radius-*
129
+ const RADIUS_PROPS =
130
+ 'border-radius|' +
131
+ 'border-(?:top|bottom)-(?:left|right)-radius|' +
132
+ 'border-(?:start|end)-(?:start|end)-radius|' +
133
+ // Custom properties with "radius" in name (e.g. --badge-radius, --notice-border-radius)
134
+ '--[a-z0-9-]*radius[a-z0-9-]*';
135
+
136
+ export default {
137
+ description:
138
+ 'Migrates --dt-size-* tokens based on CSS property context.\n' +
139
+ '- Border properties (border, border-width, outline) → var(--dt-size-border-*)\n\t' +
140
+ 'eg. border: var(--dt-size-100) solid → border: var(--dt-size-border-100) solid\n' +
141
+ '- Border-radius properties → var(--dt-size-radius-*)\n\t' +
142
+ 'eg. border-radius: var(--dt-size-300) → border-radius: var(--dt-size-radius-300)\n' +
143
+ '- Spacing properties (padding, margin, gap, inset) → var(--dt-spacing-*)\n\t' +
144
+ 'eg. padding: var(--dt-size-400) → padding: var(--dt-spacing-100)\n' +
145
+ '- Layout properties (width, height, min/max, flex-basis) → var(--dt-layout-*)\n\t' +
146
+ 'eg. width: var(--dt-size-700) → width: var(--dt-layout-100)\n' +
147
+ '- Percentage tokens → var(--dt-layout-*-percent)\n\t' +
148
+ 'eg. var(--dt-size-100-percent) → var(--dt-layout-100-percent)\n' +
149
+ '- Tokens exceeding the layout scale (>1024px) are converted to raw rem with a TODO comment.\n' +
150
+ '- Also converts calc(var(--dt-spacing-*) * -1) → var(--dt-spacing-*-negative).\n' +
151
+ '- Unmapped tokens pass through unchanged — the lint rule will flag them.\n',
152
+ patterns: ['**/*.{css,less,scss,sass,styl,html,vue,md,js,ts,jsx,tsx}'],
153
+ globbyConfig: {
154
+ ignore: ['**/dialtone_migration_helper/tests/**'],
155
+ },
156
+ expressions: [
157
+ // Border-width context → --dt-size-border-* (must run before layout to win --*-border-width* conflicts)
158
+ {
159
+ from: new RegExp(
160
+ `((?:${BORDER_PROPS})\\s*:[^;]*?)var\\(--dt-size-([0-9]+)\\)`,
161
+ 'gm',
162
+ ),
163
+ to: borderReplacer,
164
+ },
165
+ // Border-radius context → --dt-size-radius-* (must run before layout to win --*-radius* conflicts)
166
+ {
167
+ from: new RegExp(
168
+ `((?:${RADIUS_PROPS})\\s*:[^;]*?)var\\(--dt-size-([0-9]+)\\)`,
169
+ 'gm',
170
+ ),
171
+ to: radiusReplacer,
172
+ },
173
+ // Percentage tokens → --dt-layout-*-percent (context-independent, straight prefix swap)
174
+ {
175
+ from: /var\(--dt-size-([0-9]+)-percent\)/g,
176
+ to: (match, stop) => `var(--dt-layout-${stop}-percent)`,
177
+ },
178
+ // Spacing-context properties → --dt-spacing-*
179
+ {
180
+ from: new RegExp(
181
+ `((?:${SPACING_PROPS})\\s*:[^;]*?)var\\(--dt-size-([0-9]+)(-negative|-percent)?\\)`,
182
+ 'gm',
183
+ ),
184
+ to: spacingReplacer,
185
+ },
186
+ // Layout-context properties → --dt-layout-* (or raw rem for out-of-scale values)
187
+ {
188
+ from: new RegExp(
189
+ `((?:${LAYOUT_PROPS})\\s*:[^;]*?)var\\(--dt-size-([0-9]+)(-negative)?\\)`,
190
+ 'gm',
191
+ ),
192
+ to: layoutReplacer,
193
+ },
194
+ // Default: remaining --dt-size-* not matched by a known property context → layout map
195
+ {
196
+ from: /var\(--dt-size-([0-9]+)(-negative|-percent)?\)/g,
197
+ to: (match, stop, suffix) => {
198
+ const s = Number(stop);
199
+ if (LAYOUT_MAP[s]) return `var(--dt-layout-${LAYOUT_MAP[s]}${suffix || ''})`;
200
+ if (RAW_FALLBACK[s]) {
201
+ return `${RAW_FALLBACK[s]} /* TODO: no --dt-layout-* equivalent for --dt-size-${s} — replace with a layout token when one is added */`;
202
+ }
203
+ return match;
204
+ },
205
+ },
206
+ // Cleanup: calc(var(--dt-spacing-*) * -1) → var(--dt-spacing-*-negative)
207
+ {
208
+ from: /calc\(var\(--dt-spacing-([a-z0-9]+)\)\s*\*\s*-1\)/g,
209
+ to: (match, stop) => `var(--dt-spacing-${stop}-negative)`,
210
+ },
211
+ ],
212
+ };
@@ -0,0 +1,48 @@
1
+ // Lookup table: old --dt-space-{stop} → new --dt-spacing-{suffix}
2
+ // Based on px value equivalence (8px base unit). Stops with no equivalent are left unchanged.
3
+ const MAP = {
4
+ 0: 'spacing-0', // 0px
5
+ 100: 'spacing-1', // 1px
6
+ 200: 'spacing-25', // 2px
7
+ 300: 'spacing-50', // 4px
8
+ 350: 'spacing-75', // 6px
9
+ 400: 'spacing-100', // 8px
10
+ 450: 'spacing-150', // 12px
11
+ 500: 'spacing-200', // 16px
12
+ 525: 'spacing-250', // 20px
13
+ 550: 'spacing-300', // 24px
14
+ 600: 'spacing-400', // 32px
15
+ 625: 'spacing-525', // 42px
16
+ 650: 'spacing-600', // 48px
17
+ 700: 'spacing-800', // 64px
18
+ // 720 (72px), 730 (84px), 750+ (96px+) have no --dt-spacing-* equivalent.
19
+ // Tokens at these sizes are better expressed as --dt-layout-* tokens.
20
+ // These are left unchanged for manual review — the lint rule will flag them.
21
+ };
22
+
23
+ export default {
24
+ description:
25
+ 'Migrates --dt-space-* tokens to --dt-spacing-* tokens (8px base unit scale).\n' +
26
+ 'This supersedes the space-to-size migration — run this instead of space-to-size.\n' +
27
+ '- Replaces var(--dt-space-{stop}) with var(--dt-spacing-{newSuffix})\n\t' +
28
+ 'eg. var(--dt-space-400) → var(--dt-spacing-100)\n' +
29
+ '- Replaces var(--dt-space-{stop}-negative) with var(--dt-spacing-{newSuffix}-negative)\n\t' +
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' +
33
+ '- Tokens with no equivalent (720, 730, 750+) are left unchanged for manual review.\n',
34
+ patterns: ['**/*.{css,less,scss,sass,styl,html,vue,md,js,ts,jsx,tsx}'],
35
+ globbyConfig: {
36
+ ignore: ['**/dialtone_migration_helper/tests/**'],
37
+ },
38
+ expressions: [
39
+ {
40
+ from: /var\(--dt-space-([0-9]+)(-negative|-percent)?\)/g,
41
+ to: (match, stop, suffix) => {
42
+ const newSuffix = MAP[Number(stop)];
43
+ if (newSuffix == null) return match;
44
+ return `var(--dt-${newSuffix}${suffix || ''})`;
45
+ },
46
+ },
47
+ ],
48
+ };
@@ -0,0 +1,88 @@
1
+ // Mapping: old DtStack/DtDescriptionList gap prop values → new spacing stop numbers
2
+ // The old gap values used --dt-size-* stop numbers; the new values use --dt-spacing-* stop numbers.
3
+ const GAP_MAP = {
4
+ 0: '0', // 0px
5
+ 50: '1', // 0.5px → 1px
6
+ 100: '1', // 1px
7
+ 200: '25', // 2px
8
+ 300: '50', // 4px
9
+ 350: '75', // 6px
10
+ 400: '100', // 8px
11
+ 450: '150', // 12px
12
+ 500: '200', // 16px
13
+ 525: '250', // 20px
14
+ 550: '300', // 24px
15
+ 600: '400', // 32px
16
+ 625: '525', // 42px
17
+ 650: '600', // 48px
18
+ 700: '800', // 64px
19
+ // 50 (0.5px) maps to 1 (1px) — closest non-subpixel stop
20
+ };
21
+
22
+ // Values that only exist in the NEW system — if a file contains these,
23
+ // it has already been migrated. Used to detect and skip double-migration.
24
+ const NEW_ONLY_VALUES = new Set(['25', '75', '150', '250', '525']);
25
+
26
+ function isAlreadyMigrated (content) {
27
+ // Check for gap values that only exist in the new system
28
+ // If any are found, this file was already migrated
29
+ return [...NEW_ONLY_VALUES].some(v =>
30
+ content.includes(`gap="${v}"`) ||
31
+ content.includes(`gap="'${v}'"`) ||
32
+ content.includes(`d-stack--gap-${v}`) ||
33
+ content.includes(`d-description-list--gap-${v}`),
34
+ );
35
+ }
36
+
37
+ export default {
38
+ description:
39
+ 'Migrates DtStack and DtDescriptionList gap prop values from old size stops to new spacing stops.\n' +
40
+ '- Replaces gap="400" with gap="100" (8px)\n' +
41
+ '- Replaces :gap="\'400\'" with :gap="\'100\'" (8px)\n' +
42
+ '- Also handles d-stack--gap-* and d-description-list--gap-* CSS class references.\n' +
43
+ '- gap="50" (0.5px) maps to gap="1" (1px) — closest non-subpixel stop.\n' +
44
+ '- SAFE TO RE-RUN: detects already-migrated files by checking for new-only values (25, 75, 150, 250, 525).\n',
45
+ patterns: ['**/*.{vue,html,js,ts,jsx,tsx,md}'],
46
+ globbyConfig: {
47
+ ignore: ['**/dialtone_migration_helper/tests/**'],
48
+ },
49
+ expressions: [
50
+ // gap="400" → gap="100" (static prop)
51
+ {
52
+ from: /gap="([0-9]+)"/g,
53
+ to: (match, value) => {
54
+ const mapped = GAP_MAP[Number(value)];
55
+ return mapped != null ? `gap="${mapped}"` : match;
56
+ },
57
+ },
58
+ // :gap="'400'" → :gap="'100'" (dynamic prop with string literal)
59
+ {
60
+ from: /:gap="'([0-9]+)'"/g,
61
+ to: (match, value) => {
62
+ const mapped = GAP_MAP[Number(value)];
63
+ return mapped != null ? `:gap="'${mapped}'"` : match;
64
+ },
65
+ },
66
+ // d-stack--gap-400 → d-stack--gap-100 (CSS class references in templates/JS)
67
+ {
68
+ from: /d-stack--gap-([0-9]+)/g,
69
+ to: (match, value) => {
70
+ const mapped = GAP_MAP[Number(value)];
71
+ return mapped != null ? `d-stack--gap-${mapped}` : match;
72
+ },
73
+ },
74
+ // d-description-list--gap-400 → d-description-list--gap-100 (CSS class references)
75
+ {
76
+ from: /d-description-list--gap-([0-9]+)/g,
77
+ to: (match, value) => {
78
+ const mapped = GAP_MAP[Number(value)];
79
+ return mapped != null ? `d-description-list--gap-${mapped}` : match;
80
+ },
81
+ },
82
+ ],
83
+ // Called by the migration helper before processing each file.
84
+ // Return false to skip the file (already migrated).
85
+ shouldProcessFile (content) {
86
+ return !isAlreadyMigrated(content);
87
+ },
88
+ };
@@ -0,0 +1,135 @@
1
+ // Migration: old pixel-based utility class names → new token-stop-based class names
2
+ // e.g. d-h16 → d-h-25, d-p8 → d-p-100, d-m8 → d-m-100
3
+
4
+ // Sizing: pixel value → layout token stop
5
+ // MUST STAY IN SYNC with WIDTH_HEIGHTS_LAYOUT in dialtone-css/postcss/constants.cjs
6
+ const SIZING_MAP = {
7
+ 16: '25', 32: '50', 48: '75', 64: '100', 80: '125', 96: '150',
8
+ 112: '175', 128: '200', 160: '250', 192: '300', 224: '350', 256: '400',
9
+ 288: '450', 320: '500', 352: '550', 384: '600', 416: '650', 448: '700',
10
+ 480: '750', 512: '800', 544: '850', 576: '900', 608: '950', 640: '1000',
11
+ 672: '1050', 704: '1100', 736: '1150', 768: '1200', 800: '1250',
12
+ 832: '1300', 864: '1350', 896: '1400', 928: '1450', 960: '1500',
13
+ 992: '1550', 1024: '1600',
14
+ };
15
+
16
+ // Small sizing values (0-12px) that map to spacing tokens, not layout tokens.
17
+ // These old classes (d-h0, d-h1, d-h2, etc.) don't have a layout-stop equivalent.
18
+ // They should be migrated to use the spacing token directly in CSS rather than a utility class,
19
+ // or left as-is since the old classes still work.
20
+
21
+ // Spacing: pixel value → spacing token stop
22
+ // MUST STAY IN SYNC with GAP_SPACES_SPACING / MARGIN_SIZES_SPACING / PADDING_SIZES_SPACING in dialtone-css/postcss/constants.cjs
23
+ const SPACING_MAP = {
24
+ 0: '0', 1: '1', 2: '25', 4: '50', 6: '75', 8: '100',
25
+ 10: '125', 12: '150', 14: '175', 16: '200', 20: '250', 24: '300',
26
+ 32: '400', 48: '600', 64: '800',
27
+ };
28
+
29
+ // Negative spacing: old notation (n8) → new notation (n100)
30
+ const NEGATIVE_SPACING_MAP = {
31
+ 1: '1', 2: '25', 4: '50', 6: '75', 8: '100',
32
+ 10: '125', 12: '150', 14: '175', 16: '200', 20: '250', 24: '300',
33
+ 32: '400', 48: '600', 64: '800',
34
+ };
35
+
36
+ // Layout sizes for margin/padding (96px, 128px use layout tokens)
37
+ const SPACING_LAYOUT_MAP = {
38
+ 96: '150', 128: '200',
39
+ };
40
+
41
+ // Helper: build regex that matches class names with word boundaries
42
+ // Sorted by descending key length to avoid partial matches (d-h1024 before d-h102)
43
+ function buildClassRegex (prefix, map) {
44
+ const keys = Object.keys(map).sort((a, b) => b.length - a.length || Number(b) - Number(a));
45
+ const pattern = keys.join('|');
46
+ // Match class name boundary: preceded by space, quote, or start; followed by space, quote, or end
47
+ return new RegExp(`((?:^|["'\\s]))${prefix}(${pattern})((?:["'\\s]|$))`, 'gm');
48
+ }
49
+
50
+ export default {
51
+ description:
52
+ 'Migrates pixel-based utility class names to token-stop-based names.\n' +
53
+ '- Sizing: d-h16 → d-h-25, d-w64 → d-w-100, d-hmn96 → d-hmn-150\n' +
54
+ '- Margin: d-m8 → d-m-100, d-mt16 → d-mt-200, d-mtn8 → d-mt-n100\n' +
55
+ '- Padding: d-p8 → d-p-100, d-pt16 → d-pt-200\n' +
56
+ '- Gap: d-g8 → d-g-100, d-rg16 → d-rg-200\n' +
57
+ '- Position: d-t8 → d-t-100, d-tn8 → d-t-n100\n' +
58
+ '- Old deprecated sizes (d-h72, d-w332, etc.) are left unchanged for manual review.\n',
59
+ patterns: ['**/*.{vue,html,js,ts,jsx,tsx,md,less,css}'],
60
+ globbyConfig: {
61
+ ignore: ['**/dialtone_migration_helper/tests/**', '**/node_modules/**'],
62
+ },
63
+ expressions: [
64
+ // ── Sizing: d-h{px} → d-h-{layout-stop} ──────────────────────────────
65
+ ...['h', 'w', 'hmn', 'hmx', 'wmn', 'wmx'].flatMap(prefix => [
66
+ // Layout sizes (16px+)
67
+ {
68
+ from: buildClassRegex(`d-${prefix}`, SIZING_MAP),
69
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SIZING_MAP[px]}${post}`,
70
+ },
71
+ // Layout sizes for 96/128 (margin/padding also uses these for sizing)
72
+ {
73
+ from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
74
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
75
+ },
76
+ ]),
77
+
78
+ // ── Margin: d-m{px} → d-m-{spacing-stop} ─────────────────────────────
79
+ ...['m', 'mt', 'mr', 'mb', 'ml', 'mx', 'my'].flatMap(prefix => [
80
+ // Spacing sizes (0-64px)
81
+ {
82
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
83
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
84
+ },
85
+ // Layout sizes (96, 128px)
86
+ {
87
+ from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
88
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
89
+ },
90
+ ]),
91
+
92
+ // ── Negative margin: d-m{dir}n{px} → d-m{dir}-n{spacing-stop} ────────
93
+ ...['mt', 'mr', 'mb', 'ml', 'mx', 'my', 'm'].map(prefix => ({
94
+ from: buildClassRegex(`d-${prefix}n`, NEGATIVE_SPACING_MAP),
95
+ to: (match, pre, px, post) => `${pre}d-${prefix}-n${NEGATIVE_SPACING_MAP[px]}${post}`,
96
+ })),
97
+
98
+ // ── Padding: d-p{px} → d-p-{spacing-stop} ────────────────────────────
99
+ ...['p', 'pt', 'pr', 'pb', 'pl', 'px', 'py'].flatMap(prefix => [
100
+ {
101
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
102
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
103
+ },
104
+ {
105
+ from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
106
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
107
+ },
108
+ ]),
109
+
110
+ // ── Gap: d-g{px} → d-g-{spacing-stop} ────────────────────────────────
111
+ ...['g', 'rg', 'cg'].map(prefix => ({
112
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
113
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
114
+ })),
115
+
116
+ // ── Position: d-t{px} → d-t-{spacing-stop} ───────────────────────────
117
+ ...['t', 'r', 'b', 'l', 'x', 'y', 'all'].flatMap(prefix => [
118
+ {
119
+ from: buildClassRegex(`d-${prefix}`, SPACING_MAP),
120
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_MAP[px]}${post}`,
121
+ },
122
+ // Layout position sizes (96px)
123
+ {
124
+ from: buildClassRegex(`d-${prefix}`, SPACING_LAYOUT_MAP),
125
+ to: (match, pre, px, post) => `${pre}d-${prefix}-${SPACING_LAYOUT_MAP[px]}${post}`,
126
+ },
127
+ ]),
128
+
129
+ // ── Negative position: d-{dir}n{px} → d-{dir}-n{spacing-stop} ────────
130
+ ...['t', 'r', 'b', 'l', 'x', 'y', 'all'].map(prefix => ({
131
+ from: buildClassRegex(`d-${prefix}n`, NEGATIVE_SPACING_MAP),
132
+ to: (match, pre, px, post) => `${pre}d-${prefix}-n${NEGATIVE_SPACING_MAP[px]}${post}`,
133
+ })),
134
+ ],
135
+ };