@dialpad/dialtone 9.150.1 → 9.150.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 (37) hide show
  1. package/dist/js/dialtone_health_check/deprecated_icons.cjs +105 -0
  2. package/dist/js/dialtone_health_check/index.cjs +82 -0
  3. package/dist/js/dialtone_health_check/non_dialtone_properties.cjs +44 -0
  4. package/dist/js/dialtone_migrate_flex_to_stack/examples-edge-cases.vue +329 -0
  5. package/dist/js/dialtone_migrate_flex_to_stack/index.mjs +1377 -0
  6. package/dist/js/dialtone_migration_helper/configs/box-shadows.mjs +19 -0
  7. package/dist/js/dialtone_migration_helper/configs/colors.mjs +69 -0
  8. package/dist/js/dialtone_migration_helper/configs/fonts.mjs +49 -0
  9. package/dist/js/dialtone_migration_helper/configs/size-and-space.mjs +124 -0
  10. package/dist/js/dialtone_migration_helper/helpers.mjs +212 -0
  11. package/dist/js/dialtone_migration_helper/index.mjs +135 -0
  12. package/dist/tokens/doc.json +46427 -46427
  13. package/dist/vue3/common/utils/index.cjs +1 -1
  14. package/dist/vue3/common/utils/index.cjs.map +1 -1
  15. package/dist/vue3/common/utils/index.js +45 -41
  16. package/dist/vue3/common/utils/index.js.map +1 -1
  17. package/dist/vue3/lib/combobox-multi-select/combobox-multi-select.cjs +1 -1
  18. package/dist/vue3/lib/combobox-multi-select/combobox-multi-select.cjs.map +1 -1
  19. package/dist/vue3/lib/combobox-multi-select/combobox-multi-select.js +79 -75
  20. package/dist/vue3/lib/combobox-multi-select/combobox-multi-select.js.map +1 -1
  21. package/dist/vue3/types/common/utils/index.d.ts +2 -3
  22. package/dist/vue3/types/common/utils/index.d.ts.map +1 -1
  23. package/dist/vue3/types/components/collapsible/collapsible.vue.d.ts +1 -3
  24. package/dist/vue3/types/components/toast/layouts/toast_layout_alternate.vue.d.ts +1 -3
  25. package/dist/vue3/types/components/toast/layouts/toast_layout_default.vue.d.ts +1 -3
  26. package/dist/vue3/types/components/toast/toast.vue.d.ts +2 -6
  27. package/dist/vue3/types/recipes/buttons/callbar_button/callbar_button.vue.d.ts +7 -0
  28. package/dist/vue3/types/recipes/buttons/callbar_button/callbar_button.vue.d.ts.map +1 -1
  29. package/dist/vue3/types/recipes/comboboxes/combobox_multi_select/combobox_multi_select.vue.d.ts.map +1 -1
  30. package/dist/vue3/types/recipes/leftbar/contact_centers_row/contact_centers_row.vue.d.ts +1 -3
  31. package/dist/vue3/types/recipes/leftbar/contact_centers_row/contact_centers_row.vue.d.ts.map +1 -1
  32. package/dist/vue3/types/recipes/leftbar/contact_row/contact_row.vue.d.ts +1 -3
  33. package/dist/vue3/types/recipes/leftbar/general_row/general_row.vue.d.ts +1 -3
  34. package/dist/vue3/types/recipes/leftbar/general_row/general_row.vue.d.ts.map +1 -1
  35. package/dist/vue3/types/recipes/leftbar/group_row/group_row.vue.d.ts +1 -3
  36. package/dist/vue3/types/recipes/leftbar/group_row/group_row.vue.d.ts.map +1 -1
  37. package/package.json +5 -2
@@ -0,0 +1,105 @@
1
+ /* eslint-disable complexity */
2
+ const fs = require('fs');
3
+ const iconRegex = /.*@dialpad\/dialtone\/(vue\/.*|.+\.svg)/gim;
4
+ const brandIconsList = [
5
+ 'IconAirtable',
6
+ 'IconAmex',
7
+ 'IconAppStoreBadge',
8
+ 'IconApple',
9
+ 'IconAsana',
10
+ 'IconBrandDialpadMeetings',
11
+ 'IconBrandDialpad',
12
+ 'IconBullhorn',
13
+ 'IconClockify',
14
+ 'IconCopperCrm',
15
+ 'IconDialpadAi',
16
+ 'IconDinersClub',
17
+ 'IconDiscover',
18
+ 'IconEvernote',
19
+ 'IconFacebook',
20
+ 'IconFreshsalesCrm',
21
+ 'IconFront',
22
+ 'IconGmail',
23
+ 'IconGoogleBusinessMessaging',
24
+ 'IconGoogleCalendar',
25
+ 'IconGoogleDocs',
26
+ 'IconGoogleDrive',
27
+ 'IconGoogleGlyph',
28
+ 'IconGreenhouse',
29
+ 'IconHighfive',
30
+ 'IconHubspot',
31
+ 'IconInstagram',
32
+ 'IconIntercom',
33
+ 'IconJcb',
34
+ 'IconJiraServiceDesk',
35
+ 'IconLineMessenger',
36
+ 'IconLinkedin',
37
+ 'IconMaestro',
38
+ 'IconMastercard',
39
+ 'IconMessenger',
40
+ 'IconMicrosoftDynamics365',
41
+ 'IconMicrosoftTeams',
42
+ 'IconMicrosoft',
43
+ 'IconMiro',
44
+ 'IconMondayCom',
45
+ 'IconOffice365',
46
+ 'IconPipedrive',
47
+ 'IconPlayStoreBadge',
48
+ 'IconSalesforceGlyph',
49
+ 'IconSalesforceLogo',
50
+ 'IconServicenow',
51
+ 'IconSlack',
52
+ 'IconSnapchat',
53
+ 'IconTelegram',
54
+ 'IconTiktok',
55
+ 'IconToggl',
56
+ 'IconTwitter',
57
+ 'IconUnionPay',
58
+ 'IconViber',
59
+ 'IconVisa',
60
+ 'IconWeChat',
61
+ 'IconWhatsapp',
62
+ 'IconZendesk',
63
+ 'IconZohoCrm',
64
+ 'IconZohoDesk',
65
+ 'IconZoho',
66
+ 'IconZoom',
67
+ ];
68
+ let totalIconsCount = 0;
69
+
70
+ function isBrandIcon (source) {
71
+ const iconName = source.split('/').pop().slice(0, -2);
72
+ return brandIconsList.includes(iconName);
73
+ }
74
+ const main = (files, noLineNumbers) => {
75
+ try {
76
+ for (const file of files) {
77
+ const data = fs.readFileSync(file, 'utf8');
78
+ const lines = data.split('\n');
79
+ let iconCount = 0;
80
+
81
+ for (const [lineNumber, line] of lines.entries()) {
82
+ const iconMatch = iconRegex.exec(line);
83
+ // If import doesn't match or is a brand or spot icon, continue
84
+ if (!iconMatch ||
85
+ iconMatch.input.includes('/brand/') ||
86
+ iconMatch.input.includes('/spot/') ||
87
+ isBrandIcon(iconMatch.input)) continue;
88
+
89
+ if (!noLineNumbers) {
90
+ console.log(`\tdeprecated icon usage found on line ${lineNumber + 1}: ${iconMatch.input}`);
91
+ }
92
+ iconCount++;
93
+ totalIconsCount++;
94
+ }
95
+ if (iconCount > 0) {
96
+ console.log(`${file}: ${iconCount} Deprecated icons found`);
97
+ }
98
+ }
99
+ console.log(`Found ${totalIconsCount} total deprecated icons usage in this directory.`);
100
+ } catch (err) {
101
+ console.error(err);
102
+ }
103
+ };
104
+
105
+ module.exports = main;
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+
3
+ /* Will search the files in the provided directory for any properties that are not set to dialtone values.
4
+ It does this by simply checking whether the property is set to a less @variable or CSS var such as var(--val).
5
+ It does not compare to an actual list of dialtone token values so it is not perfect, and sometimes gives false
6
+ positives. This will however give a pretty good idea of where dialtone values aren't being used that should.
7
+
8
+ Searches some key properties by default as shown in the defaultSearch array below. You are however not limited to
9
+ this, you can make this application search any css property you wish. See the below options or run this application
10
+ with the -h switch for more details. */
11
+
12
+ const path = require('path');
13
+ const fs = require('fs');
14
+ const { exit } = require('process');
15
+ const { docopt } = require('docopt');
16
+ const nonDialtoneProperties = require('./non_dialtone_properties');
17
+ const deprecatedIcons = require('./deprecated_icons');
18
+
19
+ const doc = `
20
+ Usage:
21
+ ./dialtone_health_check <path> [options] (--icons|--properties) [<properties>]
22
+
23
+ Examples:
24
+ ./dialtone_health_check <path> --ext=vue,js --no-line-numbers --icons
25
+ ./dialtone_health_check <path> --ext=vue,js --properties color,background-color
26
+ ./dialtone_health_check <path> --ext=vue,js --icons --properties color,background-color
27
+
28
+ Arguments:
29
+ <properties> CSS Properties to search. Default properties if list is not provided:
30
+ color,background-color,border-color,font-family
31
+ <path> The directory to recursively search all files in.
32
+
33
+ Options:
34
+ -p --properties Verify the usage of non-dialtone properties.
35
+ -i --icons Verify the status of icons migration.
36
+ -h --help Show this screen.
37
+ --ext=<ext> Filter by file extension. comma separate to filter multiple. ex: js,vue
38
+ --no-line-numbers Only output files and their total count, do not output individual instances and
39
+ their line number.
40
+ `;
41
+ const options = docopt(doc);
42
+ const extensionFilters = options['--ext']?.split(',') ?? [''];
43
+ const searchProperties = options['--properties'];
44
+ const properties = options['<properties>']?.split(',');
45
+ const noLineNumbers = options['--no-line-numbers'];
46
+ const searchIcons = options['--icons'];
47
+ const files = [];
48
+
49
+ function fromDir (startPath, fileExtension) {
50
+ if (!fs.existsSync(startPath)) {
51
+ console.error('Directory not found');
52
+ exit(1);
53
+ }
54
+
55
+ const results = [];
56
+ const files = fs.readdirSync(startPath);
57
+ for (let i = 0; i < files.length; i++) {
58
+ const filename = path.join(startPath, files[i]);
59
+ const stat = fs.lstatSync(filename);
60
+ if (stat.isDirectory()) {
61
+ results.push(...fromDir(filename, fileExtension)); // recurse
62
+ } else if (filename.endsWith(fileExtension)) {
63
+ results.push(filename);
64
+ }
65
+ }
66
+ return results;
67
+ }
68
+
69
+ extensionFilters.forEach(extension => {
70
+ files.push(...fromDir(options['<path>'], extension));
71
+ });
72
+ if (files.length <= 0) {
73
+ console.error('No files found in directory');
74
+ exit(1);
75
+ }
76
+ if (!searchProperties && !searchIcons) {
77
+ console.error('You must set at least one flag [--icons|--properties]');
78
+ exit(1);
79
+ }
80
+
81
+ searchProperties && nonDialtoneProperties(properties, files, noLineNumbers);
82
+ searchIcons && deprecatedIcons(files, noLineNumbers);
@@ -0,0 +1,44 @@
1
+ const fs = require('fs');
2
+ const defaultSearch = [
3
+ 'color',
4
+ 'background-color',
5
+ 'border-color',
6
+ 'font-family',
7
+ ];
8
+ let totalPropertiesCount = 0;
9
+
10
+ const main = (props = defaultSearch, files, noLineNumbers) => {
11
+ const regex = props.map(property => {
12
+ return new RegExp(`^\\s*${property}:\\s(?:(?!var\\(--))(?:(?!@)).*`, 'gm');
13
+ });
14
+ try {
15
+ for (const file of files) {
16
+ const data = fs.readFileSync(file, 'utf8');
17
+ const lines = data.split('\n');
18
+ let propertiesMatch;
19
+ let propertiesCount = 0;
20
+
21
+ for (const [lineNumber, line] of lines.entries()) {
22
+ regex.forEach(re => {
23
+ // eslint-disable-next-line no-cond-assign
24
+ while (propertiesMatch = re.exec(line)) {
25
+ if (!noLineNumbers) {
26
+ console.log(`\tnon-dialtone property found on line ${lineNumber + 1}: ${propertiesMatch}`);
27
+ }
28
+ propertiesCount++;
29
+ totalPropertiesCount++;
30
+ }
31
+ });
32
+ }
33
+ if (propertiesCount > 0) {
34
+ console.log(`${file}: ${propertiesCount}`);
35
+ }
36
+ }
37
+ console.log(`Found ${totalPropertiesCount} total ${props.join(', ')} \
38
+ CSS properties that are not dialtone in this directory.`);
39
+ } catch (err) {
40
+ console.error(err);
41
+ }
42
+ };
43
+
44
+ module.exports = main;
@@ -0,0 +1,329 @@
1
+ <template>
2
+ <!--
3
+ TEST FILE FOR FLEX-TO-STACK MIGRATION EDGE CASES
4
+ This file tests all edge cases identified in Phase 11
5
+ -->
6
+
7
+ <!-- TEST 1: d-fl-center - Should convert to dt-stack with align="center" justify="center" direction="row" -->
8
+ <div class="d-fl-center">
9
+ <span>Centered content</span>
10
+ </div>
11
+
12
+ <!-- TEST 2: d-fl-center with additional utilities - Should convert and retain other classes -->
13
+ <div class="d-fl-center d-p16 d-ba d-bc-primary">
14
+ <span>Centered with padding and border</span>
15
+ </div>
16
+
17
+ <!-- TEST 3: d-d-grid - Should be SKIPPED (grid container, not flex) -->
18
+ <div class="d-d-grid d-g-cols2 d-g16">
19
+ <div>Grid item 1</div>
20
+ <div>Grid item 2</div>
21
+ </div>
22
+
23
+ <!-- TEST 4: d-d-inline-grid - Should be SKIPPED (grid container, not flex) -->
24
+ <div class="d-d-inline-grid d-g-cols3">
25
+ <span>A</span>
26
+ <span>B</span>
27
+ <span>C</span>
28
+ </div>
29
+
30
+ <!-- TEST 5: d-d-inline-flex - Should be SKIPPED (DtStack is block-level only) -->
31
+ <div class="d-d-inline-flex d-ai-center d-g8">
32
+ <span>Inline flex item</span>
33
+ </div>
34
+
35
+ <!-- TEST 6: d-d-contents - Should be SKIPPED (layout tree manipulation) -->
36
+ <div class="d-d-flex d-d-contents d-ai-center">
37
+ <span>Contents display</span>
38
+ </div>
39
+
40
+ <!-- TEST 7: d-fl-col4 - Should be SKIPPED (deprecated flex column system) -->
41
+ <div class="d-d-flex d-fl-col4">
42
+ <div>Column 1</div>
43
+ <div>Column 2</div>
44
+ <div>Column 3</div>
45
+ <div>Column 4</div>
46
+ </div>
47
+
48
+ <!-- TEST 8: d-stack8 - Should be SKIPPED (auto-spacing utility, margin-based) -->
49
+ <div class="d-d-flex d-stack8">
50
+ <div>Item 1</div>
51
+ <div>Item 2</div>
52
+ <div>Item 3</div>
53
+ </div>
54
+
55
+ <!-- TEST 9: d-flow8 - Should be SKIPPED (auto-spacing utility, margin-based) -->
56
+ <div class="d-d-flex d-flow8">
57
+ <span>Item 1</span>
58
+ <span>Item 2</span>
59
+ <span>Item 3</span>
60
+ </div>
61
+
62
+ <!-- TEST 10: d-flg8 - Should be RETAINED as class (deprecated flex gap) -->
63
+ <div class="d-d-flex d-flg8 d-ai-center">
64
+ <span>Item 1</span>
65
+ <span>Item 2</span>
66
+ </div>
67
+
68
+ <!-- TEST 11: d-ji-center - Should be RETAINED as class (justify-items, grid/flex hybrid) -->
69
+ <div class="d-d-flex d-ji-center">
70
+ <div>Item with justify-items</div>
71
+ </div>
72
+
73
+ <!-- TEST 12: d-js-center - Should be RETAINED as class (justify-self, grid/flex hybrid) -->
74
+ <div class="d-d-flex d-js-center d-ai-center">
75
+ <div>Item with justify-self</div>
76
+ </div>
77
+
78
+ <!-- TEST 13: d-plc-center - Should be RETAINED as class (place-content, grid shorthand) -->
79
+ <div class="d-d-flex d-plc-center">
80
+ <div>Item with place-content</div>
81
+ </div>
82
+
83
+ <!-- TEST 14: d-pli-center - Should be RETAINED as class (place-items, grid shorthand) -->
84
+ <div class="d-d-flex d-pli-center">
85
+ <div>Item with place-items</div>
86
+ </div>
87
+
88
+ <!-- TEST 15: d-pls-center - Should be RETAINED as class (place-self, grid shorthand) -->
89
+ <div class="d-d-flex d-pls-center d-ai-center">
90
+ <div>Item with place-self</div>
91
+ </div>
92
+
93
+ <!-- TEST 16: Direction default (no direction) - Should add direction="row" -->
94
+ <div class="d-d-flex d-ai-center d-g8">
95
+ <span>No explicit direction</span>
96
+ </div>
97
+
98
+ <!-- TEST 17: Explicit d-fd-row - Should convert to direction="row" -->
99
+ <div class="d-d-flex d-fd-row d-ai-center d-g8">
100
+ <span>Explicit row</span>
101
+ </div>
102
+
103
+ <!-- TEST 18: Explicit d-fd-column - Should OMIT direction prop (DtStack default) -->
104
+ <div class="d-d-flex d-fd-column d-ai-center d-g8">
105
+ <span>Explicit column</span>
106
+ </div>
107
+
108
+ <!-- TEST 19: d-fd-row-reverse - Should convert to direction="row-reverse" -->
109
+ <div class="d-d-flex d-fd-row-reverse d-jc-end">
110
+ <span>Row reverse</span>
111
+ </div>
112
+
113
+ <!-- TEST 20: d-fd-column-reverse - Should convert to direction="column-reverse" -->
114
+ <div class="d-d-flex d-fd-column-reverse d-ai-end">
115
+ <span>Column reverse</span>
116
+ </div>
117
+
118
+ <!-- TEST 21: Multiple direction utilities - Should retain all as classes, add direction="row" -->
119
+ <div class="d-d-flex d-fd-row d-fd-column d-ai-center">
120
+ <span>Multiple directions</span>
121
+ </div>
122
+
123
+ <!-- TEST 22: Complex case - d-fl-center with additional flex utilities -->
124
+ <div class="d-fl-center d-fw-wrap d-g16 d-p24">
125
+ <span>Item 1</span>
126
+ <span>Item 2</span>
127
+ <span>Item 3</span>
128
+ </div>
129
+
130
+ <!-- TEST 23: Regular flex with all supported props -->
131
+ <div class="d-d-flex d-fd-row d-ai-center d-jc-between d-g16">
132
+ <span>Full props</span>
133
+ <span>Example</span>
134
+ </div>
135
+
136
+ <!-- TEST 24: Flex with retained classes only -->
137
+ <div class="d-d-flex d-fw-wrap d-as-start d-order2">
138
+ <div>Retained utilities</div>
139
+ </div>
140
+
141
+ <!-- TEST 25: Combination - retained + converted utilities -->
142
+ <div class="d-d-flex d-ai-center d-g8 d-p16 d-fw-wrap d-fl-grow1">
143
+ <span>Mixed utilities</span>
144
+ </div>
145
+
146
+ <!-- TEST 26: Non-div element with as prop -->
147
+ <section class="d-d-flex d-fd-column d-g24">
148
+ <h2>Section as flex container</h2>
149
+ <p>Should use as="section"</p>
150
+ </section>
151
+
152
+ <!-- TEST 27: Multiple edge cases combined -->
153
+ <div class="d-d-flex d-flg8 d-ji-center d-ai-center d-p16">
154
+ <span>Multiple edge cases</span>
155
+ </div>
156
+
157
+ <!-- ============================================ -->
158
+ <!-- NEW TESTS: REF ATTRIBUTE SKIP DETECTION -->
159
+ <!-- ============================================ -->
160
+
161
+ <!-- TEST 28: Ref with DOM API (addEventListener) - Should be SKIPPED -->
162
+ <div ref="containerRef" class="d-d-flex d-ai-center d-g8">
163
+ <span>Element with ref used for DOM manipulation</span>
164
+ </div>
165
+
166
+ <!-- TEST 29: Ref with DOM API (focus) - Should be SKIPPED -->
167
+ <nav ref="navElement" class="d-d-flex d-fd-row d-jc-between">
168
+ <a href="#">Link 1</a>
169
+ <a href="#">Link 2</a>
170
+ </nav>
171
+
172
+ <!-- TEST 30: Ref without DOM API usage - Should be CONVERTED (ref alone doesn't trigger skip) -->
173
+ <div ref="simpleRef" class="d-d-flex d-ai-center">
174
+ <span>Ref but no DOM API usage in script</span>
175
+ </div>
176
+
177
+ <!-- ============================================ -->
178
+ <!-- NEW TESTS: DYNAMIC CLASS BINDING SKIP -->
179
+ <!-- ============================================ -->
180
+
181
+ <!-- TEST 31: Dynamic :class with flex utilities - Should be SKIPPED -->
182
+ <div :class="['d-d-flex d-ai-center', { 'd-jc-between': isActive }]">
183
+ <span>Dynamic binding with flex utilities</span>
184
+ </div>
185
+
186
+ <!-- TEST 32: Dynamic :class array with flex utilities - Should be SKIPPED -->
187
+ <div :class="[flexClass, 'd-d-flex', alignmentClass]">
188
+ <span>Dynamic array binding with flex</span>
189
+ </div>
190
+
191
+ <!-- TEST 33: Dynamic :class object with flex utilities - Should be SKIPPED -->
192
+ <div :class="{ 'd-d-flex d-ai-center': isVisible, 'd-jc-end': alignEnd }">
193
+ <span>Dynamic object binding with flex</span>
194
+ </div>
195
+
196
+ <!-- TEST 34: Dynamic :class without flex utilities - Should be CONVERTED -->
197
+ <div class="d-d-flex d-ai-center" :class="{ 'd-p16': hasPadding }">
198
+ <span>Dynamic binding but NO flex utilities in binding</span>
199
+ </div>
200
+
201
+ <!-- ============================================ -->
202
+ <!-- NEW TESTS: MORE SEMANTIC HTML ELEMENTS -->
203
+ <!-- ============================================ -->
204
+
205
+ <!-- TEST 35: span as flex container - Should use as="span" -->
206
+ <span class="d-d-flex d-ai-center d-g4">
207
+ <span>Inner span</span>
208
+ </span>
209
+
210
+ <!-- TEST 36: header as flex container - Should use as="header" -->
211
+ <header class="d-d-flex d-jc-between d-ai-center d-p16">
212
+ <span>Logo</span>
213
+ <nav>Navigation</nav>
214
+ </header>
215
+
216
+ <!-- TEST 37: footer as flex container - Should use as="footer" -->
217
+ <footer class="d-d-flex d-fd-column d-g16 d-p24">
218
+ <span>Footer content</span>
219
+ </footer>
220
+
221
+ <!-- TEST 38: aside as flex container - Should use as="aside" -->
222
+ <aside class="d-d-flex d-fd-column d-g8">
223
+ <span>Sidebar item 1</span>
224
+ <span>Sidebar item 2</span>
225
+ </aside>
226
+
227
+ <!-- TEST 39: article as flex container - Should use as="article" -->
228
+ <article class="d-d-flex d-fd-column d-g16">
229
+ <h3>Article title</h3>
230
+ <p>Article content</p>
231
+ </article>
232
+
233
+ <!-- TEST 40: main as flex container - Should use as="main" -->
234
+ <main class="d-d-flex d-fd-column d-g24">
235
+ <section>Section 1</section>
236
+ <section>Section 2</section>
237
+ </main>
238
+
239
+ <!-- TEST 41: nav as flex container - Should use as="nav" -->
240
+ <nav class="d-d-flex d-ai-center d-g16">
241
+ <a href="#">Home</a>
242
+ <a href="#">About</a>
243
+ <a href="#">Contact</a>
244
+ </nav>
245
+
246
+ <!-- ============================================ -->
247
+ <!-- NEW TESTS: NESTED SAME-TAG ELEMENTS -->
248
+ <!-- ============================================ -->
249
+
250
+ <!-- TEST 42: Nested divs at depth 2 - closing tags must match correctly -->
251
+ <div class="d-d-flex d-fd-column d-g8">
252
+ <div class="d-d-flex d-ai-center d-g4">
253
+ <span>Nested depth 2</span>
254
+ </div>
255
+ </div>
256
+
257
+ <!-- TEST 43: Nested divs at depth 3 - closing tags must match correctly -->
258
+ <div class="d-d-flex d-fd-column d-g16">
259
+ <div class="d-d-flex d-ai-center d-g8">
260
+ <div class="d-d-flex d-jc-center">
261
+ <span>Nested depth 3</span>
262
+ </div>
263
+ </div>
264
+ </div>
265
+
266
+ <!-- TEST 44: Nested spans - closing tags with as="span" must match -->
267
+ <span class="d-d-flex d-ai-center">
268
+ <span class="d-d-flex d-g4">
269
+ <span>Inner content</span>
270
+ </span>
271
+ </span>
272
+
273
+ <!-- TEST 45: Mixed nesting - different tag types -->
274
+ <section class="d-d-flex d-fd-column d-g24">
275
+ <header class="d-d-flex d-jc-between">
276
+ <span>Title</span>
277
+ </header>
278
+ <div class="d-d-flex d-ai-center d-g8">
279
+ <span>Content</span>
280
+ </div>
281
+ <footer class="d-d-flex d-jc-end">
282
+ <span>Footer</span>
283
+ </footer>
284
+ </section>
285
+
286
+ <!-- ============================================ -->
287
+ <!-- NEW TESTS: SELF-CLOSING AND EMPTY ELEMENTS -->
288
+ <!-- ============================================ -->
289
+
290
+ <!-- TEST 46: Self-closing with flex - Should NOT convert (no content to wrap) -->
291
+ <div class="d-d-flex d-ai-center" />
292
+
293
+ <!-- TEST 47: Empty element with flex - Should convert -->
294
+ <div class="d-d-flex d-fd-column"></div>
295
+ </template>
296
+
297
+ <script setup>
298
+ // Test file for edge case validation
299
+
300
+ // Refs for DOM manipulation tests (TEST 28, 29)
301
+ import { ref, onMounted } from 'vue';
302
+
303
+ const containerRef = ref(null);
304
+ const navElement = ref(null);
305
+ const simpleRef = ref(null);
306
+
307
+ // This triggers skip for containerRef (TEST 28)
308
+ onMounted(() => {
309
+ containerRef.value.addEventListener('click', () => {});
310
+ });
311
+
312
+ // This triggers skip for navElement (TEST 29)
313
+ function focusNav() {
314
+ navElement.value.focus();
315
+ }
316
+
317
+ // simpleRef is used but NOT for DOM APIs, so it should NOT trigger skip (TEST 30)
318
+ function getRefValue() {
319
+ return simpleRef.value;
320
+ }
321
+
322
+ // Dynamic class variables for tests
323
+ const isActive = ref(false);
324
+ const flexClass = ref('d-d-flex');
325
+ const alignmentClass = ref('d-ai-center');
326
+ const isVisible = ref(true);
327
+ const alignEnd = ref(false);
328
+ const hasPadding = ref(true);
329
+ </script>