smartphoto 2.1.11 → 2.1.13

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/README.md CHANGED
@@ -181,6 +181,11 @@ Slide fields:
181
181
  <td>update the URL hash (<code>#group=…&photo=…</code>) via the History API</td>
182
182
  <td>true</td>
183
183
  </tr>
184
+ <tr>
185
+ <td>useViewTransitionApi</td>
186
+ <td>use the View Transition API for the open animation when the browser supports it (falls back to the clone-based animation when disabled or unsupported)</td>
187
+ <td>true</td>
188
+ </tr>
184
189
  <tr>
185
190
  <td>swipeTopToClose</td>
186
191
  <td>close the viewer on an upward swipe</td>
@@ -132,6 +132,17 @@ dialog.smartphoto:not([open]) {
132
132
 
133
133
  .smartphoto::backdrop {
134
134
  background-color: var(--smartphoto-backdrop-color, rgba(0, 0, 0, 1));
135
+ /* iOS 26 Safari の「タブバー(下)」表示では、ページ本体はツールバーの背後
136
+ * (レイアウトビューポートの下端より下)までエッジツーエッジで描画されるのに対し、
137
+ * 既定の ::backdrop はビューポート下端で止まるため、サムネイルバーの下の帯から
138
+ * 裏のページが覗いてしまう。dialog 本体の高さを伸ばす方法は取らない
139
+ * (bottom:0 のサムネイルバーごとツールバーの背後に潜ってしまう)。
140
+ * レイアウトに影響しない ::backdrop 側だけを 100lvh + 下側セーフエリアまで
141
+ * 明示的に広げて帯を覆う。lvh 非対応ブラウザでは height 宣言ごと無効になり、
142
+ * 下の inset: 0 による従来のビューポート全面カバーにフォールバックする */
143
+ position: fixed;
144
+ inset: 0;
145
+ height: calc(100lvh + env(safe-area-inset-bottom, 0px));
135
146
  }
136
147
 
137
148
  /* View Transition(openPhotoWithViewTransition() 参照)の疑似要素ツリーは document の
@@ -146,6 +157,19 @@ dialog.smartphoto:not([open]) {
146
157
  animation-timing-function: var(--smartphoto-animation-function, ease-out);
147
158
  }
148
159
 
160
+ /* view-transition-name を付けなかった要素(サムネイル一覧のページ全体や、
161
+ * 新しく開く dialog の背景/矢印/キャプション等)は、既定では ::view-transition-*(root)
162
+ * が「開く前のページ」→「dialog が開いた後のページ」を丸ごとクロスフェードする。
163
+ * このクロスフェードは既定で mix-blend-mode: plus-lighter が掛かり、背景色が
164
+ * 大きく変わる(明るいページ→黒背景)場合に一瞬白っぽく光って見えたり、写真本体
165
+ * (smartphoto-hero)のモーフィングと重なって「一瞬消えてからまた出てくる」ように
166
+ * 見える原因になる。root 側のアニメーションは無効化し、写真の拡大だけを見せる */
167
+ ::view-transition-old(root),
168
+ ::view-transition-new(root) {
169
+ animation: none;
170
+ mix-blend-mode: normal;
171
+ }
172
+
149
173
  .smartphoto-close {
150
174
  opacity: 0;
151
175
  }
@@ -1 +1 @@
1
- @keyframes smartphoto{0%{opacity:0}to{opacity:1}}@keyframes smartphoto-img-wrap{0%{opacity:0}to{opacity:1}}@keyframes smartphoto-inner{0%{transform:translateY(100px)}to{transform:translate(0)}}@keyframes smartphoto-loader{0%{opacity:.4;transform:rotate(0deg)}50%{opacity:1;transform:rotate(180deg)}to{opacity:.4;transform:rotate(1turn)}}@keyframes smartphoto-appear{0%{opacity:0}to{opacity:1}}@keyframes smartphoto-hide{0%{opacity:1}to{opacity:0}}:root:has(dialog.smartphoto[open]){overflow:hidden}.smartphoto{border:none;background:transparent;padding:0;margin:0;outline:none;position:fixed;inset:0;width:100%;height:100%;max-width:100%;max-height:100%;overflow:hidden;height:var(--smartphoto-vh,100dvh);max-height:var(--smartphoto-vh,100dvh);background-color:var(--smartphoto-backdrop-color,#000);opacity:1;font-family:sans-serif;cursor:pointer;transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out),display var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out) allow-discrete,overlay var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out) allow-discrete}.smartphoto:not([open]){opacity:0}dialog.smartphoto:not([open]){display:none!important}.smartphoto::backdrop{background-color:var(--smartphoto-backdrop-color,#000)}::view-transition-group(smartphoto-hero),::view-transition-new(smartphoto-hero),::view-transition-old(smartphoto-hero){animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-close{opacity:0}.smartphoto-count{display:inline-block;color:var(--smartphoto-icon-color,#fff);font-size:16px}.smartphoto-header{display:block;box-sizing:border-box;position:fixed;z-index:102;top:0;left:0;width:100%;height:50px;padding:15px;background-color:var(--smartphoto-header-color,rgba(0,0,0,.2))}.smartphoto-content{display:block;position:absolute;top:0;left:0;width:100%;height:100%;touch-action:none}.smartphoto-dismiss{display:block;position:absolute;top:15px;right:10px;width:20px;height:20px;padding:0;border:none;background-color:var(--smartphoto-icon-color,#fff);mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTU3Ni40MiAxNDA2Ljc2IDI3ODQgMTk5LjE5YTU2Ljg2IDU2Ljg2IDAgMCAwIDAtODAuMThsLTc4LjkyLTc4LjkyYTU2Ljg2IDU2Ljg2IDAgMCAwLTgwLjE4IDBMMTQxNy4zMiAxMjQ3LjY2IDIwOS43NSA0MC4wOWE1Ni44NiA1Ni44NiAwIDAgMC04MC4xOCAwTDUwLjY1IDExOWE1Ni44NiA1Ni44NiAwIDAgMCAwIDgwLjE4bDEyMDcuNTggMTIwNy41OEw1MC42NSAyNjE0LjM0YTU2Ljg2IDU2Ljg2IDAgMCAwIDAgODAuMThsNzguOTIgNzguOTJhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGwxMjA3LjU3LTEyMDcuNThMMjYyNC45IDI3NzMuNDRhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGw3OC45Mi03OC45MmE1Ni44NiA1Ni44NiAwIDAgMCAwLTgwLjE4WiIvPjwvc3ZnPg==);-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTU3Ni40MiAxNDA2Ljc2IDI3ODQgMTk5LjE5YTU2Ljg2IDU2Ljg2IDAgMCAwIDAtODAuMThsLTc4LjkyLTc4LjkyYTU2Ljg2IDU2Ljg2IDAgMCAwLTgwLjE4IDBMMTQxNy4zMiAxMjQ3LjY2IDIwOS43NSA0MC4wOWE1Ni44NiA1Ni44NiAwIDAgMC04MC4xOCAwTDUwLjY1IDExOWE1Ni44NiA1Ni44NiAwIDAgMCAwIDgwLjE4bDEyMDcuNTggMTIwNy41OEw1MC42NSAyNjE0LjM0YTU2Ljg2IDU2Ljg2IDAgMCAwIDAgODAuMThsNzguOTIgNzguOTJhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGwxMjA3LjU3LTEyMDcuNThMMjYyNC45IDI3NzMuNDRhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGw3OC45Mi03OC45MmE1Ni44NiA1Ni44NiAwIDAgMCAwLTgwLjE4WiIvPjwvc3ZnPg==);mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat;mask-size:contain;-webkit-mask-size:contain;text-decoration:none;cursor:pointer;line-height:1}.smartphoto-body{z-index:102;margin:0 auto}.smartphoto-body,.smartphoto-inner{position:relative;width:100%;height:100%}.smartphoto-inner{vertical-align:top}.smartphoto-img{display:none;max-width:none;width:auto;height:auto;cursor:zoom-in;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;transition:transform var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-webkit-user-drag:none}.smartphoto-img.active{display:block}.smartphoto-img-onmove{cursor:grab;cursor:-webkit-grab;transition:none}.smartphoto-img-elasticmove{transition:transform var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out)}.smartphoto-img-wrap{display:inline-block;opacity:1;touch-action:none;-webkit-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-moz-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-ms-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-o-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);animation-name:smartphoto-img-wrap;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-img-left{transform:translateX(150%)!important}.smartphoto-img-right{transform:translateX(-150%)!important}.smartphoto-arrows{list-style-type:none;margin:0;padding:0;position:relative;z-index:1002;top:50%;left:0;opacity:1;animation-name:smartphoto-appear;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-arrows[aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-arrows li{display:block;position:absolute;top:var(--smartphoto-arrow-top,50%);width:30px;height:30px;margin-top:-20px;box-sizing:content-box;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out);animation-name:smartphoto-appear}.smartphoto-arrows li:focus{outline:none}.smartphoto-arrows [aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-arrows button{appearance:none;display:block;width:100%;height:100%;margin:0;padding:0;border:none;background-color:transparent;cursor:pointer}.smartphoto-arrow-right{right:0;padding:5px 0;background-color:rgba(0,0,0,.5)}.smartphoto-arrow-right button{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTgzNy44OCAxNDE3LjMyIDY0My41OSAyMjNhNzIuMjEgNzIuMjEgMCAwIDEgMC0xMDEuODJMNzQzLjgyIDIxYTcyLjIxIDcyLjIxIDAgMCAxIDEwMS44MiAwbDEyNDUuMTkgMTI0NS4xOSAxMDAuMjMgMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAxIDAgMTAxLjgyTDg0NS42NCAyODEzLjY1YTcyLjIxIDcyLjIxIDAgMCAxLTEwMS44MiAwbC0xMDAuMjMtMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAxIDAtMTAxLjgyWiIvPjwvc3ZnPg==)}.smartphoto-arrow-left{left:0;padding:5px 0;background-color:rgba(0,0,0,.5)}.smartphoto-arrow-left button{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNOTk2Ljc3IDE0MTcuMzIgMjE5MS4wNiAyMjNhNzIuMjEgNzIuMjEgMCAwIDAgMC0xMDEuODJMMjA5MC44MyAyMUE3Mi4yMSA3Mi4yMSAwIDAgMCAxOTg5IDIxTDc0My44MiAxMjY2LjE5bC0xMDAuMjMgMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAwIDAgMTAxLjgyTDE5ODkgMjgxMy42NWE3Mi4yMSA3Mi4yMSAwIDAgMCAxMDEuODIgMGwxMDAuMjMtMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAwIDAtMTAxLjgyWiIvPjwvc3ZnPg==)}.smartPhotoArrowHideIcon{display:none}.smartphoto-nav{position:absolute;bottom:0;left:0;width:100%;padding-bottom:env(safe-area-inset-bottom,0);box-sizing:border-box;opacity:1;animation-name:smartphoto-appear;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-nav[aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-nav ul{display:block;overflow-x:auto;list-style:none;margin:0;padding:0;text-align:center;white-space:nowrap;-webkit-overflow-scrolling:touch}.smartphoto-nav li{display:inline-block;overflow:hidden;width:50px;height:50px}.smartphoto-nav button{appearance:none;display:block;width:100%;height:100%;margin:0;padding:0;border:none;background-color:#fff;background-position:50%;background-size:cover;opacity:.5;cursor:pointer}.smartphoto-nav button:focus{opacity:.8}.smartphoto-nav button.current{opacity:1}.smartphoto-nav img{width:auto;height:100%}.smartphoto-list{list-style-type:none;position:absolute;z-index:101;top:0;left:0;margin:0;padding:0;white-space:nowrap}.smartphoto-list li{display:block;position:absolute;top:0;left:0;width:100%;height:100%;transition:all var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out)}.smartphoto-list li:focus{outline:none}.smartphoto-list-onmove{transition:all .3s var(--smartphoto-animation-function,ease-out)}.smartphoto-caption{overflow:hidden;box-sizing:border-box;position:absolute;top:0;left:0;width:100%;height:50px;padding:0 50px;color:var(--smartphoto-icon-color,#fff);font-size:12px;text-align:center;line-height:50px;white-space:nowrap;text-overflow:ellipsis;margin:0;font-weight:400}.smartphoto-caption:focus{outline:none}.smartphoto-loader-wrap{display:block;position:relative;z-index:103;width:0;height:0;transform:translate(50vw,50vh);transform:translate(50vw,50dvh);transform:translate(50vw,calc(var(--smartphoto-vh, 100dvh)/2))}.smartphoto-loader{position:absolute;z-index:101;top:0;left:0;width:30px;height:30px;margin-top:-25px;margin-left:-25px;border:8px solid #17cddd;border-right-color:transparent;border-radius:50%;animation:smartphoto-loader .5s linear infinite}.smartphoto-img-clone{position:fixed;z-index:100;top:0;left:0;transition:all var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out)}.smartphoto-sr-only{overflow:hidden;position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;clip:rect(0,0,0,0)}
1
+ @keyframes smartphoto{0%{opacity:0}to{opacity:1}}@keyframes smartphoto-img-wrap{0%{opacity:0}to{opacity:1}}@keyframes smartphoto-inner{0%{transform:translateY(100px)}to{transform:translate(0)}}@keyframes smartphoto-loader{0%{opacity:.4;transform:rotate(0deg)}50%{opacity:1;transform:rotate(180deg)}to{opacity:.4;transform:rotate(1turn)}}@keyframes smartphoto-appear{0%{opacity:0}to{opacity:1}}@keyframes smartphoto-hide{0%{opacity:1}to{opacity:0}}:root:has(dialog.smartphoto[open]){overflow:hidden}.smartphoto{border:none;background:transparent;padding:0;margin:0;outline:none;position:fixed;inset:0;width:100%;height:100%;max-width:100%;max-height:100%;overflow:hidden;height:var(--smartphoto-vh,100dvh);max-height:var(--smartphoto-vh,100dvh);background-color:var(--smartphoto-backdrop-color,#000);opacity:1;font-family:sans-serif;cursor:pointer;transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out),display var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out) allow-discrete,overlay var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out) allow-discrete}.smartphoto:not([open]){opacity:0}dialog.smartphoto:not([open]){display:none!important}.smartphoto::backdrop{background-color:var(--smartphoto-backdrop-color,#000);position:fixed;inset:0;height:calc(100lvh + env(safe-area-inset-bottom, 0px))}::view-transition-group(smartphoto-hero),::view-transition-new(smartphoto-hero),::view-transition-old(smartphoto-hero){animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}::view-transition-new(root),::view-transition-old(root){animation:none;mix-blend-mode:normal}.smartphoto-close{opacity:0}.smartphoto-count{display:inline-block;color:var(--smartphoto-icon-color,#fff);font-size:16px}.smartphoto-header{display:block;box-sizing:border-box;position:fixed;z-index:102;top:0;left:0;width:100%;height:50px;padding:15px;background-color:var(--smartphoto-header-color,rgba(0,0,0,.2))}.smartphoto-content{display:block;position:absolute;top:0;left:0;width:100%;height:100%;touch-action:none}.smartphoto-dismiss{display:block;position:absolute;top:15px;right:10px;width:20px;height:20px;padding:0;border:none;background-color:var(--smartphoto-icon-color,#fff);mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTU3Ni40MiAxNDA2Ljc2IDI3ODQgMTk5LjE5YTU2Ljg2IDU2Ljg2IDAgMCAwIDAtODAuMThsLTc4LjkyLTc4LjkyYTU2Ljg2IDU2Ljg2IDAgMCAwLTgwLjE4IDBMMTQxNy4zMiAxMjQ3LjY2IDIwOS43NSA0MC4wOWE1Ni44NiA1Ni44NiAwIDAgMC04MC4xOCAwTDUwLjY1IDExOWE1Ni44NiA1Ni44NiAwIDAgMCAwIDgwLjE4bDEyMDcuNTggMTIwNy41OEw1MC42NSAyNjE0LjM0YTU2Ljg2IDU2Ljg2IDAgMCAwIDAgODAuMThsNzguOTIgNzguOTJhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGwxMjA3LjU3LTEyMDcuNThMMjYyNC45IDI3NzMuNDRhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGw3OC45Mi03OC45MmE1Ni44NiA1Ni44NiAwIDAgMCAwLTgwLjE4WiIvPjwvc3ZnPg==);-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTU3Ni40MiAxNDA2Ljc2IDI3ODQgMTk5LjE5YTU2Ljg2IDU2Ljg2IDAgMCAwIDAtODAuMThsLTc4LjkyLTc4LjkyYTU2Ljg2IDU2Ljg2IDAgMCAwLTgwLjE4IDBMMTQxNy4zMiAxMjQ3LjY2IDIwOS43NSA0MC4wOWE1Ni44NiA1Ni44NiAwIDAgMC04MC4xOCAwTDUwLjY1IDExOWE1Ni44NiA1Ni44NiAwIDAgMCAwIDgwLjE4bDEyMDcuNTggMTIwNy41OEw1MC42NSAyNjE0LjM0YTU2Ljg2IDU2Ljg2IDAgMCAwIDAgODAuMThsNzguOTIgNzguOTJhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGwxMjA3LjU3LTEyMDcuNThMMjYyNC45IDI3NzMuNDRhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGw3OC45Mi03OC45MmE1Ni44NiA1Ni44NiAwIDAgMCAwLTgwLjE4WiIvPjwvc3ZnPg==);mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat;mask-size:contain;-webkit-mask-size:contain;text-decoration:none;cursor:pointer;line-height:1}.smartphoto-body{z-index:102;margin:0 auto}.smartphoto-body,.smartphoto-inner{position:relative;width:100%;height:100%}.smartphoto-inner{vertical-align:top}.smartphoto-img{display:none;max-width:none;width:auto;height:auto;cursor:zoom-in;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;transition:transform var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-webkit-user-drag:none}.smartphoto-img.active{display:block}.smartphoto-img-onmove{cursor:grab;cursor:-webkit-grab;transition:none}.smartphoto-img-elasticmove{transition:transform var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out)}.smartphoto-img-wrap{display:inline-block;opacity:1;touch-action:none;-webkit-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-moz-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-ms-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-o-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);animation-name:smartphoto-img-wrap;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-img-left{transform:translateX(150%)!important}.smartphoto-img-right{transform:translateX(-150%)!important}.smartphoto-arrows{list-style-type:none;margin:0;padding:0;position:relative;z-index:1002;top:50%;left:0;opacity:1;animation-name:smartphoto-appear;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-arrows[aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-arrows li{display:block;position:absolute;top:var(--smartphoto-arrow-top,50%);width:30px;height:30px;margin-top:-20px;box-sizing:content-box;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out);animation-name:smartphoto-appear}.smartphoto-arrows li:focus{outline:none}.smartphoto-arrows [aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-arrows button{appearance:none;display:block;width:100%;height:100%;margin:0;padding:0;border:none;background-color:transparent;cursor:pointer}.smartphoto-arrow-right{right:0;padding:5px 0;background-color:rgba(0,0,0,.5)}.smartphoto-arrow-right button{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTgzNy44OCAxNDE3LjMyIDY0My41OSAyMjNhNzIuMjEgNzIuMjEgMCAwIDEgMC0xMDEuODJMNzQzLjgyIDIxYTcyLjIxIDcyLjIxIDAgMCAxIDEwMS44MiAwbDEyNDUuMTkgMTI0NS4xOSAxMDAuMjMgMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAxIDAgMTAxLjgyTDg0NS42NCAyODEzLjY1YTcyLjIxIDcyLjIxIDAgMCAxLTEwMS44MiAwbC0xMDAuMjMtMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAxIDAtMTAxLjgyWiIvPjwvc3ZnPg==)}.smartphoto-arrow-left{left:0;padding:5px 0;background-color:rgba(0,0,0,.5)}.smartphoto-arrow-left button{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNOTk2Ljc3IDE0MTcuMzIgMjE5MS4wNiAyMjNhNzIuMjEgNzIuMjEgMCAwIDAgMC0xMDEuODJMMjA5MC44MyAyMUE3Mi4yMSA3Mi4yMSAwIDAgMCAxOTg5IDIxTDc0My44MiAxMjY2LjE5bC0xMDAuMjMgMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAwIDAgMTAxLjgyTDE5ODkgMjgxMy42NWE3Mi4yMSA3Mi4yMSAwIDAgMCAxMDEuODIgMGwxMDAuMjMtMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAwIDAtMTAxLjgyWiIvPjwvc3ZnPg==)}.smartPhotoArrowHideIcon{display:none}.smartphoto-nav{position:absolute;bottom:0;left:0;width:100%;padding-bottom:env(safe-area-inset-bottom,0);box-sizing:border-box;opacity:1;animation-name:smartphoto-appear;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-nav[aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-nav ul{display:block;overflow-x:auto;list-style:none;margin:0;padding:0;text-align:center;white-space:nowrap;-webkit-overflow-scrolling:touch}.smartphoto-nav li{display:inline-block;overflow:hidden;width:50px;height:50px}.smartphoto-nav button{appearance:none;display:block;width:100%;height:100%;margin:0;padding:0;border:none;background-color:#fff;background-position:50%;background-size:cover;opacity:.5;cursor:pointer}.smartphoto-nav button:focus{opacity:.8}.smartphoto-nav button.current{opacity:1}.smartphoto-nav img{width:auto;height:100%}.smartphoto-list{list-style-type:none;position:absolute;z-index:101;top:0;left:0;margin:0;padding:0;white-space:nowrap}.smartphoto-list li{display:block;position:absolute;top:0;left:0;width:100%;height:100%;transition:all var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out)}.smartphoto-list li:focus{outline:none}.smartphoto-list-onmove{transition:all .3s var(--smartphoto-animation-function,ease-out)}.smartphoto-caption{overflow:hidden;box-sizing:border-box;position:absolute;top:0;left:0;width:100%;height:50px;padding:0 50px;color:var(--smartphoto-icon-color,#fff);font-size:12px;text-align:center;line-height:50px;white-space:nowrap;text-overflow:ellipsis;margin:0;font-weight:400}.smartphoto-caption:focus{outline:none}.smartphoto-loader-wrap{display:block;position:relative;z-index:103;width:0;height:0;transform:translate(50vw,50vh);transform:translate(50vw,50dvh);transform:translate(50vw,calc(var(--smartphoto-vh, 100dvh)/2))}.smartphoto-loader{position:absolute;z-index:101;top:0;left:0;width:30px;height:30px;margin-top:-25px;margin-left:-25px;border:8px solid #17cddd;border-right-color:transparent;border-radius:50%;animation:smartphoto-loader .5s linear infinite}.smartphoto-img-clone{position:fixed;z-index:100;top:0;left:0;transition:all var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out)}.smartphoto-sr-only{overflow:hidden;position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;clip:rect(0,0,0,0)}
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * SmartPhoto v2.1.11
2
+ * SmartPhoto v2.1.13
3
3
  * (c) appleple
4
4
  * Released under the MIT License.
5
5
  */
@@ -10,6 +10,9 @@
10
10
  const agent = navigator.userAgent;
11
11
  return agent.indexOf("iPhone") > 0 || agent.indexOf("iPad") > 0 || agent.indexOf("ipod") > 0 || agent.indexOf("Android") > 0;
12
12
  };
13
+ var isWebKit = () => {
14
+ return typeof window.webkitConvertPointFromNodeToPage === "function";
15
+ };
13
16
  function deepExtend(out, ...args) {
14
17
  var _a;
15
18
  out = out || {};
@@ -148,6 +151,7 @@
148
151
  verticalGravity: false,
149
152
  useOrientationApi: false,
150
153
  useHistoryApi: true,
154
+ useViewTransitionApi: true,
151
155
  swipeTopToClose: false,
152
156
  swipeBottomToClose: true,
153
157
  swipeOffset: 100,
@@ -435,6 +439,7 @@
435
439
  let oldPos = null;
436
440
  let moveDir = null;
437
441
  let swipeStartTime = 0;
442
+ let tapTarget = null;
438
443
  let photoSwipable = false;
439
444
  let firstPhotoPos = null;
440
445
  let oldPhotoPos = null;
@@ -565,6 +570,7 @@
565
570
  firstPos = pos;
566
571
  oldPos = pos;
567
572
  swipeStartTime = Date.now();
573
+ tapTarget = e.target;
568
574
  }
569
575
  function startPhotoDrag(e) {
570
576
  photoSwipable = true;
@@ -706,11 +712,11 @@
706
712
  const swipeHeight = last.y - first.y;
707
713
  const noMove = swipeWidth === 0 && swipeHeight === 0;
708
714
  if (!isSmartPhone2() && noMove) {
709
- callbacks.onTap();
715
+ callbacks.onTap(tapTarget);
710
716
  return;
711
717
  }
712
718
  if (Math.abs(offset) <= 500 && noMove) {
713
- callbacks.onTap();
719
+ callbacks.onTap(tapTarget);
714
720
  return;
715
721
  }
716
722
  tapSecond = now;
@@ -1035,6 +1041,9 @@
1035
1041
  if (slideRefs.imgWrap && slideRefs.img) {
1036
1042
  slideRefs.imgWrap.style.transform = `translate(${item.x}px,${item.y}px) scale(${item.scale})`;
1037
1043
  slideRefs.img.style.width = `${item.width}px`;
1044
+ if (!isCurrent) {
1045
+ slideRefs.img.style.transform = "translate(0px,0px) scale(1)";
1046
+ }
1038
1047
  slideRefs.img.classList.toggle("active", viewer.appear);
1039
1048
  slideRefs.img.classList.toggle(
1040
1049
  classNames.smartPhotoImgOnMove,
@@ -1118,6 +1127,23 @@
1118
1127
  refs.list.style.transform = `translate(${viewer.translateX}px,${viewer.translateY}px)`;
1119
1128
  refs.list.classList.toggle(classNames.smartPhotoListOnMove, viewer.onMove);
1120
1129
  }
1130
+ function applyViewTransitionLayout(state) {
1131
+ for (const [item, slideRefs] of refs.slides) {
1132
+ if (item.index !== state.viewer.currentIndex) {
1133
+ continue;
1134
+ }
1135
+ const { img, imgWrap } = slideRefs;
1136
+ if (!img || !imgWrap || !item.width || !item.scale || item.scale >= 1) {
1137
+ return;
1138
+ }
1139
+ const before = img.getBoundingClientRect();
1140
+ img.style.width = `${item.width * item.scale}px`;
1141
+ imgWrap.style.transform = `translate(${item.x}px,${item.y}px) scale(1)`;
1142
+ const after = img.getBoundingClientRect();
1143
+ imgWrap.style.transform = `translate(${item.x + before.left - after.left}px,${item.y + before.top - after.top}px) scale(1)`;
1144
+ return;
1145
+ }
1146
+ }
1121
1147
  function showAppearEffect(effect) {
1122
1148
  const clone = document.createElement("img");
1123
1149
  clone.className = classNames.smartPhotoImgClone;
@@ -1142,6 +1168,7 @@
1142
1168
  render,
1143
1169
  syncSlides,
1144
1170
  updatePhotoTransform,
1171
+ applyViewTransitionLayout,
1145
1172
  updateListTransform,
1146
1173
  showAppearEffect,
1147
1174
  removeAppearEffect,
@@ -1178,6 +1205,13 @@
1178
1205
  // doHideEffect() の後始末(画像に設定した translateY の除去と promise 解決)を
1179
1206
  // transitionend を待たずに即時実行するための関数。後始末が済むと null に戻る
1180
1207
  this.finishHideEffect = null;
1208
+ // 開く View Transition が進行中かどうか。進行中にリサイズ由来の再計算(commit)が
1209
+ // 走ると、モーフの目標位置は古いビューポート基準のままなのに実要素だけ新しい
1210
+ // 位置へ動いて「一旦ずれた位置に出てから正位置へ戻る」ように見え、さらに
1211
+ // モーフ用レイアウト(applyViewTransitionLayout)も巻き戻されてしまう。
1212
+ // そのため進行中はリサイズ再計算を保留し、finished 後にまとめて実行する
1213
+ this.isViewTransitionActive = false;
1214
+ this.pendingViewTransitionResync = false;
1181
1215
  this.timeouts = [];
1182
1216
  this.loadAllFired = /* @__PURE__ */ new Set();
1183
1217
  this.syncedGroupId = null;
@@ -1236,16 +1270,24 @@
1236
1270
  if (!this.isSmartPhoneFlag || !this.state.viewer.isOpen || !currentItems(this.state)) {
1237
1271
  return;
1238
1272
  }
1273
+ if (this.isViewTransitionActive) {
1274
+ this.pendingViewTransitionResync = true;
1275
+ return;
1276
+ }
1239
1277
  this.resetTranslateCurrent();
1240
1278
  this.setPosByCurrentIndex();
1241
1279
  this.setSizeByScreen();
1242
1280
  this.commit();
1243
1281
  };
1244
1282
  this.handleResize = () => {
1245
- if (!currentItems(this.state)) {
1283
+ if (!this.state.viewer.isOpen || !currentItems(this.state)) {
1246
1284
  return;
1247
1285
  }
1248
1286
  this.updateViewportHeight();
1287
+ if (this.isViewTransitionActive) {
1288
+ this.pendingViewTransitionResync = true;
1289
+ return;
1290
+ }
1249
1291
  this.resetTranslateCurrent();
1250
1292
  this.setPosByCurrentIndex();
1251
1293
  this.setSizeByScreen();
@@ -1265,7 +1307,11 @@
1265
1307
  }
1266
1308
  };
1267
1309
  this.handleOrientationChange = () => {
1268
- if (!currentItems(this.state)) {
1310
+ if (!this.state.viewer.isOpen || !currentItems(this.state)) {
1311
+ return;
1312
+ }
1313
+ if (this.isViewTransitionActive) {
1314
+ this.pendingViewTransitionResync = true;
1269
1315
  return;
1270
1316
  }
1271
1317
  this.updateViewportHeight();
@@ -1278,6 +1324,9 @@
1278
1324
  const timeout = 500;
1279
1325
  const poll = (time) => {
1280
1326
  this.scheduleTimeout(() => {
1327
+ if (!this.state.viewer.isOpen) {
1328
+ return;
1329
+ }
1281
1330
  if (prevWidth !== getWindowWidth2()) {
1282
1331
  this.updateViewportHeight();
1283
1332
  this.resetTranslateCurrent();
@@ -1430,10 +1479,26 @@
1430
1479
  this.state.viewer.photoPosY = 0;
1431
1480
  this.view.updatePhotoTransform(this.state);
1432
1481
  this.scheduleTimeout(() => {
1482
+ if (!this.state.viewer.isOpen) {
1483
+ return;
1484
+ }
1433
1485
  this.state.viewer.scale = true;
1434
1486
  this.view.updatePhotoTransform(this.state);
1435
1487
  this.fireEvent("zoomin");
1436
- }, 300);
1488
+ }, this.state.options.animationSpeed);
1489
+ }
1490
+ // zoomPhoto() と同じ「ズームの余地があるか」の判定(scaleBorder <= 1 なら
1491
+ // ズームしても見た目が変わらない)。zoomPhoto() 自体は公開 API の契約
1492
+ // (ズームできなければ何もしない)を保つ必要があるため、タップの
1493
+ // zoom-or-close 分岐(§7)用に判定だけを切り出している
1494
+ canZoomCurrentPhoto() {
1495
+ const item = currentItem(this.state);
1496
+ return !!item && scaleBorder(
1497
+ item,
1498
+ getWindowWidth2(),
1499
+ getWindowHeight2(),
1500
+ this.isSmartPhoneFlag
1501
+ ) > 1;
1437
1502
  }
1438
1503
  zoomOutPhoto() {
1439
1504
  this.state.viewer.scaleSize = 1;
@@ -1644,6 +1709,7 @@
1644
1709
  this.state.options.headerHeight,
1645
1710
  this.state.options.footerHeight
1646
1711
  );
1712
+ this.syncFillScale();
1647
1713
  }
1648
1714
  // resize/orientationchange ハンドラは呼び出し前に currentItems の存在を確認済み
1649
1715
  resetTranslateCurrent() {
@@ -1657,9 +1723,18 @@
1657
1723
  }
1658
1724
  return null;
1659
1725
  }
1726
+ currentLiElement() {
1727
+ for (const [item, slideRefs] of this.view.refs.slides) {
1728
+ if (item.index === this.state.viewer.currentIndex) {
1729
+ return slideRefs.li;
1730
+ }
1731
+ }
1732
+ return null;
1733
+ }
1660
1734
  // ---- 内部: dialog 制御(§8) ----
1661
1735
  syncDialog() {
1662
1736
  const { dialog, caption } = this.view.refs;
1737
+ dialog.style.transition = this.state.options.showAnimation === false ? "none" : "";
1663
1738
  if (this.state.viewer.isOpen && !dialog.open) {
1664
1739
  dialog.style.removeProperty("display");
1665
1740
  dialog.showModal();
@@ -1671,6 +1746,7 @@
1671
1746
  }
1672
1747
  commit() {
1673
1748
  this.view.render(this.state);
1749
+ this.view.updatePhotoTransform(this.state);
1674
1750
  this.syncDialog();
1675
1751
  }
1676
1752
  // ---- 内部: 開く演出 ----
@@ -1689,20 +1765,34 @@
1689
1765
  this.setPosByCurrentIndex();
1690
1766
  this.setSizeByScreen();
1691
1767
  setArrow(this.state);
1692
- if (this.state.options.resizeStyle === "fill" && this.isSmartPhoneFlag) {
1693
- const item = currentItem(this.state);
1694
- this.state.viewer.scale = true;
1695
- this.state.viewer.hideUi = true;
1696
- this.state.viewer.scaleSize = scaleBorder(
1697
- item,
1698
- getWindowWidth2(),
1699
- getWindowHeight2(),
1700
- this.isSmartPhoneFlag
1701
- );
1768
+ }
1769
+ // resizeStyle: 'fill' はスマートフォンでのみ、画面を隙間なく覆うよう
1770
+ // scaleBorder() の倍率を viewer.scaleSize に適用する。fit用の item.scale に
1771
+ // 依存するため、setSizeByScreen() の末尾から必ず呼ばれる(個別に呼ぶ必要はない)
1772
+ syncFillScale() {
1773
+ if (this.state.options.resizeStyle !== "fill" || !this.isSmartPhoneFlag) {
1774
+ return;
1775
+ }
1776
+ const item = currentItem(this.state);
1777
+ if (!item) {
1778
+ return;
1702
1779
  }
1780
+ this.state.viewer.scale = true;
1781
+ this.state.viewer.hideUi = true;
1782
+ this.state.viewer.scaleSize = scaleBorder(
1783
+ item,
1784
+ getWindowWidth2(),
1785
+ getWindowHeight2(),
1786
+ this.isSmartPhoneFlag
1787
+ );
1703
1788
  }
1704
1789
  supportsViewTransition() {
1705
- return typeof document.startViewTransition === "function";
1790
+ return this.state.options.useViewTransitionApi && typeof document.startViewTransition === "function" && // WebKit には「view-transition-name 付き要素が root スナップショットから
1791
+ // 除外されず、モーフ中に最終位置へ二重描画される」実装バグがあり、開く演出が
1792
+ // 「一旦ずれた位置に出てから正位置へ戻る」ように乱れる。API 対応の有無では
1793
+ // 検出できないため、WebKit ではクローン演出(addAppearEffect)へフォールバック
1794
+ // する(§util.isWebKit)
1795
+ !isWebKit();
1706
1796
  }
1707
1797
  openPhotoWithViewTransition(trigger) {
1708
1798
  var _a, _b;
@@ -1715,7 +1805,8 @@
1715
1805
  if (thumbImg) {
1716
1806
  thumbImg.style.viewTransitionName = transitionName;
1717
1807
  }
1718
- const clearNames = () => {
1808
+ const cleanup = () => {
1809
+ this.isViewTransitionActive = false;
1719
1810
  if (thumbImg) {
1720
1811
  thumbImg.style.viewTransitionName = "";
1721
1812
  }
@@ -1723,6 +1814,21 @@
1723
1814
  if (img) {
1724
1815
  img.style.viewTransitionName = "";
1725
1816
  }
1817
+ if (!this.state.viewer.isOpen) {
1818
+ this.pendingViewTransitionResync = false;
1819
+ return;
1820
+ }
1821
+ if (this.pendingViewTransitionResync && currentItems(this.state)) {
1822
+ this.pendingViewTransitionResync = false;
1823
+ this.updateViewportHeight();
1824
+ this.resetTranslateCurrent();
1825
+ this.setPosByCurrentIndex();
1826
+ this.setSizeByScreen();
1827
+ this.commit();
1828
+ return;
1829
+ }
1830
+ this.pendingViewTransitionResync = false;
1831
+ this.view.render(this.state);
1726
1832
  };
1727
1833
  const transition = (_b = document.startViewTransition) == null ? void 0 : _b.call(document, () => {
1728
1834
  this.initPhoto();
@@ -1732,11 +1838,16 @@
1732
1838
  thumbImg.style.viewTransitionName = "";
1733
1839
  }
1734
1840
  this.currentImgElement().style.viewTransitionName = transitionName;
1841
+ this.view.applyViewTransitionLayout(this.state);
1735
1842
  });
1736
- transition == null ? void 0 : transition.ready.catch(() => {
1737
- clearNames();
1843
+ if (!transition) {
1844
+ return;
1845
+ }
1846
+ this.isViewTransitionActive = true;
1847
+ transition.ready.catch(() => {
1848
+ cleanup();
1738
1849
  });
1739
- transition == null ? void 0 : transition.finished.then(clearNames, clearNames);
1850
+ transition.finished.then(cleanup, cleanup);
1740
1851
  }
1741
1852
  // doOpen() の呼び出し元でこの分岐に来る時点で showAnimation !== false が保証されている
1742
1853
  addAppearEffect(trigger, item) {
@@ -1846,10 +1957,14 @@
1846
1957
  if (getWindowWidth2() === winWidthBefore && getWindowHeight2() === winHeightBefore) {
1847
1958
  return;
1848
1959
  }
1960
+ if (this.isViewTransitionActive) {
1961
+ this.pendingViewTransitionResync = true;
1962
+ return;
1963
+ }
1849
1964
  this.resetTranslateCurrent();
1850
1965
  this.setPosByCurrentIndex();
1851
1966
  this.setSizeByScreen();
1852
- this.view.render(this.state);
1967
+ this.commit();
1853
1968
  });
1854
1969
  }
1855
1970
  openPhoto(item, trigger) {
@@ -1871,25 +1986,42 @@
1871
1986
  }
1872
1987
  doHideEffect(dir) {
1873
1988
  return new Promise((resolve) => {
1989
+ if (this.state.options.showAnimation === false) {
1990
+ resolve();
1991
+ return;
1992
+ }
1874
1993
  const dialog = this.view.refs.dialog;
1875
- const img = this.currentImgElement();
1994
+ const item = currentItem(this.state);
1995
+ const li = item ? this.currentLiElement() : null;
1876
1996
  const height = getWindowHeight2();
1877
- const applied = dir === "top" ? `translateY(-${height}px)` : `translateY(${height}px)`;
1878
- const finish = () => {
1997
+ const img = this.currentImgElement();
1998
+ let frozenTransform = null;
1999
+ if (img) {
2000
+ const rendered = getComputedStyle(img).transform;
2001
+ if (rendered && rendered !== "none") {
2002
+ img.style.transform = rendered;
2003
+ frozenTransform = img.style.transform;
2004
+ }
2005
+ }
2006
+ if (li && item) {
2007
+ const offsetY = dir === "top" ? -height : height;
2008
+ li.style.transform = `translate(${item.translateX}px,${item.translateY + offsetY}px)`;
2009
+ }
2010
+ const finish = (e) => {
1879
2011
  if (this.finishHideEffect !== finish) {
1880
2012
  return;
1881
2013
  }
2014
+ if (e && e.target !== dialog) {
2015
+ return;
2016
+ }
1882
2017
  this.finishHideEffect = null;
1883
2018
  dialog.removeEventListener("transitionend", finish, true);
1884
- if (img && img.style.transform === applied) {
2019
+ if (img && frozenTransform && img.style.transform === frozenTransform) {
1885
2020
  img.style.transform = "";
1886
2021
  }
1887
2022
  resolve();
1888
2023
  };
1889
2024
  this.finishHideEffect = finish;
1890
- if (img) {
1891
- img.style.transform = applied;
1892
- }
1893
2025
  dialog.addEventListener("transitionend", finish, true);
1894
2026
  this.scheduleTimeout(finish, this.state.options.animationSpeed + 100);
1895
2027
  });
@@ -1960,7 +2092,9 @@
1960
2092
  const item = currentItem(this.state);
1961
2093
  this.state.viewer.onMove = false;
1962
2094
  setArrow(this.state);
1963
- this.commit();
2095
+ if (this.state.viewer.isOpen) {
2096
+ this.commit();
2097
+ }
1964
2098
  if (this.state.viewer.oldIndex !== this.state.viewer.currentIndex) {
1965
2099
  this.fireEvent("change");
1966
2100
  }
@@ -2045,7 +2179,21 @@
2045
2179
  }
2046
2180
  this.slideList();
2047
2181
  },
2048
- onTap: () => this.zoomPhoto(),
2182
+ // 主要ライトボックスのデファクトスタンダード(PhotoSwipe: bgClickAction
2183
+ // 'close' / imageClickAction 'zoom-or-close'、Fancybox: backdropClick
2184
+ // 'close'、GLightbox: closeOnOutsideClick、lightGallery: closable)に合わせ、
2185
+ // 写真の上のタップはズーム、写真の外(背景)のタップは閉じる。ズームの
2186
+ // 余地がない(scaleBorder <= 1 で zoomPhoto() が何もしない)写真の上の
2187
+ // タップも、無反応にせず 'zoom-or-close' に倣って閉じる
2188
+ onTap: (target) => {
2189
+ const img = this.currentImgElement();
2190
+ const onPhoto = !!img && target instanceof Node && img.contains(target);
2191
+ if (onPhoto && this.canZoomCurrentPhoto()) {
2192
+ this.zoomPhoto();
2193
+ } else {
2194
+ this.hidePhoto();
2195
+ }
2196
+ },
2049
2197
  onGestureStart: () => {
2050
2198
  this.fireEvent("gesturestart");
2051
2199
  this.view.updatePhotoTransform(this.state);