Skip to content

Commit

Permalink
Merge pull request #47 from keithamus/add-checkvisibility
Browse files Browse the repository at this point in the history
add checkVisibility
  • Loading branch information
keithamus committed Oct 20, 2023
2 parents 8a87ec7 + a5df092 commit 4389052
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 3 deletions.
29 changes: 26 additions & 3 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<title>GitHub Feature Support Table</title>
<meta charset="utf-8" />
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
<style>
html {
font-family: 'Alliance No.1', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
font-family:
'Alliance No.1',
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Helvetica,
Arial,
sans-serif,
'Apple Color Emoji',
'Segoe UI Emoji',
'Segoe UI Symbol';
font-weight: 400;
line-height: 28px;
}
Expand Down Expand Up @@ -630,6 +639,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
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> = {},
) {
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 @@ -3,6 +3,7 @@ import * as abortSignalTimeout from './abortsignal-timeout.js'
import * as arrayAt from './arraylike-at.js'
import * as clipboardItem from './clipboarditem.js'
import * as cryptoRandomUUID from './crypto-randomuuid.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 @@ -58,6 +59,7 @@ export const polyfills = {
arrayAt,
clipboardItem,
cryptoRandomUUID,
elementCheckVisibility,
eventAbortSignal,
navigatorClipboard,
formRequestSubmit,
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('checks visibility of elements', async () => {
// 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,
)
expect(checkVisibility.call(document.getElementById('visibilityhidden'), {checkVisibilityCSS: false})).to.equal(
true,
)
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 4389052

Please sign in to comment.