-
Notifications
You must be signed in to change notification settings - Fork 9
Bootion Key Interaction
Bootion์ Key ์ ๋ ฅ Interaction ์ ๋ํด ์ค๋ช ํฉ๋๋ค.
Browser๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์
๋ ฅ๊ณผ ๊ด๋ จ๋ ํ๋ฅญํ Interaction์ ์ง์ ํฉ๋๋ค.
ํ์ง๋ง ์ ํฌ Bootion์ Notion์ Clone ๋ฐ Upgrade ํ ์น ์๋น์ค๋ก ์ต๋ํ Notion๊ณผ ๋น์ทํ UX๋ฅผ ์ ๊ณตํด์ผํ๊ธฐ ๋๋ฌธ์ Notion์ ๋
์์ ์ธ Key Interaction ๋ํ ์ง์ํด์ผ ํฉ๋๋ค.
์ด๋ฅผ Customํ ์ด์ ๋ ๊ธฐ๋ฐ์ด ๋๋ ๊ตฌ์กฐ์ ๋ฐ์ ํ ๊ด๊ณ๊ฐ ์์ผ๋ฏ๋ก ์์ Block
์ ๋ํด ์ ํ์๊ฐ ์์ต๋๋ค.
Block
์ Notion์ ์ต์๋จ์๋ก ์ด Block์ด ๋ชจ์ฌ์ ํ๋์ Page
๊ฐ ๋ง๋ค์ด ์ง๋๋ค.
Block์ ๋ค์ํ ํ์
์ด ์์ผ๋ฉฐ Block๋ค ๊ฐ์๋ ์์น๋ ์ํ์ ๋ฐ๋ฅธ ์ํธ์์ฉ์ด ๋ฐ์ํ๊ณ ์์ ๋ก์ด ๋ฐฐ์น๋ฅผ ์ง์ ํฉ๋๋ค.
๊ทธ๋ฌ๋ฏ๋ก ๋ธ๋ก์ ์ํ์ ๋ฐ๋ผ key ์
๋ ฅ์ ๋ฐ๋ฅธ ๋ฐ์์ด ๋ฌ๋ผ์ง๋๋ค.
์์ ๊ฐ์ ์ด์ ๋ก browser์์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ ์ํธ์์ฉ์ผ๋ก๋ Notion์ UX๋ฅผ ๊ตฌํํ๊ธฐ์๋ ๋ถ์กฑํ๋ค๊ณ ํ๋จํ์ต๋๋ค. ๊ทธ๋์ key ์ ๋ ฅ์ ๋ฐ๋ฅธ Interaction์ Custom ํ๊ธฐ๋ก ํ์ต๋๋ค.
Bootion์ Recoil์ ํตํด ์ํ๊ด๋ฆฌ๊ฐ ์ด๋ฃจ์ด์ง๋ฉฐ ๋ค์ ๋ ์ํ๋ฅผ ํตํด Block ์ ๋ณด๊ฐ ๊ด๋ฆฌ ๋ฉ๋๋ค.
- page์ ๋ํ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋
pageState
const pageState = atom<Page>({
key: StateType.PAGE_STATE,
default: (async () => (await fetchData()).page)(),
});
interface Page {
id: IdType;
title: string;
rootId: IdType;
}
- block์ ๋ํ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋
blockMapState
- key ์
๋ ฅ์ ๋ฐ๋ผ
๋ณต์์ ๋ธ๋ก
์ ๋ํ ์ํ๋ฅผ ๋ณ๊ฒฝํด์ผํ ๋๊ฐ ์์ต๋๋ค. ๋๋ฌธ์ ๋ชจ๋ block์ ๋ํ ์ ๊ทผ ๋ฐ ์์ ์ด ์ฉ์ดํ ์ํ๋ฅผ ๊ตฌํํ ํ์๊ฐ ์์์ต๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก๋ชจ๋ Block์ id๋ฅผ key๊ฐ, block ๊ฐ์ฒด๋ฅผ value๋ก ํ๋ ๊ฐ์ฒด
๋ฅผ ์ํ๊ฐ์ผ๋ก ๊ฐ์ง๊ฒํด์ id๋ฅผ ํตํด ๋ชจ๋ Block์ ๋ํ ์ ๊ทผ ๋ฐ ์์ ์ด ๊ฐ๋ฅํ๊ฒ ํ์ต๋๋ค.
const blockMapState = atom<BlockMap>({
key: StateType.BLOCK_MAP_STATE,
default: (async () => (await fetchData()).blockMap)(),
});
type BlockMap = { [key: string]: Block };
recoil
์๋ atomFamily
๋ผ๋ ์ํ๊ฐ ์์ต๋๋ค.
ํด๋น ์ํ๋ atomํ๊ณ ๋น์ทํ์ง๋ง ์ฐจ์ด์ ์ผ๋ก ๊ฐ ์ธ์คํด์ค๋ง๋ค ๊ณ ์ ํ key๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ผ๋ฉฐ ์ด๋ฅผ ํตํด ๋ค๋ฅธ ์ธ์คํด์ค์ ๊ตฌ๋ถํด์ ์ํ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅ ํฉ๋๋ค.
๊ทธ๋ฌ๋ฏ๋ก blockMapState๋ฅผ atomFamily๋ก ๊ตฌ์ฑํ ์ block์ id๋ฅผ key๋ก ํ๋ค๋ฉด Map ์ฒ๋ผ ์ ๊ทผ์ด ๊ฐ๋ฅํจ๊ณผ ๋์์ ์ธ์คํด์ค๋ก ๊ฐ๋ณ์ํ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ฏ๋ก ๊ธฐ์กด๊ตฌ์กฐ๋ณด๋ค ์ฉ์ดํด๋ณด์
๋๋ค. ํ์ง๋ง...
React ๊ณต์๋ฌธ์์ ์ํ๋ฉด react Hook์ ๋ค์๊ณผ ๊ฐ์ ๊ท์น์ ๋ฐ๋ฆ ๋๋ค.
- ์ต์์(at the Top Level)์์๋ง Hook์ ํธ์ถํด์ผ ํฉ๋๋ค.
- ์ค์ง React ํจ์ ๋ด์์ Hook์ ํธ์ถํด์ผ ํฉ๋๋ค
์์ ๊ท์น์ ์ํ๋ฉด hook์ inner function ์์๋ ์ํ๋ฅผ ๊ตฌ๋ ํ๋๊ฒ ๋ถ๊ฐ๋ฅ ํฉ๋๋ค. ์ฆ, atomFamily๋ก blockMapState๋ฅผ ์์ฑํ ๊ฒฝ์ฐ ํ์ํ Block ๊ฐ์ฒด๋ฅผ ์ฆ์ ๊ตฌ๋ ํด์ ์ป๋ ๊ฒ์ด ๋ถ๊ฐ๋ฅ ํฉ๋๋ค. ๋จ, inner function์ด ์๋ Custom Hook ๋ด์์ Hook์ ํธ์ถํ๋ ๊ฒ์ ๊ฐ๋ฅ ํฉ๋๋ค. ๋๋ฌธ์ ํ์ํ ๋ชจ๋ Block ์ ๋ณด๋ฅผ ๊ฐ๊ฐ ๋ฏธ๋ฆฌ ๊ตฌ๋ ํด๋์ผ๋ฉด ๋์ง ์์๊น ํ๋ ์๊ฐ์ด ๋ค ์ ์์ง๋ง Notion์ ๋ธ๋ก๊ฐ ์ํธ์์ฉ ๋ฒ์ฃผ๊ฐ ๋์ด์ ๊ฒฐ๊ตญ ๋ชจ๋ ๋ธ๋ก ์ ๋ณด๊ฐ ํ์ํ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก ๋ชจ๋ Block ๊ฐ์ฒด ์ ๊ทผ์ด ์ฉ์ดํ ์ง๊ธ์ BlockMap ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๊ฒ ๋์์ต๋๋ค.
์์์ ์ค๋ช ํ blockMapState๋ฅผ ํตํด block์ id๋ฅผ key๋ก Block ๊ฐ์ฒด์ ์ ๊ทผ์ด ๊ฐ๋ฅ ํฉ๋๋ค. ๋ค์์ Key Interaction์ ๋ฐ๋ผ Block์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ์ํ Custom Hook ์ ๋๋ค.
- Bootion์ key Interaction์ ๊ด๋ฆฌํ๋
useCommand
Custom Hook - Block์ ๊ตฌ์กฐ๋ ์ํ ๋ณ๊ฒฝ์ ๊ด๋ฆฌํ๋
useManager
Custom Hook - Block์ ๊ณ์ธต ์ ๋ณด์ ์ ๊ทผ์ ๊ด๋ฆฌํ๋
useFamily
Custom Hook - Block์ ๊ตฌ์กฐ๋ ์ํ ๋ณ๊ฒฝ ์ด๋ ฅ์ ๊ด๋ฆฌํ๋
useHistory
Custom Hook
useCommand
๋ ์ฌ์ฉ์์ key ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ Bootion์์ ์ ๊ณตํ๋ Key Interaction์ ์ ์ฉํ๋ ํจ์๋ฅผ ๋ฐํํ๋ Custom Hook ์
๋๋ค.
useCommand
๋ ๋ธ๋ก ๊ตฌ์กฐ ๋ณ๊ฒฝ์ ์ํด ๊ธฐ์ค์ด๋๋ block์ id๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๋ useManager
Custom Hook์ ์ฌ์ฉํฉ๋๋ค.
- ๊ธฐ์ค์ด๋๋ ๋ธ๋ก์ ํค ์ ๋ ฅ์ด ๋ฐ์ํ focus ๋ Block ์ ๋๋ค.
key ์ ๋ ฅ์ ๋ฐ๋ฅธ ๋์ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- key ์ ๋ ฅ์ด ๋ฐ์ํ๋ฉด Bootion์์ ๋์ํด์ผํ๋ key์ธ์ง ๊ฒ์ฆ ํฉ๋๋ค.
- ๋ง์ฝ ๋ง๋ค๋ฉด ๊ธฐ๋ณธ ์ด๋ฒคํธ๋ฅผ ์ทจ์ํ๊ณ key๊ฐ์ useCommand์์ ๋ฐํํ dispatcher ํจ์์ ๋ฃ์ด ์คํ ํฉ๋๋ค.
- Block ๊ตฌ์กฐ์ ๋ณ๊ฒฝ์ฌํญ์ด ๋ฐ์ํ๋ ์ ๋ ฅ์ผ ๊ฒฝ์ฐ useManager์์ ๋ฐํํ startTransaction ํจ์๋ฅผ ์คํํด Transaction์ ์ด๊ธฐํ ํฉ๋๋ค.
- key ์ ๋ ฅ์ ๋์ํ๋ ๋ณ๊ฒฝ์ฌํญ์ ์ ์ฉํ๊ธฐ ์ํด useManager์์ ๋ฐํํ BlockMap ์กฐ์ ํจ์๋ฅผ ์ฑํํด Transaction์ ๋ฐ์ ํฉ๋๋ค.
- ๋ณ๊ฒฝ์ฌํญ์ Block์ ๋ฐ์ํ๊ธฐ์ํด useManager์์ ๋ฐํํ commitTransaction ํจ์๋ฅผ ์คํ ํฉ๋๋ค.
- commit๊ณผ ๋์์ useHistroy์ Transaction ์ ๋ณด๊ฐ ์ ์ฅ ๋ฉ๋๋ค.
- Transaction์ ์ ์ฉ๋ ๋ณ๊ฒฝ์ฌํญ์ด Block์ ๋ฐ์ ๋ฉ๋๋ค.
Key Interaction ์๊ณ ๋ฆฌ์ฆ ์์๋
set ํจ์๋ก ์ํ๋ฅผ ๋ณ๊ฒฝํ ๊ฒฝ์ฐ ๋ณ๊ฒฝ์ฌํญ์ด ํธ์ถ๊ณผ ๋์์ ๋ฐ์๋์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก set ํจ์ ํธ์ถํ ์ํ๋ฅผ ์ฝ์ผ๋ฉด ๋ณ๊ฒฝ ์ ์ํ๋ฅผ ์ฝ๊ฒ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ ํฉ๋๋ค. Transaction์ ์์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ณต์ฌํ blockMap์ ๋ณ๊ฒฝ์ฌํญ์ ๋ฐ์ํ๊ณ commit ์ ์ผ๊ด ๋ฐ์ํ๋ ๋ก์ง์ผ๋ก ๊ตฌํ๋์ด ์์ต๋๋ค. ๋๋ฌธ์ ๋ธ๋ก์ ํ๋๋ง ์์ ํ๋ฉด ๋ ๊ฒฝ์ฐ์๋ Transaction์ ๊ฒฝ์ ํ์ง ์์๋ ๋ฉ๋๋ค. ํ์ง๋ง ๋๋ถ๋ถ์ ์์ ์ฌํญ์ ๋ณต์์ ๋ธ๋ก์ ๋ํ ์ํ๋ณ๊ฒฝ์ผ๋ก ์ด๋ฃจ์ด์ง๋ฏ๋ก Transaction์ ํตํด ๋ณ๊ฒฝ์ฌํญ์ ๋ฐ์ํด์ผ ํฉ๋๋ค.
useManager
๋ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ block์ id๋ฅผ ๊ธฐ์ค์ผ๋ก block์ ์ํ์ ๊ตฌ์กฐ๋ณ๊ฒฝ ํจ์๋ฅผ ๋ฐํํ๋ Custom Hook ์
๋๋ค.
useManager
๋ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ block์ id์ ๊ด๋ จ๋ block ์ ๋ณด๋ฅผ ์ป๊ธฐ ์ํด useFamily
Custom Hook์ ์ฌ์ฉ ํฉ๋๋ค.
๋ํ redo, undo ์ ๋์ํ๊ธฐ์ํด useHistory
Custom Hook์ ์ฌ์ฉํฉ๋๋ค.
์์์ ์ค๋ช ํ ๋ฐ์ ๊ฐ์ด ์ง์ญ๋ณ์๋ก transaction ์ด๋ผ๋ Mutableํ ๋ณ์๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ํด๋น ๋ณ์๋ blockMap์ ๊ฐ์ผ๋ก ๊ฐ์ง๋ฉฐ block์ ์ํ๋ฅผ ํด์ผํ๋ ์ฌํญ์ transaction ๋ณ์์ ๋ฐ์ ๋ฉ๋๋ค. ๊ด๋ จ ํจ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- startTransaction์ ํตํด transaction ๋ณ์๋ฅผ blockMap์ผ๋ก ์ด๊ธฐํ ํ ์ ์์ต๋๋ค.
- commitTransaction์ ํตํด transaction ์ ์ ์ฉ๋ ๋ณ๊ฒฝ์ฌํญ์ blockMapState์ ๋ฐ์ํ ์ ์์ต๋๋ค. ๋ํ ํ์ฌ transaction ์ ๋ณด๊ฐ useHistory์ ์ด๋ ฅ์ ๋ณด์ ์ถ๊ฐ ๋ฉ๋๋ค.
useFamily
๋ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ block์ id๋ฅผ ๊ธฐ์ค์ผ๋ก ์์ , ๋ถ๋ชจ, ์กฐ๋ถ๋ชจ, ์์, ํ์ ๋ค ๋ฑ์ ๋ํ ์ํ์ ํน์ ์กฐ๊ฑด์ ๋ถํฉํ๋ Block ๊ฐ์ฒด๋ฅผ ํ์ํ๋ ํจ์๋ฅผ ๋ฐํํ๋ Hook ์
๋๋ค.
- Notion์ Block์ ์ํ์ ์ ๋ ฅ์ ๋ฐ๋ผ ์ฃผ๋ณ Block์ ์ํฅ์ ๋ผ์นฉ๋๋ค. useFamily๋ ํด๋น Block ๋ค์ ํ์ํ๊ธฐ ์ํ ํจ์๋ค์ ์ง์ ํฉ๋๋ค.
key ์
๋ ฅ๊ณผ hook๋ค์ ํตํด Block์ ๊ตฌ์กฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด focus๋ ๋์์ ๋ณ๊ฒฝ
ํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๊น๋๋ค.
์ด๋ฅผ ์ํด์๋ focus๋ block์ ์ ๋ณด๋ฅผ state๋ก ๊ด๋ฆฌํ ํ์๊ฐ ์๋๋ฐ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
- React๋ ์์ฒด์ ์ผ๋ก focus๋ฅผ ์ฃผ๊ธฐ์ํ props๋ ํจ์๋ฅผ ์ง์ํ์ง ์์ต๋๋ค.
- ์์ ๊ฐ์ ์ด์ ๋ก DOM์ focus ํจ์๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด useRef๋ก DOM์ ์ป์ ํ์๊ฐ ์๊น๋๋ค.
- ๊ทธ๋ฆฌ๊ณ ์ด๋ ๊ฒ ์ป์ ref๋ ์ ์ญ์ผ๋ก ์ ๊ทผ์ด ๊ฐ๋ฅํด์ผ ํฉ๋๋ค.
์ฌ๊ธฐ๊น์ง ๋๋ฌํ๋ฉด Block์ ref๋ฅผ ์ํ๋ก ๊ด๋ฆฌํด์ผํ ํ์์ฑ์ ๋๋๋๋ค. ํ์ง๋ง...
React State๋ก ๊ด๋ฆฌ๋๊ธฐ ์์ํ๋ ๊ฐ๋ค์ immutable
ํด์ง๋๋ค.
๊ทธ๋ฌ๋ฏ๋ก DOM์ state๋ก ๊ด๋ฆฌํ ์ ํด๋น DOM ๋ค์ ์์ ์ด ๋ถ๊ฐ๋ฅํ๊ฒ ๋ฉ๋๋ค.
์ด ์ํ์์ ํด๋น DOM ๋ค์ด ํฌํจ๋ Component๊ฐ ์ญ์ ๋ ์ ReactDom์์ ์๋์ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ ํฉ๋๋ค.
์์ธ์ ReactDom
์์ ํด๋น Component๋ฅผ ์ญ์ ํ๊ธฐ์ํด ref์ current ๊ฐ์ null๋ก ๋ฐ๊พธ๋ ค ๋ก์ง
์ ์์ต๋๋ค.
์์ ํ ์ ์๊ฒ๋ DOM ๊ฐ์ฒด๋ฅผ ์์ ํ๋ ค ํ ๊ฒ์ด์ง์.
ํด๊ฒฐ๋ฐฉ๋ฒ์ ๊ฐ๋จ ํฉ๋๋ค. block์ ๋ํ DOM ๊ฐ์ฒด๋ฅผ ์ ์ญ์ผ๋ก ์ ๊ทผํ ํ์์ฑ์ ์ฌ์ ํ ์์ง๋ง ์ด๋ฅผ state๋ก ๊ด๋ฆฌํ ์ ์์๋ฟ ์ ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก Object์ ๋ด์์ ์ ์ญ์ผ๋ก ์ ๊ทผํ๊ฒํ๋ฉด ๋ฉ๋๋ค. ์ฝ๋๋ ์๋์ ๊ฐ์ต๋๋ค.
const blockRefState: { [id: string]: MutableRefObject<any> } = {};
blockRefState๋ ๋ชจ๋ Block์ ๋ํ DOM ๊ฐ์ฒด์ ๊ทผ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ์ฑ ์๋ง ์์๋ฟ ๊ตฌ๋ ์ ํตํด Component์ ํ์๋ด์ฉ์ ๋งค๋ฒ ๊ฐฑ์ ํด์ผํ๋ ์์กด์ฑ์ด ์์ผ๋ฏ๋ก ์์ฒ๋ผ ์ฌ์ฉํด๋ ๋๋ค๋ ๊ฒฐ๋ก ์ ์ด๋ฅด๋ ์ต๋๋ค.
Enter
ํค ์
๋ ฅ ์ ํ์ฌ Focus๋ Block์ ์ฒซ๋ฒ์งธ ์์ ํน์ ๋ค์ํ์ ์ ์ ๊ท๋ธ๋ก์ด ์ฝ์
๋ฉ๋๋ค.
์ฝ์
ํ์๋ ์ ๊ท๋ธ๋ก์ Focus๋ฅผ ํ ๋นํด์ผ ํ๋๋ฐ ํด๋น ๋ก์ง์ ์ํ์ค์ธ useCommand Hook ๋ด์์๋ ์์ง ReactDom์ ์ํด ์ ๊ท๋ธ๋ก์ด ์์ฑ๋๊ธฐ ์
์ด๋ฏ๋ก blockRefState์๋ ํด๋น Block์ DOM ๊ฐ์ฒด๊ฐ ๋ด๊ฒจ์์ง ์์ต๋๋ค.
๊ทธ๋ฌ๋ฏ๋ก ์ ๊ท๋ธ๋ก์ด ๋๋๋ง๋จ๊ณผ ๋์์ ์์ ์ด focus๋ ๋ธ๋ก์์ ์ ์ ์๋ ์ํ๊ฐ ํ์ํฉ๋๋ค.
์์ ๊ฐ์ ํ์๊ฐ ์์ด focusState๋ฅผ ํตํด ํ์ฌ focus๋ Block์ id๋ฅผ ๊ด๋ฆฌํ๊ฒ ํ์ต๋๋ค. ๋ชจ๋ Block์ focusState๋ฅผ ๊ตฌ๋ ํ๊ณ focusId๊ฐ ์์ ์ id์ธ์ง ๊ฒ์ฆํ๋ฉฐ ์์ ์ id ์ผ ๊ฒฝ์ฐ ์์ ํํ focus๋ฅผ ์ค๋๋ค. ๋๋ฌธ์ focusState์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ค๋ ๊ฒ์ ๋ณ๊ฒฝํ id๋ฅผ ๊ฐ์ง Block์ focus๋ฅผ ์ฃผ๋ ๊ฒ์ด ๋ฉ๋๋ค. ํด๋น ๋ฐฉ์์ ํตํด Hook๋ด์์ focusState์ ์ํ๊ฐ์ ์ ๊ท๋ธ๋ก์ id๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ผ๋ก ๋๋๋ง ์ focus๊ฐ ํ ๋น๋๊ฒ ํ์ต๋๋ค.
Interaction์ ์ํด focus๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ caret์ ์์น๋ ์กฐ์ ๋์ด์ผํ ํ์๊ฐ ์๊น๋๋ค. ๋ณดํต ๋ค์์ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
- focus ๋ ๋ธ๋ก์
0๋ฒ์งธ offset
์ caret์ด ๋ฐฐ์น๋์ด์ผ ํ๋ ๊ฒฝ์ฐ - focus๋ ๋ธ๋ก์
๋ง์ง๋ง offset
์ caret์ด ๋ฐฐ์น๋์ด์ผ ํ๋ ๊ฒฝ์ฐ -
์ด์ ์ focus๋ ๋ธ๋ก์ offset
์ด ํ์ฌ focus๋ ๋ธ๋ก์ ๋ฐ์๋์ด์ผ ํ๋ ๊ฒฝ์ฐ
์์ ๊ฐ์ ํ์์ฑ์ ์ํด Caret Offset์ ์กฐ์ ํ๊ธฐ ์ํด์ Selection API๋ฅผ ์ฌ์ฉ ํ์ต๋๋ค.
-
Selection API
๋ ํ์ฌ Caret ์ ์ํฅ์ ๋ฐ๊ณ ์๋Node
์ offset ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. - window ํน์ document ๊ฐ์ฒด์์ getSelection() ํธ์ถ์ ํตํด ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
- Selection ๊ฐ์ฒด์ collapse ํจ์๋ฅผ ํตํด caret offset ์ ์์ ํ ์ ์์ต๋๋ค.
Selection API๋ฅผ ์ด์ฉํด Caret ์ ๋ณด๋ฅผ ์ฝ๊ฑฐ๋ ์ค์ ํ๋๊ฒ ๊ฐ๋ฅํด์ก์ง๋ง ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์
๊ฐ ๋ฐ์ ํ์ต๋๋ค.
Block Component๊ฐ rerendering
๋๊ฑฐ๋ focus๊ฐ ๋ณ๊ฒฝ
๋ ๊ฒฝ์ฐ ๊ธฐ๋ณธ Interaction์ ์ํด caret offset์ด 0
์ผ๋ก ์ค์ ๋ฉ๋๋ค.
์ด ์ํ์์ Bootion์ Key Interaction์ด ๋ฐ์๋๋ฏ๋ก ๊ธฐ๋ฅ์์ผ๋ก๋ ๋ฌธ์ ๊ฐ ์์ง๋ง UX
์ธก๋ฉด์์๋ ์ด์ focus Block์ ๋งจ ์์ผ๋ก caret์ด ๋น๊ฒจ์ก๋ค๊ฐ ์๋ ๋ฐฐ์น๋์ด์ผํ ์์น๋ก ์ฌ๋ฐฐ์น ๋๋ ํ์์ ๊ฒช๊ฒ ๋ฉ๋๋ค.
ํด๋น ํ์์ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ๋ฐ์ ํฉ๋๋ค.
- Block Component๊ฐ ์๋ก
์์ฑ
๋ ๊ฒฝ์ฐ - Block Component ๋ด ๋ก์ง์ ์ํด
focus๊ฐ ์์ ์๊ฒ ํ ๋น
๋ ๊ฒฝ์ฐ
์ฆ ๋๋๋ง ํ focus๊ฐ ์ฌํ ๋น๋์ด์ caret offset์ด 0์ผ๋ก ์ค์ ๋์๋๋ฐ caret ์์น ๋ณ๊ฒฝ๋ก์ง์ด ์ ์ฉ๋์ด์ caret ์์น๊ฐ ์๋ค๊ฐ๋ค ํ๋ ํ์์ด ๋ฐ์ํ๋ ๊ฒ๋๋ค.
๊ทธ๋ฌ๋ฏ๋ก ์๋ ์ฝ๋์ฒ๋ผ ์์ ๊ฒฝ์ฐ์ ๊ธฐ์กด focus๋ Block์ caret์ blur(focus๋ฅผ ์๊ฒ)
ํ๊ณ ๋๋๋ง ์ดํ์ focus๋ block์ caret์ด ๋ฐฐ์น ๋ ์ ์๋๋ก ์ค์ ํ๋ฉด ๋ฉ๋๋ค.
const setFocus = (targetBlock: Block) => {
if (!targetBlock) {
return null;
}
const beforeOffset = window.getSelection().focusOffset;
setFocusId(targetBlock.id);
const targetRef = blockRefState[targetBlock.id];
targetRef
? targetRef.current.focus()
: blockRefState[block.id].current.blur();
return beforeOffset;
};
์ด๋ ๊ฒ focus์ caret ์ ๋ํ UX๋ฅผ ๊ตฌํํ ์ ์์์ต๋๋ค.
ํ์ง๋ง ์ด ์ฒ๋ผ ๊ตฌํ์ ํ์ด ์กํ๋ฉด์ UX์ ๋ฐ์ ํ ํฐ ๋ฌธ์
๊ฐ ๋ฐ์ ํ์ต๋๋ค.
Key ์
๋ ฅ์ด ์ฐ์์ผ๋ก ๋น ๋ฅด๊ฒ ๋ฐ์ํ ๊ฒฝ์ฐ ๋๋๋ง ์๋๊ฐ key Interaction ์ ์ฉ ์๋๋ฅผ ๋ชป๋ฐ๋ผ์ก์ ํ๋ฉด์ด ๋ฉ์ถ๋ ํ์์ด ๋ฐ์ํ ๊ฒ ์
๋๋ค.
์ฌ์ง์ด Enter Key Interaction
์ ๊ฒฝ์ฐ ์๋ก์ด ๋ธ๋ก์์ฑ ์๋๊ฐ focus ์ํ ๋ณ๊ฒฝ์๋๋ฅผ ๋ชป๋ฐ๋ผ์ก๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํด์ useCommand
(useCommand๋ focus ๋ ๋ธ๋ก์ ๊ธฐ์ค์ผ๋ก ๋์ํ๊ธฐ ๋๋ฌธ ์
๋๋ค.)์์ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ๋ ์์ต๋๋ค.
๋๋ฌธ์ Key Interaction์ด ์ ์ฉ๋ ํ์ ์๋ก์ด Key ์
๋ ฅ์ ๋ฐ๊ฒํ ํ์๊ฐ ์๊ฒผ์ต๋๋ค.
ํด๋น ๋ฌธ์ ๋ UX์ ๊ด๋ จํด ์์ฃผ ์ธ๊ธ๋๋ ์ฌํญ์ด๋ฉฐ throttling
์ด ํด๊ฒฐ์ฑ
์ผ๋ก ๊ผฝํ๋๋ค.
๊ทธ๋์ Lodash ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ throttle ํจ์๋ฅผ ์ด์ฉํด ์ด๋ฅผ ํด๊ฒฐํ๊ณ ์ ์๋ํ์ต๋๋ค
ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
- Bootion์ Component๋ฅผ ํจ์ํ์ผ๋ก ๊ตฌํํ๋ฏ๋ก ๋๋๋ง๋ ๋ ๋ง๋ค ์ง์ญ๋ณ์๋ค์ ๋ค์ ์์ฑ ํฉ๋๋ค.
- ๊ทธ๋ฌ๋ฏ๋ก key ์ ๋ ฅ์ throttle์ ์ ์ฉํด๋ ๋ฆฌ๋๋๋ง ๋ ๋ throttle ๋ ์ํ์ธ์ง์ ๋ํ ์ ๋ณด๊ฐ ๋จ์ง ์์ผ๋ฏ๋ก throttle์ด ์ ์ฉ๋์ง ์์ต๋๋ค.
- throttle์ ์ฌ์ฉํ๋ ์ด๋ฒคํธ ํจ์๋ฅผ useRef๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ์์ด ์์ง๋ง ๋ด๋ถ์์ useCommand๊ฐ ๋ฐํํ dispatcher๋ฅผ ์ฌ์ฉํ๋ฏ๋ก useCommand์ ๊ด๋ จ๋ ์ํ์ ๋ณ๊ฒฝ์ฌํญ์ด ๋ฐ์ํจ์ ๋ฐ๋ผ dispatcher๊ฐ ์ ํจํ์ง ์์ ๊ฒฝ์ฐ๊ฐ ์๊ฒจ์ ์๋ฌ๊ฐ ๋ฐ์ ํฉ๋๋ค.
๊ฒฐ๊ตญ throttle ์ํ์ ๋ณด๊ฐ ์ ์ฅ๋์ง ์์ ํด๋น ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค๊ณ ๊ฒฐ๋ก ์ ๋ด๋ ธ์ต๋๋ค.
์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ์๋์ฒ๋ผ ํ์ฌ throttle ์ํ์ ๋ํ ์ํ๊ด๋ฆฌ๊ฐ ํ์ํ๋ค๊ณ ํ๋จ์ด ๋์์ต๋๋ค.
const throttleState = {
isThrottle: false,
};
์์ ์ํ๋ฅผ ํตํด ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ก Custom throtting์ ์ ์ฉํ ์ ์์ต๋๋ค.
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
const { focusNode, focusOffset } = window.getSelection();
if (throttleState.isThrottle) {
event.preventDefault();
} else if (/* Bootion์ด ๋ค๋ค์ผํ key ์
๋ ฅ์ธ๊ฐ? */) {
throttleState.isThrottle = true;
event.preventDefault();
setImmediate(() => {
Dispatcher(event.key);
throttleState.isThrottle = false;
});
}
};
ํด๋น ๋ก์ง์ ๋ค์๊ณผ ๊ฐ์ ์ ์ฐจ๋ก ์งํ ๋ฉ๋๋ค.
- throttleState์ isThrottle์ด false ์ผ ๊ฒฝ์ฐ์๋ง Key Interaction์ด ๋ฐ์ ํฉ๋๋ค.
- key Interaction์ด ๋ฐ์ํด์ผํ ๊ฒฝ์ฐ isThrottle ๊ฐ์ด true๊ฐ ๋์ด ์ดํ ๋ฐ์ํ๋ key ์ ๋ ฅ์ ๋ฒ๋ฆฝ๋๋ค.
- setImmediate ํจ์๋ฅผ ํตํด ์ฝ๋ฐฑํจ์์์ dispatcher๋ฅผ ์คํ ํฉ๋๋ค. ์คํ์ด ์๋ฃ๋๋ฉด isThrottle์ ๊ฐ์ false๋ก ๋ณ๊ฒฝํด์ key ์ ๋ ฅ์ ๋ฐ๋ผ Key Interaction์ด ๋ฐ์ํ๊ฒ ํฉ๋๋ค.
์์ ๋ก์ง์ ํตํด Key Interaction ์ ์ฉ์ด ์๋ฃ๋ ์ดํ ๋ค์ Key Interaction ์ ์ฉ์ ๋ณด์ฅํ ์ ์์ต๋๋ค.