summit-kit
Version:
A React component library for building modern web applications with with an earthy and outdoorsy flair.
1,050 lines • 71.4 kB
JavaScript
import { jsxs as Q, Fragment as Y, jsx as x } from "react/jsx-runtime";
import { I as O } from "./index-DiM-Qsyc.js";
import { useEffect as C, useRef as q, useState as K, useCallback as F } from "react";
const Z = (v) => {
C(() => {
const m = new AbortController();
return window.addEventListener(
"keydown",
(n) => {
for (const a of v) {
const l = a.shortcutKey.includes("+"), f = a.shortcutKey.split("+");
if (l) {
const c = f.includes("Shift"), y = f.includes("Control"), p = f.includes("Meta"), _ = f.includes("Alt"), A = f.find(
(i) => i !== "Shift" && i !== "Control" && i !== "Meta" && i !== "Alt"
), e = n.key === A, t = n.shiftKey === c, r = n.ctrlKey === y, o = n.metaKey === p, u = n.altKey === _;
e && t && r && o && u && a.action && a.action();
} else
n.key === a.shortcutKey && a.action && a.action();
}
},
{
signal: m.signal
}
), () => {
m.abort();
};
});
}, E = {
"page-slider": "_page-slider_1xrrr_1",
"right-arrow": "_right-arrow_1xrrr_13",
"left-arrow": "_left-arrow_1xrrr_20",
"down-arrow": "_down-arrow_1xrrr_27",
"up-arrow": "_up-arrow_1xrrr_34"
}, te = ({
children: v,
onNext: m,
onPrev: n,
onUp: a,
onDown: l
}) => (Z([
{
shortcutKey: "Control+Shift+ArrowRight",
action: m
},
{
shortcutKey: "Control+Shift+ArrowLeft",
action: n
},
{
shortcutKey: "Control+Shift+ArrowUp",
action: a
},
{
shortcutKey: "Control+Shift+ArrowDown",
action: l
}
]), /* @__PURE__ */ Q(Y, { children: [
/* @__PURE__ */ x("div", { className: E["page-slider"], children: v || "Slider" }),
m && /* @__PURE__ */ x(
"button",
{
className: E["right-arrow"],
onClick: m,
onKeyDown: (f) => f.key === "Enter" && m(),
tabIndex: 0,
type: "button",
"aria-label": "Go to next page",
children: /* @__PURE__ */ x(O, { name: "FiArrowRightCircle", size: 48, color: "white" })
}
),
n && /* @__PURE__ */ x(
"button",
{
className: E["left-arrow"],
onClick: n,
onKeyDown: (f) => f.key === "Enter" && n(),
tabIndex: 0,
type: "button",
"aria-label": "Go to previous page",
children: /* @__PURE__ */ x(O, { name: "FiArrowLeftCircle", size: 48, color: "white" })
}
),
a && /* @__PURE__ */ x(
"button",
{
className: E["up-arrow"],
onClick: a,
onKeyDown: (f) => f.key === "Enter" && a(),
tabIndex: 0,
type: "button",
"aria-label": "Go up",
children: /* @__PURE__ */ x(O, { name: "FiArrowUpCircle", size: 48, color: "white" })
}
),
l && /* @__PURE__ */ x(
"button",
{
className: E["down-arrow"],
onClick: l,
onKeyDown: (f) => f.key === "Enter" && l(),
tabIndex: 0,
type: "button",
"aria-label": "Go down",
children: /* @__PURE__ */ x(O, { name: "FiArrowDownCircle", size: 48, color: "white" })
}
)
] }));
var P = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {}, B = {};
/*!
* howler.js v2.2.4
* howlerjs.com
*
* (c) 2013-2020, James Simpson of GoldFire Studios
* goldfirestudios.com
*
* MIT License
*/
var R;
function j() {
return R || (R = 1, function(v) {
(function() {
var m = function() {
this.init();
};
m.prototype = {
/**
* Initialize the global Howler object.
* @return {Howler}
*/
init: function() {
var e = this || n;
return e._counter = 1e3, e._html5AudioPool = [], e.html5PoolSize = 10, e._codecs = {}, e._howls = [], e._muted = !1, e._volume = 1, e._canPlayEvent = "canplaythrough", e._navigator = typeof window < "u" && window.navigator ? window.navigator : null, e.masterGain = null, e.noAudio = !1, e.usingWebAudio = !0, e.autoSuspend = !0, e.ctx = null, e.autoUnlock = !0, e._setup(), e;
},
/**
* Get/set the global volume for all sounds.
* @param {Float} vol Volume from 0.0 to 1.0.
* @return {Howler/Float} Returns self or current volume.
*/
volume: function(e) {
var t = this || n;
if (e = parseFloat(e), t.ctx || A(), typeof e < "u" && e >= 0 && e <= 1) {
if (t._volume = e, t._muted)
return t;
t.usingWebAudio && t.masterGain.gain.setValueAtTime(e, n.ctx.currentTime);
for (var r = 0; r < t._howls.length; r++)
if (!t._howls[r]._webAudio)
for (var o = t._howls[r]._getSoundIds(), u = 0; u < o.length; u++) {
var s = t._howls[r]._soundById(o[u]);
s && s._node && (s._node.volume = s._volume * e);
}
return t;
}
return t._volume;
},
/**
* Handle muting and unmuting globally.
* @param {Boolean} muted Is muted or not.
*/
mute: function(e) {
var t = this || n;
t.ctx || A(), t._muted = e, t.usingWebAudio && t.masterGain.gain.setValueAtTime(e ? 0 : t._volume, n.ctx.currentTime);
for (var r = 0; r < t._howls.length; r++)
if (!t._howls[r]._webAudio)
for (var o = t._howls[r]._getSoundIds(), u = 0; u < o.length; u++) {
var s = t._howls[r]._soundById(o[u]);
s && s._node && (s._node.muted = e ? !0 : s._muted);
}
return t;
},
/**
* Handle stopping all sounds globally.
*/
stop: function() {
for (var e = this || n, t = 0; t < e._howls.length; t++)
e._howls[t].stop();
return e;
},
/**
* Unload and destroy all currently loaded Howl objects.
* @return {Howler}
*/
unload: function() {
for (var e = this || n, t = e._howls.length - 1; t >= 0; t--)
e._howls[t].unload();
return e.usingWebAudio && e.ctx && typeof e.ctx.close < "u" && (e.ctx.close(), e.ctx = null, A()), e;
},
/**
* Check for codec support of specific extension.
* @param {String} ext Audio file extention.
* @return {Boolean}
*/
codecs: function(e) {
return (this || n)._codecs[e.replace(/^x-/, "")];
},
/**
* Setup various state values for global tracking.
* @return {Howler}
*/
_setup: function() {
var e = this || n;
if (e.state = e.ctx && e.ctx.state || "suspended", e._autoSuspend(), !e.usingWebAudio)
if (typeof Audio < "u")
try {
var t = new Audio();
typeof t.oncanplaythrough > "u" && (e._canPlayEvent = "canplay");
} catch {
e.noAudio = !0;
}
else
e.noAudio = !0;
try {
var t = new Audio();
t.muted && (e.noAudio = !0);
} catch {
}
return e.noAudio || e._setupCodecs(), e;
},
/**
* Check for browser support for various codecs and cache the results.
* @return {Howler}
*/
_setupCodecs: function() {
var e = this || n, t = null;
try {
t = typeof Audio < "u" ? new Audio() : null;
} catch {
return e;
}
if (!t || typeof t.canPlayType != "function")
return e;
var r = t.canPlayType("audio/mpeg;").replace(/^no$/, ""), o = e._navigator ? e._navigator.userAgent : "", u = o.match(/OPR\/(\d+)/g), s = u && parseInt(u[0].split("/")[1], 10) < 33, i = o.indexOf("Safari") !== -1 && o.indexOf("Chrome") === -1, d = o.match(/Version\/(.*?) /), h = i && d && parseInt(d[1], 10) < 15;
return e._codecs = {
mp3: !!(!s && (r || t.canPlayType("audio/mp3;").replace(/^no$/, ""))),
mpeg: !!r,
opus: !!t.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ""),
ogg: !!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
oga: !!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
wav: !!(t.canPlayType('audio/wav; codecs="1"') || t.canPlayType("audio/wav")).replace(/^no$/, ""),
aac: !!t.canPlayType("audio/aac;").replace(/^no$/, ""),
caf: !!t.canPlayType("audio/x-caf;").replace(/^no$/, ""),
m4a: !!(t.canPlayType("audio/x-m4a;") || t.canPlayType("audio/m4a;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""),
m4b: !!(t.canPlayType("audio/x-m4b;") || t.canPlayType("audio/m4b;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""),
mp4: !!(t.canPlayType("audio/x-mp4;") || t.canPlayType("audio/mp4;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""),
weba: !!(!h && t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")),
webm: !!(!h && t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")),
dolby: !!t.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ""),
flac: !!(t.canPlayType("audio/x-flac;") || t.canPlayType("audio/flac;")).replace(/^no$/, "")
}, e;
},
/**
* Some browsers/devices will only allow audio to be played after a user interaction.
* Attempt to automatically unlock audio on the first user interaction.
* Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/
* @return {Howler}
*/
_unlockAudio: function() {
var e = this || n;
if (!(e._audioUnlocked || !e.ctx)) {
e._audioUnlocked = !1, e.autoUnlock = !1, !e._mobileUnloaded && e.ctx.sampleRate !== 44100 && (e._mobileUnloaded = !0, e.unload()), e._scratchBuffer = e.ctx.createBuffer(1, 1, 22050);
var t = function(r) {
for (; e._html5AudioPool.length < e.html5PoolSize; )
try {
var o = new Audio();
o._unlocked = !0, e._releaseHtml5Audio(o);
} catch {
e.noAudio = !0;
break;
}
for (var u = 0; u < e._howls.length; u++)
if (!e._howls[u]._webAudio)
for (var s = e._howls[u]._getSoundIds(), i = 0; i < s.length; i++) {
var d = e._howls[u]._soundById(s[i]);
d && d._node && !d._node._unlocked && (d._node._unlocked = !0, d._node.load());
}
e._autoResume();
var h = e.ctx.createBufferSource();
h.buffer = e._scratchBuffer, h.connect(e.ctx.destination), typeof h.start > "u" ? h.noteOn(0) : h.start(0), typeof e.ctx.resume == "function" && e.ctx.resume(), h.onended = function() {
h.disconnect(0), e._audioUnlocked = !0, document.removeEventListener("touchstart", t, !0), document.removeEventListener("touchend", t, !0), document.removeEventListener("click", t, !0), document.removeEventListener("keydown", t, !0);
for (var w = 0; w < e._howls.length; w++)
e._howls[w]._emit("unlock");
};
};
return document.addEventListener("touchstart", t, !0), document.addEventListener("touchend", t, !0), document.addEventListener("click", t, !0), document.addEventListener("keydown", t, !0), e;
}
},
/**
* Get an unlocked HTML5 Audio object from the pool. If none are left,
* return a new Audio object and throw a warning.
* @return {Audio} HTML5 Audio object.
*/
_obtainHtml5Audio: function() {
var e = this || n;
if (e._html5AudioPool.length)
return e._html5AudioPool.pop();
var t = new Audio().play();
return t && typeof Promise < "u" && (t instanceof Promise || typeof t.then == "function") && t.catch(function() {
console.warn("HTML5 Audio pool exhausted, returning potentially locked audio object.");
}), new Audio();
},
/**
* Return an activated HTML5 Audio object to the pool.
* @return {Howler}
*/
_releaseHtml5Audio: function(e) {
var t = this || n;
return e._unlocked && t._html5AudioPool.push(e), t;
},
/**
* Automatically suspend the Web Audio AudioContext after no sound has played for 30 seconds.
* This saves processing/energy and fixes various browser-specific bugs with audio getting stuck.
* @return {Howler}
*/
_autoSuspend: function() {
var e = this;
if (!(!e.autoSuspend || !e.ctx || typeof e.ctx.suspend > "u" || !n.usingWebAudio)) {
for (var t = 0; t < e._howls.length; t++)
if (e._howls[t]._webAudio) {
for (var r = 0; r < e._howls[t]._sounds.length; r++)
if (!e._howls[t]._sounds[r]._paused)
return e;
}
return e._suspendTimer && clearTimeout(e._suspendTimer), e._suspendTimer = setTimeout(function() {
if (e.autoSuspend) {
e._suspendTimer = null, e.state = "suspending";
var o = function() {
e.state = "suspended", e._resumeAfterSuspend && (delete e._resumeAfterSuspend, e._autoResume());
};
e.ctx.suspend().then(o, o);
}
}, 3e4), e;
}
},
/**
* Automatically resume the Web Audio AudioContext when a new sound is played.
* @return {Howler}
*/
_autoResume: function() {
var e = this;
if (!(!e.ctx || typeof e.ctx.resume > "u" || !n.usingWebAudio))
return e.state === "running" && e.ctx.state !== "interrupted" && e._suspendTimer ? (clearTimeout(e._suspendTimer), e._suspendTimer = null) : e.state === "suspended" || e.state === "running" && e.ctx.state === "interrupted" ? (e.ctx.resume().then(function() {
e.state = "running";
for (var t = 0; t < e._howls.length; t++)
e._howls[t]._emit("resume");
}), e._suspendTimer && (clearTimeout(e._suspendTimer), e._suspendTimer = null)) : e.state === "suspending" && (e._resumeAfterSuspend = !0), e;
}
};
var n = new m(), a = function(e) {
var t = this;
if (!e.src || e.src.length === 0) {
console.error("An array of source files must be passed with any new Howl.");
return;
}
t.init(e);
};
a.prototype = {
/**
* Initialize a new Howl group object.
* @param {Object} o Passed in properties for this group.
* @return {Howl}
*/
init: function(e) {
var t = this;
return n.ctx || A(), t._autoplay = e.autoplay || !1, t._format = typeof e.format != "string" ? e.format : [e.format], t._html5 = e.html5 || !1, t._muted = e.mute || !1, t._loop = e.loop || !1, t._pool = e.pool || 5, t._preload = typeof e.preload == "boolean" || e.preload === "metadata" ? e.preload : !0, t._rate = e.rate || 1, t._sprite = e.sprite || {}, t._src = typeof e.src != "string" ? e.src : [e.src], t._volume = e.volume !== void 0 ? e.volume : 1, t._xhr = {
method: e.xhr && e.xhr.method ? e.xhr.method : "GET",
headers: e.xhr && e.xhr.headers ? e.xhr.headers : null,
withCredentials: e.xhr && e.xhr.withCredentials ? e.xhr.withCredentials : !1
}, t._duration = 0, t._state = "unloaded", t._sounds = [], t._endTimers = {}, t._queue = [], t._playLock = !1, t._onend = e.onend ? [{ fn: e.onend }] : [], t._onfade = e.onfade ? [{ fn: e.onfade }] : [], t._onload = e.onload ? [{ fn: e.onload }] : [], t._onloaderror = e.onloaderror ? [{ fn: e.onloaderror }] : [], t._onplayerror = e.onplayerror ? [{ fn: e.onplayerror }] : [], t._onpause = e.onpause ? [{ fn: e.onpause }] : [], t._onplay = e.onplay ? [{ fn: e.onplay }] : [], t._onstop = e.onstop ? [{ fn: e.onstop }] : [], t._onmute = e.onmute ? [{ fn: e.onmute }] : [], t._onvolume = e.onvolume ? [{ fn: e.onvolume }] : [], t._onrate = e.onrate ? [{ fn: e.onrate }] : [], t._onseek = e.onseek ? [{ fn: e.onseek }] : [], t._onunlock = e.onunlock ? [{ fn: e.onunlock }] : [], t._onresume = [], t._webAudio = n.usingWebAudio && !t._html5, typeof n.ctx < "u" && n.ctx && n.autoUnlock && n._unlockAudio(), n._howls.push(t), t._autoplay && t._queue.push({
event: "play",
action: function() {
t.play();
}
}), t._preload && t._preload !== "none" && t.load(), t;
},
/**
* Load the audio file.
* @return {Howler}
*/
load: function() {
var e = this, t = null;
if (n.noAudio) {
e._emit("loaderror", null, "No audio support.");
return;
}
typeof e._src == "string" && (e._src = [e._src]);
for (var r = 0; r < e._src.length; r++) {
var o, u;
if (e._format && e._format[r])
o = e._format[r];
else {
if (u = e._src[r], typeof u != "string") {
e._emit("loaderror", null, "Non-string found in selected audio sources - ignoring.");
continue;
}
o = /^data:audio\/([^;,]+);/i.exec(u), o || (o = /\.([^.]+)$/.exec(u.split("?", 1)[0])), o && (o = o[1].toLowerCase());
}
if (o || console.warn('No file extension was found. Consider using the "format" property or specify an extension.'), o && n.codecs(o)) {
t = e._src[r];
break;
}
}
if (!t) {
e._emit("loaderror", null, "No codec support for selected audio sources.");
return;
}
return e._src = t, e._state = "loading", window.location.protocol === "https:" && t.slice(0, 5) === "http:" && (e._html5 = !0, e._webAudio = !1), new l(e), e._webAudio && c(e), e;
},
/**
* Play a sound or resume previous playback.
* @param {String/Number} sprite Sprite name for sprite playback or sound id to continue previous.
* @param {Boolean} internal Internal Use: true prevents event firing.
* @return {Number} Sound ID.
*/
play: function(e, t) {
var r = this, o = null;
if (typeof e == "number")
o = e, e = null;
else {
if (typeof e == "string" && r._state === "loaded" && !r._sprite[e])
return null;
if (typeof e > "u" && (e = "__default", !r._playLock)) {
for (var u = 0, s = 0; s < r._sounds.length; s++)
r._sounds[s]._paused && !r._sounds[s]._ended && (u++, o = r._sounds[s]._id);
u === 1 ? e = null : o = null;
}
}
var i = o ? r._soundById(o) : r._inactiveSound();
if (!i)
return null;
if (o && !e && (e = i._sprite || "__default"), r._state !== "loaded") {
i._sprite = e, i._ended = !1;
var d = i._id;
return r._queue.push({
event: "play",
action: function() {
r.play(d);
}
}), d;
}
if (o && !i._paused)
return t || r._loadQueue("play"), i._id;
r._webAudio && n._autoResume();
var h = Math.max(0, i._seek > 0 ? i._seek : r._sprite[e][0] / 1e3), w = Math.max(0, (r._sprite[e][0] + r._sprite[e][1]) / 1e3 - h), T = w * 1e3 / Math.abs(i._rate), k = r._sprite[e][0] / 1e3, H = (r._sprite[e][0] + r._sprite[e][1]) / 1e3;
i._sprite = e, i._ended = !1;
var L = function() {
i._paused = !1, i._seek = h, i._start = k, i._stop = H, i._loop = !!(i._loop || r._sprite[e][2]);
};
if (h >= H) {
r._ended(i);
return;
}
var g = i._node;
if (r._webAudio) {
var D = function() {
r._playLock = !1, L(), r._refreshBuffer(i);
var I = i._muted || r._muted ? 0 : i._volume;
g.gain.setValueAtTime(I, n.ctx.currentTime), i._playStart = n.ctx.currentTime, typeof g.bufferSource.start > "u" ? i._loop ? g.bufferSource.noteGrainOn(0, h, 86400) : g.bufferSource.noteGrainOn(0, h, w) : i._loop ? g.bufferSource.start(0, h, 86400) : g.bufferSource.start(0, h, w), T !== 1 / 0 && (r._endTimers[i._id] = setTimeout(r._ended.bind(r, i), T)), t || setTimeout(function() {
r._emit("play", i._id), r._loadQueue();
}, 0);
};
n.state === "running" && n.ctx.state !== "interrupted" ? D() : (r._playLock = !0, r.once("resume", D), r._clearTimer(i._id));
} else {
var G = function() {
g.currentTime = h, g.muted = i._muted || r._muted || n._muted || g.muted, g.volume = i._volume * n.volume(), g.playbackRate = i._rate;
try {
var I = g.play();
if (I && typeof Promise < "u" && (I instanceof Promise || typeof I.then == "function") ? (r._playLock = !0, L(), I.then(function() {
r._playLock = !1, g._unlocked = !0, t ? r._loadQueue() : r._emit("play", i._id);
}).catch(function() {
r._playLock = !1, r._emit("playerror", i._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."), i._ended = !0, i._paused = !0;
})) : t || (r._playLock = !1, L(), r._emit("play", i._id)), g.playbackRate = i._rate, g.paused) {
r._emit("playerror", i._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");
return;
}
e !== "__default" || i._loop ? r._endTimers[i._id] = setTimeout(r._ended.bind(r, i), T) : (r._endTimers[i._id] = function() {
r._ended(i), g.removeEventListener("ended", r._endTimers[i._id], !1);
}, g.addEventListener("ended", r._endTimers[i._id], !1));
} catch (W) {
r._emit("playerror", i._id, W);
}
};
g.src === "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA" && (g.src = r._src, g.load());
var N = window && window.ejecta || !g.readyState && n._navigator.isCocoonJS;
if (g.readyState >= 3 || N)
G();
else {
r._playLock = !0, r._state = "loading";
var V = function() {
r._state = "loaded", G(), g.removeEventListener(n._canPlayEvent, V, !1);
};
g.addEventListener(n._canPlayEvent, V, !1), r._clearTimer(i._id);
}
}
return i._id;
},
/**
* Pause playback and save current position.
* @param {Number} id The sound ID (empty to pause all in group).
* @return {Howl}
*/
pause: function(e) {
var t = this;
if (t._state !== "loaded" || t._playLock)
return t._queue.push({
event: "pause",
action: function() {
t.pause(e);
}
}), t;
for (var r = t._getSoundIds(e), o = 0; o < r.length; o++) {
t._clearTimer(r[o]);
var u = t._soundById(r[o]);
if (u && !u._paused && (u._seek = t.seek(r[o]), u._rateSeek = 0, u._paused = !0, t._stopFade(r[o]), u._node))
if (t._webAudio) {
if (!u._node.bufferSource)
continue;
typeof u._node.bufferSource.stop > "u" ? u._node.bufferSource.noteOff(0) : u._node.bufferSource.stop(0), t._cleanBuffer(u._node);
} else (!isNaN(u._node.duration) || u._node.duration === 1 / 0) && u._node.pause();
arguments[1] || t._emit("pause", u ? u._id : null);
}
return t;
},
/**
* Stop playback and reset to start.
* @param {Number} id The sound ID (empty to stop all in group).
* @param {Boolean} internal Internal Use: true prevents event firing.
* @return {Howl}
*/
stop: function(e, t) {
var r = this;
if (r._state !== "loaded" || r._playLock)
return r._queue.push({
event: "stop",
action: function() {
r.stop(e);
}
}), r;
for (var o = r._getSoundIds(e), u = 0; u < o.length; u++) {
r._clearTimer(o[u]);
var s = r._soundById(o[u]);
s && (s._seek = s._start || 0, s._rateSeek = 0, s._paused = !0, s._ended = !0, r._stopFade(o[u]), s._node && (r._webAudio ? s._node.bufferSource && (typeof s._node.bufferSource.stop > "u" ? s._node.bufferSource.noteOff(0) : s._node.bufferSource.stop(0), r._cleanBuffer(s._node)) : (!isNaN(s._node.duration) || s._node.duration === 1 / 0) && (s._node.currentTime = s._start || 0, s._node.pause(), s._node.duration === 1 / 0 && r._clearSound(s._node))), t || r._emit("stop", s._id));
}
return r;
},
/**
* Mute/unmute a single sound or all sounds in this Howl group.
* @param {Boolean} muted Set to true to mute and false to unmute.
* @param {Number} id The sound ID to update (omit to mute/unmute all).
* @return {Howl}
*/
mute: function(e, t) {
var r = this;
if (r._state !== "loaded" || r._playLock)
return r._queue.push({
event: "mute",
action: function() {
r.mute(e, t);
}
}), r;
if (typeof t > "u")
if (typeof e == "boolean")
r._muted = e;
else
return r._muted;
for (var o = r._getSoundIds(t), u = 0; u < o.length; u++) {
var s = r._soundById(o[u]);
s && (s._muted = e, s._interval && r._stopFade(s._id), r._webAudio && s._node ? s._node.gain.setValueAtTime(e ? 0 : s._volume, n.ctx.currentTime) : s._node && (s._node.muted = n._muted ? !0 : e), r._emit("mute", s._id));
}
return r;
},
/**
* Get/set the volume of this sound or of the Howl group. This method can optionally take 0, 1 or 2 arguments.
* volume() -> Returns the group's volume value.
* volume(id) -> Returns the sound id's current volume.
* volume(vol) -> Sets the volume of all sounds in this Howl group.
* volume(vol, id) -> Sets the volume of passed sound id.
* @return {Howl/Number} Returns self or current volume.
*/
volume: function() {
var e = this, t = arguments, r, o;
if (t.length === 0)
return e._volume;
if (t.length === 1 || t.length === 2 && typeof t[1] > "u") {
var u = e._getSoundIds(), s = u.indexOf(t[0]);
s >= 0 ? o = parseInt(t[0], 10) : r = parseFloat(t[0]);
} else t.length >= 2 && (r = parseFloat(t[0]), o = parseInt(t[1], 10));
var i;
if (typeof r < "u" && r >= 0 && r <= 1) {
if (e._state !== "loaded" || e._playLock)
return e._queue.push({
event: "volume",
action: function() {
e.volume.apply(e, t);
}
}), e;
typeof o > "u" && (e._volume = r), o = e._getSoundIds(o);
for (var d = 0; d < o.length; d++)
i = e._soundById(o[d]), i && (i._volume = r, t[2] || e._stopFade(o[d]), e._webAudio && i._node && !i._muted ? i._node.gain.setValueAtTime(r, n.ctx.currentTime) : i._node && !i._muted && (i._node.volume = r * n.volume()), e._emit("volume", i._id));
} else
return i = o ? e._soundById(o) : e._sounds[0], i ? i._volume : 0;
return e;
},
/**
* Fade a currently playing sound between two volumes (if no id is passed, all sounds will fade).
* @param {Number} from The value to fade from (0.0 to 1.0).
* @param {Number} to The volume to fade to (0.0 to 1.0).
* @param {Number} len Time in milliseconds to fade.
* @param {Number} id The sound id (omit to fade all sounds).
* @return {Howl}
*/
fade: function(e, t, r, o) {
var u = this;
if (u._state !== "loaded" || u._playLock)
return u._queue.push({
event: "fade",
action: function() {
u.fade(e, t, r, o);
}
}), u;
e = Math.min(Math.max(0, parseFloat(e)), 1), t = Math.min(Math.max(0, parseFloat(t)), 1), r = parseFloat(r), u.volume(e, o);
for (var s = u._getSoundIds(o), i = 0; i < s.length; i++) {
var d = u._soundById(s[i]);
if (d) {
if (o || u._stopFade(s[i]), u._webAudio && !d._muted) {
var h = n.ctx.currentTime, w = h + r / 1e3;
d._volume = e, d._node.gain.setValueAtTime(e, h), d._node.gain.linearRampToValueAtTime(t, w);
}
u._startFadeInterval(d, e, t, r, s[i], typeof o > "u");
}
}
return u;
},
/**
* Starts the internal interval to fade a sound.
* @param {Object} sound Reference to sound to fade.
* @param {Number} from The value to fade from (0.0 to 1.0).
* @param {Number} to The volume to fade to (0.0 to 1.0).
* @param {Number} len Time in milliseconds to fade.
* @param {Number} id The sound id to fade.
* @param {Boolean} isGroup If true, set the volume on the group.
*/
_startFadeInterval: function(e, t, r, o, u, s) {
var i = this, d = t, h = r - t, w = Math.abs(h / 0.01), T = Math.max(4, w > 0 ? o / w : o), k = Date.now();
e._fadeTo = r, e._interval = setInterval(function() {
var H = (Date.now() - k) / o;
k = Date.now(), d += h * H, d = Math.round(d * 100) / 100, h < 0 ? d = Math.max(r, d) : d = Math.min(r, d), i._webAudio ? e._volume = d : i.volume(d, e._id, !0), s && (i._volume = d), (r < t && d <= r || r > t && d >= r) && (clearInterval(e._interval), e._interval = null, e._fadeTo = null, i.volume(r, e._id), i._emit("fade", e._id));
}, T);
},
/**
* Internal method that stops the currently playing fade when
* a new fade starts, volume is changed or the sound is stopped.
* @param {Number} id The sound id.
* @return {Howl}
*/
_stopFade: function(e) {
var t = this, r = t._soundById(e);
return r && r._interval && (t._webAudio && r._node.gain.cancelScheduledValues(n.ctx.currentTime), clearInterval(r._interval), r._interval = null, t.volume(r._fadeTo, e), r._fadeTo = null, t._emit("fade", e)), t;
},
/**
* Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments.
* loop() -> Returns the group's loop value.
* loop(id) -> Returns the sound id's loop value.
* loop(loop) -> Sets the loop value for all sounds in this Howl group.
* loop(loop, id) -> Sets the loop value of passed sound id.
* @return {Howl/Boolean} Returns self or current loop value.
*/
loop: function() {
var e = this, t = arguments, r, o, u;
if (t.length === 0)
return e._loop;
if (t.length === 1)
if (typeof t[0] == "boolean")
r = t[0], e._loop = r;
else
return u = e._soundById(parseInt(t[0], 10)), u ? u._loop : !1;
else t.length === 2 && (r = t[0], o = parseInt(t[1], 10));
for (var s = e._getSoundIds(o), i = 0; i < s.length; i++)
u = e._soundById(s[i]), u && (u._loop = r, e._webAudio && u._node && u._node.bufferSource && (u._node.bufferSource.loop = r, r && (u._node.bufferSource.loopStart = u._start || 0, u._node.bufferSource.loopEnd = u._stop, e.playing(s[i]) && (e.pause(s[i], !0), e.play(s[i], !0)))));
return e;
},
/**
* Get/set the playback rate of a sound. This method can optionally take 0, 1 or 2 arguments.
* rate() -> Returns the first sound node's current playback rate.
* rate(id) -> Returns the sound id's current playback rate.
* rate(rate) -> Sets the playback rate of all sounds in this Howl group.
* rate(rate, id) -> Sets the playback rate of passed sound id.
* @return {Howl/Number} Returns self or the current playback rate.
*/
rate: function() {
var e = this, t = arguments, r, o;
if (t.length === 0)
o = e._sounds[0]._id;
else if (t.length === 1) {
var u = e._getSoundIds(), s = u.indexOf(t[0]);
s >= 0 ? o = parseInt(t[0], 10) : r = parseFloat(t[0]);
} else t.length === 2 && (r = parseFloat(t[0]), o = parseInt(t[1], 10));
var i;
if (typeof r == "number") {
if (e._state !== "loaded" || e._playLock)
return e._queue.push({
event: "rate",
action: function() {
e.rate.apply(e, t);
}
}), e;
typeof o > "u" && (e._rate = r), o = e._getSoundIds(o);
for (var d = 0; d < o.length; d++)
if (i = e._soundById(o[d]), i) {
e.playing(o[d]) && (i._rateSeek = e.seek(o[d]), i._playStart = e._webAudio ? n.ctx.currentTime : i._playStart), i._rate = r, e._webAudio && i._node && i._node.bufferSource ? i._node.bufferSource.playbackRate.setValueAtTime(r, n.ctx.currentTime) : i._node && (i._node.playbackRate = r);
var h = e.seek(o[d]), w = (e._sprite[i._sprite][0] + e._sprite[i._sprite][1]) / 1e3 - h, T = w * 1e3 / Math.abs(i._rate);
(e._endTimers[o[d]] || !i._paused) && (e._clearTimer(o[d]), e._endTimers[o[d]] = setTimeout(e._ended.bind(e, i), T)), e._emit("rate", i._id);
}
} else
return i = e._soundById(o), i ? i._rate : e._rate;
return e;
},
/**
* Get/set the seek position of a sound. This method can optionally take 0, 1 or 2 arguments.
* seek() -> Returns the first sound node's current seek position.
* seek(id) -> Returns the sound id's current seek position.
* seek(seek) -> Sets the seek position of the first sound node.
* seek(seek, id) -> Sets the seek position of passed sound id.
* @return {Howl/Number} Returns self or the current seek position.
*/
seek: function() {
var e = this, t = arguments, r, o;
if (t.length === 0)
e._sounds.length && (o = e._sounds[0]._id);
else if (t.length === 1) {
var u = e._getSoundIds(), s = u.indexOf(t[0]);
s >= 0 ? o = parseInt(t[0], 10) : e._sounds.length && (o = e._sounds[0]._id, r = parseFloat(t[0]));
} else t.length === 2 && (r = parseFloat(t[0]), o = parseInt(t[1], 10));
if (typeof o > "u")
return 0;
if (typeof r == "number" && (e._state !== "loaded" || e._playLock))
return e._queue.push({
event: "seek",
action: function() {
e.seek.apply(e, t);
}
}), e;
var i = e._soundById(o);
if (i)
if (typeof r == "number" && r >= 0) {
var d = e.playing(o);
d && e.pause(o, !0), i._seek = r, i._ended = !1, e._clearTimer(o), !e._webAudio && i._node && !isNaN(i._node.duration) && (i._node.currentTime = r);
var h = function() {
d && e.play(o, !0), e._emit("seek", o);
};
if (d && !e._webAudio) {
var w = function() {
e._playLock ? setTimeout(w, 0) : h();
};
setTimeout(w, 0);
} else
h();
} else if (e._webAudio) {
var T = e.playing(o) ? n.ctx.currentTime - i._playStart : 0, k = i._rateSeek ? i._rateSeek - i._seek : 0;
return i._seek + (k + T * Math.abs(i._rate));
} else
return i._node.currentTime;
return e;
},
/**
* Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not.
* @param {Number} id The sound id to check. If none is passed, the whole sound group is checked.
* @return {Boolean} True if playing and false if not.
*/
playing: function(e) {
var t = this;
if (typeof e == "number") {
var r = t._soundById(e);
return r ? !r._paused : !1;
}
for (var o = 0; o < t._sounds.length; o++)
if (!t._sounds[o]._paused)
return !0;
return !1;
},
/**
* Get the duration of this sound. Passing a sound id will return the sprite duration.
* @param {Number} id The sound id to check. If none is passed, return full source duration.
* @return {Number} Audio duration in seconds.
*/
duration: function(e) {
var t = this, r = t._duration, o = t._soundById(e);
return o && (r = t._sprite[o._sprite][1] / 1e3), r;
},
/**
* Returns the current loaded state of this Howl.
* @return {String} 'unloaded', 'loading', 'loaded'
*/
state: function() {
return this._state;
},
/**
* Unload and destroy the current Howl object.
* This will immediately stop all sound instances attached to this group.
*/
unload: function() {
for (var e = this, t = e._sounds, r = 0; r < t.length; r++)
t[r]._paused || e.stop(t[r]._id), e._webAudio || (e._clearSound(t[r]._node), t[r]._node.removeEventListener("error", t[r]._errorFn, !1), t[r]._node.removeEventListener(n._canPlayEvent, t[r]._loadFn, !1), t[r]._node.removeEventListener("ended", t[r]._endFn, !1), n._releaseHtml5Audio(t[r]._node)), delete t[r]._node, e._clearTimer(t[r]._id);
var o = n._howls.indexOf(e);
o >= 0 && n._howls.splice(o, 1);
var u = !0;
for (r = 0; r < n._howls.length; r++)
if (n._howls[r]._src === e._src || e._src.indexOf(n._howls[r]._src) >= 0) {
u = !1;
break;
}
return f && u && delete f[e._src], n.noAudio = !1, e._state = "unloaded", e._sounds = [], e = null, null;
},
/**
* Listen to a custom event.
* @param {String} event Event name.
* @param {Function} fn Listener to call.
* @param {Number} id (optional) Only listen to events for this sound.
* @param {Number} once (INTERNAL) Marks event to fire only once.
* @return {Howl}
*/
on: function(e, t, r, o) {
var u = this, s = u["_on" + e];
return typeof t == "function" && s.push(o ? { id: r, fn: t, once: o } : { id: r, fn: t }), u;
},
/**
* Remove a custom event. Call without parameters to remove all events.
* @param {String} event Event name.
* @param {Function} fn Listener to remove. Leave empty to remove all.
* @param {Number} id (optional) Only remove events for this sound.
* @return {Howl}
*/
off: function(e, t, r) {
var o = this, u = o["_on" + e], s = 0;
if (typeof t == "number" && (r = t, t = null), t || r)
for (s = 0; s < u.length; s++) {
var i = r === u[s].id;
if (t === u[s].fn && i || !t && i) {
u.splice(s, 1);
break;
}
}
else if (e)
o["_on" + e] = [];
else {
var d = Object.keys(o);
for (s = 0; s < d.length; s++)
d[s].indexOf("_on") === 0 && Array.isArray(o[d[s]]) && (o[d[s]] = []);
}
return o;
},
/**
* Listen to a custom event and remove it once fired.
* @param {String} event Event name.
* @param {Function} fn Listener to call.
* @param {Number} id (optional) Only listen to events for this sound.
* @return {Howl}
*/
once: function(e, t, r) {
var o = this;
return o.on(e, t, r, 1), o;
},
/**
* Emit all events of a specific type and pass the sound id.
* @param {String} event Event name.
* @param {Number} id Sound ID.
* @param {Number} msg Message to go with event.
* @return {Howl}
*/
_emit: function(e, t, r) {
for (var o = this, u = o["_on" + e], s = u.length - 1; s >= 0; s--)
(!u[s].id || u[s].id === t || e === "load") && (setTimeout(function(i) {
i.call(this, t, r);
}.bind(o, u[s].fn), 0), u[s].once && o.off(e, u[s].fn, u[s].id));
return o._loadQueue(e), o;
},
/**
* Queue of actions initiated before the sound has loaded.
* These will be called in sequence, with the next only firing
* after the previous has finished executing (even if async like play).
* @return {Howl}
*/
_loadQueue: function(e) {
var t = this;
if (t._queue.length > 0) {
var r = t._queue[0];
r.event === e && (t._queue.shift(), t._loadQueue()), e || r.action();
}
return t;
},
/**
* Fired when playback ends at the end of the duration.
* @param {Sound} sound The sound object to work with.
* @return {Howl}
*/
_ended: function(e) {
var t = this, r = e._sprite;
if (!t._webAudio && e._node && !e._node.paused && !e._node.ended && e._node.currentTime < e._stop)
return setTimeout(t._ended.bind(t, e), 100), t;
var o = !!(e._loop || t._sprite[r][2]);
if (t._emit("end", e._id), !t._webAudio && o && t.stop(e._id, !0).play(e._id), t._webAudio && o) {
t._emit("play", e._id), e._seek = e._start || 0, e._rateSeek = 0, e._playStart = n.ctx.currentTime;
var u = (e._stop - e._start) * 1e3 / Math.abs(e._rate);
t._endTimers[e._id] = setTimeout(t._ended.bind(t, e), u);
}
return t._webAudio && !o && (e._paused = !0, e._ended = !0, e._seek = e._start || 0, e._rateSeek = 0, t._clearTimer(e._id), t._cleanBuffer(e._node), n._autoSuspend()), !t._webAudio && !o && t.stop(e._id, !0), t;
},
/**
* Clear the end timer for a sound playback.
* @param {Number} id The sound ID.
* @return {Howl}
*/
_clearTimer: function(e) {
var t = this;
if (t._endTimers[e]) {
if (typeof t._endTimers[e] != "function")
clearTimeout(t._endTimers[e]);
else {
var r = t._soundById(e);
r && r._node && r._node.removeEventListener("ended", t._endTimers[e], !1);
}
delete t._endTimers[e];
}
return t;
},
/**
* Return the sound identified by this ID, or return null.
* @param {Number} id Sound ID
* @return {Object} Sound object or null.
*/
_soundById: function(e) {
for (var t = this, r = 0; r < t._sounds.length; r++)
if (e === t._sounds[r]._id)
return t._sounds[r];
return null;
},
/**
* Return an inactive sound from the pool or create a new one.
* @return {Sound} Sound playback object.
*/
_inactiveSound: function() {
var e = this;
e._drain();
for (var t = 0; t < e._sounds.length; t++)
if (e._sounds[t]._ended)
return e._sounds[t].reset();
return new l(e);
},
/**
* Drain excess inactive sounds from the pool.
*/
_drain: function() {
var e = this, t = e._pool, r = 0, o = 0;
if (!(e._sounds.length < t)) {
for (o = 0; o < e._sounds.length; o++)
e._sounds[o]._ended && r++;
for (o = e._sounds.length - 1; o >= 0; o--) {
if (r <= t)
return;
e._sounds[o]._ended && (e._webAudio && e._sounds[o]._node && e._sounds[o]._node.disconnect(0), e._sounds.splice(o, 1), r--);
}
}
},
/**
* Get all ID's from the sounds pool.
* @param {Number} id Only return one ID if one is passed.
* @return {Array} Array of IDs.
*/
_getSoundIds: function(e) {
var t = this;
if (typeof e > "u") {
for (var r = [], o = 0; o < t._sounds.length; o++)
r.push(t._sounds[o]._id);
return r;
} else
return [e];
},
/**
* Load the sound back into the buffer source.
* @param {Sound} sound The sound object to work with.
* @return {Howl}
*/
_refreshBuffer: function(e) {
var t = this;
return e._node.bufferSource = n.ctx.createBufferSource(), e._node.bufferSource.buffer = f[t._src], e._panner ? e._node.bufferSource.connect(e._panner) : e._node.bufferSource.connect(e._node), e._node.bufferSource.loop = e._loop, e._loop && (e._node.bufferSource.loopStart = e._start || 0, e._node.bufferSource.loopEnd = e._stop || 0), e._node.bufferSource.playbackRate.setValueAtTime(e._rate, n.ctx.currentTime), t;
},
/**
* Prevent memory leaks by cleaning up the buffer source after playback.
* @param {Object} node Sound's audio node containing the buffer source.
* @return {Howl}
*/
_cleanBuffer: function(e) {
var t = this, r = n._navigator && n._navigator.vendor.indexOf("Apple") >= 0;
if (!e.bufferSource)
return t;
if (n._scratchBuffer && e.bufferSource && (e.bufferSource.onended = null, e.bufferSource.disconnect(0), r))
try {
e.bufferSource.buffer = n._scratchBuffer;
} catch {
}
return e.bufferSource = null, t;
},
/**
* Set the source to a 0-second silence to stop any downloading (except in IE).
* @param {Object} node Audio node to clear.
*/
_clearSound: function(e) {
var t = /MSIE |Trident\//.test(n._navigator && n._navigator.userAgent);
t || (e.src = "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA");
}
};
var l = function(e) {
this._parent = e, this.init();
};
l.prototype = {
/**
* Initialize a new Sound object.
* @return {Sound}
*/
init: function() {
var e = this, t = e._parent;
return e._muted = t._muted, e._loop = t._loop, e._volume = t._volume, e._rate = t._rate, e._seek = 0, e._paused = !0, e._ended = !0, e._sprite = "__default", e._id = ++n._counter, t._sounds.push(e), e.create(), e;
},
/**
* Create and setup a new sound object, whether HTML5 Audio or Web Audio.
* @return {Sound}
*/
create: function() {
var e = this, t = e._parent, r = n._muted || e._muted || e._parent._muted ? 0 : e._volume;
return t._webAudio ? (e._node = typeof n.ctx.createGain > "u" ? n.ctx.createGainNode() : n.ctx.createGain(), e._node.gain.setValueAtTime(r, n.ctx.currentTime), e._node.paused = !0, e._node.connect(n.masterGain)) : n.noAudio || (e._node = n._obtainHtml5Audio(), e._errorFn = e._errorListener.bind(e), e._node.addEventListener("error", e._errorFn, !1), e._loadFn = e._loadListener.bind(e), e._node.addEventListener(n._canPlayEvent, e._loadFn, !1), e._endFn = e._endListener.bind(e), e._node.addEventListener("ended", e._endFn, !1), e._node.src = t._src, e._node.preload = t._preload === !0 ? "auto" : t._preload, e._node.volume = r * n.volume(), e._node.load()), e;
},
/**
* Reset the parameters of this sound to the original state (for recycle).
* @return {Sound}
*/
reset: function() {
var e = this, t = e._parent;
return e._muted = t._muted, e._loop = t._loop, e._volume = t._volume, e._rate = t._rate, e._seek = 0, e._rateSeek = 0, e._paused = !0, e._ended = !0, e._sprite = "__default", e._id = ++n._counter, e;
},
/**
* HTML5 Audio error listener callback.
*/
_errorListener: function() {
var e = this;
e._parent._emit("loaderror", e._id, e._node.error ? e._node.error.code : 0), e._node.removeEventListener("error", e._errorFn, !1);
},
/**
* HTML5 Audio canplaythrough listener callback.
*/
_loadListener: function() {
var e = this, t = e._parent;
t._duration = Math.ceil(e._node.duration * 10) / 10,