abledom 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -58,7 +58,7 @@ var ValidationRule = class {
58
58
  };
59
59
 
60
60
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/ui.css
61
- var ui_default = "#abledom-report {\n bottom: 20px;\n display: flex;\n flex-direction: column;\n left: 10px;\n max-height: 80%;\n max-width: 60%;\n padding: 4px 8px;\n position: fixed;\n z-index: 100500;\n}\n\n#abledom-report :focus-visible {\n outline: 3px solid red;\n mix-blend-mode: difference;\n}\n\n#abledom-report.abledom-align-left {\n left: 10px;\n right: auto;\n}\n\n#abledom-report.abledom-align-right {\n left: auto;\n right: 10px;\n}\n\n#abledom-report.abledom-align-bottom {\n bottom: 20px;\n top: auto;\n}\n\n#abledom-report.abledom-align-top {\n /* flex-direction: column-reverse; */\n bottom: auto;\n top: 10px;\n}\n\n.abledom-menu-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-block;\n margin: 2px auto 2px 0;\n}\n\n#abledom-report.abledom-align-right .abledom-menu-container {\n margin: 2px 0 2px auto;\n}\n\n.abledom-menu {\n background-color: rgba(140, 10, 121, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n\n.abledom-menu .issues-count {\n margin: 0 8px;\n display: inline-block;\n}\n\n.abledom-menu .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-menu .align-button {\n border-right-color: rgba(0, 0, 0, 0.4);\n border-radius: 0;\n margin: 0;\n}\n\n.abledom-menu .align-button:active,\n#abledom-report .pressed {\n background: linear-gradient(\n 180deg,\n rgba(130, 130, 130, 1) 0%,\n rgba(180, 180, 180, 1) 100%\n );\n}\n\n.abledom-menu .align-button-first {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n margin-left: 8px;\n}\n.abledom-menu .align-button-last {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n border-right-color: rgba(255, 255, 255, 0.4);\n}\n\n.abledom-issues-container {\n overflow: scroll;\n max-height: calc(100vh - 100px);\n}\n\n#abledom-report.abledom-align-right .abledom-issues-container {\n text-align: right;\n}\n\n.abledom-issue-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-flex;\n margin: 2px 0;\n}\n\n.abledom-issue {\n background-color: rgba(164, 2, 2, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n.abledom-issue_warning {\n background-color: rgba(163, 82, 1, 0.7);\n}\n.abledom-issue_info {\n background-color: rgba(0, 0, 255, 0.7);\n}\n\n.abledom-issue .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-issue .button:hover {\n opacity: 0.7;\n}\n\n.abledom-issue .button.close {\n background: none;\n border-color: transparent;\n color: #fff;\n margin: 0;\n}\n\n.abledom-highlight {\n background-color: yellow;\n box-sizing: border-box;\n display: none;\n opacity: 0.6;\n position: fixed;\n z-index: 100499;\n}\n\n.abledom-highlight-border1 {\n border-top: 2px solid red;\n border-bottom: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n top: -2px;\n width: calc(100% + 20px);\n height: calc(100% + 4px);\n margin: 0 -10px;\n}\n\n.abledom-highlight-border2 {\n border-left: 2px solid red;\n border-right: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n width: calc(100% + 4px);\n left: -2px;\n height: calc(100% + 20px);\n margin: -10px 0;\n}\n";
61
+ var ui_default = "#abledom-report {\n bottom: 20px;\n display: flex;\n flex-direction: column;\n left: 10px;\n max-height: 80%;\n max-width: 60%;\n padding: 4px 8px;\n position: fixed;\n z-index: 100500;\n}\n\n#abledom-report :focus-visible {\n outline: 3px solid red;\n mix-blend-mode: difference;\n}\n\n#abledom-report.abledom-align-left {\n left: 10px;\n right: auto;\n}\n\n#abledom-report.abledom-align-right {\n left: auto;\n right: 10px;\n}\n\n#abledom-report.abledom-align-bottom {\n bottom: 20px;\n top: auto;\n}\n\n#abledom-report.abledom-align-top {\n /* flex-direction: column-reverse; */\n bottom: auto;\n top: 10px;\n}\n\n.abledom-menu-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-block;\n margin: 2px auto 2px 0;\n}\n\n#abledom-report.abledom-align-right .abledom-menu-container {\n margin: 2px 0 2px auto;\n}\n\n.abledom-menu {\n background-color: rgba(140, 10, 121, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n\n.abledom-menu .issues-count {\n margin: 0 8px;\n display: inline-block;\n}\n\n.abledom-menu .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-menu .align-button {\n border-right-color: rgba(0, 0, 0, 0.4);\n border-radius: 0;\n margin: 0;\n}\n\n.abledom-menu .align-button:active,\n#abledom-report .pressed {\n background: linear-gradient(\n 180deg,\n rgba(130, 130, 130, 1) 0%,\n rgba(180, 180, 180, 1) 100%\n );\n}\n\n.abledom-menu .align-button-first {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n margin-left: 8px;\n}\n.abledom-menu .align-button-last {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n border-right-color: rgba(255, 255, 255, 0.4);\n}\n\n.abledom-issues-container {\n overflow: auto;\n max-height: calc(100vh - 100px);\n}\n\n#abledom-report.abledom-align-right .abledom-issues-container {\n text-align: right;\n}\n\n.abledom-issue-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-flex;\n margin: 2px 0;\n}\n\n.abledom-issue {\n background-color: rgba(164, 2, 2, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n.abledom-issue_warning {\n background-color: rgba(163, 82, 1, 0.7);\n}\n.abledom-issue_info {\n background-color: rgba(0, 0, 255, 0.7);\n}\n\n.abledom-issue .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-issue .button:hover {\n opacity: 0.7;\n}\n\n.abledom-issue .button.close {\n background: none;\n border-color: transparent;\n color: #fff;\n margin: 0;\n}\n\n.abledom-highlight {\n background-color: yellow;\n box-sizing: border-box;\n display: none;\n opacity: 0.6;\n position: fixed;\n z-index: 100499;\n}\n\n.abledom-highlight-border1 {\n border-top: 2px solid red;\n border-bottom: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n top: -2px;\n width: calc(100% + 20px);\n height: calc(100% + 4px);\n margin: 0 -10px;\n}\n\n.abledom-highlight-border2 {\n border-left: 2px solid red;\n border-right: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n width: calc(100% + 4px);\n left: -2px;\n height: calc(100% + 20px);\n margin: -10px 0;\n}\n";
62
62
 
63
63
  // src/ui/domBuilder.ts
64
64
  var DOMBuilder = class {
@@ -116,7 +116,7 @@ var DOMBuilder = class {
116
116
  };
117
117
 
118
118
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/close.svg
119
- var close_default = function buildSVG(parent) {
119
+ var close_default = (function buildSVG(parent) {
120
120
  const builder = new DOMBuilder(parent);
121
121
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "xmlns": "http://www.w3.org/2000/svg" }, void 0, "http://www.w3.org/2000/svg");
122
122
  builder.openTag("circle", { "cx": "12", "cy": "12", "r": "10" }, void 0, "http://www.w3.org/2000/svg");
@@ -127,10 +127,10 @@ var close_default = function buildSVG(parent) {
127
127
  builder.closeTag();
128
128
  builder.closeTag();
129
129
  return parent.firstElementChild;
130
- };
130
+ });
131
131
 
132
132
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/help.svg
133
- var help_default = function buildSVG2(parent) {
133
+ var help_default = (function buildSVG2(parent) {
134
134
  const builder = new DOMBuilder(parent);
135
135
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "xmlns": "http://www.w3.org/2000/svg" }, void 0, "http://www.w3.org/2000/svg");
136
136
  builder.openTag("circle", { "cx": "12", "cy": "12", "r": "10" }, void 0, "http://www.w3.org/2000/svg");
@@ -141,10 +141,10 @@ var help_default = function buildSVG2(parent) {
141
141
  builder.closeTag();
142
142
  builder.closeTag();
143
143
  return parent.firstElementChild;
144
- };
144
+ });
145
145
 
146
146
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/log.svg
147
- var log_default = function buildSVG3(parent) {
147
+ var log_default = (function buildSVG3(parent) {
148
148
  const builder = new DOMBuilder(parent);
149
149
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "xmlns": "http://www.w3.org/2000/svg" }, void 0, "http://www.w3.org/2000/svg");
150
150
  builder.openTag("polyline", { "points": "4 7 9 12 4 17" }, void 0, "http://www.w3.org/2000/svg");
@@ -153,10 +153,10 @@ var log_default = function buildSVG3(parent) {
153
153
  builder.closeTag();
154
154
  builder.closeTag();
155
155
  return parent.firstElementChild;
156
- };
156
+ });
157
157
 
158
158
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/reveal.svg
159
- var reveal_default = function buildSVG4(parent) {
159
+ var reveal_default = (function buildSVG4(parent) {
160
160
  const builder = new DOMBuilder(parent);
161
161
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "xmlns": "http://www.w3.org/2000/svg" }, void 0, "http://www.w3.org/2000/svg");
162
162
  builder.openTag("circle", { "cx": "12", "cy": "12", "r": "10" }, void 0, "http://www.w3.org/2000/svg");
@@ -171,10 +171,10 @@ var reveal_default = function buildSVG4(parent) {
171
171
  builder.closeTag();
172
172
  builder.closeTag();
173
173
  return parent.firstElementChild;
174
- };
174
+ });
175
175
 
176
176
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/bug.svg
177
- var bug_default = function buildSVG5(parent) {
177
+ var bug_default = (function buildSVG5(parent) {
178
178
  const builder = new DOMBuilder(parent);
179
179
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
180
180
  builder.openTag("ellipse", { "cx": "10", "cy": "12", "rx": "4", "ry": "5", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -199,10 +199,10 @@ var bug_default = function buildSVG5(parent) {
199
199
  builder.closeTag();
200
200
  builder.closeTag();
201
201
  return parent.firstElementChild;
202
- };
202
+ });
203
203
 
204
204
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/hideall.svg
205
- var hideall_default = function buildSVG6(parent) {
205
+ var hideall_default = (function buildSVG6(parent) {
206
206
  const builder = new DOMBuilder(parent);
207
207
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
208
208
  builder.openTag("path", { "d": "M11.44 17.5a1.67 1.67 0 0 1-2.89 0", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -213,10 +213,10 @@ var hideall_default = function buildSVG6(parent) {
213
213
  builder.closeTag();
214
214
  builder.closeTag();
215
215
  return parent.firstElementChild;
216
- };
216
+ });
217
217
 
218
218
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/muteall.svg
219
- var muteall_default = function buildSVG7(parent) {
219
+ var muteall_default = (function buildSVG7(parent) {
220
220
  const builder = new DOMBuilder(parent);
221
221
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
222
222
  builder.openTag("path", { "d": "M11.44 17.5a1.67 1.67 0 0 1-2.89 0", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -229,10 +229,10 @@ var muteall_default = function buildSVG7(parent) {
229
229
  builder.closeTag();
230
230
  builder.closeTag();
231
231
  return parent.firstElementChild;
232
- };
232
+ });
233
233
 
234
234
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/showall.svg
235
- var showall_default = function buildSVG8(parent) {
235
+ var showall_default = (function buildSVG8(parent) {
236
236
  const builder = new DOMBuilder(parent);
237
237
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
238
238
  builder.openTag("path", { "d": "M11.44 17.5a1.67 1.67 0 0 1-2.89 0", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -241,47 +241,47 @@ var showall_default = function buildSVG8(parent) {
241
241
  builder.closeTag();
242
242
  builder.closeTag();
243
243
  return parent.firstElementChild;
244
- };
244
+ });
245
245
 
246
246
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopleft.svg
247
- var aligntopleft_default = function buildSVG9(parent) {
247
+ var aligntopleft_default = (function buildSVG9(parent) {
248
248
  const builder = new DOMBuilder(parent);
249
249
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
250
250
  builder.openTag("rect", { "x": "3", "y": "3", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
251
251
  builder.closeTag();
252
252
  builder.closeTag();
253
253
  return parent.firstElementChild;
254
- };
254
+ });
255
255
 
256
256
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopright.svg
257
- var aligntopright_default = function buildSVG10(parent) {
257
+ var aligntopright_default = (function buildSVG10(parent) {
258
258
  const builder = new DOMBuilder(parent);
259
259
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
260
260
  builder.openTag("rect", { "x": "11", "y": "3", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
261
261
  builder.closeTag();
262
262
  builder.closeTag();
263
263
  return parent.firstElementChild;
264
- };
264
+ });
265
265
 
266
266
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomright.svg
267
- var alignbottomright_default = function buildSVG11(parent) {
267
+ var alignbottomright_default = (function buildSVG11(parent) {
268
268
  const builder = new DOMBuilder(parent);
269
269
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
270
270
  builder.openTag("rect", { "x": "11", "y": "11", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
271
271
  builder.closeTag();
272
272
  builder.closeTag();
273
273
  return parent.firstElementChild;
274
- };
274
+ });
275
275
 
276
276
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomleft.svg
277
- var alignbottomleft_default = function buildSVG12(parent) {
277
+ var alignbottomleft_default = (function buildSVG12(parent) {
278
278
  const builder = new DOMBuilder(parent);
279
279
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
280
280
  builder.openTag("rect", { "x": "3", "y": "11", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
281
281
  builder.closeTag();
282
282
  builder.closeTag();
283
283
  return parent.firstElementChild;
284
- };
284
+ });
285
285
 
286
286
  // src/ui/ui.ts
287
287
  var pressedClass = "pressed";
@@ -1580,6 +1580,147 @@ var FocusableElementLabelRule = class extends ValidationRule {
1580
1580
  }
1581
1581
  };
1582
1582
 
1583
+ // src/rules/contrast.ts
1584
+ function hexToRgb(hex) {
1585
+ hex = hex.replace(/^#/, "");
1586
+ if (hex.length === 3) {
1587
+ hex = hex.split("").map((x) => x + x).join("");
1588
+ }
1589
+ if (hex.length !== 6) {
1590
+ return null;
1591
+ }
1592
+ const num = parseInt(hex, 16);
1593
+ return [num >> 16 & 255, num >> 8 & 255, num & 255];
1594
+ }
1595
+ function parseColor(color) {
1596
+ color = color.trim();
1597
+ if (color.startsWith("#")) {
1598
+ return hexToRgb(color);
1599
+ }
1600
+ const rgbMatch = color.match(
1601
+ /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)$/
1602
+ );
1603
+ if (rgbMatch) {
1604
+ return [
1605
+ parseInt(rgbMatch[1], 10),
1606
+ parseInt(rgbMatch[2], 10),
1607
+ parseInt(rgbMatch[3], 10)
1608
+ ];
1609
+ }
1610
+ return null;
1611
+ }
1612
+ function luminance([r, g, b]) {
1613
+ const a = [r, g, b].map((v) => {
1614
+ v /= 255;
1615
+ return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
1616
+ });
1617
+ return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
1618
+ }
1619
+ function contrastRatio(l1, l2) {
1620
+ return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
1621
+ }
1622
+ function isTransparent(color) {
1623
+ if (!color) {
1624
+ return true;
1625
+ }
1626
+ color = color.trim();
1627
+ if (color === "transparent" || color === "rgba(0, 0, 0, 0)") {
1628
+ return true;
1629
+ }
1630
+ const rgbaMatch = color.match(/^rgba?\(\d+,\s*\d+,\s*\d+,\s*([\d.]+)\)$/);
1631
+ if (rgbaMatch && parseFloat(rgbaMatch[1]) === 0) {
1632
+ return true;
1633
+ }
1634
+ return false;
1635
+ }
1636
+ var ContrastRule = class extends ValidationRule {
1637
+ constructor() {
1638
+ super(...arguments);
1639
+ __publicField(this, "type", 1 /* Error */);
1640
+ __publicField(this, "name", "ContrastRule");
1641
+ __publicField(this, "anchored", true);
1642
+ }
1643
+ accept(element) {
1644
+ if (!isElementVisible(element)) {
1645
+ return false;
1646
+ }
1647
+ const hasDirectTextContent = Array.from(element.childNodes).some((node) => {
1648
+ var _a;
1649
+ if (node.nodeType === Node.TEXT_NODE) {
1650
+ const text = (_a = node.textContent) == null ? void 0 : _a.trim();
1651
+ return text && text.length > 0;
1652
+ }
1653
+ return false;
1654
+ });
1655
+ return hasDirectTextContent;
1656
+ }
1657
+ validate(element) {
1658
+ const win = this.window;
1659
+ if (!win) {
1660
+ return null;
1661
+ }
1662
+ const style = win.getComputedStyle(element);
1663
+ const fg = parseColor(style.color);
1664
+ if (!fg) {
1665
+ return null;
1666
+ }
1667
+ const hasChildWithDifferentColor = Array.from(element.children).some(
1668
+ (child) => {
1669
+ var _a;
1670
+ if (child instanceof HTMLElement && ((_a = child.textContent) == null ? void 0 : _a.trim())) {
1671
+ const childStyle = win.getComputedStyle(child);
1672
+ const childColor = parseColor(childStyle.color);
1673
+ if (childColor && (childColor[0] !== fg[0] || childColor[1] !== fg[1] || childColor[2] !== fg[2])) {
1674
+ return true;
1675
+ }
1676
+ }
1677
+ return false;
1678
+ }
1679
+ );
1680
+ if (hasChildWithDifferentColor) {
1681
+ return null;
1682
+ }
1683
+ let bg = null;
1684
+ let el = element;
1685
+ let depth = 0;
1686
+ const maxDepth = 50;
1687
+ while (el && depth < maxDepth) {
1688
+ const bgColor = win.getComputedStyle(el).backgroundColor;
1689
+ if (!isTransparent(bgColor)) {
1690
+ const parsedBg = parseColor(bgColor);
1691
+ if (parsedBg) {
1692
+ bg = parsedBg;
1693
+ break;
1694
+ }
1695
+ }
1696
+ el = el.parentElement;
1697
+ depth++;
1698
+ }
1699
+ if (!bg) {
1700
+ bg = [255, 255, 255];
1701
+ }
1702
+ const l1 = luminance(fg);
1703
+ const l2 = luminance(bg);
1704
+ const ratio = contrastRatio(l1, l2);
1705
+ const fontSize = parseFloat(style.fontSize);
1706
+ const fontWeight = style.fontWeight;
1707
+ const isBold = fontWeight === "bold" || fontWeight === "bolder" || parseInt(fontWeight, 10) >= 700;
1708
+ const isLarge = fontSize >= 24 || fontSize >= 18.66 && isBold;
1709
+ const minRatio = isLarge ? 3 : 4.5;
1710
+ if (ratio < minRatio) {
1711
+ return {
1712
+ issue: {
1713
+ id: "contrast",
1714
+ message: `Text contrast ratio is ${ratio.toFixed(2)}:1, which is below the minimum of ${minRatio}:1 (text: rgb(${fg.join(", ")}), background: rgb(${bg.join(", ")})) on ${element.tagName}`,
1715
+ element,
1716
+ help: "https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html"
1717
+ }
1718
+ };
1719
+ }
1720
+ return null;
1721
+ }
1722
+ };
1723
+
1583
1724
  // src/rules/existingid.ts
1584
1725
  var ExistingIdRule = class extends ValidationRule {
1585
1726
  constructor() {
@@ -1830,6 +1971,7 @@ export {
1830
1971
  AbleDOM,
1831
1972
  AtomicRule,
1832
1973
  BadFocusRule,
1974
+ ContrastRule,
1833
1975
  CustomNotifyRule,
1834
1976
  ExistingIdRule,
1835
1977
  FindElementRule,