@openrails/contentkit-ui 0.103.1 → 0.104.0-rc.1
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 +105 -43
- package/dist/client/beacons.d.ts +3 -13
- package/dist/client/beacons.js +4 -45
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/client.d.ts +3 -0
- package/dist/client/client.js +45 -43
- package/dist/client/client.js.map +1 -1
- package/dist/client/content/favorites.d.ts +2 -0
- package/dist/client/content/favorites.js.map +1 -1
- package/dist/client/content/types.d.ts +3 -0
- package/dist/client/content/types.js.map +1 -1
- package/dist/client/discovery.d.ts +28 -3
- package/dist/client/discovery.js +22 -1
- package/dist/client/discovery.js.map +1 -1
- package/dist/client/engagement.d.ts +70 -0
- package/dist/client/engagement.js +191 -0
- package/dist/client/engagement.js.map +1 -0
- package/dist/client/generated/routes.d.ts +35 -9
- package/dist/client/generated/routes.js +59 -2
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +53 -12
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/guest-reading-history.d.ts +40 -0
- package/dist/client/guest-reading-history.js +144 -0
- package/dist/client/guest-reading-history.js.map +1 -0
- package/dist/client/index.d.ts +4 -2
- package/dist/client/stats.d.ts +5 -5
- package/dist/client/stats.js.map +1 -1
- package/dist/client.js +24 -22
- package/dist/components/admin/content-manager.d.ts +1 -1
- package/dist/components/admin/content-manager.js +342 -302
- package/dist/components/admin/content-manager.js.map +1 -1
- package/dist/components/admin/page-review.js +106 -97
- package/dist/components/admin/page-review.js.map +1 -1
- package/dist/components/admin/quick-search.d.ts +14 -0
- package/dist/components/admin/quick-search.js +60 -0
- package/dist/components/admin/quick-search.js.map +1 -0
- package/dist/components/admin/reader-content-editor.d.ts +6 -0
- package/dist/components/admin/reader-content-editor.js +733 -0
- package/dist/components/admin/reader-content-editor.js.map +1 -0
- package/dist/components/admin/reader-manifest.js +120 -105
- package/dist/components/admin/reader-manifest.js.map +1 -1
- package/dist/components/admin/stats-dashboard.d.ts +4 -4
- package/dist/components/admin/stats-dashboard.js +132 -134
- package/dist/components/admin/stats-dashboard.js.map +1 -1
- package/dist/components/content/daily-releases.js +143 -191
- package/dist/components/content/daily-releases.js.map +1 -1
- package/dist/components/content/editor-save.d.ts +32 -0
- package/dist/components/content/editor-save.js +51 -0
- package/dist/components/content/editor-save.js.map +1 -0
- package/dist/components/content/editors.d.ts +17 -2
- package/dist/components/content/editors.js +359 -328
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/favorites.d.ts +6 -0
- package/dist/components/content/favorites.js +33 -0
- package/dist/components/content/favorites.js.map +1 -0
- package/dist/components/content/filter-dialog.js +19 -15
- package/dist/components/content/filter-dialog.js.map +1 -1
- package/dist/components/content/filters.d.ts +2 -0
- package/dist/components/content/filters.js +5 -1
- package/dist/components/content/filters.js.map +1 -1
- package/dist/components/content/grid.d.ts +34 -13
- package/dist/components/content/grid.js +300 -271
- package/dist/components/content/grid.js.map +1 -1
- package/dist/components/content/history.d.ts +6 -0
- package/dist/components/content/history.js +91 -0
- package/dist/components/content/history.js.map +1 -0
- package/dist/components/content/index.d.ts +1 -0
- package/dist/components/content/offer-fields.d.ts +1 -1
- package/dist/components/content/offer-fields.js +86 -64
- package/dist/components/content/offer-fields.js.map +1 -1
- package/dist/components/content/search.d.ts +11 -4
- package/dist/components/content/search.js +22 -11
- package/dist/components/content/search.js.map +1 -1
- package/dist/components/content/summary-tile.d.ts +14 -0
- package/dist/components/content/summary-tile.js +63 -0
- package/dist/components/content/summary-tile.js.map +1 -0
- package/dist/components/groups/memberships.d.ts +11 -1
- package/dist/components/groups/memberships.js +1 -1
- package/dist/components/groups/memberships.js.map +1 -1
- package/dist/components/media-folder-editor.d.ts +4 -0
- package/dist/components/media-folder-editor.js +178 -168
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/video-mini-player.d.ts +4 -1
- package/dist/components/video-mini-player.js +77 -71
- package/dist/components/video-mini-player.js.map +1 -1
- package/dist/components/video-player.d.ts +4 -1
- package/dist/components/video-player.js +280 -276
- package/dist/components/video-player.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +17 -14
- package/dist/locales/admin/de.js +33 -8
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +29 -4
- package/dist/locales/admin/en.js +33 -8
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +33 -8
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +33 -8
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +33 -8
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +33 -8
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/discovery/de.js +0 -1
- package/dist/locales/discovery/de.js.map +1 -1
- package/dist/locales/discovery/en.d.ts +0 -1
- package/dist/locales/discovery/en.js +0 -1
- package/dist/locales/discovery/en.js.map +1 -1
- package/dist/locales/discovery/es.js +0 -1
- package/dist/locales/discovery/es.js.map +1 -1
- package/dist/locales/discovery/ja.js +0 -1
- package/dist/locales/discovery/ja.js.map +1 -1
- package/dist/locales/discovery/ko.js +0 -1
- package/dist/locales/discovery/ko.js.map +1 -1
- package/dist/locales/discovery/zh.js +0 -1
- package/dist/locales/discovery/zh.js.map +1 -1
- package/dist/locales/en.d.ts +29 -5
- package/dist/react/discovery.d.ts +20 -17
- package/dist/react/discovery.js +273 -221
- package/dist/react/discovery.js.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/page-review.d.ts +1 -1
- package/dist/react/page-review.js +6 -5
- package/dist/react/page-review.js.map +1 -1
- package/dist/react/resources.d.ts +3 -1
- package/dist/react/resources.js +4 -0
- package/dist/react/resources.js.map +1 -1
- package/dist/react/stats.d.ts +2 -2
- package/dist/react/stats.js.map +1 -1
- package/dist/react/use-draft.d.ts +8 -0
- package/dist/react/use-draft.js +35 -0
- package/dist/react/use-draft.js.map +1 -0
- package/dist/react/use-engagement.d.ts +26 -0
- package/dist/react/use-engagement.js +221 -0
- package/dist/react/use-engagement.js.map +1 -0
- package/dist/react/use-resource.d.ts +4 -3
- package/dist/react/use-resource.js +2 -1
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react.js +12 -11
- package/dist/styles.css +1 -1
- package/dist/ui/dialog.d.ts +2 -1
- package/dist/ui/dialog.js +23 -20
- package/dist/ui/dialog.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video-mini-player.js","names":[],"sources":["../../src/components/video-mini-player.tsx"],"sourcesContent":["import { Cancel01Icon, GoBackward10SecIcon, GoForward10SecIcon, SquareArrowExpand01Icon, PauseIcon, PlayIcon, VolumeHighIcon, VolumeOffIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useCallback, useEffect, useRef, useState, type CSSProperties, type MouseEvent } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport { JUMP_SEEK, PLAYER_VOLUME_KEY, playerKeyAction, writeVolume, type PlayerAction } from \"../client/player.js\";\nimport { publicRenditions } from \"../client/public.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { useHlsPlayer, type HlsPlayerOptions } from \"../react/gallery.js\";\nimport { useActiveCues, useMediaState, useProgressReports, type PlaybackProgress } from \"../react/player.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\nimport { Captions, ControlButton, SeekBar, Spinner, clock } from \"./player-controls.js\";\nimport { RenditionImg } from \"./rendition-img.js\";\nimport { SpriteFrame, keyAllowed, type PlayerHandoff } from \"./video-player.js\";\n\nconst CONTROLS_IDLE_MS = 2500;\n\nexport interface VideoMiniPlayerProps extends Omit<HlsPlayerOptions, \"src\" | \"startAt\" | \"autoPlay\" | \"audioLanguage\" | \"subtitleLanguage\" | \"active\"> {\n /** What VideoPlayer's onMiniPlayer handed over. */\n handoff: PlayerHandoff;\n /** Back to the full player, where this one is. */\n onExpand: (state: { time: number; playing: boolean }) => void;\n onClose: (state: { time: number }) => void;\n onProgress?: (progress: PlaybackProgress) => void;\n /** Milliseconds. Default 10000. */\n progressInterval?: number;\n /** K, J, L and M page-wide (default), every shortcut while focus is in it, or none. */\n keyboard?: \"global\" | \"focus\" | false;\n /** The video's title. */\n label?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n className?: string;\n style?: CSSProperties;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * The video docked in a corner while the viewer browses: play, ±10 s, mute,\n * a seek line, expand back to the full player and close. It starts where\n * the handoff stopped, playing if it was.\n */\nexport function VideoMiniPlayer({\n handoff,\n onExpand,\n onClose,\n onProgress,\n progressInterval = 10_000,\n keyboard = \"global\",\n label,\n position = \"bottom-right\",\n crossOrigin,\n className,\n style,\n appearance,\n ...options\n}: VideoMiniPlayerProps) {\n const { t } = useMessages();\n const src = `${handoff.base}master.m3u8`;\n const player = useHlsPlayer({\n ...options,\n src,\n startAt: handoff.time,\n autoPlay: handoff.playing,\n audioLanguage: handoff.audioLanguage,\n subtitleLanguage: handoff.subtitleLanguage,\n // The handoff carries the viewer's choices; a few hundred pixels need no manual rung.\n trackKey: null,\n qualityKey: null,\n });\n const { status, error, started } = player;\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 const media = useMediaState(video);\n const cues = useActiveCues(video);\n useProgressReports(video, { enabled: started, source: started ? src : null, interval: progressInterval, onProgress });\n\n const [poked, setPoked] = useState(true);\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 const [scrubbing, setScrubbing] = useState(false);\n const playing = !media.paused && !media.ended;\n const shown = poked || !playing || scrubbing || !!error;\n\n const done = useRef(false);\n const time = () => video?.currentTime || media.time || handoff.time;\n const expand = () => {\n if (done.current) return;\n done.current = true;\n onExpand({ time: time(), playing });\n };\n const close = () => {\n if (done.current) return;\n done.current = true;\n video?.pause();\n onClose({ time: time() });\n };\n const toggle = () => {\n if (!video) return;\n if (!started || video.paused || video.ended) player.play();\n else video.pause();\n };\n const dur = media.duration || handoff.duration || 0;\n const seek = (to: number) => {\n if (video) video.currentTime = Math.min(dur || to, Math.max(0, to));\n };\n const volumeKey = options.volumeKey === undefined ? PLAYER_VOLUME_KEY : options.volumeKey;\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 };\n\n const run = (a: PlayerAction, key: string): boolean => {\n if (!video) return false;\n // Page-wide, only K, J, L and M: Space and the arrows scroll the page.\n if (keyboard === \"global\" && !\"kjlmKJLM\".includes(key)) return false;\n switch (a.type) {\n case \"toggle\":\n toggle();\n break;\n case \"seekBy\":\n if (!started) return false;\n seek(video.currentTime + a.seconds);\n break;\n case \"mute\":\n toggleMute();\n break;\n default:\n return false;\n }\n poke();\n return true;\n };\n const runRef = useRef(run);\n runRef.current = run;\n const [root, setRoot] = useState<HTMLDivElement | null>(null);\n useEffect(() => {\n if (!keyboard || !root) 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, k.key)) return;\n k.preventDefault();\n };\n on.addEventListener(\"keydown\", down);\n return () => on.removeEventListener(\"keydown\", down);\n }, [keyboard, root]);\n\n // Touch has no hover: a tap shows or hides the controls. A click plays and pauses.\n const pointerType = useRef(\"mouse\");\n const onSurfaceClick = (e: MouseEvent) => {\n e.preventDefault();\n if (pointerType.current === \"mouse\") {\n toggle();\n poke();\n } else if (shown && playing) hide();\n else poke();\n };\n\n const aspect = handoff.width && handoff.height ? handoff.width / handoff.height : (media.aspect ?? 16 / 9);\n const posterOutputs = typeof handoff.poster === \"string\" ? [] : publicRenditions(handoff.poster);\n const busy = !error && (status === \"loading\" || status === \"buffering\");\n const overlay = \"rounded-full text-white hover:bg-white/15\";\n return (\n <ContentKitUiRoot\n ref={setRoot}\n appearance={appearance}\n role=\"region\"\n aria-label={label ? `${t(\"player.miniPlayer\")}: ${label}` : t(\"player.miniPlayer\")}\n data-ckui=\"mini-player\"\n data-status={status}\n className={cn(\n \"@container fixed bottom-4 z-50 touch-manipulation overflow-hidden rounded-md bg-black text-white shadow-lg select-none\",\n position === \"bottom-left\" ? \"left-4\" : \"right-4\",\n className,\n )}\n style={{ aspectRatio: String(aspect), width: `min(24rem, calc(100vw - 2rem), calc(60svh * ${aspect}))`, ...style }}\n onPointerDown={(e) => (pointerType.current = e.pointerType || \"mouse\")}\n onPointerMove={(e) => e.pointerType === \"mouse\" && poke()}\n onPointerLeave={(e) => e.pointerType === \"mouse\" && !scrubbing && playing && hide()}\n >\n <video ref={videoRef} className=\"absolute inset-0 size-full object-contain\" playsInline preload=\"none\" crossOrigin={crossOrigin} aria-label={label} />\n {!started &&\n (typeof handoff.poster === \"string\" ? (\n <img alt=\"\" src={handoff.poster} className=\"pointer-events-none absolute inset-0 size-full object-contain\" />\n ) : posterOutputs.length ? (\n <RenditionImg outputs={posterOutputs} className=\"pointer-events-none absolute inset-0 size-full object-contain\" />\n ) : (\n <SpriteFrame vtt={`${handoff.base}sprite.vtt`} loader={options.loader} />\n ))}\n <div aria-hidden data-ckui=\"surface\" className=\"absolute inset-0\" onClick={onSurfaceClick} />\n <Captions cues={started ? cues : []} bottom={shown ? \"2.75rem\" : \"0.75rem\"} />\n <div\n data-ckui=\"controls\"\n className={cn(\n \"pointer-events-none absolute inset-0 bg-black/45 transition-opacity duration-200 focus-within:opacity-100 motion-reduce:transition-none\",\n shown ? \"opacity-100 [&_button]:pointer-events-auto\" : \"opacity-0\",\n )}\n >\n <div className=\"absolute inset-x-0 top-0 flex items-center justify-between p-1.5\">\n <ControlButton label={t(\"player.expand\")} icon={SquareArrowExpand01Icon} onClick={expand} className={overlay} data-ckui=\"mini-expand\" />\n <ControlButton label={t(\"player.close\")} icon={Cancel01Icon} onClick={close} className={overlay} data-ckui=\"mini-close\" />\n </div>\n <div className=\"absolute inset-0 m-auto flex h-fit w-fit items-center gap-3 @sm:gap-5\">\n <ControlButton\n label={t(\"player.seekBack\", { seconds: JUMP_SEEK })}\n icon={GoBackward10SecIcon}\n disabled={!started}\n onClick={() => {\n seek(time() - JUMP_SEEK);\n poke();\n }}\n className={cn(overlay, \"[&_svg]:size-6\")}\n />\n <button\n type=\"button\"\n aria-label={playing ? t(\"player.pause\") : t(\"player.resume\")}\n title={playing ? t(\"player.pause\") : t(\"player.resume\")}\n onClick={() => {\n toggle();\n poke();\n }}\n className={cn(\"flex size-12 cursor-pointer items-center justify-center outline-none focus-visible:ring-2 focus-visible:ring-white/80\", overlay)}\n data-ckui=\"mini-play\"\n >\n {busy && started ? <Spinner className=\"size-7\" /> : <HugeiconsIcon icon={playing ? PauseIcon : PlayIcon} className=\"size-7 fill-current\" strokeWidth={1.5} aria-hidden />}\n </button>\n <ControlButton\n label={t(\"player.seekForward\", { seconds: JUMP_SEEK })}\n icon={GoForward10SecIcon}\n disabled={!started}\n onClick={() => {\n seek(time() + JUMP_SEEK);\n poke();\n }}\n className={cn(overlay, \"[&_svg]:size-6\")}\n />\n </div>\n <div className=\"absolute inset-x-0 bottom-3 flex items-center justify-between px-2.5\">\n <span className=\"text-xs font-medium tabular-nums\">{dur > 0 ? `${clock(media.time || handoff.time)} / ${clock(dur)}` : clock(media.time || handoff.time)}</span>\n <ControlButton label={media.muted ? t(\"player.unmute\") : t(\"player.mute\")} icon={media.muted ? VolumeOffIcon : VolumeHighIcon} onClick={toggleMute} className={cn(overlay, \"size-8\")} />\n </div>\n </div>\n <div className=\"absolute inset-x-0 bottom-0 z-10\">\n <SeekBar thin time={media.time || handoff.time} duration={dur} buffered={media.buffered} onSeek={seek} onScrub={(v) => setScrubbing(v !== null)} />\n </div>\n {error && (\n <div role=\"alert\" className=\"absolute inset-0 z-20 flex flex-col items-center justify-center gap-2 bg-black/80 p-3 text-center text-xs\">\n <p>{t(`player.errors.${error.kind}`)}</p>\n <button type=\"button\" onClick={player.retry} className=\"rounded-md bg-white/15 px-2 py-1 font-medium hover:bg-white/25\">\n {t(\"player.retry\")}\n </button>\n </div>\n )}\n </ContentKitUiRoot>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"video-mini-player.js","names":[],"sources":["../../src/components/video-mini-player.tsx"],"sourcesContent":["import { Cancel01Icon, GoBackward10SecIcon, GoForward10SecIcon, SquareArrowExpand01Icon, PauseIcon, PlayIcon, VolumeHighIcon, VolumeOffIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useCallback, useEffect, useRef, useState, type CSSProperties, type MouseEvent } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport { JUMP_SEEK, PLAYER_VOLUME_KEY, playerKeyAction, writeVolume, type PlayerAction } from \"../client/player.js\";\nimport { publicRenditions } from \"../client/public.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { useHlsPlayer, type HlsPlayerOptions } from \"../react/gallery.js\";\nimport type { ReadingEngagement } from \"../react/use-engagement.js\";\nimport { useActiveCues, useMediaState, useProgressReports, type PlaybackProgress } from \"../react/player.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\nimport { Captions, ControlButton, SeekBar, Spinner, clock } from \"./player-controls.js\";\nimport { RenditionImg } from \"./rendition-img.js\";\nimport { SpriteFrame, keyAllowed, type PlayerHandoff } from \"./video-player.js\";\n\nconst CONTROLS_IDLE_MS = 2500;\n\nexport interface VideoMiniPlayerProps extends Omit<HlsPlayerOptions, \"src\" | \"startAt\" | \"autoPlay\" | \"audioLanguage\" | \"subtitleLanguage\" | \"active\"> {\n /** What VideoPlayer's onMiniPlayer handed over. */\n handoff: PlayerHandoff;\n /** Back to the full player, where this one is. */\n onExpand: (state: { time: number; playing: boolean }) => void;\n onClose: (state: { time: number }) => void;\n onProgress?: (progress: PlaybackProgress) => void;\n /** Continue actual visible playback measurements after the full player handoff. */\n engagement?: Pick<ReadingEngagement, \"video\">;\n /** Milliseconds. Default 10000. */\n progressInterval?: number;\n /** K, J, L and M page-wide (default), every shortcut while focus is in it, or none. */\n keyboard?: \"global\" | \"focus\" | false;\n /** The video's title. */\n label?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n className?: string;\n style?: CSSProperties;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * The video docked in a corner while the viewer browses: play, ±10 s, mute,\n * a seek line, expand back to the full player and close. It starts where\n * the handoff stopped, playing if it was.\n */\nexport function VideoMiniPlayer({\n handoff,\n onExpand,\n onClose,\n onProgress,\n engagement,\n progressInterval = 10_000,\n keyboard = \"global\",\n label,\n position = \"bottom-right\",\n crossOrigin,\n className,\n style,\n appearance,\n ...options\n}: VideoMiniPlayerProps) {\n const { t } = useMessages();\n const src = `${handoff.base}master.m3u8`;\n const player = useHlsPlayer({\n ...options,\n src,\n startAt: handoff.time,\n autoPlay: handoff.playing,\n audioLanguage: handoff.audioLanguage,\n subtitleLanguage: handoff.subtitleLanguage,\n // The handoff carries the viewer's choices; a few hundred pixels need no manual rung.\n trackKey: null,\n qualityKey: null,\n });\n const { status, error, started } = player;\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 const bindEngagement = engagement?.video;\n useEffect(() => {\n bindEngagement?.(started ? video : null);\n return () => bindEngagement?.(null);\n }, [bindEngagement, started, video]);\n const media = useMediaState(video);\n const cues = useActiveCues(video);\n useProgressReports(video, { enabled: started, source: started ? src : null, interval: progressInterval, onProgress });\n\n const [poked, setPoked] = useState(true);\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 const [scrubbing, setScrubbing] = useState(false);\n const playing = !media.paused && !media.ended;\n const shown = poked || !playing || scrubbing || !!error;\n\n const done = useRef(false);\n const time = () => video?.currentTime || media.time || handoff.time;\n const expand = () => {\n if (done.current) return;\n done.current = true;\n onExpand({ time: time(), playing });\n };\n const close = () => {\n if (done.current) return;\n done.current = true;\n video?.pause();\n onClose({ time: time() });\n };\n const toggle = () => {\n if (!video) return;\n if (!started || video.paused || video.ended) player.play();\n else video.pause();\n };\n const dur = media.duration || handoff.duration || 0;\n const seek = (to: number) => {\n if (video) video.currentTime = Math.min(dur || to, Math.max(0, to));\n };\n const volumeKey = options.volumeKey === undefined ? PLAYER_VOLUME_KEY : options.volumeKey;\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 };\n\n const run = (a: PlayerAction, key: string): boolean => {\n if (!video) return false;\n // Page-wide, only K, J, L and M: Space and the arrows scroll the page.\n if (keyboard === \"global\" && !\"kjlmKJLM\".includes(key)) return false;\n switch (a.type) {\n case \"toggle\":\n toggle();\n break;\n case \"seekBy\":\n if (!started) return false;\n seek(video.currentTime + a.seconds);\n break;\n case \"mute\":\n toggleMute();\n break;\n default:\n return false;\n }\n poke();\n return true;\n };\n const runRef = useRef(run);\n runRef.current = run;\n const [root, setRoot] = useState<HTMLDivElement | null>(null);\n useEffect(() => {\n if (!keyboard || !root) 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, k.key)) return;\n k.preventDefault();\n };\n on.addEventListener(\"keydown\", down);\n return () => on.removeEventListener(\"keydown\", down);\n }, [keyboard, root]);\n\n // Touch has no hover: a tap shows or hides the controls. A click plays and pauses.\n const pointerType = useRef(\"mouse\");\n const onSurfaceClick = (e: MouseEvent) => {\n e.preventDefault();\n if (pointerType.current === \"mouse\") {\n toggle();\n poke();\n } else if (shown && playing) hide();\n else poke();\n };\n\n const aspect = handoff.width && handoff.height ? handoff.width / handoff.height : (media.aspect ?? 16 / 9);\n const posterOutputs = typeof handoff.poster === \"string\" ? [] : publicRenditions(handoff.poster);\n const busy = !error && (status === \"loading\" || status === \"buffering\");\n const overlay = \"rounded-full text-white hover:bg-white/15\";\n return (\n <ContentKitUiRoot\n ref={setRoot}\n appearance={appearance}\n role=\"region\"\n aria-label={label ? `${t(\"player.miniPlayer\")}: ${label}` : t(\"player.miniPlayer\")}\n data-ckui=\"mini-player\"\n data-status={status}\n className={cn(\n \"@container fixed bottom-4 z-50 touch-manipulation overflow-hidden rounded-md bg-black text-white shadow-lg select-none\",\n position === \"bottom-left\" ? \"left-4\" : \"right-4\",\n className,\n )}\n style={{ aspectRatio: String(aspect), width: `min(24rem, calc(100vw - 2rem), calc(60svh * ${aspect}))`, ...style }}\n onPointerDown={(e) => (pointerType.current = e.pointerType || \"mouse\")}\n onPointerMove={(e) => e.pointerType === \"mouse\" && poke()}\n onPointerLeave={(e) => e.pointerType === \"mouse\" && !scrubbing && playing && hide()}\n >\n <video ref={videoRef} className=\"absolute inset-0 size-full object-contain\" playsInline preload=\"none\" crossOrigin={crossOrigin} aria-label={label} />\n {!started &&\n (typeof handoff.poster === \"string\" ? (\n <img alt=\"\" src={handoff.poster} className=\"pointer-events-none absolute inset-0 size-full object-contain\" />\n ) : posterOutputs.length ? (\n <RenditionImg outputs={posterOutputs} className=\"pointer-events-none absolute inset-0 size-full object-contain\" />\n ) : (\n <SpriteFrame vtt={`${handoff.base}sprite.vtt`} loader={options.loader} />\n ))}\n <div aria-hidden data-ckui=\"surface\" className=\"absolute inset-0\" onClick={onSurfaceClick} />\n <Captions cues={started ? cues : []} bottom={shown ? \"2.75rem\" : \"0.75rem\"} />\n <div\n data-ckui=\"controls\"\n className={cn(\n \"pointer-events-none absolute inset-0 bg-black/45 transition-opacity duration-200 focus-within:opacity-100 motion-reduce:transition-none\",\n shown ? \"opacity-100 [&_button]:pointer-events-auto\" : \"opacity-0\",\n )}\n >\n <div className=\"absolute inset-x-0 top-0 flex items-center justify-between p-1.5\">\n <ControlButton label={t(\"player.expand\")} icon={SquareArrowExpand01Icon} onClick={expand} className={overlay} data-ckui=\"mini-expand\" />\n <ControlButton label={t(\"player.close\")} icon={Cancel01Icon} onClick={close} className={overlay} data-ckui=\"mini-close\" />\n </div>\n <div className=\"absolute inset-0 m-auto flex h-fit w-fit items-center gap-3 @sm:gap-5\">\n <ControlButton\n label={t(\"player.seekBack\", { seconds: JUMP_SEEK })}\n icon={GoBackward10SecIcon}\n disabled={!started}\n onClick={() => {\n seek(time() - JUMP_SEEK);\n poke();\n }}\n className={cn(overlay, \"[&_svg]:size-6\")}\n />\n <button\n type=\"button\"\n aria-label={playing ? t(\"player.pause\") : t(\"player.resume\")}\n title={playing ? t(\"player.pause\") : t(\"player.resume\")}\n onClick={() => {\n toggle();\n poke();\n }}\n className={cn(\"flex size-12 cursor-pointer items-center justify-center outline-none focus-visible:ring-2 focus-visible:ring-white/80\", overlay)}\n data-ckui=\"mini-play\"\n >\n {busy && started ? <Spinner className=\"size-7\" /> : <HugeiconsIcon icon={playing ? PauseIcon : PlayIcon} className=\"size-7 fill-current\" strokeWidth={1.5} aria-hidden />}\n </button>\n <ControlButton\n label={t(\"player.seekForward\", { seconds: JUMP_SEEK })}\n icon={GoForward10SecIcon}\n disabled={!started}\n onClick={() => {\n seek(time() + JUMP_SEEK);\n poke();\n }}\n className={cn(overlay, \"[&_svg]:size-6\")}\n />\n </div>\n <div className=\"absolute inset-x-0 bottom-3 flex items-center justify-between px-2.5\">\n <span className=\"text-xs font-medium tabular-nums\">{dur > 0 ? `${clock(media.time || handoff.time)} / ${clock(dur)}` : clock(media.time || handoff.time)}</span>\n <ControlButton label={media.muted ? t(\"player.unmute\") : t(\"player.mute\")} icon={media.muted ? VolumeOffIcon : VolumeHighIcon} onClick={toggleMute} className={cn(overlay, \"size-8\")} />\n </div>\n </div>\n <div className=\"absolute inset-x-0 bottom-0 z-10\">\n <SeekBar thin time={media.time || handoff.time} duration={dur} buffered={media.buffered} onSeek={seek} onScrub={(v) => setScrubbing(v !== null)} />\n </div>\n {error && (\n <div role=\"alert\" className=\"absolute inset-0 z-20 flex flex-col items-center justify-center gap-2 bg-black/80 p-3 text-center text-xs\">\n <p>{t(`player.errors.${error.kind}`)}</p>\n <button type=\"button\" onClick={player.retry} className=\"rounded-md bg-white/15 px-2 py-1 font-medium hover:bg-white/25\">\n {t(\"player.retry\")}\n </button>\n </div>\n )}\n </ContentKitUiRoot>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CSSProperties, ReactNode } from 'react';
|
|
2
2
|
import { ContentKitUiAppearance } from '../appearance.js';
|
|
3
3
|
import { PlaybackError } from '../client/playback.js';
|
|
4
|
+
import { ReadingEngagement } from '../react/use-engagement.js';
|
|
4
5
|
import { PlayerTrack } from '../client/player.js';
|
|
5
6
|
import { HlsPlayerOptions } from '../react/gallery.js';
|
|
6
7
|
import { PlaybackProgress } from '../react/player.js';
|
|
@@ -107,6 +108,8 @@ export interface VideoPlayerProps extends Omit<HlsPlayerOptions, "src"> {
|
|
|
107
108
|
keyboard?: "focus" | "global" | false;
|
|
108
109
|
/** Resume points and watch time: every `progressInterval` of playback, and on pause, seek, end, page hide and unload. */
|
|
109
110
|
onProgress?: (progress: PlaybackProgress) => void;
|
|
111
|
+
/** Measure real playback only, excluding inline previews and the poster. */
|
|
112
|
+
engagement?: Pick<ReadingEngagement, "video">;
|
|
110
113
|
/** Milliseconds. Default 10000. */
|
|
111
114
|
progressInterval?: number;
|
|
112
115
|
onEvent?: (event: PlayerEvent) => void;
|
|
@@ -140,7 +143,7 @@ export declare function keyAllowed(target: EventTarget | null, key: string, root
|
|
|
140
143
|
* touch gestures, resume and progress reports, and a specific error with
|
|
141
144
|
* Retry and a support code.
|
|
142
145
|
*/
|
|
143
|
-
export declare function VideoPlayer({ base, poster, width, height, duration, pending, progress, failed, layout, maxHeight, inlinePreview, previewStart, keyboard, onProgress, progressInterval, onEvent, theater, onTheaterChange, onMiniPlayer, renderDownloads, menuItems, crossOrigin, label, className, style, appearance, startAt, ...options }: VideoPlayerProps): import('react').JSX.Element;
|
|
146
|
+
export declare function VideoPlayer({ base, poster, width, height, duration, pending, progress, failed, layout, maxHeight, inlinePreview, previewStart, keyboard, onProgress, engagement, progressInterval, onEvent, theater, onTheaterChange, onMiniPlayer, renderDownloads, menuItems, crossOrigin, label, className, style, appearance, startAt, ...options }: VideoPlayerProps): import('react').JSX.Element;
|
|
144
147
|
/** A preview's start: the given second, else 10% in, kept a second before the end. */
|
|
145
148
|
export declare function previewStartAt(start: number | undefined, duration: number | undefined): number;
|
|
146
149
|
/** "2160p 4K", "1080p HD", "720p": a rung by its short side. */
|