@openrails/contentkit-ui 0.83.0 → 0.86.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -7
- package/dist/client/beacons.d.ts +18 -6
- package/dist/client/beacons.js +26 -11
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/client.d.ts +3 -0
- package/dist/client/client.js +29 -27
- package/dist/client/client.js.map +1 -1
- package/dist/client/codes.d.ts +6 -1
- package/dist/client/codes.js +4 -1
- package/dist/client/codes.js.map +1 -1
- package/dist/client/content/moderation.d.ts +14 -2
- package/dist/client/content/moderation.js +34 -0
- package/dist/client/content/moderation.js.map +1 -1
- package/dist/client/content/types.d.ts +13 -0
- package/dist/client/content/types.js.map +1 -1
- package/dist/client/discovery.d.ts +6 -0
- package/dist/client/discovery.js.map +1 -1
- package/dist/client/generated/error-codes.d.ts +1 -1
- package/dist/client/generated/error-codes.js +9 -1
- package/dist/client/generated/error-codes.js.map +1 -1
- package/dist/client/generated/routes.d.ts +91 -13
- package/dist/client/generated/routes.js +123 -2
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +81 -0
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +4 -2
- package/dist/client/media/queue.d.ts +4 -2
- package/dist/client/media/queue.js +18 -12
- package/dist/client/media/queue.js.map +1 -1
- package/dist/client/media/rules.d.ts +7 -1
- package/dist/client/media/rules.js +27 -21
- package/dist/client/media/rules.js.map +1 -1
- package/dist/client/reader-meta.d.ts +27 -0
- package/dist/client/reader-meta.js +99 -0
- package/dist/client/reader-meta.js.map +1 -0
- package/dist/client/stats.d.ts +32 -0
- package/dist/client/stats.js +35 -0
- package/dist/client/stats.js.map +1 -0
- package/dist/client/versions.d.ts +1 -1
- package/dist/client/versions.js +7 -2
- package/dist/client/versions.js.map +1 -1
- package/dist/client.js +30 -28
- package/dist/components/admin/content-manager.js +206 -206
- package/dist/components/admin/content-manager.js.map +1 -1
- package/dist/components/admin/group-manager.js +71 -70
- package/dist/components/admin/group-manager.js.map +1 -1
- package/dist/components/admin/media-item-panel.d.ts +24 -7
- package/dist/components/admin/media-item-panel.js +209 -197
- package/dist/components/admin/media-item-panel.js.map +1 -1
- package/dist/components/admin/poll-manager.js +25 -25
- package/dist/components/admin/reader-manifest.d.ts +18 -0
- package/dist/components/admin/reader-manifest.js +490 -0
- package/dist/components/admin/reader-manifest.js.map +1 -0
- package/dist/components/admin/stats-dashboard.d.ts +22 -0
- package/dist/components/admin/stats-dashboard.js +257 -0
- package/dist/components/admin/stats-dashboard.js.map +1 -0
- package/dist/components/content/card.js +43 -43
- package/dist/components/content/card.js.map +1 -1
- package/dist/components/content/editors.d.ts +2 -1
- package/dist/components/content/editors.js +479 -416
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/grid.js +47 -47
- package/dist/components/content/index.d.ts +2 -1
- package/dist/components/content/listing.js +34 -34
- package/dist/components/content/listing.js.map +1 -1
- package/dist/components/content/paywall.d.ts +17 -5
- package/dist/components/content/paywall.js +115 -100
- package/dist/components/content/paywall.js.map +1 -1
- package/dist/components/content/reader-stats.d.ts +12 -0
- package/dist/components/content/reader-stats.js +47 -0
- package/dist/components/content/reader-stats.js.map +1 -0
- package/dist/components/groups/banner.d.ts +1 -1
- package/dist/components/groups/banner.js +34 -34
- package/dist/components/groups/banner.js.map +1 -1
- package/dist/components/groups/directory.js +11 -11
- package/dist/components/groups/editor.js +294 -294
- package/dist/components/groups/editor.js.map +1 -1
- package/dist/components/groups/header.js +27 -27
- package/dist/components/groups/header.js.map +1 -1
- package/dist/components/groups/memberships.js +180 -180
- package/dist/components/groups/parts.d.ts +2 -4
- package/dist/components/groups/parts.js +69 -88
- package/dist/components/groups/parts.js.map +1 -1
- package/dist/components/media-folder-editor.js +239 -189
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/notifications.js +17 -17
- package/dist/components/slot-upload.d.ts +2 -2
- package/dist/components/slot-upload.js +84 -79
- package/dist/components/slot-upload.js.map +1 -1
- package/dist/components/social/bans.js +34 -34
- package/dist/components/social/comments.js +59 -45
- package/dist/components/social/comments.js.map +1 -1
- package/dist/components/social/index.d.ts +1 -0
- package/dist/components/social/moderation.d.ts +5 -4
- package/dist/components/social/moderation.js +177 -160
- package/dist/components/social/moderation.js.map +1 -1
- package/dist/components/social/parts.js +22 -14
- package/dist/components/social/parts.js.map +1 -1
- package/dist/components/social/rules.d.ts +23 -0
- package/dist/components/social/rules.js +261 -0
- package/dist/components/social/rules.js.map +1 -0
- package/dist/components/video-player.d.ts +2 -0
- package/dist/components/video-player.js +318 -314
- package/dist/components/video-player.js.map +1 -1
- package/dist/i18n/context.d.ts +2 -0
- package/dist/i18n/context.js +23 -5
- package/dist/i18n/context.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +28 -24
- package/dist/locales/admin/de.js +105 -0
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +105 -0
- package/dist/locales/admin/en.js +105 -0
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +105 -0
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +105 -0
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +105 -0
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +105 -0
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/content/de.js +6 -0
- package/dist/locales/content/de.js.map +1 -1
- package/dist/locales/content/en.d.ts +6 -0
- package/dist/locales/content/en.js +6 -0
- package/dist/locales/content/en.js.map +1 -1
- package/dist/locales/content/es.js +6 -0
- package/dist/locales/content/es.js.map +1 -1
- package/dist/locales/content/ja.js +6 -0
- package/dist/locales/content/ja.js.map +1 -1
- package/dist/locales/content/ko.js +6 -0
- package/dist/locales/content/ko.js.map +1 -1
- package/dist/locales/content/zh.js +6 -0
- package/dist/locales/content/zh.js.map +1 -1
- package/dist/locales/de.js +4 -1
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/discovery/de.js +1 -0
- package/dist/locales/discovery/de.js.map +1 -1
- package/dist/locales/discovery/en.d.ts +1 -0
- package/dist/locales/discovery/en.js +1 -0
- package/dist/locales/discovery/en.js.map +1 -1
- package/dist/locales/discovery/es.js +1 -0
- package/dist/locales/discovery/es.js.map +1 -1
- package/dist/locales/discovery/ja.js +1 -0
- package/dist/locales/discovery/ja.js.map +1 -1
- package/dist/locales/discovery/ko.js +1 -0
- package/dist/locales/discovery/ko.js.map +1 -1
- package/dist/locales/discovery/zh.js +1 -0
- package/dist/locales/discovery/zh.js.map +1 -1
- package/dist/locales/en.d.ts +118 -0
- package/dist/locales/en.js +4 -1
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +4 -1
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/ja.js +4 -1
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +4 -1
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/social/de.js +3 -0
- package/dist/locales/social/de.js.map +1 -1
- package/dist/locales/social/en.d.ts +3 -0
- package/dist/locales/social/en.js +3 -0
- package/dist/locales/social/en.js.map +1 -1
- package/dist/locales/social/es.js +3 -0
- package/dist/locales/social/es.js.map +1 -1
- package/dist/locales/social/ja.js +3 -0
- package/dist/locales/social/ja.js.map +1 -1
- package/dist/locales/social/ko.js +3 -0
- package/dist/locales/social/ko.js.map +1 -1
- package/dist/locales/social/zh.js +3 -0
- package/dist/locales/social/zh.js.map +1 -1
- package/dist/locales/zh.js +4 -1
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/admin.d.ts +1 -1
- package/dist/react/admin.js +24 -23
- package/dist/react/admin.js.map +1 -1
- package/dist/react/canonical.d.ts +4 -3
- package/dist/react/canonical.js +34 -33
- package/dist/react/canonical.js.map +1 -1
- package/dist/react/comments.d.ts +29 -1
- package/dist/react/comments.js +30 -2
- package/dist/react/comments.js.map +1 -1
- package/dist/react/contents.js +144 -144
- package/dist/react/contents.js.map +1 -1
- package/dist/react/context.d.ts +1 -1
- package/dist/react/context.js.map +1 -1
- package/dist/react/detail.d.ts +12 -6
- package/dist/react/detail.js +31 -24
- package/dist/react/detail.js.map +1 -1
- package/dist/react/discovery.js +1 -1
- package/dist/react/discovery.js.map +1 -1
- package/dist/react/folder.d.ts +7 -2
- package/dist/react/folder.js +165 -147
- package/dist/react/folder.js.map +1 -1
- package/dist/react/groups.d.ts +0 -1
- package/dist/react/groups.js +13 -12
- package/dist/react/groups.js.map +1 -1
- package/dist/react/index.d.ts +5 -3
- package/dist/react/location.d.ts +11 -0
- package/dist/react/location.js +18 -0
- package/dist/react/location.js.map +1 -0
- package/dist/react/public.d.ts +8 -0
- package/dist/react/public.js +32 -27
- package/dist/react/public.js.map +1 -1
- package/dist/react/resources.js +6 -0
- package/dist/react/resources.js.map +1 -1
- package/dist/react/stats.d.ts +24 -0
- package/dist/react/stats.js +28 -0
- package/dist/react/stats.js.map +1 -0
- package/dist/react/use-resource.js +8 -7
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react/versions.js +20 -20
- package/dist/react.js +26 -24
- package/dist/styles.css +1 -1
- package/dist/urls/index.d.ts +35 -10
- package/dist/urls.js +100 -70
- package/dist/urls.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video-player.js","names":[],"sources":["../../src/components/video-player.tsx"],"sourcesContent":["import {\n AlertCircleIcon,\n ArrowShrink02Icon,\n ClosedCaptionIcon,\n FullScreenIcon,\n PauseIcon,\n PictureInPicture01Icon,\n PictureInPictureExitIcon,\n PictureInPictureOnIcon,\n PlayIcon,\n RectangularIcon,\n Refresh01Icon,\n Settings01Icon,\n} from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useCallback, useEffect, useRef, useState, type CSSProperties, type MouseEvent, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport { formatDuration } from \"../client/gallery.js\";\nimport type { PlaybackError } from \"../client/playback.js\";\nimport {\n JUMP_SEEK,\n PLAYBACK_SPEEDS,\n PLAYER_VOLUME_KEY,\n nextSpeed,\n playerKeyAction,\n resumeAt,\n writeVolume,\n type PlayerAction,\n type PlayerTrack,\n} from \"../client/player.js\";\nimport { useHlsPlayer, type HlsPlayerOptions } from \"../react/gallery.js\";\nimport { useInlinePreview } from \"../react/inline-preview.js\";\nimport { useActiveCues, useFullscreen, useMediaState, usePictureInPicture, useProgressReports, useSprite, type PlaybackProgress } from \"../react/player.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\nimport { RenditionImg } from \"./rendition-img.js\";\nimport { publicRenditions, type PublicPreset } from \"../client/public.js\";\nimport type { EncodeProgress as Progress } from \"../client/generated/wire.js\";\nimport { EncodeProgress } from \"./encode-progress.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Captions, ControlButton, SeekBar, SeekFlash, SettingsMenu, Spinner, VolumeControl, clock, playerButtonClass, type MenuSection, type SeekFlashState } from \"./player-controls.js\";\n\ntype XhrSetup = HlsPlayerOptions[\"xhrSetup\"];\n\n/** The first frame of a video's seek sprite (sprite.vtt), fitted like object-fit. */\nexport function SpriteFrame({ vtt, xhrSetup, fit = \"contain\", className }: { vtt: string; xhrSetup?: XhrSetup; fit?: \"contain\" | \"cover\"; className?: string }) {\n const sprite = useSprite(vtt, xhrSetup);\n const cue = sprite?.cues[0];\n if (!sprite || !cue) return null;\n return (\n <svg\n aria-hidden\n className={cn(\"pointer-events-none absolute inset-0 size-full\", className)}\n viewBox={`${cue.x} ${cue.y} ${cue.w} ${cue.h}`}\n preserveAspectRatio={fit === \"cover\" ? \"xMidYMid slice\" : \"xMidYMid meet\"}\n data-ckui=\"sprite-frame\"\n >\n <image href={cue.url} width={sprite.width} height={sprite.height} />\n </svg>\n );\n}\n\ntype At<T> = T extends unknown ? T & { time: number } : never;\n\n/** Playback as it happens, for analytics; never during an inline preview. */\nexport type PlayerEvent = At<\n | { type: \"play\" | \"playing\" | \"pause\" | \"waiting\" | \"ended\" }\n | { type: \"seek\"; from: number }\n | { type: \"rate\"; rate: number }\n | { type: \"volume\"; volume: number; muted: boolean }\n /** The viewer's quality choice; height null is Auto. */\n | { type: \"quality\"; height: number | null }\n | { type: \"audio\"; track: PlayerTrack }\n | { type: \"subtitles\"; track: PlayerTrack | null }\n | { type: \"fullscreen\" | \"pip\" | \"theater\"; on: boolean }\n | { type: \"error\"; error: PlaybackError }\n>;\n\n/** Everything a VideoMiniPlayer needs to carry on where the player stopped. */\nexport interface PlayerHandoff {\n base: string;\n time: number;\n playing: boolean;\n width?: number;\n height?: number;\n duration?: number;\n poster?: string | PublicPreset | null;\n audioLanguage?: string;\n subtitleLanguage?: string | null;\n}\n\n/** A host entry in the settings menu: a choice (e.g. version) or an action (e.g. report a problem). */\nexport type PlayerMenuItem =\n | { label: string; value: string; options: readonly { value: string; label: string }[]; onChange: (value: string) => void }\n | { label: string; onSelect: () => void };\n\nexport interface PlayerSlotContext {\n /** Where popups must portal to stay visible: the player while fullscreen, else undefined (the body). */\n container?: HTMLElement;\n /** The control buttons' class. */\n className: string;\n}\n\nexport interface VideoPlayerProps extends Omit<HlsPlayerOptions, \"src\"> {\n /** The ladder's HLS folder (client.media.hlsBase: {media}/{kind}/{id}/hls/{dir}): master.m3u8 and sprite.vtt resolve under it. */\n base?: string | null;\n /** Shown until playback starts: the poster's public preset or a URL; default the first sprite frame. */\n poster?: string | PublicPreset | null;\n /** The video's size (read API w/h): the box is reserved before anything loads; default the decoded frame's. */\n width?: number;\n height?: number;\n duration?: number;\n /** A pending encode (an editor read's `pending` and `progress`): shows its progress instead of a player. */\n pending?: boolean;\n progress?: Progress | null;\n /** Why the video cannot be encoded (an editor read's `failed.message`). */\n failed?: string;\n /**\n * `frame` is as wide as its column allows at the video's aspect, never\n * taller than `maxHeight`; `fill` fills a sized parent (a carousel slide).\n */\n layout?: \"frame\" | \"fill\";\n maxHeight?: string;\n /** Preview muted inline before play (hover, or in view on touch); default the provider's. */\n inlinePreview?: boolean;\n /** Where the preview starts, seconds; default 10% in. */\n previewStart?: number;\n /** Shortcuts while focus is in the player (default), page-wide (a watch page: one such player per page), or none. */\n keyboard?: \"focus\" | \"global\" | false;\n /** Resume points and watch time: every `progressInterval` of playback, and on pause, seek, end, page hide and unload. */\n onProgress?: (progress: PlaybackProgress) => void;\n /** Milliseconds. Default 10000. */\n progressInterval?: number;\n onEvent?: (event: PlayerEvent) => void;\n /** Theater mode is the host's layout; the button shows with onTheaterChange. */\n theater?: boolean;\n onTheaterChange?: (theater: boolean) => void;\n /** Shows the mini-player button: the player pauses and hands over where it was. */\n onMiniPlayer?: (handoff: PlayerHandoff) => void;\n /** A control-bar slot for the host's downloads. */\n renderDownloads?: (ctx: PlayerSlotContext) => ReactNode;\n /** Host entries in the settings menu, after its own. */\n menuItems?: readonly PlayerMenuItem[];\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n label?: string;\n className?: string;\n style?: CSSProperties;\n appearance?: ContentKitUiAppearance;\n}\n\nconst CONTROLS_IDLE_MS = 2500;\nconst DOUBLE_TAP_MS = 300;\nconst TAP_SEEK_CONTINUE_MS = 700;\nconst SEEK_FLASH_MS = 650;\n\nconst TEXT_ENTRY =\n 'textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=textbox], [role=combobox], [role=searchbox], input:not([type=range]):not([type=button]):not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=reset])';\nconst MENU = \"[role=menu], [role=menuitem], [role=menuitemradio], [role=menuitemcheckbox], [role=listbox], [role=option]\";\nconst OUTSIDE_INTERACTIVE = \"a, button, input, [role=button], [role=dialog], [role=alertdialog]\";\n\n/**\n * Whether a shortcut key belongs to the player: never while typing or in a\n * menu, not the arrows on a slider (it steps itself), and outside the\n * player (page-wide shortcuts) not on another control.\n */\nexport function keyAllowed(target: EventTarget | null, key: string, root: Element): boolean {\n if (!(target instanceof Element)) return true;\n if (target.closest(TEXT_ENTRY) || target.closest(MENU)) return false;\n if (target.closest(\"input[type=range], [role=slider]\") && /^(Arrow|Page|Home$|End$)/.test(key)) return false;\n return root.contains(target) || !target.closest(OUTSIDE_INTERACTIVE);\n}\n\n// Space on one of the player's buttons is play/pause, not a click on the button last used.\nconst spaceOnButton = (target: EventTarget | null, root: Element) =>\n target instanceof Element && root.contains(target) && !!target.closest(\"button\") && !target.closest(MENU);\n\n/**\n * An HLS player that never spins forever: poster and play control, its own\n * controls (seek with sprite preview, volume, subtitles, audio, quality,\n * speed, picture-in-picture, theater, fullscreen, mini player), shortcuts,\n * touch gestures, resume and progress reports, and a specific error with\n * Retry and a support code.\n */\nexport function VideoPlayer({\n base,\n poster,\n width,\n height,\n duration,\n pending,\n progress,\n failed,\n layout = \"frame\",\n maxHeight = \"80svh\",\n inlinePreview,\n previewStart,\n keyboard = \"focus\",\n onProgress,\n progressInterval = 10_000,\n onEvent,\n theater,\n onTheaterChange,\n onMiniPlayer,\n renderDownloads,\n menuItems,\n crossOrigin,\n label,\n className,\n style,\n appearance,\n startAt,\n ...options\n}: VideoPlayerProps) {\n const { t } = useMessages();\n const playable = !!base && !pending && !failed;\n const src = playable ? `${base}master.m3u8` : null;\n const start = resumeAt(startAt, duration);\n const player = useHlsPlayer({ ...options, src, startAt: start });\n const { status, error, started, previewing, audio, subtitles, quality } = player;\n const [root, setRoot] = useState<HTMLDivElement | null>(null);\n const [video, setVideo] = useState<HTMLVideoElement | null>(null);\n const attach = player.ref;\n const videoRef = useCallback(\n (el: HTMLVideoElement | null) => {\n attach(el);\n setVideo(el);\n },\n [attach],\n );\n useInlinePreview({\n setting: inlinePreview,\n available: playable && !started && !error && options.active !== false && !options.autoPlay,\n target: root,\n playing: started && status === \"playing\",\n start: () => player.preview(previewStartAt(previewStart, duration)),\n stop: player.unload,\n });\n const media = useMediaState(video);\n const fs = useFullscreen(root, video);\n const pip = usePictureInPicture(video);\n const cues = useActiveCues(video);\n const sprite = useSprite(started && base ? `${base}sprite.vtt` : null, options.xhrSetup);\n const live = !previewing && started;\n useProgressReports(video, { enabled: live, source: live ? src : null, interval: progressInterval, onProgress });\n\n // Events.\n const emit = useRef(onEvent);\n emit.current = onEvent;\n const sending = useRef(false);\n sending.current = !previewing && status !== \"idle\";\n const send = useCallback((e: { type: string; [k: string]: unknown }, always = false) => {\n if ((always || sending.current) && emit.current) emit.current({ ...e, time: video?.currentTime ?? 0 } as PlayerEvent);\n }, [video]);\n useEffect(() => {\n if (!video) return;\n let from = 0;\n const h: Record<string, () => void> = {\n play: () => send({ type: \"play\" }),\n playing: () => send({ type: \"playing\" }),\n pause: () => !video.ended && send({ type: \"pause\" }),\n waiting: () => send({ type: \"waiting\" }),\n ended: () => send({ type: \"ended\" }),\n timeupdate: () => {\n if (!video.seeking) from = video.currentTime;\n },\n seeked: () => {\n send({ type: \"seek\", from });\n from = video.currentTime;\n },\n ratechange: () => send({ type: \"rate\", rate: video.playbackRate }),\n };\n for (const [k, f] of Object.entries(h)) video.addEventListener(k, f);\n return () => {\n for (const [k, f] of Object.entries(h)) video.removeEventListener(k, f);\n };\n }, [video, send]);\n useEffect(() => {\n if (error && !previewing) send({ type: \"error\", error }, true);\n }, [error, previewing, send]);\n const was = useRef({ fs: false, pip: false });\n useEffect(() => {\n if (was.current.fs !== fs.active) send({ type: \"fullscreen\", on: fs.active });\n if (was.current.pip !== pip.active) send({ type: \"pip\", on: pip.active });\n was.current = { fs: fs.active, pip: pip.active };\n }, [fs.active, pip.active, send]);\n\n // A new resume point for the playing source seeks to it.\n const lastStart = useRef(start);\n useEffect(() => {\n if (lastStart.current === start) return;\n lastStart.current = start;\n if (video && started) video.currentTime = start;\n }, [start, video, started]);\n\n // Controls show on pointer movement and hide after a pause in it while playing.\n const [poked, setPoked] = useState(false);\n const idle = useRef<ReturnType<typeof setTimeout>>(undefined);\n const poke = useCallback(() => {\n setPoked(true);\n clearTimeout(idle.current);\n idle.current = setTimeout(() => setPoked(false), CONTROLS_IDLE_MS);\n }, []);\n const hide = useCallback(() => {\n clearTimeout(idle.current);\n setPoked(false);\n }, []);\n useEffect(() => () => clearTimeout(idle.current), []);\n useEffect(() => {\n if (started) poke();\n }, [started, poke]);\n const [menuOpen, setMenuOpen] = useState(false);\n const [scrubbing, setScrubbing] = useState(false);\n const [keyFocus, setKeyFocus] = useState(false);\n const controlsShown = started && !error && (poked || media.paused || media.ended || menuOpen || scrubbing || keyFocus);\n\n const [flash, setFlash] = useState<SeekFlashState | null>(null);\n const flashTimer = useRef<ReturnType<typeof setTimeout>>(undefined);\n const flashSeek = useCallback((direction: -1 | 1, seconds: number) => {\n const continuing = flashTimer.current !== undefined;\n clearTimeout(flashTimer.current);\n setFlash((prev) => ({ direction, seconds: continuing && prev?.direction === direction ? prev.seconds + seconds : seconds }));\n flashTimer.current = setTimeout(() => {\n setFlash(null);\n flashTimer.current = undefined;\n }, SEEK_FLASH_MS);\n }, []);\n useEffect(() => () => clearTimeout(flashTimer.current), []);\n\n const volumeKey = options.volumeKey === undefined ? PLAYER_VOLUME_KEY : options.volumeKey;\n const dur = media.duration || duration || 0;\n const seek = (to: number) => {\n if (video) video.currentTime = Math.min(dur || to, Math.max(0, to));\n };\n const seekBy = (seconds: number) => {\n if (!video) return;\n seek(video.currentTime + seconds);\n flashSeek(seconds < 0 ? -1 : 1, Math.abs(seconds));\n };\n const toggle = () => {\n if (!video) return;\n if (!started || video.ended) {\n if (video.ended) video.currentTime = 0;\n player.play();\n } else if (video.paused) player.play();\n else video.pause();\n };\n const setVolume = (v: number) => {\n if (!video) return;\n video.volume = Math.min(1, Math.max(0, v));\n if (video.volume > 0 && video.muted) video.muted = false;\n writeVolume(volumeKey, { volume: video.volume, muted: video.muted });\n send({ type: \"volume\", volume: video.volume, muted: video.muted });\n };\n const toggleMute = () => {\n if (!video) return;\n video.muted = !video.muted;\n if (!video.muted && video.volume === 0) video.volume = 1;\n writeVolume(volumeKey, { volume: video.volume, muted: video.muted });\n send({ type: \"volume\", volume: video.volume, muted: video.muted });\n };\n const selectAudio = (i: number) => {\n audio.select(i);\n const track = audio.list[i];\n if (track) send({ type: \"audio\", track });\n };\n const lastSub = useRef(-1);\n if (subtitles.selected >= 0) lastSub.current = subtitles.selected;\n const selectSubs = (i: number) => {\n subtitles.select(i);\n send({ type: \"subtitles\", track: subtitles.list[i] ?? null });\n };\n const toggleCaptions = () => selectSubs(subtitles.selected >= 0 ? -1 : lastSub.current >= 0 ? lastSub.current : 0);\n const selectQuality = (i: number) => {\n quality.select(i);\n send({ type: \"quality\", height: quality.levels.find((l) => l.index === i)?.height ?? null });\n };\n const toggleTheater = () => {\n onTheaterChange?.(!theater);\n send({ type: \"theater\", on: !theater });\n };\n const openMini = () => {\n if (!onMiniPlayer || !base || !video) return;\n const a = audio.list[audio.selected];\n const s = subtitles.list[subtitles.selected];\n const handoff: PlayerHandoff = {\n base,\n time: video.currentTime,\n playing: !video.paused && !video.ended,\n width: width ?? (video.videoWidth || undefined),\n height: height ?? (video.videoHeight || undefined),\n duration: dur || undefined,\n poster,\n audioLanguage: a?.lang,\n subtitleLanguage: s?.lang ?? null,\n };\n video.pause();\n if (fs.active) fs.toggle();\n onMiniPlayer(handoff);\n };\n\n const run = (a: PlayerAction): boolean => {\n if (!video) return false;\n if (!started && a.type !== \"toggle\") return false;\n switch (a.type) {\n case \"toggle\":\n toggle();\n break;\n case \"seekBy\":\n seekBy(a.seconds);\n break;\n case \"seekTo\":\n if (!dur) return false;\n seek(dur * a.fraction);\n break;\n case \"volumeBy\":\n setVolume((video.muted ? 0 : video.volume) + a.delta);\n break;\n case \"mute\":\n toggleMute();\n break;\n case \"captions\":\n if (!subtitles.list.length) return false;\n toggleCaptions();\n break;\n case \"fullscreen\":\n if (!fs.supported) return false;\n fs.toggle();\n break;\n case \"theater\":\n if (!onTheaterChange) return false;\n toggleTheater();\n break;\n case \"miniPlayer\":\n if (!onMiniPlayer) return false;\n openMini();\n break;\n case \"speed\":\n video.playbackRate = nextSpeed(video.playbackRate, a.step);\n break;\n }\n if (started) poke();\n return true;\n };\n const runRef = useRef(run);\n runRef.current = run;\n const active = options.active !== false;\n useEffect(() => {\n if (!keyboard || !root || !active) return;\n const on: EventTarget = keyboard === \"global\" ? document : root;\n const down = (e: Event) => {\n const k = e as KeyboardEvent;\n if (k.defaultPrevented) return;\n const action = playerKeyAction(k);\n if (!action || !keyAllowed(k.target, k.key, root) || !runRef.current(action)) return;\n k.preventDefault();\n };\n const up = (e: Event) => {\n const k = e as KeyboardEvent;\n if (k.key === \" \" && spaceOnButton(k.target, root)) k.preventDefault();\n };\n on.addEventListener(\"keydown\", down);\n on.addEventListener(\"keyup\", up);\n return () => {\n on.removeEventListener(\"keydown\", down);\n on.removeEventListener(\"keyup\", up);\n };\n }, [keyboard, root, active]);\n\n // Mouse: click plays and pauses, double click is fullscreen. Touch: a tap\n // shows or hides the controls; double taps on either side seek 10 s, and\n // taps that keep coming keep seeking.\n const pointerType = useRef(\"mouse\");\n const lastTap = useRef<{ at: number; side: -1 | 1 } | null>(null);\n const tapSeekUntil = useRef(0);\n const onSurfaceClick = (e: MouseEvent<HTMLDivElement>) => {\n if (pointerType.current === \"mouse\") {\n toggle();\n poke();\n return;\n }\n const r = e.currentTarget.getBoundingClientRect();\n const x = r.width ? (e.clientX - r.left) / r.width : 0.5;\n const side = x < 0.4 ? -1 : x > 0.6 ? 1 : null;\n const now = Date.now();\n const last = lastTap.current;\n lastTap.current = side ? { at: now, side } : null;\n if (side && last?.side === side && (now < tapSeekUntil.current || now - last.at <= DOUBLE_TAP_MS)) {\n tapSeekUntil.current = now + TAP_SEEK_CONTINUE_MS;\n seekBy(side * JUMP_SEEK);\n return;\n }\n if (controlsShown && !media.paused) hide();\n else poke();\n };\n const onSurfaceDoubleClick = () => {\n if (Date.now() >= tapSeekUntil.current && fs.supported) fs.toggle();\n };\n\n const aspect = width && height ? width / height : (media.aspect ?? 16 / 9);\n const frame: CSSProperties = fs.active\n ? { width: \"100%\", height: \"100%\", borderRadius: 0 }\n : layout === \"frame\"\n ? { aspectRatio: String(aspect), width: `min(100%, calc(${maxHeight} * ${aspect}))`, marginInline: \"auto\" }\n : {};\n const posterOutputs = typeof poster === \"string\" ? [] : publicRenditions(poster);\n const busy = !error && !previewing && (status === \"loading\" || status === \"buffering\");\n // The preview shows once frames play; the cover stays until then.\n const shown = previewing && status === \"playing\";\n const fade = cn(\"transition-opacity duration-300 motion-reduce:transition-none\", shown && \"opacity-0\");\n const portal = fs.active && root ? root : undefined;\n const sections = settingsSections();\n\n function trackName(tr: PlayerTrack) {\n const name = tr.label || t(\"player.track\", { number: tr.index + 1 });\n return tr.forced ? t(\"player.forced\", { label: name }) : name;\n }\n function settingsSections(): MenuSection[] {\n const out: MenuSection[] = [];\n if (audio.list.length > 1)\n out.push({ key: \"audio\", label: t(\"player.audio\"), value: String(audio.selected), options: audio.list.map((x) => ({ value: String(x.index), label: trackName(x) })), onChange: (v) => selectAudio(Number(v)) });\n if (subtitles.list.length)\n out.push({\n key: \"subtitles\",\n label: t(\"player.subtitles\"),\n value: String(subtitles.selected),\n options: [{ value: \"-1\", label: t(\"player.subtitlesOff\") }, ...subtitles.list.map((x) => ({ value: String(x.index), label: trackName(x) }))],\n onChange: (v) => selectSubs(Number(v)),\n });\n if (quality.levels.length > 1) {\n const playing = quality.levels.find((l) => l.index === quality.current);\n out.push({\n key: \"quality\",\n label: t(\"player.quality\"),\n value: String(quality.selected),\n options: [\n ...[...quality.levels].reverse().map((l) => ({ value: String(l.index), label: qualityLabel(l.height) })),\n { value: \"-1\", label: playing && quality.selected === -1 ? t(\"player.autoCurrent\", { quality: qualityLabel(playing.height).split(\" \")[0]! }) : t(\"player.auto\") },\n ],\n onChange: (v) => selectQuality(Number(v)),\n });\n }\n out.push({\n key: \"speed\",\n label: t(\"player.speed\"),\n value: String(media.rate),\n options: PLAYBACK_SPEEDS.map((r) => ({ value: String(r), label: r === 1 ? t(\"player.normal\") : `${r}×` })),\n onChange: (v) => {\n if (video) video.playbackRate = Number(v);\n },\n });\n menuItems?.forEach((m, i) => {\n if (\"options\" in m) out.push({ key: `host-${i}`, label: m.label, value: m.value, options: m.options, onChange: m.onChange });\n });\n return out;\n }\n const actions = menuItems?.filter((m): m is Extract<PlayerMenuItem, { onSelect: () => void }> => \"onSelect\" in m);\n\n return (\n <ContentKitUiRoot\n appearance={appearance}\n className={cn(\n \"@container relative w-full touch-manipulation overflow-hidden bg-black text-white outline-none\",\n layout === \"fill\" ? \"size-full\" : !fs.active && \"rounded-lg\",\n started && !controlsShown && \"cursor-none\",\n className,\n )}\n style={{ ...frame, ...style }}\n data-ckui=\"video-player\"\n data-status={failed ? \"failed\" : pending ? \"pending\" : status}\n data-previewing={previewing ? \"\" : undefined}\n data-fullscreen={fs.active ? \"\" : undefined}\n data-controls={controlsShown ? \"\" : undefined}\n ref={setRoot}\n role=\"group\"\n aria-label={label ?? t(\"player.label\")}\n tabIndex={playable ? -1 : undefined}\n onPointerDown={(e) => (pointerType.current = e.pointerType || \"mouse\")}\n onPointerMove={(e) => e.pointerType === \"mouse\" && started && poke()}\n onPointerLeave={(e) => e.pointerType === \"mouse\" && !scrubbing && !menuOpen && hide()}\n onFocus={(e) => setKeyFocus(focusVisible(e.target))}\n onBlur={() => setKeyFocus(false)}\n >\n {failed ? (\n <Panel icon>{t(\"player.failed\")}</Panel>\n ) : pending || !base ? (\n <div className=\"absolute inset-0 flex items-center justify-center bg-muted p-6 text-foreground\">\n <EncodeProgress progress={progress} className=\"max-w-xs\" />\n </div>\n ) : (\n <>\n <video ref={videoRef} className=\"absolute inset-0 size-full object-contain\" playsInline preload=\"none\" crossOrigin={crossOrigin} aria-label={label} />\n {started && !error && <div data-ckui=\"surface\" className=\"absolute inset-0\" onClick={onSurfaceClick} onDoubleClick={onSurfaceDoubleClick} />}\n {!started && !error && (\n <>\n {typeof poster === \"string\" ? (\n <img alt=\"\" src={poster} decoding=\"async\" className={cn(\"pointer-events-none absolute inset-0 size-full object-contain\", fade)} />\n ) : posterOutputs.length ? (\n <RenditionImg outputs={posterOutputs} className={cn(\"pointer-events-none absolute inset-0 size-full object-contain\", fade)} />\n ) : (\n <SpriteFrame vtt={`${base}sprite.vtt`} xhrSetup={options.xhrSetup} className={fade} />\n )}\n <BigButton label={t(\"player.play\")} onClick={player.play} disabled={busy} className={fade}>\n {busy ? <Spinner /> : <HugeiconsIcon icon={PlayIcon} className=\"ml-1 size-7 fill-current\" strokeWidth={1.5} />}\n </BigButton>\n {duration ? (\n <span className=\"pointer-events-none absolute right-2 bottom-2 rounded bg-black/65 px-1.5 py-0.5 text-xs font-medium tabular-nums\">{formatDuration(duration)}</span>\n ) : null}\n </>\n )}\n {started && !error && media.ended && (\n <BigButton label={t(\"player.replay\")} onClick={toggle}>\n <HugeiconsIcon icon={Refresh01Icon} className=\"size-7\" strokeWidth={1.75} />\n </BigButton>\n )}\n <Captions cues={live ? cues : []} bottom={controlsShown ? \"4.75rem\" : \"1.25rem\"} />\n {started && busy && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center\">\n <span className=\"flex size-14 items-center justify-center rounded-full bg-black/45\">\n <Spinner />\n </span>\n </div>\n )}\n <SeekFlash flash={flash} />\n {started && !error && (\n <div\n data-ckui=\"controls\"\n data-ckui-noswipe=\"\"\n className={cn(\n \"pointer-events-none absolute inset-x-0 bottom-0 z-10 flex flex-col bg-linear-to-t from-black/75 via-black/35 to-transparent px-2 pt-12 pb-1 transition-opacity duration-200 motion-reduce:transition-none\",\n controlsShown ? \"opacity-100 *:pointer-events-auto\" : \"opacity-0\",\n )}\n >\n <SeekBar time={media.time} duration={dur} buffered={media.buffered} onSeek={seek} onScrub={(v) => setScrubbing(v !== null)} sprite={sprite} />\n <div className=\"flex items-center gap-0.5\">\n <ControlButton\n label={media.ended ? t(\"player.replay\") : media.paused ? t(\"player.resume\") : t(\"player.pause\")}\n shortcut=\"k\"\n icon={media.ended ? Refresh01Icon : media.paused ? PlayIcon : PauseIcon}\n onClick={toggle}\n data-ckui=\"play\"\n />\n <VolumeControl volume={media.volume} muted={media.muted} onVolume={setVolume} onMute={toggleMute} />\n <span className=\"ml-1 shrink-0 text-xs font-medium whitespace-nowrap text-white/90 tabular-nums\" data-ckui=\"time\">\n {clock(media.time)} / {clock(dur)}\n </span>\n <div className=\"min-w-0 flex-1\" />\n {subtitles.list.length > 0 && (\n <ControlButton label={t(\"player.subtitles\")} shortcut=\"c\" icon={ClosedCaptionIcon} aria-pressed={subtitles.selected >= 0} onClick={toggleCaptions} data-ckui=\"captions-toggle\" />\n )}\n {renderDownloads?.({ container: portal, className: playerButtonClass })}\n <SettingsMenu icon={Settings01Icon} label={t(\"player.settings\")} sections={sections} actions={actions} container={portal} onOpenChange={setMenuOpen} />\n {onMiniPlayer && <ControlButton className=\"@max-sm:hidden\" label={t(\"player.miniPlayer\")} shortcut=\"i\" icon={PictureInPictureOnIcon} onClick={openMini} data-ckui=\"mini-player-open\" />}\n {pip.supported && (\n <ControlButton\n className=\"@max-md:hidden\"\n label={pip.active ? t(\"player.exitPip\") : t(\"player.pip\")}\n icon={pip.active ? PictureInPictureExitIcon : PictureInPicture01Icon}\n onClick={pip.toggle}\n data-ckui=\"pip\"\n />\n )}\n {onTheaterChange && (\n <ControlButton\n className=\"max-lg:hidden\"\n label={t(\"player.theater\")}\n shortcut=\"t\"\n icon={RectangularIcon}\n aria-pressed={!!theater}\n onClick={toggleTheater}\n data-ckui=\"theater\"\n />\n )}\n {fs.supported && (\n <ControlButton\n label={fs.active ? t(\"player.exitFullscreen\") : t(\"player.fullscreen\")}\n shortcut=\"f\"\n icon={fs.active ? ArrowShrink02Icon : FullScreenIcon}\n onClick={fs.toggle}\n data-ckui=\"fullscreen\"\n />\n )}\n </div>\n </div>\n )}\n <span className=\"sr-only\" aria-live=\"polite\">\n {busy ? t(\"player.loading\") : \"\"}\n </span>\n {error && (\n <Panel icon code={error.code} onRetry={player.retry}>\n {t(`player.errors.${error.kind}`)}\n </Panel>\n )}\n </>\n )}\n </ContentKitUiRoot>\n );\n}\n\nfunction focusVisible(el: EventTarget) {\n try {\n return el instanceof Element && el.matches(\":focus-visible\") && !!el.closest(\"[data-ckui=controls]\");\n } catch {\n return false;\n }\n}\n\nfunction BigButton({ label, onClick, disabled, className, children }: { label: string; onClick: () => void; disabled?: boolean; className?: string; children: ReactNode }) {\n return (\n <button\n type=\"button\"\n className=\"absolute inset-0 z-[7] flex items-center justify-center outline-none focus-visible:[&>span]:ring-4 focus-visible:[&>span]:ring-white/60\"\n onClick={onClick}\n aria-label={label}\n disabled={disabled}\n >\n <span className={cn(\"flex size-16 items-center justify-center rounded-full bg-black/55 shadow-lg backdrop-blur-sm transition motion-safe:hover:scale-105\", className)}>{children}</span>\n </button>\n );\n}\n\n/** A preview's start: the given second, else 10% in, kept a second before the end. */\nexport function previewStartAt(start: number | undefined, duration: number | undefined): number {\n const d = duration ?? 0;\n const t = start ?? d * 0.1;\n return Math.max(0, d > 1 ? Math.min(t, d - 1) : 0);\n}\n\n/** \"2160p 4K\", \"1080p HD\", \"720p\": a rung by its short side. */\nexport function qualityLabel(height: number): string {\n return `${height}p${height >= 2160 ? \" 4K\" : height === 1080 ? \" HD\" : \"\"}`;\n}\n\nfunction Panel({ children, icon, code, onRetry }: { children: string; icon?: boolean; code?: string; onRetry?: () => void }) {\n const { t } = useMessages();\n return (\n <div role=\"alert\" data-ckui=\"player-error\" data-ckui-noswipe=\"\" className=\"absolute inset-0 z-20 flex flex-col items-center justify-center gap-3 bg-black/80 p-6 text-center\">\n {icon && <HugeiconsIcon icon={AlertCircleIcon} className=\"size-7 text-white/80\" strokeWidth={1.75} />}\n <p className=\"max-w-sm text-sm font-medium text-balance\">{children}</p>\n {onRetry && (\n <Button size=\"sm\" variant=\"secondary\" onClick={onRetry}>\n <HugeiconsIcon icon={Refresh01Icon} data-icon=\"inline-start\" />\n {t(\"player.retry\")}\n </Button>\n )}\n {code && <p className=\"font-mono text-[11px] text-white/55\">{t(\"player.code\", { code })}</p>}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"video-player.js","names":[],"sources":["../../src/components/video-player.tsx"],"sourcesContent":["import {\n AlertCircleIcon,\n ArrowShrink02Icon,\n ClosedCaptionIcon,\n FullScreenIcon,\n PauseIcon,\n PictureInPicture01Icon,\n PictureInPictureExitIcon,\n PictureInPictureOnIcon,\n PlayIcon,\n RectangularIcon,\n Refresh01Icon,\n Settings01Icon,\n} from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useCallback, useEffect, useRef, useState, type CSSProperties, type MouseEvent, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport { formatDuration } from \"../client/gallery.js\";\nimport type { PlaybackError } from \"../client/playback.js\";\nimport {\n JUMP_SEEK,\n PLAYBACK_SPEEDS,\n PLAYER_VOLUME_KEY,\n nextSpeed,\n playerKeyAction,\n resumeAt,\n writeVolume,\n type PlayerAction,\n type PlayerTrack,\n} from \"../client/player.js\";\nimport { useHlsPlayer, type HlsPlayerOptions } from \"../react/gallery.js\";\nimport { useInlinePreview } from \"../react/inline-preview.js\";\nimport { useActiveCues, useFullscreen, useMediaState, usePictureInPicture, useProgressReports, useSprite, type PlaybackProgress } from \"../react/player.js\";\nimport { useLanguageName, useMessages } from \"../i18n/context.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\nimport { RenditionImg } from \"./rendition-img.js\";\nimport { publicRenditions, type PublicPreset } from \"../client/public.js\";\nimport type { EncodeProgress as Progress } from \"../client/generated/wire.js\";\nimport { EncodeProgress } from \"./encode-progress.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Captions, ControlButton, SeekBar, SeekFlash, SettingsMenu, Spinner, VolumeControl, clock, playerButtonClass, type MenuSection, type SeekFlashState } from \"./player-controls.js\";\n\ntype XhrSetup = HlsPlayerOptions[\"xhrSetup\"];\n\n/** The first frame of a video's seek sprite (sprite.vtt), fitted like object-fit. */\nexport function SpriteFrame({ vtt, xhrSetup, fit = \"contain\", className }: { vtt: string; xhrSetup?: XhrSetup; fit?: \"contain\" | \"cover\"; className?: string }) {\n const sprite = useSprite(vtt, xhrSetup);\n const cue = sprite?.cues[0];\n if (!sprite || !cue) return null;\n return (\n <svg\n aria-hidden\n className={cn(\"pointer-events-none absolute inset-0 size-full\", className)}\n viewBox={`${cue.x} ${cue.y} ${cue.w} ${cue.h}`}\n preserveAspectRatio={fit === \"cover\" ? \"xMidYMid slice\" : \"xMidYMid meet\"}\n data-ckui=\"sprite-frame\"\n >\n <image href={cue.url} width={sprite.width} height={sprite.height} />\n </svg>\n );\n}\n\ntype At<T> = T extends unknown ? T & { time: number } : never;\n\n/** Playback as it happens, for analytics; never during an inline preview. */\nexport type PlayerEvent = At<\n | { type: \"play\" | \"playing\" | \"pause\" | \"waiting\" | \"ended\" }\n | { type: \"seek\"; from: number }\n | { type: \"rate\"; rate: number }\n | { type: \"volume\"; volume: number; muted: boolean }\n /** The viewer's quality choice; height null is Auto. */\n | { type: \"quality\"; height: number | null }\n | { type: \"audio\"; track: PlayerTrack }\n | { type: \"subtitles\"; track: PlayerTrack | null }\n | { type: \"fullscreen\" | \"pip\" | \"theater\"; on: boolean }\n | { type: \"error\"; error: PlaybackError }\n>;\n\n/** Everything a VideoMiniPlayer needs to carry on where the player stopped. */\nexport interface PlayerHandoff {\n base: string;\n time: number;\n playing: boolean;\n width?: number;\n height?: number;\n duration?: number;\n poster?: string | PublicPreset | null;\n audioLanguage?: string;\n subtitleLanguage?: string | null;\n}\n\n/** A host entry in the settings menu: a choice (e.g. version) or an action (e.g. report a problem). */\nexport type PlayerMenuItem =\n | { label: string; value: string; options: readonly { value: string; label: string }[]; onChange: (value: string) => void }\n | { label: string; onSelect: () => void };\n\nexport interface PlayerSlotContext {\n /** Where popups must portal to stay visible: the player while fullscreen, else undefined (the body). */\n container?: HTMLElement;\n /** The control buttons' class. */\n className: string;\n}\n\nexport interface VideoPlayerProps extends Omit<HlsPlayerOptions, \"src\"> {\n /** The ladder's HLS folder (client.media.hlsBase: {media}/{kind}/{id}/hls/{dir}): master.m3u8 and sprite.vtt resolve under it. */\n base?: string | null;\n /** Shown until playback starts: the poster's public preset or a URL; default the first sprite frame. */\n poster?: string | PublicPreset | null;\n /** The video's size (read API w/h): the box is reserved before anything loads; default the decoded frame's. */\n width?: number;\n height?: number;\n duration?: number;\n /** A pending encode (an editor read's `pending` and `progress`): shows its progress instead of a player. */\n pending?: boolean;\n progress?: Progress | null;\n /** Why the video cannot be encoded (an editor read's `failed.message`). */\n failed?: string;\n /**\n * `frame` is as wide as its column allows at the video's aspect, never\n * taller than `maxHeight`; `fill` fills a sized parent (a carousel slide).\n */\n layout?: \"frame\" | \"fill\";\n maxHeight?: string;\n /** Preview muted inline before play (hover, or in view on touch); default the provider's. */\n inlinePreview?: boolean;\n /** Where the preview starts, seconds; default 10% in. */\n previewStart?: number;\n /** Shortcuts while focus is in the player (default), page-wide (a watch page: one such player per page), or none. */\n keyboard?: \"focus\" | \"global\" | false;\n /** Resume points and watch time: every `progressInterval` of playback, and on pause, seek, end, page hide and unload. */\n onProgress?: (progress: PlaybackProgress) => void;\n /** Milliseconds. Default 10000. */\n progressInterval?: number;\n onEvent?: (event: PlayerEvent) => void;\n /** Theater mode is the host's layout; the button shows with onTheaterChange. */\n theater?: boolean;\n onTheaterChange?: (theater: boolean) => void;\n /** Shows the mini-player button: the player pauses and hands over where it was. */\n onMiniPlayer?: (handoff: PlayerHandoff) => void;\n /** A control-bar slot for the host's downloads. */\n renderDownloads?: (ctx: PlayerSlotContext) => ReactNode;\n /** Host entries in the settings menu, after its own. */\n menuItems?: readonly PlayerMenuItem[];\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n label?: string;\n className?: string;\n style?: CSSProperties;\n appearance?: ContentKitUiAppearance;\n}\n\nconst CONTROLS_IDLE_MS = 2500;\nconst DOUBLE_TAP_MS = 300;\nconst TAP_SEEK_CONTINUE_MS = 700;\nconst SEEK_FLASH_MS = 650;\n\nconst TEXT_ENTRY =\n 'textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=textbox], [role=combobox], [role=searchbox], input:not([type=range]):not([type=button]):not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=reset])';\nconst MENU = \"[role=menu], [role=menuitem], [role=menuitemradio], [role=menuitemcheckbox], [role=listbox], [role=option]\";\nconst OUTSIDE_INTERACTIVE = \"a, button, input, [role=button], [role=dialog], [role=alertdialog]\";\n\n/** A track's name: its playlist name, or its language's name when the name is only the language code. */\nexport function trackLabel(tr: Pick<PlayerTrack, \"label\" | \"lang\">, languageName: (code: string) => string): string {\n const code = tr.lang && (!tr.label || tr.label.toLowerCase() === tr.lang.toLowerCase()) ? tr.lang : undefined;\n return code ? languageName(code) : tr.label;\n}\n\n/**\n * Whether a shortcut key belongs to the player: never while typing or in a\n * menu, not the arrows on a slider (it steps itself), and outside the\n * player (page-wide shortcuts) not on another control.\n */\nexport function keyAllowed(target: EventTarget | null, key: string, root: Element): boolean {\n if (!(target instanceof Element)) return true;\n if (target.closest(TEXT_ENTRY) || target.closest(MENU)) return false;\n if (target.closest(\"input[type=range], [role=slider]\") && /^(Arrow|Page|Home$|End$)/.test(key)) return false;\n return root.contains(target) || !target.closest(OUTSIDE_INTERACTIVE);\n}\n\n// Space on one of the player's buttons is play/pause, not a click on the button last used.\nconst spaceOnButton = (target: EventTarget | null, root: Element) =>\n target instanceof Element && root.contains(target) && !!target.closest(\"button\") && !target.closest(MENU);\n\n/**\n * An HLS player that never spins forever: poster and play control, its own\n * controls (seek with sprite preview, volume, subtitles, audio, quality,\n * speed, picture-in-picture, theater, fullscreen, mini player), shortcuts,\n * touch gestures, resume and progress reports, and a specific error with\n * Retry and a support code.\n */\nexport function VideoPlayer({\n base,\n poster,\n width,\n height,\n duration,\n pending,\n progress,\n failed,\n layout = \"frame\",\n maxHeight = \"80svh\",\n inlinePreview,\n previewStart,\n keyboard = \"focus\",\n onProgress,\n progressInterval = 10_000,\n onEvent,\n theater,\n onTheaterChange,\n onMiniPlayer,\n renderDownloads,\n menuItems,\n crossOrigin,\n label,\n className,\n style,\n appearance,\n startAt,\n ...options\n}: VideoPlayerProps) {\n const { t } = useMessages();\n const languageName = useLanguageName();\n const playable = !!base && !pending && !failed;\n const src = playable ? `${base}master.m3u8` : null;\n const start = resumeAt(startAt, duration);\n const player = useHlsPlayer({ ...options, src, startAt: start });\n const { status, error, started, previewing, audio, subtitles, quality } = player;\n const [root, setRoot] = useState<HTMLDivElement | null>(null);\n const [video, setVideo] = useState<HTMLVideoElement | null>(null);\n const attach = player.ref;\n const videoRef = useCallback(\n (el: HTMLVideoElement | null) => {\n attach(el);\n setVideo(el);\n },\n [attach],\n );\n useInlinePreview({\n setting: inlinePreview,\n available: playable && !started && !error && options.active !== false && !options.autoPlay,\n target: root,\n playing: started && status === \"playing\",\n start: () => player.preview(previewStartAt(previewStart, duration)),\n stop: player.unload,\n });\n const media = useMediaState(video);\n const fs = useFullscreen(root, video);\n const pip = usePictureInPicture(video);\n const cues = useActiveCues(video);\n const sprite = useSprite(started && base ? `${base}sprite.vtt` : null, options.xhrSetup);\n const live = !previewing && started;\n useProgressReports(video, { enabled: live, source: live ? src : null, interval: progressInterval, onProgress });\n\n // Events.\n const emit = useRef(onEvent);\n emit.current = onEvent;\n const sending = useRef(false);\n sending.current = !previewing && status !== \"idle\";\n const send = useCallback((e: { type: string; [k: string]: unknown }, always = false) => {\n if ((always || sending.current) && emit.current) emit.current({ ...e, time: video?.currentTime ?? 0 } as PlayerEvent);\n }, [video]);\n useEffect(() => {\n if (!video) return;\n let from = 0;\n const h: Record<string, () => void> = {\n play: () => send({ type: \"play\" }),\n playing: () => send({ type: \"playing\" }),\n pause: () => !video.ended && send({ type: \"pause\" }),\n waiting: () => send({ type: \"waiting\" }),\n ended: () => send({ type: \"ended\" }),\n timeupdate: () => {\n if (!video.seeking) from = video.currentTime;\n },\n seeked: () => {\n send({ type: \"seek\", from });\n from = video.currentTime;\n },\n ratechange: () => send({ type: \"rate\", rate: video.playbackRate }),\n };\n for (const [k, f] of Object.entries(h)) video.addEventListener(k, f);\n return () => {\n for (const [k, f] of Object.entries(h)) video.removeEventListener(k, f);\n };\n }, [video, send]);\n useEffect(() => {\n if (error && !previewing) send({ type: \"error\", error }, true);\n }, [error, previewing, send]);\n const was = useRef({ fs: false, pip: false });\n useEffect(() => {\n if (was.current.fs !== fs.active) send({ type: \"fullscreen\", on: fs.active });\n if (was.current.pip !== pip.active) send({ type: \"pip\", on: pip.active });\n was.current = { fs: fs.active, pip: pip.active };\n }, [fs.active, pip.active, send]);\n\n // A new resume point for the playing source seeks to it.\n const lastStart = useRef(start);\n useEffect(() => {\n if (lastStart.current === start) return;\n lastStart.current = start;\n if (video && started) video.currentTime = start;\n }, [start, video, started]);\n\n // Controls show on pointer movement and hide after a pause in it while playing.\n const [poked, setPoked] = useState(false);\n const idle = useRef<ReturnType<typeof setTimeout>>(undefined);\n const poke = useCallback(() => {\n setPoked(true);\n clearTimeout(idle.current);\n idle.current = setTimeout(() => setPoked(false), CONTROLS_IDLE_MS);\n }, []);\n const hide = useCallback(() => {\n clearTimeout(idle.current);\n setPoked(false);\n }, []);\n useEffect(() => () => clearTimeout(idle.current), []);\n useEffect(() => {\n if (started) poke();\n }, [started, poke]);\n const [menuOpen, setMenuOpen] = useState(false);\n const [scrubbing, setScrubbing] = useState(false);\n const [keyFocus, setKeyFocus] = useState(false);\n const controlsShown = started && !error && (poked || media.paused || media.ended || menuOpen || scrubbing || keyFocus);\n\n const [flash, setFlash] = useState<SeekFlashState | null>(null);\n const flashTimer = useRef<ReturnType<typeof setTimeout>>(undefined);\n const flashSeek = useCallback((direction: -1 | 1, seconds: number) => {\n const continuing = flashTimer.current !== undefined;\n clearTimeout(flashTimer.current);\n setFlash((prev) => ({ direction, seconds: continuing && prev?.direction === direction ? prev.seconds + seconds : seconds }));\n flashTimer.current = setTimeout(() => {\n setFlash(null);\n flashTimer.current = undefined;\n }, SEEK_FLASH_MS);\n }, []);\n useEffect(() => () => clearTimeout(flashTimer.current), []);\n\n const volumeKey = options.volumeKey === undefined ? PLAYER_VOLUME_KEY : options.volumeKey;\n const dur = media.duration || duration || 0;\n const seek = (to: number) => {\n if (video) video.currentTime = Math.min(dur || to, Math.max(0, to));\n };\n const seekBy = (seconds: number) => {\n if (!video) return;\n seek(video.currentTime + seconds);\n flashSeek(seconds < 0 ? -1 : 1, Math.abs(seconds));\n };\n const toggle = () => {\n if (!video) return;\n if (!started || video.ended) {\n if (video.ended) video.currentTime = 0;\n player.play();\n } else if (video.paused) player.play();\n else video.pause();\n };\n const setVolume = (v: number) => {\n if (!video) return;\n video.volume = Math.min(1, Math.max(0, v));\n if (video.volume > 0 && video.muted) video.muted = false;\n writeVolume(volumeKey, { volume: video.volume, muted: video.muted });\n send({ type: \"volume\", volume: video.volume, muted: video.muted });\n };\n const toggleMute = () => {\n if (!video) return;\n video.muted = !video.muted;\n if (!video.muted && video.volume === 0) video.volume = 1;\n writeVolume(volumeKey, { volume: video.volume, muted: video.muted });\n send({ type: \"volume\", volume: video.volume, muted: video.muted });\n };\n const selectAudio = (i: number) => {\n audio.select(i);\n const track = audio.list[i];\n if (track) send({ type: \"audio\", track });\n };\n const lastSub = useRef(-1);\n if (subtitles.selected >= 0) lastSub.current = subtitles.selected;\n const selectSubs = (i: number) => {\n subtitles.select(i);\n send({ type: \"subtitles\", track: subtitles.list[i] ?? null });\n };\n const toggleCaptions = () => selectSubs(subtitles.selected >= 0 ? -1 : lastSub.current >= 0 ? lastSub.current : 0);\n const selectQuality = (i: number) => {\n quality.select(i);\n send({ type: \"quality\", height: quality.levels.find((l) => l.index === i)?.height ?? null });\n };\n const toggleTheater = () => {\n onTheaterChange?.(!theater);\n send({ type: \"theater\", on: !theater });\n };\n const openMini = () => {\n if (!onMiniPlayer || !base || !video) return;\n const a = audio.list[audio.selected];\n const s = subtitles.list[subtitles.selected];\n const handoff: PlayerHandoff = {\n base,\n time: video.currentTime,\n playing: !video.paused && !video.ended,\n width: width ?? (video.videoWidth || undefined),\n height: height ?? (video.videoHeight || undefined),\n duration: dur || undefined,\n poster,\n audioLanguage: a?.lang,\n subtitleLanguage: s?.lang ?? null,\n };\n video.pause();\n if (fs.active) fs.toggle();\n onMiniPlayer(handoff);\n };\n\n const run = (a: PlayerAction): boolean => {\n if (!video) return false;\n if (!started && a.type !== \"toggle\") return false;\n switch (a.type) {\n case \"toggle\":\n toggle();\n break;\n case \"seekBy\":\n seekBy(a.seconds);\n break;\n case \"seekTo\":\n if (!dur) return false;\n seek(dur * a.fraction);\n break;\n case \"volumeBy\":\n setVolume((video.muted ? 0 : video.volume) + a.delta);\n break;\n case \"mute\":\n toggleMute();\n break;\n case \"captions\":\n if (!subtitles.list.length) return false;\n toggleCaptions();\n break;\n case \"fullscreen\":\n if (!fs.supported) return false;\n fs.toggle();\n break;\n case \"theater\":\n if (!onTheaterChange) return false;\n toggleTheater();\n break;\n case \"miniPlayer\":\n if (!onMiniPlayer) return false;\n openMini();\n break;\n case \"speed\":\n video.playbackRate = nextSpeed(video.playbackRate, a.step);\n break;\n }\n if (started) poke();\n return true;\n };\n const runRef = useRef(run);\n runRef.current = run;\n const active = options.active !== false;\n useEffect(() => {\n if (!keyboard || !root || !active) return;\n const on: EventTarget = keyboard === \"global\" ? document : root;\n const down = (e: Event) => {\n const k = e as KeyboardEvent;\n if (k.defaultPrevented) return;\n const action = playerKeyAction(k);\n if (!action || !keyAllowed(k.target, k.key, root) || !runRef.current(action)) return;\n k.preventDefault();\n };\n const up = (e: Event) => {\n const k = e as KeyboardEvent;\n if (k.key === \" \" && spaceOnButton(k.target, root)) k.preventDefault();\n };\n on.addEventListener(\"keydown\", down);\n on.addEventListener(\"keyup\", up);\n return () => {\n on.removeEventListener(\"keydown\", down);\n on.removeEventListener(\"keyup\", up);\n };\n }, [keyboard, root, active]);\n\n // Mouse: click plays and pauses, double click is fullscreen. Touch: a tap\n // shows or hides the controls; double taps on either side seek 10 s, and\n // taps that keep coming keep seeking.\n const pointerType = useRef(\"mouse\");\n const lastTap = useRef<{ at: number; side: -1 | 1 } | null>(null);\n const tapSeekUntil = useRef(0);\n const onSurfaceClick = (e: MouseEvent<HTMLDivElement>) => {\n if (pointerType.current === \"mouse\") {\n toggle();\n poke();\n return;\n }\n const r = e.currentTarget.getBoundingClientRect();\n const x = r.width ? (e.clientX - r.left) / r.width : 0.5;\n const side = x < 0.4 ? -1 : x > 0.6 ? 1 : null;\n const now = Date.now();\n const last = lastTap.current;\n lastTap.current = side ? { at: now, side } : null;\n if (side && last?.side === side && (now < tapSeekUntil.current || now - last.at <= DOUBLE_TAP_MS)) {\n tapSeekUntil.current = now + TAP_SEEK_CONTINUE_MS;\n seekBy(side * JUMP_SEEK);\n return;\n }\n if (controlsShown && !media.paused) hide();\n else poke();\n };\n const onSurfaceDoubleClick = () => {\n if (Date.now() >= tapSeekUntil.current && fs.supported) fs.toggle();\n };\n\n const aspect = width && height ? width / height : (media.aspect ?? 16 / 9);\n const frame: CSSProperties = fs.active\n ? { width: \"100%\", height: \"100%\", borderRadius: 0 }\n : layout === \"frame\"\n ? { aspectRatio: String(aspect), width: `min(100%, calc(${maxHeight} * ${aspect}))`, marginInline: \"auto\" }\n : {};\n const posterOutputs = typeof poster === \"string\" ? [] : publicRenditions(poster);\n const busy = !error && !previewing && (status === \"loading\" || status === \"buffering\");\n // The preview shows once frames play; the cover stays until then.\n const shown = previewing && status === \"playing\";\n const fade = cn(\"transition-opacity duration-300 motion-reduce:transition-none\", shown && \"opacity-0\");\n const portal = fs.active && root ? root : undefined;\n const sections = settingsSections();\n\n function trackName(tr: PlayerTrack) {\n const name = trackLabel(tr, languageName) || t(\"player.track\", { number: tr.index + 1 });\n return tr.forced ? t(\"player.forced\", { label: name }) : name;\n }\n function settingsSections(): MenuSection[] {\n const out: MenuSection[] = [];\n if (audio.list.length > 1)\n out.push({ key: \"audio\", label: t(\"player.audio\"), value: String(audio.selected), options: audio.list.map((x) => ({ value: String(x.index), label: trackName(x) })), onChange: (v) => selectAudio(Number(v)) });\n if (subtitles.list.length)\n out.push({\n key: \"subtitles\",\n label: t(\"player.subtitles\"),\n value: String(subtitles.selected),\n options: [{ value: \"-1\", label: t(\"player.subtitlesOff\") }, ...subtitles.list.map((x) => ({ value: String(x.index), label: trackName(x) }))],\n onChange: (v) => selectSubs(Number(v)),\n });\n if (quality.levels.length > 1) {\n const playing = quality.levels.find((l) => l.index === quality.current);\n out.push({\n key: \"quality\",\n label: t(\"player.quality\"),\n value: String(quality.selected),\n options: [\n ...[...quality.levels].reverse().map((l) => ({ value: String(l.index), label: qualityLabel(l.height) })),\n { value: \"-1\", label: playing && quality.selected === -1 ? t(\"player.autoCurrent\", { quality: qualityLabel(playing.height).split(\" \")[0]! }) : t(\"player.auto\") },\n ],\n onChange: (v) => selectQuality(Number(v)),\n });\n }\n out.push({\n key: \"speed\",\n label: t(\"player.speed\"),\n value: String(media.rate),\n options: PLAYBACK_SPEEDS.map((r) => ({ value: String(r), label: r === 1 ? t(\"player.normal\") : `${r}×` })),\n onChange: (v) => {\n if (video) video.playbackRate = Number(v);\n },\n });\n menuItems?.forEach((m, i) => {\n if (\"options\" in m) out.push({ key: `host-${i}`, label: m.label, value: m.value, options: m.options, onChange: m.onChange });\n });\n return out;\n }\n const actions = menuItems?.filter((m): m is Extract<PlayerMenuItem, { onSelect: () => void }> => \"onSelect\" in m);\n\n return (\n <ContentKitUiRoot\n appearance={appearance}\n className={cn(\n \"@container relative w-full touch-manipulation overflow-hidden bg-black text-white outline-none\",\n layout === \"fill\" ? \"size-full\" : !fs.active && \"rounded-lg\",\n started && !controlsShown && \"cursor-none\",\n className,\n )}\n style={{ ...frame, ...style }}\n data-ckui=\"video-player\"\n data-status={failed ? \"failed\" : pending ? \"pending\" : status}\n data-previewing={previewing ? \"\" : undefined}\n data-fullscreen={fs.active ? \"\" : undefined}\n data-controls={controlsShown ? \"\" : undefined}\n ref={setRoot}\n role=\"group\"\n aria-label={label ?? t(\"player.label\")}\n tabIndex={playable ? -1 : undefined}\n onPointerDown={(e) => (pointerType.current = e.pointerType || \"mouse\")}\n onPointerMove={(e) => e.pointerType === \"mouse\" && started && poke()}\n onPointerLeave={(e) => e.pointerType === \"mouse\" && !scrubbing && !menuOpen && hide()}\n onFocus={(e) => setKeyFocus(focusVisible(e.target))}\n onBlur={() => setKeyFocus(false)}\n >\n {failed ? (\n <Panel icon>{t(\"player.failed\")}</Panel>\n ) : pending || !base ? (\n <div className=\"absolute inset-0 flex items-center justify-center bg-muted p-6 text-foreground\">\n <EncodeProgress progress={progress} className=\"max-w-xs\" />\n </div>\n ) : (\n <>\n <video ref={videoRef} className=\"absolute inset-0 size-full object-contain\" playsInline preload=\"none\" crossOrigin={crossOrigin} aria-label={label} />\n {started && !error && <div data-ckui=\"surface\" className=\"absolute inset-0\" onClick={onSurfaceClick} onDoubleClick={onSurfaceDoubleClick} />}\n {!started && !error && (\n <>\n {typeof poster === \"string\" ? (\n <img alt=\"\" src={poster} decoding=\"async\" className={cn(\"pointer-events-none absolute inset-0 size-full object-contain\", fade)} />\n ) : posterOutputs.length ? (\n <RenditionImg outputs={posterOutputs} className={cn(\"pointer-events-none absolute inset-0 size-full object-contain\", fade)} />\n ) : (\n <SpriteFrame vtt={`${base}sprite.vtt`} xhrSetup={options.xhrSetup} className={fade} />\n )}\n <BigButton label={t(\"player.play\")} onClick={player.play} disabled={busy} className={fade}>\n {busy ? <Spinner /> : <HugeiconsIcon icon={PlayIcon} className=\"ml-1 size-7 fill-current\" strokeWidth={1.5} />}\n </BigButton>\n {duration ? (\n <span className=\"pointer-events-none absolute right-2 bottom-2 rounded bg-black/65 px-1.5 py-0.5 text-xs font-medium tabular-nums\">{formatDuration(duration)}</span>\n ) : null}\n </>\n )}\n {started && !error && media.ended && (\n <BigButton label={t(\"player.replay\")} onClick={toggle}>\n <HugeiconsIcon icon={Refresh01Icon} className=\"size-7\" strokeWidth={1.75} />\n </BigButton>\n )}\n <Captions cues={live ? cues : []} bottom={controlsShown ? \"4.75rem\" : \"1.25rem\"} />\n {started && busy && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center\">\n <span className=\"flex size-14 items-center justify-center rounded-full bg-black/45\">\n <Spinner />\n </span>\n </div>\n )}\n <SeekFlash flash={flash} />\n {started && !error && (\n <div\n data-ckui=\"controls\"\n data-ckui-noswipe=\"\"\n className={cn(\n \"pointer-events-none absolute inset-x-0 bottom-0 z-10 flex flex-col bg-linear-to-t from-black/75 via-black/35 to-transparent px-2 pt-12 pb-1 transition-opacity duration-200 motion-reduce:transition-none\",\n controlsShown ? \"opacity-100 *:pointer-events-auto\" : \"opacity-0\",\n )}\n >\n <SeekBar time={media.time} duration={dur} buffered={media.buffered} onSeek={seek} onScrub={(v) => setScrubbing(v !== null)} sprite={sprite} />\n <div className=\"flex items-center gap-0.5\">\n <ControlButton\n label={media.ended ? t(\"player.replay\") : media.paused ? t(\"player.resume\") : t(\"player.pause\")}\n shortcut=\"k\"\n icon={media.ended ? Refresh01Icon : media.paused ? PlayIcon : PauseIcon}\n onClick={toggle}\n data-ckui=\"play\"\n />\n <VolumeControl volume={media.volume} muted={media.muted} onVolume={setVolume} onMute={toggleMute} />\n <span className=\"ml-1 shrink-0 text-xs font-medium whitespace-nowrap text-white/90 tabular-nums\" data-ckui=\"time\">\n {clock(media.time)} / {clock(dur)}\n </span>\n <div className=\"min-w-0 flex-1\" />\n {subtitles.list.length > 0 && (\n <ControlButton label={t(\"player.subtitles\")} shortcut=\"c\" icon={ClosedCaptionIcon} aria-pressed={subtitles.selected >= 0} onClick={toggleCaptions} data-ckui=\"captions-toggle\" />\n )}\n {renderDownloads?.({ container: portal, className: playerButtonClass })}\n <SettingsMenu icon={Settings01Icon} label={t(\"player.settings\")} sections={sections} actions={actions} container={portal} onOpenChange={setMenuOpen} />\n {onMiniPlayer && <ControlButton className=\"@max-sm:hidden\" label={t(\"player.miniPlayer\")} shortcut=\"i\" icon={PictureInPictureOnIcon} onClick={openMini} data-ckui=\"mini-player-open\" />}\n {pip.supported && (\n <ControlButton\n className=\"@max-md:hidden\"\n label={pip.active ? t(\"player.exitPip\") : t(\"player.pip\")}\n icon={pip.active ? PictureInPictureExitIcon : PictureInPicture01Icon}\n onClick={pip.toggle}\n data-ckui=\"pip\"\n />\n )}\n {onTheaterChange && (\n <ControlButton\n className=\"max-lg:hidden\"\n label={t(\"player.theater\")}\n shortcut=\"t\"\n icon={RectangularIcon}\n aria-pressed={!!theater}\n onClick={toggleTheater}\n data-ckui=\"theater\"\n />\n )}\n {fs.supported && (\n <ControlButton\n label={fs.active ? t(\"player.exitFullscreen\") : t(\"player.fullscreen\")}\n shortcut=\"f\"\n icon={fs.active ? ArrowShrink02Icon : FullScreenIcon}\n onClick={fs.toggle}\n data-ckui=\"fullscreen\"\n />\n )}\n </div>\n </div>\n )}\n <span className=\"sr-only\" aria-live=\"polite\">\n {busy ? t(\"player.loading\") : \"\"}\n </span>\n {error && (\n <Panel icon code={error.code} onRetry={player.retry}>\n {t(`player.errors.${error.kind}`)}\n </Panel>\n )}\n </>\n )}\n </ContentKitUiRoot>\n );\n}\n\nfunction focusVisible(el: EventTarget) {\n try {\n return el instanceof Element && el.matches(\":focus-visible\") && !!el.closest(\"[data-ckui=controls]\");\n } catch {\n return false;\n }\n}\n\nfunction BigButton({ label, onClick, disabled, className, children }: { label: string; onClick: () => void; disabled?: boolean; className?: string; children: ReactNode }) {\n return (\n <button\n type=\"button\"\n className=\"absolute inset-0 z-[7] flex items-center justify-center outline-none focus-visible:[&>span]:ring-4 focus-visible:[&>span]:ring-white/60\"\n onClick={onClick}\n aria-label={label}\n disabled={disabled}\n >\n <span className={cn(\"flex size-16 items-center justify-center rounded-full bg-black/55 shadow-lg backdrop-blur-sm transition motion-safe:hover:scale-105\", className)}>{children}</span>\n </button>\n );\n}\n\n/** A preview's start: the given second, else 10% in, kept a second before the end. */\nexport function previewStartAt(start: number | undefined, duration: number | undefined): number {\n const d = duration ?? 0;\n const t = start ?? d * 0.1;\n return Math.max(0, d > 1 ? Math.min(t, d - 1) : 0);\n}\n\n/** \"2160p 4K\", \"1080p HD\", \"720p\": a rung by its short side. */\nexport function qualityLabel(height: number): string {\n return `${height}p${height >= 2160 ? \" 4K\" : height === 1080 ? \" HD\" : \"\"}`;\n}\n\nfunction Panel({ children, icon, code, onRetry }: { children: string; icon?: boolean; code?: string; onRetry?: () => void }) {\n const { t } = useMessages();\n return (\n <div role=\"alert\" data-ckui=\"player-error\" data-ckui-noswipe=\"\" className=\"absolute inset-0 z-20 flex flex-col items-center justify-center gap-3 bg-black/80 p-6 text-center\">\n {icon && <HugeiconsIcon icon={AlertCircleIcon} className=\"size-7 text-white/80\" strokeWidth={1.75} />}\n <p className=\"max-w-sm text-sm font-medium text-balance\">{children}</p>\n {onRetry && (\n <Button size=\"sm\" variant=\"secondary\" onClick={onRetry}>\n <HugeiconsIcon icon={Refresh01Icon} data-icon=\"inline-start\" />\n {t(\"player.retry\")}\n </Button>\n )}\n {code && <p className=\"font-mono text-[11px] text-white/55\">{t(\"player.code\", { code })}</p>}\n </div>\n );\n}\n"],"mappings":"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"}
|
package/dist/i18n/context.d.ts
CHANGED
|
@@ -2,3 +2,5 @@ import { Translator } from './messages.js';
|
|
|
2
2
|
export declare const MessagesContext: import('react').Context<Translator>;
|
|
3
3
|
/** English defaults when rendered outside a `ContentKitUiProvider`. */
|
|
4
4
|
export declare function useMessages(): Translator;
|
|
5
|
+
/** A language's name in the UI's language ("ja" → "Japanese"). */
|
|
6
|
+
export declare function useLanguageName(): (code: string) => string;
|
package/dist/i18n/context.js
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
import { createTranslator as e, defaultMessages as t } from "./messages.js";
|
|
2
|
-
import { createContext as n, useContext as r } from "react";
|
|
2
|
+
import { createContext as n, useContext as r, useMemo as i } from "react";
|
|
3
3
|
//#region src/i18n/context.ts
|
|
4
|
-
var
|
|
5
|
-
function
|
|
6
|
-
return r(
|
|
4
|
+
var a = n(e(t));
|
|
5
|
+
function o() {
|
|
6
|
+
return r(a);
|
|
7
|
+
}
|
|
8
|
+
function s() {
|
|
9
|
+
let { language: e } = o();
|
|
10
|
+
return i(() => {
|
|
11
|
+
let t;
|
|
12
|
+
try {
|
|
13
|
+
t = new Intl.DisplayNames(e ? [e] : void 0, { type: "language" });
|
|
14
|
+
} catch {
|
|
15
|
+
t = void 0;
|
|
16
|
+
}
|
|
17
|
+
return (e) => {
|
|
18
|
+
try {
|
|
19
|
+
return t?.of(e) ?? e;
|
|
20
|
+
} catch {
|
|
21
|
+
return e;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}, [e]);
|
|
7
25
|
}
|
|
8
26
|
//#endregion
|
|
9
|
-
export {
|
|
27
|
+
export { a as MessagesContext, s as useLanguageName, o as useMessages };
|
|
10
28
|
|
|
11
29
|
//# sourceMappingURL=context.js.map
|
package/dist/i18n/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../src/i18n/context.ts"],"sourcesContent":["import { createContext, useContext } from \"react\";\nimport { createTranslator, defaultMessages, type Translator } from \"./messages.js\";\n\nexport const MessagesContext = createContext<Translator>(createTranslator(defaultMessages));\n\n/** English defaults when rendered outside a `ContentKitUiProvider`. */\nexport function useMessages(): Translator {\n return useContext(MessagesContext);\n}\n"],"mappings":";;;AAGA,IAAa,IAAkB,EAA0B,EAAiB,CAAe,CAAC;AAG1F,SAAgB,IAA0B;CACxC,OAAO,EAAW,CAAe;AACnC"}
|
|
1
|
+
{"version":3,"file":"context.js","names":[],"sources":["../../src/i18n/context.ts"],"sourcesContent":["import { createContext, useContext, useMemo } from \"react\";\nimport { createTranslator, defaultMessages, type Translator } from \"./messages.js\";\n\nexport const MessagesContext = createContext<Translator>(createTranslator(defaultMessages));\n\n/** English defaults when rendered outside a `ContentKitUiProvider`. */\nexport function useMessages(): Translator {\n return useContext(MessagesContext);\n}\n\n/** A language's name in the UI's language (\"ja\" → \"Japanese\"). */\nexport function useLanguageName(): (code: string) => string {\n const { language } = useMessages();\n return useMemo(() => {\n let names: Intl.DisplayNames | undefined;\n try {\n names = new Intl.DisplayNames(language ? [language] : undefined, { type: \"language\" });\n } catch {\n names = undefined;\n }\n return (code: string) => {\n try {\n return names?.of(code) ?? code;\n } catch {\n return code;\n }\n };\n }, [language]);\n}\n"],"mappings":";;;AAGA,IAAa,IAAkB,EAA0B,EAAiB,CAAe,CAAC;AAG1F,SAAgB,IAA0B;CACxC,OAAO,EAAW,CAAe;AACnC;AAGA,SAAgB,IAA4C;CAC1D,IAAM,EAAE,gBAAa,EAAY;CACjC,OAAO,QAAc;EACnB,IAAI;EACJ,IAAI;GACF,IAAQ,IAAI,KAAK,aAAa,IAAW,CAAC,CAAQ,IAAI,KAAA,GAAW,EAAE,MAAM,WAAW,CAAC;EACvF,QAAQ;GACN,IAAQ,KAAA;EACV;EACA,QAAQ,MAAiB;GACvB,IAAI;IACF,OAAO,GAAO,GAAG,CAAI,KAAK;GAC5B,QAAQ;IACN,OAAO;GACT;EACF;CACF,GAAG,CAAC,CAAQ,CAAC;AACf"}
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,9 @@ export { UserCommentStanding, useUserCommentStandingAccess, type UserCommentStan
|
|
|
25
25
|
export { PollManager, pollState, usePollManagerAccess, type PollManagerProps } from './components/admin/poll-manager.js';
|
|
26
26
|
export { ContentEditor, ContentManager, contentStatus, useContentManagerAccess, type BodyEditorProps, type ContentEditorProps, type ContentManagerProps, type ContentStatus } from './components/admin/content-manager.js';
|
|
27
27
|
export { GroupManager, useGroupManagerAccess, type GroupManagerProps } from './components/admin/group-manager.js';
|
|
28
|
-
export { MediaItemPanel, type MediaItemPanelProps } from './components/admin/media-item-panel.js';
|
|
28
|
+
export { MediaItemPanel, VideoMediaEditor, videoPaths, type MediaItemPanelProps, type VideoMediaEditorProps } from './components/admin/media-item-panel.js';
|
|
29
|
+
export { StatsDashboard, type StatsDashboardProps } from './components/admin/stats-dashboard.js';
|
|
30
|
+
export { ReaderManifestEditor, type ReaderManifestEditorProps } from './components/admin/reader-manifest.js';
|
|
29
31
|
export { UploadQueue, type UploadQueueProps } from './components/admin/upload-queue.js';
|
|
30
32
|
export { NoAccess, Pager, useConfirm, type AdminFlowProps, type AdminRouteProps, type ConfirmOptions, type ContentKitGuard } from './components/admin/shell.js';
|
|
31
33
|
export type { AdminNavigation, ContentKitAuth, StaffAccess, StaffArea } from './react/admin.js';
|