gsap-timeline-viewer 0.1.0 → 0.1.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/gsap-timeline-viewer.iife.js +31 -25
- package/dist/gsap-timeline-viewer.js +184 -127
- package/dist/gsap-timeline-viewer.umd.cjs +32 -26
- package/dist/index.d.ts +8 -0
- package/package.json +1 -1
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
var GSAPTimelineViewer=function(o){"use strict";var
|
|
1
|
+
var GSAPTimelineViewer=function(o){"use strict";var P=Object.defineProperty;var L=(o,c,h)=>c in o?P(o,c,{enumerable:!0,configurable:!0,writable:!0,value:h}):o[c]=h;var n=(o,c,h)=>L(o,typeof c!="symbol"?c+"":c,h);let c=0;function h(l){if(!l||l.length===0)return"Unknown";const s=l[0];return s.id?`#${s.id}`:s.classList&&s.classList.length>0?`.${s.classList[0]}`:s.tagName?s.tagName.toLowerCase():"element"}function x(l){const s=["ease","duration","delay","onComplete","onStart","onUpdate","onCompleteParams","onStartParams","onUpdateParams","repeat","repeatDelay","yoyo","stagger","overwrite","immediateRender","lazy","autoAlpha","id","paused","reversed","startAt"];return Object.keys(l).filter(t=>!s.includes(t))}function w(l){const s=[];return l.getChildren(!0,!0,!1).forEach((e,i)=>{if(!("targets"in e))return;const a=e,r=a.targets(),d=a.vars||{},p=x(d);let v="";if(d.id&&typeof d.id=="string")v=d.id;else{const b=h(r),k=p.slice(0,2).join(", ");v=k?`${b} (${k})`:b}const y=e.startTime(),f=e.duration();s.push({id:`tween-${++c}`,label:v,startTime:y,endTime:y+f,duration:f,targets:h(r),properties:p,colorIndex:i%6})}),{duration:l.duration(),tweens:s}}function S(){c=0}function g(l,s=!0){const t=Math.abs(l);return s?t.toFixed(2):t.toFixed(0)}const T=":host{--gtv-bg: #1a1a1a;--gtv-bg-secondary: #252525;--gtv-border: #333;--gtv-text: #e0e0e0;--gtv-text-muted: #888;--gtv-accent: oklch(65% .15 220);--gtv-playhead: oklch(65% .15 220);--gtv-ruler-bg: #1f1f1f;--gtv-track-height: 28px;--gtv-controls-height: 40px;--gtv-ruler-height: 24px;--gtv-timeline-padding: 16px;--gtv-track-1: oklch(50% .12 220);--gtv-track-1-active: oklch(60% .15 220);--gtv-track-2: oklch(50% .12 70);--gtv-track-2-active: oklch(60% .15 70);--gtv-track-3: oklch(50% .12 350);--gtv-track-3-active: oklch(60% .15 350);--gtv-track-4: oklch(50% .12 160);--gtv-track-4-active: oklch(60% .15 160);--gtv-track-5: oklch(50% .12 290);--gtv-track-5-active: oklch(60% .15 290);--gtv-track-6: oklch(50% .12 25);--gtv-track-6-active: oklch(60% .15 25)}*{box-sizing:border-box;margin:0;padding:0}.gtv-container{position:fixed;bottom:0;left:0;right:0;background:var(--gtv-bg);border-top:1px solid var(--gtv-border);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:12px;color:var(--gtv-text);z-index:999999;display:flex;flex-direction:column;user-select:none;-webkit-user-select:none}.gtv-container.collapsed{height:auto!important}.gtv-container.collapsed .gtv-timeline-area{display:none}.gtv-controls{position:relative;display:flex;align-items:center;justify-content:center;height:var(--gtv-controls-height);padding:0 12px;background:var(--gtv-bg-secondary);border-bottom:1px solid var(--gtv-border);gap:8px}.gtv-controls-left{position:absolute;left:12px;display:flex;align-items:center;gap:8px}.gtv-controls-center{display:flex;align-items:center;gap:8px}.gtv-controls-right{position:absolute;right:12px;display:flex;align-items:center;gap:8px}.gtv-time-display{font-variant-numeric:tabular-nums;min-width:100px;text-align:center}.gtv-time-current{color:var(--gtv-text)}.gtv-time-total{color:var(--gtv-text-muted)}.gtv-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;background:transparent;border:none;border-radius:4px;color:var(--gtv-text);cursor:pointer;transition:background .15s}.gtv-btn:hover{background:#ffffff1a}.gtv-btn:active{background:#ffffff26}.gtv-btn.active{color:var(--gtv-accent)}.gtv-btn svg{width:16px;height:16px;fill:currentColor}.gtv-btn-play svg{width:20px;height:20px}.gtv-speed-btn{width:auto;padding:0 8px;font-size:11px;font-weight:500}.gtv-collapse-btn{margin-left:auto}.gtv-timeline-area{position:relative;display:flex;flex-direction:column;overflow:hidden;flex:1}.gtv-resize-handle{position:absolute;top:0;left:0;right:0;height:6px;cursor:ns-resize;z-index:20}.gtv-resize-handle:hover,.gtv-resize-handle:active{background:#ffffff1a}.gtv-ruler{position:relative;height:var(--gtv-ruler-height);background:var(--gtv-ruler-bg);border-bottom:1px solid var(--gtv-border);overflow:visible;flex-shrink:0;padding:0 var(--gtv-timeline-padding)}.gtv-ruler-inner{position:relative;height:100%;width:100%}.gtv-ruler-marker{position:absolute;top:0;height:100%;display:flex;flex-direction:column;align-items:center}.gtv-ruler-marker-line{width:1px;height:6px;background:var(--gtv-text-muted)}.gtv-ruler-marker-label{font-size:10px;color:var(--gtv-text-muted);margin-top:2px}.gtv-tracks-container{position:relative;overflow-y:auto;overflow-x:hidden;flex:1;padding:0 var(--gtv-timeline-padding)}.gtv-tracks-scroll{position:relative;min-height:100%;width:100%}.gtv-track{position:relative;height:var(--gtv-track-height)}.gtv-track-bar{position:absolute;top:4px;height:calc(var(--gtv-track-height) - 8px);border-radius:4px;display:flex;align-items:center;padding:0 8px;font-size:11px;font-weight:500;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:default;transition:filter .15s}.gtv-track-bar:hover{filter:brightness(1.1)}.gtv-playhead-wrapper{position:absolute;top:0;bottom:0;left:var(--gtv-timeline-padding);right:var(--gtv-timeline-padding);pointer-events:none;z-index:15}.gtv-playhead{position:absolute;top:0;bottom:0;width:0;left:0}.gtv-playhead-head{position:absolute;top:6px;left:-5px;width:11px;height:11px;background:var(--gtv-playhead);clip-path:polygon(50% 100%,0 0,100% 0)}.gtv-playhead-line{position:absolute;top:6px;bottom:0;left:0;width:1px;background:var(--gtv-playhead)}.gtv-scrub-area{position:absolute;top:0;left:0;right:0;bottom:0;cursor:ew-resize}.gtv-empty{display:flex;align-items:center;justify-content:center;padding:24px;color:var(--gtv-text-muted)}",u=[.25,.5,1,2,4];class m extends HTMLElement{constructor(){super();n(this,"shadow");n(this,"timeline",null);n(this,"timelineData",null);n(this,"isPlaying",!1);n(this,"isLooping",!1);n(this,"speedIndex",2);n(this,"collapsed",!1);n(this,"height",200);n(this,"isDragging",!1);n(this,"container");n(this,"playBtn");n(this,"loopBtn");n(this,"speedBtn");n(this,"timeDisplay");n(this,"rulerInner");n(this,"tracksScroll");n(this,"playhead");n(this,"scrubArea");n(this,"resizeHandle");n(this,"isResizing",!1);this.shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){this.detachTimeline()}setTimeline(t){this.detachTimeline(),this.timeline=t,S(),this.timelineData=w(t),t.eventCallback("onUpdate",()=>this.onTimelineUpdate()),this.renderTracks(),this.updatePlayhead(),this.updateTimeDisplay(),this.updatePlayState()}detachTimeline(){this.timeline&&(this.timeline.eventCallback("onUpdate",null),this.timeline=null,this.timelineData=null)}render(){this.shadow.innerHTML=`
|
|
2
2
|
<style>${T}</style>
|
|
3
3
|
<div class="gtv-container ${this.collapsed?"collapsed":""}" style="height: ${this.height}px;">
|
|
4
4
|
<!-- Controls Bar -->
|
|
5
5
|
<div class="gtv-controls">
|
|
6
6
|
<div class="gtv-controls-left">
|
|
7
|
+
<button class="gtv-btn" data-action="loop" title="Loop (L)">
|
|
8
|
+
<svg viewBox="0 0 24 24"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></svg>
|
|
9
|
+
</button>
|
|
10
|
+
<button class="gtv-btn gtv-speed-btn" data-action="speed" title="Playback speed">1x</button>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="gtv-controls-center">
|
|
14
|
+
<span class="gtv-time-display">
|
|
15
|
+
<span class="gtv-time-current">0.00</span>
|
|
16
|
+
<span class="gtv-time-total"> / 0.00</span>
|
|
17
|
+
</span>
|
|
7
18
|
<button class="gtv-btn" data-action="skip-start" title="Skip to start">
|
|
8
19
|
<svg viewBox="0 0 24 24"><path d="M6 6h2v12H6V6zm3.5 6l8.5 6V6l-8.5 6z"/></svg>
|
|
9
20
|
</button>
|
|
10
|
-
<button class="gtv-btn gtv-btn-play" data-action="play" title="Play/Pause">
|
|
21
|
+
<button class="gtv-btn gtv-btn-play" data-action="play" title="Play/Pause (Space)">
|
|
11
22
|
<svg class="play-icon" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>
|
|
12
23
|
<svg class="pause-icon" viewBox="0 0 24 24" style="display: none;"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
|
|
13
24
|
</button>
|
|
@@ -16,17 +27,6 @@ var GSAPTimelineViewer=function(o){"use strict";var C=Object.defineProperty;var
|
|
|
16
27
|
</button>
|
|
17
28
|
</div>
|
|
18
29
|
|
|
19
|
-
<div class="gtv-controls-center">
|
|
20
|
-
<button class="gtv-btn" data-action="loop" title="Loop">
|
|
21
|
-
<svg viewBox="0 0 24 24"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></svg>
|
|
22
|
-
</button>
|
|
23
|
-
<span class="gtv-time-display">
|
|
24
|
-
<span class="gtv-time-current">0.00</span>
|
|
25
|
-
<span class="gtv-time-total"> / 0.00</span>
|
|
26
|
-
</span>
|
|
27
|
-
<button class="gtv-btn gtv-speed-btn" data-action="speed" title="Playback speed">1x</button>
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
30
|
<div class="gtv-controls-right">
|
|
31
31
|
<button class="gtv-btn gtv-collapse-btn" data-action="collapse" title="Collapse/Expand">
|
|
32
32
|
<svg viewBox="0 0 24 24"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>
|
|
@@ -36,37 +36,43 @@ var GSAPTimelineViewer=function(o){"use strict";var C=Object.defineProperty;var
|
|
|
36
36
|
|
|
37
37
|
<!-- Timeline Area -->
|
|
38
38
|
<div class="gtv-timeline-area">
|
|
39
|
+
<!-- Resize Handle -->
|
|
40
|
+
<div class="gtv-resize-handle"></div>
|
|
41
|
+
|
|
39
42
|
<!-- Ruler -->
|
|
40
43
|
<div class="gtv-ruler">
|
|
41
44
|
<div class="gtv-ruler-inner"></div>
|
|
42
|
-
<div class="gtv-playhead-container">
|
|
43
|
-
<div class="gtv-playhead-head"></div>
|
|
44
|
-
</div>
|
|
45
45
|
</div>
|
|
46
46
|
|
|
47
47
|
<!-- Tracks -->
|
|
48
48
|
<div class="gtv-tracks-container">
|
|
49
49
|
<div class="gtv-tracks-scroll">
|
|
50
50
|
<div class="gtv-scrub-area"></div>
|
|
51
|
-
<div class="gtv-playhead-container">
|
|
52
|
-
<div class="gtv-playhead-line"></div>
|
|
53
|
-
</div>
|
|
54
51
|
</div>
|
|
55
52
|
<div class="gtv-empty">No timeline attached. Call setTimeline() to visualize a GSAP timeline.</div>
|
|
56
53
|
</div>
|
|
54
|
+
|
|
55
|
+
<!-- Playhead spans entire timeline area -->
|
|
56
|
+
<div class="gtv-playhead-wrapper">
|
|
57
|
+
<div class="gtv-playhead">
|
|
58
|
+
<div class="gtv-playhead-head"></div>
|
|
59
|
+
<div class="gtv-playhead-line"></div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
57
62
|
</div>
|
|
58
63
|
</div>
|
|
59
|
-
`,this.container=this.shadow.querySelector(".gtv-container"),this.playBtn=this.shadow.querySelector('[data-action="play"]'),this.loopBtn=this.shadow.querySelector('[data-action="loop"]'),this.speedBtn=this.shadow.querySelector('[data-action="speed"]'),this.timeDisplay=this.shadow.querySelector(".gtv-time-display"),this.rulerInner=this.shadow.querySelector(".gtv-ruler-inner"),this.tracksScroll=this.shadow.querySelector(".gtv-tracks-scroll"),this.playhead=this.shadow.querySelector(".gtv-
|
|
60
|
-
<div class="gtv-ruler-marker" style="left: ${
|
|
64
|
+
`,this.container=this.shadow.querySelector(".gtv-container"),this.playBtn=this.shadow.querySelector('[data-action="play"]'),this.loopBtn=this.shadow.querySelector('[data-action="loop"]'),this.speedBtn=this.shadow.querySelector('[data-action="speed"]'),this.timeDisplay=this.shadow.querySelector(".gtv-time-display"),this.rulerInner=this.shadow.querySelector(".gtv-ruler-inner"),this.tracksScroll=this.shadow.querySelector(".gtv-tracks-scroll"),this.playhead=this.shadow.querySelector(".gtv-playhead"),this.scrubArea=this.shadow.querySelector(".gtv-scrub-area"),this.resizeHandle=this.shadow.querySelector(".gtv-resize-handle")}setupEventListeners(){this.shadow.addEventListener("click",t=>{const i=t.target.closest("[data-action]");if(!i)return;switch(i.dataset.action){case"play":this.togglePlay();break;case"skip-start":this.skipToStart();break;case"skip-end":this.skipToEnd();break;case"loop":this.toggleLoop();break;case"speed":this.cycleSpeed();break;case"collapse":this.toggleCollapse();break}}),this.scrubArea.addEventListener("mousedown",t=>this.startScrub(t)),this.shadow.querySelector(".gtv-ruler").addEventListener("mousedown",t=>this.startScrub(t)),document.addEventListener("mousemove",t=>{this.onScrub(t),this.onResize(t)}),document.addEventListener("mouseup",()=>{this.endScrub(),this.endResize()}),this.resizeHandle.addEventListener("mousedown",t=>this.startResize(t)),document.addEventListener("keydown",t=>{if(t.target===document.body)switch(t.code){case"Space":t.preventDefault(),this.togglePlay();break;case"KeyJ":t.preventDefault(),this.jumpToPrevPoint();break;case"KeyK":t.preventDefault(),this.jumpToNextPoint();break;case"KeyL":t.preventDefault(),this.toggleLoop();break}})}startScrub(t){this.timeline&&(t.preventDefault(),this.isDragging=!0,document.body.style.cursor="ew-resize",document.body.style.userSelect="none",this.scrubToPosition(t))}onScrub(t){!this.isDragging||!this.timeline||this.scrubToPosition(t)}endScrub(){this.isDragging=!1,document.body.style.cursor="",document.body.style.userSelect=""}startResize(t){t.preventDefault(),this.isResizing=!0,document.body.style.cursor="ns-resize",document.body.style.userSelect="none"}onResize(t){if(!this.isResizing)return;const e=window.innerHeight,i=e-t.clientY;this.height=Math.max(100,Math.min(i,e-100)),this.container.style.height=`${this.height}px`}endResize(){this.isResizing&&(this.isResizing=!1,document.body.style.cursor="",document.body.style.userSelect="")}scrubToPosition(t){if(!this.timeline||!this.timelineData)return;const e=this.rulerInner.getBoundingClientRect(),a=Math.max(0,Math.min(t.clientX-e.left,e.width))/e.width;this.timeline.progress(a),this.timeline.pause(),this.updatePlayState()}togglePlay(){this.timeline&&(this.timeline.paused()||this.timeline.progress()===1?this.timeline.progress()===1?this.timeline.restart():this.timeline.play():this.timeline.pause(),this.updatePlayState())}skipToStart(){this.timeline&&(this.timeline.progress(0),this.timeline.pause(),this.updatePlayState())}skipToEnd(){this.timeline&&(this.timeline.progress(1),this.timeline.pause(),this.updatePlayState())}getTimePoints(){if(!this.timelineData)return[0];const t=new Set;return t.add(0),t.add(Math.round(this.timelineData.duration*1e3)/1e3),this.timelineData.tweens.forEach(e=>{t.add(Math.round(e.startTime*1e3)/1e3),t.add(Math.round(e.endTime*1e3)/1e3)}),Array.from(t).sort((e,i)=>e-i)}jumpToPrevPoint(){if(!this.timeline||!this.timelineData)return;const t=Math.round(this.timeline.time()*1e3)/1e3,e=this.getTimePoints();let i=0;for(const a of e)if(a<t-.001)i=a;else break;this.timeline.time(i),this.timeline.pause(),this.updatePlayState()}jumpToNextPoint(){if(!this.timeline||!this.timelineData)return;const t=Math.round(this.timeline.time()*1e3)/1e3,e=this.getTimePoints();let i=this.timelineData.duration;for(const a of e)if(a>t+.001){i=a;break}this.timeline.time(i),this.timeline.pause(),this.updatePlayState()}toggleLoop(){this.timeline&&(this.isLooping=!this.isLooping,this.timeline.repeat(this.isLooping?-1:0),this.loopBtn.classList.toggle("active",this.isLooping))}cycleSpeed(){if(!this.timeline)return;this.speedIndex=(this.speedIndex+1)%u.length;const t=u[this.speedIndex];this.timeline.timeScale(t),this.speedBtn.textContent=`${t}x`}toggleCollapse(){this.collapsed=!this.collapsed,this.container.classList.toggle("collapsed",this.collapsed);const t=this.shadow.querySelector('[data-action="collapse"]');t.innerHTML=this.collapsed?'<svg viewBox="0 0 24 24"><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z"/></svg>':'<svg viewBox="0 0 24 24"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>'}updatePlayState(){if(!this.timeline)return;this.isPlaying=!this.timeline.paused()&&this.timeline.progress()<1;const t=this.playBtn.querySelector(".play-icon"),e=this.playBtn.querySelector(".pause-icon");t.style.display=this.isPlaying?"none":"block",e.style.display=this.isPlaying?"block":"none"}onTimelineUpdate(){this.updatePlayhead(),this.updateTimeDisplay(),this.updateActiveTracks(),this.updatePlayState()}updatePlayhead(){if(!this.timeline||!this.timelineData)return;const t=this.timeline.progress();this.playhead.style.left=`${t*100}%`}updateTimeDisplay(){if(!this.timeline||!this.timelineData)return;const t=this.timeline.time(),e=this.timelineData.duration,i=this.timeDisplay.querySelector(".gtv-time-current"),a=this.timeDisplay.querySelector(".gtv-time-total");i.textContent=g(t),a.textContent=` / ${g(e)}`}updateActiveTracks(){if(!this.timeline||!this.timelineData)return;const t=this.timeline.time();this.tracksScroll.querySelectorAll(".gtv-track-bar").forEach((i,a)=>{const r=this.timelineData.tweens[a],d=t>=r.startTime&&t<=r.endTime,p=i.dataset.color;d?i.style.background=`var(--gtv-track-${p}-active)`:i.style.background=`var(--gtv-track-${p})`})}renderTracks(){if(!this.timelineData)return;const{duration:t,tweens:e}=this.timelineData,i=this.shadow.querySelector(".gtv-empty");i.style.display=e.length>0?"none":"flex",this.renderRuler(t);const a=e.map(d=>this.renderTrack(d,t)).join(""),r=this.tracksScroll.querySelector(".gtv-scrub-area");this.tracksScroll.innerHTML=a,this.tracksScroll.prepend(r),this.scrubArea=r}renderRuler(t){const e=[],i=this.calculateInterval(t);for(let a=0;a<=t;a+=i){const r=a/t*100;e.push(`
|
|
65
|
+
<div class="gtv-ruler-marker" style="left: ${r}%;">
|
|
61
66
|
<div class="gtv-ruler-marker-line"></div>
|
|
62
|
-
<span class="gtv-ruler-marker-label">${g(
|
|
67
|
+
<span class="gtv-ruler-marker-label">${g(a,!1)}s</span>
|
|
63
68
|
</div>
|
|
64
|
-
`)}this.rulerInner.innerHTML=e.join("")}calculateInterval(t){return t<=1?.25:t<=3?.5:t<=10?1:t<=30?5:10}renderTrack(t,e){const
|
|
69
|
+
`)}this.rulerInner.innerHTML=e.join("")}calculateInterval(t){return t<=1?.25:t<=3?.5:t<=10?1:t<=30?5:10}renderTrack(t,e){const i=t.startTime/e*100,a=t.duration/e*100,r=t.colorIndex+1;return`
|
|
65
70
|
<div class="gtv-track">
|
|
66
71
|
<div class="gtv-track-bar"
|
|
67
|
-
|
|
72
|
+
data-color="${r}"
|
|
73
|
+
style="left: ${i}%; width: ${a}%; background: var(--gtv-track-${r});"
|
|
68
74
|
title="${t.label} (${g(t.startTime)}s - ${g(t.endTime)}s)">
|
|
69
75
|
${t.label}
|
|
70
76
|
</div>
|
|
71
77
|
</div>
|
|
72
|
-
`}}customElements.define("gsap-timeline-viewer",m);class
|
|
78
|
+
`}}customElements.define("gsap-timeline-viewer",m);class z{constructor(s){n(this,"element");this.element=document.createElement("gsap-timeline-viewer"),s.height&&this.element.style.setProperty("--viewer-height",`${s.height}px`),s.timeline&&setTimeout(()=>{this.element.setTimeline(s.timeline)},0)}attach(s=document.body){s.appendChild(this.element)}detach(){this.element.remove()}setTimeline(s){this.element.setTimeline(s)}get htmlElement(){return this.element}}return o.TimelineViewer=z,o.TimelineViewerElement=m,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),o}({});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
let
|
|
5
|
-
function m(
|
|
6
|
-
if (!
|
|
7
|
-
const
|
|
8
|
-
return
|
|
1
|
+
var b = Object.defineProperty;
|
|
2
|
+
var k = (r, i, t) => i in r ? b(r, i, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[i] = t;
|
|
3
|
+
var n = (r, i, t) => k(r, typeof i != "symbol" ? i + "" : i, t);
|
|
4
|
+
let f = 0;
|
|
5
|
+
function m(r) {
|
|
6
|
+
if (!r || r.length === 0) return "Unknown";
|
|
7
|
+
const i = r[0];
|
|
8
|
+
return i.id ? `#${i.id}` : i.classList && i.classList.length > 0 ? `.${i.classList[0]}` : i.tagName ? i.tagName.toLowerCase() : "element";
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
const
|
|
10
|
+
function x(r) {
|
|
11
|
+
const i = [
|
|
12
12
|
"ease",
|
|
13
13
|
"duration",
|
|
14
14
|
"delay",
|
|
@@ -31,74 +31,69 @@ function k(a) {
|
|
|
31
31
|
"reversed",
|
|
32
32
|
"startAt"
|
|
33
33
|
];
|
|
34
|
-
return Object.keys(
|
|
34
|
+
return Object.keys(r).filter((t) => !i.includes(t));
|
|
35
35
|
}
|
|
36
|
-
function
|
|
37
|
-
const
|
|
38
|
-
return
|
|
39
|
-
if (!("targets" in
|
|
40
|
-
const
|
|
36
|
+
function w(r) {
|
|
37
|
+
const i = [];
|
|
38
|
+
return r.getChildren(!0, !0, !1).forEach((e, s) => {
|
|
39
|
+
if (!("targets" in e)) return;
|
|
40
|
+
const a = e, l = a.targets(), o = a.vars || {}, c = x(o);
|
|
41
41
|
let h = "";
|
|
42
42
|
if (o.id && typeof o.id == "string")
|
|
43
43
|
h = o.id;
|
|
44
44
|
else {
|
|
45
|
-
const v = m(l), u =
|
|
45
|
+
const v = m(l), u = c.slice(0, 2).join(", ");
|
|
46
46
|
h = u ? `${v} (${u})` : v;
|
|
47
47
|
}
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
id: `tween-${++
|
|
48
|
+
const p = e.startTime(), g = e.duration();
|
|
49
|
+
i.push({
|
|
50
|
+
id: `tween-${++f}`,
|
|
51
51
|
label: h,
|
|
52
|
-
startTime:
|
|
53
|
-
endTime:
|
|
54
|
-
duration:
|
|
52
|
+
startTime: p,
|
|
53
|
+
endTime: p + g,
|
|
54
|
+
duration: g,
|
|
55
55
|
targets: m(l),
|
|
56
|
-
properties:
|
|
57
|
-
colorIndex:
|
|
56
|
+
properties: c,
|
|
57
|
+
colorIndex: s % 6
|
|
58
58
|
});
|
|
59
59
|
}), {
|
|
60
|
-
duration:
|
|
61
|
-
tweens:
|
|
60
|
+
duration: r.duration(),
|
|
61
|
+
tweens: i
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
-
function
|
|
65
|
-
|
|
64
|
+
function S() {
|
|
65
|
+
f = 0;
|
|
66
66
|
}
|
|
67
|
-
function
|
|
68
|
-
const t = Math.abs(
|
|
69
|
-
return
|
|
67
|
+
function d(r, i = !0) {
|
|
68
|
+
const t = Math.abs(r);
|
|
69
|
+
return i ? t.toFixed(2) : t.toFixed(0);
|
|
70
70
|
}
|
|
71
|
-
const T = ":host{--gtv-bg: #1a1a1a;--gtv-bg-secondary: #252525;--gtv-border: #333;--gtv-text: #e0e0e0;--gtv-text-muted: #888;--gtv-accent:
|
|
72
|
-
|
|
73
|
-
"var(--gtv-track-2)",
|
|
74
|
-
"var(--gtv-track-3)",
|
|
75
|
-
"var(--gtv-track-4)",
|
|
76
|
-
"var(--gtv-track-5)",
|
|
77
|
-
"var(--gtv-track-6)"
|
|
78
|
-
], b = [0.25, 0.5, 1, 2, 4];
|
|
79
|
-
class P extends HTMLElement {
|
|
71
|
+
const T = ":host{--gtv-bg: #1a1a1a;--gtv-bg-secondary: #252525;--gtv-border: #333;--gtv-text: #e0e0e0;--gtv-text-muted: #888;--gtv-accent: oklch(65% .15 220);--gtv-playhead: oklch(65% .15 220);--gtv-ruler-bg: #1f1f1f;--gtv-track-height: 28px;--gtv-controls-height: 40px;--gtv-ruler-height: 24px;--gtv-timeline-padding: 16px;--gtv-track-1: oklch(50% .12 220);--gtv-track-1-active: oklch(60% .15 220);--gtv-track-2: oklch(50% .12 70);--gtv-track-2-active: oklch(60% .15 70);--gtv-track-3: oklch(50% .12 350);--gtv-track-3-active: oklch(60% .15 350);--gtv-track-4: oklch(50% .12 160);--gtv-track-4-active: oklch(60% .15 160);--gtv-track-5: oklch(50% .12 290);--gtv-track-5-active: oklch(60% .15 290);--gtv-track-6: oklch(50% .12 25);--gtv-track-6-active: oklch(60% .15 25)}*{box-sizing:border-box;margin:0;padding:0}.gtv-container{position:fixed;bottom:0;left:0;right:0;background:var(--gtv-bg);border-top:1px solid var(--gtv-border);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:12px;color:var(--gtv-text);z-index:999999;display:flex;flex-direction:column;user-select:none;-webkit-user-select:none}.gtv-container.collapsed{height:auto!important}.gtv-container.collapsed .gtv-timeline-area{display:none}.gtv-controls{position:relative;display:flex;align-items:center;justify-content:center;height:var(--gtv-controls-height);padding:0 12px;background:var(--gtv-bg-secondary);border-bottom:1px solid var(--gtv-border);gap:8px}.gtv-controls-left{position:absolute;left:12px;display:flex;align-items:center;gap:8px}.gtv-controls-center{display:flex;align-items:center;gap:8px}.gtv-controls-right{position:absolute;right:12px;display:flex;align-items:center;gap:8px}.gtv-time-display{font-variant-numeric:tabular-nums;min-width:100px;text-align:center}.gtv-time-current{color:var(--gtv-text)}.gtv-time-total{color:var(--gtv-text-muted)}.gtv-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;background:transparent;border:none;border-radius:4px;color:var(--gtv-text);cursor:pointer;transition:background .15s}.gtv-btn:hover{background:#ffffff1a}.gtv-btn:active{background:#ffffff26}.gtv-btn.active{color:var(--gtv-accent)}.gtv-btn svg{width:16px;height:16px;fill:currentColor}.gtv-btn-play svg{width:20px;height:20px}.gtv-speed-btn{width:auto;padding:0 8px;font-size:11px;font-weight:500}.gtv-collapse-btn{margin-left:auto}.gtv-timeline-area{position:relative;display:flex;flex-direction:column;overflow:hidden;flex:1}.gtv-resize-handle{position:absolute;top:0;left:0;right:0;height:6px;cursor:ns-resize;z-index:20}.gtv-resize-handle:hover,.gtv-resize-handle:active{background:#ffffff1a}.gtv-ruler{position:relative;height:var(--gtv-ruler-height);background:var(--gtv-ruler-bg);border-bottom:1px solid var(--gtv-border);overflow:visible;flex-shrink:0;padding:0 var(--gtv-timeline-padding)}.gtv-ruler-inner{position:relative;height:100%;width:100%}.gtv-ruler-marker{position:absolute;top:0;height:100%;display:flex;flex-direction:column;align-items:center}.gtv-ruler-marker-line{width:1px;height:6px;background:var(--gtv-text-muted)}.gtv-ruler-marker-label{font-size:10px;color:var(--gtv-text-muted);margin-top:2px}.gtv-tracks-container{position:relative;overflow-y:auto;overflow-x:hidden;flex:1;padding:0 var(--gtv-timeline-padding)}.gtv-tracks-scroll{position:relative;min-height:100%;width:100%}.gtv-track{position:relative;height:var(--gtv-track-height)}.gtv-track-bar{position:absolute;top:4px;height:calc(var(--gtv-track-height) - 8px);border-radius:4px;display:flex;align-items:center;padding:0 8px;font-size:11px;font-weight:500;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:default;transition:filter .15s}.gtv-track-bar:hover{filter:brightness(1.1)}.gtv-playhead-wrapper{position:absolute;top:0;bottom:0;left:var(--gtv-timeline-padding);right:var(--gtv-timeline-padding);pointer-events:none;z-index:15}.gtv-playhead{position:absolute;top:0;bottom:0;width:0;left:0}.gtv-playhead-head{position:absolute;top:6px;left:-5px;width:11px;height:11px;background:var(--gtv-playhead);clip-path:polygon(50% 100%,0 0,100% 0)}.gtv-playhead-line{position:absolute;top:6px;bottom:0;left:0;width:1px;background:var(--gtv-playhead)}.gtv-scrub-area{position:absolute;top:0;left:0;right:0;bottom:0;cursor:ew-resize}.gtv-empty{display:flex;align-items:center;justify-content:center;padding:24px;color:var(--gtv-text-muted)}", y = [0.25, 0.5, 1, 2, 4];
|
|
72
|
+
class z extends HTMLElement {
|
|
80
73
|
constructor() {
|
|
81
74
|
super();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
75
|
+
n(this, "shadow");
|
|
76
|
+
n(this, "timeline", null);
|
|
77
|
+
n(this, "timelineData", null);
|
|
78
|
+
n(this, "isPlaying", !1);
|
|
79
|
+
n(this, "isLooping", !1);
|
|
80
|
+
n(this, "speedIndex", 2);
|
|
88
81
|
// 1x
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
82
|
+
n(this, "collapsed", !1);
|
|
83
|
+
n(this, "height", 200);
|
|
84
|
+
n(this, "isDragging", !1);
|
|
92
85
|
// DOM references
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
86
|
+
n(this, "container");
|
|
87
|
+
n(this, "playBtn");
|
|
88
|
+
n(this, "loopBtn");
|
|
89
|
+
n(this, "speedBtn");
|
|
90
|
+
n(this, "timeDisplay");
|
|
91
|
+
n(this, "rulerInner");
|
|
92
|
+
n(this, "tracksScroll");
|
|
93
|
+
n(this, "playhead");
|
|
94
|
+
n(this, "scrubArea");
|
|
95
|
+
n(this, "resizeHandle");
|
|
96
|
+
n(this, "isResizing", !1);
|
|
102
97
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
103
98
|
}
|
|
104
99
|
connectedCallback() {
|
|
@@ -108,7 +103,7 @@ class P extends HTMLElement {
|
|
|
108
103
|
this.detachTimeline();
|
|
109
104
|
}
|
|
110
105
|
setTimeline(t) {
|
|
111
|
-
this.detachTimeline(), this.timeline = t,
|
|
106
|
+
this.detachTimeline(), this.timeline = t, S(), this.timelineData = w(t), t.eventCallback("onUpdate", () => this.onTimelineUpdate()), this.renderTracks(), this.updatePlayhead(), this.updateTimeDisplay(), this.updatePlayState();
|
|
112
107
|
}
|
|
113
108
|
detachTimeline() {
|
|
114
109
|
this.timeline && (this.timeline.eventCallback("onUpdate", null), this.timeline = null, this.timelineData = null);
|
|
@@ -120,10 +115,21 @@ class P extends HTMLElement {
|
|
|
120
115
|
<!-- Controls Bar -->
|
|
121
116
|
<div class="gtv-controls">
|
|
122
117
|
<div class="gtv-controls-left">
|
|
118
|
+
<button class="gtv-btn" data-action="loop" title="Loop (L)">
|
|
119
|
+
<svg viewBox="0 0 24 24"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></svg>
|
|
120
|
+
</button>
|
|
121
|
+
<button class="gtv-btn gtv-speed-btn" data-action="speed" title="Playback speed">1x</button>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div class="gtv-controls-center">
|
|
125
|
+
<span class="gtv-time-display">
|
|
126
|
+
<span class="gtv-time-current">0.00</span>
|
|
127
|
+
<span class="gtv-time-total"> / 0.00</span>
|
|
128
|
+
</span>
|
|
123
129
|
<button class="gtv-btn" data-action="skip-start" title="Skip to start">
|
|
124
130
|
<svg viewBox="0 0 24 24"><path d="M6 6h2v12H6V6zm3.5 6l8.5 6V6l-8.5 6z"/></svg>
|
|
125
131
|
</button>
|
|
126
|
-
<button class="gtv-btn gtv-btn-play" data-action="play" title="Play/Pause">
|
|
132
|
+
<button class="gtv-btn gtv-btn-play" data-action="play" title="Play/Pause (Space)">
|
|
127
133
|
<svg class="play-icon" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>
|
|
128
134
|
<svg class="pause-icon" viewBox="0 0 24 24" style="display: none;"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
|
|
129
135
|
</button>
|
|
@@ -132,17 +138,6 @@ class P extends HTMLElement {
|
|
|
132
138
|
</button>
|
|
133
139
|
</div>
|
|
134
140
|
|
|
135
|
-
<div class="gtv-controls-center">
|
|
136
|
-
<button class="gtv-btn" data-action="loop" title="Loop">
|
|
137
|
-
<svg viewBox="0 0 24 24"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></svg>
|
|
138
|
-
</button>
|
|
139
|
-
<span class="gtv-time-display">
|
|
140
|
-
<span class="gtv-time-current">0.00</span>
|
|
141
|
-
<span class="gtv-time-total"> / 0.00</span>
|
|
142
|
-
</span>
|
|
143
|
-
<button class="gtv-btn gtv-speed-btn" data-action="speed" title="Playback speed">1x</button>
|
|
144
|
-
</div>
|
|
145
|
-
|
|
146
141
|
<div class="gtv-controls-right">
|
|
147
142
|
<button class="gtv-btn gtv-collapse-btn" data-action="collapse" title="Collapse/Expand">
|
|
148
143
|
<svg viewBox="0 0 24 24"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>
|
|
@@ -152,33 +147,38 @@ class P extends HTMLElement {
|
|
|
152
147
|
|
|
153
148
|
<!-- Timeline Area -->
|
|
154
149
|
<div class="gtv-timeline-area">
|
|
150
|
+
<!-- Resize Handle -->
|
|
151
|
+
<div class="gtv-resize-handle"></div>
|
|
152
|
+
|
|
155
153
|
<!-- Ruler -->
|
|
156
154
|
<div class="gtv-ruler">
|
|
157
155
|
<div class="gtv-ruler-inner"></div>
|
|
158
|
-
<div class="gtv-playhead-container">
|
|
159
|
-
<div class="gtv-playhead-head"></div>
|
|
160
|
-
</div>
|
|
161
156
|
</div>
|
|
162
157
|
|
|
163
158
|
<!-- Tracks -->
|
|
164
159
|
<div class="gtv-tracks-container">
|
|
165
160
|
<div class="gtv-tracks-scroll">
|
|
166
161
|
<div class="gtv-scrub-area"></div>
|
|
167
|
-
<div class="gtv-playhead-container">
|
|
168
|
-
<div class="gtv-playhead-line"></div>
|
|
169
|
-
</div>
|
|
170
162
|
</div>
|
|
171
163
|
<div class="gtv-empty">No timeline attached. Call setTimeline() to visualize a GSAP timeline.</div>
|
|
172
164
|
</div>
|
|
165
|
+
|
|
166
|
+
<!-- Playhead spans entire timeline area -->
|
|
167
|
+
<div class="gtv-playhead-wrapper">
|
|
168
|
+
<div class="gtv-playhead">
|
|
169
|
+
<div class="gtv-playhead-head"></div>
|
|
170
|
+
<div class="gtv-playhead-line"></div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
173
|
</div>
|
|
174
174
|
</div>
|
|
175
|
-
`, this.container = this.shadow.querySelector(".gtv-container"), this.playBtn = this.shadow.querySelector('[data-action="play"]'), this.loopBtn = this.shadow.querySelector('[data-action="loop"]'), this.speedBtn = this.shadow.querySelector('[data-action="speed"]'), this.timeDisplay = this.shadow.querySelector(".gtv-time-display"), this.rulerInner = this.shadow.querySelector(".gtv-ruler-inner"), this.tracksScroll = this.shadow.querySelector(".gtv-tracks-scroll"), this.playhead = this.shadow.querySelector(".gtv-
|
|
175
|
+
`, this.container = this.shadow.querySelector(".gtv-container"), this.playBtn = this.shadow.querySelector('[data-action="play"]'), this.loopBtn = this.shadow.querySelector('[data-action="loop"]'), this.speedBtn = this.shadow.querySelector('[data-action="speed"]'), this.timeDisplay = this.shadow.querySelector(".gtv-time-display"), this.rulerInner = this.shadow.querySelector(".gtv-ruler-inner"), this.tracksScroll = this.shadow.querySelector(".gtv-tracks-scroll"), this.playhead = this.shadow.querySelector(".gtv-playhead"), this.scrubArea = this.shadow.querySelector(".gtv-scrub-area"), this.resizeHandle = this.shadow.querySelector(".gtv-resize-handle");
|
|
176
176
|
}
|
|
177
177
|
setupEventListeners() {
|
|
178
178
|
this.shadow.addEventListener("click", (t) => {
|
|
179
|
-
const
|
|
180
|
-
if (!
|
|
181
|
-
switch (
|
|
179
|
+
const s = t.target.closest("[data-action]");
|
|
180
|
+
if (!s) return;
|
|
181
|
+
switch (s.dataset.action) {
|
|
182
182
|
case "play":
|
|
183
183
|
this.togglePlay();
|
|
184
184
|
break;
|
|
@@ -198,23 +198,52 @@ class P extends HTMLElement {
|
|
|
198
198
|
this.toggleCollapse();
|
|
199
199
|
break;
|
|
200
200
|
}
|
|
201
|
-
}), this.scrubArea.addEventListener("mousedown", (t) => this.startScrub(t)), this.shadow.querySelector(".gtv-ruler").addEventListener("mousedown", (t) => this.startScrub(t)), document.addEventListener("mousemove", (t) =>
|
|
202
|
-
|
|
201
|
+
}), this.scrubArea.addEventListener("mousedown", (t) => this.startScrub(t)), this.shadow.querySelector(".gtv-ruler").addEventListener("mousedown", (t) => this.startScrub(t)), document.addEventListener("mousemove", (t) => {
|
|
202
|
+
this.onScrub(t), this.onResize(t);
|
|
203
|
+
}), document.addEventListener("mouseup", () => {
|
|
204
|
+
this.endScrub(), this.endResize();
|
|
205
|
+
}), this.resizeHandle.addEventListener("mousedown", (t) => this.startResize(t)), document.addEventListener("keydown", (t) => {
|
|
206
|
+
if (t.target === document.body)
|
|
207
|
+
switch (t.code) {
|
|
208
|
+
case "Space":
|
|
209
|
+
t.preventDefault(), this.togglePlay();
|
|
210
|
+
break;
|
|
211
|
+
case "KeyJ":
|
|
212
|
+
t.preventDefault(), this.jumpToPrevPoint();
|
|
213
|
+
break;
|
|
214
|
+
case "KeyK":
|
|
215
|
+
t.preventDefault(), this.jumpToNextPoint();
|
|
216
|
+
break;
|
|
217
|
+
case "KeyL":
|
|
218
|
+
t.preventDefault(), this.toggleLoop();
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
203
221
|
});
|
|
204
222
|
}
|
|
205
223
|
startScrub(t) {
|
|
206
|
-
this.timeline && (this.isDragging = !0, this.scrubToPosition(t));
|
|
224
|
+
this.timeline && (t.preventDefault(), this.isDragging = !0, document.body.style.cursor = "ew-resize", document.body.style.userSelect = "none", this.scrubToPosition(t));
|
|
207
225
|
}
|
|
208
226
|
onScrub(t) {
|
|
209
227
|
!this.isDragging || !this.timeline || this.scrubToPosition(t);
|
|
210
228
|
}
|
|
211
229
|
endScrub() {
|
|
212
|
-
this.isDragging = !1;
|
|
230
|
+
this.isDragging = !1, document.body.style.cursor = "", document.body.style.userSelect = "";
|
|
231
|
+
}
|
|
232
|
+
startResize(t) {
|
|
233
|
+
t.preventDefault(), this.isResizing = !0, document.body.style.cursor = "ns-resize", document.body.style.userSelect = "none";
|
|
234
|
+
}
|
|
235
|
+
onResize(t) {
|
|
236
|
+
if (!this.isResizing) return;
|
|
237
|
+
const e = window.innerHeight, s = e - t.clientY;
|
|
238
|
+
this.height = Math.max(100, Math.min(s, e - 100)), this.container.style.height = `${this.height}px`;
|
|
239
|
+
}
|
|
240
|
+
endResize() {
|
|
241
|
+
this.isResizing && (this.isResizing = !1, document.body.style.cursor = "", document.body.style.userSelect = "");
|
|
213
242
|
}
|
|
214
243
|
scrubToPosition(t) {
|
|
215
244
|
if (!this.timeline || !this.timelineData) return;
|
|
216
|
-
const
|
|
217
|
-
this.timeline.progress(
|
|
245
|
+
const e = this.rulerInner.getBoundingClientRect(), a = Math.max(0, Math.min(t.clientX - e.left, e.width)) / e.width;
|
|
246
|
+
this.timeline.progress(a), this.timeline.pause(), this.updatePlayState();
|
|
218
247
|
}
|
|
219
248
|
togglePlay() {
|
|
220
249
|
this.timeline && (this.timeline.paused() || this.timeline.progress() === 1 ? this.timeline.progress() === 1 ? this.timeline.restart() : this.timeline.play() : this.timeline.pause(), this.updatePlayState());
|
|
@@ -225,13 +254,42 @@ class P extends HTMLElement {
|
|
|
225
254
|
skipToEnd() {
|
|
226
255
|
this.timeline && (this.timeline.progress(1), this.timeline.pause(), this.updatePlayState());
|
|
227
256
|
}
|
|
257
|
+
getTimePoints() {
|
|
258
|
+
if (!this.timelineData) return [0];
|
|
259
|
+
const t = /* @__PURE__ */ new Set();
|
|
260
|
+
return t.add(0), t.add(Math.round(this.timelineData.duration * 1e3) / 1e3), this.timelineData.tweens.forEach((e) => {
|
|
261
|
+
t.add(Math.round(e.startTime * 1e3) / 1e3), t.add(Math.round(e.endTime * 1e3) / 1e3);
|
|
262
|
+
}), Array.from(t).sort((e, s) => e - s);
|
|
263
|
+
}
|
|
264
|
+
jumpToPrevPoint() {
|
|
265
|
+
if (!this.timeline || !this.timelineData) return;
|
|
266
|
+
const t = Math.round(this.timeline.time() * 1e3) / 1e3, e = this.getTimePoints();
|
|
267
|
+
let s = 0;
|
|
268
|
+
for (const a of e)
|
|
269
|
+
if (a < t - 1e-3)
|
|
270
|
+
s = a;
|
|
271
|
+
else
|
|
272
|
+
break;
|
|
273
|
+
this.timeline.time(s), this.timeline.pause(), this.updatePlayState();
|
|
274
|
+
}
|
|
275
|
+
jumpToNextPoint() {
|
|
276
|
+
if (!this.timeline || !this.timelineData) return;
|
|
277
|
+
const t = Math.round(this.timeline.time() * 1e3) / 1e3, e = this.getTimePoints();
|
|
278
|
+
let s = this.timelineData.duration;
|
|
279
|
+
for (const a of e)
|
|
280
|
+
if (a > t + 1e-3) {
|
|
281
|
+
s = a;
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
this.timeline.time(s), this.timeline.pause(), this.updatePlayState();
|
|
285
|
+
}
|
|
228
286
|
toggleLoop() {
|
|
229
287
|
this.timeline && (this.isLooping = !this.isLooping, this.timeline.repeat(this.isLooping ? -1 : 0), this.loopBtn.classList.toggle("active", this.isLooping));
|
|
230
288
|
}
|
|
231
289
|
cycleSpeed() {
|
|
232
290
|
if (!this.timeline) return;
|
|
233
|
-
this.speedIndex = (this.speedIndex + 1) %
|
|
234
|
-
const t =
|
|
291
|
+
this.speedIndex = (this.speedIndex + 1) % y.length;
|
|
292
|
+
const t = y[this.speedIndex];
|
|
235
293
|
this.timeline.timeScale(t), this.speedBtn.textContent = `${t}x`;
|
|
236
294
|
}
|
|
237
295
|
toggleCollapse() {
|
|
@@ -242,90 +300,89 @@ class P extends HTMLElement {
|
|
|
242
300
|
updatePlayState() {
|
|
243
301
|
if (!this.timeline) return;
|
|
244
302
|
this.isPlaying = !this.timeline.paused() && this.timeline.progress() < 1;
|
|
245
|
-
const t = this.playBtn.querySelector(".play-icon"),
|
|
246
|
-
t.style.display = this.isPlaying ? "none" : "block",
|
|
303
|
+
const t = this.playBtn.querySelector(".play-icon"), e = this.playBtn.querySelector(".pause-icon");
|
|
304
|
+
t.style.display = this.isPlaying ? "none" : "block", e.style.display = this.isPlaying ? "block" : "none";
|
|
247
305
|
}
|
|
248
306
|
onTimelineUpdate() {
|
|
249
307
|
this.updatePlayhead(), this.updateTimeDisplay(), this.updateActiveTracks(), this.updatePlayState();
|
|
250
308
|
}
|
|
251
309
|
updatePlayhead() {
|
|
252
310
|
if (!this.timeline || !this.timelineData) return;
|
|
253
|
-
const
|
|
254
|
-
this.playhead.style.left =
|
|
255
|
-
const r = this.tracksScroll.querySelector(".gtv-playhead-container");
|
|
256
|
-
r && (r.style.left = i);
|
|
311
|
+
const t = this.timeline.progress();
|
|
312
|
+
this.playhead.style.left = `${t * 100}%`;
|
|
257
313
|
}
|
|
258
314
|
updateTimeDisplay() {
|
|
259
315
|
if (!this.timeline || !this.timelineData) return;
|
|
260
|
-
const t = this.timeline.time(),
|
|
261
|
-
|
|
316
|
+
const t = this.timeline.time(), e = this.timelineData.duration, s = this.timeDisplay.querySelector(".gtv-time-current"), a = this.timeDisplay.querySelector(".gtv-time-total");
|
|
317
|
+
s.textContent = d(t), a.textContent = ` / ${d(e)}`;
|
|
262
318
|
}
|
|
263
319
|
updateActiveTracks() {
|
|
264
320
|
if (!this.timeline || !this.timelineData) return;
|
|
265
321
|
const t = this.timeline.time();
|
|
266
|
-
this.tracksScroll.querySelectorAll(".gtv-track-bar").forEach((
|
|
267
|
-
const l = this.timelineData.tweens[
|
|
268
|
-
|
|
322
|
+
this.tracksScroll.querySelectorAll(".gtv-track-bar").forEach((s, a) => {
|
|
323
|
+
const l = this.timelineData.tweens[a], o = t >= l.startTime && t <= l.endTime, c = s.dataset.color;
|
|
324
|
+
o ? s.style.background = `var(--gtv-track-${c}-active)` : s.style.background = `var(--gtv-track-${c})`;
|
|
269
325
|
});
|
|
270
326
|
}
|
|
271
327
|
renderTracks() {
|
|
272
328
|
if (!this.timelineData) return;
|
|
273
|
-
const { duration: t, tweens:
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
this.tracksScroll.innerHTML =
|
|
329
|
+
const { duration: t, tweens: e } = this.timelineData, s = this.shadow.querySelector(".gtv-empty");
|
|
330
|
+
s.style.display = e.length > 0 ? "none" : "flex", this.renderRuler(t);
|
|
331
|
+
const a = e.map((o) => this.renderTrack(o, t)).join(""), l = this.tracksScroll.querySelector(".gtv-scrub-area");
|
|
332
|
+
this.tracksScroll.innerHTML = a, this.tracksScroll.prepend(l), this.scrubArea = l;
|
|
277
333
|
}
|
|
278
334
|
renderRuler(t) {
|
|
279
|
-
const
|
|
280
|
-
for (let
|
|
281
|
-
const l =
|
|
282
|
-
|
|
335
|
+
const e = [], s = this.calculateInterval(t);
|
|
336
|
+
for (let a = 0; a <= t; a += s) {
|
|
337
|
+
const l = a / t * 100;
|
|
338
|
+
e.push(`
|
|
283
339
|
<div class="gtv-ruler-marker" style="left: ${l}%;">
|
|
284
340
|
<div class="gtv-ruler-marker-line"></div>
|
|
285
|
-
<span class="gtv-ruler-marker-label">${
|
|
341
|
+
<span class="gtv-ruler-marker-label">${d(a, !1)}s</span>
|
|
286
342
|
</div>
|
|
287
343
|
`);
|
|
288
344
|
}
|
|
289
|
-
this.rulerInner.innerHTML =
|
|
345
|
+
this.rulerInner.innerHTML = e.join("");
|
|
290
346
|
}
|
|
291
347
|
calculateInterval(t) {
|
|
292
348
|
return t <= 1 ? 0.25 : t <= 3 ? 0.5 : t <= 10 ? 1 : t <= 30 ? 5 : 10;
|
|
293
349
|
}
|
|
294
|
-
renderTrack(t,
|
|
295
|
-
const
|
|
350
|
+
renderTrack(t, e) {
|
|
351
|
+
const s = t.startTime / e * 100, a = t.duration / e * 100, l = t.colorIndex + 1;
|
|
296
352
|
return `
|
|
297
353
|
<div class="gtv-track">
|
|
298
354
|
<div class="gtv-track-bar"
|
|
299
|
-
|
|
300
|
-
|
|
355
|
+
data-color="${l}"
|
|
356
|
+
style="left: ${s}%; width: ${a}%; background: var(--gtv-track-${l});"
|
|
357
|
+
title="${t.label} (${d(t.startTime)}s - ${d(t.endTime)}s)">
|
|
301
358
|
${t.label}
|
|
302
359
|
</div>
|
|
303
360
|
</div>
|
|
304
361
|
`;
|
|
305
362
|
}
|
|
306
363
|
}
|
|
307
|
-
customElements.define("gsap-timeline-viewer",
|
|
308
|
-
class
|
|
309
|
-
constructor(
|
|
310
|
-
|
|
311
|
-
this.element = document.createElement("gsap-timeline-viewer"),
|
|
312
|
-
this.element.setTimeline(
|
|
364
|
+
customElements.define("gsap-timeline-viewer", z);
|
|
365
|
+
class L {
|
|
366
|
+
constructor(i) {
|
|
367
|
+
n(this, "element");
|
|
368
|
+
this.element = document.createElement("gsap-timeline-viewer"), i.height && this.element.style.setProperty("--viewer-height", `${i.height}px`), i.timeline && setTimeout(() => {
|
|
369
|
+
this.element.setTimeline(i.timeline);
|
|
313
370
|
}, 0);
|
|
314
371
|
}
|
|
315
|
-
attach(
|
|
316
|
-
|
|
372
|
+
attach(i = document.body) {
|
|
373
|
+
i.appendChild(this.element);
|
|
317
374
|
}
|
|
318
375
|
detach() {
|
|
319
376
|
this.element.remove();
|
|
320
377
|
}
|
|
321
|
-
setTimeline(
|
|
322
|
-
this.element.setTimeline(
|
|
378
|
+
setTimeline(i) {
|
|
379
|
+
this.element.setTimeline(i);
|
|
323
380
|
}
|
|
324
381
|
get htmlElement() {
|
|
325
382
|
return this.element;
|
|
326
383
|
}
|
|
327
384
|
}
|
|
328
385
|
export {
|
|
329
|
-
|
|
330
|
-
|
|
386
|
+
L as TimelineViewer,
|
|
387
|
+
z as TimelineViewerElement
|
|
331
388
|
};
|
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
(function(l,
|
|
1
|
+
(function(l,r){typeof exports=="object"&&typeof module<"u"?r(exports):typeof define=="function"&&define.amd?define(["exports"],r):(l=typeof globalThis<"u"?globalThis:l||self,r(l.GSAPTimelineViewer={}))})(this,function(l){"use strict";var P=Object.defineProperty;var L=(l,r,h)=>r in l?P(l,r,{enumerable:!0,configurable:!0,writable:!0,value:h}):l[r]=h;var n=(l,r,h)=>L(l,typeof r!="symbol"?r+"":r,h);let r=0;function h(c){if(!c||c.length===0)return"Unknown";const s=c[0];return s.id?`#${s.id}`:s.classList&&s.classList.length>0?`.${s.classList[0]}`:s.tagName?s.tagName.toLowerCase():"element"}function x(c){const s=["ease","duration","delay","onComplete","onStart","onUpdate","onCompleteParams","onStartParams","onUpdateParams","repeat","repeatDelay","yoyo","stagger","overwrite","immediateRender","lazy","autoAlpha","id","paused","reversed","startAt"];return Object.keys(c).filter(t=>!s.includes(t))}function w(c){const s=[];return c.getChildren(!0,!0,!1).forEach((e,i)=>{if(!("targets"in e))return;const a=e,o=a.targets(),d=a.vars||{},g=x(d);let v="";if(d.id&&typeof d.id=="string")v=d.id;else{const b=h(o),k=g.slice(0,2).join(", ");v=k?`${b} (${k})`:b}const f=e.startTime(),y=e.duration();s.push({id:`tween-${++r}`,label:v,startTime:f,endTime:f+y,duration:y,targets:h(o),properties:g,colorIndex:i%6})}),{duration:c.duration(),tweens:s}}function S(){r=0}function p(c,s=!0){const t=Math.abs(c);return s?t.toFixed(2):t.toFixed(0)}const T=":host{--gtv-bg: #1a1a1a;--gtv-bg-secondary: #252525;--gtv-border: #333;--gtv-text: #e0e0e0;--gtv-text-muted: #888;--gtv-accent: oklch(65% .15 220);--gtv-playhead: oklch(65% .15 220);--gtv-ruler-bg: #1f1f1f;--gtv-track-height: 28px;--gtv-controls-height: 40px;--gtv-ruler-height: 24px;--gtv-timeline-padding: 16px;--gtv-track-1: oklch(50% .12 220);--gtv-track-1-active: oklch(60% .15 220);--gtv-track-2: oklch(50% .12 70);--gtv-track-2-active: oklch(60% .15 70);--gtv-track-3: oklch(50% .12 350);--gtv-track-3-active: oklch(60% .15 350);--gtv-track-4: oklch(50% .12 160);--gtv-track-4-active: oklch(60% .15 160);--gtv-track-5: oklch(50% .12 290);--gtv-track-5-active: oklch(60% .15 290);--gtv-track-6: oklch(50% .12 25);--gtv-track-6-active: oklch(60% .15 25)}*{box-sizing:border-box;margin:0;padding:0}.gtv-container{position:fixed;bottom:0;left:0;right:0;background:var(--gtv-bg);border-top:1px solid var(--gtv-border);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:12px;color:var(--gtv-text);z-index:999999;display:flex;flex-direction:column;user-select:none;-webkit-user-select:none}.gtv-container.collapsed{height:auto!important}.gtv-container.collapsed .gtv-timeline-area{display:none}.gtv-controls{position:relative;display:flex;align-items:center;justify-content:center;height:var(--gtv-controls-height);padding:0 12px;background:var(--gtv-bg-secondary);border-bottom:1px solid var(--gtv-border);gap:8px}.gtv-controls-left{position:absolute;left:12px;display:flex;align-items:center;gap:8px}.gtv-controls-center{display:flex;align-items:center;gap:8px}.gtv-controls-right{position:absolute;right:12px;display:flex;align-items:center;gap:8px}.gtv-time-display{font-variant-numeric:tabular-nums;min-width:100px;text-align:center}.gtv-time-current{color:var(--gtv-text)}.gtv-time-total{color:var(--gtv-text-muted)}.gtv-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;background:transparent;border:none;border-radius:4px;color:var(--gtv-text);cursor:pointer;transition:background .15s}.gtv-btn:hover{background:#ffffff1a}.gtv-btn:active{background:#ffffff26}.gtv-btn.active{color:var(--gtv-accent)}.gtv-btn svg{width:16px;height:16px;fill:currentColor}.gtv-btn-play svg{width:20px;height:20px}.gtv-speed-btn{width:auto;padding:0 8px;font-size:11px;font-weight:500}.gtv-collapse-btn{margin-left:auto}.gtv-timeline-area{position:relative;display:flex;flex-direction:column;overflow:hidden;flex:1}.gtv-resize-handle{position:absolute;top:0;left:0;right:0;height:6px;cursor:ns-resize;z-index:20}.gtv-resize-handle:hover,.gtv-resize-handle:active{background:#ffffff1a}.gtv-ruler{position:relative;height:var(--gtv-ruler-height);background:var(--gtv-ruler-bg);border-bottom:1px solid var(--gtv-border);overflow:visible;flex-shrink:0;padding:0 var(--gtv-timeline-padding)}.gtv-ruler-inner{position:relative;height:100%;width:100%}.gtv-ruler-marker{position:absolute;top:0;height:100%;display:flex;flex-direction:column;align-items:center}.gtv-ruler-marker-line{width:1px;height:6px;background:var(--gtv-text-muted)}.gtv-ruler-marker-label{font-size:10px;color:var(--gtv-text-muted);margin-top:2px}.gtv-tracks-container{position:relative;overflow-y:auto;overflow-x:hidden;flex:1;padding:0 var(--gtv-timeline-padding)}.gtv-tracks-scroll{position:relative;min-height:100%;width:100%}.gtv-track{position:relative;height:var(--gtv-track-height)}.gtv-track-bar{position:absolute;top:4px;height:calc(var(--gtv-track-height) - 8px);border-radius:4px;display:flex;align-items:center;padding:0 8px;font-size:11px;font-weight:500;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:default;transition:filter .15s}.gtv-track-bar:hover{filter:brightness(1.1)}.gtv-playhead-wrapper{position:absolute;top:0;bottom:0;left:var(--gtv-timeline-padding);right:var(--gtv-timeline-padding);pointer-events:none;z-index:15}.gtv-playhead{position:absolute;top:0;bottom:0;width:0;left:0}.gtv-playhead-head{position:absolute;top:6px;left:-5px;width:11px;height:11px;background:var(--gtv-playhead);clip-path:polygon(50% 100%,0 0,100% 0)}.gtv-playhead-line{position:absolute;top:6px;bottom:0;left:0;width:1px;background:var(--gtv-playhead)}.gtv-scrub-area{position:absolute;top:0;left:0;right:0;bottom:0;cursor:ew-resize}.gtv-empty{display:flex;align-items:center;justify-content:center;padding:24px;color:var(--gtv-text-muted)}",u=[.25,.5,1,2,4];class m extends HTMLElement{constructor(){super();n(this,"shadow");n(this,"timeline",null);n(this,"timelineData",null);n(this,"isPlaying",!1);n(this,"isLooping",!1);n(this,"speedIndex",2);n(this,"collapsed",!1);n(this,"height",200);n(this,"isDragging",!1);n(this,"container");n(this,"playBtn");n(this,"loopBtn");n(this,"speedBtn");n(this,"timeDisplay");n(this,"rulerInner");n(this,"tracksScroll");n(this,"playhead");n(this,"scrubArea");n(this,"resizeHandle");n(this,"isResizing",!1);this.shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){this.detachTimeline()}setTimeline(t){this.detachTimeline(),this.timeline=t,S(),this.timelineData=w(t),t.eventCallback("onUpdate",()=>this.onTimelineUpdate()),this.renderTracks(),this.updatePlayhead(),this.updateTimeDisplay(),this.updatePlayState()}detachTimeline(){this.timeline&&(this.timeline.eventCallback("onUpdate",null),this.timeline=null,this.timelineData=null)}render(){this.shadow.innerHTML=`
|
|
2
2
|
<style>${T}</style>
|
|
3
3
|
<div class="gtv-container ${this.collapsed?"collapsed":""}" style="height: ${this.height}px;">
|
|
4
4
|
<!-- Controls Bar -->
|
|
5
5
|
<div class="gtv-controls">
|
|
6
6
|
<div class="gtv-controls-left">
|
|
7
|
+
<button class="gtv-btn" data-action="loop" title="Loop (L)">
|
|
8
|
+
<svg viewBox="0 0 24 24"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></svg>
|
|
9
|
+
</button>
|
|
10
|
+
<button class="gtv-btn gtv-speed-btn" data-action="speed" title="Playback speed">1x</button>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="gtv-controls-center">
|
|
14
|
+
<span class="gtv-time-display">
|
|
15
|
+
<span class="gtv-time-current">0.00</span>
|
|
16
|
+
<span class="gtv-time-total"> / 0.00</span>
|
|
17
|
+
</span>
|
|
7
18
|
<button class="gtv-btn" data-action="skip-start" title="Skip to start">
|
|
8
19
|
<svg viewBox="0 0 24 24"><path d="M6 6h2v12H6V6zm3.5 6l8.5 6V6l-8.5 6z"/></svg>
|
|
9
20
|
</button>
|
|
10
|
-
<button class="gtv-btn gtv-btn-play" data-action="play" title="Play/Pause">
|
|
21
|
+
<button class="gtv-btn gtv-btn-play" data-action="play" title="Play/Pause (Space)">
|
|
11
22
|
<svg class="play-icon" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>
|
|
12
23
|
<svg class="pause-icon" viewBox="0 0 24 24" style="display: none;"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
|
|
13
24
|
</button>
|
|
@@ -16,17 +27,6 @@
|
|
|
16
27
|
</button>
|
|
17
28
|
</div>
|
|
18
29
|
|
|
19
|
-
<div class="gtv-controls-center">
|
|
20
|
-
<button class="gtv-btn" data-action="loop" title="Loop">
|
|
21
|
-
<svg viewBox="0 0 24 24"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></svg>
|
|
22
|
-
</button>
|
|
23
|
-
<span class="gtv-time-display">
|
|
24
|
-
<span class="gtv-time-current">0.00</span>
|
|
25
|
-
<span class="gtv-time-total"> / 0.00</span>
|
|
26
|
-
</span>
|
|
27
|
-
<button class="gtv-btn gtv-speed-btn" data-action="speed" title="Playback speed">1x</button>
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
30
|
<div class="gtv-controls-right">
|
|
31
31
|
<button class="gtv-btn gtv-collapse-btn" data-action="collapse" title="Collapse/Expand">
|
|
32
32
|
<svg viewBox="0 0 24 24"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>
|
|
@@ -36,37 +36,43 @@
|
|
|
36
36
|
|
|
37
37
|
<!-- Timeline Area -->
|
|
38
38
|
<div class="gtv-timeline-area">
|
|
39
|
+
<!-- Resize Handle -->
|
|
40
|
+
<div class="gtv-resize-handle"></div>
|
|
41
|
+
|
|
39
42
|
<!-- Ruler -->
|
|
40
43
|
<div class="gtv-ruler">
|
|
41
44
|
<div class="gtv-ruler-inner"></div>
|
|
42
|
-
<div class="gtv-playhead-container">
|
|
43
|
-
<div class="gtv-playhead-head"></div>
|
|
44
|
-
</div>
|
|
45
45
|
</div>
|
|
46
46
|
|
|
47
47
|
<!-- Tracks -->
|
|
48
48
|
<div class="gtv-tracks-container">
|
|
49
49
|
<div class="gtv-tracks-scroll">
|
|
50
50
|
<div class="gtv-scrub-area"></div>
|
|
51
|
-
<div class="gtv-playhead-container">
|
|
52
|
-
<div class="gtv-playhead-line"></div>
|
|
53
|
-
</div>
|
|
54
51
|
</div>
|
|
55
52
|
<div class="gtv-empty">No timeline attached. Call setTimeline() to visualize a GSAP timeline.</div>
|
|
56
53
|
</div>
|
|
54
|
+
|
|
55
|
+
<!-- Playhead spans entire timeline area -->
|
|
56
|
+
<div class="gtv-playhead-wrapper">
|
|
57
|
+
<div class="gtv-playhead">
|
|
58
|
+
<div class="gtv-playhead-head"></div>
|
|
59
|
+
<div class="gtv-playhead-line"></div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
57
62
|
</div>
|
|
58
63
|
</div>
|
|
59
|
-
`,this.container=this.shadow.querySelector(".gtv-container"),this.playBtn=this.shadow.querySelector('[data-action="play"]'),this.loopBtn=this.shadow.querySelector('[data-action="loop"]'),this.speedBtn=this.shadow.querySelector('[data-action="speed"]'),this.timeDisplay=this.shadow.querySelector(".gtv-time-display"),this.rulerInner=this.shadow.querySelector(".gtv-ruler-inner"),this.tracksScroll=this.shadow.querySelector(".gtv-tracks-scroll"),this.playhead=this.shadow.querySelector(".gtv-
|
|
60
|
-
<div class="gtv-ruler-marker" style="left: ${
|
|
64
|
+
`,this.container=this.shadow.querySelector(".gtv-container"),this.playBtn=this.shadow.querySelector('[data-action="play"]'),this.loopBtn=this.shadow.querySelector('[data-action="loop"]'),this.speedBtn=this.shadow.querySelector('[data-action="speed"]'),this.timeDisplay=this.shadow.querySelector(".gtv-time-display"),this.rulerInner=this.shadow.querySelector(".gtv-ruler-inner"),this.tracksScroll=this.shadow.querySelector(".gtv-tracks-scroll"),this.playhead=this.shadow.querySelector(".gtv-playhead"),this.scrubArea=this.shadow.querySelector(".gtv-scrub-area"),this.resizeHandle=this.shadow.querySelector(".gtv-resize-handle")}setupEventListeners(){this.shadow.addEventListener("click",t=>{const i=t.target.closest("[data-action]");if(!i)return;switch(i.dataset.action){case"play":this.togglePlay();break;case"skip-start":this.skipToStart();break;case"skip-end":this.skipToEnd();break;case"loop":this.toggleLoop();break;case"speed":this.cycleSpeed();break;case"collapse":this.toggleCollapse();break}}),this.scrubArea.addEventListener("mousedown",t=>this.startScrub(t)),this.shadow.querySelector(".gtv-ruler").addEventListener("mousedown",t=>this.startScrub(t)),document.addEventListener("mousemove",t=>{this.onScrub(t),this.onResize(t)}),document.addEventListener("mouseup",()=>{this.endScrub(),this.endResize()}),this.resizeHandle.addEventListener("mousedown",t=>this.startResize(t)),document.addEventListener("keydown",t=>{if(t.target===document.body)switch(t.code){case"Space":t.preventDefault(),this.togglePlay();break;case"KeyJ":t.preventDefault(),this.jumpToPrevPoint();break;case"KeyK":t.preventDefault(),this.jumpToNextPoint();break;case"KeyL":t.preventDefault(),this.toggleLoop();break}})}startScrub(t){this.timeline&&(t.preventDefault(),this.isDragging=!0,document.body.style.cursor="ew-resize",document.body.style.userSelect="none",this.scrubToPosition(t))}onScrub(t){!this.isDragging||!this.timeline||this.scrubToPosition(t)}endScrub(){this.isDragging=!1,document.body.style.cursor="",document.body.style.userSelect=""}startResize(t){t.preventDefault(),this.isResizing=!0,document.body.style.cursor="ns-resize",document.body.style.userSelect="none"}onResize(t){if(!this.isResizing)return;const e=window.innerHeight,i=e-t.clientY;this.height=Math.max(100,Math.min(i,e-100)),this.container.style.height=`${this.height}px`}endResize(){this.isResizing&&(this.isResizing=!1,document.body.style.cursor="",document.body.style.userSelect="")}scrubToPosition(t){if(!this.timeline||!this.timelineData)return;const e=this.rulerInner.getBoundingClientRect(),a=Math.max(0,Math.min(t.clientX-e.left,e.width))/e.width;this.timeline.progress(a),this.timeline.pause(),this.updatePlayState()}togglePlay(){this.timeline&&(this.timeline.paused()||this.timeline.progress()===1?this.timeline.progress()===1?this.timeline.restart():this.timeline.play():this.timeline.pause(),this.updatePlayState())}skipToStart(){this.timeline&&(this.timeline.progress(0),this.timeline.pause(),this.updatePlayState())}skipToEnd(){this.timeline&&(this.timeline.progress(1),this.timeline.pause(),this.updatePlayState())}getTimePoints(){if(!this.timelineData)return[0];const t=new Set;return t.add(0),t.add(Math.round(this.timelineData.duration*1e3)/1e3),this.timelineData.tweens.forEach(e=>{t.add(Math.round(e.startTime*1e3)/1e3),t.add(Math.round(e.endTime*1e3)/1e3)}),Array.from(t).sort((e,i)=>e-i)}jumpToPrevPoint(){if(!this.timeline||!this.timelineData)return;const t=Math.round(this.timeline.time()*1e3)/1e3,e=this.getTimePoints();let i=0;for(const a of e)if(a<t-.001)i=a;else break;this.timeline.time(i),this.timeline.pause(),this.updatePlayState()}jumpToNextPoint(){if(!this.timeline||!this.timelineData)return;const t=Math.round(this.timeline.time()*1e3)/1e3,e=this.getTimePoints();let i=this.timelineData.duration;for(const a of e)if(a>t+.001){i=a;break}this.timeline.time(i),this.timeline.pause(),this.updatePlayState()}toggleLoop(){this.timeline&&(this.isLooping=!this.isLooping,this.timeline.repeat(this.isLooping?-1:0),this.loopBtn.classList.toggle("active",this.isLooping))}cycleSpeed(){if(!this.timeline)return;this.speedIndex=(this.speedIndex+1)%u.length;const t=u[this.speedIndex];this.timeline.timeScale(t),this.speedBtn.textContent=`${t}x`}toggleCollapse(){this.collapsed=!this.collapsed,this.container.classList.toggle("collapsed",this.collapsed);const t=this.shadow.querySelector('[data-action="collapse"]');t.innerHTML=this.collapsed?'<svg viewBox="0 0 24 24"><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z"/></svg>':'<svg viewBox="0 0 24 24"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>'}updatePlayState(){if(!this.timeline)return;this.isPlaying=!this.timeline.paused()&&this.timeline.progress()<1;const t=this.playBtn.querySelector(".play-icon"),e=this.playBtn.querySelector(".pause-icon");t.style.display=this.isPlaying?"none":"block",e.style.display=this.isPlaying?"block":"none"}onTimelineUpdate(){this.updatePlayhead(),this.updateTimeDisplay(),this.updateActiveTracks(),this.updatePlayState()}updatePlayhead(){if(!this.timeline||!this.timelineData)return;const t=this.timeline.progress();this.playhead.style.left=`${t*100}%`}updateTimeDisplay(){if(!this.timeline||!this.timelineData)return;const t=this.timeline.time(),e=this.timelineData.duration,i=this.timeDisplay.querySelector(".gtv-time-current"),a=this.timeDisplay.querySelector(".gtv-time-total");i.textContent=p(t),a.textContent=` / ${p(e)}`}updateActiveTracks(){if(!this.timeline||!this.timelineData)return;const t=this.timeline.time();this.tracksScroll.querySelectorAll(".gtv-track-bar").forEach((i,a)=>{const o=this.timelineData.tweens[a],d=t>=o.startTime&&t<=o.endTime,g=i.dataset.color;d?i.style.background=`var(--gtv-track-${g}-active)`:i.style.background=`var(--gtv-track-${g})`})}renderTracks(){if(!this.timelineData)return;const{duration:t,tweens:e}=this.timelineData,i=this.shadow.querySelector(".gtv-empty");i.style.display=e.length>0?"none":"flex",this.renderRuler(t);const a=e.map(d=>this.renderTrack(d,t)).join(""),o=this.tracksScroll.querySelector(".gtv-scrub-area");this.tracksScroll.innerHTML=a,this.tracksScroll.prepend(o),this.scrubArea=o}renderRuler(t){const e=[],i=this.calculateInterval(t);for(let a=0;a<=t;a+=i){const o=a/t*100;e.push(`
|
|
65
|
+
<div class="gtv-ruler-marker" style="left: ${o}%;">
|
|
61
66
|
<div class="gtv-ruler-marker-line"></div>
|
|
62
|
-
<span class="gtv-ruler-marker-label">${
|
|
67
|
+
<span class="gtv-ruler-marker-label">${p(a,!1)}s</span>
|
|
63
68
|
</div>
|
|
64
|
-
`)}this.rulerInner.innerHTML=e.join("")}calculateInterval(t){return t<=1?.25:t<=3?.5:t<=10?1:t<=30?5:10}renderTrack(t,e){const
|
|
69
|
+
`)}this.rulerInner.innerHTML=e.join("")}calculateInterval(t){return t<=1?.25:t<=3?.5:t<=10?1:t<=30?5:10}renderTrack(t,e){const i=t.startTime/e*100,a=t.duration/e*100,o=t.colorIndex+1;return`
|
|
65
70
|
<div class="gtv-track">
|
|
66
71
|
<div class="gtv-track-bar"
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
data-color="${o}"
|
|
73
|
+
style="left: ${i}%; width: ${a}%; background: var(--gtv-track-${o});"
|
|
74
|
+
title="${t.label} (${p(t.startTime)}s - ${p(t.endTime)}s)">
|
|
69
75
|
${t.label}
|
|
70
76
|
</div>
|
|
71
77
|
</div>
|
|
72
|
-
`}}customElements.define("gsap-timeline-viewer",m);class
|
|
78
|
+
`}}customElements.define("gsap-timeline-viewer",m);class z{constructor(s){n(this,"element");this.element=document.createElement("gsap-timeline-viewer"),s.height&&this.element.style.setProperty("--viewer-height",`${s.height}px`),s.timeline&&setTimeout(()=>{this.element.setTimeline(s.timeline)},0)}attach(s=document.body){s.appendChild(this.element)}detach(){this.element.remove()}setTimeline(s){this.element.setTimeline(s)}get htmlElement(){return this.element}}l.TimelineViewer=z,l.TimelineViewerElement=m,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export declare class TimelineViewerElement extends HTMLElement {
|
|
|
32
32
|
private tracksScroll;
|
|
33
33
|
private playhead;
|
|
34
34
|
private scrubArea;
|
|
35
|
+
private resizeHandle;
|
|
36
|
+
private isResizing;
|
|
35
37
|
constructor();
|
|
36
38
|
connectedCallback(): void;
|
|
37
39
|
disconnectedCallback(): void;
|
|
@@ -42,10 +44,16 @@ export declare class TimelineViewerElement extends HTMLElement {
|
|
|
42
44
|
private startScrub;
|
|
43
45
|
private onScrub;
|
|
44
46
|
private endScrub;
|
|
47
|
+
private startResize;
|
|
48
|
+
private onResize;
|
|
49
|
+
private endResize;
|
|
45
50
|
private scrubToPosition;
|
|
46
51
|
private togglePlay;
|
|
47
52
|
private skipToStart;
|
|
48
53
|
private skipToEnd;
|
|
54
|
+
private getTimePoints;
|
|
55
|
+
private jumpToPrevPoint;
|
|
56
|
+
private jumpToNextPoint;
|
|
49
57
|
private toggleLoop;
|
|
50
58
|
private cycleSpeed;
|
|
51
59
|
private toggleCollapse;
|