@hjmds/design-contracts 1.48.0 → 1.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/card.d.ts +5 -0
- package/dist/card.d.ts.map +1 -1
- package/dist/card.js +3 -0
- package/dist/card.js.map +1 -1
- package/dist/catalog.d.ts +34 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +4 -0
- package/dist/catalog.js.map +1 -1
- package/dist/drawing-editor.d.ts +96 -0
- package/dist/drawing-editor.d.ts.map +1 -0
- package/dist/drawing-editor.js +43 -0
- package/dist/drawing-editor.js.map +1 -0
- package/dist/timeline.d.ts +7 -0
- package/dist/timeline.d.ts.map +1 -1
- package/dist/timeline.js +7 -0
- package/dist/timeline.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/drawing-editor.md +13 -0
- package/docs/generated/component-maturity.md +5 -4
- package/docs/generated/renderer-evidence.json +109 -9
- package/docs/generated/renderer-evidence.md +5 -3
- package/docs/generated/showcase-manifest.json +52 -1
- package/docs/optional-adapters.md +1 -1
- package/docs/stable-core.md +12 -0
- package/docs/timeline.md +13 -0
- package/docs/usage/README.md +6 -5
- package/docs/usage/components/card.md +1 -0
- package/docs/usage/components/context-menu.md +2 -2
- package/docs/usage/components/drawing-editor.md +135 -0
- package/docs/usage/components/image-choice-group.md +1 -1
- package/docs/usage/components/keyboard-dock.md +2 -2
- package/docs/usage/components/keyboard-form-scroll-view.md +2 -2
- package/docs/usage/components/keyboard-motion-provider.md +2 -2
- package/docs/usage/components/share-sheet.md +5 -3
- package/docs/usage/components/sheet.md +13 -1
- package/docs/usage/components/timeline.md +27 -3
- package/docs/usage/compositions/disclosure.md +3 -3
- package/package.json +6 -1
package/docs/usage/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[선택 기준](SELECTION.md)으로 그대로 사용·공개 슬롯 확장·공통 API 보완·제품 고유 기능 연결을 고른다. 설치 버전의 지침을 본다: `node_modules/@hjmds/design-contracts/docs/usage/`.
|
|
8
8
|
이름을 모르면 [쉬운 말로 찾고 비교하기](FINDING.md)에서 일상 표현과 선택 기준·요청 예시로 시작한다.
|
|
9
9
|
제공 기준은 확인한 기본 API 버전이며 최초 출시 버전이 아니다. 구성·화면은 각 API 지침의 제공 버전을 확인한다.
|
|
10
|
-
API 안정성은 1.
|
|
10
|
+
API 안정성은 1.50.0의 생성 manifest에서 읽은 정규(canonical) API 기준이다. 동반·선택형 확장은 개별 계약을 확인한다.
|
|
11
11
|
Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품 반영을 의미하지 않는다.
|
|
12
12
|
`분류`는 Storybook 제목 `<배포|실험>/<단계>/<분류>/<항목>`의 셋째 마디이고, 토큰·구성·화면은 Storybook 메뉴와 같은 순서다.
|
|
13
13
|
|
|
@@ -95,6 +95,7 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
|
|
|
95
95
|
| [DesignSystemProvider](components/design-system-provider.md) | 기반 기능 | 앱 루트에 한 번 둔다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
96
96
|
| [Dialog](components/dialog.md) | 오버레이 | 화면 흐름을 잠시 멈추고 사용자의 주의가 필요한 **짧은 작업**에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
97
97
|
| [Divider](components/divider.md) | 레이아웃 | 서로 다른 내용 묶음 사이에 얇은 구분선이 필요할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
98
|
+
| [DrawingEditor](components/drawing-editor.md) | 입력 | 펜·지우개로 그림을 그리고 이미지로 저장하는 전체 편집 화면에 쓴다. | 1.49.0 | Web · Native | Web stable / Native stable | 배포 |
|
|
98
99
|
| [EditorScreen](components/editor-screen.md) | 레이아웃 | 글쓰기·프로필 수정처럼 한 화면 전체가 편집 흐름일 때 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
99
100
|
| [EffectSurface](components/effect-surface.md) | 시각 효과 | 환영·온보딩·빈 히어로처럼 분위기를 주는 배경이 필요할 때 내용 뒤에 장식 레이어(mesh·glow·grain)를 깐다. | 1.12.1 | Web · Native | 개별 API 계약 참조 | 배포 |
|
|
100
101
|
| [EmptyState](components/empty-state.md) | 상태와 알림 | 목록이 비었거나 검색 결과가 0건이라 **아직 없음**을 알릴 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
@@ -120,9 +121,9 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
|
|
|
120
121
|
| [InlineEdit](components/inline-edit.md) | 구성/입력과 작성 | 목록·상세의 제목처럼 이미 확정된 짧은 값 하나를 그 자리에서 명시적으로 편집·저장·취소할 때 쓴다. | 1.21.0 | Web · Native | 개별 API 계약 참조 | 배포 |
|
|
121
122
|
| [KeyboardAvoidanceContext](components/keyboard-avoidance-context.md) | — | 제품이 직접 만든 키보드 대응 영역 안에서 HJM `ScreenLayout`·`Sheet`가 여백을 두 번 주지 않게 할 때 쓴다. | 1.27.0 | Native | 개별 API 계약 참조 | 배포 |
|
|
122
123
|
| [KeyboardAvoiding](components/keyboard-avoiding.md) | — | 추가 native peer 없이 하단 행동(BottomCTA, 채팅 입력창)이 소프트웨어 키보드에 가려지지 않게 할 때 쓴다. | 1.12.1 | Native | 개별 API 계약 참조 | 배포 |
|
|
123
|
-
| [KeyboardDock](components/keyboard-dock.md) | 구성/직접 조작과 모션 | `react-native-keyboard-controller`를 설치한 앱에서 화면 하단에 고정된 행동(BottomCTA, 채팅 입력창)이 키보드와 함께 위아래로 움직이게 할 때 쓴다(Native 전용, 별도 보조 기능.
|
|
124
|
-
| [KeyboardFormScrollView](components/keyboard-form-scroll-view.md) | 구성/직접 조작과 모션 | 입력 필드가 여러 개인 세로 스크롤 폼(가입, 프로필 수정, 주소 입력)에서 포커스된 필드가 키보드에 가려지지 않게 스크롤해 줄 때 쓴다(Native 전용, 별도 보조 기능.
|
|
125
|
-
| [KeyboardMotionProvider](components/keyboard-motion-provider.md) | 구성/직접 조작과 모션 | `@hjmds/react-native/keyboard-controller` 어댑터(KeyboardDock, KeyboardFormScrollView)를 쓰는 앱의 루트에 **한 번** 설치한다(Native 전용, 별도 보조 기능.
|
|
124
|
+
| [KeyboardDock](components/keyboard-dock.md) | 구성/직접 조작과 모션 | `react-native-keyboard-controller`를 설치한 앱에서 화면 하단에 고정된 행동(BottomCTA, 채팅 입력창)이 키보드와 함께 위아래로 움직이게 할 때 쓴다(Native 전용, 별도 보조 기능. 문서화한 선택 peer 계약은 stable). 내부는 `KeyboardStickyView`이며, 여백을 바꾸는 대신 키보드 움직임을 따라 translate 한다. | 1.12.1 | Native | 개별 API 계약 참조 | 배포 |
|
|
125
|
+
| [KeyboardFormScrollView](components/keyboard-form-scroll-view.md) | 구성/직접 조작과 모션 | 입력 필드가 여러 개인 세로 스크롤 폼(가입, 프로필 수정, 주소 입력)에서 포커스된 필드가 키보드에 가려지지 않게 스크롤해 줄 때 쓴다(Native 전용, 별도 보조 기능. 문서화한 선택 peer 계약은 stable). 내부는 `react-native-keyboard-controller`의 `KeyboardAwareScrollView`이고, `keyboardShouldPersistTaps="handled"`로 고정돼 키보드가 열린 채 버튼을 눌러도 탭이 전달된다. | 1.12.1 | Native | 개별 API 계약 참조 | 배포 |
|
|
126
|
+
| [KeyboardMotionProvider](components/keyboard-motion-provider.md) | 구성/직접 조작과 모션 | `@hjmds/react-native/keyboard-controller` 어댑터(KeyboardDock, KeyboardFormScrollView)를 쓰는 앱의 루트에 **한 번** 설치한다(Native 전용, 별도 보조 기능. 문서화한 선택 peer 계약은 stable). 내부는 `react-native-keyboard-controller`의 `KeyboardProvider`이며, 어댑터를 준비하려고 OS 키보드를 미리 띄우지 않도록 `preload={false}`로 고정돼 있다. | 1.12.1 | Native | 개별 API 계약 참조 | 배포 |
|
|
126
127
|
| [Layout](components/layout.md) | 레이아웃 | 앱의 상시 골격(header · sidebar · main · footer)을 한 번 세울 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
127
128
|
| [Link](components/link.md) | 동작 | 사용자가 복사하거나 새 탭으로 열 수 있는 **목적지**로 이동할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
128
129
|
| [List](components/list.md) | 데이터 표시 | 이미 다 불러온, 개수가 많지 않은 행들을 이름 있는 목록 하나로 묶을 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
@@ -176,7 +177,7 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
|
|
|
176
177
|
| [SettingsScreen](components/settings-screen.md) | 레이아웃 | 앱의 설정 화면 전체에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
177
178
|
| [SharedTransitionElement](components/shared-transition-element.md) | 구성/직접 조작과 모션 | 목록의 카드(사진·썸네일)를 눌러 상세 화면으로 갈 때, 같은 요소가 두 화면 사이에서 확대·축소되어 이어지는 공유 요소 전환에 쓴다. | 1.12.1 | Native | 개별 API 계약 참조 | 배포 |
|
|
178
179
|
| [SharedTransitionScreen](components/shared-transition-screen.md) | 구성/직접 조작과 모션 | `createHjmTransitionStack()`으로 만든 stack에서 공유 요소 전환을 쓸 때, **각 라우트 본문**을 감싼다. | 1.12.1 | Native | 개별 API 계약 참조 | 배포 |
|
|
179
|
-
| [ShareSheet](components/share-sheet.md) | 오버레이 | 링크 하나를 **앱 안의 받는 사람에게 보내거나(선택), 링크를 복사하거나, 기기 공유 시트로 내보내는** 공유 시트에 쓴다. |
|
|
180
|
+
| [ShareSheet](components/share-sheet.md) | 오버레이 | 링크 하나를 **앱 안의 받는 사람에게 보내거나(선택), 링크를 복사하거나, 기기 공유 시트로 내보내는** 공유 시트에 쓴다. | 1.48.0 | Web · Native | 개별 API 계약 참조 | 배포 |
|
|
180
181
|
| [Sheet](components/sheet.md) | 오버레이 | 현재 화면 위에 모달로 띄우는 보조 작업 패널에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
181
182
|
| [ShortcutRecorder](components/shortcut-recorder.md) | 구성/직접 조작과 모션 | Web 앱에서 사용자가 수정키+키 조합을 눌러 기록하고, 확인 뒤 실제 단축키로 등록하게 할 때 쓴다. | 1.21.0 | Web | 개별 API 계약 참조 | 배포 |
|
|
182
183
|
| [Sidebar](components/sidebar.md) | 탐색 | 데스크톱 Web의 세로 내비게이션에 쓴다. | 1.12.1 | Web | Web stable / Native unsupported | 배포 |
|
|
@@ -82,6 +82,7 @@ Web·Native 모두 기존 `raised` Surface의 테두리·그림자를 재사용
|
|
|
82
82
|
| prop | 값 | 기본값 | 설명 |
|
|
83
83
|
| --- | --- | --- | --- |
|
|
84
84
|
| `tone` | `default` · `raised` · `accent` · `sunken` · `subtle` · `selected`(Surface tone) | `raised` | 테두리와 공통 raised shadow로 입체감 표시. 평면 카드는 `tone="default"` 지정 |
|
|
85
|
+
| `badgesPlacement` | `body` · `corner` | `body` | 개발 소스·미게시. `corner`는 짧은 비상호작용 배지를 카드 우상단 8px에 12도 기울여 겹친다. 본문 높이를 늘리지 않는다. 다에리 NEW 배지 유무로 카드 높이가 달라진 문제를 해결하며 기존 `mediaBadges`의 배경 그림 전용 분류와 구분한다 |
|
|
85
86
|
| `badgesAlign` | `start` · `center` | `start` | 미게시. 들판 대표 카드처럼 그림 아래의 배지 묶음을 가운데 배치할 때 `center` 사용. 줄바꿈된 행에도 적용 |
|
|
86
87
|
| `bordered` | `boolean` | `true` | Surface 기본 `false`와 다르다 |
|
|
87
88
|
| `padding` | spacing 이름 | `md`(16) | — |
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
Web에서 제품이 소유한 영역(카드·목록 행·캔버스)의 우클릭·길게 누르기·Shift+F10에 명령 목록을
|
|
14
14
|
띄울 때 쓴다. 같은 명령은 화면의 다른 경로(버튼·Menu)에도 있어야 한다. Native는 추가 의존성 없는
|
|
15
|
-
canonical `ContextMenu`(`@hjmds/react-native/context-menu`,
|
|
15
|
+
canonical `ContextMenu`(`@hjmds/react-native/context-menu`, 2026-10-16 도입)가 채팅 길게 누르기 메뉴와 같은
|
|
16
16
|
모양(배경 어둡게 + 누른 위치 근처 카드, 행 높이 48, 아이콘 24 칸, 위험 항목 빨간 글자)으로 연다. 대화 목록·댓글처럼
|
|
17
17
|
행을 길게 눌러 여는 동작 목록은 이것을 쓴다. OS 고유 메뉴가 꼭 필요할 때만 선택 어댑터 `NativeContextMenu`를 쓴다.
|
|
18
18
|
|
|
@@ -148,7 +148,7 @@ import { Pressable } from "react-native";
|
|
|
148
148
|
| 메뉴 접근성 이름 | `accessibilityLabel`(필수) | 없음(자식 요소가 이름을 가짐) |
|
|
149
149
|
| 항목 `textValue`·`shortcut` | 있음 | 없음 |
|
|
150
150
|
| 열림 알림 | 없음 | `onOpenChange(open)` |
|
|
151
|
-
| 성숙도 | stable |
|
|
151
|
+
| 성숙도 | stable | 선택형 어댑터 stable (canonical ContextMenu와 별도) |
|
|
152
152
|
|
|
153
153
|
Web 활성 항목은 실제 마우스 이동으로만 바꾸며(1.15.0 변경), 늦은 경계 이벤트만으로 키보드 선택을 덮지 않는다. 클릭·키보드 실행·포커스 복귀와
|
|
154
154
|
Native OS 어댑터는 기존 계약을 유지한다. 고정 대기 시간이 아니라 입력 의도로 구분한다.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# DrawingEditor
|
|
2
|
+
|
|
3
|
+
- 단계: 컴포넌트
|
|
4
|
+
- 상태: 배포
|
|
5
|
+
- 지원: Web · Native
|
|
6
|
+
- 적용: 1.49.0
|
|
7
|
+
- 검토일: 2026-10-27
|
|
8
|
+
- 근거: 다에리와 스핀트의 프로필 손그림 편집기가 복제돼 도구·이력·레이아웃이 갈라지는 것을 막으라는 사용자 요청
|
|
9
|
+
- 스토리북: `배포/컴포넌트/입력/손그림 편집기`
|
|
10
|
+
|
|
11
|
+
1.49.0에는 beta로 처음 게시됐으며 stable 판정은 1.50.0부터 적용된다.
|
|
12
|
+
|
|
13
|
+
## 언제 쓰나
|
|
14
|
+
|
|
15
|
+
펜·지우개로 그림을 그리고 이미지로 저장하는 전체 편집 화면에 쓴다. 프로필 사진뿐 아니라 사각 그림에도 사용할 수 있다.
|
|
16
|
+
도구 배치·그리기 상태·실행 취소·다시 실행·전체 지우기·펜 굵기·최근 색·배경·저장 진행·실패·닫기 확인을 공통으로 제공한다.
|
|
17
|
+
사진 선택·자르기에는 제품 이미지 피커를 사용한다. 문서 필기 인식이나 필압·벡터 파일 편집은 제공하지 않는다.
|
|
18
|
+
|
|
19
|
+
## 쓰지 않을 때
|
|
20
|
+
|
|
21
|
+
| 상황 | 대신 쓸 것 |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| 사진을 고르거나 촬영 | 제품 이미지 피커 |
|
|
24
|
+
| 색상 하나만 선택 | [ColorPicker](color-picker.md) |
|
|
25
|
+
| 일반 텍스트 편집 | [EditorScreen](editor-screen.md) |
|
|
26
|
+
|
|
27
|
+
## 공개 이름과 import
|
|
28
|
+
|
|
29
|
+
| 이름 | 역할 | Web | Native |
|
|
30
|
+
| --- | --- | --- | --- |
|
|
31
|
+
| `DrawingEditor` | 전체 편집 화면 | `@hjmds/react/drawing-editor` | `@hjmds/react-native/drawing-editor` |
|
|
32
|
+
| `DrawingEditorProps`, `DrawingEditorLabels`, `DrawingImage` | 공통 타입 | 같은 경로 | 같은 경로 |
|
|
33
|
+
| `drawingEditorRecipe`, `drawingReducer`, `drawingInkPath` | 배치·이력·선 생성 계약 | `@hjmds/design-contracts/components/drawing-editor` | 같음 |
|
|
34
|
+
|
|
35
|
+
루트 barrel로 내보내지 않는다. Web는 기존 optional `lucide-react`, Native는 `react-native-svg`와 `lucide-react-native` peer가 필요하다.
|
|
36
|
+
새 라이브러리는 추가하지 않는다. 기존 ColorPicker와 EditorScreen을 합성하며 별도 색상 피커나 화면 셸을 만들지 않는다.
|
|
37
|
+
|
|
38
|
+
## 최소 사용 예
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
// Native
|
|
42
|
+
import { DrawingEditor } from '@hjmds/react-native/drawing-editor';
|
|
43
|
+
|
|
44
|
+
<DrawingEditor
|
|
45
|
+
labels={localizedLabels}
|
|
46
|
+
cropPreview="circle"
|
|
47
|
+
safeAreaBottom={insets.bottom}
|
|
48
|
+
onCancel={close}
|
|
49
|
+
onSave={async image => {
|
|
50
|
+
// 제품이 계정 세대를 검증하고 서버가 받는 형식으로 변환한다.
|
|
51
|
+
await uploadProfileImage(image);
|
|
52
|
+
close();
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
// Web
|
|
59
|
+
import { DrawingEditor } from '@hjmds/react/drawing-editor';
|
|
60
|
+
|
|
61
|
+
<DrawingEditor labels={localizedLabels} cropPreview="circle"
|
|
62
|
+
onSave={uploadAndClose} onCancel={close} />
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 축과 기본값
|
|
66
|
+
|
|
67
|
+
| prop | 값 | 기본값 | 설명 |
|
|
68
|
+
| --- | --- | --- | --- |
|
|
69
|
+
| labels | `DrawingEditorLabels` | 필수 | 모든 도구·오류·닫기 확인 문구 |
|
|
70
|
+
| onSave | `(image: DrawingImage) => Promise<void>` | 필수 | 이미지 업로드 성공/실패를 제품이 확정 |
|
|
71
|
+
| onCancel | `() => void` | 필수 | 변경 취소 확인 후 나가기 |
|
|
72
|
+
| cropPreview | `circle`, `none` | `none` | 출력에 포함하지 않는 원형 잘림 안내 |
|
|
73
|
+
| safeAreaBottom | number | 0 | Native host의 아래 안전 영역 |
|
|
74
|
+
| testID | string | `drawing-editor` | 테스트 식별자와 캔버스 접두사 |
|
|
75
|
+
|
|
76
|
+
## 배치
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
EditorScreen: 안전 영역 + 닫기/제목
|
|
80
|
+
되돌리기·다시 실행 배경·전체 지우기
|
|
81
|
+
정사각 캔버스(원형 잘림 안내 선택)
|
|
82
|
+
펜 / 지우개
|
|
83
|
+
굵기
|
|
84
|
+
빠른 색상 스트립 · 더 많은 색
|
|
85
|
+
EditorScreen: 저장 footer + 아래 안전 영역
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
| 항목 | 값 | 근거 |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| 크기 | 캔버스 최대 400, Native 가용 영역 안 정사각 | `drawingEditorRecipe.maxCanvas` |
|
|
91
|
+
| 간격 | Native 도구 묶음 12, Web Stack md | 기존 양 표면의 편집기 배치 보존 |
|
|
92
|
+
| 순서·정렬 | 이력 → 캔버스 → 도구 → 저장 | 원형 예고는 캔버스 위 오버레이 |
|
|
93
|
+
| 고정·스크롤 | Native 본문 비스크롤, 저장 footer | 세로 획을 부모 스크롤에서 보호 |
|
|
94
|
+
| 좁은 폭·큰 글자 | 가용 폭 안에서 캔버스 축소, 색상은 가로 스크롤 | 최대 글자 조건은 전사 지침대로 제외 |
|
|
95
|
+
|
|
96
|
+
## 꼭 지킬 것
|
|
97
|
+
|
|
98
|
+
- 그림 도구·이력을 제품에서 다시 조립하지 않는다.
|
|
99
|
+
- 저장 실패는 reject하고 성공 후 화면 이동은 제품이 수행한다.
|
|
100
|
+
- 업로드 전 계정 세대와 이미지 입력 한도를 검사한다.
|
|
101
|
+
|
|
102
|
+
## 상태와 제품 경계
|
|
103
|
+
|
|
104
|
+
`labels`는 모든 문구를 요구한다. 제품은 번역·계정·업로드·형식 변환·성공 후 탐색만 연결한다.
|
|
105
|
+
`onSave`가 reject되면 오류를 보이고 그림과 이력을 보존한다. 성공을 HJM이 추정해 화면을 닫지 않는다.
|
|
106
|
+
저장 중 반복 저장과 편집을 막으며 비어 있는 기본 배경은 저장할 수 없다. 배경만 바꾼 그림은 저장 가능하다.
|
|
107
|
+
이미지는 Native SVG의 PNG 또는 Web Canvas의 JPEG base64와 실제 `mimeType`으로 전달된다. 크기·압축·업로드 한도는 제품 계약에 맞춘다.
|
|
108
|
+
계정이 바뀌는 동안 이미지 추출이 끝날 수 있으므로 소비자는 렌더 시점의 계정 세대를 캡처해 업로드 전에 다시 검증한다.
|
|
109
|
+
|
|
110
|
+
## 레이아웃과 상호작용
|
|
111
|
+
|
|
112
|
+
상단 이력·배경·지우기 → 정사각 캔버스 → 펜/지우개 → 굵기 → 색상 스트립 순서다. 저장과 닫기는 EditorScreen이 소유한다.
|
|
113
|
+
Native는 부모 스크롤이 세로 획을 가져가지 않도록 `scroll="content"`를 사용하고 실제 가용 영역 안에서 캔버스 크기를 정한다.
|
|
114
|
+
Web는 pointer capture와 `touch-action: none`을 사용한다. 첫 터치/포인터만 획을 소유한다.
|
|
115
|
+
`cropPreview="circle"`은 잘릴 모서리를 표시하지만 출력 이미지에는 포함하지 않는다. 기본값 `none`은 사각 그림이다.
|
|
116
|
+
펜과 지우개의 실제 굵기는 슬라이더 값과 같다. 배경 변경 후 지우개 자국도 새 배경을 따른다.
|
|
117
|
+
|
|
118
|
+
## 확인 범위와 소비 이관
|
|
119
|
+
|
|
120
|
+
다에리 Native·Web, 스핀트 Native가 이 컴포넌트를 소비한다. 제품의 중복 캔버스·도구·이력 구현과 그 전용 계약 테스트는 제거하고
|
|
121
|
+
공통 계약/renderer 테스트로 옮긴다. 제품 테스트는 계정·업로드 실패·탐색 연결을 계속 확인한다.
|
|
122
|
+
공개 패키지 설치, 제품 채택과 실기기 검증은 각각 확인한다. 캔버스 획 입력은 포인터·터치 전용이며 키보드로 그리는 기능은 제공하지 않는다.
|
|
123
|
+
|
|
124
|
+
## 플랫폼 차이
|
|
125
|
+
|
|
126
|
+
| 항목 | Web | Native |
|
|
127
|
+
| --- | --- | --- |
|
|
128
|
+
| 획 입력 | pointer capture | 단일 responder 소유 |
|
|
129
|
+
| 이미지 | Canvas JPEG | SVG PNG |
|
|
130
|
+
| 주변 스크롤 | touch-action none | 비스크롤 본문 |
|
|
131
|
+
|
|
132
|
+
## 근거
|
|
133
|
+
|
|
134
|
+
- 공통 소유권: 2026-10-27 사용자 지시로 다에리·스핀트의 복제 편집기를 HJM으로 옮겼다.
|
|
135
|
+
- 획 소유권과 스크롤: 기존 다에리의 두 번째 손가락·세로 획 결함 대응을 보존한다.
|
|
@@ -69,7 +69,7 @@ import { ImageChoiceGroup } from "@hjmds/react-native/image-choice";
|
|
|
69
69
|
| 크기 | 그림 72 정사각, 바깥 고리 2 + 간격 2(터치 영역 80), radius `radius.md` 12, 체크 원 20 | `imageChoiceRecipe` |
|
|
70
70
|
| 간격 | 타일 사이 `spacing.xs` 8(가로·세로), 라벨–타일 8, 그림–항목 라벨 `spacing.xxs` 4. 이름과 설명 사이 0 | `imageChoiceRecipe.gap`, `itemLabelGap` |
|
|
71
71
|
| 글자 칸 | 이름 줄(`itemLabelLines`) + 설명 줄(묶음에 설명이 있으면 1)을 caption 행간(16 × 글자 배율)으로 모든 타일이 같은 높이로 비워 둔다. 타일 높이 = 80 + 4 + 줄 수 × 행간(글자 칸이 없으면 80) | `resolveImageChoiceCaptionLines`, `resolveImageChoiceTileHeight` |
|
|
72
|
-
| 순서·정렬 | `items` 순서대로 시작 쪽부터 줄바꿈
|
|
72
|
+
| 순서·정렬 | `items` 순서대로 시작 쪽부터 줄바꿈 배치. 항목이 적어도 화면 폭에 맞는 빈 칸을 유지해 다음 항목이 중간 칸부터 채워진다(2026-10-27 Diairy 양끝 벌어짐 수정). 체크는 타일 끝 쪽 위 모서리 | 두 렌더러 |
|
|
73
73
|
| 고정·스크롤 | 기본은 자체 스크롤 없음(바깥 목록·화면이 스크롤). `virtualized`면 묶음이 `height` 높이로 스스로 스크롤한다. Web은 포커스 테두리가 잘리지 않게 안쪽 여백 4(`virtualViewportInset`), 열 수 = ⌊(폭 + 8) / 88⌋(최소 1) | 두 렌더러, `resolveImageChoiceColumns` |
|
|
74
74
|
| 좁은 폭·큰 글자 | 남은 폭에서 줄바꿈, 타일 크기는 유지 | flex wrap |
|
|
75
75
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
## 언제 쓰나
|
|
12
12
|
|
|
13
13
|
`react-native-keyboard-controller`를 설치한 앱에서 화면 하단에 고정된 행동(BottomCTA, 채팅 입력창)이
|
|
14
|
-
키보드와 함께 위아래로 움직이게 할 때 쓴다(Native 전용, 별도 보조 기능.
|
|
14
|
+
키보드와 함께 위아래로 움직이게 할 때 쓴다(Native 전용, 별도 보조 기능. 문서화한 선택 peer 계약은 stable). 내부는 `KeyboardStickyView`이며,
|
|
15
15
|
여백을 바꾸는 대신 키보드 움직임을 따라 translate 한다.
|
|
16
16
|
|
|
17
17
|
## 쓰지 않을 때
|
|
@@ -107,4 +107,4 @@ const keyboardOpen = useKeyboardState((state) => state.isVisible);
|
|
|
107
107
|
|
|
108
108
|
- sticky 좌표는 창 기준이다. Storybook 캔버스처럼 아래에 다른 막대가 있는 host에서는 위치가 어긋나므로
|
|
109
109
|
쇼케이스도 앱 크기 host에서 확인한다.
|
|
110
|
-
-
|
|
110
|
+
- 문서화한 선택 peer 계약은 stable이다([근거](../../optional-adapters.md#current-support--2026-10-26)). 실제 키보드 애니메이션은 mock 테스트로 검증되지 않는다. 개발 클라이언트로 확인한다.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
## 언제 쓰나
|
|
12
12
|
|
|
13
13
|
입력 필드가 여러 개인 세로 스크롤 폼(가입, 프로필 수정, 주소 입력)에서 포커스된 필드가 키보드에
|
|
14
|
-
가려지지 않게 스크롤해 줄 때 쓴다(Native 전용, 별도 보조 기능.
|
|
14
|
+
가려지지 않게 스크롤해 줄 때 쓴다(Native 전용, 별도 보조 기능. 문서화한 선택 peer 계약은 stable). 내부는 `react-native-keyboard-controller`의
|
|
15
15
|
`KeyboardAwareScrollView`이고, `keyboardShouldPersistTaps="handled"`로 고정돼 키보드가 열린 채 버튼을 눌러도 탭이 전달된다.
|
|
16
16
|
|
|
17
17
|
## 쓰지 않을 때
|
|
@@ -92,4 +92,4 @@ import { spacing } from "@hjmds/design-contracts/foundations";
|
|
|
92
92
|
좌우 여백까지 스크롤 컨테이너에 직접 준다. 규칙은 세로 여백만 스크롤에, 좌우는 Container `gutter`다.
|
|
93
93
|
|
|
94
94
|
- `refreshControl`, `onScroll` 같은 다른 ScrollView prop은 타입에서 빠져 있어 넘길 수 없다.
|
|
95
|
-
-
|
|
95
|
+
- 문서화한 선택 peer 계약은 stable이다([근거](../../optional-adapters.md#current-support--2026-10-26)). 포커스 이동·키보드 애니메이션은 개발 클라이언트로 기기에서 확인한다.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
## 언제 쓰나
|
|
12
12
|
|
|
13
13
|
`@hjmds/react-native/keyboard-controller` 어댑터(KeyboardDock, KeyboardFormScrollView)를 쓰는 앱의
|
|
14
|
-
루트에 **한 번** 설치한다(Native 전용, 별도 보조 기능.
|
|
14
|
+
루트에 **한 번** 설치한다(Native 전용, 별도 보조 기능. 문서화한 선택 peer 계약은 stable). 내부는 `react-native-keyboard-controller`의
|
|
15
15
|
`KeyboardProvider`이며, 어댑터를 준비하려고 OS 키보드를 미리 띄우지 않도록 `preload={false}`로 고정돼 있다.
|
|
16
16
|
|
|
17
17
|
## 쓰지 않을 때
|
|
@@ -83,4 +83,4 @@ import { KeyboardMotionProvider } from "@hjmds/react-native/keyboard-controller"
|
|
|
83
83
|
- tsc·mock 테스트 통과는 peer 설치와 native 연결의 근거가 아니다. 다른 optional subpath
|
|
84
84
|
(celebration·effect-surface·qr-code·thinking-orb·toast-liquid)에서 앱에 없는 peer 때문에
|
|
85
85
|
기기 Metro에서만 크래시가 난 사례가 있다(2026-10). 개발 클라이언트로 실제 화면을 띄워 확인한다.
|
|
86
|
-
-
|
|
86
|
+
- 문서화한 선택 peer 계약은 stable이다. 소비 기기의 키보드·보조기술 검증은 별도로 확인한다([근거](../../optional-adapters.md#current-support--2026-10-26)).
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# ShareSheet
|
|
2
2
|
|
|
3
3
|
- 단계: 컴포넌트
|
|
4
|
-
- 상태:
|
|
4
|
+
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
|
-
- 적용:
|
|
6
|
+
- 적용: 1.48.0
|
|
7
7
|
- 검토일: 2026-10-26
|
|
8
8
|
- 근거: `src/share-sheet.ts`의 `shareSheetRecipe`·`resolveShareSheetSendOutcome`·`filterShareSheetRecipients`; Web `src/share-sheet.tsx`, Native `src/share-sheet.tsx`
|
|
9
|
-
- 스토리북:
|
|
9
|
+
- 스토리북: `배포/컴포넌트/오버레이/공유 시트`
|
|
10
|
+
|
|
11
|
+
1.48.0부터 제공하며 stable 지원은 1.50.0부터 적용된다.
|
|
10
12
|
|
|
11
13
|
## 언제 쓰나
|
|
12
14
|
|
|
@@ -112,6 +112,18 @@ import { Sheet } from "@hjmds/react-native/overlays";
|
|
|
112
112
|
|
|
113
113
|
개발 소스·미게시: `size="small"`은 가용 높이의 40%로, `medium`(60%) 높이의 2/3이다. 짧은 안내에 내용 높이만 쓰면 지나치게 작고 medium은 빈 공간이 큰 경우 선택한다. Web·Native 공통 recipe가 크기를 소유한다.
|
|
114
114
|
|
|
115
|
+
### 크기 고르기 (2026-10-27)
|
|
116
|
+
|
|
117
|
+
2026-10-27 포트폴리오 전 앱 하단 시트 조사에서 고정 크기 16곳 중 6곳의 높이가 내용보다 과했다.
|
|
118
|
+
연도 선택기 하나뿐인 필터가 85%로 열렸고, 문단 하나짜리 안내가 60%였다. 사유 6개짜리 신고·몇 줄짜리 알림 설정·몇 개 안 되는 기록 목록도 85%로 열렸다.
|
|
119
|
+
그래서 크기는 아래 순서로 고른다.
|
|
120
|
+
|
|
121
|
+
- **기본은 `auto`다.** 내용이 정해진 보조 작업은 내용 높이로 연다. 신고, 행 몇 개짜리 설정, 확인, 조건 몇 개짜리 필터, 길이가 바뀌는 선택 목록이 여기에 든다. 길어지면 90%에서 멈추고 본문이 스크롤한다.
|
|
122
|
+
- **고정 크기(`medium`·`large`·`full`)는 본문이 남은 높이를 채워야 할 때만 쓴다.** 자기 스크롤과 상태 영역을 가진 검색·목록 화면(SearchScreen 등), 그리기처럼 화면을 쓰는 작업이 여기에 든다. 고르는 조건에 따라 구획이 나타나고 사라져 편집 중 높이가 흔들리는 폼도 고정 크기를 쓴다.
|
|
123
|
+
- **짧은 안내 문단에는 `medium` 대신 `small`(또는 `auto`)을 쓴다.**
|
|
124
|
+
- **화면 틀을 시트에 넣고 고정 크기로 채우지 않는다.** 시트 안 신고는 `ModerationScreen` 대신 [ModerationForm](moderation-screen.md)을 쓰고 `auto`로 연다. 화면 틀은 높이를 채워야 해서 시트를 large로 키우게 된다.
|
|
125
|
+
- **제품의 공통 시트 wrapper는 모든 사용처에 같은 고정 크기를 강제하지 않는다.** 기본은 `auto`로 두고, 위 고정 크기 조건에 맞는 사용처만 크기를 넘긴다.
|
|
126
|
+
|
|
115
127
|
Native 스크롤 본문은 viewport 높이만큼 content를 채운다(미게시). 고정 크기 시트의 빈/오류/로딩 상태는 `CompositionLayout layoutStyle={{ flex: 1 }}`로 연결해 손잡이·머리·footer를 제외한 본문 중앙에 둔다. 목록이 길면 같은 본문에서 스크롤한다.
|
|
116
128
|
|
|
117
129
|
선택형 Native `GestureSheetInput`의 실제 keyboard-tracking host에도 제품 `tokens.fontFamily.ui`가 이어진다. optional library·폰트 설치와 실제 기기 검증은 제품이 맡는다.
|
|
@@ -122,7 +134,7 @@ Native 스크롤 본문은 viewport 높이만큼 content를 채운다(미게시)
|
|
|
122
134
|
| --- | --- | --- |
|
|
123
135
|
| 크기 | 하단 시트 높이: `auto` 내용 높이(최대 화면 높이 × `maxHeightRatio` 0.9), `medium` 60%, `large` 85%, `full` 위 safe area 안 전체 높이(0.9 상한 없음). Web 하단 시트 최대 폭 640. 위 두 모서리만 `radius.xl` 24. 옆 시트(`start`·`end`): Web 폭 `min(28rem, 100%)`·높이 화면 − 32, Native 폭 88%(최대 420)·화면 높이 | `sheetRecipe.sizes`·`content`·`web`, `.hjm-sheet`, Native `Sheet` |
|
|
124
136
|
| 간격 | 두 플랫폼 같은 값: 좌우 `content.paddingHorizontal`(`spacing.lg` 20), 위·아래 `content.paddingTop/Bottom`(`spacing.sm` 12, 하단 시트는 아래 safe area를 더함), 머리·본문·footer 사이 `body.gap`(`spacing.md` 16), footer 위 `footer.paddingTop`(`spacing.sm` 12), 제목–닫기 `header.gap`(`spacing.sm` 12), footer 버튼 사이 `footer.gap`(`spacing.xs` 8) | `.hjm-sheet__*`, `sheetRecipe.content`·`body`·`footer` |
|
|
125
|
-
| 순서·정렬 | 손잡이(하단) → 머리(설명 + 닫기, 둘 다 없으면 그리지 않음) → 본문 → `footer`. 보이는 제목 줄은 없다(미게시). 머리 최소 높이 44(`control.minTouchTarget`), ×는 설명이 없어도 끝 쪽 같은 자리다. 기본 하단 시트는 머리가 없어 본문이 손잡이 영역 바로 아래 `body.gap` 16에서 시작한다. Web footer는 오른쪽 정렬 가로 줄 [보조][주]. Native footer는 세로 열이라 꽉 찬 폭 버튼을 주 행동 먼저 둔다. 하단 시트는 항상 위 가운데 36×4 손잡이(터치 최소 폭·높이44)를 둔다. `detents`가 있으면 높이 전환 버튼, 없고 ×가 없으면 `closeLabel` 이름의 닫기 버튼이다. `showClose: true`로 ×를 표시하면 손잡이는 장식으로 남겨 같은 닫기 버튼이 중복되지 않는다(미게시). 손잡이·머리 영역을 아래로 끌어 `sheetDragRecipe.dismissDistanceRatio`(시트 높이의 25%) 또는 `dismissVelocity` 0.5px/ms를 넘기면 `swipe`로 닫고, 아니면 제자리로 돌아간다(미게시, Web·Native 동일) | `sheetRecipe.header`·`handle`, `.hjm-sheet__footer`, `.hjm-sheet__handle` |
|
|
137
|
+
| 순서·정렬 | 손잡이(하단) → 머리(설명 + 닫기, 둘 다 없으면 그리지 않음) → 본문 → `footer`. 보이는 제목 줄은 없다(미게시). 머리 최소 높이 44(`control.minTouchTarget`), ×는 설명이 없어도 끝 쪽 같은 자리다. 기본 하단 시트는 머리가 없어 본문이 손잡이 영역 바로 아래 `body.gap` 16에서 시작한다. Web footer는 오른쪽 정렬 가로 줄 [보조][주]. Native footer는 세로 열이라 꽉 찬 폭 버튼을 주 행동 먼저 둔다. 하단 시트는 항상 위 가운데 36×4 손잡이(터치 최소 폭·높이44)를 둔다. `detents`가 있으면 높이 전환 버튼, 없고 ×가 없으면 `closeLabel` 이름의 닫기 버튼이다. `showClose: true`로 ×를 표시하면 손잡이는 장식으로 남겨 같은 닫기 버튼이 중복되지 않는다(미게시). 손잡이·머리 영역을 아래로 끌어 `sheetDragRecipe.dismissDistanceRatio`(시트 높이의 25%) 또는 `dismissVelocity` 0.5px/ms를 넘기면 `swipe`로 닫고, 아니면 제자리로 돌아간다(미게시, Web·Native 동일). 본문도 같은 끌기로 닫는다(2026-10-27 사용자 결정, 미게시). 스크롤 본문은 이미 맨 위일 때 시작한 아래 끌기만 시트가 가져가고, 스크롤된 상태에서는 같은 동작이 먼저 내용을 위로 되돌린다. iOS는 UIScrollView가 JS 응답자 아래서도 스스로 끌기를 가져가므로 본문 맨 위의 당김(overscroll)으로 시트를 움직이고 UIKit 탄성 거리로 환산한 같은 임계값을 쓴다. Web 본문 끌기는 터치만 받고 마우스는 글자 선택을 위해 손잡이를 쓴다. 입력칸에서 시작한 끌기와 가로 끌기는 본문 안의 행동으로 남긴다 | `sheetRecipe.header`·`handle`, `.hjm-sheet__footer`, `.hjm-sheet__handle` |
|
|
126
138
|
| 고정·스크롤 | 본문만 스크롤, 머리·`footer` 고정(Native는 `scrollable`일 때 ScrollView). 스크롤 영역은 시트 좌우 여백(`sheetRecipe.content.paddingHorizontal` 20) 끝까지 넓고 여백은 스크롤 내용 안쪽에 둔다(Web `.hjm-sheet__body` padding, Native ScrollView `marginHorizontal: -20` + 내용 `paddingHorizontal: 20`). 그래서 본문 ListRow의 8 표면이 잘리지 않고 내용 위치는 그대로다. 고정 높이(`medium`·`large`·`full`, 옆 시트)에서는 본문이 머리·footer를 뺀 남은 높이를 차지하고 `footer`는 시트 아래에 붙는다. 그래서 본문의 `flex: 1` 자식(SearchScreen, 목록 화면)이 그 높이를 채운다(Web `.hjm-sheet__body` `flex: 1 1 auto`, Native 본문 `flexGrow: 1`·`minHeight: 0`, 1.13.1 변경). `auto`는 내용 높이 그대로다. 저장·확인은 `footer`에. 아래 안전 영역은 시트가 자기 여백에 더한다(`spacing.sm` 12 + 아래 inset, Web은 `env(safe-area-inset-bottom)`). 위 inset은 시트가 올라갈 높이를 줄인다. 제품이 inset을 다시 더하지 않는다 | `.hjm-sheet__body`, `sheetRecipe.safeArea`, Native `Sheet` |
|
|
127
139
|
| 좁은 폭·큰 글자 | 폭 < 640이면 하단 시트가 화면 폭을 채운다. Web footer는 줄을 바꾼다. 큰 글자로 내용이 길어지면 `auto`는 최대 90%에서 멈추고 본문이 스크롤된다(`full`은 위 safe area까지) | `.hjm-sheet[data-placement="bottom"]`, `maxHeightRatio` |
|
|
128
140
|
|
|
@@ -4,15 +4,32 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-27
|
|
8
8
|
- 근거: [Timeline](../../timeline.md), `src/timeline.ts`(`timelineRecipe`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/데이터 표시/타임라인`
|
|
10
10
|
|
|
11
|
+
## 기본 표현: 여행 일지 (2026-10-27 개발 소스, 미게시)
|
|
12
|
+
|
|
13
|
+
사용자가 다이어리 비교 시안의 「여행 일지」를 선택한 뒤 옵션이 아닌 기본형으로 지정했다.
|
|
14
|
+
`variant` 기본값은 `journal`이다. 박스·선택 배경 없이 작은 점과 연결선으로 기록을 잇고 제목 아래에
|
|
15
|
+
시각을 둔다. 이전 면·테두리 표현이 꼭 필요한 경우에만 `variant="record"`를 명시한다.
|
|
16
|
+
|
|
17
|
+
- 수동 기록은 모든 설명·metadata·기존 행동을 계속 표시한다. 경기 중계·버전 복구·활동 이력이 자동으로 접히지 않는다.
|
|
18
|
+
- `selectedId`/`onSelectedIdChange`가 있으면 선택한 기록의 설명·metadata만 펼친다. 다시 누르면 상세만 접고 선택은 유지한다.
|
|
19
|
+
- 다른 행·지도·날짜에서 선택을 바꾸면 새 기록을 펼친다. 제목·시각은 접어도 남는다. 펼침 상태·chevron은 HJM이 소유한다.
|
|
20
|
+
- Web 기본형은 `<ol><li><button aria-expanded aria-controls>`의 disclosure 목록이다. 모든 기록 버튼에 Tab으로 접근하고 ↑/↓/Home/End로 이동·선택할 수 있다. Enter/Space는 native button 동작으로 펼침을 전환한다.
|
|
21
|
+
- Native는 `Pressable`의 selected·expanded 상태를 제공한다. 접힌 설명은 접근성 이름에서도 제외한다.
|
|
22
|
+
- `tone`의 의미와 독립 행동의 접근성·가상화 경계는 유지한다. `emphasized`의 큰 배경 면은 journal에 적용하지 않는다.
|
|
23
|
+
|
|
24
|
+
현재 사용처: 다이어리 웹·앱 여정, 번뚝 웹·앱 버전/이야기/피드 기록, 야잘알 앱 경기 중계·선수 경력,
|
|
25
|
+
Today갈게 partner-web·partner 활동 기록, portfolio-site 성과 이력. 이들은 기본 디자인 변경의 영향 대상이며
|
|
26
|
+
제품별 기능·데이터를 바꾸거나 운영 반영을 확인했다는 뜻은 아니다. 웹·앱 Storybook에도 여행 일지 예제를 둔다.
|
|
27
|
+
|
|
11
28
|
## 언제 쓰나
|
|
12
29
|
|
|
13
30
|
이미 일어난 일을 시간 순서대로 보여 줄 때 쓴다. 경기 플레이 기록, 이적·변경 이력, 주문 처리
|
|
14
31
|
기록처럼 "무슨 일이 언제 있었나"를 위→아래 한 방향으로 나열한다. 현재 위치(커서)는 없다.
|
|
15
|
-
기록 하나를 골라 옆의 지도·상세를 바꿔야 하면 `selectedId`/`onSelectedIdChange`로 기록 자체를
|
|
32
|
+
기록 하나를 골라 옆의 지도·상세를 바꿔야 하면 `selectedId`/`onSelectedIdChange`로 기록 자체를 선택·펼침 대상으로 만든다(개발 소스, 미게시).
|
|
16
33
|
|
|
17
34
|
## 쓰지 않을 때
|
|
18
35
|
|
|
@@ -20,7 +37,7 @@
|
|
|
20
37
|
| --- | --- |
|
|
21
38
|
| 흐름에서 지금 어디에 있는지(현재 단계) | [Steps](steps.md) |
|
|
22
39
|
| 항목을 눌러 다른 화면으로 이동 | [List](list.md), [ListRow](list-row.md) |
|
|
23
|
-
| 기록 옆에 번호·선택 `Button`을 두고 `tone`·`aria-pressed`로 선택을 흉내 | `selectedId`/`onSelectedIdChange`.
|
|
40
|
+
| 기록 옆에 번호·선택 `Button`을 두고 `tone`·`aria-pressed`로 선택을 흉내 | `selectedId`/`onSelectedIdChange`. 선택·펼침·키보드·접근성 의미는 Timeline이 소유한다 |
|
|
24
41
|
| 항목이 하나도 없음 | Timeline을 마운트하지 않고 [EmptyState](empty-state.md) |
|
|
25
42
|
| 과거 기록을 더 불러옴 | Timeline 아래에 [LoadMore](load-more.md)를 합성 |
|
|
26
43
|
| 항목별 짧은 배지 | `renderMetadata` 슬롯에 제품의 [Badge](badge.md) 또는 [Tag](tag.md)를 연결 |
|
|
@@ -73,6 +90,7 @@ import { Timeline } from "@hjmds/react-native/data-display";
|
|
|
73
90
|
|
|
74
91
|
| prop | 값 | 기본값 | 설명 |
|
|
75
92
|
| --- | --- | --- | --- |
|
|
93
|
+
| `variant` | `journal` · `record` | `journal` | 기본 여행 일지 / 이전 면·테두리 표현. 개발 소스, 미게시 |
|
|
76
94
|
| `items`(필수) | `id`·`label` 필수, `timestamp`·`description`·`tone` 선택 | — | 배열 순서가 곧 표시 순서 |
|
|
77
95
|
| `items[].dateTime` | string | — | timestamp의 원래 시각. Web time의 dateTime에 연결하며 표시 문구를 바꾸지 않는다. timestamp와 함께 사용 |
|
|
78
96
|
| `items[].emphasized` | boolean | false | 기록 배경의 은은한 강조. 진행 커서·선택 상태를 만들지 않는다 |
|
|
@@ -89,6 +107,10 @@ import { Timeline } from "@hjmds/react-native/data-display";
|
|
|
89
107
|
|
|
90
108
|
## 배치
|
|
91
109
|
|
|
110
|
+
기본 `journal`은 항목 사이 0, 위아래 `spacing.md` 16, 가로 안쪽 여백 0, dot 8, connector 1이다.
|
|
111
|
+
선택 배경·테두리는 없으며 펼친 설명 앞에는 `spacing.xs` 8(Web), 본문 기본 간격 `spacing.xxs` 4(Native)를 쓴다.
|
|
112
|
+
아래 표의 24/12/10 배치·중립 선택 면은 호환 `variant="record"`에 해당한다.
|
|
113
|
+
|
|
92
114
|
| 항목 | 값 | 근거 |
|
|
93
115
|
| --- | --- | --- |
|
|
94
116
|
| 크기 | 각 항목은 [레일 16][본문] 두 열. 레일은 지름 10의 dot과 다음 항목까지 이어지는 1px connector. 기록 본문은 누름 대상이 아니며 `renderActions`가 있으면 별도의 행동 열을 추가한다 | `timelineRecipe`, `.hjm-timeline__item`·`__dot`·`__connector` |
|
|
@@ -110,6 +132,8 @@ import { Timeline } from "@hjmds/react-native/data-display";
|
|
|
110
132
|
|
|
111
133
|
## 플랫폼 차이
|
|
112
134
|
|
|
135
|
+
아래 선택형 listbox/option 설명은 `variant="record"`이다. 기본 journal의 disclosure 의미는 위 기본 표현 절을 따른다.
|
|
136
|
+
|
|
113
137
|
| 항목 | Web | Native |
|
|
114
138
|
| --- | --- | --- |
|
|
115
139
|
| 구조 | `<ol>` / `<li>`, dot·connector `aria-hidden` | `View` 행, rail·본문은 접근성 트리에서 숨김 |
|
|
@@ -123,8 +123,8 @@ import { Container, Stack, Text } from "@hjmds/react/layout";
|
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
```tsx
|
|
126
|
-
// Native: 단일 펼침만. ContextMenu
|
|
127
|
-
// `NativeContextMenu`(`/context-menu-native`)
|
|
126
|
+
// Native: 단일 펼침만. ContextMenu는 `/context-menu`에 있고 Menubar는 Web 전용이다.
|
|
127
|
+
// OS 메뉴가 필요하면 선택형 `NativeContextMenu`(`/context-menu-native`)를 쓴다.
|
|
128
128
|
import { Collapsible } from "@hjmds/react-native/collapsible";
|
|
129
129
|
import { Text } from "@hjmds/react-native/primitives";
|
|
130
130
|
|
|
@@ -140,7 +140,7 @@ import { Text } from "@hjmds/react-native/primitives";
|
|
|
140
140
|
| 항목 | Web | Native |
|
|
141
141
|
| --- | --- | --- |
|
|
142
142
|
| `Collapsible` | `/collapsible`, 배치는 `layoutStyle`(또는 `className`) | `/collapsible`, 배치는 `layoutStyle`(`style`은 제거된 속성) |
|
|
143
|
-
| 대상 메뉴 | `ContextMenu`(stable) | `NativeContextMenu`(
|
|
143
|
+
| 대상 메뉴 | `ContextMenu`(stable) | `NativeContextMenu`(선택형 stable 어댑터) |
|
|
144
144
|
| `Menubar` | 있음 | 없음 |
|
|
145
145
|
|
|
146
146
|
## 함정
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hjmds/design-contracts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.50.0",
|
|
4
4
|
"description": "Renderer-neutral design contracts, tokens, recipes, and behaviors shared by HJM products.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -834,6 +834,11 @@
|
|
|
834
834
|
"react-native": "./dist/time-picker.js",
|
|
835
835
|
"import": "./dist/time-picker.js",
|
|
836
836
|
"default": "./dist/time-picker.js"
|
|
837
|
+
},
|
|
838
|
+
"./components/drawing-editor": {
|
|
839
|
+
"types": "./dist/drawing-editor.d.ts",
|
|
840
|
+
"import": "./dist/drawing-editor.js",
|
|
841
|
+
"default": "./dist/drawing-editor.js"
|
|
837
842
|
}
|
|
838
843
|
},
|
|
839
844
|
"files": [
|