smartphoto 2.1.4 → 2.1.7

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/lib/smartphoto.js CHANGED
@@ -132,7 +132,7 @@ var defaults = {
132
132
  loadOffset: 2,
133
133
  resizeStyle: "fit",
134
134
  lazyAttribute: "data-src",
135
- animationSpeed: 300
135
+ animationSpeed: 450
136
136
  };
137
137
  function deepFreeze(obj) {
138
138
  Object.keys(obj).forEach((key) => {
@@ -146,7 +146,11 @@ function deepFreeze(obj) {
146
146
  function createState(settings) {
147
147
  return {
148
148
  options: deepFreeze(
149
- extend({}, defaults, settings)
149
+ extend(
150
+ {},
151
+ defaults,
152
+ settings
153
+ )
150
154
  ),
151
155
  viewer: {
152
156
  isOpen: false,
@@ -806,6 +810,7 @@ function createView({ id, options }, handlers, { signal }) {
806
810
  const dialog = document.createElement("dialog");
807
811
  dialog.className = classNames.smartPhoto;
808
812
  dialog.setAttribute("aria-labelledby", `smartphoto-${id}-title`);
813
+ dialog.style.display = "none";
809
814
  dialog.style.setProperty(
810
815
  "--smartphoto-animation-speed",
811
816
  `${options.animationSpeed}ms`
@@ -1146,6 +1151,44 @@ var SmartPhoto = class {
1146
1151
  this.timeouts = [];
1147
1152
  this.loadAllFired = /* @__PURE__ */ new Set();
1148
1153
  this.syncedGroupId = null;
1154
+ // 文字列セレクタで構築された場合のみ設定される。Ajax等で後から追加された
1155
+ // 要素をクリック時に動的検出するための再スキャン起点(§discoverGroupElements)
1156
+ this.rootSelector = null;
1157
+ // クリックされた要素(またはその祖先)から登録済み Item を逆引きするための
1158
+ // キャッシュ。documentへのイベントデリゲーションで祖先チェーンを辿る際に使う
1159
+ this.itemsByElement = /* @__PURE__ */ new Map();
1160
+ // サムネイルクリックはこの1本の document デリゲーションリスナーだけで処理する
1161
+ // (個別バインドは廃止)。同じクリックイベントを複数の SmartPhoto インスタンスが
1162
+ // 二重処理しないよう、処理済みマーカーをイベント自体に立てて後続インスタンスに
1163
+ // 早期returnさせる(セレクタが重複するインスタンスが同時に存在するケース)
1164
+ this.handleDocumentClick = (e) => {
1165
+ if (!(e.target instanceof Element)) {
1166
+ return;
1167
+ }
1168
+ const marker = e;
1169
+ if (marker.__smartphotoClaimed) {
1170
+ return;
1171
+ }
1172
+ let matched = this.findRegisteredAncestor(e.target);
1173
+ if (!matched && this.rootSelector) {
1174
+ matched = e.target.closest(this.rootSelector);
1175
+ }
1176
+ if (!matched) {
1177
+ return;
1178
+ }
1179
+ e.preventDefault();
1180
+ marker.__smartphotoClaimed = true;
1181
+ if (!this.itemsByElement.has(matched) && this.rootSelector) {
1182
+ const groupId = groupIdFromElement(matched);
1183
+ if (this.resyncGroupFromDom(groupId)) {
1184
+ this.syncCurrentGroupView();
1185
+ }
1186
+ }
1187
+ const item = this.itemsByElement.get(matched);
1188
+ if (item) {
1189
+ this.openPhoto(item, matched);
1190
+ }
1191
+ };
1149
1192
  // ---- 内部: window イベント ----
1150
1193
  this.updateViewportHeight = () => {
1151
1194
  this.view.refs.dialog.style.setProperty(
@@ -1157,6 +1200,7 @@ var SmartPhoto = class {
1157
1200
  if (!currentItems(this.state)) {
1158
1201
  return;
1159
1202
  }
1203
+ this.updateViewportHeight();
1160
1204
  this.resetTranslateCurrent();
1161
1205
  this.setPosByCurrentIndex();
1162
1206
  this.setSizeByScreen();
@@ -1179,6 +1223,7 @@ var SmartPhoto = class {
1179
1223
  if (!currentItems(this.state)) {
1180
1224
  return;
1181
1225
  }
1226
+ this.updateViewportHeight();
1182
1227
  this.resetTranslateCurrent();
1183
1228
  this.setPosByCurrentIndex();
1184
1229
  this.setHashByCurrentIndex();
@@ -1189,6 +1234,7 @@ var SmartPhoto = class {
1189
1234
  const poll = (time) => {
1190
1235
  this.scheduleTimeout(() => {
1191
1236
  if (prevWidth !== getWindowWidth()) {
1237
+ this.updateViewportHeight();
1192
1238
  this.resetTranslateCurrent();
1193
1239
  this.setPosByCurrentIndex();
1194
1240
  this.setHashByCurrentIndex();
@@ -1201,6 +1247,7 @@ var SmartPhoto = class {
1201
1247
  };
1202
1248
  poll(0);
1203
1249
  };
1250
+ this.rootSelector = typeof source === "string" ? source : null;
1204
1251
  this.state = createState(settings ?? {});
1205
1252
  this.view = createView(
1206
1253
  { id: this.id, options: this.state.options },
@@ -1222,15 +1269,14 @@ var SmartPhoto = class {
1222
1269
  },
1223
1270
  { signal: this.abortController.signal }
1224
1271
  );
1272
+ document.addEventListener("click", this.handleDocumentClick, {
1273
+ signal: this.abortController.signal
1274
+ });
1225
1275
  this.ingestSource(source);
1226
1276
  this.syncCurrentGroupView();
1227
1277
  const restored = this.restoreFromHash();
1228
1278
  if (restored) {
1229
- if (restored.element) {
1230
- triggerEvent(restored.element, "click");
1231
- } else {
1232
- this.openPhoto(restored, null);
1233
- }
1279
+ this.openPhoto(restored, restored.element);
1234
1280
  }
1235
1281
  this.updateViewportHeight();
1236
1282
  if (window.visualViewport) {
@@ -1275,6 +1321,7 @@ var SmartPhoto = class {
1275
1321
  clearTimeout(id);
1276
1322
  });
1277
1323
  this.timeouts = [];
1324
+ this.itemsByElement.clear();
1278
1325
  this.gestures.detach();
1279
1326
  this.view.destroy();
1280
1327
  }
@@ -1387,7 +1434,7 @@ var SmartPhoto = class {
1387
1434
  this.gotoSlide(this.state.viewer.prev);
1388
1435
  }
1389
1436
  addItem(slideOrElement) {
1390
- const item = slideOrElement instanceof Element ? this.addElementItem(slideOrElement) : this.addSlideItem(slideOrElement);
1437
+ const item = slideOrElement instanceof HTMLElement ? this.addElementItem(slideOrElement) : this.addSlideItem(slideOrElement);
1391
1438
  this.syncCurrentGroupView();
1392
1439
  return item;
1393
1440
  }
@@ -1418,7 +1465,7 @@ var SmartPhoto = class {
1418
1465
  );
1419
1466
  addItemToGroup(this.state, item);
1420
1467
  this.loadAllFired.delete(groupId);
1421
- this.bindThumbnailClick(element, item);
1468
+ this.itemsByElement.set(element, item);
1422
1469
  return item;
1423
1470
  }
1424
1471
  addSlideItem(slide) {
@@ -1429,15 +1476,72 @@ var SmartPhoto = class {
1429
1476
  this.loadAllFired.delete(groupId);
1430
1477
  return item;
1431
1478
  }
1432
- bindThumbnailClick(element, item) {
1433
- element.addEventListener(
1434
- "click",
1435
- (e) => {
1436
- e.preventDefault();
1437
- this.openPhoto(item, element);
1438
- },
1439
- { signal: this.abortController.signal }
1440
- );
1479
+ // クリックされた要素(またはその祖先。<a><img></a> の img がクリックされる
1480
+ // ケースを含む)から、登録済み Item を持つ要素まで祖先チェーンを遡って探す
1481
+ findRegisteredAncestor(target) {
1482
+ let node = target;
1483
+ while (node) {
1484
+ if (this.itemsByElement.has(node)) {
1485
+ return node;
1486
+ }
1487
+ node = node.parentElement;
1488
+ }
1489
+ return null;
1490
+ }
1491
+ // rootSelector(文字列セレクタで構築した場合のみ設定される)を再スキャンし、
1492
+ // 指定グループを現在のDOM状態に合わせて丸ごと再構築する(追加・削除・並び順の
1493
+ // 変化を一度に反映)。既知要素は既存の Item オブジェクトをそのまま再利用する
1494
+ // ため loaded/width/height は保持され、DOM から消えた要素だけ itemsByElement
1495
+ // からも除去する。index/translateX は resetTranslate() で再計算する。
1496
+ // 呼び出し元(openPhoto)がこの結果を使い、変化があった場合のみ view を
1497
+ // 再同期する(§ダイアログを開く瞬間に整合を取る。開いている間の next()/prev()
1498
+ // では呼ばれないため、この間の追加/削除は次に開き直すまで反映されない)
1499
+ resyncGroupFromDom(groupId) {
1500
+ if (!this.rootSelector) {
1501
+ return false;
1502
+ }
1503
+ const domElements = Array.from(
1504
+ document.querySelectorAll(this.rootSelector)
1505
+ ).filter((el) => groupIdFromElement(el) === groupId);
1506
+ const domElementSet = new Set(domElements);
1507
+ const previous = this.state.groups.get(groupId) ?? [];
1508
+ const previousByElement = /* @__PURE__ */ new Map();
1509
+ previous.forEach((it) => {
1510
+ if (it.element) {
1511
+ previousByElement.set(it.element, it);
1512
+ }
1513
+ });
1514
+ let changed = domElements.length !== previous.length;
1515
+ const rebuilt = domElements.map((el, index) => {
1516
+ const existing = previousByElement.get(el);
1517
+ if (existing) {
1518
+ if (existing.index !== index) {
1519
+ changed = true;
1520
+ existing.index = index;
1521
+ }
1522
+ return existing;
1523
+ }
1524
+ changed = true;
1525
+ const item = itemFromElement(
1526
+ el,
1527
+ this.state.options,
1528
+ index,
1529
+ getWindowWidth()
1530
+ );
1531
+ this.itemsByElement.set(el, item);
1532
+ return item;
1533
+ });
1534
+ previous.forEach((it) => {
1535
+ if (it.element && !domElementSet.has(it.element)) {
1536
+ this.itemsByElement.delete(it.element);
1537
+ }
1538
+ });
1539
+ resetTranslate(rebuilt, getWindowWidth());
1540
+ this.state.groups.set(groupId, rebuilt);
1541
+ if (changed) {
1542
+ this.loadAllFired.delete(groupId);
1543
+ }
1544
+ return changed;
1441
1545
  }
1442
1546
  syncCurrentGroupView() {
1443
1547
  const items = currentItems(this.state);
@@ -1505,10 +1609,12 @@ var SmartPhoto = class {
1505
1609
  syncDialog() {
1506
1610
  const { dialog, caption } = this.view.refs;
1507
1611
  if (this.state.viewer.isOpen && !dialog.open) {
1612
+ dialog.style.removeProperty("display");
1508
1613
  dialog.showModal();
1509
1614
  caption.focus();
1510
1615
  } else if (!this.state.viewer.isOpen && dialog.open) {
1511
1616
  dialog.close();
1617
+ dialog.style.display = "none";
1512
1618
  }
1513
1619
  }
1514
1620
  commit() {
@@ -1691,10 +1797,11 @@ var SmartPhoto = class {
1691
1797
  });
1692
1798
  }
1693
1799
  openPhoto(item, trigger) {
1800
+ const groupChanged = this.rootSelector ? this.resyncGroupFromDom(item.groupId) : false;
1694
1801
  this.lastTriggerElement = trigger;
1695
1802
  this.state.viewer.currentGroup = item.groupId;
1696
1803
  this.state.viewer.currentIndex = item.index;
1697
- if (this.syncedGroupId !== item.groupId) {
1804
+ if (this.syncedGroupId !== item.groupId || groupChanged) {
1698
1805
  this.syncCurrentGroupView();
1699
1806
  }
1700
1807
  this.setHashByCurrentIndex();
@@ -1785,6 +1892,7 @@ var SmartPhoto = class {
1785
1892
  this.state.viewer.photoPosX = 0;
1786
1893
  this.state.viewer.photoPosY = 0;
1787
1894
  this.state.viewer.onMove = true;
1895
+ this.updateViewportHeight();
1788
1896
  this.setPosByCurrentIndex();
1789
1897
  this.setHashByCurrentIndex();
1790
1898
  this.setSizeByScreen();
@@ -106,7 +106,7 @@ var defaults = {
106
106
  loadOffset: 2,
107
107
  resizeStyle: "fit",
108
108
  lazyAttribute: "data-src",
109
- animationSpeed: 300
109
+ animationSpeed: 450
110
110
  };
111
111
  function deepFreeze(obj) {
112
112
  Object.keys(obj).forEach((key) => {
@@ -120,7 +120,11 @@ function deepFreeze(obj) {
120
120
  function createState(settings) {
121
121
  return {
122
122
  options: deepFreeze(
123
- extend({}, defaults, settings)
123
+ extend(
124
+ {},
125
+ defaults,
126
+ settings
127
+ )
124
128
  ),
125
129
  viewer: {
126
130
  isOpen: false,
@@ -780,6 +784,7 @@ function createView({ id, options }, handlers, { signal }) {
780
784
  const dialog = document.createElement("dialog");
781
785
  dialog.className = classNames.smartPhoto;
782
786
  dialog.setAttribute("aria-labelledby", `smartphoto-${id}-title`);
787
+ dialog.style.display = "none";
783
788
  dialog.style.setProperty(
784
789
  "--smartphoto-animation-speed",
785
790
  `${options.animationSpeed}ms`
@@ -1120,6 +1125,44 @@ var SmartPhoto = class {
1120
1125
  this.timeouts = [];
1121
1126
  this.loadAllFired = /* @__PURE__ */ new Set();
1122
1127
  this.syncedGroupId = null;
1128
+ // 文字列セレクタで構築された場合のみ設定される。Ajax等で後から追加された
1129
+ // 要素をクリック時に動的検出するための再スキャン起点(§discoverGroupElements)
1130
+ this.rootSelector = null;
1131
+ // クリックされた要素(またはその祖先)から登録済み Item を逆引きするための
1132
+ // キャッシュ。documentへのイベントデリゲーションで祖先チェーンを辿る際に使う
1133
+ this.itemsByElement = /* @__PURE__ */ new Map();
1134
+ // サムネイルクリックはこの1本の document デリゲーションリスナーだけで処理する
1135
+ // (個別バインドは廃止)。同じクリックイベントを複数の SmartPhoto インスタンスが
1136
+ // 二重処理しないよう、処理済みマーカーをイベント自体に立てて後続インスタンスに
1137
+ // 早期returnさせる(セレクタが重複するインスタンスが同時に存在するケース)
1138
+ this.handleDocumentClick = (e) => {
1139
+ if (!(e.target instanceof Element)) {
1140
+ return;
1141
+ }
1142
+ const marker = e;
1143
+ if (marker.__smartphotoClaimed) {
1144
+ return;
1145
+ }
1146
+ let matched = this.findRegisteredAncestor(e.target);
1147
+ if (!matched && this.rootSelector) {
1148
+ matched = e.target.closest(this.rootSelector);
1149
+ }
1150
+ if (!matched) {
1151
+ return;
1152
+ }
1153
+ e.preventDefault();
1154
+ marker.__smartphotoClaimed = true;
1155
+ if (!this.itemsByElement.has(matched) && this.rootSelector) {
1156
+ const groupId = groupIdFromElement(matched);
1157
+ if (this.resyncGroupFromDom(groupId)) {
1158
+ this.syncCurrentGroupView();
1159
+ }
1160
+ }
1161
+ const item = this.itemsByElement.get(matched);
1162
+ if (item) {
1163
+ this.openPhoto(item, matched);
1164
+ }
1165
+ };
1123
1166
  // ---- 内部: window イベント ----
1124
1167
  this.updateViewportHeight = () => {
1125
1168
  this.view.refs.dialog.style.setProperty(
@@ -1131,6 +1174,7 @@ var SmartPhoto = class {
1131
1174
  if (!currentItems(this.state)) {
1132
1175
  return;
1133
1176
  }
1177
+ this.updateViewportHeight();
1134
1178
  this.resetTranslateCurrent();
1135
1179
  this.setPosByCurrentIndex();
1136
1180
  this.setSizeByScreen();
@@ -1153,6 +1197,7 @@ var SmartPhoto = class {
1153
1197
  if (!currentItems(this.state)) {
1154
1198
  return;
1155
1199
  }
1200
+ this.updateViewportHeight();
1156
1201
  this.resetTranslateCurrent();
1157
1202
  this.setPosByCurrentIndex();
1158
1203
  this.setHashByCurrentIndex();
@@ -1163,6 +1208,7 @@ var SmartPhoto = class {
1163
1208
  const poll = (time) => {
1164
1209
  this.scheduleTimeout(() => {
1165
1210
  if (prevWidth !== getWindowWidth()) {
1211
+ this.updateViewportHeight();
1166
1212
  this.resetTranslateCurrent();
1167
1213
  this.setPosByCurrentIndex();
1168
1214
  this.setHashByCurrentIndex();
@@ -1175,6 +1221,7 @@ var SmartPhoto = class {
1175
1221
  };
1176
1222
  poll(0);
1177
1223
  };
1224
+ this.rootSelector = typeof source === "string" ? source : null;
1178
1225
  this.state = createState(settings ?? {});
1179
1226
  this.view = createView(
1180
1227
  { id: this.id, options: this.state.options },
@@ -1196,15 +1243,14 @@ var SmartPhoto = class {
1196
1243
  },
1197
1244
  { signal: this.abortController.signal }
1198
1245
  );
1246
+ document.addEventListener("click", this.handleDocumentClick, {
1247
+ signal: this.abortController.signal
1248
+ });
1199
1249
  this.ingestSource(source);
1200
1250
  this.syncCurrentGroupView();
1201
1251
  const restored = this.restoreFromHash();
1202
1252
  if (restored) {
1203
- if (restored.element) {
1204
- triggerEvent(restored.element, "click");
1205
- } else {
1206
- this.openPhoto(restored, null);
1207
- }
1253
+ this.openPhoto(restored, restored.element);
1208
1254
  }
1209
1255
  this.updateViewportHeight();
1210
1256
  if (window.visualViewport) {
@@ -1249,6 +1295,7 @@ var SmartPhoto = class {
1249
1295
  clearTimeout(id);
1250
1296
  });
1251
1297
  this.timeouts = [];
1298
+ this.itemsByElement.clear();
1252
1299
  this.gestures.detach();
1253
1300
  this.view.destroy();
1254
1301
  }
@@ -1361,7 +1408,7 @@ var SmartPhoto = class {
1361
1408
  this.gotoSlide(this.state.viewer.prev);
1362
1409
  }
1363
1410
  addItem(slideOrElement) {
1364
- const item = slideOrElement instanceof Element ? this.addElementItem(slideOrElement) : this.addSlideItem(slideOrElement);
1411
+ const item = slideOrElement instanceof HTMLElement ? this.addElementItem(slideOrElement) : this.addSlideItem(slideOrElement);
1365
1412
  this.syncCurrentGroupView();
1366
1413
  return item;
1367
1414
  }
@@ -1392,7 +1439,7 @@ var SmartPhoto = class {
1392
1439
  );
1393
1440
  addItemToGroup(this.state, item);
1394
1441
  this.loadAllFired.delete(groupId);
1395
- this.bindThumbnailClick(element, item);
1442
+ this.itemsByElement.set(element, item);
1396
1443
  return item;
1397
1444
  }
1398
1445
  addSlideItem(slide) {
@@ -1403,15 +1450,72 @@ var SmartPhoto = class {
1403
1450
  this.loadAllFired.delete(groupId);
1404
1451
  return item;
1405
1452
  }
1406
- bindThumbnailClick(element, item) {
1407
- element.addEventListener(
1408
- "click",
1409
- (e) => {
1410
- e.preventDefault();
1411
- this.openPhoto(item, element);
1412
- },
1413
- { signal: this.abortController.signal }
1414
- );
1453
+ // クリックされた要素(またはその祖先。<a><img></a> の img がクリックされる
1454
+ // ケースを含む)から、登録済み Item を持つ要素まで祖先チェーンを遡って探す
1455
+ findRegisteredAncestor(target) {
1456
+ let node = target;
1457
+ while (node) {
1458
+ if (this.itemsByElement.has(node)) {
1459
+ return node;
1460
+ }
1461
+ node = node.parentElement;
1462
+ }
1463
+ return null;
1464
+ }
1465
+ // rootSelector(文字列セレクタで構築した場合のみ設定される)を再スキャンし、
1466
+ // 指定グループを現在のDOM状態に合わせて丸ごと再構築する(追加・削除・並び順の
1467
+ // 変化を一度に反映)。既知要素は既存の Item オブジェクトをそのまま再利用する
1468
+ // ため loaded/width/height は保持され、DOM から消えた要素だけ itemsByElement
1469
+ // からも除去する。index/translateX は resetTranslate() で再計算する。
1470
+ // 呼び出し元(openPhoto)がこの結果を使い、変化があった場合のみ view を
1471
+ // 再同期する(§ダイアログを開く瞬間に整合を取る。開いている間の next()/prev()
1472
+ // では呼ばれないため、この間の追加/削除は次に開き直すまで反映されない)
1473
+ resyncGroupFromDom(groupId) {
1474
+ if (!this.rootSelector) {
1475
+ return false;
1476
+ }
1477
+ const domElements = Array.from(
1478
+ document.querySelectorAll(this.rootSelector)
1479
+ ).filter((el) => groupIdFromElement(el) === groupId);
1480
+ const domElementSet = new Set(domElements);
1481
+ const previous = this.state.groups.get(groupId) ?? [];
1482
+ const previousByElement = /* @__PURE__ */ new Map();
1483
+ previous.forEach((it) => {
1484
+ if (it.element) {
1485
+ previousByElement.set(it.element, it);
1486
+ }
1487
+ });
1488
+ let changed = domElements.length !== previous.length;
1489
+ const rebuilt = domElements.map((el, index) => {
1490
+ const existing = previousByElement.get(el);
1491
+ if (existing) {
1492
+ if (existing.index !== index) {
1493
+ changed = true;
1494
+ existing.index = index;
1495
+ }
1496
+ return existing;
1497
+ }
1498
+ changed = true;
1499
+ const item = itemFromElement(
1500
+ el,
1501
+ this.state.options,
1502
+ index,
1503
+ getWindowWidth()
1504
+ );
1505
+ this.itemsByElement.set(el, item);
1506
+ return item;
1507
+ });
1508
+ previous.forEach((it) => {
1509
+ if (it.element && !domElementSet.has(it.element)) {
1510
+ this.itemsByElement.delete(it.element);
1511
+ }
1512
+ });
1513
+ resetTranslate(rebuilt, getWindowWidth());
1514
+ this.state.groups.set(groupId, rebuilt);
1515
+ if (changed) {
1516
+ this.loadAllFired.delete(groupId);
1517
+ }
1518
+ return changed;
1415
1519
  }
1416
1520
  syncCurrentGroupView() {
1417
1521
  const items = currentItems(this.state);
@@ -1479,10 +1583,12 @@ var SmartPhoto = class {
1479
1583
  syncDialog() {
1480
1584
  const { dialog, caption } = this.view.refs;
1481
1585
  if (this.state.viewer.isOpen && !dialog.open) {
1586
+ dialog.style.removeProperty("display");
1482
1587
  dialog.showModal();
1483
1588
  caption.focus();
1484
1589
  } else if (!this.state.viewer.isOpen && dialog.open) {
1485
1590
  dialog.close();
1591
+ dialog.style.display = "none";
1486
1592
  }
1487
1593
  }
1488
1594
  commit() {
@@ -1665,10 +1771,11 @@ var SmartPhoto = class {
1665
1771
  });
1666
1772
  }
1667
1773
  openPhoto(item, trigger) {
1774
+ const groupChanged = this.rootSelector ? this.resyncGroupFromDom(item.groupId) : false;
1668
1775
  this.lastTriggerElement = trigger;
1669
1776
  this.state.viewer.currentGroup = item.groupId;
1670
1777
  this.state.viewer.currentIndex = item.index;
1671
- if (this.syncedGroupId !== item.groupId) {
1778
+ if (this.syncedGroupId !== item.groupId || groupChanged) {
1672
1779
  this.syncCurrentGroupView();
1673
1780
  }
1674
1781
  this.setHashByCurrentIndex();
@@ -1759,6 +1866,7 @@ var SmartPhoto = class {
1759
1866
  this.state.viewer.photoPosX = 0;
1760
1867
  this.state.viewer.photoPosY = 0;
1761
1868
  this.state.viewer.onMove = true;
1869
+ this.updateViewportHeight();
1762
1870
  this.setPosByCurrentIndex();
1763
1871
  this.setHashByCurrentIndex();
1764
1872
  this.setSizeByScreen();
@@ -1,4 +1,4 @@
1
- import type { Item, ItemId, Slide, SmartPhotoEvent, SmartPhotoSettings, SmartPhotoSource } from "./types";
1
+ import type { ItemId, SlideData, SmartPhotoEvent, SmartPhotoItem, SmartPhotoOptions, SmartPhotoSource } from "./types";
2
2
  interface ShowOptions {
3
3
  group?: string;
4
4
  trigger?: HTMLElement;
@@ -16,7 +16,9 @@ export default class SmartPhoto {
16
16
  private timeouts;
17
17
  private loadAllFired;
18
18
  private syncedGroupId;
19
- constructor(source: SmartPhotoSource, settings?: SmartPhotoSettings);
19
+ private rootSelector;
20
+ private readonly itemsByElement;
21
+ constructor(source: SmartPhotoSource, settings?: SmartPhotoOptions);
20
22
  on(event: SmartPhotoEvent, fn: (this: HTMLDialogElement, ev: Event) => void): void;
21
23
  destroy(): void;
22
24
  [Symbol.dispose](): void;
@@ -24,17 +26,19 @@ export default class SmartPhoto {
24
26
  hidePhoto(dir?: "top" | "bottom"): void;
25
27
  zoomPhoto(): void;
26
28
  zoomOutPhoto(): void;
27
- addNewItem(element: HTMLElement): Item;
29
+ addNewItem(element: HTMLElement): SmartPhotoItem;
28
30
  show(indexOrId?: ItemId, opts?: ShowOptions): void;
29
31
  hide(): void;
30
32
  next(): void;
31
33
  prev(): void;
32
- addItem(slideOrElement: Slide | HTMLElement): Item;
34
+ addItem(slideOrElement: SlideData | HTMLElement): SmartPhotoItem;
33
35
  get currentIndex(): number;
34
36
  private ingestSource;
35
37
  private addElementItem;
36
38
  private addSlideItem;
37
- private bindThumbnailClick;
39
+ private findRegisteredAncestor;
40
+ private resyncGroupFromDom;
41
+ private handleDocumentClick;
38
42
  private syncCurrentGroupView;
39
43
  private setHash;
40
44
  private setHashByCurrentIndex;
@@ -1,10 +1,10 @@
1
- import type { Bound, Item, Slide, SmartPhotoOptions, SmartPhotoSettings, State, ViewerState } from "./types";
2
- export declare const defaults: SmartPhotoOptions;
3
- export declare function createState(settings: SmartPhotoSettings): State;
1
+ import type { Bound, Item, ResolvedSmartPhotoOptions, SlideData, SmartPhotoOptions, State, ViewerState } from "./types";
2
+ export declare const defaults: ResolvedSmartPhotoOptions;
3
+ export declare function createState(settings: SmartPhotoOptions): State;
4
4
  export declare function groupIdFromElement(element: Element): string;
5
- export declare function groupIdFromSlide(slide: Slide): string;
6
- export declare function itemFromElement(element: Element, options: Pick<SmartPhotoOptions, "lazyAttribute">, index: number, winWidth: number): Item;
7
- export declare function itemFromSlide(slide: Slide, index: number, winWidth: number): Item;
5
+ export declare function groupIdFromSlide(slide: SlideData): string;
6
+ export declare function itemFromElement(element: Element, options: Pick<ResolvedSmartPhotoOptions, "lazyAttribute">, index: number, winWidth: number): Item;
7
+ export declare function itemFromSlide(slide: SlideData, index: number, winWidth: number): Item;
8
8
  export declare function addItemToGroup(state: State, item: Item): void;
9
9
  export declare function currentItems(state: State): Item[] | null;
10
10
  export declare function currentItem(state: State): Item | null;
@@ -31,7 +31,7 @@ export interface Messages {
31
31
  closeDialog: string;
32
32
  carouselLabel: string;
33
33
  }
34
- export interface SmartPhotoOptions {
34
+ export interface ResolvedSmartPhotoOptions {
35
35
  classNames: ClassNames;
36
36
  message: Messages;
37
37
  arrows: boolean;
@@ -53,29 +53,31 @@ export interface SmartPhotoOptions {
53
53
  lazyAttribute: string;
54
54
  animationSpeed: number;
55
55
  }
56
- export type SmartPhotoSettings = Partial<Omit<SmartPhotoOptions, "classNames" | "message">> & {
56
+ export type SmartPhotoOptions = Partial<Omit<ResolvedSmartPhotoOptions, "classNames" | "message">> & {
57
57
  classNames?: Partial<ClassNames>;
58
58
  message?: Partial<Messages>;
59
59
  };
60
60
  export type ItemId = string | number;
61
- export interface Item {
61
+ export interface SmartPhotoItem {
62
62
  src: string | null;
63
63
  thumb: string | null;
64
64
  caption: string | null;
65
65
  alt: string | null;
66
66
  groupId: string;
67
- translateX: number;
68
- translateY: number;
69
67
  index: number;
70
68
  width: number;
71
69
  height: number;
70
+ id: ItemId;
71
+ loaded: boolean;
72
+ element: HTMLElement | null;
73
+ }
74
+ export interface Item extends SmartPhotoItem {
75
+ translateX: number;
76
+ translateY: number;
72
77
  scale: number;
73
78
  x: number;
74
79
  y: number;
75
- id: ItemId;
76
- loaded: boolean;
77
80
  processed: boolean;
78
- element: HTMLElement | null;
79
81
  }
80
82
  export interface AppearEffect {
81
83
  width: number;
@@ -111,7 +113,7 @@ export interface ViewerState {
111
113
  showNextArrow: boolean;
112
114
  }
113
115
  export interface State {
114
- options: SmartPhotoOptions;
116
+ options: ResolvedSmartPhotoOptions;
115
117
  viewer: ViewerState;
116
118
  groups: Map<string, Item[]>;
117
119
  }
@@ -121,7 +123,7 @@ export interface Bound {
121
123
  maxX: number;
122
124
  maxY: number;
123
125
  }
124
- export interface Slide {
126
+ export interface SlideData {
125
127
  src: string;
126
128
  thumb?: string;
127
129
  caption?: string;
@@ -131,7 +133,7 @@ export interface Slide {
131
133
  width?: number;
132
134
  height?: number;
133
135
  }
134
- export type SmartPhotoSource = string | NodeListOf<Element> | Element[] | Slide[];
136
+ export type SmartPhotoSource = string | NodeListOf<Element> | Element[] | SlideData[];
135
137
  export type SmartPhotoEvent = "open" | "close" | "change" | "swipestart" | "swipeend" | "zoomin" | "zoomout" | "gesturestart" | "gestureend" | "loadall";
136
138
  export type SwipeEndResult = "prev" | "next" | "close-top" | "close-bottom" | "stay";
137
139
  export type PhotoDragEndResult = "prev" | "next" | "zoom-out" | null;
@@ -1,4 +1,4 @@
1
- import type { AppearEffect, Item, SmartPhotoOptions, State } from "./types";
1
+ import type { AppearEffect, Item, ResolvedSmartPhotoOptions, State } from "./types";
2
2
  interface SlideRefs {
3
3
  li: HTMLLIElement;
4
4
  loaderWrap: HTMLDivElement | null;
@@ -41,7 +41,7 @@ export interface View {
41
41
  }
42
42
  export declare function createView({ id, options }: {
43
43
  id: string;
44
- options: SmartPhotoOptions;
44
+ options: ResolvedSmartPhotoOptions;
45
45
  }, handlers: ViewHandlers, { signal }: {
46
46
  signal: AbortSignal;
47
47
  }): View;
@@ -1,2 +1,3 @@
1
1
  import SmartPhoto from "./core";
2
2
  export default SmartPhoto;
3
+ export type { ClassNames, ItemId, Messages, SlideData, SmartPhotoEvent, SmartPhotoItem, SmartPhotoOptions, SmartPhotoSource, } from "./core/types";