@shortkitsdk/web 0.3.0 → 0.3.1

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/dist/shortkit.mjs CHANGED
@@ -33847,7 +33847,7 @@ class FeedManager {
33847
33847
  }
33848
33848
  setMuted(muted) {
33849
33849
  this.isMuted = muted;
33850
- for (const [, player] of this.pool._players) {
33850
+ for (const [, player] of this.pool.assignments) {
33851
33851
  player.muted = muted;
33852
33852
  }
33853
33853
  this._pushPlayerState({ isMuted: muted });
@@ -33860,7 +33860,7 @@ class FeedManager {
33860
33860
  }
33861
33861
  setPlaybackRate(rate) {
33862
33862
  this.playbackRate = rate;
33863
- for (const [, player] of this.pool._players) {
33863
+ for (const [, player] of this.pool.assignments) {
33864
33864
  player.playbackRate = rate;
33865
33865
  }
33866
33866
  this._pushPlayerState({ playbackRate: rate });
@@ -34337,11 +34337,10 @@ class FeedManager {
34337
34337
  const player = this.pool.getPlayer(id);
34338
34338
  if (player) {
34339
34339
  player.pause();
34340
- player.style.opacity = "0";
34341
34340
  player._skRevealedFor = null;
34342
34341
  }
34343
34342
  this._stopTimeLoop(id);
34344
- this._clearOverlay(id);
34343
+ this._detachOverlay(id);
34345
34344
  this._sk._tracker.deactivateContent();
34346
34345
  }
34347
34346
  // --- Time loop ---
@@ -34523,14 +34522,20 @@ class FeedManager {
34523
34522
  }
34524
34523
  }
34525
34524
  /** Clear the overlay container's DOM and unsubscribe tracked listeners. */
34526
- _clearOverlay(itemId) {
34525
+ /** Unsubscribe overlay event listeners without clearing DOM. */
34526
+ _detachOverlay(itemId) {
34527
34527
  const entry = this._overlayContainers.get(itemId);
34528
34528
  if (!entry) return;
34529
34529
  if (entry.unsub) {
34530
34530
  entry.unsub();
34531
34531
  entry.unsub = null;
34532
34532
  }
34533
- entry.el.innerHTML = "";
34533
+ }
34534
+ /** Unsubscribe and clear overlay DOM (used on destroy). */
34535
+ _clearOverlay(itemId) {
34536
+ this._detachOverlay(itemId);
34537
+ const entry = this._overlayContainers.get(itemId);
34538
+ if (entry) entry.el.innerHTML = "";
34534
34539
  }
34535
34540
  }
34536
34541
  class EmbeddedFeedManager {
@@ -34644,7 +34649,7 @@ class EmbeddedFeedManager {
34644
34649
  }
34645
34650
  setMuted(muted) {
34646
34651
  this.isMuted = muted;
34647
- for (const [, player] of this.pool._players) {
34652
+ for (const [, player] of this.pool.assignments) {
34648
34653
  player.muted = muted;
34649
34654
  }
34650
34655
  this._pushPlayerState({ isMuted: muted });
@@ -34657,7 +34662,7 @@ class EmbeddedFeedManager {
34657
34662
  }
34658
34663
  setPlaybackRate(rate) {
34659
34664
  this.playbackRate = rate;
34660
- for (const [, player] of this.pool._players) {
34665
+ for (const [, player] of this.pool.assignments) {
34661
34666
  player.playbackRate = rate;
34662
34667
  }
34663
34668
  this._pushPlayerState({ playbackRate: rate });
@@ -34929,11 +34934,10 @@ class EmbeddedFeedManager {
34929
34934
  const p = this.pool.getPlayer(id);
34930
34935
  if (p) {
34931
34936
  p.pause();
34932
- p.style.opacity = "0";
34933
34937
  p._skRevealedFor = null;
34934
34938
  }
34935
34939
  this._stopTimeLoop(id);
34936
- this._clearOverlay(id);
34940
+ this._detachOverlay(id);
34937
34941
  }
34938
34942
  // --- Time loop (state emission only, no DOM updates) ---
34939
34943
  _startTimeLoop(id, el, player) {
@@ -35132,14 +35136,20 @@ class EmbeddedFeedManager {
35132
35136
  } catch (e) {
35133
35137
  }
35134
35138
  }
35135
- _clearOverlay(itemId) {
35139
+ /** Unsubscribe overlay event listeners without clearing DOM. */
35140
+ _detachOverlay(itemId) {
35136
35141
  const entry = this._overlayContainers.get(itemId);
35137
35142
  if (!entry) return;
35138
35143
  if (entry.unsub) {
35139
35144
  entry.unsub();
35140
35145
  entry.unsub = null;
35141
35146
  }
35142
- entry.el.innerHTML = "";
35147
+ }
35148
+ /** Unsubscribe and clear overlay DOM (used on destroy). */
35149
+ _clearOverlay(itemId) {
35150
+ this._detachOverlay(itemId);
35151
+ const entry = this._overlayContainers.get(itemId);
35152
+ if (entry) entry.el.innerHTML = "";
35143
35153
  }
35144
35154
  }
35145
35155
  const MuteOnSvg = '<svg viewBox="0 0 24 24"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>';
@@ -35489,6 +35499,7 @@ class PlayerFeedView {
35489
35499
  this._isOpen = true;
35490
35500
  this._onClose = onClose;
35491
35501
  this._openItemId = item.id;
35502
+ this._openThumbnailUrl = item.thumbnailUrl || null;
35492
35503
  const sourceRect = sourceEl.getBoundingClientRect();
35493
35504
  const sourceRadius = parseFloat(getComputedStyle(sourceEl).borderRadius) || 12;
35494
35505
  this.overlayEl.classList.add("skp-active");
@@ -35533,6 +35544,21 @@ class PlayerFeedView {
35533
35544
  feedEl.style.transform = "none";
35534
35545
  feedEl.style.borderRadius = `${targetRadius}px`;
35535
35546
  });
35547
+ this.feedManager.startObserver();
35548
+ this.feedManager._activateItem(item.id);
35549
+ this.overlayEl.classList.add("skp-feed-ready");
35550
+ const itemOverlay = feedItemEl?.querySelector('[data-ref="overlay"]');
35551
+ const chromeEls = [...this.overlayEl.querySelectorAll(".skp-feed-close, .sk-sidebar")];
35552
+ if (itemOverlay) chromeEls.push(itemOverlay);
35553
+ chromeEls.forEach((el) => {
35554
+ el.style.opacity = "0";
35555
+ el.style.transition = "none";
35556
+ });
35557
+ this.overlayEl.getBoundingClientRect();
35558
+ chromeEls.forEach((el) => {
35559
+ el.style.transition = "opacity .35s cubic-bezier(.32,.72,0,1)";
35560
+ el.style.opacity = "1";
35561
+ });
35536
35562
  await this._waitForTransitionEnd(feedEl, 450);
35537
35563
  feedEl.classList.remove("skp-flip-animating");
35538
35564
  feedEl.style.transformOrigin = "";
@@ -35540,9 +35566,10 @@ class PlayerFeedView {
35540
35566
  feedEl.style.scrollSnapType = "";
35541
35567
  feedEl.style.transform = "";
35542
35568
  feedEl.style.borderRadius = "";
35543
- this.feedManager.startObserver();
35544
- this.feedManager._activateItem(item.id);
35545
- this.overlayEl.classList.add("skp-feed-ready");
35569
+ chromeEls.forEach((el) => {
35570
+ el.style.opacity = "";
35571
+ el.style.transition = "";
35572
+ });
35546
35573
  this._escHandler = (e) => {
35547
35574
  if (e.key === "Escape") this.close();
35548
35575
  };
@@ -35555,33 +35582,44 @@ class PlayerFeedView {
35555
35582
  const feedWrapper = feedEl.parentNode;
35556
35583
  const feedRect = feedEl.getBoundingClientRect();
35557
35584
  const activeItemId = this.feedManager?.activeItemId;
35558
- let transferBack = false, transferVideo = null, transferHls = null;
35559
- if (activeItemId === this._openItemId) {
35560
- const ejected = this.feedManager?.pool.ejectPlayer(activeItemId);
35561
- if (ejected) {
35562
- transferBack = true;
35563
- transferVideo = ejected.video;
35564
- transferHls = ejected.hls;
35565
- }
35566
- }
35585
+ const canTransfer = activeItemId === this._openItemId;
35567
35586
  let targetRect = null;
35568
35587
  if (this._onClose) targetRect = this._onClose("getSourceRect");
35569
35588
  if (feedRect && targetRect) {
35570
- if (this.feedManager?.activeItemId && !transferBack) {
35589
+ if (this.feedManager?.activeItemId && !canTransfer) {
35571
35590
  this.feedManager._deactivateItem(this.feedManager.activeItemId);
35572
35591
  }
35592
+ const targetItemId = canTransfer ? this._openItemId : activeItemId;
35593
+ if (targetItemId && this.feedManager) {
35594
+ const targetEl = this.feedManager.itemEls.get(targetItemId);
35595
+ if (targetEl) targetEl.scrollIntoView({ behavior: "instant", block: "start" });
35596
+ }
35597
+ const savedScrollTop = feedEl.scrollTop;
35573
35598
  feedEl.style.position = "fixed";
35574
35599
  feedEl.style.left = `${feedRect.left}px`;
35575
35600
  feedEl.style.top = `${feedRect.top}px`;
35576
35601
  feedEl.style.width = `${feedRect.width}px`;
35577
35602
  feedEl.style.height = `${feedRect.height}px`;
35578
- feedEl.style.zIndex = "9999";
35603
+ feedEl.style.zIndex = String(getComputedStyle(this.overlayEl).zIndex || 9999);
35579
35604
  feedEl.style.margin = "0";
35580
35605
  feedEl.style.flex = "none";
35581
35606
  feedEl.style.aspectRatio = "unset";
35582
35607
  feedEl.style.maxHeight = "none";
35583
35608
  document.body.appendChild(feedEl);
35609
+ feedEl.scrollTop = savedScrollTop;
35584
35610
  this.overlayEl.classList.remove("skp-active", "skp-feed-ready");
35611
+ let thumbOverlay = null;
35612
+ if (this._openThumbnailUrl) {
35613
+ const crossfadeItemId = canTransfer ? this._openItemId : activeItemId;
35614
+ const crossfadeEl = crossfadeItemId && this.feedManager?.itemEls.get(crossfadeItemId);
35615
+ const videoContainer = crossfadeEl?.querySelector('[data-ref="videoContainer"]');
35616
+ if (videoContainer) {
35617
+ thumbOverlay = document.createElement("img");
35618
+ thumbOverlay.src = this._openThumbnailUrl;
35619
+ thumbOverlay.style.cssText = "position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .4s cubic-bezier(.32,.72,0,1);pointer-events:none;z-index:2;";
35620
+ videoContainer.appendChild(thumbOverlay);
35621
+ }
35622
+ }
35585
35623
  const scaleX = targetRect.width / feedRect.width;
35586
35624
  const scaleY = targetRect.height / feedRect.height;
35587
35625
  const translateX = targetRect.left - feedRect.left;
@@ -35591,29 +35629,58 @@ class PlayerFeedView {
35591
35629
  feedEl.style.transformOrigin = "0 0";
35592
35630
  feedEl.style.overflow = "hidden";
35593
35631
  feedEl.style.scrollSnapType = "none";
35632
+ feedEl.style.pointerEvents = "none";
35594
35633
  feedEl.getBoundingClientRect();
35595
35634
  feedEl.classList.add("skp-flip-animating");
35596
35635
  requestAnimationFrame(() => {
35597
35636
  feedEl.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
35598
35637
  feedEl.style.borderRadius = `${endRadius}px`;
35638
+ if (thumbOverlay) thumbOverlay.style.opacity = "1";
35599
35639
  });
35600
35640
  await this._waitForTransitionEnd(feedEl, 450);
35641
+ if (thumbOverlay) thumbOverlay.remove();
35642
+ let transferVideo = null;
35643
+ let transferHls = null;
35644
+ if (canTransfer) {
35645
+ const ejected = this.feedManager?.pool.ejectPlayer(this._openItemId);
35646
+ if (ejected) {
35647
+ transferVideo = ejected.video;
35648
+ transferHls = ejected.hls;
35649
+ }
35650
+ }
35601
35651
  feedEl.style.visibility = "hidden";
35602
35652
  feedEl.classList.remove("skp-flip-animating");
35603
- ["position", "left", "top", "width", "height", "zIndex", "margin", "flex", "aspectRatio", "maxHeight", "transformOrigin", "overflow", "scrollSnapType", "transform", "borderRadius"].forEach((p) => feedEl.style[p] = "");
35653
+ ["position", "left", "top", "width", "height", "zIndex", "margin", "flex", "aspectRatio", "maxHeight", "transformOrigin", "overflow", "scrollSnapType", "pointerEvents", "transform", "borderRadius"].forEach((p) => feedEl.style[p] = "");
35604
35654
  const sidebarEl = feedWrapper.querySelector(".sk-sidebar");
35605
35655
  feedWrapper.insertBefore(feedEl, sidebarEl);
35606
35656
  feedEl.style.visibility = "";
35657
+ if (this._onClose) {
35658
+ this._onClose("closed", {
35659
+ transferVideo,
35660
+ transferHls,
35661
+ transferItemId: transferVideo ? this._openItemId : null
35662
+ });
35663
+ this._onClose = null;
35664
+ }
35607
35665
  } else {
35608
35666
  this.overlayEl.classList.remove("skp-active", "skp-feed-ready");
35609
- }
35610
- if (this._onClose) {
35611
- this._onClose("closed", {
35612
- transferVideo: transferBack ? transferVideo : null,
35613
- transferHls: transferBack ? transferHls : null,
35614
- transferItemId: transferBack ? this._openItemId : null
35615
- });
35616
- this._onClose = null;
35667
+ if (this._onClose) {
35668
+ let transferVideo = null;
35669
+ let transferHls = null;
35670
+ if (canTransfer) {
35671
+ const ejected = this.feedManager?.pool.ejectPlayer(this._openItemId);
35672
+ if (ejected) {
35673
+ transferVideo = ejected.video;
35674
+ transferHls = ejected.hls;
35675
+ }
35676
+ }
35677
+ this._onClose("closed", {
35678
+ transferVideo,
35679
+ transferHls,
35680
+ transferItemId: transferVideo ? this._openItemId : null
35681
+ });
35682
+ this._onClose = null;
35683
+ }
35617
35684
  }
35618
35685
  if (this.feedManager) {
35619
35686
  this.feedManager.destroy();
@@ -35665,6 +35732,7 @@ class FeedView {
35665
35732
  this._onClose = onClose;
35666
35733
  this._openSlotIndex = startIndex;
35667
35734
  this._openItemId = item.id;
35735
+ this._openThumbnailUrl = item.thumbnailUrl || null;
35668
35736
  const slotRect = slotEl.getBoundingClientRect();
35669
35737
  const slotRadius = parseFloat(getComputedStyle(slotEl).borderRadius) || 12;
35670
35738
  if (_isPreview) {
@@ -35711,6 +35779,21 @@ class FeedView {
35711
35779
  feedEl.style.transform = "none";
35712
35780
  feedEl.style.borderRadius = `${targetRadius}px`;
35713
35781
  });
35782
+ this.feedManager.startObserver();
35783
+ this.feedManager._activateItem(item.id);
35784
+ this.overlayEl.classList.add("skw-feed-ready");
35785
+ const itemOverlay = feedItemEl?.querySelector('[data-ref="overlay"]');
35786
+ const chromeEls = [...this.overlayEl.querySelectorAll(".skw-feed-close, .sk-sidebar")];
35787
+ if (itemOverlay) chromeEls.push(itemOverlay);
35788
+ chromeEls.forEach((el) => {
35789
+ el.style.opacity = "0";
35790
+ el.style.transition = "none";
35791
+ });
35792
+ this.overlayEl.getBoundingClientRect();
35793
+ chromeEls.forEach((el) => {
35794
+ el.style.transition = "opacity .35s cubic-bezier(.32,.72,0,1)";
35795
+ el.style.opacity = "1";
35796
+ });
35714
35797
  await this._waitForTransitionEnd(feedEl, 450);
35715
35798
  feedEl.classList.remove("skw-flip-animating");
35716
35799
  feedEl.style.transformOrigin = "";
@@ -35718,9 +35801,10 @@ class FeedView {
35718
35801
  feedEl.style.scrollSnapType = "";
35719
35802
  feedEl.style.transform = "";
35720
35803
  feedEl.style.borderRadius = "";
35721
- this.feedManager.startObserver();
35722
- this.feedManager._activateItem(item.id);
35723
- this.overlayEl.classList.add("skw-feed-ready");
35804
+ chromeEls.forEach((el) => {
35805
+ el.style.opacity = "";
35806
+ el.style.transition = "";
35807
+ });
35724
35808
  this._escHandler = (e) => {
35725
35809
  if (e.key === "Escape") this.close();
35726
35810
  };
@@ -35747,6 +35831,12 @@ class FeedView {
35747
35831
  if (this.feedManager?.activeItemId && !canTransfer) {
35748
35832
  this.feedManager._deactivateItem(this.feedManager.activeItemId);
35749
35833
  }
35834
+ const targetItemId = canTransfer ? this._openItemId : activeItemId;
35835
+ if (targetItemId && this.feedManager) {
35836
+ const targetEl = this.feedManager.itemEls.get(targetItemId);
35837
+ if (targetEl) targetEl.scrollIntoView({ behavior: "instant", block: "start" });
35838
+ }
35839
+ const savedScrollTop = feedEl.scrollTop;
35750
35840
  feedEl.style.position = "fixed";
35751
35841
  feedEl.style.left = `${feedRect.left}px`;
35752
35842
  feedEl.style.top = `${feedRect.top}px`;
@@ -35758,7 +35848,20 @@ class FeedView {
35758
35848
  feedEl.style.aspectRatio = "unset";
35759
35849
  feedEl.style.maxHeight = "none";
35760
35850
  document.body.appendChild(feedEl);
35851
+ feedEl.scrollTop = savedScrollTop;
35761
35852
  this.overlayEl.classList.remove("skw-active", "skw-feed-ready");
35853
+ let thumbOverlay = null;
35854
+ if (this._openThumbnailUrl) {
35855
+ const targetItemId2 = canTransfer ? this._openItemId : activeItemId;
35856
+ const targetEl = targetItemId2 && this.feedManager?.itemEls.get(targetItemId2);
35857
+ const videoContainer = targetEl?.querySelector('[data-ref="videoContainer"]');
35858
+ if (videoContainer) {
35859
+ thumbOverlay = document.createElement("img");
35860
+ thumbOverlay.src = this._openThumbnailUrl;
35861
+ thumbOverlay.style.cssText = "position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .4s cubic-bezier(.32,.72,0,1);pointer-events:none;z-index:2;";
35862
+ videoContainer.appendChild(thumbOverlay);
35863
+ }
35864
+ }
35762
35865
  const slotRadius = parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--skw-radius").trim()) || 12;
35763
35866
  const scaleX = targetSlotRect.width / feedRect.width;
35764
35867
  const scaleY = targetSlotRect.height / feedRect.height;
@@ -35768,13 +35871,16 @@ class FeedView {
35768
35871
  feedEl.style.transformOrigin = "0 0";
35769
35872
  feedEl.style.overflow = "hidden";
35770
35873
  feedEl.style.scrollSnapType = "none";
35874
+ feedEl.style.pointerEvents = "none";
35771
35875
  feedEl.getBoundingClientRect();
35772
35876
  feedEl.classList.add("skw-flip-animating");
35773
35877
  requestAnimationFrame(() => {
35774
35878
  feedEl.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
35775
35879
  feedEl.style.borderRadius = `${endRadius}px`;
35880
+ if (thumbOverlay) thumbOverlay.style.opacity = "1";
35776
35881
  });
35777
35882
  await this._waitForTransitionEnd(feedEl, 450);
35883
+ if (thumbOverlay) thumbOverlay.remove();
35778
35884
  let transferVideo = null;
35779
35885
  let transferHls = null;
35780
35886
  if (canTransfer) {
@@ -35799,6 +35905,7 @@ class FeedView {
35799
35905
  feedEl.style.transformOrigin = "";
35800
35906
  feedEl.style.overflow = "";
35801
35907
  feedEl.style.scrollSnapType = "";
35908
+ feedEl.style.pointerEvents = "";
35802
35909
  feedEl.style.transform = "";
35803
35910
  feedEl.style.borderRadius = "";
35804
35911
  feedWrapper.insertBefore(feedEl, feedWrapper.firstChild);
@@ -36537,7 +36644,7 @@ const CSS = `
36537
36644
 
36538
36645
  /* Video container */
36539
36646
  .sk-video-container{position:absolute;inset:0;width:100%;height:100%;overflow:hidden;background-size:cover;background-position:center}
36540
- .sk-video-container video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .15s ease}
36647
+ .sk-video-container video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .35s ease}
36541
36648
 
36542
36649
  /* Tap zone */
36543
36650
  .sk-tap-zone{position:absolute;inset:0;z-index:3;cursor:pointer}
@@ -36553,7 +36660,7 @@ const CSS = `
36553
36660
 
36554
36661
  /* Widget slot */
36555
36662
  .skw-slot{position:relative;overflow:hidden;cursor:pointer}
36556
- .skw-slot video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .2s ease}
36663
+ .skw-slot video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .4s ease}
36557
36664
  .skw-slot-thumb{position:absolute;inset:0;background-size:cover;background-position:center}
36558
36665
  .skw-slot-overlay{position:absolute;inset:0;z-index:4;pointer-events:none}
36559
36666
  .skw-slot-overlay>*{pointer-events:auto}