@bouko/react 3.1.7 → 3.1.9

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,23 @@
1
+ import type { AudioRef } from "../element/with-audio";
2
+ /**
3
+ * Audio Playback Hook.
4
+ *
5
+ * Internal hook used by the Audio Player context provider to derive
6
+ * reactive playback state from. This hook is not UI-facing. It exists
7
+ * to translate the audio element events into declarative state that
8
+ * can be exposed through context and consumed by multiple components.
9
+ *
10
+ * @param {AudioRef} ref - Audio element owned by the player.
11
+ *
12
+ * @returns
13
+ * - `elapsed` (number): Current playback position (ms).
14
+ * - `duration` (number): Total track duration (ms).
15
+ * - `progress` (number): Normalized playback position (0-1).
16
+ * - `ended` (boolean): Whether the track has finished.
17
+ **/
18
+ export declare function usePlayback(ref: AudioRef): {
19
+ elapsed: number;
20
+ duration: number;
21
+ ended: boolean;
22
+ progress: number;
23
+ };
@@ -0,0 +1,50 @@
1
+ import { useEffect, useState } from "react";
2
+ import { withAudio } from "../element/with-audio";
3
+ /**
4
+ * Audio Playback Hook.
5
+ *
6
+ * Internal hook used by the Audio Player context provider to derive
7
+ * reactive playback state from. This hook is not UI-facing. It exists
8
+ * to translate the audio element events into declarative state that
9
+ * can be exposed through context and consumed by multiple components.
10
+ *
11
+ * @param {AudioRef} ref - Audio element owned by the player.
12
+ *
13
+ * @returns
14
+ * - `elapsed` (number): Current playback position (ms).
15
+ * - `duration` (number): Total track duration (ms).
16
+ * - `progress` (number): Normalized playback position (0-1).
17
+ * - `ended` (boolean): Whether the track has finished.
18
+ **/
19
+ export function usePlayback(ref) {
20
+ const [elapsed, setElapsed] = useState(0);
21
+ const [duration, setDuration] = useState(0);
22
+ const [ended, setEnded] = useState(false);
23
+ useEffect(() => withAudio(ref, (audio) => {
24
+ const onLoadedMetadata = () => {
25
+ const d = Number.isFinite(audio.duration) ? audio.duration : 0;
26
+ setDuration(d * 1000);
27
+ setEnded(false);
28
+ };
29
+ const onTimeUpdate = () => {
30
+ const e = audio.currentTime;
31
+ setElapsed(e * 1000);
32
+ };
33
+ const onPlay = () => setEnded(false);
34
+ const onEnded = () => setEnded(true);
35
+ audio.addEventListener("loadedmetadata", onLoadedMetadata);
36
+ audio.addEventListener("timeupdate", onTimeUpdate);
37
+ audio.addEventListener("play", onPlay);
38
+ audio.addEventListener("ended", onEnded);
39
+ return () => {
40
+ audio.removeEventListener("loadedmetadata", onLoadedMetadata);
41
+ audio.removeEventListener("timeupdate", onTimeUpdate);
42
+ audio.removeEventListener("play", onPlay);
43
+ audio.removeEventListener("ended", onEnded);
44
+ };
45
+ }), [ref]);
46
+ return {
47
+ elapsed, duration, ended,
48
+ progress: elapsed / duration
49
+ };
50
+ }
@@ -11,6 +11,17 @@ export type PageQuery = {
11
11
  pageSize: number;
12
12
  refresh?: boolean;
13
13
  };
14
+ export type PageState<T> = {
15
+ page: number;
16
+ isLoading: boolean;
17
+ items: T[];
18
+ totalPages: number;
19
+ fetchedAt: Date | null;
20
+ prev: () => void;
21
+ next: () => void;
22
+ jump: (page: number) => void;
23
+ refresh: () => void;
24
+ };
14
25
  export declare const useSearchParam: (key: string) => string | null;
15
26
  export declare function usePagination<T>({ fetcher, pageSize }: Options<T>): {
16
27
  items: T[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
 
3
3
  "name": "@bouko/react",
4
- "version": "3.1.7",
4
+ "version": "3.1.9",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "license": "MIT",