@hjmds/design-contracts 1.14.0 → 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/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/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/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/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/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/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 +5 -1
- 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/theming.md +18 -5
- package/docs/usage/README.md +5 -0
- package/docs/usage/components/activity-heatmap.md +3 -1
- package/docs/usage/components/agreement.md +2 -0
- package/docs/usage/components/alert-dialog.md +9 -0
- package/docs/usage/components/asset.md +9 -2
- 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 +19 -2
- package/docs/usage/components/carousel.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 +1 -1
- 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 +53 -1
- package/docs/usage/components/field.md +3 -1
- package/docs/usage/components/form.md +7 -2
- package/docs/usage/components/heading.md +7 -1
- package/docs/usage/components/image.md +2 -0
- package/docs/usage/components/list-row.md +2 -0
- package/docs/usage/components/list.md +2 -0
- 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 +11 -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 +7 -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 +3 -1
- 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 +3 -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 +6 -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 +18 -1
- package/docs/usage/components/top-bar.md +3 -1
- package/docs/usage/compositions/command-records.md +106 -0
- package/docs/usage/compositions/content-transition-comparison.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/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 +13 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Activity heatmap](../../activity-heatmap.md), descriptor `resolveActivityHeatmap`(`src/activity-heatmap.ts`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/데이터 표시/활동 히트맵`
|
|
10
10
|
|
|
@@ -74,6 +74,8 @@ import { ActivityHeatmap } from "@hjmds/react-native/activity-heatmap";
|
|
|
74
74
|
|
|
75
75
|
## 배치
|
|
76
76
|
|
|
77
|
+
Native 데이터 셀 모서리는 Provider의 `tokens.radius.sm / 4`다. Web의 같은 역할과 맞추며 날짜·0·누락 데이터의 의미는 색과 분리한다.
|
|
78
|
+
|
|
77
79
|
| 항목 | 값 | 근거 |
|
|
78
80
|
| --- | --- | --- |
|
|
79
81
|
| 크기 | 칸 16×16(Web `1rem`, Native `spacing.md`), 7행(요일) × 주 수 열. 366일이면 53열 × 20 − 4 = 1056 폭이다. 칸은 터치 대상이 아니다(44 미만) | `react/src/activity-heatmap.tsx`, `react-native/src/activity-heatmap.tsx` |
|
|
@@ -82,6 +82,8 @@ import { Agreement } from "@hjmds/react-native/agreement";
|
|
|
82
82
|
|
|
83
83
|
## 배치
|
|
84
84
|
|
|
85
|
+
Native의 전체 동의 프레임 `md`와 선택 표시 `sm`은 Provider의 `tokens.radius`를 읽는다. 제품 프로필 교체는 동의 상태를 초기화하지 않는다.
|
|
86
|
+
|
|
85
87
|
| 항목 | 값 | 근거 |
|
|
86
88
|
| --- | --- | --- |
|
|
87
89
|
| 크기 | 폭을 꽉 채운다. 전체 동의 줄 최소 44(`control.minTouchTarget`), 항목 줄 최소 44, [전문 보기] 높이 44, 체크 표시 16×16(`spacing.md`) | `agreementRecipe`, `collectionItemContract`, `.hjm-agreement__mark` |
|
|
@@ -83,6 +83,15 @@ import { AlertDialog } from "@hjmds/react-native/overlays";
|
|
|
83
83
|
| Web `modalPriority` | `number` | `0` | 높은 우선순위 모달이 뒤에 열린 낮은 모달 위에서 동작한다 |
|
|
84
84
|
| Native `contentStyle` | 배치 key(margin·width·flex·`alignSelf`)만 | — | 색·radius·padding 등 시각 key는 deprecated(개발 모드 1회 경고, 다음 major에서 배치 key로 좁힘) |
|
|
85
85
|
|
|
86
|
+
### 디자인 프로필 상속
|
|
87
|
+
|
|
88
|
+
2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
|
|
89
|
+
모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
|
|
90
|
+
읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
|
|
91
|
+
프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
|
|
92
|
+
플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
|
|
93
|
+
|
|
94
|
+
|
|
86
95
|
## 배치
|
|
87
96
|
|
|
88
97
|
| 항목 | 값 | 근거 |
|
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Asset contract](../../asset.md), [VoiceNote](../../voice-note.md), recipe `assetRecipe`(`src/asset.ts`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/데이터 표시/이미지·영상 표시` · `배포/컴포넌트/데이터 표시/음성 메모`
|
|
10
10
|
|
|
11
|
+
개발 중인 프로필 지원에서 `rounded`는 가장 가까운 프로필의 `tokens.radius.md`를 따른다.
|
|
12
|
+
프로필이 없으면 기존 12px이고 명시한 square/circle은 그대로다. 이 보강은 아직 미게시이며
|
|
13
|
+
1.12.1의 기존 Asset 제공 여부와 구분한다([근거](../../../../../docs/qa/2026-10-07-3dicons-page-review.md)).
|
|
14
|
+
|
|
11
15
|
## 언제 쓰나
|
|
12
16
|
|
|
13
17
|
아이콘·이미지·Lottie·비디오를 같은 크기·모서리 규칙의 액자에 넣을 때 쓴다. 종류가 다른 그림이
|
|
@@ -97,7 +101,7 @@ import { VoiceNote } from "@hjmds/react-native/voice-note";
|
|
|
97
101
|
|
|
98
102
|
| 항목 | 값 | 근거 |
|
|
99
103
|
| --- | --- | --- |
|
|
100
|
-
| 크기 | 정사각 액자. 한 변 `small` 32 · `medium` 48 · `large` 72 · `xlarge` 120. 모서리 `square` 0 · `rounded` `radius.md` 12 · `circle` `radius.full`. 터치 대상이 아니므로 누를 수 있게 하려면 감싸는 버튼·행이 최소 44를 확보한다 | `assetRecipe.sizes`·`shapes`, `.hjm-asset__frame` |
|
|
104
|
+
| 크기 | 정사각 액자. 한 변 `small` 32 · `medium` 48 · `large` 72 · `xlarge` 120. 모서리 `square` 0 · `rounded` `radius.md`(무프로필 12, 미게시 보강에서는 프로필 값) · `circle` foundation `radius.full`. 터치 대상이 아니므로 누를 수 있게 하려면 감싸는 버튼·행이 최소 44를 확보한다 | `assetRecipe.sizes`·`shapes`, `.hjm-asset__frame` |
|
|
101
105
|
| 간격 | `accessory`는 액자 끝·아래 모서리 바깥으로 `spacing.xxs` 4 띄워 붙으므로 옆 요소와 `spacing.xs` 8 이상 띄운다. `AssetGroup` 겹침은 크기의 30%(48이면 −14) | `assetRecipe.accessory`·`overlapRatio`, `react/src/asset.tsx` |
|
|
102
106
|
| 순서·정렬 | 늘어나지 않는 인라인 요소(Web `inline-flex`, `flex: 0 0 auto`). 행 안에서는 시작 쪽에 둔다. 한 줄에 종류가 다른 그림을 섞을 때 모두 같은 `size`·`shape`를 준다 | `.hjm-asset`, `assetBehavior.scenarios` |
|
|
103
107
|
| 고정·스크롤 | 고정 영역이 없다 | — |
|
|
@@ -109,6 +113,9 @@ import { VoiceNote } from "@hjmds/react-native/voice-note";
|
|
|
109
113
|
둘 다 준 경우 모두 렌더 중 `TypeError`가 난다.
|
|
110
114
|
- reduced motion에서는 숨기지 말고 `animate`로 재생을 멈춘다. 판단을 제품에서 다시 만들지 않는다.
|
|
111
115
|
- Lottie·비디오·오디오 엔진, 그림 자산은 제품 소유다. HJM은 액자·크기·겹침·표식 위치만 소유한다.
|
|
116
|
+
- 테마별 그림은 제품의 자산 목록에서 선택해 슬롯에 넣는다. Asset이 URL을 만들거나 재질·각도
|
|
117
|
+
변형을 자동 생성하지 않는다. 자산마다 지원하는 조합과 실패 대체를 확인하며, 3D 제공자의
|
|
118
|
+
태그를 의미 있는 대체 텍스트로 그대로 복사하지 않는다. 기능 아이콘은 Icon/Button 계약을 쓴다.
|
|
112
119
|
- `VoiceNote`의 재생 위치는 실제 플레이어 값을 넘긴다. 내부 타이머로 진행을 꾸미지 않는다.
|
|
113
120
|
|
|
114
121
|
## 플랫폼 차이
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: recipe `badgeRecipe`(`src/component-recipes.ts`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/데이터 표시/배지`
|
|
10
10
|
|
|
@@ -59,6 +59,8 @@ import { Badge } from "@hjmds/react-native/data-display";
|
|
|
59
59
|
|
|
60
60
|
## 배치
|
|
61
61
|
|
|
62
|
+
Native 모서리는 Provider token에서 recipe 역할을 읽는다. Badge의 `full`은 고정 pill 역할(999)이라 테마가 이를 사각형으로 바꾸지 않는다.
|
|
63
|
+
|
|
62
64
|
| 항목 | 값 | 근거 |
|
|
63
65
|
| --- | --- | --- |
|
|
64
66
|
| 크기 | 내용 폭만 차지한다. 최소 높이 `medium` 24 · `small` 20, 모서리 `radius.full`. 누를 수 없는 표시라 44 터치 영역이 필요 없다(누르게 하려면 [Chip](chip.md)) | `badgeRecipe.sizes`, `.hjm-badge` |
|
|
@@ -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-chrome.md), recipe `bottomCtaRecipe`(`src/component-recipes.ts`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/동작/하단 실행 버튼`
|
|
10
10
|
|
|
@@ -123,3 +123,5 @@ const insets = useSafeAreaInsets();
|
|
|
123
123
|
|
|
124
124
|
- Web `BottomCTA`의 `style`은 recipe CSS 변수 뒤에 펼쳐지므로 `--hjm-bottom-cta-*` 변수를 덮을 수 있다. 외형은 recipe 소유이므로 `style`로 변수를 바꾸지 않는다.
|
|
125
125
|
- Native는 하단 inset을 스스로 읽지 않는다. `safeAreaBottom`을 빠뜨려도 오류가 없고 홈 인디케이터에 붙어 보인다.
|
|
126
|
+
|
|
127
|
+
미게시(1.14.0 이후): 프로필의 `shadow.floating` 색·강도·반경을 상속하되, 위 콘텐츠와 겹치는 footer 역할이라 offsetY는 `-abs(offsetY)`로 위쪽에 표시한다. Native의 0-opacity 프로필은 Android elevation도 0이다. 프로필 없는 Web은 기존 무그림자, Native는 기존 위쪽 recipe 그림자를 유지한다. safe area·큰 글자·로딩/실패와 제품 행동 소유권은 바뀌지 않는다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [BottomNavigation](../../bottom-navigation.md), recipe `bottomNavigationRecipe`
|
|
9
9
|
- 스토리북: `배포/컴포넌트/탐색/하단 탐색`
|
|
10
10
|
|
|
@@ -87,6 +87,8 @@ import { BottomNavigation } from "@hjmds/react-native/navigation";
|
|
|
87
87
|
|
|
88
88
|
## 배치
|
|
89
89
|
|
|
90
|
+
Native floating 프레임·선택 표시·항목 모서리는 각 recipe radius 역할을 Provider token에서 읽는다. full/capsule 원형 역할과 목적지·키보드 동작은 유지한다.
|
|
91
|
+
|
|
90
92
|
| 항목 | 값 | 근거 |
|
|
91
93
|
| --- | --- | --- |
|
|
92
94
|
| 크기 | 항목 최소 `regular` 56×64 · `compact` 52×52. 표면 최대 폭 `bar` 제한 없음(화면 폭) · `floating` 384 · `capsule` 480. 모서리 `floating` `radius.xl` 24 · `capsule` `radius.full`. 아이콘·배지 자리 40×28 | `bottomNavigationRecipe.density`·`presentations`·`indicator` |
|
|
@@ -134,3 +136,5 @@ floating·capsule: 바깥 좌우 16 · 위 8 띄운 둥근 표면, 최대 폭 38
|
|
|
134
136
|
- `renderLink` 없이 쓰면 일반 `<a>`로 그려 SPA 전환이 일어나지 않는다.
|
|
135
137
|
- Web `onActivate`는 링크 기본 이동을 막지 않는다. `renderLink`의 라우터 Link가 이동하고 `onActivate`는 계측·맨 위로 스크롤 같은 부수 동작에만 쓴다. 수정키·가운데 클릭에는 불리지 않는다.
|
|
136
138
|
- 현재 Native 내비게이션 연구 스토리(`showcase/native/src/reference-navigation-bars.tsx`)는 deprecated `style`(`paddingHorizontal: 0`)·`listStyle`(`borderRadius`)로 recipe 여백·모서리를 덮고, 제목을 `Text variant="heading"`으로 그린다. 규칙은 `configuration`·`layoutStyle`과 [Heading](heading.md)이다(스토리 수정 후보).
|
|
139
|
+
|
|
140
|
+
미게시(1.14.0 이후): Native의 floating/capsule은 프로필 `shadow.floating`을 읽으며 0-opacity는 Android elevation도 제거한다. bar는 원래 무그림자 계약을 유지한다. Web은 기존 CSS token 경로로 같은 프로필을 읽는다. 선택 route와 이동 intent는 제품이 소유한다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [버튼 라벨 줄바꿈](../../button-label.md), `src/base-recipes.ts`(`buttonRecipe`), `src/foundations.ts`(`control.buttonHeight`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/동작/버튼`, `배포/컴포넌트/동작/버튼 안에서 확인`, `배포/컴포넌트/동작/반응 선택`
|
|
10
10
|
|
|
@@ -95,6 +95,12 @@ import { Button } from "@hjmds/react-native/actions";
|
|
|
95
95
|
|
|
96
96
|
## 꼭 지킬 것
|
|
97
97
|
|
|
98
|
+
- 2026-10-07 [Stateful Button 대조](../../../../../docs/plans/aceternity-interaction-adoption-2026-10-07.md)를
|
|
99
|
+
기존 [실행과 복구](../../action-session.md)와 비교했다. Button은 callback의 Promise를 자동으로
|
|
100
|
+
기다려 성공을 판정하는 엔진이 아니다. 제품 mutation 또는 기존 action-session의 pending을
|
|
101
|
+
`loading`에 연결하고 실제 확정 뒤 성공 문구를 보여 준다. 실패하면 초안을 보존하고 재시도를
|
|
102
|
+
제공한다. Promise가 resolve됐다는 이유만으로 도메인 응답의 실패를 성공으로 표시하지 않는다.
|
|
103
|
+
|
|
98
104
|
- 라벨은 i18n 키로 넣는다. 자르지 말고 두 줄을 넘으면 카피를 고친다([라벨 정책](../../button-label.md)).
|
|
99
105
|
- 배치는 `layoutStyle`로만 한다. 색·radius·높이를 `style`/`className`으로 덮지 않는다.
|
|
100
106
|
Native에서 `style`·`labelStyle`을 넘기면 실행 중 `TypeError`가 난다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Calendar](../../calendar.md), recipe `calendarRecipe`(`src/calendar.ts`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/데이터 표시/달력`
|
|
10
10
|
|
|
@@ -80,6 +80,8 @@ import { Calendar } from "@hjmds/react-native/calendar";
|
|
|
80
80
|
|
|
81
81
|
## 배치
|
|
82
82
|
|
|
83
|
+
Native `renderCellContent` 최소 높이는 Provider의 `tokens.typography.label.lineHeight × textScale`다. 날짜의 원형 geometry와 선택 계약은 별도다.
|
|
84
|
+
|
|
83
85
|
| 항목 | 값 | 근거 |
|
|
84
86
|
| --- | --- | --- |
|
|
85
87
|
| 크기 | 날짜 칸 44(`medium` `control.minTouchTarget`, `large` `glyph.xxl` 44 — large는 글자만 `bodyLarge`로 커진다). 격자 최소 폭 7 × 44 = 308. 월 이동 버튼 44 원(`control.buttonHeight.medium`). 셀 `content`는 날짜 아래 label 한 줄 높이 | `calendarRecipe.sizes`·`header.navButton`, `.hjm-calendar__grid` |
|
|
@@ -74,7 +74,7 @@ import { Button } from "@hjmds/react-native/actions";
|
|
|
74
74
|
| `tone` | `default` · `raised` · `accent` · `sunken` · `subtle`(Surface tone) | `default` | — |
|
|
75
75
|
| `bordered` | `boolean` | `true` | Surface 기본 `false`와 다르다 |
|
|
76
76
|
| `padding` | spacing 이름 | `md`(16) | — |
|
|
77
|
-
| `radius` | radius 이름 | `lg`(16) |
|
|
77
|
+
| `radius` | radius 이름 | `lg`(foundation 16) | 선택한 designProfile의 같은 radius 역할로 frame과 media clip을 함께 변경 |
|
|
78
78
|
| `selected` | `boolean` | `false` | `true`면 tone이 `accent`로 바뀐다(`cardRecipe.selectedTone`) |
|
|
79
79
|
| `headingLevel`(Web만) | `2` · `3` · `4` | `3` | 제목이 `h3`로 렌더되므로 문서 위계에 맞춰 고른다 |
|
|
80
80
|
| `title` · `description` · `leading` · `media` · `actions` · `children` | `ReactNode` | — | 슬롯. 순서는 HJM이 고정한다 |
|
|
@@ -82,6 +82,19 @@ import { Button } from "@hjmds/react-native/actions";
|
|
|
82
82
|
|
|
83
83
|
Card 자체에는 콜백이 없다. 누름 행동은 `actions`의 Button(Web `onClick: (event: MouseEvent<HTMLButtonElement>) => void`, Native `onPress`)이 갖는다.
|
|
84
84
|
|
|
85
|
+
2026-10-07 [확장 카드·그리드 대조](../../../../../docs/plans/aceternity-interaction-adoption-2026-10-07.md)에서
|
|
86
|
+
카드와 상세 표시를 별도 새 카드 엔진으로 복제할 필요가 없는 경우를 확인했다. 상세는 `actions`의
|
|
87
|
+
Button으로 [Dialog](dialog.md)를 열고, 위치 연결이 필요하면 Dialog의 `motionOrigin`을 사용한다.
|
|
88
|
+
같은 흐름 안에서 내용을 늘릴 때는 [Collapsible](collapsible.md)를 고른다. 이미지·제목이 각각 이동하는
|
|
89
|
+
shared-element 효과와 일반 상세 Dialog는 다르며, 전자를 제공한다고 안내하지 않는다.
|
|
90
|
+
|
|
91
|
+
### 프로필 표면 질감(미게시)
|
|
92
|
+
|
|
93
|
+
선택한 `designProfile.material.surface`를 자동으로 읽는다. glass는 지원하는 Web에서 실제 배경 흐림,
|
|
94
|
+
clay는 안쪽 그림자를 사용한다. Native는 루트 Provider의 선택형 `surfaceEffects` host와 inset capability를
|
|
95
|
+
한 번 등록한다. 사용할 수 없거나 투명도 줄이기 설정이면 불투명 표면을 유지한다. 효과와 입력은 서로 다른
|
|
96
|
+
subtree라 질감을 바꾸거나 host가 실패해도 본문/초안은 유지한다. [범위·등록·대비 계약](../../design-profile.md#surfacecard의-유리클레이-질감)을 따른다.
|
|
97
|
+
|
|
85
98
|
## 배치
|
|
86
99
|
|
|
87
100
|
| 항목 | 값 | 근거 |
|
|
@@ -108,9 +121,13 @@ Card 자체에는 콜백이 없다. 누름 행동은 `actions`의 Button(Web `on
|
|
|
108
121
|
| root | `<article>` | `View`(Surface) |
|
|
109
122
|
| 제목 | `h{headingLevel}` | `Text` + `accessibilityRole="header"`, 수준 지정 없음 |
|
|
110
123
|
| 배치 | `layoutStyle` | `layoutStyle` |
|
|
111
|
-
| 내용 clip | tone의 `clipsContent`(`raised`는 그림자 때문에 clip 안 함) | 내부 `View`가 항상 clip, 그림자는 바깥에
|
|
124
|
+
| 내용 clip | tone의 `clipsContent`(`raised`는 그림자 때문에 clip 안 함) | 내부 `View`가 항상 clip, 그림자는 바깥에 남는다. frame과 clip이 같은 Provider radius token을 사용 |
|
|
112
125
|
|
|
113
126
|
## 함정
|
|
114
127
|
|
|
128
|
+
- `radius="lg"`는 모든 테마에서 16px이라는 뜻이 아니다. foundation에서는 16이고, designProfile이
|
|
129
|
+
등록되면 그 테마의 `tokens.radius.lg`를 쓴다. 2026-10-07 카드 갤러리 비교에서 Native의 바깥
|
|
130
|
+
Surface만 테마를 따르고 내부 media clip은 foundation 값을 쓰는 누락을 발견해 같은 token으로 연결했다.
|
|
131
|
+
|
|
115
132
|
- `selected`는 tone만 바꾼다. Web은 `data-state="selected"` 속성뿐이고 Native는 접근성 state를
|
|
116
133
|
알리지 않는다. 선택 가능한 카드 목록이라면 선택 상태를 문구나 다른 컨트롤로도 전달한다.
|
|
@@ -99,6 +99,11 @@ import { Carousel } from "@hjmds/react-native/carousel";
|
|
|
99
99
|
- 슬라이드 id는 유일하고 앞뒤 공백이 없어야 한다. 빈 배열은 던지므로 로딩·빈 상태는 마운트 전에 제품이 처리한다.
|
|
100
100
|
- `composeAccessibleName`의 어순·조사는 제품 문구다. HJM은 위치 정보만 넘긴다.
|
|
101
101
|
- 슬라이드 안의 시각 콘텐츠(카드·이미지)는 제품 소유다. 컨트롤·점·접근성 구조는 HJM 소유라 다시 만들지 않는다.
|
|
102
|
+
- 2026-10-07 [Motion 네 변형 검토](../../../../../docs/qa/2026-10-07-motion-reference-page-review.md)와
|
|
103
|
+
[Cedar Filmstrip 대조](../../../../../docs/qa/2026-10-07-reference-parallel-c.md)에서 여러 카드가
|
|
104
|
+
동시에 보이는 strip은 단일 active panel과 다른 계약임을 확인했다. 현재 Carousel에 임의
|
|
105
|
+
`basis-1/3`/translate 스타일을 덮어 strip을 제공하지 않는다. 선택 버튼의 초점·현재 위치 의미,
|
|
106
|
+
끝 정렬·폭 변경·부분 노출 항목의 초점/읽기 순서를 함께 갖춘 명시적 구성 확장이 필요한 후보다.
|
|
102
107
|
- 두 renderer는 숨겨진 슬라이드에도 `renderSlide`를 호출한다. 숨김은 네트워크 요청 취소나
|
|
103
108
|
자식 unmount가 아니다. 권한 확인이 필요한 사진을 현재 페이지만 읽는 제품은 제어된
|
|
104
109
|
`currentKey`와 비교해 선택되지 않은 콘텐츠를 `null`로 반환한다. 2026-10-07 Utilverse의
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Code block](../../code-block.md), contract `src/code-block.ts`
|
|
9
9
|
- 스토리북: `배포/컴포넌트/데이터 표시/코드 블록`
|
|
10
10
|
|
|
@@ -78,6 +78,10 @@ import { CodeBlock } from "@hjmds/react-native/code-block";
|
|
|
78
78
|
|
|
79
79
|
## 배치
|
|
80
80
|
|
|
81
|
+
Native 코드 제목은 `tokens.fontFamily.ui`, 선택 가능한 원문과 그 token span은 `tokens.fontFamily.code`를 읽는다. 주변 UI와 코드 원문의 서체 역할을 구분하고 코드 본문의 LTR 순서는 유지한다.
|
|
82
|
+
|
|
83
|
+
양 플랫폼의 코드 본문은 프로필 `fontFamily.code`와 `typography.body`를 읽고 구문 span은 상속한다. Native의 기본 monospace 의도는 iOS Menlo/Android monospace로 번역하고 custom font 등록은 제품이 한다. 코드 본문은 RTL 화면에서도 LTR 읽기 순서를 유지한다.
|
|
84
|
+
|
|
81
85
|
| 항목 | 값 | 근거 |
|
|
82
86
|
| --- | --- | --- |
|
|
83
87
|
| 크기 | 부모 폭을 채우고 높이는 코드 줄 수가 정한다. 모서리 `radius.lg` 16, 배경 `surface-alt` | `react/src/code-block.tsx`, `react-native/src/code-block.tsx` |
|
|
@@ -107,5 +111,13 @@ import { CodeBlock } from "@hjmds/react-native/code-block";
|
|
|
107
111
|
## 함정
|
|
108
112
|
|
|
109
113
|
- 복사는 화면의 주 행동과 경쟁하지 않도록 `ClipboardButton tone="secondary" size="small"`을 쓴다. Web 예제도 이 구성을 따른다.
|
|
110
|
-
- `ClipboardButton`은 `navigator.clipboard`가 거부되면
|
|
114
|
+
- `ClipboardButton`은 `navigator.clipboard`가 거부되면 성공 상태로 바꾸지 않고 `onCopyError`만 부른다. 이 콜백을 비워 두면
|
|
111
115
|
사용자는 실패를 알 수 없다.
|
|
116
|
+
|
|
117
|
+
2026-10-07 명령 기록 후보를 구현하며 지연 OS 응답을 검증한 결과, 이전 원문의 복사 성공/오류가
|
|
118
|
+
새 원문과 언마운트 뒤에도 callback을 호출하고 중복 쓰기를 허용했다. 미게시(1.14.0 이후) 후속
|
|
119
|
+
수정은 OS 쓰기 동안 Button loading/aria-busy/aria-disabled로 잠그고 키보드 포커스를 유지한다.
|
|
120
|
+
원문이 바뀌어도 진행 중 OS 쓰기는 취소할 수 없으므로 완료까지 새 쓰기를 막는다. 이전 결과의
|
|
121
|
+
성공 표시·callback은 무시하고 완료 뒤 현재 원문을 다시 복사할 수 있다. value가 바뀔 때마다
|
|
122
|
+
세대를 나누므로 A→B→A 변경도 이전 요청의 성공으로 오인하지 않는다. 제품은 이미 시작된
|
|
123
|
+
OS 쓰기 자체가 취소됐다고 안내하지 않는다. [검증 기록](../../../../../docs/qa/2026-10-07-command-records.md).
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Collapsible](../../collapsible.md), `FolderPreview`는 [Folder preview](../../folder-preview.md), recipe `collapsibleRecipe`(`src/collapsible.ts`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/데이터 표시/접기와 펼치기` · `배포/컴포넌트/데이터 표시/폴더 미리보기`
|
|
10
10
|
|
|
11
11
|
## 언제 쓰나
|
|
12
12
|
|
|
13
13
|
이웃 없이 혼자 접었다 펴는 한 덩어리에 쓴다. "더 보기", 필터 패널, 접히는 본문이 여기에 속한다.
|
|
14
|
-
닫히면 내용은 트리에서 빠진다.
|
|
14
|
+
기본값에서는 닫히면 내용은 트리에서 빠진다. `keepMounted`는 로컬 입력을 보존하고 hidden/display:none 접근성 경계로 내용을 숨긴다.
|
|
15
15
|
|
|
16
16
|
## 쓰지 않을 때
|
|
17
17
|
|
|
@@ -81,6 +81,8 @@ import { FolderPreview } from "@hjmds/react-native/folder-preview";
|
|
|
81
81
|
|
|
82
82
|
## 배치
|
|
83
83
|
|
|
84
|
+
FolderPreview의 Native preview `md`와 앞면 `lg`는 Provider radius를 읽는다. 기존 Collapsible·전환·장식 접근성 제외를 유지한다.
|
|
85
|
+
|
|
84
86
|
| 항목 | 값 | 근거 |
|
|
85
87
|
| --- | --- | --- |
|
|
86
88
|
| 크기 | 트리거는 폭을 꽉 채운다. 트리거 최소 높이 44(`control.minTouchTarget`, 두 플랫폼. Native는 미게시(1.12.1 이후)), Web 위아래 `spacing.xs` 8. `FolderPreview` 표지는 최대 260×160 고정 그림 | `.hjm-collapsible__trigger`, `react-native/src/collapsible.tsx`, `react/src/folder-preview.tsx` |
|
|
@@ -110,3 +112,9 @@ import { FolderPreview } from "@hjmds/react-native/folder-preview";
|
|
|
110
112
|
|
|
111
113
|
- 현재 랜딩 스토리(Web·Native `Landing.stories.tsx`)는 FAQ 여러 항목을 `Collapsible` 반복으로 그린다. 서로 연결된
|
|
112
114
|
여러 항목은 [Accordion](accordion.md)이 규칙이다(한 번에 하나 펼침·키보드 이동·heading 위계를 Accordion이 소유한다).
|
|
115
|
+
|
|
116
|
+
### 프로필 도구의 표현
|
|
117
|
+
|
|
118
|
+
2026-10-07 테마 전환 시 입력이 사라지는 문제를 피하려고 `presentation="inline"`과 `keepMounted`를 추가했다.
|
|
119
|
+
inline은 트리거를 숨기고 항상 내용을 펼친다. 기본 disclosure는 기존 open/defaultOpen 규칙을 유지한다.
|
|
120
|
+
keepMounted가 있어도 닫힌 내용은 포커스·스크린리더·터치 대상에서 제외한다. 단순 read-only 내용은 기존 기본값을 쓴다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: recipe `comboboxRecipe`(`src/component-recipes.ts`), behavior `combobox`
|
|
9
9
|
- 스토리북: `배포/컴포넌트/입력/검색형 선택`
|
|
10
10
|
|
|
@@ -81,8 +81,19 @@ import { Combobox } from "@hjmds/react-native/forms";
|
|
|
81
81
|
| Native `asyncState` | `{ status: "idle" }` · `{ status: "loading" \| "loadingMore" \| "empty" \| "error"; message: string }` | — | 결과 시트의 상태 문구. `error`면 `onRetry: () => void`·`retryLabel`로 다시 시도 버튼이 생긴다 |
|
|
82
82
|
| `layoutStyle` | margin·width·flex·`alignSelf` | — | 필드 바깥 배치 |
|
|
83
83
|
|
|
84
|
+
### 디자인 프로필 상속
|
|
85
|
+
|
|
86
|
+
2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
|
|
87
|
+
모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
|
|
88
|
+
읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
|
|
89
|
+
프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
|
|
90
|
+
플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
|
|
91
|
+
|
|
92
|
+
|
|
84
93
|
## 배치
|
|
85
94
|
|
|
95
|
+
Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
|
|
96
|
+
|
|
86
97
|
| 항목 | 값 | 근거 |
|
|
87
98
|
| --- | --- | --- |
|
|
88
99
|
| 크기 | 입력 높이 `medium` 44(`fieldFrameContract`) · `large` 52(`control.buttonHeight.large`), 폭은 폼 열을 채운다. Web 목록 최대 높이 22.5rem(360, recipe `popover.maxHeight`), 선택지 최소 높이 `compact` 44 · `comfortable` 56(3.5rem). Native 시트 최대 높이 화면의 75% | `selectRecipe.sizes`·`popover`, `.hjm-combobox__listbox`·`__option`, `react-native/src/forms.tsx` |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [CommandPalette contract](../../command-palette.md), recipe `commandPaletteRecipe`(`src/command-palette.ts`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/오버레이/명령 검색`
|
|
10
10
|
|
|
@@ -54,8 +54,8 @@ import { CommandPalette } from "@hjmds/react/command-palette";
|
|
|
54
54
|
/>
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
`paletteSource`는 `{ sections: [{ id: "recent", label: t("palette.recent"), items: recentItems }, …] }`처럼
|
|
58
|
-
|
|
57
|
+
`paletteSource`는 `{ sections: [{ id: "recent", label: t("palette.recent"), items: recentItems }, …] }`처럼 만든다.
|
|
58
|
+
기본(`queryState` 없음)은 renderer가 `query`로 항목의 `label`·`textValue`를 부분 일치로 거른다.
|
|
59
59
|
항목은 `{ id, label, textValue, description?, shortcut?, disabled?, tone? }`이다. 항목의 label·description·shortcut과
|
|
60
60
|
섹션 label은 제품 i18n에서 만든다.
|
|
61
61
|
|
|
@@ -116,10 +116,15 @@ Native: 없음.
|
|
|
116
116
|
|
|
117
117
|
## 함정
|
|
118
118
|
|
|
119
|
-
- 현재 renderer는 `query
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
- 현재 renderer는 `query`가 바뀔 때 활성 행을 첫 활성 항목으로 되돌린다. `source`·`queryState`의
|
|
120
|
+
새 참조만으로는 키보드 선택을 초기화하지 않는다. 선택한 ID가 결과에서 없어지면 첫 활성 행으로
|
|
121
|
+
돌아간다. 2026-10-07 실제 source의 의존성과 부모 재렌더 회귀를 대조해 예전 참조 경고를 정정했다.
|
|
122
122
|
- 닫을 때 `query`를 지우는 것은 제품 몫이다. 비우지 않으면 다음에 열 때 이전 검색어가 남는다.
|
|
123
123
|
- `filtering: "external"`인데 `resultQuery`를 갱신하지 않으면 결과가 보이기만 하고 Enter·클릭이 먹지 않는다(`aria-disabled`).
|
|
124
124
|
- 현재 Web 스토리는 제품 쪽에서 `label.includes(query)`로 직접 거르고 결과가 없을 때 `asyncState` `empty`로 안내하며
|
|
125
125
|
`closeLabel`이 없다. 새 코드는 로컬 필터링 기본값과 `emptyMessage`·`closeLabel`을 쓴다.
|
|
126
|
+
|
|
127
|
+
2026-10-07 동일한 메뉴 입력 패턴을 검사해 늦은 mouseenter가 키보드로 선택한 명령을 되돌리는
|
|
128
|
+
문제를 재현했다. 미게시(1.14.0 이후) 수정은 실제 마우스 이동으로만 활성 행을 바꾸므로 팝업
|
|
129
|
+
배치의 경계 이벤트는 키보드 선택을 덮지 않는다. 검색 초기화·비활성/오래된 결과 잠금·클릭 실행은
|
|
130
|
+
유지한다. [검증 기록](../../../../../docs/qa/2026-10-07-command-records.md).
|
|
@@ -66,7 +66,7 @@ import { ContentTransition } from "@hjmds/react-native/content-transition";
|
|
|
66
66
|
|
|
67
67
|
| prop | 값 | 기본값 | 설명 |
|
|
68
68
|
| --- | --- | --- | --- |
|
|
69
|
-
| `preset` | `fade` · `rise` · `slide` · `scale` | `fade` | `rise`는 아래 12에서, `slide`는 가로 16(RTL이면 반대), `scale`은 0.96에서 시작 |
|
|
69
|
+
| `preset` | `fade` · `rise` · `slide` · `scale` | provider `designProfile.interactions.contentTransition`, 프로필 없으면 `fade` | 명시한 prop이 프로필보다 우선. `rise`는 아래 12에서, `slide`는 가로 16(RTL이면 반대), `scale`은 0.96에서 시작 |
|
|
70
70
|
| `motion` | `system` · `none` | `system` | `system`은 reduced motion을 따르고 `none`은 항상 즉시 교체 |
|
|
71
71
|
| `stateKey` | `string` | — (필수) | 바뀔 때만 새 내용이 나타난다 |
|
|
72
72
|
| `enterOnMount` | boolean | false | 미게시: 새 데이터 항목이 처음 추가될 때도 등장 전환. 이미 표시한 항목은 stable key를 유지한다 |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [ContextMenu](../../context-menu.md), [선택 어댑터](../../optional-adapters.md), recipe `menuRecipe`
|
|
9
9
|
- 스토리북: `배포/컴포넌트/탐색/상황별 메뉴`
|
|
10
10
|
|
|
@@ -134,3 +134,9 @@ import { Pressable } from "react-native";
|
|
|
134
134
|
| 항목 `textValue`·`shortcut` | 있음 | 없음 |
|
|
135
135
|
| 열림 알림 | 없음 | `onOpenChange(open)` |
|
|
136
136
|
| 성숙도 | stable | 실험적 어댑터(기기 증거 전까지 canonical unsupported) |
|
|
137
|
+
|
|
138
|
+
2026-10-07 Web 키보드 회귀에서 팝업이 정지한 커서 아래에 배치된 뒤 mouseenter가 활성 항목을
|
|
139
|
+
첫 항목으로 되돌리는 문제를 재현했다. 미게시(1.14.0 이후) 수정은 실제 마우스 이동으로 항목을
|
|
140
|
+
바꾸며, 늦은 경계 이벤트만으로 키보드 선택을 덮지 않는다. 클릭·키보드 실행·포커스 복귀와
|
|
141
|
+
Native OS 어댑터는 기존 계약을 유지한다. 고정 대기 시간을 추가하지 않고 입력 의도를 구분했다.
|
|
142
|
+
[검증 기록](../../../../../docs/qa/2026-10-07-command-records.md).
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [DatePicker](../../date-picker.md), 격자는 [Calendar](../../calendar.md), recipe `datePickerRecipe`(`src/date-picker.ts`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/입력/날짜 선택`
|
|
10
10
|
|
|
@@ -95,6 +95,8 @@ import { DatePicker } from "@hjmds/react-native/date-picker";
|
|
|
95
95
|
|
|
96
96
|
## 배치
|
|
97
97
|
|
|
98
|
+
Native trigger 모서리는 `datePickerRecipe.frame.radius` 역할을 Provider의 `tokens.radius`에서 읽는다. 날짜·열림·선택 계약은 유지한다.
|
|
99
|
+
|
|
98
100
|
| 항목 | 값 | 근거 |
|
|
99
101
|
| --- | --- | --- |
|
|
100
102
|
| 크기 | 트리거 높이: `medium` 44 · `large` 52(`datePickerRecipe.sizes`, 두 플랫폼), 좌우 여백 16 · 20. 2026-10-06까지 렌더 값이 Web 44·56, Native 48·56이었다(1.12.1 이후 미게시). 지우기 버튼 44×44. Web 팝오버 폭 `min(22.5rem, 100vw − 2rem)`(최대 360). 날짜 셀 44, 7열 | `datePickerRecipe.sizes`, `packages/react/src/styles.css` `.hjm-date-picker*`, `packages/react-native/src/date-picker.tsx`, `src/calendar.ts` |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [DesignSystemProvider](../../design-system-provider.md), [브랜드 경계](../../brand-boundary.md)(브랜드 규칙 단일 원본), [테마 주입](../../theming.md), [팔레트 결정](../../theme-palette.md)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/기반 기능/디자인 시스템 설정`
|
|
10
10
|
|
|
@@ -77,10 +77,12 @@ expect(checkBrandPaletteContrast(PRODUCT_BRAND_PALETTE)).toEqual({ light: [], da
|
|
|
77
77
|
| `reducedMotion` | `true` · `false` | `false` | — |
|
|
78
78
|
| `minimumVisualTarget` | `true` · `false` | `false` | — |
|
|
79
79
|
| `brandPalette` | `{ light?, dark? }` | — | 각각 `ThemeColors` 17개 key 중 필요한 것만 넘긴다(부분 병합). 상태 강조색은 덮을 수 없다. 중첩 Provider는 가장 가까운 상위의 값을 물려받는다 |
|
|
80
|
-
| `
|
|
80
|
+
| `designProfile` | `HjmDesignProfile` | 가장 가까운 상위 프로필 또는 없음 | 미게시 실험. `hjmDesignPresets` 또는 `defineHjmDesignProfile` 결과만 넣는다. [프로필 계약](../../design-profile.md)의 토큰·질감·전환·구성·화면 기본값을 상속한다 |
|
|
81
|
+
| `value` | `DesignSystemProviderValue`(`resolveDesignSystemProviderValue` 결과) | — | 테스트·스토리·임베딩용. 환경 prop·`brandPalette`·`designProfile`과 함께 쓸 수 없고(타입이 막는다), 주면 OS theme·모션 관찰과 상위 `brandPalette` 상속이 멈춘다 |
|
|
82
|
+
| `surfaceEffects`(Native) | `{ renderBackdrop?, insetShadows? }` | 상위 host 또는 없음 | 미게시 실험. 실제 blur host·inset capability를 한 번 등록하며 `{}`로 하위 영역을 해제. [Surface 질감 계약](../../design-profile.md#surfacecard의-유리클레이-질감) |
|
|
81
83
|
| `safeAreaInsets`(Native) | `{ top?, right?, bottom?, left? }`(pt) | `{}` | 보통 `useSafeAreaInsets()` 결과. 중첩 Provider는 가장 가까운 상위 값을 물려받는다 |
|
|
82
84
|
|
|
83
|
-
-
|
|
85
|
+
- 제품 상태를 바꾸는 이벤트 prop은 없다. Native의 선택형 `surfaceEffects.renderBackdrop`은 장식 host만 공급한다. 해석된 값은 Web `useHjmTheme()`, Native `useHjmNativeTheme()`로 읽는다.
|
|
84
86
|
- `layoutStyle`을 받지 않는다(Web `HjmProvider`는 `layoutStyle` 제외 15개 중 하나). Web 루트 `div`의 표면 처리는 `host`로 정한다.
|
|
85
87
|
|
|
86
88
|
- 주지 않은 축은 상위 Provider → OS 신호 → 기본값 순이다.
|
|
@@ -97,8 +99,8 @@ expect(checkBrandPaletteContrast(PRODUCT_BRAND_PALETTE)).toEqual({ light: [], da
|
|
|
97
99
|
|
|
98
100
|
## 꼭 지킬 것
|
|
99
101
|
|
|
100
|
-
-
|
|
101
|
-
([브랜드 경계 §1](../../brand-boundary.md#1
|
|
102
|
+
- 색만 바꾸면 `brandPalette`, 표현·구성도 바꾸면 검증한 `designProfile`을 쓴다. 전체 `value`를 손으로 조립하는 것은 테스트·임베딩용이다
|
|
103
|
+
([브랜드 경계 §1](../../brand-boundary.md#1-지원하는-제품-설정-경로)).
|
|
102
104
|
- **Showcase·Theme Studio의 예시 색·자산·테마를 제품 기본값으로 복사하지 않는다**(2026-10-05 규칙). 색은 제품 목적과
|
|
103
105
|
기존 디자인에서 정해 `brandPalette`의 semantic key로 연결하고, 로고·이미지·문구는 각 컴포넌트의 공개 슬롯으로 넘긴다.
|
|
104
106
|
- 모든 브랜드 팔레트는 `checkBrandPaletteContrast` 결과가 빈 배열이어야 한다(MUST).
|
|
@@ -105,6 +105,7 @@ await handle.closed; // portal 제거·초점 복구 뒤. 다음 오버레이는
|
|
|
105
105
|
| `size` | `small` · `medium` · `large` | `medium` | Native recipe 최대 폭 320 · 420 · 640. Web 최대 폭 28rem · 36rem · 48rem(아래 배치 표) |
|
|
106
106
|
| `dismissible` | `true` · `false` | `true` | `false`면 닫기 버튼과 바깥·Escape/back 닫기가 사라진다 |
|
|
107
107
|
| `busy` | `true` · `false` | `false` | 비동기 작업 중에는 `open`을 유지하고 `busy`로 반복 행동과 닫기를 막는다 |
|
|
108
|
+
| `motionOrigin` | `{ x, y, width, height }`(`TransitionRect`) | 없음 | 열기 직전 측정한 출발 영역. Web viewport/Native window의 물리 좌표를 쓴다. 1.14.0 양 renderer의 게시 타입에 포함. 선택적 실험 표현이며 기기·성능 검증 완료와 구분한다 |
|
|
108
109
|
| `closeLabel` | 현지화 문자열 | — | 양쪽 필수. 닫기 버튼의 접근성 이름 |
|
|
109
110
|
| `open`·`defaultOpen` | `boolean` | `false` | 제어형은 `open`+`onOpenChange`. Web 비제어형은 `trigger`가 필수다 |
|
|
110
111
|
| `onOpenChange` | `(open: boolean, detail: { reason }) => void` | — | Web `reason`: `"trigger"`·`"close-action"`·`"escape"`·`"outside"`. Native: `"close-action"`·`"back"`·`"outside"`. `busy`이거나 `dismissible={false}`면 닫기 요청을 보내지 않는다 |
|
|
@@ -118,6 +119,15 @@ await handle.closed; // portal 제거·초점 복구 뒤. 다음 오버레이는
|
|
|
118
119
|
|
|
119
120
|
- Dialog는 `layoutStyle`을 받지 않는다(Web 제외 15개 중 하나 — 포털로 가운데 그려져 배치할 흐름 안 루트가 없다).
|
|
120
121
|
|
|
122
|
+
### 디자인 프로필 상속
|
|
123
|
+
|
|
124
|
+
2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
|
|
125
|
+
모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
|
|
126
|
+
읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
|
|
127
|
+
프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
|
|
128
|
+
플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
|
|
129
|
+
|
|
130
|
+
|
|
121
131
|
## 배치
|
|
122
132
|
|
|
123
133
|
| 항목 | 값 | 근거 |
|
|
@@ -175,7 +185,13 @@ Native, 큰 글자 또는 폭 < 480: [ 취소 ]
|
|
|
175
185
|
- Native는 제어형과 비제어형을 렌더 중에 바꾸면 예외가 난다.
|
|
176
186
|
- Native 기본 렌더러 예제는 실제 저장 서버가 없는 동기 완료 예시다. 제품에서는 저장 Promise를 반환하며, 예제의 영문 고정 문구는 제품 i18n 키로 치환한다. 닫기는 action이 요청하는 `close-action`이 맡는다.
|
|
177
187
|
|
|
178
|
-
### 선택적인 트리거 형태 전환 (
|
|
188
|
+
### 선택적인 트리거 형태 전환 (게시 API·실험 표현)
|
|
189
|
+
|
|
190
|
+
2026-10-07 [확장 카드·그리드 대조](../../../../../docs/plans/aceternity-interaction-adoption-2026-10-07.md) 중
|
|
191
|
+
실제 npm 1.14.0 양 renderer tarball의 `dist/overlays.d.ts`에서 이 옵션을 확인했다. 기존 미게시 표기를
|
|
192
|
+
수정한다. 테마 변경은 모서리·서체·그림자를 상속하며, 이 옵션의 출발 위치는 제품이 측정한다.
|
|
193
|
+
`designProfile.interactions.contentTransition`이 Dialog의 출발 위치나 shared-element 전환을
|
|
194
|
+
자동 선택하는 것은 아니다. 카드 안 상세 행동은 [Card](card.md)의 `actions` Button으로 제공한다.
|
|
179
195
|
|
|
180
196
|
양 renderer의 `motionOrigin?: TransitionRect`는 열기 직전에 측정한 트리거의
|
|
181
197
|
`{ x, y, width, height }`를 받는다. Web은 getBoundingClientRect, Native는 measureInWindow로
|
|
@@ -191,3 +207,39 @@ Native는 실제 Modal 콘텐츠를 측정하며 콜백이 오지 않으면 기
|
|
|
191
207
|
|
|
192
208
|
초안은 제품 상태에 두고 닫을 때 삭제하지 않는다. 내용·화면 회전·키보드로 목적지 크기가
|
|
193
209
|
달라지는 흐름은 실제 기기 검증 후 채택한다. 원점이 다른 좌표계를 혼합하지 않는다.
|
|
210
|
+
|
|
211
|
+
Web에서 버튼 위치와 상세 대화상자를 연결하는 최소 골격은 다음과 같다. 카드·이미지 전체에서
|
|
212
|
+
이어지는 효과가 필요하면 동일 좌표계의 그 영역을 측정한다. 아래는 버튼 영역을 쓰는 예이며
|
|
213
|
+
원본 이미지/제목을 복제해 이동시키는 shared-element 애니메이션은 아니다.
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import { useRef, useState } from "react";
|
|
217
|
+
import type { TransitionRect } from "@hjmds/design-contracts/content-transition";
|
|
218
|
+
import { Button } from "@hjmds/react/actions";
|
|
219
|
+
import { Card } from "@hjmds/react/display";
|
|
220
|
+
import { Dialog } from "@hjmds/react/overlays";
|
|
221
|
+
|
|
222
|
+
function RecordDetail() {
|
|
223
|
+
const [open, setOpen] = useState(false);
|
|
224
|
+
const [origin, setOrigin] = useState<TransitionRect>();
|
|
225
|
+
const returnFocus = useRef<HTMLButtonElement>(null);
|
|
226
|
+
return <>
|
|
227
|
+
<Card title={t("record.title")} actions={<Button ref={returnFocus} onClick={event => {
|
|
228
|
+
// Measure on activation: cached mount-time bounds become stale after scroll/layout.
|
|
229
|
+
const { x, y, width, height } = event.currentTarget.getBoundingClientRect();
|
|
230
|
+
setOrigin({ x, y, width, height });
|
|
231
|
+
setOpen(true);
|
|
232
|
+
}}>{t("record.openDetail")}</Button>} />
|
|
233
|
+
<Dialog open={open} onOpenChange={setOpen} title={t("record.title")}
|
|
234
|
+
closeLabel={t("common.close")} returnFocusRef={returnFocus}
|
|
235
|
+
{...(origin ? { motionOrigin: origin } : {})}>
|
|
236
|
+
<RecordFields />
|
|
237
|
+
</Dialog>
|
|
238
|
+
</>;
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
`RecordFields`의 초안은 제품의 편집 수명에 맞춰 Dialog 밖 상태에 둔다. Native에서는 측정 가능한
|
|
243
|
+
실제 View의 `measureInWindow`로 활성화 시점의 영역을 얻고, 좌표를 얻지 못해도 일반 Dialog를 연다.
|
|
244
|
+
측정 callback만 무기한 기다리면서 열기 행동을 막지 않는다. 버튼의 접근성 이름과 초점 복귀 대상을
|
|
245
|
+
유지하고, 카드 전체를 누름 가능한 비의미적 View/div로 바꾸지 않는다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: recipe `fieldRecipe`(`src/base-recipes.ts`), GestureSheetInput: [Optional presentation adapters](../../optional-adapters.md)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/입력/입력 필드`
|
|
10
10
|
|
|
@@ -84,6 +84,8 @@ import { Field } from "@hjmds/react-native/forms";
|
|
|
84
84
|
|
|
85
85
|
## 배치
|
|
86
86
|
|
|
87
|
+
Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
|
|
88
|
+
|
|
87
89
|
| 항목 | 값 | 근거 |
|
|
88
90
|
| --- | --- | --- |
|
|
89
91
|
| 크기 | 컨트롤 최소 높이 44(`control.minTouchTarget`), 안쪽 여백 좌우 `spacing.md`(16)·위아래 `spacing.sm`(12), 테두리 1. 여러 줄 입력은 최소 80(`fieldRecipe.multilineMinHeight`)이고 `minVisibleLines`를 줘도 이 하한 아래로 내려가지 않는다(한 줄 시작은 MessageComposer 내부만). 폭은 부모를 채운다 | `base-recipes.ts` `fieldRecipe`, `styles.css` `.hjm-field__control` |
|
|
@@ -27,14 +27,19 @@ Web 내부 fieldset은 제출 중 잠금을 위한 것이며 그룹 legend를
|
|
|
27
27
|
| 한 번 확인하고 닫히는 위험 행동 | [AlertDialog](alert-dialog.md) |
|
|
28
28
|
| 필드 하나의 라벨·도움말·오류 프레임 | [Field](field.md) |
|
|
29
29
|
| 약관 동의 묶음 | [Agreement](agreement.md) |
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
|
|
31
|
+
하단 고정 행동·Native return 키 제출도 기존 Form을 사용한다. Native는 `actions={null}`과
|
|
32
|
+
`ref.current?.submit()`으로 같은 제출 경로를 호출하고 [배치](#배치)의 loading 연결을 따른다.
|
|
33
|
+
2026-10-07 참고 폼 조사에서 초기 선택 표가 이후 배치 안내와 모순된 것을 확인해 오래된
|
|
34
|
+
"내장 버튼 숨김·외부 제출 불가" 안내를 제거했다. Native 1.14.0 게시 타입의 FormHandle/actions/ref를
|
|
35
|
+
직접 대조했으며 새 폼 엔진을 제품에 복제할 이유가 없다. FormHandle·actions는 1.14.0부터다.
|
|
32
36
|
|
|
33
37
|
## 공개 이름과 import
|
|
34
38
|
|
|
35
39
|
| 이름 | 역할 | Web | Native |
|
|
36
40
|
| --- | --- | --- | --- |
|
|
37
41
|
| `Form` | 기본 | `@hjmds/react`, `/forms` | `@hjmds/react-native`, `/forms` |
|
|
42
|
+
| `FormHandle` | 같은 Native 제출을 밖에서 호출하는 ref 타입(1.14.0부터) | — | `/forms` |
|
|
38
43
|
| `createFormSubmitSession` | 보조 — 제출 결과를 값으로 받거나 언마운트 때 정산해야 할 때 쓰는 세션 | `@hjmds/design-contracts/components/form` | 같음 |
|
|
39
44
|
| `resolveFirstInvalidFieldFocusTarget` | 보조 — 필드 순서와 무효 id로 첫 오류 필드를 고른다 | `@hjmds/design-contracts/components/form` | 같음 |
|
|
40
45
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-07
|
|
8
8
|
- 근거: [Heading](../../heading.md), recipe `headingRecipe`(`src/heading.ts`)
|
|
9
9
|
- 스토리북: `배포/컴포넌트/글자와 아이콘/제목`
|
|
10
10
|
|
|
@@ -53,6 +53,12 @@ import { Heading } from "@hjmds/react-native/heading";
|
|
|
53
53
|
| `layoutStyle` | 배치 key(margin·폭·정렬 등) | — | 바깥 배치만. 크기·줄 높이·굵기·색은 받지 않는다 |
|
|
54
54
|
|
|
55
55
|
- 범위 밖 값은 `TypeError`로 거부된다.
|
|
56
|
+
- 위 크기는 프로필 없는 기본값이다. [디자인 프로필](../../design-profile.md)의
|
|
57
|
+
`tokens.heading.level1`~`level5`로 다섯 시각 단계를 지정하면 양 renderer가 따르며,
|
|
58
|
+
`semanticLevel`은 그대로다. 크기를 맞추려고 문서 단계를 바꾸지 않는다.
|
|
59
|
+
- `defineHjmDesignProfile`에서 `tokens.typography.heading/titleLarge/title`을 바꾸면 기존
|
|
60
|
+
level3/4/5 연결을 유지한다. 같은 단계에 `tokens.heading`도 지정하면 명시한 heading
|
|
61
|
+
값이 우선한다. 큰 제목 level1/2는 본문 크기에서 자동 추정하지 않는다.
|
|
56
62
|
|
|
57
63
|
## 배치
|
|
58
64
|
|