diff --git a/src/lib/utils/checklist.test.ts b/src/lib/utils/checklist.test.ts index c235827..c3905b3 100644 --- a/src/lib/utils/checklist.test.ts +++ b/src/lib/utils/checklist.test.ts @@ -112,6 +112,21 @@ describe('toggleItemWithCascade', () => { expect(result[0].checked).toBe(false); expect(result[0].parentId).toBeNull(); }); + + it('unchecking a child repositions it after its parent and siblings', () => { + // Simulates: parent + 2 children, one child checked (at end of array as done item) + const items: ChecklistItem[] = [ + { id: '1', text: 'Parent', checked: false, parentId: null }, + { id: '3', text: 'Child B', checked: false, parentId: '1' }, + { id: '4', text: 'Other', checked: false, parentId: null }, + { id: '2', text: 'Child A', checked: true, parentId: '1' } // done, at end + ]; + const result = toggleItemWithCascade('2', items); + // Child A should be repositioned after Child B (last sibling), not stay at end + const ids = result.map(i => i.id); + expect(ids).toEqual(['1', '3', '2', '4']); + expect(result.find(i => i.id === '2')!.checked).toBe(false); + }); }); describe('indentItem', () => { diff --git a/src/lib/utils/checklist.ts b/src/lib/utils/checklist.ts index 73d68af..9843ad8 100644 --- a/src/lib/utils/checklist.ts +++ b/src/lib/utils/checklist.ts @@ -31,11 +31,29 @@ export function toggleItemWithCascade(id: string, items: ChecklistItem[]): Check return item; }); - // When unchecking a child from done: if parent no longer exists, orphan it + // When unchecking a child: reposition it after its parent/siblings in the array + // (otherwise it stays at the end of the array where done items live) if (!newChecked && target.parentId) { const parentExists = result.some((i) => i.id === target.parentId); if (!parentExists) { + // Parent deleted — orphan it result = result.map((i) => (i.id === id ? { ...i, parentId: null } : i)); + } else { + // Remove the item from its current position + const uncheckedItem = result.find((i) => i.id === id)!; + result = result.filter((i) => i.id !== id); + // Find the last sibling or the parent, insert after it + let insertAfter = -1; + for (let i = 0; i < result.length; i++) { + if (result[i].id === target.parentId || result[i].parentId === target.parentId) { + insertAfter = i; + } + } + if (insertAfter >= 0) { + result.splice(insertAfter + 1, 0, uncheckedItem); + } else { + result.push(uncheckedItem); + } } }