instrumental introduction
This commit is contained in:
@@ -17,9 +17,9 @@ const getScrollY = () => (typeof window !== "undefined" ? window.scrollY : 0);
|
||||
|
||||
const randomSuffix = () => Math.random().toString(36).slice(2, 8);
|
||||
|
||||
const buildItems = (structure = []) => {
|
||||
const buildSortableItems = (values = []) => {
|
||||
const counters = {};
|
||||
return structure.map((segment, index) => {
|
||||
return sanitizeStructureList(values).map((segment, index) => {
|
||||
counters[segment] = (counters[segment] || 0) + 1;
|
||||
return {
|
||||
id: `${segment}-${index}-${randomSuffix()}`,
|
||||
@@ -44,7 +44,7 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
||||
() => sanitizeStructureList(baseStructure),
|
||||
[baseStructure]
|
||||
);
|
||||
const [items, setItems] = React.useState(() => buildItems(sanitized));
|
||||
const [items, setItems] = React.useState(() => buildSortableItems(sanitized));
|
||||
const [activeItemId, setActiveItemId] = React.useState(null);
|
||||
const containerRef = React.useRef(null);
|
||||
const dragStateRef = React.useRef({
|
||||
@@ -54,38 +54,40 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
||||
|
||||
React.useEffect(() => {
|
||||
console.debug("[CustomizeSongStructure.web] sanitized", sanitized);
|
||||
setItems((prev) => {
|
||||
const prevTypes = prev.map((item) => item.type);
|
||||
if (prevTypes.length === sanitized.length) {
|
||||
const same = prevTypes.every((type, idx) => type === sanitized[idx]);
|
||||
if (same) return prev;
|
||||
}
|
||||
return buildItems(sanitized);
|
||||
});
|
||||
setItems(buildSortableItems(sanitized));
|
||||
dragStateRef.current = { itemId: null, containerTop: 0 };
|
||||
setActiveItemId(null);
|
||||
}, [sanitized]);
|
||||
|
||||
React.useEffect(() => {
|
||||
console.debug("[CustomizeSongStructure.web] items", items);
|
||||
onChange?.(items.map((item) => item.type));
|
||||
onChange?.(
|
||||
items.map((item) => (item?.type || item?.value)).filter(Boolean)
|
||||
);
|
||||
}, [items, onChange]);
|
||||
|
||||
const labeledItems = React.useMemo(() => {
|
||||
const counts = {};
|
||||
return items.map((item) => {
|
||||
counts[item.type] = (counts[item.type] || 0) + 1;
|
||||
const type = item?.type || item?.value;
|
||||
counts[type] = (counts[type] || 0) + 1;
|
||||
return {
|
||||
...item,
|
||||
label: formatStructureLabel(item.type, counts[item.type]),
|
||||
type,
|
||||
value: type,
|
||||
label: formatStructureLabel(type, counts[type]),
|
||||
};
|
||||
});
|
||||
}, [items]);
|
||||
|
||||
const selectedTypes = React.useMemo(
|
||||
() => new Set(items.map((item) => item.type)),
|
||||
[items]
|
||||
);
|
||||
const selectedTypes = React.useMemo(() => {
|
||||
const set = new Set();
|
||||
items.forEach((item) => {
|
||||
if (item?.type) set.add(item.type);
|
||||
else if (item?.value) set.add(item.value);
|
||||
});
|
||||
return set;
|
||||
}, [items]);
|
||||
|
||||
const optionalSegments = React.useMemo(
|
||||
() =>
|
||||
@@ -98,24 +100,21 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
||||
|
||||
const toggleOptionalSegment = React.useCallback((type) => {
|
||||
setItems((prev) => {
|
||||
const exists = prev.some((item) => item.type === type);
|
||||
if (exists) {
|
||||
return prev.filter((item) => item.type !== type);
|
||||
const currentValues = prev.map((item) => item.type || item.value);
|
||||
if (currentValues.includes(type)) {
|
||||
const filtered = currentValues.filter((value) => value !== type);
|
||||
return buildSortableItems(filtered);
|
||||
}
|
||||
const meta = getSegmentMeta(type);
|
||||
let next = [...prev];
|
||||
let nextValues = [...currentValues];
|
||||
if (meta?.exclusiveGroup) {
|
||||
next = next.filter((item) => {
|
||||
const itemMeta = getSegmentMeta(item.type);
|
||||
nextValues = nextValues.filter((value) => {
|
||||
const itemMeta = getSegmentMeta(value);
|
||||
return itemMeta?.exclusiveGroup !== meta.exclusiveGroup;
|
||||
});
|
||||
}
|
||||
next.push({
|
||||
id: `${type}-${Date.now()}-${randomSuffix()}`,
|
||||
type,
|
||||
value: type,
|
||||
});
|
||||
return next;
|
||||
nextValues.push(type);
|
||||
return buildSortableItems(nextValues);
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -169,6 +168,9 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
||||
};
|
||||
|
||||
const handleRelease = () => {
|
||||
setItems((prev) =>
|
||||
buildSortableItems(prev.map((item) => item.type || item.value))
|
||||
);
|
||||
dragStateRef.current = {
|
||||
itemId: null,
|
||||
containerTop: 0,
|
||||
|
||||
Reference in New Issue
Block a user