react-media-kit 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marek Miklaszewski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # react-media-kit
2
+
3
+ Headless, unstyled video and audio player primitives for React.
4
+
5
+ `react-media-kit` gives you the behavior of a media player as a set of composable components.
6
+ It renders no CSS and imposes no visual design, so your player looks exactly however you want!
7
+
8
+ ## Features
9
+
10
+ - 🧱 **Compound components** - `Player`, `Video`, `Audio`, `Controls`, `Seekbar`,
11
+ `Volume`, `TimeDisplay`, `PlayButton`, `SkipButton`, `FullscreenButton`,
12
+ `PipButton`, `PlaybackRateButton`. Use only the parts you need.
13
+ - 🎨 **Unstyled by default** - no shipped CSS, no default theme. Style
14
+ everything yourself with plain class names.
15
+ - 🏷️ **Data-attribute state hooks** - playing, fullscreen, picture-in-picture,
16
+ and other states are exposed as `data-*` attributes, so state-driven styling
17
+ stays in CSS instead of JS.
18
+ - ⌨️ **Keyboard shortcuts** built in (play/pause, mute, fullscreen, seeking).
19
+ - 📦 **Small footprint** - Tree-shakeable, with no runtime dependencies beyond React.
20
+ - ⚡ **Optimized for performance** - player state lives outside React in an
21
+ external store; components subscribe to only the slice of state they need.
22
+ - 🔒 **Typed** - written in TypeScript.
23
+
24
+ ## Installation
25
+
26
+ ```sh
27
+ npm install react-media-kit
28
+ ```
29
+
30
+ ```sh
31
+ pnpm add react-media-kit
32
+ ```
33
+
34
+ Requires React and React DOM `>=19`.
35
+
36
+ ## Usage
37
+
38
+ ```tsx
39
+ import { Player, Video, Controls, Seekbar, PlayButton, TimeDisplay } from "react-media-kit";
40
+
41
+ function App() {
42
+ return (
43
+ <Player.Root>
44
+ <Player.Container>
45
+ <Video.Root>
46
+ <Video.Player src="/my-video.mp4" />
47
+ </Video.Root>
48
+
49
+ <Controls.Root>
50
+ <Seekbar.Root>
51
+ <Seekbar.Track>
52
+ <Seekbar.Progress />
53
+ <Seekbar.Buffer />
54
+ <Seekbar.Thumb />
55
+ </Seekbar.Track>
56
+ </Seekbar.Root>
57
+
58
+ <PlayButton.Root>Play</PlayButton.Root>
59
+
60
+ <TimeDisplay.Root>
61
+ <TimeDisplay.Toggle>
62
+ <TimeDisplay.Timer />
63
+ <span>/</span>
64
+ <TimeDisplay.Duration />
65
+ </TimeDisplay.Toggle>
66
+ </TimeDisplay.Root>
67
+ </Controls.Root>
68
+ </Player.Container>
69
+ </Player.Root>
70
+ );
71
+ }
72
+ ```
73
+
74
+ All styling is up to you — target elements by class name or by the `data-*`
75
+ state attributes they expose.
76
+
77
+ ### Adaptive streaming
78
+
79
+ `react-media-kit` ships no streaming engine (HLS, DASH, ...) — it stays
80
+ dependency-free. `Video.Player` and `Audio.Player` both accept a plain
81
+ `ref`, which easily lets you hook in hls.js, dash.js, shaka-player, or
82
+ whichever engine you need.
83
+
84
+ ## Core Concepts
85
+
86
+ Each control is a **root + sub-parts**, in the spirit of BaseUI-style
87
+ primitives:
88
+
89
+ | Component | Purpose |
90
+ | -------------------- | ------------------------------------------- |
91
+ | `Player` | Top-level provider; owns player state |
92
+ | `Video` | The `<video>` element and its overlay |
93
+ | `Audio` | The `<audio>` element |
94
+ | `Controls` | Wrapper for the control bar |
95
+ | `Seekbar` | Scrub/seek, with progress and buffer ranges |
96
+ | `Volume` | Mute toggle and volume slider |
97
+ | `TimeDisplay` | Current time / duration |
98
+ | `PlayButton` | Play/pause toggle |
99
+ | `SkipButton` | Skip forward/back by an interval |
100
+ | `FullscreenButton` | Toggle fullscreen |
101
+ | `PipButton` | Toggle picture-in-picture |
102
+ | `PlaybackRateButton` | Set a specific playback rate |
103
+
104
+ ## License
105
+
106
+ MIT
@@ -0,0 +1,275 @@
1
+ import { ButtonHTMLAttributes, HTMLAttributes, MediaHTMLAttributes, MouseEventHandler, PointerEventHandler, ReactNode, Ref, TimeHTMLAttributes, VideoHTMLAttributes } from "react";
2
+ //#region src/components/audio/player/AudioPlayer.d.ts
3
+ interface AudioPlayerProps extends MediaHTMLAttributes<HTMLAudioElement> {
4
+ src?: string;
5
+ ref?: Ref<HTMLAudioElement>;
6
+ }
7
+ declare function AudioPlayer({ ref, ...props }: AudioPlayerProps): import("react").JSX.Element;
8
+ declare namespace index_parts_d_exports {
9
+ export { AudioPlayer as Player };
10
+ }
11
+ //#endregion
12
+ //#region src/components/controls/root/ControlsRoot.d.ts
13
+ interface ControlsRootProps extends HTMLAttributes<HTMLDivElement> {
14
+ ref?: Ref<HTMLDivElement>;
15
+ }
16
+ declare function ControlsRoot(props: ControlsRootProps): import("react").JSX.Element;
17
+ declare namespace index_parts_d_exports$1 {
18
+ export { ControlsRoot as Root };
19
+ }
20
+ //#endregion
21
+ //#region src/types.d.ts
22
+ type ButtonAttributes = ButtonHTMLAttributes<HTMLButtonElement>;
23
+ type TimeDisplayAttributes = Omit<TimeHTMLAttributes<HTMLTimeElement>, "children" | "dateTime">;
24
+ type OnErrorFunc = (playerError: PlayerError) => void;
25
+ type PlayerError = MediaPlaybackError | GeneralError;
26
+ interface MediaPlaybackError {
27
+ type: "media";
28
+ error: MediaError;
29
+ }
30
+ interface GeneralError {
31
+ type: "fullscreen" | "play" | "pip";
32
+ error: unknown;
33
+ }
34
+ //#endregion
35
+ //#region src/components/fullscreenButton/root/FullscreenButtonRoot.d.ts
36
+ interface FullscreenButtonRootProps extends ButtonAttributes {
37
+ ref?: Ref<HTMLButtonElement>;
38
+ }
39
+ declare function FullscreenButtonRoot({ onClick, ...props }: FullscreenButtonRootProps): import("react").JSX.Element;
40
+ declare namespace index_parts_d_exports$2 {
41
+ export { FullscreenButtonRoot as Root };
42
+ }
43
+ //#endregion
44
+ //#region src/components/pipButton/root/PipButtonRoot.d.ts
45
+ interface PipButtonRootProps extends ButtonAttributes {
46
+ ref?: Ref<HTMLButtonElement>;
47
+ }
48
+ declare function PipButtonRoot({ onClick, ...props }: PipButtonRootProps): import("react").JSX.Element;
49
+ declare namespace index_parts_d_exports$3 {
50
+ export { PipButtonRoot as Root };
51
+ }
52
+ //#endregion
53
+ //#region src/components/playbackRateButton/root/PlaybackRateButtonRoot.d.ts
54
+ interface PlaybackRateButtonRootProps extends ButtonAttributes {
55
+ playbackRate: number;
56
+ ref?: Ref<HTMLButtonElement>;
57
+ }
58
+ declare function PlaybackRateButtonRoot({ playbackRate, onClick, ...props }: PlaybackRateButtonRootProps): import("react").JSX.Element;
59
+ declare namespace index_parts_d_exports$5 {
60
+ export { PlaybackRateButtonRoot as Root };
61
+ }
62
+ //#endregion
63
+ //#region src/components/playButton/root/PlayButtonRoot.d.ts
64
+ interface PlayButtonRootProps extends ButtonAttributes {
65
+ ref?: Ref<HTMLButtonElement>;
66
+ }
67
+ declare function PlayButtonRoot({ onClick, ...props }: PlayButtonRootProps): import("react").JSX.Element;
68
+ declare namespace index_parts_d_exports$4 {
69
+ export { PlayButtonRoot as Root };
70
+ }
71
+ //#endregion
72
+ //#region src/components/player/root/PlayerRoot.d.ts
73
+ interface PlayerRootProps {
74
+ children: ReactNode;
75
+ lang?: string;
76
+ onError?: OnErrorFunc;
77
+ }
78
+ declare const PlayerRoot: ({ children, lang, onError }: PlayerRootProps) => import("react").JSX.Element;
79
+ //#endregion
80
+ //#region src/components/player/container/PlayerContainer.d.ts
81
+ interface PlayerContainerProps extends HTMLAttributes<HTMLDivElement> {
82
+ ref?: Ref<HTMLDivElement>;
83
+ }
84
+ declare function PlayerContainer({ onKeyDown, style, ref, ...props }: PlayerContainerProps): import("react").JSX.Element;
85
+ declare namespace index_parts_d_exports$6 {
86
+ export { PlayerContainer as Container, PlayerRoot as Root };
87
+ }
88
+ //#endregion
89
+ //#region src/components/seekbar/root/SeekbarRoot.d.ts
90
+ interface SeekbarRootProps extends HTMLAttributes<HTMLDivElement> {
91
+ skipInterval?: number;
92
+ ref?: Ref<HTMLDivElement>;
93
+ }
94
+ declare function SeekbarRoot({ skipInterval, ref, onKeyDown, onPointerMove, onPointerDown, onLostPointerCapture, ...props }: SeekbarRootProps): import("react").JSX.Element;
95
+ //#endregion
96
+ //#region src/components/seekbar/track/SeekbarTrack.d.ts
97
+ interface SeekbarTrackProps extends HTMLAttributes<HTMLDivElement> {
98
+ ref?: Ref<HTMLDivElement>;
99
+ }
100
+ declare function SeekbarTrack(props: SeekbarTrackProps): import("react").JSX.Element;
101
+ //#endregion
102
+ //#region src/components/seekbar/progress/SeekbarProgress.d.ts
103
+ interface SeekbarProgressProps extends HTMLAttributes<HTMLDivElement> {
104
+ ref?: Ref<HTMLDivElement>;
105
+ }
106
+ declare function SeekbarProgress({ style, ...props }: SeekbarProgressProps): import("react").JSX.Element;
107
+ //#endregion
108
+ //#region src/components/seekbar/buffer/SeekbarBuffer.d.ts
109
+ interface SeekbarBufferProps extends HTMLAttributes<HTMLDivElement> {
110
+ ref?: Ref<HTMLDivElement>;
111
+ }
112
+ declare function SeekbarBuffer({ style, ...props }: SeekbarBufferProps): import("react").JSX.Element;
113
+ //#endregion
114
+ //#region src/components/seekbar/thumb/SeekbarThumb.d.ts
115
+ interface SeekbarThumbProps extends HTMLAttributes<HTMLDivElement> {
116
+ ref?: Ref<HTMLDivElement>;
117
+ }
118
+ declare function SeekbarThumb(props: SeekbarThumbProps): import("react").JSX.Element;
119
+ declare namespace index_parts_d_exports$7 {
120
+ export { SeekbarBuffer as Buffer, SeekbarProgress as Progress, SeekbarRoot as Root, SeekbarThumb as Thumb, SeekbarTrack as Track };
121
+ }
122
+ //#endregion
123
+ //#region src/components/skipButton/root/SkipButtonRoot.d.ts
124
+ type SkipDirection = "back" | "forward";
125
+ interface SkipButtonRootProps extends ButtonAttributes {
126
+ direction: SkipDirection;
127
+ skipInterval?: number;
128
+ ref?: Ref<HTMLButtonElement>;
129
+ }
130
+ declare function SkipButtonRoot({ direction, skipInterval, onClick, ...props }: SkipButtonRootProps): import("react").JSX.Element;
131
+ declare namespace index_parts_d_exports$8 {
132
+ export { SkipButtonRoot as Root };
133
+ }
134
+ //#endregion
135
+ //#region src/components/timeDisplay/root/TimeDisplayRoot.d.ts
136
+ interface TimeDisplayRootProps extends HTMLAttributes<HTMLDivElement> {
137
+ initialMode?: "elapsed" | "remaining";
138
+ ref?: Ref<HTMLDivElement>;
139
+ }
140
+ declare function TimeDisplayRoot({ initialMode, ...props }: TimeDisplayRootProps): import("react").JSX.Element;
141
+ //#endregion
142
+ //#region src/components/timeDisplay/toggle/TimeDisplayToggle.d.ts
143
+ interface TimeDisplayToggleProps extends ButtonAttributes {
144
+ ref?: Ref<HTMLButtonElement>;
145
+ }
146
+ declare function TimeDisplayToggle({ onClick, ...props }: TimeDisplayToggleProps): import("react").JSX.Element;
147
+ //#endregion
148
+ //#region src/components/timeDisplay/timer/TimeDisplayTimer.d.ts
149
+ interface TimeDisplayTimerProps extends TimeDisplayAttributes {
150
+ ref?: Ref<HTMLTimeElement>;
151
+ }
152
+ declare function TimeDisplayTimer({ ref, ...props }: TimeDisplayTimerProps): import("react").JSX.Element;
153
+ //#endregion
154
+ //#region src/components/timeDisplay/duration/TimeDisplayDuration.d.ts
155
+ interface TimeDisplayDurationProps extends TimeDisplayAttributes {
156
+ ref?: Ref<HTMLTimeElement>;
157
+ }
158
+ declare function TimeDisplayDuration(props: TimeDisplayDurationProps): import("react").JSX.Element;
159
+ declare namespace index_parts_d_exports$9 {
160
+ export { TimeDisplayDuration as Duration, TimeDisplayRoot as Root, TimeDisplayTimer as Timer, TimeDisplayToggle as Toggle };
161
+ }
162
+ //#endregion
163
+ //#region src/components/video/root/VideoRoot.d.ts
164
+ interface VideoRootProps extends HTMLAttributes<HTMLDivElement> {
165
+ ref?: Ref<HTMLDivElement>;
166
+ }
167
+ declare function VideoRoot({ style, ...props }: VideoRootProps): import("react").JSX.Element;
168
+ //#endregion
169
+ //#region src/components/video/overlay/useOverlayInteractivity.d.ts
170
+ type OnDoubleClick = "fullscreen" | PointerEventHandler<HTMLButtonElement>;
171
+ interface OverlayInteractivityOptions {
172
+ onPointerUp?: MouseEventHandler<HTMLButtonElement>;
173
+ onPointerDown?: MouseEventHandler<HTMLButtonElement>;
174
+ onDoubleClick?: OnDoubleClick;
175
+ onDoubleTouch?: OnDoubleClick;
176
+ doubleClickInterval?: number;
177
+ }
178
+ //#endregion
179
+ //#region src/components/video/overlay/VideoOverlay.d.ts
180
+ interface VideoOverlayRootProps extends Omit<ButtonAttributes, "onDoubleClick"> {
181
+ label: string;
182
+ onDoubleClick?: OverlayInteractivityOptions["onDoubleClick"];
183
+ onDoubleTouch?: OverlayInteractivityOptions["onDoubleTouch"];
184
+ doubleClickInterval?: number;
185
+ ref?: Ref<HTMLButtonElement>;
186
+ }
187
+ declare function VideoOverlayRoot({ style, label, onDoubleClick, onDoubleTouch, doubleClickInterval, onPointerDown, onPointerUp, onKeyDown, ...props }: VideoOverlayRootProps): import("react").JSX.Element;
188
+ //#endregion
189
+ //#region src/components/video/player/VideoPlayer.d.ts
190
+ interface VideoPlayerProps extends VideoHTMLAttributes<HTMLVideoElement> {
191
+ src?: string;
192
+ ref?: Ref<HTMLVideoElement>;
193
+ }
194
+ declare function VideoPlayer({ ref, ...props }: VideoPlayerProps): import("react").JSX.Element;
195
+ declare namespace index_parts_d_exports$10 {
196
+ export { VideoOverlayRoot as Overlay, VideoPlayer as Player, VideoRoot as Root };
197
+ }
198
+ //#endregion
199
+ //#region src/components/volume/slider/VolumeSlider.d.ts
200
+ interface VolumeSliderRootProps extends HTMLAttributes<HTMLDivElement> {
201
+ volumeInterval?: number;
202
+ ref?: Ref<HTMLDivElement>;
203
+ computeAriaValueText?: ({ volume, isMuted }: {
204
+ volume: number;
205
+ isMuted: boolean;
206
+ }) => string;
207
+ }
208
+ declare function VolumeSlider({ volumeInterval, ref, onPointerDown, onPointerMove, onLostPointerCapture, onKeyDown, computeAriaValueText, ...props }: VolumeSliderRootProps): import("react").JSX.Element;
209
+ //#endregion
210
+ //#region src/components/volume/mute/VolumeMute.d.ts
211
+ interface VolumeMuteProps extends ButtonAttributes {
212
+ ref?: Ref<HTMLButtonElement>;
213
+ }
214
+ declare function VolumeMute({ onClick, ...props }: VolumeMuteProps): import("react").JSX.Element;
215
+ //#endregion
216
+ //#region src/components/volume/track/VolumeTrack.d.ts
217
+ interface VolumeTrackProps extends HTMLAttributes<HTMLDivElement> {
218
+ ref?: Ref<HTMLDivElement>;
219
+ }
220
+ declare function VolumeTrack(props: VolumeTrackProps): import("react").JSX.Element;
221
+ //#endregion
222
+ //#region src/components/volume/progress/VolumeProgress.d.ts
223
+ interface VolumeProgressProps extends HTMLAttributes<HTMLDivElement> {
224
+ ref?: Ref<HTMLDivElement>;
225
+ }
226
+ declare function VolumeProgress(props: VolumeProgressProps): import("react").JSX.Element;
227
+ //#endregion
228
+ //#region src/components/volume/thumb/VolumeThumb.d.ts
229
+ interface VolumeThumbProps extends HTMLAttributes<HTMLDivElement> {
230
+ ref?: Ref<HTMLDivElement>;
231
+ }
232
+ declare function VolumeThumb(props: VolumeThumbProps): import("react").JSX.Element;
233
+ declare namespace index_parts_d_exports$11 {
234
+ export { VolumeMute as Mute, VolumeProgress as Progress, VolumeSlider as Slider, VolumeThumb as Thumb, VolumeTrack as Track };
235
+ }
236
+ //#endregion
237
+ //#region src/state/types.d.ts
238
+ type Selector<T> = (state: PlayerState) => T;
239
+ type LifeCycleState = "pending" | "loading" | "ready" | "error";
240
+ interface PlayerState {
241
+ state: LifeCycleState;
242
+ isPlaying: boolean;
243
+ isMuted: boolean;
244
+ isFullscreen: boolean;
245
+ isPictureInPicture: boolean;
246
+ isBuffering: boolean;
247
+ durationInSec: number;
248
+ currentTimeInSec: number;
249
+ optimisticTimeInSec: number | null;
250
+ bufferedEndInSec: number | null;
251
+ volume: number;
252
+ playbackRate: number;
253
+ }
254
+ //#endregion
255
+ //#region src/state/PlayerContext.d.ts
256
+ declare function usePlayer<T>(selector: Selector<T>): T;
257
+ declare function usePlayerControls(): {
258
+ play: () => Promise<void>;
259
+ pause: () => void | undefined;
260
+ toggle: () => void | Promise<void>;
261
+ seek: (time: number) => void;
262
+ skip: (delta: number) => void;
263
+ toggleFullscreen: () => Promise<void>;
264
+ togglePip: () => Promise<void>;
265
+ toggleMute: () => boolean | null;
266
+ mute: () => true | null;
267
+ unmute: () => false | null;
268
+ stepVolume: (delta: number) => void;
269
+ setVolume: (volume: number) => void;
270
+ stepPlaybackRate: (delta: number) => void;
271
+ setPlaybackRate: (rate: number) => void;
272
+ };
273
+ //#endregion
274
+ export { index_parts_d_exports as Audio, index_parts_d_exports$1 as Controls, index_parts_d_exports$2 as FullscreenButton, type LifeCycleState, type OnErrorFunc, index_parts_d_exports$3 as PipButton, index_parts_d_exports$4 as PlayButton, index_parts_d_exports$5 as PlaybackRateButton, index_parts_d_exports$6 as Player, type PlayerError, type PlayerState, index_parts_d_exports$7 as Seekbar, type Selector, index_parts_d_exports$8 as SkipButton, index_parts_d_exports$9 as TimeDisplay, index_parts_d_exports$10 as Video, index_parts_d_exports$11 as Volume, usePlayer, usePlayerControls };
275
+ //# sourceMappingURL=index.d.ts.map