-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/#175 캐럿 관리방식 변경 #176
The head ref may contain hidden characters: "Feature/#175_\uCE90\uB7FF_\uAD00\uB9AC\uBC29\uC2DD_\uBCC0\uACBD"
Conversation
- currentBlock 제거 - 캐럿 이동시 requestAnimationFrame과 useLayoutEffect로 캐럿 위치 수정
- 캐럿은 editor에서 관리
- update시 localUpdate 사용 - 화살표 핸들러 실행 조건 변경 - 블록간 이동시에만 캐럿 위치 수정 - 블록 내부에서 이동할 경우 currentCaret값만 변경
기존에는 char별로 인덱스로 접근해서 드래그를 하자마자 풀리는 현상과 currentblock이 업데이트되면서 렌더가 일어났는데 이 현상이 해결되었군요! 좀더 자세히 알게되었습니다. 완성도를 다듬기위해 저도 더 작업해보겠습니다! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수고 많으셨습니다! 나중에 시간되실 때 중복된 로직만 제거해주셔도 좋을 것 같네요!
editorCRDT.current.currentBlock!.crdt.currentCaret = caretPosition; | ||
requestAnimationFrame(() => { | ||
setCaretPosition({ | ||
blockId: block.id, | ||
linkedList: editorCRDT.current.LinkedList, | ||
position: caretPosition, | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 로직이 중복해서 나오네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
혹시 해당 로직들이 필요한 이유가 있을까요? 이게 없으면 어떤 부분이 동작하지 않는걸까요??
이 부분을 다 지워봤을때, 특별히 동작이 안되던 부분이 없어서 질문드립니당!
requestAnimationFrame(() => {
setCaretPosition({
blockId: block.id,
linkedList: editorCRDT.current.LinkedList,
position: caretPosition,
});
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
확인해보니 이 부분의 문제가 아니었던 것 같습니다. 다른 부분 수정하면서 조금 헷갈렸네요... 이내용 현재 구현하고 있는 텍스트 옵션 PR 올릴때 수정하도록 하겠습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 서윤님 피드백 주신 내용을 보면 requestAnimationFrame 없이도 동작하는 것 같습니다. 이부분은 삭제하겠습니다!
if (!editorCRDT.current) return; | ||
editorCRDT.current.remoteInsert(operation); | ||
setEditorState((prev) => ({ | ||
setEditorState({ | ||
clock: editorCRDT.current.clock, | ||
linkedList: editorCRDT.current.LinkedList, | ||
currentBlock: prev.currentBlock, | ||
})); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이쪽은 묶으려면 묶을 수도 있겠는데 투머치일 것 같다는 생각이 들어서 굳이 묶을 필요는 없어보이네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
묶는게 정확이 어떤 걸 묶는다는 걸까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
비슷한 로직이 아래에도 중복해서 나오는 것 같아서 함수로 묶을 수 있겠다고 생각했는데 해보니까 좀 어거지로 묶이는 것 같더라구요.. 코멘트를 달기는 했는데 이 코멘트는 그냥 거르셔도 될 것 같습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
디버깅과정,, 고생하셨씁니당..!!
{ id: "ul", label: "리스트" }, | ||
{ id: "ol", label: "순서 리스트" }, | ||
{ id: "checkbox", label: "체크박스" }, | ||
{ id: "blockquote", label: "인용문" }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
대신 해주셨군요!! 감사합니다!! 🙇♂️
clock: editorCRDT.clock, | ||
linkedList: editorCRDT.LinkedList, | ||
currentBlock: prev.currentBlock, | ||
})); | ||
}); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. 옵션창 -> 삭제버튼 누를시, 캐럿이 제대로 이동하지 않는 문제
- 맨 처음 블록을 삭제할때 findByIndex 메서드에서 에러를 띄워주더라구요!
- findByIndex 자체에서 null을 반환할지, 혹은 지금 코드상에서 예외처리를 할까 고민했는데, 지금 코드상에서 한번더 예외처리를 해주는게 좋을 것 같아
findBlock
메서드를 추가했습니다! - 또한,local, remote 모두 삭제한 후에는, current Block은 currentIndex 값 그대로를 가야하더라구요. 그래서 index 부분도 수정했습니다.
- 그리고 이것만 수정하면 실제 캐럿이 제대로 랜더링되지 않던데, 이 문제는 다음 코멘트에서 설명드리겠습니다! (여기 메서드 자체에서 setCaretPosition 유틸함수를 쓰더라도 실제로 렌더링이 제대로 되지 않더라구요! )
}; | |
// ✅ 추가 | |
const findBlock = (linkedList: BlockLinkedList, index: number) => { | |
if (index < 0) return null; | |
if (index >= linkedList.spread().length) return null; | |
return linkedList.findByIndex(index); | |
}; | |
const handleDeleteSelect = (blockId: BlockId) => { | |
const currentIndex = editorCRDT.LinkedList.spread().findIndex((block) => | |
block.id.equals(blockId), | |
); | |
sendBlockDeleteOperation(editorCRDT.localDelete(currentIndex, undefined, pageId)); | |
// 삭제할 블록이 현재 활성화된 블록인 경우 | |
if (editorCRDT.currentBlock?.id.equals(blockId)) { | |
// 다음 블록이나 이전 블록으로 currentBlock 설정 | |
const nextBlock = findBlock(editorCRDT.LinkedList, currentIndex); // ✅ 이미 삭제한 후라, next는 currentIndex | |
const prevBlock = findBlock(editorCRDT.LinkedList, currentIndex - 1); // ✅ 이미 삭제한 후라, prev는 currentIndex - 1 | |
editorCRDT.currentBlock = nextBlock || prevBlock || null; | |
} | |
setEditorState({ | |
clock: editorCRDT.clock, | |
linkedList: editorCRDT.LinkedList, | |
}); | |
};``` |
linkedList: editorCRDT.current.LinkedList, | ||
position: editorCRDT.current.currentBlock?.crdt.currentCaret, | ||
}); | ||
}, [editorCRDT.current.currentBlock?.crdt.read().length]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2. 옵션창 -> 삭제버튼 누를시, 캐럿이 제대로 이동하지 않는 문제
- 다음과 같이 변경해줘야합니다. 해당 useLayoutEffect가 도는 조건은, length가 바뀔때라서, 만약 1번째 블록이 aa, 2번째 블록이 bb면 length가 같다고해서 삭제버튼을 누르더라도 캐럿이 이동하지 않더라구요!
- 그렇다고 crdt의 value값을 의존성으로 넣는다고 해도, 1번째 블록이 aa, 2번째 블록이 aa면 동작하지 않더라구요..
- 그래서 id 자체를 의존성으로 넣어줬더니 잘 동작했습니다.
}, [editorCRDT.current.currentBlock?.crdt.read().length]); | |
}, [editorCRDT.current.currentBlock?.id.serialize()]); |
2024-11-23.5.50.39.mov
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 branch 만들때 블록 옵션 기능이 없었어서 이부분은 확인하지 못했던 것 같습니다. 현재 작업중인 텍스트 옵션 pr 올릴때 피드백 주신 부분 반영해서 올리겠습니다!
editorCRDT.current.currentBlock!.crdt.currentCaret = caretPosition; | ||
requestAnimationFrame(() => { | ||
setCaretPosition({ | ||
blockId: block.id, | ||
linkedList: editorCRDT.current.LinkedList, | ||
position: caretPosition, | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
혹시 해당 로직들이 필요한 이유가 있을까요? 이게 없으면 어떤 부분이 동작하지 않는걸까요??
이 부분을 다 지워봤을때, 특별히 동작이 안되던 부분이 없어서 질문드립니당!
requestAnimationFrame(() => {
setCaretPosition({
blockId: block.id,
linkedList: editorCRDT.current.LinkedList,
position: caretPosition,
});
});
|
||
export const addNewBlockButton = css({ | ||
display: "flex", | ||
gap: "spacing.sm", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
후후 요거 그냥 "sm"해도 동작될겁니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 수정하겠습니다!
requestAnimationFrame 없어도 동작하는군요! 이곳저곳 수정하면서 디버깅 하고 되나 안되나 확인하는 식으로 구현해서 중복되는 코드들이 많네요... 이부분도 반영해서 수정하겠습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수고하셨습니다 !
linkedList: editorCRDT.current.LinkedList, | ||
position: caretPosition, | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수고하셨습니다!!!
requestAnimationFram이 뭔가 보니, 이전의 프레임 렌더가 다 끝나고 실행하는 함수 같더라구요.
그렇다면 캐럿 연산이 다 끝나고 저 setCaretPosition이 실행된다고 볼 수 있겠네요!
이 중복되는 코드는
const updateEditorState = () => {
editorCRDT.current.currentBlock!.crdt.currentCaret = caretPosition;
requestAnimationFrame(() => {
setCaretPosition({
blockId: block.id,
linkedList: editorCRDT.current.LinkedList,
position: caretPosition,
});
});
로 줄여서
updateEditorState()
로 사용해도 되지 않을까.. 싶습니다 !
if (!selection) return false; | ||
|
||
const blockElements = Array.from( | ||
document.querySelectorAll('.d_flex.pos_relative.w_full[data-group="true"]'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이부분이 브라우저의 에디터 요소를 찾는 구문이군요..
기존에 key입력마다 처리하는 방법에서 브라우저를 활용한다면 더욱 편하게 관리할 수 있을 듯 합니다.
다만 몇개 버그를 찾은 것 같습니다!
12321.mp4
위와같은 현상은 아직 page별로 캐럿이 제대로 관리되지 않아서 생기는 현상일까요?
아마 이전에 focus된 캐럿으로 다른 page를 눌러도 새로운 page로 캐럿위치가 업데이트 되지 않는것 같군요..
currentBlock.crdt.currentCaret -= 1; | ||
} else { | ||
currentBlock.crdt.currentCaret += 1; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이전에 오른쪽에 요소가 없을때 오른쪽 화살표키를 누르면 에러가 났는데 이젠 해결이 됐군요..! 😊
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨씁니다!!!
📝 변경 사항
🔍 변경 사항 설명
멘토님 피드백 반영
멘토님 피드백 내용 중 현재 캐럿관리를 너무 많이 하고있다는 내용이 있었습니다. 불필요하게 모든 캐럿관리를 직접 하다보니 예상치 못한 에러가 발생하고, js로 캐럿을 관리하다보니 성능상 문제가 발생하고 있습니다. 이를 해결하기 위해 다음과 같이 구조를 변경했습니다.
이를 통해 캐럿 관련된 기능은 최대한 브라우저가 지원하는 기능을 사용할 수 있도록 수정했습니다.
기존 PR 내용 병합
작업중에 서윤님이 작성해주신 애니메이션, 블록 옵션 기능 PR이 머지되어서 해당 내용 merge한 후 변경사항 반영했습니다.
추가 구현사항
기존에
임시
로 되어있던 블록 추가 버튼에 스타일을 적용하고, edtiorCRDT에 Block 인스턴스가 없는 경우에만 렌더링되도록 변경했습니다.🙏 질문 사항
📷 스크린샷 (선택)
2024-11-23.4.59.04.mov
✅ 작성자 체크리스트