@hjmds/design-contracts 1.13.1 → 1.15.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/agreement.d.ts +7 -1
- package/dist/agreement.d.ts.map +1 -1
- package/dist/agreement.js +14 -3
- package/dist/agreement.js.map +1 -1
- package/dist/behaviors.d.ts +1 -1
- package/dist/catalog.d.ts +4 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/content-transition.d.ts +17 -0
- package/dist/content-transition.d.ts.map +1 -1
- package/dist/content-transition.js +21 -0
- package/dist/content-transition.js.map +1 -1
- package/dist/date-entry.d.ts +71 -0
- package/dist/date-entry.d.ts.map +1 -0
- package/dist/date-entry.js +78 -0
- package/dist/date-entry.js.map +1 -0
- package/dist/design-profile-layout.d.ts +11 -0
- package/dist/design-profile-layout.d.ts.map +1 -0
- package/dist/design-profile-layout.js +18 -0
- package/dist/design-profile-layout.js.map +1 -0
- package/dist/design-profile.d.ts +89 -0
- package/dist/design-profile.d.ts.map +1 -0
- package/dist/design-profile.js +262 -0
- package/dist/design-profile.js.map +1 -0
- package/dist/design-system-provider.d.ts +6 -0
- package/dist/design-system-provider.d.ts.map +1 -1
- package/dist/design-system-provider.js +4 -2
- package/dist/design-system-provider.js.map +1 -1
- package/dist/document-resource.d.ts +104 -0
- package/dist/document-resource.d.ts.map +1 -0
- package/dist/document-resource.js +77 -0
- package/dist/document-resource.js.map +1 -0
- package/dist/effect-surface.d.ts +6 -1
- package/dist/effect-surface.d.ts.map +1 -1
- package/dist/effect-surface.js +5 -2
- package/dist/effect-surface.js.map +1 -1
- package/dist/field-group.d.ts +47 -0
- package/dist/field-group.d.ts.map +1 -0
- package/dist/field-group.js +92 -0
- package/dist/field-group.js.map +1 -0
- package/dist/gooey-navigation.d.ts +19 -1
- package/dist/gooey-navigation.d.ts.map +1 -1
- package/dist/gooey-navigation.js +37 -2
- package/dist/gooey-navigation.js.map +1 -1
- package/dist/image.d.ts +17 -0
- package/dist/image.d.ts.map +1 -1
- package/dist/image.js +19 -0
- package/dist/image.js.map +1 -1
- package/dist/internal/effect-noise.d.ts +2 -0
- package/dist/internal/effect-noise.d.ts.map +1 -0
- package/dist/internal/effect-noise.js +4 -0
- package/dist/internal/effect-noise.js.map +1 -0
- package/dist/palette-contrast.d.ts +6 -0
- package/dist/palette-contrast.d.ts.map +1 -1
- package/dist/palette-contrast.js +17 -0
- package/dist/palette-contrast.js.map +1 -1
- package/dist/progressive-blur.d.ts +32 -0
- package/dist/progressive-blur.d.ts.map +1 -0
- package/dist/progressive-blur.js +28 -0
- package/dist/progressive-blur.js.map +1 -0
- package/dist/reference-controls.d.ts +32 -0
- package/dist/reference-controls.d.ts.map +1 -0
- package/dist/reference-controls.js +28 -0
- package/dist/reference-controls.js.map +1 -0
- package/dist/screen-patterns.d.ts +16 -1
- package/dist/screen-patterns.d.ts.map +1 -1
- package/dist/screen-patterns.js +4 -0
- package/dist/screen-patterns.js.map +1 -1
- package/dist/scroll-progress.d.ts +7 -1
- package/dist/scroll-progress.d.ts.map +1 -1
- package/dist/scroll-progress.js +21 -2
- package/dist/scroll-progress.js.map +1 -1
- package/dist/text-annotation.d.ts +43 -0
- package/dist/text-annotation.d.ts.map +1 -0
- package/dist/text-annotation.js +137 -0
- package/dist/text-annotation.js.map +1 -0
- package/dist/toast-liquid.d.ts +3 -1
- package/dist/toast-liquid.d.ts.map +1 -1
- package/dist/toast-liquid.js +6 -2
- package/dist/toast-liquid.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/agreement.md +14 -0
- package/docs/asset.md +7 -0
- package/docs/brand-boundary.md +14 -5
- package/docs/code-block.md +12 -1
- package/docs/collapsible.md +6 -0
- package/docs/design-profile.md +263 -0
- package/docs/design-system-provider.md +7 -0
- package/docs/dialog.md +20 -1
- package/docs/effect-surface.md +19 -3
- package/docs/generated/component-maturity.md +1 -1
- package/docs/generated/renderer-evidence.json +3 -3
- package/docs/generated/renderer-evidence.md +1 -1
- package/docs/generated/showcase-manifest.json +1 -1
- package/docs/gooey-navigation.md +37 -6
- package/docs/heading.md +15 -0
- package/docs/image.md +17 -0
- package/docs/optional-adapters.md +25 -0
- package/docs/popover.md +15 -0
- package/docs/rating.md +6 -1
- package/docs/reference-controls.md +40 -0
- package/docs/task-list.md +15 -1
- package/docs/text-annotation.md +85 -0
- package/docs/theming.md +18 -5
- package/docs/usage/README.md +23 -1
- package/docs/usage/components/activity-heatmap.md +3 -1
- package/docs/usage/components/agreement.md +15 -3
- package/docs/usage/components/alert-dialog.md +16 -1
- package/docs/usage/components/asset.md +9 -2
- package/docs/usage/components/avatar.md +33 -1
- package/docs/usage/components/badge.md +3 -1
- package/docs/usage/components/bottom-cta.md +3 -1
- package/docs/usage/components/bottom-navigation.md +5 -1
- package/docs/usage/components/button.md +7 -1
- package/docs/usage/components/calendar.md +3 -1
- package/docs/usage/components/card.md +26 -3
- package/docs/usage/components/carousel.md +10 -1
- package/docs/usage/components/chat-message.md +11 -1
- package/docs/usage/components/chip.md +5 -0
- package/docs/usage/components/code-block.md +14 -2
- package/docs/usage/components/collapsible.md +10 -2
- package/docs/usage/components/combobox.md +12 -1
- package/docs/usage/components/command-palette.md +11 -6
- package/docs/usage/components/content-transition.md +29 -5
- package/docs/usage/components/context-menu.md +7 -1
- package/docs/usage/components/date-picker.md +3 -1
- package/docs/usage/components/design-system-provider.md +7 -5
- package/docs/usage/components/dialog.md +70 -1
- package/docs/usage/components/effect-surface.md +4 -2
- package/docs/usage/components/empty-state.md +10 -2
- package/docs/usage/components/field.md +26 -1
- package/docs/usage/components/form.md +13 -3
- package/docs/usage/components/heading.md +7 -1
- package/docs/usage/components/image-comparison.md +82 -0
- package/docs/usage/components/image.md +83 -2
- package/docs/usage/components/keyboard-avoiding.md +6 -1
- package/docs/usage/components/link.md +3 -1
- package/docs/usage/components/list-row.md +5 -1
- package/docs/usage/components/list.md +8 -1
- package/docs/usage/components/load-more.md +3 -1
- package/docs/usage/components/mentions.md +3 -1
- package/docs/usage/components/menu.md +3 -1
- package/docs/usage/components/menubar.md +7 -1
- package/docs/usage/components/message-composer.md +16 -5
- package/docs/usage/components/notice.md +9 -0
- package/docs/usage/components/number-field.md +3 -1
- package/docs/usage/components/onboarding-screen.md +16 -9
- package/docs/usage/components/overview-screen.md +73 -0
- package/docs/usage/components/password-field.md +5 -1
- package/docs/usage/components/popover.md +14 -1
- package/docs/usage/components/progress.md +28 -0
- package/docs/usage/components/progressive-blur.md +113 -0
- package/docs/usage/components/rating.md +74 -0
- package/docs/usage/components/saved-items-screen.md +3 -1
- package/docs/usage/components/screen-layout.md +9 -1
- package/docs/usage/components/search-field.md +13 -1
- package/docs/usage/components/search-screen.md +5 -0
- package/docs/usage/components/segmented-control.md +17 -0
- package/docs/usage/components/select.md +9 -0
- package/docs/usage/components/sheet.md +14 -1
- package/docs/usage/components/skeleton.md +9 -0
- package/docs/usage/components/slider.md +3 -1
- package/docs/usage/components/statistic.md +14 -1
- package/docs/usage/components/surface.md +8 -1
- package/docs/usage/components/tabs.md +11 -2
- package/docs/usage/components/tag.md +3 -1
- package/docs/usage/components/tags-input.md +11 -1
- package/docs/usage/components/text-area.md +3 -1
- package/docs/usage/components/text-transition.md +8 -2
- package/docs/usage/components/text.md +3 -1
- package/docs/usage/components/toast.md +23 -1
- package/docs/usage/components/top-bar.md +3 -1
- package/docs/usage/components/upload-item.md +3 -1
- package/docs/usage/compositions/action-feedback.md +77 -0
- package/docs/usage/compositions/adaptive-content.md +81 -0
- package/docs/usage/compositions/command-records.md +106 -0
- package/docs/usage/compositions/content-transition-comparison.md +108 -0
- package/docs/usage/compositions/context-toolbar.md +85 -0
- package/docs/usage/compositions/date-entry.md +108 -0
- package/docs/usage/compositions/date-time-selection.md +110 -0
- package/docs/usage/compositions/design-profile-comparison.md +114 -0
- package/docs/usage/compositions/document-resource.md +124 -0
- package/docs/usage/compositions/field-group.md +104 -0
- package/docs/usage/compositions/illustrated-outcome.md +91 -0
- package/docs/usage/compositions/live-list.md +104 -0
- package/docs/usage/compositions/optional-adapters.md +1 -1
- package/docs/usage/compositions/origin-dialog.md +108 -0
- package/docs/usage/compositions/selection-motion.md +73 -0
- package/docs/usage/compositions/texture-comparison.md +86 -0
- package/docs/usage/compositions/upload-recovery.md +80 -0
- package/docs/usage/compositions/video-dialog.md +100 -0
- package/docs/usage/screens/flow-onboarding.md +5 -3
- package/docs/usage/screens/product-bento.md +117 -0
- package/docs/usage/tokens/color.md +9 -2
- package/docs/usage/tokens/elevation-opacity.md +8 -1
- package/docs/usage/tokens/motion.md +10 -1
- package/docs/usage/tokens/radius.md +8 -1
- package/docs/usage/tokens/typography.md +15 -1
- package/package.json +49 -1
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
- 단계: 컴포넌트
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
|
-
- 적용:
|
|
7
|
-
- 검토일: 2026-10-
|
|
6
|
+
- 적용: 1.14.0
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [반복 화면 조합](../../screen-patterns.md), Web·Native `src/screens.tsx`·`src/screen-flows.tsx`; 기존 개별 지침을 새 규격으로 통합. 예제 스토리는 2026-10-06 사용자 승인으로 스토리북 배포([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). 스토리북 배포는 API 게시가 아니다(`적용` 참고)
|
|
9
9
|
- 스토리북: `배포/화면/소개/온보딩`
|
|
10
10
|
|
|
11
|
+
2026-10-07 Motion의 단계 카드 검토에서 새 상태 엔진을 추가하기 전에 npm 1.14.0의
|
|
12
|
+
양 renderer `screen-flows.d.ts`·`screen-flows.js`·exports를 확인했다. 기존 `layoutStyle`과
|
|
13
|
+
마지막 `complete` 행동이 이미 게시돼 있어 오래된 미게시 표기를 바로잡는다. 현재 개발 중인
|
|
14
|
+
디자인 프로필 확장의 게시 여부와는 별개다([조사 근거](../../../../../docs/qa/2026-10-07-motion-reference-page-review.md)).
|
|
15
|
+
|
|
11
16
|
## 언제 쓰나
|
|
12
17
|
|
|
13
18
|
첫 실행 소개·초기 설정처럼 **몇 단계를 차례로 넘기는 화면**에 쓴다. 현재 단계의 제목·설명·본문,
|
|
@@ -79,18 +84,19 @@ import { OnboardingScreen } from "@hjmds/react-native/screen-flows";
|
|
|
79
84
|
| `index`, `onIndexChange` | 현재 단계(0부터, 제어형). 범위를 벗어나면 던진다 |
|
|
80
85
|
| `nextLabel`, `backLabel` | 다음·이전 문구. 첫 단계에는 이전이 없다 |
|
|
81
86
|
| `complete` | 마지막 단계의 주 행동 `{ label, onAction, disabled?, pending? }` |
|
|
82
|
-
| `skip` | 선택.
|
|
87
|
+
| `skip` | 선택. Web은 헤더 actions, Native는 본문 진행 문구 다음에 보조 버튼으로 놓인다 |
|
|
83
88
|
| `progressLabel(current, total)` | 1부터 센 현재 단계와 전체 수로 진행 문구를 만든다 |
|
|
89
|
+
| `layoutStyle` | 선택. ScreenLayout 루트의 공개 배치 슬롯 |
|
|
84
90
|
|
|
85
91
|
## 배치
|
|
86
92
|
|
|
87
93
|
| 항목 | 값 | 근거 |
|
|
88
94
|
| --- | --- | --- |
|
|
89
|
-
| 크기 |
|
|
90
|
-
| 간격 | 화면 padding `spacing.md` 16
|
|
91
|
-
| 순서·정렬 | 헤더(
|
|
92
|
-
| 고정·스크롤 | 헤더·진행 문구·footer
|
|
93
|
-
| 좁은 폭·큰 글자 | 제목
|
|
95
|
+
| 크기 | ScreenLayout의 기본 최대 폭 720; 다음·완료·이전은 `Button` 기본 크기 | `screenPatternRecipe.maxWidth` |
|
|
96
|
+
| 간격 | 기본 화면 padding `spacing.md` 16; footer 다음/완료–이전 `spacing.sm` 12; Native 본문 제목·설명·진행·건너뛰기·content 사이 `spacing.md` 16. 단계 content 내부 간격은 제품 소유 | ScreenLayout·양 renderer OnboardingScreen |
|
|
97
|
+
| 순서·정렬 | Web: 헤더(제목·설명 → 건너뛰기) → 진행 문구 → content. Native: 본문(제목 → 설명 → 진행 문구 → 건너뛰기 → content). 둘 다 footer는 다음 또는 완료 → 이전, 첫 단계는 이전 없음 | 실제 렌더 순서 |
|
|
98
|
+
| 고정·스크롤 | Web은 헤더·진행 문구·footer가 본문 스크롤 밖. Native는 제목·설명·진행·건너뛰기·content가 함께 스크롤하고 footer만 고정 | Native의 빈 header·기본 scroll="screen" |
|
|
99
|
+
| 좁은 폭·큰 글자 | Web 헤더 제목 열은 최소 폭 120 × 글자 배율이며 actions가 줄바꿈한다. Native는 본문 세로 Stack을 사용한다. 둘 다 footer 버튼은 세로로 쌓인다 | ScreenLayout·OnboardingScreen |
|
|
94
100
|
|
|
95
101
|
## 꼭 지킬 것
|
|
96
102
|
|
|
@@ -103,4 +109,5 @@ import { OnboardingScreen } from "@hjmds/react-native/screen-flows";
|
|
|
103
109
|
|
|
104
110
|
| 항목 | Web | Native |
|
|
105
111
|
| --- | --- | --- |
|
|
106
|
-
| 배치 prop | `layoutStyle`(ScreenLayout 루트,
|
|
112
|
+
| 배치 prop | `layoutStyle`(ScreenLayout 루트, 1.14.0 게시 확인) | `layoutStyle`(ScreenLayout 루트, 1.14.0 게시 확인) |
|
|
113
|
+
| 단계 안내 | 헤더와 notice | 스크롤 본문. 큰 글자에서 안내가 고정 영역을 모두 차지하지 않도록 기존 본문을 사용한다 |
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# OverviewScreen
|
|
2
|
+
|
|
3
|
+
- 단계: 컴포넌트
|
|
4
|
+
- 상태: 실험
|
|
5
|
+
- 지원: Web · Native
|
|
6
|
+
- 적용: 미게시(1.14.0 이후)
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
|
+
- 근거: [디자인 프로필](../../design-profile.md), 양 renderer `src/design-profile.tsx`; 기존 ScreenLayout·Grid·Collapsible의 상태 엔진을 재사용한다.
|
|
9
|
+
- 스토리북: `실험/컴포넌트/레이아웃/목록 화면 골격`
|
|
10
|
+
|
|
11
|
+
## 언제 쓰나
|
|
12
|
+
|
|
13
|
+
같은 데이터와 기능을 유지하면서 테마별 행·카드·격자와 도구 배치를 선택하는 목록 화면에 쓴다.
|
|
14
|
+
|
|
15
|
+
## 쓰지 않을 때
|
|
16
|
+
|
|
17
|
+
| 상황 | 대신 쓸 것 |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| 설정·검색·알림 | [SettingsScreen](settings-screen.md), [SearchScreen](search-screen.md), [NotificationInboxScreen](notification-inbox-screen.md) |
|
|
20
|
+
| 앱 전체 navigation | [Layout](layout.md) |
|
|
21
|
+
| 임의 마케팅 페이지 | 제품의 페이지 구조 |
|
|
22
|
+
|
|
23
|
+
## 공개 이름과 import
|
|
24
|
+
|
|
25
|
+
| 이름 | 역할 | Web | Native |
|
|
26
|
+
| --- | --- | --- | --- |
|
|
27
|
+
| `OverviewScreen` | 프로필 기반 목록 화면, supplemental | `@hjmds/react/design-profile` | `@hjmds/react-native/design-profile` |
|
|
28
|
+
|
|
29
|
+
root barrel에 넣지 않는다. Native 질감은 기존 optional `react-native-svg` host가 필요하다. 프로필 레지스트리는 renderer core에 번들하지 않는다.
|
|
30
|
+
|
|
31
|
+
## 최소 사용 예
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
// Web
|
|
35
|
+
import { HjmProvider } from "@hjmds/react/provider";
|
|
36
|
+
import { OverviewScreen } from "@hjmds/react/design-profile";
|
|
37
|
+
import { defineHjmDesignProfile } from "@hjmds/design-contracts/design-profile";
|
|
38
|
+
const design = defineHjmDesignProfile({ extends: "forest", id: "app-forest" });
|
|
39
|
+
<HjmProvider designProfile={design}>
|
|
40
|
+
<OverviewScreen title={t("records.title")} toolbarLabel={t("records.tools")}
|
|
41
|
+
toolbar={<RecordTools />} items={records.map(record => ({ id: record.id, children: <RecordSummary record={record} /> }))}
|
|
42
|
+
footer={<SaveAction />} />
|
|
43
|
+
</HjmProvider>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
// Native
|
|
48
|
+
import { HjmNativeProvider } from "@hjmds/react-native/provider";
|
|
49
|
+
import { OverviewScreen } from "@hjmds/react-native/design-profile";
|
|
50
|
+
<HjmNativeProvider designProfile={design}>
|
|
51
|
+
<OverviewScreen title={t("records.title")} toolbarLabel={t("records.tools")}
|
|
52
|
+
toolbar={<RecordTools />} items={records.map(record => ({ id: record.id, children: <RecordSummary record={record} /> }))}
|
|
53
|
+
footer={<SaveAction />} />
|
|
54
|
+
</HjmNativeProvider>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 배치
|
|
58
|
+
|
|
59
|
+
헤더 → notice → 도구 → 목록 → footer. 뒤로는 leading, 화면 도구는 actions, 주 행동은 footer다. 하나의 화면에 경쟁하는 주 행동을 추가하지 않는다.
|
|
60
|
+
|
|
61
|
+
| 항목 | 값 | 근거 |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| 크기 | editorial은 `layout.readingMaxWidth` 720, dashboard·landscape는 `layout.contentMaxWidth` 1200, host가 높이를 제공한다 | `resolveDesignProfileScreen`, ScreenLayout |
|
|
64
|
+
| 간격 | 도구–목록 `spacing.xl` 24, rows `spacing.sm` 12, cards/grid `spacing.lg` 20, 카드 내부 rows `spacing.md` 16 / 나머지 `spacing.xl` 24 | OverviewScreen·공유 collection resolver |
|
|
65
|
+
| 순서·정렬 | 헤더 → notice → 도구 → 목록 → footer. leading은 뒤로, actions는 화면 도구, footer는 주 행동 | ScreenLayout 슬롯 |
|
|
66
|
+
| 고정·스크롤 | 헤더·notice·footer 고정, 본문 스크롤. 가상 목록은 별도 ScreenLayout + `scroll="content"` | ScreenLayout 상태·스크롤 엔진 |
|
|
67
|
+
| 좁은 폭·큰 글자 | rows 1/1/1, cards 1/2/2, grid 1/2/3(compact/medium/expanded). 최소 열 폭 240이며 실제 컨테이너·글자 배율로 열 수를 줄인다 | `resolveDesignProfileCollection`·Grid |
|
|
68
|
+
|
|
69
|
+
`collection`, `toolbarPresentation`, `presentation` 명시값이 프로필을 이긴다. 작은 화면의 열 수는 늘리지 않는다. virtual list는 이 정적 items 목록 대신 기존 ScreenLayout의 `scroll="content"`와 제품 list를 쓴다.
|
|
70
|
+
|
|
71
|
+
## 꼭 지킬 것
|
|
72
|
+
|
|
73
|
+
ScreenLayout의 ready/loading/empty/error와 stateAction을 그대로 사용한다. 초기 조회 오류만 본문을 교체하고 저장 실패는 notice로 알린다. stable id가 중복되거나 비어 있으면 거부한다. 도구를 닫으면 입력 상태는 유지하되 접근성·포커스 대상에서 제외한다. 제품이 서버 확정·재시도·동시 저장 방지를 소유한다. 프로필은 같은 아이템의 입력 subtree를 갈아 끼우지 않는다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [PasswordField](../../password-field.md), `src/password-field.ts`(`passwordFieldRecipe`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/입력/비밀번호 입력`
|
|
10
10
|
|
|
@@ -101,6 +101,10 @@ const passwordRef = useRef<TextInput>(null);
|
|
|
101
101
|
|
|
102
102
|
## 배치
|
|
103
103
|
|
|
104
|
+
Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
|
|
105
|
+
|
|
106
|
+
Native `large`는 프로필의 `typography.bodyLarge`를 읽고 그 줄 높이로 프레임도 늘린다. recipe의 최소 높이가 큰 글자 프레임을 덮지 않으며 controlled textScale은 한 번만 적용한다.
|
|
107
|
+
|
|
104
108
|
| 항목 | 값 | 근거 |
|
|
105
109
|
| --- | --- | --- |
|
|
106
110
|
| 크기 | 높이 `medium` 44(`fieldFrameContract.minHeight`) · `large` 52(`control.buttonHeight.large`). 토글 44×44 원형(`control.minTouchTarget`) | `passwordFieldRecipe.sizes`, `.hjm-password-field__toggle` |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Popover](../../popover.md), [ConfirmPopover 조합](../../confirm-popover.md), `src/popover.ts`(`popoverRecipe`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/오버레이/팝오버`
|
|
10
10
|
|
|
@@ -63,6 +63,7 @@ Native 예는 없다(renderer 없음).
|
|
|
63
63
|
| `dismissPolicy`(부분 지정) | `{ dismissible?, outsideDismiss?, escapeDismiss?, focusOutDismiss? }`(`boolean`) | 모두 `true` | |
|
|
64
64
|
| `open` · `defaultOpen` | `boolean` | 비제어 `false` | 제어하면 `onOpenChange` 필수 |
|
|
65
65
|
| `onOpenChange` | `(open: boolean, details: { reason }) => void` | — | `reason`: `trigger` · `close-action` · `outside-pointer` · `outside-focus` · `escape` · `programmatic` |
|
|
66
|
+
| `motionOrigin` | `TransitionRect` | — | 미게시: 열기 직전 viewport 좌표. 위치 확정 뒤 공간 전환하며 기존 비모달 초점·닫기 정책 유지 |
|
|
66
67
|
| `initialFocusRef` | `RefObject<HTMLElement \| null>` | 첫 포커스 가능 요소 | 열릴 때 처음 포커스 |
|
|
67
68
|
| `portalContainer` | `HTMLElement` | `document.body` | 표면을 붙일 곳 |
|
|
68
69
|
| `className` | 문자열 | — | `layoutStyle`은 받지 않는다(아래 함정) |
|
|
@@ -106,3 +107,15 @@ Native 예는 없다(renderer 없음).
|
|
|
106
107
|
- Popover는 `layoutStyle`을 받지 않는다(Web `layoutStyle` 제외 15개 중 하나). 렌더하는 것이 제품 trigger와 떠 있는 portal뿐이라
|
|
107
108
|
배치는 trigger 쪽(또는 감싼 요소)에서 한다.
|
|
108
109
|
- 부모 Popover가 닫히면 안에 중첩된 Popover도 닫히고 `onOpenChange(false, { reason: "programmatic" })`가 온다. 제어형이면 이 reason도 처리한다.
|
|
110
|
+
|
|
111
|
+
- `motionOrigin`은 출발 버튼의 `getBoundingClientRect()` 값이다. 모션 감소·잘못된 좌표·WAAPI 미지원이면
|
|
112
|
+
공간 전환을 생략하고 기존 표현을 쓴다. 닫혔을 때는 즉시 inert/aria-hidden으로 입력에서 제외한다.
|
|
113
|
+
- 초안은 Popover 위의 제품 상태에 둔다. 종료 후 portal이 제거되므로 내부 비제어 입력에만 두면 사라진다.
|
|
114
|
+
- 공간 전환 실험은 [버튼에서 이어지는 편집](../compositions/origin-dialog.md)의 Web 전용 변형이다.
|
|
115
|
+
|
|
116
|
+
미게시(1.14.0 이후): 가장 가까운 프로필의 `shadow.floating`을 열린 portal에도 상속한다. 프로필이 없으면 기존 recipe 그림자를 유지한다. 초안과 비모달 초점/닫기 계약은 그대로이며 Native는 기존 Sheet 경로를 쓴다.
|
|
117
|
+
|
|
118
|
+
[Motion 세 편집 예제 검토](../../../../../docs/qa/2026-10-07-motion-reference-page-review.md)에서
|
|
119
|
+
aria-modal 표시와 실제 초점 경계가 다르고, 닫기 후 defaultValue 편집이 초기화되는 것을 확인했다.
|
|
120
|
+
MorphingPopover 원본 엔진으로 교체하지 않는다. 공개 `motionOrigin`은 이어지는 표현만 맡고,
|
|
121
|
+
제목/field label·nonmodal 의미·초점 복귀는 Popover, 저장 전 초안·실패/재시도는 제품이 소유한다.
|
|
@@ -120,3 +120,31 @@ linear circular (Web) circular (Native)
|
|
|
120
120
|
## 함정
|
|
121
121
|
|
|
122
122
|
- 1.12.0 전 Native `max` 기본값은 1이었다. 분수 값을 넘기던 옛 코드는 `max={1}`을 명시해야 한다([이관표](../../migration-native-legacy-removal.md)).
|
|
123
|
+
|
|
124
|
+
### 가장자리 힌트의 표시 여부
|
|
125
|
+
|
|
126
|
+
2026-10-07 레퍼런스 조사에서 끝까지 스크롤한 마지막 행도 블러에 가려지는 문제를 확인했다.
|
|
127
|
+
새 `resolveScrollEdges`는 같은 `ScrollMetrics`에서 논리적 이전/다음 콘텐츠 존재 여부를 계산한다.
|
|
128
|
+
아직 미게시이며 `/scroll-progress` subpath에서 제공한다. 블러 renderer 자체를 제공한다는 뜻은 아니다.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { resolveScrollEdges } from "@hjmds/design-contracts/scroll-progress";
|
|
132
|
+
const { before, after } = resolveScrollEdges(metrics);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
- viewportSize=0(미측정), 콘텐츠가 들어맞는 경우에는 둘 다 false다.
|
|
136
|
+
- 소수 offset과 정수 콘텐츠 크기의 오차 때문에 1 logical pixel 이내는 경계로 취급한다.
|
|
137
|
+
- Native 탄성 overscroll은 범위 안으로 제한한다. 가로 RTL offset은 제품 host가 논리적 전진 값으로 정규화한다.
|
|
138
|
+
- 콘텐츠 크기가 바뀌면 새 metrics로 다시 계산한다. focus나 읽기 도구로 접근한 콘텐츠를 가리는지는
|
|
139
|
+
이 순수 계산만으로 판단할 수 없다. 시각 효과 renderer가 해당 조작 상태에서 가림을 제거해야 한다.
|
|
140
|
+
|
|
141
|
+
### 읽기 영역의 길이가 바뀔 때
|
|
142
|
+
|
|
143
|
+
2026-10-07 외부 읽기 진행 효과 대조에서 window 장식과 실제 본문 영역의 진행률을
|
|
144
|
+
구분했다. ScrollProgress는 독서 완료 증명이 아니라 지정한 host의 위치다. 제품의 동의·
|
|
145
|
+
학습 완료를 스크롤 100%만으로 확정하지 않는다.
|
|
146
|
+
|
|
147
|
+
양쪽 읽기 진행 표시 예제의 요약만 보기/전체 내용 보기로 내용 축소와 복원을 확인한다.
|
|
148
|
+
Web은 useScrollMetrics의 resize/mutation 관찰, Native는 ScrollView의 onLayout·
|
|
149
|
+
onContentSizeChange·onScroll을 연결한다. 길이를 줄인 뒤 예전 offset을 그대로 제품 상태로
|
|
150
|
+
저장하지 않는다. 측정 전 viewport=0은 0, 측정 후 화면 안에 들어오는 내용은 1이다.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# ProgressiveBlur
|
|
2
|
+
|
|
3
|
+
- 단계: 컴포넌트
|
|
4
|
+
- 상태: 배포
|
|
5
|
+
- 지원: Web · Native
|
|
6
|
+
- 적용: 1.14.0
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
|
+
- 근거: `src/progressive-blur.ts`, [도입 검토](../../../../../docs/plans/progressive-blur-adoption-2026-10-07.md)
|
|
9
|
+
- 스토리북: `배포/컴포넌트/시각 효과/가장자리 흐림`
|
|
10
|
+
|
|
11
|
+
승급: 2026-10-07 사용자 승인, [검토 결과](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md). Storybook 분류이며 제품 적용 증거는 별도다.
|
|
12
|
+
|
|
13
|
+
## 언제 쓰나
|
|
14
|
+
|
|
15
|
+
스크롤 영역의 바깥에 더 내용이 있음을 알리거나 장식 이미지 가장자리를 흐릴 때 쓴다.
|
|
16
|
+
내용과 형제인 장식 레이어이며 텍스트·버튼을 children으로 받지 않는다. 원본 목록의 마지막
|
|
17
|
+
행이 끝에서도 가려져 HJM은 실제 ScrollMetrics 경계와 입력 초점에 따라 효과를 제거한다.
|
|
18
|
+
|
|
19
|
+
## 쓰지 않을 때
|
|
20
|
+
|
|
21
|
+
| 상황 | 대신 쓸 것 |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| 배경 mesh/glow/grain | [EffectSurface](effect-surface.md) |
|
|
24
|
+
| 읽기 완료율 | [Progress](progress.md)의 ScrollProgress |
|
|
25
|
+
| 가려야 하는 개인정보 | 권한·데이터 정책으로 제거. 블러는 보안 경계가 아님 |
|
|
26
|
+
| 중요한 본문·고정 버튼 위 | 효과를 사용하지 않음 |
|
|
27
|
+
|
|
28
|
+
## 공개 이름과 import
|
|
29
|
+
|
|
30
|
+
| 이름 | 역할 | Web | Native |
|
|
31
|
+
| --- | --- | --- | --- |
|
|
32
|
+
| `ProgressiveBlur` | 추가 장식 API | `@hjmds/react/progressive-blur` | `@hjmds/react-native/progressive-blur` |
|
|
33
|
+
| ProgressiveBlurDescriptor | 공통 입력 | `@hjmds/design-contracts/progressive-blur` | 같음 |
|
|
34
|
+
| ProgressiveBlurHostLayer | Native 호스트 입력 | 해당 없음 | `@hjmds/react-native/progressive-blur` |
|
|
35
|
+
|
|
36
|
+
루트 export에 없다. 기존 EffectSurface는 내용을 흐리지 않는 배경 장식이므로 별도 API를 둔다.
|
|
37
|
+
Native renderer에 Expo/마스크 peer를 추가하지 않는다. 실제 블러·마스크 엔진은 제품이 연결한다.
|
|
38
|
+
|
|
39
|
+
## 최소 사용 예
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
// Web
|
|
43
|
+
import { ProgressiveBlur } from "@hjmds/react/progressive-blur";
|
|
44
|
+
<ProgressiveBlur descriptor={{ edge: "bottom", extent: 64, strength: 0.5,
|
|
45
|
+
content: { kind: "scroll", metrics, focused: contentHasFocus } }} />
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
// Native
|
|
50
|
+
import { ProgressiveBlur } from "@hjmds/react-native/progressive-blur";
|
|
51
|
+
<ProgressiveBlur descriptor={{ edge: "bottom", extent: 64, strength: 0.5,
|
|
52
|
+
content: { kind: "scroll", metrics, focused: contentHasFocus } }}
|
|
53
|
+
renderLayer={layer => renderProductBackdropLayer(layer)} />
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
내용과 효과를 같은 positioned/clipped 부모의 형제로 둔다. 위쪽과 아래쪽이 필요하면 두 개를
|
|
57
|
+
놓는다. Web useScrollMetrics를 재사용하고 Native는 실제 onScroll/onLayout/onContentSizeChange를
|
|
58
|
+
연결한다. 내용에 초점이 있는 동안 focused=true를 전달한다. 읽기 도구·외부 키보드 포커스도
|
|
59
|
+
제품에서 전달하거나 그 환경에서는 효과를 끈다. Showcase를 소비 앱에서 import하지 않는다.
|
|
60
|
+
|
|
61
|
+
## 축과 기본값
|
|
62
|
+
|
|
63
|
+
| prop | 값 | 기본값 | 설명 |
|
|
64
|
+
| --- | --- | --- | --- |
|
|
65
|
+
| descriptor.edge | top · bottom · start · end | 필수 | start/end는 provider direction으로 물리 위치 결정 |
|
|
66
|
+
| descriptor.extent | 0 초과~160 logical px | 필수 | 실제 host에서 비교 후 명시적으로 선택 |
|
|
67
|
+
| descriptor.strength | 0~1 | 필수 | 0은 효과 없음, 플랫폼 간 같은 px를 뜻하지 않음 |
|
|
68
|
+
| descriptor.layers | 정수 2~8 | 4 | 실험 시작값, 기기 성능 보증이 아님 |
|
|
69
|
+
| descriptor.content | decoration 또는 scroll | 필수 | scroll은 metrics와 focused 필수 |
|
|
70
|
+
| renderLayer(Native) | layer → ReactNode | 필수 | 실제 플랫폼 블러와 alpha mask. 호스트 없음은 null로 표현 가능 |
|
|
71
|
+
|
|
72
|
+
Native layer에는 side(물리 방향), strength, start/end(0~1 alpha ramp 위치)가 전달된다.
|
|
73
|
+
inner edge에서 투명, 지정 side 쪽에서 불투명인 마스크를 만든다. Web은 strength×16px blur와
|
|
74
|
+
CSS mask를 쓴다. Native intensity와 CSS radius는 같은 단위가 아니다.
|
|
75
|
+
|
|
76
|
+
## 배치
|
|
77
|
+
|
|
78
|
+
| 항목 | 값 | 근거 |
|
|
79
|
+
| --- | --- | --- |
|
|
80
|
+
| 크기 | 상하: 부모 폭 + extent 높이, 좌우: 부모 높이 + extent 폭 | resolveProgressiveBlur와 renderer |
|
|
81
|
+
| 간격 | 자체 여백 없음, 지정 side에 0으로 부착 | renderer absolute frame |
|
|
82
|
+
| 순서·정렬 | 내용 뒤의 형제 레이어, 포인터 통과 | pointerEvents none |
|
|
83
|
+
| 고정·스크롤 | 스크롤 내용 밖 같은 부모 안에 둠 | 예제 positioned host |
|
|
84
|
+
| 좁은 폭·큰 글자 | 부모 크기와 새 ScrollMetrics를 사용, 입력 초점 때 제거 | content.kind scroll |
|
|
85
|
+
|
|
86
|
+
## 꼭 지킬 것
|
|
87
|
+
|
|
88
|
+
- 장식 내용을 별도 accessible subtree로 만들지 않는다. 컴포넌트는 장식 호스트 전체를 접근성 트리에서 숨긴다.
|
|
89
|
+
- scroll 끝에서는 해당 효과가 사라지고 맞춤/미측정이면 양쪽 모두 사라진다. content.kind decoration으로 이를 우회하지 않는다.
|
|
90
|
+
- Native renderLayer는 절대 위치로 부모를 채우고 터치 대상·텍스트를 넣지 않는다.
|
|
91
|
+
- Native 호스트가 실패하면 장식만 사라진다. 복구를 원할 때 명시적으로 remount한다.
|
|
92
|
+
- 정적 효과여서 자체 자동 애니메이션이 없다. 주변 콘텐츠의 모션 감소·일시 정지는 별도로 유지한다.
|
|
93
|
+
- 원본 8층을 무조건 복사하지 않고 2~8층과 효과 없음을 같은 기기에서 비교한다. 기본값 4는 실험용이다.
|
|
94
|
+
|
|
95
|
+
## 플랫폼 차이
|
|
96
|
+
|
|
97
|
+
| 항목 | Web | Native |
|
|
98
|
+
| --- | --- | --- |
|
|
99
|
+
| 실제 효과 | CSS backdrop-filter + mask-image | 제품 blur/mask host |
|
|
100
|
+
| 추가 peer | 없음 | HJM 없음, 제품 호스트에 따라 필요 |
|
|
101
|
+
| 지원 누락 | CSS 미지원이면 내용은 그대로 보임 | null 또는 호스트 오류 경계로 장식만 제거 |
|
|
102
|
+
| 스크롤 | useScrollMetrics | 실제 Native 이벤트 연결 |
|
|
103
|
+
| 데모 엔진 | 브라우저 | ExpoBlur + MaskedView + SVG alpha mask |
|
|
104
|
+
|
|
105
|
+
Expo SDK57 Android는 BlurTargetView/blurTarget/blurMethod가 있어야 실제 블러가 된다.
|
|
106
|
+
동적 목록 뒤에 효과를 렌더하며 Android 12 이전 비용은 별도로 측정한다. 모듈 누락 안내는
|
|
107
|
+
효과 지원·기기 검증 통과가 아니다. 실험 승격 전 양 플랫폼의 실제 합성과 기기 성능을 확인한다.
|
|
108
|
+
|
|
109
|
+
## 함정
|
|
110
|
+
|
|
111
|
+
전체 화면에 고정하면 다른 영역을 흐릴 수 있다. 부모를 반드시 클리핑한다. extent가 작은
|
|
112
|
+
viewport보다 크지 않게 선택한다. 공개 HJM API는 기본 subtree의 배치를 바꾸지 않으며,
|
|
113
|
+
제품 호스트의 alpha mask가 틀리면 단위 테스트가 통과해도 실제 블러는 보이지 않을 수 있다.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Rating
|
|
2
|
+
|
|
3
|
+
- 단계: 컴포넌트
|
|
4
|
+
- 상태: 배포
|
|
5
|
+
- 지원: Web · Native
|
|
6
|
+
- 적용: 1.14.0
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
|
+
- 근거: [계약](../../reference-controls.md)
|
|
9
|
+
- 스토리북: `배포/컴포넌트/입력/별점 선택`
|
|
10
|
+
|
|
11
|
+
승급: 2026-10-07 사용자 승인, [검토 결과](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md). Storybook 분류이며 제품 적용 증거는 별도다.
|
|
12
|
+
|
|
13
|
+
## 언제 쓰나
|
|
14
|
+
|
|
15
|
+
정수 점수를 선택하거나 계산된 소수 평균을 읽기 전용으로 보여 줄 때 쓴다.
|
|
16
|
+
|
|
17
|
+
## 쓰지 않을 때
|
|
18
|
+
|
|
19
|
+
| 상황 | 대신 쓸 것 |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| 반점 간격의 연속 점수 입력 | [Slider](slider.md)의 기존 별점 예제 |
|
|
22
|
+
| 일반 선택지 | [RadioGroup](radio-group.md) |
|
|
23
|
+
|
|
24
|
+
## 공개 이름과 import
|
|
25
|
+
|
|
26
|
+
| 이름 | 역할 | Web | Native |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| `Rating` | 독립 supplemental | `@hjmds/react/rating` | `@hjmds/react-native/rating` |
|
|
29
|
+
|
|
30
|
+
## 최소 사용 예
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// Web
|
|
34
|
+
import { Rating } from "@hjmds/react/rating";
|
|
35
|
+
<Rating label={label} value={score} onValueChange={setScore} getValueLabel={formatScore} clearLabel={clearLabel} />
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
// Native
|
|
40
|
+
import { Rating } from "@hjmds/react-native/rating";
|
|
41
|
+
<Rating label={label} value={score} onValueChange={setScore} getValueLabel={formatScore} clearLabel={clearLabel} />
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Native는 import를 `@hjmds/react-native/rating`로 바꾼다.
|
|
45
|
+
|
|
46
|
+
## 축과 기본값
|
|
47
|
+
|
|
48
|
+
| prop | 값 | 기본값 | 설명 |
|
|
49
|
+
| --- | --- | --- | --- |
|
|
50
|
+
| `value` | number 또는 null | 필수 | 5개 기본, max 1~10. 미평가는 null이며 입력 점수는 1~max의 정수, 평균은 readOnly의 0~max 소수다. |
|
|
51
|
+
| Web `layoutStyle` | 배치 전용 style | 없음 | 바깥 틀의 폭·margin·flex 배치 |
|
|
52
|
+
| `disabled` | boolean | false | 변경을 막고 현재 값을 유지 |
|
|
53
|
+
|
|
54
|
+
## 배치
|
|
55
|
+
|
|
56
|
+
| 항목 | 값 | 근거 |
|
|
57
|
+
| --- | --- | --- |
|
|
58
|
+
| 크기 | Web은 44px 최소 radio 영역, Native는 control.minTouchTarget 44. 별 그림은 글자 크기에 따라 커지고 행이 줄바꿈된다. | renderer `rating.tsx` |
|
|
59
|
+
| 간격 | space.xs=8px의 별 사이 간격; 초기화는 점수 문구 뒤에 온다. | foundations spacing |
|
|
60
|
+
| 순서·정렬 | 질문→선택→점수→선택적 초기화 | renderer 순서 |
|
|
61
|
+
| 고정·스크롤 | 바깥 화면이 스크롤을 소유한다 | 별도 스크롤 없음 |
|
|
62
|
+
| 좁은 폭·큰 글자 | 폭을 강제 고정하지 않고 본문/행의 줄바꿈을 허용한다 | 위 배치 |
|
|
63
|
+
|
|
64
|
+
## 꼭 지킬 것
|
|
65
|
+
|
|
66
|
+
- Web 초기화 후 첫 별점으로 초점이 돌아온다. Space로 다시 선택할 수 있다.
|
|
67
|
+
- label, value, getValueLabel을 제품 언어로 공급한다. 입력형은 onValueChange가 필수이고 평균형에는 전달하지 않는다.
|
|
68
|
+
- 브랜드는 HJM provider의 semantic palette로 연결한다. 점수 집계·이미지 변환·저장은 제품 소유다.
|
|
69
|
+
|
|
70
|
+
## 플랫폼 차이
|
|
71
|
+
|
|
72
|
+
| 항목 | Web | Native |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| 조작 | Web은 실제 radio와 name으로 폼에 연결한다. Native는 radio 접근성 상태와 onPress를 쓴다. | 같은 의미를 플랫폼 host로 번역 |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 미게시(1.12.1 이후)
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [반복 화면 계약](../../screen-patterns.md); 저장한 항목을 Instagram의 컬렉션 탐색 방식으로 바꾸라는 사용자 요청. 기존 ListDetailScreen·Grid를 합성하며 별도 저장 엔진은 만들지 않는다. 예제 스토리는 2026-10-06 사용자 승인으로 스토리북 배포([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). 스토리북 배포는 API 게시가 아니다(`적용` 참고)
|
|
9
9
|
- 스토리북: `배포/화면/콘텐츠/저장한 항목`
|
|
10
10
|
|
|
@@ -92,6 +92,8 @@ import { SavedItemsScreen } from "@hjmds/react-native/saved-items";
|
|
|
92
92
|
|
|
93
93
|
## 배치
|
|
94
94
|
|
|
95
|
+
Native collection cover의 모서리는 Provider의 `tokens.radius.md`다. 저장 항목·컬렉션·선택·탐색 계약은 바꾸지 않는다.
|
|
96
|
+
|
|
95
97
|
| 항목 | 값 | 근거 |
|
|
96
98
|
| --- | --- | --- |
|
|
97
99
|
| 크기 | host의 남은 높이 100%, ScreenLayout 폭(최대 720); 컬렉션 표지·게시물 썸네일 1:1, 표지 radius `radius.md` | `ListDetailScreen`, Web `.hjm-saved-*`, Native `saved-items.tsx` |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 미게시(1.12.1 이후)
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [반복 화면 조합](../../screen-patterns.md), Web·Native `src/screens.tsx`·`src/screen-flows.tsx`; 기존 개별 지침을 새 규격으로 통합. 예제 스토리는 2026-10-06 사용자 승인으로 스토리북 배포([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). 스토리북 배포는 API 게시가 아니다(`적용` 참고)
|
|
9
9
|
- 스토리북: `배포/화면/화면 틀과 도구/화면 골격과 상태`
|
|
10
10
|
|
|
@@ -79,6 +79,7 @@ import { ScreenLayout } from "@hjmds/react-native/screens";
|
|
|
79
79
|
| `stateAction` | `ReactNode` | 없음 | 상태 안내 아래 행동(재시도 등) |
|
|
80
80
|
| `scroll` | `"screen"` · `"content"` | `"screen"` | `content`는 본문 자식(가상화 목록)이 스크롤을 소유한다. 상태 교체 중에는 `screen`으로 돌아간다 |
|
|
81
81
|
| `contentInset` | `"default"` · `"none"` | `"default"` | `none`은 헤더·notice·본문·footer padding을 0으로(Native는 footer 위 테두리도 뺀다) |
|
|
82
|
+
| `presentation` | `"dashboard"` · `"editorial"` · `"landscape"` | 가장 가까운 profile.screens.overview / 없으면 기존 골격 | 미게시 실험. 명시값이 프로필을 이긴다. 헤더 배치·읽기 폭만 바꾸고 상태·입력·행동 슬롯은 유지한다 |
|
|
82
83
|
| `as` (Web) | `"main"` · `"section"` | `"main"` | 제품 셸에 이미 `<main>`이 있으면 `section` |
|
|
83
84
|
| `layoutStyle` | `HjmCompositionStyleProp` | 없음 | 화면 루트 배치 전용(예: 분할 화면의 `flex`·`width`). ScreenLayout 위에 만든 화면은 모두 이 prop을 루트까지 넘긴다 |
|
|
84
85
|
| `className` (Web) | `string` | 없음 | 식별·배치 보조. 색·여백을 덮지 않는다 |
|
|
@@ -117,3 +118,10 @@ import { ScreenLayout } from "@hjmds/react-native/screens";
|
|
|
117
118
|
## 함정
|
|
118
119
|
|
|
119
120
|
- 이미 `<main>`이 있는 제품 셸 안에서는 `as="section"`을 준다. 중첩 main이 생긴다.
|
|
121
|
+
|
|
122
|
+
### 디자인 프로필의 화면 표현
|
|
123
|
+
|
|
124
|
+
`presentation` 명시값, 가장 가까운 프로필의 screens.overview, 기존 화면 골격 순으로 선택한다.
|
|
125
|
+
dashboard는 가로 헤더/1200 목록 폭, editorial은 세로 헤더/720 읽기 폭, landscape는 중앙 세로 헤더/1200 폭이다.
|
|
126
|
+
폭은 foundations의 contentMaxWidth/readingMaxWidth다. 프로필을 지정하지 않으면 기존 recipe 배치를 유지한다.
|
|
127
|
+
같은 header/body/notice/footer 및 상태 엔진을 유지하며 입력 subtree를 테마별로 교체하지 않는다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: `src/component-recipes.ts`(`searchFieldRecipe`). 별도 계약 문서는 없다
|
|
9
9
|
- 스토리북: `배포/컴포넌트/입력/검색 입력`
|
|
10
10
|
|
|
@@ -78,6 +78,8 @@ import { SearchField } from "@hjmds/react-native/inputs";
|
|
|
78
78
|
|
|
79
79
|
## 배치
|
|
80
80
|
|
|
81
|
+
Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
|
|
82
|
+
|
|
81
83
|
| 항목 | 값 | 근거 |
|
|
82
84
|
| --- | --- | --- |
|
|
83
85
|
| 크기 | 최소 높이 `medium` 44 · `large` 52. 지우기 버튼 `medium` 지름 36 + hitSlop 4, `large` 44(Web은 36 원에 `::after` 4px로 터치 44를 만든다) | `searchFieldRecipe.sizes`, `control.minTouchTarget`, `control.buttonHeight.large`, `.hjm-search-field__clear` |
|
|
@@ -118,3 +120,13 @@ import { SearchField } from "@hjmds/react-native/inputs";
|
|
|
118
120
|
| 진행 중 입력 | 입력 가능(`aria-busy`) | 입력 가능(`accessibilityState.busy`). 2026-10-06까지 Native는 `busy`인 동안 입력을 무시했다(1.12.1 이후 미게시) |
|
|
119
121
|
| 입력 요소 | `<input type="search">`, 원시 `onChange`도 전달 | `TextInput` |
|
|
120
122
|
| 배치 | `layoutStyle`·`fieldClassName`(필드 틀), `style`은 안쪽 input | `layoutStyle` |
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
### 고정 아이콘과 큰 글자
|
|
126
|
+
|
|
127
|
+
2026-10-06 최근 검색 삭제 기호가 큰 글자에서 잘린 재현에 따라 Native 내장 삭제·메뉴 기호는 고정 아이콘 틀의 크기를 유지한다. 주변 제목·라벨은 계속 확대한다. Chip의 체크와 Toast 닫기는 기존 비확대 경로를 유지하며 회귀 검사에 포함한다. 제품이 전달한 아이콘 슬롯은 제품이 같은 조건을 검증한다.
|
|
128
|
+
|
|
129
|
+
### 브라우저 지우기 중복 방지
|
|
130
|
+
|
|
131
|
+
Web은 type=search를 유지하지만 브라우저 기본 cancel 장식은 숨긴다. 2026-10-07 빈 상태 복구
|
|
132
|
+
실측에서 ×가 두 개 보였기 때문이다. 실제 지우기는 HJM 버튼의 clearLabel·onClear·초점 복귀로 한다.
|
|
@@ -219,3 +219,8 @@ import { SearchScreen } from "@hjmds/react-native/screen-flows";
|
|
|
219
219
|
떨어졌다. utilverse는 `onSubmit`에서 `Keyboard.dismiss()`를 불렀다(2026-10-06). 1.13.1부터 SearchScreen이 닫으므로 그 호출을 지운다.
|
|
220
220
|
- 1.13.0 이하에서는 `contentInset="none"`이면 `scroll` 줄이 전혀 넓어지지 않아 host 여백(Container·Sheet)에서 잘렸다. 1.13.1부터 `hostGutter`로 맞춘다.
|
|
221
221
|
- 시트 안 SearchScreen은 Sheet `size`를 `auto` 밖으로 주고 `scrollable` 없이 넣는다. 1.13.0 이하 Native는 이때 화면이 0pt가 됐다([Sheet 함정](sheet.md#함정)).
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
### 고정 아이콘과 큰 글자
|
|
225
|
+
|
|
226
|
+
2026-10-06 최근 검색 삭제 기호가 큰 글자에서 잘린 재현에 따라 Native 내장 삭제·메뉴 기호는 고정 아이콘 틀의 크기를 유지한다. 주변 제목·라벨은 계속 확대한다. Chip의 체크와 Toast 닫기는 기존 비확대 경로를 유지하며 회귀 검사에 포함한다. 제품이 전달한 아이콘 슬롯은 제품이 같은 조건을 검증한다.
|
|
@@ -144,3 +144,20 @@ Native는 `@hjmds/react-native/inputs`에서 같은 prop을 사용한다. `prese
|
|
|
144
144
|
1.13.1부터는 레일 안에서 한 줄로 남으므로 그 분기를 지운다. 1.13.0에 머무는 제품만 우회를 유지한다.
|
|
145
145
|
- 레일(가로 스크롤)은 바깥이 만든다. SearchScreen 안이면 `filtersOverflow="scroll"`, 그 밖이면 제품의 가로 ScrollView다.
|
|
146
146
|
`pills`가 스스로 스크롤하지 않는 이유는 레일 안에 두 번째 가로 스크롤을 겹치지 않기 위해서다.
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
### 선택 배경 이동
|
|
150
|
+
|
|
151
|
+
2026-10-07 Animated Background 비교에서 시각적 선택만 있는 외부 예제를 그대로 교체하면 radio/checked 의미를 잃는 것을 확인했다.
|
|
152
|
+
`selectionMotion="slide"`는 기존 선택 엔진·키보드·접근성 이름·입력 위치를 유지하고 배경만 측정 위치로 이동한다.
|
|
153
|
+
Web은 항목과 바깥 선택 영역의 크기를 함께 관찰한다. 2026-10-07 RTL pills에서 항목 너비는
|
|
154
|
+
그대로인 채 부모 폭만 바뀌면 선택 배경이 이전 위치에 남는 오류를 수정했다. 크기 변경에는
|
|
155
|
+
이동 모션을 재생하지 않고 새 위치에 맞춘다.
|
|
156
|
+
기본은 `"none"`이며 opt-in 실험이다. 별도 버튼/선택 상태를 만들어 기존 라디오를 대체하지 않는다.
|
|
157
|
+
|
|
158
|
+
- Web/Native 모두 `connected`와 `pills`에 적용한다. 큰 글자·RTL·줄바꿈에서는 실제 항목 위치를 측정한다.
|
|
159
|
+
- 최초 배치와 resize는 즉시 맞추며 선택이 바뀔 때만 HJM `motion.normal` 시간으로 이동한다.
|
|
160
|
+
- 모션 감소와 비활성 화면에서는 이동 효과를 중지한다. 동작 중인 입력·선택 값은 그대로다.
|
|
161
|
+
- 조작 가능 영역·글자는 움직이거나 확대하지 않는다. 새 사용 예제는 [선택 배경 이동](../compositions/selection-motion.md)이다.
|
|
162
|
+
|
|
163
|
+
2026-10-07 큰 글자 UI 확인에서 Web 2배 글자 줄은 40px인데 pill 배경은 28px였다. Native처럼 세로 padding에도 pills.inset(spacing.xs=8px)을 적용해 배경이 전체 줄을 감싸게 했다. 고정 높이를 늘리는 대신 줄 높이를 따라가므로 3배·줄바꿈도 유지한다.
|
|
@@ -93,6 +93,15 @@ import { NativeSelect } from "@hjmds/react/forms";
|
|
|
93
93
|
| `options`(NativeSelect) | `readonly { value: string; label: string; disabled? }[]` | 필수 | 브라우저 `<select>` 대안 |
|
|
94
94
|
| `onValueChange`(NativeSelect) | `(value: string) => void` | — | 원시 `onChange`도 받는다 |
|
|
95
95
|
|
|
96
|
+
### 디자인 프로필 상속
|
|
97
|
+
|
|
98
|
+
2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
|
|
99
|
+
모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
|
|
100
|
+
읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
|
|
101
|
+
프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
|
|
102
|
+
플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
|
|
103
|
+
|
|
104
|
+
|
|
96
105
|
## 배치
|
|
97
106
|
|
|
98
107
|
| 항목 | 값 | 근거 |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Sheet 입력 화면과 가용 영역](../../sheet.md), [optional adapters](../../optional-adapters.md)(Native 제스처 확장), `src/component-recipes.ts`(`sheetRecipe`), `src/sheet.ts`(`sheetBehaviorDefaults`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/오버레이/시트`
|
|
10
10
|
|
|
@@ -88,8 +88,21 @@ import { Sheet } from "@hjmds/react-native/overlays";
|
|
|
88
88
|
| `safeAreaInsets`(Native) | `Partial<Insets>` | provider inset | — |
|
|
89
89
|
| `contentStyle`(Native) | 배치 key만 | — | 배치 밖 key(색·높이 등)는 deprecated(개발 모드 경고), 다음 major에서 배치 전용 타입으로 좁힌다 |
|
|
90
90
|
|
|
91
|
+
### 디자인 프로필 상속
|
|
92
|
+
|
|
93
|
+
2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
|
|
94
|
+
모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
|
|
95
|
+
읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
|
|
96
|
+
프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
|
|
97
|
+
플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
|
|
98
|
+
|
|
99
|
+
|
|
91
100
|
## 배치
|
|
92
101
|
|
|
102
|
+
선택형 Native `GestureSheetInput`의 실제 keyboard-tracking host에도 제품 `tokens.fontFamily.ui`가 이어진다. optional library·폰트 설치와 실제 기기 검증은 제품이 맡는다.
|
|
103
|
+
|
|
104
|
+
선택형 GestureSheetInput은 Provider typography와 field recipe radius 역할을 읽고 textScale을 한 번 적용한다. optional keyboard-tracking host는 그대로다.
|
|
105
|
+
|
|
93
106
|
| 항목 | 값 | 근거 |
|
|
94
107
|
| --- | --- | --- |
|
|
95
108
|
| 크기 | 하단 시트 높이: `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` |
|
|
@@ -67,6 +67,15 @@ import { Skeleton } from "@hjmds/react-native/feedback";
|
|
|
67
67
|
|
|
68
68
|
콜백 prop은 없다.
|
|
69
69
|
|
|
70
|
+
### 디자인 프로필 상속
|
|
71
|
+
|
|
72
|
+
2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
|
|
73
|
+
모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
|
|
74
|
+
읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
|
|
75
|
+
프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
|
|
76
|
+
플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
|
|
77
|
+
|
|
78
|
+
|
|
70
79
|
## 배치
|
|
71
80
|
|
|
72
81
|
| 항목 | 값 | 근거 |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Slider](../../slider.md), `src/slider.ts`(`sliderRecipe`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/입력/슬라이더`, `배포/컴포넌트/입력/별점`
|
|
10
10
|
|
|
@@ -81,6 +81,8 @@ import { Slider } from "@hjmds/react-native/slider";
|
|
|
81
81
|
|
|
82
82
|
## 배치
|
|
83
83
|
|
|
84
|
+
Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
|
|
85
|
+
|
|
84
86
|
| 항목 | 값 | 근거 |
|
|
85
87
|
| --- | --- | --- |
|
|
86
88
|
| 크기 | 가로 폭을 채운다. 트랙 줄은 터치 높이 `control.minTouchTarget` 44 안에 두께 4 트랙과 지름 20 thumb을 세로 중앙에 그린다 | `sliderRecipe.sizes.medium`, `.hjm-slider__control` |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Statistic](../../statistic.md), [optional adapters](../../optional-adapters.md), `src/component-recipes.ts`(`statisticRecipe`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/데이터 표시/수치 표시`, `배포/컴포넌트/데이터 표시/움직이는 수치`
|
|
10
10
|
|
|
@@ -88,6 +88,8 @@ import { Statistic } from "@hjmds/react-native/data-display";
|
|
|
88
88
|
|
|
89
89
|
## 배치
|
|
90
90
|
|
|
91
|
+
Native 프레임의 모서리는 `statisticRecipe.presentations`의 역할을 Provider token에서 해석한다. 수치·locale·낭독 문구는 제품 데이터 그대로다.
|
|
92
|
+
|
|
91
93
|
| 항목 | 값 | 근거 |
|
|
92
94
|
| --- | --- | --- |
|
|
93
95
|
| 크기 | `presentation="surface"`의 안쪽 여백: `comfortable` `spacing.md` 16 · `compact` `spacing.sm` 12(두 플랫폼). 테두리 `stroke.default` 1, radius `md` 12 | `statisticRecipe.density`·`presentations`, `styles.css` `.hjm-statistic[data-presentation="surface"]` |
|
|
@@ -121,3 +123,14 @@ import { Statistic } from "@hjmds/react-native/data-display";
|
|
|
121
123
|
- Web `AnimatedStatistic`은 reduced motion, RTL, 라틴 숫자가 아닌 numbering system, `ar`·`fa`·`he`·`ur` locale,
|
|
122
124
|
`scientific`·`engineering` 표기에서는 애니메이션 없이 `Intl` 결과 문자열만 그린다.
|
|
123
125
|
- `AnimatedStatistic`의 `descriptor`에는 `value`를 넣지 않는다. 값은 `value` prop의 숫자로 받는다.
|
|
126
|
+
|
|
127
|
+
### 외부 숫자 효과 대조
|
|
128
|
+
|
|
129
|
+
2026-10-07 Number Ticker 공식 소스와 기본 데모를 대조했다. 진입 시 중간 숫자를 표시하는
|
|
130
|
+
효과와 실제 값 변경은 구분한다. 현재 AnimatedStatistic의 Intl locale과 RTL·비라틴 숫자·
|
|
131
|
+
지수 표기 fallback을 유지하며 별도 count-up 엔진을 추가하지 않는다. 숫자가 올라가는 효과를
|
|
132
|
+
실제 집계 과정으로 오해시키지 않기 위해 제품은 확정한 값을 전달한다.
|
|
133
|
+
|
|
134
|
+
양쪽 움직이는 수치 Storybook에 소수와 음수(de-DE), 비라틴 숫자(ar-EG), 지수 표기(en-US),
|
|
135
|
+
동작 줄이기와 RTL 비교를 제공한다. 소수·음수 예제는 기록 개수가 아닌 측정값이다.
|
|
136
|
+
Web은 자리 단위 전환, Native는 지표 전체 전환이며 같은 시각 효과를 보장하지 않는다.
|