@scarlett-player/ui 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/dist/index.cjs +273 -51
- package/dist/index.d.cts +160 -2
- package/dist/index.d.ts +160 -2
- package/dist/index.js +269 -50
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -269,6 +269,37 @@ var styles = `
|
|
|
269
269
|
height: 5px;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
/* ============================================
|
|
273
|
+
Timeline extension layer (timeline-registry.ts)
|
|
274
|
+
|
|
275
|
+
A zero-height line lying exactly on the rail's centre, spanning exactly the
|
|
276
|
+
rail's width, so an extension can position by percentage and land on the
|
|
277
|
+
same pixels the seek slider maps a press to. The 10px offset is the rail
|
|
278
|
+
centre in BOTH wrapper modes: the fine-pointer wrapper is 20px tall with the
|
|
279
|
+
3px rail centred (8.5..11.5 from the bottom), and the coarse-pointer wrapper
|
|
280
|
+
is 44px tall with 8.5px of bottom padding and align-items: flex-end, which
|
|
281
|
+
puts the rail in the same place.
|
|
282
|
+
|
|
283
|
+
Inert by default: only the explicit hit targets an extension puts inside it
|
|
284
|
+
take pointer input, so an ordinary press on the rail still seeks.
|
|
285
|
+
============================================ */
|
|
286
|
+
.sp-progress__extension {
|
|
287
|
+
position: absolute;
|
|
288
|
+
left: 0;
|
|
289
|
+
right: 0;
|
|
290
|
+
bottom: 10px;
|
|
291
|
+
height: 0;
|
|
292
|
+
z-index: 3;
|
|
293
|
+
pointer-events: none;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* Editing reserves a lane below the rail for an extension's second handle, by
|
|
297
|
+
lifting the whole wrapper clear of the control bar. The lane above needs no
|
|
298
|
+
reservation - it is over the picture. */
|
|
299
|
+
.sp-progress-wrapper--editing {
|
|
300
|
+
bottom: calc(92px + var(--sp-inset-bottom, 0px));
|
|
301
|
+
}
|
|
302
|
+
|
|
272
303
|
.sp-progress__track {
|
|
273
304
|
position: absolute;
|
|
274
305
|
top: 0;
|
|
@@ -339,6 +370,19 @@ var styles = `
|
|
|
339
370
|
transform: translate(-50%, -50%) scale(1);
|
|
340
371
|
}
|
|
341
372
|
|
|
373
|
+
/* While an extension owns the pointer the bar must not also look like it is
|
|
374
|
+
scrubbing: the tooltip is suppressed inline by the control, and the handle
|
|
375
|
+
stops responding to hover growth.
|
|
376
|
+
|
|
377
|
+
This has to come after the :hover and --dragging rules AND match their
|
|
378
|
+
specificity, which is why the hover case is spelled out rather than left to
|
|
379
|
+
the bare class: an extension drag is a pointer drag, so the pointer is over
|
|
380
|
+
the wrapper the whole time and the hover rule is always the competing one. */
|
|
381
|
+
.sp-progress-wrapper--ext-dragging .sp-progress__handle,
|
|
382
|
+
.sp-progress-wrapper--ext-dragging:hover .sp-progress__handle {
|
|
383
|
+
transform: translate(-50%, -50%);
|
|
384
|
+
}
|
|
385
|
+
|
|
342
386
|
/* Thumbnail Preview */
|
|
343
387
|
.sp-thumbnail-preview {
|
|
344
388
|
position: absolute;
|
|
@@ -1492,9 +1536,46 @@ var ThumbnailPreview = class {
|
|
|
1492
1536
|
}
|
|
1493
1537
|
};
|
|
1494
1538
|
|
|
1539
|
+
// src/timeline-registry.ts
|
|
1540
|
+
var registrations = /* @__PURE__ */ new WeakMap();
|
|
1541
|
+
var hosts = /* @__PURE__ */ new WeakMap();
|
|
1542
|
+
function registerTimelineExtension(owner, factory) {
|
|
1543
|
+
const token = {};
|
|
1544
|
+
registrations.set(owner, { factory, token });
|
|
1545
|
+
hosts.get(owner)?.setFactory(factory);
|
|
1546
|
+
return () => {
|
|
1547
|
+
const current = registrations.get(owner);
|
|
1548
|
+
if (!current || current.token !== token) return;
|
|
1549
|
+
registrations.delete(owner);
|
|
1550
|
+
hosts.get(owner)?.setFactory(null);
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1553
|
+
function unregisterTimelineExtension(owner) {
|
|
1554
|
+
if (!registrations.has(owner)) return false;
|
|
1555
|
+
registrations.delete(owner);
|
|
1556
|
+
hosts.get(owner)?.setFactory(null);
|
|
1557
|
+
return true;
|
|
1558
|
+
}
|
|
1559
|
+
function hasTimelineExtension(owner) {
|
|
1560
|
+
return registrations.has(owner);
|
|
1561
|
+
}
|
|
1562
|
+
function attachTimelineHost(owner, host) {
|
|
1563
|
+
hosts.set(owner, host);
|
|
1564
|
+
const registration = registrations.get(owner);
|
|
1565
|
+
if (registration) host.setFactory(registration.factory);
|
|
1566
|
+
return () => {
|
|
1567
|
+
if (hosts.get(owner) === host) hosts.delete(owner);
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1495
1571
|
// src/controls/ProgressBar.ts
|
|
1572
|
+
var SEEK_KEYS = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "Home", "End"]);
|
|
1496
1573
|
var ProgressBar = class {
|
|
1497
|
-
|
|
1574
|
+
/**
|
|
1575
|
+
* @param api - The per-player plugin API
|
|
1576
|
+
* @param options - Optional hooks; see {@link ProgressBarOptions}
|
|
1577
|
+
*/
|
|
1578
|
+
constructor(api, options = {}) {
|
|
1498
1579
|
this.isDragging = false;
|
|
1499
1580
|
this.lastSeekTime = 0;
|
|
1500
1581
|
this.seekThrottleMs = 100;
|
|
@@ -1504,8 +1585,18 @@ var ProgressBar = class {
|
|
|
1504
1585
|
this.renderedChapters = null;
|
|
1505
1586
|
/** Duration the marker layer was last built against, since positions are a percentage of it. */
|
|
1506
1587
|
this.renderedDuration = 0;
|
|
1588
|
+
/** The mounted extension, or null when none is registered. */
|
|
1589
|
+
this.extension = null;
|
|
1590
|
+
/** Detaches this bar from the registry on destroy. */
|
|
1591
|
+
this.detachTimelineHost = null;
|
|
1592
|
+
/** True while the extension holds the pointer: ordinary seeking is suppressed. */
|
|
1593
|
+
this.extensionDragging = false;
|
|
1594
|
+
/** True while the extension is editing: the bar is held open and geometry reserved. */
|
|
1595
|
+
this.extensionEditing = false;
|
|
1507
1596
|
this.onMouseDown = (e) => {
|
|
1597
|
+
if (this.isExtensionInput(e)) return;
|
|
1508
1598
|
e.preventDefault();
|
|
1599
|
+
this.extension?.onSeekStart();
|
|
1509
1600
|
const video = getVideo(this.api.container);
|
|
1510
1601
|
this.wasPlayingBeforeDrag = video ? !video.paused : false;
|
|
1511
1602
|
this.isDragging = true;
|
|
@@ -1524,6 +1615,7 @@ var ProgressBar = class {
|
|
|
1524
1615
|
this.seek(e.clientX, true);
|
|
1525
1616
|
this.isDragging = false;
|
|
1526
1617
|
this.el.classList.remove("sp-progress--dragging");
|
|
1618
|
+
this.extension?.onSeekEnd();
|
|
1527
1619
|
if (this.wasPlayingBeforeDrag) {
|
|
1528
1620
|
const video = getVideo(this.api.container);
|
|
1529
1621
|
if (video && video.paused) {
|
|
@@ -1538,7 +1630,9 @@ var ProgressBar = class {
|
|
|
1538
1630
|
}
|
|
1539
1631
|
};
|
|
1540
1632
|
this.onTouchStart = (e) => {
|
|
1633
|
+
if (this.isExtensionInput(e)) return;
|
|
1541
1634
|
e.preventDefault();
|
|
1635
|
+
this.extension?.onSeekStart();
|
|
1542
1636
|
const video = getVideo(this.api.container);
|
|
1543
1637
|
this.wasPlayingBeforeDrag = video ? !video.paused : false;
|
|
1544
1638
|
this.isDragging = true;
|
|
@@ -1561,6 +1655,7 @@ var ProgressBar = class {
|
|
|
1561
1655
|
}
|
|
1562
1656
|
this.isDragging = false;
|
|
1563
1657
|
this.el.classList.remove("sp-progress--dragging");
|
|
1658
|
+
this.extension?.onSeekEnd();
|
|
1564
1659
|
if (this.wasPlayingBeforeDrag) {
|
|
1565
1660
|
const video = getVideo(this.api.container);
|
|
1566
1661
|
if (video && video.paused) {
|
|
@@ -1577,6 +1672,7 @@ var ProgressBar = class {
|
|
|
1577
1672
|
}
|
|
1578
1673
|
};
|
|
1579
1674
|
this.onMouseMove = (e) => {
|
|
1675
|
+
if (this.isExtensionInput(e)) return;
|
|
1580
1676
|
this.updateTooltip(e.clientX);
|
|
1581
1677
|
};
|
|
1582
1678
|
this.onMouseLeave = () => {
|
|
@@ -1588,51 +1684,16 @@ var ProgressBar = class {
|
|
|
1588
1684
|
this.onKeyDown = (e) => {
|
|
1589
1685
|
const video = getVideo(this.api.container);
|
|
1590
1686
|
if (!video) return;
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
e.preventDefault();
|
|
1598
|
-
video.currentTime = Math.max(seekableRange.start, video.currentTime - step);
|
|
1599
|
-
break;
|
|
1600
|
-
case "ArrowRight":
|
|
1601
|
-
e.preventDefault();
|
|
1602
|
-
video.currentTime = Math.min(seekableRange.end, video.currentTime + step);
|
|
1603
|
-
break;
|
|
1604
|
-
case "Home":
|
|
1605
|
-
e.preventDefault();
|
|
1606
|
-
video.currentTime = seekableRange.start;
|
|
1607
|
-
break;
|
|
1608
|
-
case "End":
|
|
1609
|
-
e.preventDefault();
|
|
1610
|
-
video.currentTime = seekableRange.end;
|
|
1611
|
-
break;
|
|
1612
|
-
}
|
|
1613
|
-
} else {
|
|
1614
|
-
const duration = this.api.getState("duration") || 0;
|
|
1615
|
-
switch (e.key) {
|
|
1616
|
-
case "ArrowLeft":
|
|
1617
|
-
e.preventDefault();
|
|
1618
|
-
video.currentTime = Math.max(0, video.currentTime - step);
|
|
1619
|
-
break;
|
|
1620
|
-
case "ArrowRight":
|
|
1621
|
-
e.preventDefault();
|
|
1622
|
-
video.currentTime = Math.min(duration, video.currentTime + step);
|
|
1623
|
-
break;
|
|
1624
|
-
case "Home":
|
|
1625
|
-
e.preventDefault();
|
|
1626
|
-
video.currentTime = 0;
|
|
1627
|
-
break;
|
|
1628
|
-
case "End":
|
|
1629
|
-
e.preventDefault();
|
|
1630
|
-
video.currentTime = duration;
|
|
1631
|
-
break;
|
|
1632
|
-
}
|
|
1687
|
+
if (!SEEK_KEYS.has(e.key)) return;
|
|
1688
|
+
this.extension?.onSeekStart();
|
|
1689
|
+
try {
|
|
1690
|
+
this.applyKeyboardSeek(e, video);
|
|
1691
|
+
} finally {
|
|
1692
|
+
this.extension?.onSeekEnd();
|
|
1633
1693
|
}
|
|
1634
1694
|
};
|
|
1635
1695
|
this.api = api;
|
|
1696
|
+
this.options = options;
|
|
1636
1697
|
this.wrapper = createElement("div", { className: "sp-progress-wrapper" });
|
|
1637
1698
|
this.el = createElement("div", { className: "sp-progress" });
|
|
1638
1699
|
const track = createElement("div", { className: "sp-progress__track" });
|
|
@@ -1651,6 +1712,8 @@ var ProgressBar = class {
|
|
|
1651
1712
|
this.el.appendChild(this.thumbnailPreview.getElement());
|
|
1652
1713
|
this.el.appendChild(this.tooltip);
|
|
1653
1714
|
this.wrapper.appendChild(this.el);
|
|
1715
|
+
this.extensionLayer = createElement("div", { className: "sp-progress__extension" });
|
|
1716
|
+
this.wrapper.appendChild(this.extensionLayer);
|
|
1654
1717
|
this.el.setAttribute("role", "slider");
|
|
1655
1718
|
this.el.setAttribute("aria-label", "Seek");
|
|
1656
1719
|
this.el.setAttribute("aria-valuemin", "0");
|
|
@@ -1668,6 +1731,90 @@ var ProgressBar = class {
|
|
|
1668
1731
|
document.addEventListener("touchmove", this.onDocTouchMove, { passive: false });
|
|
1669
1732
|
document.addEventListener("touchend", this.onTouchEnd);
|
|
1670
1733
|
document.addEventListener("touchcancel", this.onTouchEnd);
|
|
1734
|
+
this.detachTimelineHost = attachTimelineHost(this.api.container, {
|
|
1735
|
+
setFactory: (factory) => this.mountExtension(factory)
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
// --------------------------------------------------------------------------
|
|
1739
|
+
// Timeline extension seam
|
|
1740
|
+
// --------------------------------------------------------------------------
|
|
1741
|
+
/**
|
|
1742
|
+
* Mount a registered extension factory, replacing any predecessor.
|
|
1743
|
+
*
|
|
1744
|
+
* The previous extension is destroyed and every lease it held is released
|
|
1745
|
+
* first, so a replacement never inherits a stale editing or dragging state.
|
|
1746
|
+
*
|
|
1747
|
+
* @param factory - The factory to mount, or null to unmount
|
|
1748
|
+
*/
|
|
1749
|
+
mountExtension(factory) {
|
|
1750
|
+
if (this.extension) {
|
|
1751
|
+
this.extension.destroy();
|
|
1752
|
+
this.extension = null;
|
|
1753
|
+
this.setExtensionDragging(false);
|
|
1754
|
+
this.setExtensionEditing(false);
|
|
1755
|
+
this.extensionLayer.replaceChildren();
|
|
1756
|
+
}
|
|
1757
|
+
if (!factory) return;
|
|
1758
|
+
const surface = {
|
|
1759
|
+
element: this.extensionLayer,
|
|
1760
|
+
getRailRect: () => this.el.getBoundingClientRect(),
|
|
1761
|
+
setEditing: (active) => this.setExtensionEditing(active),
|
|
1762
|
+
setDragging: (active) => this.setExtensionDragging(active)
|
|
1763
|
+
};
|
|
1764
|
+
this.extension = factory(surface);
|
|
1765
|
+
this.extension.update();
|
|
1766
|
+
}
|
|
1767
|
+
/** Whether a registered extension is currently editing. */
|
|
1768
|
+
isTimelineEditing() {
|
|
1769
|
+
return this.extensionEditing;
|
|
1770
|
+
}
|
|
1771
|
+
/**
|
|
1772
|
+
* Apply the editing lease: reserve the handle lanes and hold the bar open.
|
|
1773
|
+
*
|
|
1774
|
+
* @param active - Whether the extension is editing
|
|
1775
|
+
*/
|
|
1776
|
+
setExtensionEditing(active) {
|
|
1777
|
+
if (this.extensionEditing === active) return;
|
|
1778
|
+
this.extensionEditing = active;
|
|
1779
|
+
this.wrapper.classList.toggle("sp-progress-wrapper--editing", active);
|
|
1780
|
+
if (active) this.show();
|
|
1781
|
+
this.options.onEditingChange?.(active);
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Apply the pointer lease: suppress ordinary seeking while the extension
|
|
1785
|
+
* owns the gesture, and get the hover tooltip out of the way.
|
|
1786
|
+
*
|
|
1787
|
+
* @param active - Whether the extension owns the pointer
|
|
1788
|
+
*/
|
|
1789
|
+
setExtensionDragging(active) {
|
|
1790
|
+
if (this.extensionDragging === active) return;
|
|
1791
|
+
this.extensionDragging = active;
|
|
1792
|
+
this.wrapper.classList.toggle("sp-progress-wrapper--ext-dragging", active);
|
|
1793
|
+
if (active) {
|
|
1794
|
+
this.isDragging = false;
|
|
1795
|
+
this.el.classList.remove("sp-progress--dragging");
|
|
1796
|
+
this.tooltip.style.opacity = "0";
|
|
1797
|
+
this.thumbnailPreview.hide();
|
|
1798
|
+
} else {
|
|
1799
|
+
this.tooltip.style.opacity = "";
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Whether an input event belongs to the extension rather than to seeking.
|
|
1804
|
+
*
|
|
1805
|
+
* Two independent reasons, and both are needed: the extension holds the
|
|
1806
|
+
* pointer lease (its drag has moved off its handle and onto the rail), or
|
|
1807
|
+
* the event started inside the extension layer at all. Touch and mouse
|
|
1808
|
+
* compatibility events replay a handle press as a wrapper press, and only
|
|
1809
|
+
* the target check catches those.
|
|
1810
|
+
*
|
|
1811
|
+
* @param event - The incoming pointer, mouse or touch event
|
|
1812
|
+
* @returns True when the timeline must not act on it
|
|
1813
|
+
*/
|
|
1814
|
+
isExtensionInput(event) {
|
|
1815
|
+
if (this.extensionDragging) return true;
|
|
1816
|
+
const target = event.target;
|
|
1817
|
+
return target instanceof Node && this.extensionLayer.contains(target);
|
|
1671
1818
|
}
|
|
1672
1819
|
render() {
|
|
1673
1820
|
return this.wrapper;
|
|
@@ -1727,6 +1874,7 @@ var ProgressBar = class {
|
|
|
1727
1874
|
this.el.setAttribute("aria-valuenow", String(Math.floor(currentTime)));
|
|
1728
1875
|
this.el.setAttribute("aria-valuetext", formatTime(currentTime));
|
|
1729
1876
|
}
|
|
1877
|
+
this.extension?.update();
|
|
1730
1878
|
}
|
|
1731
1879
|
/**
|
|
1732
1880
|
* Label of the chapter containing a point on the timeline.
|
|
@@ -1835,6 +1983,57 @@ var ProgressBar = class {
|
|
|
1835
1983
|
this.filled.style.width = `${percent * 100}%`;
|
|
1836
1984
|
this.handle.style.left = `${percent * 100}%`;
|
|
1837
1985
|
}
|
|
1986
|
+
/**
|
|
1987
|
+
* Apply one keyboard seek to the element.
|
|
1988
|
+
*
|
|
1989
|
+
* @param e - The key event (already known to be a seek key)
|
|
1990
|
+
* @param video - The player's media element
|
|
1991
|
+
*/
|
|
1992
|
+
applyKeyboardSeek(e, video) {
|
|
1993
|
+
const step = 5;
|
|
1994
|
+
const live = this.api.getState("live");
|
|
1995
|
+
const seekableRange = this.api.getState("seekableRange");
|
|
1996
|
+
if (live && seekableRange) {
|
|
1997
|
+
switch (e.key) {
|
|
1998
|
+
case "ArrowLeft":
|
|
1999
|
+
e.preventDefault();
|
|
2000
|
+
video.currentTime = Math.max(seekableRange.start, video.currentTime - step);
|
|
2001
|
+
break;
|
|
2002
|
+
case "ArrowRight":
|
|
2003
|
+
e.preventDefault();
|
|
2004
|
+
video.currentTime = Math.min(seekableRange.end, video.currentTime + step);
|
|
2005
|
+
break;
|
|
2006
|
+
case "Home":
|
|
2007
|
+
e.preventDefault();
|
|
2008
|
+
video.currentTime = seekableRange.start;
|
|
2009
|
+
break;
|
|
2010
|
+
case "End":
|
|
2011
|
+
e.preventDefault();
|
|
2012
|
+
video.currentTime = seekableRange.end;
|
|
2013
|
+
break;
|
|
2014
|
+
}
|
|
2015
|
+
} else {
|
|
2016
|
+
const duration = this.api.getState("duration") || 0;
|
|
2017
|
+
switch (e.key) {
|
|
2018
|
+
case "ArrowLeft":
|
|
2019
|
+
e.preventDefault();
|
|
2020
|
+
video.currentTime = Math.max(0, video.currentTime - step);
|
|
2021
|
+
break;
|
|
2022
|
+
case "ArrowRight":
|
|
2023
|
+
e.preventDefault();
|
|
2024
|
+
video.currentTime = Math.min(duration, video.currentTime + step);
|
|
2025
|
+
break;
|
|
2026
|
+
case "Home":
|
|
2027
|
+
e.preventDefault();
|
|
2028
|
+
video.currentTime = 0;
|
|
2029
|
+
break;
|
|
2030
|
+
case "End":
|
|
2031
|
+
e.preventDefault();
|
|
2032
|
+
video.currentTime = duration;
|
|
2033
|
+
break;
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
1838
2037
|
seek(clientX, force = false) {
|
|
1839
2038
|
const video = getVideo(this.api.container);
|
|
1840
2039
|
if (!video) return;
|
|
@@ -1849,6 +2048,10 @@ var ProgressBar = class {
|
|
|
1849
2048
|
}
|
|
1850
2049
|
}
|
|
1851
2050
|
destroy() {
|
|
2051
|
+
this.detachTimelineHost?.();
|
|
2052
|
+
this.detachTimelineHost = null;
|
|
2053
|
+
this.extension?.destroy();
|
|
2054
|
+
this.extension = null;
|
|
1852
2055
|
this.wrapper.removeEventListener("mousedown", this.onMouseDown);
|
|
1853
2056
|
this.wrapper.removeEventListener("mousemove", this.onMouseMove);
|
|
1854
2057
|
this.wrapper.removeEventListener("mouseleave", this.onMouseLeave);
|
|
@@ -3403,7 +3606,7 @@ function resetControlRegistry() {
|
|
|
3403
3606
|
}
|
|
3404
3607
|
|
|
3405
3608
|
// src/version.ts
|
|
3406
|
-
var PKG_VERSION = true ? "1.
|
|
3609
|
+
var PKG_VERSION = true ? "1.13.0" : "0.0.0-dev";
|
|
3407
3610
|
|
|
3408
3611
|
// src/index.ts
|
|
3409
3612
|
var DEFAULT_LAYOUT = [
|
|
@@ -3744,10 +3947,13 @@ function uiPlugin(config = {}) {
|
|
|
3744
3947
|
updateControls();
|
|
3745
3948
|
});
|
|
3746
3949
|
};
|
|
3747
|
-
const hasOpenMenu = () =>
|
|
3748
|
-
|
|
3749
|
-
return
|
|
3750
|
-
|
|
3950
|
+
const hasOpenMenu = () => {
|
|
3951
|
+
if (progressBar?.isTimelineEditing()) return true;
|
|
3952
|
+
return controls.some((control) => {
|
|
3953
|
+
const menu = control;
|
|
3954
|
+
return typeof menu.isMenuOpen === "function" && menu.isMenuOpen();
|
|
3955
|
+
});
|
|
3956
|
+
};
|
|
3751
3957
|
const showControls = () => {
|
|
3752
3958
|
if (controlsVisible) {
|
|
3753
3959
|
resetHideTimer();
|
|
@@ -3929,7 +4135,17 @@ function uiPlugin(config = {}) {
|
|
|
3929
4135
|
bigPlayButton = new BigPlayButton(api, () => errorOverlay?.isVisible() ?? false);
|
|
3930
4136
|
container.appendChild(bigPlayButton.render());
|
|
3931
4137
|
}
|
|
3932
|
-
progressBar = new ProgressBar(api
|
|
4138
|
+
progressBar = new ProgressBar(api, {
|
|
4139
|
+
// A timeline editor is on screen for as long as the viewer needs it,
|
|
4140
|
+
// which is longer than any hide delay. Holding visibility here rather
|
|
4141
|
+
// than through a control's isMenuOpen() is deliberate: an extension
|
|
4142
|
+
// can be opened from a host's own button, in a layout that lists no
|
|
4143
|
+
// matching control at all.
|
|
4144
|
+
onEditingChange: (active) => {
|
|
4145
|
+
if (active) showControls();
|
|
4146
|
+
else resetHideTimer();
|
|
4147
|
+
}
|
|
4148
|
+
});
|
|
3933
4149
|
container.appendChild(progressBar.render());
|
|
3934
4150
|
if (!isPlaying) {
|
|
3935
4151
|
progressBar.show();
|
|
@@ -4099,13 +4315,16 @@ export {
|
|
|
4099
4315
|
formatLiveTime,
|
|
4100
4316
|
formatTime,
|
|
4101
4317
|
getControlFactory,
|
|
4318
|
+
hasTimelineExtension,
|
|
4102
4319
|
icons,
|
|
4103
4320
|
planFit,
|
|
4104
4321
|
registerControl,
|
|
4322
|
+
registerTimelineExtension,
|
|
4105
4323
|
resetControlRegistry,
|
|
4106
4324
|
resolveFitItems,
|
|
4107
4325
|
styles,
|
|
4108
4326
|
uiPlugin,
|
|
4109
4327
|
unregisterControl,
|
|
4110
|
-
unregisterControlsFor
|
|
4328
|
+
unregisterControlsFor,
|
|
4329
|
+
unregisterTimelineExtension
|
|
4111
4330
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scarlett-player/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "UI Controls Plugin for Scarlett Player",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"typescript": "^5.3.0",
|
|
30
30
|
"vitest": "^1.6.0",
|
|
31
31
|
"jsdom": "^24.0.0",
|
|
32
|
-
"@scarlett-player/core": "1.
|
|
32
|
+
"@scarlett-player/core": "1.14.0"
|
|
33
33
|
},
|
|
34
34
|
"keywords": [
|
|
35
35
|
"video",
|