UNPKG

3.66 kBJavaScriptView Raw
1import mediumZoom from 'medium-zoom'
2
3const camelCased = string =>
4 string.replace(/-([a-z])/g, g => g[1].toUpperCase())
5
6const template = document.createElement('template')
7template.innerHTML = `
8<style>
9 :host {
10 display: block;
11 }
12 img {
13 max-width: 100%;
14 }
15 .medium-zoom-image {
16 cursor: zoom-in;
17 }
18</style>
19<img />
20`
21
22export default class MediumZoom extends HTMLElement {
23 static get observedOptions() {
24 return [
25 'margin',
26 'background',
27 'scroll-offset',
28 'disable-metaclick',
29 'zoom-target'
30 ]
31 }
32
33 static get observedAttributes() {
34 return [
35 ...MediumZoom.observedOptions,
36 'src',
37 'alt',
38 'width',
39 'height',
40 'style'
41 ]
42 }
43
44 static getOptionName(value) {
45 return value === 'disable-metaclick' ? 'metaClick' : camelCased(value)
46 }
47
48 constructor() {
49 super()
50
51 this.attachShadow({ mode: 'open' })
52 this.shadowRoot.appendChild(template.content.cloneNode(true))
53 this.image = this.shadowRoot.querySelector('img')
54 this.zoom = mediumZoom(this.image)
55
56 // Attach all zoom methods to the component
57 Object.keys(this.zoom).forEach(method => (this[method] = this.zoom[method]))
58
59 // Add accessibility attributes to the component
60 this.setAttribute('role', 'img')
61 this.setAttribute('aria-label', this.alt)
62 }
63
64 disconnectedCallback() {
65 this.zoom.detach()
66 }
67
68 adoptedCallback() {
69 this.zoom.hide()
70 }
71
72 attributeChangedCallback(name, oldValue, newValue) {
73 if (MediumZoom.observedOptions.includes(name)) {
74 if (name === 'zoom-target') {
75 this.image.setAttribute('data-zoom-target', newValue)
76 return
77 }
78
79 this.zoom.update({
80 [MediumZoom.getOptionName(name)]: this[MediumZoom.getOptionName(name)]
81 })
82 } else {
83 // Attach all DOM attributes to the image
84 this.image.setAttribute(name, newValue)
85 }
86 }
87
88 get src() {
89 return this.getAttribute('src') || ''
90 }
91
92 set src(value) {
93 this.setAttribute('src', value)
94 }
95
96 get alt() {
97 return this.getAttribute('alt') || ''
98 }
99
100 set alt(value) {
101 this.setAttribute('alt', value)
102 }
103
104 get zoomTarget() {
105 return this.getAttribute('zoom-target') || ''
106 }
107
108 set zoomTarget(value) {
109 value
110 ? this.setAttribute('zoom-target', value)
111 : this.removeAttribute('zoom-target')
112 }
113
114 get width() {
115 return this.getAttribute('width') || ''
116 }
117
118 set width(value) {
119 value ? this.setAttribute('width', value) : this.removeAttribute('width')
120 }
121
122 get height() {
123 return this.getAttribute('height') || ''
124 }
125
126 set height(value) {
127 value ? this.setAttribute('height', value) : this.removeAttribute('height')
128 }
129
130 get margin() {
131 return Number(this.getAttribute('margin')) || ''
132 }
133
134 set margin(value) {
135 value ? this.setAttribute('margin', value) : this.removeAttribute('margin')
136 }
137
138 get background() {
139 return this.getAttribute('background') || ''
140 }
141
142 set background(value) {
143 value
144 ? this.setAttribute('background', value)
145 : this.removeAttribute('background')
146 }
147
148 get scrollOffset() {
149 return this.hasAttribute('scroll-offset')
150 ? Number(this.getAttribute('scroll-offset'))
151 : ''
152 }
153
154 set scrollOffset(value) {
155 value !== null
156 ? this.setAttribute('scroll-offset', Number(value))
157 : this.removeAttribute('scroll-offset')
158 }
159
160 get metaClick() {
161 return !this.hasAttribute('disable-metaclick')
162 }
163
164 set metaClick(value) {
165 value
166 ? this.setAttribute('disable-metaclick', value)
167 : this.removeAttribute('disable-metaclick')
168 }
169}
170
171window.customElements.define('medium-zoom', MediumZoom)