diff --git a/src/components/prop-viewer.js b/src/components/prop-viewer.js new file mode 100644 index 0000000..9e41e22 --- /dev/null +++ b/src/components/prop-viewer.js @@ -0,0 +1,22 @@ +export class PropViewer extends HTMLElement { + constructor() { super(); this._src = ''; this._label = ''; } + connectedCallback() { if (!this.hasAttribute('hidden')) this.setAttribute('hidden', ''); this.render(); } + + isOpen() { return !this.hasAttribute('hidden'); } + + show(src, label = '') { + this._src = src; this._label = label; + this.removeAttribute('hidden'); + this.render(); + } + dismiss() { this.setAttribute('hidden', ''); } + + render() { + this.innerHTML = ` +
+ ${this._label} +
`; + this.querySelector('[data-role=overlay]').addEventListener('click', () => this.dismiss()); + } +} +customElements.define('prop-viewer', PropViewer); diff --git a/tests/components/prop-viewer.test.js b/tests/components/prop-viewer.test.js new file mode 100644 index 0000000..4dddb87 --- /dev/null +++ b/tests/components/prop-viewer.test.js @@ -0,0 +1,29 @@ +import { describe, it, expect, beforeEach } from 'vitest'; +import '../../src/components/prop-viewer.js'; + +describe('', () => { + let el; + beforeEach(() => { + document.body.innerHTML = ''; + el = document.createElement('prop-viewer'); + document.body.appendChild(el); + }); + + it('starts hidden', () => { + expect(el.isOpen()).toBe(false); + expect(el.hasAttribute('hidden')).toBe(true); + }); + + it('shows an image when show() is called', () => { + el.show('/art/rain-pier.png', 'Pier in the rain'); + expect(el.isOpen()).toBe(true); + const img = el.querySelector('[data-role=prop-img]'); + expect(img.getAttribute('src')).toBe('/art/rain-pier.png'); + }); + + it('dismisses when the overlay is clicked', () => { + el.show('/art/x.png', 'x'); + el.querySelector('[data-role=overlay]').click(); + expect(el.isOpen()).toBe(false); + }); +});