sm-click-library-ui 0.0.613 → 0.0.614-dev.69

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/tailwind.css CHANGED
@@ -716,12 +716,6 @@ video {
716
716
  .-top-0\.5 {
717
717
  top: -0.125rem;
718
718
  }
719
- .-top-1 {
720
- top: -0.25rem;
721
- }
722
- .-top-1\.5 {
723
- top: -0.375rem;
724
- }
725
719
  .-top-10 {
726
720
  top: -2.5rem;
727
721
  }
@@ -854,6 +848,9 @@ video {
854
848
  .z-\[51\] {
855
849
  z-index: 51;
856
850
  }
851
+ .z-\[70\] {
852
+ z-index: 70;
853
+ }
857
854
  .z-\[9999\] {
858
855
  z-index: 9999;
859
856
  }
@@ -883,10 +880,6 @@ video {
883
880
  margin-top: 0.75rem;
884
881
  margin-bottom: 0.75rem;
885
882
  }
886
- .my-4 {
887
- margin-top: 1rem;
888
- margin-bottom: 1rem;
889
- }
890
883
  .my-auto {
891
884
  margin-top: auto;
892
885
  margin-bottom: auto;
@@ -951,6 +944,9 @@ video {
951
944
  .mr-2 {
952
945
  margin-right: 0.5rem;
953
946
  }
947
+ .mr-3 {
948
+ margin-right: 0.75rem;
949
+ }
954
950
  .mr-4 {
955
951
  margin-right: 1rem;
956
952
  }
@@ -1440,15 +1436,6 @@ video {
1440
1436
  .min-w-19 {
1441
1437
  min-width: 4.5rem;
1442
1438
  }
1443
- .min-w-3 {
1444
- min-width: 0.75rem;
1445
- }
1446
- .min-w-3\.5 {
1447
- min-width: 0.875rem;
1448
- }
1449
- .min-w-4 {
1450
- min-width: 1rem;
1451
- }
1452
1439
  .min-w-48 {
1453
1440
  min-width: 12rem;
1454
1441
  }
@@ -1479,9 +1466,6 @@ video {
1479
1466
  .min-w-full {
1480
1467
  min-width: 100%;
1481
1468
  }
1482
- .max-w-0 {
1483
- max-width: 0px;
1484
- }
1485
1469
  .max-w-28 {
1486
1470
  max-width: 7rem;
1487
1471
  }
@@ -2317,28 +2301,12 @@ video {
2317
2301
  .bg-white\/40 {
2318
2302
  background-color: rgb(255 255 255 / 0.4);
2319
2303
  }
2320
- .bg-gradient-to-br {
2321
- background-image: linear-gradient(to bottom right, var(--tw-gradient-stops));
2322
- }
2323
2304
  .bg-gradient-to-r {
2324
2305
  background-image: linear-gradient(to right, var(--tw-gradient-stops));
2325
2306
  }
2326
2307
  .bg-gradient-to-t {
2327
2308
  background-image: linear-gradient(to top, var(--tw-gradient-stops));
2328
2309
  }
2329
- .bg-gradient-to-tr {
2330
- background-image: linear-gradient(to top right, var(--tw-gradient-stops));
2331
- }
2332
- .from-\[\#2AABEE\] {
2333
- --tw-gradient-from: #2AABEE var(--tw-gradient-from-position);
2334
- --tw-gradient-to: rgb(42 171 238 / 0) var(--tw-gradient-to-position);
2335
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2336
- }
2337
- .from-\[\#4ade80\] {
2338
- --tw-gradient-from: #4ade80 var(--tw-gradient-from-position);
2339
- --tw-gradient-to: rgb(74 222 128 / 0) var(--tw-gradient-to-position);
2340
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2341
- }
2342
2310
  .from-amber-500\/80 {
2343
2311
  --tw-gradient-from: rgb(245 158 11 / 0.8) var(--tw-gradient-from-position);
2344
2312
  --tw-gradient-to: rgb(245 158 11 / 0) var(--tw-gradient-to-position);
@@ -2349,11 +2317,6 @@ video {
2349
2317
  --tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);
2350
2318
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2351
2319
  }
2352
- .from-blue-400 {
2353
- --tw-gradient-from: #60a5fa var(--tw-gradient-from-position);
2354
- --tw-gradient-to: rgb(96 165 250 / 0) var(--tw-gradient-to-position);
2355
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2356
- }
2357
2320
  .from-blue-500\/10 {
2358
2321
  --tw-gradient-from: rgb(59 130 246 / 0.1) var(--tw-gradient-from-position);
2359
2322
  --tw-gradient-to: rgb(59 130 246 / 0) var(--tw-gradient-to-position);
@@ -2374,59 +2337,26 @@ video {
2374
2337
  --tw-gradient-to: rgb(148 163 184 / 0) var(--tw-gradient-to-position);
2375
2338
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2376
2339
  }
2377
- .from-violet-500 {
2378
- --tw-gradient-from: #8b5cf6 var(--tw-gradient-from-position);
2379
- --tw-gradient-to: rgb(139 92 246 / 0) var(--tw-gradient-to-position);
2380
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2381
- }
2382
2340
  .from-violet-500\/80 {
2383
2341
  --tw-gradient-from: rgb(139 92 246 / 0.8) var(--tw-gradient-from-position);
2384
2342
  --tw-gradient-to: rgb(139 92 246 / 0) var(--tw-gradient-to-position);
2385
2343
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2386
2344
  }
2387
- .from-yellow-400 {
2388
- --tw-gradient-from: #facc15 var(--tw-gradient-from-position);
2389
- --tw-gradient-to: rgb(250 204 21 / 0) var(--tw-gradient-to-position);
2390
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2391
- }
2392
- .via-cyan-500 {
2393
- --tw-gradient-to: rgb(6 182 212 / 0) var(--tw-gradient-to-position);
2394
- --tw-gradient-stops: var(--tw-gradient-from), #06b6d4 var(--tw-gradient-via-position), var(--tw-gradient-to);
2395
- }
2396
- .via-pink-500 {
2397
- --tw-gradient-to: rgb(236 72 153 / 0) var(--tw-gradient-to-position);
2398
- --tw-gradient-stops: var(--tw-gradient-from), #ec4899 var(--tw-gradient-via-position), var(--tw-gradient-to);
2399
- }
2400
- .to-\[\#16a34a\] {
2401
- --tw-gradient-to: #16a34a var(--tw-gradient-to-position);
2402
- }
2403
- .to-\[\#229ED9\] {
2404
- --tw-gradient-to: #229ED9 var(--tw-gradient-to-position);
2405
- }
2406
2345
  .to-amber-300 {
2407
2346
  --tw-gradient-to: #fcd34d var(--tw-gradient-to-position);
2408
2347
  }
2409
2348
  .to-blue-400\/10 {
2410
2349
  --tw-gradient-to: rgb(96 165 250 / 0.1) var(--tw-gradient-to-position);
2411
2350
  }
2412
- .to-blue-700 {
2413
- --tw-gradient-to: #1d4ed8 var(--tw-gradient-to-position);
2414
- }
2415
2351
  .to-fuchsia-300 {
2416
2352
  --tw-gradient-to: #f0abfc var(--tw-gradient-to-position);
2417
2353
  }
2418
- .to-purple-600 {
2419
- --tw-gradient-to: #9333ea var(--tw-gradient-to-position);
2420
- }
2421
2354
  .to-sky-300 {
2422
2355
  --tw-gradient-to: #7dd3fc var(--tw-gradient-to-position);
2423
2356
  }
2424
2357
  .to-slate-300 {
2425
2358
  --tw-gradient-to: #cbd5e1 var(--tw-gradient-to-position);
2426
2359
  }
2427
- .to-teal-500 {
2428
- --tw-gradient-to: #14b8a6 var(--tw-gradient-to-position);
2429
- }
2430
2360
  .to-transparent {
2431
2361
  --tw-gradient-to: transparent var(--tw-gradient-to-position);
2432
2362
  }
@@ -2658,15 +2588,9 @@ video {
2658
2588
  .pt-1 {
2659
2589
  padding-top: 0.25rem;
2660
2590
  }
2661
- .pt-1\.5 {
2662
- padding-top: 0.375rem;
2663
- }
2664
2591
  .pt-2 {
2665
2592
  padding-top: 0.5rem;
2666
2593
  }
2667
- .pt-4 {
2668
- padding-top: 1rem;
2669
- }
2670
2594
  .text-left {
2671
2595
  text-align: left;
2672
2596
  }
@@ -2716,9 +2640,6 @@ video {
2716
2640
  .text-\[15px\] {
2717
2641
  font-size: 15px;
2718
2642
  }
2719
- .text-\[8px\] {
2720
- font-size: 8px;
2721
- }
2722
2643
  .text-\[9px\] {
2723
2644
  font-size: 9px;
2724
2645
  }
@@ -3261,9 +3182,6 @@ video {
3261
3182
  .ring-base-300\/60 {
3262
3183
  --tw-ring-color: rgb(var(--bg-base-300) / 0.6);
3263
3184
  }
3264
- .ring-black\/10 {
3265
- --tw-ring-color: rgb(0 0 0 / 0.1);
3266
- }
3267
3185
  .ring-black\/20 {
3268
3186
  --tw-ring-color: rgb(0 0 0 / 0.2);
3269
3187
  }
@@ -3639,9 +3557,6 @@ video {
3639
3557
  .group:hover .group-hover\:inline-block {
3640
3558
  display: inline-block;
3641
3559
  }
3642
- .group:hover .group-hover\:max-w-\[3em\] {
3643
- max-width: 3em;
3644
- }
3645
3560
  .group:hover .group-hover\:-translate-x-40 {
3646
3561
  --tw-translate-x: -10rem;
3647
3562
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -3841,10 +3756,6 @@ video {
3841
3756
  .hover\:to-red-400:hover {
3842
3757
  --tw-gradient-to: #f87171 var(--tw-gradient-to-position);
3843
3758
  }
3844
- .hover\:px-1:hover {
3845
- padding-left: 0.25rem;
3846
- padding-right: 0.25rem;
3847
- }
3848
3759
  .hover\:font-medium:hover {
3849
3760
  font-weight: 500;
3850
3761
  }
@@ -1,5 +1,5 @@
1
1
  import { defineComponent, ref, watchEffect, computed, watch, createElementBlock, openBlock, normalizeStyle } from "vue";
2
- import { c as commonjsGlobal, g as getDefaultExportFromCjs } from "./index-c4ps4TBc.js";
2
+ import { c as commonjsGlobal, g as getDefaultExportFromCjs } from "./index-DYaf2nn_.js";
3
3
  var lottie = { exports: {} };
4
4
  (function(module, exports) {
5
5
  typeof navigator < "u" && function(t, e) {
@@ -1,5 +1,5 @@
1
- import { W as P, b as x } from "./index-c4ps4TBc.js";
2
- import { E } from "./web-DYAIgUw0.js";
1
+ import { W as P, b as x } from "./index-DYaf2nn_.js";
2
+ import { E } from "./web-Uhw2x6hp.js";
3
3
  function m(w) {
4
4
  const e = w.split("/").filter((t) => t !== "."), r = [];
5
5
  return e.forEach((t) => {
@@ -1,4 +1,4 @@
1
- import { r as le, C as ge, g as me, W as we } from "./index-c4ps4TBc.js";
1
+ import { r as le, C as ge, g as me, W as we } from "./index-DYaf2nn_.js";
2
2
  const F = {
3
3
  RECORDING: "RECORDING",
4
4
  PAUSED: "PAUSED",
@@ -58,7 +58,7 @@ var te;
58
58
  n.UTF8 = "utf8", n.ASCII = "ascii", n.UTF16 = "utf16";
59
59
  })(te || (te = {}));
60
60
  const k = le("Filesystem", {
61
- web: () => import("./web-DMY-0jKr.js").then((n) => new n.FilesystemWeb())
61
+ web: () => import("./web-DjNzVuT4.js").then((n) => new n.FilesystemWeb())
62
62
  });
63
63
  Ee();
64
64
  const _e = le("BlobWriter");
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "dist",
6
6
  "src/test-utils"
7
7
  ],
8
- "version": "0.0.613",
8
+ "version": "0.0.614-dev.69",
9
9
  "main": "dist/sm-click-library-ui.es.js",
10
10
  "module": "dist/sm-click-library-ui.umd.js",
11
11
  "style": "dist/style.css",
@@ -6,43 +6,49 @@ import { createPinia, setActivePinia } from "pinia";
6
6
  // elemento recebido em `media`, e o `destroy` mata esse elemento mesmo sendo externo
7
7
  // (como as versões < 7.4) — era isso que cortava o áudio na troca de conversa.
8
8
  const instances = [];
9
+ const seeks = [];
9
10
  vi.mock("wavesurfer.js", () => ({
10
- default: {
11
- create(options) {
12
- const handlers = {};
13
- const ws = {
14
- options,
15
- media: options.media,
16
- subscriptions: [],
17
- timer: { start: () => {} },
18
- initPlayerEvents: () => {},
19
- on: (evt, cb) => {
20
- (handlers[evt] ||= []).push(cb);
21
- },
22
- emit: (evt) => (handlers[evt] || []).forEach((cb) => cb()),
23
- unAll: () => {},
24
- destroy: () => {
25
- ws.media.pause();
26
- ws.media.removeAttribute("src");
27
- },
28
- getDuration: () => 12,
29
- getCurrentTime: () => ws.media.currentTime,
30
- setPlaybackRate: (rate) => {
31
- ws.media.playbackRate = rate;
32
- },
33
- load: async (url) => {
34
- ws.media.src = url;
35
- ws.emit("ready");
36
- },
37
- playPause: () => {
38
- if (ws.media.paused) ws.media.play();
39
- else ws.media.pause();
40
- },
41
- };
42
- instances.push(ws);
43
- return ws;
44
- },
45
- },
11
+ default: {
12
+ create(options) {
13
+ const handlers = {};
14
+ const ws = {
15
+ options,
16
+ media: options.media,
17
+ loads: 0,
18
+ subscriptions: [],
19
+ timer: { start: () => {} },
20
+ initPlayerEvents: () => {},
21
+ on: (evt, cb) => {
22
+ (handlers[evt] ||= []).push(cb);
23
+ },
24
+ emit: (evt) => (handlers[evt] || []).forEach((cb) => cb()),
25
+ unAll: () => {},
26
+ destroy: () => {
27
+ ws.media.pause();
28
+ ws.media.removeAttribute("src");
29
+ },
30
+ getDuration: () => 12,
31
+ getCurrentTime: () => ws.media.currentTime,
32
+ setPlaybackRate: (rate) => {
33
+ ws.media.playbackRate = rate;
34
+ },
35
+ load: async (url) => {
36
+ ws.loads += 1;
37
+ ws.media.src = url;
38
+ ws.emit("ready");
39
+ },
40
+ seekTo: (progress) => {
41
+ seeks.push(progress);
42
+ },
43
+ playPause: () => {
44
+ if (ws.media.paused) ws.media.play();
45
+ else ws.media.pause();
46
+ }
47
+ };
48
+ instances.push(ws);
49
+ return ws;
50
+ }
51
+ }
46
52
  }));
47
53
 
48
54
  import MessageAudio from "~/components/chat/messages/MessageAudio.vue";
@@ -51,101 +57,168 @@ import { useAudioPlaybackStore } from "~/stores/audioPlaybackStore";
51
57
 
52
58
  // jsdom não implementa play/pause de mídia.
53
59
  beforeEach(() => {
54
- instances.length = 0;
55
- Object.defineProperty(HTMLMediaElement.prototype, "paused", {
56
- configurable: true,
57
- get() {
58
- return this.__paused !== false;
59
- },
60
- });
61
- HTMLMediaElement.prototype.play = function () {
62
- this.__paused = false;
63
- this.dispatchEvent(new Event("play"));
64
- return Promise.resolve();
65
- };
66
- HTMLMediaElement.prototype.pause = function () {
67
- this.__paused = true;
68
- this.dispatchEvent(new Event("pause"));
69
- };
70
- HTMLMediaElement.prototype.load = function () {};
71
- setActivePinia(createPinia());
60
+ instances.length = 0;
61
+ seeks.length = 0;
62
+ Object.defineProperty(HTMLMediaElement.prototype, "paused", {
63
+ configurable: true,
64
+ get() {
65
+ return this.__paused !== false;
66
+ }
67
+ });
68
+ HTMLMediaElement.prototype.play = function () {
69
+ this.__paused = false;
70
+ this.dispatchEvent(new Event("play"));
71
+ return Promise.resolve();
72
+ };
73
+ HTMLMediaElement.prototype.pause = function () {
74
+ this.__paused = true;
75
+ this.dispatchEvent(new Event("pause"));
76
+ };
77
+ HTMLMediaElement.prototype.load = function () {};
78
+ setActivePinia(createPinia());
72
79
  });
73
80
 
74
81
  async function mountAudio(trackId = "m1") {
75
- const wrapper = mount(MessageAudio, {
76
- props: {
77
- audio: "https://example.test/a.mp3",
78
- trackId,
79
- trackMeta: { title: "Contato", chatId: 7, messageId: trackId },
80
- },
81
- attachTo: document.body,
82
- });
83
- await new Promise((resolve) => setTimeout(resolve));
84
- return wrapper;
82
+ const wrapper = mount(MessageAudio, {
83
+ props: {
84
+ audio: "https://example.test/a.mp3",
85
+ trackId,
86
+ trackMeta: { title: "Contato", chatId: 7, messageId: trackId }
87
+ },
88
+ attachTo: document.body
89
+ });
90
+ await new Promise((resolve) => setTimeout(resolve));
91
+ return wrapper;
85
92
  }
86
93
 
87
94
  describe("áudio da mensagem fora da árvore da bolha", () => {
88
- it("continua tocando depois que a bolha desmonta", async () => {
89
- const store = useAudioPlaybackStore();
90
- const wrapper = await mountAudio();
91
-
92
- await wrapper.find("button.audio-play").trigger("click");
93
- const el = store.activeElement();
94
- expect(store.trackId).toBe("m1");
95
- expect(store.isPlaying).toBe(true);
96
-
97
- wrapper.unmount();
98
-
99
- expect(store.activeElement()).toBe(el);
100
- expect(el.paused).toBe(false);
101
- expect(el.getAttribute("src")).not.toBeNull();
102
- expect(store.isPlaying).toBe(true);
103
- expect(store.isFloating).toBe(true);
104
- });
105
-
106
- it("volta para a bolha sem cortar o áudio", async () => {
107
- const store = useAudioPlaybackStore();
108
- const first = await mountAudio();
109
- await first.find("button.audio-play").trigger("click");
110
- const el = store.activeElement();
111
- el.currentTime = 5;
112
- first.unmount();
113
-
114
- const again = await mountAudio();
115
- expect(store.activeElement()).toBe(el);
116
- expect(el.paused).toBe(false);
117
- expect(el.currentTime).toBe(5);
118
- expect(store.isFloating).toBe(false);
119
- // A onda remontada controla o mesmo elemento.
120
- await again.find("button.audio-play").trigger("click");
121
- expect(el.paused).toBe(true);
122
- });
123
-
124
- it("faixa de controle aparece e comanda a reprodução", async () => {
125
- const store = useAudioPlaybackStore();
126
- const wrapper = await mountAudio();
127
- await wrapper.find("button.audio-play").trigger("click");
128
- wrapper.unmount();
129
-
130
- const player = mount(AudioPlaybackBar);
131
- expect(player.find(".apb-root").exists()).toBe(true);
132
- expect(player.text()).toContain("Contato");
133
-
134
- await player.find(".apb-play").trigger("click");
135
- expect(store.isPlaying).toBe(false);
136
- });
137
-
138
- it("outra faixa derruba a anterior", async () => {
139
- const store = useAudioPlaybackStore();
140
- const first = await mountAudio("m1");
141
- const second = await mountAudio("m2");
142
-
143
- await first.find("button.audio-play").trigger("click");
144
- const firstEl = store.activeElement();
145
- await second.find("button.audio-play").trigger("click");
146
-
147
- expect(store.trackId).toBe("m2");
148
- expect(firstEl.paused).toBe(true);
149
- expect(store.activeElement().paused).toBe(false);
150
- });
95
+ it("continua tocando depois que a bolha desmonta", async () => {
96
+ const store = useAudioPlaybackStore();
97
+ const wrapper = await mountAudio();
98
+
99
+ await wrapper.find("button.audio-play").trigger("click");
100
+ const el = store.activeElement();
101
+ expect(store.trackId).toBe("m1");
102
+ expect(store.isPlaying).toBe(true);
103
+
104
+ wrapper.unmount();
105
+
106
+ expect(store.activeElement()).toBe(el);
107
+ expect(el.paused).toBe(false);
108
+ expect(el.getAttribute("src")).not.toBeNull();
109
+ expect(store.isPlaying).toBe(true);
110
+ expect(store.isFloating).toBe(true);
111
+ });
112
+
113
+ it("volta para a bolha sem cortar o áudio", async () => {
114
+ const store = useAudioPlaybackStore();
115
+ const first = await mountAudio();
116
+ await first.find("button.audio-play").trigger("click");
117
+ const el = store.activeElement();
118
+ el.currentTime = 5;
119
+ first.unmount();
120
+
121
+ const again = await mountAudio();
122
+ expect(store.activeElement()).toBe(el);
123
+ expect(el.paused).toBe(false);
124
+ expect(el.currentTime).toBe(5);
125
+ expect(store.isFloating).toBe(false);
126
+ // A onda remontada controla o mesmo elemento.
127
+ await again.find("button.audio-play").trigger("click");
128
+ expect(el.paused).toBe(true);
129
+ });
130
+
131
+ it("faixa de controle aparece e comanda a reprodução", async () => {
132
+ const store = useAudioPlaybackStore();
133
+ const wrapper = await mountAudio();
134
+ await wrapper.find("button.audio-play").trigger("click");
135
+ wrapper.unmount();
136
+
137
+ const player = mount(AudioPlaybackBar);
138
+ expect(player.find(".apb-root").exists()).toBe(true);
139
+ expect(player.text()).toContain("Contato");
140
+
141
+ await player.find(".apb-play").trigger("click");
142
+ expect(store.isPlaying).toBe(false);
143
+ });
144
+
145
+ it("outra faixa derruba a anterior", async () => {
146
+ const store = useAudioPlaybackStore();
147
+ const first = await mountAudio("m1");
148
+ const second = await mountAudio("m2");
149
+
150
+ await first.find("button.audio-play").trigger("click");
151
+ const firstEl = store.activeElement();
152
+ await second.find("button.audio-play").trigger("click");
153
+
154
+ expect(store.trackId).toBe("m2");
155
+ expect(firstEl.paused).toBe(true);
156
+ expect(store.activeElement().paused).toBe(false);
157
+ });
158
+ });
159
+
160
+ // jsdom não tem PointerEvent; os listeners escutam por nome do evento.
161
+ function pointer(type, target, clientX = 120) {
162
+ target.dispatchEvent(new MouseEvent(type, { bubbles: true, cancelable: true, clientX, clientY: 20 }));
163
+ }
164
+
165
+ describe("seek por gesto na onda", () => {
166
+ it("toque na onda não seeka por conta do componente", async () => {
167
+ const wrapper = await mountAudio();
168
+ const wave = wrapper.find(".ws-surface").element;
169
+
170
+ pointer("pointerdown", wave);
171
+ pointer("pointerup", wave);
172
+
173
+ // Quem decide se um toque virou clique ou arrasto é o wavesurfer, com threshold.
174
+ expect(seeks).toEqual([]);
175
+ wrapper.unmount();
176
+ });
177
+
178
+ it("ponteiro cancelado pela rolagem não deixa o arrasto ligado", async () => {
179
+ const wrapper = await mountAudio();
180
+ const wave = wrapper.find(".ws-surface").element;
181
+
182
+ // O WebView assume o gesto como rolagem da conversa: vem pointercancel, não pointerup.
183
+ pointer("pointerdown", wave, 120);
184
+ pointer("pointercancel", wave, 120);
185
+ pointer("pointermove", window, 300);
186
+ pointer("pointermove", window, 60);
187
+
188
+ expect(seeks).toEqual([]);
189
+ wrapper.unmount();
190
+ });
191
+
192
+ it("delega threshold e cancelamento de arrasto ao wavesurfer", async () => {
193
+ const store = useAudioPlaybackStore();
194
+ const bubble = await mountAudio();
195
+ expect(instances.at(-1).options.dragToSeek).toBe(true);
196
+
197
+ await bubble.find("button.audio-play").trigger("click");
198
+ bubble.unmount();
199
+
200
+ const player = mount(AudioPlaybackBar);
201
+ await new Promise((resolve) => setTimeout(resolve));
202
+ expect(store.isFloating).toBe(true);
203
+ expect(instances.at(-1).options.dragToSeek).toBe(true);
204
+ player.unmount();
205
+ });
206
+
207
+ it("resize da janela não recarrega o áudio", async () => {
208
+ const wrapper = await mountAudio();
209
+ await wrapper.find("button.audio-play").trigger("click");
210
+ const ws = instances.at(-1);
211
+ ws.media.currentTime = 5;
212
+
213
+ window.dispatchEvent(new Event("resize"));
214
+ await new Promise((resolve) => setTimeout(resolve));
215
+
216
+ // O renderer do wavesurfer redesenha sozinho; recriar tudo baixava e decodificava de novo.
217
+ expect(instances).toHaveLength(1);
218
+ expect(ws.loads).toBe(1);
219
+ expect(seeks).toEqual([]);
220
+ expect(ws.media.currentTime).toBe(5);
221
+ expect(ws.media.paused).toBe(false);
222
+ wrapper.unmount();
223
+ });
151
224
  });