@afixt/test-utils 1.0.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.
Files changed (132) hide show
  1. package/.editorconfig +13 -0
  2. package/.eslintrc +78 -0
  3. package/.gitattributes +5 -0
  4. package/.nvmrc +1 -0
  5. package/CLAUDE.md +33 -0
  6. package/README.md +72 -0
  7. package/docs/arrayUtils.js.html +69 -0
  8. package/docs/data/search.json +1 -0
  9. package/docs/domUtils.js.html +182 -0
  10. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  11. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  12. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  13. package/docs/getAccessibleName.js.html +456 -0
  14. package/docs/getAccessibleText.js.html +65 -0
  15. package/docs/getAriaAttributesByElement.js.html +22 -0
  16. package/docs/getCSSGeneratedContent.js.html +62 -0
  17. package/docs/getComputedRole.js.html +172 -0
  18. package/docs/getFocusableElements.js.html +29 -0
  19. package/docs/getGeneratedContent.js.html +18 -0
  20. package/docs/getImageText.js.html +28 -0
  21. package/docs/getStyleObject.js.html +48 -0
  22. package/docs/global.html +3 -0
  23. package/docs/hasAccessibleName.js.html +30 -0
  24. package/docs/hasAttribute.js.html +18 -0
  25. package/docs/hasCSSGeneratedContent.js.html +23 -0
  26. package/docs/hasHiddenParent.js.html +32 -0
  27. package/docs/hasParent.js.html +57 -0
  28. package/docs/hasValidAriaAttributes.js.html +33 -0
  29. package/docs/hasValidAriaRole.js.html +32 -0
  30. package/docs/index.html +3 -0
  31. package/docs/index.js.html +66 -0
  32. package/docs/isAriaAttributesValid.js.html +76 -0
  33. package/docs/isComplexTable.js.html +112 -0
  34. package/docs/isDataTable.js.html +241 -0
  35. package/docs/isFocusable.js.html +37 -0
  36. package/docs/isHidden.js.html +20 -0
  37. package/docs/isOffScreen.js.html +19 -0
  38. package/docs/isValidUrl.js.html +16 -0
  39. package/docs/isVisible.js.html +65 -0
  40. package/docs/module-afixt-test-utils.html +3 -0
  41. package/docs/scripts/core.js +726 -0
  42. package/docs/scripts/core.min.js +23 -0
  43. package/docs/scripts/resize.js +90 -0
  44. package/docs/scripts/search.js +265 -0
  45. package/docs/scripts/search.min.js +6 -0
  46. package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
  47. package/docs/scripts/third-party/fuse.js +9 -0
  48. package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
  49. package/docs/scripts/third-party/hljs-line-num.js +1 -0
  50. package/docs/scripts/third-party/hljs-original.js +5171 -0
  51. package/docs/scripts/third-party/hljs.js +1 -0
  52. package/docs/scripts/third-party/popper.js +5 -0
  53. package/docs/scripts/third-party/tippy.js +1 -0
  54. package/docs/scripts/third-party/tocbot.js +672 -0
  55. package/docs/scripts/third-party/tocbot.min.js +1 -0
  56. package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
  57. package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
  58. package/docs/styles/clean-jsdoc-theme-light.css +482 -0
  59. package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
  60. package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
  61. package/docs/styles/clean-jsdoc-theme.min.css +1 -0
  62. package/docs/testContrast.js.html +236 -0
  63. package/docs/testLang.js.html +578 -0
  64. package/docs/testOrder.js.html +93 -0
  65. package/jsdoc.json +67 -0
  66. package/package.json +32 -0
  67. package/src/arrayUtils.js +67 -0
  68. package/src/domUtils.js +179 -0
  69. package/src/getAccessibleName.js +454 -0
  70. package/src/getAccessibleText.js +63 -0
  71. package/src/getAriaAttributesByElement.js +19 -0
  72. package/src/getCSSGeneratedContent.js +60 -0
  73. package/src/getComputedRole.js +169 -0
  74. package/src/getFocusableElements.js +26 -0
  75. package/src/getGeneratedContent.js +15 -0
  76. package/src/getImageText.js +25 -0
  77. package/src/getStyleObject.js +45 -0
  78. package/src/hasAccessibleName.js +28 -0
  79. package/src/hasAttribute.js +15 -0
  80. package/src/hasCSSGeneratedContent.js +20 -0
  81. package/src/hasHiddenParent.js +29 -0
  82. package/src/hasParent.js +54 -0
  83. package/src/hasValidAriaAttributes.js +30 -0
  84. package/src/hasValidAriaRole.js +29 -0
  85. package/src/index.js +64 -0
  86. package/src/interactiveRoles.js +20 -0
  87. package/src/isAriaAttributesValid.js +74 -0
  88. package/src/isComplexTable.js +109 -0
  89. package/src/isDataTable.js +239 -0
  90. package/src/isFocusable.js +34 -0
  91. package/src/isHidden.js +17 -0
  92. package/src/isOffScreen.js +16 -0
  93. package/src/isValidUrl.js +13 -0
  94. package/src/isVisible.js +62 -0
  95. package/src/stringUtils.js +150 -0
  96. package/src/testContrast.js +233 -0
  97. package/src/testLang.js +575 -0
  98. package/src/testOrder.js +90 -0
  99. package/test/_template.test.js +21 -0
  100. package/test/arrayUtils.test.js +84 -0
  101. package/test/domUtils.test.js +147 -0
  102. package/test/generate-test-stubs.js +37 -0
  103. package/test/getAccessibleName.test.js +113 -0
  104. package/test/getAccessibleText.test.js +94 -0
  105. package/test/getAriaAttributesByElement.test.js +112 -0
  106. package/test/getCSSGeneratedContent.test.js +102 -0
  107. package/test/getComputedRole.test.js +180 -0
  108. package/test/getFocusableElements.test.js +134 -0
  109. package/test/getGeneratedContent.test.js +321 -0
  110. package/test/getImageText.test.js +21 -0
  111. package/test/getStyleObject.test.js +134 -0
  112. package/test/hasAccessibleName.test.js +59 -0
  113. package/test/hasAttribute.test.js +132 -0
  114. package/test/hasCSSGeneratedContent.test.js +143 -0
  115. package/test/hasHiddenParent.test.js +176 -0
  116. package/test/hasParent.test.js +266 -0
  117. package/test/hasValidAriaAttributes.test.js +79 -0
  118. package/test/hasValidAriaRole.test.js +98 -0
  119. package/test/isAriaAttributesValid.test.js +83 -0
  120. package/test/isComplexTable.test.js +363 -0
  121. package/test/isDataTable.test.js +948 -0
  122. package/test/isFocusable.test.js +182 -0
  123. package/test/isHidden.test.js +157 -0
  124. package/test/isOffScreen.test.js +249 -0
  125. package/test/isValidUrl.test.js +63 -0
  126. package/test/isVisible.test.js +104 -0
  127. package/test/setup.js +11 -0
  128. package/test/stringUtils.test.js +106 -0
  129. package/test/testContrast.test.js +77 -0
  130. package/test/testLang.test.js +21 -0
  131. package/test/testOrder.test.js +157 -0
  132. package/vitest.config.js +25 -0
@@ -0,0 +1,575 @@
1
+ /**
2
+ * An array of language codes and their corresponding details.
3
+ * Each object in the array represents a language and contains the following properties:
4
+ *
5
+ * @property {string} alpha3 - The ISO 639-2 three-letter code for the language.
6
+ * @property {string} alpha2 - The ISO 639-1 two-letter code for the language.
7
+ * @property {string} English - The English name of the language.
8
+ * @property {string|null} [franc3] - The three-letter code used by the franc library, if available.
9
+ */
10
+ export const langCodes = [
11
+ { alpha3: "aar", alpha2: "aa", English: "Afar", franc3: null },
12
+ { alpha3: "abk", alpha2: "ab", English: "Abkhazian", franc3: null },
13
+ { alpha3: "afr", alpha2: "af", English: "Afrikaans" },
14
+ { alpha3: "aka", alpha2: "ak", English: "Akan" },
15
+ { alpha3: "alb", alpha2: "sq", English: "Albanian", franc3: "als" },
16
+ { alpha3: "amh", alpha2: "am", English: "Amharic" },
17
+ { alpha3: "ara", alpha2: "ar", English: "Arabic", franc3: "arb" },
18
+ { alpha3: "arg", alpha2: "an", English: "Aragonese", franc3: null },
19
+ { alpha3: "arm", alpha2: "hy", English: "Armenian", franc3: "hye" },
20
+ { alpha3: "asm", alpha2: "as", English: "Assamese", franc3: null },
21
+ { alpha3: "ava", alpha2: "av", English: "Avaric", franc3: null },
22
+ { alpha3: "ave", alpha2: "ae", English: "Avestan", franc3: null },
23
+ { alpha3: "aym", alpha2: "ay", English: "Aymara", franc3: "ayr" },
24
+ { alpha3: "aze", alpha2: "az", English: "Azerbaijani", franc3: "azj" },
25
+ { alpha3: "bak", alpha2: "ba", English: "Bashkir", franc3: null },
26
+ { alpha3: "bam", alpha2: "bm", English: "Bambara" },
27
+ { alpha3: "baq", alpha2: "eu", English: "Basque", franc3: null },
28
+ { alpha3: "bel", alpha2: "be", English: "Belarusian" },
29
+ { alpha3: "ben", alpha2: "bn", English: "Bengali" },
30
+ { alpha3: "bih", alpha2: "bh", English: "Bihari languages", franc3: null },
31
+ { alpha3: "bis", alpha2: "bi", English: "Bislama", franc3: null },
32
+ { alpha3: "bos", alpha2: "bs", English: "Bosnian" },
33
+ { alpha3: "bre", alpha2: "br", English: "Breton", franc3: null },
34
+ { alpha3: "bul", alpha2: "bg", English: "Bulgarian" },
35
+ { alpha3: "bur", alpha2: "my", English: "Burmese", franc3: "mya" },
36
+ { alpha3: "cat", alpha2: "ca", English: "Catalan; Valencian" },
37
+ { alpha3: "cha", alpha2: "ch", English: "Chamorro", franc3: null },
38
+ { alpha3: "che", alpha2: "ce", English: "Chechen", franc3: null },
39
+ { alpha3: "chi", alpha2: "zh", English: "Chinese", franc3: "cmn" },
40
+ {
41
+ alpha3: "chu",
42
+ alpha2: "cu",
43
+ English:
44
+ "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic",
45
+ franc3: null,
46
+ },
47
+ { alpha3: "chv", alpha2: "cv", English: "Chuvash", franc3: null },
48
+ { alpha3: "cor", alpha2: "kw", English: "Cornish", franc3: null },
49
+ { alpha3: "cos", alpha2: "co", English: "Corsican", franc3: null },
50
+ { alpha3: "cre", alpha2: "cr", English: "Cree", franc3: null },
51
+ { alpha3: "cze", alpha2: "cs", English: "Czech", franc3: "ces" },
52
+ { alpha3: "dan", alpha2: "da", English: "Danish" },
53
+ {
54
+ alpha3: "div",
55
+ alpha2: "dv",
56
+ English: "Divehi; Dhivehi; Maldivian",
57
+ franc3: null,
58
+ },
59
+ { alpha3: "dut", alpha2: "nl", English: "Dutch; Flemish", franc3: "nld" },
60
+ { alpha3: "dzo", alpha2: "dz", English: "Dzongkha", franc3: null },
61
+ { alpha3: "eng", alpha2: "en", English: "English" },
62
+ { alpha3: "epo", alpha2: "eo", English: "Esperanto" },
63
+ { alpha3: "est", alpha2: "et", English: "Estonian" },
64
+ { alpha3: "ewe", alpha2: "ee", English: "Ewe" },
65
+ { alpha3: "fao", alpha2: "fo", English: "Faroese", franc3: null },
66
+ { alpha3: "fij", alpha2: "fj", English: "Fijian", franc3: null },
67
+ { alpha3: "fin", alpha2: "fi", English: "Finnish" },
68
+ { alpha3: "fre", alpha2: "fr", English: "French", franc3: "fra" },
69
+ { alpha3: "fry", alpha2: "fy", English: "Western Frisian", franc3: null },
70
+ { alpha3: "ful", alpha2: "ff", English: "Fulah", franc3: null },
71
+ { alpha3: "geo", alpha2: "ka", English: "Georgian", franc3: "kat" },
72
+ { alpha3: "ger", alpha2: "de", English: "German", franc3: "deu" },
73
+ {
74
+ alpha3: "gla",
75
+ alpha2: "gd",
76
+ English: "Gaelic; Scottish Gaelic",
77
+ franc3: null,
78
+ },
79
+ { alpha3: "gle", alpha2: "ga", English: "Irish", franc3: null },
80
+ { alpha3: "glg", alpha2: "gl", English: "Galician" },
81
+ { alpha3: "glv", alpha2: "gv", English: "Manx", franc3: null },
82
+ {
83
+ alpha3: "gre",
84
+ alpha2: "el",
85
+ English: "Greek, Modern (1453-)",
86
+ franc3: "ell",
87
+ },
88
+ { alpha3: "grn", alpha2: "gn", English: "Guarani", franc3: null },
89
+ { alpha3: "guj", alpha2: "gu", English: "Gujarati" },
90
+ { alpha3: "hat", alpha2: "ht", English: "Haitian; Haitian Creole" },
91
+ { alpha3: "hau", alpha2: "ha", English: "Hausa" },
92
+ { alpha3: "heb", alpha2: "he", English: "Hebrew" },
93
+ { alpha3: "her", alpha2: "hz", English: "Herero", franc3: null },
94
+ { alpha3: "hin", alpha2: "hi", English: "Hindi" },
95
+ { alpha3: "hmo", alpha2: "ho", English: "Hiri Motu", franc3: null },
96
+ { alpha3: "hrv", alpha2: "hr", English: "Croatian" },
97
+ { alpha3: "hun", alpha2: "hu", English: "Hungarian" },
98
+ { alpha3: "ibo", alpha2: "ig", English: "Igbo" },
99
+ { alpha3: "ice", alpha2: "is", English: "Icelandic", franc3: null },
100
+ { alpha3: "ido", alpha2: "io", English: "Ido", franc3: null },
101
+ { alpha3: "iii", alpha2: "ii", English: "Sichuan Yi; Nuosu" },
102
+ { alpha3: "iku", alpha2: "iu", English: "Inuktitut", franc3: null },
103
+ {
104
+ alpha3: "ile",
105
+ alpha2: "ie",
106
+ English: "Interlingue; Occidental",
107
+ franc3: null,
108
+ },
109
+ {
110
+ alpha3: "ina",
111
+ alpha2: "ia",
112
+ English: "Interlingua (International Auxiliary Language Association)",
113
+ franc3: null,
114
+ },
115
+ { alpha3: "ind", alpha2: "id", English: "Indonesian" },
116
+ { alpha3: "ipk", alpha2: "ik", English: "Inupiaq", franc3: null },
117
+ { alpha3: "ita", alpha2: "it", English: "Italian" },
118
+ { alpha3: "jav", alpha2: "jv", English: "Javanese" },
119
+ { alpha3: "jpn", alpha2: "ja", English: "Japanese" },
120
+ {
121
+ alpha3: "kal",
122
+ alpha2: "kl",
123
+ English: "Kalaallisut; Greenlandic",
124
+ franc3: null,
125
+ },
126
+ { alpha3: "kan", alpha2: "kn", English: "Kannada" },
127
+ { alpha3: "kas", alpha2: "ks", English: "Kashmiri", franc3: null },
128
+ { alpha3: "kau", alpha2: "kr", English: "Kanuri", franc3: "knc" },
129
+ { alpha3: "kaz", alpha2: "kk", English: "Kazakh" },
130
+ { alpha3: "khm", alpha2: "km", English: "Central Khmer" },
131
+ { alpha3: "kik", alpha2: "ki", English: "Kikuyu; Gikuyu", franc3: null },
132
+ { alpha3: "kin", alpha2: "rw", English: "Kinyarwanda" },
133
+ { alpha3: "kir", alpha2: "ky", English: "Kirghiz; Kyrgyz" },
134
+ { alpha3: "kom", alpha2: "kv", English: "Komi", franc3: "koi" },
135
+ { alpha3: "kon", alpha2: "kg", English: "Kongo", franc3: null },
136
+ { alpha3: "kor", alpha2: "ko", English: "Korean" },
137
+ {
138
+ alpha3: "kua",
139
+ alpha2: "kj",
140
+ English: "Kuanyama; Kwanyama",
141
+ franc3: null,
142
+ },
143
+ { alpha3: "kur", alpha2: "ku", English: "Kurdish", franc3: "ckb" },
144
+ { alpha3: "lao", alpha2: "lo", English: "Lao" },
145
+ { alpha3: "lat", alpha2: "la", English: "Latin", franc3: null },
146
+ { alpha3: "lav", alpha2: "lv", English: "Latvian" },
147
+ {
148
+ alpha3: "lim",
149
+ alpha2: "li",
150
+ English: "Limburgan; Limburger; Limburgish",
151
+ franc3: null,
152
+ },
153
+ { alpha3: "lin", alpha2: "ln", English: "Lingala" },
154
+ { alpha3: "lit", alpha2: "lt", English: "Lithuanian" },
155
+ {
156
+ alpha3: "ltz",
157
+ alpha2: "lb",
158
+ English: "Luxembourgish; Letzeburgesch",
159
+ franc3: null,
160
+ },
161
+ { alpha3: "lub", alpha2: "lu", English: "Luba-Katanga", franc3: null },
162
+ { alpha3: "lug", alpha2: "lg", English: "Ganda" },
163
+ { alpha3: "mac", alpha2: "mk", English: "Macedonian", franc3: "mkd" },
164
+ { alpha3: "mah", alpha2: "mh", English: "Marshallese", franc3: null },
165
+ { alpha3: "mal", alpha2: "ml", English: "Malayalam" },
166
+ { alpha3: "mao", alpha2: "mi", English: "Maori", franc3: null },
167
+ { alpha3: "mar", alpha2: "mr", English: "Marathi" },
168
+ { alpha3: "may", alpha2: "ms", English: "Malay", franc3: null },
169
+ { alpha3: "mlg", alpha2: "mg", English: "Malagasy", franc3: "plt" },
170
+ { alpha3: "mlt", alpha2: "mt", English: "Maltese", franc3: null },
171
+ { alpha3: "mon", alpha2: "mn", English: "Mongolian", franc3: "khk" },
172
+ { alpha3: "nau", alpha2: "na", English: "Nauru", franc3: null },
173
+ { alpha3: "nav", alpha2: "nv", English: "Navajo; Navaho", franc3: null },
174
+ {
175
+ alpha3: "nbl",
176
+ alpha2: "nr",
177
+ English: "Ndebele, South; South Ndebele",
178
+ franc3: null,
179
+ },
180
+ {
181
+ alpha3: "nde",
182
+ alpha2: "nd",
183
+ English: "Ndebele, North; North Ndebele",
184
+ franc3: null,
185
+ },
186
+ { alpha3: "ndo", alpha2: "ng", English: "Ndonga" },
187
+ { alpha3: "nep", alpha2: "ne", English: "Nepali" },
188
+ {
189
+ alpha3: "nno",
190
+ alpha2: "nn",
191
+ English: "Norwegian Nynorsk; Nynorsk, Norwegian",
192
+ },
193
+ {
194
+ alpha3: "nob",
195
+ alpha2: "nb",
196
+ English: "Bokmål, Norwegian; Norwegian Bokmål",
197
+ },
198
+ { alpha3: "nor", alpha2: "no", English: "Norwegian", franc3: "nob" },
199
+ { alpha3: "nya", alpha2: "ny", English: "Chichewa; Chewa; Nyanja" },
200
+ {
201
+ alpha3: "oci",
202
+ alpha2: "oc",
203
+ English: "Occitan (post 1500); Provençal",
204
+ franc3: null,
205
+ },
206
+ { alpha3: "oji", alpha2: "oj", English: "Ojibwa", franc3: null },
207
+ { alpha3: "ori", alpha2: "or", English: "Oriya" },
208
+ { alpha3: "orm", alpha2: "om", English: "Oromo", franc3: "gax" },
209
+ { alpha3: "oss", alpha2: "os", English: "Ossetian; Ossetic", franc3: null },
210
+ { alpha3: "pan", alpha2: "pa", English: "Panjabi; Punjabi" },
211
+ { alpha3: "per", alpha2: "fa", English: "Persian", franc3: "fas" },
212
+ { alpha3: "pli", alpha2: "pi", English: "Pali", franc3: null },
213
+ { alpha3: "pol", alpha2: "pl", English: "Polish" },
214
+ { alpha3: "por", alpha2: "pt", English: "Portuguese" },
215
+ { alpha3: "pus", alpha2: "ps", English: "Pushto; Pashto", franc3: null },
216
+ { alpha3: "que", alpha2: "qu", English: "Quechua", franc3: "quz" },
217
+ { alpha3: "roh", alpha2: "rm", English: "Romansh", franc3: null },
218
+ {
219
+ alpha3: "rum",
220
+ alpha2: "ro",
221
+ English: "Romanian; Moldavian; Moldovan",
222
+ franc3: "ron",
223
+ },
224
+ { alpha3: "run", alpha2: "rn", English: "Rundi" },
225
+ { alpha3: "rus", alpha2: "ru", English: "Russian" },
226
+ { alpha3: "sag", alpha2: "sg", English: "Sango" },
227
+ { alpha3: "san", alpha2: "sa", English: "Sanskrit", franc3: null },
228
+ { alpha3: "sin", alpha2: "si", English: "Sinhala; Sinhalese" },
229
+ { alpha3: "slo", alpha2: "sk", English: "Slovak", franc3: "slk" },
230
+ { alpha3: "slv", alpha2: "sl", English: "Slovenian" },
231
+ { alpha3: "sme", alpha2: "se", English: "Northern Sami", franc3: null },
232
+ { alpha3: "smo", alpha2: "sm", English: "Samoan", franc3: null },
233
+ { alpha3: "sna", alpha2: "sn", English: "Shona" },
234
+ { alpha3: "snd", alpha2: "sd", English: "Sindhi", franc3: null },
235
+ { alpha3: "som", alpha2: "so", English: "Somali" },
236
+ { alpha3: "sot", alpha2: "st", English: "Sotho, Southern" },
237
+ { alpha3: "spa", alpha2: "es", English: "Spanish; Castilian" },
238
+ { alpha3: "srd", alpha2: "sc", English: "Sardinian", franc3: "src" },
239
+ { alpha3: "srp", alpha2: "sr", English: "Serbian" },
240
+ { alpha3: "ssw", alpha2: "ss", English: "Swati" },
241
+ { alpha3: "sun", alpha2: "su", English: "Sundanese" },
242
+ { alpha3: "swa", alpha2: "sw", English: "Swahili", franc3: "swh" },
243
+ { alpha3: "swe", alpha2: "sv", English: "Swedish" },
244
+ { alpha3: "tah", alpha2: "ty", English: "Tahitian", franc3: null },
245
+ { alpha3: "tam", alpha2: "ta", English: "Tamil" },
246
+ { alpha3: "tat", alpha2: "tt", English: "Tatar" },
247
+ { alpha3: "tel", alpha2: "te", English: "Telugu" },
248
+ { alpha3: "tgk", alpha2: "tg", English: "Tajik" },
249
+ { alpha3: "tgl", alpha2: "tl", English: "Tagalog" },
250
+ { alpha3: "tha", alpha2: "th", English: "Thai" },
251
+ { alpha3: "tib", alpha2: "bo", English: "Tibetan", franc3: "bod" },
252
+ { alpha3: "tir", alpha2: "ti", English: "Tigrinya" },
253
+ {
254
+ alpha3: "ton",
255
+ alpha2: "to",
256
+ English: "Tonga (Tonga Islands)",
257
+ franc3: "toi",
258
+ },
259
+ { alpha3: "tsn", alpha2: "tn", English: "Tswana" },
260
+ { alpha3: "tso", alpha2: "ts", English: "Tsonga" },
261
+ { alpha3: "tuk", alpha2: "tk", English: "Turkmen" },
262
+ { alpha3: "tur", alpha2: "tr", English: "Turkish" },
263
+ { alpha3: "twi", alpha2: "tw", English: "Twi", franc3: null },
264
+ { alpha3: "uig", alpha2: "ug", English: "Uighur; Uyghur" },
265
+ { alpha3: "ukr", alpha2: "uk", English: "Ukrainian" },
266
+ { alpha3: "urd", alpha2: "ur", English: "Urdu" },
267
+ { alpha3: "uzb", alpha2: "uz", English: "Uzbek", franc3: "uzn" },
268
+ { alpha3: "ven", alpha2: "ve", English: "Venda" },
269
+ { alpha3: "vie", alpha2: "vi", English: "Vietnamese" },
270
+ { alpha3: "vol", alpha2: "vo", English: "Volapük", franc3: null },
271
+ { alpha3: "wel", alpha2: "cy", English: "Welsh", franc3: null },
272
+ { alpha3: "wln", alpha2: "wa", English: "Walloon", franc3: null },
273
+ { alpha3: "wol", alpha2: "wo", English: "Wolof" },
274
+ { alpha3: "xho", alpha2: "xh", English: "Xhosa" },
275
+ { alpha3: "yid", alpha2: "yi", English: "Yiddish", franc3: "ydd" },
276
+ { alpha3: "yor", alpha2: "yo", English: "Yoruba" },
277
+ { alpha3: "zha", alpha2: "za", English: "Zhuang; Chuang", franc3: "zyb" },
278
+ { alpha3: "zul", alpha2: "zu", English: "Zulu" },
279
+ ];
280
+
281
+ /**
282
+ * An array of valid language codes.
283
+ *
284
+ * This array contains ISO 639-1 language codes that are used to identify languages.
285
+ *
286
+ * @constant {string[]}
287
+ */
288
+ export const validLangCodes = [
289
+ "af",
290
+ "agq",
291
+ "ak",
292
+ "am",
293
+ "ar",
294
+ "as",
295
+ "asa",
296
+ "ast",
297
+ "az",
298
+ "bas",
299
+ "be",
300
+ "bem",
301
+ "bez",
302
+ "bg",
303
+ "bm",
304
+ "bn",
305
+ "bo",
306
+ "br",
307
+ "brx",
308
+ "bs",
309
+ "ca",
310
+ "ce",
311
+ "cgg",
312
+ "chr",
313
+ "ckb",
314
+ "cs",
315
+ "cu",
316
+ "cy",
317
+ "da",
318
+ "dav",
319
+ "de",
320
+ "dje",
321
+ "dsb",
322
+ "dua",
323
+ "dyo",
324
+ "dz",
325
+ "ebu",
326
+ "ee",
327
+ "el",
328
+ "en",
329
+ "eo",
330
+ "es",
331
+ "et",
332
+ "eu",
333
+ "ewo",
334
+ "fa",
335
+ "ff",
336
+ "fi",
337
+ "fil",
338
+ "fo",
339
+ "fr",
340
+ "fur",
341
+ "fy",
342
+ "ga",
343
+ "gd",
344
+ "gl",
345
+ "gsw",
346
+ "gu",
347
+ "guz",
348
+ "gv",
349
+ "ha",
350
+ "haw",
351
+ "he",
352
+ "hi",
353
+ "hr",
354
+ "hsb",
355
+ "hu",
356
+ "hy",
357
+ "id",
358
+ "ig",
359
+ "ii",
360
+ "is",
361
+ "it",
362
+ "ja",
363
+ "jgo",
364
+ "jmc",
365
+ "ka",
366
+ "kab",
367
+ "kam",
368
+ "kde",
369
+ "kea",
370
+ "khq",
371
+ "ki",
372
+ "kk",
373
+ "kkj",
374
+ "kl",
375
+ "kln",
376
+ "km",
377
+ "kn",
378
+ "ko",
379
+ "kok",
380
+ "ks",
381
+ "ksb",
382
+ "ksf",
383
+ "ksh",
384
+ "kw",
385
+ "ky",
386
+ "lag",
387
+ "lb",
388
+ "lg",
389
+ "lkt",
390
+ "ln",
391
+ "lo",
392
+ "lrc",
393
+ "lt",
394
+ "lu",
395
+ "luo",
396
+ "luy",
397
+ "lv",
398
+ "mas",
399
+ "mer",
400
+ "mfe",
401
+ "mg",
402
+ "mgh",
403
+ "mgo",
404
+ "mk",
405
+ "ml",
406
+ "mn",
407
+ "mr",
408
+ "ms",
409
+ "mt",
410
+ "mua",
411
+ "my",
412
+ "mzn",
413
+ "naq",
414
+ "nb",
415
+ "nd",
416
+ "nds",
417
+ "ne",
418
+ "nl",
419
+ "nmg",
420
+ "nn",
421
+ "nnh",
422
+ "nus",
423
+ "nyn",
424
+ "om",
425
+ "or",
426
+ "os",
427
+ "pa",
428
+ "pl",
429
+ "prg",
430
+ "ps",
431
+ "pt",
432
+ "qu",
433
+ "rm",
434
+ "rn",
435
+ "ro",
436
+ "rof",
437
+ "ru",
438
+ "rw",
439
+ "rwk",
440
+ "sah",
441
+ "saq",
442
+ "sbp",
443
+ "se",
444
+ "seh",
445
+ "ses",
446
+ "sg",
447
+ "shi",
448
+ "si",
449
+ "sk",
450
+ "sl",
451
+ "smn",
452
+ "sn",
453
+ "so",
454
+ "sq",
455
+ "sr",
456
+ "sv",
457
+ "sw",
458
+ "ta",
459
+ "te",
460
+ "teo",
461
+ "th",
462
+ "ti",
463
+ "tk",
464
+ "to",
465
+ "tr",
466
+ "twq",
467
+ "tzm",
468
+ "ug",
469
+ "uk",
470
+ "ur",
471
+ "uz",
472
+ "vai",
473
+ "vi",
474
+ "vo",
475
+ "vun",
476
+ "wae",
477
+ "xog",
478
+ "yav",
479
+ "yi",
480
+ "yo",
481
+ "yue",
482
+ "zgh",
483
+ "zh",
484
+ "zu",
485
+ ];
486
+
487
+ /**
488
+ * An array of language codes that are written from right to left.
489
+ *
490
+ * @constant {string[]}
491
+ */
492
+ export const rtls = ["ar", "az", "dv", "he", "ku", "fa", "ur"];
493
+
494
+
495
+ /**
496
+ * Converts a three-letter language code to a two-letter language code.
497
+ *
498
+ * @param {string} threeLetterCode - The three-letter language code to convert.
499
+ * @returns {string|boolean} The corresponding two-letter language code, or false if not found.
500
+ */
501
+ export function getTwoLetterCode(threeLetterCode) {
502
+ if (threeLetterCode === "cmn") {
503
+ threeLetterCode = "chi";
504
+ }
505
+ const result = langCodes.find(
506
+ (value) =>
507
+ value.alpha3 === threeLetterCode || value.franc3 === threeLetterCode
508
+ );
509
+ return result ? result.alpha2 : false;
510
+ }
511
+
512
+ /**
513
+ * Tests the language of an HTML element against its content.
514
+ *
515
+ * This function checks the `lang` or `xml:lang` attribute of the given element
516
+ * and its ancestors to determine the language. It then uses the `franc` library
517
+ * to detect the language of the element's text content and compares it to the
518
+ * language attribute.
519
+ *
520
+ * @param {HTMLElement} element - The HTML element to test.
521
+ * @returns {boolean} - Returns `true` if the detected language matches the
522
+ * language attribute or if the detected language is
523
+ * undefined ("und"). Otherwise, returns `false`.
524
+ */
525
+ export function testLang(element) {
526
+ let selfLang =
527
+ element.getAttribute("lang") || element.getAttribute("xml:lang");
528
+ if (!selfLang) {
529
+ let parent = element.parentElement;
530
+ while (parent && !selfLang) {
531
+ selfLang =
532
+ parent.getAttribute("lang") || parent.getAttribute("xml:lang");
533
+ parent = parent.parentElement;
534
+ }
535
+ }
536
+ if (!selfLang || selfLang.length < 2) return false;
537
+ selfLang = selfLang.split("-")[0].toLowerCase();
538
+ const threeLetterCode = franc(element.textContent.trim());
539
+ if (threeLetterCode === "und") return true;
540
+ return getTwoLetterCode(threeLetterCode) === selfLang;
541
+ }
542
+
543
+ export function getLang(element) {
544
+ let selfLang =
545
+ element.getAttribute("lang") || element.getAttribute("xml:lang");
546
+ if (!selfLang) {
547
+ let parent = element.parentElement;
548
+ while (parent && !selfLang) {
549
+ selfLang =
550
+ parent.getAttribute("lang") || parent.getAttribute("xml:lang");
551
+ parent = parent.parentElement;
552
+ }
553
+ }
554
+ if (!selfLang || selfLang.length < 2) return false;
555
+ selfLang = selfLang.split("-")[0].toLowerCase();
556
+ const result = langCodes.find(
557
+ (value) => value.alpha2 === selfLang || value.alpha3 === selfLang
558
+ );
559
+ if (result) {
560
+ return result.alpha2;
561
+ } else if (validLangCodes.includes(selfLang)) {
562
+ return selfLang;
563
+ } else {
564
+ return false;
565
+ }
566
+ }
567
+
568
+ export function isDirValid(element) {
569
+ const lang = getLang(element);
570
+ if (element.hasAttribute("dir")) {
571
+ const dir = element.getAttribute("dir");
572
+ return rtls.includes(lang) ? dir === "rtl" : dir !== "rtl";
573
+ }
574
+ return !rtls.includes(lang);
575
+ }
@@ -0,0 +1,90 @@
1
+ import { getFocusableElements } from "./getFocusableElements.js";
2
+
3
+ /**
4
+ *
5
+ * @param {Element} a - First element to compare
6
+ * @param {Element} b - Second element to compare
7
+ * @returns {number} - Sorting order based on visual position
8
+ */
9
+ export function sortByVisualOrder(a, b) {
10
+ const rectA = a.getBoundingClientRect();
11
+ const rectB = b.getBoundingClientRect();
12
+
13
+ if (rectA.top !== rectB.top) {
14
+ return rectA.top - rectB.top;
15
+ }
16
+ return rectA.left - rectB.left;
17
+ }
18
+
19
+ /**
20
+ *
21
+ * @param {Element} el - The container element to test focus order
22
+ * @returns {boolean} - True if the focus order matches visual order
23
+ */
24
+ export function testOrder(el) {
25
+ const els = getFocusableElements(el);
26
+ let focusOrder = [...els];
27
+
28
+ // Sort by tabindex
29
+ const elsIndex = focusOrder.map((el, index) => ({ index, el }));
30
+ elsIndex.sort((a, b) => {
31
+ const tabindexA = parseInt(a.el.getAttribute("tabindex")) || 0;
32
+ const tabindexB = parseInt(b.el.getAttribute("tabindex")) || 0;
33
+
34
+ const definedA = tabindexA > 0;
35
+ const definedB = tabindexB > 0;
36
+
37
+ if (!definedA && !definedB) {
38
+ return a.index - b.index;
39
+ }
40
+ if (definedA && !definedB) {
41
+ return -1;
42
+ }
43
+ if (!definedA && definedB) {
44
+ return 1;
45
+ }
46
+ return tabindexA - tabindexB;
47
+ });
48
+ focusOrder = elsIndex.map((obj) => obj.el);
49
+
50
+ const visualOrder = [...els].sort(sortByVisualOrder);
51
+ const visualOrderNoCSS = [...els];
52
+
53
+ // Remove CSS and inline styles
54
+ const styleEls = Array.from(
55
+ document.querySelectorAll('link[rel="stylesheet"], style')
56
+ ).map((style) => style.cloneNode(true));
57
+ document
58
+ .querySelectorAll('link[rel="stylesheet"], style')
59
+ .forEach((style) => style.remove());
60
+
61
+ const inlineStyles = visualOrderNoCSS.map((el) => {
62
+ const style = el.getAttribute("style");
63
+ el.setAttribute("style", "");
64
+ return style;
65
+ });
66
+
67
+ // Sort with no styles
68
+ visualOrderNoCSS.sort(sortByVisualOrder);
69
+
70
+ // Restore styles
71
+ visualOrderNoCSS.forEach((el, i) => {
72
+ if (inlineStyles[i]) {
73
+ el.setAttribute("style", inlineStyles[i]);
74
+ } else {
75
+ el.removeAttribute("style");
76
+ }
77
+ });
78
+
79
+ styleEls.forEach((style) => document.head.appendChild(style));
80
+
81
+ for (let i = 0; i < focusOrder.length; i++) {
82
+ if (focusOrder[i] !== visualOrder[i]) {
83
+ return false;
84
+ }
85
+ if (focusOrder[i] !== visualOrderNoCSS[i]) {
86
+ return false;
87
+ }
88
+ }
89
+ return true;
90
+ }
@@ -0,0 +1,21 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ // Import the function or module you want to test
3
+ // import { functionName } from '../src/fileName';
4
+
5
+ describe('Template Test File', () => {
6
+ // Setup before each test if needed
7
+ beforeEach(() => {
8
+ document.body.innerHTML = '';
9
+ });
10
+
11
+ it('should do something expected', () => {
12
+ // Arrange: Set up your test
13
+
14
+ // Act: Call the function or method being tested
15
+
16
+ // Assert: Check the result matches what you expect
17
+ expect(true).toBe(true);
18
+ });
19
+
20
+ // Add more test cases here
21
+ });