@zeix/ui-element
Version:
UIElement - minimal reactive framework based on Web Components
124 lines (101 loc) • 4.18 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Context Tests</title>
</head>
<body>
<motion-context>
<my-animation>
<h1>Reduced Motion: <span>Unknown to Server</span></h1>
</my-animation>
</motion-context>
<user-context display-name="Jane Doe">
<hello-world>
<h1>Hello, <span>World</span>!</h1>
</hello-world>
</user-context>
<script type="module">
import { runTests } from '@web/test-runner-mocha'
import { assert } from '@esm-bundle/chai'
import { UIElement, useContext, setText } from '../index.js'
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
const animationFrame = async () => new Promise(requestAnimationFrame)
const normalizeText = text => text.replace(/\s+/g, ' ').trim()
class MotionContext extends UIElement {
static providedContexts = ['reduced-motion']
connectedCallback() {
useContext(this)
const mql = matchMedia('(prefers-reduced-motion)')
this.set('reduced-motion', mql.matches)
mql.onchange = e => this.set('reduced-motion', e.matches)
}
}
MotionContext.define('motion-context')
class MyAnimation extends UIElement {
static consumedContexts = ['reduced-motion']
connectedCallback() {
useContext(this)
this.first('span').sync(setText('reduced-motion'))
}
}
MyAnimation.define('my-animation')
class UserContext extends UIElement {
static observedAttributes = ['display-name']
static providedContexts = ['display-name']
connectedCallback() {
useContext(this)
}
}
UserContext.define('user-context')
class HelloWorld extends UIElement {
static consumedContexts = ['display-name']
connectedCallback() {
useContext(this)
this.first('span').sync(setText('display-name'))
}
}
HelloWorld.define('hello-world')
runTests(() => {
describe('Context provider', function () {
it('should have static providedContexts', async function () {
assert.deepEqual(MotionContext.providedContexts, ['reduced-motion'])
})
it('should have display-name signal from attribute', async function () {
assert.equal(document.querySelector('user-context').get('display-name'), 'Jane Doe')
})
})
describe('Context consumer', function () {
it('should have static consumedContexts', async function () {
assert.deepEqual(MyAnimation.consumedContexts, ['reduced-motion'])
})
it('should update according to consumed context', async function () {
const contextConsumer = document.querySelector('my-animation')
await animationFrame()
const textContent = normalizeText(contextConsumer.querySelector('h1').textContent)
assert.equal(textContent, `Reduced Motion: ${matchMedia('(prefers-reduced-motion)').matches}`, 'Should have updated heading from context')
})
it('should update when context is set', async function () {
const contextProvider = document.querySelector('user-context')
const contextConsumer = document.querySelector('hello-world')
await animationFrame()
let textContent = normalizeText(contextConsumer.querySelector('span').textContent)
assert.equal(textContent, 'Jane Doe', 'Should update heading from initial display-name context')
contextProvider.set('display-name', 'Esther Brunner')
await animationFrame()
textContent = normalizeText(contextConsumer.querySelector('span').textContent)
assert.equal(textContent, 'Esther Brunner', 'Should update heading from setting display-name context')
})
it('should revert when context is removed', async function () {
const contextProvider = document.querySelector('user-context')
const contextConsumer = document.querySelector('hello-world')
contextProvider.removeAttribute('display-name')
await animationFrame()
const textContent = normalizeText(contextConsumer.querySelector('span').textContent)
assert.equal(textContent, 'World', 'Should revert heading from context')
})
})
})
</script>
</body>
</html>