mirror of
https://github.com/jeffvli/feishin.git
synced 2026-07-13 05:59:58 +02:00
properly handle settings state on lyrics follow
This commit is contained in:
@@ -21,10 +21,14 @@ export interface UseLyricsAnimationEngineOptions {
|
|||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
followRef?: React.RefObject<boolean>;
|
followRef?: React.RefObject<boolean>;
|
||||||
followScrollAlignmentRef?: React.RefObject<number>;
|
followScrollAlignmentRef?: React.RefObject<number>;
|
||||||
|
fontSize?: number;
|
||||||
|
gap?: number;
|
||||||
lineIdPrefix: 'karaoke-line' | 'lyric';
|
lineIdPrefix: 'karaoke-line' | 'lyric';
|
||||||
lineLeadTimeMsRef?: React.RefObject<number>;
|
lineLeadTimeMsRef?: React.RefObject<number>;
|
||||||
lyrics: SynchronizedLyrics;
|
lyrics: SynchronizedLyrics;
|
||||||
onLineActive?: (lineIndex: number) => void;
|
onLineActive?: (lineIndex: number) => void;
|
||||||
|
paddingLeft?: number;
|
||||||
|
paddingRight?: number;
|
||||||
scrollContainerId: string;
|
scrollContainerId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,10 +38,14 @@ export const useLyricsAnimationEngine = ({
|
|||||||
enabled = true,
|
enabled = true,
|
||||||
followRef,
|
followRef,
|
||||||
followScrollAlignmentRef,
|
followScrollAlignmentRef,
|
||||||
|
fontSize,
|
||||||
|
gap,
|
||||||
lineIdPrefix,
|
lineIdPrefix,
|
||||||
lineLeadTimeMsRef,
|
lineLeadTimeMsRef,
|
||||||
lyrics,
|
lyrics,
|
||||||
onLineActive,
|
onLineActive,
|
||||||
|
paddingLeft,
|
||||||
|
paddingRight,
|
||||||
scrollContainerId,
|
scrollContainerId,
|
||||||
}: UseLyricsAnimationEngineOptions) => {
|
}: UseLyricsAnimationEngineOptions) => {
|
||||||
const internalAnimStateRef = useRef<AnimEngineState>(createAnimEngineState());
|
const internalAnimStateRef = useRef<AnimEngineState>(createAnimEngineState());
|
||||||
@@ -83,6 +91,7 @@ export const useLyricsAnimationEngine = ({
|
|||||||
const recalculatePositions = useCallback(() => {
|
const recalculatePositions = useCallback(() => {
|
||||||
if (lyricsDataRef.current) {
|
if (lyricsDataRef.current) {
|
||||||
recalculateLinePositions(lyricsDataRef.current);
|
recalculateLinePositions(lyricsDataRef.current);
|
||||||
|
animStateRef.current.scroll.pendingScroll = true;
|
||||||
animStateRef.current.scroll.wasUserScrolling = true;
|
animStateRef.current.scroll.wasUserScrolling = true;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- animStateRef is read via .current at call time
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- animStateRef is read via .current at call time
|
||||||
@@ -149,20 +158,51 @@ export const useLyricsAnimationEngine = ({
|
|||||||
};
|
};
|
||||||
}, [lyrics, enabled, rebuildLyricsData, reset]);
|
}, [lyrics, enabled, rebuildLyricsData, reset]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const frame = requestAnimationFrame(() => {
|
||||||
|
recalculatePositions();
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelAnimationFrame(frame);
|
||||||
|
};
|
||||||
|
}, [fontSize, gap, paddingLeft, paddingRight, recalculatePositions]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const container = containerRef.current;
|
const container = containerRef.current;
|
||||||
if (!container) {
|
if (!container) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const observedElements = new Set<Element>();
|
||||||
|
|
||||||
const observer = new ResizeObserver(() => {
|
const observer = new ResizeObserver(() => {
|
||||||
recalculatePositions();
|
recalculatePositions();
|
||||||
});
|
});
|
||||||
|
|
||||||
observer.observe(container);
|
const observeLayoutTargets = () => {
|
||||||
|
if (!observedElements.has(container)) {
|
||||||
|
observer.observe(container);
|
||||||
|
observedElements.add(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = container.firstElementChild;
|
||||||
|
if (content && !observedElements.has(content)) {
|
||||||
|
observer.observe(content);
|
||||||
|
observedElements.add(content);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
observeLayoutTargets();
|
||||||
|
|
||||||
|
const mutationObserver = new MutationObserver(() => {
|
||||||
|
observeLayoutTargets();
|
||||||
|
});
|
||||||
|
mutationObserver.observe(container, { childList: true });
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
|
mutationObserver.disconnect();
|
||||||
};
|
};
|
||||||
}, [containerRef, recalculatePositions]);
|
}, [containerRef, recalculatePositions]);
|
||||||
|
|
||||||
|
|||||||
@@ -94,9 +94,13 @@ export const SynchronizedKaraokeLyrics = ({
|
|||||||
containerRef,
|
containerRef,
|
||||||
followRef,
|
followRef,
|
||||||
followScrollAlignmentRef,
|
followScrollAlignmentRef,
|
||||||
|
fontSize: settings.fontSize,
|
||||||
|
gap: settings.gap,
|
||||||
lineIdPrefix: 'karaoke-line',
|
lineIdPrefix: 'karaoke-line',
|
||||||
lineLeadTimeMsRef,
|
lineLeadTimeMsRef,
|
||||||
lyrics: normalizedLyrics,
|
lyrics: normalizedLyrics,
|
||||||
|
paddingLeft: settings.paddingLeft,
|
||||||
|
paddingRight: settings.paddingRight,
|
||||||
scrollContainerId: LYRICS_SCROLL_CONTAINER_ID,
|
scrollContainerId: LYRICS_SCROLL_CONTAINER_ID,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -82,9 +82,13 @@ export const SynchronizedLyrics = ({
|
|||||||
containerRef,
|
containerRef,
|
||||||
followRef,
|
followRef,
|
||||||
followScrollAlignmentRef,
|
followScrollAlignmentRef,
|
||||||
|
fontSize: settings.fontSize,
|
||||||
|
gap: settings.gap,
|
||||||
lineIdPrefix: 'lyric',
|
lineIdPrefix: 'lyric',
|
||||||
lineLeadTimeMsRef,
|
lineLeadTimeMsRef,
|
||||||
lyrics: normalizedLyrics,
|
lyrics: normalizedLyrics,
|
||||||
|
paddingLeft: settings.paddingLeft,
|
||||||
|
paddingRight: settings.paddingRight,
|
||||||
scrollContainerId: LYRICS_SCROLL_CONTAINER_ID,
|
scrollContainerId: LYRICS_SCROLL_CONTAINER_ID,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user