diff --git a/README.md b/README.md index 4efcc582a..2e2252c53 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![](./cover.png) ## Demo -아래 QR 코드를 카메라로 찍어보세요. 당근마켓 앱 내에서 데모를 볼 수 있어요. +아래 QR 코드를 카메라로 찍어보세요. 당근마켓 앱 내에서 데모를 볼 수 있어요. 아래 데모에서는 각 플랫폼 (Android/iOS) 환경에 맞게 UI가 표현됩니다. ![](./demo-qr.png) @@ -15,94 +15,150 @@ $ yarn add @daangn/karrotframe import * as kf from '@daangn/karrotframe' ``` -## 네비게이터 -네비게이터는 화면간 전환 효과와 History를 관리합니다. 네비게이터의 핵심 로직은 `react-router-dom`과 `recoil`에 의존하고 있습니다. +## 1. 네비게이터 +네비게이터는 아래의 기능을 지원합니다. -- 자연스러운 화면전환 - History 지원 -- 네비게이션 바 -- 이전, 닫기 버튼 +- 각 플랫폼에 맞게 디자인된 자연스러운 화면전환 +- 각 플랫폼에 맞게 디자인된 네비게이션 바 +- 상황에 맞는 이전, 닫기 버튼 + +> 네비게이터의 핵심 로직은 `react-router-dom`과 `recoil`에 의존하고 있습니다. + +### 1-a. `Navigator` +`Navigator` 컴포넌트는 화면을 표현하는데 반드시 필요한 요소들이 포함됩니다. 컴포넌트 트리 상단에 포함해주세요 + +```tsx +import { Navigator } from '@daangn/karrotframe' + +const App: React.FC = () => { + return ( + { + console.log('닫기버튼이 눌렸습니다') + }} + > + {/*...*/} + + ) +} +``` + +| Props | 타입 | 역할 | 기본값 | +| ------------- | ------------- | ------------- | ------------- | +| `theme` | `Cupertino`, `Android`, `Web` | UI 테마 | `Web` | +| `animationDuration` | number | 애니메이션 지속시간 | 테마별로 다름 | +| `useCustomRecoilRoot` | boolean | `true`인 경우 `Navigator` 내에 포함된 `` 을 제거합니다 | `false` | +| `useCustomRouter` | boolean | `true`인 경우 `Navigator` 내에 포함된 `` 을 제거합니다 | `false` | + +### 1-b. `Screen` +`Screen` 컴포넌트는 화면을 선언하는데 사용합니다. `Navigator` 안에 선언합니다. -### 시작하기 -네비게이터의 핵심 컴포넌트로는 `Navigator`와 `Screen`이 존재합니다. `Navigator`의 `environment` props로 iOS(`Cupertino`), Android, Web 환경의 UI/애니메이션을 다르게 설정할 수 있습니다. ```tsx import { Navigator, Screen } from '@daangn/karrotframe' const App: React.FC = () => { return ( { - window.alert('닫기') + console.log('닫기버튼이 눌렸습니다') }} > + + {/* 또는 */} - - - - - - - + ) } ``` +| Props | 타입 | 역할 | 기본값 | +| ------------- | ------------- | ------------- | ------------- | +| `path` | string | 해당 화면을 표현할 Path | required | +| `component` | `React.ComponentType` | 렌더링 할 컴포넌트 | | +| `children` | `React.ReactNode` | 렌더링 할 요소 | | +> `component` 또는 `children`은 반드시 사용하세요 (만약 두 props가 동시에 선언되는 경우, `component`가 우선권을 갖습니다) -### `ScreenHelmet` -기본적으로 Screen은 상단 네비게이션 바를 포함하고 있지 않습니다. 기본 제공되는 상단 네비게이션 바를 수정하기 위해서는 `ScreenHelmet` 컴포넌트를 사용하세요. +### 1-c. `ScreenHelmet` +기본적으로 Screen은 상단 네비게이션 바를 포함하고 있지 않습니다. 기본 제공되는 상단 네비게이션 바를 추가, 수정하기 위해서는 `ScreenHelmet` 컴포넌트를 사용하세요. ```tsx import { ScreenHelmet } from '@daangn/karrotframe' -const Home: React.FC = () => { +const MyComponent: React.FC = () => { return (
왼쪽에추가
+ } + appendRight={ +
오른쪽에추가
+ } + customBackButton={ +
이전
+ } + customCloseButton={ +
닫기
+ } /> ) } ``` +| Props | 타입 | 역할 | 기본값 | +| ------------- | ------------- | ------------- | ------------- | +| `title` | `React.ReactNode` | 타이틀 부분에 출력할 요소 | `undefined` | +| `appendLeft` | `React.ReactNode` | 왼쪽에 요소를 추가 (이전 버튼 오른쪽에 표시됩니다) | `undefined` | +| `appendRight` | `React.ReactNode` | 오른쪽에 요소를 추가 (닫기 버튼 왼쪽에 표시됩니다) | `undefined` | +| `customBackButton` | `React.ReactNode` | 이전 버튼을 사용자화합니다 | `undefined` | +| `customCloseButton` | `React.ReactNode` | 닫기 버튼을 사용자화합니다 | `undefined` | -다음과 같이 좌측, 우측에 Element를 추가하고, 가운데 타이틀을 덮어씌울수 있습니다. +### 1-d. `Link` +특정 path로 이동할 수 있는 링크를 생성하는 컴포넌트입니다. ```tsx -import { ScreenHelmet } from '@daangn/karrotframe' +import { Link } from '@daangn/karrotframe' const Home: React.FC = () => { return (
- left
- } - right={ -
right
- } - center={ -
- } - /> + 글 목록 ) } ``` +| Props | 타입 | 역할 | 기본값 | +| ------------- | ------------- | ------------- | ------------- | +| `to` | string | 이동 할 path | required | +| `replace` | boolean | path 이동을 replace로 처리할 지 여부 | `undefined` | +| `className` | string | className | `undefined` | -### URL 파라미터 받기 -`useLocation`, `useParams`, `useRouteMatch`를 활용할 수 있습니다 +### 1-e. `useLocation`, `useParams`, `useRouteMatch` +react-router-dom에 존재하는 `useLocation`, `useParams`, `useRouteMatch`를 그대로 사용할 수 있습니다 ```tsx import { useLocation, useParams, useRouteMatch } from '@daangn/karrotframe' const Post: React.FC = () => { + /** + * 현재 location 정보 + */ const location = useLocation() + /** + * path parameter로 들어온 값 + */ const params = useParams() + /** + * 현재 위치와 특정 path regex를 비교해 파싱된 값을 반환합니다. + * (매치하지 않는다면 null 반환) + */ const match = useRouteMatch({ path: '/:post_id', }) @@ -111,64 +167,77 @@ const Post: React.FC = () => { } ``` -### 화면 전환 -화면 전환은 `Link` 또는 `useNavigator` 를 통해 수행할 수 있습니다. +### 1-f. `useNavigator` +화면 전환을 수행합니다. ```tsx -import { Link } from '@daangn/karrotframe' +import { useNavigator } from '@daangn/karrotframe' -const Home: React.FC = () => { - return ( -
- 글 목록 -
- ) -} -``` +const Posts: React.FC = () => { + const { push, pop, replace } = useNavigator() -또는 + const goPost = (postId: string) => () => { + // 특정 path로 이동합니다 + push(`/posts/${postId}`) + } -```tsx -import { useNavigator } from '@daangn/karrotframe' + const goBack = () => { + // 한단계 뒤로 갑니다 + pop() + + // depth argument를 통해 여러단계를 pop 할 수 있습니다 + pop(1) + } + + useEffect(() => { + if (!user) { + // 특정 path로 이동합니다 (replace) + // 애니메이션 없이 이동하므로, redirect behavior에 적절합니다 + replace('/login') + } + }) -const Home: React.FC = () => { - const { push } = useNavigator() return (
- +
+ ) + })} + {/* ... */} + ) } ``` -### 화면 간 데이터 전송 -`useNavigator`의 `pop()`과 `await push()`를 통해 화면간 데이터 전송을 할 수 있습니다. +추가적으로, `useNavigator`의 `pop().send()`과 `await push()`를 통해 화면간 데이터 전송을 할 수 있습니다. -`pop()` 함수 내 `depth` argument를 2 이상으로 부여할 시 여러 화면을 뛰어넘어서 전송도 가능합니다. +> `pop()` 함수 내 `depth` argument를 2 이상으로 부여할 시 여러 화면을 뛰어넘어서 전송도 가능합니다. ```tsx import { useNavigator } from '@daangn/karrotframe' -const Home: React.FC = () => { +const Posts: React.FC = () => { const { push } = useNavigator() + + const writePost = () => { + // 다음 화면에서 전송할 데이터를 기다립니다 + const data = await push('/posts/write') + console.log(data) + // { + // hello: 'world', + // } + } return (