markdown-flow-ui 0.1.128-dev.1 → 0.1.128
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/dist/assets/markdown-flow-ui.css +1 -1
- package/dist/components/Slide/Player.cjs.js +1 -1
- package/dist/components/Slide/Player.cjs.js.map +1 -1
- package/dist/components/Slide/Player.d.ts +5 -1
- package/dist/components/Slide/Player.es.js +615 -465
- package/dist/components/Slide/Player.es.js.map +1 -1
- package/dist/components/Slide/Slide.cjs.js.map +1 -1
- package/dist/components/Slide/Slide.es.js.map +1 -1
- package/dist/components/Slide/Slide.stories.d.ts +2 -0
- package/dist/components/Slide/SubtitleOverlay.cjs.js.map +1 -1
- package/dist/components/Slide/SubtitleOverlay.es.js.map +1 -1
- package/dist/components/Slide/constants.cjs.js +1 -1
- package/dist/components/Slide/constants.cjs.js.map +1 -1
- package/dist/components/Slide/constants.d.ts +4 -2
- package/dist/components/Slide/constants.es.js +4 -2
- package/dist/components/Slide/constants.es.js.map +1 -1
- package/dist/components/Slide/useSlide.cjs.js.map +1 -1
- package/dist/components/Slide/useSlide.es.js.map +1 -1
- package/dist/components/Slide/utils/playerKeyboardShortcuts.cjs.js +1 -1
- package/dist/components/Slide/utils/playerKeyboardShortcuts.cjs.js.map +1 -1
- package/dist/components/Slide/utils/playerKeyboardShortcuts.d.ts +1 -1
- package/dist/components/Slide/utils/playerKeyboardShortcuts.es.js +14 -5
- package/dist/components/Slide/utils/playerKeyboardShortcuts.es.js.map +1 -1
- package/dist/components/Slide/utils/segmentSeek.cjs.js +2 -0
- package/dist/components/Slide/utils/segmentSeek.cjs.js.map +1 -0
- package/dist/components/Slide/utils/segmentSeek.d.ts +8 -0
- package/dist/components/Slide/utils/segmentSeek.es.js +31 -0
- package/dist/components/Slide/utils/segmentSeek.es.js.map +1 -0
- package/dist/components/Slide/utils/segmentSeek.test.d.ts +1 -0
- package/dist/components/Slide/utils/streamingNavigation.cjs.js.map +1 -1
- package/dist/components/Slide/utils/streamingNavigation.es.js.map +1 -1
- package/dist/components/Slide/utils/subtitleCue.cjs.js +2 -2
- package/dist/components/Slide/utils/subtitleCue.cjs.js.map +1 -1
- package/dist/components/Slide/utils/subtitleCue.d.ts +10 -0
- package/dist/components/Slide/utils/subtitleCue.es.js +59 -5
- package/dist/components/Slide/utils/subtitleCue.es.js.map +1 -1
- package/dist/lib/interaction-defaults.cjs.js.map +1 -1
- package/dist/lib/interaction-defaults.es.js.map +1 -1
- package/dist/node_modules/lucide-react/dist/esm/icons/skip-back.cjs.js +7 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/skip-back.cjs.js.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/skip-back.es.js +16 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/skip-back.es.js.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/skip-forward.cjs.js +7 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/skip-forward.cjs.js.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/skip-forward.es.js +16 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/skip-forward.es.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSlide.cjs.js","sources":["../../../src/components/Slide/useSlide.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { applyDiffElement } from \"./diff-utils\";\nimport type { Element, ElementAudioSegment } from \"./types\";\nimport { resolveNextSlideIndexAfterMarkerAppend } from \"./utils/streamingNavigation\";\n\nexport interface SlideAudioItem {\n audioKey?: string;\n sequenceNumber?: number;\n audioUrl?: string;\n audioSegments?: ElementAudioSegment[];\n isAudioStreaming?: boolean;\n element?: Element;\n}\n\nexport interface UseSlideResult {\n currentElementList: Element[];\n stepElementLists: Element[][];\n slideElementList: Element[];\n currentIndex: number;\n audioList: SlideAudioItem[];\n currentAudioSequenceIndexes: number[];\n currentStepHasSpeakableElement: boolean;\n currentInteractionElement?: Element;\n canGoPrev: boolean;\n canGoNext: boolean;\n handlePrev: () => void;\n handleNext: () => void;\n}\n\nconst getMarkerElementList = (elementList: Element[]) =>\n elementList.filter((element) => element.is_marker);\n\nconst getMarkerElementIndexes = (elementList: Element[]) =>\n elementList.reduce<number[]>((indexes, element, index) => {\n if (element.is_marker) {\n indexes.push(index);\n }\n\n return indexes;\n }, []);\n\nconst hasPlayableAudio = (element?: Element) =>\n Boolean(\n element?.is_speakable &&\n (element.audio_url || (element.audio_segments?.length ?? 0) > 0)\n );\n\nconst isStreamingAudio = (segments: ElementAudioSegment[] = []) =>\n segments.length > 0 && !segments.some((segment) => segment.is_final);\n\nexport const resolveSlideAudioItemSource = (element: Element) => {\n const audioUrl = element.audio_url?.trim() ?? \"\";\n const audioSegments = element.audio_segments ?? [];\n\n return {\n audioUrl,\n audioSegments,\n isAudioStreaming: !audioUrl && isStreamingAudio(audioSegments),\n };\n};\n\nconst getElementAudioKey = (element: Element, index: number) => {\n const candidateElement = element as Element & {\n element_bid?: string;\n blockBid?: string;\n generated_block_bid?: string;\n };\n\n return (\n candidateElement.element_bid ||\n candidateElement.blockBid ||\n candidateElement.generated_block_bid ||\n `${element.type}:${String(element.sequence_number ?? index)}`\n );\n};\n\nconst getAudioList = (elementList: Element[]) =>\n elementList.reduce<SlideAudioItem[]>((list, element, elementIndex) => {\n if (hasPlayableAudio(element)) {\n const { audioUrl, audioSegments, isAudioStreaming } =\n resolveSlideAudioItemSource(element);\n\n list.push({\n audioKey: getElementAudioKey(element, elementIndex),\n sequenceNumber: element.sequence_number,\n // Keep the completed URL available once it arrives so loading can end.\n audioUrl,\n audioSegments,\n isAudioStreaming,\n element,\n });\n }\n\n return list;\n }, []);\n\nconst getAudioIndexMap = (elementList: Element[]) => {\n const audioIndexMap = new Map<number, number>();\n let audioIndex = 0;\n\n elementList.forEach((element, index) => {\n if (hasPlayableAudio(element)) {\n audioIndexMap.set(index, audioIndex);\n audioIndex += 1;\n }\n });\n\n return audioIndexMap;\n};\n\nconst getSlideAudioSequenceMap = (\n elementList: Element[],\n markerElementIndexes: number[],\n audioIndexMap: Map<number, number>\n) =>\n markerElementIndexes.reduce<Map<number, number[]>>(\n (sequenceMap, startIndex, slideIndex) => {\n const nextMarkerIndex =\n markerElementIndexes[slideIndex + 1] ?? elementList.length;\n const sequenceIndexes: number[] = [];\n\n for (let index = startIndex; index < nextMarkerIndex; index += 1) {\n const element = elementList[index];\n\n if (!hasPlayableAudio(element)) {\n continue;\n }\n\n const audioIndex = audioIndexMap.get(index);\n\n if (audioIndex == null) {\n continue;\n }\n\n sequenceIndexes.push(audioIndex);\n }\n\n sequenceMap.set(slideIndex, sequenceIndexes);\n return sequenceMap;\n },\n new Map<number, number[]>()\n );\n\nconst getInitialSlideIndex = (slideElementList: Element[]) => {\n const visibleIndex = slideElementList.findIndex(\n (element) => element.is_renderable === true\n );\n\n if (visibleIndex >= 0) {\n return visibleIndex;\n }\n\n return slideElementList.findIndex(\n (element) => element.is_renderable !== false\n );\n};\n\nconst getVisibleElement = (element: Element): Element => ({\n ...element,\n is_renderable: true,\n});\n\nconst getCurrentElementList = (\n slideElementList: Element[],\n currentIndex: number\n) => {\n if (currentIndex < 0) {\n return [];\n }\n\n return slideElementList\n .slice(0, currentIndex + 1)\n .reduce<Element[]>((currentList, element) => {\n if (element.type === \"interaction\") {\n return currentList;\n }\n\n const visibleElement = getVisibleElement(element);\n\n if (visibleElement.type === \"diff\") {\n const nextList = applyDiffElement(currentList, visibleElement);\n\n return nextList ?? [...currentList, visibleElement];\n }\n\n if (element.is_new) {\n return [visibleElement];\n }\n\n if (currentList.length === 0) {\n return [visibleElement];\n }\n\n return [...currentList, visibleElement];\n }, []);\n};\n\nconst getStepElementLists = (slideElementList: Element[]) =>\n slideElementList.map((_, index) =>\n getCurrentElementList(slideElementList, index)\n );\n\nconst getStepHasSpeakableElement = (\n elementList: Element[],\n markerElementIndexes: number[],\n currentIndex: number\n) => {\n if (currentIndex < 0) {\n return false;\n }\n\n const startIndex = markerElementIndexes[currentIndex];\n\n if (typeof startIndex !== \"number\") {\n return false;\n }\n\n const nextMarkerIndex =\n markerElementIndexes[currentIndex + 1] ?? elementList.length;\n\n for (let index = startIndex; index < nextMarkerIndex; index += 1) {\n if (elementList[index]?.is_speakable) {\n return true;\n }\n }\n\n return false;\n};\n\nconst hasSameElementReferences = (\n prevElementList: Element[],\n nextElementList: Element[]\n) =>\n prevElementList.length === nextElementList.length &&\n prevElementList.every((element, index) => element === nextElementList[index]);\n\nconst hasSameNumberValues = (prevValues: number[], nextValues: number[]) =>\n prevValues.length === nextValues.length &&\n prevValues.every((value, index) => value === nextValues[index]);\n\nconst useSlide = (elementList: Element[] = []): UseSlideResult => {\n const stableElementListRef = useRef(elementList);\n const stableCurrentAudioSequenceIndexesRef = useRef<number[]>([]);\n const stableElementList = useMemo(() => {\n if (hasSameElementReferences(stableElementListRef.current, elementList)) {\n return stableElementListRef.current;\n }\n\n // Reuse the previous wrapper array when the element references are unchanged.\n stableElementListRef.current = elementList;\n return elementList;\n }, [elementList]);\n const slideElementList = useMemo(\n () => getMarkerElementList(stableElementList),\n [stableElementList]\n );\n const previousSlideElementListRef = useRef(slideElementList);\n const markerElementIndexes = useMemo(\n () => getMarkerElementIndexes(stableElementList),\n [stableElementList]\n );\n const audioList = useMemo(\n () => getAudioList(stableElementList),\n [stableElementList]\n );\n const audioIndexMap = useMemo(\n () => getAudioIndexMap(stableElementList),\n [stableElementList]\n );\n const slideAudioSequenceMap = useMemo(\n () =>\n getSlideAudioSequenceMap(\n stableElementList,\n markerElementIndexes,\n audioIndexMap\n ),\n [audioIndexMap, markerElementIndexes, stableElementList]\n );\n const [currentIndex, setCurrentIndex] = useState(() =>\n getInitialSlideIndex(slideElementList)\n );\n\n useEffect(() => {\n const previousSlideElementList = previousSlideElementListRef.current;\n\n setCurrentIndex((prevIndex) => {\n const resolvedNextIndex = resolveNextSlideIndexAfterMarkerAppend({\n previousIndex: prevIndex,\n previousSlideElementList,\n nextSlideElementList: slideElementList,\n });\n\n if (resolvedNextIndex >= 0) {\n return resolvedNextIndex;\n }\n\n return getInitialSlideIndex(slideElementList);\n });\n\n previousSlideElementListRef.current = slideElementList;\n }, [slideElementList]);\n\n const handlePrev = useCallback(() => {\n setCurrentIndex((prevIndex) => {\n if (prevIndex <= 0) {\n return Math.max(prevIndex, 0);\n }\n\n return Math.max(prevIndex - 1, 0);\n });\n }, []);\n\n const handleNext = useCallback(() => {\n setCurrentIndex((prevIndex) => {\n if (prevIndex < 0) {\n return prevIndex;\n }\n\n return Math.min(prevIndex + 1, slideElementList.length - 1);\n });\n }, [slideElementList.length]);\n\n const canGoPrev = currentIndex > 0;\n const canGoNext =\n currentIndex >= 0 && currentIndex < slideElementList.length - 1;\n const currentStepElement = useMemo(() => {\n if (currentIndex < 0) {\n return undefined;\n }\n\n const element = slideElementList[currentIndex];\n\n if (!element) {\n return undefined;\n }\n\n return getVisibleElement(element);\n }, [currentIndex, slideElementList]);\n const currentElementList = useMemo(\n () => getCurrentElementList(slideElementList, currentIndex),\n [currentIndex, slideElementList]\n );\n const stepElementLists = useMemo(\n () => getStepElementLists(slideElementList),\n [slideElementList]\n );\n const currentAudioSequenceIndexes = useMemo(() => {\n const nextAudioSequenceIndexes =\n slideAudioSequenceMap.get(currentIndex) ?? [];\n\n if (\n hasSameNumberValues(\n stableCurrentAudioSequenceIndexesRef.current,\n nextAudioSequenceIndexes\n )\n ) {\n return stableCurrentAudioSequenceIndexesRef.current;\n }\n\n stableCurrentAudioSequenceIndexesRef.current = nextAudioSequenceIndexes;\n\n return nextAudioSequenceIndexes;\n }, [currentIndex, slideAudioSequenceMap]);\n const currentStepHasSpeakableElement = useMemo(\n () =>\n getStepHasSpeakableElement(\n stableElementList,\n markerElementIndexes,\n currentIndex\n ),\n [currentIndex, markerElementIndexes, stableElementList]\n );\n const currentInteractionElement = useMemo(\n () =>\n currentStepElement?.type === \"interaction\"\n ? currentStepElement\n : undefined,\n [currentStepElement]\n );\n\n return {\n currentElementList,\n stepElementLists,\n slideElementList,\n currentIndex,\n audioList,\n currentAudioSequenceIndexes,\n currentStepHasSpeakableElement,\n currentInteractionElement,\n canGoPrev,\n canGoNext,\n handlePrev,\n handleNext,\n };\n};\n\nexport default useSlide;\n"],"names":["getMarkerElementList","elementList","element","getMarkerElementIndexes","indexes","index","hasPlayableAudio","isStreamingAudio","segments","segment","resolveSlideAudioItemSource","audioUrl","audioSegments","getElementAudioKey","candidateElement","getAudioList","list","elementIndex","isAudioStreaming","getAudioIndexMap","audioIndexMap","audioIndex","getSlideAudioSequenceMap","markerElementIndexes","sequenceMap","startIndex","slideIndex","nextMarkerIndex","sequenceIndexes","getInitialSlideIndex","slideElementList","visibleIndex","getVisibleElement","getCurrentElementList","currentIndex","currentList","visibleElement","applyDiffElement","getStepElementLists","_","getStepHasSpeakableElement","hasSameElementReferences","prevElementList","nextElementList","hasSameNumberValues","prevValues","nextValues","value","useSlide","stableElementListRef","useRef","stableCurrentAudioSequenceIndexesRef","stableElementList","useMemo","previousSlideElementListRef","audioList","slideAudioSequenceMap","setCurrentIndex","useState","useEffect","previousSlideElementList","prevIndex","resolvedNextIndex","resolveNextSlideIndexAfterMarkerAppend","handlePrev","useCallback","handleNext","canGoPrev","canGoNext","currentStepElement","currentElementList","stepElementLists","currentAudioSequenceIndexes","nextAudioSequenceIndexes","currentStepHasSpeakableElement","currentInteractionElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useSlide.cjs.js","sources":["../../../src/components/Slide/useSlide.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { applyDiffElement } from \"./diff-utils\";\nimport type { Element, ElementAudioSegment } from \"./types\";\nimport { resolveNextSlideIndexAfterMarkerAppend } from \"./utils/streamingNavigation\";\n\nexport interface SlideAudioItem {\n audioKey?: string;\n sequenceNumber?: number;\n audioUrl?: string;\n audioSegments?: ElementAudioSegment[];\n isAudioStreaming?: boolean;\n element?: Element;\n}\n\nexport interface UseSlideResult {\n currentElementList: Element[];\n stepElementLists: Element[][];\n slideElementList: Element[];\n currentIndex: number;\n audioList: SlideAudioItem[];\n currentAudioSequenceIndexes: number[];\n currentStepHasSpeakableElement: boolean;\n currentInteractionElement?: Element;\n canGoPrev: boolean;\n canGoNext: boolean;\n handlePrev: () => void;\n handleNext: () => void;\n}\n\nconst getMarkerElementList = (elementList: Element[]) =>\n elementList.filter((element) => element.is_marker);\n\nconst getMarkerElementIndexes = (elementList: Element[]) =>\n elementList.reduce<number[]>((indexes, element, index) => {\n if (element.is_marker) {\n indexes.push(index);\n }\n\n return indexes;\n }, []);\n\nconst hasPlayableAudio = (element?: Element) =>\n Boolean(\n element?.is_speakable &&\n (element.audio_url || (element.audio_segments?.length ?? 0) > 0)\n );\n\nconst isStreamingAudio = (segments: ElementAudioSegment[] = []) =>\n segments.length > 0 && !segments.some((segment) => segment.is_final);\n\nexport const resolveSlideAudioItemSource = (element: Element) => {\n const audioUrl = element.audio_url?.trim() ?? \"\";\n const audioSegments = element.audio_segments ?? [];\n\n return {\n audioUrl,\n audioSegments,\n isAudioStreaming: !audioUrl && isStreamingAudio(audioSegments),\n };\n};\n\nconst getElementAudioKey = (element: Element, index: number) => {\n const candidateElement = element as Element & {\n element_bid?: string;\n blockBid?: string;\n generated_block_bid?: string;\n };\n\n return (\n candidateElement.element_bid ||\n candidateElement.blockBid ||\n candidateElement.generated_block_bid ||\n `${element.type}:${String(element.sequence_number ?? index)}`\n );\n};\n\nconst getAudioList = (elementList: Element[]) =>\n elementList.reduce<SlideAudioItem[]>((list, element, elementIndex) => {\n if (hasPlayableAudio(element)) {\n const { audioUrl, audioSegments, isAudioStreaming } =\n resolveSlideAudioItemSource(element);\n\n list.push({\n audioKey: getElementAudioKey(element, elementIndex),\n sequenceNumber: element.sequence_number,\n // Keep the completed URL available once it arrives so loading can end.\n audioUrl,\n audioSegments,\n isAudioStreaming,\n element,\n });\n }\n\n return list;\n }, []);\n\nconst getAudioIndexMap = (elementList: Element[]) => {\n const audioIndexMap = new Map<number, number>();\n let audioIndex = 0;\n\n elementList.forEach((element, index) => {\n if (hasPlayableAudio(element)) {\n audioIndexMap.set(index, audioIndex);\n audioIndex += 1;\n }\n });\n\n return audioIndexMap;\n};\n\nconst getSlideAudioSequenceMap = (\n elementList: Element[],\n markerElementIndexes: number[],\n audioIndexMap: Map<number, number>\n) =>\n markerElementIndexes.reduce<Map<number, number[]>>(\n (sequenceMap, startIndex, slideIndex) => {\n const nextMarkerIndex =\n markerElementIndexes[slideIndex + 1] ?? elementList.length;\n const sequenceIndexes: number[] = [];\n\n for (let index = startIndex; index < nextMarkerIndex; index += 1) {\n const element = elementList[index];\n\n if (!hasPlayableAudio(element)) {\n continue;\n }\n\n const audioIndex = audioIndexMap.get(index);\n\n if (audioIndex == null) {\n continue;\n }\n\n sequenceIndexes.push(audioIndex);\n }\n\n sequenceMap.set(slideIndex, sequenceIndexes);\n return sequenceMap;\n },\n new Map<number, number[]>()\n );\n\nconst getInitialSlideIndex = (slideElementList: Element[]) => {\n const visibleIndex = slideElementList.findIndex(\n (element) => element.is_renderable === true\n );\n\n if (visibleIndex >= 0) {\n return visibleIndex;\n }\n\n return slideElementList.findIndex(\n (element) => element.is_renderable !== false\n );\n};\n\nconst getVisibleElement = (element: Element): Element => ({\n ...element,\n is_renderable: true,\n});\n\nconst getCurrentElementList = (\n slideElementList: Element[],\n currentIndex: number\n) => {\n if (currentIndex < 0) {\n return [];\n }\n\n return slideElementList\n .slice(0, currentIndex + 1)\n .reduce<Element[]>((currentList, element) => {\n if (element.type === \"interaction\") {\n return currentList;\n }\n\n const visibleElement = getVisibleElement(element);\n\n if (visibleElement.type === \"diff\") {\n const nextList = applyDiffElement(currentList, visibleElement);\n\n return nextList ?? [...currentList, visibleElement];\n }\n\n if (element.is_new) {\n return [visibleElement];\n }\n\n if (currentList.length === 0) {\n return [visibleElement];\n }\n\n return [...currentList, visibleElement];\n }, []);\n};\n\nconst getStepElementLists = (slideElementList: Element[]) =>\n slideElementList.map((_, index) =>\n getCurrentElementList(slideElementList, index)\n );\n\nconst getStepHasSpeakableElement = (\n elementList: Element[],\n markerElementIndexes: number[],\n currentIndex: number\n) => {\n if (currentIndex < 0) {\n return false;\n }\n\n const startIndex = markerElementIndexes[currentIndex];\n\n if (typeof startIndex !== \"number\") {\n return false;\n }\n\n const nextMarkerIndex =\n markerElementIndexes[currentIndex + 1] ?? elementList.length;\n\n for (let index = startIndex; index < nextMarkerIndex; index += 1) {\n if (elementList[index]?.is_speakable) {\n return true;\n }\n }\n\n return false;\n};\n\nconst hasSameElementReferences = (\n prevElementList: Element[],\n nextElementList: Element[]\n) =>\n prevElementList.length === nextElementList.length &&\n prevElementList.every((element, index) => element === nextElementList[index]);\n\nconst hasSameNumberValues = (prevValues: number[], nextValues: number[]) =>\n prevValues.length === nextValues.length &&\n prevValues.every((value, index) => value === nextValues[index]);\n\nconst useSlide = (elementList: Element[] = []): UseSlideResult => {\n const stableElementListRef = useRef(elementList);\n const stableCurrentAudioSequenceIndexesRef = useRef<number[]>([]);\n const stableElementList = useMemo(() => {\n if (hasSameElementReferences(stableElementListRef.current, elementList)) {\n return stableElementListRef.current;\n }\n\n // Reuse the previous wrapper array when the element references are unchanged.\n stableElementListRef.current = elementList;\n return elementList;\n }, [elementList]);\n const slideElementList = useMemo(\n () => getMarkerElementList(stableElementList),\n [stableElementList]\n );\n const previousSlideElementListRef = useRef(slideElementList);\n const markerElementIndexes = useMemo(\n () => getMarkerElementIndexes(stableElementList),\n [stableElementList]\n );\n const audioList = useMemo(\n () => getAudioList(stableElementList),\n [stableElementList]\n );\n const audioIndexMap = useMemo(\n () => getAudioIndexMap(stableElementList),\n [stableElementList]\n );\n const slideAudioSequenceMap = useMemo(\n () =>\n getSlideAudioSequenceMap(\n stableElementList,\n markerElementIndexes,\n audioIndexMap\n ),\n [audioIndexMap, markerElementIndexes, stableElementList]\n );\n const [currentIndex, setCurrentIndex] = useState(() =>\n getInitialSlideIndex(slideElementList)\n );\n\n useEffect(() => {\n const previousSlideElementList = previousSlideElementListRef.current;\n\n setCurrentIndex((prevIndex) => {\n const resolvedNextIndex = resolveNextSlideIndexAfterMarkerAppend({\n previousIndex: prevIndex,\n previousSlideElementList,\n nextSlideElementList: slideElementList,\n });\n\n if (resolvedNextIndex >= 0) {\n return resolvedNextIndex;\n }\n\n return getInitialSlideIndex(slideElementList);\n });\n\n previousSlideElementListRef.current = slideElementList;\n }, [slideElementList]);\n\n const handlePrev = useCallback(() => {\n setCurrentIndex((prevIndex) => {\n if (prevIndex <= 0) {\n return Math.max(prevIndex, 0);\n }\n\n return Math.max(prevIndex - 1, 0);\n });\n }, []);\n\n const handleNext = useCallback(() => {\n setCurrentIndex((prevIndex) => {\n if (prevIndex < 0) {\n return prevIndex;\n }\n\n return Math.min(prevIndex + 1, slideElementList.length - 1);\n });\n }, [slideElementList.length]);\n\n const canGoPrev = currentIndex > 0;\n const canGoNext =\n currentIndex >= 0 && currentIndex < slideElementList.length - 1;\n const currentStepElement = useMemo(() => {\n if (currentIndex < 0) {\n return undefined;\n }\n\n const element = slideElementList[currentIndex];\n\n if (!element) {\n return undefined;\n }\n\n return getVisibleElement(element);\n }, [currentIndex, slideElementList]);\n const currentElementList = useMemo(\n () => getCurrentElementList(slideElementList, currentIndex),\n [currentIndex, slideElementList]\n );\n const stepElementLists = useMemo(\n () => getStepElementLists(slideElementList),\n [slideElementList]\n );\n const currentAudioSequenceIndexes = useMemo(() => {\n const nextAudioSequenceIndexes =\n slideAudioSequenceMap.get(currentIndex) ?? [];\n\n if (\n hasSameNumberValues(\n stableCurrentAudioSequenceIndexesRef.current,\n nextAudioSequenceIndexes\n )\n ) {\n return stableCurrentAudioSequenceIndexesRef.current;\n }\n\n stableCurrentAudioSequenceIndexesRef.current = nextAudioSequenceIndexes;\n\n return nextAudioSequenceIndexes;\n }, [currentIndex, slideAudioSequenceMap]);\n const currentStepHasSpeakableElement = useMemo(\n () =>\n getStepHasSpeakableElement(\n stableElementList,\n markerElementIndexes,\n currentIndex\n ),\n [currentIndex, markerElementIndexes, stableElementList]\n );\n const currentInteractionElement = useMemo(\n () =>\n currentStepElement?.type === \"interaction\"\n ? currentStepElement\n : undefined,\n [currentStepElement]\n );\n\n return {\n currentElementList,\n stepElementLists,\n slideElementList,\n currentIndex,\n audioList,\n currentAudioSequenceIndexes,\n currentStepHasSpeakableElement,\n currentInteractionElement,\n canGoPrev,\n canGoNext,\n handlePrev,\n handleNext,\n };\n};\n\nexport default useSlide;\n"],"names":["getMarkerElementList","elementList","element","getMarkerElementIndexes","indexes","index","hasPlayableAudio","isStreamingAudio","segments","segment","resolveSlideAudioItemSource","audioUrl","audioSegments","getElementAudioKey","candidateElement","getAudioList","list","elementIndex","isAudioStreaming","getAudioIndexMap","audioIndexMap","audioIndex","getSlideAudioSequenceMap","markerElementIndexes","sequenceMap","startIndex","slideIndex","nextMarkerIndex","sequenceIndexes","getInitialSlideIndex","slideElementList","visibleIndex","getVisibleElement","getCurrentElementList","currentIndex","currentList","visibleElement","applyDiffElement","getStepElementLists","_","getStepHasSpeakableElement","hasSameElementReferences","prevElementList","nextElementList","hasSameNumberValues","prevValues","nextValues","value","useSlide","stableElementListRef","useRef","stableCurrentAudioSequenceIndexesRef","stableElementList","useMemo","previousSlideElementListRef","audioList","slideAudioSequenceMap","setCurrentIndex","useState","useEffect","previousSlideElementList","prevIndex","resolvedNextIndex","resolveNextSlideIndexAfterMarkerAppend","handlePrev","useCallback","handleNext","canGoPrev","canGoNext","currentStepElement","currentElementList","stepElementLists","currentAudioSequenceIndexes","nextAudioSequenceIndexes","currentStepHasSpeakableElement","currentInteractionElement"],"mappings":"sNA8BMA,EAAwBC,GAC5BA,EAAY,OAAQC,GAAYA,EAAQ,SAAS,EAE7CC,EAA2BF,GAC/BA,EAAY,OAAiB,CAACG,EAASF,EAASG,KAC1CH,EAAQ,WACVE,EAAQ,KAAKC,CAAK,EAGbD,GACN,EAAE,EAEDE,EAAoBJ,GACxB,GACEA,GAAS,eACNA,EAAQ,YAAcA,EAAQ,gBAAgB,QAAU,GAAK,IAG9DK,EAAmB,CAACC,EAAkC,KAC1DA,EAAS,OAAS,GAAK,CAACA,EAAS,KAAMC,GAAYA,EAAQ,QAAQ,EAExDC,EAA+BR,GAAqB,CAC/D,MAAMS,EAAWT,EAAQ,WAAW,KAAA,GAAU,GACxCU,EAAgBV,EAAQ,gBAAkB,CAAA,EAEhD,MAAO,CACL,SAAAS,EACA,cAAAC,EACA,iBAAkB,CAACD,GAAYJ,EAAiBK,CAAa,CAAA,CAEjE,EAEMC,EAAqB,CAACX,EAAkBG,IAAkB,CAC9D,MAAMS,EAAmBZ,EAMzB,OACEY,EAAiB,aACjBA,EAAiB,UACjBA,EAAiB,qBACjB,GAAGZ,EAAQ,IAAI,IAAI,OAAOA,EAAQ,iBAAmBG,CAAK,CAAC,EAE/D,EAEMU,EAAgBd,GACpBA,EAAY,OAAyB,CAACe,EAAMd,EAASe,IAAiB,CACpE,GAAIX,EAAiBJ,CAAO,EAAG,CAC7B,KAAM,CAAE,SAAAS,EAAU,cAAAC,EAAe,iBAAAM,CAAA,EAC/BR,EAA4BR,CAAO,EAErCc,EAAK,KAAK,CACR,SAAUH,EAAmBX,EAASe,CAAY,EAClD,eAAgBf,EAAQ,gBAExB,SAAAS,EACA,cAAAC,EACA,iBAAAM,EACA,QAAAhB,CAAA,CACD,CACH,CAEA,OAAOc,CACT,EAAG,EAAE,EAEDG,EAAoBlB,GAA2B,CACnD,MAAMmB,MAAoB,IAC1B,IAAIC,EAAa,EAEjB,OAAApB,EAAY,QAAQ,CAACC,EAASG,IAAU,CAClCC,EAAiBJ,CAAO,IAC1BkB,EAAc,IAAIf,EAAOgB,CAAU,EACnCA,GAAc,EAElB,CAAC,EAEMD,CACT,EAEME,EAA2B,CAC/BrB,EACAsB,EACAH,IAEAG,EAAqB,OACnB,CAACC,EAAaC,EAAYC,IAAe,CACvC,MAAMC,EACJJ,EAAqBG,EAAa,CAAC,GAAKzB,EAAY,OAChD2B,EAA4B,CAAA,EAElC,QAASvB,EAAQoB,EAAYpB,EAAQsB,EAAiBtB,GAAS,EAAG,CAChE,MAAMH,EAAUD,EAAYI,CAAK,EAEjC,GAAI,CAACC,EAAiBJ,CAAO,EAC3B,SAGF,MAAMmB,EAAaD,EAAc,IAAIf,CAAK,EAEtCgB,GAAc,MAIlBO,EAAgB,KAAKP,CAAU,CACjC,CAEA,OAAAG,EAAY,IAAIE,EAAYE,CAAe,EACpCJ,CACT,MACI,GACN,EAEIK,EAAwBC,GAAgC,CAC5D,MAAMC,EAAeD,EAAiB,UACnC5B,GAAYA,EAAQ,gBAAkB,EAAA,EAGzC,OAAI6B,GAAgB,EACXA,EAGFD,EAAiB,UACrB5B,GAAYA,EAAQ,gBAAkB,EAAA,CAE3C,EAEM8B,EAAqB9B,IAA+B,CACxD,GAAGA,EACH,cAAe,EACjB,GAEM+B,EAAwB,CAC5BH,EACAI,IAEIA,EAAe,EACV,CAAA,EAGFJ,EACJ,MAAM,EAAGI,EAAe,CAAC,EACzB,OAAkB,CAACC,EAAajC,IAAY,CAC3C,GAAIA,EAAQ,OAAS,cACnB,OAAOiC,EAGT,MAAMC,EAAiBJ,EAAkB9B,CAAO,EAEhD,OAAIkC,EAAe,OAAS,OACTC,EAAAA,iBAAiBF,EAAaC,CAAc,GAE1C,CAAC,GAAGD,EAAaC,CAAc,EAGhDlC,EAAQ,OACH,CAACkC,CAAc,EAGpBD,EAAY,SAAW,EAClB,CAACC,CAAc,EAGjB,CAAC,GAAGD,EAAaC,CAAc,CACxC,EAAG,CAAA,CAAE,EAGHE,EAAuBR,GAC3BA,EAAiB,IAAI,CAACS,EAAGlC,IACvB4B,EAAsBH,EAAkBzB,CAAK,CAC/C,EAEImC,EAA6B,CACjCvC,EACAsB,EACAW,IACG,CACH,GAAIA,EAAe,EACjB,MAAO,GAGT,MAAMT,EAAaF,EAAqBW,CAAY,EAEpD,GAAI,OAAOT,GAAe,SACxB,MAAO,GAGT,MAAME,EACJJ,EAAqBW,EAAe,CAAC,GAAKjC,EAAY,OAExD,QAASI,EAAQoB,EAAYpB,EAAQsB,EAAiBtB,GAAS,EAC7D,GAAIJ,EAAYI,CAAK,GAAG,aACtB,MAAO,GAIX,MAAO,EACT,EAEMoC,EAA2B,CAC/BC,EACAC,IAEAD,EAAgB,SAAWC,EAAgB,QAC3CD,EAAgB,MAAM,CAACxC,EAASG,IAAUH,IAAYyC,EAAgBtC,CAAK,CAAC,EAExEuC,EAAsB,CAACC,EAAsBC,IACjDD,EAAW,SAAWC,EAAW,QACjCD,EAAW,MAAM,CAACE,EAAO1C,IAAU0C,IAAUD,EAAWzC,CAAK,CAAC,EAE1D2C,EAAW,CAAC/C,EAAyB,KAAuB,CAChE,MAAMgD,EAAuBC,EAAAA,OAAOjD,CAAW,EACzCkD,EAAuCD,EAAAA,OAAiB,EAAE,EAC1DE,EAAoBC,EAAAA,QAAQ,IAC5BZ,EAAyBQ,EAAqB,QAAShD,CAAW,EAC7DgD,EAAqB,SAI9BA,EAAqB,QAAUhD,EACxBA,GACN,CAACA,CAAW,CAAC,EACV6B,EAAmBuB,EAAAA,QACvB,IAAMrD,EAAqBoD,CAAiB,EAC5C,CAACA,CAAiB,CAAA,EAEdE,EAA8BJ,EAAAA,OAAOpB,CAAgB,EACrDP,EAAuB8B,EAAAA,QAC3B,IAAMlD,EAAwBiD,CAAiB,EAC/C,CAACA,CAAiB,CAAA,EAEdG,EAAYF,EAAAA,QAChB,IAAMtC,EAAaqC,CAAiB,EACpC,CAACA,CAAiB,CAAA,EAEdhC,EAAgBiC,EAAAA,QACpB,IAAMlC,EAAiBiC,CAAiB,EACxC,CAACA,CAAiB,CAAA,EAEdI,EAAwBH,EAAAA,QAC5B,IACE/B,EACE8B,EACA7B,EACAH,CAAA,EAEJ,CAACA,EAAeG,EAAsB6B,CAAiB,CAAA,EAEnD,CAAClB,EAAcuB,CAAe,EAAIC,EAAAA,SAAS,IAC/C7B,EAAqBC,CAAgB,CAAA,EAGvC6B,EAAAA,UAAU,IAAM,CACd,MAAMC,EAA2BN,EAA4B,QAE7DG,EAAiBI,GAAc,CAC7B,MAAMC,EAAoBC,EAAAA,uCAAuC,CAC/D,cAAeF,EACf,yBAAAD,EACA,qBAAsB9B,CAAA,CACvB,EAED,OAAIgC,GAAqB,EAChBA,EAGFjC,EAAqBC,CAAgB,CAC9C,CAAC,EAEDwB,EAA4B,QAAUxB,CACxC,EAAG,CAACA,CAAgB,CAAC,EAErB,MAAMkC,EAAaC,EAAAA,YAAY,IAAM,CACnCR,EAAiBI,GACXA,GAAa,EACR,KAAK,IAAIA,EAAW,CAAC,EAGvB,KAAK,IAAIA,EAAY,EAAG,CAAC,CACjC,CACH,EAAG,CAAA,CAAE,EAECK,EAAaD,EAAAA,YAAY,IAAM,CACnCR,EAAiBI,GACXA,EAAY,EACPA,EAGF,KAAK,IAAIA,EAAY,EAAG/B,EAAiB,OAAS,CAAC,CAC3D,CACH,EAAG,CAACA,EAAiB,MAAM,CAAC,EAEtBqC,EAAYjC,EAAe,EAC3BkC,EACJlC,GAAgB,GAAKA,EAAeJ,EAAiB,OAAS,EAC1DuC,EAAqBhB,EAAAA,QAAQ,IAAM,CACvC,GAAInB,EAAe,EACjB,OAGF,MAAMhC,EAAU4B,EAAiBI,CAAY,EAE7C,GAAKhC,EAIL,OAAO8B,EAAkB9B,CAAO,CAClC,EAAG,CAACgC,EAAcJ,CAAgB,CAAC,EAC7BwC,EAAqBjB,EAAAA,QACzB,IAAMpB,EAAsBH,EAAkBI,CAAY,EAC1D,CAACA,EAAcJ,CAAgB,CAAA,EAE3ByC,EAAmBlB,EAAAA,QACvB,IAAMf,EAAoBR,CAAgB,EAC1C,CAACA,CAAgB,CAAA,EAEb0C,EAA8BnB,EAAAA,QAAQ,IAAM,CAChD,MAAMoB,EACJjB,EAAsB,IAAItB,CAAY,GAAK,CAAA,EAE7C,OACEU,EACEO,EAAqC,QACrCsB,CAAA,EAGKtB,EAAqC,SAG9CA,EAAqC,QAAUsB,EAExCA,EACT,EAAG,CAACvC,EAAcsB,CAAqB,CAAC,EAClCkB,EAAiCrB,EAAAA,QACrC,IACEb,EACEY,EACA7B,EACAW,CAAA,EAEJ,CAACA,EAAcX,EAAsB6B,CAAiB,CAAA,EAElDuB,EAA4BtB,EAAAA,QAChC,IACEgB,GAAoB,OAAS,cACzBA,EACA,OACN,CAACA,CAAkB,CAAA,EAGrB,MAAO,CACL,mBAAAC,EACA,iBAAAC,EACA,iBAAAzC,EACA,aAAAI,EACA,UAAAqB,EACA,4BAAAiB,EACA,+BAAAE,EACA,0BAAAC,EACA,UAAAR,EACA,UAAAC,EACA,WAAAJ,EACA,WAAAE,CAAA,CAEJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSlide.es.js","sources":["../../../src/components/Slide/useSlide.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { applyDiffElement } from \"./diff-utils\";\nimport type { Element, ElementAudioSegment } from \"./types\";\nimport { resolveNextSlideIndexAfterMarkerAppend } from \"./utils/streamingNavigation\";\n\nexport interface SlideAudioItem {\n audioKey?: string;\n sequenceNumber?: number;\n audioUrl?: string;\n audioSegments?: ElementAudioSegment[];\n isAudioStreaming?: boolean;\n element?: Element;\n}\n\nexport interface UseSlideResult {\n currentElementList: Element[];\n stepElementLists: Element[][];\n slideElementList: Element[];\n currentIndex: number;\n audioList: SlideAudioItem[];\n currentAudioSequenceIndexes: number[];\n currentStepHasSpeakableElement: boolean;\n currentInteractionElement?: Element;\n canGoPrev: boolean;\n canGoNext: boolean;\n handlePrev: () => void;\n handleNext: () => void;\n}\n\nconst getMarkerElementList = (elementList: Element[]) =>\n elementList.filter((element) => element.is_marker);\n\nconst getMarkerElementIndexes = (elementList: Element[]) =>\n elementList.reduce<number[]>((indexes, element, index) => {\n if (element.is_marker) {\n indexes.push(index);\n }\n\n return indexes;\n }, []);\n\nconst hasPlayableAudio = (element?: Element) =>\n Boolean(\n element?.is_speakable &&\n (element.audio_url || (element.audio_segments?.length ?? 0) > 0)\n );\n\nconst isStreamingAudio = (segments: ElementAudioSegment[] = []) =>\n segments.length > 0 && !segments.some((segment) => segment.is_final);\n\nexport const resolveSlideAudioItemSource = (element: Element) => {\n const audioUrl = element.audio_url?.trim() ?? \"\";\n const audioSegments = element.audio_segments ?? [];\n\n return {\n audioUrl,\n audioSegments,\n isAudioStreaming: !audioUrl && isStreamingAudio(audioSegments),\n };\n};\n\nconst getElementAudioKey = (element: Element, index: number) => {\n const candidateElement = element as Element & {\n element_bid?: string;\n blockBid?: string;\n generated_block_bid?: string;\n };\n\n return (\n candidateElement.element_bid ||\n candidateElement.blockBid ||\n candidateElement.generated_block_bid ||\n `${element.type}:${String(element.sequence_number ?? index)}`\n );\n};\n\nconst getAudioList = (elementList: Element[]) =>\n elementList.reduce<SlideAudioItem[]>((list, element, elementIndex) => {\n if (hasPlayableAudio(element)) {\n const { audioUrl, audioSegments, isAudioStreaming } =\n resolveSlideAudioItemSource(element);\n\n list.push({\n audioKey: getElementAudioKey(element, elementIndex),\n sequenceNumber: element.sequence_number,\n // Keep the completed URL available once it arrives so loading can end.\n audioUrl,\n audioSegments,\n isAudioStreaming,\n element,\n });\n }\n\n return list;\n }, []);\n\nconst getAudioIndexMap = (elementList: Element[]) => {\n const audioIndexMap = new Map<number, number>();\n let audioIndex = 0;\n\n elementList.forEach((element, index) => {\n if (hasPlayableAudio(element)) {\n audioIndexMap.set(index, audioIndex);\n audioIndex += 1;\n }\n });\n\n return audioIndexMap;\n};\n\nconst getSlideAudioSequenceMap = (\n elementList: Element[],\n markerElementIndexes: number[],\n audioIndexMap: Map<number, number>\n) =>\n markerElementIndexes.reduce<Map<number, number[]>>(\n (sequenceMap, startIndex, slideIndex) => {\n const nextMarkerIndex =\n markerElementIndexes[slideIndex + 1] ?? elementList.length;\n const sequenceIndexes: number[] = [];\n\n for (let index = startIndex; index < nextMarkerIndex; index += 1) {\n const element = elementList[index];\n\n if (!hasPlayableAudio(element)) {\n continue;\n }\n\n const audioIndex = audioIndexMap.get(index);\n\n if (audioIndex == null) {\n continue;\n }\n\n sequenceIndexes.push(audioIndex);\n }\n\n sequenceMap.set(slideIndex, sequenceIndexes);\n return sequenceMap;\n },\n new Map<number, number[]>()\n );\n\nconst getInitialSlideIndex = (slideElementList: Element[]) => {\n const visibleIndex = slideElementList.findIndex(\n (element) => element.is_renderable === true\n );\n\n if (visibleIndex >= 0) {\n return visibleIndex;\n }\n\n return slideElementList.findIndex(\n (element) => element.is_renderable !== false\n );\n};\n\nconst getVisibleElement = (element: Element): Element => ({\n ...element,\n is_renderable: true,\n});\n\nconst getCurrentElementList = (\n slideElementList: Element[],\n currentIndex: number\n) => {\n if (currentIndex < 0) {\n return [];\n }\n\n return slideElementList\n .slice(0, currentIndex + 1)\n .reduce<Element[]>((currentList, element) => {\n if (element.type === \"interaction\") {\n return currentList;\n }\n\n const visibleElement = getVisibleElement(element);\n\n if (visibleElement.type === \"diff\") {\n const nextList = applyDiffElement(currentList, visibleElement);\n\n return nextList ?? [...currentList, visibleElement];\n }\n\n if (element.is_new) {\n return [visibleElement];\n }\n\n if (currentList.length === 0) {\n return [visibleElement];\n }\n\n return [...currentList, visibleElement];\n }, []);\n};\n\nconst getStepElementLists = (slideElementList: Element[]) =>\n slideElementList.map((_, index) =>\n getCurrentElementList(slideElementList, index)\n );\n\nconst getStepHasSpeakableElement = (\n elementList: Element[],\n markerElementIndexes: number[],\n currentIndex: number\n) => {\n if (currentIndex < 0) {\n return false;\n }\n\n const startIndex = markerElementIndexes[currentIndex];\n\n if (typeof startIndex !== \"number\") {\n return false;\n }\n\n const nextMarkerIndex =\n markerElementIndexes[currentIndex + 1] ?? elementList.length;\n\n for (let index = startIndex; index < nextMarkerIndex; index += 1) {\n if (elementList[index]?.is_speakable) {\n return true;\n }\n }\n\n return false;\n};\n\nconst hasSameElementReferences = (\n prevElementList: Element[],\n nextElementList: Element[]\n) =>\n prevElementList.length === nextElementList.length &&\n prevElementList.every((element, index) => element === nextElementList[index]);\n\nconst hasSameNumberValues = (prevValues: number[], nextValues: number[]) =>\n prevValues.length === nextValues.length &&\n prevValues.every((value, index) => value === nextValues[index]);\n\nconst useSlide = (elementList: Element[] = []): UseSlideResult => {\n const stableElementListRef = useRef(elementList);\n const stableCurrentAudioSequenceIndexesRef = useRef<number[]>([]);\n const stableElementList = useMemo(() => {\n if (hasSameElementReferences(stableElementListRef.current, elementList)) {\n return stableElementListRef.current;\n }\n\n // Reuse the previous wrapper array when the element references are unchanged.\n stableElementListRef.current = elementList;\n return elementList;\n }, [elementList]);\n const slideElementList = useMemo(\n () => getMarkerElementList(stableElementList),\n [stableElementList]\n );\n const previousSlideElementListRef = useRef(slideElementList);\n const markerElementIndexes = useMemo(\n () => getMarkerElementIndexes(stableElementList),\n [stableElementList]\n );\n const audioList = useMemo(\n () => getAudioList(stableElementList),\n [stableElementList]\n );\n const audioIndexMap = useMemo(\n () => getAudioIndexMap(stableElementList),\n [stableElementList]\n );\n const slideAudioSequenceMap = useMemo(\n () =>\n getSlideAudioSequenceMap(\n stableElementList,\n markerElementIndexes,\n audioIndexMap\n ),\n [audioIndexMap, markerElementIndexes, stableElementList]\n );\n const [currentIndex, setCurrentIndex] = useState(() =>\n getInitialSlideIndex(slideElementList)\n );\n\n useEffect(() => {\n const previousSlideElementList = previousSlideElementListRef.current;\n\n setCurrentIndex((prevIndex) => {\n const resolvedNextIndex = resolveNextSlideIndexAfterMarkerAppend({\n previousIndex: prevIndex,\n previousSlideElementList,\n nextSlideElementList: slideElementList,\n });\n\n if (resolvedNextIndex >= 0) {\n return resolvedNextIndex;\n }\n\n return getInitialSlideIndex(slideElementList);\n });\n\n previousSlideElementListRef.current = slideElementList;\n }, [slideElementList]);\n\n const handlePrev = useCallback(() => {\n setCurrentIndex((prevIndex) => {\n if (prevIndex <= 0) {\n return Math.max(prevIndex, 0);\n }\n\n return Math.max(prevIndex - 1, 0);\n });\n }, []);\n\n const handleNext = useCallback(() => {\n setCurrentIndex((prevIndex) => {\n if (prevIndex < 0) {\n return prevIndex;\n }\n\n return Math.min(prevIndex + 1, slideElementList.length - 1);\n });\n }, [slideElementList.length]);\n\n const canGoPrev = currentIndex > 0;\n const canGoNext =\n currentIndex >= 0 && currentIndex < slideElementList.length - 1;\n const currentStepElement = useMemo(() => {\n if (currentIndex < 0) {\n return undefined;\n }\n\n const element = slideElementList[currentIndex];\n\n if (!element) {\n return undefined;\n }\n\n return getVisibleElement(element);\n }, [currentIndex, slideElementList]);\n const currentElementList = useMemo(\n () => getCurrentElementList(slideElementList, currentIndex),\n [currentIndex, slideElementList]\n );\n const stepElementLists = useMemo(\n () => getStepElementLists(slideElementList),\n [slideElementList]\n );\n const currentAudioSequenceIndexes = useMemo(() => {\n const nextAudioSequenceIndexes =\n slideAudioSequenceMap.get(currentIndex) ?? [];\n\n if (\n hasSameNumberValues(\n stableCurrentAudioSequenceIndexesRef.current,\n nextAudioSequenceIndexes\n )\n ) {\n return stableCurrentAudioSequenceIndexesRef.current;\n }\n\n stableCurrentAudioSequenceIndexesRef.current = nextAudioSequenceIndexes;\n\n return nextAudioSequenceIndexes;\n }, [currentIndex, slideAudioSequenceMap]);\n const currentStepHasSpeakableElement = useMemo(\n () =>\n getStepHasSpeakableElement(\n stableElementList,\n markerElementIndexes,\n currentIndex\n ),\n [currentIndex, markerElementIndexes, stableElementList]\n );\n const currentInteractionElement = useMemo(\n () =>\n currentStepElement?.type === \"interaction\"\n ? currentStepElement\n : undefined,\n [currentStepElement]\n );\n\n return {\n currentElementList,\n stepElementLists,\n slideElementList,\n currentIndex,\n audioList,\n currentAudioSequenceIndexes,\n currentStepHasSpeakableElement,\n currentInteractionElement,\n canGoPrev,\n canGoNext,\n handlePrev,\n handleNext,\n };\n};\n\nexport default useSlide;\n"],"names":["getMarkerElementList","elementList","element","getMarkerElementIndexes","indexes","index","hasPlayableAudio","isStreamingAudio","segments","segment","resolveSlideAudioItemSource","audioUrl","audioSegments","getElementAudioKey","candidateElement","getAudioList","list","elementIndex","isAudioStreaming","getAudioIndexMap","audioIndexMap","audioIndex","getSlideAudioSequenceMap","markerElementIndexes","sequenceMap","startIndex","slideIndex","nextMarkerIndex","sequenceIndexes","getInitialSlideIndex","slideElementList","visibleIndex","getVisibleElement","getCurrentElementList","currentIndex","currentList","visibleElement","applyDiffElement","getStepElementLists","_","getStepHasSpeakableElement","hasSameElementReferences","prevElementList","nextElementList","hasSameNumberValues","prevValues","nextValues","value","useSlide","stableElementListRef","useRef","stableCurrentAudioSequenceIndexesRef","stableElementList","useMemo","previousSlideElementListRef","audioList","slideAudioSequenceMap","setCurrentIndex","useState","useEffect","previousSlideElementList","prevIndex","resolvedNextIndex","resolveNextSlideIndexAfterMarkerAppend","handlePrev","useCallback","handleNext","canGoPrev","canGoNext","currentStepElement","currentElementList","stepElementLists","currentAudioSequenceIndexes","nextAudioSequenceIndexes","currentStepHasSpeakableElement","currentInteractionElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useSlide.es.js","sources":["../../../src/components/Slide/useSlide.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { applyDiffElement } from \"./diff-utils\";\nimport type { Element, ElementAudioSegment } from \"./types\";\nimport { resolveNextSlideIndexAfterMarkerAppend } from \"./utils/streamingNavigation\";\n\nexport interface SlideAudioItem {\n audioKey?: string;\n sequenceNumber?: number;\n audioUrl?: string;\n audioSegments?: ElementAudioSegment[];\n isAudioStreaming?: boolean;\n element?: Element;\n}\n\nexport interface UseSlideResult {\n currentElementList: Element[];\n stepElementLists: Element[][];\n slideElementList: Element[];\n currentIndex: number;\n audioList: SlideAudioItem[];\n currentAudioSequenceIndexes: number[];\n currentStepHasSpeakableElement: boolean;\n currentInteractionElement?: Element;\n canGoPrev: boolean;\n canGoNext: boolean;\n handlePrev: () => void;\n handleNext: () => void;\n}\n\nconst getMarkerElementList = (elementList: Element[]) =>\n elementList.filter((element) => element.is_marker);\n\nconst getMarkerElementIndexes = (elementList: Element[]) =>\n elementList.reduce<number[]>((indexes, element, index) => {\n if (element.is_marker) {\n indexes.push(index);\n }\n\n return indexes;\n }, []);\n\nconst hasPlayableAudio = (element?: Element) =>\n Boolean(\n element?.is_speakable &&\n (element.audio_url || (element.audio_segments?.length ?? 0) > 0)\n );\n\nconst isStreamingAudio = (segments: ElementAudioSegment[] = []) =>\n segments.length > 0 && !segments.some((segment) => segment.is_final);\n\nexport const resolveSlideAudioItemSource = (element: Element) => {\n const audioUrl = element.audio_url?.trim() ?? \"\";\n const audioSegments = element.audio_segments ?? [];\n\n return {\n audioUrl,\n audioSegments,\n isAudioStreaming: !audioUrl && isStreamingAudio(audioSegments),\n };\n};\n\nconst getElementAudioKey = (element: Element, index: number) => {\n const candidateElement = element as Element & {\n element_bid?: string;\n blockBid?: string;\n generated_block_bid?: string;\n };\n\n return (\n candidateElement.element_bid ||\n candidateElement.blockBid ||\n candidateElement.generated_block_bid ||\n `${element.type}:${String(element.sequence_number ?? index)}`\n );\n};\n\nconst getAudioList = (elementList: Element[]) =>\n elementList.reduce<SlideAudioItem[]>((list, element, elementIndex) => {\n if (hasPlayableAudio(element)) {\n const { audioUrl, audioSegments, isAudioStreaming } =\n resolveSlideAudioItemSource(element);\n\n list.push({\n audioKey: getElementAudioKey(element, elementIndex),\n sequenceNumber: element.sequence_number,\n // Keep the completed URL available once it arrives so loading can end.\n audioUrl,\n audioSegments,\n isAudioStreaming,\n element,\n });\n }\n\n return list;\n }, []);\n\nconst getAudioIndexMap = (elementList: Element[]) => {\n const audioIndexMap = new Map<number, number>();\n let audioIndex = 0;\n\n elementList.forEach((element, index) => {\n if (hasPlayableAudio(element)) {\n audioIndexMap.set(index, audioIndex);\n audioIndex += 1;\n }\n });\n\n return audioIndexMap;\n};\n\nconst getSlideAudioSequenceMap = (\n elementList: Element[],\n markerElementIndexes: number[],\n audioIndexMap: Map<number, number>\n) =>\n markerElementIndexes.reduce<Map<number, number[]>>(\n (sequenceMap, startIndex, slideIndex) => {\n const nextMarkerIndex =\n markerElementIndexes[slideIndex + 1] ?? elementList.length;\n const sequenceIndexes: number[] = [];\n\n for (let index = startIndex; index < nextMarkerIndex; index += 1) {\n const element = elementList[index];\n\n if (!hasPlayableAudio(element)) {\n continue;\n }\n\n const audioIndex = audioIndexMap.get(index);\n\n if (audioIndex == null) {\n continue;\n }\n\n sequenceIndexes.push(audioIndex);\n }\n\n sequenceMap.set(slideIndex, sequenceIndexes);\n return sequenceMap;\n },\n new Map<number, number[]>()\n );\n\nconst getInitialSlideIndex = (slideElementList: Element[]) => {\n const visibleIndex = slideElementList.findIndex(\n (element) => element.is_renderable === true\n );\n\n if (visibleIndex >= 0) {\n return visibleIndex;\n }\n\n return slideElementList.findIndex(\n (element) => element.is_renderable !== false\n );\n};\n\nconst getVisibleElement = (element: Element): Element => ({\n ...element,\n is_renderable: true,\n});\n\nconst getCurrentElementList = (\n slideElementList: Element[],\n currentIndex: number\n) => {\n if (currentIndex < 0) {\n return [];\n }\n\n return slideElementList\n .slice(0, currentIndex + 1)\n .reduce<Element[]>((currentList, element) => {\n if (element.type === \"interaction\") {\n return currentList;\n }\n\n const visibleElement = getVisibleElement(element);\n\n if (visibleElement.type === \"diff\") {\n const nextList = applyDiffElement(currentList, visibleElement);\n\n return nextList ?? [...currentList, visibleElement];\n }\n\n if (element.is_new) {\n return [visibleElement];\n }\n\n if (currentList.length === 0) {\n return [visibleElement];\n }\n\n return [...currentList, visibleElement];\n }, []);\n};\n\nconst getStepElementLists = (slideElementList: Element[]) =>\n slideElementList.map((_, index) =>\n getCurrentElementList(slideElementList, index)\n );\n\nconst getStepHasSpeakableElement = (\n elementList: Element[],\n markerElementIndexes: number[],\n currentIndex: number\n) => {\n if (currentIndex < 0) {\n return false;\n }\n\n const startIndex = markerElementIndexes[currentIndex];\n\n if (typeof startIndex !== \"number\") {\n return false;\n }\n\n const nextMarkerIndex =\n markerElementIndexes[currentIndex + 1] ?? elementList.length;\n\n for (let index = startIndex; index < nextMarkerIndex; index += 1) {\n if (elementList[index]?.is_speakable) {\n return true;\n }\n }\n\n return false;\n};\n\nconst hasSameElementReferences = (\n prevElementList: Element[],\n nextElementList: Element[]\n) =>\n prevElementList.length === nextElementList.length &&\n prevElementList.every((element, index) => element === nextElementList[index]);\n\nconst hasSameNumberValues = (prevValues: number[], nextValues: number[]) =>\n prevValues.length === nextValues.length &&\n prevValues.every((value, index) => value === nextValues[index]);\n\nconst useSlide = (elementList: Element[] = []): UseSlideResult => {\n const stableElementListRef = useRef(elementList);\n const stableCurrentAudioSequenceIndexesRef = useRef<number[]>([]);\n const stableElementList = useMemo(() => {\n if (hasSameElementReferences(stableElementListRef.current, elementList)) {\n return stableElementListRef.current;\n }\n\n // Reuse the previous wrapper array when the element references are unchanged.\n stableElementListRef.current = elementList;\n return elementList;\n }, [elementList]);\n const slideElementList = useMemo(\n () => getMarkerElementList(stableElementList),\n [stableElementList]\n );\n const previousSlideElementListRef = useRef(slideElementList);\n const markerElementIndexes = useMemo(\n () => getMarkerElementIndexes(stableElementList),\n [stableElementList]\n );\n const audioList = useMemo(\n () => getAudioList(stableElementList),\n [stableElementList]\n );\n const audioIndexMap = useMemo(\n () => getAudioIndexMap(stableElementList),\n [stableElementList]\n );\n const slideAudioSequenceMap = useMemo(\n () =>\n getSlideAudioSequenceMap(\n stableElementList,\n markerElementIndexes,\n audioIndexMap\n ),\n [audioIndexMap, markerElementIndexes, stableElementList]\n );\n const [currentIndex, setCurrentIndex] = useState(() =>\n getInitialSlideIndex(slideElementList)\n );\n\n useEffect(() => {\n const previousSlideElementList = previousSlideElementListRef.current;\n\n setCurrentIndex((prevIndex) => {\n const resolvedNextIndex = resolveNextSlideIndexAfterMarkerAppend({\n previousIndex: prevIndex,\n previousSlideElementList,\n nextSlideElementList: slideElementList,\n });\n\n if (resolvedNextIndex >= 0) {\n return resolvedNextIndex;\n }\n\n return getInitialSlideIndex(slideElementList);\n });\n\n previousSlideElementListRef.current = slideElementList;\n }, [slideElementList]);\n\n const handlePrev = useCallback(() => {\n setCurrentIndex((prevIndex) => {\n if (prevIndex <= 0) {\n return Math.max(prevIndex, 0);\n }\n\n return Math.max(prevIndex - 1, 0);\n });\n }, []);\n\n const handleNext = useCallback(() => {\n setCurrentIndex((prevIndex) => {\n if (prevIndex < 0) {\n return prevIndex;\n }\n\n return Math.min(prevIndex + 1, slideElementList.length - 1);\n });\n }, [slideElementList.length]);\n\n const canGoPrev = currentIndex > 0;\n const canGoNext =\n currentIndex >= 0 && currentIndex < slideElementList.length - 1;\n const currentStepElement = useMemo(() => {\n if (currentIndex < 0) {\n return undefined;\n }\n\n const element = slideElementList[currentIndex];\n\n if (!element) {\n return undefined;\n }\n\n return getVisibleElement(element);\n }, [currentIndex, slideElementList]);\n const currentElementList = useMemo(\n () => getCurrentElementList(slideElementList, currentIndex),\n [currentIndex, slideElementList]\n );\n const stepElementLists = useMemo(\n () => getStepElementLists(slideElementList),\n [slideElementList]\n );\n const currentAudioSequenceIndexes = useMemo(() => {\n const nextAudioSequenceIndexes =\n slideAudioSequenceMap.get(currentIndex) ?? [];\n\n if (\n hasSameNumberValues(\n stableCurrentAudioSequenceIndexesRef.current,\n nextAudioSequenceIndexes\n )\n ) {\n return stableCurrentAudioSequenceIndexesRef.current;\n }\n\n stableCurrentAudioSequenceIndexesRef.current = nextAudioSequenceIndexes;\n\n return nextAudioSequenceIndexes;\n }, [currentIndex, slideAudioSequenceMap]);\n const currentStepHasSpeakableElement = useMemo(\n () =>\n getStepHasSpeakableElement(\n stableElementList,\n markerElementIndexes,\n currentIndex\n ),\n [currentIndex, markerElementIndexes, stableElementList]\n );\n const currentInteractionElement = useMemo(\n () =>\n currentStepElement?.type === \"interaction\"\n ? currentStepElement\n : undefined,\n [currentStepElement]\n );\n\n return {\n currentElementList,\n stepElementLists,\n slideElementList,\n currentIndex,\n audioList,\n currentAudioSequenceIndexes,\n currentStepHasSpeakableElement,\n currentInteractionElement,\n canGoPrev,\n canGoNext,\n handlePrev,\n handleNext,\n };\n};\n\nexport default useSlide;\n"],"names":["getMarkerElementList","elementList","element","getMarkerElementIndexes","indexes","index","hasPlayableAudio","isStreamingAudio","segments","segment","resolveSlideAudioItemSource","audioUrl","audioSegments","getElementAudioKey","candidateElement","getAudioList","list","elementIndex","isAudioStreaming","getAudioIndexMap","audioIndexMap","audioIndex","getSlideAudioSequenceMap","markerElementIndexes","sequenceMap","startIndex","slideIndex","nextMarkerIndex","sequenceIndexes","getInitialSlideIndex","slideElementList","visibleIndex","getVisibleElement","getCurrentElementList","currentIndex","currentList","visibleElement","applyDiffElement","getStepElementLists","_","getStepHasSpeakableElement","hasSameElementReferences","prevElementList","nextElementList","hasSameNumberValues","prevValues","nextValues","value","useSlide","stableElementListRef","useRef","stableCurrentAudioSequenceIndexesRef","stableElementList","useMemo","previousSlideElementListRef","audioList","slideAudioSequenceMap","setCurrentIndex","useState","useEffect","previousSlideElementList","prevIndex","resolvedNextIndex","resolveNextSlideIndexAfterMarkerAppend","handlePrev","useCallback","handleNext","canGoPrev","canGoNext","currentStepElement","currentElementList","stepElementLists","currentAudioSequenceIndexes","nextAudioSequenceIndexes","currentStepHasSpeakableElement","currentInteractionElement"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i='input, textarea, select, [contenteditable]:not([contenteditable="false"]), [role="textbox"], [role="slider"], [role="listbox"], [role="combobox"], [role="tablist"], [role="menu"], [role="tree"], [role="grid"], [data-player-keyboard-shortcuts-ignore="true"]',s="button, [role='button']",a=new Set;let r=null;const l=e=>{if(!e||typeof e!="object")return null;const t=e;return t.nodeType===3?t.parentElement??null:t},d=e=>{if(e.altKey||e.ctrlKey||e.metaKey)return null;const t=e.key.toLowerCase();if(e.shiftKey)switch(t){case"arrowleft":return"previousSubtitle";case"arrowright":return"nextSubtitle";default:return null}if(e.code==="Space"||t===" "||t==="spacebar")return"togglePlayback";switch(t){case"arrowleft":return"previous";case"arrowright":return"next";case"f":return"fullscreen";case"c":return"subtitle";case"n":return"interaction";default:return null}},u=e=>{const t=l(e);if(!t)return!1;const o=t.tagName?.toLowerCase();if(o==="input"||o==="textarea"||o==="select"||t.isContentEditable)return!0;const n=t.getAttribute?.("contenteditable");return n!=null?n.toLowerCase()!=="false":!!t.closest?.(i)},c=e=>{const t=l(e);return t?t.tagName?.toLowerCase()==="button"?!0:!!t.closest?.(s):!1},y=(e,t)=>e.defaultPrevented||!t||u(e.target)?!0:t==="togglePlayback"&&c(e.target),b=e=>(a.add(e),(!r||!a.has(r))&&(r=e),()=>{a.delete(e),r===e&&(r=a.values().next().value??null)}),f=e=>{if(a.size===0){r=e;return}a.has(e)&&(r=e)},g=e=>r===e;exports.activatePlayerKeyboardShortcutOwner=f;exports.getPlayerKeyboardShortcutAction=d;exports.isActivePlayerKeyboardShortcutOwner=g;exports.isPlayerKeyboardShortcutEditableTarget=u;exports.isPlayerKeyboardShortcutNativeSpaceTarget=c;exports.registerPlayerKeyboardShortcutOwner=b;exports.shouldIgnorePlayerKeyboardShortcutEvent=y;
|
|
2
2
|
//# sourceMappingURL=playerKeyboardShortcuts.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playerKeyboardShortcuts.cjs.js","sources":["../../../../src/components/Slide/utils/playerKeyboardShortcuts.ts"],"sourcesContent":["export type PlayerKeyboardShortcutAction =\n | \"togglePlayback\"\n | \"previous\"\n | \"next\"\n | \"fullscreen\"\n | \"subtitle\"\n | \"interaction\";\n\nexport interface PlayerKeyboardShortcutEventLike {\n altKey?: boolean;\n code?: string;\n ctrlKey?: boolean;\n defaultPrevented?: boolean;\n key: string;\n metaKey?: boolean;\n shiftKey?: boolean;\n target?: EventTarget | null;\n}\n\ntype KeyboardShortcutTarget = EventTarget & {\n closest?: (selectors: string) => unknown;\n getAttribute?: (qualifiedName: string) => string | null;\n isContentEditable?: boolean;\n nodeType?: number;\n parentElement?: Element | null;\n tagName?: string;\n};\n\nconst EDITABLE_SELECTOR =\n 'input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=\"textbox\"], [role=\"slider\"], [role=\"listbox\"], [role=\"combobox\"], [role=\"tablist\"], [role=\"menu\"], [role=\"tree\"], [role=\"grid\"], [data-player-keyboard-shortcuts-ignore=\"true\"]';\n\nconst NATIVE_SPACE_TARGET_SELECTOR = \"button, [role='button']\";\n\nconst playerKeyboardShortcutOwners = new Set<string>();\nlet activePlayerKeyboardShortcutOwnerId: string | null = null;\n\nconst getTargetCandidate = (\n target: EventTarget | null | undefined\n): KeyboardShortcutTarget | null => {\n if (!target || typeof target !== \"object\") {\n return null;\n }\n\n const candidate = target as KeyboardShortcutTarget;\n\n if (candidate.nodeType === 3) {\n return (candidate.parentElement as KeyboardShortcutTarget | null) ?? null;\n }\n\n return candidate;\n};\n\nexport const getPlayerKeyboardShortcutAction = (\n event: PlayerKeyboardShortcutEventLike\n): PlayerKeyboardShortcutAction | null => {\n if (event.altKey || event.ctrlKey || event.metaKey
|
|
1
|
+
{"version":3,"file":"playerKeyboardShortcuts.cjs.js","sources":["../../../../src/components/Slide/utils/playerKeyboardShortcuts.ts"],"sourcesContent":["export type PlayerKeyboardShortcutAction =\n | \"togglePlayback\"\n | \"previous\"\n | \"next\"\n | \"previousSubtitle\"\n | \"nextSubtitle\"\n | \"fullscreen\"\n | \"subtitle\"\n | \"interaction\";\n\nexport interface PlayerKeyboardShortcutEventLike {\n altKey?: boolean;\n code?: string;\n ctrlKey?: boolean;\n defaultPrevented?: boolean;\n key: string;\n metaKey?: boolean;\n shiftKey?: boolean;\n target?: EventTarget | null;\n}\n\ntype KeyboardShortcutTarget = EventTarget & {\n closest?: (selectors: string) => unknown;\n getAttribute?: (qualifiedName: string) => string | null;\n isContentEditable?: boolean;\n nodeType?: number;\n parentElement?: Element | null;\n tagName?: string;\n};\n\nconst EDITABLE_SELECTOR =\n 'input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=\"textbox\"], [role=\"slider\"], [role=\"listbox\"], [role=\"combobox\"], [role=\"tablist\"], [role=\"menu\"], [role=\"tree\"], [role=\"grid\"], [data-player-keyboard-shortcuts-ignore=\"true\"]';\n\nconst NATIVE_SPACE_TARGET_SELECTOR = \"button, [role='button']\";\n\nconst playerKeyboardShortcutOwners = new Set<string>();\nlet activePlayerKeyboardShortcutOwnerId: string | null = null;\n\nconst getTargetCandidate = (\n target: EventTarget | null | undefined\n): KeyboardShortcutTarget | null => {\n if (!target || typeof target !== \"object\") {\n return null;\n }\n\n const candidate = target as KeyboardShortcutTarget;\n\n if (candidate.nodeType === 3) {\n return (candidate.parentElement as KeyboardShortcutTarget | null) ?? null;\n }\n\n return candidate;\n};\n\nexport const getPlayerKeyboardShortcutAction = (\n event: PlayerKeyboardShortcutEventLike\n): PlayerKeyboardShortcutAction | null => {\n if (event.altKey || event.ctrlKey || event.metaKey) {\n return null;\n }\n\n const normalizedKey = event.key.toLowerCase();\n\n if (event.shiftKey) {\n switch (normalizedKey) {\n case \"arrowleft\":\n return \"previousSubtitle\";\n case \"arrowright\":\n return \"nextSubtitle\";\n default:\n return null;\n }\n }\n\n if (\n event.code === \"Space\" ||\n normalizedKey === \" \" ||\n normalizedKey === \"spacebar\"\n ) {\n return \"togglePlayback\";\n }\n\n switch (normalizedKey) {\n case \"arrowleft\":\n return \"previous\";\n case \"arrowright\":\n return \"next\";\n case \"f\":\n return \"fullscreen\";\n case \"c\":\n return \"subtitle\";\n case \"n\":\n return \"interaction\";\n default:\n return null;\n }\n};\n\nexport const isPlayerKeyboardShortcutEditableTarget = (\n target: EventTarget | null | undefined\n) => {\n const candidate = getTargetCandidate(target);\n\n if (!candidate) {\n return false;\n }\n\n const tagName = candidate.tagName?.toLowerCase();\n\n if (tagName === \"input\" || tagName === \"textarea\" || tagName === \"select\") {\n return true;\n }\n\n if (candidate.isContentEditable) {\n return true;\n }\n\n const contentEditable = candidate.getAttribute?.(\"contenteditable\");\n\n if (contentEditable !== undefined && contentEditable !== null) {\n return contentEditable.toLowerCase() !== \"false\";\n }\n\n return Boolean(candidate.closest?.(EDITABLE_SELECTOR));\n};\n\nexport const isPlayerKeyboardShortcutNativeSpaceTarget = (\n target: EventTarget | null | undefined\n) => {\n const candidate = getTargetCandidate(target);\n\n if (!candidate) {\n return false;\n }\n\n const tagName = candidate.tagName?.toLowerCase();\n\n if (tagName === \"button\") {\n return true;\n }\n\n return Boolean(candidate.closest?.(NATIVE_SPACE_TARGET_SELECTOR));\n};\n\nexport const shouldIgnorePlayerKeyboardShortcutEvent = (\n event: PlayerKeyboardShortcutEventLike,\n action: PlayerKeyboardShortcutAction | null\n) => {\n if (event.defaultPrevented || !action) {\n return true;\n }\n\n if (isPlayerKeyboardShortcutEditableTarget(event.target)) {\n return true;\n }\n\n return (\n action === \"togglePlayback\" &&\n isPlayerKeyboardShortcutNativeSpaceTarget(event.target)\n );\n};\n\nexport const registerPlayerKeyboardShortcutOwner = (ownerId: string) => {\n playerKeyboardShortcutOwners.add(ownerId);\n\n if (\n !activePlayerKeyboardShortcutOwnerId ||\n !playerKeyboardShortcutOwners.has(activePlayerKeyboardShortcutOwnerId)\n ) {\n activePlayerKeyboardShortcutOwnerId = ownerId;\n }\n\n return () => {\n playerKeyboardShortcutOwners.delete(ownerId);\n\n if (activePlayerKeyboardShortcutOwnerId !== ownerId) {\n return;\n }\n\n activePlayerKeyboardShortcutOwnerId =\n playerKeyboardShortcutOwners.values().next().value ?? null;\n };\n};\n\nexport const activatePlayerKeyboardShortcutOwner = (ownerId: string) => {\n if (playerKeyboardShortcutOwners.size === 0) {\n activePlayerKeyboardShortcutOwnerId = ownerId;\n return;\n }\n\n if (playerKeyboardShortcutOwners.has(ownerId)) {\n activePlayerKeyboardShortcutOwnerId = ownerId;\n }\n};\n\nexport const isActivePlayerKeyboardShortcutOwner = (ownerId: string) =>\n activePlayerKeyboardShortcutOwnerId === ownerId;\n\nexport const resetPlayerKeyboardShortcutOwnersForTest = () => {\n playerKeyboardShortcutOwners.clear();\n activePlayerKeyboardShortcutOwnerId = null;\n};\n"],"names":["EDITABLE_SELECTOR","NATIVE_SPACE_TARGET_SELECTOR","playerKeyboardShortcutOwners","activePlayerKeyboardShortcutOwnerId","getTargetCandidate","target","candidate","getPlayerKeyboardShortcutAction","event","normalizedKey","isPlayerKeyboardShortcutEditableTarget","tagName","contentEditable","isPlayerKeyboardShortcutNativeSpaceTarget","shouldIgnorePlayerKeyboardShortcutEvent","action","registerPlayerKeyboardShortcutOwner","ownerId","activatePlayerKeyboardShortcutOwner","isActivePlayerKeyboardShortcutOwner"],"mappings":"gFA8BA,MAAMA,EACJ,mQAEIC,EAA+B,0BAE/BC,MAAmC,IACzC,IAAIC,EAAqD,KAEzD,MAAMC,EACJC,GACkC,CAClC,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,OAAO,KAGT,MAAMC,EAAYD,EAElB,OAAIC,EAAU,WAAa,EACjBA,EAAU,eAAmD,KAGhEA,CACT,EAEaC,EACXC,GACwC,CACxC,GAAIA,EAAM,QAAUA,EAAM,SAAWA,EAAM,QACzC,OAAO,KAGT,MAAMC,EAAgBD,EAAM,IAAI,YAAA,EAEhC,GAAIA,EAAM,SACR,OAAQC,EAAA,CACN,IAAK,YACH,MAAO,mBACT,IAAK,aACH,MAAO,eACT,QACE,OAAO,IAAA,CAIb,GACED,EAAM,OAAS,SACfC,IAAkB,KAClBA,IAAkB,WAElB,MAAO,iBAGT,OAAQA,EAAA,CACN,IAAK,YACH,MAAO,WACT,IAAK,aACH,MAAO,OACT,IAAK,IACH,MAAO,aACT,IAAK,IACH,MAAO,WACT,IAAK,IACH,MAAO,cACT,QACE,OAAO,IAAA,CAEb,EAEaC,EACXL,GACG,CACH,MAAMC,EAAYF,EAAmBC,CAAM,EAE3C,GAAI,CAACC,EACH,MAAO,GAGT,MAAMK,EAAUL,EAAU,SAAS,YAAA,EAMnC,GAJIK,IAAY,SAAWA,IAAY,YAAcA,IAAY,UAI7DL,EAAU,kBACZ,MAAO,GAGT,MAAMM,EAAkBN,EAAU,eAAe,iBAAiB,EAElE,OAAqCM,GAAoB,KAChDA,EAAgB,gBAAkB,QAGpC,EAAQN,EAAU,UAAUN,CAAiB,CACtD,EAEaa,EACXR,GACG,CACH,MAAMC,EAAYF,EAAmBC,CAAM,EAE3C,OAAKC,EAIWA,EAAU,SAAS,YAAA,IAEnB,SACP,GAGF,EAAQA,EAAU,UAAUL,CAA4B,EATtD,EAUX,EAEaa,EAA0C,CACrDN,EACAO,IAEIP,EAAM,kBAAoB,CAACO,GAI3BL,EAAuCF,EAAM,MAAM,EAC9C,GAIPO,IAAW,kBACXF,EAA0CL,EAAM,MAAM,EAI7CQ,EAAuCC,IAClDf,EAA6B,IAAIe,CAAO,GAGtC,CAACd,GACD,CAACD,EAA6B,IAAIC,CAAmC,KAErEA,EAAsCc,GAGjC,IAAM,CACXf,EAA6B,OAAOe,CAAO,EAEvCd,IAAwCc,IAI5Cd,EACED,EAA6B,OAAA,EAAS,KAAA,EAAO,OAAS,KAC1D,GAGWgB,EAAuCD,GAAoB,CACtE,GAAIf,EAA6B,OAAS,EAAG,CAC3CC,EAAsCc,EACtC,MACF,CAEIf,EAA6B,IAAIe,CAAO,IAC1Cd,EAAsCc,EAE1C,EAEaE,EAAuCF,GAClDd,IAAwCc"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type PlayerKeyboardShortcutAction = "togglePlayback" | "previous" | "next" | "fullscreen" | "subtitle" | "interaction";
|
|
1
|
+
export type PlayerKeyboardShortcutAction = "togglePlayback" | "previous" | "next" | "previousSubtitle" | "nextSubtitle" | "fullscreen" | "subtitle" | "interaction";
|
|
2
2
|
export interface PlayerKeyboardShortcutEventLike {
|
|
3
3
|
altKey?: boolean;
|
|
4
4
|
code?: string;
|
|
@@ -6,9 +6,18 @@ const l = (e) => {
|
|
|
6
6
|
const t = e;
|
|
7
7
|
return t.nodeType === 3 ? t.parentElement ?? null : t;
|
|
8
8
|
}, d = (e) => {
|
|
9
|
-
if (e.altKey || e.ctrlKey || e.metaKey
|
|
9
|
+
if (e.altKey || e.ctrlKey || e.metaKey)
|
|
10
10
|
return null;
|
|
11
11
|
const t = e.key.toLowerCase();
|
|
12
|
+
if (e.shiftKey)
|
|
13
|
+
switch (t) {
|
|
14
|
+
case "arrowleft":
|
|
15
|
+
return "previousSubtitle";
|
|
16
|
+
case "arrowright":
|
|
17
|
+
return "nextSubtitle";
|
|
18
|
+
default:
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
12
21
|
if (e.code === "Space" || t === " " || t === "spacebar")
|
|
13
22
|
return "togglePlayback";
|
|
14
23
|
switch (t) {
|
|
@@ -37,9 +46,9 @@ const l = (e) => {
|
|
|
37
46
|
}, i = (e) => {
|
|
38
47
|
const t = l(e);
|
|
39
48
|
return t ? t.tagName?.toLowerCase() === "button" ? !0 : !!t.closest?.(c) : !1;
|
|
40
|
-
}, b = (e, t) => e.defaultPrevented || !t || s(e.target) ? !0 : t === "togglePlayback" && i(e.target),
|
|
49
|
+
}, b = (e, t) => e.defaultPrevented || !t || s(e.target) ? !0 : t === "togglePlayback" && i(e.target), f = (e) => (a.add(e), (!r || !a.has(r)) && (r = e), () => {
|
|
41
50
|
a.delete(e), r === e && (r = a.values().next().value ?? null);
|
|
42
|
-
}),
|
|
51
|
+
}), y = (e) => {
|
|
43
52
|
if (a.size === 0) {
|
|
44
53
|
r = e;
|
|
45
54
|
return;
|
|
@@ -47,12 +56,12 @@ const l = (e) => {
|
|
|
47
56
|
a.has(e) && (r = e);
|
|
48
57
|
}, g = (e) => r === e;
|
|
49
58
|
export {
|
|
50
|
-
|
|
59
|
+
y as activatePlayerKeyboardShortcutOwner,
|
|
51
60
|
d as getPlayerKeyboardShortcutAction,
|
|
52
61
|
g as isActivePlayerKeyboardShortcutOwner,
|
|
53
62
|
s as isPlayerKeyboardShortcutEditableTarget,
|
|
54
63
|
i as isPlayerKeyboardShortcutNativeSpaceTarget,
|
|
55
|
-
|
|
64
|
+
f as registerPlayerKeyboardShortcutOwner,
|
|
56
65
|
b as shouldIgnorePlayerKeyboardShortcutEvent
|
|
57
66
|
};
|
|
58
67
|
//# sourceMappingURL=playerKeyboardShortcuts.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playerKeyboardShortcuts.es.js","sources":["../../../../src/components/Slide/utils/playerKeyboardShortcuts.ts"],"sourcesContent":["export type PlayerKeyboardShortcutAction =\n | \"togglePlayback\"\n | \"previous\"\n | \"next\"\n | \"fullscreen\"\n | \"subtitle\"\n | \"interaction\";\n\nexport interface PlayerKeyboardShortcutEventLike {\n altKey?: boolean;\n code?: string;\n ctrlKey?: boolean;\n defaultPrevented?: boolean;\n key: string;\n metaKey?: boolean;\n shiftKey?: boolean;\n target?: EventTarget | null;\n}\n\ntype KeyboardShortcutTarget = EventTarget & {\n closest?: (selectors: string) => unknown;\n getAttribute?: (qualifiedName: string) => string | null;\n isContentEditable?: boolean;\n nodeType?: number;\n parentElement?: Element | null;\n tagName?: string;\n};\n\nconst EDITABLE_SELECTOR =\n 'input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=\"textbox\"], [role=\"slider\"], [role=\"listbox\"], [role=\"combobox\"], [role=\"tablist\"], [role=\"menu\"], [role=\"tree\"], [role=\"grid\"], [data-player-keyboard-shortcuts-ignore=\"true\"]';\n\nconst NATIVE_SPACE_TARGET_SELECTOR = \"button, [role='button']\";\n\nconst playerKeyboardShortcutOwners = new Set<string>();\nlet activePlayerKeyboardShortcutOwnerId: string | null = null;\n\nconst getTargetCandidate = (\n target: EventTarget | null | undefined\n): KeyboardShortcutTarget | null => {\n if (!target || typeof target !== \"object\") {\n return null;\n }\n\n const candidate = target as KeyboardShortcutTarget;\n\n if (candidate.nodeType === 3) {\n return (candidate.parentElement as KeyboardShortcutTarget | null) ?? null;\n }\n\n return candidate;\n};\n\nexport const getPlayerKeyboardShortcutAction = (\n event: PlayerKeyboardShortcutEventLike\n): PlayerKeyboardShortcutAction | null => {\n if (event.altKey || event.ctrlKey || event.metaKey
|
|
1
|
+
{"version":3,"file":"playerKeyboardShortcuts.es.js","sources":["../../../../src/components/Slide/utils/playerKeyboardShortcuts.ts"],"sourcesContent":["export type PlayerKeyboardShortcutAction =\n | \"togglePlayback\"\n | \"previous\"\n | \"next\"\n | \"previousSubtitle\"\n | \"nextSubtitle\"\n | \"fullscreen\"\n | \"subtitle\"\n | \"interaction\";\n\nexport interface PlayerKeyboardShortcutEventLike {\n altKey?: boolean;\n code?: string;\n ctrlKey?: boolean;\n defaultPrevented?: boolean;\n key: string;\n metaKey?: boolean;\n shiftKey?: boolean;\n target?: EventTarget | null;\n}\n\ntype KeyboardShortcutTarget = EventTarget & {\n closest?: (selectors: string) => unknown;\n getAttribute?: (qualifiedName: string) => string | null;\n isContentEditable?: boolean;\n nodeType?: number;\n parentElement?: Element | null;\n tagName?: string;\n};\n\nconst EDITABLE_SELECTOR =\n 'input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [role=\"textbox\"], [role=\"slider\"], [role=\"listbox\"], [role=\"combobox\"], [role=\"tablist\"], [role=\"menu\"], [role=\"tree\"], [role=\"grid\"], [data-player-keyboard-shortcuts-ignore=\"true\"]';\n\nconst NATIVE_SPACE_TARGET_SELECTOR = \"button, [role='button']\";\n\nconst playerKeyboardShortcutOwners = new Set<string>();\nlet activePlayerKeyboardShortcutOwnerId: string | null = null;\n\nconst getTargetCandidate = (\n target: EventTarget | null | undefined\n): KeyboardShortcutTarget | null => {\n if (!target || typeof target !== \"object\") {\n return null;\n }\n\n const candidate = target as KeyboardShortcutTarget;\n\n if (candidate.nodeType === 3) {\n return (candidate.parentElement as KeyboardShortcutTarget | null) ?? null;\n }\n\n return candidate;\n};\n\nexport const getPlayerKeyboardShortcutAction = (\n event: PlayerKeyboardShortcutEventLike\n): PlayerKeyboardShortcutAction | null => {\n if (event.altKey || event.ctrlKey || event.metaKey) {\n return null;\n }\n\n const normalizedKey = event.key.toLowerCase();\n\n if (event.shiftKey) {\n switch (normalizedKey) {\n case \"arrowleft\":\n return \"previousSubtitle\";\n case \"arrowright\":\n return \"nextSubtitle\";\n default:\n return null;\n }\n }\n\n if (\n event.code === \"Space\" ||\n normalizedKey === \" \" ||\n normalizedKey === \"spacebar\"\n ) {\n return \"togglePlayback\";\n }\n\n switch (normalizedKey) {\n case \"arrowleft\":\n return \"previous\";\n case \"arrowright\":\n return \"next\";\n case \"f\":\n return \"fullscreen\";\n case \"c\":\n return \"subtitle\";\n case \"n\":\n return \"interaction\";\n default:\n return null;\n }\n};\n\nexport const isPlayerKeyboardShortcutEditableTarget = (\n target: EventTarget | null | undefined\n) => {\n const candidate = getTargetCandidate(target);\n\n if (!candidate) {\n return false;\n }\n\n const tagName = candidate.tagName?.toLowerCase();\n\n if (tagName === \"input\" || tagName === \"textarea\" || tagName === \"select\") {\n return true;\n }\n\n if (candidate.isContentEditable) {\n return true;\n }\n\n const contentEditable = candidate.getAttribute?.(\"contenteditable\");\n\n if (contentEditable !== undefined && contentEditable !== null) {\n return contentEditable.toLowerCase() !== \"false\";\n }\n\n return Boolean(candidate.closest?.(EDITABLE_SELECTOR));\n};\n\nexport const isPlayerKeyboardShortcutNativeSpaceTarget = (\n target: EventTarget | null | undefined\n) => {\n const candidate = getTargetCandidate(target);\n\n if (!candidate) {\n return false;\n }\n\n const tagName = candidate.tagName?.toLowerCase();\n\n if (tagName === \"button\") {\n return true;\n }\n\n return Boolean(candidate.closest?.(NATIVE_SPACE_TARGET_SELECTOR));\n};\n\nexport const shouldIgnorePlayerKeyboardShortcutEvent = (\n event: PlayerKeyboardShortcutEventLike,\n action: PlayerKeyboardShortcutAction | null\n) => {\n if (event.defaultPrevented || !action) {\n return true;\n }\n\n if (isPlayerKeyboardShortcutEditableTarget(event.target)) {\n return true;\n }\n\n return (\n action === \"togglePlayback\" &&\n isPlayerKeyboardShortcutNativeSpaceTarget(event.target)\n );\n};\n\nexport const registerPlayerKeyboardShortcutOwner = (ownerId: string) => {\n playerKeyboardShortcutOwners.add(ownerId);\n\n if (\n !activePlayerKeyboardShortcutOwnerId ||\n !playerKeyboardShortcutOwners.has(activePlayerKeyboardShortcutOwnerId)\n ) {\n activePlayerKeyboardShortcutOwnerId = ownerId;\n }\n\n return () => {\n playerKeyboardShortcutOwners.delete(ownerId);\n\n if (activePlayerKeyboardShortcutOwnerId !== ownerId) {\n return;\n }\n\n activePlayerKeyboardShortcutOwnerId =\n playerKeyboardShortcutOwners.values().next().value ?? null;\n };\n};\n\nexport const activatePlayerKeyboardShortcutOwner = (ownerId: string) => {\n if (playerKeyboardShortcutOwners.size === 0) {\n activePlayerKeyboardShortcutOwnerId = ownerId;\n return;\n }\n\n if (playerKeyboardShortcutOwners.has(ownerId)) {\n activePlayerKeyboardShortcutOwnerId = ownerId;\n }\n};\n\nexport const isActivePlayerKeyboardShortcutOwner = (ownerId: string) =>\n activePlayerKeyboardShortcutOwnerId === ownerId;\n\nexport const resetPlayerKeyboardShortcutOwnersForTest = () => {\n playerKeyboardShortcutOwners.clear();\n activePlayerKeyboardShortcutOwnerId = null;\n};\n"],"names":["EDITABLE_SELECTOR","NATIVE_SPACE_TARGET_SELECTOR","playerKeyboardShortcutOwners","activePlayerKeyboardShortcutOwnerId","getTargetCandidate","target","candidate","getPlayerKeyboardShortcutAction","event","normalizedKey","isPlayerKeyboardShortcutEditableTarget","tagName","contentEditable","isPlayerKeyboardShortcutNativeSpaceTarget","shouldIgnorePlayerKeyboardShortcutEvent","action","registerPlayerKeyboardShortcutOwner","ownerId","activatePlayerKeyboardShortcutOwner","isActivePlayerKeyboardShortcutOwner"],"mappings":"AA8BA,MAAMA,IACJ,oQAEIC,IAA+B,2BAE/BC,wBAAmC,IAAA;AACzC,IAAIC,IAAqD;AAEzD,MAAMC,IAAqB,CACzBC,MACkC;AAClC,MAAI,CAACA,KAAU,OAAOA,KAAW;AAC/B,WAAO;AAGT,QAAMC,IAAYD;AAElB,SAAIC,EAAU,aAAa,IACjBA,EAAU,iBAAmD,OAGhEA;AACT,GAEaC,IAAkC,CAC7CC,MACwC;AACxC,MAAIA,EAAM,UAAUA,EAAM,WAAWA,EAAM;AACzC,WAAO;AAGT,QAAMC,IAAgBD,EAAM,IAAI,YAAA;AAEhC,MAAIA,EAAM;AACR,YAAQC,GAAA;AAAA,MACN,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IAAA;AAIb,MACED,EAAM,SAAS,WACfC,MAAkB,OAClBA,MAAkB;AAElB,WAAO;AAGT,UAAQA,GAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb,GAEaC,IAAyC,CACpDL,MACG;AACH,QAAMC,IAAYF,EAAmBC,CAAM;AAE3C,MAAI,CAACC;AACH,WAAO;AAGT,QAAMK,IAAUL,EAAU,SAAS,YAAA;AAMnC,MAJIK,MAAY,WAAWA,MAAY,cAAcA,MAAY,YAI7DL,EAAU;AACZ,WAAO;AAGT,QAAMM,IAAkBN,EAAU,eAAe,iBAAiB;AAElE,SAAqCM,KAAoB,OAChDA,EAAgB,kBAAkB,UAGpC,EAAQN,EAAU,UAAUN,CAAiB;AACtD,GAEaa,IAA4C,CACvDR,MACG;AACH,QAAMC,IAAYF,EAAmBC,CAAM;AAE3C,SAAKC,IAIWA,EAAU,SAAS,YAAA,MAEnB,WACP,KAGF,EAAQA,EAAU,UAAUL,CAA4B,IATtD;AAUX,GAEaa,IAA0C,CACrDN,GACAO,MAEIP,EAAM,oBAAoB,CAACO,KAI3BL,EAAuCF,EAAM,MAAM,IAC9C,KAIPO,MAAW,oBACXF,EAA0CL,EAAM,MAAM,GAI7CQ,IAAsC,CAACC,OAClDf,EAA6B,IAAIe,CAAO,IAGtC,CAACd,KACD,CAACD,EAA6B,IAAIC,CAAmC,OAErEA,IAAsCc,IAGjC,MAAM;AAGX,EAFAf,EAA6B,OAAOe,CAAO,GAEvCd,MAAwCc,MAI5Cd,IACED,EAA6B,OAAA,EAAS,KAAA,EAAO,SAAS;AAC1D,IAGWgB,IAAsC,CAACD,MAAoB;AACtE,MAAIf,EAA6B,SAAS,GAAG;AAC3C,IAAAC,IAAsCc;AACtC;AAAA,EACF;AAEA,EAAIf,EAA6B,IAAIe,CAAO,MAC1Cd,IAAsCc;AAE1C,GAEaE,IAAsC,CAACF,MAClDd,MAAwCc;"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=(e=[])=>e.reduce((o,t)=>o+Math.max(Number(t?.duration_ms??0),0),0),g=(e=[],o)=>{if(e.length===0)return!1;const t=Math.max(Number(o),0),n=u(e),a=e[e.length-1];return t<n||t===n&&!!a?.is_final},c=(e=[],o)=>{const t=Math.max(Number(o),0);let n=0;for(let a=0;a<e.length;a+=1){const r=e[a],s=Math.max(Number(r?.duration_ms??0),0),i=n+s,m=a===e.length-1,l=!!r?.is_final;if(t<i||s===0&&t===n&&(!m||l)||m&&l&&t>=i)return{segmentIndex:a,segmentTimeSeconds:Math.min(Math.max(t-n,0),s)/1e3};n=i}return null};exports.getAudioSegmentsDurationMs=u;exports.isPlaybackTimeCoveredBySegments=g;exports.resolveSegmentSeekTarget=c;
|
|
2
|
+
//# sourceMappingURL=segmentSeek.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segmentSeek.cjs.js","sources":["../../../../src/components/Slide/utils/segmentSeek.ts"],"sourcesContent":["import type { SlideAudioItem } from \"../useSlide\";\n\nexport interface SegmentSeekTarget {\n segmentIndex: number;\n segmentTimeSeconds: number;\n}\n\nexport const getAudioSegmentsDurationMs = (\n segments: NonNullable<SlideAudioItem[\"audioSegments\"]> = []\n) =>\n segments.reduce(\n (totalDurationMs, segment) =>\n totalDurationMs + Math.max(Number(segment?.duration_ms ?? 0), 0),\n 0\n );\n\nexport const isPlaybackTimeCoveredBySegments = (\n segments: NonNullable<SlideAudioItem[\"audioSegments\"]> = [],\n timeMs: number\n) => {\n if (segments.length === 0) {\n return false;\n }\n\n const normalizedTimeMs = Math.max(Number(timeMs), 0);\n const loadedDurationMs = getAudioSegmentsDurationMs(segments);\n const lastSegment = segments[segments.length - 1];\n\n return (\n normalizedTimeMs < loadedDurationMs ||\n (normalizedTimeMs === loadedDurationMs && Boolean(lastSegment?.is_final))\n );\n};\n\nexport const resolveSegmentSeekTarget = (\n segments: NonNullable<SlideAudioItem[\"audioSegments\"]> = [],\n timeMs: number\n): SegmentSeekTarget | null => {\n const normalizedTimeMs = Math.max(Number(timeMs), 0);\n let segmentStartTimeMs = 0;\n\n for (let index = 0; index < segments.length; index += 1) {\n const segment = segments[index];\n const durationMs = Math.max(Number(segment?.duration_ms ?? 0), 0);\n const segmentEndTimeMs = segmentStartTimeMs + durationMs;\n const isLastSegment = index === segments.length - 1;\n const isFinalSegment = Boolean(segment?.is_final);\n\n if (\n normalizedTimeMs < segmentEndTimeMs ||\n (durationMs === 0 &&\n normalizedTimeMs === segmentStartTimeMs &&\n (!isLastSegment || isFinalSegment)) ||\n (isLastSegment && isFinalSegment && normalizedTimeMs >= segmentEndTimeMs)\n ) {\n return {\n segmentIndex: index,\n segmentTimeSeconds:\n Math.min(\n Math.max(normalizedTimeMs - segmentStartTimeMs, 0),\n durationMs\n ) / 1000,\n };\n }\n\n segmentStartTimeMs = segmentEndTimeMs;\n }\n\n return null;\n};\n"],"names":["getAudioSegmentsDurationMs","segments","totalDurationMs","segment","isPlaybackTimeCoveredBySegments","timeMs","normalizedTimeMs","loadedDurationMs","lastSegment","resolveSegmentSeekTarget","segmentStartTimeMs","index","durationMs","segmentEndTimeMs","isLastSegment","isFinalSegment"],"mappings":"gFAOO,MAAMA,EAA6B,CACxCC,EAAyD,CAAA,IAEzDA,EAAS,OACP,CAACC,EAAiBC,IAChBD,EAAkB,KAAK,IAAI,OAAOC,GAAS,aAAe,CAAC,EAAG,CAAC,EACjE,CACF,EAEWC,EAAkC,CAC7CH,EAAyD,CAAA,EACzDI,IACG,CACH,GAAIJ,EAAS,SAAW,EACtB,MAAO,GAGT,MAAMK,EAAmB,KAAK,IAAI,OAAOD,CAAM,EAAG,CAAC,EAC7CE,EAAmBP,EAA2BC,CAAQ,EACtDO,EAAcP,EAASA,EAAS,OAAS,CAAC,EAEhD,OACEK,EAAmBC,GAClBD,IAAqBC,GAAoB,EAAQC,GAAa,QAEnE,EAEaC,EAA2B,CACtCR,EAAyD,CAAA,EACzDI,IAC6B,CAC7B,MAAMC,EAAmB,KAAK,IAAI,OAAOD,CAAM,EAAG,CAAC,EACnD,IAAIK,EAAqB,EAEzB,QAASC,EAAQ,EAAGA,EAAQV,EAAS,OAAQU,GAAS,EAAG,CACvD,MAAMR,EAAUF,EAASU,CAAK,EACxBC,EAAa,KAAK,IAAI,OAAOT,GAAS,aAAe,CAAC,EAAG,CAAC,EAC1DU,EAAmBH,EAAqBE,EACxCE,EAAgBH,IAAUV,EAAS,OAAS,EAC5Cc,EAAiB,EAAQZ,GAAS,SAExC,GACEG,EAAmBO,GAClBD,IAAe,GACdN,IAAqBI,IACpB,CAACI,GAAiBC,IACpBD,GAAiBC,GAAkBT,GAAoBO,EAExD,MAAO,CACL,aAAcF,EACd,mBACE,KAAK,IACH,KAAK,IAAIL,EAAmBI,EAAoB,CAAC,EACjDE,CAAA,EACE,GAAA,EAIVF,EAAqBG,CACvB,CAEA,OAAO,IACT"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SlideAudioItem } from '../useSlide';
|
|
2
|
+
export interface SegmentSeekTarget {
|
|
3
|
+
segmentIndex: number;
|
|
4
|
+
segmentTimeSeconds: number;
|
|
5
|
+
}
|
|
6
|
+
export declare const getAudioSegmentsDurationMs: (segments?: NonNullable<SlideAudioItem["audioSegments"]>) => number;
|
|
7
|
+
export declare const isPlaybackTimeCoveredBySegments: (segments: NonNullable<SlideAudioItem["audioSegments"]> | undefined, timeMs: number) => boolean;
|
|
8
|
+
export declare const resolveSegmentSeekTarget: (segments: NonNullable<SlideAudioItem["audioSegments"]> | undefined, timeMs: number) => SegmentSeekTarget | null;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const u = (e = []) => e.reduce(
|
|
2
|
+
(o, t) => o + Math.max(Number(t?.duration_ms ?? 0), 0),
|
|
3
|
+
0
|
|
4
|
+
), c = (e = [], o) => {
|
|
5
|
+
if (e.length === 0)
|
|
6
|
+
return !1;
|
|
7
|
+
const t = Math.max(Number(o), 0), n = u(e), a = e[e.length - 1];
|
|
8
|
+
return t < n || t === n && !!a?.is_final;
|
|
9
|
+
}, d = (e = [], o) => {
|
|
10
|
+
const t = Math.max(Number(o), 0);
|
|
11
|
+
let n = 0;
|
|
12
|
+
for (let a = 0; a < e.length; a += 1) {
|
|
13
|
+
const m = e[a], s = Math.max(Number(m?.duration_ms ?? 0), 0), i = n + s, r = a === e.length - 1, l = !!m?.is_final;
|
|
14
|
+
if (t < i || s === 0 && t === n && (!r || l) || r && l && t >= i)
|
|
15
|
+
return {
|
|
16
|
+
segmentIndex: a,
|
|
17
|
+
segmentTimeSeconds: Math.min(
|
|
18
|
+
Math.max(t - n, 0),
|
|
19
|
+
s
|
|
20
|
+
) / 1e3
|
|
21
|
+
};
|
|
22
|
+
n = i;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
26
|
+
export {
|
|
27
|
+
u as getAudioSegmentsDurationMs,
|
|
28
|
+
c as isPlaybackTimeCoveredBySegments,
|
|
29
|
+
d as resolveSegmentSeekTarget
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=segmentSeek.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segmentSeek.es.js","sources":["../../../../src/components/Slide/utils/segmentSeek.ts"],"sourcesContent":["import type { SlideAudioItem } from \"../useSlide\";\n\nexport interface SegmentSeekTarget {\n segmentIndex: number;\n segmentTimeSeconds: number;\n}\n\nexport const getAudioSegmentsDurationMs = (\n segments: NonNullable<SlideAudioItem[\"audioSegments\"]> = []\n) =>\n segments.reduce(\n (totalDurationMs, segment) =>\n totalDurationMs + Math.max(Number(segment?.duration_ms ?? 0), 0),\n 0\n );\n\nexport const isPlaybackTimeCoveredBySegments = (\n segments: NonNullable<SlideAudioItem[\"audioSegments\"]> = [],\n timeMs: number\n) => {\n if (segments.length === 0) {\n return false;\n }\n\n const normalizedTimeMs = Math.max(Number(timeMs), 0);\n const loadedDurationMs = getAudioSegmentsDurationMs(segments);\n const lastSegment = segments[segments.length - 1];\n\n return (\n normalizedTimeMs < loadedDurationMs ||\n (normalizedTimeMs === loadedDurationMs && Boolean(lastSegment?.is_final))\n );\n};\n\nexport const resolveSegmentSeekTarget = (\n segments: NonNullable<SlideAudioItem[\"audioSegments\"]> = [],\n timeMs: number\n): SegmentSeekTarget | null => {\n const normalizedTimeMs = Math.max(Number(timeMs), 0);\n let segmentStartTimeMs = 0;\n\n for (let index = 0; index < segments.length; index += 1) {\n const segment = segments[index];\n const durationMs = Math.max(Number(segment?.duration_ms ?? 0), 0);\n const segmentEndTimeMs = segmentStartTimeMs + durationMs;\n const isLastSegment = index === segments.length - 1;\n const isFinalSegment = Boolean(segment?.is_final);\n\n if (\n normalizedTimeMs < segmentEndTimeMs ||\n (durationMs === 0 &&\n normalizedTimeMs === segmentStartTimeMs &&\n (!isLastSegment || isFinalSegment)) ||\n (isLastSegment && isFinalSegment && normalizedTimeMs >= segmentEndTimeMs)\n ) {\n return {\n segmentIndex: index,\n segmentTimeSeconds:\n Math.min(\n Math.max(normalizedTimeMs - segmentStartTimeMs, 0),\n durationMs\n ) / 1000,\n };\n }\n\n segmentStartTimeMs = segmentEndTimeMs;\n }\n\n return null;\n};\n"],"names":["getAudioSegmentsDurationMs","segments","totalDurationMs","segment","isPlaybackTimeCoveredBySegments","timeMs","normalizedTimeMs","loadedDurationMs","lastSegment","resolveSegmentSeekTarget","segmentStartTimeMs","index","durationMs","segmentEndTimeMs","isLastSegment","isFinalSegment"],"mappings":"AAOO,MAAMA,IAA6B,CACxCC,IAAyD,CAAA,MAEzDA,EAAS;AAAA,EACP,CAACC,GAAiBC,MAChBD,IAAkB,KAAK,IAAI,OAAOC,GAAS,eAAe,CAAC,GAAG,CAAC;AAAA,EACjE;AACF,GAEWC,IAAkC,CAC7CH,IAAyD,CAAA,GACzDI,MACG;AACH,MAAIJ,EAAS,WAAW;AACtB,WAAO;AAGT,QAAMK,IAAmB,KAAK,IAAI,OAAOD,CAAM,GAAG,CAAC,GAC7CE,IAAmBP,EAA2BC,CAAQ,GACtDO,IAAcP,EAASA,EAAS,SAAS,CAAC;AAEhD,SACEK,IAAmBC,KAClBD,MAAqBC,KAAoB,EAAQC,GAAa;AAEnE,GAEaC,IAA2B,CACtCR,IAAyD,CAAA,GACzDI,MAC6B;AAC7B,QAAMC,IAAmB,KAAK,IAAI,OAAOD,CAAM,GAAG,CAAC;AACnD,MAAIK,IAAqB;AAEzB,WAASC,IAAQ,GAAGA,IAAQV,EAAS,QAAQU,KAAS,GAAG;AACvD,UAAMR,IAAUF,EAASU,CAAK,GACxBC,IAAa,KAAK,IAAI,OAAOT,GAAS,eAAe,CAAC,GAAG,CAAC,GAC1DU,IAAmBH,IAAqBE,GACxCE,IAAgBH,MAAUV,EAAS,SAAS,GAC5Cc,IAAiB,EAAQZ,GAAS;AAExC,QACEG,IAAmBO,KAClBD,MAAe,KACdN,MAAqBI,MACpB,CAACI,KAAiBC,MACpBD,KAAiBC,KAAkBT,KAAoBO;AAExD,aAAO;AAAA,QACL,cAAcF;AAAA,QACd,oBACE,KAAK;AAAA,UACH,KAAK,IAAIL,IAAmBI,GAAoB,CAAC;AAAA,UACjDE;AAAA,QAAA,IACE;AAAA,MAAA;AAIV,IAAAF,IAAqBG;AAAA,EACvB;AAEA,SAAO;AACT;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamingNavigation.cjs.js","sources":["../../../../src/components/Slide/utils/streamingNavigation.ts"],"sourcesContent":["import type { Element } from \"../types\";\n\ninterface ResolveNextSlideIndexParams {\n previousIndex: number;\n previousSlideElementList: Element[];\n nextSlideElementList: Element[];\n}\n\nconst isResolvedInteractionElement = (element?: Element) =>\n Boolean(\n element?.type === \"interaction\" &&\n
|
|
1
|
+
{"version":3,"file":"streamingNavigation.cjs.js","sources":["../../../../src/components/Slide/utils/streamingNavigation.ts"],"sourcesContent":["import type { Element } from \"../types\";\n\ninterface ResolveNextSlideIndexParams {\n previousIndex: number;\n previousSlideElementList: Element[];\n nextSlideElementList: Element[];\n}\n\nconst isResolvedInteractionElement = (element?: Element) =>\n Boolean(\n element?.type === \"interaction\" &&\n (element.readonly || element.user_input?.trim())\n );\n\nconst hasStableMarkerPrefix = (\n previousSlideElementList: Element[],\n nextSlideElementList: Element[]\n) =>\n previousSlideElementList.length <= nextSlideElementList.length &&\n previousSlideElementList.every(\n (element, index) => element === nextSlideElementList[index]\n );\n\nexport const resolveNextSlideIndexAfterMarkerAppend = ({\n previousIndex,\n previousSlideElementList,\n nextSlideElementList,\n}: ResolveNextSlideIndexParams) => {\n if (nextSlideElementList.length === 0) {\n return -1;\n }\n\n const hasAppendedMarkers =\n nextSlideElementList.length > previousSlideElementList.length &&\n hasStableMarkerPrefix(previousSlideElementList, nextSlideElementList);\n const previousLastMarkerIndex = previousSlideElementList.length - 1;\n const wasFocusedOnPreviousLastMarker =\n previousIndex === previousLastMarkerIndex;\n const previousCurrentElement =\n previousIndex >= 0 ? previousSlideElementList[previousIndex] : undefined;\n\n // When a resolved interaction is already the terminal step and SSE appends\n // the first follow-up marker, jump into that new marker immediately instead\n // of waiting for the interaction auto-close and silent-step delay.\n if (\n hasAppendedMarkers &&\n wasFocusedOnPreviousLastMarker &&\n isResolvedInteractionElement(previousCurrentElement)\n ) {\n return previousSlideElementList.length;\n }\n\n if (previousIndex >= 0 && previousIndex < nextSlideElementList.length) {\n return previousIndex;\n }\n\n return -1;\n};\n"],"names":["isResolvedInteractionElement","element","hasStableMarkerPrefix","previousSlideElementList","nextSlideElementList","index","resolveNextSlideIndexAfterMarkerAppend","previousIndex","hasAppendedMarkers","previousLastMarkerIndex","wasFocusedOnPreviousLastMarker","previousCurrentElement"],"mappings":"gFAQA,MAAMA,EAAgCC,GACpC,GACEA,GAAS,OAAS,gBACfA,EAAQ,UAAYA,EAAQ,YAAY,KAAA,IAGzCC,EAAwB,CAC5BC,EACAC,IAEAD,EAAyB,QAAUC,EAAqB,QACxDD,EAAyB,MACvB,CAACF,EAASI,IAAUJ,IAAYG,EAAqBC,CAAK,CAC5D,EAEWC,EAAyC,CAAC,CACrD,cAAAC,EACA,yBAAAJ,EACA,qBAAAC,CACF,IAAmC,CACjC,GAAIA,EAAqB,SAAW,EAClC,MAAO,GAGT,MAAMI,EACJJ,EAAqB,OAASD,EAAyB,QACvDD,EAAsBC,EAA0BC,CAAoB,EAChEK,EAA0BN,EAAyB,OAAS,EAC5DO,EACJH,IAAkBE,EACdE,EACJJ,GAAiB,EAAIJ,EAAyBI,CAAa,EAAI,OAKjE,OACEC,GACAE,GACAV,EAA6BW,CAAsB,EAE5CR,EAAyB,OAG9BI,GAAiB,GAAKA,EAAgBH,EAAqB,OACtDG,EAGF,EACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamingNavigation.es.js","sources":["../../../../src/components/Slide/utils/streamingNavigation.ts"],"sourcesContent":["import type { Element } from \"../types\";\n\ninterface ResolveNextSlideIndexParams {\n previousIndex: number;\n previousSlideElementList: Element[];\n nextSlideElementList: Element[];\n}\n\nconst isResolvedInteractionElement = (element?: Element) =>\n Boolean(\n element?.type === \"interaction\" &&\n
|
|
1
|
+
{"version":3,"file":"streamingNavigation.es.js","sources":["../../../../src/components/Slide/utils/streamingNavigation.ts"],"sourcesContent":["import type { Element } from \"../types\";\n\ninterface ResolveNextSlideIndexParams {\n previousIndex: number;\n previousSlideElementList: Element[];\n nextSlideElementList: Element[];\n}\n\nconst isResolvedInteractionElement = (element?: Element) =>\n Boolean(\n element?.type === \"interaction\" &&\n (element.readonly || element.user_input?.trim())\n );\n\nconst hasStableMarkerPrefix = (\n previousSlideElementList: Element[],\n nextSlideElementList: Element[]\n) =>\n previousSlideElementList.length <= nextSlideElementList.length &&\n previousSlideElementList.every(\n (element, index) => element === nextSlideElementList[index]\n );\n\nexport const resolveNextSlideIndexAfterMarkerAppend = ({\n previousIndex,\n previousSlideElementList,\n nextSlideElementList,\n}: ResolveNextSlideIndexParams) => {\n if (nextSlideElementList.length === 0) {\n return -1;\n }\n\n const hasAppendedMarkers =\n nextSlideElementList.length > previousSlideElementList.length &&\n hasStableMarkerPrefix(previousSlideElementList, nextSlideElementList);\n const previousLastMarkerIndex = previousSlideElementList.length - 1;\n const wasFocusedOnPreviousLastMarker =\n previousIndex === previousLastMarkerIndex;\n const previousCurrentElement =\n previousIndex >= 0 ? previousSlideElementList[previousIndex] : undefined;\n\n // When a resolved interaction is already the terminal step and SSE appends\n // the first follow-up marker, jump into that new marker immediately instead\n // of waiting for the interaction auto-close and silent-step delay.\n if (\n hasAppendedMarkers &&\n wasFocusedOnPreviousLastMarker &&\n isResolvedInteractionElement(previousCurrentElement)\n ) {\n return previousSlideElementList.length;\n }\n\n if (previousIndex >= 0 && previousIndex < nextSlideElementList.length) {\n return previousIndex;\n }\n\n return -1;\n};\n"],"names":["isResolvedInteractionElement","element","hasStableMarkerPrefix","previousSlideElementList","nextSlideElementList","index","resolveNextSlideIndexAfterMarkerAppend","previousIndex","hasAppendedMarkers","previousLastMarkerIndex","wasFocusedOnPreviousLastMarker","previousCurrentElement"],"mappings":"AAQA,MAAMA,IAA+B,CAACC,MACpC,GACEA,GAAS,SAAS,kBACfA,EAAQ,YAAYA,EAAQ,YAAY,KAAA,KAGzCC,IAAwB,CAC5BC,GACAC,MAEAD,EAAyB,UAAUC,EAAqB,UACxDD,EAAyB;AAAA,EACvB,CAACF,GAASI,MAAUJ,MAAYG,EAAqBC,CAAK;AAC5D,GAEWC,IAAyC,CAAC;AAAA,EACrD,eAAAC;AAAA,EACA,0BAAAJ;AAAA,EACA,sBAAAC;AACF,MAAmC;AACjC,MAAIA,EAAqB,WAAW;AAClC,WAAO;AAGT,QAAMI,IACJJ,EAAqB,SAASD,EAAyB,UACvDD,EAAsBC,GAA0BC,CAAoB,GAChEK,IAA0BN,EAAyB,SAAS,GAC5DO,IACJH,MAAkBE,GACdE,IACJJ,KAAiB,IAAIJ,EAAyBI,CAAa,IAAI;AAKjE,SACEC,KACAE,KACAV,EAA6BW,CAAsB,IAE5CR,EAAyB,SAG9BI,KAAiB,KAAKA,IAAgBH,EAAqB,SACtDG,IAGF;AACT;"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
2
|
-
`);exports.getVisibleSubtitleText=
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=(s=[],i)=>s.filter(t=>i>=t.start_ms&&i<t.end_ms).sort((t,e)=>(t.position??0)-(e.position??0)||t.segment_index-e.segment_index||t.start_ms-e.start_ms||t.end_ms-e.end_ms).map(t=>t.text.trim()).filter(Boolean).join(`
|
|
2
|
+
`),o=s=>Math.max(Number(s.start_ms??0),0),m=s=>Math.max(Number(s.end_ms??0),0),a=new WeakMap,u=(s=[])=>{const i=a.get(s);if(i)return i;const t=[...s].sort((e,n)=>o(e)-o(n)||m(e)-m(n)||(e.position??0)-(n.position??0)||(e.segment_index??0)-(n.segment_index??0));return a.set(s,t),t},c=(s,i)=>{let t=null;for(const e of s){const n=o(e);if(n>i)break;const r=m(e);i>=n&&i<r&&(t=n)}return t},S=(s,i)=>{let t=null;for(const e of s){const n=o(e);if(n>=i)break;t=n}return t},b=(s,i)=>{const t=s.find(e=>o(e)>i);return t?o(t):null},d=({currentTimeMs:s,direction:i,subtitleCues:t=[]})=>{if(t.length===0)return null;const e=u(t),n=Math.max(Number(s),0);if(i==="next")return b(e,n);const r=c(e,n);return S(e,r??n)};exports.getSubtitleCueJumpTime=d;exports.getVisibleSubtitleText=l;
|
|
3
3
|
//# sourceMappingURL=subtitleCue.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subtitleCue.cjs.js","sources":["../../../../src/components/Slide/utils/subtitleCue.ts"],"sourcesContent":["import type { ElementSubtitleCue } from \"../types\";\n\nexport const getVisibleSubtitleText = (\n subtitleCues: ElementSubtitleCue[] = [],\n currentTimeMs: number\n) =>\n subtitleCues\n .filter(\n (subtitleCue) =>\n currentTimeMs >= subtitleCue.start_ms &&\n currentTimeMs < subtitleCue.end_ms\n )\n .sort(\n (prevCue, nextCue) =>\n (prevCue.position ?? 0) - (nextCue.position ?? 0) ||\n prevCue.segment_index - nextCue.segment_index ||\n prevCue.start_ms - nextCue.start_ms ||\n prevCue.end_ms - nextCue.end_ms\n )\n .map((subtitleCue) => subtitleCue.text.trim())\n .filter(Boolean)\n .join(\"\\n\");\n"],"names":["getVisibleSubtitleText","subtitleCues","currentTimeMs","subtitleCue","prevCue","nextCue"],"mappings":"
|
|
1
|
+
{"version":3,"file":"subtitleCue.cjs.js","sources":["../../../../src/components/Slide/utils/subtitleCue.ts"],"sourcesContent":["import type { ElementSubtitleCue } from \"../types\";\n\n/** Direction for subtitle cue jump navigation. */\nexport type SubtitleCueJumpDirection = \"previous\" | \"next\";\n\nexport const getVisibleSubtitleText = (\n subtitleCues: ElementSubtitleCue[] = [],\n currentTimeMs: number\n) =>\n subtitleCues\n .filter(\n (subtitleCue) =>\n currentTimeMs >= subtitleCue.start_ms &&\n currentTimeMs < subtitleCue.end_ms\n )\n .sort(\n (prevCue, nextCue) =>\n (prevCue.position ?? 0) - (nextCue.position ?? 0) ||\n prevCue.segment_index - nextCue.segment_index ||\n prevCue.start_ms - nextCue.start_ms ||\n prevCue.end_ms - nextCue.end_ms\n )\n .map((subtitleCue) => subtitleCue.text.trim())\n .filter(Boolean)\n .join(\"\\n\");\n\nconst getSubtitleCueStartTimeMs = (subtitleCue: ElementSubtitleCue) =>\n Math.max(Number(subtitleCue.start_ms ?? 0), 0);\n\nconst getSubtitleCueEndTimeMs = (subtitleCue: ElementSubtitleCue) =>\n Math.max(Number(subtitleCue.end_ms ?? 0), 0);\n\nconst sortedSubtitleCuesCache = new WeakMap<\n ElementSubtitleCue[],\n ElementSubtitleCue[]\n>();\n\nconst sortSubtitleCuesByPlaybackTime = (\n subtitleCues: ElementSubtitleCue[] = []\n) => {\n const cachedSubtitleCues = sortedSubtitleCuesCache.get(subtitleCues);\n\n if (cachedSubtitleCues) {\n return cachedSubtitleCues;\n }\n\n const sortedSubtitleCues = [...subtitleCues].sort(\n (previousCue, nextCue) =>\n getSubtitleCueStartTimeMs(previousCue) -\n getSubtitleCueStartTimeMs(nextCue) ||\n getSubtitleCueEndTimeMs(previousCue) - getSubtitleCueEndTimeMs(nextCue) ||\n (previousCue.position ?? 0) - (nextCue.position ?? 0) ||\n (previousCue.segment_index ?? 0) - (nextCue.segment_index ?? 0)\n );\n\n sortedSubtitleCuesCache.set(subtitleCues, sortedSubtitleCues);\n\n return sortedSubtitleCues;\n};\n\nconst getActiveSubtitleCueStartTimeMs = (\n subtitleCues: ElementSubtitleCue[],\n currentTimeMs: number\n) => {\n let activeStartTimeMs: number | null = null;\n\n for (const subtitleCue of subtitleCues) {\n const startTimeMs = getSubtitleCueStartTimeMs(subtitleCue);\n\n if (startTimeMs > currentTimeMs) {\n break;\n }\n\n const endTimeMs = getSubtitleCueEndTimeMs(subtitleCue);\n\n if (currentTimeMs >= startTimeMs && currentTimeMs < endTimeMs) {\n activeStartTimeMs = startTimeMs;\n }\n }\n\n return activeStartTimeMs;\n};\n\nconst getPreviousSubtitleCueStartTimeMs = (\n subtitleCues: ElementSubtitleCue[],\n currentTimeMs: number\n) => {\n let previousStartTimeMs: number | null = null;\n\n for (const subtitleCue of subtitleCues) {\n const startTimeMs = getSubtitleCueStartTimeMs(subtitleCue);\n\n if (startTimeMs >= currentTimeMs) {\n break;\n }\n\n previousStartTimeMs = startTimeMs;\n }\n\n return previousStartTimeMs;\n};\n\nconst getNextSubtitleCueStartTimeMs = (\n subtitleCues: ElementSubtitleCue[],\n currentTimeMs: number\n) => {\n const nextSubtitleCue = subtitleCues.find(\n (subtitleCue) => getSubtitleCueStartTimeMs(subtitleCue) > currentTimeMs\n );\n\n return nextSubtitleCue ? getSubtitleCueStartTimeMs(nextSubtitleCue) : null;\n};\n\n/** Options used to resolve a subtitle cue jump target. */\nexport interface GetSubtitleCueJumpTimeOptions {\n currentTimeMs: number;\n direction: SubtitleCueJumpDirection;\n subtitleCues?: ElementSubtitleCue[];\n}\n\n/** Returns the target cue start time in milliseconds, or `null` when no target exists. */\nexport const getSubtitleCueJumpTime = ({\n currentTimeMs,\n direction,\n subtitleCues = [],\n}: GetSubtitleCueJumpTimeOptions): number | null => {\n if (subtitleCues.length === 0) {\n return null;\n }\n\n const sortedSubtitleCues = sortSubtitleCuesByPlaybackTime(subtitleCues);\n const normalizedCurrentTimeMs = Math.max(Number(currentTimeMs), 0);\n\n if (direction === \"next\") {\n return getNextSubtitleCueStartTimeMs(\n sortedSubtitleCues,\n normalizedCurrentTimeMs\n );\n }\n\n const activeStartTimeMs = getActiveSubtitleCueStartTimeMs(\n sortedSubtitleCues,\n normalizedCurrentTimeMs\n );\n\n return getPreviousSubtitleCueStartTimeMs(\n sortedSubtitleCues,\n activeStartTimeMs ?? normalizedCurrentTimeMs\n );\n};\n"],"names":["getVisibleSubtitleText","subtitleCues","currentTimeMs","subtitleCue","prevCue","nextCue","getSubtitleCueStartTimeMs","getSubtitleCueEndTimeMs","sortedSubtitleCuesCache","sortSubtitleCuesByPlaybackTime","cachedSubtitleCues","sortedSubtitleCues","previousCue","getActiveSubtitleCueStartTimeMs","activeStartTimeMs","startTimeMs","endTimeMs","getPreviousSubtitleCueStartTimeMs","previousStartTimeMs","getNextSubtitleCueStartTimeMs","nextSubtitleCue","getSubtitleCueJumpTime","direction","normalizedCurrentTimeMs"],"mappings":"gFAKO,MAAMA,EAAyB,CACpCC,EAAqC,CAAA,EACrCC,IAEAD,EACG,OACEE,GACCD,GAAiBC,EAAY,UAC7BD,EAAgBC,EAAY,MAChC,EACC,KACC,CAACC,EAASC,KACPD,EAAQ,UAAY,IAAMC,EAAQ,UAAY,IAC/CD,EAAQ,cAAgBC,EAAQ,eAChCD,EAAQ,SAAWC,EAAQ,UAC3BD,EAAQ,OAASC,EAAQ,MAC7B,EACC,IAAKF,GAAgBA,EAAY,KAAK,KAAA,CAAM,EAC5C,OAAO,OAAO,EACd,KAAK;AAAA,CAAI,EAERG,EAA6BH,GACjC,KAAK,IAAI,OAAOA,EAAY,UAAY,CAAC,EAAG,CAAC,EAEzCI,EAA2BJ,GAC/B,KAAK,IAAI,OAAOA,EAAY,QAAU,CAAC,EAAG,CAAC,EAEvCK,MAA8B,QAK9BC,EAAiC,CACrCR,EAAqC,KAClC,CACH,MAAMS,EAAqBF,EAAwB,IAAIP,CAAY,EAEnE,GAAIS,EACF,OAAOA,EAGT,MAAMC,EAAqB,CAAC,GAAGV,CAAY,EAAE,KAC3C,CAACW,EAAaP,IACZC,EAA0BM,CAAW,EACnCN,EAA0BD,CAAO,GACnCE,EAAwBK,CAAW,EAAIL,EAAwBF,CAAO,IACrEO,EAAY,UAAY,IAAMP,EAAQ,UAAY,KAClDO,EAAY,eAAiB,IAAMP,EAAQ,eAAiB,EAAA,EAGjE,OAAAG,EAAwB,IAAIP,EAAcU,CAAkB,EAErDA,CACT,EAEME,EAAkC,CACtCZ,EACAC,IACG,CACH,IAAIY,EAAmC,KAEvC,UAAWX,KAAeF,EAAc,CACtC,MAAMc,EAAcT,EAA0BH,CAAW,EAEzD,GAAIY,EAAcb,EAChB,MAGF,MAAMc,EAAYT,EAAwBJ,CAAW,EAEjDD,GAAiBa,GAAeb,EAAgBc,IAClDF,EAAoBC,EAExB,CAEA,OAAOD,CACT,EAEMG,EAAoC,CACxChB,EACAC,IACG,CACH,IAAIgB,EAAqC,KAEzC,UAAWf,KAAeF,EAAc,CACtC,MAAMc,EAAcT,EAA0BH,CAAW,EAEzD,GAAIY,GAAeb,EACjB,MAGFgB,EAAsBH,CACxB,CAEA,OAAOG,CACT,EAEMC,EAAgC,CACpClB,EACAC,IACG,CACH,MAAMkB,EAAkBnB,EAAa,KAClCE,GAAgBG,EAA0BH,CAAW,EAAID,CAAA,EAG5D,OAAOkB,EAAkBd,EAA0Bc,CAAe,EAAI,IACxE,EAUaC,EAAyB,CAAC,CACrC,cAAAnB,EACA,UAAAoB,EACA,aAAArB,EAAe,CAAA,CACjB,IAAoD,CAClD,GAAIA,EAAa,SAAW,EAC1B,OAAO,KAGT,MAAMU,EAAqBF,EAA+BR,CAAY,EAChEsB,EAA0B,KAAK,IAAI,OAAOrB,CAAa,EAAG,CAAC,EAEjE,GAAIoB,IAAc,OAChB,OAAOH,EACLR,EACAY,CAAA,EAIJ,MAAMT,EAAoBD,EACxBF,EACAY,CAAA,EAGF,OAAON,EACLN,EACAG,GAAqBS,CAAA,CAEzB"}
|
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
import { ElementSubtitleCue } from '../types';
|
|
2
|
+
/** Direction for subtitle cue jump navigation. */
|
|
3
|
+
export type SubtitleCueJumpDirection = "previous" | "next";
|
|
2
4
|
export declare const getVisibleSubtitleText: (subtitleCues: ElementSubtitleCue[] | undefined, currentTimeMs: number) => string;
|
|
5
|
+
/** Options used to resolve a subtitle cue jump target. */
|
|
6
|
+
export interface GetSubtitleCueJumpTimeOptions {
|
|
7
|
+
currentTimeMs: number;
|
|
8
|
+
direction: SubtitleCueJumpDirection;
|
|
9
|
+
subtitleCues?: ElementSubtitleCue[];
|
|
10
|
+
}
|
|
11
|
+
/** Returns the target cue start time in milliseconds, or `null` when no target exists. */
|
|
12
|
+
export declare const getSubtitleCueJumpTime: ({ currentTimeMs, direction, subtitleCues, }: GetSubtitleCueJumpTimeOptions) => number | null;
|
|
@@ -1,10 +1,64 @@
|
|
|
1
|
-
const
|
|
2
|
-
(t) =>
|
|
1
|
+
const b = (s = [], n) => s.filter(
|
|
2
|
+
(t) => n >= t.start_ms && n < t.end_ms
|
|
3
3
|
).sort(
|
|
4
|
-
(t,
|
|
4
|
+
(t, e) => (t.position ?? 0) - (e.position ?? 0) || t.segment_index - e.segment_index || t.start_ms - e.start_ms || t.end_ms - e.end_ms
|
|
5
5
|
).map((t) => t.text.trim()).filter(Boolean).join(`
|
|
6
|
-
`)
|
|
6
|
+
`), o = (s) => Math.max(Number(s.start_ms ?? 0), 0), m = (s) => Math.max(Number(s.end_ms ?? 0), 0), a = /* @__PURE__ */ new WeakMap(), l = (s = []) => {
|
|
7
|
+
const n = a.get(s);
|
|
8
|
+
if (n)
|
|
9
|
+
return n;
|
|
10
|
+
const t = [...s].sort(
|
|
11
|
+
(e, i) => o(e) - o(i) || m(e) - m(i) || (e.position ?? 0) - (i.position ?? 0) || (e.segment_index ?? 0) - (i.segment_index ?? 0)
|
|
12
|
+
);
|
|
13
|
+
return a.set(s, t), t;
|
|
14
|
+
}, c = (s, n) => {
|
|
15
|
+
let t = null;
|
|
16
|
+
for (const e of s) {
|
|
17
|
+
const i = o(e);
|
|
18
|
+
if (i > n)
|
|
19
|
+
break;
|
|
20
|
+
const r = m(e);
|
|
21
|
+
n >= i && n < r && (t = i);
|
|
22
|
+
}
|
|
23
|
+
return t;
|
|
24
|
+
}, u = (s, n) => {
|
|
25
|
+
let t = null;
|
|
26
|
+
for (const e of s) {
|
|
27
|
+
const i = o(e);
|
|
28
|
+
if (i >= n)
|
|
29
|
+
break;
|
|
30
|
+
t = i;
|
|
31
|
+
}
|
|
32
|
+
return t;
|
|
33
|
+
}, S = (s, n) => {
|
|
34
|
+
const t = s.find(
|
|
35
|
+
(e) => o(e) > n
|
|
36
|
+
);
|
|
37
|
+
return t ? o(t) : null;
|
|
38
|
+
}, d = ({
|
|
39
|
+
currentTimeMs: s,
|
|
40
|
+
direction: n,
|
|
41
|
+
subtitleCues: t = []
|
|
42
|
+
}) => {
|
|
43
|
+
if (t.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
const e = l(t), i = Math.max(Number(s), 0);
|
|
46
|
+
if (n === "next")
|
|
47
|
+
return S(
|
|
48
|
+
e,
|
|
49
|
+
i
|
|
50
|
+
);
|
|
51
|
+
const r = c(
|
|
52
|
+
e,
|
|
53
|
+
i
|
|
54
|
+
);
|
|
55
|
+
return u(
|
|
56
|
+
e,
|
|
57
|
+
r ?? i
|
|
58
|
+
);
|
|
59
|
+
};
|
|
7
60
|
export {
|
|
8
|
-
|
|
61
|
+
d as getSubtitleCueJumpTime,
|
|
62
|
+
b as getVisibleSubtitleText
|
|
9
63
|
};
|
|
10
64
|
//# sourceMappingURL=subtitleCue.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subtitleCue.es.js","sources":["../../../../src/components/Slide/utils/subtitleCue.ts"],"sourcesContent":["import type { ElementSubtitleCue } from \"../types\";\n\nexport const getVisibleSubtitleText = (\n subtitleCues: ElementSubtitleCue[] = [],\n currentTimeMs: number\n) =>\n subtitleCues\n .filter(\n (subtitleCue) =>\n currentTimeMs >= subtitleCue.start_ms &&\n currentTimeMs < subtitleCue.end_ms\n )\n .sort(\n (prevCue, nextCue) =>\n (prevCue.position ?? 0) - (nextCue.position ?? 0) ||\n prevCue.segment_index - nextCue.segment_index ||\n prevCue.start_ms - nextCue.start_ms ||\n prevCue.end_ms - nextCue.end_ms\n )\n .map((subtitleCue) => subtitleCue.text.trim())\n .filter(Boolean)\n .join(\"\\n\");\n"],"names":["getVisibleSubtitleText","subtitleCues","currentTimeMs","subtitleCue","prevCue","nextCue"],"mappings":"
|
|
1
|
+
{"version":3,"file":"subtitleCue.es.js","sources":["../../../../src/components/Slide/utils/subtitleCue.ts"],"sourcesContent":["import type { ElementSubtitleCue } from \"../types\";\n\n/** Direction for subtitle cue jump navigation. */\nexport type SubtitleCueJumpDirection = \"previous\" | \"next\";\n\nexport const getVisibleSubtitleText = (\n subtitleCues: ElementSubtitleCue[] = [],\n currentTimeMs: number\n) =>\n subtitleCues\n .filter(\n (subtitleCue) =>\n currentTimeMs >= subtitleCue.start_ms &&\n currentTimeMs < subtitleCue.end_ms\n )\n .sort(\n (prevCue, nextCue) =>\n (prevCue.position ?? 0) - (nextCue.position ?? 0) ||\n prevCue.segment_index - nextCue.segment_index ||\n prevCue.start_ms - nextCue.start_ms ||\n prevCue.end_ms - nextCue.end_ms\n )\n .map((subtitleCue) => subtitleCue.text.trim())\n .filter(Boolean)\n .join(\"\\n\");\n\nconst getSubtitleCueStartTimeMs = (subtitleCue: ElementSubtitleCue) =>\n Math.max(Number(subtitleCue.start_ms ?? 0), 0);\n\nconst getSubtitleCueEndTimeMs = (subtitleCue: ElementSubtitleCue) =>\n Math.max(Number(subtitleCue.end_ms ?? 0), 0);\n\nconst sortedSubtitleCuesCache = new WeakMap<\n ElementSubtitleCue[],\n ElementSubtitleCue[]\n>();\n\nconst sortSubtitleCuesByPlaybackTime = (\n subtitleCues: ElementSubtitleCue[] = []\n) => {\n const cachedSubtitleCues = sortedSubtitleCuesCache.get(subtitleCues);\n\n if (cachedSubtitleCues) {\n return cachedSubtitleCues;\n }\n\n const sortedSubtitleCues = [...subtitleCues].sort(\n (previousCue, nextCue) =>\n getSubtitleCueStartTimeMs(previousCue) -\n getSubtitleCueStartTimeMs(nextCue) ||\n getSubtitleCueEndTimeMs(previousCue) - getSubtitleCueEndTimeMs(nextCue) ||\n (previousCue.position ?? 0) - (nextCue.position ?? 0) ||\n (previousCue.segment_index ?? 0) - (nextCue.segment_index ?? 0)\n );\n\n sortedSubtitleCuesCache.set(subtitleCues, sortedSubtitleCues);\n\n return sortedSubtitleCues;\n};\n\nconst getActiveSubtitleCueStartTimeMs = (\n subtitleCues: ElementSubtitleCue[],\n currentTimeMs: number\n) => {\n let activeStartTimeMs: number | null = null;\n\n for (const subtitleCue of subtitleCues) {\n const startTimeMs = getSubtitleCueStartTimeMs(subtitleCue);\n\n if (startTimeMs > currentTimeMs) {\n break;\n }\n\n const endTimeMs = getSubtitleCueEndTimeMs(subtitleCue);\n\n if (currentTimeMs >= startTimeMs && currentTimeMs < endTimeMs) {\n activeStartTimeMs = startTimeMs;\n }\n }\n\n return activeStartTimeMs;\n};\n\nconst getPreviousSubtitleCueStartTimeMs = (\n subtitleCues: ElementSubtitleCue[],\n currentTimeMs: number\n) => {\n let previousStartTimeMs: number | null = null;\n\n for (const subtitleCue of subtitleCues) {\n const startTimeMs = getSubtitleCueStartTimeMs(subtitleCue);\n\n if (startTimeMs >= currentTimeMs) {\n break;\n }\n\n previousStartTimeMs = startTimeMs;\n }\n\n return previousStartTimeMs;\n};\n\nconst getNextSubtitleCueStartTimeMs = (\n subtitleCues: ElementSubtitleCue[],\n currentTimeMs: number\n) => {\n const nextSubtitleCue = subtitleCues.find(\n (subtitleCue) => getSubtitleCueStartTimeMs(subtitleCue) > currentTimeMs\n );\n\n return nextSubtitleCue ? getSubtitleCueStartTimeMs(nextSubtitleCue) : null;\n};\n\n/** Options used to resolve a subtitle cue jump target. */\nexport interface GetSubtitleCueJumpTimeOptions {\n currentTimeMs: number;\n direction: SubtitleCueJumpDirection;\n subtitleCues?: ElementSubtitleCue[];\n}\n\n/** Returns the target cue start time in milliseconds, or `null` when no target exists. */\nexport const getSubtitleCueJumpTime = ({\n currentTimeMs,\n direction,\n subtitleCues = [],\n}: GetSubtitleCueJumpTimeOptions): number | null => {\n if (subtitleCues.length === 0) {\n return null;\n }\n\n const sortedSubtitleCues = sortSubtitleCuesByPlaybackTime(subtitleCues);\n const normalizedCurrentTimeMs = Math.max(Number(currentTimeMs), 0);\n\n if (direction === \"next\") {\n return getNextSubtitleCueStartTimeMs(\n sortedSubtitleCues,\n normalizedCurrentTimeMs\n );\n }\n\n const activeStartTimeMs = getActiveSubtitleCueStartTimeMs(\n sortedSubtitleCues,\n normalizedCurrentTimeMs\n );\n\n return getPreviousSubtitleCueStartTimeMs(\n sortedSubtitleCues,\n activeStartTimeMs ?? normalizedCurrentTimeMs\n );\n};\n"],"names":["getVisibleSubtitleText","subtitleCues","currentTimeMs","subtitleCue","prevCue","nextCue","getSubtitleCueStartTimeMs","getSubtitleCueEndTimeMs","sortedSubtitleCuesCache","sortSubtitleCuesByPlaybackTime","cachedSubtitleCues","sortedSubtitleCues","previousCue","getActiveSubtitleCueStartTimeMs","activeStartTimeMs","startTimeMs","endTimeMs","getPreviousSubtitleCueStartTimeMs","previousStartTimeMs","getNextSubtitleCueStartTimeMs","nextSubtitleCue","getSubtitleCueJumpTime","direction","normalizedCurrentTimeMs"],"mappings":"AAKO,MAAMA,IAAyB,CACpCC,IAAqC,CAAA,GACrCC,MAEAD,EACG;AAAA,EACC,CAACE,MACCD,KAAiBC,EAAY,YAC7BD,IAAgBC,EAAY;AAChC,EACC;AAAA,EACC,CAACC,GAASC,OACPD,EAAQ,YAAY,MAAMC,EAAQ,YAAY,MAC/CD,EAAQ,gBAAgBC,EAAQ,iBAChCD,EAAQ,WAAWC,EAAQ,YAC3BD,EAAQ,SAASC,EAAQ;AAC7B,EACC,IAAI,CAACF,MAAgBA,EAAY,KAAK,KAAA,CAAM,EAC5C,OAAO,OAAO,EACd,KAAK;AAAA,CAAI,GAERG,IAA4B,CAACH,MACjC,KAAK,IAAI,OAAOA,EAAY,YAAY,CAAC,GAAG,CAAC,GAEzCI,IAA0B,CAACJ,MAC/B,KAAK,IAAI,OAAOA,EAAY,UAAU,CAAC,GAAG,CAAC,GAEvCK,wBAA8B,QAAA,GAK9BC,IAAiC,CACrCR,IAAqC,OAClC;AACH,QAAMS,IAAqBF,EAAwB,IAAIP,CAAY;AAEnE,MAAIS;AACF,WAAOA;AAGT,QAAMC,IAAqB,CAAC,GAAGV,CAAY,EAAE;AAAA,IAC3C,CAACW,GAAaP,MACZC,EAA0BM,CAAW,IACnCN,EAA0BD,CAAO,KACnCE,EAAwBK,CAAW,IAAIL,EAAwBF,CAAO,MACrEO,EAAY,YAAY,MAAMP,EAAQ,YAAY,OAClDO,EAAY,iBAAiB,MAAMP,EAAQ,iBAAiB;AAAA,EAAA;AAGjE,SAAAG,EAAwB,IAAIP,GAAcU,CAAkB,GAErDA;AACT,GAEME,IAAkC,CACtCZ,GACAC,MACG;AACH,MAAIY,IAAmC;AAEvC,aAAWX,KAAeF,GAAc;AACtC,UAAMc,IAAcT,EAA0BH,CAAW;AAEzD,QAAIY,IAAcb;AAChB;AAGF,UAAMc,IAAYT,EAAwBJ,CAAW;AAErD,IAAID,KAAiBa,KAAeb,IAAgBc,MAClDF,IAAoBC;AAAA,EAExB;AAEA,SAAOD;AACT,GAEMG,IAAoC,CACxChB,GACAC,MACG;AACH,MAAIgB,IAAqC;AAEzC,aAAWf,KAAeF,GAAc;AACtC,UAAMc,IAAcT,EAA0BH,CAAW;AAEzD,QAAIY,KAAeb;AACjB;AAGF,IAAAgB,IAAsBH;AAAA,EACxB;AAEA,SAAOG;AACT,GAEMC,IAAgC,CACpClB,GACAC,MACG;AACH,QAAMkB,IAAkBnB,EAAa;AAAA,IACnC,CAACE,MAAgBG,EAA0BH,CAAW,IAAID;AAAA,EAAA;AAG5D,SAAOkB,IAAkBd,EAA0Bc,CAAe,IAAI;AACxE,GAUaC,IAAyB,CAAC;AAAA,EACrC,eAAAnB;AAAA,EACA,WAAAoB;AAAA,EACA,cAAArB,IAAe,CAAA;AACjB,MAAoD;AAClD,MAAIA,EAAa,WAAW;AAC1B,WAAO;AAGT,QAAMU,IAAqBF,EAA+BR,CAAY,GAChEsB,IAA0B,KAAK,IAAI,OAAOrB,CAAa,GAAG,CAAC;AAEjE,MAAIoB,MAAc;AAChB,WAAOH;AAAA,MACLR;AAAA,MACAY;AAAA,IAAA;AAIJ,QAAMT,IAAoBD;AAAA,IACxBF;AAAA,IACAY;AAAA,EAAA;AAGF,SAAON;AAAA,IACLN;AAAA,IACAG,KAAqBS;AAAA,EAAA;AAEzB;"}
|