@lucaismyname/ginger 0.0.17 → 0.0.21
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/README.md +76 -0
- package/dist/client.cjs +1 -1
- package/dist/client.js +2 -2
- package/dist/client.test.d.ts +2 -0
- package/dist/client.test.d.ts.map +1 -0
- package/dist/components/controls/Controls.d.ts +26 -13
- package/dist/components/controls/Controls.d.ts.map +1 -1
- package/dist/experimental-gapless/index.cjs.map +1 -1
- package/dist/experimental-gapless/index.d.ts +3 -1
- package/dist/experimental-gapless/index.d.ts.map +1 -1
- package/dist/experimental-gapless/index.js.map +1 -1
- package/dist/{ginger-F4UDi2Qf.js → ginger-8x4WzVmw.js} +196 -144
- package/dist/ginger-8x4WzVmw.js.map +1 -0
- package/dist/ginger-CMbd3s8C.cjs +2 -0
- package/dist/ginger-CMbd3s8C.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +44 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/testing/helpers.d.ts +29 -0
- package/dist/testing/helpers.d.ts.map +1 -1
- package/dist/testing/helpers.test.d.ts +2 -0
- package/dist/testing/helpers.test.d.ts.map +1 -0
- package/dist/testing/index.cjs +48 -43
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +6888 -3749
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/index.test.d.ts +2 -0
- package/dist/testing/index.test.d.ts.map +1 -0
- package/dist/testing/renderGinger.d.ts.map +1 -1
- package/dist/{useNextTrackPrefetch-BeAKS3SR.cjs → useNextTrackPrefetch-CFoUynDv.cjs} +2 -2
- package/dist/{useNextTrackPrefetch-BeAKS3SR.cjs.map → useNextTrackPrefetch-CFoUynDv.cjs.map} +1 -1
- package/dist/{useNextTrackPrefetch-gKls_h_N.js → useNextTrackPrefetch-CV1khU0h.js} +2 -2
- package/dist/{useNextTrackPrefetch-gKls_h_N.js.map → useNextTrackPrefetch-CV1khU0h.js.map} +1 -1
- package/package.json +9 -1
- package/dist/ginger-DWOyCog6.cjs +0 -2
- package/dist/ginger-DWOyCog6.cjs.map +0 -1
- package/dist/ginger-F4UDi2Qf.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ginger-CMbd3s8C.cjs","sources":["../src/context/GingerContext.tsx","../src/audio/GingerPlayer.tsx","../src/core/queue.ts","../src/core/transitions.ts","../src/internal/selectors.ts","../src/components/current/createTextDisplay.tsx","../src/components/current/texts.ts","../src/components/current/Year.tsx","../src/components/current/Lyrics.tsx","../src/internal/lyrics.ts","../src/hooks/useGingerLyricsSync.ts","../src/components/current/LyricsSynced.tsx","../src/hooks/useGingerChapters.ts","../src/internal/formatTime.ts","../src/components/current/Chapters.tsx","../src/components/current/FileUrl.tsx","../src/components/current/Artwork.tsx","../src/components/current/QueueMeta.tsx","../src/components/current/Time.tsx","../src/components/current/Playback.tsx","../src/context/GingerLocaleContext.tsx","../src/hooks/useControlBindings.ts","../src/components/controls/Controls.tsx","../src/components/playlist/GingerPlaylist.tsx","../src/components/queue/QueueDisplay.tsx","../src/core/playbackReducer.ts","../src/media/useMediaSession.ts","../src/context/GingerProvider.tsx","../src/ginger.ts"],"sourcesContent":["import { createContext, useContext, type Dispatch, type MutableRefObject } from \"react\";\nimport type {\n GingerAction,\n GingerInitPayload,\n GingerState,\n PlaybackMode,\n PlaylistMeta,\n RepeatMode,\n Track,\n} from \"../types\";\n\nexport type GingerContextValue = {\n state: GingerState;\n dispatch: Dispatch<GingerAction>;\n audioRef: MutableRefObject<HTMLAudioElement | null>;\n notifyEnded: () => void;\n /** Full reset to match `createInitialState` / provider `initial*` props. */\n init: (payload: GingerInitPayload) => void;\n play: () => void;\n pause: () => void;\n togglePlayPause: () => void;\n seek: (timeSeconds: number) => void;\n setVolume: (volume: number) => void;\n setMuted: (muted: boolean) => void;\n toggleMute: () => void;\n setPlaybackRate: (rate: number) => void;\n next: () => void;\n prev: () => void;\n setRepeatMode: (mode: RepeatMode) => void;\n cycleRepeat: () => void;\n toggleShuffle: () => void;\n setQueue: (tracks: Track[], currentIndex?: number) => void;\n insertTrackAt: (track: Track, index?: number, autoPlay?: boolean) => void;\n removeTrackAt: (index: number) => void;\n moveTrack: (fromIndex: number, toIndex: number) => void;\n enqueueNext: (track: Track) => void;\n playTrackAt: (index: number) => void;\n selectTrackAt: (index: number) => void;\n setPlaylistMeta: (meta: PlaylistMeta | null) => void;\n setPlaybackMode: (mode: PlaybackMode) => void;\n};\n\nconst GingerContext = createContext<GingerContextValue | null>(null);\n\nexport function useGingerContext(): GingerContextValue {\n const ctx = useContext(GingerContext);\n if (!ctx) throw new Error(\"Ginger components must be used within <Ginger.Provider>\");\n return ctx;\n}\n\nexport { GingerContext };\n","import { useEffect, useRef, useState, type AudioHTMLAttributes, type CSSProperties } from \"react\";\nimport { useGingerContext } from \"../context/GingerContext\";\n\nexport type GingerPlayerProps = {\n className?: string;\n style?: CSSProperties;\n preload?: AudioHTMLAttributes<HTMLAudioElement>[\"preload\"];\n crossOrigin?: AudioHTMLAttributes<HTMLAudioElement>[\"crossOrigin\"];\n respectReducedMotion?: boolean;\n};\n\nfunction readBufferedFraction(el: HTMLAudioElement): number {\n const { buffered, duration } = el;\n if (!(duration > 0) || buffered.length === 0) return 0;\n return Math.min(1, buffered.end(buffered.length - 1) / duration);\n}\n\nexport function GingerPlayer({\n className,\n style,\n preload = \"metadata\",\n crossOrigin,\n respectReducedMotion = false,\n}: GingerPlayerProps) {\n const { audioRef, dispatch, state, notifyEnded } = useGingerContext();\n const url = state.tracks[state.currentIndex]?.fileUrl ?? \"\";\n const lastTimeSnapshotRef = useRef({\n currentTime: -1,\n duration: -1,\n bufferedFraction: -1,\n });\n /** Avoid MEDIA_SOURCE_CLEARED on first paint with an empty queue (no prior media). */\n const lastActiveUrlRef = useRef(\"\");\n\n const [reducedMotion, setReducedMotion] = useState(false);\n\n useEffect(() => {\n if (!respectReducedMotion || typeof window === \"undefined\") return;\n const mql = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n const sync = () => setReducedMotion(mql.matches);\n sync();\n mql.addEventListener(\"change\", sync);\n return () => mql.removeEventListener(\"change\", sync);\n }, [respectReducedMotion]);\n\n const syncTime = (el: HTMLAudioElement, force = false) => {\n const next = {\n currentTime: el.currentTime,\n duration: el.duration,\n bufferedFraction: readBufferedFraction(el),\n };\n const prev = lastTimeSnapshotRef.current;\n const timeThreshold = reducedMotion ? 0.5 : 0.25;\n const changedEnough =\n Math.abs(next.currentTime - prev.currentTime) >= timeThreshold ||\n Math.abs(next.duration - prev.duration) >= 0.01 ||\n Math.abs(next.bufferedFraction - prev.bufferedFraction) >= 0.01;\n if (!force && !changedEnough) return;\n lastTimeSnapshotRef.current = next;\n dispatch({\n type: \"MEDIA_TIME_UPDATE\",\n payload: next,\n });\n };\n\n useEffect(() => {\n const el = audioRef.current;\n if (!el) return;\n el.volume = state.volume;\n el.muted = state.muted;\n el.playbackRate = state.playbackRate;\n }, [audioRef, state.volume, state.muted, state.playbackRate]);\n\n useEffect(() => {\n const el = audioRef.current;\n if (!el) return;\n if (!url) {\n el.removeAttribute(\"src\");\n lastTimeSnapshotRef.current = { currentTime: -1, duration: -1, bufferedFraction: -1 };\n if (lastActiveUrlRef.current !== \"\") {\n dispatch({ type: \"MEDIA_SOURCE_CLEARED\" });\n }\n lastActiveUrlRef.current = \"\";\n return;\n }\n if (el.getAttribute(\"src\") !== url) {\n el.src = url;\n el.load();\n lastTimeSnapshotRef.current = { currentTime: -1, duration: -1, bufferedFraction: -1 };\n }\n lastActiveUrlRef.current = url;\n }, [audioRef, dispatch, state.currentIndex, state.tracks, url]);\n\n return (\n <audio\n ref={audioRef}\n className={className}\n style={style}\n preload={preload}\n crossOrigin={crossOrigin}\n controls={false}\n playsInline\n onTimeUpdate={(e) => {\n syncTime(e.currentTarget);\n }}\n onLoadedMetadata={(e) => {\n const el = e.currentTarget;\n lastTimeSnapshotRef.current = { currentTime: -1, duration: -1, bufferedFraction: -1 };\n dispatch({\n type: \"MEDIA_LOADED_METADATA\",\n payload: {\n duration: el.duration,\n bufferedFraction: readBufferedFraction(el),\n },\n });\n }}\n onSeeking={(e) => syncTime(e.currentTarget, true)}\n onSeeked={(e) => syncTime(e.currentTarget, true)}\n onEnded={() => notifyEnded()}\n onPlay={() => dispatch({ type: \"MEDIA_PLAY\" })}\n onPause={() => dispatch({ type: \"MEDIA_PAUSE\" })}\n onWaiting={() => dispatch({ type: \"MEDIA_WAITING\" })}\n onCanPlay={() => dispatch({ type: \"MEDIA_CANPLAY\" })}\n onProgress={(e) => syncTime(e.currentTarget, true)}\n onVolumeChange={(e) => {\n const el = e.currentTarget;\n dispatch({\n type: \"MEDIA_VOLUME_SYNC\",\n payload: { volume: el.volume, muted: el.muted },\n });\n }}\n onError={() => {\n const el = audioRef.current;\n const code = el?.error?.code;\n const message =\n code === 1\n ? \"MEDIA_ERR_ABORTED\"\n : code === 2\n ? \"MEDIA_ERR_NETWORK\"\n : code === 3\n ? \"MEDIA_ERR_DECODE\"\n : code === 4\n ? \"MEDIA_ERR_SRC_NOT_SUPPORTED\"\n : \"MEDIA_ERR_UNKNOWN\";\n dispatch({ type: \"MEDIA_ERROR\", payload: { message } });\n }}\n />\n );\n}\n","import type { Track } from \"../types\";\n\nexport function clampIndex(index: number, length: number): number {\n if (length <= 0) return 0;\n return Math.max(0, Math.min(length - 1, index));\n}\n\nexport function shuffleWithAnchor(tracks: Track[], anchorIndex: number): Track[] {\n if (tracks.length <= 1) return [...tracks];\n const anchor = tracks[anchorIndex];\n if (!anchor) return [...tracks];\n const rest = tracks.filter((_, i) => i !== anchorIndex);\n for (let i = rest.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [rest[i], rest[j]] = [rest[j]!, rest[i]!];\n }\n return [anchor, ...rest];\n}\n\nexport function trackIdentity(track: Track | null | undefined): string {\n if (!track) return \"\";\n return track.id != null && track.id !== \"\" ? `id:${track.id}` : `file:${track.fileUrl}`;\n}\n\nexport function findIndexByTrackIdentity(tracks: Track[], target: Track | null | undefined): number {\n if (!target) return 0;\n const byRef = tracks.findIndex((t) => t === target);\n if (byRef !== -1) return byRef;\n\n const identity = trackIdentity(target);\n if (!identity) return 0;\n\n const matches: number[] = [];\n for (let i = 0; i < tracks.length; i += 1) {\n if (trackIdentity(tracks[i]) === identity) matches.push(i);\n }\n if (matches.length === 0) return 0;\n if (matches.length === 1) return matches[0]!;\n\n const nodeEnv =\n typeof globalThis !== \"undefined\" && \"process\" in globalThis\n ? (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV\n : undefined;\n if (nodeEnv != null && nodeEnv !== \"production\") {\n console.warn(\n \"[@lucaismyname/ginger] Ambiguous track identity: multiple queue rows share the same fileUrl without a unique `id`. Resolving to the first match.\",\n );\n }\n return matches[0]!;\n}\n\nexport function insertTrackAt(tracks: Track[], track: Track, index?: number): Track[] {\n const next = [...tracks];\n const at = Math.max(0, Math.min(next.length, index ?? next.length));\n next.splice(at, 0, track);\n return next;\n}\n\nexport function removeTrackAt(tracks: Track[], index: number): Track[] {\n if (index < 0 || index >= tracks.length) return [...tracks];\n const next = [...tracks];\n next.splice(index, 1);\n return next;\n}\n\nexport function moveTrack(tracks: Track[], fromIndex: number, toIndex: number): Track[] {\n if (\n fromIndex === toIndex ||\n fromIndex < 0 ||\n fromIndex >= tracks.length ||\n toIndex < 0 ||\n toIndex >= tracks.length\n ) {\n return [...tracks];\n }\n const next = [...tracks];\n const [item] = next.splice(fromIndex, 1);\n if (!item) return [...tracks];\n next.splice(toIndex, 0, item);\n return next;\n}\n\nexport function addNextTrack(tracks: Track[], currentIndex: number, track: Track): Track[] {\n return insertTrackAt(tracks, track, Math.max(0, Math.min(tracks.length, currentIndex + 1)));\n}\n","import type { GingerState, RepeatMode, Track } from \"../types\";\nimport { clampIndex } from \"./queue\";\n\n/** Fields used by next/prev/ended navigation; avoids coupling helpers to full `GingerState`. */\nexport type GingerPlaybackNavigationSlice = Pick<\n GingerState,\n \"tracks\" | \"currentIndex\" | \"repeatMode\" | \"playbackMode\"\n>;\n\nexport type EndedTransition =\n | { kind: \"replay_same\" }\n | { kind: \"advance\"; nextIndex: number }\n | { kind: \"wrap\"; nextIndex: number }\n | { kind: \"stop\"; nextIndex: number };\n\nexport function computeEndedTransition(state: GingerPlaybackNavigationSlice): EndedTransition {\n const { tracks, currentIndex, repeatMode, playbackMode } = state;\n const len = tracks.length;\n if (len === 0) return { kind: \"stop\", nextIndex: 0 };\n if (repeatMode === \"one\") return { kind: \"replay_same\" };\n if (playbackMode === \"single\") return { kind: \"stop\", nextIndex: clampIndex(currentIndex, len) };\n if (currentIndex < len - 1) return { kind: \"advance\", nextIndex: currentIndex + 1 };\n if (repeatMode === \"all\") return { kind: \"wrap\", nextIndex: 0 };\n return { kind: \"stop\", nextIndex: clampIndex(currentIndex, len) };\n}\n\nexport function computeNextIndex(state: GingerPlaybackNavigationSlice): number {\n const { tracks, currentIndex, repeatMode, playbackMode } = state;\n const len = tracks.length;\n if (len === 0) return 0;\n if (playbackMode === \"single\") return clampIndex(currentIndex, len);\n if (currentIndex < len - 1) return currentIndex + 1;\n if (repeatMode === \"all\") return 0;\n return clampIndex(currentIndex, len);\n}\n\nexport function computePrevIndex(state: GingerPlaybackNavigationSlice): number {\n const { tracks, currentIndex, repeatMode, playbackMode } = state;\n const len = tracks.length;\n if (len === 0) return 0;\n if (playbackMode === \"single\") return clampIndex(currentIndex, len);\n if (currentIndex > 0) return currentIndex - 1;\n if (repeatMode === \"all\") return len - 1;\n return 0;\n}\n\nexport function cycleRepeatMode(mode: RepeatMode): RepeatMode {\n if (mode === \"off\") return \"all\";\n if (mode === \"all\") return \"one\";\n return \"off\";\n}\n\nexport function resolveArtworkUrl(track: Track | null, playlistArtwork?: string | null): string | undefined {\n return track?.artworkUrl ?? playlistArtwork ?? undefined;\n}\n\nexport function resolveAlbumLine(track: Track | null, playlistSubtitle?: string | null): string | undefined {\n return track?.album ?? playlistSubtitle ?? undefined;\n}\n","import type { GingerState, PlaybackUiState, Track } from \"../types\";\nimport { resolveAlbumLine, resolveArtworkUrl } from \"../core/transitions\";\n\nexport function getCurrentTrack(state: GingerState): Track | null {\n const t = state.tracks[state.currentIndex];\n return t ?? null;\n}\n\nexport function derivePlaybackUiState(state: GingerState): PlaybackUiState {\n if (state.errorMessage) return \"error\";\n if (state.tracks.length === 0) return \"idle\";\n if (state.isBuffering) return \"loading\";\n if (!state.isPaused) return \"playing\";\n if (\n Number.isFinite(state.duration) &&\n state.duration > 0 &&\n state.currentTime >= state.duration - 0.05\n ) {\n return \"ended\";\n }\n return \"paused\";\n}\n\nexport function effectiveDuration(state: GingerState): number {\n const d = state.duration;\n if (Number.isFinite(d) && d > 0) return d;\n const hint = state.tracks[state.currentIndex]?.durationSeconds;\n if (typeof hint === \"number\" && Number.isFinite(hint) && hint > 0) return hint;\n return 0;\n}\n\nexport function effectiveRemaining(state: GingerState): number {\n const dur = effectiveDuration(state);\n const rem = dur - state.currentTime;\n return Number.isFinite(rem) ? Math.max(0, rem) : 0;\n}\n\nexport function progressFraction(state: GingerState): number {\n const dur = effectiveDuration(state);\n if (!(dur > 0)) return 0;\n return Math.min(1, Math.max(0, state.currentTime / dur));\n}\n\nexport function resolvedArtwork(state: GingerState): string | undefined {\n const track = getCurrentTrack(state);\n return resolveArtworkUrl(track, state.playlistMeta?.artworkUrl);\n}\n\nexport function resolvedAlbumLine(state: GingerState): string | undefined {\n const track = getCurrentTrack(state);\n return resolveAlbumLine(track, state.playlistMeta?.subtitle);\n}\n","import type { ReactElement, ReactNode } from \"react\";\nimport type { DisplayBaseProps, GingerState, Track } from \"../../types\";\nimport { getCurrentTrack } from \"../../internal/selectors\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\n\nexport type TextDisplayProps = DisplayBaseProps & {\n children?: (value: string, state: GingerState) => ReactNode;\n};\n\nexport function createTextDisplay(\n displayName: string,\n select: (state: GingerState) => string | undefined,\n): (props: TextDisplayProps) => ReactElement | null {\n function Comp(props: TextDisplayProps) {\n const state = useGingerState();\n const raw = select(state) ?? \"\";\n const value = raw.trim();\n const { className, style, fallback, empty, children } = props;\n if (!value) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n if (children) return <span className={className} style={style}>{children(value, state)}</span>;\n return (\n <span className={className} style={style}>\n {value}\n </span>\n );\n }\n Comp.displayName = displayName;\n return Comp;\n}\n\nexport function createTrackFieldDisplay(\n displayName: string,\n select: (track: Track | null) => string | undefined,\n): (props: TextDisplayProps) => ReactElement | null {\n return createTextDisplay(displayName, (state) => select(getCurrentTrack(state)));\n}\n","import { createTextDisplay, createTrackFieldDisplay } from \"./createTextDisplay\";\nimport { getCurrentTrack, resolvedAlbumLine } from \"../../internal/selectors\";\n\nexport const Title = createTrackFieldDisplay(\"Ginger.Current.Title\", (t) => t?.title);\nexport const Artist = createTrackFieldDisplay(\"Ginger.Current.Artist\", (t) => t?.artist);\nexport const Album = createTextDisplay(\"Ginger.Current.Album\", (s) => resolvedAlbumLine(s));\nexport const Description = createTrackFieldDisplay(\"Ginger.Current.Description\", (t) => t?.description);\nexport const Copyright = createTextDisplay(\"Ginger.Current.Copyright\", (s) => {\n const t = getCurrentTrack(s);\n return t?.copyright ?? s.playlistMeta?.copyright;\n});\nexport const Genre = createTrackFieldDisplay(\"Ginger.Current.Genre\", (t) => t?.genre);\nexport const Label = createTrackFieldDisplay(\"Ginger.Current.Label\", (t) => t?.label);\nexport const Isrc = createTrackFieldDisplay(\"Ginger.Current.Isrc\", (t) => t?.isrc);\nexport const TrackNumber = createTrackFieldDisplay(\"Ginger.Current.TrackNumber\", (t) =>\n t?.trackNumber != null ? String(t.trackNumber) : undefined,\n);\n","import type { TextDisplayProps } from \"./createTextDisplay\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\nimport { getCurrentTrack } from \"../../internal/selectors\";\n\nexport type YearProps = TextDisplayProps & {\n format?: (year: number) => string;\n};\n\nexport function Year({ className, style, fallback, empty, children, format }: YearProps) {\n const state = useGingerState();\n const y = getCurrentTrack(state)?.year;\n if (typeof y !== \"number\" || !Number.isFinite(y)) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n const text = format ? format(y) : String(y);\n if (children) return <span className={className} style={style}>{children(text, state)}</span>;\n return (\n <span className={className} style={style}>\n {text}\n </span>\n );\n}\n\nYear.displayName = \"Ginger.Current.Year\";\n","import type { CSSProperties, ReactNode } from \"react\";\nimport type { DisplayBaseProps, GingerState } from \"../../types\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\nimport { getCurrentTrack } from \"../../internal/selectors\";\n\nexport type LyricsProps = DisplayBaseProps & {\n children?: (value: string, state: GingerState) => ReactNode;\n /** When true, preserves internal newlines; trims only leading/trailing whitespace */\n preserveWhitespace?: boolean;\n};\n\nexport function Lyrics({ className, style, fallback, empty, children, preserveWhitespace = true }: LyricsProps) {\n const state = useGingerState();\n const raw = getCurrentTrack(state)?.lyrics ?? \"\";\n const value = preserveWhitespace ? raw.replace(/^\\s+|\\s+$/g, \"\") : raw.trim();\n if (!value) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n const whiteStyle: CSSProperties | undefined = preserveWhitespace ? { whiteSpace: \"pre-wrap\" } : undefined;\n if (children) return <span className={className} style={{ ...whiteStyle, ...style }}>{children(value, state)}</span>;\n return (\n <span className={className} style={{ ...whiteStyle, ...style }}>\n {value}\n </span>\n );\n}\n\nLyrics.displayName = \"Ginger.Current.Lyrics\";\n","export type TimedLyricLine = {\n time: number;\n text: string;\n};\n\nconst lrcTag = /\\[(\\d{1,2}):(\\d{2})(?:\\.(\\d{1,3}))?\\]/g;\n\nexport function parseLrc(lrc: string): TimedLyricLine[] {\n const lines: TimedLyricLine[] = [];\n for (const rawLine of lrc.split(/\\r?\\n/)) {\n const matches = [...rawLine.matchAll(lrcTag)];\n if (matches.length === 0) continue;\n const text = rawLine.replace(lrcTag, \"\").trim();\n for (const m of matches) {\n const minutes = Number(m[1] ?? 0);\n const seconds = Number(m[2] ?? 0);\n const millis = Number((m[3] ?? \"0\").padEnd(3, \"0\"));\n const time = minutes * 60 + seconds + millis / 1000;\n if (Number.isFinite(time) && time >= 0) {\n lines.push({ time, text });\n }\n }\n }\n return lines.sort((a, b) => a.time - b.time);\n}\n","import { useMemo } from \"react\";\nimport { useGingerMedia, useGingerPlayback } from \"../context/GingerSplitContexts\";\nimport { parseLrc, type TimedLyricLine } from \"../internal/lyrics\";\n\nexport type GingerLyricsSyncState = {\n lines: TimedLyricLine[];\n activeIndex: number;\n activeLine: TimedLyricLine | null;\n};\n\nexport function useGingerLyricsSync(): GingerLyricsSyncState {\n const { tracks, currentIndex } = useGingerPlayback();\n const { currentTime } = useGingerMedia();\n const currentTrack = tracks[currentIndex];\n\n const lines = useMemo(() => {\n if (!currentTrack) return [];\n if (Array.isArray(currentTrack.lyricsTimed) && currentTrack.lyricsTimed.length > 0) {\n return [...currentTrack.lyricsTimed]\n .filter((line) => Number.isFinite(line.time) && line.time >= 0)\n .sort((a, b) => a.time - b.time);\n }\n if (typeof currentTrack.lyrics === \"string\") {\n return parseLrc(currentTrack.lyrics);\n }\n return [];\n }, [currentTrack]);\n\n const activeIndex = useMemo(() => {\n for (let i = lines.length - 1; i >= 0; i -= 1) {\n if (currentTime >= lines[i]!.time) return i;\n }\n return -1;\n }, [currentTime, lines]);\n\n return {\n lines,\n activeIndex,\n activeLine: activeIndex >= 0 ? lines[activeIndex] ?? null : null,\n };\n}\n","import type { CSSProperties, ReactNode } from \"react\";\nimport type { DisplayBaseProps, GingerState } from \"../../types\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\nimport { useGingerLyricsSync } from \"../../hooks/useGingerLyricsSync\";\nimport type { TimedLyricLine } from \"../../internal/lyrics\";\n\nexport type LyricsSyncedProps = Omit<DisplayBaseProps, \"children\"> & {\n unstyled?: boolean;\n /** Class applied to the line that matches the current playback time. */\n activeClassName?: string;\n /** Class applied to every line. */\n lineClassName?: string;\n children?: (line: TimedLyricLine, index: number, active: boolean, state: GingerState) => ReactNode;\n};\n\nexport function LyricsSynced({\n className,\n style,\n fallback,\n empty,\n unstyled = false,\n activeClassName,\n lineClassName,\n children,\n}: LyricsSyncedProps) {\n const state = useGingerState();\n const { lines, activeIndex } = useGingerLyricsSync();\n\n if (lines.length === 0) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n\n const listStyle: CSSProperties = unstyled\n ? {}\n : {\n listStyle: \"none\",\n margin: 0,\n padding: 0,\n fontFamily: \"var(--ginger-font-family, system-ui, sans-serif)\",\n fontSize: \"var(--ginger-font-size, 14px)\",\n color: \"var(--ginger-primary-color, #111827)\",\n };\n\n return (\n <ul className={className} style={{ ...listStyle, ...style }} aria-label=\"Synced lyrics\">\n {lines.map((line, index) => {\n const active = index === activeIndex;\n return (\n <li\n key={`${line.time}-${index}`}\n aria-current={active ? \"true\" : undefined}\n data-ginger-active={active || undefined}\n className={[lineClassName, active ? activeClassName : undefined].filter(Boolean).join(\" \") || undefined}\n style={\n unstyled\n ? undefined\n : {\n padding: \"var(--ginger-playlist-row-padding, 4px 8px)\",\n fontWeight: active ? 600 : 400,\n opacity: active ? 1 : 0.75,\n }\n }\n >\n {children ? children(line, index, active, state) : line.text}\n </li>\n );\n })}\n </ul>\n );\n}\n\nLyricsSynced.displayName = \"Ginger.Current.LyricsSynced\";\n","import { useMemo } from \"react\";\nimport { useGingerMedia, useGingerPlayback } from \"../context/GingerSplitContexts\";\n\nexport type GingerChapter = {\n title: string;\n startSeconds: number;\n};\n\nexport type GingerChapterState = {\n list: GingerChapter[];\n activeIndex: number;\n active: GingerChapter | null;\n seekTo: (index: number) => void;\n};\n\nexport function useGingerChapters(): GingerChapterState {\n const { tracks, currentIndex } = useGingerPlayback();\n const { currentTime, seek } = useGingerMedia();\n\n const list = useMemo(() => {\n const chapters = tracks[currentIndex]?.chapters ?? [];\n return [...chapters]\n .filter((item) => item && Number.isFinite(item.startSeconds) && item.startSeconds >= 0)\n .sort((a, b) => a.startSeconds - b.startSeconds);\n }, [currentIndex, tracks]);\n\n const activeIndex = useMemo(() => {\n if (list.length === 0) return -1;\n for (let i = list.length - 1; i >= 0; i -= 1) {\n if (currentTime >= list[i]!.startSeconds) return i;\n }\n return -1;\n }, [currentTime, list]);\n\n return {\n list,\n activeIndex,\n active: activeIndex >= 0 ? list[activeIndex] ?? null : null,\n seekTo: (index: number) => {\n const chapter = list[index];\n if (chapter) seek(chapter.startSeconds);\n },\n };\n}\n","export function formatMmSs(seconds: number): string {\n if (!Number.isFinite(seconds) || seconds < 0) return \"0:00\";\n const s = Math.floor(seconds % 60);\n const m = Math.floor(seconds / 60);\n return `${m}:${s.toString().padStart(2, \"0\")}`;\n}\n","import type { CSSProperties, ReactNode } from \"react\";\nimport type { DisplayBaseProps, GingerState } from \"../../types\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\nimport { useGingerChapters, type GingerChapter } from \"../../hooks/useGingerChapters\";\nimport { formatMmSs } from \"../../internal/formatTime\";\n\nexport type ChaptersProps = Omit<DisplayBaseProps, \"children\"> & {\n /** Remove default list/row styles for fully custom styling. */\n unstyled?: boolean;\n /** Prefix before each chapter title (default: `formatMmSs(startSeconds)`). */\n formatStart?: (startSeconds: number) => string;\n children?: (chapter: GingerChapter, index: number, active: boolean, state: GingerState) => ReactNode;\n};\n\nexport function Chapters({\n className,\n style,\n fallback,\n empty,\n unstyled = false,\n formatStart = formatMmSs,\n children,\n}: ChaptersProps) {\n const state = useGingerState();\n const { list, activeIndex, seekTo } = useGingerChapters();\n\n if (list.length === 0) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n\n const listStyle: CSSProperties = unstyled\n ? {}\n : {\n listStyle: \"none\",\n margin: 0,\n padding: 0,\n fontFamily: \"var(--ginger-font-family, system-ui, sans-serif)\",\n fontSize: \"var(--ginger-font-size, 14px)\",\n color: \"var(--ginger-primary-color, #111827)\",\n };\n\n return (\n <ul className={className} style={{ ...listStyle, ...style }} aria-label=\"Chapters\">\n {list.map((chapter, index) => {\n const active = index === activeIndex;\n return (\n <li key={`${chapter.startSeconds}-${chapter.title}`}>\n <button\n type=\"button\"\n aria-current={active ? \"true\" : undefined}\n data-ginger-active={active || undefined}\n onClick={() => seekTo(index)}\n style={{\n width: unstyled ? undefined : \"100%\",\n textAlign: unstyled ? undefined : \"left\",\n border: unstyled ? undefined : \"none\",\n background: unstyled\n ? undefined\n : active\n ? \"var(--ginger-playlist-active-bg, rgba(17, 24, 39, 0.06))\"\n : \"transparent\",\n color: unstyled ? undefined : \"inherit\",\n font: unstyled ? undefined : \"inherit\",\n cursor: unstyled ? undefined : \"pointer\",\n padding: unstyled ? undefined : \"var(--ginger-playlist-row-padding, 6px 8px)\",\n }}\n >\n {children ? (\n children(chapter, index, active, state)\n ) : (\n <span>\n <span style={{ opacity: 0.75, marginRight: \"0.35em\" }}>{formatStart(chapter.startSeconds)}</span>\n {chapter.title}\n </span>\n )}\n </button>\n </li>\n );\n })}\n </ul>\n );\n}\n\nChapters.displayName = \"Ginger.Current.Chapters\";\n","import type { TextDisplayProps } from \"./createTextDisplay\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\nimport { getCurrentTrack } from \"../../internal/selectors\";\n\nexport type FileUrlProps = TextDisplayProps & {\n /** When false (default), renders nothing unless you explicitly opt in */\n visible?: boolean;\n};\n\nexport function FileUrl({ visible = false, className, style, fallback, empty, children }: FileUrlProps) {\n const state = useGingerState();\n if (!visible) return null;\n const value = getCurrentTrack(state)?.fileUrl ?? \"\";\n if (!value) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n if (children) return <span className={className} style={style}>{children(value, state)}</span>;\n return (\n <span className={className} style={style}>\n {value}\n </span>\n );\n}\n\nFileUrl.displayName = \"Ginger.Current.FileUrl\";\n","import type { CSSProperties, ImgHTMLAttributes } from \"react\";\nimport type { DisplayBaseProps } from \"../../types\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\nimport { getCurrentTrack, resolvedArtwork } from \"../../internal/selectors\";\n\nexport type ArtworkProps = DisplayBaseProps &\n Pick<ImgHTMLAttributes<HTMLImageElement>, \"sizes\" | \"loading\" | \"onError\" | \"decoding\"> & {\n /** Remove default wrapper/image styles for fully custom layout. */\n unstyled?: boolean;\n imgStyle?: CSSProperties;\n };\n\nexport function Artwork({\n className,\n style,\n fallback,\n empty,\n sizes,\n loading,\n onError,\n decoding,\n unstyled = false,\n imgStyle,\n}: ArtworkProps) {\n const state = useGingerState();\n const track = getCurrentTrack(state);\n const src = resolvedArtwork(state);\n if (!src) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n const alt = [track?.title, track?.artist].filter(Boolean).join(\" — \") || \"Artwork\";\n return (\n <div\n className={className}\n style={\n unstyled\n ? { ...style }\n : {\n background: \"var(--ginger-artwork-bg, transparent)\",\n borderRadius: \"var(--ginger-artwork-radius, 0)\",\n overflow: \"hidden\",\n ...style,\n }\n }\n >\n <img\n src={src}\n alt={alt}\n sizes={sizes}\n loading={loading}\n decoding={decoding}\n onError={onError}\n style={{\n display: unstyled ? undefined : \"block\",\n width: unstyled ? undefined : \"100%\",\n height: unstyled ? undefined : \"100%\",\n objectFit: unstyled ? undefined : \"cover\",\n ...imgStyle,\n }}\n />\n </div>\n );\n}\n\nArtwork.displayName = \"Ginger.Current.Artwork\";\n","import type { ReactNode } from \"react\";\nimport type { DisplayBaseProps, GingerState } from \"../../types\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\n\nexport type QueueIndexProps = DisplayBaseProps & {\n base?: 0 | 1;\n children?: (value: string, state: GingerState) => ReactNode;\n};\n\nexport function QueueIndex({ base = 0, className, style, fallback, empty, children }: QueueIndexProps) {\n const state = useGingerState();\n const len = state.tracks.length;\n if (len === 0) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n const value = String(state.currentIndex + base);\n if (children) return <span className={className} style={style}>{children(value, state)}</span>;\n return (\n <span className={className} style={style}>\n {value}\n </span>\n );\n}\n\nQueueIndex.displayName = \"Ginger.Current.QueueIndex\";\n\nexport type QueueLengthProps = DisplayBaseProps & {\n children?: (value: string, state: GingerState) => ReactNode;\n};\n\nexport function QueueLength({ className, style, fallback, empty, children }: QueueLengthProps) {\n const state = useGingerState();\n const value = String(state.tracks.length);\n if (state.tracks.length === 0) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n if (children) return <span className={className} style={style}>{children(value, state)}</span>;\n return (\n <span className={className} style={style}>\n {value}\n </span>\n );\n}\n\nQueueLength.displayName = \"Ginger.Current.QueueLength\";\n\nexport type QueuePositionProps = DisplayBaseProps & {\n base?: 0 | 1;\n separator?: string;\n children?: (value: { index: string; length: string; label: string }, state: GingerState) => ReactNode;\n};\n\nexport function QueuePosition({\n base = 0,\n separator = \" / \",\n className,\n style,\n fallback,\n empty,\n children,\n}: QueuePositionProps) {\n const state = useGingerState();\n const len = state.tracks.length;\n if (len === 0) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n const index = String(state.currentIndex + base);\n const length = String(len);\n const label = `${index}${separator}${length}`;\n if (children)\n return (\n <span className={className} style={style}>\n {children({ index, length, label }, state)}\n </span>\n );\n return (\n <span className={className} style={style}>\n {label}\n </span>\n );\n}\n\nQueuePosition.displayName = \"Ginger.Current.QueuePosition\";\n","import type { ReactElement, ReactNode } from \"react\";\nimport type { DisplayBaseProps, GingerState } from \"../../types\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\nimport { effectiveDuration, effectiveRemaining, progressFraction } from \"../../internal/selectors\";\nimport { formatMmSs } from \"../../internal/formatTime\";\n\nexport type TimeTextProps = DisplayBaseProps & {\n format?: (seconds: number) => string;\n children?: (value: string, state: GingerState) => ReactNode;\n};\n\nfunction renderTime(\n valueSeconds: number,\n state: GingerState,\n props: TimeTextProps,\n): ReactElement | null {\n const { className, style, fallback, empty, children, format = formatMmSs } = props;\n if (!(valueSeconds >= 0) || !Number.isFinite(valueSeconds)) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n const text = format(valueSeconds);\n if (children) return <span className={className} style={style}>{children(text, state)}</span>;\n return (\n <span className={className} style={style}>\n {text}\n </span>\n );\n}\n\nexport function Elapsed(props: TimeTextProps) {\n const state = useGingerState();\n return renderTime(state.currentTime, state, props);\n}\n\nElapsed.displayName = \"Ginger.Current.Elapsed\";\n\nexport function Duration(props: TimeTextProps) {\n const state = useGingerState();\n return renderTime(effectiveDuration(state), state, props);\n}\n\nDuration.displayName = \"Ginger.Current.Duration\";\n\nexport function Remaining(props: TimeTextProps) {\n const state = useGingerState();\n return renderTime(effectiveRemaining(state), state, props);\n}\n\nRemaining.displayName = \"Ginger.Current.Remaining\";\n\nexport type ProgressProps = DisplayBaseProps & {\n children?: (value: { fraction: number; currentTime: number; duration: number }, state: GingerState) => ReactNode;\n};\n\nexport function Progress({ className, style, fallback, empty, children }: ProgressProps) {\n const state = useGingerState();\n const duration = effectiveDuration(state);\n const fraction = progressFraction(state);\n if (!(duration > 0)) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n if (children)\n return (\n <span className={className} style={style}>\n {children({ fraction, currentTime: state.currentTime, duration }, state)}\n </span>\n );\n return (\n <span className={className} style={style}>\n {`${Math.round(fraction * 100)}%`}\n </span>\n );\n}\n\nProgress.displayName = \"Ginger.Current.Progress\";\n\nexport type TimeRailProps = DisplayBaseProps & {\n /** 0-1 height in px for the rail */\n height?: number;\n /** When true, shows a buffered range behind the progress fill (uses `bufferedFraction`). */\n showBuffered?: boolean;\n /** Remove default rail styles and render only inline width values. */\n unstyled?: boolean;\n};\n\nexport function TimeRail({\n className,\n style,\n height = 4,\n showBuffered = false,\n unstyled = false,\n}: TimeRailProps) {\n const state = useGingerState();\n const progressPct = `${Math.round(progressFraction(state) * 100)}%`;\n const bufPct = `${Math.round(Math.min(1, Math.max(0, state.bufferedFraction)) * 100)}%`;\n return (\n <div\n className={className}\n style={\n unstyled\n ? { ...style }\n : {\n width: \"100%\",\n height,\n background: \"var(--ginger-muted-color, #e5e7eb)\",\n borderRadius: 999,\n overflow: \"hidden\",\n position: \"relative\",\n ...style,\n }\n }\n aria-hidden\n >\n {showBuffered ? (\n <div\n style={{\n position: unstyled ? undefined : \"absolute\",\n left: unstyled ? undefined : 0,\n top: unstyled ? undefined : 0,\n height: unstyled ? undefined : \"100%\",\n width: bufPct,\n background: unstyled ? undefined : \"var(--ginger-buffer-color, rgba(107, 114, 128, 0.35))\",\n }}\n />\n ) : null}\n <div\n style={{\n position: unstyled ? undefined : \"relative\",\n width: progressPct,\n height: unstyled ? undefined : \"100%\",\n background: unstyled ? undefined : \"var(--ginger-primary-color, #111827)\",\n }}\n />\n </div>\n );\n}\n\nTimeRail.displayName = \"Ginger.Current.TimeRail\";\n\nexport type BufferRailProps = DisplayBaseProps & {\n height?: number;\n /** Remove default rail styles and render only buffered width value. */\n unstyled?: boolean;\n};\n\n/** Buffered portion of the timeline (0…`bufferedFraction`); pair with `TimeRail` or use alone. */\nexport function BufferRail({ className, style, height = 4, unstyled = false }: BufferRailProps) {\n const state = useGingerState();\n const bufPct = `${Math.round(Math.min(1, Math.max(0, state.bufferedFraction)) * 100)}%`;\n return (\n <div\n className={className}\n style={\n unstyled\n ? { ...style }\n : {\n width: \"100%\",\n height,\n background: \"var(--ginger-muted-color, #e5e7eb)\",\n borderRadius: 999,\n overflow: \"hidden\",\n ...style,\n }\n }\n aria-hidden\n >\n <div\n style={{\n width: bufPct,\n height: unstyled ? undefined : \"100%\",\n background: unstyled ? undefined : \"var(--ginger-buffer-color, rgba(107, 114, 128, 0.35))\",\n }}\n />\n </div>\n );\n}\n\nBufferRail.displayName = \"Ginger.Current.BufferRail\";\n","import type { ReactNode } from \"react\";\nimport type { DisplayBaseProps, GingerState, PlaybackUiState } from \"../../types\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\nimport { derivePlaybackUiState } from \"../../internal/selectors\";\n\nexport type PlaybackStateProps = DisplayBaseProps & {\n children?: (value: PlaybackUiState, state: GingerState) => ReactNode;\n};\n\nexport function PlaybackState({ className, style, fallback, empty, children }: PlaybackStateProps) {\n const state = useGingerState();\n const value = derivePlaybackUiState(state);\n if (children) return <span className={className} style={style}>{children(value, state)}</span>;\n return (\n <span className={className} style={style}>\n {value}\n </span>\n );\n}\n\nPlaybackState.displayName = \"Ginger.Current.PlaybackState\";\n\nexport type ErrorMessageProps = DisplayBaseProps & {\n live?: \"polite\" | \"assertive\" | \"off\";\n children?: (value: string, state: GingerState) => ReactNode;\n};\n\nexport function ErrorMessage({ className, style, fallback, empty, live = \"polite\", children }: ErrorMessageProps) {\n const state = useGingerState();\n const value = state.errorMessage ?? \"\";\n if (!value) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n if (children) {\n return (\n <span className={className} style={style} aria-live={live}>\n {children(value, state)}\n </span>\n );\n }\n return (\n <span className={className} style={style} aria-live={live}>\n {value}\n </span>\n );\n}\n\nErrorMessage.displayName = \"Ginger.Current.ErrorMessage\";\n","import { createContext, useContext, type ReactNode } from \"react\";\nimport type { GingerLocaleMessages } from \"../types\";\n\nexport const defaultGingerLocale: GingerLocaleMessages = {\n seek: \"Seek\",\n volume: \"Volume\",\n playbackSpeed: \"Playback speed\",\n nextTrack: \"Next track\",\n previousTrack: \"Previous track\",\n shuffle: \"Shuffle\",\n mute: \"Mute\",\n unmute: \"Unmute\",\n play: \"Play\",\n pause: \"Pause\",\n repeat: {\n off: \"Repeat off\",\n all: \"Repeat all\",\n one: \"Repeat one\",\n },\n playbackRateNormal: \"1× normal\",\n playbackRateTimes: (rate) => `${rate}×`,\n};\n\nfunction mergeLocale(partial?: Partial<GingerLocaleMessages>): GingerLocaleMessages {\n if (!partial) return defaultGingerLocale;\n return {\n ...defaultGingerLocale,\n ...partial,\n repeat: { ...defaultGingerLocale.repeat, ...partial.repeat },\n };\n}\n\nconst GingerLocaleContext = createContext<GingerLocaleMessages>(defaultGingerLocale);\n\nexport function GingerLocaleProvider({\n locale,\n children,\n}: {\n locale?: Partial<GingerLocaleMessages>;\n children: ReactNode;\n}) {\n const value = mergeLocale(locale);\n return <GingerLocaleContext.Provider value={value}>{children}</GingerLocaleContext.Provider>;\n}\n\nexport function useGingerLocale(): GingerLocaleMessages {\n return useContext(GingerLocaleContext);\n}\n","import { useMemo } from \"react\";\nimport type { FormEvent } from \"react\";\nimport type { GingerState } from \"../types\";\nimport { gingerStateFromContextValues, useGingerMedia, useGingerPlayback } from \"../context/GingerSplitContexts\";\nimport { effectiveDuration } from \"../internal/selectors\";\nimport { formatMmSs } from \"../internal/formatTime\";\nimport { useGingerLocale } from \"../context/GingerLocaleContext\";\n\nexport type SeekBarBinding = {\n state: GingerState;\n value: number;\n min: number;\n max: number;\n step: \"any\";\n ariaValueText: string;\n ariaLabel: string;\n onSeekInput: (e: FormEvent<HTMLInputElement>) => void;\n onSeekChange: (e: FormEvent<HTMLInputElement>) => void;\n};\n\n/** Headless seek slider: bind return value to `<input type=\"range\" />` or your own component. */\nexport function useSeekBarBinding(): SeekBarBinding {\n const pb = useGingerPlayback();\n const md = useGingerMedia();\n const locale = useGingerLocale();\n const state = useMemo(() => gingerStateFromContextValues(pb, md), [pb, md]);\n const duration = effectiveDuration(state);\n const value = duration > 0 ? state.currentTime : 0;\n const numericValue = Number.isFinite(value) ? value : 0;\n const ariaValueText =\n duration > 0\n ? `${formatMmSs(numericValue)} of ${formatMmSs(duration)}`\n : formatMmSs(numericValue);\n\n const onSeekInput = (e: FormEvent<HTMLInputElement>) => {\n md.seek(Number(e.currentTarget.value));\n };\n\n return {\n state,\n value: numericValue,\n min: 0,\n max: duration > 0 ? duration : 1,\n step: \"any\",\n ariaValueText,\n ariaLabel: locale.seek,\n onSeekInput,\n onSeekChange: onSeekInput,\n };\n}\n\nexport type VolumeBinding = {\n state: GingerState;\n value: number;\n min: number;\n max: number;\n step: \"any\";\n ariaValueText: string;\n ariaLabel: string;\n onVolumeInput: (e: FormEvent<HTMLInputElement>) => void;\n onVolumeChange: (e: FormEvent<HTMLInputElement>) => void;\n};\n\n/** Headless volume slider. */\nexport function useVolumeSlider(): VolumeBinding {\n const pb = useGingerPlayback();\n const md = useGingerMedia();\n const locale = useGingerLocale();\n const state = useMemo(() => gingerStateFromContextValues(pb, md), [pb, md]);\n\n const onVolumeInput = (e: FormEvent<HTMLInputElement>) => {\n md.setVolume(Number(e.currentTarget.value));\n };\n\n return {\n state,\n value: state.volume,\n min: 0,\n max: 1,\n step: \"any\",\n ariaValueText: `${Math.round(state.volume * 100)}%`,\n ariaLabel: locale.volume,\n onVolumeInput,\n onVolumeChange: onVolumeInput,\n };\n}\n\nexport type PlayPauseBinding = {\n isPaused: boolean;\n toggle: () => void;\n /** Resolved aria label for the button’s *next* action (play vs pause). */\n ariaLabel: string;\n};\n\n/** Headless play/pause control; use with `playAriaLabel` / `pauseAriaLabel` from locale or custom strings. */\nexport function usePlayPauseBinding(options?: {\n playAriaLabel?: string;\n pauseAriaLabel?: string;\n}): PlayPauseBinding {\n const pb = useGingerPlayback();\n const locale = useGingerLocale();\n const playL = options?.playAriaLabel ?? locale.play;\n const pauseL = options?.pauseAriaLabel ?? locale.pause;\n return {\n isPaused: pb.isPaused,\n toggle: pb.togglePlayPause,\n ariaLabel: pb.isPaused ? playL : pauseL,\n };\n}\n","import { useMemo } from \"react\";\nimport type {\n ButtonHTMLAttributes,\n CSSProperties,\n InputHTMLAttributes,\n ReactNode,\n SelectHTMLAttributes,\n} from \"react\";\nimport { useGingerLocale } from \"../../context/GingerLocaleContext\";\nimport { useGingerMedia, useGingerPlayback } from \"../../context/GingerSplitContexts\";\nimport {\n usePlayPauseBinding,\n useSeekBarBinding,\n useVolumeSlider,\n} from \"../../hooks/useControlBindings\";\n\nexport type PlayPauseProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n /** Optional labels; still headless—defaults are text for a11y */\n playLabel?: ReactNode;\n pauseLabel?: ReactNode;\n /** Screen-reader label when paused (playing would start); defaults to match `playLabel` when it is a string */\n playAriaLabel?: string;\n /** Screen-reader label when playing (action would pause); defaults to match `pauseLabel` when it is a string */\n pauseAriaLabel?: string;\n children?: ReactNode;\n};\n\nexport function PlayPause({\n playLabel = \"Play\",\n pauseLabel = \"Pause\",\n playAriaLabel,\n pauseAriaLabel,\n children,\n type = \"button\",\n onClick,\n ...rest\n}: PlayPauseProps) {\n const locale = useGingerLocale();\n const defaultPlayAria = typeof playLabel === \"string\" ? playLabel : locale.play;\n const defaultPauseAria = typeof pauseLabel === \"string\" ? pauseLabel : locale.pause;\n const b = usePlayPauseBinding({\n playAriaLabel: playAriaLabel ?? defaultPlayAria,\n pauseAriaLabel: pauseAriaLabel ?? defaultPauseAria,\n });\n return (\n <button\n {...rest}\n type={type}\n aria-label={b.ariaLabel}\n onClick={(e) => {\n b.toggle();\n onClick?.(e);\n }}\n >\n {children ?? (b.isPaused ? playLabel : pauseLabel)}\n </button>\n );\n}\n\nPlayPause.displayName = \"Ginger.Control.PlayPause\";\n\nexport type RepeatProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n ariaLabel?: string;\n};\n\nexport function Repeat({ type = \"button\", ariaLabel, onClick, ...rest }: RepeatProps) {\n const { repeatMode, cycleRepeat } = useGingerPlayback();\n const locale = useGingerLocale();\n const label = locale.repeat[repeatMode];\n return (\n <button\n {...rest}\n type={type}\n aria-label={ariaLabel ?? label}\n onClick={(e) => {\n cycleRepeat();\n onClick?.(e);\n }}\n >\n {label}\n </button>\n );\n}\n\nRepeat.displayName = \"Ginger.Control.Repeat\";\n\nexport type NextProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n ariaLabel?: string;\n};\nexport function Next({\n type = \"button\",\n children = \"Next\",\n ariaLabel,\n onClick,\n ...rest\n}: NextProps) {\n const { next } = useGingerPlayback();\n const locale = useGingerLocale();\n return (\n <button\n {...rest}\n type={type}\n aria-label={ariaLabel ?? locale.nextTrack}\n onClick={(e) => {\n next();\n onClick?.(e);\n }}\n >\n {children}\n </button>\n );\n}\nNext.displayName = \"Ginger.Control.Next\";\n\nexport type PreviousProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n ariaLabel?: string;\n};\nexport function Previous({\n type = \"button\",\n children = \"Previous\",\n ariaLabel,\n onClick,\n ...rest\n}: PreviousProps) {\n const { prev } = useGingerPlayback();\n const locale = useGingerLocale();\n return (\n <button\n {...rest}\n type={type}\n aria-label={ariaLabel ?? locale.previousTrack}\n onClick={(e) => {\n prev();\n onClick?.(e);\n }}\n >\n {children}\n </button>\n );\n}\nPrevious.displayName = \"Ginger.Control.Previous\";\n\nexport type ShuffleProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n ariaLabel?: string;\n};\nexport function Shuffle({\n type = \"button\",\n children = \"Shuffle\",\n ariaLabel,\n onClick,\n ...rest\n}: ShuffleProps) {\n const { isShuffled, toggleShuffle } = useGingerPlayback();\n const locale = useGingerLocale();\n return (\n <button\n {...rest}\n type={type}\n aria-pressed={isShuffled}\n aria-label={ariaLabel ?? locale.shuffle}\n onClick={(e) => {\n toggleShuffle();\n onClick?.(e);\n }}\n >\n {children}\n </button>\n );\n}\nShuffle.displayName = \"Ginger.Control.Shuffle\";\n\nexport type SeekBarProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"type\" | \"value\" | \"onChange\" | \"onInput\" | \"min\" | \"max\" | \"step\"\n> & {\n /** Remove default width style for fully custom styling. */\n unstyled?: boolean;\n ariaLabel?: string;\n inputStyle?: CSSProperties;\n};\n\nexport function SeekBar({ inputStyle, style, unstyled = false, ariaLabel, ...rest }: SeekBarProps) {\n const b = useSeekBarBinding();\n const mergedStyle = unstyled\n ? { ...style, ...inputStyle }\n : { width: \"100%\", ...style, ...inputStyle };\n return (\n <input\n {...rest}\n type=\"range\"\n min={b.min}\n max={b.max}\n step={b.step}\n value={b.value}\n aria-label={ariaLabel ?? b.ariaLabel}\n aria-valuetext={b.ariaValueText}\n onInput={b.onSeekInput}\n onChange={b.onSeekChange}\n style={mergedStyle}\n />\n );\n}\n\nSeekBar.displayName = \"Ginger.Control.SeekBar\";\n\nexport type VolumeProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"type\" | \"value\" | \"onChange\" | \"onInput\" | \"min\" | \"max\" | \"step\"\n> & {\n /** Remove default width style for fully custom styling. */\n unstyled?: boolean;\n ariaLabel?: string;\n inputStyle?: CSSProperties;\n};\n\nexport function Volume({ inputStyle, style, unstyled = false, ariaLabel, ...rest }: VolumeProps) {\n const b = useVolumeSlider();\n const mergedStyle = unstyled\n ? { ...style, ...inputStyle }\n : { width: \"100%\", ...style, ...inputStyle };\n return (\n <input\n {...rest}\n type=\"range\"\n min={b.min}\n max={b.max}\n step={b.step}\n value={b.value}\n aria-label={ariaLabel ?? b.ariaLabel}\n aria-valuetext={b.ariaValueText}\n onInput={b.onVolumeInput}\n onChange={b.onVolumeChange}\n style={mergedStyle}\n />\n );\n}\n\nVolume.displayName = \"Ginger.Control.Volume\";\n\nexport type MuteProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n ariaLabel?: string;\n muteLabel?: ReactNode;\n unmuteLabel?: ReactNode;\n};\n\nexport function Mute({\n ariaLabel,\n muteLabel,\n unmuteLabel,\n type = \"button\",\n onClick,\n ...rest\n}: MuteProps) {\n const { muted, toggleMute } = useGingerMedia();\n const locale = useGingerLocale();\n const m = muteLabel ?? locale.mute;\n const u = unmuteLabel ?? locale.unmute;\n return (\n <button\n {...rest}\n type={type}\n aria-pressed={muted}\n aria-label={ariaLabel ?? (muted ? locale.unmute : locale.mute)}\n onClick={(e) => {\n toggleMute();\n onClick?.(e);\n }}\n >\n {muted ? u : m}\n </button>\n );\n}\n\nMute.displayName = \"Ginger.Control.Mute\";\n\nconst defaultRates = [0.5, 0.75, 1, 1.25, 1.5, 2] as const;\n\nexport type PlaybackRateProps = Omit<\n SelectHTMLAttributes<HTMLSelectElement>,\n \"value\" | \"onChange\"\n> & {\n /** Playback speed options (default: 0.5 … 2) */\n rates?: readonly number[];\n ariaLabel?: string;\n};\n\nexport function PlaybackRate({\n rates = defaultRates,\n style,\n ariaLabel,\n ...rest\n}: PlaybackRateProps) {\n const { playbackRate, setPlaybackRate } = useGingerMedia();\n const locale = useGingerLocale();\n const options = useMemo(\n () => Array.from(new Set([...rates, playbackRate])).sort((a, b) => a - b),\n [rates, playbackRate],\n );\n return (\n <select\n {...rest}\n aria-label={ariaLabel ?? locale.playbackSpeed}\n value={String(playbackRate)}\n style={style}\n onChange={(e) => setPlaybackRate(Number(e.currentTarget.value))}\n >\n {options.map((r) => (\n <option key={r} value={String(r)}>\n {r === 1 ? locale.playbackRateNormal : locale.playbackRateTimes(r)}\n </option>\n ))}\n </select>\n );\n}\n\nPlaybackRate.displayName = \"Ginger.Control.PlaybackRate\";\n","import {\n createContext,\n useContext,\n type ButtonHTMLAttributes,\n type CSSProperties,\n type HTMLAttributes,\n type LiHTMLAttributes,\n type ReactNode,\n} from \"react\";\nimport { useGingerPlayback } from \"../../context/GingerSplitContexts\";\nimport { trackIdentity } from \"../../core/queue\";\nimport type { Track } from \"../../types\";\n\nexport type GingerPlaylistConfig = {\n playOnSelect: boolean;\n};\n\nconst GingerPlaylistConfigContext = createContext<GingerPlaylistConfig | null>(null);\n\nfunction usePlaylistConfig(): GingerPlaylistConfig {\n const ctx = useContext(GingerPlaylistConfigContext);\n if (!ctx) {\n throw new Error(\"Ginger.Playlist.Track must be used inside <Ginger.Playlist>\");\n }\n return ctx;\n}\n\nexport type GingerPlaylistProps = Omit<HTMLAttributes<HTMLUListElement>, \"children\"> & {\n children?: ReactNode;\n /** Remove default list/row styles for fully custom playlist styling. */\n unstyled?: boolean;\n rowStyle?: CSSProperties;\n /**\n * Used only in **auto** mode (no custom `children`). Ignored when you pass custom `children`\n * (manual mode); use `Ginger.Playlist.Track` for each row instead.\n */\n renderTrack?: (track: Track, index: number, isActive: boolean) => ReactNode;\n /** When true (default), clicking a row selects that index and starts playback */\n playOnSelect?: boolean;\n};\n\n/**\n * - **Auto mode** (no `children`): maps `state.tracks` to rows (optional `renderTrack`).\n * - **Manual mode** (`children` defined): renders `<ul>{children}</ul>`; map `state.tracks` yourself\n * with `Ginger.Playlist.Track` for each index.\n */\nexport function GingerPlaylist({\n children,\n unstyled = false,\n rowStyle,\n renderTrack,\n playOnSelect = true,\n style,\n ...rest\n}: GingerPlaylistProps) {\n const { tracks, currentIndex, playTrackAt, selectTrackAt } = useGingerPlayback();\n\n const listStyle: CSSProperties = unstyled\n ? { ...style }\n : {\n listStyle: \"none\",\n margin: 0,\n padding: 0,\n fontFamily: \"var(--ginger-font-family, system-ui, sans-serif)\",\n fontSize: \"var(--ginger-font-size, 14px)\",\n color: \"var(--ginger-primary-color, #111827)\",\n ...style,\n };\n\n const manual = children !== undefined;\n\n if (manual) {\n return (\n <GingerPlaylistConfigContext.Provider value={{ playOnSelect }}>\n <ul style={listStyle} {...rest}>\n {children}\n </ul>\n </GingerPlaylistConfigContext.Provider>\n );\n }\n\n return (\n <GingerPlaylistConfigContext.Provider value={{ playOnSelect }}>\n <ul style={listStyle} {...rest}>\n {tracks.map((track, index) => {\n const active = index === currentIndex;\n return (\n <li key={`${index}-${trackIdentity(track)}`}>\n <button\n type=\"button\"\n onClick={() => {\n if (playOnSelect) playTrackAt(index);\n else selectTrackAt(index);\n }}\n style={{\n width: unstyled ? undefined : \"100%\",\n textAlign: unstyled ? undefined : \"left\",\n border: unstyled ? undefined : \"none\",\n background: unstyled\n ? undefined\n : active\n ? \"var(--ginger-playlist-active-bg, rgba(17, 24, 39, 0.06))\"\n : \"transparent\",\n color: unstyled ? undefined : \"inherit\",\n font: unstyled ? undefined : \"inherit\",\n cursor: unstyled ? undefined : \"pointer\",\n padding: unstyled ? undefined : \"var(--ginger-playlist-row-padding, 6px 8px)\",\n ...rowStyle,\n }}\n >\n {renderTrack ? (\n renderTrack(track, index, active)\n ) : (\n <span>\n {track.title}\n {track.artist ? ` — ${track.artist}` : \"\"}\n </span>\n )}\n </button>\n </li>\n );\n })}\n </ul>\n </GingerPlaylistConfigContext.Provider>\n );\n}\n\nGingerPlaylist.displayName = \"Ginger.Playlist\";\n\nexport type GingerPlaylistTrackProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"type\"> & {\n index: number;\n /** Remove default row button styles for fully custom styling. */\n unstyled?: boolean;\n /** Optional wrapper for the row; defaults to a plain `<li>` */\n liProps?: LiHTMLAttributes<HTMLLIElement>;\n};\n\nexport function GingerPlaylistTrack({\n index,\n unstyled = false,\n className,\n style,\n children,\n liProps,\n onClick,\n ...buttonRest\n}: GingerPlaylistTrackProps) {\n const { playOnSelect } = usePlaylistConfig();\n const { tracks, currentIndex, playTrackAt, selectTrackAt } = useGingerPlayback();\n const active = index === currentIndex;\n const track = tracks[index];\n const defaultLabel =\n track != null ? (\n <span>\n {track.title}\n {track.artist ? ` — ${track.artist}` : \"\"}\n </span>\n ) : null;\n\n return (\n <li {...liProps}>\n <button\n type=\"button\"\n aria-current={active ? \"true\" : undefined}\n data-ginger-active={active || undefined}\n className={className}\n style={{\n width: unstyled ? undefined : \"100%\",\n textAlign: unstyled ? undefined : \"left\",\n border: unstyled ? undefined : \"none\",\n background: unstyled\n ? undefined\n : active\n ? \"var(--ginger-playlist-active-bg, rgba(17, 24, 39, 0.06))\"\n : \"transparent\",\n color: unstyled ? undefined : \"inherit\",\n font: unstyled ? undefined : \"inherit\",\n cursor: unstyled ? undefined : \"pointer\",\n padding: unstyled ? undefined : \"var(--ginger-playlist-row-padding, 6px 8px)\",\n ...style,\n }}\n {...buttonRest}\n onClick={(e) => {\n onClick?.(e);\n if (e.defaultPrevented) return;\n if (playOnSelect) playTrackAt(index);\n else selectTrackAt(index);\n }}\n >\n {children ?? defaultLabel}\n </button>\n </li>\n );\n}\n\nGingerPlaylistTrack.displayName = \"Ginger.Playlist.Track\";\n\nexport const GingerPlaylistCompound = Object.assign(GingerPlaylist, {\n Track: GingerPlaylistTrack,\n});\n","import type { CSSProperties } from \"react\";\nimport type { DisplayBaseProps } from \"../../types\";\nimport { createTextDisplay } from \"../current/createTextDisplay\";\nimport { useGingerState } from \"../../context/GingerSplitContexts\";\n\nexport const Title = createTextDisplay(\"Ginger.Queue.Title\", (s) => s.playlistMeta?.title);\nexport const Subtitle = createTextDisplay(\"Ginger.Queue.Subtitle\", (s) => s.playlistMeta?.subtitle);\nexport const Description = createTextDisplay(\"Ginger.Queue.Description\", (s) => s.playlistMeta?.description);\nexport const Copyright = createTextDisplay(\"Ginger.Queue.Copyright\", (s) => s.playlistMeta?.copyright);\n\nexport type QueueArtworkProps = DisplayBaseProps & {\n /** Remove default wrapper/image styles for fully custom layout. */\n unstyled?: boolean;\n imgStyle?: CSSProperties;\n};\n\nexport function Artwork({ className, style, fallback, empty, unstyled = false, imgStyle }: QueueArtworkProps) {\n const state = useGingerState();\n const src = state.playlistMeta?.artworkUrl;\n if (!src) {\n const node = empty ?? fallback ?? null;\n return node ? <span className={className} style={style}>{node}</span> : null;\n }\n const alt = state.playlistMeta?.title ?? \"Playlist artwork\";\n return (\n <span\n className={className}\n style={\n unstyled\n ? { ...style }\n : {\n display: \"inline-block\",\n background: \"var(--ginger-artwork-bg, #f3f4f6)\",\n borderRadius: \"var(--ginger-artwork-radius, 6px)\",\n overflow: \"hidden\",\n ...style,\n }\n }\n >\n <img\n src={src}\n alt={alt}\n style={{\n display: unstyled ? undefined : \"block\",\n width: unstyled ? undefined : \"100%\",\n height: unstyled ? undefined : \"100%\",\n objectFit: unstyled ? undefined : \"cover\",\n ...imgStyle,\n }}\n />\n </span>\n );\n}\n\nArtwork.displayName = \"Ginger.Queue.Artwork\";\n","import type { GingerAction, GingerState, RepeatMode, Track } from \"../types\";\nimport {\n addNextTrack,\n clampIndex,\n findIndexByTrackIdentity,\n insertTrackAt,\n moveTrack,\n removeTrackAt,\n shuffleWithAnchor,\n} from \"./queue\";\nimport { computeNextIndex, computePrevIndex, cycleRepeatMode } from \"./transitions\";\n\nexport function clampVolume(v: number): number {\n if (!Number.isFinite(v)) return 1;\n return Math.min(1, Math.max(0, v));\n}\n\nexport function clampPlaybackRate(r: number): number {\n if (!Number.isFinite(r)) return 1;\n return Math.min(4, Math.max(0.25, r));\n}\n\n/** Reset when the active track / position changes; keeps volume / mute / speed */\nconst resetTimingOnly = {\n currentTime: 0,\n duration: 0,\n bufferedFraction: 0,\n isBuffering: false,\n errorMessage: null as string | null,\n};\n\nconst defaultMedia = {\n ...resetTimingOnly,\n volume: 1,\n muted: false,\n playbackRate: 1,\n};\n\nexport function createInitialState(params: {\n tracks: Track[];\n currentIndex?: number;\n playlistMeta?: GingerState[\"playlistMeta\"];\n isPaused?: boolean;\n isShuffled?: boolean;\n repeatMode?: RepeatMode;\n playbackMode?: GingerState[\"playbackMode\"];\n volume?: number;\n muted?: boolean;\n playbackRate?: number;\n}): GingerState {\n const tracks = [...params.tracks];\n let currentIndex = clampIndex(params.currentIndex ?? 0, tracks.length);\n let originalTracks: Track[] | null = null;\n let ordered = tracks;\n\n if (params.isShuffled && tracks.length > 1) {\n originalTracks = [...tracks];\n ordered = shuffleWithAnchor(tracks, currentIndex);\n currentIndex = 0;\n }\n\n return {\n tracks: ordered,\n currentIndex,\n playbackMode: params.playbackMode ?? \"playlist\",\n isPaused: params.isPaused ?? true,\n isShuffled: Boolean(params.isShuffled && ordered.length > 1),\n repeatMode: params.repeatMode ?? \"off\",\n originalTracks,\n playlistMeta: params.playlistMeta ?? null,\n ...defaultMedia,\n volume: clampVolume(params.volume ?? 1),\n muted: params.muted ?? false,\n playbackRate: clampPlaybackRate(params.playbackRate ?? 1),\n };\n}\n\nexport function gingerReducer(state: GingerState, action: GingerAction): GingerState {\n switch (action.type) {\n case \"INIT\": {\n const {\n tracks,\n currentIndex,\n playlistMeta,\n isPaused,\n isShuffled,\n repeatMode,\n playbackMode,\n volume,\n muted,\n playbackRate,\n } = action.payload;\n return createInitialState({\n tracks,\n currentIndex,\n playlistMeta: playlistMeta ?? null,\n isPaused: isPaused ?? true,\n isShuffled: isShuffled ?? false,\n repeatMode: repeatMode ?? \"off\",\n playbackMode: playbackMode ?? \"playlist\",\n volume,\n muted,\n playbackRate,\n });\n }\n case \"SET_QUEUE\": {\n const { tracks, currentIndex } = action.payload;\n const next = [...tracks];\n const idx = clampIndex(currentIndex ?? state.currentIndex, next.length);\n return {\n ...state,\n tracks: next,\n currentIndex: idx,\n isShuffled: false,\n originalTracks: null,\n ...resetTimingOnly,\n };\n }\n case \"INSERT_TRACK\": {\n const insertIndex = action.payload.index ?? state.tracks.length;\n const tracks = insertTrackAt(state.tracks, action.payload.track, insertIndex);\n if (action.payload.autoPlay) {\n const idx = clampIndex(insertIndex, tracks.length);\n return {\n ...state,\n tracks,\n currentIndex: idx,\n isShuffled: false,\n originalTracks: null,\n isPaused: false,\n ...resetTimingOnly,\n };\n }\n const currentIndex =\n insertIndex <= state.currentIndex ? state.currentIndex + 1 : state.currentIndex;\n return {\n ...state,\n tracks,\n isShuffled: false,\n originalTracks: null,\n currentIndex: clampIndex(currentIndex, tracks.length),\n };\n }\n case \"REMOVE_TRACK\": {\n const index = action.payload.index;\n const tracks = removeTrackAt(state.tracks, index);\n const currentIndex =\n index < state.currentIndex\n ? state.currentIndex - 1\n : index === state.currentIndex\n ? Math.min(state.currentIndex, Math.max(0, tracks.length - 1))\n : state.currentIndex;\n return {\n ...state,\n tracks,\n isShuffled: false,\n originalTracks: null,\n currentIndex: clampIndex(currentIndex, tracks.length),\n ...(index === state.currentIndex ? resetTimingOnly : {}),\n };\n }\n case \"MOVE_TRACK\": {\n const { fromIndex, toIndex } = action.payload;\n const tracks = moveTrack(state.tracks, fromIndex, toIndex);\n let currentIndex = state.currentIndex;\n if (state.currentIndex === fromIndex) currentIndex = toIndex;\n else if (fromIndex < state.currentIndex && toIndex >= state.currentIndex) currentIndex -= 1;\n else if (fromIndex > state.currentIndex && toIndex <= state.currentIndex) currentIndex += 1;\n return {\n ...state,\n tracks,\n isShuffled: false,\n originalTracks: null,\n currentIndex: clampIndex(currentIndex, tracks.length),\n };\n }\n case \"ADD_NEXT\": {\n const tracks = addNextTrack(state.tracks, state.currentIndex, action.payload.track);\n return {\n ...state,\n tracks,\n isShuffled: false,\n originalTracks: null,\n };\n }\n case \"SET_INDEX\": {\n const idx = clampIndex(action.payload.index, state.tracks.length);\n const ap = action.payload.autoPlay;\n const isPaused =\n ap === true ? false : ap === false ? true : state.isPaused;\n return {\n ...state,\n currentIndex: idx,\n ...resetTimingOnly,\n isPaused,\n };\n }\n case \"PLAY\":\n return { ...state, isPaused: false };\n case \"PAUSE\":\n return { ...state, isPaused: true };\n case \"TOGGLE_PAUSE\":\n return { ...state, isPaused: !state.isPaused };\n case \"SET_REPEAT\":\n return { ...state, repeatMode: action.payload };\n case \"CYCLE_REPEAT\":\n return { ...state, repeatMode: cycleRepeatMode(state.repeatMode) };\n case \"TOGGLE_SHUFFLE\": {\n if (state.tracks.length <= 1) return { ...state, isShuffled: false, originalTracks: null };\n if (!state.isShuffled) {\n const snapshot = [...state.tracks];\n const shuffled = shuffleWithAnchor(snapshot, state.currentIndex);\n return {\n ...state,\n isShuffled: true,\n originalTracks: snapshot,\n tracks: shuffled,\n currentIndex: 0,\n };\n }\n const restored = state.originalTracks ? [...state.originalTracks] : [...state.tracks];\n const current = state.tracks[state.currentIndex];\n const newIndex = findIndexByTrackIdentity(restored, current);\n return {\n ...state,\n isShuffled: false,\n originalTracks: null,\n tracks: restored,\n currentIndex: clampIndex(newIndex, restored.length),\n };\n }\n case \"NEXT\": {\n const nextIndex = computeNextIndex(state);\n const same = nextIndex === state.currentIndex;\n return {\n ...state,\n currentIndex: nextIndex,\n ...(same ? {} : resetTimingOnly),\n isPaused: same ? state.isPaused : false,\n };\n }\n case \"PREV\": {\n const prevIndex = computePrevIndex(state);\n const same = prevIndex === state.currentIndex;\n return {\n ...state,\n currentIndex: prevIndex,\n ...(same ? {} : resetTimingOnly),\n isPaused: same ? state.isPaused : false,\n };\n }\n case \"MEDIA_TIME_UPDATE\":\n return {\n ...state,\n currentTime: action.payload.currentTime,\n duration: Number.isFinite(action.payload.duration) ? action.payload.duration : state.duration,\n bufferedFraction: action.payload.bufferedFraction,\n isBuffering: false,\n };\n case \"MEDIA_LOADED_METADATA\":\n return {\n ...state,\n duration: Number.isFinite(action.payload.duration) ? action.payload.duration : state.duration,\n bufferedFraction: action.payload.bufferedFraction,\n errorMessage: null,\n };\n case \"SET_PLAYLIST_META\":\n return { ...state, playlistMeta: action.payload };\n case \"SET_PLAYBACK_MODE\":\n return { ...state, playbackMode: action.payload };\n case \"MEDIA_ERROR\":\n return {\n ...state,\n errorMessage: action.payload.message,\n isPaused: true,\n isBuffering: false,\n };\n case \"MEDIA_WAITING\":\n return { ...state, isBuffering: true };\n case \"MEDIA_CANPLAY\":\n return { ...state, isBuffering: false, errorMessage: null };\n case \"MEDIA_PLAY\":\n return { ...state, isPaused: false, isBuffering: false };\n case \"MEDIA_PAUSE\":\n return { ...state, isPaused: true };\n case \"RESET_MEDIA_TIMES\":\n return { ...state, currentTime: 0, duration: 0, bufferedFraction: 0 };\n case \"MEDIA_SOURCE_CLEARED\":\n return { ...state, ...resetTimingOnly };\n case \"SET_VOLUME\":\n return { ...state, volume: clampVolume(action.payload) };\n case \"SET_MUTED\":\n return { ...state, muted: action.payload };\n case \"TOGGLE_MUTE\":\n return { ...state, muted: !state.muted };\n case \"SET_PLAYBACK_RATE\":\n return { ...state, playbackRate: clampPlaybackRate(action.payload) };\n case \"MEDIA_VOLUME_SYNC\": {\n const { volume, muted } = action.payload;\n const v = clampVolume(volume);\n if (v === state.volume && muted === state.muted) return state;\n return { ...state, volume: v, muted };\n }\n default: {\n const _exhaustive: never = action;\n void _exhaustive;\n return state;\n }\n }\n}\n","import { useEffect } from \"react\";\nimport { resolveArtworkUrl } from \"../core/transitions\";\nimport type { GingerState } from \"../types\";\n\nexport type MediaSessionBridgeActions = {\n play: () => void;\n pause: () => void;\n next: () => void;\n prev: () => void;\n seek: (timeSeconds: number) => void;\n};\n\nfunction getMediaSession(): MediaSession | null {\n if (typeof navigator === \"undefined\" || !(\"mediaSession\" in navigator)) return null;\n return navigator.mediaSession;\n}\n\nexport function useMediaSessionBridge(\n enabled: boolean,\n state: GingerState,\n actions: MediaSessionBridgeActions,\n): void {\n const track = state.tracks[state.currentIndex];\n const title = track?.title;\n const artist = track?.artist;\n const album = track?.album;\n const artworkUrl = resolveArtworkUrl(track, state.playlistMeta?.artworkUrl);\n\n useEffect(() => {\n const ms = getMediaSession();\n if (!enabled || !ms) return;\n ms.metadata = new MediaMetadata({\n title: title ?? \"Unknown track\",\n artist,\n album,\n artwork: artworkUrl ? [{ src: artworkUrl }] : undefined,\n });\n }, [enabled, title, artist, album, artworkUrl]);\n\n useEffect(() => {\n const ms = getMediaSession();\n if (!enabled || !ms) return;\n ms.playbackState = state.isPaused ? \"paused\" : \"playing\";\n }, [enabled, state.isPaused]);\n\n useEffect(() => {\n const ms = getMediaSession();\n if (!enabled || !ms) return;\n try {\n ms.setActionHandler(\"play\", actions.play);\n ms.setActionHandler(\"pause\", actions.pause);\n ms.setActionHandler(\"nexttrack\", actions.next);\n ms.setActionHandler(\"previoustrack\", actions.prev);\n ms.setActionHandler(\"seekto\", (details) => {\n if (typeof details.seekTime === \"number\" && Number.isFinite(details.seekTime)) {\n actions.seek(details.seekTime);\n }\n });\n } catch {\n // Best-effort API support differs across browsers.\n }\n return () => {\n try {\n ms.setActionHandler(\"play\", null);\n ms.setActionHandler(\"pause\", null);\n ms.setActionHandler(\"nexttrack\", null);\n ms.setActionHandler(\"previoustrack\", null);\n ms.setActionHandler(\"seekto\", null);\n } catch {\n // Ignore platforms that do not support clearing handlers.\n }\n };\n }, [enabled, actions]);\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n type CSSProperties,\n} from \"react\";\nimport { computeEndedTransition } from \"../core/transitions\";\nimport { clampPlaybackRate, clampVolume, gingerReducer, createInitialState } from \"../core/playbackReducer\";\nimport { trackIdentity } from \"../core/queue\";\nimport { derivePlaybackUiState } from \"../internal/selectors\";\nimport type {\n GingerInitPayload,\n GingerProviderProps,\n PlaybackMode,\n PlaylistMeta,\n RepeatMode,\n Track,\n} from \"../types\";\nimport { useMediaSessionBridge } from \"../media/useMediaSession\";\nimport { GingerContext, type GingerContextValue } from \"./GingerContext\";\nimport { GingerLocaleProvider } from \"./GingerLocaleContext\";\nimport { GingerMediaContext, GingerPlaybackContext, type GingerMediaContextValue, type GingerPlaybackContextValue } from \"./GingerSplitContexts\";\n\nconst defaultProviderStyle: CSSProperties = {\n [\"--ginger-primary-color\" as string]: \"#111827\",\n [\"--ginger-muted-color\" as string]: \"#6b7280\",\n [\"--ginger-font-size\" as string]: \"14px\",\n [\"--ginger-font-family\" as string]: \"system-ui, sans-serif\",\n [\"--ginger-playlist-row-padding\" as string]: \"6px 8px\",\n [\"--ginger-artwork-radius\" as string]: \"6px\",\n [\"--ginger-artwork-bg\" as string]: \"#f3f4f6\",\n [\"--ginger-playlist-active-bg\" as string]: \"rgba(17, 24, 39, 0.06)\",\n [\"--ginger-buffer-color\" as string]: \"rgba(107, 114, 128, 0.35)\",\n [\"--ginger-focus-ring\" as string]: \"0 0 0 2px rgba(59, 130, 246, 0.45)\",\n};\n\nexport function GingerProvider({\n children,\n initialTracks = [],\n initialIndex = 0,\n initialPlaylistMeta = null,\n initialShuffle = false,\n initialRepeatMode = \"off\",\n initialPlaybackMode = \"playlist\",\n initialPaused = true,\n initialVolume = 1,\n initialMuted = false,\n initialPlaybackRate = 1,\n initialStateKey,\n locale,\n mediaSession = false,\n beforePlay,\n onPlayBlocked,\n persistence,\n hydrateOnMount = false,\n resumeOnTrackChange = false,\n unstyled = false,\n className,\n style,\n onTrackChange,\n onPlay,\n onPause,\n onQueueEnd,\n onError,\n}: GingerProviderProps) {\n const audioRef = useRef<HTMLAudioElement | null>(null);\n const [state, dispatch] = useReducer(\n gingerReducer,\n undefined,\n () =>\n createInitialState({\n tracks: initialTracks,\n currentIndex: initialIndex,\n playlistMeta: initialPlaylistMeta,\n isPaused: initialPaused,\n isShuffled: initialShuffle,\n repeatMode: initialRepeatMode,\n playbackMode: initialPlaybackMode,\n volume: initialVolume,\n muted: initialMuted,\n playbackRate: initialPlaybackRate,\n }),\n );\n const stateRef = useRef(state);\n\n const latestInitRef = useRef({\n tracks: initialTracks,\n currentIndex: initialIndex,\n playlistMeta: initialPlaylistMeta,\n isPaused: initialPaused,\n isShuffled: initialShuffle,\n repeatMode: initialRepeatMode,\n playbackMode: initialPlaybackMode,\n volume: initialVolume,\n muted: initialMuted,\n playbackRate: initialPlaybackRate,\n });\n latestInitRef.current = {\n tracks: initialTracks,\n currentIndex: initialIndex,\n playlistMeta: initialPlaylistMeta,\n isPaused: initialPaused,\n isShuffled: initialShuffle,\n repeatMode: initialRepeatMode,\n playbackMode: initialPlaybackMode,\n volume: initialVolume,\n muted: initialMuted,\n playbackRate: initialPlaybackRate,\n };\n\n const prevInitialStateKeyRef = useRef<typeof initialStateKey>(undefined);\n\n useEffect(() => {\n if (initialStateKey === undefined) {\n prevInitialStateKeyRef.current = undefined;\n return;\n }\n if (prevInitialStateKeyRef.current === undefined) {\n prevInitialStateKeyRef.current = initialStateKey;\n return;\n }\n if (prevInitialStateKeyRef.current === initialStateKey) return;\n prevInitialStateKeyRef.current = initialStateKey;\n const p = latestInitRef.current;\n dispatch({\n type: \"INIT\",\n payload: {\n tracks: p.tracks,\n currentIndex: p.currentIndex,\n playlistMeta: p.playlistMeta,\n isPaused: p.isPaused,\n isShuffled: p.isShuffled,\n repeatMode: p.repeatMode,\n playbackMode: p.playbackMode,\n volume: p.volume,\n muted: p.muted,\n playbackRate: p.playbackRate,\n },\n });\n }, [initialStateKey, dispatch]);\n\n useEffect(() => {\n stateRef.current = state;\n }, [state]);\n\n const currentTrack = state.tracks[state.currentIndex] ?? null;\n\n useEffect(() => {\n onTrackChange?.(currentTrack, state.currentIndex);\n }, [currentTrack, state.currentIndex, onTrackChange]);\n\n useEffect(() => {\n if (state.errorMessage) onError?.(state.errorMessage);\n }, [state.errorMessage, onError]);\n\n const prevPausedRef = useRef<boolean | undefined>(undefined);\n useEffect(() => {\n if (prevPausedRef.current === undefined) {\n prevPausedRef.current = state.isPaused;\n return;\n }\n if (prevPausedRef.current !== state.isPaused) {\n if (state.isPaused) onPause?.();\n else onPlay?.();\n }\n prevPausedRef.current = state.isPaused;\n }, [state.isPaused, onPause, onPlay]);\n\n const play = useCallback(() => {\n dispatch({ type: \"PLAY\" });\n }, []);\n\n const pause = useCallback(() => {\n dispatch({ type: \"PAUSE\" });\n audioRef.current?.pause();\n }, []);\n\n const togglePlayPause = useCallback(() => {\n if (state.isPaused) play();\n else pause();\n }, [pause, play, state.isPaused]);\n\n const seek = useCallback((timeSeconds: number) => {\n const el = audioRef.current;\n if (!el) return;\n if (!Number.isFinite(timeSeconds)) return;\n el.currentTime = Math.max(0, timeSeconds);\n }, []);\n\n const setVolume = useCallback((volume: number) => {\n dispatch({ type: \"SET_VOLUME\", payload: clampVolume(volume) });\n }, []);\n\n const setMuted = useCallback((muted: boolean) => {\n dispatch({ type: \"SET_MUTED\", payload: muted });\n }, []);\n\n const toggleMute = useCallback(() => {\n dispatch({ type: \"TOGGLE_MUTE\" });\n }, []);\n\n const setPlaybackRate = useCallback((rate: number) => {\n dispatch({ type: \"SET_PLAYBACK_RATE\", payload: clampPlaybackRate(rate) });\n }, []);\n\n const next = useCallback(() => {\n dispatch({ type: \"NEXT\" });\n }, []);\n\n const prev = useCallback(() => {\n dispatch({ type: \"PREV\" });\n }, []);\n\n const setRepeatMode = useCallback((mode: RepeatMode) => {\n dispatch({ type: \"SET_REPEAT\", payload: mode });\n }, []);\n\n const cycleRepeat = useCallback(() => {\n dispatch({ type: \"CYCLE_REPEAT\" });\n }, []);\n\n const toggleShuffle = useCallback(() => {\n dispatch({ type: \"TOGGLE_SHUFFLE\" });\n }, []);\n\n const setQueue = useCallback((tracks: Track[], currentIndex?: number) => {\n dispatch({ type: \"SET_QUEUE\", payload: { tracks, currentIndex } });\n }, []);\n\n const insertTrackAt = useCallback((track: Track, index?: number, autoPlay?: boolean) => {\n dispatch({ type: \"INSERT_TRACK\", payload: { track, index, autoPlay } });\n }, []);\n\n const removeTrackAt = useCallback((index: number) => {\n dispatch({ type: \"REMOVE_TRACK\", payload: { index } });\n }, []);\n\n const moveTrack = useCallback((fromIndex: number, toIndex: number) => {\n dispatch({ type: \"MOVE_TRACK\", payload: { fromIndex, toIndex } });\n }, []);\n\n const enqueueNext = useCallback((track: Track) => {\n dispatch({ type: \"ADD_NEXT\", payload: { track } });\n }, []);\n\n const playTrackAt = useCallback((index: number) => {\n dispatch({ type: \"SET_INDEX\", payload: { index, autoPlay: true } });\n }, []);\n\n const selectTrackAt = useCallback((index: number) => {\n dispatch({ type: \"SET_INDEX\", payload: { index, autoPlay: false } });\n }, []);\n\n const setPlaylistMeta = useCallback((meta: PlaylistMeta | null) => {\n dispatch({ type: \"SET_PLAYLIST_META\", payload: meta });\n }, []);\n\n const setPlaybackMode = useCallback((mode: PlaybackMode) => {\n dispatch({ type: \"SET_PLAYBACK_MODE\", payload: mode });\n }, []);\n\n const init = useCallback((payload: GingerInitPayload) => {\n dispatch({ type: \"INIT\", payload });\n }, []);\n\n useEffect(() => {\n if (!persistence || !hydrateOnMount) return;\n const volume = persistence.get(\"ginger:volume\");\n const muted = persistence.get(\"ginger:muted\");\n const playbackRate = persistence.get(\"ginger:playbackRate\");\n const repeatMode = persistence.get(\"ginger:repeatMode\");\n const currentIndex = persistence.get(\"ginger:currentIndex\");\n const p = latestInitRef.current;\n dispatch({\n type: \"INIT\",\n payload: {\n tracks: p.tracks,\n playlistMeta: p.playlistMeta,\n isPaused: p.isPaused,\n isShuffled: p.isShuffled,\n playbackMode: p.playbackMode,\n currentIndex: typeof currentIndex === \"number\" ? currentIndex : p.currentIndex,\n repeatMode: repeatMode === \"off\" || repeatMode === \"all\" || repeatMode === \"one\" ? repeatMode : p.repeatMode,\n volume: typeof volume === \"number\" ? volume : p.volume,\n muted: typeof muted === \"boolean\" ? muted : p.muted,\n playbackRate: typeof playbackRate === \"number\" ? playbackRate : p.playbackRate,\n },\n });\n }, [hydrateOnMount, persistence]);\n\n useEffect(() => {\n if (!persistence) return;\n persistence.set(\"ginger:volume\", state.volume);\n persistence.set(\"ginger:muted\", state.muted);\n persistence.set(\"ginger:playbackRate\", state.playbackRate);\n persistence.set(\"ginger:repeatMode\", state.repeatMode);\n persistence.set(\"ginger:currentIndex\", state.currentIndex);\n }, [persistence, state.volume, state.muted, state.playbackRate, state.repeatMode, state.currentIndex]);\n\n useEffect(() => {\n if (!persistence || !resumeOnTrackChange) return;\n const track = state.tracks[state.currentIndex];\n if (!track) return;\n const key = `ginger:resume:${trackIdentity(track)}`;\n const saved = persistence.get(key);\n if (typeof saved === \"number\" && Number.isFinite(saved)) {\n seek(saved);\n }\n }, [persistence, resumeOnTrackChange, state.currentIndex, state.tracks, seek]);\n\n useEffect(() => {\n if (!persistence || !resumeOnTrackChange) return;\n const track = state.tracks[state.currentIndex];\n if (!track || !(state.currentTime >= 0)) return;\n const key = `ginger:resume:${trackIdentity(track)}`;\n const id = setTimeout(() => persistence.set(key, state.currentTime), 250);\n return () => clearTimeout(id);\n }, [persistence, resumeOnTrackChange, state.currentIndex, state.tracks, state.currentTime]);\n\n const currentUrl = state.tracks[state.currentIndex]?.fileUrl;\n\n useEffect(() => {\n const el = audioRef.current;\n if (!el) return;\n if (state.isPaused) {\n el.pause();\n return;\n }\n let cancelled = false;\n void (async () => {\n if (beforePlay) {\n let allowed = false;\n try {\n allowed = await beforePlay();\n } catch (error) {\n const message = error instanceof Error ? error.message : \"beforePlay rejected\";\n dispatch({ type: \"MEDIA_ERROR\", payload: { message } });\n return;\n }\n if (!allowed) {\n if (!cancelled) {\n dispatch({ type: \"PAUSE\" });\n onPlayBlocked?.();\n }\n return;\n }\n }\n if (cancelled) return;\n void el.play().catch((e: unknown) => {\n const msg =\n e instanceof Error\n ? e.message\n : typeof e === \"string\"\n ? e\n : \"Playback failed (e.g. autoplay blocked or unavailable source)\";\n dispatch({ type: \"MEDIA_ERROR\", payload: { message: msg } });\n });\n })();\n return () => {\n cancelled = true;\n };\n }, [beforePlay, currentUrl, onPlayBlocked, state.isPaused]);\n\n const notifyEnded = useCallback(() => {\n const transition = computeEndedTransition(stateRef.current);\n if (transition.kind === \"replay_same\") {\n const el = audioRef.current;\n if (el) {\n el.currentTime = 0;\n }\n dispatch({ type: \"PLAY\" });\n return;\n }\n if (transition.kind === \"stop\") {\n dispatch({ type: \"PAUSE\" });\n onQueueEnd?.();\n return;\n }\n const nextIndex = transition.nextIndex;\n dispatch({ type: \"SET_INDEX\", payload: { index: nextIndex, autoPlay: true } });\n }, [onQueueEnd]);\n\n const mediaSessionActions = useMemo(\n () => ({ play, pause, next, prev, seek }),\n [play, pause, next, prev, seek],\n );\n useMediaSessionBridge(Boolean(mediaSession), state, mediaSessionActions);\n\n const providerDir = locale?.seek && /[\\u0590-\\u08FF]/.test(locale.seek) ? \"rtl\" : \"ltr\";\n\n const value = useMemo<GingerContextValue>(\n () => ({\n state,\n dispatch,\n audioRef,\n notifyEnded,\n init,\n play,\n pause,\n togglePlayPause,\n seek,\n setVolume,\n setMuted,\n toggleMute,\n setPlaybackRate,\n next,\n prev,\n setRepeatMode,\n cycleRepeat,\n toggleShuffle,\n setQueue,\n insertTrackAt,\n removeTrackAt,\n moveTrack,\n enqueueNext,\n playTrackAt,\n selectTrackAt,\n setPlaylistMeta,\n setPlaybackMode,\n }),\n [\n cycleRepeat,\n dispatch,\n init,\n next,\n notifyEnded,\n pause,\n play,\n playTrackAt,\n insertTrackAt,\n removeTrackAt,\n moveTrack,\n enqueueNext,\n selectTrackAt,\n prev,\n seek,\n setMuted,\n setPlaybackRate,\n setQueue,\n setRepeatMode,\n setPlaylistMeta,\n setPlaybackMode,\n setVolume,\n state,\n toggleMute,\n togglePlayPause,\n toggleShuffle,\n ],\n );\n\n const playbackValue = useMemo<GingerPlaybackContextValue>(\n () => ({\n tracks: state.tracks,\n currentIndex: state.currentIndex,\n isPaused: state.isPaused,\n isShuffled: state.isShuffled,\n repeatMode: state.repeatMode,\n originalTracks: state.originalTracks,\n playlistMeta: state.playlistMeta,\n init,\n play,\n pause,\n togglePlayPause,\n next,\n prev,\n setRepeatMode,\n cycleRepeat,\n toggleShuffle,\n playbackMode: state.playbackMode,\n setQueue,\n insertTrackAt,\n removeTrackAt,\n moveTrack,\n enqueueNext,\n playTrackAt,\n selectTrackAt,\n setPlaylistMeta,\n setPlaybackMode,\n dispatch,\n }),\n [\n state.tracks,\n state.currentIndex,\n state.isPaused,\n state.isShuffled,\n state.repeatMode,\n state.playbackMode,\n state.originalTracks,\n state.playlistMeta,\n init,\n play,\n pause,\n togglePlayPause,\n next,\n prev,\n setRepeatMode,\n cycleRepeat,\n toggleShuffle,\n setQueue,\n insertTrackAt,\n removeTrackAt,\n moveTrack,\n enqueueNext,\n playTrackAt,\n selectTrackAt,\n setPlaylistMeta,\n setPlaybackMode,\n dispatch,\n ],\n );\n\n const mediaValue = useMemo<GingerMediaContextValue>(\n () => ({\n currentTime: state.currentTime,\n duration: state.duration,\n bufferedFraction: state.bufferedFraction,\n isBuffering: state.isBuffering,\n errorMessage: state.errorMessage,\n volume: state.volume,\n muted: state.muted,\n playbackRate: state.playbackRate,\n seek,\n setVolume,\n setMuted,\n toggleMute,\n setPlaybackRate,\n audioRef,\n notifyEnded,\n dispatch,\n }),\n [\n state.currentTime,\n state.duration,\n state.bufferedFraction,\n state.isBuffering,\n state.errorMessage,\n state.volume,\n state.muted,\n state.playbackRate,\n seek,\n setVolume,\n setMuted,\n toggleMute,\n setPlaybackRate,\n audioRef,\n notifyEnded,\n dispatch,\n ],\n );\n\n const playbackUi = derivePlaybackUiState(state);\n\n const mergedStyle = useMemo(\n () => (unstyled ? style : { ...defaultProviderStyle, ...style }),\n [style, unstyled],\n );\n\n return (\n <GingerLocaleProvider locale={locale}>\n <GingerPlaybackContext.Provider value={playbackValue}>\n <GingerMediaContext.Provider value={mediaValue}>\n <GingerContext.Provider value={value}>\n <div\n className={className}\n style={mergedStyle}\n data-ginger-playback={playbackUi}\n dir={providerDir}\n >\n {children}\n </div>\n </GingerContext.Provider>\n </GingerMediaContext.Provider>\n </GingerPlaybackContext.Provider>\n </GingerLocaleProvider>\n );\n}\n","import { GingerPlayer } from \"./audio/GingerPlayer\";\nimport * as Current from \"./components/current\";\nimport * as Control from \"./components/controls/Controls\";\nimport { GingerPlaylistCompound } from \"./components/playlist/GingerPlaylist\";\nimport * as Queue from \"./components/queue/QueueDisplay\";\nimport { GingerProvider } from \"./context/GingerProvider\";\n\nexport const Ginger = {\n Provider: GingerProvider,\n Player: GingerPlayer,\n Current: {\n Title: Current.Title,\n Artist: Current.Artist,\n Album: Current.Album,\n Description: Current.Description,\n Copyright: Current.Copyright,\n Genre: Current.Genre,\n Label: Current.Label,\n Isrc: Current.Isrc,\n TrackNumber: Current.TrackNumber,\n Year: Current.Year,\n Lyrics: Current.Lyrics,\n LyricsSynced: Current.LyricsSynced,\n Chapters: Current.Chapters,\n FileUrl: Current.FileUrl,\n Artwork: Current.Artwork,\n QueueIndex: Current.QueueIndex,\n QueueLength: Current.QueueLength,\n QueuePosition: Current.QueuePosition,\n Elapsed: Current.Elapsed,\n Duration: Current.Duration,\n Remaining: Current.Remaining,\n Progress: Current.Progress,\n TimeRail: Current.TimeRail,\n BufferRail: Current.BufferRail,\n PlaybackState: Current.PlaybackState,\n ErrorMessage: Current.ErrorMessage,\n },\n Queue: {\n Title: Queue.Title,\n Subtitle: Queue.Subtitle,\n Description: Queue.Description,\n Copyright: Queue.Copyright,\n Artwork: Queue.Artwork,\n },\n Control: {\n PlayPause: Control.PlayPause,\n Repeat: Control.Repeat,\n Next: Control.Next,\n Previous: Control.Previous,\n Shuffle: Control.Shuffle,\n SeekBar: Control.SeekBar,\n Volume: Control.Volume,\n Mute: Control.Mute,\n PlaybackRate: Control.PlaybackRate,\n },\n Playlist: GingerPlaylistCompound,\n};\n"],"names":["GingerContext","createContext","useGingerContext","ctx","useContext","readBufferedFraction","el","buffered","duration","GingerPlayer","className","style","preload","crossOrigin","respectReducedMotion","audioRef","dispatch","state","notifyEnded","url","_a","lastTimeSnapshotRef","useRef","lastActiveUrlRef","reducedMotion","setReducedMotion","useState","useEffect","mql","sync","syncTime","force","next","prev","timeThreshold","changedEnough","jsx","e","code","clampIndex","index","length","shuffleWithAnchor","tracks","anchorIndex","anchor","rest","_","i","j","trackIdentity","track","findIndexByTrackIdentity","target","byRef","t","identity","matches","nodeEnv","_b","insertTrackAt","at","removeTrackAt","moveTrack","fromIndex","toIndex","item","addNextTrack","currentIndex","computeEndedTransition","repeatMode","playbackMode","len","computeNextIndex","computePrevIndex","cycleRepeatMode","mode","resolveArtworkUrl","playlistArtwork","resolveAlbumLine","playlistSubtitle","getCurrentTrack","derivePlaybackUiState","effectiveDuration","d","hint","effectiveRemaining","rem","progressFraction","dur","resolvedArtwork","resolvedAlbumLine","createTextDisplay","displayName","select","Comp","props","useGingerState","value","fallback","empty","children","node","createTrackFieldDisplay","Title","Artist","Album","s","Description","Copyright","Genre","Label","Isrc","TrackNumber","Year","format","y","text","Lyrics","preserveWhitespace","raw","whiteStyle","lrcTag","parseLrc","lrc","lines","rawLine","m","minutes","seconds","millis","time","a","b","useGingerLyricsSync","useGingerPlayback","currentTime","useGingerMedia","currentTrack","useMemo","line","activeIndex","LyricsSynced","unstyled","activeClassName","lineClassName","listStyle","active","useGingerChapters","seek","list","chapter","formatMmSs","Chapters","formatStart","seekTo","FileUrl","visible","Artwork","sizes","loading","onError","decoding","imgStyle","src","alt","QueueIndex","base","QueueLength","QueuePosition","separator","label","renderTime","valueSeconds","Elapsed","Duration","Remaining","Progress","fraction","TimeRail","height","showBuffered","progressPct","bufPct","jsxs","BufferRail","PlaybackState","ErrorMessage","live","defaultGingerLocale","rate","mergeLocale","partial","GingerLocaleContext","GingerLocaleProvider","locale","useGingerLocale","useSeekBarBinding","pb","md","gingerStateFromContextValues","numericValue","ariaValueText","onSeekInput","useVolumeSlider","onVolumeInput","usePlayPauseBinding","options","playL","pauseL","PlayPause","playLabel","pauseLabel","playAriaLabel","pauseAriaLabel","type","onClick","defaultPlayAria","defaultPauseAria","Repeat","ariaLabel","cycleRepeat","Next","Previous","Shuffle","isShuffled","toggleShuffle","SeekBar","inputStyle","mergedStyle","Volume","Mute","muteLabel","unmuteLabel","muted","toggleMute","u","defaultRates","PlaybackRate","rates","playbackRate","setPlaybackRate","r","GingerPlaylistConfigContext","usePlaylistConfig","GingerPlaylist","rowStyle","renderTrack","playOnSelect","playTrackAt","selectTrackAt","GingerPlaylistTrack","liProps","buttonRest","defaultLabel","GingerPlaylistCompound","Subtitle","clampVolume","v","clampPlaybackRate","resetTimingOnly","defaultMedia","createInitialState","params","originalTracks","ordered","gingerReducer","action","playlistMeta","isPaused","volume","idx","insertIndex","ap","snapshot","shuffled","restored","current","newIndex","nextIndex","same","prevIndex","getMediaSession","useMediaSessionBridge","enabled","actions","title","artist","album","artworkUrl","ms","details","defaultProviderStyle","GingerProvider","initialTracks","initialIndex","initialPlaylistMeta","initialShuffle","initialRepeatMode","initialPlaybackMode","initialPaused","initialVolume","initialMuted","initialPlaybackRate","initialStateKey","mediaSession","beforePlay","onPlayBlocked","persistence","hydrateOnMount","resumeOnTrackChange","onTrackChange","onPlay","onPause","onQueueEnd","useReducer","stateRef","latestInitRef","prevInitialStateKeyRef","p","prevPausedRef","play","useCallback","pause","togglePlayPause","timeSeconds","setVolume","setMuted","setRepeatMode","setQueue","autoPlay","enqueueNext","setPlaylistMeta","meta","setPlaybackMode","init","payload","key","saved","id","currentUrl","cancelled","allowed","error","message","msg","transition","mediaSessionActions","providerDir","playbackValue","mediaValue","playbackUi","GingerPlaybackContext","GingerMediaContext","Ginger","Current.Title","Current.Artist","Current.Album","Current.Description","Current.Copyright","Current.Genre","Current.Label","Current.Isrc","Current.TrackNumber","Current.Year","Current.Lyrics","Current.LyricsSynced","Current.Chapters","Current.FileUrl","Current.Artwork","Current.QueueIndex","Current.QueueLength","Current.QueuePosition","Current.Elapsed","Current.Duration","Current.Remaining","Current.Progress","Current.TimeRail","Current.BufferRail","Current.PlaybackState","Current.ErrorMessage","Queue.Title","Queue.Subtitle","Queue.Description","Queue.Copyright","Queue.Artwork","Control.PlayPause","Control.Repeat","Control.Next","Control.Previous","Control.Shuffle","Control.SeekBar","Control.Volume","Control.Mute","Control.PlaybackRate"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./ginger-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./ginger-CMbd3s8C.cjs"),r=require("./useNextTrackPrefetch-CFoUynDv.cjs"),a=require("./GingerSplitContexts-C7puo0M7.cjs");exports.Chapters=e.Chapters;exports.Ginger=e.Ginger;exports.LyricsSynced=e.LyricsSynced;exports.clampPlaybackRate=e.clampPlaybackRate;exports.clampVolume=e.clampVolume;exports.defaultGingerLocale=e.defaultGingerLocale;exports.derivePlaybackUiState=e.derivePlaybackUiState;exports.parseLrc=e.parseLrc;exports.useGingerChapters=e.useGingerChapters;exports.useGingerLocale=e.useGingerLocale;exports.useGingerLyricsSync=e.useGingerLyricsSync;exports.usePlayPauseBinding=e.usePlayPauseBinding;exports.useSeekBarBinding=e.useSeekBarBinding;exports.useVolumeSlider=e.useVolumeSlider;exports.attachLiveAnalyser=r.attachLiveAnalyser;exports.detachLiveAnalyser=r.detachLiveAnalyser;exports.useGinger=r.useGinger;exports.useGingerDebugLog=r.useGingerDebugLog;exports.useGingerKeyboardShortcuts=r.useGingerKeyboardShortcuts;exports.useGingerLiveAnalyzer=r.useGingerLiveAnalyzer;exports.useGingerSleepTimer=r.useGingerSleepTimer;exports.useNextTrackPrefetch=r.useNextTrackPrefetch;exports.useSeekDrag=r.useSeekDrag;exports.gingerStateFromContextValues=a.gingerStateFromContextValues;exports.gingerStateFromContexts=a.gingerStateFromContexts;exports.useGingerMedia=a.useGingerMedia;exports.useGingerPlayback=a.useGingerPlayback;exports.useGingerState=a.useGingerState;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,43 +1,85 @@
|
|
|
1
|
+
/** Compound component namespace for provider, player, controls, queue, and playlist UI primitives. */
|
|
1
2
|
export { Ginger } from './ginger';
|
|
3
|
+
/** High-level hook that returns combined state, selectors, and playback actions. */
|
|
2
4
|
export { useGinger } from './hooks/useGinger';
|
|
5
|
+
/** Hook for real-time frequency data from the active media element. */
|
|
3
6
|
export { useGingerLiveAnalyzer } from './analyzer/useGingerLiveAnalyzer';
|
|
4
|
-
|
|
7
|
+
/** Types for configuring and consuming live analyzer output. */
|
|
8
|
+
export type { UseGingerLiveAnalyzerOptions, UseGingerLiveAnalyzerResult, } from './analyzer/useGingerLiveAnalyzer';
|
|
9
|
+
/** Low-level attach/detach helpers for custom analyzer graph wiring. */
|
|
5
10
|
export { attachLiveAnalyser, detachLiveAnalyser } from './analyzer/liveAudioGraph';
|
|
11
|
+
/** Low-level analyzer graph option type. */
|
|
6
12
|
export type { LiveAnalyserOptions } from './analyzer/liveAudioGraph';
|
|
13
|
+
/** Core state and provider public type exports. */
|
|
7
14
|
export type { DisplayBaseProps, GingerAction, GingerInitPayload, GingerLocaleMessages, GingerMediaSlice, GingerPersistenceAdapter, GingerPlaybackSlice, GingerProviderProps, GingerState, PlaybackMode, PlaybackUiState, PlaylistMeta, RepeatMode, Track, } from './types';
|
|
15
|
+
/** Clamp helpers used by controls and custom integrations. */
|
|
8
16
|
export { clampPlaybackRate, clampVolume } from './core/playbackReducer';
|
|
17
|
+
/** Navigation-focused playback slice type for transition helpers. */
|
|
9
18
|
export type { GingerPlaybackNavigationSlice } from './core/transitions';
|
|
19
|
+
/** Selector that derives a normalized UI playback status value. */
|
|
10
20
|
export { derivePlaybackUiState } from './internal/selectors';
|
|
21
|
+
/** Split-context hooks and state combiners for advanced composition. */
|
|
11
22
|
export { gingerStateFromContexts, gingerStateFromContextValues, useGingerMedia, useGingerPlayback, useGingerState, } from './context/GingerSplitContexts';
|
|
23
|
+
/** Action/context types for split playback and media contexts. */
|
|
12
24
|
export type { GingerMediaActions, GingerMediaContextValue, GingerPlaybackActions, GingerPlaybackContextValue, } from './context/GingerSplitContexts';
|
|
25
|
+
/** Locale defaults and locale hook for control labels. */
|
|
13
26
|
export { defaultGingerLocale, useGingerLocale } from './context/GingerLocaleContext';
|
|
27
|
+
/** Binding types for button and slider control hooks. */
|
|
14
28
|
export type { PlayPauseBinding, SeekBarBinding, VolumeBinding, } from './hooks/useControlBindings';
|
|
15
|
-
|
|
29
|
+
/** Hooks that expose ergonomic control bindings. */
|
|
30
|
+
export { usePlayPauseBinding, useSeekBarBinding, useVolumeSlider, } from './hooks/useControlBindings';
|
|
31
|
+
/** Keyboard shortcut binding type for custom hotkey UIs. */
|
|
16
32
|
export type { GingerKeyboardShortcutBindings } from './hooks/useGingerKeyboardShortcuts';
|
|
33
|
+
/** Hook for keyboard shortcuts tied to Ginger playback actions. */
|
|
17
34
|
export { useGingerKeyboardShortcuts } from './hooks/useGingerKeyboardShortcuts';
|
|
35
|
+
/** Chapter model and chapter progress hook type. */
|
|
18
36
|
export type { GingerChapter, GingerChapterState } from './hooks/useGingerChapters';
|
|
37
|
+
/** Hook for chapter parsing and active chapter tracking. */
|
|
19
38
|
export { useGingerChapters } from './hooks/useGingerChapters';
|
|
39
|
+
/** Lyrics synchronization state type. */
|
|
20
40
|
export type { GingerLyricsSyncState } from './hooks/useGingerLyricsSync';
|
|
41
|
+
/** Hook for synced lyric line lookup by current playback time. */
|
|
21
42
|
export { useGingerLyricsSync } from './hooks/useGingerLyricsSync';
|
|
43
|
+
/** Sleep timer options type. */
|
|
22
44
|
export type { GingerSleepTimerOptions } from './hooks/useGingerSleepTimer';
|
|
45
|
+
/** Hook for sleep timer scheduling and cancellation. */
|
|
23
46
|
export { useGingerSleepTimer } from './hooks/useGingerSleepTimer';
|
|
47
|
+
/** Hook for structured debug logging of playback state transitions. */
|
|
24
48
|
export { useGingerDebugLog } from './hooks/useGingerDebugLog';
|
|
49
|
+
/** Drag state type for custom scrubbing interactions. */
|
|
25
50
|
export type { SeekDragState } from './hooks/useSeekDrag';
|
|
51
|
+
/** Hook for pointer-driven seek interactions. */
|
|
26
52
|
export { useSeekDrag } from './hooks/useSeekDrag';
|
|
53
|
+
/** Next-track prefetch options type. */
|
|
27
54
|
export type { UseNextTrackPrefetchOptions } from './hooks/useNextTrackPrefetch';
|
|
55
|
+
/** Hook for prefetching next track media resources. */
|
|
28
56
|
export { useNextTrackPrefetch } from './hooks/useNextTrackPrefetch';
|
|
57
|
+
/** Public player component props type. */
|
|
29
58
|
export type { GingerPlayerProps } from './audio/GingerPlayer';
|
|
59
|
+
/** Playlist component and track item prop types. */
|
|
30
60
|
export type { GingerPlaylistProps, GingerPlaylistTrackProps, } from './components/playlist/GingerPlaylist';
|
|
61
|
+
/** Current playback status component prop types. */
|
|
31
62
|
export type { ErrorMessageProps, PlaybackStateProps, } from './components/current/Playback';
|
|
63
|
+
/** Artwork component prop type alias for current-track artwork. */
|
|
32
64
|
export type { ArtworkProps as CurrentArtworkProps } from './components/current/Artwork';
|
|
65
|
+
/** Current file URL display prop type. */
|
|
33
66
|
export type { FileUrlProps } from './components/current/FileUrl';
|
|
67
|
+
/** Plain lyrics display prop type. */
|
|
34
68
|
export type { LyricsProps } from './components/current/Lyrics';
|
|
69
|
+
/** Chapter list component prop type. */
|
|
35
70
|
export type { ChaptersProps } from './components/current/Chapters';
|
|
71
|
+
/** Synced lyrics component prop type. */
|
|
36
72
|
export type { LyricsSyncedProps } from './components/current/LyricsSynced';
|
|
73
|
+
/** Rich current-track components that require explicit named imports. */
|
|
37
74
|
export { Chapters, LyricsSynced } from './components/current';
|
|
75
|
+
/** Time and rail component prop types. */
|
|
38
76
|
export type { BufferRailProps, ProgressProps, TimeRailProps, TimeTextProps, } from './components/current/Time';
|
|
77
|
+
/** Queue meta component prop types. */
|
|
39
78
|
export type { QueueIndexProps, QueueLengthProps, QueuePositionProps, } from './components/current/QueueMeta';
|
|
79
|
+
/** Queue artwork component prop type. */
|
|
40
80
|
export type { QueueArtworkProps } from './components/queue/QueueDisplay';
|
|
81
|
+
/** Control component prop types for headless buttons/sliders/selects. */
|
|
41
82
|
export type { MuteProps, NextProps, PlaybackRateProps, PlayPauseProps, PreviousProps, RepeatProps, SeekBarProps, ShuffleProps, VolumeProps, } from './components/controls/Controls';
|
|
83
|
+
/** Utility parser for LRC-format lyric text. */
|
|
42
84
|
export { parseLrc } from './internal/lyrics';
|
|
43
85
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,oFAAoF;AACpF,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,uEAAuE;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,gEAAgE;AAChE,YAAY,EACV,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,kCAAkC,CAAC;AAC1C,wEAAwE;AACxE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACnF,4CAA4C;AAC5C,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,mDAAmD;AACnD,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,UAAU,EACV,KAAK,GACN,MAAM,SAAS,CAAC;AAEjB,8DAA8D;AAC9D,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACxE,qEAAqE;AACrE,YAAY,EAAE,6BAA6B,EAAE,MAAM,oBAAoB,CAAC;AACxE,mEAAmE;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,wEAAwE;AACxE,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,cAAc,EACd,iBAAiB,EACjB,cAAc,GACf,MAAM,+BAA+B,CAAC;AACvC,kEAAkE;AAClE,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC;AAEvC,0DAA0D;AAC1D,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrF,yDAAyD;AACzD,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,aAAa,GACd,MAAM,4BAA4B,CAAC;AACpC,oDAAoD;AACpD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,GAChB,MAAM,4BAA4B,CAAC;AAEpC,4DAA4D;AAC5D,YAAY,EAAE,8BAA8B,EAAE,MAAM,oCAAoC,CAAC;AACzF,mEAAmE;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAEhF,oDAAoD;AACpD,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACnF,4DAA4D;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,yCAAyC;AACzC,YAAY,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACzE,kEAAkE;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,gCAAgC;AAChC,YAAY,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,wDAAwD;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,uEAAuE;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,yDAAyD;AACzD,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,iDAAiD;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,wCAAwC;AACxC,YAAY,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAChF,uDAAuD;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,0CAA0C;AAC1C,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,oDAAoD;AACpD,YAAY,EACV,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,sCAAsC,CAAC;AAC9C,oDAAoD;AACpD,YAAY,EACV,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,mEAAmE;AACnE,YAAY,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxF,0CAA0C;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,sCAAsC;AACtC,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,wCAAwC;AACxC,YAAY,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,yCAAyC;AACzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,yEAAyE;AACzE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC9D,0CAA0C;AAC1C,YAAY,EACV,eAAe,EACf,aAAa,EACb,aAAa,EACb,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,uCAAuC;AACvC,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,yCAAyC;AACzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,yEAAyE;AACzE,YAAY,EACV,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,MAAM,gCAAgC,CAAC;AAExC,gDAAgD;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as s, G as r, L as i, c as n, a as t, d as u, b as g, p as c, u as l, e as o, f as G, g as y, h as d, i as S } from "./ginger-
|
|
2
|
-
import { a as p, d as L, u as b, b as h, c as f, e as k, f as x, g as P, h as C } from "./useNextTrackPrefetch-
|
|
1
|
+
import { C as s, G as r, L as i, c as n, a as t, d as u, b as g, p as c, u as l, e as o, f as G, g as y, h as d, i as S } from "./ginger-8x4WzVmw.js";
|
|
2
|
+
import { a as p, d as L, u as b, b as h, c as f, e as k, f as x, g as P, h as C } from "./useNextTrackPrefetch-CV1khU0h.js";
|
|
3
3
|
import { g as A, a as B, u as V, b as D, c as F } from "./GingerSplitContexts-BzBExb95.js";
|
|
4
4
|
export {
|
|
5
5
|
s as Chapters,
|
|
@@ -18,4 +18,33 @@ export type RenderGingerProviderOptions = Partial<Pick<GingerProviderProps, "ini
|
|
|
18
18
|
/** When false, omit `Ginger.Player` (e.g. to assert missing-audio warnings). Default true. */
|
|
19
19
|
withPlayer?: boolean;
|
|
20
20
|
};
|
|
21
|
+
/** Create a preconfigured user-event instance for interaction tests. */
|
|
22
|
+
export declare function setupUser(): import('@testing-library/user-event').UserEvent;
|
|
23
|
+
/** Dispatch `loadedmetadata` with a deterministic duration value. */
|
|
24
|
+
export declare function emitLoadedMetadata(audio: HTMLAudioElement, duration: number): void;
|
|
25
|
+
/** Dispatch `timeupdate` and optionally update duration before emitting. */
|
|
26
|
+
export declare function emitTimeUpdate(audio: HTMLAudioElement, currentTime: number, duration?: number): void;
|
|
27
|
+
/** Dispatch an `ended` event from an audio element. */
|
|
28
|
+
export declare function emitEnded(audio: HTMLAudioElement): void;
|
|
29
|
+
export type QueueSnapshot = {
|
|
30
|
+
currentIndex: number;
|
|
31
|
+
tracks: Array<{
|
|
32
|
+
id?: string;
|
|
33
|
+
fileUrl: string;
|
|
34
|
+
}>;
|
|
35
|
+
currentTrack?: {
|
|
36
|
+
id?: string;
|
|
37
|
+
fileUrl: string;
|
|
38
|
+
} | null;
|
|
39
|
+
};
|
|
40
|
+
export type ExpectedQueueState = {
|
|
41
|
+
currentIndex?: number;
|
|
42
|
+
length?: number;
|
|
43
|
+
currentId?: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Lightweight queue assertion helper for test runners.
|
|
47
|
+
* Throws a readable error when expected queue state does not match.
|
|
48
|
+
*/
|
|
49
|
+
export declare function expectQueueState(snapshot: QueueSnapshot, expected: ExpectedQueueState): void;
|
|
21
50
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/testing/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/testing/helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEpD,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,SAAS,EAAE,WAAW,GAAG,gBAAgB,GAAG,IAAI,CAE1E;AAED,MAAM,MAAM,4BAA4B,GAAG;IACzC,kFAAkF;IAClF,IAAI,EAAE,YAAY,CAAC;IACnB,8DAA8D;IAC9D,UAAU,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,yBAAyB,GAAG,IAAI,CAAC;IAC7E,iDAAiD;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,4BAA4B,CA8B3E;AAED,MAAM,MAAM,2BAA2B,GAAG,OAAO,CAC/C,IAAI,CACF,mBAAmB,EACjB,cAAc,GACd,eAAe,GACf,qBAAqB,GACrB,qBAAqB,GACrB,cAAc,GACd,YAAY,GACZ,SAAS,GACT,aAAa,CAChB,CACF,GAAG;IACF,8FAA8F;IAC9F,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,SAAS,oDAExB;AAED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,QAM3E;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,QAa7F;AAED,uDAAuD;AACvD,wBAAgB,SAAS,CAAC,KAAK,EAAE,gBAAgB,QAEhD;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,YAAY,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACxD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,kBAAkB,QAmBrF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.test.d.ts","sourceRoot":"","sources":["../../src/testing/helpers.test.ts"],"names":[],"mappings":""}
|