Skip to content

Commit

Permalink
add checkVisibility
Browse files Browse the repository at this point in the history
  • Loading branch information
keithamus committed Oct 20, 2023
1 parent 7d751a8 commit caa52c6
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
14 changes: 14 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,20 @@ <h1>GitHub Feature Support Table</h1>
<td data-supported="true"><div>78+</div></td>
<td data-supported="true"><div>16.0+</div></td>
</tr>
<tr>
<th>
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/checkVisibility">
<code>Element.checkVisibility</code>
</a>
</th>
<td data-polyfill="elementCheckVisibility"><div>*</div></td>
<td data-supported="true"><div>105+</div></td>
<td data-supported="true"><div>105+</div></td>
<td data-supported="true"><div>106+</div></td>
<td data-supported="false"><div>*</div></td>
<td data-supported="true"><div>91+</div></td>
<td data-supported="true"><div>20.0+</div></td>
</tr>
<tr>
<th>
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/replaceChildren">
Expand Down
50 changes: 50 additions & 0 deletions src/element-checkvisibility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
declare global {
interface Element {
checkVisibility(options?: Partial<CheckVisibilityOptions>): boolean
}
}

interface CheckVisibilityOptions {
checkOpacity: boolean
checkVisibilityCSS: boolean
}

export function checkVisibility(
this: Element,
{checkOpacity = false, checkVisibilityCSS = false}: Partial<CheckVisibilityOptions> = {}

Check failure on line 14 in src/element-checkvisibility.ts

View workflow job for this annotation

GitHub Actions / build

Insert `,`
) {
if (!this.isConnected) return false
const styles = getComputedStyle(this)
if (styles.getPropertyValue('display') === 'contents') return false
if (checkVisibilityCSS && styles.getPropertyValue('visibility') !== 'visible') return false
// eslint-disable-next-line @typescript-eslint/no-this-alias
let node: Element | null = this
while (node) {
const nodeStyles = node === this ? styles : getComputedStyle(node)
if (nodeStyles.getPropertyValue('display') === 'none') return false
if (checkOpacity && nodeStyles.getPropertyValue('opacity') === '0') return false
if (node !== this && nodeStyles.getPropertyValue('content-visibility') === 'hidden') {
return false
}
if (!node.parentElement && node.getRootNode() instanceof ShadowRoot) {
node = (node.getRootNode() as ShadowRoot).host
} else {
node = node.parentElement
}
}
return true
}

export function isSupported(): boolean {
return 'checkVisibility' in Element.prototype && typeof Element.prototype.checkVisibility === 'function'
}

export function isPolyfilled(): boolean {
return Element.prototype.checkVisibility === checkVisibility
}

export function apply(): void {
if (!isSupported()) {
Element.prototype.checkVisibility = checkVisibility
}
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as arrayAt from './arraylike-at.js'
import * as clipboardItem from './clipboarditem.js'
import * as cryptoRandomUUID from './crypto-randomuuid.js'
import * as elementReplaceChildren from './element-replacechildren.js'
import * as elementCheckVisibility from './element-checkvisibility.js'
import * as eventAbortSignal from './event-abortsignal.js'
import * as navigatorClipboard from './navigator-clipboard.js'
import * as formRequestSubmit from './form-requestsubmit.js'
Expand Down Expand Up @@ -62,6 +63,7 @@ export const polyfills = {
arrayAt,
clipboardItem,
cryptoRandomUUID,
elementCheckVisibility,
elementReplaceChildren,
eventAbortSignal,
navigatorClipboard,
Expand Down
95 changes: 95 additions & 0 deletions test/element-checkvisibility.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {apply, isPolyfilled, isSupported, checkVisibility} from '../lib/element-checkvisibility.js'

describe('checkVisibility', () => {
it('has standard isSupported, isPolyfilled, apply API', () => {
expect(isSupported).to.be.a('function')
expect(isPolyfilled).to.be.a('function')
expect(apply).to.be.a('function')
expect(isSupported()).to.be.a('boolean')
expect(isPolyfilled()).to.equal(false)
})

it.only('checks visibility of elements', async () => {

Check failure on line 12 in test/element-checkvisibility.js

View workflow job for this annotation

GitHub Actions / build

it.only not permitted
// These tests originate from
// https://github.com/web-platform-tests/wpt/blob/master/css/cssom-view/checkVisibility.html
const el = document.createElement('div')
// eslint-disable-next-line github/no-inner-html
el.innerHTML = `
<div id=visibilityhidden style="visibility:hidden">hello</div>
<div style="content-visibility:hidden">
<div id=cvhidden>hello</div>
</div>
<div style="content-visibility:auto">
<div id=cvauto>hello</div>
</div>
<div id=displaynone style="display:none">hello</div>
<div style="display:none" class="shadow-host-with-slot">
<div id="slottedindisplaynone" slot="slot">slotted</div>
</div>
<div id=displaycontents style="display:contents">
<div id=displaycontentschild>hello</div>
</div>
<div id=opacityzero style="opacity:0">hello</div>
<div style="opacity:0" class="shadow-host-with-slot">
<div id="slottedinopacityzero" slot="slot">slotted</div>
</div>
<div style="content-visibility:hidden">
<div id=cvhiddenchildwithupdate></div>
</div>
<div style="content-visibility:hidden" id=cvhiddenwithupdate></div>
<div style="content-visibility:hidden" class="shadow-host-with-slot">
<div id="slottedincvhidden" slot="slot">slotted</div>
</div>
<div style="height:10000px">spacer</div>
<div style="content-visibility:auto">
<div id=cvautooffscreen>hello</div>
</div>
<div id=cvautocontainer>
<div id=cvautochild></div>
</div>
<div style="content-visibility:auto">
<div style="content-visibility:auto">
<div id=nestedcvautochild></div>
</div>
`
document.body.append(el)
for (const host of document.querySelectorAll('.shadow-host-with-slot')) {
const shadowRoot = host.attachShadow({mode: 'open'})
const slot = document.createElement('slot')
slot.name = 'slot'
shadowRoot.appendChild(slot)
}
expect(checkVisibility.call(document.getElementById('visibilityhidden'), {checkVisibilityCSS: true})).to.equal(
false

Check failure on line 63 in test/element-checkvisibility.js

View workflow job for this annotation

GitHub Actions / build

Insert `,`
)
expect(checkVisibility.call(document.getElementById('visibilityhidden'), {checkVisibilityCSS: false})).to.equal(
true

Check failure on line 66 in test/element-checkvisibility.js

View workflow job for this annotation

GitHub Actions / build

Insert `,`
)
expect(checkVisibility.call(document.getElementById('cvhidden'))).to.equal(false)
expect(checkVisibility.call(document.getElementById('slottedincvhidden'))).to.equal(false)
expect(checkVisibility.call(document.getElementById('cvauto'))).to.equal(true)
expect(checkVisibility.call(document.getElementById('cvautooffscreen'))).to.equal(true)
expect(checkVisibility.call(document.getElementById('displaynone'))).to.equal(false)
expect(checkVisibility.call(document.getElementById('slottedindisplaynone'))).to.equal(false)
expect(checkVisibility.call(document.getElementById('displaycontents'))).to.equal(false)
expect(checkVisibility.call(document.getElementById('displaycontentschild'))).to.equal(true)
expect(checkVisibility.call(document.getElementById('opacityzero'), {checkOpacity: true})).to.equal(false)
expect(checkVisibility.call(document.getElementById('opacityzero'), {checkOpacity: false})).to.equal(true)
expect(checkVisibility.call(document.getElementById('slottedinopacityzero'), {checkOpacity: true})).to.equal(false)
expect(checkVisibility.call(document.getElementById('slottedinopacityzero'), {checkOpacity: false})).to.equal(true)
const cvautocontainer = document.getElementById('cvautocontainer')
const cvautochild = document.getElementById('cvautochild')
cvautocontainer.style.contentVisibility = 'auto'
cvautochild.style.visibility = 'hidden'
expect(checkVisibility.call(cvautochild, {checkVisibilityCSS: true})).to.equal(false)
cvautochild.style.visibility = 'visible'
expect(checkVisibility.call(cvautochild, {checkVisibilityCSS: true})).to.equal(true)
expect(checkVisibility.call(document.getElementById('nestedcvautochild'))).to.equal(true)
const cvhiddenchildwithupdate = document.getElementById('cvhiddenchildwithupdate')
cvhiddenchildwithupdate.getBoundingClientRect()
expect(checkVisibility.call(cvhiddenchildwithupdate)).to.equal(false)
const cvhiddenwithupdate = document.getElementById('cvhiddenwithupdate')
cvhiddenwithupdate.getBoundingClientRect()
expect(checkVisibility.call(cvhiddenwithupdate)).to.equal(true)
})
})

0 comments on commit caa52c6

Please sign in to comment.