Skip to content

Commit 8003280

Browse files
committed
Fix margin-top animation jumping issue
- Remove space-y-2 from parent container to prevent CSS conflicts - Add explicit marginTop style to TodoItem with conditional first item handling - Update exit animation timing for smoother marginTop transition - Add isFirst prop to TodoItemProps interface - Ensure first item has no top margin, subsequent items have 8px margin - Animate marginTop collapse before height for smoother deletion
1 parent 00190f5 commit 8003280

2 files changed

Lines changed: 16 additions & 5 deletions

File tree

app/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,16 +297,17 @@ export default function Home() {
297297
<TopBar userInitial="B" onAddItem={addTodo} currentDate={currentDate} />
298298

299299
<main className="sf-main-content w-full mx-auto flex-1 p-[0_16px_40px_16px]">
300-
<div className="sf-todo-list space-y-2 mx-auto w-full max-w-sjofn">
300+
<div className="sf-todo-list mx-auto w-full max-w-sjofn">
301301
<AnimatePresence initial={false}>
302-
{todos.map((todo) => (
302+
{todos.map((todo, index) => (
303303
<TodoItem
304304
key={todo.id}
305305
todo={todo}
306306
onStatusChange={updateTodoStatus}
307307
onTextChange={updateTodoText}
308308
onDelete={deleteTodo}
309309
autoFocus={todo.id === autoFocusId}
310+
isFirst={index === 0}
310311
/>
311312
))}
312313
</AnimatePresence>

components/TodoItem.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface TodoItemProps {
1717
onTextChange: (id: string, newText: string) => void;
1818
onDelete: (id: string) => void;
1919
autoFocus?: boolean;
20+
isFirst?: boolean;
2021
}
2122

2223
// SVG Components for status icons
@@ -103,7 +104,14 @@ const DeleteIcon = () => (
103104

104105
const TodoItem = React.forwardRef<HTMLDivElement, TodoItemProps>(
105106
function TodoItem(
106-
{ todo, onStatusChange, onTextChange, onDelete, autoFocus = false },
107+
{
108+
todo,
109+
onStatusChange,
110+
onTextChange,
111+
onDelete,
112+
autoFocus = false,
113+
isFirst = false,
114+
},
107115
ref
108116
) {
109117
const [isEditing, setIsEditing] = useState(false);
@@ -182,7 +190,8 @@ const TodoItem = React.forwardRef<HTMLDivElement, TodoItemProps>(
182190
return (
183191
<motion.div
184192
ref={ref}
185-
className="sf-todo-item-wrapper mt-0"
193+
className="sf-todo-item-wrapper"
194+
style={{ marginTop: isFirst ? "0px" : "8px" }}
186195
initial={{ opacity: 0, y: -20, scale: 0.95 }}
187196
animate={{ opacity: 1, y: 0, scale: 1 }}
188197
exit={{
@@ -194,9 +203,10 @@ const TodoItem = React.forwardRef<HTMLDivElement, TodoItemProps>(
194203
transition: {
195204
duration: 0.3,
196205
ease: "easeInOut",
197-
height: { duration: 0.2, delay: 0.1 },
198206
opacity: { duration: 0.15 },
199207
scale: { duration: 0.15 },
208+
marginTop: { duration: 0.2, delay: 0.05 },
209+
height: { duration: 0.15, delay: 0.15 },
200210
},
201211
}}
202212
transition={{

0 commit comments

Comments
 (0)