feat: play from dropdown
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { BlurView } from "expo-blur";
|
||||
import { Portal } from "@gorhom/portal";
|
||||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
@@ -78,21 +80,25 @@ const defaultFormatDate = (timestamp) => {
|
||||
}
|
||||
};
|
||||
|
||||
const ProjectDropDown = ({
|
||||
style,
|
||||
projects = [],
|
||||
selectedProject,
|
||||
onSelectProject,
|
||||
onModifyProject,
|
||||
onCreateProject,
|
||||
formatDate = defaultFormatDate,
|
||||
allowEmptySelection = false,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [triggerLayout, setTriggerLayout] = useState(null);
|
||||
const [triggerWindowLayout, setTriggerWindowLayout] = useState(null);
|
||||
const triggerRef = useRef(null);
|
||||
const dropdownAnimation = useRef(new Animated.Value(0)).current;
|
||||
const ProjectDropDown = forwardRef(
|
||||
(
|
||||
{
|
||||
style,
|
||||
projects = [],
|
||||
selectedProject,
|
||||
onSelectProject,
|
||||
onModifyProject,
|
||||
onCreateProject,
|
||||
formatDate = defaultFormatDate,
|
||||
allowEmptySelection = false,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [triggerLayout, setTriggerLayout] = useState(null);
|
||||
const [triggerWindowLayout, setTriggerWindowLayout] = useState(null);
|
||||
const triggerRef = useRef(null);
|
||||
const dropdownAnimation = useRef(new Animated.Value(0)).current;
|
||||
|
||||
const measureTriggerPosition = useCallback(() => {
|
||||
if (triggerRef.current?.measureInWindow) {
|
||||
@@ -133,39 +139,47 @@ const ProjectDropDown = ({
|
||||
})
|
||||
: normalizedProjects;
|
||||
|
||||
const toggleDropdown = useCallback(() => {
|
||||
if (isDisabled) {
|
||||
return;
|
||||
}
|
||||
if (!isOpen) {
|
||||
measureTriggerPosition();
|
||||
}
|
||||
setIsOpen((prev) => !prev);
|
||||
}, [isDisabled, isOpen, measureTriggerPosition]);
|
||||
const toggleDropdown = useCallback(() => {
|
||||
if (isDisabled) {
|
||||
return;
|
||||
}
|
||||
if (!isOpen) {
|
||||
measureTriggerPosition();
|
||||
}
|
||||
setIsOpen((prev) => !prev);
|
||||
}, [isDisabled, isOpen, measureTriggerPosition]);
|
||||
|
||||
const closeDropdown = useCallback(() => setIsOpen(false), []);
|
||||
const closeDropdown = useCallback(() => setIsOpen(false), []);
|
||||
|
||||
const handleSelect = useCallback(
|
||||
(project) => {
|
||||
if (!project?.id) return;
|
||||
onSelectProject?.(project);
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => ({
|
||||
close: closeDropdown,
|
||||
}),
|
||||
[closeDropdown]
|
||||
);
|
||||
|
||||
const handleSelect = useCallback(
|
||||
(project) => {
|
||||
if (!project?.id) return;
|
||||
onSelectProject?.(project);
|
||||
closeDropdown();
|
||||
},
|
||||
[closeDropdown, onSelectProject]
|
||||
);
|
||||
|
||||
const handleModify = useCallback(
|
||||
(project, anchor) => {
|
||||
if (!project?.id) return;
|
||||
onModifyProject?.(project, anchor);
|
||||
},
|
||||
[onModifyProject]
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
onCreateProject?.();
|
||||
closeDropdown();
|
||||
},
|
||||
[closeDropdown, onSelectProject]
|
||||
);
|
||||
|
||||
const handleModify = useCallback(
|
||||
(project, anchor) => {
|
||||
if (!project?.id) return;
|
||||
onModifyProject?.(project, anchor);
|
||||
},
|
||||
[onModifyProject]
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
onCreateProject?.();
|
||||
closeDropdown();
|
||||
}, [closeDropdown, onCreateProject]);
|
||||
}, [closeDropdown, onCreateProject]);
|
||||
|
||||
const dropdownWidth = useMemo(
|
||||
() => triggerLayout?.width || 0,
|
||||
@@ -286,74 +300,75 @@ const ProjectDropDown = ({
|
||||
</ThemedBlurView>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={[styles.container, style]}>
|
||||
<View
|
||||
ref={triggerRef}
|
||||
style={styles.triggerWrapper}
|
||||
onLayout={(event) => {
|
||||
setTriggerLayout(event.nativeEvent.layout);
|
||||
measureTriggerPosition();
|
||||
}}
|
||||
>
|
||||
<Animated.View
|
||||
pointerEvents={isOpen ? "none" : "auto"}
|
||||
style={[
|
||||
styles.dropdownTriggerContainer,
|
||||
{
|
||||
opacity: triggerOpacity,
|
||||
transform: [{ translateY: triggerTranslateY }],
|
||||
},
|
||||
]}
|
||||
return (
|
||||
<View style={[styles.container, style]}>
|
||||
<View
|
||||
ref={triggerRef}
|
||||
style={styles.triggerWrapper}
|
||||
onLayout={(event) => {
|
||||
setTriggerLayout(event.nativeEvent.layout);
|
||||
measureTriggerPosition();
|
||||
}}
|
||||
>
|
||||
<ThemedBlurView
|
||||
<Animated.View
|
||||
pointerEvents={isOpen ? "none" : "auto"}
|
||||
style={[
|
||||
styles.dropdownBlur,
|
||||
isDisabled && styles.dropdownBlurDisabled,
|
||||
styles.dropdownTriggerContainer,
|
||||
{
|
||||
opacity: triggerOpacity,
|
||||
transform: [{ translateY: triggerTranslateY }],
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ProjectRow
|
||||
isTitle={true}
|
||||
isOpen={isOpen}
|
||||
project={currentProject}
|
||||
formatDate={formatDate}
|
||||
onSelect={toggleDropdown}
|
||||
/>
|
||||
</ThemedBlurView>
|
||||
</Animated.View>
|
||||
<ThemedBlurView
|
||||
style={[
|
||||
styles.dropdownBlur,
|
||||
isDisabled && styles.dropdownBlurDisabled,
|
||||
]}
|
||||
>
|
||||
<ProjectRow
|
||||
isTitle={true}
|
||||
isOpen={isOpen}
|
||||
project={currentProject}
|
||||
formatDate={formatDate}
|
||||
onSelect={toggleDropdown}
|
||||
/>
|
||||
</ThemedBlurView>
|
||||
</Animated.View>
|
||||
|
||||
{isOpen && triggerWindowLayout ? (
|
||||
<Portal>
|
||||
<View style={styles.portalContainer}>
|
||||
<Pressable style={styles.backdrop} onPress={closeDropdown}>
|
||||
<ThemedBlurView
|
||||
pointerEvents="none"
|
||||
style={styles.backdropBlur}
|
||||
/>
|
||||
</Pressable>
|
||||
<Animated.View
|
||||
pointerEvents="auto"
|
||||
style={[
|
||||
styles.dropdownOverlayContainer,
|
||||
overlayPositionStyle,
|
||||
{
|
||||
opacity: dropdownAnimation,
|
||||
transform: [
|
||||
{ translateY: overlayTranslateY },
|
||||
{ scale: overlayScale },
|
||||
],
|
||||
},
|
||||
]}
|
||||
>
|
||||
{dropdownContent}
|
||||
</Animated.View>
|
||||
</View>
|
||||
</Portal>
|
||||
) : null}
|
||||
{isOpen && triggerWindowLayout ? (
|
||||
<Portal>
|
||||
<View style={styles.portalContainer}>
|
||||
<Pressable style={styles.backdrop} onPress={closeDropdown}>
|
||||
<ThemedBlurView
|
||||
pointerEvents="none"
|
||||
style={styles.backdropBlur}
|
||||
/>
|
||||
</Pressable>
|
||||
<Animated.View
|
||||
pointerEvents="auto"
|
||||
style={[
|
||||
styles.dropdownOverlayContainer,
|
||||
overlayPositionStyle,
|
||||
{
|
||||
opacity: dropdownAnimation,
|
||||
transform: [
|
||||
{ translateY: overlayTranslateY },
|
||||
{ scale: overlayScale },
|
||||
],
|
||||
},
|
||||
]}
|
||||
>
|
||||
{dropdownContent}
|
||||
</Animated.View>
|
||||
</View>
|
||||
</Portal>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default ProjectDropDown;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user