diff --git a/src/lib/__tests__/emailHtml.test.ts b/src/lib/__tests__/emailHtml.test.ts index 286de8f..94060df 100644 --- a/src/lib/__tests__/emailHtml.test.ts +++ b/src/lib/__tests__/emailHtml.test.ts @@ -104,14 +104,21 @@ describe("prepareHtml", () => { assert.ok(!result.includes("filter:invert")); }); - it("adapts only low-contrast neutral text in dark mode", () => { + it("adapts only low-contrast neutral text and list markers in dark mode", () => { const result = prepareHtml( documentWith( - '

Black text

Brand text

Image-backed text
', + '

Black text

Brand text

Image-backed text
', ), ); assert.ok(result.includes("data-email-client-adapted-text")); - assert.ok(result.includes("contrastRatio(foreground,background)>=4.5")); + assert.ok(result.includes("data-email-client-adapted-marker")); + assert.ok( + result.includes( + "li[data-email-client-adapted-marker]::marker{color:#e2e8f0!important}", + ), + ); + assert.ok(result.includes("getComputedStyle(element,'::marker')")); + assert.ok(result.includes("contrastRatio(foreground,background)<4.5")); assert.ok(result.includes("spread>56||luminance(foreground)>0.18")); assert.ok( result.includes( diff --git a/src/lib/emailHtml.ts b/src/lib/emailHtml.ts index d9b1706..c60379f 100644 --- a/src/lib/emailHtml.ts +++ b/src/lib/emailHtml.ts @@ -186,10 +186,20 @@ function darkTextAdaptationScript(theme: EmailRenderTheme): string { } return parseRgb(${fallbackBackground}); } + function needsAdaptation(foreground,background){ + if(!foreground||!background)return false; + var spread=Math.max(foreground.r,foreground.g,foreground.b)- + Math.min(foreground.r,foreground.g,foreground.b); + if(spread>56||luminance(foreground)>0.18)return false; + return contrastRatio(foreground,background)<4.5; + } function adaptDarkText(){ - var marked=document.querySelectorAll('[data-email-client-adapted-text]'); + var marked=document.querySelectorAll( + '[data-email-client-adapted-text],[data-email-client-adapted-marker]' + ); for(var i=0;i56||luminance(foreground)>0.18)continue; - if(contrastRatio(foreground,background)>=4.5)continue; - element.setAttribute('data-email-client-adapted-text','true'); + if(!background)continue; + + if(element.tagName==='LI'&&String(element.textContent||'').trim()){ + var markerStyle=window.getComputedStyle(element,'::marker'); + var markerColour=parseRgb(markerStyle.color)||parseRgb(computed.color); + if(needsAdaptation(markerColour,background)){ + element.setAttribute('data-email-client-adapted-marker','true'); + } + } + + if(hasDirectText(element)&&needsAdaptation(parseRgb(computed.color),background)){ + element.setAttribute('data-email-client-adapted-text','true'); + } } } if(darkMode){ @@ -321,6 +336,7 @@ export function prepareHtml( body:not([text]){color:${theme.textDarkColor}} body:not([link]) a{color:${theme.linkDarkColor}} [data-email-client-adapted-text]{color:${theme.textDarkColor}!important} + li[data-email-client-adapted-marker]::marker{color:${theme.textDarkColor}!important} } `; const inject = `${viewport}${baseStyle}${resizeScript(!!opts?.stripQuotes, theme)}`;