@hjmds/design-contracts 1.34.0 → 1.35.1
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/anchor.d.ts +4 -1
- package/dist/anchor.d.ts.map +1 -1
- package/dist/anchor.js +3 -3
- package/dist/anchor.js.map +1 -1
- package/dist/base-recipes.d.ts +15 -1
- package/dist/base-recipes.d.ts.map +1 -1
- package/dist/base-recipes.js +14 -3
- package/dist/base-recipes.js.map +1 -1
- package/dist/behaviors.d.ts +22 -0
- package/dist/behaviors.d.ts.map +1 -1
- package/dist/behaviors.js +2 -0
- package/dist/behaviors.js.map +1 -1
- package/dist/calendar.d.ts +9 -7
- package/dist/calendar.d.ts.map +1 -1
- package/dist/calendar.js +31 -2
- package/dist/calendar.js.map +1 -1
- package/dist/card.d.ts +15 -1
- package/dist/card.d.ts.map +1 -1
- package/dist/card.js +14 -1
- package/dist/card.js.map +1 -1
- package/dist/carousel.d.ts +3 -0
- package/dist/carousel.d.ts.map +1 -1
- package/dist/carousel.js +10 -1
- package/dist/carousel.js.map +1 -1
- package/dist/catalog.d.ts +147 -17
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +9 -6
- package/dist/catalog.js.map +1 -1
- package/dist/colors.d.ts +1 -0
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +2 -0
- package/dist/colors.js.map +1 -1
- package/dist/component-recipes.d.ts +45 -11
- package/dist/component-recipes.d.ts.map +1 -1
- package/dist/component-recipes.js +35 -15
- package/dist/component-recipes.js.map +1 -1
- package/dist/component-references.d.ts +2 -2
- package/dist/component-references.js +1 -1
- package/dist/component-references.js.map +1 -1
- package/dist/design-profile.d.ts +14 -0
- package/dist/design-profile.d.ts.map +1 -1
- package/dist/design-profile.js +15 -0
- package/dist/design-profile.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/progress-recipe.d.ts +6 -0
- package/dist/progress-recipe.d.ts.map +1 -1
- package/dist/progress-recipe.js +15 -2
- package/dist/progress-recipe.js.map +1 -1
- package/dist/recipes.d.ts +2 -2
- package/dist/recipes.d.ts.map +1 -1
- package/dist/recipes.js +2 -2
- package/dist/recipes.js.map +1 -1
- package/dist/screen-patterns.d.ts +32 -2
- package/dist/screen-patterns.d.ts.map +1 -1
- package/dist/screen-patterns.js +26 -2
- package/dist/screen-patterns.js.map +1 -1
- package/dist/semantic-colors.d.ts +5 -0
- package/dist/semantic-colors.d.ts.map +1 -1
- package/dist/semantic-colors.js +2 -0
- package/dist/semantic-colors.js.map +1 -1
- package/dist/sheet.d.ts +15 -0
- package/dist/sheet.d.ts.map +1 -1
- package/dist/sheet.js +11 -0
- package/dist/sheet.js.map +1 -1
- package/dist/shortcut-rail.d.ts +20 -0
- package/dist/shortcut-rail.d.ts.map +1 -0
- package/dist/shortcut-rail.js +28 -0
- package/dist/shortcut-rail.js.map +1 -0
- package/dist/showcase.js +2 -2
- package/dist/showcase.js.map +1 -1
- package/dist/steps.d.ts +6 -4
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +3 -0
- package/dist/steps.js.map +1 -1
- package/dist/time-picker.d.ts +70 -0
- package/dist/time-picker.d.ts.map +1 -0
- package/dist/time-picker.js +51 -0
- package/dist/time-picker.js.map +1 -0
- package/dist/timeline.d.ts +13 -1
- package/dist/timeline.d.ts.map +1 -1
- package/dist/timeline.js +11 -1
- 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/calendar.md +19 -1
- package/docs/carousel.md +10 -0
- package/docs/collapsible.md +9 -0
- package/docs/consumer-policy.md +8 -12
- package/docs/design-profile.md +9 -0
- package/docs/expansion-roadmap.md +1 -1
- package/docs/generated/component-maturity.md +5 -4
- package/docs/generated/renderer-evidence.json +141 -16
- package/docs/generated/renderer-evidence.md +5 -3
- package/docs/generated/showcase-manifest.json +69 -7
- package/docs/optional-adapters.md +11 -0
- package/docs/stable-core.md +25 -0
- package/docs/steps.md +4 -0
- package/docs/theme-palette.md +2 -0
- package/docs/time-picker.md +22 -114
- package/docs/usage/README.md +9 -7
- package/docs/usage/SELECTION.md +44 -2
- package/docs/usage/components/accordion.md +4 -2
- package/docs/usage/components/alert-dialog.md +5 -0
- package/docs/usage/components/anchor.md +4 -1
- package/docs/usage/components/badge.md +7 -4
- package/docs/usage/components/bottom-cta.md +29 -4
- package/docs/usage/components/bottom-navigation.md +8 -0
- package/docs/usage/components/button.md +42 -2
- package/docs/usage/components/calendar.md +8 -1
- package/docs/usage/components/card.md +111 -7
- package/docs/usage/components/carousel.md +4 -1
- package/docs/usage/components/chat-screen.md +1 -1
- package/docs/usage/components/checkbox-group.md +33 -3
- package/docs/usage/components/checkbox.md +8 -2
- package/docs/usage/components/chip.md +5 -0
- package/docs/usage/components/collapsible.md +16 -1
- package/docs/usage/components/comment-thread-screen.md +12 -3
- package/docs/usage/components/composition-layout.md +6 -1
- package/docs/usage/components/conversation-row.md +2 -1
- package/docs/usage/components/data-table.md +10 -0
- package/docs/usage/components/description-list.md +1 -0
- package/docs/usage/components/field.md +8 -0
- package/docs/usage/components/icon-tile.md +29 -10
- package/docs/usage/components/image-choice-group.md +6 -0
- package/docs/usage/components/image.md +8 -1
- package/docs/usage/components/list-detail-screen.md +10 -4
- package/docs/usage/components/list-row.md +3 -0
- package/docs/usage/components/list.md +33 -1
- package/docs/usage/components/message-composer.md +2 -0
- package/docs/usage/components/notice.md +5 -1
- package/docs/usage/components/notification-row.md +19 -9
- package/docs/usage/components/onboarding-screen.md +3 -0
- package/docs/usage/components/page-indicator.md +12 -0
- package/docs/usage/components/profile-summary.md +16 -3
- package/docs/usage/components/progress.md +24 -0
- package/docs/usage/components/radio-group.md +45 -3
- package/docs/usage/components/radio.md +8 -2
- package/docs/usage/components/repeatable-field-group.md +1 -0
- package/docs/usage/components/screen-layout.md +46 -3
- package/docs/usage/components/search-screen.md +29 -1
- package/docs/usage/components/segmented-control.md +19 -3
- package/docs/usage/components/select.md +2 -0
- package/docs/usage/components/sheet.md +56 -3
- package/docs/usage/components/spinner.md +10 -0
- package/docs/usage/components/statistic.md +23 -0
- package/docs/usage/components/steps.md +11 -4
- package/docs/usage/components/switch.md +5 -0
- package/docs/usage/components/tabs.md +4 -0
- package/docs/usage/components/time-picker.md +88 -0
- package/docs/usage/components/timeline.md +19 -6
- package/docs/usage/components/top-bar.md +7 -0
- package/docs/usage/compositions/shortcut-rail.md +99 -0
- package/docs/usage/compositions/time-selection.md +5 -0
- package/package.json +17 -4
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
- 적용: 1.17.1
|
|
7
7
|
- 검토일: 2026-10-18
|
|
8
8
|
- 근거: [반복 화면 조합](../../screen-patterns.md), Web·Native `src/screens.tsx`·`src/screen-flows.tsx`; 기존 개별 지침을 새 규격으로 통합. `onSubmit`·`filtersOverflow`는 2026-10-06 사용자 요청("검색과 필터 있는 앱 서비스 따라해")의 검색 화면 개편에서 추가. 같은 날 사용자 위임 결정(권장안)으로 미리보기에만 있던 두 단계 검색 로직(`committedQuery`·`recentQueries`·`suggestedQueries`·`suggestions`·`resultSummary`·`appliedFilters`·`filterSheet`)과 `queryLabelVisibility`를, utilverse 적용 조사로 `searching`·`searchingLabel`을 추가([계약 결정 표](../../screen-patterns.md#searchscreen-두-단계-검색)). 1.13.0 utilverse 적용에서 드러난 결함으로 `hostGutter`와 확정 시 키보드 닫기(Web 결과 영역 포커스)를 추가(1.13.1 patch). `filtersRole`은 2026-10-18 choose-window 적용 감사에서 추가(검색어 때문인 0건의 복구 수단인 범위 필터가 숨겨져 제품이 `resultSummary`를 쓰지 못했다). 예제 스토리는 2026-10-06 사용자 승인으로 스토리북 배포([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). 스토리북 배포는 API 게시가 아니다(`적용` 참고)
|
|
9
|
-
- 스토리북: `배포/화면/검색/검색 결과와 필터`
|
|
9
|
+
- 스토리북: `배포/화면/검색/검색 결과와 필터` · `배포/컴포넌트/레이아웃/검색 화면`
|
|
10
10
|
|
|
11
11
|
## 언제 쓰나
|
|
12
12
|
|
|
@@ -17,6 +17,32 @@
|
|
|
17
17
|
SearchScreen이 맡고 제품은 데이터·요청·문구·아이콘만 넘긴다. 한 줄 가로 스크롤 필터 칩 줄은 `filtersOverflow="scroll"`로 만든다.
|
|
18
18
|
화면 전체 배치는 [검색 화면 지침](../screens/common-search.md)을 따른다.
|
|
19
19
|
|
|
20
|
+
### 시트와 가상 목록 연결 (미게시)
|
|
21
|
+
|
|
22
|
+
`embedded`의 기본값은 false다. true이면 부모 Sheet가 제목·닫기·진입 포커스·바깥 여백을 맡고,
|
|
23
|
+
SearchScreen은 같은 입력/필터/상태/결과 엔진을 CompositionLayout으로 렌더한다. 별도 화면 헤더를 만들지
|
|
24
|
+
않으며 결과만 입력 아래에서 스크롤한다. 부모의 고정된 높이 또는 flex 남은 높이를 제공해야 한다.
|
|
25
|
+
`header`·`exit`·헤더 `actions`는 부모에 연결하며 embedded 화면에 중복 공급하지 않는다.
|
|
26
|
+
|
|
27
|
+
Native에서 `scroll="content"`면 결과 host가 남은 높이를 채워 FlatList/SectionList를 직접 연결할 수 있다.
|
|
28
|
+
제품은 가상화 데이터·끝 도달을 연결하고 행과 구역은 HJM 공개 구성으로 공급한다.
|
|
29
|
+
FlatList/SectionList에는 `keyboardShouldPersistTaps="handled"`를 연결해 키보드가 떠 있어도 첫 탭이 결과 행동에 도달하게 한다. 임의 부모 ScrollView를
|
|
30
|
+
추가하지 않는다. 번뚝의 기존 본문 Stack이 FlatList에 높이를 주지 못해 기본 화면을 다시 조립했던 원인을 고쳤다.
|
|
31
|
+
|
|
32
|
+
TanStack Query처럼 요청·취소를 소유하는 캐시는 `onSearch={setRequestQuery}`로 HJM debounce 결과를
|
|
33
|
+
제품 query key에 연결할 수 있다. 같은 입력에 제품 debounce를 다시 붙이지 않는다. 최소 검색 길이·URL·
|
|
34
|
+
통계·현재 요청의 응답만 표시하는 판정은 제품이 유지하고, queryFn에는 캐시가 제공한 signal을 전달한다.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
// Web — Sheet가 제목/닫기/진입 포커스를 소유한다.
|
|
38
|
+
<Sheet open={open} onOpenChange={setOpen} title={t("search.title")} closeLabel={t("common.close")} size="full">
|
|
39
|
+
<SearchScreen embedded title={t("search.title")} query={query} onQueryChange={setQuery}
|
|
40
|
+
queryLabel={t("search.query")} queryClearLabel={t("common.clear")} onSearch={setRequestQuery}>
|
|
41
|
+
<Results items={queryData} />
|
|
42
|
+
</SearchScreen>
|
|
43
|
+
</Sheet>
|
|
44
|
+
```
|
|
45
|
+
|
|
20
46
|
## 쓰지 않을 때
|
|
21
47
|
|
|
22
48
|
| 상황 | 대신 쓸 것 |
|
|
@@ -229,3 +255,5 @@ import { SearchScreen } from "@hjmds/react-native/screen-flows";
|
|
|
229
255
|
### 고정 아이콘과 큰 글자
|
|
230
256
|
|
|
231
257
|
2026-10-06 최근 검색 삭제 기호가 큰 글자에서 잘린 재현에 따라 Native 내장 삭제·메뉴 기호는 고정 아이콘 틀의 크기를 유지한다. 주변 제목·라벨은 계속 확대한다. Chip의 체크와 Toast 닫기는 기존 비확대 경로를 유지하며 회귀 검사에 포함한다. 제품이 전달한 아이콘 슬롯은 제품이 같은 조건을 검증한다.
|
|
258
|
+
|
|
259
|
+
빈 검색 결과와 필터 해제·추천 검색어 묶음은 고정 검색·필터 영역 아래 보이는 본문 중앙에 배치한다. 지도 필터가 있어도 그 아래 남은 본문이 기준이다. 첫 조회 실패는 `state`/`stateAction`으로 연결하고, 기존 결과가 남은 갱신 실패는 `notice`로 알린다(2026-10-18 선택의창 실화면에서 상단에 붙은 빈 상태를 확인해 보완, 미게시).
|
|
@@ -12,6 +12,13 @@
|
|
|
12
12
|
|
|
13
13
|
2~4개의 짧은 보기 중 **항상 하나가 선택된** 전환에 쓴다. 같은 화면의 목록·기간·보기 방식을
|
|
14
14
|
바꾸는 필터(오늘/이번 주/이번 달, 목록/지도)가 전형이다. 선택하면 곧바로 화면이 바뀐다.
|
|
15
|
+
짧은 지표·시즌처럼 선택지가 더 많은 목록은 `presentation="pills" overflow="scroll"`로 한 줄에 둔다.
|
|
16
|
+
`items[].accessibilityLabel`은 축약된 화면 라벨 대신 읽을 전체 이름이다(Web radio의 aria-label, Native radio 이름).
|
|
17
|
+
생략하면 기존 label을 읽는다. 예: `{ value: "OPS", label: "OPS", accessibilityLabel: "출루율과 장타율의 합 OPS" }`.
|
|
18
|
+
|
|
19
|
+
2026-10-19 오늘야구 이관에서 지표 설명이 공통 레일의 이름에 전달되지 않던 공백을 보완했다.
|
|
20
|
+
필터 패널을 여는 행동은 선택 항목으로 섞지 않고 `actions`에 Button으로 공급한다. 이미 고른 시즌의
|
|
21
|
+
이전 연도 창도 다시 열 수 있어야 하며, 창을 여는 것만으로 선택 값이 바뀌면 안 된다.
|
|
15
22
|
|
|
16
23
|
## 쓰지 않을 때
|
|
17
24
|
|
|
@@ -72,6 +79,8 @@ import { SegmentedControl } from "@hjmds/react-native/inputs";
|
|
|
72
79
|
| `onValueChange` | Web `(value: string) => void` · Native `(value: Value) => void` | — | 다른 항목을 고를 때. `null`은 오지 않는다 |
|
|
73
80
|
| `label` | `string` | 필수 | 화면에 보이지 않는 접근성 이름. 보이는 제목은 바깥에 둔다 |
|
|
74
81
|
| `disabled` | `boolean` | `false` | 전체 비활성(Web은 fieldset 속성) |
|
|
82
|
+
| `overflow` | `wrap` · `scroll` | `wrap` | 미게시. pills는 기본 줄바꿈, scroll은 유한 가로 목록으로 배치한다. connected의 기존 내부 스크롤은 유지한다. 선택/포커스 항목을 최소 이동으로 노출한다 |
|
|
83
|
+
| `actions` | `ReactNode` | 없음 | 미게시. 스크롤 밖 끝 쪽 고정 행동. radio 그룹과 형제이며 선택 값에 포함하지 않는다. 도구는 IconButton으로 연결한다 |
|
|
75
84
|
| `layoutStyle` | 배치 전용 style 객체 | — | 바깥 배치 |
|
|
76
85
|
|
|
77
86
|
`connected`는 글자 크기 160% 이상(`stackAtFontScale`)에서 항목을 세로로 쌓는다. `pills`는 쌓지 않는다(`pills.largeTextLayout` `wrap`, 1.13.1 변경).
|
|
@@ -122,8 +131,8 @@ import { SegmentedControl } from "@hjmds/react-native/inputs";
|
|
|
122
131
|
기존 단일 선택 계약을 재사용하고 버튼마다 별도 selected 상태를 조립하는 대안은 제외했다.
|
|
123
132
|
|
|
124
133
|
- `presentation="pills"`: 카테고리·작성자·기간처럼 같은 목록의 범위를 좁힐 때 쓴다.
|
|
125
|
-
-
|
|
126
|
-
- 좌우
|
|
134
|
+
- 표면 높이·좌우 여백·글자는 같은 size의 Chip과 맞춘다. 터치 영역은 최소 `control.minTouchTarget` 44이며 안쪽 표면은 위아래 `spacing.xxs` 4만큼 들어간다. 2026-10-20 Utilverse 혼합 필터 행에서 작은 Chip36과 pill28의 불일치가 확인돼 공통 크기로 정렬했다(미게시). 누름 영역은 줄이지 않는다.
|
|
135
|
+
- 좌우 여백은 Chip과 같이 small12/medium16, 항목 사이 `spacing.xs` 8, 모서리 `radius.full`. 비선택은 `surfaceAlt`, 선택은 `content.body`/`canvas` 반전이다. 색은 제품 provider에서 따라온다.
|
|
127
136
|
- 항목은 내용 폭이며 좁아지면 줄바꿈한다. 큰 글자에서도 세로로 쌓지 않는다(`pills.largeTextLayout` `wrap`): 블록 안에서는 줄바꿈하고, 가로 스크롤 줄 안에서는 한 줄로 남아 스크롤된다. 라벨 높이만큼 항목도 늘어난다. 선택 상태(radio)와 포커스 이동(Web 화살표, Native 접근성 순서)은 배치와 관계없이 같다.
|
|
128
137
|
- 그룹 이름은 `label`, 하나의 선택은 `value`/`onValueChange`. 복수 조건은 ToggleGroup, 화면 이동은 Tabs/Navigation을 쓴다.
|
|
129
138
|
- 예제의 전체 선택값도 실제 항목으로 넣는다. 선택된 항목을 다시 눌러도 선택을 해제하지 않는다.
|
|
@@ -160,7 +169,7 @@ Web은 항목과 바깥 선택 영역의 크기를 함께 관찰한다. 2026-10-
|
|
|
160
169
|
- 모션 감소와 비활성 화면에서는 이동 효과를 중지한다. 동작 중인 입력·선택 값은 그대로다.
|
|
161
170
|
- 조작 가능 영역·글자는 움직이거나 확대하지 않는다. 새 사용 예제는 [선택 배경 이동](../compositions/selection-motion.md)이다.
|
|
162
171
|
|
|
163
|
-
2026-10-07
|
|
172
|
+
2026-10-07에는 Web 배경이 글자를 감싸도록 세로 padding과 pills.inset을 함께 적용했다. 2026-10-20에는 같은 원리를 유지하며 inset을4로 정렬하고 size별 Chip 높이를 표면의 최소값으로 사용한다.
|
|
164
173
|
|
|
165
174
|
### Text presentation (미게시, 1.23.0 이후)
|
|
166
175
|
|
|
@@ -168,3 +177,10 @@ Web은 항목과 바깥 선택 영역의 크기를 함께 관찰한다. 2026-10-
|
|
|
168
177
|
기본 strong이며 조용한 관계 목록은 regular다. 기존 `items/value/onValueChange`와 키보드·disabled 계약을 유지한다.
|
|
169
178
|
글자 탭의 radio 의미를 제품에서 재구현하던 문제를 없애기 위해 추가했다(2026-10-15 BurnTok 전사 이관).
|
|
170
179
|
선택 표시는 16×2, 목표 높이는 44, 항목 간격은 md이며 text 모드는 slide artwork를 사용하지 않는다.
|
|
180
|
+
|
|
181
|
+
## 가로 필터와 고정 행동
|
|
182
|
+
|
|
183
|
+
Spint 스팟 필터가 제품 ScrollView와 고정 추가 행을 재조립하던 공통 배치 공백을 `overflow="scroll"`과 `actions`로 보완했다(미게시). 제품은 값·목록·문구·추가 권한과 콜백을 소유하고 HJM이 줄 배치, 스크롤, 선택/포커스 항목 노출과 별도 행동의 위치를 소유한다. 이름이 긴 선택지를 탐색하는 폼은 여전히 Select를 쓰고, 화면 목록에 직접 적용하는 유한 필터가 이 rail의 대상이다.
|
|
184
|
+
|
|
185
|
+
<!-- usage-example: Web ../../../../../showcase/web/src/components/SegmentedControl.stories.tsx -->
|
|
186
|
+
<!-- usage-example: Native ../../../../../showcase/native/src/components/SegmentedControl.stories.tsx -->
|
|
@@ -148,3 +148,5 @@ Web popover Native sheet
|
|
|
148
148
|
| 낭독 보조 | 없음 | `readOnlyLabel`, `openHint`, `optionsAccessibilityLabel` |
|
|
149
149
|
| 키보드 | `loop`, typeahead(`locale`) | 해당 없음 |
|
|
150
150
|
| `description`·`error` 타입 | `ReactNode` | `string` |
|
|
151
|
+
|
|
152
|
+
Native는 목록을 열 때 선택 항목(없으면 첫 활성 항목)을 실제 행·섹션 높이로 측정해 보이는 목록 안으로 이동한다. 접근성 포커스만 이동하면 현재 시각이 화면 밖에 남았던 선택의창 점검을 반영했다(2026-10-18, 미게시). 최초 위치를 맞춘 뒤 사용자의 스크롤을 유지하며, 다시 열 때 새 선택 위치를 맞춘다. Web은 기존 활성 항목 `scrollIntoView` 동작을 유지한다.
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
| `Sheet` | 기본(모달) | `@hjmds/react`, `/overlays` | `@hjmds/react-native`, `/overlays` |
|
|
35
35
|
| `GestureSheet` | 확장(optional: 끌어서 snap·닫기) | — | `/sheet-gesture` |
|
|
36
36
|
| `GestureSheetProvider` | 동반(optional: GestureSheet host) | — | `/sheet-gesture` |
|
|
37
|
+
| `SheetPanel` | 확장(optional: 지도를 계속 조작하는 비모달 하단 패널, 미게시) | — | `/sheet-panel` |
|
|
37
38
|
| `GestureSheetInput` | 동반(GestureSheet 안 입력, 계약은 [Field](field.md)) | — | `/sheet-gesture` |
|
|
38
39
|
|
|
39
40
|
`/sheet-gesture`는 granular subpath로만 가져오며 optional peer `@gorhom/bottom-sheet` 5.2.14,
|
|
@@ -86,12 +87,13 @@ import { Sheet } from "@hjmds/react-native/overlays";
|
|
|
86
87
|
| `onDismissComplete` | `(detail: { reason }) => void` | — | 표면이 실제로 사라진 뒤 한 번. 다음 modal·화면 이동은 여기서 |
|
|
87
88
|
| `dismissPolicy` | `{ dismissible?, dismissWhileBusy?, outsideDismiss?, escapeOrBackDismiss?, swipeDismiss? }` | `dismissible` true · `dismissWhileBusy` false · `outsideDismiss` true(모든 위치, 미게시 변경, 이전 하단 false) · `escapeOrBackDismiss` true · `swipeDismiss` true(미게시 변경, 이전 false) | 닫기 허용 범위. `resolveSheetDismissPolicy(placement, override)` |
|
|
88
89
|
| `keyboardAvoidance` (Native) | `boolean` | `true`(미게시 변경, 이전 `false`) | 모달이 키보드 높이만큼 비킨다. 안쪽 `ScreenLayout`은 중복 처리하지 않는다 |
|
|
90
|
+
| `swipeDirection` | `"down"` | 하단은 항상 아래 방향, 옆은 생략 시 드래그 없음 | 미게시. 옆 읽기 패널도 아래로 내려 닫아야 할 때 설정한다. 같은 손잡이·거리/속도 기준·busy/닫기 정책·`swipe` 사유를 쓰며 `placement`의 크기/위치는 바꾸지 않는다. `showClose={false}`이면 손잡이가 유일한 화면 내 닫기 버튼이다 |
|
|
89
91
|
| `showClose` | `boolean` | 하단 `false` · 옆 `true`(미게시) | 머리의 × 표시. 하단 시트는 드래그로 닫는 것이 기본이라 끈다 |
|
|
90
92
|
| `busy` | `boolean` | `false` | 사용자 닫기를 막는다 |
|
|
91
93
|
| `title` · `closeLabel` | 문구 | 필수 | `title`은 화면에 보이지 않는다. Web은 `aria-labelledby`가 가리키는 시각 숨김 `h2`, Native는 대화상자 `accessibilityLabel`과 배치 밖 1pt 머리글이다(미게시). Native `title`이 element면 `accessibilityTitle`(string) 필수이며 element 자체는 그려지지 않는다. `closeLabel`은 손잡이·×·가림막 닫기의 이름 |
|
|
92
94
|
| `description` · `footer` | 노드(Native `description`은 `string`) | — | `footer`는 스크롤 밖 고정. 저장 행동은 여기 |
|
|
93
95
|
| `detents`(Web) · `activeDetent` · `onDetentChange` | `readonly ("medium" \| "large" \| "full")[]` · `(detent) => void` | — | 사용자가 높이를 바꿀 단계. `detentLabels: { expand, collapse }` 필수 |
|
|
94
|
-
| `
|
|
96
|
+
| `scrollable`(Native) | `boolean` | `false` | 긴 본문은 켜고 가상 목록은 중첩하지 않는다 |
|
|
95
97
|
| `safeAreaInsets`(Native) | `Partial<Insets>` | provider inset | — |
|
|
96
98
|
| `contentStyle`(Native) | 배치 key만 | — | `HjmCompositionStyleProp` 배치 전용 타입. 색·padding·높이 등 시각 key는 받지 않는다 |
|
|
97
99
|
|
|
@@ -105,6 +107,8 @@ import { Sheet } from "@hjmds/react-native/overlays";
|
|
|
105
107
|
|
|
106
108
|
## 배치
|
|
107
109
|
|
|
110
|
+
Native 스크롤 본문은 viewport 높이만큼 content를 채운다(미게시). 고정 크기 시트의 빈/오류/로딩 상태는 `CompositionLayout layoutStyle={{ flex: 1 }}`로 연결해 손잡이·머리·footer를 제외한 본문 중앙에 둔다. 목록이 길면 같은 본문에서 스크롤한다.
|
|
111
|
+
|
|
108
112
|
선택형 Native `GestureSheetInput`의 실제 keyboard-tracking host에도 제품 `tokens.fontFamily.ui`가 이어진다. optional library·폰트 설치와 실제 기기 검증은 제품이 맡는다.
|
|
109
113
|
|
|
110
114
|
선택형 GestureSheetInput은 Provider typography와 field recipe radius 역할을 읽고 textScale을 한 번 적용한다. optional keyboard-tracking host는 그대로다.
|
|
@@ -113,7 +117,7 @@ import { Sheet } from "@hjmds/react-native/overlays";
|
|
|
113
117
|
| --- | --- | --- |
|
|
114
118
|
| 크기 | 하단 시트 높이: `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` |
|
|
115
119
|
| 간격 | 두 플랫폼 같은 값: 좌우 `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.sm` 12) | `.hjm-sheet__*`, `sheetRecipe.content`·`body`·`footer` |
|
|
116
|
-
| 순서·정렬 | 손잡이(하단) → 머리(설명 + 닫기, 둘 다 없으면 그리지 않음) → 본문 → `footer`. 보이는 제목 줄은 없다(미게시). 머리 최소 높이 44(`control.minTouchTarget`), ×는 설명이 없어도 끝 쪽 같은 자리다. 기본 하단 시트는 머리가 없어 본문이 손잡이 영역 바로 아래 `body.gap` 16에서 시작한다. Web footer는 오른쪽 정렬 가로 줄 [보조][주]. Native footer는 세로 열이라 꽉 찬 폭 버튼을 주 행동 먼저 둔다. 하단 시트는 항상 위 가운데 36×4 손잡이(터치 최소
|
|
120
|
+
| 순서·정렬 | 손잡이(하단) → 머리(설명 + 닫기, 둘 다 없으면 그리지 않음) → 본문 → `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` |
|
|
117
121
|
| 고정·스크롤 | 본문만 스크롤, 머리·`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` |
|
|
118
122
|
| 좁은 폭·큰 글자 | 폭 < 640이면 하단 시트가 화면 폭을 채운다. Web footer는 줄을 바꾼다. 큰 글자로 내용이 길어지면 `auto`는 최대 90%에서 멈추고 본문이 스크롤된다(`full`은 위 safe area까지) | `.hjm-sheet[data-placement="bottom"]`, `maxHeightRatio` |
|
|
119
123
|
|
|
@@ -150,7 +154,6 @@ import { Sheet } from "@hjmds/react-native/overlays";
|
|
|
150
154
|
|
|
151
155
|
## 플랫폼 차이
|
|
152
156
|
|
|
153
|
-
Flutter 제품은 `showModalBottomSheet` 대신 `showHjmBottomSheet`(`hjm_flutter`)로 연다. 같은 기본값(드래그 닫기·손잡이 표시·배경 탭 닫기 끔·× 없음)을 적용하고 본문은 `HjmSheetLayout`을 쓴다(미게시). 2026-10-17의 제목 숨김·가림막 닫기 결정은 아직 Flutter에 반영하지 않았다.
|
|
154
157
|
|
|
155
158
|
| 항목 | Web | Native |
|
|
156
159
|
| --- | --- | --- |
|
|
@@ -190,3 +193,53 @@ Flutter 제품은 `showModalBottomSheet` 대신 `showHjmBottomSheet`(`hjm_flutte
|
|
|
190
193
|
- 디자인 프로필 상속(radius·floating shadow): 2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
|
|
191
194
|
- 하단 시트 드래그 닫기(필수): 2026-10-16 사용자 결정.
|
|
192
195
|
- 1.13.0 이하 고정 높이 Sheet 함정: 2026-10-06 utilverse 채팅 도구 선택, iPhone 17 Pro · iOS 26.5에서 확인했다.
|
|
196
|
+
|
|
197
|
+
### 옆 읽기 패널의 아래로 끌어 닫기 (미게시)
|
|
198
|
+
|
|
199
|
+
다에리 편지 상세가 옆 시트 안에 별도 손잡이/포인터 처리/본문 이동을 복제하던 경로를 없애기 위해 추가했다.
|
|
200
|
+
`placement="end" swipeDirection="down" showClose={false}`로 공통 손잡이를 사용한다. 문구·반환 경로와
|
|
201
|
+
미저장 확인은 제품의 `onOpenChange`에 남기고, 본문에 닫기 손잡이를 다시 만들지 않는다.
|
|
202
|
+
Web은 최초 포인터만 드래그를 소유하며 다른 손가락의 종료/취소는 무시한다. 소유 포인터의 취소·캡처 해제는
|
|
203
|
+
제자리로 돌아가고, 짧은 드래그 뒤 브라우저가 발생시키는 click은 닫기 명령으로 바뀌지 않는다.
|
|
204
|
+
키보드/스위치의 손잡이 클릭은 `close-action`, 충분한 드래그는 `swipe`로 같은 소유자에게 요청한다.
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
<Sheet placement="end" swipeDirection="down" showClose={false}
|
|
208
|
+
open={open} onOpenChange={handleChange} title={title} closeLabel={closeLabel}>
|
|
209
|
+
{readingContent}
|
|
210
|
+
</Sheet>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
양 Showcase의 Sheet `ReadingPanel`은 이 API의 실제 실행 예제다. Native도 같은 prop을 사용하며
|
|
214
|
+
진입/종료의 가로 이동과 사용자의 아래 드래그를 합성한다.
|
|
215
|
+
|
|
216
|
+
- 미게시 손잡이 터치 목표 수정: 다에리 실제 Web에서 44×20px이 측정됐고 Native도 bar4+상하8=20pt였다.
|
|
217
|
+
Native는 기존 hitSlop으로 실제 터치 영역은44pt였으나 배치/접근성 frame은20pt였다.
|
|
218
|
+
양 renderer의 손잡이 frame은 control.minTouchTarget44 이상으로 맞추고 Native hitSlop도 보존한다. bar36×4 그림은 그대로이며
|
|
219
|
+
닫기·drag·detent의 입력 영역만 공통 최소 목표를 충족한다.
|
|
220
|
+
|
|
221
|
+
2026-10-20 선택의창 장소 편집 실화면 수정(미게시): `footer`에 `BottomCTA`를 합성하면 시트가 바깥 여백·바탕·하단 safe area를 한 번만 소유하고 버튼은 본문과 같은 좌우 경계에 맞춘다. 앱에서 추가 padding이나 별도 하단 바를 덧대지 않는다. 자세한 계산은 [BottomCTA 배치](bottom-cta.md#배치)를 따른다.
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
## 지도와 함께 조작하는 하단 패널 — 미게시
|
|
225
|
+
|
|
226
|
+
2026-10-20 다에리의 지도 패널은 뒤 지도를 계속 조작해야 하므로 모달 Sheet나 GestureSheet로 대체할 수 없었다.
|
|
227
|
+
Native `SheetPanel`은 같은 sheet recipe의 표면·위쪽 모서리·손잡이·본문 여백을 사용하는 선택형 확장이다.
|
|
228
|
+
추가 canonical 컴포넌트가 아니며 Web은 기존 Card 기반 인라인 패널을 사용한다. Web에 없는 네이티브 지도 끌기를 흉내 내는 모달을 만들지 않는다.
|
|
229
|
+
`/sheet-panel`만 import하며 기존 Gesture Handler·Reanimated·Worklets peer가 필요하다. Gorhom이나 Modal provider는 필요 없다.
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
import { SheetPanel } from "@hjmds/react-native/sheet-panel";
|
|
233
|
+
|
|
234
|
+
<SheetPanel handleLabel="여정 패널" maximumHeight={availableHeight} height={availableHeight}
|
|
235
|
+
onHeightChange={setMapBottomInset}>
|
|
236
|
+
<Text>선택한 여정</Text>
|
|
237
|
+
</SheetPanel>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
- 배치는 손잡이(최소 44) → 본문이며 위 모서리만 `sheetRecipe.content.radius`로 둥글게 한다. 하단은 화면에 붙어 지도색이 새지 않게 각진다. 좌우 바깥 여백은 부모의 대칭 `layoutStyle`로 연결한다.
|
|
241
|
+
- `maximumHeight`는 부모의 지도/탭 영역을 제외한 가용 높이, `height`는 선택 상태 간 유지할 높이다. 본문만 스크롤하며 고정 높이에서 남은 영역을 채운다. 부모가 이미 safe area를 제외한 지도 높이를 주므로 safe area를 다시 더하지 않는다.
|
|
242
|
+
- 접으면 손잡이만 남는다. 손잡이 끌기와 본문 맨 위의 아래 방향 끌기가 같은 snap 정책을 쓴다. 취소되면 시작 위치로 돌아오며 높이가 바뀌어도 접힘 상태를 유지한다. 내용 안에서 시작한 스크롤은 중간에 맨 위에 도달해도 시트를 끌지 않는다.
|
|
243
|
+
- 손잡이를 눌러도 접기/펼치기가 가능하며 `accessibilityState.expanded`가 바뀐다. 접힌 본문은 보조기술에서 숨기고 뒤 지도는 숨기지 않는다. 포커스 격리·backdrop·Android back 가로채기는 없다.
|
|
244
|
+
- 제품의 가로 넘김은 `contentGesture`로 제공한다. 수직 동작/멀티터치/짧은 탭을 가로 넘김이 빼앗지 않도록 제품 gesture의 방향 기준을 지정한다. `handleActions`/`onHandleAction`으로 이전/다음 같은 도메인 접근성 행동을 추가할 수 있다. `overlay`는 제품 그림·소인 슬롯이다.
|
|
245
|
+
- 현재 호스트 검사와 소비 앱 타입/동작 검사 대상이며, 새 패널의 실제 iOS/Android 제스처·지도 동시 조작은 별도 기기 확인이 필요하다. 안정화·게시 완료를 뜻하지 않는다.
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
| 이름 | 역할 | Web | Native |
|
|
28
28
|
| --- | --- | --- | --- |
|
|
29
29
|
| `Spinner` | 기본 | `@hjmds/react`, `/feedback` | `@hjmds/react-native`, `/feedback` |
|
|
30
|
+
| `PendingContent` | 입력·높이를 보존하는 영역 대기(미게시) | `@hjmds/react`, `/feedback` | `@hjmds/react-native`, `/feedback` |
|
|
30
31
|
|
|
31
32
|
## 최소 사용 예
|
|
32
33
|
|
|
@@ -84,3 +85,12 @@ import { Spinner } from "@hjmds/react-native/feedback";
|
|
|
84
85
|
| tone | 있음 | 없음(항상 brand 색) |
|
|
85
86
|
| reduced motion | 회전 멈춤(CSS) | 별도 처리 없음(`ActivityIndicator` 그대로) |
|
|
86
87
|
| `style` | HTML 속성(`layoutStyle`과 합쳐지고 `layoutStyle`이 이김) | 제거된 속성 |
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
## 입력을 보존하는 대기 영역
|
|
91
|
+
|
|
92
|
+
`PendingContent`는 Spinner의 보조 구성이다. 다에리 로그인 카드가 영역 높이 측정·입력 숨김·로딩 중앙 배치를 제품에서 복제한 것이 추가 계기다. Web·Native의 `/feedback`과 root에서 제공하며 현재 개발 소스의 미게시 API다.
|
|
93
|
+
|
|
94
|
+
`pending`, 지역화한 `label`, `children`을 전달한다. 대기 중 자식은 언마운트하지 않고 마지막 준비 상태 높이를 유지하며 입력·접근성 탐색에서 제외한다. 한 Spinner를 그 영역의 가로·세로 중앙에 표시한다. 처리 결과·인증·취소는 제품이 소유한다. 화면 전체 인증은 기존 AuthScreenLayout의 pendingLabel을 사용하고, 개별 버튼은 Button.loading을 사용한다.
|
|
95
|
+
|
|
96
|
+
실행 예제는 Web·Native의 기존 Spinner 스토리 `PendingRegion`이다. 입력 후 대기 시작→취소로 값이 보존되는지 확인한다. 로컬 소스 예제이며 게시본 제공을 뜻하지 않는다.
|
|
@@ -82,10 +82,33 @@ import { Statistic } from "@hjmds/react-native/data-display";
|
|
|
82
82
|
| `composeAccessibilityLabel` | `(input: { contextLabel?, descriptor, valueText }) => string` | 기본 어순 | `descriptor`는 trend tone 기본값이 채워진 descriptor, `valueText`는 prefix·value·suffix를 이은 문자열 |
|
|
83
83
|
| `renderTrendMark` | `(props: { name: "trendUp" \| "trendDown" \| "trendFlat", color, size }) => ReactNode` | 내장 표시 | 추세 아이콘을 제품 아이콘으로 바꾼다. `color`는 Web `"currentColor"`, Native trend tone 색 |
|
|
84
84
|
| `renderValue`(Web) | `(value: string) => ReactNode` | — | 보이는 값만 바꾼다. 접근성 값은 descriptor 그대로 |
|
|
85
|
+
| `arrangement`(`StatisticGroup`, 미게시) | `grid` · `bar` | `grid` | bar는 짧은 수치들을 같은 폭 한 줄로 표시 |
|
|
86
|
+
| `leading` · `valueColor`(미게시) | ReactNode · 색 문자열 | 없음 | 수치 옆 장식과 제품 범주/시리즈 색 |
|
|
87
|
+
| `renderLeading` · `getValueColor`(`StatisticGroup`, 미게시) | callback | 없음 | 항목별 장식/색. 아래 한 줄 통계 바 참조 |
|
|
85
88
|
| `availableWidth`(Native `StatisticGroup`) | `number` | 측정 폭 | 열 수 계산에 쓸 폭 |
|
|
86
89
|
| `layoutStyle` | `HjmCompositionStyleProp` | — | 루트 배치. Web·Native 모두 |
|
|
87
90
|
| Native `style`·`labelStyle`·`valueStyle`·`affixStyle`·`trendStyle`·`hintStyle`, 그룹 `style`·`itemStyle` | 지원하지 않음 | — | 제거된 속성 — `layoutStyle` 또는 `density`·`presentation`. 현재 공개 props에서 제거되었다 |
|
|
88
91
|
|
|
92
|
+
## 한 줄 통계 바(미게시)
|
|
93
|
+
|
|
94
|
+
2026-10-18 번뚝의 피드 요약·이야기 상세가 각각 숫자 3칸의 순서·아이콘·세로 구분선을
|
|
95
|
+
다시 그리던 문제를 기존 StatisticGroup의 `arrangement="bar"`로 해결했다. 별도 통계 API를 만들지 않는다.
|
|
96
|
+
|
|
97
|
+
- 기본 `grid`는 기존 열 수/좁은 폭 동작을 유지한다. `bar`는 짧은 수치 몇 개를 한 행의 같은 폭 칸으로 둔다. 열 수는 항목 수이며 `descriptor.columns`는 grid에만 적용한다.
|
|
98
|
+
- bar는 아이콘+값 → 라벨 → 추세/힌트 순서로 가운데 정렬한다. 구분선은 논리적 시작 쪽에 그리므로 RTL도 같은 읽기 순서를 유지한다. 칸 좌우 `spacing.xs` 8, 값/라벨 간격 `spacing.xxs` 4다.
|
|
99
|
+
- `Statistic.leading`은 값 옆 장식 슬롯, `valueColor`는 제품이 소유한 범주/시리즈 색이다. 그룹은 `renderLeading(item, {color, size})`, `getValueColor(item)`로 공급한다. 아이콘 크기는 `glyph.sm`이며 값 색이 없으면 기본 본문색이다. 아이콘이 있는 경우 값 줄의 세로 중앙을 맞춘다.
|
|
100
|
+
- 아이콘은 읽기 대상이 아니다. 접근성 이름은 기존 descriptor의 label/value/trend/hint로 만든다. `0`도 값이며 숨기지 않는다.
|
|
101
|
+
- 바깥 입체 판은 Card, 이미 카드 안이면 Divider/Stack을 합성한다. 제품에서 칸 배치·숫자 굵기·구분선을 다시 그리지 않는다.
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
// Web
|
|
105
|
+
<StatisticGroup arrangement="bar" label={t("stats.summary")}
|
|
106
|
+
descriptor={{ items: stats }}
|
|
107
|
+
getValueColor={item => seriesColors[item.id]}
|
|
108
|
+
renderLeading={(item, { color, size }) => <SeriesIcon id={item.id} color={color} size={size} />} />
|
|
109
|
+
// Native: 같은 공개 props와 callback. descriptor.value는 제품에서 포맷한 문자열이다.
|
|
110
|
+
```
|
|
111
|
+
|
|
89
112
|
## 배치
|
|
90
113
|
|
|
91
114
|
Native 프레임의 모서리는 `statisticRecipe.presentations`의 역할을 Provider token에서 해석한다. 수치·locale·낭독 문구는 제품 데이터 그대로다.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
## 언제 쓰나
|
|
12
12
|
|
|
13
13
|
여러 단계로 된 **선형 흐름에서 지금 어디인지** 보여 줄 때 쓴다. 온보딩(환영 → 구단 → 알림 → 완료),
|
|
14
|
-
가입·주문 처리 단계가 여기에 속한다. 기본은 표시 전용이고, `onStepPress`를 주면 **이미 지난 단계만** 눌러 그 단계로
|
|
14
|
+
가입·주문 처리 단계가 여기에 속한다. 순서가 있는 설계 설명은 `navigationMode: "free"`로 자유롭게 탐색할 수 있다. 기본은 표시 전용이고, `onStepPress`를 주면 **이미 지난 단계만** 눌러 그 단계로
|
|
15
15
|
돌아갈 수 있다(1.31.0, 단계형 작성).
|
|
16
16
|
|
|
17
17
|
## 쓰지 않을 때
|
|
@@ -69,26 +69,27 @@ import { Steps } from "@hjmds/react-native/steps";
|
|
|
69
69
|
| prop | 값 | 기본값 | 설명 |
|
|
70
70
|
| --- | --- | --- | --- |
|
|
71
71
|
| `descriptor.currentStepId` | 단계 `id` | — (필수) | 상태는 단계별로 넘기지 않는다. 앞은 `complete`, 커서는 지정 상태, 뒤는 `pending`이 유도된다 |
|
|
72
|
+
| `descriptor.navigationMode` | `linear` · `free` | `linear` | `free`는 읽기 흐름에서 모든 단계 선택. 입력 검증이 필요한 흐름은 기본값 유지 |
|
|
72
73
|
| `descriptor.currentStepStatus` | `current` · `error` · `complete` | `current` | 커서 단계의 상태 |
|
|
73
74
|
| `descriptor.steps` | 단계 배열 | — (필수) | 2개 이상, `id`는 고유하고 앞뒤 공백이 없어야 한다. 어기면 `RangeError`/`TypeError` |
|
|
74
75
|
| `descriptor.steps[]` | `{ id, label, description? }` | — | — |
|
|
75
76
|
| `statusLabels` | `{ pending, current, complete, error }`(모두 `string`) | — (필수) | 상태를 읽는 문구 |
|
|
76
77
|
| `composeAccessibleName` | `(info: { position: number, total: number, label: string }) => string` | — (필수) | `position`은 1부터 |
|
|
77
78
|
| `renderMark` | `(status: StepStatus, position: number) => ReactNode` | `✓`·`!`·번호 | 원 안 표시를 바꾼다 |
|
|
78
|
-
| `onStepPress` | `(id) => void` | 없음 | 1.31.0. 커서 앞 단계(`revisitable`, 상태는 늘 `complete`)만 원·라벨 전체가 한 버튼이 되고 누르면 그 `id`를 넘긴다. 현재·다음 단계는 표시 전용으로
|
|
79
|
+
| `onStepPress` | `(id) => void` | 없음 | 1.31.0. 기본 linear에서 커서 앞 단계(`revisitable`, 상태는 늘 `complete`)만 원·라벨 전체가 한 버튼이 되고 누르면 그 `id`를 넘긴다. linear의 현재·다음 단계는 표시 전용으로 남는다. free에서는 현재·다음도 버튼이다. 버튼 이름은 `composeAccessibleName` 결과, 상태 문구는 설명(Web `aria-describedby`·Native `accessibilityHint`). 흐름이 잠긴 동안(제출 중)은 prop을 빼면 모두 표시 전용이 된다 |
|
|
79
80
|
| `layoutStyle` | `HjmCompositionStyleProp` | — | 루트 배치. Web·Native 모두 |
|
|
80
81
|
| `style`(Native) | 지원하지 않음 | — | 제거된 속성 — `layoutStyle`. 현재 공개 props에서 제거되었다 |
|
|
81
82
|
| `StepPlayer` `progress`·`playing` | `number`(0~1)·`boolean` | — (필수) | 호스트 소유 |
|
|
82
83
|
| `StepPlayer` `onPlayingChange`·`onReplay` | `(playing: boolean) => void`·`() => void` | — (필수) | 재생/일시정지·다시 보기 요청 |
|
|
83
84
|
| `StepPlayer` `labels` | `{ play, pause, replay, progress }` | — (필수) | — |
|
|
84
85
|
|
|
85
|
-
방향·variant
|
|
86
|
+
방향·variant 축은 없다. 항상 가로 한 줄이다. `descriptor.navigationMode`는 기본 `linear`이며 앞 단계만 이동한다. `free`는 검증을 건너뛰어도 되는 읽기 흐름에서 모든 단계 선택을 허용한다. 선택된 단계의 본문은 제품이 controlled state로 연결한다.
|
|
86
87
|
|
|
87
88
|
## 배치
|
|
88
89
|
|
|
89
90
|
| 항목 | 값 | 근거 |
|
|
90
91
|
| --- | --- | --- |
|
|
91
|
-
| 크기 |
|
|
92
|
+
| 크기 | Web은 연결선이 있는 앞 단계가 남은 폭을 균등하게 나누고 마지막 단계는 내용 폭(전체 폭/단계 수 이내)만 사용한다. 첫·마지막 표지는 양끝에 맞춘다. Native는 `flex: 1`. 원(indicator) 24(`glyph.md`), 연결선 1(`stroke.default`), 현재·오류 단계의 원 테두리 2(`stroke.strong`). 누를 수 있는 단계는 칸 전체가 버튼이고 최소 높이 44(`stepsRecipe.press.minTouchTarget`) | `stepsRecipe`, `styles.css` `.hjm-steps*`, `react-native/src/steps.tsx` |
|
|
92
93
|
| 간격 | 단계 사이·원과 글자 사이 `spacing.xs` 8(`stepsRecipe.gap`) | `stepsRecipe.gap` |
|
|
93
94
|
| 순서·정렬 | 흐름 화면의 맨 위(머리 아래, 본문 위)에 가로 한 줄. 화면 아래 행동 버튼과 떨어뜨리고, 같은 수준 화면 사이 이동(탭)으로 쓰지 않는다 | — |
|
|
94
95
|
| 고정·스크롤 | — | — |
|
|
@@ -115,3 +116,9 @@ import { Steps } from "@hjmds/react-native/steps";
|
|
|
115
116
|
## 근거
|
|
116
117
|
|
|
117
118
|
- `onStepPress`(1.31.0): 2026-10-18 spint 작성(색 → 이모지 → 글)이 지난 단계를 눌러 돌아가려고 단계 레일 전체를 PressableScale로 직접 그렸다. 계약은 "필요해지면 추가"로 clickable을 미뤄 두었고([계약](../../steps.md#공개한-축--배제한-축)), 앞으로 건너뛰기는 검증을 지나치므로 커서 앞 단계만 연다.
|
|
119
|
+
|
|
120
|
+
2026-10-19 포트폴리오 폭 확인: Web 마지막 단계에 연결선 없는 균등 칸이 남아 표지가 본문 오른쪽 끝보다 한 칸 안쪽에 보였다. Web renderer가 단계 수를 전달하고 끝 칸만 내용 폭으로 배치하도록 수정했다. 제품별 CSS 보정이나 공개 prop 추가는 하지 않는다.
|
|
121
|
+
|
|
122
|
+
2026-10-19 포트폴리오: 사용자가 단계 클릭 시 해당 설명만 표시하도록 요청했다. `navigationMode: "free"`를 명시한 읽기 흐름에 한해 모든 단계가 버튼이 된다. 기본 linear와 handler 생략 시 표시 전용 동작은 유지한다. Web 현재 버튼은 aria-current, Native는 selected를 제공한다.
|
|
123
|
+
|
|
124
|
+
2026-10-19 스핀트 실제 화면 피드백: 수평 행 gap으로 끊기던 연결선을 없애고 마지막 표지 앞의 연결 구간을 유지한다. Native도 마지막 열에 균등 여분 폭을 남기지 않아 첫·마지막 표지가 본문 양끝에 맞는다. 내부 문구 간격과 기본 이동 계약은 유지한다.
|
|
@@ -111,6 +111,11 @@ presentation="row" 큰 글자(≥1.6)
|
|
|
111
111
|
| 꺼짐 상태 hairline | 그림(track·thumb 모두 1px inset) | 그리지 않음(RN `Switch`에 테두리 hook이 없음, `*Border` 슬롯은 Web 전용) |
|
|
112
112
|
| iOS 크기 | 해당 없음 | `UISwitch` 고유 크기를 따른다(Android는 recipe 크기) |
|
|
113
113
|
|
|
114
|
+
Native renderer를 브라우저 개발 미리보기에서 실행하면 행 `Pressable`이 단일 switch와
|
|
115
|
+
`aria-checked`·Space 키 동작을 소유하고, 트랙·thumb은 recipe로 그린 장식 View다.
|
|
116
|
+
RN Web의 `Switch`는 `accessible={false}`여도 별도 focusable input을 만들기 때문에
|
|
117
|
+
2026-10-19 확인된 이중 제어와 선택 상태 불일치를 없앴다. iOS·Android의 RN Switch 경로는 유지한다.
|
|
118
|
+
|
|
114
119
|
## 함정
|
|
115
120
|
|
|
116
121
|
- Native는 옛 `value`/`defaultValue`/`onValueChange`를 받으면 실행 중 `TypeError`를 던진다.
|
|
@@ -95,6 +95,10 @@ import { Tabs } from "@hjmds/react-native/navigation";
|
|
|
95
95
|
| 고정·스크롤 | 기본 `overflow="scroll"`로 탭 목록이 가로 스크롤한다. 목록은 스크롤 영역 안에서 고정되지 않으며 상단에 붙여야 하면 제품이 sticky 영역에 넣는다 | `tabsRecipe.overflow`, `styles.css` `.hjm-tabs__list` |
|
|
96
96
|
| 좁은 폭·큰 글자 | 라벨은 줄바꿈하지 않는다(`white-space: nowrap`). 좁은 폭·큰 글자에서는 가로 스크롤로 받는다 | `styles.css` `.hjm-tabs__tab` |
|
|
97
97
|
|
|
98
|
+
Web의 가로 `overflow="scroll"`은 선택 변경뿐 아니라 목록 폭·라벨 크기 변경 후에도 선택된 탭을 목록 안으로 드러낸다.
|
|
99
|
+
포트폴리오의 데스크톱→모바일 폭 변경에서 선택된 발전 이력 탭이 가려진 사례(2026-10-20)를 수정한 동작이다.
|
|
100
|
+
페이지의 세로 위치와 선택값은 바꾸지 않으며, 사용자가 다른 탭을 찾아 목록을 직접 스크롤하는 동작은 유지한다.
|
|
101
|
+
|
|
98
102
|
```text
|
|
99
103
|
┌────────────────────────────────────┐
|
|
100
104
|
│ TopBar │
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# TimePicker
|
|
2
|
+
|
|
3
|
+
- 단계: 컴포넌트
|
|
4
|
+
- 상태: 배포
|
|
5
|
+
- 지원: Web · Native
|
|
6
|
+
- 적용: 미게시(1.34.0 이후)
|
|
7
|
+
- 검토일: 2026-10-19
|
|
8
|
+
- 근거: [TimePicker](../../time-picker.md), `src/time-picker.ts`의 `timePickerRecipe`, 양 renderer `src/time-picker.tsx`
|
|
9
|
+
- 스토리북: `배포/컴포넌트/입력/시각 선택`
|
|
10
|
+
|
|
11
|
+
## 언제 쓰나
|
|
12
|
+
|
|
13
|
+
하루 중 시각 하나를 시·분 두 열에서 고를 때 쓴다. 기본 `field`는 하나의 필드를 눌러
|
|
14
|
+
Web Popover / Native Sheet를 열고 명시적으로 확정한다. 기존 날짜 시트 안에서는 `inline`을 쓴다.
|
|
15
|
+
현재 checkout의 개발 소스에서 제공하며 npm 게시 버전은 아직 없다.
|
|
16
|
+
|
|
17
|
+
## 쓰지 않을 때
|
|
18
|
+
|
|
19
|
+
| 상황 | 대신 쓸 것 |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| 날짜 선택 | Calendar / DatePicker |
|
|
22
|
+
| 경과 시간 입력 | 제품의 duration 입력 |
|
|
23
|
+
| 시간대·서버 예약 계산 | 제품 도메인 로직 |
|
|
24
|
+
|
|
25
|
+
## 공개 이름과 import
|
|
26
|
+
|
|
27
|
+
| 이름 | 역할 | Web | Native |
|
|
28
|
+
| --- | --- | --- | --- |
|
|
29
|
+
| `TimePicker` | 기본 | `@hjmds/react/time-picker` 또는 root | `@hjmds/react-native/time-picker` 또는 root |
|
|
30
|
+
|
|
31
|
+
필수: `value: string | null`, `onValueChange(value: string | null)`,
|
|
32
|
+
`labels: { label, hour, minute, placeholder, confirm, cancel }`.
|
|
33
|
+
선택: `presentation`(`field` 기본/`inline`), `minuteStep`(1 기본), `isTimeUnavailable`,
|
|
34
|
+
`disabled`, `readOnly`, `description`, `error`, 외부 배치용 `layoutStyle`.
|
|
35
|
+
Native `safeAreaInsets`는 단독 Sheet에 전달한다.
|
|
36
|
+
|
|
37
|
+
## 최소 사용 예
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// Native
|
|
41
|
+
import { TimePicker } from '@hjmds/react-native/time-picker';
|
|
42
|
+
<TimePicker presentation="inline" value={time} onValueChange={setTime}
|
|
43
|
+
labels={{ label: '시간', hour: '시', minute: '분', placeholder: '시간 선택', confirm: '선택 완료', cancel: '취소' }} />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
// Web
|
|
48
|
+
import { TimePicker } from '@hjmds/react/time-picker';
|
|
49
|
+
<TimePicker value={time} onValueChange={setTime}
|
|
50
|
+
labels={{ label: '시간', hour: '시', minute: '분', placeholder: '시간 선택', confirm: '선택 완료', cancel: '취소' }} />
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
실행되는 원본은 [Web preview](https://github.com/jim1286/hjm-design-system/blob/main/showcase/web/src/components/preview-registry.tsx)의 `TimePickerPreview`,
|
|
54
|
+
[Native preview](https://github.com/jim1286/hjm-design-system/blob/main/showcase/native/src/component-examples.tsx)의 `TimePickerExample`이다.
|
|
55
|
+
|
|
56
|
+
## 배치
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
시간 필드 → 하나의 Popover / Sheet
|
|
60
|
+
헤더: 제목 · 닫기
|
|
61
|
+
선택한 시각 14 : 30
|
|
62
|
+
시 분
|
|
63
|
+
13 29
|
|
64
|
+
[14] [30]
|
|
65
|
+
15 31
|
|
66
|
+
[ 선택 완료 ]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
| 항목 | 값 | 근거 |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| 크기 | 요약 숫자 `typography.titleLarge` 20/28(2026-10-20 모바일 큰 글씨 지양 기준 반영·미게시), 행 44, 열 높이 220, Web 패널 최대 폭 304 | timePickerRecipe |
|
|
72
|
+
| 순서·정렬 | 요약 숫자 중앙 → 같은 폭 시·분 열 → field 확인 버튼. 숫자는 LTR·tabular-nums | 양 renderer |
|
|
73
|
+
| 간격 | 열 사이 spacing.sm(12), 영역 사이 spacing.md(16) | timePickerRecipe |
|
|
74
|
+
| 고정·스크롤 | 제목·확인은 공통 overlay 영역, 시·분 목록만 세로 스크롤 | Popover / Sheet / TimePicker |
|
|
75
|
+
| 좁은 폭·큰 글자 | 좁은 폭은 두 열을 같은 폭으로 유지. 최대 글자 조건은 사용자 지침으로 범위 제외 | 포트폴리오 AGENTS.md |
|
|
76
|
+
| 선택 표시 | radius.md, surfaceAccent 배경·contentBrand 글자 | 공통 recipe·semantic palette |
|
|
77
|
+
| 설명·오류 | 입력 아래 description/error. 오류는 보조기술에도 알림 | 양 renderer |
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
시트 안 `inline`에는 별도 확인 버튼이나 중첩 Sheet가 생기지 않는다. 헤더·바깥 틀·safe area·초점 복귀는 공통 overlay가 소유한다.
|
|
81
|
+
|
|
82
|
+
## 꼭 지킬 것
|
|
83
|
+
|
|
84
|
+
- `HH:mm | null`을 사용한다. `00:00`도 유효하며 날짜·시간대 변환은 제품이 담당한다.
|
|
85
|
+
- `minuteStep`은 60의 양의 정수 약수. 기존 값을 자동 반올림하거나 불가한 분을 몰래 교체하지 않는다.
|
|
86
|
+
- 빈 값은 `--:--`. 두 부분을 고르기 전에는 확정하지 않는다. 닫기는 초안을 취소한다.
|
|
87
|
+
- inline은 완전하고 사용 가능한 값만 문자열, 미완성·불가한 조합은 null을 전달한다. 바깥 확인 버튼은 null을 확정하지 않는다.
|
|
88
|
+
- 시간 선택의 공통 배치·초안·취소·키보드 처리를 앱에서 다시 조립하지 않는다. 상세 동작은 [계약](../../time-picker.md)을 따른다.
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
| 항목을 눌러 이동·선택 | [List](list.md), [ListRow](list-row.md) |
|
|
22
22
|
| 항목이 하나도 없음 | Timeline을 마운트하지 않고 [EmptyState](empty-state.md) |
|
|
23
23
|
| 과거 기록을 더 불러옴 | Timeline 아래에 [LoadMore](load-more.md)를 합성 |
|
|
24
|
-
| 항목별 짧은 배지 |
|
|
24
|
+
| 항목별 짧은 배지 | `renderMetadata` 슬롯에 제품의 [Badge](badge.md) 또는 [Tag](tag.md)를 연결 |
|
|
25
25
|
|
|
26
26
|
## 공개 이름과 import
|
|
27
27
|
|
|
@@ -72,8 +72,13 @@ import { Timeline } from "@hjmds/react-native/data-display";
|
|
|
72
72
|
| prop | 값 | 기본값 | 설명 |
|
|
73
73
|
| --- | --- | --- | --- |
|
|
74
74
|
| `items`(필수) | `id`·`label` 필수, `timestamp`·`description`·`tone` 선택 | — | 배열 순서가 곧 표시 순서 |
|
|
75
|
+
| `items[].dateTime` | string | — | timestamp의 원래 시각. Web time의 dateTime에 연결하며 표시 문구를 바꾸지 않는다. timestamp와 함께 사용 |
|
|
76
|
+
| `items[].emphasized` | boolean | false | 기록 배경의 은은한 강조. 진행 커서·선택 상태를 만들지 않는다 |
|
|
75
77
|
| `items[].tone` | `neutral` · `info` · `success` · `attention` | `neutral` | `warning`·`danger`는 없다 |
|
|
76
78
|
| `composeAccessibleName`(필수) | `(info: { position: number, total: number, label: string }) => string` | — | position은 1부터 |
|
|
79
|
+
| `renderMetadata` | `(item: TimelineItemDescriptor) => ReactNode` | — | 제목 줄의 수동적 배지·메타데이터 |
|
|
80
|
+
| `renderActions` | `(item: TimelineItemDescriptor) => ReactNode` | — | 기록과 독립된 버튼. 행 전체를 누름 대상으로 만들지 않는다 |
|
|
81
|
+
| `renderList`(Native) | `({ items, renderItem, separator }) => ReactNode` | — | FlatList 등 가상화 host. 전달받은 renderItem과 separator를 사용하며 레일·본문을 다시 그리지 않는다 |
|
|
77
82
|
| `layoutStyle` | `HjmCompositionStyleProp` | — | 루트 배치. Web·Native 모두 |
|
|
78
83
|
| `style`(Native) | 지원하지 않음 | — | 제거된 속성 — `layoutStyle`. 현재 공개 props에서 제거되었다 |
|
|
79
84
|
| 나머지 | Web `<ol>` 속성, Native `ViewProps`(`style` 제외) | — | — |
|
|
@@ -82,11 +87,11 @@ import { Timeline } from "@hjmds/react-native/data-display";
|
|
|
82
87
|
|
|
83
88
|
| 항목 | 값 | 근거 |
|
|
84
89
|
| --- | --- | --- |
|
|
85
|
-
| 크기 | 각 항목은 [레일 16][본문] 두 열. 레일은 지름 10의 dot과 다음 항목까지 이어지는 1px connector.
|
|
86
|
-
| 간격 | 항목 사이 `spacing.
|
|
87
|
-
| 순서·정렬 | 본문은 label·
|
|
90
|
+
| 크기 | 각 항목은 [레일 16][본문] 두 열. 레일은 지름 10의 dot과 다음 항목까지 이어지는 1px connector. 기록 본문은 누름 대상이 아니며 `renderActions`가 있으면 별도의 행동 열을 추가한다 | `timelineRecipe`, `.hjm-timeline__item`·`__dot`·`__connector` |
|
|
91
|
+
| 간격 | 항목 사이 `spacing.lg` 24, 각 항목 안쪽 `spacing.sm` 12, 레일과 본문 열 간격 `spacing.sm` 12, 본문 줄 간격 `spacing.xxs` 4 | `timelineRecipe.gap`, `.hjm-timeline*` |
|
|
92
|
+
| 순서·정렬 | 본문은 label·metadata → description → timestamp 순서다. dot은 label 첫 줄의 가운데에, 독립 행동은 기록 본문 높이의 가운데에 둔다. 강조 배경은 명시적 emphasized에만 적용한다 | `.hjm-timeline__heading`·`__dot`·`__timestamp`, Native `Timeline` |
|
|
88
93
|
| 고정·스크롤 | 본문 스크롤 영역 안의 한 섹션으로 폭을 꽉 채운다. 더 불러오기는 Timeline 아래에 [LoadMore](load-more.md) | — |
|
|
89
|
-
| 좁은 폭·큰 글자 |
|
|
94
|
+
| 좁은 폭·큰 글자 | 제목과 metadata는 좁으면 줄바꿈하고 timestamp는 별도 줄에 둔다 | `.hjm-timeline__heading`·`__label` |
|
|
90
95
|
|
|
91
96
|
## 꼭 지킬 것
|
|
92
97
|
|
|
@@ -101,9 +106,17 @@ import { Timeline } from "@hjmds/react-native/data-display";
|
|
|
101
106
|
| 항목 | Web | Native |
|
|
102
107
|
| --- | --- | --- |
|
|
103
108
|
| 구조 | `<ol>` / `<li>`, dot·connector `aria-hidden` | `View` 행, rail·본문은 접근성 트리에서 숨김 |
|
|
104
|
-
| 항목 접근 이름 | `<li aria-label={accessibleName}>` | `accessibleName,
|
|
109
|
+
| 항목 접근 이름 | `<li aria-label={accessibleName}>` | `accessibleName, description, timestamp`을 이어 붙인 `accessibilityLabel` |
|
|
105
110
|
| ref | `HTMLOListElement`로 전달 | 없음(함수 컴포넌트) |
|
|
106
111
|
|
|
107
112
|
## 근거
|
|
108
113
|
|
|
109
114
|
- 첫 줄 가운데: 2026-10-17 정렬 실측(Web 402). dot 396 · label 397 · timestamp 398.5로 어긋났다(dot은 4px 고정 여백, timestamp는 작은 글자가 기준선을 공유). Native는 dot이 맨 위에 붙었다. 수정 후 Web 402·1280에서 세 요소가 397/397/397, 377/377/377로 측정됐다.
|
|
115
|
+
|
|
116
|
+
## 개발 소스 보완 (미게시)
|
|
117
|
+
|
|
118
|
+
2026-10-19 번뚝의 버전 기록이 레일·본문·되돌리기 버튼을 별도로 재구현하던 경로를 이관하기 위해 `renderMetadata`·`renderActions`를 추가했다. Native는 버튼을 기록의 접근성 묶음 밖 독립 타깃으로 유지한다. 긴 기록의 기존 가상화를 보존하기 위해 `renderList`에 검증된 전체 descriptor와 공통 행 renderer·간격을 전달한다. 제품은 host의 높이·스크롤·데이터 연결만 담당한다. 설치 패키지에 게시된 API라는 뜻은 아니다.
|
|
119
|
+
|
|
120
|
+
2026-10-19 사용자가 비교 시안 A 기록형을 선택했다. 양 renderer에 기록별 emphasized, 설명 아래 시간, 24px 기록 간격·12px 안쪽 여백과 이어지는 레일을 반영했다. 현재 버전의 의미·문구·시간 포맷은 제품이 연결하며 다른 기록을 앞으로 진행할 단계로 해석하지 않는다.
|
|
121
|
+
|
|
122
|
+
2026-10-19 다에리 여정 일지의 지도 연결 기록은 Timeline의 레일·본문·시각과 독립적인 renderActions 지도 선택 Button을 사용한다. 지도 선택은 해당 Button만 제어하며 Timeline 항목을 진행 커서나 선택 행으로 바꾸지 않는다. 원래 이벤트 시각을 보존하도록 선택적 items[].dateTime을 추가했다(Web time.dateTime; Native 표시 문구는 기존 timestamp). dateTime은 timestamp와 함께 사용한다. 이 변경도 개발 소스이며 미게시다.
|
|
@@ -136,3 +136,10 @@ NavigationBar의 Native 프레임 모서리는 Provider의 `tokens.radius.xl`을
|
|
|
136
136
|
## 근거
|
|
137
137
|
|
|
138
138
|
- NavigationBar 양끝 여백: 2026-10-17 정렬 실측(Web 1280). 브랜드에 `spacing.xs` 8이 더해져 시작 21, 끝 행동 13으로 비대칭이었다. Native 브랜드에는 추가 inset이 없었다. Web 브랜드 inset을 없앤 뒤 양끝 13/13으로 측정됐다.
|
|
139
|
+
|
|
140
|
+
### 장면과 배경 연결 (checkout 변경·미게시)
|
|
141
|
+
|
|
142
|
+
`surface="transparent"`는 Web/Native에서 상단 바의 배경만 투명하게 한다. 기본값 `default`는 기존 canvas 배경이다.
|
|
143
|
+
상태바와 본문 장면 사이에 별도 색 띠가 생기는 경우 부모가 같은 장면의 윗색/배경을 제공하고 `ScreenLayout.header`에 연결한다.
|
|
144
|
+
바의 배치·높이·행동·터치 영역은 HJM을 유지한다. 제품별 배경색을 layoutStyle로 덮지 않는다.
|
|
145
|
+
다에리 둥지의 하늘색 상태바와 장면 사이에 짙은 헤더 띠가 생긴 2026-10-20 사용자 지적을 반영했다.
|