|
|
|
@@ -65,6 +65,17 @@ const PALETTE_SEGMENT_OVERRIDES = [
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const getPaletteSegmentInfo = (type) => {
|
|
|
|
|
const meta = getSegmentMeta(type);
|
|
|
|
|
const override = PALETTE_SEGMENT_OVERRIDES.find(
|
|
|
|
|
(segment) => segment.type === type
|
|
|
|
|
);
|
|
|
|
|
return {
|
|
|
|
|
label: meta?.label || formatStructureLabel(type, 1),
|
|
|
|
|
description: override?.description || "",
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getScrollY = () => (typeof window !== "undefined" ? window.scrollY : 0);
|
|
|
|
|
|
|
|
|
|
const randomSuffix = () => Math.random().toString(36).slice(2, 8);
|
|
|
|
@@ -163,6 +174,7 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
);
|
|
|
|
|
const [activeItemId, setActiveItemId] = useState(null);
|
|
|
|
|
const [insertPreviewIndex, setInsertPreviewIndex] = useState(null);
|
|
|
|
|
const [dragOverlay, setDragOverlay] = useState(null);
|
|
|
|
|
const containerRef = useRef(null);
|
|
|
|
|
const sortableItemsRef = useRef(sortableItems);
|
|
|
|
|
const dragStateRef = useRef({
|
|
|
|
@@ -175,8 +187,36 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
isOverContainer: false,
|
|
|
|
|
startItems: null,
|
|
|
|
|
blockedReason: null,
|
|
|
|
|
startIndex: null,
|
|
|
|
|
slotIndex: null,
|
|
|
|
|
grabOffsetX: null,
|
|
|
|
|
grabOffsetY: null,
|
|
|
|
|
});
|
|
|
|
|
const globalListenersRef = useRef({ move: null, up: null });
|
|
|
|
|
const clearDragOverlay = useCallback(() => {
|
|
|
|
|
setDragOverlay(null);
|
|
|
|
|
}, []);
|
|
|
|
|
const updateDragOverlayPosition = useCallback((clientX, clientY) => {
|
|
|
|
|
setDragOverlay((prev) => {
|
|
|
|
|
if (!prev) return prev;
|
|
|
|
|
const offsetX =
|
|
|
|
|
typeof dragStateRef.current?.grabOffsetX === "number"
|
|
|
|
|
? dragStateRef.current.grabOffsetX
|
|
|
|
|
: prev.width / 2;
|
|
|
|
|
const offsetY =
|
|
|
|
|
typeof dragStateRef.current?.grabOffsetY === "number"
|
|
|
|
|
? dragStateRef.current.grabOffsetY
|
|
|
|
|
: prev.height / 2;
|
|
|
|
|
const left =
|
|
|
|
|
typeof clientX === "number" ? clientX - offsetX : prev.left;
|
|
|
|
|
const top =
|
|
|
|
|
typeof clientY === "number" ? clientY - offsetY : prev.top;
|
|
|
|
|
if (left === prev.left && top === prev.top) {
|
|
|
|
|
return prev;
|
|
|
|
|
}
|
|
|
|
|
return { ...prev, left, top };
|
|
|
|
|
});
|
|
|
|
|
}, []);
|
|
|
|
|
const showTooltip = useCallback(
|
|
|
|
|
(text, type = "error") => {
|
|
|
|
|
if (!text) return;
|
|
|
|
@@ -229,14 +269,11 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
const paletteSegments = useMemo(
|
|
|
|
|
() =>
|
|
|
|
|
OPTIONAL_STRUCTURE_SEGMENTS.map((type) => {
|
|
|
|
|
const meta = getSegmentMeta(type);
|
|
|
|
|
const override = PALETTE_SEGMENT_OVERRIDES.find(
|
|
|
|
|
(segment) => segment.type === type
|
|
|
|
|
);
|
|
|
|
|
const info = getPaletteSegmentInfo(type);
|
|
|
|
|
return {
|
|
|
|
|
type,
|
|
|
|
|
label: meta?.label || formatStructureLabel(type, 1),
|
|
|
|
|
description: override?.description || "",
|
|
|
|
|
label: info.label,
|
|
|
|
|
description: info.description,
|
|
|
|
|
};
|
|
|
|
|
}),
|
|
|
|
|
[]
|
|
|
|
@@ -352,6 +389,10 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
isOverContainer: false,
|
|
|
|
|
startItems: null,
|
|
|
|
|
blockedReason: null,
|
|
|
|
|
startIndex: null,
|
|
|
|
|
slotIndex: null,
|
|
|
|
|
grabOffsetX: null,
|
|
|
|
|
grabOffsetY: null,
|
|
|
|
|
};
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
@@ -401,34 +442,77 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
: scrollY;
|
|
|
|
|
const pointerY = absoluteY - (dragState.containerTop || 0);
|
|
|
|
|
|
|
|
|
|
updateDragOverlayPosition(event?.clientX, event?.clientY);
|
|
|
|
|
|
|
|
|
|
if (dragState.itemId) {
|
|
|
|
|
dragStateRef.current.blockedReason = null;
|
|
|
|
|
setSortableItems((prev) => {
|
|
|
|
|
const currentIndex = prev.findIndex(
|
|
|
|
|
(it) => it.id === dragState.itemId
|
|
|
|
|
);
|
|
|
|
|
if (currentIndex === -1) return prev;
|
|
|
|
|
const maxIndex = Math.max(prev.length - 1, 0);
|
|
|
|
|
const targetIndex = clamp(
|
|
|
|
|
Math.floor(pointerY / ROW_HEIGHT),
|
|
|
|
|
0,
|
|
|
|
|
maxIndex
|
|
|
|
|
);
|
|
|
|
|
const movingItem = prev[currentIndex];
|
|
|
|
|
const rect = dragState.containerRect;
|
|
|
|
|
const listLength = sortableItemsRef.current.length;
|
|
|
|
|
const isOver =
|
|
|
|
|
rect == null
|
|
|
|
|
? true
|
|
|
|
|
: event.clientX >= rect.left && event.clientX <= rect.right;
|
|
|
|
|
dragStateRef.current.isOverContainer = isOver;
|
|
|
|
|
|
|
|
|
|
if (!isOver) {
|
|
|
|
|
dragStateRef.current.targetIndex = null;
|
|
|
|
|
dragStateRef.current.slotIndex = null;
|
|
|
|
|
if (insertPreviewIndex !== null) {
|
|
|
|
|
setInsertPreviewIndex(null);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const containerHeight = rect?.height ?? listLength * ROW_HEIGHT;
|
|
|
|
|
let slotIndex = Math.round(pointerY / ROW_HEIGHT);
|
|
|
|
|
if (pointerY < 0) slotIndex = 0;
|
|
|
|
|
if (pointerY > containerHeight) slotIndex = listLength;
|
|
|
|
|
slotIndex = clamp(slotIndex, 0, listLength);
|
|
|
|
|
|
|
|
|
|
const snapshot = dragState.startItems || sortableItemsRef.current;
|
|
|
|
|
const movingIndex =
|
|
|
|
|
typeof dragState.startIndex === "number"
|
|
|
|
|
? dragState.startIndex
|
|
|
|
|
: snapshot.findIndex((item) => item.id === dragState.itemId);
|
|
|
|
|
dragStateRef.current.startIndex = movingIndex;
|
|
|
|
|
if (movingIndex < 0) {
|
|
|
|
|
dragStateRef.current.slotIndex = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const movingItem = snapshot[movingIndex];
|
|
|
|
|
const movingType = movingItem?.type || movingItem?.value;
|
|
|
|
|
const topType = prev[0]?.type || prev[0]?.value;
|
|
|
|
|
const topType = snapshot[0]?.type || snapshot[0]?.value;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
targetIndex === 0 &&
|
|
|
|
|
slotIndex === 0 &&
|
|
|
|
|
INTRO_TYPES.has(topType) &&
|
|
|
|
|
!INTRO_TYPES.has(movingType)
|
|
|
|
|
) {
|
|
|
|
|
dragStateRef.current.blockedReason = "intro_must_be_first";
|
|
|
|
|
return prev;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (targetIndex === currentIndex) return prev;
|
|
|
|
|
const reordered = reorder(prev, currentIndex, targetIndex);
|
|
|
|
|
return recalculateOccurrences(reordered);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
dragStateRef.current.blockedReason = null;
|
|
|
|
|
const shouldPreview =
|
|
|
|
|
typeof movingIndex === "number" &&
|
|
|
|
|
slotIndex !== movingIndex &&
|
|
|
|
|
slotIndex !== movingIndex + 1;
|
|
|
|
|
if (shouldPreview) {
|
|
|
|
|
if (dragStateRef.current.slotIndex !== slotIndex) {
|
|
|
|
|
dragStateRef.current.slotIndex = slotIndex;
|
|
|
|
|
setInsertPreviewIndex(slotIndex);
|
|
|
|
|
}
|
|
|
|
|
} else if (insertPreviewIndex !== null) {
|
|
|
|
|
dragStateRef.current.slotIndex = null;
|
|
|
|
|
setInsertPreviewIndex(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let targetIndex = slotIndex;
|
|
|
|
|
if (typeof movingIndex === "number" && slotIndex > movingIndex) {
|
|
|
|
|
targetIndex -= 1;
|
|
|
|
|
}
|
|
|
|
|
targetIndex = clamp(targetIndex, 0, Math.max(listLength - 1, 0));
|
|
|
|
|
dragStateRef.current.targetIndex = targetIndex;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -462,7 +546,7 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
setInsertPreviewIndex(targetIndex);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
[insertPreviewIndex, setSortableItems]
|
|
|
|
|
[insertPreviewIndex, setInsertPreviewIndex, updateDragOverlayPosition]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const handleGlobalPointerUp = useCallback(
|
|
|
|
@@ -480,17 +564,36 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
if (dragState.itemId) {
|
|
|
|
|
if (dragState.blockedReason === "intro_must_be_first") {
|
|
|
|
|
showTooltip(INTRO_ERROR_MESSAGE);
|
|
|
|
|
}
|
|
|
|
|
const validation = validateStructureRules(
|
|
|
|
|
sortableItemsRef.current || []
|
|
|
|
|
} else if (
|
|
|
|
|
dragState.isOverContainer &&
|
|
|
|
|
typeof dragState.targetIndex === "number"
|
|
|
|
|
) {
|
|
|
|
|
const desiredIndex = dragState.targetIndex;
|
|
|
|
|
setSortableItems((prev) => {
|
|
|
|
|
const currentIndex = prev.findIndex(
|
|
|
|
|
(it) => it.id === dragState.itemId
|
|
|
|
|
);
|
|
|
|
|
if (currentIndex === -1) return prev;
|
|
|
|
|
const targetIndex = clamp(
|
|
|
|
|
desiredIndex,
|
|
|
|
|
0,
|
|
|
|
|
Math.max(prev.length, 0)
|
|
|
|
|
);
|
|
|
|
|
if (targetIndex === currentIndex) {
|
|
|
|
|
return prev;
|
|
|
|
|
}
|
|
|
|
|
const reordered = reorder(prev, currentIndex, targetIndex);
|
|
|
|
|
const recalculated = recalculateOccurrences(reordered);
|
|
|
|
|
const validation = validateStructureRules(recalculated);
|
|
|
|
|
if (!validation.valid) {
|
|
|
|
|
const fallbackItems =
|
|
|
|
|
dragState.startItems?.map((item) => item) ||
|
|
|
|
|
sortableItemsRef.current?.map((item) => item) ||
|
|
|
|
|
[];
|
|
|
|
|
setSortableItems(fallbackItems);
|
|
|
|
|
prev;
|
|
|
|
|
showTooltip(validation.message);
|
|
|
|
|
return recalculateOccurrences(fallbackItems);
|
|
|
|
|
}
|
|
|
|
|
return recalculated;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} else if (dragState.paletteType) {
|
|
|
|
|
let isOver = dragState.isOverContainer;
|
|
|
|
@@ -532,9 +635,16 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
|
|
|
|
|
setActiveItemId(null);
|
|
|
|
|
setInsertPreviewIndex(null);
|
|
|
|
|
clearDragOverlay();
|
|
|
|
|
cleanupPointerListeners();
|
|
|
|
|
},
|
|
|
|
|
[addOptionalSegment, cleanupPointerListeners, showTooltip]
|
|
|
|
|
[
|
|
|
|
|
addOptionalSegment,
|
|
|
|
|
cleanupPointerListeners,
|
|
|
|
|
clearDragOverlay,
|
|
|
|
|
showTooltip,
|
|
|
|
|
setSortableItems,
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const attachGlobalListeners = useCallback(() => {
|
|
|
|
@@ -555,7 +665,7 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
}, [handleGlobalPointerMove, handleGlobalPointerUp]);
|
|
|
|
|
|
|
|
|
|
const startItemDrag = useCallback(
|
|
|
|
|
(itemId, event) => {
|
|
|
|
|
(itemId, event, dragElement = null) => {
|
|
|
|
|
const nativeEvent = event?.nativeEvent || {};
|
|
|
|
|
if (typeof nativeEvent.button === "number" && nativeEvent.button !== 0)
|
|
|
|
|
return;
|
|
|
|
@@ -571,6 +681,32 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
: scrollY;
|
|
|
|
|
const containerTop = rect ? rect.top + scrollY : fallbackY;
|
|
|
|
|
const snapshot = sortableItemsRef.current?.map((item) => item) || [];
|
|
|
|
|
const startIndex = snapshot.findIndex((item) => item.id === itemId);
|
|
|
|
|
const movingItem = startIndex >= 0 ? snapshot[startIndex] : null;
|
|
|
|
|
const baseType = movingItem?.type || movingItem?.value;
|
|
|
|
|
const occurrence =
|
|
|
|
|
typeof movingItem?.occurrence === "number" ? movingItem.occurrence : 1;
|
|
|
|
|
const label =
|
|
|
|
|
baseType != null ? formatStructureLabel(baseType, occurrence) : "";
|
|
|
|
|
const pointerClientX =
|
|
|
|
|
typeof nativeEvent.clientX === "number" ? nativeEvent.clientX : 0;
|
|
|
|
|
const pointerClientY =
|
|
|
|
|
typeof nativeEvent.clientY === "number" ? nativeEvent.clientY : 0;
|
|
|
|
|
const getRect = (node) =>
|
|
|
|
|
typeof node?.getBoundingClientRect === "function"
|
|
|
|
|
? node.getBoundingClientRect()
|
|
|
|
|
: null;
|
|
|
|
|
const itemRect = getRect(dragElement) || getRect(event?.currentTarget);
|
|
|
|
|
const overlayWidth = itemRect?.width || rect?.width || 280;
|
|
|
|
|
const overlayHeight = itemRect?.height || ROW_HEIGHT;
|
|
|
|
|
const grabOffsetX = itemRect
|
|
|
|
|
? pointerClientX - itemRect.left
|
|
|
|
|
: overlayWidth / 2;
|
|
|
|
|
const grabOffsetY = itemRect
|
|
|
|
|
? pointerClientY - itemRect.top
|
|
|
|
|
: overlayHeight / 2;
|
|
|
|
|
const overlayLeft = pointerClientX - grabOffsetX;
|
|
|
|
|
const overlayTop = pointerClientY - grabOffsetY;
|
|
|
|
|
|
|
|
|
|
dragStateRef.current = {
|
|
|
|
|
itemId,
|
|
|
|
@@ -593,10 +729,23 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
isOverContainer: true,
|
|
|
|
|
startItems: snapshot,
|
|
|
|
|
blockedReason: null,
|
|
|
|
|
startIndex,
|
|
|
|
|
slotIndex: null,
|
|
|
|
|
grabOffsetX,
|
|
|
|
|
grabOffsetY,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setActiveItemId(itemId);
|
|
|
|
|
setInsertPreviewIndex(null);
|
|
|
|
|
setDragOverlay({
|
|
|
|
|
kind: "structure",
|
|
|
|
|
label,
|
|
|
|
|
description: "",
|
|
|
|
|
width: overlayWidth,
|
|
|
|
|
height: overlayHeight,
|
|
|
|
|
left: overlayLeft,
|
|
|
|
|
top: overlayTop,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (typeof document !== "undefined") {
|
|
|
|
|
document.body.style.userSelect = "none";
|
|
|
|
@@ -624,6 +773,25 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
? nativeEvent.clientY + scrollY
|
|
|
|
|
: scrollY;
|
|
|
|
|
const containerTop = rect ? rect.top + scrollY : fallbackY;
|
|
|
|
|
const pointerClientX =
|
|
|
|
|
typeof nativeEvent.clientX === "number" ? nativeEvent.clientX : 0;
|
|
|
|
|
const pointerClientY =
|
|
|
|
|
typeof nativeEvent.clientY === "number" ? nativeEvent.clientY : 0;
|
|
|
|
|
const cardRect =
|
|
|
|
|
typeof event?.currentTarget?.getBoundingClientRect === "function"
|
|
|
|
|
? event.currentTarget.getBoundingClientRect()
|
|
|
|
|
: null;
|
|
|
|
|
const overlayWidth = cardRect?.width || 320;
|
|
|
|
|
const overlayHeight = cardRect?.height || ROW_HEIGHT;
|
|
|
|
|
const grabOffsetX = cardRect
|
|
|
|
|
? pointerClientX - cardRect.left
|
|
|
|
|
: overlayWidth / 2;
|
|
|
|
|
const grabOffsetY = cardRect
|
|
|
|
|
? pointerClientY - cardRect.top
|
|
|
|
|
: overlayHeight / 2;
|
|
|
|
|
const overlayLeft = pointerClientX - grabOffsetX;
|
|
|
|
|
const overlayTop = pointerClientY - grabOffsetY;
|
|
|
|
|
const segmentInfo = getPaletteSegmentInfo(type);
|
|
|
|
|
|
|
|
|
|
dragStateRef.current = {
|
|
|
|
|
itemId: null,
|
|
|
|
@@ -645,10 +813,23 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
targetIndex: null,
|
|
|
|
|
isOverContainer: false,
|
|
|
|
|
blockedReason: null,
|
|
|
|
|
startIndex: null,
|
|
|
|
|
slotIndex: null,
|
|
|
|
|
grabOffsetX,
|
|
|
|
|
grabOffsetY,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setActiveItemId(`palette-${type}`);
|
|
|
|
|
setInsertPreviewIndex(null);
|
|
|
|
|
setDragOverlay({
|
|
|
|
|
kind: "palette",
|
|
|
|
|
label: segmentInfo.label,
|
|
|
|
|
description: segmentInfo.description,
|
|
|
|
|
width: overlayWidth,
|
|
|
|
|
height: overlayHeight,
|
|
|
|
|
left: overlayLeft,
|
|
|
|
|
top: overlayTop,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (typeof document !== "undefined") {
|
|
|
|
|
document.body.style.userSelect = "none";
|
|
|
|
@@ -665,17 +846,22 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
const meta = getSegmentMeta(baseType);
|
|
|
|
|
const canRemove = meta?.optional === true;
|
|
|
|
|
const isIntroduction = INTRO_TYPES.has(baseType);
|
|
|
|
|
const rowRef = useRef(null);
|
|
|
|
|
const isActive = activeItemId === item.id;
|
|
|
|
|
const containerStyle = StyleSheet.flatten([
|
|
|
|
|
styles.rowContainer,
|
|
|
|
|
activeItemId === item.id ? styles.activeItem : null,
|
|
|
|
|
isActive ? styles.activeItem : null,
|
|
|
|
|
isActive ? styles.draggingContainer : null,
|
|
|
|
|
]);
|
|
|
|
|
const blurStyle = StyleSheet.flatten([
|
|
|
|
|
styles.itemBlur,
|
|
|
|
|
activeItemId === item.id ? styles.activeBlur : null,
|
|
|
|
|
isActive ? styles.activeBlur : null,
|
|
|
|
|
isActive ? styles.draggingBlur : null,
|
|
|
|
|
]);
|
|
|
|
|
const rowStyle = StyleSheet.flatten([
|
|
|
|
|
styles.row,
|
|
|
|
|
isIntroduction ? styles.rowDisabled : styles.rowDraggable,
|
|
|
|
|
isActive ? styles.rowHidden : null,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
@@ -687,10 +873,11 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
blurViewStyle={blurStyle}
|
|
|
|
|
>
|
|
|
|
|
<View
|
|
|
|
|
ref={rowRef}
|
|
|
|
|
style={rowStyle}
|
|
|
|
|
onPointerDown={(event) => {
|
|
|
|
|
if (isIntroduction) return;
|
|
|
|
|
startItemDrag(item.id, event);
|
|
|
|
|
startItemDrag(item.id, event, rowRef.current);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Text style={styles.rowText}>{item.label}</Text>
|
|
|
|
@@ -714,7 +901,7 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
style={styles.handleWrapper}
|
|
|
|
|
onPointerDown={(event) => {
|
|
|
|
|
event?.stopPropagation?.();
|
|
|
|
|
startItemDrag(item.id, event);
|
|
|
|
|
startItemDrag(item.id, event, rowRef.current);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Image source={icons.dragDots} style={styles.handleIcon} />
|
|
|
|
@@ -848,6 +1035,52 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|
|
|
|
</View>
|
|
|
|
|
</View>
|
|
|
|
|
</ScrollView>
|
|
|
|
|
{dragOverlay ? (
|
|
|
|
|
<View
|
|
|
|
|
pointerEvents="none"
|
|
|
|
|
style={StyleSheet.flatten([
|
|
|
|
|
styles.dragOverlay,
|
|
|
|
|
{
|
|
|
|
|
width: dragOverlay.width || 320,
|
|
|
|
|
height: dragOverlay.height || ROW_HEIGHT,
|
|
|
|
|
left: dragOverlay.left || 0,
|
|
|
|
|
top: dragOverlay.top || 0,
|
|
|
|
|
},
|
|
|
|
|
])}
|
|
|
|
|
>
|
|
|
|
|
<CreateLyricsHeader
|
|
|
|
|
tint="dark"
|
|
|
|
|
intensity={40}
|
|
|
|
|
showBorder={false}
|
|
|
|
|
containerStyle={StyleSheet.flatten([
|
|
|
|
|
styles.rowContainer,
|
|
|
|
|
styles.dragOverlayContainer,
|
|
|
|
|
])}
|
|
|
|
|
blurViewStyle={StyleSheet.flatten([
|
|
|
|
|
styles.itemBlur,
|
|
|
|
|
dragOverlay.kind === "palette" ? styles.paletteItemBlur : null,
|
|
|
|
|
styles.dragOverlayBlur,
|
|
|
|
|
])}
|
|
|
|
|
>
|
|
|
|
|
{dragOverlay.kind === "palette" ? (
|
|
|
|
|
<View style={styles.paletteRow}>
|
|
|
|
|
<View style={styles.paletteTextWrapper}>
|
|
|
|
|
<Text style={styles.rowText}>{dragOverlay.label}</Text>
|
|
|
|
|
{dragOverlay.description ? (
|
|
|
|
|
<Text style={styles.paletteDescription}>
|
|
|
|
|
{dragOverlay.description}
|
|
|
|
|
</Text>
|
|
|
|
|
) : null}
|
|
|
|
|
</View>
|
|
|
|
|
</View>
|
|
|
|
|
) : (
|
|
|
|
|
<View style={styles.row}>
|
|
|
|
|
<Text style={styles.rowText}>{dragOverlay.label}</Text>
|
|
|
|
|
</View>
|
|
|
|
|
)}
|
|
|
|
|
</CreateLyricsHeader>
|
|
|
|
|
</View>
|
|
|
|
|
) : null}
|
|
|
|
|
</View>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
@@ -918,6 +1151,9 @@ const styles = StyleSheet.create({
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: Palette.white,
|
|
|
|
|
},
|
|
|
|
|
draggingContainer: {
|
|
|
|
|
opacity: 0,
|
|
|
|
|
},
|
|
|
|
|
itemBlur: {
|
|
|
|
|
minHeight: ROW_HEIGHT,
|
|
|
|
|
paddingHorizontal: 16,
|
|
|
|
@@ -934,6 +1170,9 @@ const styles = StyleSheet.create({
|
|
|
|
|
activeBlur: {
|
|
|
|
|
backgroundColor: Palette.transparentWhite,
|
|
|
|
|
},
|
|
|
|
|
draggingBlur: {
|
|
|
|
|
opacity: 0,
|
|
|
|
|
},
|
|
|
|
|
row: {
|
|
|
|
|
flex: 1,
|
|
|
|
|
flexDirection: "row",
|
|
|
|
@@ -946,6 +1185,9 @@ const styles = StyleSheet.create({
|
|
|
|
|
rowDisabled: {
|
|
|
|
|
cursor: "default",
|
|
|
|
|
},
|
|
|
|
|
rowHidden: {
|
|
|
|
|
opacity: 0,
|
|
|
|
|
},
|
|
|
|
|
rowText: {
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
color: Palette.white,
|
|
|
|
@@ -1033,4 +1275,21 @@ const styles = StyleSheet.create({
|
|
|
|
|
color: Palette.white,
|
|
|
|
|
fontFamily: FONT_FAMILY.InterMedium,
|
|
|
|
|
},
|
|
|
|
|
dragOverlay: {
|
|
|
|
|
position: "fixed",
|
|
|
|
|
zIndex: 999,
|
|
|
|
|
pointerEvents: "none",
|
|
|
|
|
},
|
|
|
|
|
dragOverlayContainer: {
|
|
|
|
|
width: "100%",
|
|
|
|
|
},
|
|
|
|
|
dragOverlayBlur: {
|
|
|
|
|
cursor: "grabbing",
|
|
|
|
|
opacity: 1,
|
|
|
|
|
shadowColor: "#000",
|
|
|
|
|
shadowOpacity: 0.35,
|
|
|
|
|
shadowRadius: 12,
|
|
|
|
|
shadowOffset: { width: 0, height: 8 },
|
|
|
|
|
elevation: 6,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|