@jswork/howler-audio-manager 0.0.0-stage → 1.0.2

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.
@@ -0,0 +1,747 @@
1
+ "use strict";
2
+ function _array_like_to_array(arr, len) {
3
+ if (len == null || len > arr.length) len = arr.length;
4
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
5
+ return arr2;
6
+ }
7
+ function _array_with_holes(arr) {
8
+ if (Array.isArray(arr)) return arr;
9
+ }
10
+ function _array_without_holes(arr) {
11
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
12
+ }
13
+ function _class_call_check(instance, Constructor) {
14
+ if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
15
+ }
16
+ function _defineProperties(target, props) {
17
+ for(var i = 0; i < props.length; i++){
18
+ var descriptor = props[i];
19
+ descriptor.enumerable = descriptor.enumerable || false;
20
+ descriptor.configurable = true;
21
+ if ("value" in descriptor) descriptor.writable = true;
22
+ Object.defineProperty(target, descriptor.key, descriptor);
23
+ }
24
+ }
25
+ function _create_class(Constructor, protoProps, staticProps) {
26
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
27
+ if (staticProps) _defineProperties(Constructor, staticProps);
28
+ return Constructor;
29
+ }
30
+ function _iterable_to_array(iter) {
31
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
32
+ return Array.from(iter);
33
+ }
34
+ }
35
+ function _iterable_to_array_limit(arr, i) {
36
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
37
+ if (_i == null) return;
38
+ var _arr = [];
39
+ var _n = true;
40
+ var _d = false;
41
+ var _s, _e;
42
+ try {
43
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
44
+ _arr.push(_s.value);
45
+ if (i && _arr.length === i) break;
46
+ }
47
+ } catch (err) {
48
+ _d = true;
49
+ _e = err;
50
+ } finally{
51
+ try {
52
+ if (!_n && _i["return"] != null) _i["return"]();
53
+ } finally{
54
+ if (_d) throw _e;
55
+ }
56
+ }
57
+ return _arr;
58
+ }
59
+ function _non_iterable_rest() {
60
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
61
+ }
62
+ function _non_iterable_spread() {
63
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
64
+ }
65
+ function _sliced_to_array(arr, i) {
66
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
67
+ }
68
+ function _to_consumable_array(arr) {
69
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
70
+ }
71
+ function _unsupported_iterable_to_array(o, minLen) {
72
+ if (!o) return;
73
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
74
+ var n = Object.prototype.toString.call(o).slice(8, -1);
75
+ if (n === "Object" && o.constructor) n = o.constructor.name;
76
+ if (n === "Map" || n === "Set") return Array.from(n);
77
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
78
+ }
79
+ Object.defineProperty(exports, "__esModule", {
80
+ value: true
81
+ });
82
+ function _nullishCoalesce(lhs, rhsFn) {
83
+ if (lhs != null) {
84
+ return lhs;
85
+ } else {
86
+ return rhsFn();
87
+ }
88
+ }
89
+ function _optionalChain(ops) {
90
+ var lastAccessLHS = undefined;
91
+ var value = ops[0];
92
+ var i = 1;
93
+ while(i < ops.length){
94
+ var op = ops[i];
95
+ var fn = ops[i + 1];
96
+ i += 2;
97
+ if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
98
+ return undefined;
99
+ }
100
+ if (op === 'access' || op === 'optionalAccess') {
101
+ lastAccessLHS = value;
102
+ value = fn(value);
103
+ } else if (op === 'call' || op === 'optionalCall') {
104
+ var _value;
105
+ value = fn(function() {
106
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
107
+ args[_key] = arguments[_key];
108
+ }
109
+ return (_value = value).call.apply(_value, [
110
+ lastAccessLHS
111
+ ].concat(_to_consumable_array(args)));
112
+ });
113
+ lastAccessLHS = undefined;
114
+ }
115
+ }
116
+ return value;
117
+ } /*!
118
+ * name: @jswork/howler-audio-manager
119
+ * description: Howler.js audio manager, enum-driven sounds for H5.
120
+ * homepage: https://js.work
121
+ * version: 1.0.2
122
+ * date: 2026-10-20 20:03:06
123
+ * license: MIT
124
+ */
125
+ // src/manager.ts
126
+ var _howler = require('howler');
127
+ var AudioManager = /*#__PURE__*/ function() {
128
+ function AudioManager(options, inject) {
129
+ _class_call_check(this, AudioManager);
130
+ this.effectCache = /* @__PURE__ */ new Map();
131
+ this.urlAudioCache = /* @__PURE__ */ new Map();
132
+ this.preloadPromises = /* @__PURE__ */ new Map();
133
+ this.activeUrlHowl = null;
134
+ this.globalVolume = 1;
135
+ this.listeners = /* @__PURE__ */ new Map();
136
+ this.HowlConstructor = _nullishCoalesce(_optionalChain([
137
+ inject,
138
+ 'optionalAccess',
139
+ function(_) {
140
+ return _.HowlClass;
141
+ }
142
+ ]), function() {
143
+ return _howler.Howl;
144
+ });
145
+ this.HowlerInstance = _nullishCoalesce(_optionalChain([
146
+ inject,
147
+ 'optionalAccess',
148
+ function(_2) {
149
+ return _2.HowlerObj;
150
+ }
151
+ ]), function() {
152
+ return _howler.Howler;
153
+ });
154
+ if (typeof _optionalChain([
155
+ options,
156
+ 'optionalAccess',
157
+ function(_3) {
158
+ return _3.defaultVolume;
159
+ }
160
+ ]) === "number") {
161
+ this.setGlobalVolume(options.defaultVolume);
162
+ }
163
+ }
164
+ _create_class(AudioManager, [
165
+ {
166
+ key: "hasEffect",
167
+ value: function hasEffect(key) {
168
+ return this.effectCache.has(key);
169
+ }
170
+ },
171
+ {
172
+ key: "loadEffect",
173
+ value: function loadEffect(key, url) {
174
+ var _this = this;
175
+ if (this.effectCache.has(key)) {
176
+ this.effectCache.get(key).unload();
177
+ }
178
+ var howl = new this.HowlConstructor({
179
+ src: [
180
+ url
181
+ ],
182
+ preload: true
183
+ });
184
+ howl.on("load", function() {
185
+ _this.emit("load", {
186
+ type: "effect",
187
+ key: key,
188
+ url: url
189
+ });
190
+ });
191
+ howl.on("loaderror", function(_id, error) {
192
+ _this.emit("error", {
193
+ type: "effect",
194
+ key: key,
195
+ url: url,
196
+ error: error
197
+ });
198
+ });
199
+ this.effectCache.set(key, howl);
200
+ }
201
+ },
202
+ {
203
+ key: "loadEffects",
204
+ value: function loadEffects(map) {
205
+ var _this = this;
206
+ Object.keys(map).forEach(function(key) {
207
+ var typedKey = isNaN(Number(key)) ? key : Number(key);
208
+ _this.loadEffect(typedKey, map[key]);
209
+ });
210
+ }
211
+ },
212
+ {
213
+ key: "playEffect",
214
+ value: function playEffect(key, options) {
215
+ var _this = this;
216
+ var howl = this.effectCache.get(key);
217
+ if (!howl) {
218
+ console.warn("[AudioManager] Effect not found for key: ".concat(String(key), "."));
219
+ return void 0;
220
+ }
221
+ if (howl.playing()) {
222
+ howl.stop();
223
+ }
224
+ if (typeof _optionalChain([
225
+ options,
226
+ 'optionalAccess',
227
+ function(_4) {
228
+ return _4.volume;
229
+ }
230
+ ]) === "number") {
231
+ howl.volume(options.volume);
232
+ }
233
+ howl.off("play");
234
+ howl.off("end");
235
+ howl.off("stop");
236
+ howl.off("playerror");
237
+ howl.once("play", function(soundId) {
238
+ _optionalChain([
239
+ options,
240
+ 'optionalAccess',
241
+ function(_5) {
242
+ return _5.onStart;
243
+ },
244
+ 'optionalCall',
245
+ function(_6) {
246
+ return _6(soundId);
247
+ }
248
+ ]);
249
+ _this.emit("play", {
250
+ type: "effect",
251
+ key: key,
252
+ soundId: soundId
253
+ });
254
+ });
255
+ howl.once("end", function(soundId) {
256
+ if (typeof _optionalChain([
257
+ options,
258
+ 'optionalAccess',
259
+ function(_7) {
260
+ return _7.volume;
261
+ }
262
+ ]) === "number") {
263
+ howl.volume(1);
264
+ }
265
+ _optionalChain([
266
+ options,
267
+ 'optionalAccess',
268
+ function(_8) {
269
+ return _8.onEnd;
270
+ },
271
+ 'optionalCall',
272
+ function(_9) {
273
+ return _9(soundId);
274
+ }
275
+ ]);
276
+ _this.emit("end", {
277
+ type: "effect",
278
+ key: key,
279
+ soundId: soundId
280
+ });
281
+ });
282
+ howl.once("stop", function(soundId) {
283
+ if (typeof _optionalChain([
284
+ options,
285
+ 'optionalAccess',
286
+ function(_10) {
287
+ return _10.volume;
288
+ }
289
+ ]) === "number") {
290
+ howl.volume(1);
291
+ }
292
+ _optionalChain([
293
+ options,
294
+ 'optionalAccess',
295
+ function(_11) {
296
+ return _11.onStop;
297
+ },
298
+ 'optionalCall',
299
+ function(_12) {
300
+ return _12(soundId);
301
+ }
302
+ ]);
303
+ _this.emit("stop", {
304
+ type: "effect",
305
+ key: key,
306
+ soundId: soundId
307
+ });
308
+ });
309
+ howl.once("playerror", function(soundId, error) {
310
+ _optionalChain([
311
+ options,
312
+ 'optionalAccess',
313
+ function(_13) {
314
+ return _13.onError;
315
+ },
316
+ 'optionalCall',
317
+ function(_14) {
318
+ return _14(soundId, error);
319
+ }
320
+ ]);
321
+ _this.emit("error", {
322
+ type: "effect",
323
+ key: key,
324
+ soundId: soundId,
325
+ error: error
326
+ });
327
+ });
328
+ return howl.play();
329
+ }
330
+ },
331
+ {
332
+ key: "stopEffect",
333
+ value: function stopEffect(key) {
334
+ var howl = this.effectCache.get(key);
335
+ if (howl) {
336
+ howl.stop();
337
+ }
338
+ }
339
+ },
340
+ {
341
+ key: "removeEffect",
342
+ value: function removeEffect(key) {
343
+ var howl = this.effectCache.get(key);
344
+ if (howl) {
345
+ howl.unload();
346
+ this.effectCache.delete(key);
347
+ }
348
+ }
349
+ },
350
+ {
351
+ key: "preloadUrl",
352
+ value: function preloadUrl(url) {
353
+ var _this = this;
354
+ var existing = this.urlAudioCache.get(url);
355
+ if (existing && existing.state() === "loaded") {
356
+ return Promise.resolve();
357
+ }
358
+ var pending = this.preloadPromises.get(url);
359
+ if (pending) {
360
+ return pending;
361
+ }
362
+ var howl = existing && existing.state() !== "unloaded" ? existing : this.createUrlHowl(url);
363
+ var promise = new Promise(function(resolve, reject) {
364
+ howl.once("load", function() {
365
+ resolve();
366
+ });
367
+ howl.once("loaderror", function(_id, error) {
368
+ _this.urlAudioCache.delete(url);
369
+ reject(error);
370
+ });
371
+ });
372
+ this.preloadPromises.set(url, promise);
373
+ var settle = function settle() {
374
+ if (_this.preloadPromises.get(url) === promise) {
375
+ _this.preloadPromises.delete(url);
376
+ }
377
+ };
378
+ promise.then(settle, settle);
379
+ return promise;
380
+ }
381
+ },
382
+ {
383
+ key: "preloadUrls",
384
+ value: function preloadUrls(urls) {
385
+ var _this = this;
386
+ return Promise.all(urls.map(function(url) {
387
+ return _this.preloadUrl(url);
388
+ }));
389
+ }
390
+ },
391
+ {
392
+ key: "createUrlHowl",
393
+ value: function createUrlHowl(url) {
394
+ var _this = this;
395
+ var howl = new this.HowlConstructor({
396
+ src: [
397
+ url
398
+ ],
399
+ preload: true
400
+ });
401
+ howl.on("load", function() {
402
+ _this.emit("load", {
403
+ type: "url",
404
+ url: url
405
+ });
406
+ });
407
+ howl.on("loaderror", function(_id, error) {
408
+ _this.urlAudioCache.delete(url);
409
+ _this.emit("error", {
410
+ type: "url",
411
+ url: url,
412
+ error: error
413
+ });
414
+ });
415
+ this.urlAudioCache.set(url, howl);
416
+ return howl;
417
+ }
418
+ },
419
+ {
420
+ key: "playUrl",
421
+ value: function playUrl(url, options) {
422
+ var _this = this;
423
+ var howl = this.urlAudioCache.get(url) || this.createUrlHowl(url);
424
+ var isSingleton = _optionalChain([
425
+ options,
426
+ 'optionalAccess',
427
+ function(_15) {
428
+ return _15.singleton;
429
+ }
430
+ ]) !== false;
431
+ if (isSingleton && this.activeUrlHowl && this.activeUrlHowl !== howl && this.activeUrlHowl.playing()) {
432
+ this.activeUrlHowl.stop();
433
+ }
434
+ if (howl.playing()) {
435
+ howl.stop();
436
+ }
437
+ if (_optionalChain([
438
+ options,
439
+ 'optionalAccess',
440
+ function(_16) {
441
+ return _16.loop;
442
+ }
443
+ ]) !== void 0) {
444
+ howl.loop(options.loop);
445
+ }
446
+ if (typeof _optionalChain([
447
+ options,
448
+ 'optionalAccess',
449
+ function(_17) {
450
+ return _17.volume;
451
+ }
452
+ ]) === "number") {
453
+ howl.volume(options.volume);
454
+ }
455
+ if (isSingleton) {
456
+ this.activeUrlHowl = howl;
457
+ }
458
+ howl.off("play");
459
+ howl.off("end");
460
+ howl.off("stop");
461
+ howl.off("playerror");
462
+ howl.once("play", function(soundId) {
463
+ _optionalChain([
464
+ options,
465
+ 'optionalAccess',
466
+ function(_18) {
467
+ return _18.onStart;
468
+ },
469
+ 'optionalCall',
470
+ function(_19) {
471
+ return _19(soundId);
472
+ }
473
+ ]);
474
+ _this.emit("play", {
475
+ type: "url",
476
+ url: url,
477
+ soundId: soundId
478
+ });
479
+ });
480
+ howl.once("end", function(soundId) {
481
+ if (typeof _optionalChain([
482
+ options,
483
+ 'optionalAccess',
484
+ function(_20) {
485
+ return _20.volume;
486
+ }
487
+ ]) === "number") {
488
+ howl.volume(1);
489
+ }
490
+ _optionalChain([
491
+ options,
492
+ 'optionalAccess',
493
+ function(_21) {
494
+ return _21.onEnd;
495
+ },
496
+ 'optionalCall',
497
+ function(_22) {
498
+ return _22(soundId);
499
+ }
500
+ ]);
501
+ _this.emit("end", {
502
+ type: "url",
503
+ url: url,
504
+ soundId: soundId
505
+ });
506
+ if (_this.activeUrlHowl === howl && !howl.loop()) {
507
+ _this.activeUrlHowl = null;
508
+ }
509
+ });
510
+ howl.once("stop", function(soundId) {
511
+ if (typeof _optionalChain([
512
+ options,
513
+ 'optionalAccess',
514
+ function(_23) {
515
+ return _23.volume;
516
+ }
517
+ ]) === "number") {
518
+ howl.volume(1);
519
+ }
520
+ _optionalChain([
521
+ options,
522
+ 'optionalAccess',
523
+ function(_24) {
524
+ return _24.onStop;
525
+ },
526
+ 'optionalCall',
527
+ function(_25) {
528
+ return _25(soundId);
529
+ }
530
+ ]);
531
+ _this.emit("stop", {
532
+ type: "url",
533
+ url: url,
534
+ soundId: soundId
535
+ });
536
+ if (_this.activeUrlHowl === howl) {
537
+ _this.activeUrlHowl = null;
538
+ }
539
+ });
540
+ howl.once("playerror", function(soundId, error) {
541
+ _optionalChain([
542
+ options,
543
+ 'optionalAccess',
544
+ function(_26) {
545
+ return _26.onError;
546
+ },
547
+ 'optionalCall',
548
+ function(_27) {
549
+ return _27(soundId, error);
550
+ }
551
+ ]);
552
+ _this.emit("error", {
553
+ type: "url",
554
+ url: url,
555
+ soundId: soundId,
556
+ error: error
557
+ });
558
+ if (_this.activeUrlHowl === howl) {
559
+ _this.activeUrlHowl = null;
560
+ }
561
+ });
562
+ return howl.play();
563
+ }
564
+ },
565
+ {
566
+ key: "stopUrl",
567
+ value: function stopUrl(url) {
568
+ var howl = this.urlAudioCache.get(url);
569
+ if (howl) {
570
+ howl.stop();
571
+ }
572
+ }
573
+ },
574
+ {
575
+ key: "on",
576
+ value: function on(event, handler) {
577
+ var set = _nullishCoalesce(this.listeners.get(event), function() {
578
+ return /* @__PURE__ */ new Set();
579
+ });
580
+ this.listeners.set(event, set);
581
+ set.add(handler);
582
+ return {
583
+ destroy: function destroy() {
584
+ set.delete(handler);
585
+ }
586
+ };
587
+ }
588
+ },
589
+ {
590
+ key: "emit",
591
+ value: function emit(event, payload) {
592
+ var set = this.listeners.get(event);
593
+ if (set) {
594
+ set.forEach(function(handler) {
595
+ try {
596
+ handler(payload);
597
+ } catch (err) {
598
+ console.error("[AudioManager] Error in event listener for ".concat(event, ":"), err);
599
+ }
600
+ });
601
+ }
602
+ }
603
+ },
604
+ {
605
+ key: "getGlobalVolume",
606
+ value: function getGlobalVolume() {
607
+ return this.globalVolume;
608
+ }
609
+ },
610
+ {
611
+ key: "setGlobalVolume",
612
+ value: function setGlobalVolume(volume) {
613
+ this.globalVolume = volume;
614
+ this.HowlerInstance.volume(volume);
615
+ }
616
+ },
617
+ {
618
+ key: "mute",
619
+ value: function mute(muted) {
620
+ this.HowlerInstance.mute(muted);
621
+ }
622
+ },
623
+ {
624
+ key: "stopAll",
625
+ value: function stopAll() {
626
+ this.HowlerInstance.stop();
627
+ this.activeUrlHowl = null;
628
+ }
629
+ },
630
+ {
631
+ key: "destroy",
632
+ value: function destroy() {
633
+ this.effectCache.forEach(function(howl) {
634
+ return howl.unload();
635
+ });
636
+ this.urlAudioCache.forEach(function(howl) {
637
+ return howl.unload();
638
+ });
639
+ this.effectCache.clear();
640
+ this.urlAudioCache.clear();
641
+ this.preloadPromises.clear();
642
+ this.listeners.clear();
643
+ this.activeUrlHowl = null;
644
+ }
645
+ }
646
+ ]);
647
+ return AudioManager;
648
+ }();
649
+ // src/react.tsx
650
+ var _react = require('react');
651
+ var _jsxruntime = require('react/jsx-runtime');
652
+ var AudioManagerContext = _react.createContext.call(void 0, null);
653
+ function AudioManagerProvider(param) {
654
+ var manager = param.manager, children = param.children;
655
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AudioManagerContext.Provider, {
656
+ value: manager,
657
+ children: children
658
+ });
659
+ }
660
+ function useAudio() {
661
+ var manager = _react.useContext.call(void 0, AudioManagerContext);
662
+ if (!manager) {
663
+ throw new Error("useAudio must be used within an <AudioManagerProvider>.");
664
+ }
665
+ return manager;
666
+ }
667
+ function useAudioEvent(event, handler) {
668
+ var manager = useAudio();
669
+ var handlerRef = _react.useRef.call(void 0, handler);
670
+ handlerRef.current = handler;
671
+ _react.useEffect.call(void 0, function() {
672
+ var subscription = manager.on(event, function(payload) {
673
+ return handlerRef.current(payload);
674
+ });
675
+ return function() {
676
+ return subscription.destroy();
677
+ };
678
+ }, [
679
+ manager,
680
+ event
681
+ ]);
682
+ }
683
+ function useGlobalVolume() {
684
+ var manager = useAudio();
685
+ var _react_useState_call = _sliced_to_array(_react.useState.call(void 0, function() {
686
+ return manager.getGlobalVolume();
687
+ }), 2), volume = _react_useState_call[0], setVolumeState = _react_useState_call[1];
688
+ var setVolume = _react.useCallback.call(void 0, function(next) {
689
+ manager.setGlobalVolume(next);
690
+ setVolumeState(next);
691
+ }, [
692
+ manager
693
+ ]);
694
+ return [
695
+ volume,
696
+ setVolume
697
+ ];
698
+ }
699
+ function usePreload(urls) {
700
+ var manager = useAudio();
701
+ var urlsKey = JSON.stringify(urls);
702
+ var _react_useState_call = _sliced_to_array(_react.useState.call(void 0, {
703
+ status: "idle",
704
+ error: null
705
+ }), 2), state = _react_useState_call[0], setState = _react_useState_call[1];
706
+ _react.useEffect.call(void 0, function() {
707
+ var list = JSON.parse(urlsKey);
708
+ if (list.length === 0) {
709
+ setState({
710
+ status: "idle",
711
+ error: null
712
+ });
713
+ return;
714
+ }
715
+ var cancelled = false;
716
+ setState({
717
+ status: "loading",
718
+ error: null
719
+ });
720
+ manager.preloadUrls(list).then(function() {
721
+ if (!cancelled) setState({
722
+ status: "loaded",
723
+ error: null
724
+ });
725
+ }, function(error) {
726
+ if (!cancelled) setState({
727
+ status: "error",
728
+ error: error
729
+ });
730
+ });
731
+ return function() {
732
+ cancelled = true;
733
+ };
734
+ }, [
735
+ manager,
736
+ urlsKey
737
+ ]);
738
+ return state;
739
+ }
740
+ exports.AudioManager = AudioManager;
741
+ exports.AudioManagerProvider = AudioManagerProvider;
742
+ exports.default = AudioManager;
743
+ exports.useAudio = useAudio;
744
+ exports.useAudioEvent = useAudioEvent;
745
+ exports.useGlobalVolume = useGlobalVolume;
746
+ exports.usePreload = usePreload;
747
+ //# sourceMappingURL=index.cjs.js.map