viewerjs 1.11.9 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/js/methods.js CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  EVENT_CLICK,
13
13
  EVENT_ERROR,
14
14
  EVENT_HIDE,
15
+ EVENT_KEY_DOWN,
15
16
  EVENT_LOAD,
16
17
  EVENT_MOVE,
17
18
  EVENT_MOVED,
@@ -40,9 +41,11 @@ import {
40
41
  getOffset,
41
42
  getPointersCenter,
42
43
  hasClass,
44
+ inheritAttributes,
43
45
  isFunction,
44
46
  isNumber,
45
47
  isPlainObject,
48
+ isTransitionEnabled,
46
49
  isUndefined,
47
50
  removeClass,
48
51
  removeListener,
@@ -97,7 +100,7 @@ export default {
97
100
  viewer.setAttribute('aria-modal', true);
98
101
  viewer.removeAttribute('aria-hidden');
99
102
 
100
- if (options.transition && !immediate) {
103
+ if (isTransitionEnabled(options, 'show') && !immediate) {
101
104
  const shown = this.shown.bind(this);
102
105
 
103
106
  this.transitioning = {
@@ -141,7 +144,7 @@ export default {
141
144
  });
142
145
  }
143
146
 
144
- if (dispatchEvent(element, EVENT_HIDE) === false) {
147
+ if (dispatchEvent(element, EVENT_HIDE) === false || this.destroyed) {
145
148
  return this;
146
149
  }
147
150
 
@@ -163,7 +166,7 @@ export default {
163
166
  this.hidden();
164
167
  };
165
168
 
166
- if (options.transition && !immediate) {
169
+ if (isTransitionEnabled(options, 'hide') && !immediate) {
167
170
  const onViewerTransitionEnd = (event) => {
168
171
  // Ignore all propagating `transitionend` events (#275).
169
172
  if (event && event.target === viewer) {
@@ -214,10 +217,12 @@ export default {
214
217
  * @returns {Viewer} this
215
218
  */
216
219
  view(index = this.options.initialViewIndex) {
220
+ const previousIndex = this.index;
221
+
217
222
  index = Number(index) || 0;
218
223
 
219
224
  if (this.hiding || this.played || index < 0 || index >= this.length
220
- || (this.viewed && index === this.index)) {
225
+ || (this.viewed && index === previousIndex)) {
221
226
  return this;
222
227
  }
223
228
 
@@ -236,20 +241,19 @@ export default {
236
241
  title,
237
242
  canvas,
238
243
  } = this;
239
- const item = this.items[index];
244
+ let item = this.getItem(index);
245
+
246
+ if (!item) {
247
+ this.initList(index);
248
+ item = this.getItem(index);
249
+ }
250
+
240
251
  const img = item.querySelector('img');
241
252
  const url = getData(img, 'originalUrl');
242
253
  const alt = img.getAttribute('alt');
243
254
  const image = document.createElement('img');
244
255
 
245
- forEach(options.inheritedAttributes, (name) => {
246
- const value = img.getAttribute(name);
247
-
248
- if (value !== null) {
249
- image.setAttribute(name, value);
250
- }
251
- });
252
-
256
+ inheritAttributes(image, img, options.inheritedAttributes);
253
257
  image.src = url;
254
258
  image.alt = alt;
255
259
 
@@ -267,7 +271,9 @@ export default {
267
271
  return this;
268
272
  }
269
273
 
270
- const activeItem = this.items[this.index];
274
+ this.hideMagnifier();
275
+
276
+ const activeItem = this.getItem(previousIndex);
271
277
 
272
278
  if (activeItem) {
273
279
  removeClass(activeItem, CLASS_ACTIVE);
@@ -308,6 +314,28 @@ export default {
308
314
  title.innerHTML = escapeHTMLEntities(isFunction(render)
309
315
  ? render.call(this, image, imageData)
310
316
  : `${alt} (${imageData.naturalWidth} × ${imageData.naturalHeight})`);
317
+
318
+ // Preload the image in the direction of navigation
319
+ if (options.preload) {
320
+ const direction = index < previousIndex ? -1 : 1;
321
+ let nextIndex = index + direction;
322
+
323
+ if (nextIndex < 0 || nextIndex >= this.length) {
324
+ if (options.loop) {
325
+ nextIndex = direction > 0 ? 0 : this.length - 1;
326
+ } else {
327
+ nextIndex = -1;
328
+ }
329
+ }
330
+
331
+ if (nextIndex !== index) {
332
+ const nextImage = this.images[nextIndex];
333
+ const preloadedImage = document.createElement('img');
334
+
335
+ inheritAttributes(preloadedImage, nextImage, options.inheritedAttributes);
336
+ preloadedImage.src = this.getImageURL(nextImage) || nextImage.src;
337
+ }
338
+ }
311
339
  };
312
340
  let onLoad;
313
341
  let onError;
@@ -481,6 +509,7 @@ export default {
481
509
  imageData.y = y;
482
510
  imageData.left = x;
483
511
  imageData.top = y;
512
+ toggleClass(this.image, CLASS_TRANSITION, isTransitionEnabled(options, 'move'));
484
513
  this.moving = true;
485
514
  this.renderImage(() => {
486
515
  this.moving = false;
@@ -545,6 +574,7 @@ export default {
545
574
  }
546
575
 
547
576
  imageData.rotate = degree;
577
+ toggleClass(this.image, CLASS_TRANSITION, isTransitionEnabled(options, 'rotate'));
548
578
  this.rotating = true;
549
579
  this.renderImage(() => {
550
580
  this.rotating = false;
@@ -636,6 +666,7 @@ export default {
636
666
 
637
667
  imageData.scaleX = scaleX;
638
668
  imageData.scaleY = scaleY;
669
+ toggleClass(this.image, CLASS_TRANSITION, isTransitionEnabled(options, 'scale'));
639
670
  this.scaling = true;
640
671
  this.renderImage(() => {
641
672
  this.scaling = false;
@@ -719,8 +750,12 @@ export default {
719
750
 
720
751
  if (isNumber(ratio) && this.viewed && !this.played && (_zoomable || options.zoomable)) {
721
752
  if (!_zoomable) {
722
- const minZoomRatio = Math.max(0.01, options.minZoomRatio);
723
- const maxZoomRatio = Math.min(100, options.maxZoomRatio);
753
+ const minZoomRatio = Math.max(0.01, isFunction(options.minZoomRatio)
754
+ ? options.minZoomRatio.call(this, this.image, imageData)
755
+ : options.minZoomRatio);
756
+ const maxZoomRatio = Math.min(100, isFunction(options.maxZoomRatio)
757
+ ? options.maxZoomRatio.call(this, this.image, imageData)
758
+ : options.maxZoomRatio);
724
759
 
725
760
  ratio = Math.min(Math.max(ratio, minZoomRatio), maxZoomRatio);
726
761
  }
@@ -794,6 +829,7 @@ export default {
794
829
  imageData.height = newHeight;
795
830
  imageData.oldRatio = oldRatio;
796
831
  imageData.ratio = ratio;
832
+ toggleClass(this.image, CLASS_TRANSITION, isTransitionEnabled(options, 'zoom'));
797
833
  this.renderImage(() => {
798
834
  this.zooming = false;
799
835
 
@@ -856,18 +892,17 @@ export default {
856
892
  }
857
893
 
858
894
  addClass(player, CLASS_SHOW);
859
- forEach(this.items, (item, i) => {
860
- const img = item.querySelector('img');
895
+ forEach(this.images, (originalImage, i) => {
861
896
  const image = document.createElement('img');
862
897
 
863
- image.src = getData(img, 'originalUrl');
864
- image.alt = img.getAttribute('alt');
865
- image.referrerPolicy = img.referrerPolicy;
898
+ image.src = this.getImageURL(originalImage) || originalImage.src;
899
+ image.alt = originalImage.alt || '';
900
+ image.referrerPolicy = originalImage.referrerPolicy;
866
901
  total += 1;
867
902
  addClass(image, CLASS_FADE);
868
- toggleClass(image, CLASS_TRANSITION, options.transition);
903
+ toggleClass(image, CLASS_TRANSITION, isTransitionEnabled(options, 'play'));
869
904
 
870
- if (hasClass(item, CLASS_ACTIVE)) {
905
+ if (i === this.index) {
871
906
  addClass(image, CLASS_IN);
872
907
  index = i;
873
908
  }
@@ -886,7 +921,7 @@ export default {
886
921
  index -= 1;
887
922
  index = index >= 0 ? index : total - 1;
888
923
  addClass(list[index], CLASS_IN);
889
- this.playing.timeout = setTimeout(prev, options.interval);
924
+ this.playing.timeout = options.autoplay ? setTimeout(prev, options.interval) : null;
890
925
  };
891
926
  const next = () => {
892
927
  clearTimeout(this.playing.timeout);
@@ -894,14 +929,14 @@ export default {
894
929
  index += 1;
895
930
  index = index < total ? index : 0;
896
931
  addClass(list[index], CLASS_IN);
897
- this.playing.timeout = setTimeout(next, options.interval);
932
+ this.playing.timeout = options.autoplay ? setTimeout(next, options.interval) : null;
898
933
  };
899
934
 
900
935
  if (total > 1) {
901
936
  this.playing = {
902
937
  prev,
903
938
  next,
904
- timeout: setTimeout(next, options.interval),
939
+ timeout: options.autoplay ? setTimeout(next, options.interval) : null,
905
940
  };
906
941
  }
907
942
  }
@@ -959,12 +994,10 @@ export default {
959
994
  this.open();
960
995
  addClass(this.button, CLASS_FULLSCREEN_EXIT);
961
996
 
962
- if (options.transition) {
963
- removeClass(list, CLASS_TRANSITION);
997
+ removeClass(list, CLASS_TRANSITION);
964
998
 
965
- if (this.viewed) {
966
- removeClass(image, CLASS_TRANSITION);
967
- }
999
+ if (this.viewed) {
1000
+ removeClass(image, CLASS_TRANSITION);
968
1001
  }
969
1002
 
970
1003
  addClass(viewer, CLASS_FIXED);
@@ -986,14 +1019,7 @@ export default {
986
1019
 
987
1020
  if (this.viewed) {
988
1021
  this.initImage(() => {
989
- this.renderImage(() => {
990
- if (options.transition) {
991
- setTimeout(() => {
992
- addClass(image, CLASS_TRANSITION);
993
- addClass(list, CLASS_TRANSITION);
994
- }, 0);
995
- }
996
- });
1022
+ this.renderImage();
997
1023
  });
998
1024
  }
999
1025
 
@@ -1017,12 +1043,10 @@ export default {
1017
1043
  this.close();
1018
1044
  removeClass(this.button, CLASS_FULLSCREEN_EXIT);
1019
1045
 
1020
- if (options.transition) {
1021
- removeClass(list, CLASS_TRANSITION);
1046
+ removeClass(list, CLASS_TRANSITION);
1022
1047
 
1023
- if (this.viewed) {
1024
- removeClass(image, CLASS_TRANSITION);
1025
- }
1048
+ if (this.viewed) {
1049
+ removeClass(image, CLASS_TRANSITION);
1026
1050
  }
1027
1051
 
1028
1052
  if (options.focus) {
@@ -1043,14 +1067,7 @@ export default {
1043
1067
 
1044
1068
  if (this.viewed) {
1045
1069
  this.initImage(() => {
1046
- this.renderImage(() => {
1047
- if (options.transition) {
1048
- setTimeout(() => {
1049
- addClass(image, CLASS_TRANSITION);
1050
- addClass(list, CLASS_TRANSITION);
1051
- }, 0);
1052
- }
1053
- });
1070
+ this.renderImage();
1054
1071
  });
1055
1072
  }
1056
1073
 
@@ -1068,7 +1085,7 @@ export default {
1068
1085
  tooltipBox.textContent = `${Math.round(imageData.ratio * 100)}%`;
1069
1086
 
1070
1087
  if (!this.tooltipping) {
1071
- if (options.transition) {
1088
+ if (isTransitionEnabled(options, 'tooltip')) {
1072
1089
  if (this.fading) {
1073
1090
  dispatchEvent(tooltipBox, EVENT_TRANSITION_END);
1074
1091
  }
@@ -1090,7 +1107,7 @@ export default {
1090
1107
  }
1091
1108
 
1092
1109
  this.tooltipping = setTimeout(() => {
1093
- if (options.transition) {
1110
+ if (isTransitionEnabled(options, 'tooltip')) {
1094
1111
  addListener(tooltipBox, EVENT_TRANSITION_END, () => {
1095
1112
  removeClass(tooltipBox, CLASS_SHOW);
1096
1113
  removeClass(tooltipBox, CLASS_FADE);
@@ -1139,10 +1156,18 @@ export default {
1139
1156
  return this;
1140
1157
  },
1141
1158
 
1142
- // Update viewer when images changed
1143
- update() {
1159
+ /**
1160
+ * Update the viewer when images or options changed.
1161
+ * @param {Object} [updateOptions] - The options to update.
1162
+ * @returns {Viewer} this
1163
+ */
1164
+ update(updateOptions) {
1144
1165
  const { element, options, isImg } = this;
1145
1166
 
1167
+ if (isPlainObject(updateOptions)) {
1168
+ assign(options, updateOptions);
1169
+ }
1170
+
1146
1171
  // Destroy viewer if the target image was deleted
1147
1172
  if (isImg && !element.parentNode) {
1148
1173
  return this.destroy();
@@ -1170,9 +1195,10 @@ export default {
1170
1195
  if (this.ready) {
1171
1196
  const changedIndexes = [];
1172
1197
 
1173
- forEach(this.items, (item, i) => {
1198
+ forEach(this.items, (item) => {
1174
1199
  const img = item.querySelector('img');
1175
- const image = images[i];
1200
+ const index = Number(getData(item, 'index'));
1201
+ const image = images[index];
1176
1202
 
1177
1203
  if (image && img) {
1178
1204
  if (
@@ -1181,10 +1207,10 @@ export default {
1181
1207
  // Title changed (#408)
1182
1208
  || image.alt !== img.alt
1183
1209
  ) {
1184
- changedIndexes.push(i);
1210
+ changedIndexes.push(index);
1185
1211
  }
1186
1212
  } else {
1187
- changedIndexes.push(i);
1213
+ changedIndexes.push(index);
1188
1214
  }
1189
1215
  });
1190
1216
 
@@ -1203,7 +1229,7 @@ export default {
1203
1229
  this.viewed = false;
1204
1230
  this.view(Math.max(Math.min(this.index - changedIndex, this.length - 1), 0));
1205
1231
  } else {
1206
- const activeItem = this.items[this.index];
1232
+ const activeItem = this.getItem(this.index);
1207
1233
 
1208
1234
  // Reactivate the current viewing item after reset the list.
1209
1235
  addClass(activeItem, CLASS_ACTIVE);
@@ -1277,7 +1303,8 @@ export default {
1277
1303
  }
1278
1304
 
1279
1305
  if (!options.inline) {
1280
- removeListener(element, EVENT_CLICK, this.onStart);
1306
+ removeListener(element, EVENT_CLICK, this.onElementClick);
1307
+ removeListener(element, EVENT_KEY_DOWN, this.onElementKeyDown);
1281
1308
  }
1282
1309
 
1283
1310
  element[NAMESPACE] = undefined;
package/src/js/others.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  ACTION_MOVE,
3
+ ACTION_ROTATE,
3
4
  ACTION_SWITCH,
5
+ ACTION_TRANSFORM,
4
6
  ACTION_ZOOM,
5
7
  CLASS_HIDE,
6
8
  CLASS_OPEN,
@@ -13,6 +15,7 @@ import {
13
15
  addListener,
14
16
  dispatchEvent,
15
17
  forEach,
18
+ getMaxRotateDegree,
16
19
  getMaxZoomRatio,
17
20
  isFunction,
18
21
  isPlainObject,
@@ -117,6 +120,12 @@ export default {
117
120
 
118
121
  hidden() {
119
122
  const { element, options, viewer } = this;
123
+ const { activeElement } = viewer.ownerDocument;
124
+
125
+ // Avoid keeping focus inside the dialog before setting `aria-hidden`.
126
+ if (activeElement && viewer.contains(activeElement) && isFunction(activeElement.blur)) {
127
+ activeElement.blur();
128
+ }
120
129
 
121
130
  if (options.focus) {
122
131
  this.clearEnforceFocus();
@@ -150,7 +159,7 @@ export default {
150
159
  },
151
160
 
152
161
  requestFullscreen(options) {
153
- const document = this.element.ownerDocument;
162
+ const { ownerDocument: document } = this;
154
163
 
155
164
  if (this.fulled && !(
156
165
  document.fullscreenElement
@@ -179,7 +188,7 @@ export default {
179
188
  },
180
189
 
181
190
  exitFullscreen() {
182
- const document = this.element.ownerDocument;
191
+ const { ownerDocument: document } = this;
183
192
 
184
193
  if (this.fulled && (
185
194
  document.fullscreenElement
@@ -223,7 +232,43 @@ export default {
223
232
 
224
233
  // Zoom the current image
225
234
  case ACTION_ZOOM:
226
- this.zoom(getMaxZoomRatio(pointers), false, null, event);
235
+ if (options.zoomable && options.zoomOnTouch) {
236
+ const zoomRatio = getMaxZoomRatio(pointers);
237
+
238
+ if (zoomRatio !== 0) {
239
+ this.zoom(zoomRatio, false, null, event);
240
+ }
241
+ }
242
+ break;
243
+
244
+ // Rotate the current image
245
+ case ACTION_ROTATE:
246
+ if (options.rotatable && options.rotateOnTouch) {
247
+ const rotateDegree = getMaxRotateDegree(pointers);
248
+
249
+ if (rotateDegree !== 0) {
250
+ this.rotate(rotateDegree, event);
251
+ }
252
+ }
253
+ break;
254
+
255
+ // Transform the current image
256
+ case ACTION_TRANSFORM:
257
+ if (options.zoomable && options.zoomOnTouch) {
258
+ const zoomRatio = getMaxZoomRatio(pointers);
259
+
260
+ if (zoomRatio !== 0) {
261
+ this.zoom(zoomRatio, false, null, event);
262
+ }
263
+ }
264
+
265
+ if (options.rotatable && options.rotateOnTouch) {
266
+ const rotateDegree = getMaxRotateDegree(pointers);
267
+
268
+ if (rotateDegree !== 0) {
269
+ this.rotate(rotateDegree, event);
270
+ }
271
+ }
227
272
  break;
228
273
 
229
274
  case ACTION_SWITCH: {
package/src/js/render.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ CLASS_ACTIVE,
2
3
  CLASS_LOADING,
3
4
  CLASS_TRANSITION,
4
5
  EVENT_ERROR,
@@ -11,11 +12,15 @@ import {
11
12
  addListener,
12
13
  assign,
13
14
  forEach,
15
+ getData,
14
16
  getImageNameFromURL,
15
17
  getImageNaturalSizes,
16
18
  getTransforms,
17
19
  hasClass,
20
+ inheritAttributes,
18
21
  isNumber,
22
+ isPlainObject,
23
+ isTransitionEnabled,
19
24
  removeClass,
20
25
  removeListener,
21
26
  setData,
@@ -31,7 +36,7 @@ export default {
31
36
  },
32
37
 
33
38
  initBody() {
34
- const { ownerDocument } = this.element;
39
+ const { ownerDocument } = this;
35
40
  const body = ownerDocument.body || ownerDocument.documentElement;
36
41
 
37
42
  this.body = body;
@@ -73,14 +78,41 @@ export default {
73
78
  }
74
79
  },
75
80
 
76
- initList() {
81
+ initList(viewIndex = this.index) {
77
82
  const { element, options, list } = this;
78
83
  const items = [];
84
+ const navbarOptions = isPlainObject(options.navbar) ? options.navbar : {};
85
+ const probe = document.createElement('li');
86
+
87
+ list.appendChild(probe);
88
+ const itemWidth = probe.offsetWidth + parseInt(window.getComputedStyle(probe).marginLeft, 10);
89
+
90
+ list.removeChild(probe);
91
+
92
+ let visibleItemCount = isNumber(navbarOptions.visibleItemCount)
93
+ ? Math.floor(navbarOptions.visibleItemCount)
94
+ : Math.floor(this.containerData.width / itemWidth);
95
+
96
+ visibleItemCount = Math.min(visibleItemCount, this.length);
97
+
98
+ const start = visibleItemCount > 0
99
+ ? Math.min(
100
+ Math.max(0, viewIndex - Math.floor(visibleItemCount / 2)),
101
+ Math.max(0, this.length - visibleItemCount),
102
+ )
103
+ : 0;
104
+ const end = visibleItemCount > 0
105
+ ? Math.min(this.length, start + visibleItemCount)
106
+ : this.length;
79
107
 
80
108
  // initList may be called in this.update, so should keep idempotent
81
109
  list.innerHTML = '';
82
110
 
83
111
  forEach(this.images, (image, index) => {
112
+ if (visibleItemCount > 0 && (index < start || index >= end)) {
113
+ return;
114
+ }
115
+
84
116
  const { src } = image;
85
117
  const alt = image.alt || getImageNameFromURL(src);
86
118
  const url = this.getImageURL(image);
@@ -89,13 +121,7 @@ export default {
89
121
  const item = document.createElement('li');
90
122
  const img = document.createElement('img');
91
123
 
92
- forEach(options.inheritedAttributes, (name) => {
93
- const value = image.getAttribute(name);
94
-
95
- if (value !== null) {
96
- img.setAttribute(name, value);
97
- }
98
- });
124
+ inheritAttributes(img, image, options.inheritedAttributes);
99
125
 
100
126
  if (options.navbar) {
101
127
  img.src = src || url;
@@ -119,6 +145,15 @@ export default {
119
145
 
120
146
  this.items = items;
121
147
 
148
+ if (this.viewed) {
149
+ const activeItem = this.getItem(this.index);
150
+
151
+ if (activeItem) {
152
+ addClass(activeItem, CLASS_ACTIVE);
153
+ activeItem.setAttribute('aria-selected', true);
154
+ }
155
+ }
156
+
122
157
  forEach(items, (item) => {
123
158
  const image = item.firstElementChild;
124
159
  let onLoad;
@@ -152,7 +187,7 @@ export default {
152
187
  });
153
188
  });
154
189
 
155
- if (options.transition) {
190
+ if (isTransitionEnabled(options, 'view')) {
156
191
  addListener(element, EVENT_VIEWED, () => {
157
192
  addClass(list, CLASS_TRANSITION);
158
193
  }, {
@@ -161,9 +196,24 @@ export default {
161
196
  }
162
197
  },
163
198
 
199
+ getItem(index) {
200
+ let item;
201
+
202
+ forEach(this.items, (candidate) => {
203
+ if (Number(getData(candidate, 'index')) === index) {
204
+ item = candidate;
205
+ return false;
206
+ }
207
+
208
+ return true;
209
+ });
210
+
211
+ return item;
212
+ },
213
+
164
214
  renderList() {
165
215
  const { index } = this;
166
- const item = this.items[index];
216
+ const item = this.getItem(index);
167
217
 
168
218
  if (!item) {
169
219
  return;
@@ -176,9 +226,9 @@ export default {
176
226
 
177
227
  // Place the active item in the center of the screen
178
228
  setStyle(this.list, assign({
179
- width: outerWidth * this.length - gutter,
229
+ width: outerWidth * this.items.length - gutter,
180
230
  }, getTransforms({
181
- translateX: ((this.viewerData.width - offsetWidth) / 2) - outerWidth * index,
231
+ translateX: ((this.viewerData.width - offsetWidth) / 2) - item.offsetLeft,
182
232
  })));
183
233
  },
184
234
 
@@ -277,9 +327,27 @@ export default {
277
327
  marginTop: imageData.y,
278
328
  }, getTransforms(imageData)));
279
329
 
330
+ if (this.magnifierPoint) {
331
+ this.renderMagnifier();
332
+ }
333
+
280
334
  if (done) {
281
- if ((this.viewing || this.moving || this.rotating || this.scaling || this.zooming)
282
- && this.options.transition
335
+ let action = false;
336
+
337
+ if (this.viewing) {
338
+ action = 'view';
339
+ } else if (this.moving) {
340
+ action = 'move';
341
+ } else if (this.rotating) {
342
+ action = 'rotate';
343
+ } else if (this.scaling) {
344
+ action = 'scale';
345
+ } else if (this.zooming) {
346
+ action = 'zoom';
347
+ }
348
+
349
+ if (action
350
+ && isTransitionEnabled(this.options, action)
283
351
  && hasClass(image, CLASS_TRANSITION)) {
284
352
  const onTransitionEnd = () => {
285
353
  this.imageRendering = false;
@@ -1,6 +1,13 @@
1
1
  export default (
2
2
  '<div class="viewer-container" tabindex="-1" touch-action="none">'
3
3
  + '<div class="viewer-canvas"></div>'
4
+ + '<div class="viewer-magnifier" aria-hidden="true">'
5
+ + '<img class="viewer-magnifier-image" alt="">'
6
+ + '</div>'
7
+ + '<div class="viewer-navigation">'
8
+ + '<div class="viewer-prev" data-viewer-action="prev" role="button" aria-label="Previous"></div>'
9
+ + '<div class="viewer-next" data-viewer-action="next" role="button" aria-label="Next"></div>'
10
+ + '</div>'
4
11
  + '<div class="viewer-footer">'
5
12
  + '<div class="viewer-title"></div>'
6
13
  + '<div class="viewer-toolbar"></div>'